lede/target/linux/silicon/patches-5.19/0160-cpufreq-apple-soc-Add-T8112-support.patch

181 lines
5.8 KiB
Diff

From 0aea6b8ab572e33f5149915c7ae8259be48042e8 Mon Sep 17 00:00:00 2001
From: Hector Martin <marcan@marcan.st>
Date: Mon, 27 Jun 2022 21:51:01 +0900
Subject: [PATCH 160/171] cpufreq: apple-soc: Add T8112 support
Apple ran out of bits for the pstates in one of the registers, so we
unfortunately need SoC-specific tweaks now.
Signed-off-by: Hector Martin <marcan@marcan.st>
---
drivers/cpufreq/apple-soc-cpufreq.c | 91 ++++++++++++++++++++++++-----
1 file changed, 77 insertions(+), 14 deletions(-)
diff --git a/drivers/cpufreq/apple-soc-cpufreq.c b/drivers/cpufreq/apple-soc-cpufreq.c
index 191eaae71744..a92f7e7c57b5 100644
--- a/drivers/cpufreq/apple-soc-cpufreq.c
+++ b/drivers/cpufreq/apple-soc-cpufreq.c
@@ -23,19 +23,28 @@
#include <linux/pm_opp.h>
#include <linux/slab.h>
+#define APPLE_DVFS_PSTATE_BITS_T8103 4
+#define APPLE_DVFS_PSTATE_BITS_T8112 5
+
#define APPLE_DVFS_CMD 0x20
#define APPLE_DVFS_CMD_BUSY BIT(31)
#define APPLE_DVFS_CMD_SET BIT(25)
-#define APPLE_DVFS_CMD_PS2 GENMASK(15, 12)
-#define APPLE_DVFS_CMD_PS1 GENMASK(3, 0)
+#define APPLE_DVFS_CMD_PS2 GENMASK(16, 12)
+#define APPLE_DVFS_CMD_PS1 GENMASK(4, 0)
/* Same timebase as CPU counter (24MHz) */
#define APPLE_DVFS_LAST_CHG_TIME 0x38
-#define APPLE_DVFS_STATUS 0x50
-#define APPLE_DVFS_STATUS_CUR_PS GENMASK(7, 4)
-#define APPLE_DVFS_STATUS_TGT_PS GENMASK(3, 0)
-
+/*
+ * Apple ran out of bits and had to shift this in T8112...
+ */
+#define APPLE_DVFS_STATUS 0x50
+#define APPLE_DVFS_STATUS_CUR_PS_T8103 GENMASK(7, 4)
+#define APPLE_DVFS_STATUS_CUR_PS_SHIFT_T8103 4
+#define APPLE_DVFS_STATUS_TGT_PS_T8103 GENMASK(3, 0)
+#define APPLE_DVFS_STATUS_CUR_PS_T8112 GENMASK(9, 5)
+#define APPLE_DVFS_STATUS_CUR_PS_SHIFT_T8112 5
+#define APPLE_DVFS_STATUS_TGT_PS_T8112 GENMASK(4, 0)
/*
* Div is +1, base clock is 12MHz on existing SoCs.
* For documentation purposes. We use the OPP table to
@@ -46,14 +55,16 @@
#define APPLE_DVFS_PLL_FACTOR_MULT GENMASK(31, 16)
#define APPLE_DVFS_PLL_FACTOR_DIV GENMASK(15, 0)
-struct apple_cpu_priv {
- struct device *cpu_dev;
- void __iomem *reg_base;
+struct apple_soc_cpufreq_info {
+ u64 max_pstate;
+ u64 cur_pstate_mask;
+ u64 cur_pstate_shift;
};
-struct apple_soc_cpufreq_priv {
- struct device *dev;
+struct apple_cpu_priv {
+ struct device *cpu_dev;
void __iomem *reg_base;
+ const struct apple_soc_cpufreq_info *info;
};
#define APPLE_DVFS_TRANSITION_TIMEOUT 100
@@ -64,10 +75,21 @@ static unsigned int apple_soc_cpufreq_get_rate(unsigned int cpu)
{
struct cpufreq_policy *policy = cpufreq_cpu_get_raw(cpu);
struct apple_cpu_priv *priv = policy->driver_data;
- u64 reg = readq_relaxed(priv->reg_base + APPLE_DVFS_STATUS);
- unsigned int pstate = FIELD_GET(APPLE_DVFS_STATUS_CUR_PS, reg);
+ unsigned int pstate;
unsigned int i;
+ if (priv->info->cur_pstate_mask) {
+ u64 reg = readq_relaxed(priv->reg_base + APPLE_DVFS_STATUS);
+ pstate = (reg & priv->info->cur_pstate_mask) >> priv->info->cur_pstate_shift;
+ } else {
+ /*
+ * For the fallback case we might not know the layout of DVFS_STATUS,
+ * so just use the command register value (which ignores boost limitations).
+ */
+ u64 reg = readq_relaxed(priv->reg_base + APPLE_DVFS_CMD);
+ pstate = FIELD_GET(APPLE_DVFS_CMD_PS1, reg);
+ }
+
for (i = 0; policy->freq_table[i].frequency != CPUFREQ_TABLE_END; i++)
if (policy->freq_table[i].driver_data == pstate)
return policy->freq_table[i].frequency;
@@ -84,6 +106,10 @@ static int apple_soc_cpufreq_set_target(struct cpufreq_policy *policy,
unsigned int pstate = policy->freq_table[index].driver_data;
u64 reg;
+ /* Fallback for newer SoCs */
+ if (index > priv->info->max_pstate)
+ index = priv->info->max_pstate;
+
if (readq_poll_timeout_atomic(priv->reg_base + APPLE_DVFS_CMD, reg,
!(reg & APPLE_DVFS_CMD_BUSY), 2,
APPLE_DVFS_TRANSITION_TIMEOUT)) {
@@ -171,6 +197,7 @@ static int apple_soc_cpufreq_init(struct cpufreq_policy *policy)
struct device *cpu_dev;
struct apple_cpu_priv *priv;
struct cpufreq_frequency_table *freq_table;
+ struct platform_device *pdev = cpufreq_get_driver_data();
cpu_dev = get_cpu_device(policy->cpu);
if (!cpu_dev) {
@@ -209,6 +236,12 @@ static int apple_soc_cpufreq_init(struct cpufreq_policy *policy)
goto out_free_opp;
}
+ priv->info = of_device_get_match_data(&pdev->dev);
+ if (!priv->info) {
+ ret = -ENODEV;
+ goto out_free_opp;
+ }
+
ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table);
if (ret) {
dev_err(cpu_dev, "failed to init cpufreq table: %d\n", ret);
@@ -295,6 +328,8 @@ static int apple_soc_cpufreq_probe(struct platform_device *pdev)
{
int ret;
+ apple_soc_cpufreq_driver.driver_data = pdev;
+
ret = cpufreq_register_driver(&apple_soc_cpufreq_driver);
if (ret)
return dev_err_probe(&pdev->dev, ret, "registering cpufreq failed\n");
@@ -309,8 +344,36 @@ static int apple_soc_cpufreq_remove(struct platform_device *pdev)
return 0;
}
+const struct apple_soc_cpufreq_info soc_t8103_info = {
+ .max_pstate = 15,
+ .cur_pstate_mask = APPLE_DVFS_STATUS_CUR_PS_T8103,
+ .cur_pstate_shift = APPLE_DVFS_STATUS_CUR_PS_SHIFT_T8103,
+};
+
+const struct apple_soc_cpufreq_info soc_t8112_info = {
+ .max_pstate = 31,
+ .cur_pstate_mask = APPLE_DVFS_STATUS_CUR_PS_T8112,
+ .cur_pstate_shift = APPLE_DVFS_STATUS_CUR_PS_SHIFT_T8112,
+};
+
+const struct apple_soc_cpufreq_info soc_default_info = {
+ .max_pstate = 15,
+ .cur_pstate_mask = 0, /* fallback */
+};
+
static const struct of_device_id apple_soc_cpufreq_of_match[] = {
- { .compatible = "apple,soc-cpufreq" },
+ {
+ .compatible = "apple,t8103-soc-cpufreq",
+ .data = &soc_t8103_info,
+ },
+ {
+ .compatible = "apple,t8112-cpufreq",
+ .data = &soc_t8112_info,
+ },
+ {
+ .compatible = "apple,soc-cpufreq",
+ .data = &soc_default_info,
+ },
{}
};
MODULE_DEVICE_TABLE(of, apple_soc_cpufreq_of_match);
--
2.34.1