1 /*
2 * Copyright (c) 2022 ASR Microelectronics (Shanghai) Co., Ltd. All rights reserved.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "duet_uart.h"
17 #include <stdbool.h>
18 #include "duet_dma.h"
19
20 #define DUET_UART0_USE_DMA 1
21 #if DUET_UART0_USE_DMA
22 #define DMA_MAX_SIZE 256
23 volatile uint8_t uart_dma_complete_flag = 1;
24 static uint8_t uart_dma_tx_mem[DMA_MAX_SIZE] = {0};
uart0_dma_callback(uint32_t i)25 void uart0_dma_callback(uint32_t i)
26 {
27 uart_dma_complete_flag = 1;
28 }
29 #endif
30 duet_uart_callback_func g_duet_uart_callback_handler[UART_NUM] = {0};
31
getUartxViaIdx(uint8_t uart_idx)32 UART_TypeDef *getUartxViaIdx(uint8_t uart_idx)
33 {
34 switch (uart_idx) {
35 case UART0_INDEX:
36 return UART0;
37 case UART1_INDEX:
38 return UART1;
39 case UART2_INDEX:
40 return UART2;
41 default:
42 return NULL;
43 }
44 }
45
duet_uart_struct_init(duet_uart_dev_t * UART_InitStruct)46 void duet_uart_struct_init(duet_uart_dev_t *UART_InitStruct)
47 {
48 UART_InitStruct->config.baud_rate = UART_BAUDRATE_115200;
49 UART_InitStruct->config.data_width = DATA_8BIT;
50 UART_InitStruct->config.parity = PARITY_NO;
51 UART_InitStruct->config.stop_bits = STOP_1BIT;
52 UART_InitStruct->config.flow_control = FLOW_CTRL_DISABLED;
53 UART_InitStruct->config.mode = TX_RX_MODE;
54 UART_InitStruct->priv = NULL;
55 }
56
duet_uart_calc_baud(uint32_t baud)57 uint32_t duet_uart_calc_baud(uint32_t baud)
58 {
59 uint32_t int_div;
60 uint32_t fac_div;
61 uint32_t remainder;
62 uint32_t temp;
63 uint32_t uart_clk = UART_CLK;
64
65 temp = 16 * baud;
66 if ((0 == baud) || uart_clk < temp) {
67 return 0;
68 }
69 int_div = (uint32_t)(uart_clk / temp);
70 remainder = uart_clk % temp;
71 temp = 8 * remainder / baud;
72 fac_div = (temp >> 1) + (temp & 1);
73
74 temp = ((int_div << 16) | (fac_div & 0xFFFF));
75 return temp;
76 }
77
78 /* get uart flag status */
duet_uart_get_flag_status(UART_TypeDef * UARTx,uint8_t uart_flag)79 ITstatus duet_uart_get_flag_status(UART_TypeDef *UARTx, uint8_t uart_flag)
80 {
81 if (UARTx->FR & uart_flag) {
82 return SET;
83 } else {
84 return RESET;
85 }
86 }
87
UART_SendData(UART_TypeDef * UARTx,unsigned char Data)88 void UART_SendData(UART_TypeDef *UARTx, unsigned char Data)
89 {
90 if (UARTx == NULL) {
91 return;
92 }
93 /* wait till tx fifo is not full */
94 while (duet_uart_get_flag_status(UARTx, UART_FLAG_TX_FIFO_FULL) == SET);
95 UARTx->DR = Data;
96 }
97
UART_ReceiveData(UART_TypeDef * UARTx)98 uint8_t UART_ReceiveData(UART_TypeDef *UARTx)
99 {
100 /* wait till rx fifo is not empty */
101 while (duet_uart_get_flag_status(UARTx, UART_FLAG_RX_FIFO_EMPTY) == SET);
102 return UARTx->DR;
103 }
104
duet_uart_interrupt_config(UART_TypeDef * UARTx,uint32_t uart_int,bool new_state)105 void duet_uart_interrupt_config(UART_TypeDef *UARTx, uint32_t uart_int, bool new_state)
106 {
107 if (new_state == DISABLE) {
108 UARTx->IMSC &= ~(uart_int);
109 } else {
110 UARTx->IMSC |= (uart_int);
111 }
112 }
113
duet_uart_get_interrupt_status(UART_TypeDef * UARTx,uint32_t uart_interrupt)114 ITstatus duet_uart_get_interrupt_status(UART_TypeDef *UARTx, uint32_t uart_interrupt)
115 {
116 if (UARTx->MIS & uart_interrupt) {
117 return SET;
118 } else {
119 return RESET;
120 }
121 }
122
duet_uart_get_raw_interrupt_status(UART_TypeDef * UARTx,uint32_t uart_interrupt)123 ITstatus duet_uart_get_raw_interrupt_status(UART_TypeDef *UARTx, uint32_t uart_interrupt)
124 {
125 if (UARTx->RIS & uart_interrupt) {
126 return SET;
127 } else {
128 return RESET;
129 }
130 }
131
duet_uart_clear_interrupt(UART_TypeDef * UARTx,uint32_t uart_interrupt)132 uint8_t duet_uart_clear_interrupt(UART_TypeDef *UARTx, uint32_t uart_interrupt)
133 {
134 UARTx->ICR |= uart_interrupt;
135 return 0;
136 }
137
duet_uart_dma_config(duet_uart_dev_t * uart,uint8_t dma_tx_rx_sel,uint8_t new_state)138 int32_t duet_uart_dma_config(duet_uart_dev_t *uart, uint8_t dma_tx_rx_sel, uint8_t new_state)
139 {
140 UART_TypeDef *UARTx = NULL;
141 if (DUET_UART0_INDEX == uart->port) {
142 UARTx = UART0;
143 } else if (DUET_UART1_INDEX == uart->port) {
144 UARTx = UART1;
145 } else if (DUET_UART2_INDEX == uart->port) {
146 UARTx = UART2;
147 } else {
148 return EIO;
149 }
150 if (new_state == ENABLE) {
151 UARTx->DMACR |= dma_tx_rx_sel;
152 } else {
153 UARTx->DMACR &= ~dma_tx_rx_sel;
154 }
155 return 0;
156 }
157
158 /**
159 * Initialises a UART interface
160 *
161 *
162 * @param[in] uart the interface which should be initialised
163 *
164 * @return 0 : on success, EIO : if an error occurred with any step
165 */
duet_uart_init(duet_uart_dev_t * uart)166 int32_t duet_uart_init(duet_uart_dev_t *uart)
167 {
168 // uart sclk enable and sclk root clk setting (XTAL)
169 uint32_t tmp_value;
170 UART_TypeDef *UARTx = NULL;
171 if (DUET_UART0_INDEX == uart->port) {
172 UARTx = UART0;
173 } else if (DUET_UART1_INDEX == uart->port) {
174 UARTx = UART1;
175 } else if (DUET_UART2_INDEX == uart->port) {
176 UARTx = UART2;
177 } else {
178 return EIO;
179 }
180 // enable uart clk
181 if (UARTx == UART0) {
182 tmp_value = REG_RD(PERI_CLK_EN_REG1) & (~(UART0_BUS_CLK_EN | UART0_PERI_CLK_EN));
183 REG_WR(PERI_CLK_EN_REG1, (tmp_value | (UART0_BUS_CLK_EN | UART0_PERI_CLK_EN)));
184 } else if (UARTx == UART1) {
185 tmp_value = REG_RD(PERI_CLK_EN_REG1) & (~(UART1_BUS_CLK_EN | UART1_PERI_CLK_EN));
186 REG_WR(PERI_CLK_EN_REG1, (tmp_value | (UART1_BUS_CLK_EN | UART1_PERI_CLK_EN)));
187 } else {
188 tmp_value = REG_RD(PERI_CLK_EN_REG1) & (~(UART2_BUS_CLK_EN | UART2_PERI_CLK_EN));
189 REG_WR(PERI_CLK_EN_REG1, (tmp_value | (UART2_BUS_CLK_EN | UART2_PERI_CLK_EN)));
190 }
191
192 // fpga no effect, soc need
193
194 // wait for the end of current charater
195 while (duet_uart_get_flag_status(UARTx, UART_FLAG_BUSY));
196
197 // disable UART
198 UARTx->CR &= ~1;
199
200 // flush fifo by setting FEN = 0
201 UARTx->LCR_H &= ~(1 << 4);
202
203 // set baudrate
204 uint32_t br_div = duet_uart_calc_baud(uart->config.baud_rate);
205 UARTx->IBRD = br_div >> 16; /* baudrate divdier register must be placed before a LCR_H write */
206 UARTx->FBRD = br_div & 0x3f;
207
208 // set LCR_H
209 UARTx->LCR_H |= (uart->config.data_width << 5) | (uart->config.stop_bits << 3);
210
211 switch (uart->config.parity) {
212 case PARITY_ODD:
213 UARTx->LCR_H &= ~(3 << 1);
214 UARTx->LCR_H |= (1 << 1);
215 break;
216 case PARITY_EVEN:
217 UARTx->LCR_H |= (3 << 1);
218 break;
219 case PARITY_NO:
220 UARTx->LCR_H &= ~(1 << 1);
221 break;
222 default:
223 break;
224 }
225 if (uart->config.mode == 0) {
226 uart->config.mode = TX_RX_MODE;
227 }
228 // set CR
229 UARTx->CR &= ~(3 << 8); // set tx/rx mode to 0
230 UARTx->CR |= (uart->config.flow_control << 14) | (uart->config.mode << 8);
231 // enable fifo
232 UARTx->LCR_H |= (ENABLE << 4);
233 UARTx->IFLS &= ~(0x7);
234 UARTx->IFLS |= FIFO_HALF_FULL; // tx fifo threshold
235 UARTx->IFLS &= ~(0x7 << 3);
236 UARTx->IFLS |= (FIFO_HALF_FULL << 3); // rx fifo threshold
237
238 if (uart->priv) {
239 // enable rx interrupt
240 UARTx->IMSC |= (UART_RX_TIMEOUT_INTERRUPT | UART_RX_INTERRUPT);
241 // enable cm4 interrupt
242 if (UARTx == UART0) {
243 tmp_value = REG_RD(DUTE_IRQ_EN_REG) & (~UART0_IRQ_BIT);
244 REG_WR(DUTE_IRQ_EN_REG, (tmp_value | (UART0_IRQ_BIT)));
245 NVIC_EnableIRQ(UART0_IRQn);
246 #if DUET_UART0_USE_DMA
247 duet_dma_init();
248 duet_uart_dma_config(uart, UART_DMA_TX_EN, ENABLE);
249 duet_dma_callback_register(DMA_CH_UART0_TX, uart0_dma_callback);
250 uart_dma_complete_flag = 1;
251 #endif
252 } else if (UARTx == UART1) {
253 tmp_value = REG_RD(DUTE_IRQ_EN_REG) & (~UART1_IRQ_BIT);
254 REG_WR(DUTE_IRQ_EN_REG, (tmp_value | (UART1_IRQ_BIT)));
255 NVIC_EnableIRQ(UART1_IRQn);
256 } else {
257 tmp_value = REG_RD(DUTE_IRQ_EN_REG) & (~UART2_IRQ_BIT);
258 REG_WR(DUTE_IRQ_EN_REG, (tmp_value | (UART2_IRQ_BIT)));
259 NVIC_EnableIRQ(UART2_IRQn);
260 }
261 g_duet_uart_callback_handler[uart->port] = (duet_uart_callback_func)(uart->priv);
262 }
263 UARTx->CR |= 0x1;
264 return 0;
265 }
266
duet_uart_start(UART_TypeDef * UARTx)267 void duet_uart_start(UART_TypeDef *UARTx)
268 {
269
270 UARTx->CR |= 0x1;
271
272 if (UART0 == UARTx) {
273 NVIC_EnableIRQ(UART0_IRQn);
274 } else if (UART1 == UARTx) {
275 NVIC_EnableIRQ(UART1_IRQn);
276 }
277 if (UART2 == UARTx) {
278 NVIC_EnableIRQ(UART2_IRQn);
279 }
280 }
281
duet_uart_stop(UART_TypeDef * UARTx)282 void duet_uart_stop(UART_TypeDef *UARTx)
283 {
284 UARTx->CR &= ~0x1;
285
286 if (UART0 == UARTx) {
287 NVIC_DisableIRQ(UART0_IRQn);
288 } else if (UART1 == UARTx) {
289 NVIC_DisableIRQ(UART1_IRQn);
290 }
291 if (UART2 == UARTx) {
292 NVIC_DisableIRQ(UART2_IRQn);
293 }
294 }
295
296 /**
297 * Transmit data on a UART interface
298 *
299 * @param[in] uart the UART interface
300 * @param[in] data pointer to the start of data
301 * @param[in] size number of bytes to transmit
302 *
303 * @return 0 : on success, EIO : if an error occurred with any step
304 */
305 extern bool lega_log_is_enable(void);
duet_uart_send(duet_uart_dev_t * uart,const void * data,uint32_t size,uint32_t timeout)306 int32_t duet_uart_send(duet_uart_dev_t *uart, const void *data, uint32_t size, uint32_t timeout)
307 {
308 UART_TypeDef *UARTx;
309 int i = 0;
310
311 if ((NULL == uart) || (NULL == data)) {
312 return EIO;
313 }
314
315 if (DUET_UART0_INDEX == uart->port) {
316 UARTx = UART0;
317 #if DUET_UART0_USE_DMA
318 while (size > DMA_MAX_SIZE) {
319 while (!uart_dma_complete_flag);
320 uart_dma_complete_flag = 0;
321 duet_dma_uart_tx(uart->port, data, DMA_MAX_SIZE);
322 size -= DMA_MAX_SIZE;
323 data += DMA_MAX_SIZE;
324 }
325 while (!uart_dma_complete_flag);
326 uart_dma_complete_flag = 0;
327 memcpy(uart_dma_tx_mem, data, size);
328 duet_dma_uart_tx(uart->port, uart_dma_tx_mem, size);
329 return 0;
330 #endif
331 } else if (DUET_UART1_INDEX == uart->port) {
332 if (!lega_log_is_enable()) {
333 return 0;
334 }
335 UARTx = UART1;
336 } else if (DUET_UART2_INDEX == uart->port) {
337 UARTx = UART2;
338 } else {
339 return EIO;
340 }
341
342 for (i = 0; i < size; i++) {
343 UART_SendData(UARTx, ((uint8_t *)data)[i]);
344 }
345
346 return 0;
347 }
348
349 /**
350 * Deinitialises a UART interface
351 *
352 * @param[in] uart the interface which should be deinitialised
353 *
354 * @return 0 : on success, EIO : if an error occurred with any step
355 */
duet_uart_finalize(duet_uart_dev_t * uart)356 int32_t duet_uart_finalize(duet_uart_dev_t *uart)
357 {
358 UART_TypeDef *UARTx;
359 unsigned int tmp_value;
360
361 if (NULL == uart) {
362 return EIO;
363 }
364
365 if (DUET_UART0_INDEX == uart->port) {
366 UARTx = UART0;
367 } else if (DUET_UART1_INDEX == uart->port) {
368 UARTx = UART1;
369 } else if (DUET_UART2_INDEX == uart->port) {
370 UARTx = UART2;
371 } else {
372 return EIO;
373 }
374
375 // disable all uart interrupt
376 UARTx->IMSC = UART_DISABLE_ALL_IRQ;
377 // disable all uart config
378 UARTx->LCR_H = 0;
379 UARTx->CR = 0;
380
381 // disable cm4 interrupt
382 if (UART0 == UARTx) {
383 tmp_value = REG_RD(DUTE_IRQ_DIS_REG) & (~UART0_IRQ_BIT);
384 REG_WR(DUTE_IRQ_DIS_REG, (tmp_value | (UART0_IRQ_BIT)));
385 NVIC_DisableIRQ(UART0_IRQn);
386 } else if (UART1 == UARTx) {
387 tmp_value = REG_RD(DUTE_IRQ_DIS_REG) & (~UART1_IRQ_BIT);
388 REG_WR(DUTE_IRQ_DIS_REG, (tmp_value | (UART1_IRQ_BIT)));
389 NVIC_DisableIRQ(UART1_IRQn);
390 } else {
391 tmp_value = REG_RD(DUTE_IRQ_DIS_REG) & (~UART2_IRQ_BIT);
392 REG_WR(DUTE_IRQ_DIS_REG, (tmp_value | (UART2_IRQ_BIT)));
393 NVIC_DisableIRQ(UART2_IRQn);
394 }
395
396 // uart sclk disable, fpga no effect, soc need
397 if (UART0 == UARTx) {
398 tmp_value = REG_RD(PERI_CLK_DIS_REG1) & (~(UART0_BUS_CLK_EN | UART0_PERI_CLK_EN));
399 REG_WR(PERI_CLK_DIS_REG1, (tmp_value | (UART0_BUS_CLK_EN | UART0_PERI_CLK_EN)));
400 #if DUET_UART0_USE_DMA
401 uart_dma_complete_flag = 1;
402 #endif
403 } else if (UART1 == UARTx) {
404 tmp_value = REG_RD(PERI_CLK_DIS_REG1) & (~(UART0_BUS_CLK_EN | UART0_PERI_CLK_EN));
405 REG_WR(PERI_CLK_DIS_REG1, (tmp_value | (UART0_BUS_CLK_EN | UART0_PERI_CLK_EN)));
406 } else {
407 tmp_value = REG_RD(PERI_CLK_DIS_REG1) & (~(UART0_BUS_CLK_EN | UART0_PERI_CLK_EN));
408 REG_WR(PERI_CLK_DIS_REG1, (tmp_value | (UART0_BUS_CLK_EN | UART0_PERI_CLK_EN)));
409 }
410
411 g_duet_uart_callback_handler[uart->port] = NULL;
412 return 0;
413 }
414
UARTX_IRQHandler(uint8_t uart_idx)415 static void UARTX_IRQHandler(uint8_t uart_idx)
416 {
417 char tmp;
418 UART_TypeDef *UARTx = getUartxViaIdx(uart_idx);
419 if (duet_uart_get_interrupt_status(UARTx, UART_RX_INTERRUPT)
420 || duet_uart_get_interrupt_status(UARTx, UART_RX_TIMEOUT_INTERRUPT)) {
421 duet_uart_interrupt_config(UARTx, UART_RX_INTERRUPT | UART_RX_TIMEOUT_INTERRUPT, DISABLE);
422 duet_uart_clear_interrupt(UARTx, UART_RX_INTERRUPT | UART_RX_TIMEOUT_INTERRUPT);
423
424 /* read rx fifo till it's empty */
425 while (! duet_uart_get_flag_status(UARTx, UART_FLAG_RX_FIFO_EMPTY)) {
426 tmp = (char)(UARTx->DR); // uart_receive_data(UART);
427 if (g_duet_uart_callback_handler[uart_idx] != NULL) {
428 g_duet_uart_callback_handler[uart_idx](tmp);
429 }
430 }
431
432 duet_uart_interrupt_config(UARTx, UART_RX_INTERRUPT | UART_RX_TIMEOUT_INTERRUPT, ENABLE);
433 }
434 }
435
436 #if (LOSCFG_USE_SHELL == 1)
437 #include "los_event.h"
438 #include "target_config.h"
439 extern EVENT_CB_S g_shellInputEvent;
UARTX_Shell_IRQHandler(uint8_t uart_idx)440 static void UARTX_Shell_IRQHandler(uint8_t uart_idx)
441 {
442 // char tmp;
443 UART_TypeDef *UARTx = getUartxViaIdx(uart_idx);
444 if (duet_uart_get_interrupt_status(UARTx, UART_RX_INTERRUPT)
445 || duet_uart_get_interrupt_status(UARTx, UART_RX_TIMEOUT_INTERRUPT)) {
446 duet_uart_interrupt_config(UARTx, UART_RX_INTERRUPT | UART_RX_TIMEOUT_INTERRUPT, DISABLE);
447 duet_uart_clear_interrupt(UARTx, UART_RX_INTERRUPT | UART_RX_TIMEOUT_INTERRUPT);
448
449 if (uart_idx == UART1_INDEX) {
450 (void)LOS_EventWrite(&g_shellInputEvent, 0x1);
451 }
452
453 duet_uart_interrupt_config(UARTx, UART_RX_INTERRUPT | UART_RX_TIMEOUT_INTERRUPT, ENABLE);
454 }
455 }
456 #endif
457
UART0_IRQHandler(void)458 void UART0_IRQHandler(void)
459 {
460 duet_intrpt_enter();
461 UARTX_IRQHandler(0);
462 duet_intrpt_exit();
463 }
464
UART1_IRQHandler(void)465 void UART1_IRQHandler(void)
466 {
467 duet_intrpt_enter();
468 #if (LOSCFG_USE_SHELL == 1)
469 UARTX_Shell_IRQHandler(1);
470 #else
471 UARTX_IRQHandler(1);
472 #endif
473 duet_intrpt_exit();
474 }
475
UART2_IRQHandler(void)476 void UART2_IRQHandler(void)
477 {
478 duet_intrpt_enter();
479 UARTX_IRQHandler(2);
480 duet_intrpt_exit();
481 }
482
duet_uart_set_callback(uint8_t uart_idx,duet_uart_callback_func func)483 void duet_uart_set_callback(uint8_t uart_idx, duet_uart_callback_func func)
484 {
485 g_duet_uart_callback_handler[uart_idx] = func;
486
487 }