Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sio: Rework sio init for dual die SoCs #389

Merged
merged 1 commit into from
Apr 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading