• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 }