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:
Marti Bolivar 2018-11-25 02:40:57 -07:00 committed by Anas Nashif
commit 502d306630
24 changed files with 1213 additions and 1 deletions

View file

@ -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)

View file

@ -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

View 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;
}

View 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>;
};
};

View file

@ -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)

View file

@ -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"

View file

@ -0,0 +1,4 @@
add_subdirectory_ifdef(
CONFIG_VEGA_SDK_HAL
vega_sdk_riscv
)

View 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)

View 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

View file

@ -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.)

View file

@ -0,0 +1,3 @@
zephyr_include_directories(.)
zephyr_sources(fsl_clock.c)

View 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
)

View 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

View 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

View 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.

View 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.*)
}
}

View 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);

View 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_ */

View 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_ */

View 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 */

View 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_ */

View 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_ */

View 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

View 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