succeed read and write sd card

This commit is contained in:
hustccc 2020-11-03 07:37:51 +09:00
parent 5ea7c669e2
commit 43db17f6ba
20 changed files with 10231 additions and 28 deletions

View File

@ -33,6 +33,11 @@ OBJS = \
$K/plic.o \
$K/virtio_disk.o \
$K/timer.o \
$K/spi.o \
$K/gpiohs.o \
$K/fpioa.o \
$K/utils.o \
$K/sdcard.o \
$K/test.o \
SDK_OBJS = \
@ -75,7 +80,7 @@ linker = ./linker/k210.ld
kendryte_sdk_lib = ./libkendryte.a
$T/kernel: $(OBJS) $(linker)
@$(LD) $(LDFLAGS) -T $(linker) -o $T/kernel $(OBJS) $(kendryte_sdk_lib) -L.
@$(LD) $(LDFLAGS) -T $(linker) -o $T/kernel $(OBJS)
@$(OBJDUMP) -S $T/kernel > $T/kernel.asm
@$(OBJDUMP) -t $T/kernel | sed '1,/SYMBOL TABLE/d; s/ .* / /; /^$$/d' > $T/kernel.sym
# @rm -f $K/*.o $K/*.d

View File

@ -0,0 +1,98 @@
/* 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.
*/
#ifndef _BSP_PLATFORM_H
#define _BSP_PLATFORM_H
#ifdef __cplusplus
extern "C" {
#endif
/* clang-format off */
/* Register base address */
/* Under Coreplex */
#define CLINT_BASE_ADDR (0x02000000U)
#define PLIC_BASE_ADDR (0x0C000000U)
/* Under TileLink */
#define UARTHS_BASE_ADDR (0x38000000U)
#define GPIOHS_BASE_ADDR (0x38001000U)
/* Under AXI 64 bit */
#define RAM_BASE_ADDR (0x80000000U)
#define RAM_SIZE (6 * 1024 * 1024U)
#define IO_BASE_ADDR (0x40000000U)
#define IO_SIZE (6 * 1024 * 1024U)
#define AI_RAM_BASE_ADDR (0x80600000U)
#define AI_RAM_SIZE (2 * 1024 * 1024U)
#define AI_IO_BASE_ADDR (0x40600000U)
#define AI_IO_SIZE (2 * 1024 * 1024U)
#define AI_BASE_ADDR (0x40800000U)
#define AI_SIZE (12 * 1024 * 1024U)
#define FFT_BASE_ADDR (0x42000000U)
#define FFT_SIZE (4 * 1024 * 1024U)
#define ROM_BASE_ADDR (0x88000000U)
#define ROM_SIZE (128 * 1024U)
/* Under AHB 32 bit */
#define DMAC_BASE_ADDR (0x50000000U)
/* Under APB1 32 bit */
#define GPIO_BASE_ADDR (0x50200000U)
#define UART1_BASE_ADDR (0x50210000U)
#define UART2_BASE_ADDR (0x50220000U)
#define UART3_BASE_ADDR (0x50230000U)
#define SPI_SLAVE_BASE_ADDR (0x50240000U)
#define I2S0_BASE_ADDR (0x50250000U)
#define I2S1_BASE_ADDR (0x50260000U)
#define I2S2_BASE_ADDR (0x50270000U)
#define I2C0_BASE_ADDR (0x50280000U)
#define I2C1_BASE_ADDR (0x50290000U)
#define I2C2_BASE_ADDR (0x502A0000U)
#define FPIOA_BASE_ADDR (0x502B0000U)
#define SHA256_BASE_ADDR (0x502C0000U)
#define TIMER0_BASE_ADDR (0x502D0000U)
#define TIMER1_BASE_ADDR (0x502E0000U)
#define TIMER2_BASE_ADDR (0x502F0000U)
/* Under APB2 32 bit */
#define WDT0_BASE_ADDR (0x50400000U)
#define WDT1_BASE_ADDR (0x50410000U)
#define OTP_BASE_ADDR (0x50420000U)
#define DVP_BASE_ADDR (0x50430000U)
#define SYSCTL_BASE_ADDR (0x50440000U)
#define AES_BASE_ADDR (0x50450000U)
#define RTC_BASE_ADDR (0x50460000U)
/* Under APB3 32 bit */
#define SPI0_BASE_ADDR (0x52000000U)
#define SPI1_BASE_ADDR (0x53000000U)
#define SPI3_BASE_ADDR (0x54000000U)
/* clang-format on */
#ifdef __cplusplus
}
#endif
#endif /* _BSP_PLATFORM_H */

4930
kernel/fpioa.c Normal file

File diff suppressed because it is too large Load Diff

203
kernel/gpiohs.c Normal file
View File

@ -0,0 +1,203 @@
// GPIOHS Protocol Implementation
#include "include/types.h"
#include "include/gpiohs.h"
#include "include/fpioa.h"
#include "include/utils.h"
#define GPIOHS_MAX_PINNO 32
volatile gpiohs_t *const gpiohs = (volatile gpiohs_t *)GPIOHS_BASE_ADDR;
typedef struct _gpiohs_pin_instance
{
uint64 pin;
gpio_pin_edge_t edge;
void (*callback)();
plic_irq_callback_t gpiohs_callback;
void *context;
} gpiohs_pin_instance_t;
static gpiohs_pin_instance_t pin_instance[32];
void gpiohs_set_drive_mode(uint8 pin, gpio_drive_mode_t mode)
{
// configASSERT(pin < GPIOHS_MAX_PINNO);
int io_number = fpioa_get_io_by_function(FUNC_GPIOHS0 + pin);
// configASSERT(io_number >= 0);
fpioa_pull_t pull = FPIOA_PULL_NONE;
uint32 dir = 0;
switch(mode)
{
case GPIO_DM_INPUT:
pull = FPIOA_PULL_NONE;
dir = 0;
break;
case GPIO_DM_INPUT_PULL_DOWN:
pull = FPIOA_PULL_DOWN;
dir = 0;
break;
case GPIO_DM_INPUT_PULL_UP:
pull = FPIOA_PULL_UP;
dir = 0;
break;
case GPIO_DM_OUTPUT:
pull = FPIOA_PULL_DOWN;
dir = 1;
break;
default:
// configASSERT(!"GPIO drive mode is not supported.")
break;
}
fpioa_set_io_pull(io_number, pull);
volatile uint32 *reg = dir ? gpiohs->output_en.u32 : gpiohs->input_en.u32;
volatile uint32 *reg_d = !dir ? gpiohs->output_en.u32 : gpiohs->input_en.u32;
set_gpio_bit(reg_d, pin, 0);
set_gpio_bit(reg, pin, 1);
}
gpio_pin_value_t gpiohs_get_pin(uint8 pin)
{
// configASSERT(pin < GPIOHS_MAX_PINNO);
return get_gpio_bit(gpiohs->input_val.u32, pin);
}
void gpiohs_set_pin(uint8 pin, gpio_pin_value_t value)
{
// configASSERT(pin < GPIOHS_MAX_PINNO);
set_gpio_bit(gpiohs->output_val.u32, pin, value);
}
void gpiohs_set_pin_edge(uint8 pin, gpio_pin_edge_t edge)
{
set_gpio_bit(gpiohs->rise_ie.u32, pin, 0);
set_gpio_bit(gpiohs->rise_ip.u32, pin, 1);
set_gpio_bit(gpiohs->fall_ie.u32, pin, 0);
set_gpio_bit(gpiohs->fall_ip.u32, pin, 1);
set_gpio_bit(gpiohs->low_ie.u32, pin, 0);
set_gpio_bit(gpiohs->low_ip.u32, pin, 1);
set_gpio_bit(gpiohs->high_ie.u32, pin, 0);
set_gpio_bit(gpiohs->high_ip.u32, pin, 1);
if(edge & GPIO_PE_FALLING)
{
set_gpio_bit(gpiohs->fall_ie.u32, pin, 1);
} else
{
set_gpio_bit(gpiohs->fall_ie.u32, pin, 0);
}
if(edge & GPIO_PE_RISING)
{
set_gpio_bit(gpiohs->rise_ie.u32, pin, 1);
} else
{
set_gpio_bit(gpiohs->rise_ie.u32, pin, 0);
}
if(edge & GPIO_PE_LOW)
{
set_gpio_bit(gpiohs->low_ie.u32, pin, 1);
} else
{
set_gpio_bit(gpiohs->low_ie.u32, pin, 0);
}
if(edge & GPIO_PE_HIGH)
{
set_gpio_bit(gpiohs->high_ie.u32, pin, 1);
} else
{
set_gpio_bit(gpiohs->high_ie.u32, pin, 0);
}
pin_instance[pin].edge = edge;
}
int gpiohs_pin_onchange_isr(void *userdata)
{
gpiohs_pin_instance_t *ctx = (gpiohs_pin_instance_t *)userdata;
uint64 pin = ctx->pin;
if(ctx->edge & GPIO_PE_FALLING)
{
set_gpio_bit(gpiohs->fall_ie.u32, pin, 0);
set_gpio_bit(gpiohs->fall_ip.u32, pin, 1);
set_gpio_bit(gpiohs->fall_ie.u32, pin, 1);
}
if(ctx->edge & GPIO_PE_RISING)
{
set_gpio_bit(gpiohs->rise_ie.u32, pin, 0);
set_gpio_bit(gpiohs->rise_ip.u32, pin, 1);
set_gpio_bit(gpiohs->rise_ie.u32, pin, 1);
}
if(ctx->edge & GPIO_PE_LOW)
{
set_gpio_bit(gpiohs->low_ie.u32, pin, 0);
set_gpio_bit(gpiohs->low_ip.u32, pin, 1);
set_gpio_bit(gpiohs->low_ie.u32, pin, 1);
}
if(ctx->edge & GPIO_PE_HIGH)
{
set_gpio_bit(gpiohs->high_ie.u32, pin, 0);
set_gpio_bit(gpiohs->high_ip.u32, pin, 1);
set_gpio_bit(gpiohs->high_ie.u32, pin, 1);
}
if(ctx->callback)
ctx->callback();
if(ctx->gpiohs_callback)
ctx->gpiohs_callback(ctx->context);
return 0;
}
void gpiohs_set_irq(uint8 pin, uint32 priority, void (*func)())
{
pin_instance[pin].pin = pin;
pin_instance[pin].callback = func;
// plic_set_priority(IRQN_GPIOHS0_INTERRUPT + pin, priority);
// plic_irq_register(IRQN_GPIOHS0_INTERRUPT + pin, gpiohs_pin_onchange_isr, &(pin_instance[pin]));
// plic_irq_enable(IRQN_GPIOHS0_INTERRUPT + pin);
}
void gpiohs_irq_register(uint8 pin, uint32 priority, plic_irq_callback_t callback, void *ctx)
{
pin_instance[pin].pin = pin;
pin_instance[pin].gpiohs_callback = callback;
pin_instance[pin].context = ctx;
// plic_set_priority(IRQN_GPIOHS0_INTERRUPT + pin, priority);
// plic_irq_register(IRQN_GPIOHS0_INTERRUPT + pin, gpiohs_pin_onchange_isr, &(pin_instance[pin]));
// plic_irq_enable(IRQN_GPIOHS0_INTERRUPT + pin);
}
void gpiohs_irq_unregister(uint8 pin)
{
pin_instance[pin] = (gpiohs_pin_instance_t){
.callback = NULL,
.gpiohs_callback = NULL,
.context = NULL,
};
set_gpio_bit(gpiohs->rise_ie.u32, pin, 0);
set_gpio_bit(gpiohs->fall_ie.u32, pin, 0);
set_gpio_bit(gpiohs->low_ie.u32, pin, 0);
set_gpio_bit(gpiohs->high_ie.u32, pin, 0);
// plic_irq_unregister(IRQN_GPIOHS0_INTERRUPT + pin);
}
void gpiohs_irq_disable(uint64 pin)
{
// plic_irq_disable(IRQN_GPIOHS0_INTERRUPT + pin);
}

View File

@ -8,7 +8,9 @@ struct spinlock;
struct sleeplock;
struct stat;
struct superblock;
// enum spi_device_num_t;
// enum spi_work_mode_t;
// enum spi_frame_format_t;
// bio.c
void binit(void);
struct buf* bread(uint, uint);
@ -153,6 +155,7 @@ void trapinithart(void);
extern struct spinlock tickslock;
void usertrapret(void);
void supervisor_external_handler(void);
void device_init(unsigned long, uint64);
// uart.c
void uartinit(void);
@ -185,7 +188,6 @@ void plicinit(void);
void plicinithart(void);
int plic_claim(void);
void plic_complete(int);
void device_init(unsigned long, uint64);
// virtio_disk.c
void virtio_disk_init(void);
@ -196,6 +198,10 @@ void virtio_disk_intr(void);
void test_kalloc(void);
void test_vm(unsigned long);
// spi.c
// void spi_init(spi_device_num_t spi_num, spi_work_mode_t work_mode, spi_frame_format_t frame_format,
// uint64 data_bit_length, uint32 endian);
// void ptesprintf(pagetable_t, int);
// int vmprint(pagetable_t);

1325
kernel/include/encoding.h Normal file

File diff suppressed because it is too large Load Diff

1035
kernel/include/fpioa.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,50 @@
/* 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.
*/
#ifndef _GPIO_COMMON_H
#define _GPIO_COMMON_H
#ifdef __cplusplus
extern "C" {
#endif
typedef enum _gpio_drive_mode
{
GPIO_DM_INPUT,
GPIO_DM_INPUT_PULL_DOWN,
GPIO_DM_INPUT_PULL_UP,
GPIO_DM_OUTPUT,
} gpio_drive_mode_t;
typedef enum _gpio_pin_edge
{
GPIO_PE_NONE,
GPIO_PE_FALLING,
GPIO_PE_RISING,
GPIO_PE_BOTH,
GPIO_PE_LOW,
GPIO_PE_HIGH = 8,
} gpio_pin_edge_t;
typedef enum _gpio_pin_value
{
GPIO_PV_LOW,
GPIO_PV_HIGH
} gpio_pin_value_t;
#ifdef __cplusplus
}
#endif
#endif /* _GPIO_COMMON_H */

266
kernel/include/gpiohs.h Normal file
View File

@ -0,0 +1,266 @@
/* 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.
*/
#ifndef _DRIVER_GPIOHS_H
#define _DRIVER_GPIOHS_H
// #include <stddef.h>
// #include <stdint.h>
#include "gpio_common.h"
#include "platform.h"
#include "plic.h"
#ifdef __cplusplus
extern "C" {
#endif
/* clang-format off */
/* Register address offsets */
#define GPIOHS_INPUT_VAL (0x00)
#define GPIOHS_INPUT_EN (0x04)
#define GPIOHS_OUTPUT_EN (0x08)
#define GPIOHS_OUTPUT_VAL (0x0C)
#define GPIOHS_PULLUP_EN (0x10)
#define GPIOHS_DRIVE (0x14)
#define GPIOHS_RISE_IE (0x18)
#define GPIOHS_RISE_IP (0x1C)
#define GPIOHS_FALL_IE (0x20)
#define GPIOHS_FALL_IP (0x24)
#define GPIOHS_HIGH_IE (0x28)
#define GPIOHS_HIGH_IP (0x2C)
#define GPIOHS_LOW_IE (0x30)
#define GPIOHS_LOW_IP (0x34)
#define GPIOHS_IOF_EN (0x38)
#define GPIOHS_IOF_SEL (0x3C)
#define GPIOHS_OUTPUT_XOR (0x40)
/* clang-format on */
/**
* @brief GPIO bits raw object
*/
typedef struct _gpiohs_raw
{
/* Address offset 0x00 */
uint32 input_val;
/* Address offset 0x04 */
uint32 input_en;
/* Address offset 0x08 */
uint32 output_en;
/* Address offset 0x0c */
uint32 output_val;
/* Address offset 0x10 */
uint32 pullup_en;
/* Address offset 0x14 */
uint32 drive;
/* Address offset 0x18 */
uint32 rise_ie;
/* Address offset 0x1c */
uint32 rise_ip;
/* Address offset 0x20 */
uint32 fall_ie;
/* Address offset 0x24 */
uint32 fall_ip;
/* Address offset 0x28 */
uint32 high_ie;
/* Address offset 0x2c */
uint32 high_ip;
/* Address offset 0x30 */
uint32 low_ie;
/* Address offset 0x34 */
uint32 low_ip;
/* Address offset 0x38 */
uint32 iof_en;
/* Address offset 0x3c */
uint32 iof_sel;
/* Address offset 0x40 */
uint32 output_xor;
} __attribute__((packed, aligned(4))) gpiohs_raw_t;
/**
* @brief GPIO bits object
*/
typedef struct _gpiohs_bits
{
uint32 b0 : 1;
uint32 b1 : 1;
uint32 b2 : 1;
uint32 b3 : 1;
uint32 b4 : 1;
uint32 b5 : 1;
uint32 b6 : 1;
uint32 b7 : 1;
uint32 b8 : 1;
uint32 b9 : 1;
uint32 b10 : 1;
uint32 b11 : 1;
uint32 b12 : 1;
uint32 b13 : 1;
uint32 b14 : 1;
uint32 b15 : 1;
uint32 b16 : 1;
uint32 b17 : 1;
uint32 b18 : 1;
uint32 b19 : 1;
uint32 b20 : 1;
uint32 b21 : 1;
uint32 b22 : 1;
uint32 b23 : 1;
uint32 b24 : 1;
uint32 b25 : 1;
uint32 b26 : 1;
uint32 b27 : 1;
uint32 b28 : 1;
uint32 b29 : 1;
uint32 b30 : 1;
uint32 b31 : 1;
} __attribute__((packed, aligned(4))) gpiohs_bits_t;
/**
* @brief GPIO bits multi access union
*/
typedef union _gpiohs_u32
{
/* 32x1 bit mode */
uint32 u32[1];
/* 16x2 bit mode */
uint16 u16[2];
/* 8x4 bit mode */
uint8 u8[4];
/* 1 bit mode */
gpiohs_bits_t bits;
} __attribute__((packed, aligned(4))) gpiohs_u32_t;
/**
* @brief GPIO object
*
* The GPIO controller is a peripheral device mapped in the
* internal memory map, discoverable in the Configuration String.
* It is responsible for low-level configuration of the actual
* GPIO pads on the device (direction, pull up-enable, and drive
* value), as well as selecting between various sources of the
* controls for these signals. The GPIO controller allows seperate
* configuration of each of N GPIO bits.
*
* Once the interrupt is pending, it will remain set until a 1 is
* written to the *_ip register at that bit.
*/
typedef struct _gpiohs
{
/* Address offset 0x00, Input Values */
gpiohs_u32_t input_val;
/* Address offset 0x04, Input enable */
gpiohs_u32_t input_en;
/* Address offset 0x08, Output enable */
gpiohs_u32_t output_en;
/* Address offset 0x0c, Onput Values */
gpiohs_u32_t output_val;
/* Address offset 0x10, Internal Pull-Ups enable */
gpiohs_u32_t pullup_en;
/* Address offset 0x14, Drive Strength */
gpiohs_u32_t drive;
/* Address offset 0x18, Rise interrupt enable */
gpiohs_u32_t rise_ie;
/* Address offset 0x1c, Rise interrupt pending */
gpiohs_u32_t rise_ip;
/* Address offset 0x20, Fall interrupt enable */
gpiohs_u32_t fall_ie;
/* Address offset 0x24, Fall interrupt pending */
gpiohs_u32_t fall_ip;
/* Address offset 0x28, High interrupt enable */
gpiohs_u32_t high_ie;
/* Address offset 0x2c, High interrupt pending */
gpiohs_u32_t high_ip;
/* Address offset 0x30, Low interrupt enable */
gpiohs_u32_t low_ie;
/* Address offset 0x34, Low interrupt pending */
gpiohs_u32_t low_ip;
/* Address offset 0x38, HW I/O Function enable */
gpiohs_u32_t iof_en;
/* Address offset 0x3c, HW I/O Function select */
gpiohs_u32_t iof_sel;
/* Address offset 0x40, Output XOR (invert) */
gpiohs_u32_t output_xor;
} __attribute__((packed, aligned(4))) gpiohs_t;
/**
* @brief GPIO High-speed object instanse
*/
extern volatile gpiohs_t *const gpiohs;
/**
* @brief Set Gpiohs drive mode
*
* @param[in] pin Gpiohs pin
* @param[in] mode Gpiohs pin drive mode
*/
void gpiohs_set_drive_mode(uint8 pin, gpio_drive_mode_t mode);
/**
* @brief Get Gpiohs pin value
*
* @param[in] pin Gpiohs pin
* @return Pin value
*
* - GPIO_PV_Low Gpiohs pin low
* - GPIO_PV_High Gpiohs pin high
*/
gpio_pin_value_t gpiohs_get_pin(uint8 pin);
/**
* @brief Set Gpiohs pin value
*
* @param[in] pin Gpiohs pin
* @param[in] value Gpiohs pin value
*/
void gpiohs_set_pin(uint8 pin, gpio_pin_value_t value);
/**
* @brief Set Gpiohs pin edge for interrupt
*
* @param[in] pin Gpiohs pin
* @param[in] edge Gpiohs pin edge type
*/
void gpiohs_set_pin_edge(uint8 pin, gpio_pin_edge_t edge);
/**
* @brief Set Gpiohs pin interrupt
*
* @param[in] pin Gpiohs pin
* @param[in] priority Gpiohs pin interrupt priority
* @param[in] func Gpiohs pin interrupt service routine
*/
void gpiohs_set_irq(uint8 pin, uint32 priority, void (*func)());
/**
* @brief Set Gpiohs pin interrupt
*
* @param[in] pin Gpiohs pin
* @param[in] priority Gpiohs pin interrupt priority
* @param[in] callback Gpiohs pin interrupt service routine
* @param[in] ctx Gpiohs interrupt param
*/
void gpiohs_irq_register(uint8 pin, uint32 priority, plic_irq_callback_t callback, void *ctx);
/**
* @brief Unregister Gpiohs pin interrupt
*
* @param[in] pin Gpiohs pin
*/
void gpiohs_irq_unregister(uint8 pin);
#ifdef __cplusplus
}
#endif
#endif /* _DRIVER_GPIOHS_H */

98
kernel/include/platform.h Normal file
View File

@ -0,0 +1,98 @@
/* 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.
*/
#ifndef _BSP_PLATFORM_H
#define _BSP_PLATFORM_H
#ifdef __cplusplus
extern "C" {
#endif
/* clang-format off */
/* Register base address */
/* Under Coreplex */
#define CLINT_BASE_ADDR (0x02000000U)
#define PLIC_BASE_ADDR (0x0C000000U)
/* Under TileLink */
#define UARTHS_BASE_ADDR (0x38000000U)
#define GPIOHS_BASE_ADDR (0x38001000U)
/* Under AXI 64 bit */
#define RAM_BASE_ADDR (0x80000000U)
#define RAM_SIZE (6 * 1024 * 1024U)
#define IO_BASE_ADDR (0x40000000U)
#define IO_SIZE (6 * 1024 * 1024U)
#define AI_RAM_BASE_ADDR (0x80600000U)
#define AI_RAM_SIZE (2 * 1024 * 1024U)
#define AI_IO_BASE_ADDR (0x40600000U)
#define AI_IO_SIZE (2 * 1024 * 1024U)
#define AI_BASE_ADDR (0x40800000U)
#define AI_SIZE (12 * 1024 * 1024U)
#define FFT_BASE_ADDR (0x42000000U)
#define FFT_SIZE (4 * 1024 * 1024U)
#define ROM_BASE_ADDR (0x88000000U)
#define ROM_SIZE (128 * 1024U)
/* Under AHB 32 bit */
#define DMAC_BASE_ADDR (0x50000000U)
/* Under APB1 32 bit */
#define GPIO_BASE_ADDR (0x50200000U)
#define UART1_BASE_ADDR (0x50210000U)
#define UART2_BASE_ADDR (0x50220000U)
#define UART3_BASE_ADDR (0x50230000U)
#define SPI_SLAVE_BASE_ADDR (0x50240000U)
#define I2S0_BASE_ADDR (0x50250000U)
#define I2S1_BASE_ADDR (0x50260000U)
#define I2S2_BASE_ADDR (0x50270000U)
#define I2C0_BASE_ADDR (0x50280000U)
#define I2C1_BASE_ADDR (0x50290000U)
#define I2C2_BASE_ADDR (0x502A0000U)
#define FPIOA_BASE_ADDR (0x502B0000U)
#define SHA256_BASE_ADDR (0x502C0000U)
#define TIMER0_BASE_ADDR (0x502D0000U)
#define TIMER1_BASE_ADDR (0x502E0000U)
#define TIMER2_BASE_ADDR (0x502F0000U)
/* Under APB2 32 bit */
#define WDT0_BASE_ADDR (0x50400000U)
#define WDT1_BASE_ADDR (0x50410000U)
#define OTP_BASE_ADDR (0x50420000U)
#define DVP_BASE_ADDR (0x50430000U)
#define SYSCTL_BASE_ADDR (0x50440000U)
#define AES_BASE_ADDR (0x50450000U)
#define RTC_BASE_ADDR (0x50460000U)
/* Under APB3 32 bit */
#define SPI0_BASE_ADDR (0x52000000U)
#define SPI1_BASE_ADDR (0x53000000U)
#define SPI3_BASE_ADDR (0x54000000U)
/* clang-format on */
#ifdef __cplusplus
}
#endif
#endif /* _BSP_PLATFORM_H */

500
kernel/include/plic.h Normal file
View File

@ -0,0 +1,500 @@
/* 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 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.
*
* @note PLIC RAM Layout
*
* | Address | Description |
* |-----------|---------------------------------|
* |0x0C000000 | Reserved |
* |0x0C000004 | source 1 priority |
* |0x0C000008 | source 2 priority |
* |... | ... |
* |0x0C000FFC | source 1023 priority |
* | | |
* |0x0C001000 | Start of pending array |
* |... | (read-only) |
* |0x0C00107C | End of pending array |
* |0x0C001080 | Reserved |
* |... | ... |
* |0x0C001FFF | Reserved |
* | | |
* |0x0C002000 | target 0 enables |
* |0x0C002080 | target 1 enables |
* |... | ... |
* |0x0C1F1F80 | target 15871 enables |
* |0x0C1F2000 | Reserved |
* |... | ... |
* |0x0C1FFFFC | Reserved |
* | | |
* |0x0C200000 | target 0 priority threshold |
* |0x0C200004 | target 0 claim/complete |
* |... | ... |
* |0x0C201000 | target 1 priority threshold |
* |0x0C201004 | target 1 claim/complete |
* |... | ... |
* |0x0FFFF000 | target 15871 priority threshold |
* |0x0FFFF004 | target 15871 claim/complete |
*
*/
#ifndef _DRIVER_PLIC_H
#define _DRIVER_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 /* _DRIVER_PLIC_H */

492
kernel/include/spi.h Normal file
View File

@ -0,0 +1,492 @@
/* 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.
*/
#ifndef _DRIVER_SPI_H
#define _DRIVER_SPI_H
#ifdef __cplusplus
extern "C" {
#endif
/* clang-format off */
typedef struct _spi
{
/* SPI Control Register 0 (0x00)*/
volatile uint32 ctrlr0;
/* SPI Control Register 1 (0x04)*/
volatile uint32 ctrlr1;
/* SPI Enable Register (0x08)*/
volatile uint32 ssienr;
/* SPI Microwire Control Register (0x0c)*/
volatile uint32 mwcr;
/* SPI Slave Enable Register (0x10)*/
volatile uint32 ser;
/* SPI Baud Rate Select (0x14)*/
volatile uint32 baudr;
/* SPI Transmit FIFO Threshold Level (0x18)*/
volatile uint32 txftlr;
/* SPI Receive FIFO Threshold Level (0x1c)*/
volatile uint32 rxftlr;
/* SPI Transmit FIFO Level Register (0x20)*/
volatile uint32 txflr;
/* SPI Receive FIFO Level Register (0x24)*/
volatile uint32 rxflr;
/* SPI Status Register (0x28)*/
volatile uint32 sr;
/* SPI Interrupt Mask Register (0x2c)*/
volatile uint32 imr;
/* SPI Interrupt Status Register (0x30)*/
volatile uint32 isr;
/* SPI Raw Interrupt Status Register (0x34)*/
volatile uint32 risr;
/* SPI Transmit FIFO Overflow Interrupt Clear Register (0x38)*/
volatile uint32 txoicr;
/* SPI Receive FIFO Overflow Interrupt Clear Register (0x3c)*/
volatile uint32 rxoicr;
/* SPI Receive FIFO Underflow Interrupt Clear Register (0x40)*/
volatile uint32 rxuicr;
/* SPI Multi-Master Interrupt Clear Register (0x44)*/
volatile uint32 msticr;
/* SPI Interrupt Clear Register (0x48)*/
volatile uint32 icr;
/* SPI DMA Control Register (0x4c)*/
volatile uint32 dmacr;
/* SPI DMA Transmit Data Level (0x50)*/
volatile uint32 dmatdlr;
/* SPI DMA Receive Data Level (0x54)*/
volatile uint32 dmardlr;
/* SPI Identification Register (0x58)*/
volatile uint32 idr;
/* SPI DWC_ssi component version (0x5c)*/
volatile uint32 ssic_version_id;
/* SPI Data Register 0-36 (0x60 -- 0xec)*/
volatile uint32 dr[36];
/* SPI RX Sample Delay Register (0xf0)*/
volatile uint32 rx_sample_delay;
/* SPI SPI Control Register (0xf4)*/
volatile uint32 spi_ctrlr0;
/* reserved (0xf8)*/
volatile uint32 resv;
/* SPI XIP Mode bits (0xfc)*/
volatile uint32 xip_mode_bits;
/* SPI XIP INCR transfer opcode (0x100)*/
volatile uint32 xip_incr_inst;
/* SPI XIP WRAP transfer opcode (0x104)*/
volatile uint32 xip_wrap_inst;
/* SPI XIP Control Register (0x108)*/
volatile uint32 xip_ctrl;
/* SPI XIP Slave Enable Register (0x10c)*/
volatile uint32 xip_ser;
/* SPI XIP Receive FIFO Overflow Interrupt Clear Register (0x110)*/
volatile uint32 xrxoicr;
/* SPI XIP time out register for continuous transfers (0x114)*/
volatile uint32 xip_cnt_time_out;
volatile uint32 endian;
} __attribute__((packed, aligned(4))) spi_t;
/* clang-format on */
typedef enum _spi_device_num
{
SPI_DEVICE_0,
SPI_DEVICE_1,
SPI_DEVICE_2,
SPI_DEVICE_3,
SPI_DEVICE_MAX,
} spi_device_num_t;
typedef enum _spi_work_mode
{
SPI_WORK_MODE_0,
SPI_WORK_MODE_1,
SPI_WORK_MODE_2,
SPI_WORK_MODE_3,
} spi_work_mode_t;
typedef enum _spi_frame_format
{
SPI_FF_STANDARD,
SPI_FF_DUAL,
SPI_FF_QUAD,
SPI_FF_OCTAL
} spi_frame_format_t;
typedef enum _spi_instruction_address_trans_mode
{
SPI_AITM_STANDARD,
SPI_AITM_ADDR_STANDARD,
SPI_AITM_AS_FRAME_FORMAT
} spi_instruction_address_trans_mode_t;
typedef enum _spi_transfer_mode
{
SPI_TMOD_TRANS_RECV,
SPI_TMOD_TRANS,
SPI_TMOD_RECV,
SPI_TMOD_EEROM
} spi_transfer_mode_t;
typedef enum _spi_transfer_width
{
SPI_TRANS_CHAR = 0x1,
SPI_TRANS_SHORT = 0x2,
SPI_TRANS_INT = 0x4,
} spi_transfer_width_t;
typedef enum _spi_chip_select
{
SPI_CHIP_SELECT_0,
SPI_CHIP_SELECT_1,
SPI_CHIP_SELECT_2,
SPI_CHIP_SELECT_3,
SPI_CHIP_SELECT_MAX,
} spi_chip_select_t;
typedef enum
{
WRITE_CONFIG,
READ_CONFIG,
WRITE_DATA_BYTE,
READ_DATA_BYTE,
WRITE_DATA_BLOCK,
READ_DATA_BLOCK,
} spi_slave_command_e;
typedef struct
{
uint8 cmd;
uint8 err;
uint32 addr;
uint32 len;
} spi_slave_command_t;
typedef enum
{
IDLE,
COMMAND,
TRANSFER,
} spi_slave_status_e;
typedef int (*spi_slave_receive_callback_t)(void *ctx);
// typedef struct _spi_slave_instance
// {
// uint8 int_pin;
// uint8 ready_pin;
// dmac_channel_number_t dmac_channel;
// uint8 dfs;
// uint8 slv_oe;
// uint8 work_mode;
// uint64 data_bit_length;
// volatile spi_slave_status_e status;
// volatile spi_slave_command_t command;
// volatile uint8 *config_ptr;
// uint32 config_len;
// spi_slave_receive_callback_t callback;
// uint8 is_dual;
// uint8 mosi_pin;
// uint8 miso_pin;
// } spi_slave_instance_t;
// typedef struct _spi_data_t
// {
// dmac_channel_number_t tx_channel;
// dmac_channel_number_t rx_channel;
// uint32 *tx_buf;
// uint64 tx_len;
// uint32 *rx_buf;
// uint64 rx_len;
// spi_transfer_mode_t transfer_mode;
// bool fill_mode;
// } spi_data_t;
extern volatile spi_t *const spi[4];
/**
* @brief Set spi configuration
*
* @param[in] spi_num Spi bus number
* @param[in] mode Spi mode
* @param[in] frame_format Spi frame format
* @param[in] data_bit_length Spi data bit length
* @param[in] endian 0:little-endian 1:big-endian
*
* @return Void
*/
void spi_init(spi_device_num_t spi_num, spi_work_mode_t work_mode, spi_frame_format_t frame_format,
uint64 data_bit_length, uint32 endian);
/**
* @brief Set multiline configuration
*
* @param[in] spi_num Spi bus number
* @param[in] instruction_length Instruction length
* @param[in] address_length Address length
* @param[in] wait_cycles Wait cycles
* @param[in] instruction_address_trans_mode Spi transfer mode
*
*/
void spi_init_non_standard(spi_device_num_t spi_num, uint32 instruction_length, uint32 address_length,
uint32 wait_cycles, spi_instruction_address_trans_mode_t instruction_address_trans_mode);
/**
* @brief Spi send data
*
* @param[in] spi_num Spi bus number
* @param[in] chip_select Spi chip select
* @param[in] cmd_buff Spi command buffer point
* @param[in] cmd_len Spi command length
* @param[in] tx_buff Spi transmit buffer point
* @param[in] tx_len Spi transmit buffer length
*
* @return Result
* - 0 Success
* - Other Fail
*/
void spi_send_data_standard(spi_device_num_t spi_num, spi_chip_select_t chip_select, const uint8 *cmd_buff,
uint64 cmd_len, const uint8 *tx_buff, uint64 tx_len);
/**
* @brief Spi receive data
*
* @param[in] spi_num Spi bus number
* @param[in] chip_select Spi chip select
* @param[in] cmd_buff Spi command buffer point
* @param[in] cmd_len Spi command length
* @param[in] rx_buff Spi receive buffer point
* @param[in] rx_len Spi receive buffer length
*
* @return Result
* - 0 Success
* - Other Fail
*/
void spi_receive_data_standard(spi_device_num_t spi_num, spi_chip_select_t chip_select, const uint8 *cmd_buff,
uint64 cmd_len, uint8 *rx_buff, uint64 rx_len);
/**
* @brief Spi special receive data
*
* @param[in] spi_num Spi bus number
* @param[in] chip_select Spi chip select
* @param[in] cmd_buff Spi command buffer point
* @param[in] cmd_len Spi command length
* @param[in] rx_buff Spi receive buffer point
* @param[in] rx_len Spi receive buffer length
*
* @return Result
* - 0 Success
* - Other Fail
*/
void spi_receive_data_multiple(spi_device_num_t spi_num, spi_chip_select_t chip_select, const uint32 *cmd_buff,
uint64 cmd_len, uint8 *rx_buff, uint64 rx_len);
/**
* @brief Spi special send data
*
* @param[in] spi_num Spi bus number
* @param[in] chip_select Spi chip select
* @param[in] cmd_buff Spi command buffer point
* @param[in] cmd_len Spi command length
* @param[in] tx_buff Spi transmit buffer point
* @param[in] tx_len Spi transmit buffer length
*
* @return Result
* - 0 Success
* - Other Fail
*/
void spi_send_data_multiple(spi_device_num_t spi_num, spi_chip_select_t chip_select, const uint32 *cmd_buff,
uint64 cmd_len, const uint8 *tx_buff, uint64 tx_len);
/**
* @brief Spi send data by dma
*
* @param[in] channel_num Dmac channel number
* @param[in] spi_num Spi bus number
* @param[in] chip_select Spi chip select
* @param[in] cmd_buff Spi command buffer point
* @param[in] cmd_len Spi command length
* @param[in] tx_buff Spi transmit buffer point
* @param[in] tx_len Spi transmit buffer length
*
* @return Result
* - 0 Success
* - Other Fail
*/
// void spi_send_data_standard_dma(dmac_channel_number_t channel_num, spi_device_num_t spi_num,
// spi_chip_select_t chip_select,
// const uint8 *cmd_buff, uint64 cmd_len, const uint8 *tx_buff, uint64 tx_len);
/**
* @brief Spi receive data by dma
*
* @param[in] w_channel_num Dmac write channel number
* @param[in] r_channel_num Dmac read channel number
* @param[in] spi_num Spi bus number
* @param[in] chip_select Spi chip select
* @param[in] cmd_buff Spi command buffer point
* @param[in] cmd_len Spi command length
* @param[in] rx_buff Spi receive buffer point
* @param[in] rx_len Spi receive buffer length
*
* @return Result
* - 0 Success
* - Other Fail
*/
// void spi_receive_data_standard_dma(dmac_channel_number_t dma_send_channel_num,
// dmac_channel_number_t dma_receive_channel_num,
// spi_device_num_t spi_num, spi_chip_select_t chip_select, const uint8 *cmd_buff,
// uint64 cmd_len, uint8 *rx_buff, uint64 rx_len);
/**
* @brief Spi special send data by dma
*
* @param[in] channel_num Dmac channel number
* @param[in] spi_num Spi bus number
* @param[in] chip_select Spi chip select
* @param[in] cmd_buff Spi command buffer point
* @param[in] cmd_len Spi command length
* @param[in] tx_buff Spi transmit buffer point
* @param[in] tx_len Spi transmit buffer length
*
* @return Result
* - 0 Success
* - Other Fail
*/
// void spi_send_data_multiple_dma(dmac_channel_number_t channel_num, spi_device_num_t spi_num,
// spi_chip_select_t chip_select,
// const uint32 *cmd_buff, uint64 cmd_len, const uint8 *tx_buff, uint64 tx_len);
/**
* @brief Spi special receive data by dma
*
* @param[in] dma_send_channel_num Dmac write channel number
* @param[in] dma_receive_channel_num Dmac read channel number
* @param[in] spi_num Spi bus number
* @param[in] chip_select Spi chip select
* @param[in] cmd_buff Spi command buffer point
* @param[in] cmd_len Spi command length
* @param[in] rx_buff Spi receive buffer point
* @param[in] rx_len Spi receive buffer length
*
* @return Result
* - 0 Success
* - Other Fail
*/
// void spi_receive_data_multiple_dma(dmac_channel_number_t dma_send_channel_num,
// dmac_channel_number_t dma_receive_channel_num,
// spi_device_num_t spi_num, spi_chip_select_t chip_select, const uint32 *cmd_buff,
// uint64 cmd_len, uint8 *rx_buff, uint64 rx_len);
/**
* @brief Spi fill dma
*
* @param[in] channel_num Dmac channel number
* @param[in] spi_num Spi bus number
* @param[in] chip_select Spi chip select
* @param[in] tx_buff Spi command buffer point
* @param[in] tx_len Spi command length
*
* @return Result
* - 0 Success
* - Other Fail
*/
// void spi_fill_data_dma(dmac_channel_number_t channel_num, spi_device_num_t spi_num, spi_chip_select_t chip_select,
// const uint32 *tx_buff, uint64 tx_len);
/**
* @brief Spi normal send by dma
*
* @param[in] channel_num Dmac channel number
* @param[in] spi_num Spi bus number
* @param[in] chip_select Spi chip select
* @param[in] tx_buff Spi transmit buffer point
* @param[in] tx_len Spi transmit buffer length
* @param[in] stw Spi transfer width
*
* @return Result
* - 0 Success
* - Other Fail
*/
// void spi_send_data_normal_dma(dmac_channel_number_t channel_num, spi_device_num_t spi_num,
// spi_chip_select_t chip_select,
// const void *tx_buff, uint64 tx_len, spi_transfer_width_t spi_transfer_width);
/**
* @brief Spi normal send by dma
*
* @param[in] spi_num Spi bus number
* @param[in] spi_clk Spi clock rate
*
* @return The real spi clock rate
*/
uint32 spi_set_clk_rate(spi_device_num_t spi_num, uint32 spi_clk);
/**
* @brief Spi full duplex send receive data by dma
*
* @param[in] dma_send_channel_num Dmac write channel number
* @param[in] dma_receive_channel_num Dmac read channel number
* @param[in] spi_num Spi bus number
* @param[in] chip_select Spi chip select
* @param[in] tx_buf Spi send buffer
* @param[in] tx_len Spi send buffer length
* @param[in] rx_buf Spi receive buffer
* @param[in] rx_len Spi receive buffer length
*
*/
// void spi_dup_send_receive_data_dma(dmac_channel_number_t dma_send_channel_num,
// dmac_channel_number_t dma_receive_channel_num,
// spi_device_num_t spi_num, spi_chip_select_t chip_select,
// const uint8 *tx_buf, uint64 tx_len, uint8 *rx_buf, uint64 rx_len);
/**
* @brief Set spi slave configuration
*
* @param[in] int_pin SPI master starts sending data interrupt.
* @param[in] ready_pin SPI slave ready.
* @param[in] dmac_channel Dmac channel number for block.
* @param[in] data_bit_length Spi data bit length
* @param[in] data SPI slave device data buffer.
* @param[in] len The length of SPI slave device data buffer.
* @param[in] callback Callback of spi slave.
*
* @return Void
*/
// void spi_slave_config(uint8 int_pin, uint8 ready_pin, dmac_channel_number_t dmac_channel, uint64 data_bit_length, uint8 *data, uint32 len, spi_slave_receive_callback_t callback);
// void spi_slave_dual_config(uint8 int_pin,
// uint8 ready_pin,
// uint8 mosi_pin,
// uint8 miso_pin,
// dmac_channel_number_t dmac_channel,
// uint64 data_bit_length,
// uint8 *data,
// uint32 len,
// spi_slave_receive_callback_t callback);
/**
* @brief Spi handle transfer data operations
*
* @param[in] spi_num Spi bus number
* @param[in] chip_select Spi chip select
* @param[in] data Spi transfer data information
* @param[in] cb Spi DMA callback
*
*/
// void spi_handle_data_dma(spi_device_num_t spi_num, spi_chip_select_t chip_select, spi_data_t data, plic_interrupt_t *cb);
#ifdef __cplusplus
}
#endif
#endif /* _DRIVER_SPI_H */

View File

@ -9,3 +9,5 @@ typedef unsigned long uint64;
typedef unsigned long uintptr_t;
typedef uint64 pde_t;
#define NULL ((void *)0)

339
kernel/include/utils.h Normal file
View File

@ -0,0 +1,339 @@
/* 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.
*/
#ifndef _DRIVER_UTILS_H
#define _DRIVER_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 *, (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 *, (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))))
/**
* @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 *bits, uint32 mask, uint32 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 *bits, uint32 mask, uint64 offset, uint32 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 *bits, uint64 idx, uint32 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 get_bit(volatile uint32 *bits, uint32 mask, uint64 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 get_gpio_bit(volatile uint32 *bits, uint64 offset);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* _DRIVER_COMMON_H */

View File

@ -5,6 +5,8 @@
#include "include/riscv.h"
#include "include/defs.h"
#include "include/sbi.h"
#include "include/sdcard.h"
#include "include/fpioa.h"
volatile static int started = 0;
// start() jumps here in supervisor mode on all CPUs.
@ -17,7 +19,6 @@ main(unsigned long hartid, unsigned long dtb_pa)
printf("\n");
printf("xv6-k210 kernel is booting\n");
printf("\n");
// uint64 core = current_coreid();
kinit(); // physical page allocator
kvminit(); // create kernel page table
kvminithart(); // turn on paging
@ -33,7 +34,40 @@ main(unsigned long hartid, unsigned long dtb_pa)
// fileinit(); // file table
// virtio_disk_init(); // emulated hard disk
// userinit(); // first user process
fpioa_set_function(27, FUNC_SPI0_SCLK);
fpioa_set_function(28, FUNC_SPI0_D0);
fpioa_set_function(26, FUNC_SPI0_D1);
fpioa_set_function(32, FUNC_GPIOHS7);
fpioa_set_function(29, FUNC_SPI0_SS3);
uint8 cardinfo = sd_init();
if(cardinfo) {
panic("sd card init error\n");
} else
{
printf("sdcard init: %d\n", cardinfo);
}
uint8 buffer[100];
memset(buffer, 0, sizeof(buffer));
if(sd_read_sector(buffer, 0, 10)) {
printf("SD card read sector err\n");
} else {
printf("SD card read sector succeed\n");
}
memmove(buffer, "Hello,World", sizeof("Hello,World"));
printf("Buffer: %s\n", buffer);
if(sd_write_sector(buffer, 0, 10)) {
printf("SD card write sector err\n");
} else {
printf("SD card write sector succeed\n");
}
memset(buffer, 0, sizeof(buffer));
if(sd_read_sector(buffer, 0, 10)) {
printf("SD card read sector err\n");
} else {
printf("SD card read sector succeed\n");
}
printf("Buffer: %s\n", buffer);
test_kalloc(); // test kalloc
test_vm(hartid); // test kernel pagetable
test_proc_init(); // test porc init

View File

@ -49,25 +49,3 @@ plic_complete(int irq)
*(uint32*)PLIC_SCLAIM(hart) = irq;
}
void device_init(unsigned long pa, uint64 hartid) {
// after RustSBI, txen = rxen = 1, rxie = 1, rxcnt = 0
// start UART interrupt configuration
// disable external interrupt on hart1 by setting threshold
uint32 *hart0_m_threshold = (uint32*)PLIC;
uint32 *hart1_m_threshold = (uint32*)PLIC_MENABLE(hartid);
*(hart0_m_threshold) = 0;
*(hart1_m_threshold) = 1;
// *(uint32*)0x0c200000 = 0;
// *(uint32*)0x0c202000 = 1;
// now using UARTHS whose IRQID = 33
// assure that its priority equals 1
// if(*(uint32*)(0x0c000000 + 33 * 4) != 1) panic("uarhs's priority is not 1\n");
// printf("uart priority: %p\n", *(uint32*)(0x0c000000 + 33 * 4));
// *(uint32*)(0x0c000000 + 33 * 4) = 0x1;
uint32 *hart0_m_int_enable_hi = (uint32*)(PLIC_MENABLE(hartid) + 0x04);
*(hart0_m_int_enable_hi) = (1 << 0x1);
// *(uint32*)0x0c002004 = (1 << 0x1);
sbi_set_extern_interrupt((uint64)supervisor_external_handler - 0xffffffff00000000);
printf("device init\n");
}

View File

@ -1,6 +1,9 @@
#include "include/types.h"
#include "include/sdcard.h"
#include "include/spi.h"
#include "include/riscv.h"
#include "include/gpiohs.h"
#include "include/defs.h"
/*
* @brief Start Data tokens:
* Tokens (necessary because at nop/idle (and CS active) only 0xff is
@ -30,3 +33,486 @@
#define SD_CMD58 58 /*!< CMD58 = 0x58 */
#define SD_CMD59 59 /*!< CMD59 = 0x59 */
SD_CardInfo cardinfo;
void SD_CS_HIGH(void)
{
gpiohs_set_pin(7, GPIO_PV_HIGH);
}
void SD_CS_LOW(void)
{
gpiohs_set_pin(7, GPIO_PV_LOW);
}
void SD_HIGH_SPEED_ENABLE(void)
{
// spi_set_clk_rate(SPI_DEVICE_0, 10000000);
}
static void sd_lowlevel_init(uint8 spi_index)
{
gpiohs_set_drive_mode(7, GPIO_DM_OUTPUT);
// spi_set_clk_rate(SPI_DEVICE_0, 200000); /*set clk rate*/
}
static void sd_write_data(uint8 *data_buff, uint32 length)
{
spi_init(SPI_DEVICE_0, SPI_WORK_MODE_0, SPI_FF_STANDARD, 8, 0);
spi_send_data_standard(SPI_DEVICE_0, SPI_CHIP_SELECT_3, NULL, 0, data_buff, length);
}
static void sd_read_data(uint8 *data_buff, uint32 length)
{
spi_init(SPI_DEVICE_0, SPI_WORK_MODE_0, SPI_FF_STANDARD, 8, 0);
spi_receive_data_standard(SPI_DEVICE_0, SPI_CHIP_SELECT_3, NULL, 0, data_buff, length);
}
/*
* @brief Send 5 bytes command to the SD card.
* @param Cmd: The user expected command to send to SD card.
* @param Arg: The command argument.
* @param Crc: The CRC.
* @retval None
*/
static void sd_send_cmd(uint8 cmd, uint32 arg, uint8 crc)
{
uint8 frame[6];
/*!< Construct byte 1 */
frame[0] = (cmd | 0x40);
/*!< Construct byte 2 */
frame[1] = (uint8)(arg >> 24);
/*!< Construct byte 3 */
frame[2] = (uint8)(arg >> 16);
/*!< Construct byte 4 */
frame[3] = (uint8)(arg >> 8);
/*!< Construct byte 5 */
frame[4] = (uint8)(arg);
/*!< Construct CRC: byte 6 */
frame[5] = (crc);
/*!< SD chip select low */
SD_CS_LOW();
/*!< Send the Cmd bytes */
sd_write_data(frame, 6);
}
/*
* @brief Send 5 bytes command to the SD card.
* @param Cmd: The user expected command to send to SD card.
* @param Arg: The command argument.
* @param Crc: The CRC.
* @retval None
*/
static void sd_end_cmd(void)
{
uint8 frame[1] = {0xFF};
/*!< SD chip select high */
SD_CS_HIGH();
/*!< Send the Cmd bytes */
sd_write_data(frame, 1);
}
/*
* @brief Returns the SD response.
* @param None
* @retval The SD Response:
* - 0xFF: Sequence failed
* - 0: Sequence succeed
*/
static uint8 sd_get_response(void)
{
uint8 result;
uint16 timeout = 0x0FFF;
/*!< Check if response is got or a timeout is happen */
while (timeout--) {
sd_read_data(&result, 1);
// sd_read_data_dma(&result);
/*!< Right response got */
if (result != 0xFF)
return result;
}
/*!< After time out */
return 0xFF;
}
/*
* @brief Get SD card data response.
* @param None
* @retval The SD status: Read data response xxx0<status>1
* - status 010: Data accecpted
* - status 101: Data rejected due to a crc error
* - status 110: Data rejected due to a Write error.
* - status 111: Data rejected due to other error.
*/
static uint8 sd_get_dataresponse(void)
{
uint8 response;
/*!< Read resonse */
sd_read_data(&response, 1);
/*!< Mask unused bits */
response &= 0x1F;
if (response != 0x05)
return 0xFF;
/*!< Wait null data */
sd_read_data(&response, 1);
while (response == 0)
sd_read_data(&response, 1);
/*!< Return response */
return 0;
}
/*
* @brief Read the CSD card register
* Reading the contents of the CSD register in SPI mode is a simple
* read-block transaction.
* @param SD_csd: pointer on an SCD register structure
* @retval The SD Response:
* - 0xFF: Sequence failed
* - 0: Sequence succeed
*/
static uint8 sd_get_csdregister(SD_CSD *SD_csd)
{
uint8 csd_tab[18];
/*!< Send CMD9 (CSD register) or CMD10(CSD register) */
sd_send_cmd(SD_CMD9, 0, 0);
/*!< Wait for response in the R1 format (0x00 is no errors) */
if (sd_get_response() != 0x00) {
sd_end_cmd();
return 0xFF;
}
if (sd_get_response() != SD_START_DATA_SINGLE_BLOCK_READ) {
sd_end_cmd();
return 0xFF;
}
/*!< Store CSD register value on csd_tab */
/*!< Get CRC bytes (not really needed by us, but required by SD) */
sd_read_data(csd_tab, 18);
sd_end_cmd();
/*!< Byte 0 */
SD_csd->CSDStruct = (csd_tab[0] & 0xC0) >> 6;
SD_csd->SysSpecVersion = (csd_tab[0] & 0x3C) >> 2;
SD_csd->Reserved1 = csd_tab[0] & 0x03;
/*!< Byte 1 */
SD_csd->TAAC = csd_tab[1];
/*!< Byte 2 */
SD_csd->NSAC = csd_tab[2];
/*!< Byte 3 */
SD_csd->MaxBusClkFrec = csd_tab[3];
/*!< Byte 4 */
SD_csd->CardComdClasses = csd_tab[4] << 4;
/*!< Byte 5 */
SD_csd->CardComdClasses |= (csd_tab[5] & 0xF0) >> 4;
SD_csd->RdBlockLen = csd_tab[5] & 0x0F;
/*!< Byte 6 */
SD_csd->PartBlockRead = (csd_tab[6] & 0x80) >> 7;
SD_csd->WrBlockMisalign = (csd_tab[6] & 0x40) >> 6;
SD_csd->RdBlockMisalign = (csd_tab[6] & 0x20) >> 5;
SD_csd->DSRImpl = (csd_tab[6] & 0x10) >> 4;
SD_csd->Reserved2 = 0; /*!< Reserved */
SD_csd->DeviceSize = (csd_tab[6] & 0x03) << 10;
/*!< Byte 7 */
SD_csd->DeviceSize = (csd_tab[7] & 0x3F) << 16;
/*!< Byte 8 */
SD_csd->DeviceSize |= csd_tab[8] << 8;
/*!< Byte 9 */
SD_csd->DeviceSize |= csd_tab[9];
/*!< Byte 10 */
SD_csd->EraseGrSize = (csd_tab[10] & 0x40) >> 6;
SD_csd->EraseGrMul = (csd_tab[10] & 0x3F) << 1;
/*!< Byte 11 */
SD_csd->EraseGrMul |= (csd_tab[11] & 0x80) >> 7;
SD_csd->WrProtectGrSize = (csd_tab[11] & 0x7F);
/*!< Byte 12 */
SD_csd->WrProtectGrEnable = (csd_tab[12] & 0x80) >> 7;
SD_csd->ManDeflECC = (csd_tab[12] & 0x60) >> 5;
SD_csd->WrSpeedFact = (csd_tab[12] & 0x1C) >> 2;
SD_csd->MaxWrBlockLen = (csd_tab[12] & 0x03) << 2;
/*!< Byte 13 */
SD_csd->MaxWrBlockLen |= (csd_tab[13] & 0xC0) >> 6;
SD_csd->WriteBlockPaPartial = (csd_tab[13] & 0x20) >> 5;
SD_csd->Reserved3 = 0;
SD_csd->ContentProtectAppli = (csd_tab[13] & 0x01);
/*!< Byte 14 */
SD_csd->FileFormatGrouop = (csd_tab[14] & 0x80) >> 7;
SD_csd->CopyFlag = (csd_tab[14] & 0x40) >> 6;
SD_csd->PermWrProtect = (csd_tab[14] & 0x20) >> 5;
SD_csd->TempWrProtect = (csd_tab[14] & 0x10) >> 4;
SD_csd->FileFormat = (csd_tab[14] & 0x0C) >> 2;
SD_csd->ECC = (csd_tab[14] & 0x03);
/*!< Byte 15 */
SD_csd->CSD_CRC = (csd_tab[15] & 0xFE) >> 1;
SD_csd->Reserved4 = 1;
/*!< Return the reponse */
return 0;
}
/*
* @brief Read the CID card register.
* Reading the contents of the CID register in SPI mode is a simple
* read-block transaction.
* @param SD_cid: pointer on an CID register structure
* @retval The SD Response:
* - 0xFF: Sequence failed
* - 0: Sequence succeed
*/
static uint8 sd_get_cidregister(SD_CID *SD_cid)
{
uint8 cid_tab[18];
/*!< Send CMD10 (CID register) */
sd_send_cmd(SD_CMD10, 0, 0);
/*!< Wait for response in the R1 format (0x00 is no errors) */
if (sd_get_response() != 0x00) {
sd_end_cmd();
return 0xFF;
}
if (sd_get_response() != SD_START_DATA_SINGLE_BLOCK_READ) {
sd_end_cmd();
return 0xFF;
}
/*!< Store CID register value on cid_tab */
/*!< Get CRC bytes (not really needed by us, but required by SD) */
sd_read_data(cid_tab, 18);
sd_end_cmd();
/*!< Byte 0 */
SD_cid->ManufacturerID = cid_tab[0];
/*!< Byte 1 */
SD_cid->OEM_AppliID = cid_tab[1] << 8;
/*!< Byte 2 */
SD_cid->OEM_AppliID |= cid_tab[2];
/*!< Byte 3 */
SD_cid->ProdName1 = cid_tab[3] << 24;
/*!< Byte 4 */
SD_cid->ProdName1 |= cid_tab[4] << 16;
/*!< Byte 5 */
SD_cid->ProdName1 |= cid_tab[5] << 8;
/*!< Byte 6 */
SD_cid->ProdName1 |= cid_tab[6];
/*!< Byte 7 */
SD_cid->ProdName2 = cid_tab[7];
/*!< Byte 8 */
SD_cid->ProdRev = cid_tab[8];
/*!< Byte 9 */
SD_cid->ProdSN = cid_tab[9] << 24;
/*!< Byte 10 */
SD_cid->ProdSN |= cid_tab[10] << 16;
/*!< Byte 11 */
SD_cid->ProdSN |= cid_tab[11] << 8;
/*!< Byte 12 */
SD_cid->ProdSN |= cid_tab[12];
/*!< Byte 13 */
SD_cid->Reserved1 |= (cid_tab[13] & 0xF0) >> 4;
SD_cid->ManufactDate = (cid_tab[13] & 0x0F) << 8;
/*!< Byte 14 */
SD_cid->ManufactDate |= cid_tab[14];
/*!< Byte 15 */
SD_cid->CID_CRC = (cid_tab[15] & 0xFE) >> 1;
SD_cid->Reserved2 = 1;
/*!< Return the reponse */
return 0;
}
/*
* @brief Returns information about specific card.
* @param cardinfo: pointer to a SD_CardInfo structure that contains all SD
* card information.
* @retval The SD Response:
* - 0xFF: Sequence failed
* - 0: Sequence succeed
*/
static uint8 sd_get_cardinfo(SD_CardInfo *cardinfo)
{
if (sd_get_csdregister(&(cardinfo->SD_csd)))
return 0xFF;
if (sd_get_cidregister(&(cardinfo->SD_cid)))
return 0xFF;
cardinfo->CardCapacity = (cardinfo->SD_csd.DeviceSize + 1) * 1024;
cardinfo->CardBlockSize = 1 << (cardinfo->SD_csd.RdBlockLen);
cardinfo->CardCapacity *= cardinfo->CardBlockSize;
/*!< Returns the reponse */
return 0;
}
/*
* @brief Initializes the SD/SD communication.
* @param None
* @retval The SD Response:
* - 0xFF: Sequence failed
* - 0: Sequence succeed
*/
uint8 sd_init(void)
{
uint8 frame[10], index, result;
/*!< Initialize SD_SPI */
sd_lowlevel_init(0);
/*!< SD chip select high */
SD_CS_HIGH();
/*!< Send dummy byte 0xFF, 10 times with CS high */
/*!< Rise CS and MOSI for 80 clocks cycles */
/*!< Send dummy byte 0xFF */
for (index = 0; index < 10; index++)
frame[index] = 0xFF;
sd_write_data(frame, 10);
/*------------Put SD in SPI mode--------------*/
/*!< SD initialized and set to SPI mode properly */
index = 0xFF;
while (index--) {
sd_send_cmd(SD_CMD0, 0, 0x95);
// printf("get_response: %d\n", index);
result = sd_get_response();
sd_end_cmd();
if (result == 0x01)
break;
}
if (index == 0)
{
printf("SD_CMD0 is %X\n", result);
return 0xFF;
}
sd_send_cmd(SD_CMD8, 0x01AA, 0x87);
/*!< 0x01 or 0x05 */
result = sd_get_response();
sd_read_data(frame, 4);
sd_end_cmd();
if (result != 0x01)
{
printf("SD_CMD8 is %X\n", result);
return 0xFF;
}
index = 0xFF;
while (index--) {
sd_send_cmd(SD_CMD55, 0, 0);
result = sd_get_response();
sd_end_cmd();
if (result != 0x01)
return 0xFF;
sd_send_cmd(SD_ACMD41, 0x40000000, 0);
result = sd_get_response();
sd_end_cmd();
if (result == 0x00)
break;
}
if (index == 0)
{
printf("SD_CMD55 is %X\n", result);
return 0xFF;
}
index = 255;
while(index--){
sd_send_cmd(SD_CMD58, 0, 1);
result = sd_get_response();
sd_read_data(frame, 4);
sd_end_cmd();
if(result == 0){
break;
}
}
if(index == 0)
{
printf("SD_CMD58 is %X\n", result);
return 0xFF;
}
if ((frame[0] & 0x40) == 0)
return 0xFF;
SD_HIGH_SPEED_ENABLE();
return sd_get_cardinfo(&cardinfo);
}
/*
* @brief Reads a block of data from the SD.
* @param data_buff: pointer to the buffer that receives the data read from the
* SD.
* @param sector: SD's internal address to read from.
* @retval The SD Response:
* - 0xFF: Sequence failed
* - 0: Sequence succeed
*/
uint8 sd_read_sector(uint8 *data_buff, uint32 sector, uint32 count)
{
uint8 frame[2], flag;
/*!< Send CMD17 (SD_CMD17) to read one block */
if (count == 1) {
flag = 0;
sd_send_cmd(SD_CMD17, sector, 0);
} else {
flag = 1;
sd_send_cmd(SD_CMD18, sector, 0);
}
/*!< Check if the SD acknowledged the read block command: R1 response (0x00: no errors) */
if (sd_get_response() != 0x00) {
sd_end_cmd();
return 0xFF;
}
while (count) {
if (sd_get_response() != SD_START_DATA_SINGLE_BLOCK_READ)
break;
/*!< Read the SD block data : read NumByteToRead data */
sd_read_data(data_buff, 512);
/*!< Get CRC bytes (not really needed by us, but required by SD) */
sd_read_data(frame, 2);
data_buff += 512;
count--;
}
sd_end_cmd();
if (flag) {
sd_send_cmd(SD_CMD12, 0, 0);
sd_get_response();
sd_end_cmd();
sd_end_cmd();
}
/*!< Returns the reponse */
return count > 0 ? 0xFF : 0;
}
/*
* @brief Writes a block on the SD
* @param data_buff: pointer to the buffer containing the data to be written on
* the SD.
* @param sector: address to write on.
* @retval The SD Response:
* - 0xFF: Sequence failed
* - 0: Sequence succeed
*/
uint8 sd_write_sector(uint8 *data_buff, uint32 sector, uint32 count)
{
uint8 frame[2] = {0xFF};
if (count == 1) {
frame[1] = SD_START_DATA_SINGLE_BLOCK_WRITE;
sd_send_cmd(SD_CMD24, sector, 0);
} else {
frame[1] = SD_START_DATA_MULTIPLE_BLOCK_WRITE;
sd_send_cmd(SD_ACMD23, count, 0);
sd_get_response();
sd_end_cmd();
sd_send_cmd(SD_CMD25, sector, 0);
}
/*!< Check if the SD acknowledged the write block command: R1 response (0x00: no errors) */
if (sd_get_response() != 0x00) {
sd_end_cmd();
return 0xFF;
}
while (count--) {
/*!< Send the data token to signify the start of the data */
sd_write_data(frame, 2);
/*!< Write the block data to SD : write count data by block */
sd_write_data(data_buff, 512);
/*!< Put CRC bytes (not really needed by us, but required by SD) */
sd_write_data(frame, 2);
data_buff += 512;
/*!< Read data response */
if (sd_get_dataresponse() != 0x00) {
sd_end_cmd();
return 0xFF;
}
}
sd_end_cmd();
sd_end_cmd();
/*!< Returns the reponse */
return 0;
}

303
kernel/spi.c Normal file
View File

@ -0,0 +1,303 @@
// SPI Protocol Implementation
#include "include/types.h"
#include "include/spi.h"
#include "../kendryte_sdk/include/platform.h"
#include "include/riscv.h"
#include "include/utils.h"
#include "include/defs.h"
volatile spi_t *const spi[4] =
{
(volatile spi_t *)SPI0_BASE_ADDR,
(volatile spi_t *)SPI1_BASE_ADDR,
(volatile spi_t *)SPI_SLAVE_BASE_ADDR,
(volatile spi_t *)SPI3_BASE_ADDR};
void spi_init(spi_device_num_t spi_num, spi_work_mode_t work_mode, spi_frame_format_t frame_format,
uint64 data_bit_length, uint32 endian)
{
// configASSERT(data_bit_length >= 4 && data_bit_length <= 32);
// configASSERT(spi_num < SPI_DEVICE_MAX && spi_num != 2);
// spi_clk_init(spi_num);
// uint8 dfs_offset, frf_offset, work_mode_offset;
uint8 dfs_offset = 0;
uint8 frf_offset = 0;
uint8 work_mode_offset = 0;
switch(spi_num)
{
case 0:
case 1:
dfs_offset = 16;
frf_offset = 21;
work_mode_offset = 6;
break;
case 2:
// configASSERT(!"Spi Bus 2 Not Support!");
break;
case 3:
default:
dfs_offset = 0;
frf_offset = 22;
work_mode_offset = 8;
break;
}
switch(frame_format)
{
case SPI_FF_DUAL:
// configASSERT(data_bit_length % 2 == 0);
break;
case SPI_FF_QUAD:
// configASSERT(data_bit_length % 4 == 0);
break;
case SPI_FF_OCTAL:
// configASSERT(data_bit_length % 8 == 0);
break;
default:
break;
}
volatile spi_t *spi_adapter = spi[spi_num];
if(spi_adapter->baudr == 0)
spi_adapter->baudr = 0x14;
spi_adapter->imr = 0x00;
spi_adapter->dmacr = 0x00;
spi_adapter->dmatdlr = 0x10;
spi_adapter->dmardlr = 0x00;
spi_adapter->ser = 0x00;
spi_adapter->ssienr = 0x00;
spi_adapter->ctrlr0 = (work_mode << work_mode_offset) | (frame_format << frf_offset) | ((data_bit_length - 1) << dfs_offset);
spi_adapter->spi_ctrlr0 = 0;
spi_adapter->endian = endian;
}
static void spi_set_tmod(uint8 spi_num, uint32 tmod)
{
// configASSERT(spi_num < SPI_DEVICE_MAX);
volatile spi_t *spi_handle = spi[spi_num];
uint8 tmod_offset = 0;
switch(spi_num)
{
case 0:
case 1:
case 2:
tmod_offset = 8;
break;
case 3:
default:
tmod_offset = 10;
break;
}
set_bit(&spi_handle->ctrlr0, 3 << tmod_offset, tmod << tmod_offset);
}
static spi_transfer_width_t spi_get_frame_size(uint64 data_bit_length)
{
if(data_bit_length < 8)
return SPI_TRANS_CHAR;
else if(data_bit_length < 16)
return SPI_TRANS_SHORT;
return SPI_TRANS_INT;
}
void spi_send_data_normal(spi_device_num_t spi_num, spi_chip_select_t chip_select, const uint8 *tx_buff, uint64 tx_len)
{
// configASSERT(spi_num < SPI_DEVICE_MAX && spi_num != 2);
uint64 index, fifo_len;
spi_set_tmod(spi_num, SPI_TMOD_TRANS);
volatile spi_t *spi_handle = spi[spi_num];
// uint8 dfs_offset;
uint8 dfs_offset = 0;
switch(spi_num)
{
case 0:
case 1:
dfs_offset = 16;
break;
case 2:
// configASSERT(!"Spi Bus 2 Not Support!");
break;
case 3:
default:
dfs_offset = 0;
break;
}
uint32 data_bit_length = (spi_handle->ctrlr0 >> dfs_offset) & 0x1F;
spi_transfer_width_t frame_width = spi_get_frame_size(data_bit_length);
uint8 v_misalign_flag = 0;
uint32 v_send_data;
if((uintptr_t)tx_buff % frame_width)
v_misalign_flag = 1;
spi_handle->ssienr = 0x01;
spi_handle->ser = 1U << chip_select;
uint32 i = 0;
while(tx_len)
{
fifo_len = 32 - spi_handle->txflr;
fifo_len = fifo_len < tx_len ? fifo_len : tx_len;
switch(frame_width)
{
case SPI_TRANS_INT:
fifo_len = fifo_len / 4 * 4;
if(v_misalign_flag)
{
for(index = 0; index < fifo_len; index += 4)
{
// memcpy(&v_send_data, tx_buff + i, 4);
memmove(&v_send_data, tx_buff + i, 4);
spi_handle->dr[0] = v_send_data;
i += 4;
}
} else
{
for(index = 0; index < fifo_len / 4; index++)
spi_handle->dr[0] = ((uint32 *)tx_buff)[i++];
}
break;
case SPI_TRANS_SHORT:
fifo_len = fifo_len / 2 * 2;
if(v_misalign_flag)
{
for(index = 0; index < fifo_len; index += 2)
{
// memcpy(&v_send_data, tx_buff + i, 2);
memmove(&v_send_data, tx_buff + i, 2);
spi_handle->dr[0] = v_send_data;
i += 2;
}
} else
{
for(index = 0; index < fifo_len / 2; index++)
spi_handle->dr[0] = ((uint16 *)tx_buff)[i++];
}
break;
default:
for(index = 0; index < fifo_len; index++)
spi_handle->dr[0] = tx_buff[i++];
break;
}
tx_len -= fifo_len;
}
while((spi_handle->sr & 0x05) != 0x04)
;
spi_handle->ser = 0x00;
spi_handle->ssienr = 0x00;
}
void spi_send_data_standard(spi_device_num_t spi_num, spi_chip_select_t chip_select, const uint8 *cmd_buff,
uint64 cmd_len, const uint8 *tx_buff, uint64 tx_len)
{
// configASSERT(spi_num < SPI_DEVICE_MAX && spi_num != 2);
// uint8 *v_buf = malloc(cmd_len + tx_len);
uint8 *v_buf = kalloc();
uint64 i;
for(i = 0; i < cmd_len; i++)
v_buf[i] = cmd_buff[i];
for(i = 0; i < tx_len; i++)
v_buf[cmd_len + i] = tx_buff[i];
spi_send_data_normal(spi_num, chip_select, v_buf, cmd_len + tx_len);
// free((void *)v_buf);
kfree((void *)v_buf);
}
void spi_receive_data_standard(spi_device_num_t spi_num, spi_chip_select_t chip_select, const uint8 *cmd_buff,
uint64 cmd_len, uint8 *rx_buff, uint64 rx_len)
{
// configASSERT(spi_num < SPI_DEVICE_MAX && spi_num != 2);
uint64 index, fifo_len;
if(cmd_len == 0)
spi_set_tmod(spi_num, SPI_TMOD_RECV);
else
spi_set_tmod(spi_num, SPI_TMOD_EEROM);
volatile spi_t *spi_handle = spi[spi_num];
// uint8 dfs_offset;
uint8 dfs_offset = 0;
switch(spi_num)
{
case 0:
case 1:
dfs_offset = 16;
break;
case 2:
// configASSERT(!"Spi Bus 2 Not Support!");
break;
case 3:
default:
dfs_offset = 0;
break;
}
uint32 data_bit_length = (spi_handle->ctrlr0 >> dfs_offset) & 0x1F;
spi_transfer_width_t frame_width = spi_get_frame_size(data_bit_length);
uint32 i = 0;
uint64 v_cmd_len = cmd_len / frame_width;
uint32 v_rx_len = rx_len / frame_width;
spi_handle->ctrlr1 = (uint32)(v_rx_len - 1);
spi_handle->ssienr = 0x01;
while(v_cmd_len)
{
fifo_len = 32 - spi_handle->txflr;
fifo_len = fifo_len < v_cmd_len ? fifo_len : v_cmd_len;
switch(frame_width)
{
case SPI_TRANS_INT:
for(index = 0; index < fifo_len; index++)
spi_handle->dr[0] = ((uint32 *)cmd_buff)[i++];
break;
case SPI_TRANS_SHORT:
for(index = 0; index < fifo_len; index++)
spi_handle->dr[0] = ((uint16 *)cmd_buff)[i++];
break;
default:
for(index = 0; index < fifo_len; index++)
spi_handle->dr[0] = cmd_buff[i++];
break;
}
spi_handle->ser = 1U << chip_select;
v_cmd_len -= fifo_len;
}
if(cmd_len == 0)
{
spi_handle->dr[0] = 0xffffffff;
spi_handle->ser = 1U << chip_select;
}
i = 0;
while(v_rx_len)
{
fifo_len = spi_handle->rxflr;
fifo_len = fifo_len < v_rx_len ? fifo_len : v_rx_len;
switch(frame_width)
{
case SPI_TRANS_INT:
for(index = 0; index < fifo_len; index++)
((uint32 *)rx_buff)[i++] = spi_handle->dr[0];
break;
case SPI_TRANS_SHORT:
for(index = 0; index < fifo_len; index++)
((uint16 *)rx_buff)[i++] = (uint16)spi_handle->dr[0];
break;
default:
for(index = 0; index < fifo_len; index++)
rx_buff[i++] = (uint8)spi_handle->dr[0];
break;
}
v_rx_len -= fifo_len;
}
spi_handle->ser = 0x00;
spi_handle->ssienr = 0x00;
}

View File

@ -5,6 +5,7 @@
#include "include/riscv.h"
#include "include/spinlock.h"
#include "include/proc.h"
#include "include/sbi.h"
#include "include/defs.h"
@ -244,3 +245,26 @@ supervisor_external_handler() {
while (1);
}
}
void device_init(unsigned long pa, uint64 hartid) {
// after RustSBI, txen = rxen = 1, rxie = 1, rxcnt = 0
// start UART interrupt configuration
// disable external interrupt on hart1 by setting threshold
uint32 *hart0_m_threshold = (uint32*)PLIC;
uint32 *hart1_m_threshold = (uint32*)PLIC_MENABLE(hartid);
*(hart0_m_threshold) = 0;
*(hart1_m_threshold) = 1;
// *(uint32*)0x0c200000 = 0;
// *(uint32*)0x0c202000 = 1;
// now using UARTHS whose IRQID = 33
// assure that its priority equals 1
// if(*(uint32*)(0x0c000000 + 33 * 4) != 1) panic("uarhs's priority is not 1\n");
// printf("uart priority: %p\n", *(uint32*)(0x0c000000 + 33 * 4));
// *(uint32*)(0x0c000000 + 33 * 4) = 0x1;
uint32 *hart0_m_int_enable_hi = (uint32*)(PLIC_MENABLE(hartid) + 0x04);
*(hart0_m_int_enable_hi) = (1 << 0x1);
// *(uint32*)0x0c002004 = (1 << 0x1);
sbi_set_extern_interrupt((uint64)supervisor_external_handler - 0xffffffff00000000);
printf("device init\n");
}

29
kernel/utils.c Normal file
View File

@ -0,0 +1,29 @@
#include "include/types.h"
#include "include/utils.h"
#include "include/encoding.h"
void set_bit(volatile uint32 *bits, uint32 mask, uint32 value)
{
uint32 org = (*bits) & ~mask;
*bits = org | (value & mask);
}
void set_bit_offset(volatile uint32 *bits, uint32 mask, uint64 offset, uint32 value)
{
set_bit(bits, mask << offset, value << offset);
}
void set_gpio_bit(volatile uint32 *bits, uint64 offset, uint32 value)
{
set_bit_offset(bits, 1, offset, value);
}
uint32 get_bit(volatile uint32 *bits, uint32 mask, uint64 offset)
{
return ((*bits) & (mask << offset)) >> offset;
}
uint32 get_gpio_bit(volatile uint32 *bits, uint64 offset)
{
return get_bit(bits, 1, offset);
}