blob: a9602cb0a3fa1836559a5b5c68c2359364f49ab6 [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
36#include "cpr3-regulator.h"
37
38#define MSM8953_APSS_FUSE_CORNERS 4
39
40/**
41 * struct cpr4_msm8953_apss_fuses - APSS specific fuse data for MSM8953
42 * @ro_sel: Ring oscillator select fuse parameter value for each
43 * fuse corner
44 * @init_voltage: Initial (i.e. open-loop) voltage fuse parameter value
45 * for each fuse corner (raw, not converted to a voltage)
46 * @target_quot: CPR target quotient fuse parameter value for each fuse
47 * corner
48 * @quot_offset: CPR target quotient offset fuse parameter value for each
49 * fuse corner (raw, not unpacked) used for target quotient
50 * interpolation
51 * @speed_bin: Application processor speed bin fuse parameter value for
52 * the given chip
53 * @cpr_fusing_rev: CPR fusing revision fuse parameter value
Tirupathi Reddy53d99a02016-08-08 17:04:23 +053054 * @foundry_id: Foundry identifier fuse parameter value for the given
55 * chip
David Collins7370f1a2017-01-18 16:21:53 -080056 * @boost_cfg: CPR boost configuration fuse parameter value
57 * @boost_voltage: CPR boost voltage fuse parameter value (raw, not
58 * converted to a voltage)
Tirupathi Reddy1bcb64f2016-03-01 16:54:40 +053059 * @aging_init_quot_diff: Initial quotient difference between CPR aging
60 * min and max sensors measured at time of manufacturing
David Collins7370f1a2017-01-18 16:21:53 -080061 *
62 * This struct holds the values for all of the fuses read from memory.
63 */
64struct cpr4_msm8953_apss_fuses {
65 u64 ro_sel[MSM8953_APSS_FUSE_CORNERS];
66 u64 init_voltage[MSM8953_APSS_FUSE_CORNERS];
67 u64 target_quot[MSM8953_APSS_FUSE_CORNERS];
68 u64 quot_offset[MSM8953_APSS_FUSE_CORNERS];
69 u64 speed_bin;
70 u64 cpr_fusing_rev;
Tirupathi Reddy53d99a02016-08-08 17:04:23 +053071 u64 foundry_id;
David Collins7370f1a2017-01-18 16:21:53 -080072 u64 boost_cfg;
73 u64 boost_voltage;
74 u64 misc;
Tirupathi Reddy1bcb64f2016-03-01 16:54:40 +053075 u64 aging_init_quot_diff;
David Collins7370f1a2017-01-18 16:21:53 -080076};
77
78/*
79 * fuse combo = fusing revision + 8 * (speed bin)
80 * where: fusing revision = 0 - 7 and speed bin = 0 - 7
81 */
82#define CPR4_MSM8953_APSS_FUSE_COMBO_COUNT 64
83
84/*
85 * Constants which define the name of each fuse corner.
86 */
87enum cpr4_msm8953_apss_fuse_corner {
88 CPR4_MSM8953_APSS_FUSE_CORNER_LOWSVS = 0,
89 CPR4_MSM8953_APSS_FUSE_CORNER_SVS = 1,
90 CPR4_MSM8953_APSS_FUSE_CORNER_NOM = 2,
91 CPR4_MSM8953_APSS_FUSE_CORNER_TURBO_L1 = 3,
92};
93
94static const char * const cpr4_msm8953_apss_fuse_corner_name[] = {
95 [CPR4_MSM8953_APSS_FUSE_CORNER_LOWSVS] = "LowSVS",
96 [CPR4_MSM8953_APSS_FUSE_CORNER_SVS] = "SVS",
97 [CPR4_MSM8953_APSS_FUSE_CORNER_NOM] = "NOM",
98 [CPR4_MSM8953_APSS_FUSE_CORNER_TURBO_L1] = "TURBO_L1",
99};
100
101/*
102 * MSM8953 APSS fuse parameter locations:
103 *
104 * Structs are organized with the following dimensions:
105 * Outer: 0 to 3 for fuse corners from lowest to highest corner
106 * Inner: large enough to hold the longest set of parameter segments which
107 * fully defines a fuse parameter, +1 (for NULL termination).
108 * Each segment corresponds to a contiguous group of bits from a
109 * single fuse row. These segments are concatentated together in
110 * order to form the full fuse parameter value. The segments for
111 * a given parameter may correspond to different fuse rows.
112 */
113static const struct cpr3_fuse_param
114msm8953_apss_ro_sel_param[MSM8953_APSS_FUSE_CORNERS][2] = {
115 {{73, 12, 15}, {} },
116 {{73, 8, 11}, {} },
117 {{73, 4, 7}, {} },
118 {{73, 0, 3}, {} },
119};
120
121static const struct cpr3_fuse_param
122msm8953_apss_init_voltage_param[MSM8953_APSS_FUSE_CORNERS][2] = {
123 {{71, 24, 29}, {} },
124 {{71, 18, 23}, {} },
125 {{71, 12, 17}, {} },
126 {{71, 6, 11}, {} },
127};
128
129static const struct cpr3_fuse_param
130msm8953_apss_target_quot_param[MSM8953_APSS_FUSE_CORNERS][2] = {
131 {{72, 44, 55}, {} },
132 {{72, 32, 43}, {} },
133 {{72, 20, 31}, {} },
134 {{72, 8, 19}, {} },
135};
136
137static const struct cpr3_fuse_param
138msm8953_apss_quot_offset_param[MSM8953_APSS_FUSE_CORNERS][2] = {
139 {{} },
140 {{71, 46, 52}, {} },
141 {{71, 39, 45}, {} },
142 {{71, 32, 38}, {} },
143};
144
145static const struct cpr3_fuse_param msm8953_cpr_fusing_rev_param[] = {
146 {71, 53, 55},
147 {},
148};
149
150static const struct cpr3_fuse_param msm8953_apss_speed_bin_param[] = {
151 {36, 40, 42},
152 {},
153};
154
Tirupathi Reddy53d99a02016-08-08 17:04:23 +0530155static const struct cpr3_fuse_param msm8953_apss_foundry_id_param[] = {
156 {37, 40, 42},
157 {},
158};
159
David Collins7370f1a2017-01-18 16:21:53 -0800160static const struct cpr3_fuse_param msm8953_cpr_boost_fuse_cfg_param[] = {
161 {36, 43, 45},
162 {},
163};
164
165static const struct cpr3_fuse_param msm8953_apss_boost_fuse_volt_param[] = {
166 {71, 0, 5},
167 {},
168};
169
170static const struct cpr3_fuse_param msm8953_misc_fuse_volt_adj_param[] = {
171 {36, 54, 54},
172 {},
173};
174
Tirupathi Reddy1bcb64f2016-03-01 16:54:40 +0530175static const struct cpr3_fuse_param msm8953_apss_aging_init_quot_diff_param[]
176= {
177 {72, 0, 7},
178 {},
179};
180
David Collins7370f1a2017-01-18 16:21:53 -0800181/*
Tirupathi Reddy53d99a02016-08-08 17:04:23 +0530182 * The maximum number of fuse combinations possible for the selected fuse
183 * parameters in fuse combo map logic.
184 * Here, possible speed-bin values = 8, fuse revision values = 8, and foundry
185 * identifier values = 8. Total number of combinations = 512 (i.e., 8 * 8 * 8)
186 */
187#define CPR4_MSM8953_APSS_FUSE_COMBO_MAP_MAX_COUNT 512
188
189
190/*
David Collins7370f1a2017-01-18 16:21:53 -0800191 * The number of possible values for misc fuse is
192 * 2^(#bits defined for misc fuse)
193 */
194#define MSM8953_MISC_FUSE_VAL_COUNT BIT(1)
195
196/*
197 * Open loop voltage fuse reference voltages in microvolts for MSM8953
198 */
199static const int msm8953_apss_fuse_ref_volt
200 [MSM8953_APSS_FUSE_CORNERS] = {
201 645000,
202 720000,
203 865000,
204 1065000,
205};
206
207#define MSM8953_APSS_FUSE_STEP_VOLT 10000
208#define MSM8953_APSS_VOLTAGE_FUSE_SIZE 6
209#define MSM8953_APSS_QUOT_OFFSET_SCALE 5
210
211#define MSM8953_APSS_CPR_SENSOR_COUNT 13
212
213#define MSM8953_APSS_CPR_CLOCK_RATE 19200000
214
215#define MSM8953_APSS_MAX_TEMP_POINTS 3
216#define MSM8953_APSS_TEMP_SENSOR_ID_START 4
217#define MSM8953_APSS_TEMP_SENSOR_ID_END 13
218/*
219 * Boost voltage fuse reference and ceiling voltages in microvolts for
220 * MSM8953.
221 */
222#define MSM8953_APSS_BOOST_FUSE_REF_VOLT 1140000
223#define MSM8953_APSS_BOOST_CEILING_VOLT 1140000
224#define MSM8953_APSS_BOOST_FLOOR_VOLT 900000
225#define MAX_BOOST_CONFIG_FUSE_VALUE 8
226
227#define MSM8953_APSS_CPR_SDELTA_CORE_COUNT 15
228
229/*
230 * Array of integer values mapped to each of the boost config fuse values to
231 * indicate boost enable/disable status.
232 */
233static bool boost_fuse[MAX_BOOST_CONFIG_FUSE_VALUE] = {0, 1, 1, 1, 1, 1, 1, 1};
234
Tirupathi Reddy1bcb64f2016-03-01 16:54:40 +0530235/* CPR Aging parameters for msm8953 */
236#define MSM8953_APSS_AGING_INIT_QUOT_DIFF_SCALE 1
237#define MSM8953_APSS_AGING_INIT_QUOT_DIFF_SIZE 8
238#define MSM8953_APSS_AGING_SENSOR_ID 6
239
240/* Use a very high value for max aging margin to be applied */
241#define MSM8953_APSS_AGING_MAX_AGE_MARGIN_QUOT (-1000)
242
David Collins7370f1a2017-01-18 16:21:53 -0800243/**
244 * cpr4_msm8953_apss_read_fuse_data() - load APSS specific fuse parameter values
245 * @vreg: Pointer to the CPR3 regulator
246 *
247 * This function allocates a cpr4_msm8953_apss_fuses struct, fills it with
248 * values read out of hardware fuses, and finally copies common fuse values
249 * into the CPR3 regulator struct.
250 *
251 * Return: 0 on success, errno on failure
252 */
253static int cpr4_msm8953_apss_read_fuse_data(struct cpr3_regulator *vreg)
254{
255 void __iomem *base = vreg->thread->ctrl->fuse_base;
256 struct cpr4_msm8953_apss_fuses *fuse;
257 int i, rc;
258
259 fuse = devm_kzalloc(vreg->thread->ctrl->dev, sizeof(*fuse), GFP_KERNEL);
260 if (!fuse)
261 return -ENOMEM;
262
263 rc = cpr3_read_fuse_param(base, msm8953_apss_speed_bin_param,
264 &fuse->speed_bin);
265 if (rc) {
266 cpr3_err(vreg, "Unable to read speed bin fuse, rc=%d\n", rc);
267 return rc;
268 }
269 cpr3_info(vreg, "speed bin = %llu\n", fuse->speed_bin);
270
271 rc = cpr3_read_fuse_param(base, msm8953_cpr_fusing_rev_param,
272 &fuse->cpr_fusing_rev);
273 if (rc) {
274 cpr3_err(vreg, "Unable to read CPR fusing revision fuse, rc=%d\n",
275 rc);
276 return rc;
277 }
278 cpr3_info(vreg, "CPR fusing revision = %llu\n", fuse->cpr_fusing_rev);
279
Tirupathi Reddy53d99a02016-08-08 17:04:23 +0530280 rc = cpr3_read_fuse_param(base, msm8953_apss_foundry_id_param,
281 &fuse->foundry_id);
282 if (rc) {
283 cpr3_err(vreg, "Unable to read foundry id fuse, rc=%d\n", rc);
284 return rc;
285 }
286 cpr3_info(vreg, "foundry id = %llu\n", fuse->foundry_id);
287
David Collins7370f1a2017-01-18 16:21:53 -0800288 rc = cpr3_read_fuse_param(base, msm8953_misc_fuse_volt_adj_param,
289 &fuse->misc);
290 if (rc) {
291 cpr3_err(vreg, "Unable to read misc voltage adjustment fuse, rc=%d\n",
292 rc);
293 return rc;
294 }
295 cpr3_info(vreg, "CPR misc fuse value = %llu\n", fuse->misc);
296 if (fuse->misc >= MSM8953_MISC_FUSE_VAL_COUNT) {
297 cpr3_err(vreg, "CPR misc fuse value = %llu, should be < %lu\n",
298 fuse->misc, MSM8953_MISC_FUSE_VAL_COUNT);
299 return -EINVAL;
300 }
301
Tirupathi Reddy1bcb64f2016-03-01 16:54:40 +0530302 rc = cpr3_read_fuse_param(base, msm8953_apss_aging_init_quot_diff_param,
303 &fuse->aging_init_quot_diff);
304 if (rc) {
305 cpr3_err(vreg, "Unable to read aging initial quotient difference fuse, rc=%d\n",
306 rc);
307 return rc;
308 }
309
David Collins7370f1a2017-01-18 16:21:53 -0800310 for (i = 0; i < MSM8953_APSS_FUSE_CORNERS; i++) {
311 rc = cpr3_read_fuse_param(base,
312 msm8953_apss_init_voltage_param[i],
313 &fuse->init_voltage[i]);
314 if (rc) {
315 cpr3_err(vreg, "Unable to read fuse-corner %d initial voltage fuse, rc=%d\n",
316 i, rc);
317 return rc;
318 }
319
320 rc = cpr3_read_fuse_param(base,
321 msm8953_apss_target_quot_param[i],
322 &fuse->target_quot[i]);
323 if (rc) {
324 cpr3_err(vreg, "Unable to read fuse-corner %d target quotient fuse, rc=%d\n",
325 i, rc);
326 return rc;
327 }
328
329 rc = cpr3_read_fuse_param(base,
330 msm8953_apss_ro_sel_param[i],
331 &fuse->ro_sel[i]);
332 if (rc) {
333 cpr3_err(vreg, "Unable to read fuse-corner %d RO select fuse, rc=%d\n",
334 i, rc);
335 return rc;
336 }
337
338 rc = cpr3_read_fuse_param(base,
339 msm8953_apss_quot_offset_param[i],
340 &fuse->quot_offset[i]);
341 if (rc) {
342 cpr3_err(vreg, "Unable to read fuse-corner %d quotient offset fuse, rc=%d\n",
343 i, rc);
344 return rc;
345 }
346 }
347
348 rc = cpr3_read_fuse_param(base, msm8953_cpr_boost_fuse_cfg_param,
349 &fuse->boost_cfg);
350 if (rc) {
351 cpr3_err(vreg, "Unable to read CPR boost config fuse, rc=%d\n",
352 rc);
353 return rc;
354 }
355 cpr3_info(vreg, "Voltage boost fuse config = %llu boost = %s\n",
356 fuse->boost_cfg, boost_fuse[fuse->boost_cfg]
357 ? "enable" : "disable");
358
359 rc = cpr3_read_fuse_param(base,
360 msm8953_apss_boost_fuse_volt_param,
361 &fuse->boost_voltage);
362 if (rc) {
363 cpr3_err(vreg, "failed to read boost fuse voltage, rc=%d\n",
364 rc);
365 return rc;
366 }
367
368 vreg->fuse_combo = fuse->cpr_fusing_rev + 8 * fuse->speed_bin;
369 if (vreg->fuse_combo >= CPR4_MSM8953_APSS_FUSE_COMBO_COUNT) {
370 cpr3_err(vreg, "invalid CPR fuse combo = %d found\n",
371 vreg->fuse_combo);
372 return -EINVAL;
373 }
374
375 vreg->speed_bin_fuse = fuse->speed_bin;
376 vreg->cpr_rev_fuse = fuse->cpr_fusing_rev;
377 vreg->fuse_corner_count = MSM8953_APSS_FUSE_CORNERS;
378 vreg->platform_fuses = fuse;
379
380 return 0;
381}
382
383/**
384 * cpr4_apss_parse_corner_data() - parse APSS corner data from device tree
385 * properties of the CPR3 regulator's device node
386 * @vreg: Pointer to the CPR3 regulator
387 *
388 * Return: 0 on success, errno on failure
389 */
390static int cpr4_apss_parse_corner_data(struct cpr3_regulator *vreg)
391{
392 int rc;
393
394 rc = cpr3_parse_common_corner_data(vreg);
395 if (rc) {
396 cpr3_err(vreg, "error reading corner data, rc=%d\n", rc);
397 return rc;
398 }
399
400 return rc;
401}
402
403/**
404 * cpr4_apss_parse_misc_fuse_voltage_adjustments() - fill an array from a
405 * portion of the voltage adjustments specified based on
406 * miscellaneous fuse bits.
407 * @vreg: Pointer to the CPR3 regulator
408 * @volt_adjust: Voltage adjustment output data array which must be
409 * of size vreg->corner_count
410 *
411 * cpr3_parse_common_corner_data() must be called for vreg before this function
412 * is called so that speed bin size elements are initialized.
413 *
414 * Two formats are supported for the device tree property:
415 * 1. Length == tuple_list_size * vreg->corner_count
416 * (reading begins at index 0)
417 * 2. Length == tuple_list_size * vreg->speed_bin_corner_sum
418 * (reading begins at index tuple_list_size * vreg->speed_bin_offset)
419 *
420 * Here, tuple_list_size is the number of possible values for misc fuse.
421 * All other property lengths are treated as errors.
422 *
423 * Return: 0 on success, errno on failure
424 */
425static int cpr4_apss_parse_misc_fuse_voltage_adjustments(
426 struct cpr3_regulator *vreg, u32 *volt_adjust)
427{
428 struct device_node *node = vreg->of_node;
429 struct cpr4_msm8953_apss_fuses *fuse = vreg->platform_fuses;
430 int tuple_list_size = MSM8953_MISC_FUSE_VAL_COUNT;
431 int i, offset, rc, len = 0;
432 const char *prop_name = "qcom,cpr-misc-fuse-voltage-adjustment";
433
434 if (!of_find_property(node, prop_name, &len)) {
435 cpr3_err(vreg, "property %s is missing\n", prop_name);
436 return -EINVAL;
437 }
438
439 if (len == tuple_list_size * vreg->corner_count * sizeof(u32)) {
440 offset = 0;
441 } else if (vreg->speed_bin_corner_sum > 0 &&
442 len == tuple_list_size * vreg->speed_bin_corner_sum
443 * sizeof(u32)) {
444 offset = tuple_list_size * vreg->speed_bin_offset
445 + fuse->misc * vreg->corner_count;
446 } else {
447 if (vreg->speed_bin_corner_sum > 0)
448 cpr3_err(vreg, "property %s has invalid length=%d, should be %zu or %zu\n",
449 prop_name, len,
450 tuple_list_size * vreg->corner_count
451 * sizeof(u32),
452 tuple_list_size * vreg->speed_bin_corner_sum
453 * sizeof(u32));
454 else
455 cpr3_err(vreg, "property %s has invalid length=%d, should be %zu\n",
456 prop_name, len,
457 tuple_list_size * vreg->corner_count
458 * sizeof(u32));
459 return -EINVAL;
460 }
461
462 for (i = 0; i < vreg->corner_count; i++) {
463 rc = of_property_read_u32_index(node, prop_name, offset + i,
464 &volt_adjust[i]);
465 if (rc) {
466 cpr3_err(vreg, "error reading property %s, rc=%d\n",
467 prop_name, rc);
468 return rc;
469 }
470 }
471
472 return 0;
473}
474
475/**
476 * cpr4_msm8953_apss_calculate_open_loop_voltages() - calculate the open-loop
477 * voltage for each corner of a CPR3 regulator
478 * @vreg: Pointer to the CPR3 regulator
479 *
480 * If open-loop voltage interpolation is allowed in device tree, then
481 * this function calculates the open-loop voltage for a given corner using
482 * linear interpolation. This interpolation is performed using the processor
483 * frequencies of the lower and higher Fmax corners along with their fused
484 * open-loop voltages.
485 *
486 * If open-loop voltage interpolation is not allowed, then this function uses
487 * the Fmax fused open-loop voltage for all of the corners associated with a
488 * given fuse corner.
489 *
490 * Return: 0 on success, errno on failure
491 */
492static int cpr4_msm8953_apss_calculate_open_loop_voltages(
493 struct cpr3_regulator *vreg)
494{
495 struct device_node *node = vreg->of_node;
496 struct cpr4_msm8953_apss_fuses *fuse = vreg->platform_fuses;
497 int i, j, rc = 0;
498 bool allow_interpolation;
499 u64 freq_low, volt_low, freq_high, volt_high;
500 int *fuse_volt, *misc_adj_volt;
501 int *fmax_corner;
502
503 fuse_volt = kcalloc(vreg->fuse_corner_count, sizeof(*fuse_volt),
504 GFP_KERNEL);
505 fmax_corner = kcalloc(vreg->fuse_corner_count, sizeof(*fmax_corner),
506 GFP_KERNEL);
507 if (!fuse_volt || !fmax_corner) {
508 rc = -ENOMEM;
509 goto done;
510 }
511
512 for (i = 0; i < vreg->fuse_corner_count; i++) {
513 fuse_volt[i] = cpr3_convert_open_loop_voltage_fuse(
514 msm8953_apss_fuse_ref_volt[i],
515 MSM8953_APSS_FUSE_STEP_VOLT, fuse->init_voltage[i],
516 MSM8953_APSS_VOLTAGE_FUSE_SIZE);
517
518 /* Log fused open-loop voltage values for debugging purposes. */
519 cpr3_info(vreg, "fused %8s: open-loop=%7d uV\n",
520 cpr4_msm8953_apss_fuse_corner_name[i],
521 fuse_volt[i]);
522 }
523
524 rc = cpr3_adjust_fused_open_loop_voltages(vreg, fuse_volt);
525 if (rc) {
526 cpr3_err(vreg, "fused open-loop voltage adjustment failed, rc=%d\n",
527 rc);
528 goto done;
529 }
530
531 allow_interpolation = of_property_read_bool(node,
532 "qcom,allow-voltage-interpolation");
533
534 for (i = 1; i < vreg->fuse_corner_count; i++) {
535 if (fuse_volt[i] < fuse_volt[i - 1]) {
536 cpr3_info(vreg, "fuse corner %d voltage=%d uV < fuse corner %d voltage=%d uV; overriding: fuse corner %d voltage=%d\n",
537 i, fuse_volt[i], i - 1, fuse_volt[i - 1],
538 i, fuse_volt[i - 1]);
539 fuse_volt[i] = fuse_volt[i - 1];
540 }
541 }
542
543 if (!allow_interpolation) {
544 /* Use fused open-loop voltage for lower frequencies. */
545 for (i = 0; i < vreg->corner_count; i++)
546 vreg->corner[i].open_loop_volt
547 = fuse_volt[vreg->corner[i].cpr_fuse_corner];
548 goto done;
549 }
550
551 /* Determine highest corner mapped to each fuse corner */
552 j = vreg->fuse_corner_count - 1;
553 for (i = vreg->corner_count - 1; i >= 0; i--) {
554 if (vreg->corner[i].cpr_fuse_corner == j) {
555 fmax_corner[j] = i;
556 j--;
557 }
558 }
559 if (j >= 0) {
560 cpr3_err(vreg, "invalid fuse corner mapping\n");
561 rc = -EINVAL;
562 goto done;
563 }
564
565 /*
566 * Interpolation is not possible for corners mapped to the lowest fuse
567 * corner so use the fuse corner value directly.
568 */
569 for (i = 0; i <= fmax_corner[0]; i++)
570 vreg->corner[i].open_loop_volt = fuse_volt[0];
571
572 /* Interpolate voltages for the higher fuse corners. */
573 for (i = 1; i < vreg->fuse_corner_count; i++) {
574 freq_low = vreg->corner[fmax_corner[i - 1]].proc_freq;
575 volt_low = fuse_volt[i - 1];
576 freq_high = vreg->corner[fmax_corner[i]].proc_freq;
577 volt_high = fuse_volt[i];
578
579 for (j = fmax_corner[i - 1] + 1; j <= fmax_corner[i]; j++)
580 vreg->corner[j].open_loop_volt = cpr3_interpolate(
581 freq_low, volt_low, freq_high, volt_high,
582 vreg->corner[j].proc_freq);
583 }
584
585done:
586 if (rc == 0) {
587 cpr3_debug(vreg, "unadjusted per-corner open-loop voltages:\n");
588 for (i = 0; i < vreg->corner_count; i++)
589 cpr3_debug(vreg, "open-loop[%2d] = %d uV\n", i,
590 vreg->corner[i].open_loop_volt);
591
592 rc = cpr3_adjust_open_loop_voltages(vreg);
593 if (rc)
594 cpr3_err(vreg, "open-loop voltage adjustment failed, rc=%d\n",
595 rc);
596
597 if (of_find_property(node,
598 "qcom,cpr-misc-fuse-voltage-adjustment",
599 NULL)) {
600 misc_adj_volt = kcalloc(vreg->corner_count,
601 sizeof(*misc_adj_volt), GFP_KERNEL);
602 if (!misc_adj_volt) {
603 rc = -ENOMEM;
604 goto _exit;
605 }
606
607 rc = cpr4_apss_parse_misc_fuse_voltage_adjustments(vreg,
608 misc_adj_volt);
609 if (rc) {
610 cpr3_err(vreg, "qcom,cpr-misc-fuse-voltage-adjustment reading failed, rc=%d\n",
611 rc);
612 kfree(misc_adj_volt);
613 goto _exit;
614 }
615
616 for (i = 0; i < vreg->corner_count; i++)
617 vreg->corner[i].open_loop_volt
618 += misc_adj_volt[i];
619 kfree(misc_adj_volt);
620 }
621 }
622
623_exit:
624 kfree(fuse_volt);
625 kfree(fmax_corner);
626 return rc;
627}
628
629/**
630 * cpr4_msm8953_apss_set_no_interpolation_quotients() - use the fused target
631 * quotient values for lower frequencies.
632 * @vreg: Pointer to the CPR3 regulator
633 * @volt_adjust: Pointer to array of per-corner closed-loop adjustment
634 * voltages
635 * @volt_adjust_fuse: Pointer to array of per-fuse-corner closed-loop
636 * adjustment voltages
637 * @ro_scale: Pointer to array of per-fuse-corner RO scaling factor
638 * values with units of QUOT/V
639 *
640 * Return: 0 on success, errno on failure
641 */
642static int cpr4_msm8953_apss_set_no_interpolation_quotients(
643 struct cpr3_regulator *vreg, int *volt_adjust,
644 int *volt_adjust_fuse, int *ro_scale)
645{
646 struct cpr4_msm8953_apss_fuses *fuse = vreg->platform_fuses;
647 u32 quot, ro;
648 int quot_adjust;
649 int i, fuse_corner;
650
651 for (i = 0; i < vreg->corner_count; i++) {
652 fuse_corner = vreg->corner[i].cpr_fuse_corner;
653 quot = fuse->target_quot[fuse_corner];
654 quot_adjust = cpr3_quot_adjustment(ro_scale[fuse_corner],
655 volt_adjust_fuse[fuse_corner] +
656 volt_adjust[i]);
657 ro = fuse->ro_sel[fuse_corner];
658 vreg->corner[i].target_quot[ro] = quot + quot_adjust;
659 cpr3_debug(vreg, "corner=%d RO=%u target quot=%u\n",
660 i, ro, quot);
661
662 if (quot_adjust)
663 cpr3_debug(vreg, "adjusted corner %d RO%u target quot: %u --> %u (%d uV)\n",
664 i, ro, quot, vreg->corner[i].target_quot[ro],
665 volt_adjust_fuse[fuse_corner] +
666 volt_adjust[i]);
667 }
668
669 return 0;
670}
671
672/**
673 * cpr4_msm8953_apss_calculate_target_quotients() - calculate the CPR target
674 * quotient for each corner of a CPR3 regulator
675 * @vreg: Pointer to the CPR3 regulator
676 *
677 * If target quotient interpolation is allowed in device tree, then this
678 * function calculates the target quotient for a given corner using linear
679 * interpolation. This interpolation is performed using the processor
680 * frequencies of the lower and higher Fmax corners along with the fused
681 * target quotient and quotient offset of the higher Fmax corner.
682 *
683 * If target quotient interpolation is not allowed, then this function uses
684 * the Fmax fused target quotient for all of the corners associated with a
685 * given fuse corner.
686 *
687 * Return: 0 on success, errno on failure
688 */
689static int cpr4_msm8953_apss_calculate_target_quotients(
690 struct cpr3_regulator *vreg)
691{
692 struct cpr4_msm8953_apss_fuses *fuse = vreg->platform_fuses;
693 int rc;
694 bool allow_interpolation;
695 u64 freq_low, freq_high, prev_quot;
696 u64 *quot_low;
697 u64 *quot_high;
698 u32 quot, ro;
699 int i, j, fuse_corner, quot_adjust;
700 int *fmax_corner;
701 int *volt_adjust, *volt_adjust_fuse, *ro_scale;
702 int *voltage_adj_misc;
703
704 /* Log fused quotient values for debugging purposes. */
705 cpr3_info(vreg, "fused LowSVS: quot[%2llu]=%4llu\n",
706 fuse->ro_sel[CPR4_MSM8953_APSS_FUSE_CORNER_LOWSVS],
707 fuse->target_quot[CPR4_MSM8953_APSS_FUSE_CORNER_LOWSVS]);
708 for (i = CPR4_MSM8953_APSS_FUSE_CORNER_SVS;
709 i <= CPR4_MSM8953_APSS_FUSE_CORNER_TURBO_L1; i++)
710 cpr3_info(vreg, "fused %8s: quot[%2llu]=%4llu, quot_offset[%2llu]=%4llu\n",
711 cpr4_msm8953_apss_fuse_corner_name[i],
712 fuse->ro_sel[i], fuse->target_quot[i],
713 fuse->ro_sel[i], fuse->quot_offset[i] *
714 MSM8953_APSS_QUOT_OFFSET_SCALE);
715
716 allow_interpolation = of_property_read_bool(vreg->of_node,
717 "qcom,allow-quotient-interpolation");
718
719 volt_adjust = kcalloc(vreg->corner_count, sizeof(*volt_adjust),
720 GFP_KERNEL);
721 volt_adjust_fuse = kcalloc(vreg->fuse_corner_count,
722 sizeof(*volt_adjust_fuse), GFP_KERNEL);
723 ro_scale = kcalloc(vreg->fuse_corner_count, sizeof(*ro_scale),
724 GFP_KERNEL);
725 fmax_corner = kcalloc(vreg->fuse_corner_count, sizeof(*fmax_corner),
726 GFP_KERNEL);
727 quot_low = kcalloc(vreg->fuse_corner_count, sizeof(*quot_low),
728 GFP_KERNEL);
729 quot_high = kcalloc(vreg->fuse_corner_count, sizeof(*quot_high),
730 GFP_KERNEL);
731 if (!volt_adjust || !volt_adjust_fuse || !ro_scale ||
732 !fmax_corner || !quot_low || !quot_high) {
733 rc = -ENOMEM;
734 goto done;
735 }
736
737 rc = cpr3_parse_closed_loop_voltage_adjustments(vreg, &fuse->ro_sel[0],
738 volt_adjust, volt_adjust_fuse, ro_scale);
739 if (rc) {
740 cpr3_err(vreg, "could not load closed-loop voltage adjustments, rc=%d\n",
741 rc);
742 goto done;
743 }
744
745 if (of_find_property(vreg->of_node,
746 "qcom,cpr-misc-fuse-voltage-adjustment", NULL)) {
747 voltage_adj_misc = kcalloc(vreg->corner_count,
748 sizeof(*voltage_adj_misc), GFP_KERNEL);
749 if (!voltage_adj_misc) {
750 rc = -ENOMEM;
751 goto done;
752 }
753
754 rc = cpr4_apss_parse_misc_fuse_voltage_adjustments(vreg,
755 voltage_adj_misc);
756 if (rc) {
757 cpr3_err(vreg, "qcom,cpr-misc-fuse-voltage-adjustment reading failed, rc=%d\n",
758 rc);
759 kfree(voltage_adj_misc);
760 goto done;
761 }
762
763 for (i = 0; i < vreg->corner_count; i++)
764 volt_adjust[i] += voltage_adj_misc[i];
765
766 kfree(voltage_adj_misc);
767 }
768
769 if (!allow_interpolation) {
770 /* Use fused target quotients for lower frequencies. */
771 return cpr4_msm8953_apss_set_no_interpolation_quotients(
772 vreg, volt_adjust, volt_adjust_fuse, ro_scale);
773 }
774
775 /* Determine highest corner mapped to each fuse corner */
776 j = vreg->fuse_corner_count - 1;
777 for (i = vreg->corner_count - 1; i >= 0; i--) {
778 if (vreg->corner[i].cpr_fuse_corner == j) {
779 fmax_corner[j] = i;
780 j--;
781 }
782 }
783 if (j >= 0) {
784 cpr3_err(vreg, "invalid fuse corner mapping\n");
785 rc = -EINVAL;
786 goto done;
787 }
788
789 /*
790 * Interpolation is not possible for corners mapped to the lowest fuse
791 * corner so use the fuse corner value directly.
792 */
793 i = CPR4_MSM8953_APSS_FUSE_CORNER_LOWSVS;
794 quot_adjust = cpr3_quot_adjustment(ro_scale[i], volt_adjust_fuse[i]);
795 quot = fuse->target_quot[i] + quot_adjust;
796 quot_high[i] = quot_low[i] = quot;
797 ro = fuse->ro_sel[i];
798 if (quot_adjust)
799 cpr3_debug(vreg, "adjusted fuse corner %d RO%u target quot: %llu --> %u (%d uV)\n",
800 i, ro, fuse->target_quot[i], quot, volt_adjust_fuse[i]);
801
802 for (i = 0; i <= fmax_corner[CPR4_MSM8953_APSS_FUSE_CORNER_LOWSVS];
803 i++)
804 vreg->corner[i].target_quot[ro] = quot;
805
806 for (i = CPR4_MSM8953_APSS_FUSE_CORNER_SVS;
807 i < vreg->fuse_corner_count; i++) {
808 quot_high[i] = fuse->target_quot[i];
809 if (fuse->ro_sel[i] == fuse->ro_sel[i - 1])
810 quot_low[i] = quot_high[i - 1];
811 else
812 quot_low[i] = quot_high[i]
813 - fuse->quot_offset[i]
814 * MSM8953_APSS_QUOT_OFFSET_SCALE;
815 if (quot_high[i] < quot_low[i]) {
816 cpr3_debug(vreg, "quot_high[%d]=%llu < quot_low[%d]=%llu; overriding: quot_high[%d]=%llu\n",
817 i, quot_high[i], i, quot_low[i],
818 i, quot_low[i]);
819 quot_high[i] = quot_low[i];
820 }
821 }
822
823 /* Perform per-fuse-corner target quotient adjustment */
824 for (i = 1; i < vreg->fuse_corner_count; i++) {
825 quot_adjust = cpr3_quot_adjustment(ro_scale[i],
826 volt_adjust_fuse[i]);
827 if (quot_adjust) {
828 prev_quot = quot_high[i];
829 quot_high[i] += quot_adjust;
830 cpr3_debug(vreg, "adjusted fuse corner %d RO%llu target quot: %llu --> %llu (%d uV)\n",
831 i, fuse->ro_sel[i], prev_quot, quot_high[i],
832 volt_adjust_fuse[i]);
833 }
834
835 if (fuse->ro_sel[i] == fuse->ro_sel[i - 1])
836 quot_low[i] = quot_high[i - 1];
837 else
838 quot_low[i] += cpr3_quot_adjustment(ro_scale[i],
839 volt_adjust_fuse[i - 1]);
840
841 if (quot_high[i] < quot_low[i]) {
842 cpr3_debug(vreg, "quot_high[%d]=%llu < quot_low[%d]=%llu after adjustment; overriding: quot_high[%d]=%llu\n",
843 i, quot_high[i], i, quot_low[i],
844 i, quot_low[i]);
845 quot_high[i] = quot_low[i];
846 }
847 }
848
849 /* Interpolate voltages for the higher fuse corners. */
850 for (i = 1; i < vreg->fuse_corner_count; i++) {
851 freq_low = vreg->corner[fmax_corner[i - 1]].proc_freq;
852 freq_high = vreg->corner[fmax_corner[i]].proc_freq;
853
854 ro = fuse->ro_sel[i];
855 for (j = fmax_corner[i - 1] + 1; j <= fmax_corner[i]; j++)
856 vreg->corner[j].target_quot[ro] = cpr3_interpolate(
857 freq_low, quot_low[i], freq_high, quot_high[i],
858 vreg->corner[j].proc_freq);
859 }
860
861 /* Perform per-corner target quotient adjustment */
862 for (i = 0; i < vreg->corner_count; i++) {
863 fuse_corner = vreg->corner[i].cpr_fuse_corner;
864 ro = fuse->ro_sel[fuse_corner];
865 quot_adjust = cpr3_quot_adjustment(ro_scale[fuse_corner],
866 volt_adjust[i]);
867 if (quot_adjust) {
868 prev_quot = vreg->corner[i].target_quot[ro];
869 vreg->corner[i].target_quot[ro] += quot_adjust;
870 cpr3_debug(vreg, "adjusted corner %d RO%u target quot: %llu --> %u (%d uV)\n",
871 i, ro, prev_quot,
872 vreg->corner[i].target_quot[ro],
873 volt_adjust[i]);
874 }
875 }
876
877 /* Ensure that target quotients increase monotonically */
878 for (i = 1; i < vreg->corner_count; i++) {
879 ro = fuse->ro_sel[vreg->corner[i].cpr_fuse_corner];
880 if (fuse->ro_sel[vreg->corner[i - 1].cpr_fuse_corner] == ro
881 && vreg->corner[i].target_quot[ro]
882 < vreg->corner[i - 1].target_quot[ro]) {
883 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",
884 i, ro, vreg->corner[i].target_quot[ro],
885 i - 1, ro, vreg->corner[i - 1].target_quot[ro],
886 i, ro, vreg->corner[i - 1].target_quot[ro]);
887 vreg->corner[i].target_quot[ro]
888 = vreg->corner[i - 1].target_quot[ro];
889 }
890 }
891
892done:
893 kfree(volt_adjust);
894 kfree(volt_adjust_fuse);
895 kfree(ro_scale);
896 kfree(fmax_corner);
897 kfree(quot_low);
898 kfree(quot_high);
899 return rc;
900}
901
902/**
903 * cpr4_apss_print_settings() - print out APSS CPR configuration settings into
904 * the kernel log for debugging purposes
905 * @vreg: Pointer to the CPR3 regulator
906 */
907static void cpr4_apss_print_settings(struct cpr3_regulator *vreg)
908{
909 struct cpr3_corner *corner;
910 int i;
911
912 cpr3_debug(vreg, "Corner: Frequency (Hz), Fuse Corner, Floor (uV), Open-Loop (uV), Ceiling (uV)\n");
913 for (i = 0; i < vreg->corner_count; i++) {
914 corner = &vreg->corner[i];
915 cpr3_debug(vreg, "%3d: %10u, %2d, %7d, %7d, %7d\n",
916 i, corner->proc_freq, corner->cpr_fuse_corner,
917 corner->floor_volt, corner->open_loop_volt,
918 corner->ceiling_volt);
919 }
920
921 if (vreg->thread->ctrl->apm)
922 cpr3_debug(vreg, "APM threshold = %d uV, APM adjust = %d uV\n",
923 vreg->thread->ctrl->apm_threshold_volt,
924 vreg->thread->ctrl->apm_adj_volt);
925}
926
927/**
928 * cpr4_apss_init_thread() - perform steps necessary to initialize the
929 * configuration data for a CPR3 thread
930 * @thread: Pointer to the CPR3 thread
931 *
932 * Return: 0 on success, errno on failure
933 */
934static int cpr4_apss_init_thread(struct cpr3_thread *thread)
935{
936 int rc;
937
938 rc = cpr3_parse_common_thread_data(thread);
939 if (rc) {
940 cpr3_err(thread->ctrl, "thread %u unable to read CPR thread data from device tree, rc=%d\n",
941 thread->thread_id, rc);
942 return rc;
943 }
944
945 return 0;
946}
947
948/**
949 * cpr4_apss_parse_temp_adj_properties() - parse temperature based
950 * adjustment properties from device tree.
951 * @ctrl: Pointer to the CPR3 controller
952 *
953 * Return: 0 on success, errno on failure
954 */
955static int cpr4_apss_parse_temp_adj_properties(struct cpr3_controller *ctrl)
956{
957 struct device_node *of_node = ctrl->dev->of_node;
958 int rc, i, len, temp_point_count;
959
960 if (!of_find_property(of_node, "qcom,cpr-temp-point-map", &len)) {
961 /*
962 * Temperature based adjustments are not defined. Single
963 * temperature band is still valid for per-online-core
964 * adjustments.
965 */
966 ctrl->temp_band_count = 1;
967 return 0;
968 }
969
970 temp_point_count = len / sizeof(u32);
971 if (temp_point_count <= 0
972 || temp_point_count > MSM8953_APSS_MAX_TEMP_POINTS) {
973 cpr3_err(ctrl, "invalid number of temperature points %d > %d (max)\n",
974 temp_point_count, MSM8953_APSS_MAX_TEMP_POINTS);
975 return -EINVAL;
976 }
977
978 ctrl->temp_points = devm_kcalloc(ctrl->dev, temp_point_count,
979 sizeof(*ctrl->temp_points), GFP_KERNEL);
980 if (!ctrl->temp_points)
981 return -ENOMEM;
982
983 rc = of_property_read_u32_array(of_node, "qcom,cpr-temp-point-map",
984 ctrl->temp_points, temp_point_count);
985 if (rc) {
986 cpr3_err(ctrl, "error reading property qcom,cpr-temp-point-map, rc=%d\n",
987 rc);
988 return rc;
989 }
990
991 for (i = 0; i < temp_point_count; i++)
992 cpr3_debug(ctrl, "Temperature Point %d=%d\n", i,
993 ctrl->temp_points[i]);
994
995 /*
996 * If t1, t2, and t3 are the temperature points, then the temperature
997 * bands are: (-inf, t1], (t1, t2], (t2, t3], and (t3, inf).
998 */
999 ctrl->temp_band_count = temp_point_count + 1;
1000 cpr3_debug(ctrl, "Number of temp bands =%d\n", ctrl->temp_band_count);
1001
1002 rc = of_property_read_u32(of_node, "qcom,cpr-initial-temp-band",
1003 &ctrl->initial_temp_band);
1004 if (rc) {
1005 cpr3_err(ctrl, "error reading qcom,cpr-initial-temp-band, rc=%d\n",
1006 rc);
1007 return rc;
1008 }
1009
1010 if (ctrl->initial_temp_band >= ctrl->temp_band_count) {
1011 cpr3_err(ctrl, "Initial temperature band value %d should be in range [0 - %d]\n",
1012 ctrl->initial_temp_band, ctrl->temp_band_count - 1);
1013 return -EINVAL;
1014 }
1015
1016 ctrl->temp_sensor_id_start = MSM8953_APSS_TEMP_SENSOR_ID_START;
1017 ctrl->temp_sensor_id_end = MSM8953_APSS_TEMP_SENSOR_ID_END;
1018 ctrl->allow_temp_adj = true;
1019 return rc;
1020}
1021
1022/**
1023 * cpr4_apss_parse_boost_properties() - parse configuration data for boost
1024 * voltage adjustment for CPR3 regulator from device tree.
1025 * @vreg: Pointer to the CPR3 regulator
1026 *
1027 * Return: 0 on success, errno on failure
1028 */
1029static int cpr4_apss_parse_boost_properties(struct cpr3_regulator *vreg)
1030{
1031 struct cpr3_controller *ctrl = vreg->thread->ctrl;
1032 struct cpr4_msm8953_apss_fuses *fuse = vreg->platform_fuses;
1033 struct cpr3_corner *corner;
1034 int i, boost_voltage, final_boost_volt, rc = 0;
1035 int *boost_table = NULL, *boost_temp_adj = NULL;
1036 int boost_voltage_adjust = 0, boost_num_cores = 0;
1037 u32 boost_allowed = 0;
1038
1039 if (!boost_fuse[fuse->boost_cfg])
1040 /* Voltage boost is disabled in fuse */
1041 return 0;
1042
1043 if (of_find_property(vreg->of_node, "qcom,allow-boost", NULL)) {
1044 rc = cpr3_parse_array_property(vreg, "qcom,allow-boost", 1,
1045 &boost_allowed);
1046 if (rc)
1047 return rc;
1048 }
1049
1050 if (!boost_allowed) {
1051 /* Voltage boost is not enabled for this regulator */
1052 return 0;
1053 }
1054
1055 boost_voltage = cpr3_convert_open_loop_voltage_fuse(
1056 MSM8953_APSS_BOOST_FUSE_REF_VOLT,
1057 MSM8953_APSS_FUSE_STEP_VOLT,
1058 fuse->boost_voltage,
1059 MSM8953_APSS_VOLTAGE_FUSE_SIZE);
1060
1061 /* Log boost voltage value for debugging purposes. */
1062 cpr3_info(vreg, "Boost open-loop=%7d uV\n", boost_voltage);
1063
1064 if (of_find_property(vreg->of_node,
1065 "qcom,cpr-boost-voltage-fuse-adjustment", NULL)) {
1066 rc = cpr3_parse_array_property(vreg,
1067 "qcom,cpr-boost-voltage-fuse-adjustment",
1068 1, &boost_voltage_adjust);
1069 if (rc) {
1070 cpr3_err(vreg, "qcom,cpr-boost-voltage-fuse-adjustment reading failed, rc=%d\n",
1071 rc);
1072 return rc;
1073 }
1074
1075 boost_voltage += boost_voltage_adjust;
1076 /* Log boost voltage value for debugging purposes. */
1077 cpr3_info(vreg, "Adjusted boost open-loop=%7d uV\n",
1078 boost_voltage);
1079 }
1080
1081 /* Limit boost voltage value between ceiling and floor voltage limits */
1082 boost_voltage = min(boost_voltage, MSM8953_APSS_BOOST_CEILING_VOLT);
1083 boost_voltage = max(boost_voltage, MSM8953_APSS_BOOST_FLOOR_VOLT);
1084
1085 /*
1086 * The boost feature can only be used for the highest voltage corner.
1087 * Also, keep core-count adjustments disabled when the boost feature
1088 * is enabled.
1089 */
1090 corner = &vreg->corner[vreg->corner_count - 1];
1091 if (!corner->sdelta) {
1092 /*
1093 * If core-count/temp adjustments are not defined, the cpr4
1094 * sdelta for this corner will not be allocated. Allocate it
1095 * here for boost configuration.
1096 */
1097 corner->sdelta = devm_kzalloc(ctrl->dev,
1098 sizeof(*corner->sdelta), GFP_KERNEL);
1099 if (!corner->sdelta)
1100 return -ENOMEM;
1101 }
1102 corner->sdelta->temp_band_count = ctrl->temp_band_count;
1103
1104 rc = of_property_read_u32(vreg->of_node, "qcom,cpr-num-boost-cores",
1105 &boost_num_cores);
1106 if (rc) {
1107 cpr3_err(vreg, "qcom,cpr-num-boost-cores reading failed, rc=%d\n",
1108 rc);
1109 return rc;
1110 }
1111
1112 if (boost_num_cores <= 0
1113 || boost_num_cores > MSM8953_APSS_CPR_SDELTA_CORE_COUNT) {
1114 cpr3_err(vreg, "Invalid boost number of cores = %d\n",
1115 boost_num_cores);
1116 return -EINVAL;
1117 }
1118 corner->sdelta->boost_num_cores = boost_num_cores;
1119
1120 boost_table = devm_kcalloc(ctrl->dev, corner->sdelta->temp_band_count,
1121 sizeof(*boost_table), GFP_KERNEL);
1122 if (!boost_table)
1123 return -ENOMEM;
1124
1125 if (of_find_property(vreg->of_node,
1126 "qcom,cpr-boost-temp-adjustment", NULL)) {
1127 boost_temp_adj = kcalloc(corner->sdelta->temp_band_count,
1128 sizeof(*boost_temp_adj), GFP_KERNEL);
1129 if (!boost_temp_adj)
1130 return -ENOMEM;
1131
1132 rc = cpr3_parse_array_property(vreg,
1133 "qcom,cpr-boost-temp-adjustment",
1134 corner->sdelta->temp_band_count,
1135 boost_temp_adj);
1136 if (rc) {
1137 cpr3_err(vreg, "qcom,cpr-boost-temp-adjustment reading failed, rc=%d\n",
1138 rc);
1139 goto done;
1140 }
1141 }
1142
1143 for (i = 0; i < corner->sdelta->temp_band_count; i++) {
1144 /* Apply static adjustments to boost voltage */
1145 final_boost_volt = boost_voltage + (boost_temp_adj == NULL
1146 ? 0 : boost_temp_adj[i]);
1147 /*
1148 * Limit final adjusted boost voltage value between ceiling
1149 * and floor voltage limits
1150 */
1151 final_boost_volt = min(final_boost_volt,
1152 MSM8953_APSS_BOOST_CEILING_VOLT);
1153 final_boost_volt = max(final_boost_volt,
1154 MSM8953_APSS_BOOST_FLOOR_VOLT);
1155
1156 boost_table[i] = (corner->open_loop_volt - final_boost_volt)
1157 / ctrl->step_volt;
1158 cpr3_debug(vreg, "Adjusted boost voltage margin for temp band %d = %d steps\n",
1159 i, boost_table[i]);
1160 }
1161
1162 corner->ceiling_volt = MSM8953_APSS_BOOST_CEILING_VOLT;
1163 corner->sdelta->boost_table = boost_table;
1164 corner->sdelta->allow_boost = true;
1165 corner->sdelta->allow_core_count_adj = false;
1166 vreg->allow_boost = true;
1167 ctrl->allow_boost = true;
1168done:
1169 kfree(boost_temp_adj);
1170 return rc;
1171}
1172
Tirupathi Reddy53d99a02016-08-08 17:04:23 +05301173/*
1174 * Constants which define the selection fuse parameters used in fuse combo map
1175 * logic.
1176 */
1177enum cpr4_msm8953_apss_fuse_combo_parameters {
1178 MSM8953_APSS_SPEED_BIN = 0,
1179 MSM8953_APSS_CPR_FUSE_REV,
1180 MSM8953_APSS_FOUNDRY_ID,
1181 MSM8953_APSS_FUSE_COMBO_PARAM_COUNT,
1182};
1183
1184/**
1185 * cpr4_parse_fuse_combo_map() - parse APSS fuse combo map data from device tree
1186 * properties of the CPR3 regulator's device node
1187 * @vreg: Pointer to the CPR3 regulator
1188 *
1189 * Return: 0 on success, errno on failure
1190 */
1191static int cpr4_parse_fuse_combo_map(struct cpr3_regulator *vreg)
1192{
1193 struct cpr4_msm8953_apss_fuses *fuse = vreg->platform_fuses;
1194 u64 *fuse_val;
1195 int rc;
1196
1197 fuse_val = kcalloc(MSM8953_APSS_FUSE_COMBO_PARAM_COUNT,
1198 sizeof(*fuse_val), GFP_KERNEL);
1199 if (!fuse_val)
1200 return -ENOMEM;
1201
1202 fuse_val[MSM8953_APSS_SPEED_BIN] = fuse->speed_bin;
1203 fuse_val[MSM8953_APSS_CPR_FUSE_REV] = fuse->cpr_fusing_rev;
1204 fuse_val[MSM8953_APSS_FOUNDRY_ID] = fuse->foundry_id;
1205 rc = cpr3_parse_fuse_combo_map(vreg, fuse_val,
1206 MSM8953_APSS_FUSE_COMBO_PARAM_COUNT);
1207 if (rc == -ENODEV) {
1208 cpr3_debug(vreg, "using legacy fuse combo logic, rc=%d\n",
1209 rc);
1210 rc = 0;
1211 } else if (rc < 0) {
1212 cpr3_err(vreg, "error reading fuse combo map data, rc=%d\n",
1213 rc);
1214 } else if (vreg->fuse_combo >=
1215 CPR4_MSM8953_APSS_FUSE_COMBO_MAP_MAX_COUNT) {
1216 cpr3_err(vreg, "invalid CPR fuse combo = %d found\n",
1217 vreg->fuse_combo);
1218 rc = -EINVAL;
1219 }
1220
1221 kfree(fuse_val);
1222 return rc;
1223}
1224
David Collins7370f1a2017-01-18 16:21:53 -08001225/**
1226 * cpr4_apss_init_regulator() - perform all steps necessary to initialize the
1227 * configuration data for a CPR3 regulator
1228 * @vreg: Pointer to the CPR3 regulator
1229 *
1230 * Return: 0 on success, errno on failure
1231 */
1232static int cpr4_apss_init_regulator(struct cpr3_regulator *vreg)
1233{
1234 struct cpr4_msm8953_apss_fuses *fuse;
1235 int rc;
1236
1237 rc = cpr4_msm8953_apss_read_fuse_data(vreg);
1238 if (rc) {
1239 cpr3_err(vreg, "unable to read CPR fuse data, rc=%d\n", rc);
1240 return rc;
1241 }
1242
1243 fuse = vreg->platform_fuses;
1244
Tirupathi Reddy53d99a02016-08-08 17:04:23 +05301245 rc = cpr4_parse_fuse_combo_map(vreg);
1246 if (rc) {
1247 cpr3_err(vreg, "error while parsing fuse combo map, rc=%d\n",
1248 rc);
1249 return rc;
1250 }
1251
David Collins7370f1a2017-01-18 16:21:53 -08001252 rc = cpr4_apss_parse_corner_data(vreg);
1253 if (rc) {
1254 cpr3_err(vreg, "unable to read CPR corner data from device tree, rc=%d\n",
1255 rc);
1256 return rc;
1257 }
1258
1259 rc = cpr3_mem_acc_init(vreg);
1260 if (rc) {
1261 if (rc != -EPROBE_DEFER)
1262 cpr3_err(vreg, "unable to initialize mem-acc regulator settings, rc=%d\n",
1263 rc);
1264 return rc;
1265 }
1266
1267 rc = cpr4_msm8953_apss_calculate_open_loop_voltages(vreg);
1268 if (rc) {
1269 cpr3_err(vreg, "unable to calculate open-loop voltages, rc=%d\n",
1270 rc);
1271 return rc;
1272 }
1273
1274 rc = cpr3_limit_open_loop_voltages(vreg);
1275 if (rc) {
1276 cpr3_err(vreg, "unable to limit open-loop voltages, rc=%d\n",
1277 rc);
1278 return rc;
1279 }
1280
1281 cpr3_open_loop_voltage_as_ceiling(vreg);
1282
1283 rc = cpr3_limit_floor_voltages(vreg);
1284 if (rc) {
1285 cpr3_err(vreg, "unable to limit floor voltages, rc=%d\n", rc);
1286 return rc;
1287 }
1288
1289 rc = cpr4_msm8953_apss_calculate_target_quotients(vreg);
1290 if (rc) {
1291 cpr3_err(vreg, "unable to calculate target quotients, rc=%d\n",
1292 rc);
1293 return rc;
1294 }
1295
1296 rc = cpr4_parse_core_count_temp_voltage_adj(vreg, false);
1297 if (rc) {
1298 cpr3_err(vreg, "unable to parse temperature and core count voltage adjustments, rc=%d\n",
1299 rc);
1300 return rc;
1301 }
1302
1303 if (vreg->allow_core_count_adj && (vreg->max_core_count <= 0
1304 || vreg->max_core_count >
1305 MSM8953_APSS_CPR_SDELTA_CORE_COUNT)) {
1306 cpr3_err(vreg, "qcom,max-core-count has invalid value = %d\n",
1307 vreg->max_core_count);
1308 return -EINVAL;
1309 }
1310
1311 rc = cpr4_apss_parse_boost_properties(vreg);
1312 if (rc) {
1313 cpr3_err(vreg, "unable to parse boost adjustments, rc=%d\n",
1314 rc);
1315 return rc;
1316 }
1317
1318 cpr4_apss_print_settings(vreg);
1319
1320 return rc;
1321}
1322
1323/**
Tirupathi Reddy1bcb64f2016-03-01 16:54:40 +05301324 * cpr4_apss_init_aging() - perform APSS CPR4 controller specific
1325 * aging initializations
1326 * @ctrl: Pointer to the CPR3 controller
1327 *
1328 * Return: 0 on success, errno on failure
1329 */
1330static int cpr4_apss_init_aging(struct cpr3_controller *ctrl)
1331{
1332 struct cpr4_msm8953_apss_fuses *fuse = NULL;
Tirupathi Reddy53d99a02016-08-08 17:04:23 +05301333 struct cpr3_regulator *vreg = NULL;
Tirupathi Reddy1bcb64f2016-03-01 16:54:40 +05301334 u32 aging_ro_scale;
1335 int i, j, rc;
1336
1337 for (i = 0; i < ctrl->thread_count; i++) {
1338 for (j = 0; j < ctrl->thread[i].vreg_count; j++) {
1339 if (ctrl->thread[i].vreg[j].aging_allowed) {
1340 ctrl->aging_required = true;
1341 vreg = &ctrl->thread[i].vreg[j];
1342 fuse = vreg->platform_fuses;
1343 break;
1344 }
1345 }
1346 }
1347
1348 if (!ctrl->aging_required || !fuse)
1349 return 0;
1350
1351 rc = cpr3_parse_array_property(vreg, "qcom,cpr-aging-ro-scaling-factor",
1352 1, &aging_ro_scale);
1353 if (rc)
1354 return rc;
1355
1356 if (aging_ro_scale == 0) {
1357 cpr3_err(ctrl, "aging RO scaling factor is invalid: %u\n",
1358 aging_ro_scale);
1359 return -EINVAL;
1360 }
1361
1362 ctrl->aging_vdd_mode = REGULATOR_MODE_NORMAL;
1363 ctrl->aging_complete_vdd_mode = REGULATOR_MODE_IDLE;
1364
1365 ctrl->aging_sensor_count = 1;
1366 ctrl->aging_sensor = kzalloc(sizeof(*ctrl->aging_sensor), GFP_KERNEL);
1367 if (!ctrl->aging_sensor)
1368 return -ENOMEM;
1369
1370 ctrl->aging_sensor->sensor_id = MSM8953_APSS_AGING_SENSOR_ID;
1371 ctrl->aging_sensor->ro_scale = aging_ro_scale;
1372
1373 ctrl->aging_sensor->init_quot_diff
1374 = cpr3_convert_open_loop_voltage_fuse(0,
1375 MSM8953_APSS_AGING_INIT_QUOT_DIFF_SCALE,
1376 fuse->aging_init_quot_diff,
1377 MSM8953_APSS_AGING_INIT_QUOT_DIFF_SIZE);
1378
1379 if (ctrl->aging_sensor->init_quot_diff == 0) {
1380 /*
1381 * Initial quotient difference value '0' has a special meaning
1382 * in MSM8953 fusing scheme. Use max age margin quotient
1383 * difference to consider full aging margin of 15 mV.
1384 */
1385 ctrl->aging_sensor->init_quot_diff
1386 = MSM8953_APSS_AGING_MAX_AGE_MARGIN_QUOT;
1387 cpr3_debug(ctrl, "Init quotient diff = 0, use max age margin quotient\n");
1388 }
1389
1390 cpr3_info(ctrl, "sensor %u aging init quotient diff = %d, aging RO scale = %u QUOT/V\n",
1391 ctrl->aging_sensor->sensor_id,
1392 ctrl->aging_sensor->init_quot_diff,
1393 ctrl->aging_sensor->ro_scale);
1394
1395 return 0;
1396}
1397
1398/**
David Collins7370f1a2017-01-18 16:21:53 -08001399 * cpr4_apss_init_controller() - perform APSS CPR4 controller specific
1400 * initializations
1401 * @ctrl: Pointer to the CPR3 controller
1402 *
1403 * Return: 0 on success, errno on failure
1404 */
1405static int cpr4_apss_init_controller(struct cpr3_controller *ctrl)
1406{
1407 int rc;
1408
1409 rc = cpr3_parse_common_ctrl_data(ctrl);
1410 if (rc) {
1411 if (rc != -EPROBE_DEFER)
1412 cpr3_err(ctrl, "unable to parse common controller data, rc=%d\n",
1413 rc);
1414 return rc;
1415 }
1416
1417 rc = of_property_read_u32(ctrl->dev->of_node,
1418 "qcom,cpr-down-error-step-limit",
1419 &ctrl->down_error_step_limit);
1420 if (rc) {
1421 cpr3_err(ctrl, "error reading qcom,cpr-down-error-step-limit, rc=%d\n",
1422 rc);
1423 return rc;
1424 }
1425
1426 rc = of_property_read_u32(ctrl->dev->of_node,
1427 "qcom,cpr-up-error-step-limit",
1428 &ctrl->up_error_step_limit);
1429 if (rc) {
1430 cpr3_err(ctrl, "error reading qcom,cpr-up-error-step-limit, rc=%d\n",
1431 rc);
1432 return rc;
1433 }
1434
1435 /*
1436 * Use fixed step quotient if specified otherwise use dynamic
1437 * calculated per RO step quotient
1438 */
1439 of_property_read_u32(ctrl->dev->of_node, "qcom,cpr-step-quot-fixed",
1440 &ctrl->step_quot_fixed);
1441 ctrl->use_dynamic_step_quot = ctrl->step_quot_fixed ? false : true;
1442
1443 ctrl->saw_use_unit_mV = of_property_read_bool(ctrl->dev->of_node,
1444 "qcom,cpr-saw-use-unit-mV");
1445
1446 of_property_read_u32(ctrl->dev->of_node,
1447 "qcom,cpr-voltage-settling-time",
1448 &ctrl->voltage_settling_time);
1449
1450 ctrl->vdd_limit_regulator = devm_regulator_get(ctrl->dev, "vdd-limit");
1451 if (IS_ERR(ctrl->vdd_limit_regulator)) {
1452 rc = PTR_ERR(ctrl->vdd_limit_regulator);
1453 if (rc != -EPROBE_DEFER)
1454 cpr3_err(ctrl, "unable to request vdd-limit regulator, rc=%d\n",
1455 rc);
1456 return rc;
1457 }
1458
1459 rc = cpr3_apm_init(ctrl);
1460 if (rc) {
1461 if (rc != -EPROBE_DEFER)
1462 cpr3_err(ctrl, "unable to initialize APM settings, rc=%d\n",
1463 rc);
1464 return rc;
1465 }
1466
1467 rc = cpr4_apss_parse_temp_adj_properties(ctrl);
1468 if (rc) {
1469 cpr3_err(ctrl, "unable to parse temperature adjustment properties, rc=%d\n",
1470 rc);
1471 return rc;
1472 }
1473
1474 ctrl->sensor_count = MSM8953_APSS_CPR_SENSOR_COUNT;
1475
1476 /*
1477 * APSS only has one thread (0) per controller so the zeroed
1478 * array does not need further modification.
1479 */
1480 ctrl->sensor_owner = devm_kcalloc(ctrl->dev, ctrl->sensor_count,
1481 sizeof(*ctrl->sensor_owner), GFP_KERNEL);
1482 if (!ctrl->sensor_owner)
1483 return -ENOMEM;
1484
1485 ctrl->cpr_clock_rate = MSM8953_APSS_CPR_CLOCK_RATE;
1486 ctrl->ctrl_type = CPR_CTRL_TYPE_CPR4;
1487 ctrl->supports_hw_closed_loop = true;
1488 ctrl->use_hw_closed_loop = of_property_read_bool(ctrl->dev->of_node,
1489 "qcom,cpr-hw-closed-loop");
1490 return 0;
1491}
1492
1493static int cpr4_apss_regulator_suspend(struct platform_device *pdev,
1494 pm_message_t state)
1495{
1496 struct cpr3_controller *ctrl = platform_get_drvdata(pdev);
1497
1498 return cpr3_regulator_suspend(ctrl);
1499}
1500
1501static int cpr4_apss_regulator_resume(struct platform_device *pdev)
1502{
1503 struct cpr3_controller *ctrl = platform_get_drvdata(pdev);
1504
1505 return cpr3_regulator_resume(ctrl);
1506}
1507
1508static int cpr4_apss_regulator_probe(struct platform_device *pdev)
1509{
1510 struct device *dev = &pdev->dev;
1511 struct cpr3_controller *ctrl;
1512 int i, rc;
1513
1514 if (!dev->of_node) {
1515 dev_err(dev, "Device tree node is missing\n");
1516 return -EINVAL;
1517 }
1518
1519 ctrl = devm_kzalloc(dev, sizeof(*ctrl), GFP_KERNEL);
1520 if (!ctrl)
1521 return -ENOMEM;
1522
1523 ctrl->dev = dev;
1524 /* Set to false later if anything precludes CPR operation. */
1525 ctrl->cpr_allowed_hw = true;
1526
1527 rc = of_property_read_string(dev->of_node, "qcom,cpr-ctrl-name",
1528 &ctrl->name);
1529 if (rc) {
1530 cpr3_err(ctrl, "unable to read qcom,cpr-ctrl-name, rc=%d\n",
1531 rc);
1532 return rc;
1533 }
1534
1535 rc = cpr3_map_fuse_base(ctrl, pdev);
1536 if (rc) {
1537 cpr3_err(ctrl, "could not map fuse base address\n");
1538 return rc;
1539 }
1540
1541 rc = cpr3_allocate_threads(ctrl, 0, 0);
1542 if (rc) {
1543 cpr3_err(ctrl, "failed to allocate CPR thread array, rc=%d\n",
1544 rc);
1545 return rc;
1546 }
1547
1548 if (ctrl->thread_count != 1) {
1549 cpr3_err(ctrl, "expected 1 thread but found %d\n",
1550 ctrl->thread_count);
1551 return -EINVAL;
1552 }
1553
1554 rc = cpr4_apss_init_controller(ctrl);
1555 if (rc) {
1556 if (rc != -EPROBE_DEFER)
1557 cpr3_err(ctrl, "failed to initialize CPR controller parameters, rc=%d\n",
1558 rc);
1559 return rc;
1560 }
1561
1562 rc = cpr4_apss_init_thread(&ctrl->thread[0]);
1563 if (rc) {
1564 cpr3_err(ctrl, "thread initialization failed, rc=%d\n", rc);
1565 return rc;
1566 }
1567
1568 for (i = 0; i < ctrl->thread[0].vreg_count; i++) {
1569 rc = cpr4_apss_init_regulator(&ctrl->thread[0].vreg[i]);
1570 if (rc) {
1571 cpr3_err(&ctrl->thread[0].vreg[i], "regulator initialization failed, rc=%d\n",
1572 rc);
1573 return rc;
1574 }
1575 }
1576
Tirupathi Reddy1bcb64f2016-03-01 16:54:40 +05301577 rc = cpr4_apss_init_aging(ctrl);
1578 if (rc) {
1579 cpr3_err(ctrl, "failed to initialize aging configurations, rc=%d\n",
1580 rc);
1581 return rc;
1582 }
1583
David Collins7370f1a2017-01-18 16:21:53 -08001584 platform_set_drvdata(pdev, ctrl);
1585
1586 return cpr3_regulator_register(pdev, ctrl);
1587}
1588
1589static int cpr4_apss_regulator_remove(struct platform_device *pdev)
1590{
1591 struct cpr3_controller *ctrl = platform_get_drvdata(pdev);
1592
1593 return cpr3_regulator_unregister(ctrl);
1594}
1595
1596static const struct of_device_id cpr4_regulator_match_table[] = {
1597 { .compatible = "qcom,cpr4-msm8953-apss-regulator", },
1598 {}
1599};
1600
1601static struct platform_driver cpr4_apss_regulator_driver = {
1602 .driver = {
1603 .name = "qcom,cpr4-apss-regulator",
1604 .of_match_table = cpr4_regulator_match_table,
1605 .owner = THIS_MODULE,
1606 },
1607 .probe = cpr4_apss_regulator_probe,
1608 .remove = cpr4_apss_regulator_remove,
1609 .suspend = cpr4_apss_regulator_suspend,
1610 .resume = cpr4_apss_regulator_resume,
1611};
1612
1613static int cpr4_regulator_init(void)
1614{
1615 return platform_driver_register(&cpr4_apss_regulator_driver);
1616}
1617
1618static void cpr4_regulator_exit(void)
1619{
1620 platform_driver_unregister(&cpr4_apss_regulator_driver);
1621}
1622
1623MODULE_DESCRIPTION("CPR4 APSS regulator driver");
1624MODULE_LICENSE("GPL v2");
1625
1626arch_initcall(cpr4_regulator_init);
1627module_exit(cpr4_regulator_exit);