1 /*
2 * Copyright (c) 2009-2022 Huawei Technologies Co., Ltd. All rights reserved.
3 *
4 * UniProton is licensed under Mulan PSL v2.
5 * You can use this software according to the terms and conditions of the Mulan PSL v2.
6 * You may obtain a copy of Mulan PSL v2 at:
7 * http://license.coscl.org.cn/MulanPSL2
8 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
9 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
10 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
11 * See the Mulan PSL v2 for more details.
12 * Create: 2009-12-22
13 * Description: UniProton hi3093 demo
14 */
15 #include "serial.h"
16 #include "uart_core.h"
17 #include "uart_regs.h"
18 #include "common.h"
19 #include "prt_typedef.h"
20
uart_busy_timeout(void)21 static S32 uart_busy_timeout(void)
22 {
23 return UART_BUSY_TIMEOUT;
24 }
25
26 /* Caculate UART Divisor Factor */
calc_uart_dll_dlh(U32 uartclk,U32 baudrate,U32 * dll,U32 * dlh)27 void calc_uart_dll_dlh(U32 uartclk, U32 baudrate, U32 *dll, U32 *dlh)
28 {
29 U32 divisor;
30
31 /*
32 * baudrate = bus_clock / (16 * divisor)
33 * ==> divisor = bus_clock/(baudrate * 16) */
34 DIV_ROUND_CLOSEST(uartclk, (16 * baudrate), divisor); /* 16 just for codestyle */
35 *dll = divisor & 0xFF;
36 *dlh = (divisor >> 8) & 0xFF; /* take high 8 bits */
37 }
38
calc_lcr_reg_val(serial_cfg * cfg)39 static U32 calc_lcr_reg_val(serial_cfg *cfg)
40 {
41 U32 lcr = 0;
42
43 switch (cfg->data_bits) {
44 case 8: /* 8个数据位 */
45 lcr |= DW_UART_8bit;
46 break;
47 case 7: /* 7个数据位 */
48 lcr |= DW_UART_7bit;
49 break;
50 case 6: /* 6个数据位 */
51 lcr |= DW_UART_6bit;
52 break;
53 case 5: /* 5个数据位 */
54 lcr |= DW_UART_5bit;
55 break;
56 default:
57 lcr |= DW_UART_8bit;
58 break;
59 }
60
61 /* 0 - 1 stop bit 1 - 2 stop bit */
62 if (cfg->stop == 2) {
63 lcr |= DW_UART_STOP;
64 }
65
66 if (cfg->pen) {
67 lcr |= DW_UART_PEN;
68 if (cfg->eps) {
69 lcr |= DW_UART_EPS;
70 }
71 }
72
73 return lcr;
74 }
75
uart_set_baudrate(serial_cfg * cfg)76 void uart_set_baudrate(serial_cfg *cfg)
77 {
78 U32 dll = 0;
79 U32 dlh = 0;
80
81 /* Wait till uart is idle */
82 (void)uart_wait4idle(cfg->hw_uart_no, uart_busy_timeout());
83 calc_uart_dll_dlh(cfg->uart_src_clk, cfg->baud_rate, &dll, &dlh);
84 uart_set_dll_dlh(cfg->hw_uart_no, dll, dlh);
85 }
86
uart_init(serial_cfg * cfg)87 S32 uart_init(serial_cfg *cfg)
88 {
89 U32 fifo_ctrl;
90
91 /* max data_bits is 8 */
92 if ((cfg == NULL) || (cfg->hw_uart_no >= MAX_UART_NUM) || (cfg->hw_uart_no < 0) || (cfg->data_bits > 8)) {
93 return -EINVAL;
94 }
95
96 /* Config FIFO,DLL,DLH at first */
97 uart_set_baudrate(cfg);
98 fifo_ctrl = FIFOENA | UART_FCR_RXCLR | UART_FCR_TXCLR;
99 uart_set_fifo_ctrl(cfg->hw_uart_no, fifo_ctrl);
100 /* Set data bits, stop bit, parity check */
101 uart_set_lcr(cfg->hw_uart_no, calc_lcr_reg_val(cfg));
102
103 /* enable rx irq */
104 uart_set_irq_enable(cfg->hw_uart_no, 1);
105 return OS_OK;
106 }
107
uart_tx(S32 hw_uart_no,const char c)108 S32 uart_tx(S32 hw_uart_no, const char c)
109 {
110 S32 timeout = 0;
111 S32 max_timeout = uart_busy_timeout();
112
113 while (uart_is_txfifo_full(hw_uart_no)) {
114 timeout++;
115 if (timeout >= max_timeout) {
116 return -ETIME;
117 }
118 }
119
120 uart_tx_char(hw_uart_no, c);
121 return OS_OK;
122 }
123
uart_rx(S32 hw_uart_no)124 S32 uart_rx(S32 hw_uart_no)
125 {
126 S32 timeout = 0;
127 S32 max_timeout = uart_busy_timeout();
128 S32 c = 0;
129
130 while (!uart_is_rx_ready(hw_uart_no)) {
131 timeout++;
132 if (timeout >= max_timeout) {
133 return -ETIME;
134 }
135 }
136
137 uart_rx_char(hw_uart_no, (S8 *)&c);
138 return c;
139 }
140
uart_raw_puts(S32 hw_uart_no,const S8 * str)141 void uart_raw_puts(S32 hw_uart_no, const S8 *str)
142 {
143 while (*str != '\0') {
144 uart_tx_char(hw_uart_no, *str++);
145 }
146 }
147
uart_tx_ready(S32 hw_uart_no)148 S32 uart_tx_ready(S32 hw_uart_no)
149 {
150 if (uart_is_txfifo_full(hw_uart_no)) {
151 return OS_OK;
152 } else {
153 return 1;
154 }
155 }
156
uart_rx_ready(S32 hw_uart_no)157 S32 uart_rx_ready(S32 hw_uart_no)
158 {
159 return uart_is_rx_ready(hw_uart_no);
160 }
161
162 /*
163 * Wait until uart is not busy
164 * Return 0 if success,otherwise return -1
165 */
uart_busy_poll(S32 hw_uart_no)166 S32 uart_busy_poll(S32 hw_uart_no)
167 {
168 return uart_wait4idle(hw_uart_no, uart_busy_timeout());
169 }
170
171 serial_cfg g_uart_cfg = {
172 .name = "uart",
173 .data_bits = 8, /* default data_bits is 8 */
174 .stop = 1,
175 .pen = 0,
176 .baud_rate = 115200 /* default baud_rate is 115200 */
177 };
178
179 uart_ops g_uart_ops = {
180 .init = uart_init,
181 .setbrg = uart_set_baudrate,
182 .put_char = uart_tx,
183 .get_char = uart_rx,
184 .tx_ready = uart_tx_ready,
185 .rx_ready = uart_rx_ready,
186 .wait4idle = uart_wait4idle,
187 };
188