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