summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/cpufreq/mediatek-cpufreq.c82
1 files changed, 81 insertions, 1 deletions
diff --git a/drivers/cpufreq/mediatek-cpufreq.c b/drivers/cpufreq/mediatek-cpufreq.c
index 4c6d53c99d79..fe168338d651 100644
--- a/drivers/cpufreq/mediatek-cpufreq.c
+++ b/drivers/cpufreq/mediatek-cpufreq.c
@@ -22,6 +22,7 @@ struct mtk_cpufreq_platform_data {
int proc_max_volt;
int sram_min_volt;
int sram_max_volt;
+ bool ccifreq_supported;
};
/*
@@ -38,6 +39,7 @@ struct mtk_cpufreq_platform_data {
struct mtk_cpu_dvfs_info {
struct cpumask cpus;
struct device *cpu_dev;
+ struct device *cci_dev;
struct regulator *proc_reg;
struct regulator *sram_reg;
struct clk *cpu_clk;
@@ -45,6 +47,7 @@ struct mtk_cpu_dvfs_info {
struct list_head list_head;
int intermediate_voltage;
bool need_voltage_tracking;
+ int vproc_on_boot;
int pre_vproc;
/* Avoid race condition for regulators between notify and policy */
struct mutex reg_lock;
@@ -53,6 +56,7 @@ struct mtk_cpu_dvfs_info {
unsigned long current_freq;
const struct mtk_cpufreq_platform_data *soc_data;
int vtrack_max;
+ bool ccifreq_bound;
};
static struct platform_device *cpufreq_pdev;
@@ -171,6 +175,28 @@ static int mtk_cpufreq_set_voltage(struct mtk_cpu_dvfs_info *info, int vproc)
return ret;
}
+static bool is_ccifreq_ready(struct mtk_cpu_dvfs_info *info)
+{
+ struct device_link *sup_link;
+
+ if (info->ccifreq_bound)
+ return true;
+
+ sup_link = device_link_add(info->cpu_dev, info->cci_dev,
+ DL_FLAG_AUTOREMOVE_CONSUMER);
+ if (!sup_link) {
+ dev_err(info->cpu_dev, "cpu%d: sup_link is NULL\n", info->opp_cpu);
+ return false;
+ }
+
+ if (sup_link->supplier->links.status != DL_DEV_DRIVER_BOUND)
+ return false;
+
+ info->ccifreq_bound = true;
+
+ return true;
+}
+
static int mtk_cpufreq_set_target(struct cpufreq_policy *policy,
unsigned int index)
{
@@ -213,6 +239,14 @@ static int mtk_cpufreq_set_target(struct cpufreq_policy *policy,
dev_pm_opp_put(opp);
/*
+ * If MediaTek cci is supported but is not ready, we will use the value
+ * of max(target cpu voltage, booting voltage) to prevent high freqeuncy
+ * low voltage crash.
+ */
+ if (info->soc_data->ccifreq_supported && !is_ccifreq_ready(info))
+ vproc = max(vproc, info->vproc_on_boot);
+
+ /*
* If the new voltage or the intermediate voltage is higher than the
* current voltage, scale up voltage first.
*/
@@ -333,6 +367,23 @@ static int mtk_cpufreq_opp_notifier(struct notifier_block *nb,
return notifier_from_errno(ret);
}
+static struct device *of_get_cci(struct device *cpu_dev)
+{
+ struct device_node *np;
+ struct platform_device *pdev;
+
+ np = of_parse_phandle(cpu_dev->of_node, "mediatek,cci", 0);
+ if (IS_ERR_OR_NULL(np))
+ return NULL;
+
+ pdev = of_find_device_by_node(np);
+ of_node_put(np);
+ if (IS_ERR_OR_NULL(pdev))
+ return NULL;
+
+ return &pdev->dev;
+}
+
static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu)
{
struct device *cpu_dev;
@@ -347,6 +398,16 @@ static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu)
}
info->cpu_dev = cpu_dev;
+ info->ccifreq_bound = false;
+ if (info->soc_data->ccifreq_supported) {
+ info->cci_dev = of_get_cci(info->cpu_dev);
+ if (IS_ERR_OR_NULL(info->cci_dev)) {
+ ret = PTR_ERR(info->cci_dev);
+ dev_err(cpu_dev, "cpu%d: failed to get cci device\n", cpu);
+ return -ENODEV;
+ }
+ }
+
info->cpu_clk = clk_get(cpu_dev, "cpu");
if (IS_ERR(info->cpu_clk)) {
ret = PTR_ERR(info->cpu_clk);
@@ -410,6 +471,15 @@ static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu)
if (ret)
goto out_disable_mux_clock;
+ if (info->soc_data->ccifreq_supported) {
+ info->vproc_on_boot = regulator_get_voltage(info->proc_reg);
+ if (info->vproc_on_boot < 0) {
+ dev_err(info->cpu_dev,
+ "invalid Vproc value: %d\n", info->vproc_on_boot);
+ goto out_disable_inter_clock;
+ }
+ }
+
/* Search a safe voltage for intermediate frequency. */
rate = clk_get_rate(info->inter_clk);
opp = dev_pm_opp_find_freq_ceil(cpu_dev, &rate);
@@ -617,6 +687,16 @@ static const struct mtk_cpufreq_platform_data mt2701_platform_data = {
.proc_max_volt = 1150000,
.sram_min_volt = 0,
.sram_max_volt = 1150000,
+ .ccifreq_supported = false,
+};
+
+static const struct mtk_cpufreq_platform_data mt8183_platform_data = {
+ .min_volt_shift = 100000,
+ .max_volt_shift = 200000,
+ .proc_max_volt = 1150000,
+ .sram_min_volt = 0,
+ .sram_max_volt = 1150000,
+ .ccifreq_supported = true,
};
/* List of machines supported by this driver */
@@ -629,7 +709,7 @@ static const struct of_device_id mtk_cpufreq_machines[] __initconst = {
{ .compatible = "mediatek,mt817x", .data = &mt2701_platform_data },
{ .compatible = "mediatek,mt8173", .data = &mt2701_platform_data },
{ .compatible = "mediatek,mt8176", .data = &mt2701_platform_data },
- { .compatible = "mediatek,mt8183", .data = &mt2701_platform_data },
+ { .compatible = "mediatek,mt8183", .data = &mt8183_platform_data },
{ .compatible = "mediatek,mt8365", .data = &mt2701_platform_data },
{ .compatible = "mediatek,mt8516", .data = &mt2701_platform_data },
{ }