1 /* SPDX-License-Identifier: BSD-3-Clause */
2 /*
3  * Copyright (c) 2020-2021 Rockchip Electronics Co., Ltd.
4  */
5 
6 #include "hal_base.h"
7 
8 #ifdef HAL_UART_MODULE_ENABLED
9 
10 /** @addtogroup RK_HAL_Driver
11  *  @{
12  */
13 
14 /** @addtogroup UART
15  *  @{
16  */
17 
18 /** @defgroup UART_How_To_Use How To Use
19  *  @{
20 
21  The UART driver can be used as follows:
22 
23  @} */
24 
25 /** @defgroup UART_Private_Definition Private Definition
26  *  @{
27  */
28 /********************* Private MACRO Definition ******************************/
29 /********************* Private Structure Definition **************************/
30 /********************* Private Variable Definition ***************************/
31 
32 /********************* Private Function Definition ***************************/
UART_EnableDLAB(struct UART_REG * pReg)33 static void UART_EnableDLAB(struct UART_REG *pReg)
34 {
35     pReg->LCR |= UART_LCR_DLAB;
36 }
37 
UART_DisableDLAB(struct UART_REG * pReg)38 static void UART_DisableDLAB(struct UART_REG *pReg)
39 {
40     pReg->LCR &= ~(UART_LCR_DLAB);
41 }
42 
UART_SetBaudRate(struct UART_REG * pReg,uint32_t clkRate,uint32_t baudRate)43 static int32_t UART_SetBaudRate(struct UART_REG *pReg, uint32_t clkRate,
44                                 uint32_t baudRate)
45 {
46     uint32_t DivLatch;
47 
48     DivLatch = clkRate / MODE_X_DIV / baudRate;
49 
50     pReg->MCR |= UART_MCR_LOOP;
51     UART_EnableDLAB(pReg);
52 
53     pReg->DLL = DivLatch & 0xff;
54     pReg->DLH = (DivLatch >> 8) & 0xff;
55 
56     UART_DisableDLAB(pReg);
57     pReg->MCR &= ~(UART_MCR_LOOP);
58 
59     return (0);
60 }
61 
UART_SetLcrReg(struct UART_REG * pReg,uint8_t byteSize,uint8_t parity,uint8_t stopBits)62 static int32_t UART_SetLcrReg(struct UART_REG *pReg, uint8_t byteSize,
63                               uint8_t parity, uint8_t stopBits)
64 {
65     uint32_t lcr = 0;
66     int32_t bRet = 0;
67 
68     switch (byteSize) {
69     case UART_DATA_5B:
70         lcr |= UART_LCR_WLEN5;
71         break;
72     case UART_DATA_6B:
73         lcr |= UART_LCR_WLEN6;
74         break;
75     case UART_DATA_7B:
76         lcr |= UART_LCR_WLEN7;
77         break;
78     case UART_DATA_8B:
79         lcr |= UART_LCR_WLEN8;
80         break;
81     default:
82         bRet = -1;
83         break;
84     }
85 
86     switch (parity) {
87     case UART_ODD_PARITY:
88     case UART_EVEN_PARITY:
89         lcr |= UART_LCR_PARITY;
90         lcr |= ((parity) << 4);
91         break;
92     case UART_PARITY_DISABLE:
93         lcr &= ~UART_LCR_PARITY;
94         break;
95     default:
96         bRet = -1;
97         break;
98     }
99 
100     if (stopBits == UART_ONE_AND_HALF_OR_TWO_STOPBIT) {
101         lcr |= UART_LCR_STOP;
102     }
103 
104     pReg->LCR = lcr;
105 
106     return (bRet);
107 }
108 
109 /** @} */
110 /********************* Public Function Definition ****************************/
111 
112 /** @defgroup UART_Exported_Functions_Group1 Suspend and Resume Functions
113 
114  This section provides functions allowing to suspend and resume the module:
115 
116  *  @{
117  */
118 /**
119   * @brief  suspend uart
120   * @param  pReg:      uart reg base
121   * @param  pUartSave: save uart reg
122   * @return HAL_OK
123   */
HAL_UART_Suspend(struct UART_REG * pReg,struct UART_SAVE_CONFIG * pUartSave)124 HAL_Status HAL_UART_Suspend(struct UART_REG *pReg, struct UART_SAVE_CONFIG *pUartSave)
125 {
126     HAL_ASSERT(IS_UART_INSTANCE(pReg));
127     if (pUartSave && pReg) {
128         while (!(pReg->USR & UART_USR_TX_FIFO_EMPTY)) {
129             ;
130         }
131         pUartSave->LCR = pReg->LCR;
132         pUartSave->IER = pReg->IER;
133         pUartSave->MCR = pReg->MCR;
134         if (pReg->USR & UART_USR_BUSY) {
135             HAL_DelayMs(10);
136         }
137         if (pReg->USR & UART_USR_BUSY) {
138             pReg->SRR = UART_SRR_XFR | UART_SRR_RFR;
139         }
140         pReg->LCR = UART_LCR_DLAB;
141         pUartSave->DLL = pReg->DLL;
142         pUartSave->DLH = pReg->DLH;
143         pUartSave->SRT = pReg->SRT;
144         pUartSave->STET = pReg->STET;
145         pReg->LCR = pUartSave->LCR;
146     }
147 
148     return HAL_OK;
149 }
150 
151 /**
152   * @brief  resume uart
153   * @param  pReg:      uart reg base
154   * @param  pUartSave: save uart reg
155   * @return HAL_OK
156   */
HAL_UART_Resume(struct UART_REG * pReg,struct UART_SAVE_CONFIG * pUartSave)157 HAL_Status HAL_UART_Resume(struct UART_REG *pReg, struct UART_SAVE_CONFIG *pUartSave)
158 {
159     HAL_ASSERT(IS_UART_INSTANCE(pReg));
160     if (pUartSave && pReg) {
161         pReg->SRR = UART_SRR_XFR | UART_SRR_RFR | UART_SRR_UR;
162         pReg->MCR = UART_MCR_LOOP;
163         pReg->LCR = UART_LCR_DLAB;
164         pReg->DLL = pUartSave->DLL;
165         pReg->DLH = pUartSave->DLH;
166         pReg->LCR = pUartSave->LCR;
167         pReg->IER = pUartSave->IER;
168         pReg->FCR = UART_FCR_ENABLE_FIFO;
169         pReg->MCR = pUartSave->MCR;
170         pReg->SRT = pUartSave->SRT;
171         pReg->STET = pUartSave->STET;
172     }
173 
174     return HAL_OK;
175 }
176 /** @} */
177 
178 /** @defgroup UART_Exported_Functions_Group2 State and Errors Functions
179 
180  This section provides functions allowing to get uart status:
181 
182  *  @{
183  */
184 
185 /**
186   * @brief  get uart sub interrupt number
187   * @param  pReg: uart reg base
188   * @return irq number like UART_IIR_RDI
189   */
HAL_UART_GetIrqID(struct UART_REG * pReg)190 uint32_t HAL_UART_GetIrqID(struct UART_REG *pReg)
191 {
192     HAL_ASSERT(IS_UART_INSTANCE(pReg));
193 
194     return (pReg->IIR & UART_IIR_MASK);
195 }
196 
197 /**
198   * @brief  get uart sub interrupt number
199   * @param  pReg: uart reg base
200   * @return line status
201   */
HAL_UART_GetLsr(struct UART_REG * pReg)202 uint32_t HAL_UART_GetLsr(struct UART_REG *pReg)
203 {
204     HAL_ASSERT(IS_UART_INSTANCE(pReg));
205 
206     return pReg->LSR;
207 }
208 
209 /**
210   * @brief  get uart status
211   * @param  pReg: uart reg base
212   * @return uart status
213   */
HAL_UART_GetUsr(struct UART_REG * pReg)214 uint32_t HAL_UART_GetUsr(struct UART_REG *pReg)
215 {
216     HAL_ASSERT(IS_UART_INSTANCE(pReg));
217 
218     return pReg->USR;
219 }
220 
221 /**
222   * @brief  get uart modem status
223   * @param  pReg: uart reg base
224   * @return uart modem status
225   */
HAL_UART_GetMsr(struct UART_REG * pReg)226 uint32_t HAL_UART_GetMsr(struct UART_REG *pReg)
227 {
228     HAL_ASSERT(IS_UART_INSTANCE(pReg));
229 
230     return pReg->MSR;
231 }
232 
233 /** @} */
234 
235 /** @defgroup UART_Exported_Functions_Group3 IO Functions
236 
237  This section provides functions allowing to IO controlling:
238 
239  *  @{
240  */
241 /**
242   * @brief  send one character
243   * @param  pReg: uart reg base
244   * @param  c: the character to be sent
245   */
HAL_UART_SerialOutChar(struct UART_REG * pReg,char c)246 void HAL_UART_SerialOutChar(struct UART_REG *pReg, char c)
247 {
248     HAL_ASSERT(IS_UART_INSTANCE(pReg));
249 
250     while (!(pReg->USR & UART_USR_TX_FIFO_NOT_FULL)) {
251         ;
252     }
253     pReg->THR = (uint32_t)c;
254 }
255 
256 /**
257   * @brief  send many characters
258   * @param  pReg: uart reg base
259   * @param  pdata: characters buffer
260   * @param  cnt: the number of characters
261   * @return dwRealSize the number has been sent
262   */
HAL_UART_SerialOut(struct UART_REG * pReg,const uint8_t * pdata,uint32_t cnt)263 int HAL_UART_SerialOut(struct UART_REG *pReg, const uint8_t *pdata, uint32_t cnt)
264 {
265     int dwRealSize = 0;
266 
267     HAL_ASSERT(IS_UART_INSTANCE(pReg));
268 
269     while (cnt--) {
270         while (!(pReg->USR & UART_USR_TX_FIFO_NOT_FULL)) {
271             ;
272         }
273         pReg->THR = *pdata++;
274         dwRealSize++;
275     }
276 
277     return dwRealSize;
278 }
279 
280 /**
281   * @brief  receive many characters
282   * @param  pReg: uart reg base
283   * @param  pdata: characters buffer
284   * @param  cnt: the number of characters
285   * @return dwRealSize the number has been received
286   */
HAL_UART_SerialIn(struct UART_REG * pReg,uint8_t * pdata,uint32_t cnt)287 int HAL_UART_SerialIn(struct UART_REG *pReg, uint8_t *pdata, uint32_t cnt)
288 {
289     int dwRealSize = 0;
290 
291     HAL_ASSERT(IS_UART_INSTANCE(pReg));
292 
293     while (cnt--) {
294         if (!(pReg->USR & UART_USR_RX_FIFO_NOT_EMPTY)) {
295             break;
296         }
297 
298         *pdata++ = (uint8_t)pReg->RBR;
299         dwRealSize++;
300     }
301 
302     return dwRealSize;
303 }
304 
305 /** @} */
306 
307 /** @defgroup UART_Exported_Functions_Group4 Init and DeInit Functions
308 
309  This section provides functions allowing to init and deinit the module:
310 
311  *  @{
312  */
313 
314 /**
315   * @brief  reset uart
316   * @param  pReg: uart reg base
317   */
HAL_UART_Reset(struct UART_REG * pReg)318 void HAL_UART_Reset(struct UART_REG *pReg)
319 {
320     HAL_ASSERT(IS_UART_INSTANCE(pReg));
321     pReg->SRR = UART_SRR_UR | UART_SRR_RFR | UART_SRR_XFR;
322     pReg->IER = 0;
323     pReg->DMASA = 1;
324 }
325 
326 /**
327   * @brief  configure uart baudrate,data bit,stop bit and so on
328   * @param  dev: uart hal information
329   * @param  config: uart baud rate,data bit
330   * @return HAL_OK for reserve
331   */
HAL_UART_Init(const struct HAL_UART_DEV * dev,const struct HAL_UART_CONFIG * config)332 HAL_Status HAL_UART_Init(const struct HAL_UART_DEV *dev, const struct HAL_UART_CONFIG *config)
333 {
334     uint32_t newRate;
335     struct UART_REG *pReg;
336 
337     HAL_ASSERT(dev != NULL);
338 
339     pReg = dev->pReg;
340     HAL_ASSERT(IS_UART_INSTANCE(pReg));
341 
342 #ifdef RK_BSP_TEMP
343 #if defined(HAL_CRU_MODULE_ENABLED) && !defined(IS_FPGA)
344     {
345         uint32_t rate;
346 
347         /* set sclk according to uart baud rate */
348         if (config->baudRate <= 115200) {
349             rate = PLL_INPUT_OSC_RATE;
350         } else {
351             rate = config->baudRate * 16;
352         }
353         HAL_CRU_ClkSetFreq(dev->sclkID, rate);
354         newRate = HAL_CRU_ClkGetFreq(dev->sclkID);
355         HAL_ASSERT(rate == newRate);
356     }
357 #elif defined(PLL_INPUT_OSC_RATE) && !defined(IS_FPGA)
358     newRate = PLL_INPUT_OSC_RATE;
359 #else
360     newRate = 24000000;
361 #endif
362 #endif
363     newRate = 24000000;
364 
365     pReg->FCR =
366         UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10 | UART_FCR_T_TRIG_10;
367     UART_SetLcrReg(pReg, config->dataBit, config->parity, config->stopBit);
368     UART_SetBaudRate(pReg, newRate, config->baudRate);
369 
370     return HAL_OK;
371 }
372 
373 /**
374   * @brief  disable uart by resetting it
375   * @param  pReg: uart reg base
376   * @return HAL_OK for reserve
377   */
HAL_UART_DeInit(struct UART_REG * pReg)378 HAL_Status HAL_UART_DeInit(struct UART_REG *pReg)
379 {
380     HAL_ASSERT(IS_UART_INSTANCE(pReg));
381     HAL_UART_Reset(pReg);
382 
383     return HAL_OK;
384 }
385 
386 /** @} */
387 
388 /** @defgroup UART_Exported_Functions_Group5 Other Functions
389 
390  This section provides functions allowing to control uart:
391 
392  *  @{
393  */
394 /**
395   * @brief  enable uart sub interrupt
396   * @param  pReg: uart reg base
397   * @param  uartIntNumb: uart irq num, such as UART_IER_RDI
398   */
HAL_UART_EnableIrq(struct UART_REG * pReg,uint32_t uartIntNumb)399 void HAL_UART_EnableIrq(struct UART_REG *pReg, uint32_t uartIntNumb)
400 {
401     HAL_ASSERT(IS_UART_INSTANCE(pReg));
402     pReg->IER |= uartIntNumb;
403 }
404 
405 /**
406   * @brief  disable uart sub interrupt
407   * @param  pReg: uart reg base
408   * @param  uartIntNumb: uart irq num, such as UART_IER_RDI
409   */
HAL_UART_DisableIrq(struct UART_REG * pReg,uint32_t uartIntNumb)410 void HAL_UART_DisableIrq(struct UART_REG *pReg, uint32_t uartIntNumb)
411 {
412     HAL_ASSERT(IS_UART_INSTANCE(pReg));
413     pReg->IER &= ~uartIntNumb;
414 }
415 
416 /**
417   * @brief  enable uart loop back mode
418   * @param  pReg: uart reg base
419   */
HAL_UART_EnableLoopback(struct UART_REG * pReg)420 void HAL_UART_EnableLoopback(struct UART_REG *pReg)
421 {
422     HAL_ASSERT(IS_UART_INSTANCE(pReg));
423     pReg->MCR |= UART_MCR_LOOP;
424 }
425 
426 /**
427   * @brief  disable uart loop back mode
428   * @param  pReg: uart reg base
429   */
HAL_UART_DisableLoopback(struct UART_REG * pReg)430 void HAL_UART_DisableLoopback(struct UART_REG *pReg)
431 {
432     HAL_ASSERT(IS_UART_INSTANCE(pReg));
433     pReg->MCR &= ~(UART_MCR_LOOP);
434 }
435 
436 /**
437   * @brief  enable uart hardware auto flow control
438   * @param  pReg: uart reg base
439   */
HAL_UART_EnableAutoFlowControl(struct UART_REG * pReg)440 void HAL_UART_EnableAutoFlowControl(struct UART_REG *pReg)
441 {
442     HAL_ASSERT(IS_UART_INSTANCE(pReg));
443     pReg->MCR = UART_MCR_AFE | 0X02;
444 }
445 
446 /**
447   * @brief  disable uart hardware auto flow control
448   * @param  pReg: uart reg base
449   */
HAL_UART_DisableAutoFlowControl(struct UART_REG * pReg)450 void HAL_UART_DisableAutoFlowControl(struct UART_REG *pReg)
451 {
452     HAL_ASSERT(IS_UART_INSTANCE(pReg));
453     pReg->MCR &= ~UART_MCR_AFE;
454 }
455 
456 /**
457   * @brief  low level irq handler, for msi, busy, rlsi
458   * @param  pReg: uart reg base
459   * @return HAL_OK for reserve
460   */
HAL_UART_HandleIrq(struct UART_REG * pReg)461 HAL_Status HAL_UART_HandleIrq(struct UART_REG *pReg)
462 {
463     int iir = 0;
464 
465     HAL_ASSERT(IS_UART_INSTANCE(pReg));
466 
467     iir = HAL_UART_GetIrqID(pReg);
468 
469     /* Handle the three sub interrupts, so the upper irq handler needn't handle those */
470     switch (iir) {
471     case UART_IIR_MSI:
472         HAL_UART_GetMsr(pReg); /* clear MSI only */
473         break;
474     case UART_IIR_BUSY:
475         HAL_UART_GetUsr(pReg); /* clear BUSY interrupt only */
476         break;
477     case UART_IIR_RLSI:
478         HAL_UART_GetMsr(pReg); /* clear RLSI interrupt only */
479         break;
480     case UART_IIR_NO_INT:
481         break;
482     }
483 
484     return HAL_OK;
485 }
486 
487 /** @} */
488 
489 /** @} */
490 
491 /** @} */
492 
493 #endif /* HAL_UART_MODULE_ENABLED */
494