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 <marti@foundries.io> Signed-off-by: Michael Scott <mike@foundries.io>
This commit is contained in:
parent
1f96f55183
commit
502d306630
24 changed files with 1213 additions and 1 deletions
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
164
drivers/timer/rv32m1_lptmr_timer.c
Normal file
164
drivers/timer/rv32m1_lptmr_timer.c
Normal file
|
@ -0,0 +1,164 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Foundries.io Ltd
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr.h>
|
||||
#include <misc/util.h>
|
||||
#include <system_timer.h>
|
||||
#include <soc.h>
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
25
dts/riscv32/rv32m1_ri5cy.dtsi
Normal file
25
dts/riscv32/rv32m1_ri5cy.dtsi
Normal file
|
@ -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>;
|
||||
};
|
||||
};
|
|
@ -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)
|
||||
|
|
|
@ -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"
|
||||
|
|
4
ext/hal/openisa/CMakeLists.txt
Normal file
4
ext/hal/openisa/CMakeLists.txt
Normal file
|
@ -0,0 +1,4 @@
|
|||
add_subdirectory_ifdef(
|
||||
CONFIG_VEGA_SDK_HAL
|
||||
vega_sdk_riscv
|
||||
)
|
16
ext/hal/openisa/vega_sdk_riscv/CMakeLists.txt
Normal file
16
ext/hal/openisa/vega_sdk_riscv/CMakeLists.txt
Normal file
|
@ -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)
|
7
ext/hal/openisa/vega_sdk_riscv/Kconfig
Normal file
7
ext/hal/openisa/vega_sdk_riscv/Kconfig
Normal file
|
@ -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
|
|
@ -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.)
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
zephyr_include_directories(.)
|
||||
|
||||
zephyr_sources(fsl_clock.c)
|
20
soc/riscv32/openisa_rv32m1/CMakeLists.txt
Normal file
20
soc/riscv32/openisa_rv32m1/CMakeLists.txt
Normal file
|
@ -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
|
||||
)
|
29
soc/riscv32/openisa_rv32m1/Kconfig
Normal file
29
soc/riscv32/openisa_rv32m1/Kconfig
Normal file
|
@ -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
|
76
soc/riscv32/openisa_rv32m1/Kconfig.defconfig
Normal file
76
soc/riscv32/openisa_rv32m1/Kconfig.defconfig
Normal file
|
@ -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
|
21
soc/riscv32/openisa_rv32m1/Kconfig.soc
Normal file
21
soc/riscv32/openisa_rv32m1/Kconfig.soc
Normal file
|
@ -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.
|
203
soc/riscv32/openisa_rv32m1/linker.ld
Normal file
203
soc/riscv32/openisa_rv32m1/linker.ld
Normal file
|
@ -0,0 +1,203 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2014 Wind River Systems, Inc.
|
||||
* Copyright (c) 2016-2017 Jean-Paul Etienne <fractalclone@gmail.com>
|
||||
* 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 <autoconf.h>
|
||||
|
||||
#include <linker/sections.h>
|
||||
#include <linker/linker-defs.h>
|
||||
#include <linker/linker-tool.h>
|
||||
|
||||
/*
|
||||
* 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 <linker/rel-sections.ld>
|
||||
|
||||
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 <linker/common-rom.ld>
|
||||
|
||||
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 <linker/common-ram.ld>
|
||||
|
||||
__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 <custom-sections.ld>
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_GEN_ISR_TABLES
|
||||
/* Bogus section, post-processed during the build to initialize interrupts. */
|
||||
#include <linker/intlist.ld>
|
||||
#endif
|
||||
|
||||
#include <linker/debug-sections.ld>
|
||||
|
||||
/*
|
||||
* 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.*)
|
||||
}
|
||||
|
||||
}
|
147
soc/riscv32/openisa_rv32m1/soc.c
Normal file
147
soc/riscv32/openisa_rv32m1/soc.c
Normal file
|
@ -0,0 +1,147 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Foundries.io
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <kernel.h>
|
||||
|
||||
#include <device.h>
|
||||
#include <init.h>
|
||||
#include <fsl_clock.h>
|
||||
|
||||
#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);
|
28
soc/riscv32/openisa_rv32m1/soc.h
Normal file
28
soc/riscv32/openisa_rv32m1/soc.h
Normal file
|
@ -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_ */
|
52
soc/riscv32/openisa_rv32m1/soc_context.h
Normal file
52
soc/riscv32/openisa_rv32m1/soc_context.h
Normal file
|
@ -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 <offsets.h> 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_ */
|
95
soc/riscv32/openisa_rv32m1/soc_irq.S
Normal file
95
soc/riscv32/openisa_rv32m1/soc_irq.S
Normal file
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Foundries.io Ltd
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <offsets.h>
|
||||
#include <toolchain.h>
|
||||
|
||||
#include <soc.h>
|
||||
|
||||
/* 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 */
|
88
soc/riscv32/openisa_rv32m1/soc_ri5cy.h
Normal file
88
soc/riscv32/openisa_rv32m1/soc_ri5cy.h
Normal file
|
@ -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_ */
|
76
soc/riscv32/openisa_rv32m1/soc_zero_riscy.h
Normal file
76
soc/riscv32/openisa_rv32m1/soc_zero_riscy.h
Normal file
|
@ -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_ */
|
80
soc/riscv32/openisa_rv32m1/vector.S
Normal file
80
soc/riscv32/openisa_rv32m1/vector.S
Normal file
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Foundries.io Ltd
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <toolchain.h>
|
||||
|
||||
/* 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
|
63
soc/riscv32/openisa_rv32m1/wdog.S
Normal file
63
soc/riscv32/openisa_rv32m1/wdog.S
Normal file
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Foundries.io Ltd
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <linker/sections.h>
|
||||
#include <toolchain.h>
|
||||
#include <soc.h>
|
||||
|
||||
/* 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
|
Loading…
Add table
Add a link
Reference in a new issue