ipq806x: copy files to kernel 5.4
[openwrt/staging/dedeckeh.git] / target / linux / ipq806x / patches-5.4 / 0038-qcom-cpufreq-nvmem-Add-support-for-krait-based-socs.patch
1 Subject: [PATCH v12 14/14] cpufreq: qcom: Add support for krait based socs
2 Date: Tue, 14 Aug 2018 17:42:33 +0530
3 Message-Id: <1534248753-2440-15-git-send-email-sricharan@codeaurora.org>
4 X-Mailer: git-send-email 1.9.1
5 In-Reply-To: <1534248753-2440-1-git-send-email-sricharan@codeaurora.org>
6 References: <1534248753-2440-1-git-send-email-sricharan@codeaurora.org>
7 Sender: linux-kernel-owner@vger.kernel.org
8 Precedence: bulk
9 List-ID: <linux-kernel.vger.kernel.org>
10 X-Mailing-List: linux-kernel@vger.kernel.org
11
12 In Certain QCOM SoCs like ipq8064, apq8064, msm8960, msm8974
13 that has KRAIT processors the voltage/current value of each OPP
14 varies based on the silicon variant in use.
15
16 The required OPP related data is determined based on
17 the efuse value. This is similar to the existing code for
18 kryo cores. So adding support for krait cores here.
19
20 Signed-off-by: Sricharan R <sricharan@codeaurora.org>
21 ---
22 .../devicetree/bindings/opp/qcom-nvmem-cpufreq.txt | 3 +-
23 drivers/cpufreq/Kconfig.arm | 2 +-
24 drivers/cpufreq/cpufreq-dt-platdev.c | 5 +
25 drivers/cpufreq/qcom-cpufreq-nvmem.c | 151 +++++++++++++++++++--
26 4 files changed, 149 insertions(+), 12 deletions(-)
27
28 # diff --git a/Documentation/devicetree/bindings/opp/qcom-nvmem-cpufreq.txt b/Documentation/devicetree/bindings/opp/qcom-nvmem-cpufreq.txt
29 # index 6dcdfcd..7bc0f1a 100644
30 # --- a/Documentation/devicetree/bindings/opp/qcom-nvmem-cpufreq.txt
31 # +++ b/Documentation/devicetree/bindings/opp/qcom-nvmem-cpufreq.txt
32 # @@ -19,7 +19,8 @@ In 'cpus' nodes:
33
34 # In 'operating-points-v2' table:
35 # - compatible: Should be
36 # - - 'operating-points-v2-qcom-cpu' for apq8096 and msm8996.
37 # + - 'operating-points-v2-qcom-cpu' for apq8096, msm8996, msm8974,
38 # + apq8064, msm8960 and ipq8074.
39 # - nvmem-cells: A phandle pointing to a nvmem-cells node representing the
40 # efuse registers that has information about the
41 # speedbin that is used to select the right frequency/voltage
42 --- a/drivers/cpufreq/Kconfig.arm
43 +++ b/drivers/cpufreq/Kconfig.arm
44 @@ -112,7 +112,7 @@ config ARM_OMAP2PLUS_CPUFREQ
45
46 config ARM_QCOM_CPUFREQ_NVMEM
47 tristate "Qualcomm nvmem based CPUFreq"
48 - depends on ARM64
49 + depends on ARCH_QCOM
50 depends on QCOM_QFPROM
51 depends on QCOM_SMEM
52 select PM_OPP
53 --- a/drivers/cpufreq/cpufreq-dt-platdev.c
54 +++ b/drivers/cpufreq/cpufreq-dt-platdev.c
55 @@ -128,6 +128,11 @@ static const struct of_device_id blackli
56 { .compatible = "ti,am43", },
57 { .compatible = "ti,dra7", },
58
59 + { .compatible = "qcom,ipq8064", },
60 + { .compatible = "qcom,apq8064", },
61 + { .compatible = "qcom,msm8974", },
62 + { .compatible = "qcom,msm8960", },
63 +
64 { }
65 };
66
67 --- a/drivers/cpufreq/qcom-cpufreq-nvmem.c
68 +++ b/drivers/cpufreq/qcom-cpufreq-nvmem.c
69 @@ -48,17 +48,92 @@ struct qcom_cpufreq_drv;
70 struct qcom_cpufreq_match_data {
71 int (*get_version)(struct device *cpu_dev,
72 struct nvmem_cell *speedbin_nvmem,
73 + char **pvs_name,
74 struct qcom_cpufreq_drv *drv);
75 };
76
77 struct qcom_cpufreq_drv {
78 - struct opp_table **opp_tables;
79 + struct opp_table **opp_tables1;
80 + struct opp_table **opp_tables2;
81 u32 versions;
82 const struct qcom_cpufreq_match_data *data;
83 };
84
85 static struct platform_device *cpufreq_dt_pdev, *cpufreq_pdev;
86
87 +static void get_krait_bin_format_a(int *speed, int *pvs, int *pvs_ver,
88 + struct nvmem_cell *pvs_nvmem, u8 *buf)
89 +{
90 + u32 pte_efuse;
91 +
92 + pte_efuse = *((u32 *)buf);
93 +
94 + *speed = pte_efuse & 0xf;
95 + if (*speed == 0xf)
96 + *speed = (pte_efuse >> 4) & 0xf;
97 +
98 + if (*speed == 0xf) {
99 + *speed = 0;
100 + pr_warn("Speed bin: Defaulting to %d\n", *speed);
101 + } else {
102 + pr_info("Speed bin: %d\n", *speed);
103 + }
104 +
105 + *pvs = (pte_efuse >> 10) & 0x7;
106 + if (*pvs == 0x7)
107 + *pvs = (pte_efuse >> 13) & 0x7;
108 +
109 + if (*pvs == 0x7) {
110 + *pvs = 0;
111 + pr_warn("PVS bin: Defaulting to %d\n", *pvs);
112 + } else {
113 + pr_info("PVS bin: %d\n", *pvs);
114 + }
115 +}
116 +
117 +static void get_krait_bin_format_b(int *speed, int *pvs, int *pvs_ver,
118 + struct nvmem_cell *pvs_nvmem, u8 *buf)
119 +{
120 + u32 pte_efuse, redundant_sel;
121 +
122 + pte_efuse = *((u32 *)buf);
123 + redundant_sel = (pte_efuse >> 24) & 0x7;
124 + *speed = pte_efuse & 0x7;
125 +
126 + /* 4 bits of PVS are in efuse register bits 31, 8-6. */
127 + *pvs = ((pte_efuse >> 28) & 0x8) | ((pte_efuse >> 6) & 0x7);
128 + *pvs_ver = (pte_efuse >> 4) & 0x3;
129 +
130 + switch (redundant_sel) {
131 + case 1:
132 + *speed = (pte_efuse >> 27) & 0xf;
133 + break;
134 + case 2:
135 + *pvs = (pte_efuse >> 27) & 0xf;
136 + break;
137 + }
138 +
139 + /* Check SPEED_BIN_BLOW_STATUS */
140 + if (pte_efuse & BIT(3)) {
141 + pr_info("Speed bin: %d\n", *speed);
142 + } else {
143 + pr_warn("Speed bin not set. Defaulting to 0!\n");
144 + *speed = 0;
145 + }
146 +
147 + /* Check PVS_BLOW_STATUS */
148 + pte_efuse = *(((u32 *)buf) + 4);
149 + pte_efuse &= BIT(21);
150 + if (pte_efuse) {
151 + pr_info("PVS bin: %d\n", *pvs);
152 + } else {
153 + pr_warn("PVS bin not set. Defaulting to 0!\n");
154 + *pvs = 0;
155 + }
156 +
157 + pr_info("PVS version: %d\n", *pvs_ver);
158 +}
159 +
160 static enum _msm8996_version qcom_cpufreq_get_msm_id(void)
161 {
162 size_t len;
163 @@ -90,11 +165,13 @@ static enum _msm8996_version qcom_cpufre
164
165 static int qcom_cpufreq_kryo_name_version(struct device *cpu_dev,
166 struct nvmem_cell *speedbin_nvmem,
167 + char **pvs_name,
168 struct qcom_cpufreq_drv *drv)
169 {
170 size_t len;
171 u8 *speedbin;
172 enum _msm8996_version msm8996_version;
173 + *pvs_name = NULL;
174
175 msm8996_version = qcom_cpufreq_get_msm_id();
176 if (NUM_OF_MSM8996_VERSIONS == msm8996_version) {
177 @@ -122,16 +199,51 @@ static int qcom_cpufreq_kryo_name_versio
178 return 0;
179 }
180
181 +static int qcom_cpufreq_krait_name_version(struct device *cpu_dev,
182 + struct nvmem_cell *speedbin_nvmem,
183 + char **pvs_name,
184 + struct qcom_cpufreq_drv *drv)
185 +{
186 + int speed = 0, pvs = 0, pvs_ver = 0;
187 + u8 *speedbin;
188 + size_t len;
189 +
190 + speedbin = nvmem_cell_read(speedbin_nvmem, &len);
191 + if (len == 4) {
192 + get_krait_bin_format_a(&speed, &pvs, &pvs_ver,
193 + speedbin_nvmem, speedbin);
194 + } else if (len == 8) {
195 + get_krait_bin_format_b(&speed, &pvs, &pvs_ver,
196 + speedbin_nvmem, speedbin);
197 + } else {
198 + dev_err(cpu_dev, "Unable to read nvmem data. Defaulting to 0!\n");
199 + return -ENODEV;
200 + }
201 +
202 + snprintf(*pvs_name, sizeof("speedXX-pvsXX-vXX"), "speed%d-pvs%d-v%d",
203 + speed, pvs, pvs_ver);
204 +
205 + drv->versions = (1 << speed);
206 +
207 + kfree(speedbin);
208 + return 0;
209 +}
210 +
211 static const struct qcom_cpufreq_match_data match_data_kryo = {
212 .get_version = qcom_cpufreq_kryo_name_version,
213 };
214
215 +static const struct qcom_cpufreq_match_data match_data_krait = {
216 + .get_version = qcom_cpufreq_krait_name_version,
217 +};
218 +
219 static int qcom_cpufreq_probe(struct platform_device *pdev)
220 {
221 struct qcom_cpufreq_drv *drv;
222 struct nvmem_cell *speedbin_nvmem;
223 struct device_node *np;
224 struct device *cpu_dev;
225 + char *pvs_name = "speedXX-pvsXX-vXX";
226 unsigned cpu;
227 const struct of_device_id *match;
228 int ret;
229 @@ -144,7 +256,7 @@ static int qcom_cpufreq_probe(struct pla
230 if (!np)
231 return -ENOENT;
232
233 - ret = of_device_is_compatible(np, "operating-points-v2-kryo-cpu");
234 + ret = of_device_is_compatible(np, "operating-points-v2-qcom-cpu");
235 if (!ret) {
236 of_node_put(np);
237 return -ENOENT;
238 @@ -172,7 +284,7 @@ static int qcom_cpufreq_probe(struct pla
239 goto free_drv;
240 }
241
242 - ret = drv->data->get_version(cpu_dev, speedbin_nvmem, drv);
243 + ret = drv->data->get_version(cpu_dev, speedbin_nvmem, &pvs_name, drv);
244 if (ret) {
245 nvmem_cell_put(speedbin_nvmem);
246 goto free_drv;
247 @@ -181,12 +293,18 @@ static int qcom_cpufreq_probe(struct pla
248 }
249 of_node_put(np);
250
251 - drv->opp_tables = kcalloc(num_possible_cpus(), sizeof(*drv->opp_tables),
252 + drv->opp_tables1 = kcalloc(num_possible_cpus(), sizeof(*drv->opp_tables1),
253 GFP_KERNEL);
254 - if (!drv->opp_tables) {
255 + if (!drv->opp_tables1) {
256 ret = -ENOMEM;
257 goto free_drv;
258 }
259 + drv->opp_tables2 = kcalloc(num_possible_cpus(), sizeof(*drv->opp_tables2),
260 + GFP_KERNEL);
261 + if (!drv->opp_tables2) {
262 + ret = -ENOMEM;
263 + goto free_opp1;
264 + }
265
266 for_each_possible_cpu(cpu) {
267 cpu_dev = get_cpu_device(cpu);
268 @@ -196,11 +314,22 @@ static int qcom_cpufreq_probe(struct pla
269 }
270
271 if (drv->data->get_version) {
272 - drv->opp_tables[cpu] =
273 - dev_pm_opp_set_supported_hw(cpu_dev,
274 +
275 + if (pvs_name) {
276 + drv->opp_tables1[cpu] = dev_pm_opp_set_prop_name(cpu_dev,
277 + pvs_name);
278 + if (IS_ERR(drv->opp_tables1[cpu])) {
279 + ret = PTR_ERR(drv->opp_tables1[cpu]);
280 + dev_err(cpu_dev, "Failed to add OPP name %s\n",
281 + pvs_name);
282 + goto free_opp;
283 + }
284 + }
285 +
286 + drv->opp_tables2[cpu] = dev_pm_opp_set_supported_hw(cpu_dev,
287 &drv->versions, 1);
288 - if (IS_ERR(drv->opp_tables[cpu])) {
289 - ret = PTR_ERR(drv->opp_tables[cpu]);
290 + if (IS_ERR(drv->opp_tables2[cpu])) {
291 + ret = PTR_ERR(drv->opp_tables2[cpu]);
292 dev_err(cpu_dev,
293 "Failed to set supported hardware\n");
294 goto free_opp;
295 @@ -220,11 +349,18 @@ static int qcom_cpufreq_probe(struct pla
296
297 free_opp:
298 for_each_possible_cpu(cpu) {
299 - if (IS_ERR_OR_NULL(drv->opp_tables[cpu]))
300 + if (IS_ERR_OR_NULL(drv->opp_tables1[cpu]))
301 break;
302 - dev_pm_opp_put_supported_hw(drv->opp_tables[cpu]);
303 + dev_pm_opp_put_prop_name(drv->opp_tables1[cpu]);
304 }
305 - kfree(drv->opp_tables);
306 + for_each_possible_cpu(cpu) {
307 + if (IS_ERR_OR_NULL(drv->opp_tables2[cpu]))
308 + break;
309 + dev_pm_opp_put_supported_hw(drv->opp_tables2[cpu]);
310 + }
311 + kfree(drv->opp_tables2);
312 +free_opp1:
313 + kfree(drv->opp_tables1);
314 free_drv:
315 kfree(drv);
316
317 @@ -239,10 +375,14 @@ static int qcom_cpufreq_remove(struct pl
318 platform_device_unregister(cpufreq_dt_pdev);
319
320 for_each_possible_cpu(cpu)
321 - if (drv->opp_tables[cpu])
322 - dev_pm_opp_put_supported_hw(drv->opp_tables[cpu]);
323 + if (drv->opp_tables1[cpu])
324 + dev_pm_opp_put_prop_name(drv->opp_tables1[cpu]);
325 + for_each_possible_cpu(cpu)
326 + if (drv->opp_tables2[cpu])
327 + dev_pm_opp_put_supported_hw(drv->opp_tables2[cpu]);
328
329 - kfree(drv->opp_tables);
330 + kfree(drv->opp_tables1);
331 + kfree(drv->opp_tables2);
332 kfree(drv);
333
334 return 0;
335 @@ -259,6 +399,10 @@ static struct platform_driver qcom_cpufr
336 static const struct of_device_id qcom_cpufreq_match_list[] __initconst = {
337 { .compatible = "qcom,apq8096", .data = &match_data_kryo },
338 { .compatible = "qcom,msm8996", .data = &match_data_kryo },
339 + { .compatible = "qcom,ipq8064", .data = &match_data_krait },
340 + { .compatible = "qcom,apq8064", .data = &match_data_krait },
341 + { .compatible = "qcom,msm8974", .data = &match_data_krait },
342 + { .compatible = "qcom,msm8960", .data = &match_data_krait },
343 {},
344 };
345