1
0
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:
Koen Zandberg 2021-02-17 13:46:05 +01:00
parent 9239c2fe14
commit 48aa533639
No known key found for this signature in database
GPG Key ID: 0895A893E6D2985B
5 changed files with 205 additions and 8 deletions

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

View File

@ -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;
/**

View File

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

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

View File

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