From c1ca2ac66e4d5f931c0e5433e4affa884e4f4ccf Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Wed, 18 Sep 2024 14:18:16 +0800 Subject: [PATCH] drivers: intc: plic: implement `riscv_plic_irq_set_pending()` Set a PLIC interrupt line as pending. For more info, see "4. Interrupt Pending Bits" of the riscv-plic specs. Signed-off-by: Yong Cong Sin Signed-off-by: Yong Cong Sin --- drivers/interrupt_controller/intc_plic.c | 21 +++++++++++++++++++ .../drivers/interrupt_controller/riscv_plic.h | 7 +++++++ 2 files changed, 28 insertions(+) diff --git a/drivers/interrupt_controller/intc_plic.c b/drivers/interrupt_controller/intc_plic.c index 7a235083cb245ae..cd34d219c980339 100644 --- a/drivers/interrupt_controller/intc_plic.c +++ b/drivers/interrupt_controller/intc_plic.c @@ -39,6 +39,7 @@ #define CONTEXT_CLAIM 0x04 #define CONTEXT_ENABLE_BASE 0x2000 #define CONTEXT_ENABLE_SIZE 0x80 +#define CONTEXT_PENDING_BASE 0x1000 /* * Trigger type is mentioned, but not defined in the RISCV PLIC specs. * However, it is defined and supported by at least the Andes & Telink datasheet, and supported @@ -75,6 +76,7 @@ struct plic_config { mem_addr_t prio; mem_addr_t irq_en; mem_addr_t reg; + mem_addr_t pend; mem_addr_t trig; uint32_t max_prio; uint32_t num_irqs; @@ -161,6 +163,13 @@ static inline mem_addr_t get_threshold_priority_addr(const struct device *dev, u return config->reg + (get_hart_context(dev, hartid) * CONTEXT_SIZE); } +static inline mem_addr_t get_pending_reg(const struct device *dev, uint32_t local_irq) +{ + const struct plic_config *config = dev->config; + + return config->pend + local_irq_to_reg_offset(local_irq); +} + /** * @brief Determine the PLIC device from the IRQ * @@ -302,6 +311,17 @@ void riscv_plic_set_priority(uint32_t irq, uint32_t priority) sys_write32(priority, prio_addr); } +void riscv_plic_irq_set_pending(uint32_t irq) +{ + const struct device *dev = get_plic_dev_from_irq(irq); + const uint32_t local_irq = irq_from_level_2(irq); + mem_addr_t pend_addr = get_pending_reg(dev, local_irq); + uint32_t pend_value = sys_read32(pend_addr); + + WRITE_BIT(pend_value, local_irq & PLIC_REG_MASK, true); + sys_write32(pend_value, pend_addr); +} + /** * @brief Get riscv PLIC-specific interrupt line causing an interrupt * @@ -579,6 +599,7 @@ SHELL_CMD_ARG_REGISTER(plic, &plic_cmds, "PLIC shell commands", .prio = PLIC_BASE_ADDR(n), \ .irq_en = PLIC_BASE_ADDR(n) + CONTEXT_ENABLE_BASE, \ .reg = PLIC_BASE_ADDR(n) + CONTEXT_BASE, \ + .pend = PLIC_BASE_ADDR(n) + CONTEXT_PENDING_BASE, \ IF_ENABLED(PLIC_SUPPORTS_TRIG_TYPE, \ (.trig = PLIC_BASE_ADDR(n) + PLIC_REG_TRIG_TYPE_OFFSET,)) \ .max_prio = DT_INST_PROP(n, riscv_max_priority), \ diff --git a/include/zephyr/drivers/interrupt_controller/riscv_plic.h b/include/zephyr/drivers/interrupt_controller/riscv_plic.h index 22c57a4b69673aa..db08b4a49fb4792 100644 --- a/include/zephyr/drivers/interrupt_controller/riscv_plic.h +++ b/include/zephyr/drivers/interrupt_controller/riscv_plic.h @@ -44,6 +44,13 @@ int riscv_plic_irq_is_enabled(uint32_t irq); */ void riscv_plic_set_priority(uint32_t irq, uint32_t prio); +/** + * @brief Set interrupt as pending + * + * @param irq Multi-level encoded interrupt ID + */ +void riscv_plic_irq_set_pending(uint32_t irq); + /** * @brief Get active interrupt ID *