123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220 |
- /*
- * Copyright (c) 2006-2023, RT-Thread Development Team
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date Author Notes
- * 2021-10-19 JasonHu first version
- * 2021-11-12 JasonHu fix bug that not intr on f133
- * 2023-04-22 flyingcys add plic register ioremap
- */
- #include <rtthread.h>
- #include <rtdbg.h>
- #include "plic.h"
- #include "rt_interrupt.h"
- #include "io.h"
- #include "encoding.h"
- #include "ioremap.h"
- static void *c906_plic_regs = RT_NULL;
- extern struct rt_irq_desc isr_table[];
- struct plic_handler
- {
- rt_bool_t present;
- void *hart_base;
- void *enable_base;
- };
- rt_inline void plic_toggle(struct plic_handler *handler, int hwirq, int enable);
- struct plic_handler c906_plic_handlers[C906_NR_CPUS];
- static void *c906_irq_priority[INTERRUPTS_MAX] = {RT_NULL};
- rt_inline void plic_irq_toggle(int hwirq, int enable)
- {
- int cpu = 0;
- void *priority_addr;
- /* set priority of interrupt, interrupt 0 is zero. */
- priority_addr = (void *)((rt_size_t)c906_plic_regs + PRIORITY_BASE + hwirq * PRIORITY_PER_ID);
- #ifdef RT_USING_SMART
- if (c906_irq_priority[hwirq] == RT_NULL)
- {
- c906_irq_priority[hwirq] = (void *)rt_ioremap(priority_addr, 0x1000);
- }
- priority_addr = c906_irq_priority[hwirq];
- #endif
- writel(enable, priority_addr);
- struct plic_handler *handler = &c906_plic_handlers[cpu];
- if (handler->present)
- {
- plic_toggle(handler, hwirq, enable);
- }
- }
- static void generic_handle_irq(int irq)
- {
- rt_isr_handler_t isr;
- void *param;
- if (irq < 0 || irq >= IRQ_MAX_NR)
- {
- LOG_E("bad irq number %d!\n", irq);
- return;
- }
- if (!irq) // irq = 0 => no irq
- {
- LOG_W("no irq!\n");
- return;
- }
- isr = isr_table[IRQ_OFFSET + irq].handler;
- param = isr_table[IRQ_OFFSET + irq].param;
- if (isr != RT_NULL)
- {
- isr(irq, param);
- }
- /* complete irq. */
- plic_complete(irq);
- }
- void plic_complete(int irqno)
- {
- int cpu = 0;
- struct plic_handler *handler = &c906_plic_handlers[cpu];
- writel(irqno, (void *)((rt_size_t)handler->hart_base + CONTEXT_CLAIM));
- }
- void plic_disable_irq(int irqno)
- {
- plic_irq_toggle(irqno, 0);
- }
- void plic_enable_irq(int irqno)
- {
- plic_irq_toggle(irqno, 1);
- }
- /*
- * Handling an interrupt is a two-step process: first you claim the interrupt
- * by reading the claim register, then you complete the interrupt by writing
- * that source ID back to the same claim register. This automatically enables
- * and disables the interrupt, so there's nothing else to do.
- */
- void plic_handle_irq(void)
- {
- int cpu = 0;
- unsigned int irq;
- struct plic_handler *handler = &c906_plic_handlers[cpu];
- void *claim = (void *)((rt_size_t)handler->hart_base + CONTEXT_CLAIM);
- if (c906_plic_regs == RT_NULL || !handler->present)
- {
- LOG_E("plic state not initialized.");
- return;
- }
- clear_csr(sie, SIE_SEIE);
- while ((irq = readl(claim)))
- {
- /* ID0 is diabled permantually from spec. */
- if (irq == 0)
- {
- LOG_E("irq no is zero.");
- }
- else
- {
- generic_handle_irq(irq);
- }
- }
- set_csr(sie, SIE_SEIE);
- }
- rt_inline void plic_toggle(struct plic_handler *handler, int hwirq, int enable)
- {
- uint32_t *reg = (uint32_t *)((rt_size_t)handler->enable_base + (hwirq / 32) * sizeof(uint32_t));
- uint32_t hwirq_mask = 1 << (hwirq % 32);
- if (enable)
- {
- writel(readl(reg) | hwirq_mask, reg);
- }
- else
- {
- writel(readl(reg) & ~hwirq_mask, reg);
- }
- }
- void plic_init(void)
- {
- int nr_irqs;
- int nr_context;
- int i;
- unsigned long hwirq;
- int cpu = 0;
- if (c906_plic_regs)
- {
- LOG_E("plic already initialized!");
- return;
- }
- nr_context = C906_NR_CONTEXT;
- c906_plic_regs = (void *)C906_PLIC_PHY_ADDR;
- if (!c906_plic_regs)
- {
- LOG_E("fatal error, plic is reg space is null.");
- return;
- }
- nr_irqs = C906_PLIC_NR_EXT_IRQS;
- for (i = 0; i < nr_context; i ++)
- {
- struct plic_handler *handler;
- uint32_t threshold = 0;
- cpu = 0;
- /* skip contexts other than supervisor external interrupt */
- if (i == 0)
- {
- continue;
- }
- // we always use CPU0 M-mode target register.
- handler = &c906_plic_handlers[cpu];
- if (handler->present)
- {
- threshold = 0xffffffff;
- goto done;
- }
- handler->present = RT_TRUE;
- handler->hart_base = (void *)((rt_size_t)c906_plic_regs + CONTEXT_BASE + i * CONTEXT_PER_HART);
- handler->enable_base = (void *)((rt_size_t)c906_plic_regs + ENABLE_BASE + i * ENABLE_PER_HART);
- #ifdef RT_USING_SMART
- handler->hart_base = (void *)rt_ioremap(handler->hart_base, 0x1000);
- handler->enable_base = (void *)rt_ioremap(handler->enable_base, 0x1000);
- #endif
- done:
- /* priority must be > threshold to trigger an interrupt */
- writel(threshold, (void *)((rt_size_t)handler->hart_base + CONTEXT_THRESHOLD));
- for (hwirq = 1; hwirq <= nr_irqs; hwirq++)
- {
- plic_toggle(handler, hwirq, 0);
- }
- }
- /* Enable supervisor external interrupts. */
- set_csr(sie, SIE_SEIE);
- }
|