1 /*
2 * Copyright (c) 2020 HiSilicon (Shanghai) Technologies CO., LIMITED.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "hi_uart.h"
17
18 #include <hi_lowpower.h>
19 #include <hi_stdlib.h>
20 #ifdef CONFIG_UART_DMA_SUPPORT
21 #include <hi_dma.h>
22 #endif
23
24 #include "hi_early_debug.h"
25 #include "uart.h"
26 #include "uart_drv.h"
27
28 #define UART_FR_BUSY (1 << 3)
29 #define UART_FR_TXFE (1 << 7)
30 #define UART_FR_RXFE (1 << 4)
31 #define WAIT_TIME 10000 /* wait 10 seconds */
32 #define CLKEN_UART2 6
33 #define CLKEN_UART2_BUS 9
34 #define OFFSET_14_BITS 14
35 #define UART_DR 0x0
36 #define UART_FR 0x18
37 #define UART_IBRD 0x24
38 #define UART_FBRD 0x28
39 #define UART_LCR_H 0x2C
40 #define UART_CR 0x30
41 #define UART_IFLS 0x34
42 #define UART_IMSC 0x38
43 #define UART_DMACR 0x48
44 #define UART_DMA_DISABLE 0X04
45 #define UARTCR_CFG 0x301 /* UART tx enable, rx enable, uart enable */
46
47 #ifndef UART_FR
48 #define UART_FR 0x18
49 #endif
50
51 typedef struct {
52 hi_u16 ibrd;
53 hi_u16 fbrd;
54 hi_u16 lcr_h;
55 hi_u16 cr;
56 hi_u16 ifls;
57 } uart_regs;
58
59 uart_regs g_uart_regs_save[UART_NUM] = {0};
60
61 hi_u32 g_uart_timer_handle[UART_NUM] = {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF};
62 volatile hi_bool g_uart_timeout[UART_NUM] = {0};
63
init_uart_param(uart_attr_t * uart_attr,const hi_uart_attribute * attr)64 static void init_uart_param(uart_attr_t *uart_attr, const hi_uart_attribute *attr)
65 {
66 uart_attr->baud_rate = attr->baud_rate;
67 uart_attr->data_bits = attr->data_bits;
68 uart_attr->stop_bits = attr->stop_bits;
69 uart_attr->parity = attr->parity;
70 uart_attr->pad = attr->pad;
71 }
72
get_uart_param(const uart_driver_data_t * udd,hi_uart_attribute * attr,hi_uart_extra_attr * extra_attr)73 static hi_u32 get_uart_param(const uart_driver_data_t *udd, hi_uart_attribute *attr, hi_uart_extra_attr *extra_attr)
74 {
75 if (udd == HI_NULL) {
76 return HI_ERR_UART_INVALID_PARAMETER;
77 }
78
79 if (udd->state != UART_STATE_USEABLE) {
80 uart_set_errno(UART_ERR_NOT_OPENED);
81 return HI_ERR_FAILURE;
82 }
83
84 if (extra_attr != HI_NULL) {
85 extra_attr->tx_fifo_line = (hi_uart_fifo_line)(udd->attr.tx_fifo_line + 1);
86 extra_attr->rx_fifo_line = (hi_uart_fifo_line)(udd->attr.rx_fifo_line + 1);
87 extra_attr->flow_fifo_line = (hi_uart_fifo_line)(udd->attr.flow_fifo_line + 1);
88
89 extra_attr->tx_block = (hi_uart_block_state)udd->act.tx_block;
90 extra_attr->rx_block = (hi_uart_block_state)udd->act.rx_block;
91 extra_attr->tx_buf_size = udd->act.tx_buffer_size;
92 extra_attr->rx_buf_size = udd->act.rx_buffer_size;
93 extra_attr->tx_use_dma = (hi_uart_dma_state)udd->act.tx_use_dma;
94 extra_attr->rx_use_dma = (hi_uart_dma_state)udd->act.rx_use_dma;
95 }
96
97 attr->baud_rate = udd->attr.baud_rate;
98 attr->data_bits = udd->attr.data_bits;
99 attr->stop_bits = udd->attr.stop_bits;
100 attr->parity = udd->attr.parity;
101 attr->pad = udd->attr.pad;
102
103 return HI_ERR_SUCCESS;
104 }
105
hi_uart_is_busy(hi_uart_idx id,hi_bool * busy)106 BSP_RAM_TEXT_SECTION hi_u32 hi_uart_is_busy(hi_uart_idx id, hi_bool *busy)
107 {
108 hi_u32 port_num = (hi_u32) id;
109 uart_driver_data_t *udd = HI_NULL;
110 hi_u32 val;
111 if (port_num >= UART_NUM || busy == HI_NULL) {
112 return HI_ERR_UART_INVALID_PARAMETER;
113 }
114 udd = g_udd_g[port_num];
115 hi_reg_read32(udd->phys_base + UART_FR, val);
116 if (val & UART_FR_BUSY) {
117 *busy = HI_TRUE;
118 } else {
119 *busy = HI_FALSE;
120 }
121 return HI_ERR_SUCCESS;
122 }
123
hi_uart_is_buf_empty(hi_uart_idx id,hi_bool * empty)124 BSP_RAM_TEXT_SECTION hi_u32 hi_uart_is_buf_empty(hi_uart_idx id, hi_bool *empty)
125 {
126 hi_u32 port_num = (hi_u32) id;
127 uart_driver_data_t *udd = HI_NULL;
128 hi_u32 val;
129 hi_u32 ret;
130 if (port_num >= UART_NUM || empty == HI_NULL) {
131 return HI_ERR_UART_INVALID_PARAMETER;
132 }
133 udd = g_udd_g[port_num];
134 hi_reg_read32(udd->phys_base + UART_FR, val);
135 if (((val & UART_FR_RXFE) == 0) || ((val & UART_FR_TXFE) == 0)) {
136 *empty = HI_FALSE;
137 return HI_ERR_SUCCESS;
138 }
139 ret = uart_ioctl(udd, UART_CFG_GET_BUF_EMPTY, (hi_u32)(uintptr_t)&val);
140 if ((val == 0) && (ret == HI_ERR_SUCCESS)) {
141 *empty = HI_FALSE;
142 } else {
143 *empty = HI_TRUE;
144 }
145 return ret;
146 }
147
uart_check_extra_param(const hi_uart_extra_attr * extra_attr)148 hi_bool uart_check_extra_param(const hi_uart_extra_attr *extra_attr)
149 {
150 if (extra_attr->tx_fifo_line <= HI_FIFO_LINE_SEVEN_EIGHTS &&
151 extra_attr->rx_fifo_line <= HI_FIFO_LINE_SEVEN_EIGHTS &&
152 extra_attr->flow_fifo_line <= HI_FIFO_LINE_SEVEN_EIGHTS &&
153 extra_attr->tx_block <= HI_UART_BLOCK_STATE_BLOCK &&
154 extra_attr->rx_block <= HI_UART_BLOCK_STATE_BLOCK &&
155 extra_attr->tx_use_dma <= HI_UART_USE_DMA &&
156 extra_attr->rx_use_dma <= HI_UART_USE_DMA) {
157 return HI_TRUE;
158 }
159
160 return HI_FALSE;
161 }
162
init_uart_extra_param(hi_u32 port_num,const hi_uart_extra_attr * extra_attr)163 hi_u32 init_uart_extra_param(hi_u32 port_num, const hi_uart_extra_attr *extra_attr)
164 {
165 uart_driver_data_t *udd = HI_NULL;
166
167 udd = g_udd_g[port_num];
168
169 if (udd == HI_NULL || uart_check_extra_param(extra_attr) != HI_TRUE) {
170 return HI_ERR_UART_INVALID_PARAMETER;
171 }
172
173 if (udd->state != UART_STATE_NOT_OPENED) {
174 uart_set_errno(UART_ERR_NOT_IDLE);
175 return HI_ERR_FAILURE;
176 }
177
178 if (extra_attr->tx_fifo_line != 0) {
179 udd->attr.tx_fifo_line = (hi_u8)(extra_attr->tx_fifo_line) - 1;
180 }
181 if (extra_attr->rx_fifo_line != 0) {
182 udd->attr.rx_fifo_line = (hi_u8)(extra_attr->rx_fifo_line) - 1;
183 }
184 if (extra_attr->flow_fifo_line != 0) {
185 udd->attr.flow_fifo_line = (hi_u8)(extra_attr->flow_fifo_line) - 1;
186 }
187 if (extra_attr->tx_block != 0) {
188 udd->act.tx_block = extra_attr->tx_block;
189 }
190 if (extra_attr->rx_block != 0) {
191 udd->act.rx_block = extra_attr->rx_block;
192 }
193 if (extra_attr->tx_buf_size != 0) {
194 udd->act.tx_buffer_size = extra_attr->tx_buf_size;
195 }
196 if (extra_attr->rx_buf_size != 0) {
197 udd->act.rx_buffer_size = extra_attr->rx_buf_size;
198 }
199 if (extra_attr->tx_use_dma == UART_TX_USE_DMA) {
200 #ifdef CONFIG_UART_DMA_SUPPORT
201 udd->act.tx_use_dma = extra_attr->tx_use_dma;
202 #else
203 return HI_ERR_UART_NOT_SUPPORT_DMA;
204 #endif
205 }
206 if (extra_attr->rx_use_dma == UART_RX_USE_DMA) {
207 #ifdef CONFIG_UART_DMA_SUPPORT
208 udd->act.rx_use_dma = extra_attr->rx_use_dma;
209 #else
210 return HI_ERR_UART_NOT_SUPPORT_DMA;
211 #endif
212 }
213 return HI_ERR_SUCCESS;
214 }
215
uart_attribute_ioctl(uart_driver_data_t * udd,const hi_uart_attribute * attr)216 hi_u32 uart_attribute_ioctl(uart_driver_data_t *udd, const hi_uart_attribute *attr)
217 {
218 if (udd == HI_NULL) {
219 return HI_ERR_UART_INVALID_PARAMETER;
220 }
221 uart_attr_t uart_attr = { 0 };
222
223 if (memcpy_s(&uart_attr, sizeof(uart_attr_t), &udd->attr, sizeof(uart_attr_t)) != EOK) {
224 return HI_ERR_FAILURE;
225 }
226 init_uart_param(&uart_attr, attr);
227
228 return uart_ioctl(udd, UART_CFG_SET_ATTR, (uintptr_t)&uart_attr);
229 }
230
hi_uart_init(hi_uart_idx id,const hi_uart_attribute * param,const hi_uart_extra_attr * extra_attr)231 hi_u32 hi_uart_init(hi_uart_idx id, const hi_uart_attribute *param, const hi_uart_extra_attr *extra_attr)
232 {
233 hi_u32 port_num = (hi_u32) id;
234 uart_driver_data_t *udd = HI_NULL;
235
236 if (port_num >= UART_NUM || param == HI_NULL) {
237 return HI_ERR_UART_INVALID_PARAMETER;
238 }
239
240 if (extra_attr != HI_NULL) {
241 hi_u32 ret = init_uart_extra_param(port_num, extra_attr);
242 if (ret != HI_ERR_SUCCESS) {
243 return ret;
244 }
245 }
246 if (id == HI_UART_IDX_2) {
247 hi_u16 reg_val;
248 hi_reg_read16(W_CTL_UART_MAC80M_CLKEN_REG, reg_val);
249 reg_val |= (1 << CLKEN_UART2) | (1 << CLKEN_UART2_BUS);
250 hi_reg_write16(W_CTL_UART_MAC80M_CLKEN_REG, reg_val); /* enable uart2 clk */
251 }
252 udd = uart_open(port_num, UART_232);
253 if (udd == HI_NULL) {
254 return HI_ERR_FAILURE;
255 }
256
257 #ifdef CONFIG_UART_DMA_SUPPORT
258 if (extra_attr != HI_NULL && (extra_attr->tx_use_dma == HI_TRUE || extra_attr->rx_use_dma == HI_TRUE)) {
259 if (hi_dma_is_init() == HI_FALSE) {
260 hi_u32 ret = hi_dma_init();
261 if (ret != HI_ERR_SUCCESS) {
262 return ret;
263 }
264 }
265 }
266 #endif
267
268 if (g_uart_timer_handle[id] == 0xFFFFFFFF) {
269 hi_u32 ret = hi_timer_create(&(g_uart_timer_handle[id]));
270 if (ret != HI_ERR_SUCCESS) {
271 return ret;
272 }
273 }
274
275 return uart_attribute_ioctl(udd, param);
276 }
277
hi_uart_set_flow_ctrl(hi_uart_idx id,hi_flow_ctrl flow_ctrl)278 hi_u32 hi_uart_set_flow_ctrl(hi_uart_idx id, hi_flow_ctrl flow_ctrl)
279 {
280 hi_u32 port_num = (hi_u32) id;
281 uart_driver_data_t *udd = HI_NULL;
282 uart_attr_t uart_attr = { 0 };
283
284 if (port_num >= UART_NUM || flow_ctrl > HI_FLOW_CTRL_CTS_ONLY) {
285 return HI_ERR_UART_INVALID_PARAMETER;
286 }
287
288 udd = g_udd_g[port_num];
289 if (memcpy_s(&uart_attr, sizeof(uart_attr_t), &udd->attr, sizeof(uart_attr_t)) != EOK) {
290 return HI_ERR_FAILURE;
291 }
292 uart_attr.flow_ctrl = (hi_u8) flow_ctrl;
293
294 return uart_ioctl(udd, UART_CFG_SET_ATTR, (uintptr_t)&uart_attr);
295 }
296
hi_uart_read(hi_uart_idx id,hi_u8 * data,hi_u32 data_len)297 hi_s32 hi_uart_read(hi_uart_idx id, hi_u8 *data, hi_u32 data_len)
298 {
299 hi_u32 port_num = (hi_u32) id;
300 hi_s32 num;
301
302 if (port_num >= UART_NUM) {
303 return (hi_s32)HI_ERR_FAILURE;
304 }
305
306 num = uart_read(g_udd_g[port_num], (hi_char *) data, data_len);
307 return num;
308 }
309
uart_read_timeout_func(hi_u32 uart_id)310 hi_void uart_read_timeout_func(hi_u32 uart_id)
311 {
312 g_uart_timeout[uart_id] = HI_TRUE;
313 hi_u32 ret = hi_uart_quit_read(uart_id);
314 if (ret != HI_ERR_SUCCESS) {
315 printf("uart:%d quit fail:0x%x\r\n", uart_id, ret);
316 }
317 }
318
hi_uart_read_timeout(hi_uart_idx id,hi_u8 * data,hi_u32 len,hi_u32 timeout_ms)319 hi_s32 hi_uart_read_timeout(hi_uart_idx id, hi_u8 *data, hi_u32 len, hi_u32 timeout_ms)
320 {
321 hi_s32 need_read_len = len;
322
323 g_uart_timeout[id] = HI_FALSE;
324 hi_u32 ret = hi_timer_start(g_uart_timer_handle[id], HI_TIMER_TYPE_ONCE, timeout_ms,
325 uart_read_timeout_func, id);
326 if (ret != HI_ERR_SUCCESS) {
327 return ret;
328 }
329
330 while ((need_read_len > 0) && (g_uart_timeout[id] == HI_FALSE)) {
331 hi_s32 read_len = hi_uart_read(id, data, need_read_len);
332 if (read_len == -1) {
333 (hi_void)hi_timer_stop(g_uart_timer_handle[id]);
334 return HI_ERR_FAILURE;
335 }
336 data += read_len;
337 need_read_len -= read_len;
338 }
339
340 if (g_uart_timeout[id] == HI_FALSE) {
341 (hi_void)hi_timer_stop(g_uart_timer_handle[id]);
342 }
343
344 return (len - need_read_len);
345 }
346
hi_uart_write(hi_uart_idx id,const hi_u8 * data,hi_u32 data_len)347 hi_s32 hi_uart_write(hi_uart_idx id, const hi_u8 *data, hi_u32 data_len)
348 {
349 hi_u32 port_num = (hi_u32) id;
350 uart_driver_data_t *udd = HI_NULL;
351
352 if (port_num >= UART_NUM) {
353 return (hi_s32)HI_ERR_FAILURE;
354 }
355
356 udd = g_udd_g[port_num];
357 if (udd->tx_use_int != HI_TRUE) {
358 udd->tx_use_int = HI_TRUE;
359 }
360
361 return uart_write(udd, (hi_char *) data, data_len);
362 }
363
hi_uart_write_immediately(hi_uart_idx id,const hi_u8 * data,hi_u32 data_len)364 hi_s32 hi_uart_write_immediately(hi_uart_idx id, const hi_u8 *data, hi_u32 data_len)
365 {
366 hi_u32 port_num = (hi_u32) id;
367 uart_driver_data_t *udd = HI_NULL;
368
369 if (port_num >= UART_NUM) {
370 return (hi_s32)HI_ERR_FAILURE;
371 }
372
373 udd = g_udd_g[port_num];
374 if (udd->tx_use_int != HI_FALSE) {
375 udd->tx_use_int = HI_FALSE;
376 }
377
378 return uart_write_immediately(udd, (hi_char *) data, data_len);
379 }
380
hi_uart_deinit(hi_uart_idx id)381 hi_u32 hi_uart_deinit(hi_uart_idx id)
382 {
383 hi_u32 port_num = (hi_u32) id;
384 hi_u32 ret;
385 if (port_num >= UART_NUM) {
386 return HI_ERR_UART_INVALID_PARAMETER;
387 }
388
389 ret = uart_close(g_udd_g[port_num]);
390 if (ret != HI_ERR_SUCCESS) {
391 return ret;
392 }
393
394 if (id == HI_UART_IDX_2) {
395 hi_u16 reg_val;
396 hi_reg_read16(W_CTL_UART_MAC80M_CLKEN_REG, reg_val);
397 reg_val &= ~((1 << CLKEN_UART2) | (1 << CLKEN_UART2_BUS));
398 hi_reg_write16(W_CTL_UART_MAC80M_CLKEN_REG, reg_val); /* disable uart2 clk */
399 }
400
401 if (g_uart_timer_handle[id] != 0xFFFFFFFF) {
402 ret = hi_timer_delete(g_uart_timer_handle[id]);
403 if (ret != HI_ERR_SUCCESS) {
404 return ret;
405 }
406 g_uart_timer_handle[id] = 0xFFFFFFFF;
407 }
408
409 return ret;
410 }
411
hi_uart_get_attribute(hi_uart_idx id,hi_uart_attribute * attr,hi_uart_extra_attr * extra_attr)412 hi_u32 hi_uart_get_attribute(hi_uart_idx id, hi_uart_attribute *attr, hi_uart_extra_attr *extra_attr)
413 {
414 hi_u32 port_num = (hi_u32) id;
415
416 if (port_num >= UART_NUM || attr == HI_NULL) {
417 return HI_ERR_UART_INVALID_PARAMETER;
418 }
419
420 return get_uart_param(g_udd_g[port_num], attr, extra_attr);
421 }
422
hi_uart_quit_read(hi_uart_idx id)423 hi_u32 hi_uart_quit_read(hi_uart_idx id)
424 {
425 hi_u32 port_num = (hi_u32) id;
426 if (port_num >= UART_NUM) {
427 return HI_ERR_UART_INVALID_PARAMETER;
428 }
429
430 uart_driver_data_t *udd = (uart_driver_data_t *) g_udd_g[id];
431 if (udd->act.rx_block != UART_FLG_RD_BLOCK) {
432 return HI_ERR_UART_NOT_BLOCK_MODE;
433 }
434
435 if (hi_event_send(udd->event_id, UART_RD_QUIT_EVENT) != HI_ERR_SUCCESS) {
436 return HI_ERR_FAILURE;
437 }
438
439 return HI_ERR_SUCCESS;
440 }
441
hi_uart_lp_save(hi_uart_idx id)442 hi_u32 hi_uart_lp_save(hi_uart_idx id)
443 {
444 hi_u32 port_num = (hi_u32) id;
445 if (port_num >= UART_NUM) {
446 return HI_ERR_UART_INVALID_PARAMETER;
447 }
448 uart_driver_data_t *udd = HI_NULL;
449 udd = (uart_driver_data_t *) g_udd_g[port_num];
450 g_uart_regs_save[port_num].ibrd = hi_reg_read_val16(udd->phys_base + UART_IBRD);
451 g_uart_regs_save[port_num].fbrd = hi_reg_read_val16(udd->phys_base + UART_FBRD);
452 g_uart_regs_save[port_num].lcr_h = hi_reg_read_val16(udd->phys_base + UART_LCR_H);
453 g_uart_regs_save[port_num].cr = hi_reg_read_val16(udd->phys_base + UART_CR);
454 g_uart_regs_save[port_num].ifls = hi_reg_read_val16(udd->phys_base + UART_IFLS);
455 return HI_ERR_SUCCESS;
456 }
457
hi_uart_lp_restore(hi_uart_idx id)458 hi_u32 hi_uart_lp_restore(hi_uart_idx id)
459 {
460 hi_u32 port_num = (hi_u32) id;
461 if (port_num >= UART_NUM) {
462 return HI_ERR_UART_INVALID_PARAMETER;
463 }
464 hi_u32 phys_base = ((uart_driver_data_t *) g_udd_g[port_num])->phys_base;
465 hi_u16 temp;
466 if (id == HI_UART_IDX_2) {
467 hi_reg_read16(W_CTL_UART_MAC80M_CLKEN_REG, temp);
468 temp |= (1 << CLKEN_UART2) | (1 << CLKEN_UART2_BUS);
469 hi_reg_write16(W_CTL_UART_MAC80M_CLKEN_REG, temp); /* enable uart2 clk */
470 }
471 /* wait until tx fifo is null, in order to let data send before reset work normal. */
472 while ((hi_reg_read_val16(phys_base + UART_FR) & 0x08) == 0x08) { }
473 /* disable uart tx rx and uart */
474 hi_reg_write16((phys_base + UART_CR), 0);
475 /* flush fifo */
476 hi_reg_write16((phys_base + UART_LCR_H), 0);
477 /* set baudrate */
478 hi_reg_write16((phys_base + UART_IBRD), g_uart_regs_save[port_num].ibrd);
479 hi_reg_write16((phys_base + UART_FBRD), g_uart_regs_save[port_num].fbrd);
480 /* set databit stopbit parity */
481 hi_reg_write16((phys_base + UART_LCR_H), g_uart_regs_save[port_num].lcr_h);
482 /* set fifo line */
483 hi_reg_write16(phys_base + UART_IFLS, g_uart_regs_save[port_num].ifls); /* default val: 0x10A */
484 /* disable the transmit DMA */
485 hi_reg_write16((phys_base + UART_DMACR), UART_DMA_DISABLE);
486 /* set flow ctrl */
487 if (phys_base != HI_UART0_REG_BASE) {
488 temp = hi_reg_read_val16(phys_base + UART_CR);
489 temp &= ~(0x3 << OFFSET_14_BITS);
490 temp |= g_uart_regs_save[port_num].cr & (0x3 << OFFSET_14_BITS);
491 hi_reg_write16(phys_base + UART_CR, temp); /* 14 15 bit */
492 }
493 /* enable uart tx rx and uart */
494 temp = hi_reg_read_val16(phys_base + UART_CR);
495 temp |= UARTCR_CFG;
496 hi_reg_write16((phys_base + UART_CR), temp);
497 temp = hi_reg_read_val16(phys_base + UART_IMSC);
498 hi_reg_write16(phys_base + UART_IMSC, UART_RX_INT_ENABLE | temp);
499 return HI_ERR_SUCCESS;
500 }
501