mirror of
https://github.com/coolsnowwolf/lede.git
synced 2025-07-16 12:46:59 +08:00
181 lines
5.8 KiB
Diff
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
|
|
|