From 8176ea4d58d18740e344dd4b587433c9f7772ac1 Mon Sep 17 00:00:00 2001 From: Lukas Auer Date: Wed, 12 Dec 2018 06:12:23 -0800 Subject: [PATCH 01/29] riscv: add Kconfig entries for the code model RISC-V has two code models, medium low (medlow) and medium any (medany). Medlow limits addressable memory to a single 2 GiB range between the absolute addresses -2 GiB and +2 GiB. Medany limits addressable memory to any single 2 GiB address range. By default, medlow is selected for U-Boot on both 32-bit and 64-bit systems. The -mcmodel compiler flag is selected according to the Kconfig configuration. Signed-off-by: Lukas Auer [bmeng: adjust to make medlow the default code model for U-Boot] Signed-off-by: Bin Meng Reviewed-by: Anup Patel --- arch/riscv/Kconfig | 18 ++++++++++++++++++ arch/riscv/Makefile | 9 ++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 732a357a99..6d85ac96f8 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -44,6 +44,24 @@ 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 + config RISCV_ISA_C bool "Emit compressed instructions" default y diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile index 55d7c6550e..0b80eb8d86 100644 --- a/arch/riscv/Makefile +++ b/arch/riscv/Makefile @@ -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) From b859694776a522da9fd7d3ca2d8c027d6776c791 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 12 Dec 2018 06:12:24 -0800 Subject: [PATCH 02/29] dm: cpu: Add timebase frequency to the platdata This adds a timebase_freq member to the 'struct cpu_platdata', to hold the "timebase-frequency" value in the cpu or /cpus node. Signed-off-by: Bin Meng Reviewed-by: Simon Glass Reviewed-by: Lukas Auer Reviewed-by: Anup Patel --- include/cpu.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/cpu.h b/include/cpu.h index 367c5f46a0..28dd48feb8 100644 --- a/include/cpu.h +++ b/include/cpu.h @@ -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 */ From 27dc2c130e29093ba88630e8947d189641bda442 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 12 Dec 2018 06:12:25 -0800 Subject: [PATCH 03/29] riscv: qemu: Create a simple-bus driver for the soc node To enumerate devices on the /soc/ node, create a "simple-bus" driver to match "riscv-virtio-soc". Signed-off-by: Bin Meng Reviewed-by: Lukas Auer Reviewed-by: Anup Patel --- arch/riscv/cpu/qemu/cpu.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/arch/riscv/cpu/qemu/cpu.c b/arch/riscv/cpu/qemu/cpu.c index 25d97d0b41..ad2950ce40 100644 --- a/arch/riscv/cpu/qemu/cpu.c +++ b/arch/riscv/cpu/qemu/cpu.c @@ -4,6 +4,7 @@ */ #include +#include /* * 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, +}; From 833508c05c1309624cd397dbea2714b723d58c35 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 12 Dec 2018 06:12:26 -0800 Subject: [PATCH 04/29] cpu: Add a RISC-V CPU driver This adds a driver for RISC-V CPU. Note the driver will bind a RISC-V timer driver if "timebase-frequency" property is present in the device tree. Signed-off-by: Bin Meng Reviewed-by: Lukas Auer Reviewed-by: Anup Patel --- drivers/cpu/Kconfig | 6 +++ drivers/cpu/Makefile | 1 + drivers/cpu/riscv_cpu.c | 116 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 123 insertions(+) create mode 100644 drivers/cpu/riscv_cpu.c diff --git a/drivers/cpu/Kconfig b/drivers/cpu/Kconfig index d4052005e2..3d5729f6dc 100644 --- a/drivers/cpu/Kconfig +++ b/drivers/cpu/Kconfig @@ -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. diff --git a/drivers/cpu/Makefile b/drivers/cpu/Makefile index 858b03755f..be0300cd4a 100644 --- a/drivers/cpu/Makefile +++ b/drivers/cpu/Makefile @@ -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 diff --git a/drivers/cpu/riscv_cpu.c b/drivers/cpu/riscv_cpu.c new file mode 100644 index 0000000000..5e15df590e --- /dev/null +++ b/drivers/cpu/riscv_cpu.c @@ -0,0 +1,116 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2018, Bin Meng + */ + +#include +#include +#include +#include +#include +#include + +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, +}; From 60262cd041529cabd5fbabb6f2077495fa922fca Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 12 Dec 2018 06:12:27 -0800 Subject: [PATCH 05/29] timer: Add generic driver for RISC-V privileged architecture defined timer RISC-V privileged architecture v1.10 defines a real-time counter, exposed as a memory-mapped machine-mode register - mtime. mtime must run at constant frequency, and the platform must provide a mechanism for determining the timebase of mtime. The mtime register has a 64-bit precision on all RV32, RV64, and RV128 systems. Different platform may have different implementation of the mtime block hence an API riscv_get_time() is required by this driver for platform codes to hide such implementation details. For example, on some platforms mtime is provided by the CLINT module, while on some other platforms a simple 'rdtime' can be used to get the timer counter. With this timer driver the U-Boot timer functionalities like delay works correctly now. Signed-off-by: Bin Meng Reviewed-by: Lukas Auer Reviewed-by: Anup Patel --- drivers/timer/Kconfig | 7 +++++ drivers/timer/Makefile | 1 + drivers/timer/riscv_timer.c | 56 +++++++++++++++++++++++++++++++++++++ 3 files changed, 64 insertions(+) create mode 100644 drivers/timer/riscv_timer.c diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig index b0e6f32f0b..df37a798bd 100644 --- a/drivers/timer/Kconfig +++ b/drivers/timer/Kconfig @@ -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 diff --git a/drivers/timer/Makefile b/drivers/timer/Makefile index c4fbab2aac..d0bf218b11 100644 --- a/drivers/timer/Makefile +++ b/drivers/timer/Makefile @@ -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 diff --git a/drivers/timer/riscv_timer.c b/drivers/timer/riscv_timer.c new file mode 100644 index 0000000000..9f9f070e0b --- /dev/null +++ b/drivers/timer/riscv_timer.c @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2018, Bin Meng + * + * 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 +#include +#include +#include +#include + +/** + * 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, +}; From 44fe795c149cac67a6dbc12a16f7ec5d813b9523 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 12 Dec 2018 06:12:28 -0800 Subject: [PATCH 06/29] riscv: ax25: Hide the ax25-specific Kconfig option There is no need to expose RISCV_NDS to the Kconfig menu as it is an ax25-specific option. Introduce a dedicated Kconfig option for the cache ops of ax25 platform and use that to guard the cache ops. Signed-off-by: Bin Meng Reviewed-by: Lukas Auer Reviewed-by: Rick Chen --- arch/riscv/cpu/ax25/Kconfig | 17 ++++++++++++----- arch/riscv/cpu/ax25/cache.c | 12 ++++++------ board/AndesTech/ax25-ae350/Kconfig | 4 ++++ 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/arch/riscv/cpu/ax25/Kconfig b/arch/riscv/cpu/ax25/Kconfig index 6c7022f0f5..e9dbca2fae 100644 --- a/arch/riscv/cpu/ax25/Kconfig +++ b/arch/riscv/cpu/ax25/Kconfig @@ -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 diff --git a/arch/riscv/cpu/ax25/cache.c b/arch/riscv/cpu/ax25/cache.c index 6600ac2fac..8d6ae170b8 100644 --- a/arch/riscv/cpu/ax25/cache.c +++ b/arch/riscv/cpu/ax25/cache.c @@ -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" diff --git a/board/AndesTech/ax25-ae350/Kconfig b/board/AndesTech/ax25-ae350/Kconfig index bb69ea3489..44cb302f70 100644 --- a/board/AndesTech/ax25-ae350/Kconfig +++ b/board/AndesTech/ax25-ae350/Kconfig @@ -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 From 3cfc825261d90472fa11ea72d7ed2d293b744140 Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Wed, 12 Dec 2018 06:12:29 -0800 Subject: [PATCH 07/29] riscv: Introduce a Kconfig option for machine mode So far we have a Kconfig option for supervisor mode. This adds an option for the machine mode. Signed-off-by: Anup Patel Signed-off-by: Bin Meng Reviewed-by: Lukas Auer --- arch/riscv/Kconfig | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 6d85ac96f8..55c60e4aeb 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -62,6 +62,22 @@ config CMODEL_MEDANY 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 @@ -73,11 +89,6 @@ 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 From 644a3cd77e840d1be6a714b8ce284d6ef3ad2f06 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 12 Dec 2018 06:12:30 -0800 Subject: [PATCH 08/29] riscv: Add a SYSCON driver for SiFive's Core Local Interruptor This adds 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. This driver implements the riscv_get_time() API as required by the generic RISC-V timer driver, as well as some other APIs that are needed for handling IPI. Signed-off-by: Bin Meng Reviewed-by: Lukas Auer Reviewed-by: Anup Patel --- arch/riscv/Kconfig | 9 +++ arch/riscv/include/asm/global_data.h | 3 + arch/riscv/include/asm/syscon.h | 19 +++++++ arch/riscv/lib/Makefile | 1 + arch/riscv/lib/sifive_clint.c | 84 ++++++++++++++++++++++++++++ 5 files changed, 116 insertions(+) create mode 100644 arch/riscv/include/asm/syscon.h create mode 100644 arch/riscv/lib/sifive_clint.c diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 55c60e4aeb..f513f52672 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -95,4 +95,13 @@ config 32BIT 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. + endmenu diff --git a/arch/riscv/include/asm/global_data.h b/arch/riscv/include/asm/global_data.h index 4d5d623725..46fcfab840 100644 --- a/arch/riscv/include/asm/global_data.h +++ b/arch/riscv/include/asm/global_data.h @@ -12,6 +12,9 @@ /* Architecture-specific global data */ struct arch_global_data { +#ifdef CONFIG_SIFIVE_CLINT + void __iomem *clint; /* clint base address */ +#endif }; #include diff --git a/arch/riscv/include/asm/syscon.h b/arch/riscv/include/asm/syscon.h new file mode 100644 index 0000000000..d311ee6b45 --- /dev/null +++ b/arch/riscv/include/asm/syscon.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2018, Bin Meng + */ + +#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 */ diff --git a/arch/riscv/lib/Makefile b/arch/riscv/lib/Makefile index b58db89752..b13c87661e 100644 --- a/arch/riscv/lib/Makefile +++ b/arch/riscv/lib/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_CMD_BOOTM) += bootm.o obj-$(CONFIG_CMD_GO) += boot.o obj-y += cache.o +obj-$(CONFIG_SIFIVE_CLINT) += sifive_clint.o obj-y += interrupts.o obj-y += reset.o obj-y += setjmp.o diff --git a/arch/riscv/lib/sifive_clint.c b/arch/riscv/lib/sifive_clint.c new file mode 100644 index 0000000000..d24e0d585b --- /dev/null +++ b/arch/riscv/lib/sifive_clint.c @@ -0,0 +1,84 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2018, Bin Meng + * + * 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 +#include +#include +#include +#include +#include + +/* 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, +}; From 511107d85d6f2739a641076acfb5646ba2a19fc8 Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Wed, 12 Dec 2018 06:12:31 -0800 Subject: [PATCH 09/29] riscv: Implement riscv_get_time() API using rdtime instruction This adds an implementation of riscv_get_time() API that is using rdtime instruction. This is the case for S-mode U-Boot, and is useful for processors that support rdtime in M-mode too. Signed-off-by: Anup Patel Signed-off-by: Bin Meng Reviewed-by: Lukas Auer --- arch/riscv/Kconfig | 8 ++++++++ arch/riscv/lib/Makefile | 1 + arch/riscv/lib/rdtime.c | 38 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+) create mode 100644 arch/riscv/lib/rdtime.c diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index f513f52672..7dc6e3fad2 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -104,4 +104,12 @@ config SIFIVE_CLINT 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. + endmenu diff --git a/arch/riscv/lib/Makefile b/arch/riscv/lib/Makefile index b13c87661e..edfa61690c 100644 --- a/arch/riscv/lib/Makefile +++ b/arch/riscv/lib/Makefile @@ -9,6 +9,7 @@ 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 diff --git a/arch/riscv/lib/rdtime.c b/arch/riscv/lib/rdtime.c new file mode 100644 index 0000000000..e128d7fce6 --- /dev/null +++ b/arch/riscv/lib/rdtime.c @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2018, Anup Patel + * Copyright (C) 2018, Bin Meng + * + * The riscv_get_time() API implementation that is using the + * standard rdtime instruction. + */ + +#include + +/* 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; +} From 84304d4866c8d69cd1ddb4b5c6cbcc17d6708da0 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 12 Dec 2018 06:12:32 -0800 Subject: [PATCH 10/29] riscv: qemu: Add platform-specific Kconfig options Add the QEMU RISC-V platform-specific Kconfig options, to include CPU and timer drivers. Signed-off-by: Bin Meng Reviewed-by: Lukas Auer Reviewed-by: Anup Patel --- arch/riscv/Kconfig | 1 + arch/riscv/cpu/qemu/Kconfig | 11 +++++++++++ board/emulation/qemu-riscv/Kconfig | 1 + 3 files changed, 13 insertions(+) create mode 100644 arch/riscv/cpu/qemu/Kconfig diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 7dc6e3fad2..39ca2d829c 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -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 diff --git a/arch/riscv/cpu/qemu/Kconfig b/arch/riscv/cpu/qemu/Kconfig new file mode 100644 index 0000000000..2e953e172f --- /dev/null +++ b/arch/riscv/cpu/qemu/Kconfig @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# Copyright (C) 2018, Bin Meng + +config QEMU_RISCV + bool + imply CPU + imply CPU_RISCV + imply RISCV_TIMER + imply SIFIVE_CLINT if RISCV_MMODE + imply CMD_CPU diff --git a/board/emulation/qemu-riscv/Kconfig b/board/emulation/qemu-riscv/Kconfig index 56bb5337d4..ed005e5678 100644 --- a/board/emulation/qemu-riscv/Kconfig +++ b/board/emulation/qemu-riscv/Kconfig @@ -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 From 92b64fef0580fab1c86bede68451270dc3772857 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 12 Dec 2018 06:12:33 -0800 Subject: [PATCH 11/29] riscv: Enlarge the default SYS_MALLOC_F_LEN Increase the heap size for the pre-relocation stage, so that CPU driver can be loaded. Signed-off-by: Bin Meng Reviewed-by: Lukas Auer Reviewed-by: Anup Patel --- arch/riscv/Kconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 39ca2d829c..c45e4d73a8 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -113,4 +113,7 @@ config RISCV_RDTIME 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 From 39cad5bc0b36fca721416c28d1948c4805760f33 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 12 Dec 2018 06:12:34 -0800 Subject: [PATCH 12/29] riscv: Probe cpus during boot This calls cpu_probe_all() to probe all available cpus. Signed-off-by: Bin Meng Reviewed-by: Lukas Auer Reviewed-by: Anup Patel --- arch/riscv/cpu/cpu.c | 26 ++++++++++++++++++++++++++ arch/riscv/cpu/qemu/Kconfig | 1 + 2 files changed, 27 insertions(+) diff --git a/arch/riscv/cpu/cpu.c b/arch/riscv/cpu/cpu.c index d9f820c44c..8286a0c959 100644 --- a/arch/riscv/cpu/cpu.c +++ b/arch/riscv/cpu/cpu.c @@ -4,6 +4,8 @@ */ #include +#include +#include #include /* @@ -53,3 +55,27 @@ int print_cpuinfo(void) return 0; } + +static int riscv_cpu_probe(void) +{ +#ifdef CONFIG_CPU + int ret; + + /* 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) +{ + return riscv_cpu_probe(); +} + +int arch_early_init_r(void) +{ + return riscv_cpu_probe(); +} diff --git a/arch/riscv/cpu/qemu/Kconfig b/arch/riscv/cpu/qemu/Kconfig index 2e953e172f..f48751e6de 100644 --- a/arch/riscv/cpu/qemu/Kconfig +++ b/arch/riscv/cpu/qemu/Kconfig @@ -4,6 +4,7 @@ config QEMU_RISCV bool + select ARCH_EARLY_INIT_R imply CPU imply CPU_RISCV imply RISCV_TIMER From 3c276b27032f53bef478f9a2c05fd6923ad560bf Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 12 Dec 2018 06:12:35 -0800 Subject: [PATCH 13/29] riscv: Remove non-DM version of print_cpuinfo() With DM CPU driver, the non-DM version of print_cpuinfo() is no longer needed. Signed-off-by: Bin Meng Reviewed-by: Lukas Auer Reviewed-by: Anup Patel --- arch/riscv/cpu/cpu.c | 37 ------------------------------------- 1 file changed, 37 deletions(-) diff --git a/arch/riscv/cpu/cpu.c b/arch/riscv/cpu/cpu.c index 8286a0c959..d3c59da34b 100644 --- a/arch/riscv/cpu/cpu.c +++ b/arch/riscv/cpu/cpu.c @@ -14,48 +14,11 @@ */ 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) { return csr_read(misa) & (1 << (ext - 'a')); } -int print_cpuinfo(void) -{ - char name[32]; - char *s = name; - int bit; - - 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); - - return 0; -} - static int riscv_cpu_probe(void) { #ifdef CONFIG_CPU From ea53f1c74272bd7b1d9c8a28df4ac145c72131dd Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 12 Dec 2018 06:12:36 -0800 Subject: [PATCH 14/29] riscv: Add CSR numbers The standard RISC-V ISA sets aside a 12-bit encoding space for up to 4096 CSRs. This adds all known CSR numbers as defined in the RISC-V Privileged Architecture Version 1.10. Signed-off-by: Bin Meng Reviewed-by: Lukas Auer Reviewed-by: Anup Patel --- arch/riscv/include/asm/encoding.h | 221 ++++++++++++++++++++++++++++++ 1 file changed, 221 insertions(+) diff --git a/arch/riscv/include/asm/encoding.h b/arch/riscv/include/asm/encoding.h index 97cf906aa6..05e1ce3526 100644 --- a/arch/riscv/include/asm/encoding.h +++ b/arch/riscv/include/asm/encoding.h @@ -152,6 +152,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 */ From 3967156464282df161f5e4be40999dae47adf799 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 12 Dec 2018 06:12:37 -0800 Subject: [PATCH 15/29] riscv: Add exception codes for xcause register This adds all exception codes in encoding.h. Signed-off-by: Bin Meng Reviewed-by: Lukas Auer Reviewed-by: Anup Patel --- arch/riscv/include/asm/encoding.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/arch/riscv/include/asm/encoding.h b/arch/riscv/include/asm/encoding.h index 05e1ce3526..772668c74e 100644 --- a/arch/riscv/include/asm/encoding.h +++ b/arch/riscv/include/asm/encoding.h @@ -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 From aef59e5cc450f403478f799bbb0f0647ff28a3c3 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 12 Dec 2018 06:12:38 -0800 Subject: [PATCH 16/29] riscv: Update supports_extension() to use desc from cpu driver This updates supports_extension() implementation to use the desc string from the cpu driver whenever possible, which avoids the reading of misa CSR for S-mode U-Boot. Signed-off-by: Bin Meng Reviewed-by: Lukas Auer Reviewed-by: Anup Patel --- arch/riscv/cpu/cpu.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/arch/riscv/cpu/cpu.c b/arch/riscv/cpu/cpu.c index d3c59da34b..fc7c9b3751 100644 --- a/arch/riscv/cpu/cpu.c +++ b/arch/riscv/cpu/cpu.c @@ -5,8 +5,10 @@ #include #include +#include #include #include +#include /* * prior_stage_fdt_address must be stored in the data section since it is used @@ -16,7 +18,31 @@ phys_addr_t prior_stage_fdt_address __attribute__((section(".data"))); 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 */ } static int riscv_cpu_probe(void) From 57fe5c64cb078c25c81cf40b5b268dc6857dc00c Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 12 Dec 2018 06:12:39 -0800 Subject: [PATCH 17/29] riscv: Add indirect stringification to csr_xxx ops With current csr_xxx ops, we cannot pass a macro to parameter 'csr', hence we need add another level to allow the parameter to be a macro itself, aka indirect stringification. Signed-off-by: Bin Meng Reviewed-by: Lukas Auer Reviewed-by: Anup Patel --- arch/riscv/include/asm/csr.h | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/arch/riscv/include/asm/csr.h b/arch/riscv/include/asm/csr.h index 29624fdbb5..86136f542c 100644 --- a/arch/riscv/include/asm/csr.h +++ b/arch/riscv/include/asm/csr.h @@ -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"); \ }) From 485e822346caa982a5c17b7b136b17e8d09dafee Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 12 Dec 2018 06:12:40 -0800 Subject: [PATCH 18/29] riscv: Do some basic architecture level cpu initialization In arch_cpu_init_dm() do some basic architecture level cpu initialization, like FPU enable, etc. Signed-off-by: Bin Meng Reviewed-by: Lukas Auer Reviewed-by: Anup Patel --- arch/riscv/cpu/cpu.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/arch/riscv/cpu/cpu.c b/arch/riscv/cpu/cpu.c index fc7c9b3751..e662140427 100644 --- a/arch/riscv/cpu/cpu.c +++ b/arch/riscv/cpu/cpu.c @@ -8,6 +8,7 @@ #include #include #include +#include #include /* @@ -61,7 +62,31 @@ static int riscv_cpu_probe(void) int arch_cpu_init_dm(void) { - return riscv_cpu_probe(); + 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) From 4b3f5ed5ac1a4376c29c3010d25049c03de4ed57 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 12 Dec 2018 06:12:41 -0800 Subject: [PATCH 19/29] riscv: Move trap handler codes to mtrap.S Currently the M-mode trap handler codes are in start.S. For future extension, move them to a separate file mtrap.S. Signed-off-by: Bin Meng Reviewed-by: Lukas Auer Reviewed-by: Anup Patel --- arch/riscv/cpu/Makefile | 2 +- arch/riscv/cpu/mtrap.S | 111 ++++++++++++++++++++++++++++++++++++++++ arch/riscv/cpu/start.S | 89 -------------------------------- 3 files changed, 112 insertions(+), 90 deletions(-) create mode 100644 arch/riscv/cpu/mtrap.S diff --git a/arch/riscv/cpu/Makefile b/arch/riscv/cpu/Makefile index 2cc6757fcf..6bf6f911c6 100644 --- a/arch/riscv/cpu/Makefile +++ b/arch/riscv/cpu/Makefile @@ -4,4 +4,4 @@ extra-y = start.o -obj-y += cpu.o +obj-y += cpu.o mtrap.o diff --git a/arch/riscv/cpu/mtrap.S b/arch/riscv/cpu/mtrap.S new file mode 100644 index 0000000000..a5ad558621 --- /dev/null +++ b/arch/riscv/cpu/mtrap.S @@ -0,0 +1,111 @@ +/* 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 + * + * Copyright (C) 2017 Andes Technology Corporation + * Rick Chen, Andes Technology Corporation + * + * Copyright (C) 2018, Bin Meng + */ + +#include +#include + +#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 + +#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) diff --git a/arch/riscv/cpu/start.S b/arch/riscv/cpu/start.S index 64246a4e09..47c3bf0434 100644 --- a/arch/riscv/cpu/start.S +++ b/arch/riscv/cpu/start.S @@ -198,92 +198,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) From 496262cca63f25408c6715b39cea1747e8ce9b59 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 12 Dec 2018 06:12:42 -0800 Subject: [PATCH 20/29] riscv: Fix context restore before returning from trap handler sp cannot be loaded before restoring other registers. Signed-off-by: Bin Meng Reviewed-by: Lukas Auer Reviewed-by: Anup Patel --- arch/riscv/cpu/mtrap.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/riscv/cpu/mtrap.S b/arch/riscv/cpu/mtrap.S index a5ad558621..da307e4273 100644 --- a/arch/riscv/cpu/mtrap.S +++ b/arch/riscv/cpu/mtrap.S @@ -77,7 +77,6 @@ trap_entry: #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) @@ -107,5 +106,6 @@ trap_entry: 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) From 10753ef8fd14dfe1d41ec253966569de19463adc Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 12 Dec 2018 06:12:43 -0800 Subject: [PATCH 21/29] riscv: Return to previous privilege level after trap handling At present the trap handler returns to hardcoded M-mode/S-mode. Change to returning to previous privilege level instead. Signed-off-by: Bin Meng Reviewed-by: Lukas Auer Reviewed-by: Anup Patel --- arch/riscv/cpu/mtrap.S | 8 -------- 1 file changed, 8 deletions(-) diff --git a/arch/riscv/cpu/mtrap.S b/arch/riscv/cpu/mtrap.S index da307e4273..407ecfa9c0 100644 --- a/arch/riscv/cpu/mtrap.S +++ b/arch/riscv/cpu/mtrap.S @@ -68,14 +68,6 @@ trap_entry: 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 x3, 3 * REGBYTES(sp) LREG x4, 4 * REGBYTES(sp) From 7f5d35a547afb1e4d8e7ca780ab1b9f78ed11d68 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 12 Dec 2018 06:12:44 -0800 Subject: [PATCH 22/29] riscv: Adjust the _exit_trap() position to come before handle_trap() With this change, we can avoid a forward declaration. Signed-off-by: Bin Meng Reviewed-by: Lukas Auer Reviewed-by: Anup Patel --- arch/riscv/lib/interrupts.c | 62 ++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 32 deletions(-) diff --git a/arch/riscv/lib/interrupts.c b/arch/riscv/lib/interrupts.c index 3aff006977..e185933b01 100644 --- a/arch/riscv/lib/interrupts.c +++ b/arch/riscv/lib/interrupts.c @@ -12,7 +12,36 @@ #include #include -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(); -} From 51ab4570f3920ae3d6822c96fe03ffb97e2072b4 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 12 Dec 2018 06:12:45 -0800 Subject: [PATCH 23/29] riscv: Save boot hart id to the global data At present the hart id passed via a0 in the U-Boot entry is saved to s0 at the beginning but does not preserve later. Save it to the global data structure so that it can be used later. Signed-off-by: Bin Meng Reviewed-by: Lukas Auer Reviewed-by: Anup Patel --- arch/riscv/cpu/start.S | 4 ++++ arch/riscv/include/asm/global_data.h | 1 + arch/riscv/lib/asm-offsets.c | 19 +++++++++++++++++++ 3 files changed, 24 insertions(+) create mode 100644 arch/riscv/lib/asm-offsets.c diff --git a/arch/riscv/cpu/start.S b/arch/riscv/cpu/start.S index 47c3bf0434..81ea52b170 100644 --- a/arch/riscv/cpu/start.S +++ b/arch/riscv/cpu/start.S @@ -14,6 +14,7 @@ #include #include #include +#include #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() */ diff --git a/arch/riscv/include/asm/global_data.h b/arch/riscv/include/asm/global_data.h index 46fcfab840..a3a342c6e1 100644 --- a/arch/riscv/include/asm/global_data.h +++ b/arch/riscv/include/asm/global_data.h @@ -12,6 +12,7 @@ /* 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 diff --git a/arch/riscv/lib/asm-offsets.c b/arch/riscv/lib/asm-offsets.c new file mode 100644 index 0000000000..e0b71f5691 --- /dev/null +++ b/arch/riscv/lib/asm-offsets.c @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2018, Bin Meng + * + * From arch/x86/lib/asm-offsets.c + * + * This program is used to generate definitions needed by + * assembly language modules. + */ + +#include +#include + +int main(void) +{ + DEFINE(GD_BOOT_HART, offsetof(gd_t, arch.boot_hart)); + + return 0; +} From 3c85099aa329274c99b49672bba9e1ff710121e2 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 12 Dec 2018 06:12:46 -0800 Subject: [PATCH 24/29] riscv: bootm: Change to use boot_hart from global data Avoid reading mhartid CSR directly, instead use the one we saved in the global data structure before. With this patch, BBL no longer needs to be hacked to provide the mhartid CSR emulation for S-mode U-Boot. Signed-off-by: Bin Meng Reviewed-by: Lukas Auer Reviewed-by: Anup Patel --- arch/riscv/lib/bootm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/riscv/lib/bootm.c b/arch/riscv/lib/bootm.c index 124aeefff8..60b32cca81 100644 --- a/arch/riscv/lib/bootm.c +++ b/arch/riscv/lib/bootm.c @@ -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); } } From dcad9b8d66d68e9258ce4be89fb0ac9ab95083b0 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 12 Dec 2018 06:12:47 -0800 Subject: [PATCH 25/29] riscv: Remove ae350.dts This is not used by any board. Remove it. Signed-off-by: Bin Meng Reviewed-by: Lukas Auer Reviewed-by: Anup Patel --- arch/riscv/dts/ae350.dts | 229 --------------------------------------- 1 file changed, 229 deletions(-) delete mode 100644 arch/riscv/dts/ae350.dts diff --git a/arch/riscv/dts/ae350.dts b/arch/riscv/dts/ae350.dts deleted file mode 100644 index e48c298645..0000000000 --- a/arch/riscv/dts/ae350.dts +++ /dev/null @@ -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; - }; - }; -}; From e2842496ac64c19a0c40cb4cbe301d9d91cf0f56 Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Sat, 15 Dec 2018 11:35:15 +0530 Subject: [PATCH 26/29] drivers: serial: Add SiFive UART driver This patch adds SiFive UART driver. The driver is 100% DM driver and it determines input clock using clk framework. Signed-off-by: Anup Patel Reviewed-by: Palmer Dabbelt Reviewed-by: Bin Meng Tested-by: Bin Meng --- drivers/serial/Kconfig | 13 ++ drivers/serial/Makefile | 1 + drivers/serial/serial_sifive.c | 215 +++++++++++++++++++++++++++++++++ 3 files changed, 229 insertions(+) create mode 100644 drivers/serial/serial_sifive.c diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 6252dd8c4b..b7ff2960ab 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -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 diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index 2f8d065a4c..06ee30697d 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -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 diff --git a/drivers/serial/serial_sifive.c b/drivers/serial/serial_sifive.c new file mode 100644 index 0000000000..341728a690 --- /dev/null +++ b/drivers/serial/serial_sifive.c @@ -0,0 +1,215 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2018 Anup Patel + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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), ®s->div); +} + +static void _sifive_serial_init(struct uart_sifive *regs) +{ + writel(UART_TXCTRL_TXEN, ®s->txctrl); + writel(UART_RXCTRL_RXEN, ®s->rxctrl); + writel(0, ®s->ie); +} + +static int _sifive_serial_putc(struct uart_sifive *regs, const char c) +{ + if (readl(®s->txfifo) & UART_TXFIFO_FULL) + return -EAGAIN; + + writel(c, ®s->txfifo); + + return 0; +} + +static int _sifive_serial_getc(struct uart_sifive *regs) +{ + int ch = readl(®s->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(®s->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 From 9acaf60bfdc9c96647772afd42c8150524520fcb Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Sat, 15 Dec 2018 11:35:16 +0530 Subject: [PATCH 27/29] riscv: qemu: Imply SIFIVE_SERIAL for emulation This patch enables SiFive UART driver for QEMU RISC-V emulation by implying SIFIVE_SERIAL on BOARD_SPECIFIC_OPTIONS. Signed-off-by: Anup Patel Reviewed-by: Bin Meng Tested-by: Bin Meng --- board/emulation/qemu-riscv/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/board/emulation/qemu-riscv/Kconfig b/board/emulation/qemu-riscv/Kconfig index ed005e5678..0d865acf10 100644 --- a/board/emulation/qemu-riscv/Kconfig +++ b/board/emulation/qemu-riscv/Kconfig @@ -33,5 +33,6 @@ config BOARD_SPECIFIC_OPTIONS # dummy imply CMD_FAT imply BOARD_LATE_INIT imply OF_BOARD_SETUP + imply SIFIVE_SERIAL endif From ab3f92dee69b863e1fc50756abfb3df6febd37fd Mon Sep 17 00:00:00 2001 From: Rick Chen Date: Tue, 18 Dec 2018 11:02:27 +0800 Subject: [PATCH 28/29] riscv: configs: Rename ax25-ae350 defconfig Remove cpu name from the defconfig naming. Because other cpus maybe run on AE350 platform. So only use platfrom name in defconfig naming will be better. Also sync MAINTAINERS: Rename a25-ae350_32_defconfig as ae350_rv32_defconfig ax25-ae350_64_defconfig as ae350_rv64_defconfig Signed-off-by: Rick Chen Cc: Greentime Hu Reviewed-by: Bin Meng --- board/AndesTech/ax25-ae350/MAINTAINERS | 5 ++--- configs/{a25-ae350_32_defconfig => ae350_rv32_defconfig} | 0 configs/{ax25-ae350_64_defconfig => ae350_rv64_defconfig} | 0 3 files changed, 2 insertions(+), 3 deletions(-) rename configs/{a25-ae350_32_defconfig => ae350_rv32_defconfig} (100%) rename configs/{ax25-ae350_64_defconfig => ae350_rv64_defconfig} (100%) diff --git a/board/AndesTech/ax25-ae350/MAINTAINERS b/board/AndesTech/ax25-ae350/MAINTAINERS index d87446ee1c..b0a99e4ac4 100644 --- a/board/AndesTech/ax25-ae350/MAINTAINERS +++ b/board/AndesTech/ax25-ae350/MAINTAINERS @@ -3,6 +3,5 @@ M: Rick Chen 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 diff --git a/configs/a25-ae350_32_defconfig b/configs/ae350_rv32_defconfig similarity index 100% rename from configs/a25-ae350_32_defconfig rename to configs/ae350_rv32_defconfig diff --git a/configs/ax25-ae350_64_defconfig b/configs/ae350_rv64_defconfig similarity index 100% rename from configs/ax25-ae350_64_defconfig rename to configs/ae350_rv64_defconfig From 368ff57805b03bebf99e97e703ce07aec721bc71 Mon Sep 17 00:00:00 2001 From: Rick Chen Date: Tue, 18 Dec 2018 10:48:55 +0800 Subject: [PATCH 29/29] doc: README.ae350: Sync for ax25-ae350 rename Rename ax25-ae350 as ae350_rv[32|64] for 32 or 64 bit. Signed-off-by: Rick Chen Cc: Greentime Hu Reviewed-by: Bin Meng --- doc/README.ae350 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/README.ae350 b/doc/README.ae350 index fe75b80eb7..189a6b7ec3 100644 --- a/doc/README.ae350 +++ b/doc/README.ae350 @@ -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 ====================