rk3368: dvfs: add temperature control
authorXiao Feng <xf@rock-chips.com>
Tue, 24 Mar 2015 13:06:42 +0000 (21:06 +0800)
committerHuang, Tao <huangtao@rock-chips.com>
Tue, 24 Mar 2015 13:33:35 +0000 (21:33 +0800)
Signed-off-by: Xiao Feng <xf@rock-chips.com>
arch/arm/mach-rockchip/dvfs.c
arch/arm64/boot/dts/rk3368.dtsi
include/linux/rockchip/common.h

index 20cb311198b173222fc3302b2c9bc08d6c89ec7b..382e37fdc0f47b3805a312ff94e0f62be542de7d 100644 (file)
 static LIST_HEAD(rk_dvfs_tree);
 static DEFINE_MUTEX(rk_dvfs_mutex);
 static struct workqueue_struct *dvfs_wq;
+static struct dvfs_node *clk_cpu_b_dvfs_node;
+static struct dvfs_node *clk_cpu_l_dvfs_node;
+static struct dvfs_node *clk_cpu_bl_dvfs_node;
 static struct dvfs_node *clk_cpu_dvfs_node;
 static struct dvfs_node *clk_gpu_dvfs_node;
 static int pd_gpu_off, early_suspend;
 static DEFINE_MUTEX(switch_vdd_gpu_mutex);
 struct regulator *vdd_gpu_regulator;
 
+static int dvfs_get_temp(int chn)
+{
+       int temp = 0;
+
+#if IS_ENABLED(CONFIG_ROCKCHIP_THERMAL)
+       int read_back = 0;
+
+       mutex_lock(&clk_cpu_bl_dvfs_node->vd->mutex);
+       read_back = dvfs_regulator_get_voltage(
+               clk_cpu_bl_dvfs_node->vd->regulator);
+       temp = rockchip_tsadc_get_temp(chn, read_back);
+       mutex_unlock(&clk_cpu_bl_dvfs_node->vd->mutex);
+#else
+       temp = rockchip_tsadc_get_temp(chn);
+#endif
+
+       return temp;
+}
+
 static int vdd_gpu_reboot_notifier_event(struct notifier_block *this,
        unsigned long event, void *ptr)
 {
@@ -959,7 +981,11 @@ static int pvtm_set_single_dvfs(struct dvfs_node *dvfs_node, u32 idx,
                n++;
 
        pvtm_margin = n*info->delta_pvtm_by_volt;
-       temp = rockchip_tsadc_get_temp(1);
+       if (cpu_is_rk3288())
+               temp = dvfs_get_temp(1);
+       else
+               temp = dvfs_get_temp(0);
+
        target_pvtm = min_pvtm+temp * info->delta_pvtm_by_temp + pvtm_margin;
 
        DVFS_DBG("=====%s: temp:%d, freq:%d, target pvtm:%d=====\n",
@@ -1190,22 +1216,38 @@ static void dvfs_temp_limit(struct dvfs_node *dvfs_node, int temp)
        DVFS_DBG("cur temp: %d, temp_limit_core_rate: %lu\n",
                 temp, dvfs_node->temp_limit_rate);
 }
+
 static void dvfs_temp_limit_work_func(struct work_struct *work)
 {
        unsigned long delay = HZ/10;
-       int temp = 0;
+       int temp = INVALID_TEMP;
 
        queue_delayed_work_on(0, dvfs_wq, to_delayed_work(work), delay);
 
-       if (clk_cpu_dvfs_node->temp_limit_enable == 1) {
-               temp = rockchip_tsadc_get_temp(1);
+       if (clk_cpu_b_dvfs_node &&
+           clk_cpu_b_dvfs_node->temp_limit_enable == 1) {
+               temp = dvfs_get_temp(0);
+               if (temp != INVALID_TEMP)
+                       dvfs_temp_limit(clk_cpu_b_dvfs_node, temp);
+       }
+       if (clk_cpu_l_dvfs_node &&
+           clk_cpu_l_dvfs_node->temp_limit_enable == 1) {
+               if (temp == INVALID_TEMP)
+                       temp = dvfs_get_temp(0);
+               if (temp != INVALID_TEMP)
+                       dvfs_temp_limit(clk_cpu_l_dvfs_node, temp);
+       }
+       if (clk_cpu_dvfs_node &&
+           clk_cpu_dvfs_node->temp_limit_enable == 1) {
+               temp = dvfs_get_temp(1);
                if (temp == INVALID_TEMP)
                        dvfs_virt_temp_limit_work_func(clk_cpu_dvfs_node);
                else
                        dvfs_temp_limit(clk_cpu_dvfs_node, temp);
        }
-       if (clk_gpu_dvfs_node->temp_limit_enable == 1) {
-               temp = rockchip_tsadc_get_temp(2);
+       if (clk_gpu_dvfs_node &&
+           clk_gpu_dvfs_node->temp_limit_enable == 1) {
+               temp = dvfs_get_temp(2);
                if (temp != INVALID_TEMP)
                        dvfs_temp_limit(clk_gpu_dvfs_node, temp);
        }
@@ -1281,6 +1323,10 @@ int dvfs_clk_disable_limit(struct dvfs_node *clk_dvfs_node)
 EXPORT_SYMBOL(dvfs_clk_disable_limit);
 
 void dvfs_disable_temp_limit(void) {
+       if (clk_cpu_b_dvfs_node)
+               clk_cpu_b_dvfs_node->temp_limit_enable = 0;
+       if (clk_cpu_l_dvfs_node)
+               clk_cpu_l_dvfs_node->temp_limit_enable = 0;
        if (clk_cpu_dvfs_node)
                clk_cpu_dvfs_node->temp_limit_enable = 0;
        if (clk_gpu_dvfs_node)
@@ -2341,19 +2387,38 @@ static int __init dvfs_init(void)
                }
        }
 
+       clk_cpu_b_dvfs_node = clk_get_dvfs_node("clk_core_b");
+       if (clk_cpu_b_dvfs_node) {
+               clk_cpu_b_dvfs_node->temp_limit_rate =
+               clk_cpu_b_dvfs_node->max_rate;
+               if (clk_cpu_bl_dvfs_node == NULL)
+                       clk_cpu_bl_dvfs_node = clk_cpu_b_dvfs_node;
+       }
+
+       clk_cpu_l_dvfs_node = clk_get_dvfs_node("clk_core_l");
+       if (clk_cpu_l_dvfs_node) {
+               clk_cpu_l_dvfs_node->temp_limit_rate =
+               clk_cpu_l_dvfs_node->max_rate;
+               if (clk_cpu_bl_dvfs_node == NULL)
+                       clk_cpu_bl_dvfs_node = clk_cpu_l_dvfs_node;
+       }
+
        clk_cpu_dvfs_node = clk_get_dvfs_node("clk_core");
-       if (!clk_cpu_dvfs_node)
-               return -EINVAL;
-       clk_cpu_dvfs_node->temp_limit_rate = clk_cpu_dvfs_node->max_rate;
+       if (clk_cpu_dvfs_node)
+               clk_cpu_dvfs_node->temp_limit_rate =
+               clk_cpu_dvfs_node->max_rate;
 
        clk_gpu_dvfs_node = clk_get_dvfs_node("clk_gpu");
-       if (!clk_gpu_dvfs_node)
-               return -EINVAL;
-       clk_gpu_dvfs_node->temp_limit_rate = clk_gpu_dvfs_node->max_rate;
-
-       if (clk_cpu_dvfs_node->temp_limit_enable ||
-           clk_gpu_dvfs_node->temp_limit_enable) {
-               dvfs_wq = alloc_workqueue("dvfs", WQ_NON_REENTRANT | WQ_MEM_RECLAIM | WQ_HIGHPRI | WQ_FREEZABLE, 1);
+       if (clk_gpu_dvfs_node)
+               clk_gpu_dvfs_node->temp_limit_rate =
+               clk_gpu_dvfs_node->max_rate;
+
+       if ((clk_cpu_b_dvfs_node && clk_cpu_b_dvfs_node->temp_limit_enable) ||
+           (clk_cpu_l_dvfs_node && clk_cpu_l_dvfs_node->temp_limit_enable) ||
+           (clk_gpu_dvfs_node && clk_gpu_dvfs_node->temp_limit_enable) ||
+           (clk_cpu_dvfs_node && clk_cpu_dvfs_node->temp_limit_enable)) {
+               dvfs_wq = alloc_workqueue("dvfs", WQ_NON_REENTRANT |
+                       WQ_MEM_RECLAIM | WQ_HIGHPRI | WQ_FREEZABLE, 1);
                queue_delayed_work_on(0, dvfs_wq, &dvfs_temp_limit_work, 0*HZ);
        }
 
index 478dfef621f5cedda847485f09efd944f52a3f63..e6ac58903182cedac0a30432fd7c8c956d27641c 100755 (executable)
                                                1008000 1200000
                                                >;
                                        status = "okay";
+                                       temp-limit-enable = <1>;
+                                       target-temp = <80>;
+                                       min_temp_limit = <216>;
+                                       normal-temp-limit = <
+                                       /*delta-temp    delta-freq*/
+                                               3       96000
+                                               6       144000
+                                               9       192000
+                                               15      384000
+                                               >;
+                                       performance-temp-limit = <
+                                               /*temp    freq*/
+                                               100     816000
+                                               >;
                                };
                                clk_core_l_dvfs_table: clk_core_l {
                                        operating-points = <
                                                1008000 1200000
                                                >;
                                        status = "okay";
+                                       temp-limit-enable = <1>;
+                                       target-temp = <80>;
+                                       min_temp_limit = <216>;
+                                       normal-temp-limit = <
+                                       /*delta-temp    delta-freq*/
+                                               3       96000
+                                               6       144000
+                                               9       192000
+                                               15      384000
+                                               >;
+                                       performance-temp-limit = <
+                                               /*temp    freq*/
+                                               100     816000
+                                               >;
                                };
                        };
                };
index 282e25bdfbc05be21dd28eefc7e005c211def753..34d6a928cc5bdab5e5af115b0f58426c0672f455 100644 (file)
@@ -80,11 +80,15 @@ unsigned long rockchip_get_system_status(void);
 u32 pvtm_get_value(u32 ch, u32 time_us);
 
 #define INVALID_TEMP INT_MAX
+#if IS_ENABLED(CONFIG_ROCKCHIP_THERMAL)
+int rockchip_tsadc_get_temp(int chn, int voltage);
+#else
 #if IS_ENABLED(CONFIG_SENSORS_ROCKCHIP_TSADC)
 int rockchip_tsadc_get_temp(int chn);
 #else
 static inline int rockchip_tsadc_get_temp(int chn) { return INVALID_TEMP; }
 #endif
+#endif
 
 #ifdef CONFIG_RK_LAST_LOG
 void rk_last_log_text(char *text, size_t size);