blob: c39394042865f416c970ac9016da90ee8b184948 [file] [log] [blame]
David Collins7370f1a2017-01-18 16:21:53 -08001/*
2 * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14#define pr_fmt(fmt) "%s: " fmt, __func__
15
16#include <linux/bitops.h>
17#include <linux/debugfs.h>
18#include <linux/err.h>
19#include <linux/init.h>
20#include <linux/interrupt.h>
21#include <linux/io.h>
22#include <linux/kernel.h>
23#include <linux/list.h>
24#include <linux/module.h>
25#include <linux/of.h>
26#include <linux/of_device.h>
27#include <linux/platform_device.h>
David Collins7370f1a2017-01-18 16:21:53 -080028#include <linux/slab.h>
29#include <linux/string.h>
30#include <linux/uaccess.h>
31#include <linux/regulator/driver.h>
32#include <linux/regulator/machine.h>
33#include <linux/regulator/of_regulator.h>
34
35#include "cpr3-regulator.h"
36
David Collinse367ce62017-05-08 18:15:03 -070037#define MSM8998_KBSS_FUSE_CORNERS 4
38#define SDM660_KBSS_FUSE_CORNERS 5
39
40#define SDM845_KBSS_POWER_CLUSTER_FUSE_CORNERS 4
David Collins97e4c412017-07-19 17:41:46 -070041#define SDM845_V1_KBSS_PERF_CLUSTER_FUSE_CORNERS 3
42#define SDM845_V2_KBSS_PERF_CLUSTER_FUSE_CORNERS 5
43/* This must be set to the largest of SDM845 FUSE_CORNERS values. */
44#define SDM845_KBSS_MAX_FUSE_CORNERS 5
David Collins7370f1a2017-01-18 16:21:53 -080045
46/**
47 * struct cprh_kbss_fuses - KBSS specific fuse data
48 * @ro_sel: Ring oscillator select fuse parameter value for each
49 * fuse corner
50 * @init_voltage: Initial (i.e. open-loop) voltage fuse parameter value
51 * for each fuse corner (raw, not converted to a voltage)
52 * @target_quot: CPR target quotient fuse parameter value for each fuse
53 * corner
54 * @quot_offset: CPR target quotient offset fuse parameter value for each
55 * fuse corner (raw, not unpacked) used for target quotient
56 * interpolation
57 * @speed_bin: Application processor speed bin fuse parameter value for
58 * the given chip
59 * @cpr_fusing_rev: CPR fusing revision fuse parameter value
60 * @force_highest_corner: Flag indicating that all corners must operate
61 * at the voltage of the highest corner. This is
62 * applicable to MSM8998 only.
63 * @aging_init_quot_diff: Initial quotient difference between CPR aging
64 * min and max sensors measured at time of manufacturing
65 *
66 * This struct holds the values for all of the fuses read from memory.
67 */
68struct cprh_kbss_fuses {
69 u64 *ro_sel;
70 u64 *init_voltage;
71 u64 *target_quot;
72 u64 *quot_offset;
73 u64 speed_bin;
74 u64 cpr_fusing_rev;
75 u64 force_highest_corner;
76 u64 aging_init_quot_diff;
77};
78
79/*
80 * Fuse combos 0 - 7 map to CPR fusing revision 0 - 7 with speed bin fuse = 0.
81 * Fuse combos 8 - 15 map to CPR fusing revision 0 - 7 with speed bin fuse = 1.
82 * Fuse combos 16 - 23 map to CPR fusing revision 0 - 7 with speed bin fuse = 2.
83 * Fuse combos 24 - 31 map to CPR fusing revision 0 - 7 with speed bin fuse = 3.
84 */
85#define CPRH_MSM8998_KBSS_FUSE_COMBO_COUNT 32
86#define CPRH_SDM660_KBSS_FUSE_COMBO_COUNT 16
David Collins48f8e1c2017-05-23 17:41:52 -070087#define CPRH_SDM845_KBSS_FUSE_COMBO_COUNT 24
David Collins7370f1a2017-01-18 16:21:53 -080088
89/*
90 * Constants which define the name of each fuse corner.
91 */
92enum cprh_msm8998_kbss_fuse_corner {
93 CPRH_MSM8998_KBSS_FUSE_CORNER_LOWSVS = 0,
94 CPRH_MSM8998_KBSS_FUSE_CORNER_SVS = 1,
95 CPRH_MSM8998_KBSS_FUSE_CORNER_NOM = 2,
96 CPRH_MSM8998_KBSS_FUSE_CORNER_TURBO_L1 = 3,
97};
98
99static const char * const cprh_msm8998_kbss_fuse_corner_name[] = {
100 [CPRH_MSM8998_KBSS_FUSE_CORNER_LOWSVS] = "LowSVS",
101 [CPRH_MSM8998_KBSS_FUSE_CORNER_SVS] = "SVS",
102 [CPRH_MSM8998_KBSS_FUSE_CORNER_NOM] = "NOM",
103 [CPRH_MSM8998_KBSS_FUSE_CORNER_TURBO_L1] = "TURBO_L1",
104};
105
106enum cprh_sdm660_power_kbss_fuse_corner {
107 CPRH_SDM660_POWER_KBSS_FUSE_CORNER_LOWSVS = 0,
108 CPRH_SDM660_POWER_KBSS_FUSE_CORNER_SVS = 1,
109 CPRH_SDM660_POWER_KBSS_FUSE_CORNER_SVSPLUS = 2,
110 CPRH_SDM660_POWER_KBSS_FUSE_CORNER_NOM = 3,
111 CPRH_SDM660_POWER_KBSS_FUSE_CORNER_TURBO_L1 = 4,
112};
113
114static const char * const cprh_sdm660_power_kbss_fuse_corner_name[] = {
115 [CPRH_SDM660_POWER_KBSS_FUSE_CORNER_LOWSVS] = "LowSVS",
116 [CPRH_SDM660_POWER_KBSS_FUSE_CORNER_SVS] = "SVS",
117 [CPRH_SDM660_POWER_KBSS_FUSE_CORNER_SVSPLUS] = "SVSPLUS",
118 [CPRH_SDM660_POWER_KBSS_FUSE_CORNER_NOM] = "NOM",
119 [CPRH_SDM660_POWER_KBSS_FUSE_CORNER_TURBO_L1] = "TURBO_L1",
120};
121
122enum cprh_sdm660_perf_kbss_fuse_corner {
123 CPRH_SDM660_PERF_KBSS_FUSE_CORNER_SVS = 0,
124 CPRH_SDM660_PERF_KBSS_FUSE_CORNER_SVSPLUS = 1,
125 CPRH_SDM660_PERF_KBSS_FUSE_CORNER_NOM = 2,
126 CPRH_SDM660_PERF_KBSS_FUSE_CORNER_TURBO = 3,
127 CPRH_SDM660_PERF_KBSS_FUSE_CORNER_TURBO_L2 = 4,
128};
129
130static const char * const cprh_sdm660_perf_kbss_fuse_corner_name[] = {
131 [CPRH_SDM660_PERF_KBSS_FUSE_CORNER_SVS] = "SVS",
132 [CPRH_SDM660_PERF_KBSS_FUSE_CORNER_SVSPLUS] = "SVSPLUS",
133 [CPRH_SDM660_PERF_KBSS_FUSE_CORNER_NOM] = "NOM",
134 [CPRH_SDM660_PERF_KBSS_FUSE_CORNER_TURBO] = "TURBO",
135 [CPRH_SDM660_PERF_KBSS_FUSE_CORNER_TURBO_L2] = "TURBO_L2",
136};
137
138/* KBSS cluster IDs */
139#define CPRH_KBSS_POWER_CLUSTER_ID 0
140#define CPRH_KBSS_PERFORMANCE_CLUSTER_ID 1
141
142/* KBSS controller IDs */
143#define CPRH_KBSS_MIN_CONTROLLER_ID 0
144#define CPRH_KBSS_MAX_CONTROLLER_ID 1
145
David Collins54f78b72017-02-24 11:18:57 -0800146/* SDM845 KBSS cluster 0 thread IDs */
147#define CPRH_KBSS_POWER_CLUSTER_THREAD_ID 0
148#define CPRH_KBSS_L3_THREAD_ID 1
149
150/* SDM845 KBSS cluster 1 thread IDs */
151#define CPRH_KBSS_PERFORMANCE_CLUSTER_THREAD_ID 0
152
153static const char * const
David Collins97e4c412017-07-19 17:41:46 -0700154cprh_sdm845_v1_kbss_fuse_corner_name[2][SDM845_KBSS_MAX_FUSE_CORNERS] = {
David Collins54f78b72017-02-24 11:18:57 -0800155 [CPRH_KBSS_POWER_CLUSTER_ID] = {
156 "LowSVS",
157 "SVS_L1",
158 "NOM_L1",
David Collinse367ce62017-05-08 18:15:03 -0700159 "TURBO",
David Collins97e4c412017-07-19 17:41:46 -0700160 "",
David Collins54f78b72017-02-24 11:18:57 -0800161 },
162 [CPRH_KBSS_PERFORMANCE_CLUSTER_ID] = {
163 "SVS",
164 "NOM",
165 "TURBO_L2",
David Collinse367ce62017-05-08 18:15:03 -0700166 "",
David Collins97e4c412017-07-19 17:41:46 -0700167 "",
168 },
169};
170
171static const char * const
172cprh_sdm845_v2_kbss_fuse_corner_name[2][SDM845_KBSS_MAX_FUSE_CORNERS] = {
173 [CPRH_KBSS_POWER_CLUSTER_ID] = {
174 "LowSVS",
175 "SVS_L1",
176 "NOM",
177 "TURBO",
178 "",
179 },
180 [CPRH_KBSS_PERFORMANCE_CLUSTER_ID] = {
181 "LowSVS",
182 "SVS",
183 "NOM_L1",
184 "TURBO_L2",
185 "BINNING",
David Collins54f78b72017-02-24 11:18:57 -0800186 },
187};
188
David Collins7370f1a2017-01-18 16:21:53 -0800189/*
190 * MSM8998 KBSS fuse parameter locations:
191 *
192 * Structs are organized with the following dimensions:
193 * Outer: 0 or 1 for power or performance cluster
194 * Middle: 0 to 3 for fuse corners from lowest to highest corner
195 * Inner: large enough to hold the longest set of parameter segments which
196 * fully defines a fuse parameter, +1 (for NULL termination).
197 * Each segment corresponds to a contiguous group of bits from a
198 * single fuse row. These segments are concatentated together in
199 * order to form the full fuse parameter value. The segments for
200 * a given parameter may correspond to different fuse rows.
201 *
202 */
203static const struct cpr3_fuse_param
204msm8998_kbss_ro_sel_param[2][MSM8998_KBSS_FUSE_CORNERS][2] = {
205 [CPRH_KBSS_POWER_CLUSTER_ID] = {
206 {{67, 12, 15}, {} },
207 {{67, 8, 11}, {} },
208 {{67, 4, 7}, {} },
209 {{67, 0, 3}, {} },
210 },
211 [CPRH_KBSS_PERFORMANCE_CLUSTER_ID] = {
212 {{69, 26, 29}, {} },
213 {{69, 22, 25}, {} },
214 {{69, 18, 21}, {} },
215 {{69, 14, 17}, {} },
216 },
217};
218
219static const struct cpr3_fuse_param
220sdm660_kbss_ro_sel_param[2][SDM660_KBSS_FUSE_CORNERS][3] = {
221 [CPRH_KBSS_POWER_CLUSTER_ID] = {
222 {{67, 12, 15}, {} },
223 {{67, 8, 11}, {} },
224 {{65, 56, 59}, {} },
225 {{67, 4, 7}, {} },
226 {{67, 0, 3}, {} },
227 },
228 [CPRH_KBSS_PERFORMANCE_CLUSTER_ID] = {
229 {{68, 61, 63}, {69, 0, 0} },
230 {{69, 1, 4}, {} },
231 {{68, 57, 60}, {} },
232 {{68, 53, 56}, {} },
233 {{66, 14, 17}, {} },
234 },
235};
236
237static const struct cpr3_fuse_param
238msm8998_kbss_init_voltage_param[2][MSM8998_KBSS_FUSE_CORNERS][2] = {
239 [CPRH_KBSS_POWER_CLUSTER_ID] = {
240 {{67, 34, 39}, {} },
241 {{67, 28, 33}, {} },
242 {{67, 22, 27}, {} },
243 {{67, 16, 21}, {} },
244 },
245 [CPRH_KBSS_PERFORMANCE_CLUSTER_ID] = {
246 {{69, 48, 53}, {} },
247 {{69, 42, 47}, {} },
248 {{69, 36, 41}, {} },
249 {{69, 30, 35}, {} },
250 },
251};
252
253static const struct cpr3_fuse_param
254sdm660_kbss_init_voltage_param[2][SDM660_KBSS_FUSE_CORNERS][2] = {
255 [CPRH_KBSS_POWER_CLUSTER_ID] = {
256 {{67, 34, 39}, {} },
257 {{67, 28, 33}, {} },
258 {{71, 3, 8}, {} },
259 {{67, 22, 27}, {} },
260 {{67, 16, 21}, {} },
261 },
262 [CPRH_KBSS_PERFORMANCE_CLUSTER_ID] = {
263 {{69, 17, 22}, {} },
264 {{69, 23, 28}, {} },
265 {{69, 11, 16}, {} },
266 {{69, 5, 10}, {} },
267 {{70, 42, 47}, {} },
268 },
269};
270
271static const struct cpr3_fuse_param
272msm8998_kbss_target_quot_param[2][MSM8998_KBSS_FUSE_CORNERS][3] = {
273 [CPRH_KBSS_POWER_CLUSTER_ID] = {
274 {{68, 18, 29}, {} },
275 {{68, 6, 17}, {} },
276 {{67, 58, 63}, {68, 0, 5} },
277 {{67, 46, 57}, {} },
278 },
279 [CPRH_KBSS_PERFORMANCE_CLUSTER_ID] = {
280 {{70, 32, 43}, {} },
281 {{70, 20, 31}, {} },
282 {{70, 8, 19}, {} },
283 {{69, 60, 63}, {70, 0, 7}, {} },
284 },
285};
286
287static const struct cpr3_fuse_param
288sdm660_kbss_target_quot_param[2][SDM660_KBSS_FUSE_CORNERS][3] = {
289 [CPRH_KBSS_POWER_CLUSTER_ID] = {
290 {{68, 12, 23}, {} },
291 {{68, 0, 11}, {} },
292 {{71, 9, 20}, {} },
293 {{67, 52, 63}, {} },
294 {{67, 40, 51}, {} },
295 },
296 [CPRH_KBSS_PERFORMANCE_CLUSTER_ID] = {
297 {{69, 53, 63}, {70, 0, 0}, {} },
298 {{70, 1, 12}, {} },
299 {{69, 41, 52}, {} },
300 {{69, 29, 40}, {} },
301 {{70, 48, 59}, {} },
302 },
303};
304
305static const struct cpr3_fuse_param
306msm8998_kbss_quot_offset_param[2][MSM8998_KBSS_FUSE_CORNERS][3] = {
307 [CPRH_KBSS_POWER_CLUSTER_ID] = {
308 {{} },
309 {{68, 63, 63}, {69, 0, 5}, {} },
310 {{68, 56, 62}, {} },
311 {{68, 49, 55}, {} },
312 },
313 [CPRH_KBSS_PERFORMANCE_CLUSTER_ID] = {
314 {{} },
315 {{71, 13, 15}, {71, 21, 24}, {} },
316 {{71, 6, 12}, {} },
317 {{70, 63, 63}, {71, 0, 5}, {} },
318 },
319};
320
321static const struct cpr3_fuse_param
322sdm660_kbss_quot_offset_param[2][SDM660_KBSS_FUSE_CORNERS][3] = {
323 [CPRH_KBSS_POWER_CLUSTER_ID] = {
324 {{} },
325 {{68, 38, 44}, {} },
326 {{71, 21, 27}, {} },
327 {{68, 31, 37}, {} },
328 {{68, 24, 30}, {} },
329 },
330 [CPRH_KBSS_PERFORMANCE_CLUSTER_ID] = {
331 {{} },
332 {{70, 27, 33}, {} },
333 {{70, 20, 26}, {} },
334 {{70, 13, 19}, {} },
335 {{70, 60, 63}, {71, 0, 2}, {} },
336 },
337};
338
David Collins54f78b72017-02-24 11:18:57 -0800339/*
340 * SDM845 KBSS fuse parameter locations:
341 *
342 * Structs are organized with the following dimensions:
343 * Outer: 0 or 1 for power or performance cluster
344 * Outer-1: 0 or 1 for power cluster or L3 cache
345 * Inner+1: 0 to 3 for fuse corners from lowest to highest corner
346 * Inner: large enough to hold the longest set of parameter segments
347 * which fully defines a fuse parameter, +1 (for NULL
348 * termination). Each segment corresponds to a contiguous group
349 * of bits from a single fuse row. These segments are
350 * concatentated together in order to form the full fuse parameter
351 * value. The segments for a given parameter may correspond to
352 * different fuse rows.
353 */
354static const struct cpr3_fuse_param
David Collins97e4c412017-07-19 17:41:46 -0700355sdm845_v1_kbss_ro_sel_param[2][2][SDM845_KBSS_MAX_FUSE_CORNERS][3] = {
David Collins54f78b72017-02-24 11:18:57 -0800356 [CPRH_KBSS_POWER_CLUSTER_ID] = {
357 [CPRH_KBSS_POWER_CLUSTER_THREAD_ID] = {
358 {{66, 52, 55}, {} },
359 {{66, 48, 51}, {} },
360 {{66, 44, 47}, {} },
David Collinse367ce62017-05-08 18:15:03 -0700361 {{66, 40, 43}, {} },
David Collins54f78b72017-02-24 11:18:57 -0800362 },
363 [CPRH_KBSS_L3_THREAD_ID] = {
364 {{66, 52, 55}, {} },
365 {{66, 48, 51}, {} },
366 {{66, 44, 47}, {} },
David Collinse367ce62017-05-08 18:15:03 -0700367 {{66, 40, 43}, {} },
David Collins54f78b72017-02-24 11:18:57 -0800368 },
369 },
370 [CPRH_KBSS_PERFORMANCE_CLUSTER_ID] = {
371 [CPRH_KBSS_PERFORMANCE_CLUSTER_THREAD_ID] = {
372 {{70, 6, 9}, {} },
373 {{70, 2, 5}, {} },
374 {{69, 62, 63}, {70, 0, 1}, {} },
375 },
376 },
377};
378
379static const struct cpr3_fuse_param
David Collins97e4c412017-07-19 17:41:46 -0700380sdm845_v2_kbss_ro_sel_param[2][2][SDM845_KBSS_MAX_FUSE_CORNERS][3] = {
381 [CPRH_KBSS_POWER_CLUSTER_ID] = {
382 [CPRH_KBSS_POWER_CLUSTER_THREAD_ID] = {
383 {{66, 52, 55}, {} },
384 {{66, 48, 51}, {} },
385 {{66, 44, 47}, {} },
386 {{66, 40, 43}, {} },
387 },
388 [CPRH_KBSS_L3_THREAD_ID] = {
389 {{66, 52, 55}, {} },
390 {{66, 48, 51}, {} },
391 {{66, 44, 47}, {} },
392 {{66, 40, 43}, {} },
393 },
394 },
395 [CPRH_KBSS_PERFORMANCE_CLUSTER_ID] = {
396 [CPRH_KBSS_PERFORMANCE_CLUSTER_THREAD_ID] = {
397 {{73, 5, 8}, {} },
398 {{70, 12, 15}, {} },
399 {{70, 8, 11}, {} },
400 {{70, 4, 7}, {} },
401 {{70, 0, 3}, {} },
402 },
403 },
404};
405
406static const struct cpr3_fuse_param
407sdm845_v1_kbss_init_voltage_param[2][2][SDM845_KBSS_MAX_FUSE_CORNERS][3] = {
David Collins54f78b72017-02-24 11:18:57 -0800408 [CPRH_KBSS_POWER_CLUSTER_ID] = {
409 [CPRH_KBSS_POWER_CLUSTER_THREAD_ID] = {
410 {{67, 10, 15}, {} },
411 {{67, 4, 9}, {} },
412 {{66, 62, 63}, {67, 0, 3}, {} },
David Collinse367ce62017-05-08 18:15:03 -0700413 {{66, 56, 61}, {} },
David Collins54f78b72017-02-24 11:18:57 -0800414 },
415 [CPRH_KBSS_L3_THREAD_ID] = {
416 {{68, 47, 52}, {} },
417 {{68, 41, 46}, {} },
418 {{68, 35, 40}, {} },
David Collinse367ce62017-05-08 18:15:03 -0700419 {{68, 29, 34}, {} },
David Collins54f78b72017-02-24 11:18:57 -0800420 },
421 },
422 [CPRH_KBSS_PERFORMANCE_CLUSTER_ID] = {
423 [CPRH_KBSS_PERFORMANCE_CLUSTER_THREAD_ID] = {
424 {{70, 28, 33}, {} },
425 {{70, 22, 27}, {} },
426 {{70, 16, 21}, {} },
427 },
428 },
429};
430
431static const struct cpr3_fuse_param
David Collins97e4c412017-07-19 17:41:46 -0700432sdm845_v2_kbss_init_voltage_param[2][2][SDM845_KBSS_MAX_FUSE_CORNERS][3] = {
433 [CPRH_KBSS_POWER_CLUSTER_ID] = {
434 [CPRH_KBSS_POWER_CLUSTER_THREAD_ID] = {
435 {{67, 10, 15}, {} },
436 {{67, 4, 9}, {} },
437 {{66, 62, 63}, {67, 0, 3}, {} },
438 {{66, 56, 61}, {} },
439 },
440 [CPRH_KBSS_L3_THREAD_ID] = {
441 {{68, 50, 55}, {} },
442 {{68, 44, 49}, {} },
443 {{68, 38, 43}, {} },
444 {{68, 32, 37}, {} },
445 },
446 },
447 [CPRH_KBSS_PERFORMANCE_CLUSTER_ID] = {
448 [CPRH_KBSS_PERFORMANCE_CLUSTER_THREAD_ID] = {
449 {{72, 10, 15}, {} },
450 {{70, 34, 39}, {} },
451 {{70, 28, 33}, {} },
452 {{70, 22, 27}, {} },
453 {{70, 16, 21}, {} },
454 },
455 },
456};
457
458static const struct cpr3_fuse_param
459sdm845_v1_kbss_target_quot_param[2][2][SDM845_KBSS_MAX_FUSE_CORNERS][3] = {
David Collins54f78b72017-02-24 11:18:57 -0800460 [CPRH_KBSS_POWER_CLUSTER_ID] = {
461 [CPRH_KBSS_POWER_CLUSTER_THREAD_ID] = {
462 {{67, 52, 63}, {} },
463 {{67, 40, 51}, {} },
464 {{67, 28, 39}, {} },
David Collinse367ce62017-05-08 18:15:03 -0700465 {{67, 16, 27}, {} },
David Collins54f78b72017-02-24 11:18:57 -0800466 },
467 [CPRH_KBSS_L3_THREAD_ID] = {
468 {{69, 25, 36}, {} },
469 {{69, 13, 24}, {} },
470 {{69, 1, 12}, {} },
David Collinse367ce62017-05-08 18:15:03 -0700471 {{68, 53, 63}, {69, 0, 0}, {} },
David Collins54f78b72017-02-24 11:18:57 -0800472 },
473 },
474 [CPRH_KBSS_PERFORMANCE_CLUSTER_ID] = {
475 [CPRH_KBSS_PERFORMANCE_CLUSTER_THREAD_ID] = {
476 {{71, 6, 17}, {} },
477 {{70, 58, 63}, {71, 0, 5}, {} },
478 {{70, 46, 57}, {} },
479 },
480 },
481};
482
483static const struct cpr3_fuse_param
David Collins97e4c412017-07-19 17:41:46 -0700484sdm845_v2_kbss_target_quot_param[2][2][SDM845_KBSS_MAX_FUSE_CORNERS][3] = {
485 [CPRH_KBSS_POWER_CLUSTER_ID] = {
486 [CPRH_KBSS_POWER_CLUSTER_THREAD_ID] = {
487 {{67, 52, 63}, {} },
488 {{67, 40, 51}, {} },
489 {{67, 28, 39}, {} },
490 {{67, 16, 27}, {} },
491 },
492 [CPRH_KBSS_L3_THREAD_ID] = {
493 {{69, 28, 39}, {} },
494 {{69, 16, 27}, {} },
495 {{69, 4, 15}, {} },
496 {{68, 56, 63}, {69, 0, 3}, {} },
497 },
498 },
499 [CPRH_KBSS_PERFORMANCE_CLUSTER_ID] = {
500 [CPRH_KBSS_PERFORMANCE_CLUSTER_THREAD_ID] = {
501 {{72, 16, 27}, {} },
502 {{71, 12, 23}, {} },
503 {{71, 0, 11}, {} },
504 {{70, 52, 63}, {} },
505 {{70, 40, 51}, {} },
506 },
507 },
508};
509
510static const struct cpr3_fuse_param
511sdm845_v1_kbss_quot_offset_param[2][2][SDM845_KBSS_MAX_FUSE_CORNERS][2] = {
David Collins54f78b72017-02-24 11:18:57 -0800512 [CPRH_KBSS_POWER_CLUSTER_ID] = {
513 [CPRH_KBSS_POWER_CLUSTER_THREAD_ID] = {
514 {{} },
515 {{68, 14, 20}, {} },
516 {{68, 7, 13}, {} },
David Collinse367ce62017-05-08 18:15:03 -0700517 {{68, 0, 6}, {} },
David Collins54f78b72017-02-24 11:18:57 -0800518 },
519 [CPRH_KBSS_L3_THREAD_ID] = {
520 {{} },
521 {{69, 51, 57}, {} },
522 {{69, 44, 50}, {} },
David Collinse367ce62017-05-08 18:15:03 -0700523 {{69, 37, 43}, {} },
David Collins54f78b72017-02-24 11:18:57 -0800524 },
525 },
526 [CPRH_KBSS_PERFORMANCE_CLUSTER_ID] = {
527 [CPRH_KBSS_PERFORMANCE_CLUSTER_THREAD_ID] = {
528 {{} },
529 {{71, 32, 38}, {} },
530 {{71, 25, 31}, {} },
531 },
532 },
533};
534
David Collins97e4c412017-07-19 17:41:46 -0700535static const struct cpr3_fuse_param
536sdm845_v2_kbss_quot_offset_param[2][2][SDM845_KBSS_MAX_FUSE_CORNERS][2] = {
537 [CPRH_KBSS_POWER_CLUSTER_ID] = {
538 [CPRH_KBSS_POWER_CLUSTER_THREAD_ID] = {
539 {{} },
540 {{68, 16, 23}, {} },
541 {{68, 8, 15}, {} },
542 {{68, 0, 7}, {} },
543 },
544 [CPRH_KBSS_L3_THREAD_ID] = {
545 {{} },
546 {{69, 56, 63}, {} },
547 {{69, 48, 55}, {} },
548 {{69, 40, 47}, {} },
549 },
550 },
551 [CPRH_KBSS_PERFORMANCE_CLUSTER_ID] = {
552 [CPRH_KBSS_PERFORMANCE_CLUSTER_THREAD_ID] = {
553 {{} },
554 {{72, 28, 35}, {} },
555 {{71, 40, 47}, {} },
556 {{71, 32, 39}, {} },
557 {{71, 24, 31}, {} },
558 },
559 },
560};
561
David Collins7370f1a2017-01-18 16:21:53 -0800562static const struct cpr3_fuse_param msm8998_cpr_fusing_rev_param[] = {
563 {39, 51, 53},
564 {},
565};
566
567static const struct cpr3_fuse_param sdm660_cpr_fusing_rev_param[] = {
568 {71, 28, 30},
569 {},
570};
571
David Collins97e4c412017-07-19 17:41:46 -0700572static const struct cpr3_fuse_param sdm845_v1_cpr_fusing_rev_param[] = {
David Collins54f78b72017-02-24 11:18:57 -0800573 {73, 3, 5},
574 {},
575};
576
David Collins97e4c412017-07-19 17:41:46 -0700577static const struct cpr3_fuse_param sdm845_v2_cpr_fusing_rev_param[] = {
578 {75, 34, 36},
579 {},
580};
581
David Collins7370f1a2017-01-18 16:21:53 -0800582static const struct cpr3_fuse_param kbss_speed_bin_param[] = {
583 {38, 29, 31},
584 {},
585};
586
587static const struct cpr3_fuse_param
588msm8998_cpr_force_highest_corner_param[] = {
589 {100, 45, 45},
590 {},
591};
592
593static const struct cpr3_fuse_param
David Collins54f78b72017-02-24 11:18:57 -0800594sdm845_cpr_force_highest_corner_param[] = {
595 {100, 45, 45},
596 {},
597};
598
599static const struct cpr3_fuse_param
David Collins7370f1a2017-01-18 16:21:53 -0800600msm8998_kbss_aging_init_quot_diff_param[2][2] = {
601 [CPRH_KBSS_POWER_CLUSTER_ID] = {
602 {69, 6, 13},
603 {},
604 },
605 [CPRH_KBSS_PERFORMANCE_CLUSTER_ID] = {
606 {71, 25, 32},
607 {},
608 },
609};
610
611static const struct cpr3_fuse_param
612sdm660_kbss_aging_init_quot_diff_param[2][2] = {
613 [CPRH_KBSS_POWER_CLUSTER_ID] = {
614 {68, 45, 52},
615 {},
616 },
617 [CPRH_KBSS_PERFORMANCE_CLUSTER_ID] = {
618 {70, 34, 41},
619 {},
620 },
621};
622
David Collins54f78b72017-02-24 11:18:57 -0800623static const struct cpr3_fuse_param
David Collins97e4c412017-07-19 17:41:46 -0700624sdm845_v1_kbss_aging_init_quot_diff_param[2][2] = {
David Collins54f78b72017-02-24 11:18:57 -0800625 [CPRH_KBSS_POWER_CLUSTER_ID] = {
626 {68, 21, 28},
627 {},
628 },
629 [CPRH_KBSS_PERFORMANCE_CLUSTER_ID] = {
630 {71, 39, 46},
631 {},
632 },
633};
634
David Collins97e4c412017-07-19 17:41:46 -0700635static const struct cpr3_fuse_param
636sdm845_v2_kbss_aging_init_quot_diff_param[2][2] = {
637 [CPRH_KBSS_POWER_CLUSTER_ID] = {
638 {68, 24, 31},
639 {},
640 },
641 [CPRH_KBSS_PERFORMANCE_CLUSTER_ID] = {
642 {71, 48, 55},
643 {},
644 },
645};
646
David Collins7370f1a2017-01-18 16:21:53 -0800647/*
648 * Open loop voltage fuse reference voltages in microvolts for MSM8998 v1
649 */
650static const int
651msm8998_v1_kbss_fuse_ref_volt[MSM8998_KBSS_FUSE_CORNERS] = {
652 696000,
653 768000,
654 896000,
655 1112000,
656};
657
658/*
659 * Open loop voltage fuse reference voltages in microvolts for MSM8998 v2
660 */
661static const int
662msm8998_v2_kbss_fuse_ref_volt[2][MSM8998_KBSS_FUSE_CORNERS] = {
663 [CPRH_KBSS_POWER_CLUSTER_ID] = {
664 688000,
665 756000,
666 828000,
667 1056000,
668 },
669 [CPRH_KBSS_PERFORMANCE_CLUSTER_ID] = {
670 756000,
671 756000,
672 828000,
673 1056000,
674 },
675};
676
677/*
678 * Open loop voltage fuse reference voltages in microvolts for SDM660
679 */
680static const int
681sdm660_kbss_fuse_ref_volt[2][SDM660_KBSS_FUSE_CORNERS] = {
682 [CPRH_KBSS_POWER_CLUSTER_ID] = {
683 644000,
684 724000,
685 788000,
686 868000,
687 1068000,
688 },
689 [CPRH_KBSS_PERFORMANCE_CLUSTER_ID] = {
690 724000,
691 788000,
692 868000,
693 988000,
694 1068000,
695 },
696};
697
David Collins54f78b72017-02-24 11:18:57 -0800698/*
699 * Open loop voltage fuse reference voltages in microvolts for SDM845
700 */
701static const int
David Collins97e4c412017-07-19 17:41:46 -0700702sdm845_v1_kbss_fuse_ref_volt[2][2][SDM845_KBSS_MAX_FUSE_CORNERS] = {
David Collins54f78b72017-02-24 11:18:57 -0800703 [CPRH_KBSS_POWER_CLUSTER_ID] = {
704 [CPRH_KBSS_POWER_CLUSTER_THREAD_ID] = {
705 688000,
706 812000,
David Collinse899e132017-03-20 14:13:43 -0700707 896000,
David Collinse367ce62017-05-08 18:15:03 -0700708 900000,
David Collins54f78b72017-02-24 11:18:57 -0800709 },
710 [CPRH_KBSS_L3_THREAD_ID] = {
711 688000,
712 812000,
David Collinse899e132017-03-20 14:13:43 -0700713 896000,
David Collinse367ce62017-05-08 18:15:03 -0700714 900000,
David Collins54f78b72017-02-24 11:18:57 -0800715 },
716 },
717 [CPRH_KBSS_PERFORMANCE_CLUSTER_ID] = {
718 [CPRH_KBSS_PERFORMANCE_CLUSTER_THREAD_ID] = {
719 756000,
720 828000,
David Collinse899e132017-03-20 14:13:43 -0700721 1000000,
David Collins54f78b72017-02-24 11:18:57 -0800722 },
723 },
724};
725
David Collins97e4c412017-07-19 17:41:46 -0700726static const int
727sdm845_v2_kbss_fuse_ref_volt[2][2][SDM845_KBSS_MAX_FUSE_CORNERS] = {
728 [CPRH_KBSS_POWER_CLUSTER_ID] = {
729 [CPRH_KBSS_POWER_CLUSTER_THREAD_ID] = {
730 688000,
731 812000,
732 828000,
733 952000,
734 },
735 [CPRH_KBSS_L3_THREAD_ID] = {
736 688000,
737 812000,
738 828000,
739 952000,
740 },
741 },
742 [CPRH_KBSS_PERFORMANCE_CLUSTER_ID] = {
743 [CPRH_KBSS_PERFORMANCE_CLUSTER_THREAD_ID] = {
744 688000,
745 812000,
746 884000,
747 1000000,
748 1000000,
749 },
750 },
751};
752
David Collins7370f1a2017-01-18 16:21:53 -0800753#define CPRH_KBSS_FUSE_STEP_VOLT 10000
David Collinse899e132017-03-20 14:13:43 -0700754#define CPRH_SDM845_KBSS_FUSE_STEP_VOLT 8000
David Collins7370f1a2017-01-18 16:21:53 -0800755#define CPRH_KBSS_VOLTAGE_FUSE_SIZE 6
756#define CPRH_KBSS_QUOT_OFFSET_SCALE 5
757#define CPRH_KBSS_AGING_INIT_QUOT_DIFF_SIZE 8
758#define CPRH_KBSS_AGING_INIT_QUOT_DIFF_SCALE 1
759
760#define CPRH_KBSS_CPR_CLOCK_RATE 19200000
761
762#define CPRH_KBSS_MAX_CORNER_BAND_COUNT 4
763#define CPRH_KBSS_MAX_CORNER_COUNT 40
764
765#define CPRH_KBSS_CPR_SDELTA_CORE_COUNT 4
766
767#define CPRH_KBSS_MAX_TEMP_POINTS 3
768
769/*
770 * msm8998 configuration
771 */
772#define MSM8998_KBSS_POWER_CPR_SENSOR_COUNT 6
773#define MSM8998_KBSS_PERFORMANCE_CPR_SENSOR_COUNT 9
774
775#define MSM8998_KBSS_POWER_TEMP_SENSOR_ID_START 1
776#define MSM8998_KBSS_POWER_TEMP_SENSOR_ID_END 5
777#define MSM8998_KBSS_PERFORMANCE_TEMP_SENSOR_ID_START 6
778#define MSM8998_KBSS_PERFORMANCE_TEMP_SENSOR_ID_END 10
779
780#define MSM8998_KBSS_POWER_AGING_SENSOR_ID 0
781#define MSM8998_KBSS_POWER_AGING_BYPASS_MASK0 0
782
783#define MSM8998_KBSS_PERFORMANCE_AGING_SENSOR_ID 0
784#define MSM8998_KBSS_PERFORMANCE_AGING_BYPASS_MASK0 0
785
786/*
787 * sdm660 configuration
788 */
789#define SDM660_KBSS_POWER_CPR_SENSOR_COUNT 6
790#define SDM660_KBSS_PERFORMANCE_CPR_SENSOR_COUNT 9
791
792#define SDM660_KBSS_POWER_TEMP_SENSOR_ID_START 10
793#define SDM660_KBSS_POWER_TEMP_SENSOR_ID_END 11
794#define SDM660_KBSS_PERFORMANCE_TEMP_SENSOR_ID_START 4
795#define SDM660_KBSS_PERFORMANCE_TEMP_SENSOR_ID_END 9
796
797#define SDM660_KBSS_POWER_AGING_SENSOR_ID 0
798#define SDM660_KBSS_POWER_AGING_BYPASS_MASK0 0
799
800#define SDM660_KBSS_PERFORMANCE_AGING_SENSOR_ID 0
801#define SDM660_KBSS_PERFORMANCE_AGING_BYPASS_MASK0 0
802
803/*
David Collins54f78b72017-02-24 11:18:57 -0800804 * sdm845 configuration
805 */
806#define SDM845_KBSS_POWER_CPR_SENSOR_COUNT 8
807#define SDM845_KBSS_L3_THREAD_CPR_SENSOR_ID_START 0
808#define SDM845_KBSS_L3_THREAD_CPR_SENSOR_ID_END 3
809#define SDM845_KBSS_POWER_THREAD_CPR_SENSOR_ID_START 4
810#define SDM845_KBSS_POWER_THREAD_CPR_SENSOR_ID_END 7
811
812#define SDM845_KBSS_PERFORMANCE_CPR_SENSOR_COUNT 14
813
814#define SDM845_KBSS_POWER_TEMP_SENSOR_ID_START 1
815#define SDM845_KBSS_POWER_TEMP_SENSOR_ID_END 5
816#define SDM845_KBSS_PERFORMANCE_TEMP_SENSOR_ID_START 6
817#define SDM845_KBSS_PERFORMANCE_TEMP_SENSOR_ID_END 10
818
819#define SDM845_KBSS_POWER_AGING_SENSOR_ID 0
820#define SDM845_KBSS_POWER_AGING_BYPASS_MASK0 0
821
822#define SDM845_KBSS_PERFORMANCE_AGING_SENSOR_ID 0
823#define SDM845_KBSS_PERFORMANCE_AGING_BYPASS_MASK0 0
824
825/*
David Collins7370f1a2017-01-18 16:21:53 -0800826 * SOC IDs
827 */
828enum soc_id {
David Collins54f78b72017-02-24 11:18:57 -0800829 MSM8998_V1_SOC_ID = 1,
830 MSM8998_V2_SOC_ID = 2,
831 SDM660_SOC_ID = 3,
832 SDM845_V1_SOC_ID = 4,
833 SDM845_V2_SOC_ID = 5,
David Collins7370f1a2017-01-18 16:21:53 -0800834};
835
836/**
David Collins54f78b72017-02-24 11:18:57 -0800837 * cprh_kbss_get_thread_id() - get the logical fusing thread ID for a CPR3
838 * thread
839 * @thread: Pointer to the CPR3 thread
840 *
841 * Return: CPR3 thread's thread ID fuse parameter index
842 */
843static u32 cprh_kbss_get_thread_id(struct cpr3_thread *thread)
844{
845 int thread_id = thread->thread_id;
846
847 /* Power cluster and L3 cache CPR threads are swapped on SDM845 v1 */
848 if (thread->ctrl->soc_revision == SDM845_V1_SOC_ID
849 && thread->ctrl->ctrl_id == CPRH_KBSS_POWER_CLUSTER_ID)
850 thread_id = thread_id == CPRH_KBSS_POWER_CLUSTER_THREAD_ID
851 ? CPRH_KBSS_L3_THREAD_ID
852 : CPRH_KBSS_POWER_CLUSTER_THREAD_ID;
853
854 return thread_id;
855}
856
857/**
David Collins7370f1a2017-01-18 16:21:53 -0800858 * cprh_msm8998_kbss_read_fuse_data() - load msm8998 KBSS specific fuse
859 * parameter values
860 * @vreg: Pointer to the CPR3 regulator
861 * @fuse: KBSS specific fuse data
862 *
863 * This function fills cprh_kbss_fuses struct with values read out of hardware
864 * fuses.
865 *
866 * Return: 0 on success, errno on failure
867 */
868static int cprh_msm8998_kbss_read_fuse_data(struct cpr3_regulator *vreg,
869 struct cprh_kbss_fuses *fuse)
870{
871 void __iomem *base = vreg->thread->ctrl->fuse_base;
872 int i, id, rc;
873
874 rc = cpr3_read_fuse_param(base, msm8998_cpr_fusing_rev_param,
875 &fuse->cpr_fusing_rev);
876 if (rc) {
877 cpr3_err(vreg, "Unable to read CPR fusing revision fuse, rc=%d\n",
878 rc);
879 return rc;
880 }
881 cpr3_info(vreg, "CPR fusing revision = %llu\n", fuse->cpr_fusing_rev);
882
883 id = vreg->thread->ctrl->ctrl_id;
884 for (i = 0; i < MSM8998_KBSS_FUSE_CORNERS; i++) {
885 rc = cpr3_read_fuse_param(base,
886 msm8998_kbss_init_voltage_param[id][i],
887 &fuse->init_voltage[i]);
888 if (rc) {
889 cpr3_err(vreg, "Unable to read fuse-corner %d initial voltage fuse, rc=%d\n",
890 i, rc);
891 return rc;
892 }
893
894 rc = cpr3_read_fuse_param(base,
895 msm8998_kbss_target_quot_param[id][i],
896 &fuse->target_quot[i]);
897 if (rc) {
898 cpr3_err(vreg, "Unable to read fuse-corner %d target quotient fuse, rc=%d\n",
899 i, rc);
900 return rc;
901 }
902
903 rc = cpr3_read_fuse_param(base,
904 msm8998_kbss_ro_sel_param[id][i],
905 &fuse->ro_sel[i]);
906 if (rc) {
907 cpr3_err(vreg, "Unable to read fuse-corner %d RO select fuse, rc=%d\n",
908 i, rc);
909 return rc;
910 }
911
912 rc = cpr3_read_fuse_param(base,
913 msm8998_kbss_quot_offset_param[id][i],
914 &fuse->quot_offset[i]);
915 if (rc) {
916 cpr3_err(vreg, "Unable to read fuse-corner %d quotient offset fuse, rc=%d\n",
917 i, rc);
918 return rc;
919 }
920
921 }
922
923 rc = cpr3_read_fuse_param(base,
924 msm8998_kbss_aging_init_quot_diff_param[id],
925 &fuse->aging_init_quot_diff);
926 if (rc) {
927 cpr3_err(vreg, "Unable to read aging initial quotient difference fuse, rc=%d\n",
928 rc);
929 return rc;
930 }
931
932 rc = cpr3_read_fuse_param(base,
933 msm8998_cpr_force_highest_corner_param,
934 &fuse->force_highest_corner);
935 if (rc) {
936 cpr3_err(vreg, "Unable to read CPR force highest corner fuse, rc=%d\n",
937 rc);
938 return rc;
939 }
940
941 if (fuse->force_highest_corner)
942 cpr3_info(vreg, "Fusing requires all operation at the highest corner\n");
943
944 vreg->fuse_combo = fuse->cpr_fusing_rev + 8 * fuse->speed_bin;
945 if (vreg->fuse_combo >= CPRH_MSM8998_KBSS_FUSE_COMBO_COUNT) {
946 cpr3_err(vreg, "invalid CPR fuse combo = %d found\n",
947 vreg->fuse_combo);
948 return -EINVAL;
949 }
950
951 return rc;
952};
953
954/**
955 * cprh_sdm660_kbss_read_fuse_data() - load SDM660 KBSS specific fuse parameter
956 * values
957 * @vreg: Pointer to the CPR3 regulator
958 * @fuse: KBSS specific fuse data
959 *
960 * This function fills cprh_kbss_fuses struct with values read out of hardware
961 * fuses.
962 *
963 * Return: 0 on success, errno on failure
964 */
965static int cprh_sdm660_kbss_read_fuse_data(struct cpr3_regulator *vreg,
966 struct cprh_kbss_fuses *fuse)
967{
968 void __iomem *base = vreg->thread->ctrl->fuse_base;
969 int i, id, rc;
970
971 rc = cpr3_read_fuse_param(base, sdm660_cpr_fusing_rev_param,
972 &fuse->cpr_fusing_rev);
973 if (rc) {
974 cpr3_err(vreg, "Unable to read CPR fusing revision fuse, rc=%d\n",
975 rc);
976 return rc;
977 }
978 cpr3_info(vreg, "CPR fusing revision = %llu\n", fuse->cpr_fusing_rev);
979
980 id = vreg->thread->ctrl->ctrl_id;
981 for (i = 0; i < SDM660_KBSS_FUSE_CORNERS; i++) {
982 rc = cpr3_read_fuse_param(base,
983 sdm660_kbss_init_voltage_param[id][i],
984 &fuse->init_voltage[i]);
985 if (rc) {
986 cpr3_err(vreg, "Unable to read fuse-corner %d initial voltage fuse, rc=%d\n",
987 i, rc);
988 return rc;
989 }
990
991 rc = cpr3_read_fuse_param(base,
992 sdm660_kbss_target_quot_param[id][i],
993 &fuse->target_quot[i]);
994 if (rc) {
995 cpr3_err(vreg, "Unable to read fuse-corner %d target quotient fuse, rc=%d\n",
996 i, rc);
997 return rc;
998 }
999
1000 rc = cpr3_read_fuse_param(base,
1001 sdm660_kbss_ro_sel_param[id][i],
1002 &fuse->ro_sel[i]);
1003 if (rc) {
1004 cpr3_err(vreg, "Unable to read fuse-corner %d RO select fuse, rc=%d\n",
1005 i, rc);
1006 return rc;
1007 }
1008
1009 rc = cpr3_read_fuse_param(base,
1010 sdm660_kbss_quot_offset_param[id][i],
1011 &fuse->quot_offset[i]);
1012 if (rc) {
1013 cpr3_err(vreg, "Unable to read fuse-corner %d quotient offset fuse, rc=%d\n",
1014 i, rc);
1015 return rc;
1016 }
1017 }
1018
1019 rc = cpr3_read_fuse_param(base,
1020 sdm660_kbss_aging_init_quot_diff_param[id],
1021 &fuse->aging_init_quot_diff);
1022 if (rc) {
1023 cpr3_err(vreg, "Unable to read aging initial quotient difference fuse, rc=%d\n",
1024 rc);
1025 return rc;
1026 }
1027
1028 vreg->fuse_combo = fuse->cpr_fusing_rev + 8 * fuse->speed_bin;
1029 if (vreg->fuse_combo >= CPRH_SDM660_KBSS_FUSE_COMBO_COUNT) {
1030 cpr3_err(vreg, "invalid CPR fuse combo = %d found\n",
1031 vreg->fuse_combo);
1032 return -EINVAL;
1033 }
1034
1035 return rc;
1036};
1037
1038/**
David Collins54f78b72017-02-24 11:18:57 -08001039 * cprh_sdm845_kbss_read_fuse_data() - load sdm845 KBSS specific fuse parameter
1040 * values
1041 * @vreg: Pointer to the CPR3 regulator
1042 * @fuse: KBSS specific fuse data
1043 *
1044 * This function fills cprh_kbss_fuses struct with values read out of hardware
1045 * fuses.
1046 *
1047 * Return: 0 on success, errno on failure
1048 */
1049static int cprh_sdm845_kbss_read_fuse_data(struct cpr3_regulator *vreg,
1050 struct cprh_kbss_fuses *fuse)
1051{
1052 void __iomem *base = vreg->thread->ctrl->fuse_base;
David Collins97e4c412017-07-19 17:41:46 -07001053 bool is_v1 = (vreg->thread->ctrl->soc_revision == SDM845_V1_SOC_ID);
David Collins54f78b72017-02-24 11:18:57 -08001054 int i, cid, tid, rc;
1055
David Collins97e4c412017-07-19 17:41:46 -07001056 rc = cpr3_read_fuse_param(base, is_v1 ? sdm845_v1_cpr_fusing_rev_param
1057 : sdm845_v2_cpr_fusing_rev_param,
David Collins54f78b72017-02-24 11:18:57 -08001058 &fuse->cpr_fusing_rev);
1059 if (rc) {
1060 cpr3_err(vreg, "Unable to read CPR fusing revision fuse, rc=%d\n",
1061 rc);
1062 return rc;
1063 }
1064 cpr3_info(vreg, "CPR fusing revision = %llu\n", fuse->cpr_fusing_rev);
1065
1066 tid = cprh_kbss_get_thread_id(vreg->thread);
1067 cid = vreg->thread->ctrl->ctrl_id;
1068
1069 for (i = 0; i < vreg->fuse_corner_count; i++) {
David Collins97e4c412017-07-19 17:41:46 -07001070 rc = cpr3_read_fuse_param(base, is_v1 ?
1071 sdm845_v1_kbss_init_voltage_param[cid][tid][i] :
1072 sdm845_v2_kbss_init_voltage_param[cid][tid][i],
David Collins54f78b72017-02-24 11:18:57 -08001073 &fuse->init_voltage[i]);
1074 if (rc) {
1075 cpr3_err(vreg, "Unable to read fuse-corner %d initial voltage fuse, rc=%d\n",
1076 i, rc);
1077 return rc;
1078 }
1079
David Collins97e4c412017-07-19 17:41:46 -07001080 rc = cpr3_read_fuse_param(base, is_v1 ?
1081 sdm845_v1_kbss_target_quot_param[cid][tid][i] :
1082 sdm845_v2_kbss_target_quot_param[cid][tid][i],
David Collins54f78b72017-02-24 11:18:57 -08001083 &fuse->target_quot[i]);
1084 if (rc) {
1085 cpr3_err(vreg, "Unable to read fuse-corner %d target quotient fuse, rc=%d\n",
1086 i, rc);
1087 return rc;
1088 }
1089
David Collins97e4c412017-07-19 17:41:46 -07001090 rc = cpr3_read_fuse_param(base, is_v1 ?
1091 sdm845_v1_kbss_ro_sel_param[cid][tid][i] :
1092 sdm845_v2_kbss_ro_sel_param[cid][tid][i],
David Collins54f78b72017-02-24 11:18:57 -08001093 &fuse->ro_sel[i]);
1094 if (rc) {
1095 cpr3_err(vreg, "Unable to read fuse-corner %d RO select fuse, rc=%d\n",
1096 i, rc);
1097 return rc;
1098 }
1099
David Collins97e4c412017-07-19 17:41:46 -07001100 rc = cpr3_read_fuse_param(base, is_v1 ?
1101 sdm845_v1_kbss_quot_offset_param[cid][tid][i] :
1102 sdm845_v2_kbss_quot_offset_param[cid][tid][i],
David Collins54f78b72017-02-24 11:18:57 -08001103 &fuse->quot_offset[i]);
1104 if (rc) {
1105 cpr3_err(vreg, "Unable to read fuse-corner %d quotient offset fuse, rc=%d\n",
1106 i, rc);
1107 return rc;
1108 }
1109 }
1110
David Collins97e4c412017-07-19 17:41:46 -07001111 rc = cpr3_read_fuse_param(base, is_v1 ?
1112 sdm845_v1_kbss_aging_init_quot_diff_param[cid] :
1113 sdm845_v2_kbss_aging_init_quot_diff_param[cid],
David Collins54f78b72017-02-24 11:18:57 -08001114 &fuse->aging_init_quot_diff);
1115 if (rc) {
1116 cpr3_err(vreg, "Unable to read aging initial quotient difference fuse, rc=%d\n",
1117 rc);
1118 return rc;
1119 }
1120
1121 rc = cpr3_read_fuse_param(base,
1122 sdm845_cpr_force_highest_corner_param,
1123 &fuse->force_highest_corner);
1124 if (rc) {
1125 cpr3_err(vreg, "Unable to read CPR force highest corner fuse, rc=%d\n",
1126 rc);
1127 return rc;
1128 }
1129
1130 if (fuse->force_highest_corner)
1131 cpr3_info(vreg, "Fusing requires all operation at the highest corner\n");
1132
1133 vreg->fuse_combo = fuse->cpr_fusing_rev + 8 * fuse->speed_bin;
1134 if (vreg->fuse_combo >= CPRH_SDM845_KBSS_FUSE_COMBO_COUNT) {
1135 cpr3_err(vreg, "invalid CPR fuse combo = %d found\n",
1136 vreg->fuse_combo);
1137 return -EINVAL;
1138 }
1139
1140 return rc;
1141};
1142
1143/**
David Collins7370f1a2017-01-18 16:21:53 -08001144 * cprh_kbss_read_fuse_data() - load KBSS specific fuse parameter values
1145 * @vreg: Pointer to the CPR3 regulator
1146 *
1147 * This function allocates a cprh_kbss_fuses struct, fills it with values
1148 * read out of hardware fuses, and finally copies common fuse values
1149 * into the CPR3 regulator struct.
1150 *
1151 * Return: 0 on success, errno on failure
1152 */
1153static int cprh_kbss_read_fuse_data(struct cpr3_regulator *vreg)
1154{
1155 void __iomem *base = vreg->thread->ctrl->fuse_base;
1156 struct cprh_kbss_fuses *fuse;
1157 int rc, fuse_corners;
1158 enum soc_id soc_revision;
1159
1160 fuse = devm_kzalloc(vreg->thread->ctrl->dev, sizeof(*fuse), GFP_KERNEL);
1161 if (!fuse)
1162 return -ENOMEM;
1163
1164 soc_revision = vreg->thread->ctrl->soc_revision;
1165 switch (soc_revision) {
1166 case SDM660_SOC_ID:
1167 fuse_corners = SDM660_KBSS_FUSE_CORNERS;
1168 break;
1169 case MSM8998_V1_SOC_ID:
1170 case MSM8998_V2_SOC_ID:
1171 fuse_corners = MSM8998_KBSS_FUSE_CORNERS;
1172 break;
David Collins54f78b72017-02-24 11:18:57 -08001173 case SDM845_V1_SOC_ID:
David Collins97e4c412017-07-19 17:41:46 -07001174 fuse_corners = vreg->thread->ctrl->ctrl_id
1175 == CPRH_KBSS_POWER_CLUSTER_ID
1176 ? SDM845_KBSS_POWER_CLUSTER_FUSE_CORNERS
1177 : SDM845_V1_KBSS_PERF_CLUSTER_FUSE_CORNERS;
1178 break;
David Collins54f78b72017-02-24 11:18:57 -08001179 case SDM845_V2_SOC_ID:
David Collinse367ce62017-05-08 18:15:03 -07001180 fuse_corners = vreg->thread->ctrl->ctrl_id
1181 == CPRH_KBSS_POWER_CLUSTER_ID
1182 ? SDM845_KBSS_POWER_CLUSTER_FUSE_CORNERS
David Collins97e4c412017-07-19 17:41:46 -07001183 : SDM845_V2_KBSS_PERF_CLUSTER_FUSE_CORNERS;
David Collins54f78b72017-02-24 11:18:57 -08001184 break;
David Collins7370f1a2017-01-18 16:21:53 -08001185 default:
1186 cpr3_err(vreg, "unsupported soc id = %d\n", soc_revision);
1187 return -EINVAL;
1188 }
1189
David Collins7c8a25a2017-04-18 14:23:08 -07001190 vreg->fuse_corner_count = fuse_corners;
1191 vreg->platform_fuses = fuse;
1192
David Collins7370f1a2017-01-18 16:21:53 -08001193 fuse->ro_sel = devm_kcalloc(vreg->thread->ctrl->dev, fuse_corners,
1194 sizeof(*fuse->ro_sel), GFP_KERNEL);
1195 fuse->init_voltage = devm_kcalloc(vreg->thread->ctrl->dev, fuse_corners,
1196 sizeof(*fuse->init_voltage), GFP_KERNEL);
1197 fuse->target_quot = devm_kcalloc(vreg->thread->ctrl->dev, fuse_corners,
1198 sizeof(*fuse->target_quot), GFP_KERNEL);
1199 fuse->quot_offset = devm_kcalloc(vreg->thread->ctrl->dev, fuse_corners,
1200 sizeof(*fuse->quot_offset), GFP_KERNEL);
1201
1202 if (!fuse->ro_sel || !fuse->init_voltage || !fuse->target_quot
1203 || !fuse->quot_offset)
1204 return -ENOMEM;
1205
1206 rc = cpr3_read_fuse_param(base, kbss_speed_bin_param, &fuse->speed_bin);
1207 if (rc) {
1208 cpr3_err(vreg, "Unable to read speed bin fuse, rc=%d\n", rc);
1209 return rc;
1210 }
1211 cpr3_info(vreg, "speed bin = %llu\n", fuse->speed_bin);
1212
1213 switch (soc_revision) {
1214 case SDM660_SOC_ID:
1215 rc = cprh_sdm660_kbss_read_fuse_data(vreg, fuse);
1216 if (rc) {
1217 cpr3_err(vreg, "sdm660 kbss fuse data read failed, rc=%d\n",
1218 rc);
1219 return rc;
1220 }
1221 break;
1222 case MSM8998_V1_SOC_ID:
1223 case MSM8998_V2_SOC_ID:
1224 rc = cprh_msm8998_kbss_read_fuse_data(vreg, fuse);
1225 if (rc) {
1226 cpr3_err(vreg, "msm8998 kbss fuse data read failed, rc=%d\n",
1227 rc);
1228 return rc;
1229 }
1230 break;
David Collins54f78b72017-02-24 11:18:57 -08001231 case SDM845_V1_SOC_ID:
1232 case SDM845_V2_SOC_ID:
1233 rc = cprh_sdm845_kbss_read_fuse_data(vreg, fuse);
1234 if (rc) {
1235 cpr3_err(vreg, "sdm845 kbss fuse data read failed, rc=%d\n",
1236 rc);
1237 return rc;
1238 }
1239 break;
David Collins7370f1a2017-01-18 16:21:53 -08001240 default:
1241 cpr3_err(vreg, "unsupported soc id = %d\n", soc_revision);
1242 return -EINVAL;
1243 }
1244
1245 vreg->speed_bin_fuse = fuse->speed_bin;
1246 vreg->cpr_rev_fuse = fuse->cpr_fusing_rev;
David Collins7370f1a2017-01-18 16:21:53 -08001247
1248 return 0;
1249}
1250
1251/**
1252 * cprh_kbss_parse_corner_data() - parse KBSS corner data from device tree
1253 * properties of the CPR3 regulator's device node
1254 * @vreg: Pointer to the CPR3 regulator
1255 *
1256 * Return: 0 on success, errno on failure
1257 */
1258static int cprh_kbss_parse_corner_data(struct cpr3_regulator *vreg)
1259{
1260 int rc;
1261
1262 rc = cpr3_parse_common_corner_data(vreg);
1263 if (rc) {
1264 cpr3_err(vreg, "error reading corner data, rc=%d\n", rc);
1265 return rc;
1266 }
1267
1268 /*
1269 * A total of CPRH_KBSS_MAX_CORNER_COUNT - 1 corners
1270 * may be specified in device tree as an additional corner
1271 * must be allocated to correspond to the APM crossover voltage.
1272 */
1273 if (vreg->corner_count > CPRH_KBSS_MAX_CORNER_COUNT - 1) {
1274 cpr3_err(vreg, "corner count %d exceeds supported maximum %d\n",
1275 vreg->corner_count, CPRH_KBSS_MAX_CORNER_COUNT - 1);
1276 return -EINVAL;
1277 }
1278
1279 return rc;
1280}
1281
1282/**
1283 * cprh_kbss_calculate_open_loop_voltages() - calculate the open-loop
1284 * voltage for each corner of a CPR3 regulator
1285 * @vreg: Pointer to the CPR3 regulator
1286 *
1287 * If open-loop voltage interpolation is allowed in device tree, then this
1288 * function calculates the open-loop voltage for a given corner using linear
1289 * interpolation. This interpolation is performed using the processor
1290 * frequencies of the lower and higher Fmax corners along with their fused
1291 * open-loop voltages.
1292 *
1293 * If open-loop voltage interpolation is not allowed, then this function uses
1294 * the Fmax fused open-loop voltage for all of the corners associated with a
1295 * given fuse corner.
1296 *
1297 * Return: 0 on success, errno on failure
1298 */
1299static int cprh_kbss_calculate_open_loop_voltages(struct cpr3_regulator *vreg)
1300{
1301 struct device_node *node = vreg->of_node;
1302 struct cprh_kbss_fuses *fuse = vreg->platform_fuses;
David Collins54f78b72017-02-24 11:18:57 -08001303 int i, j, id, tid, rc = 0;
David Collins7370f1a2017-01-18 16:21:53 -08001304 bool allow_interpolation;
1305 u64 freq_low, volt_low, freq_high, volt_high;
1306 const int *ref_volt;
1307 int *fuse_volt;
1308 int *fmax_corner;
1309 const char * const *corner_name;
1310 enum soc_id soc_revision;
1311
1312 fuse_volt = kcalloc(vreg->fuse_corner_count, sizeof(*fuse_volt),
1313 GFP_KERNEL);
1314 fmax_corner = kcalloc(vreg->fuse_corner_count, sizeof(*fmax_corner),
1315 GFP_KERNEL);
1316 if (!fuse_volt || !fmax_corner) {
1317 rc = -ENOMEM;
1318 goto done;
1319 }
1320
1321 id = vreg->thread->ctrl->ctrl_id;
1322 soc_revision = vreg->thread->ctrl->soc_revision;
1323
1324 switch (soc_revision) {
1325 case SDM660_SOC_ID:
1326 ref_volt = sdm660_kbss_fuse_ref_volt[id];
1327 if (id == CPRH_KBSS_POWER_CLUSTER_ID)
1328 corner_name = cprh_sdm660_power_kbss_fuse_corner_name;
1329 else
1330 corner_name = cprh_sdm660_perf_kbss_fuse_corner_name;
1331 break;
1332 case MSM8998_V1_SOC_ID:
1333 ref_volt = msm8998_v1_kbss_fuse_ref_volt;
1334 corner_name = cprh_msm8998_kbss_fuse_corner_name;
1335 break;
1336 case MSM8998_V2_SOC_ID:
1337 ref_volt = msm8998_v2_kbss_fuse_ref_volt[id];
1338 corner_name = cprh_msm8998_kbss_fuse_corner_name;
1339 break;
David Collins54f78b72017-02-24 11:18:57 -08001340 case SDM845_V1_SOC_ID:
David Collins97e4c412017-07-19 17:41:46 -07001341 tid = cprh_kbss_get_thread_id(vreg->thread);
1342 ref_volt = sdm845_v1_kbss_fuse_ref_volt[id][tid];
1343 corner_name = cprh_sdm845_v1_kbss_fuse_corner_name[id];
1344 break;
David Collins54f78b72017-02-24 11:18:57 -08001345 case SDM845_V2_SOC_ID:
1346 tid = cprh_kbss_get_thread_id(vreg->thread);
David Collins97e4c412017-07-19 17:41:46 -07001347 ref_volt = sdm845_v2_kbss_fuse_ref_volt[id][tid];
1348 corner_name = cprh_sdm845_v2_kbss_fuse_corner_name[id];
David Collins54f78b72017-02-24 11:18:57 -08001349 break;
David Collins7370f1a2017-01-18 16:21:53 -08001350 default:
1351 cpr3_err(vreg, "unsupported soc id = %d\n", soc_revision);
1352 rc = -EINVAL;
1353 goto done;
1354 }
1355
1356 for (i = 0; i < vreg->fuse_corner_count; i++) {
1357 fuse_volt[i] = cpr3_convert_open_loop_voltage_fuse(ref_volt[i],
David Collins54f78b72017-02-24 11:18:57 -08001358 soc_revision == SDM845_V1_SOC_ID
1359 || soc_revision == SDM845_V2_SOC_ID
1360 ? CPRH_SDM845_KBSS_FUSE_STEP_VOLT
1361 : CPRH_KBSS_FUSE_STEP_VOLT,
1362 fuse->init_voltage[i],
David Collins7370f1a2017-01-18 16:21:53 -08001363 CPRH_KBSS_VOLTAGE_FUSE_SIZE);
1364
1365 /* Log fused open-loop voltage values for debugging purposes. */
1366 cpr3_info(vreg, "fused %8s: open-loop=%7d uV\n", corner_name[i],
1367 fuse_volt[i]);
1368 }
1369
1370 rc = cpr3_adjust_fused_open_loop_voltages(vreg, fuse_volt);
1371 if (rc) {
1372 cpr3_err(vreg, "fused open-loop voltage adjustment failed, rc=%d\n",
1373 rc);
1374 goto done;
1375 }
1376
1377 allow_interpolation = of_property_read_bool(node,
1378 "qcom,allow-voltage-interpolation");
1379
1380 for (i = 1; i < vreg->fuse_corner_count; i++) {
1381 if (fuse_volt[i] < fuse_volt[i - 1]) {
1382 cpr3_info(vreg, "fuse corner %d voltage=%d uV < fuse corner %d voltage=%d uV; overriding: fuse corner %d voltage=%d\n",
1383 i, fuse_volt[i], i - 1, fuse_volt[i - 1],
1384 i, fuse_volt[i - 1]);
1385 fuse_volt[i] = fuse_volt[i - 1];
1386 }
1387 }
1388
1389 if (!allow_interpolation) {
1390 /* Use fused open-loop voltage for lower frequencies. */
1391 for (i = 0; i < vreg->corner_count; i++)
1392 vreg->corner[i].open_loop_volt
1393 = fuse_volt[vreg->corner[i].cpr_fuse_corner];
1394 goto done;
1395 }
1396
1397 /* Determine highest corner mapped to each fuse corner */
1398 j = vreg->fuse_corner_count - 1;
1399 for (i = vreg->corner_count - 1; i >= 0; i--) {
1400 if (vreg->corner[i].cpr_fuse_corner == j) {
1401 fmax_corner[j] = i;
1402 j--;
1403 }
1404 }
1405 if (j >= 0) {
1406 cpr3_err(vreg, "invalid fuse corner mapping\n");
1407 rc = -EINVAL;
1408 goto done;
1409 }
1410
1411 /*
1412 * Interpolation is not possible for corners mapped to the lowest fuse
1413 * corner so use the fuse corner value directly.
1414 */
1415 for (i = 0; i <= fmax_corner[0]; i++)
1416 vreg->corner[i].open_loop_volt = fuse_volt[0];
1417
1418 /* Interpolate voltages for the higher fuse corners. */
1419 for (i = 1; i < vreg->fuse_corner_count; i++) {
1420 freq_low = vreg->corner[fmax_corner[i - 1]].proc_freq;
1421 volt_low = fuse_volt[i - 1];
1422 freq_high = vreg->corner[fmax_corner[i]].proc_freq;
1423 volt_high = fuse_volt[i];
1424
1425 for (j = fmax_corner[i - 1] + 1; j <= fmax_corner[i]; j++)
1426 vreg->corner[j].open_loop_volt = cpr3_interpolate(
1427 freq_low, volt_low, freq_high, volt_high,
1428 vreg->corner[j].proc_freq);
1429 }
1430
1431done:
1432 if (rc == 0) {
1433 cpr3_debug(vreg, "unadjusted per-corner open-loop voltages:\n");
1434 for (i = 0; i < vreg->corner_count; i++)
1435 cpr3_debug(vreg, "open-loop[%2d] = %d uV\n", i,
1436 vreg->corner[i].open_loop_volt);
1437
1438 rc = cpr3_adjust_open_loop_voltages(vreg);
1439 if (rc)
1440 cpr3_err(vreg, "open-loop voltage adjustment failed, rc=%d\n",
1441 rc);
1442 }
1443
1444 kfree(fuse_volt);
1445 kfree(fmax_corner);
1446 return rc;
1447}
1448
1449/**
1450 * cprh_msm8998_partial_binning_override() - override the voltage and quotient
1451 * settings for low corners based upon special partial binning
1452 * fuse values
1453 *
1454 * @vreg: Pointer to the CPR3 regulator
1455 *
1456 * Some parts are not able to operate at low voltages. The force highest
1457 * corner fuse specifies if a given part must operate with voltages
1458 * corresponding to the highest corner.
1459 *
1460 * Return: 0 on success, errno on failure
1461 */
1462static int cprh_msm8998_partial_binning_override(struct cpr3_regulator *vreg)
1463{
1464 struct cprh_kbss_fuses *fuse = vreg->platform_fuses;
1465 struct cpr3_corner *corner;
1466 struct cpr4_sdelta *sdelta;
1467 int i;
1468 u32 proc_freq;
1469
1470 if (fuse->force_highest_corner) {
1471 cpr3_info(vreg, "overriding CPR parameters for corners 0 to %d with quotients and voltages of corner %d\n",
1472 vreg->corner_count - 2, vreg->corner_count - 1);
1473 corner = &vreg->corner[vreg->corner_count - 1];
1474 for (i = 0; i < vreg->corner_count - 1; i++) {
1475 proc_freq = vreg->corner[i].proc_freq;
1476 sdelta = vreg->corner[i].sdelta;
1477 if (sdelta) {
1478 if (sdelta->table)
1479 devm_kfree(vreg->thread->ctrl->dev,
1480 sdelta->table);
1481 if (sdelta->boost_table)
1482 devm_kfree(vreg->thread->ctrl->dev,
1483 sdelta->boost_table);
1484 devm_kfree(vreg->thread->ctrl->dev,
1485 sdelta);
1486 }
1487 vreg->corner[i] = *corner;
1488 vreg->corner[i].proc_freq = proc_freq;
1489 }
1490
1491 return 0;
1492 }
1493
1494 return 0;
1495};
1496
1497/**
1498 * cprh_kbss_parse_core_count_temp_adj_properties() - load device tree
1499 * properties associated with per-corner-band and temperature
1500 * voltage adjustments.
1501 * @vreg: Pointer to the CPR3 regulator
1502 *
1503 * Return: 0 on success, errno on failure
1504 */
1505static int cprh_kbss_parse_core_count_temp_adj_properties(
1506 struct cpr3_regulator *vreg)
1507{
1508 struct cpr3_controller *ctrl = vreg->thread->ctrl;
1509 struct device_node *node = vreg->of_node;
1510 u32 *temp, *combo_corner_bands, *speed_bin_corner_bands;
1511 int rc, i, len, temp_point_count;
1512
1513 vreg->allow_core_count_adj = of_find_property(node,
1514 "qcom,corner-band-allow-core-count-adjustment",
1515 NULL);
1516 vreg->allow_temp_adj = of_find_property(node,
1517 "qcom,corner-band-allow-temp-adjustment",
1518 NULL);
1519
1520 if (!vreg->allow_core_count_adj && !vreg->allow_temp_adj)
1521 return 0;
1522
1523 combo_corner_bands = kcalloc(vreg->fuse_combos_supported,
1524 sizeof(*combo_corner_bands),
1525 GFP_KERNEL);
1526 if (!combo_corner_bands)
1527 return -ENOMEM;
1528
1529 rc = of_property_read_u32_array(node, "qcom,cpr-corner-bands",
1530 combo_corner_bands,
1531 vreg->fuse_combos_supported);
1532 if (rc == -EOVERFLOW) {
1533 /* Single value case */
1534 rc = of_property_read_u32(node, "qcom,cpr-corner-bands",
1535 combo_corner_bands);
1536 for (i = 1; i < vreg->fuse_combos_supported; i++)
1537 combo_corner_bands[i] = combo_corner_bands[0];
1538 }
1539 if (rc) {
1540 cpr3_err(vreg, "error reading property qcom,cpr-corner-bands, rc=%d\n",
1541 rc);
1542 kfree(combo_corner_bands);
1543 return rc;
1544 }
1545
1546 vreg->fuse_combo_corner_band_offset = 0;
1547 vreg->fuse_combo_corner_band_sum = 0;
1548 for (i = 0; i < vreg->fuse_combos_supported; i++) {
1549 vreg->fuse_combo_corner_band_sum += combo_corner_bands[i];
1550 if (i < vreg->fuse_combo)
1551 vreg->fuse_combo_corner_band_offset +=
1552 combo_corner_bands[i];
1553 }
1554
1555 vreg->corner_band_count = combo_corner_bands[vreg->fuse_combo];
1556
1557 kfree(combo_corner_bands);
1558
1559 if (vreg->corner_band_count <= 0 ||
1560 vreg->corner_band_count > CPRH_KBSS_MAX_CORNER_BAND_COUNT ||
1561 vreg->corner_band_count > vreg->corner_count) {
1562 cpr3_err(vreg, "invalid corner band count %d > %d (max) for %d corners\n",
1563 vreg->corner_band_count,
1564 CPRH_KBSS_MAX_CORNER_BAND_COUNT,
1565 vreg->corner_count);
1566 return -EINVAL;
1567 }
1568
1569 vreg->speed_bin_corner_band_offset = 0;
1570 vreg->speed_bin_corner_band_sum = 0;
1571 if (vreg->speed_bins_supported > 0) {
1572 speed_bin_corner_bands = kcalloc(vreg->speed_bins_supported,
1573 sizeof(*speed_bin_corner_bands),
1574 GFP_KERNEL);
1575 if (!speed_bin_corner_bands)
1576 return -ENOMEM;
1577
1578 rc = of_property_read_u32_array(node,
1579 "qcom,cpr-speed-bin-corner-bands",
1580 speed_bin_corner_bands,
1581 vreg->speed_bins_supported);
1582 if (rc) {
1583 cpr3_err(vreg, "error reading property qcom,cpr-speed-bin-corner-bands, rc=%d\n",
1584 rc);
1585 kfree(speed_bin_corner_bands);
1586 return rc;
1587 }
1588
1589 for (i = 0; i < vreg->speed_bins_supported; i++) {
1590 vreg->speed_bin_corner_band_sum +=
1591 speed_bin_corner_bands[i];
1592 if (i < vreg->speed_bin_fuse)
1593 vreg->speed_bin_corner_band_offset +=
1594 speed_bin_corner_bands[i];
1595 }
1596
1597 if (speed_bin_corner_bands[vreg->speed_bin_fuse]
1598 != vreg->corner_band_count) {
1599 cpr3_err(vreg, "qcom,cpr-corner-bands and qcom,cpr-speed-bin-corner-bands conflict on number of corners bands: %d vs %u\n",
1600 vreg->corner_band_count,
1601 speed_bin_corner_bands[vreg->speed_bin_fuse]);
1602 kfree(speed_bin_corner_bands);
1603 return -EINVAL;
1604 }
1605
1606 kfree(speed_bin_corner_bands);
1607 }
1608
1609 vreg->corner_band = devm_kcalloc(ctrl->dev,
1610 vreg->corner_band_count,
1611 sizeof(*vreg->corner_band),
1612 GFP_KERNEL);
1613
1614 temp = kcalloc(vreg->corner_band_count, sizeof(*temp), GFP_KERNEL);
1615
1616 if (!vreg->corner_band || !temp) {
1617 rc = -ENOMEM;
1618 goto free_temp;
1619 }
1620
1621 rc = cpr3_parse_corner_band_array_property(vreg,
1622 "qcom,cpr-corner-band-map",
1623 1, temp);
1624 if (rc) {
1625 cpr3_err(vreg, "could not load corner band map, rc=%d\n",
1626 rc);
1627 goto free_temp;
1628 }
1629
1630 for (i = 1; i < vreg->corner_band_count; i++) {
1631 if (temp[i - 1] > temp[i]) {
1632 cpr3_err(vreg, "invalid corner band mapping: band %d corner %d, band %d corner %d\n",
1633 i - 1, temp[i - 1],
1634 i, temp[i]);
1635 rc = -EINVAL;
1636 goto free_temp;
1637 }
1638 }
1639
1640 for (i = 0; i < vreg->corner_band_count; i++)
1641 vreg->corner_band[i].corner = temp[i] - CPR3_CORNER_OFFSET;
1642
1643 if (!of_find_property(ctrl->dev->of_node,
1644 "qcom,cpr-temp-point-map", &len)) {
1645 /*
1646 * Temperature based adjustments are not defined. Single
1647 * temperature band is still valid for per-online-core
1648 * adjustments.
1649 */
1650 ctrl->temp_band_count = 1;
1651 rc = 0;
1652 goto free_temp;
1653 }
1654
1655 if (!vreg->allow_temp_adj) {
1656 rc = 0;
1657 goto free_temp;
1658 }
1659
1660 temp_point_count = len / sizeof(u32);
1661 if (temp_point_count <= 0 || temp_point_count >
1662 CPRH_KBSS_MAX_TEMP_POINTS) {
1663 cpr3_err(ctrl, "invalid number of temperature points %d > %d (max)\n",
1664 temp_point_count, CPRH_KBSS_MAX_TEMP_POINTS);
1665 rc = -EINVAL;
1666 goto free_temp;
1667 }
1668
1669 ctrl->temp_points = devm_kcalloc(ctrl->dev, temp_point_count,
1670 sizeof(*ctrl->temp_points), GFP_KERNEL);
1671 if (!ctrl->temp_points) {
1672 rc = -ENOMEM;
1673 goto free_temp;
1674 }
1675 rc = of_property_read_u32_array(ctrl->dev->of_node,
1676 "qcom,cpr-temp-point-map",
1677 ctrl->temp_points, temp_point_count);
1678 if (rc) {
1679 cpr3_err(ctrl, "error reading property qcom,cpr-temp-point-map, rc=%d\n",
1680 rc);
1681 goto free_temp;
1682 }
1683
1684 for (i = 0; i < temp_point_count; i++)
1685 cpr3_debug(ctrl, "Temperature Point %d=%d\n", i,
1686 ctrl->temp_points[i]);
1687
1688 /*
1689 * If t1, t2, and t3 are the temperature points, then the temperature
1690 * bands are: (-inf, t1], (t1, t2], (t2, t3], and (t3, inf).
1691 */
1692 ctrl->temp_band_count = temp_point_count + 1;
1693 cpr3_debug(ctrl, "Number of temp bands=%d\n",
1694 ctrl->temp_band_count);
1695
1696 rc = of_property_read_u32(ctrl->dev->of_node,
1697 "qcom,cpr-initial-temp-band",
1698 &ctrl->initial_temp_band);
1699 if (rc) {
1700 cpr3_err(ctrl, "error reading qcom,cpr-initial-temp-band, rc=%d\n",
1701 rc);
1702 goto free_temp;
1703 }
1704
1705 if (ctrl->initial_temp_band >= ctrl->temp_band_count) {
1706 cpr3_err(ctrl, "Initial temperature band value %d should be in range [0 - %d]\n",
1707 ctrl->initial_temp_band, ctrl->temp_band_count - 1);
1708 rc = -EINVAL;
1709 goto free_temp;
1710 }
1711
1712 switch (ctrl->soc_revision) {
1713 case SDM660_SOC_ID:
1714 ctrl->temp_sensor_id_start = ctrl->ctrl_id ==
1715 CPRH_KBSS_POWER_CLUSTER_ID
1716 ? SDM660_KBSS_POWER_TEMP_SENSOR_ID_START :
1717 SDM660_KBSS_PERFORMANCE_TEMP_SENSOR_ID_START;
1718 ctrl->temp_sensor_id_end = ctrl->ctrl_id ==
1719 CPRH_KBSS_POWER_CLUSTER_ID
1720 ? SDM660_KBSS_POWER_TEMP_SENSOR_ID_END :
1721 SDM660_KBSS_PERFORMANCE_TEMP_SENSOR_ID_END;
1722 break;
1723 case MSM8998_V1_SOC_ID:
1724 case MSM8998_V2_SOC_ID:
1725 ctrl->temp_sensor_id_start = ctrl->ctrl_id ==
1726 CPRH_KBSS_POWER_CLUSTER_ID
1727 ? MSM8998_KBSS_POWER_TEMP_SENSOR_ID_START :
1728 MSM8998_KBSS_PERFORMANCE_TEMP_SENSOR_ID_START;
1729 ctrl->temp_sensor_id_end = ctrl->ctrl_id ==
1730 CPRH_KBSS_POWER_CLUSTER_ID
1731 ? MSM8998_KBSS_POWER_TEMP_SENSOR_ID_END :
1732 MSM8998_KBSS_PERFORMANCE_TEMP_SENSOR_ID_END;
1733 break;
David Collins54f78b72017-02-24 11:18:57 -08001734 case SDM845_V1_SOC_ID:
1735 case SDM845_V2_SOC_ID:
1736 ctrl->temp_sensor_id_start = ctrl->ctrl_id ==
1737 CPRH_KBSS_POWER_CLUSTER_ID
1738 ? SDM845_KBSS_POWER_TEMP_SENSOR_ID_START :
1739 SDM845_KBSS_PERFORMANCE_TEMP_SENSOR_ID_START;
1740 ctrl->temp_sensor_id_end = ctrl->ctrl_id ==
1741 CPRH_KBSS_POWER_CLUSTER_ID
1742 ? SDM845_KBSS_POWER_TEMP_SENSOR_ID_END :
1743 SDM845_KBSS_PERFORMANCE_TEMP_SENSOR_ID_END;
1744 break;
David Collins7370f1a2017-01-18 16:21:53 -08001745 default:
1746 cpr3_err(ctrl, "unsupported soc id = %d\n", ctrl->soc_revision);
1747 rc = -EINVAL;
1748 goto free_temp;
1749 }
1750 ctrl->allow_temp_adj = true;
1751
1752free_temp:
1753 kfree(temp);
1754
1755 return rc;
1756}
1757
1758/**
1759 * cprh_kbss_apm_crossover_as_corner() - introduce a corner whose floor,
1760 * open-loop, and ceiling voltages correspond to the APM
1761 * crossover voltage.
1762 * @vreg: Pointer to the CPR3 regulator
1763 *
1764 * The APM corner is utilized as a crossover corner by OSM and CPRh
1765 * hardware to set the VDD supply voltage during the APM switch
1766 * routine.
1767 *
1768 * Return: 0 on success, errno on failure
1769 */
1770static int cprh_kbss_apm_crossover_as_corner(struct cpr3_regulator *vreg)
1771{
1772 struct cpr3_controller *ctrl = vreg->thread->ctrl;
1773 struct cpr3_corner *corner;
1774
1775 if (!ctrl->apm_crossover_volt) {
1776 /* APM voltage crossover corner not required. */
1777 return 0;
1778 }
1779
1780 corner = &vreg->corner[vreg->corner_count];
1781 /*
1782 * 0 MHz indicates this corner is not to be
1783 * used as active DCVS set point.
1784 */
1785 corner->proc_freq = 0;
1786 corner->floor_volt = ctrl->apm_crossover_volt;
1787 corner->ceiling_volt = ctrl->apm_crossover_volt;
1788 corner->open_loop_volt = ctrl->apm_crossover_volt;
1789 corner->abs_ceiling_volt = ctrl->apm_crossover_volt;
1790 corner->use_open_loop = true;
1791 vreg->corner_count++;
1792
1793 return 0;
1794}
1795
1796/**
1797 * cprh_kbss_mem_acc_crossover_as_corner() - introduce a corner whose floor,
1798 * open-loop, and ceiling voltages correspond to the MEM ACC
1799 * crossover voltage.
1800 * @vreg: Pointer to the CPR3 regulator
1801 *
1802 * The MEM ACC corner is utilized as a crossover corner by OSM and CPRh
1803 * hardware to set the VDD supply voltage during the MEM ACC switch
1804 * routine.
1805 *
1806 * Return: 0 on success, errno on failure
1807 */
1808static int cprh_kbss_mem_acc_crossover_as_corner(struct cpr3_regulator *vreg)
1809{
1810 struct cpr3_controller *ctrl = vreg->thread->ctrl;
1811 struct cpr3_corner *corner;
1812
1813 if (!ctrl->mem_acc_crossover_volt) {
1814 /* MEM ACC voltage crossover corner not required. */
1815 return 0;
1816 }
1817
1818 corner = &vreg->corner[vreg->corner_count];
1819 /*
1820 * 0 MHz indicates this corner is not to be
1821 * used as active DCVS set point.
1822 */
1823 corner->proc_freq = 0;
1824 corner->floor_volt = ctrl->mem_acc_crossover_volt;
1825 corner->ceiling_volt = ctrl->mem_acc_crossover_volt;
1826 corner->open_loop_volt = ctrl->mem_acc_crossover_volt;
1827 corner->abs_ceiling_volt = ctrl->mem_acc_crossover_volt;
1828 corner->use_open_loop = true;
1829 vreg->corner_count++;
1830
1831 return 0;
1832}
1833
1834/**
1835 * cprh_kbss_set_no_interpolation_quotients() - use the fused target quotient
1836 * values for lower frequencies.
1837 * @vreg: Pointer to the CPR3 regulator
1838 * @volt_adjust: Pointer to array of per-corner closed-loop adjustment
1839 * voltages
1840 * @volt_adjust_fuse: Pointer to array of per-fuse-corner closed-loop
1841 * adjustment voltages
1842 * @ro_scale: Pointer to array of per-fuse-corner RO scaling factor
1843 * values with units of QUOT/V
1844 *
1845 * Return: 0 on success, errno on failure
1846 */
1847static int cprh_kbss_set_no_interpolation_quotients(struct cpr3_regulator *vreg,
1848 int *volt_adjust, int *volt_adjust_fuse, int *ro_scale)
1849{
1850 struct cprh_kbss_fuses *fuse = vreg->platform_fuses;
1851 u32 quot, ro;
1852 int quot_adjust;
1853 int i, fuse_corner;
1854
1855 for (i = 0; i < vreg->corner_count; i++) {
1856 fuse_corner = vreg->corner[i].cpr_fuse_corner;
1857 quot = fuse->target_quot[fuse_corner];
1858 quot_adjust = cpr3_quot_adjustment(ro_scale[fuse_corner],
1859 volt_adjust_fuse[fuse_corner] +
1860 volt_adjust[i]);
1861 ro = fuse->ro_sel[fuse_corner];
1862 vreg->corner[i].target_quot[ro] = quot + quot_adjust;
1863 cpr3_debug(vreg, "corner=%d RO=%u target quot=%u\n",
1864 i, ro, quot);
1865
1866 if (quot_adjust)
1867 cpr3_debug(vreg, "adjusted corner %d RO%u target quot: %u --> %u (%d uV)\n",
1868 i, ro, quot, vreg->corner[i].target_quot[ro],
1869 volt_adjust_fuse[fuse_corner] +
1870 volt_adjust[i]);
1871 }
1872
1873 return 0;
1874}
1875
1876/**
1877 * cprh_kbss_calculate_target_quotients() - calculate the CPR target
1878 * quotient for each corner of a CPR3 regulator
1879 * @vreg: Pointer to the CPR3 regulator
1880 *
1881 * If target quotient interpolation is allowed in device tree, then this
1882 * function calculates the target quotient for a given corner using linear
1883 * interpolation. This interpolation is performed using the processor
1884 * frequencies of the lower and higher Fmax corners along with the fused
1885 * target quotient and quotient offset of the higher Fmax corner.
1886 *
1887 * If target quotient interpolation is not allowed, then this function uses
1888 * the Fmax fused target quotient for all of the corners associated with a
1889 * given fuse corner.
1890 *
1891 * Return: 0 on success, errno on failure
1892 */
1893static int cprh_kbss_calculate_target_quotients(struct cpr3_regulator *vreg)
1894{
1895 struct cprh_kbss_fuses *fuse = vreg->platform_fuses;
1896 int rc;
1897 bool allow_interpolation;
1898 u64 freq_low, freq_high, prev_quot;
1899 u64 *quot_low;
1900 u64 *quot_high;
1901 u32 quot, ro;
1902 int i, j, fuse_corner, quot_adjust;
1903 int *fmax_corner;
1904 int *volt_adjust, *volt_adjust_fuse, *ro_scale;
1905 int lowest_fuse_corner, highest_fuse_corner;
1906 const char * const *corner_name;
1907
1908 switch (vreg->thread->ctrl->soc_revision) {
1909 case SDM660_SOC_ID:
1910 if (vreg->thread->ctrl->ctrl_id == CPRH_KBSS_POWER_CLUSTER_ID) {
1911 corner_name = cprh_sdm660_power_kbss_fuse_corner_name;
1912 lowest_fuse_corner =
1913 CPRH_SDM660_POWER_KBSS_FUSE_CORNER_LOWSVS;
1914 highest_fuse_corner =
1915 CPRH_SDM660_POWER_KBSS_FUSE_CORNER_TURBO_L1;
1916 } else {
1917 corner_name = cprh_sdm660_perf_kbss_fuse_corner_name;
1918 lowest_fuse_corner =
1919 CPRH_SDM660_PERF_KBSS_FUSE_CORNER_SVS;
1920 highest_fuse_corner =
1921 CPRH_SDM660_PERF_KBSS_FUSE_CORNER_TURBO_L2;
1922 }
1923 break;
1924 case MSM8998_V1_SOC_ID:
1925 case MSM8998_V2_SOC_ID:
1926 corner_name = cprh_msm8998_kbss_fuse_corner_name;
1927 lowest_fuse_corner =
1928 CPRH_MSM8998_KBSS_FUSE_CORNER_LOWSVS;
1929 highest_fuse_corner =
1930 CPRH_MSM8998_KBSS_FUSE_CORNER_TURBO_L1;
1931 break;
David Collins54f78b72017-02-24 11:18:57 -08001932 case SDM845_V1_SOC_ID:
David Collins97e4c412017-07-19 17:41:46 -07001933 corner_name = cprh_sdm845_v1_kbss_fuse_corner_name[
1934 vreg->thread->ctrl->ctrl_id];
1935 lowest_fuse_corner = 0;
1936 highest_fuse_corner = vreg->fuse_corner_count - 1;
1937 break;
David Collins54f78b72017-02-24 11:18:57 -08001938 case SDM845_V2_SOC_ID:
David Collins97e4c412017-07-19 17:41:46 -07001939 corner_name = cprh_sdm845_v2_kbss_fuse_corner_name[
David Collins54f78b72017-02-24 11:18:57 -08001940 vreg->thread->ctrl->ctrl_id];
1941 lowest_fuse_corner = 0;
1942 highest_fuse_corner = vreg->fuse_corner_count - 1;
1943 break;
David Collins7370f1a2017-01-18 16:21:53 -08001944 default:
1945 cpr3_err(vreg, "unsupported soc id = %d\n",
1946 vreg->thread->ctrl->soc_revision);
1947 return -EINVAL;
1948 }
1949
1950 /* Log fused quotient values for debugging purposes. */
1951 cpr3_info(vreg, "fused %8s: quot[%2llu]=%4llu\n",
1952 corner_name[lowest_fuse_corner],
1953 fuse->ro_sel[lowest_fuse_corner],
1954 fuse->target_quot[lowest_fuse_corner]);
1955 for (i = lowest_fuse_corner + 1; i <= highest_fuse_corner; i++)
1956 cpr3_info(vreg, "fused %8s: quot[%2llu]=%4llu, quot_offset[%2llu]=%4llu\n",
1957 corner_name[i], fuse->ro_sel[i], fuse->target_quot[i],
1958 fuse->ro_sel[i], fuse->quot_offset[i] *
1959 CPRH_KBSS_QUOT_OFFSET_SCALE);
1960
1961 allow_interpolation = of_property_read_bool(vreg->of_node,
1962 "qcom,allow-quotient-interpolation");
1963
1964 volt_adjust = kcalloc(vreg->corner_count, sizeof(*volt_adjust),
1965 GFP_KERNEL);
1966 volt_adjust_fuse = kcalloc(vreg->fuse_corner_count,
1967 sizeof(*volt_adjust_fuse), GFP_KERNEL);
1968 ro_scale = kcalloc(vreg->fuse_corner_count, sizeof(*ro_scale),
1969 GFP_KERNEL);
1970 fmax_corner = kcalloc(vreg->fuse_corner_count, sizeof(*fmax_corner),
1971 GFP_KERNEL);
1972 quot_low = kcalloc(vreg->fuse_corner_count, sizeof(*quot_low),
1973 GFP_KERNEL);
1974 quot_high = kcalloc(vreg->fuse_corner_count, sizeof(*quot_high),
1975 GFP_KERNEL);
1976 if (!volt_adjust || !volt_adjust_fuse || !ro_scale ||
1977 !fmax_corner || !quot_low || !quot_high) {
1978 rc = -ENOMEM;
1979 goto done;
1980 }
1981
1982 rc = cpr3_parse_closed_loop_voltage_adjustments(vreg, &fuse->ro_sel[0],
1983 volt_adjust, volt_adjust_fuse, ro_scale);
1984 if (rc) {
1985 cpr3_err(vreg, "could not load closed-loop voltage adjustments, rc=%d\n",
1986 rc);
1987 goto done;
1988 }
1989
1990 if (!allow_interpolation) {
1991 /* Use fused target quotients for lower frequencies. */
1992 return cprh_kbss_set_no_interpolation_quotients(vreg,
1993 volt_adjust, volt_adjust_fuse, ro_scale);
1994 }
1995
1996 /* Determine highest corner mapped to each fuse corner */
1997 j = vreg->fuse_corner_count - 1;
1998 for (i = vreg->corner_count - 1; i >= 0; i--) {
1999 if (vreg->corner[i].cpr_fuse_corner == j) {
2000 fmax_corner[j] = i;
2001 j--;
2002 }
2003 }
2004 if (j >= 0) {
2005 cpr3_err(vreg, "invalid fuse corner mapping\n");
2006 rc = -EINVAL;
2007 goto done;
2008 }
2009
2010 /*
2011 * Interpolation is not possible for corners mapped to the lowest fuse
2012 * corner so use the fuse corner value directly.
2013 */
2014 i = lowest_fuse_corner;
2015 quot_adjust = cpr3_quot_adjustment(ro_scale[i], volt_adjust_fuse[i]);
2016 quot = fuse->target_quot[i] + quot_adjust;
2017 quot_high[i] = quot_low[i] = quot;
2018 ro = fuse->ro_sel[i];
2019 if (quot_adjust)
2020 cpr3_debug(vreg, "adjusted fuse corner %d RO%u target quot: %llu --> %u (%d uV)\n",
2021 i, ro, fuse->target_quot[i], quot, volt_adjust_fuse[i]);
2022
2023 for (i = 0; i <= fmax_corner[lowest_fuse_corner]; i++)
2024 vreg->corner[i].target_quot[ro] = quot;
2025
2026 for (i = lowest_fuse_corner + 1; i < vreg->fuse_corner_count; i++) {
2027 quot_high[i] = fuse->target_quot[i];
2028 if (fuse->ro_sel[i] == fuse->ro_sel[i - 1])
2029 quot_low[i] = quot_high[i - 1];
2030 else
2031 quot_low[i] = quot_high[i]
2032 - fuse->quot_offset[i]
2033 * CPRH_KBSS_QUOT_OFFSET_SCALE;
2034 if (quot_high[i] < quot_low[i]) {
2035 cpr3_debug(vreg, "quot_high[%d]=%llu < quot_low[%d]=%llu; overriding: quot_high[%d]=%llu\n",
2036 i, quot_high[i], i, quot_low[i],
2037 i, quot_low[i]);
2038 quot_high[i] = quot_low[i];
2039 }
2040 }
2041
2042 /* Perform per-fuse-corner target quotient adjustment */
2043 for (i = 1; i < vreg->fuse_corner_count; i++) {
2044 quot_adjust = cpr3_quot_adjustment(ro_scale[i],
2045 volt_adjust_fuse[i]);
2046 if (quot_adjust) {
2047 prev_quot = quot_high[i];
2048 quot_high[i] += quot_adjust;
2049 cpr3_debug(vreg, "adjusted fuse corner %d RO%llu target quot: %llu --> %llu (%d uV)\n",
2050 i, fuse->ro_sel[i], prev_quot, quot_high[i],
2051 volt_adjust_fuse[i]);
2052 }
2053
2054 if (fuse->ro_sel[i] == fuse->ro_sel[i - 1])
2055 quot_low[i] = quot_high[i - 1];
2056 else
2057 quot_low[i] += cpr3_quot_adjustment(ro_scale[i],
2058 volt_adjust_fuse[i - 1]);
2059
2060 if (quot_high[i] < quot_low[i]) {
2061 cpr3_debug(vreg, "quot_high[%d]=%llu < quot_low[%d]=%llu after adjustment; overriding: quot_high[%d]=%llu\n",
2062 i, quot_high[i], i, quot_low[i],
2063 i, quot_low[i]);
2064 quot_high[i] = quot_low[i];
2065 }
2066 }
2067
2068 /* Interpolate voltages for the higher fuse corners. */
2069 for (i = 1; i < vreg->fuse_corner_count; i++) {
2070 freq_low = vreg->corner[fmax_corner[i - 1]].proc_freq;
2071 freq_high = vreg->corner[fmax_corner[i]].proc_freq;
2072
2073 ro = fuse->ro_sel[i];
2074 for (j = fmax_corner[i - 1] + 1; j <= fmax_corner[i]; j++)
2075 vreg->corner[j].target_quot[ro] = cpr3_interpolate(
2076 freq_low, quot_low[i], freq_high, quot_high[i],
2077 vreg->corner[j].proc_freq);
2078 }
2079
2080 /* Perform per-corner target quotient adjustment */
2081 for (i = 0; i < vreg->corner_count; i++) {
2082 fuse_corner = vreg->corner[i].cpr_fuse_corner;
2083 ro = fuse->ro_sel[fuse_corner];
2084 quot_adjust = cpr3_quot_adjustment(ro_scale[fuse_corner],
2085 volt_adjust[i]);
2086 if (quot_adjust) {
2087 prev_quot = vreg->corner[i].target_quot[ro];
2088 vreg->corner[i].target_quot[ro] += quot_adjust;
2089 cpr3_debug(vreg, "adjusted corner %d RO%u target quot: %llu --> %u (%d uV)\n",
2090 i, ro, prev_quot,
2091 vreg->corner[i].target_quot[ro],
2092 volt_adjust[i]);
2093 }
2094 }
2095
2096 /* Ensure that target quotients increase monotonically */
2097 for (i = 1; i < vreg->corner_count; i++) {
2098 ro = fuse->ro_sel[vreg->corner[i].cpr_fuse_corner];
2099 if (fuse->ro_sel[vreg->corner[i - 1].cpr_fuse_corner] == ro
2100 && vreg->corner[i].target_quot[ro]
2101 < vreg->corner[i - 1].target_quot[ro]) {
2102 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",
2103 i, ro, vreg->corner[i].target_quot[ro],
2104 i - 1, ro, vreg->corner[i - 1].target_quot[ro],
2105 i, ro, vreg->corner[i - 1].target_quot[ro]);
2106 vreg->corner[i].target_quot[ro]
2107 = vreg->corner[i - 1].target_quot[ro];
2108 }
2109 }
2110
2111done:
2112 kfree(volt_adjust);
2113 kfree(volt_adjust_fuse);
2114 kfree(ro_scale);
2115 kfree(fmax_corner);
2116 kfree(quot_low);
2117 kfree(quot_high);
2118 return rc;
2119}
2120
2121/**
2122 * cprh_kbss_print_settings() - print out KBSS CPR configuration settings into
2123 * the kernel log for debugging purposes
2124 * @vreg: Pointer to the CPR3 regulator
2125 */
2126static void cprh_kbss_print_settings(struct cpr3_regulator *vreg)
2127{
2128 struct cpr3_corner *corner;
2129 int i;
2130
2131 cpr3_debug(vreg, "Corner: Frequency (Hz), Fuse Corner, Floor (uV), Open-Loop (uV), Ceiling (uV)\n");
2132 for (i = 0; i < vreg->corner_count; i++) {
2133 corner = &vreg->corner[i];
2134 cpr3_debug(vreg, "%3d: %10u, %2d, %7d, %7d, %7d\n",
2135 i, corner->proc_freq, corner->cpr_fuse_corner,
2136 corner->floor_volt, corner->open_loop_volt,
2137 corner->ceiling_volt);
2138 }
2139}
2140
2141/**
2142 * cprh_kbss_init_thread() - perform steps necessary to initialize the
2143 * configuration data for a CPR3 thread
2144 * @thread: Pointer to the CPR3 thread
2145 *
2146 * Return: 0 on success, errno on failure
2147 */
2148static int cprh_kbss_init_thread(struct cpr3_thread *thread)
2149{
2150 int rc;
2151
2152 rc = cpr3_parse_common_thread_data(thread);
2153 if (rc) {
2154 cpr3_err(thread->ctrl, "thread %u unable to read CPR thread data from device tree, rc=%d\n",
2155 thread->thread_id, rc);
2156 return rc;
2157 }
2158
2159 return 0;
2160}
2161
2162/**
2163 * cprh_kbss_init_regulator() - perform all steps necessary to initialize the
2164 * configuration data for a CPR3 regulator
2165 * @vreg: Pointer to the CPR3 regulator
2166 *
2167 * Return: 0 on success, errno on failure
2168 */
2169static int cprh_kbss_init_regulator(struct cpr3_regulator *vreg)
2170{
2171 struct cprh_kbss_fuses *fuse;
2172 int rc;
2173
2174 rc = cprh_kbss_read_fuse_data(vreg);
2175 if (rc) {
2176 cpr3_err(vreg, "unable to read CPR fuse data, rc=%d\n", rc);
2177 return rc;
2178 }
2179
2180 fuse = vreg->platform_fuses;
2181
2182 rc = cprh_kbss_parse_corner_data(vreg);
2183 if (rc) {
2184 cpr3_err(vreg, "unable to read CPR corner data from device tree, rc=%d\n",
2185 rc);
2186 return rc;
2187 }
2188
2189 rc = cprh_kbss_calculate_open_loop_voltages(vreg);
2190 if (rc) {
2191 cpr3_err(vreg, "unable to calculate open-loop voltages, rc=%d\n",
2192 rc);
2193 return rc;
2194 }
2195
2196 rc = cpr3_limit_open_loop_voltages(vreg);
2197 if (rc) {
2198 cpr3_err(vreg, "unable to limit open-loop voltages, rc=%d\n",
2199 rc);
2200 return rc;
2201 }
2202
2203 cprh_adjust_voltages_for_apm(vreg);
2204 cprh_adjust_voltages_for_mem_acc(vreg);
2205
2206 cpr3_open_loop_voltage_as_ceiling(vreg);
2207
2208 rc = cpr3_limit_floor_voltages(vreg);
2209 if (rc) {
2210 cpr3_err(vreg, "unable to limit floor voltages, rc=%d\n", rc);
2211 return rc;
2212 }
2213
2214 rc = cprh_kbss_calculate_target_quotients(vreg);
2215 if (rc) {
2216 cpr3_err(vreg, "unable to calculate target quotients, rc=%d\n",
2217 rc);
2218 return rc;
2219 }
2220
2221 rc = cprh_kbss_parse_core_count_temp_adj_properties(vreg);
2222 if (rc) {
2223 cpr3_err(vreg, "unable to parse core count and temperature adjustment properties, rc=%d\n",
2224 rc);
2225 return rc;
2226 }
2227
2228 rc = cpr4_parse_core_count_temp_voltage_adj(vreg, true);
2229 if (rc) {
2230 cpr3_err(vreg, "unable to parse temperature and core count voltage adjustments, rc=%d\n",
2231 rc);
2232 return rc;
2233 }
2234
2235 if (vreg->allow_core_count_adj && (vreg->max_core_count <= 0
2236 || vreg->max_core_count >
2237 CPRH_KBSS_CPR_SDELTA_CORE_COUNT)) {
2238 cpr3_err(vreg, "qcom,max-core-count has invalid value = %d\n",
2239 vreg->max_core_count);
2240 return -EINVAL;
2241 }
2242
David Collins54f78b72017-02-24 11:18:57 -08002243 if ((vreg->allow_core_count_adj || vreg->allow_temp_adj)
2244 && vreg->thread->thread_id != 0) {
2245 cpr3_err(vreg, "core count and temperature based adjustments are only allowed for CPR thread 0\n");
2246 return -EINVAL;
2247 }
2248
David Collins7370f1a2017-01-18 16:21:53 -08002249 rc = cprh_msm8998_partial_binning_override(vreg);
2250 if (rc) {
2251 cpr3_err(vreg, "unable to override CPR parameters based on partial binning fuse values, rc=%d\n",
2252 rc);
2253 return rc;
2254 }
2255
2256 rc = cprh_kbss_apm_crossover_as_corner(vreg);
2257 if (rc) {
2258 cpr3_err(vreg, "unable to introduce APM voltage crossover corner, rc=%d\n",
2259 rc);
2260 return rc;
2261 }
2262
2263 rc = cprh_kbss_mem_acc_crossover_as_corner(vreg);
2264 if (rc) {
2265 cpr3_err(vreg, "unable to introduce MEM ACC voltage crossover corner, rc=%d\n",
2266 rc);
2267 return rc;
2268 }
2269
2270 cprh_kbss_print_settings(vreg);
2271
2272 return 0;
2273}
2274
2275/**
2276 * cprh_kbss_init_aging() - perform KBSS CPRh controller specific aging
2277 * initializations
2278 * @ctrl: Pointer to the CPR3 controller
2279 *
2280 * Return: 0 on success, errno on failure
2281 */
2282static int cprh_kbss_init_aging(struct cpr3_controller *ctrl)
2283{
2284 struct cprh_kbss_fuses *fuse = NULL;
Channagoud Kadabi075db3b2017-03-16 14:26:17 -07002285 struct cpr3_regulator *vreg = NULL;
David Collins7370f1a2017-01-18 16:21:53 -08002286 u32 aging_ro_scale;
2287 int i, j, rc = 0;
2288
2289 for (i = 0; i < ctrl->thread_count; i++) {
2290 for (j = 0; j < ctrl->thread[i].vreg_count; j++) {
2291 if (ctrl->thread[i].vreg[j].aging_allowed) {
2292 ctrl->aging_required = true;
2293 vreg = &ctrl->thread[i].vreg[j];
2294 fuse = vreg->platform_fuses;
2295 break;
2296 }
2297 }
2298 }
2299
2300 if (!ctrl->aging_required || !fuse || !vreg)
2301 return 0;
2302
2303 rc = cpr3_parse_array_property(vreg, "qcom,cpr-aging-ro-scaling-factor",
2304 1, &aging_ro_scale);
2305 if (rc)
2306 return rc;
2307
2308 if (aging_ro_scale == 0) {
2309 cpr3_err(ctrl, "aging RO scaling factor is invalid: %u\n",
2310 aging_ro_scale);
2311 return -EINVAL;
2312 }
2313
2314 ctrl->aging_vdd_mode = REGULATOR_MODE_NORMAL;
2315 ctrl->aging_complete_vdd_mode = REGULATOR_MODE_IDLE;
2316
2317 ctrl->aging_sensor_count = 1;
2318 ctrl->aging_sensor = devm_kzalloc(ctrl->dev,
2319 sizeof(*ctrl->aging_sensor),
2320 GFP_KERNEL);
2321 if (!ctrl->aging_sensor)
2322 return -ENOMEM;
2323
2324 switch (ctrl->soc_revision) {
2325 case SDM660_SOC_ID:
2326 if (ctrl->ctrl_id == CPRH_KBSS_POWER_CLUSTER_ID) {
2327 ctrl->aging_sensor->sensor_id
2328 = SDM660_KBSS_POWER_AGING_SENSOR_ID;
2329 ctrl->aging_sensor->bypass_mask[0]
2330 = SDM660_KBSS_POWER_AGING_BYPASS_MASK0;
2331 } else {
2332 ctrl->aging_sensor->sensor_id
2333 = SDM660_KBSS_PERFORMANCE_AGING_SENSOR_ID;
2334 ctrl->aging_sensor->bypass_mask[0]
2335 = SDM660_KBSS_PERFORMANCE_AGING_BYPASS_MASK0;
2336 }
2337 break;
2338 case MSM8998_V1_SOC_ID:
2339 case MSM8998_V2_SOC_ID:
2340 if (ctrl->ctrl_id == CPRH_KBSS_POWER_CLUSTER_ID) {
2341 ctrl->aging_sensor->sensor_id
2342 = MSM8998_KBSS_POWER_AGING_SENSOR_ID;
2343 ctrl->aging_sensor->bypass_mask[0]
2344 = MSM8998_KBSS_POWER_AGING_BYPASS_MASK0;
2345 } else {
2346 ctrl->aging_sensor->sensor_id
2347 = MSM8998_KBSS_PERFORMANCE_AGING_SENSOR_ID;
2348 ctrl->aging_sensor->bypass_mask[0]
2349 = MSM8998_KBSS_PERFORMANCE_AGING_BYPASS_MASK0;
2350 }
2351 break;
David Collins54f78b72017-02-24 11:18:57 -08002352 case SDM845_V1_SOC_ID:
2353 case SDM845_V2_SOC_ID:
2354 if (ctrl->ctrl_id == CPRH_KBSS_POWER_CLUSTER_ID) {
2355 ctrl->aging_sensor->sensor_id
2356 = SDM845_KBSS_POWER_AGING_SENSOR_ID;
2357 ctrl->aging_sensor->bypass_mask[0]
2358 = SDM845_KBSS_POWER_AGING_BYPASS_MASK0;
2359 } else {
2360 ctrl->aging_sensor->sensor_id
2361 = SDM845_KBSS_PERFORMANCE_AGING_SENSOR_ID;
2362 ctrl->aging_sensor->bypass_mask[0]
2363 = SDM845_KBSS_PERFORMANCE_AGING_BYPASS_MASK0;
2364 }
2365 break;
David Collins7370f1a2017-01-18 16:21:53 -08002366 default:
2367 cpr3_err(ctrl, "unsupported soc id = %d\n", ctrl->soc_revision);
2368 return -EINVAL;
2369 }
2370 ctrl->aging_sensor->ro_scale = aging_ro_scale;
2371
2372 ctrl->aging_sensor->init_quot_diff
2373 = cpr3_convert_open_loop_voltage_fuse(0,
2374 CPRH_KBSS_AGING_INIT_QUOT_DIFF_SCALE,
2375 fuse->aging_init_quot_diff,
2376 CPRH_KBSS_AGING_INIT_QUOT_DIFF_SIZE);
2377
2378 cpr3_debug(ctrl, "sensor %u aging init quotient diff = %d, aging RO scale = %u QUOT/V\n",
2379 ctrl->aging_sensor->sensor_id,
2380 ctrl->aging_sensor->init_quot_diff,
2381 ctrl->aging_sensor->ro_scale);
2382
2383 return 0;
2384}
2385
2386/**
2387 * cprh_kbss_init_controller() - perform KBSS CPRh controller specific
2388 * initializations
2389 * @ctrl: Pointer to the CPR3 controller
2390 *
2391 * Return: 0 on success, errno on failure
2392 */
2393static int cprh_kbss_init_controller(struct cpr3_controller *ctrl)
2394{
David Collins54f78b72017-02-24 11:18:57 -08002395 int rc, i, tid_power, tid_l3;
David Collins7370f1a2017-01-18 16:21:53 -08002396
2397 ctrl->ctrl_type = CPR_CTRL_TYPE_CPRH;
2398 rc = cpr3_parse_common_ctrl_data(ctrl);
2399 if (rc) {
2400 if (rc != -EPROBE_DEFER)
2401 cpr3_err(ctrl, "unable to parse common controller data, rc=%d\n",
2402 rc);
2403 return rc;
2404 }
2405
2406 rc = of_property_read_u32(ctrl->dev->of_node, "qcom,cpr-controller-id",
2407 &ctrl->ctrl_id);
2408 if (rc) {
2409 cpr3_err(ctrl, "could not read DT property qcom,cpr-controller-id, rc=%d\n",
2410 rc);
2411 return rc;
2412 }
2413
2414 if (ctrl->ctrl_id < CPRH_KBSS_MIN_CONTROLLER_ID ||
2415 ctrl->ctrl_id > CPRH_KBSS_MAX_CONTROLLER_ID) {
2416 cpr3_err(ctrl, "invalid qcom,cpr-controller-id specified\n");
2417 return -EINVAL;
2418 }
2419
2420 rc = of_property_read_u32(ctrl->dev->of_node,
2421 "qcom,cpr-down-error-step-limit",
2422 &ctrl->down_error_step_limit);
2423 if (rc) {
2424 cpr3_err(ctrl, "error reading qcom,cpr-down-error-step-limit, rc=%d\n",
2425 rc);
2426 return rc;
2427 }
2428
2429 rc = of_property_read_u32(ctrl->dev->of_node,
2430 "qcom,cpr-up-error-step-limit",
2431 &ctrl->up_error_step_limit);
2432 if (rc) {
2433 cpr3_err(ctrl, "error reading qcom,cpr-up-error-step-limit, rc=%d\n",
2434 rc);
2435 return rc;
2436 }
2437
Osvaldo Banuelosd688dded2017-03-22 13:35:46 -07002438 ctrl->acd_avg_enabled = of_property_read_bool(ctrl->dev->of_node,
2439 "qcom,cpr-acd-avg-enable");
2440 if (ctrl->acd_avg_enabled) {
2441 rc = of_property_read_u32(ctrl->dev->of_node,
2442 "qcom,cpr-acd-adj-down-step-limit",
2443 &ctrl->acd_adj_down_step_limit);
2444 if (rc) {
2445 cpr3_err(ctrl, "error reading qcom,cpr-acd-adj-down-step-limit, rc=%d\n",
2446 rc);
2447 return rc;
2448 }
2449
2450 rc = of_property_read_u32(ctrl->dev->of_node,
2451 "qcom,cpr-acd-adj-up-step-limit",
2452 &ctrl->acd_adj_up_step_limit);
2453 if (rc) {
2454 cpr3_err(ctrl, "error reading qcom,cpr-acd-adj-up-step-limit, rc=%d\n",
2455 rc);
2456 return rc;
2457 }
2458
2459 rc = of_property_read_u32(ctrl->dev->of_node,
2460 "qcom,cpr-acd-adj-down-step-size",
2461 &ctrl->acd_adj_down_step_size);
2462 if (rc) {
2463 cpr3_err(ctrl, "error reading qcom,cpr-acd-down-step-size, rc=%d\n",
2464 rc);
2465 return rc;
2466 }
2467
2468 rc = of_property_read_u32(ctrl->dev->of_node,
2469 "qcom,cpr-acd-adj-up-step-size",
2470 &ctrl->acd_adj_up_step_size);
2471 if (rc) {
2472 cpr3_err(ctrl, "error reading qcom,cpr-acd-up-step-size, rc=%d\n",
2473 rc);
2474 return rc;
2475 }
Osvaldo Banuelos3bdabd02017-03-22 13:39:39 -07002476
2477 ctrl->acd_notwait_for_cl_settled =
2478 of_property_read_bool(ctrl->dev->of_node,
2479 "qcom,cpr-acd-notwait-for-cl-settled");
2480 ctrl->acd_adj_avg_fast_update =
2481 of_property_read_bool(ctrl->dev->of_node,
2482 "qcom,cpr-acd-avg-fast-update");
Osvaldo Banuelosd688dded2017-03-22 13:35:46 -07002483 }
2484
David Collins7370f1a2017-01-18 16:21:53 -08002485 rc = of_property_read_u32(ctrl->dev->of_node,
2486 "qcom,voltage-base",
2487 &ctrl->base_volt);
2488 if (rc) {
2489 cpr3_err(ctrl, "error reading property qcom,voltage-base, rc=%d\n",
2490 rc);
2491 return rc;
2492 }
2493
2494 rc = of_property_read_u32(ctrl->dev->of_node,
2495 "qcom,cpr-up-down-delay-time",
2496 &ctrl->up_down_delay_time);
2497 if (rc) {
2498 cpr3_err(ctrl, "error reading property qcom,cpr-up-down-delay-time, rc=%d\n",
2499 rc);
2500 return rc;
2501 }
2502
2503 rc = of_property_read_u32(ctrl->dev->of_node,
2504 "qcom,apm-threshold-voltage",
2505 &ctrl->apm_threshold_volt);
2506 if (rc) {
2507 cpr3_debug(ctrl, "qcom,apm-threshold-voltage not specified\n");
2508 } else {
2509 rc = of_property_read_u32(ctrl->dev->of_node,
2510 "qcom,apm-crossover-voltage",
2511 &ctrl->apm_crossover_volt);
2512 if (rc) {
2513 cpr3_err(ctrl, "error reading property qcom,apm-crossover-voltage, rc=%d\n",
2514 rc);
2515 return rc;
2516 }
2517 }
2518
2519 of_property_read_u32(ctrl->dev->of_node, "qcom,apm-hysteresis-voltage",
2520 &ctrl->apm_adj_volt);
2521 ctrl->apm_adj_volt = CPR3_ROUND(ctrl->apm_adj_volt, ctrl->step_volt);
2522
2523 ctrl->saw_use_unit_mV = of_property_read_bool(ctrl->dev->of_node,
2524 "qcom,cpr-saw-use-unit-mV");
2525
2526 rc = of_property_read_u32(ctrl->dev->of_node,
2527 "qcom,mem-acc-threshold-voltage",
2528 &ctrl->mem_acc_threshold_volt);
2529 if (!rc) {
2530 ctrl->mem_acc_threshold_volt
2531 = CPR3_ROUND(ctrl->mem_acc_threshold_volt, ctrl->step_volt);
2532
2533 rc = of_property_read_u32(ctrl->dev->of_node,
2534 "qcom,mem-acc-crossover-voltage",
2535 &ctrl->mem_acc_crossover_volt);
2536 if (rc) {
2537 cpr3_err(ctrl, "error reading property qcom,mem-acc-crossover-voltage, rc=%d\n",
2538 rc);
2539 return rc;
2540 }
2541 ctrl->mem_acc_crossover_volt
2542 = CPR3_ROUND(ctrl->mem_acc_crossover_volt, ctrl->step_volt);
2543 }
2544
2545 /*
2546 * Use fixed step quotient if specified otherwise use dynamically
2547 * calculated per RO step quotient
2548 */
2549 of_property_read_u32(ctrl->dev->of_node, "qcom,cpr-step-quot-fixed",
2550 &ctrl->step_quot_fixed);
2551 ctrl->use_dynamic_step_quot = !ctrl->step_quot_fixed;
2552
2553 of_property_read_u32(ctrl->dev->of_node,
2554 "qcom,cpr-voltage-settling-time",
2555 &ctrl->voltage_settling_time);
2556
2557 of_property_read_u32(ctrl->dev->of_node,
2558 "qcom,cpr-corner-switch-delay-time",
2559 &ctrl->corner_switch_delay_time);
2560
2561 switch (ctrl->soc_revision) {
2562 case SDM660_SOC_ID:
2563 if (ctrl->ctrl_id == CPRH_KBSS_POWER_CLUSTER_ID)
2564 ctrl->sensor_count =
2565 SDM660_KBSS_POWER_CPR_SENSOR_COUNT;
2566 else
2567 ctrl->sensor_count =
2568 SDM660_KBSS_PERFORMANCE_CPR_SENSOR_COUNT;
2569 break;
2570 case MSM8998_V1_SOC_ID:
2571 case MSM8998_V2_SOC_ID:
2572 if (ctrl->ctrl_id == CPRH_KBSS_POWER_CLUSTER_ID)
2573 ctrl->sensor_count =
2574 MSM8998_KBSS_POWER_CPR_SENSOR_COUNT;
2575 else
2576 ctrl->sensor_count =
2577 MSM8998_KBSS_PERFORMANCE_CPR_SENSOR_COUNT;
2578 break;
David Collins54f78b72017-02-24 11:18:57 -08002579 case SDM845_V1_SOC_ID:
2580 case SDM845_V2_SOC_ID:
2581 if (ctrl->ctrl_id == CPRH_KBSS_POWER_CLUSTER_ID)
2582 ctrl->sensor_count =
2583 SDM845_KBSS_POWER_CPR_SENSOR_COUNT;
2584 else
2585 ctrl->sensor_count =
2586 SDM845_KBSS_PERFORMANCE_CPR_SENSOR_COUNT;
2587 break;
David Collins7370f1a2017-01-18 16:21:53 -08002588 default:
2589 cpr3_err(ctrl, "unsupported soc id = %d\n", ctrl->soc_revision);
2590 return -EINVAL;
2591 }
2592
2593 /*
2594 * KBSS only has one thread (0) per controller so the zeroed
2595 * array does not need further modification.
2596 */
2597 ctrl->sensor_owner = devm_kcalloc(ctrl->dev, ctrl->sensor_count,
2598 sizeof(*ctrl->sensor_owner), GFP_KERNEL);
2599 if (!ctrl->sensor_owner)
2600 return -ENOMEM;
2601
David Collins54f78b72017-02-24 11:18:57 -08002602 /* Specify sensor ownership for SDM845 controller 0 */
2603 if ((ctrl->soc_revision == SDM845_V1_SOC_ID
2604 || ctrl->soc_revision == SDM845_V2_SOC_ID)
2605 && ctrl->ctrl_id == CPRH_KBSS_POWER_CLUSTER_ID) {
2606 if (ctrl->soc_revision == SDM845_V1_SOC_ID) {
2607 /* Thread IDs are swapped for SDM845 V1 */
2608 tid_power = CPRH_KBSS_L3_THREAD_ID;
2609 tid_l3 = CPRH_KBSS_POWER_CLUSTER_THREAD_ID;
2610 } else {
2611 tid_power = CPRH_KBSS_POWER_CLUSTER_THREAD_ID;
2612 tid_l3 = CPRH_KBSS_L3_THREAD_ID;
2613 }
2614
2615 for (i = SDM845_KBSS_POWER_THREAD_CPR_SENSOR_ID_START;
2616 i <= SDM845_KBSS_POWER_THREAD_CPR_SENSOR_ID_END; i++)
2617 ctrl->sensor_owner[i] = tid_power;
2618 for (i = SDM845_KBSS_L3_THREAD_CPR_SENSOR_ID_START;
2619 i <= SDM845_KBSS_L3_THREAD_CPR_SENSOR_ID_END; i++)
2620 ctrl->sensor_owner[i] = tid_l3;
2621 }
2622
David Collins7370f1a2017-01-18 16:21:53 -08002623 ctrl->cpr_clock_rate = CPRH_KBSS_CPR_CLOCK_RATE;
2624 ctrl->supports_hw_closed_loop = true;
2625 ctrl->use_hw_closed_loop = of_property_read_bool(ctrl->dev->of_node,
2626 "qcom,cpr-hw-closed-loop");
2627
2628 return 0;
2629}
2630
David Collins7370f1a2017-01-18 16:21:53 -08002631static int cprh_kbss_regulator_suspend(struct platform_device *pdev,
2632 pm_message_t state)
2633{
2634 struct cpr3_controller *ctrl = platform_get_drvdata(pdev);
2635
2636 return cpr3_regulator_suspend(ctrl);
2637}
2638
2639static int cprh_kbss_regulator_resume(struct platform_device *pdev)
2640{
2641 struct cpr3_controller *ctrl = platform_get_drvdata(pdev);
2642
2643 return cpr3_regulator_resume(ctrl);
2644}
2645
2646/* Data corresponds to the SoC revision */
2647static const struct of_device_id cprh_regulator_match_table[] = {
2648 {
2649 .compatible = "qcom,cprh-msm8998-v1-kbss-regulator",
2650 .data = (void *)(uintptr_t)MSM8998_V1_SOC_ID,
2651 },
2652 {
2653 .compatible = "qcom,cprh-msm8998-v2-kbss-regulator",
2654 .data = (void *)(uintptr_t)MSM8998_V2_SOC_ID,
2655 },
2656 {
2657 .compatible = "qcom,cprh-msm8998-kbss-regulator",
2658 .data = (void *)(uintptr_t)MSM8998_V2_SOC_ID,
2659 },
2660 {
2661 .compatible = "qcom,cprh-sdm660-kbss-regulator",
2662 .data = (void *)(uintptr_t)SDM660_SOC_ID,
2663 },
David Collins54f78b72017-02-24 11:18:57 -08002664 {
2665 .compatible = "qcom,cprh-sdm845-v1-kbss-regulator",
2666 .data = (void *)(uintptr_t)SDM845_V1_SOC_ID,
2667 },
2668 {
2669 .compatible = "qcom,cprh-sdm845-v2-kbss-regulator",
2670 .data = (void *)(uintptr_t)SDM845_V2_SOC_ID,
2671 },
2672 {
2673 .compatible = "qcom,cprh-sdm845-kbss-regulator",
2674 .data = (void *)(uintptr_t)SDM845_V2_SOC_ID,
2675 },
David Collins7370f1a2017-01-18 16:21:53 -08002676 {}
2677};
2678
2679static int cprh_kbss_regulator_probe(struct platform_device *pdev)
2680{
2681 struct device *dev = &pdev->dev;
2682 const struct of_device_id *match;
2683 struct cpr3_controller *ctrl;
David Collins54f78b72017-02-24 11:18:57 -08002684 int i, rc, max_thread_count;
David Collins7370f1a2017-01-18 16:21:53 -08002685
2686 if (!dev->of_node) {
2687 dev_err(dev, "Device tree node is missing\n");
2688 return -EINVAL;
2689 }
2690
2691 ctrl = devm_kzalloc(dev, sizeof(*ctrl), GFP_KERNEL);
2692 if (!ctrl)
2693 return -ENOMEM;
2694
2695 ctrl->dev = dev;
2696 ctrl->cpr_allowed_hw = true;
2697
2698 rc = of_property_read_string(dev->of_node, "qcom,cpr-ctrl-name",
2699 &ctrl->name);
2700 if (rc) {
2701 cpr3_err(ctrl, "unable to read qcom,cpr-ctrl-name, rc=%d\n",
2702 rc);
2703 return rc;
2704 }
2705
2706 match = of_match_node(cprh_regulator_match_table, dev->of_node);
2707 if (match)
2708 ctrl->soc_revision = (uintptr_t)match->data;
2709 else
2710 cpr3_err(ctrl, "could not find compatible string match\n");
2711
2712 rc = cpr3_map_fuse_base(ctrl, pdev);
2713 if (rc) {
2714 cpr3_err(ctrl, "could not map fuse base address\n");
2715 return rc;
2716 }
2717
David Collins54f78b72017-02-24 11:18:57 -08002718 rc = cpr3_allocate_threads(ctrl, 0, 1);
David Collins7370f1a2017-01-18 16:21:53 -08002719 if (rc) {
2720 cpr3_err(ctrl, "failed to allocate CPR thread array, rc=%d\n",
2721 rc);
2722 return rc;
2723 }
2724
David Collins7370f1a2017-01-18 16:21:53 -08002725 rc = cprh_kbss_init_controller(ctrl);
2726 if (rc) {
2727 if (rc != -EPROBE_DEFER)
2728 cpr3_err(ctrl, "failed to initialize CPR controller parameters, rc=%d\n",
2729 rc);
2730 return rc;
2731 }
2732
David Collins54f78b72017-02-24 11:18:57 -08002733 /*
2734 * SDM845 controller 0 supports 2 CPR threads. All other controllers
2735 * only support 1.
2736 */
2737 max_thread_count = (ctrl->soc_revision == SDM845_V1_SOC_ID
2738 || ctrl->soc_revision == SDM845_V2_SOC_ID)
2739 && ctrl->ctrl_id == CPRH_KBSS_POWER_CLUSTER_ID
2740 ? 2 : 1;
2741
2742 if (ctrl->thread_count < 1 || ctrl->thread_count > max_thread_count) {
2743 cpr3_err(ctrl, "expected 1 or %d threads but found %d\n",
2744 max_thread_count, ctrl->thread_count);
2745 return -EINVAL;
2746 } else if (ctrl->thread[0].vreg_count != 1) {
2747 cpr3_err(ctrl, "expected 1 regulator for thread 0 but found %d\n",
2748 ctrl->thread[0].vreg_count);
2749 return -EINVAL;
2750 } else if (ctrl->thread_count == 2 && ctrl->thread[1].vreg_count != 1) {
2751 cpr3_err(ctrl, "expected 1 regulator for thread 1 but found %d\n",
2752 ctrl->thread[1].vreg_count);
2753 return -EINVAL;
David Collins7370f1a2017-01-18 16:21:53 -08002754 }
2755
David Collins54f78b72017-02-24 11:18:57 -08002756 for (i = 0; i < ctrl->thread_count; i++) {
2757 rc = cprh_kbss_init_thread(&ctrl->thread[i]);
2758 if (rc) {
2759 cpr3_err(ctrl, "thread initialization failed, rc=%d\n",
2760 rc);
2761 return rc;
2762 }
2763
2764 rc = cprh_kbss_init_regulator(&ctrl->thread[i].vreg[0]);
2765 if (rc) {
2766 cpr3_err(&ctrl->thread[i].vreg[0], "regulator initialization failed, rc=%d\n",
2767 rc);
2768 return rc;
2769 }
David Collins7370f1a2017-01-18 16:21:53 -08002770 }
2771
2772 rc = cprh_kbss_init_aging(ctrl);
2773 if (rc) {
2774 cpr3_err(ctrl, "failed to initialize aging configurations, rc=%d\n",
2775 rc);
2776 return rc;
2777 }
2778
2779 platform_set_drvdata(pdev, ctrl);
2780
David Collins7370f1a2017-01-18 16:21:53 -08002781 return cpr3_regulator_register(pdev, ctrl);
2782}
2783
2784static int cprh_kbss_regulator_remove(struct platform_device *pdev)
2785{
2786 struct cpr3_controller *ctrl = platform_get_drvdata(pdev);
2787
2788 return cpr3_regulator_unregister(ctrl);
2789}
2790
2791static struct platform_driver cprh_kbss_regulator_driver = {
2792 .driver = {
2793 .name = "qcom,cprh-kbss-regulator",
2794 .of_match_table = cprh_regulator_match_table,
2795 .owner = THIS_MODULE,
2796 },
2797 .probe = cprh_kbss_regulator_probe,
2798 .remove = cprh_kbss_regulator_remove,
2799 .suspend = cprh_kbss_regulator_suspend,
2800 .resume = cprh_kbss_regulator_resume,
2801};
2802
2803static int cpr_regulator_init(void)
2804{
2805 return platform_driver_register(&cprh_kbss_regulator_driver);
2806}
2807
2808static void cpr_regulator_exit(void)
2809{
2810 platform_driver_unregister(&cprh_kbss_regulator_driver);
2811}
2812
2813MODULE_DESCRIPTION("CPRh KBSS regulator driver");
2814MODULE_LICENSE("GPL v2");
2815
2816arch_initcall(cpr_regulator_init);
2817module_exit(cpr_regulator_exit);