riscv32: rename to riscv

With the upcoming riscv64 support, it is best to use "riscv" as the
subdirectory name and common symbols as riscv32 and riscv64 support
code is almost identical. Then later decide whether 32-bit or 64-bit
compilation is wanted.

Redirects for the web documentation are also included.

Then zephyrbot complained about this:

"
New files added that are not covered in CODEOWNERS:

dts/riscv/microsemi-miv.dtsi
dts/riscv/riscv32-fe310.dtsi

Please add one or more entries in the CODEOWNERS file to cover
those files
"

So I assigned them to those who created them. Feel free to readjust
as necessary.

Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
This commit is contained in:
Nicolas Pitre 2019-07-17 13:17:05 -04:00 committed by Andrew Boie
commit 1f4b5ddd0f
159 changed files with 125 additions and 118 deletions

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 riscv 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/riscv.
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,186 @@
# 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"
# 32 from event unit + 32 * (1 + max enabled INTMUX channel)
config NUM_IRQS
int
default 288 if RV32M1_INTMUX_CHANNEL_7
default 256 if RV32M1_INTMUX_CHANNEL_6
default 224 if RV32M1_INTMUX_CHANNEL_5
default 192 if RV32M1_INTMUX_CHANNEL_4
default 160 if RV32M1_INTMUX_CHANNEL_3
default 128 if RV32M1_INTMUX_CHANNEL_2
default 96 if RV32M1_INTMUX_CHANNEL_1
default 64 if RV32M1_INTMUX_CHANNEL_0
default 32
config XIP
bool
default y
config RISCV_GENERIC_TOOLCHAIN
bool
default y if "$(ZEPHYR_TOOLCHAIN_VARIANT)" = "zephyr"
default n
config RISCV_SOC_CONTEXT_SAVE
bool
default y if SOC_OPENISA_RV32M1_RI5CY
config RISCV_SOC_OFFSETS
bool
default y
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
# The event unit looks for vector tables at the end of each core's
# flash space. These vector tables are not relocatable.
config RISCV_RV32M1_VECTOR_BASE_ADDR
hex
default 0x000FFF00 if SOC_OPENISA_RV32M1_RI5CY
default 0x0103FF00 if SOC_OPENISA_RV32M1_ZERO_RISCY
config RISCV_RV32M1_VECTOR_SIZE
hex
default 0x100
config SYS_CLOCK_HW_CYCLES_PER_SEC
int
default 8000000
if MULTI_LEVEL_INTERRUPTS
config MAX_IRQ_PER_AGGREGATOR
int
default 32
config 2ND_LEVEL_INTERRUPTS
default y
config 2ND_LVL_ISR_TBL_OFFSET
int
default 32
config NUM_2ND_LEVEL_AGGREGATORS
int
default 8 if RV32M1_INTMUX_CHANNEL_7
default 7 if RV32M1_INTMUX_CHANNEL_6
default 6 if RV32M1_INTMUX_CHANNEL_5
default 5 if RV32M1_INTMUX_CHANNEL_4
default 4 if RV32M1_INTMUX_CHANNEL_3
default 3 if RV32M1_INTMUX_CHANNEL_2
default 2 if RV32M1_INTMUX_CHANNEL_1
default 1 # just channel 0
config 2ND_LVL_INTR_00_OFFSET
int
default 24
config 2ND_LVL_INTR_01_OFFSET
int
default 25
config 2ND_LVL_INTR_02_OFFSET
int
default 26
config 2ND_LVL_INTR_03_OFFSET
int
default 27
config 2ND_LVL_INTR_04_OFFSET
int
default 28
config 2ND_LVL_INTR_05_OFFSET
int
default 29
config 2ND_LVL_INTR_06_OFFSET
int
default 30
config 2ND_LVL_INTR_07_OFFSET
int
default 31
config RV32M1_INTMUX
default y
config RV32M1_INTMUX_CHANNEL_0
default y
config RV32M1_INTMUX_CHANNEL_1
default y
config RV32M1_INTMUX_CHANNEL_2
default y
config RV32M1_INTMUX_CHANNEL_3
default y
config RV32M1_INTMUX_CHANNEL_4
default y
config RV32M1_INTMUX_CHANNEL_5
default y
config RV32M1_INTMUX_CHANNEL_6
default y
config RV32M1_INTMUX_CHANNEL_7
default y
endif # MULTI_LEVEL_INTERRUPTS
config PINMUX_RV32M1
default y
if GPIO
config GPIO_RV32M1
default y
endif # GPIO
if SERIAL
config UART_RV32M1_LPUART
def_bool y
endif # SERIAL
if I2C
config I2C_RV32M1_LPI2C
def_bool y
endif # I2C
if FLASH
config SOC_FLASH_RV32M1
default y
config FLASH_BASE_ADDRESS
default $(dt_hex_val,DT_FLASH_BASE_ADDRESS)
endif # FLASH
endif # SOC_OPENISA_RV32M1_RISCV32

View file

@ -0,0 +1,22 @@
# 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 RISCV
# The following select is due to limitations in the linker script.
# (We can't make it a 'depends on' without causing a dependency loop).
select XIP
select HAS_RV32M1_LPUART
select HAS_RV32M1_LPI2C
select ATOMIC_OPERATIONS_C
select VEGA_SDK_HAL
select RISCV_SOC_INTERRUPT_INIT
select CLOCK_CONTROL
select HAS_RV32M1_FTFX
select HAS_FLASH_LOAD_OFFSET
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,17 @@
/*
* Copyright (c) 2019 NXP
*
* SPDX-License-Identifier: Apache-2.0
*/
/* SoC level DTS fixup file */
#if defined(CONFIG_SOC_OPENISA_RV32M1_RISCV32)
#define DT_FLASH_DEV_BASE_ADDRESS DT_OPENISA_RV32M1_FTFE_40023000_BASE_ADDRESS
#define DT_FLASH_DEV_NAME DT_OPENISA_RV32M1_FTFE_40023000_LABEL
#define DT_START_UP_ENTRY_OFFSET 0x80
#endif /* CONFIG_SOC_OPENISA_RV32M1_RISCV32 */
/* End of SoC Level DTS fixup file */

View file

@ -0,0 +1,282 @@
/*
* 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/riscv/common/linker.ld
* - include/arch/riscv/pulpino/linker.ld
*
* SPDX-License-Identifier: Apache-2.0
*/
#define _LINKER
#define _ASMLANGUAGE
#include <generated_dts_board.h>
#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 VECTOR_SIZE CONFIG_RISCV_RV32M1_VECTOR_SIZE
#ifdef CONFIG_USE_CODE_PARTITION
#ifdef CONFIG_BOOTLOADER_MCUBOOT
#define ROM_BASE (DT_CODE_PARTITION_OFFSET)
#define ROM_SIZE (DT_CODE_PARTITION_SIZE)
#define VECTOR_BASE (ROM_BASE + CONFIG_TEXT_SECTION_OFFSET)
#else
#define ROM_BASE DT_CODE_PARTITION_OFFSET
#define ROM_SIZE (DT_CODE_PARTITION_SIZE - VECTOR_SIZE)
#define VECTOR_BASE (ROM_BASE + ROM_SIZE)
#endif
#else
#define ROM_BASE DT_FLASH_BASE_ADDRESS
#define ROM_SIZE (KB(DT_FLASH_SIZE) - VECTOR_SIZE)
#define VECTOR_BASE (ROM_BASE + ROM_SIZE)
#endif
#define RAM_BASE DT_SRAM_BASE_ADDRESS
#define RAM_SIZE KB(DT_SRAM_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.)
*/
#ifndef CONFIG_BOOTLOADER_MCUBOOT
VECTORS (rx) : ORIGIN = VECTOR_BASE, LENGTH = VECTOR_SIZE
#endif
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.
*/
#ifdef CONFIG_BOOTLOADER_MCUBOOT
/*
* For CONFIG_BOOTLOADER_MCUBOOT, the vector table is located at the
* end of the image header of the MCUboot. After the tagert image is
* boot, the register Machine Trap-Vector Base Address (MTVEC) is
* set with the value of _vector_start in the reset handler.
*/
_vector_start = .;
KEEP(*(.vectors.*))
_vector_end = .;
. = ALIGN(4);
#endif
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);
*(.srodata)
*(".srodata.*")
*(.rodata)
*(.rodata.*)
*(.gnu.linkonce.r.*)
/* Located in generated directory. This file is populated by the
* zephyr_linker_sources() Cmake function.
*/
#include <snippets-rodata.ld>
} GROUP_LINK_IN(ROMABLE_REGION)
_image_rodata_end = .;
_image_rom_end = .;
#ifndef CONFIG_BOOTLOADER_MCUBOOT
/* The vector table goes into core-dependent flash locations. */
SECTION_PROLOGUE(vectors,,)
{
_vector_start = .;
KEEP(*(.vectors.*))
} GROUP_LINK_IN(VECTORS)
_vector_end = .;
#endif
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.*)
/* Located in generated directory. This file is populated by the
* zephyr_linker_sources() Cmake function.
*/
#include <snippets-rwdata.ld>
} 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.*)
/* Located in generated directory. This file is populated by the
* zephyr_linker_sources() Cmake function.
*/
#include <snippets-noinit.ld>
} GROUP_LINK_IN(RAMABLE_REGION)
/* Located in generated directory. This file is populated by the
* zephyr_linker_sources() Cmake function.
*/
#include <snippets-ram-sections.ld>
_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
/* Located in generated directory. This file is populated by the
* zephyr_linker_sources() Cmake function.
*/
#include <snippets-sections.ld>
#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>
SECTION_PROLOGUE(.riscv.attributes, 0,)
{
KEEP(*(.riscv.attributes))
KEEP(*(.gnu.attributes))
}
/*
* 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,222 @@
/*
* Copyright (c) 2018 Foundries.io
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <kernel.h>
#include <device.h>
#include <init.h>
#include <fsl_clock.h>
#include <sys/util.h>
#if defined(CONFIG_MULTI_LEVEL_INTERRUPTS)
#include <errno.h>
#include <irq_nextlevel.h>
#endif
#define LOG_LEVEL CONFIG_SOC_LOG_LEVEL
#include <logging/log.h>
LOG_MODULE_REGISTER(soc);
#define SCG_LPFLL_DISABLE 0U
static struct device *dev_intmux;
/*
* 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 sys_arch_reboot(int type)
{
ARG_UNUSED(type);
EVENT_UNIT->SLPCTRL |= EVENT_SLPCTRL_SYSRSTREQST_MASK;
}
void z_arch_irq_enable(unsigned int irq)
{
if (IS_ENABLED(CONFIG_MULTI_LEVEL_INTERRUPTS)) {
unsigned int level = rv32m1_irq_level(irq);
if (level == 1U) {
EVENT_UNIT->INTPTEN |= BIT(rv32m1_level1_irq(irq));
/* Ensures write has finished: */
(void)(EVENT_UNIT->INTPTEN);
} else {
irq_enable_next_level(dev_intmux, irq);
}
} else {
EVENT_UNIT->INTPTEN |= BIT(rv32m1_level1_irq(irq));
(void)(EVENT_UNIT->INTPTEN);
}
}
void z_arch_irq_disable(unsigned int irq)
{
if (IS_ENABLED(CONFIG_MULTI_LEVEL_INTERRUPTS)) {
unsigned int level = rv32m1_irq_level(irq);
if (level == 1U) {
EVENT_UNIT->INTPTEN &= ~BIT(rv32m1_level1_irq(irq));
/* Ensures write has finished: */
(void)(EVENT_UNIT->INTPTEN);
} else {
irq_disable_next_level(dev_intmux, irq);
}
} else {
EVENT_UNIT->INTPTEN &= ~BIT(rv32m1_level1_irq(irq));
(void)(EVENT_UNIT->INTPTEN);
}
}
int z_arch_irq_is_enabled(unsigned int irq)
{
if (IS_ENABLED(CONFIG_MULTI_LEVEL_INTERRUPTS)) {
unsigned int level = rv32m1_irq_level(irq);
if (level == 1U) {
return (EVENT_UNIT->INTPTEN &
BIT(rv32m1_level1_irq(irq))) != 0;
} else {
u32_t channel, line, ier;
/*
* Here we break the abstraction and look
* directly at the INTMUX registers. We can't
* use the irq_nextlevel.h API, as that only
* tells us whether some IRQ at the next level
* is enabled or not.
*/
channel = rv32m1_intmux_channel(irq);
line = rv32m1_intmux_line(irq);
ier = INTMUX->CHANNEL[channel].CHn_IER_31_0 & BIT(line);
return ier != 0U;
}
} else {
return (EVENT_UNIT->INTPTEN & BIT(rv32m1_level1_irq(irq))) != 0;
}
}
/*
* SoC-level interrupt initialization. Clear any pending interrupts or
* events, and find the INTMUX device if necessary.
*
* This gets called as almost the first thing z_cstart() does, so it
* will happen before any calls to the _arch_irq_xxx() routines above.
*/
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. */
if (IS_ENABLED(CONFIG_MULTI_LEVEL_INTERRUPTS)) {
dev_intmux = device_get_binding(DT_OPENISA_RV32M1_INTMUX_INTMUX_LABEL);
__ASSERT(dev_intmux, "no INTMUX device found");
}
}
/**
* @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,111 @@
/*
* 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"
#include <zephyr/types.h>
/*
* Helpers related to interrupt handling. This SoC has two levels of
* interrupts.
*
* Level 1 interrupts go straight to the SoC. Level 2 interrupts must
* go through one of the 8 channels in the the INTMUX
* peripheral. There are 32 level 1 interrupts, including 8 INTMUX
* interrupts. Each INTMUX interrupt can mux at most
* CONFIG_MAX_IRQ_PER_AGGREGATOR (which happens to be 32) interrupts
* to its level 1 interrupt.
*
* See gen_isr_tables.py for details on the Zephyr multi-level IRQ
* number encoding, which determines how these helpers work.
*/
/**
* @brief Get an IRQ's level
* @param irq The IRQ number in the Zephyr irq.h numbering system
* @return IRQ level, either 1 or 2
*/
static inline unsigned int rv32m1_irq_level(unsigned int irq)
{
return ((irq >> 8) & 0xff) == 0U ? 1 : 2;
}
/**
* @brief Level 1 interrupt line associated with an IRQ
*
* Results are undefined if rv32m1_irq_level(irq) is not 1.
*
* @param The IRQ number in the Zephyr <irq.h> numbering system
* @return Level 1 (i.e. event unit) IRQ number associated with irq
*/
static inline u32_t rv32m1_level1_irq(unsigned int irq)
{
/*
* There's no need to do any math; the precondition is that
* it's a level 1 IRQ.
*/
return irq;
}
/**
* @brief INTMUX channel (i.e. level 2 aggregator number) for an IRQ
*
* Results are undefined if rv32m1_irq_level(irq) is not 2.
*
* @param irq The IRQ number whose INTMUX channel / level 2 aggregator
* to get, in the Zephyr <irq.h> numbering system
* @return INTMUX channel number associated with the IRQ
*/
static inline u32_t rv32m1_intmux_channel(unsigned int irq)
{
/*
* Here we make use of these facts:
*
* - the INTMUX output IRQ numbers are arranged consecutively
* by channel in the event unit IRQ numbering assignment,
* starting from channel 0.
*
* - CONFIG_2ND_LVL_INTR_00_OFFSET is defined to
* be the offset of the first level 2 aggregator in the parent
* interrupt controller's IRQ numbers, i.e. channel 0's
* IRQ number in the event unit.
*/
return (irq & 0xff) - CONFIG_2ND_LVL_INTR_00_OFFSET;
}
/**
* @brief INTMUX interrupt ID number for an IRQ
*
* Results are undefined if rv32m1_irq_level(irq) is not 2.
*
* @param The IRQ number whose INTMUX interrupt ID to get, in the Zephyr
* <irq.h> numbering system
* @return The INTMUX interrupt ID, in the inclusive range 0 to 31
*/
static inline u32_t rv32m1_intmux_line(unsigned int irq)
{
return ((irq >> 8) & 0xff) - 1;
}
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 KB(DT_SRAM_SIZE)
#define RISCV_RAM_BASE DT_SRAM_BASE_ADDRESS
#endif /* SOC_RISCV32_OPENISA_RV32M1_SOC_H_ */

View file

@ -0,0 +1,36 @@
/*
* 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
#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, __EVENT_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,42 @@
/*
* Copyright (c) 2018 Foundries.io Ltd
*
* SPDX-License-Identifier: Apache-2.0
*/
/*
* Extra definitions required for CONFIG_RISCV_SOC_OFFSETS.
*/
#ifndef SOC_RISCV32_OPENISA_RV32M1_SOC_OFFSETS_H_
#define SOC_RISCV32_OPENISA_RV32M1_SOC_OFFSETS_H_
#ifdef CONFIG_SOC_OPENISA_RV32M1_RI5CY
/*
* Ensure offset macros are available in <offsets.h>.
*
* 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(__EVENT_INTPTPENDCLEAR, \
(uint32_t)&EVENT0->INTPTPENDCLEAR)
#endif /* CONFIG_SOC_OPENISA_RV32M1_RI5CY */
#ifdef CONFIG_SOC_OPENISA_RV32M1_ZERO_RISCY
#define GEN_SOC_OFFSET_SYMS() \
GEN_ABSOLUTE_SYM(__EVENT_INTPTPENDCLEAR, \
(uint32_t)&EVENT1->INTPTPENDCLEAR)
#endif /* CONFIG_SOC_OPENISA_RV32M1_ZERO_RISCY */
#endif /* SOC_RISCV32_OPENISA_RV32M1_SOC_OFFSETS_H_ */

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