Browse Source

drivers: interrupt_controller: intc_clic: add indirect access clic reg

Add indirect CSR access to access CLIC register to satisfy the current
CLIC spec (Version v0.9, 2024-06-28: Draf).

Add CONFIG_LEGACY_CLIC_MEMORYMAP_ACCESS for legacy CLIC implementation
with memory-mapped CLIC register.

Signed-off-by: Jimmy Zheng <jimmyzhe@andestech.com>
pull/88165/head
Jimmy Zheng 5 months ago committed by Benjamin Cabé
parent
commit
dbd0ac40ce
  1. 7
      drivers/interrupt_controller/Kconfig.clic
  2. 85
      drivers/interrupt_controller/intc_clic.c
  3. 13
      drivers/interrupt_controller/intc_clic.h

7
drivers/interrupt_controller/Kconfig.clic

@ -17,6 +17,7 @@ config NUCLEI_ECLIC
select CLIC select CLIC
select CLIC_SMCLICSHV_EXT if RISCV_VECTORED_MODE select CLIC_SMCLICSHV_EXT if RISCV_VECTORED_MODE
select CLIC_SMCLICCONFIG_EXT select CLIC_SMCLICCONFIG_EXT
select LEGACY_CLIC_MEMORYMAP_ACCESS
help help
Interrupt controller for Nuclei SoC core. Interrupt controller for Nuclei SoC core.
@ -59,6 +60,12 @@ config CLIC_PARAMETER_MNLBITS
This option specifies the number of bits in CLICINTCTLBITS assigned to This option specifies the number of bits in CLICINTCTLBITS assigned to
encode the interrupt level at machine mode. encode the interrupt level at machine mode.
config LEGACY_CLIC_MEMORYMAP_ACCESS
bool
help
Enables legacy CLIC, allowing access to CLIC registers through
memory-mapped access instead of indirect CSR access.
config LEGACY_CLIC config LEGACY_CLIC
bool "Use the legacy clic specification" bool "Use the legacy clic specification"
depends on RISCV_HAS_CLIC depends on RISCV_HAS_CLIC

85
drivers/interrupt_controller/intc_clic.c

@ -117,10 +117,15 @@ static ALWAYS_INLINE uint8_t read_clic8(const struct device *dev, uint32_t offse
*/ */
void riscv_clic_irq_enable(uint32_t irq) void riscv_clic_irq_enable(uint32_t irq)
{ {
if (IS_ENABLED(CONFIG_LEGACY_CLIC_MEMORYMAP_ACCESS)) {
const struct device *dev = DEVICE_DT_INST_GET(0); const struct device *dev = DEVICE_DT_INST_GET(0);
union CLICINTIE clicintie = {.b = {.IE = 0x1}}; union CLICINTIE clicintie = {.b = {.IE = 0x1}};
write_clic8(dev, CLIC_INTIE(irq), clicintie.w); write_clic8(dev, CLIC_INTIE(irq), clicintie.w);
} else {
csr_write(CSR_MISELECT, CLIC_INTIE(irq));
csr_set(CSR_MIREG2, BIT(irq % 32));
}
} }
/** /**
@ -128,10 +133,15 @@ void riscv_clic_irq_enable(uint32_t irq)
*/ */
void riscv_clic_irq_disable(uint32_t irq) void riscv_clic_irq_disable(uint32_t irq)
{ {
if (IS_ENABLED(CONFIG_LEGACY_CLIC_MEMORYMAP_ACCESS)) {
const struct device *dev = DEVICE_DT_INST_GET(0); const struct device *dev = DEVICE_DT_INST_GET(0);
union CLICINTIE clicintie = {.b = {.IE = 0x0}}; union CLICINTIE clicintie = {.b = {.IE = 0x0}};
write_clic8(dev, CLIC_INTIE(irq), clicintie.w); write_clic8(dev, CLIC_INTIE(irq), clicintie.w);
} else {
csr_write(CSR_MISELECT, CLIC_INTIE(irq));
csr_clear(CSR_MIREG2, BIT(irq % 32));
}
} }
/** /**
@ -139,10 +149,19 @@ void riscv_clic_irq_disable(uint32_t irq)
*/ */
int riscv_clic_irq_is_enabled(uint32_t irq) int riscv_clic_irq_is_enabled(uint32_t irq)
{ {
int is_enabled = 0;
if (IS_ENABLED(CONFIG_LEGACY_CLIC_MEMORYMAP_ACCESS)) {
const struct device *dev = DEVICE_DT_INST_GET(0); const struct device *dev = DEVICE_DT_INST_GET(0);
union CLICINTIE clicintie = {.w = read_clic8(dev, CLIC_INTIE(irq))}; union CLICINTIE clicintie = {.w = read_clic8(dev, CLIC_INTIE(irq))};
return clicintie.b.IE; is_enabled = clicintie.b.IE;
} else {
csr_write(CSR_MISELECT, CLIC_INTIE(irq));
is_enabled = csr_read(CSR_MIREG2) & BIT(irq % 32);
}
return !!is_enabled;
} }
/** /**
@ -172,12 +191,32 @@ void riscv_clic_irq_priority_set(uint32_t irq, uint32_t pri, uint32_t flags)
(MIN(pri, max_level) << (8U - data->nlbits)) | (MIN(pri, max_level) << (8U - data->nlbits)) |
BIT_MASK(8U - data->intctlbits); BIT_MASK(8U - data->intctlbits);
if (IS_ENABLED(CONFIG_LEGACY_CLIC_MEMORYMAP_ACCESS)) {
write_clic8(dev, CLIC_INTCTRL(irq), intctrl); write_clic8(dev, CLIC_INTCTRL(irq), intctrl);
} else {
uint32_t clicintctl, bit_offset = 8 * (irq % 4);
csr_write(CSR_MISELECT, CLIC_INTCTRL(irq));
clicintctl = csr_read(CSR_MIREG);
clicintctl &= ~GENMASK(bit_offset + 7, bit_offset);
clicintctl |= intctrl << bit_offset;
csr_write(CSR_MIREG, clicintctl);
}
/* Set the IRQ operates in machine mode, non-vectoring and the trigger type. */ /* Set the IRQ operates in machine mode, non-vectoring and the trigger type. */
union CLICINTATTR clicattr = {.b = {.mode = 0x3, .shv = 0x0, .trg = flags & BIT_MASK(3)}}; union CLICINTATTR clicattr = {.b = {.mode = 0x3, .shv = 0x0, .trg = flags & BIT_MASK(3)}};
if (IS_ENABLED(CONFIG_LEGACY_CLIC_MEMORYMAP_ACCESS)) {
write_clic8(dev, CLIC_INTATTR(irq), clicattr.w); write_clic8(dev, CLIC_INTATTR(irq), clicattr.w);
} else {
uint32_t clicintattr, bit_offset = 8 * (irq % 4);
csr_write(CSR_MISELECT, CLIC_INTATTR(irq));
clicintattr = csr_read(CSR_MIREG2);
clicintattr &= ~GENMASK(bit_offset + 7, bit_offset);
clicintattr |= clicattr.w << bit_offset;
csr_write(CSR_MIREG2, clicintattr);
}
} }
/** /**
@ -185,12 +224,22 @@ void riscv_clic_irq_priority_set(uint32_t irq, uint32_t pri, uint32_t flags)
*/ */
void riscv_clic_irq_vector_set(uint32_t irq) void riscv_clic_irq_vector_set(uint32_t irq)
{ {
if (IS_ENABLED(CONFIG_LEGACY_CLIC_MEMORYMAP_ACCESS)) {
const struct device *dev = DEVICE_DT_INST_GET(0); const struct device *dev = DEVICE_DT_INST_GET(0);
union CLICINTATTR clicattr = {.w = read_clic8(dev, CLIC_INTATTR(irq))}; union CLICINTATTR clicattr = {.w = read_clic8(dev, CLIC_INTATTR(irq))};
/* Set Selective Hardware Vectoring. */ /* Set Selective Hardware Vectoring. */
clicattr.b.shv = 1; clicattr.b.shv = 1;
write_clic8(dev, CLIC_INTATTR(irq), clicattr.w); write_clic8(dev, CLIC_INTATTR(irq), clicattr.w);
} else {
uint32_t clicintattr, bit_offset = 8 * (irq % 4);
union CLICINTATTR clicattr = {.b = {.shv = 1}};
csr_write(CSR_MISELECT, CLIC_INTATTR(irq));
clicintattr = csr_read(CSR_MIREG2);
clicintattr |= clicattr.w << bit_offset;
csr_write(CSR_MIREG2, clicintattr);
}
} }
/** /**
@ -198,10 +247,15 @@ void riscv_clic_irq_vector_set(uint32_t irq)
*/ */
void riscv_clic_irq_set_pending(uint32_t irq) void riscv_clic_irq_set_pending(uint32_t irq)
{ {
if (IS_ENABLED(CONFIG_LEGACY_CLIC_MEMORYMAP_ACCESS)) {
const struct device *dev = DEVICE_DT_INST_GET(0); const struct device *dev = DEVICE_DT_INST_GET(0);
union CLICINTIP clicintip = {.b = {.IP = 0x1}}; union CLICINTIP clicintip = {.b = {.IP = 0x1}};
write_clic8(dev, CLIC_INTIP(irq), clicintip.w); write_clic8(dev, CLIC_INTIP(irq), clicintip.w);
} else {
csr_write(CSR_MISELECT, CLIC_INTIP(irq));
csr_set(CSR_MIREG, BIT(irq % 32));
}
} }
static int clic_init(const struct device *dev) static int clic_init(const struct device *dev)
@ -228,17 +282,41 @@ static int clic_init(const struct device *dev)
} }
if (IS_ENABLED(CONFIG_CLIC_SMCLICCONFIG_EXT)) { if (IS_ENABLED(CONFIG_CLIC_SMCLICCONFIG_EXT)) {
if (IS_ENABLED(CONFIG_LEGACY_CLIC_MEMORYMAP_ACCESS)) {
/* Configure the number of bits assigned to interrupt levels. */ /* Configure the number of bits assigned to interrupt levels. */
union CLICCFG cliccfg = {.qw = read_clic32(dev, CLIC_CFG)}; union CLICCFG cliccfg = {.qw = read_clic32(dev, CLIC_CFG)};
cliccfg.w.nlbits = data->nlbits; cliccfg.w.nlbits = data->nlbits;
write_clic32(dev, CLIC_CFG, cliccfg.qw); write_clic32(dev, CLIC_CFG, cliccfg.qw);
} else {
csr_write(CSR_MISELECT, CLIC_CFG);
union CLICCFG cliccfg = {.qw = csr_read(CSR_MIREG)};
cliccfg.w.nlbits = data->nlbits;
csr_write(CSR_MIREG, cliccfg.qw);
}
} }
/* Reset all interrupt control register */ if (IS_ENABLED(CONFIG_LEGACY_CLIC_MEMORYMAP_ACCESS)) {
/* Reset all interrupt control register. */
for (int i = 0; i < CONFIG_NUM_IRQS; i++) { for (int i = 0; i < CONFIG_NUM_IRQS; i++) {
write_clic32(dev, CLIC_CTRL(i), 0); write_clic32(dev, CLIC_CTRL(i), 0);
} }
} else {
/* Reset all clicintip, clicintie register. */
for (int i = 0; i < CONFIG_NUM_IRQS; i += 32) {
csr_write(CSR_MISELECT, CLIC_INTIP(i));
csr_write(CSR_MIREG, 0);
csr_write(CSR_MIREG2, 0);
}
/* Reset all clicintctl, clicintattr register. */
for (int i = 0; i < CONFIG_NUM_IRQS; i += 4) {
csr_write(CSR_MISELECT, CLIC_INTCTRL(i));
csr_write(CSR_MIREG, 0);
csr_write(CSR_MIREG2, 0);
}
}
return 0; return 0;
} }
@ -250,7 +328,8 @@ static int clic_init(const struct device *dev)
}; };
#define CLIC_INTC_CONFIG_INIT(n) \ #define CLIC_INTC_CONFIG_INIT(n) \
const static struct clic_config clic_config_##n = { \ const static struct clic_config clic_config_##n = { \
.base = DT_REG_ADDR(DT_DRV_INST(n)), \ .base = COND_CODE_1(CONFIG_LEGACY_CLIC_MEMORYMAP_ACCESS, \
(DT_REG_ADDR(DT_DRV_INST(n))), (0)), \
}; };
#define CLIC_INTC_DEVICE_INIT(n) \ #define CLIC_INTC_DEVICE_INIT(n) \
CLIC_INTC_DATA_INIT(n) \ CLIC_INTC_DATA_INIT(n) \

13
drivers/interrupt_controller/intc_clic.h

@ -12,11 +12,15 @@
#define CSR_MTVT (0x307) #define CSR_MTVT (0x307)
#define CSR_MNXTI (0x345) #define CSR_MNXTI (0x345)
#define CSR_MINTTHRESH (0x347) #define CSR_MINTTHRESH (0x347)
#define CSR_MISELECT (0x350)
#define CSR_MIREG (0x351)
#define CSR_MIREG2 (0x352)
#ifndef __ASSEMBLER__ #ifndef __ASSEMBLER__
#include <stddef.h> #include <stddef.h>
#ifdef CONFIG_LEGACY_CLIC_MEMORYMAP_ACCESS
/* CLIC Memory mapped register offset */ /* CLIC Memory mapped register offset */
#define CLIC_CFG (0x0) #define CLIC_CFG (0x0)
#define CLIC_CTRL(irq) (0x1000 + 4 * (irq)) #define CLIC_CTRL(irq) (0x1000 + 4 * (irq))
@ -24,6 +28,15 @@
#define CLIC_INTIE(irq) (CLIC_CTRL(irq) + offsetof(union CLICCTRL, w.INTIE)) #define CLIC_INTIE(irq) (CLIC_CTRL(irq) + offsetof(union CLICCTRL, w.INTIE))
#define CLIC_INTATTR(irq) (CLIC_CTRL(irq) + offsetof(union CLICCTRL, w.INTATTR)) #define CLIC_INTATTR(irq) (CLIC_CTRL(irq) + offsetof(union CLICCTRL, w.INTATTR))
#define CLIC_INTCTRL(irq) (CLIC_CTRL(irq) + offsetof(union CLICCTRL, w.INTCTRL)) #define CLIC_INTCTRL(irq) (CLIC_CTRL(irq) + offsetof(union CLICCTRL, w.INTCTRL))
#else
/* Indirect CSR Access miselect offset */
#define CLIC_CFG (0x14A0)
#define CLIC_CTRL(irq) (0x0) /* Dummy value for driver compatibility */
#define CLIC_INTIP(irq) (0x1400 + (irq) / 32)
#define CLIC_INTIE(irq) (0x1400 + (irq) / 32)
#define CLIC_INTATTR(irq) (0x1000 + (irq) / 4)
#define CLIC_INTCTRL(irq) (0x1000 + (irq) / 4)
#endif /* !CONFIG_LEGACY_CLIC_MEMORYMAP_ACCESS */
/* Nuclei ECLIC memory mapped register offset */ /* Nuclei ECLIC memory mapped register offset */
#define CLIC_INFO (0x4) #define CLIC_INFO (0x4)

Loading…
Cancel
Save