Skip to content

Commit

Permalink
sio: Rework sio init for dual die SoCs
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
jannau committed Apr 27, 2024
1 parent 396d1d7 commit c33c17a
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 92 deletions.
69 changes: 46 additions & 23 deletions src/kboot.c
Original file line number Diff line number Diff line change
Expand Up @@ -1841,35 +1841,33 @@ 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);

if (!phandle) {
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);
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
101 changes: 37 additions & 64 deletions src/sio.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,32 +13,25 @@
#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);
goto done;
}
#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);
Expand All @@ -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;
}
Expand Down Expand Up @@ -152,65 +145,55 @@ 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++) {
struct copy_rule *rule = &copy_rules[i];
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;
}

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)) {
Expand All @@ -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;
}
18 changes: 13 additions & 5 deletions src/sio.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
#ifndef SIO_H
#define SIO_H

#include "types.h"

struct sio_mapping {
u64 phys;
u64 iova;
Expand All @@ -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

0 comments on commit c33c17a

Please sign in to comment.