diff --git a/include/plat/spike/plat/instance/hifive/hardware.h b/include/plat/spike/plat/instance/hifive/hardware.h index d90d2af9e..cb038b842 100644 --- a/include/plat/spike/plat/instance/hifive/hardware.h +++ b/include/plat/spike/plat/instance/hifive/hardware.h @@ -13,6 +13,114 @@ #ifndef __PLAT_INSTANCE_HARDWARE_H #define __PLAT_INSTANCE_HARDWARE_H +#define PLIC_MAX_NUM_INT 53 + +#define PLIC_BASE 0x0C000000 +#define PLIC_PPTR_BASE 0xFFFFFFFFCC000000 + +#define PLIC_HARTID 2 + +#define PLIC_PRIO 0x0 +#define PLIC_PRIO_PER_ID 0x4 + +#define PLIC_EN 0x2000 +#define PLIC_EN_PER_HART 0x80 + +#define PLIC_THRES 0x200000 +#define PLIC_THRES_PER_HART 0x1000 +#define PLIC_THRES_CLAIM 0x4 + +static inline uint32_t readl(const volatile uint64_t addr) +{ + uint32_t val; + asm volatile("lw %0, 0(%1)" : "=r"(val) : "r"(addr)); + + return val; +} + +static inline void writel(uint32_t val, volatile uint64_t addr) +{ + asm volatile("sw %0, 0(%1)" : : "r"(val), "r"(addr)); +} + + +static inline interrupt_t plic_get_claim(void) +{ + /* Read the claim register for our HART interrupt context */ + return readl(PLIC_PPTR_BASE + PLIC_THRES + PLIC_THRES_PER_HART * PLIC_HARTID + + PLIC_THRES_CLAIM); +} + +static inline void plic_complete_claim(interrupt_t irq) +{ + /* Complete the IRQ claim by writing back to the claim register. */ + writel(irq, PLIC_PPTR_BASE + PLIC_THRES + PLIC_THRES_PER_HART * PLIC_HARTID + + PLIC_THRES_CLAIM); +} + +static inline void plic_mask_irq(bool_t disable, interrupt_t irq) +{ + uint64_t addr = 0; + uint32_t val = 0; + + if (irq >= 32) { + irq -= 32; + addr = 0x4; + } + + addr += PLIC_PPTR_BASE + PLIC_EN; + val = readl(addr + PLIC_EN_PER_HART * PLIC_HARTID); + if (disable) { + val &= ~BIT(irq); + } else { + val |= BIT(irq); + } + + writel(val, addr + PLIC_EN_PER_HART * PLIC_HARTID); + + if (!disable) { + /* Clear any pending claims if we are enabling otherwise they may not + * be raised again */ + plic_complete_claim(irq); + } +} + +static inline void plic_init_controller(void) +{ + uint32_t pending; + + /* Clear all pending bits */ + pending = readl(PLIC_PPTR_BASE + 0x1000); + for (int i = 0; i < 32 ; i++) { + if (pending & (1 << i)) { + readl(PLIC_PPTR_BASE + PLIC_THRES + + PLIC_THRES_PER_HART * PLIC_HARTID + + PLIC_THRES_CLAIM); + } + } + pending = readl(PLIC_PPTR_BASE + 0x1004); + for (int i = 0; i < 22 ; i++) { + if (pending & (1 << i)) { + readl(PLIC_PPTR_BASE + PLIC_THRES + + PLIC_THRES_PER_HART * PLIC_HARTID + + PLIC_THRES_CLAIM); + } + } + + /* Disable interrupts */ + writel(0, PLIC_PPTR_BASE + PLIC_EN + PLIC_EN_PER_HART * PLIC_HARTID); + writel(0, PLIC_PPTR_BASE + PLIC_EN + PLIC_EN_PER_HART * PLIC_HARTID + 0x4); + + /* Set threshold to zero */ + writel(1, (PLIC_PPTR_BASE + PLIC_THRES + PLIC_THRES_PER_HART * PLIC_HARTID)); + + /* Set the priorities of all interrupts to 1 */ + for (int i = 1; i <= PLIC_MAX_NUM_INT + 1; i++) { + writel(2, PLIC_PPTR_BASE + PLIC_PRIO + PLIC_PRIO_PER_ID * i); + } + +} + /* Available physical memory regions on platform (RAM minus kernel image). */ /* NOTE: Regions are not allowed to be adjacent! */ static p_region_t BOOT_DATA avail_p_regs[] = { diff --git a/include/plat/spike/plat/instance/qemu/hardware.h b/include/plat/spike/plat/instance/qemu/hardware.h index 9d29663f0..175f60756 100644 --- a/include/plat/spike/plat/instance/qemu/hardware.h +++ b/include/plat/spike/plat/instance/qemu/hardware.h @@ -13,6 +13,25 @@ #ifndef __PLAT_INSTANCE_HARDWARE_H #define __PLAT_INSTANCE_HARDWARE_H +#define PLIC_MAX_NUM_INT 0 + +static inline interrupt_t plic_get_claim(void) +{ + return irqInvalid; +} + +static inline void plic_complete_claim(interrupt_t irq) +{ +} + +static inline void plic_mask_irq(bool_t disable, interrupt_t irq) +{ +} + +static inline void plic_init_controller(void) +{ +} + /* Available physical memory regions on platform (RAM minus kernel image). */ /* NOTE: Regions are not allowed to be adjacent! */ static p_region_t BOOT_DATA avail_p_regs[] = { diff --git a/include/plat/spike/plat/instance/rocket-chip/hardware.h b/include/plat/spike/plat/instance/rocket-chip/hardware.h index 7fd3fa950..97d0f8ef4 100644 --- a/include/plat/spike/plat/instance/rocket-chip/hardware.h +++ b/include/plat/spike/plat/instance/rocket-chip/hardware.h @@ -13,6 +13,26 @@ #ifndef __PLAT_INSTANCE_HARDWARE_H #define __PLAT_INSTANCE_HARDWARE_H +#define PLIC_MAX_NUM_INT 0 + +static inline interrupt_t plic_get_claim(void) +{ + return irqInvalid; +} + +static inline void plic_complete_claim(interrupt_t irq) +{ +} + +static inline void plic_mask_irq(bool_t disable, interrupt_t irq) +{ +} + +static inline void plic_init_controller(void) +{ + +} + /* Available physical memory regions on platform (RAM minus kernel image). */ /* NOTE: Regions are not allowed to be adjacent! */ static p_region_t BOOT_DATA avail_p_regs[] = { diff --git a/include/plat/spike/plat/machine.h b/include/plat/spike/plat/machine.h index 514f3f9a6..2ac2dc4ca 100644 --- a/include/plat/spike/plat/machine.h +++ b/include/plat/spike/plat/machine.h @@ -21,6 +21,44 @@ #ifndef __ASSEMBLER__ + +/* + * RISC-V defines a Platform-level interrupt controller (PLIC) (priv-1.10). + * It is responsible for managing global interrupts in a RISC-V system. + * + * A PLIC takes multiple interrupt sources from external devices and delivers + * them to different HART contexts depending on per IRQ configuration registers. + * A HART context is a given privilege level on a given HART. If an IRQ is pending + * for a particular HART context, the PLIC will raise an interrupt on that HART context's + * External interrupt pending(EIP) pin and trigger an interrupt. The HART can then claim + * the IRQ message by communicating with the PLIC where it will receive the highest + * priority pending interrupt. The PLIC will deassert the EIP pin when there are + * no more pending interrupts for that HART. When the HART has finished processing + * the IRQ it completes the claim by notifying the PLIC. Until an IRQ claim has + * completed, the PLIC won't generate futher interrupts for that IRQ. In multicore + * systems, if an IRQ is routed to multiple HARTs, the first HART to claim the IRQ + * gets to process the IRQ and subsequent HARTs won't receive a claim for the same IRQ. + * + * We require each platform to provide the following functions: + * interrupt_t plic_get_claim(void): If called when an IRQ is pending, returns + * the pending priority and starts a claim process. Will return irqInvalid + * if no IRQs are pending. + * void plic_complete_claim(interrupt_t irq): Complete a claim process for an + * interrupt. + * void plic_mask_irq(bool_t disable, interrupt_t irq): Disables or enables an + * IRQ at the PLIC. + * void plic_irq_set_trigger(interrupt_t irq, bool_t edge_triggered): Configure + * an IRQ source on the PLIC to be edge or level triggered. This function does + * not need to be implemented if the PLIC doesn't support configuring this. + * void plic_init_controller(void): Perform PLIC initialisation during boot. + */ +typedef uint32_t interrupt_t; +typedef uint32_t irq_t; + +enum irqNumbers { + irqInvalid = 6 +}; + #if defined(CONFIG_BUILD_SPIKE_QEMU) #include #elif defined(CONFIG_BUILD_ROCKET_CHIP_ZEDBOARD) @@ -41,12 +79,5 @@ enum IRQConstants { #define KERNEL_TIMER_IRQ INTERRUPT_TIMER #define IRQ_CNODE_SLOT_BITS 3 -enum irqNumbers { - irqInvalid = 6 -}; - -typedef uint32_t interrupt_t; -typedef uint32_t irq_t; - #endif /* !__ASSEMBLER__ */ #endif