diff options
Diffstat (limited to 'ports/risc-v64/gnu/example_build/erbium/plic.c')
| -rw-r--r-- | ports/risc-v64/gnu/example_build/erbium/plic.c | 118 |
1 files changed, 118 insertions, 0 deletions
diff --git a/ports/risc-v64/gnu/example_build/erbium/plic.c b/ports/risc-v64/gnu/example_build/erbium/plic.c new file mode 100644 index 00000000..9ca25f1b --- /dev/null +++ b/ports/risc-v64/gnu/example_build/erbium/plic.c @@ -0,0 +1,118 @@ +/*************************************************************************** + * 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 <stddef.h> + +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; +} |
