From 88ca909400fa24c0c00a96a012f3e357bb1287f9 Mon Sep 17 00:00:00 2001 From: Youwes09 Date: Fri, 30 Oct 2026 01:33:34 -0500 Subject: [PATCH 1/5] pmgr: Report whether an ADT device is powered pmgr_adt_power_is_active() lets a caller power a device only if it is off and leave it as it was found. Like pmgr_set_mode_recursive(), it follows each gate's parents: on T8132, dart-ane's gates are virtual, under an ANE_SYS that is off at boot. Assisted-By: LLM Signed-off-by: Youwes09 --- src/pmgr.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ src/pmgr.h | 1 + 2 files changed, 48 insertions(+) diff --git a/src/pmgr.c b/src/pmgr.c index 921a9dae..4bac2cf7 100644 --- a/src/pmgr.c +++ b/src/pmgr.c @@ -287,6 +287,53 @@ int pmgr_adt_power_disable_index(const char *path, u32 index) return pmgr_adt_device_set_mode(path, index, PMGR_PS_PWRGATE, false); } +/* A device is active when it and its parents are. A virtual device has no state of its own. */ +static int pmgr_is_active_recursive(u8 die, u16 id) +{ + const struct pmgr_device *device; + + if (pmgr_find_device(id, &device)) + return -1; + + if (!(device->flags & PMGR_FLAG_VIRTUAL)) { + uintptr_t addr = pmgr_device_get_addr(die, device); + if (!addr) + return -1; + if (FIELD_GET(PMGR_PS_ACTUAL, read32(addr)) != PMGR_PS_ACTIVE) + return 0; + } + + u16 parents[2]; + pmgr_adt_get_parents(device, parents); + for (int i = 0; i < 2; i++) { + if (parents[i]) { + int ret = pmgr_is_active_recursive(die, parents[i]); + if (ret <= 0) + return ret; + } + } + + return 1; +} + +int pmgr_adt_power_is_active(const char *path) +{ + const u32 *devices; + u32 n_devices; + + if (pmgr_adt_find_devices(path, &devices, &n_devices) < 0) + return -1; + + for (u32 i = 0; i < n_devices; ++i) { + int ret = pmgr_is_active_recursive(FIELD_GET(PMGR_DIE_ID, devices[i]), + FIELD_GET(PMGR_DEVICE_ID, devices[i])); + if (ret <= 0) + return ret; + } + + return 1; +} + static int pmgr_reset_device(int die, const struct pmgr_device *dev) { if (die < 0 || die > 16) { diff --git a/src/pmgr.h b/src/pmgr.h index e0f81951..8542936a 100644 --- a/src/pmgr.h +++ b/src/pmgr.h @@ -23,6 +23,7 @@ int pmgr_adt_power_enable(const char *path); int pmgr_adt_power_disable(const char *path); int pmgr_adt_power_enable_index(const char *path, u32 index); int pmgr_adt_power_disable_index(const char *path, u32 index); +int pmgr_adt_power_is_active(const char *path); int pmgr_adt_reset(const char *path); int pmgr_reset(int die, const char *name); From 955d96d2ab4db94c3e1d22d1b23c779b797852e1 Mon Sep 17 00:00:00 2001 From: Youwes09 Date: Fri, 30 Oct 2026 01:34:22 -0500 Subject: [PATCH 2/5] dapf: Find each DART's DAPF from the ADT instance list dapf_entries hardcodes the DAPF reg index of a fixed set of DARTs. On T8132, dart-pmp, dart-dcp and dart-dcpext0 have no DAPF, and their reg at that index is a PS_PROT page shared by many DARTs, which raises an SError when written. Newer SoCs also have DAPFs on DARTs the table does not name: dart-ave0/1 and dart-ane0 on T6040/T6041, dart-pmp0/1 on T6050 and dart-ane1 on T8152. Walk every DART under /arm-io and take the DAPF from its "instance" property, which types each reg range by fourcc in one of two layouts: {type, unit, name[8]} per range, or {type, name[8]} per DART range with the DAPF in the range after them. The entry count tells them apart. Fall back to the table for a DART with no instance list. Assisted-By: LLM Signed-off-by: Youwes09 --- src/dapf.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 91 insertions(+), 8 deletions(-) diff --git a/src/dapf.c b/src/dapf.c index f5c2b055..ae7f3aa3 100644 --- a/src/dapf.c +++ b/src/dapf.c @@ -175,6 +175,10 @@ int dapf_init(const char *path, int index) return ret; } +#define DAPF_REG_NONE -1 +#define DAPF_REG_UNKNOWN -2 + +/* DAPF reg indices for DARTs whose ADT has no "instance" list. */ struct entry { const char *path; int index; @@ -188,21 +192,100 @@ struct entry dapf_entries[] = { {"/arm-io/dart-ave", 3}, {NULL, -1}, }; +static int dapf_table_index(const char *path) +{ + for (struct entry *entry = dapf_entries; entry->path; entry++) { + if (!strcmp(entry->path, path)) + return entry->index; + } + return DAPF_REG_NONE; +} + +/* + * "instance" types a DART's reg ranges by fourcc, as {type, unit, name[8]} for + * every range, or as {type, name[8]} for the DART ranges only, where an entry + * of type DAPF puts the DAPF in the range after them. + */ +struct dapf_instance_short { + u32 type; + char name[8]; +} PACKED; + +struct dapf_instance_long { + u32 type; + u32 unit; + char name[8]; +} PACKED; + +#define DAPF_INSTANCE_TYPE 0x44415046 /* DAPF */ + +static int dapf_reg_index(const char *path) +{ + int dart_path[8]; + int node = adt_path_offset_trace(adt, path, dart_path); + if (node < 0) + return DAPF_REG_UNKNOWN; + + u32 len = 0; + const void *instance = adt_getprop(adt, node, "instance", &len); + if (!instance || !len) + return DAPF_REG_UNKNOWN; + + u32 regs = 0; + while (!adt_get_reg(adt, dart_path, "reg", regs, NULL, NULL)) + regs++; + + if (len == regs * sizeof(struct dapf_instance_long)) { + const struct dapf_instance_long *inst = instance; + + for (u32 i = 0; i < regs; i++) { + if (inst[i].type == DAPF_INSTANCE_TYPE) + return i; + } + return DAPF_REG_NONE; + } + + if (len % sizeof(struct dapf_instance_short) == 0) { + const struct dapf_instance_short *inst = instance; + u32 count = len / sizeof(*inst); + + if (count + 1 != regs) + return count == regs ? DAPF_REG_NONE : DAPF_REG_UNKNOWN; + for (u32 i = 0; i < count; i++) { + if (inst[i].type == DAPF_INSTANCE_TYPE) + return count; + } + return DAPF_REG_NONE; + } + + return DAPF_REG_UNKNOWN; +} + int dapf_init_all(void) { int ret = 0; int count = 0; - struct entry *entry = dapf_entries; + int node = adt_path_offset(adt, "/arm-io"); + if (node < 0) + return -1; - while (entry->path != NULL) { - if (adt_path_offset(adt, entry->path) < 0) { - entry++; + ADT_FOREACH_CHILD(adt, node) + { + const char *type = adt_getprop(adt, node, "device_type", NULL); + if (!type || strcmp(type, "dart")) continue; - } - if (dapf_init(entry->path, entry->index) < 0) { + + char path[64]; + snprintf(path, sizeof(path), "/arm-io/%s", adt_get_name(adt, node)); + + int index = dapf_reg_index(path); + if (index == DAPF_REG_UNKNOWN) + index = dapf_table_index(path); + if (index == DAPF_REG_NONE) + continue; + + if (dapf_init(path, index) < 0) ret = -1; - } - entry++; count += 1; } return ret ? ret : count; From 740b97fdde24fba1427d6319921acac4043e6e33 Mon Sep 17 00:00:00 2001 From: Youwes09 Date: Fri, 30 Oct 2026 01:34:51 -0500 Subject: [PATCH 3/5] dapf: Skip a DAPF that has no filter data On T8132, T8142 and T8152, dart-ave has a DAPF but lists no filter data, so there is nothing to write, yet it was reported as an error. Look the data up before powering the device and skip the DAPF if there is none. Assisted-By: LLM Signed-off-by: Youwes09 --- src/dapf.c | 84 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 44 insertions(+), 40 deletions(-) diff --git a/src/dapf.c b/src/dapf.c index ae7f3aa3..ea06cde5 100644 --- a/src/dapf.c +++ b/src/dapf.c @@ -19,14 +19,12 @@ struct dapf_t8020_config { u32 r4; } PACKED; -static int dapf_init_t8020(const char *path, u64 base, int node) +static int dapf_init_t8020(const char *path, u64 base, const void *data, u32 length) { - u32 length = 0; - const char *prop = "filter-data-instance-0"; - const struct dapf_t8020_config *config = adt_getprop(adt, node, prop, &length); + const struct dapf_t8020_config *config = data; - if (!config || !length || (length % sizeof(*config)) != 0) { - printf("dapf: Error getting ADT node %s property %s.\n", path, prop); + if ((length % sizeof(*config)) != 0) { + printf("dapf: Invalid filter data length for %s\n", path); return -1; } @@ -99,27 +97,8 @@ static int dapf_init_t8110b(u64 base, struct dapf_t8110b_config *config, u32 len return 0; } -static int dapf_init_t8110(const char *path, u64 base, int node) +static int dapf_init_t8110(const char *path, u64 base, const void *config, u32 length) { - u32 length = 0; - char prop[32]; - const void *config = NULL; - - // The dapf config is not always under instance 0; find the first present - // dapf-instance-N. - for (int i = 0; i < 8; i++) { - snprintf(prop, sizeof(prop), "dapf-instance-%d", i); - length = 0; - config = adt_getprop(adt, node, prop, &length); - if (config && length) - break; - } - - if (!config || !length) { - printf("dapf: Error getting ADT node %s dapf-instance property.\n", path); - return -1; - } - // The least common multiple of 52 and 56 is 728 which is in the range of // the observed lengthe for "dapf-instance-0". The 52 byte variant is more // common and prefering that works so far. @@ -128,11 +107,27 @@ static int dapf_init_t8110(const char *path, u64 base, int node) } else if (length % sizeof(struct dapf_t8110b_config) == 0) { return dapf_init_t8110b(base, (struct dapf_t8110b_config *)config, length); } else { - printf("dapf: Invalid length for %s property %s\n", path, prop); + printf("dapf: Invalid filter data length for %s\n", path); return -1; } } +/* dart,t8110 keeps its filter data in the first dapf-instance-N present. */ +static const void *dapf_filter_data(int node, u32 *length) +{ + if (!adt_is_compatible(adt, node, "dart,t8110")) + return adt_getprop(adt, node, "filter-data-instance-0", length); + + for (int i = 0; i < 8; i++) { + char prop[32]; + snprintf(prop, sizeof(prop), "dapf-instance-%d", i); + const void *data = adt_getprop(adt, node, prop, length); + if (data && *length) + return data; + } + return NULL; +} + int dapf_init(const char *path, int index) { int ret; @@ -143,29 +138,38 @@ int dapf_init(const char *path, int index) return -1; } - u32 pwr; - if (!adt_getprop(adt, node, "clock-gates", &pwr)) - pwr = 0; - if (pwr && (pmgr_adt_power_enable(path) < 0)) - return -1; - u64 base; if (adt_get_reg(adt, dart_path, "reg", index, &base, NULL) < 0) { printf("dapf: Error getting DAPF %s base address.\n", path); return -1; } - if (adt_is_compatible(adt, node, "dart,t8020")) { - ret = dapf_init_t8020(path, base, node); - } else if (adt_is_compatible(adt, node, "dart,t6000")) { - ret = dapf_init_t8020(path, base, node); - } else if (adt_is_compatible(adt, node, "dart,t8110")) { - ret = dapf_init_t8110(path, base, node); - } else { + bool t8110 = adt_is_compatible(adt, node, "dart,t8110"); + if (!t8110 && !adt_is_compatible(adt, node, "dart,t8020") && + !adt_is_compatible(adt, node, "dart,t6000")) { printf("dapf: DAPF %s at 0x%lx is of an unknown type\n", path, base); return -1; } + /* M4-generation SoCs list no filter data for dart-ave's DAPF. */ + u32 length = 0; + const void *data = dapf_filter_data(node, &length); + if (!data || !length) { + printf("dapf: %s has no filter data\n", path); + return 0; + } + + u32 pwr; + if (!adt_getprop(adt, node, "clock-gates", &pwr)) + pwr = 0; + if (pwr && (pmgr_adt_power_enable(path) < 0)) + return -1; + + if (t8110) + ret = dapf_init_t8110(path, base, data, length); + else + ret = dapf_init_t8020(path, base, data, length); + if (pwr) pmgr_adt_power_disable(path); From 651ed9abe4464660cfd7daa307712b2725447ca1 Mon Sep 17 00:00:00 2001 From: Youwes09 Date: Fri, 30 Oct 2026 01:35:06 -0500 Subject: [PATCH 4/5] dapf: Power the device behind the DART The DAPF is clock gated with the device behind its DART. On T8132, T8140, T8142 and T8152, the DART lists no gates of its own; they are on the device named without "dart-" (isp, ane, ave, pmp), so those DAPFs were written unpowered. An empty clock-gates, as on T8132's mtp and aop, counts as none. Power the device only if it is off, and power it down again only then: the old code gated a device it found running. If the state cannot be read, power the device and leave it on rather than write to it unpowered. Assisted-By: LLM Signed-off-by: Youwes09 --- src/dapf.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 47 insertions(+), 7 deletions(-) diff --git a/src/dapf.c b/src/dapf.c index ea06cde5..13b197b0 100644 --- a/src/dapf.c +++ b/src/dapf.c @@ -128,6 +128,38 @@ static const void *dapf_filter_data(int node, u32 *length) return NULL; } +static bool dapf_has_clock_gates(const char *path) +{ + int node = adt_path_offset(adt, path); + u32 len = 0; + + /* mtp and aop on T8132 list an empty set. */ + return node >= 0 && adt_getprop(adt, node, "clock-gates", &len) && len; +} + +/* + * The DAPF is gated with the device behind its DART, whose clock gates are on + * the DART or on the device named without "dart-". + */ +static bool dapf_power_path(const char *path, char *buf, size_t size) +{ + const char *name = strrchr(path, '/'); + + if (!name || strlen(path) >= size) + return false; + + strcpy(buf, path); + if (dapf_has_clock_gates(buf)) + return true; + + name++; + if (strncmp(name, "dart-", 5)) + return false; + strcpy(buf + (name - path), name + 5); + + return dapf_has_clock_gates(buf); +} + int dapf_init(const char *path, int index) { int ret; @@ -159,19 +191,27 @@ int dapf_init(const char *path, int index) return 0; } - u32 pwr; - if (!adt_getprop(adt, node, "clock-gates", &pwr)) - pwr = 0; - if (pwr && (pmgr_adt_power_enable(path) < 0)) - return -1; + /* + * Power the device if it is off, and power it down again after. If its + * state is unknown, power it and leave it on. + */ + char power[64]; + int active = 1; + if (dapf_power_path(path, power, sizeof(power))) { + active = pmgr_adt_power_is_active(power); + if (active != 1 && pmgr_adt_power_enable(power) < 0) { + printf("dapf: Error powering %s\n", power); + return -1; + } + } if (t8110) ret = dapf_init_t8110(path, base, data, length); else ret = dapf_init_t8020(path, base, data, length); - if (pwr) - pmgr_adt_power_disable(path); + if (active == 0) + pmgr_adt_power_disable(power); if (!ret) printf("dapf: Initialized %s\n", path); From ffc86bf2fe4878adabb08c77e49bd0d542dc4429 Mon Sep 17 00:00:00 2001 From: Youwes09 Date: Fri, 30 Oct 2026 01:35:12 -0500 Subject: [PATCH 5/5] kboot: Initialize the DAPFs on T8132 DAPF init was skipped on T8132 because it raised an SError. With each DAPF found from the ADT and its device powered, the full set initializes. Without the MTP's DAPF, its DART reports a SID exception as soon as the MTP starts and RTKit never gets a HELLO, so the keyboard and trackpad stay dead. Assisted-By: LLM Signed-off-by: Youwes09 --- src/kboot.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/kboot.c b/src/kboot.c index c5ed8486..8a24eada 100644 --- a/src/kboot.c +++ b/src/kboot.c @@ -2883,9 +2883,7 @@ int kboot_boot(void *kernel) usb_init(); pcie_init(); - /* HACK: DAPF init raises an SError on T8132. */ - if (chip_id != T8132) - dapf_init_all(); + dapf_init_all(); printf("Setting SMP mode to WFE...\n"); smp_set_wfe_mode(true);