1  /*
2  * Copyright (C) 2017-2024 Alibaba Group Holding Limited
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 
19 /******************************************************************************
20  * @file     dw_uart_ll.c
21  * @brief    dw uart ll driver
22  * @version  V1.0
23  * @date     18. December 2024
24  ******************************************************************************/
25 #include <dw_uart_ll.h>
26 
dw_uart_wait_idle(dw_uart_regs_t * uart_base)27 int32_t dw_uart_wait_idle(dw_uart_regs_t *uart_base)
28 {
29     uint32_t timecount = 0U;
30     int32_t ret = 0;
31 
32     while ((uart_base->USR & DW_UART_USR_BUSY_SET) && (timecount < UART_BUSY_TIMEOUT)) {
33         timecount++;
34     }
35 
36     if (timecount >= UART_BUSY_TIMEOUT) {
37         ret = -1;
38     }
39 
40     return ret;
41 }
42 
dw_uart_wait_timeout(dw_uart_regs_t * uart_base)43 int32_t  dw_uart_wait_timeout(dw_uart_regs_t *uart_base)
44 {
45     uint32_t timecount = 0U;
46     int32_t ret = 0;
47 
48     while ((uart_base->LSR & 0x81U) || (uart_base->USR & 0x1U)) {
49         uart_base->LSR;
50         uart_base->RBR;
51         timecount++;
52 
53         if (timecount >= UART_BUSY_TIMEOUT) {
54             ret = -1;
55             break;
56         }
57     }
58 
59     if (ret == 0) {
60         ret = dw_uart_wait_idle(uart_base);
61     }
62 
63     return ret;
64 }
65 
dw_uart_config_baudrate(dw_uart_regs_t * uart_base,uint32_t baud,uint32_t uart_freq)66 int32_t dw_uart_config_baudrate(dw_uart_regs_t *uart_base, uint32_t baud, uint32_t uart_freq)
67 {
68     uint32_t divisor;
69     int32_t ret = 0;
70     ret = dw_uart_wait_timeout(uart_base);
71 
72     if (ret == 0) {
73         if ((uart_freq / 16) % baud >= (baud / 2))
74             divisor = (uart_freq / 16) / baud + 1;
75         else
76             divisor = (uart_freq / 16) / baud;
77 
78         uart_base->LCR |= DW_UART_LCR_DLAB_EN;
79 
80         /* DLL and DLH is lower 8-bits and higher 8-bits of divisor.*/
81         uart_base->DLH = (divisor >> 8U) & 0xFFU;
82         uart_base->DLL = divisor & 0xFFU;
83         /*
84          * The DLAB must be cleared after the baudrate is setted
85          * to access other registers.
86          */
87         uart_base->LCR &= (~DW_UART_LCR_DLAB_EN);
88     }
89 
90     return ret;
91 }
92 
dw_uart_config_stop_bits(dw_uart_regs_t * uart_base,uint32_t stop_bits)93 int32_t  dw_uart_config_stop_bits(dw_uart_regs_t *uart_base, uint32_t stop_bits)
94 {
95     int32_t ret;
96     ret = dw_uart_wait_timeout(uart_base);
97 
98     if (ret == 0) {
99 
100         //when data length is 5 bits, use dw_uart_config_stop_bits_2 will be 1.5 stop bits
101         if (stop_bits == 1U) {
102             dw_uart_config_stop_bits_1(uart_base);
103         } else if (stop_bits == 2U) {
104             dw_uart_config_stop_bits_2(uart_base);
105         }
106     }
107 
108     //FIXME: no console output sometimes
109     mdelay(1);
110 
111     return ret;
112 }
113 
dw_uart_config_parity_none(dw_uart_regs_t * uart_base)114 int32_t dw_uart_config_parity_none(dw_uart_regs_t *uart_base)
115 {
116     int32_t ret;
117     ret = dw_uart_wait_timeout(uart_base);
118 
119     if (ret == 0) {
120         uart_base->LCR &= (~DW_UART_LCR_PEN_EN);
121     }
122 
123     return ret;
124 }
125 
dw_uart_config_parity_odd(dw_uart_regs_t * uart_base)126 int32_t dw_uart_config_parity_odd(dw_uart_regs_t *uart_base)
127 {
128     int32_t ret;
129 
130     ret = dw_uart_wait_timeout(uart_base);
131 
132     if (ret == 0) {
133         uart_base->LCR |= DW_UART_LCR_PEN_EN;
134         uart_base->LCR &= ~(DW_UART_LCR_EPS_EN);
135     }
136 
137     return ret;
138 }
139 
dw_uart_config_parity_even(dw_uart_regs_t * uart_base)140 int32_t dw_uart_config_parity_even(dw_uart_regs_t *uart_base)
141 {
142     int32_t ret;
143 
144     ret = dw_uart_wait_timeout(uart_base);
145 
146     if (ret == 0) {
147         uart_base->LCR |= DW_UART_LCR_PEN_EN;
148         uart_base->LCR |= DW_UART_LCR_EPS_EN;
149     }
150 
151     return ret;
152 }
153 
dw_uart_config_data_bits(dw_uart_regs_t * uart_base,uint32_t data_bits)154 int32_t dw_uart_config_data_bits(dw_uart_regs_t *uart_base, uint32_t data_bits)
155 {
156     int32_t ret;
157 
158     ret = dw_uart_wait_timeout(uart_base);
159 
160     uart_base->LCR &= 0xFCU;
161     uart_base->LCR |= (data_bits - 5U);
162 
163     return ret;
164 }
165