blob: 39ee3c551e025639385bd5eec467cefff43dd831 [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/*
15 * This file contains utility functions to be used by platform specific CPR3
16 * regulator drivers.
17 */
18
19#define pr_fmt(fmt) "%s: " fmt, __func__
20
21#include <linux/cpumask.h>
22#include <linux/device.h>
23#include <linux/io.h>
24#include <linux/kernel.h>
25#include <linux/of.h>
26#include <linux/platform_device.h>
27#include <linux/slab.h>
28#include <linux/types.h>
29
30#include "cpr3-regulator.h"
31
32#define BYTES_PER_FUSE_ROW 8
33#define MAX_FUSE_ROW_BIT 63
34
35#define CPR3_CONSECUTIVE_UP_DOWN_MIN 0
36#define CPR3_CONSECUTIVE_UP_DOWN_MAX 15
37#define CPR3_UP_DOWN_THRESHOLD_MIN 0
38#define CPR3_UP_DOWN_THRESHOLD_MAX 31
39#define CPR3_STEP_QUOT_MIN 0
40#define CPR3_STEP_QUOT_MAX 63
41#define CPR3_IDLE_CLOCKS_MIN 0
42#define CPR3_IDLE_CLOCKS_MAX 31
43
44/* This constant has units of uV/mV so 1000 corresponds to 100%. */
45#define CPR3_AGING_DERATE_UNITY 1000
46
47/**
48 * cpr3_allocate_regulators() - allocate and initialize CPR3 regulators for a
49 * given thread based upon device tree data
50 * @thread: Pointer to the CPR3 thread
51 *
52 * This function allocates the thread->vreg array based upon the number of
53 * device tree regulator subnodes. It also initializes generic elements of each
54 * regulator struct such as name, of_node, and thread.
55 *
56 * Return: 0 on success, errno on failure
57 */
58static int cpr3_allocate_regulators(struct cpr3_thread *thread)
59{
60 struct device_node *node;
61 int i, rc;
62
63 thread->vreg_count = 0;
64
65 for_each_available_child_of_node(thread->of_node, node) {
66 thread->vreg_count++;
67 }
68
69 thread->vreg = devm_kcalloc(thread->ctrl->dev, thread->vreg_count,
70 sizeof(*thread->vreg), GFP_KERNEL);
71 if (!thread->vreg)
72 return -ENOMEM;
73
74 i = 0;
75 for_each_available_child_of_node(thread->of_node, node) {
76 thread->vreg[i].of_node = node;
77 thread->vreg[i].thread = thread;
78
79 rc = of_property_read_string(node, "regulator-name",
80 &thread->vreg[i].name);
81 if (rc) {
82 dev_err(thread->ctrl->dev, "could not find regulator name, rc=%d\n",
83 rc);
84 return rc;
85 }
86
87 i++;
88 }
89
90 return 0;
91}
92
93/**
94 * cpr3_allocate_threads() - allocate and initialize CPR3 threads for a given
95 * controller based upon device tree data
96 * @ctrl: Pointer to the CPR3 controller
97 * @min_thread_id: Minimum allowed hardware thread ID for this controller
98 * @max_thread_id: Maximum allowed hardware thread ID for this controller
99 *
100 * This function allocates the ctrl->thread array based upon the number of
101 * device tree thread subnodes. It also initializes generic elements of each
102 * thread struct such as thread_id, of_node, ctrl, and vreg array.
103 *
104 * Return: 0 on success, errno on failure
105 */
106int cpr3_allocate_threads(struct cpr3_controller *ctrl, u32 min_thread_id,
107 u32 max_thread_id)
108{
109 struct device *dev = ctrl->dev;
110 struct device_node *thread_node;
111 int i, j, rc;
112
113 ctrl->thread_count = 0;
114
115 for_each_available_child_of_node(dev->of_node, thread_node) {
116 ctrl->thread_count++;
117 }
118
119 ctrl->thread = devm_kcalloc(dev, ctrl->thread_count,
120 sizeof(*ctrl->thread), GFP_KERNEL);
121 if (!ctrl->thread)
122 return -ENOMEM;
123
124 i = 0;
125 for_each_available_child_of_node(dev->of_node, thread_node) {
126 ctrl->thread[i].of_node = thread_node;
127 ctrl->thread[i].ctrl = ctrl;
128
129 rc = of_property_read_u32(thread_node, "qcom,cpr-thread-id",
130 &ctrl->thread[i].thread_id);
131 if (rc) {
132 dev_err(dev, "could not read DT property qcom,cpr-thread-id, rc=%d\n",
133 rc);
134 return rc;
135 }
136
137 if (ctrl->thread[i].thread_id < min_thread_id ||
138 ctrl->thread[i].thread_id > max_thread_id) {
139 dev_err(dev, "invalid thread id = %u; not within [%u, %u]\n",
140 ctrl->thread[i].thread_id, min_thread_id,
141 max_thread_id);
142 return -EINVAL;
143 }
144
145 /* Verify that the thread ID is unique for all child nodes. */
146 for (j = 0; j < i; j++) {
147 if (ctrl->thread[j].thread_id
148 == ctrl->thread[i].thread_id) {
149 dev_err(dev, "duplicate thread id = %u found\n",
150 ctrl->thread[i].thread_id);
151 return -EINVAL;
152 }
153 }
154
155 rc = cpr3_allocate_regulators(&ctrl->thread[i]);
156 if (rc)
157 return rc;
158
159 i++;
160 }
161
162 return 0;
163}
164
165/**
166 * cpr3_map_fuse_base() - ioremap the base address of the fuse region
167 * @ctrl: Pointer to the CPR3 controller
168 * @pdev: Platform device pointer for the CPR3 controller
169 *
170 * Return: 0 on success, errno on failure
171 */
172int cpr3_map_fuse_base(struct cpr3_controller *ctrl,
173 struct platform_device *pdev)
174{
175 struct resource *res;
176
177 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fuse_base");
178 if (!res || !res->start) {
179 dev_err(&pdev->dev, "fuse base address is missing\n");
180 return -ENXIO;
181 }
182
183 ctrl->fuse_base = devm_ioremap(&pdev->dev, res->start,
184 resource_size(res));
185
186 return 0;
187}
188
189/**
190 * cpr3_read_fuse_param() - reads a CPR3 fuse parameter out of eFuses
191 * @fuse_base_addr: Virtual memory address of the eFuse base address
192 * @param: Null terminated array of fuse param segments to read
193 * from
194 * @param_value: Output with value read from the eFuses
195 *
196 * This function reads from each of the parameter segments listed in the param
197 * array and concatenates their values together. Reading stops when an element
198 * is reached which has all 0 struct values. The total number of bits specified
199 * for the fuse parameter across all segments must be less than or equal to 64.
200 *
201 * Return: 0 on success, errno on failure
202 */
203int cpr3_read_fuse_param(void __iomem *fuse_base_addr,
204 const struct cpr3_fuse_param *param, u64 *param_value)
205{
206 u64 fuse_val, val;
207 int bits;
208 int bits_total = 0;
209
210 *param_value = 0;
211
212 while (param->row || param->bit_start || param->bit_end) {
213 if (param->bit_start > param->bit_end
214 || param->bit_end > MAX_FUSE_ROW_BIT) {
215 pr_err("Invalid fuse parameter segment: row=%u, start=%u, end=%u\n",
216 param->row, param->bit_start, param->bit_end);
217 return -EINVAL;
218 }
219
220 bits = param->bit_end - param->bit_start + 1;
221 if (bits_total + bits > 64) {
222 pr_err("Invalid fuse parameter segments; total bits = %d\n",
223 bits_total + bits);
224 return -EINVAL;
225 }
226
227 fuse_val = readq_relaxed(fuse_base_addr
228 + param->row * BYTES_PER_FUSE_ROW);
229 val = (fuse_val >> param->bit_start) & ((1ULL << bits) - 1);
230 *param_value |= val << bits_total;
231 bits_total += bits;
232
233 param++;
234 }
235
236 return 0;
237}
238
239/**
240 * cpr3_convert_open_loop_voltage_fuse() - converts an open loop voltage fuse
241 * value into an absolute voltage with units of microvolts
242 * @ref_volt: Reference voltage in microvolts
243 * @step_volt: The step size in microvolts of the fuse LSB
244 * @fuse: Open loop voltage fuse value
245 * @fuse_len: The bit length of the fuse value
246 *
247 * The MSB of the fuse parameter corresponds to a sign bit. If it is set, then
248 * the lower bits correspond to the number of steps to go down from the
249 * reference voltage. If it is not set, then the lower bits correspond to the
250 * number of steps to go up from the reference voltage.
251 */
252int cpr3_convert_open_loop_voltage_fuse(int ref_volt, int step_volt, u32 fuse,
253 int fuse_len)
254{
255 int sign, steps;
256
257 sign = (fuse & (1 << (fuse_len - 1))) ? -1 : 1;
258 steps = fuse & ((1 << (fuse_len - 1)) - 1);
259
260 return ref_volt + sign * steps * step_volt;
261}
262
263/**
264 * cpr3_interpolate() - performs linear interpolation
265 * @x1 Lower known x value
266 * @y1 Lower known y value
267 * @x2 Upper known x value
268 * @y2 Upper known y value
269 * @x Intermediate x value
270 *
271 * Returns y where (x, y) falls on the line between (x1, y1) and (x2, y2).
272 * It is required that x1 < x2, y1 <= y2, and x1 <= x <= x2. If these
273 * conditions are not met, then y2 will be returned.
274 */
275u64 cpr3_interpolate(u64 x1, u64 y1, u64 x2, u64 y2, u64 x)
276{
277 u64 temp;
278
279 if (x1 >= x2 || y1 > y2 || x1 > x || x > x2)
280 return y2;
281
282 temp = (x2 - x) * (y2 - y1);
283 do_div(temp, (u32)(x2 - x1));
284
285 return y2 - temp;
286}
287
288/**
289 * cpr3_parse_array_property() - fill an array from a portion of the values
290 * specified for a device tree property
291 * @vreg: Pointer to the CPR3 regulator
292 * @prop_name: The name of the device tree property to read from
293 * @tuple_size: The number of elements in each tuple
294 * @out: Output data array which must be of size tuple_size
295 *
296 * cpr3_parse_common_corner_data() must be called for vreg before this function
297 * is called so that fuse combo and speed bin size elements are initialized.
298 *
299 * Three formats are supported for the device tree property:
300 * 1. Length == tuple_size
301 * (reading begins at index 0)
302 * 2. Length == tuple_size * vreg->fuse_combos_supported
303 * (reading begins at index tuple_size * vreg->fuse_combo)
304 * 3. Length == tuple_size * vreg->speed_bins_supported
305 * (reading begins at index tuple_size * vreg->speed_bin_fuse)
306 *
307 * All other property lengths are treated as errors.
308 *
309 * Return: 0 on success, errno on failure
310 */
311int cpr3_parse_array_property(struct cpr3_regulator *vreg,
312 const char *prop_name, int tuple_size, u32 *out)
313{
314 struct device_node *node = vreg->of_node;
315 int len = 0;
316 int i, offset, rc;
317
318 if (!of_find_property(node, prop_name, &len)) {
319 cpr3_err(vreg, "property %s is missing\n", prop_name);
320 return -EINVAL;
321 }
322
323 if (len == tuple_size * sizeof(u32)) {
324 offset = 0;
325 } else if (len == tuple_size * vreg->fuse_combos_supported
326 * sizeof(u32)) {
327 offset = tuple_size * vreg->fuse_combo;
328 } else if (vreg->speed_bins_supported > 0 &&
329 len == tuple_size * vreg->speed_bins_supported * sizeof(u32)) {
330 offset = tuple_size * vreg->speed_bin_fuse;
331 } else {
332 if (vreg->speed_bins_supported > 0)
333 cpr3_err(vreg, "property %s has invalid length=%d, should be %zu, %zu, or %zu\n",
334 prop_name, len,
335 tuple_size * sizeof(u32),
336 tuple_size * vreg->speed_bins_supported
337 * sizeof(u32),
338 tuple_size * vreg->fuse_combos_supported
339 * sizeof(u32));
340 else
341 cpr3_err(vreg, "property %s has invalid length=%d, should be %zu or %zu\n",
342 prop_name, len,
343 tuple_size * sizeof(u32),
344 tuple_size * vreg->fuse_combos_supported
345 * sizeof(u32));
346 return -EINVAL;
347 }
348
349 for (i = 0; i < tuple_size; i++) {
350 rc = of_property_read_u32_index(node, prop_name, offset + i,
351 &out[i]);
352 if (rc) {
353 cpr3_err(vreg, "error reading property %s, rc=%d\n",
354 prop_name, rc);
355 return rc;
356 }
357 }
358
359 return 0;
360}
361
362/**
363 * cpr3_parse_corner_array_property() - fill a per-corner array from a portion
364 * of the values specified for a device tree property
365 * @vreg: Pointer to the CPR3 regulator
366 * @prop_name: The name of the device tree property to read from
367 * @tuple_size: The number of elements in each per-corner tuple
368 * @out: Output data array which must be of size:
369 * tuple_size * vreg->corner_count
370 *
371 * cpr3_parse_common_corner_data() must be called for vreg before this function
372 * is called so that fuse combo and speed bin size elements are initialized.
373 *
374 * Three formats are supported for the device tree property:
375 * 1. Length == tuple_size * vreg->corner_count
376 * (reading begins at index 0)
377 * 2. Length == tuple_size * vreg->fuse_combo_corner_sum
378 * (reading begins at index tuple_size * vreg->fuse_combo_offset)
379 * 3. Length == tuple_size * vreg->speed_bin_corner_sum
380 * (reading begins at index tuple_size * vreg->speed_bin_offset)
381 *
382 * All other property lengths are treated as errors.
383 *
384 * Return: 0 on success, errno on failure
385 */
386int cpr3_parse_corner_array_property(struct cpr3_regulator *vreg,
387 const char *prop_name, int tuple_size, u32 *out)
388{
389 struct device_node *node = vreg->of_node;
390 int len = 0;
391 int i, offset, rc;
392
393 if (!of_find_property(node, prop_name, &len)) {
394 cpr3_err(vreg, "property %s is missing\n", prop_name);
395 return -EINVAL;
396 }
397
398 if (len == tuple_size * vreg->corner_count * sizeof(u32)) {
399 offset = 0;
400 } else if (len == tuple_size * vreg->fuse_combo_corner_sum
401 * sizeof(u32)) {
402 offset = tuple_size * vreg->fuse_combo_offset;
403 } else if (vreg->speed_bin_corner_sum > 0 &&
404 len == tuple_size * vreg->speed_bin_corner_sum * sizeof(u32)) {
405 offset = tuple_size * vreg->speed_bin_offset;
406 } else {
407 if (vreg->speed_bin_corner_sum > 0)
408 cpr3_err(vreg, "property %s has invalid length=%d, should be %zu, %zu, or %zu\n",
409 prop_name, len,
410 tuple_size * vreg->corner_count * sizeof(u32),
411 tuple_size * vreg->speed_bin_corner_sum
412 * sizeof(u32),
413 tuple_size * vreg->fuse_combo_corner_sum
414 * sizeof(u32));
415 else
416 cpr3_err(vreg, "property %s has invalid length=%d, should be %zu or %zu\n",
417 prop_name, len,
418 tuple_size * vreg->corner_count * sizeof(u32),
419 tuple_size * vreg->fuse_combo_corner_sum
420 * sizeof(u32));
421 return -EINVAL;
422 }
423
424 for (i = 0; i < tuple_size * vreg->corner_count; i++) {
425 rc = of_property_read_u32_index(node, prop_name, offset + i,
426 &out[i]);
427 if (rc) {
428 cpr3_err(vreg, "error reading property %s, rc=%d\n",
429 prop_name, rc);
430 return rc;
431 }
432 }
433
434 return 0;
435}
436
437/**
438 * cpr3_parse_corner_band_array_property() - fill a per-corner band array
439 * from a portion of the values specified for a device tree
440 * property
441 * @vreg: Pointer to the CPR3 regulator
442 * @prop_name: The name of the device tree property to read from
443 * @tuple_size: The number of elements in each per-corner band tuple
444 * @out: Output data array which must be of size:
445 * tuple_size * vreg->corner_band_count
446 *
447 * cpr3_parse_common_corner_data() must be called for vreg before this function
448 * is called so that fuse combo and speed bin size elements are initialized.
449 * In addition, corner band fuse combo and speed bin sum and offset elements
450 * must be initialized prior to executing this function.
451 *
452 * Three formats are supported for the device tree property:
453 * 1. Length == tuple_size * vreg->corner_band_count
454 * (reading begins at index 0)
455 * 2. Length == tuple_size * vreg->fuse_combo_corner_band_sum
456 * (reading begins at index tuple_size *
457 * vreg->fuse_combo_corner_band_offset)
458 * 3. Length == tuple_size * vreg->speed_bin_corner_band_sum
459 * (reading begins at index tuple_size *
460 * vreg->speed_bin_corner_band_offset)
461 *
462 * All other property lengths are treated as errors.
463 *
464 * Return: 0 on success, errno on failure
465 */
466int cpr3_parse_corner_band_array_property(struct cpr3_regulator *vreg,
467 const char *prop_name, int tuple_size, u32 *out)
468{
469 struct device_node *node = vreg->of_node;
470 int len = 0;
471 int i, offset, rc;
472
473 if (!of_find_property(node, prop_name, &len)) {
474 cpr3_err(vreg, "property %s is missing\n", prop_name);
475 return -EINVAL;
476 }
477
478 if (len == tuple_size * vreg->corner_band_count * sizeof(u32)) {
479 offset = 0;
480 } else if (len == tuple_size * vreg->fuse_combo_corner_band_sum
481 * sizeof(u32)) {
482 offset = tuple_size * vreg->fuse_combo_corner_band_offset;
483 } else if (vreg->speed_bin_corner_band_sum > 0 &&
484 len == tuple_size * vreg->speed_bin_corner_band_sum *
485 sizeof(u32)) {
486 offset = tuple_size * vreg->speed_bin_corner_band_offset;
487 } else {
488 if (vreg->speed_bin_corner_band_sum > 0)
489 cpr3_err(vreg, "property %s has invalid length=%d, should be %zu, %zu, or %zu\n",
490 prop_name, len,
491 tuple_size * vreg->corner_band_count *
492 sizeof(u32),
493 tuple_size * vreg->speed_bin_corner_band_sum
494 * sizeof(u32),
495 tuple_size * vreg->fuse_combo_corner_band_sum
496 * sizeof(u32));
497 else
498 cpr3_err(vreg, "property %s has invalid length=%d, should be %zu or %zu\n",
499 prop_name, len,
500 tuple_size * vreg->corner_band_count *
501 sizeof(u32),
502 tuple_size * vreg->fuse_combo_corner_band_sum
503 * sizeof(u32));
504 return -EINVAL;
505 }
506
507 for (i = 0; i < tuple_size * vreg->corner_band_count; i++) {
508 rc = of_property_read_u32_index(node, prop_name, offset + i,
509 &out[i]);
510 if (rc) {
511 cpr3_err(vreg, "error reading property %s, rc=%d\n",
512 prop_name, rc);
513 return rc;
514 }
515 }
516
517 return 0;
518}
519
520/**
521 * cpr3_parse_common_corner_data() - parse common CPR3 properties relating to
522 * the corners supported by a CPR3 regulator from device tree
523 * @vreg: Pointer to the CPR3 regulator
524 *
525 * This function reads, validates, and utilizes the following device tree
526 * properties: qcom,cpr-fuse-corners, qcom,cpr-fuse-combos, qcom,cpr-speed-bins,
527 * qcom,cpr-speed-bin-corners, qcom,cpr-corners, qcom,cpr-voltage-ceiling,
528 * qcom,cpr-voltage-floor, qcom,corner-frequencies,
529 * and qcom,cpr-corner-fmax-map.
530 *
531 * It initializes these CPR3 regulator elements: corner, corner_count,
532 * fuse_combos_supported, fuse_corner_map, and speed_bins_supported. It
533 * initializes these elements for each corner: ceiling_volt, floor_volt,
534 * proc_freq, and cpr_fuse_corner.
535 *
536 * It requires that the following CPR3 regulator elements be initialized before
537 * being called: fuse_corner_count, fuse_combo, and speed_bin_fuse.
538 *
539 * Return: 0 on success, errno on failure
540 */
541int cpr3_parse_common_corner_data(struct cpr3_regulator *vreg)
542{
543 struct device_node *node = vreg->of_node;
544 struct cpr3_controller *ctrl = vreg->thread->ctrl;
545 u32 max_fuse_combos, fuse_corners, aging_allowed = 0;
546 u32 max_speed_bins = 0;
547 u32 *combo_corners;
548 u32 *speed_bin_corners;
549 u32 *temp;
550 int i, j, rc;
551
552 rc = of_property_read_u32(node, "qcom,cpr-fuse-corners", &fuse_corners);
553 if (rc) {
554 cpr3_err(vreg, "error reading property qcom,cpr-fuse-corners, rc=%d\n",
555 rc);
556 return rc;
557 }
558
559 if (vreg->fuse_corner_count != fuse_corners) {
560 cpr3_err(vreg, "device tree config supports %d fuse corners but the hardware has %d fuse corners\n",
561 fuse_corners, vreg->fuse_corner_count);
562 return -EINVAL;
563 }
564
David Collins7370f1a2017-01-18 16:21:53 -0800565 /*
Tirupathi Reddy53d99a02016-08-08 17:04:23 +0530566 * Check if CPR3 regulator's fuse_combos_supported element is already
567 * populated by fuse-combo-map logic. If not populated, then parse the
568 * qcom,cpr-fuse-combos property.
David Collins7370f1a2017-01-18 16:21:53 -0800569 */
Tirupathi Reddy53d99a02016-08-08 17:04:23 +0530570 if (vreg->fuse_combos_supported)
571 max_fuse_combos = vreg->fuse_combos_supported;
572 else {
573 rc = of_property_read_u32(node, "qcom,cpr-fuse-combos",
574 &max_fuse_combos);
575 if (rc) {
576 cpr3_err(vreg, "error reading property qcom,cpr-fuse-combos, rc=%d\n",
577 rc);
578 return rc;
579 }
David Collins7370f1a2017-01-18 16:21:53 -0800580
Tirupathi Reddy53d99a02016-08-08 17:04:23 +0530581 /*
582 * Sanity check against arbitrarily large value to avoid
583 * excessive memory allocation.
584 */
585 if (max_fuse_combos > 100 || max_fuse_combos == 0) {
586 cpr3_err(vreg, "qcom,cpr-fuse-combos is invalid: %u\n",
587 max_fuse_combos);
588 return -EINVAL;
589 }
David Collins7370f1a2017-01-18 16:21:53 -0800590
Tirupathi Reddy53d99a02016-08-08 17:04:23 +0530591 if (vreg->fuse_combo >= max_fuse_combos) {
592 cpr3_err(vreg, "device tree config supports fuse combos 0-%u but the hardware has combo %d\n",
593 max_fuse_combos - 1, vreg->fuse_combo);
594 WARN_ON(1);
595 return -EINVAL;
596 }
597
598 vreg->fuse_combos_supported = max_fuse_combos;
599 }
David Collins7370f1a2017-01-18 16:21:53 -0800600
601 of_property_read_u32(node, "qcom,cpr-speed-bins", &max_speed_bins);
602
603 /*
604 * Sanity check against arbitrarily large value to avoid excessive
605 * memory allocation.
606 */
607 if (max_speed_bins > 100) {
608 cpr3_err(vreg, "qcom,cpr-speed-bins is invalid: %u\n",
609 max_speed_bins);
610 return -EINVAL;
611 }
612
613 if (max_speed_bins && vreg->speed_bin_fuse >= max_speed_bins) {
614 cpr3_err(vreg, "device tree config supports speed bins 0-%u but the hardware has speed bin %d\n",
615 max_speed_bins - 1, vreg->speed_bin_fuse);
616 BUG();
617 return -EINVAL;
618 }
619
620 vreg->speed_bins_supported = max_speed_bins;
621
622 combo_corners = kcalloc(vreg->fuse_combos_supported,
623 sizeof(*combo_corners), GFP_KERNEL);
624 if (!combo_corners)
625 return -ENOMEM;
626
627 rc = of_property_read_u32_array(node, "qcom,cpr-corners", combo_corners,
628 vreg->fuse_combos_supported);
629 if (rc == -EOVERFLOW) {
630 /* Single value case */
631 rc = of_property_read_u32(node, "qcom,cpr-corners",
632 combo_corners);
633 for (i = 1; i < vreg->fuse_combos_supported; i++)
634 combo_corners[i] = combo_corners[0];
635 }
636 if (rc) {
637 cpr3_err(vreg, "error reading property qcom,cpr-corners, rc=%d\n",
638 rc);
639 kfree(combo_corners);
640 return rc;
641 }
642
643 vreg->fuse_combo_offset = 0;
644 vreg->fuse_combo_corner_sum = 0;
645 for (i = 0; i < vreg->fuse_combos_supported; i++) {
646 vreg->fuse_combo_corner_sum += combo_corners[i];
647 if (i < vreg->fuse_combo)
648 vreg->fuse_combo_offset += combo_corners[i];
649 }
650
651 vreg->corner_count = combo_corners[vreg->fuse_combo];
652
653 kfree(combo_corners);
654
655 vreg->speed_bin_offset = 0;
656 vreg->speed_bin_corner_sum = 0;
657 if (vreg->speed_bins_supported > 0) {
658 speed_bin_corners = kcalloc(vreg->speed_bins_supported,
659 sizeof(*speed_bin_corners), GFP_KERNEL);
660 if (!speed_bin_corners)
661 return -ENOMEM;
662
663 rc = of_property_read_u32_array(node,
664 "qcom,cpr-speed-bin-corners", speed_bin_corners,
665 vreg->speed_bins_supported);
666 if (rc) {
667 cpr3_err(vreg, "error reading property qcom,cpr-speed-bin-corners, rc=%d\n",
668 rc);
669 kfree(speed_bin_corners);
670 return rc;
671 }
672
673 for (i = 0; i < vreg->speed_bins_supported; i++) {
674 vreg->speed_bin_corner_sum += speed_bin_corners[i];
675 if (i < vreg->speed_bin_fuse)
676 vreg->speed_bin_offset += speed_bin_corners[i];
677 }
678
679 if (speed_bin_corners[vreg->speed_bin_fuse]
680 != vreg->corner_count) {
681 cpr3_err(vreg, "qcom,cpr-corners and qcom,cpr-speed-bin-corners conflict on number of corners: %d vs %u\n",
682 vreg->corner_count,
683 speed_bin_corners[vreg->speed_bin_fuse]);
684 kfree(speed_bin_corners);
685 return -EINVAL;
686 }
687
688 kfree(speed_bin_corners);
689 }
690
691 /*
692 * For CPRh compliant controllers two additional corners are
693 * allocated to correspond to the APM crossover voltage and the MEM ACC
694 * crossover voltage.
695 */
696 vreg->corner = devm_kcalloc(ctrl->dev, ctrl->ctrl_type ==
697 CPR_CTRL_TYPE_CPRH ?
698 vreg->corner_count + 2 :
699 vreg->corner_count,
700 sizeof(*vreg->corner), GFP_KERNEL);
701 temp = kcalloc(vreg->corner_count, sizeof(*temp), GFP_KERNEL);
702 if (!vreg->corner || !temp)
703 return -ENOMEM;
704
705 rc = cpr3_parse_corner_array_property(vreg, "qcom,cpr-voltage-ceiling",
706 1, temp);
707 if (rc)
708 goto free_temp;
709 for (i = 0; i < vreg->corner_count; i++) {
710 vreg->corner[i].ceiling_volt
711 = CPR3_ROUND(temp[i], ctrl->step_volt);
712 vreg->corner[i].abs_ceiling_volt = vreg->corner[i].ceiling_volt;
713 }
714
715 rc = cpr3_parse_corner_array_property(vreg, "qcom,cpr-voltage-floor",
716 1, temp);
717 if (rc)
718 goto free_temp;
719 for (i = 0; i < vreg->corner_count; i++)
720 vreg->corner[i].floor_volt
721 = CPR3_ROUND(temp[i], ctrl->step_volt);
722
723 /* Validate ceiling and floor values */
724 for (i = 0; i < vreg->corner_count; i++) {
725 if (vreg->corner[i].floor_volt
726 > vreg->corner[i].ceiling_volt) {
727 cpr3_err(vreg, "CPR floor[%d]=%d > ceiling[%d]=%d uV\n",
728 i, vreg->corner[i].floor_volt,
729 i, vreg->corner[i].ceiling_volt);
730 rc = -EINVAL;
731 goto free_temp;
732 }
733 }
734
735 /* Load optional system-supply voltages */
736 if (of_find_property(vreg->of_node, "qcom,system-voltage", NULL)) {
737 rc = cpr3_parse_corner_array_property(vreg,
738 "qcom,system-voltage", 1, temp);
739 if (rc)
740 goto free_temp;
741 for (i = 0; i < vreg->corner_count; i++)
742 vreg->corner[i].system_volt = temp[i];
743 }
744
745 rc = cpr3_parse_corner_array_property(vreg, "qcom,corner-frequencies",
746 1, temp);
747 if (rc)
748 goto free_temp;
749 for (i = 0; i < vreg->corner_count; i++)
750 vreg->corner[i].proc_freq = temp[i];
751
752 /* Validate frequencies */
753 for (i = 1; i < vreg->corner_count; i++) {
754 if (vreg->corner[i].proc_freq
755 < vreg->corner[i - 1].proc_freq) {
756 cpr3_err(vreg, "invalid frequency: freq[%d]=%u < freq[%d]=%u\n",
757 i, vreg->corner[i].proc_freq, i - 1,
758 vreg->corner[i - 1].proc_freq);
759 rc = -EINVAL;
760 goto free_temp;
761 }
762 }
763
764 vreg->fuse_corner_map = devm_kcalloc(ctrl->dev, vreg->fuse_corner_count,
765 sizeof(*vreg->fuse_corner_map), GFP_KERNEL);
766 if (!vreg->fuse_corner_map) {
767 rc = -ENOMEM;
768 goto free_temp;
769 }
770
771 rc = cpr3_parse_array_property(vreg, "qcom,cpr-corner-fmax-map",
772 vreg->fuse_corner_count, temp);
773 if (rc)
774 goto free_temp;
775 for (i = 0; i < vreg->fuse_corner_count; i++) {
776 vreg->fuse_corner_map[i] = temp[i] - CPR3_CORNER_OFFSET;
777 if (temp[i] < CPR3_CORNER_OFFSET
778 || temp[i] > vreg->corner_count + CPR3_CORNER_OFFSET) {
779 cpr3_err(vreg, "invalid corner value specified in qcom,cpr-corner-fmax-map: %u\n",
780 temp[i]);
781 rc = -EINVAL;
782 goto free_temp;
783 } else if (i > 0 && temp[i - 1] >= temp[i]) {
784 cpr3_err(vreg, "invalid corner %u less than or equal to previous corner %u\n",
785 temp[i], temp[i - 1]);
786 rc = -EINVAL;
787 goto free_temp;
788 }
789 }
790 if (temp[vreg->fuse_corner_count - 1] != vreg->corner_count)
791 cpr3_debug(vreg, "Note: highest Fmax corner %u in qcom,cpr-corner-fmax-map does not match highest supported corner %d\n",
792 temp[vreg->fuse_corner_count - 1],
793 vreg->corner_count);
794
795 for (i = 0; i < vreg->corner_count; i++) {
796 for (j = 0; j < vreg->fuse_corner_count; j++) {
797 if (i + CPR3_CORNER_OFFSET <= temp[j]) {
798 vreg->corner[i].cpr_fuse_corner = j;
799 break;
800 }
801 }
802 if (j == vreg->fuse_corner_count) {
803 /*
804 * Handle the case where the highest fuse corner maps
805 * to a corner below the highest corner.
806 */
807 vreg->corner[i].cpr_fuse_corner
808 = vreg->fuse_corner_count - 1;
809 }
810 }
811
812 if (of_find_property(vreg->of_node,
813 "qcom,allow-aging-voltage-adjustment", NULL)) {
814 rc = cpr3_parse_array_property(vreg,
815 "qcom,allow-aging-voltage-adjustment",
816 1, &aging_allowed);
817 if (rc)
818 goto free_temp;
819
820 vreg->aging_allowed = aging_allowed;
821 }
822
823 if (of_find_property(vreg->of_node,
824 "qcom,allow-aging-open-loop-voltage-adjustment", NULL)) {
825 rc = cpr3_parse_array_property(vreg,
826 "qcom,allow-aging-open-loop-voltage-adjustment",
827 1, &aging_allowed);
828 if (rc)
829 goto free_temp;
830
831 vreg->aging_allow_open_loop_adj = aging_allowed;
832 }
833
834 if (vreg->aging_allowed) {
835 if (ctrl->aging_ref_volt <= 0) {
836 cpr3_err(ctrl, "qcom,cpr-aging-ref-voltage must be specified\n");
837 rc = -EINVAL;
838 goto free_temp;
839 }
840
841 rc = cpr3_parse_array_property(vreg,
842 "qcom,cpr-aging-max-voltage-adjustment",
843 1, &vreg->aging_max_adjust_volt);
844 if (rc)
845 goto free_temp;
846
847 rc = cpr3_parse_array_property(vreg,
848 "qcom,cpr-aging-ref-corner", 1, &vreg->aging_corner);
849 if (rc) {
850 goto free_temp;
851 } else if (vreg->aging_corner < CPR3_CORNER_OFFSET
852 || vreg->aging_corner > vreg->corner_count - 1
853 + CPR3_CORNER_OFFSET) {
854 cpr3_err(vreg, "aging reference corner=%d not in range [%d, %d]\n",
855 vreg->aging_corner, CPR3_CORNER_OFFSET,
856 vreg->corner_count - 1 + CPR3_CORNER_OFFSET);
857 rc = -EINVAL;
858 goto free_temp;
859 }
860 vreg->aging_corner -= CPR3_CORNER_OFFSET;
861
862 if (of_find_property(vreg->of_node, "qcom,cpr-aging-derate",
863 NULL)) {
864 rc = cpr3_parse_corner_array_property(vreg,
865 "qcom,cpr-aging-derate", 1, temp);
866 if (rc)
867 goto free_temp;
868
869 for (i = 0; i < vreg->corner_count; i++)
870 vreg->corner[i].aging_derate = temp[i];
871 } else {
872 for (i = 0; i < vreg->corner_count; i++)
873 vreg->corner[i].aging_derate
874 = CPR3_AGING_DERATE_UNITY;
875 }
876 }
877
878free_temp:
879 kfree(temp);
880 return rc;
881}
882
883/**
884 * cpr3_parse_thread_u32() - parse the specified property from the CPR3 thread's
885 * device tree node and verify that it is within the allowed limits
886 * @thread: Pointer to the CPR3 thread
887 * @propname: The name of the device tree property to read
888 * @out_value: The output pointer to fill with the value read
889 * @value_min: The minimum allowed property value
890 * @value_max: The maximum allowed property value
891 *
892 * This function prints a verbose error message if the property is missing or
893 * has a value which is not within the specified range.
894 *
895 * Return: 0 on success, errno on failure
896 */
897int cpr3_parse_thread_u32(struct cpr3_thread *thread, const char *propname,
898 u32 *out_value, u32 value_min, u32 value_max)
899{
900 int rc;
901
902 rc = of_property_read_u32(thread->of_node, propname, out_value);
903 if (rc) {
904 cpr3_err(thread->ctrl, "thread %u error reading property %s, rc=%d\n",
905 thread->thread_id, propname, rc);
906 return rc;
907 }
908
909 if (*out_value < value_min || *out_value > value_max) {
910 cpr3_err(thread->ctrl, "thread %u %s=%u is invalid; allowed range: [%u, %u]\n",
911 thread->thread_id, propname, *out_value, value_min,
912 value_max);
913 return -EINVAL;
914 }
915
916 return 0;
917}
918
919/**
920 * cpr3_parse_ctrl_u32() - parse the specified property from the CPR3
921 * controller's device tree node and verify that it is within the
922 * allowed limits
923 * @ctrl: Pointer to the CPR3 controller
924 * @propname: The name of the device tree property to read
925 * @out_value: The output pointer to fill with the value read
926 * @value_min: The minimum allowed property value
927 * @value_max: The maximum allowed property value
928 *
929 * This function prints a verbose error message if the property is missing or
930 * has a value which is not within the specified range.
931 *
932 * Return: 0 on success, errno on failure
933 */
934int cpr3_parse_ctrl_u32(struct cpr3_controller *ctrl, const char *propname,
935 u32 *out_value, u32 value_min, u32 value_max)
936{
937 int rc;
938
939 rc = of_property_read_u32(ctrl->dev->of_node, propname, out_value);
940 if (rc) {
941 cpr3_err(ctrl, "error reading property %s, rc=%d\n",
942 propname, rc);
943 return rc;
944 }
945
946 if (*out_value < value_min || *out_value > value_max) {
947 cpr3_err(ctrl, "%s=%u is invalid; allowed range: [%u, %u]\n",
948 propname, *out_value, value_min, value_max);
949 return -EINVAL;
950 }
951
952 return 0;
953}
954
955/**
956 * cpr3_parse_common_thread_data() - parse common CPR3 thread properties from
957 * device tree
958 * @thread: Pointer to the CPR3 thread
959 *
960 * Return: 0 on success, errno on failure
961 */
962int cpr3_parse_common_thread_data(struct cpr3_thread *thread)
963{
964 int rc;
965
966 rc = cpr3_parse_thread_u32(thread, "qcom,cpr-consecutive-up",
967 &thread->consecutive_up, CPR3_CONSECUTIVE_UP_DOWN_MIN,
968 CPR3_CONSECUTIVE_UP_DOWN_MAX);
969 if (rc)
970 return rc;
971
972 rc = cpr3_parse_thread_u32(thread, "qcom,cpr-consecutive-down",
973 &thread->consecutive_down, CPR3_CONSECUTIVE_UP_DOWN_MIN,
974 CPR3_CONSECUTIVE_UP_DOWN_MAX);
975 if (rc)
976 return rc;
977
978 rc = cpr3_parse_thread_u32(thread, "qcom,cpr-up-threshold",
979 &thread->up_threshold, CPR3_UP_DOWN_THRESHOLD_MIN,
980 CPR3_UP_DOWN_THRESHOLD_MAX);
981 if (rc)
982 return rc;
983
984 rc = cpr3_parse_thread_u32(thread, "qcom,cpr-down-threshold",
985 &thread->down_threshold, CPR3_UP_DOWN_THRESHOLD_MIN,
986 CPR3_UP_DOWN_THRESHOLD_MAX);
987 if (rc)
988 return rc;
989
990 return rc;
991}
992
993/**
994 * cpr3_parse_irq_affinity() - parse CPR IRQ affinity information
995 * @ctrl: Pointer to the CPR3 controller
996 *
997 * Return: 0 on success, errno on failure
998 */
999static int cpr3_parse_irq_affinity(struct cpr3_controller *ctrl)
1000{
1001 struct device_node *cpu_node;
1002 int i, cpu;
1003 int len = 0;
1004
1005 if (!of_find_property(ctrl->dev->of_node, "qcom,cpr-interrupt-affinity",
1006 &len)) {
1007 /* No IRQ affinity required */
1008 return 0;
1009 }
1010
1011 len /= sizeof(u32);
1012
1013 for (i = 0; i < len; i++) {
1014 cpu_node = of_parse_phandle(ctrl->dev->of_node,
1015 "qcom,cpr-interrupt-affinity", i);
1016 if (!cpu_node) {
1017 cpr3_err(ctrl, "could not find CPU node %d\n", i);
1018 return -EINVAL;
1019 }
1020
1021 for_each_possible_cpu(cpu) {
1022 if (of_get_cpu_node(cpu, NULL) == cpu_node) {
1023 cpumask_set_cpu(cpu, &ctrl->irq_affinity_mask);
1024 break;
1025 }
1026 }
1027 of_node_put(cpu_node);
1028 }
1029
1030 return 0;
1031}
1032
1033static int cpr3_panic_notifier_init(struct cpr3_controller *ctrl)
1034{
1035 struct device_node *node = ctrl->dev->of_node;
1036 struct cpr3_panic_regs_info *panic_regs_info;
1037 struct cpr3_reg_info *regs;
1038 int i, reg_count, len, rc = 0;
1039
1040 if (!of_find_property(node, "qcom,cpr-panic-reg-addr-list", &len)) {
1041 /* panic register address list not specified */
1042 return rc;
1043 }
1044
1045 reg_count = len / sizeof(u32);
1046 if (!reg_count) {
1047 cpr3_err(ctrl, "qcom,cpr-panic-reg-addr-list has invalid len = %d\n",
1048 len);
1049 return -EINVAL;
1050 }
1051
1052 if (!of_find_property(node, "qcom,cpr-panic-reg-name-list", NULL)) {
1053 cpr3_err(ctrl, "property qcom,cpr-panic-reg-name-list not specified\n");
1054 return -EINVAL;
1055 }
1056
1057 len = of_property_count_strings(node, "qcom,cpr-panic-reg-name-list");
1058 if (reg_count != len) {
1059 cpr3_err(ctrl, "qcom,cpr-panic-reg-name-list should have %d strings\n",
1060 reg_count);
1061 return -EINVAL;
1062 }
1063
1064 panic_regs_info = devm_kzalloc(ctrl->dev, sizeof(*panic_regs_info),
1065 GFP_KERNEL);
1066 if (!panic_regs_info)
1067 return -ENOMEM;
1068
1069 regs = devm_kcalloc(ctrl->dev, reg_count, sizeof(*regs), GFP_KERNEL);
1070 if (!regs)
1071 return -ENOMEM;
1072
1073 for (i = 0; i < reg_count; i++) {
1074 rc = of_property_read_string_index(node,
1075 "qcom,cpr-panic-reg-name-list", i,
1076 &(regs[i].name));
1077 if (rc) {
1078 cpr3_err(ctrl, "error reading property qcom,cpr-panic-reg-name-list, rc=%d\n",
1079 rc);
1080 return rc;
1081 }
1082
1083 rc = of_property_read_u32_index(node,
1084 "qcom,cpr-panic-reg-addr-list", i,
1085 &(regs[i].addr));
1086 if (rc) {
1087 cpr3_err(ctrl, "error reading property qcom,cpr-panic-reg-addr-list, rc=%d\n",
1088 rc);
1089 return rc;
1090 }
1091 regs[i].virt_addr = devm_ioremap(ctrl->dev, regs[i].addr, 0x4);
1092 if (!regs[i].virt_addr) {
1093 pr_err("Unable to map panic register addr 0x%08x\n",
1094 regs[i].addr);
1095 return -EINVAL;
1096 }
1097 regs[i].value = 0xFFFFFFFF;
1098 }
1099
1100 panic_regs_info->reg_count = reg_count;
1101 panic_regs_info->regs = regs;
1102 ctrl->panic_regs_info = panic_regs_info;
1103
1104 return rc;
1105}
1106
1107/**
1108 * cpr3_parse_common_ctrl_data() - parse common CPR3 controller properties from
1109 * device tree
1110 * @ctrl: Pointer to the CPR3 controller
1111 *
1112 * Return: 0 on success, errno on failure
1113 */
1114int cpr3_parse_common_ctrl_data(struct cpr3_controller *ctrl)
1115{
1116 int rc;
1117
1118 rc = cpr3_parse_ctrl_u32(ctrl, "qcom,cpr-sensor-time",
1119 &ctrl->sensor_time, 0, UINT_MAX);
1120 if (rc)
1121 return rc;
1122
1123 rc = cpr3_parse_ctrl_u32(ctrl, "qcom,cpr-loop-time",
1124 &ctrl->loop_time, 0, UINT_MAX);
1125 if (rc)
1126 return rc;
1127
1128 rc = cpr3_parse_ctrl_u32(ctrl, "qcom,cpr-idle-cycles",
1129 &ctrl->idle_clocks, CPR3_IDLE_CLOCKS_MIN,
1130 CPR3_IDLE_CLOCKS_MAX);
1131 if (rc)
1132 return rc;
1133
1134 rc = cpr3_parse_ctrl_u32(ctrl, "qcom,cpr-step-quot-init-min",
1135 &ctrl->step_quot_init_min, CPR3_STEP_QUOT_MIN,
1136 CPR3_STEP_QUOT_MAX);
1137 if (rc)
1138 return rc;
1139
1140 rc = cpr3_parse_ctrl_u32(ctrl, "qcom,cpr-step-quot-init-max",
1141 &ctrl->step_quot_init_max, CPR3_STEP_QUOT_MIN,
1142 CPR3_STEP_QUOT_MAX);
1143 if (rc)
1144 return rc;
1145
1146 rc = of_property_read_u32(ctrl->dev->of_node, "qcom,voltage-step",
1147 &ctrl->step_volt);
1148 if (rc) {
1149 cpr3_err(ctrl, "error reading property qcom,voltage-step, rc=%d\n",
1150 rc);
1151 return rc;
1152 }
1153 if (ctrl->step_volt <= 0) {
1154 cpr3_err(ctrl, "qcom,voltage-step=%d is invalid\n",
1155 ctrl->step_volt);
1156 return -EINVAL;
1157 }
1158
1159 rc = cpr3_parse_ctrl_u32(ctrl, "qcom,cpr-count-mode",
1160 &ctrl->count_mode, CPR3_COUNT_MODE_ALL_AT_ONCE_MIN,
1161 CPR3_COUNT_MODE_STAGGERED);
1162 if (rc)
1163 return rc;
1164
1165 /* Count repeat is optional */
1166 ctrl->count_repeat = 0;
1167 of_property_read_u32(ctrl->dev->of_node, "qcom,cpr-count-repeat",
1168 &ctrl->count_repeat);
1169
1170 ctrl->cpr_allowed_sw = of_property_read_bool(ctrl->dev->of_node,
1171 "qcom,cpr-enable");
1172
1173 rc = cpr3_parse_irq_affinity(ctrl);
1174 if (rc)
1175 return rc;
1176
David Collins044e9e72017-03-06 16:47:09 -08001177 ctrl->ignore_invalid_fuses = of_property_read_bool(ctrl->dev->of_node,
1178 "qcom,cpr-ignore-invalid-fuses");
1179
David Collins7370f1a2017-01-18 16:21:53 -08001180 /* Aging reference voltage is optional */
1181 ctrl->aging_ref_volt = 0;
1182 of_property_read_u32(ctrl->dev->of_node, "qcom,cpr-aging-ref-voltage",
1183 &ctrl->aging_ref_volt);
1184
1185 /* Aging possible bitmask is optional */
1186 ctrl->aging_possible_mask = 0;
1187 of_property_read_u32(ctrl->dev->of_node,
1188 "qcom,cpr-aging-allowed-reg-mask",
1189 &ctrl->aging_possible_mask);
1190
1191 if (ctrl->aging_possible_mask) {
1192 /*
1193 * Aging possible register value required if bitmask is
1194 * specified
1195 */
1196 rc = cpr3_parse_ctrl_u32(ctrl,
1197 "qcom,cpr-aging-allowed-reg-value",
1198 &ctrl->aging_possible_val, 0, UINT_MAX);
1199 if (rc)
1200 return rc;
1201 }
1202
1203 if (of_find_property(ctrl->dev->of_node, "clock-names", NULL)) {
1204 ctrl->core_clk = devm_clk_get(ctrl->dev, "core_clk");
1205 if (IS_ERR(ctrl->core_clk)) {
1206 rc = PTR_ERR(ctrl->core_clk);
1207 if (rc != -EPROBE_DEFER)
1208 cpr3_err(ctrl, "unable request core clock, rc=%d\n",
1209 rc);
1210 return rc;
1211 }
1212 }
1213
1214 rc = cpr3_panic_notifier_init(ctrl);
1215 if (rc)
1216 return rc;
1217
1218 if (of_find_property(ctrl->dev->of_node, "vdd-supply", NULL)) {
1219 ctrl->vdd_regulator = devm_regulator_get(ctrl->dev, "vdd");
1220 if (IS_ERR(ctrl->vdd_regulator)) {
1221 rc = PTR_ERR(ctrl->vdd_regulator);
1222 if (rc != -EPROBE_DEFER)
1223 cpr3_err(ctrl, "unable to request vdd regulator, rc=%d\n",
1224 rc);
1225 return rc;
1226 }
1227 } else if (ctrl->ctrl_type == CPR_CTRL_TYPE_CPRH) {
1228 /* vdd-supply is optional for CPRh controllers. */
1229 ctrl->vdd_regulator = NULL;
1230 } else {
1231 cpr3_err(ctrl, "vdd supply is not defined\n");
1232 return -ENODEV;
1233 }
1234
1235 /*
Tirupathi Reddy718bc802017-02-09 16:29:24 +05301236 * Reset step_quot to default on each loop_en = 0 transition is
1237 * optional.
1238 */
1239 ctrl->reset_step_quot_loop_en
1240 = of_property_read_bool(ctrl->dev->of_node,
1241 "qcom,cpr-reset-step-quot-loop-en");
1242
1243 /*
David Collins7370f1a2017-01-18 16:21:53 -08001244 * Regulator device handles are not necessary for CPRh controllers
1245 * since communication with the regulators is completely managed
1246 * in hardware.
1247 */
1248 if (ctrl->ctrl_type == CPR_CTRL_TYPE_CPRH)
1249 return rc;
1250
1251 ctrl->system_regulator = devm_regulator_get_optional(ctrl->dev,
1252 "system");
1253 if (IS_ERR(ctrl->system_regulator)) {
1254 rc = PTR_ERR(ctrl->system_regulator);
1255 if (rc != -EPROBE_DEFER) {
1256 rc = 0;
1257 ctrl->system_regulator = NULL;
1258 } else {
1259 return rc;
1260 }
1261 }
1262
1263 ctrl->mem_acc_regulator = devm_regulator_get_optional(ctrl->dev,
1264 "mem-acc");
1265 if (IS_ERR(ctrl->mem_acc_regulator)) {
1266 rc = PTR_ERR(ctrl->mem_acc_regulator);
1267 if (rc != -EPROBE_DEFER) {
1268 rc = 0;
1269 ctrl->mem_acc_regulator = NULL;
1270 } else {
1271 return rc;
1272 }
1273 }
1274
1275 return rc;
1276}
1277
1278/**
1279 * cpr3_limit_open_loop_voltages() - modify the open-loop voltage of each corner
1280 * so that it fits within the floor to ceiling
1281 * voltage range of the corner
1282 * @vreg: Pointer to the CPR3 regulator
1283 *
1284 * This function clips the open-loop voltage for each corner so that it is
1285 * limited to the floor to ceiling range. It also rounds each open-loop voltage
1286 * so that it corresponds to a set point available to the underlying regulator.
1287 *
1288 * Return: 0 on success, errno on failure
1289 */
1290int cpr3_limit_open_loop_voltages(struct cpr3_regulator *vreg)
1291{
1292 int i, volt;
1293
1294 cpr3_debug(vreg, "open-loop voltages after trimming and rounding:\n");
1295 for (i = 0; i < vreg->corner_count; i++) {
1296 volt = CPR3_ROUND(vreg->corner[i].open_loop_volt,
1297 vreg->thread->ctrl->step_volt);
1298 if (volt < vreg->corner[i].floor_volt)
1299 volt = vreg->corner[i].floor_volt;
1300 else if (volt > vreg->corner[i].ceiling_volt)
1301 volt = vreg->corner[i].ceiling_volt;
1302 vreg->corner[i].open_loop_volt = volt;
1303 cpr3_debug(vreg, "corner[%2d]: open-loop=%d uV\n", i, volt);
1304 }
1305
1306 return 0;
1307}
1308
1309/**
1310 * cpr3_open_loop_voltage_as_ceiling() - configures the ceiling voltage for each
1311 * corner to equal the open-loop voltage if the relevant device
1312 * tree property is found for the CPR3 regulator
1313 * @vreg: Pointer to the CPR3 regulator
1314 *
1315 * This function assumes that the the open-loop voltage for each corner has
1316 * already been rounded to the nearest allowed set point and that it falls
1317 * within the floor to ceiling range.
1318 *
1319 * Return: none
1320 */
1321void cpr3_open_loop_voltage_as_ceiling(struct cpr3_regulator *vreg)
1322{
1323 int i;
1324
1325 if (!of_property_read_bool(vreg->of_node,
1326 "qcom,cpr-scaled-open-loop-voltage-as-ceiling"))
1327 return;
1328
1329 for (i = 0; i < vreg->corner_count; i++)
1330 vreg->corner[i].ceiling_volt
1331 = vreg->corner[i].open_loop_volt;
1332}
1333
1334/**
1335 * cpr3_limit_floor_voltages() - raise the floor voltage of each corner so that
1336 * the optional maximum floor to ceiling voltage range specified in
1337 * device tree is satisfied
1338 * @vreg: Pointer to the CPR3 regulator
1339 *
1340 * This function also ensures that the open-loop voltage for each corner falls
1341 * within the final floor to ceiling voltage range and that floor voltages
1342 * increase monotonically.
1343 *
1344 * Return: 0 on success, errno on failure
1345 */
1346int cpr3_limit_floor_voltages(struct cpr3_regulator *vreg)
1347{
1348 char *prop = "qcom,cpr-floor-to-ceiling-max-range";
1349 int i, floor_new;
1350 u32 *floor_range;
1351 int rc = 0;
1352
1353 if (!of_find_property(vreg->of_node, prop, NULL))
1354 goto enforce_monotonicity;
1355
1356 floor_range = kcalloc(vreg->corner_count, sizeof(*floor_range),
1357 GFP_KERNEL);
1358 if (!floor_range)
1359 return -ENOMEM;
1360
1361 rc = cpr3_parse_corner_array_property(vreg, prop, 1, floor_range);
1362 if (rc)
1363 goto free_floor_adjust;
1364
1365 for (i = 0; i < vreg->corner_count; i++) {
1366 if ((s32)floor_range[i] >= 0) {
1367 floor_new = CPR3_ROUND(vreg->corner[i].ceiling_volt
1368 - floor_range[i],
1369 vreg->thread->ctrl->step_volt);
1370
1371 vreg->corner[i].floor_volt = max(floor_new,
1372 vreg->corner[i].floor_volt);
1373 if (vreg->corner[i].open_loop_volt
1374 < vreg->corner[i].floor_volt)
1375 vreg->corner[i].open_loop_volt
1376 = vreg->corner[i].floor_volt;
1377 }
1378 }
1379
1380free_floor_adjust:
1381 kfree(floor_range);
1382
1383enforce_monotonicity:
1384 /* Ensure that floor voltages increase monotonically. */
1385 for (i = 1; i < vreg->corner_count; i++) {
1386 if (vreg->corner[i].floor_volt
1387 < vreg->corner[i - 1].floor_volt) {
1388 cpr3_debug(vreg, "corner %d floor voltage=%d uV < corner %d voltage=%d uV; overriding: corner %d voltage=%d\n",
1389 i, vreg->corner[i].floor_volt,
1390 i - 1, vreg->corner[i - 1].floor_volt,
1391 i, vreg->corner[i - 1].floor_volt);
1392 vreg->corner[i].floor_volt
1393 = vreg->corner[i - 1].floor_volt;
1394
1395 if (vreg->corner[i].open_loop_volt
1396 < vreg->corner[i].floor_volt)
1397 vreg->corner[i].open_loop_volt
1398 = vreg->corner[i].floor_volt;
1399 if (vreg->corner[i].ceiling_volt
1400 < vreg->corner[i].floor_volt)
1401 vreg->corner[i].ceiling_volt
1402 = vreg->corner[i].floor_volt;
1403 }
1404 }
1405
1406 return rc;
1407}
1408
1409/**
1410 * cpr3_print_quots() - print CPR target quotients into the kernel log for
1411 * debugging purposes
1412 * @vreg: Pointer to the CPR3 regulator
1413 *
1414 * Return: none
1415 */
1416void cpr3_print_quots(struct cpr3_regulator *vreg)
1417{
1418 int i, j, pos;
1419 size_t buflen;
1420 char *buf;
1421
1422 buflen = sizeof(*buf) * CPR3_RO_COUNT * (MAX_CHARS_PER_INT + 2);
1423 buf = kzalloc(buflen, GFP_KERNEL);
1424 if (!buf)
1425 return;
1426
1427 for (i = 0; i < vreg->corner_count; i++) {
1428 for (j = 0, pos = 0; j < CPR3_RO_COUNT; j++)
1429 pos += scnprintf(buf + pos, buflen - pos, " %u",
1430 vreg->corner[i].target_quot[j]);
1431 cpr3_debug(vreg, "target quots[%2d]:%s\n", i, buf);
1432 }
1433
1434 kfree(buf);
1435}
1436
1437/**
1438 * cpr3_adjust_fused_open_loop_voltages() - adjust the fused open-loop voltages
1439 * for each fuse corner according to device tree values
1440 * @vreg: Pointer to the CPR3 regulator
1441 * @fuse_volt: Pointer to an array of the fused open-loop voltage
1442 * values
1443 *
1444 * Voltage values in fuse_volt are modified in place.
1445 *
1446 * Return: 0 on success, errno on failure
1447 */
1448int cpr3_adjust_fused_open_loop_voltages(struct cpr3_regulator *vreg,
1449 int *fuse_volt)
1450{
1451 int i, rc, prev_volt;
1452 int *volt_adjust;
1453
1454 if (!of_find_property(vreg->of_node,
1455 "qcom,cpr-open-loop-voltage-fuse-adjustment", NULL)) {
1456 /* No adjustment required. */
1457 return 0;
1458 }
1459
1460 volt_adjust = kcalloc(vreg->fuse_corner_count, sizeof(*volt_adjust),
1461 GFP_KERNEL);
1462 if (!volt_adjust)
1463 return -ENOMEM;
1464
1465 rc = cpr3_parse_array_property(vreg,
1466 "qcom,cpr-open-loop-voltage-fuse-adjustment",
1467 vreg->fuse_corner_count, volt_adjust);
1468 if (rc) {
1469 cpr3_err(vreg, "could not load open-loop fused voltage adjustments, rc=%d\n",
1470 rc);
1471 goto done;
1472 }
1473
1474 for (i = 0; i < vreg->fuse_corner_count; i++) {
1475 if (volt_adjust[i]) {
1476 prev_volt = fuse_volt[i];
1477 fuse_volt[i] += volt_adjust[i];
1478 cpr3_debug(vreg, "adjusted fuse corner %d open-loop voltage: %d --> %d uV\n",
1479 i, prev_volt, fuse_volt[i]);
1480 }
1481 }
1482
1483done:
1484 kfree(volt_adjust);
1485 return rc;
1486}
1487
1488/**
1489 * cpr3_adjust_open_loop_voltages() - adjust the open-loop voltages for each
1490 * corner according to device tree values
1491 * @vreg: Pointer to the CPR3 regulator
1492 *
1493 * Return: 0 on success, errno on failure
1494 */
1495int cpr3_adjust_open_loop_voltages(struct cpr3_regulator *vreg)
1496{
1497 int i, rc, prev_volt, min_volt;
1498 int *volt_adjust, *volt_diff;
1499
1500 if (!of_find_property(vreg->of_node,
1501 "qcom,cpr-open-loop-voltage-adjustment", NULL)) {
1502 /* No adjustment required. */
1503 return 0;
1504 }
1505
1506 volt_adjust = kcalloc(vreg->corner_count, sizeof(*volt_adjust),
1507 GFP_KERNEL);
1508 volt_diff = kcalloc(vreg->corner_count, sizeof(*volt_diff), GFP_KERNEL);
1509 if (!volt_adjust || !volt_diff) {
1510 rc = -ENOMEM;
1511 goto done;
1512 }
1513
1514 rc = cpr3_parse_corner_array_property(vreg,
1515 "qcom,cpr-open-loop-voltage-adjustment", 1, volt_adjust);
1516 if (rc) {
1517 cpr3_err(vreg, "could not load open-loop voltage adjustments, rc=%d\n",
1518 rc);
1519 goto done;
1520 }
1521
1522 for (i = 0; i < vreg->corner_count; i++) {
1523 if (volt_adjust[i]) {
1524 prev_volt = vreg->corner[i].open_loop_volt;
1525 vreg->corner[i].open_loop_volt += volt_adjust[i];
1526 cpr3_debug(vreg, "adjusted corner %d open-loop voltage: %d --> %d uV\n",
1527 i, prev_volt, vreg->corner[i].open_loop_volt);
1528 }
1529 }
1530
1531 if (of_find_property(vreg->of_node,
1532 "qcom,cpr-open-loop-voltage-min-diff", NULL)) {
1533 rc = cpr3_parse_corner_array_property(vreg,
1534 "qcom,cpr-open-loop-voltage-min-diff", 1, volt_diff);
1535 if (rc) {
1536 cpr3_err(vreg, "could not load minimum open-loop voltage differences, rc=%d\n",
1537 rc);
1538 goto done;
1539 }
1540 }
1541
1542 /*
1543 * Ensure that open-loop voltages increase monotonically with respect
1544 * to configurable minimum allowed differences.
1545 */
1546 for (i = 1; i < vreg->corner_count; i++) {
1547 min_volt = vreg->corner[i - 1].open_loop_volt + volt_diff[i];
1548 if (vreg->corner[i].open_loop_volt < min_volt) {
1549 cpr3_debug(vreg, "adjusted corner %d open-loop voltage=%d uV < corner %d voltage=%d uV + min diff=%d uV; overriding: corner %d voltage=%d\n",
1550 i, vreg->corner[i].open_loop_volt,
1551 i - 1, vreg->corner[i - 1].open_loop_volt,
1552 volt_diff[i], i, min_volt);
1553 vreg->corner[i].open_loop_volt = min_volt;
1554 }
1555 }
1556
1557done:
1558 kfree(volt_diff);
1559 kfree(volt_adjust);
1560 return rc;
1561}
1562
1563/**
1564 * cpr3_quot_adjustment() - returns the quotient adjustment value resulting from
1565 * the specified voltage adjustment and RO scaling factor
1566 * @ro_scale: The CPR ring oscillator (RO) scaling factor with units
1567 * of QUOT/V
1568 * @volt_adjust: The amount to adjust the voltage by in units of
1569 * microvolts. This value may be positive or negative.
1570 */
1571int cpr3_quot_adjustment(int ro_scale, int volt_adjust)
1572{
1573 unsigned long long temp;
1574 int quot_adjust;
1575 int sign = 1;
1576
1577 if (ro_scale < 0) {
1578 sign = -sign;
1579 ro_scale = -ro_scale;
1580 }
1581
1582 if (volt_adjust < 0) {
1583 sign = -sign;
1584 volt_adjust = -volt_adjust;
1585 }
1586
1587 temp = (unsigned long long)ro_scale * (unsigned long long)volt_adjust;
1588 do_div(temp, 1000000);
1589
1590 quot_adjust = temp;
1591 quot_adjust *= sign;
1592
1593 return quot_adjust;
1594}
1595
1596/**
1597 * cpr3_voltage_adjustment() - returns the voltage adjustment value resulting
1598 * from the specified quotient adjustment and RO scaling factor
1599 * @ro_scale: The CPR ring oscillator (RO) scaling factor with units
1600 * of QUOT/V
1601 * @quot_adjust: The amount to adjust the quotient by in units of
1602 * QUOT. This value may be positive or negative.
1603 */
1604int cpr3_voltage_adjustment(int ro_scale, int quot_adjust)
1605{
1606 unsigned long long temp;
1607 int volt_adjust;
1608 int sign = 1;
1609
1610 if (ro_scale < 0) {
1611 sign = -sign;
1612 ro_scale = -ro_scale;
1613 }
1614
1615 if (quot_adjust < 0) {
1616 sign = -sign;
1617 quot_adjust = -quot_adjust;
1618 }
1619
1620 if (ro_scale == 0)
1621 return 0;
1622
1623 temp = (unsigned long long)quot_adjust * 1000000;
1624 do_div(temp, ro_scale);
1625
1626 volt_adjust = temp;
1627 volt_adjust *= sign;
1628
1629 return volt_adjust;
1630}
1631
1632/**
1633 * cpr3_parse_closed_loop_voltage_adjustments() - load per-fuse-corner and
1634 * per-corner closed-loop adjustment values from device tree
1635 * @vreg: Pointer to the CPR3 regulator
1636 * @ro_sel: Array of ring oscillator values selected for each
1637 * fuse corner
1638 * @volt_adjust: Pointer to array which will be filled with the
1639 * per-corner closed-loop adjustment voltages
1640 * @volt_adjust_fuse: Pointer to array which will be filled with the
1641 * per-fuse-corner closed-loop adjustment voltages
1642 * @ro_scale: Pointer to array which will be filled with the
1643 * per-fuse-corner RO scaling factor values with units of
1644 * QUOT/V
1645 *
1646 * Return: 0 on success, errno on failure
1647 */
1648int cpr3_parse_closed_loop_voltage_adjustments(
1649 struct cpr3_regulator *vreg, u64 *ro_sel,
1650 int *volt_adjust, int *volt_adjust_fuse, int *ro_scale)
1651{
1652 int i, rc;
1653 u32 *ro_all_scale;
1654
1655 if (!of_find_property(vreg->of_node,
1656 "qcom,cpr-closed-loop-voltage-adjustment", NULL)
1657 && !of_find_property(vreg->of_node,
1658 "qcom,cpr-closed-loop-voltage-fuse-adjustment", NULL)
1659 && !vreg->aging_allowed) {
1660 /* No adjustment required. */
1661 return 0;
1662 } else if (!of_find_property(vreg->of_node,
1663 "qcom,cpr-ro-scaling-factor", NULL)) {
1664 cpr3_err(vreg, "qcom,cpr-ro-scaling-factor is required for closed-loop voltage adjustment, but is missing\n");
1665 return -EINVAL;
1666 }
1667
1668 ro_all_scale = kcalloc(vreg->fuse_corner_count * CPR3_RO_COUNT,
1669 sizeof(*ro_all_scale), GFP_KERNEL);
1670 if (!ro_all_scale)
1671 return -ENOMEM;
1672
1673 rc = cpr3_parse_array_property(vreg, "qcom,cpr-ro-scaling-factor",
1674 vreg->fuse_corner_count * CPR3_RO_COUNT, ro_all_scale);
1675 if (rc) {
1676 cpr3_err(vreg, "could not load RO scaling factors, rc=%d\n",
1677 rc);
1678 goto done;
1679 }
1680
1681 for (i = 0; i < vreg->fuse_corner_count; i++)
1682 ro_scale[i] = ro_all_scale[i * CPR3_RO_COUNT + ro_sel[i]];
1683
1684 for (i = 0; i < vreg->corner_count; i++)
1685 memcpy(vreg->corner[i].ro_scale,
1686 &ro_all_scale[vreg->corner[i].cpr_fuse_corner * CPR3_RO_COUNT],
1687 sizeof(*ro_all_scale) * CPR3_RO_COUNT);
1688
1689 if (of_find_property(vreg->of_node,
1690 "qcom,cpr-closed-loop-voltage-fuse-adjustment", NULL)) {
1691 rc = cpr3_parse_array_property(vreg,
1692 "qcom,cpr-closed-loop-voltage-fuse-adjustment",
1693 vreg->fuse_corner_count, volt_adjust_fuse);
1694 if (rc) {
1695 cpr3_err(vreg, "could not load closed-loop fused voltage adjustments, rc=%d\n",
1696 rc);
1697 goto done;
1698 }
1699 }
1700
1701 if (of_find_property(vreg->of_node,
1702 "qcom,cpr-closed-loop-voltage-adjustment", NULL)) {
1703 rc = cpr3_parse_corner_array_property(vreg,
1704 "qcom,cpr-closed-loop-voltage-adjustment",
1705 1, volt_adjust);
1706 if (rc) {
1707 cpr3_err(vreg, "could not load closed-loop voltage adjustments, rc=%d\n",
1708 rc);
1709 goto done;
1710 }
1711 }
1712
1713done:
1714 kfree(ro_all_scale);
1715 return rc;
1716}
1717
1718/**
1719 * cpr3_apm_init() - initialize APM data for a CPR3 controller
1720 * @ctrl: Pointer to the CPR3 controller
1721 *
1722 * This function loads memory array power mux (APM) data from device tree
1723 * if it is present and requests a handle to the appropriate APM controller
1724 * device.
1725 *
1726 * Return: 0 on success, errno on failure
1727 */
1728int cpr3_apm_init(struct cpr3_controller *ctrl)
1729{
1730 struct device_node *node = ctrl->dev->of_node;
1731 int rc;
1732
1733 if (!of_find_property(node, "qcom,apm-ctrl", NULL)) {
1734 /* No APM used */
1735 return 0;
1736 }
1737
1738 ctrl->apm = msm_apm_ctrl_dev_get(ctrl->dev);
1739 if (IS_ERR(ctrl->apm)) {
1740 rc = PTR_ERR(ctrl->apm);
1741 if (rc != -EPROBE_DEFER)
1742 cpr3_err(ctrl, "APM get failed, rc=%d\n", rc);
1743 return rc;
1744 }
1745
1746 rc = of_property_read_u32(node, "qcom,apm-threshold-voltage",
1747 &ctrl->apm_threshold_volt);
1748 if (rc) {
1749 cpr3_err(ctrl, "error reading qcom,apm-threshold-voltage, rc=%d\n",
1750 rc);
1751 return rc;
1752 }
1753 ctrl->apm_threshold_volt
1754 = CPR3_ROUND(ctrl->apm_threshold_volt, ctrl->step_volt);
1755
1756 /* No error check since this is an optional property. */
1757 of_property_read_u32(node, "qcom,apm-hysteresis-voltage",
1758 &ctrl->apm_adj_volt);
1759 ctrl->apm_adj_volt = CPR3_ROUND(ctrl->apm_adj_volt, ctrl->step_volt);
1760
1761 ctrl->apm_high_supply = MSM_APM_SUPPLY_APCC;
1762 ctrl->apm_low_supply = MSM_APM_SUPPLY_MX;
1763
1764 return 0;
1765}
1766
1767/**
1768 * cpr3_mem_acc_init() - initialize mem-acc regulator data for
1769 * a CPR3 regulator
1770 * @ctrl: Pointer to the CPR3 controller
1771 *
1772 * Return: 0 on success, errno on failure
1773 */
1774int cpr3_mem_acc_init(struct cpr3_regulator *vreg)
1775{
1776 struct cpr3_controller *ctrl = vreg->thread->ctrl;
1777 u32 *temp;
1778 int i, rc;
1779
1780 if (!ctrl->mem_acc_regulator) {
1781 cpr3_info(ctrl, "not using memory accelerator regulator\n");
1782 return 0;
1783 }
1784
1785 temp = kcalloc(vreg->corner_count, sizeof(*temp), GFP_KERNEL);
1786 if (!temp)
1787 return -ENOMEM;
1788
1789 rc = cpr3_parse_corner_array_property(vreg, "qcom,mem-acc-voltage",
1790 1, temp);
1791 if (rc) {
1792 cpr3_err(ctrl, "could not load mem-acc corners, rc=%d\n", rc);
1793 } else {
1794 for (i = 0; i < vreg->corner_count; i++)
1795 vreg->corner[i].mem_acc_volt = temp[i];
1796 }
1797
1798 kfree(temp);
1799 return rc;
1800}
1801
1802/**
1803 * cpr4_load_core_and_temp_adj() - parse amount of voltage adjustment for
1804 * per-online-core and per-temperature voltage adjustment for a
1805 * given corner or corner band from device tree.
1806 * @vreg: Pointer to the CPR3 regulator
1807 * @num: Corner number or corner band number
1808 * @use_corner_band: Boolean indicating if the CPR3 regulator supports
1809 * adjustments per corner band
1810 *
1811 * Return: 0 on success, errno on failure
1812 */
1813static int cpr4_load_core_and_temp_adj(struct cpr3_regulator *vreg,
1814 int num, bool use_corner_band)
1815{
1816 struct cpr3_controller *ctrl = vreg->thread->ctrl;
1817 struct cpr4_sdelta *sdelta;
1818 int sdelta_size, i, j, pos, rc = 0;
1819 char str[75];
1820 size_t buflen;
1821 char *buf;
1822
1823 sdelta = use_corner_band ? vreg->corner_band[num].sdelta :
1824 vreg->corner[num].sdelta;
1825
1826 if (!sdelta->allow_core_count_adj && !sdelta->allow_temp_adj) {
1827 /* corner doesn't need sdelta table */
1828 sdelta->max_core_count = 0;
1829 sdelta->temp_band_count = 0;
1830 return rc;
1831 }
1832
1833 sdelta_size = sdelta->max_core_count * sdelta->temp_band_count;
1834 snprintf(str, sizeof(str), use_corner_band ?
1835 "corner_band=%d core_config_count=%d temp_band_count=%d sdelta_size=%d\n"
1836 : "corner=%d core_config_count=%d temp_band_count=%d sdelta_size=%d\n",
1837 num, sdelta->max_core_count,
1838 sdelta->temp_band_count, sdelta_size);
1839
1840 cpr3_debug(vreg, "%s", str);
1841
1842 sdelta->table = devm_kcalloc(ctrl->dev, sdelta_size,
1843 sizeof(*sdelta->table), GFP_KERNEL);
1844 if (!sdelta->table)
1845 return -ENOMEM;
1846
1847 snprintf(str, sizeof(str), use_corner_band ?
1848 "qcom,cpr-corner-band%d-temp-core-voltage-adjustment" :
1849 "qcom,cpr-corner%d-temp-core-voltage-adjustment",
1850 num + CPR3_CORNER_OFFSET);
1851
1852 rc = cpr3_parse_array_property(vreg, str, sdelta_size,
1853 sdelta->table);
1854 if (rc) {
1855 cpr3_err(vreg, "could not load %s, rc=%d\n", str, rc);
1856 return rc;
1857 }
1858
1859 /*
1860 * Convert sdelta margins from uV to PMIC steps and apply negation to
1861 * follow the SDELTA register semantics.
1862 */
1863 for (i = 0; i < sdelta_size; i++)
1864 sdelta->table[i] = -(sdelta->table[i] / ctrl->step_volt);
1865
1866 buflen = sizeof(*buf) * sdelta_size * (MAX_CHARS_PER_INT + 2);
1867 buf = kzalloc(buflen, GFP_KERNEL);
1868 if (!buf)
1869 return rc;
1870
1871 for (i = 0; i < sdelta->max_core_count; i++) {
1872 for (j = 0, pos = 0; j < sdelta->temp_band_count; j++)
1873 pos += scnprintf(buf + pos, buflen - pos, " %u",
1874 sdelta->table[i * sdelta->temp_band_count + j]);
1875 cpr3_debug(vreg, "sdelta[%d]:%s\n", i, buf);
1876 }
1877
1878 kfree(buf);
1879 return rc;
1880}
1881
1882/**
1883 * cpr4_parse_core_count_temp_voltage_adj() - parse configuration data for
1884 * per-online-core and per-temperature voltage adjustment for
1885 * a CPR3 regulator from device tree.
1886 * @vreg: Pointer to the CPR3 regulator
1887 * @use_corner_band: Boolean indicating if the CPR3 regulator supports
1888 * adjustments per corner band
1889 *
1890 * This function supports parsing of per-online-core and per-temperature
1891 * adjustments per corner or per corner band. CPR controllers which support
1892 * corner bands apply the same adjustments to all corners within a corner band.
1893 *
1894 * Return: 0 on success, errno on failure
1895 */
1896int cpr4_parse_core_count_temp_voltage_adj(
1897 struct cpr3_regulator *vreg, bool use_corner_band)
1898{
1899 struct cpr3_controller *ctrl = vreg->thread->ctrl;
1900 struct device_node *node = vreg->of_node;
1901 struct cpr3_corner *corner;
1902 struct cpr4_sdelta *sdelta;
1903 int i, sdelta_table_count, rc = 0;
1904 int *allow_core_count_adj = NULL, *allow_temp_adj = NULL;
1905 char prop_str[75];
1906
1907 if (of_find_property(node, use_corner_band ?
1908 "qcom,corner-band-allow-temp-adjustment"
1909 : "qcom,corner-allow-temp-adjustment", NULL)) {
1910 if (!ctrl->allow_temp_adj) {
1911 cpr3_err(ctrl, "Temperature adjustment configurations missing\n");
1912 return -EINVAL;
1913 }
1914
1915 vreg->allow_temp_adj = true;
1916 }
1917
1918 if (of_find_property(node, use_corner_band ?
1919 "qcom,corner-band-allow-core-count-adjustment"
1920 : "qcom,corner-allow-core-count-adjustment",
1921 NULL)) {
1922 rc = of_property_read_u32(node, "qcom,max-core-count",
1923 &vreg->max_core_count);
1924 if (rc) {
1925 cpr3_err(vreg, "error reading qcom,max-core-count, rc=%d\n",
1926 rc);
1927 return -EINVAL;
1928 }
1929
1930 vreg->allow_core_count_adj = true;
1931 ctrl->allow_core_count_adj = true;
1932 }
1933
1934 if (!vreg->allow_temp_adj && !vreg->allow_core_count_adj) {
1935 /*
1936 * Both per-online-core and temperature based adjustments are
1937 * disabled for this regulator.
1938 */
1939 return 0;
1940 } else if (!vreg->allow_core_count_adj) {
1941 /*
1942 * Only per-temperature voltage adjusments are allowed.
1943 * Keep max core count value as 1 to allocate SDELTA.
1944 */
1945 vreg->max_core_count = 1;
1946 }
1947
1948 if (vreg->allow_core_count_adj) {
1949 allow_core_count_adj = kcalloc(vreg->corner_count,
1950 sizeof(*allow_core_count_adj),
1951 GFP_KERNEL);
1952 if (!allow_core_count_adj)
1953 return -ENOMEM;
1954
1955 snprintf(prop_str, sizeof(prop_str), use_corner_band ?
1956 "qcom,corner-band-allow-core-count-adjustment" :
1957 "qcom,corner-allow-core-count-adjustment");
1958
1959 rc = use_corner_band ?
1960 cpr3_parse_corner_band_array_property(vreg, prop_str,
1961 1, allow_core_count_adj) :
1962 cpr3_parse_corner_array_property(vreg, prop_str,
1963 1, allow_core_count_adj);
1964 if (rc) {
1965 cpr3_err(vreg, "error reading %s, rc=%d\n", prop_str,
1966 rc);
1967 goto done;
1968 }
1969 }
1970
1971 if (vreg->allow_temp_adj) {
1972 allow_temp_adj = kcalloc(vreg->corner_count,
1973 sizeof(*allow_temp_adj), GFP_KERNEL);
1974 if (!allow_temp_adj) {
1975 rc = -ENOMEM;
1976 goto done;
1977 }
1978
1979 snprintf(prop_str, sizeof(prop_str), use_corner_band ?
1980 "qcom,corner-band-allow-temp-adjustment" :
1981 "qcom,corner-allow-temp-adjustment");
1982
1983 rc = use_corner_band ?
1984 cpr3_parse_corner_band_array_property(vreg, prop_str,
1985 1, allow_temp_adj) :
1986 cpr3_parse_corner_array_property(vreg, prop_str,
1987 1, allow_temp_adj);
1988 if (rc) {
1989 cpr3_err(vreg, "error reading %s, rc=%d\n", prop_str,
1990 rc);
1991 goto done;
1992 }
1993 }
1994
1995 sdelta_table_count = use_corner_band ? vreg->corner_band_count :
1996 vreg->corner_count;
1997
1998 for (i = 0; i < sdelta_table_count; i++) {
1999 sdelta = devm_kzalloc(ctrl->dev, sizeof(*corner->sdelta),
2000 GFP_KERNEL);
2001 if (!sdelta) {
2002 rc = -ENOMEM;
2003 goto done;
2004 }
2005
2006 if (allow_core_count_adj)
2007 sdelta->allow_core_count_adj = allow_core_count_adj[i];
2008 if (allow_temp_adj)
2009 sdelta->allow_temp_adj = allow_temp_adj[i];
2010 sdelta->max_core_count = vreg->max_core_count;
2011 sdelta->temp_band_count = ctrl->temp_band_count;
2012
2013 if (use_corner_band)
2014 vreg->corner_band[i].sdelta = sdelta;
2015 else
2016 vreg->corner[i].sdelta = sdelta;
2017
2018 rc = cpr4_load_core_and_temp_adj(vreg, i, use_corner_band);
2019 if (rc) {
2020 cpr3_err(vreg, "corner/band %d core and temp adjustment loading failed, rc=%d\n",
2021 i, rc);
2022 goto done;
2023 }
2024 }
2025
2026done:
2027 kfree(allow_core_count_adj);
2028 kfree(allow_temp_adj);
2029
2030 return rc;
2031}
2032
2033/**
2034 * cprh_adjust_voltages_for_apm() - adjust per-corner floor and ceiling voltages
2035 * so that they do not overlap the APM threshold voltage.
2036 * @vreg: Pointer to the CPR3 regulator
2037 *
2038 * The memory array power mux (APM) must be configured for a specific supply
2039 * based upon where the VDD voltage lies with respect to the APM threshold
2040 * voltage. When using CPR hardware closed-loop, the voltage may vary anywhere
2041 * between the floor and ceiling voltage without software notification.
2042 * Therefore, it is required that the floor to ceiling range for every corner
2043 * not intersect the APM threshold voltage. This function adjusts the floor to
2044 * ceiling range for each corner which violates this requirement.
2045 *
2046 * The following algorithm is applied:
2047 * if floor < threshold <= ceiling:
2048 * if open_loop >= threshold, then floor = threshold - adj
2049 * else ceiling = threshold - step
2050 * where:
2051 * adj = APM hysteresis voltage established to minimize the number of
2052 * corners with artificially increased floor voltages
2053 * step = voltage in microvolts of a single step of the VDD supply
2054 *
2055 * The open-loop voltage is also bounded by the new floor or ceiling value as
2056 * needed.
2057 *
2058 * Return: none
2059 */
2060void cprh_adjust_voltages_for_apm(struct cpr3_regulator *vreg)
2061{
2062 struct cpr3_controller *ctrl = vreg->thread->ctrl;
2063 struct cpr3_corner *corner;
2064 int i, adj, threshold, prev_ceiling, prev_floor, prev_open_loop;
2065
2066 if (!ctrl->apm_threshold_volt) {
2067 /* APM not being used. */
2068 return;
2069 }
2070
2071 ctrl->apm_threshold_volt = CPR3_ROUND(ctrl->apm_threshold_volt,
2072 ctrl->step_volt);
2073 ctrl->apm_adj_volt = CPR3_ROUND(ctrl->apm_adj_volt, ctrl->step_volt);
2074
2075 threshold = ctrl->apm_threshold_volt;
2076 adj = ctrl->apm_adj_volt;
2077
2078 for (i = 0; i < vreg->corner_count; i++) {
2079 corner = &vreg->corner[i];
2080
2081 if (threshold <= corner->floor_volt
2082 || threshold > corner->ceiling_volt)
2083 continue;
2084
2085 prev_floor = corner->floor_volt;
2086 prev_ceiling = corner->ceiling_volt;
2087 prev_open_loop = corner->open_loop_volt;
2088
2089 if (corner->open_loop_volt >= threshold) {
2090 corner->floor_volt = max(corner->floor_volt,
2091 threshold - adj);
2092 if (corner->open_loop_volt < corner->floor_volt)
2093 corner->open_loop_volt = corner->floor_volt;
2094 } else {
2095 corner->ceiling_volt = threshold - ctrl->step_volt;
2096 }
2097
2098 if (corner->floor_volt != prev_floor
2099 || corner->ceiling_volt != prev_ceiling
2100 || corner->open_loop_volt != prev_open_loop)
2101 cpr3_debug(vreg, "APM threshold=%d, APM adj=%d changed corner %d voltages; prev: floor=%d, ceiling=%d, open-loop=%d; new: floor=%d, ceiling=%d, open-loop=%d\n",
2102 threshold, adj, i, prev_floor, prev_ceiling,
2103 prev_open_loop, corner->floor_volt,
2104 corner->ceiling_volt, corner->open_loop_volt);
2105 }
2106}
2107
2108/**
2109 * cprh_adjust_voltages_for_mem_acc() - adjust per-corner floor and ceiling
2110 * voltages so that they do not intersect the MEM ACC threshold
2111 * voltage
2112 * @vreg: Pointer to the CPR3 regulator
2113 *
2114 * The following algorithm is applied:
2115 * if floor < threshold <= ceiling:
2116 * if open_loop >= threshold, then floor = threshold
2117 * else ceiling = threshold - step
2118 * where:
2119 * step = voltage in microvolts of a single step of the VDD supply
2120 *
2121 * The open-loop voltage is also bounded by the new floor or ceiling value as
2122 * needed.
2123 *
2124 * Return: none
2125 */
2126void cprh_adjust_voltages_for_mem_acc(struct cpr3_regulator *vreg)
2127{
2128 struct cpr3_controller *ctrl = vreg->thread->ctrl;
2129 struct cpr3_corner *corner;
2130 int i, threshold, prev_ceiling, prev_floor, prev_open_loop;
2131
2132 if (!ctrl->mem_acc_threshold_volt) {
2133 /* MEM ACC not being used. */
2134 return;
2135 }
2136
2137 ctrl->mem_acc_threshold_volt = CPR3_ROUND(ctrl->mem_acc_threshold_volt,
2138 ctrl->step_volt);
2139
2140 threshold = ctrl->mem_acc_threshold_volt;
2141
2142 for (i = 0; i < vreg->corner_count; i++) {
2143 corner = &vreg->corner[i];
2144
2145 if (threshold <= corner->floor_volt
2146 || threshold > corner->ceiling_volt)
2147 continue;
2148
2149 prev_floor = corner->floor_volt;
2150 prev_ceiling = corner->ceiling_volt;
2151 prev_open_loop = corner->open_loop_volt;
2152
2153 if (corner->open_loop_volt >= threshold) {
2154 corner->floor_volt = max(corner->floor_volt, threshold);
2155 if (corner->open_loop_volt < corner->floor_volt)
2156 corner->open_loop_volt = corner->floor_volt;
2157 } else {
2158 corner->ceiling_volt = threshold - ctrl->step_volt;
2159 }
2160
2161 if (corner->floor_volt != prev_floor
2162 || corner->ceiling_volt != prev_ceiling
2163 || corner->open_loop_volt != prev_open_loop)
2164 cpr3_debug(vreg, "MEM ACC threshold=%d changed corner %d voltages; prev: floor=%d, ceiling=%d, open-loop=%d; new: floor=%d, ceiling=%d, open-loop=%d\n",
2165 threshold, i, prev_floor, prev_ceiling,
2166 prev_open_loop, corner->floor_volt,
2167 corner->ceiling_volt, corner->open_loop_volt);
2168 }
2169}
2170
2171/**
2172 * cpr3_apply_closed_loop_offset_voltages() - modify the closed-loop voltage
2173 * adjustments by the amounts that are needed for this
2174 * fuse combo
2175 * @vreg: Pointer to the CPR3 regulator
2176 * @volt_adjust: Array of closed-loop voltage adjustment values of length
2177 * vreg->corner_count which is further adjusted based upon
2178 * offset voltage fuse values.
2179 * @fuse_volt_adjust: Fused closed-loop voltage adjustment values of length
2180 * vreg->fuse_corner_count.
2181 *
2182 * Return: 0 on success, errno on failure
2183 */
2184static int cpr3_apply_closed_loop_offset_voltages(struct cpr3_regulator *vreg,
2185 int *volt_adjust, int *fuse_volt_adjust)
2186{
2187 u32 *corner_map;
2188 int rc = 0, i;
2189
2190 if (!of_find_property(vreg->of_node,
2191 "qcom,cpr-fused-closed-loop-voltage-adjustment-map", NULL)) {
2192 /* No closed-loop offset required. */
2193 return 0;
2194 }
2195
2196 corner_map = kcalloc(vreg->corner_count, sizeof(*corner_map),
2197 GFP_KERNEL);
2198 if (!corner_map)
2199 return -ENOMEM;
2200
2201 rc = cpr3_parse_corner_array_property(vreg,
2202 "qcom,cpr-fused-closed-loop-voltage-adjustment-map",
2203 1, corner_map);
2204 if (rc)
2205 goto done;
2206
2207 for (i = 0; i < vreg->corner_count; i++) {
2208 if (corner_map[i] == 0) {
2209 continue;
2210 } else if (corner_map[i] > vreg->fuse_corner_count) {
2211 cpr3_err(vreg, "corner %d mapped to invalid fuse corner: %u\n",
2212 i, corner_map[i]);
2213 rc = -EINVAL;
2214 goto done;
2215 }
2216
2217 volt_adjust[i] += fuse_volt_adjust[corner_map[i] - 1];
2218 }
2219
2220done:
2221 kfree(corner_map);
2222 return rc;
2223}
2224
2225/**
2226 * cpr3_enforce_inc_quotient_monotonicity() - Ensure that target quotients
2227 * increase monotonically from lower to higher corners
2228 * @vreg: Pointer to the CPR3 regulator
2229 *
2230 * Return: 0 on success, errno on failure
2231 */
2232static void cpr3_enforce_inc_quotient_monotonicity(struct cpr3_regulator *vreg)
2233{
2234 int i, j;
2235
2236 for (i = 1; i < vreg->corner_count; i++) {
2237 for (j = 0; j < CPR3_RO_COUNT; j++) {
2238 if (vreg->corner[i].target_quot[j]
2239 && vreg->corner[i].target_quot[j]
2240 < vreg->corner[i - 1].target_quot[j]) {
2241 cpr3_debug(vreg, "corner %d RO%u target quot=%u < corner %d RO%u target quot=%u; overriding: corner %d RO%u target quot=%u\n",
2242 i, j,
2243 vreg->corner[i].target_quot[j],
2244 i - 1, j,
2245 vreg->corner[i - 1].target_quot[j],
2246 i, j,
2247 vreg->corner[i - 1].target_quot[j]);
2248 vreg->corner[i].target_quot[j]
2249 = vreg->corner[i - 1].target_quot[j];
2250 }
2251 }
2252 }
2253}
2254
2255/**
2256 * cpr3_enforce_dec_quotient_monotonicity() - Ensure that target quotients
2257 * decrease monotonically from higher to lower corners
2258 * @vreg: Pointer to the CPR3 regulator
2259 *
2260 * Return: 0 on success, errno on failure
2261 */
2262static void cpr3_enforce_dec_quotient_monotonicity(struct cpr3_regulator *vreg)
2263{
2264 int i, j;
2265
2266 for (i = vreg->corner_count - 2; i >= 0; i--) {
2267 for (j = 0; j < CPR3_RO_COUNT; j++) {
2268 if (vreg->corner[i + 1].target_quot[j]
2269 && vreg->corner[i].target_quot[j]
2270 > vreg->corner[i + 1].target_quot[j]) {
2271 cpr3_debug(vreg, "corner %d RO%u target quot=%u > corner %d RO%u target quot=%u; overriding: corner %d RO%u target quot=%u\n",
2272 i, j,
2273 vreg->corner[i].target_quot[j],
2274 i + 1, j,
2275 vreg->corner[i + 1].target_quot[j],
2276 i, j,
2277 vreg->corner[i + 1].target_quot[j]);
2278 vreg->corner[i].target_quot[j]
2279 = vreg->corner[i + 1].target_quot[j];
2280 }
2281 }
2282 }
2283}
2284
2285/**
2286 * _cpr3_adjust_target_quotients() - adjust the target quotients for each
2287 * corner of the regulator according to input adjustment and
2288 * scaling arrays
2289 * @vreg: Pointer to the CPR3 regulator
2290 * @volt_adjust: Pointer to an array of closed-loop voltage adjustments
2291 * with units of microvolts. The array must have
2292 * vreg->corner_count number of elements.
2293 * @ro_scale: Pointer to a flattened 2D array of RO scaling factors.
2294 * The array must have an inner dimension of CPR3_RO_COUNT
2295 * and an outer dimension of vreg->corner_count
2296 * @label: Null terminated string providing a label for the type
2297 * of adjustment.
2298 *
2299 * Return: true if any corners received a positive voltage adjustment (> 0),
2300 * else false
2301 */
2302static bool _cpr3_adjust_target_quotients(struct cpr3_regulator *vreg,
2303 const int *volt_adjust, const int *ro_scale, const char *label)
2304{
2305 int i, j, quot_adjust;
2306 bool is_increasing = false;
2307 u32 prev_quot;
2308
2309 for (i = 0; i < vreg->corner_count; i++) {
2310 for (j = 0; j < CPR3_RO_COUNT; j++) {
2311 if (vreg->corner[i].target_quot[j]) {
2312 quot_adjust = cpr3_quot_adjustment(
2313 ro_scale[i * CPR3_RO_COUNT + j],
2314 volt_adjust[i]);
2315 if (quot_adjust) {
2316 prev_quot = vreg->corner[i].
2317 target_quot[j];
2318 vreg->corner[i].target_quot[j]
2319 += quot_adjust;
2320 cpr3_debug(vreg, "adjusted corner %d RO%d target quot %s: %u --> %u (%d uV)\n",
2321 i, j, label, prev_quot,
2322 vreg->corner[i].target_quot[j],
2323 volt_adjust[i]);
2324 }
2325 }
2326 }
2327 if (volt_adjust[i] > 0)
2328 is_increasing = true;
2329 }
2330
2331 return is_increasing;
2332}
2333
2334/**
2335 * cpr3_adjust_target_quotients() - adjust the target quotients for each
2336 * corner according to device tree values and fuse values
2337 * @vreg: Pointer to the CPR3 regulator
2338 * @fuse_volt_adjust: Fused closed-loop voltage adjustment values of length
2339 * vreg->fuse_corner_count. This parameter could be null
2340 * pointer when no fused adjustments are needed.
2341 *
2342 * Return: 0 on success, errno on failure
2343 */
2344int cpr3_adjust_target_quotients(struct cpr3_regulator *vreg,
2345 int *fuse_volt_adjust)
2346{
2347 int i, rc;
2348 int *volt_adjust, *ro_scale;
2349 bool explicit_adjustment, fused_adjustment, is_increasing;
2350
2351 explicit_adjustment = of_find_property(vreg->of_node,
2352 "qcom,cpr-closed-loop-voltage-adjustment", NULL);
2353 fused_adjustment = of_find_property(vreg->of_node,
2354 "qcom,cpr-fused-closed-loop-voltage-adjustment-map", NULL);
2355
2356 if (!explicit_adjustment && !fused_adjustment && !vreg->aging_allowed) {
2357 /* No adjustment required. */
2358 return 0;
2359 } else if (!of_find_property(vreg->of_node,
2360 "qcom,cpr-ro-scaling-factor", NULL)) {
2361 cpr3_err(vreg, "qcom,cpr-ro-scaling-factor is required for closed-loop voltage adjustment, but is missing\n");
2362 return -EINVAL;
2363 }
2364
2365 volt_adjust = kcalloc(vreg->corner_count, sizeof(*volt_adjust),
2366 GFP_KERNEL);
2367 ro_scale = kcalloc(vreg->corner_count * CPR3_RO_COUNT,
2368 sizeof(*ro_scale), GFP_KERNEL);
2369 if (!volt_adjust || !ro_scale) {
2370 rc = -ENOMEM;
2371 goto done;
2372 }
2373
2374 rc = cpr3_parse_corner_array_property(vreg,
2375 "qcom,cpr-ro-scaling-factor", CPR3_RO_COUNT, ro_scale);
2376 if (rc) {
2377 cpr3_err(vreg, "could not load RO scaling factors, rc=%d\n",
2378 rc);
2379 goto done;
2380 }
2381
2382 for (i = 0; i < vreg->corner_count; i++)
2383 memcpy(vreg->corner[i].ro_scale, &ro_scale[i * CPR3_RO_COUNT],
2384 sizeof(*ro_scale) * CPR3_RO_COUNT);
2385
2386 if (explicit_adjustment) {
2387 rc = cpr3_parse_corner_array_property(vreg,
2388 "qcom,cpr-closed-loop-voltage-adjustment",
2389 1, volt_adjust);
2390 if (rc) {
2391 cpr3_err(vreg, "could not load closed-loop voltage adjustments, rc=%d\n",
2392 rc);
2393 goto done;
2394 }
2395
2396 _cpr3_adjust_target_quotients(vreg, volt_adjust, ro_scale,
2397 "from DT");
2398 cpr3_enforce_inc_quotient_monotonicity(vreg);
2399 }
2400
2401 if (fused_adjustment && fuse_volt_adjust) {
2402 memset(volt_adjust, 0,
2403 sizeof(*volt_adjust) * vreg->corner_count);
2404
2405 rc = cpr3_apply_closed_loop_offset_voltages(vreg, volt_adjust,
2406 fuse_volt_adjust);
2407 if (rc) {
2408 cpr3_err(vreg, "could not apply fused closed-loop voltage reductions, rc=%d\n",
2409 rc);
2410 goto done;
2411 }
2412
2413 is_increasing = _cpr3_adjust_target_quotients(vreg, volt_adjust,
2414 ro_scale, "from fuse");
2415 if (is_increasing)
2416 cpr3_enforce_inc_quotient_monotonicity(vreg);
2417 else
2418 cpr3_enforce_dec_quotient_monotonicity(vreg);
2419 }
2420
2421done:
2422 kfree(volt_adjust);
2423 kfree(ro_scale);
2424 return rc;
2425}
Tirupathi Reddy53d99a02016-08-08 17:04:23 +05302426
2427/**
2428 * cpr3_parse_fuse_combo_map() - parse fuse combo map data for a CPR3 regulator
2429 * from device tree.
2430 * @vreg: Pointer to the CPR3 regulator
2431 * @fuse_val: Array of selection fuse parameter values
2432 * @fuse_count: Number of selection fuse parameters used in fuse combo
2433 * map
2434 *
2435 * This function reads the qcom,cpr-fuse-combo-map device tree property and
2436 * populates the fuse_combo element of CPR3 regulator with the row number of
2437 * fuse combo map data that matches with the data in fuse_val input array.
2438 *
2439 * Return: 0 on success, -ENODEV if qcom,cpr-fuse-combo-map property is not
2440 * specified in device node, other errno on failure
2441 */
2442int cpr3_parse_fuse_combo_map(struct cpr3_regulator *vreg, u64 *fuse_val,
2443 int fuse_count)
2444{
2445 struct device_node *node = vreg->of_node;
2446 int i, j, len, num_fuse_combos, row_size, rc = 0;
2447 u32 *tmp;
2448
2449 if (!of_find_property(node, "qcom,cpr-fuse-combo-map", &len)) {
2450 /* property not specified */
2451 return -ENODEV;
2452 }
2453
2454 row_size = fuse_count * 2;
2455 if (len == 0 || len % (sizeof(u32) * row_size)) {
2456 cpr3_err(vreg, "qcom,cpr-fuse-combo-map length=%d is invalid\n",
2457 len);
2458 return -EINVAL;
2459 }
2460
2461 num_fuse_combos = len / (sizeof(u32) * row_size);
2462 vreg->fuse_combos_supported = num_fuse_combos;
2463
2464 tmp = kzalloc(len, GFP_KERNEL);
2465 if (!tmp)
2466 return -ENOMEM;
2467
2468 rc = of_property_read_u32_array(node, "qcom,cpr-fuse-combo-map",
2469 tmp, num_fuse_combos * row_size);
2470 if (rc) {
2471 cpr3_err(vreg, "could not read qcom,cpr-fuse-combo-map, rc=%d\n",
2472 rc);
2473 goto done;
2474 }
2475
2476 for (i = 0; i < num_fuse_combos; i++) {
2477 for (j = 0; j < fuse_count; j++) {
2478 if (tmp[i * row_size + j * 2] > fuse_val[j]
2479 || tmp[i * row_size + j * 2 + 1] < fuse_val[j])
2480 break;
2481 }
2482 if (j == fuse_count) {
2483 vreg->fuse_combo = i;
2484 break;
2485 }
2486 }
2487
2488 if (i >= num_fuse_combos) {
2489 cpr3_err(vreg, "No matching CPR fuse combo found!\n");
2490 WARN_ON(1);
2491 rc = -EINVAL;
2492 goto done;
2493 }
2494
2495done:
2496 kfree(tmp);
2497 return rc;
2498}