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