embox
98 строк · 3.6 Кб
1/**
2* @file
3*
4* @brief PLIC interrupt driver for SiFive U54-MC Core
5*
6* @date 08.06.2024
7* @author Suraj Sonawane
8*/
9
10#include <assert.h>11#include <stdint.h>12
13#include <asm/interrupts.h>14#include <asm/regs.h>15#include <drivers/irqctrl.h>16#include <embox/unit.h>17#include <hal/reg.h>18#include <util/log.h>19
20#define SIFIVE_PLIC_BASE_ADDR 0x0C000000UL /* Base address for SiFive PLIC */21#define SIFIVE_PLIC_PRIORITY_OFFSET 0x00000000UL22#define SIFIVE_PLIC_PENDING_OFFSET 0x00001000UL23#define SIFIVE_PLIC_ENABLE_OFFSET 0x00002000UL24#define SIFIVE_PLIC_THRESHOLD_OFFSET 0x00200000UL25#define SIFIVE_PLIC_CLAIM_OFFSET 0x00200004UL26
27#define SIFIVE_PLIC_PRIORITY_REG(interrupt_id) (SIFIVE_PLIC_BASE_ADDR + SIFIVE_PLIC_PRIORITY_OFFSET + (interrupt_id) * 4)28#define SIFIVE_PLIC_PENDING_REG(word_index) (SIFIVE_PLIC_BASE_ADDR + SIFIVE_PLIC_PENDING_OFFSET + (word_index) * 4)29#define SIFIVE_PLIC_ENABLE_REG(hart_id, word_index) (SIFIVE_PLIC_BASE_ADDR + SIFIVE_PLIC_ENABLE_OFFSET + (hart_id) * 0x80 + (word_index) * 4)30#define SIFIVE_PLIC_THRESHOLD_REG(hart_id) (SIFIVE_PLIC_BASE_ADDR + SIFIVE_PLIC_THRESHOLD_OFFSET + (hart_id) * 0x1000)31#define SIFIVE_PLIC_CLAIM_REG(hart_id) (SIFIVE_PLIC_BASE_ADDR + SIFIVE_PLIC_CLAIM_OFFSET + (hart_id) * 0x1000)32
33#define SIFIVE_PLIC_MAX_INTERRUPTS 51134#define SIFIVE_PLIC_MAX_PRIORITY 735
36static int sifive_plic_init(void) {37for (uint32_t hart_id = 0; hart_id < 4; hart_id++) {38REG32_STORE(SIFIVE_PLIC_THRESHOLD_REG(hart_id), 0);39}40enable_external_interrupts();41return 0;42}
43
44void irqctrl_set_prio(unsigned int interrupt_nr, unsigned int prio) {45if (interrupt_nr > 0 && interrupt_nr <= SIFIVE_PLIC_MAX_INTERRUPTS) {46if (prio <= SIFIVE_PLIC_MAX_PRIORITY) {47REG32_STORE(SIFIVE_PLIC_PRIORITY_REG(interrupt_nr), prio);48} else {49log_error("Priority value %u exceeds the maximum allowable priority %u",50prio, SIFIVE_PLIC_MAX_PRIORITY);51}52} else {53log_error("Interrupt number %u is out of valid range (1 to %u)",54interrupt_nr, SIFIVE_PLIC_MAX_INTERRUPTS);55}56}
57
58void irqctrl_enable_in_cpu(uint32_t hart_id, unsigned int interrupt_nr) {59if (interrupt_nr > 0 && interrupt_nr <= SIFIVE_PLIC_MAX_INTERRUPTS) {60uint32_t reg;61uint32_t word_index = interrupt_nr / 32;62uint32_t bit_index = interrupt_nr % 32;63
64REG32_STORE(SIFIVE_PLIC_PRIORITY_REG(interrupt_nr), 1);65
66reg = REG32_LOAD(SIFIVE_PLIC_ENABLE_REG(hart_id, word_index));67reg |= (1U << bit_index);68REG32_STORE(SIFIVE_PLIC_ENABLE_REG(hart_id, word_index), reg);69} else {70log_error("Interrupt number %u is out of valid range (1 to %u)",71interrupt_nr, SIFIVE_PLIC_MAX_INTERRUPTS);72}73}
74
75void irqctrl_disable_in_cpu(uint32_t hart_id, unsigned int interrupt_nr) {76if (interrupt_nr > 0 && interrupt_nr <= SIFIVE_PLIC_MAX_INTERRUPTS) {77uint32_t reg;78uint32_t word_index = interrupt_nr / 32;79uint32_t bit_index = interrupt_nr % 32;80
81reg = REG32_LOAD(SIFIVE_PLIC_ENABLE_REG(hart_id, word_index));82reg &= ~(1U << bit_index);83REG32_STORE(SIFIVE_PLIC_ENABLE_REG(hart_id, word_index), reg);84} else {85log_error("Interrupt number %u is out of valid range (1 to %u)",86interrupt_nr, SIFIVE_PLIC_MAX_INTERRUPTS);87}88}
89
90void irqctrl_eoi_in_cpu(uint32_t hart_id, unsigned int irq) {91REG32_STORE(SIFIVE_PLIC_CLAIM_REG(hart_id), irq);92}
93
94unsigned int irqctrl_get_intid_from_cpu(uint32_t hart_id) {95return REG32_LOAD(SIFIVE_PLIC_CLAIM_REG(hart_id));96}
97
98IRQCTRL_DEF(sifive_plic, sifive_plic_init);