ipq806x: rework L2 cache patch
[openwrt/openwrt.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 @@ -134,7 +134,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 @@ -138,6 +138,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 @@ -49,12 +49,14 @@ 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 const char **genpd_names;
76 };
77
78 struct qcom_cpufreq_drv {
79 - struct opp_table **opp_tables;
80 + struct opp_table **opp_tables1;
81 + struct opp_table **opp_tables2;
82 struct opp_table **genpd_opp_tables;
83 u32 versions;
84 const struct qcom_cpufreq_match_data *data;
85 @@ -62,6 +64,79 @@ struct qcom_cpufreq_drv {
86
87 static struct platform_device *cpufreq_dt_pdev, *cpufreq_pdev;
88
89 +static void get_krait_bin_format_a(int *speed, int *pvs, int *pvs_ver,
90 + struct nvmem_cell *pvs_nvmem, u8 *buf)
91 +{
92 + u32 pte_efuse;
93 +
94 + pte_efuse = *((u32 *)buf);
95 +
96 + *speed = pte_efuse & 0xf;
97 + if (*speed == 0xf)
98 + *speed = (pte_efuse >> 4) & 0xf;
99 +
100 + if (*speed == 0xf) {
101 + *speed = 0;
102 + pr_warn("Speed bin: Defaulting to %d\n", *speed);
103 + } else {
104 + pr_info("Speed bin: %d\n", *speed);
105 + }
106 +
107 + *pvs = (pte_efuse >> 10) & 0x7;
108 + if (*pvs == 0x7)
109 + *pvs = (pte_efuse >> 13) & 0x7;
110 +
111 + if (*pvs == 0x7) {
112 + *pvs = 0;
113 + pr_warn("PVS bin: Defaulting to %d\n", *pvs);
114 + } else {
115 + pr_info("PVS bin: %d\n", *pvs);
116 + }
117 +}
118 +
119 +static void get_krait_bin_format_b(int *speed, int *pvs, int *pvs_ver,
120 + struct nvmem_cell *pvs_nvmem, u8 *buf)
121 +{
122 + u32 pte_efuse, redundant_sel;
123 +
124 + pte_efuse = *((u32 *)buf);
125 + redundant_sel = (pte_efuse >> 24) & 0x7;
126 + *speed = pte_efuse & 0x7;
127 +
128 + /* 4 bits of PVS are in efuse register bits 31, 8-6. */
129 + *pvs = ((pte_efuse >> 28) & 0x8) | ((pte_efuse >> 6) & 0x7);
130 + *pvs_ver = (pte_efuse >> 4) & 0x3;
131 +
132 + switch (redundant_sel) {
133 + case 1:
134 + *speed = (pte_efuse >> 27) & 0xf;
135 + break;
136 + case 2:
137 + *pvs = (pte_efuse >> 27) & 0xf;
138 + break;
139 + }
140 +
141 + /* Check SPEED_BIN_BLOW_STATUS */
142 + if (pte_efuse & BIT(3)) {
143 + pr_info("Speed bin: %d\n", *speed);
144 + } else {
145 + pr_warn("Speed bin not set. Defaulting to 0!\n");
146 + *speed = 0;
147 + }
148 +
149 + /* Check PVS_BLOW_STATUS */
150 + pte_efuse = *(((u32 *)buf) + 4);
151 + pte_efuse &= BIT(21);
152 + if (pte_efuse) {
153 + pr_info("PVS bin: %d\n", *pvs);
154 + } else {
155 + pr_warn("PVS bin not set. Defaulting to 0!\n");
156 + *pvs = 0;
157 + }
158 +
159 + pr_info("PVS version: %d\n", *pvs_ver);
160 +}
161 +
162 static enum _msm8996_version qcom_cpufreq_get_msm_id(void)
163 {
164 size_t len;
165 @@ -93,11 +168,13 @@ static enum _msm8996_version qcom_cpufre
166
167 static int qcom_cpufreq_kryo_name_version(struct device *cpu_dev,
168 struct nvmem_cell *speedbin_nvmem,
169 + char **pvs_name,
170 struct qcom_cpufreq_drv *drv)
171 {
172 size_t len;
173 u8 *speedbin;
174 enum _msm8996_version msm8996_version;
175 + *pvs_name = NULL;
176
177 msm8996_version = qcom_cpufreq_get_msm_id();
178 if (NUM_OF_MSM8996_VERSIONS == msm8996_version) {
179 @@ -125,10 +202,44 @@ static int qcom_cpufreq_kryo_name_versio
180 return 0;
181 }
182
183 +static int qcom_cpufreq_krait_name_version(struct device *cpu_dev,
184 + struct nvmem_cell *speedbin_nvmem,
185 + char **pvs_name,
186 + struct qcom_cpufreq_drv *drv)
187 +{
188 + int speed = 0, pvs = 0, pvs_ver = 0;
189 + u8 *speedbin;
190 + size_t len;
191 +
192 + speedbin = nvmem_cell_read(speedbin_nvmem, &len);
193 + if (len == 4) {
194 + get_krait_bin_format_a(&speed, &pvs, &pvs_ver,
195 + speedbin_nvmem, speedbin);
196 + } else if (len == 8) {
197 + get_krait_bin_format_b(&speed, &pvs, &pvs_ver,
198 + speedbin_nvmem, speedbin);
199 + } else {
200 + dev_err(cpu_dev, "Unable to read nvmem data. Defaulting to 0!\n");
201 + return -ENODEV;
202 + }
203 +
204 + snprintf(*pvs_name, sizeof("speedXX-pvsXX-vXX"), "speed%d-pvs%d-v%d",
205 + speed, pvs, pvs_ver);
206 +
207 + drv->versions = (1 << speed);
208 +
209 + kfree(speedbin);
210 + return 0;
211 +}
212 +
213 static const struct qcom_cpufreq_match_data match_data_kryo = {
214 .get_version = qcom_cpufreq_kryo_name_version,
215 };
216
217 +static const struct qcom_cpufreq_match_data match_data_krait = {
218 + .get_version = qcom_cpufreq_krait_name_version,
219 +};
220 +
221 static const char *qcs404_genpd_names[] = { "cpr", NULL };
222
223 static const struct qcom_cpufreq_match_data match_data_qcs404 = {
224 @@ -141,6 +252,7 @@ static int qcom_cpufreq_probe(struct pla
225 struct nvmem_cell *speedbin_nvmem;
226 struct device_node *np;
227 struct device *cpu_dev;
228 + char *pvs_name = "speedXX-pvsXX-vXX";
229 unsigned cpu;
230 const struct of_device_id *match;
231 int ret;
232 @@ -153,7 +265,7 @@ static int qcom_cpufreq_probe(struct pla
233 if (!np)
234 return -ENOENT;
235
236 - ret = of_device_is_compatible(np, "operating-points-v2-kryo-cpu");
237 + ret = of_device_is_compatible(np, "operating-points-v2-qcom-cpu");
238 if (!ret) {
239 of_node_put(np);
240 return -ENOENT;
241 @@ -181,7 +293,7 @@ static int qcom_cpufreq_probe(struct pla
242 goto free_drv;
243 }
244
245 - ret = drv->data->get_version(cpu_dev, speedbin_nvmem, drv);
246 + ret = drv->data->get_version(cpu_dev, speedbin_nvmem, &pvs_name, drv);
247 if (ret) {
248 nvmem_cell_put(speedbin_nvmem);
249 goto free_drv;
250 @@ -190,12 +302,18 @@ static int qcom_cpufreq_probe(struct pla
251 }
252 of_node_put(np);
253
254 - drv->opp_tables = kcalloc(num_possible_cpus(), sizeof(*drv->opp_tables),
255 + drv->opp_tables1 = kcalloc(num_possible_cpus(), sizeof(*drv->opp_tables1),
256 GFP_KERNEL);
257 - if (!drv->opp_tables) {
258 + if (!drv->opp_tables1) {
259 ret = -ENOMEM;
260 goto free_drv;
261 }
262 + drv->opp_tables2 = kcalloc(num_possible_cpus(), sizeof(*drv->opp_tables2),
263 + GFP_KERNEL);
264 + if (!drv->opp_tables2) {
265 + ret = -ENOMEM;
266 + goto free_opp1;
267 + }
268
269 drv->genpd_opp_tables = kcalloc(num_possible_cpus(),
270 sizeof(*drv->genpd_opp_tables),
271 @@ -213,11 +331,22 @@ static int qcom_cpufreq_probe(struct pla
272 }
273
274 if (drv->data->get_version) {
275 - drv->opp_tables[cpu] =
276 - dev_pm_opp_set_supported_hw(cpu_dev,
277 +
278 + if (pvs_name) {
279 + drv->opp_tables1[cpu] = dev_pm_opp_set_prop_name(cpu_dev,
280 + pvs_name);
281 + if (IS_ERR(drv->opp_tables1[cpu])) {
282 + ret = PTR_ERR(drv->opp_tables1[cpu]);
283 + dev_err(cpu_dev, "Failed to add OPP name %s\n",
284 + pvs_name);
285 + goto free_opp;
286 + }
287 + }
288 +
289 + drv->opp_tables2[cpu] = dev_pm_opp_set_supported_hw(cpu_dev,
290 &drv->versions, 1);
291 - if (IS_ERR(drv->opp_tables[cpu])) {
292 - ret = PTR_ERR(drv->opp_tables[cpu]);
293 + if (IS_ERR(drv->opp_tables2[cpu])) {
294 + ret = PTR_ERR(drv->opp_tables2[cpu]);
295 dev_err(cpu_dev,
296 "Failed to set supported hardware\n");
297 goto free_genpd_opp;
298 @@ -259,11 +388,18 @@ free_genpd_opp:
299 kfree(drv->genpd_opp_tables);
300 free_opp:
301 for_each_possible_cpu(cpu) {
302 - if (IS_ERR_OR_NULL(drv->opp_tables[cpu]))
303 + if (IS_ERR_OR_NULL(drv->opp_tables1[cpu]))
304 + break;
305 + dev_pm_opp_put_prop_name(drv->opp_tables1[cpu]);
306 + }
307 + for_each_possible_cpu(cpu) {
308 + if (IS_ERR_OR_NULL(drv->opp_tables2[cpu]))
309 break;
310 - dev_pm_opp_put_supported_hw(drv->opp_tables[cpu]);
311 + dev_pm_opp_put_supported_hw(drv->opp_tables2[cpu]);
312 }
313 - kfree(drv->opp_tables);
314 + kfree(drv->opp_tables2);
315 +free_opp1:
316 + kfree(drv->opp_tables1);
317 free_drv:
318 kfree(drv);
319
320 @@ -278,13 +414,16 @@ static int qcom_cpufreq_remove(struct pl
321 platform_device_unregister(cpufreq_dt_pdev);
322
323 for_each_possible_cpu(cpu) {
324 - if (drv->opp_tables[cpu])
325 - dev_pm_opp_put_supported_hw(drv->opp_tables[cpu]);
326 + if (drv->opp_tables1[cpu])
327 + dev_pm_opp_put_supported_hw(drv->opp_tables1[cpu]);
328 + if (drv->opp_tables2[cpu])
329 + dev_pm_opp_put_supported_hw(drv->opp_tables2[cpu]);
330 if (drv->genpd_opp_tables[cpu])
331 dev_pm_opp_detach_genpd(drv->genpd_opp_tables[cpu]);
332 }
333
334 - kfree(drv->opp_tables);
335 + kfree(drv->opp_tables1);
336 + kfree(drv->opp_tables2);
337 kfree(drv->genpd_opp_tables);
338 kfree(drv);
339
340 @@ -303,6 +442,10 @@ static const struct of_device_id qcom_cp
341 { .compatible = "qcom,apq8096", .data = &match_data_kryo },
342 { .compatible = "qcom,msm8996", .data = &match_data_kryo },
343 { .compatible = "qcom,qcs404", .data = &match_data_qcs404 },
344 + { .compatible = "qcom,ipq8064", .data = &match_data_krait },
345 + { .compatible = "qcom,apq8064", .data = &match_data_krait },
346 + { .compatible = "qcom,msm8974", .data = &match_data_krait },
347 + { .compatible = "qcom,msm8960", .data = &match_data_krait },
348 {},
349 };
350