Merge branch 'pulls/286' into m2_dptx

This commit is contained in:
Janne Grunau 2023-03-31 18:03:57 +02:00
commit e029c588c0
7 changed files with 444 additions and 19 deletions

View file

@ -119,6 +119,7 @@ OBJECTS := \
rtkit.o \
sart.o \
sep.o \
sio.o \
smp.o \
start.o \
startup.o \

View file

@ -399,12 +399,7 @@ int display_configure(const char *config)
return -1;
}
cur_boot_args.mem_size -= size;
fb_pa = cur_boot_args.phys_base + cur_boot_args.mem_size;
/* add guard page between RAM and framebuffer */
// TODO: update mapping?
cur_boot_args.mem_size -= SZ_16K;
fb_pa = top_of_memory_alloc(size);
memset((void *)fb_pa, 0, size);
tmp_dva = iova_alloc(dcp->iovad_dcp, size);

View file

@ -14,6 +14,7 @@
#include "pcie.h"
#include "pmgr.h"
#include "sep.h"
#include "sio.h"
#include "smp.h"
#include "types.h"
#include "usb.h"
@ -1155,18 +1156,14 @@ static u64 dart_get_mapping(dart_dev_t *dart, const char *path, u64 paddr, size_
return iova;
}
static int dt_device_set_reserved_mem(int node, dart_dev_t *dart, const char *name,
uint32_t phandle, u64 paddr, u64 size)
static int dt_device_set_reserved_mem(int node, const char *name, uint32_t phandle, u64 iova,
u64 size)
{
int ret;
u64 iova = dart_get_mapping(dart, name, paddr, size);
if (DART_IS_ERR(iova))
bail("ADT: no mapping found for '%s' 0x%012lx iova:0x%08lx)\n", name, paddr, iova);
ret = fdt_appendprop_u32(dt, node, "iommu-addresses", phandle);
if (ret != 0)
bail("DT: could not append phandle '%s.compatible' property: %d\n", name, ret);
bail("DT: could not append phandle to '%s.iommu-addresses' property: %d\n", name, ret);
ret = fdt_appendprop_u64(dt, node, "iommu-addresses", iova);
if (ret != 0)
@ -1179,6 +1176,16 @@ static int dt_device_set_reserved_mem(int node, dart_dev_t *dart, const char *na
return 0;
}
static int dt_device_set_reserved_mem_from_dart(int node, dart_dev_t *dart, const char *name,
uint32_t phandle, u64 paddr, u64 size)
{
u64 iova = dart_get_mapping(dart, name, paddr, size);
if (DART_IS_ERR(iova))
bail("ADT: no mapping found for '%s' 0x%012lx iova:0x%08lx)\n", name, paddr, iova);
return dt_device_set_reserved_mem(node, name, phandle, iova, size);
}
static int dt_get_or_add_reserved_mem(const char *node_name, const char *compat, u64 paddr,
size_t size)
{
@ -1235,6 +1242,9 @@ static int dt_device_add_mem_region(const char *alias, uint32_t phandle, const c
if (dev_node < 0)
bail("DT: failed to update node for alias '%s'\n", alias);
if (!name)
return 0;
ret = fdt_appendprop_string(dt, dev_node, "memory-region-names", name);
if (ret != 0)
bail("DT: failed to append to 'memory-region-names' property\n");
@ -1350,20 +1360,20 @@ static int dt_add_reserved_regions(const char *dcp_alias, const char *disp_alias
uint32_t mem_phandle = fdt_get_phandle(dt, mem_node);
if (maps[i].map_dcp && dart_dcp) {
ret = dt_device_set_reserved_mem(mem_node, dart_dcp, node_name, dcp_phandle,
region[i].paddr, region[i].size);
ret = dt_device_set_reserved_mem_from_dart(mem_node, dart_dcp, node_name, dcp_phandle,
region[i].paddr, region[i].size);
if (ret != 0)
goto err;
}
if (maps[i].map_disp && dart_disp) {
ret = dt_device_set_reserved_mem(mem_node, dart_disp, node_name, disp_phandle,
region[i].paddr, region[i].size);
ret = dt_device_set_reserved_mem_from_dart(mem_node, dart_disp, node_name, disp_phandle,
region[i].paddr, region[i].size);
if (ret != 0)
goto err;
}
if (maps[i].map_piodma && dart_piodma) {
ret = dt_device_set_reserved_mem(mem_node, dart_piodma, node_name, piodma_phandle,
region[i].paddr, region[i].size);
ret = dt_device_set_reserved_mem_from_dart(
mem_node, dart_piodma, node_name, piodma_phandle, region[i].paddr, region[i].size);
if (ret != 0)
goto err;
}
@ -1490,6 +1500,61 @@ static int dt_vram_reserved_region(const char *dcp_alias, const char *disp_alias
disp_reserved_regions_vram, &region, 1);
}
static int dt_reserve_asc_firmware(const char *adt_path, const char *fdt_path)
{
int ret = 0;
int fdt_node = fdt_path_offset(dt, fdt_path);
if (fdt_node < 0) {
printf("DT: '%s' not found\n", fdt_path);
return 0;
}
int node = adt_path_offset(adt, adt_path);
if (node < 0)
bail("ADT: '%s' not found\n", adt_path);
uint32_t dev_phandle = fdt_get_phandle(dt, fdt_node);
if (!dev_phandle) {
ret = fdt_generate_phandle(dt, &dev_phandle);
if (!ret)
ret = fdt_setprop_u32(dt, fdt_node, "phandle", dev_phandle);
if (ret != 0)
bail("DT: couldn't set '%s.phandle' property: %d\n", fdt_path, ret);
}
const uint64_t *segments;
u32 segments_len;
segments = adt_getprop(adt, node, "segment-ranges", &segments_len);
unsigned int num_maps = segments_len / 32;
for (unsigned i = 0; i < num_maps; i++) {
u64 paddr = segments[0];
u64 iova = segments[2];
u32 size = segments[3];
segments += 4;
char node_name[64];
snprintf(node_name, sizeof(node_name), "asc-firmware@%lx", paddr);
int mem_node = dt_get_or_add_reserved_mem(node_name, "apple,asc-mem", paddr, size);
if (mem_node < 0)
return ret;
uint32_t mem_phandle = fdt_get_phandle(dt, mem_node);
ret = dt_device_set_reserved_mem(mem_node, node_name, dev_phandle, iova, size);
if (ret < 0)
return ret;
ret = dt_device_add_mem_region(fdt_path, mem_phandle, NULL);
if (ret < 0)
return ret;
}
return 0;
}
static struct disp_mapping disp_reserved_regions_t8103[] = {
{"region-id-50", "dcp_data", true, false, false},
{"region-id-57", "region57", true, false, false},
@ -1626,6 +1691,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;
@ -1934,6 +2065,10 @@ 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", "/soc/sio"))
return -1;
if (dt_set_sio_fwdata())
return -1;
#ifndef RELEASE
if (dt_transfer_virtios())
return 1;

249
src/sio.c Normal file
View file

@ -0,0 +1,249 @@
/* 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 = top_of_memory_alloc(size);
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;
}
#define PARAM_UNK_000b 0x000b
#define PARAM_PANIC_BUFFER 0x000f
#define PARAM_MAP_RANGE 0x001a
#define PARAM_DEVICE_TYPE 0x001c
#define PARAM_TUNABLES 0x001e
#define PARAM_DMASHIM_DATA 0x0022
#define PARAM_UNK_030d 0x030d
struct copy_rule {
const char *prop;
int fw_param;
bool keyed;
int blobsize;
u32 nkeys;
const char *keys[9];
};
#define SPACER "\xff\xff\xff\xff"
struct copy_rule copy_rules[] = {
{
.prop = "asio-ascwrap-tunables",
.fw_param = PARAM_TUNABLES,
},
{
.blobsize = 0x1b80,
.fw_param = PARAM_UNK_000b,
},
{
.blobsize = 0x1e000,
.fw_param = PARAM_PANIC_BUFFER,
},
{
// peformance endpoint? FIFO?
.blobsize = 0x4000,
.fw_param = PARAM_UNK_030d,
},
{
.prop = "map-range",
.fw_param = PARAM_MAP_RANGE,
.blobsize = 16,
.keyed = true,
.keys = {SPACER, SPACER, SPACER, "MISC", NULL},
},
{
.prop = "dmashim",
.fw_param = PARAM_DMASHIM_DATA,
.blobsize = 32,
.keyed = true,
.keys = {"SSPI", "SUAR", "SAUD", "ADMA", "AAUD", NULL},
},
{
// it seems 'device_type' must go after 'dmashim'
.prop = "device-type",
.fw_param = PARAM_DEVICE_TYPE,
.blobsize = 8,
.keyed = true,
.keys = {"dSPI", "dUAR", "dMCA", "dDPA", "dPDM", "dALE", "dAMC", "dAPD", NULL},
},
};
int find_key_index(const char *keylist[], u32 needle)
{
int i;
for (i = 0; keylist[i]; i++) {
const char *s = keylist[i];
u32 key = ((u32)s[0]) << 24 | ((u32)s[1]) << 16 | ((u32)s[2]) << 8 | s[3];
if (key == needle)
break;
}
return i;
}
int sio_setup_fwdata(void)
{
int ret = -ENOMEM;
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;
}
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;
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;
}
if (!rule->keyed) {
u8 *sio_blob = add_fwdata(len, rule->fw_param);
if (!sio_blob)
goto err_nomem;
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);
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);
}
for (u32 off = 0; off + rule->blobsize <= len; off += (rule->blobsize + 4)) {
const u8 *p = &adt_blob[off];
u32 key = *((u32 *)p);
int key_idx = find_key_index(rule->keys, key);
if (key_idx >= nkeys) {
printf("%s: unknown key %x found in ADT property '%s'\n", __func__, key,
rule->prop);
goto err_inval;
}
memcpy8(sio_blob + (key_idx * rule->blobsize), (void *)(p + 4), rule->blobsize);
}
}
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;
// 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;
return ret;
}

24
src/sio.h Normal file
View 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

View file

@ -180,3 +180,23 @@ bool is_heap(void *addr)
return p > top_of_kernel_data && p < top_of_ram;
}
// TODO: update mapping?
u64 top_of_memory_alloc(size_t size)
{
static bool guard_page_inserted = false;
cur_boot_args.mem_size -= ALIGN_UP(size, SZ_16K);
u64 ret = cur_boot_args.phys_base + cur_boot_args.mem_size;
if (!guard_page_inserted) {
cur_boot_args.mem_size -= SZ_16K;
guard_page_inserted = true;
} else {
// If the guard page was already there, move it down and allocate
// above it -- this is accomplished by simply shifting the allocated
// region by one page up.
ret += SZ_16K;
}
return ret;
}

View file

@ -440,5 +440,6 @@ extern struct vector_args next_stage;
void deep_wfi(void);
bool is_heap(void *addr);
u64 top_of_memory_alloc(size_t size);
#endif