From 4a6a4c0376f36fb86a88cc1b56950af702479c18 Mon Sep 17 00:00:00 2001 From: Asahi Lina Date: Fri, 21 Oct 2022 21:56:00 +0900 Subject: [PATCH] kboot: Add initial GPU property forwarding Signed-off-by: Asahi Lina --- Makefile | 2 +- src/kboot.c | 4 ++ src/kboot_gpu.c | 135 ++++++++++++++++++++++++++++++++++++++++++++++++ src/utils.h | 2 + 4 files changed, 142 insertions(+), 1 deletion(-) create mode 100644 src/kboot_gpu.c diff --git a/Makefile b/Makefile index b9a809ff..fcfad325 100644 --- a/Makefile +++ b/Makefile @@ -100,7 +100,7 @@ OBJECTS := \ i2c.o \ iodev.o \ iova.o \ - kboot.o \ + kboot.o kboot_gpu.o \ main.o \ mcc.o \ memory.o memory_asm.o \ diff --git a/src/kboot.c b/src/kboot.c index 965fb0ee..903f9785 100644 --- a/src/kboot.c +++ b/src/kboot.c @@ -33,6 +33,8 @@ static void *initrd_start = NULL; static size_t initrd_size = 0; static char *chosen_params[MAX_CHOSEN_PARAMS][2]; +int dt_set_gpu(void *dt); + #define DT_ALIGN 16384 #define bail(...) \ @@ -1528,6 +1530,8 @@ int kboot_prepare_dt(void *fdt) return -1; if (dt_set_display()) return -1; + if (dt_set_gpu(dt)) + return -1; if (dt_disable_missing_devs("usb-drd", "usb@", 8)) return -1; if (dt_disable_missing_devs("i2c", "i2c@", 8)) diff --git a/src/kboot_gpu.c b/src/kboot_gpu.c new file mode 100644 index 00000000..300a4343 --- /dev/null +++ b/src/kboot_gpu.c @@ -0,0 +1,135 @@ +/* SPDX-License-Identifier: MIT */ + +#include "kboot.h" +#include "adt.h" +#include "assert.h" +#include "soc.h" +#include "utils.h" + +#include "libfdt/libfdt.h" + +#define bail(...) \ + do { \ + printf(__VA_ARGS__); \ + return -1; \ + } while (0) + +u32 t8103_pwr_scale[] = {0, 63, 80, 108, 150, 198, 210}; + +static int dt_set_region(void *dt, int sgx, const char *name, const char *path) +{ + u64 base, size; + char prop[64]; + + snprintf(prop, sizeof(prop), "%s-base", name); + if (ADT_GETPROP(adt, sgx, prop, &base) < 0 || !base) + bail("ADT: GPU: failed to find %s property\n", prop); + + snprintf(prop, sizeof(prop), "%s-size", name); + if (ADT_GETPROP(adt, sgx, prop, &size) < 0 || !base) + bail("ADT: GPU: failed to find %s property\n", prop); + + int node = fdt_path_offset(dt, path); + if (node < 0) + bail("FDT: GPU: failed to find %s node\n", path); + + fdt64_t reg[2]; + + fdt64_st(®[0], base); + fdt64_st(®[1], size); + + if (fdt_setprop_inplace(dt, node, "reg", reg, sizeof(reg))) + bail("FDT: GPU: failed to set reg prop for %s\n", path); + + return 0; +} + +int dt_set_gpu(void *dt) +{ + u32 *pwr_scale; + u32 pwr_scale_count; + switch (chip_id) { + case T8103: + pwr_scale = t8103_pwr_scale; + pwr_scale_count = ARRAY_SIZE(t8103_pwr_scale); + break; + default: + printf("ADT: GPU: unsupported chip!\n"); + return 0; + } + + int gpu = fdt_path_offset(dt, "gpu"); + if (gpu < 0) { + printf("FDT: GPU: gpu alias not found in device tree\n"); + return 0; + } + + int len; + const fdt32_t *opps_ph = fdt_getprop(dt, gpu, "operating-points-v2", &len); + if (!opps_ph || len != 4) + bail("FDT: GPU: operating-points-v2 not found\n"); + + int opps = fdt_node_offset_by_phandle(dt, fdt32_ld(opps_ph)); + if (opps < 0) + bail("FDT: GPU: node for phandle %u not found\n", fdt32_ld(opps_ph)); + + int sgx = adt_path_offset(adt, "/arm-io/sgx"); + if (sgx < 0) + bail("ADT: GPU: /arm-io/sgx node not found\n"); + + u32 perf_state_count; + if (ADT_GETPROP(adt, sgx, "perf-state-count", &perf_state_count) < 0 || !perf_state_count) + bail("ADT: GPU: missing perf-state-count\n"); + + if (perf_state_count != pwr_scale_count) + bail("ADT: GPU: expected %d perf states but got %d\n", pwr_scale_count, perf_state_count); + + u32 perf_states_len; + const struct { + u32 freq; + u32 volt; + } * perf_states; + + perf_states = adt_getprop(adt, sgx, "perf-states", &perf_states_len); + if (!perf_states || perf_states_len != sizeof(*perf_states) * perf_state_count) + bail("ADT: GPU: invalid perf-states length\n"); + + u64 max_pwr[16]; + + for (u32 i = 0; i < pwr_scale_count; i++) + max_pwr[i] = (u64)perf_states[i].volt * (u64)pwr_scale[i]; + + for (u32 i = 0; i < pwr_scale_count; i++) + max_pwr[i] = 100 * max_pwr[i] / max_pwr[pwr_scale_count - 1]; + + u32 i = 0; + int opp; + fdt_for_each_subnode(opp, dt, opps) + { + if (i >= perf_state_count) + bail("FDT: GPU: Expected %d operating points, but found more\n", perf_state_count); + + if (fdt_setprop_inplace_u32(dt, opp, "opp-microvolt", perf_states[i].volt * 1000)) + bail("FDT: GPU: Failed to set opp-microvolt for PS %d\n", i); + + if (fdt_setprop_inplace_u64(dt, opp, "opp-hz", perf_states[i].freq)) + bail("FDT: GPU: Failed to set opp-hz for PS %d\n", i); + + if (fdt_setprop_inplace_u32(dt, opp, "apple,opp-rel-power", max_pwr[i])) + bail("FDT: GPU: Failed to set apple,opp-rel-power for PS %d\n", i); + + i++; + } + + if (i != perf_state_count) + bail("FDT: GPU: Expected %d operating points, but found %d\n", perf_state_count, i); + + if (dt_set_region(dt, sgx, "gfx-handoff", "/reserved-memory/uat-handoff")) + return -1; + if (dt_set_region(dt, sgx, "gfx-shared-region", "/reserved-memory/uat-pagetables")) + return -1; + if (dt_set_region(dt, sgx, "gpu-region", "/reserved-memory/uat-ttbs")) + return -1; + + return 0; +} diff --git a/src/utils.h b/src/utils.h index 49fa5662..1d053d2e 100644 --- a/src/utils.h +++ b/src/utils.h @@ -15,6 +15,8 @@ } while (0) #endif +#define ARRAY_SIZE(s) (sizeof(s) / sizeof((s)[0])) + #define BIT(x) (1UL << (x)) #define MASK(x) (BIT(x) - 1) #define GENMASK(msb, lsb) ((BIT((msb + 1) - (lsb)) - 1) << (lsb))