Merge git://git.denx.de/u-boot-riscv

- Add DM drivers to support RISC-V CPU and timer, plus some bug fixes.
- Support SiFive UART
- Rename ax25-ae350 defconfig
This commit is contained in:
Tom Rini 2018-12-21 13:36:08 -05:00
commit 328e3f8a70
37 changed files with 1156 additions and 411 deletions

View File

@ -22,6 +22,7 @@ source "board/emulation/qemu-riscv/Kconfig"
# platform-specific options below
source "arch/riscv/cpu/ax25/Kconfig"
source "arch/riscv/cpu/qemu/Kconfig"
# architecture-specific options below
@ -44,6 +45,40 @@ config ARCH_RV64I
endchoice
choice
prompt "Code Model"
default CMODEL_MEDLOW
config CMODEL_MEDLOW
bool "medium low code model"
help
U-Boot and its statically defined symbols must lie within a single 2 GiB
address range and must lie between absolute addresses -2 GiB and +2 GiB.
config CMODEL_MEDANY
bool "medium any code model"
help
U-Boot and its statically defined symbols must be within any single 2 GiB
address range.
endchoice
choice
prompt "Run Mode"
default RISCV_MMODE
config RISCV_MMODE
bool "Machine"
help
Choose this option to build U-Boot for RISC-V M-Mode.
config RISCV_SMODE
bool "Supervisor"
help
Choose this option to build U-Boot for RISC-V S-Mode.
endchoice
config RISCV_ISA_C
bool "Emit compressed instructions"
default y
@ -55,15 +90,30 @@ config RISCV_ISA_C
config RISCV_ISA_A
def_bool y
config RISCV_SMODE
bool "Run in S-Mode"
help
Enable this option to build U-Boot for RISC-V S-Mode
config 32BIT
bool
config 64BIT
bool
config SIFIVE_CLINT
bool
depends on RISCV_MMODE
select REGMAP
select SYSCON
help
The SiFive CLINT block holds memory-mapped control and status registers
associated with software and timer interrupts.
config RISCV_RDTIME
bool
default y if RISCV_SMODE
help
The provides the riscv_get_time() API that is implemented using the
standard rdtime instruction. This is the case for S-mode U-Boot, and
is useful for processors that support rdtime in M-mode too.
config SYS_MALLOC_F_LEN
default 0x1000
endmenu

View File

@ -17,8 +17,15 @@ endif
ifeq ($(CONFIG_RISCV_ISA_C),y)
ARCH_C = c
endif
ifeq ($(CONFIG_CMODEL_MEDLOW),y)
CMODEL = medlow
endif
ifeq ($(CONFIG_CMODEL_MEDANY),y)
CMODEL = medany
endif
ARCH_FLAGS = -march=$(ARCH_BASE)$(ARCH_A)$(ARCH_C) -mabi=$(ABI)
ARCH_FLAGS = -march=$(ARCH_BASE)$(ARCH_A)$(ARCH_C) -mabi=$(ABI) \
-mcmodel=$(CMODEL)
PLATFORM_CPPFLAGS += $(ARCH_FLAGS)
CFLAGS_EFI += $(ARCH_FLAGS)

View File

@ -4,4 +4,4 @@
extra-y = start.o
obj-y += cpu.o
obj-y += cpu.o mtrap.o

View File

@ -1,7 +1,14 @@
config RISCV_NDS
bool "AndeStar V5 ISA support"
default n
bool
help
Say Y here if you plan to run U-Boot on AndeStar v5
platforms and use some specific features which are
provided by Andes Technology AndeStar V5 Families.
Run U-Boot on AndeStar V5 platforms and use some specific features
which are provided by Andes Technology AndeStar V5 families.
if RISCV_NDS
config RISCV_NDS_CACHE
bool "AndeStar V5 families specific cache support"
help
Provide Andes Technology AndeStar V5 families specific cache support.
endif

View File

@ -9,7 +9,7 @@
void icache_enable(void)
{
#ifndef CONFIG_SYS_ICACHE_OFF
#ifdef CONFIG_RISCV_NDS
#ifdef CONFIG_RISCV_NDS_CACHE
asm volatile (
"csrr t1, mcache_ctl\n\t"
"ori t0, t1, 0x1\n\t"
@ -22,7 +22,7 @@ void icache_enable(void)
void icache_disable(void)
{
#ifndef CONFIG_SYS_ICACHE_OFF
#ifdef CONFIG_RISCV_NDS
#ifdef CONFIG_RISCV_NDS_CACHE
asm volatile (
"fence.i\n\t"
"csrr t1, mcache_ctl\n\t"
@ -36,7 +36,7 @@ void icache_disable(void)
void dcache_enable(void)
{
#ifndef CONFIG_SYS_DCACHE_OFF
#ifdef CONFIG_RISCV_NDS
#ifdef CONFIG_RISCV_NDS_CACHE
asm volatile (
"csrr t1, mcache_ctl\n\t"
"ori t0, t1, 0x2\n\t"
@ -49,7 +49,7 @@ void dcache_enable(void)
void dcache_disable(void)
{
#ifndef CONFIG_SYS_DCACHE_OFF
#ifdef CONFIG_RISCV_NDS
#ifdef CONFIG_RISCV_NDS_CACHE
asm volatile (
"fence\n\t"
"csrr t1, mcache_ctl\n\t"
@ -64,7 +64,7 @@ int icache_status(void)
{
int ret = 0;
#ifdef CONFIG_RISCV_NDS
#ifdef CONFIG_RISCV_NDS_CACHE
asm volatile (
"csrr t1, mcache_ctl\n\t"
"andi %0, t1, 0x01\n\t"
@ -81,7 +81,7 @@ int dcache_status(void)
{
int ret = 0;
#ifdef CONFIG_RISCV_NDS
#ifdef CONFIG_RISCV_NDS_CACHE
asm volatile (
"csrr t1, mcache_ctl\n\t"
"andi %0, t1, 0x02\n\t"

View File

@ -4,7 +4,12 @@
*/
#include <common.h>
#include <cpu.h>
#include <dm.h>
#include <log.h>
#include <asm/csr.h>
#include <asm/encoding.h>
#include <dm/uclass-internal.h>
/*
* prior_stage_fdt_address must be stored in the data section since it is used
@ -12,44 +17,79 @@
*/
phys_addr_t prior_stage_fdt_address __attribute__((section(".data")));
enum {
ISA_INVALID = 0,
ISA_32BIT,
ISA_64BIT,
ISA_128BIT
};
static const char * const isa_bits[] = {
[ISA_INVALID] = NULL,
[ISA_32BIT] = "32",
[ISA_64BIT] = "64",
[ISA_128BIT] = "128"
};
static inline bool supports_extension(char ext)
{
#ifdef CONFIG_CPU
struct udevice *dev;
char desc[32];
uclass_find_first_device(UCLASS_CPU, &dev);
if (!dev) {
debug("unable to find the RISC-V cpu device\n");
return false;
}
if (!cpu_get_desc(dev, desc, sizeof(desc))) {
/* skip the first 4 characters (rv32|rv64) */
if (strchr(desc + 4, ext))
return true;
}
return false;
#else /* !CONFIG_CPU */
#ifdef CONFIG_RISCV_MMODE
return csr_read(misa) & (1 << (ext - 'a'));
#else /* !CONFIG_RISCV_MMODE */
#warning "There is no way to determine the available extensions in S-mode."
#warning "Please convert your board to use the RISC-V CPU driver."
return false;
#endif /* CONFIG_RISCV_MMODE */
#endif /* CONFIG_CPU */
}
int print_cpuinfo(void)
static int riscv_cpu_probe(void)
{
char name[32];
char *s = name;
int bit;
#ifdef CONFIG_CPU
int ret;
s += sprintf(name, "rv");
bit = csr_read(misa) >> (sizeof(long) * 8 - 2);
s += sprintf(s, isa_bits[bit]);
supports_extension('i') ? *s++ = 'i' : 'r';
supports_extension('m') ? *s++ = 'm' : 'i';
supports_extension('a') ? *s++ = 'a' : 's';
supports_extension('f') ? *s++ = 'f' : 'c';
supports_extension('d') ? *s++ = 'd' : '-';
supports_extension('c') ? *s++ = 'c' : 'v';
*s++ = '\0';
printf("CPU: %s\n", name);
/* probe cpus so that RISC-V timer can be bound */
ret = cpu_probe_all();
if (ret)
return log_msg_ret("RISC-V cpus probe failed\n", ret);
#endif
return 0;
}
int arch_cpu_init_dm(void)
{
int ret;
ret = riscv_cpu_probe();
if (ret)
return ret;
/* Enable FPU */
if (supports_extension('d') || supports_extension('f')) {
csr_set(MODE_PREFIX(status), MSTATUS_FS);
csr_write(fcsr, 0);
}
if (CONFIG_IS_ENABLED(RISCV_MMODE)) {
/*
* Enable perf counters for cycle, time,
* and instret counters only
*/
csr_write(mcounteren, GENMASK(2, 0));
/* Disable paging */
if (supports_extension('s'))
csr_write(satp, 0);
}
return 0;
}
int arch_early_init_r(void)
{
return riscv_cpu_probe();
}

103
arch/riscv/cpu/mtrap.S Normal file
View File

@ -0,0 +1,103 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* M-mode Trap Handler Code for RISC-V Core
*
* Copyright (c) 2017 Microsemi Corporation.
* Copyright (c) 2017 Padmarao Begari <Padmarao.Begari@microsemi.com>
*
* Copyright (C) 2017 Andes Technology Corporation
* Rick Chen, Andes Technology Corporation <rick@andestech.com>
*
* Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
*/
#include <common.h>
#include <asm/encoding.h>
#ifdef CONFIG_32BIT
#define LREG lw
#define SREG sw
#define REGBYTES 4
#else
#define LREG ld
#define SREG sd
#define REGBYTES 8
#endif
.text
/* trap entry */
.align 2
.global trap_entry
trap_entry:
addi sp, sp, -32 * REGBYTES
SREG x1, 1 * REGBYTES(sp)
SREG x2, 2 * REGBYTES(sp)
SREG x3, 3 * REGBYTES(sp)
SREG x4, 4 * REGBYTES(sp)
SREG x5, 5 * REGBYTES(sp)
SREG x6, 6 * REGBYTES(sp)
SREG x7, 7 * REGBYTES(sp)
SREG x8, 8 * REGBYTES(sp)
SREG x9, 9 * REGBYTES(sp)
SREG x10, 10 * REGBYTES(sp)
SREG x11, 11 * REGBYTES(sp)
SREG x12, 12 * REGBYTES(sp)
SREG x13, 13 * REGBYTES(sp)
SREG x14, 14 * REGBYTES(sp)
SREG x15, 15 * REGBYTES(sp)
SREG x16, 16 * REGBYTES(sp)
SREG x17, 17 * REGBYTES(sp)
SREG x18, 18 * REGBYTES(sp)
SREG x19, 19 * REGBYTES(sp)
SREG x20, 20 * REGBYTES(sp)
SREG x21, 21 * REGBYTES(sp)
SREG x22, 22 * REGBYTES(sp)
SREG x23, 23 * REGBYTES(sp)
SREG x24, 24 * REGBYTES(sp)
SREG x25, 25 * REGBYTES(sp)
SREG x26, 26 * REGBYTES(sp)
SREG x27, 27 * REGBYTES(sp)
SREG x28, 28 * REGBYTES(sp)
SREG x29, 29 * REGBYTES(sp)
SREG x30, 30 * REGBYTES(sp)
SREG x31, 31 * REGBYTES(sp)
csrr a0, MODE_PREFIX(cause)
csrr a1, MODE_PREFIX(epc)
mv a2, sp
jal handle_trap
csrw MODE_PREFIX(epc), a0
LREG x1, 1 * REGBYTES(sp)
LREG x3, 3 * REGBYTES(sp)
LREG x4, 4 * REGBYTES(sp)
LREG x5, 5 * REGBYTES(sp)
LREG x6, 6 * REGBYTES(sp)
LREG x7, 7 * REGBYTES(sp)
LREG x8, 8 * REGBYTES(sp)
LREG x9, 9 * REGBYTES(sp)
LREG x10, 10 * REGBYTES(sp)
LREG x11, 11 * REGBYTES(sp)
LREG x12, 12 * REGBYTES(sp)
LREG x13, 13 * REGBYTES(sp)
LREG x14, 14 * REGBYTES(sp)
LREG x15, 15 * REGBYTES(sp)
LREG x16, 16 * REGBYTES(sp)
LREG x17, 17 * REGBYTES(sp)
LREG x18, 18 * REGBYTES(sp)
LREG x19, 19 * REGBYTES(sp)
LREG x20, 20 * REGBYTES(sp)
LREG x21, 21 * REGBYTES(sp)
LREG x22, 22 * REGBYTES(sp)
LREG x23, 23 * REGBYTES(sp)
LREG x24, 24 * REGBYTES(sp)
LREG x25, 25 * REGBYTES(sp)
LREG x26, 26 * REGBYTES(sp)
LREG x27, 27 * REGBYTES(sp)
LREG x28, 28 * REGBYTES(sp)
LREG x29, 29 * REGBYTES(sp)
LREG x30, 30 * REGBYTES(sp)
LREG x31, 31 * REGBYTES(sp)
LREG x2, 2 * REGBYTES(sp)
addi sp, sp, 32 * REGBYTES
MODE_PREFIX(ret)

View File

@ -0,0 +1,12 @@
# SPDX-License-Identifier: GPL-2.0+
#
# Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
config QEMU_RISCV
bool
select ARCH_EARLY_INIT_R
imply CPU
imply CPU_RISCV
imply RISCV_TIMER
imply SIFIVE_CLINT if RISCV_MMODE
imply CMD_CPU

View File

@ -4,6 +4,7 @@
*/
#include <common.h>
#include <dm.h>
/*
* cleanup_before_linux() is called just before we call linux
@ -19,3 +20,16 @@ int cleanup_before_linux(void)
return 0;
}
/* To enumerate devices on the /soc/ node, create a "simple-bus" driver */
static const struct udevice_id riscv_virtio_soc_ids[] = {
{ .compatible = "riscv-virtio-soc" },
{ }
};
U_BOOT_DRIVER(riscv_virtio_soc) = {
.name = "riscv_virtio_soc",
.id = UCLASS_SIMPLE_BUS,
.of_match = riscv_virtio_soc_ids,
.flags = DM_FLAG_PRE_RELOC,
};

View File

@ -14,6 +14,7 @@
#include <common.h>
#include <elf.h>
#include <asm/encoding.h>
#include <generated/asm-offsets.h>
#ifdef CONFIG_32BIT
#define LREG lw
@ -70,6 +71,9 @@ call_board_init_f_0:
jal board_init_f_init_reserve
/* save the boot hart id to global_data */
SREG s0, GD_BOOT_HART(gp)
mv a0, zero /* a0 <-- boot_flags = 0 */
la t5, board_init_f
jr t5 /* jump to board_init_f() */
@ -198,92 +202,3 @@ call_board_init_r:
* jump to it ...
*/
jr t4 /* jump to board_init_r() */
/*
* trap entry
*/
.align 2
trap_entry:
addi sp, sp, -32*REGBYTES
SREG x1, 1*REGBYTES(sp)
SREG x2, 2*REGBYTES(sp)
SREG x3, 3*REGBYTES(sp)
SREG x4, 4*REGBYTES(sp)
SREG x5, 5*REGBYTES(sp)
SREG x6, 6*REGBYTES(sp)
SREG x7, 7*REGBYTES(sp)
SREG x8, 8*REGBYTES(sp)
SREG x9, 9*REGBYTES(sp)
SREG x10, 10*REGBYTES(sp)
SREG x11, 11*REGBYTES(sp)
SREG x12, 12*REGBYTES(sp)
SREG x13, 13*REGBYTES(sp)
SREG x14, 14*REGBYTES(sp)
SREG x15, 15*REGBYTES(sp)
SREG x16, 16*REGBYTES(sp)
SREG x17, 17*REGBYTES(sp)
SREG x18, 18*REGBYTES(sp)
SREG x19, 19*REGBYTES(sp)
SREG x20, 20*REGBYTES(sp)
SREG x21, 21*REGBYTES(sp)
SREG x22, 22*REGBYTES(sp)
SREG x23, 23*REGBYTES(sp)
SREG x24, 24*REGBYTES(sp)
SREG x25, 25*REGBYTES(sp)
SREG x26, 26*REGBYTES(sp)
SREG x27, 27*REGBYTES(sp)
SREG x28, 28*REGBYTES(sp)
SREG x29, 29*REGBYTES(sp)
SREG x30, 30*REGBYTES(sp)
SREG x31, 31*REGBYTES(sp)
csrr a0, MODE_PREFIX(cause)
csrr a1, MODE_PREFIX(epc)
mv a2, sp
jal handle_trap
csrw MODE_PREFIX(epc), a0
#ifdef CONFIG_RISCV_SMODE
/*
* Remain in S-mode after sret
*/
li t0, SSTATUS_SPP
#else
/*
* Remain in M-mode after mret
*/
li t0, MSTATUS_MPP
#endif
csrs MODE_PREFIX(status), t0
LREG x1, 1*REGBYTES(sp)
LREG x2, 2*REGBYTES(sp)
LREG x3, 3*REGBYTES(sp)
LREG x4, 4*REGBYTES(sp)
LREG x5, 5*REGBYTES(sp)
LREG x6, 6*REGBYTES(sp)
LREG x7, 7*REGBYTES(sp)
LREG x8, 8*REGBYTES(sp)
LREG x9, 9*REGBYTES(sp)
LREG x10, 10*REGBYTES(sp)
LREG x11, 11*REGBYTES(sp)
LREG x12, 12*REGBYTES(sp)
LREG x13, 13*REGBYTES(sp)
LREG x14, 14*REGBYTES(sp)
LREG x15, 15*REGBYTES(sp)
LREG x16, 16*REGBYTES(sp)
LREG x17, 17*REGBYTES(sp)
LREG x18, 18*REGBYTES(sp)
LREG x19, 19*REGBYTES(sp)
LREG x20, 20*REGBYTES(sp)
LREG x21, 21*REGBYTES(sp)
LREG x22, 22*REGBYTES(sp)
LREG x23, 23*REGBYTES(sp)
LREG x24, 24*REGBYTES(sp)
LREG x25, 25*REGBYTES(sp)
LREG x26, 26*REGBYTES(sp)
LREG x27, 27*REGBYTES(sp)
LREG x28, 28*REGBYTES(sp)
LREG x29, 29*REGBYTES(sp)
LREG x30, 30*REGBYTES(sp)
LREG x31, 31*REGBYTES(sp)
addi sp, sp, 32*REGBYTES
MODE_PREFIX(ret)

View File

@ -1,229 +0,0 @@
/dts-v1/;
/ {
#address-cells = <2>;
#size-cells = <2>;
compatible = "andestech,ax25";
model = "andestech,ax25";
aliases {
uart0 = &serial0;
spi0 = &spi;
};
chosen {
bootargs = "console=ttyS0,38400n8 debug loglevel=7";
stdout-path = "uart0:38400n8";
};
cpus {
#address-cells = <1>;
#size-cells = <0>;
timebase-frequency = <60000000>;
CPU0: cpu@0 {
device_type = "cpu";
reg = <0>;
status = "okay";
compatible = "riscv";
riscv,isa = "rv64imafdc";
mmu-type = "riscv,sv39";
clock-frequency = <60000000>;
d-cache-size = <0x8000>;
d-cache-line-size = <32>;
CPU0_intc: interrupt-controller {
#interrupt-cells = <1>;
interrupt-controller;
compatible = "riscv,cpu-intc";
};
};
};
memory@0 {
device_type = "memory";
reg = <0x0 0x00000000 0x0 0x40000000>;
};
soc {
#address-cells = <2>;
#size-cells = <2>;
compatible = "andestech,riscv-ae350-soc";
ranges;
plic0: interrupt-controller@e4000000 {
compatible = "riscv,plic0";
#address-cells = <2>;
#interrupt-cells = <2>;
interrupt-controller;
reg = <0x0 0xe4000000 0x0 0x2000000>;
riscv,ndev=<71>;
interrupts-extended = <&CPU0_intc 11 &CPU0_intc 9>;
};
plic1: interrupt-controller@e6400000 {
compatible = "riscv,plic1";
#address-cells = <2>;
#interrupt-cells = <2>;
interrupt-controller;
reg = <0x0 0xe6400000 0x0 0x400000>;
riscv,ndev=<1>;
interrupts-extended = <&CPU0_intc 3>;
};
plmt0@e6000000 {
compatible = "riscv,plmt0";
interrupts-extended = <&CPU0_intc 7>;
reg = <0x0 0xe6000000 0x0 0x100000>;
};
};
spiclk: virt_100mhz {
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <100000000>;
};
timer0: timer@f0400000 {
compatible = "andestech,atcpit100";
reg = <0x0 0xf0400000 0x0 0x1000>;
clock-frequency = <60000000>;
interrupts = <3 4>;
interrupt-parent = <&plic0>;
};
serial0: serial@f0300000 {
compatible = "andestech,uart16550", "ns16550a";
reg = <0x0 0xf0300000 0x0 0x1000>;
interrupts = <9 4>;
clock-frequency = <19660800>;
reg-shift = <2>;
reg-offset = <32>;
no-loopback-test = <1>;
interrupt-parent = <&plic0>;
};
mac0: mac@e0100000 {
compatible = "andestech,atmac100";
reg = <0x0 0xe0100000 0x0 0x1000>;
interrupts = <19 4>;
interrupt-parent = <&plic0>;
};
mmc0: mmc@f0e00000 {
compatible = "andestech,atfsdc010";
max-frequency = <100000000>;
clock-freq-min-max = <400000 100000000>;
fifo-depth = <0x10>;
reg = <0x0 0xf0e00000 0x0 0x1000>;
interrupts = <18 4>;
cap-sd-highspeed;
interrupt-parent = <&plic0>;
};
dma0: dma@f0c00000 {
compatible = "andestech,atcdmac300";
reg = <0x0 0xf0c00000 0x0 0x1000>;
interrupts = <10 4 64 4 65 4 66 4 67 4 68 4 69 4 70 4 71 4>;
dma-channels = <8>;
interrupt-parent = <&plic0>;
};
lcd0: lcd@e0200000 {
compatible = "andestech,atflcdc100";
reg = <0x0 0xe0200000 0x0 0x1000>;
interrupts = <20 4>;
interrupt-parent = <&plic0>;
};
smc0: smc@e0400000 {
compatible = "andestech,atfsmc020";
reg = <0x0 0xe0400000 0x0 0x1000>;
};
snd0: snd@f0d00000 {
compatible = "andestech,atfac97";
reg = <0x0 0xf0d00000 0x0 0x1000>;
interrupts = <17 4>;
interrupt-parent = <&plic0>;
};
virtio_mmio@fe007000 {
interrupts = <0x17 0x4>;
interrupt-parent = <0x2>;
reg = <0x0 0xfe007000 0x0 0x1000>;
compatible = "virtio,mmio";
};
virtio_mmio@fe006000 {
interrupts = <0x16 0x4>;
interrupt-parent = <0x2>;
reg = <0x0 0xfe006000 0x0 0x1000>;
compatible = "virtio,mmio";
};
virtio_mmio@fe005000 {
interrupts = <0x15 0x4>;
interrupt-parent = <0x2>;
reg = <0x0 0xfe005000 0x0 0x1000>;
compatible = "virtio,mmio";
};
virtio_mmio@fe004000 {
interrupts = <0x14 0x4>;
interrupt-parent = <0x2>;
reg = <0x0 0xfe004000 0x0 0x1000>;
compatible = "virtio,mmio";
};
virtio_mmio@fe003000 {
interrupts = <0x13 0x4>;
interrupt-parent = <0x2>;
reg = <0x0 0xfe003000 0x0 0x1000>;
compatible = "virtio,mmio";
};
virtio_mmio@fe002000 {
interrupts = <0x12 0x4>;
interrupt-parent = <0x2>;
reg = <0x0 0xfe002000 0x0 0x1000>;
compatible = "virtio,mmio";
};
virtio_mmio@fe001000 {
interrupts = <0x11 0x4>;
interrupt-parent = <0x2>;
reg = <0x0 0xfe001000 0x0 0x1000>;
compatible = "virtio,mmio";
};
virtio_mmio@fe000000 {
interrupts = <0x10 0x4>;
interrupt-parent = <0x2>;
reg = <0x0 0xfe000000 0x0 0x1000>;
compatible = "virtio,mmio";
};
nor@0,0 {
compatible = "cfi-flash";
reg = <0x0 0x88000000 0x0 0x1000>;
bank-width = <2>;
device-width = <1>;
};
spi: spi@f0b00000 {
compatible = "andestech,atcspi200";
reg = <0x0 0xf0b00000 0x0 0x1000>;
#address-cells = <1>;
#size-cells = <0>;
num-cs = <1>;
clocks = <&spiclk>;
interrupts = <4 4>;
interrupt-parent = <&plic0>;
flash@0 {
compatible = "spi-flash";
spi-max-frequency = <50000000>;
reg = <0>;
spi-cpol;
spi-cpha;
};
};
};

View File

@ -61,10 +61,12 @@
#ifndef __ASSEMBLY__
#define xcsr(csr) #csr
#define csr_swap(csr, val) \
({ \
unsigned long __v = (unsigned long)(val); \
__asm__ __volatile__ ("csrrw %0, " #csr ", %1" \
__asm__ __volatile__ ("csrrw %0, " xcsr(csr) ", %1" \
: "=r" (__v) : "rK" (__v) \
: "memory"); \
__v; \
@ -73,7 +75,7 @@
#define csr_read(csr) \
({ \
register unsigned long __v; \
__asm__ __volatile__ ("csrr %0, " #csr \
__asm__ __volatile__ ("csrr %0, " xcsr(csr) \
: "=r" (__v) : \
: "memory"); \
__v; \
@ -82,7 +84,7 @@
#define csr_write(csr, val) \
({ \
unsigned long __v = (unsigned long)(val); \
__asm__ __volatile__ ("csrw " #csr ", %0" \
__asm__ __volatile__ ("csrw " xcsr(csr) ", %0" \
: : "rK" (__v) \
: "memory"); \
})
@ -90,7 +92,7 @@
#define csr_read_set(csr, val) \
({ \
unsigned long __v = (unsigned long)(val); \
__asm__ __volatile__ ("csrrs %0, " #csr ", %1" \
__asm__ __volatile__ ("csrrs %0, " xcsr(csr) ", %1" \
: "=r" (__v) : "rK" (__v) \
: "memory"); \
__v; \
@ -99,7 +101,7 @@
#define csr_set(csr, val) \
({ \
unsigned long __v = (unsigned long)(val); \
__asm__ __volatile__ ("csrs " #csr ", %0" \
__asm__ __volatile__ ("csrs " xcsr(csr) ", %0" \
: : "rK" (__v) \
: "memory"); \
})
@ -107,7 +109,7 @@
#define csr_read_clear(csr, val) \
({ \
unsigned long __v = (unsigned long)(val); \
__asm__ __volatile__ ("csrrc %0, " #csr ", %1" \
__asm__ __volatile__ ("csrrc %0, " xcsr(csr) ", %1" \
: "=r" (__v) : "rK" (__v) \
: "memory"); \
__v; \
@ -116,7 +118,7 @@
#define csr_clear(csr, val) \
({ \
unsigned long __v = (unsigned long)(val); \
__asm__ __volatile__ ("csrc " #csr ", %0" \
__asm__ __volatile__ ("csrc " xcsr(csr) ", %0" \
: : "rK" (__v) \
: "memory"); \
})

View File

@ -85,6 +85,21 @@
#define IRQ_COP 12
#define IRQ_HOST 13
#define CAUSE_MISALIGNED_FETCH 0
#define CAUSE_FETCH_ACCESS 1
#define CAUSE_ILLEGAL_INSTRUCTION 2
#define CAUSE_BREAKPOINT 3
#define CAUSE_MISALIGNED_LOAD 4
#define CAUSE_LOAD_ACCESS 5
#define CAUSE_MISALIGNED_STORE 6
#define CAUSE_STORE_ACCESS 7
#define CAUSE_USER_ECALL 8
#define CAUSE_SUPERVISOR_ECALL 9
#define CAUSE_MACHINE_ECALL 11
#define CAUSE_FETCH_PAGE_FAULT 12
#define CAUSE_LOAD_PAGE_FAULT 13
#define CAUSE_STORE_PAGE_FAULT 15
#define DEFAULT_RSTVEC 0x00001000
#define DEFAULT_NMIVEC 0x00001004
#define DEFAULT_MTVEC 0x00001010
@ -152,6 +167,227 @@
#define RISCV_PGSHIFT 12
#define RISCV_PGSIZE BIT(RISCV_PGSHIFT)
/* CSR numbers */
#define CSR_FFLAGS 0x1
#define CSR_FRM 0x2
#define CSR_FCSR 0x3
#define CSR_SSTATUS 0x100
#define CSR_SEDELEG 0x102
#define CSR_SIDELEG 0x103
#define CSR_SIE 0x104
#define CSR_STVEC 0x105
#define CSR_SCOUNTEREN 0x106
#define CSR_SSCRATCH 0x140
#define CSR_SEPC 0x141
#define CSR_SCAUSE 0x142
#define CSR_STVAL 0x143
#define CSR_SIP 0x144
#define CSR_SATP 0x180
#define CSR_MSTATUS 0x300
#define CSR_MISA 0x301
#define CSR_MEDELEG 0x302
#define CSR_MIDELEG 0x303
#define CSR_MIE 0x304
#define CSR_MTVEC 0x305
#define CSR_MCOUNTEREN 0x306
#define CSR_MHPMEVENT3 0x323
#define CSR_MHPMEVENT4 0x324
#define CSR_MHPMEVENT5 0x325
#define CSR_MHPMEVENT6 0x326
#define CSR_MHPMEVENT7 0x327
#define CSR_MHPMEVENT8 0x328
#define CSR_MHPMEVENT9 0x329
#define CSR_MHPMEVENT10 0x32a
#define CSR_MHPMEVENT11 0x32b
#define CSR_MHPMEVENT12 0x32c
#define CSR_MHPMEVENT13 0x32d
#define CSR_MHPMEVENT14 0x32e
#define CSR_MHPMEVENT15 0x32f
#define CSR_MHPMEVENT16 0x330
#define CSR_MHPMEVENT17 0x331
#define CSR_MHPMEVENT18 0x332
#define CSR_MHPMEVENT19 0x333
#define CSR_MHPMEVENT20 0x334
#define CSR_MHPMEVENT21 0x335
#define CSR_MHPMEVENT22 0x336
#define CSR_MHPMEVENT23 0x337
#define CSR_MHPMEVENT24 0x338
#define CSR_MHPMEVENT25 0x339
#define CSR_MHPMEVENT26 0x33a
#define CSR_MHPMEVENT27 0x33b
#define CSR_MHPMEVENT28 0x33c
#define CSR_MHPMEVENT29 0x33d
#define CSR_MHPMEVENT30 0x33e
#define CSR_MHPMEVENT31 0x33f
#define CSR_MSCRATCH 0x340
#define CSR_MEPC 0x341
#define CSR_MCAUSE 0x342
#define CSR_MTVAL 0x343
#define CSR_MIP 0x344
#define CSR_PMPCFG0 0x3a0
#define CSR_PMPCFG1 0x3a1
#define CSR_PMPCFG2 0x3a2
#define CSR_PMPCFG3 0x3a3
#define CSR_PMPADDR0 0x3b0
#define CSR_PMPADDR1 0x3b1
#define CSR_PMPADDR2 0x3b2
#define CSR_PMPADDR3 0x3b3
#define CSR_PMPADDR4 0x3b4
#define CSR_PMPADDR5 0x3b5
#define CSR_PMPADDR6 0x3b6
#define CSR_PMPADDR7 0x3b7
#define CSR_PMPADDR8 0x3b8
#define CSR_PMPADDR9 0x3b9
#define CSR_PMPADDR10 0x3ba
#define CSR_PMPADDR11 0x3bb
#define CSR_PMPADDR12 0x3bc
#define CSR_PMPADDR13 0x3bd
#define CSR_PMPADDR14 0x3be
#define CSR_PMPADDR15 0x3bf
#define CSR_TSELECT 0x7a0
#define CSR_TDATA1 0x7a1
#define CSR_TDATA2 0x7a2
#define CSR_TDATA3 0x7a3
#define CSR_DCSR 0x7b0
#define CSR_DPC 0x7b1
#define CSR_DSCRATCH 0x7b2
#define CSR_MCYCLE 0xb00
#define CSR_MINSTRET 0xb02
#define CSR_MHPMCOUNTER3 0xb03
#define CSR_MHPMCOUNTER4 0xb04
#define CSR_MHPMCOUNTER5 0xb05
#define CSR_MHPMCOUNTER6 0xb06
#define CSR_MHPMCOUNTER7 0xb07
#define CSR_MHPMCOUNTER8 0xb08
#define CSR_MHPMCOUNTER9 0xb09
#define CSR_MHPMCOUNTER10 0xb0a
#define CSR_MHPMCOUNTER11 0xb0b
#define CSR_MHPMCOUNTER12 0xb0c
#define CSR_MHPMCOUNTER13 0xb0d
#define CSR_MHPMCOUNTER14 0xb0e
#define CSR_MHPMCOUNTER15 0xb0f
#define CSR_MHPMCOUNTER16 0xb10
#define CSR_MHPMCOUNTER17 0xb11
#define CSR_MHPMCOUNTER18 0xb12
#define CSR_MHPMCOUNTER19 0xb13
#define CSR_MHPMCOUNTER20 0xb14
#define CSR_MHPMCOUNTER21 0xb15
#define CSR_MHPMCOUNTER22 0xb16
#define CSR_MHPMCOUNTER23 0xb17
#define CSR_MHPMCOUNTER24 0xb18
#define CSR_MHPMCOUNTER25 0xb19
#define CSR_MHPMCOUNTER26 0xb1a
#define CSR_MHPMCOUNTER27 0xb1b
#define CSR_MHPMCOUNTER28 0xb1c
#define CSR_MHPMCOUNTER29 0xb1d
#define CSR_MHPMCOUNTER30 0xb1e
#define CSR_MHPMCOUNTER31 0xb1f
#define CSR_MCYCLEH 0xb80
#define CSR_MINSTRETH 0xb82
#define CSR_MHPMCOUNTER3H 0xb83
#define CSR_MHPMCOUNTER4H 0xb84
#define CSR_MHPMCOUNTER5H 0xb85
#define CSR_MHPMCOUNTER6H 0xb86
#define CSR_MHPMCOUNTER7H 0xb87
#define CSR_MHPMCOUNTER8H 0xb88
#define CSR_MHPMCOUNTER9H 0xb89
#define CSR_MHPMCOUNTER10H 0xb8a
#define CSR_MHPMCOUNTER11H 0xb8b
#define CSR_MHPMCOUNTER12H 0xb8c
#define CSR_MHPMCOUNTER13H 0xb8d
#define CSR_MHPMCOUNTER14H 0xb8e
#define CSR_MHPMCOUNTER15H 0xb8f
#define CSR_MHPMCOUNTER16H 0xb90
#define CSR_MHPMCOUNTER17H 0xb91
#define CSR_MHPMCOUNTER18H 0xb92
#define CSR_MHPMCOUNTER19H 0xb93
#define CSR_MHPMCOUNTER20H 0xb94
#define CSR_MHPMCOUNTER21H 0xb95
#define CSR_MHPMCOUNTER22H 0xb96
#define CSR_MHPMCOUNTER23H 0xb97
#define CSR_MHPMCOUNTER24H 0xb98
#define CSR_MHPMCOUNTER25H 0xb99
#define CSR_MHPMCOUNTER26H 0xb9a
#define CSR_MHPMCOUNTER27H 0xb9b
#define CSR_MHPMCOUNTER28H 0xb9c
#define CSR_MHPMCOUNTER29H 0xb9d
#define CSR_MHPMCOUNTER30H 0xb9e
#define CSR_MHPMCOUNTER31H 0xb9f
#define CSR_CYCLE 0xc00
#define CSR_TIME 0xc01
#define CSR_INSTRET 0xc02
#define CSR_HPMCOUNTER3 0xc03
#define CSR_HPMCOUNTER4 0xc04
#define CSR_HPMCOUNTER5 0xc05
#define CSR_HPMCOUNTER6 0xc06
#define CSR_HPMCOUNTER7 0xc07
#define CSR_HPMCOUNTER8 0xc08
#define CSR_HPMCOUNTER9 0xc09
#define CSR_HPMCOUNTER10 0xc0a
#define CSR_HPMCOUNTER11 0xc0b
#define CSR_HPMCOUNTER12 0xc0c
#define CSR_HPMCOUNTER13 0xc0d
#define CSR_HPMCOUNTER14 0xc0e
#define CSR_HPMCOUNTER15 0xc0f
#define CSR_HPMCOUNTER16 0xc10
#define CSR_HPMCOUNTER17 0xc11
#define CSR_HPMCOUNTER18 0xc12
#define CSR_HPMCOUNTER19 0xc13
#define CSR_HPMCOUNTER20 0xc14
#define CSR_HPMCOUNTER21 0xc15
#define CSR_HPMCOUNTER22 0xc16
#define CSR_HPMCOUNTER23 0xc17
#define CSR_HPMCOUNTER24 0xc18
#define CSR_HPMCOUNTER25 0xc19
#define CSR_HPMCOUNTER26 0xc1a
#define CSR_HPMCOUNTER27 0xc1b
#define CSR_HPMCOUNTER28 0xc1c
#define CSR_HPMCOUNTER29 0xc1d
#define CSR_HPMCOUNTER30 0xc1e
#define CSR_HPMCOUNTER31 0xc1f
#define CSR_CYCLEH 0xc80
#define CSR_TIMEH 0xc81
#define CSR_INSTRETH 0xc82
#define CSR_HPMCOUNTER3H 0xc83
#define CSR_HPMCOUNTER4H 0xc84
#define CSR_HPMCOUNTER5H 0xc85
#define CSR_HPMCOUNTER6H 0xc86
#define CSR_HPMCOUNTER7H 0xc87
#define CSR_HPMCOUNTER8H 0xc88
#define CSR_HPMCOUNTER9H 0xc89
#define CSR_HPMCOUNTER10H 0xc8a
#define CSR_HPMCOUNTER11H 0xc8b
#define CSR_HPMCOUNTER12H 0xc8c
#define CSR_HPMCOUNTER13H 0xc8d
#define CSR_HPMCOUNTER14H 0xc8e
#define CSR_HPMCOUNTER15H 0xc8f
#define CSR_HPMCOUNTER16H 0xc90
#define CSR_HPMCOUNTER17H 0xc91
#define CSR_HPMCOUNTER18H 0xc92
#define CSR_HPMCOUNTER19H 0xc93
#define CSR_HPMCOUNTER20H 0xc94
#define CSR_HPMCOUNTER21H 0xc95
#define CSR_HPMCOUNTER22H 0xc96
#define CSR_HPMCOUNTER23H 0xc97
#define CSR_HPMCOUNTER24H 0xc98
#define CSR_HPMCOUNTER25H 0xc99
#define CSR_HPMCOUNTER26H 0xc9a
#define CSR_HPMCOUNTER27H 0xc9b
#define CSR_HPMCOUNTER28H 0xc9c
#define CSR_HPMCOUNTER29H 0xc9d
#define CSR_HPMCOUNTER30H 0xc9e
#define CSR_HPMCOUNTER31H 0xc9f
#define CSR_MVENDORID 0xf11
#define CSR_MARCHID 0xf12
#define CSR_MIMPID 0xf13
#define CSR_MHARTID 0xf14
#endif /* __riscv */
#endif /* RISCV_CSR_ENCODING_H */

View File

@ -12,6 +12,10 @@
/* Architecture-specific global data */
struct arch_global_data {
long boot_hart; /* boot hart id */
#ifdef CONFIG_SIFIVE_CLINT
void __iomem *clint; /* clint base address */
#endif
};
#include <asm-generic/global_data.h>

View File

@ -0,0 +1,19 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
*/
#ifndef _ASM_SYSCON_H
#define _ASM_SYSCON_H
/*
* System controllers in a RISC-V system
*
* So far only SiFive's Core Local Interruptor (CLINT) is defined.
*/
enum {
RISCV_NONE,
RISCV_SYSCON_CLINT, /* Core Local Interruptor (CLINT) */
};
#endif /* _ASM_SYSCON_H */

View File

@ -9,6 +9,8 @@
obj-$(CONFIG_CMD_BOOTM) += bootm.o
obj-$(CONFIG_CMD_GO) += boot.o
obj-y += cache.o
obj-$(CONFIG_RISCV_RDTIME) += rdtime.o
obj-$(CONFIG_SIFIVE_CLINT) += sifive_clint.o
obj-y += interrupts.o
obj-y += reset.o
obj-y += setjmp.o

View File

@ -0,0 +1,19 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
*
* From arch/x86/lib/asm-offsets.c
*
* This program is used to generate definitions needed by
* assembly language modules.
*/
#include <common.h>
#include <linux/kbuild.h>
int main(void)
{
DEFINE(GD_BOOT_HART, offsetof(gd_t, arch.boot_hart));
return 0;
}

View File

@ -93,7 +93,7 @@ static void boot_jump_linux(bootm_headers_t *images, int flag)
if (!fake) {
if (IMAGE_ENABLE_OF_LIBFDT && images->ft_len)
kernel(csr_read(mhartid), images->ft_addr);
kernel(gd->arch.boot_hart, images->ft_addr);
}
}

View File

@ -12,7 +12,36 @@
#include <asm/system.h>
#include <asm/encoding.h>
static void _exit_trap(ulong code, ulong epc, struct pt_regs *regs);
static void _exit_trap(ulong code, ulong epc, struct pt_regs *regs)
{
static const char * const exception_code[] = {
"Instruction address misaligned",
"Instruction access fault",
"Illegal instruction",
"Breakpoint",
"Load address misaligned",
"Load access fault",
"Store/AMO address misaligned",
"Store/AMO access fault",
"Environment call from U-mode",
"Environment call from S-mode",
"Reserved",
"Environment call from M-mode",
"Instruction page fault",
"Load page fault",
"Reserved",
"Store/AMO page fault",
};
if (code < ARRAY_SIZE(exception_code)) {
printf("exception code: %ld , %s , epc %lx , ra %lx\n",
code, exception_code[code], epc, regs->ra);
} else {
printf("Reserved\n");
}
hang();
}
int interrupt_init(void)
{
@ -72,34 +101,3 @@ __attribute__((weak)) void external_interrupt(struct pt_regs *regs)
__attribute__((weak)) void timer_interrupt(struct pt_regs *regs)
{
}
static void _exit_trap(ulong code, ulong epc, struct pt_regs *regs)
{
static const char * const exception_code[] = {
"Instruction address misaligned",
"Instruction access fault",
"Illegal instruction",
"Breakpoint",
"Load address misaligned",
"Load access fault",
"Store/AMO address misaligned",
"Store/AMO access fault",
"Environment call from U-mode",
"Environment call from S-mode",
"Reserved",
"Environment call from M-mode",
"Instruction page fault",
"Load page fault",
"Reserved",
"Store/AMO page fault",
};
if (code < ARRAY_SIZE(exception_code)) {
printf("exception code: %ld , %s , epc %lx , ra %lx\n",
code, exception_code[code], epc, regs->ra);
} else {
printf("Reserved\n");
}
hang();
}

38
arch/riscv/lib/rdtime.c Normal file
View File

@ -0,0 +1,38 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2018, Anup Patel <anup@brainfault.org>
* Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
*
* The riscv_get_time() API implementation that is using the
* standard rdtime instruction.
*/
#include <common.h>
/* Implement the API required by RISC-V timer driver */
int riscv_get_time(u64 *time)
{
#ifdef CONFIG_64BIT
u64 n;
__asm__ __volatile__ (
"rdtime %0"
: "=r" (n));
*time = n;
#else
u32 lo, hi, tmp;
__asm__ __volatile__ (
"1:\n"
"rdtimeh %0\n"
"rdtime %1\n"
"rdtimeh %2\n"
"bne %0, %2, 1b"
: "=&r" (hi), "=&r" (lo), "=&r" (tmp));
*time = ((u64)hi << 32) | lo;
#endif
return 0;
}

View File

@ -0,0 +1,84 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
*
* U-Boot syscon driver for SiFive's Core Local Interruptor (CLINT).
* The CLINT block holds memory-mapped control and status registers
* associated with software and timer interrupts.
*/
#include <common.h>
#include <dm.h>
#include <regmap.h>
#include <syscon.h>
#include <asm/io.h>
#include <asm/syscon.h>
/* MSIP registers */
#define MSIP_REG(base, hart) ((ulong)(base) + (hart) * 4)
/* mtime compare register */
#define MTIMECMP_REG(base, hart) ((ulong)(base) + 0x4000 + (hart) * 8)
/* mtime register */
#define MTIME_REG(base) ((ulong)(base) + 0xbff8)
DECLARE_GLOBAL_DATA_PTR;
#define CLINT_BASE_GET(void) \
do { \
long *ret; \
\
if (!gd->arch.clint) { \
ret = syscon_get_first_range(RISCV_SYSCON_CLINT); \
if (IS_ERR(ret)) \
return PTR_ERR(ret); \
gd->arch.clint = ret; \
} \
} while (0)
int riscv_get_time(u64 *time)
{
CLINT_BASE_GET();
*time = readq((void __iomem *)MTIME_REG(gd->arch.clint));
return 0;
}
int riscv_set_timecmp(int hart, u64 cmp)
{
CLINT_BASE_GET();
writeq(cmp, (void __iomem *)MTIMECMP_REG(gd->arch.clint, hart));
return 0;
}
int riscv_send_ipi(int hart)
{
CLINT_BASE_GET();
writel(1, (void __iomem *)MSIP_REG(gd->arch.clint, hart));
return 0;
}
int riscv_clear_ipi(int hart)
{
CLINT_BASE_GET();
writel(0, (void __iomem *)MSIP_REG(gd->arch.clint, hart));
return 0;
}
static const struct udevice_id sifive_clint_ids[] = {
{ .compatible = "riscv,clint0", .data = RISCV_SYSCON_CLINT },
{ }
};
U_BOOT_DRIVER(sifive_clint) = {
.name = "sifive_clint",
.id = UCLASS_SYSCON,
.of_match = sifive_clint_ids,
.flags = DM_FLAG_PRE_RELOC,
};

View File

@ -21,4 +21,8 @@ config ENV_SIZE
config ENV_OFFSET
default 0x140000 if ENV_IS_IN_SPI_FLASH
config BOARD_SPECIFIC_OPTIONS # dummy
def_bool y
select RISCV_NDS
endif

View File

@ -3,6 +3,5 @@ M: Rick Chen <rick@andestech.com>
S: Maintained
F: board/AndesTech/ax25-ae350/
F: include/configs/ax25-ae350.h
F: configs/a25-ae350_32_defconfig
F: configs/ax25-ae350_64_defconfig
F: configs/ax25-ae350_defconfig
F: configs/ae350_rv32_defconfig
F: configs/ae350_rv64_defconfig

View File

@ -18,6 +18,7 @@ config SYS_TEXT_BASE
config BOARD_SPECIFIC_OPTIONS # dummy
def_bool y
select QEMU_RISCV
imply SYS_NS16550
imply VIRTIO_MMIO
imply VIRTIO_NET
@ -32,5 +33,6 @@ config BOARD_SPECIFIC_OPTIONS # dummy
imply CMD_FAT
imply BOARD_LATE_INIT
imply OF_BOARD_SETUP
imply SIFIVE_SERIAL
endif

View File

@ -25,7 +25,7 @@ Build and boot steps
build:
1. Prepare the toolchains and make sure the $PATH to toolchains is correct.
2. Use `make ax25-ae350_defconfig` in u-boot root to build the image.
2. Use `make ae350_rv[32|64]_defconfig` in u-boot root to build the image for 32 or 64 bit.
Verification
====================

View File

@ -13,3 +13,9 @@ config CPU_MPC83XX
select CLK_MPC83XX
help
Support CPU cores for SoCs of the MPC83xx series.
config CPU_RISCV
bool "Enable RISC-V CPU driver"
depends on CPU && RISCV
help
Support CPU cores for RISC-V architecture.

View File

@ -8,4 +8,5 @@ obj-$(CONFIG_CPU) += cpu-uclass.o
obj-$(CONFIG_ARCH_BMIPS) += bmips_cpu.o
obj-$(CONFIG_CPU_MPC83XX) += mpc83xx_cpu.o
obj-$(CONFIG_CPU_RISCV) += riscv_cpu.o
obj-$(CONFIG_SANDBOX) += cpu_sandbox.o

116
drivers/cpu/riscv_cpu.c Normal file
View File

@ -0,0 +1,116 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
*/
#include <common.h>
#include <cpu.h>
#include <dm.h>
#include <errno.h>
#include <dm/device-internal.h>
#include <dm/lists.h>
static int riscv_cpu_get_desc(struct udevice *dev, char *buf, int size)
{
const char *isa;
isa = dev_read_string(dev, "riscv,isa");
if (size < (strlen(isa) + 1))
return -ENOSPC;
strcpy(buf, isa);
return 0;
}
static int riscv_cpu_get_info(struct udevice *dev, struct cpu_info *info)
{
const char *mmu;
dev_read_u32(dev, "clock-frequency", (u32 *)&info->cpu_freq);
mmu = dev_read_string(dev, "mmu-type");
if (!mmu)
info->features |= BIT(CPU_FEAT_MMU);
return 0;
}
static int riscv_cpu_get_count(struct udevice *dev)
{
ofnode node;
int num = 0;
ofnode_for_each_subnode(node, dev_ofnode(dev->parent)) {
const char *device_type;
device_type = ofnode_read_string(node, "device_type");
if (!device_type)
continue;
if (strcmp(device_type, "cpu") == 0)
num++;
}
return num;
}
static int riscv_cpu_bind(struct udevice *dev)
{
struct cpu_platdata *plat = dev_get_parent_platdata(dev);
struct driver *drv;
int ret;
/* save the hart id */
plat->cpu_id = dev_read_addr(dev);
/* first examine the property in current cpu node */
ret = dev_read_u32(dev, "timebase-frequency", &plat->timebase_freq);
/* if not found, then look at the parent /cpus node */
if (ret)
dev_read_u32(dev->parent, "timebase-frequency",
&plat->timebase_freq);
/*
* Bind riscv-timer driver on hart 0
*
* We only instantiate one timer device which is enough for U-Boot.
* Pass the "timebase-frequency" value as the driver data for the
* timer device.
*
* Return value is not checked since it's possible that the timer
* driver is not included.
*/
if (!plat->cpu_id && plat->timebase_freq) {
drv = lists_driver_lookup_name("riscv_timer");
if (!drv) {
debug("Cannot find the timer driver, not included?\n");
return 0;
}
device_bind_with_driver_data(dev, drv, "riscv_timer",
plat->timebase_freq, ofnode_null(),
NULL);
}
return 0;
}
static const struct cpu_ops riscv_cpu_ops = {
.get_desc = riscv_cpu_get_desc,
.get_info = riscv_cpu_get_info,
.get_count = riscv_cpu_get_count,
};
static const struct udevice_id riscv_cpu_ids[] = {
{ .compatible = "riscv" },
{ }
};
U_BOOT_DRIVER(riscv_cpu) = {
.name = "riscv_cpu",
.id = UCLASS_CPU,
.of_match = riscv_cpu_ids,
.bind = riscv_cpu_bind,
.ops = &riscv_cpu_ops,
.flags = DM_FLAG_PRE_RELOC,
};

View File

@ -343,6 +343,13 @@ config DEBUG_UART_SANDBOX
start up driver model. The driver will be available until the real
driver model serial is running.
config DEBUG_UART_SIFIVE
bool "SiFive UART"
help
Select this to enable a debug UART using the serial_sifive driver. You
will need to provide parameters to make this work. The driver will
be available until the real driver-model serial is running.
config DEBUG_UART_STM32
bool "STMicroelectronics STM32"
depends on STM32_SERIAL
@ -679,6 +686,12 @@ config PXA_SERIAL
If you have a machine based on a Marvell XScale PXA2xx CPU you
can enable its onboard serial ports by enabling this option.
config SIFIVE_SERIAL
bool "SiFive UART support"
depends on DM_SERIAL
help
This driver supports the SiFive UART. If unsure say N.
config STI_ASC_SERIAL
bool "STMicroelectronics on-chip UART"
depends on DM_SERIAL && ARCH_STI

View File

@ -67,6 +67,7 @@ obj-$(CONFIG_NULLDEV_SERIAL) += serial_nulldev.o
obj-$(CONFIG_OWL_SERIAL) += serial_owl.o
obj-$(CONFIG_OMAP_SERIAL) += serial_omap.o
obj-$(CONFIG_MTK_SERIAL) += serial_mtk.o
obj-$(CONFIG_SIFIVE_SERIAL) += serial_sifive.o
ifndef CONFIG_SPL_BUILD
obj-$(CONFIG_USB_TTY) += usbtty.o

View File

@ -0,0 +1,215 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2018 Anup Patel <anup@brainfault.org>
*/
#include <clk.h>
#include <common.h>
#include <debug_uart.h>
#include <dm.h>
#include <errno.h>
#include <fdtdec.h>
#include <watchdog.h>
#include <asm/io.h>
#include <linux/compiler.h>
#include <serial.h>
DECLARE_GLOBAL_DATA_PTR;
#define UART_TXFIFO_FULL 0x80000000
#define UART_RXFIFO_EMPTY 0x80000000
#define UART_RXFIFO_DATA 0x000000ff
#define UART_TXCTRL_TXEN 0x1
#define UART_RXCTRL_RXEN 0x1
struct uart_sifive {
u32 txfifo;
u32 rxfifo;
u32 txctrl;
u32 rxctrl;
u32 ie;
u32 ip;
u32 div;
};
struct sifive_uart_platdata {
unsigned int clock;
int saved_input_char;
struct uart_sifive *regs;
};
/* Set up the baud rate in gd struct */
static void _sifive_serial_setbrg(struct uart_sifive *regs,
unsigned long clock, unsigned long baud)
{
writel((u32)((clock / baud) - 1), &regs->div);
}
static void _sifive_serial_init(struct uart_sifive *regs)
{
writel(UART_TXCTRL_TXEN, &regs->txctrl);
writel(UART_RXCTRL_RXEN, &regs->rxctrl);
writel(0, &regs->ie);
}
static int _sifive_serial_putc(struct uart_sifive *regs, const char c)
{
if (readl(&regs->txfifo) & UART_TXFIFO_FULL)
return -EAGAIN;
writel(c, &regs->txfifo);
return 0;
}
static int _sifive_serial_getc(struct uart_sifive *regs)
{
int ch = readl(&regs->rxfifo);
if (ch & UART_RXFIFO_EMPTY)
return -EAGAIN;
ch &= UART_RXFIFO_DATA;
return (!ch) ? -EAGAIN : ch;
}
static int sifive_serial_setbrg(struct udevice *dev, int baudrate)
{
int err;
struct clk clk;
struct sifive_uart_platdata *platdata = dev_get_platdata(dev);
err = clk_get_by_index(dev, 0, &clk);
if (!err) {
err = clk_get_rate(&clk);
if (!IS_ERR_VALUE(err))
platdata->clock = err;
} else if (err != -ENOENT && err != -ENODEV && err != -ENOSYS) {
debug("SiFive UART failed to get clock\n");
return err;
}
if (!platdata->clock)
platdata->clock = dev_read_u32_default(dev, "clock-frequency", 0);
if (!platdata->clock) {
debug("SiFive UART clock not defined\n");
return -EINVAL;
}
_sifive_serial_setbrg(platdata->regs, platdata->clock, baudrate);
return 0;
}
static int sifive_serial_probe(struct udevice *dev)
{
struct sifive_uart_platdata *platdata = dev_get_platdata(dev);
/* No need to reinitialize the UART after relocation */
if (gd->flags & GD_FLG_RELOC)
return 0;
platdata->saved_input_char = 0;
_sifive_serial_init(platdata->regs);
return 0;
}
static int sifive_serial_getc(struct udevice *dev)
{
int c;
struct sifive_uart_platdata *platdata = dev_get_platdata(dev);
struct uart_sifive *regs = platdata->regs;
if (platdata->saved_input_char > 0) {
c = platdata->saved_input_char;
platdata->saved_input_char = 0;
return c;
}
while ((c = _sifive_serial_getc(regs)) == -EAGAIN) ;
return c;
}
static int sifive_serial_putc(struct udevice *dev, const char ch)
{
int rc;
struct sifive_uart_platdata *platdata = dev_get_platdata(dev);
while ((rc = _sifive_serial_putc(platdata->regs, ch)) == -EAGAIN) ;
return rc;
}
static int sifive_serial_pending(struct udevice *dev, bool input)
{
struct sifive_uart_platdata *platdata = dev_get_platdata(dev);
struct uart_sifive *regs = platdata->regs;
if (input) {
if (platdata->saved_input_char > 0)
return 1;
platdata->saved_input_char = _sifive_serial_getc(regs);
return (platdata->saved_input_char > 0) ? 1 : 0;
} else {
return !!(readl(&regs->txfifo) & UART_TXFIFO_FULL);
}
}
static int sifive_serial_ofdata_to_platdata(struct udevice *dev)
{
struct sifive_uart_platdata *platdata = dev_get_platdata(dev);
platdata->regs = (struct uart_sifive *)dev_read_addr(dev);
if (IS_ERR(platdata->regs))
return PTR_ERR(platdata->regs);
return 0;
}
static const struct dm_serial_ops sifive_serial_ops = {
.putc = sifive_serial_putc,
.getc = sifive_serial_getc,
.pending = sifive_serial_pending,
.setbrg = sifive_serial_setbrg,
};
static const struct udevice_id sifive_serial_ids[] = {
{ .compatible = "sifive,uart0" },
{ }
};
U_BOOT_DRIVER(serial_sifive) = {
.name = "serial_sifive",
.id = UCLASS_SERIAL,
.of_match = sifive_serial_ids,
.ofdata_to_platdata = sifive_serial_ofdata_to_platdata,
.platdata_auto_alloc_size = sizeof(struct sifive_uart_platdata),
.probe = sifive_serial_probe,
.ops = &sifive_serial_ops,
};
#ifdef CONFIG_DEBUG_UART_SIFIVE
static inline void _debug_uart_init(void)
{
struct uart_sifive *regs =
(struct uart_sifive *)CONFIG_DEBUG_UART_BASE;
_sifive_serial_setbrg(regs, CONFIG_DEBUG_UART_CLOCK,
CONFIG_BAUDRATE);
_sifive_serial_init(regs);
}
static inline void _debug_uart_putc(int ch)
{
struct uart_sifive *regs =
(struct uart_sifive *)CONFIG_DEBUG_UART_BASE;
while (_sifive_serial_putc(regs, ch) == -EAGAIN)
WATCHDOG_RESET();
}
DEBUG_UART_FUNCS
#endif

View File

@ -126,6 +126,13 @@ config OMAP_TIMER
help
Select this to enable an timer for Omap devices.
config RISCV_TIMER
bool "RISC-V timer support"
depends on TIMER && RISCV
help
Select this to enable support for the timer as defined
by the RISC-V privileged architecture spec.
config ROCKCHIP_TIMER
bool "Rockchip timer support"
depends on TIMER

View File

@ -13,6 +13,7 @@ obj-$(CONFIG_CADENCE_TTC_TIMER) += cadence-ttc.o
obj-$(CONFIG_DESIGNWARE_APB_TIMER) += dw-apb-timer.o
obj-$(CONFIG_MPC83XX_TIMER) += mpc83xx_timer.o
obj-$(CONFIG_OMAP_TIMER) += omap-timer.o
obj-$(CONFIG_RISCV_TIMER) += riscv_timer.o
obj-$(CONFIG_ROCKCHIP_TIMER) += rockchip_timer.o
obj-$(CONFIG_SANDBOX_TIMER) += sandbox_timer.o
obj-$(CONFIG_STI_TIMER) += sti-timer.o

View File

@ -0,0 +1,56 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
*
* RISC-V privileged architecture defined generic timer driver
*
* This driver relies on RISC-V platform codes to provide the essential API
* riscv_get_time() which is supposed to return the timer counter as defined
* by the RISC-V privileged architecture spec.
*
* This driver can be used in both M-mode and S-mode U-Boot.
*/
#include <common.h>
#include <dm.h>
#include <errno.h>
#include <timer.h>
#include <asm/io.h>
/**
* riscv_get_time() - get the timer counter
*
* Platform codes should provide this API in order to make this driver function.
*
* @time: the 64-bit timer count as defined by the RISC-V privileged
* architecture spec.
* @return: 0 on success, -ve on error.
*/
extern int riscv_get_time(u64 *time);
static int riscv_timer_get_count(struct udevice *dev, u64 *count)
{
return riscv_get_time(count);
}
static int riscv_timer_probe(struct udevice *dev)
{
struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
/* clock frequency was passed from the cpu driver as driver data */
uc_priv->clock_rate = dev->driver_data;
return 0;
}
static const struct timer_ops riscv_timer_ops = {
.get_count = riscv_timer_get_count,
};
U_BOOT_DRIVER(riscv_timer) = {
.name = "riscv_timer",
.id = UCLASS_TIMER,
.probe = riscv_timer_probe,
.ops = &riscv_timer_ops,
.flags = DM_FLAG_PRE_RELOC,
};

View File

@ -14,6 +14,8 @@
* @device_id: Driver-defined device identifier
* @family: DMTF CPU Family identifier
* @id: DMTF CPU Processor identifier
* @timebase_freq: the current frequency at which the cpu timer timebase
* registers are updated (in Hz)
*
* This can be accessed with dev_get_parent_platdata() for any UCLASS_CPU
* device.
@ -24,6 +26,7 @@ struct cpu_platdata {
ulong device_id;
u16 family;
u32 id[2];
u32 timebase_freq;
};
/* CPU features - mostly just a placeholder for now */