/*************************************************************************** * Copyright (c) 2026 Eclipse ThreadX contributors * * This program and the accompanying materials are made available under the * terms of the MIT License which is available at * https://opensource.org/licenses/MIT. * * AI Disclosure: This file was largely AI-generated by Claude Code (Opus 5.5). * The AI-generated portions may be considered public domain (CC0-1.0) * and not subject to the project's licence. The human contributor has * reviewed and verified that the code is correct. * * SPDX-License-Identifier: MIT and CC0-1.0 **************************************************************************/ /* PLIC driver for Erbium, machine-mode context of the current hart. */ #include "plic.h" #include static irq_callback callbacks[MAX_CALLBACK_NUM]; /* Source 0 is reserved and the six sources fit in the first enable word. */ static int plic_source_valid(int irqno) { return (irqno > 0) && (irqno < MAX_CALLBACK_NUM); } void plic_irq_enable(int irqno) { volatile uint32_t *reg = (volatile uint32_t *)PLIC_MENABLE(riscv_get_core()); int intr_enable; if (!plic_source_valid(irqno)) return; intr_enable = riscv_mintr_save(); *reg = *reg | (1u << (unsigned int)irqno); riscv_mintr_restore(intr_enable); } void plic_irq_disable(int irqno) { volatile uint32_t *reg = (volatile uint32_t *)PLIC_MENABLE(riscv_get_core()); int intr_enable; if (!plic_source_valid(irqno)) return; intr_enable = riscv_mintr_save(); *reg = *reg & ~(1u << (unsigned int)irqno); riscv_mintr_restore(intr_enable); } int plic_register_callback(int irqno, irq_callback callback) { if (!plic_source_valid(irqno)) return -1; callbacks[irqno] = callback; return 0; } int plic_unregister_callback(int irqno) { return plic_register_callback(irqno, NULL); } int plic_init(void) { uintptr_t hart = riscv_get_core(); for (int i = 0; i < MAX_CALLBACK_NUM; i++) callbacks[i] = NULL; /* Do not depend on the reset state or on a prior boot stage: start with every source disabled for this context. Drivers enable their own sources. */ *(volatile uint32_t *)PLIC_MENABLE(hart) = 0; /* The values the silicon hardwires; see plic.h. */ *(volatile uint32_t *)PLIC_MTHRESHOLD(hart) = 0; for (int i = 1; i <= PLIC_NUM_SOURCES; i++) *(volatile uint32_t *)PLIC_PRIORITY(i) = 1; return 0; } int plic_claim(void) { return (int)(*(volatile uint32_t *)PLIC_MCLAIM(riscv_get_core())); } void plic_complete(int irqno) { *(volatile uint32_t *)PLIC_MCOMPLETE(riscv_get_core()) = (uint32_t)irqno; } int plic_irq_intr(void) { int ret = -1; int irqno = plic_claim(); /* Nothing pending: another context claimed it first. */ if (irqno == 0) return 0; if (!plic_source_valid(irqno)) { plic_complete(irqno); return -1; } if (callbacks[irqno] != NULL) ret = (callbacks[irqno])(irqno); plic_complete(irqno); return ret; }