[COMMON] thermal: samsung: Parse ECT data for throttling
authorSoomin Kim <sm8326.kim@samsung.com>
Tue, 19 Jul 2016 00:41:58 +0000 (09:41 +0900)
committerChungwoo Park <cww.park@samsung.com>
Mon, 21 May 2018 08:13:10 +0000 (17:13 +0900)
Throttling temperature and frequency data are parsed
from ECT. These data are swapped after binding thermal
sensor and thermal zone because exynos_tmu_data can't be
referenced before that time.

Change-Id: I19f52dd509e859574142a31f3f896368de03cb19
Signed-off-by: Soomin Kim <sm8326.kim@samsung.com>
drivers/thermal/of-thermal.c
drivers/thermal/samsung/exynos_tmu.c
drivers/thermal/samsung/exynos_tmu.h

index 7ba2769757f9ae3d3f9815ba211d234896516fcf..7dc6b768bc527d0bec4ca9ff39e3b8921b90188c 100644 (file)
 
 #include "thermal_core.h"
 
+#if defined(CONFIG_ECT)
+#include <soc/samsung/ect_parser.h>
+#include "samsung/exynos_tmu.h"
+#endif
+
 /***   Private data structures to represent thermal device tree data ***/
 
 /**
@@ -500,6 +505,18 @@ thermal_zone_of_sensor_register(struct device *dev, int sensor_id, void *data,
        struct device_node *np, *child, *sensor_np;
        struct thermal_zone_device *tzd = ERR_PTR(-ENODEV);
 
+#if defined(CONFIG_ECT)
+       struct thermal_instance *instance;
+       struct __thermal_zone *__tz;
+       void *thermal_block;
+       struct ect_ap_thermal_function *function;
+       int i = 0, j = 0;
+       struct exynos_tmu_data *tmu_data;
+       int hotplug_threshold_temp = 0, hotplug_flag = 0;
+       unsigned int level, freq;
+       int temperature;
+#endif
+
        np = of_find_node_by_name(NULL, "thermal-zones");
        if (!np)
                return ERR_PTR(-ENODEV);
@@ -534,6 +551,86 @@ thermal_zone_of_sensor_register(struct device *dev, int sensor_id, void *data,
                if (sensor_specs.np == sensor_np && id == sensor_id) {
                        tzd = thermal_zone_of_add_sensor(child, sensor_np,
                                                         data, ops);
+#if defined(CONFIG_ECT)
+                       __tz = tzd->devdata;
+                       tmu_data = (struct exynos_tmu_data *)data;
+
+                       thermal_block = ect_get_block(BLOCK_AP_THERMAL);
+                       if (thermal_block == NULL) {
+                               dev_err(dev, "Failed to get thermal block");
+                               return ERR_PTR(-EINVAL);
+                       }
+
+                       pr_info("%s %d thermal zone_name = %s \n", __func__, __LINE__, tzd->type);
+                       function = ect_ap_thermal_get_function(thermal_block, tzd->type);
+                       if (function == NULL) {
+                               dev_err(dev, "Failed to get thermal block %s", tzd->type);
+                               return ERR_PTR(-EINVAL);
+                       }
+
+                       __tz->ntrips = __tz->num_tbps = function->num_of_range;
+                       dev_info(dev, "Trip count parsed from ECT : %d, zone : %s", function->num_of_range, tzd->type);
+
+                       instance = list_first_entry(&tzd->thermal_instances, typeof(*instance), tz_node);
+
+                       for (i = 0; i < function->num_of_range; ++i) {
+                               temperature = function->range_list[i].lower_bound_temperature;
+                               freq = function->range_list[i].max_frequency;
+
+                               for (j = 0; j < ARRAY_SIZE(tz_zone_names); j++)
+                                       if (!strcasecmp(tzd->type, tz_zone_names[j])) {
+                                               switch (j) {
+                                                       case MNGS_QUAD :
+                                                               level = cpufreq_cooling_get_level(4, freq);
+                                                               break;
+                                                       case APOLLO :
+                                                               level = cpufreq_cooling_get_level(0, freq);
+                                                               break;
+                                                       case GPU :
+                                                               level = gpufreq_cooling_get_level(0, freq);
+                                                               break;
+                                                       case ISP :
+                                                               level = isp_cooling_get_fps(0, freq);
+                                                               break;
+                                                       case MNGS_DUAL :
+                                                               level = cpufreq_cooling_get_level(4, freq);
+                                                               break;
+                                               }
+                                       }
+
+                               if (level > 100) {
+                                       dev_err(dev, "Level is strange!!! freq = %u, level = %u\n", freq, level);
+                                       level = 0;
+                               }
+
+                               /* Change 'trips' and 'tbps' data with ECT data instead of DT data */
+                               __tz->trips[i].temperature = temperature  * MCELSIUS;
+                               __tz->tbps[i].max = level;
+
+                               /* Change thermal instance information with tbps data */
+                               instance->upper = __tz->tbps[i].max;
+                               instance = list_next_entry(instance, tz_node);
+                               pr_info("Parsed From ECT : [%d] Temperature : %d, frequency : %u, level = %lu\n", i, temperature, freq, __tz->tbps[i].max);
+
+                               if (function->range_list[i].flag != hotplug_flag) {
+                                       hotplug_threshold_temp = temperature;
+                                       hotplug_flag = function->range_list[i].flag;
+                                       tmu_data->hotplug_out_threshold = temperature;
+
+                                       if (i)
+                                               tmu_data->hotplug_in_threshold = function->range_list[i-1].lower_bound_temperature;
+
+                                       pr_info("[ECT]hotplug_threshold : %d \n", hotplug_threshold_temp);
+                                       pr_info("[ECT]hotplug_in_threshold : %d \n", tmu_data->hotplug_in_threshold);
+                                       pr_info("[ECT]hotplug_out_threshold : %d \n", tmu_data->hotplug_out_threshold);
+                               }
+                       }
+
+                       if (hotplug_threshold_temp != 0)
+                               tmu_data->hotplug_enable = true;
+                       else
+                               tmu_data->hotplug_enable = false;
+#endif
 
                        of_node_put(sensor_specs.np);
                        of_node_put(child);
index 011ef77e30ecdaa355dbd97518bae78c02d45447..c9faf776cc645780dd6f83fe3aed6c1c2730a8ac 100644 (file)
 #define EXYNOS_TMU_DEM_ENABLE                  (1)
 #define EXYNOS_TMU_DEM_SHIFT                   (4)
 
-#define MCELSIUS       1000
-
 #define TOTAL_SENSORS  8
 
 static bool suspended;
@@ -135,66 +133,6 @@ static DEFINE_MUTEX (thermal_suspend_lock);
 static LIST_HEAD(dtm_dev_list);
 struct cpufreq_frequency_table gpu_freq_table[10];
 
-struct sensor_info {
-       u8 sensor_num;
-       u16 cal_type;
-       u32 temp_error1;
-       u32 temp_error2;
-};
-
-/**
- * struct exynos_tmu_data : A structure to hold the private data of the TMU
-       driver
- * @id: identifier of the one instance of the TMU controller.
- * @pdata: pointer to the tmu platform/configuration data
- * @base: base address of the single instance of the TMU controller.
- * @base_second: base address of the common registers of the TMU controller.
- * @irq: irq number of the TMU controller.
- * @soc: id of the SOC type.
- * @irq_work: pointer to the irq work structure.
- * @lock: lock to implement synchronization.
- * @temp_error1: fused value of the first point trim.
- * @temp_error2: fused value of the second point trim.
- * @regulator: pointer to the TMU regulator structure.
- * @reg_conf: pointer to structure to register with core thermal.
- * @ntrip: number of supported trip points.
- * @tmu_initialize: SoC specific TMU initialization method
- * @tmu_control: SoC specific TMU control method
- * @tmu_read: SoC specific TMU temperature read method
- * @tmu_set_emulation: SoC specific TMU emulation setting method
- * @tmu_clear_irqs: SoC specific TMU interrupts clearing method
- */
-struct exynos_tmu_data {
-       int id;
-       /* Throttle hotplug related variables */
-       bool hotplug_enable;
-       int hotplug_in_threshold;
-       int hotplug_out_threshold;
-       struct exynos_tmu_platform_data *pdata;
-       void __iomem *base;
-       int irq;
-       enum soc_type soc;
-       struct work_struct irq_work;
-       struct mutex lock;
-       u16 temp_error1, temp_error2;
-       struct thermal_zone_device *tzd;
-       unsigned int ntrip;
-       struct thermal_cooling_device *cool_dev;
-       struct list_head node;
-       u32 sensors;
-       int num_of_sensors;
-       struct sensor_info *sensor_info;
-       int sensing_mode;
-       char tmu_name[THERMAL_NAME_LENGTH];
-       struct device_node *np;
-
-       int (*tmu_initialize)(struct platform_device *pdev);
-       void (*tmu_control)(struct platform_device *pdev, bool on);
-       int (*tmu_read)(struct exynos_tmu_data *data);
-       void (*tmu_set_emulation)(struct exynos_tmu_data *data, int temp);
-       void (*tmu_clear_irqs)(struct exynos_tmu_data *data);
-};
-
 static int find_sensor(struct exynos_tmu_data *data, int start)
 {
        int i;
index 889934b09ab2d159072d29ab0b208653551e91c3..c6d378c4d76ceeab74593c30cd8a452af9beea57 100644 (file)
 #ifndef _EXYNOS_TMU_H
 #define _EXYNOS_TMU_H
 #include <linux/cpu_cooling.h>
+#include <linux/gpu_cooling.h>
+#include <linux/isp_cooling.h>
 #include <dt-bindings/thermal/thermal_exynos.h>
 
 #define NR_HOTPLUG_CPUS        4
+#define MCELSIUS        1000
 
 enum soc_type {
        SOC_ARCH_EXYNOS8890 = 1,
@@ -75,4 +78,83 @@ static const char * const sensing_method[] = {
        [MIN] = "min",
 };
 
+enum thermal_zone_name {
+       MNGS_QUAD = 0,
+       APOLLO,
+       GPU,
+       ISP,
+       MNGS_DUAL,
+       END_ZONE_NAME,
+};
+
+/**
+ * It maps 'enum znoe_name' defined in above and is used to define zone name.
+ */
+static const char * const tz_zone_names[] = {
+       [MNGS_QUAD]= "MNGS_QUAD",
+       [APOLLO] = "APOLLO",
+       [GPU] = "GPU",
+       [ISP] = "ISP",
+       [MNGS_DUAL]= "MNGS_DUAL",
+};
+
+struct sensor_info {
+       u16 sensor_num;
+       u16 cal_type;
+       u32 temp_error1;
+       u32 temp_error2;
+};
+
+/**
+ * struct exynos_tmu_data : A structure to hold the private data of the TMU
+       driver
+ * @id: identifier of the one instance of the TMU controller.
+ * @pdata: pointer to the tmu platform/configuration data
+ * @base: base address of the single instance of the TMU controller.
+ * @base_second: base address of the common registers of the TMU controller.
+ * @irq: irq number of the TMU controller.
+ * @soc: id of the SOC type.
+ * @irq_work: pointer to the irq work structure.
+ * @lock: lock to implement synchronization.
+ * @temp_error1: fused value of the first point trim.
+ * @temp_error2: fused value of the second point trim.
+ * @regulator: pointer to the TMU regulator structure.
+ * @reg_conf: pointer to structure to register with core thermal.
+ * @ntrip: number of supported trip points.
+ * @tmu_initialize: SoC specific TMU initialization method
+ * @tmu_control: SoC specific TMU control method
+ * @tmu_read: SoC specific TMU temperature read method
+ * @tmu_set_emulation: SoC specific TMU emulation setting method
+ * @tmu_clear_irqs: SoC specific TMU interrupts clearing method
+ */
+struct exynos_tmu_data {
+       int id;
+       /* Throttle hotplug related variables */
+       bool hotplug_enable;
+       int hotplug_in_threshold;
+       int hotplug_out_threshold;
+       struct exynos_tmu_platform_data *pdata;
+       void __iomem *base;
+       int irq;
+       enum soc_type soc;
+       struct work_struct irq_work;
+       struct mutex lock;
+       u16 temp_error1, temp_error2;
+       struct thermal_zone_device *tzd;
+       unsigned int ntrip;
+       struct thermal_cooling_device *cool_dev;
+       struct list_head node;
+       u32 sensors;
+       int num_of_sensors;
+       struct sensor_info *sensor_info;
+       int sensing_mode;
+       char tmu_name[THERMAL_NAME_LENGTH];
+       struct device_node *np;
+
+       int (*tmu_initialize)(struct platform_device *pdev);
+       void (*tmu_control)(struct platform_device *pdev, bool on);
+       int (*tmu_read)(struct exynos_tmu_data *data);
+       void (*tmu_set_emulation)(struct exynos_tmu_data *data, int temp);
+       void (*tmu_clear_irqs)(struct exynos_tmu_data *data);
+};
 #endif /* _EXYNOS_TMU_H */