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 <j@jannau.net>
This commit is contained in:
Janne Grunau 2024-04-21 14:34:27 +02:00 committed by Hector Martin
parent 396d1d7207
commit 0c64b6b4c1
3 changed files with 96 additions and 92 deletions

View file

@ -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;

101
src/sio.c
View file

@ -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 @@ done:
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;
struct sio_data *siodata = calloc(1, sizeof(struct sio_data));
if (sio_fwdata)
return 0;
if (!siodata)
return NULL;
sio_fwdata = calloc(MAX_FWDATA, sizeof(*sio_fwdata));
if (!sio_fwdata)
return -ENOMEM;
sio_num_fwdata = 0;
siodata->iova_base = 0x30000;
sio_fwparams = calloc(MAX_FWPARAMS, sizeof(*sio_fwdata));
if (!sio_fwparams) {
free(sio_fwdata);
return -ENOMEM;
}
sio_num_fwparams = 0;
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();
mapping_fixup(siodata);
return 0;
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;
}

View file

@ -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
int sio_setup_fwdata(void);
struct sio_data {
u64 iova_base;
struct sio_mapping fwdata[MAX_FWDATA];
struct sio_fwparam fwparams[MAX_FWPARAMS];
int num_fwdata;
int num_fwparams;
};
struct sio_data *sio_setup_fwdata(const char *adt_path);
#endif