/** * @file wm_uart.c * * @brief uart Driver Module * * @author dave * * Copyright (c) 2015 Winner Microelectronics Co., Ltd. */ #include #include "wm_regs.h" #include "wm_uart.h" #include "wm_debug.h" #include "wm_irq.h" #include "wm_config.h" #include "wm_mem.h" #include "wm_dma.h" #include "wm_cpu.h" #if TLS_CONFIG_UART #define RX_CACHE_LIMIT 128 #define STEP_SIZE (HR_UART1_BASE_ADDR - HR_UART0_BASE_ADDR) extern void tls_irq_priority(u8 vec_no, u32 prio); void tls_uart_tx_callback_register(u16 uart_no, s16(*tx_callback) (struct tls_uart_port *port)); const u32 baud_rates[] = { 2000000, 1500000, 1250000, 1000000, 921600, 460800, 230400, 115200, 57600, 38400, 19200, 9600, 4800, 2400, 1800, 1200, 600 }; struct tls_uart_port uart_port[TLS_UART_MAX]; static u8 uart_rx_byte_cb_flag[TLS_UART_MAX] = {0}; static void tls_uart_tx_enable(struct tls_uart_port *port) { u32 ucon; ucon = port->regs->UR_LC; ucon |= ULCON_TX_EN; port->regs->UR_LC = ucon; } /** * @brief This function is used to continue transfer data. * @param[in] port: is the uart port. * @retval */ static void tls_uart_tx_chars(struct tls_uart_port *port) { struct dl_list *pending_list = &port->tx_msg_pending_list; tls_uart_tx_msg_t *tx_msg = NULL; int tx_count; u32 cpu_sr; /* send some chars */ tx_count = 32; cpu_sr = tls_os_set_critical(); if (!dl_list_empty(pending_list)) { tx_msg = dl_list_first(pending_list, tls_uart_tx_msg_t, list); while (tx_count-- > 0 && tx_msg->offset < tx_msg->buflen) { /* 检查tx fifo是否已满 */ if ((port->regs->UR_FIFOS & UFS_TX_FIFO_CNT_MASK) == port->tx_fifofull) { break; } port->regs->UR_TXW = tx_msg->buf[tx_msg->offset]; tx_msg->offset++; port->icount.tx++; } if (tx_msg->offset >= tx_msg->buflen) { dl_list_del(&tx_msg->list); dl_list_add_tail(&port->tx_msg_to_be_freed_list, &tx_msg->list); tls_os_release_critical(cpu_sr); if (port->tx_sent_callback) port->tx_sent_callback(port); if (port->tx_callback) port->tx_callback(port); }else{ tls_os_release_critical(cpu_sr); } } else{ tls_os_release_critical(cpu_sr); } } static void UartRegInit(int uart_no) { u32 bd; u32 apbclk; tls_sys_clk sysclk; tls_sys_clk_get(&sysclk); apbclk = sysclk.apbclk * 1000000; if (TLS_UART_0 == uart_no) { bd = (apbclk / (16 * 115200) - 1) | (((apbclk % (115200 * 16)) * 16 / (115200 * 16)) << 16); tls_reg_write32(HR_UART0_BAUD_RATE_CTRL, bd); /* Line control register : Normal,No parity,1 stop,8 bits, only use tx */ tls_reg_write32(HR_UART0_LINE_CTRL, ULCON_WL8 | ULCON_TX_EN); /* disable auto flow control */ tls_reg_write32(HR_UART0_FLOW_CTRL, 0); /* disable dma */ tls_reg_write32(HR_UART0_DMA_CTRL, 0); /* one byte tx */ tls_reg_write32(HR_UART0_FIFO_CTRL, 0); /* disable interrupt */ tls_reg_write32(HR_UART0_INT_MASK, 0xFF); } else { /* 4 byte tx, 8 bytes rx */ tls_reg_write32(HR_UART0_FIFO_CTRL + uart_no*STEP_SIZE, (0x01 << 2) | (0x02 << 4)); /* enable rx timeout, disable rx dma, disable tx dma */ tls_reg_write32(HR_UART0_DMA_CTRL + uart_no*STEP_SIZE, (8 << 3) | (1 << 2)); /* enable rx/timeout interrupt */ tls_reg_write32(HR_UART0_INT_MASK + uart_no*STEP_SIZE, ~(3 << 2)); } } int tls_uart_check_baudrate(u32 baudrate) { int i; for (i = 0; i < sizeof(baud_rates) / sizeof(u32); i++) { if (baudrate == baud_rates[i]) return 1; } /* not found match baudrate */ return -1; } u32 tls_uart_get_baud_rate(struct tls_uart_port * port) { if ((port != NULL) && (port->regs != NULL)) return port->opts.baudrate; else return 0; } static int tls_uart_set_baud_rate_inside(struct tls_uart_port *port, u32 baudrate) { int index; u32 value; u32 apbclk; tls_sys_clk sysclk; // index = tls_uart_check_baudrate(baudrate); // if (index < 0) // { // return WM_FAILED; // } tls_sys_clk_get(&sysclk); apbclk = sysclk.apbclk * 1000000; value = (apbclk / (16 * baudrate) - 1) | (((apbclk % (baudrate * 16)) * 16 / (baudrate * 16)) << 16); port->regs->UR_BD = value; port->opts.baudrate = baudrate; return WM_SUCCESS; } static int tls_uart_set_parity_inside(struct tls_uart_port *port, TLS_UART_PMODE_T paritytype) { if (port == NULL) return WM_FAILED; port->opts.paritytype = paritytype; if (paritytype == TLS_UART_PMODE_DISABLED) port->regs->UR_LC &= ~ULCON_PMD_EN; else if (paritytype == TLS_UART_PMODE_EVEN) { port->regs->UR_LC &= ~ULCON_PMD_MASK; port->regs->UR_LC |= ULCON_PMD_EVEN; } else if (paritytype == TLS_UART_PMODE_ODD) { port->regs->UR_LC &= ~ULCON_PMD_MASK; port->regs->UR_LC |= ULCON_PMD_ODD; } else return WM_FAILED; return WM_SUCCESS; } #if 0 static TLS_UART_PMODE_T tls_uart_get_parity(struct tls_uart_port * port) { return port->opts.paritytype; } #endif static int tls_uart_set_data_bits(struct tls_uart_port *port, TLS_UART_CHSIZE_T charlength) { if (!port) return WM_FAILED; port->opts.charlength = charlength; port->regs->UR_LC &= ~ULCON_WL_MASK; if (charlength == TLS_UART_CHSIZE_5BIT) port->regs->UR_LC |= ULCON_WL5; else if (charlength == TLS_UART_CHSIZE_6BIT) port->regs->UR_LC |= ULCON_WL6; else if (charlength == TLS_UART_CHSIZE_7BIT) port->regs->UR_LC |= ULCON_WL7; else if (charlength == TLS_UART_CHSIZE_8BIT) port->regs->UR_LC |= ULCON_WL8; else return WM_FAILED; return WM_SUCCESS; } #if 0 static TLS_UART_CHSIZE_T tls_uart_get_data_bits(struct tls_uart_port * port) { return port->opts.charlength; } #endif static int tls_uart_set_stop_bits_inside(struct tls_uart_port *port, TLS_UART_STOPBITS_T stopbits) { if (!port) return WM_FAILED; port->opts.stopbits = stopbits; if (stopbits == TLS_UART_TWO_STOPBITS) port->regs->UR_LC |= ULCON_STOP_2; else port->regs->UR_LC &= ~ULCON_STOP_2; return WM_SUCCESS; } #if 0 static TLS_UART_STOPBITS_T tls_uart_get_stop_bits(struct tls_uart_port * port) { return port->opts.stopbits; } #endif static TLS_UART_STATUS_T tls_uart_set_flow_ctrl(struct tls_uart_port * port, TLS_UART_FLOW_CTRL_MODE_T flow_ctrl) { TLS_UART_STATUS_T status = TLS_UART_STATUS_OK; if (!port) return TLS_UART_STATUS_ERROR; // port->opts.flow_ctrl = flow_ctrl; // //不能在这里修改,为了配合透传和AT指令,软件会自己修改flowctrl配置,但是参数还是固定不变的 //printf("\nport %d flow ctrl==%d\n",port->uart_no,flow_ctrl); switch (flow_ctrl) { case TLS_UART_FLOW_CTRL_NONE: port->regs->UR_FC = 0; break; case TLS_UART_FLOW_CTRL_HARDWARE: if (TLS_UART_FLOW_CTRL_HARDWARE == port->opts.flow_ctrl) { port->regs->UR_FC = (1UL << 0) | (6UL << 2); } break; default: return TLS_UART_STATUS_ERROR; } return status; } void tls_uart_set_fc_status(int uart_no, TLS_UART_FLOW_CTRL_MODE_T status) { struct tls_uart_port *port; port = &uart_port[uart_no]; port->fcStatus = status; tls_uart_set_flow_ctrl(port, status); if (TLS_UART_FLOW_CTRL_HARDWARE == port->opts.flow_ctrl && 0 == status && port->hw_stopped) // 准备关闭流控时,发现tx已经停止,需要再打开tx { tls_uart_tx_enable(port); tls_uart_tx_chars(port); port->hw_stopped = 0; } } void tls_uart_rx_disable(struct tls_uart_port *port) { u32 ucon; ucon = port->regs->UR_LC; ucon &= ~ULCON_RX_EN; port->regs->UR_LC = ucon; } void tls_uart_rx_enable(struct tls_uart_port *port) { port->regs->UR_LC |= ULCON_RX_EN; } static void tls_uart_tx_disable(struct tls_uart_port *port) { u32 ucon; ucon = port->regs->UR_LC; ucon &= ~ULCON_TX_EN; port->regs->UR_LC = ucon; } static int tls_uart_config(struct tls_uart_port *port, struct tls_uart_options *opts) { if (NULL == port || NULL == opts) return WM_FAILED; tls_uart_set_baud_rate_inside(port, opts->baudrate); tls_uart_set_parity_inside(port, opts->paritytype); tls_uart_set_data_bits(port, opts->charlength); tls_uart_set_stop_bits_inside(port, opts->stopbits); port->opts.flow_ctrl = opts->flow_ctrl; tls_uart_set_flow_ctrl(port, opts->flow_ctrl); { /* clear interrupt */ port->regs->UR_INTS = 0xFFFFFFFF; /* enable interupt */ port->regs->UR_INTM = 0x0; port->regs->UR_DMAC = (4UL << UDMA_RX_FIFO_TIMEOUT_SHIFT) | UDMA_RX_FIFO_TIMEOUT; } /* config FIFO control */ port->regs->UR_FIFOC = UFC_TX_FIFO_LVL_16_BYTE | UFC_RX_FIFO_LVL_16_BYTE | UFC_TX_FIFO_RESET | UFC_RX_FIFO_RESET; port->regs->UR_LC &= ~(ULCON_TX_EN | ULCON_RX_EN); port->regs->UR_LC |= ULCON_RX_EN | ULCON_TX_EN; return WM_SUCCESS; } /** * @brief handle a change of clear-to-send state * @param[in] port: uart_port structure for the open port * @param[in] status: new clear to send status, nonzero if active */ static void uart_handle_cts_change(struct tls_uart_port *port, unsigned int status) { if (((1 == port->fcStatus) && (port->opts.flow_ctrl == TLS_UART_FLOW_CTRL_HARDWARE)) && (port->uart_no == TLS_UART_1)) { if (port->hw_stopped) { if (status) { port->hw_stopped = 0; tls_uart_tx_enable(port); tls_uart_tx_chars(port); } } else { if (!status) { port->hw_stopped = 1; tls_uart_tx_disable(port); } } } } static void uart_tx_finish_callback(void *arg) { if (arg) { tls_mem_free(arg); } } int tls_uart_tx_remain_len(struct tls_uart_port *port) { tls_uart_tx_msg_t *tx_msg = NULL; u16 buf_len = 0; u32 cpu_sr; cpu_sr = tls_os_set_critical(); dl_list_for_each(tx_msg, &port->tx_msg_pending_list, tls_uart_tx_msg_t, list) { buf_len += tx_msg->buflen; } tls_os_release_critical(cpu_sr); return TLS_UART_TX_BUF_SIZE - buf_len; } /** * @brief This function is used to fill tx buffer. * @param[in] port: is the uart port. * @param[in] buf: is the user buffer. * @param[in] count: is the user data length * @retval */ int tls_uart_fill_buf(struct tls_uart_port *port, char *buf, u32 count) { tls_uart_tx_msg_t *uart_tx_msg; int ret = 0; u32 cpu_sr; uart_tx_msg = tls_mem_alloc(sizeof(tls_uart_tx_msg_t)); if (uart_tx_msg == NULL) { TLS_DBGPRT_ERR("mem err\n"); return -1; } dl_list_init(&uart_tx_msg->list); uart_tx_msg->buf = tls_mem_alloc(count); if (uart_tx_msg->buf == NULL) { tls_mem_free(uart_tx_msg); TLS_DBGPRT_ERR("mem err 1 count=%d\n", count); return -1; } memcpy(uart_tx_msg->buf, buf, count); uart_tx_msg->buflen = count; uart_tx_msg->offset = 0; uart_tx_msg->finish_callback = uart_tx_finish_callback; uart_tx_msg->callback_arg = uart_tx_msg->buf; cpu_sr = tls_os_set_critical(); dl_list_add_tail(&port->tx_msg_pending_list, &uart_tx_msg->list); tls_os_release_critical(cpu_sr); return ret; } /** * @brief free the data buffer has been transmitted. * @param[in] port: is the uart port. * @retval */ s16 tls_uart_free_tx_sent_data(struct tls_uart_port *port) { tls_uart_tx_msg_t *tx_msg = NULL; u32 cpu_sr = tls_os_set_critical(); while (!dl_list_empty(&port->tx_msg_to_be_freed_list)) { tx_msg = dl_list_first(&port->tx_msg_to_be_freed_list, tls_uart_tx_msg_t, list); dl_list_del(&tx_msg->list); tls_os_release_critical(cpu_sr); if (tx_msg->buf != NULL) { if (tx_msg->finish_callback) tx_msg->finish_callback(tx_msg->callback_arg); tls_mem_free(tx_msg); } cpu_sr = tls_os_set_critical(); } tls_os_release_critical(cpu_sr); return 0; } /** * @brief This function is used to start transfer data. * @param[in] port: is the uart port. * @retval */ void tls_uart_tx_chars_start(struct tls_uart_port *port) { struct dl_list *pending_list = &port->tx_msg_pending_list; tls_uart_tx_msg_t *tx_msg = NULL; int tx_count; u32 cpu_sr; /* send some chars */ tx_count = 32; cpu_sr = tls_os_set_critical(); if (!dl_list_empty(pending_list)) { tx_msg = dl_list_first(pending_list, tls_uart_tx_msg_t, list); while (tx_count-- > 0 && tx_msg->offset < tx_msg->buflen) { /* 检查tx fifo是否已满 */ if ((port->regs->UR_FIFOS & UFS_TX_FIFO_CNT_MASK) == port->tx_fifofull) { break; } port->regs->UR_TXW = tx_msg->buf[tx_msg->offset]; tx_msg->offset++; port->icount.tx++; } if (tx_msg->offset >= tx_msg->buflen) { dl_list_del(&tx_msg->list); dl_list_add_tail(&port->tx_msg_to_be_freed_list, &tx_msg->list); tls_os_release_critical(cpu_sr); if (port->tx_sent_callback) port->tx_sent_callback(port); if (port->tx_callback) port->tx_callback(port); }else{ tls_os_release_critical(cpu_sr); } }else{ tls_os_release_critical(cpu_sr); } } void tls_set_uart_rx_status(int uart_no, int status) { u32 cpu_sr; struct tls_uart_port *port; if (TLS_UART_1 == uart_no) { port = &uart_port[1]; if ((TLS_UART_RX_DISABLE == port->rxstatus && TLS_UART_RX_DISABLE == status) || (TLS_UART_RX_ENABLE == port->rxstatus && TLS_UART_RX_ENABLE == status)) return; if (TLS_UART_RX_DISABLE == status) { if ((TLS_UART_FLOW_CTRL_HARDWARE == port->opts.flow_ctrl) && (TLS_UART_FLOW_CTRL_HARDWARE == port->fcStatus)) { cpu_sr = tls_os_set_critical(); // 锟斤拷rxfifo trigger level interrupt锟斤拷overrun error port->regs->UR_INTM |= ((0x1 << 2) | (0x01 << 8)); port->rxstatus = TLS_UART_RX_DISABLE; tls_os_release_critical(cpu_sr); } } else { cpu_sr = tls_os_set_critical(); uart_port[1].regs->UR_INTM &= ~((0x1 << 2) | (0x01 << 8)); port->rxstatus = TLS_UART_RX_ENABLE; tls_os_release_critical(cpu_sr); } } } ATTRIBUTE_ISR void UART0_IRQHandler(void) { struct tls_uart_port *port = &uart_port[0]; struct tls_uart_circ_buf *recv = &port->recv; u8 rx_byte_cb_flag = uart_rx_byte_cb_flag[0]; u32 intr_src; u32 rx_fifocnt; u32 fifos; u8 ch; u32 rxlen = 0; csi_kernel_intrpt_enter(); /* check interrupt status */ intr_src = port->regs->UR_INTS; port->regs->UR_INTS = intr_src; if ((intr_src & UART_RX_INT_FLAG) && (0 == (port->regs->UR_INTM & UIS_RX_FIFO))) { rx_fifocnt = (port->regs->UR_FIFOS >> 6) & 0x3F; while (rx_fifocnt-- > 0) { ch = (u8) port->regs->UR_RXW; if (intr_src & UART_RX_ERR_INT_FLAG) { port->regs->UR_INTS |= UART_RX_ERR_INT_FLAG; TLS_DBGPRT_INFO("\nrx err=%x,c=%d,ch=%x\n", intr_src, rx_fifocnt, ch); /* not insert to buffer */ continue; } if (CIRC_SPACE(recv->head, recv->tail, TLS_UART_RX_BUF_SIZE) <= 2) { TLS_DBGPRT_INFO("\nrx buf overrun int_src=%x\n", intr_src); if (TLS_UART_FLOW_CTRL_HARDWARE == port->fcStatus) { tls_set_uart_rx_status(port->uart_no, TLS_UART_RX_DISABLE); rx_fifocnt = 0; // 如果有硬件流控,关闭接收,把最后一个字符放进环形buffer中 } else break; } /* insert the character into the buffer */ recv->buf[recv->head] = ch; recv->head = (recv->head + 1) & (TLS_UART_RX_BUF_SIZE - 1); rxlen++; if(port->rx_callback != NULL && rx_byte_cb_flag) { port->rx_callback(1, port->priv_data); } } if (port->rx_callback != NULL && !rx_byte_cb_flag) { port->rx_callback(rxlen, port->priv_data); } } if (intr_src & UART_TX_INT_FLAG) { tls_uart_tx_chars(port); } if (intr_src & UIS_CTS_CHNG) { fifos = port->regs->UR_FIFOS; uart_handle_cts_change(port, fifos & UFS_CST_STS); } if (port->rx_callback != NULL && intr_src & UIS_RX_FIFO_TIMEOUT) { port->rx_callback(0, (void*)((int)port->priv_data+100)); } csi_kernel_intrpt_exit(); } void tls_uart_push(int index, u8* data, int length) { int i = 0; struct tls_uart_port *port = &uart_port[1]; struct tls_uart_circ_buf *recv = &port->recv; while(ibuf[recv->head] = data[i]; recv->head = (recv->head + 1) & (TLS_UART_RX_BUF_SIZE - 1); i++; } } ATTRIBUTE_ISR void UART1_IRQHandler(void) { struct tls_uart_port *port = &uart_port[1]; struct tls_uart_circ_buf *recv = &port->recv; u8 rx_byte_cb_flag = uart_rx_byte_cb_flag[1]; u32 intr_src; u32 rx_fifocnt; u32 fifos; u8 ch = 0; u8 escapefifocnt = 0; u32 rxlen = 0; csi_kernel_intrpt_enter(); intr_src = port->regs->UR_INTS; port->regs->UR_INTS = intr_src; if (intr_src & UIS_OVERRUN) { port->regs->UR_INTS |= UIS_OVERRUN; if(port->tx_dma_on) { tls_reg_write32((int)&port->regs->UR_DMAC, (tls_reg_read32((int)&port->regs->UR_DMAC) & ~0x01)); tls_reg_write32((int)&port->regs->UR_DMAC, (tls_reg_read32((int)&port->regs->UR_DMAC) | 0x01)); } } if ((intr_src & UART_RX_INT_FLAG) && (0 == (port->regs->UR_INTM & UIS_RX_FIFO))) { rx_fifocnt = (port->regs->UR_FIFOS >> 6) & 0x3F; escapefifocnt = rx_fifocnt; port->plus_char_cnt = 0; rxlen = rx_fifocnt; if (CIRC_SPACE(recv->head, recv->tail, TLS_UART_RX_BUF_SIZE) <= RX_CACHE_LIMIT) { recv->tail = (recv->tail + RX_CACHE_LIMIT) & (TLS_UART_RX_BUF_SIZE - 1); } while (rx_fifocnt-- > 0) { ch = (u8) port->regs->UR_RXW; if (intr_src & UART_RX_ERR_INT_FLAG) { port->regs->UR_INTS |= UART_RX_ERR_INT_FLAG; TLS_DBGPRT_INFO("\nrx err=%x,c=%d,ch=%x\n", intr_src, rx_fifocnt, ch); continue; } recv->buf[recv->head] = ch; recv->head = (recv->head + 1) & (TLS_UART_RX_BUF_SIZE - 1); } if( escapefifocnt==3 && ch=='+') { switch(recv->head-1) { case 0: if(recv->buf[TLS_UART_RX_BUF_SIZE-1]=='+' && recv->buf[TLS_UART_RX_BUF_SIZE-2]=='+') port->plus_char_cnt = 3; break; case 1: if(recv->buf[0]=='+' && recv->buf[TLS_UART_RX_BUF_SIZE-1]=='+') port->plus_char_cnt = 3; break; default: if(recv->buf[recv->head-2]=='+' && recv->buf[recv->head-3]=='+') port->plus_char_cnt = 3; break; } if(port->rx_callback != NULL && rx_byte_cb_flag) { port->rx_callback(1, port->priv_data); } } if (port->rx_callback!=NULL && !rx_byte_cb_flag) { port->rx_callback(rxlen, port->priv_data); } } if (intr_src & UART_TX_INT_FLAG) { tls_uart_tx_chars(port); } if (intr_src & UIS_CTS_CHNG) { fifos = port->regs->UR_FIFOS; uart_handle_cts_change(port, fifos & UFS_CST_STS); } if (port->rx_callback != NULL && intr_src & UIS_RX_FIFO_TIMEOUT) { port->rx_callback(0, (void*)((int)port->priv_data+100)); } csi_kernel_intrpt_exit(); } static int findOutIntUart(void) { int i; u32 regValue; for( i=TLS_UART_2; i< TLS_UART_MAX; i++ ) { regValue = tls_reg_read32(HR_UART0_INT_SRC + i*STEP_SIZE); regValue &= 0x1FF; if( regValue ) break; } return i; } ATTRIBUTE_ISR void UART2_4_IRQHandler(void) { int intUartNum = findOutIntUart(); struct tls_uart_port *port = &uart_port[intUartNum]; struct tls_uart_circ_buf *recv = &port->recv; u8 rx_byte_cb_flag = uart_rx_byte_cb_flag[intUartNum]; u32 intr_src; u32 rx_fifocnt; u32 fifos; u8 escapefifocnt = 0; u32 rxlen = 0; u8 ch = 0; csi_kernel_intrpt_enter(); intr_src = port->regs->UR_INTS; if (intr_src & UIS_OVERRUN) { port->regs->UR_INTS |= UIS_OVERRUN; if(port->tx_dma_on) { tls_reg_write32((int)&port->regs->UR_DMAC, (tls_reg_read32((int)&port->regs->UR_DMAC) & ~0x01)); tls_reg_write32((int)&port->regs->UR_DMAC, (tls_reg_read32((int)&port->regs->UR_DMAC) | 0x01)); } } if ((intr_src & UART_RX_INT_FLAG) && (0 == (port->regs->UR_INTM & UIS_RX_FIFO))) { rx_fifocnt = (port->regs->UR_FIFOS >> 6) & 0x3F; escapefifocnt = rx_fifocnt; port->plus_char_cnt = 0; rxlen = rx_fifocnt; if (CIRC_SPACE(recv->head, recv->tail, TLS_UART_RX_BUF_SIZE) <= RX_CACHE_LIMIT) { recv->tail = (recv->tail + RX_CACHE_LIMIT) & (TLS_UART_RX_BUF_SIZE - 1); } while (rx_fifocnt-- > 0) { ch = (u8) port->regs->UR_RXW; if (intr_src & UART_RX_ERR_INT_FLAG) { port->regs->UR_INTS |= UART_RX_ERR_INT_FLAG; //TLS_DBGPRT_INFO("\nrx err=%x,c=%d,ch=%x\n", intr_src, rx_fifocnt, ch); continue; } recv->buf[recv->head] = ch; recv->head = (recv->head + 1) & (TLS_UART_RX_BUF_SIZE - 1); } if( escapefifocnt==3 && ch=='+') { switch(recv->head-1) { case 0: if(recv->buf[TLS_UART_RX_BUF_SIZE-1]=='+' && recv->buf[TLS_UART_RX_BUF_SIZE-2]=='+') port->plus_char_cnt = 3; break; case 1: if(recv->buf[0]=='+' && recv->buf[TLS_UART_RX_BUF_SIZE-1]=='+') port->plus_char_cnt = 3; break; default: if(recv->buf[recv->head-2]=='+' && recv->buf[recv->head-3]=='+') port->plus_char_cnt = 3; break; } if(port->rx_callback != NULL && rx_byte_cb_flag) { port->rx_callback(1, port->priv_data); } } if (port->rx_callback!=NULL && !rx_byte_cb_flag) { port->rx_callback(rxlen, port->priv_data); } } if (intr_src & UART_TX_INT_FLAG) { tls_uart_tx_chars(port); } if (intr_src & UIS_CTS_CHNG) { fifos = port->regs->UR_FIFOS; uart_handle_cts_change(port, fifos & UFS_CST_STS); } if (port->rx_callback != NULL && intr_src & UIS_RX_FIFO_TIMEOUT) { port->rx_callback(0, (void*)((int)port->priv_data+100)); } port->regs->UR_INTS = intr_src; csi_kernel_intrpt_exit(); } /** * @brief This function is used to initial uart port. * * @param[in] uart_no: is the uart number. * - \ref TLS_UART_0 TLS_UART_1 TLS_UART_2 TLS_UART_3 TLS_UART_4 TLS_UART5 * @param[in] opts: is the uart setting options,if this param is NULL,this function will use the default options. * @param[in] modeChoose:; choose uart2 mode or 7816 mode when uart_no is TLS_UART_2, 0 for uart2 mode and 1 for 7816 mode. * * @retval * - \ref WM_SUCCESS * - \ref WM_FAILED * * @note When the system is initialized, the function has been called, so users can not call the function. */ int tls_uart_port_init(u16 uart_no, tls_uart_options_t * opts, u8 modeChoose) { struct tls_uart_port *port; int ret; char *bufrx; // ,*buftx tls_uart_options_t opt; if (TLS_UART_MAX <= uart_no) { return WM_FAILED; } switch( uart_no ) { case TLS_UART_0: case TLS_UART_1: tls_irq_disable((UART0_IRQn+uart_no)); break; case TLS_UART_2: case TLS_UART_3: case TLS_UART_4: case TLS_UART_5: tls_irq_disable(UART24_IRQn); break; } UartRegInit(uart_no); if (uart_port[uart_no].recv.buf) { tls_mem_free((void *)uart_port[uart_no].recv.buf); uart_port[uart_no].recv.buf = NULL; } memset(&uart_port[uart_no], 0, sizeof(struct tls_uart_port)); port = &uart_port[uart_no]; port->regs = (TLS_UART_REGS_T *)(HR_UART0_BASE_ADDR + uart_no*STEP_SIZE); if( uart_no==TLS_UART_2 ) { (modeChoose == 1)?(port->regs->UR_LC |= (1 << 24)):(port->regs->UR_LC &= ~(0x1000000)); } port->uart_no = uart_no; if (NULL == opts) { opt.baudrate = UART_BAUDRATE_B115200; opt.charlength = TLS_UART_CHSIZE_8BIT; opt.flow_ctrl = TLS_UART_FLOW_CTRL_NONE; opt.paritytype = TLS_UART_PMODE_DISABLED; opt.stopbits = TLS_UART_ONE_STOPBITS; ret = tls_uart_config(port, &opt); } else { ret = tls_uart_config(port, opts); } if (ret != WM_SUCCESS) return WM_FAILED; port->rxstatus = TLS_UART_RX_ENABLE; switch( uart_no ) { case TLS_UART_0: case TLS_UART_1: port->uart_irq_no = (UART0_IRQn+uart_no); break; case TLS_UART_2: case TLS_UART_3: case TLS_UART_4: case TLS_UART_5: port->uart_irq_no = UART24_IRQn; break; } if (port->recv.buf == NULL) { bufrx = tls_mem_alloc(TLS_UART_RX_BUF_SIZE); if (!bufrx) return WM_FAILED; memset(bufrx, 0, TLS_UART_RX_BUF_SIZE); port->recv.buf = (u8 *) bufrx; } port->recv.head = 0; port->recv.tail = 0; port->tx_fifofull = 16; dl_list_init(&port->tx_msg_pending_list); dl_list_init(&port->tx_msg_to_be_freed_list); tls_uart_tx_callback_register(uart_no, tls_uart_free_tx_sent_data); tls_irq_enable(port->uart_irq_no); /* enable uart interrupt */ return WM_SUCCESS; } /** * @brief This function is used to register uart rx interrupt. * * @param[in] uart_no: is the uart numer. * @param[in] callback: is the uart rx interrupt call back function. * * @retval * * @note This function should be called after the fucntion tls_uart_port_init() or it won't work. */ void tls_uart_rx_callback_register(u16 uart_no, s16(*rx_callback) (u16 len, void* user_data), void *priv_data) { uart_port[uart_no].rx_callback = rx_callback; uart_port[uart_no].priv_data = priv_data; } void tls_uart_rx_byte_callback_flag(u16 uart_no, u8 flag) { uart_rx_byte_cb_flag[uart_no] = flag; } /** * @brief This function is used to register uart tx interrupt. * * @param[in] uart_no: is the uart numer. * @param[in] callback: is the uart tx interrupt call back function. * * @retval */ void tls_uart_tx_callback_register(u16 uart_no, s16(*tx_callback) (struct tls_uart_port *port)) { uart_port[uart_no].tx_callback = tx_callback; } void tls_uart_tx_sent_callback_register(u16 uart_no, s16(*tx_callback) (struct tls_uart_port *port)) { uart_port[uart_no].tx_sent_callback = tx_callback; } int tls_uart_try_read(u16 uart_no, int32_t read_size) { int data_cnt = 0; struct tls_uart_port *port = NULL; struct tls_uart_circ_buf *recv; port = &uart_port[uart_no]; recv = &port->recv; data_cnt = CIRC_CNT(recv->head, recv->tail, TLS_UART_RX_BUF_SIZE); if(data_cnt >= read_size) { return read_size; }else { return 0; } } /** * @brief This function is used to copy circular buffer data to user buffer. * @param[in] uart_no: is the uart numer. * @param[in] buf: is the user buffer. * @param[in] readsize: is the user read size. * @retval */ int tls_uart_read(u16 uart_no, u8 * buf, u16 readsize) { int data_cnt, buflen, bufcopylen; struct tls_uart_port *port = NULL; struct tls_uart_circ_buf *recv; if (NULL == buf || readsize < 1) { return WM_FAILED; } port = &uart_port[uart_no]; recv = &port->recv; data_cnt = CIRC_CNT(recv->head, recv->tail, TLS_UART_RX_BUF_SIZE); (data_cnt >= readsize)?(buflen = readsize):(buflen = data_cnt); if ((recv->tail + buflen) > TLS_UART_RX_BUF_SIZE) { bufcopylen = (TLS_UART_RX_BUF_SIZE - recv->tail); MEMCPY(buf, (void *)(recv->buf + recv->tail), bufcopylen); MEMCPY(buf + bufcopylen, (void *)recv->buf, buflen - bufcopylen); } else { MEMCPY(buf, (void *)(recv->buf + recv->tail), buflen); } recv->tail = (recv->tail + buflen) & (TLS_UART_RX_BUF_SIZE - 1); return buflen; } /** * @brief This function is used to transfer data throuth DMA. * * @param[in] buf is a buf for saving user data * @param[in] writesize is the user data length * @param[in] cmpl_callback function point,when the transfer is completed, the function will be called. * * @retval WM_SUCCESS success * @retval WM_FAILED failed * * @note Only uart1 support DMA transfer. */ int tls_uart_dma_write(char *buf, u16 writesize, void (*cmpl_callback) (void *p), u16 uart_no) { unsigned char dmaCh = 0; struct tls_dma_descriptor DmaDesc; struct tls_uart_port *port = &uart_port[uart_no]; if (NULL == buf || writesize < 1 || writesize >= 4096) { TLS_DBGPRT_ERR("param err\n"); return WM_FAILED; } if (port->tx_dma_on) { TLS_DBGPRT_ERR("transmiting,wait\n"); return WM_FAILED; } tls_reg_write32(HR_DMA_CHNL_SEL, uart_no); /* Request DMA Channel */ dmaCh = tls_dma_request(2, TLS_DMA_FLAGS_CHANNEL_SEL(TLS_DMA_SEL_UART_TX) | TLS_DMA_FLAGS_HARD_MODE); if (dmaCh == 0xFF) { TLS_DBGPRT_ERR("dma request err\n"); return WM_FAILED; } tls_reg_write32((int)&port->regs->UR_DMAC, (tls_reg_read32((int)&port->regs->UR_DMAC) & ~0x01)); tls_dma_irq_register(dmaCh, cmpl_callback, (void *)(u32)uart_no, TLS_DMA_IRQ_TRANSFER_DONE); DmaDesc.src_addr = (int) buf; DmaDesc.dest_addr = (int)&port->regs->UR_TXW; DmaDesc.dma_ctrl = TLS_DMA_DESC_CTRL_SRC_ADD_INC | TLS_DMA_DESC_CTRL_DATA_SIZE_BYTE | (writesize << 7); DmaDesc.valid = TLS_DMA_DESC_VALID; DmaDesc.next = NULL; tls_dma_start(dmaCh, &DmaDesc, 0); /* Enable uart TX DMA */ port->tx_dma_on = TRUE; tls_reg_write32((int)&port->regs->UR_DMAC, (tls_reg_read32((int)&port->regs->UR_DMAC) | 0x01)); tls_reg_write32(HR_DMA_INT_MASK, (tls_reg_read32(HR_DMA_INT_MASK) & ~(0x01 << 5))); /* enable dma interrupt */ tls_irq_enable(DMA_Channel2_IRQn); return WM_SUCCESS; } /** * @brief This function is used to transfer data asynchronous. * * @param[in] uart_no is the uart number * @param[in] buf is a buf for saving user data. * @param[in] writesize is the data length * * @retval WM_SUCCESS success * @retval WM_FAILED failed * * @note The function only start transmission, fill buffer in the callback function. */ int tls_uart_write_async(u16 uart_no, char *buf, u16 writesize) { struct tls_uart_port *port = NULL; int ret; if (NULL == buf || writesize < 1) { TLS_DBGPRT_ERR("param err\n"); return WM_FAILED; } port = &uart_port[uart_no]; ret = tls_uart_fill_buf(port, buf, writesize); if (0 == ret) { tls_uart_tx_chars_start(port); } return ret; } /** * @brief get the data length has been transmitted. * * @param[in] uart_no is the uart number * * @retval the length has been transmitted * */ int tls_uart_tx_length(u16 uart_no) { struct tls_uart_port *port = &uart_port[uart_no]; return port->icount.tx; } /** * @brief This function is used to transfer data synchronous. * * @param[in] uart_no is the uart number * @param[in] buf is a buf for saving user data. * @param[in] writesize is the data length * * @retval WM_SUCCESS success * @retval WM_FAILED failed * * @note The function only start transmission, fill buffer in the callback function. */ int tls_uart_write(u16 uart_no, char *buf, u16 writesize) { return tls_uart_write_async(uart_no, buf, writesize); } /** * @brief This function is used to set uart parity. * * @param[in] paritytype is a parity type defined in TLS_UART_PMODE_T * * @retval WM_SUCCESS success * @retval WM_FAILED failed * */ int tls_uart_set_parity(u16 uart_no, TLS_UART_PMODE_T paritytype) { return tls_uart_set_parity_inside(&uart_port[uart_no], paritytype); } /** * @brief This function is used to set uart baudrate. * * @param[in] uart_no is the uart number * @param[in] baudrate is the baudrate user want used,the unit is HZ. * * @retval WM_SUCCESS success * @retval WM_FAILED failed * */ int tls_uart_set_baud_rate(u16 uart_no, u32 baudrate) { return tls_uart_set_baud_rate_inside(&uart_port[uart_no], baudrate); } /** * @brief This function is used to set uart stop bits. * * @param[in] uart_no is the uart number * @param[in] stopbits is a stop bit type defined in TLS_UART_STOPBITS_T. * * @retval WM_SUCCESS success * @retval WM_FAILED failed * */ int tls_uart_set_stop_bits(u16 uart_no, TLS_UART_STOPBITS_T stopbits) { return tls_uart_set_stop_bits_inside(&uart_port[uart_no], stopbits); } int tls_uart_dma_off(u16 uart_no) { uart_port[uart_no].tx_dma_on = FALSE; return WM_SUCCESS; } #endif //TLS_CONFIG_UART