1 From b018e44a68dc2f4df819ae194e39e07313841dad Mon Sep 17 00:00:00 2001
2 From: Yangbo Lu <yangbo.lu@nxp.com>
3 Date: Wed, 17 Jan 2018 15:27:58 +0800
4 Subject: [PATCH 15/30] cpufreq: support layerscape
6 This is an integrated patch for layerscape pm support.
8 Signed-off-by: Tang Yuantian <Yuantian.Tang@nxp.com>
9 Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
11 drivers/cpufreq/Kconfig | 2 +-
12 drivers/cpufreq/qoriq-cpufreq.c | 176 +++++++++++++++-------------------------
13 drivers/firmware/psci.c | 12 ++-
14 drivers/soc/fsl/rcpm.c | 158 ++++++++++++++++++++++++++++++++++++
15 4 files changed, 235 insertions(+), 113 deletions(-)
16 create mode 100644 drivers/soc/fsl/rcpm.c
18 --- a/drivers/cpufreq/Kconfig
19 +++ b/drivers/cpufreq/Kconfig
20 @@ -332,7 +332,7 @@ endif
23 tristate "CPU frequency scaling driver for Freescale QorIQ SoCs"
24 - depends on OF && COMMON_CLK && (PPC_E500MC || ARM)
25 + depends on OF && COMMON_CLK && (PPC_E500MC || ARM || ARM64)
26 depends on !CPU_THERMAL || THERMAL
29 --- a/drivers/cpufreq/qoriq-cpufreq.c
30 +++ b/drivers/cpufreq/qoriq-cpufreq.c
32 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
34 #include <linux/clk.h>
35 +#include <linux/clk-provider.h>
36 #include <linux/cpufreq.h>
37 #include <linux/cpu_cooling.h>
38 #include <linux/errno.h>
40 #include <linux/slab.h>
41 #include <linux/smp.h>
43 -#if !defined(CONFIG_ARM)
44 -#include <asm/smp.h> /* for get_hard_smp_processor_id() in UP configs */
49 * @pclk: the parent clock of cpu
50 @@ -37,73 +34,51 @@ struct cpu_data {
51 struct thermal_cooling_device *cdev;
55 + * Don't use cpufreq on this SoC -- used when the SoC would have otherwise
56 + * matched a more generic compatible.
58 +#define SOC_BLACKLIST 1
61 * struct soc_data - SoC specific data
62 - * @freq_mask: mask the disallowed frequencies
63 - * @flag: unique flags
72 -/* see hardware specification for the allowed frqeuencies */
73 -static const struct soc_data sdata[] = {
74 - { /* used by p2041 and p3041 */
75 - .freq_mask = {0x8, 0x8, 0x2, 0x2},
78 - { /* used by p5020 */
79 - .freq_mask = {0x8, 0x2},
82 - { /* used by p4080, p5040 */
90 - * the minimum allowed core frequency, in Hz
91 - * for chassis v1.0, >= platform frequency
92 - * for chassis v2.0, >= platform frequency / 2
94 -static u32 min_cpufreq;
95 -static const u32 *fmask;
97 -#if defined(CONFIG_ARM)
98 -static int get_cpu_physical_id(int cpu)
100 - return topology_core_id(cpu);
103 -static int get_cpu_physical_id(int cpu)
105 - return get_hard_smp_processor_id(cpu);
109 static u32 get_bus_freq(void)
111 struct device_node *soc;
113 + struct clk *pltclk;
116 + /* get platform freq by searching bus-frequency property */
117 soc = of_find_node_by_type(NULL, "soc");
121 - if (of_property_read_u32(soc, "bus-frequency", &sysfreq))
124 + ret = of_property_read_u32(soc, "bus-frequency", &sysfreq);
131 + /* get platform freq by its clock name */
132 + pltclk = clk_get(NULL, "cg-pll0-div1");
133 + if (IS_ERR(pltclk)) {
134 + pr_err("%s: can't get bus frequency %ld\n",
135 + __func__, PTR_ERR(pltclk));
136 + return PTR_ERR(pltclk);
140 + return clk_get_rate(pltclk);
143 -static struct device_node *cpu_to_clk_node(int cpu)
144 +static struct clk *cpu_to_clk(int cpu)
146 - struct device_node *np, *clk_np;
147 + struct device_node *np;
150 if (!cpu_present(cpu))
152 @@ -112,37 +87,28 @@ static struct device_node *cpu_to_clk_no
156 - clk_np = of_parse_phandle(np, "clocks", 0);
160 + clk = of_clk_get(np, 0);
167 /* traverse cpu nodes to get cpu mask of sharing clock wire */
168 static void set_affected_cpus(struct cpufreq_policy *policy)
170 - struct device_node *np, *clk_np;
171 struct cpumask *dstp = policy->cpus;
175 - np = cpu_to_clk_node(policy->cpu);
179 for_each_present_cpu(i) {
180 - clk_np = cpu_to_clk_node(i);
182 + clk = cpu_to_clk(i);
184 + pr_err("%s: no clock for cpu %d\n", __func__, i);
189 + if (clk_is_match(policy->clk, clk))
190 cpumask_set_cpu(i, dstp);
192 - of_node_put(clk_np);
197 /* reduce the duplicated frequencies in frequency table */
198 @@ -198,10 +164,11 @@ static void freq_table_sort(struct cpufr
200 static int qoriq_cpufreq_cpu_init(struct cpufreq_policy *policy)
202 - struct device_node *np, *pnode;
203 + struct device_node *np;
208 + const struct clk_hw *hwclk;
209 struct cpufreq_frequency_table *table;
210 struct cpu_data *data;
211 unsigned int cpu = policy->cpu;
212 @@ -221,17 +188,13 @@ static int qoriq_cpufreq_cpu_init(struct
216 - pnode = of_parse_phandle(np, "clocks", 0);
218 - pr_err("%s: could not get clock information\n", __func__);
221 + hwclk = __clk_get_hw(policy->clk);
222 + count = clk_hw_get_num_parents(hwclk);
224 - count = of_property_count_strings(pnode, "clock-names");
225 data->pclk = kcalloc(count, sizeof(struct clk *), GFP_KERNEL);
227 pr_err("%s: no memory\n", __func__);
232 table = kcalloc(count + 1, sizeof(*table), GFP_KERNEL);
233 @@ -240,23 +203,11 @@ static int qoriq_cpufreq_cpu_init(struct
238 - mask = fmask[get_cpu_physical_id(cpu)];
242 for (i = 0; i < count; i++) {
243 - clk = of_clk_get(pnode, i);
244 + clk = clk_hw_get_parent_by_index(hwclk, i)->clk;
246 freq = clk_get_rate(clk);
248 - * the clock is valid if its frequency is not masked
249 - * and large than minimum allowed frequency.
251 - if (freq < min_cpufreq || (mask & (1 << i)))
252 - table[i].frequency = CPUFREQ_ENTRY_INVALID;
254 - table[i].frequency = freq / 1000;
255 + table[i].frequency = freq / 1000;
256 table[i].driver_data = i;
258 freq_table_redup(table, count);
259 @@ -282,7 +233,6 @@ static int qoriq_cpufreq_cpu_init(struct
260 policy->cpuinfo.transition_latency = u64temp + 1;
263 - of_node_put(pnode);
267 @@ -290,10 +240,7 @@ err_nomem1:
272 - of_node_put(pnode);
274 - policy->driver_data = NULL;
278 @@ -357,12 +304,25 @@ static struct cpufreq_driver qoriq_cpufr
279 .attr = cpufreq_generic_attr,
282 +static const struct soc_data blacklist = {
283 + .flags = SOC_BLACKLIST,
286 static const struct of_device_id node_matches[] __initconst = {
287 - { .compatible = "fsl,p2041-clockgen", .data = &sdata[0], },
288 - { .compatible = "fsl,p3041-clockgen", .data = &sdata[0], },
289 - { .compatible = "fsl,p5020-clockgen", .data = &sdata[1], },
290 - { .compatible = "fsl,p4080-clockgen", .data = &sdata[2], },
291 - { .compatible = "fsl,p5040-clockgen", .data = &sdata[2], },
292 + /* e6500 cannot use cpufreq due to erratum A-008083 */
293 + { .compatible = "fsl,b4420-clockgen", &blacklist },
294 + { .compatible = "fsl,b4860-clockgen", &blacklist },
295 + { .compatible = "fsl,t2080-clockgen", &blacklist },
296 + { .compatible = "fsl,t4240-clockgen", &blacklist },
298 + { .compatible = "fsl,ls1012a-clockgen", },
299 + { .compatible = "fsl,ls1021a-clockgen", },
300 + { .compatible = "fsl,ls1043a-clockgen", },
301 + { .compatible = "fsl,ls1046a-clockgen", },
302 + { .compatible = "fsl,ls1088a-clockgen", },
303 + { .compatible = "fsl,ls2080a-clockgen", },
304 + { .compatible = "fsl,p4080-clockgen", },
305 + { .compatible = "fsl,qoriq-clockgen-1.0", },
306 { .compatible = "fsl,qoriq-clockgen-2.0", },
309 @@ -380,16 +340,12 @@ static int __init qoriq_cpufreq_init(voi
311 match = of_match_node(node_matches, np);
315 - fmask = data->freq_mask;
316 - min_cpufreq = get_bus_freq();
318 - min_cpufreq = get_bus_freq() / 2;
323 + if (data && data->flags & SOC_BLACKLIST)
326 ret = cpufreq_register_driver(&qoriq_cpufreq_driver);
328 pr_info("Freescale QorIQ CPU frequency scaling driver\n");
329 --- a/drivers/firmware/psci.c
330 +++ b/drivers/firmware/psci.c
331 @@ -418,8 +418,12 @@ CPUIDLE_METHOD_OF_DECLARE(psci, "psci",
333 static int psci_system_suspend(unsigned long unused)
335 - return invoke_psci_fn(PSCI_FN_NATIVE(1_0, SYSTEM_SUSPEND),
336 - virt_to_phys(cpu_resume), 0, 0);
339 + state = ( 2 << PSCI_0_2_POWER_STATE_AFFL_SHIFT) |
340 + (1 << PSCI_0_2_POWER_STATE_TYPE_SHIFT);
342 + return psci_cpu_suspend(state, virt_to_phys(cpu_resume));
345 static int psci_system_suspend_enter(suspend_state_t state)
346 @@ -439,6 +443,8 @@ static void __init psci_init_system_susp
347 if (!IS_ENABLED(CONFIG_SUSPEND))
350 + suspend_set_ops(&psci_suspend_ops);
352 ret = psci_features(PSCI_FN_NATIVE(1_0, SYSTEM_SUSPEND));
354 if (ret != PSCI_RET_NOT_SUPPORTED)
355 @@ -516,6 +522,8 @@ static void __init psci_0_2_set_function
356 arm_pm_restart = psci_sys_reset;
358 pm_power_off = psci_sys_poweroff;
359 + psci_init_system_suspend();
360 + suspend_set_ops(&psci_suspend_ops);
365 +++ b/drivers/soc/fsl/rcpm.c
368 + * Run Control and Power Management (RCPM) driver
370 + * Copyright 2016 NXP
372 + * This program is free software; you can redistribute it and/or modify
373 + * it under the terms of the GNU General Public License as published by
374 + * the Free Software Foundation; either version 2 of the License, or
375 + * (at your option) any later version.
377 + * This program is distributed in the hope that it will be useful,
378 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
379 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
380 + * GNU General Public License for more details.
383 +#define pr_fmt(fmt) "RCPM: %s: " fmt, __func__
385 +#include <linux/kernel.h>
386 +#include <linux/io.h>
387 +#include <linux/of_platform.h>
388 +#include <linux/of_address.h>
389 +#include <linux/suspend.h>
391 +/* RCPM register offset */
392 +#define RCPM_IPPDEXPCR0 0x140
394 +#define RCPM_WAKEUP_CELL_SIZE 2
396 +struct rcpm_config {
398 + int ippdexpcr_offset;
400 + void *rcpm_reg_base;
403 +static struct rcpm_config *rcpm;
405 +static inline void rcpm_reg_write(u32 offset, u32 value)
407 + iowrite32be(value, rcpm->rcpm_reg_base + offset);
410 +static inline u32 rcpm_reg_read(u32 offset)
412 + return ioread32be(rcpm->rcpm_reg_base + offset);
415 +static void rcpm_wakeup_fixup(struct device *dev, void *data)
417 + struct device_node *node = dev ? dev->of_node : NULL;
418 + u32 value[RCPM_WAKEUP_CELL_SIZE];
421 + if (!dev || !node || !device_may_wakeup(dev))
425 + * Get the values in the "rcpm-wakeup" property.
426 + * Three values are:
427 + * The first is a pointer to the RCPM node.
428 + * The second is the value of the ippdexpcr0 register.
429 + * The third is the value of the ippdexpcr1 register.
431 + ret = of_property_read_u32_array(node, "fsl,rcpm-wakeup",
432 + value, RCPM_WAKEUP_CELL_SIZE);
436 + pr_debug("wakeup source: the device %s\n", node->full_name);
438 + for (i = 0; i < rcpm->ipp_num; i++)
439 + rcpm->ippdexpcr[i] |= value[i + 1];
442 +static int rcpm_suspend_prepare(void)
449 + for (i = 0; i < rcpm->ipp_num; i++)
450 + rcpm->ippdexpcr[i] = 0;
452 + dpm_for_each_dev(NULL, rcpm_wakeup_fixup);
454 + for (i = 0; i < rcpm->ipp_num; i++) {
455 + if (rcpm->ippdexpcr[i]) {
456 + val = rcpm_reg_read(rcpm->ippdexpcr_offset + 4 * i);
457 + rcpm_reg_write(rcpm->ippdexpcr_offset + 4 * i,
458 + val | rcpm->ippdexpcr[i]);
459 + pr_debug("ippdexpcr%d = 0x%x\n", i, rcpm->ippdexpcr[i]);
466 +static int rcpm_suspend_notifier_call(struct notifier_block *bl,
467 + unsigned long state,
471 + case PM_SUSPEND_PREPARE:
472 + rcpm_suspend_prepare();
476 + return NOTIFY_DONE;
479 +static struct rcpm_config rcpm_default_config = {
481 + .ippdexpcr_offset = RCPM_IPPDEXPCR0,
484 +static const struct of_device_id rcpm_matches[] = {
486 + .compatible = "fsl,qoriq-rcpm-2.1",
487 + .data = &rcpm_default_config,
492 +static struct notifier_block rcpm_suspend_notifier = {
493 + .notifier_call = rcpm_suspend_notifier_call,
496 +static int __init layerscape_rcpm_init(void)
498 + const struct of_device_id *match;
499 + struct device_node *np;
501 + np = of_find_matching_node_and_match(NULL, rcpm_matches, &match);
503 + pr_err("Can't find the RCPM node.\n");
508 + rcpm = (struct rcpm_config *)match->data;
512 + rcpm->rcpm_reg_base = of_iomap(np, 0);
514 + if (!rcpm->rcpm_reg_base)
517 + register_pm_notifier(&rcpm_suspend_notifier);
519 + pr_info("The RCPM driver initialized.\n");
524 +subsys_initcall(layerscape_rcpm_init);