diff options
Diffstat (limited to 'machine/finisher.c')
-rw-r--r-- | machine/finisher.c | 58 |
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); +} |