kboot: propagate ATC tunables to the FDT

Signed-off-by: Sven Peter <sven@svenpeter.dev>
This commit is contained in:
Sven Peter 2022-03-11 16:58:06 +01:00 committed by Hector Martin
parent 3b68165900
commit 28103d9003

View file

@ -18,6 +18,8 @@
#define MAX_CHOSEN_PARAMS 16 #define MAX_CHOSEN_PARAMS 16
#define MAX_ATC_DEVS 8
static void *dt = NULL; static void *dt = NULL;
static int dt_bufsize = 0; static int dt_bufsize = 0;
static void *initrd_start = NULL; static void *initrd_start = NULL;
@ -621,6 +623,165 @@ static int dt_set_uboot(void)
return 0; 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) static int dt_disable_missing_devs(const char *adt_prefix, const char *dt_prefix, int max_devs)
{ {
int ret = -1; int ret = -1;
@ -801,6 +962,8 @@ int kboot_prepare_dt(void *fdt)
return -1; return -1;
if (dt_set_uboot()) if (dt_set_uboot())
return -1; return -1;
if (dt_set_atc_tunables())
return -1;
if (dt_disable_missing_devs("usb-drd", "usb@", 8)) if (dt_disable_missing_devs("usb-drd", "usb@", 8))
return -1; return -1;
if (dt_disable_missing_devs("i2c", "i2c@", 8)) if (dt_disable_missing_devs("i2c", "i2c@", 8))