CI: build-tools: build all host tools
[openwrt/staging/jow.git] / target / linux / ipq807x / patches-6.1 / 0901-regulator-add-Qualcomm-CPR-regulators.patch
1 From c9df32c057e43e38c8113199e64f7a64f8d341df Mon Sep 17 00:00:00 2001
2 From: Robert Marko <robimarko@gmail.com>
3 Date: Mon, 11 Apr 2022 14:35:36 +0200
4 Subject: [PATCH] regulator: add Qualcomm CPR regulators
5
6 Allow building Qualcomm CPR regulators.
7
8 Signed-off-by: Robert Marko <robimarko@gmail.com>
9 ---
10 drivers/regulator/Kconfig | 33 +
11 drivers/regulator/Makefile | 3 +
12 drivers/regulator/cpr3-npu-regulator.c | 695 +++
13 drivers/regulator/cpr3-regulator.c | 5111 +++++++++++++++++++++++
14 drivers/regulator/cpr3-regulator.h | 1211 ++++++
15 drivers/regulator/cpr3-util.c | 2750 ++++++++++++
16 drivers/regulator/cpr4-apss-regulator.c | 1819 ++++++++
17 include/soc/qcom/socinfo.h | 463 ++
18 8 files changed, 12085 insertions(+)
19 create mode 100644 drivers/regulator/cpr3-npu-regulator.c
20 create mode 100644 drivers/regulator/cpr3-regulator.c
21 create mode 100644 drivers/regulator/cpr3-regulator.h
22 create mode 100644 drivers/regulator/cpr3-util.c
23 create mode 100644 drivers/regulator/cpr4-apss-regulator.c
24 create mode 100644 include/soc/qcom/socinfo.h
25
26 --- a/drivers/regulator/Kconfig
27 +++ b/drivers/regulator/Kconfig
28 @@ -1524,4 +1524,37 @@ config REGULATOR_QCOM_LABIBB
29 boost regulator and IBB can be used as a negative boost regulator
30 for LCD display panel.
31
32 +config REGULATOR_CPR3
33 + bool "QCOM CPR3 regulator core support"
34 + help
35 + This driver supports Core Power Reduction (CPR) version 3 controllers
36 + which are used by some Qualcomm Technologies, Inc. SoCs to
37 + manage important voltage regulators. CPR3 controllers are capable of
38 + monitoring several ring oscillator sensing loops simultaneously. The
39 + CPR3 controller informs software when the silicon conditions require
40 + the supply voltage to be increased or decreased. On certain supply
41 + rails, the CPR3 controller is able to propagate the voltage increase
42 + or decrease requests all the way to the PMIC without software
43 + involvement.
44 +
45 +config REGULATOR_CPR3_NPU
46 + bool "QCOM CPR3 regulator for NPU"
47 + depends on OF && REGULATOR_CPR3
48 + help
49 + This driver supports Qualcomm Technologies, Inc. NPU CPR3
50 + regulator Which will always operate in open loop.
51 +
52 +config REGULATOR_CPR4_APSS
53 + bool "QCOM CPR4 regulator for APSS"
54 + depends on OF && REGULATOR_CPR3
55 + help
56 + This driver supports Qualcomm Technologies, Inc. APSS application
57 + processor specific features including memory array power mux (APM)
58 + switching, one CPR4 thread which monitor the two APSS clusters that
59 + are both powered by a shared supply, hardware closed-loop auto
60 + voltage stepping, voltage adjustments based on online core count,
61 + voltage adjustments based on temperature readings, and voltage
62 + adjustments for performance boost mode. This driver reads both initial
63 + voltage and CPR target quotient values out of hardware fuses.
64 +
65 endif
66 --- a/drivers/regulator/Makefile
67 +++ b/drivers/regulator/Makefile
68 @@ -110,6 +110,9 @@ obj-$(CONFIG_REGULATOR_QCOM_RPMH) += qco
69 obj-$(CONFIG_REGULATOR_QCOM_SMD_RPM) += qcom_smd-regulator.o
70 obj-$(CONFIG_REGULATOR_QCOM_SPMI) += qcom_spmi-regulator.o
71 obj-$(CONFIG_REGULATOR_QCOM_USB_VBUS) += qcom_usb_vbus-regulator.o
72 +obj-$(CONFIG_REGULATOR_CPR3) += cpr3-regulator.o cpr3-util.o
73 +obj-$(CONFIG_REGULATOR_CPR3_NPU) += cpr3-npu-regulator.o
74 +obj-$(CONFIG_REGULATOR_CPR4_APSS) += cpr4-apss-regulator.o
75 obj-$(CONFIG_REGULATOR_PALMAS) += palmas-regulator.o
76 obj-$(CONFIG_REGULATOR_PCA9450) += pca9450-regulator.o
77 obj-$(CONFIG_REGULATOR_PF8X00) += pf8x00-regulator.o
78 --- /dev/null
79 +++ b/drivers/regulator/cpr3-npu-regulator.c
80 @@ -0,0 +1,695 @@
81 +/*
82 + * Copyright (c) 2017, The Linux Foundation. All rights reserved.
83 + *
84 + * Permission to use, copy, modify, and/or distribute this software for any
85 + * purpose with or without fee is hereby granted, provided that the above
86 + * copyright notice and this permission notice appear in all copies.
87 + *
88 + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
89 + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
90 + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
91 + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
92 + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
93 + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
94 + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
95 + */
96 +
97 +#include <linux/err.h>
98 +#include <linux/platform_device.h>
99 +#include <linux/module.h>
100 +#include <linux/of.h>
101 +#include <linux/of_device.h>
102 +#include <linux/slab.h>
103 +#include <linux/thermal.h>
104 +
105 +#include "cpr3-regulator.h"
106 +
107 +#define IPQ807x_NPU_FUSE_CORNERS 2
108 +#define IPQ817x_NPU_FUSE_CORNERS 1
109 +#define IPQ807x_NPU_FUSE_STEP_VOLT 8000
110 +#define IPQ807x_NPU_VOLTAGE_FUSE_SIZE 6
111 +#define IPQ807x_NPU_CPR_CLOCK_RATE 19200000
112 +
113 +#define IPQ807x_NPU_CPR_TCSR_START 6
114 +#define IPQ807x_NPU_CPR_TCSR_END 7
115 +
116 +#define NPU_TSENS 5
117 +
118 +u32 g_valid_npu_fuse_count = IPQ807x_NPU_FUSE_CORNERS;
119 +/**
120 + * struct cpr3_ipq807x_npu_fuses - NPU specific fuse data for IPQ807x
121 + * @init_voltage: Initial (i.e. open-loop) voltage fuse parameter value
122 + * for each fuse corner (raw, not converted to a voltage)
123 + * This struct holds the values for all of the fuses read from memory.
124 + */
125 +struct cpr3_ipq807x_npu_fuses {
126 + u64 init_voltage[IPQ807x_NPU_FUSE_CORNERS];
127 +};
128 +
129 +/*
130 + * Constants which define the name of each fuse corner.
131 + */
132 +enum cpr3_ipq807x_npu_fuse_corner {
133 + CPR3_IPQ807x_NPU_FUSE_CORNER_NOM = 0,
134 + CPR3_IPQ807x_NPU_FUSE_CORNER_TURBO = 1,
135 +};
136 +
137 +static const char * const cpr3_ipq807x_npu_fuse_corner_name[] = {
138 + [CPR3_IPQ807x_NPU_FUSE_CORNER_NOM] = "NOM",
139 + [CPR3_IPQ807x_NPU_FUSE_CORNER_TURBO] = "TURBO",
140 +};
141 +
142 +/*
143 + * IPQ807x NPU fuse parameter locations:
144 + *
145 + * Structs are organized with the following dimensions:
146 + * Outer: 0 to 1 for fuse corners from lowest to highest corner
147 + * Inner: large enough to hold the longest set of parameter segments which
148 + * fully defines a fuse parameter, +1 (for NULL termination).
149 + * Each segment corresponds to a contiguous group of bits from a
150 + * single fuse row. These segments are concatentated together in
151 + * order to form the full fuse parameter value. The segments for
152 + * a given parameter may correspond to different fuse rows.
153 + */
154 +static struct cpr3_fuse_param
155 +ipq807x_npu_init_voltage_param[IPQ807x_NPU_FUSE_CORNERS][2] = {
156 + {{73, 22, 27}, {} },
157 + {{73, 16, 21}, {} },
158 +};
159 +
160 +/*
161 + * Open loop voltage fuse reference voltages in microvolts for IPQ807x
162 + */
163 +static int
164 +ipq807x_npu_fuse_ref_volt [IPQ807x_NPU_FUSE_CORNERS] = {
165 + 912000,
166 + 992000,
167 +};
168 +
169 +/*
170 + * IPQ9574 (Few parameters are changed, remaining are same as IPQ807x)
171 + */
172 +#define IPQ9574_NPU_FUSE_CORNERS 2
173 +#define IPQ9574_NPU_FUSE_STEP_VOLT 10000
174 +#define IPQ9574_NPU_CPR_CLOCK_RATE 24000000
175 +
176 +/*
177 + * fues parameters for IPQ9574
178 + */
179 +static struct cpr3_fuse_param
180 +ipq9574_npu_init_voltage_param[IPQ9574_NPU_FUSE_CORNERS][2] = {
181 + {{105, 12, 17}, {} },
182 + {{105, 6, 11}, {} },
183 +};
184 +
185 +/*
186 + * Open loop voltage fuse reference voltages in microvolts for IPQ9574
187 + */
188 +static int
189 +ipq9574_npu_fuse_ref_volt [IPQ9574_NPU_FUSE_CORNERS] = {
190 + 862500,
191 + 987500,
192 +};
193 +
194 +struct cpr3_controller *g_ctrl;
195 +
196 +void cpr3_npu_temp_notify(int sensor, int temp, int low_notif)
197 +{
198 + u32 prev_sensor_state;
199 +
200 + if (sensor != NPU_TSENS)
201 + return;
202 +
203 + prev_sensor_state = g_ctrl->cur_sensor_state;
204 + if (low_notif)
205 + g_ctrl->cur_sensor_state |= BIT(sensor);
206 + else
207 + g_ctrl->cur_sensor_state &= ~BIT(sensor);
208 +
209 + if (!prev_sensor_state && g_ctrl->cur_sensor_state)
210 + cpr3_handle_temp_open_loop_adjustment(g_ctrl, true);
211 + else if (prev_sensor_state && !g_ctrl->cur_sensor_state)
212 + cpr3_handle_temp_open_loop_adjustment(g_ctrl, false);
213 +}
214 +
215 +/**
216 + * cpr3_ipq807x_npu_read_fuse_data() - load NPU specific fuse parameter values
217 + * @vreg: Pointer to the CPR3 regulator
218 + *
219 + * This function allocates a cpr3_ipq807x_npu_fuses struct, fills it with
220 + * values read out of hardware fuses, and finally copies common fuse values
221 + * into the CPR3 regulator struct.
222 + *
223 + * Return: 0 on success, errno on failure
224 + */
225 +static int cpr3_ipq807x_npu_read_fuse_data(struct cpr3_regulator *vreg)
226 +{
227 + void __iomem *base = vreg->thread->ctrl->fuse_base;
228 + struct cpr3_ipq807x_npu_fuses *fuse;
229 + int i, rc;
230 +
231 + fuse = devm_kzalloc(vreg->thread->ctrl->dev, sizeof(*fuse), GFP_KERNEL);
232 + if (!fuse)
233 + return -ENOMEM;
234 +
235 + for (i = 0; i < g_valid_npu_fuse_count; i++) {
236 + rc = cpr3_read_fuse_param(base,
237 + vreg->cpr3_regulator_data->init_voltage_param[i],
238 + &fuse->init_voltage[i]);
239 + if (rc) {
240 + cpr3_err(vreg, "Unable to read fuse-corner %d initial voltage fuse, rc=%d\n",
241 + i, rc);
242 + return rc;
243 + }
244 + }
245 +
246 + vreg->fuse_corner_count = g_valid_npu_fuse_count;
247 + vreg->platform_fuses = fuse;
248 +
249 + return 0;
250 +}
251 +
252 +/**
253 + * cpr3_npu_parse_corner_data() - parse NPU corner data from device tree
254 + * properties of the CPR3 regulator's device node
255 + * @vreg: Pointer to the CPR3 regulator
256 + *
257 + * Return: 0 on success, errno on failure
258 + */
259 +static int cpr3_npu_parse_corner_data(struct cpr3_regulator *vreg)
260 +{
261 + int rc;
262 +
263 + rc = cpr3_parse_common_corner_data(vreg);
264 + if (rc) {
265 + cpr3_err(vreg, "error reading corner data, rc=%d\n", rc);
266 + return rc;
267 + }
268 +
269 + return rc;
270 +}
271 +
272 +/**
273 + * cpr3_ipq807x_npu_calculate_open_loop_voltages() - calculate the open-loop
274 + * voltage for each corner of a CPR3 regulator
275 + * @vreg: Pointer to the CPR3 regulator
276 + * @temp_correction: Temperature based correction
277 + *
278 + * If open-loop voltage interpolation is allowed in device tree, then
279 + * this function calculates the open-loop voltage for a given corner using
280 + * linear interpolation. This interpolation is performed using the processor
281 + * frequencies of the lower and higher Fmax corners along with their fused
282 + * open-loop voltages.
283 + *
284 + * If open-loop voltage interpolation is not allowed, then this function uses
285 + * the Fmax fused open-loop voltage for all of the corners associated with a
286 + * given fuse corner.
287 + *
288 + * Return: 0 on success, errno on failure
289 + */
290 +static int cpr3_ipq807x_npu_calculate_open_loop_voltages(
291 + struct cpr3_regulator *vreg, bool temp_correction)
292 +{
293 + struct cpr3_ipq807x_npu_fuses *fuse = vreg->platform_fuses;
294 + struct cpr3_controller *ctrl = vreg->thread->ctrl;
295 + int i, j, rc = 0;
296 + u64 freq_low, volt_low, freq_high, volt_high;
297 + int *fuse_volt;
298 + int *fmax_corner;
299 +
300 + fuse_volt = kcalloc(vreg->fuse_corner_count, sizeof(*fuse_volt),
301 + GFP_KERNEL);
302 + fmax_corner = kcalloc(vreg->fuse_corner_count, sizeof(*fmax_corner),
303 + GFP_KERNEL);
304 + if (!fuse_volt || !fmax_corner) {
305 + rc = -ENOMEM;
306 + goto done;
307 + }
308 +
309 + for (i = 0; i < vreg->fuse_corner_count; i++) {
310 + if (ctrl->cpr_global_setting == CPR_DISABLED)
311 + fuse_volt[i] = vreg->cpr3_regulator_data->fuse_ref_volt[i];
312 + else
313 + fuse_volt[i] = cpr3_convert_open_loop_voltage_fuse(
314 + vreg->cpr3_regulator_data->fuse_ref_volt[i],
315 + vreg->cpr3_regulator_data->fuse_step_volt,
316 + fuse->init_voltage[i],
317 + IPQ807x_NPU_VOLTAGE_FUSE_SIZE);
318 +
319 + /* Log fused open-loop voltage values for debugging purposes. */
320 + cpr3_info(vreg, "fused %8s: open-loop=%7d uV\n",
321 + cpr3_ipq807x_npu_fuse_corner_name[i],
322 + fuse_volt[i]);
323 + }
324 +
325 + rc = cpr3_determine_part_type(vreg,
326 + fuse_volt[CPR3_IPQ807x_NPU_FUSE_CORNER_TURBO]);
327 + if (rc) {
328 + cpr3_err(vreg,
329 + "fused part type detection failed failed, rc=%d\n", rc);
330 + goto done;
331 + }
332 +
333 + rc = cpr3_adjust_fused_open_loop_voltages(vreg, fuse_volt);
334 + if (rc) {
335 + cpr3_err(vreg,
336 + "fused open-loop voltage adjustment failed, rc=%d\n",
337 + rc);
338 + goto done;
339 + }
340 + if (temp_correction) {
341 + rc = cpr3_determine_temp_base_open_loop_correction(vreg,
342 + fuse_volt);
343 + if (rc) {
344 + cpr3_err(vreg,
345 + "temp open-loop voltage adj. failed, rc=%d\n",
346 + rc);
347 + goto done;
348 + }
349 + }
350 +
351 + for (i = 1; i < vreg->fuse_corner_count; i++) {
352 + if (fuse_volt[i] < fuse_volt[i - 1]) {
353 + cpr3_info(vreg,
354 + "fuse corner %d voltage=%d uV < fuse corner %d \
355 + voltage=%d uV; overriding: fuse corner %d \
356 + voltage=%d\n",
357 + i, fuse_volt[i], i - 1, fuse_volt[i - 1],
358 + i, fuse_volt[i - 1]);
359 + fuse_volt[i] = fuse_volt[i - 1];
360 + }
361 + }
362 +
363 + /* Determine highest corner mapped to each fuse corner */
364 + j = vreg->fuse_corner_count - 1;
365 + for (i = vreg->corner_count - 1; i >= 0; i--) {
366 + if (vreg->corner[i].cpr_fuse_corner == j) {
367 + fmax_corner[j] = i;
368 + j--;
369 + }
370 + }
371 +
372 + if (j >= 0) {
373 + cpr3_err(vreg, "invalid fuse corner mapping\n");
374 + rc = -EINVAL;
375 + goto done;
376 + }
377 +
378 + /*
379 + * Interpolation is not possible for corners mapped to the lowest fuse
380 + * corner so use the fuse corner value directly.
381 + */
382 + for (i = 0; i <= fmax_corner[0]; i++)
383 + vreg->corner[i].open_loop_volt = fuse_volt[0];
384 +
385 + /* Interpolate voltages for the higher fuse corners. */
386 + for (i = 1; i < vreg->fuse_corner_count; i++) {
387 + freq_low = vreg->corner[fmax_corner[i - 1]].proc_freq;
388 + volt_low = fuse_volt[i - 1];
389 + freq_high = vreg->corner[fmax_corner[i]].proc_freq;
390 + volt_high = fuse_volt[i];
391 +
392 + for (j = fmax_corner[i - 1] + 1; j <= fmax_corner[i]; j++)
393 + vreg->corner[j].open_loop_volt = cpr3_interpolate(
394 + freq_low, volt_low, freq_high, volt_high,
395 + vreg->corner[j].proc_freq);
396 + }
397 +
398 +done:
399 + if (rc == 0) {
400 + cpr3_debug(vreg, "unadjusted per-corner open-loop voltages:\n");
401 + for (i = 0; i < vreg->corner_count; i++)
402 + cpr3_debug(vreg, "open-loop[%2d] = %d uV\n", i,
403 + vreg->corner[i].open_loop_volt);
404 +
405 + rc = cpr3_adjust_open_loop_voltages(vreg);
406 + if (rc)
407 + cpr3_err(vreg,
408 + "open-loop voltage adjustment failed, rc=%d\n",
409 + rc);
410 + }
411 +
412 + kfree(fuse_volt);
413 + kfree(fmax_corner);
414 + return rc;
415 +}
416 +
417 +/**
418 + * cpr3_npu_print_settings() - print out NPU CPR configuration settings into
419 + * the kernel log for debugging purposes
420 + * @vreg: Pointer to the CPR3 regulator
421 + */
422 +static void cpr3_npu_print_settings(struct cpr3_regulator *vreg)
423 +{
424 + struct cpr3_corner *corner;
425 + int i;
426 +
427 + cpr3_debug(vreg,
428 + "Corner: Frequency (Hz), Fuse Corner, Floor (uV), \
429 + Open-Loop (uV), Ceiling (uV)\n");
430 + for (i = 0; i < vreg->corner_count; i++) {
431 + corner = &vreg->corner[i];
432 + cpr3_debug(vreg, "%3d: %10u, %2d, %7d, %7d, %7d\n",
433 + i, corner->proc_freq, corner->cpr_fuse_corner,
434 + corner->floor_volt, corner->open_loop_volt,
435 + corner->ceiling_volt);
436 + }
437 +
438 + if (vreg->thread->ctrl->apm)
439 + cpr3_debug(vreg, "APM threshold = %d uV, APM adjust = %d uV\n",
440 + vreg->thread->ctrl->apm_threshold_volt,
441 + vreg->thread->ctrl->apm_adj_volt);
442 +}
443 +
444 +/**
445 + * cpr3_ipq807x_npu_calc_temp_based_ol_voltages() - Calculate the open loop
446 + * voltages based on temperature based correction margins
447 + * @vreg: Pointer to the CPR3 regulator
448 + */
449 +
450 +static int
451 +cpr3_ipq807x_npu_calc_temp_based_ol_voltages(struct cpr3_regulator *vreg,
452 + bool temp_correction)
453 +{
454 + int rc, i;
455 +
456 + rc = cpr3_ipq807x_npu_calculate_open_loop_voltages(vreg,
457 + temp_correction);
458 + if (rc) {
459 + cpr3_err(vreg,
460 + "unable to calculate open-loop voltages, rc=%d\n", rc);
461 + return rc;
462 + }
463 +
464 + rc = cpr3_limit_open_loop_voltages(vreg);
465 + if (rc) {
466 + cpr3_err(vreg, "unable to limit open-loop voltages, rc=%d\n",
467 + rc);
468 + return rc;
469 + }
470 +
471 + cpr3_open_loop_voltage_as_ceiling(vreg);
472 +
473 + rc = cpr3_limit_floor_voltages(vreg);
474 + if (rc) {
475 + cpr3_err(vreg, "unable to limit floor voltages, rc=%d\n", rc);
476 + return rc;
477 + }
478 +
479 + for (i = 0; i < vreg->corner_count; i++) {
480 + if (temp_correction)
481 + vreg->corner[i].cold_temp_open_loop_volt =
482 + vreg->corner[i].open_loop_volt;
483 + else
484 + vreg->corner[i].normal_temp_open_loop_volt =
485 + vreg->corner[i].open_loop_volt;
486 + }
487 +
488 + cpr3_npu_print_settings(vreg);
489 +
490 + return rc;
491 +}
492 +
493 +/**
494 + * cpr3_npu_init_thread() - perform steps necessary to initialize the
495 + * configuration data for a CPR3 thread
496 + * @thread: Pointer to the CPR3 thread
497 + *
498 + * Return: 0 on success, errno on failure
499 + */
500 +static int cpr3_npu_init_thread(struct cpr3_thread *thread)
501 +{
502 + int rc;
503 +
504 + rc = cpr3_parse_common_thread_data(thread);
505 + if (rc) {
506 + cpr3_err(thread->ctrl,
507 + "thread %u CPR thread data from DT- failed, rc=%d\n",
508 + thread->thread_id, rc);
509 + return rc;
510 + }
511 +
512 + return 0;
513 +}
514 +
515 +/**
516 + * cpr3_npu_init_regulator() - perform all steps necessary to initialize the
517 + * configuration data for a CPR3 regulator
518 + * @vreg: Pointer to the CPR3 regulator
519 + *
520 + * Return: 0 on success, errno on failure
521 + */
522 +static int cpr3_npu_init_regulator(struct cpr3_regulator *vreg)
523 +{
524 + struct cpr3_ipq807x_npu_fuses *fuse;
525 + int rc, cold_temp = 0;
526 + bool can_adj_cold_temp = cpr3_can_adjust_cold_temp(vreg);
527 +
528 + rc = cpr3_ipq807x_npu_read_fuse_data(vreg);
529 + if (rc) {
530 + cpr3_err(vreg, "unable to read CPR fuse data, rc=%d\n", rc);
531 + return rc;
532 + }
533 +
534 + fuse = vreg->platform_fuses;
535 +
536 + rc = cpr3_npu_parse_corner_data(vreg);
537 + if (rc) {
538 + cpr3_err(vreg,
539 + "Cannot read CPR corner data from DT, rc=%d\n", rc);
540 + return rc;
541 + }
542 +
543 + rc = cpr3_mem_acc_init(vreg);
544 + if (rc) {
545 + if (rc != -EPROBE_DEFER)
546 + cpr3_err(vreg,
547 + "Cannot initialize mem-acc regulator settings, rc=%d\n",
548 + rc);
549 + return rc;
550 + }
551 +
552 + if (can_adj_cold_temp) {
553 + rc = cpr3_ipq807x_npu_calc_temp_based_ol_voltages(vreg, true);
554 + if (rc) {
555 + cpr3_err(vreg,
556 + "unable to calculate open-loop voltages, rc=%d\n", rc);
557 + return rc;
558 + }
559 + }
560 +
561 + rc = cpr3_ipq807x_npu_calc_temp_based_ol_voltages(vreg, false);
562 + if (rc) {
563 + cpr3_err(vreg,
564 + "unable to calculate open-loop voltages, rc=%d\n", rc);
565 + return rc;
566 + }
567 +
568 + if (can_adj_cold_temp) {
569 + cpr3_info(vreg,
570 + "Normal and Cold condition init done. Default to normal.\n");
571 +
572 + rc = cpr3_get_cold_temp_threshold(vreg, &cold_temp);
573 + if (rc) {
574 + cpr3_err(vreg,
575 + "Get cold temperature threshold failed, rc=%d\n", rc);
576 + return rc;
577 + }
578 + register_low_temp_notif(NPU_TSENS, cold_temp,
579 + cpr3_npu_temp_notify);
580 + }
581 +
582 + return rc;
583 +}
584 +
585 +/**
586 + * cpr3_npu_init_controller() - perform NPU CPR3 controller specific
587 + * initializations
588 + * @ctrl: Pointer to the CPR3 controller
589 + *
590 + * Return: 0 on success, errno on failure
591 + */
592 +static int cpr3_npu_init_controller(struct cpr3_controller *ctrl)
593 +{
594 + int rc;
595 +
596 + rc = cpr3_parse_open_loop_common_ctrl_data(ctrl);
597 + if (rc) {
598 + if (rc != -EPROBE_DEFER)
599 + cpr3_err(ctrl, "unable to parse common controller data, rc=%d\n",
600 + rc);
601 + return rc;
602 + }
603 +
604 + ctrl->ctrl_type = CPR_CTRL_TYPE_CPR3;
605 + ctrl->supports_hw_closed_loop = false;
606 +
607 + return 0;
608 +}
609 +
610 +static const struct cpr3_reg_data ipq807x_cpr_npu = {
611 + .cpr_valid_fuse_count = IPQ807x_NPU_FUSE_CORNERS,
612 + .init_voltage_param = ipq807x_npu_init_voltage_param,
613 + .fuse_ref_volt = ipq807x_npu_fuse_ref_volt,
614 + .fuse_step_volt = IPQ807x_NPU_FUSE_STEP_VOLT,
615 + .cpr_clk_rate = IPQ807x_NPU_CPR_CLOCK_RATE,
616 +};
617 +
618 +static const struct cpr3_reg_data ipq817x_cpr_npu = {
619 + .cpr_valid_fuse_count = IPQ817x_NPU_FUSE_CORNERS,
620 + .init_voltage_param = ipq807x_npu_init_voltage_param,
621 + .fuse_ref_volt = ipq807x_npu_fuse_ref_volt,
622 + .fuse_step_volt = IPQ807x_NPU_FUSE_STEP_VOLT,
623 + .cpr_clk_rate = IPQ807x_NPU_CPR_CLOCK_RATE,
624 +};
625 +
626 +static const struct cpr3_reg_data ipq9574_cpr_npu = {
627 + .cpr_valid_fuse_count = IPQ9574_NPU_FUSE_CORNERS,
628 + .init_voltage_param = ipq9574_npu_init_voltage_param,
629 + .fuse_ref_volt = ipq9574_npu_fuse_ref_volt,
630 + .fuse_step_volt = IPQ9574_NPU_FUSE_STEP_VOLT,
631 + .cpr_clk_rate = IPQ9574_NPU_CPR_CLOCK_RATE,
632 +};
633 +
634 +static struct of_device_id cpr3_regulator_match_table[] = {
635 + {
636 + .compatible = "qcom,cpr3-ipq807x-npu-regulator",
637 + .data = &ipq807x_cpr_npu
638 + },
639 + {
640 + .compatible = "qcom,cpr3-ipq817x-npu-regulator",
641 + .data = &ipq817x_cpr_npu
642 + },
643 + {
644 + .compatible = "qcom,cpr3-ipq9574-npu-regulator",
645 + .data = &ipq9574_cpr_npu
646 + },
647 + {}
648 +};
649 +
650 +static int cpr3_npu_regulator_probe(struct platform_device *pdev)
651 +{
652 + struct device *dev = &pdev->dev;
653 + struct cpr3_controller *ctrl;
654 + int i, rc;
655 + const struct of_device_id *match;
656 + struct cpr3_reg_data *cpr_data;
657 +
658 + if (!dev->of_node) {
659 + dev_err(dev, "Device tree node is missing\n");
660 + return -EINVAL;
661 + }
662 +
663 + ctrl = devm_kzalloc(dev, sizeof(*ctrl), GFP_KERNEL);
664 + if (!ctrl)
665 + return -ENOMEM;
666 + g_ctrl = ctrl;
667 +
668 + match = of_match_device(cpr3_regulator_match_table, &pdev->dev);
669 + if (!match)
670 + return -ENODEV;
671 +
672 + cpr_data = (struct cpr3_reg_data *)match->data;
673 + g_valid_npu_fuse_count = cpr_data->cpr_valid_fuse_count;
674 + dev_info(dev, "NPU CPR valid fuse count: %d\n", g_valid_npu_fuse_count);
675 + ctrl->cpr_clock_rate = cpr_data->cpr_clk_rate;
676 +
677 + ctrl->dev = dev;
678 + /* Set to false later if anything precludes CPR operation. */
679 + ctrl->cpr_allowed_hw = true;
680 +
681 + rc = of_property_read_string(dev->of_node, "qcom,cpr-ctrl-name",
682 + &ctrl->name);
683 + if (rc) {
684 + cpr3_err(ctrl, "unable to read qcom,cpr-ctrl-name, rc=%d\n",
685 + rc);
686 + return rc;
687 + }
688 +
689 + rc = cpr3_map_fuse_base(ctrl, pdev);
690 + if (rc) {
691 + cpr3_err(ctrl, "could not map fuse base address\n");
692 + return rc;
693 + }
694 +
695 + rc = cpr3_read_tcsr_setting(ctrl, pdev, IPQ807x_NPU_CPR_TCSR_START,
696 + IPQ807x_NPU_CPR_TCSR_END);
697 + if (rc) {
698 + cpr3_err(ctrl, "could not read CPR tcsr rsetting\n");
699 + return rc;
700 + }
701 +
702 + rc = cpr3_allocate_threads(ctrl, 0, 0);
703 + if (rc) {
704 + cpr3_err(ctrl, "failed to allocate CPR thread array, rc=%d\n",
705 + rc);
706 + return rc;
707 + }
708 +
709 + if (ctrl->thread_count != 1) {
710 + cpr3_err(ctrl, "expected 1 thread but found %d\n",
711 + ctrl->thread_count);
712 + return -EINVAL;
713 + }
714 +
715 + rc = cpr3_npu_init_controller(ctrl);
716 + if (rc) {
717 + if (rc != -EPROBE_DEFER)
718 + cpr3_err(ctrl, "failed to initialize CPR controller parameters, rc=%d\n",
719 + rc);
720 + return rc;
721 + }
722 +
723 + rc = cpr3_npu_init_thread(&ctrl->thread[0]);
724 + if (rc) {
725 + cpr3_err(ctrl, "thread initialization failed, rc=%d\n", rc);
726 + return rc;
727 + }
728 +
729 + for (i = 0; i < ctrl->thread[0].vreg_count; i++) {
730 + ctrl->thread[0].vreg[i].cpr3_regulator_data = cpr_data;
731 + rc = cpr3_npu_init_regulator(&ctrl->thread[0].vreg[i]);
732 + if (rc) {
733 + cpr3_err(&ctrl->thread[0].vreg[i], "regulator initialization failed, rc=%d\n",
734 + rc);
735 + return rc;
736 + }
737 + }
738 +
739 + platform_set_drvdata(pdev, ctrl);
740 +
741 + return cpr3_open_loop_regulator_register(pdev, ctrl);
742 +}
743 +
744 +static int cpr3_npu_regulator_remove(struct platform_device *pdev)
745 +{
746 + struct cpr3_controller *ctrl = platform_get_drvdata(pdev);
747 +
748 + return cpr3_open_loop_regulator_unregister(ctrl);
749 +}
750 +
751 +static struct platform_driver cpr3_npu_regulator_driver = {
752 + .driver = {
753 + .name = "qcom,cpr3-npu-regulator",
754 + .of_match_table = cpr3_regulator_match_table,
755 + .owner = THIS_MODULE,
756 + },
757 + .probe = cpr3_npu_regulator_probe,
758 + .remove = cpr3_npu_regulator_remove,
759 +};
760 +
761 +static int cpr3_regulator_init(void)
762 +{
763 + return platform_driver_register(&cpr3_npu_regulator_driver);
764 +}
765 +arch_initcall(cpr3_regulator_init);
766 +
767 +static void cpr3_regulator_exit(void)
768 +{
769 + platform_driver_unregister(&cpr3_npu_regulator_driver);
770 +}
771 +module_exit(cpr3_regulator_exit);
772 +
773 +MODULE_DESCRIPTION("QCOM CPR3 NPU regulator driver");
774 +MODULE_LICENSE("Dual BSD/GPLv2");
775 +MODULE_ALIAS("platform:npu-ipq807x");
776 --- /dev/null
777 +++ b/drivers/regulator/cpr3-regulator.c
778 @@ -0,0 +1,5111 @@
779 +/*
780 + * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
781 + *
782 + * This program is free software; you can redistribute it and/or modify
783 + * it under the terms of the GNU General Public License version 2 and
784 + * only version 2 as published by the Free Software Foundation.
785 + *
786 + * This program is distributed in the hope that it will be useful,
787 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
788 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
789 + * GNU General Public License for more details.
790 + */
791 +
792 +#define pr_fmt(fmt) "%s: " fmt, __func__
793 +
794 +#include <linux/bitops.h>
795 +#include <linux/debugfs.h>
796 +#include <linux/delay.h>
797 +#include <linux/err.h>
798 +#include <linux/init.h>
799 +#include <linux/interrupt.h>
800 +#include <linux/io.h>
801 +#include <linux/kernel.h>
802 +#include <linux/ktime.h>
803 +#include <linux/list.h>
804 +#include <linux/module.h>
805 +#include <linux/of.h>
806 +#include <linux/of_device.h>
807 +#include <linux/platform_device.h>
808 +#include <linux/pm_opp.h>
809 +#include <linux/slab.h>
810 +#include <linux/sort.h>
811 +#include <linux/string.h>
812 +#include <linux/uaccess.h>
813 +#include <linux/regulator/driver.h>
814 +#include <linux/regulator/machine.h>
815 +#include <linux/regulator/of_regulator.h>
816 +#include <linux/panic_notifier.h>
817 +
818 +#include "cpr3-regulator.h"
819 +
820 +#define CPR3_REGULATOR_CORNER_INVALID (-1)
821 +#define CPR3_RO_MASK GENMASK(CPR3_RO_COUNT - 1, 0)
822 +
823 +/* CPR3 registers */
824 +#define CPR3_REG_CPR_CTL 0x4
825 +#define CPR3_CPR_CTL_LOOP_EN_MASK BIT(0)
826 +#define CPR3_CPR_CTL_LOOP_ENABLE BIT(0)
827 +#define CPR3_CPR_CTL_LOOP_DISABLE 0
828 +#define CPR3_CPR_CTL_IDLE_CLOCKS_MASK GENMASK(5, 1)
829 +#define CPR3_CPR_CTL_IDLE_CLOCKS_SHIFT 1
830 +#define CPR3_CPR_CTL_COUNT_MODE_MASK GENMASK(7, 6)
831 +#define CPR3_CPR_CTL_COUNT_MODE_SHIFT 6
832 +#define CPR3_CPR_CTL_COUNT_MODE_ALL_AT_ONCE_MIN 0
833 +#define CPR3_CPR_CTL_COUNT_MODE_ALL_AT_ONCE_MAX 1
834 +#define CPR3_CPR_CTL_COUNT_MODE_STAGGERED 2
835 +#define CPR3_CPR_CTL_COUNT_MODE_ALL_AT_ONCE_AGE 3
836 +#define CPR3_CPR_CTL_COUNT_REPEAT_MASK GENMASK(31, 9)
837 +#define CPR3_CPR_CTL_COUNT_REPEAT_SHIFT 9
838 +
839 +#define CPR3_REG_CPR_STATUS 0x8
840 +#define CPR3_CPR_STATUS_BUSY_MASK BIT(0)
841 +#define CPR3_CPR_STATUS_AGING_MEASUREMENT_MASK BIT(1)
842 +
843 +/*
844 + * This register is not present on controllers that support HW closed-loop
845 + * except CPR4 APSS controller.
846 + */
847 +#define CPR3_REG_CPR_TIMER_AUTO_CONT 0xC
848 +
849 +#define CPR3_REG_CPR_STEP_QUOT 0x14
850 +#define CPR3_CPR_STEP_QUOT_MIN_MASK GENMASK(5, 0)
851 +#define CPR3_CPR_STEP_QUOT_MIN_SHIFT 0
852 +#define CPR3_CPR_STEP_QUOT_MAX_MASK GENMASK(11, 6)
853 +#define CPR3_CPR_STEP_QUOT_MAX_SHIFT 6
854 +
855 +#define CPR3_REG_GCNT(ro) (0xA0 + 0x4 * (ro))
856 +
857 +#define CPR3_REG_SENSOR_BYPASS_WRITE(sensor) (0xE0 + 0x4 * ((sensor) / 32))
858 +#define CPR3_REG_SENSOR_BYPASS_WRITE_BANK(bank) (0xE0 + 0x4 * (bank))
859 +
860 +#define CPR3_REG_SENSOR_MASK_WRITE(sensor) (0x120 + 0x4 * ((sensor) / 32))
861 +#define CPR3_REG_SENSOR_MASK_WRITE_BANK(bank) (0x120 + 0x4 * (bank))
862 +#define CPR3_REG_SENSOR_MASK_READ(sensor) (0x140 + 0x4 * ((sensor) / 32))
863 +
864 +#define CPR3_REG_SENSOR_OWNER(sensor) (0x200 + 0x4 * (sensor))
865 +
866 +#define CPR3_REG_CONT_CMD 0x800
867 +#define CPR3_CONT_CMD_ACK 0x1
868 +#define CPR3_CONT_CMD_NACK 0x0
869 +
870 +#define CPR3_REG_THRESH(thread) (0x808 + 0x440 * (thread))
871 +#define CPR3_THRESH_CONS_DOWN_MASK GENMASK(3, 0)
872 +#define CPR3_THRESH_CONS_DOWN_SHIFT 0
873 +#define CPR3_THRESH_CONS_UP_MASK GENMASK(7, 4)
874 +#define CPR3_THRESH_CONS_UP_SHIFT 4
875 +#define CPR3_THRESH_DOWN_THRESH_MASK GENMASK(12, 8)
876 +#define CPR3_THRESH_DOWN_THRESH_SHIFT 8
877 +#define CPR3_THRESH_UP_THRESH_MASK GENMASK(17, 13)
878 +#define CPR3_THRESH_UP_THRESH_SHIFT 13
879 +
880 +#define CPR3_REG_RO_MASK(thread) (0x80C + 0x440 * (thread))
881 +
882 +#define CPR3_REG_RESULT0(thread) (0x810 + 0x440 * (thread))
883 +#define CPR3_RESULT0_BUSY_MASK BIT(0)
884 +#define CPR3_RESULT0_STEP_DN_MASK BIT(1)
885 +#define CPR3_RESULT0_STEP_UP_MASK BIT(2)
886 +#define CPR3_RESULT0_ERROR_STEPS_MASK GENMASK(7, 3)
887 +#define CPR3_RESULT0_ERROR_STEPS_SHIFT 3
888 +#define CPR3_RESULT0_ERROR_MASK GENMASK(19, 8)
889 +#define CPR3_RESULT0_ERROR_SHIFT 8
890 +#define CPR3_RESULT0_NEGATIVE_MASK BIT(20)
891 +
892 +#define CPR3_REG_RESULT1(thread) (0x814 + 0x440 * (thread))
893 +#define CPR3_RESULT1_QUOT_MIN_MASK GENMASK(11, 0)
894 +#define CPR3_RESULT1_QUOT_MIN_SHIFT 0
895 +#define CPR3_RESULT1_QUOT_MAX_MASK GENMASK(23, 12)
896 +#define CPR3_RESULT1_QUOT_MAX_SHIFT 12
897 +#define CPR3_RESULT1_RO_MIN_MASK GENMASK(27, 24)
898 +#define CPR3_RESULT1_RO_MIN_SHIFT 24
899 +#define CPR3_RESULT1_RO_MAX_MASK GENMASK(31, 28)
900 +#define CPR3_RESULT1_RO_MAX_SHIFT 28
901 +
902 +#define CPR3_REG_RESULT2(thread) (0x818 + 0x440 * (thread))
903 +#define CPR3_RESULT2_STEP_QUOT_MIN_MASK GENMASK(5, 0)
904 +#define CPR3_RESULT2_STEP_QUOT_MIN_SHIFT 0
905 +#define CPR3_RESULT2_STEP_QUOT_MAX_MASK GENMASK(11, 6)
906 +#define CPR3_RESULT2_STEP_QUOT_MAX_SHIFT 6
907 +#define CPR3_RESULT2_SENSOR_MIN_MASK GENMASK(23, 16)
908 +#define CPR3_RESULT2_SENSOR_MIN_SHIFT 16
909 +#define CPR3_RESULT2_SENSOR_MAX_MASK GENMASK(31, 24)
910 +#define CPR3_RESULT2_SENSOR_MAX_SHIFT 24
911 +
912 +#define CPR3_REG_IRQ_EN 0x81C
913 +#define CPR3_REG_IRQ_CLEAR 0x820
914 +#define CPR3_REG_IRQ_STATUS 0x824
915 +#define CPR3_IRQ_UP BIT(3)
916 +#define CPR3_IRQ_MID BIT(2)
917 +#define CPR3_IRQ_DOWN BIT(1)
918 +
919 +#define CPR3_REG_TARGET_QUOT(thread, ro) \
920 + (0x840 + 0x440 * (thread) + 0x4 * (ro))
921 +
922 +/* Registers found only on controllers that support HW closed-loop. */
923 +#define CPR3_REG_PD_THROTTLE 0xE8
924 +#define CPR3_PD_THROTTLE_DISABLE 0x0
925 +
926 +#define CPR3_REG_HW_CLOSED_LOOP 0x3000
927 +#define CPR3_HW_CLOSED_LOOP_ENABLE 0x0
928 +#define CPR3_HW_CLOSED_LOOP_DISABLE 0x1
929 +
930 +#define CPR3_REG_CPR_TIMER_MID_CONT 0x3004
931 +#define CPR3_REG_CPR_TIMER_UP_DN_CONT 0x3008
932 +
933 +#define CPR3_REG_LAST_MEASUREMENT 0x7F8
934 +#define CPR3_LAST_MEASUREMENT_THREAD_DN_SHIFT 0
935 +#define CPR3_LAST_MEASUREMENT_THREAD_UP_SHIFT 4
936 +#define CPR3_LAST_MEASUREMENT_THREAD_DN(thread) \
937 + (BIT(thread) << CPR3_LAST_MEASUREMENT_THREAD_DN_SHIFT)
938 +#define CPR3_LAST_MEASUREMENT_THREAD_UP(thread) \
939 + (BIT(thread) << CPR3_LAST_MEASUREMENT_THREAD_UP_SHIFT)
940 +#define CPR3_LAST_MEASUREMENT_AGGR_DN BIT(8)
941 +#define CPR3_LAST_MEASUREMENT_AGGR_MID BIT(9)
942 +#define CPR3_LAST_MEASUREMENT_AGGR_UP BIT(10)
943 +#define CPR3_LAST_MEASUREMENT_VALID BIT(11)
944 +#define CPR3_LAST_MEASUREMENT_SAW_ERROR BIT(12)
945 +#define CPR3_LAST_MEASUREMENT_PD_BYPASS_MASK GENMASK(23, 16)
946 +#define CPR3_LAST_MEASUREMENT_PD_BYPASS_SHIFT 16
947 +
948 +/* CPR4 controller specific registers and bit definitions */
949 +#define CPR4_REG_CPR_TIMER_CLAMP 0x10
950 +#define CPR4_CPR_TIMER_CLAMP_THREAD_AGGREGATION_EN BIT(27)
951 +
952 +#define CPR4_REG_MISC 0x700
953 +#define CPR4_MISC_MARGIN_TABLE_ROW_SELECT_MASK GENMASK(23, 20)
954 +#define CPR4_MISC_MARGIN_TABLE_ROW_SELECT_SHIFT 20
955 +#define CPR4_MISC_TEMP_SENSOR_ID_START_MASK GENMASK(27, 24)
956 +#define CPR4_MISC_TEMP_SENSOR_ID_START_SHIFT 24
957 +#define CPR4_MISC_TEMP_SENSOR_ID_END_MASK GENMASK(31, 28)
958 +#define CPR4_MISC_TEMP_SENSOR_ID_END_SHIFT 28
959 +
960 +#define CPR4_REG_SAW_ERROR_STEP_LIMIT 0x7A4
961 +#define CPR4_SAW_ERROR_STEP_LIMIT_UP_MASK GENMASK(4, 0)
962 +#define CPR4_SAW_ERROR_STEP_LIMIT_UP_SHIFT 0
963 +#define CPR4_SAW_ERROR_STEP_LIMIT_DN_MASK GENMASK(9, 5)
964 +#define CPR4_SAW_ERROR_STEP_LIMIT_DN_SHIFT 5
965 +
966 +#define CPR4_REG_MARGIN_TEMP_CORE_TIMERS 0x7A8
967 +#define CPR4_MARGIN_TEMP_CORE_TIMERS_SETTLE_VOLTAGE_COUNT_MASK GENMASK(28, 18)
968 +#define CPR4_MARGIN_TEMP_CORE_TIMERS_SETTLE_VOLTAGE_COUNT_SHIFT 18
969 +
970 +#define CPR4_REG_MARGIN_TEMP_CORE(core) (0x7AC + 0x4 * (core))
971 +#define CPR4_MARGIN_TEMP_CORE_ADJ_MASK GENMASK(7, 0)
972 +#define CPR4_MARGIN_TEMP_CORE_ADJ_SHIFT 8
973 +
974 +#define CPR4_REG_MARGIN_TEMP_POINT0N1 0x7F0
975 +#define CPR4_MARGIN_TEMP_POINT0_MASK GENMASK(11, 0)
976 +#define CPR4_MARGIN_TEMP_POINT0_SHIFT 0
977 +#define CPR4_MARGIN_TEMP_POINT1_MASK GENMASK(23, 12)
978 +#define CPR4_MARGIN_TEMP_POINT1_SHIFT 12
979 +#define CPR4_REG_MARGIN_TEMP_POINT2 0x7F4
980 +#define CPR4_MARGIN_TEMP_POINT2_MASK GENMASK(11, 0)
981 +#define CPR4_MARGIN_TEMP_POINT2_SHIFT 0
982 +
983 +#define CPR4_REG_MARGIN_ADJ_CTL 0x7F8
984 +#define CPR4_MARGIN_ADJ_CTL_BOOST_EN BIT(0)
985 +#define CPR4_MARGIN_ADJ_CTL_CORE_ADJ_EN BIT(1)
986 +#define CPR4_MARGIN_ADJ_CTL_TEMP_ADJ_EN BIT(2)
987 +#define CPR4_MARGIN_ADJ_CTL_TIMER_SETTLE_VOLTAGE_EN BIT(3)
988 +#define CPR4_MARGIN_ADJ_CTL_HW_CLOSED_LOOP_EN_MASK BIT(4)
989 +#define CPR4_MARGIN_ADJ_CTL_HW_CLOSED_LOOP_ENABLE BIT(4)
990 +#define CPR4_MARGIN_ADJ_CTL_HW_CLOSED_LOOP_DISABLE 0
991 +#define CPR4_MARGIN_ADJ_CTL_PER_RO_KV_MARGIN_EN BIT(7)
992 +#define CPR4_MARGIN_ADJ_CTL_KV_MARGIN_ADJ_EN BIT(8)
993 +#define CPR4_MARGIN_ADJ_CTL_PMIC_STEP_SIZE_MASK GENMASK(16, 12)
994 +#define CPR4_MARGIN_ADJ_CTL_PMIC_STEP_SIZE_SHIFT 12
995 +#define CPR4_MARGIN_ADJ_CTL_INITIAL_TEMP_BAND_MASK GENMASK(21, 19)
996 +#define CPR4_MARGIN_ADJ_CTL_INITIAL_TEMP_BAND_SHIFT 19
997 +#define CPR4_MARGIN_ADJ_CTL_MAX_NUM_CORES_MASK GENMASK(25, 22)
998 +#define CPR4_MARGIN_ADJ_CTL_MAX_NUM_CORES_SHIFT 22
999 +#define CPR4_MARGIN_ADJ_CTL_KV_MARGIN_ADJ_STEP_QUOT_MASK GENMASK(31, 26)
1000 +#define CPR4_MARGIN_ADJ_CTL_KV_MARGIN_ADJ_STEP_QUOT_SHIFT 26
1001 +
1002 +#define CPR4_REG_CPR_MASK_THREAD(thread) (0x80C + 0x440 * (thread))
1003 +#define CPR4_CPR_MASK_THREAD_DISABLE_THREAD BIT(31)
1004 +#define CPR4_CPR_MASK_THREAD_RO_MASK4THREAD_MASK GENMASK(15, 0)
1005 +
1006 +/*
1007 + * The amount of time to wait for the CPR controller to become idle when
1008 + * performing an aging measurement.
1009 + */
1010 +#define CPR3_AGING_MEASUREMENT_TIMEOUT_NS 5000000
1011 +
1012 +/*
1013 + * The number of individual aging measurements to perform which are then
1014 + * averaged together in order to determine the final aging adjustment value.
1015 + */
1016 +#define CPR3_AGING_MEASUREMENT_ITERATIONS 16
1017 +
1018 +/*
1019 + * Aging measurements for the aged and unaged ring oscillators take place a few
1020 + * microseconds apart. If the vdd-supply voltage fluctuates between the two
1021 + * measurements, then the difference between them will be incorrect. The
1022 + * difference could end up too high or too low. This constant defines the
1023 + * number of lowest and highest measurements to ignore when averaging.
1024 + */
1025 +#define CPR3_AGING_MEASUREMENT_FILTER 3
1026 +
1027 +/*
1028 + * The number of times to attempt the full aging measurement sequence before
1029 + * declaring a measurement failure.
1030 + */
1031 +#define CPR3_AGING_RETRY_COUNT 5
1032 +
1033 +/*
1034 + * The maximum time to wait in microseconds for a CPR register write to
1035 + * complete.
1036 + */
1037 +#define CPR3_REGISTER_WRITE_DELAY_US 200
1038 +
1039 +static DEFINE_MUTEX(cpr3_controller_list_mutex);
1040 +static LIST_HEAD(cpr3_controller_list);
1041 +static struct dentry *cpr3_debugfs_base;
1042 +
1043 +/**
1044 + * cpr3_read() - read four bytes from the memory address specified
1045 + * @ctrl: Pointer to the CPR3 controller
1046 + * @offset: Offset in bytes from the CPR3 controller's base address
1047 + *
1048 + * Return: memory address value
1049 + */
1050 +static inline u32 cpr3_read(struct cpr3_controller *ctrl, u32 offset)
1051 +{
1052 + if (!ctrl->cpr_enabled) {
1053 + cpr3_err(ctrl, "CPR register reads are not possible when CPR clocks are disabled\n");
1054 + return 0;
1055 + }
1056 +
1057 + return readl_relaxed(ctrl->cpr_ctrl_base + offset);
1058 +}
1059 +
1060 +/**
1061 + * cpr3_write() - write four bytes to the memory address specified
1062 + * @ctrl: Pointer to the CPR3 controller
1063 + * @offset: Offset in bytes from the CPR3 controller's base address
1064 + * @value: Value to write to the memory address
1065 + *
1066 + * Return: none
1067 + */
1068 +static inline void cpr3_write(struct cpr3_controller *ctrl, u32 offset,
1069 + u32 value)
1070 +{
1071 + if (!ctrl->cpr_enabled) {
1072 + cpr3_err(ctrl, "CPR register writes are not possible when CPR clocks are disabled\n");
1073 + return;
1074 + }
1075 +
1076 + writel_relaxed(value, ctrl->cpr_ctrl_base + offset);
1077 +}
1078 +
1079 +/**
1080 + * cpr3_masked_write() - perform a read-modify-write sequence so that only
1081 + * masked bits are modified
1082 + * @ctrl: Pointer to the CPR3 controller
1083 + * @offset: Offset in bytes from the CPR3 controller's base address
1084 + * @mask: Mask identifying the bits that should be modified
1085 + * @value: Value to write to the memory address
1086 + *
1087 + * Return: none
1088 + */
1089 +static inline void cpr3_masked_write(struct cpr3_controller *ctrl, u32 offset,
1090 + u32 mask, u32 value)
1091 +{
1092 + u32 reg_val, orig_val;
1093 +
1094 + if (!ctrl->cpr_enabled) {
1095 + cpr3_err(ctrl, "CPR register writes are not possible when CPR clocks are disabled\n");
1096 + return;
1097 + }
1098 +
1099 + reg_val = orig_val = readl_relaxed(ctrl->cpr_ctrl_base + offset);
1100 + reg_val &= ~mask;
1101 + reg_val |= value & mask;
1102 +
1103 + if (reg_val != orig_val)
1104 + writel_relaxed(reg_val, ctrl->cpr_ctrl_base + offset);
1105 +}
1106 +
1107 +/**
1108 + * cpr3_ctrl_loop_enable() - enable the CPR sensing loop for a given controller
1109 + * @ctrl: Pointer to the CPR3 controller
1110 + *
1111 + * Return: none
1112 + */
1113 +static inline void cpr3_ctrl_loop_enable(struct cpr3_controller *ctrl)
1114 +{
1115 + if (ctrl->cpr_enabled && !(ctrl->aggr_corner.sdelta
1116 + && ctrl->aggr_corner.sdelta->allow_boost))
1117 + cpr3_masked_write(ctrl, CPR3_REG_CPR_CTL,
1118 + CPR3_CPR_CTL_LOOP_EN_MASK, CPR3_CPR_CTL_LOOP_ENABLE);
1119 +}
1120 +
1121 +/**
1122 + * cpr3_ctrl_loop_disable() - disable the CPR sensing loop for a given
1123 + * controller
1124 + * @ctrl: Pointer to the CPR3 controller
1125 + *
1126 + * Return: none
1127 + */
1128 +static inline void cpr3_ctrl_loop_disable(struct cpr3_controller *ctrl)
1129 +{
1130 + if (ctrl->cpr_enabled)
1131 + cpr3_masked_write(ctrl, CPR3_REG_CPR_CTL,
1132 + CPR3_CPR_CTL_LOOP_EN_MASK, CPR3_CPR_CTL_LOOP_DISABLE);
1133 +}
1134 +
1135 +/**
1136 + * cpr3_clock_enable() - prepare and enable all clocks used by this CPR3
1137 + * controller
1138 + * @ctrl: Pointer to the CPR3 controller
1139 + *
1140 + * Return: 0 on success, errno on failure
1141 + */
1142 +static int cpr3_clock_enable(struct cpr3_controller *ctrl)
1143 +{
1144 + int rc;
1145 +
1146 + rc = clk_prepare_enable(ctrl->bus_clk);
1147 + if (rc) {
1148 + cpr3_err(ctrl, "failed to enable bus clock, rc=%d\n", rc);
1149 + return rc;
1150 + }
1151 +
1152 + rc = clk_prepare_enable(ctrl->iface_clk);
1153 + if (rc) {
1154 + cpr3_err(ctrl, "failed to enable interface clock, rc=%d\n", rc);
1155 + clk_disable_unprepare(ctrl->bus_clk);
1156 + return rc;
1157 + }
1158 +
1159 + rc = clk_prepare_enable(ctrl->core_clk);
1160 + if (rc) {
1161 + cpr3_err(ctrl, "failed to enable core clock, rc=%d\n", rc);
1162 + clk_disable_unprepare(ctrl->iface_clk);
1163 + clk_disable_unprepare(ctrl->bus_clk);
1164 + return rc;
1165 + }
1166 +
1167 + return 0;
1168 +}
1169 +
1170 +/**
1171 + * cpr3_clock_disable() - disable and unprepare all clocks used by this CPR3
1172 + * controller
1173 + * @ctrl: Pointer to the CPR3 controller
1174 + *
1175 + * Return: none
1176 + */
1177 +static void cpr3_clock_disable(struct cpr3_controller *ctrl)
1178 +{
1179 + clk_disable_unprepare(ctrl->core_clk);
1180 + clk_disable_unprepare(ctrl->iface_clk);
1181 + clk_disable_unprepare(ctrl->bus_clk);
1182 +}
1183 +
1184 +/**
1185 + * cpr3_ctrl_clear_cpr4_config() - clear the CPR4 register configuration
1186 + * programmed for current aggregated corner of a given controller
1187 + * @ctrl: Pointer to the CPR3 controller
1188 + *
1189 + * Return: 0 on success, errno on failure
1190 + */
1191 +static inline int cpr3_ctrl_clear_cpr4_config(struct cpr3_controller *ctrl)
1192 +{
1193 + struct cpr4_sdelta *aggr_sdelta = ctrl->aggr_corner.sdelta;
1194 + bool cpr_enabled = ctrl->cpr_enabled;
1195 + int i, rc = 0;
1196 +
1197 + if (!aggr_sdelta || !(aggr_sdelta->allow_core_count_adj
1198 + || aggr_sdelta->allow_temp_adj || aggr_sdelta->allow_boost))
1199 + /* cpr4 features are not enabled */
1200 + return 0;
1201 +
1202 + /* Ensure that CPR clocks are enabled before writing to registers. */
1203 + if (!cpr_enabled) {
1204 + rc = cpr3_clock_enable(ctrl);
1205 + if (rc) {
1206 + cpr3_err(ctrl, "clock enable failed, rc=%d\n", rc);
1207 + return rc;
1208 + }
1209 + ctrl->cpr_enabled = true;
1210 + }
1211 +
1212 + /*
1213 + * Clear feature enable configuration made for current
1214 + * aggregated corner.
1215 + */
1216 + cpr3_masked_write(ctrl, CPR4_REG_MARGIN_ADJ_CTL,
1217 + CPR4_MARGIN_ADJ_CTL_MAX_NUM_CORES_MASK
1218 + | CPR4_MARGIN_ADJ_CTL_CORE_ADJ_EN
1219 + | CPR4_MARGIN_ADJ_CTL_TEMP_ADJ_EN
1220 + | CPR4_MARGIN_ADJ_CTL_KV_MARGIN_ADJ_EN
1221 + | CPR4_MARGIN_ADJ_CTL_BOOST_EN
1222 + | CPR4_MARGIN_ADJ_CTL_HW_CLOSED_LOOP_EN_MASK, 0);
1223 +
1224 + cpr3_masked_write(ctrl, CPR4_REG_MISC,
1225 + CPR4_MISC_MARGIN_TABLE_ROW_SELECT_MASK,
1226 + 0 << CPR4_MISC_MARGIN_TABLE_ROW_SELECT_SHIFT);
1227 +
1228 + for (i = 0; i <= aggr_sdelta->max_core_count; i++) {
1229 + /* Clear voltage margin adjustments programmed in TEMP_COREi */
1230 + cpr3_write(ctrl, CPR4_REG_MARGIN_TEMP_CORE(i), 0);
1231 + }
1232 +
1233 + /* Turn off CPR clocks if they were off before this function call. */
1234 + if (!cpr_enabled) {
1235 + cpr3_clock_disable(ctrl);
1236 + ctrl->cpr_enabled = false;
1237 + }
1238 +
1239 + return 0;
1240 +}
1241 +
1242 +/**
1243 + * cpr3_closed_loop_enable() - enable logical CPR closed-loop operation
1244 + * @ctrl: Pointer to the CPR3 controller
1245 + *
1246 + * Return: 0 on success, errno on failure
1247 + */
1248 +static int cpr3_closed_loop_enable(struct cpr3_controller *ctrl)
1249 +{
1250 + int rc;
1251 +
1252 + if (!ctrl->cpr_allowed_hw || !ctrl->cpr_allowed_sw) {
1253 + cpr3_err(ctrl, "cannot enable closed-loop CPR operation because it is disallowed\n");
1254 + return -EPERM;
1255 + } else if (ctrl->cpr_enabled) {
1256 + /* Already enabled */
1257 + return 0;
1258 + } else if (ctrl->cpr_suspended) {
1259 + /*
1260 + * CPR must remain disabled as the system is entering suspend.
1261 + */
1262 + return 0;
1263 + }
1264 +
1265 + rc = cpr3_clock_enable(ctrl);
1266 + if (rc) {
1267 + cpr3_err(ctrl, "unable to enable CPR clocks, rc=%d\n", rc);
1268 + return rc;
1269 + }
1270 +
1271 + ctrl->cpr_enabled = true;
1272 + cpr3_debug(ctrl, "CPR closed-loop operation enabled\n");
1273 +
1274 + return 0;
1275 +}
1276 +
1277 +/**
1278 + * cpr3_closed_loop_disable() - disable logical CPR closed-loop operation
1279 + * @ctrl: Pointer to the CPR3 controller
1280 + *
1281 + * Return: 0 on success, errno on failure
1282 + */
1283 +static inline int cpr3_closed_loop_disable(struct cpr3_controller *ctrl)
1284 +{
1285 + if (!ctrl->cpr_enabled) {
1286 + /* Already disabled */
1287 + return 0;
1288 + }
1289 +
1290 + cpr3_clock_disable(ctrl);
1291 + ctrl->cpr_enabled = false;
1292 + cpr3_debug(ctrl, "CPR closed-loop operation disabled\n");
1293 +
1294 + return 0;
1295 +}
1296 +
1297 +/**
1298 + * cpr3_regulator_get_gcnt() - returns the GCNT register value corresponding
1299 + * to the clock rate and sensor time of the CPR3 controller
1300 + * @ctrl: Pointer to the CPR3 controller
1301 + *
1302 + * Return: GCNT value
1303 + */
1304 +static u32 cpr3_regulator_get_gcnt(struct cpr3_controller *ctrl)
1305 +{
1306 + u64 temp;
1307 + unsigned int remainder;
1308 + u32 gcnt;
1309 +
1310 + temp = (u64)ctrl->cpr_clock_rate * (u64)ctrl->sensor_time;
1311 + remainder = do_div(temp, 1000000000);
1312 + if (remainder)
1313 + temp++;
1314 + /*
1315 + * GCNT == 0 corresponds to a single ref clock measurement interval so
1316 + * offset GCNT values by 1.
1317 + */
1318 + gcnt = temp - 1;
1319 +
1320 + return gcnt;
1321 +}
1322 +
1323 +/**
1324 + * cpr3_regulator_init_thread() - performs hardware initialization of CPR
1325 + * thread registers
1326 + * @thread: Pointer to the CPR3 thread
1327 + *
1328 + * CPR interface/bus clocks must be enabled before calling this function.
1329 + *
1330 + * Return: 0 on success, errno on failure
1331 + */
1332 +static int cpr3_regulator_init_thread(struct cpr3_thread *thread)
1333 +{
1334 + u32 reg;
1335 +
1336 + reg = (thread->consecutive_up << CPR3_THRESH_CONS_UP_SHIFT)
1337 + & CPR3_THRESH_CONS_UP_MASK;
1338 + reg |= (thread->consecutive_down << CPR3_THRESH_CONS_DOWN_SHIFT)
1339 + & CPR3_THRESH_CONS_DOWN_MASK;
1340 + reg |= (thread->up_threshold << CPR3_THRESH_UP_THRESH_SHIFT)
1341 + & CPR3_THRESH_UP_THRESH_MASK;
1342 + reg |= (thread->down_threshold << CPR3_THRESH_DOWN_THRESH_SHIFT)
1343 + & CPR3_THRESH_DOWN_THRESH_MASK;
1344 +
1345 + cpr3_write(thread->ctrl, CPR3_REG_THRESH(thread->thread_id), reg);
1346 +
1347 + /*
1348 + * Mask all RO's initially so that unused thread doesn't contribute
1349 + * to closed-loop voltage.
1350 + */
1351 + cpr3_write(thread->ctrl, CPR3_REG_RO_MASK(thread->thread_id),
1352 + CPR3_RO_MASK);
1353 +
1354 + return 0;
1355 +}
1356 +
1357 +/**
1358 + * cpr4_regulator_init_temp_points() - performs hardware initialization of CPR4
1359 + * registers to track tsen temperature data and also specify the
1360 + * temperature band range values to apply different voltage margins
1361 + * @ctrl: Pointer to the CPR3 controller
1362 + *
1363 + * CPR interface/bus clocks must be enabled before calling this function.
1364 + *
1365 + * Return: 0 on success, errno on failure
1366 + */
1367 +static int cpr4_regulator_init_temp_points(struct cpr3_controller *ctrl)
1368 +{
1369 + if (!ctrl->allow_temp_adj)
1370 + return 0;
1371 +
1372 + cpr3_masked_write(ctrl, CPR4_REG_MISC,
1373 + CPR4_MISC_TEMP_SENSOR_ID_START_MASK,
1374 + ctrl->temp_sensor_id_start
1375 + << CPR4_MISC_TEMP_SENSOR_ID_START_SHIFT);
1376 +
1377 + cpr3_masked_write(ctrl, CPR4_REG_MISC,
1378 + CPR4_MISC_TEMP_SENSOR_ID_END_MASK,
1379 + ctrl->temp_sensor_id_end
1380 + << CPR4_MISC_TEMP_SENSOR_ID_END_SHIFT);
1381 +
1382 + cpr3_masked_write(ctrl, CPR4_REG_MARGIN_TEMP_POINT2,
1383 + CPR4_MARGIN_TEMP_POINT2_MASK,
1384 + (ctrl->temp_band_count == 4 ? ctrl->temp_points[2] : 0x7FF)
1385 + << CPR4_MARGIN_TEMP_POINT2_SHIFT);
1386 +
1387 + cpr3_masked_write(ctrl, CPR4_REG_MARGIN_TEMP_POINT0N1,
1388 + CPR4_MARGIN_TEMP_POINT1_MASK,
1389 + (ctrl->temp_band_count >= 3 ? ctrl->temp_points[1] : 0x7FF)
1390 + << CPR4_MARGIN_TEMP_POINT1_SHIFT);
1391 +
1392 + cpr3_masked_write(ctrl, CPR4_REG_MARGIN_TEMP_POINT0N1,
1393 + CPR4_MARGIN_TEMP_POINT0_MASK,
1394 + (ctrl->temp_band_count >= 2 ? ctrl->temp_points[0] : 0x7FF)
1395 + << CPR4_MARGIN_TEMP_POINT0_SHIFT);
1396 + return 0;
1397 +}
1398 +
1399 +/**
1400 + * cpr3_regulator_init_cpr4() - performs hardware initialization at the
1401 + * controller and thread level required for CPR4 operation.
1402 + * @ctrl: Pointer to the CPR3 controller
1403 + *
1404 + * CPR interface/bus clocks must be enabled before calling this function.
1405 + * This function allocates sdelta structures and sdelta tables for aggregated
1406 + * corners of the controller and its threads.
1407 + *
1408 + * Return: 0 on success, errno on failure
1409 + */
1410 +static int cpr3_regulator_init_cpr4(struct cpr3_controller *ctrl)
1411 +{
1412 + struct cpr3_thread *thread;
1413 + struct cpr3_regulator *vreg;
1414 + struct cpr4_sdelta *sdelta;
1415 + int i, j, ctrl_max_core_count, thread_max_core_count, rc = 0;
1416 + bool ctrl_valid_sdelta, thread_valid_sdelta;
1417 + u32 pmic_step_size = 1;
1418 + int thread_id = 0;
1419 + u64 temp;
1420 +
1421 + if (ctrl->supports_hw_closed_loop) {
1422 + if (ctrl->saw_use_unit_mV)
1423 + pmic_step_size = ctrl->step_volt / 1000;
1424 + cpr3_masked_write(ctrl, CPR4_REG_MARGIN_ADJ_CTL,
1425 + CPR4_MARGIN_ADJ_CTL_PMIC_STEP_SIZE_MASK,
1426 + (pmic_step_size
1427 + << CPR4_MARGIN_ADJ_CTL_PMIC_STEP_SIZE_SHIFT));
1428 +
1429 + cpr3_masked_write(ctrl, CPR4_REG_SAW_ERROR_STEP_LIMIT,
1430 + CPR4_SAW_ERROR_STEP_LIMIT_DN_MASK,
1431 + (ctrl->down_error_step_limit
1432 + << CPR4_SAW_ERROR_STEP_LIMIT_DN_SHIFT));
1433 +
1434 + cpr3_masked_write(ctrl, CPR4_REG_SAW_ERROR_STEP_LIMIT,
1435 + CPR4_SAW_ERROR_STEP_LIMIT_UP_MASK,
1436 + (ctrl->up_error_step_limit
1437 + << CPR4_SAW_ERROR_STEP_LIMIT_UP_SHIFT));
1438 +
1439 + /*
1440 + * Enable thread aggregation regardless of which threads are
1441 + * enabled or disabled.
1442 + */
1443 + cpr3_masked_write(ctrl, CPR4_REG_CPR_TIMER_CLAMP,
1444 + CPR4_CPR_TIMER_CLAMP_THREAD_AGGREGATION_EN,
1445 + CPR4_CPR_TIMER_CLAMP_THREAD_AGGREGATION_EN);
1446 +
1447 + switch (ctrl->thread_count) {
1448 + case 0:
1449 + /* Disable both threads */
1450 + cpr3_masked_write(ctrl, CPR4_REG_CPR_MASK_THREAD(0),
1451 + CPR4_CPR_MASK_THREAD_DISABLE_THREAD
1452 + | CPR4_CPR_MASK_THREAD_RO_MASK4THREAD_MASK,
1453 + CPR4_CPR_MASK_THREAD_DISABLE_THREAD
1454 + | CPR4_CPR_MASK_THREAD_RO_MASK4THREAD_MASK);
1455 +
1456 + cpr3_masked_write(ctrl, CPR4_REG_CPR_MASK_THREAD(1),
1457 + CPR4_CPR_MASK_THREAD_DISABLE_THREAD
1458 + | CPR4_CPR_MASK_THREAD_RO_MASK4THREAD_MASK,
1459 + CPR4_CPR_MASK_THREAD_DISABLE_THREAD
1460 + | CPR4_CPR_MASK_THREAD_RO_MASK4THREAD_MASK);
1461 + break;
1462 + case 1:
1463 + /* Disable unused thread */
1464 + thread_id = ctrl->thread[0].thread_id ? 0 : 1;
1465 + cpr3_masked_write(ctrl,
1466 + CPR4_REG_CPR_MASK_THREAD(thread_id),
1467 + CPR4_CPR_MASK_THREAD_DISABLE_THREAD
1468 + | CPR4_CPR_MASK_THREAD_RO_MASK4THREAD_MASK,
1469 + CPR4_CPR_MASK_THREAD_DISABLE_THREAD
1470 + | CPR4_CPR_MASK_THREAD_RO_MASK4THREAD_MASK);
1471 + break;
1472 + }
1473 + }
1474 +
1475 + if (!ctrl->allow_core_count_adj && !ctrl->allow_temp_adj
1476 + && !ctrl->allow_boost) {
1477 + /*
1478 + * Skip below configuration as none of the features
1479 + * are enabled.
1480 + */
1481 + return rc;
1482 + }
1483 +
1484 + if (ctrl->supports_hw_closed_loop)
1485 + cpr3_masked_write(ctrl, CPR4_REG_MARGIN_ADJ_CTL,
1486 + CPR4_MARGIN_ADJ_CTL_TIMER_SETTLE_VOLTAGE_EN,
1487 + CPR4_MARGIN_ADJ_CTL_TIMER_SETTLE_VOLTAGE_EN);
1488 +
1489 + cpr3_masked_write(ctrl, CPR4_REG_MARGIN_ADJ_CTL,
1490 + CPR4_MARGIN_ADJ_CTL_KV_MARGIN_ADJ_STEP_QUOT_MASK,
1491 + ctrl->step_quot_fixed
1492 + << CPR4_MARGIN_ADJ_CTL_KV_MARGIN_ADJ_STEP_QUOT_SHIFT);
1493 +
1494 + cpr3_masked_write(ctrl, CPR4_REG_MARGIN_ADJ_CTL,
1495 + CPR4_MARGIN_ADJ_CTL_PER_RO_KV_MARGIN_EN,
1496 + (ctrl->use_dynamic_step_quot
1497 + ? CPR4_MARGIN_ADJ_CTL_PER_RO_KV_MARGIN_EN : 0));
1498 +
1499 + cpr3_masked_write(ctrl, CPR4_REG_MARGIN_ADJ_CTL,
1500 + CPR4_MARGIN_ADJ_CTL_INITIAL_TEMP_BAND_MASK,
1501 + ctrl->initial_temp_band
1502 + << CPR4_MARGIN_ADJ_CTL_INITIAL_TEMP_BAND_SHIFT);
1503 +
1504 + rc = cpr4_regulator_init_temp_points(ctrl);
1505 + if (rc) {
1506 + cpr3_err(ctrl, "initialize temp points failed, rc=%d\n", rc);
1507 + return rc;
1508 + }
1509 +
1510 + if (ctrl->voltage_settling_time) {
1511 + /*
1512 + * Configure the settling timer used to account for
1513 + * one VDD supply step.
1514 + */
1515 + temp = (u64)ctrl->cpr_clock_rate
1516 + * (u64)ctrl->voltage_settling_time;
1517 + do_div(temp, 1000000000);
1518 + cpr3_masked_write(ctrl, CPR4_REG_MARGIN_TEMP_CORE_TIMERS,
1519 + CPR4_MARGIN_TEMP_CORE_TIMERS_SETTLE_VOLTAGE_COUNT_MASK,
1520 + temp
1521 + << CPR4_MARGIN_TEMP_CORE_TIMERS_SETTLE_VOLTAGE_COUNT_SHIFT);
1522 + }
1523 +
1524 + /*
1525 + * Allocate memory for cpr4_sdelta structure and sdelta table for
1526 + * controller aggregated corner by finding the maximum core count
1527 + * used by any cpr3 regulators.
1528 + */
1529 + ctrl_max_core_count = 1;
1530 + ctrl_valid_sdelta = false;
1531 + for (i = 0; i < ctrl->thread_count; i++) {
1532 + thread = &ctrl->thread[i];
1533 +
1534 + /*
1535 + * Allocate memory for cpr4_sdelta structure and sdelta table
1536 + * for thread aggregated corner by finding the maximum core
1537 + * count used by any cpr3 regulators of the thread.
1538 + */
1539 + thread_max_core_count = 1;
1540 + thread_valid_sdelta = false;
1541 + for (j = 0; j < thread->vreg_count; j++) {
1542 + vreg = &thread->vreg[j];
1543 + thread_max_core_count = max(thread_max_core_count,
1544 + vreg->max_core_count);
1545 + thread_valid_sdelta |= (vreg->allow_core_count_adj
1546 + | vreg->allow_temp_adj
1547 + | vreg->allow_boost);
1548 + }
1549 + if (thread_valid_sdelta) {
1550 + sdelta = devm_kzalloc(ctrl->dev, sizeof(*sdelta),
1551 + GFP_KERNEL);
1552 + if (!sdelta)
1553 + return -ENOMEM;
1554 +
1555 + sdelta->table = devm_kcalloc(ctrl->dev,
1556 + thread_max_core_count
1557 + * ctrl->temp_band_count,
1558 + sizeof(*sdelta->table),
1559 + GFP_KERNEL);
1560 + if (!sdelta->table)
1561 + return -ENOMEM;
1562 +
1563 + sdelta->boost_table = devm_kcalloc(ctrl->dev,
1564 + ctrl->temp_band_count,
1565 + sizeof(*sdelta->boost_table),
1566 + GFP_KERNEL);
1567 + if (!sdelta->boost_table)
1568 + return -ENOMEM;
1569 +
1570 + thread->aggr_corner.sdelta = sdelta;
1571 + }
1572 +
1573 + ctrl_valid_sdelta |= thread_valid_sdelta;
1574 + ctrl_max_core_count = max(ctrl_max_core_count,
1575 + thread_max_core_count);
1576 + }
1577 +
1578 + if (ctrl_valid_sdelta) {
1579 + sdelta = devm_kzalloc(ctrl->dev, sizeof(*sdelta), GFP_KERNEL);
1580 + if (!sdelta)
1581 + return -ENOMEM;
1582 +
1583 + sdelta->table = devm_kcalloc(ctrl->dev, ctrl_max_core_count
1584 + * ctrl->temp_band_count,
1585 + sizeof(*sdelta->table), GFP_KERNEL);
1586 + if (!sdelta->table)
1587 + return -ENOMEM;
1588 +
1589 + sdelta->boost_table = devm_kcalloc(ctrl->dev,
1590 + ctrl->temp_band_count,
1591 + sizeof(*sdelta->boost_table),
1592 + GFP_KERNEL);
1593 + if (!sdelta->boost_table)
1594 + return -ENOMEM;
1595 +
1596 + ctrl->aggr_corner.sdelta = sdelta;
1597 + }
1598 +
1599 + return 0;
1600 +}
1601 +
1602 +/**
1603 + * cpr3_write_temp_core_margin() - programs hardware SDELTA registers with
1604 + * the voltage margin adjustments that need to be applied for
1605 + * different online core-count and temperature bands.
1606 + * @ctrl: Pointer to the CPR3 controller
1607 + * @addr: SDELTA register address
1608 + * @temp_core_adj: Array of voltage margin values for different temperature
1609 + * bands.
1610 + *
1611 + * CPR interface/bus clocks must be enabled before calling this function.
1612 + *
1613 + * Return: none
1614 + */
1615 +static void cpr3_write_temp_core_margin(struct cpr3_controller *ctrl,
1616 + int addr, int *temp_core_adj)
1617 +{
1618 + int i, margin_steps;
1619 + u32 reg = 0;
1620 +
1621 + for (i = 0; i < ctrl->temp_band_count; i++) {
1622 + margin_steps = max(min(temp_core_adj[i], 127), -128);
1623 + reg |= (margin_steps & CPR4_MARGIN_TEMP_CORE_ADJ_MASK) <<
1624 + (i * CPR4_MARGIN_TEMP_CORE_ADJ_SHIFT);
1625 + }
1626 +
1627 + cpr3_write(ctrl, addr, reg);
1628 + cpr3_debug(ctrl, "sdelta offset=0x%08x, val=0x%08x\n", addr, reg);
1629 +}
1630 +
1631 +/**
1632 + * cpr3_controller_program_sdelta() - programs hardware SDELTA registers with
1633 + * the voltage margin adjustments that need to be applied at
1634 + * different online core-count and temperature bands. Also,
1635 + * programs hardware register configuration for per-online-core
1636 + * and per-temperature based adjustments.
1637 + * @ctrl: Pointer to the CPR3 controller
1638 + *
1639 + * CPR interface/bus clocks must be enabled before calling this function.
1640 + *
1641 + * Return: 0 on success, errno on failure
1642 + */
1643 +static int cpr3_controller_program_sdelta(struct cpr3_controller *ctrl)
1644 +{
1645 + struct cpr3_corner *corner = &ctrl->aggr_corner;
1646 + struct cpr4_sdelta *sdelta = corner->sdelta;
1647 + int i, index, max_core_count, rc = 0;
1648 + bool cpr_enabled = ctrl->cpr_enabled;
1649 +
1650 + if (!sdelta)
1651 + /* cpr4_sdelta not defined for current aggregated corner */
1652 + return 0;
1653 +
1654 + if (ctrl->supports_hw_closed_loop && ctrl->cpr_enabled) {
1655 + cpr3_masked_write(ctrl, CPR4_REG_MARGIN_ADJ_CTL,
1656 + CPR4_MARGIN_ADJ_CTL_HW_CLOSED_LOOP_EN_MASK,
1657 + (ctrl->use_hw_closed_loop && !sdelta->allow_boost)
1658 + ? CPR4_MARGIN_ADJ_CTL_HW_CLOSED_LOOP_ENABLE : 0);
1659 + }
1660 +
1661 + if (!sdelta->allow_core_count_adj && !sdelta->allow_temp_adj
1662 + && !sdelta->allow_boost) {
1663 + /*
1664 + * Per-online-core, per-temperature and voltage boost
1665 + * adjustments are disabled for this aggregation corner.
1666 + */
1667 + return 0;
1668 + }
1669 +
1670 + /* Ensure that CPR clocks are enabled before writing to registers. */
1671 + if (!cpr_enabled) {
1672 + rc = cpr3_clock_enable(ctrl);
1673 + if (rc) {
1674 + cpr3_err(ctrl, "clock enable failed, rc=%d\n", rc);
1675 + return rc;
1676 + }
1677 + ctrl->cpr_enabled = true;
1678 + }
1679 +
1680 + max_core_count = sdelta->max_core_count;
1681 +
1682 + if (sdelta->allow_core_count_adj || sdelta->allow_temp_adj) {
1683 + if (sdelta->allow_core_count_adj) {
1684 + /* Program TEMP_CORE0 to same margins as TEMP_CORE1 */
1685 + cpr3_write_temp_core_margin(ctrl,
1686 + CPR4_REG_MARGIN_TEMP_CORE(0),
1687 + &sdelta->table[0]);
1688 + }
1689 +
1690 + for (i = 0; i < max_core_count; i++) {
1691 + index = i * sdelta->temp_band_count;
1692 + /*
1693 + * Program TEMP_COREi with voltage margin adjustments
1694 + * that need to be applied when the number of cores
1695 + * becomes i.
1696 + */
1697 + cpr3_write_temp_core_margin(ctrl,
1698 + CPR4_REG_MARGIN_TEMP_CORE(
1699 + sdelta->allow_core_count_adj
1700 + ? i + 1 : max_core_count),
1701 + &sdelta->table[index]);
1702 + }
1703 + }
1704 +
1705 + if (sdelta->allow_boost) {
1706 + /* Program only boost_num_cores row of SDELTA */
1707 + cpr3_write_temp_core_margin(ctrl,
1708 + CPR4_REG_MARGIN_TEMP_CORE(sdelta->boost_num_cores),
1709 + &sdelta->boost_table[0]);
1710 + }
1711 +
1712 + if (!sdelta->allow_core_count_adj && !sdelta->allow_boost) {
1713 + cpr3_masked_write(ctrl, CPR4_REG_MISC,
1714 + CPR4_MISC_MARGIN_TABLE_ROW_SELECT_MASK,
1715 + max_core_count
1716 + << CPR4_MISC_MARGIN_TABLE_ROW_SELECT_SHIFT);
1717 + }
1718 +
1719 + cpr3_masked_write(ctrl, CPR4_REG_MARGIN_ADJ_CTL,
1720 + CPR4_MARGIN_ADJ_CTL_MAX_NUM_CORES_MASK
1721 + | CPR4_MARGIN_ADJ_CTL_CORE_ADJ_EN
1722 + | CPR4_MARGIN_ADJ_CTL_TEMP_ADJ_EN
1723 + | CPR4_MARGIN_ADJ_CTL_KV_MARGIN_ADJ_EN
1724 + | CPR4_MARGIN_ADJ_CTL_BOOST_EN,
1725 + max_core_count << CPR4_MARGIN_ADJ_CTL_MAX_NUM_CORES_SHIFT
1726 + | ((sdelta->allow_core_count_adj || sdelta->allow_boost)
1727 + ? CPR4_MARGIN_ADJ_CTL_CORE_ADJ_EN : 0)
1728 + | ((sdelta->allow_temp_adj && ctrl->supports_hw_closed_loop)
1729 + ? CPR4_MARGIN_ADJ_CTL_TEMP_ADJ_EN : 0)
1730 + | (((ctrl->use_hw_closed_loop && !sdelta->allow_boost)
1731 + || !ctrl->supports_hw_closed_loop)
1732 + ? CPR4_MARGIN_ADJ_CTL_KV_MARGIN_ADJ_EN : 0)
1733 + | (sdelta->allow_boost
1734 + ? CPR4_MARGIN_ADJ_CTL_BOOST_EN : 0));
1735 +
1736 + /*
1737 + * Ensure that all previous CPR register writes have completed before
1738 + * continuing.
1739 + */
1740 + mb();
1741 +
1742 + /* Turn off CPR clocks if they were off before this function call. */
1743 + if (!cpr_enabled) {
1744 + cpr3_clock_disable(ctrl);
1745 + ctrl->cpr_enabled = false;
1746 + }
1747 +
1748 + return 0;
1749 +}
1750 +
1751 +/**
1752 + * cpr3_regulator_init_ctrl() - performs hardware initialization of CPR
1753 + * controller registers
1754 + * @ctrl: Pointer to the CPR3 controller
1755 + *
1756 + * Return: 0 on success, errno on failure
1757 + */
1758 +static int cpr3_regulator_init_ctrl(struct cpr3_controller *ctrl)
1759 +{
1760 + int i, j, k, m, rc;
1761 + u32 ro_used = 0;
1762 + u32 gcnt, cont_dly, up_down_dly, val;
1763 + u64 temp;
1764 + char *mode;
1765 +
1766 + if (ctrl->core_clk) {
1767 + rc = clk_set_rate(ctrl->core_clk, ctrl->cpr_clock_rate);
1768 + if (rc) {
1769 + cpr3_err(ctrl, "clk_set_rate(core_clk, %u) failed, rc=%d\n",
1770 + ctrl->cpr_clock_rate, rc);
1771 + return rc;
1772 + }
1773 + }
1774 +
1775 + rc = cpr3_clock_enable(ctrl);
1776 + if (rc) {
1777 + cpr3_err(ctrl, "clock enable failed, rc=%d\n", rc);
1778 + return rc;
1779 + }
1780 + ctrl->cpr_enabled = true;
1781 +
1782 + /* Find all RO's used by any corner of any regulator. */
1783 + for (i = 0; i < ctrl->thread_count; i++)
1784 + for (j = 0; j < ctrl->thread[i].vreg_count; j++)
1785 + for (k = 0; k < ctrl->thread[i].vreg[j].corner_count;
1786 + k++)
1787 + for (m = 0; m < CPR3_RO_COUNT; m++)
1788 + if (ctrl->thread[i].vreg[j].corner[k].
1789 + target_quot[m])
1790 + ro_used |= BIT(m);
1791 +
1792 + /* Configure the GCNT of the RO's that will be used */
1793 + gcnt = cpr3_regulator_get_gcnt(ctrl);
1794 + for (i = 0; i < CPR3_RO_COUNT; i++)
1795 + if (ro_used & BIT(i))
1796 + cpr3_write(ctrl, CPR3_REG_GCNT(i), gcnt);
1797 +
1798 + /* Configure the loop delay time */
1799 + temp = (u64)ctrl->cpr_clock_rate * (u64)ctrl->loop_time;
1800 + do_div(temp, 1000000000);
1801 + cont_dly = temp;
1802 + if (ctrl->supports_hw_closed_loop
1803 + && ctrl->ctrl_type == CPR_CTRL_TYPE_CPR3)
1804 + cpr3_write(ctrl, CPR3_REG_CPR_TIMER_MID_CONT, cont_dly);
1805 + else
1806 + cpr3_write(ctrl, CPR3_REG_CPR_TIMER_AUTO_CONT, cont_dly);
1807 +
1808 + if (ctrl->ctrl_type == CPR_CTRL_TYPE_CPR3) {
1809 + temp = (u64)ctrl->cpr_clock_rate *
1810 + (u64)ctrl->up_down_delay_time;
1811 + do_div(temp, 1000000000);
1812 + up_down_dly = temp;
1813 + if (ctrl->supports_hw_closed_loop)
1814 + cpr3_write(ctrl, CPR3_REG_CPR_TIMER_UP_DN_CONT,
1815 + up_down_dly);
1816 + cpr3_debug(ctrl, "up_down_dly=%u, up_down_delay_time=%u ns\n",
1817 + up_down_dly, ctrl->up_down_delay_time);
1818 + }
1819 +
1820 + cpr3_debug(ctrl, "cpr_clock_rate=%u HZ, sensor_time=%u ns, loop_time=%u ns, gcnt=%u, cont_dly=%u\n",
1821 + ctrl->cpr_clock_rate, ctrl->sensor_time, ctrl->loop_time,
1822 + gcnt, cont_dly);
1823 +
1824 + /* Configure CPR sensor operation */
1825 + val = (ctrl->idle_clocks << CPR3_CPR_CTL_IDLE_CLOCKS_SHIFT)
1826 + & CPR3_CPR_CTL_IDLE_CLOCKS_MASK;
1827 + val |= (ctrl->count_mode << CPR3_CPR_CTL_COUNT_MODE_SHIFT)
1828 + & CPR3_CPR_CTL_COUNT_MODE_MASK;
1829 + val |= (ctrl->count_repeat << CPR3_CPR_CTL_COUNT_REPEAT_SHIFT)
1830 + & CPR3_CPR_CTL_COUNT_REPEAT_MASK;
1831 + cpr3_write(ctrl, CPR3_REG_CPR_CTL, val);
1832 +
1833 + cpr3_debug(ctrl, "idle_clocks=%u, count_mode=%u, count_repeat=%u; CPR_CTL=0x%08X\n",
1834 + ctrl->idle_clocks, ctrl->count_mode, ctrl->count_repeat, val);
1835 +
1836 + /* Configure CPR default step quotients */
1837 + val = (ctrl->step_quot_init_min << CPR3_CPR_STEP_QUOT_MIN_SHIFT)
1838 + & CPR3_CPR_STEP_QUOT_MIN_MASK;
1839 + val |= (ctrl->step_quot_init_max << CPR3_CPR_STEP_QUOT_MAX_SHIFT)
1840 + & CPR3_CPR_STEP_QUOT_MAX_MASK;
1841 + cpr3_write(ctrl, CPR3_REG_CPR_STEP_QUOT, val);
1842 +
1843 + cpr3_debug(ctrl, "step_quot_min=%u, step_quot_max=%u; STEP_QUOT=0x%08X\n",
1844 + ctrl->step_quot_init_min, ctrl->step_quot_init_max, val);
1845 +
1846 + /* Configure the CPR sensor ownership */
1847 + for (i = 0; i < ctrl->sensor_count; i++)
1848 + cpr3_write(ctrl, CPR3_REG_SENSOR_OWNER(i),
1849 + ctrl->sensor_owner[i]);
1850 +
1851 + /* Configure per-thread registers */
1852 + for (i = 0; i < ctrl->thread_count; i++) {
1853 + rc = cpr3_regulator_init_thread(&ctrl->thread[i]);
1854 + if (rc) {
1855 + cpr3_err(ctrl, "CPR thread register initialization failed, rc=%d\n",
1856 + rc);
1857 + return rc;
1858 + }
1859 + }
1860 +
1861 + if (ctrl->supports_hw_closed_loop) {
1862 + if (ctrl->ctrl_type == CPR_CTRL_TYPE_CPR4) {
1863 + cpr3_masked_write(ctrl, CPR4_REG_MARGIN_ADJ_CTL,
1864 + CPR4_MARGIN_ADJ_CTL_HW_CLOSED_LOOP_EN_MASK,
1865 + ctrl->use_hw_closed_loop
1866 + ? CPR4_MARGIN_ADJ_CTL_HW_CLOSED_LOOP_ENABLE
1867 + : CPR4_MARGIN_ADJ_CTL_HW_CLOSED_LOOP_DISABLE);
1868 + } else if (ctrl->ctrl_type == CPR_CTRL_TYPE_CPR3) {
1869 + cpr3_write(ctrl, CPR3_REG_HW_CLOSED_LOOP,
1870 + ctrl->use_hw_closed_loop
1871 + ? CPR3_HW_CLOSED_LOOP_ENABLE
1872 + : CPR3_HW_CLOSED_LOOP_DISABLE);
1873 +
1874 + cpr3_debug(ctrl, "PD_THROTTLE=0x%08X\n",
1875 + ctrl->proc_clock_throttle);
1876 + }
1877 +
1878 + if ((ctrl->use_hw_closed_loop ||
1879 + ctrl->ctrl_type == CPR_CTRL_TYPE_CPR4) &&
1880 + ctrl->vdd_limit_regulator) {
1881 + rc = regulator_enable(ctrl->vdd_limit_regulator);
1882 + if (rc) {
1883 + cpr3_err(ctrl, "CPR limit regulator enable failed, rc=%d\n",
1884 + rc);
1885 + return rc;
1886 + }
1887 + }
1888 + }
1889 +
1890 + if (ctrl->ctrl_type == CPR_CTRL_TYPE_CPR4) {
1891 + rc = cpr3_regulator_init_cpr4(ctrl);
1892 + if (rc) {
1893 + cpr3_err(ctrl, "CPR4-specific controller initialization failed, rc=%d\n",
1894 + rc);
1895 + return rc;
1896 + }
1897 + }
1898 +
1899 + /* Ensure that all register writes complete before disabling clocks. */
1900 + wmb();
1901 +
1902 + cpr3_clock_disable(ctrl);
1903 + ctrl->cpr_enabled = false;
1904 +
1905 + if (!ctrl->cpr_allowed_sw || !ctrl->cpr_allowed_hw)
1906 + mode = "open-loop";
1907 + else if (ctrl->supports_hw_closed_loop)
1908 + mode = ctrl->use_hw_closed_loop
1909 + ? "HW closed-loop" : "SW closed-loop";
1910 + else
1911 + mode = "closed-loop";
1912 +
1913 + cpr3_info(ctrl, "Default CPR mode = %s", mode);
1914 +
1915 + return 0;
1916 +}
1917 +
1918 +/**
1919 + * cpr3_regulator_set_target_quot() - configure the target quotient for each
1920 + * RO of the CPR3 thread and set the RO mask
1921 + * @thread: Pointer to the CPR3 thread
1922 + *
1923 + * Return: none
1924 + */
1925 +static void cpr3_regulator_set_target_quot(struct cpr3_thread *thread)
1926 +{
1927 + u32 new_quot, last_quot;
1928 + int i;
1929 +
1930 + if (thread->aggr_corner.ro_mask == CPR3_RO_MASK
1931 + && thread->last_closed_loop_aggr_corner.ro_mask == CPR3_RO_MASK) {
1932 + /* Avoid writing target quotients since all RO's are masked. */
1933 + return;
1934 + } else if (thread->aggr_corner.ro_mask == CPR3_RO_MASK) {
1935 + cpr3_write(thread->ctrl, CPR3_REG_RO_MASK(thread->thread_id),
1936 + CPR3_RO_MASK);
1937 + thread->last_closed_loop_aggr_corner.ro_mask = CPR3_RO_MASK;
1938 + /*
1939 + * Only the RO_MASK register needs to be written since all
1940 + * RO's are masked.
1941 + */
1942 + return;
1943 + } else if (thread->aggr_corner.ro_mask
1944 + != thread->last_closed_loop_aggr_corner.ro_mask) {
1945 + cpr3_write(thread->ctrl, CPR3_REG_RO_MASK(thread->thread_id),
1946 + thread->aggr_corner.ro_mask);
1947 + }
1948 +
1949 + for (i = 0; i < CPR3_RO_COUNT; i++) {
1950 + new_quot = thread->aggr_corner.target_quot[i];
1951 + last_quot = thread->last_closed_loop_aggr_corner.target_quot[i];
1952 + if (new_quot != last_quot)
1953 + cpr3_write(thread->ctrl,
1954 + CPR3_REG_TARGET_QUOT(thread->thread_id, i),
1955 + new_quot);
1956 + }
1957 +
1958 + thread->last_closed_loop_aggr_corner = thread->aggr_corner;
1959 +
1960 + return;
1961 +}
1962 +
1963 +/**
1964 + * cpr3_update_vreg_closed_loop_volt() - update the last known settled
1965 + * closed loop voltage for a CPR3 regulator
1966 + * @vreg: Pointer to the CPR3 regulator
1967 + * @vdd_volt: Last known settled voltage in microvolts for the
1968 + * VDD supply
1969 + * @reg_last_measurement: Value read from the LAST_MEASUREMENT register
1970 + *
1971 + * Return: none
1972 + */
1973 +static void cpr3_update_vreg_closed_loop_volt(struct cpr3_regulator *vreg,
1974 + int vdd_volt, u32 reg_last_measurement)
1975 +{
1976 + bool step_dn, step_up, aggr_step_up, aggr_step_dn, aggr_step_mid;
1977 + bool valid, pd_valid, saw_error;
1978 + struct cpr3_controller *ctrl = vreg->thread->ctrl;
1979 + struct cpr3_corner *corner;
1980 + u32 id;
1981 +
1982 + if (vreg->last_closed_loop_corner == CPR3_REGULATOR_CORNER_INVALID)
1983 + return;
1984 + else
1985 + corner = &vreg->corner[vreg->last_closed_loop_corner];
1986 +
1987 + if (vreg->thread->last_closed_loop_aggr_corner.ro_mask
1988 + == CPR3_RO_MASK || !vreg->aggregated) {
1989 + return;
1990 + } else if (!ctrl->cpr_enabled || !ctrl->last_corner_was_closed_loop) {
1991 + return;
1992 + } else if (ctrl->thread_count == 1
1993 + && vdd_volt >= corner->floor_volt
1994 + && vdd_volt <= corner->ceiling_volt) {
1995 + corner->last_volt = vdd_volt;
1996 + cpr3_debug(vreg, "last_volt updated: last_volt[%d]=%d, ceiling_volt[%d]=%d, floor_volt[%d]=%d\n",
1997 + vreg->last_closed_loop_corner, corner->last_volt,
1998 + vreg->last_closed_loop_corner,
1999 + corner->ceiling_volt,
2000 + vreg->last_closed_loop_corner,
2001 + corner->floor_volt);
2002 + return;
2003 + } else if (!ctrl->supports_hw_closed_loop) {
2004 + return;
2005 + } else if (ctrl->ctrl_type != CPR_CTRL_TYPE_CPR3) {
2006 + corner->last_volt = vdd_volt;
2007 + cpr3_debug(vreg, "last_volt updated: last_volt[%d]=%d, ceiling_volt[%d]=%d, floor_volt[%d]=%d\n",
2008 + vreg->last_closed_loop_corner, corner->last_volt,
2009 + vreg->last_closed_loop_corner,
2010 + corner->ceiling_volt,
2011 + vreg->last_closed_loop_corner,
2012 + corner->floor_volt);
2013 + return;
2014 + }
2015 +
2016 + /* CPR clocks are on and HW closed loop is supported */
2017 + valid = !!(reg_last_measurement & CPR3_LAST_MEASUREMENT_VALID);
2018 + if (!valid) {
2019 + cpr3_debug(vreg, "CPR_LAST_VALID_MEASUREMENT=0x%X valid bit not set\n",
2020 + reg_last_measurement);
2021 + return;
2022 + }
2023 +
2024 + id = vreg->thread->thread_id;
2025 +
2026 + step_dn
2027 + = !!(reg_last_measurement & CPR3_LAST_MEASUREMENT_THREAD_DN(id));
2028 + step_up
2029 + = !!(reg_last_measurement & CPR3_LAST_MEASUREMENT_THREAD_UP(id));
2030 + aggr_step_dn = !!(reg_last_measurement & CPR3_LAST_MEASUREMENT_AGGR_DN);
2031 + aggr_step_mid
2032 + = !!(reg_last_measurement & CPR3_LAST_MEASUREMENT_AGGR_MID);
2033 + aggr_step_up = !!(reg_last_measurement & CPR3_LAST_MEASUREMENT_AGGR_UP);
2034 + saw_error = !!(reg_last_measurement & CPR3_LAST_MEASUREMENT_SAW_ERROR);
2035 + pd_valid
2036 + = !((((reg_last_measurement & CPR3_LAST_MEASUREMENT_PD_BYPASS_MASK)
2037 + >> CPR3_LAST_MEASUREMENT_PD_BYPASS_SHIFT)
2038 + & vreg->pd_bypass_mask) == vreg->pd_bypass_mask);
2039 +
2040 + if (!pd_valid) {
2041 + cpr3_debug(vreg, "CPR_LAST_VALID_MEASUREMENT=0x%X, all power domains bypassed\n",
2042 + reg_last_measurement);
2043 + return;
2044 + } else if (step_dn && step_up) {
2045 + cpr3_err(vreg, "both up and down status bits set, CPR_LAST_VALID_MEASUREMENT=0x%X\n",
2046 + reg_last_measurement);
2047 + return;
2048 + } else if (aggr_step_dn && step_dn && vdd_volt < corner->last_volt
2049 + && vdd_volt >= corner->floor_volt) {
2050 + corner->last_volt = vdd_volt;
2051 + } else if (aggr_step_up && step_up && vdd_volt > corner->last_volt
2052 + && vdd_volt <= corner->ceiling_volt) {
2053 + corner->last_volt = vdd_volt;
2054 + } else if (aggr_step_mid
2055 + && vdd_volt >= corner->floor_volt
2056 + && vdd_volt <= corner->ceiling_volt) {
2057 + corner->last_volt = vdd_volt;
2058 + } else if (saw_error && (vdd_volt == corner->ceiling_volt
2059 + || vdd_volt == corner->floor_volt)) {
2060 + corner->last_volt = vdd_volt;
2061 + } else {
2062 + cpr3_debug(vreg, "last_volt not updated: last_volt[%d]=%d, ceiling_volt[%d]=%d, floor_volt[%d]=%d, vdd_volt=%d, CPR_LAST_VALID_MEASUREMENT=0x%X\n",
2063 + vreg->last_closed_loop_corner, corner->last_volt,
2064 + vreg->last_closed_loop_corner,
2065 + corner->ceiling_volt,
2066 + vreg->last_closed_loop_corner, corner->floor_volt,
2067 + vdd_volt, reg_last_measurement);
2068 + return;
2069 + }
2070 +
2071 + cpr3_debug(vreg, "last_volt updated: last_volt[%d]=%d, ceiling_volt[%d]=%d, floor_volt[%d]=%d, CPR_LAST_VALID_MEASUREMENT=0x%X\n",
2072 + vreg->last_closed_loop_corner, corner->last_volt,
2073 + vreg->last_closed_loop_corner, corner->ceiling_volt,
2074 + vreg->last_closed_loop_corner, corner->floor_volt,
2075 + reg_last_measurement);
2076 +}
2077 +
2078 +/**
2079 + * cpr3_regulator_mem_acc_bhs_used() - determines if mem-acc regulators powered
2080 + * through a BHS are associated with the CPR3 controller or any of
2081 + * the CPR3 regulators it controls.
2082 + * @ctrl: Pointer to the CPR3 controller
2083 + *
2084 + * This function determines if the CPR3 controller or any of its CPR3 regulators
2085 + * need to manage mem-acc regulators that are currently powered through a BHS
2086 + * and whose corner selection is based upon a particular voltage threshold.
2087 + *
2088 + * Return: true or false
2089 + */
2090 +static bool cpr3_regulator_mem_acc_bhs_used(struct cpr3_controller *ctrl)
2091 +{
2092 + struct cpr3_regulator *vreg;
2093 + int i, j;
2094 +
2095 + if (!ctrl->mem_acc_threshold_volt)
2096 + return false;
2097 +
2098 + if (ctrl->mem_acc_regulator)
2099 + return true;
2100 +
2101 + for (i = 0; i < ctrl->thread_count; i++) {
2102 + for (j = 0; j < ctrl->thread[i].vreg_count; j++) {
2103 + vreg = &ctrl->thread[i].vreg[j];
2104 +
2105 + if (vreg->mem_acc_regulator)
2106 + return true;
2107 + }
2108 + }
2109 +
2110 + return false;
2111 +}
2112 +
2113 +/**
2114 + * cpr3_regulator_config_bhs_mem_acc() - configure the mem-acc regulator
2115 + * settings for hardware blocks currently powered through the BHS.
2116 + * @ctrl: Pointer to the CPR3 controller
2117 + * @new_volt: New voltage in microvolts that VDD supply needs to
2118 + * end up at
2119 + * @last_volt: Pointer to the last known voltage in microvolts for the
2120 + * VDD supply
2121 + * @aggr_corner: Pointer to the CPR3 corner which corresponds to the max
2122 + * corner aggregated from all CPR3 threads managed by the
2123 + * CPR3 controller
2124 + *
2125 + * This function programs the mem-acc regulator corners for CPR3 regulators
2126 + * whose LDO regulators are in bypassed state. The function also handles
2127 + * CPR3 controllers which utilize mem-acc regulators that operate independently
2128 + * from the LDO hardware and that must be programmed when the VDD supply
2129 + * crosses a particular voltage threshold.
2130 + *
2131 + * Return: 0 on success, errno on failure. If the VDD supply voltage is
2132 + * modified, last_volt is updated to reflect the new voltage setpoint.
2133 + */
2134 +static int cpr3_regulator_config_bhs_mem_acc(struct cpr3_controller *ctrl,
2135 + int new_volt, int *last_volt,
2136 + struct cpr3_corner *aggr_corner)
2137 +{
2138 + struct cpr3_regulator *vreg;
2139 + int i, j, rc, mem_acc_corn, safe_volt;
2140 + int mem_acc_volt = ctrl->mem_acc_threshold_volt;
2141 + int ref_volt;
2142 +
2143 + if (!cpr3_regulator_mem_acc_bhs_used(ctrl))
2144 + return 0;
2145 +
2146 + ref_volt = ctrl->use_hw_closed_loop ? aggr_corner->floor_volt :
2147 + new_volt;
2148 +
2149 + if (((*last_volt < mem_acc_volt && mem_acc_volt <= ref_volt) ||
2150 + (*last_volt >= mem_acc_volt && mem_acc_volt > ref_volt))) {
2151 + if (ref_volt < *last_volt)
2152 + safe_volt = max(mem_acc_volt, aggr_corner->last_volt);
2153 + else
2154 + safe_volt = max(mem_acc_volt, *last_volt);
2155 +
2156 + rc = regulator_set_voltage(ctrl->vdd_regulator, safe_volt,
2157 + new_volt < *last_volt ?
2158 + ctrl->aggr_corner.ceiling_volt :
2159 + new_volt);
2160 + if (rc) {
2161 + cpr3_err(ctrl, "regulator_set_voltage(vdd) == %d failed, rc=%d\n",
2162 + safe_volt, rc);
2163 + return rc;
2164 + }
2165 +
2166 + *last_volt = safe_volt;
2167 +
2168 + mem_acc_corn = ref_volt < mem_acc_volt ?
2169 + ctrl->mem_acc_corner_map[CPR3_MEM_ACC_LOW_CORNER] :
2170 + ctrl->mem_acc_corner_map[CPR3_MEM_ACC_HIGH_CORNER];
2171 +
2172 + if (ctrl->mem_acc_regulator) {
2173 + rc = regulator_set_voltage(ctrl->mem_acc_regulator,
2174 + mem_acc_corn, mem_acc_corn);
2175 + if (rc) {
2176 + cpr3_err(ctrl, "regulator_set_voltage(mem_acc) == %d failed, rc=%d\n",
2177 + mem_acc_corn, rc);
2178 + return rc;
2179 + }
2180 + }
2181 +
2182 + for (i = 0; i < ctrl->thread_count; i++) {
2183 + for (j = 0; j < ctrl->thread[i].vreg_count; j++) {
2184 + vreg = &ctrl->thread[i].vreg[j];
2185 +
2186 + if (!vreg->mem_acc_regulator)
2187 + continue;
2188 +
2189 + rc = regulator_set_voltage(
2190 + vreg->mem_acc_regulator, mem_acc_corn,
2191 + mem_acc_corn);
2192 + if (rc) {
2193 + cpr3_err(vreg, "regulator_set_voltage(mem_acc) == %d failed, rc=%d\n",
2194 + mem_acc_corn, rc);
2195 + return rc;
2196 + }
2197 + }
2198 + }
2199 + }
2200 +
2201 + return 0;
2202 +}
2203 +
2204 +/**
2205 + * cpr3_regulator_switch_apm_mode() - switch the mode of the APM controller
2206 + * associated with a given CPR3 controller
2207 + * @ctrl: Pointer to the CPR3 controller
2208 + * @new_volt: New voltage in microvolts that VDD supply needs to
2209 + * end up at
2210 + * @last_volt: Pointer to the last known voltage in microvolts for the
2211 + * VDD supply
2212 + * @aggr_corner: Pointer to the CPR3 corner which corresponds to the max
2213 + * corner aggregated from all CPR3 threads managed by the
2214 + * CPR3 controller
2215 + *
2216 + * This function requests a switch of the APM mode while guaranteeing
2217 + * any LDO regulator hardware requirements are satisfied. The function must
2218 + * be called once it is known a new VDD supply setpoint crosses the APM
2219 + * voltage threshold.
2220 + *
2221 + * Return: 0 on success, errno on failure. If the VDD supply voltage is
2222 + * modified, last_volt is updated to reflect the new voltage setpoint.
2223 + */
2224 +static int cpr3_regulator_switch_apm_mode(struct cpr3_controller *ctrl,
2225 + int new_volt, int *last_volt,
2226 + struct cpr3_corner *aggr_corner)
2227 +{
2228 + struct regulator *vdd = ctrl->vdd_regulator;
2229 + int apm_volt = ctrl->apm_threshold_volt;
2230 + int orig_last_volt = *last_volt;
2231 + int rc;
2232 +
2233 + rc = regulator_set_voltage(vdd, apm_volt, apm_volt);
2234 + if (rc) {
2235 + cpr3_err(ctrl, "regulator_set_voltage(vdd) == %d failed, rc=%d\n",
2236 + apm_volt, rc);
2237 + return rc;
2238 + }
2239 +
2240 + *last_volt = apm_volt;
2241 +
2242 + rc = msm_apm_set_supply(ctrl->apm, new_volt >= apm_volt
2243 + ? ctrl->apm_high_supply : ctrl->apm_low_supply);
2244 + if (rc) {
2245 + cpr3_err(ctrl, "APM switch failed, rc=%d\n", rc);
2246 + /* Roll back the voltage. */
2247 + regulator_set_voltage(vdd, orig_last_volt, INT_MAX);
2248 + *last_volt = orig_last_volt;
2249 + return rc;
2250 + }
2251 + return 0;
2252 +}
2253 +
2254 +/**
2255 + * cpr3_regulator_config_voltage_crossings() - configure APM and mem-acc
2256 + * settings depending upon a new VDD supply setpoint
2257 + *
2258 + * @ctrl: Pointer to the CPR3 controller
2259 + * @new_volt: New voltage in microvolts that VDD supply needs to
2260 + * end up at
2261 + * @last_volt: Pointer to the last known voltage in microvolts for the
2262 + * VDD supply
2263 + * @aggr_corner: Pointer to the CPR3 corner which corresponds to the max
2264 + * corner aggregated from all CPR3 threads managed by the
2265 + * CPR3 controller
2266 + *
2267 + * This function handles the APM and mem-acc regulator reconfiguration if
2268 + * the new VDD supply voltage will result in crossing their respective voltage
2269 + * thresholds.
2270 + *
2271 + * Return: 0 on success, errno on failure. If the VDD supply voltage is
2272 + * modified, last_volt is updated to reflect the new voltage setpoint.
2273 + */
2274 +static int cpr3_regulator_config_voltage_crossings(struct cpr3_controller *ctrl,
2275 + int new_volt, int *last_volt,
2276 + struct cpr3_corner *aggr_corner)
2277 +{
2278 + bool apm_crossing = false, mem_acc_crossing = false;
2279 + bool mem_acc_bhs_used;
2280 + int apm_volt = ctrl->apm_threshold_volt;
2281 + int mem_acc_volt = ctrl->mem_acc_threshold_volt;
2282 + int ref_volt, rc;
2283 +
2284 + if (ctrl->apm && apm_volt > 0
2285 + && ((*last_volt < apm_volt && apm_volt <= new_volt)
2286 + || (*last_volt >= apm_volt && apm_volt > new_volt)))
2287 + apm_crossing = true;
2288 +
2289 + mem_acc_bhs_used = cpr3_regulator_mem_acc_bhs_used(ctrl);
2290 +
2291 + ref_volt = ctrl->use_hw_closed_loop ? aggr_corner->floor_volt :
2292 + new_volt;
2293 +
2294 + if (mem_acc_bhs_used &&
2295 + (((*last_volt < mem_acc_volt && mem_acc_volt <= ref_volt) ||
2296 + (*last_volt >= mem_acc_volt && mem_acc_volt > ref_volt))))
2297 + mem_acc_crossing = true;
2298 +
2299 + if (apm_crossing && mem_acc_crossing) {
2300 + if ((new_volt < *last_volt && apm_volt >= mem_acc_volt) ||
2301 + (new_volt >= *last_volt && apm_volt < mem_acc_volt)) {
2302 + rc = cpr3_regulator_switch_apm_mode(ctrl, new_volt,
2303 + last_volt,
2304 + aggr_corner);
2305 + if (rc) {
2306 + cpr3_err(ctrl, "unable to switch APM mode\n");
2307 + return rc;
2308 + }
2309 +
2310 + rc = cpr3_regulator_config_bhs_mem_acc(ctrl, new_volt,
2311 + last_volt, aggr_corner);
2312 + if (rc) {
2313 + cpr3_err(ctrl, "unable to configure BHS mem-acc settings\n");
2314 + return rc;
2315 + }
2316 + } else {
2317 + rc = cpr3_regulator_config_bhs_mem_acc(ctrl, new_volt,
2318 + last_volt, aggr_corner);
2319 + if (rc) {
2320 + cpr3_err(ctrl, "unable to configure BHS mem-acc settings\n");
2321 + return rc;
2322 + }
2323 +
2324 + rc = cpr3_regulator_switch_apm_mode(ctrl, new_volt,
2325 + last_volt,
2326 + aggr_corner);
2327 + if (rc) {
2328 + cpr3_err(ctrl, "unable to switch APM mode\n");
2329 + return rc;
2330 + }
2331 + }
2332 + } else if (apm_crossing) {
2333 + rc = cpr3_regulator_switch_apm_mode(ctrl, new_volt, last_volt,
2334 + aggr_corner);
2335 + if (rc) {
2336 + cpr3_err(ctrl, "unable to switch APM mode\n");
2337 + return rc;
2338 + }
2339 + } else if (mem_acc_crossing) {
2340 + rc = cpr3_regulator_config_bhs_mem_acc(ctrl, new_volt,
2341 + last_volt, aggr_corner);
2342 + if (rc) {
2343 + cpr3_err(ctrl, "unable to configure BHS mem-acc settings\n");
2344 + return rc;
2345 + }
2346 + }
2347 +
2348 + return 0;
2349 +}
2350 +
2351 +/**
2352 + * cpr3_regulator_config_mem_acc() - configure the corner of the mem-acc
2353 + * regulator associated with the CPR3 controller
2354 + * @ctrl: Pointer to the CPR3 controller
2355 + * @aggr_corner: Pointer to the CPR3 corner which corresponds to the max
2356 + * corner aggregated from all CPR3 threads managed by the
2357 + * CPR3 controller
2358 + *
2359 + * Return: 0 on success, errno on failure
2360 + */
2361 +static int cpr3_regulator_config_mem_acc(struct cpr3_controller *ctrl,
2362 + struct cpr3_corner *aggr_corner)
2363 +{
2364 + int rc;
2365 +
2366 + if (ctrl->mem_acc_regulator && aggr_corner->mem_acc_volt) {
2367 + rc = regulator_set_voltage(ctrl->mem_acc_regulator,
2368 + aggr_corner->mem_acc_volt,
2369 + aggr_corner->mem_acc_volt);
2370 + if (rc) {
2371 + cpr3_err(ctrl, "regulator_set_voltage(mem_acc) == %d failed, rc=%d\n",
2372 + aggr_corner->mem_acc_volt, rc);
2373 + return rc;
2374 + }
2375 + }
2376 +
2377 + return 0;
2378 +}
2379 +
2380 +/**
2381 + * cpr3_regulator_scale_vdd_voltage() - scale the CPR controlled VDD supply
2382 + * voltage to the new level while satisfying any other hardware
2383 + * requirements
2384 + * @ctrl: Pointer to the CPR3 controller
2385 + * @new_volt: New voltage in microvolts that VDD supply needs to end
2386 + * up at
2387 + * @last_volt: Last known voltage in microvolts for the VDD supply
2388 + * @aggr_corner: Pointer to the CPR3 corner which corresponds to the max
2389 + * corner aggregated from all CPR3 threads managed by the
2390 + * CPR3 controller
2391 + *
2392 + * This function scales the CPR controlled VDD supply voltage from its
2393 + * current level to the new voltage that is specified. If the supply is
2394 + * configured to use the APM and the APM threshold is crossed as a result of
2395 + * the voltage scaling, then this function also stops at the APM threshold,
2396 + * switches the APM source, and finally sets the final new voltage.
2397 + *
2398 + * Return: 0 on success, errno on failure
2399 + */
2400 +static int cpr3_regulator_scale_vdd_voltage(struct cpr3_controller *ctrl,
2401 + int new_volt, int last_volt,
2402 + struct cpr3_corner *aggr_corner)
2403 +{
2404 + struct regulator *vdd = ctrl->vdd_regulator;
2405 + int rc;
2406 +
2407 + if (new_volt < last_volt) {
2408 + rc = cpr3_regulator_config_mem_acc(ctrl, aggr_corner);
2409 + if (rc)
2410 + return rc;
2411 + } else {
2412 + /* Increasing VDD voltage */
2413 + if (ctrl->system_regulator) {
2414 + rc = regulator_set_voltage(ctrl->system_regulator,
2415 + aggr_corner->system_volt, INT_MAX);
2416 + if (rc) {
2417 + cpr3_err(ctrl, "regulator_set_voltage(system) == %d failed, rc=%d\n",
2418 + aggr_corner->system_volt, rc);
2419 + return rc;
2420 + }
2421 + }
2422 + }
2423 +
2424 + rc = cpr3_regulator_config_voltage_crossings(ctrl, new_volt, &last_volt,
2425 + aggr_corner);
2426 + if (rc) {
2427 + cpr3_err(ctrl, "unable to handle voltage threshold crossing configurations, rc=%d\n",
2428 + rc);
2429 + return rc;
2430 + }
2431 +
2432 + /*
2433 + * Subtract a small amount from the min_uV parameter so that the
2434 + * set voltage request is not dropped by the framework due to being
2435 + * duplicate. This is needed in order to switch from hardware
2436 + * closed-loop to open-loop successfully.
2437 + */
2438 + rc = regulator_set_voltage(vdd, new_volt - (ctrl->cpr_enabled ? 0 : 1),
2439 + aggr_corner->ceiling_volt);
2440 + if (rc) {
2441 + cpr3_err(ctrl, "regulator_set_voltage(vdd) == %d failed, rc=%d\n",
2442 + new_volt, rc);
2443 + return rc;
2444 + }
2445 +
2446 + if (new_volt == last_volt && ctrl->supports_hw_closed_loop
2447 + && ctrl->ctrl_type == CPR_CTRL_TYPE_CPR4) {
2448 + /*
2449 + * CPR4 features enforce voltage reprogramming when the last
2450 + * set voltage and new set voltage are same. This way, we can
2451 + * ensure that SAW PMIC STATUS register is updated with newly
2452 + * programmed voltage.
2453 + */
2454 + rc = regulator_sync_voltage(vdd);
2455 + if (rc) {
2456 + cpr3_err(ctrl, "regulator_sync_voltage(vdd) == %d failed, rc=%d\n",
2457 + new_volt, rc);
2458 + return rc;
2459 + }
2460 + }
2461 +
2462 + if (new_volt >= last_volt) {
2463 + rc = cpr3_regulator_config_mem_acc(ctrl, aggr_corner);
2464 + if (rc)
2465 + return rc;
2466 + } else {
2467 + /* Decreasing VDD voltage */
2468 + if (ctrl->system_regulator) {
2469 + rc = regulator_set_voltage(ctrl->system_regulator,
2470 + aggr_corner->system_volt, INT_MAX);
2471 + if (rc) {
2472 + cpr3_err(ctrl, "regulator_set_voltage(system) == %d failed, rc=%d\n",
2473 + aggr_corner->system_volt, rc);
2474 + return rc;
2475 + }
2476 + }
2477 + }
2478 +
2479 + return 0;
2480 +}
2481 +
2482 +/**
2483 + * cpr3_regulator_get_dynamic_floor_volt() - returns the current dynamic floor
2484 + * voltage based upon static configurations and the state of all
2485 + * power domains during the last CPR measurement
2486 + * @ctrl: Pointer to the CPR3 controller
2487 + * @reg_last_measurement: Value read from the LAST_MEASUREMENT register
2488 + *
2489 + * When using HW closed-loop, the dynamic floor voltage is always returned
2490 + * regardless of the current state of the power domains.
2491 + *
2492 + * Return: dynamic floor voltage in microvolts or 0 if dynamic floor is not
2493 + * currently required
2494 + */
2495 +static int cpr3_regulator_get_dynamic_floor_volt(struct cpr3_controller *ctrl,
2496 + u32 reg_last_measurement)
2497 +{
2498 + int dynamic_floor_volt = 0;
2499 + struct cpr3_regulator *vreg;
2500 + bool valid, pd_valid;
2501 + u32 bypass_bits;
2502 + int i, j;
2503 +
2504 + if (!ctrl->supports_hw_closed_loop)
2505 + return 0;
2506 +
2507 + if (likely(!ctrl->use_hw_closed_loop)) {
2508 + valid = !!(reg_last_measurement & CPR3_LAST_MEASUREMENT_VALID);
2509 + bypass_bits
2510 + = (reg_last_measurement & CPR3_LAST_MEASUREMENT_PD_BYPASS_MASK)
2511 + >> CPR3_LAST_MEASUREMENT_PD_BYPASS_SHIFT;
2512 + } else {
2513 + /*
2514 + * Ensure that the dynamic floor voltage is always used for
2515 + * HW closed-loop since the conditions below cannot be evaluated
2516 + * after each CPR measurement.
2517 + */
2518 + valid = false;
2519 + bypass_bits = 0;
2520 + }
2521 +
2522 + for (i = 0; i < ctrl->thread_count; i++) {
2523 + for (j = 0; j < ctrl->thread[i].vreg_count; j++) {
2524 + vreg = &ctrl->thread[i].vreg[j];
2525 +
2526 + if (!vreg->uses_dynamic_floor)
2527 + continue;
2528 +
2529 + pd_valid = !((bypass_bits & vreg->pd_bypass_mask)
2530 + == vreg->pd_bypass_mask);
2531 +
2532 + if (!valid || !pd_valid)
2533 + dynamic_floor_volt = max(dynamic_floor_volt,
2534 + vreg->corner[
2535 + vreg->dynamic_floor_corner].last_volt);
2536 + }
2537 + }
2538 +
2539 + return dynamic_floor_volt;
2540 +}
2541 +
2542 +/**
2543 + * cpr3_regulator_max_sdelta_diff() - returns the maximum voltage difference in
2544 + * microvolts that can result from different operating conditions
2545 + * for the specified sdelta struct
2546 + * @sdelta: Pointer to the sdelta structure
2547 + * @step_volt: Step size in microvolts between available set
2548 + * points of the VDD supply.
2549 + *
2550 + * Return: voltage difference between the highest and lowest adjustments if
2551 + * sdelta and sdelta->table are valid, else 0.
2552 + */
2553 +static int cpr3_regulator_max_sdelta_diff(const struct cpr4_sdelta *sdelta,
2554 + int step_volt)
2555 +{
2556 + int i, j, index, sdelta_min = INT_MAX, sdelta_max = INT_MIN;
2557 +
2558 + if (!sdelta || !sdelta->table)
2559 + return 0;
2560 +
2561 + for (i = 0; i < sdelta->max_core_count; i++) {
2562 + for (j = 0; j < sdelta->temp_band_count; j++) {
2563 + index = i * sdelta->temp_band_count + j;
2564 + sdelta_min = min(sdelta_min, sdelta->table[index]);
2565 + sdelta_max = max(sdelta_max, sdelta->table[index]);
2566 + }
2567 + }
2568 +
2569 + return (sdelta_max - sdelta_min) * step_volt;
2570 +}
2571 +
2572 +/**
2573 + * cpr3_regulator_aggregate_sdelta() - check open-loop voltages of current
2574 + * aggregated corner and current corner of a given regulator
2575 + * and adjust the sdelta strucuture data of aggregate corner.
2576 + * @aggr_corner: Pointer to accumulated aggregated corner which
2577 + * is both an input and an output
2578 + * @corner: Pointer to the corner to be aggregated with
2579 + * aggr_corner
2580 + * @step_volt: Step size in microvolts between available set
2581 + * points of the VDD supply.
2582 + *
2583 + * Return: none
2584 + */
2585 +static void cpr3_regulator_aggregate_sdelta(
2586 + struct cpr3_corner *aggr_corner,
2587 + const struct cpr3_corner *corner, int step_volt)
2588 +{
2589 + struct cpr4_sdelta *aggr_sdelta, *sdelta;
2590 + int aggr_core_count, core_count, temp_band_count;
2591 + u32 aggr_index, index;
2592 + int i, j, sdelta_size, cap_steps, adjust_sdelta;
2593 +
2594 + aggr_sdelta = aggr_corner->sdelta;
2595 + sdelta = corner->sdelta;
2596 +
2597 + if (aggr_corner->open_loop_volt < corner->open_loop_volt) {
2598 + /*
2599 + * Found the new dominant regulator as its open-loop requirement
2600 + * is higher than previous dominant regulator. Calculate cap
2601 + * voltage to limit the SDELTA values to make sure the runtime
2602 + * (Core-count/temp) adjustments do not violate other
2603 + * regulators' voltage requirements. Use cpr4_sdelta values of
2604 + * new dominant regulator.
2605 + */
2606 + aggr_sdelta->cap_volt = min(aggr_sdelta->cap_volt,
2607 + (corner->open_loop_volt -
2608 + aggr_corner->open_loop_volt));
2609 +
2610 + /* Clear old data in the sdelta table */
2611 + sdelta_size = aggr_sdelta->max_core_count
2612 + * aggr_sdelta->temp_band_count;
2613 +
2614 + if (aggr_sdelta->allow_core_count_adj
2615 + || aggr_sdelta->allow_temp_adj)
2616 + memset(aggr_sdelta->table, 0, sdelta_size
2617 + * sizeof(*aggr_sdelta->table));
2618 +
2619 + if (sdelta->allow_temp_adj || sdelta->allow_core_count_adj) {
2620 + /* Copy new data in sdelta table */
2621 + sdelta_size = sdelta->max_core_count
2622 + * sdelta->temp_band_count;
2623 + if (sdelta->table)
2624 + memcpy(aggr_sdelta->table, sdelta->table,
2625 + sdelta_size * sizeof(*sdelta->table));
2626 + }
2627 +
2628 + if (sdelta->allow_boost) {
2629 + memcpy(aggr_sdelta->boost_table, sdelta->boost_table,
2630 + sdelta->temp_band_count
2631 + * sizeof(*sdelta->boost_table));
2632 + aggr_sdelta->boost_num_cores = sdelta->boost_num_cores;
2633 + } else if (aggr_sdelta->allow_boost) {
2634 + for (i = 0; i < aggr_sdelta->temp_band_count; i++) {
2635 + adjust_sdelta = (corner->open_loop_volt
2636 + - aggr_corner->open_loop_volt)
2637 + / step_volt;
2638 + aggr_sdelta->boost_table[i] += adjust_sdelta;
2639 + aggr_sdelta->boost_table[i]
2640 + = min(aggr_sdelta->boost_table[i], 0);
2641 + }
2642 + }
2643 +
2644 + aggr_corner->open_loop_volt = corner->open_loop_volt;
2645 + aggr_sdelta->allow_temp_adj = sdelta->allow_temp_adj;
2646 + aggr_sdelta->allow_core_count_adj
2647 + = sdelta->allow_core_count_adj;
2648 + aggr_sdelta->max_core_count = sdelta->max_core_count;
2649 + aggr_sdelta->temp_band_count = sdelta->temp_band_count;
2650 + } else if (aggr_corner->open_loop_volt > corner->open_loop_volt) {
2651 + /*
2652 + * Adjust the cap voltage if the open-loop requirement of new
2653 + * regulator is the next highest.
2654 + */
2655 + aggr_sdelta->cap_volt = min(aggr_sdelta->cap_volt,
2656 + (aggr_corner->open_loop_volt
2657 + - corner->open_loop_volt));
2658 +
2659 + if (sdelta->allow_boost) {
2660 + for (i = 0; i < aggr_sdelta->temp_band_count; i++) {
2661 + adjust_sdelta = (aggr_corner->open_loop_volt
2662 + - corner->open_loop_volt)
2663 + / step_volt;
2664 + aggr_sdelta->boost_table[i] =
2665 + sdelta->boost_table[i] + adjust_sdelta;
2666 + aggr_sdelta->boost_table[i]
2667 + = min(aggr_sdelta->boost_table[i], 0);
2668 + }
2669 + aggr_sdelta->boost_num_cores = sdelta->boost_num_cores;
2670 + }
2671 + } else {
2672 + /*
2673 + * Found another dominant regulator with same open-loop
2674 + * requirement. Make cap voltage to '0'. Disable core-count
2675 + * adjustments as we couldn't support for both regulators.
2676 + * Keep enable temp based adjustments if enabled for both
2677 + * regulators and choose mininum margin adjustment values
2678 + * between them.
2679 + */
2680 + aggr_sdelta->cap_volt = 0;
2681 + aggr_sdelta->allow_core_count_adj = false;
2682 +
2683 + if (aggr_sdelta->allow_temp_adj
2684 + && sdelta->allow_temp_adj) {
2685 + aggr_core_count = aggr_sdelta->max_core_count - 1;
2686 + core_count = sdelta->max_core_count - 1;
2687 + temp_band_count = sdelta->temp_band_count;
2688 + for (j = 0; j < temp_band_count; j++) {
2689 + aggr_index = aggr_core_count * temp_band_count
2690 + + j;
2691 + index = core_count * temp_band_count + j;
2692 + aggr_sdelta->table[aggr_index] =
2693 + min(aggr_sdelta->table[aggr_index],
2694 + sdelta->table[index]);
2695 + }
2696 + } else {
2697 + aggr_sdelta->allow_temp_adj = false;
2698 + }
2699 +
2700 + if (sdelta->allow_boost) {
2701 + memcpy(aggr_sdelta->boost_table, sdelta->boost_table,
2702 + sdelta->temp_band_count
2703 + * sizeof(*sdelta->boost_table));
2704 + aggr_sdelta->boost_num_cores = sdelta->boost_num_cores;
2705 + }
2706 + }
2707 +
2708 + /* Keep non-dominant clients boost enable state */
2709 + aggr_sdelta->allow_boost |= sdelta->allow_boost;
2710 + if (aggr_sdelta->allow_boost)
2711 + aggr_sdelta->allow_core_count_adj = false;
2712 +
2713 + if (aggr_sdelta->cap_volt && !(aggr_sdelta->cap_volt == INT_MAX)) {
2714 + core_count = aggr_sdelta->max_core_count;
2715 + temp_band_count = aggr_sdelta->temp_band_count;
2716 + /*
2717 + * Convert cap voltage from uV to PMIC steps and use to limit
2718 + * sdelta margin adjustments.
2719 + */
2720 + cap_steps = aggr_sdelta->cap_volt / step_volt;
2721 + for (i = 0; i < core_count; i++)
2722 + for (j = 0; j < temp_band_count; j++) {
2723 + index = i * temp_band_count + j;
2724 + aggr_sdelta->table[index] =
2725 + min(aggr_sdelta->table[index],
2726 + cap_steps);
2727 + }
2728 + }
2729 +}
2730 +
2731 +/**
2732 + * cpr3_regulator_aggregate_corners() - aggregate two corners together
2733 + * @aggr_corner: Pointer to accumulated aggregated corner which
2734 + * is both an input and an output
2735 + * @corner: Pointer to the corner to be aggregated with
2736 + * aggr_corner
2737 + * @aggr_quot: Flag indicating that target quotients should be
2738 + * aggregated as well.
2739 + * @step_volt: Step size in microvolts between available set
2740 + * points of the VDD supply.
2741 + *
2742 + * Return: none
2743 + */
2744 +static void cpr3_regulator_aggregate_corners(struct cpr3_corner *aggr_corner,
2745 + const struct cpr3_corner *corner, bool aggr_quot,
2746 + int step_volt)
2747 +{
2748 + int i;
2749 +
2750 + aggr_corner->ceiling_volt
2751 + = max(aggr_corner->ceiling_volt, corner->ceiling_volt);
2752 + aggr_corner->floor_volt
2753 + = max(aggr_corner->floor_volt, corner->floor_volt);
2754 + aggr_corner->last_volt
2755 + = max(aggr_corner->last_volt, corner->last_volt);
2756 + aggr_corner->system_volt
2757 + = max(aggr_corner->system_volt, corner->system_volt);
2758 + aggr_corner->mem_acc_volt
2759 + = max(aggr_corner->mem_acc_volt, corner->mem_acc_volt);
2760 + aggr_corner->irq_en |= corner->irq_en;
2761 + aggr_corner->use_open_loop |= corner->use_open_loop;
2762 +
2763 + if (aggr_quot) {
2764 + aggr_corner->ro_mask &= corner->ro_mask;
2765 +
2766 + for (i = 0; i < CPR3_RO_COUNT; i++)
2767 + aggr_corner->target_quot[i]
2768 + = max(aggr_corner->target_quot[i],
2769 + corner->target_quot[i]);
2770 + }
2771 +
2772 + if (aggr_corner->sdelta && corner->sdelta
2773 + && (aggr_corner->sdelta->table
2774 + || aggr_corner->sdelta->boost_table)) {
2775 + cpr3_regulator_aggregate_sdelta(aggr_corner, corner, step_volt);
2776 + } else {
2777 + aggr_corner->open_loop_volt
2778 + = max(aggr_corner->open_loop_volt,
2779 + corner->open_loop_volt);
2780 + }
2781 +}
2782 +
2783 +/**
2784 + * cpr3_regulator_update_ctrl_state() - update the state of the CPR controller
2785 + * to reflect the corners used by all CPR3 regulators as well as
2786 + * the CPR operating mode
2787 + * @ctrl: Pointer to the CPR3 controller
2788 + *
2789 + * This function aggregates the CPR parameters for all CPR3 regulators
2790 + * associated with the VDD supply. Upon success, it sets the aggregated last
2791 + * known good voltage.
2792 + *
2793 + * The VDD supply voltage will not be physically configured unless this
2794 + * condition is met by at least one of the regulators of the controller:
2795 + * regulator->vreg_enabled == true &&
2796 + * regulator->current_corner != CPR3_REGULATOR_CORNER_INVALID
2797 + *
2798 + * CPR registers for the controller and each thread are updated as long as
2799 + * ctrl->cpr_enabled == true.
2800 + *
2801 + * Note, CPR3 controller lock must be held by the caller.
2802 + *
2803 + * Return: 0 on success, errno on failure
2804 + */
2805 +static int _cpr3_regulator_update_ctrl_state(struct cpr3_controller *ctrl)
2806 +{
2807 + struct cpr3_corner aggr_corner = {};
2808 + struct cpr3_thread *thread;
2809 + struct cpr3_regulator *vreg;
2810 + struct cpr4_sdelta *sdelta;
2811 + bool valid = false;
2812 + bool thread_valid;
2813 + int i, j, rc, new_volt, vdd_volt, dynamic_floor_volt, last_corner_volt;
2814 + u32 reg_last_measurement = 0, sdelta_size;
2815 + int *sdelta_table, *boost_table;
2816 +
2817 + last_corner_volt = 0;
2818 + if (ctrl->ctrl_type == CPR_CTRL_TYPE_CPR4) {
2819 + rc = cpr3_ctrl_clear_cpr4_config(ctrl);
2820 + if (rc) {
2821 + cpr3_err(ctrl, "failed to clear CPR4 configuration,rc=%d\n",
2822 + rc);
2823 + return rc;
2824 + }
2825 + }
2826 +
2827 + cpr3_ctrl_loop_disable(ctrl);
2828 +
2829 + vdd_volt = regulator_get_voltage(ctrl->vdd_regulator);
2830 + if (vdd_volt < 0) {
2831 + cpr3_err(ctrl, "regulator_get_voltage(vdd) failed, rc=%d\n",
2832 + vdd_volt);
2833 + return vdd_volt;
2834 + }
2835 +
2836 + if (ctrl->ctrl_type == CPR_CTRL_TYPE_CPR4) {
2837 + /*
2838 + * Save aggregated corner open-loop voltage which was programmed
2839 + * during last corner switch which is used when programming new
2840 + * aggregated corner open-loop voltage.
2841 + */
2842 + last_corner_volt = ctrl->aggr_corner.open_loop_volt;
2843 + }
2844 +
2845 + if (ctrl->cpr_enabled && ctrl->use_hw_closed_loop &&
2846 + ctrl->ctrl_type == CPR_CTRL_TYPE_CPR3)
2847 + reg_last_measurement
2848 + = cpr3_read(ctrl, CPR3_REG_LAST_MEASUREMENT);
2849 +
2850 + aggr_corner.sdelta = ctrl->aggr_corner.sdelta;
2851 + if (aggr_corner.sdelta) {
2852 + sdelta = aggr_corner.sdelta;
2853 + sdelta_table = sdelta->table;
2854 + if (sdelta_table) {
2855 + sdelta_size = sdelta->max_core_count *
2856 + sdelta->temp_band_count;
2857 + memset(sdelta_table, 0, sdelta_size
2858 + * sizeof(*sdelta_table));
2859 + }
2860 +
2861 + boost_table = sdelta->boost_table;
2862 + if (boost_table)
2863 + memset(boost_table, 0, sdelta->temp_band_count
2864 + * sizeof(*boost_table));
2865 +
2866 + memset(sdelta, 0, sizeof(*sdelta));
2867 + sdelta->table = sdelta_table;
2868 + sdelta->cap_volt = INT_MAX;
2869 + sdelta->boost_table = boost_table;
2870 + }
2871 +
2872 + /* Aggregate the requests of all threads */
2873 + for (i = 0; i < ctrl->thread_count; i++) {
2874 + thread = &ctrl->thread[i];
2875 + thread_valid = false;
2876 +
2877 + sdelta = thread->aggr_corner.sdelta;
2878 + if (sdelta) {
2879 + sdelta_table = sdelta->table;
2880 + if (sdelta_table) {
2881 + sdelta_size = sdelta->max_core_count *
2882 + sdelta->temp_band_count;
2883 + memset(sdelta_table, 0, sdelta_size
2884 + * sizeof(*sdelta_table));
2885 + }
2886 +
2887 + boost_table = sdelta->boost_table;
2888 + if (boost_table)
2889 + memset(boost_table, 0, sdelta->temp_band_count
2890 + * sizeof(*boost_table));
2891 +
2892 + memset(sdelta, 0, sizeof(*sdelta));
2893 + sdelta->table = sdelta_table;
2894 + sdelta->cap_volt = INT_MAX;
2895 + sdelta->boost_table = boost_table;
2896 + }
2897 +
2898 + memset(&thread->aggr_corner, 0, sizeof(thread->aggr_corner));
2899 + thread->aggr_corner.sdelta = sdelta;
2900 + thread->aggr_corner.ro_mask = CPR3_RO_MASK;
2901 +
2902 + for (j = 0; j < thread->vreg_count; j++) {
2903 + vreg = &thread->vreg[j];
2904 +
2905 + if (ctrl->cpr_enabled && ctrl->use_hw_closed_loop)
2906 + cpr3_update_vreg_closed_loop_volt(vreg,
2907 + vdd_volt, reg_last_measurement);
2908 +
2909 + if (!vreg->vreg_enabled
2910 + || vreg->current_corner
2911 + == CPR3_REGULATOR_CORNER_INVALID) {
2912 + /* Cannot participate in aggregation. */
2913 + vreg->aggregated = false;
2914 + continue;
2915 + } else {
2916 + vreg->aggregated = true;
2917 + thread_valid = true;
2918 + }
2919 +
2920 + cpr3_regulator_aggregate_corners(&thread->aggr_corner,
2921 + &vreg->corner[vreg->current_corner],
2922 + true, ctrl->step_volt);
2923 + }
2924 +
2925 + valid |= thread_valid;
2926 +
2927 + if (thread_valid)
2928 + cpr3_regulator_aggregate_corners(&aggr_corner,
2929 + &thread->aggr_corner,
2930 + false, ctrl->step_volt);
2931 + }
2932 +
2933 + if (valid && ctrl->cpr_allowed_hw && ctrl->cpr_allowed_sw) {
2934 + rc = cpr3_closed_loop_enable(ctrl);
2935 + if (rc) {
2936 + cpr3_err(ctrl, "could not enable CPR, rc=%d\n", rc);
2937 + return rc;
2938 + }
2939 + } else {
2940 + rc = cpr3_closed_loop_disable(ctrl);
2941 + if (rc) {
2942 + cpr3_err(ctrl, "could not disable CPR, rc=%d\n", rc);
2943 + return rc;
2944 + }
2945 + }
2946 +
2947 + /* No threads are enabled with a valid corner so exit. */
2948 + if (!valid)
2949 + return 0;
2950 +
2951 + /*
2952 + * When using CPR hardware closed-loop, the voltage may vary anywhere
2953 + * between the floor and ceiling voltage without software notification.
2954 + * Therefore, it is required that the floor to ceiling range for the
2955 + * aggregated corner not intersect the APM threshold voltage. Adjust
2956 + * the floor to ceiling range if this requirement is violated.
2957 + *
2958 + * The following algorithm is applied in the case that
2959 + * floor < threshold <= ceiling:
2960 + * if open_loop >= threshold - adj, then floor = threshold
2961 + * else ceiling = threshold - step
2962 + * where adj = an adjustment factor to ensure sufficient voltage margin
2963 + * and step = VDD output step size
2964 + *
2965 + * The open-loop and last known voltages are also bounded by the new
2966 + * floor or ceiling value as needed.
2967 + */
2968 + if (ctrl->use_hw_closed_loop
2969 + && aggr_corner.ceiling_volt >= ctrl->apm_threshold_volt
2970 + && aggr_corner.floor_volt < ctrl->apm_threshold_volt) {
2971 +
2972 + if (aggr_corner.open_loop_volt
2973 + >= ctrl->apm_threshold_volt - ctrl->apm_adj_volt)
2974 + aggr_corner.floor_volt = ctrl->apm_threshold_volt;
2975 + else
2976 + aggr_corner.ceiling_volt
2977 + = ctrl->apm_threshold_volt - ctrl->step_volt;
2978 +
2979 + aggr_corner.last_volt
2980 + = max(aggr_corner.last_volt, aggr_corner.floor_volt);
2981 + aggr_corner.last_volt
2982 + = min(aggr_corner.last_volt, aggr_corner.ceiling_volt);
2983 + aggr_corner.open_loop_volt
2984 + = max(aggr_corner.open_loop_volt, aggr_corner.floor_volt);
2985 + aggr_corner.open_loop_volt
2986 + = min(aggr_corner.open_loop_volt, aggr_corner.ceiling_volt);
2987 + }
2988 +
2989 + if (ctrl->use_hw_closed_loop
2990 + && aggr_corner.ceiling_volt >= ctrl->mem_acc_threshold_volt
2991 + && aggr_corner.floor_volt < ctrl->mem_acc_threshold_volt) {
2992 + aggr_corner.floor_volt = ctrl->mem_acc_threshold_volt;
2993 + aggr_corner.last_volt = max(aggr_corner.last_volt,
2994 + aggr_corner.floor_volt);
2995 + aggr_corner.open_loop_volt = max(aggr_corner.open_loop_volt,
2996 + aggr_corner.floor_volt);
2997 + }
2998 +
2999 + if (ctrl->use_hw_closed_loop) {
3000 + dynamic_floor_volt
3001 + = cpr3_regulator_get_dynamic_floor_volt(ctrl,
3002 + reg_last_measurement);
3003 + if (aggr_corner.floor_volt < dynamic_floor_volt) {
3004 + aggr_corner.floor_volt = dynamic_floor_volt;
3005 + aggr_corner.last_volt = max(aggr_corner.last_volt,
3006 + aggr_corner.floor_volt);
3007 + aggr_corner.open_loop_volt
3008 + = max(aggr_corner.open_loop_volt,
3009 + aggr_corner.floor_volt);
3010 + aggr_corner.ceiling_volt = max(aggr_corner.ceiling_volt,
3011 + aggr_corner.floor_volt);
3012 + }
3013 + }
3014 +
3015 + if (ctrl->cpr_enabled && ctrl->last_corner_was_closed_loop) {
3016 + /*
3017 + * Always program open-loop voltage for CPR4 controllers which
3018 + * support hardware closed-loop. Storing the last closed loop
3019 + * voltage in corner structure can still help with debugging.
3020 + */
3021 + if (ctrl->ctrl_type == CPR_CTRL_TYPE_CPR3)
3022 + new_volt = aggr_corner.last_volt;
3023 + else if (ctrl->ctrl_type == CPR_CTRL_TYPE_CPR4
3024 + && ctrl->supports_hw_closed_loop)
3025 + new_volt = aggr_corner.open_loop_volt;
3026 + else
3027 + new_volt = min(aggr_corner.last_volt +
3028 + cpr3_regulator_max_sdelta_diff(aggr_corner.sdelta,
3029 + ctrl->step_volt),
3030 + aggr_corner.ceiling_volt);
3031 +
3032 + aggr_corner.last_volt = new_volt;
3033 + } else {
3034 + new_volt = aggr_corner.open_loop_volt;
3035 + aggr_corner.last_volt = aggr_corner.open_loop_volt;
3036 + }
3037 +
3038 + if (ctrl->ctrl_type == CPR_CTRL_TYPE_CPR4
3039 + && ctrl->supports_hw_closed_loop) {
3040 + /*
3041 + * Store last aggregated corner open-loop voltage in vdd_volt
3042 + * which is used when programming current aggregated corner
3043 + * required voltage.
3044 + */
3045 + vdd_volt = last_corner_volt;
3046 + }
3047 +
3048 + cpr3_debug(ctrl, "setting new voltage=%d uV\n", new_volt);
3049 + rc = cpr3_regulator_scale_vdd_voltage(ctrl, new_volt,
3050 + vdd_volt, &aggr_corner);
3051 + if (rc) {
3052 + cpr3_err(ctrl, "vdd voltage scaling failed, rc=%d\n", rc);
3053 + return rc;
3054 + }
3055 +
3056 + /* Only update registers if CPR is enabled. */
3057 + if (ctrl->cpr_enabled) {
3058 + if (ctrl->use_hw_closed_loop) {
3059 + /* Hardware closed-loop */
3060 +
3061 + /* Set ceiling and floor limits in hardware */
3062 + rc = regulator_set_voltage(ctrl->vdd_limit_regulator,
3063 + aggr_corner.floor_volt,
3064 + aggr_corner.ceiling_volt);
3065 + if (rc) {
3066 + cpr3_err(ctrl, "could not configure HW closed-loop voltage limits, rc=%d\n",
3067 + rc);
3068 + return rc;
3069 + }
3070 + } else {
3071 + /* Software closed-loop */
3072 +
3073 + /*
3074 + * Disable UP or DOWN interrupts when at ceiling or
3075 + * floor respectively.
3076 + */
3077 + if (new_volt == aggr_corner.floor_volt)
3078 + aggr_corner.irq_en &= ~CPR3_IRQ_DOWN;
3079 + if (new_volt == aggr_corner.ceiling_volt)
3080 + aggr_corner.irq_en &= ~CPR3_IRQ_UP;
3081 +
3082 + cpr3_write(ctrl, CPR3_REG_IRQ_CLEAR,
3083 + CPR3_IRQ_UP | CPR3_IRQ_DOWN);
3084 + cpr3_write(ctrl, CPR3_REG_IRQ_EN, aggr_corner.irq_en);
3085 + }
3086 +
3087 + for (i = 0; i < ctrl->thread_count; i++) {
3088 + cpr3_regulator_set_target_quot(&ctrl->thread[i]);
3089 +
3090 + for (j = 0; j < ctrl->thread[i].vreg_count; j++) {
3091 + vreg = &ctrl->thread[i].vreg[j];
3092 +
3093 + if (vreg->vreg_enabled)
3094 + vreg->last_closed_loop_corner
3095 + = vreg->current_corner;
3096 + }
3097 + }
3098 +
3099 + if (ctrl->proc_clock_throttle) {
3100 + if (aggr_corner.ceiling_volt > aggr_corner.floor_volt
3101 + && (ctrl->use_hw_closed_loop
3102 + || new_volt < aggr_corner.ceiling_volt))
3103 + cpr3_write(ctrl, CPR3_REG_PD_THROTTLE,
3104 + ctrl->proc_clock_throttle);
3105 + else
3106 + cpr3_write(ctrl, CPR3_REG_PD_THROTTLE,
3107 + CPR3_PD_THROTTLE_DISABLE);
3108 + }
3109 +
3110 + /*
3111 + * Ensure that all CPR register writes complete before
3112 + * re-enabling CPR loop operation.
3113 + */
3114 + wmb();
3115 + } else if (ctrl->ctrl_type == CPR_CTRL_TYPE_CPR4
3116 + && ctrl->vdd_limit_regulator) {
3117 + /* Set ceiling and floor limits in hardware */
3118 + rc = regulator_set_voltage(ctrl->vdd_limit_regulator,
3119 + aggr_corner.floor_volt,
3120 + aggr_corner.ceiling_volt);
3121 + if (rc) {
3122 + cpr3_err(ctrl, "could not configure HW closed-loop voltage limits, rc=%d\n",
3123 + rc);
3124 + return rc;
3125 + }
3126 + }
3127 +
3128 + ctrl->aggr_corner = aggr_corner;
3129 +
3130 + if (ctrl->allow_core_count_adj || ctrl->allow_temp_adj
3131 + || ctrl->allow_boost) {
3132 + rc = cpr3_controller_program_sdelta(ctrl);
3133 + if (rc) {
3134 + cpr3_err(ctrl, "failed to program sdelta, rc=%d\n", rc);
3135 + return rc;
3136 + }
3137 + }
3138 +
3139 + /*
3140 + * Only enable the CPR controller if it is possible to set more than
3141 + * one vdd-supply voltage.
3142 + */
3143 + if (aggr_corner.ceiling_volt > aggr_corner.floor_volt &&
3144 + !aggr_corner.use_open_loop)
3145 + cpr3_ctrl_loop_enable(ctrl);
3146 +
3147 + ctrl->last_corner_was_closed_loop = ctrl->cpr_enabled;
3148 + cpr3_debug(ctrl, "CPR configuration updated\n");
3149 +
3150 + return 0;
3151 +}
3152 +
3153 +/**
3154 + * cpr3_regulator_wait_for_idle() - wait for the CPR controller to no longer be
3155 + * busy
3156 + * @ctrl: Pointer to the CPR3 controller
3157 + * @max_wait_ns: Max wait time in nanoseconds
3158 + *
3159 + * Return: 0 on success or -ETIMEDOUT if the controller was still busy after
3160 + * the maximum delay time
3161 + */
3162 +static int cpr3_regulator_wait_for_idle(struct cpr3_controller *ctrl,
3163 + s64 max_wait_ns)
3164 +{
3165 + ktime_t start, end;
3166 + s64 time_ns;
3167 + u32 reg;
3168 +
3169 + /*
3170 + * Ensure that all previous CPR register writes have completed before
3171 + * checking the status register.
3172 + */
3173 + mb();
3174 +
3175 + start = ktime_get();
3176 + do {
3177 + end = ktime_get();
3178 + time_ns = ktime_to_ns(ktime_sub(end, start));
3179 + if (time_ns > max_wait_ns) {
3180 + cpr3_err(ctrl, "CPR controller still busy after %lld us\n",
3181 + div_s64(time_ns, 1000));
3182 + return -ETIMEDOUT;
3183 + }
3184 + usleep_range(50, 100);
3185 + reg = cpr3_read(ctrl, CPR3_REG_CPR_STATUS);
3186 + } while (reg & CPR3_CPR_STATUS_BUSY_MASK);
3187 +
3188 + return 0;
3189 +}
3190 +
3191 +/**
3192 + * cmp_int() - int comparison function to be passed into the sort() function
3193 + * which leads to ascending sorting
3194 + * @a: First int value
3195 + * @b: Second int value
3196 + *
3197 + * Return: >0 if a > b, 0 if a == b, <0 if a < b
3198 + */
3199 +static int cmp_int(const void *a, const void *b)
3200 +{
3201 + return *(int *)a - *(int *)b;
3202 +}
3203 +
3204 +/**
3205 + * cpr3_regulator_measure_aging() - measure the quotient difference for the
3206 + * specified CPR aging sensor
3207 + * @ctrl: Pointer to the CPR3 controller
3208 + * @aging_sensor: Aging sensor to measure
3209 + *
3210 + * Note that vdd-supply must be configured to the aging reference voltage before
3211 + * calling this function.
3212 + *
3213 + * Return: 0 on success, errno on failure
3214 + */
3215 +static int cpr3_regulator_measure_aging(struct cpr3_controller *ctrl,
3216 + struct cpr3_aging_sensor_info *aging_sensor)
3217 +{
3218 + u32 mask, reg, result, quot_min, quot_max, sel_min, sel_max;
3219 + u32 quot_min_scaled, quot_max_scaled;
3220 + u32 gcnt, gcnt_ref, gcnt0_restore, gcnt1_restore, irq_restore;
3221 + u32 ro_mask_restore, cont_dly_restore, up_down_dly_restore = 0;
3222 + int quot_delta, quot_delta_scaled, quot_delta_scaled_sum;
3223 + int *quot_delta_results;
3224 + int rc, rc2, i, aging_measurement_count, filtered_count;
3225 + bool is_aging_measurement;
3226 +
3227 + quot_delta_results = kcalloc(CPR3_AGING_MEASUREMENT_ITERATIONS,
3228 + sizeof(*quot_delta_results), GFP_KERNEL);
3229 + if (!quot_delta_results)
3230 + return -ENOMEM;
3231 +
3232 + if (ctrl->ctrl_type == CPR_CTRL_TYPE_CPR4) {
3233 + rc = cpr3_ctrl_clear_cpr4_config(ctrl);
3234 + if (rc) {
3235 + cpr3_err(ctrl, "failed to clear CPR4 configuration,rc=%d\n",
3236 + rc);
3237 + kfree(quot_delta_results);
3238 + return rc;
3239 + }
3240 + }
3241 +
3242 + cpr3_ctrl_loop_disable(ctrl);
3243 +
3244 + /* Enable up, down, and mid CPR interrupts */
3245 + irq_restore = cpr3_read(ctrl, CPR3_REG_IRQ_EN);
3246 + cpr3_write(ctrl, CPR3_REG_IRQ_EN,
3247 + CPR3_IRQ_UP | CPR3_IRQ_DOWN | CPR3_IRQ_MID);
3248 +
3249 + /* Ensure that the aging sensor is assigned to CPR thread 0 */
3250 + cpr3_write(ctrl, CPR3_REG_SENSOR_OWNER(aging_sensor->sensor_id), 0);
3251 +
3252 + /* Switch from HW to SW closed-loop if necessary */
3253 + if (ctrl->supports_hw_closed_loop) {
3254 + if (ctrl->ctrl_type == CPR_CTRL_TYPE_CPR4) {
3255 + cpr3_masked_write(ctrl, CPR4_REG_MARGIN_ADJ_CTL,
3256 + CPR4_MARGIN_ADJ_CTL_HW_CLOSED_LOOP_EN_MASK,
3257 + CPR4_MARGIN_ADJ_CTL_HW_CLOSED_LOOP_DISABLE);
3258 + } else if (ctrl->ctrl_type == CPR_CTRL_TYPE_CPR3) {
3259 + cpr3_write(ctrl, CPR3_REG_HW_CLOSED_LOOP,
3260 + CPR3_HW_CLOSED_LOOP_DISABLE);
3261 + }
3262 + }
3263 +
3264 + /* Configure the GCNT for RO0 and RO1 that are used for aging */
3265 + gcnt0_restore = cpr3_read(ctrl, CPR3_REG_GCNT(0));
3266 + gcnt1_restore = cpr3_read(ctrl, CPR3_REG_GCNT(1));
3267 + gcnt_ref = cpr3_regulator_get_gcnt(ctrl);
3268 + gcnt = gcnt_ref * 3 / 2;
3269 + cpr3_write(ctrl, CPR3_REG_GCNT(0), gcnt);
3270 + cpr3_write(ctrl, CPR3_REG_GCNT(1), gcnt);
3271 +
3272 + /* Unmask all RO's */
3273 + ro_mask_restore = cpr3_read(ctrl, CPR3_REG_RO_MASK(0));
3274 + cpr3_write(ctrl, CPR3_REG_RO_MASK(0), 0);
3275 +
3276 + /*
3277 + * Mask all sensors except for the one to measure and bypass all
3278 + * sensors in collapsible domains.
3279 + */
3280 + for (i = 0; i <= ctrl->sensor_count / 32; i++) {
3281 + mask = GENMASK(min(31, ctrl->sensor_count - i * 32), 0);
3282 + if (aging_sensor->sensor_id / 32 >= i
3283 + && aging_sensor->sensor_id / 32 < (i + 1))
3284 + mask &= ~BIT(aging_sensor->sensor_id % 32);
3285 + cpr3_write(ctrl, CPR3_REG_SENSOR_MASK_WRITE_BANK(i), mask);
3286 + cpr3_write(ctrl, CPR3_REG_SENSOR_BYPASS_WRITE_BANK(i),
3287 + aging_sensor->bypass_mask[i]);
3288 + }
3289 +
3290 + /* Set CPR loop delays to 0 us */
3291 + if (ctrl->supports_hw_closed_loop
3292 + && ctrl->ctrl_type == CPR_CTRL_TYPE_CPR3) {
3293 + cont_dly_restore = cpr3_read(ctrl, CPR3_REG_CPR_TIMER_MID_CONT);
3294 + up_down_dly_restore = cpr3_read(ctrl,
3295 + CPR3_REG_CPR_TIMER_UP_DN_CONT);
3296 + cpr3_write(ctrl, CPR3_REG_CPR_TIMER_MID_CONT, 0);
3297 + cpr3_write(ctrl, CPR3_REG_CPR_TIMER_UP_DN_CONT, 0);
3298 + } else {
3299 + cont_dly_restore = cpr3_read(ctrl,
3300 + CPR3_REG_CPR_TIMER_AUTO_CONT);
3301 + cpr3_write(ctrl, CPR3_REG_CPR_TIMER_AUTO_CONT, 0);
3302 + }
3303 +
3304 + /* Set count mode to all-at-once min with no repeat */
3305 + cpr3_masked_write(ctrl, CPR3_REG_CPR_CTL,
3306 + CPR3_CPR_CTL_COUNT_MODE_MASK | CPR3_CPR_CTL_COUNT_REPEAT_MASK,
3307 + CPR3_CPR_CTL_COUNT_MODE_ALL_AT_ONCE_MIN
3308 + << CPR3_CPR_CTL_COUNT_MODE_SHIFT);
3309 +
3310 + cpr3_ctrl_loop_enable(ctrl);
3311 +
3312 + rc = cpr3_regulator_wait_for_idle(ctrl,
3313 + CPR3_AGING_MEASUREMENT_TIMEOUT_NS);
3314 + if (rc)
3315 + goto cleanup;
3316 +
3317 + /* Set count mode to all-at-once aging */
3318 + cpr3_masked_write(ctrl, CPR3_REG_CPR_CTL, CPR3_CPR_CTL_COUNT_MODE_MASK,
3319 + CPR3_CPR_CTL_COUNT_MODE_ALL_AT_ONCE_AGE
3320 + << CPR3_CPR_CTL_COUNT_MODE_SHIFT);
3321 +
3322 + aging_measurement_count = 0;
3323 + for (i = 0; i < CPR3_AGING_MEASUREMENT_ITERATIONS; i++) {
3324 + /* Send CONT_NACK */
3325 + cpr3_write(ctrl, CPR3_REG_CONT_CMD, CPR3_CONT_CMD_NACK);
3326 +
3327 + rc = cpr3_regulator_wait_for_idle(ctrl,
3328 + CPR3_AGING_MEASUREMENT_TIMEOUT_NS);
3329 + if (rc)
3330 + goto cleanup;
3331 +
3332 + /* Check for PAGE_IS_AGE flag in status register */
3333 + reg = cpr3_read(ctrl, CPR3_REG_CPR_STATUS);
3334 + is_aging_measurement
3335 + = reg & CPR3_CPR_STATUS_AGING_MEASUREMENT_MASK;
3336 +
3337 + /* Read CPR measurement results */
3338 + result = cpr3_read(ctrl, CPR3_REG_RESULT1(0));
3339 + quot_min = (result & CPR3_RESULT1_QUOT_MIN_MASK)
3340 + >> CPR3_RESULT1_QUOT_MIN_SHIFT;
3341 + quot_max = (result & CPR3_RESULT1_QUOT_MAX_MASK)
3342 + >> CPR3_RESULT1_QUOT_MAX_SHIFT;
3343 + sel_min = (result & CPR3_RESULT1_RO_MIN_MASK)
3344 + >> CPR3_RESULT1_RO_MIN_SHIFT;
3345 + sel_max = (result & CPR3_RESULT1_RO_MAX_MASK)
3346 + >> CPR3_RESULT1_RO_MAX_SHIFT;
3347 +
3348 + /*
3349 + * Scale the quotients so that they are equivalent to the fused
3350 + * values. This accounts for the difference in measurement
3351 + * interval times.
3352 + */
3353 + quot_min_scaled = quot_min * (gcnt_ref + 1) / (gcnt + 1);
3354 + quot_max_scaled = quot_max * (gcnt_ref + 1) / (gcnt + 1);
3355 +
3356 + if (sel_max == 1) {
3357 + quot_delta = quot_max - quot_min;
3358 + quot_delta_scaled = quot_max_scaled - quot_min_scaled;
3359 + } else {
3360 + quot_delta = quot_min - quot_max;
3361 + quot_delta_scaled = quot_min_scaled - quot_max_scaled;
3362 + }
3363 +
3364 + if (is_aging_measurement)
3365 + quot_delta_results[aging_measurement_count++]
3366 + = quot_delta_scaled;
3367 +
3368 + cpr3_debug(ctrl, "aging results: page_is_age=%u, sel_min=%u, sel_max=%u, quot_min=%u, quot_max=%u, quot_delta=%d, quot_min_scaled=%u, quot_max_scaled=%u, quot_delta_scaled=%d\n",
3369 + is_aging_measurement, sel_min, sel_max, quot_min,
3370 + quot_max, quot_delta, quot_min_scaled, quot_max_scaled,
3371 + quot_delta_scaled);
3372 + }
3373 +
3374 + filtered_count
3375 + = aging_measurement_count - CPR3_AGING_MEASUREMENT_FILTER * 2;
3376 + if (filtered_count > 0) {
3377 + sort(quot_delta_results, aging_measurement_count,
3378 + sizeof(*quot_delta_results), cmp_int, NULL);
3379 +
3380 + quot_delta_scaled_sum = 0;
3381 + for (i = 0; i < filtered_count; i++)
3382 + quot_delta_scaled_sum
3383 + += quot_delta_results[i
3384 + + CPR3_AGING_MEASUREMENT_FILTER];
3385 +
3386 + aging_sensor->measured_quot_diff
3387 + = quot_delta_scaled_sum / filtered_count;
3388 + cpr3_info(ctrl, "average quotient delta=%d (count=%d)\n",
3389 + aging_sensor->measured_quot_diff,
3390 + filtered_count);
3391 + } else {
3392 + cpr3_err(ctrl, "%d aging measurements completed after %d iterations\n",
3393 + aging_measurement_count,
3394 + CPR3_AGING_MEASUREMENT_ITERATIONS);
3395 + rc = -EBUSY;
3396 + }
3397 +
3398 +cleanup:
3399 + kfree(quot_delta_results);
3400 +
3401 + if (ctrl->ctrl_type == CPR_CTRL_TYPE_CPR4) {
3402 + rc2 = cpr3_ctrl_clear_cpr4_config(ctrl);
3403 + if (rc2) {
3404 + cpr3_err(ctrl, "failed to clear CPR4 configuration,rc=%d\n",
3405 + rc2);
3406 + rc = rc2;
3407 + }
3408 + }
3409 +
3410 + cpr3_ctrl_loop_disable(ctrl);
3411 +
3412 + cpr3_write(ctrl, CPR3_REG_IRQ_EN, irq_restore);
3413 +
3414 + cpr3_write(ctrl, CPR3_REG_RO_MASK(0), ro_mask_restore);
3415 +
3416 + cpr3_write(ctrl, CPR3_REG_GCNT(0), gcnt0_restore);
3417 + cpr3_write(ctrl, CPR3_REG_GCNT(1), gcnt1_restore);
3418 +
3419 + if (ctrl->supports_hw_closed_loop
3420 + && ctrl->ctrl_type == CPR_CTRL_TYPE_CPR3) {
3421 + cpr3_write(ctrl, CPR3_REG_CPR_TIMER_MID_CONT, cont_dly_restore);
3422 + cpr3_write(ctrl, CPR3_REG_CPR_TIMER_UP_DN_CONT,
3423 + up_down_dly_restore);
3424 + } else {
3425 + cpr3_write(ctrl, CPR3_REG_CPR_TIMER_AUTO_CONT,
3426 + cont_dly_restore);
3427 + }
3428 +
3429 + for (i = 0; i <= ctrl->sensor_count / 32; i++) {
3430 + cpr3_write(ctrl, CPR3_REG_SENSOR_MASK_WRITE_BANK(i), 0);
3431 + cpr3_write(ctrl, CPR3_REG_SENSOR_BYPASS_WRITE_BANK(i), 0);
3432 + }
3433 +
3434 + cpr3_masked_write(ctrl, CPR3_REG_CPR_CTL,
3435 + CPR3_CPR_CTL_COUNT_MODE_MASK | CPR3_CPR_CTL_COUNT_REPEAT_MASK,
3436 + (ctrl->count_mode << CPR3_CPR_CTL_COUNT_MODE_SHIFT)
3437 + | (ctrl->count_repeat << CPR3_CPR_CTL_COUNT_REPEAT_SHIFT));
3438 +
3439 + cpr3_write(ctrl, CPR3_REG_SENSOR_OWNER(aging_sensor->sensor_id),
3440 + ctrl->sensor_owner[aging_sensor->sensor_id]);
3441 +
3442 + cpr3_write(ctrl, CPR3_REG_IRQ_CLEAR,
3443 + CPR3_IRQ_UP | CPR3_IRQ_DOWN | CPR3_IRQ_MID);
3444 +
3445 + if (ctrl->supports_hw_closed_loop) {
3446 + if (ctrl->ctrl_type == CPR_CTRL_TYPE_CPR4) {
3447 + cpr3_masked_write(ctrl, CPR4_REG_MARGIN_ADJ_CTL,
3448 + CPR4_MARGIN_ADJ_CTL_HW_CLOSED_LOOP_EN_MASK,
3449 + ctrl->use_hw_closed_loop
3450 + ? CPR4_MARGIN_ADJ_CTL_HW_CLOSED_LOOP_ENABLE
3451 + : CPR4_MARGIN_ADJ_CTL_HW_CLOSED_LOOP_DISABLE);
3452 + } else if (ctrl->ctrl_type == CPR_CTRL_TYPE_CPR3) {
3453 + cpr3_write(ctrl, CPR3_REG_HW_CLOSED_LOOP,
3454 + ctrl->use_hw_closed_loop
3455 + ? CPR3_HW_CLOSED_LOOP_ENABLE
3456 + : CPR3_HW_CLOSED_LOOP_DISABLE);
3457 + }
3458 + }
3459 +
3460 + return rc;
3461 +}
3462 +
3463 +/**
3464 + * cpr3_regulator_readjust_volt_and_quot() - readjust the target quotients as
3465 + * well as the floor, ceiling, and open-loop voltages for the
3466 + * regulator by removing the old adjustment and adding the new one
3467 + * @vreg: Pointer to the CPR3 regulator
3468 + * @old_adjust_volt: Old aging adjustment voltage in microvolts
3469 + * @new_adjust_volt: New aging adjustment voltage in microvolts
3470 + *
3471 + * Also reset the cached closed loop voltage (last_volt) to equal the open-loop
3472 + * voltage for each corner.
3473 + *
3474 + * Return: None
3475 + */
3476 +static void cpr3_regulator_readjust_volt_and_quot(struct cpr3_regulator *vreg,
3477 + int old_adjust_volt, int new_adjust_volt)
3478 +{
3479 + unsigned long long temp;
3480 + int i, j, old_volt, new_volt, rounded_volt;
3481 +
3482 + if (!vreg->aging_allowed)
3483 + return;
3484 +
3485 + for (i = 0; i < vreg->corner_count; i++) {
3486 + temp = (unsigned long long)old_adjust_volt
3487 + * (unsigned long long)vreg->corner[i].aging_derate;
3488 + do_div(temp, 1000);
3489 + old_volt = temp;
3490 +
3491 + temp = (unsigned long long)new_adjust_volt
3492 + * (unsigned long long)vreg->corner[i].aging_derate;
3493 + do_div(temp, 1000);
3494 + new_volt = temp;
3495 +
3496 + old_volt = min(vreg->aging_max_adjust_volt, old_volt);
3497 + new_volt = min(vreg->aging_max_adjust_volt, new_volt);
3498 +
3499 + for (j = 0; j < CPR3_RO_COUNT; j++) {
3500 + if (vreg->corner[i].target_quot[j] != 0) {
3501 + vreg->corner[i].target_quot[j]
3502 + += cpr3_quot_adjustment(
3503 + vreg->corner[i].ro_scale[j],
3504 + new_volt)
3505 + - cpr3_quot_adjustment(
3506 + vreg->corner[i].ro_scale[j],
3507 + old_volt);
3508 + }
3509 + }
3510 +
3511 + rounded_volt = CPR3_ROUND(new_volt,
3512 + vreg->thread->ctrl->step_volt);
3513 +
3514 + if (!vreg->aging_allow_open_loop_adj)
3515 + rounded_volt = 0;
3516 +
3517 + vreg->corner[i].ceiling_volt
3518 + = vreg->corner[i].unaged_ceiling_volt + rounded_volt;
3519 + vreg->corner[i].ceiling_volt = min(vreg->corner[i].ceiling_volt,
3520 + vreg->corner[i].abs_ceiling_volt);
3521 + vreg->corner[i].floor_volt
3522 + = vreg->corner[i].unaged_floor_volt + rounded_volt;
3523 + vreg->corner[i].floor_volt = min(vreg->corner[i].floor_volt,
3524 + vreg->corner[i].ceiling_volt);
3525 + vreg->corner[i].open_loop_volt
3526 + = vreg->corner[i].unaged_open_loop_volt + rounded_volt;
3527 + vreg->corner[i].open_loop_volt
3528 + = min(vreg->corner[i].open_loop_volt,
3529 + vreg->corner[i].ceiling_volt);
3530 +
3531 + vreg->corner[i].last_volt = vreg->corner[i].open_loop_volt;
3532 +
3533 + cpr3_debug(vreg, "corner %d: applying %d uV closed-loop and %d uV open-loop voltage margin adjustment\n",
3534 + i, new_volt, rounded_volt);
3535 + }
3536 +}
3537 +
3538 +/**
3539 + * cpr3_regulator_set_aging_ref_adjustment() - adjust target quotients for the
3540 + * regulators managed by this CPR controller to account for aging
3541 + * @ctrl: Pointer to the CPR3 controller
3542 + * @ref_adjust_volt: New aging reference adjustment voltage in microvolts to
3543 + * apply to all regulators managed by this CPR controller
3544 + *
3545 + * The existing aging adjustment as defined by ctrl->aging_ref_adjust_volt is
3546 + * first removed and then the adjustment is applied. Lastly, the value of
3547 + * ctrl->aging_ref_adjust_volt is updated to ref_adjust_volt.
3548 + */
3549 +static void cpr3_regulator_set_aging_ref_adjustment(
3550 + struct cpr3_controller *ctrl, int ref_adjust_volt)
3551 +{
3552 + struct cpr3_regulator *vreg;
3553 + int i, j;
3554 +
3555 + for (i = 0; i < ctrl->thread_count; i++) {
3556 + for (j = 0; j < ctrl->thread[i].vreg_count; j++) {
3557 + vreg = &ctrl->thread[i].vreg[j];
3558 + cpr3_regulator_readjust_volt_and_quot(vreg,
3559 + ctrl->aging_ref_adjust_volt, ref_adjust_volt);
3560 + }
3561 + }
3562 +
3563 + ctrl->aging_ref_adjust_volt = ref_adjust_volt;
3564 +}
3565 +
3566 +/**
3567 + * cpr3_regulator_aging_adjust() - adjust the target quotients for regulators
3568 + * based on the output of CPR aging sensors
3569 + * @ctrl: Pointer to the CPR3 controller
3570 + *
3571 + * Return: 0 on success, errno on failure
3572 + */
3573 +static int cpr3_regulator_aging_adjust(struct cpr3_controller *ctrl)
3574 +{
3575 + struct cpr3_regulator *vreg;
3576 + struct cpr3_corner restore_aging_corner;
3577 + struct cpr3_corner *corner;
3578 + int *restore_current_corner;
3579 + bool *restore_vreg_enabled;
3580 + int i, j, id, rc, rc2, vreg_count, aging_volt, max_aging_volt = 0;
3581 + u32 reg;
3582 +
3583 + if (!ctrl->aging_required || !ctrl->cpr_enabled
3584 + || ctrl->aggr_corner.ceiling_volt == 0
3585 + || ctrl->aggr_corner.ceiling_volt > ctrl->aging_ref_volt)
3586 + return 0;
3587 +
3588 + for (i = 0, vreg_count = 0; i < ctrl->thread_count; i++) {
3589 + for (j = 0; j < ctrl->thread[i].vreg_count; j++) {
3590 + vreg = &ctrl->thread[i].vreg[j];
3591 + vreg_count++;
3592 +
3593 + if (vreg->aging_allowed && vreg->vreg_enabled
3594 + && vreg->current_corner > vreg->aging_corner)
3595 + return 0;
3596 + }
3597 + }
3598 +
3599 + /* Verify that none of the aging sensors are currently masked. */
3600 + for (i = 0; i < ctrl->aging_sensor_count; i++) {
3601 + id = ctrl->aging_sensor[i].sensor_id;
3602 + reg = cpr3_read(ctrl, CPR3_REG_SENSOR_MASK_READ(id));
3603 + if (reg & BIT(id % 32))
3604 + return 0;
3605 + }
3606 +
3607 + /*
3608 + * Verify that the aging possible register (if specified) has an
3609 + * acceptable value.
3610 + */
3611 + if (ctrl->aging_possible_reg) {
3612 + reg = readl_relaxed(ctrl->aging_possible_reg);
3613 + reg &= ctrl->aging_possible_mask;
3614 + if (reg != ctrl->aging_possible_val)
3615 + return 0;
3616 + }
3617 +
3618 + restore_current_corner = kcalloc(vreg_count,
3619 + sizeof(*restore_current_corner), GFP_KERNEL);
3620 + restore_vreg_enabled = kcalloc(vreg_count,
3621 + sizeof(*restore_vreg_enabled), GFP_KERNEL);
3622 + if (!restore_current_corner || !restore_vreg_enabled) {
3623 + kfree(restore_current_corner);
3624 + kfree(restore_vreg_enabled);
3625 + return -ENOMEM;
3626 + }
3627 +
3628 + /* Force all regulators to the aging corner */
3629 + for (i = 0, vreg_count = 0; i < ctrl->thread_count; i++) {
3630 + for (j = 0; j < ctrl->thread[i].vreg_count; j++, vreg_count++) {
3631 + vreg = &ctrl->thread[i].vreg[j];
3632 +
3633 + restore_current_corner[vreg_count]
3634 + = vreg->current_corner;
3635 + restore_vreg_enabled[vreg_count]
3636 + = vreg->vreg_enabled;
3637 +
3638 + vreg->current_corner = vreg->aging_corner;
3639 + vreg->vreg_enabled = true;
3640 + }
3641 + }
3642 +
3643 + /* Force one of the regulators to require the aging reference voltage */
3644 + vreg = &ctrl->thread[0].vreg[0];
3645 + corner = &vreg->corner[vreg->current_corner];
3646 + restore_aging_corner = *corner;
3647 + corner->ceiling_volt = ctrl->aging_ref_volt;
3648 + corner->floor_volt = ctrl->aging_ref_volt;
3649 + corner->open_loop_volt = ctrl->aging_ref_volt;
3650 + corner->last_volt = ctrl->aging_ref_volt;
3651 +
3652 + /* Skip last_volt caching */
3653 + ctrl->last_corner_was_closed_loop = false;
3654 +
3655 + /* Set the vdd supply voltage to the aging reference voltage */
3656 + rc = _cpr3_regulator_update_ctrl_state(ctrl);
3657 + if (rc) {
3658 + cpr3_err(ctrl, "unable to force vdd-supply to the aging reference voltage=%d uV, rc=%d\n",
3659 + ctrl->aging_ref_volt, rc);
3660 + goto cleanup;
3661 + }
3662 +
3663 + if (ctrl->aging_vdd_mode) {
3664 + rc = regulator_set_mode(ctrl->vdd_regulator,
3665 + ctrl->aging_vdd_mode);
3666 + if (rc) {
3667 + cpr3_err(ctrl, "unable to configure vdd-supply for mode=%u, rc=%d\n",
3668 + ctrl->aging_vdd_mode, rc);
3669 + goto cleanup;
3670 + }
3671 + }
3672 +
3673 + /* Perform aging measurement on all aging sensors */
3674 + for (i = 0; i < ctrl->aging_sensor_count; i++) {
3675 + for (j = 0; j < CPR3_AGING_RETRY_COUNT; j++) {
3676 + rc = cpr3_regulator_measure_aging(ctrl,
3677 + &ctrl->aging_sensor[i]);
3678 + if (!rc)
3679 + break;
3680 + }
3681 +
3682 + if (!rc) {
3683 + aging_volt =
3684 + cpr3_voltage_adjustment(
3685 + ctrl->aging_sensor[i].ro_scale,
3686 + ctrl->aging_sensor[i].measured_quot_diff
3687 + - ctrl->aging_sensor[i].init_quot_diff);
3688 + max_aging_volt = max(max_aging_volt, aging_volt);
3689 + } else {
3690 + cpr3_err(ctrl, "CPR aging measurement failed after %d tries, rc=%d\n",
3691 + j, rc);
3692 + ctrl->aging_failed = true;
3693 + ctrl->aging_required = false;
3694 + goto cleanup;
3695 + }
3696 + }
3697 +
3698 +cleanup:
3699 + vreg = &ctrl->thread[0].vreg[0];
3700 + vreg->corner[vreg->current_corner] = restore_aging_corner;
3701 +
3702 + for (i = 0, vreg_count = 0; i < ctrl->thread_count; i++) {
3703 + for (j = 0; j < ctrl->thread[i].vreg_count; j++, vreg_count++) {
3704 + vreg = &ctrl->thread[i].vreg[j];
3705 + vreg->current_corner
3706 + = restore_current_corner[vreg_count];
3707 + vreg->vreg_enabled = restore_vreg_enabled[vreg_count];
3708 + }
3709 + }
3710 +
3711 + kfree(restore_current_corner);
3712 + kfree(restore_vreg_enabled);
3713 +
3714 + /* Adjust the CPR target quotients according to the aging measurement */
3715 + if (!rc) {
3716 + cpr3_regulator_set_aging_ref_adjustment(ctrl, max_aging_volt);
3717 +
3718 + cpr3_info(ctrl, "aging measurement successful; aging reference adjustment voltage=%d uV\n",
3719 + ctrl->aging_ref_adjust_volt);
3720 + ctrl->aging_succeeded = true;
3721 + ctrl->aging_required = false;
3722 + }
3723 +
3724 + if (ctrl->aging_complete_vdd_mode) {
3725 + rc = regulator_set_mode(ctrl->vdd_regulator,
3726 + ctrl->aging_complete_vdd_mode);
3727 + if (rc)
3728 + cpr3_err(ctrl, "unable to configure vdd-supply for mode=%u, rc=%d\n",
3729 + ctrl->aging_complete_vdd_mode, rc);
3730 + }
3731 +
3732 + /* Skip last_volt caching */
3733 + ctrl->last_corner_was_closed_loop = false;
3734 +
3735 + /*
3736 + * Restore vdd-supply to the voltage before the aging measurement and
3737 + * restore the CPR3 controller hardware state.
3738 + */
3739 + rc2 = _cpr3_regulator_update_ctrl_state(ctrl);
3740 +
3741 + /* Stop last_volt caching on for the next request */
3742 + ctrl->last_corner_was_closed_loop = false;
3743 +
3744 + return rc ? rc : rc2;
3745 +}
3746 +
3747 +/**
3748 + * cpr3_regulator_update_ctrl_state() - update the state of the CPR controller
3749 + * to reflect the corners used by all CPR3 regulators as well as
3750 + * the CPR operating mode and perform aging adjustments if needed
3751 + * @ctrl: Pointer to the CPR3 controller
3752 + *
3753 + * Note, CPR3 controller lock must be held by the caller.
3754 + *
3755 + * Return: 0 on success, errno on failure
3756 + */
3757 +static int cpr3_regulator_update_ctrl_state(struct cpr3_controller *ctrl)
3758 +{
3759 + int rc;
3760 +
3761 + rc = _cpr3_regulator_update_ctrl_state(ctrl);
3762 + if (rc)
3763 + return rc;
3764 +
3765 + return cpr3_regulator_aging_adjust(ctrl);
3766 +}
3767 +
3768 +/**
3769 + * cpr3_regulator_set_voltage() - set the voltage corner for the CPR3 regulator
3770 + * associated with the regulator device
3771 + * @rdev: Regulator device pointer for the cpr3-regulator
3772 + * @corner: New voltage corner to set (offset by CPR3_CORNER_OFFSET)
3773 + * @corner_max: Maximum voltage corner allowed (offset by
3774 + * CPR3_CORNER_OFFSET)
3775 + * @selector: Pointer which is filled with the selector value for the
3776 + * corner
3777 + *
3778 + * This function is passed as a callback function into the regulator ops that
3779 + * are registered for each cpr3-regulator device. The VDD voltage will not be
3780 + * physically configured until both this function and cpr3_regulator_enable()
3781 + * are called.
3782 + *
3783 + * Return: 0 on success, errno on failure
3784 + */
3785 +static int cpr3_regulator_set_voltage(struct regulator_dev *rdev,
3786 + int corner, int corner_max, unsigned *selector)
3787 +{
3788 + struct cpr3_regulator *vreg = rdev_get_drvdata(rdev);
3789 + struct cpr3_controller *ctrl = vreg->thread->ctrl;
3790 + int rc = 0;
3791 + int last_corner;
3792 +
3793 + corner -= CPR3_CORNER_OFFSET;
3794 + corner_max -= CPR3_CORNER_OFFSET;
3795 + *selector = corner;
3796 +
3797 + mutex_lock(&ctrl->lock);
3798 +
3799 + if (!vreg->vreg_enabled) {
3800 + vreg->current_corner = corner;
3801 + cpr3_debug(vreg, "stored corner=%d\n", corner);
3802 + goto done;
3803 + } else if (vreg->current_corner == corner) {
3804 + goto done;
3805 + }
3806 +
3807 + last_corner = vreg->current_corner;
3808 + vreg->current_corner = corner;
3809 +
3810 + if (vreg->cpr4_regulator_data != NULL)
3811 + if (vreg->cpr4_regulator_data->mem_acc_funcs != NULL)
3812 + vreg->cpr4_regulator_data->mem_acc_funcs->set_mem_acc(rdev);
3813 +
3814 + rc = cpr3_regulator_update_ctrl_state(ctrl);
3815 + if (rc) {
3816 + cpr3_err(vreg, "could not update CPR state, rc=%d\n", rc);
3817 + vreg->current_corner = last_corner;
3818 + }
3819 +
3820 + if (vreg->cpr4_regulator_data != NULL)
3821 + if (vreg->cpr4_regulator_data->mem_acc_funcs != NULL)
3822 + vreg->cpr4_regulator_data->mem_acc_funcs->clear_mem_acc(rdev);
3823 +
3824 + cpr3_debug(vreg, "set corner=%d\n", corner);
3825 +done:
3826 + mutex_unlock(&ctrl->lock);
3827 +
3828 + return rc;
3829 +}
3830 +
3831 +/**
3832 + * cpr3_handle_temp_open_loop_adjustment() - voltage based cold temperature
3833 + *
3834 + * @rdev: Regulator device pointer for the cpr3-regulator
3835 + * @is_cold: Flag to denote enter/exit cold condition
3836 + *
3837 + * This function is adjusts voltage margin based on cold condition
3838 + *
3839 + * Return: 0 = success
3840 + */
3841 +
3842 +int cpr3_handle_temp_open_loop_adjustment(struct cpr3_controller *ctrl,
3843 + bool is_cold)
3844 +{
3845 + int i ,j, k, rc;
3846 + struct cpr3_regulator *vreg;
3847 +
3848 + mutex_lock(&ctrl->lock);
3849 + for (i = 0; i < ctrl->thread_count; i++) {
3850 + for (j = 0; j < ctrl->thread[i].vreg_count; j++) {
3851 + vreg = &ctrl->thread[i].vreg[j];
3852 + for (k = 0; k < vreg->corner_count; k++) {
3853 + vreg->corner[k].open_loop_volt = is_cold ?
3854 + vreg->corner[k].cold_temp_open_loop_volt :
3855 + vreg->corner[k].normal_temp_open_loop_volt;
3856 + }
3857 + }
3858 + }
3859 + rc = cpr3_regulator_update_ctrl_state(ctrl);
3860 + mutex_unlock(&ctrl->lock);
3861 +
3862 + return rc;
3863 +}
3864 +
3865 +/**
3866 + * cpr3_regulator_get_voltage() - get the voltage corner for the CPR3 regulator
3867 + * associated with the regulator device
3868 + * @rdev: Regulator device pointer for the cpr3-regulator
3869 + *
3870 + * This function is passed as a callback function into the regulator ops that
3871 + * are registered for each cpr3-regulator device.
3872 + *
3873 + * Return: voltage corner value offset by CPR3_CORNER_OFFSET
3874 + */
3875 +static int cpr3_regulator_get_voltage(struct regulator_dev *rdev)
3876 +{
3877 + struct cpr3_regulator *vreg = rdev_get_drvdata(rdev);
3878 +
3879 + if (vreg->current_corner == CPR3_REGULATOR_CORNER_INVALID)
3880 + return CPR3_CORNER_OFFSET;
3881 + else
3882 + return vreg->current_corner + CPR3_CORNER_OFFSET;
3883 +}
3884 +
3885 +/**
3886 + * cpr3_regulator_list_voltage() - return the voltage corner mapped to the
3887 + * specified selector
3888 + * @rdev: Regulator device pointer for the cpr3-regulator
3889 + * @selector: Regulator selector
3890 + *
3891 + * This function is passed as a callback function into the regulator ops that
3892 + * are registered for each cpr3-regulator device.
3893 + *
3894 + * Return: voltage corner value offset by CPR3_CORNER_OFFSET
3895 + */
3896 +static int cpr3_regulator_list_voltage(struct regulator_dev *rdev,
3897 + unsigned selector)
3898 +{
3899 + struct cpr3_regulator *vreg = rdev_get_drvdata(rdev);
3900 +
3901 + if (selector < vreg->corner_count)
3902 + return selector + CPR3_CORNER_OFFSET;
3903 + else
3904 + return 0;
3905 +}
3906 +
3907 +/**
3908 + * cpr3_regulator_is_enabled() - return the enable state of the CPR3 regulator
3909 + * @rdev: Regulator device pointer for the cpr3-regulator
3910 + *
3911 + * This function is passed as a callback function into the regulator ops that
3912 + * are registered for each cpr3-regulator device.
3913 + *
3914 + * Return: true if regulator is enabled, false if regulator is disabled
3915 + */
3916 +static int cpr3_regulator_is_enabled(struct regulator_dev *rdev)
3917 +{
3918 + struct cpr3_regulator *vreg = rdev_get_drvdata(rdev);
3919 +
3920 + return vreg->vreg_enabled;
3921 +}
3922 +
3923 +/**
3924 + * cpr3_regulator_enable() - enable the CPR3 regulator
3925 + * @rdev: Regulator device pointer for the cpr3-regulator
3926 + *
3927 + * This function is passed as a callback function into the regulator ops that
3928 + * are registered for each cpr3-regulator device.
3929 + *
3930 + * Return: 0 on success, errno on failure
3931 + */
3932 +static int cpr3_regulator_enable(struct regulator_dev *rdev)
3933 +{
3934 + struct cpr3_regulator *vreg = rdev_get_drvdata(rdev);
3935 + struct cpr3_controller *ctrl = vreg->thread->ctrl;
3936 + int rc = 0;
3937 +
3938 + if (vreg->vreg_enabled == true)
3939 + return 0;
3940 +
3941 + mutex_lock(&ctrl->lock);
3942 +
3943 + if (ctrl->system_regulator) {
3944 + rc = regulator_enable(ctrl->system_regulator);
3945 + if (rc) {
3946 + cpr3_err(ctrl, "regulator_enable(system) failed, rc=%d\n",
3947 + rc);
3948 + goto done;
3949 + }
3950 + }
3951 +
3952 + rc = regulator_enable(ctrl->vdd_regulator);
3953 + if (rc) {
3954 + cpr3_err(vreg, "regulator_enable(vdd) failed, rc=%d\n", rc);
3955 + goto done;
3956 + }
3957 +
3958 + vreg->vreg_enabled = true;
3959 + rc = cpr3_regulator_update_ctrl_state(ctrl);
3960 + if (rc) {
3961 + cpr3_err(vreg, "could not update CPR state, rc=%d\n", rc);
3962 + regulator_disable(ctrl->vdd_regulator);
3963 + vreg->vreg_enabled = false;
3964 + goto done;
3965 + }
3966 +
3967 + cpr3_debug(vreg, "Enabled\n");
3968 +done:
3969 + mutex_unlock(&ctrl->lock);
3970 +
3971 + return rc;
3972 +}
3973 +
3974 +/**
3975 + * cpr3_regulator_disable() - disable the CPR3 regulator
3976 + * @rdev: Regulator device pointer for the cpr3-regulator
3977 + *
3978 + * This function is passed as a callback function into the regulator ops that
3979 + * are registered for each cpr3-regulator device.
3980 + *
3981 + * Return: 0 on success, errno on failure
3982 + */
3983 +static int cpr3_regulator_disable(struct regulator_dev *rdev)
3984 +{
3985 + struct cpr3_regulator *vreg = rdev_get_drvdata(rdev);
3986 + struct cpr3_controller *ctrl = vreg->thread->ctrl;
3987 + int rc, rc2;
3988 +
3989 + if (vreg->vreg_enabled == false)
3990 + return 0;
3991 +
3992 + mutex_lock(&ctrl->lock);
3993 + rc = regulator_disable(ctrl->vdd_regulator);
3994 + if (rc) {
3995 + cpr3_err(vreg, "regulator_disable(vdd) failed, rc=%d\n", rc);
3996 + goto done;
3997 + }
3998 +
3999 + vreg->vreg_enabled = false;
4000 + rc = cpr3_regulator_update_ctrl_state(ctrl);
4001 + if (rc) {
4002 + cpr3_err(vreg, "could not update CPR state, rc=%d\n", rc);
4003 + rc2 = regulator_enable(ctrl->vdd_regulator);
4004 + vreg->vreg_enabled = true;
4005 + goto done;
4006 + }
4007 +
4008 + if (ctrl->system_regulator) {
4009 + rc = regulator_disable(ctrl->system_regulator);
4010 + if (rc) {
4011 + cpr3_err(ctrl, "regulator_disable(system) failed, rc=%d\n",
4012 + rc);
4013 + goto done;
4014 + }
4015 + }
4016 +
4017 + cpr3_debug(vreg, "Disabled\n");
4018 +done:
4019 + mutex_unlock(&ctrl->lock);
4020 +
4021 + return rc;
4022 +}
4023 +
4024 +static struct regulator_ops cpr3_regulator_ops = {
4025 + .enable = cpr3_regulator_enable,
4026 + .disable = cpr3_regulator_disable,
4027 + .is_enabled = cpr3_regulator_is_enabled,
4028 + .set_voltage = cpr3_regulator_set_voltage,
4029 + .get_voltage = cpr3_regulator_get_voltage,
4030 + .list_voltage = cpr3_regulator_list_voltage,
4031 +};
4032 +
4033 +/**
4034 + * cpr3_print_result() - print CPR measurement results to the kernel log for
4035 + * debugging purposes
4036 + * @thread: Pointer to the CPR3 thread
4037 + *
4038 + * Return: None
4039 + */
4040 +static void cpr3_print_result(struct cpr3_thread *thread)
4041 +{
4042 + struct cpr3_controller *ctrl = thread->ctrl;
4043 + u32 result[3], busy, step_dn, step_up, error_steps, error, negative;
4044 + u32 quot_min, quot_max, ro_min, ro_max, step_quot_min, step_quot_max;
4045 + u32 sensor_min, sensor_max;
4046 + char *sign;
4047 +
4048 + result[0] = cpr3_read(ctrl, CPR3_REG_RESULT0(thread->thread_id));
4049 + result[1] = cpr3_read(ctrl, CPR3_REG_RESULT1(thread->thread_id));
4050 + result[2] = cpr3_read(ctrl, CPR3_REG_RESULT2(thread->thread_id));
4051 +
4052 + busy = !!(result[0] & CPR3_RESULT0_BUSY_MASK);
4053 + step_dn = !!(result[0] & CPR3_RESULT0_STEP_DN_MASK);
4054 + step_up = !!(result[0] & CPR3_RESULT0_STEP_UP_MASK);
4055 + error_steps = (result[0] & CPR3_RESULT0_ERROR_STEPS_MASK)
4056 + >> CPR3_RESULT0_ERROR_STEPS_SHIFT;
4057 + error = (result[0] & CPR3_RESULT0_ERROR_MASK)
4058 + >> CPR3_RESULT0_ERROR_SHIFT;
4059 + negative = !!(result[0] & CPR3_RESULT0_NEGATIVE_MASK);
4060 +
4061 + quot_min = (result[1] & CPR3_RESULT1_QUOT_MIN_MASK)
4062 + >> CPR3_RESULT1_QUOT_MIN_SHIFT;
4063 + quot_max = (result[1] & CPR3_RESULT1_QUOT_MAX_MASK)
4064 + >> CPR3_RESULT1_QUOT_MAX_SHIFT;
4065 + ro_min = (result[1] & CPR3_RESULT1_RO_MIN_MASK)
4066 + >> CPR3_RESULT1_RO_MIN_SHIFT;
4067 + ro_max = (result[1] & CPR3_RESULT1_RO_MAX_MASK)
4068 + >> CPR3_RESULT1_RO_MAX_SHIFT;
4069 +
4070 + step_quot_min = (result[2] & CPR3_RESULT2_STEP_QUOT_MIN_MASK)
4071 + >> CPR3_RESULT2_STEP_QUOT_MIN_SHIFT;
4072 + step_quot_max = (result[2] & CPR3_RESULT2_STEP_QUOT_MAX_MASK)
4073 + >> CPR3_RESULT2_STEP_QUOT_MAX_SHIFT;
4074 + sensor_min = (result[2] & CPR3_RESULT2_SENSOR_MIN_MASK)
4075 + >> CPR3_RESULT2_SENSOR_MIN_SHIFT;
4076 + sensor_max = (result[2] & CPR3_RESULT2_SENSOR_MAX_MASK)
4077 + >> CPR3_RESULT2_SENSOR_MAX_SHIFT;
4078 +
4079 + sign = negative ? "-" : "";
4080 + cpr3_debug(ctrl, "thread %u: busy=%u, step_dn=%u, step_up=%u, error_steps=%s%u, error=%s%u\n",
4081 + thread->thread_id, busy, step_dn, step_up, sign, error_steps,
4082 + sign, error);
4083 + cpr3_debug(ctrl, "thread %u: quot_min=%u, quot_max=%u, ro_min=%u, ro_max=%u\n",
4084 + thread->thread_id, quot_min, quot_max, ro_min, ro_max);
4085 + cpr3_debug(ctrl, "thread %u: step_quot_min=%u, step_quot_max=%u, sensor_min=%u, sensor_max=%u\n",
4086 + thread->thread_id, step_quot_min, step_quot_max, sensor_min,
4087 + sensor_max);
4088 +}
4089 +
4090 +/**
4091 + * cpr3_thread_busy() - returns if the specified CPR3 thread is busy taking
4092 + * a measurement
4093 + * @thread: Pointer to the CPR3 thread
4094 + *
4095 + * Return: CPR3 busy status
4096 + */
4097 +static bool cpr3_thread_busy(struct cpr3_thread *thread)
4098 +{
4099 + u32 result;
4100 +
4101 + result = cpr3_read(thread->ctrl, CPR3_REG_RESULT0(thread->thread_id));
4102 +
4103 + return !!(result & CPR3_RESULT0_BUSY_MASK);
4104 +}
4105 +
4106 +/**
4107 + * cpr3_irq_handler() - CPR interrupt handler callback function used for
4108 + * software closed-loop operation
4109 + * @irq: CPR interrupt number
4110 + * @data: Private data corresponding to the CPR3 controller
4111 + * pointer
4112 + *
4113 + * This function increases or decreases the vdd supply voltage based upon the
4114 + * CPR controller recommendation.
4115 + *
4116 + * Return: IRQ_HANDLED
4117 + */
4118 +static irqreturn_t cpr3_irq_handler(int irq, void *data)
4119 +{
4120 + struct cpr3_controller *ctrl = data;
4121 + struct cpr3_corner *aggr = &ctrl->aggr_corner;
4122 + u32 cont = CPR3_CONT_CMD_NACK;
4123 + u32 reg_last_measurement = 0;
4124 + struct cpr3_regulator *vreg;
4125 + struct cpr3_corner *corner;
4126 + unsigned long flags;
4127 + int i, j, new_volt, last_volt, dynamic_floor_volt, rc;
4128 + u32 irq_en, status, cpr_status, ctl;
4129 + bool up, down;
4130 +
4131 + mutex_lock(&ctrl->lock);
4132 +
4133 + if (!ctrl->cpr_enabled) {
4134 + cpr3_debug(ctrl, "CPR interrupt received but CPR is disabled\n");
4135 + mutex_unlock(&ctrl->lock);
4136 + return IRQ_HANDLED;
4137 + } else if (ctrl->use_hw_closed_loop) {
4138 + cpr3_debug(ctrl, "CPR interrupt received but CPR is using HW closed-loop\n");
4139 + goto done;
4140 + }
4141 +
4142 + /*
4143 + * CPR IRQ status checking and CPR controller disabling must happen
4144 + * atomically and without invening delay in order to avoid an interrupt
4145 + * storm caused by the handler racing with the CPR controller.
4146 + */
4147 + local_irq_save(flags);
4148 + preempt_disable();
4149 +
4150 + status = cpr3_read(ctrl, CPR3_REG_IRQ_STATUS);
4151 + up = status & CPR3_IRQ_UP;
4152 + down = status & CPR3_IRQ_DOWN;
4153 +
4154 + if (!up && !down) {
4155 + /*
4156 + * Toggle the CPR controller off and then back on since the
4157 + * hardware and software states are out of sync. This condition
4158 + * occurs after an aging measurement completes as the CPR IRQ
4159 + * physically triggers during the aging measurement but the
4160 + * handler is stuck waiting on the mutex lock.
4161 + */
4162 + cpr3_ctrl_loop_disable(ctrl);
4163 +
4164 + local_irq_restore(flags);
4165 + preempt_enable();
4166 +
4167 + /* Wait for the loop disable write to complete */
4168 + mb();
4169 +
4170 + /* Wait for BUSY=1 and LOOP_EN=0 in CPR controller registers. */
4171 + for (i = 0; i < CPR3_REGISTER_WRITE_DELAY_US / 10; i++) {
4172 + cpr_status = cpr3_read(ctrl, CPR3_REG_CPR_STATUS);
4173 + ctl = cpr3_read(ctrl, CPR3_REG_CPR_CTL);
4174 + if (cpr_status & CPR3_CPR_STATUS_BUSY_MASK
4175 + && (ctl & CPR3_CPR_CTL_LOOP_EN_MASK)
4176 + == CPR3_CPR_CTL_LOOP_DISABLE)
4177 + break;
4178 + udelay(10);
4179 + }
4180 + if (i == CPR3_REGISTER_WRITE_DELAY_US / 10)
4181 + cpr3_debug(ctrl, "CPR controller not disabled after %d us\n",
4182 + CPR3_REGISTER_WRITE_DELAY_US);
4183 +
4184 + /* Clear interrupt status */
4185 + cpr3_write(ctrl, CPR3_REG_IRQ_CLEAR,
4186 + CPR3_IRQ_UP | CPR3_IRQ_DOWN);
4187 +
4188 + /* Wait for the interrupt clearing write to complete */
4189 + mb();
4190 +
4191 + /* Wait for IRQ_STATUS register to be cleared. */
4192 + for (i = 0; i < CPR3_REGISTER_WRITE_DELAY_US / 10; i++) {
4193 + status = cpr3_read(ctrl, CPR3_REG_IRQ_STATUS);
4194 + if (!(status & (CPR3_IRQ_UP | CPR3_IRQ_DOWN)))
4195 + break;
4196 + udelay(10);
4197 + }
4198 + if (i == CPR3_REGISTER_WRITE_DELAY_US / 10)
4199 + cpr3_debug(ctrl, "CPR interrupts not cleared after %d us\n",
4200 + CPR3_REGISTER_WRITE_DELAY_US);
4201 +
4202 + cpr3_ctrl_loop_enable(ctrl);
4203 +
4204 + cpr3_debug(ctrl, "CPR interrupt received but no up or down status bit is set\n");
4205 +
4206 + mutex_unlock(&ctrl->lock);
4207 + return IRQ_HANDLED;
4208 + } else if (up && down) {
4209 + cpr3_debug(ctrl, "both up and down status bits set\n");
4210 + /* The up flag takes precedence over the down flag. */
4211 + down = false;
4212 + }
4213 +
4214 + if (ctrl->supports_hw_closed_loop)
4215 + reg_last_measurement
4216 + = cpr3_read(ctrl, CPR3_REG_LAST_MEASUREMENT);
4217 + dynamic_floor_volt = cpr3_regulator_get_dynamic_floor_volt(ctrl,
4218 + reg_last_measurement);
4219 +
4220 + local_irq_restore(flags);
4221 + preempt_enable();
4222 +
4223 + irq_en = aggr->irq_en;
4224 + last_volt = aggr->last_volt;
4225 +
4226 + for (i = 0; i < ctrl->thread_count; i++) {
4227 + if (cpr3_thread_busy(&ctrl->thread[i])) {
4228 + cpr3_debug(ctrl, "CPR thread %u busy when it should be waiting for SW cont\n",
4229 + ctrl->thread[i].thread_id);
4230 + goto done;
4231 + }
4232 + }
4233 +
4234 + new_volt = up ? last_volt + ctrl->step_volt
4235 + : last_volt - ctrl->step_volt;
4236 +
4237 + /* Re-enable UP/DOWN interrupt when its opposite is received. */
4238 + irq_en |= up ? CPR3_IRQ_DOWN : CPR3_IRQ_UP;
4239 +
4240 + if (new_volt > aggr->ceiling_volt) {
4241 + new_volt = aggr->ceiling_volt;
4242 + irq_en &= ~CPR3_IRQ_UP;
4243 + cpr3_debug(ctrl, "limiting to ceiling=%d uV\n",
4244 + aggr->ceiling_volt);
4245 + } else if (new_volt < aggr->floor_volt) {
4246 + new_volt = aggr->floor_volt;
4247 + irq_en &= ~CPR3_IRQ_DOWN;
4248 + cpr3_debug(ctrl, "limiting to floor=%d uV\n", aggr->floor_volt);
4249 + }
4250 +
4251 + if (down && new_volt < dynamic_floor_volt) {
4252 + /*
4253 + * The vdd-supply voltage should not be decreased below the
4254 + * dynamic floor voltage. However, it is not necessary (and
4255 + * counter productive) to force the voltage up to this level
4256 + * if it happened to be below it since the closed-loop voltage
4257 + * must have gotten there in a safe manner while the power
4258 + * domains for the CPR3 regulator imposing the dynamic floor
4259 + * were not bypassed.
4260 + */
4261 + new_volt = last_volt;
4262 + irq_en &= ~CPR3_IRQ_DOWN;
4263 + cpr3_debug(ctrl, "limiting to dynamic floor=%d uV\n",
4264 + dynamic_floor_volt);
4265 + }
4266 +
4267 + for (i = 0; i < ctrl->thread_count; i++)
4268 + cpr3_print_result(&ctrl->thread[i]);
4269 +
4270 + cpr3_debug(ctrl, "%s: new_volt=%d uV, last_volt=%d uV\n",
4271 + up ? "UP" : "DN", new_volt, last_volt);
4272 +
4273 + if (ctrl->proc_clock_throttle && last_volt == aggr->ceiling_volt
4274 + && new_volt < last_volt)
4275 + cpr3_write(ctrl, CPR3_REG_PD_THROTTLE,
4276 + ctrl->proc_clock_throttle);
4277 +
4278 + if (new_volt != last_volt) {
4279 + rc = cpr3_regulator_scale_vdd_voltage(ctrl, new_volt,
4280 + last_volt,
4281 + aggr);
4282 + if (rc) {
4283 + cpr3_err(ctrl, "scale_vdd() failed to set vdd=%d uV, rc=%d\n",
4284 + new_volt, rc);
4285 + goto done;
4286 + }
4287 + cont = CPR3_CONT_CMD_ACK;
4288 +
4289 + /*
4290 + * Update the closed-loop voltage for all regulators managed
4291 + * by this CPR controller.
4292 + */
4293 + for (i = 0; i < ctrl->thread_count; i++) {
4294 + for (j = 0; j < ctrl->thread[i].vreg_count; j++) {
4295 + vreg = &ctrl->thread[i].vreg[j];
4296 + cpr3_update_vreg_closed_loop_volt(vreg,
4297 + new_volt, reg_last_measurement);
4298 + }
4299 + }
4300 + }
4301 +
4302 + if (ctrl->proc_clock_throttle && new_volt == aggr->ceiling_volt)
4303 + cpr3_write(ctrl, CPR3_REG_PD_THROTTLE,
4304 + CPR3_PD_THROTTLE_DISABLE);
4305 +
4306 + corner = &ctrl->thread[0].vreg[0].corner[
4307 + ctrl->thread[0].vreg[0].current_corner];
4308 +
4309 + if (irq_en != aggr->irq_en) {
4310 + aggr->irq_en = irq_en;
4311 + cpr3_write(ctrl, CPR3_REG_IRQ_EN, irq_en);
4312 + }
4313 +
4314 + aggr->last_volt = new_volt;
4315 +
4316 +done:
4317 + /* Clear interrupt status */
4318 + cpr3_write(ctrl, CPR3_REG_IRQ_CLEAR, CPR3_IRQ_UP | CPR3_IRQ_DOWN);
4319 +
4320 + /* ACK or NACK the CPR controller */
4321 + cpr3_write(ctrl, CPR3_REG_CONT_CMD, cont);
4322 +
4323 + mutex_unlock(&ctrl->lock);
4324 + return IRQ_HANDLED;
4325 +}
4326 +
4327 +/**
4328 + * cpr3_ceiling_irq_handler() - CPR ceiling reached interrupt handler callback
4329 + * function used for hardware closed-loop operation
4330 + * @irq: CPR ceiling interrupt number
4331 + * @data: Private data corresponding to the CPR3 controller
4332 + * pointer
4333 + *
4334 + * This function disables processor clock throttling and closed-loop operation
4335 + * when the ceiling voltage is reached.
4336 + *
4337 + * Return: IRQ_HANDLED
4338 + */
4339 +static irqreturn_t cpr3_ceiling_irq_handler(int irq, void *data)
4340 +{
4341 + struct cpr3_controller *ctrl = data;
4342 + int volt;
4343 +
4344 + mutex_lock(&ctrl->lock);
4345 +
4346 + if (!ctrl->cpr_enabled) {
4347 + cpr3_debug(ctrl, "CPR ceiling interrupt received but CPR is disabled\n");
4348 + goto done;
4349 + } else if (!ctrl->use_hw_closed_loop) {
4350 + cpr3_debug(ctrl, "CPR ceiling interrupt received but CPR is using SW closed-loop\n");
4351 + goto done;
4352 + }
4353 +
4354 + volt = regulator_get_voltage(ctrl->vdd_regulator);
4355 + if (volt < 0) {
4356 + cpr3_err(ctrl, "could not get vdd voltage, rc=%d\n", volt);
4357 + goto done;
4358 + } else if (volt != ctrl->aggr_corner.ceiling_volt) {
4359 + cpr3_debug(ctrl, "CPR ceiling interrupt received but vdd voltage: %d uV != ceiling voltage: %d uV\n",
4360 + volt, ctrl->aggr_corner.ceiling_volt);
4361 + goto done;
4362 + }
4363 +
4364 + if (ctrl->ctrl_type == CPR_CTRL_TYPE_CPR3) {
4365 + /*
4366 + * Since the ceiling voltage has been reached, disable processor
4367 + * clock throttling as well as CPR closed-loop operation.
4368 + */
4369 + cpr3_write(ctrl, CPR3_REG_PD_THROTTLE,
4370 + CPR3_PD_THROTTLE_DISABLE);
4371 + cpr3_ctrl_loop_disable(ctrl);
4372 + cpr3_debug(ctrl, "CPR closed-loop and throttling disabled\n");
4373 + }
4374 +
4375 +done:
4376 + mutex_unlock(&ctrl->lock);
4377 + return IRQ_HANDLED;
4378 +}
4379 +
4380 +/**
4381 + * cpr3_regulator_vreg_register() - register a regulator device for a CPR3
4382 + * regulator
4383 + * @vreg: Pointer to the CPR3 regulator
4384 + *
4385 + * This function initializes all regulator framework related structures and then
4386 + * calls regulator_register() for the CPR3 regulator.
4387 + *
4388 + * Return: 0 on success, errno on failure
4389 + */
4390 +static int cpr3_regulator_vreg_register(struct cpr3_regulator *vreg)
4391 +{
4392 + struct regulator_config config = {};
4393 + struct regulator_desc *rdesc;
4394 + struct regulator_init_data *init_data;
4395 + int rc;
4396 +
4397 + init_data = of_get_regulator_init_data(vreg->thread->ctrl->dev,
4398 + vreg->of_node, &vreg->rdesc);
4399 + if (!init_data) {
4400 + cpr3_err(vreg, "regulator init data is missing\n");
4401 + return -EINVAL;
4402 + }
4403 +
4404 + init_data->constraints.input_uV = init_data->constraints.max_uV;
4405 + rdesc = &vreg->rdesc;
4406 + init_data->constraints.valid_ops_mask |=
4407 + REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS;
4408 + rdesc->ops = &cpr3_regulator_ops;
4409 +
4410 + rdesc->n_voltages = vreg->corner_count;
4411 + rdesc->name = init_data->constraints.name;
4412 + rdesc->owner = THIS_MODULE;
4413 + rdesc->type = REGULATOR_VOLTAGE;
4414 +
4415 + config.dev = vreg->thread->ctrl->dev;
4416 + config.driver_data = vreg;
4417 + config.init_data = init_data;
4418 + config.of_node = vreg->of_node;
4419 +
4420 + vreg->rdev = regulator_register(vreg->thread->ctrl->dev, rdesc, &config);
4421 + if (IS_ERR(vreg->rdev)) {
4422 + rc = PTR_ERR(vreg->rdev);
4423 + cpr3_err(vreg, "regulator_register failed, rc=%d\n", rc);
4424 + return rc;
4425 + }
4426 +
4427 + return 0;
4428 +}
4429 +
4430 +static int debugfs_int_set(void *data, u64 val)
4431 +{
4432 + *(int *)data = val;
4433 + return 0;
4434 +}
4435 +
4436 +static int debugfs_int_get(void *data, u64 *val)
4437 +{
4438 + *val = *(int *)data;
4439 + return 0;
4440 +}
4441 +DEFINE_SIMPLE_ATTRIBUTE(fops_int, debugfs_int_get, debugfs_int_set, "%lld\n");
4442 +DEFINE_SIMPLE_ATTRIBUTE(fops_int_ro, debugfs_int_get, NULL, "%lld\n");
4443 +DEFINE_SIMPLE_ATTRIBUTE(fops_int_wo, NULL, debugfs_int_set, "%lld\n");
4444 +
4445 +/**
4446 + * debugfs_create_int - create a debugfs file that is used to read and write a
4447 + * signed int value
4448 + * @name: Pointer to a string containing the name of the file to
4449 + * create
4450 + * @mode: The permissions that the file should have
4451 + * @parent: Pointer to the parent dentry for this file. This should
4452 + * be a directory dentry if set. If this parameter is
4453 + * %NULL, then the file will be created in the root of the
4454 + * debugfs filesystem.
4455 + * @value: Pointer to the variable that the file should read to and
4456 + * write from
4457 + *
4458 + * This function creates a file in debugfs with the given name that
4459 + * contains the value of the variable @value. If the @mode variable is so
4460 + * set, it can be read from, and written to.
4461 + *
4462 + * This function will return a pointer to a dentry if it succeeds. This
4463 + * pointer must be passed to the debugfs_remove() function when the file is
4464 + * to be removed. If an error occurs, %NULL will be returned.
4465 + */
4466 +static struct dentry *debugfs_create_int(const char *name, umode_t mode,
4467 + struct dentry *parent, int *value)
4468 +{
4469 + /* if there are no write bits set, make read only */
4470 + if (!(mode & S_IWUGO))
4471 + return debugfs_create_file(name, mode, parent, value,
4472 + &fops_int_ro);
4473 + /* if there are no read bits set, make write only */
4474 + if (!(mode & S_IRUGO))
4475 + return debugfs_create_file(name, mode, parent, value,
4476 + &fops_int_wo);
4477 +
4478 + return debugfs_create_file(name, mode, parent, value, &fops_int);
4479 +}
4480 +
4481 +static int debugfs_bool_get(void *data, u64 *val)
4482 +{
4483 + *val = *(bool *)data;
4484 + return 0;
4485 +}
4486 +DEFINE_SIMPLE_ATTRIBUTE(fops_bool_ro, debugfs_bool_get, NULL, "%lld\n");
4487 +
4488 +/**
4489 + * struct cpr3_debug_corner_info - data structure used by the
4490 + * cpr3_debugfs_create_corner_int function
4491 + * @vreg: Pointer to the CPR3 regulator
4492 + * @index: Pointer to the corner array index
4493 + * @member_offset: Offset in bytes from the beginning of struct cpr3_corner
4494 + * to the beginning of the value to be read from
4495 + * @corner: Pointer to the CPR3 corner array
4496 + */
4497 +struct cpr3_debug_corner_info {
4498 + struct cpr3_regulator *vreg;
4499 + int *index;
4500 + size_t member_offset;
4501 + struct cpr3_corner *corner;
4502 +};
4503 +
4504 +static int cpr3_debug_corner_int_get(void *data, u64 *val)
4505 +{
4506 + struct cpr3_debug_corner_info *info = data;
4507 + struct cpr3_controller *ctrl = info->vreg->thread->ctrl;
4508 + int i;
4509 +
4510 + mutex_lock(&ctrl->lock);
4511 +
4512 + i = *info->index;
4513 + if (i < 0)
4514 + i = 0;
4515 +
4516 + *val = *(int *)((char *)&info->vreg->corner[i] + info->member_offset);
4517 +
4518 + mutex_unlock(&ctrl->lock);
4519 +
4520 + return 0;
4521 +}
4522 +DEFINE_SIMPLE_ATTRIBUTE(cpr3_debug_corner_int_fops, cpr3_debug_corner_int_get,
4523 + NULL, "%lld\n");
4524 +
4525 +/**
4526 + * cpr3_debugfs_create_corner_int - create a debugfs file that is used to read
4527 + * a signed int value out of a CPR3 regulator's corner array
4528 + * @vreg: Pointer to the CPR3 regulator
4529 + * @name: Pointer to a string containing the name of the file to
4530 + * create
4531 + * @mode: The permissions that the file should have
4532 + * @parent: Pointer to the parent dentry for this file. This should
4533 + * be a directory dentry if set. If this parameter is
4534 + * %NULL, then the file will be created in the root of the
4535 + * debugfs filesystem.
4536 + * @index: Pointer to the corner array index
4537 + * @member_offset: Offset in bytes from the beginning of struct cpr3_corner
4538 + * to the beginning of the value to be read from
4539 + *
4540 + * This function creates a file in debugfs with the given name that
4541 + * contains the value of the int type variable vreg->corner[index].member
4542 + * where member_offset == offsetof(struct cpr3_corner, member).
4543 + */
4544 +static struct dentry *cpr3_debugfs_create_corner_int(
4545 + struct cpr3_regulator *vreg, const char *name, umode_t mode,
4546 + struct dentry *parent, int *index, size_t member_offset)
4547 +{
4548 + struct cpr3_debug_corner_info *info;
4549 +
4550 + info = devm_kzalloc(vreg->thread->ctrl->dev, sizeof(*info), GFP_KERNEL);
4551 + if (!info)
4552 + return NULL;
4553 +
4554 + info->vreg = vreg;
4555 + info->index = index;
4556 + info->member_offset = member_offset;
4557 +
4558 + return debugfs_create_file(name, mode, parent, info,
4559 + &cpr3_debug_corner_int_fops);
4560 +}
4561 +
4562 +static int cpr3_debug_quot_open(struct inode *inode, struct file *file)
4563 +{
4564 + struct cpr3_debug_corner_info *info = inode->i_private;
4565 + struct cpr3_thread *thread = info->vreg->thread;
4566 + int size, i, pos;
4567 + u32 *quot;
4568 + char *buf;
4569 +
4570 + /*
4571 + * Max size:
4572 + * - 10 digits + ' ' or '\n' = 11 bytes per number
4573 + * - terminating '\0'
4574 + */
4575 + size = CPR3_RO_COUNT * 11;
4576 + buf = kzalloc(size + 1, GFP_KERNEL);
4577 + if (!buf)
4578 + return -ENOMEM;
4579 +
4580 + file->private_data = buf;
4581 +
4582 + mutex_lock(&thread->ctrl->lock);
4583 +
4584 + quot = info->corner[*info->index].target_quot;
4585 +
4586 + for (i = 0, pos = 0; i < CPR3_RO_COUNT; i++)
4587 + pos += scnprintf(buf + pos, size - pos, "%u%c",
4588 + quot[i], i < CPR3_RO_COUNT - 1 ? ' ' : '\n');
4589 +
4590 + mutex_unlock(&thread->ctrl->lock);
4591 +
4592 + return nonseekable_open(inode, file);
4593 +}
4594 +
4595 +static ssize_t cpr3_debug_quot_read(struct file *file, char __user *buf,
4596 + size_t len, loff_t *ppos)
4597 +{
4598 + return simple_read_from_buffer(buf, len, ppos, file->private_data,
4599 + strlen(file->private_data));
4600 +}
4601 +
4602 +static int cpr3_debug_quot_release(struct inode *inode, struct file *file)
4603 +{
4604 + kfree(file->private_data);
4605 +
4606 + return 0;
4607 +}
4608 +
4609 +static const struct file_operations cpr3_debug_quot_fops = {
4610 + .owner = THIS_MODULE,
4611 + .open = cpr3_debug_quot_open,
4612 + .release = cpr3_debug_quot_release,
4613 + .read = cpr3_debug_quot_read,
4614 +};
4615 +
4616 +/**
4617 + * cpr3_regulator_debugfs_corner_add() - add debugfs files to expose
4618 + * configuration data for the CPR corner
4619 + * @vreg: Pointer to the CPR3 regulator
4620 + * @corner_dir: Pointer to the parent corner dentry for the new files
4621 + * @index: Pointer to the corner array index
4622 + *
4623 + * Return: none
4624 + */
4625 +static void cpr3_regulator_debugfs_corner_add(struct cpr3_regulator *vreg,
4626 + struct dentry *corner_dir, int *index)
4627 +{
4628 + struct cpr3_debug_corner_info *info;
4629 + struct dentry *temp;
4630 +
4631 + temp = cpr3_debugfs_create_corner_int(vreg, "floor_volt", S_IRUGO,
4632 + corner_dir, index, offsetof(struct cpr3_corner, floor_volt));
4633 + if (IS_ERR_OR_NULL(temp)) {
4634 + cpr3_err(vreg, "floor_volt debugfs file creation failed\n");
4635 + return;
4636 + }
4637 +
4638 + temp = cpr3_debugfs_create_corner_int(vreg, "ceiling_volt", S_IRUGO,
4639 + corner_dir, index, offsetof(struct cpr3_corner, ceiling_volt));
4640 + if (IS_ERR_OR_NULL(temp)) {
4641 + cpr3_err(vreg, "ceiling_volt debugfs file creation failed\n");
4642 + return;
4643 + }
4644 +
4645 + temp = cpr3_debugfs_create_corner_int(vreg, "open_loop_volt", S_IRUGO,
4646 + corner_dir, index,
4647 + offsetof(struct cpr3_corner, open_loop_volt));
4648 + if (IS_ERR_OR_NULL(temp)) {
4649 + cpr3_err(vreg, "open_loop_volt debugfs file creation failed\n");
4650 + return;
4651 + }
4652 +
4653 + temp = cpr3_debugfs_create_corner_int(vreg, "last_volt", S_IRUGO,
4654 + corner_dir, index, offsetof(struct cpr3_corner, last_volt));
4655 + if (IS_ERR_OR_NULL(temp)) {
4656 + cpr3_err(vreg, "last_volt debugfs file creation failed\n");
4657 + return;
4658 + }
4659 +
4660 + info = devm_kzalloc(vreg->thread->ctrl->dev, sizeof(*info), GFP_KERNEL);
4661 + if (!info)
4662 + return;
4663 +
4664 + info->vreg = vreg;
4665 + info->index = index;
4666 + info->corner = vreg->corner;
4667 +
4668 + temp = debugfs_create_file("target_quots", S_IRUGO, corner_dir,
4669 + info, &cpr3_debug_quot_fops);
4670 + if (IS_ERR_OR_NULL(temp)) {
4671 + cpr3_err(vreg, "target_quots debugfs file creation failed\n");
4672 + return;
4673 + }
4674 +}
4675 +
4676 +/**
4677 + * cpr3_debug_corner_index_set() - debugfs callback used to change the
4678 + * value of the CPR3 regulator debug_corner index
4679 + * @data: Pointer to private data which is equal to the CPR3
4680 + * regulator pointer
4681 + * @val: New value for debug_corner
4682 + *
4683 + * Return: 0 on success, errno on failure
4684 + */
4685 +static int cpr3_debug_corner_index_set(void *data, u64 val)
4686 +{
4687 + struct cpr3_regulator *vreg = data;
4688 +
4689 + if (val < CPR3_CORNER_OFFSET || val > vreg->corner_count) {
4690 + cpr3_err(vreg, "invalid corner index %llu; allowed values: %d-%d\n",
4691 + val, CPR3_CORNER_OFFSET, vreg->corner_count);
4692 + return -EINVAL;
4693 + }
4694 +
4695 + mutex_lock(&vreg->thread->ctrl->lock);
4696 + vreg->debug_corner = val - CPR3_CORNER_OFFSET;
4697 + mutex_unlock(&vreg->thread->ctrl->lock);
4698 +
4699 + return 0;
4700 +}
4701 +
4702 +/**
4703 + * cpr3_debug_corner_index_get() - debugfs callback used to retrieve
4704 + * the value of the CPR3 regulator debug_corner index
4705 + * @data: Pointer to private data which is equal to the CPR3
4706 + * regulator pointer
4707 + * @val: Output parameter written with the value of
4708 + * debug_corner
4709 + *
4710 + * Return: 0 on success, errno on failure
4711 + */
4712 +static int cpr3_debug_corner_index_get(void *data, u64 *val)
4713 +{
4714 + struct cpr3_regulator *vreg = data;
4715 +
4716 + *val = vreg->debug_corner + CPR3_CORNER_OFFSET;
4717 +
4718 + return 0;
4719 +}
4720 +DEFINE_SIMPLE_ATTRIBUTE(cpr3_debug_corner_index_fops,
4721 + cpr3_debug_corner_index_get,
4722 + cpr3_debug_corner_index_set,
4723 + "%llu\n");
4724 +
4725 +/**
4726 + * cpr3_debug_current_corner_index_get() - debugfs callback used to retrieve
4727 + * the value of the CPR3 regulator current_corner index
4728 + * @data: Pointer to private data which is equal to the CPR3
4729 + * regulator pointer
4730 + * @val: Output parameter written with the value of
4731 + * current_corner
4732 + *
4733 + * Return: 0 on success, errno on failure
4734 + */
4735 +static int cpr3_debug_current_corner_index_get(void *data, u64 *val)
4736 +{
4737 + struct cpr3_regulator *vreg = data;
4738 +
4739 + *val = vreg->current_corner + CPR3_CORNER_OFFSET;
4740 +
4741 + return 0;
4742 +}
4743 +DEFINE_SIMPLE_ATTRIBUTE(cpr3_debug_current_corner_index_fops,
4744 + cpr3_debug_current_corner_index_get,
4745 + NULL, "%llu\n");
4746 +
4747 +/**
4748 + * cpr3_regulator_debugfs_vreg_add() - add debugfs files to expose configuration
4749 + * data for the CPR3 regulator
4750 + * @vreg: Pointer to the CPR3 regulator
4751 + * @thread_dir CPR3 thread debugfs directory handle
4752 + *
4753 + * Return: none
4754 + */
4755 +static void cpr3_regulator_debugfs_vreg_add(struct cpr3_regulator *vreg,
4756 + struct dentry *thread_dir)
4757 +{
4758 + struct dentry *temp, *corner_dir, *vreg_dir;
4759 +
4760 + vreg_dir = debugfs_create_dir(vreg->name, thread_dir);
4761 + if (IS_ERR_OR_NULL(vreg_dir)) {
4762 + cpr3_err(vreg, "%s debugfs directory creation failed\n",
4763 + vreg->name);
4764 + return;
4765 + }
4766 +
4767 + temp = debugfs_create_int("speed_bin_fuse", S_IRUGO, vreg_dir,
4768 + &vreg->speed_bin_fuse);
4769 + if (IS_ERR_OR_NULL(temp)) {
4770 + cpr3_err(vreg, "speed_bin_fuse debugfs file creation failed\n");
4771 + return;
4772 + }
4773 +
4774 + temp = debugfs_create_int("cpr_rev_fuse", S_IRUGO, vreg_dir,
4775 + &vreg->cpr_rev_fuse);
4776 + if (IS_ERR_OR_NULL(temp)) {
4777 + cpr3_err(vreg, "cpr_rev_fuse debugfs file creation failed\n");
4778 + return;
4779 + }
4780 +
4781 + temp = debugfs_create_int("fuse_combo", S_IRUGO, vreg_dir,
4782 + &vreg->fuse_combo);
4783 + if (IS_ERR_OR_NULL(temp)) {
4784 + cpr3_err(vreg, "fuse_combo debugfs file creation failed\n");
4785 + return;
4786 + }
4787 +
4788 + temp = debugfs_create_int("corner_count", S_IRUGO, vreg_dir,
4789 + &vreg->corner_count);
4790 + if (IS_ERR_OR_NULL(temp)) {
4791 + cpr3_err(vreg, "corner_count debugfs file creation failed\n");
4792 + return;
4793 + }
4794 +
4795 + corner_dir = debugfs_create_dir("corner", vreg_dir);
4796 + if (IS_ERR_OR_NULL(corner_dir)) {
4797 + cpr3_err(vreg, "corner debugfs directory creation failed\n");
4798 + return;
4799 + }
4800 +
4801 + temp = debugfs_create_file("index", S_IRUGO | S_IWUSR, corner_dir,
4802 + vreg, &cpr3_debug_corner_index_fops);
4803 + if (IS_ERR_OR_NULL(temp)) {
4804 + cpr3_err(vreg, "index debugfs file creation failed\n");
4805 + return;
4806 + }
4807 +
4808 + cpr3_regulator_debugfs_corner_add(vreg, corner_dir,
4809 + &vreg->debug_corner);
4810 +
4811 + corner_dir = debugfs_create_dir("current_corner", vreg_dir);
4812 + if (IS_ERR_OR_NULL(corner_dir)) {
4813 + cpr3_err(vreg, "current_corner debugfs directory creation failed\n");
4814 + return;
4815 + }
4816 +
4817 + temp = debugfs_create_file("index", S_IRUGO, corner_dir,
4818 + vreg, &cpr3_debug_current_corner_index_fops);
4819 + if (IS_ERR_OR_NULL(temp)) {
4820 + cpr3_err(vreg, "index debugfs file creation failed\n");
4821 + return;
4822 + }
4823 +
4824 + cpr3_regulator_debugfs_corner_add(vreg, corner_dir,
4825 + &vreg->current_corner);
4826 +}
4827 +
4828 +/**
4829 + * cpr3_regulator_debugfs_thread_add() - add debugfs files to expose
4830 + * configuration data for the CPR thread
4831 + * @thread: Pointer to the CPR3 thread
4832 + *
4833 + * Return: none
4834 + */
4835 +static void cpr3_regulator_debugfs_thread_add(struct cpr3_thread *thread)
4836 +{
4837 + struct cpr3_controller *ctrl = thread->ctrl;
4838 + struct dentry *aggr_dir, *temp, *thread_dir;
4839 + struct cpr3_debug_corner_info *info;
4840 + char buf[20];
4841 + int *index;
4842 + int i;
4843 +
4844 + scnprintf(buf, sizeof(buf), "thread%u", thread->thread_id);
4845 + thread_dir = debugfs_create_dir(buf, thread->ctrl->debugfs);
4846 + if (IS_ERR_OR_NULL(thread_dir)) {
4847 + cpr3_err(ctrl, "thread %u %s debugfs directory creation failed\n",
4848 + thread->thread_id, buf);
4849 + return;
4850 + }
4851 +
4852 + aggr_dir = debugfs_create_dir("max_aggregated_params", thread_dir);
4853 + if (IS_ERR_OR_NULL(aggr_dir)) {
4854 + cpr3_err(ctrl, "thread %u max_aggregated_params debugfs directory creation failed\n",
4855 + thread->thread_id);
4856 + return;
4857 + }
4858 +
4859 + temp = debugfs_create_int("floor_volt", S_IRUGO, aggr_dir,
4860 + &thread->aggr_corner.floor_volt);
4861 + if (IS_ERR_OR_NULL(temp)) {
4862 + cpr3_err(ctrl, "thread %u aggr floor_volt debugfs file creation failed\n",
4863 + thread->thread_id);
4864 + return;
4865 + }
4866 +
4867 + temp = debugfs_create_int("ceiling_volt", S_IRUGO, aggr_dir,
4868 + &thread->aggr_corner.ceiling_volt);
4869 + if (IS_ERR_OR_NULL(temp)) {
4870 + cpr3_err(ctrl, "thread %u aggr ceiling_volt debugfs file creation failed\n",
4871 + thread->thread_id);
4872 + return;
4873 + }
4874 +
4875 + temp = debugfs_create_int("open_loop_volt", S_IRUGO, aggr_dir,
4876 + &thread->aggr_corner.open_loop_volt);
4877 + if (IS_ERR_OR_NULL(temp)) {
4878 + cpr3_err(ctrl, "thread %u aggr open_loop_volt debugfs file creation failed\n",
4879 + thread->thread_id);
4880 + return;
4881 + }
4882 +
4883 + temp = debugfs_create_int("last_volt", S_IRUGO, aggr_dir,
4884 + &thread->aggr_corner.last_volt);
4885 + if (IS_ERR_OR_NULL(temp)) {
4886 + cpr3_err(ctrl, "thread %u aggr last_volt debugfs file creation failed\n",
4887 + thread->thread_id);
4888 + return;
4889 + }
4890 +
4891 + info = devm_kzalloc(thread->ctrl->dev, sizeof(*info), GFP_KERNEL);
4892 + index = devm_kzalloc(thread->ctrl->dev, sizeof(*index), GFP_KERNEL);
4893 + if (!info || !index)
4894 + return;
4895 + *index = 0;
4896 + info->vreg = &thread->vreg[0];
4897 + info->index = index;
4898 + info->corner = &thread->aggr_corner;
4899 +
4900 + temp = debugfs_create_file("target_quots", S_IRUGO, aggr_dir,
4901 + info, &cpr3_debug_quot_fops);
4902 + if (IS_ERR_OR_NULL(temp)) {
4903 + cpr3_err(ctrl, "thread %u target_quots debugfs file creation failed\n",
4904 + thread->thread_id);
4905 + return;
4906 + }
4907 +
4908 + for (i = 0; i < thread->vreg_count; i++)
4909 + cpr3_regulator_debugfs_vreg_add(&thread->vreg[i], thread_dir);
4910 +}
4911 +
4912 +/**
4913 + * cpr3_debug_closed_loop_enable_set() - debugfs callback used to change the
4914 + * value of the CPR controller cpr_allowed_sw flag which enables or
4915 + * disables closed-loop operation
4916 + * @data: Pointer to private data which is equal to the CPR
4917 + * controller pointer
4918 + * @val: New value for cpr_allowed_sw
4919 + *
4920 + * Return: 0 on success, errno on failure
4921 + */
4922 +static int cpr3_debug_closed_loop_enable_set(void *data, u64 val)
4923 +{
4924 + struct cpr3_controller *ctrl = data;
4925 + bool enable = !!val;
4926 + int rc;
4927 +
4928 + mutex_lock(&ctrl->lock);
4929 +
4930 + if (ctrl->cpr_allowed_sw == enable)
4931 + goto done;
4932 +
4933 + if (enable && !ctrl->cpr_allowed_hw) {
4934 + cpr3_err(ctrl, "CPR closed-loop operation is not allowed\n");
4935 + goto done;
4936 + }
4937 +
4938 + ctrl->cpr_allowed_sw = enable;
4939 +
4940 + rc = cpr3_regulator_update_ctrl_state(ctrl);
4941 + if (rc) {
4942 + cpr3_err(ctrl, "could not change CPR enable state=%u, rc=%d\n",
4943 + enable, rc);
4944 + goto done;
4945 + }
4946 +
4947 + if (ctrl->proc_clock_throttle && !ctrl->cpr_enabled) {
4948 + rc = cpr3_clock_enable(ctrl);
4949 + if (rc) {
4950 + cpr3_err(ctrl, "clock enable failed, rc=%d\n",
4951 + rc);
4952 + goto done;
4953 + }
4954 + ctrl->cpr_enabled = true;
4955 +
4956 + cpr3_write(ctrl, CPR3_REG_PD_THROTTLE,
4957 + CPR3_PD_THROTTLE_DISABLE);
4958 +
4959 + cpr3_clock_disable(ctrl);
4960 + ctrl->cpr_enabled = false;
4961 + }
4962 +
4963 + cpr3_debug(ctrl, "closed-loop=%s\n", enable ? "enabled" : "disabled");
4964 +done:
4965 + mutex_unlock(&ctrl->lock);
4966 + return 0;
4967 +}
4968 +
4969 +/**
4970 + * cpr3_debug_closed_loop_enable_get() - debugfs callback used to retrieve
4971 + * the value of the CPR controller cpr_allowed_sw flag which
4972 + * indicates if closed-loop operation is enabled
4973 + * @data: Pointer to private data which is equal to the CPR
4974 + * controller pointer
4975 + * @val: Output parameter written with the value of
4976 + * cpr_allowed_sw
4977 + *
4978 + * Return: 0 on success, errno on failure
4979 + */
4980 +static int cpr3_debug_closed_loop_enable_get(void *data, u64 *val)
4981 +{
4982 + struct cpr3_controller *ctrl = data;
4983 +
4984 + *val = ctrl->cpr_allowed_sw;
4985 +
4986 + return 0;
4987 +}
4988 +DEFINE_SIMPLE_ATTRIBUTE(cpr3_debug_closed_loop_enable_fops,
4989 + cpr3_debug_closed_loop_enable_get,
4990 + cpr3_debug_closed_loop_enable_set,
4991 + "%llu\n");
4992 +
4993 +/**
4994 + * cpr3_debug_hw_closed_loop_enable_set() - debugfs callback used to change the
4995 + * value of the CPR controller use_hw_closed_loop flag which
4996 + * switches between software closed-loop and hardware closed-loop
4997 + * operation for CPR3 and CPR4 controllers and between open-loop
4998 + * and full hardware closed-loop operation for CPRh controllers.
4999 + * @data: Pointer to private data which is equal to the CPR
5000 + * controller pointer
5001 + * @val: New value for use_hw_closed_loop
5002 + *
5003 + * Return: 0 on success, errno on failure
5004 + */
5005 +static int cpr3_debug_hw_closed_loop_enable_set(void *data, u64 val)
5006 +{
5007 + struct cpr3_controller *ctrl = data;
5008 + bool use_hw_closed_loop = !!val;
5009 + struct cpr3_regulator *vreg;
5010 + bool cpr_enabled;
5011 + int i, j, k, rc;
5012 +
5013 + mutex_lock(&ctrl->lock);
5014 +
5015 + if (ctrl->use_hw_closed_loop == use_hw_closed_loop)
5016 + goto done;
5017 +
5018 + if (ctrl->ctrl_type == CPR_CTRL_TYPE_CPR4) {
5019 + rc = cpr3_ctrl_clear_cpr4_config(ctrl);
5020 + if (rc) {
5021 + cpr3_err(ctrl, "failed to clear CPR4 configuration,rc=%d\n",
5022 + rc);
5023 + goto done;
5024 + }
5025 + }
5026 +
5027 + cpr3_ctrl_loop_disable(ctrl);
5028 +
5029 + ctrl->use_hw_closed_loop = use_hw_closed_loop;
5030 +
5031 + cpr_enabled = ctrl->cpr_enabled;
5032 +
5033 + /* Ensure that CPR clocks are enabled before writing to registers. */
5034 + if (!cpr_enabled) {
5035 + rc = cpr3_clock_enable(ctrl);
5036 + if (rc) {
5037 + cpr3_err(ctrl, "clock enable failed, rc=%d\n", rc);
5038 + goto done;
5039 + }
5040 + ctrl->cpr_enabled = true;
5041 + }
5042 +
5043 + if (ctrl->use_hw_closed_loop)
5044 + cpr3_write(ctrl, CPR3_REG_IRQ_EN, 0);
5045 +
5046 + if (ctrl->ctrl_type == CPR_CTRL_TYPE_CPR4) {
5047 + cpr3_masked_write(ctrl, CPR4_REG_MARGIN_ADJ_CTL,
5048 + CPR4_MARGIN_ADJ_CTL_HW_CLOSED_LOOP_EN_MASK,
5049 + ctrl->use_hw_closed_loop
5050 + ? CPR4_MARGIN_ADJ_CTL_HW_CLOSED_LOOP_ENABLE
5051 + : CPR4_MARGIN_ADJ_CTL_HW_CLOSED_LOOP_DISABLE);
5052 + } else if (ctrl->ctrl_type == CPR_CTRL_TYPE_CPR3) {
5053 + cpr3_write(ctrl, CPR3_REG_HW_CLOSED_LOOP,
5054 + ctrl->use_hw_closed_loop
5055 + ? CPR3_HW_CLOSED_LOOP_ENABLE
5056 + : CPR3_HW_CLOSED_LOOP_DISABLE);
5057 + }
5058 +
5059 + /* Turn off CPR clocks if they were off before this function call. */
5060 + if (!cpr_enabled) {
5061 + cpr3_clock_disable(ctrl);
5062 + ctrl->cpr_enabled = false;
5063 + }
5064 +
5065 + if (ctrl->use_hw_closed_loop && ctrl->ctrl_type == CPR_CTRL_TYPE_CPR3) {
5066 + rc = regulator_enable(ctrl->vdd_limit_regulator);
5067 + if (rc) {
5068 + cpr3_err(ctrl, "CPR limit regulator enable failed, rc=%d\n",
5069 + rc);
5070 + goto done;
5071 + }
5072 + } else if (!ctrl->use_hw_closed_loop
5073 + && ctrl->ctrl_type == CPR_CTRL_TYPE_CPR3) {
5074 + rc = regulator_disable(ctrl->vdd_limit_regulator);
5075 + if (rc) {
5076 + cpr3_err(ctrl, "CPR limit regulator disable failed, rc=%d\n",
5077 + rc);
5078 + goto done;
5079 + }
5080 + }
5081 +
5082 + /*
5083 + * Due to APM and mem-acc floor restriction constraints,
5084 + * the closed-loop voltage may be different when using
5085 + * software closed-loop vs hardware closed-loop. Therefore,
5086 + * reset the cached closed-loop voltage for all corners to the
5087 + * corresponding open-loop voltage when switching between
5088 + * SW and HW closed-loop mode.
5089 + */
5090 + for (i = 0; i < ctrl->thread_count; i++) {
5091 + for (j = 0; j < ctrl->thread[i].vreg_count; j++) {
5092 + vreg = &ctrl->thread[i].vreg[j];
5093 + for (k = 0; k < vreg->corner_count; k++)
5094 + vreg->corner[k].last_volt
5095 + = vreg->corner[k].open_loop_volt;
5096 + }
5097 + }
5098 +
5099 + /* Skip last_volt caching */
5100 + ctrl->last_corner_was_closed_loop = false;
5101 +
5102 + rc = cpr3_regulator_update_ctrl_state(ctrl);
5103 + if (rc) {
5104 + cpr3_err(ctrl, "could not change CPR HW closed-loop enable state=%u, rc=%d\n",
5105 + use_hw_closed_loop, rc);
5106 + goto done;
5107 + }
5108 +
5109 + cpr3_debug(ctrl, "CPR mode=%s\n",
5110 + use_hw_closed_loop ?
5111 + "HW closed-loop" : "SW closed-loop");
5112 +done:
5113 + mutex_unlock(&ctrl->lock);
5114 + return 0;
5115 +}
5116 +
5117 +/**
5118 + * cpr3_debug_hw_closed_loop_enable_get() - debugfs callback used to retrieve
5119 + * the value of the CPR controller use_hw_closed_loop flag which
5120 + * indicates if hardware closed-loop operation is being used in
5121 + * place of software closed-loop operation
5122 + * @data: Pointer to private data which is equal to the CPR
5123 + * controller pointer
5124 + * @val: Output parameter written with the value of
5125 + * use_hw_closed_loop
5126 + *
5127 + * Return: 0 on success, errno on failure
5128 + */
5129 +static int cpr3_debug_hw_closed_loop_enable_get(void *data, u64 *val)
5130 +{
5131 + struct cpr3_controller *ctrl = data;
5132 +
5133 + *val = ctrl->use_hw_closed_loop;
5134 +
5135 + return 0;
5136 +}
5137 +DEFINE_SIMPLE_ATTRIBUTE(cpr3_debug_hw_closed_loop_enable_fops,
5138 + cpr3_debug_hw_closed_loop_enable_get,
5139 + cpr3_debug_hw_closed_loop_enable_set,
5140 + "%llu\n");
5141 +
5142 +/**
5143 + * cpr3_debug_trigger_aging_measurement_set() - debugfs callback used to trigger
5144 + * another CPR measurement
5145 + * @data: Pointer to private data which is equal to the CPR
5146 + * controller pointer
5147 + * @val: Unused
5148 + *
5149 + * Return: 0 on success, errno on failure
5150 + */
5151 +static int cpr3_debug_trigger_aging_measurement_set(void *data, u64 val)
5152 +{
5153 + struct cpr3_controller *ctrl = data;
5154 + int rc;
5155 +
5156 + mutex_lock(&ctrl->lock);
5157 +
5158 + if (ctrl->ctrl_type == CPR_CTRL_TYPE_CPR4) {
5159 + rc = cpr3_ctrl_clear_cpr4_config(ctrl);
5160 + if (rc) {
5161 + cpr3_err(ctrl, "failed to clear CPR4 configuration,rc=%d\n",
5162 + rc);
5163 + goto done;
5164 + }
5165 + }
5166 +
5167 + cpr3_ctrl_loop_disable(ctrl);
5168 +
5169 + cpr3_regulator_set_aging_ref_adjustment(ctrl, INT_MAX);
5170 + ctrl->aging_required = true;
5171 + ctrl->aging_succeeded = false;
5172 + ctrl->aging_failed = false;
5173 +
5174 + rc = cpr3_regulator_update_ctrl_state(ctrl);
5175 + if (rc) {
5176 + cpr3_err(ctrl, "could not update the CPR controller state, rc=%d\n",
5177 + rc);
5178 + goto done;
5179 + }
5180 +
5181 +done:
5182 + mutex_unlock(&ctrl->lock);
5183 + return 0;
5184 +}
5185 +DEFINE_SIMPLE_ATTRIBUTE(cpr3_debug_trigger_aging_measurement_fops,
5186 + NULL,
5187 + cpr3_debug_trigger_aging_measurement_set,
5188 + "%llu\n");
5189 +
5190 +/**
5191 + * cpr3_regulator_debugfs_ctrl_add() - add debugfs files to expose configuration
5192 + * data for the CPR controller
5193 + * @ctrl: Pointer to the CPR3 controller
5194 + *
5195 + * Return: none
5196 + */
5197 +static void cpr3_regulator_debugfs_ctrl_add(struct cpr3_controller *ctrl)
5198 +{
5199 + struct dentry *temp, *aggr_dir;
5200 + int i;
5201 +
5202 + /* Add cpr3-regulator base directory if it isn't present already. */
5203 + if (cpr3_debugfs_base == NULL) {
5204 + cpr3_debugfs_base = debugfs_create_dir("cpr3-regulator", NULL);
5205 + if (IS_ERR_OR_NULL(cpr3_debugfs_base)) {
5206 + cpr3_err(ctrl, "cpr3-regulator debugfs base directory creation failed\n");
5207 + cpr3_debugfs_base = NULL;
5208 + return;
5209 + }
5210 + }
5211 +
5212 + ctrl->debugfs = debugfs_create_dir(ctrl->name, cpr3_debugfs_base);
5213 + if (IS_ERR_OR_NULL(ctrl->debugfs)) {
5214 + cpr3_err(ctrl, "cpr3-regulator controller debugfs directory creation failed\n");
5215 + return;
5216 + }
5217 +
5218 + temp = debugfs_create_file("cpr_closed_loop_enable", S_IRUGO | S_IWUSR,
5219 + ctrl->debugfs, ctrl,
5220 + &cpr3_debug_closed_loop_enable_fops);
5221 + if (IS_ERR_OR_NULL(temp)) {
5222 + cpr3_err(ctrl, "cpr_closed_loop_enable debugfs file creation failed\n");
5223 + return;
5224 + }
5225 +
5226 + if (ctrl->supports_hw_closed_loop) {
5227 + temp = debugfs_create_file("use_hw_closed_loop",
5228 + S_IRUGO | S_IWUSR, ctrl->debugfs, ctrl,
5229 + &cpr3_debug_hw_closed_loop_enable_fops);
5230 + if (IS_ERR_OR_NULL(temp)) {
5231 + cpr3_err(ctrl, "use_hw_closed_loop debugfs file creation failed\n");
5232 + return;
5233 + }
5234 + }
5235 +
5236 + temp = debugfs_create_int("thread_count", S_IRUGO, ctrl->debugfs,
5237 + &ctrl->thread_count);
5238 + if (IS_ERR_OR_NULL(temp)) {
5239 + cpr3_err(ctrl, "thread_count debugfs file creation failed\n");
5240 + return;
5241 + }
5242 +
5243 + if (ctrl->apm) {
5244 + temp = debugfs_create_int("apm_threshold_volt", S_IRUGO,
5245 + ctrl->debugfs, &ctrl->apm_threshold_volt);
5246 + if (IS_ERR_OR_NULL(temp)) {
5247 + cpr3_err(ctrl, "apm_threshold_volt debugfs file creation failed\n");
5248 + return;
5249 + }
5250 + }
5251 +
5252 + if (ctrl->aging_required || ctrl->aging_succeeded
5253 + || ctrl->aging_failed) {
5254 + temp = debugfs_create_int("aging_adj_volt", S_IRUGO,
5255 + ctrl->debugfs, &ctrl->aging_ref_adjust_volt);
5256 + if (IS_ERR_OR_NULL(temp)) {
5257 + cpr3_err(ctrl, "aging_adj_volt debugfs file creation failed\n");
5258 + return;
5259 + }
5260 +
5261 + temp = debugfs_create_file("aging_succeeded", S_IRUGO,
5262 + ctrl->debugfs, &ctrl->aging_succeeded, &fops_bool_ro);
5263 + if (IS_ERR_OR_NULL(temp)) {
5264 + cpr3_err(ctrl, "aging_succeeded debugfs file creation failed\n");
5265 + return;
5266 + }
5267 +
5268 + temp = debugfs_create_file("aging_failed", S_IRUGO,
5269 + ctrl->debugfs, &ctrl->aging_failed, &fops_bool_ro);
5270 + if (IS_ERR_OR_NULL(temp)) {
5271 + cpr3_err(ctrl, "aging_failed debugfs file creation failed\n");
5272 + return;
5273 + }
5274 +
5275 + temp = debugfs_create_file("aging_trigger", S_IWUSR,
5276 + ctrl->debugfs, ctrl,
5277 + &cpr3_debug_trigger_aging_measurement_fops);
5278 + if (IS_ERR_OR_NULL(temp)) {
5279 + cpr3_err(ctrl, "aging_trigger debugfs file creation failed\n");
5280 + return;
5281 + }
5282 + }
5283 +
5284 + aggr_dir = debugfs_create_dir("max_aggregated_voltages", ctrl->debugfs);
5285 + if (IS_ERR_OR_NULL(aggr_dir)) {
5286 + cpr3_err(ctrl, "max_aggregated_voltages debugfs directory creation failed\n");
5287 + return;
5288 + }
5289 +
5290 + temp = debugfs_create_int("floor_volt", S_IRUGO, aggr_dir,
5291 + &ctrl->aggr_corner.floor_volt);
5292 + if (IS_ERR_OR_NULL(temp)) {
5293 + cpr3_err(ctrl, "aggr floor_volt debugfs file creation failed\n");
5294 + return;
5295 + }
5296 +
5297 + temp = debugfs_create_int("ceiling_volt", S_IRUGO, aggr_dir,
5298 + &ctrl->aggr_corner.ceiling_volt);
5299 + if (IS_ERR_OR_NULL(temp)) {
5300 + cpr3_err(ctrl, "aggr ceiling_volt debugfs file creation failed\n");
5301 + return;
5302 + }
5303 +
5304 + temp = debugfs_create_int("open_loop_volt", S_IRUGO, aggr_dir,
5305 + &ctrl->aggr_corner.open_loop_volt);
5306 + if (IS_ERR_OR_NULL(temp)) {
5307 + cpr3_err(ctrl, "aggr open_loop_volt debugfs file creation failed\n");
5308 + return;
5309 + }
5310 +
5311 + temp = debugfs_create_int("last_volt", S_IRUGO, aggr_dir,
5312 + &ctrl->aggr_corner.last_volt);
5313 + if (IS_ERR_OR_NULL(temp)) {
5314 + cpr3_err(ctrl, "aggr last_volt debugfs file creation failed\n");
5315 + return;
5316 + }
5317 +
5318 + for (i = 0; i < ctrl->thread_count; i++)
5319 + cpr3_regulator_debugfs_thread_add(&ctrl->thread[i]);
5320 +}
5321 +
5322 +/**
5323 + * cpr3_regulator_debugfs_ctrl_remove() - remove debugfs files for the CPR
5324 + * controller
5325 + * @ctrl: Pointer to the CPR3 controller
5326 + *
5327 + * Note, this function must be called after the controller has been removed from
5328 + * cpr3_controller_list and while the cpr3_controller_list_mutex lock is held.
5329 + *
5330 + * Return: none
5331 + */
5332 +static void cpr3_regulator_debugfs_ctrl_remove(struct cpr3_controller *ctrl)
5333 +{
5334 + if (list_empty(&cpr3_controller_list)) {
5335 + debugfs_remove_recursive(cpr3_debugfs_base);
5336 + cpr3_debugfs_base = NULL;
5337 + } else {
5338 + debugfs_remove_recursive(ctrl->debugfs);
5339 + }
5340 +}
5341 +
5342 +/**
5343 + * cpr3_regulator_init_ctrl_data() - performs initialization of CPR controller
5344 + * elements
5345 + * @ctrl: Pointer to the CPR3 controller
5346 + *
5347 + * Return: 0 on success, errno on failure
5348 + */
5349 +static int cpr3_regulator_init_ctrl_data(struct cpr3_controller *ctrl)
5350 +{
5351 + /* Read the initial vdd voltage from hardware. */
5352 + ctrl->aggr_corner.last_volt
5353 + = regulator_get_voltage(ctrl->vdd_regulator);
5354 + if (ctrl->aggr_corner.last_volt < 0) {
5355 + cpr3_err(ctrl, "regulator_get_voltage(vdd) failed, rc=%d\n",
5356 + ctrl->aggr_corner.last_volt);
5357 + return ctrl->aggr_corner.last_volt;
5358 + }
5359 + ctrl->aggr_corner.open_loop_volt = ctrl->aggr_corner.last_volt;
5360 +
5361 + return 0;
5362 +}
5363 +
5364 +/**
5365 + * cpr3_regulator_init_vreg_data() - performs initialization of common CPR3
5366 + * regulator elements and validate aging configurations
5367 + * @vreg: Pointer to the CPR3 regulator
5368 + *
5369 + * Return: 0 on success, errno on failure
5370 + */
5371 +static int cpr3_regulator_init_vreg_data(struct cpr3_regulator *vreg)
5372 +{
5373 + int i, j;
5374 + bool init_aging;
5375 +
5376 + vreg->current_corner = CPR3_REGULATOR_CORNER_INVALID;
5377 + vreg->last_closed_loop_corner = CPR3_REGULATOR_CORNER_INVALID;
5378 +
5379 + init_aging = vreg->aging_allowed && vreg->thread->ctrl->aging_required;
5380 +
5381 + for (i = 0; i < vreg->corner_count; i++) {
5382 + vreg->corner[i].last_volt = vreg->corner[i].open_loop_volt;
5383 + vreg->corner[i].irq_en = CPR3_IRQ_UP | CPR3_IRQ_DOWN;
5384 +
5385 + vreg->corner[i].ro_mask = 0;
5386 + for (j = 0; j < CPR3_RO_COUNT; j++) {
5387 + if (vreg->corner[i].target_quot[j] == 0)
5388 + vreg->corner[i].ro_mask |= BIT(j);
5389 + }
5390 +
5391 + if (init_aging) {
5392 + vreg->corner[i].unaged_floor_volt
5393 + = vreg->corner[i].floor_volt;
5394 + vreg->corner[i].unaged_ceiling_volt
5395 + = vreg->corner[i].ceiling_volt;
5396 + vreg->corner[i].unaged_open_loop_volt
5397 + = vreg->corner[i].open_loop_volt;
5398 + }
5399 +
5400 + if (vreg->aging_allowed) {
5401 + if (vreg->corner[i].unaged_floor_volt <= 0) {
5402 + cpr3_err(vreg, "invalid unaged_floor_volt[%d] = %d\n",
5403 + i, vreg->corner[i].unaged_floor_volt);
5404 + return -EINVAL;
5405 + }
5406 + if (vreg->corner[i].unaged_ceiling_volt <= 0) {
5407 + cpr3_err(vreg, "invalid unaged_ceiling_volt[%d] = %d\n",
5408 + i, vreg->corner[i].unaged_ceiling_volt);
5409 + return -EINVAL;
5410 + }
5411 + if (vreg->corner[i].unaged_open_loop_volt <= 0) {
5412 + cpr3_err(vreg, "invalid unaged_open_loop_volt[%d] = %d\n",
5413 + i, vreg->corner[i].unaged_open_loop_volt);
5414 + return -EINVAL;
5415 + }
5416 + }
5417 + }
5418 +
5419 + if (vreg->aging_allowed && vreg->corner[vreg->aging_corner].ceiling_volt
5420 + > vreg->thread->ctrl->aging_ref_volt) {
5421 + cpr3_err(vreg, "aging corner %d ceiling voltage = %d > aging ref voltage = %d uV\n",
5422 + vreg->aging_corner,
5423 + vreg->corner[vreg->aging_corner].ceiling_volt,
5424 + vreg->thread->ctrl->aging_ref_volt);
5425 + return -EINVAL;
5426 + }
5427 +
5428 + return 0;
5429 +}
5430 +
5431 +/**
5432 + * cpr3_regulator_suspend() - perform common required CPR3 power down steps
5433 + * before the system enters suspend
5434 + * @ctrl: Pointer to the CPR3 controller
5435 + *
5436 + * Return: 0 on success, errno on failure
5437 + */
5438 +int cpr3_regulator_suspend(struct cpr3_controller *ctrl)
5439 +{
5440 + int rc;
5441 +
5442 + mutex_lock(&ctrl->lock);
5443 +
5444 + if (ctrl->ctrl_type == CPR_CTRL_TYPE_CPR4) {
5445 + rc = cpr3_ctrl_clear_cpr4_config(ctrl);
5446 + if (rc) {
5447 + cpr3_err(ctrl, "failed to clear CPR4 configuration,rc=%d\n",
5448 + rc);
5449 + mutex_unlock(&ctrl->lock);
5450 + return rc;
5451 + }
5452 + }
5453 +
5454 + cpr3_ctrl_loop_disable(ctrl);
5455 +
5456 + rc = cpr3_closed_loop_disable(ctrl);
5457 + if (rc)
5458 + cpr3_err(ctrl, "could not disable CPR, rc=%d\n", rc);
5459 +
5460 + ctrl->cpr_suspended = true;
5461 +
5462 + mutex_unlock(&ctrl->lock);
5463 + return 0;
5464 +}
5465 +
5466 +/**
5467 + * cpr3_regulator_resume() - perform common required CPR3 power up steps after
5468 + * the system resumes from suspend
5469 + * @ctrl: Pointer to the CPR3 controller
5470 + *
5471 + * Return: 0 on success, errno on failure
5472 + */
5473 +int cpr3_regulator_resume(struct cpr3_controller *ctrl)
5474 +{
5475 + int rc;
5476 +
5477 + mutex_lock(&ctrl->lock);
5478 +
5479 + ctrl->cpr_suspended = false;
5480 + rc = cpr3_regulator_update_ctrl_state(ctrl);
5481 + if (rc)
5482 + cpr3_err(ctrl, "could not enable CPR, rc=%d\n", rc);
5483 +
5484 + mutex_unlock(&ctrl->lock);
5485 + return 0;
5486 +}
5487 +
5488 +/**
5489 + * cpr3_regulator_validate_controller() - verify the data passed in via the
5490 + * cpr3_controller data structure
5491 + * @ctrl: Pointer to the CPR3 controller
5492 + *
5493 + * Return: 0 on success, errno on failure
5494 + */
5495 +static int cpr3_regulator_validate_controller(struct cpr3_controller *ctrl)
5496 +{
5497 + struct cpr3_thread *thread;
5498 + struct cpr3_regulator *vreg;
5499 + int i, j, allow_boost_vreg_count = 0;
5500 +
5501 + if (!ctrl->vdd_regulator) {
5502 + cpr3_err(ctrl, "vdd regulator missing\n");
5503 + return -EINVAL;
5504 + } else if (ctrl->sensor_count <= 0
5505 + || ctrl->sensor_count > CPR3_MAX_SENSOR_COUNT) {
5506 + cpr3_err(ctrl, "invalid CPR sensor count=%d\n",
5507 + ctrl->sensor_count);
5508 + return -EINVAL;
5509 + } else if (!ctrl->sensor_owner) {
5510 + cpr3_err(ctrl, "CPR sensor ownership table missing\n");
5511 + return -EINVAL;
5512 + }
5513 +
5514 + if (ctrl->aging_required) {
5515 + for (i = 0; i < ctrl->aging_sensor_count; i++) {
5516 + if (ctrl->aging_sensor[i].sensor_id
5517 + >= ctrl->sensor_count) {
5518 + cpr3_err(ctrl, "aging_sensor[%d] id=%u is not in the value range 0-%d",
5519 + i, ctrl->aging_sensor[i].sensor_id,
5520 + ctrl->sensor_count - 1);
5521 + return -EINVAL;
5522 + }
5523 + }
5524 + }
5525 +
5526 + for (i = 0; i < ctrl->thread_count; i++) {
5527 + thread = &ctrl->thread[i];
5528 + for (j = 0; j < thread->vreg_count; j++) {
5529 + vreg = &thread->vreg[j];
5530 + if (vreg->allow_boost)
5531 + allow_boost_vreg_count++;
5532 + }
5533 + }
5534 +
5535 + if (allow_boost_vreg_count > 1) {
5536 + /*
5537 + * Boost feature is not allowed to be used for more
5538 + * than one CPR3 regulator of a CPR3 controller.
5539 + */
5540 + cpr3_err(ctrl, "Boost feature is enabled for more than one regulator\n");
5541 + return -EINVAL;
5542 + }
5543 +
5544 + return 0;
5545 +}
5546 +
5547 +/**
5548 + * cpr3_panic_callback() - panic notification callback function. This function
5549 + * is invoked when a kernel panic occurs.
5550 + * @nfb: Notifier block pointer of CPR3 controller
5551 + * @event: Value passed unmodified to notifier function
5552 + * @data: Pointer passed unmodified to notifier function
5553 + *
5554 + * Return: NOTIFY_OK
5555 + */
5556 +static int cpr3_panic_callback(struct notifier_block *nfb,
5557 + unsigned long event, void *data)
5558 +{
5559 + struct cpr3_controller *ctrl = container_of(nfb,
5560 + struct cpr3_controller, panic_notifier);
5561 + struct cpr3_panic_regs_info *regs_info = ctrl->panic_regs_info;
5562 + struct cpr3_reg_info *reg;
5563 + int i = 0;
5564 +
5565 + for (i = 0; i < regs_info->reg_count; i++) {
5566 + reg = &(regs_info->regs[i]);
5567 + reg->value = readl_relaxed(reg->virt_addr);
5568 + pr_err("%s[0x%08x] = 0x%08x\n", reg->name, reg->addr,
5569 + reg->value);
5570 + }
5571 + /*
5572 + * Barrier to ensure that the information has been updated in the
5573 + * structure.
5574 + */
5575 + mb();
5576 +
5577 + return NOTIFY_OK;
5578 +}
5579 +
5580 +/**
5581 + * cpr3_regulator_register() - register the regulators for a CPR3 controller and
5582 + * perform CPR hardware initialization
5583 + * @pdev: Platform device pointer for the CPR3 controller
5584 + * @ctrl: Pointer to the CPR3 controller
5585 + *
5586 + * Return: 0 on success, errno on failure
5587 + */
5588 +int cpr3_regulator_register(struct platform_device *pdev,
5589 + struct cpr3_controller *ctrl)
5590 +{
5591 + struct device *dev = &pdev->dev;
5592 + struct resource *res;
5593 + int i, j, rc;
5594 +
5595 + if (!dev->of_node) {
5596 + dev_err(dev, "%s: Device tree node is missing\n", __func__);
5597 + return -EINVAL;
5598 + }
5599 +
5600 + if (!ctrl || !ctrl->name) {
5601 + dev_err(dev, "%s: CPR controller data is missing\n", __func__);
5602 + return -EINVAL;
5603 + }
5604 +
5605 + rc = cpr3_regulator_validate_controller(ctrl);
5606 + if (rc) {
5607 + cpr3_err(ctrl, "controller validation failed, rc=%d\n", rc);
5608 + return rc;
5609 + }
5610 +
5611 + mutex_init(&ctrl->lock);
5612 +
5613 + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cpr_ctrl");
5614 + if (!res || !res->start) {
5615 + cpr3_err(ctrl, "CPR controller address is missing\n");
5616 + return -ENXIO;
5617 + }
5618 + ctrl->cpr_ctrl_base = devm_ioremap(dev, res->start, resource_size(res));
5619 +
5620 + if (ctrl->aging_possible_mask) {
5621 + /*
5622 + * Aging possible register address is required if an aging
5623 + * possible mask has been specified.
5624 + */
5625 + res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
5626 + "aging_allowed");
5627 + if (!res || !res->start) {
5628 + cpr3_err(ctrl, "CPR aging allowed address is missing\n");
5629 + return -ENXIO;
5630 + }
5631 + ctrl->aging_possible_reg = devm_ioremap(dev, res->start,
5632 + resource_size(res));
5633 + }
5634 +
5635 + ctrl->irq = platform_get_irq_byname(pdev, "cpr");
5636 + if (ctrl->irq < 0) {
5637 + cpr3_err(ctrl, "missing CPR interrupt\n");
5638 + return ctrl->irq;
5639 + }
5640 +
5641 + if (ctrl->supports_hw_closed_loop) {
5642 + if (ctrl->ctrl_type == CPR_CTRL_TYPE_CPR3) {
5643 + ctrl->ceiling_irq = platform_get_irq_byname(pdev,
5644 + "ceiling");
5645 + if (ctrl->ceiling_irq < 0) {
5646 + cpr3_err(ctrl, "missing ceiling interrupt\n");
5647 + return ctrl->ceiling_irq;
5648 + }
5649 + }
5650 + }
5651 +
5652 + rc = cpr3_regulator_init_ctrl_data(ctrl);
5653 + if (rc) {
5654 + cpr3_err(ctrl, "CPR controller data initialization failed, rc=%d\n",
5655 + rc);
5656 + return rc;
5657 + }
5658 +
5659 + for (i = 0; i < ctrl->thread_count; i++) {
5660 + for (j = 0; j < ctrl->thread[i].vreg_count; j++) {
5661 + rc = cpr3_regulator_init_vreg_data(
5662 + &ctrl->thread[i].vreg[j]);
5663 + if (rc)
5664 + return rc;
5665 + cpr3_print_quots(&ctrl->thread[i].vreg[j]);
5666 + }
5667 + }
5668 +
5669 + /*
5670 + * Add the maximum possible aging voltage margin until it is possible
5671 + * to perform an aging measurement.
5672 + */
5673 + if (ctrl->aging_required)
5674 + cpr3_regulator_set_aging_ref_adjustment(ctrl, INT_MAX);
5675 +
5676 + rc = cpr3_regulator_init_ctrl(ctrl);
5677 + if (rc) {
5678 + cpr3_err(ctrl, "CPR controller initialization failed, rc=%d\n",
5679 + rc);
5680 + return rc;
5681 + }
5682 +
5683 + /* Register regulator devices for all threads. */
5684 + for (i = 0; i < ctrl->thread_count; i++) {
5685 + for (j = 0; j < ctrl->thread[i].vreg_count; j++) {
5686 + rc = cpr3_regulator_vreg_register(
5687 + &ctrl->thread[i].vreg[j]);
5688 + if (rc) {
5689 + cpr3_err(&ctrl->thread[i].vreg[j], "failed to register regulator, rc=%d\n",
5690 + rc);
5691 + goto free_regulators;
5692 + }
5693 + }
5694 + }
5695 +
5696 + rc = devm_request_threaded_irq(dev, ctrl->irq, NULL,
5697 + cpr3_irq_handler,
5698 + IRQF_ONESHOT |
5699 + IRQF_TRIGGER_RISING,
5700 + "cpr3", ctrl);
5701 + if (rc) {
5702 + cpr3_err(ctrl, "could not request IRQ %d, rc=%d\n",
5703 + ctrl->irq, rc);
5704 + goto free_regulators;
5705 + }
5706 +
5707 + if (ctrl->supports_hw_closed_loop &&
5708 + ctrl->ctrl_type == CPR_CTRL_TYPE_CPR3) {
5709 + rc = devm_request_threaded_irq(dev, ctrl->ceiling_irq, NULL,
5710 + cpr3_ceiling_irq_handler,
5711 + IRQF_ONESHOT | IRQF_TRIGGER_RISING,
5712 + "cpr3_ceiling", ctrl);
5713 + if (rc) {
5714 + cpr3_err(ctrl, "could not request ceiling IRQ %d, rc=%d\n",
5715 + ctrl->ceiling_irq, rc);
5716 + goto free_regulators;
5717 + }
5718 + }
5719 +
5720 + mutex_lock(&cpr3_controller_list_mutex);
5721 + cpr3_regulator_debugfs_ctrl_add(ctrl);
5722 + list_add(&ctrl->list, &cpr3_controller_list);
5723 + mutex_unlock(&cpr3_controller_list_mutex);
5724 +
5725 + if (ctrl->panic_regs_info) {
5726 + /* Register panic notification call back */
5727 + ctrl->panic_notifier.notifier_call = cpr3_panic_callback;
5728 + atomic_notifier_chain_register(&panic_notifier_list,
5729 + &ctrl->panic_notifier);
5730 + }
5731 +
5732 + return 0;
5733 +
5734 +free_regulators:
5735 + for (i = 0; i < ctrl->thread_count; i++)
5736 + for (j = 0; j < ctrl->thread[i].vreg_count; j++)
5737 + if (!IS_ERR_OR_NULL(ctrl->thread[i].vreg[j].rdev))
5738 + regulator_unregister(
5739 + ctrl->thread[i].vreg[j].rdev);
5740 + return rc;
5741 +}
5742 +
5743 +/**
5744 + * cpr3_open_loop_regulator_register() - register the regulators for a CPR3
5745 + * controller which will always work in Open loop and
5746 + * won't support close loop.
5747 + * @pdev: Platform device pointer for the CPR3 controller
5748 + * @ctrl: Pointer to the CPR3 controller
5749 + *
5750 + * Return: 0 on success, errno on failure
5751 + */
5752 +int cpr3_open_loop_regulator_register(struct platform_device *pdev,
5753 + struct cpr3_controller *ctrl)
5754 +{
5755 + struct device *dev = &pdev->dev;
5756 + struct cpr3_regulator *vreg;
5757 + int i, j, rc;
5758 +
5759 + if (!dev->of_node) {
5760 + dev_err(dev, "%s: Device tree node is missing\n", __func__);
5761 + return -EINVAL;
5762 + }
5763 +
5764 + if (!ctrl || !ctrl->name) {
5765 + dev_err(dev, "%s: CPR controller data is missing\n", __func__);
5766 + return -EINVAL;
5767 + }
5768 +
5769 + if (!ctrl->vdd_regulator) {
5770 + cpr3_err(ctrl, "vdd regulator missing\n");
5771 + return -EINVAL;
5772 + }
5773 +
5774 + mutex_init(&ctrl->lock);
5775 +
5776 + rc = cpr3_regulator_init_ctrl_data(ctrl);
5777 + if (rc) {
5778 + cpr3_err(ctrl, "CPR controller data initialization failed, rc=%d\n",
5779 + rc);
5780 + return rc;
5781 + }
5782 +
5783 + for (i = 0; i < ctrl->thread_count; i++) {
5784 + for (j = 0; j < ctrl->thread[i].vreg_count; j++) {
5785 + vreg = &ctrl->thread[i].vreg[j];
5786 + vreg->corner[i].last_volt =
5787 + vreg->corner[i].open_loop_volt;
5788 + }
5789 + }
5790 +
5791 + /* Register regulator devices for all threads. */
5792 + for (i = 0; i < ctrl->thread_count; i++) {
5793 + for (j = 0; j < ctrl->thread[i].vreg_count; j++) {
5794 + rc = cpr3_regulator_vreg_register(
5795 + &ctrl->thread[i].vreg[j]);
5796 + if (rc) {
5797 + cpr3_err(&ctrl->thread[i].vreg[j], "failed to register regulator, rc=%d\n",
5798 + rc);
5799 + goto free_regulators;
5800 + }
5801 + }
5802 + }
5803 +
5804 + mutex_lock(&cpr3_controller_list_mutex);
5805 + list_add(&ctrl->list, &cpr3_controller_list);
5806 + mutex_unlock(&cpr3_controller_list_mutex);
5807 +
5808 + return 0;
5809 +
5810 +free_regulators:
5811 + for (i = 0; i < ctrl->thread_count; i++)
5812 + for (j = 0; j < ctrl->thread[i].vreg_count; j++)
5813 + if (!IS_ERR_OR_NULL(ctrl->thread[i].vreg[j].rdev))
5814 + regulator_unregister(
5815 + ctrl->thread[i].vreg[j].rdev);
5816 + return rc;
5817 +}
5818 +
5819 +/**
5820 + * cpr3_regulator_unregister() - unregister the regulators for a CPR3 controller
5821 + * and perform CPR hardware shutdown
5822 + * @ctrl: Pointer to the CPR3 controller
5823 + *
5824 + * Return: 0 on success, errno on failure
5825 + */
5826 +int cpr3_regulator_unregister(struct cpr3_controller *ctrl)
5827 +{
5828 + int i, j, rc = 0;
5829 +
5830 + mutex_lock(&cpr3_controller_list_mutex);
5831 + list_del(&ctrl->list);
5832 + cpr3_regulator_debugfs_ctrl_remove(ctrl);
5833 + mutex_unlock(&cpr3_controller_list_mutex);
5834 +
5835 + if (ctrl->ctrl_type == CPR_CTRL_TYPE_CPR4) {
5836 + rc = cpr3_ctrl_clear_cpr4_config(ctrl);
5837 + if (rc)
5838 + cpr3_err(ctrl, "failed to clear CPR4 configuration,rc=%d\n",
5839 + rc);
5840 + }
5841 +
5842 + cpr3_ctrl_loop_disable(ctrl);
5843 +
5844 + cpr3_closed_loop_disable(ctrl);
5845 +
5846 + if (ctrl->vdd_limit_regulator) {
5847 + regulator_disable(ctrl->vdd_limit_regulator);
5848 + }
5849 +
5850 + for (i = 0; i < ctrl->thread_count; i++)
5851 + for (j = 0; j < ctrl->thread[i].vreg_count; j++)
5852 + regulator_unregister(ctrl->thread[i].vreg[j].rdev);
5853 +
5854 + if (ctrl->panic_notifier.notifier_call)
5855 + atomic_notifier_chain_unregister(&panic_notifier_list,
5856 + &ctrl->panic_notifier);
5857 +
5858 + return 0;
5859 +}
5860 +
5861 +/**
5862 + * cpr3_open_loop_regulator_unregister() - unregister the regulators for a CPR3
5863 + * open loop controller and perform CPR hardware shutdown
5864 + * @ctrl: Pointer to the CPR3 controller
5865 + *
5866 + * Return: 0 on success, errno on failure
5867 + */
5868 +int cpr3_open_loop_regulator_unregister(struct cpr3_controller *ctrl)
5869 +{
5870 + int i, j;
5871 +
5872 + mutex_lock(&cpr3_controller_list_mutex);
5873 + list_del(&ctrl->list);
5874 + mutex_unlock(&cpr3_controller_list_mutex);
5875 +
5876 + if (ctrl->vdd_limit_regulator) {
5877 + regulator_disable(ctrl->vdd_limit_regulator);
5878 + }
5879 +
5880 + for (i = 0; i < ctrl->thread_count; i++)
5881 + for (j = 0; j < ctrl->thread[i].vreg_count; j++)
5882 + regulator_unregister(ctrl->thread[i].vreg[j].rdev);
5883 +
5884 + if (ctrl->panic_notifier.notifier_call)
5885 + atomic_notifier_chain_unregister(&panic_notifier_list,
5886 + &ctrl->panic_notifier);
5887 +
5888 + return 0;
5889 +}
5890 --- /dev/null
5891 +++ b/drivers/regulator/cpr3-regulator.h
5892 @@ -0,0 +1,1211 @@
5893 +/*
5894 + * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
5895 + *
5896 + * This program is free software; you can redistribute it and/or modify
5897 + * it under the terms of the GNU General Public License version 2 and
5898 + * only version 2 as published by the Free Software Foundation.
5899 + *
5900 + * This program is distributed in the hope that it will be useful,
5901 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
5902 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
5903 + * GNU General Public License for more details.
5904 + */
5905 +
5906 +#ifndef __REGULATOR_CPR3_REGULATOR_H__
5907 +#define __REGULATOR_CPR3_REGULATOR_H__
5908 +
5909 +#include <linux/clk.h>
5910 +#include <linux/mutex.h>
5911 +#include <linux/of.h>
5912 +#include <linux/platform_device.h>
5913 +#include <linux/types.h>
5914 +#include <linux/power/qcom/apm.h>
5915 +#include <linux/regulator/driver.h>
5916 +
5917 +struct cpr3_controller;
5918 +struct cpr3_thread;
5919 +
5920 +/**
5921 + * struct cpr3_fuse_param - defines one contiguous segment of a fuse parameter
5922 + * that is contained within a given row.
5923 + * @row: Fuse row number
5924 + * @bit_start: The first bit within the row of the fuse parameter segment
5925 + * @bit_end: The last bit within the row of the fuse parameter segment
5926 + *
5927 + * Each fuse row is 64 bits in length. bit_start and bit_end may take values
5928 + * from 0 to 63. bit_start must be less than or equal to bit_end.
5929 + */
5930 +struct cpr3_fuse_param {
5931 + unsigned row;
5932 + unsigned bit_start;
5933 + unsigned bit_end;
5934 +};
5935 +
5936 +/* Each CPR3 sensor has 16 ring oscillators */
5937 +#define CPR3_RO_COUNT 16
5938 +
5939 +/* The maximum number of sensors that can be present on a single CPR loop. */
5940 +#define CPR3_MAX_SENSOR_COUNT 256
5941 +
5942 +/* This constant is used when allocating array printing buffers. */
5943 +#define MAX_CHARS_PER_INT 10
5944 +
5945 +/**
5946 + * struct cpr4_sdelta - CPR4 controller specific data structure for the sdelta
5947 + * adjustment table which is used to adjust the VDD supply
5948 + * voltage automatically based upon the temperature and/or
5949 + * the number of online CPU cores.
5950 + * @allow_core_count_adj: Core count adjustments are allowed.
5951 + * @allow_temp_adj: Temperature based adjustments are allowed.
5952 + * @max_core_count: Maximum number of cores considered for core count
5953 + * adjustment logic.
5954 + * @temp_band_count: Number of temperature bands considered for temperature
5955 + * based adjustment logic.
5956 + * @cap_volt: CAP in uV to apply to SDELTA margins with multiple
5957 + * cpr3-regulators defined for single controller.
5958 + * @table: SDELTA table with per-online-core and temperature based
5959 + * adjustments of size (max_core_count * temp_band_count)
5960 + * Outer: core count
5961 + * Inner: temperature band
5962 + * Each element has units of VDD supply steps. Positive
5963 + * values correspond to a reduction in voltage and negative
5964 + * value correspond to an increase (this follows the SDELTA
5965 + * register semantics).
5966 + * @allow_boost: Voltage boost allowed.
5967 + * @boost_num_cores: The number of online cores at which the boost voltage
5968 + * adjustments will be applied
5969 + * @boost_table: SDELTA table with boost voltage adjustments of size
5970 + * temp_band_count. Each element has units of VDD supply
5971 + * steps. Positive values correspond to a reduction in
5972 + * voltage and negative value correspond to an increase
5973 + * (this follows the SDELTA register semantics).
5974 + */
5975 +struct cpr4_sdelta {
5976 + bool allow_core_count_adj;
5977 + bool allow_temp_adj;
5978 + int max_core_count;
5979 + int temp_band_count;
5980 + int cap_volt;
5981 + int *table;
5982 + bool allow_boost;
5983 + int boost_num_cores;
5984 + int *boost_table;
5985 +};
5986 +
5987 +/**
5988 + * struct cpr3_corner - CPR3 virtual voltage corner data structure
5989 + * @floor_volt: CPR closed-loop floor voltage in microvolts
5990 + * @ceiling_volt: CPR closed-loop ceiling voltage in microvolts
5991 + * @open_loop_volt: CPR open-loop voltage (i.e. initial voltage) in
5992 + * microvolts
5993 + * @last_volt: Last known settled CPR closed-loop voltage which is used
5994 + * when switching to a new corner
5995 + * @abs_ceiling_volt: The absolute CPR closed-loop ceiling voltage in
5996 + * microvolts. This is used to limit the ceiling_volt
5997 + * value when it is increased as a result of aging
5998 + * adjustment.
5999 + * @unaged_floor_volt: The CPR closed-loop floor voltage in microvolts before
6000 + * any aging adjustment is performed
6001 + * @unaged_ceiling_volt: The CPR closed-loop ceiling voltage in microvolts
6002 + * before any aging adjustment is performed
6003 + * @unaged_open_loop_volt: The CPR open-loop voltage (i.e. initial voltage) in
6004 + * microvolts before any aging adjusment is performed
6005 + * @system_volt: The system-supply voltage in microvolts or corners or
6006 + * levels
6007 + * @mem_acc_volt: The mem-acc-supply voltage in corners
6008 + * @proc_freq: Processor frequency in Hertz. For CPR rev. 3 and 4
6009 + * conrollers, this field is only used by platform specific
6010 + * CPR3 driver for interpolation. For CPRh-compliant
6011 + * controllers, this frequency is also utilized by the
6012 + * clock driver to determine the corner to CPU clock
6013 + * frequency mappings.
6014 + * @cpr_fuse_corner: Fused corner index associated with this virtual corner
6015 + * (only used by platform specific CPR3 driver for
6016 + * mapping purposes)
6017 + * @target_quot: Array of target quotient values to use for each ring
6018 + * oscillator (RO) for this corner. A value of 0 should be
6019 + * specified as the target quotient for each RO that is
6020 + * unused by this corner.
6021 + * @ro_scale: Array of CPR ring oscillator (RO) scaling factors. The
6022 + * scaling factor for each RO is defined from RO0 to RO15
6023 + * with units of QUOT/V. A value of 0 may be specified for
6024 + * an RO that is unused.
6025 + * @ro_mask: Bitmap where each of the 16 LSBs indicate if the
6026 + * corresponding ROs should be masked for this corner
6027 + * @irq_en: Bitmap of the CPR interrupts to enable for this corner
6028 + * @aging_derate: The amount to derate the aging voltage adjustment
6029 + * determined for the reference corner in units of uV/mV.
6030 + * E.g. a value of 900 would imply that the adjustment for
6031 + * this corner should be 90% (900/1000) of that for the
6032 + * reference corner.
6033 + * @use_open_loop: Boolean indicating that open-loop (i.e CPR disabled) as
6034 + * opposed to closed-loop operation must be used for this
6035 + * corner on CPRh controllers.
6036 + * @sdelta: The CPR4 controller specific data for this corner. This
6037 + * field is applicable for CPR4 controllers.
6038 + *
6039 + * The value of last_volt is initialized inside of the cpr3_regulator_register()
6040 + * call with the open_loop_volt value. It can later be updated to the settled
6041 + * VDD supply voltage. The values for unaged_floor_volt, unaged_ceiling_volt,
6042 + * and unaged_open_loop_volt are initialized inside of cpr3_regulator_register()
6043 + * if ctrl->aging_required == true. These three values must be pre-initialized
6044 + * if cpr3_regulator_register() is called with ctrl->aging_required == false and
6045 + * ctrl->aging_succeeded == true.
6046 + *
6047 + * The values of ro_mask and irq_en are initialized inside of the
6048 + * cpr3_regulator_register() call.
6049 + */
6050 +struct cpr3_corner {
6051 + int floor_volt;
6052 + int ceiling_volt;
6053 + int cold_temp_open_loop_volt;
6054 + int normal_temp_open_loop_volt;
6055 + int open_loop_volt;
6056 + int last_volt;
6057 + int abs_ceiling_volt;
6058 + int unaged_floor_volt;
6059 + int unaged_ceiling_volt;
6060 + int unaged_open_loop_volt;
6061 + int system_volt;
6062 + int mem_acc_volt;
6063 + u32 proc_freq;
6064 + int cpr_fuse_corner;
6065 + u32 target_quot[CPR3_RO_COUNT];
6066 + u32 ro_scale[CPR3_RO_COUNT];
6067 + u32 ro_mask;
6068 + u32 irq_en;
6069 + int aging_derate;
6070 + bool use_open_loop;
6071 + struct cpr4_sdelta *sdelta;
6072 +};
6073 +
6074 +/**
6075 + * struct cprh_corner_band - CPRh controller specific data structure which
6076 + * encapsulates the range of corners and the SDELTA
6077 + * adjustment table to be applied to the corners within
6078 + * the min and max bounds of the corner band.
6079 + * @corner: Corner number which defines the corner band boundary
6080 + * @sdelta: The SDELTA adjustment table which contains core-count
6081 + * and temp based margin adjustments that are applicable
6082 + * to the corner band.
6083 + */
6084 +struct cprh_corner_band {
6085 + int corner;
6086 + struct cpr4_sdelta *sdelta;
6087 +};
6088 +
6089 +/**
6090 + * struct cpr3_fuse_parameters - CPR4 fuse specific data structure which has
6091 + * the required fuse parameters need for Close Loop CPR
6092 + * @(*apss_ro_sel_param)[2]: Pointer to RO select fuse details
6093 + * @(*apss_init_voltage_param)[2]: Pointer to Target voltage fuse details
6094 + * @(*apss_target_quot_param)[2]: Pointer to Target quot fuse details
6095 + * @(*apss_quot_offset_param)[2]: Pointer to quot offset fuse details
6096 + * @cpr_fusing_rev_param: Pointer to CPR revision fuse details
6097 + * @apss_speed_bin_param: Pointer to Speed bin fuse details
6098 + * @cpr_boost_fuse_cfg_param: Pointer to Boost fuse cfg details
6099 + * @apss_boost_fuse_volt_param: Pointer to Boost fuse volt details
6100 + * @misc_fuse_volt_adj_param: Pointer to Misc fuse volt fuse details
6101 + */
6102 +struct cpr3_fuse_parameters {
6103 + struct cpr3_fuse_param (*apss_ro_sel_param)[2];
6104 + struct cpr3_fuse_param (*apss_init_voltage_param)[2];
6105 + struct cpr3_fuse_param (*apss_target_quot_param)[2];
6106 + struct cpr3_fuse_param (*apss_quot_offset_param)[2];
6107 + struct cpr3_fuse_param *cpr_fusing_rev_param;
6108 + struct cpr3_fuse_param *apss_speed_bin_param;
6109 + struct cpr3_fuse_param *cpr_boost_fuse_cfg_param;
6110 + struct cpr3_fuse_param *apss_boost_fuse_volt_param;
6111 + struct cpr3_fuse_param *misc_fuse_volt_adj_param;
6112 +};
6113 +
6114 +struct cpr4_mem_acc_func {
6115 + void (*set_mem_acc)(struct regulator_dev *);
6116 + void (*clear_mem_acc)(struct regulator_dev *);
6117 +};
6118 +
6119 +/**
6120 + * struct cpr4_reg_data - CPR4 regulator specific data structure which is
6121 + * target specific
6122 + * @cpr_valid_fuse_count: Number of valid fuse corners
6123 + * @fuse_ref_volt: Pointer to fuse reference voltage
6124 + * @fuse_step_volt: CPR step voltage available in fuse
6125 + * @cpr_clk_rate: CPR clock rate
6126 + * @boost_fuse_ref_volt: Boost fuse reference voltage
6127 + * @boost_ceiling_volt: Boost ceiling voltage
6128 + * @boost_floor_volt: Boost floor voltage
6129 + * @cpr3_fuse_params: Pointer to CPR fuse parameters
6130 + * @mem_acc_funcs: Pointer to MEM ACC set/clear functions
6131 + **/
6132 +struct cpr4_reg_data {
6133 + u32 cpr_valid_fuse_count;
6134 + int *fuse_ref_volt;
6135 + u32 fuse_step_volt;
6136 + u32 cpr_clk_rate;
6137 + int boost_fuse_ref_volt;
6138 + int boost_ceiling_volt;
6139 + int boost_floor_volt;
6140 + struct cpr3_fuse_parameters *cpr3_fuse_params;
6141 + struct cpr4_mem_acc_func *mem_acc_funcs;
6142 +};
6143 +/**
6144 + * struct cpr3_reg_data - CPR3 regulator specific data structure which is
6145 + * target specific
6146 + * @cpr_valid_fuse_count: Number of valid fuse corners
6147 + * @(*init_voltage_param)[2]: Pointer to Target voltage fuse details
6148 + * @fuse_ref_volt: Pointer to fuse reference voltage
6149 + * @fuse_step_volt: CPR step voltage available in fuse
6150 + * @cpr_clk_rate: CPR clock rate
6151 + * @cpr3_fuse_params: Pointer to CPR fuse parameters
6152 + **/
6153 +struct cpr3_reg_data {
6154 + u32 cpr_valid_fuse_count;
6155 + struct cpr3_fuse_param (*init_voltage_param)[2];
6156 + int *fuse_ref_volt;
6157 + u32 fuse_step_volt;
6158 + u32 cpr_clk_rate;
6159 +};
6160 +
6161 +/**
6162 + * struct cpr3_regulator - CPR3 logical regulator instance associated with a
6163 + * given CPR3 hardware thread
6164 + * @of_node: Device node associated with the device tree child node
6165 + * of this CPR3 regulator
6166 + * @thread: Pointer to the CPR3 thread which manages this CPR3
6167 + * regulator
6168 + * @name: Unique name for this CPR3 regulator which is filled
6169 + * using the device tree regulator-name property
6170 + * @rdesc: Regulator description for this CPR3 regulator
6171 + * @rdev: Regulator device pointer for the regulator registered
6172 + * for this CPR3 regulator
6173 + * @mem_acc_regulator: Pointer to the optional mem-acc supply regulator used
6174 + * to manage memory circuitry settings based upon CPR3
6175 + * regulator output voltage.
6176 + * @corner: Array of all corners supported by this CPR3 regulator
6177 + * @corner_count: The number of elements in the corner array
6178 + * @corner_band: Array of all corner bands supported by CPRh compatible
6179 + * controllers
6180 + * @cpr4_regulator_data Target specific cpr4 regulator data
6181 + * @cpr3_regulator_data Target specific cpr3 regulator data
6182 + * @corner_band_count: The number of elements in the corner band array
6183 + * @platform_fuses: Pointer to platform specific CPR fuse data (only used by
6184 + * platform specific CPR3 driver)
6185 + * @speed_bin_fuse: Value read from the speed bin fuse parameter
6186 + * @speed_bins_supported: The number of speed bins supported by the device tree
6187 + * configuration for this CPR3 regulator
6188 + * @cpr_rev_fuse: Value read from the CPR fusing revision fuse parameter
6189 + * @fuse_combo: Platform specific enum value identifying the specific
6190 + * combination of fuse values found on a given chip
6191 + * @fuse_combos_supported: The number of fuse combinations supported by the
6192 + * device tree configuration for this CPR3 regulator
6193 + * @fuse_corner_count: Number of corners defined by fuse parameters
6194 + * @fuse_corner_map: Array of length fuse_corner_count which specifies the
6195 + * highest corner associated with each fuse corner. Note
6196 + * that each element must correspond to a valid corner
6197 + * and that element values must be strictly increasing.
6198 + * Also, it is acceptable for the lowest fuse corner to map
6199 + * to a corner other than the lowest. Likewise, it is
6200 + * acceptable for the highest fuse corner to map to a
6201 + * corner other than the highest.
6202 + * @fuse_combo_corner_sum: The sum of the corner counts across all fuse combos
6203 + * @fuse_combo_offset: The device tree property array offset for the selected
6204 + * fuse combo
6205 + * @speed_bin_corner_sum: The sum of the corner counts across all speed bins
6206 + * This may be specified as 0 if per speed bin parsing
6207 + * support is not required.
6208 + * @speed_bin_offset: The device tree property array offset for the selected
6209 + * speed bin
6210 + * @fuse_combo_corner_band_sum: The sum of the corner band counts across all
6211 + * fuse combos
6212 + * @fuse_combo_corner_band_offset: The device tree property array offset for
6213 + * the corner band count corresponding to the selected
6214 + * fuse combo
6215 + * @speed_bin_corner_band_sum: The sum of the corner band counts across all
6216 + * speed bins. This may be specified as 0 if per speed bin
6217 + * parsing support is not required
6218 + * @speed_bin_corner_band_offset: The device tree property array offset for the
6219 + * corner band count corresponding to the selected speed
6220 + * bin
6221 + * @pd_bypass_mask: Bit mask of power domains associated with this CPR3
6222 + * regulator
6223 + * @dynamic_floor_corner: Index identifying the voltage corner for the CPR3
6224 + * regulator whose last_volt value should be used as the
6225 + * global CPR floor voltage if all of the power domains
6226 + * associated with this CPR3 regulator are bypassed
6227 + * @uses_dynamic_floor: Boolean flag indicating that dynamic_floor_corner should
6228 + * be utilized for the CPR3 regulator
6229 + * @current_corner: Index identifying the currently selected voltage corner
6230 + * for the CPR3 regulator or less than 0 if no corner has
6231 + * been requested
6232 + * @last_closed_loop_corner: Index identifying the last voltage corner for the
6233 + * CPR3 regulator which was configured when operating in
6234 + * CPR closed-loop mode or less than 0 if no corner has
6235 + * been requested. CPR registers are only written to when
6236 + * using closed-loop mode.
6237 + * @aggregated: Boolean flag indicating that this CPR3 regulator
6238 + * participated in the last aggregation event
6239 + * @debug_corner: Index identifying voltage corner used for displaying
6240 + * corner configuration values in debugfs
6241 + * @vreg_enabled: Boolean defining the enable state of the CPR3
6242 + * regulator's regulator within the regulator framework.
6243 + * @aging_allowed: Boolean defining if CPR aging adjustments are allowed
6244 + * for this CPR3 regulator given the fuse combo of the
6245 + * device
6246 + * @aging_allow_open_loop_adj: Boolean defining if the open-loop voltage of each
6247 + * corner of this regulator should be adjusted as a result
6248 + * of an aging measurement. This flag can be set to false
6249 + * when the open-loop voltage adjustments have been
6250 + * specified such that they include the maximum possible
6251 + * aging adjustment. This flag is only used if
6252 + * aging_allowed == true.
6253 + * @aging_corner: The corner that should be configured for this regulator
6254 + * when an aging measurement is performed.
6255 + * @aging_max_adjust_volt: The maximum aging voltage margin in microvolts that
6256 + * may be added to the target quotients of this regulator.
6257 + * A value of 0 may be specified if this regulator does not
6258 + * require any aging adjustment.
6259 + * @allow_core_count_adj: Core count adjustments are allowed for this regulator.
6260 + * @allow_temp_adj: Temperature based adjustments are allowed for this
6261 + * regulator.
6262 + * @max_core_count: Maximum number of cores considered for core count
6263 + * adjustment logic.
6264 + * @allow_boost: Voltage boost allowed for this regulator.
6265 + *
6266 + * This structure contains both configuration and runtime state data. The
6267 + * elements current_corner, last_closed_loop_corner, aggregated, debug_corner,
6268 + * and vreg_enabled are state variables.
6269 + */
6270 +struct cpr3_regulator {
6271 + struct device_node *of_node;
6272 + struct cpr3_thread *thread;
6273 + const char *name;
6274 + struct regulator_desc rdesc;
6275 + struct regulator_dev *rdev;
6276 + struct regulator *mem_acc_regulator;
6277 + struct cpr3_corner *corner;
6278 + int corner_count;
6279 + struct cprh_corner_band *corner_band;
6280 + struct cpr4_reg_data *cpr4_regulator_data;
6281 + struct cpr3_reg_data *cpr3_regulator_data;
6282 + u32 corner_band_count;
6283 +
6284 + void *platform_fuses;
6285 + int speed_bin_fuse;
6286 + int speed_bins_supported;
6287 + int cpr_rev_fuse;
6288 + int part_type;
6289 + int part_type_supported;
6290 + int fuse_combo;
6291 + int fuse_combos_supported;
6292 + int fuse_corner_count;
6293 + int *fuse_corner_map;
6294 + int fuse_combo_corner_sum;
6295 + int fuse_combo_offset;
6296 + int speed_bin_corner_sum;
6297 + int speed_bin_offset;
6298 + int fuse_combo_corner_band_sum;
6299 + int fuse_combo_corner_band_offset;
6300 + int speed_bin_corner_band_sum;
6301 + int speed_bin_corner_band_offset;
6302 + u32 pd_bypass_mask;
6303 + int dynamic_floor_corner;
6304 + bool uses_dynamic_floor;
6305 +
6306 + int current_corner;
6307 + int last_closed_loop_corner;
6308 + bool aggregated;
6309 + int debug_corner;
6310 + bool vreg_enabled;
6311 +
6312 + bool aging_allowed;
6313 + bool aging_allow_open_loop_adj;
6314 + int aging_corner;
6315 + int aging_max_adjust_volt;
6316 +
6317 + bool allow_core_count_adj;
6318 + bool allow_temp_adj;
6319 + int max_core_count;
6320 + bool allow_boost;
6321 +};
6322 +
6323 +/**
6324 + * struct cpr3_thread - CPR3 hardware thread data structure
6325 + * @thread_id: Hardware thread ID
6326 + * @of_node: Device node associated with the device tree child node
6327 + * of this CPR3 thread
6328 + * @ctrl: Pointer to the CPR3 controller which manages this thread
6329 + * @vreg: Array of CPR3 regulators handled by the CPR3 thread
6330 + * @vreg_count: Number of elements in the vreg array
6331 + * @aggr_corner: CPR corner containing the in process aggregated voltage
6332 + * and target quotient configurations which will be applied
6333 + * @last_closed_loop_aggr_corner: CPR corner containing the most recent
6334 + * configurations which were written into hardware
6335 + * registers when operating in closed loop mode (i.e. with
6336 + * CPR enabled)
6337 + * @consecutive_up: The number of consecutive CPR step up events needed to
6338 + * to trigger an up interrupt
6339 + * @consecutive_down: The number of consecutive CPR step down events needed to
6340 + * to trigger a down interrupt
6341 + * @up_threshold: The number CPR error steps required to generate an up
6342 + * event
6343 + * @down_threshold: The number CPR error steps required to generate a down
6344 + * event
6345 + *
6346 + * This structure contains both configuration and runtime state data. The
6347 + * elements aggr_corner and last_closed_loop_aggr_corner are state variables.
6348 + */
6349 +struct cpr3_thread {
6350 + u32 thread_id;
6351 + struct device_node *of_node;
6352 + struct cpr3_controller *ctrl;
6353 + struct cpr3_regulator *vreg;
6354 + int vreg_count;
6355 + struct cpr3_corner aggr_corner;
6356 + struct cpr3_corner last_closed_loop_aggr_corner;
6357 +
6358 + u32 consecutive_up;
6359 + u32 consecutive_down;
6360 + u32 up_threshold;
6361 + u32 down_threshold;
6362 +};
6363 +
6364 +/* Per CPR controller data */
6365 +/**
6366 + * enum cpr3_mem_acc_corners - Constants which define the number of mem-acc
6367 + * regulator corners available in the mem-acc corner map array.
6368 + * %CPR3_MEM_ACC_LOW_CORNER: Index in mem-acc corner map array mapping to the
6369 + * mem-acc regulator corner
6370 + * to be used for low voltage vdd supply
6371 + * %CPR3_MEM_ACC_HIGH_CORNER: Index in mem-acc corner map array mapping to the
6372 + * mem-acc regulator corner to be used for high
6373 + * voltage vdd supply
6374 + * %CPR3_MEM_ACC_CORNERS: Number of elements in the mem-acc corner map
6375 + * array
6376 + */
6377 +enum cpr3_mem_acc_corners {
6378 + CPR3_MEM_ACC_LOW_CORNER = 0,
6379 + CPR3_MEM_ACC_HIGH_CORNER = 1,
6380 + CPR3_MEM_ACC_CORNERS = 2,
6381 +};
6382 +
6383 +/**
6384 + * enum cpr3_count_mode - CPR3 controller count mode which defines the
6385 + * method that CPR sensor data is acquired
6386 + * %CPR3_COUNT_MODE_ALL_AT_ONCE_MIN: Capture all CPR sensor readings
6387 + * simultaneously and report the minimum
6388 + * value seen in successive measurements
6389 + * %CPR3_COUNT_MODE_ALL_AT_ONCE_MAX: Capture all CPR sensor readings
6390 + * simultaneously and report the maximum
6391 + * value seen in successive measurements
6392 + * %CPR3_COUNT_MODE_STAGGERED: Read one sensor at a time in a
6393 + * sequential fashion
6394 + * %CPR3_COUNT_MODE_ALL_AT_ONCE_AGE: Capture all CPR aging sensor readings
6395 + * simultaneously.
6396 + */
6397 +enum cpr3_count_mode {
6398 + CPR3_COUNT_MODE_ALL_AT_ONCE_MIN = 0,
6399 + CPR3_COUNT_MODE_ALL_AT_ONCE_MAX = 1,
6400 + CPR3_COUNT_MODE_STAGGERED = 2,
6401 + CPR3_COUNT_MODE_ALL_AT_ONCE_AGE = 3,
6402 +};
6403 +
6404 +/**
6405 + * enum cpr_controller_type - supported CPR controller hardware types
6406 + * %CPR_CTRL_TYPE_CPR3: HW has CPR3 controller
6407 + * %CPR_CTRL_TYPE_CPR4: HW has CPR4 controller
6408 + */
6409 +enum cpr_controller_type {
6410 + CPR_CTRL_TYPE_CPR3,
6411 + CPR_CTRL_TYPE_CPR4,
6412 +};
6413 +
6414 +/**
6415 + * cpr_setting - supported CPR global settings
6416 + * %CPR_DEFAULT: default mode from dts will be used
6417 + * %CPR_DISABLED: ceiling voltage will be used for all the corners
6418 + * %CPR_OPEN_LOOP_EN: CPR will work in OL
6419 + * %CPR_CLOSED_LOOP_EN: CPR will work in CL, if supported
6420 + */
6421 +enum cpr_setting {
6422 + CPR_DEFAULT = 0,
6423 + CPR_DISABLED = 1,
6424 + CPR_OPEN_LOOP_EN = 2,
6425 + CPR_CLOSED_LOOP_EN = 3,
6426 +};
6427 +
6428 +/**
6429 + * struct cpr3_aging_sensor_info - CPR3 aging sensor information
6430 + * @sensor_id The index of the CPR3 sensor to be used in the aging
6431 + * measurement.
6432 + * @ro_scale The CPR ring oscillator (RO) scaling factor for the
6433 + * aging sensor with units of QUOT/V.
6434 + * @init_quot_diff: The fused quotient difference between aged and un-aged
6435 + * paths that was measured at manufacturing time.
6436 + * @measured_quot_diff: The quotient difference measured at runtime.
6437 + * @bypass_mask: Bit mask of the CPR sensors that must be bypassed during
6438 + * the aging measurement for this sensor
6439 + *
6440 + * This structure contains both configuration and runtime state data. The
6441 + * element measured_quot_diff is a state variable.
6442 + */
6443 +struct cpr3_aging_sensor_info {
6444 + u32 sensor_id;
6445 + u32 ro_scale;
6446 + int init_quot_diff;
6447 + int measured_quot_diff;
6448 + u32 bypass_mask[CPR3_MAX_SENSOR_COUNT / 32];
6449 +};
6450 +
6451 +/**
6452 + * struct cpr3_reg_info - Register information data structure
6453 + * @name: Register name
6454 + * @addr: Register physical address
6455 + * @value: Register content
6456 + * @virt_addr: Register virtual address
6457 + *
6458 + * This data structure is used to dump some critical register contents
6459 + * when the device crashes due to a kernel panic.
6460 + */
6461 +struct cpr3_reg_info {
6462 + const char *name;
6463 + u32 addr;
6464 + u32 value;
6465 + void __iomem *virt_addr;
6466 +};
6467 +
6468 +/**
6469 + * struct cpr3_panic_regs_info - Data structure to dump critical register
6470 + * contents.
6471 + * @reg_count: Number of elements in the regs array
6472 + * @regs: Array of critical registers information
6473 + *
6474 + * This data structure is used to dump critical register contents when
6475 + * the device crashes due to a kernel panic.
6476 + */
6477 +struct cpr3_panic_regs_info {
6478 + int reg_count;
6479 + struct cpr3_reg_info *regs;
6480 +};
6481 +
6482 +/**
6483 + * struct cpr3_controller - CPR3 controller data structure
6484 + * @dev: Device pointer for the CPR3 controller device
6485 + * @name: Unique name for the CPR3 controller
6486 + * @ctrl_id: Controller ID corresponding to the VDD supply number
6487 + * that this CPR3 controller manages.
6488 + * @cpr_ctrl_base: Virtual address of the CPR3 controller base register
6489 + * @fuse_base: Virtual address of fuse row 0
6490 + * @aging_possible_reg: Virtual address of an optional platform-specific
6491 + * register that must be ready to determine if it is
6492 + * possible to perform an aging measurement.
6493 + * @list: list head used in a global cpr3-regulator list so that
6494 + * cpr3-regulator structs can be found easily in RAM dumps
6495 + * @thread: Array of CPR3 threads managed by the CPR3 controller
6496 + * @thread_count: Number of elements in the thread array
6497 + * @sensor_owner: Array of thread IDs indicating which thread owns a given
6498 + * CPR sensor
6499 + * @sensor_count: The number of CPR sensors found on the CPR loop managed
6500 + * by this CPR controller. Must be equal to the number of
6501 + * elements in the sensor_owner array
6502 + * @soc_revision: Revision number of the SoC. This may be unused by
6503 + * platforms that do not have different behavior for
6504 + * different SoC revisions.
6505 + * @lock: Mutex lock used to ensure mutual exclusion between
6506 + * all of the threads associated with the controller
6507 + * @vdd_regulator: Pointer to the VDD supply regulator which this CPR3
6508 + * controller manages
6509 + * @system_regulator: Pointer to the optional system-supply regulator upon
6510 + * which the VDD supply regulator depends.
6511 + * @mem_acc_regulator: Pointer to the optional mem-acc supply regulator used
6512 + * to manage memory circuitry settings based upon the
6513 + * VDD supply output voltage.
6514 + * @vdd_limit_regulator: Pointer to the VDD supply limit regulator which is used
6515 + * for hardware closed-loop in order specify ceiling and
6516 + * floor voltage limits (platform specific)
6517 + * @system_supply_max_volt: Voltage in microvolts which corresponds to the
6518 + * absolute ceiling voltage of the system-supply
6519 + * @mem_acc_threshold_volt: mem-acc threshold voltage in microvolts
6520 + * @mem_acc_corner_map: mem-acc regulator corners mapping to low and high
6521 + * voltage mem-acc settings for the memories powered by
6522 + * this CPR3 controller and its associated CPR3 regulators
6523 + * @mem_acc_crossover_volt: Voltage in microvolts corresponding to the voltage
6524 + * that the VDD supply must be set to while a MEM ACC
6525 + * switch is in progress. This element must be initialized
6526 + * for CPRh controllers when a MEM ACC threshold voltage is
6527 + * defined.
6528 + * @core_clk: Pointer to the CPR3 controller core clock
6529 + * @iface_clk: Pointer to the CPR3 interface clock (platform specific)
6530 + * @bus_clk: Pointer to the CPR3 bus clock (platform specific)
6531 + * @irq: CPR interrupt number
6532 + * @irq_affinity_mask: The cpumask for the CPUs which the CPR interrupt should
6533 + * have affinity for
6534 + * @cpu_hotplug_notifier: CPU hotplug notifier used to reset IRQ affinity when a
6535 + * CPU is brought back online
6536 + * @ceiling_irq: Interrupt number for the interrupt that is triggered
6537 + * when hardware closed-loop attempts to exceed the ceiling
6538 + * voltage
6539 + * @apm: Handle to the array power mux (APM)
6540 + * @apm_threshold_volt: Voltage in microvolts which defines the threshold
6541 + * voltage to determine the APM supply selection for
6542 + * each corner
6543 + * @apm_crossover_volt: Voltage in microvolts corresponding to the voltage that
6544 + * the VDD supply must be set to while an APM switch is in
6545 + * progress. This element must be initialized for CPRh
6546 + * controllers when an APM threshold voltage is defined
6547 + * @apm_adj_volt: Minimum difference between APM threshold voltage and
6548 + * open-loop voltage which allows the APM threshold voltage
6549 + * to be used as a ceiling
6550 + * @apm_high_supply: APM supply to configure if VDD voltage is greater than
6551 + * or equal to the APM threshold voltage
6552 + * @apm_low_supply: APM supply to configure if the VDD voltage is less than
6553 + * the APM threshold voltage
6554 + * @base_volt: Minimum voltage in microvolts supported by the VDD
6555 + * supply managed by this CPR controller
6556 + * @corner_switch_delay_time: The delay time in nanoseconds used by the CPR
6557 + * controller to wait for voltage settling before
6558 + * acknowledging the OSM block after corner changes
6559 + * @cpr_clock_rate: CPR reference clock frequency in Hz.
6560 + * @sensor_time: The time in nanoseconds that each sensor takes to
6561 + * perform a measurement.
6562 + * @loop_time: The time in nanoseconds between consecutive CPR
6563 + * measurements.
6564 + * @up_down_delay_time: The time to delay in nanoseconds between consecutive CPR
6565 + * measurements when the last measurement recommended
6566 + * increasing or decreasing the vdd-supply voltage.
6567 + * (platform specific)
6568 + * @idle_clocks: Number of CPR reference clock ticks that the CPR
6569 + * controller waits in transitional states.
6570 + * @step_quot_init_min: The default minimum CPR step quotient value. The step
6571 + * quotient is the number of additional ring oscillator
6572 + * ticks observed when increasing one step in vdd-supply
6573 + * output voltage.
6574 + * @step_quot_init_max: The default maximum CPR step quotient value.
6575 + * @step_volt: Step size in microvolts between available set points
6576 + * of the VDD supply
6577 + * @down_error_step_limit: CPR4 hardware closed-loop down error step limit which
6578 + * defines the maximum number of VDD supply regulator steps
6579 + * that the voltage may be reduced as the result of a
6580 + * single CPR measurement.
6581 + * @up_error_step_limit: CPR4 hardware closed-loop up error step limit which
6582 + * defines the maximum number of VDD supply regulator steps
6583 + * that the voltage may be increased as the result of a
6584 + * single CPR measurement.
6585 + * @count_mode: CPR controller count mode
6586 + * @count_repeat: Number of times to perform consecutive sensor
6587 + * measurements when using all-at-once count modes.
6588 + * @proc_clock_throttle: Defines the processor clock frequency throttling
6589 + * register value to use. This can be used to reduce the
6590 + * clock frequency when a power domain exits a low power
6591 + * mode until CPR settles at a new voltage.
6592 + * (platform specific)
6593 + * @cpr_allowed_hw: Boolean which indicates if closed-loop CPR operation is
6594 + * permitted for a given chip based upon hardware fuse
6595 + * values
6596 + * @cpr_allowed_sw: Boolean which indicates if closed-loop CPR operation is
6597 + * permitted based upon software policies
6598 + * @supports_hw_closed_loop: Boolean which indicates if this CPR3/4 controller
6599 + * physically supports hardware closed-loop CPR operation
6600 + * @use_hw_closed_loop: Boolean which indicates that this controller will be
6601 + * using hardware closed-loop operation in place of
6602 + * software closed-loop operation.
6603 + * @ctrl_type: CPR controller type
6604 + * @saw_use_unit_mV: Boolean which indicates the unit used in SAW PVC
6605 + * interface is mV.
6606 + * @aggr_corner: CPR corner containing the most recently aggregated
6607 + * voltage configurations which are being used currently
6608 + * @cpr_enabled: Boolean which indicates that the CPR controller is
6609 + * enabled and operating in closed-loop mode. CPR clocks
6610 + * have been prepared and enabled whenever this flag is
6611 + * true.
6612 + * @last_corner_was_closed_loop: Boolean indicating if the last known corners
6613 + * were updated during closed loop operation.
6614 + * @cpr_suspended: Boolean which indicates that CPR has been temporarily
6615 + * disabled while enterring system suspend.
6616 + * @debugfs: Pointer to the debugfs directory of this CPR3 controller
6617 + * @aging_ref_volt: Reference voltage in microvolts to configure when
6618 + * performing CPR aging measurements.
6619 + * @aging_vdd_mode: vdd-supply regulator mode to configure before performing
6620 + * a CPR aging measurement. It should be one of
6621 + * REGULATOR_MODE_*.
6622 + * @aging_complete_vdd_mode: vdd-supply regulator mode to configure after
6623 + * performing a CPR aging measurement. It should be one of
6624 + * REGULATOR_MODE_*.
6625 + * @aging_ref_adjust_volt: The reference aging voltage margin in microvolts that
6626 + * should be added to the target quotients of the
6627 + * regulators managed by this controller after derating.
6628 + * @aging_required: Flag which indicates that a CPR aging measurement still
6629 + * needs to be performed for this CPR3 controller.
6630 + * @aging_succeeded: Flag which indicates that a CPR aging measurement has
6631 + * completed successfully.
6632 + * @aging_failed: Flag which indicates that a CPR aging measurement has
6633 + * failed to complete successfully.
6634 + * @aging_sensor: Array of CPR3 aging sensors which are used to perform
6635 + * aging measurements at a runtime.
6636 + * @aging_sensor_count: Number of elements in the aging_sensor array
6637 + * @aging_possible_mask: Optional bitmask used to mask off the
6638 + * aging_possible_reg register.
6639 + * @aging_possible_val: Optional value that the masked aging_possible_reg
6640 + * register must have in order for a CPR aging measurement
6641 + * to be possible.
6642 + * @step_quot_fixed: Fixed step quotient value used for target quotient
6643 + * adjustment if use_dynamic_step_quot is not set.
6644 + * This parameter is only relevant for CPR4 controllers
6645 + * when using the per-online-core or per-temperature
6646 + * adjustments.
6647 + * @initial_temp_band: Temperature band used for calculation of base-line
6648 + * target quotients (fused).
6649 + * @use_dynamic_step_quot: Boolean value which indicates that margin adjustment
6650 + * of target quotient will be based on the step quotient
6651 + * calculated dynamically in hardware for each RO.
6652 + * @allow_core_count_adj: Core count adjustments are allowed for this controller
6653 + * @allow_temp_adj: Temperature based adjustments are allowed for
6654 + * this controller
6655 + * @allow_boost: Voltage boost allowed for this controller.
6656 + * @temp_band_count: Number of temperature bands used for temperature based
6657 + * adjustment logic
6658 + * @temp_points: Array of temperature points in decidegrees Celsius used
6659 + * to specify the ranges for selected temperature bands.
6660 + * The array must have (temp_band_count - 1) elements
6661 + * allocated.
6662 + * @temp_sensor_id_start: Start ID of temperature sensors used for temperature
6663 + * based adjustments.
6664 + * @temp_sensor_id_end: End ID of temperature sensors used for temperature
6665 + * based adjustments.
6666 + * @voltage_settling_time: The time in nanoseconds that it takes for the
6667 + * VDD supply voltage to settle after being increased or
6668 + * decreased by step_volt microvolts which is used when
6669 + * SDELTA voltage margin adjustments are applied.
6670 + * @cpr_global_setting: Global setting for this CPR controller
6671 + * @panic_regs_info: Array of panic registers information which provides the
6672 + * list of registers to dump when the device crashes.
6673 + * @panic_notifier: Notifier block registered to global panic notifier list.
6674 + *
6675 + * This structure contains both configuration and runtime state data. The
6676 + * elements cpr_allowed_sw, use_hw_closed_loop, aggr_corner, cpr_enabled,
6677 + * last_corner_was_closed_loop, cpr_suspended, aging_ref_adjust_volt,
6678 + * aging_required, aging_succeeded, and aging_failed are state variables.
6679 + *
6680 + * The apm* elements do not need to be initialized if the VDD supply managed by
6681 + * the CPR3 controller does not utilize an APM.
6682 + *
6683 + * The elements step_quot_fixed, initial_temp_band, allow_core_count_adj,
6684 + * allow_temp_adj and temp* need to be initialized for CPR4 controllers which
6685 + * are using per-online-core or per-temperature adjustments.
6686 + */
6687 +struct cpr3_controller {
6688 + struct device *dev;
6689 + const char *name;
6690 + int ctrl_id;
6691 + void __iomem *cpr_ctrl_base;
6692 + void __iomem *fuse_base;
6693 + void __iomem *aging_possible_reg;
6694 + struct list_head list;
6695 + struct cpr3_thread *thread;
6696 + int thread_count;
6697 + u8 *sensor_owner;
6698 + int sensor_count;
6699 + int soc_revision;
6700 + struct mutex lock;
6701 + struct regulator *vdd_regulator;
6702 + struct regulator *system_regulator;
6703 + struct regulator *mem_acc_regulator;
6704 + struct regulator *vdd_limit_regulator;
6705 + int system_supply_max_volt;
6706 + int mem_acc_threshold_volt;
6707 + int mem_acc_corner_map[CPR3_MEM_ACC_CORNERS];
6708 + int mem_acc_crossover_volt;
6709 + struct clk *core_clk;
6710 + struct clk *iface_clk;
6711 + struct clk *bus_clk;
6712 + int irq;
6713 + struct cpumask irq_affinity_mask;
6714 + struct notifier_block cpu_hotplug_notifier;
6715 + int ceiling_irq;
6716 + struct msm_apm_ctrl_dev *apm;
6717 + int apm_threshold_volt;
6718 + int apm_crossover_volt;
6719 + int apm_adj_volt;
6720 + enum msm_apm_supply apm_high_supply;
6721 + enum msm_apm_supply apm_low_supply;
6722 + int base_volt;
6723 + u32 corner_switch_delay_time;
6724 + u32 cpr_clock_rate;
6725 + u32 sensor_time;
6726 + u32 loop_time;
6727 + u32 up_down_delay_time;
6728 + u32 idle_clocks;
6729 + u32 step_quot_init_min;
6730 + u32 step_quot_init_max;
6731 + int step_volt;
6732 + u32 down_error_step_limit;
6733 + u32 up_error_step_limit;
6734 + enum cpr3_count_mode count_mode;
6735 + u32 count_repeat;
6736 + u32 proc_clock_throttle;
6737 + bool cpr_allowed_hw;
6738 + bool cpr_allowed_sw;
6739 + bool supports_hw_closed_loop;
6740 + bool use_hw_closed_loop;
6741 + enum cpr_controller_type ctrl_type;
6742 + bool saw_use_unit_mV;
6743 + struct cpr3_corner aggr_corner;
6744 + bool cpr_enabled;
6745 + bool last_corner_was_closed_loop;
6746 + bool cpr_suspended;
6747 + struct dentry *debugfs;
6748 +
6749 + int aging_ref_volt;
6750 + unsigned int aging_vdd_mode;
6751 + unsigned int aging_complete_vdd_mode;
6752 + int aging_ref_adjust_volt;
6753 + bool aging_required;
6754 + bool aging_succeeded;
6755 + bool aging_failed;
6756 + struct cpr3_aging_sensor_info *aging_sensor;
6757 + int aging_sensor_count;
6758 + u32 cur_sensor_state;
6759 + u32 aging_possible_mask;
6760 + u32 aging_possible_val;
6761 +
6762 + u32 step_quot_fixed;
6763 + u32 initial_temp_band;
6764 + bool use_dynamic_step_quot;
6765 + bool allow_core_count_adj;
6766 + bool allow_temp_adj;
6767 + bool allow_boost;
6768 + int temp_band_count;
6769 + int *temp_points;
6770 + u32 temp_sensor_id_start;
6771 + u32 temp_sensor_id_end;
6772 + u32 voltage_settling_time;
6773 + enum cpr_setting cpr_global_setting;
6774 + struct cpr3_panic_regs_info *panic_regs_info;
6775 + struct notifier_block panic_notifier;
6776 +};
6777 +
6778 +/* Used for rounding voltages to the closest physically available set point. */
6779 +#define CPR3_ROUND(n, d) (DIV_ROUND_UP(n, d) * (d))
6780 +
6781 +#define cpr3_err(cpr3_thread, message, ...) \
6782 + pr_err("%s: " message, (cpr3_thread)->name, ##__VA_ARGS__)
6783 +#define cpr3_info(cpr3_thread, message, ...) \
6784 + pr_info("%s: " message, (cpr3_thread)->name, ##__VA_ARGS__)
6785 +#define cpr3_debug(cpr3_thread, message, ...) \
6786 + pr_debug("%s: " message, (cpr3_thread)->name, ##__VA_ARGS__)
6787 +
6788 +/*
6789 + * Offset subtracted from voltage corner values passed in from the regulator
6790 + * framework in order to get internal voltage corner values. This is needed
6791 + * since the regulator framework treats 0 as an error value at regulator
6792 + * registration time.
6793 + */
6794 +#define CPR3_CORNER_OFFSET 1
6795 +
6796 +#ifdef CONFIG_REGULATOR_CPR3
6797 +
6798 +int cpr3_regulator_register(struct platform_device *pdev,
6799 + struct cpr3_controller *ctrl);
6800 +int cpr3_open_loop_regulator_register(struct platform_device *pdev,
6801 + struct cpr3_controller *ctrl);
6802 +int cpr3_regulator_unregister(struct cpr3_controller *ctrl);
6803 +int cpr3_open_loop_regulator_unregister(struct cpr3_controller *ctrl);
6804 +int cpr3_regulator_suspend(struct cpr3_controller *ctrl);
6805 +int cpr3_regulator_resume(struct cpr3_controller *ctrl);
6806 +
6807 +int cpr3_allocate_threads(struct cpr3_controller *ctrl, u32 min_thread_id,
6808 + u32 max_thread_id);
6809 +int cpr3_map_fuse_base(struct cpr3_controller *ctrl,
6810 + struct platform_device *pdev);
6811 +int cpr3_read_tcsr_setting(struct cpr3_controller *ctrl,
6812 + struct platform_device *pdev, u8 start, u8 end);
6813 +int cpr3_read_fuse_param(void __iomem *fuse_base_addr,
6814 + const struct cpr3_fuse_param *param, u64 *param_value);
6815 +int cpr3_convert_open_loop_voltage_fuse(int ref_volt, int step_volt, u32 fuse,
6816 + int fuse_len);
6817 +u64 cpr3_interpolate(u64 x1, u64 y1, u64 x2, u64 y2, u64 x);
6818 +int cpr3_parse_array_property(struct cpr3_regulator *vreg,
6819 + const char *prop_name, int tuple_size, u32 *out);
6820 +int cpr3_parse_corner_array_property(struct cpr3_regulator *vreg,
6821 + const char *prop_name, int tuple_size, u32 *out);
6822 +int cpr3_parse_corner_band_array_property(struct cpr3_regulator *vreg,
6823 + const char *prop_name, int tuple_size, u32 *out);
6824 +int cpr3_parse_common_corner_data(struct cpr3_regulator *vreg);
6825 +int cpr3_parse_thread_u32(struct cpr3_thread *thread, const char *propname,
6826 + u32 *out_value, u32 value_min, u32 value_max);
6827 +int cpr3_parse_ctrl_u32(struct cpr3_controller *ctrl, const char *propname,
6828 + u32 *out_value, u32 value_min, u32 value_max);
6829 +int cpr3_parse_common_thread_data(struct cpr3_thread *thread);
6830 +int cpr3_parse_common_ctrl_data(struct cpr3_controller *ctrl);
6831 +int cpr3_parse_open_loop_common_ctrl_data(struct cpr3_controller *ctrl);
6832 +int cpr3_limit_open_loop_voltages(struct cpr3_regulator *vreg);
6833 +void cpr3_open_loop_voltage_as_ceiling(struct cpr3_regulator *vreg);
6834 +int cpr3_limit_floor_voltages(struct cpr3_regulator *vreg);
6835 +void cpr3_print_quots(struct cpr3_regulator *vreg);
6836 +int cpr3_determine_part_type(struct cpr3_regulator *vreg, int fuse_volt);
6837 +int cpr3_determine_temp_base_open_loop_correction(struct cpr3_regulator *vreg,
6838 + int *fuse_volt);
6839 +int cpr3_adjust_fused_open_loop_voltages(struct cpr3_regulator *vreg,
6840 + int *fuse_volt);
6841 +int cpr3_adjust_open_loop_voltages(struct cpr3_regulator *vreg);
6842 +int cpr3_quot_adjustment(int ro_scale, int volt_adjust);
6843 +int cpr3_voltage_adjustment(int ro_scale, int quot_adjust);
6844 +int cpr3_parse_closed_loop_voltage_adjustments(struct cpr3_regulator *vreg,
6845 + u64 *ro_sel, int *volt_adjust,
6846 + int *volt_adjust_fuse, int *ro_scale);
6847 +int cpr4_parse_core_count_temp_voltage_adj(struct cpr3_regulator *vreg,
6848 + bool use_corner_band);
6849 +int cpr3_apm_init(struct cpr3_controller *ctrl);
6850 +int cpr3_mem_acc_init(struct cpr3_regulator *vreg);
6851 +void cprh_adjust_voltages_for_apm(struct cpr3_regulator *vreg);
6852 +void cprh_adjust_voltages_for_mem_acc(struct cpr3_regulator *vreg);
6853 +int cpr3_adjust_target_quotients(struct cpr3_regulator *vreg,
6854 + int *fuse_volt_adjust);
6855 +int cpr3_handle_temp_open_loop_adjustment(struct cpr3_controller *ctrl,
6856 + bool is_cold);
6857 +int cpr3_get_cold_temp_threshold(struct cpr3_regulator *vreg, int *cold_temp);
6858 +bool cpr3_can_adjust_cold_temp(struct cpr3_regulator *vreg);
6859 +
6860 +#else
6861 +
6862 +static inline int cpr3_regulator_register(struct platform_device *pdev,
6863 + struct cpr3_controller *ctrl)
6864 +{
6865 + return -ENXIO;
6866 +}
6867 +
6868 +static inline int
6869 +cpr3_open_loop_regulator_register(struct platform_device *pdev,
6870 + struct cpr3_controller *ctrl);
6871 +{
6872 + return -ENXIO;
6873 +}
6874 +
6875 +static inline int cpr3_regulator_unregister(struct cpr3_controller *ctrl)
6876 +{
6877 + return -ENXIO;
6878 +}
6879 +
6880 +static inline int
6881 +cpr3_open_loop_regulator_unregister(struct cpr3_controller *ctrl)
6882 +{
6883 + return -ENXIO;
6884 +}
6885 +
6886 +static inline int cpr3_regulator_suspend(struct cpr3_controller *ctrl)
6887 +{
6888 + return -ENXIO;
6889 +}
6890 +
6891 +static inline int cpr3_regulator_resume(struct cpr3_controller *ctrl)
6892 +{
6893 + return -ENXIO;
6894 +}
6895 +
6896 +static inline int cpr3_get_thread_name(struct cpr3_thread *thread,
6897 + struct device_node *thread_node)
6898 +{
6899 + return -EPERM;
6900 +}
6901 +
6902 +static inline int cpr3_allocate_threads(struct cpr3_controller *ctrl,
6903 + u32 min_thread_id, u32 max_thread_id)
6904 +{
6905 + return -EPERM;
6906 +}
6907 +
6908 +static inline int cpr3_map_fuse_base(struct cpr3_controller *ctrl,
6909 + struct platform_device *pdev)
6910 +{
6911 + return -ENXIO;
6912 +}
6913 +
6914 +static inline int cpr3_read_tcsr_setting(struct cpr3_controller *ctrl,
6915 + struct platform_device *pdev, u8 start, u8 end)
6916 +{
6917 + return 0;
6918 +}
6919 +
6920 +static inline int cpr3_read_fuse_param(void __iomem *fuse_base_addr,
6921 + const struct cpr3_fuse_param *param, u64 *param_value)
6922 +{
6923 + return -EPERM;
6924 +}
6925 +
6926 +static inline int cpr3_convert_open_loop_voltage_fuse(int ref_volt,
6927 + int step_volt, u32 fuse, int fuse_len)
6928 +{
6929 + return -EPERM;
6930 +}
6931 +
6932 +static inline u64 cpr3_interpolate(u64 x1, u64 y1, u64 x2, u64 y2, u64 x)
6933 +{
6934 + return 0;
6935 +}
6936 +
6937 +static inline int cpr3_parse_array_property(struct cpr3_regulator *vreg,
6938 + const char *prop_name, int tuple_size, u32 *out)
6939 +{
6940 + return -EPERM;
6941 +}
6942 +
6943 +static inline int cpr3_parse_corner_array_property(struct cpr3_regulator *vreg,
6944 + const char *prop_name, int tuple_size, u32 *out)
6945 +{
6946 + return -EPERM;
6947 +}
6948 +
6949 +static inline int cpr3_parse_corner_band_array_property(
6950 + struct cpr3_regulator *vreg, const char *prop_name,
6951 + int tuple_size, u32 *out)
6952 +{
6953 + return -EPERM;
6954 +}
6955 +
6956 +static inline int cpr3_parse_common_corner_data(struct cpr3_regulator *vreg)
6957 +{
6958 + return -EPERM;
6959 +}
6960 +
6961 +static inline int cpr3_parse_thread_u32(struct cpr3_thread *thread,
6962 + const char *propname, u32 *out_value, u32 value_min,
6963 + u32 value_max)
6964 +{
6965 + return -EPERM;
6966 +}
6967 +
6968 +static inline int cpr3_parse_ctrl_u32(struct cpr3_controller *ctrl,
6969 + const char *propname, u32 *out_value, u32 value_min,
6970 + u32 value_max)
6971 +{
6972 + return -EPERM;
6973 +}
6974 +
6975 +static inline int cpr3_parse_common_thread_data(struct cpr3_thread *thread)
6976 +{
6977 + return -EPERM;
6978 +}
6979 +
6980 +static inline int cpr3_parse_common_ctrl_data(struct cpr3_controller *ctrl)
6981 +{
6982 + return -EPERM;
6983 +}
6984 +
6985 +static inline int
6986 +cpr3_parse_open_loop_common_ctrl_data(struct cpr3_controller *ctrl)
6987 +{
6988 + return -EPERM;
6989 +}
6990 +
6991 +static inline int cpr3_limit_open_loop_voltages(struct cpr3_regulator *vreg)
6992 +{
6993 + return -EPERM;
6994 +}
6995 +
6996 +static inline void cpr3_open_loop_voltage_as_ceiling(
6997 + struct cpr3_regulator *vreg)
6998 +{
6999 + return;
7000 +}
7001 +
7002 +static inline int cpr3_limit_floor_voltages(struct cpr3_regulator *vreg)
7003 +{
7004 + return -EPERM;
7005 +}
7006 +
7007 +static inline void cpr3_print_quots(struct cpr3_regulator *vreg)
7008 +{
7009 + return;
7010 +}
7011 +
7012 +static inline int
7013 +cpr3_determine_part_type(struct cpr3_regulator *vreg, int fuse_volt)
7014 +{
7015 + return -EPERM;
7016 +}
7017 +
7018 +static inline int
7019 +cpr3_determine_temp_base_open_loop_correction(struct cpr3_regulator *vreg,
7020 + int *fuse_volt)
7021 +{
7022 + return -EPERM;
7023 +}
7024 +
7025 +static inline int cpr3_adjust_fused_open_loop_voltages(
7026 + struct cpr3_regulator *vreg, int *fuse_volt)
7027 +{
7028 + return -EPERM;
7029 +}
7030 +
7031 +static inline int cpr3_adjust_open_loop_voltages(struct cpr3_regulator *vreg)
7032 +{
7033 + return -EPERM;
7034 +}
7035 +
7036 +static inline int cpr3_quot_adjustment(int ro_scale, int volt_adjust)
7037 +{
7038 + return 0;
7039 +}
7040 +
7041 +static inline int cpr3_voltage_adjustment(int ro_scale, int quot_adjust)
7042 +{
7043 + return 0;
7044 +}
7045 +
7046 +static inline int cpr3_parse_closed_loop_voltage_adjustments(
7047 + struct cpr3_regulator *vreg, u64 *ro_sel,
7048 + int *volt_adjust, int *volt_adjust_fuse, int *ro_scale)
7049 +{
7050 + return 0;
7051 +}
7052 +
7053 +static inline int cpr4_parse_core_count_temp_voltage_adj(
7054 + struct cpr3_regulator *vreg, bool use_corner_band)
7055 +{
7056 + return 0;
7057 +}
7058 +
7059 +static inline int cpr3_apm_init(struct cpr3_controller *ctrl)
7060 +{
7061 + return 0;
7062 +}
7063 +
7064 +static inline int cpr3_mem_acc_init(struct cpr3_regulator *vreg)
7065 +{
7066 + return 0;
7067 +}
7068 +
7069 +static inline void cprh_adjust_voltages_for_apm(struct cpr3_regulator *vreg)
7070 +{
7071 +}
7072 +
7073 +static inline void cprh_adjust_voltages_for_mem_acc(struct cpr3_regulator *vreg)
7074 +{
7075 +}
7076 +
7077 +static inline int cpr3_adjust_target_quotients(struct cpr3_regulator *vreg,
7078 + int *fuse_volt_adjust)
7079 +{
7080 + return 0;
7081 +}
7082 +
7083 +static inline int
7084 +cpr3_handle_temp_open_loop_adjustment(struct cpr3_controller *ctrl,
7085 + bool is_cold)
7086 +{
7087 + return 0;
7088 +}
7089 +
7090 +static inline bool
7091 +cpr3_can_adjust_cold_temp(struct cpr3_regulator *vreg)
7092 +{
7093 + return false;
7094 +}
7095 +
7096 +static inline int
7097 +cpr3_get_cold_temp_threshold(struct cpr3_regulator *vreg, int *cold_temp)
7098 +{
7099 + return 0;
7100 +}
7101 +#endif /* CONFIG_REGULATOR_CPR3 */
7102 +
7103 +#endif /* __REGULATOR_CPR_REGULATOR_H__ */
7104 --- /dev/null
7105 +++ b/drivers/regulator/cpr3-util.c
7106 @@ -0,0 +1,2750 @@
7107 +/*
7108 + * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
7109 + *
7110 + * This program is free software; you can redistribute it and/or modify
7111 + * it under the terms of the GNU General Public License version 2 and
7112 + * only version 2 as published by the Free Software Foundation.
7113 + *
7114 + * This program is distributed in the hope that it will be useful,
7115 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
7116 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
7117 + * GNU General Public License for more details.
7118 + */
7119 +
7120 +/*
7121 + * This file contains utility functions to be used by platform specific CPR3
7122 + * regulator drivers.
7123 + */
7124 +
7125 +#define pr_fmt(fmt) "%s: " fmt, __func__
7126 +
7127 +#include <linux/cpumask.h>
7128 +#include <linux/device.h>
7129 +#include <linux/io.h>
7130 +#include <linux/kernel.h>
7131 +#include <linux/of.h>
7132 +#include <linux/platform_device.h>
7133 +#include <linux/slab.h>
7134 +#include <linux/types.h>
7135 +
7136 +#include <soc/qcom/socinfo.h>
7137 +
7138 +#include "cpr3-regulator.h"
7139 +
7140 +#define BYTES_PER_FUSE_ROW 8
7141 +#define MAX_FUSE_ROW_BIT 63
7142 +
7143 +#define CPR3_CONSECUTIVE_UP_DOWN_MIN 0
7144 +#define CPR3_CONSECUTIVE_UP_DOWN_MAX 15
7145 +#define CPR3_UP_DOWN_THRESHOLD_MIN 0
7146 +#define CPR3_UP_DOWN_THRESHOLD_MAX 31
7147 +#define CPR3_STEP_QUOT_MIN 0
7148 +#define CPR3_STEP_QUOT_MAX 63
7149 +#define CPR3_IDLE_CLOCKS_MIN 0
7150 +#define CPR3_IDLE_CLOCKS_MAX 31
7151 +
7152 +/* This constant has units of uV/mV so 1000 corresponds to 100%. */
7153 +#define CPR3_AGING_DERATE_UNITY 1000
7154 +
7155 +/**
7156 + * cpr3_allocate_regulators() - allocate and initialize CPR3 regulators for a
7157 + * given thread based upon device tree data
7158 + * @thread: Pointer to the CPR3 thread
7159 + *
7160 + * This function allocates the thread->vreg array based upon the number of
7161 + * device tree regulator subnodes. It also initializes generic elements of each
7162 + * regulator struct such as name, of_node, and thread.
7163 + *
7164 + * Return: 0 on success, errno on failure
7165 + */
7166 +static int cpr3_allocate_regulators(struct cpr3_thread *thread)
7167 +{
7168 + struct device_node *node;
7169 + int i, rc;
7170 +
7171 + thread->vreg_count = 0;
7172 +
7173 + for_each_available_child_of_node(thread->of_node, node) {
7174 + thread->vreg_count++;
7175 + }
7176 +
7177 + thread->vreg = devm_kcalloc(thread->ctrl->dev, thread->vreg_count,
7178 + sizeof(*thread->vreg), GFP_KERNEL);
7179 + if (!thread->vreg)
7180 + return -ENOMEM;
7181 +
7182 + i = 0;
7183 + for_each_available_child_of_node(thread->of_node, node) {
7184 + thread->vreg[i].of_node = node;
7185 + thread->vreg[i].thread = thread;
7186 +
7187 + rc = of_property_read_string(node, "regulator-name",
7188 + &thread->vreg[i].name);
7189 + if (rc) {
7190 + dev_err(thread->ctrl->dev, "could not find regulator name, rc=%d\n",
7191 + rc);
7192 + return rc;
7193 + }
7194 +
7195 + i++;
7196 + }
7197 +
7198 + return 0;
7199 +}
7200 +
7201 +/**
7202 + * cpr3_allocate_threads() - allocate and initialize CPR3 threads for a given
7203 + * controller based upon device tree data
7204 + * @ctrl: Pointer to the CPR3 controller
7205 + * @min_thread_id: Minimum allowed hardware thread ID for this controller
7206 + * @max_thread_id: Maximum allowed hardware thread ID for this controller
7207 + *
7208 + * This function allocates the ctrl->thread array based upon the number of
7209 + * device tree thread subnodes. It also initializes generic elements of each
7210 + * thread struct such as thread_id, of_node, ctrl, and vreg array.
7211 + *
7212 + * Return: 0 on success, errno on failure
7213 + */
7214 +int cpr3_allocate_threads(struct cpr3_controller *ctrl, u32 min_thread_id,
7215 + u32 max_thread_id)
7216 +{
7217 + struct device *dev = ctrl->dev;
7218 + struct device_node *thread_node;
7219 + int i, j, rc;
7220 +
7221 + ctrl->thread_count = 0;
7222 +
7223 + for_each_available_child_of_node(dev->of_node, thread_node) {
7224 + ctrl->thread_count++;
7225 + }
7226 +
7227 + ctrl->thread = devm_kcalloc(dev, ctrl->thread_count,
7228 + sizeof(*ctrl->thread), GFP_KERNEL);
7229 + if (!ctrl->thread)
7230 + return -ENOMEM;
7231 +
7232 + i = 0;
7233 + for_each_available_child_of_node(dev->of_node, thread_node) {
7234 + ctrl->thread[i].of_node = thread_node;
7235 + ctrl->thread[i].ctrl = ctrl;
7236 +
7237 + rc = of_property_read_u32(thread_node, "qcom,cpr-thread-id",
7238 + &ctrl->thread[i].thread_id);
7239 + if (rc) {
7240 + dev_err(dev, "could not read DT property qcom,cpr-thread-id, rc=%d\n",
7241 + rc);
7242 + return rc;
7243 + }
7244 +
7245 + if (ctrl->thread[i].thread_id < min_thread_id ||
7246 + ctrl->thread[i].thread_id > max_thread_id) {
7247 + dev_err(dev, "invalid thread id = %u; not within [%u, %u]\n",
7248 + ctrl->thread[i].thread_id, min_thread_id,
7249 + max_thread_id);
7250 + return -EINVAL;
7251 + }
7252 +
7253 + /* Verify that the thread ID is unique for all child nodes. */
7254 + for (j = 0; j < i; j++) {
7255 + if (ctrl->thread[j].thread_id
7256 + == ctrl->thread[i].thread_id) {
7257 + dev_err(dev, "duplicate thread id = %u found\n",
7258 + ctrl->thread[i].thread_id);
7259 + return -EINVAL;
7260 + }
7261 + }
7262 +
7263 + rc = cpr3_allocate_regulators(&ctrl->thread[i]);
7264 + if (rc)
7265 + return rc;
7266 +
7267 + i++;
7268 + }
7269 +
7270 + return 0;
7271 +}
7272 +
7273 +/**
7274 + * cpr3_map_fuse_base() - ioremap the base address of the fuse region
7275 + * @ctrl: Pointer to the CPR3 controller
7276 + * @pdev: Platform device pointer for the CPR3 controller
7277 + *
7278 + * Return: 0 on success, errno on failure
7279 + */
7280 +int cpr3_map_fuse_base(struct cpr3_controller *ctrl,
7281 + struct platform_device *pdev)
7282 +{
7283 + struct resource *res;
7284 +
7285 + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fuse_base");
7286 + if (!res || !res->start) {
7287 + dev_err(&pdev->dev, "fuse base address is missing\n");
7288 + return -ENXIO;
7289 + }
7290 +
7291 + ctrl->fuse_base = devm_ioremap(&pdev->dev, res->start,
7292 + resource_size(res));
7293 +
7294 + return 0;
7295 +}
7296 +
7297 +/**
7298 + * cpr3_read_tcsr_setting - reads the CPR setting bits from TCSR register
7299 + * @ctrl: Pointer to the CPR3 controller
7300 + * @pdev: Platform device pointer for the CPR3 controller
7301 + * @start: start bit in TCSR register
7302 + * @end: end bit in TCSR register
7303 + *
7304 + * Return: 0 on success, errno on failure
7305 + */
7306 +int cpr3_read_tcsr_setting(struct cpr3_controller *ctrl,
7307 + struct platform_device *pdev, u8 start, u8 end)
7308 +{
7309 + struct resource *res;
7310 + void __iomem *tcsr_reg;
7311 + u32 val;
7312 +
7313 + res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
7314 + "cpr_tcsr_reg");
7315 + if (!res || !res->start)
7316 + return 0;
7317 +
7318 + tcsr_reg = ioremap(res->start, resource_size(res));
7319 + if (!tcsr_reg) {
7320 + dev_err(&pdev->dev, "tcsr ioremap failed\n");
7321 + return 0;
7322 + }
7323 +
7324 + val = readl_relaxed(tcsr_reg);
7325 + val &= GENMASK(end, start);
7326 + val >>= start;
7327 +
7328 + switch (val) {
7329 + case 1:
7330 + ctrl->cpr_global_setting = CPR_DISABLED;
7331 + break;
7332 + case 2:
7333 + ctrl->cpr_global_setting = CPR_OPEN_LOOP_EN;
7334 + break;
7335 + case 3:
7336 + ctrl->cpr_global_setting = CPR_CLOSED_LOOP_EN;
7337 + break;
7338 + default:
7339 + ctrl->cpr_global_setting = CPR_DEFAULT;
7340 + }
7341 +
7342 + iounmap(tcsr_reg);
7343 +
7344 + return 0;
7345 +}
7346 +
7347 +/**
7348 + * cpr3_read_fuse_param() - reads a CPR3 fuse parameter out of eFuses
7349 + * @fuse_base_addr: Virtual memory address of the eFuse base address
7350 + * @param: Null terminated array of fuse param segments to read
7351 + * from
7352 + * @param_value: Output with value read from the eFuses
7353 + *
7354 + * This function reads from each of the parameter segments listed in the param
7355 + * array and concatenates their values together. Reading stops when an element
7356 + * is reached which has all 0 struct values. The total number of bits specified
7357 + * for the fuse parameter across all segments must be less than or equal to 64.
7358 + *
7359 + * Return: 0 on success, errno on failure
7360 + */
7361 +int cpr3_read_fuse_param(void __iomem *fuse_base_addr,
7362 + const struct cpr3_fuse_param *param, u64 *param_value)
7363 +{
7364 + u64 fuse_val, val;
7365 + int bits;
7366 + int bits_total = 0;
7367 +
7368 + *param_value = 0;
7369 +
7370 + while (param->row || param->bit_start || param->bit_end) {
7371 + if (param->bit_start > param->bit_end
7372 + || param->bit_end > MAX_FUSE_ROW_BIT) {
7373 + pr_err("Invalid fuse parameter segment: row=%u, start=%u, end=%u\n",
7374 + param->row, param->bit_start, param->bit_end);
7375 + return -EINVAL;
7376 + }
7377 +
7378 + bits = param->bit_end - param->bit_start + 1;
7379 + if (bits_total + bits > 64) {
7380 + pr_err("Invalid fuse parameter segments; total bits = %d\n",
7381 + bits_total + bits);
7382 + return -EINVAL;
7383 + }
7384 +
7385 + fuse_val = readq_relaxed(fuse_base_addr
7386 + + param->row * BYTES_PER_FUSE_ROW);
7387 + val = (fuse_val >> param->bit_start) & ((1ULL << bits) - 1);
7388 + *param_value |= val << bits_total;
7389 + bits_total += bits;
7390 +
7391 + param++;
7392 + }
7393 +
7394 + return 0;
7395 +}
7396 +
7397 +/**
7398 + * cpr3_convert_open_loop_voltage_fuse() - converts an open loop voltage fuse
7399 + * value into an absolute voltage with units of microvolts
7400 + * @ref_volt: Reference voltage in microvolts
7401 + * @step_volt: The step size in microvolts of the fuse LSB
7402 + * @fuse: Open loop voltage fuse value
7403 + * @fuse_len: The bit length of the fuse value
7404 + *
7405 + * The MSB of the fuse parameter corresponds to a sign bit. If it is set, then
7406 + * the lower bits correspond to the number of steps to go down from the
7407 + * reference voltage. If it is not set, then the lower bits correspond to the
7408 + * number of steps to go up from the reference voltage.
7409 + */
7410 +int cpr3_convert_open_loop_voltage_fuse(int ref_volt, int step_volt, u32 fuse,
7411 + int fuse_len)
7412 +{
7413 + int sign, steps;
7414 +
7415 + sign = (fuse & (1 << (fuse_len - 1))) ? -1 : 1;
7416 + steps = fuse & ((1 << (fuse_len - 1)) - 1);
7417 +
7418 + return ref_volt + sign * steps * step_volt;
7419 +}
7420 +
7421 +/**
7422 + * cpr3_interpolate() - performs linear interpolation
7423 + * @x1 Lower known x value
7424 + * @y1 Lower known y value
7425 + * @x2 Upper known x value
7426 + * @y2 Upper known y value
7427 + * @x Intermediate x value
7428 + *
7429 + * Returns y where (x, y) falls on the line between (x1, y1) and (x2, y2).
7430 + * It is required that x1 < x2, y1 <= y2, and x1 <= x <= x2. If these
7431 + * conditions are not met, then y2 will be returned.
7432 + */
7433 +u64 cpr3_interpolate(u64 x1, u64 y1, u64 x2, u64 y2, u64 x)
7434 +{
7435 + u64 temp;
7436 +
7437 + if (x1 >= x2 || y1 > y2 || x1 > x || x > x2)
7438 + return y2;
7439 +
7440 + temp = (x2 - x) * (y2 - y1);
7441 + do_div(temp, (u32)(x2 - x1));
7442 +
7443 + return y2 - temp;
7444 +}
7445 +
7446 +/**
7447 + * cpr3_parse_array_property() - fill an array from a portion of the values
7448 + * specified for a device tree property
7449 + * @vreg: Pointer to the CPR3 regulator
7450 + * @prop_name: The name of the device tree property to read from
7451 + * @tuple_size: The number of elements in each tuple
7452 + * @out: Output data array which must be of size tuple_size
7453 + *
7454 + * cpr3_parse_common_corner_data() must be called for vreg before this function
7455 + * is called so that fuse combo and speed bin size elements are initialized.
7456 + *
7457 + * Three formats are supported for the device tree property:
7458 + * 1. Length == tuple_size
7459 + * (reading begins at index 0)
7460 + * 2. Length == tuple_size * vreg->fuse_combos_supported
7461 + * (reading begins at index tuple_size * vreg->fuse_combo)
7462 + * 3. Length == tuple_size * vreg->speed_bins_supported
7463 + * (reading begins at index tuple_size * vreg->speed_bin_fuse)
7464 + *
7465 + * All other property lengths are treated as errors.
7466 + *
7467 + * Return: 0 on success, errno on failure
7468 + */
7469 +int cpr3_parse_array_property(struct cpr3_regulator *vreg,
7470 + const char *prop_name, int tuple_size, u32 *out)
7471 +{
7472 + struct device_node *node = vreg->of_node;
7473 + int len = 0;
7474 + int i, offset, rc;
7475 +
7476 + if (!of_find_property(node, prop_name, &len)) {
7477 + cpr3_err(vreg, "property %s is missing\n", prop_name);
7478 + return -EINVAL;
7479 + }
7480 +
7481 + if (len == tuple_size * sizeof(u32)) {
7482 + offset = 0;
7483 + } else if (len == tuple_size * vreg->fuse_combos_supported
7484 + * sizeof(u32)) {
7485 + offset = tuple_size * vreg->fuse_combo;
7486 + } else if (vreg->speed_bins_supported > 0 &&
7487 + len == tuple_size * vreg->speed_bins_supported * sizeof(u32)) {
7488 + offset = tuple_size * vreg->speed_bin_fuse;
7489 + } else {
7490 + if (vreg->speed_bins_supported > 0)
7491 + cpr3_err(vreg, "property %s has invalid length=%d, should be %zu, %zu, or %zu\n",
7492 + prop_name, len,
7493 + tuple_size * sizeof(u32),
7494 + tuple_size * vreg->speed_bins_supported
7495 + * sizeof(u32),
7496 + tuple_size * vreg->fuse_combos_supported
7497 + * sizeof(u32));
7498 + else
7499 + cpr3_err(vreg, "property %s has invalid length=%d, should be %zu or %zu\n",
7500 + prop_name, len,
7501 + tuple_size * sizeof(u32),
7502 + tuple_size * vreg->fuse_combos_supported
7503 + * sizeof(u32));
7504 + return -EINVAL;
7505 + }
7506 +
7507 + for (i = 0; i < tuple_size; i++) {
7508 + rc = of_property_read_u32_index(node, prop_name, offset + i,
7509 + &out[i]);
7510 + if (rc) {
7511 + cpr3_err(vreg, "error reading property %s, rc=%d\n",
7512 + prop_name, rc);
7513 + return rc;
7514 + }
7515 + }
7516 +
7517 + return 0;
7518 +}
7519 +
7520 +/**
7521 + * cpr3_parse_corner_array_property() - fill a per-corner array from a portion
7522 + * of the values specified for a device tree property
7523 + * @vreg: Pointer to the CPR3 regulator
7524 + * @prop_name: The name of the device tree property to read from
7525 + * @tuple_size: The number of elements in each per-corner tuple
7526 + * @out: Output data array which must be of size:
7527 + * tuple_size * vreg->corner_count
7528 + *
7529 + * cpr3_parse_common_corner_data() must be called for vreg before this function
7530 + * is called so that fuse combo and speed bin size elements are initialized.
7531 + *
7532 + * Three formats are supported for the device tree property:
7533 + * 1. Length == tuple_size * vreg->corner_count
7534 + * (reading begins at index 0)
7535 + * 2. Length == tuple_size * vreg->fuse_combo_corner_sum
7536 + * (reading begins at index tuple_size * vreg->fuse_combo_offset)
7537 + * 3. Length == tuple_size * vreg->speed_bin_corner_sum
7538 + * (reading begins at index tuple_size * vreg->speed_bin_offset)
7539 + *
7540 + * All other property lengths are treated as errors.
7541 + *
7542 + * Return: 0 on success, errno on failure
7543 + */
7544 +int cpr3_parse_corner_array_property(struct cpr3_regulator *vreg,
7545 + const char *prop_name, int tuple_size, u32 *out)
7546 +{
7547 + struct device_node *node = vreg->of_node;
7548 + int len = 0;
7549 + int i, offset, rc;
7550 +
7551 + if (!of_find_property(node, prop_name, &len)) {
7552 + cpr3_err(vreg, "property %s is missing\n", prop_name);
7553 + return -EINVAL;
7554 + }
7555 +
7556 + if (len == tuple_size * vreg->corner_count * sizeof(u32)) {
7557 + offset = 0;
7558 + } else if (len == tuple_size * vreg->fuse_combo_corner_sum
7559 + * sizeof(u32)) {
7560 + offset = tuple_size * vreg->fuse_combo_offset;
7561 + } else if (vreg->speed_bin_corner_sum > 0 &&
7562 + len == tuple_size * vreg->speed_bin_corner_sum * sizeof(u32)) {
7563 + offset = tuple_size * vreg->speed_bin_offset;
7564 + } else {
7565 + if (vreg->speed_bin_corner_sum > 0)
7566 + cpr3_err(vreg, "property %s has invalid length=%d, should be %zu, %zu, or %zu\n",
7567 + prop_name, len,
7568 + tuple_size * vreg->corner_count * sizeof(u32),
7569 + tuple_size * vreg->speed_bin_corner_sum
7570 + * sizeof(u32),
7571 + tuple_size * vreg->fuse_combo_corner_sum
7572 + * sizeof(u32));
7573 + else
7574 + cpr3_err(vreg, "property %s has invalid length=%d, should be %zu or %zu\n",
7575 + prop_name, len,
7576 + tuple_size * vreg->corner_count * sizeof(u32),
7577 + tuple_size * vreg->fuse_combo_corner_sum
7578 + * sizeof(u32));
7579 + return -EINVAL;
7580 + }
7581 +
7582 + for (i = 0; i < tuple_size * vreg->corner_count; i++) {
7583 + rc = of_property_read_u32_index(node, prop_name, offset + i,
7584 + &out[i]);
7585 + if (rc) {
7586 + cpr3_err(vreg, "error reading property %s, rc=%d\n",
7587 + prop_name, rc);
7588 + return rc;
7589 + }
7590 + }
7591 +
7592 + return 0;
7593 +}
7594 +
7595 +/**
7596 + * cpr3_parse_corner_band_array_property() - fill a per-corner band array
7597 + * from a portion of the values specified for a device tree
7598 + * property
7599 + * @vreg: Pointer to the CPR3 regulator
7600 + * @prop_name: The name of the device tree property to read from
7601 + * @tuple_size: The number of elements in each per-corner band tuple
7602 + * @out: Output data array which must be of size:
7603 + * tuple_size * vreg->corner_band_count
7604 + *
7605 + * cpr3_parse_common_corner_data() must be called for vreg before this function
7606 + * is called so that fuse combo and speed bin size elements are initialized.
7607 + * In addition, corner band fuse combo and speed bin sum and offset elements
7608 + * must be initialized prior to executing this function.
7609 + *
7610 + * Three formats are supported for the device tree property:
7611 + * 1. Length == tuple_size * vreg->corner_band_count
7612 + * (reading begins at index 0)
7613 + * 2. Length == tuple_size * vreg->fuse_combo_corner_band_sum
7614 + * (reading begins at index tuple_size *
7615 + * vreg->fuse_combo_corner_band_offset)
7616 + * 3. Length == tuple_size * vreg->speed_bin_corner_band_sum
7617 + * (reading begins at index tuple_size *
7618 + * vreg->speed_bin_corner_band_offset)
7619 + *
7620 + * All other property lengths are treated as errors.
7621 + *
7622 + * Return: 0 on success, errno on failure
7623 + */
7624 +int cpr3_parse_corner_band_array_property(struct cpr3_regulator *vreg,
7625 + const char *prop_name, int tuple_size, u32 *out)
7626 +{
7627 + struct device_node *node = vreg->of_node;
7628 + int len = 0;
7629 + int i, offset, rc;
7630 +
7631 + if (!of_find_property(node, prop_name, &len)) {
7632 + cpr3_err(vreg, "property %s is missing\n", prop_name);
7633 + return -EINVAL;
7634 + }
7635 +
7636 + if (len == tuple_size * vreg->corner_band_count * sizeof(u32)) {
7637 + offset = 0;
7638 + } else if (len == tuple_size * vreg->fuse_combo_corner_band_sum
7639 + * sizeof(u32)) {
7640 + offset = tuple_size * vreg->fuse_combo_corner_band_offset;
7641 + } else if (vreg->speed_bin_corner_band_sum > 0 &&
7642 + len == tuple_size * vreg->speed_bin_corner_band_sum *
7643 + sizeof(u32)) {
7644 + offset = tuple_size * vreg->speed_bin_corner_band_offset;
7645 + } else {
7646 + if (vreg->speed_bin_corner_band_sum > 0)
7647 + cpr3_err(vreg, "property %s has invalid length=%d, should be %zu, %zu, or %zu\n",
7648 + prop_name, len,
7649 + tuple_size * vreg->corner_band_count *
7650 + sizeof(u32),
7651 + tuple_size * vreg->speed_bin_corner_band_sum
7652 + * sizeof(u32),
7653 + tuple_size * vreg->fuse_combo_corner_band_sum
7654 + * sizeof(u32));
7655 + else
7656 + cpr3_err(vreg, "property %s has invalid length=%d, should be %zu or %zu\n",
7657 + prop_name, len,
7658 + tuple_size * vreg->corner_band_count *
7659 + sizeof(u32),
7660 + tuple_size * vreg->fuse_combo_corner_band_sum
7661 + * sizeof(u32));
7662 + return -EINVAL;
7663 + }
7664 +
7665 + for (i = 0; i < tuple_size * vreg->corner_band_count; i++) {
7666 + rc = of_property_read_u32_index(node, prop_name, offset + i,
7667 + &out[i]);
7668 + if (rc) {
7669 + cpr3_err(vreg, "error reading property %s, rc=%d\n",
7670 + prop_name, rc);
7671 + return rc;
7672 + }
7673 + }
7674 +
7675 + return 0;
7676 +}
7677 +
7678 +/**
7679 + * cpr3_parse_common_corner_data() - parse common CPR3 properties relating to
7680 + * the corners supported by a CPR3 regulator from device tree
7681 + * @vreg: Pointer to the CPR3 regulator
7682 + *
7683 + * This function reads, validates, and utilizes the following device tree
7684 + * properties: qcom,cpr-fuse-corners, qcom,cpr-fuse-combos, qcom,cpr-speed-bins,
7685 + * qcom,cpr-speed-bin-corners, qcom,cpr-corners, qcom,cpr-voltage-ceiling,
7686 + * qcom,cpr-voltage-floor, qcom,corner-frequencies,
7687 + * and qcom,cpr-corner-fmax-map.
7688 + *
7689 + * It initializes these CPR3 regulator elements: corner, corner_count,
7690 + * fuse_combos_supported, fuse_corner_map, and speed_bins_supported. It
7691 + * initializes these elements for each corner: ceiling_volt, floor_volt,
7692 + * proc_freq, and cpr_fuse_corner.
7693 + *
7694 + * It requires that the following CPR3 regulator elements be initialized before
7695 + * being called: fuse_corner_count, fuse_combo, and speed_bin_fuse.
7696 + *
7697 + * Return: 0 on success, errno on failure
7698 + */
7699 +int cpr3_parse_common_corner_data(struct cpr3_regulator *vreg)
7700 +{
7701 + struct device_node *node = vreg->of_node;
7702 + struct cpr3_controller *ctrl = vreg->thread->ctrl;
7703 + u32 max_fuse_combos, fuse_corners, aging_allowed = 0;
7704 + u32 max_speed_bins = 0;
7705 + u32 *combo_corners;
7706 + u32 *speed_bin_corners;
7707 + u32 *temp;
7708 + int i, j, rc;
7709 +
7710 + rc = of_property_read_u32(node, "qcom,cpr-fuse-corners", &fuse_corners);
7711 + if (rc) {
7712 + cpr3_err(vreg, "error reading property qcom,cpr-fuse-corners, rc=%d\n",
7713 + rc);
7714 + return rc;
7715 + }
7716 +
7717 + if (vreg->fuse_corner_count != fuse_corners) {
7718 + cpr3_err(vreg, "device tree config supports %d fuse corners but the hardware has %d fuse corners\n",
7719 + fuse_corners, vreg->fuse_corner_count);
7720 + return -EINVAL;
7721 + }
7722 +
7723 + rc = of_property_read_u32(node, "qcom,cpr-fuse-combos",
7724 + &max_fuse_combos);
7725 + if (rc) {
7726 + cpr3_err(vreg, "error reading property qcom,cpr-fuse-combos, rc=%d\n",
7727 + rc);
7728 + return rc;
7729 + }
7730 +
7731 + /*
7732 + * Sanity check against arbitrarily large value to avoid excessive
7733 + * memory allocation.
7734 + */
7735 + if (max_fuse_combos > 100 || max_fuse_combos == 0) {
7736 + cpr3_err(vreg, "qcom,cpr-fuse-combos is invalid: %u\n",
7737 + max_fuse_combos);
7738 + return -EINVAL;
7739 + }
7740 +
7741 + if (vreg->fuse_combo >= max_fuse_combos) {
7742 + cpr3_err(vreg, "device tree config supports fuse combos 0-%u but the hardware has combo %d\n",
7743 + max_fuse_combos - 1, vreg->fuse_combo);
7744 + BUG_ON(1);
7745 + return -EINVAL;
7746 + }
7747 +
7748 + vreg->fuse_combos_supported = max_fuse_combos;
7749 +
7750 + of_property_read_u32(node, "qcom,cpr-speed-bins", &max_speed_bins);
7751 +
7752 + /*
7753 + * Sanity check against arbitrarily large value to avoid excessive
7754 + * memory allocation.
7755 + */
7756 + if (max_speed_bins > 100) {
7757 + cpr3_err(vreg, "qcom,cpr-speed-bins is invalid: %u\n",
7758 + max_speed_bins);
7759 + return -EINVAL;
7760 + }
7761 +
7762 + if (max_speed_bins && vreg->speed_bin_fuse >= max_speed_bins) {
7763 + cpr3_err(vreg, "device tree config supports speed bins 0-%u but the hardware has speed bin %d\n",
7764 + max_speed_bins - 1, vreg->speed_bin_fuse);
7765 + BUG();
7766 + return -EINVAL;
7767 + }
7768 +
7769 + vreg->speed_bins_supported = max_speed_bins;
7770 +
7771 + combo_corners = kcalloc(vreg->fuse_combos_supported,
7772 + sizeof(*combo_corners), GFP_KERNEL);
7773 + if (!combo_corners)
7774 + return -ENOMEM;
7775 +
7776 + rc = of_property_read_u32_array(node, "qcom,cpr-corners", combo_corners,
7777 + vreg->fuse_combos_supported);
7778 + if (rc == -EOVERFLOW) {
7779 + /* Single value case */
7780 + rc = of_property_read_u32(node, "qcom,cpr-corners",
7781 + combo_corners);
7782 + for (i = 1; i < vreg->fuse_combos_supported; i++)
7783 + combo_corners[i] = combo_corners[0];
7784 + }
7785 + if (rc) {
7786 + cpr3_err(vreg, "error reading property qcom,cpr-corners, rc=%d\n",
7787 + rc);
7788 + kfree(combo_corners);
7789 + return rc;
7790 + }
7791 +
7792 + vreg->fuse_combo_offset = 0;
7793 + vreg->fuse_combo_corner_sum = 0;
7794 + for (i = 0; i < vreg->fuse_combos_supported; i++) {
7795 + vreg->fuse_combo_corner_sum += combo_corners[i];
7796 + if (i < vreg->fuse_combo)
7797 + vreg->fuse_combo_offset += combo_corners[i];
7798 + }
7799 +
7800 + vreg->corner_count = combo_corners[vreg->fuse_combo];
7801 +
7802 + kfree(combo_corners);
7803 +
7804 + vreg->speed_bin_offset = 0;
7805 + vreg->speed_bin_corner_sum = 0;
7806 + if (vreg->speed_bins_supported > 0) {
7807 + speed_bin_corners = kcalloc(vreg->speed_bins_supported,
7808 + sizeof(*speed_bin_corners), GFP_KERNEL);
7809 + if (!speed_bin_corners)
7810 + return -ENOMEM;
7811 +
7812 + rc = of_property_read_u32_array(node,
7813 + "qcom,cpr-speed-bin-corners", speed_bin_corners,
7814 + vreg->speed_bins_supported);
7815 + if (rc) {
7816 + cpr3_err(vreg, "error reading property qcom,cpr-speed-bin-corners, rc=%d\n",
7817 + rc);
7818 + kfree(speed_bin_corners);
7819 + return rc;
7820 + }
7821 +
7822 + for (i = 0; i < vreg->speed_bins_supported; i++) {
7823 + vreg->speed_bin_corner_sum += speed_bin_corners[i];
7824 + if (i < vreg->speed_bin_fuse)
7825 + vreg->speed_bin_offset += speed_bin_corners[i];
7826 + }
7827 +
7828 + if (speed_bin_corners[vreg->speed_bin_fuse]
7829 + != vreg->corner_count) {
7830 + cpr3_err(vreg, "qcom,cpr-corners and qcom,cpr-speed-bin-corners conflict on number of corners: %d vs %u\n",
7831 + vreg->corner_count,
7832 + speed_bin_corners[vreg->speed_bin_fuse]);
7833 + kfree(speed_bin_corners);
7834 + return -EINVAL;
7835 + }
7836 +
7837 + kfree(speed_bin_corners);
7838 + }
7839 +
7840 + vreg->corner = devm_kcalloc(ctrl->dev, vreg->corner_count,
7841 + sizeof(*vreg->corner), GFP_KERNEL);
7842 + temp = kcalloc(vreg->corner_count, sizeof(*temp), GFP_KERNEL);
7843 + if (!vreg->corner || !temp)
7844 + return -ENOMEM;
7845 +
7846 + rc = cpr3_parse_corner_array_property(vreg, "qcom,cpr-voltage-ceiling",
7847 + 1, temp);
7848 + if (rc)
7849 + goto free_temp;
7850 + for (i = 0; i < vreg->corner_count; i++) {
7851 + vreg->corner[i].ceiling_volt
7852 + = CPR3_ROUND(temp[i], ctrl->step_volt);
7853 + vreg->corner[i].abs_ceiling_volt = vreg->corner[i].ceiling_volt;
7854 + }
7855 +
7856 + rc = cpr3_parse_corner_array_property(vreg, "qcom,cpr-voltage-floor",
7857 + 1, temp);
7858 + if (rc)
7859 + goto free_temp;
7860 + for (i = 0; i < vreg->corner_count; i++)
7861 + vreg->corner[i].floor_volt
7862 + = CPR3_ROUND(temp[i], ctrl->step_volt);
7863 +
7864 + /* Validate ceiling and floor values */
7865 + for (i = 0; i < vreg->corner_count; i++) {
7866 + if (vreg->corner[i].floor_volt
7867 + > vreg->corner[i].ceiling_volt) {
7868 + cpr3_err(vreg, "CPR floor[%d]=%d > ceiling[%d]=%d uV\n",
7869 + i, vreg->corner[i].floor_volt,
7870 + i, vreg->corner[i].ceiling_volt);
7871 + rc = -EINVAL;
7872 + goto free_temp;
7873 + }
7874 + }
7875 +
7876 + /* Load optional system-supply voltages */
7877 + if (of_find_property(vreg->of_node, "qcom,system-voltage", NULL)) {
7878 + rc = cpr3_parse_corner_array_property(vreg,
7879 + "qcom,system-voltage", 1, temp);
7880 + if (rc)
7881 + goto free_temp;
7882 + for (i = 0; i < vreg->corner_count; i++)
7883 + vreg->corner[i].system_volt = temp[i];
7884 + }
7885 +
7886 + rc = cpr3_parse_corner_array_property(vreg, "qcom,corner-frequencies",
7887 + 1, temp);
7888 + if (rc)
7889 + goto free_temp;
7890 + for (i = 0; i < vreg->corner_count; i++)
7891 + vreg->corner[i].proc_freq = temp[i];
7892 +
7893 + /* Validate frequencies */
7894 + for (i = 1; i < vreg->corner_count; i++) {
7895 + if (vreg->corner[i].proc_freq
7896 + < vreg->corner[i - 1].proc_freq) {
7897 + cpr3_err(vreg, "invalid frequency: freq[%d]=%u < freq[%d]=%u\n",
7898 + i, vreg->corner[i].proc_freq, i - 1,
7899 + vreg->corner[i - 1].proc_freq);
7900 + rc = -EINVAL;
7901 + goto free_temp;
7902 + }
7903 + }
7904 +
7905 + vreg->fuse_corner_map = devm_kcalloc(ctrl->dev, vreg->fuse_corner_count,
7906 + sizeof(*vreg->fuse_corner_map), GFP_KERNEL);
7907 + if (!vreg->fuse_corner_map) {
7908 + rc = -ENOMEM;
7909 + goto free_temp;
7910 + }
7911 +
7912 + rc = cpr3_parse_array_property(vreg, "qcom,cpr-corner-fmax-map",
7913 + vreg->fuse_corner_count, temp);
7914 + if (rc)
7915 + goto free_temp;
7916 + for (i = 0; i < vreg->fuse_corner_count; i++) {
7917 + vreg->fuse_corner_map[i] = temp[i] - CPR3_CORNER_OFFSET;
7918 + if (temp[i] < CPR3_CORNER_OFFSET
7919 + || temp[i] > vreg->corner_count + CPR3_CORNER_OFFSET) {
7920 + cpr3_err(vreg, "invalid corner value specified in qcom,cpr-corner-fmax-map: %u\n",
7921 + temp[i]);
7922 + rc = -EINVAL;
7923 + goto free_temp;
7924 + } else if (i > 0 && temp[i - 1] >= temp[i]) {
7925 + cpr3_err(vreg, "invalid corner %u less than or equal to previous corner %u\n",
7926 + temp[i], temp[i - 1]);
7927 + rc = -EINVAL;
7928 + goto free_temp;
7929 + }
7930 + }
7931 + if (temp[vreg->fuse_corner_count - 1] != vreg->corner_count)
7932 + cpr3_debug(vreg, "Note: highest Fmax corner %u in qcom,cpr-corner-fmax-map does not match highest supported corner %d\n",
7933 + temp[vreg->fuse_corner_count - 1],
7934 + vreg->corner_count);
7935 +
7936 + for (i = 0; i < vreg->corner_count; i++) {
7937 + for (j = 0; j < vreg->fuse_corner_count; j++) {
7938 + if (i + CPR3_CORNER_OFFSET <= temp[j]) {
7939 + vreg->corner[i].cpr_fuse_corner = j;
7940 + break;
7941 + }
7942 + }
7943 + if (j == vreg->fuse_corner_count) {
7944 + /*
7945 + * Handle the case where the highest fuse corner maps
7946 + * to a corner below the highest corner.
7947 + */
7948 + vreg->corner[i].cpr_fuse_corner
7949 + = vreg->fuse_corner_count - 1;
7950 + }
7951 + }
7952 +
7953 + if (of_find_property(vreg->of_node,
7954 + "qcom,allow-aging-voltage-adjustment", NULL)) {
7955 + rc = cpr3_parse_array_property(vreg,
7956 + "qcom,allow-aging-voltage-adjustment",
7957 + 1, &aging_allowed);
7958 + if (rc)
7959 + goto free_temp;
7960 +
7961 + vreg->aging_allowed = aging_allowed;
7962 + }
7963 +
7964 + if (of_find_property(vreg->of_node,
7965 + "qcom,allow-aging-open-loop-voltage-adjustment", NULL)) {
7966 + rc = cpr3_parse_array_property(vreg,
7967 + "qcom,allow-aging-open-loop-voltage-adjustment",
7968 + 1, &aging_allowed);
7969 + if (rc)
7970 + goto free_temp;
7971 +
7972 + vreg->aging_allow_open_loop_adj = aging_allowed;
7973 + }
7974 +
7975 + if (vreg->aging_allowed) {
7976 + if (ctrl->aging_ref_volt <= 0) {
7977 + cpr3_err(ctrl, "qcom,cpr-aging-ref-voltage must be specified\n");
7978 + rc = -EINVAL;
7979 + goto free_temp;
7980 + }
7981 +
7982 + rc = cpr3_parse_array_property(vreg,
7983 + "qcom,cpr-aging-max-voltage-adjustment",
7984 + 1, &vreg->aging_max_adjust_volt);
7985 + if (rc)
7986 + goto free_temp;
7987 +
7988 + rc = cpr3_parse_array_property(vreg,
7989 + "qcom,cpr-aging-ref-corner", 1, &vreg->aging_corner);
7990 + if (rc) {
7991 + goto free_temp;
7992 + } else if (vreg->aging_corner < CPR3_CORNER_OFFSET
7993 + || vreg->aging_corner > vreg->corner_count - 1
7994 + + CPR3_CORNER_OFFSET) {
7995 + cpr3_err(vreg, "aging reference corner=%d not in range [%d, %d]\n",
7996 + vreg->aging_corner, CPR3_CORNER_OFFSET,
7997 + vreg->corner_count - 1 + CPR3_CORNER_OFFSET);
7998 + rc = -EINVAL;
7999 + goto free_temp;
8000 + }
8001 + vreg->aging_corner -= CPR3_CORNER_OFFSET;
8002 +
8003 + if (of_find_property(vreg->of_node, "qcom,cpr-aging-derate",
8004 + NULL)) {
8005 + rc = cpr3_parse_corner_array_property(vreg,
8006 + "qcom,cpr-aging-derate", 1, temp);
8007 + if (rc)
8008 + goto free_temp;
8009 +
8010 + for (i = 0; i < vreg->corner_count; i++)
8011 + vreg->corner[i].aging_derate = temp[i];
8012 + } else {
8013 + for (i = 0; i < vreg->corner_count; i++)
8014 + vreg->corner[i].aging_derate
8015 + = CPR3_AGING_DERATE_UNITY;
8016 + }
8017 + }
8018 +
8019 +free_temp:
8020 + kfree(temp);
8021 + return rc;
8022 +}
8023 +
8024 +/**
8025 + * cpr3_parse_thread_u32() - parse the specified property from the CPR3 thread's
8026 + * device tree node and verify that it is within the allowed limits
8027 + * @thread: Pointer to the CPR3 thread
8028 + * @propname: The name of the device tree property to read
8029 + * @out_value: The output pointer to fill with the value read
8030 + * @value_min: The minimum allowed property value
8031 + * @value_max: The maximum allowed property value
8032 + *
8033 + * This function prints a verbose error message if the property is missing or
8034 + * has a value which is not within the specified range.
8035 + *
8036 + * Return: 0 on success, errno on failure
8037 + */
8038 +int cpr3_parse_thread_u32(struct cpr3_thread *thread, const char *propname,
8039 + u32 *out_value, u32 value_min, u32 value_max)
8040 +{
8041 + int rc;
8042 +
8043 + rc = of_property_read_u32(thread->of_node, propname, out_value);
8044 + if (rc) {
8045 + cpr3_err(thread->ctrl, "thread %u error reading property %s, rc=%d\n",
8046 + thread->thread_id, propname, rc);
8047 + return rc;
8048 + }
8049 +
8050 + if (*out_value < value_min || *out_value > value_max) {
8051 + cpr3_err(thread->ctrl, "thread %u %s=%u is invalid; allowed range: [%u, %u]\n",
8052 + thread->thread_id, propname, *out_value, value_min,
8053 + value_max);
8054 + return -EINVAL;
8055 + }
8056 +
8057 + return 0;
8058 +}
8059 +
8060 +/**
8061 + * cpr3_parse_ctrl_u32() - parse the specified property from the CPR3
8062 + * controller's device tree node and verify that it is within the
8063 + * allowed limits
8064 + * @ctrl: Pointer to the CPR3 controller
8065 + * @propname: The name of the device tree property to read
8066 + * @out_value: The output pointer to fill with the value read
8067 + * @value_min: The minimum allowed property value
8068 + * @value_max: The maximum allowed property value
8069 + *
8070 + * This function prints a verbose error message if the property is missing or
8071 + * has a value which is not within the specified range.
8072 + *
8073 + * Return: 0 on success, errno on failure
8074 + */
8075 +int cpr3_parse_ctrl_u32(struct cpr3_controller *ctrl, const char *propname,
8076 + u32 *out_value, u32 value_min, u32 value_max)
8077 +{
8078 + int rc;
8079 +
8080 + rc = of_property_read_u32(ctrl->dev->of_node, propname, out_value);
8081 + if (rc) {
8082 + cpr3_err(ctrl, "error reading property %s, rc=%d\n",
8083 + propname, rc);
8084 + return rc;
8085 + }
8086 +
8087 + if (*out_value < value_min || *out_value > value_max) {
8088 + cpr3_err(ctrl, "%s=%u is invalid; allowed range: [%u, %u]\n",
8089 + propname, *out_value, value_min, value_max);
8090 + return -EINVAL;
8091 + }
8092 +
8093 + return 0;
8094 +}
8095 +
8096 +/**
8097 + * cpr3_parse_common_thread_data() - parse common CPR3 thread properties from
8098 + * device tree
8099 + * @thread: Pointer to the CPR3 thread
8100 + *
8101 + * Return: 0 on success, errno on failure
8102 + */
8103 +int cpr3_parse_common_thread_data(struct cpr3_thread *thread)
8104 +{
8105 + int rc;
8106 +
8107 + rc = cpr3_parse_thread_u32(thread, "qcom,cpr-consecutive-up",
8108 + &thread->consecutive_up, CPR3_CONSECUTIVE_UP_DOWN_MIN,
8109 + CPR3_CONSECUTIVE_UP_DOWN_MAX);
8110 + if (rc)
8111 + return rc;
8112 +
8113 + rc = cpr3_parse_thread_u32(thread, "qcom,cpr-consecutive-down",
8114 + &thread->consecutive_down, CPR3_CONSECUTIVE_UP_DOWN_MIN,
8115 + CPR3_CONSECUTIVE_UP_DOWN_MAX);
8116 + if (rc)
8117 + return rc;
8118 +
8119 + rc = cpr3_parse_thread_u32(thread, "qcom,cpr-up-threshold",
8120 + &thread->up_threshold, CPR3_UP_DOWN_THRESHOLD_MIN,
8121 + CPR3_UP_DOWN_THRESHOLD_MAX);
8122 + if (rc)
8123 + return rc;
8124 +
8125 + rc = cpr3_parse_thread_u32(thread, "qcom,cpr-down-threshold",
8126 + &thread->down_threshold, CPR3_UP_DOWN_THRESHOLD_MIN,
8127 + CPR3_UP_DOWN_THRESHOLD_MAX);
8128 + if (rc)
8129 + return rc;
8130 +
8131 + return rc;
8132 +}
8133 +
8134 +/**
8135 + * cpr3_parse_irq_affinity() - parse CPR IRQ affinity information
8136 + * @ctrl: Pointer to the CPR3 controller
8137 + *
8138 + * Return: 0 on success, errno on failure
8139 + */
8140 +static int cpr3_parse_irq_affinity(struct cpr3_controller *ctrl)
8141 +{
8142 + struct device_node *cpu_node;
8143 + int i, cpu;
8144 + int len = 0;
8145 +
8146 + if (!of_find_property(ctrl->dev->of_node, "qcom,cpr-interrupt-affinity",
8147 + &len)) {
8148 + /* No IRQ affinity required */
8149 + return 0;
8150 + }
8151 +
8152 + len /= sizeof(u32);
8153 +
8154 + for (i = 0; i < len; i++) {
8155 + cpu_node = of_parse_phandle(ctrl->dev->of_node,
8156 + "qcom,cpr-interrupt-affinity", i);
8157 + if (!cpu_node) {
8158 + cpr3_err(ctrl, "could not find CPU node %d\n", i);
8159 + return -EINVAL;
8160 + }
8161 +
8162 + for_each_possible_cpu(cpu) {
8163 + if (of_get_cpu_node(cpu, NULL) == cpu_node) {
8164 + cpumask_set_cpu(cpu, &ctrl->irq_affinity_mask);
8165 + break;
8166 + }
8167 + }
8168 + of_node_put(cpu_node);
8169 + }
8170 +
8171 + return 0;
8172 +}
8173 +
8174 +static int cpr3_panic_notifier_init(struct cpr3_controller *ctrl)
8175 +{
8176 + struct device_node *node = ctrl->dev->of_node;
8177 + struct cpr3_panic_regs_info *panic_regs_info;
8178 + struct cpr3_reg_info *regs;
8179 + int i, reg_count, len, rc = 0;
8180 +
8181 + if (!of_find_property(node, "qcom,cpr-panic-reg-addr-list", &len)) {
8182 + /* panic register address list not specified */
8183 + return rc;
8184 + }
8185 +
8186 + reg_count = len / sizeof(u32);
8187 + if (!reg_count) {
8188 + cpr3_err(ctrl, "qcom,cpr-panic-reg-addr-list has invalid len = %d\n",
8189 + len);
8190 + return -EINVAL;
8191 + }
8192 +
8193 + if (!of_find_property(node, "qcom,cpr-panic-reg-name-list", NULL)) {
8194 + cpr3_err(ctrl, "property qcom,cpr-panic-reg-name-list not specified\n");
8195 + return -EINVAL;
8196 + }
8197 +
8198 + len = of_property_count_strings(node, "qcom,cpr-panic-reg-name-list");
8199 + if (reg_count != len) {
8200 + cpr3_err(ctrl, "qcom,cpr-panic-reg-name-list should have %d strings\n",
8201 + reg_count);
8202 + return -EINVAL;
8203 + }
8204 +
8205 + panic_regs_info = devm_kzalloc(ctrl->dev, sizeof(*panic_regs_info),
8206 + GFP_KERNEL);
8207 + if (!panic_regs_info)
8208 + return -ENOMEM;
8209 +
8210 + regs = devm_kcalloc(ctrl->dev, reg_count, sizeof(*regs), GFP_KERNEL);
8211 + if (!regs)
8212 + return -ENOMEM;
8213 +
8214 + for (i = 0; i < reg_count; i++) {
8215 + rc = of_property_read_string_index(node,
8216 + "qcom,cpr-panic-reg-name-list", i,
8217 + &(regs[i].name));
8218 + if (rc) {
8219 + cpr3_err(ctrl, "error reading property qcom,cpr-panic-reg-name-list, rc=%d\n",
8220 + rc);
8221 + return rc;
8222 + }
8223 +
8224 + rc = of_property_read_u32_index(node,
8225 + "qcom,cpr-panic-reg-addr-list", i,
8226 + &(regs[i].addr));
8227 + if (rc) {
8228 + cpr3_err(ctrl, "error reading property qcom,cpr-panic-reg-addr-list, rc=%d\n",
8229 + rc);
8230 + return rc;
8231 + }
8232 + regs[i].virt_addr = devm_ioremap(ctrl->dev, regs[i].addr, 0x4);
8233 + if (!regs[i].virt_addr) {
8234 + pr_err("Unable to map panic register addr 0x%08x\n",
8235 + regs[i].addr);
8236 + return -EINVAL;
8237 + }
8238 + regs[i].value = 0xFFFFFFFF;
8239 + }
8240 +
8241 + panic_regs_info->reg_count = reg_count;
8242 + panic_regs_info->regs = regs;
8243 + ctrl->panic_regs_info = panic_regs_info;
8244 +
8245 + return rc;
8246 +}
8247 +
8248 +/**
8249 + * cpr3_parse_common_ctrl_data() - parse common CPR3 controller properties from
8250 + * device tree
8251 + * @ctrl: Pointer to the CPR3 controller
8252 + *
8253 + * Return: 0 on success, errno on failure
8254 + */
8255 +int cpr3_parse_common_ctrl_data(struct cpr3_controller *ctrl)
8256 +{
8257 + int rc;
8258 +
8259 + rc = cpr3_parse_ctrl_u32(ctrl, "qcom,cpr-sensor-time",
8260 + &ctrl->sensor_time, 0, UINT_MAX);
8261 + if (rc)
8262 + return rc;
8263 +
8264 + rc = cpr3_parse_ctrl_u32(ctrl, "qcom,cpr-loop-time",
8265 + &ctrl->loop_time, 0, UINT_MAX);
8266 + if (rc)
8267 + return rc;
8268 +
8269 + rc = cpr3_parse_ctrl_u32(ctrl, "qcom,cpr-idle-cycles",
8270 + &ctrl->idle_clocks, CPR3_IDLE_CLOCKS_MIN,
8271 + CPR3_IDLE_CLOCKS_MAX);
8272 + if (rc)
8273 + return rc;
8274 +
8275 + rc = cpr3_parse_ctrl_u32(ctrl, "qcom,cpr-step-quot-init-min",
8276 + &ctrl->step_quot_init_min, CPR3_STEP_QUOT_MIN,
8277 + CPR3_STEP_QUOT_MAX);
8278 + if (rc)
8279 + return rc;
8280 +
8281 + rc = cpr3_parse_ctrl_u32(ctrl, "qcom,cpr-step-quot-init-max",
8282 + &ctrl->step_quot_init_max, CPR3_STEP_QUOT_MIN,
8283 + CPR3_STEP_QUOT_MAX);
8284 + if (rc)
8285 + return rc;
8286 +
8287 + rc = of_property_read_u32(ctrl->dev->of_node, "qcom,voltage-step",
8288 + &ctrl->step_volt);
8289 + if (rc) {
8290 + cpr3_err(ctrl, "error reading property qcom,voltage-step, rc=%d\n",
8291 + rc);
8292 + return rc;
8293 + }
8294 + if (ctrl->step_volt <= 0) {
8295 + cpr3_err(ctrl, "qcom,voltage-step=%d is invalid\n",
8296 + ctrl->step_volt);
8297 + return -EINVAL;
8298 + }
8299 +
8300 + rc = cpr3_parse_ctrl_u32(ctrl, "qcom,cpr-count-mode",
8301 + &ctrl->count_mode, CPR3_COUNT_MODE_ALL_AT_ONCE_MIN,
8302 + CPR3_COUNT_MODE_STAGGERED);
8303 + if (rc)
8304 + return rc;
8305 +
8306 + /* Count repeat is optional */
8307 + ctrl->count_repeat = 0;
8308 + of_property_read_u32(ctrl->dev->of_node, "qcom,cpr-count-repeat",
8309 + &ctrl->count_repeat);
8310 +
8311 + ctrl->cpr_allowed_sw =
8312 + of_property_read_bool(ctrl->dev->of_node, "qcom,cpr-enable") ||
8313 + ctrl->cpr_global_setting == CPR_CLOSED_LOOP_EN;
8314 +
8315 + rc = cpr3_parse_irq_affinity(ctrl);
8316 + if (rc)
8317 + return rc;
8318 +
8319 + /* Aging reference voltage is optional */
8320 + ctrl->aging_ref_volt = 0;
8321 + of_property_read_u32(ctrl->dev->of_node, "qcom,cpr-aging-ref-voltage",
8322 + &ctrl->aging_ref_volt);
8323 +
8324 + /* Aging possible bitmask is optional */
8325 + ctrl->aging_possible_mask = 0;
8326 + of_property_read_u32(ctrl->dev->of_node,
8327 + "qcom,cpr-aging-allowed-reg-mask",
8328 + &ctrl->aging_possible_mask);
8329 +
8330 + if (ctrl->aging_possible_mask) {
8331 + /*
8332 + * Aging possible register value required if bitmask is
8333 + * specified
8334 + */
8335 + rc = cpr3_parse_ctrl_u32(ctrl,
8336 + "qcom,cpr-aging-allowed-reg-value",
8337 + &ctrl->aging_possible_val, 0, UINT_MAX);
8338 + if (rc)
8339 + return rc;
8340 + }
8341 +
8342 + if (of_find_property(ctrl->dev->of_node, "clock-names", NULL)) {
8343 + ctrl->core_clk = devm_clk_get(ctrl->dev, "core_clk");
8344 + if (IS_ERR(ctrl->core_clk)) {
8345 + rc = PTR_ERR(ctrl->core_clk);
8346 + if (rc != -EPROBE_DEFER)
8347 + cpr3_err(ctrl, "unable request core clock, rc=%d\n",
8348 + rc);
8349 + return rc;
8350 + }
8351 + }
8352 +
8353 + rc = cpr3_panic_notifier_init(ctrl);
8354 + if (rc)
8355 + return rc;
8356 +
8357 + if (of_find_property(ctrl->dev->of_node, "vdd-supply", NULL)) {
8358 + ctrl->vdd_regulator = devm_regulator_get(ctrl->dev, "vdd");
8359 + if (IS_ERR(ctrl->vdd_regulator)) {
8360 + rc = PTR_ERR(ctrl->vdd_regulator);
8361 + if (rc != -EPROBE_DEFER)
8362 + cpr3_err(ctrl, "unable to request vdd regulator, rc=%d\n",
8363 + rc);
8364 + return rc;
8365 + }
8366 + } else {
8367 + cpr3_err(ctrl, "vdd supply is not defined\n");
8368 + return -ENODEV;
8369 + }
8370 +
8371 + ctrl->system_regulator = devm_regulator_get_optional(ctrl->dev,
8372 + "system");
8373 + if (IS_ERR(ctrl->system_regulator)) {
8374 + rc = PTR_ERR(ctrl->system_regulator);
8375 + if (rc != -EPROBE_DEFER) {
8376 + rc = 0;
8377 + ctrl->system_regulator = NULL;
8378 + } else {
8379 + return rc;
8380 + }
8381 + }
8382 +
8383 + ctrl->mem_acc_regulator = devm_regulator_get_optional(ctrl->dev,
8384 + "mem-acc");
8385 + if (IS_ERR(ctrl->mem_acc_regulator)) {
8386 + rc = PTR_ERR(ctrl->mem_acc_regulator);
8387 + if (rc != -EPROBE_DEFER) {
8388 + rc = 0;
8389 + ctrl->mem_acc_regulator = NULL;
8390 + } else {
8391 + return rc;
8392 + }
8393 + }
8394 +
8395 + return rc;
8396 +}
8397 +
8398 +/**
8399 + * cpr3_parse_open_loop_common_ctrl_data() - parse common open loop CPR3
8400 + * controller properties from device tree
8401 + * @ctrl: Pointer to the CPR3 controller
8402 + *
8403 + * Return: 0 on success, errno on failure
8404 + */
8405 +int cpr3_parse_open_loop_common_ctrl_data(struct cpr3_controller *ctrl)
8406 +{
8407 + int rc;
8408 +
8409 + rc = of_property_read_u32(ctrl->dev->of_node, "qcom,voltage-step",
8410 + &ctrl->step_volt);
8411 + if (rc) {
8412 + cpr3_err(ctrl, "error reading property qcom,voltage-step, rc=%d\n",
8413 + rc);
8414 + return rc;
8415 + }
8416 +
8417 + if (ctrl->step_volt <= 0) {
8418 + cpr3_err(ctrl, "qcom,voltage-step=%d is invalid\n",
8419 + ctrl->step_volt);
8420 + return -EINVAL;
8421 + }
8422 +
8423 + if (of_find_property(ctrl->dev->of_node, "vdd-supply", NULL)) {
8424 + ctrl->vdd_regulator = devm_regulator_get(ctrl->dev, "vdd");
8425 + if (IS_ERR(ctrl->vdd_regulator)) {
8426 + rc = PTR_ERR(ctrl->vdd_regulator);
8427 + if (rc != -EPROBE_DEFER)
8428 + cpr3_err(ctrl, "unable to request vdd regulator, rc=%d\n",
8429 + rc);
8430 + return rc;
8431 + }
8432 + } else {
8433 + cpr3_err(ctrl, "vdd supply is not defined\n");
8434 + return -ENODEV;
8435 + }
8436 +
8437 + ctrl->system_regulator = devm_regulator_get_optional(ctrl->dev,
8438 + "system");
8439 + if (IS_ERR(ctrl->system_regulator)) {
8440 + rc = PTR_ERR(ctrl->system_regulator);
8441 + if (rc != -EPROBE_DEFER) {
8442 + rc = 0;
8443 + ctrl->system_regulator = NULL;
8444 + } else {
8445 + return rc;
8446 + }
8447 + } else {
8448 + rc = regulator_enable(ctrl->system_regulator);
8449 + }
8450 +
8451 + ctrl->mem_acc_regulator = devm_regulator_get_optional(ctrl->dev,
8452 + "mem-acc");
8453 + if (IS_ERR(ctrl->mem_acc_regulator)) {
8454 + rc = PTR_ERR(ctrl->mem_acc_regulator);
8455 + if (rc != -EPROBE_DEFER) {
8456 + rc = 0;
8457 + ctrl->mem_acc_regulator = NULL;
8458 + } else {
8459 + return rc;
8460 + }
8461 + }
8462 +
8463 + return rc;
8464 +}
8465 +
8466 +/**
8467 + * cpr3_limit_open_loop_voltages() - modify the open-loop voltage of each corner
8468 + * so that it fits within the floor to ceiling
8469 + * voltage range of the corner
8470 + * @vreg: Pointer to the CPR3 regulator
8471 + *
8472 + * This function clips the open-loop voltage for each corner so that it is
8473 + * limited to the floor to ceiling range. It also rounds each open-loop voltage
8474 + * so that it corresponds to a set point available to the underlying regulator.
8475 + *
8476 + * Return: 0 on success, errno on failure
8477 + */
8478 +int cpr3_limit_open_loop_voltages(struct cpr3_regulator *vreg)
8479 +{
8480 + int i, volt;
8481 +
8482 + cpr3_debug(vreg, "open-loop voltages after trimming and rounding:\n");
8483 + for (i = 0; i < vreg->corner_count; i++) {
8484 + volt = CPR3_ROUND(vreg->corner[i].open_loop_volt,
8485 + vreg->thread->ctrl->step_volt);
8486 + if (volt < vreg->corner[i].floor_volt)
8487 + volt = vreg->corner[i].floor_volt;
8488 + else if (volt > vreg->corner[i].ceiling_volt)
8489 + volt = vreg->corner[i].ceiling_volt;
8490 + vreg->corner[i].open_loop_volt = volt;
8491 + cpr3_debug(vreg, "corner[%2d]: open-loop=%d uV\n", i, volt);
8492 + }
8493 +
8494 + return 0;
8495 +}
8496 +
8497 +/**
8498 + * cpr3_open_loop_voltage_as_ceiling() - configures the ceiling voltage for each
8499 + * corner to equal the open-loop voltage if the relevant device
8500 + * tree property is found for the CPR3 regulator
8501 + * @vreg: Pointer to the CPR3 regulator
8502 + *
8503 + * This function assumes that the the open-loop voltage for each corner has
8504 + * already been rounded to the nearest allowed set point and that it falls
8505 + * within the floor to ceiling range.
8506 + *
8507 + * Return: none
8508 + */
8509 +void cpr3_open_loop_voltage_as_ceiling(struct cpr3_regulator *vreg)
8510 +{
8511 + int i;
8512 +
8513 + if (!of_property_read_bool(vreg->of_node,
8514 + "qcom,cpr-scaled-open-loop-voltage-as-ceiling"))
8515 + return;
8516 +
8517 + for (i = 0; i < vreg->corner_count; i++)
8518 + vreg->corner[i].ceiling_volt
8519 + = vreg->corner[i].open_loop_volt;
8520 +}
8521 +
8522 +/**
8523 + * cpr3_limit_floor_voltages() - raise the floor voltage of each corner so that
8524 + * the optional maximum floor to ceiling voltage range specified in
8525 + * device tree is satisfied
8526 + * @vreg: Pointer to the CPR3 regulator
8527 + *
8528 + * This function also ensures that the open-loop voltage for each corner falls
8529 + * within the final floor to ceiling voltage range and that floor voltages
8530 + * increase monotonically.
8531 + *
8532 + * Return: 0 on success, errno on failure
8533 + */
8534 +int cpr3_limit_floor_voltages(struct cpr3_regulator *vreg)
8535 +{
8536 + char *prop = "qcom,cpr-floor-to-ceiling-max-range";
8537 + int i, floor_new;
8538 + u32 *floor_range;
8539 + int rc = 0;
8540 +
8541 + if (!of_find_property(vreg->of_node, prop, NULL))
8542 + goto enforce_monotonicity;
8543 +
8544 + floor_range = kcalloc(vreg->corner_count, sizeof(*floor_range),
8545 + GFP_KERNEL);
8546 + if (!floor_range)
8547 + return -ENOMEM;
8548 +
8549 + rc = cpr3_parse_corner_array_property(vreg, prop, 1, floor_range);
8550 + if (rc)
8551 + goto free_floor_adjust;
8552 +
8553 + for (i = 0; i < vreg->corner_count; i++) {
8554 + if ((s32)floor_range[i] >= 0) {
8555 + floor_new = CPR3_ROUND(vreg->corner[i].ceiling_volt
8556 + - floor_range[i],
8557 + vreg->thread->ctrl->step_volt);
8558 +
8559 + vreg->corner[i].floor_volt = max(floor_new,
8560 + vreg->corner[i].floor_volt);
8561 + if (vreg->corner[i].open_loop_volt
8562 + < vreg->corner[i].floor_volt)
8563 + vreg->corner[i].open_loop_volt
8564 + = vreg->corner[i].floor_volt;
8565 + }
8566 + }
8567 +
8568 +free_floor_adjust:
8569 + kfree(floor_range);
8570 +
8571 +enforce_monotonicity:
8572 + /* Ensure that floor voltages increase monotonically. */
8573 + for (i = 1; i < vreg->corner_count; i++) {
8574 + if (vreg->corner[i].floor_volt
8575 + < vreg->corner[i - 1].floor_volt) {
8576 + cpr3_debug(vreg, "corner %d floor voltage=%d uV < corner %d voltage=%d uV; overriding: corner %d voltage=%d\n",
8577 + i, vreg->corner[i].floor_volt,
8578 + i - 1, vreg->corner[i - 1].floor_volt,
8579 + i, vreg->corner[i - 1].floor_volt);
8580 + vreg->corner[i].floor_volt
8581 + = vreg->corner[i - 1].floor_volt;
8582 +
8583 + if (vreg->corner[i].open_loop_volt
8584 + < vreg->corner[i].floor_volt)
8585 + vreg->corner[i].open_loop_volt
8586 + = vreg->corner[i].floor_volt;
8587 + if (vreg->corner[i].ceiling_volt
8588 + < vreg->corner[i].floor_volt)
8589 + vreg->corner[i].ceiling_volt
8590 + = vreg->corner[i].floor_volt;
8591 + }
8592 + }
8593 +
8594 + return rc;
8595 +}
8596 +
8597 +/**
8598 + * cpr3_print_quots() - print CPR target quotients into the kernel log for
8599 + * debugging purposes
8600 + * @vreg: Pointer to the CPR3 regulator
8601 + *
8602 + * Return: none
8603 + */
8604 +void cpr3_print_quots(struct cpr3_regulator *vreg)
8605 +{
8606 + int i, j, pos;
8607 + size_t buflen;
8608 + char *buf;
8609 +
8610 + buflen = sizeof(*buf) * CPR3_RO_COUNT * (MAX_CHARS_PER_INT + 2);
8611 + buf = kzalloc(buflen, GFP_KERNEL);
8612 + if (!buf)
8613 + return;
8614 +
8615 + for (i = 0; i < vreg->corner_count; i++) {
8616 + for (j = 0, pos = 0; j < CPR3_RO_COUNT; j++)
8617 + pos += scnprintf(buf + pos, buflen - pos, " %u",
8618 + vreg->corner[i].target_quot[j]);
8619 + cpr3_debug(vreg, "target quots[%2d]:%s\n", i, buf);
8620 + }
8621 +
8622 + kfree(buf);
8623 +}
8624 +
8625 +/**
8626 + * cpr3_determine_part_type() - determine the part type (SS/TT/FF).
8627 + *
8628 + * qcom,cpr-part-types prop tells the number of part types for which correction
8629 + * voltages are different. Another prop qcom,cpr-parts-voltage will contain the
8630 + * open loop fuse voltage which will be compared with this part voltage
8631 + * and accordingly part type will de determined.
8632 + *
8633 + * if qcom,cpr-part-types has value n, then qcom,cpr-parts-voltage will be
8634 + * array of n - 1 elements which will contain the voltage in increasing order.
8635 + * This function compares the fused volatge with all these voltage and returns
8636 + * the first index for which the fused volatge is greater.
8637 + *
8638 + * @vreg: Pointer to the CPR3 regulator
8639 + * @fuse_volt: fused open loop voltage which will be compared with
8640 + * qcom,cpr-parts-voltage array
8641 + *
8642 + * Return: 0 on success, errno on failure
8643 + */
8644 +int cpr3_determine_part_type(struct cpr3_regulator *vreg, int fuse_volt)
8645 +{
8646 + int i, rc, len;
8647 + u32 volt;
8648 + int soc_version_major;
8649 + char prop_name[100];
8650 + const char prop_name_def[] = "qcom,cpr-parts-voltage";
8651 + const char prop_name_v2[] = "qcom,cpr-parts-voltage-v2";
8652 +
8653 + soc_version_major = read_ipq_soc_version_major();
8654 + BUG_ON(soc_version_major <= 0);
8655 +
8656 + if (of_property_read_u32(vreg->of_node, "qcom,cpr-part-types",
8657 + &vreg->part_type_supported))
8658 + return 0;
8659 +
8660 + if (soc_version_major > 1)
8661 + strlcpy(prop_name, prop_name_v2, sizeof(prop_name_v2));
8662 + else
8663 + strlcpy(prop_name, prop_name_def, sizeof(prop_name_def));
8664 +
8665 + if (!of_find_property(vreg->of_node, prop_name, &len)) {
8666 + cpr3_err(vreg, "property %s is missing\n", prop_name);
8667 + return -EINVAL;
8668 + }
8669 +
8670 + if (len != (vreg->part_type_supported - 1) * sizeof(u32)) {
8671 + cpr3_err(vreg, "wrong len in qcom,cpr-parts-voltage\n");
8672 + return -EINVAL;
8673 + }
8674 +
8675 + for (i = 0; i < vreg->part_type_supported - 1; i++) {
8676 + rc = of_property_read_u32_index(vreg->of_node,
8677 + prop_name, i, &volt);
8678 + if (rc) {
8679 + cpr3_err(vreg, "error reading property %s, rc=%d\n",
8680 + prop_name, rc);
8681 + return rc;
8682 + }
8683 +
8684 + if (fuse_volt < volt)
8685 + break;
8686 + }
8687 +
8688 + vreg->part_type = i;
8689 + return 0;
8690 +}
8691 +
8692 +int cpr3_determine_temp_base_open_loop_correction(struct cpr3_regulator *vreg,
8693 + int *fuse_volt)
8694 +{
8695 + int i, rc, prev_volt;
8696 + int *volt_adjust;
8697 + char prop_str[75];
8698 + int soc_version_major = read_ipq_soc_version_major();
8699 +
8700 + BUG_ON(soc_version_major <= 0);
8701 +
8702 + if (vreg->part_type_supported) {
8703 + if (soc_version_major > 1)
8704 + snprintf(prop_str, sizeof(prop_str),
8705 + "qcom,cpr-cold-temp-voltage-adjustment-v2-%d",
8706 + vreg->part_type);
8707 + else
8708 + snprintf(prop_str, sizeof(prop_str),
8709 + "qcom,cpr-cold-temp-voltage-adjustment-%d",
8710 + vreg->part_type);
8711 + } else {
8712 + strlcpy(prop_str, "qcom,cpr-cold-temp-voltage-adjustment",
8713 + sizeof(prop_str));
8714 + }
8715 +
8716 + if (!of_find_property(vreg->of_node, prop_str, NULL)) {
8717 + /* No adjustment required. */
8718 + cpr3_info(vreg, "No cold temperature adjustment required.\n");
8719 + return 0;
8720 + }
8721 +
8722 + volt_adjust = kcalloc(vreg->fuse_corner_count, sizeof(*volt_adjust),
8723 + GFP_KERNEL);
8724 + if (!volt_adjust)
8725 + return -ENOMEM;
8726 +
8727 + rc = cpr3_parse_array_property(vreg, prop_str,
8728 + vreg->fuse_corner_count, volt_adjust);
8729 + if (rc) {
8730 + cpr3_err(vreg, "could not load cold temp voltage adjustments, rc=%d\n",
8731 + rc);
8732 + goto done;
8733 + }
8734 +
8735 + for (i = 0; i < vreg->fuse_corner_count; i++) {
8736 + if (volt_adjust[i]) {
8737 + prev_volt = fuse_volt[i];
8738 + fuse_volt[i] += volt_adjust[i];
8739 + cpr3_debug(vreg,
8740 + "adjusted fuse corner %d open-loop voltage: %d -> %d uV\n",
8741 + i, prev_volt, fuse_volt[i]);
8742 + }
8743 + }
8744 +
8745 +done:
8746 + kfree(volt_adjust);
8747 + return rc;
8748 +}
8749 +
8750 +/**
8751 + * cpr3_can_adjust_cold_temp() - Is cold temperature adjustment available
8752 + *
8753 + * @vreg: Pointer to the CPR3 regulator
8754 + *
8755 + * This function checks the cold temperature threshold is available
8756 + *
8757 + * Return: true on cold temperature threshold is available, else false
8758 + */
8759 +bool cpr3_can_adjust_cold_temp(struct cpr3_regulator *vreg)
8760 +{
8761 + char prop_str[75];
8762 + int soc_version_major = read_ipq_soc_version_major();
8763 +
8764 + BUG_ON(soc_version_major <= 0);
8765 +
8766 + if (soc_version_major > 1)
8767 + strlcpy(prop_str, "qcom,cpr-cold-temp-threshold-v2",
8768 + sizeof(prop_str));
8769 + else
8770 + strlcpy(prop_str, "qcom,cpr-cold-temp-threshold",
8771 + sizeof(prop_str));
8772 +
8773 + if (!of_find_property(vreg->of_node, prop_str, NULL)) {
8774 + /* No adjustment required. */
8775 + return false;
8776 + } else
8777 + return true;
8778 +}
8779 +
8780 +/**
8781 + * cpr3_get_cold_temp_threshold() - get cold temperature threshold
8782 + *
8783 + * @vreg: Pointer to the CPR3 regulator
8784 + * @cold_temp: cold temperature read.
8785 + *
8786 + * This function reads the cold temperature threshold below which
8787 + * cold temperature adjustment margins will be applied.
8788 + *
8789 + * Return: 0 on success, errno on failure
8790 + */
8791 +int cpr3_get_cold_temp_threshold(struct cpr3_regulator *vreg, int *cold_temp)
8792 +{
8793 + int rc;
8794 + u32 temp;
8795 + char req_prop_str[75], prop_str[75];
8796 + int soc_version_major = read_ipq_soc_version_major();
8797 +
8798 + BUG_ON(soc_version_major <= 0);
8799 +
8800 + if (vreg->part_type_supported) {
8801 + if (soc_version_major > 1)
8802 + snprintf(req_prop_str, sizeof(req_prop_str),
8803 + "qcom,cpr-cold-temp-voltage-adjustment-v2-%d",
8804 + vreg->part_type);
8805 + else
8806 + snprintf(req_prop_str, sizeof(req_prop_str),
8807 + "qcom,cpr-cold-temp-voltage-adjustment-%d",
8808 + vreg->part_type);
8809 + } else {
8810 + strlcpy(req_prop_str, "qcom,cpr-cold-temp-voltage-adjustment",
8811 + sizeof(req_prop_str));
8812 + }
8813 +
8814 + if (soc_version_major > 1)
8815 + strlcpy(prop_str, "qcom,cpr-cold-temp-threshold-v2",
8816 + sizeof(prop_str));
8817 + else
8818 + strlcpy(prop_str, "qcom,cpr-cold-temp-threshold",
8819 + sizeof(prop_str));
8820 +
8821 + if (!of_find_property(vreg->of_node, req_prop_str, NULL)) {
8822 + /* No adjustment required. */
8823 + cpr3_info(vreg, "Cold temperature adjustment not required.\n");
8824 + return 0;
8825 + }
8826 +
8827 + if (!of_find_property(vreg->of_node, prop_str, NULL)) {
8828 + /* No adjustment required. */
8829 + cpr3_err(vreg, "Missing %s required for %s\n",
8830 + prop_str, req_prop_str);
8831 + return -EINVAL;
8832 + }
8833 +
8834 + rc = of_property_read_u32(vreg->of_node, prop_str, &temp);
8835 + if (rc) {
8836 + cpr3_err(vreg, "error reading property %s, rc=%d\n",
8837 + prop_str, rc);
8838 + return rc;
8839 + }
8840 +
8841 + *cold_temp = temp;
8842 + return 0;
8843 +}
8844 +
8845 +/**
8846 + * cpr3_adjust_fused_open_loop_voltages() - adjust the fused open-loop voltages
8847 + * for each fuse corner according to device tree values
8848 + * @vreg: Pointer to the CPR3 regulator
8849 + * @fuse_volt: Pointer to an array of the fused open-loop voltage
8850 + * values
8851 + *
8852 + * Voltage values in fuse_volt are modified in place.
8853 + *
8854 + * Return: 0 on success, errno on failure
8855 + */
8856 +int cpr3_adjust_fused_open_loop_voltages(struct cpr3_regulator *vreg,
8857 + int *fuse_volt)
8858 +{
8859 + int i, rc, prev_volt;
8860 + int *volt_adjust;
8861 + char prop_str[75];
8862 + int soc_version_major = read_ipq_soc_version_major();
8863 +
8864 + BUG_ON(soc_version_major <= 0);
8865 +
8866 + if (vreg->part_type_supported) {
8867 + if (soc_version_major > 1)
8868 + snprintf(prop_str, sizeof(prop_str),
8869 + "qcom,cpr-open-loop-voltage-fuse-adjustment-v2-%d",
8870 + vreg->part_type);
8871 + else
8872 + snprintf(prop_str, sizeof(prop_str),
8873 + "qcom,cpr-open-loop-voltage-fuse-adjustment-%d",
8874 + vreg->part_type);
8875 + } else {
8876 + strlcpy(prop_str, "qcom,cpr-open-loop-voltage-fuse-adjustment",
8877 + sizeof(prop_str));
8878 + }
8879 +
8880 + if (!of_find_property(vreg->of_node, prop_str, NULL)) {
8881 + /* No adjustment required. */
8882 + return 0;
8883 + }
8884 +
8885 + volt_adjust = kcalloc(vreg->fuse_corner_count, sizeof(*volt_adjust),
8886 + GFP_KERNEL);
8887 + if (!volt_adjust)
8888 + return -ENOMEM;
8889 +
8890 + rc = cpr3_parse_array_property(vreg,
8891 + prop_str, vreg->fuse_corner_count, volt_adjust);
8892 + if (rc) {
8893 + cpr3_err(vreg, "could not load open-loop fused voltage adjustments, rc=%d\n",
8894 + rc);
8895 + goto done;
8896 + }
8897 +
8898 + for (i = 0; i < vreg->fuse_corner_count; i++) {
8899 + if (volt_adjust[i]) {
8900 + prev_volt = fuse_volt[i];
8901 + fuse_volt[i] += volt_adjust[i];
8902 + cpr3_debug(vreg, "adjusted fuse corner %d open-loop voltage: %d --> %d uV\n",
8903 + i, prev_volt, fuse_volt[i]);
8904 + }
8905 + }
8906 +
8907 +done:
8908 + kfree(volt_adjust);
8909 + return rc;
8910 +}
8911 +
8912 +/**
8913 + * cpr3_adjust_open_loop_voltages() - adjust the open-loop voltages for each
8914 + * corner according to device tree values
8915 + * @vreg: Pointer to the CPR3 regulator
8916 + *
8917 + * Return: 0 on success, errno on failure
8918 + */
8919 +int cpr3_adjust_open_loop_voltages(struct cpr3_regulator *vreg)
8920 +{
8921 + int i, rc, prev_volt, min_volt;
8922 + int *volt_adjust, *volt_diff;
8923 +
8924 + if (!of_find_property(vreg->of_node,
8925 + "qcom,cpr-open-loop-voltage-adjustment", NULL)) {
8926 + /* No adjustment required. */
8927 + return 0;
8928 + }
8929 +
8930 + volt_adjust = kcalloc(vreg->corner_count, sizeof(*volt_adjust),
8931 + GFP_KERNEL);
8932 + volt_diff = kcalloc(vreg->corner_count, sizeof(*volt_diff), GFP_KERNEL);
8933 + if (!volt_adjust || !volt_diff) {
8934 + rc = -ENOMEM;
8935 + goto done;
8936 + }
8937 +
8938 + rc = cpr3_parse_corner_array_property(vreg,
8939 + "qcom,cpr-open-loop-voltage-adjustment", 1, volt_adjust);
8940 + if (rc) {
8941 + cpr3_err(vreg, "could not load open-loop voltage adjustments, rc=%d\n",
8942 + rc);
8943 + goto done;
8944 + }
8945 +
8946 + for (i = 0; i < vreg->corner_count; i++) {
8947 + if (volt_adjust[i]) {
8948 + prev_volt = vreg->corner[i].open_loop_volt;
8949 + vreg->corner[i].open_loop_volt += volt_adjust[i];
8950 + cpr3_debug(vreg, "adjusted corner %d open-loop voltage: %d --> %d uV\n",
8951 + i, prev_volt, vreg->corner[i].open_loop_volt);
8952 + }
8953 + }
8954 +
8955 + if (of_find_property(vreg->of_node,
8956 + "qcom,cpr-open-loop-voltage-min-diff", NULL)) {
8957 + rc = cpr3_parse_corner_array_property(vreg,
8958 + "qcom,cpr-open-loop-voltage-min-diff", 1, volt_diff);
8959 + if (rc) {
8960 + cpr3_err(vreg, "could not load minimum open-loop voltage differences, rc=%d\n",
8961 + rc);
8962 + goto done;
8963 + }
8964 + }
8965 +
8966 + /*
8967 + * Ensure that open-loop voltages increase monotonically with respect
8968 + * to configurable minimum allowed differences.
8969 + */
8970 + for (i = 1; i < vreg->corner_count; i++) {
8971 + min_volt = vreg->corner[i - 1].open_loop_volt + volt_diff[i];
8972 + if (vreg->corner[i].open_loop_volt < min_volt) {
8973 + 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",
8974 + i, vreg->corner[i].open_loop_volt,
8975 + i - 1, vreg->corner[i - 1].open_loop_volt,
8976 + volt_diff[i], i, min_volt);
8977 + vreg->corner[i].open_loop_volt = min_volt;
8978 + }
8979 + }
8980 +
8981 +done:
8982 + kfree(volt_diff);
8983 + kfree(volt_adjust);
8984 + return rc;
8985 +}
8986 +
8987 +/**
8988 + * cpr3_quot_adjustment() - returns the quotient adjustment value resulting from
8989 + * the specified voltage adjustment and RO scaling factor
8990 + * @ro_scale: The CPR ring oscillator (RO) scaling factor with units
8991 + * of QUOT/V
8992 + * @volt_adjust: The amount to adjust the voltage by in units of
8993 + * microvolts. This value may be positive or negative.
8994 + */
8995 +int cpr3_quot_adjustment(int ro_scale, int volt_adjust)
8996 +{
8997 + unsigned long long temp;
8998 + int quot_adjust;
8999 + int sign = 1;
9000 +
9001 + if (ro_scale < 0) {
9002 + sign = -sign;
9003 + ro_scale = -ro_scale;
9004 + }
9005 +
9006 + if (volt_adjust < 0) {
9007 + sign = -sign;
9008 + volt_adjust = -volt_adjust;
9009 + }
9010 +
9011 + temp = (unsigned long long)ro_scale * (unsigned long long)volt_adjust;
9012 + do_div(temp, 1000000);
9013 +
9014 + quot_adjust = temp;
9015 + quot_adjust *= sign;
9016 +
9017 + return quot_adjust;
9018 +}
9019 +
9020 +/**
9021 + * cpr3_voltage_adjustment() - returns the voltage adjustment value resulting
9022 + * from the specified quotient adjustment and RO scaling factor
9023 + * @ro_scale: The CPR ring oscillator (RO) scaling factor with units
9024 + * of QUOT/V
9025 + * @quot_adjust: The amount to adjust the quotient by in units of
9026 + * QUOT. This value may be positive or negative.
9027 + */
9028 +int cpr3_voltage_adjustment(int ro_scale, int quot_adjust)
9029 +{
9030 + unsigned long long temp;
9031 + int volt_adjust;
9032 + int sign = 1;
9033 +
9034 + if (ro_scale < 0) {
9035 + sign = -sign;
9036 + ro_scale = -ro_scale;
9037 + }
9038 +
9039 + if (quot_adjust < 0) {
9040 + sign = -sign;
9041 + quot_adjust = -quot_adjust;
9042 + }
9043 +
9044 + if (ro_scale == 0)
9045 + return 0;
9046 +
9047 + temp = (unsigned long long)quot_adjust * 1000000;
9048 + do_div(temp, ro_scale);
9049 +
9050 + volt_adjust = temp;
9051 + volt_adjust *= sign;
9052 +
9053 + return volt_adjust;
9054 +}
9055 +
9056 +/**
9057 + * cpr3_parse_closed_loop_voltage_adjustments() - load per-fuse-corner and
9058 + * per-corner closed-loop adjustment values from device tree
9059 + * @vreg: Pointer to the CPR3 regulator
9060 + * @ro_sel: Array of ring oscillator values selected for each
9061 + * fuse corner
9062 + * @volt_adjust: Pointer to array which will be filled with the
9063 + * per-corner closed-loop adjustment voltages
9064 + * @volt_adjust_fuse: Pointer to array which will be filled with the
9065 + * per-fuse-corner closed-loop adjustment voltages
9066 + * @ro_scale: Pointer to array which will be filled with the
9067 + * per-fuse-corner RO scaling factor values with units of
9068 + * QUOT/V
9069 + *
9070 + * Return: 0 on success, errno on failure
9071 + */
9072 +int cpr3_parse_closed_loop_voltage_adjustments(
9073 + struct cpr3_regulator *vreg, u64 *ro_sel,
9074 + int *volt_adjust, int *volt_adjust_fuse, int *ro_scale)
9075 +{
9076 + int i, rc;
9077 + u32 *ro_all_scale;
9078 +
9079 + char volt_adj[] = "qcom,cpr-closed-loop-voltage-adjustment";
9080 + char volt_fuse_adj[] = "qcom,cpr-closed-loop-voltage-fuse-adjustment";
9081 + char ro_scaling[] = "qcom,cpr-ro-scaling-factor";
9082 +
9083 + if (!of_find_property(vreg->of_node, volt_adj, NULL)
9084 + && !of_find_property(vreg->of_node, volt_fuse_adj, NULL)
9085 + && !vreg->aging_allowed) {
9086 + /* No adjustment required. */
9087 + return 0;
9088 + } else if (!of_find_property(vreg->of_node, ro_scaling, NULL)) {
9089 + cpr3_err(vreg, "Missing %s required for closed-loop voltage adjustment.\n",
9090 + ro_scaling);
9091 + return -EINVAL;
9092 + }
9093 +
9094 + ro_all_scale = kcalloc(vreg->fuse_corner_count * CPR3_RO_COUNT,
9095 + sizeof(*ro_all_scale), GFP_KERNEL);
9096 + if (!ro_all_scale)
9097 + return -ENOMEM;
9098 +
9099 + rc = cpr3_parse_array_property(vreg, ro_scaling,
9100 + vreg->fuse_corner_count * CPR3_RO_COUNT, ro_all_scale);
9101 + if (rc) {
9102 + cpr3_err(vreg, "could not load RO scaling factors, rc=%d\n",
9103 + rc);
9104 + goto done;
9105 + }
9106 +
9107 + for (i = 0; i < vreg->fuse_corner_count; i++)
9108 + ro_scale[i] = ro_all_scale[i * CPR3_RO_COUNT + ro_sel[i]];
9109 +
9110 + for (i = 0; i < vreg->corner_count; i++)
9111 + memcpy(vreg->corner[i].ro_scale,
9112 + &ro_all_scale[vreg->corner[i].cpr_fuse_corner * CPR3_RO_COUNT],
9113 + sizeof(*ro_all_scale) * CPR3_RO_COUNT);
9114 +
9115 + if (of_find_property(vreg->of_node, volt_fuse_adj, NULL)) {
9116 + rc = cpr3_parse_array_property(vreg, volt_fuse_adj,
9117 + vreg->fuse_corner_count, volt_adjust_fuse);
9118 + if (rc) {
9119 + cpr3_err(vreg, "could not load closed-loop fused voltage adjustments, rc=%d\n",
9120 + rc);
9121 + goto done;
9122 + }
9123 + }
9124 +
9125 + if (of_find_property(vreg->of_node, volt_adj, NULL)) {
9126 + rc = cpr3_parse_corner_array_property(vreg, volt_adj,
9127 + 1, volt_adjust);
9128 + if (rc) {
9129 + cpr3_err(vreg, "could not load closed-loop voltage adjustments, rc=%d\n",
9130 + rc);
9131 + goto done;
9132 + }
9133 + }
9134 +
9135 +done:
9136 + kfree(ro_all_scale);
9137 + return rc;
9138 +}
9139 +
9140 +/**
9141 + * cpr3_apm_init() - initialize APM data for a CPR3 controller
9142 + * @ctrl: Pointer to the CPR3 controller
9143 + *
9144 + * This function loads memory array power mux (APM) data from device tree
9145 + * if it is present and requests a handle to the appropriate APM controller
9146 + * device.
9147 + *
9148 + * Return: 0 on success, errno on failure
9149 + */
9150 +int cpr3_apm_init(struct cpr3_controller *ctrl)
9151 +{
9152 + struct device_node *node = ctrl->dev->of_node;
9153 + int rc;
9154 +
9155 + if (!of_find_property(node, "qcom,apm-ctrl", NULL)) {
9156 + /* No APM used */
9157 + return 0;
9158 + }
9159 +
9160 + ctrl->apm = msm_apm_ctrl_dev_get(ctrl->dev);
9161 + if (IS_ERR(ctrl->apm)) {
9162 + rc = PTR_ERR(ctrl->apm);
9163 + if (rc != -EPROBE_DEFER)
9164 + cpr3_err(ctrl, "APM get failed, rc=%d\n", rc);
9165 + return rc;
9166 + }
9167 +
9168 + rc = of_property_read_u32(node, "qcom,apm-threshold-voltage",
9169 + &ctrl->apm_threshold_volt);
9170 + if (rc) {
9171 + cpr3_err(ctrl, "error reading qcom,apm-threshold-voltage, rc=%d\n",
9172 + rc);
9173 + return rc;
9174 + }
9175 + ctrl->apm_threshold_volt
9176 + = CPR3_ROUND(ctrl->apm_threshold_volt, ctrl->step_volt);
9177 +
9178 + /* No error check since this is an optional property. */
9179 + of_property_read_u32(node, "qcom,apm-hysteresis-voltage",
9180 + &ctrl->apm_adj_volt);
9181 + ctrl->apm_adj_volt = CPR3_ROUND(ctrl->apm_adj_volt, ctrl->step_volt);
9182 +
9183 + ctrl->apm_high_supply = MSM_APM_SUPPLY_APCC;
9184 + ctrl->apm_low_supply = MSM_APM_SUPPLY_MX;
9185 +
9186 + return 0;
9187 +}
9188 +
9189 +/**
9190 + * cpr3_mem_acc_init() - initialize mem-acc regulator data for
9191 + * a CPR3 regulator
9192 + * @ctrl: Pointer to the CPR3 controller
9193 + *
9194 + * Return: 0 on success, errno on failure
9195 + */
9196 +int cpr3_mem_acc_init(struct cpr3_regulator *vreg)
9197 +{
9198 + struct cpr3_controller *ctrl = vreg->thread->ctrl;
9199 + u32 *temp;
9200 + int i, rc;
9201 +
9202 + if (!ctrl->mem_acc_regulator) {
9203 + cpr3_info(ctrl, "not using memory accelerator regulator\n");
9204 + return 0;
9205 + }
9206 +
9207 + temp = kcalloc(vreg->corner_count, sizeof(*temp), GFP_KERNEL);
9208 + if (!temp)
9209 + return -ENOMEM;
9210 +
9211 + rc = cpr3_parse_corner_array_property(vreg, "qcom,mem-acc-voltage",
9212 + 1, temp);
9213 + if (rc) {
9214 + cpr3_err(ctrl, "could not load mem-acc corners, rc=%d\n", rc);
9215 + } else {
9216 + for (i = 0; i < vreg->corner_count; i++)
9217 + vreg->corner[i].mem_acc_volt = temp[i];
9218 + }
9219 +
9220 + kfree(temp);
9221 + return rc;
9222 +}
9223 +
9224 +/**
9225 + * cpr4_load_core_and_temp_adj() - parse amount of voltage adjustment for
9226 + * per-online-core and per-temperature voltage adjustment for a
9227 + * given corner or corner band from device tree.
9228 + * @vreg: Pointer to the CPR3 regulator
9229 + * @num: Corner number or corner band number
9230 + * @use_corner_band: Boolean indicating if the CPR3 regulator supports
9231 + * adjustments per corner band
9232 + *
9233 + * Return: 0 on success, errno on failure
9234 + */
9235 +static int cpr4_load_core_and_temp_adj(struct cpr3_regulator *vreg,
9236 + int num, bool use_corner_band)
9237 +{
9238 + struct cpr3_controller *ctrl = vreg->thread->ctrl;
9239 + struct cpr4_sdelta *sdelta;
9240 + int sdelta_size, i, j, pos, rc = 0;
9241 + char str[75];
9242 + size_t buflen;
9243 + char *buf;
9244 +
9245 + sdelta = use_corner_band ? vreg->corner_band[num].sdelta :
9246 + vreg->corner[num].sdelta;
9247 +
9248 + if (!sdelta->allow_core_count_adj && !sdelta->allow_temp_adj) {
9249 + /* corner doesn't need sdelta table */
9250 + sdelta->max_core_count = 0;
9251 + sdelta->temp_band_count = 0;
9252 + return rc;
9253 + }
9254 +
9255 + sdelta_size = sdelta->max_core_count * sdelta->temp_band_count;
9256 + if (use_corner_band)
9257 + snprintf(str, sizeof(str),
9258 + "corner_band=%d core_config_count=%d temp_band_count=%d sdelta_size=%d\n",
9259 + num, sdelta->max_core_count,
9260 + sdelta->temp_band_count, sdelta_size);
9261 + else
9262 + snprintf(str, sizeof(str),
9263 + "corner=%d core_config_count=%d temp_band_count=%d sdelta_size=%d\n",
9264 + num, sdelta->max_core_count,
9265 + sdelta->temp_band_count, sdelta_size);
9266 +
9267 + cpr3_debug(vreg, "%s", str);
9268 +
9269 + sdelta->table = devm_kcalloc(ctrl->dev, sdelta_size,
9270 + sizeof(*sdelta->table), GFP_KERNEL);
9271 + if (!sdelta->table)
9272 + return -ENOMEM;
9273 +
9274 + if (use_corner_band)
9275 + snprintf(str, sizeof(str),
9276 + "qcom,cpr-corner-band%d-temp-core-voltage-adjustment",
9277 + num + CPR3_CORNER_OFFSET);
9278 + else
9279 + snprintf(str, sizeof(str),
9280 + "qcom,cpr-corner%d-temp-core-voltage-adjustment",
9281 + num + CPR3_CORNER_OFFSET);
9282 +
9283 + rc = cpr3_parse_array_property(vreg, str, sdelta_size,
9284 + sdelta->table);
9285 + if (rc) {
9286 + cpr3_err(vreg, "could not load %s, rc=%d\n", str, rc);
9287 + return rc;
9288 + }
9289 +
9290 + /*
9291 + * Convert sdelta margins from uV to PMIC steps and apply negation to
9292 + * follow the SDELTA register semantics.
9293 + */
9294 + for (i = 0; i < sdelta_size; i++)
9295 + sdelta->table[i] = -(sdelta->table[i] / ctrl->step_volt);
9296 +
9297 + buflen = sizeof(*buf) * sdelta_size * (MAX_CHARS_PER_INT + 2);
9298 + buf = kzalloc(buflen, GFP_KERNEL);
9299 + if (!buf)
9300 + return rc;
9301 +
9302 + for (i = 0; i < sdelta->max_core_count; i++) {
9303 + for (j = 0, pos = 0; j < sdelta->temp_band_count; j++)
9304 + pos += scnprintf(buf + pos, buflen - pos, " %u",
9305 + sdelta->table[i * sdelta->temp_band_count + j]);
9306 + cpr3_debug(vreg, "sdelta[%d]:%s\n", i, buf);
9307 + }
9308 +
9309 + kfree(buf);
9310 + return rc;
9311 +}
9312 +
9313 +/**
9314 + * cpr4_parse_core_count_temp_voltage_adj() - parse configuration data for
9315 + * per-online-core and per-temperature voltage adjustment for
9316 + * a CPR3 regulator from device tree.
9317 + * @vreg: Pointer to the CPR3 regulator
9318 + * @use_corner_band: Boolean indicating if the CPR3 regulator supports
9319 + * adjustments per corner band
9320 + *
9321 + * This function supports parsing of per-online-core and per-temperature
9322 + * adjustments per corner or per corner band. CPR controllers which support
9323 + * corner bands apply the same adjustments to all corners within a corner band.
9324 + *
9325 + * Return: 0 on success, errno on failure
9326 + */
9327 +int cpr4_parse_core_count_temp_voltage_adj(
9328 + struct cpr3_regulator *vreg, bool use_corner_band)
9329 +{
9330 + struct cpr3_controller *ctrl = vreg->thread->ctrl;
9331 + struct device_node *node = vreg->of_node;
9332 + struct cpr3_corner *corner;
9333 + struct cpr4_sdelta *sdelta;
9334 + int i, sdelta_table_count, rc = 0;
9335 + int *allow_core_count_adj = NULL, *allow_temp_adj = NULL;
9336 + char prop_str[75];
9337 +
9338 + if (of_find_property(node, use_corner_band ?
9339 + "qcom,corner-band-allow-temp-adjustment"
9340 + : "qcom,corner-allow-temp-adjustment", NULL)) {
9341 + if (!ctrl->allow_temp_adj) {
9342 + cpr3_err(ctrl, "Temperature adjustment configurations missing\n");
9343 + return -EINVAL;
9344 + }
9345 +
9346 + vreg->allow_temp_adj = true;
9347 + }
9348 +
9349 + if (of_find_property(node, use_corner_band ?
9350 + "qcom,corner-band-allow-core-count-adjustment"
9351 + : "qcom,corner-allow-core-count-adjustment",
9352 + NULL)) {
9353 + rc = of_property_read_u32(node, "qcom,max-core-count",
9354 + &vreg->max_core_count);
9355 + if (rc) {
9356 + cpr3_err(vreg, "error reading qcom,max-core-count, rc=%d\n",
9357 + rc);
9358 + return -EINVAL;
9359 + }
9360 +
9361 + vreg->allow_core_count_adj = true;
9362 + ctrl->allow_core_count_adj = true;
9363 + }
9364 +
9365 + if (!vreg->allow_temp_adj && !vreg->allow_core_count_adj) {
9366 + /*
9367 + * Both per-online-core and temperature based adjustments are
9368 + * disabled for this regulator.
9369 + */
9370 + return 0;
9371 + } else if (!vreg->allow_core_count_adj) {
9372 + /*
9373 + * Only per-temperature voltage adjusments are allowed.
9374 + * Keep max core count value as 1 to allocate SDELTA.
9375 + */
9376 + vreg->max_core_count = 1;
9377 + }
9378 +
9379 + if (vreg->allow_core_count_adj) {
9380 + allow_core_count_adj = kcalloc(vreg->corner_count,
9381 + sizeof(*allow_core_count_adj),
9382 + GFP_KERNEL);
9383 + if (!allow_core_count_adj)
9384 + return -ENOMEM;
9385 +
9386 + snprintf(prop_str, sizeof(prop_str), "%s", use_corner_band ?
9387 + "qcom,corner-band-allow-core-count-adjustment" :
9388 + "qcom,corner-allow-core-count-adjustment");
9389 +
9390 + rc = use_corner_band ?
9391 + cpr3_parse_corner_band_array_property(vreg, prop_str,
9392 + 1, allow_core_count_adj) :
9393 + cpr3_parse_corner_array_property(vreg, prop_str,
9394 + 1, allow_core_count_adj);
9395 + if (rc) {
9396 + cpr3_err(vreg, "error reading %s, rc=%d\n", prop_str,
9397 + rc);
9398 + goto done;
9399 + }
9400 + }
9401 +
9402 + if (vreg->allow_temp_adj) {
9403 + allow_temp_adj = kcalloc(vreg->corner_count,
9404 + sizeof(*allow_temp_adj), GFP_KERNEL);
9405 + if (!allow_temp_adj) {
9406 + rc = -ENOMEM;
9407 + goto done;
9408 + }
9409 +
9410 + snprintf(prop_str, sizeof(prop_str), "%s", use_corner_band ?
9411 + "qcom,corner-band-allow-temp-adjustment" :
9412 + "qcom,corner-allow-temp-adjustment");
9413 +
9414 + rc = use_corner_band ?
9415 + cpr3_parse_corner_band_array_property(vreg, prop_str,
9416 + 1, allow_temp_adj) :
9417 + cpr3_parse_corner_array_property(vreg, prop_str,
9418 + 1, allow_temp_adj);
9419 + if (rc) {
9420 + cpr3_err(vreg, "error reading %s, rc=%d\n", prop_str,
9421 + rc);
9422 + goto done;
9423 + }
9424 + }
9425 +
9426 + sdelta_table_count = use_corner_band ? vreg->corner_band_count :
9427 + vreg->corner_count;
9428 +
9429 + for (i = 0; i < sdelta_table_count; i++) {
9430 + sdelta = devm_kzalloc(ctrl->dev, sizeof(*corner->sdelta),
9431 + GFP_KERNEL);
9432 + if (!sdelta) {
9433 + rc = -ENOMEM;
9434 + goto done;
9435 + }
9436 +
9437 + if (allow_core_count_adj)
9438 + sdelta->allow_core_count_adj = allow_core_count_adj[i];
9439 + if (allow_temp_adj)
9440 + sdelta->allow_temp_adj = allow_temp_adj[i];
9441 + sdelta->max_core_count = vreg->max_core_count;
9442 + sdelta->temp_band_count = ctrl->temp_band_count;
9443 +
9444 + if (use_corner_band)
9445 + vreg->corner_band[i].sdelta = sdelta;
9446 + else
9447 + vreg->corner[i].sdelta = sdelta;
9448 +
9449 + rc = cpr4_load_core_and_temp_adj(vreg, i, use_corner_band);
9450 + if (rc) {
9451 + cpr3_err(vreg, "corner/band %d core and temp adjustment loading failed, rc=%d\n",
9452 + i, rc);
9453 + goto done;
9454 + }
9455 + }
9456 +
9457 +done:
9458 + kfree(allow_core_count_adj);
9459 + kfree(allow_temp_adj);
9460 +
9461 + return rc;
9462 +}
9463 +
9464 +/**
9465 + * cprh_adjust_voltages_for_apm() - adjust per-corner floor and ceiling voltages
9466 + * so that they do not overlap the APM threshold voltage.
9467 + * @vreg: Pointer to the CPR3 regulator
9468 + *
9469 + * The memory array power mux (APM) must be configured for a specific supply
9470 + * based upon where the VDD voltage lies with respect to the APM threshold
9471 + * voltage. When using CPR hardware closed-loop, the voltage may vary anywhere
9472 + * between the floor and ceiling voltage without software notification.
9473 + * Therefore, it is required that the floor to ceiling range for every corner
9474 + * not intersect the APM threshold voltage. This function adjusts the floor to
9475 + * ceiling range for each corner which violates this requirement.
9476 + *
9477 + * The following algorithm is applied:
9478 + * if floor < threshold <= ceiling:
9479 + * if open_loop >= threshold, then floor = threshold - adj
9480 + * else ceiling = threshold - step
9481 + * where:
9482 + * adj = APM hysteresis voltage established to minimize the number of
9483 + * corners with artificially increased floor voltages
9484 + * step = voltage in microvolts of a single step of the VDD supply
9485 + *
9486 + * The open-loop voltage is also bounded by the new floor or ceiling value as
9487 + * needed.
9488 + *
9489 + * Return: none
9490 + */
9491 +void cprh_adjust_voltages_for_apm(struct cpr3_regulator *vreg)
9492 +{
9493 + struct cpr3_controller *ctrl = vreg->thread->ctrl;
9494 + struct cpr3_corner *corner;
9495 + int i, adj, threshold, prev_ceiling, prev_floor, prev_open_loop;
9496 +
9497 + if (!ctrl->apm_threshold_volt) {
9498 + /* APM not being used. */
9499 + return;
9500 + }
9501 +
9502 + ctrl->apm_threshold_volt = CPR3_ROUND(ctrl->apm_threshold_volt,
9503 + ctrl->step_volt);
9504 + ctrl->apm_adj_volt = CPR3_ROUND(ctrl->apm_adj_volt, ctrl->step_volt);
9505 +
9506 + threshold = ctrl->apm_threshold_volt;
9507 + adj = ctrl->apm_adj_volt;
9508 +
9509 + for (i = 0; i < vreg->corner_count; i++) {
9510 + corner = &vreg->corner[i];
9511 +
9512 + if (threshold <= corner->floor_volt
9513 + || threshold > corner->ceiling_volt)
9514 + continue;
9515 +
9516 + prev_floor = corner->floor_volt;
9517 + prev_ceiling = corner->ceiling_volt;
9518 + prev_open_loop = corner->open_loop_volt;
9519 +
9520 + if (corner->open_loop_volt >= threshold) {
9521 + corner->floor_volt = max(corner->floor_volt,
9522 + threshold - adj);
9523 + if (corner->open_loop_volt < corner->floor_volt)
9524 + corner->open_loop_volt = corner->floor_volt;
9525 + } else {
9526 + corner->ceiling_volt = threshold - ctrl->step_volt;
9527 + }
9528 +
9529 + if (corner->floor_volt != prev_floor
9530 + || corner->ceiling_volt != prev_ceiling
9531 + || corner->open_loop_volt != prev_open_loop)
9532 + 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",
9533 + threshold, adj, i, prev_floor, prev_ceiling,
9534 + prev_open_loop, corner->floor_volt,
9535 + corner->ceiling_volt, corner->open_loop_volt);
9536 + }
9537 +}
9538 +
9539 +/**
9540 + * cprh_adjust_voltages_for_mem_acc() - adjust per-corner floor and ceiling
9541 + * voltages so that they do not intersect the MEM ACC threshold
9542 + * voltage
9543 + * @vreg: Pointer to the CPR3 regulator
9544 + *
9545 + * The following algorithm is applied:
9546 + * if floor < threshold <= ceiling:
9547 + * if open_loop >= threshold, then floor = threshold
9548 + * else ceiling = threshold - step
9549 + * where:
9550 + * step = voltage in microvolts of a single step of the VDD supply
9551 + *
9552 + * The open-loop voltage is also bounded by the new floor or ceiling value as
9553 + * needed.
9554 + *
9555 + * Return: none
9556 + */
9557 +void cprh_adjust_voltages_for_mem_acc(struct cpr3_regulator *vreg)
9558 +{
9559 + struct cpr3_controller *ctrl = vreg->thread->ctrl;
9560 + struct cpr3_corner *corner;
9561 + int i, threshold, prev_ceiling, prev_floor, prev_open_loop;
9562 +
9563 + if (!ctrl->mem_acc_threshold_volt) {
9564 + /* MEM ACC not being used. */
9565 + return;
9566 + }
9567 +
9568 + ctrl->mem_acc_threshold_volt = CPR3_ROUND(ctrl->mem_acc_threshold_volt,
9569 + ctrl->step_volt);
9570 +
9571 + threshold = ctrl->mem_acc_threshold_volt;
9572 +
9573 + for (i = 0; i < vreg->corner_count; i++) {
9574 + corner = &vreg->corner[i];
9575 +
9576 + if (threshold <= corner->floor_volt
9577 + || threshold > corner->ceiling_volt)
9578 + continue;
9579 +
9580 + prev_floor = corner->floor_volt;
9581 + prev_ceiling = corner->ceiling_volt;
9582 + prev_open_loop = corner->open_loop_volt;
9583 +
9584 + if (corner->open_loop_volt >= threshold) {
9585 + corner->floor_volt = max(corner->floor_volt, threshold);
9586 + if (corner->open_loop_volt < corner->floor_volt)
9587 + corner->open_loop_volt = corner->floor_volt;
9588 + } else {
9589 + corner->ceiling_volt = threshold - ctrl->step_volt;
9590 + }
9591 +
9592 + if (corner->floor_volt != prev_floor
9593 + || corner->ceiling_volt != prev_ceiling
9594 + || corner->open_loop_volt != prev_open_loop)
9595 + 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",
9596 + threshold, i, prev_floor, prev_ceiling,
9597 + prev_open_loop, corner->floor_volt,
9598 + corner->ceiling_volt, corner->open_loop_volt);
9599 + }
9600 +}
9601 +
9602 +/**
9603 + * cpr3_apply_closed_loop_offset_voltages() - modify the closed-loop voltage
9604 + * adjustments by the amounts that are needed for this
9605 + * fuse combo
9606 + * @vreg: Pointer to the CPR3 regulator
9607 + * @volt_adjust: Array of closed-loop voltage adjustment values of length
9608 + * vreg->corner_count which is further adjusted based upon
9609 + * offset voltage fuse values.
9610 + * @fuse_volt_adjust: Fused closed-loop voltage adjustment values of length
9611 + * vreg->fuse_corner_count.
9612 + *
9613 + * Return: 0 on success, errno on failure
9614 + */
9615 +static int cpr3_apply_closed_loop_offset_voltages(struct cpr3_regulator *vreg,
9616 + int *volt_adjust, int *fuse_volt_adjust)
9617 +{
9618 + u32 *corner_map;
9619 + int rc = 0, i;
9620 +
9621 + if (!of_find_property(vreg->of_node,
9622 + "qcom,cpr-fused-closed-loop-voltage-adjustment-map", NULL)) {
9623 + /* No closed-loop offset required. */
9624 + return 0;
9625 + }
9626 +
9627 + corner_map = kcalloc(vreg->corner_count, sizeof(*corner_map),
9628 + GFP_KERNEL);
9629 + if (!corner_map)
9630 + return -ENOMEM;
9631 +
9632 + rc = cpr3_parse_corner_array_property(vreg,
9633 + "qcom,cpr-fused-closed-loop-voltage-adjustment-map",
9634 + 1, corner_map);
9635 + if (rc)
9636 + goto done;
9637 +
9638 + for (i = 0; i < vreg->corner_count; i++) {
9639 + if (corner_map[i] == 0) {
9640 + continue;
9641 + } else if (corner_map[i] > vreg->fuse_corner_count) {
9642 + cpr3_err(vreg, "corner %d mapped to invalid fuse corner: %u\n",
9643 + i, corner_map[i]);
9644 + rc = -EINVAL;
9645 + goto done;
9646 + }
9647 +
9648 + volt_adjust[i] += fuse_volt_adjust[corner_map[i] - 1];
9649 + }
9650 +
9651 +done:
9652 + kfree(corner_map);
9653 + return rc;
9654 +}
9655 +
9656 +/**
9657 + * cpr3_enforce_inc_quotient_monotonicity() - Ensure that target quotients
9658 + * increase monotonically from lower to higher corners
9659 + * @vreg: Pointer to the CPR3 regulator
9660 + *
9661 + * Return: 0 on success, errno on failure
9662 + */
9663 +static void cpr3_enforce_inc_quotient_monotonicity(struct cpr3_regulator *vreg)
9664 +{
9665 + int i, j;
9666 +
9667 + for (i = 1; i < vreg->corner_count; i++) {
9668 + for (j = 0; j < CPR3_RO_COUNT; j++) {
9669 + if (vreg->corner[i].target_quot[j]
9670 + && vreg->corner[i].target_quot[j]
9671 + < vreg->corner[i - 1].target_quot[j]) {
9672 + 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",
9673 + i, j,
9674 + vreg->corner[i].target_quot[j],
9675 + i - 1, j,
9676 + vreg->corner[i - 1].target_quot[j],
9677 + i, j,
9678 + vreg->corner[i - 1].target_quot[j]);
9679 + vreg->corner[i].target_quot[j]
9680 + = vreg->corner[i - 1].target_quot[j];
9681 + }
9682 + }
9683 + }
9684 +}
9685 +
9686 +/**
9687 + * cpr3_enforce_dec_quotient_monotonicity() - Ensure that target quotients
9688 + * decrease monotonically from higher to lower corners
9689 + * @vreg: Pointer to the CPR3 regulator
9690 + *
9691 + * Return: 0 on success, errno on failure
9692 + */
9693 +static void cpr3_enforce_dec_quotient_monotonicity(struct cpr3_regulator *vreg)
9694 +{
9695 + int i, j;
9696 +
9697 + for (i = vreg->corner_count - 2; i >= 0; i--) {
9698 + for (j = 0; j < CPR3_RO_COUNT; j++) {
9699 + if (vreg->corner[i + 1].target_quot[j]
9700 + && vreg->corner[i].target_quot[j]
9701 + > vreg->corner[i + 1].target_quot[j]) {
9702 + 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",
9703 + i, j,
9704 + vreg->corner[i].target_quot[j],
9705 + i + 1, j,
9706 + vreg->corner[i + 1].target_quot[j],
9707 + i, j,
9708 + vreg->corner[i + 1].target_quot[j]);
9709 + vreg->corner[i].target_quot[j]
9710 + = vreg->corner[i + 1].target_quot[j];
9711 + }
9712 + }
9713 + }
9714 +}
9715 +
9716 +/**
9717 + * _cpr3_adjust_target_quotients() - adjust the target quotients for each
9718 + * corner of the regulator according to input adjustment and
9719 + * scaling arrays
9720 + * @vreg: Pointer to the CPR3 regulator
9721 + * @volt_adjust: Pointer to an array of closed-loop voltage adjustments
9722 + * with units of microvolts. The array must have
9723 + * vreg->corner_count number of elements.
9724 + * @ro_scale: Pointer to a flattened 2D array of RO scaling factors.
9725 + * The array must have an inner dimension of CPR3_RO_COUNT
9726 + * and an outer dimension of vreg->corner_count
9727 + * @label: Null terminated string providing a label for the type
9728 + * of adjustment.
9729 + *
9730 + * Return: true if any corners received a positive voltage adjustment (> 0),
9731 + * else false
9732 + */
9733 +static bool _cpr3_adjust_target_quotients(struct cpr3_regulator *vreg,
9734 + const int *volt_adjust, const int *ro_scale, const char *label)
9735 +{
9736 + int i, j, quot_adjust;
9737 + bool is_increasing = false;
9738 + u32 prev_quot;
9739 +
9740 + for (i = 0; i < vreg->corner_count; i++) {
9741 + for (j = 0; j < CPR3_RO_COUNT; j++) {
9742 + if (vreg->corner[i].target_quot[j]) {
9743 + quot_adjust = cpr3_quot_adjustment(
9744 + ro_scale[i * CPR3_RO_COUNT + j],
9745 + volt_adjust[i]);
9746 + if (quot_adjust) {
9747 + prev_quot = vreg->corner[i].
9748 + target_quot[j];
9749 + vreg->corner[i].target_quot[j]
9750 + += quot_adjust;
9751 + cpr3_debug(vreg, "adjusted corner %d RO%d target quot %s: %u --> %u (%d uV)\n",
9752 + i, j, label, prev_quot,
9753 + vreg->corner[i].target_quot[j],
9754 + volt_adjust[i]);
9755 + }
9756 + }
9757 + }
9758 + if (volt_adjust[i] > 0)
9759 + is_increasing = true;
9760 + }
9761 +
9762 + return is_increasing;
9763 +}
9764 +
9765 +/**
9766 + * cpr3_adjust_target_quotients() - adjust the target quotients for each
9767 + * corner according to device tree values and fuse values
9768 + * @vreg: Pointer to the CPR3 regulator
9769 + * @fuse_volt_adjust: Fused closed-loop voltage adjustment values of length
9770 + * vreg->fuse_corner_count. This parameter could be null
9771 + * pointer when no fused adjustments are needed.
9772 + *
9773 + * Return: 0 on success, errno on failure
9774 + */
9775 +int cpr3_adjust_target_quotients(struct cpr3_regulator *vreg,
9776 + int *fuse_volt_adjust)
9777 +{
9778 + int i, rc;
9779 + int *volt_adjust, *ro_scale;
9780 + bool explicit_adjustment, fused_adjustment, is_increasing;
9781 +
9782 + explicit_adjustment = of_find_property(vreg->of_node,
9783 + "qcom,cpr-closed-loop-voltage-adjustment", NULL);
9784 + fused_adjustment = of_find_property(vreg->of_node,
9785 + "qcom,cpr-fused-closed-loop-voltage-adjustment-map", NULL);
9786 +
9787 + if (!explicit_adjustment && !fused_adjustment && !vreg->aging_allowed) {
9788 + /* No adjustment required. */
9789 + return 0;
9790 + } else if (!of_find_property(vreg->of_node,
9791 + "qcom,cpr-ro-scaling-factor", NULL)) {
9792 + cpr3_err(vreg, "qcom,cpr-ro-scaling-factor is required for closed-loop voltage adjustment, but is missing\n");
9793 + return -EINVAL;
9794 + }
9795 +
9796 + volt_adjust = kcalloc(vreg->corner_count, sizeof(*volt_adjust),
9797 + GFP_KERNEL);
9798 + ro_scale = kcalloc(vreg->corner_count * CPR3_RO_COUNT,
9799 + sizeof(*ro_scale), GFP_KERNEL);
9800 + if (!volt_adjust || !ro_scale) {
9801 + rc = -ENOMEM;
9802 + goto done;
9803 + }
9804 +
9805 + rc = cpr3_parse_corner_array_property(vreg,
9806 + "qcom,cpr-ro-scaling-factor", CPR3_RO_COUNT, ro_scale);
9807 + if (rc) {
9808 + cpr3_err(vreg, "could not load RO scaling factors, rc=%d\n",
9809 + rc);
9810 + goto done;
9811 + }
9812 +
9813 + for (i = 0; i < vreg->corner_count; i++)
9814 + memcpy(vreg->corner[i].ro_scale, &ro_scale[i * CPR3_RO_COUNT],
9815 + sizeof(*ro_scale) * CPR3_RO_COUNT);
9816 +
9817 + if (explicit_adjustment) {
9818 + rc = cpr3_parse_corner_array_property(vreg,
9819 + "qcom,cpr-closed-loop-voltage-adjustment",
9820 + 1, volt_adjust);
9821 + if (rc) {
9822 + cpr3_err(vreg, "could not load closed-loop voltage adjustments, rc=%d\n",
9823 + rc);
9824 + goto done;
9825 + }
9826 +
9827 + _cpr3_adjust_target_quotients(vreg, volt_adjust, ro_scale,
9828 + "from DT");
9829 + cpr3_enforce_inc_quotient_monotonicity(vreg);
9830 + }
9831 +
9832 + if (fused_adjustment && fuse_volt_adjust) {
9833 + memset(volt_adjust, 0,
9834 + sizeof(*volt_adjust) * vreg->corner_count);
9835 +
9836 + rc = cpr3_apply_closed_loop_offset_voltages(vreg, volt_adjust,
9837 + fuse_volt_adjust);
9838 + if (rc) {
9839 + cpr3_err(vreg, "could not apply fused closed-loop voltage reductions, rc=%d\n",
9840 + rc);
9841 + goto done;
9842 + }
9843 +
9844 + is_increasing = _cpr3_adjust_target_quotients(vreg, volt_adjust,
9845 + ro_scale, "from fuse");
9846 + if (is_increasing)
9847 + cpr3_enforce_inc_quotient_monotonicity(vreg);
9848 + else
9849 + cpr3_enforce_dec_quotient_monotonicity(vreg);
9850 + }
9851 +
9852 +done:
9853 + kfree(volt_adjust);
9854 + kfree(ro_scale);
9855 + return rc;
9856 +}
9857 --- /dev/null
9858 +++ b/drivers/regulator/cpr4-apss-regulator.c
9859 @@ -0,0 +1,1819 @@
9860 +/*
9861 + * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
9862 + *
9863 + * This program is free software; you can redistribute it and/or modify
9864 + * it under the terms of the GNU General Public License version 2 and
9865 + * only version 2 as published by the Free Software Foundation.
9866 + *
9867 + * This program is distributed in the hope that it will be useful,
9868 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
9869 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9870 + * GNU General Public License for more details.
9871 + */
9872 +
9873 +#define pr_fmt(fmt) "%s: " fmt, __func__
9874 +
9875 +#include <linux/bitops.h>
9876 +#include <linux/debugfs.h>
9877 +#include <linux/err.h>
9878 +#include <linux/init.h>
9879 +#include <linux/interrupt.h>
9880 +#include <linux/io.h>
9881 +#include <linux/kernel.h>
9882 +#include <linux/list.h>
9883 +#include <linux/module.h>
9884 +#include <linux/of.h>
9885 +#include <linux/of_device.h>
9886 +#include <linux/platform_device.h>
9887 +#include <linux/pm_opp.h>
9888 +#include <linux/slab.h>
9889 +#include <linux/string.h>
9890 +#include <linux/uaccess.h>
9891 +#include <linux/regulator/driver.h>
9892 +#include <linux/regulator/machine.h>
9893 +#include <linux/regulator/of_regulator.h>
9894 +
9895 +#include "cpr3-regulator.h"
9896 +
9897 +#define IPQ807x_APSS_FUSE_CORNERS 4
9898 +#define IPQ817x_APPS_FUSE_CORNERS 2
9899 +#define IPQ6018_APSS_FUSE_CORNERS 4
9900 +#define IPQ9574_APSS_FUSE_CORNERS 4
9901 +
9902 +u32 g_valid_fuse_count = IPQ807x_APSS_FUSE_CORNERS;
9903 +
9904 +/**
9905 + * struct cpr4_ipq807x_apss_fuses - APSS specific fuse data for IPQ807x
9906 + * @ro_sel: Ring oscillator select fuse parameter value for each
9907 + * fuse corner
9908 + * @init_voltage: Initial (i.e. open-loop) voltage fuse parameter value
9909 + * for each fuse corner (raw, not converted to a voltage)
9910 + * @target_quot: CPR target quotient fuse parameter value for each fuse
9911 + * corner
9912 + * @quot_offset: CPR target quotient offset fuse parameter value for each
9913 + * fuse corner (raw, not unpacked) used for target quotient
9914 + * interpolation
9915 + * @speed_bin: Application processor speed bin fuse parameter value for
9916 + * the given chip
9917 + * @cpr_fusing_rev: CPR fusing revision fuse parameter value
9918 + * @boost_cfg: CPR boost configuration fuse parameter value
9919 + * @boost_voltage: CPR boost voltage fuse parameter value (raw, not
9920 + * converted to a voltage)
9921 + *
9922 + * This struct holds the values for all of the fuses read from memory.
9923 + */
9924 +struct cpr4_ipq807x_apss_fuses {
9925 + u64 ro_sel[IPQ807x_APSS_FUSE_CORNERS];
9926 + u64 init_voltage[IPQ807x_APSS_FUSE_CORNERS];
9927 + u64 target_quot[IPQ807x_APSS_FUSE_CORNERS];
9928 + u64 quot_offset[IPQ807x_APSS_FUSE_CORNERS];
9929 + u64 speed_bin;
9930 + u64 cpr_fusing_rev;
9931 + u64 boost_cfg;
9932 + u64 boost_voltage;
9933 + u64 misc;
9934 +};
9935 +
9936 +/*
9937 + * fuse combo = fusing revision + 8 * (speed bin)
9938 + * where: fusing revision = 0 - 7 and speed bin = 0 - 7
9939 + */
9940 +#define CPR4_IPQ807x_APSS_FUSE_COMBO_COUNT 64
9941 +
9942 +/*
9943 + * Constants which define the name of each fuse corner.
9944 + */
9945 +enum cpr4_ipq807x_apss_fuse_corner {
9946 + CPR4_IPQ807x_APSS_FUSE_CORNER_SVS = 0,
9947 + CPR4_IPQ807x_APSS_FUSE_CORNER_NOM = 1,
9948 + CPR4_IPQ807x_APSS_FUSE_CORNER_TURBO = 2,
9949 + CPR4_IPQ807x_APSS_FUSE_CORNER_STURBO = 3,
9950 +};
9951 +
9952 +static const char * const cpr4_ipq807x_apss_fuse_corner_name[] = {
9953 + [CPR4_IPQ807x_APSS_FUSE_CORNER_SVS] = "SVS",
9954 + [CPR4_IPQ807x_APSS_FUSE_CORNER_NOM] = "NOM",
9955 + [CPR4_IPQ807x_APSS_FUSE_CORNER_TURBO] = "TURBO",
9956 + [CPR4_IPQ807x_APSS_FUSE_CORNER_STURBO] = "STURBO",
9957 +};
9958 +
9959 +/*
9960 + * IPQ807x APSS fuse parameter locations:
9961 + *
9962 + * Structs are organized with the following dimensions:
9963 + * Outer: 0 to 3 for fuse corners from lowest to highest corner
9964 + * Inner: large enough to hold the longest set of parameter segments which
9965 + * fully defines a fuse parameter, +1 (for NULL termination).
9966 + * Each segment corresponds to a contiguous group of bits from a
9967 + * single fuse row. These segments are concatentated together in
9968 + * order to form the full fuse parameter value. The segments for
9969 + * a given parameter may correspond to different fuse rows.
9970 + */
9971 +static struct cpr3_fuse_param
9972 +ipq807x_apss_ro_sel_param[IPQ807x_APSS_FUSE_CORNERS][2] = {
9973 + {{73, 8, 11}, {} },
9974 + {{73, 4, 7}, {} },
9975 + {{73, 0, 3}, {} },
9976 + {{73, 12, 15}, {} },
9977 +};
9978 +
9979 +static struct cpr3_fuse_param
9980 +ipq807x_apss_init_voltage_param[IPQ807x_APSS_FUSE_CORNERS][2] = {
9981 + {{71, 18, 23}, {} },
9982 + {{71, 12, 17}, {} },
9983 + {{71, 6, 11}, {} },
9984 + {{71, 0, 5}, {} },
9985 +};
9986 +
9987 +static struct cpr3_fuse_param
9988 +ipq807x_apss_target_quot_param[IPQ807x_APSS_FUSE_CORNERS][2] = {
9989 + {{72, 32, 43}, {} },
9990 + {{72, 20, 31}, {} },
9991 + {{72, 8, 19}, {} },
9992 + {{72, 44, 55}, {} },
9993 +};
9994 +
9995 +static struct cpr3_fuse_param
9996 +ipq807x_apss_quot_offset_param[IPQ807x_APSS_FUSE_CORNERS][2] = {
9997 + {{} },
9998 + {{71, 46, 52}, {} },
9999 + {{71, 39, 45}, {} },
10000 + {{71, 32, 38}, {} },
10001 +};
10002 +
10003 +static struct cpr3_fuse_param ipq807x_cpr_fusing_rev_param[] = {
10004 + {71, 53, 55},
10005 + {},
10006 +};
10007 +
10008 +static struct cpr3_fuse_param ipq807x_apss_speed_bin_param[] = {
10009 + {36, 40, 42},
10010 + {},
10011 +};
10012 +
10013 +static struct cpr3_fuse_param ipq807x_cpr_boost_fuse_cfg_param[] = {
10014 + {36, 43, 45},
10015 + {},
10016 +};
10017 +
10018 +static struct cpr3_fuse_param ipq807x_apss_boost_fuse_volt_param[] = {
10019 + {71, 0, 5},
10020 + {},
10021 +};
10022 +
10023 +static struct cpr3_fuse_param ipq807x_misc_fuse_volt_adj_param[] = {
10024 + {36, 54, 54},
10025 + {},
10026 +};
10027 +
10028 +static struct cpr3_fuse_parameters ipq807x_fuse_params = {
10029 + .apss_ro_sel_param = ipq807x_apss_ro_sel_param,
10030 + .apss_init_voltage_param = ipq807x_apss_init_voltage_param,
10031 + .apss_target_quot_param = ipq807x_apss_target_quot_param,
10032 + .apss_quot_offset_param = ipq807x_apss_quot_offset_param,
10033 + .cpr_fusing_rev_param = ipq807x_cpr_fusing_rev_param,
10034 + .apss_speed_bin_param = ipq807x_apss_speed_bin_param,
10035 + .cpr_boost_fuse_cfg_param = ipq807x_cpr_boost_fuse_cfg_param,
10036 + .apss_boost_fuse_volt_param = ipq807x_apss_boost_fuse_volt_param,
10037 + .misc_fuse_volt_adj_param = ipq807x_misc_fuse_volt_adj_param
10038 +};
10039 +
10040 +/*
10041 + * The number of possible values for misc fuse is
10042 + * 2^(#bits defined for misc fuse)
10043 + */
10044 +#define IPQ807x_MISC_FUSE_VAL_COUNT BIT(1)
10045 +
10046 +/*
10047 + * Open loop voltage fuse reference voltages in microvolts for IPQ807x
10048 + */
10049 +static int ipq807x_apss_fuse_ref_volt
10050 + [IPQ807x_APSS_FUSE_CORNERS] = {
10051 + 720000,
10052 + 864000,
10053 + 992000,
10054 + 1064000,
10055 +};
10056 +
10057 +#define IPQ807x_APSS_FUSE_STEP_VOLT 8000
10058 +#define IPQ807x_APSS_VOLTAGE_FUSE_SIZE 6
10059 +#define IPQ807x_APSS_QUOT_OFFSET_SCALE 5
10060 +
10061 +#define IPQ807x_APSS_CPR_SENSOR_COUNT 6
10062 +
10063 +#define IPQ807x_APSS_CPR_CLOCK_RATE 19200000
10064 +
10065 +#define IPQ807x_APSS_MAX_TEMP_POINTS 3
10066 +#define IPQ807x_APSS_TEMP_SENSOR_ID_START 4
10067 +#define IPQ807x_APSS_TEMP_SENSOR_ID_END 13
10068 +/*
10069 + * Boost voltage fuse reference and ceiling voltages in microvolts for
10070 + * IPQ807x.
10071 + */
10072 +#define IPQ807x_APSS_BOOST_FUSE_REF_VOLT 1140000
10073 +#define IPQ807x_APSS_BOOST_CEILING_VOLT 1140000
10074 +#define IPQ807x_APSS_BOOST_FLOOR_VOLT 900000
10075 +#define MAX_BOOST_CONFIG_FUSE_VALUE 8
10076 +
10077 +#define IPQ807x_APSS_CPR_SDELTA_CORE_COUNT 15
10078 +
10079 +#define IPQ807x_APSS_CPR_TCSR_START 8
10080 +#define IPQ807x_APSS_CPR_TCSR_END 9
10081 +
10082 +/*
10083 + * Array of integer values mapped to each of the boost config fuse values to
10084 + * indicate boost enable/disable status.
10085 + */
10086 +static bool boost_fuse[MAX_BOOST_CONFIG_FUSE_VALUE] = {0, 1, 1, 1, 1, 1, 1, 1};
10087 +
10088 +/*
10089 + * IPQ6018 (Few parameters are changed, remaining are same as IPQ807x)
10090 + */
10091 +#define IPQ6018_APSS_FUSE_STEP_VOLT 12500
10092 +#define IPQ6018_APSS_CPR_CLOCK_RATE 24000000
10093 +
10094 +static struct cpr3_fuse_param
10095 +ipq6018_apss_ro_sel_param[IPQ6018_APSS_FUSE_CORNERS][2] = {
10096 + {{75, 8, 11}, {} },
10097 + {{75, 4, 7}, {} },
10098 + {{75, 0, 3}, {} },
10099 + {{75, 12, 15}, {} },
10100 +};
10101 +
10102 +static struct cpr3_fuse_param
10103 +ipq6018_apss_init_voltage_param[IPQ6018_APSS_FUSE_CORNERS][2] = {
10104 + {{73, 18, 23}, {} },
10105 + {{73, 12, 17}, {} },
10106 + {{73, 6, 11}, {} },
10107 + {{73, 0, 5}, {} },
10108 +};
10109 +
10110 +static struct cpr3_fuse_param
10111 +ipq6018_apss_target_quot_param[IPQ6018_APSS_FUSE_CORNERS][2] = {
10112 + {{74, 32, 43}, {} },
10113 + {{74, 20, 31}, {} },
10114 + {{74, 8, 19}, {} },
10115 + {{74, 44, 55}, {} },
10116 +};
10117 +
10118 +static struct cpr3_fuse_param
10119 +ipq6018_apss_quot_offset_param[IPQ6018_APSS_FUSE_CORNERS][2] = {
10120 + {{} },
10121 + {{73, 48, 55}, {} },
10122 + {{73, 40, 47}, {} },
10123 + {{73, 32, 39}, {} },
10124 +};
10125 +
10126 +static struct cpr3_fuse_param ipq6018_cpr_fusing_rev_param[] = {
10127 + {75, 16, 18},
10128 + {},
10129 +};
10130 +
10131 +static struct cpr3_fuse_param ipq6018_apss_speed_bin_param[] = {
10132 + {36, 40, 42},
10133 + {},
10134 +};
10135 +
10136 +static struct cpr3_fuse_param ipq6018_cpr_boost_fuse_cfg_param[] = {
10137 + {36, 43, 45},
10138 + {},
10139 +};
10140 +
10141 +static struct cpr3_fuse_param ipq6018_apss_boost_fuse_volt_param[] = {
10142 + {73, 0, 5},
10143 + {},
10144 +};
10145 +
10146 +static struct cpr3_fuse_param ipq6018_misc_fuse_volt_adj_param[] = {
10147 + {36, 54, 54},
10148 + {},
10149 +};
10150 +
10151 +static struct cpr3_fuse_parameters ipq6018_fuse_params = {
10152 + .apss_ro_sel_param = ipq6018_apss_ro_sel_param,
10153 + .apss_init_voltage_param = ipq6018_apss_init_voltage_param,
10154 + .apss_target_quot_param = ipq6018_apss_target_quot_param,
10155 + .apss_quot_offset_param = ipq6018_apss_quot_offset_param,
10156 + .cpr_fusing_rev_param = ipq6018_cpr_fusing_rev_param,
10157 + .apss_speed_bin_param = ipq6018_apss_speed_bin_param,
10158 + .cpr_boost_fuse_cfg_param = ipq6018_cpr_boost_fuse_cfg_param,
10159 + .apss_boost_fuse_volt_param = ipq6018_apss_boost_fuse_volt_param,
10160 + .misc_fuse_volt_adj_param = ipq6018_misc_fuse_volt_adj_param
10161 +};
10162 +
10163 +
10164 +/*
10165 + * Boost voltage fuse reference and ceiling voltages in microvolts for
10166 + * IPQ6018.
10167 + */
10168 +#define IPQ6018_APSS_BOOST_FUSE_REF_VOLT 1140000
10169 +#define IPQ6018_APSS_BOOST_CEILING_VOLT 1140000
10170 +#define IPQ6018_APSS_BOOST_FLOOR_VOLT 900000
10171 +
10172 +/*
10173 + * Open loop voltage fuse reference voltages in microvolts for IPQ807x
10174 + */
10175 +static int ipq6018_apss_fuse_ref_volt
10176 + [IPQ6018_APSS_FUSE_CORNERS] = {
10177 + 725000,
10178 + 862500,
10179 + 987500,
10180 + 1062500,
10181 +};
10182 +
10183 +/*
10184 + * IPQ6018 Memory ACC settings on TCSR
10185 + *
10186 + * Turbo_L1: write TCSR_MEM_ACC_SW_OVERRIDE_LEGACY_APC0 0x10
10187 + * write TCSR_CUSTOM_VDDAPC0_ACC_1 0x1
10188 + * Other modes: write TCSR_MEM_ACC_SW_OVERRIDE_LEGACY_APC0 0x0
10189 + * write TCSR_CUSTOM_VDDAPC0_ACC_1 0x0
10190 + *
10191 + */
10192 +#define IPQ6018_APSS_MEM_ACC_TCSR_COUNT 2
10193 +#define TCSR_MEM_ACC_SW_OVERRIDE_LEGACY_APC0 0x1946178
10194 +#define TCSR_CUSTOM_VDDAPC0_ACC_1 0x1946124
10195 +
10196 +struct mem_acc_tcsr {
10197 + u32 phy_addr;
10198 + void __iomem *ioremap_addr;
10199 + u32 value;
10200 +};
10201 +
10202 +static struct mem_acc_tcsr ipq6018_mem_acc_tcsr[IPQ6018_APSS_MEM_ACC_TCSR_COUNT] = {
10203 + {TCSR_MEM_ACC_SW_OVERRIDE_LEGACY_APC0, NULL, 0x10},
10204 + {TCSR_CUSTOM_VDDAPC0_ACC_1, NULL, 0x1},
10205 +};
10206 +
10207 +/*
10208 + * IPQ9574 (Few parameters are changed, remaining are same as IPQ6018)
10209 + */
10210 +#define IPQ9574_APSS_FUSE_STEP_VOLT 10000
10211 +
10212 +static struct cpr3_fuse_param
10213 +ipq9574_apss_ro_sel_param[IPQ9574_APSS_FUSE_CORNERS][2] = {
10214 + {{107, 4, 7}, {} },
10215 + {{107, 0, 3}, {} },
10216 + {{106, 4, 7}, {} },
10217 + {{106, 0, 3}, {} },
10218 +};
10219 +
10220 +static struct cpr3_fuse_param
10221 +ipq9574_apss_init_voltage_param[IPQ9574_APSS_FUSE_CORNERS][2] = {
10222 + {{104, 24, 29}, {} },
10223 + {{104, 18, 23}, {} },
10224 + {{104, 12, 17}, {} },
10225 + {{104, 6, 11}, {} },
10226 +};
10227 +
10228 +static struct cpr3_fuse_param
10229 +ipq9574_apss_target_quot_param[IPQ9574_APSS_FUSE_CORNERS][2] = {
10230 + {{106, 32, 43}, {} },
10231 + {{106, 20, 31}, {} },
10232 + {{106, 8, 19}, {} },
10233 + {{106, 44, 55}, {} },
10234 +};
10235 +
10236 +static struct cpr3_fuse_param
10237 +ipq9574_apss_quot_offset_param[IPQ9574_APSS_FUSE_CORNERS][2] = {
10238 + {{} },
10239 + {{105, 48, 55}, {} },
10240 + {{105, 40, 47}, {} },
10241 + {{105, 32, 39}, {} },
10242 +};
10243 +
10244 +static struct cpr3_fuse_param ipq9574_cpr_fusing_rev_param[] = {
10245 + {107, 8, 10},
10246 + {},
10247 +};
10248 +
10249 +static struct cpr3_fuse_param ipq9574_apss_speed_bin_param[] = {
10250 + {0, 40, 42},
10251 + {},
10252 +};
10253 +
10254 +static struct cpr3_fuse_param ipq9574_cpr_boost_fuse_cfg_param[] = {
10255 + {0, 43, 45},
10256 + {},
10257 +};
10258 +
10259 +static struct cpr3_fuse_param ipq9574_apss_boost_fuse_volt_param[] = {
10260 + {104, 0, 5},
10261 + {},
10262 +};
10263 +
10264 +static struct cpr3_fuse_param ipq9574_misc_fuse_volt_adj_param[] = {
10265 + {0, 54, 54},
10266 + {},
10267 +};
10268 +
10269 +static struct cpr3_fuse_parameters ipq9574_fuse_params = {
10270 + .apss_ro_sel_param = ipq9574_apss_ro_sel_param,
10271 + .apss_init_voltage_param = ipq9574_apss_init_voltage_param,
10272 + .apss_target_quot_param = ipq9574_apss_target_quot_param,
10273 + .apss_quot_offset_param = ipq9574_apss_quot_offset_param,
10274 + .cpr_fusing_rev_param = ipq9574_cpr_fusing_rev_param,
10275 + .apss_speed_bin_param = ipq9574_apss_speed_bin_param,
10276 + .cpr_boost_fuse_cfg_param = ipq9574_cpr_boost_fuse_cfg_param,
10277 + .apss_boost_fuse_volt_param = ipq9574_apss_boost_fuse_volt_param,
10278 + .misc_fuse_volt_adj_param = ipq9574_misc_fuse_volt_adj_param
10279 +};
10280 +
10281 +/*
10282 + * Open loop voltage fuse reference voltages in microvolts for IPQ9574
10283 + */
10284 +static int ipq9574_apss_fuse_ref_volt
10285 + [IPQ9574_APSS_FUSE_CORNERS] = {
10286 + 725000,
10287 + 862500,
10288 + 987500,
10289 + 1062500,
10290 +};
10291 +
10292 +/**
10293 + * cpr4_ipq807x_apss_read_fuse_data() - load APSS specific fuse parameter values
10294 + * @vreg: Pointer to the CPR3 regulator
10295 + *
10296 + * This function allocates a cpr4_ipq807x_apss_fuses struct, fills it with
10297 + * values read out of hardware fuses, and finally copies common fuse values
10298 + * into the CPR3 regulator struct.
10299 + *
10300 + * Return: 0 on success, errno on failure
10301 + */
10302 +static int cpr4_ipq807x_apss_read_fuse_data(struct cpr3_regulator *vreg)
10303 +{
10304 + void __iomem *base = vreg->thread->ctrl->fuse_base;
10305 + struct cpr4_ipq807x_apss_fuses *fuse;
10306 + int i, rc;
10307 +
10308 + fuse = devm_kzalloc(vreg->thread->ctrl->dev, sizeof(*fuse), GFP_KERNEL);
10309 + if (!fuse)
10310 + return -ENOMEM;
10311 +
10312 + rc = cpr3_read_fuse_param(base, vreg->cpr4_regulator_data->cpr3_fuse_params->apss_speed_bin_param,
10313 + &fuse->speed_bin);
10314 + if (rc) {
10315 + cpr3_err(vreg, "Unable to read speed bin fuse, rc=%d\n", rc);
10316 + return rc;
10317 + }
10318 + cpr3_info(vreg, "speed bin = %llu\n", fuse->speed_bin);
10319 +
10320 + rc = cpr3_read_fuse_param(base, vreg->cpr4_regulator_data->cpr3_fuse_params->cpr_fusing_rev_param,
10321 + &fuse->cpr_fusing_rev);
10322 + if (rc) {
10323 + cpr3_err(vreg, "Unable to read CPR fusing revision fuse, rc=%d\n",
10324 + rc);
10325 + return rc;
10326 + }
10327 + cpr3_info(vreg, "CPR fusing revision = %llu\n", fuse->cpr_fusing_rev);
10328 +
10329 + rc = cpr3_read_fuse_param(base, vreg->cpr4_regulator_data->cpr3_fuse_params->misc_fuse_volt_adj_param,
10330 + &fuse->misc);
10331 + if (rc) {
10332 + cpr3_err(vreg, "Unable to read misc voltage adjustment fuse, rc=%d\n",
10333 + rc);
10334 + return rc;
10335 + }
10336 + cpr3_info(vreg, "CPR misc fuse value = %llu\n", fuse->misc);
10337 + if (fuse->misc >= IPQ807x_MISC_FUSE_VAL_COUNT) {
10338 + cpr3_err(vreg, "CPR misc fuse value = %llu, should be < %lu\n",
10339 + fuse->misc, IPQ807x_MISC_FUSE_VAL_COUNT);
10340 + return -EINVAL;
10341 + }
10342 +
10343 + for (i = 0; i < g_valid_fuse_count; i++) {
10344 + rc = cpr3_read_fuse_param(base,
10345 + vreg->cpr4_regulator_data->cpr3_fuse_params->apss_init_voltage_param[i],
10346 + &fuse->init_voltage[i]);
10347 + if (rc) {
10348 + cpr3_err(vreg, "Unable to read fuse-corner %d initial voltage fuse, rc=%d\n",
10349 + i, rc);
10350 + return rc;
10351 + }
10352 +
10353 + rc = cpr3_read_fuse_param(base,
10354 + vreg->cpr4_regulator_data->cpr3_fuse_params->apss_target_quot_param[i],
10355 + &fuse->target_quot[i]);
10356 + if (rc) {
10357 + cpr3_err(vreg, "Unable to read fuse-corner %d target quotient fuse, rc=%d\n",
10358 + i, rc);
10359 + return rc;
10360 + }
10361 +
10362 + rc = cpr3_read_fuse_param(base,
10363 + vreg->cpr4_regulator_data->cpr3_fuse_params->apss_ro_sel_param[i],
10364 + &fuse->ro_sel[i]);
10365 + if (rc) {
10366 + cpr3_err(vreg, "Unable to read fuse-corner %d RO select fuse, rc=%d\n",
10367 + i, rc);
10368 + return rc;
10369 + }
10370 +
10371 + rc = cpr3_read_fuse_param(base,
10372 + vreg->cpr4_regulator_data->cpr3_fuse_params->apss_quot_offset_param[i],
10373 + &fuse->quot_offset[i]);
10374 + if (rc) {
10375 + cpr3_err(vreg, "Unable to read fuse-corner %d quotient offset fuse, rc=%d\n",
10376 + i, rc);
10377 + return rc;
10378 + }
10379 + }
10380 +
10381 + rc = cpr3_read_fuse_param(base, vreg->cpr4_regulator_data->cpr3_fuse_params->cpr_boost_fuse_cfg_param,
10382 + &fuse->boost_cfg);
10383 + if (rc) {
10384 + cpr3_err(vreg, "Unable to read CPR boost config fuse, rc=%d\n",
10385 + rc);
10386 + return rc;
10387 + }
10388 + cpr3_info(vreg, "Voltage boost fuse config = %llu boost = %s\n",
10389 + fuse->boost_cfg, boost_fuse[fuse->boost_cfg]
10390 + ? "enable" : "disable");
10391 +
10392 + rc = cpr3_read_fuse_param(base,
10393 + vreg->cpr4_regulator_data->cpr3_fuse_params->apss_boost_fuse_volt_param,
10394 + &fuse->boost_voltage);
10395 + if (rc) {
10396 + cpr3_err(vreg, "failed to read boost fuse voltage, rc=%d\n",
10397 + rc);
10398 + return rc;
10399 + }
10400 +
10401 + vreg->fuse_combo = fuse->cpr_fusing_rev + 8 * fuse->speed_bin;
10402 + if (vreg->fuse_combo >= CPR4_IPQ807x_APSS_FUSE_COMBO_COUNT) {
10403 + cpr3_err(vreg, "invalid CPR fuse combo = %d found\n",
10404 + vreg->fuse_combo);
10405 + return -EINVAL;
10406 + }
10407 +
10408 + vreg->speed_bin_fuse = fuse->speed_bin;
10409 + vreg->cpr_rev_fuse = fuse->cpr_fusing_rev;
10410 + vreg->fuse_corner_count = g_valid_fuse_count;
10411 + vreg->platform_fuses = fuse;
10412 +
10413 + return 0;
10414 +}
10415 +
10416 +/**
10417 + * cpr4_apss_parse_corner_data() - parse APSS corner data from device tree
10418 + * properties of the CPR3 regulator's device node
10419 + * @vreg: Pointer to the CPR3 regulator
10420 + *
10421 + * Return: 0 on success, errno on failure
10422 + */
10423 +static int cpr4_apss_parse_corner_data(struct cpr3_regulator *vreg)
10424 +{
10425 + struct device_node *node = vreg->of_node;
10426 + struct cpr4_ipq807x_apss_fuses *fuse = vreg->platform_fuses;
10427 + u32 *temp = NULL;
10428 + int i, rc;
10429 +
10430 + rc = cpr3_parse_common_corner_data(vreg);
10431 + if (rc) {
10432 + cpr3_err(vreg, "error reading corner data, rc=%d\n", rc);
10433 + return rc;
10434 + }
10435 +
10436 + /* If fuse has incorrect RO Select values and dtsi has "qcom,cpr-ro-sel"
10437 + * entry with RO select values other than zero, then dtsi values will
10438 + * be used.
10439 + */
10440 + if (of_find_property(node, "qcom,cpr-ro-sel", NULL)) {
10441 + temp = kcalloc(vreg->fuse_corner_count, sizeof(*temp),
10442 + GFP_KERNEL);
10443 + if (!temp)
10444 + return -ENOMEM;
10445 +
10446 + rc = cpr3_parse_array_property(vreg, "qcom,cpr-ro-sel",
10447 + vreg->fuse_corner_count, temp);
10448 + if (rc)
10449 + goto done;
10450 +
10451 + for (i = 0; i < vreg->fuse_corner_count; i++) {
10452 + if (temp[i] != 0)
10453 + fuse->ro_sel[i] = temp[i];
10454 + }
10455 + }
10456 +done:
10457 + kfree(temp);
10458 + return rc;
10459 +}
10460 +
10461 +/**
10462 + * cpr4_apss_parse_misc_fuse_voltage_adjustments() - fill an array from a
10463 + * portion of the voltage adjustments specified based on
10464 + * miscellaneous fuse bits.
10465 + * @vreg: Pointer to the CPR3 regulator
10466 + * @volt_adjust: Voltage adjustment output data array which must be
10467 + * of size vreg->corner_count
10468 + *
10469 + * cpr3_parse_common_corner_data() must be called for vreg before this function
10470 + * is called so that speed bin size elements are initialized.
10471 + *
10472 + * Two formats are supported for the device tree property:
10473 + * 1. Length == tuple_list_size * vreg->corner_count
10474 + * (reading begins at index 0)
10475 + * 2. Length == tuple_list_size * vreg->speed_bin_corner_sum
10476 + * (reading begins at index tuple_list_size * vreg->speed_bin_offset)
10477 + *
10478 + * Here, tuple_list_size is the number of possible values for misc fuse.
10479 + * All other property lengths are treated as errors.
10480 + *
10481 + * Return: 0 on success, errno on failure
10482 + */
10483 +static int cpr4_apss_parse_misc_fuse_voltage_adjustments(
10484 + struct cpr3_regulator *vreg, u32 *volt_adjust)
10485 +{
10486 + struct device_node *node = vreg->of_node;
10487 + struct cpr4_ipq807x_apss_fuses *fuse = vreg->platform_fuses;
10488 + int tuple_list_size = IPQ807x_MISC_FUSE_VAL_COUNT;
10489 + int i, offset, rc, len = 0;
10490 + const char *prop_name = "qcom,cpr-misc-fuse-voltage-adjustment";
10491 +
10492 + if (!of_find_property(node, prop_name, &len)) {
10493 + cpr3_err(vreg, "property %s is missing\n", prop_name);
10494 + return -EINVAL;
10495 + }
10496 +
10497 + if (len == tuple_list_size * vreg->corner_count * sizeof(u32)) {
10498 + offset = 0;
10499 + } else if (vreg->speed_bin_corner_sum > 0 &&
10500 + len == tuple_list_size * vreg->speed_bin_corner_sum
10501 + * sizeof(u32)) {
10502 + offset = tuple_list_size * vreg->speed_bin_offset
10503 + + fuse->misc * vreg->corner_count;
10504 + } else {
10505 + if (vreg->speed_bin_corner_sum > 0)
10506 + cpr3_err(vreg, "property %s has invalid length=%d, should be %zu or %zu\n",
10507 + prop_name, len,
10508 + tuple_list_size * vreg->corner_count
10509 + * sizeof(u32),
10510 + tuple_list_size * vreg->speed_bin_corner_sum
10511 + * sizeof(u32));
10512 + else
10513 + cpr3_err(vreg, "property %s has invalid length=%d, should be %zu\n",
10514 + prop_name, len,
10515 + tuple_list_size * vreg->corner_count
10516 + * sizeof(u32));
10517 + return -EINVAL;
10518 + }
10519 +
10520 + for (i = 0; i < vreg->corner_count; i++) {
10521 + rc = of_property_read_u32_index(node, prop_name, offset + i,
10522 + &volt_adjust[i]);
10523 + if (rc) {
10524 + cpr3_err(vreg, "error reading property %s, rc=%d\n",
10525 + prop_name, rc);
10526 + return rc;
10527 + }
10528 + }
10529 +
10530 + return 0;
10531 +}
10532 +
10533 +/**
10534 + * cpr4_ipq807x_apss_calculate_open_loop_voltages() - calculate the open-loop
10535 + * voltage for each corner of a CPR3 regulator
10536 + * @vreg: Pointer to the CPR3 regulator
10537 + *
10538 + * If open-loop voltage interpolation is allowed in device tree, then
10539 + * this function calculates the open-loop voltage for a given corner using
10540 + * linear interpolation. This interpolation is performed using the processor
10541 + * frequencies of the lower and higher Fmax corners along with their fused
10542 + * open-loop voltages.
10543 + *
10544 + * If open-loop voltage interpolation is not allowed, then this function uses
10545 + * the Fmax fused open-loop voltage for all of the corners associated with a
10546 + * given fuse corner.
10547 + *
10548 + * Return: 0 on success, errno on failure
10549 + */
10550 +static int cpr4_ipq807x_apss_calculate_open_loop_voltages(
10551 + struct cpr3_regulator *vreg)
10552 +{
10553 + struct device_node *node = vreg->of_node;
10554 + struct cpr4_ipq807x_apss_fuses *fuse = vreg->platform_fuses;
10555 + struct cpr3_controller *ctrl = vreg->thread->ctrl;
10556 + int i, j, rc = 0;
10557 + bool allow_interpolation;
10558 + u64 freq_low, volt_low, freq_high, volt_high;
10559 + int *fuse_volt, *misc_adj_volt;
10560 + int *fmax_corner;
10561 +
10562 + fuse_volt = kcalloc(vreg->fuse_corner_count, sizeof(*fuse_volt),
10563 + GFP_KERNEL);
10564 + fmax_corner = kcalloc(vreg->fuse_corner_count, sizeof(*fmax_corner),
10565 + GFP_KERNEL);
10566 + if (!fuse_volt || !fmax_corner) {
10567 + rc = -ENOMEM;
10568 + goto done;
10569 + }
10570 +
10571 + for (i = 0; i < vreg->fuse_corner_count; i++) {
10572 + if (ctrl->cpr_global_setting == CPR_DISABLED)
10573 + fuse_volt[i] = vreg->cpr4_regulator_data->fuse_ref_volt[i];
10574 + else
10575 + fuse_volt[i] = cpr3_convert_open_loop_voltage_fuse(
10576 + vreg->cpr4_regulator_data->fuse_ref_volt[i],
10577 + vreg->cpr4_regulator_data->fuse_step_volt,
10578 + fuse->init_voltage[i],
10579 + IPQ807x_APSS_VOLTAGE_FUSE_SIZE);
10580 +
10581 + /* Log fused open-loop voltage values for debugging purposes. */
10582 + cpr3_info(vreg, "fused %8s: open-loop=%7d uV\n",
10583 + cpr4_ipq807x_apss_fuse_corner_name[i],
10584 + fuse_volt[i]);
10585 + }
10586 +
10587 + rc = cpr3_determine_part_type(vreg,
10588 + fuse_volt[vreg->fuse_corner_count - 1]);
10589 + if (rc) {
10590 + cpr3_err(vreg, "fused part type detection failed failed, rc=%d\n",
10591 + rc);
10592 + goto done;
10593 + }
10594 +
10595 + rc = cpr3_adjust_fused_open_loop_voltages(vreg, fuse_volt);
10596 + if (rc) {
10597 + cpr3_err(vreg, "fused open-loop voltage adjustment failed, rc=%d\n",
10598 + rc);
10599 + goto done;
10600 + }
10601 +
10602 + allow_interpolation = of_property_read_bool(node,
10603 + "qcom,allow-voltage-interpolation");
10604 +
10605 + for (i = 1; i < vreg->fuse_corner_count; i++) {
10606 + if (fuse_volt[i] < fuse_volt[i - 1]) {
10607 + cpr3_info(vreg, "fuse corner %d voltage=%d uV < fuse corner %d voltage=%d uV; overriding: fuse corner %d voltage=%d\n",
10608 + i, fuse_volt[i], i - 1, fuse_volt[i - 1],
10609 + i, fuse_volt[i - 1]);
10610 + fuse_volt[i] = fuse_volt[i - 1];
10611 + }
10612 + }
10613 +
10614 + if (!allow_interpolation) {
10615 + /* Use fused open-loop voltage for lower frequencies. */
10616 + for (i = 0; i < vreg->corner_count; i++)
10617 + vreg->corner[i].open_loop_volt
10618 + = fuse_volt[vreg->corner[i].cpr_fuse_corner];
10619 + goto done;
10620 + }
10621 +
10622 + /* Determine highest corner mapped to each fuse corner */
10623 + j = vreg->fuse_corner_count - 1;
10624 + for (i = vreg->corner_count - 1; i >= 0; i--) {
10625 + if (vreg->corner[i].cpr_fuse_corner == j) {
10626 + fmax_corner[j] = i;
10627 + j--;
10628 + }
10629 + }
10630 + if (j >= 0) {
10631 + cpr3_err(vreg, "invalid fuse corner mapping\n");
10632 + rc = -EINVAL;
10633 + goto done;
10634 + }
10635 +
10636 + /*
10637 + * Interpolation is not possible for corners mapped to the lowest fuse
10638 + * corner so use the fuse corner value directly.
10639 + */
10640 + for (i = 0; i <= fmax_corner[0]; i++)
10641 + vreg->corner[i].open_loop_volt = fuse_volt[0];
10642 +
10643 + /* Interpolate voltages for the higher fuse corners. */
10644 + for (i = 1; i < vreg->fuse_corner_count; i++) {
10645 + freq_low = vreg->corner[fmax_corner[i - 1]].proc_freq;
10646 + volt_low = fuse_volt[i - 1];
10647 + freq_high = vreg->corner[fmax_corner[i]].proc_freq;
10648 + volt_high = fuse_volt[i];
10649 +
10650 + for (j = fmax_corner[i - 1] + 1; j <= fmax_corner[i]; j++)
10651 + vreg->corner[j].open_loop_volt = cpr3_interpolate(
10652 + freq_low, volt_low, freq_high, volt_high,
10653 + vreg->corner[j].proc_freq);
10654 + }
10655 +
10656 +done:
10657 + if (rc == 0) {
10658 + cpr3_debug(vreg, "unadjusted per-corner open-loop voltages:\n");
10659 + for (i = 0; i < vreg->corner_count; i++)
10660 + cpr3_debug(vreg, "open-loop[%2d] = %d uV\n", i,
10661 + vreg->corner[i].open_loop_volt);
10662 +
10663 + rc = cpr3_adjust_open_loop_voltages(vreg);
10664 + if (rc)
10665 + cpr3_err(vreg, "open-loop voltage adjustment failed, rc=%d\n",
10666 + rc);
10667 +
10668 + if (of_find_property(node,
10669 + "qcom,cpr-misc-fuse-voltage-adjustment",
10670 + NULL)) {
10671 + misc_adj_volt = kcalloc(vreg->corner_count,
10672 + sizeof(*misc_adj_volt), GFP_KERNEL);
10673 + if (!misc_adj_volt) {
10674 + rc = -ENOMEM;
10675 + goto _exit;
10676 + }
10677 +
10678 + rc = cpr4_apss_parse_misc_fuse_voltage_adjustments(vreg,
10679 + misc_adj_volt);
10680 + if (rc) {
10681 + cpr3_err(vreg, "qcom,cpr-misc-fuse-voltage-adjustment reading failed, rc=%d\n",
10682 + rc);
10683 + kfree(misc_adj_volt);
10684 + goto _exit;
10685 + }
10686 +
10687 + for (i = 0; i < vreg->corner_count; i++)
10688 + vreg->corner[i].open_loop_volt
10689 + += misc_adj_volt[i];
10690 + kfree(misc_adj_volt);
10691 + }
10692 + }
10693 +
10694 +_exit:
10695 + kfree(fuse_volt);
10696 + kfree(fmax_corner);
10697 + return rc;
10698 +}
10699 +
10700 +/**
10701 + * cpr4_ipq807x_apss_set_no_interpolation_quotients() - use the fused target
10702 + * quotient values for lower frequencies.
10703 + * @vreg: Pointer to the CPR3 regulator
10704 + * @volt_adjust: Pointer to array of per-corner closed-loop adjustment
10705 + * voltages
10706 + * @volt_adjust_fuse: Pointer to array of per-fuse-corner closed-loop
10707 + * adjustment voltages
10708 + * @ro_scale: Pointer to array of per-fuse-corner RO scaling factor
10709 + * values with units of QUOT/V
10710 + *
10711 + * Return: 0 on success, errno on failure
10712 + */
10713 +static int cpr4_ipq807x_apss_set_no_interpolation_quotients(
10714 + struct cpr3_regulator *vreg, int *volt_adjust,
10715 + int *volt_adjust_fuse, int *ro_scale)
10716 +{
10717 + struct cpr4_ipq807x_apss_fuses *fuse = vreg->platform_fuses;
10718 + u32 quot, ro;
10719 + int quot_adjust;
10720 + int i, fuse_corner;
10721 +
10722 + for (i = 0; i < vreg->corner_count; i++) {
10723 + fuse_corner = vreg->corner[i].cpr_fuse_corner;
10724 + quot = fuse->target_quot[fuse_corner];
10725 + quot_adjust = cpr3_quot_adjustment(ro_scale[fuse_corner],
10726 + volt_adjust_fuse[fuse_corner] +
10727 + volt_adjust[i]);
10728 + ro = fuse->ro_sel[fuse_corner];
10729 + vreg->corner[i].target_quot[ro] = quot + quot_adjust;
10730 + cpr3_debug(vreg, "corner=%d RO=%u target quot=%u\n",
10731 + i, ro, quot);
10732 +
10733 + if (quot_adjust)
10734 + cpr3_debug(vreg, "adjusted corner %d RO%u target quot: %u --> %u (%d uV)\n",
10735 + i, ro, quot, vreg->corner[i].target_quot[ro],
10736 + volt_adjust_fuse[fuse_corner] +
10737 + volt_adjust[i]);
10738 + }
10739 +
10740 + return 0;
10741 +}
10742 +
10743 +/**
10744 + * cpr4_ipq807x_apss_calculate_target_quotients() - calculate the CPR target
10745 + * quotient for each corner of a CPR3 regulator
10746 + * @vreg: Pointer to the CPR3 regulator
10747 + *
10748 + * If target quotient interpolation is allowed in device tree, then this
10749 + * function calculates the target quotient for a given corner using linear
10750 + * interpolation. This interpolation is performed using the processor
10751 + * frequencies of the lower and higher Fmax corners along with the fused
10752 + * target quotient and quotient offset of the higher Fmax corner.
10753 + *
10754 + * If target quotient interpolation is not allowed, then this function uses
10755 + * the Fmax fused target quotient for all of the corners associated with a
10756 + * given fuse corner.
10757 + *
10758 + * Return: 0 on success, errno on failure
10759 + */
10760 +static int cpr4_ipq807x_apss_calculate_target_quotients(
10761 + struct cpr3_regulator *vreg)
10762 +{
10763 + struct cpr4_ipq807x_apss_fuses *fuse = vreg->platform_fuses;
10764 + int rc;
10765 + bool allow_interpolation;
10766 + u64 freq_low, freq_high, prev_quot;
10767 + u64 *quot_low;
10768 + u64 *quot_high;
10769 + u32 quot, ro;
10770 + int i, j, fuse_corner, quot_adjust;
10771 + int *fmax_corner;
10772 + int *volt_adjust, *volt_adjust_fuse, *ro_scale;
10773 + int *voltage_adj_misc;
10774 +
10775 + /* Log fused quotient values for debugging purposes. */
10776 + for (i = CPR4_IPQ807x_APSS_FUSE_CORNER_SVS;
10777 + i < vreg->fuse_corner_count; i++)
10778 + cpr3_info(vreg, "fused %8s: quot[%2llu]=%4llu, quot_offset[%2llu]=%4llu\n",
10779 + cpr4_ipq807x_apss_fuse_corner_name[i],
10780 + fuse->ro_sel[i], fuse->target_quot[i],
10781 + fuse->ro_sel[i], fuse->quot_offset[i] *
10782 + IPQ807x_APSS_QUOT_OFFSET_SCALE);
10783 +
10784 + allow_interpolation = of_property_read_bool(vreg->of_node,
10785 + "qcom,allow-quotient-interpolation");
10786 +
10787 + volt_adjust = kcalloc(vreg->corner_count, sizeof(*volt_adjust),
10788 + GFP_KERNEL);
10789 + volt_adjust_fuse = kcalloc(vreg->fuse_corner_count,
10790 + sizeof(*volt_adjust_fuse), GFP_KERNEL);
10791 + ro_scale = kcalloc(vreg->fuse_corner_count, sizeof(*ro_scale),
10792 + GFP_KERNEL);
10793 + fmax_corner = kcalloc(vreg->fuse_corner_count, sizeof(*fmax_corner),
10794 + GFP_KERNEL);
10795 + quot_low = kcalloc(vreg->fuse_corner_count, sizeof(*quot_low),
10796 + GFP_KERNEL);
10797 + quot_high = kcalloc(vreg->fuse_corner_count, sizeof(*quot_high),
10798 + GFP_KERNEL);
10799 + if (!volt_adjust || !volt_adjust_fuse || !ro_scale ||
10800 + !fmax_corner || !quot_low || !quot_high) {
10801 + rc = -ENOMEM;
10802 + goto done;
10803 + }
10804 +
10805 + rc = cpr3_parse_closed_loop_voltage_adjustments(vreg, &fuse->ro_sel[0],
10806 + volt_adjust, volt_adjust_fuse, ro_scale);
10807 + if (rc) {
10808 + cpr3_err(vreg, "could not load closed-loop voltage adjustments, rc=%d\n",
10809 + rc);
10810 + goto done;
10811 + }
10812 +
10813 + if (of_find_property(vreg->of_node,
10814 + "qcom,cpr-misc-fuse-voltage-adjustment", NULL)) {
10815 + voltage_adj_misc = kcalloc(vreg->corner_count,
10816 + sizeof(*voltage_adj_misc), GFP_KERNEL);
10817 + if (!voltage_adj_misc) {
10818 + rc = -ENOMEM;
10819 + goto done;
10820 + }
10821 +
10822 + rc = cpr4_apss_parse_misc_fuse_voltage_adjustments(vreg,
10823 + voltage_adj_misc);
10824 + if (rc) {
10825 + cpr3_err(vreg, "qcom,cpr-misc-fuse-voltage-adjustment reading failed, rc=%d\n",
10826 + rc);
10827 + kfree(voltage_adj_misc);
10828 + goto done;
10829 + }
10830 +
10831 + for (i = 0; i < vreg->corner_count; i++)
10832 + volt_adjust[i] += voltage_adj_misc[i];
10833 +
10834 + kfree(voltage_adj_misc);
10835 + }
10836 +
10837 + if (!allow_interpolation) {
10838 + /* Use fused target quotients for lower frequencies. */
10839 + return cpr4_ipq807x_apss_set_no_interpolation_quotients(
10840 + vreg, volt_adjust, volt_adjust_fuse, ro_scale);
10841 + }
10842 +
10843 + /* Determine highest corner mapped to each fuse corner */
10844 + j = vreg->fuse_corner_count - 1;
10845 + for (i = vreg->corner_count - 1; i >= 0; i--) {
10846 + if (vreg->corner[i].cpr_fuse_corner == j) {
10847 + fmax_corner[j] = i;
10848 + j--;
10849 + }
10850 + }
10851 + if (j >= 0) {
10852 + cpr3_err(vreg, "invalid fuse corner mapping\n");
10853 + rc = -EINVAL;
10854 + goto done;
10855 + }
10856 +
10857 + /*
10858 + * Interpolation is not possible for corners mapped to the lowest fuse
10859 + * corner so use the fuse corner value directly.
10860 + */
10861 + i = CPR4_IPQ807x_APSS_FUSE_CORNER_SVS;
10862 + quot_adjust = cpr3_quot_adjustment(ro_scale[i], volt_adjust_fuse[i]);
10863 + quot = fuse->target_quot[i] + quot_adjust;
10864 + quot_high[i] = quot_low[i] = quot;
10865 + ro = fuse->ro_sel[i];
10866 + if (quot_adjust)
10867 + cpr3_debug(vreg, "adjusted fuse corner %d RO%u target quot: %llu --> %u (%d uV)\n",
10868 + i, ro, fuse->target_quot[i], quot, volt_adjust_fuse[i]);
10869 +
10870 + for (i = 0; i <= fmax_corner[CPR4_IPQ807x_APSS_FUSE_CORNER_SVS];
10871 + i++)
10872 + vreg->corner[i].target_quot[ro] = quot;
10873 +
10874 + for (i = CPR4_IPQ807x_APSS_FUSE_CORNER_NOM;
10875 + i < vreg->fuse_corner_count; i++) {
10876 + quot_high[i] = fuse->target_quot[i];
10877 + if (fuse->ro_sel[i] == fuse->ro_sel[i - 1])
10878 + quot_low[i] = quot_high[i - 1];
10879 + else
10880 + quot_low[i] = quot_high[i]
10881 + - fuse->quot_offset[i]
10882 + * IPQ807x_APSS_QUOT_OFFSET_SCALE;
10883 + if (quot_high[i] < quot_low[i]) {
10884 + cpr3_debug(vreg, "quot_high[%d]=%llu < quot_low[%d]=%llu; overriding: quot_high[%d]=%llu\n",
10885 + i, quot_high[i], i, quot_low[i],
10886 + i, quot_low[i]);
10887 + quot_high[i] = quot_low[i];
10888 + }
10889 + }
10890 +
10891 + /* Perform per-fuse-corner target quotient adjustment */
10892 + for (i = 1; i < vreg->fuse_corner_count; i++) {
10893 + quot_adjust = cpr3_quot_adjustment(ro_scale[i],
10894 + volt_adjust_fuse[i]);
10895 + if (quot_adjust) {
10896 + prev_quot = quot_high[i];
10897 + quot_high[i] += quot_adjust;
10898 + cpr3_debug(vreg, "adjusted fuse corner %d RO%llu target quot: %llu --> %llu (%d uV)\n",
10899 + i, fuse->ro_sel[i], prev_quot, quot_high[i],
10900 + volt_adjust_fuse[i]);
10901 + }
10902 +
10903 + if (fuse->ro_sel[i] == fuse->ro_sel[i - 1])
10904 + quot_low[i] = quot_high[i - 1];
10905 + else
10906 + quot_low[i] += cpr3_quot_adjustment(ro_scale[i],
10907 + volt_adjust_fuse[i - 1]);
10908 +
10909 + if (quot_high[i] < quot_low[i]) {
10910 + cpr3_debug(vreg, "quot_high[%d]=%llu < quot_low[%d]=%llu after adjustment; overriding: quot_high[%d]=%llu\n",
10911 + i, quot_high[i], i, quot_low[i],
10912 + i, quot_low[i]);
10913 + quot_high[i] = quot_low[i];
10914 + }
10915 + }
10916 +
10917 + /* Interpolate voltages for the higher fuse corners. */
10918 + for (i = 1; i < vreg->fuse_corner_count; i++) {
10919 + freq_low = vreg->corner[fmax_corner[i - 1]].proc_freq;
10920 + freq_high = vreg->corner[fmax_corner[i]].proc_freq;
10921 +
10922 + ro = fuse->ro_sel[i];
10923 + for (j = fmax_corner[i - 1] + 1; j <= fmax_corner[i]; j++)
10924 + vreg->corner[j].target_quot[ro] = cpr3_interpolate(
10925 + freq_low, quot_low[i], freq_high, quot_high[i],
10926 + vreg->corner[j].proc_freq);
10927 + }
10928 +
10929 + /* Perform per-corner target quotient adjustment */
10930 + for (i = 0; i < vreg->corner_count; i++) {
10931 + fuse_corner = vreg->corner[i].cpr_fuse_corner;
10932 + ro = fuse->ro_sel[fuse_corner];
10933 + quot_adjust = cpr3_quot_adjustment(ro_scale[fuse_corner],
10934 + volt_adjust[i]);
10935 + if (quot_adjust) {
10936 + prev_quot = vreg->corner[i].target_quot[ro];
10937 + vreg->corner[i].target_quot[ro] += quot_adjust;
10938 + cpr3_debug(vreg, "adjusted corner %d RO%u target quot: %llu --> %u (%d uV)\n",
10939 + i, ro, prev_quot,
10940 + vreg->corner[i].target_quot[ro],
10941 + volt_adjust[i]);
10942 + }
10943 + }
10944 +
10945 + /* Ensure that target quotients increase monotonically */
10946 + for (i = 1; i < vreg->corner_count; i++) {
10947 + ro = fuse->ro_sel[vreg->corner[i].cpr_fuse_corner];
10948 + if (fuse->ro_sel[vreg->corner[i - 1].cpr_fuse_corner] == ro
10949 + && vreg->corner[i].target_quot[ro]
10950 + < vreg->corner[i - 1].target_quot[ro]) {
10951 + 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",
10952 + i, ro, vreg->corner[i].target_quot[ro],
10953 + i - 1, ro, vreg->corner[i - 1].target_quot[ro],
10954 + i, ro, vreg->corner[i - 1].target_quot[ro]);
10955 + vreg->corner[i].target_quot[ro]
10956 + = vreg->corner[i - 1].target_quot[ro];
10957 + }
10958 + }
10959 +
10960 +done:
10961 + kfree(volt_adjust);
10962 + kfree(volt_adjust_fuse);
10963 + kfree(ro_scale);
10964 + kfree(fmax_corner);
10965 + kfree(quot_low);
10966 + kfree(quot_high);
10967 + return rc;
10968 +}
10969 +
10970 +/**
10971 + * cpr4_apss_print_settings() - print out APSS CPR configuration settings into
10972 + * the kernel log for debugging purposes
10973 + * @vreg: Pointer to the CPR3 regulator
10974 + */
10975 +static void cpr4_apss_print_settings(struct cpr3_regulator *vreg)
10976 +{
10977 + struct cpr3_corner *corner;
10978 + int i;
10979 +
10980 + cpr3_debug(vreg, "Corner: Frequency (Hz), Fuse Corner, Floor (uV), Open-Loop (uV), Ceiling (uV)\n");
10981 + for (i = 0; i < vreg->corner_count; i++) {
10982 + corner = &vreg->corner[i];
10983 + cpr3_debug(vreg, "%3d: %10u, %2d, %7d, %7d, %7d\n",
10984 + i, corner->proc_freq, corner->cpr_fuse_corner,
10985 + corner->floor_volt, corner->open_loop_volt,
10986 + corner->ceiling_volt);
10987 + }
10988 +
10989 + if (vreg->thread->ctrl->apm)
10990 + cpr3_debug(vreg, "APM threshold = %d uV, APM adjust = %d uV\n",
10991 + vreg->thread->ctrl->apm_threshold_volt,
10992 + vreg->thread->ctrl->apm_adj_volt);
10993 +}
10994 +
10995 +/**
10996 + * cpr4_apss_init_thread() - perform steps necessary to initialize the
10997 + * configuration data for a CPR3 thread
10998 + * @thread: Pointer to the CPR3 thread
10999 + *
11000 + * Return: 0 on success, errno on failure
11001 + */
11002 +static int cpr4_apss_init_thread(struct cpr3_thread *thread)
11003 +{
11004 + int rc;
11005 +
11006 + rc = cpr3_parse_common_thread_data(thread);
11007 + if (rc) {
11008 + cpr3_err(thread->ctrl, "thread %u unable to read CPR thread data from device tree, rc=%d\n",
11009 + thread->thread_id, rc);
11010 + return rc;
11011 + }
11012 +
11013 + return 0;
11014 +}
11015 +
11016 +/**
11017 + * cpr4_apss_parse_temp_adj_properties() - parse temperature based
11018 + * adjustment properties from device tree.
11019 + * @ctrl: Pointer to the CPR3 controller
11020 + *
11021 + * Return: 0 on success, errno on failure
11022 + */
11023 +static int cpr4_apss_parse_temp_adj_properties(struct cpr3_controller *ctrl)
11024 +{
11025 + struct device_node *of_node = ctrl->dev->of_node;
11026 + int rc, i, len, temp_point_count;
11027 +
11028 + if (!of_find_property(of_node, "qcom,cpr-temp-point-map", &len)) {
11029 + /*
11030 + * Temperature based adjustments are not defined. Single
11031 + * temperature band is still valid for per-online-core
11032 + * adjustments.
11033 + */
11034 + ctrl->temp_band_count = 1;
11035 + return 0;
11036 + }
11037 +
11038 + temp_point_count = len / sizeof(u32);
11039 + if (temp_point_count <= 0 ||
11040 + temp_point_count > IPQ807x_APSS_MAX_TEMP_POINTS) {
11041 + cpr3_err(ctrl, "invalid number of temperature points %d > %d (max)\n",
11042 + temp_point_count, IPQ807x_APSS_MAX_TEMP_POINTS);
11043 + return -EINVAL;
11044 + }
11045 +
11046 + ctrl->temp_points = devm_kcalloc(ctrl->dev, temp_point_count,
11047 + sizeof(*ctrl->temp_points), GFP_KERNEL);
11048 + if (!ctrl->temp_points)
11049 + return -ENOMEM;
11050 +
11051 + rc = of_property_read_u32_array(of_node, "qcom,cpr-temp-point-map",
11052 + ctrl->temp_points, temp_point_count);
11053 + if (rc) {
11054 + cpr3_err(ctrl, "error reading property qcom,cpr-temp-point-map, rc=%d\n",
11055 + rc);
11056 + return rc;
11057 + }
11058 +
11059 + for (i = 0; i < temp_point_count; i++)
11060 + cpr3_debug(ctrl, "Temperature Point %d=%d\n", i,
11061 + ctrl->temp_points[i]);
11062 +
11063 + /*
11064 + * If t1, t2, and t3 are the temperature points, then the temperature
11065 + * bands are: (-inf, t1], (t1, t2], (t2, t3], and (t3, inf).
11066 + */
11067 + ctrl->temp_band_count = temp_point_count + 1;
11068 + cpr3_debug(ctrl, "Number of temp bands =%d\n", ctrl->temp_band_count);
11069 +
11070 + rc = of_property_read_u32(of_node, "qcom,cpr-initial-temp-band",
11071 + &ctrl->initial_temp_band);
11072 + if (rc) {
11073 + cpr3_err(ctrl, "error reading qcom,cpr-initial-temp-band, rc=%d\n",
11074 + rc);
11075 + return rc;
11076 + }
11077 +
11078 + if (ctrl->initial_temp_band >= ctrl->temp_band_count) {
11079 + cpr3_err(ctrl, "Initial temperature band value %d should be in range [0 - %d]\n",
11080 + ctrl->initial_temp_band, ctrl->temp_band_count - 1);
11081 + return -EINVAL;
11082 + }
11083 +
11084 + ctrl->temp_sensor_id_start = IPQ807x_APSS_TEMP_SENSOR_ID_START;
11085 + ctrl->temp_sensor_id_end = IPQ807x_APSS_TEMP_SENSOR_ID_END;
11086 + ctrl->allow_temp_adj = true;
11087 + return rc;
11088 +}
11089 +
11090 +/**
11091 + * cpr4_apss_parse_boost_properties() - parse configuration data for boost
11092 + * voltage adjustment for CPR3 regulator from device tree.
11093 + * @vreg: Pointer to the CPR3 regulator
11094 + *
11095 + * Return: 0 on success, errno on failure
11096 + */
11097 +static int cpr4_apss_parse_boost_properties(struct cpr3_regulator *vreg)
11098 +{
11099 + struct cpr3_controller *ctrl = vreg->thread->ctrl;
11100 + struct cpr4_ipq807x_apss_fuses *fuse = vreg->platform_fuses;
11101 + struct cpr3_corner *corner;
11102 + int i, boost_voltage, final_boost_volt, rc = 0;
11103 + int *boost_table = NULL, *boost_temp_adj = NULL;
11104 + int boost_voltage_adjust = 0, boost_num_cores = 0;
11105 + u32 boost_allowed = 0;
11106 +
11107 + if (!boost_fuse[fuse->boost_cfg])
11108 + /* Voltage boost is disabled in fuse */
11109 + return 0;
11110 +
11111 + if (of_find_property(vreg->of_node, "qcom,allow-boost", NULL)) {
11112 + rc = cpr3_parse_array_property(vreg, "qcom,allow-boost", 1,
11113 + &boost_allowed);
11114 + if (rc)
11115 + return rc;
11116 + }
11117 +
11118 + if (!boost_allowed) {
11119 + /* Voltage boost is not enabled for this regulator */
11120 + return 0;
11121 + }
11122 +
11123 + boost_voltage = cpr3_convert_open_loop_voltage_fuse(
11124 + vreg->cpr4_regulator_data->boost_fuse_ref_volt,
11125 + vreg->cpr4_regulator_data->fuse_step_volt,
11126 + fuse->boost_voltage,
11127 + IPQ807x_APSS_VOLTAGE_FUSE_SIZE);
11128 +
11129 + /* Log boost voltage value for debugging purposes. */
11130 + cpr3_info(vreg, "Boost open-loop=%7d uV\n", boost_voltage);
11131 +
11132 + if (of_find_property(vreg->of_node,
11133 + "qcom,cpr-boost-voltage-fuse-adjustment", NULL)) {
11134 + rc = cpr3_parse_array_property(vreg,
11135 + "qcom,cpr-boost-voltage-fuse-adjustment",
11136 + 1, &boost_voltage_adjust);
11137 + if (rc) {
11138 + cpr3_err(vreg, "qcom,cpr-boost-voltage-fuse-adjustment reading failed, rc=%d\n",
11139 + rc);
11140 + return rc;
11141 + }
11142 +
11143 + boost_voltage += boost_voltage_adjust;
11144 + /* Log boost voltage value for debugging purposes. */
11145 + cpr3_info(vreg, "Adjusted boost open-loop=%7d uV\n",
11146 + boost_voltage);
11147 + }
11148 +
11149 + /* Limit boost voltage value between ceiling and floor voltage limits */
11150 + boost_voltage = min(boost_voltage, vreg->cpr4_regulator_data->boost_ceiling_volt);
11151 + boost_voltage = max(boost_voltage, vreg->cpr4_regulator_data->boost_floor_volt);
11152 +
11153 + /*
11154 + * The boost feature can only be used for the highest voltage corner.
11155 + * Also, keep core-count adjustments disabled when the boost feature
11156 + * is enabled.
11157 + */
11158 + corner = &vreg->corner[vreg->corner_count - 1];
11159 + if (!corner->sdelta) {
11160 + /*
11161 + * If core-count/temp adjustments are not defined, the cpr4
11162 + * sdelta for this corner will not be allocated. Allocate it
11163 + * here for boost configuration.
11164 + */
11165 + corner->sdelta = devm_kzalloc(ctrl->dev,
11166 + sizeof(*corner->sdelta), GFP_KERNEL);
11167 + if (!corner->sdelta)
11168 + return -ENOMEM;
11169 + }
11170 + corner->sdelta->temp_band_count = ctrl->temp_band_count;
11171 +
11172 + rc = of_property_read_u32(vreg->of_node, "qcom,cpr-num-boost-cores",
11173 + &boost_num_cores);
11174 + if (rc) {
11175 + cpr3_err(vreg, "qcom,cpr-num-boost-cores reading failed, rc=%d\n",
11176 + rc);
11177 + return rc;
11178 + }
11179 +
11180 + if (boost_num_cores <= 0 ||
11181 + boost_num_cores > IPQ807x_APSS_CPR_SDELTA_CORE_COUNT) {
11182 + cpr3_err(vreg, "Invalid boost number of cores = %d\n",
11183 + boost_num_cores);
11184 + return -EINVAL;
11185 + }
11186 + corner->sdelta->boost_num_cores = boost_num_cores;
11187 +
11188 + boost_table = devm_kcalloc(ctrl->dev, corner->sdelta->temp_band_count,
11189 + sizeof(*boost_table), GFP_KERNEL);
11190 + if (!boost_table)
11191 + return -ENOMEM;
11192 +
11193 + if (of_find_property(vreg->of_node,
11194 + "qcom,cpr-boost-temp-adjustment", NULL)) {
11195 + boost_temp_adj = kcalloc(corner->sdelta->temp_band_count,
11196 + sizeof(*boost_temp_adj), GFP_KERNEL);
11197 + if (!boost_temp_adj)
11198 + return -ENOMEM;
11199 +
11200 + rc = cpr3_parse_array_property(vreg,
11201 + "qcom,cpr-boost-temp-adjustment",
11202 + corner->sdelta->temp_band_count,
11203 + boost_temp_adj);
11204 + if (rc) {
11205 + cpr3_err(vreg, "qcom,cpr-boost-temp-adjustment reading failed, rc=%d\n",
11206 + rc);
11207 + goto done;
11208 + }
11209 + }
11210 +
11211 + for (i = 0; i < corner->sdelta->temp_band_count; i++) {
11212 + /* Apply static adjustments to boost voltage */
11213 + final_boost_volt = boost_voltage + (boost_temp_adj == NULL
11214 + ? 0 : boost_temp_adj[i]);
11215 + /*
11216 + * Limit final adjusted boost voltage value between ceiling
11217 + * and floor voltage limits
11218 + */
11219 + final_boost_volt = min(final_boost_volt,
11220 + vreg->cpr4_regulator_data->boost_ceiling_volt);
11221 + final_boost_volt = max(final_boost_volt,
11222 + vreg->cpr4_regulator_data->boost_floor_volt);
11223 +
11224 + boost_table[i] = (corner->open_loop_volt - final_boost_volt)
11225 + / ctrl->step_volt;
11226 + cpr3_debug(vreg, "Adjusted boost voltage margin for temp band %d = %d steps\n",
11227 + i, boost_table[i]);
11228 + }
11229 +
11230 + corner->ceiling_volt = vreg->cpr4_regulator_data->boost_ceiling_volt;
11231 + corner->sdelta->boost_table = boost_table;
11232 + corner->sdelta->allow_boost = true;
11233 + corner->sdelta->allow_core_count_adj = false;
11234 + vreg->allow_boost = true;
11235 + ctrl->allow_boost = true;
11236 +done:
11237 + kfree(boost_temp_adj);
11238 + return rc;
11239 +}
11240 +
11241 +/**
11242 + * cpr4_apss_init_regulator() - perform all steps necessary to initialize the
11243 + * configuration data for a CPR3 regulator
11244 + * @vreg: Pointer to the CPR3 regulator
11245 + *
11246 + * Return: 0 on success, errno on failure
11247 + */
11248 +static int cpr4_apss_init_regulator(struct cpr3_regulator *vreg)
11249 +{
11250 + struct cpr4_ipq807x_apss_fuses *fuse;
11251 + int rc;
11252 +
11253 + rc = cpr4_ipq807x_apss_read_fuse_data(vreg);
11254 + if (rc) {
11255 + cpr3_err(vreg, "unable to read CPR fuse data, rc=%d\n", rc);
11256 + return rc;
11257 + }
11258 +
11259 + fuse = vreg->platform_fuses;
11260 +
11261 + rc = cpr4_apss_parse_corner_data(vreg);
11262 + if (rc) {
11263 + cpr3_err(vreg, "unable to read CPR corner data from device tree, rc=%d\n",
11264 + rc);
11265 + return rc;
11266 + }
11267 +
11268 + rc = cpr3_mem_acc_init(vreg);
11269 + if (rc) {
11270 + if (rc != -EPROBE_DEFER)
11271 + cpr3_err(vreg, "unable to initialize mem-acc regulator settings, rc=%d\n",
11272 + rc);
11273 + return rc;
11274 + }
11275 +
11276 + rc = cpr4_ipq807x_apss_calculate_open_loop_voltages(vreg);
11277 + if (rc) {
11278 + cpr3_err(vreg, "unable to calculate open-loop voltages, rc=%d\n",
11279 + rc);
11280 + return rc;
11281 + }
11282 +
11283 + rc = cpr3_limit_open_loop_voltages(vreg);
11284 + if (rc) {
11285 + cpr3_err(vreg, "unable to limit open-loop voltages, rc=%d\n",
11286 + rc);
11287 + return rc;
11288 + }
11289 +
11290 + cpr3_open_loop_voltage_as_ceiling(vreg);
11291 +
11292 + rc = cpr3_limit_floor_voltages(vreg);
11293 + if (rc) {
11294 + cpr3_err(vreg, "unable to limit floor voltages, rc=%d\n", rc);
11295 + return rc;
11296 + }
11297 +
11298 + rc = cpr4_ipq807x_apss_calculate_target_quotients(vreg);
11299 + if (rc) {
11300 + cpr3_err(vreg, "unable to calculate target quotients, rc=%d\n",
11301 + rc);
11302 + return rc;
11303 + }
11304 +
11305 + rc = cpr4_parse_core_count_temp_voltage_adj(vreg, false);
11306 + if (rc) {
11307 + cpr3_err(vreg, "unable to parse temperature and core count voltage adjustments, rc=%d\n",
11308 + rc);
11309 + return rc;
11310 + }
11311 +
11312 + if (vreg->allow_core_count_adj && (vreg->max_core_count <= 0
11313 + || vreg->max_core_count >
11314 + IPQ807x_APSS_CPR_SDELTA_CORE_COUNT)) {
11315 + cpr3_err(vreg, "qcom,max-core-count has invalid value = %d\n",
11316 + vreg->max_core_count);
11317 + return -EINVAL;
11318 + }
11319 +
11320 + rc = cpr4_apss_parse_boost_properties(vreg);
11321 + if (rc) {
11322 + cpr3_err(vreg, "unable to parse boost adjustments, rc=%d\n",
11323 + rc);
11324 + return rc;
11325 + }
11326 +
11327 + cpr4_apss_print_settings(vreg);
11328 +
11329 + return rc;
11330 +}
11331 +
11332 +/**
11333 + * cpr4_apss_init_controller() - perform APSS CPR4 controller specific
11334 + * initializations
11335 + * @ctrl: Pointer to the CPR3 controller
11336 + *
11337 + * Return: 0 on success, errno on failure
11338 + */
11339 +static int cpr4_apss_init_controller(struct cpr3_controller *ctrl)
11340 +{
11341 + int rc;
11342 +
11343 + rc = cpr3_parse_common_ctrl_data(ctrl);
11344 + if (rc) {
11345 + if (rc != -EPROBE_DEFER)
11346 + cpr3_err(ctrl, "unable to parse common controller data, rc=%d\n",
11347 + rc);
11348 + return rc;
11349 + }
11350 +
11351 + rc = of_property_read_u32(ctrl->dev->of_node,
11352 + "qcom,cpr-down-error-step-limit",
11353 + &ctrl->down_error_step_limit);
11354 + if (rc) {
11355 + cpr3_err(ctrl, "error reading qcom,cpr-down-error-step-limit, rc=%d\n",
11356 + rc);
11357 + return rc;
11358 + }
11359 +
11360 + rc = of_property_read_u32(ctrl->dev->of_node,
11361 + "qcom,cpr-up-error-step-limit",
11362 + &ctrl->up_error_step_limit);
11363 + if (rc) {
11364 + cpr3_err(ctrl, "error reading qcom,cpr-up-error-step-limit, rc=%d\n",
11365 + rc);
11366 + return rc;
11367 + }
11368 +
11369 + /*
11370 + * Use fixed step quotient if specified otherwise use dynamic
11371 + * calculated per RO step quotient
11372 + */
11373 + of_property_read_u32(ctrl->dev->of_node, "qcom,cpr-step-quot-fixed",
11374 + &ctrl->step_quot_fixed);
11375 + ctrl->use_dynamic_step_quot = ctrl->step_quot_fixed ? false : true;
11376 +
11377 + ctrl->saw_use_unit_mV = of_property_read_bool(ctrl->dev->of_node,
11378 + "qcom,cpr-saw-use-unit-mV");
11379 +
11380 + of_property_read_u32(ctrl->dev->of_node,
11381 + "qcom,cpr-voltage-settling-time",
11382 + &ctrl->voltage_settling_time);
11383 +
11384 + if (of_find_property(ctrl->dev->of_node, "vdd-limit-supply", NULL)) {
11385 + ctrl->vdd_limit_regulator =
11386 + devm_regulator_get(ctrl->dev, "vdd-limit");
11387 + if (IS_ERR(ctrl->vdd_limit_regulator)) {
11388 + rc = PTR_ERR(ctrl->vdd_limit_regulator);
11389 + if (rc != -EPROBE_DEFER)
11390 + cpr3_err(ctrl, "unable to request vdd-limit regulator, rc=%d\n",
11391 + rc);
11392 + return rc;
11393 + }
11394 + }
11395 +
11396 + rc = cpr3_apm_init(ctrl);
11397 + if (rc) {
11398 + if (rc != -EPROBE_DEFER)
11399 + cpr3_err(ctrl, "unable to initialize APM settings, rc=%d\n",
11400 + rc);
11401 + return rc;
11402 + }
11403 +
11404 + rc = cpr4_apss_parse_temp_adj_properties(ctrl);
11405 + if (rc) {
11406 + cpr3_err(ctrl, "unable to parse temperature adjustment properties, rc=%d\n",
11407 + rc);
11408 + return rc;
11409 + }
11410 +
11411 + ctrl->sensor_count = IPQ807x_APSS_CPR_SENSOR_COUNT;
11412 +
11413 + /*
11414 + * APSS only has one thread (0) per controller so the zeroed
11415 + * array does not need further modification.
11416 + */
11417 + ctrl->sensor_owner = devm_kcalloc(ctrl->dev, ctrl->sensor_count,
11418 + sizeof(*ctrl->sensor_owner), GFP_KERNEL);
11419 + if (!ctrl->sensor_owner)
11420 + return -ENOMEM;
11421 +
11422 + ctrl->ctrl_type = CPR_CTRL_TYPE_CPR4;
11423 + ctrl->supports_hw_closed_loop = false;
11424 + ctrl->use_hw_closed_loop = of_property_read_bool(ctrl->dev->of_node,
11425 + "qcom,cpr-hw-closed-loop");
11426 + return 0;
11427 +}
11428 +
11429 +static int cpr4_apss_regulator_suspend(struct platform_device *pdev,
11430 + pm_message_t state)
11431 +{
11432 + struct cpr3_controller *ctrl = platform_get_drvdata(pdev);
11433 +
11434 + return cpr3_regulator_suspend(ctrl);
11435 +}
11436 +
11437 +static int cpr4_apss_regulator_resume(struct platform_device *pdev)
11438 +{
11439 + struct cpr3_controller *ctrl = platform_get_drvdata(pdev);
11440 +
11441 + return cpr3_regulator_resume(ctrl);
11442 +}
11443 +
11444 +static void ipq6018_set_mem_acc(struct regulator_dev *rdev)
11445 +{
11446 + struct cpr3_regulator *vreg = rdev_get_drvdata(rdev);
11447 +
11448 + ipq6018_mem_acc_tcsr[0].ioremap_addr =
11449 + ioremap(ipq6018_mem_acc_tcsr[0].phy_addr, 0x4);
11450 + ipq6018_mem_acc_tcsr[1].ioremap_addr =
11451 + ioremap(ipq6018_mem_acc_tcsr[1].phy_addr, 0x4);
11452 +
11453 + if ((ipq6018_mem_acc_tcsr[0].ioremap_addr != NULL) &&
11454 + (ipq6018_mem_acc_tcsr[1].ioremap_addr != NULL) &&
11455 + (vreg->current_corner == (vreg->corner_count - CPR3_CORNER_OFFSET))) {
11456 +
11457 + writel_relaxed(ipq6018_mem_acc_tcsr[0].value,
11458 + ipq6018_mem_acc_tcsr[0].ioremap_addr);
11459 + writel_relaxed(ipq6018_mem_acc_tcsr[1].value,
11460 + ipq6018_mem_acc_tcsr[1].ioremap_addr);
11461 + }
11462 +}
11463 +
11464 +static void ipq6018_clr_mem_acc(struct regulator_dev *rdev)
11465 +{
11466 + struct cpr3_regulator *vreg = rdev_get_drvdata(rdev);
11467 +
11468 + if ((ipq6018_mem_acc_tcsr[0].ioremap_addr != NULL) &&
11469 + (ipq6018_mem_acc_tcsr[1].ioremap_addr != NULL) &&
11470 + (vreg->current_corner != vreg->corner_count - CPR3_CORNER_OFFSET)) {
11471 + writel_relaxed(0x0, ipq6018_mem_acc_tcsr[0].ioremap_addr);
11472 + writel_relaxed(0x0, ipq6018_mem_acc_tcsr[1].ioremap_addr);
11473 + }
11474 +
11475 + iounmap(ipq6018_mem_acc_tcsr[0].ioremap_addr);
11476 + iounmap(ipq6018_mem_acc_tcsr[1].ioremap_addr);
11477 +}
11478 +
11479 +static struct cpr4_mem_acc_func ipq6018_mem_acc_funcs = {
11480 + .set_mem_acc = ipq6018_set_mem_acc,
11481 + .clear_mem_acc = ipq6018_clr_mem_acc
11482 +};
11483 +
11484 +static const struct cpr4_reg_data ipq807x_cpr_apss = {
11485 + .cpr_valid_fuse_count = IPQ807x_APSS_FUSE_CORNERS,
11486 + .fuse_ref_volt = ipq807x_apss_fuse_ref_volt,
11487 + .fuse_step_volt = IPQ807x_APSS_FUSE_STEP_VOLT,
11488 + .cpr_clk_rate = IPQ807x_APSS_CPR_CLOCK_RATE,
11489 + .boost_fuse_ref_volt= IPQ807x_APSS_BOOST_FUSE_REF_VOLT,
11490 + .boost_ceiling_volt= IPQ807x_APSS_BOOST_CEILING_VOLT,
11491 + .boost_floor_volt= IPQ807x_APSS_BOOST_FLOOR_VOLT,
11492 + .cpr3_fuse_params = &ipq807x_fuse_params,
11493 + .mem_acc_funcs = NULL,
11494 +};
11495 +
11496 +static const struct cpr4_reg_data ipq817x_cpr_apss = {
11497 + .cpr_valid_fuse_count = IPQ817x_APPS_FUSE_CORNERS,
11498 + .fuse_ref_volt = ipq807x_apss_fuse_ref_volt,
11499 + .fuse_step_volt = IPQ807x_APSS_FUSE_STEP_VOLT,
11500 + .cpr_clk_rate = IPQ807x_APSS_CPR_CLOCK_RATE,
11501 + .boost_fuse_ref_volt= IPQ807x_APSS_BOOST_FUSE_REF_VOLT,
11502 + .boost_ceiling_volt= IPQ807x_APSS_BOOST_CEILING_VOLT,
11503 + .boost_floor_volt= IPQ807x_APSS_BOOST_FLOOR_VOLT,
11504 + .cpr3_fuse_params = &ipq807x_fuse_params,
11505 + .mem_acc_funcs = NULL,
11506 +};
11507 +
11508 +static const struct cpr4_reg_data ipq6018_cpr_apss = {
11509 + .cpr_valid_fuse_count = IPQ6018_APSS_FUSE_CORNERS,
11510 + .fuse_ref_volt = ipq6018_apss_fuse_ref_volt,
11511 + .fuse_step_volt = IPQ6018_APSS_FUSE_STEP_VOLT,
11512 + .cpr_clk_rate = IPQ6018_APSS_CPR_CLOCK_RATE,
11513 + .boost_fuse_ref_volt = IPQ6018_APSS_BOOST_FUSE_REF_VOLT,
11514 + .boost_ceiling_volt = IPQ6018_APSS_BOOST_CEILING_VOLT,
11515 + .boost_floor_volt = IPQ6018_APSS_BOOST_FLOOR_VOLT,
11516 + .cpr3_fuse_params = &ipq6018_fuse_params,
11517 + .mem_acc_funcs = &ipq6018_mem_acc_funcs,
11518 +};
11519 +
11520 +static const struct cpr4_reg_data ipq9574_cpr_apss = {
11521 + .cpr_valid_fuse_count = IPQ9574_APSS_FUSE_CORNERS,
11522 + .fuse_ref_volt = ipq9574_apss_fuse_ref_volt,
11523 + .fuse_step_volt = IPQ9574_APSS_FUSE_STEP_VOLT,
11524 + .cpr_clk_rate = IPQ6018_APSS_CPR_CLOCK_RATE,
11525 + .boost_fuse_ref_volt = IPQ6018_APSS_BOOST_FUSE_REF_VOLT,
11526 + .boost_ceiling_volt = IPQ6018_APSS_BOOST_CEILING_VOLT,
11527 + .boost_floor_volt = IPQ6018_APSS_BOOST_FLOOR_VOLT,
11528 + .cpr3_fuse_params = &ipq9574_fuse_params,
11529 + .mem_acc_funcs = NULL,
11530 +};
11531 +
11532 +static struct of_device_id cpr4_regulator_match_table[] = {
11533 + {
11534 + .compatible = "qcom,cpr4-ipq807x-apss-regulator",
11535 + .data = &ipq807x_cpr_apss
11536 + },
11537 + {
11538 + .compatible = "qcom,cpr4-ipq817x-apss-regulator",
11539 + .data = &ipq817x_cpr_apss
11540 + },
11541 + {
11542 + .compatible = "qcom,cpr4-ipq6018-apss-regulator",
11543 + .data = &ipq6018_cpr_apss
11544 + },
11545 + {
11546 + .compatible = "qcom,cpr4-ipq9574-apss-regulator",
11547 + .data = &ipq9574_cpr_apss
11548 + },
11549 + {}
11550 +};
11551 +
11552 +static int cpr4_apss_regulator_probe(struct platform_device *pdev)
11553 +{
11554 + struct device *dev = &pdev->dev;
11555 + struct cpr3_controller *ctrl;
11556 + const struct of_device_id *match;
11557 + struct cpr4_reg_data *cpr_data;
11558 + int i, rc;
11559 +
11560 + if (!dev->of_node) {
11561 + dev_err(dev, "Device tree node is missing\n");
11562 + return -EINVAL;
11563 + }
11564 +
11565 + ctrl = devm_kzalloc(dev, sizeof(*ctrl), GFP_KERNEL);
11566 + if (!ctrl)
11567 + return -ENOMEM;
11568 +
11569 + match = of_match_device(cpr4_regulator_match_table, &pdev->dev);
11570 + if (!match)
11571 + return -ENODEV;
11572 +
11573 + cpr_data = (struct cpr4_reg_data *)match->data;
11574 + g_valid_fuse_count = cpr_data->cpr_valid_fuse_count;
11575 + dev_info(dev, "CPR valid fuse count: %d\n", g_valid_fuse_count);
11576 + ctrl->cpr_clock_rate = cpr_data->cpr_clk_rate;
11577 +
11578 + ctrl->dev = dev;
11579 + /* Set to false later if anything precludes CPR operation. */
11580 + ctrl->cpr_allowed_hw = true;
11581 +
11582 + rc = of_property_read_string(dev->of_node, "qcom,cpr-ctrl-name",
11583 + &ctrl->name);
11584 + if (rc) {
11585 + cpr3_err(ctrl, "unable to read qcom,cpr-ctrl-name, rc=%d\n",
11586 + rc);
11587 + return rc;
11588 + }
11589 +
11590 + rc = cpr3_map_fuse_base(ctrl, pdev);
11591 + if (rc) {
11592 + cpr3_err(ctrl, "could not map fuse base address\n");
11593 + return rc;
11594 + }
11595 +
11596 + rc = cpr3_read_tcsr_setting(ctrl, pdev, IPQ807x_APSS_CPR_TCSR_START,
11597 + IPQ807x_APSS_CPR_TCSR_END);
11598 + if (rc) {
11599 + cpr3_err(ctrl, "could not read CPR tcsr setting\n");
11600 + return rc;
11601 + }
11602 +
11603 + rc = cpr3_allocate_threads(ctrl, 0, 0);
11604 + if (rc) {
11605 + cpr3_err(ctrl, "failed to allocate CPR thread array, rc=%d\n",
11606 + rc);
11607 + return rc;
11608 + }
11609 +
11610 + if (ctrl->thread_count != 1) {
11611 + cpr3_err(ctrl, "expected 1 thread but found %d\n",
11612 + ctrl->thread_count);
11613 + return -EINVAL;
11614 + }
11615 +
11616 + rc = cpr4_apss_init_controller(ctrl);
11617 + if (rc) {
11618 + if (rc != -EPROBE_DEFER)
11619 + cpr3_err(ctrl, "failed to initialize CPR controller parameters, rc=%d\n",
11620 + rc);
11621 + return rc;
11622 + }
11623 +
11624 + rc = cpr4_apss_init_thread(&ctrl->thread[0]);
11625 + if (rc) {
11626 + cpr3_err(ctrl, "thread initialization failed, rc=%d\n", rc);
11627 + return rc;
11628 + }
11629 +
11630 + for (i = 0; i < ctrl->thread[0].vreg_count; i++) {
11631 + ctrl->thread[0].vreg[i].cpr4_regulator_data = cpr_data;
11632 + rc = cpr4_apss_init_regulator(&ctrl->thread[0].vreg[i]);
11633 + if (rc) {
11634 + cpr3_err(&ctrl->thread[0].vreg[i], "regulator initialization failed, rc=%d\n",
11635 + rc);
11636 + return rc;
11637 + }
11638 + }
11639 +
11640 + platform_set_drvdata(pdev, ctrl);
11641 +
11642 + return cpr3_regulator_register(pdev, ctrl);
11643 +}
11644 +
11645 +static int cpr4_apss_regulator_remove(struct platform_device *pdev)
11646 +{
11647 + struct cpr3_controller *ctrl = platform_get_drvdata(pdev);
11648 +
11649 + return cpr3_regulator_unregister(ctrl);
11650 +}
11651 +
11652 +static struct platform_driver cpr4_apss_regulator_driver = {
11653 + .driver = {
11654 + .name = "qcom,cpr4-apss-regulator",
11655 + .of_match_table = cpr4_regulator_match_table,
11656 + .owner = THIS_MODULE,
11657 + },
11658 + .probe = cpr4_apss_regulator_probe,
11659 + .remove = cpr4_apss_regulator_remove,
11660 + .suspend = cpr4_apss_regulator_suspend,
11661 + .resume = cpr4_apss_regulator_resume,
11662 +};
11663 +
11664 +static int cpr4_regulator_init(void)
11665 +{
11666 + return platform_driver_register(&cpr4_apss_regulator_driver);
11667 +}
11668 +
11669 +static void cpr4_regulator_exit(void)
11670 +{
11671 + platform_driver_unregister(&cpr4_apss_regulator_driver);
11672 +}
11673 +
11674 +MODULE_DESCRIPTION("CPR4 APSS regulator driver");
11675 +MODULE_LICENSE("GPL v2");
11676 +
11677 +arch_initcall(cpr4_regulator_init);
11678 +module_exit(cpr4_regulator_exit);
11679 --- /dev/null
11680 +++ b/include/soc/qcom/socinfo.h
11681 @@ -0,0 +1,463 @@
11682 +/* Copyright (c) 2009-2014, 2016, 2020, The Linux Foundation. All rights reserved.
11683 + *
11684 + * This program is free software; you can redistribute it and/or modify
11685 + * it under the terms of the GNU General Public License version 2 and
11686 + * only version 2 as published by the Free Software Foundation.
11687 + *
11688 + * This program is distributed in the hope that it will be useful,
11689 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
11690 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11691 + * GNU General Public License for more details.
11692 + *
11693 + */
11694 +
11695 +#ifndef _ARCH_ARM_MACH_MSM_SOCINFO_H_
11696 +#define _ARCH_ARM_MACH_MSM_SOCINFO_H_
11697 +
11698 +#include <linux/of.h>
11699 +
11700 +#define CPU_IPQ8074 323
11701 +#define CPU_IPQ8072 342
11702 +#define CPU_IPQ8076 343
11703 +#define CPU_IPQ8078 344
11704 +#define CPU_IPQ8070 375
11705 +#define CPU_IPQ8071 376
11706 +
11707 +#define CPU_IPQ8072A 389
11708 +#define CPU_IPQ8074A 390
11709 +#define CPU_IPQ8076A 391
11710 +#define CPU_IPQ8078A 392
11711 +#define CPU_IPQ8070A 395
11712 +#define CPU_IPQ8071A 396
11713 +
11714 +#define CPU_IPQ8172 397
11715 +#define CPU_IPQ8173 398
11716 +#define CPU_IPQ8174 399
11717 +
11718 +#define CPU_IPQ6018 402
11719 +#define CPU_IPQ6028 403
11720 +#define CPU_IPQ6000 421
11721 +#define CPU_IPQ6010 422
11722 +#define CPU_IPQ6005 453
11723 +
11724 +#define CPU_IPQ5010 446
11725 +#define CPU_IPQ5018 447
11726 +#define CPU_IPQ5028 448
11727 +#define CPU_IPQ5000 503
11728 +#define CPU_IPQ0509 504
11729 +#define CPU_IPQ0518 505
11730 +
11731 +#define CPU_IPQ9514 510
11732 +#define CPU_IPQ9554 512
11733 +#define CPU_IPQ9570 513
11734 +#define CPU_IPQ9574 514
11735 +#define CPU_IPQ9550 511
11736 +#define CPU_IPQ9510 521
11737 +
11738 +static inline int read_ipq_soc_version_major(void)
11739 +{
11740 + const int *prop;
11741 + prop = of_get_property(of_find_node_by_path("/"), "soc_version_major",
11742 + NULL);
11743 +
11744 + if (!prop)
11745 + return -EINVAL;
11746 +
11747 + return le32_to_cpu(*prop);
11748 +}
11749 +
11750 +static inline int read_ipq_cpu_type(void)
11751 +{
11752 + const int *prop;
11753 + prop = of_get_property(of_find_node_by_path("/"), "cpu_type", NULL);
11754 + /*
11755 + * Return Default CPU type if "cpu_type" property is not found in DTSI
11756 + */
11757 + if (!prop)
11758 + return CPU_IPQ8074;
11759 +
11760 + return le32_to_cpu(*prop);
11761 +}
11762 +
11763 +static inline int cpu_is_ipq8070(void)
11764 +{
11765 +#ifdef CONFIG_ARCH_QCOM
11766 + return read_ipq_cpu_type() == CPU_IPQ8070;
11767 +#else
11768 + return 0;
11769 +#endif
11770 +}
11771 +
11772 +static inline int cpu_is_ipq8071(void)
11773 +{
11774 +#ifdef CONFIG_ARCH_QCOM
11775 + return read_ipq_cpu_type() == CPU_IPQ8071;
11776 +#else
11777 + return 0;
11778 +#endif
11779 +}
11780 +
11781 +static inline int cpu_is_ipq8072(void)
11782 +{
11783 +#ifdef CONFIG_ARCH_QCOM
11784 + return read_ipq_cpu_type() == CPU_IPQ8072;
11785 +#else
11786 + return 0;
11787 +#endif
11788 +}
11789 +
11790 +static inline int cpu_is_ipq8074(void)
11791 +{
11792 +#ifdef CONFIG_ARCH_QCOM
11793 + return read_ipq_cpu_type() == CPU_IPQ8074;
11794 +#else
11795 + return 0;
11796 +#endif
11797 +}
11798 +
11799 +static inline int cpu_is_ipq8076(void)
11800 +{
11801 +#ifdef CONFIG_ARCH_QCOM
11802 + return read_ipq_cpu_type() == CPU_IPQ8076;
11803 +#else
11804 + return 0;
11805 +#endif
11806 +}
11807 +
11808 +static inline int cpu_is_ipq8078(void)
11809 +{
11810 +#ifdef CONFIG_ARCH_QCOM
11811 + return read_ipq_cpu_type() == CPU_IPQ8078;
11812 +#else
11813 + return 0;
11814 +#endif
11815 +}
11816 +
11817 +static inline int cpu_is_ipq8072a(void)
11818 +{
11819 +#ifdef CONFIG_ARCH_QCOM
11820 + return read_ipq_cpu_type() == CPU_IPQ8072A;
11821 +#else
11822 + return 0;
11823 +#endif
11824 +}
11825 +
11826 +static inline int cpu_is_ipq8074a(void)
11827 +{
11828 +#ifdef CONFIG_ARCH_QCOM
11829 + return read_ipq_cpu_type() == CPU_IPQ8074A;
11830 +#else
11831 + return 0;
11832 +#endif
11833 +}
11834 +
11835 +static inline int cpu_is_ipq8076a(void)
11836 +{
11837 +#ifdef CONFIG_ARCH_QCOM
11838 + return read_ipq_cpu_type() == CPU_IPQ8076A;
11839 +#else
11840 + return 0;
11841 +#endif
11842 +}
11843 +
11844 +static inline int cpu_is_ipq8078a(void)
11845 +{
11846 +#ifdef CONFIG_ARCH_QCOM
11847 + return read_ipq_cpu_type() == CPU_IPQ8078A;
11848 +#else
11849 + return 0;
11850 +#endif
11851 +}
11852 +
11853 +static inline int cpu_is_ipq8070a(void)
11854 +{
11855 +#ifdef CONFIG_ARCH_QCOM
11856 + return read_ipq_cpu_type() == CPU_IPQ8070A;
11857 +#else
11858 + return 0;
11859 +#endif
11860 +}
11861 +
11862 +static inline int cpu_is_ipq8071a(void)
11863 +{
11864 +#ifdef CONFIG_ARCH_QCOM
11865 + return read_ipq_cpu_type() == CPU_IPQ8071A;
11866 +#else
11867 + return 0;
11868 +#endif
11869 +}
11870 +
11871 +static inline int cpu_is_ipq8172(void)
11872 +{
11873 +#ifdef CONFIG_ARCH_QCOM
11874 + return read_ipq_cpu_type() == CPU_IPQ8172;
11875 +#else
11876 + return 0;
11877 +#endif
11878 +}
11879 +
11880 +static inline int cpu_is_ipq8173(void)
11881 +{
11882 +#ifdef CONFIG_ARCH_QCOM
11883 + return read_ipq_cpu_type() == CPU_IPQ8173;
11884 +#else
11885 + return 0;
11886 +#endif
11887 +}
11888 +
11889 +static inline int cpu_is_ipq8174(void)
11890 +{
11891 +#ifdef CONFIG_ARCH_QCOM
11892 + return read_ipq_cpu_type() == CPU_IPQ8174;
11893 +#else
11894 + return 0;
11895 +#endif
11896 +}
11897 +
11898 +static inline int cpu_is_ipq6018(void)
11899 +{
11900 +#ifdef CONFIG_ARCH_QCOM
11901 + return read_ipq_cpu_type() == CPU_IPQ6018;
11902 +#else
11903 + return 0;
11904 +#endif
11905 +}
11906 +
11907 +static inline int cpu_is_ipq6028(void)
11908 +{
11909 +#ifdef CONFIG_ARCH_QCOM
11910 + return read_ipq_cpu_type() == CPU_IPQ6028;
11911 +#else
11912 + return 0;
11913 +#endif
11914 +}
11915 +
11916 +static inline int cpu_is_ipq6000(void)
11917 +{
11918 +#ifdef CONFIG_ARCH_QCOM
11919 + return read_ipq_cpu_type() == CPU_IPQ6000;
11920 +#else
11921 + return 0;
11922 +#endif
11923 +}
11924 +
11925 +static inline int cpu_is_ipq6010(void)
11926 +{
11927 +#ifdef CONFIG_ARCH_QCOM
11928 + return read_ipq_cpu_type() == CPU_IPQ6010;
11929 +#else
11930 + return 0;
11931 +#endif
11932 +}
11933 +
11934 +static inline int cpu_is_ipq6005(void)
11935 +{
11936 +#ifdef CONFIG_ARCH_QCOM
11937 + return read_ipq_cpu_type() == CPU_IPQ6005;
11938 +#else
11939 + return 0;
11940 +#endif
11941 +}
11942 +
11943 +static inline int cpu_is_ipq5010(void)
11944 +{
11945 +#ifdef CONFIG_ARCH_QCOM
11946 + return read_ipq_cpu_type() == CPU_IPQ5010;
11947 +#else
11948 + return 0;
11949 +#endif
11950 +}
11951 +
11952 +static inline int cpu_is_ipq5018(void)
11953 +{
11954 +#ifdef CONFIG_ARCH_QCOM
11955 + return read_ipq_cpu_type() == CPU_IPQ5018;
11956 +#else
11957 + return 0;
11958 +#endif
11959 +}
11960 +
11961 +static inline int cpu_is_ipq5028(void)
11962 +{
11963 +#ifdef CONFIG_ARCH_QCOM
11964 + return read_ipq_cpu_type() == CPU_IPQ5028;
11965 +#else
11966 + return 0;
11967 +#endif
11968 +}
11969 +
11970 +static inline int cpu_is_ipq5000(void)
11971 +{
11972 +#ifdef CONFIG_ARCH_QCOM
11973 + return read_ipq_cpu_type() == CPU_IPQ5000;
11974 +#else
11975 + return 0;
11976 +#endif
11977 +}
11978 +
11979 +static inline int cpu_is_ipq0509(void)
11980 +{
11981 +#ifdef CONFIG_ARCH_QCOM
11982 + return read_ipq_cpu_type() == CPU_IPQ0509;
11983 +#else
11984 + return 0;
11985 +#endif
11986 +}
11987 +
11988 +static inline int cpu_is_ipq0518(void)
11989 +{
11990 +#ifdef CONFIG_ARCH_QCOM
11991 + return read_ipq_cpu_type() == CPU_IPQ0518;
11992 +#else
11993 + return 0;
11994 +#endif
11995 +}
11996 +
11997 +static inline int cpu_is_ipq9514(void)
11998 +{
11999 +#ifdef CONFIG_ARCH_QCOM
12000 + return read_ipq_cpu_type() == CPU_IPQ9514;
12001 +#else
12002 + return 0;
12003 +#endif
12004 +}
12005 +
12006 +static inline int cpu_is_ipq9554(void)
12007 +{
12008 +#ifdef CONFIG_ARCH_QCOM
12009 + return read_ipq_cpu_type() == CPU_IPQ9554;
12010 +#else
12011 + return 0;
12012 +#endif
12013 +}
12014 +
12015 +static inline int cpu_is_ipq9570(void)
12016 +{
12017 +#ifdef CONFIG_ARCH_QCOM
12018 + return read_ipq_cpu_type() == CPU_IPQ9570;
12019 +#else
12020 + return 0;
12021 +#endif
12022 +}
12023 +
12024 +static inline int cpu_is_ipq9574(void)
12025 +{
12026 +#ifdef CONFIG_ARCH_QCOM
12027 + return read_ipq_cpu_type() == CPU_IPQ9574;
12028 +#else
12029 + return 0;
12030 +#endif
12031 +}
12032 +
12033 +static inline int cpu_is_ipq9550(void)
12034 +{
12035 +#ifdef CONFIG_ARCH_QCOM
12036 + return read_ipq_cpu_type() == CPU_IPQ9550;
12037 +#else
12038 + return 0;
12039 +#endif
12040 +}
12041 +
12042 +static inline int cpu_is_ipq9510(void)
12043 +{
12044 +#ifdef CONFIG_ARCH_QCOM
12045 + return read_ipq_cpu_type() == CPU_IPQ9510;
12046 +#else
12047 + return 0;
12048 +#endif
12049 +}
12050 +
12051 +static inline int cpu_is_ipq807x(void)
12052 +{
12053 +#ifdef CONFIG_ARCH_QCOM
12054 + return cpu_is_ipq8072() || cpu_is_ipq8074() ||
12055 + cpu_is_ipq8076() || cpu_is_ipq8078() ||
12056 + cpu_is_ipq8070() || cpu_is_ipq8071() ||
12057 + cpu_is_ipq8072a() || cpu_is_ipq8074a() ||
12058 + cpu_is_ipq8076a() || cpu_is_ipq8078a() ||
12059 + cpu_is_ipq8070a() || cpu_is_ipq8071a() ||
12060 + cpu_is_ipq8172() || cpu_is_ipq8173() ||
12061 + cpu_is_ipq8174();
12062 +#else
12063 + return 0;
12064 +#endif
12065 +}
12066 +
12067 +static inline int cpu_is_ipq60xx(void)
12068 +{
12069 +#ifdef CONFIG_ARCH_QCOM
12070 + return cpu_is_ipq6018() || cpu_is_ipq6028() ||
12071 + cpu_is_ipq6000() || cpu_is_ipq6010() ||
12072 + cpu_is_ipq6005();
12073 +#else
12074 + return 0;
12075 +#endif
12076 +}
12077 +
12078 +static inline int cpu_is_ipq50xx(void)
12079 +{
12080 +#ifdef CONFIG_ARCH_QCOM
12081 + return cpu_is_ipq5010() || cpu_is_ipq5018() ||
12082 + cpu_is_ipq5028() || cpu_is_ipq5000() ||
12083 + cpu_is_ipq0509() || cpu_is_ipq0518();
12084 +#else
12085 + return 0;
12086 +#endif
12087 +}
12088 +
12089 +static inline int cpu_is_ipq95xx(void)
12090 +{
12091 +#ifdef CONFIG_ARCH_QCOM
12092 + return cpu_is_ipq9514() || cpu_is_ipq9554() ||
12093 + cpu_is_ipq9570() || cpu_is_ipq9574() ||
12094 + cpu_is_ipq9550() || cpu_is_ipq9510();
12095 +#else
12096 + return 0;
12097 +#endif
12098 +}
12099 +
12100 +static inline int cpu_is_nss_crypto_enabled(void)
12101 +{
12102 +#ifdef CONFIG_ARCH_QCOM
12103 + return cpu_is_ipq807x() || cpu_is_ipq60xx() ||
12104 + cpu_is_ipq50xx() || cpu_is_ipq9570() ||
12105 + cpu_is_ipq9550() || cpu_is_ipq9574() ||
12106 + cpu_is_ipq9554();
12107 +#else
12108 + return 0;
12109 +#endif
12110 +}
12111 +
12112 +static inline int cpu_is_internal_wifi_enabled(void)
12113 +{
12114 +#ifdef CONFIG_ARCH_QCOM
12115 + return cpu_is_ipq807x() || cpu_is_ipq60xx() ||
12116 + cpu_is_ipq50xx() || cpu_is_ipq9514() ||
12117 + cpu_is_ipq9554() || cpu_is_ipq9574();
12118 +#else
12119 + return 0;
12120 +#endif
12121 +}
12122 +
12123 +static inline int cpu_is_uniphy1_enabled(void)
12124 +{
12125 +#ifdef CONFIG_ARCH_QCOM
12126 + return cpu_is_ipq807x() || cpu_is_ipq60xx() ||
12127 + cpu_is_ipq9554() || cpu_is_ipq9570() ||
12128 + cpu_is_ipq9574() || cpu_is_ipq9550();
12129 +#else
12130 + return 0;
12131 +#endif
12132 +}
12133 +
12134 +static inline int cpu_is_uniphy2_enabled(void)
12135 +{
12136 +#ifdef CONFIG_ARCH_QCOM
12137 + return cpu_is_ipq807x() || cpu_is_ipq9570() ||
12138 + cpu_is_ipq9574();
12139 +#else
12140 + return 0;
12141 +#endif
12142 +}
12143 +
12144 +#endif /* _ARCH_ARM_MACH_MSM_SOCINFO_H_ */