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