diff --git a/Makefile b/Makefile index 5ada7a24..c54150ed 100644 --- a/Makefile +++ b/Makefile @@ -103,6 +103,7 @@ OBJECTS := \ i2c.o \ iodev.o \ iova.o \ + isp.o \ kboot.o \ main.o \ mcc.o \ diff --git a/src/isp.c b/src/isp.c new file mode 100644 index 00000000..716402ca --- /dev/null +++ b/src/isp.c @@ -0,0 +1,83 @@ +/* SPDX-License-Identifier: MIT */ + +#include "adt.h" +#include "pmgr.h" +#include "utils.h" + +/* ISP DART has some quirks we must work around */ + +#define DART_T8020_ENABLED_STREAMS 0xfc +#define DART_T8020_STREAM_COMMAND 0x20 +#define DART_T8020_STREAM_SELECT 0x34 +#define DART_T8020_TCR_OFF 0x100 +#define DART_T8020_TTBR 0x200 + +#define DART_T8020_TCR_TRANSLATE_ENABLE BIT(7) +#define DART_T8020_STREAM_COMMAND_INVALIDATE BIT(20) + +struct dart_tunables { + u64 offset; + u64 clear; + u64 set; +}; + +int isp_init(void) +{ + int err = 0; + const char *path = "/arm-io/isp"; + const char *dart_path = "/arm-io/dart-isp"; + + if (pmgr_adt_power_enable(path) < 0) + return -1; + + int adt_path[8]; + int node = adt_path_offset_trace(adt, dart_path, adt_path); + if (node < 0) { + printf("isp: Error getting node %s\n", dart_path); + return -1; + } + + int dart_domain_count = 3; // TODO get from dt + for (int index = 0; index < dart_domain_count; index++) { + u64 base; + err = adt_get_reg(adt, adt_path, "reg", index, &base, NULL); + if (err < 0) + goto out; + + u32 length; + char prop[32] = "dart-tunables-instance"; + snprintf(prop, sizeof(prop), "dart-tunables-instance-%u", index); + const struct dart_tunables *config = adt_getprop(adt, node, prop, &length); + if (!config || !length) { + printf("isp: Error getting ADT node %s property %s.\n", path, prop); + err = -1; + goto out; + } + + err = adt_get_reg(adt, adt_path, "reg", index, &base, NULL); + if (err < 0) + goto out; + + /* DART error handler gets stuck w/o these */ + write32(base + DART_T8020_ENABLED_STREAMS, 0x1); + write32(base + 0x2f0, 0x0); + write32(base + DART_T8020_STREAM_SELECT, 0xffffffff); + write32(base + DART_T8020_STREAM_COMMAND, DART_T8020_STREAM_COMMAND_INVALIDATE); + + /* I think these lock CTRR? Coproc __TEXT read-only region? */ + int count = length / sizeof(*config); + for (int i = 0; i < count; i++) { + u64 offset = config->offset & 0xffff; + u32 set = config->set & 0xffffffff; + mask32(base + offset, read32(base + offset), set); + config++; + } + + write32(base + DART_T8020_TCR_OFF, DART_T8020_TCR_TRANSLATE_ENABLE); + write32(base + 0x13c, 0x20000); + } + +out: + pmgr_adt_power_disable(path); + return err; +} diff --git a/src/isp.h b/src/isp.h new file mode 100644 index 00000000..af83b344 --- /dev/null +++ b/src/isp.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: MIT */ + +#ifndef ISP_H +#define ISP_H + +#include "types.h" + +int isp_init(void); + +#endif diff --git a/src/kboot.c b/src/kboot.c index dcd15ba0..18438d07 100644 --- a/src/kboot.c +++ b/src/kboot.c @@ -10,6 +10,7 @@ #include "devicetree.h" #include "exception.h" #include "firmware.h" +#include "isp.h" #include "malloc.h" #include "mcc.h" #include "memory.h" @@ -2198,6 +2199,7 @@ int kboot_boot(void *kernel) usb_init(); pcie_init(); dapf_init_all(); + isp_init(); printf("Setting SMP mode to WFE...\n"); smp_set_wfe_mode(true);