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" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
 * @brief Bit mask for the MCAUSE register
|
||||
 */
|
||||
#define CPU_CSR_MCAUSE_CAUSE_MSK (0x0fffu)
|
||||
|
||||
extern volatile int riscv_in_isr;
|
||||
|
||||
/**
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include "panic.h"
|
||||
#include "sched.h"
|
||||
#include "plic.h"
|
||||
#include "clic.h"
|
||||
|
||||
#include "vendor/riscv_csr.h"
|
||||
|
||||
@ -50,7 +51,13 @@ void timer_isr(void);
|
||||
void riscv_irq_init(void)
|
||||
{
|
||||
/* 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 */
|
||||
write_csr(mie, 0);
|
||||
@ -59,12 +66,17 @@ void riscv_irq_init(void)
|
||||
if (IS_ACTIVE(MODULE_PERIPH_PLIC)) {
|
||||
plic_init();
|
||||
}
|
||||
if (IS_ACTIVE(MODULE_PERIPH_CLIC)) {
|
||||
clic_init();
|
||||
}
|
||||
|
||||
/* Enable external interrupts */
|
||||
set_csr(mie, MIP_MEIP);
|
||||
|
||||
/* Set default state of mstatus */
|
||||
set_csr(mstatus, MSTATUS_DEFAULT);
|
||||
|
||||
irq_enable();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -76,11 +88,13 @@ void handle_trap(uint32_t mcause)
|
||||
* calling thread_yield(). */
|
||||
riscv_in_isr = 1;
|
||||
|
||||
uint32_t trap = mcause & CPU_CSR_MCAUSE_CAUSE_MSK;
|
||||
/* Check for INT or TRAP */
|
||||
if ((mcause & MCAUSE_INT) == MCAUSE_INT) {
|
||||
/* Cause is an interrupt - determine type */
|
||||
switch (mcause & MCAUSE_CAUSE) {
|
||||
#ifdef MODULE_PERIPH_TIMER
|
||||
|
||||
#ifdef MODULE_PERIPH_CORETIMER
|
||||
case IRQ_M_TIMER:
|
||||
/* Handle timer interrupt */
|
||||
timer_isr();
|
||||
@ -94,13 +108,18 @@ void handle_trap(uint32_t mcause)
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Unknown interrupt */
|
||||
core_panic(PANIC_GENERAL_ERROR, "Unhandled interrupt");
|
||||
if (IS_ACTIVE(MODULE_PERIPH_CLIC)) {
|
||||
clic_isr_handler(trap);
|
||||
}
|
||||
else {
|
||||
/* Unknown interrupt */
|
||||
core_panic(PANIC_GENERAL_ERROR, "Unhandled interrupt");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
switch (mcause) {
|
||||
switch (trap) {
|
||||
case CAUSE_USER_ECALL: /* ECALL from user mode */
|
||||
case CAUSE_MACHINE_ECALL: /* ECALL from machine mode */
|
||||
{
|
||||
@ -115,7 +134,7 @@ void handle_trap(uint32_t mcause)
|
||||
default:
|
||||
#ifdef DEVELHELP
|
||||
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(" mtval: 0x%lx\n", read_csr(mtval));
|
||||
#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
|
||||
* compiler. Aligned to 4-byte boundary as per RISC-V spec */
|
||||
static void __attribute((aligned(4))) __attribute__((interrupt)) trap_entry(void)
|
||||
* compiler. Aligned to 64-byte boundary as per RISC-V spec and required by some
|
||||
* of the supported platforms (gd32)*/
|
||||
static void __attribute((aligned(64))) __attribute__((interrupt)) trap_entry(void)
|
||||
{
|
||||
__asm__ volatile (
|
||||
"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
|
||||
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
|
||||
bool
|
||||
help
|
||||
|
Loading…
Reference in New Issue
Block a user