kernel: bump 5.4 to 5.4.69
[openwrt/openwrt.git] / target / linux / ipq806x / patches-5.4 / 0049-PM-OPP-Support-adjusting-OPP-voltages-at-runtime.patch
1 From: Sylwester Nawrocki <s.nawrocki@samsung.com>
2 To: krzk@kernel.org, vireshk@kernel.org, robh+dt@kernel.org
3 Cc: sboyd@kernel.org, roger.lu@mediatek.com,
4 linux-pm@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
5 linux-samsung-soc@vger.kernel.org, devicetree@vger.kernel.org,
6 b.zolnierkie@samsung.com, m.szyprowski@samsung.com,
7 Stephen Boyd <sboyd@codeaurora.org>,
8 Sylwester Nawrocki <s.nawrocki@samsung.com>
9 Subject: [PATCH v5 1/4] PM / OPP: Support adjusting OPP voltages at runtime
10 Date: Wed, 16 Oct 2019 16:57:53 +0200
11 Message-ID: <20191016145756.16004-2-s.nawrocki@samsung.com> (raw)
12 In-Reply-To: <20191016145756.16004-1-s.nawrocki@samsung.com>
13
14 From: Stephen Boyd <sboyd@codeaurora.org>
15
16 On some SoCs the Adaptive Voltage Scaling (AVS) technique is
17 employed to optimize the operating voltage of a device. At a
18 given frequency, the hardware monitors dynamic factors and either
19 makes a suggestion for how much to adjust a voltage for the
20 current frequency, or it automatically adjusts the voltage
21 without software intervention. Add an API to the OPP library for
22 the former case, so that AVS type devices can update the voltages
23 for an OPP when the hardware determines the voltage should
24 change. The assumption is that drivers like CPUfreq or devfreq
25 will register for the OPP notifiers and adjust the voltage
26 according to suggestions that AVS makes.
27
28 This patch is derived from [1] submitted by Stephen.
29 [1] https://lore.kernel.org/patchwork/patch/599279/
30
31 Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
32 Signed-off-by: Roger Lu <roger.lu@mediatek.com>
33 [s.nawrocki@samsung.com: added handling of OPP min/max voltage]
34 Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
35 ---
36 drivers/opp/core.c | 69 ++++++++++++++++++++++++++++++++++++++++++
37 include/linux/pm_opp.h | 13 ++++++++
38 2 files changed, 82 insertions(+)
39
40 --- a/drivers/opp/core.c
41 +++ b/drivers/opp/core.c
42 @@ -2095,6 +2095,75 @@ put_table:
43 }
44
45 /**
46 + * dev_pm_opp_adjust_voltage() - helper to change the voltage of an OPP
47 + * @dev: device for which we do this operation
48 + * @freq: OPP frequency to adjust voltage of
49 + * @u_volt: new OPP target voltage
50 + * @u_volt_min: new OPP min voltage
51 + * @u_volt_max: new OPP max voltage
52 + *
53 + * Return: -EINVAL for bad pointers, -ENOMEM if no memory available for the
54 + * copy operation, returns 0 if no modifcation was done OR modification was
55 + * successful.
56 + */
57 +int dev_pm_opp_adjust_voltage(struct device *dev, unsigned long freq,
58 + unsigned long u_volt, unsigned long u_volt_min,
59 + unsigned long u_volt_max)
60 +
61 +{
62 + struct opp_table *opp_table;
63 + struct dev_pm_opp *tmp_opp, *opp = ERR_PTR(-ENODEV);
64 + int r = 0;
65 +
66 + /* Find the opp_table */
67 + opp_table = _find_opp_table(dev);
68 + if (IS_ERR(opp_table)) {
69 + r = PTR_ERR(opp_table);
70 + dev_warn(dev, "%s: Device OPP not found (%d)\n", __func__, r);
71 + return r;
72 + }
73 +
74 + mutex_lock(&opp_table->lock);
75 +
76 + /* Do we have the frequency? */
77 + list_for_each_entry(tmp_opp, &opp_table->opp_list, node) {
78 + if (tmp_opp->rate == freq) {
79 + opp = tmp_opp;
80 + break;
81 + }
82 + }
83 +
84 + if (IS_ERR(opp)) {
85 + r = PTR_ERR(opp);
86 + goto adjust_unlock;
87 + }
88 +
89 + /* Is update really needed? */
90 + if (opp->supplies->u_volt == u_volt)
91 + goto adjust_unlock;
92 +
93 + opp->supplies->u_volt = u_volt;
94 + opp->supplies->u_volt_min = u_volt_min;
95 + opp->supplies->u_volt_max = u_volt_max;
96 +
97 + dev_pm_opp_get(opp);
98 + mutex_unlock(&opp_table->lock);
99 +
100 + /* Notify the voltage change of the OPP */
101 + blocking_notifier_call_chain(&opp_table->head, OPP_EVENT_ADJUST_VOLTAGE,
102 + opp);
103 +
104 + dev_pm_opp_put(opp);
105 + goto adjust_put_table;
106 +
107 +adjust_unlock:
108 + mutex_unlock(&opp_table->lock);
109 +adjust_put_table:
110 + dev_pm_opp_put_opp_table(opp_table);
111 + return r;
112 +}
113 +
114 +/**
115 * dev_pm_opp_enable() - Enable a specific OPP
116 * @dev: device for which we do this operation
117 * @freq: OPP frequency to enable
118 --- a/include/linux/pm_opp.h
119 +++ b/include/linux/pm_opp.h
120 @@ -22,6 +22,7 @@ struct opp_table;
121
122 enum dev_pm_opp_event {
123 OPP_EVENT_ADD, OPP_EVENT_REMOVE, OPP_EVENT_ENABLE, OPP_EVENT_DISABLE,
124 + OPP_EVENT_ADJUST_VOLTAGE,
125 };
126
127 /**
128 @@ -113,6 +114,10 @@ int dev_pm_opp_add(struct device *dev, u
129 void dev_pm_opp_remove(struct device *dev, unsigned long freq);
130 void dev_pm_opp_remove_all_dynamic(struct device *dev);
131
132 +int dev_pm_opp_adjust_voltage(struct device *dev, unsigned long freq,
133 + unsigned long u_volt, unsigned long u_volt_min,
134 + unsigned long u_volt_max);
135 +
136 int dev_pm_opp_enable(struct device *dev, unsigned long freq);
137
138 int dev_pm_opp_disable(struct device *dev, unsigned long freq);
139 @@ -242,6 +247,14 @@ static inline void dev_pm_opp_remove_all
140 {
141 }
142
143 +static inline int
144 +dev_pm_opp_adjust_voltage(struct device *dev, unsigned long freq,
145 + unsigned long u_volt, unsigned long u_volt_min,
146 + unsigned long u_volt_max)
147 +{
148 + return 0;
149 +}
150 +
151 static inline int dev_pm_opp_enable(struct device *dev, unsigned long freq)
152 {
153 return 0;