aboutsummaryrefslogtreecommitdiff
path: root/machine/finisher.c
diff options
context:
space:
mode:
Diffstat (limited to 'machine/finisher.c')
-rw-r--r--machine/finisher.c58
1 files changed, 58 insertions, 0 deletions
diff --git a/machine/finisher.c b/machine/finisher.c
new file mode 100644
index 0000000..d113096
--- /dev/null
+++ b/machine/finisher.c
@@ -0,0 +1,58 @@
+#include <string.h>
+#include "finisher.h"
+#include "fdt.h"
+
+volatile uint32_t* finisher;
+
+void finisher_exit(uint16_t code)
+{
+ if (!finisher) return;
+ if (code == 0) {
+ *finisher = FINISHER_PASS;
+ } else {
+ *finisher = code << 16 | FINISHER_FAIL;
+ }
+}
+
+struct finisher_scan
+{
+ int compat;
+ uint64_t reg;
+};
+
+static void finisher_open(const struct fdt_scan_node *node, void *extra)
+{
+ struct finisher_scan *scan = (struct finisher_scan *)extra;
+ memset(scan, 0, sizeof(*scan));
+}
+
+static void finisher_prop(const struct fdt_scan_prop *prop, void *extra)
+{
+ struct finisher_scan *scan = (struct finisher_scan *)extra;
+ if (!strcmp(prop->name, "compatible") && !strcmp((const char*)prop->value, "sifive,test0")) {
+ scan->compat = 1;
+ } else if (!strcmp(prop->name, "reg")) {
+ fdt_get_address(prop->node->parent, prop->value, &scan->reg);
+ }
+}
+
+static void finisher_done(const struct fdt_scan_node *node, void *extra)
+{
+ struct finisher_scan *scan = (struct finisher_scan *)extra;
+ if (!scan->compat || !scan->reg || finisher) return;
+ finisher = (uint32_t*)(uintptr_t)scan->reg;
+}
+
+void query_finisher(uintptr_t fdt)
+{
+ struct fdt_cb cb;
+ struct finisher_scan scan;
+
+ memset(&cb, 0, sizeof(cb));
+ cb.open = finisher_open;
+ cb.prop = finisher_prop;
+ cb.done = finisher_done;
+ cb.extra = &scan;
+
+ fdt_scan(fdt, &cb);
+}