abstractaccelerator/opene906/smart_run/tests/lib/clib/uart.c

219 lines
7.1 KiB
C

/*Copyright 2020-2021 T-Head Semiconductor Co., Ltd.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include "uart.h"
#include "config.h"
/* UART register bit definitions */
#define USR_UART_BUSY 0x01
#define LSR_DATA_READY 0x01
#define LSR_THR_EMPTY 0x20
#define IER_RDA_INT_ENABLE 0x01
#define IER_THRE_INT_ENABLE 0x02
#define IIR_NO_ISQ_PEND 0x01
#define LCR_SET_DLAB 0x80 /* enable r/w DLR to set the baud rate */
#define LCR_PARITY_ENABLE 0x08 /* parity enabled */
#define LCR_PARITY_EVEN 0x10 /* Even parity enabled */
#define LCR_PARITY_ODD 0xef /* Odd parity enabled */
#define LCR_WORD_SIZE_5 0xfc /* the data length is 5 bits */
#define LCR_WORD_SIZE_6 0x01 /* the data length is 6 bits */
#define LCR_WORD_SIZE_7 0x02 /* the data length is 7 bits */
#define LCR_WORD_SIZE_8 0x03 /* the data length is 8 bits */
#define LCR_STOP_BIT1 0xfb /* 1 stop bit */
#define LCR_STOP_BIT2 0x04 /* 1.5 stop bit */
#define CK_LSR_PFE 0x80
#define CK_LSR_TEMT 0x40
#define CK_LSR_THRE 0x40
#define CK_LSR_BI 0x10
#define CK_LSR_FE 0x08
#define CK_LSR_PE 0x04
#define CK_LSR_OE 0x02
#define CK_LSR_DR 0x01
#define CK_LSR_TRANS_EMPTY 0x20
void ck_uart_set_baudrate(p_ck_uart_device uart_device, uint32_t baudrate)
{ /* {{{ ck_uart_set_baudrate */
uint32_t baud_div;
uint32_t *addr = uart_device->register_map;
baud_div = (APB_FREQ/baudrate) >> 4;
uart_device->baudrate = baudrate;
*(reg8_t*)(addr+CK_UART_LCR) |= LCR_SET_DLAB;
*(reg8_t*)(addr+CK_UART_DLL) = (baud_div & 0xFF);
*(reg8_t*)(addr+CK_UART_DLH) = ((baud_div >> 8) & 0xFF);
*(reg8_t*)(addr+CK_UART_LCR) &= (~LCR_SET_DLAB);
} /* }}} */
void ck_uart_set_parity(p_ck_uart_device uart_device, t_ck_uart_parity parity)
{ /* {{{ ck_uart_set_parity */
uart_device->parity = parity;
switch (parity)
{
case PARITY_NONE:
*(reg8_t*)(uart_device->register_map+CK_UART_LCR) &= (~LCR_PARITY_ENABLE);
break;
case PARITY_ODD:
*(reg8_t*)(uart_device->register_map+CK_UART_LCR) |= LCR_PARITY_ENABLE;
*(reg8_t*)(uart_device->register_map+CK_UART_LCR) &= LCR_PARITY_ODD;
break;
case PARITY_EVEN:
*(reg8_t*)(uart_device->register_map+CK_UART_LCR) |= LCR_PARITY_ENABLE;
*(reg8_t*)(uart_device->register_map+CK_UART_LCR) |= LCR_PARITY_EVEN;
break;
default:
break;
}
} /* }}} */
void ck_uart_set_wordsize(p_ck_uart_device uart_device, t_ck_uart_wordsize wordsize)
{ /* {{{ ck_uart_set_wordsize */
uart_device->wordsize = wordsize;
switch (wordsize)
{
case WORDSIZE_5:
*(reg8_t*)(uart_device->register_map+CK_UART_LCR) &= LCR_WORD_SIZE_5;
break;
case WORDSIZE_6:
*(reg8_t*)(uart_device->register_map+CK_UART_LCR) &= 0xfd;
*(reg8_t*)(uart_device->register_map+CK_UART_LCR) |= LCR_WORD_SIZE_6;
break;
case WORDSIZE_7:
*(reg8_t*)(uart_device->register_map+CK_UART_LCR) &= 0xfe;
*(reg8_t*)(uart_device->register_map+CK_UART_LCR) |= LCR_WORD_SIZE_7;
break;
case WORDSIZE_8:
*(reg8_t*)(uart_device->register_map+CK_UART_LCR) |= LCR_WORD_SIZE_8;
break;
default:
break;
}
} /* }}} */
void ck_uart_set_stopbit(p_ck_uart_device uart_device, t_ck_uart_stopbit stopbit)
{ /* {{{ ck_uart_set_stopbit */
uart_device->stopbit = stopbit;
switch(stopbit)
{
case STOPBIT_1:
*(reg8_t*)(uart_device->register_map+CK_UART_LCR) &= LCR_STOP_BIT1;
break;
case STOPBIT_2:
*(reg8_t*)(uart_device->register_map+CK_UART_LCR) |= LCR_STOP_BIT2;
break;
default:
break;
}
} /* }}} */
void ck_uart_set_rxmode(p_ck_uart_device uart_device, t_ck_uart_mode rxmode)
{ /* {{{ ck_uart_set_rxmode */
uart_device->rxmode = rxmode;
} /* }}} */
void ck_uart_set_txmode(p_ck_uart_device uart_device, t_ck_uart_mode txmode)
{ /* {{{ ck_uart_set_txmode */
uart_device->txmode = txmode;
} /* }}} */
/*
* @brief open a UART device, use id to select
* if more than one UART devices exist in SOC
* @param uart_device: uart device handler
* @param id: UART device ID
* @retval 0 if success, 1 if fail
*/
uint32_t ck_uart_open(p_ck_uart_device uart_device, uint32_t id)
{
if (id == 0)
{
uart_device->uart_id = 0;
uart_device->register_map = (uint32_t*)UART0_BASE_ADDR;
return 0;
}
else
{
return 1;
}
}
/*
* @brief Initialize UART configurations from uart_cfig data structure
* @param uart_device: uart device handler
* @param uart_cfig: uart configurations collection, a structure datatype
* @retval 0 if success, 1 if fail
*/
uint32_t ck_uart_init(p_ck_uart_device uart_device, p_ck_uart_cfig uart_cfig)
{
if (uart_device->uart_id == 0xFFFF)
return 1;
ck_uart_set_baudrate(uart_device, uart_cfig->baudrate);
ck_uart_set_parity(uart_device, uart_cfig->parity);
ck_uart_set_wordsize(uart_device, uart_cfig->wordsize);
ck_uart_set_stopbit(uart_device, uart_cfig->stopbit);
ck_uart_set_rxmode(uart_device, uart_cfig->rxmode);
ck_uart_set_txmode(uart_device, uart_cfig->txmode);
return 0;
}
/*
* @brief close UART device handler
* @param uart_device: uart device handler
* @retval 0 if success, 1 if fail
*/
uint32_t ck_uart_close(p_ck_uart_device uart_device)
{
ck_uart_set_rxmode(uart_device, DISABLE);
ck_uart_set_txmode(uart_device, DISABLE);
uart_device->uart_id = 0xFFFF;
return 0;
}
/*
* @brief transmit a character through UART
* @param uart_device: uart device handler
* @param c: character needs to transmit
* @retval 0 if success, 1 if fail
*/
uint32_t ck_uart_putc(p_ck_uart_device uart_device, uint8_t c)
{
if (uart_device->txmode == DISABLE)
return 1;
// wait until uart transmit buffer is empty
while (!((*(reg8_t*)(uart_device->register_map+CK_UART_LSR)) & CK_LSR_TRANS_EMPTY));
*(reg8_t*)(uart_device->register_map+CK_UART_THR) = c;
return 0;
}
/*
* @brief check uart device's status, busy or idle
* @param uart_device: uart device handler
* @retval 0 if uart is in idle, 1 if busy
*/
uint32_t ck_uart_status(p_ck_uart_device uart_device)
{
uint8_t uart_lsr;
return 0;
//uart_lsr = *(reg8_t*)(uart_device->register_map+CK_UART_LSR);
if (uart_lsr & CK_LSR_TEMT)
return 0;
else
return 1;
}