Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions proxyclient/tools/pmgr_adt2dt.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,20 @@ def die_label(s):
if dev.flags.critical:
print("\t\tapple,always-on;")

if any(dt.pmgr_dev_get_parents(dev)):
domains = [f"<&{die_node('ps_'+dev_by_id[idx].name.lower())}>" for idx in dt.pmgr_dev_get_parents(dev) if idx]
# no_ps parents (fabric nodes like SIO/AFISOCNI0 on t8142) have no node; use their parents
def ps_parents(d):
for idx in dt.pmgr_dev_get_parents(d):
if not idx:
continue
p = dev_by_id[idx]
if p.flags.no_ps:
yield from ps_parents(p)
else:
yield p

parents = list(dict.fromkeys(p.name for p in ps_parents(dev)))
if parents:
domains = [f"<&{die_node('ps_'+name.lower())}>" for name in parents]
print(f"\t\tpower-domains = {', '.join(domains)};")

print( "\t};")
Expand Down
2 changes: 2 additions & 0 deletions src/cpu_regs.h
Original file line number Diff line number Diff line change
Expand Up @@ -822,3 +822,5 @@
/* 48kb read only region given to us by iBoot */
#define SYS_IMP_APL_CTRR_LOWER_EL1 sys_reg(3, 0, 11, 0, 0)
#define SYS_IMP_APL_CTRR_UPPER_EL1 sys_reg(3, 0, 11, 0, 1)
#define SYS_IMP_APL_CTRR_D_LOWER_EL1 sys_reg(3, 0, 11, 0, 2)
#define SYS_IMP_APL_CTRR_D_UPPER_EL1 sys_reg(3, 0, 11, 0, 3)
32 changes: 31 additions & 1 deletion src/dapf.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "malloc.h"
#include "memory.h"
#include "pmgr.h"
#include "soc.h"
#include "string.h"
#include "utils.h"

Expand Down Expand Up @@ -188,6 +189,29 @@ struct entry dapf_entries[] = {
{"/arm-io/dart-ave", 3}, {NULL, -1},
};

/*
* T8142: the DAPF reg index differs per DART (dart-mtp: reg[1]; dart-aop/pmp have none, their reg[1] is a
* shared PSWRDIS page that SErrors on write). The ADT "instance" list names each reg in order as
* {fourcc, index, name[8]}, so find the entry named DAPF; -1 if there is none.
*/
static int dapf_reg_index(const char *path)
{
const struct {
u32 type;
u32 idx;
char name[8];
} PACKED *inst;
u32 len;
int node = adt_path_offset(adt, path);

if (node < 0 || !(inst = adt_getprop(adt, node, "instance", &len)))
return -1;
for (u32 i = 0; i < len / sizeof(*inst); i++)
if (!strncmp(inst[i].name, "DAPF", sizeof(inst[i].name)))
return i;
return -1;
}

int dapf_init_all(void)
{
int ret = 0;
Expand All @@ -199,7 +223,13 @@ int dapf_init_all(void)
entry++;
continue;
}
if (dapf_init(entry->path, entry->index) < 0) {
int index = chip_id == T8142 ? dapf_reg_index(entry->path) : entry->index;
if (index < 0) {
printf("dapf: %s has no DAPF instance, skipping\n", entry->path);
entry++;
continue;
}
if (dapf_init(entry->path, index) < 0) {
ret = -1;
}
entry++;
Expand Down
211 changes: 197 additions & 14 deletions src/kboot.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "mcc.h"
#include "memory.h"
#include "pcie.h"
#include "smc.h"
#include "pmgr.h"
#include "sep.h"
#include "sio.h"
Expand Down Expand Up @@ -388,6 +389,26 @@ static int dt_set_memory(void)
bail("FDT: Could not reserve CTRR range\n");
}

// On t8142 a second CTRR instance covers the DeviceTree/TrustCache area below m1n1, and Linux
// faults the same way if it hands those pages to a secondary CPU. Only reserve it where it is
// known to be populated; the instance reads back zero when it is not in use.
if (chip_id == T8142) {
u64 d_lower = mrs(SYS_IMP_APL_CTRR_D_LOWER_EL1);
u64 d_upper = mrs(SYS_IMP_APL_CTRR_D_UPPER_EL1);

if (d_lower && d_upper >= d_lower) {
u64 d_start = ALIGN_DOWN(d_lower, get_page_size());
u64 d_end = ALIGN_UP(d_upper + SZ_4K, get_page_size());

if (d_start < dram_min || d_end <= d_start || d_end > dram_max)
bail("FDT: Invalid CTRR D range 0x%lx..0x%lx\n", d_start, d_end);

printf("FDT: Reserving CTRR D range 0x%lx..0x%lx\n", d_start, d_end);
if (fdt_add_mem_rsv(dt, d_start, d_end - d_start))
bail("FDT: Could not reserve CTRR D range\n");
}
}

printf("FDT: DRAM at 0x%lx size 0x%lx\n", dram_base, dram_size);
printf("FDT: Usable memory is 0x%lx..0x%lx (0x%lx)\n", dram_min, dram_max, dram_max - dram_min);

Expand Down Expand Up @@ -584,8 +605,17 @@ static int dt_set_cpus(void)
if (dt_mpidr == (mrs(MPIDR_EL1) & 0xFFFFFF))
goto next_cpu;

if (!smp_is_alive(cpu)) {
printf("FDT: CPU %d is not alive, disabling...\n", cpu);
/* Match DT CPU nodes to running CPUs by MPIDR, so the DT order doesn't matter */
int idx = -1;
for (int i = 0; i < MAX_CPUS; i++) {
if (smp_is_alive(i) && smp_get_mpidr(i) == dt_mpidr) {
idx = i;
break;
}
}

if (idx < 0) {
printf("FDT: CPU %d (MPIDR 0x%lx) is not alive, disabling...\n", cpu, dt_mpidr);
pruned_phandles[pruned++] = fdt_get_phandle(dt, node);

int next = fdt_next_subnode(dt, node);
Expand All @@ -603,16 +633,11 @@ static int dt_set_cpus(void)
}
}

u64 mpidr = smp_get_mpidr(cpu);

if (dt_mpidr != mpidr)
bail_cleanup("FDT: DT CPU %d MPIDR mismatch: 0x%lx != 0x%lx\n", cpu, dt_mpidr, mpidr);

u64 release_addr = smp_get_release_addr(cpu);
u64 release_addr = smp_get_release_addr(idx);
if (fdt_setprop_inplace_u64(dt, node, "cpu-release-addr", release_addr))
bail_cleanup("FDT: couldn't set cpu-release-addr property\n");

printf("FDT: CPU %d MPIDR=0x%lx release-addr=0x%lx\n", cpu, mpidr, release_addr);
printf("FDT: CPU %d MPIDR=0x%lx release-addr=0x%lx\n", idx, dt_mpidr, release_addr);

next_cpu:
cpu++;
Expand Down Expand Up @@ -1410,6 +1435,12 @@ static int dt_device_set_reserved_mem(int node, const char *name, uint32_t phand
{
int ret;

// j704: phandle 0 matches no device, so Linux would map nothing and wipe a locked DART's boot tables
if (!phandle) {
printf("FDT: '%s': device has no phandle, skipping iommu-addresses\n", name);
return 0;
}

ret = fdt_appendprop_u32(dt, node, "iommu-addresses", phandle);
if (ret != 0)
bail("FDT: could not append phandle to '%s.iommu-addresses' property: %d\n", name, ret);
Expand All @@ -1429,12 +1460,41 @@ static int dt_device_set_reserved_mem_from_dart(int node, dart_dev_t *dart, cons
uint32_t phandle, u64 paddr, u64 size)
{
u64 iova = dart_get_mapping(dart, name, paddr, size);
if (DART_IS_ERR(iova)) {
printf("ADT: no mapping found for '%s' (0x%012lx iova:0x%08lx)\n", name, paddr, iova);
return 0;
}
if (!DART_IS_ERR(iova))
return dt_device_set_reserved_mem(node, name, phandle, iova, size);

return dt_device_set_reserved_mem(node, name, phandle, iova, size);
/*
* j704: iBoot maps some regions in several IOVA runs (t8142 dcp_data). Describe each run, since
* Linux replaces a locked DART's tables with what iommu-addresses lists.
*/
for (u64 done = 0; done < size;) {
iova = dart_search(dart, (void *)(paddr + done));
if (DART_IS_ERR(iova)) {
/*
* With nothing described yet, keep the historical behaviour: the region stays in
* /reserved-memory without an iommu-addresses entry and the boot continues. Once a
* run has been appended, stopping here would leave Linux a truncated list and it
* would drop the rest of a locked DART's mappings, so fail instead.
*/
if (done)
bail("FDT: '%s' is mapped only up to +0x%lx of 0x%lx, refusing to describe a "
"partial region\n",
name, done, size);
printf("ADT: no mapping found for '%s' (0x%012lx)\n", name, paddr);
return 0;
}
u64 len = SZ_16K;
while (done + len < size &&
(u64)dart_translate_silent(dart, iova + len) == paddr + done + len)
len += SZ_16K;
printf("ADT: %s run 0x%lx..0x%lx at iova 0x%lx\n", name, paddr + done, paddr + done + len,
iova);
int ret = dt_device_set_reserved_mem(node, name, phandle, iova, len);
if (ret)
return ret;
done += len;
}
return 0;
}

static int dt_get_or_add_reserved_mem(const char *node_name, const char *compat, bool nomap,
Expand Down Expand Up @@ -1762,6 +1822,87 @@ static int dt_vram_reserved_region(const char *dcp_alias, const char *disp_alias
disp_reserved_regions_vram, &region, 1);
}

/*
* j704: reserve the iBoot DCP mappings that no carveout in the table covers (on 26.6.2: 0x20000 at
* 0x103df7f0000, the DCP crashlog/coredump area just below dcp_data, iova 0x8cd4000). Linux replaces the
* locked dart-dcp L1 with its own table, so anything not in iommu-addresses vanishes under the running DCP.
*/
static int dt_reserve_dcp_unlisted(const char *dcp_alias, struct disp_mapping *maps, u32 num_maps)
{
struct mem_region known[MAX_DISP_MAPPINGS + 1];
u32 num_known = 0;
int adt_path[4];

int node = adt_path_offset(adt, "/chosen/carveout-memory-map");
if (node < 0)
return 0;
for (u32 i = 0; i < num_maps; i++) {
u64 phys_map[2];
if (ADT_GETPROP_ARRAY(adt, node, maps[i].region_adt, phys_map) == sizeof(phys_map)) {
known[num_known].paddr = phys_map[0];
known[num_known++].size = phys_map[1];
}
}
node = adt_path_offset_trace(adt, "/vram", adt_path);
if (node >= 0) {
int pp = 0;
while (adt_path[pp])
pp++;
adt_path[pp + 1] = 0;
if (adt_get_reg(adt, adt_path, "reg", 0, &known[num_known].paddr,
&known[num_known].size) >= 0)
num_known++;
}

int dcp_node = fdt_path_offset(dt, dcp_alias);
if (dcp_node < 0)
return 0;
uint32_t dcp_phandle = fdt_get_phandle(dt, dcp_node);
dart_dev_t *dart = dt_init_dart_by_node(dcp_node, 0);
if (!dart)
bail("FDT: failed to init DART for '%s'\n", dcp_alias);

int ret = 0;
// iBoot maps the DCP below 0x9000000 on 26.6.2; scan 256 MiB, widen if that grows
for (u64 iova = 0; iova < 0x10000000;) {
u64 pa = (u64)dart_translate_silent(dart, iova);
if (!pa) {
iova += SZ_16K;
continue;
}
u64 len = SZ_16K;
while ((u64)dart_translate_silent(dart, iova + len) == pa + len)
len += SZ_16K;

bool covered = false;
for (u32 i = 0; i < num_known; i++)
if (pa >= known[i].paddr && pa + len <= known[i].paddr + known[i].size)
covered = true;

if (!covered) {
char name[64];
snprintf(name, sizeof(name), "dcp-iboot@%lx", pa);
int mem_node = dt_get_or_add_reserved_mem(name, "apple,asc-mem", true, pa, len);
if (mem_node < 0) {
ret = -1;
break;
}
uint32_t mem_phandle = fdt_get_phandle(dt, mem_node);
ret = dt_device_set_reserved_mem(mem_node, name, dcp_phandle, iova, len);
if (!ret)
ret = dt_device_add_mem_region(dcp_alias, mem_phandle, "dcp-iboot");
if (ret < 0)
break;
printf("FDT: %s: kept unlisted iBoot mapping 0x%lx (0x%lx) at iova 0x%lx\n", dcp_alias,
pa, len, iova);
}
iova += len;
}

dart_shutdown(dart);
return ret;
}

static int dt_reserve_asc_firmware(const char *adt_path, const char *adt_path_alt,
const char *fdt_path, bool remap, u64 base)
{
Expand Down Expand Up @@ -2002,6 +2143,20 @@ static int dt_set_display(void)
ARRAY_SIZE(disp_reserved_regions_t602x));
if (ret)
return ret;
} else if (!fdt_node_check_compatible(dt, 0, "apple,t8142")) {
/*
* j704: same carveout ids as t8112 (49/50/57/94/95 + vram), all mapped in dart-dcp stream 23
* (proxy dump 2026-10-19). DCP only for now: no disp0 / piodma nodes in the DT yet.
*/
ret = dt_carveout_reserved_regions("dcp", NULL, NULL, disp_reserved_regions_t8112,
ARRAY_SIZE(disp_reserved_regions_t8112));
if (ret)
return ret;
ret = dt_vram_reserved_region("dcp", NULL);
if (ret || !fdt_get_alias(dt, "dcp"))
return ret;
return dt_reserve_dcp_unlisted("dcp", disp_reserved_regions_t8112,
ARRAY_SIZE(disp_reserved_regions_t8112));
} else if (!fdt_node_check_compatible(dt, 0, "apple,t6022")) {
/* noop */
} else {
Expand Down Expand Up @@ -2875,13 +3030,41 @@ int kboot_prepare_dt(void *fdt)
return 0;
}

#ifdef J704_WLAN_PWR
/*
* j704: WLAN_REG_ON is SMC GPIO 0x13 (ADT /arm-io/amfm function-reg_on = pKW4('gP13', ...)). Linux has no
* SMC driver for t8142 yet, so raise it here, before pcie_init/Linux release PERST#. The value is what
* Asahi's macsmc-gpio writes to set an output pin (CMD_OUTPUT | 1).
*/
static void j704_wlan_power_on(void)
{
smc_dev_t *smc = smc_init();
if (!smc) {
printf("j704: SMC init failed, Wi-Fi stays off\n");
return;
}
u32 old = 0;
int ret = smc_read_u32(smc, 0x67503133 /* 'gP13' */, &old);
printf("j704: gP13 = 0x%x (read: %d)\n", old, ret);
if (!ret) {
ret = smc_write_u32(smc, 0x67503133, 0x01000001);
printf("j704: gP13 <- 0x01000001 (WLAN_REG_ON): %d\n", ret);
}
smc_shutdown(smc);
mdelay(10);
}
#endif

int kboot_boot(void *kernel)
{
mcc_enable_cache();
tunables_apply_static();
clk_init();

usb_init();
#ifdef J704_WLAN_PWR
j704_wlan_power_on();
#endif
pcie_init();
/* HACK: DAPF init raises an SError on T8132. */
if (chip_id != T8132)
Expand Down
4 changes: 3 additions & 1 deletion src/kboot_atc.c
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ static const struct atc_fuse_info atc_fuses_t8112_port1[] = {
// Order "atc-phy" compatibles in reverse chronologically order to deal with mutliple compatible
// strings in ADT atc-phy nodes.
static const struct atc_fuse_hw atc_fuses[] = {
{"atc-phy,t8142", -1, NULL, 0},
{"atc-phy,t8132", -1, NULL, 0},
{"atc-phy,t8122", -1, NULL, 0},
{"atc-phy,t6020", -1, NULL, 0},
Expand Down Expand Up @@ -301,7 +302,8 @@ static void dt_copy_atc_tunables(void *dt, const char *adt_path, const char *dt_
}

if (adt_is_compatible_at(adt, adt_node, "atc-phy,t8132", 0) ||
adt_is_compatible_at(adt, adt_node, "atc-phy,t8122", 0)) {
adt_is_compatible_at(adt, adt_node, "atc-phy,t8122", 0) ||
adt_is_compatible_at(adt, adt_node, "atc-phy,t8142", 0)) {
tunables = &atc_tunables_t8122[0];
tunable_count = atc_tunables_t8122_count;
} else {
Expand Down
Loading