From: Soomin Kim Date: Tue, 19 Jul 2016 00:41:58 +0000 (+0900) Subject: [COMMON] thermal: samsung: Parse ECT data for throttling X-Git-Url: https://git.stricted.de/?a=commitdiff_plain;h=2cb9d489be99c6dc758d448563832a99b207933f;p=GitHub%2FLineageOS%2Fandroid_kernel_motorola_exynos9610.git [COMMON] thermal: samsung: Parse ECT data for throttling 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 --- diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c index 7ba2769757f9..7dc6b768bc52 100644 --- a/drivers/thermal/of-thermal.c +++ b/drivers/thermal/of-thermal.c @@ -34,6 +34,11 @@ #include "thermal_core.h" +#if defined(CONFIG_ECT) +#include +#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); diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c index 011ef77e30ec..c9faf776cc64 100644 --- a/drivers/thermal/samsung/exynos_tmu.c +++ b/drivers/thermal/samsung/exynos_tmu.c @@ -123,8 +123,6 @@ #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; diff --git a/drivers/thermal/samsung/exynos_tmu.h b/drivers/thermal/samsung/exynos_tmu.h index 889934b09ab2..c6d378c4d76c 100644 --- a/drivers/thermal/samsung/exynos_tmu.h +++ b/drivers/thermal/samsung/exynos_tmu.h @@ -23,9 +23,12 @@ #ifndef _EXYNOS_TMU_H #define _EXYNOS_TMU_H #include +#include +#include #include #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 */