diff --git a/CODEOWNERS b/CODEOWNERS index 7986045e8b..7c9c75952d 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -44,7 +44,7 @@ /cpu/cortexm_common/ @haukepetersen @thomaseichinger @DipSwitch /cpu/efm32/ @basilfx /cpu/esp*/ @gschorcht -/cpu/fe310/ @aabadie @kaspar030 +/cpu/fe310/ @aabadie @kaspar030 @bergzand /cpu/kinetis/ @fjmolinas /cpu/lpc2387/ @benpicco @maribu /cpu/mips*/ @kaspar030 @francois-berder diff --git a/cpu/fe310/Kconfig b/cpu/fe310/Kconfig index 1335636419..bdadfff1b5 100644 --- a/cpu/fe310/Kconfig +++ b/cpu/fe310/Kconfig @@ -21,6 +21,7 @@ config CPU_FAM_FE310 select HAS_PERIPH_CPUID select HAS_PERIPH_GPIO select HAS_PERIPH_GPIO_IRQ + select HAS_PERIPH_PLIC select HAS_PERIPH_PM select HAS_PERIPH_WDT select HAS_CPP diff --git a/cpu/fe310/Makefile.dep b/cpu/fe310/Makefile.dep index 9d1c9bdb2a..ff4abe1366 100644 --- a/cpu/fe310/Makefile.dep +++ b/cpu/fe310/Makefile.dep @@ -10,6 +10,8 @@ USEMODULE += sifive_drivers_fe310 USEMODULE += periph USEMODULE += periph_pm +FEATURES_REQUIRED += periph_plic + ifneq (,$(filter periph_rtc,$(USEMODULE))) FEATURES_REQUIRED += periph_rtt endif diff --git a/cpu/fe310/Makefile.features b/cpu/fe310/Makefile.features index 14b6ff70a2..9f46d6ce83 100644 --- a/cpu/fe310/Makefile.features +++ b/cpu/fe310/Makefile.features @@ -4,6 +4,7 @@ FEATURES_PROVIDED += cpp FEATURES_PROVIDED += libstdcpp FEATURES_PROVIDED += periph_cpuid FEATURES_PROVIDED += periph_gpio periph_gpio_irq +FEATURES_PROVIDED += periph_plic FEATURES_PROVIDED += periph_pm FEATURES_PROVIDED += periph_wdt FEATURES_PROVIDED += ssp diff --git a/cpu/fe310/include/cpu.h b/cpu/fe310/include/cpu.h index bd29923796..0959b7b926 100644 --- a/cpu/fe310/include/cpu.h +++ b/cpu/fe310/include/cpu.h @@ -56,16 +56,6 @@ uint32_t cpu_freq(void); */ void irq_init(void); -/** - * @brief External ISR callback - */ -typedef void (*external_isr_ptr_t)(int intNum); - -/** - * @brief Set External ISR callback - */ -void set_external_isr_cb(int intNum, external_isr_ptr_t cbFunc); - /** * @brief Print the last instruction's address * diff --git a/cpu/fe310/include/plic.h b/cpu/fe310/include/plic.h new file mode 100644 index 0000000000..4e49176603 --- /dev/null +++ b/cpu/fe310/include/plic.h @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2020 Koen Zandberg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup cpu_fe310 + * @{ + * + * @file + * @brief Platform-Level interrupt controller driver + * + * @author Koen Zandberg + * @} + */ + +#ifndef PLIC_H +#define PLIC_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief PLIC callback declaration + * + * @param irq Interrupt number + */ +typedef void (*plic_isr_cb_t)(int irq); + +/** + * @brief Initialize the Platform-level interrupt controller + */ +void plic_init(void); + +/** + * @brief Disable an interrupt on the PLIC + * + * @param irq Interrupt number + */ +void plic_disable_interrupt(unsigned irq); + +/** + * @brief Enable an interrupt on the PLIC + * + * @param irq Interrupt number + */ +void plic_enable_interrupt(unsigned irq); + +/** + * @brief Set an interrupt priority + * + * @param irq Interrupt number + * @param priority Priority + */ +void plic_set_priority(unsigned irq, unsigned priority); + +/** + * @brief Set the interrupt callback + * + * @param irq Interrupt number + * @param cb Callback to call on interrupt + */ +void plic_set_isr_cb(unsigned irq, plic_isr_cb_t cb); + +/** + * @brief External ISR callback + */ + +/** + * @brief Interrupt handler for the PLIC + * + * Must be called from the trap handler when an interrupt from the PLIC is + * pending + */ +void plic_isr_handler(void); + +#ifdef __cplusplus +} +#endif + +#endif /* PLIC_H */ +/** @} */ diff --git a/cpu/fe310/include/vendor/plic.h b/cpu/fe310/include/vendor/plic.h index f59faa47af..250dc496d2 100644 --- a/cpu/fe310/include/vendor/plic.h +++ b/cpu/fe310/include/vendor/plic.h @@ -1,7 +1,7 @@ // See LICENSE for license details. -#ifndef PLIC_H -#define PLIC_H +#ifndef VENDOR_PLIC_H +#define VENDOR_PLIC_H // 32 bits per source @@ -27,4 +27,4 @@ #define PLIC_MAX_TARGET 15871 #define PLIC_TARGET_MASK 0x3FFF -#endif /* PLIC_H */ +#endif /* VENDOR_PLIC_H */ diff --git a/cpu/fe310/irq_arch.c b/cpu/fe310/irq_arch.c index 53931a5eb3..85bbbd0b18 100644 --- a/cpu/fe310/irq_arch.c +++ b/cpu/fe310/irq_arch.c @@ -28,6 +28,7 @@ #include "irq_arch.h" #include "panic.h" #include "sched.h" +#include "plic.h" #include "vendor/encoding.h" #include "vendor/platform.h" @@ -38,9 +39,6 @@ volatile int fe310_in_isr = 0; -/* PLIC external ISR function list */ -static external_isr_ptr_t _ext_isrs[PLIC_NUM_INTERRUPTS]; - /** * @brief ISR trap vector */ @@ -60,7 +58,9 @@ void irq_init(void) write_csr(mie, 0); /* Initial PLIC external interrupt controller */ - PLIC_init(PLIC_CTRL_ADDR, PLIC_NUM_INTERRUPTS, PLIC_NUM_PRIORITIES); + if (IS_ACTIVE(MODULE_PERIPH_PLIC)) { + plic_init(); + } /* Enable SW and external interrupts */ set_csr(mie, MIP_MSIP); @@ -70,30 +70,6 @@ void irq_init(void) set_csr(mstatus, MSTATUS_DEFAULT); } -/** - * @brief Set External ISR callback - */ -void set_external_isr_cb(int intNum, external_isr_ptr_t cbFunc) -{ - assert((intNum > 0) && (intNum < PLIC_NUM_INTERRUPTS)); - - _ext_isrs[intNum] = cbFunc; -} - -/** - * @brief External interrupt handler - */ -void external_isr(void) -{ - uint32_t intNum = (uint32_t)PLIC_claim_interrupt(); - - if ((intNum > 0) && (intNum < PLIC_NUM_INTERRUPTS) && (_ext_isrs[intNum] != NULL)) { - _ext_isrs[intNum](intNum); - } - - PLIC_complete_interrupt(intNum); -} - /** * @brief Global trap and interrupt handler */ @@ -121,7 +97,9 @@ void handle_trap(uint32_t mcause) #endif case IRQ_M_EXT: /* Handle external interrupt */ - external_isr(); + if (IS_ACTIVE(MODULE_PERIPH_PLIC)) { + plic_isr_handler(); + } break; default: diff --git a/cpu/fe310/periph/gpio.c b/cpu/fe310/periph/gpio.c index 6c7819871a..988be19337 100644 --- a/cpu/fe310/periph/gpio.c +++ b/cpu/fe310/periph/gpio.c @@ -25,6 +25,7 @@ #include "periph_cpu.h" #include "periph_conf.h" #include "periph/gpio.h" +#include "plic.h" #include "vendor/encoding.h" #include "vendor/platform.h" #include "vendor/plic_driver.h" @@ -159,9 +160,9 @@ int gpio_init_int(gpio_t pin, gpio_mode_t mode, gpio_flank_t flank, clear_csr(mie, MIP_MEIP); /* Configure GPIO ISR with PLIC */ - set_external_isr_cb(INT_GPIO_BASE + pin, gpio_isr); - PLIC_enable_interrupt(INT_GPIO_BASE + pin); - PLIC_set_priority(INT_GPIO_BASE + pin, GPIO_INTR_PRIORITY); + plic_set_isr_cb(INT_GPIO_BASE + pin, gpio_isr); + plic_enable_interrupt(INT_GPIO_BASE + pin); + plic_set_priority(INT_GPIO_BASE + pin, GPIO_INTR_PRIORITY); /* Configure the active flank(s) */ gpio_irq_enable(pin); diff --git a/cpu/fe310/periph/plic.c b/cpu/fe310/periph/plic.c new file mode 100644 index 0000000000..a0c94e5344 --- /dev/null +++ b/cpu/fe310/periph/plic.c @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2020 Koen Zandberg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup cpu_fe310 + * @{ + * + * @file + * @brief Platform-Level interrupt controller driver + * + * @author Koen Zandberg + * @} + */ + +#include "vendor/encoding.h" +#include "vendor/platform.h" +#include "cpu.h" +#include "plic.h" + +/* PLIC external ISR function list */ +static plic_isr_cb_t _ext_isrs[PLIC_NUM_INTERRUPTS]; + +static inline volatile uint32_t *_get_claim_complete_addr(void) +{ + uint32_t hart_id = read_csr(mhartid); + + /* Construct the claim address */ + return &PLIC_REG(PLIC_CLAIM_OFFSET + + (hart_id << PLIC_CLAIM_SHIFT_PER_TARGET)); +} + +static inline volatile uint32_t *_get_threshold_addr(void) +{ + uint32_t hart_id = read_csr(mhartid); + + /* Construct the claim address */ + return &PLIC_REG(PLIC_THRESHOLD_OFFSET + + (hart_id << PLIC_THRESHOLD_SHIFT_PER_TARGET)); +} + +static inline volatile uint32_t *_get_irq_reg(unsigned irq) +{ + uint32_t hart_id = read_csr(mhartid); + + return &PLIC_REG(PLIC_ENABLE_OFFSET + + (hart_id << PLIC_ENABLE_SHIFT_PER_TARGET)) + + (irq >> 5); /* Intentionally outside the PLIC_REG macro */ +} + +void plic_enable_interrupt(unsigned irq) +{ + volatile uint32_t *irq_reg = _get_irq_reg(irq); + + __atomic_fetch_or(irq_reg, 1 << (irq & 0x1f), __ATOMIC_RELAXED); +} + +void plic_disable_interrupt(unsigned irq) +{ + volatile uint32_t *irq_reg = _get_irq_reg(irq); + + __atomic_fetch_and(irq_reg, ~(1 << (irq & 0x1f)), __ATOMIC_RELAXED); +} + +void plic_set_threshold(unsigned threshold) +{ + volatile uint32_t *plic_threshold = _get_threshold_addr(); + + *plic_threshold = threshold; + +} + +void plic_set_priority(unsigned irq, unsigned priority) +{ + assert(irq <= PLIC_NUM_INTERRUPTS); + assert(irq != 0); + *(&PLIC_REG(PLIC_PRIORITY_OFFSET) + irq) = priority; +} + +static void plic_complete_interrupt(unsigned irq) +{ + volatile uint32_t *complete_addr = _get_claim_complete_addr(); + + *complete_addr = irq; +} + +static unsigned plic_claim_interrupt(void) +{ + return *_get_claim_complete_addr(); +} + +void plic_set_isr_cb(unsigned irq, plic_isr_cb_t cb) +{ + assert(irq <= PLIC_NUM_INTERRUPTS); + assert(irq != 0); + _ext_isrs[irq] = cb; +} + +void plic_init(void) +{ + for (unsigned i = 1; i <= PLIC_NUM_INTERRUPTS; i++) { + plic_disable_interrupt(i); + plic_set_priority(i, 0); + } + + plic_set_threshold(0); +} + +void plic_isr_handler(void) +{ + unsigned irq = plic_claim_interrupt(); + + /* Don't check here, just crash hard if no handler is available */ + _ext_isrs[irq](irq); + + plic_complete_interrupt(irq); +} diff --git a/cpu/fe310/periph/rtt.c b/cpu/fe310/periph/rtt.c index 9c8d68d966..e758d3aba5 100644 --- a/cpu/fe310/periph/rtt.c +++ b/cpu/fe310/periph/rtt.c @@ -29,6 +29,7 @@ #include "periph_cpu.h" #include "periph_conf.h" #include "periph/rtt.h" +#include "plic.h" #include "vendor/encoding.h" #include "vendor/platform.h" #include "vendor/plic_driver.h" @@ -76,9 +77,9 @@ void rtt_init(void) clear_csr(mie, MIP_MEIP); /* Configure RTC ISR with PLIC */ - set_external_isr_cb(INT_RTCCMP, rtt_isr); - PLIC_enable_interrupt(INT_RTCCMP); - PLIC_set_priority(INT_RTCCMP, RTT_INTR_PRIORITY); + plic_set_isr_cb(INT_RTCCMP, rtt_isr); + plic_enable_interrupt(INT_RTCCMP); + plic_set_priority(INT_RTCCMP, RTT_INTR_PRIORITY); /* Configure RTC scaler, etc... */ AON_REG(AON_RTCCFG) = RTT_SCALE; diff --git a/cpu/fe310/periph/uart.c b/cpu/fe310/periph/uart.c index 7cc2581d74..8f5567370d 100644 --- a/cpu/fe310/periph/uart.c +++ b/cpu/fe310/periph/uart.c @@ -25,6 +25,7 @@ #include "irq.h" #include "cpu.h" #include "periph/uart.h" +#include "plic.h" #include "vendor/encoding.h" #include "vendor/platform.h" #include "vendor/plic_driver.h" @@ -111,9 +112,9 @@ int uart_init(uart_t dev, uint32_t baudrate, uart_rx_cb_t rx_cb, void *arg) clear_csr(mie, MIP_MEIP); /* Configure UART ISR with PLIC */ - set_external_isr_cb(uart_config[dev].isr_num, uart_isr); - PLIC_enable_interrupt(uart_config[dev].isr_num); - PLIC_set_priority(uart_config[dev].isr_num, UART_ISR_PRIO); + plic_set_isr_cb(uart_config[dev].isr_num, uart_isr); + plic_enable_interrupt(uart_config[dev].isr_num); + plic_set_priority(uart_config[dev].isr_num, UART_ISR_PRIO); /* avoid trap by emptying RX FIFO */ _drain(dev); diff --git a/cpu/fe310/vendor/plic_driver.c b/cpu/fe310/vendor/plic_driver.c deleted file mode 100644 index 3009f0623e..0000000000 --- a/cpu/fe310/vendor/plic_driver.c +++ /dev/null @@ -1,153 +0,0 @@ -// See LICENSE for license details. - -#include -#include - -#include "vendor/encoding.h" -#include "vendor/platform.h" -#include "vendor/plic_driver.h" - - -typedef struct __plic_instance_t -{ - uintptr_t base_addr; - uint32_t num_sources; - uint32_t num_priorities; - -} plic_instance_t; - - -// PLIC instance -static plic_instance_t _plic; - - - -// Note that there are no assertions or bounds checking on these -// parameter values. - -void volatile_memzero(uint8_t * base, unsigned int size) -{ - volatile uint8_t * ptr; - for (ptr = base; ptr < (base + size); ptr++){ - *ptr = 0; - } -} - -void PLIC_init ( - uintptr_t base_addr, - uint32_t num_sources, - uint32_t num_priorities - ) -{ - plic_instance_t* this_plic = &_plic; - - this_plic->base_addr = base_addr; - this_plic->num_sources = num_sources; - this_plic->num_priorities = num_priorities; - - // Disable all interrupts (don't assume that these registers are reset). - unsigned long hart_id = read_csr(mhartid); - volatile_memzero((uint8_t*) (this_plic->base_addr + - PLIC_ENABLE_OFFSET + - (hart_id << PLIC_ENABLE_SHIFT_PER_TARGET)), - (num_sources + 8) / 8); - - // Set all priorities to 0 (equal priority -- don't assume that these are reset). - volatile_memzero ((uint8_t *)(this_plic->base_addr + - PLIC_PRIORITY_OFFSET), - (num_sources + 1) << PLIC_PRIORITY_SHIFT_PER_SOURCE); - - // Set the threshold to 0. - volatile plic_threshold* threshold = (plic_threshold*) - (this_plic->base_addr + - PLIC_THRESHOLD_OFFSET + - (hart_id << PLIC_THRESHOLD_SHIFT_PER_TARGET)); - - *threshold = 0; - -} - -void PLIC_set_threshold (plic_threshold threshold) -{ - plic_instance_t* this_plic = &_plic; - - unsigned long hart_id = read_csr(mhartid); - volatile plic_threshold* threshold_ptr = (plic_threshold*) (this_plic->base_addr + - PLIC_THRESHOLD_OFFSET + - (hart_id << PLIC_THRESHOLD_SHIFT_PER_TARGET)); - - *threshold_ptr = threshold; - -} - - -void PLIC_enable_interrupt (plic_source source) -{ - plic_instance_t* this_plic = &_plic; - - unsigned long hart_id = read_csr(mhartid); - volatile uint8_t * current_ptr = (volatile uint8_t *)(this_plic->base_addr + - PLIC_ENABLE_OFFSET + - (hart_id << PLIC_ENABLE_SHIFT_PER_TARGET) + - (source >> 3)); - uint8_t current = *current_ptr; - current = current | ( 1 << (source & 0x7)); - *current_ptr = current; - -} - -void PLIC_disable_interrupt (plic_source source) -{ - plic_instance_t* this_plic = &_plic; - - unsigned long hart_id = read_csr(mhartid); - volatile uint8_t * current_ptr = (volatile uint8_t *) (this_plic->base_addr + - PLIC_ENABLE_OFFSET + - (hart_id << PLIC_ENABLE_SHIFT_PER_TARGET) + - (source >> 3)); - uint8_t current = *current_ptr; - current = current & ~(( 1 << (source & 0x7))); - *current_ptr = current; - -} - -void PLIC_set_priority (plic_source source, plic_priority priority) -{ - plic_instance_t* this_plic = &_plic; - - if (this_plic->num_priorities > 0) { - volatile plic_priority * priority_ptr = (volatile plic_priority *) - (this_plic->base_addr + - PLIC_PRIORITY_OFFSET + - (source << PLIC_PRIORITY_SHIFT_PER_SOURCE)); - *priority_ptr = priority; - } -} - -plic_source PLIC_claim_interrupt(void) -{ - plic_instance_t* this_plic = &_plic; - - unsigned long hart_id = read_csr(mhartid); - - volatile plic_source * claim_addr = (volatile plic_source * ) - (this_plic->base_addr + - PLIC_CLAIM_OFFSET + - (hart_id << PLIC_CLAIM_SHIFT_PER_TARGET)); - - return *claim_addr; - -} - -void PLIC_complete_interrupt(plic_source source) -{ - plic_instance_t* this_plic = &_plic; - - unsigned long hart_id = read_csr(mhartid); - volatile plic_source * claim_addr = (volatile plic_source *) (this_plic->base_addr + - PLIC_CLAIM_OFFSET + - (hart_id << PLIC_CLAIM_SHIFT_PER_TARGET)); - *claim_addr = source; - -} - diff --git a/kconfigs/Kconfig.features b/kconfigs/Kconfig.features index c621830b66..caba82a5ca 100644 --- a/kconfigs/Kconfig.features +++ b/kconfigs/Kconfig.features @@ -180,6 +180,11 @@ config HAS_PERIPH_MCG help Indicates that an MCG peripheral is present. +config HAS_PERIPH_PLIC + bool + help + Indicates that a RISC-V Platform-local Interrupt Controller (PLIC) peripheral is present. + config HAS_PERIPH_PM bool help