aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWesley W. Terpstra <wesley@sifive.com>2017-03-27 20:46:05 -0700
committerWesley W. Terpstra <wesley@sifive.com>2017-03-28 16:28:20 -0700
commit75f1854cd9d665dd6a7ed3bff7556b98e5a4a26c (patch)
tree46fbb0c991f88db96ca19646ca01ad41e4541282
parentb394a92597a5ee766dca42478e12492aba399543 (diff)
downloadriscv-pk-75f1854cd9d665dd6a7ed3bff7556b98e5a4a26c.zip
riscv-pk-75f1854cd9d665dd6a7ed3bff7556b98e5a4a26c.tar.gz
riscv-pk-75f1854cd9d665dd6a7ed3bff7556b98e5a4a26c.tar.bz2
plic: discovered via fdt
-rw-r--r--machine/fdt.c101
-rw-r--r--machine/fdt.h1
-rw-r--r--machine/minit.c1
3 files changed, 103 insertions, 0 deletions
diff --git a/machine/fdt.c b/machine/fdt.c
index 5257f76..b0ba260 100644
--- a/machine/fdt.c
+++ b/machine/fdt.c
@@ -309,3 +309,104 @@ void query_clint(uintptr_t fdt)
fdt_scan(fdt, &cb);
assert (scan.done);
}
+
+///////////////////////////////////////////// PLIC SCAN /////////////////////////////////////////
+
+struct plic_scan
+{
+ int compat;
+ uintptr_t reg;
+ const uint32_t *int_value;
+ int int_len;
+ int done;
+ int ndev;
+};
+
+static void plic_open(const struct fdt_scan_node *node, void *extra)
+{
+ struct plic_scan *scan = (struct plic_scan *)extra;
+ scan->compat = 0;
+ scan->reg = 0;
+ scan->int_value = 0;
+}
+
+static void plic_prop(const struct fdt_scan_prop *prop, void *extra)
+{
+ struct plic_scan *scan = (struct plic_scan *)extra;
+ if (!strcmp(prop->name, "compatible") && !strcmp((const char*)prop->value, "riscv,plic0")) {
+ scan->compat = 1;
+ } else if (!strcmp(prop->name, "reg")) {
+ fdt_get_address(prop->node->parent, prop->value, &scan->reg);
+ } else if (!strcmp(prop->name, "interrupts-extended")) {
+ scan->int_value = prop->value;
+ scan->int_len = prop->len;
+ } else if (!strcmp(prop->name, "riscv,ndev")) {
+ scan->ndev = bswap(prop->value[0]);
+ }
+}
+
+#define HART_BASE 0x200000
+#define HART_SIZE 0x1000
+#define ENABLE_BASE 0x2000
+#define ENABLE_SIZE 0x80
+
+static void plic_done(const struct fdt_scan_node *node, void *extra)
+{
+ struct plic_scan *scan = (struct plic_scan *)extra;
+ const uint32_t *value = scan->int_value;
+ const uint32_t *end = value + scan->int_len/4;
+
+ if (!scan->compat) return;
+ assert (scan->reg != 0);
+ assert (scan->int_value && scan->int_len % 8 == 0);
+ assert (scan->ndev >= 0 && scan->ndev < 1024);
+ assert (!scan->done); // only one plic
+
+ scan->done = 1;
+ plic_priorities = (uint32_t*)scan->reg;
+ plic_ndevs = scan->ndev;
+
+ for (int index = 0; end - value > 0; ++index) {
+ uint32_t phandle = bswap(value[0]);
+ uint32_t cpu_int = bswap(value[1]);
+ int hart;
+ for (hart = 0; hart < MAX_HARTS; ++hart)
+ if (hart_phandles[hart] == phandle)
+ break;
+ if (hart < MAX_HARTS) {
+ hls_t *hls = OTHER_HLS(hart);
+ if (cpu_int == IRQ_M_EXT) {
+ hls->plic_m_ie = (uintptr_t*)(scan->reg + ENABLE_BASE + ENABLE_SIZE * index);
+ hls->plic_m_thresh = (uint32_t*) (scan->reg + HART_BASE + HART_SIZE * index);
+ } else if (cpu_int == IRQ_S_EXT) {
+ hls->plic_s_ie = (uintptr_t*)(scan->reg + ENABLE_BASE + ENABLE_SIZE * index);
+ hls->plic_s_thresh = (uint32_t*) (scan->reg + HART_BASE + HART_SIZE * index);
+ } else {
+ printm("PLIC wired hart %d to wrong interrupt %d", hart, cpu_int);
+ }
+ }
+ value += 2;
+ }
+#if 0
+ printm("PLIC: prio %x devs %d\n", (uint32_t)(uintptr_t)plic_priorities, plic_ndevs);
+ for (int i = 0; i < MAX_HARTS; ++i) {
+ hls_t *hls = OTHER_HLS(i);
+ printm("CPU %d: %x %x %x %x\n", i, (uint32_t)(uintptr_t)hls->plic_m_ie, (uint32_t)(uintptr_t)hls->plic_m_thresh, (uint32_t)(uintptr_t)hls->plic_s_ie, (uint32_t)(uintptr_t)hls->plic_s_thresh);
+ }
+#endif
+}
+
+void query_plic(uintptr_t fdt)
+{
+ struct fdt_cb cb;
+ struct plic_scan scan;
+
+ memset(&cb, 0, sizeof(cb));
+ cb.open = plic_open;
+ cb.prop = plic_prop;
+ cb.done = plic_done;
+ cb.extra = &scan;
+
+ scan.done = 0;
+ fdt_scan(fdt, &cb);
+}
diff --git a/machine/fdt.h b/machine/fdt.h
index ee17007..41c1b52 100644
--- a/machine/fdt.h
+++ b/machine/fdt.h
@@ -56,6 +56,7 @@ const uint32_t *fdt_get_size(const struct fdt_scan_node *node, const uint32_t *b
// Setup memory+clint+plic
void query_mem(uintptr_t fdt);
void query_harts(uintptr_t fdt);
+void query_plic(uintptr_t fdt);
void query_clint(uintptr_t fdt);
#endif
diff --git a/machine/minit.c b/machine/minit.c
index 6fc51c6..c584e9d 100644
--- a/machine/minit.c
+++ b/machine/minit.c
@@ -132,6 +132,7 @@ void init_first_hart(uintptr_t hartid, uintptr_t dtb)
query_mem(dtb);
query_harts(dtb);
+ query_plic(dtb);
query_clint(dtb);
plic_init();