First commit XiUOS

This commit is contained in:
xuetest
2021-04-28 17:49:18 +08:00
commit 6001051eb7
1331 changed files with 433955 additions and 0 deletions
+29
View File
@@ -0,0 +1,29 @@
menuconfig BSP_USING_PLIC
bool "Using PLIC device"
default y
if BSP_USING_PLIC
source "$BSP_DIR/third_party_driver/plic/Kconfig"
endif
menuconfig BSP_USING_SYSCLOCK
bool "Using SYSCLOCK device"
default y
if BSP_USING_SYSCLOCK
source "$BSP_DIR/third_party_driver/sys_clock/Kconfig"
endif
menuconfig BSP_USING_UART
bool "Using UART device"
default y
select RESOURCES_SERIAL
if BSP_USING_UART
source "$BSP_DIR/third_party_driver/uart/Kconfig"
endif
+65
View File
@@ -0,0 +1,65 @@
SRC_FILES := sleep.c
ifeq ($(CONFIG_BSP_USING_AUDIO),y)
SRC_DIR += audio
endif
ifeq ($(CONFIG_BSP_USING_CAMERA),y)
SRC_DIR += camera
endif
ifeq ($(CONFIG_BSP_USING_DMA),y)
SRC_DIR += dma
endif
ifeq ($(CONFIG_BSP_USING_GPIO),y)
SRC_DIR += gpio
endif
ifeq ($(CONFIG_BSP_USING_I2C),y)
SRC_DIR += i2c
endif
ifeq ($(CONFIG_BSP_USING_I2S),y)
SRC_DIR += i2s
endif
ifeq ($(CONFIG_BSP_USING_LCD),y)
SRC_DIR += lcd
endif
ifeq ($(CONFIG_BSP_USING_PLIC),y)
SRC_DIR += plic
endif
ifeq ($(CONFIG_BSP_USING_RTC),y)
SRC_DIR += rtc
endif
ifeq ($(CONFIG_BSP_USING_SECURITY),y)
SRC_DIR += security
endif
ifeq ($(CONFIG_BSP_USING_SPI),y)
SRC_DIR += spi
endif
ifeq ($(CONFIG_BSP_USING_SYSCLOCK),y)
SRC_DIR += sys_clock
endif
ifeq ($(CONFIG_BSP_USING_UART),y)
SRC_DIR += uart
endif
ifeq ($(CONFIG_BSP_USING_VIDEO),y)
SRC_DIR += video
endif
ifeq ($(CONFIG_BSP_USING_WDT),y)
SRC_DIR += watchdog
endif
include $(KERNEL_ROOT)/compiler.mk
@@ -0,0 +1,323 @@
/* 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 clint.h
* @brief add from Canaan k210 SDK
* https://canaan-creative.com/developer
* @version 1.0
* @author AIIT XUOS Lab
* @date 2021-04-25
*/
#ifndef __CLINT_H__
#define __CLINT_H__
#include <stddef.h>
#include <stdint.h>
#include "platform.h"
#ifdef __cplusplus
extern "C" {
#endif
/* clang-format off */
/* Register address offsets */
#define CLINT_MSIP (0x0000)
#define CLINT_MSIP_SIZE (0x4)
#define CLINT_MTIMECMP (0x4000)
#define CLINT_MTIMECMP_SIZE (0x8)
#define CLINT_MTIME (0xBFF8)
#define CLINT_MTIME_SIZE (0x8)
/* Max number of cores */
#define CLINT_MAX_CORES (4095)
/* Real number of cores */
#define CLINT_NUM_CORES (2)
/* Clock frequency division factor */
#define CLINT_CLOCK_DIV (50)
/* clang-format on */
/**
* @brief MSIP Registers
*
* Machine-mode software interrupts are generated by writing to a
* per-core memory-mapped control register. The msip registers are
* 32-bit wide WARL registers, where the LSB is reflected in the
* msip bit of the associated cores mip register. Other bits in
* the msip registers are hardwired to zero. The mapping supports
* up to 4095 machine-mode cores.
*/
typedef struct _clint_msip
{
uint32_t msip : 1; /*!< Bit 0 is msip */
uint32_t zero : 31; /*!< Bits [32:1] is 0 */
} __attribute__((packed, aligned(4))) clint_msip_t;
/**
* @brief Timer compare Registers Machine-mode timer interrupts are
* generated by a real-time counter and a per-core comparator. The
* mtime register is a 64-bit read-only register that contains the
* current value of the real-time counter. Each mtimecmp register
* holds its cores time comparator. A timer interrupt is pending
* whenever mtime is greater than or equal to the value in a
* cores mtimecmp register. The timer interrupt is reflected in
* the mtip bit of the associated cores mip register.
*/
typedef uint64_t clint_mtimecmp_t;
/**
* @brief Timer Registers
*
* The mtime register has a 64-bit precision on all RV32, RV64,
* and RV128 systems. Platforms provide a 64-bit memory-mapped
* machine-mode timer compare register (mtimecmp), which causes a
* timer interrupt to be posted when the mtime register contains a
* value greater than or equal to the value in the mtimecmp
* register. The interrupt remains posted until it is cleared by
* writing the mtimecmp register. The interrupt will only be taken
* if interrupts are enabled and the MTIE bit is set in the mie
* register.
*/
typedef uint64_t clint_mtime_t;
/**
* @brief CLINT object
*
* Coreplex-Local INTerrupts, which includes software interrupts,
* local timer interrupts, and other interrupts routed directly to
* a core.
*/
typedef struct _clint
{
/* 0x0000 to 0x3FF8, MSIP Registers */
clint_msip_t msip[CLINT_MAX_CORES];
/* Resverd space, do not use */
uint32_t resv0;
/* 0x4000 to 0xBFF0, Timer Compare Registers */
clint_mtimecmp_t mtimecmp[CLINT_MAX_CORES];
/* 0xBFF8, Time Register */
clint_mtime_t mtime;
} __attribute__((packed, aligned(4))) clint_t;
/**
* @brief Clint object instanse
*/
extern volatile clint_t* const clint;
/**
* @brief Definitions for the timer callbacks
*/
typedef int (*clint_timer_callback_t)(void *ctx);
/**
* @brief Definitions for local interprocessor interrupt callbacks
*/
typedef int (*clint_ipi_callback_t)(void *ctx);
typedef struct _clint_timer_instance
{
uint64_t interval;
uint64_t cycles;
uint64_t single_shot;
clint_timer_callback_t callback;
void *ctx;
} clint_timer_instance_t;
typedef struct _clint_ipi_instance
{
clint_ipi_callback_t callback;
void *ctx;
} clint_ipi_instance_t;
/**
* @brief Get the time form CLINT timer register
*
* @note The CLINT must init to get right time
*
* @return 64bit Time
*/
uint64_t clint_get_time(void);
/**
* @brief Init the CLINT timer
*
* @note MIP_MTIP will be clear after init. The MSTATUS_MIE must set by
* user.
*
* @return result
* - 0 Success
* - Other Fail
*/
int clint_timer_init(void);
/**
* @brief Stop the CLINT timer
*
* @note MIP_MTIP will be clear after stop
*
* @return result
* - 0 Success
* - Other Fail
*/
int clint_timer_stop(void);
/**
* @brief Start the CLINT timer
*
* @param[in] interval The interval with Millisecond(ms)
* @param[in] single_shot Single shot or repeat
*
* @return result
* - 0 Success
* - Other Fail
*/
int clint_timer_start(uint64_t interval, int single_shot);
/**
* @brief Get the interval of timer
*
* @return The interval with Millisecond(ms)
*/
uint64_t clint_timer_get_interval(void);
/**
* @brief Set the interval with Millisecond(ms)
*
* @param[in] interval The interval with Millisecond(ms)
*
* @return result
* - 0 Success
* - Other Fail
*/
int clint_timer_set_interval(uint64_t interval);
/**
* @brief Get whether the timer is a single shot timer
*
* @return result
* - 0 It is a repeat timer
* - 1 It is a single shot timer
*/
int clint_timer_get_single_shot(void);
/**
* @brief Set the timer working as a single shot timer or repeat timer
*
* @param[in] single_shot Single shot or repeat
*
* @return result
* - 0 Success
* - Other Fail
*/
int clint_timer_set_single_shot(int single_shot);
/**
* @brief Set user callback function when timer is timeout
*
* @param[in] callback The callback function
* @param[in] ctx The context
*
* @return result
* - 0 Success
* - Other Fail
*/
int clint_timer_register(clint_timer_callback_t callback, void *ctx);
/**
* @brief Deregister user callback function
*
* @return result
* - 0 Success
* - Other Fail
*/
int clint_timer_unregister(void);
/**
* @brief Initialize local interprocessor interrupt
*
* @return result
* - 0 Success
* - Other Fail
*/
int clint_ipi_init(void);
/**
* @brief Enable local interprocessor interrupt
*
* @return result
* - 0 Success
* - Other Fail
*/
int clint_ipi_enable(void);
/**
* @brief Disable local interprocessor interrupt
*
* @return result
* - 0 Success
* - Other Fail
*/
int clint_ipi_disable(void);
/**
* @brief Send local interprocessor interrupt to core by core id
*
* @param[in] core_id The core identifier
*
* @return result
* - 0 Success
* - Other Fail
*/
int clint_ipi_send(size_t core_id);
/**
* @brief Clear local interprocessor interrupt
*
* @param[in] core_id The core identifier
*
* @return result
* - 1 An IPI was pending
* - 0 Non IPI was pending
* - -1 Fail
*/
int clint_ipi_clear(size_t core_id);
/**
* @brief Set user callback function when interprocessor interrupt
*
* @param[in] callback The callback function
* @param[in] ctx The context
*
* @return result
* - 0 Success
* - Other Fail
*/
int clint_ipi_register(clint_ipi_callback_t callback, void *ctx);
/**
* @brief Deregister user callback function
*
* @return result
* - 0 Success
* - Other Fail
*/
int clint_ipi_unregister(void);
#ifdef __cplusplus
}
#endif
#endif /* __CLINT_H__ */
@@ -0,0 +1,40 @@
/*
* 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_uart.h
* @brief define kd233-board uart function and struct
* @version 1.0
* @author AIIT XUOS Lab
* @date 2021-04-25
*/
#ifndef CONNECT_UART_H
#define CONNECT_UART_H
#include <device.h>
#ifdef __cplusplus
extern "C" {
#endif
#define KERNEL_CONSOLE_BUS_NAME SERIAL_BUS_NAME_0
#define KERNEL_CONSOLE_DRV_NAME SERIAL_DRV_NAME_0
#define KERNEL_CONSOLE_DEVICE_NAME SERIAL_0_DEVICE_NAME_0
int HwUartInit(void);
#ifdef __cplusplus
}
#endif
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,364 @@
/* 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
* @brief Universal Asynchronous Receiver/Transmitter (UART)
*
* The UART peripheral supports the following features:
*
* - 8-N-1 and 8-N-2 formats: 8 data bits, no parity bit, 1 start
* bit, 1 or 2 stop bits
*
* - 8-entry transmit and receive FIFO buffers with programmable
* watermark interrupts
*
* - 16× Rx oversampling with 2/3 majority voting per bit
*
* The UART peripheral does not support hardware flow control or
* other modem control signals, or synchronous serial data
* tranfesrs.
*
*
*/
/**
* @file hardware_uart.h
* @brief add from Canaan k210 SDK
* https://canaan-creative.com/developer
* @version 1.0
* @author AIIT XUOS Lab
* @date 2021-04-25
*/
#ifndef __HARDWARE_UART_H__
#define __HARDWARE_UART_H__
#include <stdint.h>
#include "platform.h"
#include "plic.h"
#include "dmac.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef enum _uart_dev
{
UART_DEV1 = 0,
UART_DEV2,
UART_DEV3,
} uart_dev_t;
typedef struct _uart
{
union
{
volatile uint32_t RBR;
volatile uint32_t DLL;
volatile uint32_t THR;
};
union
{
volatile uint32_t DLH;
volatile uint32_t IER;
};
union
{
volatile uint32_t FCR;
volatile uint32_t IIR;
};
volatile uint32_t LCR;
volatile uint32_t MCR;
volatile uint32_t LSR;
volatile uint32_t MSR;
volatile uint32_t SCR;
volatile uint32_t LPDLL;
volatile uint32_t LPDLH;
volatile uint32_t reserved1[2];
union
{
volatile uint32_t SRBR[16];
volatile uint32_t STHR[16];
};
volatile uint32_t FAR;
volatile uint32_t TFR;
volatile uint32_t RFW;
volatile uint32_t USR;
volatile uint32_t TFL;
volatile uint32_t RFL;
volatile uint32_t SRR;
volatile uint32_t SRTS;
volatile uint32_t SBCR;
volatile uint32_t SDMAM;
volatile uint32_t SFE;
volatile uint32_t SRT;
volatile uint32_t STET;
volatile uint32_t HTX;
volatile uint32_t DMASA;
volatile uint32_t TCR;
volatile uint32_t DE_EN;
volatile uint32_t RE_EN;
volatile uint32_t DET;
volatile uint32_t TAT;
volatile uint32_t DLF;
volatile uint32_t RAR;
volatile uint32_t TAR;
volatile uint32_t LCR_EXT;
volatile uint32_t reserved2[9];
volatile uint32_t CPR;
volatile uint32_t UCV;
volatile uint32_t CTR;
} UartT;
typedef enum _uart_device_number
{
UART_DEVICE_1,
UART_DEVICE_2,
UART_DEVICE_3,
UART_DEVICE_MAX,
} UartDeviceNumberT;
typedef enum _uart_bitwidth
{
UART_BITWIDTH_5BIT = 5,
UART_BITWIDTH_6BIT,
UART_BITWIDTH_7BIT,
UART_BITWIDTH_8BIT,
} UartBitwidthPointer;
typedef enum _uart_stopbit
{
UART_STOP_1,
UART_STOP_1_5,
UART_STOP_2
} UartStopbitT;
typedef enum _uart_rede_sel
{
DISABLE = 0,
ENABLE,
} uart_rede_sel_t;
typedef enum _uart_parity
{
UART_PARITY_NONE,
UART_PARITY_ODD,
UART_PARITY_EVEN
} UartParityT;
typedef enum _uart_interrupt_mode
{
UART_SEND = 1,
UART_RECEIVE = 2,
} UartInterruptModeT;
typedef enum _uart_send_trigger
{
UART_SEND_FIFO_0,
UART_SEND_FIFO_2,
UART_SEND_FIFO_4,
UART_SEND_FIFO_8,
} uart_send_trigger_t;
typedef enum _uart_receive_trigger
{
UART_RECEIVE_FIFO_1,
UART_RECEIVE_FIFO_4,
UART_RECEIVE_FIFO_8,
UART_RECEIVE_FIFO_14,
} uart_receive_trigger_t;
typedef struct _uart_data_t
{
dmac_channel_number_t tx_channel;
dmac_channel_number_t rx_channel;
uint32_t *tx_buf;
size_t tx_len;
uint32_t *rx_buf;
size_t rx_len;
UartInterruptModeT TransferMode;
} uart_data_t;
/**
* @brief Send data from uart
*
* @param[in] channel Uart index
* @param[in] buffer The data be transfer
* @param[in] len The data length
*
* @return Transfer length
*/
int UartSendData(UartDeviceNumberT channel, const char *buffer, size_t BufLen);
/**
* @brief Read data from uart
*
* @param[in] channel Uart index
* @param[in] buffer The Data received
* @param[in] len Receive length
*
* @return Receive length
*/
int UartReceiveData(UartDeviceNumberT channel, char *buffer, size_t BufLen);
/**
* @brief Init uart
*
* @param[in] channel Uart index
*
*/
void UartInit(UartDeviceNumberT channel);
/**
* @brief Set uart param
*
* @param[in] channel Uart index
* @param[in] BaudRate Baudrate
* @param[in] DataWidth Data width
* @param[in] stopbit Stop bit
* @param[in] parity Odd Even parity
*
*/
void uart_config(UartDeviceNumberT channel, uint32_t BaudRate, UartBitwidthPointer DataWidth, UartStopbitT stopbit, UartParityT parity);
/**
* @brief Set uart param
*
* @param[in] channel Uart index
* @param[in] BaudRate Baudrate
* @param[in] DataWidth Data width
* @param[in] stopbit Stop bit
* @param[in] parity Odd Even parity
*
*/
void uart_configure(UartDeviceNumberT channel, uint32_t BaudRate, UartBitwidthPointer DataWidth, UartStopbitT stopbit, UartParityT parity);
/**
* @brief Register uart interrupt
*
* @param[in] channel Uart index
* @param[in] interrupt_mode Interrupt Mode receive or send
* @param[in] uart_callback Call back
* @param[in] ctx Param of call back
* @param[in] priority Interrupt priority
*
*/
void uart_irq_register(UartDeviceNumberT channel, UartInterruptModeT interrupt_mode, plic_irq_callback_t uart_callback, void *ctx, uint32_t priority);
/**
* @brief Deregister uart interrupt
*
* @param[in] channel Uart index
* @param[in] interrupt_mode Interrupt Mode receive or send
*
*/
void uart_irq_unregister(UartDeviceNumberT channel, UartInterruptModeT interrupt_mode);
/**
* @brief Set send interrupt threshold
*
* @param[in] channel Uart index
* @param[in] trigger Threshold of send interrupt
*
*/
void UartSetSendTrigger(UartDeviceNumberT channel, uart_send_trigger_t trigger);
/**
* @brief Set receive interrupt threshold
*
* @param[in] channel Uart index
* @param[in] trigger Threshold of receive interrupt
*
*/
void uart_set_receive_trigger(UartDeviceNumberT channel, uart_receive_trigger_t trigger);
/**
* @brief Send data by dma
*
* @param[in] channel Uart index
* @param[in] dmac_channel Dmac channel
* @param[in] buffer Send data
* @param[in] BufLen Data length
*
*/
void UartSendDataDma(UartDeviceNumberT uart_channel, dmac_channel_number_t dmac_channel, const uint8_t *buffer, size_t BufLen);
/**
* @brief Receive data by dma
*
* @param[in] channel Uart index
* @param[in] dmac_channel Dmac channel
* @param[in] buffer Receive data
* @param[in] BufLen Data length
*
*/
void UartReceiveDataDma(UartDeviceNumberT uart_channel, dmac_channel_number_t dmac_channel, uint8_t *buffer, size_t BufLen);
/**
* @brief Send data by dma
*
* @param[in] uart_channel Uart index
* @param[in] dmac_channel Dmac channel
* @param[in] buffer Send data
* @param[in] BufLen Data length
* @param[in] uart_callback Call back
* @param[in] ctx Param of call back
* @param[in] priority Interrupt priority
*
*/
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);
/**
* @brief Receive data by dma
*
* @param[in] uart_channel Uart index
* @param[in] dmac_channel Dmac channel
* @param[in] buffer Receive data
* @param[in] BufLen Data length
* @param[in] uart_callback Call back
* @param[in] ctx Param of call back
* @param[in] priority Interrupt priority
*
*/
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);
/**
* @brief Uart handle transfer data operations
*
* @param[in] uart_channel Uart index
* @param[in] data Uart data information
* @param[in] buffer Uart DMA callback
*
*/
void uart_handle_data_dma(UartDeviceNumberT uart_channel ,uart_data_t data, plic_interrupt_t *cb);
#ifdef __cplusplus
}
#endif
#endif /* __UART_H__ */
@@ -0,0 +1,302 @@
/* 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
* @brief Universal Asynchronous Receiver/Transmitter (UART)
*
* The UART peripheral supports the following features:
*
* - 8-N-1 and 8-N-2 formats: 8 data bits, no parity bit, 1 start
* bit, 1 or 2 stop bits
*
* - 8-entry transmit and receive FIFO buffers with programmable
* watermark interrupts
*
* - 16× Rx oversampling with 2/3 majority voting per bit
*
* The UART peripheral does not support hardware flow control or
* other modem control signals, or synchronous serial data
* tranfesrs.
*
* @note UART RAM Layout
*
* | Address | Name | Description |
* |-----------|----------|---------------------------------|
* | 0x000 | txdata | Transmit data register |
* | 0x004 | rxdata | Receive data register |
* | 0x008 | txctrl | Transmit control register |
* | 0x00C | rxctrl | Receive control register |
* | 0x010 | ie | UART interrupt enable |
* | 0x014 | ip | UART Interrupt pending |
* | 0x018 | div | Baud rate divisor |
*
*/
/**
* @file hardware_uarths.h
* @brief add from Canaan k210 SDK
* https://canaan-creative.com/developer
* @version 1.0
* @author AIIT XUOS Lab
* @date 2021-04-25
*/
#ifndef __HARDWARE_UARTHS_H__
#define __HARDWARE_UARTHS_H__
#include <stddef.h>
#include <stdint.h>
#include "platform.h"
#include "plic.h"
#ifdef __cplusplus
extern "C" {
#endif
/* clang-format off */
/* Register address offsets */
#define UARTHS_REG_TXFIFO (0x00)
#define UARTHS_REG_RXFIFO (0x04)
#define UARTHS_REG_TXCTRL (0x08)
#define UARTHS_REG_RXCTRL (0x0c)
#define UARTHS_REG_IE (0x10)
#define UARTHS_REG_IP (0x14)
#define UARTHS_REG_DIV (0x18)
/* TXCTRL register */
#define UARTHS_TXEN (0x01)
#define UARTHS_TXWM(x) (((x) & 0xffff) << 16)
/* RXCTRL register */
#define UARTHS_RXEN (0x01)
#define UARTHS_RXWM(x) (((x) & 0xffff) << 16)
/* IP register */
#define UARTHS_IP_TXWM (0x01)
#define UARTHS_IP_RXWM (0x02)
/* clang-format on */
typedef struct _uarths_txdata
{
/* Bits [7:0] is data */
uint32_t data : 8;
/* Bits [30:8] is 0 */
uint32_t zero : 23;
/* Bit 31 is full status */
uint32_t full : 1;
} __attribute__((packed, aligned(4))) uarths_txdata_t;
typedef struct _uarths_rxdata
{
/* Bits [7:0] is data */
uint32_t data : 8;
/* Bits [30:8] is 0 */
uint32_t zero : 23;
/* Bit 31 is empty status */
uint32_t empty : 1;
} __attribute__((packed, aligned(4))) uarths_rxdata_t;
typedef struct _uarths_txctrl
{
/* Bit 0 is txen, controls whether the Tx channel is active. */
uint32_t txen : 1;
/* Bit 1 is nstop, 0 for one stop bit and 1 for two stop bits */
uint32_t nstop : 1;
/* Bits [15:2] is reserved */
uint32_t resv0 : 14;
/* Bits [18:16] is threshold of interrupt triggers */
uint32_t txcnt : 3;
/* Bits [31:19] is reserved */
uint32_t resv1 : 13;
} __attribute__((packed, aligned(4))) uarths_txctrl_t;
typedef struct _uarths_rxctrl
{
/* Bit 0 is txen, controls whether the Tx channel is active. */
uint32_t rxen : 1;
/* Bits [15:1] is reserved */
uint32_t resv0 : 15;
/* Bits [18:16] is threshold of interrupt triggers */
uint32_t rxcnt : 3;
/* Bits [31:19] is reserved */
uint32_t resv1 : 13;
} __attribute__((packed, aligned(4))) uarths_rxctrl_t;
typedef struct _uarths_ip
{
/* Bit 0 is txwm, raised less than txcnt */
uint32_t txwm : 1;
/* Bit 1 is txwm, raised greater than rxcnt */
uint32_t rxwm : 1;
/* Bits [31:2] is 0 */
uint32_t zero : 30;
} __attribute__((packed, aligned(4))) uarths_ip_t;
typedef struct _uarths_ie
{
/* Bit 0 is txwm, raised less than txcnt */
uint32_t txwm : 1;
/* Bit 1 is txwm, raised greater than rxcnt */
uint32_t rxwm : 1;
/* Bits [31:2] is 0 */
uint32_t zero : 30;
} __attribute__((packed, aligned(4))) uarths_ie_t;
typedef struct _uarths_div
{
/* Bits [31:2] is baud rate divisor register */
uint32_t div : 16;
/* Bits [31:16] is 0 */
uint32_t zero : 16;
} __attribute__((packed, aligned(4))) uarths_div_t;
typedef struct _uarths
{
/* Address offset 0x00 */
uarths_txdata_t txdata;
/* Address offset 0x04 */
uarths_rxdata_t rxdata;
/* Address offset 0x08 */
uarths_txctrl_t txctrl;
/* Address offset 0x0c */
uarths_rxctrl_t rxctrl;
/* Address offset 0x10 */
uarths_ie_t ie;
/* Address offset 0x14 */
uarths_ip_t ip;
/* Address offset 0x18 */
uarths_div_t div;
} __attribute__((packed, aligned(4))) UarthsT;
typedef enum _uarths_interrupt_mode
{
UARTHS_SEND = 1,
UARTHS_RECEIVE = 2,
UARTHS_SEND_RECEIVE = 3,
} uarths_interrupt_mode_t;
typedef enum _uarths_stopbit
{
UARTHS_STOP_1,
UARTHS_STOP_2
} uarths_stopbit_t;
extern volatile UarthsT *const uarths;
/**
* @brief Initialization Core UART
*
* @return result
* - 0 Success
* - Other Fail
*/
void uarths_init(void);
/**
* @brief Put a char to UART
*
* @param[in] c The char to put
*
* @note If c is '\n', a '\r' will be appended automatically
*
* @return result
* - 0 Success
* - Other Fail
*/
int uarths_putchar(char c);
/**
* @brief Send a string to UART
*
* @param[in] s The string to send
*
* @note The string must ending with '\0'
*
* @return result
* - 0 Success
* - Other Fail
*/
int uarths_puts(const char *s);
/**
* @brief Get a byte from UART
*
* @return byte as int type from UART
*/
int uarths_getc(void);
/**
* @brief Set uarths interrupt callback
*
* @param[in] interrupt_mode Interrupt mode recevice or send
* @param[in] uarths_callback Interrupt callback
* @param[in] ctx Param of callback
* @param[in] priority Interrupt priority
*
*/
void uarths_set_irq(uarths_interrupt_mode_t interrupt_mode, plic_irq_callback_t uarths_callback, void *ctx, uint32_t priority);
/**
* @brief Uarths receive data
*
* @param[in] buf The data received
* @param[in] BufLen The length of data
*
* @return Number of received data
*/
size_t uarths_receive_data(uint8_t *buf, size_t BufLen);
/**
* @brief Uarths receive data
*
* @param[in] buf The data sended
* @param[in] BufLen The length of data
*
* @return Number of sended data
*/
size_t uarths_send_data(const uint8_t *buf, size_t BufLen);
/**
* @brief Get interrupt mode
*
* @return Mode of interrupt
*/
uarths_interrupt_mode_t uarths_get_interrupt_mode(void);
/**
* @brief Set uarths baud rate and stopbit
*
* @param[in] BaudRate The baud rate
* @param[in] stopbit The stopbit of data
*
*/
void uarths_config(uint32_t BaudRate, uarths_stopbit_t stopbit);
/**
* @brief Set uart interrupt condition
*
* @param[in] interrupt_mode The interrupt mode
* @param[in] cnt The count of tigger
*
*/
void uarths_set_interrupt_cnt(uarths_interrupt_mode_t interrupt_mode, uint8_t cnt);
#ifdef __cplusplus
}
#endif
#endif /* __UARTHS_H__ */
@@ -0,0 +1,60 @@
/* 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 io.h
* @brief add from Canaan k210 SDK
* https://canaan-creative.com/developer
* @version 1.0
* @author AIIT XUOS Lab
* @date 2021-04-25
*/
#ifndef __IO_H__
#define __IO_H__
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
#define readb(addr) (*(volatile uint8_t *)(addr))
#define readw(addr) (*(volatile uint16_t *)(addr))
#define readl(addr) (*(volatile uint32_t *)(addr))
#define readq(addr) (*(volatile uint64_t *)(addr))
#define writeb(v, addr) \
{ \
(*(volatile uint8_t *)(addr)) = (v); \
}
#define writew(v, addr) \
{ \
(*(volatile uint16_t *)(addr)) = (v); \
}
#define writel(v, addr) \
{ \
(*(volatile uint32_t *)(addr)) = (v); \
}
#define writeq(v, addr) \
{ \
(*(volatile uint64_t *)(addr)) = (v); \
}
#ifdef __cplusplus
}
#endif
#endif /* __IO_H__ */
@@ -0,0 +1,467 @@
/* 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 plic.h
* @brief add from Canaan k210 SDK
* https://canaan-creative.com/developer
* @version 1.0
* @author AIIT XUOS Lab
* @date 2021-04-25
*/
#ifndef __PLIC_H__
#define __PLIC_H__
#include <stdint.h>
#include "encoding.h"
#include "platform.h"
/* For c++ compatibility */
#ifdef __cplusplus
extern "C" {
#endif
/* clang-format off */
/* IRQ number settings */
#define PLIC_NUM_SOURCES (IRQN_MAX - 1)
#define PLIC_NUM_PRIORITIES (7)
/* Real number of cores */
#define PLIC_NUM_CORES (2)
/* clang-format on */
/**
* @brief PLIC External Interrupt Numbers
*
* @note PLIC interrupt sources
*
* | Source | Name | Description |
* |--------|--------------------------|------------------------------------|
* | 0 | IRQN_NO_INTERRUPT | The non-existent interrupt |
* | 1 | IRQN_SPI0_INTERRUPT | SPI0 interrupt |
* | 2 | IRQN_SPI1_INTERRUPT | SPI1 interrupt |
* | 3 | IRQN_SPI_SLAVE_INTERRUPT | SPI_SLAVE interrupt |
* | 4 | IRQN_SPI3_INTERRUPT | SPI3 interrupt |
* | 5 | IRQN_I2S0_INTERRUPT | I2S0 interrupt |
* | 6 | IRQN_I2S1_INTERRUPT | I2S1 interrupt |
* | 7 | IRQN_I2S2_INTERRUPT | I2S2 interrupt |
* | 8 | IRQN_I2C0_INTERRUPT | I2C0 interrupt |
* | 9 | IRQN_I2C1_INTERRUPT | I2C1 interrupt |
* | 10 | IRQN_I2C2_INTERRUPT | I2C2 interrupt |
* | 11 | IRQN_UART1_INTERRUPT | UART1 interrupt |
* | 12 | IRQN_UART2_INTERRUPT | UART2 interrupt |
* | 13 | IRQN_UART3_INTERRUPT | UART3 interrupt |
* | 14 | IRQN_TIMER0A_INTERRUPT | TIMER0 channel 0 or 1 interrupt |
* | 15 | IRQN_TIMER0B_INTERRUPT | TIMER0 channel 2 or 3 interrupt |
* | 16 | IRQN_TIMER1A_INTERRUPT | TIMER1 channel 0 or 1 interrupt |
* | 17 | IRQN_TIMER1B_INTERRUPT | TIMER1 channel 2 or 3 interrupt |
* | 18 | IRQN_TIMER2A_INTERRUPT | TIMER2 channel 0 or 1 interrupt |
* | 19 | IRQN_TIMER2B_INTERRUPT | TIMER2 channel 2 or 3 interrupt |
* | 20 | IRQN_RTC_INTERRUPT | RTC tick and alarm interrupt |
* | 21 | IRQN_WDT0_INTERRUPT | Watching dog timer0 interrupt |
* | 22 | IRQN_WDT1_INTERRUPT | Watching dog timer1 interrupt |
* | 23 | IRQN_APB_GPIO_INTERRUPT | APB GPIO interrupt |
* | 24 | IRQN_DVP_INTERRUPT | Digital video port interrupt |
* | 25 | IRQN_AI_INTERRUPT | AI accelerator interrupt |
* | 26 | IRQN_FFT_INTERRUPT | FFT accelerator interrupt |
* | 27 | IRQN_DMA0_INTERRUPT | DMA channel0 interrupt |
* | 28 | IRQN_DMA1_INTERRUPT | DMA channel1 interrupt |
* | 29 | IRQN_DMA2_INTERRUPT | DMA channel2 interrupt |
* | 30 | IRQN_DMA3_INTERRUPT | DMA channel3 interrupt |
* | 31 | IRQN_DMA4_INTERRUPT | DMA channel4 interrupt |
* | 32 | IRQN_DMA5_INTERRUPT | DMA channel5 interrupt |
* | 33 | IRQN_UARTHS_INTERRUPT | Hi-speed UART0 interrupt |
* | 34 | IRQN_GPIOHS0_INTERRUPT | Hi-speed GPIO0 interrupt |
* | 35 | IRQN_GPIOHS1_INTERRUPT | Hi-speed GPIO1 interrupt |
* | 36 | IRQN_GPIOHS2_INTERRUPT | Hi-speed GPIO2 interrupt |
* | 37 | IRQN_GPIOHS3_INTERRUPT | Hi-speed GPIO3 interrupt |
* | 38 | IRQN_GPIOHS4_INTERRUPT | Hi-speed GPIO4 interrupt |
* | 39 | IRQN_GPIOHS5_INTERRUPT | Hi-speed GPIO5 interrupt |
* | 40 | IRQN_GPIOHS6_INTERRUPT | Hi-speed GPIO6 interrupt |
* | 41 | IRQN_GPIOHS7_INTERRUPT | Hi-speed GPIO7 interrupt |
* | 42 | IRQN_GPIOHS8_INTERRUPT | Hi-speed GPIO8 interrupt |
* | 43 | IRQN_GPIOHS9_INTERRUPT | Hi-speed GPIO9 interrupt |
* | 44 | IRQN_GPIOHS10_INTERRUPT | Hi-speed GPIO10 interrupt |
* | 45 | IRQN_GPIOHS11_INTERRUPT | Hi-speed GPIO11 interrupt |
* | 46 | IRQN_GPIOHS12_INTERRUPT | Hi-speed GPIO12 interrupt |
* | 47 | IRQN_GPIOHS13_INTERRUPT | Hi-speed GPIO13 interrupt |
* | 48 | IRQN_GPIOHS14_INTERRUPT | Hi-speed GPIO14 interrupt |
* | 49 | IRQN_GPIOHS15_INTERRUPT | Hi-speed GPIO15 interrupt |
* | 50 | IRQN_GPIOHS16_INTERRUPT | Hi-speed GPIO16 interrupt |
* | 51 | IRQN_GPIOHS17_INTERRUPT | Hi-speed GPIO17 interrupt |
* | 52 | IRQN_GPIOHS18_INTERRUPT | Hi-speed GPIO18 interrupt |
* | 53 | IRQN_GPIOHS19_INTERRUPT | Hi-speed GPIO19 interrupt |
* | 54 | IRQN_GPIOHS20_INTERRUPT | Hi-speed GPIO20 interrupt |
* | 55 | IRQN_GPIOHS21_INTERRUPT | Hi-speed GPIO21 interrupt |
* | 56 | IRQN_GPIOHS22_INTERRUPT | Hi-speed GPIO22 interrupt |
* | 57 | IRQN_GPIOHS23_INTERRUPT | Hi-speed GPIO23 interrupt |
* | 58 | IRQN_GPIOHS24_INTERRUPT | Hi-speed GPIO24 interrupt |
* | 59 | IRQN_GPIOHS25_INTERRUPT | Hi-speed GPIO25 interrupt |
* | 60 | IRQN_GPIOHS26_INTERRUPT | Hi-speed GPIO26 interrupt |
* | 61 | IRQN_GPIOHS27_INTERRUPT | Hi-speed GPIO27 interrupt |
* | 62 | IRQN_GPIOHS28_INTERRUPT | Hi-speed GPIO28 interrupt |
* | 63 | IRQN_GPIOHS29_INTERRUPT | Hi-speed GPIO29 interrupt |
* | 64 | IRQN_GPIOHS30_INTERRUPT | Hi-speed GPIO30 interrupt |
* | 65 | IRQN_GPIOHS31_INTERRUPT | Hi-speed GPIO31 interrupt |
*
*/
/* clang-format off */
typedef enum _plic_irq
{
IRQN_NO_INTERRUPT = 0, /*!< The non-existent interrupt */
IRQN_SPI0_INTERRUPT = 1, /*!< SPI0 interrupt */
IRQN_SPI1_INTERRUPT = 2, /*!< SPI1 interrupt */
IRQN_SPI_SLAVE_INTERRUPT = 3, /*!< SPI_SLAVE interrupt */
IRQN_SPI3_INTERRUPT = 4, /*!< SPI3 interrupt */
IRQN_I2S0_INTERRUPT = 5, /*!< I2S0 interrupt */
IRQN_I2S1_INTERRUPT = 6, /*!< I2S1 interrupt */
IRQN_I2S2_INTERRUPT = 7, /*!< I2S2 interrupt */
IRQN_I2C0_INTERRUPT = 8, /*!< I2C0 interrupt */
IRQN_I2C1_INTERRUPT = 9, /*!< I2C1 interrupt */
IRQN_I2C2_INTERRUPT = 10, /*!< I2C2 interrupt */
IRQN_UART1_INTERRUPT = 11, /*!< UART1 interrupt */
IRQN_UART2_INTERRUPT = 12, /*!< UART2 interrupt */
IRQN_UART3_INTERRUPT = 13, /*!< UART3 interrupt */
IRQN_TIMER0A_INTERRUPT = 14, /*!< TIMER0 channel 0 or 1 interrupt */
IRQN_TIMER0B_INTERRUPT = 15, /*!< TIMER0 channel 2 or 3 interrupt */
IRQN_TIMER1A_INTERRUPT = 16, /*!< TIMER1 channel 0 or 1 interrupt */
IRQN_TIMER1B_INTERRUPT = 17, /*!< TIMER1 channel 2 or 3 interrupt */
IRQN_TIMER2A_INTERRUPT = 18, /*!< TIMER2 channel 0 or 1 interrupt */
IRQN_TIMER2B_INTERRUPT = 19, /*!< TIMER2 channel 2 or 3 interrupt */
IRQN_RTC_INTERRUPT = 20, /*!< RTC tick and alarm interrupt */
IRQN_WDT0_INTERRUPT = 21, /*!< Watching dog timer0 interrupt */
IRQN_WDT1_INTERRUPT = 22, /*!< Watching dog timer1 interrupt */
IRQN_APB_GPIO_INTERRUPT = 23, /*!< APB GPIO interrupt */
IRQN_DVP_INTERRUPT = 24, /*!< Digital video port interrupt */
IRQN_AI_INTERRUPT = 25, /*!< AI accelerator interrupt */
IRQN_FFT_INTERRUPT = 26, /*!< FFT accelerator interrupt */
IRQN_DMA0_INTERRUPT = 27, /*!< DMA channel0 interrupt */
IRQN_DMA1_INTERRUPT = 28, /*!< DMA channel1 interrupt */
IRQN_DMA2_INTERRUPT = 29, /*!< DMA channel2 interrupt */
IRQN_DMA3_INTERRUPT = 30, /*!< DMA channel3 interrupt */
IRQN_DMA4_INTERRUPT = 31, /*!< DMA channel4 interrupt */
IRQN_DMA5_INTERRUPT = 32, /*!< DMA channel5 interrupt */
IRQN_UARTHS_INTERRUPT = 33, /*!< Hi-speed UART0 interrupt */
IRQN_GPIOHS0_INTERRUPT = 34, /*!< Hi-speed GPIO0 interrupt */
IRQN_GPIOHS1_INTERRUPT = 35, /*!< Hi-speed GPIO1 interrupt */
IRQN_GPIOHS2_INTERRUPT = 36, /*!< Hi-speed GPIO2 interrupt */
IRQN_GPIOHS3_INTERRUPT = 37, /*!< Hi-speed GPIO3 interrupt */
IRQN_GPIOHS4_INTERRUPT = 38, /*!< Hi-speed GPIO4 interrupt */
IRQN_GPIOHS5_INTERRUPT = 39, /*!< Hi-speed GPIO5 interrupt */
IRQN_GPIOHS6_INTERRUPT = 40, /*!< Hi-speed GPIO6 interrupt */
IRQN_GPIOHS7_INTERRUPT = 41, /*!< Hi-speed GPIO7 interrupt */
IRQN_GPIOHS8_INTERRUPT = 42, /*!< Hi-speed GPIO8 interrupt */
IRQN_GPIOHS9_INTERRUPT = 43, /*!< Hi-speed GPIO9 interrupt */
IRQN_GPIOHS10_INTERRUPT = 44, /*!< Hi-speed GPIO10 interrupt */
IRQN_GPIOHS11_INTERRUPT = 45, /*!< Hi-speed GPIO11 interrupt */
IRQN_GPIOHS12_INTERRUPT = 46, /*!< Hi-speed GPIO12 interrupt */
IRQN_GPIOHS13_INTERRUPT = 47, /*!< Hi-speed GPIO13 interrupt */
IRQN_GPIOHS14_INTERRUPT = 48, /*!< Hi-speed GPIO14 interrupt */
IRQN_GPIOHS15_INTERRUPT = 49, /*!< Hi-speed GPIO15 interrupt */
IRQN_GPIOHS16_INTERRUPT = 50, /*!< Hi-speed GPIO16 interrupt */
IRQN_GPIOHS17_INTERRUPT = 51, /*!< Hi-speed GPIO17 interrupt */
IRQN_GPIOHS18_INTERRUPT = 52, /*!< Hi-speed GPIO18 interrupt */
IRQN_GPIOHS19_INTERRUPT = 53, /*!< Hi-speed GPIO19 interrupt */
IRQN_GPIOHS20_INTERRUPT = 54, /*!< Hi-speed GPIO20 interrupt */
IRQN_GPIOHS21_INTERRUPT = 55, /*!< Hi-speed GPIO21 interrupt */
IRQN_GPIOHS22_INTERRUPT = 56, /*!< Hi-speed GPIO22 interrupt */
IRQN_GPIOHS23_INTERRUPT = 57, /*!< Hi-speed GPIO23 interrupt */
IRQN_GPIOHS24_INTERRUPT = 58, /*!< Hi-speed GPIO24 interrupt */
IRQN_GPIOHS25_INTERRUPT = 59, /*!< Hi-speed GPIO25 interrupt */
IRQN_GPIOHS26_INTERRUPT = 60, /*!< Hi-speed GPIO26 interrupt */
IRQN_GPIOHS27_INTERRUPT = 61, /*!< Hi-speed GPIO27 interrupt */
IRQN_GPIOHS28_INTERRUPT = 62, /*!< Hi-speed GPIO28 interrupt */
IRQN_GPIOHS29_INTERRUPT = 63, /*!< Hi-speed GPIO29 interrupt */
IRQN_GPIOHS30_INTERRUPT = 64, /*!< Hi-speed GPIO30 interrupt */
IRQN_GPIOHS31_INTERRUPT = 65, /*!< Hi-speed GPIO31 interrupt */
IRQN_MAX
} plic_irq_t;
/* clang-format on */
/**
* @brief Interrupt Source Priorities
*
* Each external interrupt source can be assigned a priority by
* writing to its 32-bit memory-mapped priority register. The
* number and value of supported priority levels can vary by
* implementa- tion, with the simplest implementations having all
* devices hardwired at priority 1, in which case, interrupts with
* the lowest ID have the highest effective priority. The priority
* registers are all WARL.
*/
typedef struct _plic_source_priorities
{
/* 0x0C000000: Reserved, 0x0C000004-0x0C000FFC: 1-1023 priorities */
uint32_t priority[1024];
} __attribute__((packed, aligned(4))) plic_source_priorities_t;
/**
* @brief Interrupt Pending Bits
*
* The current status of the interrupt source pending bits in the
* PLIC core can be read from the pending array, organized as 32
* words of 32 bits. The pending bit for interrupt ID N is stored
* in bit (N mod 32) of word (N/32). Bit 0 of word 0, which
* represents the non-existent interrupt source 0, is always
* hardwired to zero. The pending bits are read-only. A pending
* bit in the PLIC core can be cleared by setting enable bits to
* only enable the desired interrupt, then performing a claim. A
* pending bit can be set by instructing the associated gateway to
* send an interrupt service request.
*/
typedef struct _plic_pending_bits
{
/* 0x0C001000-0x0C00107C: Bit 0 is zero, Bits 1-1023 is pending bits */
uint32_t u32[32];
/* 0x0C001080-0x0C001FFF: Reserved */
uint8_t resv[0xF80];
} __attribute__((packed, aligned(4))) plic_pending_bits_t;
/**
* @brief Target Interrupt Enables
*
* For each interrupt target, each devices interrupt can be
* enabled by setting the corresponding bit in that targets
* enables registers. The enables for a target are accessed as a
* contiguous array of 32×32-bit words, packed the same way as the
* pending bits. For each target, bit 0 of enable word 0
* represents the non-existent interrupt ID 0 and is hardwired to
* 0. Unused interrupt IDs are also hardwired to zero. The enables
* arrays for different targets are packed contiguously in the
* address space. Only 32-bit word accesses are supported by the
* enables array in RV32 systems. Implementations can trap on
* accesses to enables for non-existent targets, but must allow
* access to the full enables array for any extant target,
* treating all non-existent interrupt sources enables as
* hardwired to zero.
*/
typedef struct _plic_target_enables
{
/* 0x0C002000-0x0C1F1F80: target 0-15871 enables */
struct
{
uint32_t enable[32 * 2];/* Offset 0x00-0x7C: Bit 0 is zero, Bits 1-1023 is bits*/
} target[15872 / 2];
/* 0x0C1F2000-0x0C1FFFFC: Reserved, size 0xE000 */
uint8_t resv[0xE000];
} __attribute__((packed, aligned(4))) plic_target_enables_t;
/**
* @brief PLIC Targets
*
* Target Priority Thresholds The threshold for a pending
* interrupt priority that can interrupt each target can be set in
* the targets threshold register. The threshold is a WARL field,
* where different implementations can support different numbers
* of thresholds. The simplest implementation has a threshold
* hardwired to zero.
*
* Target Claim Each target can perform a claim by reading the
* claim/complete register, which returns the ID of the highest
* priority pending interrupt or zero if there is no pending
* interrupt for the target. A successful claim will also
* atomically clear the corresponding pending bit on the interrupt
* source. A target can perform a claim at any time, even if the
* EIP is not set. The claim operation is not affected by the
* setting of the targets priority threshold register.
*
* Target Completion A target signals it has completed running a
* handler by writing the interrupt ID it received from the claim
* to the claim/complete register. This is routed to the
* corresponding interrupt gateway, which can now send another
* interrupt request to the PLIC. The PLIC does not check whether
* the completion ID is the same as the last claim ID for that
* target. If the completion ID does not match an interrupt source
* that is currently enabled for the target, the completion is
* silently ignored.
*/
typedef struct _plic_target
{
/* 0x0C200000-0x0FFFF004: target 0-15871 */
struct {
uint32_t priority_threshold;/* Offset 0x000 */
uint32_t claim_complete; /* Offset 0x004 */
uint8_t resv[0x1FF8]; /* Offset 0x008, Size 0xFF8 */
} target[15872 / 2];
} __attribute__((packed, aligned(4))) plic_target_t;
/**
* @brief Platform-Level Interrupt Controller
*
* PLIC is Platform-Level Interrupt Controller. The PLIC complies
* with the RISC-V Privileged Architecture specification, and can
* support a maximum of 1023 external interrupt sources targeting
* up to 15,872 core contexts.
*/
typedef struct _plic
{
/* 0x0C000000-0x0C000FFC */
plic_source_priorities_t source_priorities;
/* 0x0C001000-0x0C001FFF */
const plic_pending_bits_t pending_bits;
/* 0x0C002000-0x0C1FFFFC */
plic_target_enables_t target_enables;
/* 0x0C200000-0x0FFFF004 */
plic_target_t targets;
} __attribute__((packed, aligned(4))) plic_t;
extern volatile plic_t *const plic;
/**
* @brief Definitions for the interrupt callbacks
*/
typedef int (*plic_irq_callback_t)(void *ctx);
/**
* @brief Definitions for IRQ table instance
*/
typedef struct _plic_instance_t
{
plic_irq_callback_t callback;
void *ctx;
} plic_instance_t;
typedef struct _plic_callback_t
{
plic_irq_callback_t callback;
void *ctx;
uint32_t priority;
} plic_interrupt_t;
/**
* @brief Initialize PLIC external interrupt
*
* @note This function will set MIP_MEIP. The MSTATUS_MIE must set by user.
*
* @return result
* - 0 Success
* - Other Fail
*/
void plic_init(void);
/**
* @brief Enable PLIC external interrupt
*
* @param[in] irq_number external interrupt number
*
* @return result
* - 0 Success
* - Other Fail
*/
int plic_irq_enable(plic_irq_t irq_number);
/**
* @brief Disable PLIC external interrupt
*
* @param[in] irq_number The external interrupt number
*
* @return result
* - 0 Success
* - Other Fail
*/
int plic_irq_disable(plic_irq_t irq_number);
/**
* @brief Set IRQ priority
*
* @param[in] irq_number The external interrupt number
* @param[in] priority The priority of external interrupt number
*
* @return result
* - 0 Success
* - Other Fail
*/
int plic_set_priority(plic_irq_t irq_number, uint32_t priority);
/**
* @brief Get IRQ priority
*
* @param[in] irq_number The external interrupt number
*
* @return The priority of external interrupt number
*/
uint32_t plic_get_priority(plic_irq_t irq_number);
/**
* @brief Claim an IRQ
*
* @return The current IRQ number
*/
uint32_t plic_irq_claim(void);
/**
* @brief Complete an IRQ
*
* @param[in] source The source IRQ number to complete
*
* @return result
* - 0 Success
* - Other Fail
*/
int plic_irq_complete(uint32_t source);
/**
* @brief Register user callback function by IRQ number
*
* @param[in] irq The irq
* @param[in] callback The callback
* @param ctx The context
*
* @return result
* - 0 Success
* - Other Fail
*/
void plic_irq_register(plic_irq_t irq, plic_irq_callback_t callback, void *ctx);
/**
* @brief Deegister user callback function by IRQ number
*
* @param[in] irq The irq
*
* @return result
* - 0 Success
* - Other Fail
*/
void plic_irq_deregister(plic_irq_t irq);
/**
* @brief Deegister user callback function by IRQ number
*
* @param[in] irq The irq
*
* @return result
* - 0 Success
* - Other Fail
*/
void plic_irq_unregister(plic_irq_t irq);
/**
* @brief Get IRQ table, Usage:
* plic_instance_t (*plic_instance)[IRQN_MAX] = plic_get_instance();
* ... plic_instance[x][y] ...;
*
* @return the point of IRQ table
*/
plic_instance_t (*plic_get_instance(void))[IRQN_MAX];
/* For c++ compatibility */
#ifdef __cplusplus
}
#endif
#endif /* __PLIC_H__ */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,357 @@
/* 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 utils.h
* @brief add from Canaan k210 SDK
* https://canaan-creative.com/developer
* @version 1.0
* @author AIIT XUOS Lab
* @date 2021-04-25
*/
#ifndef __UTILS_H__
#define __UTILS_H__
#ifdef __cplusplus
#include <cstdbool>
#include <cstddef>
#include <cstdint>
#else /* __cplusplus */
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#endif /* __cplusplus */
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
#define KENDRYTE_MIN(a, b) ((a) > (b) ? (b) : (a))
#define KENDRYTE_MAX(a, b) ((a) > (b) ? (a) : (b))
#ifdef __ASSEMBLY__
#define KENDRYTE_CAST(type, ptr) ptr
#else /* __ASSEMBLY__ */
/**
* @brief Cast the pointer to specified pointer type.
*
* @param[in] type The pointer type to cast to
* @param[in] ptr The pointer to apply the type cast to
*/
#define KENDRYTE_CAST(type, ptr) ((type)(ptr))
#endif /* __ASSEMBLY__ */
/**
* @addtogroup UTIL_RW_FUNC Memory Read/Write Utilities
*
* This section implements read and write functionality for various
* memory untis. The memory unit terms used for these functions are
* consistent with those used in the ARM Architecture Reference Manual
* ARMv7-A and ARMv7-R edition manual. The terms used for units of memory are:
*
* Unit of Memory | Abbreviation | Size in Bits
* :---------------|:-------------|:------------:
* Byte | byte | 8
* Half Word | hword | 16
* Word | word | 32
* Double Word | dword | 64
*
*/
/**
* @brief Write the 8 bit byte to the destination address in device memory.
*
* @param[in] dest Write destination pointer address
* @param[in] src 8 bit data byte to write to memory
*/
#define kendryte_write_byte(dest, src) \
(*KENDRYTE_CAST(volatile uint8_t*, (dest)) = (src))
/**
* @brief Read and return the 8 bit byte from the source address in device memory.
*
* @param[in] src Read source pointer address
*
* @return 8 bit data byte value
*/
#define kendryte_read_byte(src) (*KENDRYTE_CAST(volatile uint8_t*, (src)))
/**
* @brief Write the 16 bit half word to the destination address in device memory.
*
* @param[in] dest Write destination pointer address
* @param[in] src 16 bit data half word to write to memory
*/
#define kendryte_write_hword(dest, src) \
(*KENDRYTE_CAST(volatile uint16_t*, (dest)) = (src))
/**
* @brief Read and return the 16 bit half word from the source address in device
*
* @param[in] src Read source pointer address
*
* @return 16 bit data half word value
*/
#define kendryte_read_hword(src) (*KENDRYTE_CAST(volatile uint16_t*, (src)))
/**
* @brief Write the 32 bit word to the destination address in device memory.
*
* @param[in] dest Write destination pointer address
* @param[in] src 32 bit data word to write to memory
*/
#define kendryte_write_word(dest, src) \
(*KENDRYTE_CAST(volatile uint32_t*, (dest)) = (src))
/**
* @brief Read and return the 32 bit word from the source address in device memory.
*
* @param[in] src Read source pointer address
*
* @return 32 bit data half word value
*/
#define kendryte_read_word(src) (*KENDRYTE_CAST(volatile uint32_t*, (src)))
/**
* @brief Write the 64 bit double word to the destination address in device memory.
*
* @param[in] dest Write destination pointer address
* @param[in] src 64 bit data word to write to memory
*/
#define kendryte_write_dword(dest, src) \
(*KENDRYTE_CAST(volatile uint64_t*, (dest)) = (src))
/**
* @brief Read and return the 64 bit double word from the source address in device
*
* @param[in] src Read source pointer address
*
* @return 64 bit data half word value
*/
#define kendryte_read_dword(src) (*KENDRYTE_CAST(volatile uint64_t*, (src)))
/**
* @brief Set selected bits in the 8 bit byte at the destination address in device
*
* @param[in] dest Destination pointer address
* @param[in] bits Bits to set in destination byte
*/
#define kendryte_setbits_byte(dest, bits) \
(kendryte_write_byte(dest, kendryte_read_byte(dest) | (bits)))
/**
* @brief Clear selected bits in the 8 bit byte at the destination address in device
*
* @param[in] dest Destination pointer address
* @param[in] bits Bits to clear in destination byte
*/
#define kendryte_clrbits_byte(dest, bits) \
(kendryte_write_byte(dest, kendryte_read_byte(dest) & ~(bits)))
/**
* @brief Change or toggle selected bits in the 8 bit byte at the destination address
*
* @param[in] dest Destination pointer address
* @param[in] bits Bits to change in destination byte
*/
#define kendryte_xorbits_byte(dest, bits) \
(kendryte_write_byte(dest, kendryte_read_byte(dest) ^ (bits)))
/**
* @brief Replace selected bits in the 8 bit byte at the destination address in device
*
* @param[in] dest Destination pointer address
* @param[in] msk Bits to replace in destination byte
* @param[in] src Source bits to write to cleared bits in destination byte
*/
#define kendryte_replbits_byte(dest, msk, src) \
(kendryte_write_byte(dest, (kendryte_read_byte(dest) & ~(msk)) | ((src) & (msk))))
/**
* @brief Set selected bits in the 16 bit halfword at the destination address in
*
* @param[in] dest Destination pointer address
* @param[in] bits Bits to set in destination halfword
*/
#define kendryte_setbits_hword(dest, bits) \
(kendryte_write_hword(dest, kendryte_read_hword(dest) | (bits)))
/**
* @brief Clear selected bits in the 16 bit halfword at the destination address in
*
* @param[in] dest Destination pointer address
* @param[in] bits Bits to clear in destination halfword
*/
#define kendryte_clrbits_hword(dest, bits) \
(kendryte_write_hword(dest, kendryte_read_hword(dest) & ~(bits)))
/**
* @brief Change or toggle selected bits in the 16 bit halfword at the destination
*
* @param[in] dest Destination pointer address
* @param[in] bits Bits to change in destination halfword
*/
#define kendryte_xorbits_hword(dest, bits) \
(kendryte_write_hword(dest, kendryte_read_hword(dest) ^ (bits)))
/**
* @brief Replace selected bits in the 16 bit halfword at the destination address in
*
* @param[in] dest Destination pointer address
* @param[in] msk Bits to replace in destination byte
* @param[in] src Source bits to write to cleared bits in destination halfword
*/
#define kendryte_replbits_hword(dest, msk, src) \
(kendryte_write_hword(dest, (kendryte_read_hword(dest) & ~(msk)) | ((src) & (msk))))
/**
* @brief Set selected bits in the 32 bit word at the destination address in device
*
* @param[in] dest Destination pointer address
* @param[in] bits Bits to set in destination word
*/
#define kendryte_setbits_word(dest, bits) \
(kendryte_write_word(dest, kendryte_read_word(dest) | (bits)))
/**
* @brief Clear selected bits in the 32 bit word at the destination address in device
*
* @param[in] dest Destination pointer address
* @param[in] bits Bits to clear in destination word
*/
#define kendryte_clrbits_word(dest, bits) \
(kendryte_write_word(dest, kendryte_read_word(dest) & ~(bits)))
/**
* @brief Change or toggle selected bits in the 32 bit word at the destination address
*
* @param[in] dest Destination pointer address
* @param[in] bits Bits to change in destination word
*/
#define kendryte_xorbits_word(dest, bits) \
(kendryte_write_word(dest, kendryte_read_word(dest) ^ (bits)))
/**
* @brief Replace selected bits in the 32 bit word at the destination address in
*
* @param[in] dest Destination pointer address
* @param[in] msk Bits to replace in destination word
* @param[in] src Source bits to write to cleared bits in destination word
*/
#define kendryte_replbits_word(dest, msk, src) \
(kendryte_write_word(dest, (kendryte_read_word(dest) & ~(msk)) | ((src) & (msk))))
/**
* @brief Set selected bits in the 64 bit doubleword at the destination address in
*
* @param[in] dest Destination pointer address
* @param[in] bits Bits to set in destination doubleword
*/
#define kendryte_setbits_dword(dest, bits) \
(kendryte_write_dword(dest, kendryte_read_dword(dest) | (bits)))
/**
* @brief Clear selected bits in the 64 bit doubleword at the destination address in
*
* @param[in] dest Destination pointer address
* @param[in] bits Bits to clear in destination doubleword
*/
#define kendryte_clrbits_dword(dest, bits) \
(kendryte_write_dword(dest, kendryte_read_dword(dest) & ~(bits)))
/**
* @brief Change or toggle selected bits in the 64 bit doubleword at the destination
*
* @param[in] dest Destination pointer address
* @param[in] bits Bits to change in destination doubleword
*/
#define kendryte_xorbits_dword(dest, bits) \
(kendryte_write_dword(dest, kendryte_read_dword(dest) ^ (bits)))
/**
* @brief Replace selected bits in the 64 bit doubleword at the destination address in
*
* @param[in] dest Destination pointer address
* @param[in] msk its to replace in destination doubleword
* @param[in] src Source bits to write to cleared bits in destination word
*/
#define kendryte_replbits_dword(dest, msk, src) \
(kendryte_write_dword(dest, (kendryte_read_dword(dest) & ~(msk)) | ((src) & (msk))))
#define configASSERT(x) \
if ((x) == 0) \
{ \
printf("(%s:%d) %s\r\n", __FILE__, __LINE__, #x); \
for (;;) \
; \
}
/**
* @brief Set value by mask
*
* @param[in] bits The one be set
* @param[in] mask mask value
* @param[in] value The value to set
*/
void set_bit(volatile uint32_t *bits, uint32_t mask, uint32_t value);
/**
* @brief Set value by mask
*
* @param[in] bits The one be set
* @param[in] mask Mask value
* @param[in] offset Mask's offset
* @param[in] value The value to set
*/
void set_bit_offset(volatile uint32_t *bits, uint32_t mask, size_t offset, uint32_t value);
/**
* @brief Set bit for gpio, only set one bit
*
* @param[in] bits The one be set
* @param[in] idx Offset value
* @param[in] value The value to set
*/
void set_gpio_bit(volatile uint32_t *bits, size_t idx, uint32_t value);
/**
* @brief Get bits value of mask
*
* @param[in] bits The source data
* @param[in] mask Mask value
* @param[in] offset Mask's offset
*
* @return The bits value of mask
*/
uint32_t get_bit(volatile uint32_t *bits, uint32_t mask, size_t offset);
/**
* @brief Get a bit value by offset
*
* @param[in] bits The source data
* @param[in] offset Bit's offset
*
*
* @return The bit value
*/
uint32_t get_gpio_bit(volatile uint32_t *bits, size_t offset);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* _DRIVER_COMMON_H */
@@ -0,0 +1 @@
@@ -0,0 +1,5 @@
SRC_FILES := drv_interrupt.c plic.c clint.c
include $(KERNEL_ROOT)/compiler.mk
@@ -0,0 +1,229 @@
/* 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 clint.c
* @brief add from Canaan k210 SDK
* https://canaan-creative.com/developer
* @version 1.0
* @author AIIT XUOS Lab
* @date 2021-04-25
*/
#include <stddef.h>
#include <stdint.h>
#include "encoding.h"
#include "clint.h"
#include "sysctl.h"
volatile clint_t* const clint = (volatile clint_t*)CLINT_BASE_ADDR;
static clint_timer_instance_t clint_timer_instance[CLINT_NUM_CORES];
static clint_ipi_instance_t clint_ipi_instance[CLINT_NUM_CORES];
uint64_t clint_get_time(void)
{
/* No difference on cores */
return clint->mtime;
}
int clint_timer_init(void)
{
/* Read core id */
unsigned long core_id = current_coreid();
/* Clear the Machine-Timer bit in MIE */
CLEAR_CSR(mie, MIP_MTIP);
/* Fill core's instance with original data */
/* clang-format off */
clint_timer_instance[core_id] = (const clint_timer_instance_t)
{
.interval = 0,
.cycles = 0,
.single_shot = 0,
.callback = NULL,
.ctx = NULL,
};
/* clang-format on */
return 0;
}
int clint_timer_stop(void)
{
/* Clear the Machine-Timer bit in MIE */
CLEAR_CSR(mie, MIP_MTIP);
return 0;
}
uint64_t clint_timer_get_freq(void)
{
/* The clock is divided by CLINT_CLOCK_DIV */
return SysctlClockGetFreq(SYSCTL_CLOCK_CPU) / CLINT_CLOCK_DIV;
}
int clint_timer_start(uint64_t interval, int single_shot)
{
/* Read core id */
unsigned long core_id = current_coreid();
/* Set timer interval */
if (clint_timer_set_interval(interval) != 0)
return -1;
/* Set timer single shot */
if (clint_timer_set_single_shot(single_shot) != 0)
return -1;
/* Check settings to prevent interval is 0 */
if (clint_timer_instance[core_id].interval == 0)
return -1;
/* Check settings to prevent cycles is 0 */
if (clint_timer_instance[core_id].cycles == 0)
return -1;
/* Add cycle interval to mtimecmp */
uint64_t now = clint->mtime;
uint64_t then = now + clint_timer_instance[core_id].cycles;
/* Set mtimecmp by core id */
clint->mtimecmp[core_id] = then;
/* Enable interrupts in general */
SET_CSR(mstatus, MSTATUS_MIE);
/* Enable the Machine-Timer bit in MIE */
SET_CSR(mie, MIP_MTIP);
return 0;
}
uint64_t clint_timer_get_interval(void)
{
/* Read core id */
unsigned long core_id = current_coreid();
return clint_timer_instance[core_id].interval;
}
int clint_timer_set_interval(uint64_t interval)
{
/* Read core id */
unsigned long core_id = current_coreid();
/* Check parameter */
if (interval == 0)
return -1;
/* Assign user interval with Millisecond(ms) */
clint_timer_instance[core_id].interval = interval;
/* Convert interval to cycles */
clint_timer_instance[core_id].cycles = interval * clint_timer_get_freq() / 1000ULL;
return 0;
}
int clint_timer_get_single_shot(void)
{
/* Read core id */
unsigned long core_id = current_coreid();
/* Get single shot mode by core id */
return clint_timer_instance[core_id].single_shot;
}
int clint_timer_set_single_shot(int single_shot)
{
/* Read core id */
unsigned long core_id = current_coreid();
/* Set single shot mode by core id */
clint_timer_instance[core_id].single_shot = single_shot;
return 0;
}
int clint_timer_register(clint_timer_callback_t callback, void *ctx)
{
/* Read core id */
unsigned long core_id = current_coreid();
/* Set user callback function */
clint_timer_instance[core_id].callback = callback;
/* Assign user context */
clint_timer_instance[core_id].ctx = ctx;
return 0;
}
int clint_timer_unregister(void)
{
/* Just assign NULL to user callback function and context */
return clint_timer_register(NULL, NULL);
}
int clint_ipi_init(void)
{
/* Read core id */
unsigned long core_id = current_coreid();
/* Clear the Machine-Software bit in MIE */
CLEAR_CSR(mie, MIP_MSIP);
/* Fill core's instance with original data */
/* clang-format off */
clint_ipi_instance[core_id] = (const clint_ipi_instance_t){
.callback = NULL,
.ctx = NULL,
};
/* clang-format on */
return 0;
}
int clint_ipi_enable(void)
{
/* Enable interrupts in general */
SET_CSR(mstatus, MSTATUS_MIE);
/* Set the Machine-Software bit in MIE */
SET_CSR(mie, MIP_MSIP);
return 0;
}
int clint_ipi_disable(void)
{
/* Clear the Machine-Software bit in MIE */
CLEAR_CSR(mie, MIP_MSIP);
return 0;
}
int clint_ipi_send(size_t core_id)
{
if (core_id >= CLINT_NUM_CORES)
return -1;
clint->msip[core_id].msip = 1;
return 0;
}
int clint_ipi_clear(size_t core_id)
{
if (core_id >= CLINT_NUM_CORES)
return -1;
if (clint->msip[core_id].msip)
{
clint->msip[core_id].msip = 0;
return 1;
}
return 0;
}
int clint_ipi_register(clint_ipi_callback_t callback, void *ctx)
{
/* Read core id */
unsigned long core_id = current_coreid();
/* Set user callback function */
clint_ipi_instance[core_id].callback = callback;
/* Assign user context */
clint_ipi_instance[core_id].ctx = ctx;
return 0;
}
int clint_ipi_unregister(void)
{
/* Just assign NULL to user callback function and context */
return clint_ipi_register(NULL, NULL);
}
@@ -0,0 +1,41 @@
/* 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 drv_interrupt.c
* @brief add from Canaan k210 SDK
* https://canaan-creative.com/developer
* @version 1.0
* @author AIIT XUOS Lab
* @date 2021-04-25
*/
#include <plic.h>
void PlicIrqHandle(plic_irq_t irq)
{
plic_instance_t (*plic_instance)[IRQN_MAX] = plic_get_instance();
if (plic_instance[0][irq].callback)
{
plic_instance[0][irq].callback(
plic_instance[0][irq].ctx);
}
else if (plic_instance[1][irq].callback)
{
plic_instance[1][irq].callback(
plic_instance[1][irq].ctx);
}
}
@@ -0,0 +1,219 @@
/* 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 plic.c
* @brief add from Canaan k210 SDK
* https://canaan-creative.com/developer
* @version 1.0
* @author AIIT XUOS Lab
* @date 2021-04-25
*/
#include <stddef.h>
#include <stdint.h>
#include "encoding.h"
#include "plic.h"
#include "syscalls.h"
#include "syslog.h"
volatile plic_t* const plic = (volatile plic_t*)PLIC_BASE_ADDR;
static plic_instance_t plic_instance[PLIC_NUM_CORES][IRQN_MAX];
void plic_init(void)
{
int i = 0;
/* Get current core id */
unsigned long core_id = current_coreid();
/* Disable all interrupts for the current core. */
for (i = 0; i < ((PLIC_NUM_SOURCES + 32u) / 32u); i++)
plic->target_enables.target[core_id].enable[i] = 0;
static uint8_t s_plic_priorities_init_flag = 0;
/* Set priorities to zero. */
if(s_plic_priorities_init_flag == 0)
{
for (i = 0; i < PLIC_NUM_SOURCES; i++)
plic->source_priorities.priority[i] = 0;
s_plic_priorities_init_flag = 1;
}
/* Set the threshold to zero. */
plic->targets.target[core_id].priority_threshold = 0;
/* Clear PLIC instance for every cores */
for (i = 0; i < IRQN_MAX; i++)
{
/* clang-format off */
plic_instance[core_id][i] = (const plic_instance_t){
.callback = NULL,
.ctx = NULL,
};
/* clang-format on */
}
/*
* A successful claim will also atomically clear the corresponding
* pending bit on the interrupt source. A target can perform a claim
* at any time, even if the EIP is not set.
*/
i = 0;
while (plic->targets.target[core_id].claim_complete > 0 && i < 100)
{
/* This loop will clear pending bit on the interrupt source */
i++;
}
/* Enable machine external interrupts. */
SET_CSR(mie, MIP_MEIP);
}
int plic_irq_enable(plic_irq_t irq_number)
{
/* Check parameters */
if (PLIC_NUM_SOURCES < irq_number || 0 > irq_number)
return -1;
unsigned long core_id = current_coreid();
/* Get current enable bit array by IRQ number */
uint32_t current = plic->target_enables.target[core_id].enable[irq_number / 32];
/* Set enable bit in enable bit array */
current |= (uint32_t)1 << (irq_number % 32);
/* Write back the enable bit array */
plic->target_enables.target[core_id].enable[irq_number / 32] = current;
return 0;
}
int plic_irq_disable(plic_irq_t irq_number)
{
/* Check parameters */
if (PLIC_NUM_SOURCES < irq_number || 0 > irq_number)
return -1;
unsigned long core_id = current_coreid();
/* Get current enable bit array by IRQ number */
uint32_t current = plic->target_enables.target[core_id].enable[irq_number / 32];
/* Clear enable bit in enable bit array */
current &= ~((uint32_t)1 << (irq_number % 32));
/* Write back the enable bit array */
plic->target_enables.target[core_id].enable[irq_number / 32] = current;
return 0;
}
int plic_set_priority(plic_irq_t irq_number, uint32_t priority)
{
/* Check parameters */
if (PLIC_NUM_SOURCES < irq_number || 0 > irq_number)
return -1;
/* Set interrupt priority by IRQ number */
plic->source_priorities.priority[irq_number] = priority;
return 0;
}
uint32_t plic_get_priority(plic_irq_t irq_number)
{
/* Check parameters */
if (PLIC_NUM_SOURCES < irq_number || 0 > irq_number)
return 0;
/* Get interrupt priority by IRQ number */
return plic->source_priorities.priority[irq_number];
}
uint32_t plic_irq_claim(void)
{
unsigned long core_id = current_coreid();
/* Perform IRQ claim */
return plic->targets.target[core_id].claim_complete;
}
int plic_irq_complete(uint32_t source)
{
unsigned long core_id = current_coreid();
/* Perform IRQ complete */
plic->targets.target[core_id].claim_complete = source;
return 0;
}
void plic_irq_register(plic_irq_t irq, plic_irq_callback_t callback, void *ctx)
{
/* Read core id */
unsigned long core_id = current_coreid();
/* Set user callback function */
plic_instance[core_id][irq].callback = callback;
/* Assign user context */
plic_instance[core_id][irq].ctx = ctx;
}
void plic_irq_unregister(plic_irq_t irq)
{
/* Just assign NULL to user callback function and context */
plic_irq_register(irq, NULL, NULL);
}
void __attribute__((weak, alias("plic_irq_unregister"))) plic_irq_deregister(plic_irq_t irq);
plic_instance_t (*plic_get_instance(void))[IRQN_MAX]
{
return plic_instance;
}
/*Entry Point for PLIC Interrupt Handler*/
uintptr_t __attribute__((weak))
HandleIrqMExt(uintptr_t cause, uintptr_t epc)
{
/*
* After the highest-priority pending interrupt is claimed by a target
* and the corresponding IP bit is cleared, other lower-priority
* pending interrupts might then become visible to the target, and so
* the PLIC EIP bit might not be cleared after a claim. The interrupt
* handler can check the local meip/heip/seip/ueip bits before exiting
* the handler, to allow more efficient service of other interrupts
* without first restoring the interrupted context and taking another
* interrupt trap.
*/
if (READ_CSR(mip) & MIP_MEIP)
{
/* Get current core id */
uint64_t core_id = current_coreid();
/* Get primitive interrupt enable flag */
uint64_t ie_flag = READ_CSR(mie);
/* Get current IRQ num */
uint32_t int_num = plic->targets.target[core_id].claim_complete;
/* Get primitive IRQ threshold */
uint32_t int_threshold = plic->targets.target[core_id].priority_threshold;
/* Set new IRQ threshold = current IRQ threshold */
plic->targets.target[core_id].priority_threshold = plic->source_priorities.priority[int_num];
/* Disable software interrupt and timer interrupt */
CLEAR_CSR(mie, MIP_MTIP | MIP_MSIP);
/* Enable global interrupt */
SET_CSR(mstatus, MSTATUS_MIE);
if (plic_instance[core_id][int_num].callback)
plic_instance[core_id][int_num].callback(
plic_instance[core_id][int_num].ctx);
/* Perform IRQ complete */
plic->targets.target[core_id].claim_complete = int_num;
/* Disable global interrupt */
CLEAR_CSR(mstatus, MSTATUS_MIE);
/* Set MPIE and MPP flag used to MRET instructions restore MIE flag */
SET_CSR(mstatus, MSTATUS_MPIE | MSTATUS_MPP);
/* Restore primitive interrupt enable flag */
WRITE_CSR(mie, ie_flag);
/* Restore primitive IRQ threshold */
plic->targets.target[core_id].priority_threshold = int_threshold;
}
return epc;
}
+49
View File
@@ -0,0 +1,49 @@
/* 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 sleep.c
* @brief add from Canaan k210 SDK
* https://canaan-creative.com/developer
* @version 1.0
* @author AIIT XUOS Lab
* @date 2021-04-25
*/
#include "sleep.h"
#include "sysctl.h"
int usleep(uint64_t usec)
{
uint64_t cycle = read_cycle();
uint64_t nop_all = usec * SysctlClockGetFreq(SYSCTL_CLOCK_CPU) / 1000000UL;
while (1)
{
if(read_cycle() - cycle >= nop_all)
break;
}
return 0;
}
int msleep(uint64_t msec)
{
return (unsigned int)usleep(msec * 1000);
}
unsigned int sleep(unsigned int seconds)
{
return (unsigned int)msleep(seconds * 1000);
}
@@ -0,0 +1 @@
@@ -0,0 +1,6 @@
SRC_FILES := sysctl.c
include $(KERNEL_ROOT)/compiler.mk
File diff suppressed because it is too large Load Diff
@@ -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 maix-go-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 maix-go-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 maix-go-board uart configure, write and read
2. support maix-go-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;
}