Commit | Line | Data |
---|---|---|
3bb16560 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
9f123def VK |
2 | /* |
3 | * CPUFreq support for Armada 370/XP platforms. | |
4 | * | |
5 | * Copyright (C) 2012-2016 Marvell | |
6 | * | |
7 | * Yehuda Yitschak <yehuday@marvell.com> | |
8 | * Gregory Clement <gregory.clement@free-electrons.com> | |
9 | * Thomas Petazzoni <thomas.petazzoni@free-electrons.com> | |
9f123def VK |
10 | */ |
11 | ||
12 | #define pr_fmt(fmt) "mvebu-pmsu: " fmt | |
13 | ||
14 | #include <linux/clk.h> | |
15 | #include <linux/cpu.h> | |
16 | #include <linux/init.h> | |
17 | #include <linux/kernel.h> | |
18 | #include <linux/of_address.h> | |
19 | #include <linux/platform_device.h> | |
20 | #include <linux/pm_opp.h> | |
21 | #include <linux/resource.h> | |
22 | ||
23 | static int __init armada_xp_pmsu_cpufreq_init(void) | |
24 | { | |
25 | struct device_node *np; | |
26 | struct resource res; | |
27 | int ret, cpu; | |
28 | ||
29 | if (!of_machine_is_compatible("marvell,armadaxp")) | |
30 | return 0; | |
31 | ||
32 | /* | |
33 | * In order to have proper cpufreq handling, we need to ensure | |
34 | * that the Device Tree description of the CPU clock includes | |
35 | * the definition of the PMU DFS registers. If not, we do not | |
36 | * register the clock notifier and the cpufreq driver. This | |
37 | * piece of code is only for compatibility with old Device | |
38 | * Trees. | |
39 | */ | |
40 | np = of_find_compatible_node(NULL, NULL, "marvell,armada-xp-cpu-clock"); | |
41 | if (!np) | |
42 | return 0; | |
43 | ||
44 | ret = of_address_to_resource(np, 1, &res); | |
45 | if (ret) { | |
46 | pr_warn(FW_WARN "not enabling cpufreq, deprecated armada-xp-cpu-clock binding\n"); | |
47 | of_node_put(np); | |
48 | return 0; | |
49 | } | |
50 | ||
51 | of_node_put(np); | |
52 | ||
53 | /* | |
54 | * For each CPU, this loop registers the operating points | |
55 | * supported (which are the nominal CPU frequency and half of | |
56 | * it), and registers the clock notifier that will take care | |
57 | * of doing the PMSU part of a frequency transition. | |
58 | */ | |
59 | for_each_possible_cpu(cpu) { | |
60 | struct device *cpu_dev; | |
61 | struct clk *clk; | |
62 | int ret; | |
63 | ||
64 | cpu_dev = get_cpu_device(cpu); | |
65 | if (!cpu_dev) { | |
66 | pr_err("Cannot get CPU %d\n", cpu); | |
67 | continue; | |
68 | } | |
69 | ||
a0944d90 | 70 | clk = clk_get(cpu_dev, NULL); |
9f123def VK |
71 | if (IS_ERR(clk)) { |
72 | pr_err("Cannot get clock for CPU %d\n", cpu); | |
73 | return PTR_ERR(clk); | |
74 | } | |
75 | ||
9f123def VK |
76 | ret = dev_pm_opp_add(cpu_dev, clk_get_rate(clk), 0); |
77 | if (ret) { | |
78 | clk_put(clk); | |
79 | return ret; | |
80 | } | |
81 | ||
82 | ret = dev_pm_opp_add(cpu_dev, clk_get_rate(clk) / 2, 0); | |
83 | if (ret) { | |
883071c4 | 84 | dev_pm_opp_remove(cpu_dev, clk_get_rate(clk)); |
9f123def | 85 | clk_put(clk); |
3f4590a4 | 86 | dev_err(cpu_dev, "Failed to register OPPs\n"); |
883071c4 | 87 | return ret; |
9f123def VK |
88 | } |
89 | ||
90 | ret = dev_pm_opp_set_sharing_cpus(cpu_dev, | |
91 | cpumask_of(cpu_dev->id)); | |
92 | if (ret) | |
93 | dev_err(cpu_dev, "%s: failed to mark OPPs as shared: %d\n", | |
94 | __func__, ret); | |
b3371600 | 95 | clk_put(clk); |
9f123def VK |
96 | } |
97 | ||
98 | platform_device_register_simple("cpufreq-dt", -1, NULL, 0); | |
99 | return 0; | |
100 | } | |
101 | device_initcall(armada_xp_pmsu_cpufreq_init); |