forked from xuos/xiuos
Adjust directory structure
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
menuconfig BSP_USING_UART_HS
|
||||
bool "Enable High Speed UART"
|
||||
default y
|
||||
if BSP_USING_UART_HS
|
||||
config SERIAL_BUS_NAME_0
|
||||
string "serial high speed bus 0 name"
|
||||
default "uart0"
|
||||
config SERIAL_DRV_NAME_0
|
||||
string "serial high speed bus 0 driver name"
|
||||
default "uart0_drv"
|
||||
config SERIAL_0_DEVICE_NAME_0
|
||||
string "serial high speed bus 0 device 0 name"
|
||||
default "uart0_dev0"
|
||||
endif
|
||||
|
||||
menuconfig BSP_USING_UART1
|
||||
bool "Enable UART1"
|
||||
default y
|
||||
if BSP_USING_UART1
|
||||
config BSP_UART1_TXD_PIN
|
||||
int "uart1 TXD pin number"
|
||||
default 20
|
||||
config BSP_UART1_RXD_PIN
|
||||
int "uart1 RXD pin number"
|
||||
default 21
|
||||
config SERIAL_BUS_NAME_1
|
||||
string "serial bus 1 name"
|
||||
default "uart1"
|
||||
config SERIAL_DRV_NAME_1
|
||||
string "serial bus 1 driver name"
|
||||
default "uart1_drv"
|
||||
config SERIAL_1_DEVICE_NAME_0
|
||||
string "serial bus 1 device 0 name"
|
||||
default "uart1_dev1"
|
||||
endif
|
||||
|
||||
menuconfig BSP_USING_UART2
|
||||
bool "Enable UART2"
|
||||
default y
|
||||
if BSP_USING_UART2
|
||||
config BSP_UART2_TXD_PIN
|
||||
int "uart2 TXD pin number"
|
||||
default 28
|
||||
config BSP_UART2_RXD_PIN
|
||||
int "uart2 RXD pin number"
|
||||
default 27
|
||||
config SERIAL_BUS_NAME_2
|
||||
string "serial bus 2 name"
|
||||
default "uart2"
|
||||
config SERIAL_DRV_NAME_2
|
||||
string "serial bus 2 driver name"
|
||||
default "uart2_drv"
|
||||
config SERIAL_2_DEVICE_NAME_0
|
||||
string "serial bus 2 device 0 name"
|
||||
default "uart2_dev2"
|
||||
endif
|
||||
|
||||
menuconfig BSP_USING_UART3
|
||||
bool "Enable UART3"
|
||||
default y
|
||||
if BSP_USING_UART3
|
||||
config BSP_UART3_TXD_PIN
|
||||
int "uart3 TXD pin number"
|
||||
default 22
|
||||
config BSP_UART3_RXD_PIN
|
||||
int "uart3 RXD pin number"
|
||||
default 23
|
||||
config SERIAL_BUS_NAME_3
|
||||
string "serial bus 3 name"
|
||||
default "uart3"
|
||||
config SERIAL_DRV_NAME_3
|
||||
string "serial bus 3 driver name"
|
||||
default "uart3_drv"
|
||||
config SERIAL_3_DEVICE_NAME_0
|
||||
string "serial bus 3 device 0 name"
|
||||
default "uart3_dev3"
|
||||
endif
|
||||
@@ -0,0 +1,3 @@
|
||||
SRC_FILES := connect_uart.c
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
||||
@@ -0,0 +1,652 @@
|
||||
/*
|
||||
* Copyright (c) 2020 RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file connect_uart.c
|
||||
* @brief support kd233-board uart function and register to bus framework
|
||||
* @version 1.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2021-04-25
|
||||
*/
|
||||
|
||||
/*************************************************
|
||||
File name: connect_uart.c
|
||||
Description: support kd233-board uart configure and uart bus register function
|
||||
Others: take RT-Thread v4.0.2/bsp/k210/driver/drv_uart.c for references
|
||||
https://github.com/RT-Thread/rt-thread/tree/v4.0.2
|
||||
History:
|
||||
1. Date: 2021-04-25
|
||||
Author: AIIT XUOS Lab
|
||||
Modification:
|
||||
1. support kd233-board uart configure, write and read
|
||||
2. support kd233-board uart bus device and driver register
|
||||
*************************************************/
|
||||
|
||||
#include <sysctl.h>
|
||||
#include <stdio.h>
|
||||
#include "plic.h"
|
||||
#include "connect_uart.h"
|
||||
#include "hardware_uart.h"
|
||||
#include "hardware_uarths.h"
|
||||
|
||||
static volatile UarthsT *const _uarths = (volatile UarthsT *)UARTHS_BASE_ADDR;
|
||||
|
||||
/* START ported from kendryte standalone sdk uart.c */
|
||||
#define __UART_BRATE_CONST 16
|
||||
|
||||
volatile UartT* const _uart_new[3] =
|
||||
{
|
||||
(volatile UartT*)UART1_BASE_ADDR,
|
||||
(volatile UartT*)UART2_BASE_ADDR,
|
||||
(volatile UartT*)UART3_BASE_ADDR
|
||||
};
|
||||
|
||||
void _uart_init_new(UartDeviceNumberT channel)
|
||||
{
|
||||
sysctl_clock_enable(SYSCTL_CLOCK_UART1 + channel);
|
||||
sysctl_reset(SYSCTL_RESET_UART1 + channel);
|
||||
}
|
||||
|
||||
/* END ported from kendryte standalone sdk uart.c */
|
||||
static inline UartDeviceNumberT GetUartChannel(uint32 addr)
|
||||
{
|
||||
switch (addr)
|
||||
{
|
||||
case UART1_BASE_ADDR:
|
||||
return UART_DEVICE_1;
|
||||
case UART2_BASE_ADDR:
|
||||
return UART_DEVICE_2;
|
||||
case UART3_BASE_ADDR:
|
||||
return UART_DEVICE_3;
|
||||
default:
|
||||
return UART_DEVICE_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
extern void SerialSetIsr(struct SerialHardwareDevice *serial_dev, int event);
|
||||
|
||||
static void SerialCfgParamCheck(struct SerialCfgParam *serial_cfg_default, struct SerialCfgParam *serial_cfg_new)
|
||||
{
|
||||
struct SerialDataCfg *data_cfg_default = &serial_cfg_default->data_cfg;
|
||||
struct SerialDataCfg *data_cfg_new = &serial_cfg_new->data_cfg;
|
||||
|
||||
if ((data_cfg_default->serial_baud_rate != data_cfg_new->serial_baud_rate) && (data_cfg_new->serial_baud_rate)) {
|
||||
data_cfg_default->serial_baud_rate = data_cfg_new->serial_baud_rate;
|
||||
}
|
||||
|
||||
if ((data_cfg_default->serial_bit_order != data_cfg_new->serial_bit_order) && (data_cfg_new->serial_bit_order)) {
|
||||
data_cfg_default->serial_bit_order = data_cfg_new->serial_bit_order;
|
||||
}
|
||||
|
||||
if ((data_cfg_default->serial_buffer_size != data_cfg_new->serial_buffer_size) && (data_cfg_new->serial_buffer_size)) {
|
||||
data_cfg_default->serial_buffer_size = data_cfg_new->serial_buffer_size;
|
||||
}
|
||||
|
||||
if ((data_cfg_default->serial_data_bits != data_cfg_new->serial_data_bits) && (data_cfg_new->serial_data_bits)) {
|
||||
data_cfg_default->serial_data_bits = data_cfg_new->serial_data_bits;
|
||||
}
|
||||
|
||||
if ((data_cfg_default->serial_invert_mode != data_cfg_new->serial_invert_mode) && (data_cfg_new->serial_invert_mode)) {
|
||||
data_cfg_default->serial_invert_mode = data_cfg_new->serial_invert_mode;
|
||||
}
|
||||
|
||||
if ((data_cfg_default->serial_parity_mode != data_cfg_new->serial_parity_mode) && (data_cfg_new->serial_parity_mode)) {
|
||||
data_cfg_default->serial_parity_mode = data_cfg_new->serial_parity_mode;
|
||||
}
|
||||
|
||||
if ((data_cfg_default->serial_stop_bits != data_cfg_new->serial_stop_bits) && (data_cfg_new->serial_stop_bits)) {
|
||||
data_cfg_default->serial_stop_bits = data_cfg_new->serial_stop_bits;
|
||||
}
|
||||
}
|
||||
|
||||
/* UARTHS ISR */
|
||||
static void UarthsIrqHandler(int irqno, void *param)
|
||||
{
|
||||
struct SerialBus *serial_bus = (struct SerialBus *)param;
|
||||
struct SerialDriver *serial_drv = (struct SerialDriver *)serial_bus->bus.owner_driver;
|
||||
struct SerialHardwareDevice *serial_dev = (struct SerialHardwareDevice *)serial_bus->bus.owner_haldev;
|
||||
struct SerialCfgParam *serial_cfg = (struct SerialCfgParam *)serial_drv->private_data;
|
||||
CHECK(UARTHS_BASE_ADDR == serial_cfg->hw_cfg.serial_register_base);
|
||||
|
||||
/* read interrupt status and clear it */
|
||||
if(_uarths->ip.rxwm)
|
||||
SerialSetIsr(serial_dev, SERIAL_EVENT_RX_IND);
|
||||
}
|
||||
|
||||
/* UART ISR */
|
||||
static void UartIrqHandler(int irqno, void *param)
|
||||
{
|
||||
struct SerialBus *serial_bus = (struct SerialBus *)param;
|
||||
struct SerialDriver *serial_drv = (struct SerialDriver *)serial_bus->bus.owner_driver;
|
||||
struct SerialHardwareDevice *serial_dev = (struct SerialHardwareDevice *)serial_bus->bus.owner_haldev;
|
||||
struct SerialCfgParam *serial_cfg = (struct SerialCfgParam *)serial_drv->private_data;
|
||||
|
||||
UartDeviceNumberT channel = GetUartChannel(serial_cfg->hw_cfg.serial_register_base);
|
||||
CHECK(channel != UART_DEVICE_MAX);
|
||||
|
||||
/* read interrupt status and clear it */
|
||||
if(_uart_new[channel]->LSR)
|
||||
SerialSetIsr(serial_dev, SERIAL_EVENT_RX_IND);
|
||||
}
|
||||
|
||||
static uint32 SerialHsInit(struct SerialDriver *serial_drv, struct BusConfigureInfo *configure_info)
|
||||
{
|
||||
NULL_PARAM_CHECK(serial_drv);
|
||||
|
||||
struct SerialCfgParam *serial_cfg = (struct SerialCfgParam *)serial_drv->private_data;
|
||||
|
||||
if (configure_info->private_data) {
|
||||
struct SerialCfgParam *serial_cfg_new = (struct SerialCfgParam *)configure_info->private_data;
|
||||
SerialCfgParamCheck(serial_cfg, serial_cfg_new);
|
||||
}
|
||||
|
||||
uint32 freq_hs = SysctlClockGetFreq(SYSCTL_CLOCK_CPU);
|
||||
uint16 div_hs = freq_hs / serial_cfg->data_cfg.serial_baud_rate - 1;
|
||||
|
||||
if (UARTHS_BASE_ADDR == serial_cfg->hw_cfg.serial_register_base) {
|
||||
_uarths->div.div = div_hs;
|
||||
_uarths->txctrl.txen = 1;
|
||||
_uarths->rxctrl.rxen = 1;
|
||||
_uarths->txctrl.txcnt = 0;
|
||||
_uarths->rxctrl.rxcnt = 0;
|
||||
_uarths->ip.txwm = 1;
|
||||
_uarths->ip.rxwm = 1;
|
||||
_uarths->ie.txwm = 0;
|
||||
_uarths->ie.rxwm = 1;
|
||||
} else {
|
||||
KPrintf("SerialHsInit error base 0x%x\n", serial_cfg->hw_cfg.serial_register_base);
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
return EOK;
|
||||
}
|
||||
|
||||
static uint32 SerialHsConfigure(struct SerialDriver *serial_drv, int serial_operation_cmd)
|
||||
{
|
||||
NULL_PARAM_CHECK(serial_drv);
|
||||
|
||||
struct SerialCfgParam *serial_cfg = (struct SerialCfgParam *)serial_drv->private_data;
|
||||
struct SerialBus *serial_bus = CONTAINER_OF(serial_drv->driver.owner_bus, struct SerialBus, bus);
|
||||
|
||||
switch (serial_operation_cmd)
|
||||
{
|
||||
case OPER_CLR_INT:
|
||||
isrManager.done->disableIrq(serial_cfg->hw_cfg.serial_irq_interrupt);
|
||||
break;
|
||||
case OPER_SET_INT:
|
||||
isrManager.done->registerIrq(serial_cfg->hw_cfg.serial_irq_interrupt, UarthsIrqHandler, serial_bus);
|
||||
isrManager.done->enableIrq(serial_cfg->hw_cfg.serial_irq_interrupt);
|
||||
break;
|
||||
}
|
||||
|
||||
return EOK;
|
||||
}
|
||||
|
||||
static int SerialHsPutChar(struct SerialHardwareDevice *serial_dev, char c)
|
||||
{
|
||||
struct SerialCfgParam *serial_cfg = (struct SerialCfgParam *)serial_dev->private_data;
|
||||
CHECK(serial_cfg->hw_cfg.serial_register_base == UARTHS_BASE_ADDR);
|
||||
|
||||
while (_uarths->txdata.full);
|
||||
_uarths->txdata.data = (uint8)c;
|
||||
|
||||
return EOK;
|
||||
}
|
||||
|
||||
static int SerialHsGetChar(struct SerialHardwareDevice *serial_dev)
|
||||
{
|
||||
struct SerialCfgParam *serial_cfg = (struct SerialCfgParam *)serial_dev->private_data;
|
||||
CHECK(serial_cfg->hw_cfg.serial_register_base == UARTHS_BASE_ADDR);
|
||||
|
||||
uarths_rxdata_t recv = _uarths->rxdata;
|
||||
if (recv.empty)
|
||||
return -ERROR;
|
||||
else
|
||||
return (recv.data & 0xff);
|
||||
|
||||
return -ERROR;
|
||||
}
|
||||
|
||||
static uint32 SerialInit(struct SerialDriver *serial_drv, struct BusConfigureInfo *configure_info)
|
||||
{
|
||||
NULL_PARAM_CHECK(serial_drv);
|
||||
struct SerialCfgParam *serial_cfg = (struct SerialCfgParam *)serial_drv->private_data;
|
||||
|
||||
if (configure_info->private_data) {
|
||||
struct SerialCfgParam *serial_cfg_new = (struct SerialCfgParam *)configure_info->private_data;
|
||||
SerialCfgParamCheck(serial_cfg, serial_cfg_new);
|
||||
}
|
||||
|
||||
UartBitwidthPointer DataWidth = (UartBitwidthPointer)serial_cfg->data_cfg.serial_data_bits;
|
||||
UartStopbitT stopbit = (UartStopbitT)(serial_cfg->data_cfg.serial_stop_bits - 1);
|
||||
UartParityT parity = (UartParityT)(serial_cfg->data_cfg.serial_parity_mode - 1);
|
||||
|
||||
uint32 freq = SysctlClockGetFreq(SYSCTL_CLOCK_APB0);
|
||||
uint32 divisor = freq / (uint32)serial_cfg->data_cfg.serial_baud_rate;
|
||||
uint8 dlh = divisor >> 12;
|
||||
uint8 dll = (divisor - (dlh << 12)) / __UART_BRATE_CONST;
|
||||
uint8 dlf = divisor - (dlh << 12) - dll * __UART_BRATE_CONST;
|
||||
|
||||
UartDeviceNumberT channel = GetUartChannel(serial_cfg->hw_cfg.serial_register_base);
|
||||
CHECK(channel != UART_DEVICE_MAX);
|
||||
|
||||
CHECK(DataWidth >= 5 && DataWidth <= 8);
|
||||
if (DataWidth == 5) {
|
||||
CHECK(stopbit != UART_STOP_2);
|
||||
} else {
|
||||
CHECK(stopbit != UART_STOP_1_5);
|
||||
}
|
||||
|
||||
uint32 stopbit_val = stopbit == UART_STOP_1 ? 0 : 1;
|
||||
uint32 ParityVal;
|
||||
switch (parity)
|
||||
{
|
||||
case UART_PARITY_NONE:
|
||||
ParityVal = 0;
|
||||
break;
|
||||
case UART_PARITY_ODD:
|
||||
ParityVal = 1;
|
||||
break;
|
||||
case UART_PARITY_EVEN:
|
||||
ParityVal = 3;
|
||||
break;
|
||||
default:
|
||||
CHECK(!"Invalid parity");
|
||||
break;
|
||||
}
|
||||
|
||||
_uart_new[channel]->LCR |= 1u << 7;
|
||||
_uart_new[channel]->DLH = dlh;
|
||||
_uart_new[channel]->DLL = dll;
|
||||
_uart_new[channel]->DLF = dlf;
|
||||
_uart_new[channel]->LCR = 0;
|
||||
_uart_new[channel]->LCR = (DataWidth - 5) |
|
||||
(stopbit_val << 2) |
|
||||
(ParityVal << 3);
|
||||
_uart_new[channel]->LCR &= ~(1u << 7);
|
||||
_uart_new[channel]->IER |= 0x80; /* THRE */
|
||||
_uart_new[channel]->FCR = UART_RECEIVE_FIFO_1 << 6 |
|
||||
UART_SEND_FIFO_8 << 4 |
|
||||
0x1 << 3 |
|
||||
0x1;
|
||||
|
||||
return EOK;
|
||||
}
|
||||
|
||||
static uint32 SerialConfigure(struct SerialDriver *serial_drv, int serial_operation_cmd)
|
||||
{
|
||||
NULL_PARAM_CHECK(serial_drv);
|
||||
|
||||
struct SerialCfgParam *serial_cfg = (struct SerialCfgParam *)serial_drv->private_data;
|
||||
struct SerialBus *serial_bus = CONTAINER_OF(serial_drv->driver.owner_bus, struct SerialBus, bus);
|
||||
|
||||
UartDeviceNumberT channel = GetUartChannel(serial_cfg->hw_cfg.serial_register_base);
|
||||
CHECK(channel != UART_DEVICE_MAX);
|
||||
|
||||
switch (serial_operation_cmd)
|
||||
{
|
||||
case OPER_CLR_INT:
|
||||
/* Disable the UART Interrupt */
|
||||
isrManager.done->disableIrq(serial_cfg->hw_cfg.serial_irq_interrupt);
|
||||
_uart_new[channel]->IER &= ~0x1;
|
||||
break;
|
||||
case OPER_SET_INT:
|
||||
/* install interrupt */
|
||||
isrManager.done->registerIrq(serial_cfg->hw_cfg.serial_irq_interrupt, UartIrqHandler, serial_bus);
|
||||
isrManager.done->enableIrq(serial_cfg->hw_cfg.serial_irq_interrupt);
|
||||
_uart_new[channel]->IER |= 0x1;
|
||||
break;
|
||||
}
|
||||
|
||||
return EOK;
|
||||
}
|
||||
|
||||
static int SerialPutChar(struct SerialHardwareDevice *serial_dev, char c)
|
||||
{
|
||||
struct SerialCfgParam *serial_cfg = (struct SerialCfgParam *)serial_dev->private_data;
|
||||
UartDeviceNumberT channel = GetUartChannel(serial_cfg->hw_cfg.serial_register_base);
|
||||
CHECK(channel != UART_DEVICE_MAX);
|
||||
|
||||
while (_uart_new[channel]->LSR & (1u << 5));
|
||||
_uart_new[channel]->THR = c;
|
||||
|
||||
return EOK;
|
||||
}
|
||||
|
||||
static int SerialGetChar(struct SerialHardwareDevice *serial_dev)
|
||||
{
|
||||
struct SerialCfgParam *serial_cfg = (struct SerialCfgParam *)serial_dev->private_data;
|
||||
UartDeviceNumberT channel = GetUartChannel(serial_cfg->hw_cfg.serial_register_base);
|
||||
CHECK(channel != UART_DEVICE_MAX);
|
||||
|
||||
if (_uart_new[channel]->LSR & 1)
|
||||
return (char)(_uart_new[channel]->RBR & 0xff);
|
||||
else
|
||||
return -ERROR;
|
||||
|
||||
return -ERROR;
|
||||
}
|
||||
|
||||
static uint32 SerialHsDrvConfigure(void *drv, struct BusConfigureInfo *configure_info)
|
||||
{
|
||||
NULL_PARAM_CHECK(drv);
|
||||
NULL_PARAM_CHECK(configure_info);
|
||||
|
||||
x_err_t ret = EOK;
|
||||
int serial_operation_cmd;
|
||||
struct SerialDriver *serial_drv = (struct SerialDriver *)drv;
|
||||
|
||||
switch (configure_info->configure_cmd)
|
||||
{
|
||||
case OPE_INT:
|
||||
ret = SerialHsInit(serial_drv, configure_info);
|
||||
break;
|
||||
case OPE_CFG:
|
||||
serial_operation_cmd = *((int *)configure_info->private_data);
|
||||
ret = SerialHsConfigure(serial_drv, serial_operation_cmd);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static uint32 SerialDrvConfigure(void *drv, struct BusConfigureInfo *configure_info)
|
||||
{
|
||||
NULL_PARAM_CHECK(drv);
|
||||
NULL_PARAM_CHECK(configure_info);
|
||||
|
||||
x_err_t ret = EOK;
|
||||
int serial_operation_cmd;
|
||||
struct SerialDriver *serial_drv = (struct SerialDriver *)drv;
|
||||
|
||||
switch (configure_info->configure_cmd)
|
||||
{
|
||||
case OPE_INT:
|
||||
ret = SerialInit(serial_drv, configure_info);
|
||||
break;
|
||||
case OPE_CFG:
|
||||
serial_operation_cmd = *(int *)configure_info->private_data;
|
||||
ret = SerialConfigure(serial_drv, serial_operation_cmd);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct SerialDataCfg data_cfg_init =
|
||||
{
|
||||
.serial_baud_rate = BAUD_RATE_115200,
|
||||
.serial_data_bits = DATA_BITS_8,
|
||||
.serial_stop_bits = STOP_BITS_1,
|
||||
.serial_parity_mode = PARITY_NONE,
|
||||
.serial_bit_order = BIT_ORDER_LSB,
|
||||
.serial_invert_mode = NRZ_NORMAL,
|
||||
.serial_buffer_size = SERIAL_RB_BUFSZ,
|
||||
};
|
||||
|
||||
/*manage the serial high speed device operations*/
|
||||
static const struct SerialDrvDone drv_done_hs =
|
||||
{
|
||||
.init = SerialHsInit,
|
||||
.configure = SerialHsConfigure,
|
||||
};
|
||||
|
||||
/*manage the serial high speed device hal operations*/
|
||||
static struct SerialHwDevDone hwdev_done_hs =
|
||||
{
|
||||
.put_char = SerialHsPutChar,
|
||||
.get_char = SerialHsGetChar,
|
||||
};
|
||||
|
||||
/*manage the serial device operations*/
|
||||
static const struct SerialDrvDone drv_done =
|
||||
{
|
||||
.init = SerialInit,
|
||||
.configure = SerialConfigure,
|
||||
};
|
||||
|
||||
/*manage the serial device hal operations*/
|
||||
static struct SerialHwDevDone hwdev_done =
|
||||
{
|
||||
.put_char = SerialPutChar,
|
||||
.get_char = SerialGetChar,
|
||||
};
|
||||
|
||||
static int BoardSerialBusInit(struct SerialBus *serial_bus, struct SerialDriver *serial_driver, const char *bus_name, const char *drv_name)
|
||||
{
|
||||
x_err_t ret = EOK;
|
||||
|
||||
/*Init the serial bus */
|
||||
ret = SerialBusInit(serial_bus, bus_name);
|
||||
if (EOK != ret) {
|
||||
KPrintf("hw_serial_init SerialBusInit error %d\n", ret);
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
/*Init the serial driver*/
|
||||
ret = SerialDriverInit(serial_driver, drv_name);
|
||||
if (EOK != ret) {
|
||||
KPrintf("hw_serial_init SerialDriverInit error %d\n", ret);
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
/*Attach the serial driver to the serial bus*/
|
||||
ret = SerialDriverAttachToBus(drv_name, bus_name);
|
||||
if (EOK != ret) {
|
||||
KPrintf("hw_serial_init SerialDriverAttachToBus error %d\n", ret);
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*Attach the serial device to the serial bus*/
|
||||
static int BoardSerialDevBend(struct SerialHardwareDevice *serial_device, void *serial_param, const char *bus_name, const char *dev_name)
|
||||
{
|
||||
x_err_t ret = EOK;
|
||||
|
||||
ret = SerialDeviceRegister(serial_device, serial_param, dev_name);
|
||||
if (EOK != ret) {
|
||||
KPrintf("hw_serial_init SerialDeviceInit device %s error %d\n", dev_name, ret);
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
ret = SerialDeviceAttachToBus(dev_name, bus_name);
|
||||
if (EOK != ret) {
|
||||
KPrintf("hw_serial_init SerialDeviceAttachToBus device %s error %d\n", dev_name, ret);
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int HwUartInit(void)
|
||||
{
|
||||
x_err_t ret = EOK;
|
||||
|
||||
#ifdef BSP_USING_UART_HS
|
||||
static struct SerialBus serial_bus_hs;
|
||||
memset(&serial_bus_hs, 0, sizeof(struct SerialBus));
|
||||
|
||||
static struct SerialDriver serial_driver_hs;
|
||||
memset(&serial_driver_hs, 0, sizeof(struct SerialDriver));
|
||||
|
||||
static struct SerialHardwareDevice serial_device_hs;
|
||||
memset(&serial_device_hs, 0, sizeof(struct SerialHardwareDevice));
|
||||
|
||||
static struct SerialCfgParam serial_cfg_hs;
|
||||
memset(&serial_cfg_hs, 0, sizeof(struct SerialCfgParam));
|
||||
|
||||
static struct SerialDevParam serial_dev_param_hs;
|
||||
memset(&serial_dev_param_hs, 0, sizeof(struct SerialDevParam));
|
||||
|
||||
serial_driver_hs.drv_done = &drv_done_hs;
|
||||
serial_driver_hs.configure = &SerialHsDrvConfigure;
|
||||
serial_device_hs.hwdev_done = &hwdev_done_hs;
|
||||
|
||||
serial_cfg_hs.data_cfg = data_cfg_init;
|
||||
|
||||
serial_cfg_hs.hw_cfg.serial_register_base = UARTHS_BASE_ADDR;
|
||||
serial_cfg_hs.hw_cfg.serial_irq_interrupt = IRQN_UARTHS_INTERRUPT;
|
||||
serial_driver_hs.private_data = (void *)&serial_cfg_hs;
|
||||
|
||||
serial_dev_param_hs.serial_work_mode = SIGN_OPER_INT_RX;
|
||||
serial_device_hs.haldev.private_data = (void *)&serial_dev_param_hs;
|
||||
|
||||
ret = BoardSerialBusInit(&serial_bus_hs, &serial_driver_hs, SERIAL_BUS_NAME_0, SERIAL_DRV_NAME_0);
|
||||
if (EOK != ret) {
|
||||
KPrintf("hw_serial_init uarths error ret %u\n", ret);
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
ret = BoardSerialDevBend(&serial_device_hs, (void *)&serial_cfg_hs, SERIAL_BUS_NAME_0, SERIAL_0_DEVICE_NAME_0);
|
||||
if (EOK != ret) {
|
||||
KPrintf("hw_serial_init uarths error ret %u\n", ret);
|
||||
return ERROR;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef BSP_USING_UART1
|
||||
static struct SerialBus serial_bus_1;
|
||||
memset(&serial_bus_1, 0, sizeof(struct SerialBus));
|
||||
|
||||
static struct SerialDriver serial_driver_1;
|
||||
memset(&serial_driver_1, 0, sizeof(struct SerialDriver));
|
||||
|
||||
static struct SerialHardwareDevice serial_device_1;
|
||||
memset(&serial_device_1, 0, sizeof(struct SerialHardwareDevice));
|
||||
|
||||
static struct SerialCfgParam serial_cfg_1;
|
||||
memset(&serial_cfg_1, 0, sizeof(struct SerialCfgParam));
|
||||
|
||||
static struct SerialDevParam serial_dev_param_1;
|
||||
memset(&serial_dev_param_1, 0, sizeof(struct SerialDevParam));
|
||||
|
||||
serial_driver_1.drv_done = &drv_done;
|
||||
serial_driver_1.configure = &SerialDrvConfigure;
|
||||
serial_device_1.hwdev_done = &hwdev_done;
|
||||
|
||||
serial_cfg_1.data_cfg = data_cfg_init;
|
||||
|
||||
serial_cfg_1.hw_cfg.serial_register_base = UART1_BASE_ADDR;
|
||||
serial_cfg_1.hw_cfg.serial_irq_interrupt = IRQN_UART1_INTERRUPT;
|
||||
serial_driver_1.private_data = (void *)&serial_cfg_1;
|
||||
|
||||
serial_dev_param_1.serial_work_mode = SIGN_OPER_INT_RX;
|
||||
serial_device_1.haldev.private_data = (void *)&serial_dev_param_1;
|
||||
|
||||
_uart_init_new(UART_DEVICE_1);
|
||||
|
||||
ret = BoardSerialBusInit(&serial_bus_1, &serial_driver_1, SERIAL_BUS_NAME_1, SERIAL_DRV_NAME_1);
|
||||
if (EOK != ret) {
|
||||
KPrintf("hw_serial_init uart1 error ret %u\n", ret);
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
ret = BoardSerialDevBend(&serial_device_1, (void *)&serial_cfg_1, SERIAL_BUS_NAME_1, SERIAL_1_DEVICE_NAME_0);
|
||||
if (EOK != ret) {
|
||||
KPrintf("hw_serial_init uart1 error ret %u\n", ret);
|
||||
return ERROR;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef BSP_USING_UART2
|
||||
static struct SerialBus serial_bus_2;
|
||||
memset(&serial_bus_2, 0, sizeof(struct SerialBus));
|
||||
|
||||
static struct SerialDriver serial_driver_2;
|
||||
memset(&serial_driver_2, 0, sizeof(struct SerialDriver));
|
||||
|
||||
static struct SerialHardwareDevice serial_device_2;
|
||||
memset(&serial_device_2, 0, sizeof(struct SerialHardwareDevice));
|
||||
|
||||
static struct SerialCfgParam serial_cfg_2;
|
||||
memset(&serial_cfg_2, 0, sizeof(struct SerialCfgParam));
|
||||
|
||||
static struct SerialDevParam serial_dev_param_2;
|
||||
memset(&serial_dev_param_2, 0, sizeof(struct SerialDevParam));
|
||||
|
||||
serial_driver_2.drv_done = &drv_done;
|
||||
serial_driver_2.configure = &SerialDrvConfigure;
|
||||
serial_device_2.hwdev_done = &hwdev_done;
|
||||
|
||||
serial_cfg_2.data_cfg = data_cfg_init;
|
||||
|
||||
serial_cfg_2.hw_cfg.serial_register_base = UART2_BASE_ADDR;
|
||||
serial_cfg_2.hw_cfg.serial_irq_interrupt = IRQN_UART2_INTERRUPT;
|
||||
serial_driver_2.private_data = (void *)&serial_cfg_2;
|
||||
|
||||
serial_dev_param_2.serial_work_mode = SIGN_OPER_INT_RX;
|
||||
serial_device_2.haldev.private_data = (void *)&serial_dev_param_2;
|
||||
|
||||
_uart_init_new(UART_DEVICE_2);
|
||||
|
||||
ret = BoardSerialBusInit(&serial_bus_2, &serial_driver_2, SERIAL_BUS_NAME_2, SERIAL_DRV_NAME_2);
|
||||
if (EOK != ret) {
|
||||
KPrintf("hw_serial_init uart2 error ret %u\n", ret);
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
ret = BoardSerialDevBend(&serial_device_2, (void *)&serial_cfg_2, SERIAL_BUS_NAME_2, SERIAL_2_DEVICE_NAME_0);
|
||||
if (EOK != ret) {
|
||||
KPrintf("hw_serial_init uart2 error ret %u\n", ret);
|
||||
return ERROR;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef BSP_USING_UART3
|
||||
static struct SerialBus serial_bus_3;
|
||||
memset(&serial_bus_3, 0, sizeof(struct SerialBus));
|
||||
|
||||
static struct SerialDriver serial_driver_3;
|
||||
memset(&serial_driver_3, 0, sizeof(struct SerialDriver));
|
||||
|
||||
static struct SerialHardwareDevice serial_device_3;
|
||||
memset(&serial_device_3, 0, sizeof(struct SerialHardwareDevice));
|
||||
|
||||
static struct SerialCfgParam serial_cfg_3;
|
||||
memset(&serial_cfg_3, 0, sizeof(struct SerialCfgParam));
|
||||
|
||||
static struct SerialDevParam serial_dev_param_3;
|
||||
memset(&serial_dev_param_3, 0, sizeof(struct SerialDevParam));
|
||||
|
||||
serial_driver_3.drv_done = &drv_done;
|
||||
serial_driver_3.configure = &SerialDrvConfigure;
|
||||
serial_device_3.hwdev_done = &hwdev_done;
|
||||
|
||||
serial_cfg_3.data_cfg = data_cfg_init;
|
||||
|
||||
serial_cfg_3.hw_cfg.serial_register_base = UART3_BASE_ADDR;
|
||||
serial_cfg_3.hw_cfg.serial_irq_interrupt = IRQN_UART3_INTERRUPT;
|
||||
serial_driver_3.private_data = (void *)&serial_cfg_3;
|
||||
|
||||
serial_dev_param_3.serial_work_mode = SIGN_OPER_INT_RX;
|
||||
serial_device_3.haldev.private_data = (void *)&serial_dev_param_3;
|
||||
|
||||
_uart_init_new(UART_DEVICE_3);
|
||||
|
||||
ret = BoardSerialBusInit(&serial_bus_3, &serial_driver_3, SERIAL_BUS_NAME_3, SERIAL_DRV_NAME_3);
|
||||
if (EOK != ret) {
|
||||
KPrintf("hw_serial_init uart3 error ret %u\n", ret);
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
ret = BoardSerialDevBend(&serial_device_3, (void *)&serial_cfg_3, SERIAL_BUS_NAME_3, SERIAL_3_DEVICE_NAME_0);
|
||||
if (EOK != ret) {
|
||||
KPrintf("hw_serial_init uart3 error ret %u\n", ret);
|
||||
return ERROR;
|
||||
}
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,424 @@
|
||||
/* Copyright 2018 Canaan Inc.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file hardware_uart.c
|
||||
* @brief add from Canaan k210 SDK
|
||||
* https://canaan-creative.com/developer
|
||||
* @version 1.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2021-04-25
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include "plic.h"
|
||||
#include "sysctl.h"
|
||||
#include "hardware_uart.h"
|
||||
#include "utils.h"
|
||||
#include "atomic.h"
|
||||
|
||||
#define __UART_BRATE_CONST 16
|
||||
|
||||
volatile UartT* const uart[3] =
|
||||
{
|
||||
(volatile UartT*)UART1_BASE_ADDR,
|
||||
(volatile UartT*)UART2_BASE_ADDR,
|
||||
(volatile UartT*)UART3_BASE_ADDR
|
||||
};
|
||||
|
||||
#define UART_INTERRUPT_SEND 0x02U
|
||||
#define UART_INTERRUPT_RECEIVE 0x04U
|
||||
#define UART_INTERRUPT_CHARACTER_TIMEOUT 0x0CU
|
||||
|
||||
typedef struct UartInterruptInstance
|
||||
{
|
||||
plic_irq_callback_t callback;
|
||||
void *ctx;
|
||||
} UartInterruptInstanceT;
|
||||
|
||||
typedef struct UartInstance
|
||||
{
|
||||
UartInterruptInstanceT UartReceiveInstance;
|
||||
UartInterruptInstanceT UartSendInstance;
|
||||
uint32_t UartNum;
|
||||
} UartInstancePointer;
|
||||
|
||||
UartInstancePointer GUartInstance[3];
|
||||
|
||||
typedef struct UartDmaInstance
|
||||
{
|
||||
uint8_t *buffer;
|
||||
size_t BufLen;
|
||||
uint32_t *MallocBuffer;
|
||||
UartInterruptModeT IntMode;
|
||||
dmac_channel_number_t dmac_channel;
|
||||
UartDeviceNumberT UartNum;
|
||||
UartInterruptInstanceT UartIntInstance;
|
||||
} UartDmaInstanceT;
|
||||
|
||||
UartDmaInstanceT uart_send_dma_instance[3];
|
||||
UartDmaInstanceT UartRecvDmaInstance[3];
|
||||
|
||||
typedef struct UartInstanceDma
|
||||
{
|
||||
UartDeviceNumberT UartNum;
|
||||
UartInterruptModeT TransferMode;
|
||||
dmac_channel_number_t dmac_channel;
|
||||
plic_instance_t UartIntInstance;
|
||||
spinlock_t lock;
|
||||
} UartInstanceDmaT;
|
||||
|
||||
static UartInstanceDmaT GUartSendInstanceDma[3];
|
||||
static UartInstanceDmaT GUartRecvInstanceDma[3];
|
||||
|
||||
volatile int GWriteCount = 0;
|
||||
|
||||
static int UartIrqCallback(void *param)
|
||||
{
|
||||
UartInstancePointer *uart_instance = (UartInstancePointer *)param;
|
||||
uint32_t v_channel = uart_instance->UartNum;
|
||||
uint8_t VIntStatus = uart[v_channel]->IIR & 0xF;
|
||||
|
||||
if(VIntStatus == UART_INTERRUPT_SEND && GWriteCount != 0)
|
||||
{
|
||||
if(uart_instance->UartSendInstance.callback != NULL)
|
||||
uart_instance->UartSendInstance.callback(uart_instance->UartSendInstance.ctx);
|
||||
}
|
||||
else if(VIntStatus == UART_INTERRUPT_RECEIVE || VIntStatus == UART_INTERRUPT_CHARACTER_TIMEOUT)
|
||||
{
|
||||
if(uart_instance->UartReceiveInstance.callback != NULL)
|
||||
uart_instance->UartReceiveInstance.callback(uart_instance->UartReceiveInstance.ctx);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int UartapbPutc(UartDeviceNumberT channel, char c)
|
||||
{
|
||||
while (uart[channel]->LSR & (1u << 5))
|
||||
continue;
|
||||
uart[channel]->THR = c;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int UartapbGetc(UartDeviceNumberT channel)
|
||||
{
|
||||
while (!(uart[channel]->LSR & 1))
|
||||
continue;
|
||||
|
||||
return (char)(uart[channel]->RBR & 0xff);
|
||||
}
|
||||
|
||||
static int UartDmaCallback(void *ctx)
|
||||
{
|
||||
UartDmaInstanceT *VUartDmaInstance = (UartDmaInstanceT *)ctx;
|
||||
dmac_channel_number_t dmac_channel = VUartDmaInstance->dmac_channel;
|
||||
dmac_irq_unregister(dmac_channel);
|
||||
|
||||
if(VUartDmaInstance->IntMode == UART_RECEIVE)
|
||||
{
|
||||
size_t VBufLen = VUartDmaInstance->BufLen;
|
||||
uint8_t *VBuffer = VUartDmaInstance->buffer;
|
||||
uint32_t *VRecvBuffer = VUartDmaInstance->MallocBuffer;
|
||||
for(size_t i = 0; i < VBufLen; i++)
|
||||
{
|
||||
VBuffer[i] = VRecvBuffer[i];
|
||||
}
|
||||
}
|
||||
free(VUartDmaInstance->MallocBuffer);
|
||||
if(VUartDmaInstance->UartIntInstance.callback)
|
||||
VUartDmaInstance->UartIntInstance.callback(VUartDmaInstance->UartIntInstance.ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int UartReceiveData(UartDeviceNumberT channel, char *buffer, size_t BufLen)
|
||||
{
|
||||
size_t i = 0;
|
||||
for(i = 0;i < BufLen; i++)
|
||||
{
|
||||
if(uart[channel]->LSR & 1)
|
||||
buffer[i] = (char)(uart[channel]->RBR & 0xff);
|
||||
else
|
||||
break;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
void UartReceiveDataDma(UartDeviceNumberT uart_channel, dmac_channel_number_t dmac_channel, uint8_t *buffer, size_t BufLen)
|
||||
{
|
||||
uint32_t *VRecvBuf = malloc(BufLen * sizeof(uint32_t));
|
||||
configASSERT(VRecvBuf!=NULL);
|
||||
|
||||
sysctl_dma_select((sysctl_dma_channel_t)dmac_channel, SYSCTL_DMA_SELECT_UART1_RX_REQ + uart_channel * 2);
|
||||
dmac_set_single_mode(dmac_channel, (void *)(&uart[uart_channel]->RBR), VRecvBuf, DMAC_ADDR_NOCHANGE, DMAC_ADDR_INCREMENT,
|
||||
DMAC_MSIZE_1, DMAC_TRANS_WIDTH_32, BufLen);
|
||||
dmac_wait_done(dmac_channel);
|
||||
for(uint32_t i = 0; i < BufLen; i++)
|
||||
{
|
||||
buffer[i] = (uint8_t)(VRecvBuf[i] & 0xff);
|
||||
}
|
||||
free(VRecvBuf);
|
||||
}
|
||||
|
||||
void UartReceiveDataDmaIrq(UartDeviceNumberT uart_channel, dmac_channel_number_t dmac_channel,
|
||||
uint8_t *buffer, size_t BufLen, plic_irq_callback_t uart_callback,
|
||||
void *ctx, uint32_t priority)
|
||||
{
|
||||
uint32_t *VRecvBuf = malloc(BufLen * sizeof(uint32_t));
|
||||
configASSERT(VRecvBuf!=NULL);
|
||||
|
||||
UartRecvDmaInstance[uart_channel].dmac_channel = dmac_channel;
|
||||
UartRecvDmaInstance[uart_channel].UartNum = uart_channel;
|
||||
UartRecvDmaInstance[uart_channel].MallocBuffer = VRecvBuf;
|
||||
UartRecvDmaInstance[uart_channel].buffer = buffer;
|
||||
UartRecvDmaInstance[uart_channel].BufLen = BufLen;
|
||||
UartRecvDmaInstance[uart_channel].IntMode = UART_RECEIVE;
|
||||
UartRecvDmaInstance[uart_channel].UartIntInstance.callback = uart_callback;
|
||||
UartRecvDmaInstance[uart_channel].UartIntInstance.ctx = ctx;
|
||||
|
||||
dmac_irq_register(dmac_channel, UartDmaCallback, &UartRecvDmaInstance[uart_channel], priority);
|
||||
sysctl_dma_select((sysctl_dma_channel_t)dmac_channel, SYSCTL_DMA_SELECT_UART1_RX_REQ + uart_channel * 2);
|
||||
dmac_set_single_mode(dmac_channel, (void *)(&uart[uart_channel]->RBR), VRecvBuf, DMAC_ADDR_NOCHANGE, DMAC_ADDR_INCREMENT,
|
||||
DMAC_MSIZE_1, DMAC_TRANS_WIDTH_32, BufLen);
|
||||
}
|
||||
|
||||
int UartSendData(UartDeviceNumberT channel, const char *buffer, size_t BufLen)
|
||||
{
|
||||
GWriteCount = 0;
|
||||
while (GWriteCount < BufLen)
|
||||
{
|
||||
UartapbPutc(channel, *buffer++);
|
||||
GWriteCount++;
|
||||
}
|
||||
return GWriteCount;
|
||||
}
|
||||
|
||||
void UartSendDataDma(UartDeviceNumberT uart_channel, dmac_channel_number_t dmac_channel, const uint8_t *buffer, size_t BufLen)
|
||||
{
|
||||
uint32_t *VSendBuf = malloc(BufLen * sizeof(uint32_t));
|
||||
configASSERT(VSendBuf!=NULL);
|
||||
for(uint32_t i = 0; i < BufLen; i++)
|
||||
VSendBuf[i] = buffer[i];
|
||||
sysctl_dma_select((sysctl_dma_channel_t)dmac_channel, SYSCTL_DMA_SELECT_UART1_TX_REQ + uart_channel * 2);
|
||||
dmac_set_single_mode(dmac_channel, VSendBuf, (void *)(&uart[uart_channel]->THR), DMAC_ADDR_INCREMENT, DMAC_ADDR_NOCHANGE,
|
||||
DMAC_MSIZE_1, DMAC_TRANS_WIDTH_32, BufLen);
|
||||
dmac_wait_done(dmac_channel);
|
||||
free((void *)VSendBuf);
|
||||
}
|
||||
|
||||
void UartSendDataDmaIrq(UartDeviceNumberT uart_channel, dmac_channel_number_t dmac_channel,
|
||||
const uint8_t *buffer, size_t BufLen, plic_irq_callback_t uart_callback,
|
||||
void *ctx, uint32_t priority)
|
||||
{
|
||||
uint32_t *VSendBuf = malloc(BufLen * sizeof(uint32_t));
|
||||
configASSERT(VSendBuf!=NULL);
|
||||
|
||||
uart_send_dma_instance[uart_channel] = (UartDmaInstanceT) {
|
||||
.dmac_channel = dmac_channel,
|
||||
.UartNum = uart_channel,
|
||||
.MallocBuffer = VSendBuf,
|
||||
.buffer = (uint8_t *)buffer,
|
||||
.BufLen = BufLen,
|
||||
.IntMode = UART_SEND,
|
||||
.UartIntInstance.callback = uart_callback,
|
||||
.UartIntInstance.ctx = ctx,
|
||||
};
|
||||
|
||||
for(uint32_t i = 0; i < BufLen; i++)
|
||||
VSendBuf[i] = buffer[i];
|
||||
dmac_irq_register(dmac_channel, UartDmaCallback, &uart_send_dma_instance[uart_channel], priority);
|
||||
sysctl_dma_select((sysctl_dma_channel_t)dmac_channel, SYSCTL_DMA_SELECT_UART1_TX_REQ + uart_channel * 2);
|
||||
dmac_set_single_mode(dmac_channel, VSendBuf, (void *)(&uart[uart_channel]->THR), DMAC_ADDR_INCREMENT, DMAC_ADDR_NOCHANGE,
|
||||
DMAC_MSIZE_1, DMAC_TRANS_WIDTH_32, BufLen);
|
||||
|
||||
}
|
||||
|
||||
void uart_configure(UartDeviceNumberT channel, uint32_t BaudRate, UartBitwidthPointer DataWidth, UartStopbitT stopbit, UartParityT parity)
|
||||
{
|
||||
configASSERT(DataWidth >= 5 && DataWidth <= 8);
|
||||
if (DataWidth == 5)
|
||||
{
|
||||
configASSERT(stopbit != UART_STOP_2);
|
||||
}
|
||||
else
|
||||
{
|
||||
configASSERT(stopbit != UART_STOP_1_5);
|
||||
}
|
||||
|
||||
uint32_t stopbit_val = stopbit == UART_STOP_1 ? 0 : 1;
|
||||
uint32_t ParityVal;
|
||||
switch (parity)
|
||||
{
|
||||
case UART_PARITY_NONE:
|
||||
ParityVal = 0;
|
||||
break;
|
||||
case UART_PARITY_ODD:
|
||||
ParityVal = 1;
|
||||
break;
|
||||
case UART_PARITY_EVEN:
|
||||
ParityVal = 3;
|
||||
break;
|
||||
default:
|
||||
configASSERT(!"Invalid parity");
|
||||
break;
|
||||
}
|
||||
|
||||
uint32_t freq = SysctlClockGetFreq(SYSCTL_CLOCK_APB0);
|
||||
uint32_t divisor = freq / BaudRate;
|
||||
uint8_t dlh = divisor >> 12;
|
||||
uint8_t dll = (divisor - (dlh << 12)) / __UART_BRATE_CONST;
|
||||
uint8_t dlf = divisor - (dlh << 12) - dll * __UART_BRATE_CONST;
|
||||
|
||||
/* Set UART registers */
|
||||
uart[channel]->TCR &= ~(1u);
|
||||
uart[channel]->TCR &= ~(1u << 3);
|
||||
uart[channel]->TCR &= ~(1u << 4);
|
||||
uart[channel]->TCR |= (1u << 2);
|
||||
uart[channel]->TCR &= ~(1u << 1);
|
||||
uart[channel]->DE_EN &= ~(1u);
|
||||
|
||||
uart[channel]->LCR |= 1u << 7;
|
||||
uart[channel]->DLH = dlh;
|
||||
uart[channel]->DLL = dll;
|
||||
uart[channel]->DLF = dlf;
|
||||
uart[channel]->LCR = 0;
|
||||
uart[channel]->LCR = (DataWidth - 5) | (stopbit_val << 2) | (ParityVal << 3);
|
||||
uart[channel]->LCR &= ~(1u << 7);
|
||||
uart[channel]->MCR &= ~3;
|
||||
uart[channel]->IER |= 0x80; /* THRE */
|
||||
uart[channel]->FCR = UART_RECEIVE_FIFO_1 << 6 | UART_SEND_FIFO_8 << 4 | 0x1 << 3 | 0x1;
|
||||
}
|
||||
|
||||
void __attribute__((weak, alias("uart_configure")))
|
||||
uart_config(UartDeviceNumberT channel, uint32_t BaudRate, UartBitwidthPointer DataWidth, UartStopbitT stopbit, UartParityT parity);
|
||||
|
||||
void UartInit(UartDeviceNumberT channel)
|
||||
{
|
||||
sysctl_clock_enable(SYSCTL_CLOCK_UART1 + channel);
|
||||
}
|
||||
|
||||
void UartSetSendTrigger(UartDeviceNumberT channel, uart_send_trigger_t trigger)
|
||||
{
|
||||
uart[channel]->STET = trigger;
|
||||
}
|
||||
|
||||
void uart_set_receive_trigger(UartDeviceNumberT channel, uart_receive_trigger_t trigger)
|
||||
{
|
||||
uart[channel]->SRT = trigger;
|
||||
}
|
||||
|
||||
void uart_irq_register(UartDeviceNumberT channel, UartInterruptModeT interrupt_mode, plic_irq_callback_t uart_callback, void *ctx, uint32_t priority)
|
||||
{
|
||||
if(interrupt_mode == UART_SEND)
|
||||
{
|
||||
uart[channel]->IER |= 0x2;
|
||||
GUartInstance[channel].UartSendInstance.callback = uart_callback;
|
||||
GUartInstance[channel].UartSendInstance.ctx = ctx;
|
||||
}
|
||||
else if(interrupt_mode == UART_RECEIVE)
|
||||
{
|
||||
uart[channel]->IER |= 0x1;
|
||||
GUartInstance[channel].UartReceiveInstance.callback = uart_callback;
|
||||
GUartInstance[channel].UartReceiveInstance.ctx = ctx;
|
||||
}
|
||||
GUartInstance[channel].UartNum = channel;
|
||||
plic_set_priority(IRQN_UART1_INTERRUPT + channel, priority);
|
||||
plic_irq_register(IRQN_UART1_INTERRUPT + channel, UartIrqCallback, &GUartInstance[channel]);
|
||||
plic_irq_enable(IRQN_UART1_INTERRUPT + channel);
|
||||
}
|
||||
|
||||
void uart_irq_unregister(UartDeviceNumberT channel, UartInterruptModeT interrupt_mode)
|
||||
{
|
||||
if(interrupt_mode == UART_SEND)
|
||||
{
|
||||
uart[channel]->IER &= ~(0x2);
|
||||
GUartInstance[channel].UartSendInstance.callback = NULL;
|
||||
GUartInstance[channel].UartSendInstance.ctx = NULL;
|
||||
}
|
||||
else if(interrupt_mode == UART_RECEIVE)
|
||||
{
|
||||
uart[channel]->IER &= ~(0x1);
|
||||
GUartInstance[channel].UartReceiveInstance.callback = NULL;
|
||||
GUartInstance[channel].UartReceiveInstance.ctx = NULL;
|
||||
}
|
||||
if(uart[channel]->IER == 0)
|
||||
{
|
||||
plic_irq_unregister(IRQN_UART1_INTERRUPT + channel);
|
||||
}
|
||||
}
|
||||
|
||||
int uart_dma_irq(void *ctx)
|
||||
{
|
||||
UartInstanceDmaT *v_instance = (UartInstanceDmaT *)ctx;
|
||||
dmac_irq_unregister(v_instance->dmac_channel);
|
||||
if(v_instance->TransferMode == UART_SEND)
|
||||
{
|
||||
while(!(uart[v_instance->UartNum]->LSR & (1u << 6)));
|
||||
}
|
||||
spinlock_unlock(&v_instance->lock);
|
||||
if(v_instance->UartIntInstance.callback)
|
||||
{
|
||||
v_instance->UartIntInstance.callback(v_instance->UartIntInstance.ctx);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void uart_handle_data_dma(UartDeviceNumberT uart_channel ,uart_data_t data, plic_interrupt_t *cb)
|
||||
{
|
||||
configASSERT(uart_channel < UART_DEVICE_MAX);
|
||||
if(data.TransferMode == UART_SEND)
|
||||
{
|
||||
configASSERT(data.tx_buf && data.tx_len && data.tx_channel < DMAC_CHANNEL_MAX);
|
||||
spinlock_lock(&GUartSendInstanceDma[uart_channel].lock);
|
||||
if(cb)
|
||||
{
|
||||
GUartSendInstanceDma[uart_channel].UartIntInstance.callback = cb->callback;
|
||||
GUartSendInstanceDma[uart_channel].UartIntInstance.ctx = cb->ctx;
|
||||
GUartSendInstanceDma[uart_channel].dmac_channel = data.tx_channel;
|
||||
GUartSendInstanceDma[uart_channel].TransferMode = UART_SEND;
|
||||
dmac_irq_register(data.tx_channel, uart_dma_irq, &GUartSendInstanceDma[uart_channel], cb->priority);
|
||||
}
|
||||
sysctl_dma_select((sysctl_dma_channel_t)data.tx_channel, SYSCTL_DMA_SELECT_UART1_TX_REQ + uart_channel * 2);
|
||||
dmac_set_single_mode(data.tx_channel, data.tx_buf, (void *)(&uart[uart_channel]->THR), DMAC_ADDR_INCREMENT, DMAC_ADDR_NOCHANGE,
|
||||
DMAC_MSIZE_1, DMAC_TRANS_WIDTH_32, data.tx_len);
|
||||
if(!cb)
|
||||
{
|
||||
dmac_wait_done(data.tx_channel);
|
||||
while(!(uart[uart_channel]->LSR & (1u << 6)));
|
||||
spinlock_unlock(&GUartSendInstanceDma[uart_channel].lock);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
configASSERT(data.rx_buf && data.rx_len && data.rx_channel < DMAC_CHANNEL_MAX);
|
||||
spinlock_lock(&GUartRecvInstanceDma[uart_channel].lock);
|
||||
if(cb)
|
||||
{
|
||||
GUartRecvInstanceDma[uart_channel].UartIntInstance.callback = cb->callback;
|
||||
GUartRecvInstanceDma[uart_channel].UartIntInstance.ctx = cb->ctx;
|
||||
GUartRecvInstanceDma[uart_channel].dmac_channel = data.rx_channel;
|
||||
GUartRecvInstanceDma[uart_channel].TransferMode = UART_RECEIVE;
|
||||
dmac_irq_register(data.rx_channel, uart_dma_irq, &GUartRecvInstanceDma[uart_channel], cb->priority);
|
||||
}
|
||||
sysctl_dma_select((sysctl_dma_channel_t)data.rx_channel, SYSCTL_DMA_SELECT_UART1_RX_REQ + uart_channel * 2);
|
||||
dmac_set_single_mode(data.rx_channel, (void *)(&uart[uart_channel]->RBR), data.rx_buf, DMAC_ADDR_NOCHANGE, DMAC_ADDR_INCREMENT,
|
||||
DMAC_MSIZE_1, DMAC_TRANS_WIDTH_32, data.rx_len);
|
||||
if(!cb)
|
||||
{
|
||||
dmac_wait_done(data.rx_channel);
|
||||
spinlock_unlock(&GUartRecvInstanceDma[uart_channel].lock);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
/* Copyright 2018 Canaan Inc.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file hardware_uarths.c
|
||||
* @brief add from Canaan k210 SDK
|
||||
* https://canaan-creative.com/developer
|
||||
* @version 1.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2021-04-25
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include "hardware_uarths.h"
|
||||
#include "sysctl.h"
|
||||
#include "encoding.h"
|
||||
|
||||
volatile UarthsT *const uarths = (volatile UarthsT *)UARTHS_BASE_ADDR;
|
||||
|
||||
typedef struct _uarths_instance
|
||||
{
|
||||
plic_irq_callback_t callback;
|
||||
void *ctx;
|
||||
uarths_interrupt_mode_t uarths_interrupt_mode;
|
||||
} uarths_instance_t;
|
||||
|
||||
uarths_instance_t g_uarths_instance;
|
||||
|
||||
uarths_interrupt_mode_t uarths_get_interrupt_mode(void)
|
||||
{
|
||||
uint32_t v_rx_interrupt = uarths->ip.rxwm;
|
||||
uint32_t v_tx_interrupt = uarths->ip.txwm;
|
||||
return (v_rx_interrupt << 1) | v_tx_interrupt;
|
||||
}
|
||||
|
||||
int uarths_irq_callback(void *ctx)
|
||||
{
|
||||
uarths_instance_t *uart_context = (uarths_instance_t *)ctx;
|
||||
|
||||
if(uart_context->callback)
|
||||
uart_context->callback(uart_context->ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void uarths_set_interrupt_cnt(uarths_interrupt_mode_t interrupt_mode, uint8_t cnt)
|
||||
{
|
||||
switch(interrupt_mode)
|
||||
{
|
||||
case UARTHS_SEND:
|
||||
uarths->txctrl.txcnt = cnt;
|
||||
break;
|
||||
case UARTHS_RECEIVE:
|
||||
uarths->rxctrl.rxcnt = cnt;
|
||||
break;
|
||||
case UARTHS_SEND_RECEIVE:
|
||||
default:
|
||||
uarths->txctrl.txcnt = cnt;
|
||||
uarths->rxctrl.rxcnt = cnt;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void uarths_set_irq(uarths_interrupt_mode_t interrupt_mode, plic_irq_callback_t uarths_callback, void *ctx, uint32_t priority)
|
||||
{
|
||||
g_uarths_instance.callback = uarths_callback;
|
||||
g_uarths_instance.ctx = ctx;
|
||||
|
||||
switch(interrupt_mode)
|
||||
{
|
||||
case UARTHS_SEND:
|
||||
uarths->ie.txwm = 1;
|
||||
uarths->ie.rxwm = 0;
|
||||
break;
|
||||
case UARTHS_RECEIVE:
|
||||
uarths->ie.txwm = 0;
|
||||
uarths->ie.rxwm = 1;
|
||||
break;
|
||||
default:
|
||||
uarths->ie.txwm = 1;
|
||||
uarths->ie.rxwm = 1;
|
||||
break;
|
||||
}
|
||||
g_uarths_instance.uarths_interrupt_mode = interrupt_mode;
|
||||
|
||||
plic_set_priority(IRQN_UARTHS_INTERRUPT, priority);
|
||||
plic_irq_register(IRQN_UARTHS_INTERRUPT, uarths_irq_callback, &g_uarths_instance);
|
||||
plic_irq_enable(IRQN_UARTHS_INTERRUPT);
|
||||
}
|
||||
|
||||
static inline int uarths_putc(char c)
|
||||
{
|
||||
while (uarths->txdata.full)
|
||||
continue;
|
||||
uarths->txdata.data = (uint8_t)c;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t uarths_receive_data(uint8_t *buf, size_t BufLen)
|
||||
{
|
||||
size_t i;
|
||||
for(i = 0; i < BufLen; i++)
|
||||
{
|
||||
uarths_rxdata_t recv = uarths->rxdata;
|
||||
if(recv.empty)
|
||||
break;
|
||||
else
|
||||
buf[i] = (recv.data & 0xFF);
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
size_t uarths_send_data(const uint8_t *buf, size_t BufLen)
|
||||
{
|
||||
size_t write = 0;
|
||||
while (write < BufLen)
|
||||
{
|
||||
uarths_putc(*buf++);
|
||||
write++;
|
||||
}
|
||||
return write;
|
||||
}
|
||||
|
||||
int uarths_getc(void)
|
||||
{
|
||||
/* while not empty */
|
||||
uarths_rxdata_t recv = uarths->rxdata;
|
||||
|
||||
if (recv.empty)
|
||||
return EOF;
|
||||
else
|
||||
return recv.data;
|
||||
}
|
||||
|
||||
int uarths_putchar(char c)
|
||||
{
|
||||
return uarths_putc(c);
|
||||
}
|
||||
|
||||
int uarths_puts(const char *s)
|
||||
{
|
||||
while (*s)
|
||||
if (uarths_putc(*s++) != 0)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void uarths_init(void)
|
||||
{
|
||||
uint32_t freq = SysctlClockGetFreq(SYSCTL_CLOCK_CPU);
|
||||
uint16_t div = freq / 115200 - 1;
|
||||
|
||||
/* Set UART registers */
|
||||
uarths->div.div = div;
|
||||
uarths->txctrl.txen = 1;
|
||||
uarths->rxctrl.rxen = 1;
|
||||
uarths->txctrl.txcnt = 0;
|
||||
uarths->rxctrl.rxcnt = 0;
|
||||
uarths->ip.txwm = 1;
|
||||
uarths->ip.rxwm = 1;
|
||||
uarths->ie.txwm = 0;
|
||||
uarths->ie.rxwm = 1;
|
||||
}
|
||||
|
||||
void uarths_config(uint32_t BaudRate, uarths_stopbit_t stopbit)
|
||||
{
|
||||
uint32_t freq = SysctlClockGetFreq(SYSCTL_CLOCK_CPU);
|
||||
uint16_t div = freq / BaudRate - 1;
|
||||
uarths->div.div = div;
|
||||
uarths->txctrl.nstop = stopbit;
|
||||
}
|
||||
Reference in New Issue
Block a user