diff --git a/src/kboot_gpu.c b/src/kboot_gpu.c index 300a4343..613d4cf9 100644 --- a/src/kboot_gpu.c +++ b/src/kboot_gpu.c @@ -14,8 +14,71 @@ return -1; \ } while (0) +#define MAX_PSTATES 16 +#define MAX_CLUSTERS 8 + +struct perf_state { + u32 freq; + u32 volt; +}; + u32 t8103_pwr_scale[] = {0, 63, 80, 108, 150, 198, 210}; +int calc_power_t8103(int sgx, u32 count, u32 table_count, const struct perf_state *perf_states, + u32 *max_pwr) +{ + UNUSED(sgx); + + u32 pwr_scale_count = ARRAY_SIZE(t8103_pwr_scale); + + if (table_count != 1) + bail("ADT: GPU: expected 1 perf state table but got %d\n", table_count); + + if (count != pwr_scale_count) + bail("ADT: GPU: expected %d perf states but got %d\n", pwr_scale_count, count); + + for (u32 i = 0; i < pwr_scale_count; i++) + max_pwr[i] = (u32)perf_states[i].volt * (u32)t8103_pwr_scale[i] * 100; + + return 0; +} + +u32 t6000_pwr_scale[] = {0, 15, 19, 25, 34, 50, 100}; + +int calc_power_t600x(int sgx, u32 count, u32 table_count, const struct perf_state *perf_states, + u32 *max_pwr) +{ + UNUSED(sgx); + UNUSED(perf_states); + + u32 nclusters = 0; + switch (chip_id) { + case T6000: + nclusters = 2; + break; + case T6001: + nclusters = 4; + break; + case T6002: + nclusters = 8; + break; + } + + u32 pwr_scale_count = ARRAY_SIZE(t6000_pwr_scale); + + if (table_count != nclusters) + bail("ADT: GPU: expected %d perf state tables but got %d\n", nclusters, table_count); + + if (count != pwr_scale_count) + bail("ADT: GPU: expected %d perf states but got %d\n", pwr_scale_count, count); + + for (u32 i = 0; i < pwr_scale_count; i++) { + max_pwr[i] = t6000_pwr_scale[i] * 1667430 * nclusters / 8; + } + + return 0; +} + static int dt_set_region(void *dt, int sgx, const char *name, const char *path) { u64 base, size; @@ -46,12 +109,17 @@ static int dt_set_region(void *dt, int sgx, const char *name, const char *path) int dt_set_gpu(void *dt) { - u32 *pwr_scale; - u32 pwr_scale_count; + int (*calc_power)(int sgx, u32 count, u32 table_count, const struct perf_state *perf, + u32 *max_pwr); + switch (chip_id) { case T8103: - pwr_scale = t8103_pwr_scale; - pwr_scale_count = ARRAY_SIZE(t8103_pwr_scale); + calc_power = calc_power_t8103; + break; + case T6000: + case T6001: + case T6002: + calc_power = calc_power_t600x; break; default: printf("ADT: GPU: unsupported chip!\n"); @@ -81,42 +149,52 @@ int dt_set_gpu(void *dt) 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_state_table_count; + if (ADT_GETPROP(adt, sgx, "perf-state-table-count", &perf_state_table_count) < 0 || + !perf_state_table_count) + bail("ADT: GPU: missing perf-state-table-count\n"); + + if (perf_state_count > MAX_PSTATES) + bail("ADT: GPU: perf-state-count too large\n"); + + if (perf_state_table_count > MAX_CLUSTERS) + bail("ADT: GPU: perf-state-table-count too large\n"); u32 perf_states_len; - const struct { - u32 freq; - u32 volt; - } * perf_states; + const struct perf_state *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) + if (!perf_states || + perf_states_len != sizeof(*perf_states) * perf_state_count * perf_state_table_count) bail("ADT: GPU: invalid perf-states length\n"); - u64 max_pwr[16]; + u32 max_pwr[MAX_PSTATES]; - 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]; + if (calc_power(sgx, perf_state_count, perf_state_table_count, perf_states, max_pwr)) + return -1; u32 i = 0; int opp; fdt_for_each_subnode(opp, dt, opps) { + fdt32_t volts[MAX_CLUSTERS]; + + for (u32 j = 0; j < perf_state_table_count; j++) { + volts[j] = cpu_to_fdt32(perf_states[i + j * perf_state_count].volt * 1000); + } + 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)) + if (fdt_setprop_inplace(dt, opp, "opp-microvolt", &volts, + sizeof(u32) * perf_state_table_count)) 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); + if (fdt_setprop_inplace_u32(dt, opp, "opp-microwatt", max_pwr[i])) + bail("FDT: GPU: Failed to set opp-microwatt for PS %d\n", i); i++; }