rt-thread-official/bsp/gkipc/drivers/drv_uart.c

475 lines
13 KiB
C

#include <rtdevice.h>
#include "gtypes.h"
#include "gh_uart.h"
#include "gh_debug_rct.h"
#include "gd_uart.h"
#include "gd_int.h"
/*---------------------------------------------------------------------------*/
/* local defines */
/*---------------------------------------------------------------------------*/
#define UART_IRQ_CLEAR_ALL 0x3 /* IRQ CLR Register: rx_IRQ, rx_parity_IRQ */
#define UART_RISING_TXE_RXE 0x3 /* for UART_control register: */
/* clock edge polarity = rising, */
/* TX = enable, RX = enable */
/* UART[x]_FC_REG */
#define UART_FC_RX_ONECHAR 0x0 /* RCVR_Trigger: FIFO has 1 char */
#define UART_FC_RX_QUARTER_FULL 0x1 /* RCVR_Trigger: FIFO is one-fourth to full */
#define UART_FC_RX_HALF_FULL 0x2 /* RCVR_Trigger: FIFO is half to full */
#define UART_FC_RX_2_TO_FULL 0x3 /* RCVR_Trigger: FIFO is 2 char to full */
#define UART_FC_TX_EMPTY 0x0 /* TX_Empty_Trigger: FIFO is empty */
#define UART_FC_TX_2_IN_FIFO 0x1 /* TX_Empty_Trigger: FIFO has 2 char */
#define UART_FC_TX_QUATER_IN_FIFO 0x2 /* TX_Empty_Trigger: FIFO is one-fourth to full */
#define UART_FC_TX_HALF_IN_FIFO 0x3 /* TX_Empty_Trigger: FIFO is half to full */
/* UART[x]_II_REG */
#define UART_II_MODEM_STATUS_CHANGED 0x0
#define UART_II_NO_INT_PENDING 0x1
#define UART_II_THR_EMPTY 0x2
#define UART_II_RCV_DATA_AVAIL 0x4
#define UART_II_RCV_STATUS 0x6
#define UART_II_CHAR_TIMEOUT 0xc
#define MAX_UART_CNT (3)
/*---------------------------------------------------------------------------*/
/* local data types */
/*---------------------------------------------------------------------------*/
struct gk_uart
{
u8 index;
};
/*---------------------------------------------------------------------------*/
/* local data */
/*---------------------------------------------------------------------------*/
static struct gk_uart uart[MAX_UART_CNT] =
{
{0},{1},{2}
};
static GD_HANDLE intHandle[MAX_UART_CNT];
static struct rt_serial_device serial[MAX_UART_CNT];
/*---------------------------------------------------------------------------*/
/* local functions */
/*---------------------------------------------------------------------------*/
static void uartSetBaudrate(U32 index, U32 baudRate)
{
U32 brdi;
GH_PLL_set_SCALER_UART(0x01);
brdi = (48000000/2) * 10 / baudRate / 16;
if (brdi % 10 >= 5)
brdi = (brdi / 10) + 1;
else
brdi = (brdi / 10);
GH_UART_set_LCR_dlab(index, 1);
GH_UART_set_DLL_BaudDivint_L(index, brdi & 0xff);
GH_UART_set_DLH_BaudDivint_H(index, (brdi >> 8) & 0xff);
GH_UART_set_LCR_dlab(index, 0);
}
static void uartSetDataBits(U32 index, U32 dataBits)
{
U32 data_bits = dataBits;
// 0 = use 5 data bits
// 1 = use 6 data bits
// 2 = use 7 data bits
// 3 = use 8 data bits
//data_bits -= GD_UART_5_DATATBITS;
if(GH_UART_get_LCR_cls(index) != data_bits)
{
GH_UART_set_LCR_cls(index, data_bits);
}
}
static void uartSetStopBits(U32 index, U32 stopBits)
{
// 0 = use 1 stop bit
// 1 = use 2 stop bits
if(GH_UART_get_LCR_stop(index) != stopBits)
{
GH_UART_set_LCR_stop(index, stopBits);
}
}
static void uartSetParity(U32 index, U32 parity)
{
switch(parity)
{
case GD_UART_NO_PARITY:
if(GH_UART_get_LCR_pen(index))
{
GH_UART_set_LCR_pen(index, 0);
}
break;
case GD_UART_ODD_PARITY:
if(!GH_UART_get_LCR_pen(index))
{
GH_UART_set_LCR_pen(index, 1);
}
if(GH_UART_get_LCR_eps(index))
{
GH_UART_set_LCR_eps(index, 0);
}
break;
case GD_UART_EVEN_PARITY:
if(!GH_UART_get_LCR_pen(index))
{
GH_UART_set_LCR_pen(index, 1);
}
if(!GH_UART_get_LCR_eps(index))
{
GH_UART_set_LCR_eps(index, 1);
}
break;
default:
break;
}
}
static void uartSetFlowControl(U32 index, U32 flowCtrl)
{
if(index == 0)
{
// In UART0, only the Loopback bit is used and flow control is not supported.
// In UART1, all the bits are used.
if((flowCtrl == 0) || (flowCtrl == 0x10))
{
if(GH_UART_get_MCR(index) != flowCtrl)
{
GH_UART_set_MCR(index, flowCtrl);
}
}
return;
}
if(GH_UART_get_MCR(index) != flowCtrl)
{
GH_UART_set_MCR(index, flowCtrl);
}
}
static void uartISR(void)
{
U8 interruptID;
interruptID = GH_UART_get_IIR_interrupt_id(0);
switch (interruptID)
{
case UART_II_MODEM_STATUS_CHANGED:
case UART_II_NO_INT_PENDING:
break;
case UART_II_THR_EMPTY:
rt_hw_serial_isr(&serial[0], RT_SERIAL_EVENT_TX_DONE);
break;
case UART_II_RCV_DATA_AVAIL:
case UART_II_RCV_STATUS:
rt_hw_serial_isr(&serial[0], RT_SERIAL_EVENT_RX_IND);
break;
case UART_II_CHAR_TIMEOUT:
GH_UART_get_RBR_Data(0);
rt_hw_serial_isr(&serial[0], RT_SERIAL_EVENT_RX_TIMEOUT);
break;
default:
break;
}
}
static void uartISR1(void)
{
U8 interruptID;
interruptID = GH_UART_get_IIR_interrupt_id(1);
switch (interruptID)
{
case UART_II_MODEM_STATUS_CHANGED:
case UART_II_NO_INT_PENDING:
break;
case UART_II_THR_EMPTY:
rt_hw_serial_isr(&serial[1], RT_SERIAL_EVENT_TX_DONE);
break;
case UART_II_RCV_DATA_AVAIL:
case UART_II_RCV_STATUS:
rt_hw_serial_isr(&serial[1], RT_SERIAL_EVENT_RX_IND);
break;
case UART_II_CHAR_TIMEOUT:
GH_UART_get_RBR_Data(1);
rt_hw_serial_isr(&serial[1], RT_SERIAL_EVENT_RX_TIMEOUT);
break;
default:
break;
}
}
static void uartISR2(void)
{
U8 interruptID;
interruptID = GH_UART_get_IIR_interrupt_id(2);
switch (interruptID)
{
case UART_II_MODEM_STATUS_CHANGED:
case UART_II_NO_INT_PENDING:
break;
case UART_II_THR_EMPTY:
rt_hw_serial_isr(&serial[2], RT_SERIAL_EVENT_TX_DONE);
break;
case UART_II_RCV_DATA_AVAIL:
case UART_II_RCV_STATUS:
rt_hw_serial_isr(&serial[2], RT_SERIAL_EVENT_RX_IND);
break;
case UART_II_CHAR_TIMEOUT:
GH_UART_get_RBR_Data(2);
rt_hw_serial_isr(&serial[2], RT_SERIAL_EVENT_RX_TIMEOUT);
break;
default:
break;
}
}
static GERR uartSetIntMode(U8 channel)
{
GD_UART_STATE_MACHINE_S* uart_handle_ptr = NULL;
GD_INT_OPEN_PARAMS_S intParams;
GERR ret = GD_OK;
intParams.sensitivity = GD_INT_LEVEL_HIGH; //hhl note: check this value.
intParams.active = GD_INT_INVERT_IRQ;
intParams.priority = GD_INT_MID_PRIORITY;
if(channel == 0)
{
intParams.type = (S8)GD_INT_UART_IRQ;
intParams.isrFct.lowPrio = uartISR;
ret = GD_INT_Open(&intParams, &intHandle[0]);
}
else if(channel == 1)
{
intParams.type = (S8)GD_INT_UART1_IRQ;
intParams.isrFct.lowPrio = uartISR1;
ret = GD_INT_Open(&intParams, &intHandle[1]);
}
else
{
intParams.type = (S8)GD_INT_UART2_IRQ;
intParams.isrFct.lowPrio = uartISR2;
ret = GD_INT_Open(&intParams, &intHandle[2]);
}
return ret;
}
/**
* UART device in RT-Thread
*/
static rt_err_t gk_uart_configure(struct rt_serial_device *serial,
struct serial_configure *cfg)
{
int div;
GD_UART_DATABITS_E data_mode;
GD_UART_STOPBITS_E stop_mode;
GD_UART_PARITY_E parity_mode;
struct gk_uart *uart;
RT_ASSERT(serial != RT_NULL);
RT_ASSERT(cfg != RT_NULL);
uart = (struct gk_uart *)serial->parent.user_data;
switch (cfg->data_bits)
{
case DATA_BITS_8:
data_mode = GD_UART_8_DATATBITS;
break;
case DATA_BITS_7:
data_mode = GD_UART_7_DATATBITS;
break;
case DATA_BITS_6:
data_mode = GD_UART_6_DATATBITS;
break;
case DATA_BITS_5:
data_mode = GD_UART_5_DATATBITS;
break;
default:
data_mode = GD_UART_8_DATATBITS;
break;
}
switch (cfg->stop_bits)
{
case STOP_BITS_2:
stop_mode = GD_UART_20_STOPBITS;//UART_STOP_BIT2;
break;
case STOP_BITS_1:
default:
stop_mode = GD_UART_10_STOPBITS;
break;
}
switch (cfg->parity)
{
case PARITY_ODD:
parity_mode = GD_UART_ODD_PARITY;
break;
case PARITY_EVEN:
parity_mode = GD_UART_EVEN_PARITY;
break;
case PARITY_NONE:
default:
parity_mode = GD_UART_NO_PARITY;
break;
}
uartSetBaudrate(uart->index,cfg->baud_rate);
uartSetDataBits(uart->index, data_mode);
uartSetParity(uart->index, parity_mode);
uartSetStopBits(uart->index, stop_mode);
uartSetFlowControl(uart->index,0);
return RT_EOK;
}
#define RT_DEVICE_CTRL_GET_CONFIG 0xFF
static rt_err_t gk_uart_control(struct rt_serial_device *serial,
int cmd, void *arg)
{
struct gk_uart* uart;
RT_ASSERT(serial != RT_NULL);
uart = (struct gk_uart *)serial->parent.user_data;
switch (cmd)
{
case RT_DEVICE_CTRL_CLR_INT:
/* disable rx irq */
GD_INT_Enable(&intHandle[uart->index],0);
GH_UART_set_IER_erbfi(uart->index, 0);
break;
case RT_DEVICE_CTRL_SET_INT:
/* enable rx irq */
GH_UART_set_FCR_FIFO_Enable(uart->index, 1);
GH_UART_set_FCR_RCVR_Trigger(uart->index, UART_FC_RX_ONECHAR);
GH_UART_set_FCR_TX_Empty_Trigger(uart->index, UART_FC_TX_EMPTY);
GH_UART_set_FCR_XMIT_FIFO_Reset(uart->index, 1);
GH_UART_set_FCR_RCVR_FIFO_Reset(uart->index, 1);
GH_UART_set_IER_etbei(uart->index, 0); //Turn off THRE interrupt
uartSetIntMode(uart->index);
GD_INT_Enable(&intHandle[uart->index],1);
GH_UART_set_IER_erbfi(uart->index,1);
GH_UART_set_IER_elsi(uart->index,1);
break;
case RT_DEVICE_CTRL_GET_CONFIG:
if(!arg)
{
rt_kprintf("%s,line=%d,param is NULL!\n",__FUNCTION__,__LINE__);
return RT_ERROR;
}
*((struct serial_configure *)arg) = serial->config;
break;
default:
break;
}
return RT_EOK;
}
static int gk_uart_putc(struct rt_serial_device *serial, char c)
{
struct gk_uart *uart = serial->parent.user_data;
unsigned int ret;
ret = GH_UART_get_LSR_temt(uart->index);
if(serial->parent.open_flag & RT_DEVICE_FLAG_INT_TX){
GH_UART_set_THR_Data(uart->index, c);
if (GH_UART_get_IER_etbei(uart->index) == 0)
{
GH_UART_set_IER_etbei(uart->index, 1); //Turn on THRE interrupt
}
return 1;
}
else
{
while(!GH_UART_get_LSR_temt(uart->index));
GH_UART_set_THR_Data(uart->index, c);
return 1;
}
}
static int gk_uart_getc(struct rt_serial_device *serial)
{
struct gk_uart *uart = serial->parent.user_data;
if(!GH_UART_get_LSR_dr(uart->index))
return -1;
return GH_UART_get_RBR_Data(uart->index);
}
static const struct rt_uart_ops gk_uart_ops =
{
gk_uart_configure,
gk_uart_control,
gk_uart_putc,
gk_uart_getc,
};
/**
* This function will handle init uart
*/
void rt_hw_uart_init(void)
{
struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
int i;
char devname[6];
for(i=0; i<MAX_UART_CNT; i++)
{
serial[i].ops = &gk_uart_ops;
serial[i].config = config;
rt_sprintf(devname,"uart%d",i);
rt_hw_serial_register(&serial[i], devname,
RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_INT_TX | RT_DEVICE_FLAG_STREAM ,
&uart[i]);
}
}
int GM_Printf(const char *__format, ...)
{
rt_kprintf(__format);
return 0;
}