succeed read and write sd card
This commit is contained in:
parent
5ea7c669e2
commit
43db17f6ba
7
Makefile
7
Makefile
|
@ -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
|
||||
|
|
|
@ -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 */
|
File diff suppressed because it is too large
Load Diff
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 device’s interrupt can be
|
||||
* enabled by setting the corresponding bit in that target’s
|
||||
* 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 source’s 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 target’s 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 target’s 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 */
|
|
@ -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 */
|
|
@ -9,3 +9,5 @@ typedef unsigned long uint64;
|
|||
|
||||
typedef unsigned long uintptr_t;
|
||||
typedef uint64 pde_t;
|
||||
|
||||
#define NULL ((void *)0)
|
||||
|
|
|
@ -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 */
|
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
}
|
488
kernel/sdcard.c
488
kernel/sdcard.c
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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");
|
||||
}
|
|
@ -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);
|
||||
}
|
Loading…
Reference in New Issue