mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-10 04:48:04 +09:00
Merge "thermal: add thermal driver support for m8b" into amlogic-4.9-dev
This commit is contained in:
@@ -244,6 +244,109 @@
|
||||
pinctrl-0=<&hdmi_cec_1>;
|
||||
reg = <0xc8100000 0x200>;
|
||||
};
|
||||
|
||||
aml_sensor0: aml-sensor@0 {
|
||||
compatible = "amlogic, aml-thermal";
|
||||
device_name = "thermal";
|
||||
#thermal-sensor-cells = <1>;
|
||||
cooling_devices {
|
||||
cpufreq_cool_cluster0 {
|
||||
min_state = <768000>;
|
||||
dyn_coeff = <110>;
|
||||
cluster_id = <0>;
|
||||
node_name = "cpufreq_cool0";
|
||||
device_type = "cpufreq";
|
||||
};
|
||||
cpucore_cool_cluster0 {
|
||||
min_state = <1>;
|
||||
dyn_coeff = <0>;
|
||||
cluster_id = <0>;
|
||||
node_name = "cpucore_cool0";
|
||||
device_type = "cpucore";
|
||||
};
|
||||
gpufreq_cool {
|
||||
min_state = <318>;
|
||||
dyn_coeff = <437>;
|
||||
cluster_id = <0>;
|
||||
node_name = "gpufreq_cool0";
|
||||
device_type = "gpufreq";
|
||||
};
|
||||
gpucore_cool {
|
||||
min_state = <1>;
|
||||
dyn_coeff = <0>;
|
||||
cluster_id = <0>;
|
||||
node_name = "gpucore_cool0";
|
||||
device_type = "gpucore";
|
||||
};
|
||||
};
|
||||
cpufreq_cool0:cpufreq_cool0 {
|
||||
#cooling-cells = <2>; /* min followed by max */
|
||||
};
|
||||
cpucore_cool0:cpucore_cool0 {
|
||||
#cooling-cells = <2>; /* min followed by max */
|
||||
};
|
||||
gpufreq_cool0:gpufreq_cool0 {
|
||||
#cooling-cells = <2>; /* min followed by max */
|
||||
};
|
||||
gpucore_cool0:gpucore_cool0 {
|
||||
#cooling-cells = <2>; /* min followed by max */
|
||||
};
|
||||
};
|
||||
thermal-zones {
|
||||
soc_thermal {
|
||||
polling-delay = <1000>;
|
||||
polling-delay-passive = <100>;
|
||||
sustainable-power = <1350>;
|
||||
|
||||
thermal-sensors = <&aml_sensor0 3>;
|
||||
|
||||
trips {
|
||||
switch_on: trip-point@0 {
|
||||
temperature = <70000>;
|
||||
hysteresis = <1000>;
|
||||
type = "passive";
|
||||
};
|
||||
control: trip-point@1 {
|
||||
temperature = <80000>;
|
||||
hysteresis = <1000>;
|
||||
type = "passive";
|
||||
};
|
||||
hot: trip-point@2 {
|
||||
temperature = <85000>;
|
||||
hysteresis = <5000>;
|
||||
type = "hot";
|
||||
};
|
||||
critical: trip-point@3 {
|
||||
temperature = <260000>;
|
||||
hysteresis = <1000>;
|
||||
type = "critical";
|
||||
};
|
||||
};
|
||||
|
||||
cooling-maps {
|
||||
cpufreq_cooling_map {
|
||||
trip = <&control>;
|
||||
cooling-device = <&cpufreq_cool0 0 4>;
|
||||
contribution = <1024>;
|
||||
};
|
||||
cpucore_cooling_map {
|
||||
trip = <&control>;
|
||||
cooling-device = <&cpucore_cool0 0 3>;
|
||||
contribution = <1024>;
|
||||
};
|
||||
gpufreq_cooling_map {
|
||||
trip = <&control>;
|
||||
cooling-device = <&gpufreq_cool0 0 4>;
|
||||
contribution = <1024>;
|
||||
};
|
||||
gpucore_cooling_map {
|
||||
trip = <&control>;
|
||||
cooling-device = <&gpucore_cool0 0 2>;
|
||||
contribution = <1024>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&uart_AO {
|
||||
|
||||
@@ -183,6 +183,169 @@
|
||||
*/
|
||||
};
|
||||
};
|
||||
cpufreq-meson{
|
||||
compatible = "amlogic, cpufreq-meson";
|
||||
status = "okay";
|
||||
fixpll_target = <1536000>;
|
||||
clocks = <&clkc CLKID_CPUCLK>,
|
||||
<&clkc CLKID_PLL_SYS>;
|
||||
clock-names = "cpu_clk", "sys_clk";
|
||||
opp_table = <
|
||||
/* frequent(Khz) uV */
|
||||
96000 860000
|
||||
312000 860000
|
||||
504000 860000
|
||||
600000 860000
|
||||
720000 860000
|
||||
816000 900000
|
||||
1008000 1140000
|
||||
1200000 1140000
|
||||
1320000 1140000
|
||||
1488000 1140000
|
||||
1536000 1140000
|
||||
>;
|
||||
};
|
||||
|
||||
dvfs {
|
||||
compatible = "amlogic, amlogic-dvfs";
|
||||
status = "okay";
|
||||
vcck_dvfs {
|
||||
dvfs_id = <1>;
|
||||
};
|
||||
};
|
||||
|
||||
pmu {
|
||||
compatible = "amlogic, aml_pmu_prober";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
status = "okay";
|
||||
aml1218 {
|
||||
compatible = "amlogic, amlogic_pmu";
|
||||
sub_type = "aml1218_pmu";
|
||||
i2c_bus = "i2c_bus_ao";
|
||||
slave_address = <0x35>;
|
||||
status = "okay";
|
||||
};
|
||||
};
|
||||
|
||||
aocec: aocec{
|
||||
compatible = "amlogic, amlogic-aocec";
|
||||
device_name = "aocec";
|
||||
status = "okay";
|
||||
vendor_id = <0x000000>;
|
||||
cec_osd_string = "MBox"; /* Max Chars: 14 */
|
||||
cec_version = <6>; /* 5: 1.4, 6: 2.0 */
|
||||
port_num = <1>;
|
||||
arc_port_mask = <0x0>;
|
||||
interrupts = <0 151 1>;
|
||||
interrupt-names = "hdmi_aocec";
|
||||
pinctrl-names = "hdmi_cec_1";
|
||||
pinctrl-0=<&hdmi_cec_1>;
|
||||
reg = <0xc8100000 0x200>;
|
||||
};
|
||||
|
||||
aml_sensor0: aml-sensor@0 {
|
||||
compatible = "amlogic, aml-thermal";
|
||||
device_name = "thermal";
|
||||
#thermal-sensor-cells = <1>;
|
||||
cooling_devices {
|
||||
cpufreq_cool_cluster0 {
|
||||
min_state = <768000>;
|
||||
dyn_coeff = <110>;
|
||||
cluster_id = <0>;
|
||||
node_name = "cpufreq_cool0";
|
||||
device_type = "cpufreq";
|
||||
};
|
||||
cpucore_cool_cluster0 {
|
||||
min_state = <1>;
|
||||
dyn_coeff = <0>;
|
||||
cluster_id = <0>;
|
||||
node_name = "cpucore_cool0";
|
||||
device_type = "cpucore";
|
||||
};
|
||||
gpufreq_cool {
|
||||
min_state = <318>;
|
||||
dyn_coeff = <437>;
|
||||
cluster_id = <0>;
|
||||
node_name = "gpufreq_cool0";
|
||||
device_type = "gpufreq";
|
||||
};
|
||||
gpucore_cool {
|
||||
min_state = <1>;
|
||||
dyn_coeff = <0>;
|
||||
cluster_id = <0>;
|
||||
node_name = "gpucore_cool0";
|
||||
device_type = "gpucore";
|
||||
};
|
||||
};
|
||||
cpufreq_cool0:cpufreq_cool0 {
|
||||
#cooling-cells = <2>; /* min followed by max */
|
||||
};
|
||||
cpucore_cool0:cpucore_cool0 {
|
||||
#cooling-cells = <2>; /* min followed by max */
|
||||
};
|
||||
gpufreq_cool0:gpufreq_cool0 {
|
||||
#cooling-cells = <2>; /* min followed by max */
|
||||
};
|
||||
gpucore_cool0:gpucore_cool0 {
|
||||
#cooling-cells = <2>; /* min followed by max */
|
||||
};
|
||||
};
|
||||
thermal-zones {
|
||||
soc_thermal {
|
||||
polling-delay = <1000>;
|
||||
polling-delay-passive = <100>;
|
||||
sustainable-power = <1350>;
|
||||
|
||||
thermal-sensors = <&aml_sensor0 3>;
|
||||
|
||||
trips {
|
||||
switch_on: trip-point@0 {
|
||||
temperature = <70000>;
|
||||
hysteresis = <1000>;
|
||||
type = "passive";
|
||||
};
|
||||
control: trip-point@1 {
|
||||
temperature = <80000>;
|
||||
hysteresis = <1000>;
|
||||
type = "passive";
|
||||
};
|
||||
hot: trip-point@2 {
|
||||
temperature = <85000>;
|
||||
hysteresis = <5000>;
|
||||
type = "hot";
|
||||
};
|
||||
critical: trip-point@3 {
|
||||
temperature = <260000>;
|
||||
hysteresis = <1000>;
|
||||
type = "critical";
|
||||
};
|
||||
};
|
||||
|
||||
cooling-maps {
|
||||
cpufreq_cooling_map {
|
||||
trip = <&control>;
|
||||
cooling-device = <&cpufreq_cool0 0 4>;
|
||||
contribution = <1024>;
|
||||
};
|
||||
cpucore_cooling_map {
|
||||
trip = <&control>;
|
||||
cooling-device = <&cpucore_cool0 0 3>;
|
||||
contribution = <1024>;
|
||||
};
|
||||
gpufreq_cooling_map {
|
||||
trip = <&control>;
|
||||
cooling-device = <&gpufreq_cool0 0 4>;
|
||||
contribution = <1024>;
|
||||
};
|
||||
gpucore_cooling_map {
|
||||
trip = <&control>;
|
||||
cooling-device = <&gpucore_cool0 0 2>;
|
||||
contribution = <1024>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&uart_AO {
|
||||
|
||||
@@ -60,15 +60,20 @@ CONFIG_AMLOGIC_CLK=y
|
||||
CONFIG_AMLOGIC_M8B_CLK=y
|
||||
CONFIG_AMLOGIC_CRYPTO=y
|
||||
CONFIG_AMLOGIC_CRYPTO_BLKMV=y
|
||||
CONFIG_AMLOGIC_INPUT=y
|
||||
CONFIG_AMLOGIC_SARADC=y
|
||||
CONFIG_AMLOGIC_EFUSE=y
|
||||
CONFIG_AMLOGIC_CPU_HOTPLUG=y
|
||||
CONFIG_AMLOGIC_PWM=y
|
||||
CONFIG_AMLOGIC_INPUT=y
|
||||
CONFIG_AMLOGIC_SARADC=y
|
||||
CONFIG_AMLOGIC_MMC=y
|
||||
CONFIG_AMLOGIC_M8B_MMC=y
|
||||
CONFIG_AMLOGIC_CEC=y
|
||||
CONFIG_AMLOGIC_M8B_CEC=y
|
||||
CONFIG_AMLOGIC_TEMP_SENSOR=y
|
||||
CONFIG_AMLOGIC_M8B_TEMP_SENSOR=y
|
||||
CONFIG_AMLOGIC_CPUCORE_THERMAL=y
|
||||
CONFIG_AMLOGIC_GPU_THERMAL=y
|
||||
CONFIG_AMLOGIC_GPUCORE_THERMAL=y
|
||||
CONFIG_AMLOGIC_POWER=y
|
||||
CONFIG_AMLOGIC_PMU_OF=y
|
||||
CONFIG_AMLOGIC_PMU=y
|
||||
@@ -100,6 +105,11 @@ CONFIG_POWER_RESET_GPIO=y
|
||||
CONFIG_POWER_RESET_GPIO_RESTART=y
|
||||
CONFIG_POWER_RESET_SYSCON=y
|
||||
CONFIG_POWER_SUPPLY=y
|
||||
CONFIG_THERMAL=y
|
||||
CONFIG_THERMAL_WRITABLE_TRIPS=y
|
||||
CONFIG_THERMAL_DEFAULT_GOV_POWER_ALLOCATOR=y
|
||||
CONFIG_THERMAL_GOV_STEP_WISE=y
|
||||
CONFIG_CPU_THERMAL=y
|
||||
CONFIG_WATCHDOG=y
|
||||
CONFIG_WATCHDOG_CORE=y
|
||||
CONFIG_BCMA=y
|
||||
|
||||
@@ -6,6 +6,7 @@ menu "Amlogic temperature sensor"
|
||||
|
||||
config AMLOGIC_TEMP_SENSOR
|
||||
bool "Amlgoic temperature sensor Support"
|
||||
depends on THERMAL
|
||||
default n
|
||||
---help---
|
||||
Thermal sensor low level support for thermal
|
||||
@@ -14,6 +15,24 @@ config AMLOGIC_TEMP_SENSOR
|
||||
|
||||
If you wan this driver, selest it.
|
||||
|
||||
config AMLOGIC_M8B_TEMP_SENSOR
|
||||
bool "Amlgoic temperature sensor Support for M8 chips"
|
||||
depends on AMLOGIC_TEMP_SENSOR
|
||||
depends on MACH_MESON8B
|
||||
default n
|
||||
help
|
||||
this config enables thermal driver for M8/M8baby chips.
|
||||
Say Y if you want this driver.
|
||||
|
||||
config AMLOGIC_GX_TEMP_SENSOR
|
||||
bool "Amlgoic temperature sensor Support for GX chips"
|
||||
depends on AMLOGIC_TEMP_SENSOR
|
||||
depends on ARM64
|
||||
default y
|
||||
help
|
||||
this config enables thermal driver for GX/GXB/GXL/GXM chips.
|
||||
Say Y if you want this driver.
|
||||
|
||||
config AMLOGIC_CPUCORE_THERMAL
|
||||
bool "generic cpu core cooling support"
|
||||
depends on AMLOGIC_TEMP_SENSOR
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
|
||||
obj-$(CONFIG_AMLOGIC_TEMP_SENSOR) += aml_thermal_hw.o
|
||||
obj-$(CONFIG_AMLOGIC_GX_TEMP_SENSOR) += aml_thermal_hw.o
|
||||
obj-$(CONFIG_AMLOGIC_M8B_TEMP_SENSOR) += aml_thermal_hw_m8b.o
|
||||
obj-$(CONFIG_AMLOGIC_CPUCORE_THERMAL) += cpucore_cooling.o
|
||||
obj-$(CONFIG_AMLOGIC_GPU_THERMAL) += gpu_cooling.o
|
||||
obj-$(CONFIG_AMLOGIC_GPUCORE_THERMAL) += gpucore_cooling.o
|
||||
|
||||
442
drivers/amlogic/thermal/aml_thermal_hw_m8b.c
Normal file
442
drivers/amlogic/thermal/aml_thermal_hw_m8b.c
Normal file
@@ -0,0 +1,442 @@
|
||||
/*
|
||||
* drivers/amlogic/thermal/aml_thermal_hw_m8b.c
|
||||
*
|
||||
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/amlogic/cpu_version.h>
|
||||
#include <linux/amlogic/scpi_protocol.h>
|
||||
#include <linux/printk.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/cpufreq.h>
|
||||
#include <linux/cpu_cooling.h>
|
||||
#include <linux/amlogic/cpucore_cooling.h>
|
||||
#include <linux/amlogic/gpucore_cooling.h>
|
||||
#include <linux/amlogic/gpu_cooling.h>
|
||||
#include <linux/amlogic/saradc.h>
|
||||
#include <linux/amlogic/efuse.h>
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/amlogic/aml_thermal_hw.h>
|
||||
|
||||
#define NOT_WRITE_EFUSE 0x0
|
||||
#define EFUEE_PRIVATE 0x4
|
||||
#define EFUSE_OPS 0xa
|
||||
|
||||
#define TEMP_ADC_CHANNEL 6
|
||||
#define TEMP_NOT_TRIMMED (-1000)
|
||||
#define TEMP_ADC_ERROR (-1001)
|
||||
|
||||
enum cluster_type {
|
||||
CLUSTER_BIG = 0,
|
||||
CLUSTER_LITTLE,
|
||||
NUM_CLUSTERS
|
||||
};
|
||||
|
||||
enum cool_dev_type {
|
||||
COOL_DEV_TYPE_CPU_FREQ = 0,
|
||||
COOL_DEV_TYPE_CPU_CORE,
|
||||
COOL_DEV_TYPE_GPU_FREQ,
|
||||
COOL_DEV_TYPE_GPU_CORE,
|
||||
COOL_DEV_TYPE_MAX
|
||||
};
|
||||
|
||||
struct cool_dev {
|
||||
int min_state;
|
||||
int coeff;
|
||||
int cluster_id;
|
||||
char *device_type;
|
||||
struct device_node *np;
|
||||
struct thermal_cooling_device *cooling_dev;
|
||||
};
|
||||
|
||||
struct aml_thermal_sensor {
|
||||
bool chip_trimmed : 1;
|
||||
bool adc_flag : 1;
|
||||
unsigned int fix_value : 12;
|
||||
unsigned int extra_flag : 4;
|
||||
unsigned int ts_c : 5;
|
||||
unsigned int cool_dev_num : 9;
|
||||
struct cpumask mask[NUM_CLUSTERS];
|
||||
struct cool_dev *cool_devs;
|
||||
struct thermal_zone_device *tzd;
|
||||
};
|
||||
|
||||
static struct aml_thermal_sensor soc_sensor;
|
||||
|
||||
int thermal_firmware_init(void)
|
||||
{
|
||||
int err = 0;
|
||||
unsigned char buf[4] = {0};
|
||||
int temp;
|
||||
|
||||
err = efuse_read_intlItem("temper_cvbs", buf, 4);
|
||||
if (err >= 0) {
|
||||
pr_info("efuse buf:%02x %02x %02x %02x, err=%d\n",
|
||||
buf[0], buf[1], buf[2], buf[3], err);
|
||||
temp = (buf[1] << 8) | buf[0];
|
||||
soc_sensor.ts_c = temp & 0x1F;
|
||||
soc_sensor.adc_flag = (temp & 0x8000) >> 15;
|
||||
soc_sensor.fix_value = (temp & 0x7fff) >> 5;
|
||||
soc_sensor.extra_flag = (buf[3] >> 4) & 0xf;
|
||||
pr_info("adc:%d, ts_c:%d, flag:%d, ext_flag:%x\n",
|
||||
soc_sensor.fix_value, soc_sensor.ts_c,
|
||||
soc_sensor.adc_flag, soc_sensor.extra_flag);
|
||||
if ((soc_sensor.extra_flag == EFUEE_PRIVATE) ||
|
||||
(soc_sensor.extra_flag == EFUSE_OPS)) {
|
||||
if (soc_sensor.adc_flag)
|
||||
soc_sensor.chip_trimmed = 1;
|
||||
} else
|
||||
soc_sensor.chip_trimmed = 0;
|
||||
}
|
||||
if (soc_sensor.chip_trimmed) {
|
||||
temp_sensor_adc_init(soc_sensor.ts_c);
|
||||
return 0;
|
||||
} else
|
||||
return -1;
|
||||
|
||||
}
|
||||
EXPORT_SYMBOL(thermal_firmware_init);
|
||||
|
||||
int get_cpu_temp(void)
|
||||
{
|
||||
int ret = TEMP_NOT_TRIMMED, tempa;
|
||||
|
||||
if (soc_sensor.chip_trimmed) {
|
||||
ret = get_adc_sample(0, TEMP_ADC_CHANNEL);
|
||||
if (ret >= 0) {
|
||||
tempa = (10 * (ret - soc_sensor.fix_value)) / 32 + 27;
|
||||
ret = tempa;
|
||||
} else
|
||||
ret = TEMP_ADC_ERROR;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(get_cpu_temp);
|
||||
|
||||
static int get_cur_temp(void *data, int *temp)
|
||||
{
|
||||
int val;
|
||||
|
||||
val = get_cpu_temp();
|
||||
if (val == -1000)
|
||||
return -EINVAL;
|
||||
|
||||
*temp = val * 1000;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_cool_dev_type(char *type)
|
||||
{
|
||||
if (!strcmp(type, "cpufreq"))
|
||||
return COOL_DEV_TYPE_CPU_FREQ;
|
||||
if (!strcmp(type, "cpucore"))
|
||||
return COOL_DEV_TYPE_CPU_CORE;
|
||||
if (!strcmp(type, "gpufreq"))
|
||||
return COOL_DEV_TYPE_GPU_FREQ;
|
||||
if (!strcmp(type, "gpucore"))
|
||||
return COOL_DEV_TYPE_GPU_CORE;
|
||||
return COOL_DEV_TYPE_MAX;
|
||||
}
|
||||
|
||||
static struct cool_dev *get_cool_dev_by_node(struct device_node *np)
|
||||
{
|
||||
int i;
|
||||
struct cool_dev *dev;
|
||||
|
||||
if (!np)
|
||||
return NULL;
|
||||
for (i = 0; i < soc_sensor.cool_dev_num; i++) {
|
||||
dev = &soc_sensor.cool_devs[i];
|
||||
if (dev->np == np)
|
||||
return dev;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int aml_thermal_min_update(struct thermal_cooling_device *cdev)
|
||||
{
|
||||
struct gpufreq_cooling_device *gf_cdev;
|
||||
struct gpucore_cooling_device *gc_cdev;
|
||||
struct cool_dev *cool;
|
||||
long min_state;
|
||||
int i;
|
||||
int cpu, c_id;
|
||||
|
||||
cool = get_cool_dev_by_node(cdev->np);
|
||||
if (!cool)
|
||||
return -ENODEV;
|
||||
|
||||
if (cool->cooling_dev == NULL)
|
||||
cool->cooling_dev = cdev;
|
||||
|
||||
if (cool->min_state == 0)
|
||||
return 0;
|
||||
|
||||
switch (get_cool_dev_type(cool->device_type)) {
|
||||
case COOL_DEV_TYPE_CPU_CORE:
|
||||
/* TODO: cluster ID */
|
||||
cool->cooling_dev->ops->get_max_state(cdev, &min_state);
|
||||
min_state = min_state - cool->min_state;
|
||||
break;
|
||||
|
||||
case COOL_DEV_TYPE_CPU_FREQ:
|
||||
for_each_possible_cpu(cpu) {
|
||||
if (mc_capable())
|
||||
c_id = topology_physical_package_id(cpu);
|
||||
else
|
||||
c_id = 0; /* force cluster 0 if no MC */
|
||||
if (c_id == cool->cluster_id)
|
||||
break;
|
||||
}
|
||||
min_state = cpufreq_cooling_get_level(cpu, cool->min_state);
|
||||
break;
|
||||
|
||||
case COOL_DEV_TYPE_GPU_CORE:
|
||||
gc_cdev = (struct gpucore_cooling_device *)cdev->devdata;
|
||||
cdev->ops->get_max_state(cdev, &min_state);
|
||||
min_state = min_state - cool->min_state;
|
||||
break;
|
||||
|
||||
case COOL_DEV_TYPE_GPU_FREQ:
|
||||
gf_cdev = (struct gpufreq_cooling_device *)cdev->devdata;
|
||||
min_state = gf_cdev->get_gpu_freq_level(cool->min_state);
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < soc_sensor.tzd->trips; i++)
|
||||
thermal_set_upper(soc_sensor.tzd, cdev, i, min_state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(aml_thermal_min_update);
|
||||
|
||||
int set_cur_mode(struct thermal_zone_device *tzd, enum thermal_device_mode mode)
|
||||
{
|
||||
int i, ret = 0;
|
||||
struct thermal_cooling_device *cdev;
|
||||
|
||||
/*
|
||||
* each cooling device should return to max state if thermal is disalbed
|
||||
*/
|
||||
if (mode != THERMAL_DEVICE_DISABLED)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < soc_sensor.cool_dev_num; i++) {
|
||||
cdev = soc_sensor.cool_devs[i].cooling_dev;
|
||||
if (cdev)
|
||||
ret |= cdev->ops->set_cur_state(cdev, 0);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct thermal_zone_of_device_ops aml_thermal_ops = {
|
||||
.get_temp = get_cur_temp,
|
||||
.set_mode = set_cur_mode,
|
||||
};
|
||||
|
||||
static int register_cool_dev(struct cool_dev *cool)
|
||||
{
|
||||
int pp;
|
||||
int id = cool->cluster_id;
|
||||
struct cpumask *mask;
|
||||
|
||||
switch (get_cool_dev_type(cool->device_type)) {
|
||||
case COOL_DEV_TYPE_CPU_CORE:
|
||||
cool->cooling_dev = cpucore_cooling_register(cool->np,
|
||||
cool->cluster_id);
|
||||
break;
|
||||
|
||||
case COOL_DEV_TYPE_CPU_FREQ:
|
||||
mask = &soc_sensor.mask[id];
|
||||
cool->cooling_dev = of_cpufreq_power_cooling_register(cool->np,
|
||||
mask,
|
||||
cool->coeff,
|
||||
NULL);
|
||||
break;
|
||||
|
||||
/* GPU is KO, just save these parameters */
|
||||
case COOL_DEV_TYPE_GPU_FREQ:
|
||||
if (of_property_read_u32(cool->np, "num_of_pp", &pp))
|
||||
pr_err("thermal: read num_of_pp failed\n");
|
||||
save_gpu_cool_para(cool->coeff, cool->np, pp);
|
||||
return 0;
|
||||
|
||||
case COOL_DEV_TYPE_GPU_CORE:
|
||||
save_gpucore_thermal_para(cool->np);
|
||||
return 0;
|
||||
|
||||
default:
|
||||
pr_err("thermal: unknown type:%s\n", cool->device_type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (IS_ERR(cool->cooling_dev)) {
|
||||
pr_err("thermal: register %s failed\n", cool->device_type);
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_cool_device(struct device_node *np)
|
||||
{
|
||||
int i, temp, ret = 0;
|
||||
struct cool_dev *cool;
|
||||
struct device_node *node, *child;
|
||||
const char *str;
|
||||
|
||||
child = of_get_next_child(np, NULL);
|
||||
for (i = 0; i < soc_sensor.cool_dev_num; i++) {
|
||||
cool = &soc_sensor.cool_devs[i];
|
||||
if (child == NULL)
|
||||
break;
|
||||
if (of_property_read_u32(child, "min_state", &temp))
|
||||
pr_err("thermal: read min_state failed\n");
|
||||
else
|
||||
cool->min_state = temp;
|
||||
|
||||
if (of_property_read_u32(child, "dyn_coeff", &temp))
|
||||
pr_err("thermal: read dyn_coeff failed\n");
|
||||
else
|
||||
cool->coeff = temp;
|
||||
|
||||
if (of_property_read_u32(child, "cluster_id", &temp))
|
||||
pr_err("thermal: read cluster_id failed\n");
|
||||
else
|
||||
cool->cluster_id = temp;
|
||||
|
||||
if (of_property_read_string(child, "device_type", &str))
|
||||
pr_err("thermal: read device_type failed\n");
|
||||
else
|
||||
cool->device_type = (char *)str;
|
||||
|
||||
if (of_property_read_string(child, "node_name", &str))
|
||||
pr_err("thermal: read node_name failed\n");
|
||||
else {
|
||||
node = of_find_node_by_name(NULL, str);
|
||||
if (!node)
|
||||
pr_err("thermal: can't find node\n");
|
||||
cool->np = node;
|
||||
}
|
||||
if (cool->np)
|
||||
ret += register_cool_dev(cool);
|
||||
child = of_get_next_child(np, child);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int aml_thermal_probe(struct platform_device *pdev)
|
||||
{
|
||||
int cpu, i, c_id;
|
||||
struct device_node *np, *child;
|
||||
struct cool_dev *cool;
|
||||
struct cpufreq_policy *policy;
|
||||
|
||||
memset(&soc_sensor, 0, sizeof(struct aml_thermal_sensor));
|
||||
policy = cpufreq_cpu_get(0);
|
||||
if (!policy || !policy->freq_table) {
|
||||
dev_info(&pdev->dev,
|
||||
"Frequency policy not init. Deferring probe...\n");
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
|
||||
if (thermal_firmware_init() < 0) {
|
||||
dev_err(&pdev->dev, "chip is not trimmed, disable thermal\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for_each_possible_cpu(cpu) {
|
||||
if (mc_capable())
|
||||
c_id = topology_physical_package_id(cpu);
|
||||
else
|
||||
c_id = CLUSTER_BIG; /* Always cluster 0 if no mc */
|
||||
if (c_id > NUM_CLUSTERS) {
|
||||
pr_err("Cluster id: %d > %d\n", c_id, NUM_CLUSTERS);
|
||||
return -EINVAL;
|
||||
}
|
||||
cpumask_set_cpu(cpu, &soc_sensor.mask[c_id]);
|
||||
}
|
||||
|
||||
np = pdev->dev.of_node;
|
||||
child = of_get_child_by_name(np, "cooling_devices");
|
||||
if (child == NULL) {
|
||||
pr_err("thermal: can't found cooling_devices\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
soc_sensor.cool_dev_num = of_get_child_count(child);
|
||||
i = sizeof(struct cool_dev) * soc_sensor.cool_dev_num;
|
||||
soc_sensor.cool_devs = kzalloc(i, GFP_KERNEL);
|
||||
if (soc_sensor.cool_devs == NULL) {
|
||||
pr_err("thermal: alloc mem failed\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (parse_cool_device(child))
|
||||
return -EINVAL;
|
||||
|
||||
soc_sensor.tzd = thermal_zone_of_sensor_register(&pdev->dev,
|
||||
3,
|
||||
&soc_sensor,
|
||||
&aml_thermal_ops);
|
||||
|
||||
if (IS_ERR(soc_sensor.tzd)) {
|
||||
dev_warn(&pdev->dev, "Error registering sensor: %p\n",
|
||||
soc_sensor.tzd);
|
||||
return PTR_ERR(soc_sensor.tzd);
|
||||
}
|
||||
|
||||
/* update min state for each device */
|
||||
for (i = 0; i < soc_sensor.cool_dev_num; i++) {
|
||||
cool = &soc_sensor.cool_devs[i];
|
||||
if (cool->cooling_dev)
|
||||
aml_thermal_min_update(cool->cooling_dev);
|
||||
}
|
||||
thermal_zone_device_update(soc_sensor.tzd, THERMAL_EVENT_UNSPECIFIED);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int aml_thermal_remove(struct platform_device *pdev)
|
||||
{
|
||||
kfree(soc_sensor.cool_devs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id aml_thermal_of_match[] = {
|
||||
{ .compatible = "amlogic, aml-thermal" },
|
||||
{},
|
||||
};
|
||||
|
||||
static struct platform_driver aml_thermal_platdrv = {
|
||||
.driver = {
|
||||
.name = "aml-thermal",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = aml_thermal_of_match,
|
||||
},
|
||||
.probe = aml_thermal_probe,
|
||||
.remove = aml_thermal_remove,
|
||||
};
|
||||
|
||||
|
||||
static int __init aml_thermal_platdrv_init(void)
|
||||
{
|
||||
return platform_driver_register(&(aml_thermal_platdrv));
|
||||
}
|
||||
late_initcall(aml_thermal_platdrv_init);
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <linux/amlogic/cpucore_cooling.h>
|
||||
#include <linux/amlogic/cpu_hotplug.h>
|
||||
#include <linux/cpumask.h>
|
||||
#include <linux/amlogic/aml_thermal_hw.h>
|
||||
|
||||
/**
|
||||
* struct cpucore_cooling_device - data for cooling device with cpucore
|
||||
|
||||
@@ -17,6 +17,11 @@
|
||||
|
||||
#ifndef ARCH__THERMAL_H__
|
||||
#define ARCH__THERMAL_H__
|
||||
|
||||
#ifndef mc_capable
|
||||
#define mc_capable() 0
|
||||
#endif
|
||||
|
||||
struct thermal_cooling_device;
|
||||
extern int thermal_firmware_init(void);
|
||||
extern int get_cpu_temp(void);
|
||||
|
||||
Reference in New Issue
Block a user