diff options
Diffstat (limited to 'bsp/ultrarisc/drivers')
| -rwxr-xr-x | bsp/ultrarisc/drivers/SConscript | 16 | ||||
| -rw-r--r-- | bsp/ultrarisc/drivers/drv_dw_spi.c | 390 | ||||
| -rw-r--r-- | bsp/ultrarisc/drivers/drv_dw_spi.h | 105 | ||||
| -rw-r--r-- | bsp/ultrarisc/drivers/drv_uart.c | 187 | ||||
| -rw-r--r-- | bsp/ultrarisc/drivers/drv_uart.h | 61 |
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, ®s->ssienr); + writel(0, ®s->ser); + writel(0, ®s->imr); + writel(0, ®s->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, ®s->baudr); + + /* write TX threshold register */ + writel(0, ®s->txflr); + /* write RX threshold register */ + writel(0, ®s->rxflr); + /* enable spi */ + writel(1, ®s->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(®s->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(®s->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, ®s->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(®s->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(®s->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, ®s->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(®s->ctrl0)) + { + writel(cr0, ®s->ctrl0); + } + /* set slave select */ + writel(1 << (dw_spi_dev->cs), ®s->ser); + + /* enable spi */ + writel(1, ®s->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, ®s->ssienr); + /* disbale all interrupts */ + writel(0, ®s->imr); + /* read and clear interrupt status */ + readl(®s->icr); + /* set slave select */ + writel(0, ®s->ser); + /* enable spi */ + writel(1, ®s->ssienr); + + dw_spi_dev->version = readl(®s->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, ®s->txftlr); + if (fifo != readl(®s->txftlr)) + { + break; + } + } + dw_spi_dev->fifo_len = (fifo == 1) ? 0 : fifo; + writel(0, ®s->txftlr); + rt_kprintf("fifo length is %d\n", dw_spi_dev->fifo_len); + } + + rt_uint32_t cr0, tmp = readl(®s->ctrl0); + writel(0, ®s->ssienr); + + writel(0xffffffff, ®s->ctrl0); + cr0 = readl(®s->ctrl0); + writel(tmp, ®s->ctrl0); + + writel(1, ®s->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 |
