diff options
Diffstat (limited to 'tools/src/cpufreq.c')
| -rw-r--r-- | tools/src/cpufreq.c | 120 |
1 files changed, 120 insertions, 0 deletions
diff --git a/tools/src/cpufreq.c b/tools/src/cpufreq.c new file mode 100644 index 0000000..e7c4f41 --- /dev/null +++ b/tools/src/cpufreq.c @@ -0,0 +1,120 @@ +/* SPDX-License-Identifier: MIT */ + +#include "cpufreq.h" +#include "adt.h" +#include "soc.h" +#include "utils.h" + +#define CLUSTER_PSTATE 0x20 +#define CLUSTER_CONFIG 0x6b8 + +#define CLUSTER_PSTATE_BUSY BIT(31) +#define CLUSTER_PSTATE_SET BIT(25) +#define CLUSTER_PSTATE_DESIRED2 GENMASK(15, 12) +#define CLUSTER_PSTATE_DESIRED1 GENMASK(3, 0) + +#define CLUSTER_CONFIG_ENABLE BIT(63) +#define CLUSTER_CONFIG_DVMR1 BIT(32) +#define CLUSTER_CONFIG_DVMR2 BIT(31) + +#define CLUSTER_SWITCH_TIMEOUT 100 + +struct cluster_t { + const char *name; + u64 base; + bool dvmr; + uint32_t boot_pstate; +}; + +int cpufreq_init_cluster(const struct cluster_t *cluster) +{ + u64 enable = CLUSTER_CONFIG_ENABLE; + if (cluster->dvmr) + enable |= CLUSTER_CONFIG_DVMR1 | CLUSTER_CONFIG_DVMR2; + + u64 val = read64(cluster->base + CLUSTER_CONFIG); + if ((val & enable) != enable) { + printf("cpufreq: Configuring cluster %s (dvmr: %d)\n", cluster->name, cluster->dvmr); + write64(cluster->base + CLUSTER_CONFIG, val | enable); + } + + val = read64(cluster->base + CLUSTER_PSTATE); + + if (FIELD_GET(CLUSTER_PSTATE_DESIRED1, val) != cluster->boot_pstate) { + val &= CLUSTER_PSTATE_DESIRED1 | CLUSTER_PSTATE_DESIRED2; + val |= CLUSTER_PSTATE_SET | FIELD_PREP(CLUSTER_PSTATE_DESIRED1, cluster->boot_pstate) | + FIELD_PREP(CLUSTER_PSTATE_DESIRED2, cluster->boot_pstate); + printf("cpufreq: Switching cluster %s to P-State %d\n", cluster->name, + cluster->boot_pstate); + write64(cluster->base + CLUSTER_PSTATE, val); + if (poll32(cluster->base + CLUSTER_PSTATE, CLUSTER_PSTATE_BUSY, 0, CLUSTER_SWITCH_TIMEOUT) < + 0) { + printf("cpufreq: Timed out waiting for cluster %s P-State switch\n", cluster->name); + return -1; + } + } + + return 0; +} + +static const struct cluster_t t8103_clusters[] = { + {"ECPU", 0x210e20000, false, 5}, + {"PCPU", 0x211e20000, true, 7}, + {}, +}; + +static const struct cluster_t t6000_clusters[] = { + {"ECPU0", 0x210e20000, false, 5}, + {"PCPU0", 0x211e20000, false, 7}, + {"PCPU1", 0x212e20000, false, 7}, + {}, +}; + +static const struct cluster_t t6002_clusters[] = { + {"ECPU0", 0x0210e20000, false, 5}, + {"PCPU0", 0x0211e20000, false, 7}, + {"PCPU1", 0x0212e20000, false, 7}, + {"ECPU1", 0x2210e20000, false, 5}, + {"PCPU2", 0x2211e20000, false, 7}, + {"PCPU3", 0x2212e20000, false, 7}, + {}, +}; + +static const struct cluster_t t8112_clusters[] = { + {"ECPU", 0x210e20000, false, 7}, + {"PCPU", 0x211e20000, true, 6}, + {}, +}; + +int cpufreq_init(void) +{ + printf("cpufreq: Initializing clusters\n"); + + const struct cluster_t *cluster; + + switch (chip_id) { + case T8103: + cluster = t8103_clusters; + break; + case T6000: + case T6001: + cluster = t6000_clusters; + break; + case T6002: + cluster = t6002_clusters; + break; + case T8112: + cluster = t8112_clusters; + break; + default: + printf("cpufreq: Chip 0x%x is unsupported\n", chip_id); + return -1; + } + + bool err = false; + while (cluster->base) { + err |= cpufreq_init_cluster(cluster++); + } + + return err ? -1 : 0; +} |
