Loading drivers/cpufreq/qcom-cpufreq-hw.c +67 −6 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. * Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. */ #include <linux/bitfield.h> Loading Loading @@ -31,6 +31,7 @@ #define GT_IRQ_STATUS BIT(2) #define MAX_FN_SIZE 20 #define LIMITS_POLLING_DELAY_MS 10 #define MAX_ROW 2 #define CYCLE_CNTR_OFFSET(c, m, acc_count) \ (acc_count ? ((c - cpumask_first(m) + 1) * 4) : 0) Loading Loading @@ -60,6 +61,8 @@ struct cpufreq_qcom { struct cpufreq_frequency_table *table; void __iomem *base; void __iomem *pdmem_base; void __iomem **sdpm_base; int sdpm_base_count; cpumask_t related_cpus; unsigned long dcvsh_freq_limit; struct delayed_work freq_poll_work; Loading Loading @@ -236,19 +239,25 @@ static int qcom_cpufreq_hw_target_index(struct cpufreq_policy *policy, unsigned int index) { struct cpufreq_qcom *c; struct cpufreq_qcom *c = qcom_freq_domain_map[policy->cpu]; unsigned long freq = policy->freq_table[index].frequency; int i; if (perf_lock_support) { c = qcom_freq_domain_map[policy->cpu]; if (c->pdmem_base) writel_relaxed(index, c->pdmem_base); } for (i = 0; i < c->sdpm_base_count && freq > policy->cur; i++) writel_relaxed(freq / 1000, c->sdpm_base[i]); writel_relaxed(index, policy->driver_data + offsets[REG_PERF_STATE]); arch_set_freq_scale(policy->related_cpus, policy->freq_table[index].frequency, arch_set_freq_scale(policy->related_cpus, freq, policy->cpuinfo.max_freq); for (i = 0; i < c->sdpm_base_count && freq < policy->cur; i++) writel_relaxed(freq / 1000, c->sdpm_base[i]); return 0; } Loading Loading @@ -379,6 +388,30 @@ static void qcom_cpufreq_ready(struct cpufreq_policy *policy) of_node_put(np); } static int qcom_cpufreq_hw_suspend(struct cpufreq_policy *policy) { struct cpufreq_qcom *c = qcom_freq_domain_map[policy->cpu]; unsigned long freq = policy->freq_table[0].frequency; int i; for (i = 0; i < c->sdpm_base_count && freq < policy->cur; i++) writel_relaxed(freq / 1000, c->sdpm_base[i]); return 0; } static int qcom_cpufreq_hw_resume(struct cpufreq_policy *policy) { struct cpufreq_qcom *c = qcom_freq_domain_map[policy->cpu]; unsigned long freq = policy->cur; int i; for (i = 0; i < c->sdpm_base_count; i++) writel_relaxed(freq / 1000, c->sdpm_base[i]); return 0; } static struct cpufreq_driver cpufreq_qcom_hw_driver = { .flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK | CPUFREQ_HAVE_GOVERNOR_PER_POLICY, Loading @@ -391,6 +424,8 @@ static struct cpufreq_driver cpufreq_qcom_hw_driver = { .attr = qcom_cpufreq_hw_attr, .boost_enabled = true, .ready = qcom_cpufreq_ready, .suspend = qcom_cpufreq_hw_suspend, .resume = qcom_cpufreq_hw_resume, }; static int qcom_cpufreq_hw_read_lut(struct platform_device *pdev, Loading Loading @@ -486,7 +521,8 @@ static int qcom_cpu_resources_init(struct platform_device *pdev, struct device *dev = &pdev->dev; void __iomem *base; char pdmem_name[MAX_FN_SIZE] = {}; int ret, cpu_r; char sdpm_name[MAX_FN_SIZE] = {}; int ret, cpu_r, len, reg, size, i, j; c = devm_kzalloc(dev, sizeof(*c), GFP_KERNEL); if (!c) Loading Loading @@ -543,6 +579,31 @@ static int qcom_cpu_resources_init(struct platform_device *pdev, c->pdmem_base = base; } snprintf(sdpm_name, sizeof(sdpm_name), "qcom,sdpm-cx-mx-%d", index); len = of_property_count_u32_elems(dev->of_node, sdpm_name); if (len > 0) { c->sdpm_base_count = len / MAX_ROW; c->sdpm_base = devm_kcalloc(dev, c->sdpm_base_count, sizeof(*c->sdpm_base), GFP_KERNEL); if (!c->sdpm_base) return -ENOMEM; for (i = 0, j = 0; i < c->sdpm_base_count; i++, j += 2) { of_property_read_u32_index(dev->of_node, sdpm_name, j, ®); of_property_read_u32_index(dev->of_node, sdpm_name, j + 1, &size); base = devm_ioremap(dev, reg, size); if (IS_ERR(base)) { dev_err(dev, "Failed to map base %d domain-%d\n", i, index); return PTR_ERR(base); } c->sdpm_base[i] = base; } } if (of_find_property(dev->of_node, "interrupts", NULL)) { c->dcvsh_irq = of_irq_get(dev->of_node, index); if (c->dcvsh_irq > 0) { Loading Loading
drivers/cpufreq/qcom-cpufreq-hw.c +67 −6 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. * Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. */ #include <linux/bitfield.h> Loading Loading @@ -31,6 +31,7 @@ #define GT_IRQ_STATUS BIT(2) #define MAX_FN_SIZE 20 #define LIMITS_POLLING_DELAY_MS 10 #define MAX_ROW 2 #define CYCLE_CNTR_OFFSET(c, m, acc_count) \ (acc_count ? ((c - cpumask_first(m) + 1) * 4) : 0) Loading Loading @@ -60,6 +61,8 @@ struct cpufreq_qcom { struct cpufreq_frequency_table *table; void __iomem *base; void __iomem *pdmem_base; void __iomem **sdpm_base; int sdpm_base_count; cpumask_t related_cpus; unsigned long dcvsh_freq_limit; struct delayed_work freq_poll_work; Loading Loading @@ -236,19 +239,25 @@ static int qcom_cpufreq_hw_target_index(struct cpufreq_policy *policy, unsigned int index) { struct cpufreq_qcom *c; struct cpufreq_qcom *c = qcom_freq_domain_map[policy->cpu]; unsigned long freq = policy->freq_table[index].frequency; int i; if (perf_lock_support) { c = qcom_freq_domain_map[policy->cpu]; if (c->pdmem_base) writel_relaxed(index, c->pdmem_base); } for (i = 0; i < c->sdpm_base_count && freq > policy->cur; i++) writel_relaxed(freq / 1000, c->sdpm_base[i]); writel_relaxed(index, policy->driver_data + offsets[REG_PERF_STATE]); arch_set_freq_scale(policy->related_cpus, policy->freq_table[index].frequency, arch_set_freq_scale(policy->related_cpus, freq, policy->cpuinfo.max_freq); for (i = 0; i < c->sdpm_base_count && freq < policy->cur; i++) writel_relaxed(freq / 1000, c->sdpm_base[i]); return 0; } Loading Loading @@ -379,6 +388,30 @@ static void qcom_cpufreq_ready(struct cpufreq_policy *policy) of_node_put(np); } static int qcom_cpufreq_hw_suspend(struct cpufreq_policy *policy) { struct cpufreq_qcom *c = qcom_freq_domain_map[policy->cpu]; unsigned long freq = policy->freq_table[0].frequency; int i; for (i = 0; i < c->sdpm_base_count && freq < policy->cur; i++) writel_relaxed(freq / 1000, c->sdpm_base[i]); return 0; } static int qcom_cpufreq_hw_resume(struct cpufreq_policy *policy) { struct cpufreq_qcom *c = qcom_freq_domain_map[policy->cpu]; unsigned long freq = policy->cur; int i; for (i = 0; i < c->sdpm_base_count; i++) writel_relaxed(freq / 1000, c->sdpm_base[i]); return 0; } static struct cpufreq_driver cpufreq_qcom_hw_driver = { .flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK | CPUFREQ_HAVE_GOVERNOR_PER_POLICY, Loading @@ -391,6 +424,8 @@ static struct cpufreq_driver cpufreq_qcom_hw_driver = { .attr = qcom_cpufreq_hw_attr, .boost_enabled = true, .ready = qcom_cpufreq_ready, .suspend = qcom_cpufreq_hw_suspend, .resume = qcom_cpufreq_hw_resume, }; static int qcom_cpufreq_hw_read_lut(struct platform_device *pdev, Loading Loading @@ -486,7 +521,8 @@ static int qcom_cpu_resources_init(struct platform_device *pdev, struct device *dev = &pdev->dev; void __iomem *base; char pdmem_name[MAX_FN_SIZE] = {}; int ret, cpu_r; char sdpm_name[MAX_FN_SIZE] = {}; int ret, cpu_r, len, reg, size, i, j; c = devm_kzalloc(dev, sizeof(*c), GFP_KERNEL); if (!c) Loading Loading @@ -543,6 +579,31 @@ static int qcom_cpu_resources_init(struct platform_device *pdev, c->pdmem_base = base; } snprintf(sdpm_name, sizeof(sdpm_name), "qcom,sdpm-cx-mx-%d", index); len = of_property_count_u32_elems(dev->of_node, sdpm_name); if (len > 0) { c->sdpm_base_count = len / MAX_ROW; c->sdpm_base = devm_kcalloc(dev, c->sdpm_base_count, sizeof(*c->sdpm_base), GFP_KERNEL); if (!c->sdpm_base) return -ENOMEM; for (i = 0, j = 0; i < c->sdpm_base_count; i++, j += 2) { of_property_read_u32_index(dev->of_node, sdpm_name, j, ®); of_property_read_u32_index(dev->of_node, sdpm_name, j + 1, &size); base = devm_ioremap(dev, reg, size); if (IS_ERR(base)) { dev_err(dev, "Failed to map base %d domain-%d\n", i, index); return PTR_ERR(base); } c->sdpm_base[i] = base; } } if (of_find_property(dev->of_node, "interrupts", NULL)) { c->dcvsh_irq = of_irq_get(dev->of_node, index); if (c->dcvsh_irq > 0) { Loading