mirror of
https://github.com/AsahiLinux/m1n1
synced 2024-11-21 22:23:05 +00:00
sio: Set up auxiliary SIO data in FDT
On kboot, parse the ADT for SIO firmware parameters, set up the expected data structures for SIO consumption in reserved memory, and pass those in properties of the SIO FDT node. Signed-off-by: Martin Povišer <povik@cutebit.org>
This commit is contained in:
parent
44f65b1875
commit
39f4919fc1
4 changed files with 316 additions and 0 deletions
1
Makefile
1
Makefile
|
@ -116,6 +116,7 @@ OBJECTS := \
|
|||
rtkit.o \
|
||||
sart.o \
|
||||
sep.o \
|
||||
sio.o \
|
||||
smp.o \
|
||||
start.o \
|
||||
startup.o \
|
||||
|
|
69
src/kboot.c
69
src/kboot.c
|
@ -15,6 +15,7 @@
|
|||
#include "pcie.h"
|
||||
#include "pmgr.h"
|
||||
#include "sep.h"
|
||||
#include "sio.h"
|
||||
#include "smp.h"
|
||||
#include "tunables.h"
|
||||
#include "types.h"
|
||||
|
@ -1724,6 +1725,72 @@ static int dt_set_display(void)
|
|||
return dt_vram_reserved_region("dcp", "disp0");
|
||||
}
|
||||
|
||||
static int dt_set_sio_fwdata(void)
|
||||
{
|
||||
const char *path = "/soc/sio";
|
||||
|
||||
int node = fdt_path_offset(dt, path);
|
||||
if (node < 0) {
|
||||
printf("FDT: '%s' node not found\n", path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ret = sio_setup_fwdata();
|
||||
if (ret < 0)
|
||||
bail("DT: 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);
|
||||
if (ret)
|
||||
bail("DT: 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("DT: couldn't set '%s.phandle' property: %d\n", path, ret);
|
||||
}
|
||||
|
||||
for (int i = 0; i < sio_num_fwdata; i++) {
|
||||
struct sio_mapping *mapping = &sio_fwdata[i];
|
||||
|
||||
char node_name[64];
|
||||
snprintf(node_name, sizeof(node_name), "sio-firmware-data@%lx", mapping->phys);
|
||||
|
||||
int mem_node =
|
||||
dt_get_or_add_reserved_mem(node_name, "apple,asc-mem", mapping->phys, mapping->size);
|
||||
if (mem_node < 0)
|
||||
return ret;
|
||||
uint32_t mem_phandle = fdt_get_phandle(dt, mem_node);
|
||||
|
||||
int ret =
|
||||
dt_device_set_reserved_mem(mem_node, node_name, phandle, mapping->iova, mapping->size);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = dt_device_add_mem_region(path, mem_phandle, NULL);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
node = fdt_path_offset(dt, path);
|
||||
if (node < 0)
|
||||
bail("DT: '%s' not found\n", path);
|
||||
|
||||
for (int i = 0; i < sio_num_fwparams; i++) {
|
||||
struct sio_fwparam *param = &sio_fwparams[i];
|
||||
|
||||
if (fdt_appendprop_u32(dt, node, "apple,sio-firmware-params", param->key))
|
||||
bail("DT: couldn't append to SIO parameters\n");
|
||||
|
||||
if (fdt_appendprop_u32(dt, node, "apple,sio-firmware-params", param->value))
|
||||
bail("DT: couldn't append to SIO parameters\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dt_disable_missing_devs(const char *adt_prefix, const char *dt_prefix, int max_devs)
|
||||
{
|
||||
int ret = -1;
|
||||
|
@ -2034,6 +2101,8 @@ int kboot_prepare_dt(void *fdt)
|
|||
return -1;
|
||||
if (dt_reserve_asc_firmware("/arm-io/sio", "/soc/sio"))
|
||||
return -1;
|
||||
if (dt_set_sio_fwdata())
|
||||
return -1;
|
||||
#ifndef RELEASE
|
||||
if (dt_transfer_virtios())
|
||||
return 1;
|
||||
|
|
222
src/sio.c
Normal file
222
src/sio.c
Normal file
|
@ -0,0 +1,222 @@
|
|||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#include "adt.h"
|
||||
#include "errno.h"
|
||||
#include "malloc.h"
|
||||
#include "sio.h"
|
||||
#include "types.h"
|
||||
#include "utils.h"
|
||||
|
||||
// Reuse pages for different data sections, if space allows it
|
||||
#define MERGE_SIO_FWDATA
|
||||
|
||||
#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)
|
||||
{
|
||||
if (sio_num_fwdata >= MAX_FWDATA)
|
||||
return NULL;
|
||||
|
||||
struct sio_mapping *mapping = &sio_fwdata[sio_num_fwdata];
|
||||
|
||||
#ifdef MERGE_SIO_FWDATA
|
||||
if (sio_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;
|
||||
else
|
||||
mapping->iova = *iova = ALIGN_UP((mapping - 1)->iova + (mapping - 1)->size, SZ_16K);
|
||||
mapping->size = ALIGN_UP(size, SZ_4K);
|
||||
mapping->phys = (u64)memalign(SZ_16K, ALIGN_UP(size, SZ_16K));
|
||||
memset64((void *)mapping->phys, 0, ALIGN_UP(mapping->size, SZ_16K));
|
||||
|
||||
done:
|
||||
return (void *)((*iova - mapping->iova) + mapping->phys);
|
||||
}
|
||||
|
||||
static void mapping_fixup(void)
|
||||
{
|
||||
for (int i = 0; i < sio_num_fwdata; i++) {
|
||||
struct sio_mapping *mapping = &sio_fwdata[i];
|
||||
mapping->size = ALIGN_UP(mapping->size, SZ_16K);
|
||||
}
|
||||
}
|
||||
|
||||
static void *add_fwdata(size_t size, u32 param_id)
|
||||
{
|
||||
if (sio_num_fwparams + 1 >= MAX_FWPARAMS)
|
||||
return NULL;
|
||||
|
||||
u64 iova;
|
||||
void *p = alloc_mapped_data(size, &iova);
|
||||
|
||||
struct sio_fwparam *param = &sio_fwparams[sio_num_fwparams];
|
||||
param->key = param_id;
|
||||
param->value = iova >> 12;
|
||||
param++;
|
||||
param->key = param_id + 1;
|
||||
param->value = size;
|
||||
sio_num_fwparams += 2;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
int sio_setup_fwdata(void)
|
||||
{
|
||||
int ret = -ENOMEM;
|
||||
u32 len;
|
||||
|
||||
if (sio_fwdata)
|
||||
return 0;
|
||||
|
||||
sio_fwdata = calloc(MAX_FWDATA, sizeof(*sio_fwdata));
|
||||
if (!sio_fwdata)
|
||||
return -ENOMEM;
|
||||
sio_num_fwdata = 0;
|
||||
|
||||
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");
|
||||
if (node < 0) {
|
||||
printf("%s: missing node\n", __func__);
|
||||
goto err_inval;
|
||||
}
|
||||
|
||||
{
|
||||
const u8 *prop = adt_getprop(adt, node, "asio-ascwrap-tunables", &len);
|
||||
u8 *asio_tunables = add_fwdata(len, 0x1e);
|
||||
if (!asio_tunables)
|
||||
goto err_nomem;
|
||||
memcpy8(asio_tunables, (void *)prop, len);
|
||||
}
|
||||
|
||||
u8 *unk_0b = add_fwdata(0x1b80, 0xb);
|
||||
if (!unk_0b)
|
||||
goto err_nomem;
|
||||
u8 *unk_0f = add_fwdata(0x1e000, 0xf); // crash dump memory
|
||||
if (!unk_0f)
|
||||
goto err_nomem;
|
||||
u8 *unk_ep3_0d = add_fwdata(0x4000, 0x30d); // peformance endpoint? FIFO?
|
||||
if (!unk_ep3_0d)
|
||||
goto err_nomem;
|
||||
|
||||
{
|
||||
u8 *map_range = add_fwdata(0x50, 0x1a);
|
||||
if (!map_range)
|
||||
goto err_nomem;
|
||||
const u32 *prop = adt_getprop(adt, node, "map-range", &len);
|
||||
if (len != 20 || prop[0] != (u32)SIO_KEY(MISC)) {
|
||||
printf("%s: bad 'map-range' property (%d, %x)\n", __func__, len, prop[0]);
|
||||
goto err_inval;
|
||||
}
|
||||
memcpy8(map_range + 48, (void *)(prop + 1), 16);
|
||||
}
|
||||
|
||||
{
|
||||
u8 *dmashim = add_fwdata(0xa0, 0x22);
|
||||
if (!dmashim)
|
||||
goto err_nomem;
|
||||
const u32 *prop = adt_getprop(adt, node, "dmashim", &len);
|
||||
for (; len >= 36; len -= 36) {
|
||||
switch (prop[0]) {
|
||||
case SIO_KEY(SSPI):
|
||||
memcpy8(dmashim, (void *)(prop + 1), 32);
|
||||
break;
|
||||
|
||||
case SIO_KEY(SUAR):
|
||||
memcpy8(dmashim + 32, (void *)(prop + 1), 32);
|
||||
break;
|
||||
|
||||
case SIO_KEY(SAUD):
|
||||
memcpy8(dmashim + 64, (void *)(prop + 1), 32);
|
||||
break;
|
||||
|
||||
case SIO_KEY(ADMA):
|
||||
break;
|
||||
|
||||
case SIO_KEY(AAUD):
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("%s: unknown 'dmashim' entry %x\n", __func__, prop[0]);
|
||||
};
|
||||
|
||||
prop += 9;
|
||||
}
|
||||
}
|
||||
|
||||
{ // it seems 'device_type' must go after 'dmashim'
|
||||
u8 *device_type = add_fwdata(0x40, 0x1c);
|
||||
if (!device_type)
|
||||
goto err_nomem;
|
||||
const u32 *prop = adt_getprop(adt, node, "device-type", &len);
|
||||
for (; len >= 12; len -= 12) {
|
||||
switch (prop[0]) {
|
||||
case SIO_KEY(dSPI):
|
||||
memcpy8(device_type, (void *)(prop + 1), 8);
|
||||
break;
|
||||
|
||||
case SIO_KEY(dUAR):
|
||||
memcpy8(device_type + 8, (void *)(prop + 1), 8);
|
||||
break;
|
||||
|
||||
case SIO_KEY(dMCA):
|
||||
memcpy8(device_type + 16, (void *)(prop + 1), 8);
|
||||
break;
|
||||
|
||||
case SIO_KEY(dDPA):
|
||||
memcpy8(device_type + 24, (void *)(prop + 1), 8);
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("%s: unknown 'device-type' entry %x\n", __func__, prop[0]);
|
||||
};
|
||||
|
||||
prop += 3;
|
||||
}
|
||||
}
|
||||
|
||||
mapping_fixup();
|
||||
|
||||
return 0;
|
||||
|
||||
err_inval:
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
err_nomem:
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
|
||||
err:
|
||||
for (int i = 0; i < MAX_FWDATA; i++) {
|
||||
if (!sio_fwdata[i].size)
|
||||
break;
|
||||
free((void *)sio_fwdata[i].phys);
|
||||
}
|
||||
free(sio_fwdata);
|
||||
free(sio_fwparams);
|
||||
sio_fwdata = NULL;
|
||||
sio_fwparams = NULL;
|
||||
|
||||
return ret;
|
||||
}
|
24
src/sio.h
Normal file
24
src/sio.h
Normal file
|
@ -0,0 +1,24 @@
|
|||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SIO_H
|
||||
#define SIO_H
|
||||
|
||||
struct sio_mapping {
|
||||
u64 phys;
|
||||
u64 iova;
|
||||
u64 size;
|
||||
};
|
||||
|
||||
struct sio_fwparam {
|
||||
u32 key;
|
||||
u32 value;
|
||||
};
|
||||
|
||||
extern int sio_num_fwdata;
|
||||
extern struct sio_mapping *sio_fwdata;
|
||||
extern int sio_num_fwparams;
|
||||
extern struct sio_fwparam *sio_fwparams;
|
||||
|
||||
int sio_setup_fwdata(void);
|
||||
|
||||
#endif
|
Loading…
Reference in a new issue