1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * Copyright (c) 2017 Fuzhou Rockchip Electronics Co., Ltd
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * SPDX-License-Identifier: GPL-2.0+
5*4882a593Smuzhiyun */
6*4882a593Smuzhiyun //#define DEBUG
7*4882a593Smuzhiyun #include <linux/clk.h>
8*4882a593Smuzhiyun #include <linux/cpufreq.h>
9*4882a593Smuzhiyun #include <linux/devfreq.h>
10*4882a593Smuzhiyun #include <linux/mfd/syscon.h>
11*4882a593Smuzhiyun #include <linux/module.h>
12*4882a593Smuzhiyun #include <linux/nvmem-consumer.h>
13*4882a593Smuzhiyun #include <linux/regmap.h>
14*4882a593Smuzhiyun #include <linux/regulator/consumer.h>
15*4882a593Smuzhiyun #include <linux/slab.h>
16*4882a593Smuzhiyun #include <linux/soc/rockchip/pvtm.h>
17*4882a593Smuzhiyun #include <linux/thermal.h>
18*4882a593Smuzhiyun #include <linux/pm_opp.h>
19*4882a593Smuzhiyun #include <linux/version.h>
20*4882a593Smuzhiyun #include <soc/rockchip/rockchip_opp_select.h>
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun #include "../../clk/rockchip/clk.h"
23*4882a593Smuzhiyun #include "../../opp/opp.h"
24*4882a593Smuzhiyun #include "../../devfreq/governor.h"
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun #define MAX_PROP_NAME_LEN 6
27*4882a593Smuzhiyun #define SEL_TABLE_END ~1
28*4882a593Smuzhiyun #define AVS_DELETE_OPP 0
29*4882a593Smuzhiyun #define AVS_SCALING_RATE 1
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun #define LEAKAGE_V1 1
32*4882a593Smuzhiyun #define LEAKAGE_V2 2
33*4882a593Smuzhiyun #define LEAKAGE_V3 3
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun #define to_thermal_opp_info(nb) container_of(nb, struct thermal_opp_info, \
36*4882a593Smuzhiyun thermal_nb)
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun struct sel_table {
39*4882a593Smuzhiyun int min;
40*4882a593Smuzhiyun int max;
41*4882a593Smuzhiyun int sel;
42*4882a593Smuzhiyun };
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun struct bin_sel_table {
45*4882a593Smuzhiyun int bin;
46*4882a593Smuzhiyun int sel;
47*4882a593Smuzhiyun };
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun struct pvtm_config {
50*4882a593Smuzhiyun unsigned int freq;
51*4882a593Smuzhiyun unsigned int volt;
52*4882a593Smuzhiyun unsigned int ch[2];
53*4882a593Smuzhiyun unsigned int sample_time;
54*4882a593Smuzhiyun unsigned int num;
55*4882a593Smuzhiyun unsigned int err;
56*4882a593Smuzhiyun unsigned int ref_temp;
57*4882a593Smuzhiyun unsigned int offset;
58*4882a593Smuzhiyun int temp_prop[2];
59*4882a593Smuzhiyun const char *tz_name;
60*4882a593Smuzhiyun struct thermal_zone_device *tz;
61*4882a593Smuzhiyun struct regmap *grf;
62*4882a593Smuzhiyun };
63*4882a593Smuzhiyun
64*4882a593Smuzhiyun struct lkg_conversion_table {
65*4882a593Smuzhiyun int temp;
66*4882a593Smuzhiyun int conv;
67*4882a593Smuzhiyun };
68*4882a593Smuzhiyun
69*4882a593Smuzhiyun struct otp_opp_info {
70*4882a593Smuzhiyun u16 min_freq;
71*4882a593Smuzhiyun u16 max_freq;
72*4882a593Smuzhiyun u8 volt;
73*4882a593Smuzhiyun u8 length;
74*4882a593Smuzhiyun } __packed;
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun #define PVTM_CH_MAX 8
77*4882a593Smuzhiyun #define PVTM_SUB_CH_MAX 8
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun #define FRAC_BITS 10
80*4882a593Smuzhiyun #define int_to_frac(x) ((x) << FRAC_BITS)
81*4882a593Smuzhiyun #define frac_to_int(x) ((x) >> FRAC_BITS)
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun static int pvtm_value[PVTM_CH_MAX][PVTM_SUB_CH_MAX];
84*4882a593Smuzhiyun static int lkg_version;
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun /*
87*4882a593Smuzhiyun * temp = temp * 10
88*4882a593Smuzhiyun * conv = exp(-ln(1.2) / 5 * (temp - 23)) * 100
89*4882a593Smuzhiyun */
90*4882a593Smuzhiyun static const struct lkg_conversion_table conv_table[] = {
91*4882a593Smuzhiyun { 200, 111 },
92*4882a593Smuzhiyun { 205, 109 },
93*4882a593Smuzhiyun { 210, 107 },
94*4882a593Smuzhiyun { 215, 105 },
95*4882a593Smuzhiyun { 220, 103 },
96*4882a593Smuzhiyun { 225, 101 },
97*4882a593Smuzhiyun { 230, 100 },
98*4882a593Smuzhiyun { 235, 98 },
99*4882a593Smuzhiyun { 240, 96 },
100*4882a593Smuzhiyun { 245, 94 },
101*4882a593Smuzhiyun { 250, 92 },
102*4882a593Smuzhiyun { 255, 91 },
103*4882a593Smuzhiyun { 260, 89 },
104*4882a593Smuzhiyun { 265, 88 },
105*4882a593Smuzhiyun { 270, 86 },
106*4882a593Smuzhiyun { 275, 84 },
107*4882a593Smuzhiyun { 280, 83 },
108*4882a593Smuzhiyun { 285, 81 },
109*4882a593Smuzhiyun { 290, 80 },
110*4882a593Smuzhiyun { 295, 78 },
111*4882a593Smuzhiyun { 300, 77 },
112*4882a593Smuzhiyun { 305, 76 },
113*4882a593Smuzhiyun { 310, 74 },
114*4882a593Smuzhiyun { 315, 73 },
115*4882a593Smuzhiyun { 320, 72 },
116*4882a593Smuzhiyun { 325, 70 },
117*4882a593Smuzhiyun { 330, 69 },
118*4882a593Smuzhiyun { 335, 68 },
119*4882a593Smuzhiyun { 340, 66 },
120*4882a593Smuzhiyun { 345, 65 },
121*4882a593Smuzhiyun { 350, 64 },
122*4882a593Smuzhiyun { 355, 63 },
123*4882a593Smuzhiyun { 360, 62 },
124*4882a593Smuzhiyun { 365, 61 },
125*4882a593Smuzhiyun { 370, 60 },
126*4882a593Smuzhiyun { 375, 58 },
127*4882a593Smuzhiyun { 380, 57 },
128*4882a593Smuzhiyun { 385, 56 },
129*4882a593Smuzhiyun { 390, 55 },
130*4882a593Smuzhiyun { 395, 54 },
131*4882a593Smuzhiyun { 400, 53 },
132*4882a593Smuzhiyun };
133*4882a593Smuzhiyun
rockchip_nvmem_cell_read_common(struct device_node * np,const char * cell_id,void * val,size_t count)134*4882a593Smuzhiyun static int rockchip_nvmem_cell_read_common(struct device_node *np,
135*4882a593Smuzhiyun const char *cell_id,
136*4882a593Smuzhiyun void *val, size_t count)
137*4882a593Smuzhiyun {
138*4882a593Smuzhiyun struct nvmem_cell *cell;
139*4882a593Smuzhiyun void *buf;
140*4882a593Smuzhiyun size_t len;
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun cell = of_nvmem_cell_get(np, cell_id);
143*4882a593Smuzhiyun if (IS_ERR(cell))
144*4882a593Smuzhiyun return PTR_ERR(cell);
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun buf = nvmem_cell_read(cell, &len);
147*4882a593Smuzhiyun if (IS_ERR(buf)) {
148*4882a593Smuzhiyun nvmem_cell_put(cell);
149*4882a593Smuzhiyun return PTR_ERR(buf);
150*4882a593Smuzhiyun }
151*4882a593Smuzhiyun if (len != count) {
152*4882a593Smuzhiyun kfree(buf);
153*4882a593Smuzhiyun nvmem_cell_put(cell);
154*4882a593Smuzhiyun return -EINVAL;
155*4882a593Smuzhiyun }
156*4882a593Smuzhiyun memcpy(val, buf, count);
157*4882a593Smuzhiyun kfree(buf);
158*4882a593Smuzhiyun nvmem_cell_put(cell);
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun return 0;
161*4882a593Smuzhiyun }
162*4882a593Smuzhiyun
rockchip_nvmem_cell_read_u8(struct device_node * np,const char * cell_id,u8 * val)163*4882a593Smuzhiyun int rockchip_nvmem_cell_read_u8(struct device_node *np, const char *cell_id,
164*4882a593Smuzhiyun u8 *val)
165*4882a593Smuzhiyun {
166*4882a593Smuzhiyun return rockchip_nvmem_cell_read_common(np, cell_id, val, sizeof(*val));
167*4882a593Smuzhiyun }
168*4882a593Smuzhiyun EXPORT_SYMBOL(rockchip_nvmem_cell_read_u8);
169*4882a593Smuzhiyun
rockchip_nvmem_cell_read_u16(struct device_node * np,const char * cell_id,u16 * val)170*4882a593Smuzhiyun int rockchip_nvmem_cell_read_u16(struct device_node *np, const char *cell_id,
171*4882a593Smuzhiyun u16 *val)
172*4882a593Smuzhiyun {
173*4882a593Smuzhiyun return rockchip_nvmem_cell_read_common(np, cell_id, val, sizeof(*val));
174*4882a593Smuzhiyun }
175*4882a593Smuzhiyun EXPORT_SYMBOL(rockchip_nvmem_cell_read_u16);
176*4882a593Smuzhiyun
rockchip_get_sel_table(struct device_node * np,char * porp_name,struct sel_table ** table)177*4882a593Smuzhiyun static int rockchip_get_sel_table(struct device_node *np, char *porp_name,
178*4882a593Smuzhiyun struct sel_table **table)
179*4882a593Smuzhiyun {
180*4882a593Smuzhiyun struct sel_table *sel_table;
181*4882a593Smuzhiyun const struct property *prop;
182*4882a593Smuzhiyun int count, i;
183*4882a593Smuzhiyun
184*4882a593Smuzhiyun prop = of_find_property(np, porp_name, NULL);
185*4882a593Smuzhiyun if (!prop)
186*4882a593Smuzhiyun return -EINVAL;
187*4882a593Smuzhiyun
188*4882a593Smuzhiyun if (!prop->value)
189*4882a593Smuzhiyun return -ENODATA;
190*4882a593Smuzhiyun
191*4882a593Smuzhiyun count = of_property_count_u32_elems(np, porp_name);
192*4882a593Smuzhiyun if (count < 0)
193*4882a593Smuzhiyun return -EINVAL;
194*4882a593Smuzhiyun
195*4882a593Smuzhiyun if (count % 3)
196*4882a593Smuzhiyun return -EINVAL;
197*4882a593Smuzhiyun
198*4882a593Smuzhiyun sel_table = kzalloc(sizeof(*sel_table) * (count / 3 + 1), GFP_KERNEL);
199*4882a593Smuzhiyun if (!sel_table)
200*4882a593Smuzhiyun return -ENOMEM;
201*4882a593Smuzhiyun
202*4882a593Smuzhiyun for (i = 0; i < count / 3; i++) {
203*4882a593Smuzhiyun of_property_read_u32_index(np, porp_name, 3 * i,
204*4882a593Smuzhiyun &sel_table[i].min);
205*4882a593Smuzhiyun of_property_read_u32_index(np, porp_name, 3 * i + 1,
206*4882a593Smuzhiyun &sel_table[i].max);
207*4882a593Smuzhiyun of_property_read_u32_index(np, porp_name, 3 * i + 2,
208*4882a593Smuzhiyun &sel_table[i].sel);
209*4882a593Smuzhiyun }
210*4882a593Smuzhiyun sel_table[i].min = 0;
211*4882a593Smuzhiyun sel_table[i].max = 0;
212*4882a593Smuzhiyun sel_table[i].sel = SEL_TABLE_END;
213*4882a593Smuzhiyun
214*4882a593Smuzhiyun *table = sel_table;
215*4882a593Smuzhiyun
216*4882a593Smuzhiyun return 0;
217*4882a593Smuzhiyun }
218*4882a593Smuzhiyun
rockchip_get_bin_sel_table(struct device_node * np,char * porp_name,struct bin_sel_table ** table)219*4882a593Smuzhiyun static int rockchip_get_bin_sel_table(struct device_node *np, char *porp_name,
220*4882a593Smuzhiyun struct bin_sel_table **table)
221*4882a593Smuzhiyun {
222*4882a593Smuzhiyun struct bin_sel_table *sel_table;
223*4882a593Smuzhiyun const struct property *prop;
224*4882a593Smuzhiyun int count, i;
225*4882a593Smuzhiyun
226*4882a593Smuzhiyun prop = of_find_property(np, porp_name, NULL);
227*4882a593Smuzhiyun if (!prop)
228*4882a593Smuzhiyun return -EINVAL;
229*4882a593Smuzhiyun
230*4882a593Smuzhiyun if (!prop->value)
231*4882a593Smuzhiyun return -ENODATA;
232*4882a593Smuzhiyun
233*4882a593Smuzhiyun count = of_property_count_u32_elems(np, porp_name);
234*4882a593Smuzhiyun if (count < 0)
235*4882a593Smuzhiyun return -EINVAL;
236*4882a593Smuzhiyun
237*4882a593Smuzhiyun if (count % 2)
238*4882a593Smuzhiyun return -EINVAL;
239*4882a593Smuzhiyun
240*4882a593Smuzhiyun sel_table = kzalloc(sizeof(*sel_table) * (count / 2 + 1), GFP_KERNEL);
241*4882a593Smuzhiyun if (!sel_table)
242*4882a593Smuzhiyun return -ENOMEM;
243*4882a593Smuzhiyun
244*4882a593Smuzhiyun for (i = 0; i < count / 2; i++) {
245*4882a593Smuzhiyun of_property_read_u32_index(np, porp_name, 2 * i,
246*4882a593Smuzhiyun &sel_table[i].bin);
247*4882a593Smuzhiyun of_property_read_u32_index(np, porp_name, 2 * i + 1,
248*4882a593Smuzhiyun &sel_table[i].sel);
249*4882a593Smuzhiyun }
250*4882a593Smuzhiyun
251*4882a593Smuzhiyun sel_table[i].bin = 0;
252*4882a593Smuzhiyun sel_table[i].sel = SEL_TABLE_END;
253*4882a593Smuzhiyun
254*4882a593Smuzhiyun *table = sel_table;
255*4882a593Smuzhiyun
256*4882a593Smuzhiyun return 0;
257*4882a593Smuzhiyun }
258*4882a593Smuzhiyun
rockchip_get_sel(struct device_node * np,char * name,int value,int * sel)259*4882a593Smuzhiyun static int rockchip_get_sel(struct device_node *np, char *name,
260*4882a593Smuzhiyun int value, int *sel)
261*4882a593Smuzhiyun {
262*4882a593Smuzhiyun struct sel_table *table = NULL;
263*4882a593Smuzhiyun int i, ret = -EINVAL;
264*4882a593Smuzhiyun
265*4882a593Smuzhiyun if (!sel)
266*4882a593Smuzhiyun return -EINVAL;
267*4882a593Smuzhiyun
268*4882a593Smuzhiyun if (rockchip_get_sel_table(np, name, &table))
269*4882a593Smuzhiyun return -EINVAL;
270*4882a593Smuzhiyun
271*4882a593Smuzhiyun for (i = 0; table[i].sel != SEL_TABLE_END; i++) {
272*4882a593Smuzhiyun if (value >= table[i].min) {
273*4882a593Smuzhiyun *sel = table[i].sel;
274*4882a593Smuzhiyun ret = 0;
275*4882a593Smuzhiyun }
276*4882a593Smuzhiyun }
277*4882a593Smuzhiyun kfree(table);
278*4882a593Smuzhiyun
279*4882a593Smuzhiyun return ret;
280*4882a593Smuzhiyun }
281*4882a593Smuzhiyun
rockchip_get_bin_sel(struct device_node * np,char * name,int value,int * sel)282*4882a593Smuzhiyun static int rockchip_get_bin_sel(struct device_node *np, char *name,
283*4882a593Smuzhiyun int value, int *sel)
284*4882a593Smuzhiyun {
285*4882a593Smuzhiyun struct bin_sel_table *table = NULL;
286*4882a593Smuzhiyun int i, ret = -EINVAL;
287*4882a593Smuzhiyun
288*4882a593Smuzhiyun if (!sel)
289*4882a593Smuzhiyun return -EINVAL;
290*4882a593Smuzhiyun
291*4882a593Smuzhiyun if (rockchip_get_bin_sel_table(np, name, &table))
292*4882a593Smuzhiyun return -EINVAL;
293*4882a593Smuzhiyun
294*4882a593Smuzhiyun for (i = 0; table[i].sel != SEL_TABLE_END; i++) {
295*4882a593Smuzhiyun if (value == table[i].bin) {
296*4882a593Smuzhiyun *sel = table[i].sel;
297*4882a593Smuzhiyun ret = 0;
298*4882a593Smuzhiyun break;
299*4882a593Smuzhiyun }
300*4882a593Smuzhiyun }
301*4882a593Smuzhiyun kfree(table);
302*4882a593Smuzhiyun
303*4882a593Smuzhiyun return ret;
304*4882a593Smuzhiyun }
305*4882a593Smuzhiyun
rockchip_parse_pvtm_config(struct device_node * np,struct pvtm_config * pvtm)306*4882a593Smuzhiyun static int rockchip_parse_pvtm_config(struct device_node *np,
307*4882a593Smuzhiyun struct pvtm_config *pvtm)
308*4882a593Smuzhiyun {
309*4882a593Smuzhiyun if (of_property_read_u32(np, "rockchip,pvtm-freq", &pvtm->freq))
310*4882a593Smuzhiyun return -EINVAL;
311*4882a593Smuzhiyun if (of_property_read_u32(np, "rockchip,pvtm-volt", &pvtm->volt))
312*4882a593Smuzhiyun return -EINVAL;
313*4882a593Smuzhiyun if (of_property_read_u32(np, "rockchip,pvtm-sample-time",
314*4882a593Smuzhiyun &pvtm->sample_time))
315*4882a593Smuzhiyun return -EINVAL;
316*4882a593Smuzhiyun if (of_property_read_u32(np, "rockchip,pvtm-ref-temp", &pvtm->ref_temp))
317*4882a593Smuzhiyun return -EINVAL;
318*4882a593Smuzhiyun if (of_property_read_u32_array(np, "rockchip,pvtm-temp-prop",
319*4882a593Smuzhiyun pvtm->temp_prop, 2))
320*4882a593Smuzhiyun return -EINVAL;
321*4882a593Smuzhiyun if (of_property_read_string(np, "rockchip,pvtm-thermal-zone",
322*4882a593Smuzhiyun &pvtm->tz_name)) {
323*4882a593Smuzhiyun if (of_property_read_string(np, "rockchip,thermal-zone",
324*4882a593Smuzhiyun &pvtm->tz_name))
325*4882a593Smuzhiyun return -EINVAL;
326*4882a593Smuzhiyun }
327*4882a593Smuzhiyun pvtm->tz = thermal_zone_get_zone_by_name(pvtm->tz_name);
328*4882a593Smuzhiyun if (IS_ERR(pvtm->tz))
329*4882a593Smuzhiyun return -EINVAL;
330*4882a593Smuzhiyun if (!pvtm->tz->ops->get_temp)
331*4882a593Smuzhiyun return -EINVAL;
332*4882a593Smuzhiyun if (of_property_read_bool(np, "rockchip,pvtm-pvtpll")) {
333*4882a593Smuzhiyun if (of_property_read_u32(np, "rockchip,pvtm-offset",
334*4882a593Smuzhiyun &pvtm->offset))
335*4882a593Smuzhiyun return -EINVAL;
336*4882a593Smuzhiyun pvtm->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
337*4882a593Smuzhiyun if (IS_ERR(pvtm->grf))
338*4882a593Smuzhiyun return -EINVAL;
339*4882a593Smuzhiyun return 0;
340*4882a593Smuzhiyun }
341*4882a593Smuzhiyun if (of_property_read_u32_array(np, "rockchip,pvtm-ch", pvtm->ch, 2))
342*4882a593Smuzhiyun return -EINVAL;
343*4882a593Smuzhiyun if (pvtm->ch[0] >= PVTM_CH_MAX || pvtm->ch[1] >= PVTM_SUB_CH_MAX)
344*4882a593Smuzhiyun return -EINVAL;
345*4882a593Smuzhiyun if (of_property_read_u32(np, "rockchip,pvtm-number", &pvtm->num))
346*4882a593Smuzhiyun return -EINVAL;
347*4882a593Smuzhiyun if (of_property_read_u32(np, "rockchip,pvtm-error", &pvtm->err))
348*4882a593Smuzhiyun return -EINVAL;
349*4882a593Smuzhiyun
350*4882a593Smuzhiyun return 0;
351*4882a593Smuzhiyun }
352*4882a593Smuzhiyun
rockchip_get_pvtm_specific_value(struct device * dev,struct device_node * np,struct clk * clk,struct regulator * reg,int * target_value)353*4882a593Smuzhiyun static int rockchip_get_pvtm_specific_value(struct device *dev,
354*4882a593Smuzhiyun struct device_node *np,
355*4882a593Smuzhiyun struct clk *clk,
356*4882a593Smuzhiyun struct regulator *reg,
357*4882a593Smuzhiyun int *target_value)
358*4882a593Smuzhiyun {
359*4882a593Smuzhiyun struct pvtm_config *pvtm;
360*4882a593Smuzhiyun unsigned long old_freq;
361*4882a593Smuzhiyun unsigned int old_volt;
362*4882a593Smuzhiyun int cur_temp, diff_temp;
363*4882a593Smuzhiyun int cur_value, total_value, avg_value, diff_value;
364*4882a593Smuzhiyun int min_value, max_value;
365*4882a593Smuzhiyun int ret = 0, i = 0, retry = 2;
366*4882a593Smuzhiyun
367*4882a593Smuzhiyun pvtm = kzalloc(sizeof(*pvtm), GFP_KERNEL);
368*4882a593Smuzhiyun if (!pvtm)
369*4882a593Smuzhiyun return -ENOMEM;
370*4882a593Smuzhiyun
371*4882a593Smuzhiyun ret = rockchip_parse_pvtm_config(np, pvtm);
372*4882a593Smuzhiyun if (ret)
373*4882a593Smuzhiyun goto pvtm_value_out;
374*4882a593Smuzhiyun
375*4882a593Smuzhiyun old_freq = clk_get_rate(clk);
376*4882a593Smuzhiyun old_volt = regulator_get_voltage(reg);
377*4882a593Smuzhiyun
378*4882a593Smuzhiyun /*
379*4882a593Smuzhiyun * Set pvtm_freq to the lowest frequency in dts,
380*4882a593Smuzhiyun * so change frequency first.
381*4882a593Smuzhiyun */
382*4882a593Smuzhiyun ret = clk_set_rate(clk, pvtm->freq * 1000);
383*4882a593Smuzhiyun if (ret) {
384*4882a593Smuzhiyun dev_err(dev, "Failed to set pvtm freq\n");
385*4882a593Smuzhiyun goto pvtm_value_out;
386*4882a593Smuzhiyun }
387*4882a593Smuzhiyun
388*4882a593Smuzhiyun ret = regulator_set_voltage(reg, pvtm->volt, pvtm->volt);
389*4882a593Smuzhiyun if (ret) {
390*4882a593Smuzhiyun dev_err(dev, "Failed to set pvtm_volt\n");
391*4882a593Smuzhiyun goto restore_clk;
392*4882a593Smuzhiyun }
393*4882a593Smuzhiyun
394*4882a593Smuzhiyun /* The first few values may be fluctuant, if error is too big, retry*/
395*4882a593Smuzhiyun while (retry--) {
396*4882a593Smuzhiyun total_value = 0;
397*4882a593Smuzhiyun min_value = INT_MAX;
398*4882a593Smuzhiyun max_value = 0;
399*4882a593Smuzhiyun
400*4882a593Smuzhiyun for (i = 0; i < pvtm->num; i++) {
401*4882a593Smuzhiyun cur_value = rockchip_get_pvtm_value(pvtm->ch[0],
402*4882a593Smuzhiyun pvtm->ch[1],
403*4882a593Smuzhiyun pvtm->sample_time);
404*4882a593Smuzhiyun if (cur_value <= 0) {
405*4882a593Smuzhiyun ret = -EINVAL;
406*4882a593Smuzhiyun goto resetore_volt;
407*4882a593Smuzhiyun }
408*4882a593Smuzhiyun if (cur_value < min_value)
409*4882a593Smuzhiyun min_value = cur_value;
410*4882a593Smuzhiyun if (cur_value > max_value)
411*4882a593Smuzhiyun max_value = cur_value;
412*4882a593Smuzhiyun total_value += cur_value;
413*4882a593Smuzhiyun }
414*4882a593Smuzhiyun if (max_value - min_value < pvtm->err)
415*4882a593Smuzhiyun break;
416*4882a593Smuzhiyun }
417*4882a593Smuzhiyun if (!total_value || !pvtm->num) {
418*4882a593Smuzhiyun ret = -EINVAL;
419*4882a593Smuzhiyun goto resetore_volt;
420*4882a593Smuzhiyun }
421*4882a593Smuzhiyun avg_value = total_value / pvtm->num;
422*4882a593Smuzhiyun
423*4882a593Smuzhiyun /*
424*4882a593Smuzhiyun * As pvtm is influenced by temperature, compute difference between
425*4882a593Smuzhiyun * current temperature and reference temperature
426*4882a593Smuzhiyun */
427*4882a593Smuzhiyun pvtm->tz->ops->get_temp(pvtm->tz, &cur_temp);
428*4882a593Smuzhiyun diff_temp = (cur_temp / 1000 - pvtm->ref_temp);
429*4882a593Smuzhiyun diff_value = diff_temp *
430*4882a593Smuzhiyun (diff_temp < 0 ? pvtm->temp_prop[0] : pvtm->temp_prop[1]);
431*4882a593Smuzhiyun *target_value = avg_value + diff_value;
432*4882a593Smuzhiyun
433*4882a593Smuzhiyun pvtm_value[pvtm->ch[0]][pvtm->ch[1]] = *target_value;
434*4882a593Smuzhiyun
435*4882a593Smuzhiyun dev_info(dev, "temp=%d, pvtm=%d (%d + %d)\n",
436*4882a593Smuzhiyun cur_temp, *target_value, avg_value, diff_value);
437*4882a593Smuzhiyun
438*4882a593Smuzhiyun resetore_volt:
439*4882a593Smuzhiyun regulator_set_voltage(reg, old_volt, INT_MAX);
440*4882a593Smuzhiyun restore_clk:
441*4882a593Smuzhiyun clk_set_rate(clk, old_freq);
442*4882a593Smuzhiyun pvtm_value_out:
443*4882a593Smuzhiyun kfree(pvtm);
444*4882a593Smuzhiyun
445*4882a593Smuzhiyun return ret;
446*4882a593Smuzhiyun }
447*4882a593Smuzhiyun
448*4882a593Smuzhiyun /**
449*4882a593Smuzhiyun * mul_frac() - multiply two fixed-point numbers
450*4882a593Smuzhiyun * @x: first multiplicand
451*4882a593Smuzhiyun * @y: second multiplicand
452*4882a593Smuzhiyun *
453*4882a593Smuzhiyun * Return: the result of multiplying two fixed-point numbers. The
454*4882a593Smuzhiyun * result is also a fixed-point number.
455*4882a593Smuzhiyun */
mul_frac(s64 x,s64 y)456*4882a593Smuzhiyun static inline s64 mul_frac(s64 x, s64 y)
457*4882a593Smuzhiyun {
458*4882a593Smuzhiyun return (x * y) >> FRAC_BITS;
459*4882a593Smuzhiyun }
460*4882a593Smuzhiyun
temp_to_conversion_rate(int temp)461*4882a593Smuzhiyun static int temp_to_conversion_rate(int temp)
462*4882a593Smuzhiyun {
463*4882a593Smuzhiyun int high, low, mid;
464*4882a593Smuzhiyun
465*4882a593Smuzhiyun low = 0;
466*4882a593Smuzhiyun high = ARRAY_SIZE(conv_table) - 1;
467*4882a593Smuzhiyun mid = (high + low) / 2;
468*4882a593Smuzhiyun
469*4882a593Smuzhiyun /* No temp available, return max conversion_rate */
470*4882a593Smuzhiyun if (temp <= conv_table[low].temp)
471*4882a593Smuzhiyun return conv_table[low].conv;
472*4882a593Smuzhiyun if (temp >= conv_table[high].temp)
473*4882a593Smuzhiyun return conv_table[high].conv;
474*4882a593Smuzhiyun
475*4882a593Smuzhiyun while (low <= high) {
476*4882a593Smuzhiyun if (temp <= conv_table[mid].temp && temp >
477*4882a593Smuzhiyun conv_table[mid - 1].temp) {
478*4882a593Smuzhiyun return conv_table[mid - 1].conv +
479*4882a593Smuzhiyun (conv_table[mid].conv - conv_table[mid - 1].conv) *
480*4882a593Smuzhiyun (temp - conv_table[mid - 1].temp) /
481*4882a593Smuzhiyun (conv_table[mid].temp - conv_table[mid - 1].temp);
482*4882a593Smuzhiyun } else if (temp > conv_table[mid].temp) {
483*4882a593Smuzhiyun low = mid + 1;
484*4882a593Smuzhiyun } else {
485*4882a593Smuzhiyun high = mid - 1;
486*4882a593Smuzhiyun }
487*4882a593Smuzhiyun mid = (low + high) / 2;
488*4882a593Smuzhiyun }
489*4882a593Smuzhiyun
490*4882a593Smuzhiyun return 100;
491*4882a593Smuzhiyun }
492*4882a593Smuzhiyun
rockchip_adjust_leakage(struct device * dev,struct device_node * np,int * leakage)493*4882a593Smuzhiyun static int rockchip_adjust_leakage(struct device *dev, struct device_node *np,
494*4882a593Smuzhiyun int *leakage)
495*4882a593Smuzhiyun {
496*4882a593Smuzhiyun struct nvmem_cell *cell;
497*4882a593Smuzhiyun u8 value = 0;
498*4882a593Smuzhiyun u32 temp;
499*4882a593Smuzhiyun int conversion;
500*4882a593Smuzhiyun int ret;
501*4882a593Smuzhiyun
502*4882a593Smuzhiyun cell = of_nvmem_cell_get(np, "leakage_temp");
503*4882a593Smuzhiyun if (IS_ERR(cell))
504*4882a593Smuzhiyun goto next;
505*4882a593Smuzhiyun nvmem_cell_put(cell);
506*4882a593Smuzhiyun ret = rockchip_nvmem_cell_read_u8(np, "leakage_temp", &value);
507*4882a593Smuzhiyun if (ret) {
508*4882a593Smuzhiyun dev_err(dev, "Failed to get leakage temp\n");
509*4882a593Smuzhiyun return -EINVAL;
510*4882a593Smuzhiyun }
511*4882a593Smuzhiyun /*
512*4882a593Smuzhiyun * The ambient temperature range: 20C to 40C
513*4882a593Smuzhiyun * In order to improve the precision, we do a conversion.
514*4882a593Smuzhiyun * The temp in efuse : temp_efuse = (temp - 20) / (40 - 20) * 63
515*4882a593Smuzhiyun * The ambient temp : temp = (temp_efuse / 63) * (40 - 20) + 20
516*4882a593Smuzhiyun * Reserves a decimal point : temp = temp * 10
517*4882a593Smuzhiyun */
518*4882a593Smuzhiyun temp = value;
519*4882a593Smuzhiyun temp = mul_frac((int_to_frac(temp) / 63 * 20 + int_to_frac(20)),
520*4882a593Smuzhiyun int_to_frac(10));
521*4882a593Smuzhiyun conversion = temp_to_conversion_rate(frac_to_int(temp));
522*4882a593Smuzhiyun *leakage = *leakage * conversion / 100;
523*4882a593Smuzhiyun
524*4882a593Smuzhiyun next:
525*4882a593Smuzhiyun cell = of_nvmem_cell_get(np, "leakage_volt");
526*4882a593Smuzhiyun if (IS_ERR(cell))
527*4882a593Smuzhiyun return 0;
528*4882a593Smuzhiyun nvmem_cell_put(cell);
529*4882a593Smuzhiyun ret = rockchip_nvmem_cell_read_u8(np, "leakage_volt", &value);
530*4882a593Smuzhiyun if (ret) {
531*4882a593Smuzhiyun dev_err(dev, "Failed to get leakage volt\n");
532*4882a593Smuzhiyun return -EINVAL;
533*4882a593Smuzhiyun }
534*4882a593Smuzhiyun /*
535*4882a593Smuzhiyun * if ft write leakage use 1.35v, need convert to 1v.
536*4882a593Smuzhiyun * leakage(1v) = leakage(1.35v) / 4
537*4882a593Smuzhiyun */
538*4882a593Smuzhiyun if (value)
539*4882a593Smuzhiyun *leakage = *leakage / 4;
540*4882a593Smuzhiyun
541*4882a593Smuzhiyun return 0;
542*4882a593Smuzhiyun }
543*4882a593Smuzhiyun
rockchip_get_leakage_version(int * version)544*4882a593Smuzhiyun static int rockchip_get_leakage_version(int *version)
545*4882a593Smuzhiyun {
546*4882a593Smuzhiyun if (*version)
547*4882a593Smuzhiyun return 0;
548*4882a593Smuzhiyun
549*4882a593Smuzhiyun if (of_machine_is_compatible("rockchip,rk3368"))
550*4882a593Smuzhiyun *version = LEAKAGE_V2;
551*4882a593Smuzhiyun else if (of_machine_is_compatible("rockchip,rv1126") ||
552*4882a593Smuzhiyun of_machine_is_compatible("rockchip,rv1109"))
553*4882a593Smuzhiyun *version = LEAKAGE_V3;
554*4882a593Smuzhiyun else
555*4882a593Smuzhiyun *version = LEAKAGE_V1;
556*4882a593Smuzhiyun
557*4882a593Smuzhiyun return 0;
558*4882a593Smuzhiyun }
559*4882a593Smuzhiyun
rockchip_get_leakage_v1(struct device * dev,struct device_node * np,char * lkg_name,int * leakage)560*4882a593Smuzhiyun static int rockchip_get_leakage_v1(struct device *dev, struct device_node *np,
561*4882a593Smuzhiyun char *lkg_name, int *leakage)
562*4882a593Smuzhiyun {
563*4882a593Smuzhiyun struct nvmem_cell *cell;
564*4882a593Smuzhiyun int ret = 0;
565*4882a593Smuzhiyun u8 value = 0;
566*4882a593Smuzhiyun
567*4882a593Smuzhiyun cell = of_nvmem_cell_get(np, "leakage");
568*4882a593Smuzhiyun if (IS_ERR(cell)) {
569*4882a593Smuzhiyun ret = rockchip_nvmem_cell_read_u8(np, lkg_name, &value);
570*4882a593Smuzhiyun } else {
571*4882a593Smuzhiyun nvmem_cell_put(cell);
572*4882a593Smuzhiyun ret = rockchip_nvmem_cell_read_u8(np, "leakage", &value);
573*4882a593Smuzhiyun }
574*4882a593Smuzhiyun if (ret)
575*4882a593Smuzhiyun dev_err(dev, "Failed to get %s\n", lkg_name);
576*4882a593Smuzhiyun else
577*4882a593Smuzhiyun *leakage = value;
578*4882a593Smuzhiyun
579*4882a593Smuzhiyun return ret;
580*4882a593Smuzhiyun }
581*4882a593Smuzhiyun
rockchip_get_leakage_v2(struct device * dev,struct device_node * np,char * lkg_name,int * leakage)582*4882a593Smuzhiyun static int rockchip_get_leakage_v2(struct device *dev, struct device_node *np,
583*4882a593Smuzhiyun char *lkg_name, int *leakage)
584*4882a593Smuzhiyun {
585*4882a593Smuzhiyun int lkg = 0, ret = 0;
586*4882a593Smuzhiyun
587*4882a593Smuzhiyun if (rockchip_get_leakage_v1(dev, np, lkg_name, &lkg))
588*4882a593Smuzhiyun return -EINVAL;
589*4882a593Smuzhiyun
590*4882a593Smuzhiyun ret = rockchip_adjust_leakage(dev, np, &lkg);
591*4882a593Smuzhiyun if (ret)
592*4882a593Smuzhiyun dev_err(dev, "Failed to adjust leakage, value=%d\n", lkg);
593*4882a593Smuzhiyun else
594*4882a593Smuzhiyun *leakage = lkg;
595*4882a593Smuzhiyun
596*4882a593Smuzhiyun return ret;
597*4882a593Smuzhiyun }
598*4882a593Smuzhiyun
rockchip_get_leakage_v3(struct device * dev,struct device_node * np,char * lkg_name,int * leakage)599*4882a593Smuzhiyun static int rockchip_get_leakage_v3(struct device *dev, struct device_node *np,
600*4882a593Smuzhiyun char *lkg_name, int *leakage)
601*4882a593Smuzhiyun {
602*4882a593Smuzhiyun int lkg = 0;
603*4882a593Smuzhiyun
604*4882a593Smuzhiyun if (rockchip_get_leakage_v1(dev, np, lkg_name, &lkg))
605*4882a593Smuzhiyun return -EINVAL;
606*4882a593Smuzhiyun
607*4882a593Smuzhiyun *leakage = (((lkg & 0xf8) >> 3) * 1000) + ((lkg & 0x7) * 125);
608*4882a593Smuzhiyun
609*4882a593Smuzhiyun return 0;
610*4882a593Smuzhiyun }
611*4882a593Smuzhiyun
rockchip_of_get_leakage(struct device * dev,char * lkg_name,int * leakage)612*4882a593Smuzhiyun int rockchip_of_get_leakage(struct device *dev, char *lkg_name, int *leakage)
613*4882a593Smuzhiyun {
614*4882a593Smuzhiyun struct device_node *np;
615*4882a593Smuzhiyun int ret = -EINVAL;
616*4882a593Smuzhiyun
617*4882a593Smuzhiyun np = of_parse_phandle(dev->of_node, "operating-points-v2", 0);
618*4882a593Smuzhiyun if (!np) {
619*4882a593Smuzhiyun dev_warn(dev, "OPP-v2 not supported\n");
620*4882a593Smuzhiyun return -ENOENT;
621*4882a593Smuzhiyun }
622*4882a593Smuzhiyun
623*4882a593Smuzhiyun rockchip_get_leakage_version(&lkg_version);
624*4882a593Smuzhiyun
625*4882a593Smuzhiyun switch (lkg_version) {
626*4882a593Smuzhiyun case LEAKAGE_V1:
627*4882a593Smuzhiyun ret = rockchip_get_leakage_v1(dev, np, lkg_name, leakage);
628*4882a593Smuzhiyun break;
629*4882a593Smuzhiyun case LEAKAGE_V2:
630*4882a593Smuzhiyun ret = rockchip_get_leakage_v2(dev, np, lkg_name, leakage);
631*4882a593Smuzhiyun break;
632*4882a593Smuzhiyun case LEAKAGE_V3:
633*4882a593Smuzhiyun ret = rockchip_get_leakage_v3(dev, np, lkg_name, leakage);
634*4882a593Smuzhiyun if (!ret) {
635*4882a593Smuzhiyun /*
636*4882a593Smuzhiyun * round up to the nearest whole number for calculating
637*4882a593Smuzhiyun * static power, it does not need to be precise.
638*4882a593Smuzhiyun */
639*4882a593Smuzhiyun if (*leakage % 1000 > 500)
640*4882a593Smuzhiyun *leakage = *leakage / 1000 + 1;
641*4882a593Smuzhiyun else
642*4882a593Smuzhiyun *leakage = *leakage / 1000;
643*4882a593Smuzhiyun }
644*4882a593Smuzhiyun break;
645*4882a593Smuzhiyun default:
646*4882a593Smuzhiyun break;
647*4882a593Smuzhiyun }
648*4882a593Smuzhiyun
649*4882a593Smuzhiyun of_node_put(np);
650*4882a593Smuzhiyun
651*4882a593Smuzhiyun return ret;
652*4882a593Smuzhiyun }
653*4882a593Smuzhiyun EXPORT_SYMBOL(rockchip_of_get_leakage);
654*4882a593Smuzhiyun
rockchip_of_get_lkg_sel(struct device * dev,struct device_node * np,char * lkg_name,int process,int * volt_sel,int * scale_sel)655*4882a593Smuzhiyun void rockchip_of_get_lkg_sel(struct device *dev, struct device_node *np,
656*4882a593Smuzhiyun char *lkg_name, int process,
657*4882a593Smuzhiyun int *volt_sel, int *scale_sel)
658*4882a593Smuzhiyun {
659*4882a593Smuzhiyun struct property *prop = NULL;
660*4882a593Smuzhiyun int leakage = -EINVAL, ret = 0;
661*4882a593Smuzhiyun char name[NAME_MAX];
662*4882a593Smuzhiyun
663*4882a593Smuzhiyun rockchip_get_leakage_version(&lkg_version);
664*4882a593Smuzhiyun
665*4882a593Smuzhiyun switch (lkg_version) {
666*4882a593Smuzhiyun case LEAKAGE_V1:
667*4882a593Smuzhiyun ret = rockchip_get_leakage_v1(dev, np, lkg_name, &leakage);
668*4882a593Smuzhiyun if (ret)
669*4882a593Smuzhiyun return;
670*4882a593Smuzhiyun dev_info(dev, "leakage=%d\n", leakage);
671*4882a593Smuzhiyun break;
672*4882a593Smuzhiyun case LEAKAGE_V2:
673*4882a593Smuzhiyun ret = rockchip_get_leakage_v2(dev, np, lkg_name, &leakage);
674*4882a593Smuzhiyun if (ret)
675*4882a593Smuzhiyun return;
676*4882a593Smuzhiyun dev_info(dev, "leakage=%d\n", leakage);
677*4882a593Smuzhiyun break;
678*4882a593Smuzhiyun case LEAKAGE_V3:
679*4882a593Smuzhiyun ret = rockchip_get_leakage_v3(dev, np, lkg_name, &leakage);
680*4882a593Smuzhiyun if (ret)
681*4882a593Smuzhiyun return;
682*4882a593Smuzhiyun dev_info(dev, "leakage=%d.%d\n", leakage / 1000,
683*4882a593Smuzhiyun leakage % 1000);
684*4882a593Smuzhiyun break;
685*4882a593Smuzhiyun default:
686*4882a593Smuzhiyun return;
687*4882a593Smuzhiyun }
688*4882a593Smuzhiyun
689*4882a593Smuzhiyun if (!volt_sel)
690*4882a593Smuzhiyun goto next;
691*4882a593Smuzhiyun if (process >= 0) {
692*4882a593Smuzhiyun snprintf(name, sizeof(name),
693*4882a593Smuzhiyun "rockchip,p%d-leakage-voltage-sel", process);
694*4882a593Smuzhiyun prop = of_find_property(np, name, NULL);
695*4882a593Smuzhiyun }
696*4882a593Smuzhiyun if (!prop)
697*4882a593Smuzhiyun sprintf(name, "rockchip,leakage-voltage-sel");
698*4882a593Smuzhiyun ret = rockchip_get_sel(np, name, leakage, volt_sel);
699*4882a593Smuzhiyun if (!ret)
700*4882a593Smuzhiyun dev_info(dev, "leakage-volt-sel=%d\n", *volt_sel);
701*4882a593Smuzhiyun
702*4882a593Smuzhiyun next:
703*4882a593Smuzhiyun if (!scale_sel)
704*4882a593Smuzhiyun return;
705*4882a593Smuzhiyun if (process >= 0) {
706*4882a593Smuzhiyun snprintf(name, sizeof(name),
707*4882a593Smuzhiyun "rockchip,p%d-leakage-scaling-sel", process);
708*4882a593Smuzhiyun prop = of_find_property(np, name, NULL);
709*4882a593Smuzhiyun }
710*4882a593Smuzhiyun if (!prop)
711*4882a593Smuzhiyun sprintf(name, "rockchip,leakage-scaling-sel");
712*4882a593Smuzhiyun ret = rockchip_get_sel(np, name, leakage, scale_sel);
713*4882a593Smuzhiyun if (!ret)
714*4882a593Smuzhiyun dev_info(dev, "leakage-scale=%d\n", *scale_sel);
715*4882a593Smuzhiyun }
716*4882a593Smuzhiyun EXPORT_SYMBOL(rockchip_of_get_lkg_sel);
717*4882a593Smuzhiyun
rockchip_pvtpll_get_rate(struct rockchip_opp_info * info)718*4882a593Smuzhiyun static unsigned long rockchip_pvtpll_get_rate(struct rockchip_opp_info *info)
719*4882a593Smuzhiyun {
720*4882a593Smuzhiyun unsigned int rate0, rate1, delta;
721*4882a593Smuzhiyun int i;
722*4882a593Smuzhiyun
723*4882a593Smuzhiyun #define MIN_STABLE_DELTA 3
724*4882a593Smuzhiyun regmap_read(info->grf, info->pvtpll_avg_offset, &rate0);
725*4882a593Smuzhiyun /* max delay 2ms */
726*4882a593Smuzhiyun for (i = 0; i < 20; i++) {
727*4882a593Smuzhiyun udelay(100);
728*4882a593Smuzhiyun regmap_read(info->grf, info->pvtpll_avg_offset, &rate1);
729*4882a593Smuzhiyun delta = abs(rate1 - rate0);
730*4882a593Smuzhiyun rate0 = rate1;
731*4882a593Smuzhiyun if (delta <= MIN_STABLE_DELTA)
732*4882a593Smuzhiyun break;
733*4882a593Smuzhiyun }
734*4882a593Smuzhiyun
735*4882a593Smuzhiyun if (delta > MIN_STABLE_DELTA) {
736*4882a593Smuzhiyun dev_err(info->dev, "%s: bad delta: %u\n", __func__, delta);
737*4882a593Smuzhiyun return 0;
738*4882a593Smuzhiyun }
739*4882a593Smuzhiyun
740*4882a593Smuzhiyun return rate0 * 1000000;
741*4882a593Smuzhiyun }
742*4882a593Smuzhiyun
rockchip_pvtpll_parse_dt(struct rockchip_opp_info * info)743*4882a593Smuzhiyun static int rockchip_pvtpll_parse_dt(struct rockchip_opp_info *info)
744*4882a593Smuzhiyun {
745*4882a593Smuzhiyun struct device_node *np;
746*4882a593Smuzhiyun int ret;
747*4882a593Smuzhiyun
748*4882a593Smuzhiyun np = of_parse_phandle(info->dev->of_node, "operating-points-v2", 0);
749*4882a593Smuzhiyun if (!np) {
750*4882a593Smuzhiyun dev_warn(info->dev, "OPP-v2 not supported\n");
751*4882a593Smuzhiyun return -ENOENT;
752*4882a593Smuzhiyun }
753*4882a593Smuzhiyun
754*4882a593Smuzhiyun ret = of_property_read_u32(np, "rockchip,pvtpll-avg-offset", &info->pvtpll_avg_offset);
755*4882a593Smuzhiyun if (ret)
756*4882a593Smuzhiyun goto out;
757*4882a593Smuzhiyun
758*4882a593Smuzhiyun ret = of_property_read_u32(np, "rockchip,pvtpll-min-rate", &info->pvtpll_min_rate);
759*4882a593Smuzhiyun if (ret)
760*4882a593Smuzhiyun goto out;
761*4882a593Smuzhiyun
762*4882a593Smuzhiyun ret = of_property_read_u32(np, "rockchip,pvtpll-volt-step", &info->pvtpll_volt_step);
763*4882a593Smuzhiyun out:
764*4882a593Smuzhiyun of_node_put(np);
765*4882a593Smuzhiyun
766*4882a593Smuzhiyun return ret;
767*4882a593Smuzhiyun }
768*4882a593Smuzhiyun
rockchip_init_pvtpll_info(struct rockchip_opp_info * info)769*4882a593Smuzhiyun static int rockchip_init_pvtpll_info(struct rockchip_opp_info *info)
770*4882a593Smuzhiyun {
771*4882a593Smuzhiyun struct opp_table *opp_table;
772*4882a593Smuzhiyun struct dev_pm_opp *opp;
773*4882a593Smuzhiyun int i = 0, max_count, ret;
774*4882a593Smuzhiyun
775*4882a593Smuzhiyun ret = rockchip_pvtpll_parse_dt(info);
776*4882a593Smuzhiyun if (ret)
777*4882a593Smuzhiyun return ret;
778*4882a593Smuzhiyun
779*4882a593Smuzhiyun max_count = dev_pm_opp_get_opp_count(info->dev);
780*4882a593Smuzhiyun if (max_count <= 0)
781*4882a593Smuzhiyun return max_count ? max_count : -ENODATA;
782*4882a593Smuzhiyun
783*4882a593Smuzhiyun info->opp_table = kcalloc(max_count, sizeof(*info->opp_table), GFP_KERNEL);
784*4882a593Smuzhiyun if (!info->opp_table)
785*4882a593Smuzhiyun return -ENOMEM;
786*4882a593Smuzhiyun
787*4882a593Smuzhiyun opp_table = dev_pm_opp_get_opp_table(info->dev);
788*4882a593Smuzhiyun if (!opp_table) {
789*4882a593Smuzhiyun kfree(info->opp_table);
790*4882a593Smuzhiyun info->opp_table = NULL;
791*4882a593Smuzhiyun return -ENOMEM;
792*4882a593Smuzhiyun }
793*4882a593Smuzhiyun
794*4882a593Smuzhiyun mutex_lock(&opp_table->lock);
795*4882a593Smuzhiyun list_for_each_entry(opp, &opp_table->opp_list, node) {
796*4882a593Smuzhiyun if (!opp->available)
797*4882a593Smuzhiyun continue;
798*4882a593Smuzhiyun
799*4882a593Smuzhiyun info->opp_table[i].u_volt = opp->supplies[0].u_volt;
800*4882a593Smuzhiyun info->opp_table[i].u_volt_min = opp->supplies[0].u_volt_min;
801*4882a593Smuzhiyun info->opp_table[i].u_volt_max = opp->supplies[0].u_volt_max;
802*4882a593Smuzhiyun if (opp_table->regulator_count > 1) {
803*4882a593Smuzhiyun info->opp_table[i].u_volt_mem = opp->supplies[1].u_volt;
804*4882a593Smuzhiyun info->opp_table[i].u_volt_mem_min = opp->supplies[1].u_volt_min;
805*4882a593Smuzhiyun info->opp_table[i].u_volt_mem_max = opp->supplies[1].u_volt_max;
806*4882a593Smuzhiyun }
807*4882a593Smuzhiyun info->opp_table[i++].rate = opp->rate;
808*4882a593Smuzhiyun }
809*4882a593Smuzhiyun mutex_unlock(&opp_table->lock);
810*4882a593Smuzhiyun
811*4882a593Smuzhiyun dev_pm_opp_put_opp_table(opp_table);
812*4882a593Smuzhiyun
813*4882a593Smuzhiyun return 0;
814*4882a593Smuzhiyun }
815*4882a593Smuzhiyun
rockchip_pvtpll_set_volt(struct device * dev,struct regulator * reg,int target_uV,int max_uV,char * reg_name)816*4882a593Smuzhiyun static int rockchip_pvtpll_set_volt(struct device *dev, struct regulator *reg,
817*4882a593Smuzhiyun int target_uV, int max_uV, char *reg_name)
818*4882a593Smuzhiyun {
819*4882a593Smuzhiyun int ret = 0;
820*4882a593Smuzhiyun
821*4882a593Smuzhiyun ret = regulator_set_voltage(reg, target_uV, max_uV);
822*4882a593Smuzhiyun if (ret)
823*4882a593Smuzhiyun dev_err(dev, "%s: failed to set %s voltage (%d %d uV): %d\n",
824*4882a593Smuzhiyun __func__, reg_name, target_uV, max_uV, ret);
825*4882a593Smuzhiyun
826*4882a593Smuzhiyun return ret;
827*4882a593Smuzhiyun }
828*4882a593Smuzhiyun
rockchip_pvtpll_set_clk(struct device * dev,struct clk * clk,unsigned long rate)829*4882a593Smuzhiyun static int rockchip_pvtpll_set_clk(struct device *dev, struct clk *clk,
830*4882a593Smuzhiyun unsigned long rate)
831*4882a593Smuzhiyun {
832*4882a593Smuzhiyun int ret = 0;
833*4882a593Smuzhiyun
834*4882a593Smuzhiyun ret = clk_set_rate(clk, rate);
835*4882a593Smuzhiyun if (ret)
836*4882a593Smuzhiyun dev_err(dev, "%s: failed to set rate %lu Hz, ret:%d\n",
837*4882a593Smuzhiyun __func__, rate, ret);
838*4882a593Smuzhiyun
839*4882a593Smuzhiyun return ret;
840*4882a593Smuzhiyun }
841*4882a593Smuzhiyun
rockchip_pvtpll_calibrate_opp(struct rockchip_opp_info * info)842*4882a593Smuzhiyun void rockchip_pvtpll_calibrate_opp(struct rockchip_opp_info *info)
843*4882a593Smuzhiyun {
844*4882a593Smuzhiyun struct opp_table *opp_table;
845*4882a593Smuzhiyun struct dev_pm_opp *opp;
846*4882a593Smuzhiyun struct regulator *reg = NULL, *reg_mem = NULL;
847*4882a593Smuzhiyun unsigned long old_volt = 0, old_volt_mem = 0;
848*4882a593Smuzhiyun unsigned long volt = 0, volt_mem = 0;
849*4882a593Smuzhiyun unsigned long volt_min, volt_max, volt_mem_min, volt_mem_max;
850*4882a593Smuzhiyun unsigned long rate, pvtpll_rate, old_rate, cur_rate, delta0, delta1;
851*4882a593Smuzhiyun int i = 0, max_count, step, cur_step, ret;
852*4882a593Smuzhiyun
853*4882a593Smuzhiyun if (!info || !info->grf)
854*4882a593Smuzhiyun return;
855*4882a593Smuzhiyun
856*4882a593Smuzhiyun dev_dbg(info->dev, "calibrating opp ...\n");
857*4882a593Smuzhiyun ret = rockchip_init_pvtpll_info(info);
858*4882a593Smuzhiyun if (ret)
859*4882a593Smuzhiyun return;
860*4882a593Smuzhiyun
861*4882a593Smuzhiyun max_count = dev_pm_opp_get_opp_count(info->dev);
862*4882a593Smuzhiyun if (max_count <= 0)
863*4882a593Smuzhiyun return;
864*4882a593Smuzhiyun
865*4882a593Smuzhiyun opp_table = dev_pm_opp_get_opp_table(info->dev);
866*4882a593Smuzhiyun if (!opp_table)
867*4882a593Smuzhiyun return;
868*4882a593Smuzhiyun
869*4882a593Smuzhiyun if ((!opp_table->regulators) || IS_ERR(opp_table->clk))
870*4882a593Smuzhiyun goto out_put;
871*4882a593Smuzhiyun
872*4882a593Smuzhiyun reg = opp_table->regulators[0];
873*4882a593Smuzhiyun old_volt = regulator_get_voltage(reg);
874*4882a593Smuzhiyun if (opp_table->regulator_count > 1) {
875*4882a593Smuzhiyun reg_mem = opp_table->regulators[1];
876*4882a593Smuzhiyun old_volt_mem = regulator_get_voltage(reg_mem);
877*4882a593Smuzhiyun if (IS_ERR_VALUE(old_volt_mem))
878*4882a593Smuzhiyun goto out_put;
879*4882a593Smuzhiyun }
880*4882a593Smuzhiyun old_rate = clk_get_rate(opp_table->clk);
881*4882a593Smuzhiyun if (IS_ERR_VALUE(old_volt) || IS_ERR_VALUE(old_rate))
882*4882a593Smuzhiyun goto out_put;
883*4882a593Smuzhiyun cur_rate = old_rate;
884*4882a593Smuzhiyun
885*4882a593Smuzhiyun step = regulator_get_linear_step(reg);
886*4882a593Smuzhiyun if (!step || info->pvtpll_volt_step > step)
887*4882a593Smuzhiyun step = info->pvtpll_volt_step;
888*4882a593Smuzhiyun
889*4882a593Smuzhiyun if (old_rate > info->pvtpll_min_rate * 1000) {
890*4882a593Smuzhiyun if (rockchip_pvtpll_set_clk(info->dev, opp_table->clk,
891*4882a593Smuzhiyun info->pvtpll_min_rate * 1000))
892*4882a593Smuzhiyun goto out_put;
893*4882a593Smuzhiyun }
894*4882a593Smuzhiyun
895*4882a593Smuzhiyun for (i = 0; i < max_count; i++) {
896*4882a593Smuzhiyun rate = info->opp_table[i].rate;
897*4882a593Smuzhiyun if (rate < 1000 * info->pvtpll_min_rate)
898*4882a593Smuzhiyun continue;
899*4882a593Smuzhiyun
900*4882a593Smuzhiyun volt = max(volt, info->opp_table[i].u_volt);
901*4882a593Smuzhiyun volt_min = info->opp_table[i].u_volt_min;
902*4882a593Smuzhiyun volt_max = info->opp_table[i].u_volt_max;
903*4882a593Smuzhiyun
904*4882a593Smuzhiyun if (opp_table->regulator_count > 1) {
905*4882a593Smuzhiyun volt_mem = max(volt_mem, info->opp_table[i].u_volt_mem);
906*4882a593Smuzhiyun volt_mem_min = info->opp_table[i].u_volt_mem_min;
907*4882a593Smuzhiyun volt_mem_max = info->opp_table[i].u_volt_mem_max;
908*4882a593Smuzhiyun if (rockchip_pvtpll_set_volt(info->dev, reg_mem,
909*4882a593Smuzhiyun volt_mem, volt_mem_max, "mem"))
910*4882a593Smuzhiyun goto out;
911*4882a593Smuzhiyun }
912*4882a593Smuzhiyun if (rockchip_pvtpll_set_volt(info->dev, reg, volt, volt_max, "vdd"))
913*4882a593Smuzhiyun goto out;
914*4882a593Smuzhiyun
915*4882a593Smuzhiyun if (rockchip_pvtpll_set_clk(info->dev, opp_table->clk, rate))
916*4882a593Smuzhiyun goto out;
917*4882a593Smuzhiyun cur_rate = rate;
918*4882a593Smuzhiyun pvtpll_rate = rockchip_pvtpll_get_rate(info);
919*4882a593Smuzhiyun if (!pvtpll_rate)
920*4882a593Smuzhiyun goto out;
921*4882a593Smuzhiyun cur_step = (pvtpll_rate < rate) ? step : -step;
922*4882a593Smuzhiyun delta1 = abs(pvtpll_rate - rate);
923*4882a593Smuzhiyun do {
924*4882a593Smuzhiyun delta0 = delta1;
925*4882a593Smuzhiyun volt += cur_step;
926*4882a593Smuzhiyun if ((volt < volt_min) || (volt > volt_max))
927*4882a593Smuzhiyun break;
928*4882a593Smuzhiyun if (opp_table->regulator_count > 1) {
929*4882a593Smuzhiyun if (volt > volt_mem_max)
930*4882a593Smuzhiyun break;
931*4882a593Smuzhiyun else if (volt < volt_mem_min)
932*4882a593Smuzhiyun volt_mem = volt_mem_min;
933*4882a593Smuzhiyun else
934*4882a593Smuzhiyun volt_mem = volt;
935*4882a593Smuzhiyun if (rockchip_pvtpll_set_volt(info->dev, reg_mem,
936*4882a593Smuzhiyun volt_mem, volt_mem_max,
937*4882a593Smuzhiyun "mem"))
938*4882a593Smuzhiyun break;
939*4882a593Smuzhiyun }
940*4882a593Smuzhiyun if (rockchip_pvtpll_set_volt(info->dev, reg, volt,
941*4882a593Smuzhiyun volt_max, "vdd"))
942*4882a593Smuzhiyun break;
943*4882a593Smuzhiyun pvtpll_rate = rockchip_pvtpll_get_rate(info);
944*4882a593Smuzhiyun if (!pvtpll_rate)
945*4882a593Smuzhiyun goto out;
946*4882a593Smuzhiyun delta1 = abs(pvtpll_rate - rate);
947*4882a593Smuzhiyun } while (delta1 < delta0);
948*4882a593Smuzhiyun
949*4882a593Smuzhiyun volt -= cur_step;
950*4882a593Smuzhiyun info->opp_table[i].u_volt = volt;
951*4882a593Smuzhiyun if (opp_table->regulator_count > 1) {
952*4882a593Smuzhiyun if (volt < volt_mem_min)
953*4882a593Smuzhiyun volt_mem = volt_mem_min;
954*4882a593Smuzhiyun else
955*4882a593Smuzhiyun volt_mem = volt;
956*4882a593Smuzhiyun info->opp_table[i].u_volt_mem = volt_mem;
957*4882a593Smuzhiyun }
958*4882a593Smuzhiyun }
959*4882a593Smuzhiyun
960*4882a593Smuzhiyun i = 0;
961*4882a593Smuzhiyun mutex_lock(&opp_table->lock);
962*4882a593Smuzhiyun list_for_each_entry(opp, &opp_table->opp_list, node) {
963*4882a593Smuzhiyun if (!opp->available)
964*4882a593Smuzhiyun continue;
965*4882a593Smuzhiyun
966*4882a593Smuzhiyun opp->supplies[0].u_volt = info->opp_table[i].u_volt;
967*4882a593Smuzhiyun if (opp_table->regulator_count > 1)
968*4882a593Smuzhiyun opp->supplies[1].u_volt = info->opp_table[i].u_volt_mem;
969*4882a593Smuzhiyun i++;
970*4882a593Smuzhiyun }
971*4882a593Smuzhiyun mutex_unlock(&opp_table->lock);
972*4882a593Smuzhiyun dev_info(info->dev, "opp calibration done\n");
973*4882a593Smuzhiyun out:
974*4882a593Smuzhiyun if (cur_rate > old_rate)
975*4882a593Smuzhiyun rockchip_pvtpll_set_clk(info->dev, opp_table->clk, old_rate);
976*4882a593Smuzhiyun if (opp_table->regulator_count > 1)
977*4882a593Smuzhiyun rockchip_pvtpll_set_volt(info->dev, reg_mem, old_volt_mem,
978*4882a593Smuzhiyun INT_MAX, "mem");
979*4882a593Smuzhiyun rockchip_pvtpll_set_volt(info->dev, reg, old_volt, INT_MAX, "vdd");
980*4882a593Smuzhiyun if (cur_rate < old_rate)
981*4882a593Smuzhiyun rockchip_pvtpll_set_clk(info->dev, opp_table->clk, old_rate);
982*4882a593Smuzhiyun out_put:
983*4882a593Smuzhiyun dev_pm_opp_put_opp_table(opp_table);
984*4882a593Smuzhiyun }
985*4882a593Smuzhiyun EXPORT_SYMBOL(rockchip_pvtpll_calibrate_opp);
986*4882a593Smuzhiyun
rockchip_pvtpll_add_length(struct rockchip_opp_info * info)987*4882a593Smuzhiyun void rockchip_pvtpll_add_length(struct rockchip_opp_info *info)
988*4882a593Smuzhiyun {
989*4882a593Smuzhiyun struct device_node *np;
990*4882a593Smuzhiyun struct opp_table *opp_table;
991*4882a593Smuzhiyun struct dev_pm_opp *opp;
992*4882a593Smuzhiyun unsigned long old_rate;
993*4882a593Smuzhiyun unsigned int min_rate = 0, max_rate = 0, margin = 0;
994*4882a593Smuzhiyun u32 opp_flag = 0;
995*4882a593Smuzhiyun int ret;
996*4882a593Smuzhiyun
997*4882a593Smuzhiyun if (!info)
998*4882a593Smuzhiyun return;
999*4882a593Smuzhiyun
1000*4882a593Smuzhiyun np = of_parse_phandle(info->dev->of_node, "operating-points-v2", 0);
1001*4882a593Smuzhiyun if (!np) {
1002*4882a593Smuzhiyun dev_warn(info->dev, "OPP-v2 not supported\n");
1003*4882a593Smuzhiyun return;
1004*4882a593Smuzhiyun }
1005*4882a593Smuzhiyun
1006*4882a593Smuzhiyun if (of_property_read_u32(np, "rockchip,pvtpll-len-min-rate", &min_rate))
1007*4882a593Smuzhiyun return;
1008*4882a593Smuzhiyun if (of_property_read_u32(np, "rockchip,pvtpll-len-max-rate", &max_rate))
1009*4882a593Smuzhiyun return;
1010*4882a593Smuzhiyun if (of_property_read_u32(np, "rockchip,pvtpll-len-margin", &margin))
1011*4882a593Smuzhiyun return;
1012*4882a593Smuzhiyun
1013*4882a593Smuzhiyun opp_table = dev_pm_opp_get_opp_table(info->dev);
1014*4882a593Smuzhiyun if (!opp_table)
1015*4882a593Smuzhiyun return;
1016*4882a593Smuzhiyun old_rate = clk_get_rate(opp_table->clk);
1017*4882a593Smuzhiyun opp_flag = OPP_ADD_LENGTH | ((margin & OPP_LENGTH_MASK) << OPP_LENGTH_SHIFT);
1018*4882a593Smuzhiyun
1019*4882a593Smuzhiyun mutex_lock(&opp_table->lock);
1020*4882a593Smuzhiyun list_for_each_entry(opp, &opp_table->opp_list, node) {
1021*4882a593Smuzhiyun if (opp->rate < min_rate * 1000 || opp->rate > max_rate * 1000)
1022*4882a593Smuzhiyun continue;
1023*4882a593Smuzhiyun ret = clk_set_rate(opp_table->clk, opp->rate | opp_flag);
1024*4882a593Smuzhiyun if (ret) {
1025*4882a593Smuzhiyun dev_err(info->dev,
1026*4882a593Smuzhiyun "failed to change %lu len margin %d\n",
1027*4882a593Smuzhiyun opp->rate, margin);
1028*4882a593Smuzhiyun break;
1029*4882a593Smuzhiyun }
1030*4882a593Smuzhiyun }
1031*4882a593Smuzhiyun mutex_unlock(&opp_table->lock);
1032*4882a593Smuzhiyun
1033*4882a593Smuzhiyun clk_set_rate(opp_table->clk, old_rate);
1034*4882a593Smuzhiyun
1035*4882a593Smuzhiyun dev_pm_opp_put_opp_table(opp_table);
1036*4882a593Smuzhiyun }
1037*4882a593Smuzhiyun EXPORT_SYMBOL(rockchip_pvtpll_add_length);
1038*4882a593Smuzhiyun
rockchip_get_pvtm_pvtpll(struct device * dev,struct device_node * np,char * reg_name)1039*4882a593Smuzhiyun static int rockchip_get_pvtm_pvtpll(struct device *dev, struct device_node *np,
1040*4882a593Smuzhiyun char *reg_name)
1041*4882a593Smuzhiyun {
1042*4882a593Smuzhiyun struct regulator *reg;
1043*4882a593Smuzhiyun struct clk *clk;
1044*4882a593Smuzhiyun struct pvtm_config *pvtm;
1045*4882a593Smuzhiyun unsigned long old_freq;
1046*4882a593Smuzhiyun unsigned int old_volt;
1047*4882a593Smuzhiyun int cur_temp, diff_temp, prop_temp, diff_value;
1048*4882a593Smuzhiyun int pvtm_value = 0;
1049*4882a593Smuzhiyun int ret = 0;
1050*4882a593Smuzhiyun
1051*4882a593Smuzhiyun if (!rockchip_nvmem_cell_read_u16(np, "pvtm", (u16 *)&pvtm_value) && pvtm_value) {
1052*4882a593Smuzhiyun dev_info(dev, "pvtm = %d, get from otp\n", pvtm_value);
1053*4882a593Smuzhiyun return pvtm_value;
1054*4882a593Smuzhiyun }
1055*4882a593Smuzhiyun
1056*4882a593Smuzhiyun pvtm = kzalloc(sizeof(*pvtm), GFP_KERNEL);
1057*4882a593Smuzhiyun if (!pvtm)
1058*4882a593Smuzhiyun return -ENOMEM;
1059*4882a593Smuzhiyun
1060*4882a593Smuzhiyun ret = rockchip_parse_pvtm_config(np, pvtm);
1061*4882a593Smuzhiyun if (ret)
1062*4882a593Smuzhiyun goto out;
1063*4882a593Smuzhiyun
1064*4882a593Smuzhiyun clk = clk_get(dev, NULL);
1065*4882a593Smuzhiyun if (IS_ERR_OR_NULL(clk)) {
1066*4882a593Smuzhiyun dev_warn(dev, "Failed to get clk\n");
1067*4882a593Smuzhiyun goto out;
1068*4882a593Smuzhiyun }
1069*4882a593Smuzhiyun
1070*4882a593Smuzhiyun reg = regulator_get_optional(dev, reg_name);
1071*4882a593Smuzhiyun if (IS_ERR_OR_NULL(reg)) {
1072*4882a593Smuzhiyun dev_warn(dev, "Failed to get reg\n");
1073*4882a593Smuzhiyun clk_put(clk);
1074*4882a593Smuzhiyun goto out;
1075*4882a593Smuzhiyun }
1076*4882a593Smuzhiyun old_freq = clk_get_rate(clk);
1077*4882a593Smuzhiyun old_volt = regulator_get_voltage(reg);
1078*4882a593Smuzhiyun
1079*4882a593Smuzhiyun ret = clk_set_rate(clk, pvtm->freq * 1000);
1080*4882a593Smuzhiyun if (ret) {
1081*4882a593Smuzhiyun dev_err(dev, "Failed to set pvtm freq\n");
1082*4882a593Smuzhiyun goto put_reg;
1083*4882a593Smuzhiyun }
1084*4882a593Smuzhiyun ret = regulator_set_voltage(reg, pvtm->volt, INT_MAX);
1085*4882a593Smuzhiyun if (ret) {
1086*4882a593Smuzhiyun dev_err(dev, "Failed to set pvtm_volt\n");
1087*4882a593Smuzhiyun goto restore_clk;
1088*4882a593Smuzhiyun }
1089*4882a593Smuzhiyun usleep_range(pvtm->sample_time, pvtm->sample_time + 100);
1090*4882a593Smuzhiyun
1091*4882a593Smuzhiyun ret = regmap_read(pvtm->grf, pvtm->offset, &pvtm_value);
1092*4882a593Smuzhiyun if (ret < 0) {
1093*4882a593Smuzhiyun dev_err(dev, "failed to get pvtm from 0x%x\n", pvtm->offset);
1094*4882a593Smuzhiyun goto resetore_volt;
1095*4882a593Smuzhiyun }
1096*4882a593Smuzhiyun pvtm->tz->ops->get_temp(pvtm->tz, &cur_temp);
1097*4882a593Smuzhiyun diff_temp = (cur_temp / 1000 - pvtm->ref_temp);
1098*4882a593Smuzhiyun if (diff_temp < 0)
1099*4882a593Smuzhiyun prop_temp = pvtm->temp_prop[0];
1100*4882a593Smuzhiyun else
1101*4882a593Smuzhiyun prop_temp = pvtm->temp_prop[1];
1102*4882a593Smuzhiyun diff_value = diff_temp * prop_temp / 1000;
1103*4882a593Smuzhiyun pvtm_value += diff_value;
1104*4882a593Smuzhiyun
1105*4882a593Smuzhiyun dev_info(dev, "pvtm=%d\n", pvtm_value);
1106*4882a593Smuzhiyun
1107*4882a593Smuzhiyun resetore_volt:
1108*4882a593Smuzhiyun regulator_set_voltage(reg, old_volt, INT_MAX);
1109*4882a593Smuzhiyun restore_clk:
1110*4882a593Smuzhiyun clk_set_rate(clk, old_freq);
1111*4882a593Smuzhiyun put_reg:
1112*4882a593Smuzhiyun regulator_put(reg);
1113*4882a593Smuzhiyun clk_put(clk);
1114*4882a593Smuzhiyun out:
1115*4882a593Smuzhiyun kfree(pvtm);
1116*4882a593Smuzhiyun
1117*4882a593Smuzhiyun return pvtm_value;
1118*4882a593Smuzhiyun }
1119*4882a593Smuzhiyun
rockchip_get_pvtm(struct device * dev,struct device_node * np,char * reg_name)1120*4882a593Smuzhiyun static int rockchip_get_pvtm(struct device *dev, struct device_node *np,
1121*4882a593Smuzhiyun char *reg_name)
1122*4882a593Smuzhiyun {
1123*4882a593Smuzhiyun struct regulator *reg;
1124*4882a593Smuzhiyun struct clk *clk;
1125*4882a593Smuzhiyun unsigned int ch[2];
1126*4882a593Smuzhiyun int pvtm = 0;
1127*4882a593Smuzhiyun u16 tmp = 0;
1128*4882a593Smuzhiyun
1129*4882a593Smuzhiyun if (!rockchip_nvmem_cell_read_u16(np, "pvtm", &tmp) && tmp) {
1130*4882a593Smuzhiyun pvtm = 10 * tmp;
1131*4882a593Smuzhiyun dev_info(dev, "pvtm = %d, from nvmem\n", pvtm);
1132*4882a593Smuzhiyun return pvtm;
1133*4882a593Smuzhiyun }
1134*4882a593Smuzhiyun
1135*4882a593Smuzhiyun if (of_property_read_u32_array(np, "rockchip,pvtm-ch", ch, 2))
1136*4882a593Smuzhiyun return -EINVAL;
1137*4882a593Smuzhiyun
1138*4882a593Smuzhiyun if (ch[0] >= PVTM_CH_MAX || ch[1] >= PVTM_SUB_CH_MAX)
1139*4882a593Smuzhiyun return -EINVAL;
1140*4882a593Smuzhiyun
1141*4882a593Smuzhiyun if (pvtm_value[ch[0]][ch[1]]) {
1142*4882a593Smuzhiyun dev_info(dev, "pvtm = %d, form pvtm_value\n", pvtm_value[ch[0]][ch[1]]);
1143*4882a593Smuzhiyun return pvtm_value[ch[0]][ch[1]];
1144*4882a593Smuzhiyun }
1145*4882a593Smuzhiyun
1146*4882a593Smuzhiyun clk = clk_get(dev, NULL);
1147*4882a593Smuzhiyun if (IS_ERR_OR_NULL(clk)) {
1148*4882a593Smuzhiyun dev_warn(dev, "Failed to get clk\n");
1149*4882a593Smuzhiyun return PTR_ERR_OR_ZERO(clk);
1150*4882a593Smuzhiyun }
1151*4882a593Smuzhiyun
1152*4882a593Smuzhiyun reg = regulator_get_optional(dev, reg_name);
1153*4882a593Smuzhiyun if (IS_ERR_OR_NULL(reg)) {
1154*4882a593Smuzhiyun dev_warn(dev, "Failed to get reg\n");
1155*4882a593Smuzhiyun clk_put(clk);
1156*4882a593Smuzhiyun return PTR_ERR_OR_ZERO(reg);
1157*4882a593Smuzhiyun }
1158*4882a593Smuzhiyun
1159*4882a593Smuzhiyun rockchip_get_pvtm_specific_value(dev, np, clk, reg, &pvtm);
1160*4882a593Smuzhiyun
1161*4882a593Smuzhiyun regulator_put(reg);
1162*4882a593Smuzhiyun clk_put(clk);
1163*4882a593Smuzhiyun
1164*4882a593Smuzhiyun return pvtm;
1165*4882a593Smuzhiyun }
1166*4882a593Smuzhiyun
rockchip_of_get_pvtm_sel(struct device * dev,struct device_node * np,char * reg_name,int bin,int process,int * volt_sel,int * scale_sel)1167*4882a593Smuzhiyun void rockchip_of_get_pvtm_sel(struct device *dev, struct device_node *np,
1168*4882a593Smuzhiyun char *reg_name, int bin, int process,
1169*4882a593Smuzhiyun int *volt_sel, int *scale_sel)
1170*4882a593Smuzhiyun {
1171*4882a593Smuzhiyun struct property *prop = NULL;
1172*4882a593Smuzhiyun char name[NAME_MAX];
1173*4882a593Smuzhiyun int pvtm, ret;
1174*4882a593Smuzhiyun u32 hw = 0;
1175*4882a593Smuzhiyun
1176*4882a593Smuzhiyun if (of_property_read_bool(np, "rockchip,pvtm-pvtpll"))
1177*4882a593Smuzhiyun pvtm = rockchip_get_pvtm_pvtpll(dev, np, reg_name);
1178*4882a593Smuzhiyun else
1179*4882a593Smuzhiyun pvtm = rockchip_get_pvtm(dev, np, reg_name);
1180*4882a593Smuzhiyun if (pvtm <= 0)
1181*4882a593Smuzhiyun return;
1182*4882a593Smuzhiyun
1183*4882a593Smuzhiyun if (!volt_sel)
1184*4882a593Smuzhiyun goto next;
1185*4882a593Smuzhiyun if (process >= 0) {
1186*4882a593Smuzhiyun snprintf(name, sizeof(name),
1187*4882a593Smuzhiyun "rockchip,p%d-pvtm-voltage-sel", process);
1188*4882a593Smuzhiyun prop = of_find_property(np, name, NULL);
1189*4882a593Smuzhiyun } else if (bin >= 0) {
1190*4882a593Smuzhiyun of_property_read_u32(np, "rockchip,pvtm-hw", &hw);
1191*4882a593Smuzhiyun if (hw && (hw & BIT(bin))) {
1192*4882a593Smuzhiyun sprintf(name, "rockchip,pvtm-voltage-sel-hw");
1193*4882a593Smuzhiyun prop = of_find_property(np, name, NULL);
1194*4882a593Smuzhiyun }
1195*4882a593Smuzhiyun }
1196*4882a593Smuzhiyun if (!prop)
1197*4882a593Smuzhiyun sprintf(name, "rockchip,pvtm-voltage-sel");
1198*4882a593Smuzhiyun ret = rockchip_get_sel(np, name, pvtm, volt_sel);
1199*4882a593Smuzhiyun if (!ret && volt_sel)
1200*4882a593Smuzhiyun dev_info(dev, "pvtm-volt-sel=%d\n", *volt_sel);
1201*4882a593Smuzhiyun
1202*4882a593Smuzhiyun next:
1203*4882a593Smuzhiyun if (!scale_sel)
1204*4882a593Smuzhiyun return;
1205*4882a593Smuzhiyun prop = NULL;
1206*4882a593Smuzhiyun if (process >= 0) {
1207*4882a593Smuzhiyun snprintf(name, sizeof(name),
1208*4882a593Smuzhiyun "rockchip,p%d-pvtm-scaling-sel", process);
1209*4882a593Smuzhiyun prop = of_find_property(np, name, NULL);
1210*4882a593Smuzhiyun }
1211*4882a593Smuzhiyun if (!prop)
1212*4882a593Smuzhiyun sprintf(name, "rockchip,pvtm-scaling-sel");
1213*4882a593Smuzhiyun ret = rockchip_get_sel(np, name, pvtm, scale_sel);
1214*4882a593Smuzhiyun if (!ret)
1215*4882a593Smuzhiyun dev_info(dev, "pvtm-scale=%d\n", *scale_sel);
1216*4882a593Smuzhiyun }
1217*4882a593Smuzhiyun EXPORT_SYMBOL(rockchip_of_get_pvtm_sel);
1218*4882a593Smuzhiyun
rockchip_of_get_bin_sel(struct device * dev,struct device_node * np,int bin,int * scale_sel)1219*4882a593Smuzhiyun void rockchip_of_get_bin_sel(struct device *dev, struct device_node *np,
1220*4882a593Smuzhiyun int bin, int *scale_sel)
1221*4882a593Smuzhiyun {
1222*4882a593Smuzhiyun int ret = 0;
1223*4882a593Smuzhiyun
1224*4882a593Smuzhiyun if (!scale_sel || bin < 0)
1225*4882a593Smuzhiyun return;
1226*4882a593Smuzhiyun
1227*4882a593Smuzhiyun ret = rockchip_get_bin_sel(np, "rockchip,bin-scaling-sel",
1228*4882a593Smuzhiyun bin, scale_sel);
1229*4882a593Smuzhiyun if (!ret)
1230*4882a593Smuzhiyun dev_info(dev, "bin-scale=%d\n", *scale_sel);
1231*4882a593Smuzhiyun }
1232*4882a593Smuzhiyun EXPORT_SYMBOL(rockchip_of_get_bin_sel);
1233*4882a593Smuzhiyun
rockchip_of_get_bin_volt_sel(struct device * dev,struct device_node * np,int bin,int * bin_volt_sel)1234*4882a593Smuzhiyun void rockchip_of_get_bin_volt_sel(struct device *dev, struct device_node *np,
1235*4882a593Smuzhiyun int bin, int *bin_volt_sel)
1236*4882a593Smuzhiyun {
1237*4882a593Smuzhiyun int ret = 0;
1238*4882a593Smuzhiyun
1239*4882a593Smuzhiyun if (!bin_volt_sel || bin < 0)
1240*4882a593Smuzhiyun return;
1241*4882a593Smuzhiyun
1242*4882a593Smuzhiyun ret = rockchip_get_bin_sel(np, "rockchip,bin-voltage-sel",
1243*4882a593Smuzhiyun bin, bin_volt_sel);
1244*4882a593Smuzhiyun if (!ret)
1245*4882a593Smuzhiyun dev_info(dev, "bin-volt-sel=%d\n", *bin_volt_sel);
1246*4882a593Smuzhiyun }
1247*4882a593Smuzhiyun EXPORT_SYMBOL(rockchip_of_get_bin_volt_sel);
1248*4882a593Smuzhiyun
rockchip_get_opp_data(const struct of_device_id * matches,struct rockchip_opp_info * info)1249*4882a593Smuzhiyun void rockchip_get_opp_data(const struct of_device_id *matches,
1250*4882a593Smuzhiyun struct rockchip_opp_info *info)
1251*4882a593Smuzhiyun {
1252*4882a593Smuzhiyun const struct of_device_id *match;
1253*4882a593Smuzhiyun struct device_node *node;
1254*4882a593Smuzhiyun
1255*4882a593Smuzhiyun node = of_find_node_by_path("/");
1256*4882a593Smuzhiyun match = of_match_node(matches, node);
1257*4882a593Smuzhiyun if (match && match->data)
1258*4882a593Smuzhiyun info->data = match->data;
1259*4882a593Smuzhiyun of_node_put(node);
1260*4882a593Smuzhiyun }
1261*4882a593Smuzhiyun EXPORT_SYMBOL(rockchip_get_opp_data);
1262*4882a593Smuzhiyun
rockchip_get_volt_rm_table(struct device * dev,struct device_node * np,char * porp_name,struct volt_rm_table ** table)1263*4882a593Smuzhiyun int rockchip_get_volt_rm_table(struct device *dev, struct device_node *np,
1264*4882a593Smuzhiyun char *porp_name, struct volt_rm_table **table)
1265*4882a593Smuzhiyun {
1266*4882a593Smuzhiyun struct volt_rm_table *rm_table;
1267*4882a593Smuzhiyun const struct property *prop;
1268*4882a593Smuzhiyun int count, i;
1269*4882a593Smuzhiyun
1270*4882a593Smuzhiyun prop = of_find_property(np, porp_name, NULL);
1271*4882a593Smuzhiyun if (!prop)
1272*4882a593Smuzhiyun return -EINVAL;
1273*4882a593Smuzhiyun
1274*4882a593Smuzhiyun if (!prop->value)
1275*4882a593Smuzhiyun return -ENODATA;
1276*4882a593Smuzhiyun
1277*4882a593Smuzhiyun count = of_property_count_u32_elems(np, porp_name);
1278*4882a593Smuzhiyun if (count < 0)
1279*4882a593Smuzhiyun return -EINVAL;
1280*4882a593Smuzhiyun
1281*4882a593Smuzhiyun if (count % 2)
1282*4882a593Smuzhiyun return -EINVAL;
1283*4882a593Smuzhiyun
1284*4882a593Smuzhiyun rm_table = devm_kzalloc(dev, sizeof(*rm_table) * (count / 2 + 1),
1285*4882a593Smuzhiyun GFP_KERNEL);
1286*4882a593Smuzhiyun if (!rm_table)
1287*4882a593Smuzhiyun return -ENOMEM;
1288*4882a593Smuzhiyun
1289*4882a593Smuzhiyun for (i = 0; i < count / 2; i++) {
1290*4882a593Smuzhiyun of_property_read_u32_index(np, porp_name, 2 * i,
1291*4882a593Smuzhiyun &rm_table[i].volt);
1292*4882a593Smuzhiyun of_property_read_u32_index(np, porp_name, 2 * i + 1,
1293*4882a593Smuzhiyun &rm_table[i].rm);
1294*4882a593Smuzhiyun }
1295*4882a593Smuzhiyun
1296*4882a593Smuzhiyun rm_table[i].volt = 0;
1297*4882a593Smuzhiyun rm_table[i].rm = VOLT_RM_TABLE_END;
1298*4882a593Smuzhiyun
1299*4882a593Smuzhiyun *table = rm_table;
1300*4882a593Smuzhiyun
1301*4882a593Smuzhiyun return 0;
1302*4882a593Smuzhiyun }
1303*4882a593Smuzhiyun EXPORT_SYMBOL(rockchip_get_volt_rm_table);
1304*4882a593Smuzhiyun
rockchip_get_soc_info(struct device * dev,struct device_node * np,int * bin,int * process)1305*4882a593Smuzhiyun int rockchip_get_soc_info(struct device *dev, struct device_node *np, int *bin,
1306*4882a593Smuzhiyun int *process)
1307*4882a593Smuzhiyun {
1308*4882a593Smuzhiyun u8 value = 0;
1309*4882a593Smuzhiyun int ret = 0;
1310*4882a593Smuzhiyun
1311*4882a593Smuzhiyun if (*bin >= 0 || *process >= 0)
1312*4882a593Smuzhiyun return 0;
1313*4882a593Smuzhiyun
1314*4882a593Smuzhiyun if (of_property_match_string(np, "nvmem-cell-names",
1315*4882a593Smuzhiyun "specification_serial_number") >= 0) {
1316*4882a593Smuzhiyun ret = rockchip_nvmem_cell_read_u8(np,
1317*4882a593Smuzhiyun "specification_serial_number",
1318*4882a593Smuzhiyun &value);
1319*4882a593Smuzhiyun if (ret) {
1320*4882a593Smuzhiyun dev_err(dev,
1321*4882a593Smuzhiyun "Failed to get specification_serial_number\n");
1322*4882a593Smuzhiyun return ret;
1323*4882a593Smuzhiyun }
1324*4882a593Smuzhiyun /* M */
1325*4882a593Smuzhiyun if (value == 0xd)
1326*4882a593Smuzhiyun *bin = 1;
1327*4882a593Smuzhiyun /* J */
1328*4882a593Smuzhiyun else if (value == 0xa)
1329*4882a593Smuzhiyun *bin = 2;
1330*4882a593Smuzhiyun }
1331*4882a593Smuzhiyun
1332*4882a593Smuzhiyun if (*bin < 0)
1333*4882a593Smuzhiyun *bin = 0;
1334*4882a593Smuzhiyun dev_info(dev, "bin=%d\n", *bin);
1335*4882a593Smuzhiyun
1336*4882a593Smuzhiyun return 0;
1337*4882a593Smuzhiyun }
1338*4882a593Smuzhiyun EXPORT_SYMBOL(rockchip_get_soc_info);
1339*4882a593Smuzhiyun
rockchip_get_scale_volt_sel(struct device * dev,char * lkg_name,char * reg_name,int bin,int process,int * scale,int * volt_sel)1340*4882a593Smuzhiyun void rockchip_get_scale_volt_sel(struct device *dev, char *lkg_name,
1341*4882a593Smuzhiyun char *reg_name, int bin, int process,
1342*4882a593Smuzhiyun int *scale, int *volt_sel)
1343*4882a593Smuzhiyun {
1344*4882a593Smuzhiyun struct device_node *np;
1345*4882a593Smuzhiyun int lkg_scale = 0, pvtm_scale = 0, bin_scale = 0;
1346*4882a593Smuzhiyun int lkg_volt_sel = -EINVAL, pvtm_volt_sel = -EINVAL;
1347*4882a593Smuzhiyun int bin_volt_sel = -EINVAL;
1348*4882a593Smuzhiyun
1349*4882a593Smuzhiyun np = of_parse_phandle(dev->of_node, "operating-points-v2", 0);
1350*4882a593Smuzhiyun if (!np) {
1351*4882a593Smuzhiyun dev_warn(dev, "OPP-v2 not supported\n");
1352*4882a593Smuzhiyun return;
1353*4882a593Smuzhiyun }
1354*4882a593Smuzhiyun
1355*4882a593Smuzhiyun rockchip_of_get_lkg_sel(dev, np, lkg_name, process,
1356*4882a593Smuzhiyun &lkg_volt_sel, &lkg_scale);
1357*4882a593Smuzhiyun rockchip_of_get_pvtm_sel(dev, np, reg_name, bin, process,
1358*4882a593Smuzhiyun &pvtm_volt_sel, &pvtm_scale);
1359*4882a593Smuzhiyun rockchip_of_get_bin_sel(dev, np, bin, &bin_scale);
1360*4882a593Smuzhiyun rockchip_of_get_bin_volt_sel(dev, np, bin, &bin_volt_sel);
1361*4882a593Smuzhiyun if (scale)
1362*4882a593Smuzhiyun *scale = max3(lkg_scale, pvtm_scale, bin_scale);
1363*4882a593Smuzhiyun if (volt_sel) {
1364*4882a593Smuzhiyun if (bin_volt_sel >= 0)
1365*4882a593Smuzhiyun *volt_sel = bin_volt_sel;
1366*4882a593Smuzhiyun else
1367*4882a593Smuzhiyun *volt_sel = max(lkg_volt_sel, pvtm_volt_sel);
1368*4882a593Smuzhiyun }
1369*4882a593Smuzhiyun
1370*4882a593Smuzhiyun of_node_put(np);
1371*4882a593Smuzhiyun }
1372*4882a593Smuzhiyun EXPORT_SYMBOL(rockchip_get_scale_volt_sel);
1373*4882a593Smuzhiyun
rockchip_set_opp_prop_name(struct device * dev,int process,int volt_sel)1374*4882a593Smuzhiyun struct opp_table *rockchip_set_opp_prop_name(struct device *dev, int process,
1375*4882a593Smuzhiyun int volt_sel)
1376*4882a593Smuzhiyun {
1377*4882a593Smuzhiyun char name[MAX_PROP_NAME_LEN];
1378*4882a593Smuzhiyun
1379*4882a593Smuzhiyun if (process >= 0) {
1380*4882a593Smuzhiyun if (volt_sel >= 0)
1381*4882a593Smuzhiyun snprintf(name, MAX_PROP_NAME_LEN, "P%d-L%d",
1382*4882a593Smuzhiyun process, volt_sel);
1383*4882a593Smuzhiyun else
1384*4882a593Smuzhiyun snprintf(name, MAX_PROP_NAME_LEN, "P%d", process);
1385*4882a593Smuzhiyun } else if (volt_sel >= 0) {
1386*4882a593Smuzhiyun snprintf(name, MAX_PROP_NAME_LEN, "L%d", volt_sel);
1387*4882a593Smuzhiyun } else {
1388*4882a593Smuzhiyun return NULL;
1389*4882a593Smuzhiyun }
1390*4882a593Smuzhiyun
1391*4882a593Smuzhiyun return dev_pm_opp_set_prop_name(dev, name);
1392*4882a593Smuzhiyun }
1393*4882a593Smuzhiyun EXPORT_SYMBOL(rockchip_set_opp_prop_name);
1394*4882a593Smuzhiyun
rockchip_set_opp_supported_hw(struct device * dev,struct device_node * np,int bin,int volt_sel)1395*4882a593Smuzhiyun struct opp_table *rockchip_set_opp_supported_hw(struct device *dev,
1396*4882a593Smuzhiyun struct device_node *np,
1397*4882a593Smuzhiyun int bin, int volt_sel)
1398*4882a593Smuzhiyun {
1399*4882a593Smuzhiyun struct opp_table *opp_table;
1400*4882a593Smuzhiyun u32 supported_hw[2];
1401*4882a593Smuzhiyun u32 version = 0, speed = 0;
1402*4882a593Smuzhiyun
1403*4882a593Smuzhiyun if (!of_property_read_bool(np, "rockchip,supported-hw"))
1404*4882a593Smuzhiyun return NULL;
1405*4882a593Smuzhiyun
1406*4882a593Smuzhiyun opp_table = dev_pm_opp_get_opp_table(dev);
1407*4882a593Smuzhiyun if (!opp_table)
1408*4882a593Smuzhiyun return NULL;
1409*4882a593Smuzhiyun if (opp_table->supported_hw) {
1410*4882a593Smuzhiyun dev_pm_opp_put_opp_table(opp_table);
1411*4882a593Smuzhiyun return NULL;
1412*4882a593Smuzhiyun }
1413*4882a593Smuzhiyun dev_pm_opp_put_opp_table(opp_table);
1414*4882a593Smuzhiyun
1415*4882a593Smuzhiyun if (bin >= 0)
1416*4882a593Smuzhiyun version = bin;
1417*4882a593Smuzhiyun if (volt_sel >= 0)
1418*4882a593Smuzhiyun speed = volt_sel;
1419*4882a593Smuzhiyun
1420*4882a593Smuzhiyun /* SoC Version */
1421*4882a593Smuzhiyun supported_hw[0] = BIT(version);
1422*4882a593Smuzhiyun /* Speed Grade */
1423*4882a593Smuzhiyun supported_hw[1] = BIT(speed);
1424*4882a593Smuzhiyun
1425*4882a593Smuzhiyun dev_info(dev, "soc version=%d, speed=%d\n", version, speed);
1426*4882a593Smuzhiyun
1427*4882a593Smuzhiyun return dev_pm_opp_set_supported_hw(dev, supported_hw, 2);
1428*4882a593Smuzhiyun }
1429*4882a593Smuzhiyun EXPORT_SYMBOL(rockchip_set_opp_supported_hw);
1430*4882a593Smuzhiyun
rockchip_adjust_opp_by_irdrop(struct device * dev,struct device_node * np,unsigned long * safe_rate,unsigned long * max_rate)1431*4882a593Smuzhiyun static int rockchip_adjust_opp_by_irdrop(struct device *dev,
1432*4882a593Smuzhiyun struct device_node *np,
1433*4882a593Smuzhiyun unsigned long *safe_rate,
1434*4882a593Smuzhiyun unsigned long *max_rate)
1435*4882a593Smuzhiyun {
1436*4882a593Smuzhiyun struct sel_table *irdrop_table = NULL;
1437*4882a593Smuzhiyun struct opp_table *opp_table;
1438*4882a593Smuzhiyun struct dev_pm_opp *opp;
1439*4882a593Smuzhiyun unsigned long tmp_safe_rate = 0;
1440*4882a593Smuzhiyun int evb_irdrop = 0, board_irdrop, delta_irdrop;
1441*4882a593Smuzhiyun int opp_rate, i, ret = 0;
1442*4882a593Smuzhiyun u32 max_volt = UINT_MAX;
1443*4882a593Smuzhiyun bool reach_max_volt = false;
1444*4882a593Smuzhiyun
1445*4882a593Smuzhiyun of_property_read_u32_index(np, "rockchip,max-volt", 0, &max_volt);
1446*4882a593Smuzhiyun of_property_read_u32_index(np, "rockchip,evb-irdrop", 0, &evb_irdrop);
1447*4882a593Smuzhiyun rockchip_get_sel_table(np, "rockchip,board-irdrop", &irdrop_table);
1448*4882a593Smuzhiyun
1449*4882a593Smuzhiyun opp_table = dev_pm_opp_get_opp_table(dev);
1450*4882a593Smuzhiyun if (!opp_table) {
1451*4882a593Smuzhiyun ret = -ENOMEM;
1452*4882a593Smuzhiyun goto out;
1453*4882a593Smuzhiyun }
1454*4882a593Smuzhiyun
1455*4882a593Smuzhiyun mutex_lock(&opp_table->lock);
1456*4882a593Smuzhiyun list_for_each_entry(opp, &opp_table->opp_list, node) {
1457*4882a593Smuzhiyun if (!opp->available)
1458*4882a593Smuzhiyun continue;
1459*4882a593Smuzhiyun if (!irdrop_table) {
1460*4882a593Smuzhiyun delta_irdrop = 0;
1461*4882a593Smuzhiyun } else {
1462*4882a593Smuzhiyun opp_rate = opp->rate / 1000000;
1463*4882a593Smuzhiyun board_irdrop = -EINVAL;
1464*4882a593Smuzhiyun for (i = 0; irdrop_table[i].sel != SEL_TABLE_END; i++) {
1465*4882a593Smuzhiyun if (opp_rate >= irdrop_table[i].min)
1466*4882a593Smuzhiyun board_irdrop = irdrop_table[i].sel;
1467*4882a593Smuzhiyun }
1468*4882a593Smuzhiyun if (board_irdrop == -EINVAL)
1469*4882a593Smuzhiyun delta_irdrop = 0;
1470*4882a593Smuzhiyun else
1471*4882a593Smuzhiyun delta_irdrop = board_irdrop - evb_irdrop;
1472*4882a593Smuzhiyun }
1473*4882a593Smuzhiyun if ((opp->supplies[0].u_volt + delta_irdrop) <= max_volt) {
1474*4882a593Smuzhiyun opp->supplies[0].u_volt += delta_irdrop;
1475*4882a593Smuzhiyun opp->supplies[0].u_volt_min += delta_irdrop;
1476*4882a593Smuzhiyun if (opp->supplies[0].u_volt_max + delta_irdrop <=
1477*4882a593Smuzhiyun max_volt)
1478*4882a593Smuzhiyun opp->supplies[0].u_volt_max += delta_irdrop;
1479*4882a593Smuzhiyun else
1480*4882a593Smuzhiyun opp->supplies[0].u_volt_max = max_volt;
1481*4882a593Smuzhiyun if (!reach_max_volt)
1482*4882a593Smuzhiyun tmp_safe_rate = opp->rate;
1483*4882a593Smuzhiyun if (opp->supplies[0].u_volt == max_volt)
1484*4882a593Smuzhiyun reach_max_volt = true;
1485*4882a593Smuzhiyun } else {
1486*4882a593Smuzhiyun opp->supplies[0].u_volt = max_volt;
1487*4882a593Smuzhiyun opp->supplies[0].u_volt_min = max_volt;
1488*4882a593Smuzhiyun opp->supplies[0].u_volt_max = max_volt;
1489*4882a593Smuzhiyun }
1490*4882a593Smuzhiyun if (max_rate)
1491*4882a593Smuzhiyun *max_rate = opp->rate;
1492*4882a593Smuzhiyun if (safe_rate && tmp_safe_rate != opp->rate)
1493*4882a593Smuzhiyun *safe_rate = tmp_safe_rate;
1494*4882a593Smuzhiyun }
1495*4882a593Smuzhiyun mutex_unlock(&opp_table->lock);
1496*4882a593Smuzhiyun
1497*4882a593Smuzhiyun dev_pm_opp_put_opp_table(opp_table);
1498*4882a593Smuzhiyun out:
1499*4882a593Smuzhiyun kfree(irdrop_table);
1500*4882a593Smuzhiyun
1501*4882a593Smuzhiyun return ret;
1502*4882a593Smuzhiyun }
1503*4882a593Smuzhiyun
rockchip_adjust_opp_by_mbist_vmin(struct device * dev,struct device_node * np)1504*4882a593Smuzhiyun static void rockchip_adjust_opp_by_mbist_vmin(struct device *dev,
1505*4882a593Smuzhiyun struct device_node *np)
1506*4882a593Smuzhiyun {
1507*4882a593Smuzhiyun struct opp_table *opp_table;
1508*4882a593Smuzhiyun struct dev_pm_opp *opp;
1509*4882a593Smuzhiyun u32 vmin = 0;
1510*4882a593Smuzhiyun u8 index = 0;
1511*4882a593Smuzhiyun
1512*4882a593Smuzhiyun if (rockchip_nvmem_cell_read_u8(np, "mbist-vmin", &index))
1513*4882a593Smuzhiyun return;
1514*4882a593Smuzhiyun
1515*4882a593Smuzhiyun if (!index)
1516*4882a593Smuzhiyun return;
1517*4882a593Smuzhiyun
1518*4882a593Smuzhiyun if (of_property_read_u32_index(np, "mbist-vmin", index-1, &vmin))
1519*4882a593Smuzhiyun return;
1520*4882a593Smuzhiyun
1521*4882a593Smuzhiyun opp_table = dev_pm_opp_get_opp_table(dev);
1522*4882a593Smuzhiyun if (!opp_table)
1523*4882a593Smuzhiyun return;
1524*4882a593Smuzhiyun
1525*4882a593Smuzhiyun mutex_lock(&opp_table->lock);
1526*4882a593Smuzhiyun list_for_each_entry(opp, &opp_table->opp_list, node) {
1527*4882a593Smuzhiyun if (!opp->available)
1528*4882a593Smuzhiyun continue;
1529*4882a593Smuzhiyun if (opp->supplies->u_volt < vmin) {
1530*4882a593Smuzhiyun opp->supplies->u_volt = vmin;
1531*4882a593Smuzhiyun opp->supplies->u_volt_min = vmin;
1532*4882a593Smuzhiyun }
1533*4882a593Smuzhiyun }
1534*4882a593Smuzhiyun mutex_unlock(&opp_table->lock);
1535*4882a593Smuzhiyun }
1536*4882a593Smuzhiyun
rockchip_adjust_opp_by_otp(struct device * dev,struct device_node * np)1537*4882a593Smuzhiyun static void rockchip_adjust_opp_by_otp(struct device *dev,
1538*4882a593Smuzhiyun struct device_node *np)
1539*4882a593Smuzhiyun {
1540*4882a593Smuzhiyun struct dev_pm_opp *opp;
1541*4882a593Smuzhiyun struct opp_table *opp_table;
1542*4882a593Smuzhiyun struct otp_opp_info opp_info = {};
1543*4882a593Smuzhiyun int ret;
1544*4882a593Smuzhiyun
1545*4882a593Smuzhiyun ret = rockchip_nvmem_cell_read_common(np, "opp-info", &opp_info,
1546*4882a593Smuzhiyun sizeof(opp_info));
1547*4882a593Smuzhiyun if (ret || !opp_info.volt)
1548*4882a593Smuzhiyun return;
1549*4882a593Smuzhiyun
1550*4882a593Smuzhiyun dev_info(dev, "adjust opp-table by otp: min=%uM, max=%uM, volt=%umV\n",
1551*4882a593Smuzhiyun opp_info.min_freq, opp_info.max_freq, opp_info.volt);
1552*4882a593Smuzhiyun
1553*4882a593Smuzhiyun opp_table = dev_pm_opp_get_opp_table(dev);
1554*4882a593Smuzhiyun if (!opp_table)
1555*4882a593Smuzhiyun return;
1556*4882a593Smuzhiyun
1557*4882a593Smuzhiyun mutex_lock(&opp_table->lock);
1558*4882a593Smuzhiyun list_for_each_entry(opp, &opp_table->opp_list, node) {
1559*4882a593Smuzhiyun if (!opp->available)
1560*4882a593Smuzhiyun continue;
1561*4882a593Smuzhiyun if (opp->rate < opp_info.min_freq * 1000000)
1562*4882a593Smuzhiyun continue;
1563*4882a593Smuzhiyun if (opp->rate > opp_info.max_freq * 1000000)
1564*4882a593Smuzhiyun continue;
1565*4882a593Smuzhiyun
1566*4882a593Smuzhiyun opp->supplies[0].u_volt += opp_info.volt * 1000;
1567*4882a593Smuzhiyun if (opp->supplies[0].u_volt > opp->supplies[0].u_volt_max)
1568*4882a593Smuzhiyun opp->supplies[0].u_volt = opp->supplies[0].u_volt_max;
1569*4882a593Smuzhiyun if (opp_table->regulator_count > 1) {
1570*4882a593Smuzhiyun opp->supplies[1].u_volt += opp_info.volt * 1000;
1571*4882a593Smuzhiyun if (opp->supplies[1].u_volt > opp->supplies[1].u_volt_max)
1572*4882a593Smuzhiyun opp->supplies[1].u_volt = opp->supplies[1].u_volt_max;
1573*4882a593Smuzhiyun }
1574*4882a593Smuzhiyun }
1575*4882a593Smuzhiyun mutex_unlock(&opp_table->lock);
1576*4882a593Smuzhiyun
1577*4882a593Smuzhiyun dev_pm_opp_put_opp_table(opp_table);
1578*4882a593Smuzhiyun }
1579*4882a593Smuzhiyun
rockchip_adjust_opp_table(struct device * dev,unsigned long scale_rate)1580*4882a593Smuzhiyun static int rockchip_adjust_opp_table(struct device *dev,
1581*4882a593Smuzhiyun unsigned long scale_rate)
1582*4882a593Smuzhiyun {
1583*4882a593Smuzhiyun struct dev_pm_opp *opp;
1584*4882a593Smuzhiyun unsigned long rate;
1585*4882a593Smuzhiyun int i, count, ret = 0;
1586*4882a593Smuzhiyun
1587*4882a593Smuzhiyun count = dev_pm_opp_get_opp_count(dev);
1588*4882a593Smuzhiyun if (count <= 0) {
1589*4882a593Smuzhiyun ret = count ? count : -ENODATA;
1590*4882a593Smuzhiyun goto out;
1591*4882a593Smuzhiyun }
1592*4882a593Smuzhiyun
1593*4882a593Smuzhiyun for (i = 0, rate = 0; i < count; i++, rate++) {
1594*4882a593Smuzhiyun /* find next rate */
1595*4882a593Smuzhiyun opp = dev_pm_opp_find_freq_ceil(dev, &rate);
1596*4882a593Smuzhiyun if (IS_ERR(opp)) {
1597*4882a593Smuzhiyun ret = PTR_ERR(opp);
1598*4882a593Smuzhiyun goto out;
1599*4882a593Smuzhiyun }
1600*4882a593Smuzhiyun if (opp->rate > scale_rate)
1601*4882a593Smuzhiyun dev_pm_opp_disable(dev, opp->rate);
1602*4882a593Smuzhiyun dev_pm_opp_put(opp);
1603*4882a593Smuzhiyun }
1604*4882a593Smuzhiyun out:
1605*4882a593Smuzhiyun return ret;
1606*4882a593Smuzhiyun }
1607*4882a593Smuzhiyun
rockchip_adjust_power_scale(struct device * dev,int scale)1608*4882a593Smuzhiyun int rockchip_adjust_power_scale(struct device *dev, int scale)
1609*4882a593Smuzhiyun {
1610*4882a593Smuzhiyun struct device_node *np;
1611*4882a593Smuzhiyun struct clk *clk;
1612*4882a593Smuzhiyun unsigned long safe_rate = 0, max_rate = 0;
1613*4882a593Smuzhiyun int irdrop_scale = 0, opp_scale = 0;
1614*4882a593Smuzhiyun u32 target_scale, avs = 0, avs_scale = 0;
1615*4882a593Smuzhiyun long scale_rate = 0;
1616*4882a593Smuzhiyun int ret = 0;
1617*4882a593Smuzhiyun
1618*4882a593Smuzhiyun np = of_parse_phandle(dev->of_node, "operating-points-v2", 0);
1619*4882a593Smuzhiyun if (!np) {
1620*4882a593Smuzhiyun dev_warn(dev, "OPP-v2 not supported\n");
1621*4882a593Smuzhiyun return -ENOENT;
1622*4882a593Smuzhiyun }
1623*4882a593Smuzhiyun of_property_read_u32(np, "rockchip,avs-enable", &avs);
1624*4882a593Smuzhiyun of_property_read_u32(np, "rockchip,avs", &avs);
1625*4882a593Smuzhiyun of_property_read_u32(np, "rockchip,avs-scale", &avs_scale);
1626*4882a593Smuzhiyun rockchip_adjust_opp_by_otp(dev, np);
1627*4882a593Smuzhiyun rockchip_adjust_opp_by_mbist_vmin(dev, np);
1628*4882a593Smuzhiyun rockchip_adjust_opp_by_irdrop(dev, np, &safe_rate, &max_rate);
1629*4882a593Smuzhiyun
1630*4882a593Smuzhiyun dev_info(dev, "avs=%d\n", avs);
1631*4882a593Smuzhiyun clk = of_clk_get_by_name(np, NULL);
1632*4882a593Smuzhiyun if (IS_ERR(clk)) {
1633*4882a593Smuzhiyun if (!safe_rate)
1634*4882a593Smuzhiyun goto out_np;
1635*4882a593Smuzhiyun dev_dbg(dev, "Failed to get clk, safe_rate=%lu\n", safe_rate);
1636*4882a593Smuzhiyun ret = rockchip_adjust_opp_table(dev, safe_rate);
1637*4882a593Smuzhiyun if (ret)
1638*4882a593Smuzhiyun dev_err(dev, "Failed to adjust opp table\n");
1639*4882a593Smuzhiyun goto out_np;
1640*4882a593Smuzhiyun }
1641*4882a593Smuzhiyun
1642*4882a593Smuzhiyun if (safe_rate)
1643*4882a593Smuzhiyun irdrop_scale = rockchip_pll_clk_rate_to_scale(clk, safe_rate);
1644*4882a593Smuzhiyun if (max_rate)
1645*4882a593Smuzhiyun opp_scale = rockchip_pll_clk_rate_to_scale(clk, max_rate);
1646*4882a593Smuzhiyun target_scale = max(irdrop_scale, scale);
1647*4882a593Smuzhiyun if (target_scale <= 0)
1648*4882a593Smuzhiyun goto out_clk;
1649*4882a593Smuzhiyun dev_dbg(dev, "target_scale=%d, irdrop_scale=%d, scale=%d\n",
1650*4882a593Smuzhiyun target_scale, irdrop_scale, scale);
1651*4882a593Smuzhiyun
1652*4882a593Smuzhiyun if (avs == AVS_SCALING_RATE) {
1653*4882a593Smuzhiyun ret = rockchip_pll_clk_adaptive_scaling(clk, target_scale);
1654*4882a593Smuzhiyun if (ret)
1655*4882a593Smuzhiyun dev_err(dev, "Failed to adaptive scaling\n");
1656*4882a593Smuzhiyun if (opp_scale >= avs_scale)
1657*4882a593Smuzhiyun goto out_clk;
1658*4882a593Smuzhiyun dev_info(dev, "avs-scale=%d, opp-scale=%d\n", avs_scale,
1659*4882a593Smuzhiyun opp_scale);
1660*4882a593Smuzhiyun scale_rate = rockchip_pll_clk_scale_to_rate(clk, avs_scale);
1661*4882a593Smuzhiyun if (scale_rate <= 0) {
1662*4882a593Smuzhiyun dev_err(dev, "Failed to get avs scale rate, %d\n",
1663*4882a593Smuzhiyun avs_scale);
1664*4882a593Smuzhiyun goto out_clk;
1665*4882a593Smuzhiyun }
1666*4882a593Smuzhiyun dev_dbg(dev, "scale_rate=%lu\n", scale_rate);
1667*4882a593Smuzhiyun ret = rockchip_adjust_opp_table(dev, scale_rate);
1668*4882a593Smuzhiyun if (ret)
1669*4882a593Smuzhiyun dev_err(dev, "Failed to adjust opp table\n");
1670*4882a593Smuzhiyun } else if (avs == AVS_DELETE_OPP) {
1671*4882a593Smuzhiyun if (opp_scale >= target_scale)
1672*4882a593Smuzhiyun goto out_clk;
1673*4882a593Smuzhiyun dev_info(dev, "target_scale=%d, opp-scale=%d\n", target_scale,
1674*4882a593Smuzhiyun opp_scale);
1675*4882a593Smuzhiyun scale_rate = rockchip_pll_clk_scale_to_rate(clk, target_scale);
1676*4882a593Smuzhiyun if (scale_rate <= 0) {
1677*4882a593Smuzhiyun dev_err(dev, "Failed to get scale rate, %d\n",
1678*4882a593Smuzhiyun target_scale);
1679*4882a593Smuzhiyun goto out_clk;
1680*4882a593Smuzhiyun }
1681*4882a593Smuzhiyun dev_dbg(dev, "scale_rate=%lu\n", scale_rate);
1682*4882a593Smuzhiyun ret = rockchip_adjust_opp_table(dev, scale_rate);
1683*4882a593Smuzhiyun if (ret)
1684*4882a593Smuzhiyun dev_err(dev, "Failed to adjust opp table\n");
1685*4882a593Smuzhiyun }
1686*4882a593Smuzhiyun
1687*4882a593Smuzhiyun out_clk:
1688*4882a593Smuzhiyun clk_put(clk);
1689*4882a593Smuzhiyun out_np:
1690*4882a593Smuzhiyun of_node_put(np);
1691*4882a593Smuzhiyun
1692*4882a593Smuzhiyun return ret;
1693*4882a593Smuzhiyun }
1694*4882a593Smuzhiyun EXPORT_SYMBOL(rockchip_adjust_power_scale);
1695*4882a593Smuzhiyun
rockchip_get_read_margin(struct device * dev,struct rockchip_opp_info * opp_info,unsigned long volt,u32 * target_rm)1696*4882a593Smuzhiyun int rockchip_get_read_margin(struct device *dev,
1697*4882a593Smuzhiyun struct rockchip_opp_info *opp_info,
1698*4882a593Smuzhiyun unsigned long volt, u32 *target_rm)
1699*4882a593Smuzhiyun {
1700*4882a593Smuzhiyun int i;
1701*4882a593Smuzhiyun
1702*4882a593Smuzhiyun if (!opp_info || !opp_info->volt_rm_tbl)
1703*4882a593Smuzhiyun return 0;
1704*4882a593Smuzhiyun
1705*4882a593Smuzhiyun for (i = 0; opp_info->volt_rm_tbl[i].rm != VOLT_RM_TABLE_END; i++) {
1706*4882a593Smuzhiyun if (volt >= opp_info->volt_rm_tbl[i].volt) {
1707*4882a593Smuzhiyun opp_info->target_rm = opp_info->volt_rm_tbl[i].rm;
1708*4882a593Smuzhiyun break;
1709*4882a593Smuzhiyun }
1710*4882a593Smuzhiyun }
1711*4882a593Smuzhiyun *target_rm = opp_info->target_rm;
1712*4882a593Smuzhiyun
1713*4882a593Smuzhiyun return 0;
1714*4882a593Smuzhiyun }
1715*4882a593Smuzhiyun EXPORT_SYMBOL(rockchip_get_read_margin);
1716*4882a593Smuzhiyun
rockchip_set_read_margin(struct device * dev,struct rockchip_opp_info * opp_info,u32 rm,bool is_set_rm)1717*4882a593Smuzhiyun int rockchip_set_read_margin(struct device *dev,
1718*4882a593Smuzhiyun struct rockchip_opp_info *opp_info, u32 rm,
1719*4882a593Smuzhiyun bool is_set_rm)
1720*4882a593Smuzhiyun {
1721*4882a593Smuzhiyun if (!is_set_rm || !opp_info)
1722*4882a593Smuzhiyun return 0;
1723*4882a593Smuzhiyun if (!opp_info || !opp_info->volt_rm_tbl)
1724*4882a593Smuzhiyun return 0;
1725*4882a593Smuzhiyun if (!opp_info->data || !opp_info->data->set_read_margin)
1726*4882a593Smuzhiyun return 0;
1727*4882a593Smuzhiyun if (rm == opp_info->current_rm)
1728*4882a593Smuzhiyun return 0;
1729*4882a593Smuzhiyun
1730*4882a593Smuzhiyun return opp_info->data->set_read_margin(dev, opp_info, rm);
1731*4882a593Smuzhiyun }
1732*4882a593Smuzhiyun EXPORT_SYMBOL(rockchip_set_read_margin);
1733*4882a593Smuzhiyun
rockchip_init_read_margin(struct device * dev,struct rockchip_opp_info * opp_info,char * reg_name)1734*4882a593Smuzhiyun int rockchip_init_read_margin(struct device *dev,
1735*4882a593Smuzhiyun struct rockchip_opp_info *opp_info,
1736*4882a593Smuzhiyun char *reg_name)
1737*4882a593Smuzhiyun {
1738*4882a593Smuzhiyun struct clk *clk;
1739*4882a593Smuzhiyun struct regulator *reg;
1740*4882a593Smuzhiyun unsigned long cur_rate;
1741*4882a593Smuzhiyun int cur_volt, ret = 0;
1742*4882a593Smuzhiyun u32 target_rm = UINT_MAX;
1743*4882a593Smuzhiyun
1744*4882a593Smuzhiyun reg = regulator_get_optional(dev, reg_name);
1745*4882a593Smuzhiyun if (IS_ERR(reg)) {
1746*4882a593Smuzhiyun ret = PTR_ERR(reg);
1747*4882a593Smuzhiyun if (ret != -EPROBE_DEFER)
1748*4882a593Smuzhiyun dev_err(dev, "%s: no regulator (%s) found: %d\n",
1749*4882a593Smuzhiyun __func__, reg_name, ret);
1750*4882a593Smuzhiyun return ret;
1751*4882a593Smuzhiyun }
1752*4882a593Smuzhiyun cur_volt = regulator_get_voltage(reg);
1753*4882a593Smuzhiyun if (cur_volt < 0) {
1754*4882a593Smuzhiyun ret = cur_volt;
1755*4882a593Smuzhiyun if (ret != -EPROBE_DEFER)
1756*4882a593Smuzhiyun dev_err(dev, "%s: failed to get (%s) volt: %d\n",
1757*4882a593Smuzhiyun __func__, reg_name, ret);
1758*4882a593Smuzhiyun goto out;
1759*4882a593Smuzhiyun }
1760*4882a593Smuzhiyun
1761*4882a593Smuzhiyun clk = clk_get(dev, NULL);
1762*4882a593Smuzhiyun if (IS_ERR(clk)) {
1763*4882a593Smuzhiyun ret = PTR_ERR(clk);
1764*4882a593Smuzhiyun dev_err(dev, "%s: failed to get clk: %d\n", __func__, ret);
1765*4882a593Smuzhiyun goto out;
1766*4882a593Smuzhiyun }
1767*4882a593Smuzhiyun cur_rate = clk_get_rate(clk);
1768*4882a593Smuzhiyun
1769*4882a593Smuzhiyun rockchip_get_read_margin(dev, opp_info, cur_volt, &target_rm);
1770*4882a593Smuzhiyun dev_dbg(dev, "cur_rate=%lu, threshold=%lu, cur_volt=%d, target_rm=%d\n",
1771*4882a593Smuzhiyun cur_rate, opp_info->intermediate_threshold_freq,
1772*4882a593Smuzhiyun cur_volt, target_rm);
1773*4882a593Smuzhiyun if (opp_info->intermediate_threshold_freq &&
1774*4882a593Smuzhiyun cur_rate > opp_info->intermediate_threshold_freq) {
1775*4882a593Smuzhiyun clk_set_rate(clk, opp_info->intermediate_threshold_freq);
1776*4882a593Smuzhiyun rockchip_set_read_margin(dev, opp_info, target_rm, true);
1777*4882a593Smuzhiyun clk_set_rate(clk, cur_rate);
1778*4882a593Smuzhiyun } else {
1779*4882a593Smuzhiyun rockchip_set_read_margin(dev, opp_info, target_rm, true);
1780*4882a593Smuzhiyun }
1781*4882a593Smuzhiyun
1782*4882a593Smuzhiyun clk_put(clk);
1783*4882a593Smuzhiyun out:
1784*4882a593Smuzhiyun regulator_put(reg);
1785*4882a593Smuzhiyun
1786*4882a593Smuzhiyun return ret;
1787*4882a593Smuzhiyun }
1788*4882a593Smuzhiyun EXPORT_SYMBOL(rockchip_init_read_margin);
1789*4882a593Smuzhiyun
rockchip_set_intermediate_rate(struct device * dev,struct rockchip_opp_info * opp_info,struct clk * clk,unsigned long old_freq,unsigned long new_freq,bool is_scaling_up,bool is_set_clk)1790*4882a593Smuzhiyun int rockchip_set_intermediate_rate(struct device *dev,
1791*4882a593Smuzhiyun struct rockchip_opp_info *opp_info,
1792*4882a593Smuzhiyun struct clk *clk, unsigned long old_freq,
1793*4882a593Smuzhiyun unsigned long new_freq, bool is_scaling_up,
1794*4882a593Smuzhiyun bool is_set_clk)
1795*4882a593Smuzhiyun {
1796*4882a593Smuzhiyun if (!is_set_clk)
1797*4882a593Smuzhiyun return 0;
1798*4882a593Smuzhiyun if (!opp_info || !opp_info->volt_rm_tbl)
1799*4882a593Smuzhiyun return 0;
1800*4882a593Smuzhiyun if (!opp_info->data || !opp_info->data->set_read_margin)
1801*4882a593Smuzhiyun return 0;
1802*4882a593Smuzhiyun if (opp_info->target_rm == opp_info->current_rm)
1803*4882a593Smuzhiyun return 0;
1804*4882a593Smuzhiyun /*
1805*4882a593Smuzhiyun * There is no need to set intermediate rate if the new voltage
1806*4882a593Smuzhiyun * and the current voltage are high voltage.
1807*4882a593Smuzhiyun */
1808*4882a593Smuzhiyun if ((opp_info->target_rm < opp_info->low_rm) &&
1809*4882a593Smuzhiyun (opp_info->current_rm < opp_info->low_rm))
1810*4882a593Smuzhiyun return 0;
1811*4882a593Smuzhiyun
1812*4882a593Smuzhiyun if (is_scaling_up) {
1813*4882a593Smuzhiyun /*
1814*4882a593Smuzhiyun * If scaling up and the current frequency is less than
1815*4882a593Smuzhiyun * or equal to intermediate threshold frequency, there is
1816*4882a593Smuzhiyun * no need to set intermediate rate.
1817*4882a593Smuzhiyun */
1818*4882a593Smuzhiyun if (opp_info->intermediate_threshold_freq &&
1819*4882a593Smuzhiyun old_freq <= opp_info->intermediate_threshold_freq)
1820*4882a593Smuzhiyun return 0;
1821*4882a593Smuzhiyun return clk_set_rate(clk, new_freq | OPP_SCALING_UP_INTER);
1822*4882a593Smuzhiyun }
1823*4882a593Smuzhiyun /*
1824*4882a593Smuzhiyun * If scaling down and the new frequency is less than or equal to
1825*4882a593Smuzhiyun * intermediate threshold frequency , there is no need to set
1826*4882a593Smuzhiyun * intermediate rate and set the new frequency directly.
1827*4882a593Smuzhiyun */
1828*4882a593Smuzhiyun if (opp_info->intermediate_threshold_freq &&
1829*4882a593Smuzhiyun new_freq <= opp_info->intermediate_threshold_freq)
1830*4882a593Smuzhiyun return clk_set_rate(clk, new_freq);
1831*4882a593Smuzhiyun
1832*4882a593Smuzhiyun return clk_set_rate(clk, new_freq | OPP_SCALING_DOWN_INTER);
1833*4882a593Smuzhiyun }
1834*4882a593Smuzhiyun EXPORT_SYMBOL(rockchip_set_intermediate_rate);
1835*4882a593Smuzhiyun
rockchip_init_opp_table(struct device * dev,struct rockchip_opp_info * info,char * lkg_name,char * reg_name)1836*4882a593Smuzhiyun int rockchip_init_opp_table(struct device *dev, struct rockchip_opp_info *info,
1837*4882a593Smuzhiyun char *lkg_name, char *reg_name)
1838*4882a593Smuzhiyun {
1839*4882a593Smuzhiyun struct device_node *np;
1840*4882a593Smuzhiyun int bin = -EINVAL, process = -EINVAL;
1841*4882a593Smuzhiyun int scale = 0, volt_sel = -EINVAL;
1842*4882a593Smuzhiyun int ret = 0, num_clks = 0, i;
1843*4882a593Smuzhiyun u32 freq;
1844*4882a593Smuzhiyun
1845*4882a593Smuzhiyun /* Get OPP descriptor node */
1846*4882a593Smuzhiyun np = of_parse_phandle(dev->of_node, "operating-points-v2", 0);
1847*4882a593Smuzhiyun if (!np) {
1848*4882a593Smuzhiyun dev_dbg(dev, "Failed to find operating-points-v2\n");
1849*4882a593Smuzhiyun return -ENOENT;
1850*4882a593Smuzhiyun }
1851*4882a593Smuzhiyun if (!info)
1852*4882a593Smuzhiyun goto next;
1853*4882a593Smuzhiyun info->dev = dev;
1854*4882a593Smuzhiyun
1855*4882a593Smuzhiyun num_clks = of_clk_get_parent_count(np);
1856*4882a593Smuzhiyun if (num_clks > 0) {
1857*4882a593Smuzhiyun info->clks = devm_kcalloc(dev, num_clks, sizeof(*info->clks),
1858*4882a593Smuzhiyun GFP_KERNEL);
1859*4882a593Smuzhiyun if (!info->clks) {
1860*4882a593Smuzhiyun ret = -ENOMEM;
1861*4882a593Smuzhiyun goto out;
1862*4882a593Smuzhiyun }
1863*4882a593Smuzhiyun for (i = 0; i < num_clks; i++) {
1864*4882a593Smuzhiyun info->clks[i].clk = of_clk_get(np, i);
1865*4882a593Smuzhiyun if (IS_ERR(info->clks[i].clk)) {
1866*4882a593Smuzhiyun ret = PTR_ERR(info->clks[i].clk);
1867*4882a593Smuzhiyun dev_err(dev, "%s: failed to get clk %d\n",
1868*4882a593Smuzhiyun np->name, i);
1869*4882a593Smuzhiyun goto out;
1870*4882a593Smuzhiyun }
1871*4882a593Smuzhiyun }
1872*4882a593Smuzhiyun info->num_clks = num_clks;
1873*4882a593Smuzhiyun ret = clk_bulk_prepare_enable(info->num_clks, info->clks);
1874*4882a593Smuzhiyun if (ret) {
1875*4882a593Smuzhiyun dev_err(dev, "failed to enable opp clks\n");
1876*4882a593Smuzhiyun goto out;
1877*4882a593Smuzhiyun }
1878*4882a593Smuzhiyun }
1879*4882a593Smuzhiyun if (info->data && info->data->set_read_margin) {
1880*4882a593Smuzhiyun info->current_rm = UINT_MAX;
1881*4882a593Smuzhiyun info->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
1882*4882a593Smuzhiyun if (IS_ERR(info->grf))
1883*4882a593Smuzhiyun info->grf = NULL;
1884*4882a593Smuzhiyun rockchip_get_volt_rm_table(dev, np, "volt-mem-read-margin",
1885*4882a593Smuzhiyun &info->volt_rm_tbl);
1886*4882a593Smuzhiyun of_property_read_u32(np, "low-volt-mem-read-margin",
1887*4882a593Smuzhiyun &info->low_rm);
1888*4882a593Smuzhiyun if (!of_property_read_u32(np, "intermediate-threshold-freq",
1889*4882a593Smuzhiyun &freq))
1890*4882a593Smuzhiyun info->intermediate_threshold_freq = freq * 1000;
1891*4882a593Smuzhiyun rockchip_init_read_margin(dev, info, reg_name);
1892*4882a593Smuzhiyun }
1893*4882a593Smuzhiyun if (info->data && info->data->get_soc_info)
1894*4882a593Smuzhiyun info->data->get_soc_info(dev, np, &bin, &process);
1895*4882a593Smuzhiyun
1896*4882a593Smuzhiyun next:
1897*4882a593Smuzhiyun rockchip_get_soc_info(dev, np, &bin, &process);
1898*4882a593Smuzhiyun rockchip_get_scale_volt_sel(dev, lkg_name, reg_name, bin, process,
1899*4882a593Smuzhiyun &scale, &volt_sel);
1900*4882a593Smuzhiyun if (info && info->data && info->data->set_soc_info)
1901*4882a593Smuzhiyun info->data->set_soc_info(dev, np, bin, process, volt_sel);
1902*4882a593Smuzhiyun rockchip_set_opp_prop_name(dev, process, volt_sel);
1903*4882a593Smuzhiyun rockchip_set_opp_supported_hw(dev, np, bin, volt_sel);
1904*4882a593Smuzhiyun ret = dev_pm_opp_of_add_table(dev);
1905*4882a593Smuzhiyun if (ret) {
1906*4882a593Smuzhiyun dev_err(dev, "Invalid operating-points in device tree.\n");
1907*4882a593Smuzhiyun goto dis_opp_clk;
1908*4882a593Smuzhiyun }
1909*4882a593Smuzhiyun rockchip_adjust_power_scale(dev, scale);
1910*4882a593Smuzhiyun rockchip_pvtpll_calibrate_opp(info);
1911*4882a593Smuzhiyun rockchip_pvtpll_add_length(info);
1912*4882a593Smuzhiyun
1913*4882a593Smuzhiyun dis_opp_clk:
1914*4882a593Smuzhiyun if (info && info->clks)
1915*4882a593Smuzhiyun clk_bulk_disable_unprepare(info->num_clks, info->clks);
1916*4882a593Smuzhiyun out:
1917*4882a593Smuzhiyun of_node_put(np);
1918*4882a593Smuzhiyun
1919*4882a593Smuzhiyun return ret;
1920*4882a593Smuzhiyun }
1921*4882a593Smuzhiyun EXPORT_SYMBOL(rockchip_init_opp_table);
1922*4882a593Smuzhiyun
1923*4882a593Smuzhiyun MODULE_DESCRIPTION("ROCKCHIP OPP Select");
1924*4882a593Smuzhiyun MODULE_AUTHOR("Finley Xiao <finley.xiao@rock-chips.com>, Liang Chen <cl@rock-chips.com>");
1925*4882a593Smuzhiyun MODULE_LICENSE("GPL");
1926