blob: 77e8bf4b98959814fc15cd6d70f7c4a82fb6ecbd [file] [log] [blame]
David Collins7370f1a2017-01-18 16:21:53 -08001/*
2 * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14#define pr_fmt(fmt) "%s: " fmt, __func__
15
16#include <linux/bitops.h>
17#include <linux/debugfs.h>
18#include <linux/err.h>
19#include <linux/init.h>
20#include <linux/interrupt.h>
21#include <linux/io.h>
22#include <linux/kernel.h>
23#include <linux/list.h>
24#include <linux/module.h>
25#include <linux/of.h>
26#include <linux/of_device.h>
27#include <linux/platform_device.h>
28#include <linux/pm_opp.h>
29#include <linux/slab.h>
30#include <linux/string.h>
31#include <linux/uaccess.h>
32#include <linux/regulator/driver.h>
33#include <linux/regulator/machine.h>
34#include <linux/regulator/of_regulator.h>
35#include <linux/regulator/msm-ldo-regulator.h>
36
37#include "cpr3-regulator.h"
38
39#define MSM8996_HMSS_FUSE_CORNERS 5
40
41/**
42 * struct cpr3_msm8996_hmss_fuses - HMSS specific fuse data for MSM8996
43 * @ro_sel: Ring oscillator select fuse parameter value for each
44 * fuse corner
45 * @init_voltage: Initial (i.e. open-loop) voltage fuse parameter value
46 * for each fuse corner (raw, not converted to a voltage)
47 * @target_quot: CPR target quotient fuse parameter value for each fuse
48 * corner
49 * @quot_offset: CPR target quotient offset fuse parameter value for each
50 * fuse corner (raw, not unpacked) used for target quotient
51 * interpolation
52 * @speed_bin: Application processor speed bin fuse parameter value for
53 * the given chip
54 * @cbf_voltage_offset: Voltage margin offset for the CBF regulator used on
55 * MSM8996-Pro chips.
56 * @cpr_fusing_rev: CPR fusing revision fuse parameter value
57 * @redundant_fusing: Redundant fusing select fuse parameter value
58 * @limitation: CPR limitation select fuse parameter value
59 * @partial_binning: Chip partial binning fuse parameter value which defines
60 * limitations found on a given chip
61 * @vdd_mx_ret_fuse: Defines the logic retention voltage of VDD_MX
62 * @vdd_apcc_ret_fuse: Defines the logic retention voltage of VDD_APCC
63 * @aging_init_quot_diff: Initial quotient difference between CPR aging
64 * min and max sensors measured at time of manufacturing
65 *
66 * This struct holds the values for all of the fuses read from memory. The
67 * values for ro_sel, init_voltage, target_quot, and quot_offset come from
68 * either the primary or redundant fuse locations depending upon the value of
69 * redundant_fusing.
70 */
71struct cpr3_msm8996_hmss_fuses {
72 u64 ro_sel[MSM8996_HMSS_FUSE_CORNERS];
73 u64 init_voltage[MSM8996_HMSS_FUSE_CORNERS];
74 u64 target_quot[MSM8996_HMSS_FUSE_CORNERS];
75 u64 quot_offset[MSM8996_HMSS_FUSE_CORNERS];
76 u64 cbf_voltage_offset[MSM8996_HMSS_FUSE_CORNERS];
77 u64 speed_bin;
78 u64 cpr_fusing_rev;
79 u64 redundant_fusing;
80 u64 limitation;
81 u64 partial_binning;
82 u64 vdd_mx_ret_fuse;
83 u64 vdd_apcc_ret_fuse;
84 u64 aging_init_quot_diff;
85};
86
87/*
88 * Fuse combos 0 - 7 map to CPR fusing revision 0 - 7 with speed bin fuse = 0.
89 * Fuse combos 8 - 15 map to CPR fusing revision 0 - 7 with speed bin fuse = 1.
90 */
91#define CPR3_MSM8996_HMSS_FUSE_COMBO_COUNT 16
92
93/*
94 * Constants which define the name of each fuse corner. Note that no actual
95 * fuses are defined for LowSVS. However, a mapping from corner to LowSVS
96 * is required in order to perform target quotient interpolation properly.
97 */
98enum cpr3_msm8996_hmss_fuse_corner {
99 CPR3_MSM8996_HMSS_FUSE_CORNER_MINSVS = 0,
100 CPR3_MSM8996_HMSS_FUSE_CORNER_LOWSVS = 1,
101 CPR3_MSM8996_HMSS_FUSE_CORNER_SVS = 2,
102 CPR3_MSM8996_HMSS_FUSE_CORNER_NOM = 3,
103 CPR3_MSM8996_HMSS_FUSE_CORNER_TURBO = 4,
104};
105
106static const char * const cpr3_msm8996_hmss_fuse_corner_name[] = {
107 [CPR3_MSM8996_HMSS_FUSE_CORNER_MINSVS] = "MinSVS",
108 [CPR3_MSM8996_HMSS_FUSE_CORNER_LOWSVS] = "LowSVS",
109 [CPR3_MSM8996_HMSS_FUSE_CORNER_SVS] = "SVS",
110 [CPR3_MSM8996_HMSS_FUSE_CORNER_NOM] = "NOM",
111 [CPR3_MSM8996_HMSS_FUSE_CORNER_TURBO] = "TURBO",
112};
113
114/* CPR3 hardware thread IDs */
115#define MSM8996_HMSS_POWER_CLUSTER_THREAD_ID 0
116#define MSM8996_HMSS_PERFORMANCE_CLUSTER_THREAD_ID 1
117
118/*
119 * MSM8996 HMSS fuse parameter locations:
120 *
121 * Structs are organized with the following dimensions:
122 * Outer: 0 or 1 for power or performance cluster
123 * Middle: 0 to 3 for fuse corners from lowest to highest corner
124 * Inner: large enough to hold the longest set of parameter segments which
125 * fully defines a fuse parameter, +1 (for NULL termination).
126 * Each segment corresponds to a contiguous group of bits from a
127 * single fuse row. These segments are concatentated together in
128 * order to form the full fuse parameter value. The segments for
129 * a given parameter may correspond to different fuse rows.
130 *
131 * Note that there are only physically 4 sets of fuse parameters which
132 * correspond to the MinSVS, SVS, NOM, and TURBO fuse corners. However, the SVS
133 * quotient offset fuse is used to define the target quotient for the LowSVS
134 * fuse corner. In order to utilize LowSVS, it must be treated as if it were a
135 * real fully defined fuse corner. Thus, LowSVS fuse parameter locations are
136 * specified. These locations duplicate the SVS values in order to simplify
137 * interpolation logic.
138 */
139static const struct cpr3_fuse_param
140msm8996_hmss_ro_sel_param[2][MSM8996_HMSS_FUSE_CORNERS][2] = {
141 [MSM8996_HMSS_POWER_CLUSTER_THREAD_ID] = {
142 {{66, 38, 41}, {} },
143 {{66, 38, 41}, {} },
144 {{66, 38, 41}, {} },
145 {{66, 34, 37}, {} },
146 {{66, 30, 33}, {} },
147 },
148 [MSM8996_HMSS_PERFORMANCE_CLUSTER_THREAD_ID] = {
149 {{64, 54, 57}, {} },
150 {{64, 54, 57}, {} },
151 {{64, 54, 57}, {} },
152 {{64, 50, 53}, {} },
153 {{64, 46, 49}, {} },
154 },
155};
156
157static const struct cpr3_fuse_param
158msm8996_hmss_init_voltage_param[2][MSM8996_HMSS_FUSE_CORNERS][3] = {
159 [MSM8996_HMSS_POWER_CLUSTER_THREAD_ID] = {
160 {{67, 0, 5}, {} },
161 {{66, 58, 63}, {} },
162 {{66, 58, 63}, {} },
163 {{66, 52, 57}, {} },
164 {{66, 46, 51}, {} },
165 },
166 [MSM8996_HMSS_PERFORMANCE_CLUSTER_THREAD_ID] = {
167 {{65, 16, 21}, {} },
168 {{65, 10, 15}, {} },
169 {{65, 10, 15}, {} },
170 {{65, 4, 9}, {} },
171 {{64, 62, 63}, {65, 0, 3}, {} },
172 },
173};
174
175static const struct cpr3_fuse_param
176msm8996_hmss_target_quot_param[2][MSM8996_HMSS_FUSE_CORNERS][3] = {
177 [MSM8996_HMSS_POWER_CLUSTER_THREAD_ID] = {
178 {{67, 42, 53}, {} },
179 {{67, 30, 41}, {} },
180 {{67, 30, 41}, {} },
181 {{67, 18, 29}, {} },
182 {{67, 6, 17}, {} },
183 },
184 [MSM8996_HMSS_PERFORMANCE_CLUSTER_THREAD_ID] = {
185 {{65, 58, 63}, {66, 0, 5}, {} },
186 {{65, 46, 57}, {} },
187 {{65, 46, 57}, {} },
188 {{65, 34, 45}, {} },
189 {{65, 22, 33}, {} },
190 },
191};
192
193static const struct cpr3_fuse_param
194msm8996_hmss_quot_offset_param[2][MSM8996_HMSS_FUSE_CORNERS][3] = {
195 [MSM8996_HMSS_POWER_CLUSTER_THREAD_ID] = {
196 {{} },
197 {{} },
198 {{68, 6, 13}, {} },
199 {{67, 62, 63}, {68, 0, 5}, {} },
200 {{67, 54, 61}, {} },
201 },
202 [MSM8996_HMSS_PERFORMANCE_CLUSTER_THREAD_ID] = {
203 {{} },
204 {{} },
205 {{66, 22, 29}, {} },
206 {{66, 14, 21}, {} },
207 {{66, 6, 13}, {} },
208 },
209};
210
211/*
212 * This fuse is used to define if the redundant set of fuses should be used for
213 * any particular feature. CPR is one such feature. The redundant CPR fuses
214 * should be used if this fuse parameter has a value of 1.
215 */
216static const struct cpr3_fuse_param msm8996_redundant_fusing_param[] = {
217 {73, 61, 63},
218 {},
219};
220#define MSM8996_CPR_REDUNDANT_FUSING 1
221
222static const struct cpr3_fuse_param
223msm8996_hmss_redun_ro_sel_param[2][MSM8996_HMSS_FUSE_CORNERS][2] = {
224 [MSM8996_HMSS_POWER_CLUSTER_THREAD_ID] = {
225 {{76, 36, 39}, {} },
226 {{76, 32, 35}, {} },
227 {{76, 32, 35}, {} },
228 {{76, 28, 31}, {} },
229 {{76, 24, 27}, {} },
230 },
231 [MSM8996_HMSS_PERFORMANCE_CLUSTER_THREAD_ID] = {
232 {{74, 52, 55}, {} },
233 {{74, 48, 51}, {} },
234 {{74, 48, 51}, {} },
235 {{74, 44, 47}, {} },
236 {{74, 40, 43}, {} },
237 },
238};
239
240static const struct cpr3_fuse_param
241msm8996_hmss_redun_init_voltage_param[2][MSM8996_HMSS_FUSE_CORNERS][3] = {
242 [MSM8996_HMSS_POWER_CLUSTER_THREAD_ID] = {
243 {{76, 58, 63}, {} },
244 {{76, 52, 57}, {} },
245 {{76, 52, 57}, {} },
246 {{76, 46, 51}, {} },
247 {{76, 40, 45}, {} },
248 },
249 [MSM8996_HMSS_PERFORMANCE_CLUSTER_THREAD_ID] = {
250 {{75, 10, 15}, {} },
251 {{75, 4, 9}, {} },
252 {{75, 4, 9}, {} },
253 {{74, 62, 63}, {75, 0, 3}, {} },
254 {{74, 56, 61}, {} },
255 },
256};
257
258static const struct cpr3_fuse_param
259msm8996_hmss_redun_target_quot_param[2][MSM8996_HMSS_FUSE_CORNERS][2] = {
260 [MSM8996_HMSS_POWER_CLUSTER_THREAD_ID] = {
261 {{77, 36, 47}, {} },
262 {{77, 24, 35}, {} },
263 {{77, 24, 35}, {} },
264 {{77, 12, 23}, {} },
265 {{77, 0, 11}, {} },
266 },
267 [MSM8996_HMSS_PERFORMANCE_CLUSTER_THREAD_ID] = {
268 {{75, 52, 63}, {} },
269 {{75, 40, 51}, {} },
270 {{75, 40, 51}, {} },
271 {{75, 28, 39}, {} },
272 {{75, 16, 27}, {} },
273 },
274};
275
276static const struct cpr3_fuse_param
277msm8996_hmss_redun_quot_offset_param[2][MSM8996_HMSS_FUSE_CORNERS][2] = {
278 [MSM8996_HMSS_POWER_CLUSTER_THREAD_ID] = {
279 {{} },
280 {{} },
281 {{68, 11, 18}, {} },
282 {{77, 56, 63}, {} },
283 {{77, 48, 55}, {} },
284 },
285 [MSM8996_HMSS_PERFORMANCE_CLUSTER_THREAD_ID] = {
286 {{} },
287 {{} },
288 {{76, 16, 23}, {} },
289 {{76, 8, 15}, {} },
290 {{76, 0, 7}, {} },
291 },
292};
293
294static const struct cpr3_fuse_param msm8996_cpr_fusing_rev_param[] = {
295 {39, 51, 53},
296 {},
297};
298
299static const struct cpr3_fuse_param msm8996_hmss_speed_bin_param[] = {
300 {38, 29, 31},
301 {},
302};
303
304static const struct cpr3_fuse_param msm8996_cpr_limitation_param[] = {
305 {41, 31, 32},
306 {},
307};
308
309static const struct cpr3_fuse_param msm8996_vdd_mx_ret_param[] = {
310 {41, 2, 4},
311 {},
312};
313
314static const struct cpr3_fuse_param msm8996_vdd_apcc_ret_param[] = {
315 {41, 52, 54},
316 {},
317};
318
319static const struct cpr3_fuse_param msm8996_cpr_partial_binning_param[] = {
320 {39, 55, 59},
321 {},
322};
323
324static const struct cpr3_fuse_param
325msm8996_hmss_aging_init_quot_diff_param[] = {
326 {68, 14, 19},
327 {},
328};
329
330static const struct cpr3_fuse_param
331msm8996pro_hmss_voltage_offset_param[MSM8996_HMSS_FUSE_CORNERS][4] = {
332 {{68, 50, 52}, {41, 63, 63}, {} },
333 {{62, 30, 31}, {62, 63, 63}, {66, 45, 45}, {} },
334 {{61, 35, 36}, {61, 62, 63}, {} },
335 {{61, 26, 26}, {61, 32, 34}, {} },
336 {{61, 22, 25}, {} },
337};
338
339#define MSM8996PRO_SOC_ID 4
340
341/*
342 * Some initial msm8996 parts cannot be used in a meaningful way by software.
343 * Other parts can only be used when operating with CPR disabled (i.e. at the
344 * fused open-loop voltage) when no voltage interpolation is applied. A fuse
345 * parameter is provided so that software can properly handle these limitations.
346 */
347enum msm8996_cpr_limitation {
348 MSM8996_CPR_LIMITATION_NONE = 0,
349 MSM8996_CPR_LIMITATION_UNSUPPORTED = 2,
350 MSM8996_CPR_LIMITATION_NO_CPR_OR_INTERPOLATION = 3,
351};
352
353/*
354 * Some initial msm8996 parts cannot be operated at low voltages. A fuse
355 * parameter is provided so that software can properly handle these limitations.
356 */
357enum msm8996_cpr_partial_binning {
358 MSM8996_CPR_PARTIAL_BINNING_SVS = 11,
359 MSM8996_CPR_PARTIAL_BINNING_NOM = 12,
360};
361
362/* Additional MSM8996 specific data: */
363
364/* Open loop voltage fuse reference voltages in microvolts for MSM8996 v1/v2 */
365static const int msm8996_v1_v2_hmss_fuse_ref_volt[MSM8996_HMSS_FUSE_CORNERS] = {
366 605000,
367 745000, /* Place holder entry for LowSVS */
368 745000,
369 905000,
370 1015000,
371};
372
373/* Open loop voltage fuse reference voltages in microvolts for MSM8996 v3 */
374static const int msm8996_v3_hmss_fuse_ref_volt[MSM8996_HMSS_FUSE_CORNERS] = {
375 605000,
376 745000, /* Place holder entry for LowSVS */
377 745000,
378 905000,
379 1140000,
380};
381
382/*
383 * Open loop voltage fuse reference voltages in microvolts for MSM8996 v3 with
384 * speed_bin == 1 and cpr_fusing_rev >= 5.
385 */
386static const int msm8996_v3_speed_bin1_rev5_hmss_fuse_ref_volt[
387 MSM8996_HMSS_FUSE_CORNERS] = {
388 605000,
389 745000, /* Place holder entry for LowSVS */
390 745000,
391 905000,
392 1040000,
393};
394
395/* Defines mapping from retention fuse values to voltages in microvolts */
396static const int msm8996_vdd_apcc_fuse_ret_volt[] = {
397 600000, 550000, 500000, 450000, 400000, 350000, 300000, 600000,
398};
399
400static const int msm8996_vdd_mx_fuse_ret_volt[] = {
401 700000, 650000, 580000, 550000, 490000, 490000, 490000, 490000,
402};
403
404#define MSM8996_HMSS_FUSE_STEP_VOLT 10000
405#define MSM8996_HMSS_VOLTAGE_FUSE_SIZE 6
406#define MSM8996PRO_HMSS_CBF_FUSE_STEP_VOLT 10000
407#define MSM8996PRO_HMSS_CBF_VOLTAGE_FUSE_SIZE 4
408#define MSM8996_HMSS_QUOT_OFFSET_SCALE 5
409#define MSM8996_HMSS_AGING_INIT_QUOT_DIFF_SCALE 2
410#define MSM8996_HMSS_AGING_INIT_QUOT_DIFF_SIZE 6
411
412#define MSM8996_HMSS_CPR_SENSOR_COUNT 25
413#define MSM8996_HMSS_THREAD0_SENSOR_MIN 0
414#define MSM8996_HMSS_THREAD0_SENSOR_MAX 14
415#define MSM8996_HMSS_THREAD1_SENSOR_MIN 15
416#define MSM8996_HMSS_THREAD1_SENSOR_MAX 24
417
418#define MSM8996_HMSS_CPR_CLOCK_RATE 19200000
419
420#define MSM8996_HMSS_AGING_SENSOR_ID 11
421#define MSM8996_HMSS_AGING_BYPASS_MASK0 (GENMASK(7, 0) & ~BIT(3))
422
423/**
424 * cpr3_msm8996_hmss_use_voltage_offset_fuse() - return if this part utilizes
425 * voltage offset fuses or not
426 * @vreg: Pointer to the CPR3 regulator
427 *
428 * Return: true if this part utilizes voltage offset fuses, else false
429 */
430static inline bool cpr3_msm8996_hmss_use_voltage_offset_fuse(
431 struct cpr3_regulator *vreg)
432{
433 struct cpr3_msm8996_hmss_fuses *fuse = vreg->platform_fuses;
434
435 return vreg->thread->ctrl->soc_revision == MSM8996PRO_SOC_ID
436 && fuse->cpr_fusing_rev >= 1
437 && of_property_read_bool(vreg->of_node, "qcom,is-cbf-regulator");
438}
439
440/**
441 * cpr3_msm8996_hmss_read_fuse_data() - load HMSS specific fuse parameter values
442 * @vreg: Pointer to the CPR3 regulator
443 *
444 * This function allocates a cpr3_msm8996_hmss_fuses struct, fills it with
445 * values read out of hardware fuses, and finally copies common fuse values
446 * into the CPR3 regulator struct.
447 *
448 * Return: 0 on success, errno on failure
449 */
450static int cpr3_msm8996_hmss_read_fuse_data(struct cpr3_regulator *vreg)
451{
452 void __iomem *base = vreg->thread->ctrl->fuse_base;
453 struct cpr3_msm8996_hmss_fuses *fuse;
454 bool redundant;
455 int i, id, rc;
456
457 fuse = devm_kzalloc(vreg->thread->ctrl->dev, sizeof(*fuse), GFP_KERNEL);
458 if (!fuse)
459 return -ENOMEM;
460
461 rc = cpr3_read_fuse_param(base, msm8996_hmss_speed_bin_param,
462 &fuse->speed_bin);
463 if (rc) {
464 cpr3_err(vreg, "Unable to read speed bin fuse, rc=%d\n", rc);
465 return rc;
466 }
467 cpr3_info(vreg, "speed bin = %llu\n", fuse->speed_bin);
468
469 rc = cpr3_read_fuse_param(base, msm8996_cpr_fusing_rev_param,
470 &fuse->cpr_fusing_rev);
471 if (rc) {
472 cpr3_err(vreg, "Unable to read CPR fusing revision fuse, rc=%d\n",
473 rc);
474 return rc;
475 }
476 cpr3_info(vreg, "CPR fusing revision = %llu\n", fuse->cpr_fusing_rev);
477
478 rc = cpr3_read_fuse_param(base, msm8996_redundant_fusing_param,
479 &fuse->redundant_fusing);
480 if (rc) {
481 cpr3_err(vreg, "Unable to read redundant fusing config fuse, rc=%d\n",
482 rc);
483 return rc;
484 }
485
486 redundant = (fuse->redundant_fusing == MSM8996_CPR_REDUNDANT_FUSING);
487 cpr3_info(vreg, "using redundant fuses = %c\n",
488 redundant ? 'Y' : 'N');
489
490 rc = cpr3_read_fuse_param(base, msm8996_cpr_limitation_param,
491 &fuse->limitation);
492 if (rc) {
493 cpr3_err(vreg, "Unable to read CPR limitation fuse, rc=%d\n",
494 rc);
495 return rc;
496 }
497 cpr3_info(vreg, "CPR limitation = %s\n",
498 fuse->limitation == MSM8996_CPR_LIMITATION_UNSUPPORTED
499 ? "unsupported chip" : fuse->limitation
500 == MSM8996_CPR_LIMITATION_NO_CPR_OR_INTERPOLATION
501 ? "CPR disabled and no interpolation" : "none");
502
503 rc = cpr3_read_fuse_param(base, msm8996_cpr_partial_binning_param,
504 &fuse->partial_binning);
505 if (rc) {
506 cpr3_err(vreg, "Unable to read partial binning fuse, rc=%d\n",
507 rc);
508 return rc;
509 }
510 cpr3_info(vreg, "CPR partial binning limitation = %s\n",
511 fuse->partial_binning == MSM8996_CPR_PARTIAL_BINNING_SVS
512 ? "SVS min voltage"
513 : fuse->partial_binning == MSM8996_CPR_PARTIAL_BINNING_NOM
514 ? "NOM min voltage"
515 : "none");
516
517 rc = cpr3_read_fuse_param(base, msm8996_vdd_mx_ret_param,
518 &fuse->vdd_mx_ret_fuse);
519 if (rc) {
520 cpr3_err(vreg, "Unable to read VDD_MX retention fuse, rc=%d\n",
521 rc);
522 return rc;
523 }
524
525 rc = cpr3_read_fuse_param(base, msm8996_vdd_apcc_ret_param,
526 &fuse->vdd_apcc_ret_fuse);
527 if (rc) {
528 cpr3_err(vreg, "Unable to read VDD_APCC retention fuse, rc=%d\n",
529 rc);
530 return rc;
531 }
532
533 cpr3_info(vreg, "Retention voltage fuses: VDD_MX = %llu, VDD_APCC = %llu\n",
534 fuse->vdd_mx_ret_fuse, fuse->vdd_apcc_ret_fuse);
535
536 rc = cpr3_read_fuse_param(base, msm8996_hmss_aging_init_quot_diff_param,
537 &fuse->aging_init_quot_diff);
538 if (rc) {
539 cpr3_err(vreg, "Unable to read aging initial quotient difference fuse, rc=%d\n",
540 rc);
541 return rc;
542 }
543
544 id = vreg->thread->thread_id;
545
546 for (i = 0; i < MSM8996_HMSS_FUSE_CORNERS; i++) {
547 rc = cpr3_read_fuse_param(base,
548 redundant
549 ? msm8996_hmss_redun_init_voltage_param[id][i]
550 : msm8996_hmss_init_voltage_param[id][i],
551 &fuse->init_voltage[i]);
552 if (rc) {
553 cpr3_err(vreg, "Unable to read fuse-corner %d initial voltage fuse, rc=%d\n",
554 i, rc);
555 return rc;
556 }
557
558 rc = cpr3_read_fuse_param(base,
559 redundant
560 ? msm8996_hmss_redun_target_quot_param[id][i]
561 : msm8996_hmss_target_quot_param[id][i],
562 &fuse->target_quot[i]);
563 if (rc) {
564 cpr3_err(vreg, "Unable to read fuse-corner %d target quotient fuse, rc=%d\n",
565 i, rc);
566 return rc;
567 }
568
569 rc = cpr3_read_fuse_param(base,
570 redundant
571 ? msm8996_hmss_redun_ro_sel_param[id][i]
572 : msm8996_hmss_ro_sel_param[id][i],
573 &fuse->ro_sel[i]);
574 if (rc) {
575 cpr3_err(vreg, "Unable to read fuse-corner %d RO select fuse, rc=%d\n",
576 i, rc);
577 return rc;
578 }
579
580 rc = cpr3_read_fuse_param(base,
581 redundant
582 ? msm8996_hmss_redun_quot_offset_param[id][i]
583 : msm8996_hmss_quot_offset_param[id][i],
584 &fuse->quot_offset[i]);
585 if (rc) {
586 cpr3_err(vreg, "Unable to read fuse-corner %d quotient offset fuse, rc=%d\n",
587 i, rc);
588 return rc;
589 }
590 }
591
592 vreg->fuse_combo = fuse->cpr_fusing_rev + 8 * fuse->speed_bin;
593 if (vreg->fuse_combo >= CPR3_MSM8996_HMSS_FUSE_COMBO_COUNT) {
594 cpr3_err(vreg, "invalid CPR fuse combo = %d found\n",
595 vreg->fuse_combo);
596 return -EINVAL;
597 }
598
599 vreg->speed_bin_fuse = fuse->speed_bin;
600 vreg->cpr_rev_fuse = fuse->cpr_fusing_rev;
601 vreg->fuse_corner_count = MSM8996_HMSS_FUSE_CORNERS;
602 vreg->platform_fuses = fuse;
603
604 if (cpr3_msm8996_hmss_use_voltage_offset_fuse(vreg)) {
605 for (i = 0; i < MSM8996_HMSS_FUSE_CORNERS; i++) {
606 rc = cpr3_read_fuse_param(base,
607 msm8996pro_hmss_voltage_offset_param[i],
608 &fuse->cbf_voltage_offset[i]);
609 if (rc) {
610 cpr3_err(vreg, "Unable to read fuse-corner %d CBF voltage offset fuse, rc=%d\n",
611 i, rc);
612 return rc;
613 }
614 }
615 }
616
617 return 0;
618}
619
620/**
621 * cpr3_hmss_apply_fused_voltage_offset() - adjust the fused voltages for each
622 * fuse corner according to voltage offset fuse values
623 * @vreg: Pointer to the CPR3 regulator
624 * @fuse_volt: Pointer to an array of the fused voltage values; must
625 * have length equal to vreg->fuse_corner_count
626 *
627 * Voltage values in fuse_volt are modified in place.
628 *
629 * Return: 0 on success, errno on failure
630 */
631static int cpr3_hmss_apply_fused_voltage_offset(struct cpr3_regulator *vreg,
632 int *fuse_volt)
633{
634 struct cpr3_msm8996_hmss_fuses *fuse = vreg->platform_fuses;
635 int i;
636
637 if (!cpr3_msm8996_hmss_use_voltage_offset_fuse(vreg))
638 return 0;
639
640 for (i = 0; i < vreg->fuse_corner_count; i++)
641 fuse_volt[i] += cpr3_convert_open_loop_voltage_fuse(
642 0,
643 MSM8996PRO_HMSS_CBF_FUSE_STEP_VOLT,
644 fuse->cbf_voltage_offset[i],
645 MSM8996PRO_HMSS_CBF_VOLTAGE_FUSE_SIZE);
646
647 return 0;
648}
649
650/**
651 * cpr3_hmss_parse_corner_data() - parse HMSS corner data from device tree
652 * properties of the CPR3 regulator's device node
653 * @vreg: Pointer to the CPR3 regulator
654 *
655 * Return: 0 on success, errno on failure
656 */
657static int cpr3_hmss_parse_corner_data(struct cpr3_regulator *vreg)
658{
659 int rc;
660
661 rc = cpr3_parse_common_corner_data(vreg);
662 if (rc) {
663 cpr3_err(vreg, "error reading corner data, rc=%d\n", rc);
664 return rc;
665 }
666
667 return rc;
668}
669
670/**
671 * cpr3_msm8996_hmss_calculate_open_loop_voltages() - calculate the open-loop
672 * voltage for each corner of a CPR3 regulator
673 * @vreg: Pointer to the CPR3 regulator
674 *
675 * If open-loop voltage interpolation is allowed in both device tree and in
676 * hardware fuses, then this function calculates the open-loop voltage for a
677 * given corner using linear interpolation. This interpolation is performed
678 * using the processor frequencies of the lower and higher Fmax corners along
679 * with their fused open-loop voltages.
680 *
681 * If open-loop voltage interpolation is not allowed, then this function uses
682 * the Fmax fused open-loop voltage for all of the corners associated with a
683 * given fuse corner.
684 *
685 * Return: 0 on success, errno on failure
686 */
687static int cpr3_msm8996_hmss_calculate_open_loop_voltages(
688 struct cpr3_regulator *vreg)
689{
690 struct device_node *node = vreg->of_node;
691 struct cpr3_msm8996_hmss_fuses *fuse = vreg->platform_fuses;
692 int rc = 0;
693 bool allow_interpolation;
694 u64 freq_low, volt_low, freq_high, volt_high;
695 int i, j, soc_revision;
696 const int *ref_volt;
697 int *fuse_volt;
698 int *fmax_corner;
699
700 fuse_volt = kcalloc(vreg->fuse_corner_count, sizeof(*fuse_volt),
701 GFP_KERNEL);
702 fmax_corner = kcalloc(vreg->fuse_corner_count, sizeof(*fmax_corner),
703 GFP_KERNEL);
704 if (!fuse_volt || !fmax_corner) {
705 rc = -ENOMEM;
706 goto done;
707 }
708
709 soc_revision = vreg->thread->ctrl->soc_revision;
710 if (soc_revision == 1 || soc_revision == 2)
711 ref_volt = msm8996_v1_v2_hmss_fuse_ref_volt;
712 else if (soc_revision == 3 && fuse->speed_bin == 1
713 && fuse->cpr_fusing_rev >= 5)
714 ref_volt = msm8996_v3_speed_bin1_rev5_hmss_fuse_ref_volt;
715 else
716 ref_volt = msm8996_v3_hmss_fuse_ref_volt;
717
718 for (i = 0; i < vreg->fuse_corner_count; i++) {
719 fuse_volt[i] = cpr3_convert_open_loop_voltage_fuse(
720 ref_volt[i],
721 MSM8996_HMSS_FUSE_STEP_VOLT, fuse->init_voltage[i],
722 MSM8996_HMSS_VOLTAGE_FUSE_SIZE);
723
724 /* Log fused open-loop voltage values for debugging purposes. */
725 if (i != CPR3_MSM8996_HMSS_FUSE_CORNER_LOWSVS)
726 cpr3_info(vreg, "fused %6s: open-loop=%7d uV\n",
727 cpr3_msm8996_hmss_fuse_corner_name[i],
728 fuse_volt[i]);
729 }
730
731 if (cpr3_msm8996_hmss_use_voltage_offset_fuse(vreg)) {
732 rc = cpr3_hmss_apply_fused_voltage_offset(vreg, fuse_volt);
733 if (rc) {
734 cpr3_err(vreg, "could not apply CBF voltage offsets, rc=%d\n",
735 rc);
736 goto done;
737 }
738
739 for (i = 0; i < vreg->fuse_corner_count; i++)
740 cpr3_info(vreg, "fused %6s: CBF offset open-loop=%7d uV\n",
741 cpr3_msm8996_hmss_fuse_corner_name[i],
742 fuse_volt[i]);
743 }
744
745 rc = cpr3_adjust_fused_open_loop_voltages(vreg, fuse_volt);
746 if (rc) {
747 cpr3_err(vreg, "fused open-loop voltage adjustment failed, rc=%d\n",
748 rc);
749 goto done;
750 }
751
752 allow_interpolation = of_property_read_bool(node,
753 "qcom,allow-voltage-interpolation");
754
755 /*
756 * No LowSVS open-loop voltage fuse exists. Instead, intermediate
757 * voltages are interpolated between MinSVS and SVS. Set the LowSVS
758 * voltage to be equal to the adjusted SVS voltage in order to avoid
759 * triggering an incorrect condition violation in the following loop.
760 */
761 fuse_volt[CPR3_MSM8996_HMSS_FUSE_CORNER_LOWSVS]
762 = fuse_volt[CPR3_MSM8996_HMSS_FUSE_CORNER_SVS];
763
764 for (i = 1; i < vreg->fuse_corner_count; i++) {
765 if (fuse_volt[i] < fuse_volt[i - 1]) {
766 cpr3_debug(vreg, "fuse corner %d voltage=%d uV < fuse corner %d voltage=%d uV; overriding: fuse corner %d voltage=%d\n",
767 i, fuse_volt[i], i - 1, fuse_volt[i - 1],
768 i, fuse_volt[i - 1]);
769 fuse_volt[i] = fuse_volt[i - 1];
770 }
771 }
772
773 if (fuse->limitation == MSM8996_CPR_LIMITATION_NO_CPR_OR_INTERPOLATION)
774 allow_interpolation = false;
775
776 if (!allow_interpolation) {
777 /* Use fused open-loop voltage for lower frequencies. */
778 for (i = 0; i < vreg->corner_count; i++)
779 vreg->corner[i].open_loop_volt
780 = fuse_volt[vreg->corner[i].cpr_fuse_corner];
781 goto done;
782 }
783
784 for (i = 0; i < vreg->fuse_corner_count; i++)
785 fmax_corner[i] = vreg->fuse_corner_map[i];
786
787 /*
788 * Interpolation is not possible for corners mapped to the lowest fuse
789 * corner so use the fuse corner value directly.
790 */
791 for (i = 0; i <= fmax_corner[0]; i++)
792 vreg->corner[i].open_loop_volt = fuse_volt[0];
793
794 /*
795 * Interpolation is not possible for corners mapped above the highest
796 * fuse corner so use the fuse corner value directly.
797 */
798 j = vreg->fuse_corner_count - 1;
799 for (i = fmax_corner[j] + 1; i < vreg->corner_count; i++)
800 vreg->corner[i].open_loop_volt = fuse_volt[j];
801
802 /*
803 * Corner LowSVS should be skipped for voltage interpolation
804 * since no fuse exists for it. Instead, the lowest interpolation
805 * should be between MinSVS and SVS.
806 */
807 for (i = CPR3_MSM8996_HMSS_FUSE_CORNER_LOWSVS;
808 i < vreg->fuse_corner_count - 1; i++) {
809 fmax_corner[i] = fmax_corner[i + 1];
810 fuse_volt[i] = fuse_volt[i + 1];
811 }
812
813 /* Interpolate voltages for the higher fuse corners. */
814 for (i = 1; i < vreg->fuse_corner_count - 1; i++) {
815 freq_low = vreg->corner[fmax_corner[i - 1]].proc_freq;
816 volt_low = fuse_volt[i - 1];
817 freq_high = vreg->corner[fmax_corner[i]].proc_freq;
818 volt_high = fuse_volt[i];
819
820 for (j = fmax_corner[i - 1] + 1; j <= fmax_corner[i]; j++)
821 vreg->corner[j].open_loop_volt = cpr3_interpolate(
822 freq_low, volt_low, freq_high, volt_high,
823 vreg->corner[j].proc_freq);
824 }
825
826done:
827 if (rc == 0) {
828 cpr3_debug(vreg, "unadjusted per-corner open-loop voltages:\n");
829 for (i = 0; i < vreg->corner_count; i++)
830 cpr3_debug(vreg, "open-loop[%2d] = %d uV\n", i,
831 vreg->corner[i].open_loop_volt);
832
833 rc = cpr3_adjust_open_loop_voltages(vreg);
834 if (rc)
835 cpr3_err(vreg, "open-loop voltage adjustment failed, rc=%d\n",
836 rc);
837 }
838
839 kfree(fuse_volt);
840 kfree(fmax_corner);
841 return rc;
842}
843
844/**
845 * cpr3_msm8996_hmss_set_no_interpolation_quotients() - use the fused target
846 * quotient values for lower frequencies.
847 * @vreg: Pointer to the CPR3 regulator
848 * @volt_adjust: Pointer to array of per-corner closed-loop adjustment
849 * voltages
850 * @volt_adjust_fuse: Pointer to array of per-fuse-corner closed-loop
851 * adjustment voltages
852 * @ro_scale: Pointer to array of per-fuse-corner RO scaling factor
853 * values with units of QUOT/V
854 *
855 * Return: 0 on success, errno on failure
856 */
857static int cpr3_msm8996_hmss_set_no_interpolation_quotients(
858 struct cpr3_regulator *vreg, int *volt_adjust,
859 int *volt_adjust_fuse, int *ro_scale)
860{
861 struct cpr3_msm8996_hmss_fuses *fuse = vreg->platform_fuses;
862 u32 quot, ro;
863 int quot_adjust;
864 int i, fuse_corner;
865
866 for (i = 0; i < vreg->corner_count; i++) {
867 fuse_corner = vreg->corner[i].cpr_fuse_corner;
868 quot = fuse->target_quot[fuse_corner];
869 quot_adjust = cpr3_quot_adjustment(ro_scale[fuse_corner],
870 volt_adjust_fuse[fuse_corner] + volt_adjust[i]);
871 ro = fuse->ro_sel[fuse_corner];
872 vreg->corner[i].target_quot[ro] = quot + quot_adjust;
873 if (quot_adjust)
874 cpr3_debug(vreg, "adjusted corner %d RO%u target quot: %u --> %u (%d uV)\n",
875 i, ro, quot, vreg->corner[i].target_quot[ro],
876 volt_adjust_fuse[fuse_corner] + volt_adjust[i]);
877 }
878
879 return 0;
880}
881
882/**
883 * cpr3_msm8996_hmss_calculate_target_quotients() - calculate the CPR target
884 * quotient for each corner of a CPR3 regulator
885 * @vreg: Pointer to the CPR3 regulator
886 *
887 * If target quotient interpolation is allowed in both device tree and in
888 * hardware fuses, then this function calculates the target quotient for a
889 * given corner using linear interpolation. This interpolation is performed
890 * using the processor frequencies of the lower and higher Fmax corners along
891 * with the fused target quotient and quotient offset of the higher Fmax corner.
892 *
893 * If target quotient interpolation is not allowed, then this function uses
894 * the Fmax fused target quotient for all of the corners associated with a
895 * given fuse corner.
896 *
897 * Return: 0 on success, errno on failure
898 */
899static int cpr3_msm8996_hmss_calculate_target_quotients(
900 struct cpr3_regulator *vreg)
901{
902 struct cpr3_msm8996_hmss_fuses *fuse = vreg->platform_fuses;
903 int rc;
904 bool allow_interpolation;
905 u64 freq_low, freq_high, prev_quot;
906 u64 *quot_low;
907 u64 *quot_high;
908 u32 quot, ro;
909 int i, j, fuse_corner, quot_adjust;
910 int *fmax_corner;
911 int *volt_adjust, *volt_adjust_fuse, *ro_scale;
912
913 /* Log fused quotient values for debugging purposes. */
914 cpr3_info(vreg, "fused MinSVS: quot[%2llu]=%4llu\n",
915 fuse->ro_sel[CPR3_MSM8996_HMSS_FUSE_CORNER_MINSVS],
916 fuse->target_quot[CPR3_MSM8996_HMSS_FUSE_CORNER_MINSVS]);
917 for (i = CPR3_MSM8996_HMSS_FUSE_CORNER_SVS;
918 i <= CPR3_MSM8996_HMSS_FUSE_CORNER_TURBO; i++)
919 cpr3_info(vreg, "fused %6s: quot[%2llu]=%4llu, quot_offset[%2llu]=%4llu\n",
920 cpr3_msm8996_hmss_fuse_corner_name[i],
921 fuse->ro_sel[i], fuse->target_quot[i], fuse->ro_sel[i],
922 fuse->quot_offset[i] * MSM8996_HMSS_QUOT_OFFSET_SCALE);
923
924 allow_interpolation = of_property_read_bool(vreg->of_node,
925 "qcom,allow-quotient-interpolation");
926
927 if (fuse->limitation == MSM8996_CPR_LIMITATION_NO_CPR_OR_INTERPOLATION)
928 allow_interpolation = false;
929
930 volt_adjust = kcalloc(vreg->corner_count, sizeof(*volt_adjust),
931 GFP_KERNEL);
932 volt_adjust_fuse = kcalloc(vreg->fuse_corner_count,
933 sizeof(*volt_adjust_fuse), GFP_KERNEL);
934 ro_scale = kcalloc(vreg->fuse_corner_count, sizeof(*ro_scale),
935 GFP_KERNEL);
936 fmax_corner = kcalloc(vreg->fuse_corner_count, sizeof(*fmax_corner),
937 GFP_KERNEL);
938 quot_low = kcalloc(vreg->fuse_corner_count, sizeof(*quot_low),
939 GFP_KERNEL);
940 quot_high = kcalloc(vreg->fuse_corner_count, sizeof(*quot_high),
941 GFP_KERNEL);
942 if (!volt_adjust || !volt_adjust_fuse || !ro_scale ||
943 !fmax_corner || !quot_low || !quot_high) {
944 rc = -ENOMEM;
945 goto done;
946 }
947
948 rc = cpr3_parse_closed_loop_voltage_adjustments(vreg, &fuse->ro_sel[0],
949 volt_adjust, volt_adjust_fuse, ro_scale);
950 if (rc) {
951 cpr3_err(vreg, "could not load closed-loop voltage adjustments, rc=%d\n",
952 rc);
953 goto done;
954 }
955
956 rc = cpr3_hmss_apply_fused_voltage_offset(vreg, volt_adjust_fuse);
957 if (rc) {
958 cpr3_err(vreg, "could not apply CBF voltage offsets, rc=%d\n",
959 rc);
960 goto done;
961 }
962
963 if (!allow_interpolation) {
964 /* Use fused target quotients for lower frequencies. */
965 return cpr3_msm8996_hmss_set_no_interpolation_quotients(vreg,
966 volt_adjust, volt_adjust_fuse, ro_scale);
967 }
968
969 for (i = 0; i < vreg->fuse_corner_count; i++)
970 fmax_corner[i] = vreg->fuse_corner_map[i];
971
972 /*
973 * Interpolation is not possible for corners mapped to the lowest fuse
974 * corner so use the fuse corner value directly.
975 */
976 i = CPR3_MSM8996_HMSS_FUSE_CORNER_MINSVS;
977 quot_adjust = cpr3_quot_adjustment(ro_scale[i], volt_adjust_fuse[i]);
978 quot = fuse->target_quot[i] + quot_adjust;
979 quot_high[i] = quot;
980 ro = fuse->ro_sel[i];
981 if (quot_adjust)
982 cpr3_debug(vreg, "adjusted fuse corner %d RO%u target quot: %llu --> %u (%d uV)\n",
983 i, ro, fuse->target_quot[i], quot, volt_adjust_fuse[i]);
984 for (i = 0; i <= fmax_corner[CPR3_MSM8996_HMSS_FUSE_CORNER_MINSVS]; i++)
985 vreg->corner[i].target_quot[ro] = quot;
986
987 /*
988 * Interpolation is not possible for corners mapped above the highest
989 * fuse corner so use the fuse corner value directly.
990 */
991 j = vreg->fuse_corner_count - 1;
992 quot_adjust = cpr3_quot_adjustment(ro_scale[j], volt_adjust_fuse[j]);
993 quot = fuse->target_quot[j] + quot_adjust;
994 ro = fuse->ro_sel[j];
995 for (i = fmax_corner[j] + 1; i < vreg->corner_count; i++)
996 vreg->corner[i].target_quot[ro] = quot;
997
998 /*
999 * The LowSVS target quotient is defined as:
1000 * (SVS target quotient) - (the unpacked SVS quotient offset)
1001 * MinSVS, LowSVS, and SVS fuse corners all share the same RO so it is
1002 * possible to interpolate between their target quotient values.
1003 */
1004 i = CPR3_MSM8996_HMSS_FUSE_CORNER_LOWSVS;
1005 quot_high[i] = fuse->target_quot[CPR3_MSM8996_HMSS_FUSE_CORNER_SVS]
1006 - fuse->quot_offset[CPR3_MSM8996_HMSS_FUSE_CORNER_SVS]
1007 * MSM8996_HMSS_QUOT_OFFSET_SCALE;
1008 quot_low[i] = fuse->target_quot[CPR3_MSM8996_HMSS_FUSE_CORNER_MINSVS];
1009 if (quot_high[i] < quot_low[i]) {
1010 cpr3_info(vreg, "quot_lowsvs=%llu < quot_minsvs=%llu; overriding: quot_lowsvs=%llu\n",
1011 quot_high[i], quot_low[i], quot_low[i]);
1012 quot_high[i] = quot_low[i];
1013 }
1014 if (fuse->ro_sel[CPR3_MSM8996_HMSS_FUSE_CORNER_MINSVS]
1015 != fuse->ro_sel[CPR3_MSM8996_HMSS_FUSE_CORNER_SVS]) {
1016 cpr3_info(vreg, "MinSVS RO=%llu != SVS RO=%llu; disabling LowSVS interpolation\n",
1017 fuse->ro_sel[CPR3_MSM8996_HMSS_FUSE_CORNER_MINSVS],
1018 fuse->ro_sel[CPR3_MSM8996_HMSS_FUSE_CORNER_SVS]);
1019 quot_low[i] = quot_high[i];
1020 }
1021
1022 for (i = CPR3_MSM8996_HMSS_FUSE_CORNER_SVS;
1023 i < vreg->fuse_corner_count; i++) {
1024 quot_high[i] = fuse->target_quot[i];
1025 if (fuse->ro_sel[i] == fuse->ro_sel[i - 1])
1026 quot_low[i] = quot_high[i - 1];
1027 else
1028 quot_low[i] = quot_high[i]
1029 - fuse->quot_offset[i]
1030 * MSM8996_HMSS_QUOT_OFFSET_SCALE;
1031 if (quot_high[i] < quot_low[i]) {
1032 cpr3_debug(vreg, "quot_high[%d]=%llu < quot_low[%d]=%llu; overriding: quot_high[%d]=%llu\n",
1033 i, quot_high[i], i, quot_low[i],
1034 i, quot_low[i]);
1035 quot_high[i] = quot_low[i];
1036 }
1037 }
1038
1039 /* Perform per-fuse-corner target quotient adjustment */
1040 for (i = 1; i < vreg->fuse_corner_count; i++) {
1041 quot_adjust = cpr3_quot_adjustment(ro_scale[i],
1042 volt_adjust_fuse[i]);
1043 if (quot_adjust) {
1044 prev_quot = quot_high[i];
1045 quot_high[i] += quot_adjust;
1046 cpr3_debug(vreg, "adjusted fuse corner %d RO%llu target quot: %llu --> %llu (%d uV)\n",
1047 i, fuse->ro_sel[i], prev_quot, quot_high[i],
1048 volt_adjust_fuse[i]);
1049 }
1050
1051 if (fuse->ro_sel[i] == fuse->ro_sel[i - 1])
1052 quot_low[i] = quot_high[i - 1];
1053 else
1054 quot_low[i] += cpr3_quot_adjustment(ro_scale[i],
1055 volt_adjust_fuse[i - 1]);
1056
1057 if (quot_high[i] < quot_low[i]) {
1058 cpr3_debug(vreg, "quot_high[%d]=%llu < quot_low[%d]=%llu after adjustment; overriding: quot_high[%d]=%llu\n",
1059 i, quot_high[i], i, quot_low[i],
1060 i, quot_low[i]);
1061 quot_high[i] = quot_low[i];
1062 }
1063 }
1064
1065 /* Interpolate voltages for the higher fuse corners. */
1066 for (i = 1; i < vreg->fuse_corner_count; i++) {
1067 freq_low = vreg->corner[fmax_corner[i - 1]].proc_freq;
1068 freq_high = vreg->corner[fmax_corner[i]].proc_freq;
1069
1070 ro = fuse->ro_sel[i];
1071 for (j = fmax_corner[i - 1] + 1; j <= fmax_corner[i]; j++)
1072 vreg->corner[j].target_quot[ro] = cpr3_interpolate(
1073 freq_low, quot_low[i], freq_high, quot_high[i],
1074 vreg->corner[j].proc_freq);
1075 }
1076
1077 /* Perform per-corner target quotient adjustment */
1078 for (i = 0; i < vreg->corner_count; i++) {
1079 fuse_corner = vreg->corner[i].cpr_fuse_corner;
1080 ro = fuse->ro_sel[fuse_corner];
1081 quot_adjust = cpr3_quot_adjustment(ro_scale[fuse_corner],
1082 volt_adjust[i]);
1083 if (quot_adjust) {
1084 prev_quot = vreg->corner[i].target_quot[ro];
1085 vreg->corner[i].target_quot[ro] += quot_adjust;
1086 cpr3_debug(vreg, "adjusted corner %d RO%u target quot: %llu --> %u (%d uV)\n",
1087 i, ro, prev_quot,
1088 vreg->corner[i].target_quot[ro],
1089 volt_adjust[i]);
1090 }
1091 }
1092
1093 /* Ensure that target quotients increase monotonically */
1094 for (i = 1; i < vreg->corner_count; i++) {
1095 ro = fuse->ro_sel[vreg->corner[i].cpr_fuse_corner];
1096 if (fuse->ro_sel[vreg->corner[i - 1].cpr_fuse_corner] == ro
1097 && vreg->corner[i].target_quot[ro]
1098 < vreg->corner[i - 1].target_quot[ro]) {
1099 cpr3_debug(vreg, "adjusted corner %d RO%u target quot=%u < adjusted corner %d RO%u target quot=%u; overriding: corner %d RO%u target quot=%u\n",
1100 i, ro, vreg->corner[i].target_quot[ro],
1101 i - 1, ro, vreg->corner[i - 1].target_quot[ro],
1102 i, ro, vreg->corner[i - 1].target_quot[ro]);
1103 vreg->corner[i].target_quot[ro]
1104 = vreg->corner[i - 1].target_quot[ro];
1105 }
1106 }
1107
1108done:
1109 kfree(volt_adjust);
1110 kfree(volt_adjust_fuse);
1111 kfree(ro_scale);
1112 kfree(fmax_corner);
1113 kfree(quot_low);
1114 kfree(quot_high);
1115 return rc;
1116}
1117
1118/**
1119 * cpr3_msm8996_partial_binning_override() - override the voltage and quotient
1120 * settings for low corners based upon the value of the partial
1121 * binning fuse
1122 * @vreg: Pointer to the CPR3 regulator
1123 *
1124 * Some parts are not able to operate at low voltages. The partial binning
1125 * fuse specifies if a given part has such limitations.
1126 *
1127 * Return: 0 on success, errno on failure
1128 */
1129static int cpr3_msm8996_partial_binning_override(struct cpr3_regulator *vreg)
1130{
1131 struct cpr3_msm8996_hmss_fuses *fuse = vreg->platform_fuses;
1132 int i, fuse_corner, fmax_corner;
1133
1134 if (fuse->partial_binning == MSM8996_CPR_PARTIAL_BINNING_SVS)
1135 fuse_corner = CPR3_MSM8996_HMSS_FUSE_CORNER_SVS;
1136 else if (fuse->partial_binning == MSM8996_CPR_PARTIAL_BINNING_NOM)
1137 fuse_corner = CPR3_MSM8996_HMSS_FUSE_CORNER_NOM;
1138 else
1139 return 0;
1140
1141 cpr3_info(vreg, "overriding voltages and quotients for all corners below %s Fmax\n",
1142 cpr3_msm8996_hmss_fuse_corner_name[fuse_corner]);
1143
1144 fmax_corner = -1;
1145 for (i = vreg->corner_count - 1; i >= 0; i--) {
1146 if (vreg->corner[i].cpr_fuse_corner == fuse_corner) {
1147 fmax_corner = i;
1148 break;
1149 }
1150 }
1151 if (fmax_corner < 0) {
1152 cpr3_err(vreg, "could not find %s Fmax corner\n",
1153 cpr3_msm8996_hmss_fuse_corner_name[fuse_corner]);
1154 return -EINVAL;
1155 }
1156
1157 for (i = 0; i < fmax_corner; i++)
1158 vreg->corner[i] = vreg->corner[fmax_corner];
1159
1160 return 0;
1161}
1162
1163/**
1164 * cpr3_hmss_print_settings() - print out HMSS CPR configuration settings into
1165 * the kernel log for debugging purposes
1166 * @vreg: Pointer to the CPR3 regulator
1167 */
1168static void cpr3_hmss_print_settings(struct cpr3_regulator *vreg)
1169{
1170 struct cpr3_corner *corner;
1171 int i;
1172
1173 cpr3_debug(vreg, "Corner: Frequency (Hz), Fuse Corner, Floor (uV), Open-Loop (uV), Ceiling (uV)\n");
1174 for (i = 0; i < vreg->corner_count; i++) {
1175 corner = &vreg->corner[i];
1176 cpr3_debug(vreg, "%3d: %10u, %2d, %7d, %7d, %7d\n",
1177 i, corner->proc_freq, corner->cpr_fuse_corner,
1178 corner->floor_volt, corner->open_loop_volt,
1179 corner->ceiling_volt);
1180 }
1181
1182 if (vreg->thread->ctrl->apm)
1183 cpr3_debug(vreg, "APM threshold = %d uV, APM adjust = %d uV\n",
1184 vreg->thread->ctrl->apm_threshold_volt,
1185 vreg->thread->ctrl->apm_adj_volt);
1186}
1187
1188/**
1189 * cpr3_hmss_init_thread() - perform steps necessary to initialize the
1190 * configuration data for a CPR3 thread
1191 * @thread: Pointer to the CPR3 thread
1192 *
1193 * Return: 0 on success, errno on failure
1194 */
1195static int cpr3_hmss_init_thread(struct cpr3_thread *thread)
1196{
1197 int rc;
1198
1199 rc = cpr3_parse_common_thread_data(thread);
1200 if (rc) {
1201 cpr3_err(thread->ctrl, "thread %u unable to read CPR thread data from device tree, rc=%d\n",
1202 thread->thread_id, rc);
1203 return rc;
1204 }
1205
1206 return 0;
1207}
1208
1209#define MAX_VREG_NAME_SIZE 25
1210/**
1211 * cpr3_hmss_kvreg_init() - initialize HMSS Kryo Regulator data for a CPR3
1212 * regulator
1213 * @vreg: Pointer to the CPR3 regulator
1214 *
1215 * This function loads Kryo Regulator data from device tree if it is present
1216 * and requests a handle to the appropriate Kryo regulator device. In addition,
1217 * it initializes Kryo Regulator data originating from hardware fuses, such as
1218 * the LDO retention voltage, and requests the Kryo retention regulator to
1219 * be configured to that value.
1220 *
1221 * Return: 0 on success, errno on failure
1222 */
1223static int cpr3_hmss_kvreg_init(struct cpr3_regulator *vreg)
1224{
1225 struct cpr3_msm8996_hmss_fuses *fuse = vreg->platform_fuses;
1226 struct device_node *node = vreg->of_node;
1227 struct cpr3_controller *ctrl = vreg->thread->ctrl;
1228 int id = vreg->thread->thread_id;
1229 char kvreg_name_buf[MAX_VREG_NAME_SIZE];
1230 int rc;
1231
1232 scnprintf(kvreg_name_buf, MAX_VREG_NAME_SIZE,
1233 "vdd-thread%d-ldo-supply", id);
1234
1235 if (!of_find_property(ctrl->dev->of_node, kvreg_name_buf, NULL))
1236 return 0;
1237 else if (!of_find_property(node, "qcom,ldo-min-headroom-voltage", NULL))
1238 return 0;
1239
1240 scnprintf(kvreg_name_buf, MAX_VREG_NAME_SIZE, "vdd-thread%d-ldo", id);
1241
1242 vreg->ldo_regulator = devm_regulator_get(ctrl->dev, kvreg_name_buf);
1243 if (IS_ERR(vreg->ldo_regulator)) {
1244 rc = PTR_ERR(vreg->ldo_regulator);
1245 if (rc != -EPROBE_DEFER)
1246 cpr3_err(vreg, "unable to request %s regulator, rc=%d\n",
1247 kvreg_name_buf, rc);
1248 return rc;
1249 }
1250
1251 vreg->ldo_regulator_bypass = BHS_MODE;
1252
1253 scnprintf(kvreg_name_buf, MAX_VREG_NAME_SIZE, "vdd-thread%d-ldo-ret",
1254 id);
1255
1256 vreg->ldo_ret_regulator = devm_regulator_get(ctrl->dev, kvreg_name_buf);
1257 if (IS_ERR(vreg->ldo_ret_regulator)) {
1258 rc = PTR_ERR(vreg->ldo_ret_regulator);
1259 if (rc != -EPROBE_DEFER)
1260 cpr3_err(vreg, "unable to request %s regulator, rc=%d\n",
1261 kvreg_name_buf, rc);
1262 return rc;
1263 }
1264
1265 if (!ctrl->system_supply_max_volt) {
1266 cpr3_err(ctrl, "system-supply max voltage must be specified\n");
1267 return -EINVAL;
1268 }
1269
1270 rc = of_property_read_u32(node, "qcom,ldo-min-headroom-voltage",
1271 &vreg->ldo_min_headroom_volt);
1272 if (rc) {
1273 cpr3_err(vreg, "error reading qcom,ldo-min-headroom-voltage, rc=%d\n",
1274 rc);
1275 return rc;
1276 }
1277
1278 rc = of_property_read_u32(node, "qcom,ldo-max-headroom-voltage",
1279 &vreg->ldo_max_headroom_volt);
1280 if (rc) {
1281 cpr3_err(vreg, "error reading qcom,ldo-max-headroom-voltage, rc=%d\n",
1282 rc);
1283 return rc;
1284 }
1285
1286 rc = of_property_read_u32(node, "qcom,ldo-max-voltage",
1287 &vreg->ldo_max_volt);
1288 if (rc) {
1289 cpr3_err(vreg, "error reading qcom,ldo-max-voltage, rc=%d\n",
1290 rc);
1291 return rc;
1292 }
1293
1294 /* Determine the CPU retention voltage based on fused data */
1295 vreg->ldo_ret_volt =
1296 max(msm8996_vdd_apcc_fuse_ret_volt[fuse->vdd_apcc_ret_fuse],
1297 msm8996_vdd_mx_fuse_ret_volt[fuse->vdd_mx_ret_fuse]);
1298
1299 rc = regulator_set_voltage(vreg->ldo_ret_regulator, vreg->ldo_ret_volt,
1300 INT_MAX);
1301 if (rc < 0) {
1302 cpr3_err(vreg, "regulator_set_voltage(ldo_ret) == %d failed, rc=%d\n",
1303 vreg->ldo_ret_volt, rc);
1304 return rc;
1305 }
1306
1307 /* optional properties, do not error out if missing */
1308 of_property_read_u32(node, "qcom,ldo-adjust-voltage",
1309 &vreg->ldo_adjust_volt);
1310
1311 vreg->ldo_mode_allowed = !of_property_read_bool(node,
1312 "qcom,ldo-disable");
1313
1314 cpr3_info(vreg, "LDO min headroom=%d uV, LDO max headroom=%d uV, LDO adj=%d uV, LDO mode=%s, LDO retention=%d uV\n",
1315 vreg->ldo_min_headroom_volt,
1316 vreg->ldo_max_headroom_volt,
1317 vreg->ldo_adjust_volt,
1318 vreg->ldo_mode_allowed ? "allowed" : "disallowed",
1319 vreg->ldo_ret_volt);
1320
1321 return 0;
1322}
1323
1324/**
1325 * cpr3_hmss_mem_acc_init() - initialize mem-acc regulator data for
1326 * a CPR3 regulator
1327 * @vreg: Pointer to the CPR3 regulator
1328 *
1329 * This function loads mem-acc data from device tree to enable
1330 * the control of mem-acc settings based upon the CPR3 regulator
1331 * output voltage.
1332 *
1333 * Return: 0 on success, errno on failure
1334 */
1335static int cpr3_hmss_mem_acc_init(struct cpr3_regulator *vreg)
1336{
1337 struct cpr3_controller *ctrl = vreg->thread->ctrl;
1338 int id = vreg->thread->thread_id;
1339 char mem_acc_vreg_name_buf[MAX_VREG_NAME_SIZE];
1340 int rc;
1341
1342 scnprintf(mem_acc_vreg_name_buf, MAX_VREG_NAME_SIZE,
1343 "mem-acc-thread%d-supply", id);
1344
1345 if (!of_find_property(ctrl->dev->of_node, mem_acc_vreg_name_buf,
1346 NULL)) {
1347 cpr3_debug(vreg, "not using memory accelerator regulator\n");
1348 return 0;
1349 } else if (!of_property_read_bool(vreg->of_node, "qcom,uses-mem-acc")) {
1350 return 0;
1351 }
1352
1353 scnprintf(mem_acc_vreg_name_buf, MAX_VREG_NAME_SIZE,
1354 "mem-acc-thread%d", id);
1355
1356 vreg->mem_acc_regulator = devm_regulator_get(ctrl->dev,
1357 mem_acc_vreg_name_buf);
1358 if (IS_ERR(vreg->mem_acc_regulator)) {
1359 rc = PTR_ERR(vreg->mem_acc_regulator);
1360 if (rc != -EPROBE_DEFER)
1361 cpr3_err(vreg, "unable to request %s regulator, rc=%d\n",
1362 mem_acc_vreg_name_buf, rc);
1363 return rc;
1364 }
1365
1366 return 0;
1367}
1368
1369/**
1370 * cpr3_hmss_init_regulator() - perform all steps necessary to initialize the
1371 * configuration data for a CPR3 regulator
1372 * @vreg: Pointer to the CPR3 regulator
1373 *
1374 * Return: 0 on success, errno on failure
1375 */
1376static int cpr3_hmss_init_regulator(struct cpr3_regulator *vreg)
1377{
1378 struct cpr3_msm8996_hmss_fuses *fuse;
1379 int rc;
1380
1381 rc = cpr3_msm8996_hmss_read_fuse_data(vreg);
1382 if (rc) {
1383 cpr3_err(vreg, "unable to read CPR fuse data, rc=%d\n", rc);
1384 return rc;
1385 }
1386
1387 rc = cpr3_hmss_kvreg_init(vreg);
1388 if (rc) {
1389 if (rc != -EPROBE_DEFER)
1390 cpr3_err(vreg, "unable to initialize Kryo Regulator settings, rc=%d\n",
1391 rc);
1392 return rc;
1393 }
1394
1395 rc = cpr3_hmss_mem_acc_init(vreg);
1396 if (rc) {
1397 if (rc != -EPROBE_DEFER)
1398 cpr3_err(vreg, "unable to initialize mem-acc regulator settings, rc=%d\n",
1399 rc);
1400 return rc;
1401 }
1402
1403 fuse = vreg->platform_fuses;
1404 if (fuse->limitation == MSM8996_CPR_LIMITATION_UNSUPPORTED) {
1405 cpr3_err(vreg, "this chip requires an unsupported voltage\n");
1406 return -EPERM;
1407 } else if (fuse->limitation
1408 == MSM8996_CPR_LIMITATION_NO_CPR_OR_INTERPOLATION) {
1409 vreg->thread->ctrl->cpr_allowed_hw = false;
1410 }
1411
1412 rc = of_property_read_u32(vreg->of_node, "qcom,cpr-pd-bypass-mask",
1413 &vreg->pd_bypass_mask);
1414 if (rc) {
1415 cpr3_err(vreg, "error reading qcom,cpr-pd-bypass-mask, rc=%d\n",
1416 rc);
1417 return rc;
1418 }
1419
1420 rc = cpr3_hmss_parse_corner_data(vreg);
1421 if (rc) {
1422 cpr3_err(vreg, "unable to read CPR corner data from device tree, rc=%d\n",
1423 rc);
1424 return rc;
1425 }
1426
1427 if (of_find_property(vreg->of_node, "qcom,cpr-dynamic-floor-corner",
1428 NULL)) {
1429 rc = cpr3_parse_array_property(vreg,
1430 "qcom,cpr-dynamic-floor-corner",
1431 1, &vreg->dynamic_floor_corner);
1432 if (rc) {
1433 cpr3_err(vreg, "error reading qcom,cpr-dynamic-floor-corner, rc=%d\n",
1434 rc);
1435 return rc;
1436 }
1437
1438 if (vreg->dynamic_floor_corner <= 0) {
1439 vreg->uses_dynamic_floor = false;
1440 } else if (vreg->dynamic_floor_corner < CPR3_CORNER_OFFSET
1441 || vreg->dynamic_floor_corner
1442 > vreg->corner_count - 1 + CPR3_CORNER_OFFSET) {
1443 cpr3_err(vreg, "dynamic floor corner=%d not in range [%d, %d]\n",
1444 vreg->dynamic_floor_corner, CPR3_CORNER_OFFSET,
1445 vreg->corner_count - 1 + CPR3_CORNER_OFFSET);
1446 return -EINVAL;
1447 }
1448
1449 vreg->dynamic_floor_corner -= CPR3_CORNER_OFFSET;
1450 vreg->uses_dynamic_floor = true;
1451 }
1452
1453 rc = cpr3_msm8996_hmss_calculate_open_loop_voltages(vreg);
1454 if (rc) {
1455 cpr3_err(vreg, "unable to calculate open-loop voltages, rc=%d\n",
1456 rc);
1457 return rc;
1458 }
1459
1460 rc = cpr3_limit_open_loop_voltages(vreg);
1461 if (rc) {
1462 cpr3_err(vreg, "unable to limit open-loop voltages, rc=%d\n",
1463 rc);
1464 return rc;
1465 }
1466
1467 cpr3_open_loop_voltage_as_ceiling(vreg);
1468
1469 rc = cpr3_limit_floor_voltages(vreg);
1470 if (rc) {
1471 cpr3_err(vreg, "unable to limit floor voltages, rc=%d\n", rc);
1472 return rc;
1473 }
1474
1475 rc = cpr3_msm8996_hmss_calculate_target_quotients(vreg);
1476 if (rc) {
1477 cpr3_err(vreg, "unable to calculate target quotients, rc=%d\n",
1478 rc);
1479 return rc;
1480 }
1481
1482 rc = cpr3_msm8996_partial_binning_override(vreg);
1483 if (rc) {
1484 cpr3_err(vreg, "unable to override voltages and quotients based on partial binning fuse, rc=%d\n",
1485 rc);
1486 return rc;
1487 }
1488
1489 cpr3_hmss_print_settings(vreg);
1490
1491 return 0;
1492}
1493
1494/**
1495 * cpr3_hmss_init_aging() - perform HMSS CPR3 controller specific
1496 * aging initializations
1497 * @ctrl: Pointer to the CPR3 controller
1498 *
1499 * Return: 0 on success, errno on failure
1500 */
1501static int cpr3_hmss_init_aging(struct cpr3_controller *ctrl)
1502{
1503 struct cpr3_msm8996_hmss_fuses *fuse = NULL;
1504 struct cpr3_regulator *vreg;
1505 u32 aging_ro_scale;
1506 int i, j, rc;
1507
1508 for (i = 0; i < ctrl->thread_count; i++) {
1509 for (j = 0; j < ctrl->thread[i].vreg_count; j++) {
1510 if (ctrl->thread[i].vreg[j].aging_allowed) {
1511 ctrl->aging_required = true;
1512 vreg = &ctrl->thread[i].vreg[j];
1513 fuse = vreg->platform_fuses;
1514 break;
1515 }
1516 }
1517 }
1518
1519 if (!ctrl->aging_required || !fuse || !vreg)
1520 return 0;
1521
1522 rc = cpr3_parse_array_property(vreg, "qcom,cpr-aging-ro-scaling-factor",
1523 1, &aging_ro_scale);
1524 if (rc)
1525 return rc;
1526
1527 if (aging_ro_scale == 0) {
1528 cpr3_err(ctrl, "aging RO scaling factor is invalid: %u\n",
1529 aging_ro_scale);
1530 return -EINVAL;
1531 }
1532
1533 ctrl->aging_vdd_mode = REGULATOR_MODE_NORMAL;
1534 ctrl->aging_complete_vdd_mode = REGULATOR_MODE_IDLE;
1535
1536 ctrl->aging_sensor_count = 1;
1537 ctrl->aging_sensor = kzalloc(sizeof(*ctrl->aging_sensor), GFP_KERNEL);
1538 if (!ctrl->aging_sensor)
1539 return -ENOMEM;
1540
1541 ctrl->aging_sensor->sensor_id = MSM8996_HMSS_AGING_SENSOR_ID;
1542 ctrl->aging_sensor->bypass_mask[0] = MSM8996_HMSS_AGING_BYPASS_MASK0;
1543 ctrl->aging_sensor->ro_scale = aging_ro_scale;
1544
1545 ctrl->aging_sensor->init_quot_diff
1546 = cpr3_convert_open_loop_voltage_fuse(0,
1547 MSM8996_HMSS_AGING_INIT_QUOT_DIFF_SCALE,
1548 fuse->aging_init_quot_diff,
1549 MSM8996_HMSS_AGING_INIT_QUOT_DIFF_SIZE);
1550
1551 cpr3_debug(ctrl, "sensor %u aging init quotient diff = %d, aging RO scale = %u QUOT/V\n",
1552 ctrl->aging_sensor->sensor_id,
1553 ctrl->aging_sensor->init_quot_diff,
1554 ctrl->aging_sensor->ro_scale);
1555
1556 return 0;
1557}
1558
1559/**
1560 * cpr3_hmss_init_controller() - perform HMSS CPR3 controller specific
1561 * initializations
1562 * @ctrl: Pointer to the CPR3 controller
1563 *
1564 * Return: 0 on success, errno on failure
1565 */
1566static int cpr3_hmss_init_controller(struct cpr3_controller *ctrl)
1567{
1568 int i, rc;
1569
1570 rc = cpr3_parse_common_ctrl_data(ctrl);
1571 if (rc) {
1572 if (rc != -EPROBE_DEFER)
1573 cpr3_err(ctrl, "unable to parse common controller data, rc=%d\n",
1574 rc);
1575 return rc;
1576 }
1577
1578 ctrl->vdd_limit_regulator = devm_regulator_get(ctrl->dev, "vdd-limit");
1579 if (IS_ERR(ctrl->vdd_limit_regulator)) {
1580 rc = PTR_ERR(ctrl->vdd_limit_regulator);
1581 if (rc != -EPROBE_DEFER)
1582 cpr3_err(ctrl, "unable to request vdd-supply regulator, rc=%d\n",
1583 rc);
1584 return rc;
1585 }
1586
1587 rc = of_property_read_u32(ctrl->dev->of_node,
1588 "qcom,cpr-up-down-delay-time",
1589 &ctrl->up_down_delay_time);
1590 if (rc) {
1591 cpr3_err(ctrl, "error reading property qcom,cpr-up-down-delay-time, rc=%d\n",
1592 rc);
1593 return rc;
1594 }
1595
1596 /* No error check since this is an optional property. */
1597 of_property_read_u32(ctrl->dev->of_node,
1598 "qcom,system-supply-max-voltage",
1599 &ctrl->system_supply_max_volt);
1600
1601 /* No error check since this is an optional property. */
1602 of_property_read_u32(ctrl->dev->of_node, "qcom,cpr-clock-throttling",
1603 &ctrl->proc_clock_throttle);
1604
1605 rc = cpr3_apm_init(ctrl);
1606 if (rc) {
1607 if (rc != -EPROBE_DEFER)
1608 cpr3_err(ctrl, "unable to initialize APM settings, rc=%d\n",
1609 rc);
1610 return rc;
1611 }
1612
1613 ctrl->sensor_count = MSM8996_HMSS_CPR_SENSOR_COUNT;
1614
1615 ctrl->sensor_owner = devm_kcalloc(ctrl->dev, ctrl->sensor_count,
1616 sizeof(*ctrl->sensor_owner), GFP_KERNEL);
1617 if (!ctrl->sensor_owner)
1618 return -ENOMEM;
1619
1620 /* Specify sensor ownership */
1621 for (i = MSM8996_HMSS_THREAD0_SENSOR_MIN;
1622 i <= MSM8996_HMSS_THREAD0_SENSOR_MAX; i++)
1623 ctrl->sensor_owner[i] = 0;
1624 for (i = MSM8996_HMSS_THREAD1_SENSOR_MIN;
1625 i <= MSM8996_HMSS_THREAD1_SENSOR_MAX; i++)
1626 ctrl->sensor_owner[i] = 1;
1627
1628 ctrl->cpr_clock_rate = MSM8996_HMSS_CPR_CLOCK_RATE;
1629 ctrl->ctrl_type = CPR_CTRL_TYPE_CPR3;
1630 ctrl->supports_hw_closed_loop = true;
1631 ctrl->use_hw_closed_loop = of_property_read_bool(ctrl->dev->of_node,
1632 "qcom,cpr-hw-closed-loop");
1633
1634 if (ctrl->mem_acc_regulator) {
1635 rc = of_property_read_u32(ctrl->dev->of_node,
1636 "qcom,mem-acc-supply-threshold-voltage",
1637 &ctrl->mem_acc_threshold_volt);
1638 if (rc) {
1639 cpr3_err(ctrl, "error reading property qcom,mem-acc-supply-threshold-voltage, rc=%d\n",
1640 rc);
1641 return rc;
1642 }
1643
1644 ctrl->mem_acc_threshold_volt =
1645 CPR3_ROUND(ctrl->mem_acc_threshold_volt,
1646 ctrl->step_volt);
1647
1648 rc = of_property_read_u32_array(ctrl->dev->of_node,
1649 "qcom,mem-acc-supply-corner-map",
1650 &ctrl->mem_acc_corner_map[CPR3_MEM_ACC_LOW_CORNER],
1651 CPR3_MEM_ACC_CORNERS);
1652 if (rc) {
1653 cpr3_err(ctrl, "error reading qcom,mem-acc-supply-corner-map, rc=%d\n",
1654 rc);
1655 return rc;
1656 }
1657 }
1658
1659 return 0;
1660}
1661
1662static int cpr3_hmss_regulator_suspend(struct platform_device *pdev,
1663 pm_message_t state)
1664{
1665 struct cpr3_controller *ctrl = platform_get_drvdata(pdev);
1666
1667 return cpr3_regulator_suspend(ctrl);
1668}
1669
1670static int cpr3_hmss_regulator_resume(struct platform_device *pdev)
1671{
1672 struct cpr3_controller *ctrl = platform_get_drvdata(pdev);
1673
1674 return cpr3_regulator_resume(ctrl);
1675}
1676
1677/* Data corresponds to the SoC revision */
1678static const struct of_device_id cpr_regulator_match_table[] = {
1679 {
1680 .compatible = "qcom,cpr3-msm8996-v1-hmss-regulator",
1681 .data = (void *)(uintptr_t)1
1682 },
1683 {
1684 .compatible = "qcom,cpr3-msm8996-v2-hmss-regulator",
1685 .data = (void *)(uintptr_t)2
1686 },
1687 {
1688 .compatible = "qcom,cpr3-msm8996-v3-hmss-regulator",
1689 .data = (void *)(uintptr_t)3
1690 },
1691 {
1692 .compatible = "qcom,cpr3-msm8996-hmss-regulator",
1693 .data = (void *)(uintptr_t)3
1694 },
1695 {
1696 .compatible = "qcom,cpr3-msm8996pro-hmss-regulator",
1697 .data = (void *)(uintptr_t)MSM8996PRO_SOC_ID,
1698 },
1699 {}
1700};
1701
1702static int cpr3_hmss_regulator_probe(struct platform_device *pdev)
1703{
1704 struct device *dev = &pdev->dev;
1705 const struct of_device_id *match;
1706 struct cpr3_controller *ctrl;
1707 struct cpr3_regulator *vreg;
1708 int i, j, rc;
1709
1710 if (!dev->of_node) {
1711 dev_err(dev, "Device tree node is missing\n");
1712 return -EINVAL;
1713 }
1714
1715 ctrl = devm_kzalloc(dev, sizeof(*ctrl), GFP_KERNEL);
1716 if (!ctrl)
1717 return -ENOMEM;
1718
1719 ctrl->dev = dev;
1720 /* Set to false later if anything precludes CPR operation. */
1721 ctrl->cpr_allowed_hw = true;
1722
1723 rc = of_property_read_string(dev->of_node, "qcom,cpr-ctrl-name",
1724 &ctrl->name);
1725 if (rc) {
1726 cpr3_err(ctrl, "unable to read qcom,cpr-ctrl-name, rc=%d\n",
1727 rc);
1728 return rc;
1729 }
1730
1731 match = of_match_node(cpr_regulator_match_table, dev->of_node);
1732 if (match)
1733 ctrl->soc_revision = (uintptr_t)match->data;
1734 else
1735 cpr3_err(ctrl, "could not find compatible string match\n");
1736
1737 rc = cpr3_map_fuse_base(ctrl, pdev);
1738 if (rc) {
1739 cpr3_err(ctrl, "could not map fuse base address\n");
1740 return rc;
1741 }
1742
1743 rc = cpr3_allocate_threads(ctrl, MSM8996_HMSS_POWER_CLUSTER_THREAD_ID,
1744 MSM8996_HMSS_PERFORMANCE_CLUSTER_THREAD_ID);
1745 if (rc) {
1746 cpr3_err(ctrl, "failed to allocate CPR thread array, rc=%d\n",
1747 rc);
1748 return rc;
1749 }
1750
1751 if (ctrl->thread_count < 1) {
1752 cpr3_err(ctrl, "thread nodes are missing\n");
1753 return -EINVAL;
1754 }
1755
1756 rc = cpr3_hmss_init_controller(ctrl);
1757 if (rc) {
1758 if (rc != -EPROBE_DEFER)
1759 cpr3_err(ctrl, "failed to initialize CPR controller parameters, rc=%d\n",
1760 rc);
1761 return rc;
1762 }
1763
1764 for (i = 0; i < ctrl->thread_count; i++) {
1765 rc = cpr3_hmss_init_thread(&ctrl->thread[i]);
1766 if (rc) {
1767 cpr3_err(ctrl, "thread %u initialization failed, rc=%d\n",
1768 ctrl->thread[i].thread_id, rc);
1769 return rc;
1770 }
1771
1772 for (j = 0; j < ctrl->thread[i].vreg_count; j++) {
1773 vreg = &ctrl->thread[i].vreg[j];
1774
1775 rc = cpr3_hmss_init_regulator(vreg);
1776 if (rc) {
1777 cpr3_err(vreg, "regulator initialization failed, rc=%d\n",
1778 rc);
1779 return rc;
1780 }
1781 }
1782 }
1783
1784 rc = cpr3_hmss_init_aging(ctrl);
1785 if (rc) {
1786 cpr3_err(ctrl, "failed to initialize aging configurations, rc=%d\n",
1787 rc);
1788 return rc;
1789 }
1790
1791 platform_set_drvdata(pdev, ctrl);
1792
1793 return cpr3_regulator_register(pdev, ctrl);
1794}
1795
1796static int cpr3_hmss_regulator_remove(struct platform_device *pdev)
1797{
1798 struct cpr3_controller *ctrl = platform_get_drvdata(pdev);
1799
1800 return cpr3_regulator_unregister(ctrl);
1801}
1802
1803static struct platform_driver cpr3_hmss_regulator_driver = {
1804 .driver = {
1805 .name = "qcom,cpr3-hmss-regulator",
1806 .of_match_table = cpr_regulator_match_table,
1807 .owner = THIS_MODULE,
1808 },
1809 .probe = cpr3_hmss_regulator_probe,
1810 .remove = cpr3_hmss_regulator_remove,
1811 .suspend = cpr3_hmss_regulator_suspend,
1812 .resume = cpr3_hmss_regulator_resume,
1813};
1814
1815static int cpr_regulator_init(void)
1816{
1817 return platform_driver_register(&cpr3_hmss_regulator_driver);
1818}
1819
1820static void cpr_regulator_exit(void)
1821{
1822 platform_driver_unregister(&cpr3_hmss_regulator_driver);
1823}
1824
1825MODULE_DESCRIPTION("CPR3 HMSS regulator driver");
1826MODULE_LICENSE("GPL v2");
1827
1828arch_initcall(cpr_regulator_init);
1829module_exit(cpr_regulator_exit);