drivers: interrupt-controller: add Nuclei ECLIC driver
Add support for the ECLIC interrupt controller which is used with the Nuclei processor core. Signed-off-by: TOKITA Hiroshi <tokita.hiroshi@gmail.com>
This commit is contained in:
parent
949d4b91d9
commit
5c7a0ef888
|
@ -277,6 +277,7 @@
|
|||
/drivers/interrupt_controller/ @dcpleung @nashif
|
||||
/drivers/interrupt_controller/intc_gic.c @stephanosio
|
||||
/drivers/interrupt_controller/*esp32* @glaubermaroto
|
||||
/drivers/interrupt_controller/intc_nuclei_eclic.c @soburi
|
||||
/drivers/ipm/ipm_mhu* @karl-zh
|
||||
/drivers/ipm/Kconfig.nrfx @masz-nordic
|
||||
/drivers/ipm/Kconfig.nrfx_ipc_channel @masz-nordic
|
||||
|
|
|
@ -26,3 +26,4 @@ zephyr_library_sources_ifdef(CONFIG_INTC_ESP32 intc_esp32.c)
|
|||
zephyr_library_sources_ifdef(CONFIG_INTC_ESP32C3 intc_esp32c3.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_SWERV_PIC intc_swerv_pic.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_VEXRISCV_LITEX_IRQ intc_vexriscv_litex.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_NUCLEI_ECLIC intc_nuclei_eclic.c)
|
||||
|
|
|
@ -73,4 +73,6 @@ source "drivers/interrupt_controller/Kconfig.esp32c3"
|
|||
|
||||
source "drivers/interrupt_controller/Kconfig.xec"
|
||||
|
||||
source "drivers/interrupt_controller/Kconfig.eclic"
|
||||
|
||||
endmenu
|
||||
|
|
18
drivers/interrupt_controller/Kconfig.eclic
Normal file
18
drivers/interrupt_controller/Kconfig.eclic
Normal file
|
@ -0,0 +1,18 @@
|
|||
# Nuclei ECLIC interrupt-controller configuration
|
||||
|
||||
# Copyright (c) 2021 Tokita, Hiroshi <tokita.hiroshi@gmail.com>
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
DT_COMPAT_NUCLEI_ECLIC = nuclei,eclic
|
||||
|
||||
config HAS_NUCLEI_ECLIC
|
||||
bool
|
||||
help
|
||||
Indicate that the platform has ECLIC.
|
||||
|
||||
config NUCLEI_ECLIC
|
||||
bool "Enhanced Core Local Interrupt Controller (ECLIC)"
|
||||
default $(dt_compat_enabled,$(DT_COMPAT_NUCLEI_ECLIC))
|
||||
depends on HAS_NUCLEI_ECLIC
|
||||
help
|
||||
Interrupt controller for Nuclei SoC core.
|
184
drivers/interrupt_controller/intc_nuclei_eclic.c
Normal file
184
drivers/interrupt_controller/intc_nuclei_eclic.c
Normal file
|
@ -0,0 +1,184 @@
|
|||
/*
|
||||
* Copyright (c) 2021 Tokita, Hiroshi <tokita.hiroshi@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Driver for Nuclie's Extended Core Interrupt Controller
|
||||
*/
|
||||
|
||||
#include <kernel.h>
|
||||
#include <arch/cpu.h>
|
||||
#include <sys/util.h>
|
||||
#include <init.h>
|
||||
#include <soc.h>
|
||||
|
||||
#include <sw_isr_table.h>
|
||||
|
||||
union CLICCFG {
|
||||
struct {
|
||||
uint8_t _reserved0 : 1;
|
||||
/** number of interrupt level bits */
|
||||
uint8_t nlbits : 4;
|
||||
uint8_t _reserved1 : 2;
|
||||
uint8_t _reserved2 : 1;
|
||||
} b;
|
||||
uint8_t w;
|
||||
};
|
||||
|
||||
union CLICINFO {
|
||||
struct {
|
||||
/** number of max supported interrupts */
|
||||
uint32_t numint : 13;
|
||||
/** architecture version */
|
||||
uint32_t version : 8;
|
||||
/** supported bits in the clicintctl */
|
||||
uint32_t intctlbits : 4;
|
||||
uint32_t _reserved0 : 7;
|
||||
} b;
|
||||
uint32_t qw;
|
||||
};
|
||||
|
||||
union CLICMTH {
|
||||
uint8_t w;
|
||||
};
|
||||
|
||||
union CLICINTIP {
|
||||
struct {
|
||||
/** Interrupt Pending */
|
||||
uint8_t IP : 1;
|
||||
uint8_t reserved0 : 7;
|
||||
} b;
|
||||
uint8_t w;
|
||||
};
|
||||
|
||||
union CLICINTIE {
|
||||
struct {
|
||||
/** Interrupt Enabled */
|
||||
uint8_t IE : 1;
|
||||
uint8_t reserved0 : 7;
|
||||
} b;
|
||||
uint8_t w;
|
||||
};
|
||||
|
||||
union CLICINTATTR {
|
||||
struct {
|
||||
/** 0: non-vectored 1:vectored */
|
||||
uint8_t shv : 1;
|
||||
/** 0: level 1: rising edge 2: falling edge */
|
||||
uint8_t trg : 2;
|
||||
uint8_t reserved0 : 3;
|
||||
uint8_t reserved1 : 2;
|
||||
} b;
|
||||
uint8_t w;
|
||||
};
|
||||
|
||||
struct CLICCTRL {
|
||||
volatile union CLICINTIP INTIP;
|
||||
volatile union CLICINTIE INTIE;
|
||||
volatile union CLICINTATTR INTATTR;
|
||||
volatile uint8_t INTCTRL;
|
||||
};
|
||||
|
||||
/** ECLIC Mode mask for MTVT CSR Register */
|
||||
#define ECLIC_MODE_MTVEC_Msk 3U
|
||||
|
||||
/** CLIC INTATTR: TRIG Position */
|
||||
#define CLIC_INTATTR_TRIG_Pos 1U
|
||||
/** CLIC INTATTR: TRIG Mask */
|
||||
#define CLIC_INTATTR_TRIG_Msk (0x3UL << CLIC_INTATTR_TRIG_Pos)
|
||||
|
||||
#define ECLIC_CFG (*((volatile union CLICCFG *)(DT_REG_ADDR_BY_IDX(DT_NODELABEL(eclic), 0))))
|
||||
#define ECLIC_INFO (*((volatile union CLICINFO *)(DT_REG_ADDR_BY_IDX(DT_NODELABEL(eclic), 1))))
|
||||
#define ECLIC_MTH (*((volatile union CLICMTH *)(DT_REG_ADDR_BY_IDX(DT_NODELABEL(eclic), 2))))
|
||||
#define ECLIC_CTRL ((volatile struct CLICCTRL *)(DT_REG_ADDR_BY_IDX(DT_NODELABEL(eclic), 3)))
|
||||
#define ECLIC_CTRL_SIZE (DT_REG_SIZE_BY_IDX(DT_NODELABEL(eclic), 3))
|
||||
|
||||
#if CONFIG_3RD_LEVEL_INTERRUPTS
|
||||
#define INTERRUPT_LEVEL 2
|
||||
#elif CONFIG_2ND_LEVEL_INTERRUPTS
|
||||
#define INTERRUPT_LEVEL 1
|
||||
#else
|
||||
#define INTERRUPT_LEVEL 0
|
||||
#endif
|
||||
|
||||
static uint8_t nlbits;
|
||||
static uint8_t intctlbits;
|
||||
static uint8_t max_prio;
|
||||
static uint8_t max_level;
|
||||
static uint8_t intctrl_mask;
|
||||
|
||||
static inline uint8_t leftalign8(uint8_t val, uint8_t shift)
|
||||
{
|
||||
return (val << (8U - shift));
|
||||
}
|
||||
|
||||
static inline uint8_t mask8(uint8_t len)
|
||||
{
|
||||
return ((1 << len) - 1) & 0xFFFFU;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable interrupt
|
||||
*/
|
||||
void nuclei_eclic_irq_enable(uint32_t irq)
|
||||
{
|
||||
ECLIC_CTRL[irq].INTIE.b.IE = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disable interrupt
|
||||
*/
|
||||
void nuclei_eclic_irq_disable(uint32_t irq)
|
||||
{
|
||||
ECLIC_CTRL[irq].INTIE.b.IE = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get enable status of interrupt
|
||||
*/
|
||||
int nuclei_eclic_irq_is_enabled(uint32_t irq)
|
||||
{
|
||||
return ECLIC_CTRL[irq].INTIE.b.IE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set priority and level of interrupt
|
||||
*/
|
||||
void nuclei_eclic_irq_priority_set(uint32_t irq, uint32_t pri, uint32_t flags)
|
||||
{
|
||||
const uint8_t prio = leftalign8(MIN(pri, max_prio), intctlbits);
|
||||
const uint8_t level = leftalign8(MIN((irq_get_level(irq) - 1), max_level), nlbits);
|
||||
const uint8_t intctrl = (prio | level) | (~intctrl_mask);
|
||||
|
||||
ECLIC_CTRL[irq].INTCTRL = intctrl;
|
||||
|
||||
ECLIC_CTRL[irq].INTATTR.b.shv = 0;
|
||||
ECLIC_CTRL[irq].INTATTR.b.trg = (uint8_t)(flags & CLIC_INTATTR_TRIG_Msk);
|
||||
}
|
||||
|
||||
static int nuclei_eclic_init(const struct device *dev)
|
||||
{
|
||||
/* check hardware support required interrupt levels */
|
||||
__ASSERT_NO_MSG(ECLIC_INFO.b.intctlbits >= INTERRUPT_LEVEL);
|
||||
|
||||
ECLIC_MTH.w = 0;
|
||||
ECLIC_CFG.w = 0;
|
||||
ECLIC_CFG.b.nlbits = INTERRUPT_LEVEL;
|
||||
for (int i = 0; i < ECLIC_CTRL_SIZE; i++) {
|
||||
ECLIC_CTRL[i] = (struct CLICCTRL) { 0 };
|
||||
}
|
||||
|
||||
csr_write(mtvec, ((csr_read(mtvec) & 0xFFFFFFC0) | ECLIC_MODE_MTVEC_Msk));
|
||||
|
||||
nlbits = ECLIC_CFG.b.nlbits;
|
||||
intctlbits = ECLIC_INFO.b.intctlbits;
|
||||
max_prio = mask8(intctlbits - nlbits);
|
||||
max_level = mask8(nlbits);
|
||||
intctrl_mask = leftalign8(mask8(intctlbits), intctlbits);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
SYS_INIT(nuclei_eclic_init, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);
|
19
dts/bindings/interrupt-controller/nuclei,eclic.yaml
Normal file
19
dts/bindings/interrupt-controller/nuclei,eclic.yaml
Normal file
|
@ -0,0 +1,19 @@
|
|||
# Copyright (c) 2021, Tokita, Hiroshi
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
description: Nuclei ECLIC interrupt controller
|
||||
|
||||
compatible: "nuclei,eclic"
|
||||
|
||||
include: [interrupt-controller.yaml, base.yaml]
|
||||
|
||||
properties:
|
||||
reg:
|
||||
required: true
|
||||
|
||||
"#interrupt-cells":
|
||||
const: 2
|
||||
|
||||
interrupt-cells:
|
||||
- irq
|
||||
- priority
|
|
@ -40,6 +40,17 @@
|
|||
clk-divider = <RISCV_MACHINE_TIMER_DIVIDER_4>;
|
||||
};
|
||||
|
||||
eclic: interrupt-controller@d2000000 {
|
||||
#interrupt-cells = <2>;
|
||||
compatible = "nuclei,eclic";
|
||||
interrupt-controller;
|
||||
reg = <0xd2000000 0x0001
|
||||
0xd2000004 0x0004
|
||||
0xd200000b 0x0001
|
||||
0xd2001000 0x1000>;
|
||||
label = "NUCLEI_ECLIC";
|
||||
};
|
||||
|
||||
fmc: flash-controller@40022000 {
|
||||
compatible = "gd,gd32-flash-controller";
|
||||
label = "FMC";
|
||||
|
|
|
@ -291,6 +291,13 @@ void z_irq_spurious(const void *unused);
|
|||
Z_ISR_DECLARE(irq_p, 0, isr_p, isr_param_p); \
|
||||
arch_irq_priority_set(irq_p, priority_p); \
|
||||
}
|
||||
#elif defined(CONFIG_NUCLEI_ECLIC)
|
||||
void nuclei_eclic_irq_priority_set(unsigned int irq, unsigned int prio, unsigned int flags);
|
||||
#define ARCH_IRQ_CONNECT(irq_p, priority_p, isr_p, isr_param_p, flags_p) \
|
||||
{ \
|
||||
Z_ISR_DECLARE(irq_p, 0, isr_p, isr_param_p); \
|
||||
nuclei_eclic_irq_priority_set(irq_p, priority_p, flags_p); \
|
||||
}
|
||||
#else
|
||||
#define ARCH_IRQ_CONNECT(irq_p, priority_p, isr_p, isr_param_p, flags_p) \
|
||||
{ \
|
||||
|
|
|
@ -106,12 +106,6 @@ config USE_GD32_DMA
|
|||
help
|
||||
Enable GD32 Direct Memory Access controller (DMA) HAL module driver
|
||||
|
||||
config USE_GD32_ECLIC
|
||||
bool
|
||||
help
|
||||
Enable GD32 Enhancement Core-Local Interrupt Controller (ECLIC) HAL
|
||||
module driver
|
||||
|
||||
config USE_GD32_ENET
|
||||
bool
|
||||
help
|
||||
|
|
|
@ -50,6 +50,13 @@ void riscv_plic_set_priority(uint32_t irq, uint32_t priority);
|
|||
int riscv_plic_get_irq(void);
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_NUCLEI_ECLIC)
|
||||
void nuclei_eclic_irq_enable(uint32_t irq);
|
||||
void nuclei_eclic_irq_disable(uint32_t irq);
|
||||
int nuclei_eclic_irq_is_enabled(uint32_t irq);
|
||||
void nuclei_eclic_set_priority(uint32_t irq, uint32_t priority);
|
||||
#endif
|
||||
|
||||
#endif /* !_ASMLANGUAGE */
|
||||
|
||||
#endif /* __SOC_COMMON_H_ */
|
||||
|
|
|
@ -24,6 +24,10 @@ void arch_irq_enable(unsigned int irq)
|
|||
return;
|
||||
}
|
||||
#endif
|
||||
#if defined(CONFIG_NUCLEI_ECLIC)
|
||||
nuclei_eclic_irq_enable(irq);
|
||||
return;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* CSR mie register is updated using atomic instruction csrrs
|
||||
|
@ -47,6 +51,10 @@ void arch_irq_disable(unsigned int irq)
|
|||
return;
|
||||
}
|
||||
#endif
|
||||
#if defined(CONFIG_NUCLEI_ECLIC)
|
||||
nuclei_eclic_irq_disable(irq);
|
||||
return;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Use atomic instruction csrrc to disable device interrupt in mie CSR.
|
||||
|
@ -67,6 +75,9 @@ void arch_irq_priority_set(unsigned int irq, unsigned int prio)
|
|||
riscv_plic_set_priority(irq, prio);
|
||||
}
|
||||
#endif
|
||||
#if defined(CONFIG_NUCLEI_ECLIC)
|
||||
nuclei_eclic_set_priority(irq, prio);
|
||||
#endif
|
||||
|
||||
return ;
|
||||
}
|
||||
|
@ -83,6 +94,9 @@ int arch_irq_is_enabled(unsigned int irq)
|
|||
return riscv_plic_irq_is_enabled(irq);
|
||||
}
|
||||
#endif
|
||||
#if defined(CONFIG_NUCLEI_ECLIC)
|
||||
return nuclei_eclic_irq_is_enabled(irq);
|
||||
#endif
|
||||
|
||||
__asm__ volatile ("csrr %0, mie" : "=r" (mie));
|
||||
|
||||
|
|
|
@ -31,11 +31,15 @@ config RISCV_HAS_PLIC
|
|||
default n
|
||||
|
||||
config NUM_IRQS
|
||||
default 64
|
||||
default 87 if NUCLEI_ECLIC
|
||||
default 16 if !NUCLEI_ECLIC
|
||||
|
||||
config FLASH_BASE_ADDRESS
|
||||
default $(dt_node_reg_addr_hex,flash0@8000000)
|
||||
|
||||
config 2ND_LEVEL_INTERRUPTS
|
||||
default y
|
||||
|
||||
config PINCTRL
|
||||
default y
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ config SOC_SERIES_GD32VF103
|
|||
select XIP
|
||||
select GD32_HAS_AFIO_PINMUX
|
||||
select HAS_GD32_HAL
|
||||
select HAS_NUCLEI_ECLIC
|
||||
|
||||
help
|
||||
Enable support for GigaDevice GD32VF1 series SoC
|
||||
|
|
Loading…
Reference in a new issue