• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2017 Fuzhou Rockchip Electronics Co., Ltd
3  *
4  * SPDX-License-Identifier: GPL-2.0+
5  */
6 #include <linux/clk.h>
7 #include <linux/cpufreq.h>
8 #include <linux/devfreq.h>
9 #include <linux/mfd/syscon.h>
10 #include <linux/module.h>
11 #include <linux/nvmem-consumer.h>
12 #include <linux/regmap.h>
13 #include <linux/regulator/consumer.h>
14 #include <linux/slab.h>
15 #include <linux/soc/rockchip/pvtm.h>
16 #include <linux/thermal.h>
17 #include <linux/pm_opp.h>
18 #include <linux/version.h>
19 #include <soc/rockchip/rockchip_opp_select.h>
20 
21 #include "../../clk/rockchip/clk.h"
22 #include "../../opp/opp.h"
23 #include "../../devfreq/governor.h"
24 
25 #define MAX_PROP_NAME_LEN	6
26 #define SEL_TABLE_END		~1
27 #define AVS_DELETE_OPP		0
28 #define AVS_SCALING_RATE	1
29 
30 #define LEAKAGE_V1		1
31 #define LEAKAGE_V2		2
32 #define LEAKAGE_V3		3
33 
34 #define to_thermal_opp_info(nb) container_of(nb, struct thermal_opp_info, \
35 					     thermal_nb)
36 
37 struct sel_table {
38 	int min;
39 	int max;
40 	int sel;
41 };
42 
43 struct bin_sel_table {
44 	int bin;
45 	int sel;
46 };
47 
48 struct pvtm_config {
49 	unsigned int freq;
50 	unsigned int volt;
51 	unsigned int ch[2];
52 	unsigned int sample_time;
53 	unsigned int num;
54 	unsigned int err;
55 	unsigned int ref_temp;
56 	int temp_prop[2];
57 	const char *tz_name;
58 	struct thermal_zone_device *tz;
59 };
60 
61 struct lkg_conversion_table {
62 	int temp;
63 	int conv;
64 };
65 
66 #define PVTM_CH_MAX	8
67 #define PVTM_SUB_CH_MAX	8
68 
69 #define FRAC_BITS 10
70 #define int_to_frac(x) ((x) << FRAC_BITS)
71 #define frac_to_int(x) ((x) >> FRAC_BITS)
72 
73 static int pvtm_value[PVTM_CH_MAX][PVTM_SUB_CH_MAX];
74 static int lkg_version;
75 
76 /*
77  * temp = temp * 10
78  * conv = exp(-ln(1.2) / 5 * (temp - 23)) * 100
79  */
80 static const struct lkg_conversion_table conv_table[] = {
81 	{ 200, 111 },
82 	{ 205, 109 },
83 	{ 210, 107 },
84 	{ 215, 105 },
85 	{ 220, 103 },
86 	{ 225, 101 },
87 	{ 230, 100 },
88 	{ 235, 98 },
89 	{ 240, 96 },
90 	{ 245, 94 },
91 	{ 250, 92 },
92 	{ 255, 91 },
93 	{ 260, 89 },
94 	{ 265, 88 },
95 	{ 270, 86 },
96 	{ 275, 84 },
97 	{ 280, 83 },
98 	{ 285, 81 },
99 	{ 290, 80 },
100 	{ 295, 78 },
101 	{ 300, 77 },
102 	{ 305, 76 },
103 	{ 310, 74 },
104 	{ 315, 73 },
105 	{ 320, 72 },
106 	{ 325, 70 },
107 	{ 330, 69 },
108 	{ 335, 68 },
109 	{ 340, 66 },
110 	{ 345, 65 },
111 	{ 350, 64 },
112 	{ 355, 63 },
113 	{ 360, 62 },
114 	{ 365, 61 },
115 	{ 370, 60 },
116 	{ 375, 58 },
117 	{ 380, 57 },
118 	{ 385, 56 },
119 	{ 390, 55 },
120 	{ 395, 54 },
121 	{ 400, 53 },
122 };
123 
rockchip_nvmem_cell_read_common(struct device_node * np,const char * cell_id,void * val,size_t count)124 static int rockchip_nvmem_cell_read_common(struct device_node *np,
125 					   const char *cell_id,
126 					   void *val, size_t count)
127 {
128 	struct nvmem_cell *cell;
129 	void *buf;
130 	size_t len;
131 
132 	cell = of_nvmem_cell_get(np, cell_id);
133 	if (IS_ERR(cell))
134 		return PTR_ERR(cell);
135 
136 	buf = nvmem_cell_read(cell, &len);
137 	if (IS_ERR(buf)) {
138 		nvmem_cell_put(cell);
139 		return PTR_ERR(buf);
140 	}
141 	if (len != count) {
142 		kfree(buf);
143 		nvmem_cell_put(cell);
144 		return -EINVAL;
145 	}
146 	memcpy(val, buf, count);
147 	kfree(buf);
148 	nvmem_cell_put(cell);
149 
150 	return 0;
151 }
152 
rockchip_nvmem_cell_read_u8(struct device_node * np,const char * cell_id,u8 * val)153 int rockchip_nvmem_cell_read_u8(struct device_node *np, const char *cell_id,
154 				u8 *val)
155 {
156 	return rockchip_nvmem_cell_read_common(np, cell_id, val, sizeof(*val));
157 }
158 EXPORT_SYMBOL(rockchip_nvmem_cell_read_u8);
159 
rockchip_nvmem_cell_read_u16(struct device_node * np,const char * cell_id,u16 * val)160 int rockchip_nvmem_cell_read_u16(struct device_node *np, const char *cell_id,
161 				 u16 *val)
162 {
163 	return rockchip_nvmem_cell_read_common(np, cell_id, val, sizeof(*val));
164 }
165 EXPORT_SYMBOL(rockchip_nvmem_cell_read_u16);
166 
rockchip_get_sel_table(struct device_node * np,char * porp_name,struct sel_table ** table)167 static int rockchip_get_sel_table(struct device_node *np, char *porp_name,
168 				  struct sel_table **table)
169 {
170 	struct sel_table *sel_table;
171 	const struct property *prop;
172 	int count, i;
173 
174 	prop = of_find_property(np, porp_name, NULL);
175 	if (!prop)
176 		return -EINVAL;
177 
178 	if (!prop->value)
179 		return -ENODATA;
180 
181 	count = of_property_count_u32_elems(np, porp_name);
182 	if (count < 0)
183 		return -EINVAL;
184 
185 	if (count % 3)
186 		return -EINVAL;
187 
188 	sel_table = kzalloc(sizeof(*sel_table) * (count / 3 + 1), GFP_KERNEL);
189 	if (!sel_table)
190 		return -ENOMEM;
191 
192 	for (i = 0; i < count / 3; i++) {
193 		of_property_read_u32_index(np, porp_name, 3 * i,
194 					   &sel_table[i].min);
195 		of_property_read_u32_index(np, porp_name, 3 * i + 1,
196 					   &sel_table[i].max);
197 		of_property_read_u32_index(np, porp_name, 3 * i + 2,
198 					   &sel_table[i].sel);
199 	}
200 	sel_table[i].min = 0;
201 	sel_table[i].max = 0;
202 	sel_table[i].sel = SEL_TABLE_END;
203 
204 	*table = sel_table;
205 
206 	return 0;
207 }
208 
rockchip_get_bin_sel_table(struct device_node * np,char * porp_name,struct bin_sel_table ** table)209 static int rockchip_get_bin_sel_table(struct device_node *np, char *porp_name,
210 				      struct bin_sel_table **table)
211 {
212 	struct bin_sel_table *sel_table;
213 	const struct property *prop;
214 	int count, i;
215 
216 	prop = of_find_property(np, porp_name, NULL);
217 	if (!prop)
218 		return -EINVAL;
219 
220 	if (!prop->value)
221 		return -ENODATA;
222 
223 	count = of_property_count_u32_elems(np, porp_name);
224 	if (count < 0)
225 		return -EINVAL;
226 
227 	if (count % 2)
228 		return -EINVAL;
229 
230 	sel_table = kzalloc(sizeof(*sel_table) * (count / 2 + 1), GFP_KERNEL);
231 	if (!sel_table)
232 		return -ENOMEM;
233 
234 	for (i = 0; i < count / 2; i++) {
235 		of_property_read_u32_index(np, porp_name, 2 * i,
236 					   &sel_table[i].bin);
237 		of_property_read_u32_index(np, porp_name, 2 * i + 1,
238 					   &sel_table[i].sel);
239 	}
240 
241 	sel_table[i].bin = 0;
242 	sel_table[i].sel = SEL_TABLE_END;
243 
244 	*table = sel_table;
245 
246 	return 0;
247 }
248 
rockchip_get_sel(struct device_node * np,char * name,int value,int * sel)249 static int rockchip_get_sel(struct device_node *np, char *name,
250 			    int value, int *sel)
251 {
252 	struct sel_table *table = NULL;
253 	int i, ret = -EINVAL;
254 
255 	if (!sel)
256 		return -EINVAL;
257 
258 	if (rockchip_get_sel_table(np, name, &table))
259 		return -EINVAL;
260 
261 	for (i = 0; table[i].sel != SEL_TABLE_END; i++) {
262 		if (value >= table[i].min) {
263 			*sel = table[i].sel;
264 			ret = 0;
265 		}
266 	}
267 	kfree(table);
268 
269 	return ret;
270 }
271 
rockchip_get_bin_sel(struct device_node * np,char * name,int value,int * sel)272 static int rockchip_get_bin_sel(struct device_node *np, char *name,
273 				int value, int *sel)
274 {
275 	struct bin_sel_table *table = NULL;
276 	int i, ret = -EINVAL;
277 
278 	if (!sel)
279 		return -EINVAL;
280 
281 	if (rockchip_get_bin_sel_table(np, name, &table))
282 		return -EINVAL;
283 
284 	for (i = 0; table[i].sel != SEL_TABLE_END; i++) {
285 		if (value == table[i].bin) {
286 			*sel = table[i].sel;
287 			ret = 0;
288 			break;
289 		}
290 	}
291 	kfree(table);
292 
293 	return ret;
294 }
295 
rockchip_parse_pvtm_config(struct device_node * np,struct pvtm_config * pvtm)296 static int rockchip_parse_pvtm_config(struct device_node *np,
297 				      struct pvtm_config *pvtm)
298 {
299 	if (of_property_read_u32(np, "rockchip,pvtm-freq", &pvtm->freq))
300 		return -EINVAL;
301 	if (of_property_read_u32(np, "rockchip,pvtm-volt", &pvtm->volt))
302 		return -EINVAL;
303 	if (of_property_read_u32_array(np, "rockchip,pvtm-ch", pvtm->ch, 2))
304 		return -EINVAL;
305 	if (pvtm->ch[0] >= PVTM_CH_MAX || pvtm->ch[1] >= PVTM_SUB_CH_MAX)
306 		return -EINVAL;
307 	if (of_property_read_u32(np, "rockchip,pvtm-sample-time",
308 				 &pvtm->sample_time))
309 		return -EINVAL;
310 	if (of_property_read_u32(np, "rockchip,pvtm-number", &pvtm->num))
311 		return -EINVAL;
312 	if (of_property_read_u32(np, "rockchip,pvtm-error", &pvtm->err))
313 		return -EINVAL;
314 	if (of_property_read_u32(np, "rockchip,pvtm-ref-temp", &pvtm->ref_temp))
315 		return -EINVAL;
316 	if (of_property_read_u32_array(np, "rockchip,pvtm-temp-prop",
317 				       pvtm->temp_prop, 2))
318 		return -EINVAL;
319 	if (of_property_read_string(np, "rockchip,pvtm-thermal-zone",
320 				    &pvtm->tz_name)) {
321 		if (of_property_read_string(np, "rockchip,thermal-zone",
322 					    &pvtm->tz_name))
323 			return -EINVAL;
324 	}
325 	pvtm->tz = thermal_zone_get_zone_by_name(pvtm->tz_name);
326 	if (IS_ERR(pvtm->tz))
327 		return -EINVAL;
328 	if (!pvtm->tz->ops->get_temp)
329 		return -EINVAL;
330 
331 	return 0;
332 }
333 
rockchip_get_pvtm_specific_value(struct device * dev,struct device_node * np,struct clk * clk,struct regulator * reg,int * target_value)334 static int rockchip_get_pvtm_specific_value(struct device *dev,
335 					    struct device_node *np,
336 					    struct clk *clk,
337 					    struct regulator *reg,
338 					    int *target_value)
339 {
340 	struct pvtm_config *pvtm;
341 	unsigned long old_freq;
342 	unsigned int old_volt;
343 	int cur_temp, diff_temp;
344 	int cur_value, total_value, avg_value, diff_value;
345 	int min_value, max_value;
346 	int ret = 0, i = 0, retry = 2;
347 
348 	pvtm = kzalloc(sizeof(*pvtm), GFP_KERNEL);
349 	if (!pvtm)
350 		return -ENOMEM;
351 
352 	ret = rockchip_parse_pvtm_config(np, pvtm);
353 	if (ret)
354 		goto pvtm_value_out;
355 
356 	old_freq = clk_get_rate(clk);
357 	old_volt = regulator_get_voltage(reg);
358 
359 	/*
360 	 * Set pvtm_freq to the lowest frequency in dts,
361 	 * so change frequency first.
362 	 */
363 	ret = clk_set_rate(clk, pvtm->freq * 1000);
364 	if (ret) {
365 		dev_err(dev, "Failed to set pvtm freq\n");
366 		goto pvtm_value_out;
367 	}
368 
369 	ret = regulator_set_voltage(reg, pvtm->volt, pvtm->volt);
370 	if (ret) {
371 		dev_err(dev, "Failed to set pvtm_volt\n");
372 		goto restore_clk;
373 	}
374 
375 	/* The first few values may be fluctuant, if error is too big, retry*/
376 	while (retry--) {
377 		total_value = 0;
378 		min_value = INT_MAX;
379 		max_value = 0;
380 
381 		for (i = 0; i < pvtm->num; i++) {
382 			cur_value = rockchip_get_pvtm_value(pvtm->ch[0],
383 							    pvtm->ch[1],
384 							    pvtm->sample_time);
385 			if (cur_value <= 0) {
386 				ret = -EINVAL;
387 				goto resetore_volt;
388 			}
389 			if (cur_value < min_value)
390 				min_value = cur_value;
391 			if (cur_value > max_value)
392 				max_value = cur_value;
393 			total_value += cur_value;
394 		}
395 		if (max_value - min_value < pvtm->err)
396 			break;
397 	}
398 	if (!total_value || !pvtm->num) {
399 		ret = -EINVAL;
400 		goto resetore_volt;
401 	}
402 	avg_value = total_value / pvtm->num;
403 
404 	/*
405 	 * As pvtm is influenced by temperature, compute difference between
406 	 * current temperature and reference temperature
407 	 */
408 	pvtm->tz->ops->get_temp(pvtm->tz, &cur_temp);
409 	diff_temp = (cur_temp / 1000 - pvtm->ref_temp);
410 	diff_value = diff_temp *
411 		(diff_temp < 0 ? pvtm->temp_prop[0] : pvtm->temp_prop[1]);
412 	*target_value = avg_value + diff_value;
413 
414 	pvtm_value[pvtm->ch[0]][pvtm->ch[1]] = *target_value;
415 
416 	dev_info(dev, "temp=%d, pvtm=%d (%d + %d)\n",
417 		 cur_temp, *target_value, avg_value, diff_value);
418 
419 resetore_volt:
420 	regulator_set_voltage(reg, old_volt, old_volt);
421 restore_clk:
422 	clk_set_rate(clk, old_freq);
423 pvtm_value_out:
424 	kfree(pvtm);
425 
426 	return ret;
427 }
428 
429 /**
430  * mul_frac() - multiply two fixed-point numbers
431  * @x:	first multiplicand
432  * @y:	second multiplicand
433  *
434  * Return: the result of multiplying two fixed-point numbers.  The
435  * result is also a fixed-point number.
436  */
mul_frac(s64 x,s64 y)437 static inline s64 mul_frac(s64 x, s64 y)
438 {
439 	return (x * y) >> FRAC_BITS;
440 }
441 
temp_to_conversion_rate(int temp)442 static int temp_to_conversion_rate(int temp)
443 {
444 	int high, low, mid;
445 
446 	low = 0;
447 	high = ARRAY_SIZE(conv_table) - 1;
448 	mid = (high + low) / 2;
449 
450 	/* No temp available, return max conversion_rate */
451 	if (temp <= conv_table[low].temp)
452 		return conv_table[low].conv;
453 	if (temp >= conv_table[high].temp)
454 		return conv_table[high].conv;
455 
456 	while (low <= high) {
457 		if (temp <= conv_table[mid].temp && temp >
458 		    conv_table[mid - 1].temp) {
459 			return conv_table[mid - 1].conv +
460 			    (conv_table[mid].conv - conv_table[mid - 1].conv) *
461 			    (temp - conv_table[mid - 1].temp) /
462 			    (conv_table[mid].temp - conv_table[mid - 1].temp);
463 		} else if (temp > conv_table[mid].temp) {
464 			low = mid + 1;
465 		} else {
466 			high = mid - 1;
467 		}
468 		mid = (low + high) / 2;
469 	}
470 
471 	return 100;
472 }
473 
rockchip_adjust_leakage(struct device * dev,struct device_node * np,int * leakage)474 static int rockchip_adjust_leakage(struct device *dev, struct device_node *np,
475 				   int *leakage)
476 {
477 	struct nvmem_cell *cell;
478 	u8 value = 0;
479 	u32 temp;
480 	int conversion;
481 	int ret;
482 
483 	cell = of_nvmem_cell_get(np, "leakage_temp");
484 	if (IS_ERR(cell))
485 		goto next;
486 	nvmem_cell_put(cell);
487 	ret = rockchip_nvmem_cell_read_u8(np, "leakage_temp", &value);
488 	if (ret) {
489 		dev_err(dev, "Failed to get leakage temp\n");
490 		return -EINVAL;
491 	}
492 	/*
493 	 * The ambient temperature range: 20C to 40C
494 	 * In order to improve the precision, we do a conversion.
495 	 * The temp in efuse : temp_efuse = (temp - 20) / (40 - 20) * 63
496 	 * The ambient temp : temp = (temp_efuse / 63) * (40 - 20) + 20
497 	 * Reserves a decimal point : temp = temp * 10
498 	 */
499 	temp = value;
500 	temp = mul_frac((int_to_frac(temp) / 63 * 20 + int_to_frac(20)),
501 			int_to_frac(10));
502 	conversion = temp_to_conversion_rate(frac_to_int(temp));
503 	*leakage = *leakage * conversion / 100;
504 
505 next:
506 	cell = of_nvmem_cell_get(np, "leakage_volt");
507 	if (IS_ERR(cell))
508 		return 0;
509 	nvmem_cell_put(cell);
510 	ret = rockchip_nvmem_cell_read_u8(np, "leakage_volt", &value);
511 	if (ret) {
512 		dev_err(dev, "Failed to get leakage volt\n");
513 		return -EINVAL;
514 	}
515 	/*
516 	 * if ft write leakage use 1.35v, need convert to 1v.
517 	 * leakage(1v) = leakage(1.35v) / 4
518 	 */
519 	if (value)
520 		*leakage = *leakage / 4;
521 
522 	return 0;
523 }
524 
rockchip_get_leakage_version(int * version)525 static int rockchip_get_leakage_version(int *version)
526 {
527 	if (*version)
528 		return 0;
529 
530 	if (of_machine_is_compatible("rockchip,rk3368"))
531 		*version = LEAKAGE_V2;
532 	else if (of_machine_is_compatible("rockchip,rv1126") ||
533 		 of_machine_is_compatible("rockchip,rv1109"))
534 		*version = LEAKAGE_V3;
535 	else
536 		*version = LEAKAGE_V1;
537 
538 	return 0;
539 }
540 
rockchip_get_leakage_v1(struct device * dev,struct device_node * np,char * lkg_name,int * leakage)541 static int rockchip_get_leakage_v1(struct device *dev, struct device_node *np,
542 				   char *lkg_name, int *leakage)
543 {
544 	struct nvmem_cell *cell;
545 	int ret = 0;
546 	u8 value = 0;
547 
548 	cell = of_nvmem_cell_get(np, "leakage");
549 	if (IS_ERR(cell)) {
550 		ret = rockchip_nvmem_cell_read_u8(np, lkg_name, &value);
551 	} else {
552 		nvmem_cell_put(cell);
553 		ret = rockchip_nvmem_cell_read_u8(np, "leakage", &value);
554 	}
555 	if (ret)
556 		dev_err(dev, "Failed to get %s\n", lkg_name);
557 	else
558 		*leakage = value;
559 
560 	return ret;
561 }
562 
rockchip_get_leakage_v2(struct device * dev,struct device_node * np,char * lkg_name,int * leakage)563 static int rockchip_get_leakage_v2(struct device *dev, struct device_node *np,
564 				   char *lkg_name, int *leakage)
565 {
566 	int lkg = 0, ret = 0;
567 
568 	if (rockchip_get_leakage_v1(dev, np, lkg_name, &lkg))
569 		return -EINVAL;
570 
571 	ret = rockchip_adjust_leakage(dev, np, &lkg);
572 	if (ret)
573 		dev_err(dev, "Failed to adjust leakage, value=%d\n", lkg);
574 	else
575 		*leakage = lkg;
576 
577 	return ret;
578 }
579 
rockchip_get_leakage_v3(struct device * dev,struct device_node * np,char * lkg_name,int * leakage)580 static int rockchip_get_leakage_v3(struct device *dev, struct device_node *np,
581 				   char *lkg_name, int *leakage)
582 {
583 	int lkg = 0;
584 
585 	if (rockchip_get_leakage_v1(dev, np, lkg_name, &lkg))
586 		return -EINVAL;
587 
588 	*leakage = (((lkg & 0xf8) >> 3) * 1000) + ((lkg & 0x7) * 125);
589 
590 	return 0;
591 }
592 
rockchip_of_get_leakage(struct device * dev,char * lkg_name,int * leakage)593 int rockchip_of_get_leakage(struct device *dev, char *lkg_name, int *leakage)
594 {
595 	struct device_node *np;
596 	int ret = -EINVAL;
597 
598 	np = of_parse_phandle(dev->of_node, "operating-points-v2", 0);
599 	if (!np) {
600 		dev_warn(dev, "OPP-v2 not supported\n");
601 		return -ENOENT;
602 	}
603 
604 	rockchip_get_leakage_version(&lkg_version);
605 
606 	switch (lkg_version) {
607 	case LEAKAGE_V1:
608 		ret = rockchip_get_leakage_v1(dev, np, lkg_name, leakage);
609 		break;
610 	case LEAKAGE_V2:
611 		ret = rockchip_get_leakage_v2(dev, np, lkg_name, leakage);
612 		break;
613 	case LEAKAGE_V3:
614 		ret = rockchip_get_leakage_v3(dev, np, lkg_name, leakage);
615 		if (!ret) {
616 			/*
617 			 * round up to the nearest whole number for calculating
618 			 * static power,  it does not need to be precise.
619 			 */
620 			if (*leakage % 1000 > 500)
621 				*leakage = *leakage / 1000 + 1;
622 			else
623 				*leakage = *leakage / 1000;
624 		}
625 		break;
626 	default:
627 		break;
628 	}
629 
630 	of_node_put(np);
631 
632 	return ret;
633 }
634 EXPORT_SYMBOL(rockchip_of_get_leakage);
635 
rockchip_of_get_lkg_sel(struct device * dev,struct device_node * np,char * lkg_name,int process,int * volt_sel,int * scale_sel)636 void rockchip_of_get_lkg_sel(struct device *dev, struct device_node *np,
637 			     char *lkg_name, int process,
638 			     int *volt_sel, int *scale_sel)
639 {
640 	struct property *prop = NULL;
641 	int leakage = -EINVAL, ret = 0;
642 	char name[NAME_MAX];
643 
644 	rockchip_get_leakage_version(&lkg_version);
645 
646 	switch (lkg_version) {
647 	case LEAKAGE_V1:
648 		ret = rockchip_get_leakage_v1(dev, np, lkg_name, &leakage);
649 		if (ret)
650 			return;
651 		dev_info(dev, "leakage=%d\n", leakage);
652 		break;
653 	case LEAKAGE_V2:
654 		ret = rockchip_get_leakage_v2(dev, np, lkg_name, &leakage);
655 		if (ret)
656 			return;
657 		dev_info(dev, "leakage=%d\n", leakage);
658 		break;
659 	case LEAKAGE_V3:
660 		ret = rockchip_get_leakage_v3(dev, np, lkg_name, &leakage);
661 		if (ret)
662 			return;
663 		dev_info(dev, "leakage=%d.%d\n", leakage / 1000,
664 			 leakage % 1000);
665 		break;
666 	default:
667 		return;
668 	}
669 
670 	if (!volt_sel)
671 		goto next;
672 	if (process >= 0) {
673 		snprintf(name, sizeof(name),
674 			 "rockchip,p%d-leakage-voltage-sel", process);
675 		prop = of_find_property(np, name, NULL);
676 	}
677 	if (!prop)
678 		sprintf(name, "rockchip,leakage-voltage-sel");
679 	ret = rockchip_get_sel(np, name, leakage, volt_sel);
680 	if (!ret)
681 		dev_info(dev, "leakage-volt-sel=%d\n", *volt_sel);
682 
683 next:
684 	if (!scale_sel)
685 		return;
686 	if (process >= 0) {
687 		snprintf(name, sizeof(name),
688 			 "rockchip,p%d-leakage-scaling-sel", process);
689 		prop = of_find_property(np, name, NULL);
690 	}
691 	if (!prop)
692 		sprintf(name, "rockchip,leakage-scaling-sel");
693 	ret = rockchip_get_sel(np, name, leakage, scale_sel);
694 	if (!ret)
695 		dev_info(dev, "leakage-scale=%d\n", *scale_sel);
696 }
697 EXPORT_SYMBOL(rockchip_of_get_lkg_sel);
698 
699 
rockchip_get_pvtm(struct device * dev,struct device_node * np,char * reg_name)700 static int rockchip_get_pvtm(struct device *dev, struct device_node *np,
701 			     char *reg_name)
702 {
703 	struct regulator *reg;
704 	struct clk *clk;
705 	unsigned int ch[2];
706 	int pvtm = 0;
707 	u16 tmp = 0;
708 
709 	if (!rockchip_nvmem_cell_read_u16(np, "pvtm", &tmp) && tmp) {
710 		pvtm = 10 * tmp;
711 		dev_info(dev, "pvtm = %d, from nvmem\n", pvtm);
712 		return pvtm;
713 	}
714 
715 	if (of_property_read_u32_array(np, "rockchip,pvtm-ch", ch, 2))
716 		return -EINVAL;
717 
718 	if (ch[0] >= PVTM_CH_MAX || ch[1] >= PVTM_SUB_CH_MAX)
719 		return -EINVAL;
720 
721 	if (pvtm_value[ch[0]][ch[1]]) {
722 		dev_info(dev, "pvtm = %d, form pvtm_value\n", pvtm_value[ch[0]][ch[1]]);
723 		return pvtm_value[ch[0]][ch[1]];
724 	}
725 
726 	clk = clk_get(dev, NULL);
727 	if (IS_ERR_OR_NULL(clk)) {
728 		dev_warn(dev, "Failed to get clk\n");
729 		return PTR_ERR_OR_ZERO(clk);
730 	}
731 
732 	reg = regulator_get_optional(dev, reg_name);
733 	if (IS_ERR_OR_NULL(reg)) {
734 		dev_warn(dev, "Failed to get reg\n");
735 		clk_put(clk);
736 		return PTR_ERR_OR_ZERO(reg);
737 	}
738 
739 	rockchip_get_pvtm_specific_value(dev, np, clk, reg, &pvtm);
740 
741 	regulator_put(reg);
742 	clk_put(clk);
743 
744 	return pvtm;
745 }
746 
rockchip_of_get_pvtm_sel(struct device * dev,struct device_node * np,char * reg_name,int process,int * volt_sel,int * scale_sel)747 void rockchip_of_get_pvtm_sel(struct device *dev, struct device_node *np,
748 			      char *reg_name, int process,
749 			      int *volt_sel, int *scale_sel)
750 {
751 	struct property *prop = NULL;
752 	char name[NAME_MAX];
753 	int pvtm, ret;
754 
755 	pvtm = rockchip_get_pvtm(dev, np, reg_name);
756 	if (pvtm <= 0)
757 		return;
758 
759 	if (!volt_sel)
760 		goto next;
761 	if (process >= 0) {
762 		snprintf(name, sizeof(name),
763 			 "rockchip,p%d-pvtm-voltage-sel", process);
764 		prop = of_find_property(np, name, NULL);
765 	}
766 	if (!prop)
767 		sprintf(name, "rockchip,pvtm-voltage-sel");
768 	ret = rockchip_get_sel(np, name, pvtm, volt_sel);
769 	if (!ret && volt_sel)
770 		dev_info(dev, "pvtm-volt-sel=%d\n", *volt_sel);
771 
772 next:
773 	if (!scale_sel)
774 		return;
775 	if (process >= 0) {
776 		snprintf(name, sizeof(name),
777 			 "rockchip,p%d-pvtm-scaling-sel", process);
778 		prop = of_find_property(np, name, NULL);
779 	}
780 	if (!prop)
781 		sprintf(name, "rockchip,pvtm-scaling-sel");
782 	ret = rockchip_get_sel(np, name, pvtm, scale_sel);
783 	if (!ret)
784 		dev_info(dev, "pvtm-scale=%d\n", *scale_sel);
785 }
786 EXPORT_SYMBOL(rockchip_of_get_pvtm_sel);
787 
rockchip_of_get_bin_sel(struct device * dev,struct device_node * np,int bin,int * scale_sel)788 void rockchip_of_get_bin_sel(struct device *dev, struct device_node *np,
789 			     int bin, int *scale_sel)
790 {
791 	int ret = 0;
792 
793 	if (!scale_sel || bin < 0)
794 		return;
795 
796 	ret = rockchip_get_bin_sel(np, "rockchip,bin-scaling-sel",
797 				   bin, scale_sel);
798 	if (!ret)
799 		dev_info(dev, "bin-scale=%d\n", *scale_sel);
800 }
801 EXPORT_SYMBOL(rockchip_of_get_bin_sel);
802 
rockchip_of_get_bin_volt_sel(struct device * dev,struct device_node * np,int bin,int * bin_volt_sel)803 void rockchip_of_get_bin_volt_sel(struct device *dev, struct device_node *np,
804 				  int bin, int *bin_volt_sel)
805 {
806 	int ret = 0;
807 
808 	if (!bin_volt_sel || bin < 0)
809 		return;
810 
811 	ret = rockchip_get_bin_sel(np, "rockchip,bin-voltage-sel",
812 				   bin, bin_volt_sel);
813 	if (!ret)
814 		dev_info(dev, "bin-volt-sel=%d\n", *bin_volt_sel);
815 }
816 EXPORT_SYMBOL(rockchip_of_get_bin_volt_sel);
817 
rockchip_get_opp_data(const struct of_device_id * matches,struct rockchip_opp_info * info)818 void rockchip_get_opp_data(const struct of_device_id *matches,
819 			   struct rockchip_opp_info *info)
820 {
821 	const struct of_device_id *match;
822 	struct device_node *node;
823 
824 	node = of_find_node_by_path("/");
825 	match = of_match_node(matches, node);
826 	if (match && match->data)
827 		info->data = match->data;
828 	of_node_put(node);
829 }
830 EXPORT_SYMBOL(rockchip_get_opp_data);
831 
rockchip_get_volt_rm_table(struct device * dev,struct device_node * np,char * porp_name,struct volt_rm_table ** table)832 int rockchip_get_volt_rm_table(struct device *dev, struct device_node *np,
833 			       char *porp_name, struct volt_rm_table **table)
834 {
835 	struct volt_rm_table *rm_table;
836 	const struct property *prop;
837 	int count, i;
838 
839 	prop = of_find_property(np, porp_name, NULL);
840 	if (!prop)
841 		return -EINVAL;
842 
843 	if (!prop->value)
844 		return -ENODATA;
845 
846 	count = of_property_count_u32_elems(np, porp_name);
847 	if (count < 0)
848 		return -EINVAL;
849 
850 	if (count % 2)
851 		return -EINVAL;
852 
853 	rm_table = devm_kzalloc(dev, sizeof(*rm_table) * (count / 2 + 1),
854 				GFP_KERNEL);
855 	if (!rm_table)
856 		return -ENOMEM;
857 
858 	for (i = 0; i < count / 2; i++) {
859 		of_property_read_u32_index(np, porp_name, 2 * i,
860 					   &rm_table[i].volt);
861 		of_property_read_u32_index(np, porp_name, 2 * i + 1,
862 					   &rm_table[i].rm);
863 	}
864 
865 	rm_table[i].volt = 0;
866 	rm_table[i].rm = VOLT_RM_TABLE_END;
867 
868 	*table = rm_table;
869 
870 	return 0;
871 }
872 EXPORT_SYMBOL(rockchip_get_volt_rm_table);
873 
rockchip_get_scale_volt_sel(struct device * dev,char * lkg_name,char * reg_name,int bin,int process,int * scale,int * volt_sel)874 void rockchip_get_scale_volt_sel(struct device *dev, char *lkg_name,
875 				 char *reg_name, int bin, int process,
876 				 int *scale, int *volt_sel)
877 {
878 	struct device_node *np;
879 	int lkg_scale = 0, pvtm_scale = 0, bin_scale = 0;
880 	int lkg_volt_sel = -EINVAL, pvtm_volt_sel = -EINVAL;
881 	int bin_volt_sel = -EINVAL;
882 
883 	np = of_parse_phandle(dev->of_node, "operating-points-v2", 0);
884 	if (!np) {
885 		dev_warn(dev, "OPP-v2 not supported\n");
886 		return;
887 	}
888 
889 	rockchip_of_get_lkg_sel(dev, np, lkg_name, process,
890 				&lkg_volt_sel, &lkg_scale);
891 	rockchip_of_get_pvtm_sel(dev, np, reg_name, process,
892 				 &pvtm_volt_sel, &pvtm_scale);
893 	rockchip_of_get_bin_sel(dev, np, bin, &bin_scale);
894 	rockchip_of_get_bin_volt_sel(dev, np, bin, &bin_volt_sel);
895 	if (scale)
896 		*scale = max3(lkg_scale, pvtm_scale, bin_scale);
897 	if (volt_sel) {
898 		if (bin_volt_sel >= 0)
899 			*volt_sel = bin_volt_sel;
900 		else
901 			*volt_sel = max(lkg_volt_sel, pvtm_volt_sel);
902 	}
903 
904 	of_node_put(np);
905 }
906 EXPORT_SYMBOL(rockchip_get_scale_volt_sel);
907 
rockchip_set_opp_prop_name(struct device * dev,int process,int volt_sel)908 struct opp_table *rockchip_set_opp_prop_name(struct device *dev, int process,
909 					     int volt_sel)
910 {
911 	char name[MAX_PROP_NAME_LEN];
912 
913 	if (process >= 0) {
914 		if (volt_sel >= 0)
915 			snprintf(name, MAX_PROP_NAME_LEN, "P%d-L%d",
916 				 process, volt_sel);
917 		else
918 			snprintf(name, MAX_PROP_NAME_LEN, "P%d", process);
919 	} else if (volt_sel >= 0) {
920 		snprintf(name, MAX_PROP_NAME_LEN, "L%d", volt_sel);
921 	} else {
922 		return NULL;
923 	}
924 
925 	return dev_pm_opp_set_prop_name(dev, name);
926 }
927 EXPORT_SYMBOL(rockchip_set_opp_prop_name);
928 
rockchip_adjust_opp_by_irdrop(struct device * dev,struct device_node * np,unsigned long * safe_rate,unsigned long * max_rate)929 static int rockchip_adjust_opp_by_irdrop(struct device *dev,
930 					 struct device_node *np,
931 					 unsigned long *safe_rate,
932 					 unsigned long *max_rate)
933 {
934 	struct sel_table *irdrop_table = NULL;
935 	struct opp_table *opp_table;
936 	struct dev_pm_opp *opp;
937 	int evb_irdrop = 0, board_irdrop, delta_irdrop;
938 	int tmp_safe_rate = 0, opp_rate, i, ret = 0;
939 	u32 max_volt = UINT_MAX;
940 	bool reach_max_volt = false;
941 
942 	of_property_read_u32_index(np, "rockchip,max-volt", 0, &max_volt);
943 	of_property_read_u32_index(np, "rockchip,evb-irdrop", 0, &evb_irdrop);
944 	rockchip_get_sel_table(np, "rockchip,board-irdrop", &irdrop_table);
945 
946 	opp_table = dev_pm_opp_get_opp_table(dev);
947 	if (!opp_table) {
948 		ret =  -ENOMEM;
949 		goto out;
950 	}
951 
952 	mutex_lock(&opp_table->lock);
953 	list_for_each_entry(opp, &opp_table->opp_list, node) {
954 		if (!irdrop_table) {
955 			delta_irdrop = 0;
956 		} else {
957 			opp_rate = opp->rate / 1000000;
958 			board_irdrop = -EINVAL;
959 			for (i = 0; irdrop_table[i].sel != SEL_TABLE_END; i++) {
960 				if (opp_rate >= irdrop_table[i].min)
961 					board_irdrop = irdrop_table[i].sel;
962 			}
963 			if (board_irdrop == -EINVAL)
964 				delta_irdrop = 0;
965 			else
966 				delta_irdrop = board_irdrop - evb_irdrop;
967 		}
968 		if ((opp->supplies[0].u_volt + delta_irdrop) <= max_volt) {
969 			opp->supplies[0].u_volt += delta_irdrop;
970 			opp->supplies[0].u_volt_min += delta_irdrop;
971 			if (opp->supplies[0].u_volt_max + delta_irdrop <=
972 			    max_volt)
973 				opp->supplies[0].u_volt_max += delta_irdrop;
974 			else
975 				opp->supplies[0].u_volt_max = max_volt;
976 			if (!reach_max_volt)
977 				tmp_safe_rate = opp->rate;
978 			if (opp->supplies[0].u_volt == max_volt)
979 				reach_max_volt = true;
980 		} else {
981 			opp->supplies[0].u_volt = max_volt;
982 			opp->supplies[0].u_volt_min = max_volt;
983 			opp->supplies[0].u_volt_max = max_volt;
984 		}
985 		if (max_rate)
986 			*max_rate = opp->rate;
987 		if (safe_rate && tmp_safe_rate != opp->rate)
988 			*safe_rate = tmp_safe_rate;
989 	}
990 	mutex_unlock(&opp_table->lock);
991 
992 	dev_pm_opp_put_opp_table(opp_table);
993 out:
994 	kfree(irdrop_table);
995 
996 	return ret;
997 }
998 
rockchip_adjust_opp_by_mbist_vmin(struct device * dev,struct device_node * np)999 static void rockchip_adjust_opp_by_mbist_vmin(struct device *dev,
1000 					      struct device_node *np)
1001 {
1002 	struct opp_table *opp_table;
1003 	struct dev_pm_opp *opp;
1004 	u32 vmin = 0;
1005 	u8 index = 0;
1006 
1007 	if (rockchip_nvmem_cell_read_u8(np, "mbist-vmin", &index))
1008 		return;
1009 
1010 	if (!index)
1011 		return;
1012 
1013 	if (of_property_read_u32_index(np, "mbist-vmin", index-1, &vmin))
1014 		return;
1015 
1016 	opp_table = dev_pm_opp_get_opp_table(dev);
1017 	if (!opp_table)
1018 		return;
1019 
1020 	mutex_lock(&opp_table->lock);
1021 	list_for_each_entry(opp, &opp_table->opp_list, node) {
1022 		if (opp->supplies->u_volt < vmin) {
1023 			opp->supplies->u_volt = vmin;
1024 			opp->supplies->u_volt_min = vmin;
1025 		}
1026 	}
1027 	mutex_unlock(&opp_table->lock);
1028 }
1029 
rockchip_adjust_opp_table(struct device * dev,unsigned long scale_rate)1030 static int rockchip_adjust_opp_table(struct device *dev,
1031 				     unsigned long scale_rate)
1032 {
1033 	struct dev_pm_opp *opp;
1034 	unsigned long rate;
1035 	int i, count, ret = 0;
1036 
1037 	count = dev_pm_opp_get_opp_count(dev);
1038 	if (count <= 0) {
1039 		ret = count ? count : -ENODATA;
1040 		goto out;
1041 	}
1042 
1043 	for (i = 0, rate = 0; i < count; i++, rate++) {
1044 		/* find next rate */
1045 		opp = dev_pm_opp_find_freq_ceil(dev, &rate);
1046 		if (IS_ERR(opp)) {
1047 			ret = PTR_ERR(opp);
1048 			goto out;
1049 		}
1050 		if (opp->rate > scale_rate)
1051 			dev_pm_opp_remove(dev, opp->rate);
1052 		dev_pm_opp_put(opp);
1053 	}
1054 out:
1055 	return ret;
1056 }
1057 
rockchip_adjust_power_scale(struct device * dev,int scale)1058 int rockchip_adjust_power_scale(struct device *dev, int scale)
1059 {
1060 	struct device_node *np;
1061 	struct clk *clk;
1062 	unsigned long safe_rate = 0, max_rate = 0;
1063 	int irdrop_scale = 0, opp_scale = 0;
1064 	u32 target_scale, avs = 0, avs_scale = 0;
1065 	long scale_rate = 0;
1066 	int ret = 0;
1067 
1068 	np = of_parse_phandle(dev->of_node, "operating-points-v2", 0);
1069 	if (!np) {
1070 		dev_warn(dev, "OPP-v2 not supported\n");
1071 		return -ENOENT;
1072 	}
1073 	of_property_read_u32(np, "rockchip,avs-enable", &avs);
1074 	of_property_read_u32(np, "rockchip,avs", &avs);
1075 	of_property_read_u32(np, "rockchip,avs-scale", &avs_scale);
1076 	rockchip_adjust_opp_by_mbist_vmin(dev, np);
1077 	rockchip_adjust_opp_by_irdrop(dev, np, &safe_rate, &max_rate);
1078 
1079 	dev_info(dev, "avs=%d\n", avs);
1080 	clk = of_clk_get_by_name(np, NULL);
1081 	if (IS_ERR(clk)) {
1082 		if (!safe_rate)
1083 			goto out_np;
1084 		dev_dbg(dev, "Failed to get clk, safe_rate=%lu\n", safe_rate);
1085 		ret = rockchip_adjust_opp_table(dev, safe_rate);
1086 		if (ret)
1087 			dev_err(dev, "Failed to adjust opp table\n");
1088 		goto out_np;
1089 	}
1090 
1091 	if (safe_rate)
1092 		irdrop_scale = rockchip_pll_clk_rate_to_scale(clk, safe_rate);
1093 	if (max_rate)
1094 		opp_scale = rockchip_pll_clk_rate_to_scale(clk, max_rate);
1095 	target_scale = max(irdrop_scale, scale);
1096 	if (target_scale <= 0)
1097 		goto out_clk;
1098 	dev_dbg(dev, "target_scale=%d, irdrop_scale=%d, scale=%d\n",
1099 		target_scale, irdrop_scale, scale);
1100 
1101 	if (avs == AVS_SCALING_RATE) {
1102 		ret = rockchip_pll_clk_adaptive_scaling(clk, target_scale);
1103 		if (ret)
1104 			dev_err(dev, "Failed to adaptive scaling\n");
1105 		if (opp_scale >= avs_scale)
1106 			goto out_clk;
1107 		dev_info(dev, "avs-scale=%d, opp-scale=%d\n", avs_scale,
1108 			 opp_scale);
1109 		scale_rate = rockchip_pll_clk_scale_to_rate(clk, avs_scale);
1110 		if (scale_rate <= 0) {
1111 			dev_err(dev, "Failed to get avs scale rate, %d\n",
1112 				avs_scale);
1113 			goto out_clk;
1114 		}
1115 		dev_dbg(dev, "scale_rate=%lu\n", scale_rate);
1116 		ret = rockchip_adjust_opp_table(dev, scale_rate);
1117 		if (ret)
1118 			dev_err(dev, "Failed to adjust opp table\n");
1119 	} else if (avs == AVS_DELETE_OPP) {
1120 		if (opp_scale >= target_scale)
1121 			goto out_clk;
1122 		dev_info(dev, "target_scale=%d, opp-scale=%d\n", target_scale,
1123 			 opp_scale);
1124 		scale_rate = rockchip_pll_clk_scale_to_rate(clk, target_scale);
1125 		if (scale_rate <= 0) {
1126 			dev_err(dev, "Failed to get scale rate, %d\n",
1127 				target_scale);
1128 			goto out_clk;
1129 		}
1130 		dev_dbg(dev, "scale_rate=%lu\n", scale_rate);
1131 		ret = rockchip_adjust_opp_table(dev, scale_rate);
1132 		if (ret)
1133 			dev_err(dev, "Failed to adjust opp table\n");
1134 	}
1135 
1136 out_clk:
1137 	clk_put(clk);
1138 out_np:
1139 	of_node_put(np);
1140 
1141 	return ret;
1142 }
1143 EXPORT_SYMBOL(rockchip_adjust_power_scale);
1144 
rockchip_init_opp_table(struct device * dev,struct rockchip_opp_info * info,char * lkg_name,char * reg_name)1145 int rockchip_init_opp_table(struct device *dev, struct rockchip_opp_info *info,
1146 			    char *lkg_name, char *reg_name)
1147 {
1148 	struct device_node *np;
1149 	int bin = -EINVAL, process = -EINVAL;
1150 	int scale = 0, volt_sel = -EINVAL;
1151 	int ret = 0, num_clks = 0, i;
1152 
1153 	/* Get OPP descriptor node */
1154 	np = of_parse_phandle(dev->of_node, "operating-points-v2", 0);
1155 	if (!np) {
1156 		dev_dbg(dev, "Failed to find operating-points-v2\n");
1157 		return -ENOENT;
1158 	}
1159 	if (!info)
1160 		goto next;
1161 
1162 	num_clks = of_clk_get_parent_count(np);
1163 	if (num_clks > 0) {
1164 		info->clks = devm_kcalloc(dev, num_clks, sizeof(*info->clks),
1165 					  GFP_KERNEL);
1166 		if (!info->clks) {
1167 			ret = -ENOMEM;
1168 			goto out;
1169 		}
1170 		for (i = 0; i < num_clks; i++) {
1171 			info->clks[i].clk = of_clk_get(np, i);
1172 			if (IS_ERR(info->clks[i].clk)) {
1173 				ret = PTR_ERR(info->clks[i].clk);
1174 				dev_err(dev, "%s: failed to get clk %d\n",
1175 					np->name, i);
1176 				goto out;
1177 			}
1178 		}
1179 		info->num_clks = num_clks;
1180 	}
1181 	if (info->data && info->data->set_read_margin) {
1182 		info->current_rm = UINT_MAX;
1183 		info->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
1184 		if (IS_ERR(info->grf))
1185 			info->grf = NULL;
1186 		rockchip_get_volt_rm_table(dev, np, "volt-mem-read-margin",
1187 					   &info->volt_rm_tbl);
1188 	}
1189 	if (info->data && info->data->get_soc_info)
1190 		info->data->get_soc_info(dev, np, &bin, &process);
1191 
1192 next:
1193 	rockchip_get_scale_volt_sel(dev, lkg_name, reg_name, bin, process,
1194 				    &scale, &volt_sel);
1195 	rockchip_set_opp_prop_name(dev, process, volt_sel);
1196 	ret = dev_pm_opp_of_add_table(dev);
1197 	if (ret) {
1198 		dev_err(dev, "Invalid operating-points in device tree.\n");
1199 		goto out;
1200 	}
1201 	rockchip_adjust_power_scale(dev, scale);
1202 out:
1203 	of_node_put(np);
1204 
1205 	return ret;
1206 }
1207 EXPORT_SYMBOL(rockchip_init_opp_table);
1208 
1209 MODULE_DESCRIPTION("ROCKCHIP OPP Select");
1210 MODULE_AUTHOR("Finley Xiao <finley.xiao@rock-chips.com>, Liang Chen <cl@rock-chips.com>");
1211 MODULE_LICENSE("GPL");
1212