1 /*
2 * Copyright (C) 2020-2021 Alibaba Group Holding Limited
3 */
4
5 #define BES_HAL_DEBUG 0
6 #include <aos/kernel.h>
7 #include <aos/tty_core.h>
8 #include <ulog/ulog.h>
9 #include <hal_uart.h>
10 #include <hal_iomux.h>
11 #include <hal_trace.h>
12 #include <plat_types.h>
13
14 #define UART_DMA_RING_BUFFER_SIZE 256 /* mast be 2^n */
15
16 static __SRAMBSS unsigned char _hal_uart0_buf[UART_DMA_RING_BUFFER_SIZE];
17 static __SRAMBSS unsigned char _hal_uart1_buf[UART_DMA_RING_BUFFER_SIZE];
18 static __SRAMBSS unsigned char _hal_uart2_buf[UART_DMA_RING_BUFFER_SIZE];
19
20 typedef struct {
21 aos_tty_t tty;
22 unsigned char *rx_buf;
23 unsigned char tx_buf[UART_DMA_RING_BUFFER_SIZE];
24 void (*rx_handler)(uint32_t, int, union HAL_UART_IRQ_T);
25 void (*tx_handler)(uint32_t, int);
26 bool rx_busy;
27 bool tx_busy;
28 } tty_uart_t;
29
hal_set_uart_iomux(uint32_t uart_id)30 static void hal_set_uart_iomux(uint32_t uart_id)
31 {
32 if (uart_id == HAL_UART_ID_0)
33 hal_iomux_set_uart0();
34 else if (uart_id == HAL_UART_ID_1)
35 hal_iomux_set_uart1();
36 else
37 hal_iomux_set_uart2();
38 }
39
tty_uart_unregister(aos_tty_t * tty)40 static void tty_uart_unregister(aos_tty_t *tty)
41 {
42 }
43
tty_uart_startup(aos_tty_t * tty)44 static aos_status_t tty_uart_startup(aos_tty_t *tty)
45 {
46 tty_uart_t *uart = aos_container_of(tty, tty_uart_t, tty);
47 uint32_t id = tty->dev.id;
48 struct HAL_UART_CFG_T cfg;
49
50 switch (tty->termios.c_cflag & CBAUD) {
51 case B50:
52 cfg.baud = 50;
53 break;
54 case B75:
55 cfg.baud = 75;
56 break;
57 case B110:
58 cfg.baud = 110;
59 break;
60 case B134:
61 cfg.baud = 134;
62 break;
63 case B150:
64 cfg.baud = 150;
65 break;
66 case B200:
67 cfg.baud = 200;
68 break;
69 case B300:
70 cfg.baud = 300;
71 break;
72 case B600:
73 cfg.baud = 600;
74 break;
75 case B1200:
76 cfg.baud = 1200;
77 break;
78 case B1800:
79 cfg.baud = 1800;
80 break;
81 case B2400:
82 cfg.baud = 2400;
83 break;
84 case B4800:
85 cfg.baud = 4800;
86 break;
87 case B9600:
88 cfg.baud = 9600;
89 break;
90 case B19200:
91 cfg.baud = 19200;
92 break;
93 case B38400:
94 cfg.baud = 38400;
95 break;
96 case B57600:
97 cfg.baud = 57600;
98 break;
99 case B115200:
100 cfg.baud = 115200;
101 break;
102 case B230400:
103 cfg.baud = 230400;
104 break;
105 case B460800:
106 cfg.baud = 460800;
107 break;
108 case B500000:
109 cfg.baud = 500000;
110 break;
111 case B576000:
112 cfg.baud = 576000;
113 break;
114 case B921600:
115 cfg.baud = 921600;
116 break;
117 case B1000000:
118 cfg.baud = 1000000;
119 break;
120 case B1152000:
121 cfg.baud = 1152000;
122 break;
123 case B1500000:
124 cfg.baud = 1500000;
125 break;
126 case B2000000:
127 cfg.baud = 2000000;
128 break;
129 case B2500000:
130 cfg.baud = 2500000;
131 break;
132 case B3000000:
133 cfg.baud = 3000000;
134 break;
135 case B3500000:
136 cfg.baud = 3500000;
137 break;
138 case B4000000:
139 cfg.baud = 4000000;
140 break;
141 default:
142 cfg.baud = 9600;
143 break;
144 }
145
146 if (tty->termios.c_cflag & PARENB) {
147 if (tty->termios.c_cflag & PARODD)
148 cfg.parity = HAL_UART_PARITY_ODD;
149 else
150 cfg.parity = HAL_UART_PARITY_EVEN;
151 } else {
152 cfg.parity = HAL_UART_PARITY_NONE;
153 }
154
155 if (tty->termios.c_cflag & CSTOPB)
156 cfg.stop = HAL_UART_STOP_BITS_2;
157 else
158 cfg.stop = HAL_UART_STOP_BITS_1;
159
160 switch (tty->termios.c_cflag & CSIZE) {
161 case CS5:
162 cfg.data = HAL_UART_DATA_BITS_5;
163 break;
164 case CS6:
165 cfg.data = HAL_UART_DATA_BITS_6;
166 break;
167 case CS7:
168 cfg.data = HAL_UART_DATA_BITS_7;
169 break;
170 case CS8:
171 cfg.data = HAL_UART_DATA_BITS_8;
172 break;
173 default:
174 cfg.data = HAL_UART_DATA_BITS_8;
175 break;
176 }
177
178 switch (tty->termios.c_cflag & CRTSCTS) {
179 case RTSFLOW:
180 cfg.flow = HAL_UART_FLOW_CONTROL_RTS;
181 break;
182 case CTSFLOW:
183 cfg.flow = HAL_UART_FLOW_CONTROL_CTS;
184 break;
185 case CRTSCTS:
186 cfg.flow = HAL_UART_FLOW_CONTROL_RTSCTS;
187 break;
188 default:
189 cfg.flow = HAL_UART_FLOW_CONTROL_NONE;
190 break;
191 }
192
193 cfg.tx_level = HAL_UART_FIFO_LEVEL_1_2;
194 cfg.rx_level = HAL_UART_FIFO_LEVEL_1_2;
195 cfg.dma_rx = true;
196 cfg.dma_tx = true;
197 cfg.dma_rx_stop_on_err = false;
198
199 if (hal_uart_open(id, &cfg))
200 return -EIO;
201
202 hal_set_uart_iomux(id);
203 hal_uart_irq_set_dma_handler(id, uart->rx_handler, uart->tx_handler, NULL);
204
205 return 0;
206 }
207
tty_uart_shutdown(aos_tty_t * tty)208 static void tty_uart_shutdown(aos_tty_t *tty)
209 {
210 tty_uart_t *uart = aos_container_of(tty, tty_uart_t, tty);
211 uint32_t id = tty->dev.id;
212
213 hal_uart_close(id);
214 }
215
tty_uart_set_attr(aos_tty_t * tty)216 static aos_status_t tty_uart_set_attr(aos_tty_t *tty)
217 {
218 tty_uart_shutdown(tty);
219
220 return tty_uart_startup(tty);
221 }
222
start_rx_dma(tty_uart_t * uart)223 static void start_rx_dma(tty_uart_t *uart)
224 {
225 uint32_t id = uart->tty.dev.id;
226 struct HAL_DMA_DESC_T desc;
227 uint32_t desc_count = 1;
228 union HAL_UART_IRQ_T mask;
229
230 mask.reg = 0;
231 mask.BE = 0;
232 mask.FE = 0;
233 mask.OE = 0;
234 mask.PE = 0;
235 mask.RT = 1;
236 hal_uart_dma_recv_mask(id, uart->rx_buf, UART_DMA_RING_BUFFER_SIZE, &desc, &desc_count, &mask);
237 }
238
tty_uart_enable_rx(aos_tty_t * tty)239 static void tty_uart_enable_rx(aos_tty_t *tty)
240 {
241 tty_uart_t *uart = aos_container_of(tty, tty_uart_t, tty);
242 aos_irqsave_t flags;
243
244 flags = aos_spin_lock_irqsave(&tty->lock);
245 uart->rx_busy = true;
246 start_rx_dma(uart);
247 aos_spin_unlock_irqrestore(&tty->lock, flags);
248 }
249
tty_uart_disable_rx(aos_tty_t * tty)250 static void tty_uart_disable_rx(aos_tty_t *tty)
251 {
252 tty_uart_t *uart = aos_container_of(tty, tty_uart_t, tty);
253 uint32_t id = tty->dev.id;
254 aos_irqsave_t flags;
255
256 flags = aos_spin_lock_irqsave(&tty->lock);
257 uart->rx_busy = false;
258 hal_uart_stop_dma_recv(id);
259 aos_spin_unlock_irqrestore(&tty->lock, flags);
260 }
261
tty_uart_start_tx(aos_tty_t * tty)262 static void tty_uart_start_tx(aos_tty_t *tty)
263 {
264 tty_uart_t *uart = aos_container_of(tty, tty_uart_t, tty);
265 uint32_t id = tty->dev.id;
266 size_t count;
267
268 if (uart->tx_busy)
269 return;
270
271 uart->tx_busy = true;
272 count = aos_tty_tx_buffer_consume(tty, uart->tx_buf, sizeof(uart->tx_buf));
273 hal_uart_dma_send_sync_cache(id, uart->tx_buf, count, NULL, NULL);
274 }
275
tty_uart_stop_tx(aos_tty_t * tty)276 static void tty_uart_stop_tx(aos_tty_t *tty)
277 {
278 tty_uart_t *uart = aos_container_of(tty, tty_uart_t, tty);
279 uint32_t id = tty->dev.id;
280 aos_irqsave_t flags;
281
282 flags = aos_spin_lock_irqsave(&tty->lock);
283
284 if (uart->tx_busy) {
285 uart->tx_busy = false;
286 hal_uart_stop_dma_send(id);
287 }
288
289 aos_spin_unlock_irqrestore(&tty->lock, flags);
290 }
291
292 static const aos_tty_ops_t tty_uart_ops = {
293 .unregister = tty_uart_unregister,
294 .startup = tty_uart_startup,
295 .shutdown = tty_uart_shutdown,
296 .set_attr = tty_uart_set_attr,
297 .enable_rx = tty_uart_enable_rx,
298 .disable_rx = tty_uart_disable_rx,
299 .start_tx = tty_uart_start_tx,
300 .stop_tx = tty_uart_stop_tx,
301 };
302
303 static tty_uart_t tty_uarts[3];
304
tty_uart_rx_handler(tty_uart_t * uart,size_t rx_count)305 static void tty_uart_rx_handler(tty_uart_t *uart, size_t rx_count)
306 {
307 aos_tty_t *tty = &uart->tty;
308 uint32_t id = tty->dev.id;
309 aos_irqsave_t flags;
310
311 flags = aos_spin_lock_irqsave(&tty->lock);
312
313 if (!uart->rx_busy) {
314 aos_spin_unlock_irqrestore(&tty->lock, flags);
315 return;
316 }
317
318 (void)aos_tty_rx_buffer_produce(tty, uart->rx_buf, rx_count);
319 start_rx_dma(uart);
320 aos_spin_unlock_irqrestore(&tty->lock, flags);
321 }
322
tty_uart1_rx_handler(uint32_t xfer_size,int dma_error,union HAL_UART_IRQ_T status)323 static void tty_uart1_rx_handler(uint32_t xfer_size, int dma_error, union HAL_UART_IRQ_T status)
324 {
325 tty_uart_rx_handler(&tty_uarts[1], xfer_size);
326 }
327
tty_uart2_rx_handler(uint32_t xfer_size,int dma_error,union HAL_UART_IRQ_T status)328 static void tty_uart2_rx_handler(uint32_t xfer_size, int dma_error, union HAL_UART_IRQ_T status)
329 {
330 tty_uart_rx_handler(&tty_uarts[2], xfer_size);
331 }
332
tty_uart_tx_handler(tty_uart_t * uart)333 static void tty_uart_tx_handler(tty_uart_t *uart)
334 {
335 aos_tty_t *tty = &uart->tty;
336 uint32_t id = tty->dev.id;
337 size_t count;
338 aos_irqsave_t flags;
339
340 flags = aos_spin_lock_irqsave(&tty->lock);
341
342 if (!uart->tx_busy) {
343 aos_spin_unlock_irqrestore(&tty->lock, flags);
344 return;
345 }
346
347 count = aos_tty_tx_buffer_consume(tty, uart->tx_buf, sizeof(uart->tx_buf));
348 if (count == 0) {
349 uart->tx_busy = false;
350 aos_spin_unlock_irqrestore(&tty->lock, flags);
351 return;
352 }
353
354 hal_uart_dma_send_sync_cache(id, uart->tx_buf, count, NULL, NULL);
355 aos_spin_unlock_irqrestore(&tty->lock, flags);
356 }
357
tty_uart1_tx_handler(uint32_t xfer_size,int dma_error)358 static void tty_uart1_tx_handler(uint32_t xfer_size, int dma_error)
359 {
360 tty_uart_tx_handler(&tty_uarts[1]);
361 }
362
tty_uart2_tx_handler(uint32_t xfer_size,int dma_error)363 static void tty_uart2_tx_handler(uint32_t xfer_size, int dma_error)
364 {
365 tty_uart_tx_handler(&tty_uarts[2]);
366 }
367
tty_uart_init(void)368 static int tty_uart_init(void)
369 {
370 int ret;
371
372 tty_uarts[1].tty.dev.id = 1;
373 tty_uarts[1].tty.ops = &tty_uart_ops;
374 tty_uarts[1].tty.flags = 0;
375 tty_uarts[1].rx_buf = _hal_uart1_buf;
376 tty_uarts[1].rx_handler = tty_uart1_rx_handler;
377 tty_uarts[1].tx_handler = tty_uart1_tx_handler;
378 tty_uarts[1].rx_busy = false;
379 tty_uarts[1].tx_busy = false;
380 ret = (int)aos_tty_register(&tty_uarts[1].tty);
381 if (ret)
382 return ret;
383
384 tty_uarts[2].tty.dev.id = 2;
385 tty_uarts[2].tty.ops = &tty_uart_ops;
386 tty_uarts[2].tty.flags = 0;
387 tty_uarts[2].rx_buf = _hal_uart2_buf;
388 tty_uarts[2].rx_handler = tty_uart2_rx_handler;
389 tty_uarts[2].tx_handler = tty_uart2_tx_handler;
390 tty_uarts[2].rx_busy = false;
391 tty_uarts[2].tx_busy = false;
392 ret = (int)aos_tty_register(&tty_uarts[2].tty);
393 if (ret) {
394 (void)aos_tty_unregister(1);
395 return ret;
396 }
397
398 return 0;
399 }
400
401 LEVEL1_DRIVER_ENTRY(tty_uart_init)
402