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