mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
cpu/riscv_common: Add CLIC peripheral driver
The CLIC is a next generation interrupt controller for the RISC-V architecture. Co-authored-by:
This commit is contained in:
parent
9239c2fe14
commit
48aa533639
97
cpu/riscv_common/include/clic.h
Normal file
97
cpu/riscv_common/include/clic.h
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 Koen Zandberg <koen@bergzand.net>
|
||||||
|
*
|
||||||
|
* 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_riscv_common
|
||||||
|
* @{
|
||||||
|
*
|
||||||
|
* @file
|
||||||
|
* @brief RISCV CLIC interrupt controller definitions
|
||||||
|
*
|
||||||
|
* RISCV implementations using this peripheral must define the `CLIC_BASE_ADDR`,
|
||||||
|
* in order to use the PLIC as interrupt controller. Also required is
|
||||||
|
* CLIC_NUM_INTERRUPTS.
|
||||||
|
*
|
||||||
|
* @author Koen Zandberg <koen@bergzand.net>
|
||||||
|
*/
|
||||||
|
#ifndef CLIC_H
|
||||||
|
#define CLIC_H
|
||||||
|
|
||||||
|
#include "cpu_conf.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief CLIC callback declaration
|
||||||
|
*
|
||||||
|
* @param irq Interrupt number
|
||||||
|
*/
|
||||||
|
typedef void (*clic_isr_cb_t)(unsigned irq);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief RISC-V CLIC per interrupt configuration registers
|
||||||
|
*/
|
||||||
|
typedef struct __attribute((packed)) {
|
||||||
|
volatile uint8_t ip; /**< Interrupt pending */
|
||||||
|
volatile uint8_t ie; /**< Interrupt enable */
|
||||||
|
volatile uint8_t attr; /**< Interrupt attributes */
|
||||||
|
volatile uint8_t ctl; /**< Interrupt control */
|
||||||
|
} clic_clicint_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize the CLIC interrupt controller
|
||||||
|
*/
|
||||||
|
void clic_init(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enable a single interrupt
|
||||||
|
*
|
||||||
|
* @param irq Interrupt number to enable
|
||||||
|
* @param priority Priority level to configure
|
||||||
|
*/
|
||||||
|
void clic_enable_interrupt(unsigned irq, unsigned priority);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Disable a single interrupt
|
||||||
|
*
|
||||||
|
* @param irq Interrupt number to disable
|
||||||
|
*/
|
||||||
|
void clic_disable_interrupt(unsigned irq);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the priority of an interrupt
|
||||||
|
*
|
||||||
|
* @param irq Interrupt number to configure
|
||||||
|
* @param priority Priority level to configure
|
||||||
|
*/
|
||||||
|
void clic_set_priority(unsigned irq, unsigned priority);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the handler for an interrupt
|
||||||
|
*
|
||||||
|
* @param irq Interrupt number to configure
|
||||||
|
* @param cb Callback handler to configure
|
||||||
|
*/
|
||||||
|
void clic_set_handler(unsigned irq, clic_isr_cb_t cb);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief CLIC interrupt handler
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*
|
||||||
|
* @param irq Interrupt number to call the handler for
|
||||||
|
*/
|
||||||
|
void clic_isr_handler(uint32_t irq);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* CLIC_H */
|
||||||
|
/** @} */
|
@ -32,6 +32,11 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
 * @brief Bit mask for the MCAUSE register
|
||||||
|
 */
|
||||||
|
#define CPU_CSR_MCAUSE_CAUSE_MSK (0x0fffu)
|
||||||
|
|
||||||
extern volatile int riscv_in_isr;
|
extern volatile int riscv_in_isr;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
#include "panic.h"
|
#include "panic.h"
|
||||||
#include "sched.h"
|
#include "sched.h"
|
||||||
#include "plic.h"
|
#include "plic.h"
|
||||||
|
#include "clic.h"
|
||||||
|
|
||||||
#include "vendor/riscv_csr.h"
|
#include "vendor/riscv_csr.h"
|
||||||
|
|
||||||
@ -50,7 +51,13 @@ void timer_isr(void);
|
|||||||
void riscv_irq_init(void)
|
void riscv_irq_init(void)
|
||||||
{
|
{
|
||||||
/* Setup trap handler function */
|
/* Setup trap handler function */
|
||||||
write_csr(mtvec, &trap_entry);
|
if (IS_ACTIVE(MODULE_PERIPH_CLIC)) {
|
||||||
|
/* Signal CLIC usage to the core */
|
||||||
|
write_csr(mtvec, (uintptr_t)&trap_entry | 0x03);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
write_csr(mtvec, (uintptr_t)&trap_entry);
|
||||||
|
}
|
||||||
|
|
||||||
/* Clear all interrupt enables */
|
/* Clear all interrupt enables */
|
||||||
write_csr(mie, 0);
|
write_csr(mie, 0);
|
||||||
@ -59,12 +66,17 @@ void riscv_irq_init(void)
|
|||||||
if (IS_ACTIVE(MODULE_PERIPH_PLIC)) {
|
if (IS_ACTIVE(MODULE_PERIPH_PLIC)) {
|
||||||
plic_init();
|
plic_init();
|
||||||
}
|
}
|
||||||
|
if (IS_ACTIVE(MODULE_PERIPH_CLIC)) {
|
||||||
|
clic_init();
|
||||||
|
}
|
||||||
|
|
||||||
/* Enable external interrupts */
|
/* Enable external interrupts */
|
||||||
set_csr(mie, MIP_MEIP);
|
set_csr(mie, MIP_MEIP);
|
||||||
|
|
||||||
/* Set default state of mstatus */
|
/* Set default state of mstatus */
|
||||||
set_csr(mstatus, MSTATUS_DEFAULT);
|
set_csr(mstatus, MSTATUS_DEFAULT);
|
||||||
|
|
||||||
|
irq_enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -76,11 +88,13 @@ void handle_trap(uint32_t mcause)
|
|||||||
* calling thread_yield(). */
|
* calling thread_yield(). */
|
||||||
riscv_in_isr = 1;
|
riscv_in_isr = 1;
|
||||||
|
|
||||||
|
uint32_t trap = mcause & CPU_CSR_MCAUSE_CAUSE_MSK;
|
||||||
/* Check for INT or TRAP */
|
/* Check for INT or TRAP */
|
||||||
if ((mcause & MCAUSE_INT) == MCAUSE_INT) {
|
if ((mcause & MCAUSE_INT) == MCAUSE_INT) {
|
||||||
/* Cause is an interrupt - determine type */
|
/* Cause is an interrupt - determine type */
|
||||||
switch (mcause & MCAUSE_CAUSE) {
|
switch (mcause & MCAUSE_CAUSE) {
|
||||||
#ifdef MODULE_PERIPH_TIMER
|
|
||||||
|
#ifdef MODULE_PERIPH_CORETIMER
|
||||||
case IRQ_M_TIMER:
|
case IRQ_M_TIMER:
|
||||||
/* Handle timer interrupt */
|
/* Handle timer interrupt */
|
||||||
timer_isr();
|
timer_isr();
|
||||||
@ -94,13 +108,18 @@ void handle_trap(uint32_t mcause)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
/* Unknown interrupt */
|
if (IS_ACTIVE(MODULE_PERIPH_CLIC)) {
|
||||||
core_panic(PANIC_GENERAL_ERROR, "Unhandled interrupt");
|
clic_isr_handler(trap);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* Unknown interrupt */
|
||||||
|
core_panic(PANIC_GENERAL_ERROR, "Unhandled interrupt");
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
switch (mcause) {
|
switch (trap) {
|
||||||
case CAUSE_USER_ECALL: /* ECALL from user mode */
|
case CAUSE_USER_ECALL: /* ECALL from user mode */
|
||||||
case CAUSE_MACHINE_ECALL: /* ECALL from machine mode */
|
case CAUSE_MACHINE_ECALL: /* ECALL from machine mode */
|
||||||
{
|
{
|
||||||
@ -115,7 +134,7 @@ void handle_trap(uint32_t mcause)
|
|||||||
default:
|
default:
|
||||||
#ifdef DEVELHELP
|
#ifdef DEVELHELP
|
||||||
printf("Unhandled trap:\n");
|
printf("Unhandled trap:\n");
|
||||||
printf(" mcause: 0x%" PRIx32 "\n", mcause);
|
printf(" mcause: 0x%" PRIx32 "\n", trap);
|
||||||
printf(" mepc: 0x%lx\n", read_csr(mepc));
|
printf(" mepc: 0x%lx\n", read_csr(mepc));
|
||||||
printf(" mtval: 0x%lx\n", read_csr(mtval));
|
printf(" mtval: 0x%lx\n", read_csr(mtval));
|
||||||
#endif
|
#endif
|
||||||
@ -128,8 +147,9 @@ void handle_trap(uint32_t mcause)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Marking this as interrupt to ensure an mret at the end, provided by the
|
/* Marking this as interrupt to ensure an mret at the end, provided by the
|
||||||
* compiler. Aligned to 4-byte boundary as per RISC-V spec */
|
* compiler. Aligned to 64-byte boundary as per RISC-V spec and required by some
|
||||||
static void __attribute((aligned(4))) __attribute__((interrupt)) trap_entry(void)
|
* of the supported platforms (gd32)*/
|
||||||
|
static void __attribute((aligned(64))) __attribute__((interrupt)) trap_entry(void)
|
||||||
{
|
{
|
||||||
__asm__ volatile (
|
__asm__ volatile (
|
||||||
"addi sp, sp, -"XTSTR (CONTEXT_FRAME_SIZE)" \n"
|
"addi sp, sp, -"XTSTR (CONTEXT_FRAME_SIZE)" \n"
|
||||||
|
70
cpu/riscv_common/periph/clic.c
Normal file
70
cpu/riscv_common/periph/clic.c
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 Koen Zandberg <koen@bergzand.net>
|
||||||
|
*
|
||||||
|
* 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_riscv_common
|
||||||
|
* @{
|
||||||
|
*
|
||||||
|
* @file
|
||||||
|
* @brief RISCV CLIC interrupt controller implementation
|
||||||
|
*
|
||||||
|
* @author Koen Zandberg <koen@bergzand.net>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include "clic.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief CLIC registry offset helper
|
||||||
|
*/
|
||||||
|
#define CLIC_REGP(offset) ((volatile uint32_t *)((CLIC_BASE_ADDR) + (offset)))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name CLIC configuration registers
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#define CLIC_CFG *((volatile uint8_t *)CLIC_REGP(0x0))
|
||||||
|
#define CLIC_INFO *((volatile uint32_t *)CLIC_REGP(0x4)
|
||||||
|
#define CLIC_MTH *((volatile uint8_t *)CLIC_REGP(0xb)
|
||||||
|
#define CLIC_INT_ADDR CLIC_REGP(0x1000)
|
||||||
|
#define CLIC_INT ((volatile clic_clicint_t *)CLIC_INT_ADDR)
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/* PLIC external ISR function list */
|
||||||
|
static clic_isr_cb_t _ext_isrs[CLIC_NUM_INTERRUPTS];
|
||||||
|
|
||||||
|
void clic_init(void)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void clic_enable_interrupt(unsigned irq, unsigned priority)
|
||||||
|
{
|
||||||
|
CLIC_INT[irq].ie = 1;
|
||||||
|
CLIC_INT[irq].attr = 0;
|
||||||
|
clic_set_priority(irq, priority);
|
||||||
|
}
|
||||||
|
|
||||||
|
void clic_disable_interrupt(unsigned irq)
|
||||||
|
{
|
||||||
|
CLIC_INT[irq].ie = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void clic_set_priority(unsigned irq, unsigned priority)
|
||||||
|
{
|
||||||
|
CLIC_INT[irq].ctl = priority;
|
||||||
|
}
|
||||||
|
|
||||||
|
void clic_set_handler(unsigned irq, clic_isr_cb_t cb)
|
||||||
|
{
|
||||||
|
assert(irq < CLIC_NUM_INTERRUPTS);
|
||||||
|
_ext_isrs[irq] = cb;
|
||||||
|
}
|
||||||
|
|
||||||
|
void clic_isr_handler(uint32_t irq)
|
||||||
|
{
|
||||||
|
_ext_isrs[irq](irq);
|
||||||
|
}
|
@ -200,6 +200,11 @@ config HAS_PERIPH_MCG
|
|||||||
help
|
help
|
||||||
Indicates that an MCG peripheral is present.
|
Indicates that an MCG peripheral is present.
|
||||||
|
|
||||||
|
config HAS_PERIPH_CLIC
|
||||||
|
bool
|
||||||
|
help
|
||||||
|
Indicates that a RISC-V Core-local Interrupt Controller (CLIC) peripheral is present.
|
||||||
|
|
||||||
config HAS_PERIPH_PLIC
|
config HAS_PERIPH_PLIC
|
||||||
bool
|
bool
|
||||||
help
|
help
|
||||||
|
Loading…
Reference in New Issue
Block a user