xref: /OK3568_Linux_fs/kernel/drivers/cpufreq/rockchip-cpufreq.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Rockchip CPUFreq Driver
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * Copyright (C) 2017 Fuzhou Rockchip Electronics Co., Ltd
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * This program is free software; you can redistribute it and/or modify
7*4882a593Smuzhiyun  * it under the terms of the GNU General Public License version 2 as
8*4882a593Smuzhiyun  * published by the Free Software Foundation.
9*4882a593Smuzhiyun  *
10*4882a593Smuzhiyun  * This program is distributed "as is" WITHOUT ANY WARRANTY of any
11*4882a593Smuzhiyun  * kind, whether express or implied; without even the implied warranty
12*4882a593Smuzhiyun  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13*4882a593Smuzhiyun  * GNU General Public License for more details.
14*4882a593Smuzhiyun  */
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun #include <linux/clk.h>
17*4882a593Smuzhiyun #include <linux/cpu.h>
18*4882a593Smuzhiyun #include <linux/cpufreq.h>
19*4882a593Smuzhiyun #include <linux/cpuidle.h>
20*4882a593Smuzhiyun #include <linux/err.h>
21*4882a593Smuzhiyun #include <linux/init.h>
22*4882a593Smuzhiyun #include <linux/kernel.h>
23*4882a593Smuzhiyun #include <linux/mfd/syscon.h>
24*4882a593Smuzhiyun #include <linux/module.h>
25*4882a593Smuzhiyun #include <linux/nvmem-consumer.h>
26*4882a593Smuzhiyun #include <linux/of.h>
27*4882a593Smuzhiyun #include <linux/of_address.h>
28*4882a593Smuzhiyun #include <linux/platform_device.h>
29*4882a593Smuzhiyun #include <linux/pm_opp.h>
30*4882a593Smuzhiyun #include <linux/pm_qos.h>
31*4882a593Smuzhiyun #include <linux/slab.h>
32*4882a593Smuzhiyun #include <linux/regmap.h>
33*4882a593Smuzhiyun #include <linux/regulator/consumer.h>
34*4882a593Smuzhiyun #include <linux/rockchip/cpu.h>
35*4882a593Smuzhiyun #include <soc/rockchip/rockchip_opp_select.h>
36*4882a593Smuzhiyun #include <soc/rockchip/rockchip_system_monitor.h>
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun #include "cpufreq-dt.h"
39*4882a593Smuzhiyun #include "rockchip-cpufreq.h"
40*4882a593Smuzhiyun 
41*4882a593Smuzhiyun struct cluster_info {
42*4882a593Smuzhiyun 	struct list_head list_head;
43*4882a593Smuzhiyun 	struct monitor_dev_info *mdev_info;
44*4882a593Smuzhiyun 	struct rockchip_opp_info opp_info;
45*4882a593Smuzhiyun 	struct freq_qos_request dsu_qos_req;
46*4882a593Smuzhiyun 	cpumask_t cpus;
47*4882a593Smuzhiyun 	unsigned int idle_threshold_freq;
48*4882a593Smuzhiyun 	int scale;
49*4882a593Smuzhiyun 	bool is_idle_disabled;
50*4882a593Smuzhiyun 	bool is_opp_shared_dsu;
51*4882a593Smuzhiyun 	unsigned int regulator_count;
52*4882a593Smuzhiyun 	unsigned long rate;
53*4882a593Smuzhiyun 	unsigned long volt, mem_volt;
54*4882a593Smuzhiyun };
55*4882a593Smuzhiyun static LIST_HEAD(cluster_info_list);
56*4882a593Smuzhiyun 
px30_get_soc_info(struct device * dev,struct device_node * np,int * bin,int * process)57*4882a593Smuzhiyun static int px30_get_soc_info(struct device *dev, struct device_node *np,
58*4882a593Smuzhiyun 			     int *bin, int *process)
59*4882a593Smuzhiyun {
60*4882a593Smuzhiyun 	int ret = 0;
61*4882a593Smuzhiyun 	u8 value = 0;
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun 	if (!bin)
64*4882a593Smuzhiyun 		return 0;
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun 	if (of_property_match_string(np, "nvmem-cell-names",
67*4882a593Smuzhiyun 				     "performance") >= 0) {
68*4882a593Smuzhiyun 		ret = rockchip_nvmem_cell_read_u8(np, "performance", &value);
69*4882a593Smuzhiyun 		if (ret) {
70*4882a593Smuzhiyun 			dev_err(dev, "Failed to get soc performance value\n");
71*4882a593Smuzhiyun 			return ret;
72*4882a593Smuzhiyun 		}
73*4882a593Smuzhiyun 		*bin = value;
74*4882a593Smuzhiyun 	}
75*4882a593Smuzhiyun 	if (*bin >= 0)
76*4882a593Smuzhiyun 		dev_info(dev, "bin=%d\n", *bin);
77*4882a593Smuzhiyun 
78*4882a593Smuzhiyun 	return ret;
79*4882a593Smuzhiyun }
80*4882a593Smuzhiyun 
rk3288_get_soc_info(struct device * dev,struct device_node * np,int * bin,int * process)81*4882a593Smuzhiyun static int rk3288_get_soc_info(struct device *dev, struct device_node *np,
82*4882a593Smuzhiyun 			       int *bin, int *process)
83*4882a593Smuzhiyun {
84*4882a593Smuzhiyun 	int ret = 0;
85*4882a593Smuzhiyun 	u8 value = 0;
86*4882a593Smuzhiyun 	char *name;
87*4882a593Smuzhiyun 
88*4882a593Smuzhiyun 	if (!bin)
89*4882a593Smuzhiyun 		goto next;
90*4882a593Smuzhiyun 	if (of_property_match_string(np, "nvmem-cell-names", "special") >= 0) {
91*4882a593Smuzhiyun 		ret = rockchip_nvmem_cell_read_u8(np, "special", &value);
92*4882a593Smuzhiyun 		if (ret) {
93*4882a593Smuzhiyun 			dev_err(dev, "Failed to get soc special value\n");
94*4882a593Smuzhiyun 			goto out;
95*4882a593Smuzhiyun 		}
96*4882a593Smuzhiyun 		if (value == 0xc)
97*4882a593Smuzhiyun 			*bin = 0;
98*4882a593Smuzhiyun 		else
99*4882a593Smuzhiyun 			*bin = 1;
100*4882a593Smuzhiyun 	}
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun 	if (soc_is_rk3288w())
103*4882a593Smuzhiyun 		name = "performance-w";
104*4882a593Smuzhiyun 	else
105*4882a593Smuzhiyun 		name = "performance";
106*4882a593Smuzhiyun 
107*4882a593Smuzhiyun 	if (of_property_match_string(np, "nvmem-cell-names", name) >= 0) {
108*4882a593Smuzhiyun 		ret = rockchip_nvmem_cell_read_u8(np, name, &value);
109*4882a593Smuzhiyun 		if (ret) {
110*4882a593Smuzhiyun 			dev_err(dev, "Failed to get soc performance value\n");
111*4882a593Smuzhiyun 			goto out;
112*4882a593Smuzhiyun 		}
113*4882a593Smuzhiyun 		if (value & 0x2)
114*4882a593Smuzhiyun 			*bin = 3;
115*4882a593Smuzhiyun 		else if (value & 0x01)
116*4882a593Smuzhiyun 			*bin = 2;
117*4882a593Smuzhiyun 	}
118*4882a593Smuzhiyun 	if (*bin >= 0)
119*4882a593Smuzhiyun 		dev_info(dev, "bin=%d\n", *bin);
120*4882a593Smuzhiyun 
121*4882a593Smuzhiyun next:
122*4882a593Smuzhiyun 	if (!process)
123*4882a593Smuzhiyun 		goto out;
124*4882a593Smuzhiyun 	if (of_property_match_string(np, "nvmem-cell-names",
125*4882a593Smuzhiyun 				     "process") >= 0) {
126*4882a593Smuzhiyun 		ret = rockchip_nvmem_cell_read_u8(np, "process", &value);
127*4882a593Smuzhiyun 		if (ret) {
128*4882a593Smuzhiyun 			dev_err(dev, "Failed to get soc process version\n");
129*4882a593Smuzhiyun 			goto out;
130*4882a593Smuzhiyun 		}
131*4882a593Smuzhiyun 		if (soc_is_rk3288() && (value == 0 || value == 1))
132*4882a593Smuzhiyun 			*process = 0;
133*4882a593Smuzhiyun 	}
134*4882a593Smuzhiyun 	if (*process >= 0)
135*4882a593Smuzhiyun 		dev_info(dev, "process=%d\n", *process);
136*4882a593Smuzhiyun 
137*4882a593Smuzhiyun out:
138*4882a593Smuzhiyun 	return ret;
139*4882a593Smuzhiyun }
140*4882a593Smuzhiyun 
rk3399_get_soc_info(struct device * dev,struct device_node * np,int * bin,int * process)141*4882a593Smuzhiyun static int rk3399_get_soc_info(struct device *dev, struct device_node *np,
142*4882a593Smuzhiyun 			       int *bin, int *process)
143*4882a593Smuzhiyun {
144*4882a593Smuzhiyun 	int ret = 0;
145*4882a593Smuzhiyun 	u8 value = 0;
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun 	if (!bin)
148*4882a593Smuzhiyun 		return 0;
149*4882a593Smuzhiyun 
150*4882a593Smuzhiyun 	if (of_property_match_string(np, "nvmem-cell-names",
151*4882a593Smuzhiyun 				     "specification_serial_number") >= 0) {
152*4882a593Smuzhiyun 		ret = rockchip_nvmem_cell_read_u8(np,
153*4882a593Smuzhiyun 						  "specification_serial_number",
154*4882a593Smuzhiyun 						  &value);
155*4882a593Smuzhiyun 		if (ret) {
156*4882a593Smuzhiyun 			dev_err(dev,
157*4882a593Smuzhiyun 				"Failed to get specification_serial_number\n");
158*4882a593Smuzhiyun 			goto out;
159*4882a593Smuzhiyun 		}
160*4882a593Smuzhiyun 
161*4882a593Smuzhiyun 		if (value == 0xb) {
162*4882a593Smuzhiyun 			*bin = 0;
163*4882a593Smuzhiyun 		} else if (value == 0x1) {
164*4882a593Smuzhiyun 			if (of_property_match_string(np, "nvmem-cell-names",
165*4882a593Smuzhiyun 						     "customer_demand") >= 0) {
166*4882a593Smuzhiyun 				ret = rockchip_nvmem_cell_read_u8(np,
167*4882a593Smuzhiyun 								  "customer_demand",
168*4882a593Smuzhiyun 								  &value);
169*4882a593Smuzhiyun 				if (ret) {
170*4882a593Smuzhiyun 					dev_err(dev, "Failed to get customer_demand\n");
171*4882a593Smuzhiyun 					goto out;
172*4882a593Smuzhiyun 				}
173*4882a593Smuzhiyun 				if (value == 0x0)
174*4882a593Smuzhiyun 					*bin = 0;
175*4882a593Smuzhiyun 				else
176*4882a593Smuzhiyun 					*bin = 1;
177*4882a593Smuzhiyun 			}
178*4882a593Smuzhiyun 		} else if (value == 0x10) {
179*4882a593Smuzhiyun 			*bin = 1;
180*4882a593Smuzhiyun 		}
181*4882a593Smuzhiyun 	}
182*4882a593Smuzhiyun 
183*4882a593Smuzhiyun out:
184*4882a593Smuzhiyun 	if (*bin >= 0)
185*4882a593Smuzhiyun 		dev_info(dev, "bin=%d\n", *bin);
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun 	return ret;
188*4882a593Smuzhiyun }
189*4882a593Smuzhiyun 
rk3588_get_soc_info(struct device * dev,struct device_node * np,int * bin,int * process)190*4882a593Smuzhiyun static int rk3588_get_soc_info(struct device *dev, struct device_node *np,
191*4882a593Smuzhiyun 			       int *bin, int *process)
192*4882a593Smuzhiyun {
193*4882a593Smuzhiyun 	int ret = 0;
194*4882a593Smuzhiyun 	u8 value = 0;
195*4882a593Smuzhiyun 
196*4882a593Smuzhiyun 	if (!bin)
197*4882a593Smuzhiyun 		return 0;
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun 	if (of_property_match_string(np, "nvmem-cell-names",
200*4882a593Smuzhiyun 				     "specification_serial_number") >= 0) {
201*4882a593Smuzhiyun 		ret = rockchip_nvmem_cell_read_u8(np,
202*4882a593Smuzhiyun 						  "specification_serial_number",
203*4882a593Smuzhiyun 						  &value);
204*4882a593Smuzhiyun 		if (ret) {
205*4882a593Smuzhiyun 			dev_err(dev,
206*4882a593Smuzhiyun 				"Failed to get specification_serial_number\n");
207*4882a593Smuzhiyun 			return ret;
208*4882a593Smuzhiyun 		}
209*4882a593Smuzhiyun 		/* RK3588M */
210*4882a593Smuzhiyun 		if (value == 0xd)
211*4882a593Smuzhiyun 			*bin = 1;
212*4882a593Smuzhiyun 		/* RK3588J */
213*4882a593Smuzhiyun 		else if (value == 0xa)
214*4882a593Smuzhiyun 			*bin = 2;
215*4882a593Smuzhiyun 	}
216*4882a593Smuzhiyun 	if (*bin < 0)
217*4882a593Smuzhiyun 		*bin = 0;
218*4882a593Smuzhiyun 	dev_info(dev, "bin=%d\n", *bin);
219*4882a593Smuzhiyun 
220*4882a593Smuzhiyun 	return ret;
221*4882a593Smuzhiyun }
222*4882a593Smuzhiyun 
rk3588_change_length(struct device * dev,struct device_node * np,int bin,int process,int volt_sel)223*4882a593Smuzhiyun static int rk3588_change_length(struct device *dev, struct device_node *np,
224*4882a593Smuzhiyun 				int bin, int process, int volt_sel)
225*4882a593Smuzhiyun {
226*4882a593Smuzhiyun 	struct clk *clk;
227*4882a593Smuzhiyun 	unsigned long old_rate;
228*4882a593Smuzhiyun 	unsigned int low_len_sel;
229*4882a593Smuzhiyun 	u32 opp_flag = 0;
230*4882a593Smuzhiyun 	int ret = 0;
231*4882a593Smuzhiyun 
232*4882a593Smuzhiyun 	clk = clk_get(dev, NULL);
233*4882a593Smuzhiyun 	if (IS_ERR(clk)) {
234*4882a593Smuzhiyun 		dev_warn(dev, "failed to get cpu clk\n");
235*4882a593Smuzhiyun 		return PTR_ERR(clk);
236*4882a593Smuzhiyun 	}
237*4882a593Smuzhiyun 
238*4882a593Smuzhiyun 	/* RK3588 low speed grade should change to low length */
239*4882a593Smuzhiyun 	if (of_property_read_u32(np, "rockchip,pvtm-low-len-sel",
240*4882a593Smuzhiyun 				 &low_len_sel))
241*4882a593Smuzhiyun 		goto out;
242*4882a593Smuzhiyun 	if (volt_sel > low_len_sel)
243*4882a593Smuzhiyun 		goto out;
244*4882a593Smuzhiyun 	opp_flag = OPP_LENGTH_LOW;
245*4882a593Smuzhiyun 
246*4882a593Smuzhiyun 	old_rate = clk_get_rate(clk);
247*4882a593Smuzhiyun 	ret = clk_set_rate(clk, old_rate | opp_flag);
248*4882a593Smuzhiyun 	if (ret) {
249*4882a593Smuzhiyun 		dev_err(dev, "failed to change length\n");
250*4882a593Smuzhiyun 		goto out;
251*4882a593Smuzhiyun 	}
252*4882a593Smuzhiyun 	clk_set_rate(clk, old_rate);
253*4882a593Smuzhiyun out:
254*4882a593Smuzhiyun 	clk_put(clk);
255*4882a593Smuzhiyun 
256*4882a593Smuzhiyun 	return ret;
257*4882a593Smuzhiyun }
258*4882a593Smuzhiyun 
rk3588_set_supported_hw(struct device * dev,struct device_node * np,int bin,int process,int volt_sel)259*4882a593Smuzhiyun static int rk3588_set_supported_hw(struct device *dev, struct device_node *np,
260*4882a593Smuzhiyun 				   int bin, int process, int volt_sel)
261*4882a593Smuzhiyun {
262*4882a593Smuzhiyun 	struct opp_table *opp_table;
263*4882a593Smuzhiyun 	u32 supported_hw[2];
264*4882a593Smuzhiyun 
265*4882a593Smuzhiyun 	if (!of_property_read_bool(np, "rockchip,supported-hw"))
266*4882a593Smuzhiyun 		return 0;
267*4882a593Smuzhiyun 
268*4882a593Smuzhiyun 	/* SoC Version */
269*4882a593Smuzhiyun 	supported_hw[0] = BIT(bin);
270*4882a593Smuzhiyun 	/* Speed Grade */
271*4882a593Smuzhiyun 	supported_hw[1] = BIT(volt_sel);
272*4882a593Smuzhiyun 	opp_table = dev_pm_opp_set_supported_hw(dev, supported_hw, 2);
273*4882a593Smuzhiyun 	if (IS_ERR(opp_table)) {
274*4882a593Smuzhiyun 		dev_err(dev, "failed to set supported opp\n");
275*4882a593Smuzhiyun 		return PTR_ERR(opp_table);
276*4882a593Smuzhiyun 	}
277*4882a593Smuzhiyun 
278*4882a593Smuzhiyun 	return 0;
279*4882a593Smuzhiyun }
280*4882a593Smuzhiyun 
rk3588_set_soc_info(struct device * dev,struct device_node * np,int bin,int process,int volt_sel)281*4882a593Smuzhiyun static int rk3588_set_soc_info(struct device *dev, struct device_node *np,
282*4882a593Smuzhiyun 			       int bin, int process, int volt_sel)
283*4882a593Smuzhiyun {
284*4882a593Smuzhiyun 	if (volt_sel < 0)
285*4882a593Smuzhiyun 		return 0;
286*4882a593Smuzhiyun 	if (bin < 0)
287*4882a593Smuzhiyun 		bin = 0;
288*4882a593Smuzhiyun 
289*4882a593Smuzhiyun 	rk3588_change_length(dev, np, bin, process, volt_sel);
290*4882a593Smuzhiyun 	rk3588_set_supported_hw(dev, np, bin, process, volt_sel);
291*4882a593Smuzhiyun 
292*4882a593Smuzhiyun 	return 0;
293*4882a593Smuzhiyun }
294*4882a593Smuzhiyun 
rk3588_cpu_set_read_margin(struct device * dev,struct rockchip_opp_info * opp_info,u32 rm)295*4882a593Smuzhiyun static int rk3588_cpu_set_read_margin(struct device *dev,
296*4882a593Smuzhiyun 				      struct rockchip_opp_info *opp_info,
297*4882a593Smuzhiyun 				      u32 rm)
298*4882a593Smuzhiyun {
299*4882a593Smuzhiyun 	if (!opp_info->volt_rm_tbl)
300*4882a593Smuzhiyun 		return 0;
301*4882a593Smuzhiyun 	if (rm == opp_info->current_rm || rm  == UINT_MAX)
302*4882a593Smuzhiyun 		return 0;
303*4882a593Smuzhiyun 
304*4882a593Smuzhiyun 	dev_dbg(dev, "set rm to %d\n", rm);
305*4882a593Smuzhiyun 	if (opp_info->grf) {
306*4882a593Smuzhiyun 		regmap_write(opp_info->grf, 0x20, 0x001c0000 | (rm << 2));
307*4882a593Smuzhiyun 		regmap_write(opp_info->grf, 0x28, 0x003c0000 | (rm << 2));
308*4882a593Smuzhiyun 		regmap_write(opp_info->grf, 0x2c, 0x003c0000 | (rm << 2));
309*4882a593Smuzhiyun 		regmap_write(opp_info->grf, 0x30, 0x00200020);
310*4882a593Smuzhiyun 		udelay(1);
311*4882a593Smuzhiyun 		regmap_write(opp_info->grf, 0x30, 0x00200000);
312*4882a593Smuzhiyun 	}
313*4882a593Smuzhiyun 	if (opp_info->dsu_grf) {
314*4882a593Smuzhiyun 		regmap_write(opp_info->dsu_grf, 0x20, 0x001c0000 | (rm << 2));
315*4882a593Smuzhiyun 		regmap_write(opp_info->dsu_grf, 0x28, 0x003c0000 | (rm << 2));
316*4882a593Smuzhiyun 		regmap_write(opp_info->dsu_grf, 0x2c, 0x003c0000 | (rm << 2));
317*4882a593Smuzhiyun 		regmap_write(opp_info->dsu_grf, 0x30, 0x001c0000 | (rm << 2));
318*4882a593Smuzhiyun 		regmap_write(opp_info->dsu_grf, 0x38, 0x001c0000 | (rm << 2));
319*4882a593Smuzhiyun 		regmap_write(opp_info->dsu_grf, 0x18, 0x40004000);
320*4882a593Smuzhiyun 		udelay(1);
321*4882a593Smuzhiyun 		regmap_write(opp_info->dsu_grf, 0x18, 0x40000000);
322*4882a593Smuzhiyun 	}
323*4882a593Smuzhiyun 
324*4882a593Smuzhiyun 	opp_info->current_rm = rm;
325*4882a593Smuzhiyun 
326*4882a593Smuzhiyun 	return 0;
327*4882a593Smuzhiyun }
328*4882a593Smuzhiyun 
rv1126_get_soc_info(struct device * dev,struct device_node * np,int * bin,int * process)329*4882a593Smuzhiyun static int rv1126_get_soc_info(struct device *dev, struct device_node *np,
330*4882a593Smuzhiyun 			       int *bin, int *process)
331*4882a593Smuzhiyun {
332*4882a593Smuzhiyun 	int ret = 0;
333*4882a593Smuzhiyun 	u8 value = 0;
334*4882a593Smuzhiyun 
335*4882a593Smuzhiyun 	if (of_property_match_string(np, "nvmem-cell-names", "performance") >= 0) {
336*4882a593Smuzhiyun 		ret = rockchip_nvmem_cell_read_u8(np, "performance", &value);
337*4882a593Smuzhiyun 		if (ret) {
338*4882a593Smuzhiyun 			dev_err(dev, "Failed to get soc performance value\n");
339*4882a593Smuzhiyun 			return ret;
340*4882a593Smuzhiyun 		}
341*4882a593Smuzhiyun 		if (value == 0x1)
342*4882a593Smuzhiyun 			*bin = 1;
343*4882a593Smuzhiyun 		else
344*4882a593Smuzhiyun 			*bin = 0;
345*4882a593Smuzhiyun 	}
346*4882a593Smuzhiyun 	if (*bin >= 0)
347*4882a593Smuzhiyun 		dev_info(dev, "bin=%d\n", *bin);
348*4882a593Smuzhiyun 
349*4882a593Smuzhiyun 	return ret;
350*4882a593Smuzhiyun }
351*4882a593Smuzhiyun 
352*4882a593Smuzhiyun static const struct rockchip_opp_data px30_cpu_opp_data = {
353*4882a593Smuzhiyun 	.get_soc_info = px30_get_soc_info,
354*4882a593Smuzhiyun };
355*4882a593Smuzhiyun 
356*4882a593Smuzhiyun static const struct rockchip_opp_data rk3288_cpu_opp_data = {
357*4882a593Smuzhiyun 	.get_soc_info = rk3288_get_soc_info,
358*4882a593Smuzhiyun };
359*4882a593Smuzhiyun 
360*4882a593Smuzhiyun static const struct rockchip_opp_data rk3399_cpu_opp_data = {
361*4882a593Smuzhiyun 	.get_soc_info = rk3399_get_soc_info,
362*4882a593Smuzhiyun };
363*4882a593Smuzhiyun 
364*4882a593Smuzhiyun static const struct rockchip_opp_data rk3588_cpu_opp_data = {
365*4882a593Smuzhiyun 	.get_soc_info = rk3588_get_soc_info,
366*4882a593Smuzhiyun 	.set_soc_info = rk3588_set_soc_info,
367*4882a593Smuzhiyun 	.set_read_margin = rk3588_cpu_set_read_margin,
368*4882a593Smuzhiyun };
369*4882a593Smuzhiyun 
370*4882a593Smuzhiyun static const struct rockchip_opp_data rv1126_cpu_opp_data = {
371*4882a593Smuzhiyun 	.get_soc_info = rv1126_get_soc_info,
372*4882a593Smuzhiyun };
373*4882a593Smuzhiyun 
374*4882a593Smuzhiyun static const struct of_device_id rockchip_cpufreq_of_match[] = {
375*4882a593Smuzhiyun 	{
376*4882a593Smuzhiyun 		.compatible = "rockchip,px30",
377*4882a593Smuzhiyun 		.data = (void *)&px30_cpu_opp_data,
378*4882a593Smuzhiyun 	},
379*4882a593Smuzhiyun 	{
380*4882a593Smuzhiyun 		.compatible = "rockchip,rk3288",
381*4882a593Smuzhiyun 		.data = (void *)&rk3288_cpu_opp_data,
382*4882a593Smuzhiyun 	},
383*4882a593Smuzhiyun 	{
384*4882a593Smuzhiyun 		.compatible = "rockchip,rk3288w",
385*4882a593Smuzhiyun 		.data = (void *)&rk3288_cpu_opp_data,
386*4882a593Smuzhiyun 	},
387*4882a593Smuzhiyun 	{
388*4882a593Smuzhiyun 		.compatible = "rockchip,rk3326",
389*4882a593Smuzhiyun 		.data = (void *)&px30_cpu_opp_data,
390*4882a593Smuzhiyun 	},
391*4882a593Smuzhiyun 	{
392*4882a593Smuzhiyun 		.compatible = "rockchip,rk3399",
393*4882a593Smuzhiyun 		.data = (void *)&rk3399_cpu_opp_data,
394*4882a593Smuzhiyun 	},
395*4882a593Smuzhiyun 	{
396*4882a593Smuzhiyun 		.compatible = "rockchip,rk3588",
397*4882a593Smuzhiyun 		.data = (void *)&rk3588_cpu_opp_data,
398*4882a593Smuzhiyun 	},
399*4882a593Smuzhiyun 	{
400*4882a593Smuzhiyun 		.compatible = "rockchip,rv1109",
401*4882a593Smuzhiyun 		.data = (void *)&rv1126_cpu_opp_data,
402*4882a593Smuzhiyun 	},
403*4882a593Smuzhiyun 	{
404*4882a593Smuzhiyun 		.compatible = "rockchip,rv1126",
405*4882a593Smuzhiyun 		.data = (void *)&rv1126_cpu_opp_data,
406*4882a593Smuzhiyun 	},
407*4882a593Smuzhiyun 	{},
408*4882a593Smuzhiyun };
409*4882a593Smuzhiyun 
rockchip_cluster_info_lookup(int cpu)410*4882a593Smuzhiyun static struct cluster_info *rockchip_cluster_info_lookup(int cpu)
411*4882a593Smuzhiyun {
412*4882a593Smuzhiyun 	struct cluster_info *cluster;
413*4882a593Smuzhiyun 
414*4882a593Smuzhiyun 	list_for_each_entry(cluster, &cluster_info_list, list_head) {
415*4882a593Smuzhiyun 		if (cpumask_test_cpu(cpu, &cluster->cpus))
416*4882a593Smuzhiyun 			return cluster;
417*4882a593Smuzhiyun 	}
418*4882a593Smuzhiyun 
419*4882a593Smuzhiyun 	return NULL;
420*4882a593Smuzhiyun }
421*4882a593Smuzhiyun 
rockchip_cpufreq_set_volt(struct device * dev,struct regulator * reg,struct dev_pm_opp_supply * supply,char * reg_name)422*4882a593Smuzhiyun static int rockchip_cpufreq_set_volt(struct device *dev,
423*4882a593Smuzhiyun 				     struct regulator *reg,
424*4882a593Smuzhiyun 				     struct dev_pm_opp_supply *supply,
425*4882a593Smuzhiyun 				     char *reg_name)
426*4882a593Smuzhiyun {
427*4882a593Smuzhiyun 	int ret;
428*4882a593Smuzhiyun 
429*4882a593Smuzhiyun 	dev_dbg(dev, "%s: %s voltages (uV): %lu %lu %lu\n", __func__, reg_name,
430*4882a593Smuzhiyun 		supply->u_volt_min, supply->u_volt, supply->u_volt_max);
431*4882a593Smuzhiyun 
432*4882a593Smuzhiyun 	ret = regulator_set_voltage_triplet(reg, supply->u_volt_min,
433*4882a593Smuzhiyun 					    supply->u_volt, supply->u_volt_max);
434*4882a593Smuzhiyun 	if (ret)
435*4882a593Smuzhiyun 		dev_err(dev, "%s: failed to set voltage (%lu %lu %lu uV): %d\n",
436*4882a593Smuzhiyun 			__func__, supply->u_volt_min, supply->u_volt,
437*4882a593Smuzhiyun 			supply->u_volt_max, ret);
438*4882a593Smuzhiyun 
439*4882a593Smuzhiyun 	return ret;
440*4882a593Smuzhiyun }
441*4882a593Smuzhiyun 
cpu_opp_helper(struct dev_pm_set_opp_data * data)442*4882a593Smuzhiyun static int cpu_opp_helper(struct dev_pm_set_opp_data *data)
443*4882a593Smuzhiyun {
444*4882a593Smuzhiyun 	struct dev_pm_opp_supply *old_supply_vdd = &data->old_opp.supplies[0];
445*4882a593Smuzhiyun 	struct dev_pm_opp_supply *old_supply_mem = &data->old_opp.supplies[1];
446*4882a593Smuzhiyun 	struct dev_pm_opp_supply *new_supply_vdd = &data->new_opp.supplies[0];
447*4882a593Smuzhiyun 	struct dev_pm_opp_supply *new_supply_mem = &data->new_opp.supplies[1];
448*4882a593Smuzhiyun 	struct regulator *vdd_reg = data->regulators[0];
449*4882a593Smuzhiyun 	struct regulator *mem_reg = data->regulators[1];
450*4882a593Smuzhiyun 	struct device *dev = data->dev;
451*4882a593Smuzhiyun 	struct clk *clk = data->clk;
452*4882a593Smuzhiyun 	struct cluster_info *cluster;
453*4882a593Smuzhiyun 	struct rockchip_opp_info *opp_info;
454*4882a593Smuzhiyun 	unsigned long old_freq = data->old_opp.rate;
455*4882a593Smuzhiyun 	unsigned long new_freq = data->new_opp.rate;
456*4882a593Smuzhiyun 	u32 target_rm = UINT_MAX;
457*4882a593Smuzhiyun 	int ret = 0;
458*4882a593Smuzhiyun 
459*4882a593Smuzhiyun 	cluster = rockchip_cluster_info_lookup(dev->id);
460*4882a593Smuzhiyun 	if (!cluster)
461*4882a593Smuzhiyun 		return -EINVAL;
462*4882a593Smuzhiyun 	opp_info = &cluster->opp_info;
463*4882a593Smuzhiyun 	rockchip_get_read_margin(dev, opp_info, new_supply_vdd->u_volt,
464*4882a593Smuzhiyun 				 &target_rm);
465*4882a593Smuzhiyun 
466*4882a593Smuzhiyun 	/* Change frequency */
467*4882a593Smuzhiyun 	dev_dbg(dev, "%s: switching OPP: %lu Hz --> %lu Hz\n", __func__,
468*4882a593Smuzhiyun 		old_freq, new_freq);
469*4882a593Smuzhiyun 	/* Scaling up? Scale voltage before frequency */
470*4882a593Smuzhiyun 	if (new_freq >= old_freq) {
471*4882a593Smuzhiyun 		ret = rockchip_set_intermediate_rate(dev, opp_info, clk,
472*4882a593Smuzhiyun 						     old_freq, new_freq,
473*4882a593Smuzhiyun 						     true, true);
474*4882a593Smuzhiyun 		if (ret) {
475*4882a593Smuzhiyun 			dev_err(dev, "%s: failed to set clk rate: %lu\n",
476*4882a593Smuzhiyun 				__func__, new_freq);
477*4882a593Smuzhiyun 			return -EINVAL;
478*4882a593Smuzhiyun 		}
479*4882a593Smuzhiyun 		ret = rockchip_cpufreq_set_volt(dev, mem_reg, new_supply_mem,
480*4882a593Smuzhiyun 						"mem");
481*4882a593Smuzhiyun 		if (ret)
482*4882a593Smuzhiyun 			goto restore_voltage;
483*4882a593Smuzhiyun 		ret = rockchip_cpufreq_set_volt(dev, vdd_reg, new_supply_vdd,
484*4882a593Smuzhiyun 						"vdd");
485*4882a593Smuzhiyun 		if (ret)
486*4882a593Smuzhiyun 			goto restore_voltage;
487*4882a593Smuzhiyun 		rockchip_set_read_margin(dev, opp_info, target_rm, true);
488*4882a593Smuzhiyun 		ret = clk_set_rate(clk, new_freq);
489*4882a593Smuzhiyun 		if (ret) {
490*4882a593Smuzhiyun 			dev_err(dev, "%s: failed to set clk rate: %lu %d\n",
491*4882a593Smuzhiyun 				__func__, new_freq, ret);
492*4882a593Smuzhiyun 			goto restore_rm;
493*4882a593Smuzhiyun 		}
494*4882a593Smuzhiyun 	/* Scaling down? Scale voltage after frequency */
495*4882a593Smuzhiyun 	} else {
496*4882a593Smuzhiyun 		ret = rockchip_set_intermediate_rate(dev, opp_info, clk,
497*4882a593Smuzhiyun 						     old_freq, new_freq,
498*4882a593Smuzhiyun 						     false, true);
499*4882a593Smuzhiyun 		if (ret) {
500*4882a593Smuzhiyun 			dev_err(dev, "%s: failed to set clk rate: %lu\n",
501*4882a593Smuzhiyun 				__func__, new_freq);
502*4882a593Smuzhiyun 			return -EINVAL;
503*4882a593Smuzhiyun 		}
504*4882a593Smuzhiyun 		rockchip_set_read_margin(dev, opp_info, target_rm, true);
505*4882a593Smuzhiyun 		ret = clk_set_rate(clk, new_freq);
506*4882a593Smuzhiyun 		if (ret) {
507*4882a593Smuzhiyun 			dev_err(dev, "%s: failed to set clk rate: %lu %d\n",
508*4882a593Smuzhiyun 				__func__, new_freq, ret);
509*4882a593Smuzhiyun 			goto restore_rm;
510*4882a593Smuzhiyun 		}
511*4882a593Smuzhiyun 		ret = rockchip_cpufreq_set_volt(dev, vdd_reg, new_supply_vdd,
512*4882a593Smuzhiyun 						"vdd");
513*4882a593Smuzhiyun 		if (ret)
514*4882a593Smuzhiyun 			goto restore_freq;
515*4882a593Smuzhiyun 		ret = rockchip_cpufreq_set_volt(dev, mem_reg, new_supply_mem,
516*4882a593Smuzhiyun 						"mem");
517*4882a593Smuzhiyun 		if (ret)
518*4882a593Smuzhiyun 			goto restore_freq;
519*4882a593Smuzhiyun 	}
520*4882a593Smuzhiyun 
521*4882a593Smuzhiyun 	cluster->volt = new_supply_vdd->u_volt;
522*4882a593Smuzhiyun 	cluster->mem_volt = new_supply_mem->u_volt;
523*4882a593Smuzhiyun 
524*4882a593Smuzhiyun 	return 0;
525*4882a593Smuzhiyun 
526*4882a593Smuzhiyun restore_freq:
527*4882a593Smuzhiyun 	if (clk_set_rate(clk, old_freq))
528*4882a593Smuzhiyun 		dev_err(dev, "%s: failed to restore old-freq (%lu Hz)\n",
529*4882a593Smuzhiyun 			__func__, old_freq);
530*4882a593Smuzhiyun restore_rm:
531*4882a593Smuzhiyun 	rockchip_get_read_margin(dev, opp_info, old_supply_vdd->u_volt,
532*4882a593Smuzhiyun 				 &target_rm);
533*4882a593Smuzhiyun 	rockchip_set_read_margin(dev, opp_info, target_rm, true);
534*4882a593Smuzhiyun restore_voltage:
535*4882a593Smuzhiyun 	rockchip_cpufreq_set_volt(dev, mem_reg, old_supply_mem, "mem");
536*4882a593Smuzhiyun 	rockchip_cpufreq_set_volt(dev, vdd_reg, old_supply_vdd, "vdd");
537*4882a593Smuzhiyun 
538*4882a593Smuzhiyun 	return ret;
539*4882a593Smuzhiyun }
540*4882a593Smuzhiyun 
rockchip_cpufreq_cluster_init(int cpu,struct cluster_info * cluster)541*4882a593Smuzhiyun static int rockchip_cpufreq_cluster_init(int cpu, struct cluster_info *cluster)
542*4882a593Smuzhiyun {
543*4882a593Smuzhiyun 	struct rockchip_opp_info *opp_info = &cluster->opp_info;
544*4882a593Smuzhiyun 	struct opp_table *pname_table = NULL;
545*4882a593Smuzhiyun 	struct opp_table *reg_table = NULL;
546*4882a593Smuzhiyun 	struct opp_table *opp_table;
547*4882a593Smuzhiyun 	struct device_node *np;
548*4882a593Smuzhiyun 	struct device *dev;
549*4882a593Smuzhiyun 	const char * const reg_names[] = {"cpu", "mem"};
550*4882a593Smuzhiyun 	char *reg_name = NULL;
551*4882a593Smuzhiyun 	int bin = -EINVAL;
552*4882a593Smuzhiyun 	int process = -EINVAL;
553*4882a593Smuzhiyun 	int volt_sel = -EINVAL;
554*4882a593Smuzhiyun 	int ret = 0;
555*4882a593Smuzhiyun 	u32 freq = 0;
556*4882a593Smuzhiyun 
557*4882a593Smuzhiyun 	dev = get_cpu_device(cpu);
558*4882a593Smuzhiyun 	if (!dev)
559*4882a593Smuzhiyun 		return -ENODEV;
560*4882a593Smuzhiyun 
561*4882a593Smuzhiyun 	opp_info->dev = dev;
562*4882a593Smuzhiyun 
563*4882a593Smuzhiyun 	if (of_find_property(dev->of_node, "cpu-supply", NULL))
564*4882a593Smuzhiyun 		reg_name = "cpu";
565*4882a593Smuzhiyun 	else if (of_find_property(dev->of_node, "cpu0-supply", NULL))
566*4882a593Smuzhiyun 		reg_name = "cpu0";
567*4882a593Smuzhiyun 	else
568*4882a593Smuzhiyun 		return -ENOENT;
569*4882a593Smuzhiyun 
570*4882a593Smuzhiyun 	np = of_parse_phandle(dev->of_node, "operating-points-v2", 0);
571*4882a593Smuzhiyun 	if (!np) {
572*4882a593Smuzhiyun 		dev_warn(dev, "OPP-v2 not supported\n");
573*4882a593Smuzhiyun 		return -ENOENT;
574*4882a593Smuzhiyun 	}
575*4882a593Smuzhiyun 
576*4882a593Smuzhiyun 	opp_info->grf = syscon_regmap_lookup_by_phandle(np,
577*4882a593Smuzhiyun 							"rockchip,grf");
578*4882a593Smuzhiyun 	if (IS_ERR(opp_info->grf))
579*4882a593Smuzhiyun 		opp_info->grf = NULL;
580*4882a593Smuzhiyun 
581*4882a593Smuzhiyun 	ret = dev_pm_opp_of_get_sharing_cpus(dev, &cluster->cpus);
582*4882a593Smuzhiyun 	if (ret) {
583*4882a593Smuzhiyun 		dev_err(dev, "Failed to get sharing cpus\n");
584*4882a593Smuzhiyun 		goto np_err;
585*4882a593Smuzhiyun 	}
586*4882a593Smuzhiyun 
587*4882a593Smuzhiyun 	cluster->is_opp_shared_dsu = of_property_read_bool(np, "rockchip,opp-shared-dsu");
588*4882a593Smuzhiyun 	if (!of_property_read_u32(np, "rockchip,idle-threshold-freq", &freq))
589*4882a593Smuzhiyun 		cluster->idle_threshold_freq = freq;
590*4882a593Smuzhiyun 	rockchip_get_opp_data(rockchip_cpufreq_of_match, opp_info);
591*4882a593Smuzhiyun 	if (opp_info->data && opp_info->data->set_read_margin) {
592*4882a593Smuzhiyun 		opp_info->current_rm = UINT_MAX;
593*4882a593Smuzhiyun 		opp_info->target_rm = UINT_MAX;
594*4882a593Smuzhiyun 		opp_info->dsu_grf =
595*4882a593Smuzhiyun 			syscon_regmap_lookup_by_phandle(np, "rockchip,dsu-grf");
596*4882a593Smuzhiyun 		if (IS_ERR(opp_info->dsu_grf))
597*4882a593Smuzhiyun 			opp_info->dsu_grf = NULL;
598*4882a593Smuzhiyun 		rockchip_get_volt_rm_table(dev, np, "volt-mem-read-margin",
599*4882a593Smuzhiyun 					   &opp_info->volt_rm_tbl);
600*4882a593Smuzhiyun 		of_property_read_u32(np, "low-volt-mem-read-margin",
601*4882a593Smuzhiyun 				     &opp_info->low_rm);
602*4882a593Smuzhiyun 		if (!of_property_read_u32(np, "intermediate-threshold-freq", &freq))
603*4882a593Smuzhiyun 			opp_info->intermediate_threshold_freq = freq * 1000;
604*4882a593Smuzhiyun 		rockchip_init_read_margin(dev, opp_info, reg_name);
605*4882a593Smuzhiyun 	}
606*4882a593Smuzhiyun 	if (opp_info->data && opp_info->data->get_soc_info)
607*4882a593Smuzhiyun 		opp_info->data->get_soc_info(dev, np, &bin, &process);
608*4882a593Smuzhiyun 	rockchip_get_scale_volt_sel(dev, "cpu_leakage", reg_name, bin, process,
609*4882a593Smuzhiyun 				    &cluster->scale, &volt_sel);
610*4882a593Smuzhiyun 	if (opp_info->data && opp_info->data->set_soc_info)
611*4882a593Smuzhiyun 		opp_info->data->set_soc_info(dev, np, bin, process, volt_sel);
612*4882a593Smuzhiyun 	pname_table = rockchip_set_opp_prop_name(dev, process, volt_sel);
613*4882a593Smuzhiyun 
614*4882a593Smuzhiyun 	if (of_find_property(dev->of_node, "cpu-supply", NULL) &&
615*4882a593Smuzhiyun 	    of_find_property(dev->of_node, "mem-supply", NULL)) {
616*4882a593Smuzhiyun 		cluster->regulator_count = 2;
617*4882a593Smuzhiyun 		reg_table = dev_pm_opp_set_regulators(dev, reg_names,
618*4882a593Smuzhiyun 						      ARRAY_SIZE(reg_names));
619*4882a593Smuzhiyun 		if (IS_ERR(reg_table)) {
620*4882a593Smuzhiyun 			ret = PTR_ERR(reg_table);
621*4882a593Smuzhiyun 			goto pname_opp_table;
622*4882a593Smuzhiyun 		}
623*4882a593Smuzhiyun 		opp_table = dev_pm_opp_register_set_opp_helper(dev,
624*4882a593Smuzhiyun 							       cpu_opp_helper);
625*4882a593Smuzhiyun 		if (IS_ERR(opp_table)) {
626*4882a593Smuzhiyun 			ret = PTR_ERR(opp_table);
627*4882a593Smuzhiyun 			goto reg_opp_table;
628*4882a593Smuzhiyun 		}
629*4882a593Smuzhiyun 	} else {
630*4882a593Smuzhiyun 		cluster->regulator_count = 1;
631*4882a593Smuzhiyun 	}
632*4882a593Smuzhiyun 
633*4882a593Smuzhiyun 	of_node_put(np);
634*4882a593Smuzhiyun 
635*4882a593Smuzhiyun 	return 0;
636*4882a593Smuzhiyun 
637*4882a593Smuzhiyun reg_opp_table:
638*4882a593Smuzhiyun 	if (reg_table)
639*4882a593Smuzhiyun 		dev_pm_opp_put_regulators(reg_table);
640*4882a593Smuzhiyun pname_opp_table:
641*4882a593Smuzhiyun 	if (!IS_ERR_OR_NULL(pname_table))
642*4882a593Smuzhiyun 		dev_pm_opp_put_prop_name(pname_table);
643*4882a593Smuzhiyun np_err:
644*4882a593Smuzhiyun 	of_node_put(np);
645*4882a593Smuzhiyun 
646*4882a593Smuzhiyun 	return ret;
647*4882a593Smuzhiyun }
648*4882a593Smuzhiyun 
rockchip_cpufreq_adjust_power_scale(struct device * dev)649*4882a593Smuzhiyun int rockchip_cpufreq_adjust_power_scale(struct device *dev)
650*4882a593Smuzhiyun {
651*4882a593Smuzhiyun 	struct cluster_info *cluster;
652*4882a593Smuzhiyun 
653*4882a593Smuzhiyun 	cluster = rockchip_cluster_info_lookup(dev->id);
654*4882a593Smuzhiyun 	if (!cluster)
655*4882a593Smuzhiyun 		return -EINVAL;
656*4882a593Smuzhiyun 	rockchip_adjust_power_scale(dev, cluster->scale);
657*4882a593Smuzhiyun 	rockchip_pvtpll_calibrate_opp(&cluster->opp_info);
658*4882a593Smuzhiyun 	rockchip_pvtpll_add_length(&cluster->opp_info);
659*4882a593Smuzhiyun 
660*4882a593Smuzhiyun 	return 0;
661*4882a593Smuzhiyun }
662*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(rockchip_cpufreq_adjust_power_scale);
663*4882a593Smuzhiyun 
rockchip_cpufreq_opp_set_rate(struct device * dev,unsigned long target_freq)664*4882a593Smuzhiyun int rockchip_cpufreq_opp_set_rate(struct device *dev, unsigned long target_freq)
665*4882a593Smuzhiyun {
666*4882a593Smuzhiyun 	struct cluster_info *cluster;
667*4882a593Smuzhiyun 	struct dev_pm_opp *opp;
668*4882a593Smuzhiyun 	unsigned long freq;
669*4882a593Smuzhiyun 	int ret = 0;
670*4882a593Smuzhiyun 
671*4882a593Smuzhiyun 	cluster = rockchip_cluster_info_lookup(dev->id);
672*4882a593Smuzhiyun 	if (!cluster)
673*4882a593Smuzhiyun 		return -EINVAL;
674*4882a593Smuzhiyun 
675*4882a593Smuzhiyun 	rockchip_monitor_volt_adjust_lock(cluster->mdev_info);
676*4882a593Smuzhiyun 	ret = dev_pm_opp_set_rate(dev, target_freq);
677*4882a593Smuzhiyun 	if (!ret) {
678*4882a593Smuzhiyun 		cluster->rate = target_freq;
679*4882a593Smuzhiyun 		if (cluster->regulator_count == 1) {
680*4882a593Smuzhiyun 			freq = target_freq;
681*4882a593Smuzhiyun 			opp = dev_pm_opp_find_freq_ceil(cluster->opp_info.dev, &freq);
682*4882a593Smuzhiyun 			if (!IS_ERR(opp)) {
683*4882a593Smuzhiyun 				cluster->volt = dev_pm_opp_get_voltage(opp);
684*4882a593Smuzhiyun 				dev_pm_opp_put(opp);
685*4882a593Smuzhiyun 			}
686*4882a593Smuzhiyun 		}
687*4882a593Smuzhiyun 	}
688*4882a593Smuzhiyun 	rockchip_monitor_volt_adjust_unlock(cluster->mdev_info);
689*4882a593Smuzhiyun 
690*4882a593Smuzhiyun 	return ret;
691*4882a593Smuzhiyun }
692*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(rockchip_cpufreq_opp_set_rate);
693*4882a593Smuzhiyun 
rockchip_cpufreq_suspend(struct cpufreq_policy * policy)694*4882a593Smuzhiyun static int rockchip_cpufreq_suspend(struct cpufreq_policy *policy)
695*4882a593Smuzhiyun {
696*4882a593Smuzhiyun 	int ret = 0;
697*4882a593Smuzhiyun 
698*4882a593Smuzhiyun 	ret = cpufreq_generic_suspend(policy);
699*4882a593Smuzhiyun 	if (!ret)
700*4882a593Smuzhiyun 		rockchip_monitor_suspend_low_temp_adjust(policy->cpu);
701*4882a593Smuzhiyun 
702*4882a593Smuzhiyun 	return ret;
703*4882a593Smuzhiyun }
704*4882a593Smuzhiyun 
rockchip_cpufreq_add_monitor(struct cluster_info * cluster,struct cpufreq_policy * policy)705*4882a593Smuzhiyun static int rockchip_cpufreq_add_monitor(struct cluster_info *cluster,
706*4882a593Smuzhiyun 					struct cpufreq_policy *policy)
707*4882a593Smuzhiyun {
708*4882a593Smuzhiyun 	struct device *dev = cluster->opp_info.dev;
709*4882a593Smuzhiyun 	struct monitor_dev_profile *mdevp = NULL;
710*4882a593Smuzhiyun 	struct monitor_dev_info *mdev_info = NULL;
711*4882a593Smuzhiyun 
712*4882a593Smuzhiyun 	mdevp = kzalloc(sizeof(*mdevp), GFP_KERNEL);
713*4882a593Smuzhiyun 	if (!mdevp)
714*4882a593Smuzhiyun 		return -ENOMEM;
715*4882a593Smuzhiyun 
716*4882a593Smuzhiyun 	mdevp->type = MONITOR_TYPE_CPU;
717*4882a593Smuzhiyun 	mdevp->low_temp_adjust = rockchip_monitor_cpu_low_temp_adjust;
718*4882a593Smuzhiyun 	mdevp->high_temp_adjust = rockchip_monitor_cpu_high_temp_adjust;
719*4882a593Smuzhiyun 	mdevp->update_volt = rockchip_monitor_check_rate_volt;
720*4882a593Smuzhiyun 	mdevp->data = (void *)policy;
721*4882a593Smuzhiyun 	mdevp->opp_info = &cluster->opp_info;
722*4882a593Smuzhiyun 	cpumask_copy(&mdevp->allowed_cpus, policy->cpus);
723*4882a593Smuzhiyun 	mdev_info = rockchip_system_monitor_register(dev, mdevp);
724*4882a593Smuzhiyun 	if (IS_ERR(mdev_info)) {
725*4882a593Smuzhiyun 		kfree(mdevp);
726*4882a593Smuzhiyun 		dev_err(dev, "failed to register system monitor\n");
727*4882a593Smuzhiyun 		return -EINVAL;
728*4882a593Smuzhiyun 	}
729*4882a593Smuzhiyun 	mdev_info->devp = mdevp;
730*4882a593Smuzhiyun 	cluster->mdev_info = mdev_info;
731*4882a593Smuzhiyun 
732*4882a593Smuzhiyun 	return 0;
733*4882a593Smuzhiyun }
734*4882a593Smuzhiyun 
rockchip_cpufreq_remove_monitor(struct cluster_info * cluster)735*4882a593Smuzhiyun static int rockchip_cpufreq_remove_monitor(struct cluster_info *cluster)
736*4882a593Smuzhiyun {
737*4882a593Smuzhiyun 	if (cluster->mdev_info) {
738*4882a593Smuzhiyun 		kfree(cluster->mdev_info->devp);
739*4882a593Smuzhiyun 		rockchip_system_monitor_unregister(cluster->mdev_info);
740*4882a593Smuzhiyun 		cluster->mdev_info = NULL;
741*4882a593Smuzhiyun 	}
742*4882a593Smuzhiyun 
743*4882a593Smuzhiyun 	return 0;
744*4882a593Smuzhiyun }
745*4882a593Smuzhiyun 
rockchip_cpufreq_remove_dsu_qos(struct cluster_info * cluster)746*4882a593Smuzhiyun static int rockchip_cpufreq_remove_dsu_qos(struct cluster_info *cluster)
747*4882a593Smuzhiyun {
748*4882a593Smuzhiyun 	struct cluster_info *ci;
749*4882a593Smuzhiyun 
750*4882a593Smuzhiyun 	if (!cluster->is_opp_shared_dsu)
751*4882a593Smuzhiyun 		return 0;
752*4882a593Smuzhiyun 
753*4882a593Smuzhiyun 	list_for_each_entry(ci, &cluster_info_list, list_head) {
754*4882a593Smuzhiyun 		if (ci->is_opp_shared_dsu)
755*4882a593Smuzhiyun 			continue;
756*4882a593Smuzhiyun 		if (freq_qos_request_active(&ci->dsu_qos_req))
757*4882a593Smuzhiyun 			freq_qos_remove_request(&ci->dsu_qos_req);
758*4882a593Smuzhiyun 	}
759*4882a593Smuzhiyun 
760*4882a593Smuzhiyun 	return 0;
761*4882a593Smuzhiyun }
762*4882a593Smuzhiyun 
rockchip_cpufreq_add_dsu_qos_req(struct cluster_info * cluster,struct cpufreq_policy * policy)763*4882a593Smuzhiyun static int rockchip_cpufreq_add_dsu_qos_req(struct cluster_info *cluster,
764*4882a593Smuzhiyun 					    struct cpufreq_policy *policy)
765*4882a593Smuzhiyun {
766*4882a593Smuzhiyun 	struct device *dev = cluster->opp_info.dev;
767*4882a593Smuzhiyun 	struct cluster_info *ci;
768*4882a593Smuzhiyun 	int ret;
769*4882a593Smuzhiyun 
770*4882a593Smuzhiyun 	if (!cluster->is_opp_shared_dsu)
771*4882a593Smuzhiyun 		return 0;
772*4882a593Smuzhiyun 
773*4882a593Smuzhiyun 	list_for_each_entry(ci, &cluster_info_list, list_head) {
774*4882a593Smuzhiyun 		if (ci->is_opp_shared_dsu)
775*4882a593Smuzhiyun 			continue;
776*4882a593Smuzhiyun 		ret = freq_qos_add_request(&policy->constraints,
777*4882a593Smuzhiyun 					   &ci->dsu_qos_req,
778*4882a593Smuzhiyun 					   FREQ_QOS_MIN,
779*4882a593Smuzhiyun 					   FREQ_QOS_MIN_DEFAULT_VALUE);
780*4882a593Smuzhiyun 		if (ret < 0) {
781*4882a593Smuzhiyun 			dev_err(dev, "failed to add dsu freq constraint\n");
782*4882a593Smuzhiyun 			goto error;
783*4882a593Smuzhiyun 		}
784*4882a593Smuzhiyun 	}
785*4882a593Smuzhiyun 
786*4882a593Smuzhiyun 	return 0;
787*4882a593Smuzhiyun 
788*4882a593Smuzhiyun error:
789*4882a593Smuzhiyun 	rockchip_cpufreq_remove_dsu_qos(cluster);
790*4882a593Smuzhiyun 
791*4882a593Smuzhiyun 	return ret;
792*4882a593Smuzhiyun }
793*4882a593Smuzhiyun 
rockchip_cpufreq_notifier(struct notifier_block * nb,unsigned long event,void * data)794*4882a593Smuzhiyun static int rockchip_cpufreq_notifier(struct notifier_block *nb,
795*4882a593Smuzhiyun 				     unsigned long event, void *data)
796*4882a593Smuzhiyun {
797*4882a593Smuzhiyun 	struct cpufreq_policy *policy = data;
798*4882a593Smuzhiyun 	struct cluster_info *cluster;
799*4882a593Smuzhiyun 
800*4882a593Smuzhiyun 	cluster = rockchip_cluster_info_lookup(policy->cpu);
801*4882a593Smuzhiyun 	if (!cluster)
802*4882a593Smuzhiyun 		return NOTIFY_BAD;
803*4882a593Smuzhiyun 
804*4882a593Smuzhiyun 	if (event == CPUFREQ_CREATE_POLICY) {
805*4882a593Smuzhiyun 		if (rockchip_cpufreq_add_monitor(cluster, policy))
806*4882a593Smuzhiyun 			return NOTIFY_BAD;
807*4882a593Smuzhiyun 		if (rockchip_cpufreq_add_dsu_qos_req(cluster, policy))
808*4882a593Smuzhiyun 			return NOTIFY_BAD;
809*4882a593Smuzhiyun 	} else if (event == CPUFREQ_REMOVE_POLICY) {
810*4882a593Smuzhiyun 		rockchip_cpufreq_remove_monitor(cluster);
811*4882a593Smuzhiyun 		rockchip_cpufreq_remove_dsu_qos(cluster);
812*4882a593Smuzhiyun 	}
813*4882a593Smuzhiyun 
814*4882a593Smuzhiyun 	return NOTIFY_OK;
815*4882a593Smuzhiyun }
816*4882a593Smuzhiyun 
817*4882a593Smuzhiyun static struct notifier_block rockchip_cpufreq_notifier_block = {
818*4882a593Smuzhiyun 	.notifier_call = rockchip_cpufreq_notifier,
819*4882a593Smuzhiyun };
820*4882a593Smuzhiyun 
821*4882a593Smuzhiyun #ifdef MODULE
822*4882a593Smuzhiyun static struct pm_qos_request idle_pm_qos;
823*4882a593Smuzhiyun static int idle_disable_refcnt;
824*4882a593Smuzhiyun static DEFINE_MUTEX(idle_disable_lock);
825*4882a593Smuzhiyun 
rockchip_cpufreq_idle_state_disable(struct cpumask * cpumask,int index,bool disable)826*4882a593Smuzhiyun static int rockchip_cpufreq_idle_state_disable(struct cpumask *cpumask,
827*4882a593Smuzhiyun 					       int index, bool disable)
828*4882a593Smuzhiyun {
829*4882a593Smuzhiyun 	mutex_lock(&idle_disable_lock);
830*4882a593Smuzhiyun 
831*4882a593Smuzhiyun 	if (disable) {
832*4882a593Smuzhiyun 		if (idle_disable_refcnt == 0)
833*4882a593Smuzhiyun 			cpu_latency_qos_update_request(&idle_pm_qos, 0);
834*4882a593Smuzhiyun 		idle_disable_refcnt++;
835*4882a593Smuzhiyun 	} else {
836*4882a593Smuzhiyun 		if (--idle_disable_refcnt == 0)
837*4882a593Smuzhiyun 			cpu_latency_qos_update_request(&idle_pm_qos,
838*4882a593Smuzhiyun 						       PM_QOS_DEFAULT_VALUE);
839*4882a593Smuzhiyun 	}
840*4882a593Smuzhiyun 
841*4882a593Smuzhiyun 	mutex_unlock(&idle_disable_lock);
842*4882a593Smuzhiyun 
843*4882a593Smuzhiyun 	return 0;
844*4882a593Smuzhiyun }
845*4882a593Smuzhiyun #else
rockchip_cpufreq_idle_state_disable(struct cpumask * cpumask,int index,bool disable)846*4882a593Smuzhiyun static int rockchip_cpufreq_idle_state_disable(struct cpumask *cpumask,
847*4882a593Smuzhiyun 					       int index, bool disable)
848*4882a593Smuzhiyun {
849*4882a593Smuzhiyun 	unsigned int cpu;
850*4882a593Smuzhiyun 
851*4882a593Smuzhiyun 	for_each_cpu(cpu, cpumask) {
852*4882a593Smuzhiyun 		struct cpuidle_device *dev = per_cpu(cpuidle_devices, cpu);
853*4882a593Smuzhiyun 		struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev);
854*4882a593Smuzhiyun 
855*4882a593Smuzhiyun 		if (!dev || !drv)
856*4882a593Smuzhiyun 			continue;
857*4882a593Smuzhiyun 		if (index >= drv->state_count)
858*4882a593Smuzhiyun 			continue;
859*4882a593Smuzhiyun 		cpuidle_driver_state_disabled(drv, index, disable);
860*4882a593Smuzhiyun 	}
861*4882a593Smuzhiyun 
862*4882a593Smuzhiyun 	if (disable) {
863*4882a593Smuzhiyun 		preempt_disable();
864*4882a593Smuzhiyun 		for_each_cpu(cpu, cpumask) {
865*4882a593Smuzhiyun 			if (cpu != smp_processor_id() && cpu_online(cpu))
866*4882a593Smuzhiyun 				wake_up_if_idle(cpu);
867*4882a593Smuzhiyun 		}
868*4882a593Smuzhiyun 		preempt_enable();
869*4882a593Smuzhiyun 	}
870*4882a593Smuzhiyun 
871*4882a593Smuzhiyun 	return 0;
872*4882a593Smuzhiyun }
873*4882a593Smuzhiyun #endif
874*4882a593Smuzhiyun 
875*4882a593Smuzhiyun #define cpu_to_dsu_freq(freq)  ((freq) * 4 / 5)
876*4882a593Smuzhiyun 
rockchip_cpufreq_update_dsu_req(struct cluster_info * cluster,unsigned int freq)877*4882a593Smuzhiyun static int rockchip_cpufreq_update_dsu_req(struct cluster_info *cluster,
878*4882a593Smuzhiyun 					   unsigned int freq)
879*4882a593Smuzhiyun {
880*4882a593Smuzhiyun 	struct device *dev = cluster->opp_info.dev;
881*4882a593Smuzhiyun 	unsigned int dsu_freq = rounddown(cpu_to_dsu_freq(freq), 100000);
882*4882a593Smuzhiyun 
883*4882a593Smuzhiyun 	if (cluster->is_opp_shared_dsu ||
884*4882a593Smuzhiyun 	    !freq_qos_request_active(&cluster->dsu_qos_req))
885*4882a593Smuzhiyun 		return 0;
886*4882a593Smuzhiyun 
887*4882a593Smuzhiyun 	dev_dbg(dev, "cpu to dsu: %u -> %u\n", freq, dsu_freq);
888*4882a593Smuzhiyun 
889*4882a593Smuzhiyun 	return freq_qos_update_request(&cluster->dsu_qos_req, dsu_freq);
890*4882a593Smuzhiyun }
891*4882a593Smuzhiyun 
rockchip_cpufreq_transition_notifier(struct notifier_block * nb,unsigned long event,void * data)892*4882a593Smuzhiyun static int rockchip_cpufreq_transition_notifier(struct notifier_block *nb,
893*4882a593Smuzhiyun 						unsigned long event, void *data)
894*4882a593Smuzhiyun {
895*4882a593Smuzhiyun 	struct cpufreq_freqs *freqs = data;
896*4882a593Smuzhiyun 	struct cpufreq_policy *policy = freqs->policy;
897*4882a593Smuzhiyun 	struct cluster_info *cluster;
898*4882a593Smuzhiyun 
899*4882a593Smuzhiyun 	cluster = rockchip_cluster_info_lookup(policy->cpu);
900*4882a593Smuzhiyun 	if (!cluster)
901*4882a593Smuzhiyun 		return NOTIFY_BAD;
902*4882a593Smuzhiyun 
903*4882a593Smuzhiyun 	if (event == CPUFREQ_PRECHANGE) {
904*4882a593Smuzhiyun 		if (cluster->idle_threshold_freq &&
905*4882a593Smuzhiyun 		    freqs->new >= cluster->idle_threshold_freq &&
906*4882a593Smuzhiyun 		    !cluster->is_idle_disabled) {
907*4882a593Smuzhiyun 			rockchip_cpufreq_idle_state_disable(policy->cpus, 1,
908*4882a593Smuzhiyun 							    true);
909*4882a593Smuzhiyun 			cluster->is_idle_disabled = true;
910*4882a593Smuzhiyun 		}
911*4882a593Smuzhiyun 	} else if (event == CPUFREQ_POSTCHANGE) {
912*4882a593Smuzhiyun 		if (cluster->idle_threshold_freq &&
913*4882a593Smuzhiyun 		    freqs->new < cluster->idle_threshold_freq &&
914*4882a593Smuzhiyun 		    cluster->is_idle_disabled) {
915*4882a593Smuzhiyun 			rockchip_cpufreq_idle_state_disable(policy->cpus, 1,
916*4882a593Smuzhiyun 							    false);
917*4882a593Smuzhiyun 			cluster->is_idle_disabled = false;
918*4882a593Smuzhiyun 		}
919*4882a593Smuzhiyun 		rockchip_cpufreq_update_dsu_req(cluster, freqs->new);
920*4882a593Smuzhiyun 	}
921*4882a593Smuzhiyun 
922*4882a593Smuzhiyun 	return NOTIFY_OK;
923*4882a593Smuzhiyun }
924*4882a593Smuzhiyun 
925*4882a593Smuzhiyun static struct notifier_block rockchip_cpufreq_transition_notifier_block = {
926*4882a593Smuzhiyun 	.notifier_call = rockchip_cpufreq_transition_notifier,
927*4882a593Smuzhiyun };
928*4882a593Smuzhiyun 
rockchip_cpufreq_panic_notifier(struct notifier_block * nb,unsigned long v,void * p)929*4882a593Smuzhiyun static int rockchip_cpufreq_panic_notifier(struct notifier_block *nb,
930*4882a593Smuzhiyun 					   unsigned long v, void *p)
931*4882a593Smuzhiyun {
932*4882a593Smuzhiyun 	struct cluster_info *ci;
933*4882a593Smuzhiyun 	struct device *dev;
934*4882a593Smuzhiyun 
935*4882a593Smuzhiyun 	list_for_each_entry(ci, &cluster_info_list, list_head) {
936*4882a593Smuzhiyun 		dev = ci->opp_info.dev;
937*4882a593Smuzhiyun 
938*4882a593Smuzhiyun 		if (ci->regulator_count == 1)
939*4882a593Smuzhiyun 			dev_info(dev, "cur_freq: %lu Hz, volt: %lu uV\n",
940*4882a593Smuzhiyun 				 ci->rate, ci->volt);
941*4882a593Smuzhiyun 		else
942*4882a593Smuzhiyun 			dev_info(dev, "cur_freq: %lu Hz, volt_vdd: %lu uV, volt_mem: %lu uV\n",
943*4882a593Smuzhiyun 				 ci->rate, ci->volt, ci->mem_volt);
944*4882a593Smuzhiyun 	}
945*4882a593Smuzhiyun 
946*4882a593Smuzhiyun 	return 0;
947*4882a593Smuzhiyun }
948*4882a593Smuzhiyun 
949*4882a593Smuzhiyun static struct notifier_block rockchip_cpufreq_panic_notifier_block = {
950*4882a593Smuzhiyun 	.notifier_call = rockchip_cpufreq_panic_notifier,
951*4882a593Smuzhiyun };
952*4882a593Smuzhiyun 
rockchip_cpufreq_driver_init(void)953*4882a593Smuzhiyun static int __init rockchip_cpufreq_driver_init(void)
954*4882a593Smuzhiyun {
955*4882a593Smuzhiyun 	struct cluster_info *cluster, *pos;
956*4882a593Smuzhiyun 	struct cpufreq_dt_platform_data pdata = {0};
957*4882a593Smuzhiyun 	int cpu, ret;
958*4882a593Smuzhiyun 
959*4882a593Smuzhiyun 	for_each_possible_cpu(cpu) {
960*4882a593Smuzhiyun 		cluster = rockchip_cluster_info_lookup(cpu);
961*4882a593Smuzhiyun 		if (cluster)
962*4882a593Smuzhiyun 			continue;
963*4882a593Smuzhiyun 
964*4882a593Smuzhiyun 		cluster = kzalloc(sizeof(*cluster), GFP_KERNEL);
965*4882a593Smuzhiyun 		if (!cluster) {
966*4882a593Smuzhiyun 			ret = -ENOMEM;
967*4882a593Smuzhiyun 			goto release_cluster_info;
968*4882a593Smuzhiyun 		}
969*4882a593Smuzhiyun 
970*4882a593Smuzhiyun 		ret = rockchip_cpufreq_cluster_init(cpu, cluster);
971*4882a593Smuzhiyun 		if (ret) {
972*4882a593Smuzhiyun 			pr_err("Failed to initialize dvfs info cpu%d\n", cpu);
973*4882a593Smuzhiyun 			goto release_cluster_info;
974*4882a593Smuzhiyun 		}
975*4882a593Smuzhiyun 		list_add(&cluster->list_head, &cluster_info_list);
976*4882a593Smuzhiyun 	}
977*4882a593Smuzhiyun 
978*4882a593Smuzhiyun 	pdata.have_governor_per_policy = true;
979*4882a593Smuzhiyun 	pdata.suspend = rockchip_cpufreq_suspend;
980*4882a593Smuzhiyun 
981*4882a593Smuzhiyun 	ret = cpufreq_register_notifier(&rockchip_cpufreq_notifier_block,
982*4882a593Smuzhiyun 					CPUFREQ_POLICY_NOTIFIER);
983*4882a593Smuzhiyun 	if (ret) {
984*4882a593Smuzhiyun 		pr_err("failed to register cpufreq notifier\n");
985*4882a593Smuzhiyun 		goto release_cluster_info;
986*4882a593Smuzhiyun 	}
987*4882a593Smuzhiyun 
988*4882a593Smuzhiyun 	if (of_machine_is_compatible("rockchip,rk3588")) {
989*4882a593Smuzhiyun 		ret = cpufreq_register_notifier(&rockchip_cpufreq_transition_notifier_block,
990*4882a593Smuzhiyun 						CPUFREQ_TRANSITION_NOTIFIER);
991*4882a593Smuzhiyun 		if (ret) {
992*4882a593Smuzhiyun 			cpufreq_unregister_notifier(&rockchip_cpufreq_notifier_block,
993*4882a593Smuzhiyun 						    CPUFREQ_POLICY_NOTIFIER);
994*4882a593Smuzhiyun 			pr_err("failed to register cpufreq notifier\n");
995*4882a593Smuzhiyun 			goto release_cluster_info;
996*4882a593Smuzhiyun 		}
997*4882a593Smuzhiyun #ifdef MODULE
998*4882a593Smuzhiyun 		cpu_latency_qos_add_request(&idle_pm_qos, PM_QOS_DEFAULT_VALUE);
999*4882a593Smuzhiyun #endif
1000*4882a593Smuzhiyun 	}
1001*4882a593Smuzhiyun 
1002*4882a593Smuzhiyun 	ret = atomic_notifier_chain_register(&panic_notifier_list,
1003*4882a593Smuzhiyun 					     &rockchip_cpufreq_panic_notifier_block);
1004*4882a593Smuzhiyun 	if (ret)
1005*4882a593Smuzhiyun 		pr_err("failed to register cpufreq panic notifier\n");
1006*4882a593Smuzhiyun 
1007*4882a593Smuzhiyun 	return PTR_ERR_OR_ZERO(platform_device_register_data(NULL, "cpufreq-dt",
1008*4882a593Smuzhiyun 			       -1, (void *)&pdata,
1009*4882a593Smuzhiyun 			       sizeof(struct cpufreq_dt_platform_data)));
1010*4882a593Smuzhiyun 
1011*4882a593Smuzhiyun release_cluster_info:
1012*4882a593Smuzhiyun 	list_for_each_entry_safe(cluster, pos, &cluster_info_list, list_head) {
1013*4882a593Smuzhiyun 		list_del(&cluster->list_head);
1014*4882a593Smuzhiyun 		kfree(cluster);
1015*4882a593Smuzhiyun 	}
1016*4882a593Smuzhiyun 	return ret;
1017*4882a593Smuzhiyun }
1018*4882a593Smuzhiyun module_init(rockchip_cpufreq_driver_init);
1019*4882a593Smuzhiyun 
1020*4882a593Smuzhiyun MODULE_AUTHOR("Finley Xiao <finley.xiao@rock-chips.com>");
1021*4882a593Smuzhiyun MODULE_DESCRIPTION("Rockchip cpufreq driver");
1022*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
1023