From 502d3066300e3e5bc9f520270983876562160864 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Sun, 25 Nov 2018 02:40:57 -0700 Subject: [PATCH] soc: riscv32: add RV32M1 SoC as openisa_rv32m1 The OpenISA RV32M1 SoC has four CPU cores. Two of these are RISC-V 32-bit cores, which are named "RI5CY" and "ZERO-RISCY". (The other two cores are ARM Cortex-M0+ and -M4.) This patch adds basic SoC enablement for the RISC-V cores: - basic dtsi, to be extended as additional drivers are added - SoC definition in soc/riscv32/openisa_rv32m1 for RI5CY / ZERO-RISCY - system timer driver for RI5CY, based on LPTMR0 peripheral The timer driver will be generalized a bit soon once proper multi-level interrupt support is available. Emphasis is on supporting the RI5CY core as the more capable of the two; the ZERO-RISCY SoC definitions are a good starting point, but additional work setting up a dtsi and initial drivers is needed to support that core. Signed-off-by: Marti Bolivar Signed-off-by: Michael Scott --- drivers/timer/CMakeLists.txt | 1 + drivers/timer/Kconfig | 10 + drivers/timer/rv32m1_lptmr_timer.c | 164 ++++++++++++++ dts/riscv32/rv32m1_ri5cy.dtsi | 25 +++ ext/hal/CMakeLists.txt | 1 + ext/hal/Kconfig | 2 + ext/hal/openisa/CMakeLists.txt | 4 + ext/hal/openisa/vega_sdk_riscv/CMakeLists.txt | 16 ++ ext/hal/openisa/vega_sdk_riscv/Kconfig | 7 + ext/hal/openisa/vega_sdk_riscv/README | 3 +- .../devices/RV32M1/drivers/CMakeLists.txt | 3 + soc/riscv32/openisa_rv32m1/CMakeLists.txt | 20 ++ soc/riscv32/openisa_rv32m1/Kconfig | 29 +++ soc/riscv32/openisa_rv32m1/Kconfig.defconfig | 76 +++++++ soc/riscv32/openisa_rv32m1/Kconfig.soc | 21 ++ soc/riscv32/openisa_rv32m1/linker.ld | 203 ++++++++++++++++++ soc/riscv32/openisa_rv32m1/soc.c | 147 +++++++++++++ soc/riscv32/openisa_rv32m1/soc.h | 28 +++ soc/riscv32/openisa_rv32m1/soc_context.h | 52 +++++ soc/riscv32/openisa_rv32m1/soc_irq.S | 95 ++++++++ soc/riscv32/openisa_rv32m1/soc_ri5cy.h | 88 ++++++++ soc/riscv32/openisa_rv32m1/soc_zero_riscy.h | 76 +++++++ soc/riscv32/openisa_rv32m1/vector.S | 80 +++++++ soc/riscv32/openisa_rv32m1/wdog.S | 63 ++++++ 24 files changed, 1213 insertions(+), 1 deletion(-) create mode 100644 drivers/timer/rv32m1_lptmr_timer.c create mode 100644 dts/riscv32/rv32m1_ri5cy.dtsi create mode 100644 ext/hal/openisa/CMakeLists.txt create mode 100644 ext/hal/openisa/vega_sdk_riscv/CMakeLists.txt create mode 100644 ext/hal/openisa/vega_sdk_riscv/Kconfig create mode 100644 ext/hal/openisa/vega_sdk_riscv/devices/RV32M1/drivers/CMakeLists.txt create mode 100644 soc/riscv32/openisa_rv32m1/CMakeLists.txt create mode 100644 soc/riscv32/openisa_rv32m1/Kconfig create mode 100644 soc/riscv32/openisa_rv32m1/Kconfig.defconfig create mode 100644 soc/riscv32/openisa_rv32m1/Kconfig.soc create mode 100644 soc/riscv32/openisa_rv32m1/linker.ld create mode 100644 soc/riscv32/openisa_rv32m1/soc.c create mode 100644 soc/riscv32/openisa_rv32m1/soc.h create mode 100644 soc/riscv32/openisa_rv32m1/soc_context.h create mode 100644 soc/riscv32/openisa_rv32m1/soc_irq.S create mode 100644 soc/riscv32/openisa_rv32m1/soc_ri5cy.h create mode 100644 soc/riscv32/openisa_rv32m1/soc_zero_riscy.h create mode 100644 soc/riscv32/openisa_rv32m1/vector.S create mode 100644 soc/riscv32/openisa_rv32m1/wdog.S diff --git a/drivers/timer/CMakeLists.txt b/drivers/timer/CMakeLists.txt index 07b8c653ec2..f3dee5eb8bc 100644 --- a/drivers/timer/CMakeLists.txt +++ b/drivers/timer/CMakeLists.txt @@ -6,6 +6,7 @@ zephyr_sources_ifdef(CONFIG_ALTERA_AVALON_TIMER altera_avalon_timer_hal.c) zephyr_sources_if_kconfig( nrf_rtc_timer.c) zephyr_sources_if_kconfig( pulpino_timer.c) zephyr_sources_if_kconfig( riscv_machine_timer.c) +zephyr_sources_if_kconfig( rv32m1_lptmr_timer.c) zephyr_sources_if_kconfig( cortex_m_systick.c) zephyr_sources_ifdef(CONFIG_XTENSA_TIMER xtensa_sys_timer.c) zephyr_sources_if_kconfig( native_posix_timer.c) diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig index 34f75eae300..078a07460f4 100644 --- a/drivers/timer/Kconfig +++ b/drivers/timer/Kconfig @@ -134,6 +134,16 @@ config RISCV_MACHINE_TIMER This module implements a kernel device driver for the generic RISCV machine timer driver. It provides the standard "system clock driver" interfaces. +config RV32M1_LPTMR_TIMER + bool "RV32M1 LPTMR system timer driver" + default y + depends on SOC_OPENISA_RV32M1_RISCV32 + depends on !TICKLESS_IDLE + help + This module implements a kernel device driver for using the LPTMR + peripheral as the system clock. It provides the standard "system clock + driver" interfaces. + config NATIVE_POSIX_TIMER bool "(POSIX) native_posix timer driver" default y diff --git a/drivers/timer/rv32m1_lptmr_timer.c b/drivers/timer/rv32m1_lptmr_timer.c new file mode 100644 index 00000000000..3eb38aac100 --- /dev/null +++ b/drivers/timer/rv32m1_lptmr_timer.c @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2018 Foundries.io Ltd + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +/* + * This is just a getting started point. + * + * Assumptions and limitations: + * + * - LPTMR0 clocked by SIRC output SIRCDIV3 divide-by-1, SIRC at 8MHz + * - no tickless + * - direct control of INTMUX0 channel 0 (bypasses intmux driver) + * + * This should be rewritten as follows: + * + * - use RTC instead of LPTMR + * - support tickless operation + */ + +#define CYCLES_PER_TICK \ + (CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC / CONFIG_SYS_CLOCK_TICKS_PER_SEC) + +/* Sanity check the 8MHz clock assumption. */ +#if CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC != 8000000 +#error "timer driver misconfiguration" +#endif + +#define LPTMR_INSTANCE LPTMR0 +#define LPTMR_LEVEL0_IRQ 24 /* INTMUX channel 0 */ +#define LPTMR_LEVEL0_IRQ_PRIO 0 +#define LPTMR_LEVEL1_IRQ 7 +#define LPTMR_LEVEL1_IRQ_EN (1U << LPTMR_LEVEL1_IRQ) + +#define SIRC_RANGE_8MHZ SCG_SIRCCFG_RANGE(1) +#define SIRCDIV3_DIVIDE_BY_1 1 +#define PCS_SOURCE_SIRCDIV3 0 + +struct device; /* forward declaration; type is not used. */ + +static volatile u32_t cycle_count; + +static void lptmr_irq_handler(struct device *unused) +{ + ARG_UNUSED(unused); + + LPTMR_INSTANCE->CSR |= LPTMR_CSR_TCF(1); /* Rearm timer. */ + cycle_count += CYCLES_PER_TICK; /* Track cycles. */ + z_clock_announce(1); /* Poke the scheduler. */ +} + +static void enable_intmux0_pcc(void) +{ + u32_t ier; + + /* + * The reference manual doesn't say this exists, but it's in + * the peripheral registers. + */ + *(u32_t*)(PCC0_BASE + 0x13c) |= PCC_CLKCFG_CGC_MASK; + + ier = INTMUX0->CHANNEL[0].CHn_IER_31_0; + ier |= LPTMR_LEVEL1_IRQ_EN; + INTMUX0->CHANNEL[0].CHn_IER_31_0 = ier; +} + +int z_clock_driver_init(struct device *unused) +{ + u32_t csr, psr, sircdiv; /* LPTMR registers */ + + ARG_UNUSED(unused); + IRQ_CONNECT(LPTMR_LEVEL0_IRQ, LPTMR_LEVEL0_IRQ_PRIO, lptmr_irq_handler, NULL, 0); + + if ((SCG->SIRCCSR & SCG_SIRCCSR_SIRCEN_MASK) == SCG_SIRCCSR_SIRCEN(0)) { + /* + * SIRC is on by default, so something else turned it off. + * + * This is incompatible with this driver, which is SIRC-based. + */ + return -ENODEV; + } + + /* Disable the timer and clear any pending IRQ. */ + csr = LPTMR_INSTANCE->CSR; + csr &= ~LPTMR_CSR_TEN(0); + csr |= LPTMR_CSR_TFC(1); + LPTMR_INSTANCE->CSR = csr; + + /* + * Set up the timer clock source and configure the timer. + */ + + /* + * SIRCDIV3 is the SIRC divider for LPTMR (SoC dependent). + * Pass it directly through without any divider. + */ + sircdiv = SCG->SIRCDIV; + sircdiv &= ~SCG_SIRCDIV_SIRCDIV3_MASK; + sircdiv |= SCG_SIRCDIV_SIRCDIV3(SIRCDIV3_DIVIDE_BY_1); + SCG->SIRCDIV = sircdiv; + /* + * TMS = 0: time counter mode, not pulse counter + * TCF = 0: reset counter register on reaching compare value + * TDRE = 0: disable DMA request + */ + csr &= ~(LPTMR_CSR_TMS(1) | LPTMR_CSR_TFC(1) | LPTMR_CSR_TDRE(1)); + /* + * TIE = 1: enable interrupt + */ + csr |= LPTMR_CSR_TIE(1); + LPTMR_INSTANCE->CSR = csr; + /* + * PCS = 0: clock source is SIRCDIV3 (SoC dependent) + * PBYP = 1: bypass the prescaler + */ + psr = LPTMR_INSTANCE->PSR; + psr &= ~LPTMR_PSR_PCS_MASK; + psr |= (LPTMR_PSR_PBYP(1) | LPTMR_PSR_PCS(PCS_SOURCE_SIRCDIV3)); + LPTMR_INSTANCE->PSR = psr; + + /* + * Set compare register to the proper tick count. The check + * here makes sure SIRC is left at its default reset value to + * make the defconfig setting work properly. + * + * TODO: be smarter to meet arbitrary Kconfig settings. + */ + if ((SCG->SIRCCFG & SCG_SIRCCFG_RANGE_MASK) != SIRC_RANGE_8MHZ) { + return -EINVAL; + } + LPTMR_INSTANCE->CMR = CYCLES_PER_TICK; + + /* + * Enable interrupts and the timer. There's no need to clear the + * TFC bit in the csr variable, as it's already clear. + */ + enable_intmux0_pcc(); + + irq_enable(LPTMR_LEVEL0_IRQ); + csr = LPTMR_INSTANCE->CSR; + csr |= LPTMR_CSR_TEN(1); + LPTMR_INSTANCE->CSR = csr; + return 0; +} + +u32_t _timer_cycle_get_32(void) +{ + return cycle_count + LPTMR_INSTANCE->CNR; +} + +/* + * Since we're tickless, this is identically zero unless the timer + * interrupt is getting locked out due to other higher priority work. + */ +u32_t z_clock_elapsed(void) +{ + return 0; +} diff --git a/dts/riscv32/rv32m1_ri5cy.dtsi b/dts/riscv32/rv32m1_ri5cy.dtsi new file mode 100644 index 00000000000..dcddd2e3da5 --- /dev/null +++ b/dts/riscv32/rv32m1_ri5cy.dtsi @@ -0,0 +1,25 @@ +/* + * Copyright 2018 Foundries.io Ltd + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + #address-cells = <1>; + #size-cells = <1>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + cpu@0 { + device_type = "cpu"; + compatible = "riscv"; + reg = <0>; + }; + }; + + sram0: memory@20000000 { + device_type = "memory"; + compatible = "mmio-sram"; + reg = <0x20000000 0x30000>; + }; +}; diff --git a/ext/hal/CMakeLists.txt b/ext/hal/CMakeLists.txt index cbdd31783b4..54db876604a 100644 --- a/ext/hal/CMakeLists.txt +++ b/ext/hal/CMakeLists.txt @@ -4,6 +4,7 @@ add_subdirectory(cypress) add_subdirectory_if_kconfig(libmetal) add_subdirectory(nordic) add_subdirectory(nxp) +add_subdirectory(openisa) add_subdirectory_if_kconfig(qmsi) add_subdirectory(st) add_subdirectory(ti) diff --git a/ext/hal/Kconfig b/ext/hal/Kconfig index 5ff96b70fcb..773caa581c5 100644 --- a/ext/hal/Kconfig +++ b/ext/hal/Kconfig @@ -26,6 +26,8 @@ source "ext/hal/nxp/mcux/Kconfig" source "ext/hal/nxp/imx/Kconfig" +source "ext/hal/openisa/vega_sdk_riscv/Kconfig" + source "ext/hal/qmsi/Kconfig" source "ext/hal/silabs/gecko/Kconfig" diff --git a/ext/hal/openisa/CMakeLists.txt b/ext/hal/openisa/CMakeLists.txt new file mode 100644 index 00000000000..f6f7083bdad --- /dev/null +++ b/ext/hal/openisa/CMakeLists.txt @@ -0,0 +1,4 @@ +add_subdirectory_ifdef( + CONFIG_VEGA_SDK_HAL + vega_sdk_riscv + ) diff --git a/ext/hal/openisa/vega_sdk_riscv/CMakeLists.txt b/ext/hal/openisa/vega_sdk_riscv/CMakeLists.txt new file mode 100644 index 00000000000..29994f2da58 --- /dev/null +++ b/ext/hal/openisa/vega_sdk_riscv/CMakeLists.txt @@ -0,0 +1,16 @@ +# This CMakeLists.txt is being kept deliberately simple for now, since +# the HAL is currently only needed to support one SoC. + +zephyr_include_directories(RISCV) +zephyr_include_directories(devices/RV32M1) + +# The HAL uses a CPU name to expose core-specific features. +# See fsl_device_registers.h and $CPU_RV32M1_{ri5cy,zero_riscy}_features.h +# for details. +if(CONFIG_SOC_OPENISA_RV32M1_RI5CY) + zephyr_compile_definitions(CPU_RV32M1_ri5cy) +else() + zephyr_compile_definitions(CPU_RV32M1_zero_riscy) +endif() + +add_subdirectory(devices/RV32M1/drivers) diff --git a/ext/hal/openisa/vega_sdk_riscv/Kconfig b/ext/hal/openisa/vega_sdk_riscv/Kconfig new file mode 100644 index 00000000000..e10f764fa38 --- /dev/null +++ b/ext/hal/openisa/vega_sdk_riscv/Kconfig @@ -0,0 +1,7 @@ +# Copyright (c) 2018 Foundries.io +# +# SPDX-License-Identifier: Apache-2.0 + +menuconfig VEGA_SDK_HAL + bool "RV32M1 VEGA SDK support" + depends on SOC_OPENISA_RV32M1_RISCV32 diff --git a/ext/hal/openisa/vega_sdk_riscv/README b/ext/hal/openisa/vega_sdk_riscv/README index 7fe7e79fe0e..a25c539d68d 100644 --- a/ext/hal/openisa/vega_sdk_riscv/README +++ b/ext/hal/openisa/vega_sdk_riscv/README @@ -38,4 +38,5 @@ License Link: Patch List: No changes were made to any imported source files. - Additional Zephyr-specific files may be added (Kconfig, CMake, etc.) + Additional Zephyr-specific build system files were added (Kconfig files, + CMakeLists.txt, etc.) diff --git a/ext/hal/openisa/vega_sdk_riscv/devices/RV32M1/drivers/CMakeLists.txt b/ext/hal/openisa/vega_sdk_riscv/devices/RV32M1/drivers/CMakeLists.txt new file mode 100644 index 00000000000..33cd6b7ff36 --- /dev/null +++ b/ext/hal/openisa/vega_sdk_riscv/devices/RV32M1/drivers/CMakeLists.txt @@ -0,0 +1,3 @@ +zephyr_include_directories(.) + +zephyr_sources(fsl_clock.c) diff --git a/soc/riscv32/openisa_rv32m1/CMakeLists.txt b/soc/riscv32/openisa_rv32m1/CMakeLists.txt new file mode 100644 index 00000000000..433ac777519 --- /dev/null +++ b/soc/riscv32/openisa_rv32m1/CMakeLists.txt @@ -0,0 +1,20 @@ +# Copyright (c) 2018 Foundries.io Ltd +# +# SPDX-License-Identifier: Apache-2.0 + +if(CONFIG_SOC_OPENISA_RV32M1_RI5CY) + if (CONFIG_RISCV_GENERIC_TOOLCHAIN) + zephyr_compile_options(-march=rv32imc) + else() + zephyr_compile_options(-march=rv32imcxpulpv2) + endif() +elseif(CONFIG_SOC_OPENISA_RV32M1_ZERO_RISCY) + zephyr_compile_options(-march=rv32imc) +endif() + +zephyr_sources( + vector.S + soc_irq.S + wdog.S + soc.c +) diff --git a/soc/riscv32/openisa_rv32m1/Kconfig b/soc/riscv32/openisa_rv32m1/Kconfig new file mode 100644 index 00000000000..94fa8365843 --- /dev/null +++ b/soc/riscv32/openisa_rv32m1/Kconfig @@ -0,0 +1,29 @@ +# Copyright (c) 2018 Foundries.io Ltd +# +# SPDX-License-Identifier: Apache-2.0 + +# The OpenISA RV32M1 SoC directory in riscv32 supports the RISC-V +# cores on OpenISA RV32M1 SoCs. +# +# The Zephyr "soc" abstraction isn't a great fit here. These SoCs (in +# the strict physical sense of "systems on chip") also contain Arm +# cores, so this type of "soc" doesn't really belong to a single "arch". +# +# However, due to constraints imposed by Zephyr's file hierarchy +# conventions, those "other" cores would need to be supported under a +# different soc subdirectory, e.g. soc/arm instead of soc/riscv32. + +if SOC_OPENISA_RV32M1_RISCV32 + +choice +prompt "OpenISA RV32M1 RISC-V Core Selection" + +config SOC_OPENISA_RV32M1_RI5CY + bool "OpenISA RV32M1 RI5CY core" + +config SOC_OPENISA_RV32M1_ZERO_RISCY + bool "OpenISA RV32M1 ZERO-RISCY core" + +endchoice + +endif # SOC_OPENISA_RV32M1_RISCV32 diff --git a/soc/riscv32/openisa_rv32m1/Kconfig.defconfig b/soc/riscv32/openisa_rv32m1/Kconfig.defconfig new file mode 100644 index 00000000000..4d4d2d80df4 --- /dev/null +++ b/soc/riscv32/openisa_rv32m1/Kconfig.defconfig @@ -0,0 +1,76 @@ +# Kconfig.defconfig: RV32M1 SoC RISC-V core default configuration values +# +# Copyright (c) 2018 Foundries.io Ltd +# +# SPDX-License-Identifier: Apache-2.0 + +if SOC_OPENISA_RV32M1_RISCV32 + +config SOC + string + default "openisa_rv32m1" + +config NUM_IRQS + int + default 32 + +config XIP + bool + default y + +config RISCV_GENERIC_TOOLCHAIN + bool + default n + +config RISCV_SOC_CONTEXT_SAVE + bool + default y if SOC_OPENISA_RV32M1_RI5CY + +config RISCV_SOC_INTERRUPT_INIT + bool + default y + +# We need to disable the watchdog out of reset, as it's enabled by +# default. Use the WDOG_INIT hook for doing that. +config WDOG_INIT + def_bool y + +# Built-in flash allocated to each chip. This configuration +# assumes the Arm cores are disabled, as these base addresses +# contain the Arm core vector tables if they are used. +config RISCV32_RV32M1_ROM_BASE_ADDR + hex + default 0x00000000 if SOC_OPENISA_RV32M1_RI5CY + default 0x01000000 if SOC_OPENISA_RV32M1_ZERO_RISCY + +config RISCV32_RV32M1_ROM_SIZE + hex + default 0x000FFF00 if SOC_OPENISA_RV32M1_RI5CY + default 0x0003FF00 if SOC_OPENISA_RV32M1_ZERO_RISCY + +config RISCV32_RV32M1_RAM_BASE_ADDR + hex + default 0x20000000 if SOC_OPENISA_RV32M1_RI5CY + default 0x09000000 if SOC_OPENISA_RV32M1_ZERO_RISCY + +config RISCV32_RV32M1_RAM_SIZE + hex + default 0x00030000 if SOC_OPENISA_RV32M1_RI5CY + default 0x00020000 if SOC_OPENISA_RV32M1_ZERO_RISCY + +# The event unit looks for vector tables at the end of each core's +# flash space. These vector tables are not relocatable. +config RISCV32_RV32M1_VECTOR_BASE_ADDR + hex + default 0x000FFF00 if SOC_OPENISA_RV32M1_RI5CY + default 0x0103FF00 if SOC_OPENISA_RV32M1_ZERO_RISCY + +config RISCV32_RV32M1_VECTOR_SIZE + hex + default 0x100 + +config SYS_CLOCK_HW_CYCLES_PER_SEC + int + default 8000000 if SOC_OPENISA_RV32M1_RI5CY # SIRC at 8MHz + +endif # SOC_OPENISA_RV32M1_RISCV32 diff --git a/soc/riscv32/openisa_rv32m1/Kconfig.soc b/soc/riscv32/openisa_rv32m1/Kconfig.soc new file mode 100644 index 00000000000..ab4751f38b9 --- /dev/null +++ b/soc/riscv32/openisa_rv32m1/Kconfig.soc @@ -0,0 +1,21 @@ +# Copyright (c) 2018 Foundries.io Ltd +# +# SPDX-License-Identifier: Apache-2.0 + +config SOC_OPENISA_RV32M1_RISCV32 + bool "OpenISA RV32M1 RISC-V cores" + depends on RISCV32 + # The following depends is due to limitations in the linker script. + # It's not inherent to the chip itself. + depends on !CUSTOM_RODATA_LD && !CUSTOM_RWDATA_LD + # The following select is also due to limitations in the linker script. + # (We can't make it a 'depends on' without causing a dependency loop). + select XIP + select HAS_DTS + select ATOMIC_OPERATIONS_C + select VEGA_SDK_HAL + select RISCV_SOC_INTERRUPT_INIT + help + Enable support for OpenISA RV32M1 RISC-V processors. Choose + this option to target the RI5CY or ZERO-RISCY core. This + option should not be used to target either Arm core. diff --git a/soc/riscv32/openisa_rv32m1/linker.ld b/soc/riscv32/openisa_rv32m1/linker.ld new file mode 100644 index 00000000000..845709d35fa --- /dev/null +++ b/soc/riscv32/openisa_rv32m1/linker.ld @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2013-2014 Wind River Systems, Inc. + * Copyright (c) 2016-2017 Jean-Paul Etienne + * Copyright (c) 2018 Foundries.io Ltd + * + * This file is based on: + * + * - include/arch/arm/cortex_m/scripts/linker.ld + * - include/arch/riscv32/common/linker.ld + * - include/arch/riscv32/pulpino/linker.ld + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define _LINKER +#define _ASMLANGUAGE + +#include + +#include +#include +#include + +/* + * Extra efforts would need to be taken to ensure the IRQ handlers are within + * jumping distance of the vector table in non-XIP builds, so avoid them. + */ +#define ROMABLE_REGION ROM +#define RAMABLE_REGION RAM + +#define ROM_BASE CONFIG_RISCV32_RV32M1_ROM_BASE_ADDR +#define ROM_SIZE CONFIG_RISCV32_RV32M1_ROM_SIZE +#define RAM_BASE CONFIG_RISCV32_RV32M1_RAM_BASE_ADDR +#define RAM_SIZE CONFIG_RISCV32_RV32M1_RAM_SIZE +#define VECTOR_BASE CONFIG_RISCV32_RV32M1_VECTOR_BASE_ADDR +#define VECTOR_SIZE CONFIG_RISCV32_RV32M1_VECTOR_SIZE + +MEMORY + { + ROM (rx) : ORIGIN = ROM_BASE, LENGTH = ROM_SIZE + /* + * Each RISC-V core on this chip (RI5CY and ZERO-RISCY) has + * a vector table at the end of its flash bank. They are relocatable + * at runtime, but we need to put the reset vectors in hardcoded places. + * + * (The Arm core vector tables are at the beginning of each + * flash bank.) + */ + VECTORS (rx) : ORIGIN = VECTOR_BASE, LENGTH = VECTOR_SIZE + RAM (rwx) : ORIGIN = RAM_BASE, LENGTH = RAM_SIZE + /* + * Special section, not included in the final binary, used + * to generate interrupt tables. See include/linker/intlist.ld. + */ + IDT_LIST (wx) : ORIGIN = 0xFFFFF7FF, LENGTH = 2K + } + +ENTRY(CONFIG_KERNEL_ENTRY) + +SECTIONS + { + +#include + + SECTION_PROLOGUE(.plt,,) + { + *(.plt) + } + + SECTION_PROLOGUE(.iplt,,) + { + *(.iplt) + } + + GROUP_START(ROM) + _image_rom_start = ROM_BASE; + + SECTION_PROLOGUE(_TEXT_SECTION_NAME,,) + { + . = CONFIG_TEXT_SECTION_OFFSET; + . = ALIGN(4); + + /* + * Respect for CONFIG_TEXT_SECTION_OFFSET is mandatory + * for MCUboot support, so .reset.* and .exception.* + * must come after that offset from ROM_BASE. + */ + KEEP(*(.reset.*)) + KEEP(*(".exception.entry.*")) /* contains __irq_wrapper */ + *(".exception.other.*") + + KEEP(*(.openocd_debug)) + KEEP(*(".openocd_debug.*")) + + _image_text_start = .; + *(.text .text.*) + *(.gnu.linkonce.t.*) + *(.eh_frame) + } GROUP_LINK_IN(ROM) + + _image_text_end = .; + + _image_rodata_start = .; + +#include + + SECTION_PROLOGUE(_RODATA_SECTION_NAME,,) + { + . = ALIGN(4); + *(.rodata) + *(.rodata.*) + *(.gnu.linkonce.r.*) + } GROUP_LINK_IN(ROMABLE_REGION) + + _image_rodata_end = .; + _image_rom_end = .; + + /* The vector table goes into core-dependent flash locations. */ + SECTION_PROLOGUE(vectors,,) + { + _vector_start = .; + KEEP(*(.vectors.*)) + } GROUP_LINK_IN(VECTORS) + _vector_end = .; + + GROUP_END(ROM) + + GROUP_START(RAM) + + SECTION_DATA_PROLOGUE(_DATA_SECTION_NAME,,) + { + . = ALIGN(4); + _image_ram_start = .; + __data_ram_start = .; + + *(.data) + *(.data.*) + *(.gnu.linkonce.s.*) + + /* https://groups.google.com/a/groups.riscv.org/d/msg/sw-dev/60IdaZj27dY/TKT3hbNlAgAJ */ + *(.sdata .sdata.* .gnu.linkonce.s.*) + *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) + } GROUP_DATA_LINK_IN(RAMABLE_REGION, ROMABLE_REGION) + +#include + + __data_ram_end = .; + __data_rom_start = LOADADDR(_DATA_SECTION_NAME); + + SECTION_DATA_PROLOGUE(_BSS_SECTION_NAME,(NOLOAD),) + { + /* + * For performance, BSS section is assumed to be 4 byte aligned and + * a multiple of 4 bytes, so it can be cleared in words. + */ + . = ALIGN(4); + __bss_start = .; + + *(.bss .bss.*) + *(.sbss .sbss.*) + COMMON_SYMBOLS + + /* Ensure 4 byte alignment for the entire section. */ + . = ALIGN(4); + __bss_end = .; + } GROUP_DATA_LINK_IN(RAMABLE_REGION, RAMABLE_REGION) + + SECTION_PROLOGUE(_NOINIT_SECTION_NAME,(NOLOAD),) + { + /* + * This section is used for non-initialized objects that + * will not be cleared during the boot process. + */ + *(.noinit .noinit.*) + } GROUP_LINK_IN(RAMABLE_REGION) + + _image_ram_end = .; + _end = .; /* end of image */ + + GROUP_END(RAM) + +#ifdef CONFIG_CUSTOM_SECTIONS_LD +/* Located in project source directory */ +#include +#endif + +#ifdef CONFIG_GEN_ISR_TABLES +/* Bogus section, post-processed during the build to initialize interrupts. */ +#include +#endif + +#include + + /* + * Pulpino toolchains emit these sections; we don't care about them, + * but need to avoid build system warnings about orphaned sections. + */ + SECTION_PROLOGUE(.Pulp_Chip.Info,,) + { + *(.Pulp_Chip.*) + } + + } diff --git a/soc/riscv32/openisa_rv32m1/soc.c b/soc/riscv32/openisa_rv32m1/soc.c new file mode 100644 index 00000000000..dbf60cb6ed1 --- /dev/null +++ b/soc/riscv32/openisa_rv32m1/soc.c @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2018 Foundries.io + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include +#include +#include + +#define SCG_LPFLL_DISABLE 0U + +/* + * Run-mode configuration for the fast internal reference clock (FIRC). + */ +static const scg_firc_config_t rv32m1_firc_config = { + .enableMode = kSCG_FircEnable, + .div1 = kSCG_AsyncClkDivBy1, + .div2 = kSCG_AsyncClkDivBy1, + .div3 = kSCG_AsyncClkDivBy1, + .range = kSCG_FircRange48M, + .trimConfig = NULL, +}; + +/* + * FIRC-based system clock configuration. + */ +static const scg_sys_clk_config_t rv32m1_sys_clk_config_firc = { + .divSlow = kSCG_SysClkDivBy2, + .divBus = kSCG_SysClkDivBy1, + .divExt = kSCG_SysClkDivBy1, + .divCore = kSCG_SysClkDivBy1, + .src = kSCG_SysClkSrcFirc, +}; + +/* + * LPFLL configuration. + */ +static const scg_lpfll_config_t rv32m1_lpfll_cfg = { + .enableMode = SCG_LPFLL_DISABLE, + .div1 = kSCG_AsyncClkDivBy1, + .div2 = kSCG_AsyncClkDisable, + .div3 = kSCG_AsyncClkDisable, + .range = kSCG_LpFllRange48M, + .trimConfig = NULL, +}; + +void _arch_irq_enable(unsigned int irq) +{ + EVENT_UNIT->INTPTEN |= (1U << irq); + (void)(EVENT_UNIT->INTPTEN); /* Ensures write has finished. */ +} + +void _arch_irq_disable(unsigned int irq) +{ + EVENT_UNIT->INTPTEN &= ~(1U << irq); + (void)(EVENT_UNIT->INTPTEN); /* Ensures write has finished. */ +} + +int _arch_irq_is_enabled(unsigned int irq) +{ + return (EVENT_UNIT->INTPTEN & (1U << irq)) != 0; +} + +/* + * SoC-level interrupt initialization. Clear any pending interrupts or + * events. + */ +void soc_interrupt_init(void) +{ + EVENT_UNIT->INTPTPENDCLEAR = 0xFFFFFFFF; + (void)(EVENT_UNIT->INTPTPENDCLEAR); /* Ensures write has finished. */ + EVENT_UNIT->EVTPENDCLEAR = 0xFFFFFFFF; + (void)(EVENT_UNIT->EVTPENDCLEAR); /* Ensures write has finished. */ +} + +/** + * @brief Switch system clock configuration in run mode. + * + * Blocks until the updated configuration takes effect. + * + * @param cfg New system clock configuration + */ +static void rv32m1_switch_sys_clk(const scg_sys_clk_config_t *cfg) +{ + scg_sys_clk_config_t cur_cfg; + + CLOCK_SetRunModeSysClkConfig(cfg); + do { + CLOCK_GetCurSysClkConfig(&cur_cfg); + } while (cur_cfg.src != cfg->src); +} + +/** + * @brief Initializes SIRC and switches system clock source to SIRC. + */ +static void rv32m1_switch_to_sirc(void) +{ + const scg_sirc_config_t sirc_config = { + .enableMode = kSCG_SircEnable, + .div1 = kSCG_AsyncClkDisable, + .div2 = kSCG_AsyncClkDivBy2, + .range = kSCG_SircRangeHigh, + }; + const scg_sys_clk_config_t sys_clk_config_sirc = { + .divSlow = kSCG_SysClkDivBy4, + .divCore = kSCG_SysClkDivBy1, + .src = kSCG_SysClkSrcSirc, + }; + + CLOCK_InitSirc(&sirc_config); + rv32m1_switch_sys_clk(&sys_clk_config_sirc); +} + +/** + * @brief Perform basic hardware initialization + * + * Initializes the base clocks and LPFLL using helpers provided by the HAL. + * + * @return 0 + */ +static int soc_rv32m1_init(struct device *arg) +{ + unsigned int key; + + ARG_UNUSED(arg); + + key = irq_lock(); + + /* Switch to SIRC so we can initialize the FIRC. */ + rv32m1_switch_to_sirc(); + + /* Now that we're running off of SIRC, set up and switch to FIRC. */ + CLOCK_InitFirc(&rv32m1_firc_config); + rv32m1_switch_sys_clk(&rv32m1_sys_clk_config_firc); + + /* Initialize LPFLL */ + CLOCK_InitLpFll(&rv32m1_lpfll_cfg); + + irq_unlock(key); + + return 0; +} + +SYS_INIT(soc_rv32m1_init, PRE_KERNEL_1, 0); diff --git a/soc/riscv32/openisa_rv32m1/soc.h b/soc/riscv32/openisa_rv32m1/soc.h new file mode 100644 index 00000000000..cc017c014b1 --- /dev/null +++ b/soc/riscv32/openisa_rv32m1/soc.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2018 Foundries.io Ltd + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef SOC_RISCV32_OPENISA_RV32M1_SOC_H_ +#define SOC_RISCV32_OPENISA_RV32M1_SOC_H_ + +#ifndef _ASMLANGUAGE + +#include "fsl_device_registers.h" + +void soc_interrupt_init(void); + +#endif /* !_ASMLANGUAGE */ + +#if defined(CONFIG_SOC_OPENISA_RV32M1_RI5CY) +#include "soc_ri5cy.h" +#elif defined(CONFIG_SOC_OPENISA_RV32M1_ZERO_RISCY) +#include "soc_zero_riscy.h" +#endif + +/* Newlib hooks (and potentially other things) use these defines. */ +#define RISCV_RAM_SIZE CONFIG_RISCV32_RV32M1_RAM_SIZE +#define RISCV_RAM_BASE CONFIG_RISCV32_RV32M1_RAM_BASE_ADDR + +#endif /* SOC_RISCV32_OPENISA_RV32M1_SOC_H_ */ diff --git a/soc/riscv32/openisa_rv32m1/soc_context.h b/soc/riscv32/openisa_rv32m1/soc_context.h new file mode 100644 index 00000000000..b6ee789d38a --- /dev/null +++ b/soc/riscv32/openisa_rv32m1/soc_context.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2018 Foundries.io Ltd + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * Extra definitions required for CONFIG_RISCV_SOC_CONTEXT_SAVE. + */ + +#ifndef SOC_RISCV32_OPENISA_RV32M1_SOC_CONTEXT_H_ +#define SOC_RISCV32_OPENISA_RV32M1_SOC_CONTEXT_H_ + +#ifdef CONFIG_SOC_OPENISA_RV32M1_RI5CY + +/* Extra state for RI5CY hardware loop registers. */ +#define SOC_ESF_MEMBERS \ + u32_t lpstart0; \ + u32_t lpend0; \ + u32_t lpcount0; \ + u32_t lpstart1; \ + u32_t lpend1; \ + u32_t lpcount1 + +/* Initial saved state. */ +#define SOC_ESF_INIT \ + 0xdeadbaad, \ + 0xdeadbaad, \ + 0xdeadbaad, \ + 0xdeadbaad, \ + 0xdeadbaad, \ + 0xdeadbaad + +/* + * Ensure offset macros are available in for the above. + * + * Also create a macro which contains the value of &EVENT0->INTPTPENDCLEAR, + * for use in assembly. + */ +#define GEN_SOC_OFFSET_SYMS() \ + GEN_OFFSET_SYM(soc_esf_t, lpstart0); \ + GEN_OFFSET_SYM(soc_esf_t, lpend0); \ + GEN_OFFSET_SYM(soc_esf_t, lpcount0); \ + GEN_OFFSET_SYM(soc_esf_t, lpstart1); \ + GEN_OFFSET_SYM(soc_esf_t, lpend1); \ + GEN_OFFSET_SYM(soc_esf_t, lpcount1); \ + GEN_ABSOLUTE_SYM(__EVENT0_INTPTPENDCLEAR, \ + (uint32_t)&EVENT0->INTPTPENDCLEAR) + +#endif /* CONFIG_SOC_OPENISA_RV32M1_RI5CY */ + +#endif /* SOC_RISCV32_OPENISA_RV32M1_SOC_CONTEXT_H_ */ diff --git a/soc/riscv32/openisa_rv32m1/soc_irq.S b/soc/riscv32/openisa_rv32m1/soc_irq.S new file mode 100644 index 00000000000..dd6a72bd1f7 --- /dev/null +++ b/soc/riscv32/openisa_rv32m1/soc_irq.S @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2018 Foundries.io Ltd + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include + +/* Exports */ +GTEXT(__soc_is_irq) +GTEXT(__soc_handle_irq) +#ifdef CONFIG_RISCV_SOC_CONTEXT_SAVE +GTEXT(__soc_save_context) +GTEXT(__soc_restore_context) +#endif + +/* + * Whether we're in an IRQ is bog-standard RISC-V on this SoC: + * yes if the top mcause bit is set, otherwise no. + */ +SECTION_FUNC(exception.other, __soc_is_irq) + csrr a0, mcause + srli a0, a0, 31 + ret + +/* + * With a0 == irq_num, this is equivalent to: + * + * EVENT_UNIT->INTPTPENDCLEAR = (1U << irq_num); + * + * We could write this routine in C, but the assembly + * that's calling us requires that a0 still contain irq_num + * on return, and assuming nobody would ever change a + * C implementation in a way that silently clobbers it + * is playing with fire. Instead, we play tricks in + * soc_context.h so that offsets.h contains a pointer to + * INTPTPENDCLEAR. + */ +SECTION_FUNC(exception.other, __soc_handle_irq) + la t0, __EVENT0_INTPTPENDCLEAR + li t1, 1 + sll t1, t1, a0 + sw t1, 0x00(t0) + ret + +#ifdef CONFIG_RISCV_SOC_CONTEXT_SAVE +/* + * The RI5CY core has ISA extensions for faster loop performance + * that use extra registers. + * + * If the toolchain generates instructions that use them, they must be saved + * prior to handling an interrupt/exception. This case is handled using + * Zephyr's generic RISC-V mechanism for soc-specific context. + * + * For details, see the Kconfig help for CONFIG_RISCV_SOC_CONTEXT_SAVE. + */ +SECTION_FUNC(exception.other, __soc_save_context) +#ifdef CONFIG_SOC_OPENISA_RV32M1_RI5CY + csrr t0, RI5CY_LPSTART0 + csrr t1, RI5CY_LPEND0 + csrr t2, RI5CY_LPCOUNT0 + sw t0, __soc_esf_t_lpstart0_OFFSET(a0) + sw t1, __soc_esf_t_lpend0_OFFSET(a0) + sw t2, __soc_esf_t_lpcount0_OFFSET(a0) + csrr t0, RI5CY_LPSTART1 + csrr t1, RI5CY_LPEND1 + csrr t2, RI5CY_LPCOUNT1 + sw t0, __soc_esf_t_lpstart1_OFFSET(a0) + sw t1, __soc_esf_t_lpend1_OFFSET(a0) + sw t2, __soc_esf_t_lpcount1_OFFSET(a0) +#endif /* CONFIG_SOC_OPENISA_RV32M1_RI5CY */ + + ret + +SECTION_FUNC(exception.other, __soc_restore_context) +#ifdef CONFIG_SOC_OPENISA_RV32M1_RI5CY + lw t0, __soc_esf_t_lpstart0_OFFSET(a0) + lw t1, __soc_esf_t_lpend0_OFFSET(a0) + lw t2, __soc_esf_t_lpcount0_OFFSET(a0) + csrw RI5CY_LPSTART0, t0 + csrw RI5CY_LPEND0, t1 + csrw RI5CY_LPCOUNT0, t2 + lw t0, __soc_esf_t_lpstart1_OFFSET(a0) + lw t1, __soc_esf_t_lpend1_OFFSET(a0) + lw t2, __soc_esf_t_lpcount1_OFFSET(a0) + csrw RI5CY_LPSTART1, t0 + csrw RI5CY_LPEND1, t1 + csrw RI5CY_LPCOUNT1, t2 +#endif /* CONFIG_SOC_OPENISA_RV32M1_RI5CY */ + + ret +#endif /* CONFIG_RISCV_SOC_CONTEXT_SAVE */ diff --git a/soc/riscv32/openisa_rv32m1/soc_ri5cy.h b/soc/riscv32/openisa_rv32m1/soc_ri5cy.h new file mode 100644 index 00000000000..eee84b7b103 --- /dev/null +++ b/soc/riscv32/openisa_rv32m1/soc_ri5cy.h @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2018 Foundries.io Ltd + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef SOC_RISCV32_OPENISA_RV32M1_SOC_RI5CY_H_ +#define SOC_RISCV32_OPENISA_RV32M1_SOC_RI5CY_H_ + +/* Control and Status Registers (CSRs) available for RI5CY. */ +#define RI5CY_USTATUS 0x000 +#define RI5CY_UTVEC 0x005 +#define RI5CY_UHARTID 0x014 +#define RI5CY_UEPC 0x041 +#define RI5CY_UCAUSE 0x042 +#define RI5CY_MSTATUS 0x300 +#define RI5CY_MTVEC 0x305 +#define RI5CY_MEPC 0x341 +#define RI5CY_MCAUSE 0x342 +#define RI5CY_PCCR0 0x780 +#define RI5CY_PCCR1 0x781 +#define RI5CY_PCCR2 0x782 +#define RI5CY_PCCR3 0x783 +#define RI5CY_PCCR4 0x784 +#define RI5CY_PCCR5 0x785 +#define RI5CY_PCCR6 0x786 +#define RI5CY_PCCR7 0x787 +#define RI5CY_PCCR8 0x788 +#define RI5CY_PCCR9 0x789 +#define RI5CY_PCCR10 0x78A +#define RI5CY_PCCR11 0x78B +#define RI5CY_PCER 0x7A0 +#define RI5CY_PCMR 0x7A1 +#define RI5CY_LPSTART0 0x7B0 +#define RI5CY_LPEND0 0x7B1 +#define RI5CY_LPCOUNT0 0x7B2 +#define RI5CY_LPSTART1 0x7B4 +#define RI5CY_LPEND1 0x7B5 +#define RI5CY_LPCOUNT1 0x7B6 +#define RI5CY_PRIVLV 0xC10 +#define RI5CY_MHARTID 0xF14 + +/* + * Map from SoC-specific configuration to generic Zephyr macros. + * + * These are expected by the code in arch/, and must be provided for + * the kernel to work (or even build at all). + * + * Some of these may also apply to ZERO-RISCY; needs investigation. + */ + +/* + * MSTATUS CSR number. (Note this is the standard value in the RISC-V + * privileged ISA v1.10). + */ +#define SOC_MSTATUS_REG RI5CY_MSTATUS +/* MSTATUS's interrupt enable mask. This is also standard. */ +#define SOC_MSTATUS_IEN (1U << 3) +/* + * Exception code mask. Use of the bottom five bits is a subset of + * what the standard allocates (which is XLEN-1 bits). + */ +#define SOC_MCAUSE_EXP_MASK 0x1F +/* + * Assembler instruction to exit from interrupt in machine mode. + * The name "ERET" is a leftover from pre-v1.10 privileged ISA specs. + * The "mret" mnemonic works properly with the Pulpino toolchain; + * YMMV if using a generic toolchain. + */ +#define SOC_ERET mret +/* The ecall exception number. This is a standard value. */ +#define SOC_MCAUSE_ECALL_EXP 11 +/* + * Default MSTATUS value to write when scheduling in a new thread for + * the first time. + * + * - Preserve machine privileges in MPP. If you see any documentation + * telling you that MPP is read-only on this SoC, don't believe its + * lies. + * - Enable interrupts when exiting from exception into a new thread + * by setting MPIE now, so it will be copied into IE on mret. + */ +#define RI5CY_MSTATUS_MPP_M (0x3U << 11) +#define RI5CY_MSTATUS_MPIE_EN (1U << 7) +#define SOC_MSTATUS_DEF_RESTORE (RI5CY_MSTATUS_MPP_M | \ + RI5CY_MSTATUS_MPIE_EN) + +#endif /* SOC_RISCV32_OPENISA_RV32M1_SOC_RI5CY_H_ */ diff --git a/soc/riscv32/openisa_rv32m1/soc_zero_riscy.h b/soc/riscv32/openisa_rv32m1/soc_zero_riscy.h new file mode 100644 index 00000000000..714a57aa1de --- /dev/null +++ b/soc/riscv32/openisa_rv32m1/soc_zero_riscy.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2018 Foundries.io Ltd + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef SOC_RISCV32_OPENISA_RV32M1_SOC_ZERO_RISCY_H_ +#define SOC_RISCV32_OPENISA_RV32M1_SOC_ZERO_RISCY_H_ + +/* Control and Status Registers (CSRs) available for ZERO_RISCY. */ +#define ZERO_RISCY_MSTATUS 0x300U +#define ZERO_RISCY_MTVEC 0x305U +#define ZERO_RISCY_MEPC 0x341U +#define ZERO_RISCY_MCAUSE 0x342U +#define ZERO_RISCY_PCCR0 0x780U +#define ZERO_RISCY_PCCR1 0x781U +#define ZERO_RISCY_PCCR2 0x782U +#define ZERO_RISCY_PCCR3 0x783U +#define ZERO_RISCY_PCCR4 0x784U +#define ZERO_RISCY_PCCR5 0x785U +#define ZERO_RISCY_PCCR6 0x786U +#define ZERO_RISCY_PCCR7 0x787U +#define ZERO_RISCY_PCCR8 0x788U +#define ZERO_RISCY_PCCR9 0x789U +#define ZERO_RISCY_PCCR10 0x78AU +#define ZERO_RISCY_PCCR 0x78BU +#define ZERO_RISCY_PCER 0x7A0U +#define ZERO_RISCY_PCMR 0x7A1U +#define ZERO_RISCY_MHARTID 0xF14U + +/* + * Map from SoC-specific configuration to generic Zephyr macros. + * + * These are expected by the code in arch/, and must be provided for + * the kernel to work (or even build at all). + * + * Some of these may also apply to ZERO-RISCY; needs investigation. + */ + +/* + * MSTATUS CSR number. (Note this is the standard value in the RISC-V + * privileged ISA v1.10). + */ +#define SOC_MSTATUS_REG ZERO_RISCY_MSTATUS +/* MSTATUS's interrupt enable mask. This is also standard. */ +#define SOC_MSTATUS_IEN (1U << 3) +/* + * Exception code mask. Use of the bottom five bits is a subset of + * what the standard allocates (which is XLEN-1 bits). + */ +#define SOC_MCAUSE_EXP_MASK 0x1F +/* + * Assembler instruction to exit from interrupt in machine mode. + * The name "ERET" is a leftover from pre-v1.10 privileged ISA specs. + * The "mret" mnemonic works properly with the Pulpino toolchain; + * YMMV if using a generic toolchain. + */ +#define SOC_ERET mret +/* The ecall exception number. This is a standard value. */ +#define SOC_MCAUSE_ECALL_EXP 11 +/* + * Default MSTATUS value to write when scheduling in a new thread for + * the first time. + * + * - Preserve machine privileges in MPP. If you see any documentation + * telling you that MPP is read-only on this SoC, don't believe its + * lies. + * - Enable interrupts when exiting from exception into a new thread + * by setting MPIE now, so it will be copied into IE on mret. + */ +#define ZERO_RISCY_MSTATUS_MPP_M (0x3U << 11) +#define ZERO_RISCY_MSTATUS_MPIE_EN (1U << 7) +#define SOC_MSTATUS_DEF_RESTORE (ZERO_RISCY_MSTATUS_MPP_M | \ + ZERO_RISCY_MSTATUS_MPIE_EN) + +#endif /* SOC_RISCV32_OPENISA_RV32M1_SOC_ZERO_RISCY_H_ */ diff --git a/soc/riscv32/openisa_rv32m1/vector.S b/soc/riscv32/openisa_rv32m1/vector.S new file mode 100644 index 00000000000..7e62a98e2e3 --- /dev/null +++ b/soc/riscv32/openisa_rv32m1/vector.S @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2018 Foundries.io Ltd + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/* Imports */ +GTEXT(__initialize) +GTEXT(__irq_wrapper) + +/* Exports */ +GTEXT(__start) + +/* + * Interrupts work the same way for both the RI5CY and ZERO-RISCY cores + * in this SoC; the only difference is the location of the vectors section + * on flash. We thus reuse this ivt definition for each core. + * + * On interrupt, the event unit sets pc to the address in this table + * at byte offset 4 * (IRQ line number). + * + * The reset, illegal instruction, ecall, and load store unit error exceptions + * are handled by the addresses right after the IRQ table. + * + * Note: Per RV32I restrictions, "j SOME_HANDLER" can jump within a +/- 1MiB + * range. This is not a problem on this SoC: RI5CY is allocated 1MiB flash + * and ZERO-RISCY is allocated 256 KiB, and these flash banks contain the + * text and vectors sections, so the limits are satisfied. + */ +SECTION_FUNC(vectors, ivt) + .option norvc + + /* Interrupts */ + j __irq_wrapper /* IRQ 0 */ + j __irq_wrapper /* IRQ 1 */ + j __irq_wrapper /* IRQ 2 */ + j __irq_wrapper /* IRQ 3 */ + j __irq_wrapper /* IRQ 4 */ + j __irq_wrapper /* IRQ 5 */ + j __irq_wrapper /* IRQ 6 */ + j __irq_wrapper /* IRQ 7 */ + j __irq_wrapper /* IRQ 8 */ + j __irq_wrapper /* IRQ 9 */ + j __irq_wrapper /* IRQ 10 */ + j __irq_wrapper /* IRQ 11 */ + j __irq_wrapper /* IRQ 12 */ + j __irq_wrapper /* IRQ 13 */ + j __irq_wrapper /* IRQ 14 */ + j __irq_wrapper /* IRQ 15 */ + j __irq_wrapper /* IRQ 16 */ + j __irq_wrapper /* IRQ 17 */ + j __irq_wrapper /* IRQ 18 */ + j __irq_wrapper /* IRQ 19 */ + j __irq_wrapper /* IRQ 20 */ + j __irq_wrapper /* IRQ 21 */ + j __irq_wrapper /* IRQ 22 */ + j __irq_wrapper /* IRQ 23 */ + j __irq_wrapper /* IRQ 24 */ + j __irq_wrapper /* IRQ 25 */ + j __irq_wrapper /* IRQ 26 */ + j __irq_wrapper /* IRQ 27 */ + j __irq_wrapper /* IRQ 28 */ + j __irq_wrapper /* IRQ 29 */ + j __irq_wrapper /* IRQ 30 */ + j __irq_wrapper /* IRQ 31 */ + + /* Exceptions */ + j __start /* reset */ + j __irq_wrapper /* illegal instruction */ + j __irq_wrapper /* ecall */ + j __irq_wrapper /* load store eunit error */ + +SECTION_FUNC(vectors, __start) + /* Set mtvec to point at ivt. */ + la t0, ivt + csrw 0x305, t0 + /* Call into Zephyr initialization. */ + tail __initialize diff --git a/soc/riscv32/openisa_rv32m1/wdog.S b/soc/riscv32/openisa_rv32m1/wdog.S new file mode 100644 index 00000000000..fd17570cebe --- /dev/null +++ b/soc/riscv32/openisa_rv32m1/wdog.S @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2018 Foundries.io Ltd + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +/* Exports */ +GTEXT(_WdogInit) + +/* WDOG instance base address. */ +#ifdef CONFIG_SOC_OPENISA_RV32M1_RI5CY +#define WDOG_BASE 0x4002A000 /* WDOG0 */ +#else +#define WDOG_BASE 0x41026000 /* WDOG1 */ +#endif + +/* Register offsets. */ +#define WDOG_CS_OFFSET 0x00 +#define WDOG_CNT_OFFSET 0x04 +#define WDOG_TOVAL_OFFSET 0x08 + +/* Watchdog unlock key. */ +#define WDOG_CNT_UNLOCK 0xD928C520 + +/* TOVAL must be set when disabling watchdog after reset. */ +#define WDOG_TOVAL_SET 0xFFFF + +/* Disable the WDOG_CS[EN] bit. */ +#define WDOG_CS_EN_DISABLED ~0x80 +/* Set WDOG_CS[UPDATE] bit. */ +#define WDOG_CS_UPDATE_ENABLED 0x20 + +/* + * Unlock and disable the watchdog, which is enabled by default. + */ +SECTION_FUNC(TEXT, _WdogInit) + /* Disable interrupts if they're on. This is timing-sensitive code. */ + csrrc t0, mstatus, SOC_MSTATUS_IEN + + /* Get base address. */ + li t1, WDOG_BASE + + /* Unlock the watchdog. */ + li t2, WDOG_CNT_UNLOCK + sw t2, WDOG_CNT_OFFSET(t1) + + /* Disable the watchdog. Allow updates later. */ + lw t2, WDOG_CS_OFFSET(t1) + andi t2, t2, WDOG_CS_EN_DISABLED + ori t2, t2, WDOG_CS_UPDATE_ENABLED + sw t2, WDOG_CS_OFFSET(t1) + + /* This must also be done per reference manual. */ + li t2, WDOG_TOVAL_SET + sw t2, WDOG_TOVAL_OFFSET(t1) + + /* Re-enable interrupts if they were disabled. */ + csrrs x0, mstatus, t0 + ret