forked from xuos/xiuos
add gap8 board of riscv for xiuos
This commit is contained in:
@@ -0,0 +1,14 @@
|
||||
menuconfig BSP_USING_UART0
|
||||
bool "Enable UART0"
|
||||
default y
|
||||
if BSP_USING_UART0
|
||||
config SERIAL_BUS_NAME_0
|
||||
string "serial bus name"
|
||||
default "uart0"
|
||||
config SERIAL_DRV_NAME_0
|
||||
string "serial bus driver name"
|
||||
default "uart0_drv"
|
||||
config SERIAL_0_DEVICE_NAME_0
|
||||
string "serial bus device name"
|
||||
default "uart0_dev0"
|
||||
endif
|
||||
@@ -0,0 +1,4 @@
|
||||
SRC_FILES := connect_uart.c hardware_udma.c
|
||||
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
||||
@@ -0,0 +1,326 @@
|
||||
/*
|
||||
* Copyright (c) 2020 AIIT XUOS Lab
|
||||
* XiUOS is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file connect_usart.c
|
||||
* @brief support gap8-board uart function and register to bus framework
|
||||
* @version 1.1
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2021-07-23
|
||||
*/
|
||||
|
||||
#include <xiuos.h>
|
||||
#include <device.h>
|
||||
|
||||
#include "connect_uart.h"
|
||||
#include "hardware_udma.h"
|
||||
#include "hardware_gpio.h"
|
||||
#include <board.h>
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
static void UartRxIsr(void *arg)
|
||||
{
|
||||
struct SerialBus *serial_bus = (struct SerialBus *)arg;
|
||||
struct SerialHardwareDevice *serial_dev = (struct SerialHardwareDevice *)serial_bus->bus.owner_haldev;
|
||||
|
||||
SerialSetIsr(serial_dev, SERIAL_EVENT_RX_IND);
|
||||
}
|
||||
|
||||
static uint32 SerialInit(struct SerialDriver *serial_drv, struct BusConfigureInfo *configure_info)
|
||||
{
|
||||
asm volatile("nop");
|
||||
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);
|
||||
}
|
||||
|
||||
struct gap8_udma_peripheral *uart_udma = (struct gap8_udma_peripheral *)serial_cfg->hw_cfg.private_data;
|
||||
uart_reg_t *uart_reg = (uart_reg_t *)uart_udma->regs;
|
||||
uint32_t cfg_reg = 0;
|
||||
|
||||
uint16_t div = CONFIG_CORE_CLOCK_FREQ / serial_cfg->data_cfg.serial_baud_rate;
|
||||
|
||||
gap8_udma_init(uart_udma);
|
||||
|
||||
/* Setup baudrate etc. */
|
||||
cfg_reg = UART_SETUP_BIT_LENGTH(serial_cfg->data_cfg.serial_data_bits - 5) |
|
||||
UART_SETUP_PARITY_ENA(serial_cfg->data_cfg.serial_parity_mode - 1) |
|
||||
UART_SETUP_STOP_BITS(serial_cfg->data_cfg.serial_stop_bits - 1) |
|
||||
UART_SETUP_TX_ENA(1) |
|
||||
UART_SETUP_RX_ENA(1) |
|
||||
UART_SETUP_CLKDIV(div);
|
||||
uart_reg->SETUP = cfg_reg;
|
||||
|
||||
gap8_configpin(GAP8_PIN_A7_UART_TX | GAP8_PIN_PULL_UP | GAP8_PIN_SPEED_HIGH);
|
||||
gap8_configpin(GAP8_PIN_B6_UART_RX | GAP8_PIN_PULL_UP | GAP8_PIN_SPEED_HIGH);
|
||||
|
||||
return EOK;
|
||||
}
|
||||
|
||||
static uint32 SerialConfigure(struct SerialDriver *serial_drv, int serial_operation_cmd)
|
||||
{
|
||||
NULL_PARAM_CHECK(serial_drv);
|
||||
|
||||
struct SerialHardwareDevice *serial_dev = (struct SerialHardwareDevice *)serial_drv->driver.owner_bus->owner_haldev;
|
||||
|
||||
struct SerialCfgParam *serial_cfg = (struct SerialCfgParam *)serial_drv->private_data;
|
||||
struct gap8_udma_peripheral *uart_udma = (struct gap8_udma_peripheral *)serial_cfg->hw_cfg.private_data;
|
||||
|
||||
if (OPER_SET_INT == serial_operation_cmd) {
|
||||
x_base lock = 0;
|
||||
lock = DISABLE_INTERRUPT();
|
||||
|
||||
gap8_udma_rx_setirq(uart_udma, 1);
|
||||
|
||||
gap8_udma_rx_start(uart_udma, serial_dev->serial_fifo.serial_rx->serial_rx_buffer, 1, 1);
|
||||
|
||||
ENABLE_INTERRUPT(lock);
|
||||
} else if (OPER_CLR_INT == serial_operation_cmd) {
|
||||
gap8_udma_rx_setirq(uart_udma, 0);
|
||||
|
||||
gap8_udma_deinit(uart_udma);
|
||||
}
|
||||
|
||||
return EOK;
|
||||
}
|
||||
|
||||
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 int SerialPutChar(struct SerialHardwareDevice *serial_dev, char c)
|
||||
{
|
||||
struct Driver *drv = serial_dev->haldev.owner_bus->owner_driver;
|
||||
struct SerialDriver *serial_drv = (struct SerialDriver *)drv;
|
||||
struct SerialDevParam *serial_dev_param = (struct SerialDevParam *)serial_dev->haldev.private_data;
|
||||
struct SerialCfgParam *serial_cfg = (struct SerialCfgParam *)serial_dev->private_data;
|
||||
struct gap8_udma_peripheral *uart_udma = (struct gap8_udma_peripheral *)serial_cfg->hw_cfg.private_data;
|
||||
|
||||
gap8_udma_tx_setirq(uart_udma,1);
|
||||
gap8_udma_tx_start(uart_udma, &c, 1, 1);
|
||||
|
||||
for(int i = 999 ; i> 0 ; i--);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int SerialGetChar(struct SerialHardwareDevice *serial_dev)
|
||||
{
|
||||
struct Driver *drv = serial_dev->haldev.owner_bus->owner_driver;
|
||||
struct SerialDriver *serial_drv = (struct SerialDriver *)drv;
|
||||
struct SerialDevParam *serial_dev_param = (struct SerialDevParam *)serial_dev->haldev.private_data;
|
||||
struct SerialCfgParam *serial_cfg = (struct SerialCfgParam *)serial_dev->private_data;
|
||||
struct gap8_udma_peripheral *uart_udma = (struct gap8_udma_peripheral *)serial_cfg->hw_cfg.private_data;
|
||||
|
||||
uint8_t rx_buf[4] = {0};
|
||||
uint8_t ch = rx_buf[0];
|
||||
|
||||
/* Then trigger another reception */
|
||||
|
||||
gap8_udma_rx_start(uart_udma, rx_buf, 1, 1);
|
||||
if (ch == 0)
|
||||
return -ERROR;
|
||||
|
||||
return ch;
|
||||
}
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
static struct gap8_udma_peripheral gap8_udma =
|
||||
{
|
||||
.regs = (udma_reg_t *)UART,
|
||||
.id = GAP8_UDMA_ID_UART,
|
||||
.on_tx = NONE,//UartRxIsr??
|
||||
// .on_tx = UartTxIsr,//UartRxIsr??
|
||||
.tx_arg = NONE,
|
||||
.on_rx = UartRxIsr,
|
||||
.rx_arg = NONE,
|
||||
.is_tx_continous = 0,
|
||||
.is_rx_continous = 1,
|
||||
};
|
||||
|
||||
/*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("InitHwUart SerialBusInit error %d\n", ret);
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
/*Init the serial driver*/
|
||||
ret = SerialDriverInit(serial_driver, drv_name);
|
||||
if (EOK != ret) {
|
||||
KPrintf("InitHwUart 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("InitHwUart 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("InitHwUart SerialDeviceInit device %s error %d\n", dev_name, ret);
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
ret = SerialDeviceAttachToBus(dev_name, bus_name);
|
||||
if (EOK != ret) {
|
||||
KPrintf("InitHwUart SerialDeviceAttachToBus device %s error %d\n", dev_name, ret);
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int InitHwUart(void)
|
||||
{
|
||||
x_err_t ret = EOK;
|
||||
|
||||
static struct SerialBus serial_bus;
|
||||
memset(&serial_bus, 0, sizeof(struct SerialBus));
|
||||
|
||||
|
||||
static struct SerialDriver serial_driver;
|
||||
memset(&serial_driver, 0, sizeof(struct SerialDriver));
|
||||
|
||||
static struct SerialHardwareDevice serial_device;
|
||||
memset(&serial_device, 0, sizeof(struct SerialHardwareDevice));
|
||||
|
||||
static struct SerialCfgParam serial_cfg;
|
||||
memset(&serial_cfg, 0, sizeof(struct SerialCfgParam));
|
||||
|
||||
static struct SerialDevParam serial_dev_param;
|
||||
memset(&serial_dev_param, 0, sizeof(struct SerialDevParam));
|
||||
|
||||
serial_driver.drv_done = &drv_done;
|
||||
serial_driver.configure = &SerialDrvConfigure;
|
||||
serial_device.hwdev_done = &hwdev_done;
|
||||
|
||||
serial_cfg.data_cfg = data_cfg_init;
|
||||
|
||||
serial_cfg.hw_cfg.private_data = (void *)&gap8_udma;
|
||||
serial_driver.private_data = (void *)&serial_cfg;
|
||||
|
||||
serial_dev_param.serial_work_mode = SIGN_OPER_INT_RX;
|
||||
serial_device.haldev.private_data = (void *)&serial_dev_param;
|
||||
|
||||
ret = BoardSerialBusInit(&serial_bus, &serial_driver, SERIAL_BUS_NAME_0, SERIAL_DRV_NAME_0);
|
||||
if (EOK != ret) {
|
||||
KPrintf("InitHwUart uarths error ret %u\n", ret);
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
ret = BoardSerialDevBend(&serial_device, (void *)&serial_cfg, SERIAL_BUS_NAME_0, SERIAL_0_DEVICE_NAME_0);
|
||||
if (EOK != ret) {
|
||||
KPrintf("InitHwUart uarths error ret %u\n", ret);
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
gap8_udma.rx_arg = (void *)&serial_bus;
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,387 @@
|
||||
/****************************************************************************
|
||||
* arch/risc-v/src/gap8/gap8_udma.c
|
||||
* uDMA driver for GAP8
|
||||
*
|
||||
* Copyright (C) 2018 Gregory Nutt. All rights reserved.
|
||||
* Author: hhuysqt <1020988872@qq.com>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* 3. Neither the name NuttX nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* GAP8 features a simple uDMA subsystem. Peripherals including UART, SPI,
|
||||
* I2C, I2S, CPI, LVDS, Hyperbus, have config registers memory-mapped, but
|
||||
* not data registers. The only way to send or receive data is using the
|
||||
* uDMA. Those peripherals share the same uDMA ISR.
|
||||
*
|
||||
* Note that uDMA can only recognize L2 RAM. So data must not be stored at
|
||||
* L1, which means that if you link the stack at L1, you cannot use local
|
||||
* buffers as data src or destination.
|
||||
*
|
||||
* As for the UART driver, the SOC_EU may fire a redundant IRQ even if the
|
||||
* uDMA hasn't finished its job. So I spin on TX channel and bypass on RX
|
||||
* channel, if the IRQ is redundant.
|
||||
****************************************************************************/
|
||||
|
||||
/**
|
||||
* @file hardware_udma.c
|
||||
* @brief add from Gap8 riscv SDK
|
||||
* https://greenwavesdev2.wpengine.com/sdk-manuals/
|
||||
* @version 1.1
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2021-07-27
|
||||
*/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include "hardware_udma.h"
|
||||
#include <stddef.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
#define CHECK_CHANNEL_ID(INSTANCE) \
|
||||
if ((INSTANCE) == NULL || \
|
||||
(INSTANCE)->id >= GAP8_UDMA_NR_CHANNELS) \
|
||||
{ \
|
||||
return -1; \
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
/* uDMA peripheral instances
|
||||
* The peripheral driver instantiate it and register through _init()
|
||||
*/
|
||||
|
||||
static struct gap8_udma_peripheral *_peripherals[GAP8_UDMA_NR_CHANNELS] =
|
||||
{
|
||||
0
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
static void _dma_txstart(struct gap8_udma_peripheral *the_peri)
|
||||
{
|
||||
the_peri->regs->TX_SADDR = (uint32_t)the_peri->tx.buff;
|
||||
the_peri->regs->TX_SIZE = (uint32_t)the_peri->tx.block_size;
|
||||
the_peri->regs->TX_CFG = UDMA_CFG_EN(1);
|
||||
}
|
||||
|
||||
static void _dma_rxstart(struct gap8_udma_peripheral *the_peri)
|
||||
{
|
||||
the_peri->regs->RX_SADDR = (uint32_t)the_peri->rx.buff;
|
||||
the_peri->regs->RX_SIZE = (uint32_t)the_peri->rx.block_size;
|
||||
the_peri->regs->RX_CFG = UDMA_CFG_EN(1);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: gap8_udma_init
|
||||
*
|
||||
* Description:
|
||||
* Initialize (and enable) a udma peripheral.
|
||||
*
|
||||
* Input:
|
||||
* instance: pointer to a peripheral instance connected to uDMA
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int gap8_udma_init(struct gap8_udma_peripheral *instance)
|
||||
{
|
||||
uint32_t id;
|
||||
asm volatile("nop");
|
||||
CHECK_CHANNEL_ID(instance)
|
||||
|
||||
id = instance->id;
|
||||
_peripherals[id] = instance;
|
||||
|
||||
/* Enable clock gating */
|
||||
|
||||
UDMA_GC->CG |= (1L << id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: gap8_udma_deinit
|
||||
*
|
||||
* Description:
|
||||
* Deinit a udma peripheral
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int gap8_udma_deinit(struct gap8_udma_peripheral *instance)
|
||||
{
|
||||
uint32_t id;
|
||||
|
||||
CHECK_CHANNEL_ID(instance)
|
||||
|
||||
id = instance->id;
|
||||
_peripherals[id] = NULL;
|
||||
|
||||
/* Disable clock gating */
|
||||
|
||||
UDMA_GC->CG &= ~(1L << id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: gap8_udma_tx_setirq
|
||||
*
|
||||
* Description:
|
||||
* Enable or disable the tx interrupt.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int gap8_udma_tx_setirq(struct gap8_udma_peripheral *instance, bool enable)
|
||||
{
|
||||
CHECK_CHANNEL_ID(instance)
|
||||
|
||||
/* The irq enable bit happened to be 2*id + 1 */
|
||||
|
||||
if (enable)
|
||||
{
|
||||
up_enable_event(1 + (instance->id << 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
up_disable_event(1 + (instance->id << 1));
|
||||
#if 0
|
||||
instance->regs->TX_CFG = UDMA_CFG_CLR(1);
|
||||
#endif
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: gap8_udma_rx_setirq
|
||||
*
|
||||
* Description:
|
||||
* Enable or disable the rx interrupt.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int gap8_udma_rx_setirq(struct gap8_udma_peripheral *instance, bool enable)
|
||||
{
|
||||
CHECK_CHANNEL_ID(instance)
|
||||
|
||||
/* The irq enable bit happened to be 2*id */
|
||||
|
||||
if (enable)
|
||||
{
|
||||
up_enable_event(instance->id << 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
up_disable_event(instance->id << 1);
|
||||
#if 0
|
||||
instance->regs->RX_CFG = UDMA_CFG_CLR(1);
|
||||
#endif
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: gap8_udma_tx_start
|
||||
*
|
||||
* Description:
|
||||
* Send size * count bytes non-blocking.
|
||||
*
|
||||
* This function may be called from ISR, so it cannot be blocked. The
|
||||
* caller should manage the muxing.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int gap8_udma_tx_start(struct gap8_udma_peripheral *instance,
|
||||
uint8_t *buff, uint32_t size, int count)
|
||||
{
|
||||
CHECK_CHANNEL_ID(instance)
|
||||
|
||||
instance->tx.buff = buff;
|
||||
instance->tx.block_size = size;
|
||||
instance->tx.block_count = count;
|
||||
|
||||
_dma_txstart(instance);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: gap8_udma_rx_start
|
||||
*
|
||||
* Description:
|
||||
* Receive size * count bytes
|
||||
*
|
||||
* This function may be called from ISR, so it cannot be blocked. The
|
||||
* caller should manage the muxing.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int gap8_udma_rx_start(struct gap8_udma_peripheral *instance,
|
||||
uint8_t *buff, uint32_t size, int count)
|
||||
{
|
||||
CHECK_CHANNEL_ID(instance)
|
||||
|
||||
instance->rx.buff = buff;
|
||||
instance->rx.block_size = size;
|
||||
instance->rx.block_count = count;
|
||||
|
||||
_dma_rxstart(instance);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: gap8_udma_tx_poll
|
||||
*
|
||||
* Description:
|
||||
* Return 0 if the buffer is not in the tx pending list.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int gap8_udma_tx_poll(struct gap8_udma_peripheral *instance)
|
||||
{
|
||||
CHECK_CHANNEL_ID(instance)
|
||||
|
||||
return instance->tx.block_count <= 0 ? 0 : -1;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: gap8_udma_rx_poll
|
||||
*
|
||||
* Description:
|
||||
* Return 0 if the buffer is not in the rx pending list.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int gap8_udma_rx_poll(struct gap8_udma_peripheral *instance)
|
||||
{
|
||||
CHECK_CHANNEL_ID(instance)
|
||||
|
||||
return instance->rx.block_count <= 0 ? 0 : -1;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: gap8_udma_doirq
|
||||
*
|
||||
* Description:
|
||||
* uDMA ISR
|
||||
*
|
||||
****************************************************************************/
|
||||
int gap8_udma_doirq(int irq, void *context, void *arg)
|
||||
{
|
||||
struct gap8_udma_peripheral *the_peripheral;
|
||||
uint32_t event = SOC_EVENTS->CURRENT_EVENT & 0xff;
|
||||
|
||||
if (event > GAP8_UDMA_MAX_EVENT)
|
||||
{
|
||||
/* Bypass */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Peripheral id happened to be half of event... */
|
||||
|
||||
the_peripheral = _peripherals[event >> 1];
|
||||
if (the_peripheral == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (event & 0x1)
|
||||
{
|
||||
/* Tx channel */
|
||||
|
||||
if (the_peripheral->tx.block_count > 1)
|
||||
{
|
||||
the_peripheral->tx.block_count--;
|
||||
the_peripheral->tx.buff += the_peripheral->tx.block_size;
|
||||
_dma_txstart(the_peripheral);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The buffer is exhausted. Forward to peripheral's driver */
|
||||
|
||||
while (the_peripheral->regs->TX_SIZE != 0)
|
||||
{
|
||||
/* I don't know why but I have to spin here. SOC_EU would
|
||||
* fire the IRQ even if uDMA hasn't finished the job.
|
||||
* If I bypassed it, I would lose the finish event...
|
||||
*/
|
||||
}
|
||||
|
||||
the_peripheral->tx.block_count = 0;
|
||||
if (the_peripheral->on_tx)
|
||||
{
|
||||
the_peripheral->on_tx(the_peripheral->tx_arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Rx channel */
|
||||
asm volatile("nop");
|
||||
if (the_peripheral->rx.block_count > 1)
|
||||
{
|
||||
the_peripheral->rx.block_count--;
|
||||
the_peripheral->rx.buff += the_peripheral->rx.block_size;
|
||||
_dma_rxstart(the_peripheral);
|
||||
}
|
||||
else if (!(the_peripheral->regs->RX_CFG & UDMA_CFG_CLR(1)))
|
||||
{
|
||||
/* The buffer is exhausted. Forward to peripheral's driver
|
||||
*
|
||||
* Again I don't know why but I have to test the PENDING bit of
|
||||
* the uDMA, so as to avoid the redundant IRQ...
|
||||
*/
|
||||
|
||||
the_peripheral->rx.block_count = 0;
|
||||
if (the_peripheral->on_rx)
|
||||
{
|
||||
the_peripheral->on_rx(the_peripheral->rx_arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user