605 lines
21 KiB
C
605 lines
21 KiB
C
|
|
/*
|
||
|
|
* Copyright (c) CompanyNameMagicTag 2012-2019. All rights reserved.
|
||
|
|
* Description: Adjust the directory structure to prepare for compiling the SDK. uart_drv.c code
|
||
|
|
* Author: CompanyName
|
||
|
|
* Create: 2012-07-14
|
||
|
|
*/
|
||
|
|
|
||
|
|
#include "uart_drv.h"
|
||
|
|
#include "uart.h"
|
||
|
|
#include "soc_mdm_isr.h"
|
||
|
|
#include "errno.h"
|
||
|
|
|
||
|
|
#include <soc_stdlib.h>
|
||
|
|
#include <los_hwi.h>
|
||
|
|
#include <los_base.h>
|
||
|
|
#include <los_memory.h>
|
||
|
|
#include <soc_mdm_time.h>
|
||
|
|
#include <soc_mdm_mem.h>
|
||
|
|
#include <dw21_platform_rom.h>
|
||
|
|
|
||
|
|
#define UART_RBR 0x00 /* Receive buff. */
|
||
|
|
#define UART_THR 0x00 /* Transmit Holding */
|
||
|
|
#define UART_DLL 0x00 /* Divisor Latch Low */
|
||
|
|
#define UART_DLH 0x04 /* Divisor Latch High */
|
||
|
|
#define UART_IER 0x04 /* int enable */
|
||
|
|
#define UART_IIR 0x08 /* interrupt indentification REG */
|
||
|
|
#define UART_FCR 0x08 /* FIFO control */
|
||
|
|
#define UART_LCR 0x0C /* Line control */
|
||
|
|
#define UART_MCR 0x10 /* Line control */
|
||
|
|
#define UART_LSR 0x14 /* Line statue */
|
||
|
|
#define UART_USR 0x7C /* Uart statues */
|
||
|
|
#define UART_TFL 0x80
|
||
|
|
#define UART_RFL 0x84
|
||
|
|
#define UART_HTX 0xA4 /* Halt Tx */
|
||
|
|
|
||
|
|
#define UART_FCR_RXFIFO_ONEBYTE 0
|
||
|
|
#define UART_FCR_RXFIFO_QUARTER (1 << 6)
|
||
|
|
#define UART_FCR_RXFIFO_HALF (2 << 6)
|
||
|
|
#define UART_FCR_RXFIFO_2TOFULL (3 << 6)
|
||
|
|
#define UART_FCR_TXFIFO_EMPTY 0
|
||
|
|
#define UART_FCR_TXFIFO_2BYTE (1 << 4)
|
||
|
|
#define UART_FCR_TXFIFO_QUARTER (2 << 4)
|
||
|
|
#define UART_FCR_TXFIFO_HALF (3 << 4)
|
||
|
|
#define UART_FCR_RESET_TXFIFO (1 << 2)
|
||
|
|
#define UART_FCR_RESET_RXFIFO (1 << 1)
|
||
|
|
#define UART_FCR_ENABLE_FIFO (1 << 0)
|
||
|
|
|
||
|
|
#define FCR_CONFIG_VAL \
|
||
|
|
(UART_FCR_RXFIFO_QUARTER | UART_FCR_TXFIFO_2BYTE | UART_FCR_RESET_TXFIFO | UART_FCR_RESET_RXFIFO | \
|
||
|
|
UART_FCR_ENABLE_FIFO)
|
||
|
|
|
||
|
|
#define UART_FIFO_TX_SIZE 16
|
||
|
|
#define UART_IER_TX (0x01 << 1)
|
||
|
|
#define UART_IER_RX (0x01 << 0)
|
||
|
|
#define UART_IER_TF (0x01 << 8) /* Tx finish */
|
||
|
|
#define UART_IER_MASK 0x18F
|
||
|
|
|
||
|
|
#define UART_IIR_RX_TIMEOUT (0x03 << 2)
|
||
|
|
#define UART_IIR_RX (0x01 << 2)
|
||
|
|
#define UART_IIR_TX (0x01 << 1)
|
||
|
|
#define UART_IIR_TF 0xE /* Tx finish */
|
||
|
|
|
||
|
|
#define UART_USR_BUSY (0x01 << 0)
|
||
|
|
#define UART_USR_TXF_NF (0x01 << 1)
|
||
|
|
#define UART_USR_TXF_E (0x01 << 2)
|
||
|
|
#define UART_USR_RXF_NE (0X01 << 3)
|
||
|
|
|
||
|
|
#define UART_LSR_OE 0x02 /* overrun error */
|
||
|
|
#define UART_LSR_PE 0x04 /* parity error */
|
||
|
|
#define UART_LSR_FE 0x08 /* framing error */
|
||
|
|
#define UART_LSR_BI 0x10 /* break interrupt */
|
||
|
|
|
||
|
|
int g_irq_send_count = 0;
|
||
|
|
|
||
|
|
#define ext_uart_buffer_lock(x) uapi_int_lock()
|
||
|
|
#define ext_uart_buffer_unlock(x, val) uapi_int_restore(val)
|
||
|
|
|
||
|
|
int uart_circ_buf_empty(EXT_CONST uart_circ_buf_t *transfer)
|
||
|
|
{
|
||
|
|
if (transfer->flags & BUF_CIRCLED) {
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (transfer->wp == transfer->rp) {
|
||
|
|
return 1;
|
||
|
|
} else {
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
__init unsigned int uart_init_circ_buf(uart_driver_data_t *udd, unsigned int rx_buf_size, unsigned int tx_buf_size)
|
||
|
|
{
|
||
|
|
if ((rx_buf_size == 0) || (tx_buf_size == 0)) {
|
||
|
|
return EXT_ERR_INVALID_PARAMETER;
|
||
|
|
}
|
||
|
|
|
||
|
|
udd->rx_transfer = (uart_circ_buf_t *)uapi_malloc(EXT_MOD_ID_UART, sizeof(uart_circ_buf_t));
|
||
|
|
if (udd->rx_transfer == NULL) {
|
||
|
|
goto END;
|
||
|
|
}
|
||
|
|
(td_void)memset_s((td_void *)udd->rx_transfer, sizeof(uart_circ_buf_t), 0, sizeof(uart_circ_buf_t));
|
||
|
|
udd->rx_transfer->data = (char *)uapi_malloc(EXT_MOD_ID_UART, rx_buf_size);
|
||
|
|
if (udd->rx_transfer->data == NULL) {
|
||
|
|
goto FREE_RX_TRANSFER;
|
||
|
|
}
|
||
|
|
udd->rx_transfer->size = rx_buf_size;
|
||
|
|
|
||
|
|
udd->tx_transfer = (uart_circ_buf_t *)uapi_malloc(EXT_MOD_ID_UART, sizeof(uart_circ_buf_t));
|
||
|
|
if (udd->tx_transfer == NULL) {
|
||
|
|
goto FREE_RX_CIRC_BUF;
|
||
|
|
}
|
||
|
|
(td_void)memset_s((td_void *)udd->tx_transfer, sizeof(uart_circ_buf_t), 0, sizeof(uart_circ_buf_t));
|
||
|
|
udd->tx_transfer->data = (char *)uapi_malloc(EXT_MOD_ID_UART, tx_buf_size);
|
||
|
|
if (udd->tx_transfer->data == NULL) {
|
||
|
|
goto FREE_TX_CIRC_BUF;
|
||
|
|
}
|
||
|
|
udd->tx_transfer->size = tx_buf_size;
|
||
|
|
|
||
|
|
return EXT_ERR_SUCCESS;
|
||
|
|
|
||
|
|
FREE_TX_CIRC_BUF:
|
||
|
|
uapi_free(EXT_MOD_ID_UART, (VOID *)udd->tx_transfer);
|
||
|
|
udd->tx_transfer = TD_NULL;
|
||
|
|
|
||
|
|
FREE_RX_CIRC_BUF:
|
||
|
|
uapi_free(EXT_MOD_ID_UART, (VOID *)udd->rx_transfer->data);
|
||
|
|
udd->rx_transfer->data = TD_NULL;
|
||
|
|
FREE_RX_TRANSFER:
|
||
|
|
uapi_free(EXT_MOD_ID_UART, (VOID *)udd->rx_transfer);
|
||
|
|
udd->rx_transfer = TD_NULL;
|
||
|
|
END:
|
||
|
|
return EXT_ERR_FAILURE;
|
||
|
|
}
|
||
|
|
|
||
|
|
__init void uart_deinit_circ_buf(uart_driver_data_t *udd)
|
||
|
|
{
|
||
|
|
if (udd->rx_transfer != TD_NULL) {
|
||
|
|
if (udd->rx_transfer->data != TD_NULL) {
|
||
|
|
uapi_free(EXT_MOD_ID_UART, udd->rx_transfer->data);
|
||
|
|
udd->rx_transfer->data = TD_NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
uapi_free(EXT_MOD_ID_UART, udd->rx_transfer);
|
||
|
|
udd->rx_transfer = TD_NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (udd->tx_transfer != TD_NULL) {
|
||
|
|
if (udd->tx_transfer->data != TD_NULL) {
|
||
|
|
uapi_free(EXT_MOD_ID_UART, udd->tx_transfer->data);
|
||
|
|
udd->tx_transfer->data = TD_NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
uapi_free(EXT_MOD_ID_UART, udd->tx_transfer);
|
||
|
|
udd->tx_transfer = TD_NULL;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
int uart_read_circ_buf(uart_circ_buf_t *transfer, char *buf, size_t count)
|
||
|
|
{
|
||
|
|
if (transfer == NULL) {
|
||
|
|
return -EFAULT;
|
||
|
|
}
|
||
|
|
td_u32 last_int_val = ext_uart_buffer_lock(transfer);
|
||
|
|
unsigned int wp = transfer->wp;
|
||
|
|
unsigned int rp = transfer->rp;
|
||
|
|
unsigned int flags = transfer->flags;
|
||
|
|
ext_uart_buffer_unlock(transfer, last_int_val);
|
||
|
|
unsigned long data = (unsigned long)(uintptr_t)transfer->data;
|
||
|
|
unsigned int buf_size = transfer->size;
|
||
|
|
if ((flags & BUF_CIRCLED) == 0) {
|
||
|
|
if (count >= (wp - rp)) {
|
||
|
|
count = wp - rp;
|
||
|
|
}
|
||
|
|
if (count > 0 && memcpy_s(buf, count, (void *)((uintptr_t)data + rp), count) != EOK) {
|
||
|
|
return -EFAULT;
|
||
|
|
}
|
||
|
|
transfer->rp += count;
|
||
|
|
return (int)count;
|
||
|
|
} else {
|
||
|
|
if (count < (buf_size - rp)) {
|
||
|
|
if (count > 0 && memcpy_s(buf, count, (void *)((uintptr_t)data + rp), count) != EOK) {
|
||
|
|
return -EFAULT;
|
||
|
|
}
|
||
|
|
transfer->rp += count;
|
||
|
|
return (int)count;
|
||
|
|
} else {
|
||
|
|
unsigned int copy_size = buf_size - rp;
|
||
|
|
unsigned int left_size = count - copy_size;
|
||
|
|
if (copy_size > 0 && memcpy_s(buf, copy_size, (void *)((uintptr_t)data + rp), copy_size) != EOK) {
|
||
|
|
return -EFAULT;
|
||
|
|
}
|
||
|
|
rp = 0;
|
||
|
|
if (left_size > wp) {
|
||
|
|
left_size = wp;
|
||
|
|
}
|
||
|
|
if (left_size > 0 &&
|
||
|
|
memcpy_s((void *)(buf + copy_size), left_size, (void *)((uintptr_t)data + rp), left_size) != EOK) {
|
||
|
|
return -EFAULT;
|
||
|
|
}
|
||
|
|
last_int_val = ext_uart_buffer_lock(transfer);
|
||
|
|
transfer->rp = left_size;
|
||
|
|
transfer->flags &= ~BUF_CIRCLED;
|
||
|
|
ext_uart_buffer_unlock(transfer, last_int_val);
|
||
|
|
return (int)(copy_size + left_size);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
unsigned char uart_rx_fifo_num(EXT_CONST uart_driver_data_t *udd)
|
||
|
|
{
|
||
|
|
return (unsigned char)UAPI_REG_READ_VAL32((uintptr_t)udd->phys_base + UART_RFL);
|
||
|
|
}
|
||
|
|
|
||
|
|
int uart_write_circ_buf(uart_circ_buf_t *transfer, const char *buf, size_t count)
|
||
|
|
{
|
||
|
|
if (transfer == NULL) {
|
||
|
|
return -EFAULT;
|
||
|
|
}
|
||
|
|
td_u32 last_int_val = ext_uart_buffer_lock(transfer);
|
||
|
|
unsigned int wp = transfer->wp;
|
||
|
|
unsigned int rp = transfer->rp;
|
||
|
|
unsigned int flags = transfer->flags;
|
||
|
|
ext_uart_buffer_unlock(transfer, last_int_val);
|
||
|
|
unsigned long data = (unsigned long)(uintptr_t)transfer->data;
|
||
|
|
unsigned int buf_size = transfer->size;
|
||
|
|
if ((flags & BUF_CIRCLED) == 0) {
|
||
|
|
if (count < (buf_size - wp)) {
|
||
|
|
if (count > 0 && memcpy_s((void *)((uintptr_t)data + wp), count, buf, count) != EOK) {
|
||
|
|
return -EFAULT;
|
||
|
|
}
|
||
|
|
transfer->wp += count;
|
||
|
|
return (int)count;
|
||
|
|
} else {
|
||
|
|
unsigned int copy_size = buf_size - wp;
|
||
|
|
unsigned int left_size = count - copy_size;
|
||
|
|
if (copy_size > 0 && memcpy_s((void *)((uintptr_t)data + wp), copy_size, buf, copy_size) != EOK) {
|
||
|
|
return -EFAULT;
|
||
|
|
}
|
||
|
|
wp = 0;
|
||
|
|
if (left_size > rp) {
|
||
|
|
/* overflowed. some new data will be discarded */
|
||
|
|
left_size = rp;
|
||
|
|
}
|
||
|
|
if (left_size > 0 &&
|
||
|
|
memcpy_s((void *)((uintptr_t)data + wp), left_size, (void *)(buf + copy_size), left_size) != EOK) {
|
||
|
|
return -EFAULT;
|
||
|
|
}
|
||
|
|
last_int_val = ext_uart_buffer_lock(transfer);
|
||
|
|
transfer->wp = left_size;
|
||
|
|
transfer->flags |= BUF_CIRCLED;
|
||
|
|
ext_uart_buffer_unlock(transfer, last_int_val);
|
||
|
|
return (int)(copy_size + left_size);
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
if (count > (rp - wp)) {
|
||
|
|
/* overflowed. some new data will be discarded */
|
||
|
|
count = rp - wp;
|
||
|
|
}
|
||
|
|
if (count > 0 && memcpy_s((void *)((uintptr_t)data + wp), count, buf, count) != EOK) {
|
||
|
|
return -EFAULT;
|
||
|
|
}
|
||
|
|
transfer->wp += count;
|
||
|
|
return (int)count;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void uart_tx_interrupt_disable(EXT_CONST uart_driver_data_t *udd)
|
||
|
|
{
|
||
|
|
unsigned int tx_status = UAPI_REG_READ_VAL32(udd->phys_base + UART_IER);
|
||
|
|
UAPI_REG_WRITE32((uintptr_t)udd->phys_base + UART_IER, (~UART_IER_TX) & tx_status);
|
||
|
|
}
|
||
|
|
|
||
|
|
void uart_tx_interrupt_enable(EXT_CONST uart_driver_data_t *udd)
|
||
|
|
{
|
||
|
|
unsigned int tx_status = UAPI_REG_READ_VAL32(udd->phys_base + UART_IER);
|
||
|
|
UAPI_REG_WRITE32((uintptr_t)udd->phys_base + UART_IER, (unsigned short)(UART_IER_TX | tx_status));
|
||
|
|
}
|
||
|
|
|
||
|
|
void uart_rx_interrupt_disable(EXT_CONST uart_driver_data_t *udd)
|
||
|
|
{
|
||
|
|
unsigned int tx_status = UAPI_REG_READ_VAL32(udd->phys_base + UART_IER);
|
||
|
|
UAPI_REG_WRITE32((uintptr_t)udd->phys_base + UART_IER, ~(UART_IER_RX)&tx_status);
|
||
|
|
}
|
||
|
|
|
||
|
|
EXT_PRV void uart_rx_interrupt_enable(EXT_CONST uart_driver_data_t *udd)
|
||
|
|
{
|
||
|
|
unsigned int tx_status = UAPI_REG_READ_VAL32(udd->phys_base + UART_IER);
|
||
|
|
UAPI_REG_WRITE32((uintptr_t)udd->phys_base + UART_IER, UART_IER_RX | tx_status);
|
||
|
|
}
|
||
|
|
|
||
|
|
void uart_tf_interrupt_disable(EXT_CONST uart_driver_data_t *udd)
|
||
|
|
{
|
||
|
|
unsigned int tx_status = UAPI_REG_READ_VAL32((uintptr_t)udd->phys_base + UART_IER);
|
||
|
|
UAPI_REG_WRITE32((uintptr_t)udd->phys_base + UART_IER, ~(UART_IER_TF)&tx_status);
|
||
|
|
}
|
||
|
|
EXT_PRV void uart_tf_interrupt_enable(EXT_CONST uart_driver_data_t *udd)
|
||
|
|
{
|
||
|
|
unsigned int tx_status = UAPI_REG_READ_VAL32((uintptr_t)udd->phys_base + UART_IER);
|
||
|
|
UAPI_REG_WRITE32((uintptr_t)udd->phys_base + UART_IER, UART_IER_TF | tx_status);
|
||
|
|
}
|
||
|
|
|
||
|
|
EXT_PRV td_u32 uart_interrupt_disable(EXT_CONST uart_driver_data_t *udd)
|
||
|
|
{
|
||
|
|
unsigned int int_val = UAPI_REG_READ_VAL32((uintptr_t)udd->phys_base + UART_IER);
|
||
|
|
UAPI_REG_WRITE32((uintptr_t)udd->phys_base + UART_IER, int_val & (~UART_IER_MASK));
|
||
|
|
return int_val;
|
||
|
|
}
|
||
|
|
|
||
|
|
EXT_PRV void uart_interrupt_restore(EXT_CONST uart_driver_data_t *udd, td_u32 int_val)
|
||
|
|
{
|
||
|
|
UAPI_REG_WRITE32((uintptr_t)udd->phys_base + UART_IER, int_val);
|
||
|
|
}
|
||
|
|
|
||
|
|
EXT_PRV void get_recv_irq_err(unsigned int int_status, uart_drv_stat_info_t *uart_stat_info)
|
||
|
|
{
|
||
|
|
if ((int_status & UART_LSR_OE) != 0) {
|
||
|
|
(uart_stat_info->recv_irq_err_overrun)++;
|
||
|
|
}
|
||
|
|
|
||
|
|
if ((int_status & UART_LSR_PE) != 0) {
|
||
|
|
(uart_stat_info->recv_irq_err_parity)++;
|
||
|
|
}
|
||
|
|
|
||
|
|
if ((int_status & UART_LSR_FE) != 0) {
|
||
|
|
(uart_stat_info->recv_irq_err_frame)++;
|
||
|
|
}
|
||
|
|
|
||
|
|
if ((int_status & UART_LSR_BI) != 0) {
|
||
|
|
(uart_stat_info->recv_irq_err_break)++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
EXT_PRV void uart_drv_iir_tx_proc(uart_driver_data_t *udd, char *buf, td_u32 len)
|
||
|
|
{
|
||
|
|
ext_unref_param(len);
|
||
|
|
if (udd->tx_transfer == TD_NULL || udd->ops == TD_NULL) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
if (uart_circ_buf_empty(udd->tx_transfer) == TD_TRUE) {
|
||
|
|
uart_tx_interrupt_disable(udd);
|
||
|
|
uart_tf_interrupt_enable(udd);
|
||
|
|
} else {
|
||
|
|
unsigned int tfl = UAPI_REG_READ_VAL32(udd->phys_base + UART_TFL);
|
||
|
|
EXT_CONST unsigned int tx_fifo_cnt = UART_FIFO_TX_SIZE - tfl;
|
||
|
|
unsigned int count = (unsigned int)udd->tx_send(udd->tx_transfer, buf, tx_fifo_cnt);
|
||
|
|
if (udd->ops->start_tx) {
|
||
|
|
(void)udd->ops->start_tx(udd, buf, count);
|
||
|
|
}
|
||
|
|
if ((udd->flags & UART_FLG_WD_BLOCK) != 0) {
|
||
|
|
(void)LOS_EventWrite(&udd->uart_event, UART_WD_EVENT);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
#ifdef UART_DEBUG_INFO
|
||
|
|
udd->uart_stat_info.send_irq_cnt++;
|
||
|
|
#endif
|
||
|
|
}
|
||
|
|
#define BUFF_SIZE 64
|
||
|
|
|
||
|
|
EXT_PRV void uart_drv_irq_stat_count(uart_driver_data_t *udd, unsigned int count, unsigned int rcv_suc_cnt)
|
||
|
|
{
|
||
|
|
udd->uart_stat_info.recv_irq_cnt++;
|
||
|
|
udd->uart_stat_info.recv_irq_data_cnt += count;
|
||
|
|
udd->uart_stat_info.recv_irq_data_suc_cnt += rcv_suc_cnt;
|
||
|
|
if (rcv_suc_cnt < count) {
|
||
|
|
udd->uart_stat_info.recv_buf_overflow_cnt++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
EXT_PRV void uart_drv_irq(td_u32 data)
|
||
|
|
{
|
||
|
|
char buf[BUFF_SIZE] = { 0 };
|
||
|
|
unsigned int count = 0;
|
||
|
|
unsigned int rcv_suc_cnt = 0;
|
||
|
|
uintptr_t data_t = (uintptr_t)data;
|
||
|
|
uart_driver_data_t *udd = (uart_driver_data_t *)data_t;
|
||
|
|
if (udd == NULL || udd->rx_transfer == TD_NULL) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
uart_drv_stat_info_t *uart_stat_info = &(udd->uart_stat_info);
|
||
|
|
unsigned int status = UAPI_REG_READ_VAL32(udd->phys_base + UART_IIR) & 0xf;
|
||
|
|
if ((status == UART_IIR_RX_TIMEOUT) || (status == UART_IIR_RX)) {
|
||
|
|
get_recv_irq_err(UAPI_REG_READ_VAL32(udd->phys_base + UART_LSR), uart_stat_info);
|
||
|
|
do {
|
||
|
|
unsigned int usr = UAPI_REG_READ_VAL32(udd->phys_base + UART_USR);
|
||
|
|
/* if uart hardware rx fifo is empty, go out of circle */
|
||
|
|
if (((usr & UART_USR_RXF_NE) == 0) && (count == 0)) {
|
||
|
|
UAPI_REG_READ_VAL32((td_u32)(udd->phys_base + (td_u32)UART_RBR));
|
||
|
|
(udd->uart_stat_info.recv_irq_err_emptyfifo_cnt)++;
|
||
|
|
}
|
||
|
|
if ((usr & UART_USR_RXF_NE) == 0) {
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
buf[count] = (char)UAPI_REG_READ_VAL32(udd->phys_base + UART_RBR);
|
||
|
|
if (udd->uart_stat_info.recv_last_context.num < EXT_UART_LAST_RECORD_BYTE_COUNT) {
|
||
|
|
udd->uart_stat_info.recv_last_context.data[udd->uart_stat_info.recv_last_context.num] =
|
||
|
|
(unsigned char)buf[count];
|
||
|
|
}
|
||
|
|
udd->uart_stat_info.recv_last_context.num++;
|
||
|
|
udd->uart_stat_info.recv_last_context.num &= (EXT_UART_LAST_RECORD_BYTE_COUNT - 1);
|
||
|
|
count++;
|
||
|
|
} while (count < BUFF_SIZE);
|
||
|
|
if (count >= 1) {
|
||
|
|
rcv_suc_cnt = (unsigned int)udd->rx_recv(udd->rx_transfer, buf, count);
|
||
|
|
if ((udd->flags & UART_FLG_RD_BLOCK) != 0) {
|
||
|
|
LOS_EventWrite(&udd->uart_event, UART_RD_EVENT);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
#ifdef UART_DEBUG_INFO
|
||
|
|
uart_drv_irq_stat_count(udd, count, rcv_suc_cnt);
|
||
|
|
#endif
|
||
|
|
}
|
||
|
|
if (status == UART_IIR_TX) {
|
||
|
|
/* disable uart tx fifo interrupt */
|
||
|
|
uart_drv_iir_tx_proc(udd, buf, sizeof(buf));
|
||
|
|
} else if (status == UART_IIR_TF) {
|
||
|
|
uart_tf_interrupt_disable(udd);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
#define WRITE_LCR_TIMEOUT 1000000
|
||
|
|
#define LCR_DLAB 0x80
|
||
|
|
EXT_PRV void writelcr(EXT_CONST uart_driver_data_t *udd, unsigned int val)
|
||
|
|
{
|
||
|
|
unsigned int usr = 0;
|
||
|
|
unsigned int lcr;
|
||
|
|
unsigned int timeout_cnt = 0;
|
||
|
|
unsigned int i = 0;
|
||
|
|
|
||
|
|
lcr = UAPI_REG_READ_VAL32((uintptr_t)udd->phys_base + UART_LCR);
|
||
|
|
while (lcr != val) {
|
||
|
|
if (timeout_cnt++ >= WRITE_LCR_TIMEOUT) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
usr = UAPI_REG_READ_VAL32((uintptr_t)udd->phys_base + UART_USR);
|
||
|
|
while (usr & UART_USR_BUSY) {
|
||
|
|
uapi_udelay(1);
|
||
|
|
if (timeout_cnt++ >= WRITE_LCR_TIMEOUT) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
lcr = UAPI_REG_READ_VAL32((uintptr_t)udd->phys_base + UART_LCR);
|
||
|
|
for (i = 0; i < UART_FIFO_TX_SIZE + 1 && !(lcr & LCR_DLAB); i++) {
|
||
|
|
(void)UAPI_REG_READ_VAL32((uintptr_t)udd->phys_base + UART_RBR);
|
||
|
|
}
|
||
|
|
|
||
|
|
if ((lcr & LCR_DLAB)) {
|
||
|
|
/* reset fifo */
|
||
|
|
UAPI_REG_WRITE32((uintptr_t)udd->phys_base + UART_FCR, FCR_CONFIG_VAL);
|
||
|
|
}
|
||
|
|
|
||
|
|
usr = UAPI_REG_READ_VAL32((uintptr_t)udd->phys_base + UART_USR);
|
||
|
|
}
|
||
|
|
|
||
|
|
UAPI_REG_WRITE32((uintptr_t)udd->phys_base + UART_LCR, val);
|
||
|
|
lcr = UAPI_REG_READ_VAL32((uintptr_t)udd->phys_base + UART_LCR);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
__init static void uart_drv_set_attr(EXT_CONST uart_driver_data_t *udd)
|
||
|
|
{
|
||
|
|
unsigned int baudrate;
|
||
|
|
unsigned int lcr = 0;
|
||
|
|
unsigned int mcr;
|
||
|
|
|
||
|
|
unsigned int divider;
|
||
|
|
unsigned char divider_h;
|
||
|
|
unsigned char divider_l;
|
||
|
|
|
||
|
|
unsigned int uv_int_save;
|
||
|
|
|
||
|
|
/* Caculate devide */
|
||
|
|
baudrate= uapi_min(CONFIG_MAX_BAUDRATE, udd->attr.baudrate);
|
||
|
|
baudrate = 16 * baudrate; /* Calculate the baud rate and multiply by 16 */
|
||
|
|
divider = ((g_cfg_uart_clock * 10) / baudrate + 5) / 10; /* Serial clock *10/baud rate + 5 */
|
||
|
|
|
||
|
|
divider_h = ((divider) & 0xff00) >> 8; /* Exchange high and low 8 */
|
||
|
|
divider_l = ((divider) & 0x00ff);
|
||
|
|
|
||
|
|
if (udd->attr.data_bits == 5) { /* data bit, 5bit */
|
||
|
|
lcr |= (DATA_BIT_5);
|
||
|
|
} else if (udd->attr.data_bits == 6) { /* data 6bit */
|
||
|
|
lcr |= (DATA_BIT_6);
|
||
|
|
} else if (udd->attr.data_bits == 7) { /* data 7bit */
|
||
|
|
lcr |= (DATA_BIT_7);
|
||
|
|
} else { /* data 8bit */
|
||
|
|
lcr |= (DATA_BIT_8);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (udd->attr.stop_bits == 1) {
|
||
|
|
lcr |= (STOP_BIT_1);
|
||
|
|
} else if (udd->attr.stop_bits == STOP_BIT_1P5 || udd->attr.stop_bits == STOP_BIT_2) {
|
||
|
|
lcr |= (STOP_BIT_2);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (udd->attr.parity == PARITY_NONE) {
|
||
|
|
lcr |= (PARITY_NONE);
|
||
|
|
} else if (udd->attr.parity == PARITY_ODD) {
|
||
|
|
lcr |= (PARITY_ODD);
|
||
|
|
} else if (udd->attr.parity == PARITY_EVEN) {
|
||
|
|
lcr |= (PARITY_EVEN);
|
||
|
|
}
|
||
|
|
|
||
|
|
uv_int_save = uart_interrupt_disable(udd);
|
||
|
|
|
||
|
|
/* loopback mode */
|
||
|
|
mcr = UAPI_REG_READ_VAL32((uintptr_t)udd->phys_base + UART_MCR);
|
||
|
|
UAPI_REG_WRITE32((uintptr_t)udd->phys_base + UART_MCR, mcr | (1 << 4)); /* get 4 bit */
|
||
|
|
|
||
|
|
writelcr(udd, 0x80);
|
||
|
|
|
||
|
|
/* configure DLL and DLH */
|
||
|
|
UAPI_REG_WRITE32((uintptr_t)udd->phys_base + UART_DLL, divider_l);
|
||
|
|
UAPI_REG_WRITE32((uintptr_t)udd->phys_base + UART_DLH, divider_h);
|
||
|
|
|
||
|
|
writelcr(udd, lcr);
|
||
|
|
|
||
|
|
mcr = UAPI_REG_READ_VAL32((uintptr_t)udd->phys_base + UART_MCR);
|
||
|
|
UAPI_REG_WRITE32((uintptr_t)udd->phys_base + UART_MCR, mcr & (~(1 << 4))); /* get low 4 bit */
|
||
|
|
|
||
|
|
uart_interrupt_restore(udd, uv_int_save);
|
||
|
|
}
|
||
|
|
|
||
|
|
/* uops */
|
||
|
|
__init static int uart_drv_startup(uart_driver_data_t *udd)
|
||
|
|
{
|
||
|
|
unsigned int ret;
|
||
|
|
unsigned int fcr;
|
||
|
|
|
||
|
|
/* disable interrupt */
|
||
|
|
UAPI_REG_WRITE32((uintptr_t)udd->phys_base + UART_IER, 0);
|
||
|
|
|
||
|
|
/* set baudrate,data_bit,stop_bit,parity */
|
||
|
|
uart_drv_set_attr(udd);
|
||
|
|
|
||
|
|
/* reset and enable FIFO */
|
||
|
|
fcr = FCR_CONFIG_VAL;
|
||
|
|
UAPI_REG_WRITE32((uintptr_t)udd->phys_base + UART_FCR, fcr);
|
||
|
|
|
||
|
|
/* creat interrupt function for uart */
|
||
|
|
ret = uapi_irq_request(udd->irq_num, 3, (lisr_proc_func)uart_drv_irq, (uintptr_t)udd); /* priority 3 */
|
||
|
|
if (ret == 0) {
|
||
|
|
uart_rx_interrupt_enable(udd);
|
||
|
|
uart_tf_interrupt_disable(udd);
|
||
|
|
uapi_irq_enable((td_u32)udd->irq_num);
|
||
|
|
}
|
||
|
|
|
||
|
|
return (td_s32)ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
__init static void uart_drv_shutdown(const struct uart_driver_data *udd)
|
||
|
|
{
|
||
|
|
uart_tf_interrupt_disable(udd);
|
||
|
|
uart_tx_interrupt_disable(udd);
|
||
|
|
uart_rx_interrupt_disable(udd);
|
||
|
|
uapi_irq_disable((td_u32)udd->irq_num);
|
||
|
|
|
||
|
|
LOS_HwiDelete(udd->irq_num);
|
||
|
|
}
|
||
|
|
|
||
|
|
EXT_PRV int uart_drv_start_tx(struct uart_driver_data *udd, const char *buf, size_t count)
|
||
|
|
{
|
||
|
|
unsigned int idx = 0;
|
||
|
|
|
||
|
|
if (count > UART_FIFO_TX_SIZE) {
|
||
|
|
return (int)EXT_ERR_FAILURE;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* if tx fifo is empty, write data to fifo */
|
||
|
|
while (idx < count) {
|
||
|
|
UAPI_REG_WRITE32((uintptr_t)udd->phys_base + UART_THR, (unsigned)(td_u8)buf[idx]);
|
||
|
|
|
||
|
|
if (udd->uart_stat_info.send_last_context.num < EXT_UART_LAST_RECORD_BYTE_COUNT) {
|
||
|
|
udd->uart_stat_info.send_last_context.data[udd->uart_stat_info.send_last_context.num] =
|
||
|
|
(unsigned char)buf[idx];
|
||
|
|
}
|
||
|
|
udd->uart_stat_info.send_last_context.num++;
|
||
|
|
udd->uart_stat_info.send_last_context.num &= (EXT_UART_LAST_RECORD_BYTE_COUNT - 1);
|
||
|
|
|
||
|
|
idx++;
|
||
|
|
}
|
||
|
|
#ifdef UART_DEBUG_INFO
|
||
|
|
udd->uart_stat_info.send_irq_data_cnt += count;
|
||
|
|
#endif
|
||
|
|
return (int)count;
|
||
|
|
}
|
||
|
|
|
||
|
|
__init static int uart_drv_ioctl(uart_driver_data_t *udd)
|
||
|
|
{
|
||
|
|
unsigned int fcr;
|
||
|
|
/* wait for send finish */
|
||
|
|
uart_drv_set_attr(udd);
|
||
|
|
|
||
|
|
/* reset and enable FIFO */
|
||
|
|
fcr = FCR_CONFIG_VAL;
|
||
|
|
UAPI_REG_WRITE32(udd->phys_base + UART_FCR, fcr);
|
||
|
|
|
||
|
|
uart_rx_interrupt_enable(udd);
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
uart_ops_t g_uart_driver_uops = {
|
||
|
|
.startup = uart_drv_startup,
|
||
|
|
.shutdown = uart_drv_shutdown,
|
||
|
|
.start_tx = uart_drv_start_tx,
|
||
|
|
.ioctl = uart_drv_ioctl,
|
||
|
|
};
|