summaryrefslogtreecommitdiff
path: root/ports/risc-v64/gnu/example_build/erbium/plic.c
diff options
context:
space:
mode:
Diffstat (limited to 'ports/risc-v64/gnu/example_build/erbium/plic.c')
-rw-r--r--ports/risc-v64/gnu/example_build/erbium/plic.c118
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;
+}