mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-08 03:40:35 +09:00
thermal: initial add thermal driver
PD#138714: initial add thermal driver 1. Add amlogic thermal sensor driver 2. add cpu/gpu core cooling methord and gpu freq cooling devices; 3. device tree support of thermal for p212/q200 4. related dtsi/Makefiles/Kconfig/Headfiles update Change-Id: I555fbb1e36a3cdc3187d92bdf5da6a720f2377d0 Signed-off-by: Tao Zeng <tao.zeng@amlogic.com>
This commit is contained in:
10
Documentation/devicetree/bindings/arm/arm_gpu.txt
Normal file
10
Documentation/devicetree/bindings/arm/arm_gpu.txt
Normal file
@@ -0,0 +1,10 @@
|
||||
ARM Mali GPU device tree bindings
|
||||
------------------------------------
|
||||
|
||||
Boards with Mali-450 GPU shall have the following properties:
|
||||
Required root node property:
|
||||
compatible: "arm,mali-450"
|
||||
|
||||
Boards with Mali-t82x GPU shall have the following properties:
|
||||
Required root node property:
|
||||
compatible: "arm,malit602", "arm,malit60x", "arm,malit6xx", "arm,mali-midgard"
|
||||
@@ -13464,6 +13464,10 @@ AMLOGIC reboot
|
||||
M: Jianxin Pan <jianxin.pan@amlogic.com>
|
||||
F: drivers/amlogic/reboot/*
|
||||
|
||||
AMLOGIC driver for thermal
|
||||
M: Tao Zeng <tao.zeng@amlogic.com>
|
||||
F: drivers/amlogic/thermal/*
|
||||
|
||||
HDMITX OUTPUT DRIVER
|
||||
M: Zongdong Jiao <zongdong.jiao@amlogic.com>
|
||||
S: Maintained
|
||||
|
||||
@@ -302,6 +302,109 @@
|
||||
internal_phy=<1>;
|
||||
};
|
||||
|
||||
aml_sensor0: aml-sensor@0 {
|
||||
compatible = "amlogic, aml-thermal";
|
||||
device_name = "thermal";
|
||||
#thermal-sensor-cells = <1>;
|
||||
cooling_devices {
|
||||
cpufreq_cool_cluster0 {
|
||||
min_state = <1000000>;
|
||||
dyn_coeff = <140>;
|
||||
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 = <400>;
|
||||
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 = <2150>;
|
||||
|
||||
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>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
dwc3: dwc3@c9000000 {
|
||||
compatible = "synopsys, dwc3";
|
||||
reg = <0x0 0xc9000000 0x0 0x100000>;
|
||||
|
||||
@@ -377,6 +377,108 @@
|
||||
"mailbox_2";
|
||||
};
|
||||
|
||||
aml_sensor0: aml-sensor@0 {
|
||||
compatible = "amlogic, aml-thermal";
|
||||
device_name = "thermal";
|
||||
#thermal-sensor-cells = <1>;
|
||||
cooling_devices {
|
||||
cpufreq_cool_cluster0 {
|
||||
min_state = <1000000>;
|
||||
dyn_coeff = <140>;
|
||||
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 = <400>;
|
||||
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 = <2150>;
|
||||
|
||||
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>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
dwc3: dwc3@c9000000 {
|
||||
compatible = "synopsys, dwc3";
|
||||
|
||||
@@ -379,6 +379,139 @@
|
||||
"mailbox_2";
|
||||
};
|
||||
|
||||
aml_sensor0: aml-sensor@0 {
|
||||
compatible = "amlogic, aml-thermal";
|
||||
device_name = "thermal";
|
||||
#thermal-sensor-cells = <1>;
|
||||
cooling_devices {
|
||||
cpufreq_cool_cluster0 {
|
||||
min_state = <1000000>;
|
||||
dyn_coeff = <140>;
|
||||
cluster_id = <0>;
|
||||
node_name = "cpufreq_cool0";
|
||||
device_type = "cpufreq";
|
||||
};
|
||||
cpufreq_cool_cluster1 {
|
||||
min_state = <500000>;
|
||||
dyn_coeff = <140>;
|
||||
cluster_id = <1>;
|
||||
node_name = "cpufreq_cool1";
|
||||
device_type = "cpufreq";
|
||||
};
|
||||
cpucore_cool_cluster0 {
|
||||
min_state = <1>;
|
||||
dyn_coeff = <0>;
|
||||
cluster_id = <0>;
|
||||
node_name = "cpucore_cool0";
|
||||
device_type = "cpucore";
|
||||
};
|
||||
cpucore_cool_cluster1 {
|
||||
min_state = <1>;
|
||||
dyn_coeff = <0>;
|
||||
cluster_id = <1>;
|
||||
node_name = "cpucore_cool1";
|
||||
device_type = "cpucore";
|
||||
};
|
||||
gpufreq_cool {
|
||||
min_state = <400>;
|
||||
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 */
|
||||
};
|
||||
cpufreq_cool1:cpufreq_cool1 {
|
||||
#cooling-cells = <2>; /* min followed by max */
|
||||
};
|
||||
cpucore_cool0:cpucore_cool0 {
|
||||
#cooling-cells = <2>; /* min followed by max */
|
||||
};
|
||||
cpucore_cool1:cpucore_cool1 {
|
||||
#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 = <2450>;
|
||||
|
||||
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_map0 {
|
||||
trip = <&control>;
|
||||
cooling-device = <&cpufreq_cool0 0 4>;
|
||||
contribution = <1024>;
|
||||
};
|
||||
cpufreq_cooling_map1 {
|
||||
trip = <&control>;
|
||||
cooling-device = <&cpufreq_cool1 0 4>;
|
||||
contribution = <1024>;
|
||||
};
|
||||
cpucore_cooling_map0 {
|
||||
trip = <&control>;
|
||||
cooling-device = <&cpucore_cool0 0 3>;
|
||||
contribution = <1024>;
|
||||
};
|
||||
cpucore_cooling_map1 {
|
||||
trip = <&control>;
|
||||
cooling-device = <&cpucore_cool1 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>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
dwc3: dwc3@c9000000 {
|
||||
compatible = "synopsys, dwc3";
|
||||
reg = <0x0 0xc9000000 0x0 0x100000>;
|
||||
|
||||
@@ -358,6 +358,139 @@
|
||||
"mailbox_2";
|
||||
};
|
||||
|
||||
aml_sensor0: aml-sensor@0 {
|
||||
compatible = "amlogic, aml-thermal";
|
||||
device_name = "thermal";
|
||||
#thermal-sensor-cells = <1>;
|
||||
cooling_devices {
|
||||
cpufreq_cool_cluster0 {
|
||||
min_state = <1000000>;
|
||||
dyn_coeff = <140>;
|
||||
cluster_id = <0>;
|
||||
node_name = "cpufreq_cool0";
|
||||
device_type = "cpufreq";
|
||||
};
|
||||
cpufreq_cool_cluster1 {
|
||||
min_state = <500000>;
|
||||
dyn_coeff = <140>;
|
||||
cluster_id = <1>;
|
||||
node_name = "cpufreq_cool1";
|
||||
device_type = "cpufreq";
|
||||
};
|
||||
cpucore_cool_cluster0 {
|
||||
min_state = <1>;
|
||||
dyn_coeff = <0>;
|
||||
cluster_id = <0>;
|
||||
node_name = "cpucore_cool0";
|
||||
device_type = "cpucore";
|
||||
};
|
||||
cpucore_cool_cluster1 {
|
||||
min_state = <1>;
|
||||
dyn_coeff = <0>;
|
||||
cluster_id = <1>;
|
||||
node_name = "cpucore_cool1";
|
||||
device_type = "cpucore";
|
||||
};
|
||||
gpufreq_cool {
|
||||
min_state = <400>;
|
||||
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 */
|
||||
};
|
||||
cpufreq_cool1:cpufreq_cool1 {
|
||||
#cooling-cells = <2>; /* min followed by max */
|
||||
};
|
||||
cpucore_cool0:cpucore_cool0 {
|
||||
#cooling-cells = <2>; /* min followed by max */
|
||||
};
|
||||
cpucore_cool1:cpucore_cool1 {
|
||||
#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 = <2450>;
|
||||
|
||||
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_map0 {
|
||||
trip = <&control>;
|
||||
cooling-device = <&cpufreq_cool0 0 4>;
|
||||
contribution = <1024>;
|
||||
};
|
||||
cpufreq_cooling_map1 {
|
||||
trip = <&control>;
|
||||
cooling-device = <&cpufreq_cool1 0 4>;
|
||||
contribution = <1024>;
|
||||
};
|
||||
cpucore_cooling_map0 {
|
||||
trip = <&control>;
|
||||
cooling-device = <&cpucore_cool0 0 3>;
|
||||
contribution = <1024>;
|
||||
};
|
||||
cpucore_cooling_map1 {
|
||||
trip = <&control>;
|
||||
cooling-device = <&cpucore_cool1 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>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
vout {
|
||||
compatible = "amlogic, vout";
|
||||
dev_name = "vout";
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
|
||||
cpu-map {
|
||||
cluster0:cluster0 {
|
||||
#cooling-cells = <2>; /* min followed by max */
|
||||
core0 {
|
||||
cpu = <&CPU0>;
|
||||
};
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
|
||||
cpu-map {
|
||||
cluster0:cluster0 {
|
||||
#cooling-cells = <2>; /* min followed by max */
|
||||
core0 {
|
||||
cpu = <&CPU0>;
|
||||
};
|
||||
@@ -46,7 +45,6 @@
|
||||
};
|
||||
};
|
||||
cluster1:cluster1 {
|
||||
#cooling-cells = <2>; /* min followed by max */
|
||||
core0 {
|
||||
cpu = <&CPU4>;
|
||||
};
|
||||
|
||||
@@ -7,11 +7,11 @@ CONFIG_BSD_PROCESS_ACCT=y
|
||||
CONFIG_IKCONFIG=y
|
||||
CONFIG_LOG_BUF_SHIFT=19
|
||||
CONFIG_CGROUPS=y
|
||||
CONFIG_CGROUP_SCHED=y
|
||||
CONFIG_RT_GROUP_SCHED=y
|
||||
CONFIG_CGROUP_DEBUG=y
|
||||
CONFIG_CGROUP_FREEZER=y
|
||||
CONFIG_CGROUP_CPUACCT=y
|
||||
CONFIG_CGROUP_DEBUG=y
|
||||
CONFIG_CGROUP_SCHED=y
|
||||
CONFIG_RT_GROUP_SCHED=y
|
||||
CONFIG_BLK_DEV_INITRD=y
|
||||
CONFIG_EMBEDDED=y
|
||||
# CONFIG_COMPAT_BRK is not set
|
||||
@@ -187,7 +187,6 @@ CONFIG_AMLOGIC_MESON_REMOTE=y
|
||||
CONFIG_AMLOGIC_EFUSE=y
|
||||
CONFIG_AMLOGIC_REBOOT=y
|
||||
CONFIG_AMLOGIC_INTERNAL_PHY=y
|
||||
CONFIG_AMLOGIC_AO_CEC=y
|
||||
CONFIG_AMLOGIC_CPU_HOTPLUG=y
|
||||
CONFIG_AMLOGIC_PWM=y
|
||||
CONFIG_AMLOGIC_MEDIA_ENABLE=y
|
||||
@@ -218,8 +217,13 @@ CONFIG_AMLOGIC_MEDIA_VIUIN=y
|
||||
CONFIG_AMLOGIC_MMC=y
|
||||
CONFIG_AMLOGIC_VRTC=y
|
||||
CONFIG_AMLOGIC_SMARTCARD=y
|
||||
CONFIG_AMLOGIC_AO_CEC=y
|
||||
CONFIG_AMLOGIC_SECURITY_KEY=y
|
||||
CONFIG_AMLOGIC_KEY_MANAGE=y
|
||||
CONFIG_AMLOGIC_TEMP_SENSOR=y
|
||||
CONFIG_AMLOGIC_CPUCORE_THERMAL=y
|
||||
CONFIG_AMLOGIC_GPU_THERMAL=y
|
||||
CONFIG_AMLOGIC_GPUCORE_THERMAL=y
|
||||
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
|
||||
CONFIG_DEVTMPFS=y
|
||||
CONFIG_DEVTMPFS_MOUNT=y
|
||||
|
||||
@@ -18,6 +18,7 @@ extern struct cpu_topology cpu_topology[NR_CPUS];
|
||||
#define topology_core_cpumask(cpu) (&cpu_topology[cpu].core_sibling)
|
||||
#define topology_sibling_cpumask(cpu) (&cpu_topology[cpu].thread_sibling)
|
||||
|
||||
#define mc_capable() (cpu_topology[0].cluster_id != -1)
|
||||
void init_cpu_topology(void);
|
||||
void store_cpu_topology(unsigned int cpuid);
|
||||
const struct cpumask *cpu_coregroup_mask(int cpu);
|
||||
|
||||
@@ -63,5 +63,7 @@ source "drivers/amlogic/securitykey/Kconfig"
|
||||
|
||||
source "drivers/amlogic/key_manage/Kconfig"
|
||||
|
||||
source "drivers/amlogic/thermal/Kconfig"
|
||||
|
||||
endmenu
|
||||
endif
|
||||
|
||||
@@ -59,3 +59,5 @@ obj-$(CONFIG_AMLOGIC_SECURITY_KEY) += securitykey/
|
||||
|
||||
obj-$(CONFIG_AMLOGIC_KEY_MANAGE) += key_manage/
|
||||
|
||||
obj-$(CONFIG_AMLOGIC_TEMP_SENSOR) += thermal/
|
||||
|
||||
|
||||
52
drivers/amlogic/thermal/Kconfig
Normal file
52
drivers/amlogic/thermal/Kconfig
Normal file
@@ -0,0 +1,52 @@
|
||||
#
|
||||
# Amlogic temperature sensor configuration
|
||||
#
|
||||
|
||||
menu "Amlogic temperature sensor"
|
||||
|
||||
config AMLOGIC_TEMP_SENSOR
|
||||
bool "Amlgoic temperature sensor Support"
|
||||
default n
|
||||
---help---
|
||||
Thermal sensor low level support for thermal
|
||||
This driver parse thermal config data from device tree files.
|
||||
And register each cooling device for thermal framework.
|
||||
|
||||
If you wan this driver, selest it.
|
||||
|
||||
config AMLOGIC_CPUCORE_THERMAL
|
||||
bool "generic cpu core cooling support"
|
||||
depends on AMLOGIC_TEMP_SENSOR
|
||||
default n
|
||||
help
|
||||
This implements the generic cpu cooling mechanism through reduce cpu core numbers.
|
||||
This will be useful for platforms using the generic thermal interface
|
||||
and not the ACPI interface.
|
||||
|
||||
If you want this support, you should say Y here.
|
||||
|
||||
config AMLOGIC_GPU_THERMAL
|
||||
bool "generic gpu cooling support"
|
||||
depends on AMLOGIC_TEMP_SENSOR
|
||||
default n
|
||||
help
|
||||
This implements the generic gpu cooling mechanism through frequency
|
||||
reduction. An ACPI version of this already exists
|
||||
(drivers/acpi/processor_thermal.c).
|
||||
This will be useful for platforms using the generic thermal interface
|
||||
and not the ACPI interface.
|
||||
|
||||
If you want this support, you should say Y here.
|
||||
|
||||
config AMLOGIC_GPUCORE_THERMAL
|
||||
bool "generic gpu core cooling support"
|
||||
depends on AMLOGIC_TEMP_SENSOR
|
||||
default n
|
||||
help
|
||||
This implements the generic cpu cooling mechanism through reduce cpu core numbers.
|
||||
This will be useful for platforms using the generic thermal interface
|
||||
and not the ACPI interface.
|
||||
|
||||
If you want this support, you should say Y here.
|
||||
|
||||
endmenu
|
||||
6
drivers/amlogic/thermal/Makefile
Normal file
6
drivers/amlogic/thermal/Makefile
Normal file
@@ -0,0 +1,6 @@
|
||||
|
||||
obj-$(CONFIG_AMLOGIC_TEMP_SENSOR) += aml_thermal_hw.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
|
||||
|
||||
406
drivers/amlogic/thermal/aml_thermal_hw.c
Normal file
406
drivers/amlogic/thermal/aml_thermal_hw.c
Normal file
@@ -0,0 +1,406 @@
|
||||
/*
|
||||
* drivers/amlogic/thermal/aml_thermal_hw.c
|
||||
*
|
||||
* Copyright (C) 2016 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/cpu.h>
|
||||
|
||||
#define NOT_WRITE_EFUSE 0x0
|
||||
#define EFUEE_PRIVATE 0x4
|
||||
#define EFUSE_OPS 0xa
|
||||
|
||||
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 {
|
||||
int chip_trimmed;
|
||||
int cool_dev_num;
|
||||
int min_exist;
|
||||
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 ret;
|
||||
|
||||
ret = scpi_get_sensor("aml_thermal");
|
||||
soc_sensor.chip_trimmed = ret < 0 ? 0 : 1;
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(thermal_firmware_init);
|
||||
|
||||
int get_cpu_temp(void)
|
||||
{
|
||||
unsigned int val = 0;
|
||||
|
||||
if (soc_sensor.chip_trimmed) { /* only supported trimmed chips */
|
||||
if (scpi_get_sensor_value(0, &val) < 0)
|
||||
return -1000;
|
||||
return val;
|
||||
} else {
|
||||
return -1000;
|
||||
}
|
||||
}
|
||||
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);
|
||||
314
drivers/amlogic/thermal/cpucore_cooling.c
Normal file
314
drivers/amlogic/thermal/cpucore_cooling.c
Normal file
@@ -0,0 +1,314 @@
|
||||
/*
|
||||
* drivers/amlogic/thermal/cpucore_cooling.c
|
||||
*
|
||||
* Copyright (C) 2016 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/module.h>
|
||||
#include <linux/thermal.h>
|
||||
#include <linux/cpufreq.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/amlogic/cpucore_cooling.h>
|
||||
#include <linux/amlogic/cpu_hotplug.h>
|
||||
#include <linux/cpumask.h>
|
||||
|
||||
/**
|
||||
* struct cpucore_cooling_device - data for cooling device with cpucore
|
||||
* @id: unique integer value corresponding to each cpucore_cooling_device
|
||||
* registered.
|
||||
* @cool_dev: thermal_cooling_device pointer to keep track of the
|
||||
* registered cooling device.
|
||||
* @cpucore_state: integer value representing the current state of cpucore
|
||||
* cooling devices.
|
||||
* @cpucore_val: integer value representing the absolute value of the clipped
|
||||
* frequency.
|
||||
* @allowed_cpus: all the cpus involved for this cpucore_cooling_device.
|
||||
*
|
||||
* This structure is required for keeping information of each
|
||||
* cpucore_cooling_device registered. In order to prevent corruption of this a
|
||||
* mutex lock cooling_cpucore_lock is used.
|
||||
*/
|
||||
|
||||
static DEFINE_IDR(cpucore_idr);
|
||||
static DEFINE_MUTEX(cooling_cpucore_lock);
|
||||
static LIST_HEAD(cpucore_dev_list);
|
||||
|
||||
/* notify_table passes value to the cpucore_ADJUST callback function. */
|
||||
#define NOTIFY_INVALID NULL
|
||||
|
||||
/**
|
||||
* get_idr - function to get a unique id.
|
||||
* @idr: struct idr * handle used to create a id.
|
||||
* @id: int * value generated by this function.
|
||||
*
|
||||
* This function will populate @id with an unique
|
||||
* id, using the idr API.
|
||||
*
|
||||
* Return: 0 on success, an error code on failure.
|
||||
*/
|
||||
static int get_idr(struct idr *idr, int *id)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&cooling_cpucore_lock);
|
||||
ret = idr_alloc(idr, NULL, 0, 0, GFP_KERNEL);
|
||||
mutex_unlock(&cooling_cpucore_lock);
|
||||
if (unlikely(ret < 0))
|
||||
return ret;
|
||||
*id = ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* release_idr - function to free the unique id.
|
||||
* @idr: struct idr * handle used for creating the id.
|
||||
* @id: int value representing the unique id.
|
||||
*/
|
||||
static void release_idr(struct idr *idr, int id)
|
||||
{
|
||||
mutex_lock(&cooling_cpucore_lock);
|
||||
idr_remove(idr, id);
|
||||
mutex_unlock(&cooling_cpucore_lock);
|
||||
}
|
||||
|
||||
/* cpucore cooling device callback functions are defined below */
|
||||
|
||||
/**
|
||||
* cpucore_get_max_state - callback function to get the max cooling state.
|
||||
* @cdev: thermal cooling device pointer.
|
||||
* @state: fill this variable with the max cooling state.
|
||||
*
|
||||
* Callback for the thermal cooling device to return the cpucore
|
||||
* max cooling state.
|
||||
*
|
||||
* Return: 0 on success, an error code otherwise.
|
||||
*/
|
||||
static int cpucore_get_max_state(struct thermal_cooling_device *cdev,
|
||||
unsigned long *state)
|
||||
{
|
||||
struct cpucore_cooling_device *cpucore_device = cdev->devdata;
|
||||
*state = cpucore_device->max_cpu_core_num;
|
||||
pr_debug("max cpu core=%ld\n", *state);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* cpucore_get_cur_state - callback function to get the current cooling state.
|
||||
* @cdev: thermal cooling device pointer.
|
||||
* @state: fill this variable with the current cooling state.
|
||||
*
|
||||
* Callback for the thermal cooling device to return the cpucore
|
||||
* current cooling state.
|
||||
*
|
||||
* Return: 0 on success, an error code otherwise.
|
||||
*/
|
||||
static int cpucore_get_cur_state(struct thermal_cooling_device *cdev,
|
||||
unsigned long *state)
|
||||
{
|
||||
struct cpucore_cooling_device *cpucore_device = cdev->devdata;
|
||||
*state = cpucore_device->cpucore_state;
|
||||
pr_debug("current state=%ld\n", *state);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* cpucore_set_cur_state - callback function to set the current cooling state.
|
||||
* @cdev: thermal cooling device pointer.
|
||||
* @state: set this variable to the current cooling state.
|
||||
*
|
||||
* Callback for the thermal cooling device to change the cpucore
|
||||
* current cooling state.
|
||||
*
|
||||
* Return: 0 on success, an error code otherwise.
|
||||
*/
|
||||
static int cpucore_set_cur_state(struct thermal_cooling_device *cdev,
|
||||
unsigned long state)
|
||||
{
|
||||
struct cpucore_cooling_device *cpucore_device = cdev->devdata;
|
||||
int set_max_num, id;
|
||||
|
||||
mutex_lock(&cooling_cpucore_lock);
|
||||
if (cpucore_device->stop_flag) {
|
||||
mutex_unlock(&cooling_cpucore_lock);
|
||||
return 0;
|
||||
}
|
||||
if ((state & CPU_STOP) == CPU_STOP) {
|
||||
cpucore_device->stop_flag = 1;
|
||||
state = state&(~CPU_STOP);
|
||||
}
|
||||
mutex_unlock(&cooling_cpucore_lock);
|
||||
if (cpucore_device->max_cpu_core_num - state > 0) {
|
||||
cpucore_device->cpucore_state = state;
|
||||
set_max_num = cpucore_device->max_cpu_core_num - state;
|
||||
id = cpucore_device->cluster_id;
|
||||
pr_debug("set max cpu num=%d,state=%ld\n", set_max_num, state);
|
||||
cpufreq_set_max_cpu_num(set_max_num, id);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Simple mathematics model for cpu core power:
|
||||
* just for ipa hook, nothing to do;
|
||||
*/
|
||||
static int cpucore_get_requested_power(struct thermal_cooling_device *cdev,
|
||||
struct thermal_zone_device *tz,
|
||||
u32 *power)
|
||||
{
|
||||
*power = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cpucore_state2power(struct thermal_cooling_device *cdev,
|
||||
struct thermal_zone_device *tz,
|
||||
unsigned long state, u32 *power)
|
||||
{
|
||||
*power = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cpucore_power2state(struct thermal_cooling_device *cdev,
|
||||
struct thermal_zone_device *tz, u32 power,
|
||||
unsigned long *state)
|
||||
{
|
||||
cdev->ops->get_cur_state(cdev, state);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cpucore_notify_state(struct thermal_cooling_device *cdev,
|
||||
struct thermal_zone_device *tz,
|
||||
enum thermal_trip_type type)
|
||||
{
|
||||
unsigned long cur_state, ins_upper;
|
||||
long upper = -1;
|
||||
int i;
|
||||
|
||||
switch (type) {
|
||||
case THERMAL_TRIP_HOT:
|
||||
for (i = 0; i < tz->trips; i++) {
|
||||
ins_upper = thermal_get_upper(tz, cdev, i);
|
||||
if (ins_upper > upper)
|
||||
upper = ins_upper;
|
||||
}
|
||||
cur_state = tz->hot_step;
|
||||
/* do not exceed levels */
|
||||
if (upper != -1 && cur_state > upper)
|
||||
cur_state = upper;
|
||||
if (cur_state < 0)
|
||||
cur_state = 0;
|
||||
pr_debug("%s, cur_state:%ld, upper:%ld, step:%d\n",
|
||||
__func__, cur_state, upper, tz->hot_step);
|
||||
cdev->ops->set_cur_state(cdev, cur_state);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Bind cpucore callbacks to thermal cooling device ops */
|
||||
static struct thermal_cooling_device_ops const cpucore_cooling_ops = {
|
||||
.get_max_state = cpucore_get_max_state,
|
||||
.get_cur_state = cpucore_get_cur_state,
|
||||
.set_cur_state = cpucore_set_cur_state,
|
||||
.state2power = cpucore_state2power,
|
||||
.power2state = cpucore_power2state,
|
||||
.notify_state = cpucore_notify_state,
|
||||
.get_requested_power = cpucore_get_requested_power,
|
||||
};
|
||||
|
||||
/**
|
||||
* cpucore_cooling_register - function to create cpucore cooling device.
|
||||
*
|
||||
* This interface function registers the cpucore cooling device with the name
|
||||
* "thermal-cpucore-%x". This api can support multiple instances of cpucore
|
||||
* cooling devices.
|
||||
*
|
||||
* Return: a valid struct thermal_cooling_device pointer on success,
|
||||
* on failure, it returns a corresponding ERR_PTR().
|
||||
*/
|
||||
struct thermal_cooling_device *
|
||||
cpucore_cooling_register(struct device_node *np, int cluster_id)
|
||||
{
|
||||
struct thermal_cooling_device *cool_dev;
|
||||
struct cpucore_cooling_device *cpucore_dev = NULL;
|
||||
char dev_name[THERMAL_NAME_LENGTH];
|
||||
int ret = 0, cpu;
|
||||
int cores = 0;
|
||||
|
||||
cpucore_dev = kzalloc(sizeof(struct cpucore_cooling_device),
|
||||
GFP_KERNEL);
|
||||
if (!cpucore_dev)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
ret = get_idr(&cpucore_idr, &cpucore_dev->id);
|
||||
if (ret) {
|
||||
kfree(cpucore_dev);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
if (mc_capable()) {
|
||||
for_each_possible_cpu(cpu) {
|
||||
if (topology_physical_package_id(cpu) == cluster_id)
|
||||
cores++;
|
||||
}
|
||||
} else {
|
||||
cores = num_possible_cpus();
|
||||
}
|
||||
cpucore_dev->max_cpu_core_num = cores;
|
||||
pr_info("%s, max_cpu_core_num:%d\n", __func__, cores);
|
||||
snprintf(dev_name, sizeof(dev_name), "thermal-cpucore-%d",
|
||||
cpucore_dev->id);
|
||||
|
||||
cool_dev = thermal_of_cooling_device_register(np, dev_name, cpucore_dev,
|
||||
&cpucore_cooling_ops);
|
||||
if (!cool_dev) {
|
||||
release_idr(&cpucore_idr, cpucore_dev->id);
|
||||
kfree(cpucore_dev);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
cpucore_dev->cool_dev = cool_dev;
|
||||
cpucore_dev->cpucore_state = 0;
|
||||
cpucore_dev->cluster_id = cluster_id;
|
||||
return cool_dev;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cpucore_cooling_register);
|
||||
|
||||
/**
|
||||
* cpucore_cooling_unregister - function to remove cpucore cooling device.
|
||||
* @cdev: thermal cooling device pointer.
|
||||
*
|
||||
* This interface function unregisters the "thermal-cpucore-%x" cooling device.
|
||||
*/
|
||||
void cpucore_cooling_unregister(struct thermal_cooling_device *cdev)
|
||||
{
|
||||
struct cpucore_cooling_device *cpucore_dev;
|
||||
|
||||
if (!cdev)
|
||||
return;
|
||||
|
||||
cpucore_dev = cdev->devdata;
|
||||
|
||||
thermal_cooling_device_unregister(cpucore_dev->cool_dev);
|
||||
release_idr(&cpucore_idr, cpucore_dev->id);
|
||||
kfree(cpucore_dev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cpucore_cooling_unregister);
|
||||
342
drivers/amlogic/thermal/gpu_cooling.c
Normal file
342
drivers/amlogic/thermal/gpu_cooling.c
Normal file
@@ -0,0 +1,342 @@
|
||||
/*
|
||||
* drivers/amlogic/thermal/gpu_cooling.c
|
||||
*
|
||||
* Copyright (C) 2016 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/module.h>
|
||||
#include <linux/thermal.h>
|
||||
#include <linux/cpufreq.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/amlogic/gpu_cooling.h>
|
||||
|
||||
|
||||
static DEFINE_IDR(gpufreq_idr);
|
||||
static DEFINE_MUTEX(cooling_gpufreq_lock);
|
||||
static int dyn_coef = -1;
|
||||
static int max_pp;
|
||||
static struct device_node *np;
|
||||
|
||||
/* notify_table passes value to the gpuFREQ_ADJUST callback function. */
|
||||
#define NOTIFY_INVALID NULL
|
||||
|
||||
void save_gpu_cool_para(int coef, struct device_node *n, int pp)
|
||||
{
|
||||
if (dyn_coef == -1 && np == NULL) {
|
||||
dyn_coef = coef;
|
||||
np = n;
|
||||
max_pp = pp;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get_idr - function to get a unique id.
|
||||
* @idr: struct idr * handle used to create a id.
|
||||
* @id: int * value generated by this function.
|
||||
*
|
||||
* This function will populate @id with an unique
|
||||
* id, using the idr API.
|
||||
*
|
||||
* Return: 0 on success, an error code on failure.
|
||||
*/
|
||||
static int get_idr(struct idr *idr, int *id)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&cooling_gpufreq_lock);
|
||||
ret = idr_alloc(idr, NULL, 0, 0, GFP_KERNEL);
|
||||
mutex_unlock(&cooling_gpufreq_lock);
|
||||
if (unlikely(ret < 0))
|
||||
return ret;
|
||||
*id = ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* release_idr - function to free the unique id.
|
||||
* @idr: struct idr * handle used for creating the id.
|
||||
* @id: int value representing the unique id.
|
||||
*/
|
||||
static void release_idr(struct idr *idr, int id)
|
||||
{
|
||||
mutex_lock(&cooling_gpufreq_lock);
|
||||
idr_remove(idr, id);
|
||||
mutex_unlock(&cooling_gpufreq_lock);
|
||||
}
|
||||
|
||||
|
||||
/* gpufreq cooling device callback functions are defined below */
|
||||
|
||||
/**
|
||||
* gpufreq_get_max_state - callback function to get the max cooling state.
|
||||
* @cdev: thermal cooling device pointer.
|
||||
* @state: fill this variable with the max cooling state.
|
||||
*
|
||||
* Callback for the thermal cooling device to return the gpufreq
|
||||
* max cooling state.
|
||||
*
|
||||
* Return: 0 on success, an error code otherwise.
|
||||
*/
|
||||
static int gpufreq_get_max_state(struct thermal_cooling_device *cdev,
|
||||
unsigned long *state)
|
||||
{
|
||||
struct gpufreq_cooling_device *gpufreq_device = cdev->devdata;
|
||||
|
||||
if (gpufreq_device->get_gpu_max_level)
|
||||
*state = (unsigned long)(gpufreq_device->get_gpu_max_level());
|
||||
pr_debug("default max state=%ld\n", *state);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* gpufreq_get_cur_state - callback function to get the current cooling state.
|
||||
* @cdev: thermal cooling device pointer.
|
||||
* @state: fill this variable with the current cooling state.
|
||||
*
|
||||
* Callback for the thermal cooling device to return the gpufreq
|
||||
* current cooling state.
|
||||
*
|
||||
* Return: 0 on success, an error code otherwise.
|
||||
*/
|
||||
static int gpufreq_get_cur_state(struct thermal_cooling_device *cdev,
|
||||
unsigned long *state)
|
||||
{
|
||||
struct gpufreq_cooling_device *gpufreq_device = cdev->devdata;
|
||||
unsigned long max_state = 0, temp = 0;
|
||||
|
||||
/* *state = gpufreq_device->gpufreq_state; */
|
||||
gpufreq_get_max_state(cdev, &max_state);
|
||||
if (gpufreq_device->get_gpu_current_max_level) {
|
||||
temp = gpufreq_device->get_gpu_current_max_level();
|
||||
*state = ((max_state - 1) - temp);
|
||||
gpufreq_device->gpufreq_state = *state;
|
||||
pr_debug("current max state=%ld\n", *state);
|
||||
} else
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* gpufreq_set_cur_state - callback function to set the current cooling state.
|
||||
* @cdev: thermal cooling device pointer.
|
||||
* @state: set this variable to the current cooling state.
|
||||
*
|
||||
* Callback for the thermal cooling device to change the gpufreq
|
||||
* current cooling state.
|
||||
*
|
||||
* Return: 0 on success, an error code otherwise.
|
||||
*/
|
||||
static int gpufreq_set_cur_state(struct thermal_cooling_device *cdev,
|
||||
unsigned long state)
|
||||
{
|
||||
struct gpufreq_cooling_device *gpufreq_device = cdev->devdata;
|
||||
unsigned long max_state = 0;
|
||||
int ret;
|
||||
|
||||
pr_debug("state=%ld,gpufreq_device->gpufreq_state=%d\n",
|
||||
state, gpufreq_device->gpufreq_state);
|
||||
/* if (gpufreq_device->gpufreq_state == state) */
|
||||
/* return 0; */
|
||||
gpufreq_device->gpufreq_state = state;
|
||||
ret = gpufreq_get_max_state(cdev, &max_state);
|
||||
state = max_state-1-state;
|
||||
|
||||
pr_debug("state=%ld,gpufreq_device->gpufreq_state=%d\n",
|
||||
state, gpufreq_device->gpufreq_state);
|
||||
if (state >= 0 && state <= max_state) {
|
||||
if (gpufreq_device->set_gpu_freq_idx)
|
||||
gpufreq_device->set_gpu_freq_idx((unsigned int)state);
|
||||
}
|
||||
return 0;
|
||||
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Simple mathematics model for gpu freq power:
|
||||
* power is linear with frequent with coefficient t_c, each GPU pp has
|
||||
* same frequent
|
||||
* We set: online PP to n_c;
|
||||
* temperature coefficient to t_c;
|
||||
* power to p_c;
|
||||
* current runnint frequent to F(MHz)
|
||||
* We have:
|
||||
* Power = n_c * t_c * F
|
||||
*/
|
||||
static int gpufreq_get_requested_power(struct thermal_cooling_device *cdev,
|
||||
struct thermal_zone_device *tz,
|
||||
u32 *power)
|
||||
{
|
||||
struct gpufreq_cooling_device *gf_dev = cdev->devdata;
|
||||
int freq, coef, pp;
|
||||
long freq_state, max_state = 0;
|
||||
int load;
|
||||
|
||||
gpufreq_get_max_state(cdev, &max_state);
|
||||
freq_state = (max_state - 1 - gf_dev->gpufreq_state);
|
||||
freq = gf_dev->get_gpu_freq(freq_state);
|
||||
pp = gf_dev->get_online_pp();
|
||||
coef = gf_dev->dyn_coeff;
|
||||
load = gf_dev->get_gpu_loading();
|
||||
|
||||
*power = (freq * coef * pp) * load / 102400;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gpufreq_state2power(struct thermal_cooling_device *cdev,
|
||||
struct thermal_zone_device *tz,
|
||||
unsigned long state, u32 *power)
|
||||
{
|
||||
struct gpufreq_cooling_device *gf_dev = cdev->devdata;
|
||||
int freq;
|
||||
int coef = gf_dev->dyn_coeff;
|
||||
int pp;
|
||||
int full_power;
|
||||
long max_state = 0;
|
||||
|
||||
/* assume max pp */
|
||||
gpufreq_get_max_state(cdev, &max_state);
|
||||
freq = gf_dev->get_gpu_freq(max_state - 1 - state);
|
||||
pp = gf_dev->max_pp;
|
||||
full_power = freq * coef * pp;
|
||||
|
||||
/* round up */
|
||||
*power = full_power / 1024 + ((full_power & 0x3ff) ? 1 : 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gpufreq_power2state(struct thermal_cooling_device *cdev,
|
||||
struct thermal_zone_device *tz, u32 power,
|
||||
unsigned long *state)
|
||||
{
|
||||
struct gpufreq_cooling_device *gf_dev = cdev->devdata;
|
||||
int freq;
|
||||
int coef;
|
||||
int pp;
|
||||
long max_state = 0;
|
||||
|
||||
gpufreq_get_max_state(cdev, &max_state);
|
||||
pp = gf_dev->max_pp;
|
||||
coef = gf_dev->dyn_coeff;
|
||||
freq = (power * 1024) / (coef * pp);
|
||||
|
||||
*state = gf_dev->get_gpu_freq_level(freq);
|
||||
return 0;
|
||||
}
|
||||
/* Bind gpufreq callbacks to thermal cooling device ops */
|
||||
static struct thermal_cooling_device_ops const gpufreq_cooling_ops = {
|
||||
.get_max_state = gpufreq_get_max_state,
|
||||
.get_cur_state = gpufreq_get_cur_state,
|
||||
.set_cur_state = gpufreq_set_cur_state,
|
||||
.state2power = gpufreq_state2power,
|
||||
.power2state = gpufreq_power2state,
|
||||
.get_requested_power = gpufreq_get_requested_power,
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* gpufreq_cooling_register - function to create gpufreq cooling device.
|
||||
* @clip_gpus: gpumask of gpus where the frequency constraints will happen.
|
||||
*
|
||||
* This interface function registers the gpufreq cooling device with the name
|
||||
* "thermal-gpufreq-%x". This api can support multiple instances of gpufreq
|
||||
* cooling devices.
|
||||
*
|
||||
* Return: a valid struct thermal_cooling_device pointer on success,
|
||||
* on failure, it returns a corresponding ERR_PTR().
|
||||
*/
|
||||
struct gpufreq_cooling_device *gpufreq_cooling_alloc(void)
|
||||
{
|
||||
struct gpufreq_cooling_device *gcdev;
|
||||
|
||||
gcdev = kzalloc(sizeof(struct gpufreq_cooling_device), GFP_KERNEL);
|
||||
if (!gcdev)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
memset(gcdev, 0, sizeof(*gcdev));
|
||||
if (np) {
|
||||
gcdev->np = np;
|
||||
gcdev->dyn_coeff = dyn_coef;
|
||||
gcdev->max_pp = max_pp;
|
||||
}
|
||||
return gcdev;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpufreq_cooling_alloc);
|
||||
|
||||
int gpufreq_cooling_register(struct gpufreq_cooling_device *gpufreq_dev)
|
||||
{
|
||||
struct thermal_cooling_device *cool_dev;
|
||||
char dev_name[THERMAL_NAME_LENGTH];
|
||||
int ret = 0;
|
||||
|
||||
ret = get_idr(&gpufreq_idr, &gpufreq_dev->id);
|
||||
if (ret) {
|
||||
kfree(gpufreq_dev);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
snprintf(dev_name, sizeof(dev_name), "thermal-gpufreq-%d",
|
||||
gpufreq_dev->id);
|
||||
gpufreq_dev->gpufreq_state = 0;
|
||||
|
||||
cool_dev = thermal_of_cooling_device_register(gpufreq_dev->np,
|
||||
dev_name, gpufreq_dev,
|
||||
&gpufreq_cooling_ops);
|
||||
if (!cool_dev) {
|
||||
release_idr(&gpufreq_idr, gpufreq_dev->id);
|
||||
kfree(gpufreq_dev);
|
||||
return -EINVAL;
|
||||
}
|
||||
gpufreq_dev->cool_dev = cool_dev;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpufreq_cooling_register);
|
||||
|
||||
/**
|
||||
* gpufreq_cooling_unregister - function to remove gpufreq cooling device.
|
||||
* @cdev: thermal cooling device pointer.
|
||||
*
|
||||
* This interface function unregisters the "thermal-gpufreq-%x" cooling device.
|
||||
*/
|
||||
void gpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
|
||||
{
|
||||
struct gpufreq_cooling_device *gpufreq_dev;
|
||||
|
||||
if (!cdev)
|
||||
return;
|
||||
|
||||
gpufreq_dev = cdev->devdata;
|
||||
|
||||
thermal_cooling_device_unregister(gpufreq_dev->cool_dev);
|
||||
release_idr(&gpufreq_idr, gpufreq_dev->id);
|
||||
kfree(gpufreq_dev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpufreq_cooling_unregister);
|
||||
|
||||
unsigned int (*gpu_freq_callback)(void) = NULL;
|
||||
EXPORT_SYMBOL(gpu_freq_callback);
|
||||
|
||||
int register_gpu_freq_info(unsigned int (*fun)(void))
|
||||
{
|
||||
if (fun)
|
||||
gpu_freq_callback = fun;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(register_gpu_freq_info);
|
||||
322
drivers/amlogic/thermal/gpucore_cooling.c
Normal file
322
drivers/amlogic/thermal/gpucore_cooling.c
Normal file
@@ -0,0 +1,322 @@
|
||||
/*
|
||||
* drivers/amlogic/thermal/gpucore_cooling.c
|
||||
*
|
||||
* Copyright (C) 2016 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/module.h>
|
||||
#include <linux/thermal.h>
|
||||
#include <linux/cpufreq.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/amlogic/gpucore_cooling.h>
|
||||
#include <linux/device.h>
|
||||
|
||||
/**
|
||||
* struct gpucore_cooling_device - data for cooling device with gpucore
|
||||
* @id: unique integer value corresponding to each gpucore_cooling_device
|
||||
* registered.
|
||||
* @cool_dev: thermal_cooling_device pointer to keep track of the
|
||||
* registered cooling device.
|
||||
* @gpucore_state: integer value representing the current state of gpucore
|
||||
* cooling devices.
|
||||
* @gpucore_val: integer value representing the absolute value of the clipped
|
||||
* frequency.
|
||||
* @allowed_cpus: all the cpus involved for this gpucore_cooling_device.
|
||||
*
|
||||
* This structure is required for keeping information of each
|
||||
* gpucore_cooling_device registered. In order to prevent corruption of this a
|
||||
* mutex lock cooling_gpucore_lock is used.
|
||||
*/
|
||||
|
||||
static DEFINE_IDR(gpucore_idr);
|
||||
static DEFINE_MUTEX(cooling_gpucore_lock);
|
||||
|
||||
/* notify_table passes value to the gpucore_ADJUST callback function. */
|
||||
#define NOTIFY_INVALID NULL
|
||||
|
||||
static struct device_node *np;
|
||||
static int save_flag = -1;
|
||||
|
||||
void save_gpucore_thermal_para(struct device_node *n)
|
||||
{
|
||||
if (!n)
|
||||
return;
|
||||
|
||||
if (save_flag == -1) {
|
||||
save_flag = 1;
|
||||
np = n;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get_idr - function to get a unique id.
|
||||
* @idr: struct idr * handle used to create a id.
|
||||
* @id: int * value generated by this function.
|
||||
*
|
||||
* This function will populate @id with an unique
|
||||
* id, using the idr API.
|
||||
*
|
||||
* Return: 0 on success, an error code on failure.
|
||||
*/
|
||||
static int get_idr(struct idr *idr, int *id)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&cooling_gpucore_lock);
|
||||
ret = idr_alloc(idr, NULL, 0, 0, GFP_KERNEL);
|
||||
mutex_unlock(&cooling_gpucore_lock);
|
||||
if (unlikely(ret < 0))
|
||||
return ret;
|
||||
*id = ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* release_idr - function to free the unique id.
|
||||
* @idr: struct idr * handle used for creating the id.
|
||||
* @id: int value representing the unique id.
|
||||
*/
|
||||
static void release_idr(struct idr *idr, int id)
|
||||
{
|
||||
mutex_lock(&cooling_gpucore_lock);
|
||||
idr_remove(idr, id);
|
||||
mutex_unlock(&cooling_gpucore_lock);
|
||||
}
|
||||
|
||||
/* gpucore cooling device callback functions are defined below */
|
||||
|
||||
/**
|
||||
* gpucore_get_max_state - callback function to get the max cooling state.
|
||||
* @cdev: thermal cooling device pointer.
|
||||
* @state: fill this variable with the max cooling state.
|
||||
*
|
||||
* Callback for the thermal cooling device to return the gpucore
|
||||
* max cooling state.
|
||||
*
|
||||
* Return: 0 on success, an error code otherwise.
|
||||
*/
|
||||
static int gpucore_get_max_state(struct thermal_cooling_device *cdev,
|
||||
unsigned long *state)
|
||||
{
|
||||
struct gpucore_cooling_device *gpucore_device = cdev->devdata;
|
||||
*state = gpucore_device->max_gpu_core_num;
|
||||
pr_debug("max Gpu core=%ld\n", *state);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* gpucore_get_cur_state - callback function to get the current cooling state.
|
||||
* @cdev: thermal cooling device pointer.
|
||||
* @state: fill this variable with the current cooling state.
|
||||
*
|
||||
* Callback for the thermal cooling device to return the gpucore
|
||||
* current cooling state.
|
||||
*
|
||||
* Return: 0 on success, an error code otherwise.
|
||||
*/
|
||||
static int gpucore_get_cur_state(struct thermal_cooling_device *cdev,
|
||||
unsigned long *state)
|
||||
{
|
||||
struct gpucore_cooling_device *gpucore_device = cdev->devdata;
|
||||
|
||||
*state = gpucore_device->gpucore_state;
|
||||
pr_debug("current state=%ld\n", *state);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* gpucore_set_cur_state - callback function to set the current cooling state.
|
||||
* @cdev: thermal cooling device pointer.
|
||||
* @state: set this variable to the current cooling state.
|
||||
*
|
||||
* Callback for the thermal cooling device to change the gpucore
|
||||
* current cooling state.
|
||||
*
|
||||
* Return: 0 on success, an error code otherwise.
|
||||
*/
|
||||
static int gpucore_set_cur_state(struct thermal_cooling_device *cdev,
|
||||
unsigned long state)
|
||||
{
|
||||
struct gpucore_cooling_device *gpucore_device = cdev->devdata;
|
||||
int set_max_num;
|
||||
|
||||
mutex_lock(&cooling_gpucore_lock);
|
||||
if (gpucore_device->stop_flag) {
|
||||
mutex_unlock(&cooling_gpucore_lock);
|
||||
return 0;
|
||||
}
|
||||
if ((state & GPU_STOP) == GPU_STOP) {
|
||||
gpucore_device->stop_flag = 1;
|
||||
state = state&(~GPU_STOP);
|
||||
}
|
||||
mutex_unlock(&cooling_gpucore_lock);
|
||||
set_max_num = gpucore_device->max_gpu_core_num - state;
|
||||
/* pp should not be 0 */
|
||||
if (!set_max_num)
|
||||
return -EINVAL;
|
||||
|
||||
gpucore_device->gpucore_state = state;
|
||||
gpucore_device->set_max_pp_num((unsigned int)set_max_num);
|
||||
pr_debug("need set max gpu num=%d,state=%ld\n", set_max_num, state);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Simple mathematics model for gpu core power:
|
||||
* just for ipa hook
|
||||
*/
|
||||
static int gpucore_get_requested_power(struct thermal_cooling_device *cdev,
|
||||
struct thermal_zone_device *tz,
|
||||
u32 *power)
|
||||
{
|
||||
*power = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gpucore_state2power(struct thermal_cooling_device *cdev,
|
||||
struct thermal_zone_device *tz,
|
||||
unsigned long state, u32 *power)
|
||||
{
|
||||
*power = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gpucore_power2state(struct thermal_cooling_device *cdev,
|
||||
struct thermal_zone_device *tz, u32 power,
|
||||
unsigned long *state)
|
||||
{
|
||||
cdev->ops->get_cur_state(cdev, state);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gpucore_notify_state(struct thermal_cooling_device *cdev,
|
||||
struct thermal_zone_device *tz,
|
||||
enum thermal_trip_type type)
|
||||
{
|
||||
unsigned long cur_state, ins_upper;
|
||||
long upper = -1;
|
||||
int i;
|
||||
|
||||
switch (type) {
|
||||
case THERMAL_TRIP_HOT:
|
||||
for (i = 0; i < tz->trips; i++) {
|
||||
ins_upper = thermal_get_upper(tz, cdev, i);
|
||||
if (ins_upper > upper)
|
||||
upper = ins_upper;
|
||||
}
|
||||
cur_state = tz->hot_step;
|
||||
/* do not exceed levels */
|
||||
if (upper != -1 && cur_state > upper)
|
||||
cur_state = upper;
|
||||
if (cur_state < 0)
|
||||
cur_state = 0;
|
||||
pr_debug("%s, cur_state:%ld, upper:%ld, step:%d\n",
|
||||
__func__, cur_state, upper, tz->hot_step);
|
||||
cdev->ops->set_cur_state(cdev, cur_state);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Bind gpucore callbacks to thermal cooling device ops */
|
||||
static struct thermal_cooling_device_ops const gpucore_cooling_ops = {
|
||||
.get_max_state = gpucore_get_max_state,
|
||||
.get_cur_state = gpucore_get_cur_state,
|
||||
.set_cur_state = gpucore_set_cur_state,
|
||||
.state2power = gpucore_state2power,
|
||||
.power2state = gpucore_power2state,
|
||||
.notify_state = gpucore_notify_state,
|
||||
.get_requested_power = gpucore_get_requested_power,
|
||||
};
|
||||
|
||||
/**
|
||||
* gpucore_cooling_register - function to create gpucore cooling device.
|
||||
* @clip_cpus: cpumask of cpus where the frequency constraints will happen.
|
||||
*
|
||||
* This interface function registers the gpucore cooling device with the name
|
||||
* "thermal-gpucore-%x". This api can support multiple instances of gpucore
|
||||
* cooling devices.
|
||||
*
|
||||
* Return: a valid struct thermal_cooling_device pointer on success,
|
||||
* on failure, it returns a corresponding ERR_PTR().
|
||||
*/
|
||||
struct gpucore_cooling_device *gpucore_cooling_alloc(void)
|
||||
{
|
||||
struct gpucore_cooling_device *gcdev;
|
||||
|
||||
gcdev = kzalloc(sizeof(struct gpucore_cooling_device), GFP_KERNEL);
|
||||
if (!gcdev)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
memset(gcdev, 0, sizeof(*gcdev));
|
||||
if (save_flag == 1)
|
||||
gcdev->np = np;
|
||||
return gcdev;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpucore_cooling_alloc);
|
||||
|
||||
int gpucore_cooling_register(struct gpucore_cooling_device *gpucore_dev)
|
||||
{
|
||||
struct thermal_cooling_device *cool_dev;
|
||||
char dev_name[THERMAL_NAME_LENGTH];
|
||||
int ret = 0;
|
||||
|
||||
ret = get_idr(&gpucore_idr, &gpucore_dev->id);
|
||||
if (ret) {
|
||||
kfree(gpucore_dev);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
snprintf(dev_name, sizeof(dev_name), "thermal-gpucore-%d",
|
||||
gpucore_dev->id);
|
||||
|
||||
gpucore_dev->gpucore_state = 0;
|
||||
cool_dev = thermal_of_cooling_device_register(gpucore_dev->np,
|
||||
dev_name, gpucore_dev, &gpucore_cooling_ops);
|
||||
if (!cool_dev) {
|
||||
release_idr(&gpucore_idr, gpucore_dev->id);
|
||||
kfree(gpucore_dev);
|
||||
return -EINVAL;
|
||||
}
|
||||
gpucore_dev->cool_dev = cool_dev;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpucore_cooling_register);
|
||||
|
||||
/**
|
||||
* gpucore_cooling_unregister - function to remove gpucore cooling device.
|
||||
* @cdev: thermal cooling device pointer.
|
||||
*
|
||||
* This interface function unregisters the "thermal-gpucore-%x" cooling device.
|
||||
*/
|
||||
void gpucore_cooling_unregister(struct thermal_cooling_device *cdev)
|
||||
{
|
||||
struct gpucore_cooling_device *gpucore_dev;
|
||||
|
||||
if (!cdev)
|
||||
return;
|
||||
|
||||
gpucore_dev = cdev->devdata;
|
||||
|
||||
thermal_cooling_device_unregister(gpucore_dev->cool_dev);
|
||||
release_idr(&gpucore_idr, gpucore_dev->id);
|
||||
kfree(gpucore_dev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpucore_cooling_unregister);
|
||||
@@ -278,11 +278,28 @@ static int of_thermal_set_mode(struct thermal_zone_device *tz,
|
||||
|
||||
mutex_lock(&tz->lock);
|
||||
|
||||
#ifdef CONFIG_AMLOGIC_TEMP_SENSOR
|
||||
/* passive_delay should be cleared if disabled */
|
||||
if (mode == THERMAL_DEVICE_ENABLED) {
|
||||
tz->polling_delay = data->polling_delay;
|
||||
tz->passive_delay = data->passive_delay;
|
||||
} else {
|
||||
tz->polling_delay = 0;
|
||||
tz->passive_delay = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* give opportunity that theraml device can
|
||||
* do something when mode change
|
||||
*/
|
||||
if (data->ops && data->ops->set_mode)
|
||||
data->ops->set_mode(tz, mode);
|
||||
#else
|
||||
if (mode == THERMAL_DEVICE_ENABLED)
|
||||
tz->polling_delay = data->polling_delay;
|
||||
else
|
||||
tz->polling_delay = 0;
|
||||
|
||||
#endif
|
||||
mutex_unlock(&tz->lock);
|
||||
|
||||
data->mode = mode;
|
||||
@@ -381,6 +398,23 @@ static int of_thermal_get_crit_temp(struct thermal_zone_device *tz,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_AMLOGIC_TEMP_SENSOR
|
||||
static int of_thermal_notify(struct thermal_zone_device *tz, int trip,
|
||||
enum thermal_trip_type type)
|
||||
{
|
||||
struct thermal_instance *instance;
|
||||
struct thermal_cooling_device *cdev;
|
||||
int ret = 0;
|
||||
|
||||
list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
|
||||
cdev = instance->cdev;
|
||||
if (cdev->ops && cdev->ops->notify_state)
|
||||
ret += cdev->ops->notify_state(cdev, tz, type);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct thermal_zone_device_ops of_thermal_ops = {
|
||||
.get_mode = of_thermal_get_mode,
|
||||
.set_mode = of_thermal_set_mode,
|
||||
@@ -394,6 +428,9 @@ static struct thermal_zone_device_ops of_thermal_ops = {
|
||||
|
||||
.bind = of_thermal_bind,
|
||||
.unbind = of_thermal_unbind,
|
||||
#ifdef CONFIG_AMLOGIC_TEMP_SENSOR
|
||||
.notify = of_thermal_notify,
|
||||
#endif
|
||||
};
|
||||
|
||||
/*** sensor API ***/
|
||||
@@ -973,6 +1010,9 @@ int __init of_parse_thermal_zones(void)
|
||||
for_each_available_child_of_node(np, child) {
|
||||
struct thermal_zone_device *zone;
|
||||
struct thermal_zone_params *tzp;
|
||||
#ifdef CONFIG_AMLOGIC_TEMP_SENSOR
|
||||
const char *str;
|
||||
#endif
|
||||
int i, mask = 0;
|
||||
u32 prop;
|
||||
|
||||
@@ -1000,6 +1040,11 @@ int __init of_parse_thermal_zones(void)
|
||||
if (!of_property_read_u32(child, "sustainable-power", &prop))
|
||||
tzp->sustainable_power = prop;
|
||||
|
||||
#ifdef CONFIG_AMLOGIC_TEMP_SENSOR
|
||||
if (!of_property_read_string(child, "policy", &str))
|
||||
strncpy(tzp->governor_name, str, THERMAL_NAME_LENGTH);
|
||||
#endif
|
||||
|
||||
for (i = 0; i < tz->ntrips; i++)
|
||||
mask |= 1 << i;
|
||||
|
||||
|
||||
@@ -271,6 +271,33 @@ struct thermal_instance *get_thermal_instance(struct thermal_zone_device *tz,
|
||||
}
|
||||
EXPORT_SYMBOL(get_thermal_instance);
|
||||
|
||||
#ifdef CONFIG_AMLOGIC_TEMP_SENSOR
|
||||
void thermal_set_upper(struct thermal_zone_device *tz,
|
||||
struct thermal_cooling_device *cdev,
|
||||
int trip, unsigned long upper)
|
||||
{
|
||||
struct thermal_instance *ins;
|
||||
|
||||
ins = get_thermal_instance(tz, cdev, trip);
|
||||
if (ins != NULL)
|
||||
ins->upper = upper;
|
||||
}
|
||||
EXPORT_SYMBOL(thermal_set_upper);
|
||||
|
||||
unsigned long thermal_get_upper(struct thermal_zone_device *tz,
|
||||
struct thermal_cooling_device *cdev, int trip)
|
||||
{
|
||||
struct thermal_instance *ins;
|
||||
|
||||
ins = get_thermal_instance(tz, cdev, trip);
|
||||
if (ins != NULL)
|
||||
return ins->upper;
|
||||
|
||||
return (-1UL);
|
||||
}
|
||||
EXPORT_SYMBOL(thermal_get_upper);
|
||||
#endif
|
||||
|
||||
static void print_bind_err_msg(struct thermal_zone_device *tz,
|
||||
struct thermal_cooling_device *cdev, int ret)
|
||||
{
|
||||
@@ -426,11 +453,64 @@ static void handle_non_critical_trips(struct thermal_zone_device *tz,
|
||||
def_governor->throttle(tz, trip);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_AMLOGIC_TEMP_SENSOR
|
||||
static bool can_notify(struct thermal_zone_device *tz,
|
||||
int trip, enum thermal_trip_type trip_type,
|
||||
long trip_temp)
|
||||
{
|
||||
unsigned int hyst = 0;
|
||||
|
||||
if (trip_type != THERMAL_TRIP_HOT)
|
||||
return false;
|
||||
tz->ops->get_trip_hyst(tz, trip, &hyst);
|
||||
|
||||
if (tz->temperature < 0)
|
||||
return false;
|
||||
|
||||
/* increase each hyst step */
|
||||
if (tz->temperature >= (trip_temp + tz->hot_step * hyst)) {
|
||||
tz->hot_step++;
|
||||
dev_info(&tz->device,
|
||||
"temp:%d increase, hyst:%d, trip_temp:%ld, hot:%x\n",
|
||||
tz->temperature, hyst, trip_temp, tz->hot_step);
|
||||
return true;
|
||||
}
|
||||
/* reserve a step gap */
|
||||
if (tz->temperature <= (trip_temp + (tz->hot_step - 2) * hyst) &&
|
||||
tz->hot_step) {
|
||||
tz->hot_step--;
|
||||
dev_info(&tz->device,
|
||||
"temp:%d decrease, hyst:%d, trip_temp:%ld, hot:%x\n",
|
||||
tz->temperature, hyst, trip_temp, tz->hot_step);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void handle_critical_trips(struct thermal_zone_device *tz,
|
||||
int trip, enum thermal_trip_type trip_type)
|
||||
{
|
||||
int trip_temp;
|
||||
|
||||
#ifdef CONFIG_AMLOGIC_TEMP_SENSOR
|
||||
tz->ops->get_trip_temp(tz, trip, &trip_temp);
|
||||
|
||||
trace_thermal_zone_trip(tz, trip, trip_type);
|
||||
|
||||
if (can_notify(tz, trip, trip_type, trip_temp)) {
|
||||
if (tz->ops->notify)
|
||||
tz->ops->notify(tz, trip, trip_type);
|
||||
}
|
||||
|
||||
if ((trip_type == THERMAL_TRIP_CRITICAL) &&
|
||||
(tz->temperature >= trip_temp)) {
|
||||
dev_emerg(&tz->device,
|
||||
"critical temperature reached(%d C),shutting down\n",
|
||||
tz->temperature / 1000);
|
||||
orderly_poweroff(true);
|
||||
}
|
||||
#else
|
||||
tz->ops->get_trip_temp(tz, trip, &trip_temp);
|
||||
|
||||
/* If we have not crossed the trip_temp, we do not care. */
|
||||
@@ -448,6 +528,7 @@ static void handle_critical_trips(struct thermal_zone_device *tz,
|
||||
tz->temperature / 1000);
|
||||
orderly_poweroff(true);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void handle_thermal_trip(struct thermal_zone_device *tz, int trip)
|
||||
@@ -1150,6 +1231,10 @@ int power_actor_set_power(struct thermal_cooling_device *cdev,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
#ifdef CONFIG_AMLOGIC_TEMP_SENSOR
|
||||
if (state > instance->upper)
|
||||
state = instance->upper;
|
||||
#endif
|
||||
instance->target = state;
|
||||
mutex_lock(&cdev->lock);
|
||||
cdev->updated = false;
|
||||
|
||||
24
include/linux/amlogic/aml_thermal_hw.h
Normal file
24
include/linux/amlogic/aml_thermal_hw.h
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* include/linux/amlogic/aml_thermal_hw.h
|
||||
*
|
||||
* Copyright (C) 2016 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ARCH__THERMAL_H__
|
||||
#define ARCH__THERMAL_H__
|
||||
struct thermal_cooling_device;
|
||||
extern int thermal_firmware_init(void);
|
||||
extern int get_cpu_temp(void);
|
||||
extern int aml_thermal_min_update(struct thermal_cooling_device *cdev);
|
||||
#endif
|
||||
62
include/linux/amlogic/cpucore_cooling.h
Normal file
62
include/linux/amlogic/cpucore_cooling.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* include/linux/amlogic/cpucore_cooling.h
|
||||
*
|
||||
* Copyright (C) 2016 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __CPUCORE_COOLING_H__
|
||||
#define __CPUCORE_COOLING_H__
|
||||
|
||||
#include <linux/thermal.h>
|
||||
#include <linux/cpumask.h>
|
||||
struct cpucore_cooling_device {
|
||||
int id;
|
||||
struct thermal_cooling_device *cool_dev;
|
||||
unsigned int cpucore_state;
|
||||
unsigned int cpucore_val;
|
||||
struct list_head node;
|
||||
int max_cpu_core_num;
|
||||
int cluster_id;
|
||||
int stop_flag;
|
||||
};
|
||||
#define CPU_STOP 0x80000000
|
||||
#ifdef CONFIG_AMLOGIC_CPUCORE_THERMAL
|
||||
|
||||
/**
|
||||
* cpucore_cooling_register - function to create cpucore cooling device.
|
||||
* @clip_cpus: cpumask of cpus where the frequency constraints will happen
|
||||
*/
|
||||
struct thermal_cooling_device *cpucore_cooling_register(struct device_node *,
|
||||
int);
|
||||
|
||||
/**
|
||||
* cpucore_cooling_unregister - function to remove cpucore cooling device.
|
||||
* @cdev: thermal cooling device pointer.
|
||||
*/
|
||||
void cpucore_cooling_unregister(struct thermal_cooling_device *cdev);
|
||||
|
||||
|
||||
#else
|
||||
static inline struct thermal_cooling_device *
|
||||
cpucore_cooling_register(struct device_node *np)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
static inline
|
||||
void cpucore_cooling_unregister(struct thermal_cooling_device *cdev)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __CPU_COOLING_H__ */
|
||||
106
include/linux/amlogic/gpu_cooling.h
Normal file
106
include/linux/amlogic/gpu_cooling.h
Normal file
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* include/linux/amlogic/gpu_cooling.h
|
||||
*
|
||||
* Copyright (C) 2016 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __gpu_COOLING_H__
|
||||
#define __gpu_COOLING_H__
|
||||
|
||||
#include <linux/thermal.h>
|
||||
#include <linux/cpumask.h>
|
||||
|
||||
#ifdef CONFIG_AMLOGIC_GPU_THERMAL
|
||||
|
||||
/**
|
||||
* gpufreq_cooling_register - function to create gpufreq cooling device.
|
||||
* @clip_gpus: gpumask of gpus where the frequency constraints will happen
|
||||
*/
|
||||
/**
|
||||
* struct gpufreq_cooling_device - data for cooling device with gpufreq
|
||||
* @id: unique integer value corresponding to each gpufreq_cooling_device
|
||||
* registered.
|
||||
* @cool_dev: thermal_cooling_device pointer to keep track of the
|
||||
* registered cooling device.
|
||||
* @gpufreq_state: integer value representing the current state of gpufreq
|
||||
* cooling devices.
|
||||
* @gpufreq_val: integer value representing the absolute value of the clipped
|
||||
* frequency.
|
||||
* @allowed_gpus: all the gpus involved for this gpufreq_cooling_device.
|
||||
*
|
||||
* This structure is required for keeping information of each
|
||||
* gpufreq_cooling_device registered. In order to prevent corruption of this a
|
||||
* mutex lock cooling_gpufreq_lock is used.
|
||||
*/
|
||||
struct gpufreq_cooling_device {
|
||||
int id;
|
||||
struct thermal_cooling_device *cool_dev;
|
||||
unsigned int gpufreq_state;
|
||||
unsigned int gpufreq_val;
|
||||
int (*get_gpu_freq_level)(int freq);
|
||||
unsigned int (*get_gpu_max_level)(void);
|
||||
unsigned int (*get_gpu_current_max_level)(void);
|
||||
void (*set_gpu_freq_idx)(unsigned int idx);
|
||||
unsigned int (*get_online_pp)(void);
|
||||
unsigned int (*get_gpu_loading)(void);
|
||||
unsigned int (*get_gpu_freq)(unsigned int idx);
|
||||
unsigned int *gpu_freq_tbl;
|
||||
unsigned int dyn_coeff;
|
||||
int max_pp;
|
||||
struct device_node *np;
|
||||
};
|
||||
int gpufreq_cooling_register(struct gpufreq_cooling_device *gpufreq_dev);
|
||||
struct gpufreq_cooling_device *gpufreq_cooling_alloc(void);
|
||||
|
||||
/**
|
||||
* gpufreq_cooling_unregister - function to remove gpufreq cooling device.
|
||||
* @cdev: thermal cooling device pointer.
|
||||
*/
|
||||
void gpufreq_cooling_unregister(struct thermal_cooling_device *cdev);
|
||||
int register_gpu_freq_info(unsigned int (*fun)(void));
|
||||
|
||||
unsigned long gpufreq_cooling_get_level(unsigned int gpu, unsigned int freq);
|
||||
void save_gpu_cool_para(int i, struct device_node *d, int j);
|
||||
#else
|
||||
static inline void save_gpu_cool_para(unsigned int coef,
|
||||
struct device_node *n, int pp)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
struct gpufreq_cooling_device *gpufreq_cooling_alloc(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int gpufreq_cooling_register(struct gpufreq_cooling_device *gpufreq_dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline
|
||||
void gpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
|
||||
{
|
||||
}
|
||||
static inline
|
||||
unsigned long gpufreq_cooling_get_level(unsigned int gpu, unsigned int freq)
|
||||
{
|
||||
return THERMAL_CSTATE_INVALID;
|
||||
}
|
||||
static inline int register_gpu_freq_info(unsigned int (*fun)(void))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __GPU_COOLING_H__ */
|
||||
69
include/linux/amlogic/gpucore_cooling.h
Normal file
69
include/linux/amlogic/gpucore_cooling.h
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* include/linux/amlogic/gpucore_cooling.h
|
||||
*
|
||||
* Copyright (C) 2016 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __GPUCORE_COOLING_H__
|
||||
#define __GPUCORE_COOLING_H__
|
||||
|
||||
#include <linux/thermal.h>
|
||||
#include <linux/cpumask.h>
|
||||
struct gpucore_cooling_device {
|
||||
int id;
|
||||
struct thermal_cooling_device *cool_dev;
|
||||
unsigned int gpucore_state;
|
||||
unsigned int gpucore_val;
|
||||
int max_gpu_core_num;
|
||||
unsigned int (*set_max_pp_num)(unsigned int pp);
|
||||
struct device_node *np;
|
||||
int stop_flag;
|
||||
};
|
||||
#define GPU_STOP 0x80000000
|
||||
|
||||
#ifdef CONFIG_AMLOGIC_GPUCORE_THERMAL
|
||||
|
||||
/**
|
||||
* gpucore_cooling_register - function to create gpucore cooling device.
|
||||
* @clip_cpus: cpumask of cpus where the frequency constraints will happen
|
||||
*/
|
||||
int gpucore_cooling_register(struct gpucore_cooling_device *gcd);
|
||||
|
||||
/**
|
||||
* gpucore_cooling_unregister - function to remove gpucore cooling device.
|
||||
* @cdev: thermal cooling device pointer.
|
||||
*/
|
||||
void gpucore_cooling_unregister(struct thermal_cooling_device *cdev);
|
||||
struct gpucore_cooling_device *gpucore_cooling_alloc(void);
|
||||
void save_gpucore_thermal_para(struct device_node *node);
|
||||
|
||||
#else
|
||||
inline struct gpucore_cooling_device *gpucore_cooling_alloc(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
inline int gpucore_cooling_register(struct gpucore_cooling_device *gcd)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
inline void gpucore_cooling_unregister(struct thermal_cooling_device *cdev)
|
||||
{
|
||||
}
|
||||
inline void save_gpucore_thermal_para(struct device_node *n)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __CPU_COOLING_H__ */
|
||||
@@ -138,6 +138,11 @@ struct thermal_cooling_device_ops {
|
||||
struct thermal_zone_device *, unsigned long, u32 *);
|
||||
int (*power2state)(struct thermal_cooling_device *,
|
||||
struct thermal_zone_device *, u32, unsigned long *);
|
||||
#ifdef CONFIG_AMLOGIC_TEMP_SENSOR
|
||||
int (*notify_state)(struct thermal_cooling_device *,
|
||||
struct thermal_zone_device *,
|
||||
enum thermal_trip_type);
|
||||
#endif
|
||||
};
|
||||
|
||||
struct thermal_cooling_device {
|
||||
@@ -216,6 +221,9 @@ struct thermal_zone_device {
|
||||
int last_temperature;
|
||||
int emul_temperature;
|
||||
int passive;
|
||||
#ifdef CONFIG_AMLOGIC_TEMP_SENSOR
|
||||
int hot_step;
|
||||
#endif
|
||||
int prev_low_trip;
|
||||
int prev_high_trip;
|
||||
unsigned int forced_passive;
|
||||
@@ -365,6 +373,9 @@ struct thermal_zone_of_device_ops {
|
||||
int (*get_temp)(void *, int *);
|
||||
int (*get_trend)(void *, int, enum thermal_trend *);
|
||||
int (*set_trips)(void *, int, int);
|
||||
#ifdef CONFIG_AMLOGIC_TEMP_SENSOR
|
||||
int (*set_mode)(struct thermal_zone_device*, enum thermal_device_mode);
|
||||
#endif
|
||||
int (*set_emul_temp)(void *, int);
|
||||
int (*set_trip_temp)(void *, int, int);
|
||||
};
|
||||
@@ -469,6 +480,13 @@ struct thermal_instance *get_thermal_instance(struct thermal_zone_device *,
|
||||
struct thermal_cooling_device *, int);
|
||||
void thermal_cdev_update(struct thermal_cooling_device *);
|
||||
void thermal_notify_framework(struct thermal_zone_device *, int);
|
||||
#ifdef CONFIG_AMLOGIC_TEMP_SENSOR
|
||||
void thermal_set_upper(struct thermal_zone_device *tzd,
|
||||
struct thermal_cooling_device *tcd,
|
||||
int trip, unsigned long upper);
|
||||
unsigned long thermal_get_upper(struct thermal_zone_device *tzd,
|
||||
struct thermal_cooling_device *tcd, int trip);
|
||||
#endif
|
||||
#else
|
||||
static inline bool cdev_is_power_actor(struct thermal_cooling_device *cdev)
|
||||
{ return false; }
|
||||
@@ -540,6 +558,15 @@ static inline void thermal_cdev_update(struct thermal_cooling_device *cdev)
|
||||
static inline void thermal_notify_framework(struct thermal_zone_device *tz,
|
||||
int trip)
|
||||
{ }
|
||||
#ifdef CONFIG_AMLOGIC_TEMP_SENSOR
|
||||
static inline void thermal_set_upper(struct thermal_zone_device *tz,
|
||||
struct thermal_cooling_device *cdev,
|
||||
int trip, unsigned long upper)
|
||||
{ }
|
||||
static inline unsigned long thermal_get_upper(struct thermal_zone_device *tz,
|
||||
struct thermal_cooling_device *cdev, int trip)
|
||||
{ return -1UL; }
|
||||
#endif
|
||||
#endif /* CONFIG_THERMAL */
|
||||
|
||||
#if defined(CONFIG_NET) && IS_ENABLED(CONFIG_THERMAL)
|
||||
|
||||
Reference in New Issue
Block a user