From c33c17a36ebb4531acbb33510685ef5add567422 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sun, 21 Apr 2024 14:34:27 +0200 Subject: [PATCH] sio: Rework sio init for dual die SoCs Use a struct instead of global variable to hold the necessary setup information. This allows executing the setup for both sio instances. In addition change the status to "okay" so that sio can remain disabled if the setup fails. Signed-off-by: Janne Grunau --- src/kboot.c | 69 +++++++++++++++++++++++------------ src/sio.c | 101 +++++++++++++++++++--------------------------------- src/sio.h | 18 +++++++--- 3 files changed, 96 insertions(+), 92 deletions(-) diff --git a/src/kboot.c b/src/kboot.c index a0656dc74..cca409cca 100644 --- a/src/kboot.c +++ b/src/kboot.c @@ -1841,23 +1841,17 @@ static int dt_set_display(void) return dt_vram_reserved_region(disp_cfg->dcp_alias, "disp0"); } -static int dt_set_sio_fwdata(void) +static int dt_set_sio_fwdata(const char *adt_path, const char *fdt_alias) { - const char *path = "sio"; - - int node = fdt_path_offset(dt, path); + int node = fdt_path_offset(dt, fdt_alias); if (node < 0) { - printf("FDT: '%s' node not found\n", path); + printf("FDT: '%s' node not found\n", fdt_alias); return 0; } - int ret = sio_setup_fwdata(); - if (ret < 0) - bail("FDT: failed to set up SIO firmware data: %d\n", ret); - int phandle = fdt_get_phandle(dt, node); uint32_t max_phandle; - ret = fdt_find_max_phandle(dt, &max_phandle); + int ret = fdt_find_max_phandle(dt, &max_phandle); if (ret) bail("FDT: failed to get max phandle: %d\n", ret); @@ -1865,11 +1859,15 @@ static int dt_set_sio_fwdata(void) phandle = ++max_phandle; ret = fdt_setprop_u32(dt, node, "phandle", phandle); if (ret != 0) - bail("FDT: couldn't set '%s.phandle' property: %d\n", path, ret); + bail("FDT: couldn't set '%s.phandle' property: %d\n", fdt_alias, ret); } - for (int i = 0; i < sio_num_fwdata; i++) { - struct sio_mapping *mapping = &sio_fwdata[i]; + struct sio_data *siodata = sio_setup_fwdata(adt_path); + if (!siodata) + bail("FDT: failed to set up SIO(%s) firmware data\n", adt_path); + + for (int i = 0; i < siodata->num_fwdata; i++) { + struct sio_mapping *mapping = &siodata->fwdata[i]; char node_name[64]; snprintf(node_name, sizeof(node_name), "sio-firmware-data@%lx", mapping->phys); @@ -1885,23 +1883,50 @@ static int dt_set_sio_fwdata(void) if (ret < 0) return ret; - ret = dt_device_add_mem_region(path, mem_phandle, NULL); + ret = dt_device_add_mem_region(fdt_alias, mem_phandle, NULL); if (ret < 0) return ret; } - node = fdt_path_offset(dt, path); + node = fdt_path_offset(dt, fdt_alias); if (node < 0) - bail("FDT: '%s' not found\n", path); + bail_cleanup("FDT: '%s' not found\n", fdt_alias); - for (int i = 0; i < sio_num_fwparams; i++) { - struct sio_fwparam *param = &sio_fwparams[i]; + for (int i = 0; i < siodata->num_fwparams; i++) { + struct sio_fwparam *param = &siodata->fwparams[i]; if (fdt_appendprop_u32(dt, node, "apple,sio-firmware-params", param->key)) - bail("FDT: couldn't append to SIO parameters\n"); + bail_cleanup("FDT: couldn't append to SIO parameters\n"); if (fdt_appendprop_u32(dt, node, "apple,sio-firmware-params", param->value)) - bail("FDT: couldn't append to SIO parameters\n"); + bail_cleanup("FDT: couldn't append to SIO parameters\n"); + } + +err: + free(siodata); + return 0; +} + +static int dt_setup_sio(void) +{ + static const char *sio_names[2] = {"sio", "sio1"}; + + for (size_t i = 0; i < ARRAY_SIZE(sio_names); i++) { + + int node = fdt_path_offset(dt, sio_names[i]); + if (node < 0) + continue; + + char adt_path[16]; + snprintf(adt_path, sizeof(adt_path), "/arm-io/%s", sio_names[i]); + + if (dt_reserve_asc_firmware(adt_path, NULL, sio_names[i], true, 0)) + continue; + if (dt_set_sio_fwdata(adt_path, sio_names[i])) + continue; + + node = fdt_path_offset(dt, sio_names[i]); + fdt_setprop_string(dt, node, "status", "okay"); } return 0; @@ -2294,9 +2319,7 @@ int kboot_prepare_dt(void *fdt) return -1; if (dt_disable_missing_devs("i2c", "i2c@", 8)) return -1; - if (dt_reserve_asc_firmware("/arm-io/sio", NULL, "sio", true, 0)) - return -1; - if (dt_set_sio_fwdata()) + if (dt_setup_sio()) return -1; if (dt_reserve_asc_firmware("/arm-io/isp", "/arm-io/isp0", "isp", false, isp_iova_base())) return -1; diff --git a/src/sio.c b/src/sio.c index 0008d9c31..150d8305e 100644 --- a/src/sio.c +++ b/src/sio.c @@ -13,23 +13,16 @@ #define SIO_KEY(s) _SIO_KEY(#s) #define _SIO_KEY(s) (((s)[0] << 24) | ((s)[1] << 16) | ((s)[2] << 8) | (s)[3]) -#define MAX_FWDATA 6 -#define MAX_FWPARAMS 16 - -int sio_num_fwdata; -struct sio_mapping *sio_fwdata; -int sio_num_fwparams; -struct sio_fwparam *sio_fwparams; - -static void *alloc_mapped_data(size_t size, u64 *iova) +static void *alloc_mapped_data(struct sio_data *siodata, size_t size, u64 *iova) { - if (sio_num_fwdata >= MAX_FWDATA) + if (siodata->num_fwdata >= MAX_FWDATA) return NULL; - struct sio_mapping *mapping = &sio_fwdata[sio_num_fwdata]; + struct sio_mapping *mapping = &siodata->fwdata[siodata->num_fwdata]; #ifdef MERGE_SIO_FWDATA - if (sio_num_fwdata && ALIGN_UP((mapping - 1)->size, SZ_16K) >= (mapping - 1)->size + size) { + if (siodata->num_fwdata && + ALIGN_UP((mapping - 1)->size, SZ_16K) >= (mapping - 1)->size + size) { mapping--; *iova = mapping->iova + mapping->size; mapping->size = ALIGN_UP(mapping->size + size, SZ_4K); @@ -37,8 +30,8 @@ static void *alloc_mapped_data(size_t size, u64 *iova) } #endif - if (!sio_num_fwdata++) - mapping->iova = *iova = 0x30000; + if (!siodata->num_fwdata++) + mapping->iova = *iova = siodata->iova_base; else mapping->iova = *iova = ALIGN_UP((mapping - 1)->iova + (mapping - 1)->size, SZ_16K); mapping->size = ALIGN_UP(size, SZ_4K); @@ -49,32 +42,32 @@ static void *alloc_mapped_data(size_t size, u64 *iova) return (void *)((*iova - mapping->iova) + mapping->phys); } -static void mapping_fixup(void) +static void mapping_fixup(struct sio_data *siodata) { - for (int i = 0; i < sio_num_fwdata; i++) { - struct sio_mapping *mapping = &sio_fwdata[i]; + for (int i = 0; i < siodata->num_fwdata; i++) { + struct sio_mapping *mapping = &siodata->fwdata[i]; mapping->size = ALIGN_UP(mapping->size, SZ_16K); } } -static void *add_fwdata(size_t size, u32 param_id) +static void *add_fwdata(struct sio_data *siodata, size_t size, u32 param_id) { - if (sio_num_fwparams + 1 >= MAX_FWPARAMS) + if (siodata->num_fwparams + 1 >= MAX_FWPARAMS) return NULL; u64 iova; - void *p = alloc_mapped_data(size, &iova); + void *p = alloc_mapped_data(siodata, size, &iova); if (!p) return NULL; - struct sio_fwparam *param = &sio_fwparams[sio_num_fwparams]; + struct sio_fwparam *param = &siodata->fwparams[siodata->num_fwparams]; param->key = param_id; param->value = iova >> 12; param++; param->key = param_id + 1; param->value = size; - sio_num_fwparams += 2; + siodata->num_fwparams += 2; return p; } @@ -152,29 +145,19 @@ int find_key_index(const char *keylist[], u32 needle) return i; } -int sio_setup_fwdata(void) +struct sio_data *sio_setup_fwdata(const char *adt_path) { - int ret = -ENOMEM; - - if (sio_fwdata) - return 0; + struct sio_data *siodata = calloc(1, sizeof(struct sio_data)); - sio_fwdata = calloc(MAX_FWDATA, sizeof(*sio_fwdata)); - if (!sio_fwdata) - return -ENOMEM; - sio_num_fwdata = 0; + if (!siodata) + return NULL; - sio_fwparams = calloc(MAX_FWPARAMS, sizeof(*sio_fwdata)); - if (!sio_fwparams) { - free(sio_fwdata); - return -ENOMEM; - } - sio_num_fwparams = 0; + siodata->iova_base = 0x30000; - int node = adt_path_offset(adt, "/arm-io/sio"); + int node = adt_path_offset(adt, adt_path); if (node < 0) { - printf("%s: missing node\n", __func__); - goto err_inval; + printf("%s: missing node %s\n", __func__, adt_path); + goto err; } for (int i = 0; i < (int)ARRAY_SIZE(copy_rules); i++) { @@ -182,8 +165,8 @@ int sio_setup_fwdata(void) u32 len; if (!rule->prop) { - if (!add_fwdata(rule->blobsize, rule->fw_param)) - goto err_nomem; + if (!add_fwdata(siodata, rule->blobsize, rule->fw_param)) + goto err; continue; } @@ -191,26 +174,26 @@ int sio_setup_fwdata(void) const u8 *adt_blob = adt_getprop(adt, node, rule->prop, &len); if (!adt_blob) { printf("%s: missing ADT property '%s'\n", __func__, rule->prop); - goto err_inval; + goto err; } if (!rule->keyed) { - u8 *sio_blob = add_fwdata(len, rule->fw_param); + u8 *sio_blob = add_fwdata(siodata, len, rule->fw_param); if (!sio_blob) - goto err_nomem; + goto err; memcpy8(sio_blob, (void *)adt_blob, len); continue; } int nkeys = find_key_index(rule->keys, 0); - u8 *sio_blob = add_fwdata(nkeys * rule->blobsize, rule->fw_param); + u8 *sio_blob = add_fwdata(siodata, nkeys * rule->blobsize, rule->fw_param); if (!sio_blob) - goto err_nomem; + goto err; if (len % (rule->blobsize + 4) != 0) { printf("%s: bad length %d of ADT property '%s', expected multiple of %d + 4\n", __func__, len, rule->prop, rule->blobsize); - goto err_inval; + goto err; } for (u32 off = 0; off + rule->blobsize <= len; off += (rule->blobsize + 4)) { @@ -221,36 +204,26 @@ int sio_setup_fwdata(void) if (key_idx >= nkeys) { printf("%s: unknown key %x found in ADT property '%s'\n", __func__, key, rule->prop); - goto err_inval; + goto err; } memcpy8(sio_blob + (key_idx * rule->blobsize), (void *)(p + 4), rule->blobsize); } } - mapping_fixup(); - - return 0; + mapping_fixup(siodata); -err_inval: - ret = -EINVAL; - goto err; -err_nomem: - ret = -ENOMEM; - goto err; + return siodata; err: for (int i = 0; i < MAX_FWDATA; i++) { - if (!sio_fwdata[i].size) + if (!siodata->fwdata[i].size) break; // No way to give back memory with the top of memory // allocator. // free((void *)sio_fwdata[i].phys); } - free(sio_fwdata); - free(sio_fwparams); - sio_fwdata = NULL; - sio_fwparams = NULL; + free(siodata); - return ret; + return NULL; } diff --git a/src/sio.h b/src/sio.h index be8f63bdf..2ad41f57d 100644 --- a/src/sio.h +++ b/src/sio.h @@ -3,6 +3,8 @@ #ifndef SIO_H #define SIO_H +#include "types.h" + struct sio_mapping { u64 phys; u64 iova; @@ -14,11 +16,17 @@ struct sio_fwparam { u32 value; }; -extern int sio_num_fwdata; -extern struct sio_mapping *sio_fwdata; -extern int sio_num_fwparams; -extern struct sio_fwparam *sio_fwparams; +#define MAX_FWDATA 6 +#define MAX_FWPARAMS 16 + +struct sio_data { + u64 iova_base; + struct sio_mapping fwdata[MAX_FWDATA]; + struct sio_fwparam fwparams[MAX_FWPARAMS]; + int num_fwdata; + int num_fwparams; +}; -int sio_setup_fwdata(void); +struct sio_data *sio_setup_fwdata(const char *adt_path); #endif