xref: /OK3568_Linux_fs/kernel/drivers/soc/rockchip/rockchip_system_monitor.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd
4*4882a593Smuzhiyun  * Author: Finley Xiao <finley.xiao@rock-chips.com>
5*4882a593Smuzhiyun  */
6*4882a593Smuzhiyun 
7*4882a593Smuzhiyun #include <dt-bindings/soc/rockchip-system-status.h>
8*4882a593Smuzhiyun #include <linux/clk-provider.h>
9*4882a593Smuzhiyun #include <linux/cpu.h>
10*4882a593Smuzhiyun #include <linux/cpufreq.h>
11*4882a593Smuzhiyun #include <linux/devfreq.h>
12*4882a593Smuzhiyun #include <linux/device.h>
13*4882a593Smuzhiyun #include <linux/fb.h>
14*4882a593Smuzhiyun #include <linux/module.h>
15*4882a593Smuzhiyun #include <linux/mutex.h>
16*4882a593Smuzhiyun #include <linux/notifier.h>
17*4882a593Smuzhiyun #include <linux/of.h>
18*4882a593Smuzhiyun #include <linux/platform_device.h>
19*4882a593Smuzhiyun #include <linux/pm_opp.h>
20*4882a593Smuzhiyun #include <linux/pm_qos.h>
21*4882a593Smuzhiyun #include <linux/pm_runtime.h>
22*4882a593Smuzhiyun #include <linux/regulator/consumer.h>
23*4882a593Smuzhiyun #include <linux/regulator/coupler.h>
24*4882a593Smuzhiyun #include <linux/regulator/driver.h>
25*4882a593Smuzhiyun #include <linux/regulator/machine.h>
26*4882a593Smuzhiyun #include <linux/reboot.h>
27*4882a593Smuzhiyun #include <linux/slab.h>
28*4882a593Smuzhiyun #include <linux/suspend.h>
29*4882a593Smuzhiyun #include <linux/thermal.h>
30*4882a593Smuzhiyun #include <linux/uaccess.h>
31*4882a593Smuzhiyun #include <linux/version.h>
32*4882a593Smuzhiyun #include <linux/delay.h>
33*4882a593Smuzhiyun #include <soc/rockchip/rockchip_opp_select.h>
34*4882a593Smuzhiyun #include <soc/rockchip/rockchip_system_monitor.h>
35*4882a593Smuzhiyun #include <soc/rockchip/rockchip-system-status.h>
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun #include "../../gpu/drm/rockchip/ebc-dev/ebc_dev.h"
38*4882a593Smuzhiyun #include "../../opp/opp.h"
39*4882a593Smuzhiyun #include "../../regulator/internal.h"
40*4882a593Smuzhiyun #include "../../thermal/thermal_core.h"
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun #define CPU_REBOOT_FREQ		816000 /* kHz */
43*4882a593Smuzhiyun #define VIDEO_1080P_SIZE	(1920 * 1080)
44*4882a593Smuzhiyun #define THERMAL_POLLING_DELAY	200 /* milliseconds */
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun struct video_info {
47*4882a593Smuzhiyun 	unsigned int width;
48*4882a593Smuzhiyun 	unsigned int height;
49*4882a593Smuzhiyun 	unsigned int ishevc;
50*4882a593Smuzhiyun 	unsigned int videoFramerate;
51*4882a593Smuzhiyun 	unsigned int streamBitrate;
52*4882a593Smuzhiyun 	struct list_head node;
53*4882a593Smuzhiyun };
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun struct system_monitor_attr {
56*4882a593Smuzhiyun 	struct attribute attr;
57*4882a593Smuzhiyun 	ssize_t (*show)(struct kobject *kobj, struct kobj_attribute *attr,
58*4882a593Smuzhiyun 			char *buf);
59*4882a593Smuzhiyun 	ssize_t (*store)(struct kobject *kobj, struct kobj_attribute *attr,
60*4882a593Smuzhiyun 			 const char *buf, size_t n);
61*4882a593Smuzhiyun };
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun struct system_monitor {
64*4882a593Smuzhiyun 	struct device *dev;
65*4882a593Smuzhiyun 	struct cpumask video_4k_offline_cpus;
66*4882a593Smuzhiyun 	struct cpumask status_offline_cpus;
67*4882a593Smuzhiyun 	struct cpumask temp_offline_cpus;
68*4882a593Smuzhiyun 	struct cpumask offline_cpus;
69*4882a593Smuzhiyun 	struct notifier_block status_nb;
70*4882a593Smuzhiyun 	struct kobject *kobj;
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun 	struct thermal_zone_device *tz;
73*4882a593Smuzhiyun 	struct delayed_work thermal_work;
74*4882a593Smuzhiyun 	int last_temp;
75*4882a593Smuzhiyun 	int offline_cpus_temp;
76*4882a593Smuzhiyun 	int temp_hysteresis;
77*4882a593Smuzhiyun 	unsigned int delay;
78*4882a593Smuzhiyun 	bool is_temp_offline;
79*4882a593Smuzhiyun };
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun static unsigned long system_status;
82*4882a593Smuzhiyun static unsigned long ref_count[32] = {0};
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun static DEFINE_MUTEX(system_status_mutex);
85*4882a593Smuzhiyun static DEFINE_MUTEX(video_info_mutex);
86*4882a593Smuzhiyun static DEFINE_MUTEX(cpu_on_off_mutex);
87*4882a593Smuzhiyun 
88*4882a593Smuzhiyun static DECLARE_RWSEM(mdev_list_sem);
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun static LIST_HEAD(video_info_list);
91*4882a593Smuzhiyun static LIST_HEAD(monitor_dev_list);
92*4882a593Smuzhiyun static struct system_monitor *system_monitor;
93*4882a593Smuzhiyun static atomic_t monitor_in_suspend;
94*4882a593Smuzhiyun 
95*4882a593Smuzhiyun static BLOCKING_NOTIFIER_HEAD(system_monitor_notifier_list);
96*4882a593Smuzhiyun static BLOCKING_NOTIFIER_HEAD(system_status_notifier_list);
97*4882a593Smuzhiyun 
rockchip_register_system_status_notifier(struct notifier_block * nb)98*4882a593Smuzhiyun int rockchip_register_system_status_notifier(struct notifier_block *nb)
99*4882a593Smuzhiyun {
100*4882a593Smuzhiyun 	return blocking_notifier_chain_register(&system_status_notifier_list,
101*4882a593Smuzhiyun 						nb);
102*4882a593Smuzhiyun }
103*4882a593Smuzhiyun EXPORT_SYMBOL(rockchip_register_system_status_notifier);
104*4882a593Smuzhiyun 
rockchip_unregister_system_status_notifier(struct notifier_block * nb)105*4882a593Smuzhiyun int rockchip_unregister_system_status_notifier(struct notifier_block *nb)
106*4882a593Smuzhiyun {
107*4882a593Smuzhiyun 	return blocking_notifier_chain_unregister(&system_status_notifier_list,
108*4882a593Smuzhiyun 						  nb);
109*4882a593Smuzhiyun }
110*4882a593Smuzhiyun EXPORT_SYMBOL(rockchip_unregister_system_status_notifier);
111*4882a593Smuzhiyun 
rockchip_system_status_notifier_call_chain(unsigned long val)112*4882a593Smuzhiyun static int rockchip_system_status_notifier_call_chain(unsigned long val)
113*4882a593Smuzhiyun {
114*4882a593Smuzhiyun 	int ret = blocking_notifier_call_chain(&system_status_notifier_list,
115*4882a593Smuzhiyun 					       val, NULL);
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun 	return notifier_to_errno(ret);
118*4882a593Smuzhiyun }
119*4882a593Smuzhiyun 
rockchip_set_system_status(unsigned long status)120*4882a593Smuzhiyun void rockchip_set_system_status(unsigned long status)
121*4882a593Smuzhiyun {
122*4882a593Smuzhiyun 	unsigned long old_system_status;
123*4882a593Smuzhiyun 	unsigned int single_status_offset;
124*4882a593Smuzhiyun 
125*4882a593Smuzhiyun 	mutex_lock(&system_status_mutex);
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun 	old_system_status = system_status;
128*4882a593Smuzhiyun 
129*4882a593Smuzhiyun 	while (status) {
130*4882a593Smuzhiyun 		single_status_offset = fls(status) - 1;
131*4882a593Smuzhiyun 		status &= ~(1 << single_status_offset);
132*4882a593Smuzhiyun 		if (ref_count[single_status_offset] == 0)
133*4882a593Smuzhiyun 			system_status |= 1 << single_status_offset;
134*4882a593Smuzhiyun 		ref_count[single_status_offset]++;
135*4882a593Smuzhiyun 	}
136*4882a593Smuzhiyun 
137*4882a593Smuzhiyun 	if (old_system_status != system_status)
138*4882a593Smuzhiyun 		rockchip_system_status_notifier_call_chain(system_status);
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun 	mutex_unlock(&system_status_mutex);
141*4882a593Smuzhiyun }
142*4882a593Smuzhiyun EXPORT_SYMBOL(rockchip_set_system_status);
143*4882a593Smuzhiyun 
rockchip_clear_system_status(unsigned long status)144*4882a593Smuzhiyun void rockchip_clear_system_status(unsigned long status)
145*4882a593Smuzhiyun {
146*4882a593Smuzhiyun 	unsigned long old_system_status;
147*4882a593Smuzhiyun 	unsigned int single_status_offset;
148*4882a593Smuzhiyun 
149*4882a593Smuzhiyun 	mutex_lock(&system_status_mutex);
150*4882a593Smuzhiyun 
151*4882a593Smuzhiyun 	old_system_status = system_status;
152*4882a593Smuzhiyun 
153*4882a593Smuzhiyun 	while (status) {
154*4882a593Smuzhiyun 		single_status_offset = fls(status) - 1;
155*4882a593Smuzhiyun 		status &= ~(1 << single_status_offset);
156*4882a593Smuzhiyun 		if (ref_count[single_status_offset] == 0) {
157*4882a593Smuzhiyun 			continue;
158*4882a593Smuzhiyun 		} else {
159*4882a593Smuzhiyun 			if (ref_count[single_status_offset] == 1)
160*4882a593Smuzhiyun 				system_status &= ~(1 << single_status_offset);
161*4882a593Smuzhiyun 			ref_count[single_status_offset]--;
162*4882a593Smuzhiyun 		}
163*4882a593Smuzhiyun 	}
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun 	if (old_system_status != system_status)
166*4882a593Smuzhiyun 		rockchip_system_status_notifier_call_chain(system_status);
167*4882a593Smuzhiyun 
168*4882a593Smuzhiyun 	mutex_unlock(&system_status_mutex);
169*4882a593Smuzhiyun }
170*4882a593Smuzhiyun EXPORT_SYMBOL(rockchip_clear_system_status);
171*4882a593Smuzhiyun 
rockchip_get_system_status(void)172*4882a593Smuzhiyun unsigned long rockchip_get_system_status(void)
173*4882a593Smuzhiyun {
174*4882a593Smuzhiyun 	return system_status;
175*4882a593Smuzhiyun }
176*4882a593Smuzhiyun EXPORT_SYMBOL(rockchip_get_system_status);
177*4882a593Smuzhiyun 
rockchip_add_system_status_interface(struct device * dev)178*4882a593Smuzhiyun int rockchip_add_system_status_interface(struct device *dev)
179*4882a593Smuzhiyun {
180*4882a593Smuzhiyun 	if (!system_monitor || !system_monitor->kobj) {
181*4882a593Smuzhiyun 		pr_err("failed to get system status kobj\n");
182*4882a593Smuzhiyun 		return -EINVAL;
183*4882a593Smuzhiyun 	}
184*4882a593Smuzhiyun 
185*4882a593Smuzhiyun 	return compat_only_sysfs_link_entry_to_kobj(&dev->kobj,
186*4882a593Smuzhiyun 						    system_monitor->kobj,
187*4882a593Smuzhiyun 						    "system_status", NULL);
188*4882a593Smuzhiyun }
189*4882a593Smuzhiyun EXPORT_SYMBOL(rockchip_add_system_status_interface);
190*4882a593Smuzhiyun 
rockchip_get_video_param(char ** str)191*4882a593Smuzhiyun static unsigned long rockchip_get_video_param(char **str)
192*4882a593Smuzhiyun {
193*4882a593Smuzhiyun 	char *p;
194*4882a593Smuzhiyun 	unsigned long val = 0;
195*4882a593Smuzhiyun 
196*4882a593Smuzhiyun 	strsep(str, "=");
197*4882a593Smuzhiyun 	p = strsep(str, ",");
198*4882a593Smuzhiyun 	if (p) {
199*4882a593Smuzhiyun 		if (kstrtoul(p, 10, &val))
200*4882a593Smuzhiyun 			return 0;
201*4882a593Smuzhiyun 	}
202*4882a593Smuzhiyun 
203*4882a593Smuzhiyun 	return val;
204*4882a593Smuzhiyun }
205*4882a593Smuzhiyun 
206*4882a593Smuzhiyun /*
207*4882a593Smuzhiyun  * format:
208*4882a593Smuzhiyun  * 0,width=val,height=val,ishevc=val,videoFramerate=val,streamBitrate=val
209*4882a593Smuzhiyun  * 1,width=val,height=val,ishevc=val,videoFramerate=val,streamBitrate=val
210*4882a593Smuzhiyun  */
rockchip_parse_video_info(const char * buf)211*4882a593Smuzhiyun static struct video_info *rockchip_parse_video_info(const char *buf)
212*4882a593Smuzhiyun {
213*4882a593Smuzhiyun 	struct video_info *video_info;
214*4882a593Smuzhiyun 	const char *cp = buf;
215*4882a593Smuzhiyun 	char *str, *p;
216*4882a593Smuzhiyun 	int ntokens = 0;
217*4882a593Smuzhiyun 
218*4882a593Smuzhiyun 	while ((cp = strpbrk(cp + 1, ",")))
219*4882a593Smuzhiyun 		ntokens++;
220*4882a593Smuzhiyun 	if (ntokens != 5)
221*4882a593Smuzhiyun 		return NULL;
222*4882a593Smuzhiyun 
223*4882a593Smuzhiyun 	video_info = kzalloc(sizeof(*video_info), GFP_KERNEL);
224*4882a593Smuzhiyun 	if (!video_info)
225*4882a593Smuzhiyun 		return NULL;
226*4882a593Smuzhiyun 
227*4882a593Smuzhiyun 	INIT_LIST_HEAD(&video_info->node);
228*4882a593Smuzhiyun 
229*4882a593Smuzhiyun 	str = kstrdup(buf, GFP_KERNEL);
230*4882a593Smuzhiyun 	p = str;
231*4882a593Smuzhiyun 	strsep(&p, ",");
232*4882a593Smuzhiyun 	video_info->width = rockchip_get_video_param(&p);
233*4882a593Smuzhiyun 	video_info->height = rockchip_get_video_param(&p);
234*4882a593Smuzhiyun 	video_info->ishevc = rockchip_get_video_param(&p);
235*4882a593Smuzhiyun 	video_info->videoFramerate = rockchip_get_video_param(&p);
236*4882a593Smuzhiyun 	video_info->streamBitrate = rockchip_get_video_param(&p);
237*4882a593Smuzhiyun 	pr_debug("%c,width=%d,height=%d,ishevc=%d,videoFramerate=%d,streamBitrate=%d\n",
238*4882a593Smuzhiyun 		 buf[0],
239*4882a593Smuzhiyun 		 video_info->width,
240*4882a593Smuzhiyun 		 video_info->height,
241*4882a593Smuzhiyun 		 video_info->ishevc,
242*4882a593Smuzhiyun 		 video_info->videoFramerate,
243*4882a593Smuzhiyun 		 video_info->streamBitrate);
244*4882a593Smuzhiyun 	kfree(str);
245*4882a593Smuzhiyun 
246*4882a593Smuzhiyun 	return video_info;
247*4882a593Smuzhiyun }
248*4882a593Smuzhiyun 
rockchip_find_video_info(const char * buf)249*4882a593Smuzhiyun static struct video_info *rockchip_find_video_info(const char *buf)
250*4882a593Smuzhiyun {
251*4882a593Smuzhiyun 	struct video_info *info, *video_info;
252*4882a593Smuzhiyun 
253*4882a593Smuzhiyun 	video_info = rockchip_parse_video_info(buf);
254*4882a593Smuzhiyun 
255*4882a593Smuzhiyun 	if (!video_info)
256*4882a593Smuzhiyun 		return NULL;
257*4882a593Smuzhiyun 
258*4882a593Smuzhiyun 	mutex_lock(&video_info_mutex);
259*4882a593Smuzhiyun 	list_for_each_entry(info, &video_info_list, node) {
260*4882a593Smuzhiyun 		if (info->width == video_info->width &&
261*4882a593Smuzhiyun 		    info->height == video_info->height &&
262*4882a593Smuzhiyun 		    info->ishevc == video_info->ishevc &&
263*4882a593Smuzhiyun 		    info->videoFramerate == video_info->videoFramerate &&
264*4882a593Smuzhiyun 		    info->streamBitrate == video_info->streamBitrate) {
265*4882a593Smuzhiyun 			mutex_unlock(&video_info_mutex);
266*4882a593Smuzhiyun 			kfree(video_info);
267*4882a593Smuzhiyun 			return info;
268*4882a593Smuzhiyun 		}
269*4882a593Smuzhiyun 	}
270*4882a593Smuzhiyun 
271*4882a593Smuzhiyun 	mutex_unlock(&video_info_mutex);
272*4882a593Smuzhiyun 	kfree(video_info);
273*4882a593Smuzhiyun 
274*4882a593Smuzhiyun 	return NULL;
275*4882a593Smuzhiyun }
276*4882a593Smuzhiyun 
rockchip_add_video_info(struct video_info * video_info)277*4882a593Smuzhiyun static void rockchip_add_video_info(struct video_info *video_info)
278*4882a593Smuzhiyun {
279*4882a593Smuzhiyun 	if (video_info) {
280*4882a593Smuzhiyun 		mutex_lock(&video_info_mutex);
281*4882a593Smuzhiyun 		list_add(&video_info->node, &video_info_list);
282*4882a593Smuzhiyun 		mutex_unlock(&video_info_mutex);
283*4882a593Smuzhiyun 	}
284*4882a593Smuzhiyun }
285*4882a593Smuzhiyun 
rockchip_del_video_info(struct video_info * video_info)286*4882a593Smuzhiyun static void rockchip_del_video_info(struct video_info *video_info)
287*4882a593Smuzhiyun {
288*4882a593Smuzhiyun 	if (video_info) {
289*4882a593Smuzhiyun 		mutex_lock(&video_info_mutex);
290*4882a593Smuzhiyun 		list_del(&video_info->node);
291*4882a593Smuzhiyun 		mutex_unlock(&video_info_mutex);
292*4882a593Smuzhiyun 		kfree(video_info);
293*4882a593Smuzhiyun 	}
294*4882a593Smuzhiyun }
295*4882a593Smuzhiyun 
rockchip_update_video_info(void)296*4882a593Smuzhiyun static void rockchip_update_video_info(void)
297*4882a593Smuzhiyun {
298*4882a593Smuzhiyun 	struct video_info *video_info;
299*4882a593Smuzhiyun 	unsigned int max_res = 0, max_stream_bitrate = 0, res = 0;
300*4882a593Smuzhiyun 	unsigned int max_video_framerate = 0;
301*4882a593Smuzhiyun 
302*4882a593Smuzhiyun 	mutex_lock(&video_info_mutex);
303*4882a593Smuzhiyun 	if (list_empty(&video_info_list)) {
304*4882a593Smuzhiyun 		mutex_unlock(&video_info_mutex);
305*4882a593Smuzhiyun 		rockchip_clear_system_status(SYS_STATUS_VIDEO);
306*4882a593Smuzhiyun 		return;
307*4882a593Smuzhiyun 	}
308*4882a593Smuzhiyun 
309*4882a593Smuzhiyun 	list_for_each_entry(video_info, &video_info_list, node) {
310*4882a593Smuzhiyun 		res = video_info->width * video_info->height;
311*4882a593Smuzhiyun 		if (res > max_res)
312*4882a593Smuzhiyun 			max_res = res;
313*4882a593Smuzhiyun 		if (video_info->streamBitrate > max_stream_bitrate)
314*4882a593Smuzhiyun 			max_stream_bitrate = video_info->streamBitrate;
315*4882a593Smuzhiyun 		if (video_info->videoFramerate > max_video_framerate)
316*4882a593Smuzhiyun 			max_video_framerate = video_info->videoFramerate;
317*4882a593Smuzhiyun 	}
318*4882a593Smuzhiyun 	mutex_unlock(&video_info_mutex);
319*4882a593Smuzhiyun 
320*4882a593Smuzhiyun 	if (max_res <= VIDEO_1080P_SIZE) {
321*4882a593Smuzhiyun 		rockchip_set_system_status(SYS_STATUS_VIDEO_1080P);
322*4882a593Smuzhiyun 	} else {
323*4882a593Smuzhiyun 		if (max_stream_bitrate == 10)
324*4882a593Smuzhiyun 			rockchip_set_system_status(SYS_STATUS_VIDEO_4K_10B);
325*4882a593Smuzhiyun 		if (max_video_framerate == 60)
326*4882a593Smuzhiyun 			rockchip_set_system_status(SYS_STATUS_VIDEO_4K_60P);
327*4882a593Smuzhiyun 		rockchip_set_system_status(SYS_STATUS_VIDEO_4K);
328*4882a593Smuzhiyun 	}
329*4882a593Smuzhiyun }
330*4882a593Smuzhiyun 
rockchip_update_system_status(const char * buf)331*4882a593Smuzhiyun void rockchip_update_system_status(const char *buf)
332*4882a593Smuzhiyun {
333*4882a593Smuzhiyun 	struct video_info *video_info;
334*4882a593Smuzhiyun 
335*4882a593Smuzhiyun 	if (!buf)
336*4882a593Smuzhiyun 		return;
337*4882a593Smuzhiyun 
338*4882a593Smuzhiyun 	switch (buf[0]) {
339*4882a593Smuzhiyun 	case '0':
340*4882a593Smuzhiyun 		/* clear video flag */
341*4882a593Smuzhiyun 		video_info = rockchip_find_video_info(buf);
342*4882a593Smuzhiyun 		if (video_info) {
343*4882a593Smuzhiyun 			rockchip_del_video_info(video_info);
344*4882a593Smuzhiyun 			rockchip_update_video_info();
345*4882a593Smuzhiyun 		}
346*4882a593Smuzhiyun 		break;
347*4882a593Smuzhiyun 	case '1':
348*4882a593Smuzhiyun 		/* set video flag */
349*4882a593Smuzhiyun 		video_info = rockchip_parse_video_info(buf);
350*4882a593Smuzhiyun 		if (video_info) {
351*4882a593Smuzhiyun 			rockchip_add_video_info(video_info);
352*4882a593Smuzhiyun 			rockchip_update_video_info();
353*4882a593Smuzhiyun 		}
354*4882a593Smuzhiyun 		break;
355*4882a593Smuzhiyun 	case 'L':
356*4882a593Smuzhiyun 		/* clear low power flag */
357*4882a593Smuzhiyun 		rockchip_clear_system_status(SYS_STATUS_LOW_POWER);
358*4882a593Smuzhiyun 		break;
359*4882a593Smuzhiyun 	case 'l':
360*4882a593Smuzhiyun 		/* set low power flag */
361*4882a593Smuzhiyun 		rockchip_set_system_status(SYS_STATUS_LOW_POWER);
362*4882a593Smuzhiyun 		break;
363*4882a593Smuzhiyun 	case 'p':
364*4882a593Smuzhiyun 		/* set performance flag */
365*4882a593Smuzhiyun 		rockchip_set_system_status(SYS_STATUS_PERFORMANCE);
366*4882a593Smuzhiyun 		break;
367*4882a593Smuzhiyun 	case 'n':
368*4882a593Smuzhiyun 		/* clear performance flag */
369*4882a593Smuzhiyun 		rockchip_clear_system_status(SYS_STATUS_PERFORMANCE);
370*4882a593Smuzhiyun 		break;
371*4882a593Smuzhiyun 	case 'S':
372*4882a593Smuzhiyun 		/* set video svep flag */
373*4882a593Smuzhiyun 		rockchip_set_system_status(SYS_STATUS_VIDEO_SVEP);
374*4882a593Smuzhiyun 		break;
375*4882a593Smuzhiyun 	case 's':
376*4882a593Smuzhiyun 		/* clear video svep flag */
377*4882a593Smuzhiyun 		rockchip_clear_system_status(SYS_STATUS_VIDEO_SVEP);
378*4882a593Smuzhiyun 		break;
379*4882a593Smuzhiyun 	default:
380*4882a593Smuzhiyun 		break;
381*4882a593Smuzhiyun 	}
382*4882a593Smuzhiyun }
383*4882a593Smuzhiyun EXPORT_SYMBOL(rockchip_update_system_status);
384*4882a593Smuzhiyun 
status_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)385*4882a593Smuzhiyun static ssize_t status_show(struct kobject *kobj, struct kobj_attribute *attr,
386*4882a593Smuzhiyun 			   char *buf)
387*4882a593Smuzhiyun {
388*4882a593Smuzhiyun 	unsigned int status = rockchip_get_system_status();
389*4882a593Smuzhiyun 
390*4882a593Smuzhiyun 	return sprintf(buf, "0x%x\n", status);
391*4882a593Smuzhiyun }
392*4882a593Smuzhiyun 
status_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t n)393*4882a593Smuzhiyun static ssize_t status_store(struct kobject *kobj, struct kobj_attribute *attr,
394*4882a593Smuzhiyun 			    const char *buf, size_t n)
395*4882a593Smuzhiyun {
396*4882a593Smuzhiyun 	if (!n)
397*4882a593Smuzhiyun 		return -EINVAL;
398*4882a593Smuzhiyun 
399*4882a593Smuzhiyun 	rockchip_update_system_status(buf);
400*4882a593Smuzhiyun 
401*4882a593Smuzhiyun 	return n;
402*4882a593Smuzhiyun }
403*4882a593Smuzhiyun 
404*4882a593Smuzhiyun static struct system_monitor_attr status =
405*4882a593Smuzhiyun 	__ATTR(system_status, 0644, status_show, status_store);
406*4882a593Smuzhiyun 
rockchip_get_temp_freq_table(struct device_node * np,char * porp_name,struct temp_freq_table ** freq_table)407*4882a593Smuzhiyun static int rockchip_get_temp_freq_table(struct device_node *np,
408*4882a593Smuzhiyun 					char *porp_name,
409*4882a593Smuzhiyun 					struct temp_freq_table **freq_table)
410*4882a593Smuzhiyun {
411*4882a593Smuzhiyun 	struct temp_freq_table *table;
412*4882a593Smuzhiyun 	const struct property *prop;
413*4882a593Smuzhiyun 	int count, i;
414*4882a593Smuzhiyun 
415*4882a593Smuzhiyun 	prop = of_find_property(np, porp_name, NULL);
416*4882a593Smuzhiyun 	if (!prop)
417*4882a593Smuzhiyun 		return -EINVAL;
418*4882a593Smuzhiyun 
419*4882a593Smuzhiyun 	if (!prop->value)
420*4882a593Smuzhiyun 		return -ENODATA;
421*4882a593Smuzhiyun 
422*4882a593Smuzhiyun 	count = of_property_count_u32_elems(np, porp_name);
423*4882a593Smuzhiyun 	if (count < 0)
424*4882a593Smuzhiyun 		return -EINVAL;
425*4882a593Smuzhiyun 
426*4882a593Smuzhiyun 	if (count % 2)
427*4882a593Smuzhiyun 		return -EINVAL;
428*4882a593Smuzhiyun 
429*4882a593Smuzhiyun 	table = kzalloc(sizeof(*table) * (count / 2 + 1), GFP_KERNEL);
430*4882a593Smuzhiyun 	if (!table)
431*4882a593Smuzhiyun 		return -ENOMEM;
432*4882a593Smuzhiyun 
433*4882a593Smuzhiyun 	for (i = 0; i < count / 2; i++) {
434*4882a593Smuzhiyun 		of_property_read_u32_index(np, porp_name, 2 * i,
435*4882a593Smuzhiyun 					   &table[i].temp);
436*4882a593Smuzhiyun 		of_property_read_u32_index(np, porp_name, 2 * i + 1,
437*4882a593Smuzhiyun 					   &table[i].freq);
438*4882a593Smuzhiyun 	}
439*4882a593Smuzhiyun 	table[i].freq = UINT_MAX;
440*4882a593Smuzhiyun 	*freq_table = table;
441*4882a593Smuzhiyun 
442*4882a593Smuzhiyun 	return 0;
443*4882a593Smuzhiyun }
444*4882a593Smuzhiyun 
rockchip_get_adjust_volt_table(struct device_node * np,char * porp_name,struct volt_adjust_table ** table)445*4882a593Smuzhiyun static int rockchip_get_adjust_volt_table(struct device_node *np,
446*4882a593Smuzhiyun 					  char *porp_name,
447*4882a593Smuzhiyun 					  struct volt_adjust_table **table)
448*4882a593Smuzhiyun {
449*4882a593Smuzhiyun 	struct volt_adjust_table *volt_table;
450*4882a593Smuzhiyun 	const struct property *prop;
451*4882a593Smuzhiyun 	int count, i;
452*4882a593Smuzhiyun 
453*4882a593Smuzhiyun 	prop = of_find_property(np, porp_name, NULL);
454*4882a593Smuzhiyun 	if (!prop)
455*4882a593Smuzhiyun 		return -EINVAL;
456*4882a593Smuzhiyun 
457*4882a593Smuzhiyun 	if (!prop->value)
458*4882a593Smuzhiyun 		return -ENODATA;
459*4882a593Smuzhiyun 
460*4882a593Smuzhiyun 	count = of_property_count_u32_elems(np, porp_name);
461*4882a593Smuzhiyun 	if (count < 0)
462*4882a593Smuzhiyun 		return -EINVAL;
463*4882a593Smuzhiyun 
464*4882a593Smuzhiyun 	if (count % 3)
465*4882a593Smuzhiyun 		return -EINVAL;
466*4882a593Smuzhiyun 
467*4882a593Smuzhiyun 	volt_table = kzalloc(sizeof(*volt_table) * (count / 3 + 1), GFP_KERNEL);
468*4882a593Smuzhiyun 	if (!volt_table)
469*4882a593Smuzhiyun 		return -ENOMEM;
470*4882a593Smuzhiyun 
471*4882a593Smuzhiyun 	for (i = 0; i < count / 3; i++) {
472*4882a593Smuzhiyun 		of_property_read_u32_index(np, porp_name, 3 * i,
473*4882a593Smuzhiyun 					   &volt_table[i].min);
474*4882a593Smuzhiyun 		of_property_read_u32_index(np, porp_name, 3 * i + 1,
475*4882a593Smuzhiyun 					   &volt_table[i].max);
476*4882a593Smuzhiyun 		of_property_read_u32_index(np, porp_name, 3 * i + 2,
477*4882a593Smuzhiyun 					   &volt_table[i].volt);
478*4882a593Smuzhiyun 	}
479*4882a593Smuzhiyun 	volt_table[i].min = 0;
480*4882a593Smuzhiyun 	volt_table[i].max = 0;
481*4882a593Smuzhiyun 	volt_table[i].volt = INT_MAX;
482*4882a593Smuzhiyun 
483*4882a593Smuzhiyun 	*table = volt_table;
484*4882a593Smuzhiyun 
485*4882a593Smuzhiyun 	return 0;
486*4882a593Smuzhiyun }
487*4882a593Smuzhiyun 
rockchip_get_low_temp_volt(struct monitor_dev_info * info,unsigned long rate,int * delta_volt)488*4882a593Smuzhiyun static int rockchip_get_low_temp_volt(struct monitor_dev_info *info,
489*4882a593Smuzhiyun 				      unsigned long rate, int *delta_volt)
490*4882a593Smuzhiyun {
491*4882a593Smuzhiyun 	int i, ret = -EINVAL;
492*4882a593Smuzhiyun 	unsigned int _rate = (unsigned int)(rate / 1000000);
493*4882a593Smuzhiyun 
494*4882a593Smuzhiyun 	if (!info->low_temp_adjust_table)
495*4882a593Smuzhiyun 		return ret;
496*4882a593Smuzhiyun 
497*4882a593Smuzhiyun 	for (i = 0; info->low_temp_adjust_table[i].volt != INT_MAX; i++) {
498*4882a593Smuzhiyun 		if (_rate >= info->low_temp_adjust_table[i].min &&
499*4882a593Smuzhiyun 		    _rate <= info->low_temp_adjust_table[i].max) {
500*4882a593Smuzhiyun 			*delta_volt = info->low_temp_adjust_table[i].volt;
501*4882a593Smuzhiyun 			ret = 0;
502*4882a593Smuzhiyun 		}
503*4882a593Smuzhiyun 	}
504*4882a593Smuzhiyun 
505*4882a593Smuzhiyun 	return ret;
506*4882a593Smuzhiyun }
507*4882a593Smuzhiyun 
rockchip_init_temp_opp_table(struct monitor_dev_info * info)508*4882a593Smuzhiyun static int rockchip_init_temp_opp_table(struct monitor_dev_info *info)
509*4882a593Smuzhiyun {
510*4882a593Smuzhiyun 	struct device *dev = info->dev;
511*4882a593Smuzhiyun 	struct opp_table *opp_table;
512*4882a593Smuzhiyun 	struct dev_pm_opp *opp;
513*4882a593Smuzhiyun 	int delta_volt = 0;
514*4882a593Smuzhiyun 	int i = 0, max_count;
515*4882a593Smuzhiyun 	unsigned long low_limit = 0, high_limit = 0;
516*4882a593Smuzhiyun 	unsigned long low_limit_mem = 0, high_limit_mem = 0;
517*4882a593Smuzhiyun 	bool reach_max_volt = false;
518*4882a593Smuzhiyun 	bool reach_max_mem_volt = false;
519*4882a593Smuzhiyun 	bool reach_high_temp_max_volt = false;
520*4882a593Smuzhiyun 	bool reach_high_temp_max_mem_volt = false;
521*4882a593Smuzhiyun 
522*4882a593Smuzhiyun 	max_count = dev_pm_opp_get_opp_count(dev);
523*4882a593Smuzhiyun 	if (max_count <= 0)
524*4882a593Smuzhiyun 		return max_count ? max_count : -ENODATA;
525*4882a593Smuzhiyun 	info->opp_table = kzalloc(sizeof(*info->opp_table) * max_count,
526*4882a593Smuzhiyun 				  GFP_KERNEL);
527*4882a593Smuzhiyun 	if (!info->opp_table)
528*4882a593Smuzhiyun 		return -ENOMEM;
529*4882a593Smuzhiyun 
530*4882a593Smuzhiyun 	opp_table = dev_pm_opp_get_opp_table(dev);
531*4882a593Smuzhiyun 	if (!opp_table) {
532*4882a593Smuzhiyun 		kfree(info->opp_table);
533*4882a593Smuzhiyun 		info->opp_table = NULL;
534*4882a593Smuzhiyun 		return -ENOMEM;
535*4882a593Smuzhiyun 	}
536*4882a593Smuzhiyun 	mutex_lock(&opp_table->lock);
537*4882a593Smuzhiyun 	list_for_each_entry(opp, &opp_table->opp_list, node) {
538*4882a593Smuzhiyun 		if (!opp->available)
539*4882a593Smuzhiyun 			continue;
540*4882a593Smuzhiyun 		info->opp_table[i].rate = opp->rate;
541*4882a593Smuzhiyun 		info->opp_table[i].volt = opp->supplies[0].u_volt;
542*4882a593Smuzhiyun 		info->opp_table[i].max_volt = opp->supplies[0].u_volt_max;
543*4882a593Smuzhiyun 
544*4882a593Smuzhiyun 		if (opp->supplies[0].u_volt <= info->high_temp_max_volt) {
545*4882a593Smuzhiyun 			if (!reach_high_temp_max_volt)
546*4882a593Smuzhiyun 				high_limit = opp->rate;
547*4882a593Smuzhiyun 			if (opp->supplies[0].u_volt == info->high_temp_max_volt)
548*4882a593Smuzhiyun 				reach_high_temp_max_volt = true;
549*4882a593Smuzhiyun 		}
550*4882a593Smuzhiyun 
551*4882a593Smuzhiyun 		if (rockchip_get_low_temp_volt(info, opp->rate, &delta_volt))
552*4882a593Smuzhiyun 			delta_volt = 0;
553*4882a593Smuzhiyun 		if ((opp->supplies[0].u_volt + delta_volt) <= info->max_volt) {
554*4882a593Smuzhiyun 			info->opp_table[i].low_temp_volt =
555*4882a593Smuzhiyun 				opp->supplies[0].u_volt + delta_volt;
556*4882a593Smuzhiyun 			if (info->opp_table[i].low_temp_volt <
557*4882a593Smuzhiyun 			    info->low_temp_min_volt)
558*4882a593Smuzhiyun 				info->opp_table[i].low_temp_volt =
559*4882a593Smuzhiyun 					info->low_temp_min_volt;
560*4882a593Smuzhiyun 			if (!reach_max_volt)
561*4882a593Smuzhiyun 				low_limit = opp->rate;
562*4882a593Smuzhiyun 			if (info->opp_table[i].low_temp_volt == info->max_volt)
563*4882a593Smuzhiyun 				reach_max_volt = true;
564*4882a593Smuzhiyun 		} else {
565*4882a593Smuzhiyun 			info->opp_table[i].low_temp_volt = info->max_volt;
566*4882a593Smuzhiyun 		}
567*4882a593Smuzhiyun 		if (low_limit && low_limit != opp->rate)
568*4882a593Smuzhiyun 			info->low_limit = low_limit;
569*4882a593Smuzhiyun 		if (high_limit && high_limit != opp->rate)
570*4882a593Smuzhiyun 			info->high_limit = high_limit;
571*4882a593Smuzhiyun 
572*4882a593Smuzhiyun 		if (opp_table->regulator_count > 1) {
573*4882a593Smuzhiyun 			info->opp_table[i].mem_volt = opp->supplies[1].u_volt;
574*4882a593Smuzhiyun 			info->opp_table[i].max_mem_volt = opp->supplies[1].u_volt_max;
575*4882a593Smuzhiyun 
576*4882a593Smuzhiyun 			if (opp->supplies[1].u_volt <= info->high_temp_max_volt) {
577*4882a593Smuzhiyun 				if (!reach_high_temp_max_mem_volt)
578*4882a593Smuzhiyun 					high_limit_mem = opp->rate;
579*4882a593Smuzhiyun 				if (opp->supplies[1].u_volt == info->high_temp_max_volt)
580*4882a593Smuzhiyun 					reach_high_temp_max_mem_volt = true;
581*4882a593Smuzhiyun 			}
582*4882a593Smuzhiyun 
583*4882a593Smuzhiyun 			if ((opp->supplies[1].u_volt + delta_volt) <= info->max_volt) {
584*4882a593Smuzhiyun 				info->opp_table[i].low_temp_mem_volt =
585*4882a593Smuzhiyun 					opp->supplies[1].u_volt + delta_volt;
586*4882a593Smuzhiyun 				if (info->opp_table[i].low_temp_mem_volt <
587*4882a593Smuzhiyun 				    info->low_temp_min_volt)
588*4882a593Smuzhiyun 					info->opp_table[i].low_temp_mem_volt =
589*4882a593Smuzhiyun 						info->low_temp_min_volt;
590*4882a593Smuzhiyun 				if (!reach_max_mem_volt)
591*4882a593Smuzhiyun 					low_limit_mem = opp->rate;
592*4882a593Smuzhiyun 				if (info->opp_table[i].low_temp_mem_volt == info->max_volt)
593*4882a593Smuzhiyun 					reach_max_mem_volt = true;
594*4882a593Smuzhiyun 			} else {
595*4882a593Smuzhiyun 				info->opp_table[i].low_temp_mem_volt = info->max_volt;
596*4882a593Smuzhiyun 			}
597*4882a593Smuzhiyun 
598*4882a593Smuzhiyun 			if (low_limit_mem && low_limit_mem != opp->rate) {
599*4882a593Smuzhiyun 				if (info->low_limit > low_limit_mem)
600*4882a593Smuzhiyun 					info->low_limit = low_limit_mem;
601*4882a593Smuzhiyun 			}
602*4882a593Smuzhiyun 			if (high_limit_mem && high_limit_mem != opp->rate) {
603*4882a593Smuzhiyun 				if (info->high_limit > high_limit_mem)
604*4882a593Smuzhiyun 					info->high_limit = high_limit_mem;
605*4882a593Smuzhiyun 			}
606*4882a593Smuzhiyun 		}
607*4882a593Smuzhiyun 
608*4882a593Smuzhiyun 		dev_dbg(dev, "rate=%lu, volt=%lu %lu low_temp_volt=%lu %lu\n",
609*4882a593Smuzhiyun 			info->opp_table[i].rate, info->opp_table[i].volt,
610*4882a593Smuzhiyun 			info->opp_table[i].mem_volt,
611*4882a593Smuzhiyun 			info->opp_table[i].low_temp_volt,
612*4882a593Smuzhiyun 			info->opp_table[i].low_temp_mem_volt);
613*4882a593Smuzhiyun 		i++;
614*4882a593Smuzhiyun 	}
615*4882a593Smuzhiyun 	mutex_unlock(&opp_table->lock);
616*4882a593Smuzhiyun 
617*4882a593Smuzhiyun 	dev_pm_opp_put_opp_table(opp_table);
618*4882a593Smuzhiyun 
619*4882a593Smuzhiyun 	return 0;
620*4882a593Smuzhiyun }
621*4882a593Smuzhiyun 
monitor_device_parse_wide_temp_config(struct device_node * np,struct monitor_dev_info * info)622*4882a593Smuzhiyun static int monitor_device_parse_wide_temp_config(struct device_node *np,
623*4882a593Smuzhiyun 						 struct monitor_dev_info *info)
624*4882a593Smuzhiyun {
625*4882a593Smuzhiyun 	struct device *dev = info->dev;
626*4882a593Smuzhiyun 	unsigned long high_temp_max_freq;
627*4882a593Smuzhiyun 	int ret = 0;
628*4882a593Smuzhiyun 	u32 value;
629*4882a593Smuzhiyun 
630*4882a593Smuzhiyun 	np = of_parse_phandle(dev->of_node, "operating-points-v2", 0);
631*4882a593Smuzhiyun 	if (!np)
632*4882a593Smuzhiyun 		return -EINVAL;
633*4882a593Smuzhiyun 
634*4882a593Smuzhiyun 	if (of_property_read_u32(np, "rockchip,max-volt", &value))
635*4882a593Smuzhiyun 		info->max_volt = ULONG_MAX;
636*4882a593Smuzhiyun 	else
637*4882a593Smuzhiyun 		info->max_volt = value;
638*4882a593Smuzhiyun 	of_property_read_u32(np, "rockchip,temp-hysteresis",
639*4882a593Smuzhiyun 			     &info->temp_hysteresis);
640*4882a593Smuzhiyun 	if (of_property_read_u32(np, "rockchip,low-temp", &info->low_temp))
641*4882a593Smuzhiyun 		info->low_temp = INT_MIN;
642*4882a593Smuzhiyun 	rockchip_get_adjust_volt_table(np, "rockchip,low-temp-adjust-volt",
643*4882a593Smuzhiyun 				       &info->low_temp_adjust_table);
644*4882a593Smuzhiyun 	if (!of_property_read_u32(np, "rockchip,low-temp-min-volt", &value))
645*4882a593Smuzhiyun 		info->low_temp_min_volt = value;
646*4882a593Smuzhiyun 	if (of_property_read_u32(np, "rockchip,high-temp", &info->high_temp))
647*4882a593Smuzhiyun 		info->high_temp = INT_MAX;
648*4882a593Smuzhiyun 	if (of_property_read_u32(np, "rockchip,high-temp-max-volt",
649*4882a593Smuzhiyun 				 &value))
650*4882a593Smuzhiyun 		info->high_temp_max_volt = ULONG_MAX;
651*4882a593Smuzhiyun 	else
652*4882a593Smuzhiyun 		info->high_temp_max_volt = value;
653*4882a593Smuzhiyun 	rockchip_init_temp_opp_table(info);
654*4882a593Smuzhiyun 	rockchip_get_temp_freq_table(np, "rockchip,temp-freq-table",
655*4882a593Smuzhiyun 				     &info->high_limit_table);
656*4882a593Smuzhiyun 	if (!info->high_limit_table)
657*4882a593Smuzhiyun 		rockchip_get_temp_freq_table(np, "rockchip,high-temp-limit-table",
658*4882a593Smuzhiyun 					     &info->high_limit_table);
659*4882a593Smuzhiyun 	if (!info->high_limit_table) {
660*4882a593Smuzhiyun 		if (!of_property_read_u32(np, "rockchip,high-temp-max-freq",
661*4882a593Smuzhiyun 					  &value)) {
662*4882a593Smuzhiyun 			high_temp_max_freq = value * 1000;
663*4882a593Smuzhiyun 			if (info->high_limit)
664*4882a593Smuzhiyun 				info->high_limit = min(high_temp_max_freq,
665*4882a593Smuzhiyun 						       info->high_limit);
666*4882a593Smuzhiyun 			else
667*4882a593Smuzhiyun 				info->high_limit = high_temp_max_freq;
668*4882a593Smuzhiyun 		}
669*4882a593Smuzhiyun 	} else {
670*4882a593Smuzhiyun 		info->high_limit = 0;
671*4882a593Smuzhiyun 	}
672*4882a593Smuzhiyun 	dev_info(dev, "l=%d h=%d hyst=%d l_limit=%lu h_limit=%lu h_table=%d\n",
673*4882a593Smuzhiyun 		 info->low_temp, info->high_temp, info->temp_hysteresis,
674*4882a593Smuzhiyun 		 info->low_limit, info->high_limit,
675*4882a593Smuzhiyun 		 info->high_limit_table ? true : false);
676*4882a593Smuzhiyun 
677*4882a593Smuzhiyun 	if ((info->low_temp + info->temp_hysteresis) > info->high_temp) {
678*4882a593Smuzhiyun 		dev_err(dev, "Invalid temperature, low=%d high=%d hyst=%d\n",
679*4882a593Smuzhiyun 			info->low_temp, info->high_temp,
680*4882a593Smuzhiyun 			info->temp_hysteresis);
681*4882a593Smuzhiyun 		ret = -EINVAL;
682*4882a593Smuzhiyun 		goto err;
683*4882a593Smuzhiyun 	}
684*4882a593Smuzhiyun 	if (!info->low_temp_adjust_table && !info->low_temp_min_volt &&
685*4882a593Smuzhiyun 	    !info->low_limit && !info->high_limit && !info->high_limit_table) {
686*4882a593Smuzhiyun 		ret = -EINVAL;
687*4882a593Smuzhiyun 		goto err;
688*4882a593Smuzhiyun 	}
689*4882a593Smuzhiyun 	if (info->low_temp_adjust_table || info->low_temp_min_volt)
690*4882a593Smuzhiyun 		info->is_low_temp_enabled = true;
691*4882a593Smuzhiyun 
692*4882a593Smuzhiyun 	return 0;
693*4882a593Smuzhiyun err:
694*4882a593Smuzhiyun 	kfree(info->low_temp_adjust_table);
695*4882a593Smuzhiyun 	info->low_temp_adjust_table = NULL;
696*4882a593Smuzhiyun 	kfree(info->opp_table);
697*4882a593Smuzhiyun 	info->opp_table = NULL;
698*4882a593Smuzhiyun 
699*4882a593Smuzhiyun 	return ret;
700*4882a593Smuzhiyun }
701*4882a593Smuzhiyun 
monitor_device_parse_status_config(struct device_node * np,struct monitor_dev_info * info)702*4882a593Smuzhiyun static int monitor_device_parse_status_config(struct device_node *np,
703*4882a593Smuzhiyun 					      struct monitor_dev_info *info)
704*4882a593Smuzhiyun {
705*4882a593Smuzhiyun 	int ret;
706*4882a593Smuzhiyun 
707*4882a593Smuzhiyun 	ret = of_property_read_u32(np, "rockchip,video-4k-freq",
708*4882a593Smuzhiyun 				   &info->video_4k_freq);
709*4882a593Smuzhiyun 	ret &= of_property_read_u32(np, "rockchip,reboot-freq",
710*4882a593Smuzhiyun 				    &info->reboot_freq);
711*4882a593Smuzhiyun 	if (info->devp->type == MONITOR_TYPE_CPU) {
712*4882a593Smuzhiyun 		if (!info->reboot_freq) {
713*4882a593Smuzhiyun 			info->reboot_freq = CPU_REBOOT_FREQ;
714*4882a593Smuzhiyun 			ret = 0;
715*4882a593Smuzhiyun 		}
716*4882a593Smuzhiyun 	}
717*4882a593Smuzhiyun 
718*4882a593Smuzhiyun 	return ret;
719*4882a593Smuzhiyun }
720*4882a593Smuzhiyun 
monitor_device_parse_early_min_volt(struct device_node * np,struct monitor_dev_info * info)721*4882a593Smuzhiyun static int monitor_device_parse_early_min_volt(struct device_node *np,
722*4882a593Smuzhiyun 					       struct monitor_dev_info *info)
723*4882a593Smuzhiyun {
724*4882a593Smuzhiyun 	return of_property_read_u32(np, "rockchip,early-min-microvolt",
725*4882a593Smuzhiyun 				    &info->early_min_volt);
726*4882a593Smuzhiyun }
727*4882a593Smuzhiyun 
monitor_device_parse_read_margin(struct device_node * np,struct monitor_dev_info * info)728*4882a593Smuzhiyun static int monitor_device_parse_read_margin(struct device_node *np,
729*4882a593Smuzhiyun 					    struct monitor_dev_info *info)
730*4882a593Smuzhiyun {
731*4882a593Smuzhiyun 	if (of_property_read_bool(np, "volt-mem-read-margin"))
732*4882a593Smuzhiyun 		return 0;
733*4882a593Smuzhiyun 	return -EINVAL;
734*4882a593Smuzhiyun }
735*4882a593Smuzhiyun 
monitor_device_parse_scmi_clk(struct device_node * np,struct monitor_dev_info * info)736*4882a593Smuzhiyun static int monitor_device_parse_scmi_clk(struct device_node *np,
737*4882a593Smuzhiyun 					 struct monitor_dev_info *info)
738*4882a593Smuzhiyun {
739*4882a593Smuzhiyun 	struct clk *clk;
740*4882a593Smuzhiyun 
741*4882a593Smuzhiyun 	clk = clk_get(info->dev, NULL);
742*4882a593Smuzhiyun 	if (strstr(__clk_get_name(clk), "scmi"))
743*4882a593Smuzhiyun 		return 0;
744*4882a593Smuzhiyun 	return -EINVAL;
745*4882a593Smuzhiyun }
746*4882a593Smuzhiyun 
monitor_device_parse_dt(struct device * dev,struct monitor_dev_info * info)747*4882a593Smuzhiyun static int monitor_device_parse_dt(struct device *dev,
748*4882a593Smuzhiyun 				   struct monitor_dev_info *info)
749*4882a593Smuzhiyun {
750*4882a593Smuzhiyun 	struct device_node *np;
751*4882a593Smuzhiyun 	int ret;
752*4882a593Smuzhiyun 
753*4882a593Smuzhiyun 	np = of_parse_phandle(dev->of_node, "operating-points-v2", 0);
754*4882a593Smuzhiyun 	if (!np)
755*4882a593Smuzhiyun 		return -EINVAL;
756*4882a593Smuzhiyun 
757*4882a593Smuzhiyun 	of_property_read_u32(np, "rockchip,init-freq", &info->init_freq);
758*4882a593Smuzhiyun 
759*4882a593Smuzhiyun 	ret = monitor_device_parse_wide_temp_config(np, info);
760*4882a593Smuzhiyun 	ret &= monitor_device_parse_status_config(np, info);
761*4882a593Smuzhiyun 	ret &= monitor_device_parse_early_min_volt(np, info);
762*4882a593Smuzhiyun 	ret &= monitor_device_parse_read_margin(np, info);
763*4882a593Smuzhiyun 	ret &= monitor_device_parse_scmi_clk(np, info);
764*4882a593Smuzhiyun 
765*4882a593Smuzhiyun 	of_node_put(np);
766*4882a593Smuzhiyun 
767*4882a593Smuzhiyun 	return ret;
768*4882a593Smuzhiyun }
769*4882a593Smuzhiyun 
rockchip_monitor_cpu_low_temp_adjust(struct monitor_dev_info * info,bool is_low)770*4882a593Smuzhiyun int rockchip_monitor_cpu_low_temp_adjust(struct monitor_dev_info *info,
771*4882a593Smuzhiyun 					 bool is_low)
772*4882a593Smuzhiyun {
773*4882a593Smuzhiyun 	if (!info->low_limit)
774*4882a593Smuzhiyun 		return 0;
775*4882a593Smuzhiyun 
776*4882a593Smuzhiyun 	if (!freq_qos_request_active(&info->max_temp_freq_req))
777*4882a593Smuzhiyun 		return 0;
778*4882a593Smuzhiyun 
779*4882a593Smuzhiyun 	if (is_low)
780*4882a593Smuzhiyun 		freq_qos_update_request(&info->max_temp_freq_req,
781*4882a593Smuzhiyun 					info->low_limit / 1000);
782*4882a593Smuzhiyun 	else
783*4882a593Smuzhiyun 		freq_qos_update_request(&info->max_temp_freq_req,
784*4882a593Smuzhiyun 					FREQ_QOS_MAX_DEFAULT_VALUE);
785*4882a593Smuzhiyun 
786*4882a593Smuzhiyun 	return 0;
787*4882a593Smuzhiyun }
788*4882a593Smuzhiyun EXPORT_SYMBOL(rockchip_monitor_cpu_low_temp_adjust);
789*4882a593Smuzhiyun 
rockchip_monitor_cpu_high_temp_adjust(struct monitor_dev_info * info,bool is_high)790*4882a593Smuzhiyun int rockchip_monitor_cpu_high_temp_adjust(struct monitor_dev_info *info,
791*4882a593Smuzhiyun 					  bool is_high)
792*4882a593Smuzhiyun {
793*4882a593Smuzhiyun 	if (!info->high_limit)
794*4882a593Smuzhiyun 		return 0;
795*4882a593Smuzhiyun 
796*4882a593Smuzhiyun 	if (!freq_qos_request_active(&info->max_temp_freq_req))
797*4882a593Smuzhiyun 		return 0;
798*4882a593Smuzhiyun 
799*4882a593Smuzhiyun 	if (info->high_limit_table) {
800*4882a593Smuzhiyun 		freq_qos_update_request(&info->max_temp_freq_req,
801*4882a593Smuzhiyun 					info->high_limit / 1000);
802*4882a593Smuzhiyun 		return 0;
803*4882a593Smuzhiyun 	}
804*4882a593Smuzhiyun 
805*4882a593Smuzhiyun 	if (is_high)
806*4882a593Smuzhiyun 		freq_qos_update_request(&info->max_temp_freq_req,
807*4882a593Smuzhiyun 					info->high_limit / 1000);
808*4882a593Smuzhiyun 	else
809*4882a593Smuzhiyun 		freq_qos_update_request(&info->max_temp_freq_req,
810*4882a593Smuzhiyun 					FREQ_QOS_MAX_DEFAULT_VALUE);
811*4882a593Smuzhiyun 
812*4882a593Smuzhiyun 	return 0;
813*4882a593Smuzhiyun }
814*4882a593Smuzhiyun EXPORT_SYMBOL(rockchip_monitor_cpu_high_temp_adjust);
815*4882a593Smuzhiyun 
rockchip_monitor_dev_low_temp_adjust(struct monitor_dev_info * info,bool is_low)816*4882a593Smuzhiyun int rockchip_monitor_dev_low_temp_adjust(struct monitor_dev_info *info,
817*4882a593Smuzhiyun 					 bool is_low)
818*4882a593Smuzhiyun {
819*4882a593Smuzhiyun 	if (!dev_pm_qos_request_active(&info->dev_max_freq_req))
820*4882a593Smuzhiyun 		return 0;
821*4882a593Smuzhiyun 
822*4882a593Smuzhiyun 	if (!info->low_limit)
823*4882a593Smuzhiyun 		return 0;
824*4882a593Smuzhiyun 
825*4882a593Smuzhiyun 	if (is_low)
826*4882a593Smuzhiyun 		dev_pm_qos_update_request(&info->dev_max_freq_req,
827*4882a593Smuzhiyun 					  info->low_limit / 1000);
828*4882a593Smuzhiyun 	else
829*4882a593Smuzhiyun 		dev_pm_qos_update_request(&info->dev_max_freq_req,
830*4882a593Smuzhiyun 					  PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE);
831*4882a593Smuzhiyun 
832*4882a593Smuzhiyun 	return 0;
833*4882a593Smuzhiyun }
834*4882a593Smuzhiyun EXPORT_SYMBOL(rockchip_monitor_dev_low_temp_adjust);
835*4882a593Smuzhiyun 
rockchip_monitor_dev_high_temp_adjust(struct monitor_dev_info * info,bool is_high)836*4882a593Smuzhiyun int rockchip_monitor_dev_high_temp_adjust(struct monitor_dev_info *info,
837*4882a593Smuzhiyun 					  bool is_high)
838*4882a593Smuzhiyun {
839*4882a593Smuzhiyun 	if (!dev_pm_qos_request_active(&info->dev_max_freq_req))
840*4882a593Smuzhiyun 		return 0;
841*4882a593Smuzhiyun 
842*4882a593Smuzhiyun 	if (!info->high_limit)
843*4882a593Smuzhiyun 		return 0;
844*4882a593Smuzhiyun 
845*4882a593Smuzhiyun 	if (info->high_limit_table) {
846*4882a593Smuzhiyun 		dev_pm_qos_update_request(&info->dev_max_freq_req,
847*4882a593Smuzhiyun 					  info->high_limit / 1000);
848*4882a593Smuzhiyun 		return 0;
849*4882a593Smuzhiyun 	}
850*4882a593Smuzhiyun 
851*4882a593Smuzhiyun 	if (is_high)
852*4882a593Smuzhiyun 		dev_pm_qos_update_request(&info->dev_max_freq_req,
853*4882a593Smuzhiyun 					  info->high_limit / 1000);
854*4882a593Smuzhiyun 	else
855*4882a593Smuzhiyun 		dev_pm_qos_update_request(&info->dev_max_freq_req,
856*4882a593Smuzhiyun 					  PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE);
857*4882a593Smuzhiyun 
858*4882a593Smuzhiyun 	return 0;
859*4882a593Smuzhiyun }
860*4882a593Smuzhiyun EXPORT_SYMBOL(rockchip_monitor_dev_high_temp_adjust);
861*4882a593Smuzhiyun 
rockchip_adjust_low_temp_opp_volt(struct monitor_dev_info * info,bool is_low_temp)862*4882a593Smuzhiyun static int rockchip_adjust_low_temp_opp_volt(struct monitor_dev_info *info,
863*4882a593Smuzhiyun 					     bool is_low_temp)
864*4882a593Smuzhiyun {
865*4882a593Smuzhiyun 	struct device *dev = info->dev;
866*4882a593Smuzhiyun 	struct opp_table *opp_table;
867*4882a593Smuzhiyun 	struct dev_pm_opp *opp;
868*4882a593Smuzhiyun 	int i = 0;
869*4882a593Smuzhiyun 
870*4882a593Smuzhiyun 	opp_table = dev_pm_opp_get_opp_table(dev);
871*4882a593Smuzhiyun 	if (!opp_table)
872*4882a593Smuzhiyun 		return -ENOMEM;
873*4882a593Smuzhiyun 
874*4882a593Smuzhiyun 	mutex_lock(&opp_table->lock);
875*4882a593Smuzhiyun 	list_for_each_entry(opp, &opp_table->opp_list, node) {
876*4882a593Smuzhiyun 		if (!opp->available)
877*4882a593Smuzhiyun 			continue;
878*4882a593Smuzhiyun 		if (is_low_temp) {
879*4882a593Smuzhiyun 			if (opp->supplies[0].u_volt_max <
880*4882a593Smuzhiyun 			    info->opp_table[i].low_temp_volt)
881*4882a593Smuzhiyun 				opp->supplies[0].u_volt_max =
882*4882a593Smuzhiyun 					info->opp_table[i].low_temp_volt;
883*4882a593Smuzhiyun 			opp->supplies[0].u_volt =
884*4882a593Smuzhiyun 				info->opp_table[i].low_temp_volt;
885*4882a593Smuzhiyun 			opp->supplies[0].u_volt_min = opp->supplies[0].u_volt;
886*4882a593Smuzhiyun 			if (opp_table->regulator_count > 1) {
887*4882a593Smuzhiyun 				if (opp->supplies[1].u_volt_max <
888*4882a593Smuzhiyun 				    info->opp_table[i].low_temp_mem_volt)
889*4882a593Smuzhiyun 					opp->supplies[1].u_volt_max =
890*4882a593Smuzhiyun 						info->opp_table[i].low_temp_mem_volt;
891*4882a593Smuzhiyun 				opp->supplies[1].u_volt =
892*4882a593Smuzhiyun 					info->opp_table[i].low_temp_mem_volt;
893*4882a593Smuzhiyun 				opp->supplies[1].u_volt_min =
894*4882a593Smuzhiyun 					opp->supplies[1].u_volt;
895*4882a593Smuzhiyun 			}
896*4882a593Smuzhiyun 		} else {
897*4882a593Smuzhiyun 			opp->supplies[0].u_volt_min = info->opp_table[i].volt;
898*4882a593Smuzhiyun 			opp->supplies[0].u_volt = opp->supplies[0].u_volt_min;
899*4882a593Smuzhiyun 			opp->supplies[0].u_volt_max =
900*4882a593Smuzhiyun 				info->opp_table[i].max_volt;
901*4882a593Smuzhiyun 			if (opp_table->regulator_count > 1) {
902*4882a593Smuzhiyun 				opp->supplies[1].u_volt_min =
903*4882a593Smuzhiyun 					info->opp_table[i].mem_volt;
904*4882a593Smuzhiyun 				opp->supplies[1].u_volt =
905*4882a593Smuzhiyun 					opp->supplies[1].u_volt_min;
906*4882a593Smuzhiyun 				opp->supplies[1].u_volt_max =
907*4882a593Smuzhiyun 					info->opp_table[i].max_mem_volt;
908*4882a593Smuzhiyun 			}
909*4882a593Smuzhiyun 		}
910*4882a593Smuzhiyun 		i++;
911*4882a593Smuzhiyun 	}
912*4882a593Smuzhiyun 	mutex_unlock(&opp_table->lock);
913*4882a593Smuzhiyun 
914*4882a593Smuzhiyun 	dev_pm_opp_put_opp_table(opp_table);
915*4882a593Smuzhiyun 
916*4882a593Smuzhiyun 	return 0;
917*4882a593Smuzhiyun }
918*4882a593Smuzhiyun 
rockchip_low_temp_adjust(struct monitor_dev_info * info,bool is_low)919*4882a593Smuzhiyun static void rockchip_low_temp_adjust(struct monitor_dev_info *info,
920*4882a593Smuzhiyun 				     bool is_low)
921*4882a593Smuzhiyun {
922*4882a593Smuzhiyun 	struct monitor_dev_profile *devp = info->devp;
923*4882a593Smuzhiyun 	int ret = 0;
924*4882a593Smuzhiyun 
925*4882a593Smuzhiyun 	dev_dbg(info->dev, "low_temp %d\n", is_low);
926*4882a593Smuzhiyun 
927*4882a593Smuzhiyun 	if (info->opp_table)
928*4882a593Smuzhiyun 		rockchip_adjust_low_temp_opp_volt(info, is_low);
929*4882a593Smuzhiyun 
930*4882a593Smuzhiyun 	if (devp->low_temp_adjust)
931*4882a593Smuzhiyun 		ret = devp->low_temp_adjust(info, is_low);
932*4882a593Smuzhiyun 	if (!ret)
933*4882a593Smuzhiyun 		info->is_low_temp = is_low;
934*4882a593Smuzhiyun 
935*4882a593Smuzhiyun 	if (devp->update_volt)
936*4882a593Smuzhiyun 		devp->update_volt(info);
937*4882a593Smuzhiyun }
938*4882a593Smuzhiyun 
rockchip_high_temp_adjust(struct monitor_dev_info * info,bool is_high)939*4882a593Smuzhiyun static void rockchip_high_temp_adjust(struct monitor_dev_info *info,
940*4882a593Smuzhiyun 				      bool is_high)
941*4882a593Smuzhiyun {
942*4882a593Smuzhiyun 	struct monitor_dev_profile *devp = info->devp;
943*4882a593Smuzhiyun 	int ret = 0;
944*4882a593Smuzhiyun 
945*4882a593Smuzhiyun 	if (!devp->high_temp_adjust)
946*4882a593Smuzhiyun 		return;
947*4882a593Smuzhiyun 
948*4882a593Smuzhiyun 	if (info->high_limit_table) {
949*4882a593Smuzhiyun 		devp->high_temp_adjust(info, is_high);
950*4882a593Smuzhiyun 	} else {
951*4882a593Smuzhiyun 		dev_dbg(info->dev, "high_temp %d\n", is_high);
952*4882a593Smuzhiyun 		ret = devp->high_temp_adjust(info, is_high);
953*4882a593Smuzhiyun 		if (!ret)
954*4882a593Smuzhiyun 			info->is_high_temp = is_high;
955*4882a593Smuzhiyun 	}
956*4882a593Smuzhiyun }
957*4882a593Smuzhiyun 
rockchip_monitor_suspend_low_temp_adjust(int cpu)958*4882a593Smuzhiyun int rockchip_monitor_suspend_low_temp_adjust(int cpu)
959*4882a593Smuzhiyun {
960*4882a593Smuzhiyun 	struct monitor_dev_info *info = NULL, *tmp;
961*4882a593Smuzhiyun 
962*4882a593Smuzhiyun 	list_for_each_entry(tmp, &monitor_dev_list, node) {
963*4882a593Smuzhiyun 		if (tmp->devp->type != MONITOR_TYPE_CPU)
964*4882a593Smuzhiyun 			continue;
965*4882a593Smuzhiyun 		if (cpumask_test_cpu(cpu, &tmp->devp->allowed_cpus)) {
966*4882a593Smuzhiyun 			info = tmp;
967*4882a593Smuzhiyun 			break;
968*4882a593Smuzhiyun 		}
969*4882a593Smuzhiyun 	}
970*4882a593Smuzhiyun 
971*4882a593Smuzhiyun 	if (!info || !info->is_low_temp_enabled)
972*4882a593Smuzhiyun 		return 0;
973*4882a593Smuzhiyun 
974*4882a593Smuzhiyun 	if (info->high_limit_table) {
975*4882a593Smuzhiyun 		info->high_limit = 0;
976*4882a593Smuzhiyun 		rockchip_high_temp_adjust(info, true);
977*4882a593Smuzhiyun 	} else if (info->is_high_temp) {
978*4882a593Smuzhiyun 		rockchip_high_temp_adjust(info, false);
979*4882a593Smuzhiyun 	}
980*4882a593Smuzhiyun 	if (!info->is_low_temp)
981*4882a593Smuzhiyun 		rockchip_low_temp_adjust(info, true);
982*4882a593Smuzhiyun 
983*4882a593Smuzhiyun 	return 0;
984*4882a593Smuzhiyun }
985*4882a593Smuzhiyun EXPORT_SYMBOL(rockchip_monitor_suspend_low_temp_adjust);
986*4882a593Smuzhiyun 
987*4882a593Smuzhiyun static int
rockchip_system_monitor_wide_temp_adjust(struct monitor_dev_info * info,int temp)988*4882a593Smuzhiyun rockchip_system_monitor_wide_temp_adjust(struct monitor_dev_info *info,
989*4882a593Smuzhiyun 					 int temp)
990*4882a593Smuzhiyun {
991*4882a593Smuzhiyun 	unsigned long target_freq = 0;
992*4882a593Smuzhiyun 	int i;
993*4882a593Smuzhiyun 
994*4882a593Smuzhiyun 	if (temp < info->low_temp) {
995*4882a593Smuzhiyun 		if (!info->is_low_temp)
996*4882a593Smuzhiyun 			rockchip_low_temp_adjust(info, true);
997*4882a593Smuzhiyun 	} else if (temp > (info->low_temp + info->temp_hysteresis)) {
998*4882a593Smuzhiyun 		if (info->is_low_temp)
999*4882a593Smuzhiyun 			rockchip_low_temp_adjust(info, false);
1000*4882a593Smuzhiyun 	}
1001*4882a593Smuzhiyun 
1002*4882a593Smuzhiyun 	if (info->high_limit_table) {
1003*4882a593Smuzhiyun 		for (i = 0; info->high_limit_table[i].freq != UINT_MAX; i++) {
1004*4882a593Smuzhiyun 			if (temp > info->high_limit_table[i].temp)
1005*4882a593Smuzhiyun 				target_freq =
1006*4882a593Smuzhiyun 					info->high_limit_table[i].freq * 1000;
1007*4882a593Smuzhiyun 		}
1008*4882a593Smuzhiyun 		if (target_freq != info->high_limit) {
1009*4882a593Smuzhiyun 			info->high_limit = target_freq;
1010*4882a593Smuzhiyun 			rockchip_high_temp_adjust(info, true);
1011*4882a593Smuzhiyun 		}
1012*4882a593Smuzhiyun 	} else {
1013*4882a593Smuzhiyun 		if (temp > info->high_temp) {
1014*4882a593Smuzhiyun 			if (!info->is_high_temp)
1015*4882a593Smuzhiyun 				rockchip_high_temp_adjust(info, true);
1016*4882a593Smuzhiyun 		} else if (temp < (info->high_temp - info->temp_hysteresis)) {
1017*4882a593Smuzhiyun 			if (info->is_high_temp)
1018*4882a593Smuzhiyun 				rockchip_high_temp_adjust(info, false);
1019*4882a593Smuzhiyun 		}
1020*4882a593Smuzhiyun 	}
1021*4882a593Smuzhiyun 
1022*4882a593Smuzhiyun 	return 0;
1023*4882a593Smuzhiyun }
1024*4882a593Smuzhiyun 
1025*4882a593Smuzhiyun static void
rockchip_system_monitor_wide_temp_init(struct monitor_dev_info * info)1026*4882a593Smuzhiyun rockchip_system_monitor_wide_temp_init(struct monitor_dev_info *info)
1027*4882a593Smuzhiyun {
1028*4882a593Smuzhiyun 	int ret, temp;
1029*4882a593Smuzhiyun 
1030*4882a593Smuzhiyun 	if (!info->opp_table)
1031*4882a593Smuzhiyun 		return;
1032*4882a593Smuzhiyun 
1033*4882a593Smuzhiyun 	/*
1034*4882a593Smuzhiyun 	 * set the init state to low temperature that the voltage will be enough
1035*4882a593Smuzhiyun 	 * when cpu up at low temperature.
1036*4882a593Smuzhiyun 	 */
1037*4882a593Smuzhiyun 	if (!info->is_low_temp) {
1038*4882a593Smuzhiyun 		if (info->opp_table)
1039*4882a593Smuzhiyun 			rockchip_adjust_low_temp_opp_volt(info, true);
1040*4882a593Smuzhiyun 		info->is_low_temp = true;
1041*4882a593Smuzhiyun 	}
1042*4882a593Smuzhiyun 
1043*4882a593Smuzhiyun 	ret = thermal_zone_get_temp(system_monitor->tz, &temp);
1044*4882a593Smuzhiyun 	if (ret || temp == THERMAL_TEMP_INVALID) {
1045*4882a593Smuzhiyun 		dev_err(info->dev,
1046*4882a593Smuzhiyun 			"failed to read out thermal zone (%d)\n", ret);
1047*4882a593Smuzhiyun 		return;
1048*4882a593Smuzhiyun 	}
1049*4882a593Smuzhiyun 
1050*4882a593Smuzhiyun 	if (temp > info->high_temp) {
1051*4882a593Smuzhiyun 		if (info->opp_table)
1052*4882a593Smuzhiyun 			rockchip_adjust_low_temp_opp_volt(info, false);
1053*4882a593Smuzhiyun 		info->is_low_temp = false;
1054*4882a593Smuzhiyun 		info->is_high_temp = true;
1055*4882a593Smuzhiyun 	} else if (temp > (info->low_temp + info->temp_hysteresis)) {
1056*4882a593Smuzhiyun 		if (info->opp_table)
1057*4882a593Smuzhiyun 			rockchip_adjust_low_temp_opp_volt(info, false);
1058*4882a593Smuzhiyun 		info->is_low_temp = false;
1059*4882a593Smuzhiyun 	}
1060*4882a593Smuzhiyun }
1061*4882a593Smuzhiyun 
get_rdev_name(struct regulator_dev * rdev)1062*4882a593Smuzhiyun static const char *get_rdev_name(struct regulator_dev *rdev)
1063*4882a593Smuzhiyun {
1064*4882a593Smuzhiyun 	if (rdev->constraints && rdev->constraints->name)
1065*4882a593Smuzhiyun 		return rdev->constraints->name;
1066*4882a593Smuzhiyun 	else if (rdev->desc->name)
1067*4882a593Smuzhiyun 		return rdev->desc->name;
1068*4882a593Smuzhiyun 	else
1069*4882a593Smuzhiyun 		return "";
1070*4882a593Smuzhiyun }
1071*4882a593Smuzhiyun 
1072*4882a593Smuzhiyun static void
rockchip_system_monitor_early_regulator_init(struct monitor_dev_info * info)1073*4882a593Smuzhiyun rockchip_system_monitor_early_regulator_init(struct monitor_dev_info *info)
1074*4882a593Smuzhiyun {
1075*4882a593Smuzhiyun 	struct regulator *reg;
1076*4882a593Smuzhiyun 	struct regulator_dev *rdev;
1077*4882a593Smuzhiyun 
1078*4882a593Smuzhiyun 	if (!info->early_min_volt || !info->regulators)
1079*4882a593Smuzhiyun 		return;
1080*4882a593Smuzhiyun 
1081*4882a593Smuzhiyun 	rdev = info->regulators[0]->rdev;
1082*4882a593Smuzhiyun 	reg = regulator_get(NULL, get_rdev_name(rdev));
1083*4882a593Smuzhiyun 	if (!IS_ERR_OR_NULL(reg)) {
1084*4882a593Smuzhiyun 		info->early_reg = reg;
1085*4882a593Smuzhiyun 		reg->voltage[PM_SUSPEND_ON].min_uV = info->early_min_volt;
1086*4882a593Smuzhiyun 		reg->voltage[PM_SUSPEND_ON].max_uV = rdev->constraints->max_uV;
1087*4882a593Smuzhiyun 	}
1088*4882a593Smuzhiyun }
1089*4882a593Smuzhiyun 
1090*4882a593Smuzhiyun static int
rockchip_system_monitor_freq_qos_requset(struct monitor_dev_info * info)1091*4882a593Smuzhiyun rockchip_system_monitor_freq_qos_requset(struct monitor_dev_info *info)
1092*4882a593Smuzhiyun {
1093*4882a593Smuzhiyun 	struct devfreq *devfreq;
1094*4882a593Smuzhiyun 	struct cpufreq_policy *policy;
1095*4882a593Smuzhiyun 	int max_default_value = FREQ_QOS_MAX_DEFAULT_VALUE;
1096*4882a593Smuzhiyun 	int ret;
1097*4882a593Smuzhiyun 
1098*4882a593Smuzhiyun 	if (!info->devp->data)
1099*4882a593Smuzhiyun 		return 0;
1100*4882a593Smuzhiyun 
1101*4882a593Smuzhiyun 	if (info->is_low_temp && info->low_limit)
1102*4882a593Smuzhiyun 		max_default_value = info->low_limit / 1000;
1103*4882a593Smuzhiyun 	else if (info->is_high_temp && info->high_limit)
1104*4882a593Smuzhiyun 		max_default_value = info->high_limit / 1000;
1105*4882a593Smuzhiyun 
1106*4882a593Smuzhiyun 	if (info->devp->type == MONITOR_TYPE_CPU) {
1107*4882a593Smuzhiyun 		policy = (struct cpufreq_policy *)info->devp->data;
1108*4882a593Smuzhiyun 		ret = freq_qos_add_request(&policy->constraints,
1109*4882a593Smuzhiyun 					   &info->max_temp_freq_req,
1110*4882a593Smuzhiyun 					   FREQ_QOS_MAX,
1111*4882a593Smuzhiyun 					   max_default_value);
1112*4882a593Smuzhiyun 		if (ret < 0) {
1113*4882a593Smuzhiyun 			dev_info(info->dev,
1114*4882a593Smuzhiyun 				 "failed to add temp freq constraint\n");
1115*4882a593Smuzhiyun 			return ret;
1116*4882a593Smuzhiyun 		}
1117*4882a593Smuzhiyun 		ret = freq_qos_add_request(&policy->constraints,
1118*4882a593Smuzhiyun 					   &info->min_sta_freq_req,
1119*4882a593Smuzhiyun 					   FREQ_QOS_MIN,
1120*4882a593Smuzhiyun 					   FREQ_QOS_MIN_DEFAULT_VALUE);
1121*4882a593Smuzhiyun 		if (ret < 0) {
1122*4882a593Smuzhiyun 			dev_info(info->dev,
1123*4882a593Smuzhiyun 				 "failed to add sta freq constraint\n");
1124*4882a593Smuzhiyun 			freq_qos_remove_request(&info->max_temp_freq_req);
1125*4882a593Smuzhiyun 			return ret;
1126*4882a593Smuzhiyun 		}
1127*4882a593Smuzhiyun 		ret = freq_qos_add_request(&policy->constraints,
1128*4882a593Smuzhiyun 					   &info->max_sta_freq_req,
1129*4882a593Smuzhiyun 					   FREQ_QOS_MAX,
1130*4882a593Smuzhiyun 					   FREQ_QOS_MAX_DEFAULT_VALUE);
1131*4882a593Smuzhiyun 		if (ret < 0) {
1132*4882a593Smuzhiyun 			dev_info(info->dev,
1133*4882a593Smuzhiyun 				 "failed to add sta freq constraint\n");
1134*4882a593Smuzhiyun 			freq_qos_remove_request(&info->max_temp_freq_req);
1135*4882a593Smuzhiyun 			freq_qos_remove_request(&info->min_sta_freq_req);
1136*4882a593Smuzhiyun 			return ret;
1137*4882a593Smuzhiyun 		}
1138*4882a593Smuzhiyun 	} else if (info->devp->type == MONITOR_TYPE_DEV) {
1139*4882a593Smuzhiyun 		devfreq = (struct devfreq *)info->devp->data;
1140*4882a593Smuzhiyun 		ret = dev_pm_qos_add_request(devfreq->dev.parent,
1141*4882a593Smuzhiyun 					     &info->dev_max_freq_req,
1142*4882a593Smuzhiyun 					     DEV_PM_QOS_MAX_FREQUENCY,
1143*4882a593Smuzhiyun 					     max_default_value);
1144*4882a593Smuzhiyun 		if (ret < 0) {
1145*4882a593Smuzhiyun 			dev_info(info->dev, "failed to add freq constraint\n");
1146*4882a593Smuzhiyun 			return ret;
1147*4882a593Smuzhiyun 		}
1148*4882a593Smuzhiyun 	}
1149*4882a593Smuzhiyun 
1150*4882a593Smuzhiyun 	return 0;
1151*4882a593Smuzhiyun }
1152*4882a593Smuzhiyun 
rockchip_system_monitor_parse_supplies(struct device * dev,struct monitor_dev_info * info)1153*4882a593Smuzhiyun static int rockchip_system_monitor_parse_supplies(struct device *dev,
1154*4882a593Smuzhiyun 						  struct monitor_dev_info *info)
1155*4882a593Smuzhiyun {
1156*4882a593Smuzhiyun 	struct opp_table *opp_table;
1157*4882a593Smuzhiyun 	struct dev_pm_set_opp_data *data;
1158*4882a593Smuzhiyun 	int len, count;
1159*4882a593Smuzhiyun 
1160*4882a593Smuzhiyun 	opp_table = dev_pm_opp_get_opp_table(dev);
1161*4882a593Smuzhiyun 	if (IS_ERR(opp_table))
1162*4882a593Smuzhiyun 		return PTR_ERR(opp_table);
1163*4882a593Smuzhiyun 
1164*4882a593Smuzhiyun 	if (opp_table->clk)
1165*4882a593Smuzhiyun 		info->clk = opp_table->clk;
1166*4882a593Smuzhiyun 	if (opp_table->regulators)
1167*4882a593Smuzhiyun 		info->regulators = opp_table->regulators;
1168*4882a593Smuzhiyun 	info->regulator_count = opp_table->regulator_count;
1169*4882a593Smuzhiyun 
1170*4882a593Smuzhiyun 	if (opp_table->regulators && info->devp->set_opp) {
1171*4882a593Smuzhiyun 		count = opp_table->regulator_count;
1172*4882a593Smuzhiyun 		/* space for set_opp_data */
1173*4882a593Smuzhiyun 		len = sizeof(*data);
1174*4882a593Smuzhiyun 		/* space for old_opp.supplies and new_opp.supplies */
1175*4882a593Smuzhiyun 		len += 2 * sizeof(struct dev_pm_opp_supply) * count;
1176*4882a593Smuzhiyun 		data = kzalloc(len, GFP_KERNEL);
1177*4882a593Smuzhiyun 		if (!data)
1178*4882a593Smuzhiyun 			return -ENOMEM;
1179*4882a593Smuzhiyun 		data->old_opp.supplies = (void *)(data + 1);
1180*4882a593Smuzhiyun 		data->new_opp.supplies = data->old_opp.supplies + count;
1181*4882a593Smuzhiyun 		info->set_opp_data = data;
1182*4882a593Smuzhiyun 	}
1183*4882a593Smuzhiyun 
1184*4882a593Smuzhiyun 	dev_pm_opp_put_opp_table(opp_table);
1185*4882a593Smuzhiyun 
1186*4882a593Smuzhiyun 	return 0;
1187*4882a593Smuzhiyun }
1188*4882a593Smuzhiyun 
rockchip_monitor_volt_adjust_lock(struct monitor_dev_info * info)1189*4882a593Smuzhiyun void rockchip_monitor_volt_adjust_lock(struct monitor_dev_info *info)
1190*4882a593Smuzhiyun {
1191*4882a593Smuzhiyun 	if (info)
1192*4882a593Smuzhiyun 		mutex_lock(&info->volt_adjust_mutex);
1193*4882a593Smuzhiyun }
1194*4882a593Smuzhiyun EXPORT_SYMBOL(rockchip_monitor_volt_adjust_lock);
1195*4882a593Smuzhiyun 
rockchip_monitor_volt_adjust_unlock(struct monitor_dev_info * info)1196*4882a593Smuzhiyun void rockchip_monitor_volt_adjust_unlock(struct monitor_dev_info *info)
1197*4882a593Smuzhiyun {
1198*4882a593Smuzhiyun 	if (info)
1199*4882a593Smuzhiyun 		mutex_unlock(&info->volt_adjust_mutex);
1200*4882a593Smuzhiyun }
1201*4882a593Smuzhiyun EXPORT_SYMBOL(rockchip_monitor_volt_adjust_unlock);
1202*4882a593Smuzhiyun 
rockchip_monitor_enable_opp_clk(struct device * dev,struct rockchip_opp_info * opp_info)1203*4882a593Smuzhiyun static int rockchip_monitor_enable_opp_clk(struct device *dev,
1204*4882a593Smuzhiyun 					   struct rockchip_opp_info *opp_info)
1205*4882a593Smuzhiyun {
1206*4882a593Smuzhiyun 	int ret = 0;
1207*4882a593Smuzhiyun 
1208*4882a593Smuzhiyun 	if (!opp_info)
1209*4882a593Smuzhiyun 		return 0;
1210*4882a593Smuzhiyun 
1211*4882a593Smuzhiyun 	ret = clk_bulk_prepare_enable(opp_info->num_clks, opp_info->clks);
1212*4882a593Smuzhiyun 	if (ret) {
1213*4882a593Smuzhiyun 		dev_err(dev, "failed to enable opp clks\n");
1214*4882a593Smuzhiyun 		return ret;
1215*4882a593Smuzhiyun 	}
1216*4882a593Smuzhiyun 
1217*4882a593Smuzhiyun 	return 0;
1218*4882a593Smuzhiyun }
1219*4882a593Smuzhiyun 
rockchip_monitor_disable_opp_clk(struct device * dev,struct rockchip_opp_info * opp_info)1220*4882a593Smuzhiyun static void rockchip_monitor_disable_opp_clk(struct device *dev,
1221*4882a593Smuzhiyun 					     struct rockchip_opp_info *opp_info)
1222*4882a593Smuzhiyun {
1223*4882a593Smuzhiyun 	if (!opp_info)
1224*4882a593Smuzhiyun 		return;
1225*4882a593Smuzhiyun 
1226*4882a593Smuzhiyun 	clk_bulk_disable_unprepare(opp_info->num_clks, opp_info->clks);
1227*4882a593Smuzhiyun }
1228*4882a593Smuzhiyun 
rockchip_monitor_set_opp(struct monitor_dev_info * info,unsigned long old_freq,unsigned long freq,struct dev_pm_opp_supply * old_supply,struct dev_pm_opp_supply * new_supply)1229*4882a593Smuzhiyun static int rockchip_monitor_set_opp(struct monitor_dev_info *info,
1230*4882a593Smuzhiyun 				    unsigned long old_freq,
1231*4882a593Smuzhiyun 				    unsigned long freq,
1232*4882a593Smuzhiyun 				    struct dev_pm_opp_supply *old_supply,
1233*4882a593Smuzhiyun 				    struct dev_pm_opp_supply *new_supply)
1234*4882a593Smuzhiyun {
1235*4882a593Smuzhiyun 	struct dev_pm_set_opp_data *data;
1236*4882a593Smuzhiyun 	int size;
1237*4882a593Smuzhiyun 
1238*4882a593Smuzhiyun 	data = info->set_opp_data;
1239*4882a593Smuzhiyun 	data->regulators = info->regulators;
1240*4882a593Smuzhiyun 	data->regulator_count = info->regulator_count;
1241*4882a593Smuzhiyun 	data->clk = info->clk;
1242*4882a593Smuzhiyun 	data->dev = info->dev;
1243*4882a593Smuzhiyun 
1244*4882a593Smuzhiyun 	data->old_opp.rate = old_freq;
1245*4882a593Smuzhiyun 	size = sizeof(*old_supply) * info->regulator_count;
1246*4882a593Smuzhiyun 	if (!old_supply)
1247*4882a593Smuzhiyun 		memset(data->old_opp.supplies, 0, size);
1248*4882a593Smuzhiyun 	else
1249*4882a593Smuzhiyun 		memcpy(data->old_opp.supplies, old_supply, size);
1250*4882a593Smuzhiyun 
1251*4882a593Smuzhiyun 	data->new_opp.rate = freq;
1252*4882a593Smuzhiyun 	memcpy(data->new_opp.supplies, new_supply, size);
1253*4882a593Smuzhiyun 
1254*4882a593Smuzhiyun 	return info->devp->set_opp(data);
1255*4882a593Smuzhiyun }
1256*4882a593Smuzhiyun 
rockchip_monitor_check_rate_volt(struct monitor_dev_info * info)1257*4882a593Smuzhiyun int rockchip_monitor_check_rate_volt(struct monitor_dev_info *info)
1258*4882a593Smuzhiyun {
1259*4882a593Smuzhiyun 	struct device *dev = info->dev;
1260*4882a593Smuzhiyun 	struct regulator *vdd_reg = NULL;
1261*4882a593Smuzhiyun 	struct regulator *mem_reg = NULL;
1262*4882a593Smuzhiyun 	struct rockchip_opp_info *opp_info = info->devp->opp_info;
1263*4882a593Smuzhiyun 	struct dev_pm_opp *opp;
1264*4882a593Smuzhiyun 	unsigned long old_rate, new_rate, new_volt, new_mem_volt;
1265*4882a593Smuzhiyun 	int old_volt, old_mem_volt;
1266*4882a593Smuzhiyun 	u32 target_rm = UINT_MAX;
1267*4882a593Smuzhiyun 	bool is_set_clk = true;
1268*4882a593Smuzhiyun 	bool is_set_rm = false;
1269*4882a593Smuzhiyun 	int ret = 0;
1270*4882a593Smuzhiyun 
1271*4882a593Smuzhiyun 	if (!info->regulators || !info->clk)
1272*4882a593Smuzhiyun 		return 0;
1273*4882a593Smuzhiyun 
1274*4882a593Smuzhiyun 	mutex_lock(&info->volt_adjust_mutex);
1275*4882a593Smuzhiyun 
1276*4882a593Smuzhiyun 	vdd_reg = info->regulators[0];
1277*4882a593Smuzhiyun 	old_rate = clk_get_rate(info->clk);
1278*4882a593Smuzhiyun 	old_volt = regulator_get_voltage(vdd_reg);
1279*4882a593Smuzhiyun 	if (info->regulator_count > 1) {
1280*4882a593Smuzhiyun 		mem_reg = info->regulators[1];
1281*4882a593Smuzhiyun 		old_mem_volt = regulator_get_voltage(mem_reg);
1282*4882a593Smuzhiyun 	}
1283*4882a593Smuzhiyun 
1284*4882a593Smuzhiyun 	if (info->init_freq) {
1285*4882a593Smuzhiyun 		new_rate = info->init_freq * 1000;
1286*4882a593Smuzhiyun 		info->init_freq = 0;
1287*4882a593Smuzhiyun 	} else {
1288*4882a593Smuzhiyun 		new_rate = old_rate;
1289*4882a593Smuzhiyun 	}
1290*4882a593Smuzhiyun 	opp = dev_pm_opp_find_freq_ceil(dev, &new_rate);
1291*4882a593Smuzhiyun 	if (IS_ERR(opp)) {
1292*4882a593Smuzhiyun 		opp = dev_pm_opp_find_freq_floor(dev, &new_rate);
1293*4882a593Smuzhiyun 		if (IS_ERR(opp)) {
1294*4882a593Smuzhiyun 			ret = PTR_ERR(opp);
1295*4882a593Smuzhiyun 			goto unlock;
1296*4882a593Smuzhiyun 		}
1297*4882a593Smuzhiyun 	}
1298*4882a593Smuzhiyun 	new_volt = opp->supplies[0].u_volt;
1299*4882a593Smuzhiyun 	if (info->regulator_count > 1)
1300*4882a593Smuzhiyun 		new_mem_volt = opp->supplies[1].u_volt;
1301*4882a593Smuzhiyun 	dev_pm_opp_put(opp);
1302*4882a593Smuzhiyun 
1303*4882a593Smuzhiyun 	if (old_rate == new_rate) {
1304*4882a593Smuzhiyun 		if (info->regulator_count > 1) {
1305*4882a593Smuzhiyun 			if (old_volt == new_volt &&
1306*4882a593Smuzhiyun 			    new_mem_volt == old_mem_volt)
1307*4882a593Smuzhiyun 				goto unlock;
1308*4882a593Smuzhiyun 		} else if (old_volt == new_volt) {
1309*4882a593Smuzhiyun 			goto unlock;
1310*4882a593Smuzhiyun 		}
1311*4882a593Smuzhiyun 	}
1312*4882a593Smuzhiyun 	if (!new_volt || (info->regulator_count > 1 && !new_mem_volt))
1313*4882a593Smuzhiyun 		goto unlock;
1314*4882a593Smuzhiyun 
1315*4882a593Smuzhiyun 	if (info->devp->set_opp) {
1316*4882a593Smuzhiyun 		ret = rockchip_monitor_set_opp(info, old_rate, new_rate,
1317*4882a593Smuzhiyun 					       NULL, opp->supplies);
1318*4882a593Smuzhiyun 		goto unlock;
1319*4882a593Smuzhiyun 	}
1320*4882a593Smuzhiyun 
1321*4882a593Smuzhiyun 	if (opp_info && opp_info->data && opp_info->data->set_read_margin) {
1322*4882a593Smuzhiyun 		is_set_rm = true;
1323*4882a593Smuzhiyun 		if (info->devp->type == MONITOR_TYPE_DEV) {
1324*4882a593Smuzhiyun 			if (!pm_runtime_active(dev)) {
1325*4882a593Smuzhiyun 				is_set_rm = false;
1326*4882a593Smuzhiyun 				if (opp_info->scmi_clk)
1327*4882a593Smuzhiyun 					is_set_clk = false;
1328*4882a593Smuzhiyun 			}
1329*4882a593Smuzhiyun 		}
1330*4882a593Smuzhiyun 	}
1331*4882a593Smuzhiyun 	rockchip_monitor_enable_opp_clk(dev, opp_info);
1332*4882a593Smuzhiyun 	rockchip_get_read_margin(dev, opp_info, new_volt, &target_rm);
1333*4882a593Smuzhiyun 
1334*4882a593Smuzhiyun 	dev_dbg(dev, "%s: %lu Hz --> %lu Hz\n", __func__, old_rate, new_rate);
1335*4882a593Smuzhiyun 	if (new_rate >= old_rate) {
1336*4882a593Smuzhiyun 		rockchip_set_intermediate_rate(dev, opp_info, info->clk,
1337*4882a593Smuzhiyun 					       old_rate, new_rate,
1338*4882a593Smuzhiyun 					       true, is_set_clk);
1339*4882a593Smuzhiyun 		if (info->regulator_count > 1) {
1340*4882a593Smuzhiyun 			ret = regulator_set_voltage(mem_reg, new_mem_volt,
1341*4882a593Smuzhiyun 						    INT_MAX);
1342*4882a593Smuzhiyun 			if (ret) {
1343*4882a593Smuzhiyun 				dev_err(dev, "%s: failed to set volt: %lu\n",
1344*4882a593Smuzhiyun 					__func__, new_mem_volt);
1345*4882a593Smuzhiyun 				goto restore_voltage;
1346*4882a593Smuzhiyun 			}
1347*4882a593Smuzhiyun 		}
1348*4882a593Smuzhiyun 		ret = regulator_set_voltage(vdd_reg, new_volt, INT_MAX);
1349*4882a593Smuzhiyun 		if (ret) {
1350*4882a593Smuzhiyun 			dev_err(dev, "%s: failed to set volt: %lu\n",
1351*4882a593Smuzhiyun 				__func__, new_volt);
1352*4882a593Smuzhiyun 			goto restore_voltage;
1353*4882a593Smuzhiyun 		}
1354*4882a593Smuzhiyun 		rockchip_set_read_margin(dev, opp_info, target_rm, is_set_rm);
1355*4882a593Smuzhiyun 		if (is_set_clk && clk_set_rate(info->clk, new_rate)) {
1356*4882a593Smuzhiyun 			dev_err(dev, "%s: failed to set clock rate: %lu\n",
1357*4882a593Smuzhiyun 				__func__, new_rate);
1358*4882a593Smuzhiyun 			goto restore_rm;
1359*4882a593Smuzhiyun 		}
1360*4882a593Smuzhiyun 	} else {
1361*4882a593Smuzhiyun 		rockchip_set_intermediate_rate(dev, opp_info, info->clk,
1362*4882a593Smuzhiyun 					       old_rate, new_rate,
1363*4882a593Smuzhiyun 					       false, is_set_clk);
1364*4882a593Smuzhiyun 		rockchip_set_read_margin(dev, opp_info, target_rm, is_set_rm);
1365*4882a593Smuzhiyun 		if (is_set_clk && clk_set_rate(info->clk, new_rate)) {
1366*4882a593Smuzhiyun 			dev_err(dev, "%s: failed to set clock rate: %lu\n",
1367*4882a593Smuzhiyun 				__func__, new_rate);
1368*4882a593Smuzhiyun 			goto restore_rm;
1369*4882a593Smuzhiyun 		}
1370*4882a593Smuzhiyun 		ret = regulator_set_voltage(vdd_reg, new_volt,
1371*4882a593Smuzhiyun 					    INT_MAX);
1372*4882a593Smuzhiyun 		if (ret) {
1373*4882a593Smuzhiyun 			dev_err(dev, "%s: failed to set volt: %lu\n",
1374*4882a593Smuzhiyun 				__func__, new_volt);
1375*4882a593Smuzhiyun 			goto restore_freq;
1376*4882a593Smuzhiyun 		}
1377*4882a593Smuzhiyun 		if (info->regulator_count > 1) {
1378*4882a593Smuzhiyun 			ret = regulator_set_voltage(mem_reg, new_mem_volt,
1379*4882a593Smuzhiyun 						    INT_MAX);
1380*4882a593Smuzhiyun 			if (ret) {
1381*4882a593Smuzhiyun 				dev_err(dev, "%s: failed to set volt: %lu\n",
1382*4882a593Smuzhiyun 					__func__, new_mem_volt);
1383*4882a593Smuzhiyun 				goto restore_freq;
1384*4882a593Smuzhiyun 			}
1385*4882a593Smuzhiyun 		}
1386*4882a593Smuzhiyun 	}
1387*4882a593Smuzhiyun 	goto disable_clk;
1388*4882a593Smuzhiyun 
1389*4882a593Smuzhiyun restore_freq:
1390*4882a593Smuzhiyun 	if (is_set_clk && clk_set_rate(info->clk, old_rate))
1391*4882a593Smuzhiyun 		dev_err(dev, "%s: failed to restore old-freq (%lu Hz)\n",
1392*4882a593Smuzhiyun 			__func__, old_rate);
1393*4882a593Smuzhiyun restore_rm:
1394*4882a593Smuzhiyun 	rockchip_get_read_margin(dev, opp_info, old_volt, &target_rm);
1395*4882a593Smuzhiyun 	rockchip_set_read_margin(dev, opp_info, target_rm, is_set_rm);
1396*4882a593Smuzhiyun restore_voltage:
1397*4882a593Smuzhiyun 	if (info->regulator_count > 1)
1398*4882a593Smuzhiyun 		regulator_set_voltage(mem_reg, old_mem_volt, INT_MAX);
1399*4882a593Smuzhiyun 	regulator_set_voltage(vdd_reg, old_volt, INT_MAX);
1400*4882a593Smuzhiyun disable_clk:
1401*4882a593Smuzhiyun 	rockchip_monitor_disable_opp_clk(dev, opp_info);
1402*4882a593Smuzhiyun unlock:
1403*4882a593Smuzhiyun 	mutex_unlock(&info->volt_adjust_mutex);
1404*4882a593Smuzhiyun 
1405*4882a593Smuzhiyun 	return ret;
1406*4882a593Smuzhiyun }
1407*4882a593Smuzhiyun EXPORT_SYMBOL(rockchip_monitor_check_rate_volt);
1408*4882a593Smuzhiyun 
1409*4882a593Smuzhiyun struct monitor_dev_info *
rockchip_system_monitor_register(struct device * dev,struct monitor_dev_profile * devp)1410*4882a593Smuzhiyun rockchip_system_monitor_register(struct device *dev,
1411*4882a593Smuzhiyun 				 struct monitor_dev_profile *devp)
1412*4882a593Smuzhiyun {
1413*4882a593Smuzhiyun 	struct monitor_dev_info *info;
1414*4882a593Smuzhiyun 
1415*4882a593Smuzhiyun 	if (!system_monitor)
1416*4882a593Smuzhiyun 		return ERR_PTR(-ENOMEM);
1417*4882a593Smuzhiyun 
1418*4882a593Smuzhiyun 	if (!devp)
1419*4882a593Smuzhiyun 		return ERR_PTR(-EINVAL);
1420*4882a593Smuzhiyun 
1421*4882a593Smuzhiyun 	info = kzalloc(sizeof(*info), GFP_KERNEL);
1422*4882a593Smuzhiyun 	if (!info)
1423*4882a593Smuzhiyun 		return ERR_PTR(-ENOMEM);
1424*4882a593Smuzhiyun 	info->dev = dev;
1425*4882a593Smuzhiyun 	info->devp = devp;
1426*4882a593Smuzhiyun 
1427*4882a593Smuzhiyun 	mutex_init(&info->volt_adjust_mutex);
1428*4882a593Smuzhiyun 
1429*4882a593Smuzhiyun 	rockchip_system_monitor_parse_supplies(dev, info);
1430*4882a593Smuzhiyun 	if (monitor_device_parse_dt(dev, info)) {
1431*4882a593Smuzhiyun 		rockchip_monitor_check_rate_volt(info);
1432*4882a593Smuzhiyun 		devp->is_checked = true;
1433*4882a593Smuzhiyun 		kfree(info->set_opp_data);
1434*4882a593Smuzhiyun 		kfree(info);
1435*4882a593Smuzhiyun 		return ERR_PTR(-EINVAL);
1436*4882a593Smuzhiyun 	}
1437*4882a593Smuzhiyun 
1438*4882a593Smuzhiyun 	rockchip_system_monitor_early_regulator_init(info);
1439*4882a593Smuzhiyun 	rockchip_system_monitor_wide_temp_init(info);
1440*4882a593Smuzhiyun 	rockchip_monitor_check_rate_volt(info);
1441*4882a593Smuzhiyun 	devp->is_checked = true;
1442*4882a593Smuzhiyun 	rockchip_system_monitor_freq_qos_requset(info);
1443*4882a593Smuzhiyun 
1444*4882a593Smuzhiyun 	down_write(&mdev_list_sem);
1445*4882a593Smuzhiyun 	list_add(&info->node, &monitor_dev_list);
1446*4882a593Smuzhiyun 	up_write(&mdev_list_sem);
1447*4882a593Smuzhiyun 
1448*4882a593Smuzhiyun 	return info;
1449*4882a593Smuzhiyun }
1450*4882a593Smuzhiyun EXPORT_SYMBOL(rockchip_system_monitor_register);
1451*4882a593Smuzhiyun 
rockchip_system_monitor_unregister(struct monitor_dev_info * info)1452*4882a593Smuzhiyun void rockchip_system_monitor_unregister(struct monitor_dev_info *info)
1453*4882a593Smuzhiyun {
1454*4882a593Smuzhiyun 	if (!info)
1455*4882a593Smuzhiyun 		return;
1456*4882a593Smuzhiyun 
1457*4882a593Smuzhiyun 	down_write(&mdev_list_sem);
1458*4882a593Smuzhiyun 	list_del(&info->node);
1459*4882a593Smuzhiyun 	up_write(&mdev_list_sem);
1460*4882a593Smuzhiyun 
1461*4882a593Smuzhiyun 	if (info->devp->type == MONITOR_TYPE_CPU) {
1462*4882a593Smuzhiyun 		if (freq_qos_request_active(&info->max_temp_freq_req))
1463*4882a593Smuzhiyun 			freq_qos_remove_request(&info->max_temp_freq_req);
1464*4882a593Smuzhiyun 		if (freq_qos_request_active(&info->min_sta_freq_req))
1465*4882a593Smuzhiyun 			freq_qos_remove_request(&info->min_sta_freq_req);
1466*4882a593Smuzhiyun 		if (freq_qos_request_active(&info->max_sta_freq_req))
1467*4882a593Smuzhiyun 			freq_qos_remove_request(&info->max_sta_freq_req);
1468*4882a593Smuzhiyun 	} else {
1469*4882a593Smuzhiyun 		if (dev_pm_qos_request_active(&info->dev_max_freq_req))
1470*4882a593Smuzhiyun 			dev_pm_qos_remove_request(&info->dev_max_freq_req);
1471*4882a593Smuzhiyun 	}
1472*4882a593Smuzhiyun 
1473*4882a593Smuzhiyun 	kfree(info->low_temp_adjust_table);
1474*4882a593Smuzhiyun 	kfree(info->opp_table);
1475*4882a593Smuzhiyun 	kfree(info->set_opp_data);
1476*4882a593Smuzhiyun 	kfree(info);
1477*4882a593Smuzhiyun }
1478*4882a593Smuzhiyun EXPORT_SYMBOL(rockchip_system_monitor_unregister);
1479*4882a593Smuzhiyun 
rockchip_system_monitor_register_notifier(struct notifier_block * nb)1480*4882a593Smuzhiyun int rockchip_system_monitor_register_notifier(struct notifier_block *nb)
1481*4882a593Smuzhiyun {
1482*4882a593Smuzhiyun 	return blocking_notifier_chain_register(&system_monitor_notifier_list, nb);
1483*4882a593Smuzhiyun }
1484*4882a593Smuzhiyun EXPORT_SYMBOL(rockchip_system_monitor_register_notifier);
1485*4882a593Smuzhiyun 
rockchip_system_monitor_unregister_notifier(struct notifier_block * nb)1486*4882a593Smuzhiyun void rockchip_system_monitor_unregister_notifier(struct notifier_block *nb)
1487*4882a593Smuzhiyun {
1488*4882a593Smuzhiyun 	blocking_notifier_chain_unregister(&system_monitor_notifier_list, nb);
1489*4882a593Smuzhiyun }
1490*4882a593Smuzhiyun EXPORT_SYMBOL(rockchip_system_monitor_unregister_notifier);
1491*4882a593Smuzhiyun 
rockchip_system_monitor_temp_notify(int temp)1492*4882a593Smuzhiyun static int rockchip_system_monitor_temp_notify(int temp)
1493*4882a593Smuzhiyun {
1494*4882a593Smuzhiyun 	struct system_monitor_event_data event_data;
1495*4882a593Smuzhiyun 	int ret;
1496*4882a593Smuzhiyun 
1497*4882a593Smuzhiyun 	event_data.temp = temp;
1498*4882a593Smuzhiyun 	ret = blocking_notifier_call_chain(&system_monitor_notifier_list,
1499*4882a593Smuzhiyun 					   SYSTEM_MONITOR_CHANGE_TEMP,
1500*4882a593Smuzhiyun 					   (void *)&event_data);
1501*4882a593Smuzhiyun 
1502*4882a593Smuzhiyun 	return notifier_to_errno(ret);
1503*4882a593Smuzhiyun }
1504*4882a593Smuzhiyun 
notify_dummy(struct thermal_zone_device * tz,int trip)1505*4882a593Smuzhiyun static int notify_dummy(struct thermal_zone_device *tz, int trip)
1506*4882a593Smuzhiyun {
1507*4882a593Smuzhiyun 	return 0;
1508*4882a593Smuzhiyun }
1509*4882a593Smuzhiyun 
1510*4882a593Smuzhiyun static struct thermal_governor thermal_gov_dummy = {
1511*4882a593Smuzhiyun 	.name		= "dummy",
1512*4882a593Smuzhiyun 	.throttle	= notify_dummy,
1513*4882a593Smuzhiyun };
1514*4882a593Smuzhiyun 
rockchip_system_monitor_parse_dt(struct system_monitor * monitor)1515*4882a593Smuzhiyun static int rockchip_system_monitor_parse_dt(struct system_monitor *monitor)
1516*4882a593Smuzhiyun {
1517*4882a593Smuzhiyun 	struct device_node *np = monitor->dev->of_node;
1518*4882a593Smuzhiyun 	const char *tz_name, *buf = NULL;
1519*4882a593Smuzhiyun 
1520*4882a593Smuzhiyun 	if (of_property_read_string(np, "rockchip,video-4k-offline-cpus", &buf))
1521*4882a593Smuzhiyun 		cpumask_clear(&monitor->video_4k_offline_cpus);
1522*4882a593Smuzhiyun 	else
1523*4882a593Smuzhiyun 		cpulist_parse(buf, &monitor->video_4k_offline_cpus);
1524*4882a593Smuzhiyun 
1525*4882a593Smuzhiyun 	if (of_property_read_string(np, "rockchip,thermal-zone", &tz_name))
1526*4882a593Smuzhiyun 		goto out;
1527*4882a593Smuzhiyun 	monitor->tz = thermal_zone_get_zone_by_name(tz_name);
1528*4882a593Smuzhiyun 	if (IS_ERR(monitor->tz)) {
1529*4882a593Smuzhiyun 		monitor->tz = NULL;
1530*4882a593Smuzhiyun 		goto out;
1531*4882a593Smuzhiyun 	}
1532*4882a593Smuzhiyun 	if (of_property_read_u32(np, "rockchip,polling-delay",
1533*4882a593Smuzhiyun 				 &monitor->delay))
1534*4882a593Smuzhiyun 		monitor->delay = THERMAL_POLLING_DELAY;
1535*4882a593Smuzhiyun 
1536*4882a593Smuzhiyun 	if (of_property_read_string(np, "rockchip,temp-offline-cpus",
1537*4882a593Smuzhiyun 				    &buf))
1538*4882a593Smuzhiyun 		cpumask_clear(&system_monitor->temp_offline_cpus);
1539*4882a593Smuzhiyun 	else
1540*4882a593Smuzhiyun 		cpulist_parse(buf, &system_monitor->temp_offline_cpus);
1541*4882a593Smuzhiyun 
1542*4882a593Smuzhiyun 	if (of_property_read_u32(np, "rockchip,offline-cpu-temp",
1543*4882a593Smuzhiyun 				 &system_monitor->offline_cpus_temp))
1544*4882a593Smuzhiyun 		system_monitor->offline_cpus_temp = INT_MAX;
1545*4882a593Smuzhiyun 	of_property_read_u32(np, "rockchip,temp-hysteresis",
1546*4882a593Smuzhiyun 			     &system_monitor->temp_hysteresis);
1547*4882a593Smuzhiyun 
1548*4882a593Smuzhiyun 	if (of_find_property(np, "rockchip,thermal-governor-dummy", NULL)) {
1549*4882a593Smuzhiyun 		if (monitor->tz->governor->unbind_from_tz)
1550*4882a593Smuzhiyun 			monitor->tz->governor->unbind_from_tz(monitor->tz);
1551*4882a593Smuzhiyun 		monitor->tz->governor = &thermal_gov_dummy;
1552*4882a593Smuzhiyun 	}
1553*4882a593Smuzhiyun 
1554*4882a593Smuzhiyun out:
1555*4882a593Smuzhiyun 	return 0;
1556*4882a593Smuzhiyun }
1557*4882a593Smuzhiyun 
rockchip_system_monitor_cpu_on_off(void)1558*4882a593Smuzhiyun static void rockchip_system_monitor_cpu_on_off(void)
1559*4882a593Smuzhiyun {
1560*4882a593Smuzhiyun #ifdef CONFIG_HOTPLUG_CPU
1561*4882a593Smuzhiyun 	struct cpumask online_cpus, offline_cpus;
1562*4882a593Smuzhiyun 	unsigned int cpu;
1563*4882a593Smuzhiyun 
1564*4882a593Smuzhiyun 	mutex_lock(&cpu_on_off_mutex);
1565*4882a593Smuzhiyun 
1566*4882a593Smuzhiyun 	cpumask_clear(&offline_cpus);
1567*4882a593Smuzhiyun 	if (system_monitor->is_temp_offline) {
1568*4882a593Smuzhiyun 		cpumask_or(&offline_cpus, &system_monitor->status_offline_cpus,
1569*4882a593Smuzhiyun 			   &system_monitor->temp_offline_cpus);
1570*4882a593Smuzhiyun 	} else {
1571*4882a593Smuzhiyun 		cpumask_copy(&offline_cpus,
1572*4882a593Smuzhiyun 			     &system_monitor->status_offline_cpus);
1573*4882a593Smuzhiyun 	}
1574*4882a593Smuzhiyun 	if (cpumask_equal(&offline_cpus, &system_monitor->offline_cpus))
1575*4882a593Smuzhiyun 		goto out;
1576*4882a593Smuzhiyun 	cpumask_copy(&system_monitor->offline_cpus, &offline_cpus);
1577*4882a593Smuzhiyun 	for_each_cpu(cpu, &system_monitor->offline_cpus) {
1578*4882a593Smuzhiyun 		if (cpu_online(cpu))
1579*4882a593Smuzhiyun 			remove_cpu(cpu);
1580*4882a593Smuzhiyun 	}
1581*4882a593Smuzhiyun 
1582*4882a593Smuzhiyun 	cpumask_clear(&online_cpus);
1583*4882a593Smuzhiyun 	cpumask_andnot(&online_cpus, cpu_possible_mask,
1584*4882a593Smuzhiyun 		       &system_monitor->offline_cpus);
1585*4882a593Smuzhiyun 	cpumask_xor(&online_cpus, cpu_online_mask, &online_cpus);
1586*4882a593Smuzhiyun 	if (cpumask_empty(&online_cpus))
1587*4882a593Smuzhiyun 		goto out;
1588*4882a593Smuzhiyun 	for_each_cpu(cpu, &online_cpus)
1589*4882a593Smuzhiyun 		add_cpu(cpu);
1590*4882a593Smuzhiyun 
1591*4882a593Smuzhiyun out:
1592*4882a593Smuzhiyun 	mutex_unlock(&cpu_on_off_mutex);
1593*4882a593Smuzhiyun #endif
1594*4882a593Smuzhiyun }
1595*4882a593Smuzhiyun 
rockchip_system_monitor_temp_cpu_on_off(int temp)1596*4882a593Smuzhiyun static void rockchip_system_monitor_temp_cpu_on_off(int temp)
1597*4882a593Smuzhiyun {
1598*4882a593Smuzhiyun 	bool is_temp_offline;
1599*4882a593Smuzhiyun 
1600*4882a593Smuzhiyun 	if (cpumask_empty(&system_monitor->temp_offline_cpus))
1601*4882a593Smuzhiyun 		return;
1602*4882a593Smuzhiyun 
1603*4882a593Smuzhiyun 	if (temp > system_monitor->offline_cpus_temp)
1604*4882a593Smuzhiyun 		is_temp_offline = true;
1605*4882a593Smuzhiyun 	else if (temp < system_monitor->offline_cpus_temp -
1606*4882a593Smuzhiyun 		 system_monitor->temp_hysteresis)
1607*4882a593Smuzhiyun 		is_temp_offline = false;
1608*4882a593Smuzhiyun 	else
1609*4882a593Smuzhiyun 		return;
1610*4882a593Smuzhiyun 
1611*4882a593Smuzhiyun 	if (system_monitor->is_temp_offline == is_temp_offline)
1612*4882a593Smuzhiyun 		return;
1613*4882a593Smuzhiyun 	system_monitor->is_temp_offline = is_temp_offline;
1614*4882a593Smuzhiyun 	rockchip_system_monitor_cpu_on_off();
1615*4882a593Smuzhiyun }
1616*4882a593Smuzhiyun 
rockchip_system_monitor_thermal_update(void)1617*4882a593Smuzhiyun static void rockchip_system_monitor_thermal_update(void)
1618*4882a593Smuzhiyun {
1619*4882a593Smuzhiyun 	int temp, ret;
1620*4882a593Smuzhiyun 	struct monitor_dev_info *info;
1621*4882a593Smuzhiyun 
1622*4882a593Smuzhiyun 	ret = thermal_zone_get_temp(system_monitor->tz, &temp);
1623*4882a593Smuzhiyun 	if (ret || temp == THERMAL_TEMP_INVALID)
1624*4882a593Smuzhiyun 		goto out;
1625*4882a593Smuzhiyun 
1626*4882a593Smuzhiyun 	dev_dbg(system_monitor->dev, "temperature=%d\n", temp);
1627*4882a593Smuzhiyun 
1628*4882a593Smuzhiyun 	if (temp < system_monitor->last_temp &&
1629*4882a593Smuzhiyun 	    system_monitor->last_temp - temp <= 2000)
1630*4882a593Smuzhiyun 		goto out;
1631*4882a593Smuzhiyun 	system_monitor->last_temp = temp;
1632*4882a593Smuzhiyun 
1633*4882a593Smuzhiyun 	rockchip_system_monitor_temp_notify(temp);
1634*4882a593Smuzhiyun 
1635*4882a593Smuzhiyun 	down_read(&mdev_list_sem);
1636*4882a593Smuzhiyun 	list_for_each_entry(info, &monitor_dev_list, node)
1637*4882a593Smuzhiyun 		rockchip_system_monitor_wide_temp_adjust(info, temp);
1638*4882a593Smuzhiyun 	up_read(&mdev_list_sem);
1639*4882a593Smuzhiyun 
1640*4882a593Smuzhiyun 	rockchip_system_monitor_temp_cpu_on_off(temp);
1641*4882a593Smuzhiyun 
1642*4882a593Smuzhiyun out:
1643*4882a593Smuzhiyun 	mod_delayed_work(system_freezable_wq, &system_monitor->thermal_work,
1644*4882a593Smuzhiyun 			 msecs_to_jiffies(system_monitor->delay));
1645*4882a593Smuzhiyun }
1646*4882a593Smuzhiyun 
rockchip_system_monitor_thermal_check(struct work_struct * work)1647*4882a593Smuzhiyun static void rockchip_system_monitor_thermal_check(struct work_struct *work)
1648*4882a593Smuzhiyun {
1649*4882a593Smuzhiyun 	if (atomic_read(&monitor_in_suspend))
1650*4882a593Smuzhiyun 		return;
1651*4882a593Smuzhiyun 
1652*4882a593Smuzhiyun 	rockchip_system_monitor_thermal_update();
1653*4882a593Smuzhiyun }
1654*4882a593Smuzhiyun 
rockchip_system_status_cpu_limit_freq(struct monitor_dev_info * info,unsigned long status)1655*4882a593Smuzhiyun static void rockchip_system_status_cpu_limit_freq(struct monitor_dev_info *info,
1656*4882a593Smuzhiyun 						  unsigned long status)
1657*4882a593Smuzhiyun {
1658*4882a593Smuzhiyun 	unsigned int target_freq = 0;
1659*4882a593Smuzhiyun 
1660*4882a593Smuzhiyun 	if (!freq_qos_request_active(&info->min_sta_freq_req))
1661*4882a593Smuzhiyun 		return;
1662*4882a593Smuzhiyun 	if (!freq_qos_request_active(&info->max_sta_freq_req))
1663*4882a593Smuzhiyun 		return;
1664*4882a593Smuzhiyun 
1665*4882a593Smuzhiyun 	if (status & SYS_STATUS_REBOOT) {
1666*4882a593Smuzhiyun 		freq_qos_update_request(&info->max_sta_freq_req,
1667*4882a593Smuzhiyun 					info->reboot_freq);
1668*4882a593Smuzhiyun 		freq_qos_update_request(&info->min_sta_freq_req,
1669*4882a593Smuzhiyun 					info->reboot_freq);
1670*4882a593Smuzhiyun 		return;
1671*4882a593Smuzhiyun 	}
1672*4882a593Smuzhiyun 
1673*4882a593Smuzhiyun 	if (info->video_4k_freq && (status & SYS_STATUS_VIDEO_4K))
1674*4882a593Smuzhiyun 		target_freq = info->video_4k_freq;
1675*4882a593Smuzhiyun 
1676*4882a593Smuzhiyun 	if (target_freq == info->status_max_limit)
1677*4882a593Smuzhiyun 		return;
1678*4882a593Smuzhiyun 	info->status_max_limit = target_freq;
1679*4882a593Smuzhiyun 	if (info->status_max_limit)
1680*4882a593Smuzhiyun 		freq_qos_update_request(&info->max_sta_freq_req,
1681*4882a593Smuzhiyun 					info->status_max_limit);
1682*4882a593Smuzhiyun 	else
1683*4882a593Smuzhiyun 		freq_qos_update_request(&info->max_sta_freq_req,
1684*4882a593Smuzhiyun 					FREQ_QOS_MAX_DEFAULT_VALUE);
1685*4882a593Smuzhiyun }
1686*4882a593Smuzhiyun 
rockchip_system_status_limit_freq(unsigned long status)1687*4882a593Smuzhiyun static void rockchip_system_status_limit_freq(unsigned long status)
1688*4882a593Smuzhiyun {
1689*4882a593Smuzhiyun 	struct monitor_dev_info *info;
1690*4882a593Smuzhiyun 
1691*4882a593Smuzhiyun 	down_read(&mdev_list_sem);
1692*4882a593Smuzhiyun 	list_for_each_entry(info, &monitor_dev_list, node) {
1693*4882a593Smuzhiyun 		if (info->devp->type == MONITOR_TYPE_CPU)
1694*4882a593Smuzhiyun 			rockchip_system_status_cpu_limit_freq(info, status);
1695*4882a593Smuzhiyun 	}
1696*4882a593Smuzhiyun 	up_read(&mdev_list_sem);
1697*4882a593Smuzhiyun }
1698*4882a593Smuzhiyun 
rockchip_system_status_cpu_on_off(unsigned long status)1699*4882a593Smuzhiyun static void rockchip_system_status_cpu_on_off(unsigned long status)
1700*4882a593Smuzhiyun {
1701*4882a593Smuzhiyun 	struct cpumask offline_cpus;
1702*4882a593Smuzhiyun 
1703*4882a593Smuzhiyun 	if (cpumask_empty(&system_monitor->video_4k_offline_cpus))
1704*4882a593Smuzhiyun 		return;
1705*4882a593Smuzhiyun 
1706*4882a593Smuzhiyun 	cpumask_clear(&offline_cpus);
1707*4882a593Smuzhiyun 	if (status & SYS_STATUS_VIDEO_4K)
1708*4882a593Smuzhiyun 		cpumask_copy(&offline_cpus,
1709*4882a593Smuzhiyun 			     &system_monitor->video_4k_offline_cpus);
1710*4882a593Smuzhiyun 	if (cpumask_equal(&offline_cpus, &system_monitor->status_offline_cpus))
1711*4882a593Smuzhiyun 		return;
1712*4882a593Smuzhiyun 	cpumask_copy(&system_monitor->status_offline_cpus, &offline_cpus);
1713*4882a593Smuzhiyun 	rockchip_system_monitor_cpu_on_off();
1714*4882a593Smuzhiyun }
1715*4882a593Smuzhiyun 
rockchip_system_status_notifier(struct notifier_block * nb,unsigned long status,void * ptr)1716*4882a593Smuzhiyun static int rockchip_system_status_notifier(struct notifier_block *nb,
1717*4882a593Smuzhiyun 					   unsigned long status,
1718*4882a593Smuzhiyun 					   void *ptr)
1719*4882a593Smuzhiyun {
1720*4882a593Smuzhiyun 	rockchip_system_status_limit_freq(status);
1721*4882a593Smuzhiyun 
1722*4882a593Smuzhiyun 	rockchip_system_status_cpu_on_off(status);
1723*4882a593Smuzhiyun 
1724*4882a593Smuzhiyun 	return NOTIFY_OK;
1725*4882a593Smuzhiyun }
1726*4882a593Smuzhiyun 
rockchip_system_monitor_set_cpu_uevent_suppress(bool is_suppress)1727*4882a593Smuzhiyun static int rockchip_system_monitor_set_cpu_uevent_suppress(bool is_suppress)
1728*4882a593Smuzhiyun {
1729*4882a593Smuzhiyun 	struct monitor_dev_info *info;
1730*4882a593Smuzhiyun 	struct cpufreq_policy *policy;
1731*4882a593Smuzhiyun 
1732*4882a593Smuzhiyun 	list_for_each_entry(info, &monitor_dev_list, node) {
1733*4882a593Smuzhiyun 		if (info->devp->type != MONITOR_TYPE_CPU)
1734*4882a593Smuzhiyun 			continue;
1735*4882a593Smuzhiyun 		policy = (struct cpufreq_policy *)info->devp->data;
1736*4882a593Smuzhiyun 		if (!policy || !policy->cdev)
1737*4882a593Smuzhiyun 			continue;
1738*4882a593Smuzhiyun 		if (is_suppress)
1739*4882a593Smuzhiyun 			dev_set_uevent_suppress(&policy->cdev->device, 1);
1740*4882a593Smuzhiyun 		else
1741*4882a593Smuzhiyun 			dev_set_uevent_suppress(&policy->cdev->device, 0);
1742*4882a593Smuzhiyun 	}
1743*4882a593Smuzhiyun 
1744*4882a593Smuzhiyun 	return 0;
1745*4882a593Smuzhiyun }
1746*4882a593Smuzhiyun 
monitor_pm_notify(struct notifier_block * nb,unsigned long mode,void * _unused)1747*4882a593Smuzhiyun static int monitor_pm_notify(struct notifier_block *nb,
1748*4882a593Smuzhiyun 			     unsigned long mode, void *_unused)
1749*4882a593Smuzhiyun {
1750*4882a593Smuzhiyun 	switch (mode) {
1751*4882a593Smuzhiyun 	case PM_HIBERNATION_PREPARE:
1752*4882a593Smuzhiyun 	case PM_RESTORE_PREPARE:
1753*4882a593Smuzhiyun 	case PM_SUSPEND_PREPARE:
1754*4882a593Smuzhiyun 		atomic_set(&monitor_in_suspend, 1);
1755*4882a593Smuzhiyun 		rockchip_system_monitor_set_cpu_uevent_suppress(true);
1756*4882a593Smuzhiyun 		break;
1757*4882a593Smuzhiyun 	case PM_POST_HIBERNATION:
1758*4882a593Smuzhiyun 	case PM_POST_RESTORE:
1759*4882a593Smuzhiyun 	case PM_POST_SUSPEND:
1760*4882a593Smuzhiyun 		if (system_monitor->tz)
1761*4882a593Smuzhiyun 			rockchip_system_monitor_thermal_update();
1762*4882a593Smuzhiyun 		atomic_set(&monitor_in_suspend, 0);
1763*4882a593Smuzhiyun 		rockchip_system_monitor_set_cpu_uevent_suppress(false);
1764*4882a593Smuzhiyun 		system_monitor->last_temp = INT_MAX;
1765*4882a593Smuzhiyun 		break;
1766*4882a593Smuzhiyun 	default:
1767*4882a593Smuzhiyun 		break;
1768*4882a593Smuzhiyun 	}
1769*4882a593Smuzhiyun 	return 0;
1770*4882a593Smuzhiyun }
1771*4882a593Smuzhiyun 
1772*4882a593Smuzhiyun static struct notifier_block monitor_pm_nb = {
1773*4882a593Smuzhiyun 	.notifier_call = monitor_pm_notify,
1774*4882a593Smuzhiyun };
1775*4882a593Smuzhiyun 
rockchip_monitor_reboot_notifier(struct notifier_block * nb,unsigned long action,void * ptr)1776*4882a593Smuzhiyun static int rockchip_monitor_reboot_notifier(struct notifier_block *nb,
1777*4882a593Smuzhiyun 					     unsigned long action, void *ptr)
1778*4882a593Smuzhiyun {
1779*4882a593Smuzhiyun 	rockchip_set_system_status(SYS_STATUS_REBOOT);
1780*4882a593Smuzhiyun 	if (system_monitor->tz)
1781*4882a593Smuzhiyun 		cancel_delayed_work_sync(&system_monitor->thermal_work);
1782*4882a593Smuzhiyun 
1783*4882a593Smuzhiyun 	return NOTIFY_OK;
1784*4882a593Smuzhiyun }
1785*4882a593Smuzhiyun 
1786*4882a593Smuzhiyun static struct notifier_block rockchip_monitor_reboot_nb = {
1787*4882a593Smuzhiyun 	.notifier_call = rockchip_monitor_reboot_notifier,
1788*4882a593Smuzhiyun };
1789*4882a593Smuzhiyun 
rockchip_monitor_fb_notifier(struct notifier_block * nb,unsigned long action,void * ptr)1790*4882a593Smuzhiyun static int rockchip_monitor_fb_notifier(struct notifier_block *nb,
1791*4882a593Smuzhiyun 					unsigned long action, void *ptr)
1792*4882a593Smuzhiyun {
1793*4882a593Smuzhiyun 	struct fb_event *event = ptr;
1794*4882a593Smuzhiyun 
1795*4882a593Smuzhiyun 	if (action != FB_EVENT_BLANK)
1796*4882a593Smuzhiyun 		return NOTIFY_OK;
1797*4882a593Smuzhiyun 
1798*4882a593Smuzhiyun 	switch (*((int *)event->data)) {
1799*4882a593Smuzhiyun 	case FB_BLANK_UNBLANK:
1800*4882a593Smuzhiyun 		rockchip_clear_system_status(SYS_STATUS_SUSPEND);
1801*4882a593Smuzhiyun 		break;
1802*4882a593Smuzhiyun 	case FB_BLANK_POWERDOWN:
1803*4882a593Smuzhiyun 		rockchip_set_system_status(SYS_STATUS_SUSPEND);
1804*4882a593Smuzhiyun 		break;
1805*4882a593Smuzhiyun 	default:
1806*4882a593Smuzhiyun 		break;
1807*4882a593Smuzhiyun 	}
1808*4882a593Smuzhiyun 
1809*4882a593Smuzhiyun 	return NOTIFY_OK;
1810*4882a593Smuzhiyun }
1811*4882a593Smuzhiyun 
1812*4882a593Smuzhiyun static struct notifier_block rockchip_monitor_fb_nb = {
1813*4882a593Smuzhiyun 	.notifier_call = rockchip_monitor_fb_notifier,
1814*4882a593Smuzhiyun };
1815*4882a593Smuzhiyun 
rockchip_eink_devfs_notifier(struct notifier_block * nb,unsigned long action,void * ptr)1816*4882a593Smuzhiyun static int rockchip_eink_devfs_notifier(struct notifier_block *nb,
1817*4882a593Smuzhiyun 					unsigned long action, void *ptr)
1818*4882a593Smuzhiyun {
1819*4882a593Smuzhiyun 	switch (action) {
1820*4882a593Smuzhiyun 	case EBC_ON:
1821*4882a593Smuzhiyun 		rockchip_clear_system_status(SYS_STATUS_LOW_POWER);
1822*4882a593Smuzhiyun 		break;
1823*4882a593Smuzhiyun 	case EBC_OFF:
1824*4882a593Smuzhiyun 		rockchip_set_system_status(SYS_STATUS_LOW_POWER);
1825*4882a593Smuzhiyun 		break;
1826*4882a593Smuzhiyun 	default:
1827*4882a593Smuzhiyun 		break;
1828*4882a593Smuzhiyun 	}
1829*4882a593Smuzhiyun 
1830*4882a593Smuzhiyun 	return NOTIFY_OK;
1831*4882a593Smuzhiyun }
1832*4882a593Smuzhiyun 
1833*4882a593Smuzhiyun static struct notifier_block rockchip_monitor_ebc_nb = {
1834*4882a593Smuzhiyun 	.notifier_call = rockchip_eink_devfs_notifier,
1835*4882a593Smuzhiyun };
1836*4882a593Smuzhiyun 
system_monitor_early_min_volt_function(struct work_struct * work)1837*4882a593Smuzhiyun static void system_monitor_early_min_volt_function(struct work_struct *work)
1838*4882a593Smuzhiyun {
1839*4882a593Smuzhiyun 	struct monitor_dev_info *info;
1840*4882a593Smuzhiyun 	struct regulator_dev *rdev;
1841*4882a593Smuzhiyun 	int min_uV, max_uV;
1842*4882a593Smuzhiyun 	int ret;
1843*4882a593Smuzhiyun 
1844*4882a593Smuzhiyun 	down_read(&mdev_list_sem);
1845*4882a593Smuzhiyun 	list_for_each_entry(info, &monitor_dev_list, node) {
1846*4882a593Smuzhiyun 		if (!info->early_min_volt || !info->early_reg)
1847*4882a593Smuzhiyun 			continue;
1848*4882a593Smuzhiyun 		rdev = info->early_reg->rdev;
1849*4882a593Smuzhiyun 		min_uV = rdev->constraints->min_uV;
1850*4882a593Smuzhiyun 		max_uV = rdev->constraints->max_uV;
1851*4882a593Smuzhiyun 		ret = regulator_set_voltage(info->early_reg, min_uV, max_uV);
1852*4882a593Smuzhiyun 		if (ret)
1853*4882a593Smuzhiyun 			dev_err(&rdev->dev,
1854*4882a593Smuzhiyun 				"%s: failed to set volt\n", __func__);
1855*4882a593Smuzhiyun 		regulator_put(info->early_reg);
1856*4882a593Smuzhiyun 	}
1857*4882a593Smuzhiyun 	up_read(&mdev_list_sem);
1858*4882a593Smuzhiyun }
1859*4882a593Smuzhiyun 
1860*4882a593Smuzhiyun static DECLARE_DELAYED_WORK(system_monitor_early_min_volt_work,
1861*4882a593Smuzhiyun 			    system_monitor_early_min_volt_function);
1862*4882a593Smuzhiyun 
rockchip_system_monitor_probe(struct platform_device * pdev)1863*4882a593Smuzhiyun static int rockchip_system_monitor_probe(struct platform_device *pdev)
1864*4882a593Smuzhiyun {
1865*4882a593Smuzhiyun 	struct device *dev = &pdev->dev;
1866*4882a593Smuzhiyun 
1867*4882a593Smuzhiyun 	system_monitor = devm_kzalloc(dev, sizeof(struct system_monitor),
1868*4882a593Smuzhiyun 				      GFP_KERNEL);
1869*4882a593Smuzhiyun 	if (!system_monitor)
1870*4882a593Smuzhiyun 		return -ENOMEM;
1871*4882a593Smuzhiyun 	system_monitor->dev = dev;
1872*4882a593Smuzhiyun 
1873*4882a593Smuzhiyun 	system_monitor->kobj = kobject_create_and_add("system_monitor", NULL);
1874*4882a593Smuzhiyun 	if (!system_monitor->kobj)
1875*4882a593Smuzhiyun 		return -ENOMEM;
1876*4882a593Smuzhiyun 	if (sysfs_create_file(system_monitor->kobj, &status.attr))
1877*4882a593Smuzhiyun 		dev_err(dev, "failed to create system status sysfs\n");
1878*4882a593Smuzhiyun 
1879*4882a593Smuzhiyun 	cpumask_clear(&system_monitor->status_offline_cpus);
1880*4882a593Smuzhiyun 	cpumask_clear(&system_monitor->offline_cpus);
1881*4882a593Smuzhiyun 
1882*4882a593Smuzhiyun 	rockchip_system_monitor_parse_dt(system_monitor);
1883*4882a593Smuzhiyun 	if (system_monitor->tz) {
1884*4882a593Smuzhiyun 		system_monitor->last_temp = INT_MAX;
1885*4882a593Smuzhiyun 		INIT_DELAYED_WORK(&system_monitor->thermal_work,
1886*4882a593Smuzhiyun 				  rockchip_system_monitor_thermal_check);
1887*4882a593Smuzhiyun 		mod_delayed_work(system_freezable_wq,
1888*4882a593Smuzhiyun 				 &system_monitor->thermal_work,
1889*4882a593Smuzhiyun 				 msecs_to_jiffies(system_monitor->delay));
1890*4882a593Smuzhiyun 	}
1891*4882a593Smuzhiyun 
1892*4882a593Smuzhiyun 	system_monitor->status_nb.notifier_call =
1893*4882a593Smuzhiyun 		rockchip_system_status_notifier;
1894*4882a593Smuzhiyun 	rockchip_register_system_status_notifier(&system_monitor->status_nb);
1895*4882a593Smuzhiyun 
1896*4882a593Smuzhiyun 	if (register_pm_notifier(&monitor_pm_nb))
1897*4882a593Smuzhiyun 		dev_err(dev, "failed to register suspend notifier\n");
1898*4882a593Smuzhiyun 
1899*4882a593Smuzhiyun 	register_reboot_notifier(&rockchip_monitor_reboot_nb);
1900*4882a593Smuzhiyun 
1901*4882a593Smuzhiyun 	if (fb_register_client(&rockchip_monitor_fb_nb))
1902*4882a593Smuzhiyun 		dev_err(dev, "failed to register fb nb\n");
1903*4882a593Smuzhiyun 
1904*4882a593Smuzhiyun 	ebc_register_notifier(&rockchip_monitor_ebc_nb);
1905*4882a593Smuzhiyun 
1906*4882a593Smuzhiyun 	schedule_delayed_work(&system_monitor_early_min_volt_work,
1907*4882a593Smuzhiyun 			      msecs_to_jiffies(30000));
1908*4882a593Smuzhiyun 
1909*4882a593Smuzhiyun 	dev_info(dev, "system monitor probe\n");
1910*4882a593Smuzhiyun 
1911*4882a593Smuzhiyun 	return 0;
1912*4882a593Smuzhiyun }
1913*4882a593Smuzhiyun 
1914*4882a593Smuzhiyun static const struct of_device_id rockchip_system_monitor_of_match[] = {
1915*4882a593Smuzhiyun 	{
1916*4882a593Smuzhiyun 		.compatible = "rockchip,system-monitor",
1917*4882a593Smuzhiyun 	},
1918*4882a593Smuzhiyun 	{ /* sentinel */ },
1919*4882a593Smuzhiyun };
1920*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, rockchip_system_monitor_of_match);
1921*4882a593Smuzhiyun 
1922*4882a593Smuzhiyun static struct platform_driver rockchip_system_monitor_driver = {
1923*4882a593Smuzhiyun 	.probe	= rockchip_system_monitor_probe,
1924*4882a593Smuzhiyun 	.driver = {
1925*4882a593Smuzhiyun 		.name	= "rockchip-system-monitor",
1926*4882a593Smuzhiyun 		.of_match_table = rockchip_system_monitor_of_match,
1927*4882a593Smuzhiyun 	},
1928*4882a593Smuzhiyun };
1929*4882a593Smuzhiyun module_platform_driver(rockchip_system_monitor_driver);
1930*4882a593Smuzhiyun 
1931*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
1932*4882a593Smuzhiyun MODULE_AUTHOR("Finley Xiao <finley.xiao@rock-chips.com>");
1933*4882a593Smuzhiyun MODULE_DESCRIPTION("rockchip system monitor driver");
1934