summaryrefslogtreecommitdiff
path: root/bsp/ultrarisc/drivers
diff options
context:
space:
mode:
authorZhangJing <[email protected]>2025-05-30 13:32:58 +0800
committerRbb666 <[email protected]>2025-05-30 14:06:33 +0800
commit97893c004c65760c638fd7eb571a08fc987a55e5 (patch)
tree71c7c743e10a1281a104bfac56307e3d338a9818 /bsp/ultrarisc/drivers
parent93cc80e461d1e6d81e84c16caee4358f229e80f3 (diff)
[bsp]增加超睿DP1000 bsp支持v5.2.1
Diffstat (limited to 'bsp/ultrarisc/drivers')
-rwxr-xr-xbsp/ultrarisc/drivers/SConscript16
-rw-r--r--bsp/ultrarisc/drivers/drv_dw_spi.c390
-rw-r--r--bsp/ultrarisc/drivers/drv_dw_spi.h105
-rw-r--r--bsp/ultrarisc/drivers/drv_uart.c187
-rw-r--r--bsp/ultrarisc/drivers/drv_uart.h61
5 files changed, 759 insertions, 0 deletions
diff --git a/bsp/ultrarisc/drivers/SConscript b/bsp/ultrarisc/drivers/SConscript
new file mode 100755
index 0000000000..4b78609473
--- /dev/null
+++ b/bsp/ultrarisc/drivers/SConscript
@@ -0,0 +1,16 @@
+# RT-Thread building script for component
+
+from building import *
+
+cwd = GetCurrentDir()
+src = Glob('*.c')
+CPPPATH = [cwd]
+
+if not GetDepend('BSP_USING_DW_SPI'):
+ SrcRemove(src, ['drv_dw_spi.c'])
+
+group = DefineGroup('Drivers', src, depend = [''], CPPPATH = CPPPATH)
+
+objs = [group]
+
+Return('objs')
diff --git a/bsp/ultrarisc/drivers/drv_dw_spi.c b/bsp/ultrarisc/drivers/drv_dw_spi.c
new file mode 100644
index 0000000000..f2e263197d
--- /dev/null
+++ b/bsp/ultrarisc/drivers/drv_dw_spi.c
@@ -0,0 +1,390 @@
+/*
+ * Copyright (c) 2006-2025 RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * spi driver for synopsys dw apb spi
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2025-01-03 ZhangJing first version
+ */
+#include <rtconfig.h>
+
+#ifdef BSP_USING_DW_SPI
+#include <rtthread.h>
+#include <rtdevice.h>
+#include "drv_dw_spi.h"
+#include <rtdbg.h>
+#include <io.h>
+#ifdef RT_USING_SMART
+ #include <ioremap.h>
+#endif
+#define SPI0_BUS_NAME "spi0"
+#define SPI0_BUS_DEVICE0_NAME "spi00"
+
+static struct dw_spi dw_spi_device =
+{
+ .device_name = "spi0",
+ .irq = DW_SPI_IRQ_BASE,
+ .max_freq = DW_SPI_MAX_FREQ,
+ .bits_per_word = 8,
+ .cs = 0,
+ .fifo_len = 0,
+ .type = DW_SPI_CTRLR0_FRF_MOT,
+};
+
+static rt_uint32_t update_control_reg_16(struct dw_spi *dw_spi_dev)
+{
+ return ((dw_spi_dev->bits_per_word - 1) << CTRLR0_DFS_SHIFT) |
+ (dw_spi_dev->type << DW_SPI_CTRLR0_FRF_SHIFT) |
+ (dw_spi_dev->mode << DW_SPI_CTRLR0_MODE_SHIFT) |
+ (dw_spi_dev->tmode << DW_SPI_CTRLR0_TMOD_SHIFT);
+}
+
+static rt_uint32_t update_control_reg_32(struct dw_spi *dw_spi_dev)
+{
+ return ((dw_spi_dev->bits_per_word - 1) << CTRLR0_DFS_32_SHIFT) |
+ (dw_spi_dev->type << DW_SPI_CTRLR0_FRF_SHIFT) |
+ (dw_spi_dev->mode << DW_SPI_CTRLR0_MODE_SHIFT) |
+ (dw_spi_dev->tmode << DW_SPI_CTRLR0_TMOD_SHIFT);
+}
+
+static rt_err_t _dw_drv_spi_configure(struct rt_spi_device *device,
+ struct rt_spi_configuration *config)
+{
+ struct dw_spi *dw_spi_dev = (struct dw_spi *)(device->bus->parent.user_data);
+ if (!dw_spi_dev)
+ {
+ LOG_E("SPI device is null");
+ return -RT_ERROR;
+ }
+
+ struct dw_spi_regs *regs = dw_spi_dev->reg;
+ writel(0, &regs->ssienr);
+ writel(0, &regs->ser);
+ writel(0, &regs->imr);
+ writel(0, &regs->dmacr);
+
+ rt_uint32_t ctrl = 0;
+ switch (config->mode & (RT_SPI_CPHA | RT_SPI_CPOL))
+ {
+ case RT_SPI_MODE_0:
+ ctrl |= 0;
+ break;
+ case RT_SPI_MODE_1:
+ ctrl |= DW_SPI_CTRLR0_SCPH;
+ break;
+ case RT_SPI_MODE_2:
+ ctrl |= DW_SPI_CTRLR0_SCPOL;
+ break;
+ case RT_SPI_MODE_3:
+ ctrl |= DW_SPI_CTRLR0_SCPH | DW_SPI_CTRLR0_SCPOL;
+ break;
+ }
+
+ dw_spi_dev->mode = ctrl;
+
+
+ /* div = dw_spi_dev->max_freq / configuration->max_hz;*/
+ rt_uint32_t div = 0;
+ div = dw_spi_dev->max_freq / 15625000;
+ if (div % 2)
+ div++;
+ /* TODO: */
+ /* write clock divider register */
+ writel(div, &regs->baudr);
+
+ /* write TX threshold register */
+ writel(0, &regs->txflr);
+ /* write RX threshold register */
+ writel(0, &regs->rxflr);
+ /* enable spi */
+ writel(1, &regs->ssienr);
+
+ return RT_EOK;
+}
+
+static rt_uint32_t min3(rt_uint32_t a, rt_uint32_t b, rt_uint32_t c)
+{
+ return (a < b) ? ((a < c) ? a : c) : ((b < c) ? b : c);
+}
+
+
+static inline rt_uint32_t tx_max(struct dw_spi *dw_spi_dev)
+{
+ rt_uint32_t tx_left, tx_room, rxtx_gap;
+ struct dw_spi_regs *regs = dw_spi_dev->reg;
+
+ tx_left = dw_spi_dev->tx_len;
+ tx_room = dw_spi_dev->fifo_len - (rt_uint32_t)(readl(&regs->txflr));
+
+ /*
+ * Another concern is about the tx/rx mismatch, we
+ * thought about using (priv->fifo_len - rxflr - txflr) as
+ * one maximum value for tx, but it doesn't cover the
+ * data which is out of tx/rx fifo and inside the
+ * shift registers. So a control from sw point of
+ * view is taken.
+ */
+ if (dw_spi_dev->rx != NULL && dw_spi_dev->tx != NULL)
+ {
+ rxtx_gap = dw_spi_dev->fifo_len - (dw_spi_dev->rx_len - dw_spi_dev->tx_len);
+ return min3(tx_left, tx_room, (rt_uint32_t)(rxtx_gap));
+
+ }
+ else
+ {
+ return tx_left < tx_room ? tx_left : tx_room;
+ }
+}
+
+static inline rt_uint32_t rx_max(struct dw_spi *dw_spi_dev)
+{
+ rt_uint32_t rx_left = dw_spi_dev->rx_len;
+ struct dw_spi_regs *regs = dw_spi_dev->reg;
+
+ rt_uint32_t val = readl(&regs->rxflr);
+ return (rx_left < val) ? rx_left : val;
+}
+
+/* write data to spi */
+static void dw_spi_writer(struct dw_spi *dw_spi_dev)
+{
+ rt_uint32_t max = tx_max(dw_spi_dev);
+ rt_uint32_t txw = 0xFF;
+ struct dw_spi_regs *regs = dw_spi_dev->reg;
+
+ while (max--)
+ {
+ /* Set the tx word if the transfer's original "tx" is not null */
+ if (dw_spi_dev->tx)
+ {
+ if (dw_spi_dev->bits_per_word == 8)
+ txw = *(rt_uint8_t *)(dw_spi_dev->tx);
+ else
+ txw = *(rt_uint16_t *)(dw_spi_dev->tx);
+
+ dw_spi_dev->tx += dw_spi_dev->bits_per_word >> 3;
+ }
+ writel(txw, &regs->dr);
+ dw_spi_dev->tx_len--;
+ }
+}
+
+/* read data from spi */
+static void dw_spi_reader(struct dw_spi *dw_spi_dev)
+{
+ struct dw_spi_regs *regs = dw_spi_dev->reg;
+ rt_uint32_t max = rx_max(dw_spi_dev);
+ rt_uint16_t rxw;
+
+ while (max--)
+ {
+ rxw = readl(&regs->dr);
+ if (dw_spi_dev->rx)
+ {
+ if (dw_spi_dev->bits_per_word == 8)
+ *(rt_uint8_t *)(dw_spi_dev->rx) = rxw;
+ else
+ *(rt_uint16_t *)(dw_spi_dev->rx) = rxw;
+
+ dw_spi_dev->rx += dw_spi_dev->bits_per_word >> 3;
+
+ }
+ dw_spi_dev->rx_len--;
+ }
+}
+
+static void wait_for_idle(struct dw_spi *dw_spi_dev)
+{
+ rt_uint32_t status;
+ struct dw_spi_regs *regs = dw_spi_dev->reg;
+
+ while (1)
+ {
+ status = readl(&regs->sr);
+ if (!(status & DW_SPI_SR_BUSY))
+ {
+ if (status & DW_SPI_SR_TX_EMPTY)
+ {
+ break;
+ }
+ }
+ rt_thread_yield();
+ }
+}
+
+static int dw_spi_poll_transfer(struct dw_spi *dw_spi_dev)
+{
+ do
+ {
+ dw_spi_writer(dw_spi_dev);
+ wait_for_idle(dw_spi_dev);
+ dw_spi_reader(dw_spi_dev);
+ }
+ while (dw_spi_dev->rx_len && dw_spi_dev->tx_len);
+
+ return 0;
+}
+
+static rt_ssize_t _dw_spixfer(struct rt_spi_device *device, struct rt_spi_message *message)
+{
+ struct dw_spi *dw_spi_dev = (struct dw_spi *)(device->bus->parent.user_data);
+ if (!dw_spi_dev)
+ {
+ LOG_E("SPI device is null");
+ return -RT_ERROR;
+ }
+
+ dw_spi_dev->tx = (void *)message->send_buf;
+ dw_spi_dev->tx_end = dw_spi_dev->tx + dw_spi_dev->tx_len;
+
+ dw_spi_dev->rx = (void *)message->recv_buf;
+ dw_spi_dev->rx_end = dw_spi_dev->rx + dw_spi_dev->rx_len;
+
+ dw_spi_dev->tx_len = message->length;
+ dw_spi_dev->rx_len = message->length;
+
+ if (dw_spi_dev->tx && dw_spi_dev->rx)
+ {
+ /* set mode to Tx & Rx */
+ dw_spi_dev->tmode = DW_SPI_CTRLR0_TMOD_TX_RX;
+ }
+ else if (dw_spi_dev->rx)
+ {
+ /* set mode to Rx only */
+ dw_spi_dev->tmode = DW_SPI_CTRLR0_TMOD_RX;
+ }
+ else
+ {
+ /* set mode to Tx only */
+ dw_spi_dev->tmode = DW_SPI_CTRLR0_TMOD_TX;
+ }
+
+ struct dw_spi_regs *regs = dw_spi_dev->reg;
+ /* disable spi */
+ writel(0, &regs->ssienr);
+
+ LOG_D("dw_spixfer:tx 0x%x rx 0x%x len %d\n", dw_spi_dev->tx, dw_spi_dev->rx, message->length);
+
+ rt_uint32_t cr0 = dw_spi_dev->update_cr0(dw_spi_dev);
+ /* write control register */
+ if (cr0 != readl(&regs->ctrl0))
+ {
+ writel(cr0, &regs->ctrl0);
+ }
+ /* set slave select */
+ writel(1 << (dw_spi_dev->cs), &regs->ser);
+
+ /* enable spi */
+ writel(1, &regs->ssienr);
+ /* transfer data */
+ dw_spi_poll_transfer(dw_spi_dev);
+
+ /* wait for transfer complete */
+ wait_for_idle(dw_spi_dev);
+
+ return message->length;
+}
+
+const static struct rt_spi_ops dw_drv_spi_ops =
+{
+ _dw_drv_spi_configure,
+ _dw_spixfer,
+};
+
+
+static int dw_spi_hw_init(struct dw_spi *dw_spi_dev)
+{
+ struct dw_spi_regs *regs = dw_spi_dev->reg;
+
+ /* disable spi */
+ writel(0, &regs->ssienr);
+ /* disbale all interrupts */
+ writel(0, &regs->imr);
+ /* read and clear interrupt status */
+ readl(&regs->icr);
+ /* set slave select */
+ writel(0, &regs->ser);
+ /* enable spi */
+ writel(1, &regs->ssienr);
+
+ dw_spi_dev->version = readl(&regs->version);
+ rt_kprintf("ssi_version_id=%c.%c%c%c\n",
+ dw_spi_dev->version >> 24, dw_spi_dev->version >> 16,
+ dw_spi_dev->version >> 8, dw_spi_dev->version);
+
+ /* detect the FIFO depth if not set by interface driver */
+ if (!dw_spi_dev->fifo_len)
+ {
+ uint32_t fifo;
+ for (fifo = 1; fifo < 256; fifo++)
+ {
+ writel(fifo, &regs->txftlr);
+ if (fifo != readl(&regs->txftlr))
+ {
+ break;
+ }
+ }
+ dw_spi_dev->fifo_len = (fifo == 1) ? 0 : fifo;
+ writel(0, &regs->txftlr);
+ rt_kprintf("fifo length is %d\n", dw_spi_dev->fifo_len);
+ }
+
+ rt_uint32_t cr0, tmp = readl(&regs->ctrl0);
+ writel(0, &regs->ssienr);
+
+ writel(0xffffffff, &regs->ctrl0);
+ cr0 = readl(&regs->ctrl0);
+ writel(tmp, &regs->ctrl0);
+
+ writel(1, &regs->ssienr);
+
+ if (cr0 & DW_SPI_CTRLR0_DFS_MASK)
+ {
+ dw_spi_device.update_cr0 = update_control_reg_16;
+ }
+ else
+ {
+ dw_spi_device.update_cr0 = update_control_reg_32;
+ }
+ return 0;
+}
+
+int rt_hw_dw_spi_init(void)
+{
+ rt_err_t ret = RT_EOK;
+ struct dw_spi_regs *reg = NULL;
+
+ /* set reg base */
+#ifdef RT_USING_SMART
+ reg = (struct dw_spi_regs *)rt_ioremap((void *)DW_SPI_BASE_ADDR, sizeof(struct dw_spi_regs));
+#else
+ reg = (struct dw_spi_regs *)DW_SPI_BASE_ADDR;
+#endif
+ LOG_D("%s: reg base %p\n", __func__, reg);
+ if (!reg)
+ return -RT_ERROR;
+
+ dw_spi_device.reg = reg;
+ dw_spi_device.spi_bus.parent.user_data = &dw_spi_device;
+
+ dw_spi_device.tmode = 0; /* Tx & Rx */
+ dw_spi_device.bits_per_word = 8;
+
+ /* init spi */
+ dw_spi_hw_init(&dw_spi_device);
+
+ /* Register SPI bus*/
+ ret = rt_spi_bus_register(&dw_spi_device.spi_bus, dw_spi_device.device_name, &dw_drv_spi_ops);
+ if (ret == RT_EOK)
+ {
+ static struct rt_spi_device spi_device0;
+ rt_spi_bus_attach_device(&spi_device0, SPI0_BUS_DEVICE0_NAME, SPI0_BUS_NAME, (void *)&dw_spi_device);
+ }
+ return ret;
+}
+INIT_BOARD_EXPORT(rt_hw_dw_spi_init);
+
+#endif /* BSP_USING_DW_SPI */ \ No newline at end of file
diff --git a/bsp/ultrarisc/drivers/drv_dw_spi.h b/bsp/ultrarisc/drivers/drv_dw_spi.h
new file mode 100644
index 0000000000..bc9b4b8228
--- /dev/null
+++ b/bsp/ultrarisc/drivers/drv_dw_spi.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2006-2025 RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * spi driver for synopsys dw apb spi
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2025-01-03 ZhangJing first version
+ */
+#ifndef __DRV_DW_SPI_H__
+#define __DRV_DW_SPI_H__
+
+/* dw spi register */
+struct dw_spi_regs
+{
+ uint32_t ctrl0; /* 0x00:Control Register 0 (ctrl0) */
+ uint32_t ctrl1; /* 0x04:Control Register 1 (ctrl1) */
+ uint32_t ssienr; /* 0x08:Synchronous Serial Interface Enable Register (ssienr) */
+ uint32_t mwcr; /* 0x0c:Master Mode Control Register (mwcr) */
+ uint32_t ser; /* 0x10:Slave Enable Register (ser) */
+ uint32_t baudr; /* 0x14:Baud Rate Select Register (baudr) */
+ uint32_t txftlr; /* 0x18:Transmit FIFO Threshold Level Register (txftlr) */
+ uint32_t rxftlr; /* 0x1c:Receive FIFO Threshold Level Register (rxftlr) */
+ uint32_t txflr; /* 0x20:Transmit FIFO Level Register (txflr) */
+ uint32_t rxflr; /* 0x24:Receive FIFO Level Register (rxflr) */
+ uint32_t sr; /* 0x28:Status Register (sr) */
+ uint32_t imr; /* 0x2c:Interrupt Mask Register (imr) */
+ uint32_t isr; /* 0x30:Interrupt Status Register (isr) */
+ uint32_t risr; /* 0x34:Raw Interrupt Status Register (risr) */
+ uint32_t txoicr; /* 0x38:Transmit FIFO Overflow Interrupt Clear Register (txoicr) */
+ uint32_t rxoicr; /* 0x3c:Receive FIFO Overflow Interrupt Clear Register (rxoicr) */
+ uint32_t rxuicr; /* 0x40:Receive FIFO Underflow Interrupt Clear Register (rxuicr) */
+ uint32_t msticr; /* 0x44:Multi-Master Contention Interrupt Clear Register (msticr) */
+ uint32_t icr; /* 0x48:Interrupt Clear Register (icr) */
+ uint32_t dmacr; /* 0x4c:DMA Control Register (dmacr) */
+ uint32_t dmatdlr; /* 0x50:DMA Transmit Data Level Register (dmatdlr) */
+ uint32_t dmardlr; /* 0x54:DMA Receive Data Level Register (dmardlr) */
+ uint32_t idr; /* 0x58:Identification Register (idr) */
+ uint32_t version; /* 0x5c:Version Register (version) */
+ uint32_t dr[36]; /* 0x60:Data Register (dr) */
+ uint32_t rx_sample_delay; /* 0xf0: RX Sample Delay Register */
+ uint32_t spi_ctrl0; /* 0xf4*/
+ uint32_t txd_drive_edge; /* 0xf8*/
+ uint32_t rsvd; /* 0xfc*/
+};
+
+/* dw spi device */
+struct dw_spi
+{
+ struct dw_spi_regs *reg;
+ struct rt_spi_bus spi_bus;
+ char *device_name;
+ uint32_t version;
+ int irq;
+ uint32_t fifo_len;
+ uint32_t max_freq;
+ int bits_per_word;
+ void *tx;
+ void *tx_end;
+ void *rx;
+ void *rx_end;
+ unsigned int tx_len;
+ unsigned int rx_len;
+ uint32_t (*update_cr0)(struct dw_spi *dw_spi_dev);
+ uint8_t mode;
+ uint8_t cs; /* chip select pin */
+ uint8_t tmode; /* TR/TO/RO/EEPROM */
+ uint8_t type; /* SPI/SSP/MicroWire */
+};
+
+/* CTRLR0 bit definiation */
+#define DW_SPI_CTRLR0_DFS_MASK ((uint32_t)0x000F)
+#define CTRLR0_DFS_SHIFT 0
+#define DW_SPI_CTRLR0_DFS_0 ((uint32_t)(1<<0))
+#define DW_SPI_CTRLR0_DFS_1 ((uint32_t)(1<<1))
+#define DW_SPI_CTRLR0_DFS_2 ((uint32_t)(1<<2))
+#define DW_SPI_CTRLR0_DFS_3 ((uint32_t)(1<<3))
+
+#define DW_SPI_CTRLR0_FRF_SHIFT (4)
+#define DW_SPI_CTRLR0_FRF_MOT (0)
+#define DW_SPI_CTRLR0_FRF_TI (1)
+#define DW_SPI_CTRLR0_FRF_MICROWIRE (2)
+#define DW_SPI_CTRLR0_FRF_RESV (3)
+
+#define DW_SPI_CTRLR0_MODE_SHIFT (6)
+#define DW_SPI_CTRLR0_SCPH ((uint32_t)(1<<6))
+#define DW_SPI_CTRLR0_SCPOL ((uint32_t)(1<<7))
+
+#define DW_SPI_CTRLR0_TMOD_SHIFT (8)
+#define DW_SPI_CTRLR0_TMOD_TX_RX (0) /* transmit and receive */
+#define DW_SPI_CTRLR0_TMOD_TX (1) /* transmit only */
+#define DW_SPI_CTRLR0_TMOD_RX (2) /* receive only */
+#define DW_SPI_CTRLR0_TMOD_EEPROM_READ (3) /* eeprom read mode */
+
+#define CTRLR0_DFS_32_SHIFT (16)
+
+#define DW_SPI_CTRLR0_SLV_OE ((uint32_t)(1<<10)) /* salve output enable */
+#define DW_SPI_CTRLR0_SRL ((uint32_t)(1<<11)) /* shift register loop */
+#define DW_SPI_CTRLR0_CFS ((uint32_t)(0xF << 12)) /* control frame size */
+
+#define DW_SPI_SR_BUSY ((uint32_t)(1<<0))
+#define DW_SPI_SR_TX_EMPTY ((uint32_t)(1<<2))
+#endif /* __DRV_DW_SPI_H__ */ \ No newline at end of file
diff --git a/bsp/ultrarisc/drivers/drv_uart.c b/bsp/ultrarisc/drivers/drv_uart.c
new file mode 100644
index 0000000000..94bfaa2733
--- /dev/null
+++ b/bsp/ultrarisc/drivers/drv_uart.c
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2006-2025 RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2025-05-28 ZhangJing Porting to ultrarisc dp1000
+ */
+
+#include <rthw.h>
+#include <rtdevice.h>
+#include <rtthread.h>
+
+#include "board.h"
+#include "drv_uart.h"
+
+#include <stdio.h>
+#ifdef RT_USING_SMART
+ #include <ioremap.h>
+#endif
+#include "sbi.h"
+
+struct device_uart
+{
+ rt_ubase_t hw_base;
+ rt_uint32_t irqno;
+};
+
+#ifdef BSP_USING_UART0
+ void *uart0_base = (void *)UART0_BASE_ADDR;
+ struct rt_serial_device serial0;
+ struct device_uart uart0;
+
+ #define UART0_CLK (UART0_REFERENCE_CLOCK)
+ #define UART0_BAUDRATE (UART0_DEFAULT_BAUDRATE)
+#endif
+
+#define UART_REFERENCE_CLOCK (UART0_CLK)
+#define REG_SHIFT (1 << UART0_REG_SHIFT)
+#define write8_uart(base,idx, value) __raw_writeb(((rt_uint8_t)value), (void*)((size_t)base + (idx*REG_SHIFT)))
+#define read8_uart(base,idx) __raw_readb((void*)((size_t)base + (idx*REG_SHIFT)))
+
+static rt_err_t _uart_configure(struct rt_serial_device *serial, struct serial_configure *cfg)
+{
+ struct device_uart *uart = (struct device_uart *)serial->parent.user_data;
+ rt_uint32_t div = UART_REFERENCE_CLOCK / (cfg->baud_rate * 16);
+ rt_uint32_t ier = read8_uart(uart->hw_base, UART_IER);
+
+ write8_uart(uart->hw_base, UART_IER, 0x00);
+ write8_uart(uart->hw_base, UART_LCR, UART_LCR_BAUD_LATCH);
+
+ /* LSB */
+ write8_uart(uart->hw_base, 0, div & 0xff);
+ /* MSB */
+ write8_uart(uart->hw_base, 1, (div >> 8) & 0xff);
+
+ /* set word length to 8 bits, no parity */
+ write8_uart(uart->hw_base, UART_LCR, UART_LCR_EIGHT_BITS);
+
+ write8_uart(uart->hw_base, UART_FCR, UART_FCR_FIFO_ENABLE | UART_FCR_FIFO_CLEAR);
+ write8_uart(uart->hw_base, UART_IER, ier);
+ return (RT_EOK);
+}
+
+static rt_err_t _uart_control(struct rt_serial_device *serial, int cmd, void *arg)
+{
+ struct device_uart *uart = (struct device_uart *)serial->parent.user_data;
+
+ switch (cmd)
+ {
+ case RT_DEVICE_CTRL_CLR_INT:
+ if ((size_t)arg == RT_DEVICE_FLAG_INT_RX)
+ {
+ rt_uint8_t value = read8_uart(uart->hw_base, UART_IER);
+ write8_uart(uart->hw_base, UART_IER, value & ~UART_IER_RX_ENABLE);
+ }
+ break;
+
+ case RT_DEVICE_CTRL_SET_INT:
+ if ((size_t)arg == RT_DEVICE_FLAG_INT_RX)
+ {
+ rt_uint8_t value = read8_uart(uart->hw_base, UART_IER);
+ write8_uart(uart->hw_base, UART_IER, value | UART_IER_RX_ENABLE);
+ }
+ break;
+ }
+
+ return (RT_EOK);
+}
+
+static int _uart_putc(struct rt_serial_device *serial, char c)
+{
+ struct device_uart *uart;
+ uart = (struct device_uart *)serial->parent.user_data;
+
+ /* wait for Transmit Holding Empty to be set in LSR. */
+ while ((read8_uart(uart->hw_base, UART_LSR) & UART_LSR_TX_IDLE) == 0)
+ ;
+ write8_uart(uart->hw_base, UART_THR, c);
+
+ return (1);
+}
+
+static int _uart_getc(struct rt_serial_device *serial)
+{
+ struct device_uart *uart;
+ volatile rt_uint32_t lsr;
+ int ch = -1;
+
+ uart = (struct device_uart *)serial->parent.user_data;
+ lsr = read8_uart(uart->hw_base, UART_LSR);
+
+ if (lsr & UART_LSR_RX_READY)
+ {
+ ch = read8_uart(uart->hw_base, UART_RHR);
+ }
+ return ch;
+}
+
+const struct rt_uart_ops _uart_ops =
+{
+ _uart_configure,
+ _uart_control,
+ _uart_putc,
+ _uart_getc,
+ /* TODO: add DMA support */
+ RT_NULL
+};
+
+static void rt_hw_uart_isr(int irqno, void *param)
+{
+ rt_ubase_t level = rt_hw_interrupt_disable();
+
+ struct rt_serial_device *serial = (struct rt_serial_device *)param;
+ struct device_uart *uart = (struct device_uart *)serial->parent.user_data;
+
+ if ((read8_uart(uart->hw_base, UART_LSR) & UART_LSR_RX_READY) != 0)
+ {
+ rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_IND);
+ }
+
+ rt_hw_interrupt_enable(level);
+ return;
+}
+
+/*
+ * UART Initiation
+ */
+int rt_hw_uart_init(void)
+{
+ struct rt_serial_device *serial;
+ struct device_uart *uart;
+ struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
+ char ch;
+#ifdef BSP_USING_UART0
+ /* register device */
+ serial = &serial0;
+ uart = &uart0;
+
+ serial->ops = &_uart_ops;
+ serial->config = config;
+ serial->config.baud_rate = UART0_BAUDRATE;
+ uart->hw_base = (rt_ubase_t)uart0_base;
+#ifdef RT_USING_SMART
+ uart->hw_base = (rt_ubase_t)rt_ioremap((void *)uart0_base, 0x1000);
+#endif
+ uart->irqno = UART0_IRQ_BASE;
+ /* disable all uart irqs */
+ write8_uart(uart->hw_base, UART_IER, 0);
+ /* wait for Transmit Holding Empty to be set in LSR. */
+ while ((read8_uart(uart->hw_base, UART_LSR) & UART_LSR_TX_IDLE) == 0)
+ ;
+
+ while ((read8_uart(uart->hw_base, UART_LSR) & UART_LSR_RX_READY) != 0)
+ {
+ ch = read8_uart(uart->hw_base, UART_RHR);
+ }
+
+ rt_hw_serial_register(serial,
+ RT_CONSOLE_DEVICE_NAME,
+ RT_DEVICE_FLAG_STREAM | RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX,
+ uart);
+ rt_hw_interrupt_install(uart->irqno, rt_hw_uart_isr, serial, RT_CONSOLE_DEVICE_NAME);
+ rt_hw_interrupt_umask(uart->irqno);
+#endif
+} \ No newline at end of file
diff --git a/bsp/ultrarisc/drivers/drv_uart.h b/bsp/ultrarisc/drivers/drv_uart.h
new file mode 100644
index 0000000000..49170553f0
--- /dev/null
+++ b/bsp/ultrarisc/drivers/drv_uart.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2006-2025 RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2025-05-28 ZhangJing Porting to ultrarisc dp1000
+ */
+
+#ifndef __DRV_UART_H__
+#define __DRV_UART_H__
+
+#include "riscv_io.h"
+
+/**
+ * uart ns16550a
+ * http://byterunner.com/16550.html
+ */
+
+/* TRANSMIT AND RECEIVE HOLDING REGISTER */
+#define UART_RHR 0
+#define UART_THR 0
+
+/* INTERRUPT ENABLE REGISTER */
+#define UART_IER 1
+#define UART_IER_RX_ENABLE (1 << 0)
+#define UART_IER_TX_ENABLE (1 << 1)
+
+/* FIFO CONTROL REGISTER */
+#define UART_FCR 2
+#define UART_FCR_FIFO_ENABLE (1 << 0)
+#define UART_FCR_FIFO_CLEAR (3 << 1)
+
+/* INTERRUPT STATUS REGISTER */
+#define UART_ISR 2
+
+/* LINE CONTROL REGISTER */
+#define UART_LCR 3
+#define UART_LCR_EIGHT_BITS (3 << 0)
+/* special mode to set baud rate */
+#define UART_LCR_BAUD_LATCH (1 << 7)
+
+/* LINE STATUS REGISTER */
+#define UART_LSR 5
+/* input is waiting to be read from RHR */
+#define UART_LSR_RX_READY (1 << 0)
+/* THR can accept another character to send */
+#define UART_LSR_TX_IDLE (1 << 5)
+
+/*#define UART_REFERENCE_CLOCK 1843200
+#define UART_DEFAULT_BAUDRATE 115200*/
+
+extern void *uart0_base;
+
+
+void rt_hw_uart_start_rx_thread();
+int rt_hw_uart_init(void);
+void drv_uart_puts(char *str); /* for syscall */
+
+#endif /* __DRV_UART_H__ */ \ No newline at end of file