mirror of
https://github.com/AsahiLinux/m1n1
synced 2024-11-23 15:13:02 +00:00
kboot: propagate ATC tunables to the FDT
Signed-off-by: Sven Peter <sven@svenpeter.dev>
This commit is contained in:
parent
3b68165900
commit
28103d9003
1 changed files with 163 additions and 0 deletions
163
src/kboot.c
163
src/kboot.c
|
@ -18,6 +18,8 @@
|
|||
|
||||
#define MAX_CHOSEN_PARAMS 16
|
||||
|
||||
#define MAX_ATC_DEVS 8
|
||||
|
||||
static void *dt = NULL;
|
||||
static int dt_bufsize = 0;
|
||||
static void *initrd_start = NULL;
|
||||
|
@ -621,6 +623,165 @@ static int dt_set_uboot(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
struct atc_tunable {
|
||||
u32 offset : 24;
|
||||
u32 size : 8;
|
||||
u32 mask;
|
||||
u32 value;
|
||||
} PACKED;
|
||||
static_assert(sizeof(struct atc_tunable) == 12, "Invalid atc_tunable size");
|
||||
|
||||
struct atc_tunable_info {
|
||||
const char *adt_name;
|
||||
const char *fdt_name;
|
||||
size_t reg_offset;
|
||||
size_t reg_size;
|
||||
bool required;
|
||||
};
|
||||
|
||||
static const struct atc_tunable_info atc_tunables[] = {
|
||||
/* global tunables applied after power on or reset */
|
||||
{"tunable_ATC0AXI2AF", "apple,tunable-axi2af", 0x0, 0x4000, true},
|
||||
{"tunable_ATC_FABRIC", "apple,tunable-common", 0x45000, 0x4000, true},
|
||||
{"tunable_AUS_CMN_TOP", "apple,tunable-common", 0x800, 0x4000, true},
|
||||
{"tunable_AUS_CMN_SHM", "apple,tunable-common", 0xa00, 0x4000, true},
|
||||
{"tunable_AUSPLL_CORE", "apple,tunable-common", 0x2200, 0x4000, true},
|
||||
{"tunable_AUSPLL_TOP", "apple,tunable-common", 0x2000, 0x4000, true},
|
||||
{"tunable_CIO3PLL_CORE", "apple,tunable-common", 0x2a00, 0x4000, true},
|
||||
{"tunable_CIO3PLL_TOP", "apple,tunable-common", 0x2800, 0x4000, true},
|
||||
{"tunable_CIO_CIO3PLL_TOP", "apple,tunable-common", 0x2800, 0x4000, false},
|
||||
{"tunable_USB_ACIOPHY_TOP", "apple,tunable-common", 0x0, 0x4000, true},
|
||||
/* lane-specific tunables applied after a cable is connected */
|
||||
{"tunable_DP_LN0_AUSPMA_TX_TOP", "apple,tunable-lane0-dp", 0xc000, 0x1000, true},
|
||||
{"tunable_DP_LN1_AUSPMA_TX_TOP", "apple,tunable-lane1-dp", 0x13000, 0x1000, true},
|
||||
{"tunable_USB_LN0_AUSPMA_RX_TOP", "apple,tunable-lane0-usb", 0x9000, 0x1000, true},
|
||||
{"tunable_USB_LN0_AUSPMA_RX_EQ", "apple,tunable-lane0-usb", 0xa000, 0x1000, true},
|
||||
{"tunable_USB_LN0_AUSPMA_RX_SHM", "apple,tunable-lane0-usb", 0xb000, 0x1000, true},
|
||||
{"tunable_USB_LN0_AUSPMA_TX_TOP", "apple,tunable-lane0-usb", 0xc000, 0x1000, true},
|
||||
{"tunable_USB_LN1_AUSPMA_RX_TOP", "apple,tunable-lane1-usb", 0x10000, 0x1000, true},
|
||||
{"tunable_USB_LN1_AUSPMA_RX_EQ", "apple,tunable-lane1-usb", 0x11000, 0x1000, true},
|
||||
{"tunable_USB_LN1_AUSPMA_RX_SHM", "apple,tunable-lane1-usb", 0x12000, 0x1000, true},
|
||||
{"tunable_USB_LN1_AUSPMA_TX_TOP", "apple,tunable-lane1-usb", 0x13000, 0x1000, true},
|
||||
{"tunable_CIO_LN0_AUSPMA_RX_TOP", "apple,tunable-lane0-cio", 0x9000, 0x1000, true},
|
||||
{"tunable_CIO_LN0_AUSPMA_RX_EQ", "apple,tunable-lane0-cio", 0xa000, 0x1000, true},
|
||||
{"tunable_CIO_LN0_AUSPMA_RX_SHM", "apple,tunable-lane0-cio", 0xb000, 0x1000, true},
|
||||
{"tunable_CIO_LN0_AUSPMA_TX_TOP", "apple,tunable-lane0-cio", 0xc000, 0x1000, true},
|
||||
{"tunable_CIO_LN1_AUSPMA_RX_TOP", "apple,tunable-lane1-cio", 0x10000, 0x1000, true},
|
||||
{"tunable_CIO_LN1_AUSPMA_RX_EQ", "apple,tunable-lane1-cio", 0x11000, 0x1000, true},
|
||||
{"tunable_CIO_LN1_AUSPMA_RX_SHM", "apple,tunable-lane1-cio", 0x12000, 0x1000, true},
|
||||
{"tunable_CIO_LN1_AUSPMA_TX_TOP", "apple,tunable-lane1-cio", 0x13000, 0x1000, true},
|
||||
};
|
||||
|
||||
static int dt_append_atc_tunable(int adt_node, int fdt_node,
|
||||
const struct atc_tunable_info *tunable_info)
|
||||
{
|
||||
u32 tunables_len;
|
||||
const struct atc_tunable *tunable_adt =
|
||||
adt_getprop(adt, adt_node, tunable_info->adt_name, &tunables_len);
|
||||
|
||||
if (!tunable_adt) {
|
||||
printf("ADT: tunable %s not found\n", tunable_info->adt_name);
|
||||
|
||||
if (tunable_info->required)
|
||||
return -1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (tunables_len % sizeof(*tunable_adt)) {
|
||||
printf("ADT: tunable %s with invalid length %d\n", tunable_info->adt_name, tunables_len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
u32 n_tunables = tunables_len / sizeof(*tunable_adt);
|
||||
for (size_t j = 0; j < n_tunables; j++) {
|
||||
const struct atc_tunable *tunable = &tunable_adt[j];
|
||||
|
||||
if (tunable->size != 32) {
|
||||
printf("kboot: ATC tunable has invalid size %d\n", tunable->size);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (tunable->offset % (tunable->size / 8)) {
|
||||
printf("kboot: ATC tunable has unaligned offset %x\n", tunable->offset);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (tunable->offset + (tunable->size / 8) > tunable_info->reg_size) {
|
||||
printf("kboot: ATC tunable has invalid offset %x\n", tunable->offset);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fdt_appendprop_u32(dt, fdt_node, tunable_info->fdt_name,
|
||||
tunable->offset + tunable_info->reg_offset) < 0)
|
||||
return -1;
|
||||
if (fdt_appendprop_u32(dt, fdt_node, tunable_info->fdt_name, tunable->mask) < 0)
|
||||
return -1;
|
||||
if (fdt_appendprop_u32(dt, fdt_node, tunable_info->fdt_name, tunable->value) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dt_copy_atc_tunables(const char *adt_path, const char *dt_alias)
|
||||
{
|
||||
int ret;
|
||||
|
||||
int adt_node = adt_path_offset(adt, adt_path);
|
||||
if (adt_node < 0)
|
||||
return;
|
||||
|
||||
const char *fdt_path = fdt_get_alias(dt, dt_alias);
|
||||
if (fdt_path == NULL) {
|
||||
printf("FDT: Unable to find alias %s\n", dt_alias);
|
||||
return;
|
||||
}
|
||||
|
||||
int fdt_node = fdt_path_offset(dt, fdt_path);
|
||||
if (fdt_node < 0) {
|
||||
printf("FDT: Unable to find path %s for alias %s\n", fdt_path, dt_alias);
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < sizeof(atc_tunables) / sizeof(*atc_tunables); ++i) {
|
||||
ret = dt_append_atc_tunable(adt_node, fdt_node, &atc_tunables[i]);
|
||||
if (ret)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
cleanup:
|
||||
/*
|
||||
* USB3 and Thunderbolt won't work if something went wrong. Clean up to make
|
||||
* sure we don't leave half-filled properties around so that we can at least
|
||||
* try to boot with USB2 support only.
|
||||
*/
|
||||
for (size_t i = 0; i < sizeof(atc_tunables) / sizeof(*atc_tunables); ++i)
|
||||
fdt_delprop(dt, fdt_node, atc_tunables[i].fdt_name);
|
||||
|
||||
printf("FDT: Unable to setup ATC tunables for %s - USB3/Thunderbolt will not work\n", adt_path);
|
||||
}
|
||||
|
||||
static int dt_set_atc_tunables(void)
|
||||
{
|
||||
char adt_path[32];
|
||||
char fdt_alias[32];
|
||||
|
||||
for (int i = 0; i < MAX_ATC_DEVS; ++i) {
|
||||
memset(adt_path, 0, sizeof(adt_path));
|
||||
snprintf(adt_path, sizeof(adt_path), "/arm-io/atc-phy%d", i);
|
||||
|
||||
memset(fdt_alias, 0, sizeof(adt_path));
|
||||
snprintf(fdt_alias, sizeof(fdt_alias), "atcphy%d", i);
|
||||
|
||||
dt_copy_atc_tunables(adt_path, fdt_alias);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dt_disable_missing_devs(const char *adt_prefix, const char *dt_prefix, int max_devs)
|
||||
{
|
||||
int ret = -1;
|
||||
|
@ -801,6 +962,8 @@ int kboot_prepare_dt(void *fdt)
|
|||
return -1;
|
||||
if (dt_set_uboot())
|
||||
return -1;
|
||||
if (dt_set_atc_tunables())
|
||||
return -1;
|
||||
if (dt_disable_missing_devs("usb-drd", "usb@", 8))
|
||||
return -1;
|
||||
if (dt_disable_missing_devs("i2c", "i2c@", 8))
|
||||
|
|
Loading…
Reference in a new issue