1 /*
2  * Copyright (c) 2006-2025 RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2025-05-28     ZhangJing    Porting to ultrarisc dp1000
9  */
10 
11 #include <rthw.h>
12 #include <rtdevice.h>
13 #include <rtthread.h>
14 
15 #include "board.h"
16 #include "drv_uart.h"
17 
18 #include <stdio.h>
19 #ifdef RT_USING_SMART
20     #include <ioremap.h>
21 #endif
22 #include "sbi.h"
23 
24 struct device_uart
25 {
26     rt_ubase_t hw_base;
27     rt_uint32_t irqno;
28 };
29 
30 #ifdef BSP_USING_UART0
31     void *uart0_base = (void *)UART0_BASE_ADDR;
32     struct rt_serial_device serial0;
33     struct device_uart uart0;
34 
35     #define UART0_CLK        (UART0_REFERENCE_CLOCK)
36     #define UART0_BAUDRATE   (UART0_DEFAULT_BAUDRATE)
37 #endif
38 
39 #define UART_REFERENCE_CLOCK (UART0_CLK)
40 #define REG_SHIFT            (1 << UART0_REG_SHIFT)
41 #define write8_uart(base,idx, value)  __raw_writeb(((rt_uint8_t)value), (void*)((size_t)base + (idx*REG_SHIFT)))
42 #define read8_uart(base,idx)  __raw_readb((void*)((size_t)base + (idx*REG_SHIFT)))
43 
_uart_configure(struct rt_serial_device * serial,struct serial_configure * cfg)44 static rt_err_t _uart_configure(struct rt_serial_device *serial, struct serial_configure *cfg)
45 {
46     struct device_uart *uart = (struct device_uart *)serial->parent.user_data;
47     rt_uint32_t div = UART_REFERENCE_CLOCK / (cfg->baud_rate  * 16);
48     rt_uint32_t ier = read8_uart(uart->hw_base, UART_IER);
49 
50     write8_uart(uart->hw_base, UART_IER, 0x00);
51     write8_uart(uart->hw_base, UART_LCR, UART_LCR_BAUD_LATCH);
52 
53     /* LSB */
54     write8_uart(uart->hw_base, 0, div & 0xff);
55     /* MSB */
56     write8_uart(uart->hw_base, 1, (div >> 8) & 0xff);
57 
58     /* set word length to 8 bits, no parity */
59     write8_uart(uart->hw_base, UART_LCR, UART_LCR_EIGHT_BITS);
60 
61     write8_uart(uart->hw_base, UART_FCR, UART_FCR_FIFO_ENABLE | UART_FCR_FIFO_CLEAR);
62     write8_uart(uart->hw_base, UART_IER, ier);
63     return (RT_EOK);
64 }
65 
_uart_control(struct rt_serial_device * serial,int cmd,void * arg)66 static rt_err_t _uart_control(struct rt_serial_device *serial, int cmd, void *arg)
67 {
68     struct device_uart *uart = (struct device_uart *)serial->parent.user_data;
69 
70     switch (cmd)
71     {
72     case RT_DEVICE_CTRL_CLR_INT:
73         if ((size_t)arg == RT_DEVICE_FLAG_INT_RX)
74         {
75             rt_uint8_t value = read8_uart(uart->hw_base, UART_IER);
76             write8_uart(uart->hw_base, UART_IER, value & ~UART_IER_RX_ENABLE);
77         }
78         break;
79 
80     case RT_DEVICE_CTRL_SET_INT:
81         if ((size_t)arg == RT_DEVICE_FLAG_INT_RX)
82         {
83             rt_uint8_t value = read8_uart(uart->hw_base, UART_IER);
84             write8_uart(uart->hw_base, UART_IER, value | UART_IER_RX_ENABLE);
85         }
86         break;
87     }
88 
89     return (RT_EOK);
90 }
91 
_uart_putc(struct rt_serial_device * serial,char c)92 static int _uart_putc(struct rt_serial_device *serial, char c)
93 {
94     struct device_uart *uart;
95     uart = (struct device_uart *)serial->parent.user_data;
96 
97     /* wait for Transmit Holding Empty to be set in LSR. */
98     while ((read8_uart(uart->hw_base, UART_LSR) & UART_LSR_TX_IDLE) == 0)
99         ;
100     write8_uart(uart->hw_base, UART_THR, c);
101 
102     return (1);
103 }
104 
_uart_getc(struct rt_serial_device * serial)105 static int _uart_getc(struct rt_serial_device *serial)
106 {
107     struct device_uart *uart;
108     volatile rt_uint32_t lsr;
109     int ch = -1;
110 
111     uart = (struct device_uart *)serial->parent.user_data;
112     lsr = read8_uart(uart->hw_base, UART_LSR);
113 
114     if (lsr & UART_LSR_RX_READY)
115     {
116         ch = read8_uart(uart->hw_base, UART_RHR);
117     }
118     return ch;
119 }
120 
121 const struct rt_uart_ops _uart_ops =
122 {
123     _uart_configure,
124     _uart_control,
125     _uart_putc,
126     _uart_getc,
127     /* TODO: add DMA support */
128     RT_NULL
129 };
130 
rt_hw_uart_isr(int irqno,void * param)131 static void rt_hw_uart_isr(int irqno, void *param)
132 {
133     rt_ubase_t level = rt_hw_interrupt_disable();
134 
135     struct rt_serial_device *serial = (struct rt_serial_device *)param;
136     struct device_uart *uart = (struct device_uart *)serial->parent.user_data;
137 
138     if ((read8_uart(uart->hw_base, UART_LSR) & UART_LSR_RX_READY) != 0)
139     {
140         rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_IND);
141     }
142 
143     rt_hw_interrupt_enable(level);
144     return;
145 }
146 
147 /*
148  * UART Initiation
149  */
rt_hw_uart_init(void)150 int rt_hw_uart_init(void)
151 {
152     struct rt_serial_device *serial;
153     struct device_uart *uart;
154     struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
155     char ch;
156 #ifdef BSP_USING_UART0
157     /* register device */
158     serial = &serial0;
159     uart = &uart0;
160 
161     serial->ops = &_uart_ops;
162     serial->config = config;
163     serial->config.baud_rate = UART0_BAUDRATE;
164     uart->hw_base = (rt_ubase_t)uart0_base;
165 #ifdef RT_USING_SMART
166     uart->hw_base = (rt_ubase_t)rt_ioremap((void *)uart0_base, 0x1000);
167 #endif
168     uart->irqno = UART0_IRQ_BASE;
169     /* disable all uart irqs */
170     write8_uart(uart->hw_base, UART_IER, 0);
171     /* wait for Transmit Holding Empty to be set in LSR. */
172     while ((read8_uart(uart->hw_base, UART_LSR) & UART_LSR_TX_IDLE) == 0)
173         ;
174 
175     while ((read8_uart(uart->hw_base, UART_LSR) & UART_LSR_RX_READY) != 0)
176     {
177         ch = read8_uart(uart->hw_base, UART_RHR);
178     }
179 
180     rt_hw_serial_register(serial,
181                           RT_CONSOLE_DEVICE_NAME,
182                           RT_DEVICE_FLAG_STREAM | RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX,
183                           uart);
184     rt_hw_interrupt_install(uart->irqno, rt_hw_uart_isr, serial, RT_CONSOLE_DEVICE_NAME);
185     rt_hw_interrupt_umask(uart->irqno);
186 #endif
187 }