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-04-27     WangShun     the first version
9  */
10 
11 #include "board.h"
12 #include "rtthread.h"
13 #include <rtdevice.h>
14 #include <string.h>
15 #include <drv_usart.h>
16 
17 #ifdef RT_USING_SERIAL
18     #define DRV_DEBUG
19     #define LOG_TAG              "drv.uart"
20 
21     #ifdef DRV_DEBUG
22         #define DBG_LVL          DBG_LOG
23     #else
24         #define DBG_LVL          DBG_INFO
25     #endif /* DRV_DEBUG */
26 
27     #include <rtdbg.h>
28 
29     #if !defined(BSP_USING_UART0) && !defined(BSP_USING_UART1) && !defined(BSP_USING_UART2) && !defined(BSP_USING_UART3) \
30         && !defined(BSP_USING_UART4) && !defined(BSP_USING_UART5) && !defined(BSP_USING_UART6) && !defined(BSP_USING_UART7)
31         #error "Please define at least one BSP_USING_UARTx"
32         /* this driver can be disabled at menuconfig -> RT-Thread Components -> Device Drivers */
33     #endif
34 
35 static void xuantie_uart0_rx_isr(csi_uart_t *uart_handler, csi_uart_event_t event, void *arg);
36 
37 enum
38 {
39 #ifdef BSP_USING_UART0
40     UART0_INDEX,
41 #endif
42 };
43 
44 struct xuantie_uart_config uart_config[] =
45 {
46 #ifdef BSP_USING_UART0
47     {
48         "uart0",
49         0,
50         xuantie_uart0_rx_isr
51     }
52 #endif
53 };
54 
55 struct xuantie_uart uart_obj[sizeof(uart_config) / sizeof(uart_config[0])] = {0};
56 
xuantie_configure(struct rt_serial_device * serial,struct serial_configure * cfg)57 static rt_err_t xuantie_configure(struct rt_serial_device *serial, struct serial_configure *cfg)
58 {
59     struct xuantie_uart *uart = (struct xuantie_uart *)serial->parent.user_data;
60     csi_error_t ret;
61 
62     ret = csi_uart_baud(&uart->uart, cfg->baud_rate);
63     if (ret != CSI_OK)
64     {
65         return -RT_ERROR;
66     }
67 
68     csi_uart_data_bits_t data_bits;
69     csi_uart_parity_t parity;
70     csi_uart_stop_bits_t stop_bits;
71 
72     switch (cfg->data_bits)
73     {
74     case DATA_BITS_5:
75         data_bits = UART_DATA_BITS_5;
76         break;
77     case DATA_BITS_6:
78         data_bits = UART_DATA_BITS_6;
79         break;
80     case DATA_BITS_7:
81         data_bits = UART_DATA_BITS_7;
82         break;
83     case DATA_BITS_8:
84         data_bits = UART_DATA_BITS_8;
85         break;
86     case DATA_BITS_9:
87         data_bits = UART_DATA_BITS_9;
88         break;
89     default:
90         data_bits = UART_DATA_BITS_8;
91         break;
92     }
93 
94     switch (cfg->parity)
95     {
96     case PARITY_NONE:
97         parity = UART_PARITY_NONE;
98         break;
99     case PARITY_ODD:
100         parity = UART_PARITY_ODD;
101         break;
102     case PARITY_EVEN:
103         parity = UART_PARITY_EVEN;
104         break;
105     default:
106         parity = UART_PARITY_NONE;
107         break;
108     }
109 
110     switch (cfg->stop_bits)
111     {
112     case STOP_BITS_1:
113         stop_bits = UART_STOP_BITS_1;
114         break;
115     case STOP_BITS_2:
116         stop_bits = UART_STOP_BITS_2;
117         break;
118     default:
119         stop_bits = UART_STOP_BITS_1;
120         break;
121     }
122 
123     ret = csi_uart_format(&uart->uart, data_bits, parity, stop_bits);
124     if (ret != CSI_OK)
125     {
126         return -RT_ERROR;
127     }
128 
129     return RT_EOK;
130 }
131 
xuantie_control(struct rt_serial_device * serial,int cmd,void * arg)132 static rt_err_t xuantie_control(struct rt_serial_device *serial, int cmd, void *arg)
133 {
134     switch (cmd)
135     {
136     case RT_DEVICE_CTRL_CONFIG:
137         return xuantie_configure(serial, (struct serial_configure *)arg);
138     default:
139         return -RT_ERROR;
140     }
141 }
142 
xuantie_putc(struct rt_serial_device * serial,char c)143 static int xuantie_putc(struct rt_serial_device *serial, char c)
144 {
145     struct xuantie_uart *uart = (struct xuantie_uart *)serial->parent.user_data;
146     int32_t ret;
147 
148     ret = csi_uart_send(&uart->uart, &c, 1, 50);
149     if (ret == 1)
150         return RT_EOK;
151 
152     return -RT_ERROR;
153 }
154 
xuantie_getc(struct rt_serial_device * serial)155 static int xuantie_getc(struct rt_serial_device *serial)
156 {
157     int c = -1;
158     struct xuantie_uart *uart = (struct xuantie_uart *)serial->parent.user_data;
159     dw_uart_regs_t *uart_base = (dw_uart_regs_t *)HANDLE_REG_BASE((&uart->uart));
160 
161     csi_uart_receive(&uart->uart, &c, 1, 0x5);
162     dw_uart_enable_recv_irq(uart_base);
163     return c;
164 }
165 
166 static const struct rt_uart_ops xuantie_uart_ops =
167 {
168     xuantie_configure,
169     xuantie_control,
170     xuantie_putc,
171     xuantie_getc,
172     RT_NULL,
173 };
174 
xuantie_uart0_rx_isr(csi_uart_t * uart_handler,csi_uart_event_t event,void * arg)175 static void xuantie_uart0_rx_isr(csi_uart_t *uart_handler, csi_uart_event_t event, void *arg)
176 {
177     rt_interrupt_enter();
178     rt_hw_serial_isr(&uart_obj[UART0_INDEX].serial, RT_SERIAL_EVENT_RX_IND);
179     rt_interrupt_leave();
180 }
181 
rt_hw_usart_init(void)182 int rt_hw_usart_init(void)
183 {
184     rt_size_t obj_num = sizeof(uart_obj) / sizeof(struct xuantie_uart);
185     struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
186     rt_err_t result = 0;
187 
188     for (int i = 0; i < obj_num; i++)
189     {
190         /* Initialize YOC UART */
191         result = csi_uart_init(&uart_obj[i].uart, 0);
192         if (result != CSI_OK)
193         {
194             LOG_E("Failed to initialize UART %d", uart_obj[i].config->idx);
195             return -RT_ERROR;
196         }
197 
198         /* Init UART object */
199         uart_obj[i].config        = &uart_config[i];
200         uart_obj[i].serial.ops    = &xuantie_uart_ops;
201         uart_obj[i].serial.config = config;
202 
203         csi_uart_attach_callback(&uart_obj[i].uart, uart_obj[i].config->xuantie_uart_rx_isr, NULL);
204 
205         /* Register UART device */
206         result = rt_hw_serial_register(&uart_obj[i].serial, uart_obj[i].config->name,
207                                        RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX,
208                                        &uart_obj[i]);
209         if (result != RT_EOK)
210         {
211             LOG_E("Failed to register UART device %s", uart_obj[i].config->name);
212             csi_uart_uninit(&uart_obj[i].uart);
213             return -RT_ERROR;
214         }
215     }
216     return result;
217 }
218 
219 #endif /* RT_USING_SERIAL */
220