Skip to content

Commit ce39426

Browse files
committed
soc: rockchip: system_monitor: limit frequency at different temperature
This adds support to limit frequency at multiple temperature zones, but the frequency will be also changed by thermal framework if the device is a cooling device. Signed-off-by: Finley Xiao <finley.xiao@rock-chips.com> Change-Id: I609cede78fce7e0a264fb961b422f05a45a7c949
1 parent 2c729a4 commit ce39426

2 files changed

Lines changed: 127 additions & 79 deletions

File tree

drivers/soc/rockchip/rockchip_system_monitor.c

Lines changed: 122 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,44 @@ static ssize_t status_store(struct kobject *kobj, struct kobj_attribute *attr,
381381
static struct system_monitor_attr status =
382382
__ATTR(system_status, 0644, status_show, status_store);
383383

384+
static int rockchip_get_temp_freq_table(struct device_node *np,
385+
char *porp_name,
386+
struct temp_freq_table **freq_table)
387+
{
388+
struct temp_freq_table *table;
389+
const struct property *prop;
390+
int count, i;
391+
392+
prop = of_find_property(np, porp_name, NULL);
393+
if (!prop)
394+
return -EINVAL;
395+
396+
if (!prop->value)
397+
return -ENODATA;
398+
399+
count = of_property_count_u32_elems(np, porp_name);
400+
if (count < 0)
401+
return -EINVAL;
402+
403+
if (count % 2)
404+
return -EINVAL;
405+
406+
table = kzalloc(sizeof(*table) * (count / 2 + 1), GFP_KERNEL);
407+
if (!table)
408+
return -ENOMEM;
409+
410+
for (i = 0; i < count / 2; i++) {
411+
of_property_read_u32_index(np, porp_name, 2 * i,
412+
&table[i].temp);
413+
of_property_read_u32_index(np, porp_name, 2 * i + 1,
414+
&table[i].freq);
415+
}
416+
table[i].freq = UINT_MAX;
417+
*freq_table = table;
418+
419+
return 0;
420+
}
421+
384422
static int rockchip_get_adjust_volt_table(struct device_node *np,
385423
char *porp_name,
386424
struct volt_adjust_table **table)
@@ -553,17 +591,25 @@ static int monitor_device_parse_wide_temp_config(struct device_node *np,
553591
else
554592
info->high_temp_max_volt = value;
555593
rockchip_init_temp_opp_table(info);
556-
if (!of_property_read_u32(np, "rockchip,high-temp-max-freq", &value)) {
557-
high_temp_max_freq = value * 1000;
558-
if (info->high_limit)
559-
info->high_limit = min(high_temp_max_freq,
560-
info->high_limit);
561-
else
562-
info->high_limit = high_temp_max_freq;
594+
if (rockchip_get_temp_freq_table(np, "rockchip,high-temp-limit-table",
595+
&info->high_limit_table)) {
596+
info->high_limit_table = NULL;
597+
if (!of_property_read_u32(np, "rockchip,high-temp-max-freq",
598+
&value)) {
599+
high_temp_max_freq = value * 1000;
600+
if (info->high_limit)
601+
info->high_limit = min(high_temp_max_freq,
602+
info->high_limit);
603+
else
604+
info->high_limit = high_temp_max_freq;
605+
}
606+
} else {
607+
info->high_limit = 0;
563608
}
564-
dev_info(dev, "l=%d h=%d hyst=%d l_limit=%lu h_limit=%lu\n",
609+
dev_info(dev, "l=%d h=%d hyst=%d l_limit=%lu h_limit=%lu h_table=%d\n",
565610
info->low_temp, info->high_temp, info->temp_hysteresis,
566-
info->low_limit, info->high_limit);
611+
info->low_limit, info->high_limit,
612+
info->high_limit_table ? true : false);
567613

568614
if ((info->low_temp + info->temp_hysteresis) > info->high_temp) {
569615
dev_err(dev, "Invalid temperature, low=%d high=%d hyst=%d\n",
@@ -573,7 +619,7 @@ static int monitor_device_parse_wide_temp_config(struct device_node *np,
573619
goto err;
574620
}
575621
if (!info->low_temp_adjust_table && !info->low_temp_min_volt &&
576-
!info->low_limit && !info->high_limit) {
622+
!info->low_limit && !info->high_limit && !info->high_limit_table) {
577623
ret = -EINVAL;
578624
goto err;
579625
}
@@ -609,44 +655,6 @@ static int monitor_device_parse_status_config(struct device_node *np,
609655
return ret;
610656
}
611657

612-
static int rockchip_get_temp_freq_table(struct device_node *np,
613-
char *porp_name,
614-
struct temp_freq_table **freq_table)
615-
{
616-
struct temp_freq_table *table;
617-
const struct property *prop;
618-
int count, i;
619-
620-
prop = of_find_property(np, porp_name, NULL);
621-
if (!prop)
622-
return -EINVAL;
623-
624-
if (!prop->value)
625-
return -ENODATA;
626-
627-
count = of_property_count_u32_elems(np, porp_name);
628-
if (count < 0)
629-
return -EINVAL;
630-
631-
if (count % 2)
632-
return -EINVAL;
633-
634-
table = kzalloc(sizeof(*table) * (count / 2 + 1), GFP_KERNEL);
635-
if (!table)
636-
return -ENOMEM;
637-
638-
for (i = 0; i < count / 2; i++) {
639-
of_property_read_u32_index(np, porp_name, 2 * i,
640-
&table[i].temp);
641-
of_property_read_u32_index(np, porp_name, 2 * i + 1,
642-
&table[i].freq);
643-
}
644-
table[i].freq = UINT_MAX;
645-
*freq_table = table;
646-
647-
return 0;
648-
}
649-
650658
static int monitor_device_parse_dt(struct device *dev,
651659
struct monitor_dev_info *info)
652660
{
@@ -717,12 +725,17 @@ int rockchip_monitor_cpu_high_temp_adjust(struct monitor_dev_info *info,
717725
{
718726
unsigned int cpu = cpumask_any(&info->devp->allowed_cpus);
719727

720-
if (info->high_limit) {
721-
if (is_high)
722-
info->wide_temp_limit = info->high_limit;
723-
else
724-
info->wide_temp_limit = 0;
728+
if (info->high_limit_table) {
729+
info->wide_temp_limit = info->high_limit;
725730
cpufreq_update_policy(cpu);
731+
} else {
732+
if (info->high_limit) {
733+
if (is_high)
734+
info->wide_temp_limit = info->high_limit;
735+
else
736+
info->wide_temp_limit = 0;
737+
cpufreq_update_policy(cpu);
738+
}
726739
}
727740

728741
return 0;
@@ -767,16 +780,23 @@ int rockchip_monitor_dev_high_temp_adjust(struct monitor_dev_info *info,
767780
{
768781
struct devfreq *df;
769782

770-
if (info->high_limit) {
771-
if (is_high)
772-
info->wide_temp_limit = info->high_limit;
773-
else
774-
info->wide_temp_limit = 0;
775-
}
776-
777-
if (info->devp && info->devp->data) {
778-
df = (struct devfreq *)info->devp->data;
779-
rockchip_monitor_update_devfreq(df);
783+
if (info->high_limit_table) {
784+
info->wide_temp_limit = info->high_limit;
785+
if (info->devp && info->devp->data) {
786+
df = (struct devfreq *)info->devp->data;
787+
rockchip_monitor_update_devfreq(df);
788+
}
789+
} else {
790+
if (info->high_limit) {
791+
if (is_high)
792+
info->wide_temp_limit = info->high_limit;
793+
else
794+
info->wide_temp_limit = 0;
795+
if (info->devp && info->devp->data) {
796+
df = (struct devfreq *)info->devp->data;
797+
rockchip_monitor_update_devfreq(df);
798+
}
799+
}
780800
}
781801

782802
return 0;
@@ -850,20 +870,28 @@ static void rockchip_high_temp_adjust(struct monitor_dev_info *info,
850870
struct monitor_dev_profile *devp = info->devp;
851871
int ret = 0;
852872

853-
dev_dbg(info->dev, "high_temp %d\n", is_high);
854-
if (devp->high_temp_adjust)
855-
ret = devp->high_temp_adjust(info, is_high);
856-
if (!ret)
857-
info->is_high_temp = is_high;
873+
if (info->high_limit_table) {
874+
devp->high_temp_adjust(info, is_high);
875+
} else {
876+
dev_dbg(info->dev, "high_temp %d\n", is_high);
877+
if (devp->high_temp_adjust)
878+
ret = devp->high_temp_adjust(info, is_high);
879+
if (!ret)
880+
info->is_high_temp = is_high;
881+
}
858882
}
859883

860884
int rockchip_monitor_suspend_low_temp_adjust(struct monitor_dev_info *info)
861885
{
862886
if (!info || !info->is_low_temp_enabled)
863887
return 0;
864888

865-
if (info->is_high_temp)
889+
if (info->high_limit_table) {
890+
info->high_limit = 0;
891+
rockchip_high_temp_adjust(info, true);
892+
} else if (info->is_high_temp) {
866893
rockchip_high_temp_adjust(info, false);
894+
}
867895
if (!info->is_low_temp)
868896
rockchip_low_temp_adjust(info, true);
869897

@@ -875,24 +903,35 @@ static int
875903
rockchip_system_monitor_wide_temp_adjust(struct monitor_dev_info *info,
876904
int temp)
877905
{
906+
unsigned long target_freq = 0;
907+
int i;
908+
878909
if (temp < info->low_temp) {
879-
if (info->is_high_temp)
880-
rockchip_high_temp_adjust(info, false);
881910
if (!info->is_low_temp)
882911
rockchip_low_temp_adjust(info, true);
883912
} else if (temp > (info->low_temp + info->temp_hysteresis)) {
884913
if (info->is_low_temp)
885914
rockchip_low_temp_adjust(info, false);
886915
}
887916

888-
if (temp > info->high_temp) {
889-
if (info->is_low_temp)
890-
rockchip_low_temp_adjust(info, false);
891-
if (!info->is_high_temp)
917+
if (info->high_limit_table) {
918+
for (i = 0; info->high_limit_table[i].freq != UINT_MAX; i++) {
919+
if (temp > info->high_limit_table[i].temp)
920+
target_freq =
921+
info->high_limit_table[i].freq * 1000;
922+
}
923+
if (target_freq != info->high_limit) {
924+
info->high_limit = target_freq;
892925
rockchip_high_temp_adjust(info, true);
893-
} else if (temp < (info->high_temp - info->temp_hysteresis)) {
894-
if (info->is_high_temp)
895-
rockchip_high_temp_adjust(info, false);
926+
}
927+
} else {
928+
if (temp > info->high_temp) {
929+
if (!info->is_high_temp)
930+
rockchip_high_temp_adjust(info, true);
931+
} else if (temp < (info->high_temp - info->temp_hysteresis)) {
932+
if (info->is_high_temp)
933+
rockchip_high_temp_adjust(info, false);
934+
}
896935
}
897936

898937
return 0;
@@ -1225,13 +1264,18 @@ static void rockchip_system_monitor_thermal_update(void)
12251264
{
12261265
int temp, ret;
12271266
struct monitor_dev_info *info;
1267+
static int last_temp = INT_MAX;
12281268

12291269
ret = thermal_zone_get_temp(system_monitor->tz, &temp);
12301270
if (ret || temp == THERMAL_TEMP_INVALID)
12311271
goto out;
12321272

12331273
dev_dbg(system_monitor->dev, "temperature=%d\n", temp);
12341274

1275+
if (temp < last_temp && last_temp - temp <= 2000)
1276+
goto out;
1277+
last_temp = temp;
1278+
12351279
down_read(&mdev_list_sem);
12361280
list_for_each_entry(info, &monitor_dev_list, node)
12371281
rockchip_system_monitor_wide_temp_adjust(info, temp);

include/soc/rockchip/rockchip_system_monitor.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,10 @@ struct temp_opp_table {
4646
* @opp_table: Frequency and voltage information of device
4747
* @devp: Device-specific system monitor profile
4848
* @node: Node in monitor_dev_list
49-
* @temp_freq_table: Maximum frequency at different temperature
49+
* @temp_freq_table: Maximum frequency at different temperature and the
50+
* frequency will not be changed by thermal framework.
51+
* @high_limit_table: Limit maximum frequency at different temperature,
52+
* but the frequency is also changed by thermal framework.
5053
* @volt_adjust_mutex: A mutex to protect changing voltage.
5154
* @low_limit: Limit maximum frequency when low temperature, in Hz
5255
* @high_limit: Limit maximum frequency when high temperature, in Hz
@@ -79,6 +82,7 @@ struct monitor_dev_info {
7982
struct monitor_dev_profile *devp;
8083
struct list_head node;
8184
struct temp_freq_table *temp_freq_table;
85+
struct temp_freq_table *high_limit_table;
8286
struct mutex volt_adjust_mutex;
8387
unsigned long low_limit;
8488
unsigned long high_limit;

0 commit comments

Comments
 (0)