blob: 3ec131cbc6e10993206928b2dd8953cb4d34cf2f [file] [log] [blame]
Peng Fan8a021112019-05-05 13:23:54 +00001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright 2019 NXP
4 */
5
6#include <config.h>
7#include <common.h>
8#include <dm.h>
9#include <errno.h>
Simon Glass0f2af882020-05-10 11:40:05 -060010#include <log.h>
Peng Fan8a021112019-05-05 13:23:54 +000011#include <thermal.h>
Simon Glass3ba929a2020-10-30 21:38:53 -060012#include <asm/global_data.h>
Peng Fan8a021112019-05-05 13:23:54 +000013#include <dm/device-internal.h>
14#include <dm/device.h>
Peng Fan2e0644a2023-04-28 12:08:09 +080015#include <firmware/imx/sci/sci.h>
Simon Glassdbd79542020-05-10 11:40:11 -060016#include <linux/delay.h>
Simon Glass2dc9c342020-05-10 11:40:01 -060017#include <linux/libfdt.h>
Peng Fan8a021112019-05-05 13:23:54 +000018
19DECLARE_GLOBAL_DATA_PTR;
20
21struct imx_sc_thermal_plat {
22 int critical;
23 int alert;
24 int polling_delay;
25 int id;
26 bool zone_node;
27};
28
29static int read_temperature(struct udevice *dev, int *temp)
30{
31 s16 celsius;
32 s8 tenths;
33 int ret;
34
35 sc_rsrc_t *sensor_rsrc = (sc_rsrc_t *)dev_get_driver_data(dev);
36
Simon Glassfa20e932020-12-03 16:55:20 -070037 struct imx_sc_thermal_plat *pdata = dev_get_plat(dev);
Peng Fan8a021112019-05-05 13:23:54 +000038
39 if (!temp)
40 return -EINVAL;
41
42 ret = sc_misc_get_temp(-1, sensor_rsrc[pdata->id], SC_C_TEMP,
43 &celsius, &tenths);
44 if (ret) {
45 printf("Error: get temperature failed! (error = %d)\n", ret);
46 return ret;
47 }
48
49 *temp = celsius * 1000 + tenths * 100;
50
51 return 0;
52}
53
54int imx_sc_thermal_get_temp(struct udevice *dev, int *temp)
55{
Simon Glassfa20e932020-12-03 16:55:20 -070056 struct imx_sc_thermal_plat *pdata = dev_get_plat(dev);
Peng Fan8a021112019-05-05 13:23:54 +000057 int cpu_temp = 0;
58 int ret;
59
60 ret = read_temperature(dev, &cpu_temp);
61 if (ret)
62 return ret;
63
64 while (cpu_temp >= pdata->alert) {
Anatolij Gustschinf2aed092020-05-20 10:21:53 +020065 printf("CPU Temperature (%dC) beyond alert (%dC), close to critical (%dC)",
Peng Fan8a021112019-05-05 13:23:54 +000066 cpu_temp, pdata->alert, pdata->critical);
67 puts(" waiting...\n");
68 mdelay(pdata->polling_delay);
69 ret = read_temperature(dev, &cpu_temp);
70 if (ret)
71 return ret;
Anatolij Gustschinf2aed092020-05-20 10:21:53 +020072 if (cpu_temp >= pdata->alert && !pdata->alert)
73 break;
Peng Fan8a021112019-05-05 13:23:54 +000074 }
75
76 *temp = cpu_temp / 1000;
77
78 return 0;
79}
80
81static const struct dm_thermal_ops imx_sc_thermal_ops = {
82 .get_temp = imx_sc_thermal_get_temp,
83};
84
85static int imx_sc_thermal_probe(struct udevice *dev)
86{
87 debug("%s dev name %s\n", __func__, dev->name);
88 return 0;
89}
90
91static int imx_sc_thermal_bind(struct udevice *dev)
92{
Simon Glassfa20e932020-12-03 16:55:20 -070093 struct imx_sc_thermal_plat *pdata = dev_get_plat(dev);
Peng Fan8a021112019-05-05 13:23:54 +000094 int reg, ret;
95 int offset;
96 const char *name;
97 const void *prop;
98
99 debug("%s dev name %s\n", __func__, dev->name);
100
101 prop = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), "compatible",
102 NULL);
103 if (!prop)
104 return 0;
105
106 pdata->zone_node = 1;
107
108 reg = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), "tsens-num", 0);
109 if (reg == 0) {
110 printf("%s: no temp sensor number provided!\n", __func__);
111 return -EINVAL;
112 }
113
114 offset = fdt_subnode_offset(gd->fdt_blob, 0, "thermal-zones");
115 fdt_for_each_subnode(offset, gd->fdt_blob, offset) {
116 /* Bind the subnode to this driver */
117 name = fdt_get_name(gd->fdt_blob, offset, NULL);
118
119 ret = device_bind_with_driver_data(dev, dev->driver, name,
120 dev->driver_data,
121 offset_to_ofnode(offset),
122 NULL);
123 if (ret)
124 printf("Error binding driver '%s': %d\n",
125 dev->driver->name, ret);
126 }
127 return 0;
128}
129
Simon Glassaad29ae2020-12-03 16:55:21 -0700130static int imx_sc_thermal_of_to_plat(struct udevice *dev)
Peng Fan8a021112019-05-05 13:23:54 +0000131{
Simon Glassfa20e932020-12-03 16:55:20 -0700132 struct imx_sc_thermal_plat *pdata = dev_get_plat(dev);
Peng Fan8a021112019-05-05 13:23:54 +0000133 struct fdtdec_phandle_args args;
134 const char *type;
135 int ret;
136 int trips_np;
137
138 debug("%s dev name %s\n", __func__, dev->name);
139
140 if (pdata->zone_node)
141 return 0;
142
143 ret = fdtdec_parse_phandle_with_args(gd->fdt_blob, dev_of_offset(dev),
144 "thermal-sensors",
145 "#thermal-sensor-cells",
146 0, 0, &args);
147 if (ret)
148 return ret;
149
150 if (args.node != dev_of_offset(dev->parent))
151 return -EFAULT;
152
153 if (args.args_count >= 1)
154 pdata->id = args.args[0];
155 else
156 pdata->id = 0;
157
158 debug("args.args_count %d, id %d\n", args.args_count, pdata->id);
159
160 pdata->polling_delay = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
161 "polling-delay", 1000);
162
163 trips_np = fdt_subnode_offset(gd->fdt_blob, dev_of_offset(dev),
164 "trips");
165 fdt_for_each_subnode(trips_np, gd->fdt_blob, trips_np) {
166 type = fdt_getprop(gd->fdt_blob, trips_np, "type", NULL);
167 if (type) {
168 if (strcmp(type, "critical") == 0) {
169 pdata->critical = fdtdec_get_int(gd->fdt_blob,
170 trips_np,
171 "temperature",
172 85);
173 } else if (strcmp(type, "passive") == 0) {
174 pdata->alert = fdtdec_get_int(gd->fdt_blob,
175 trips_np,
176 "temperature",
177 80);
178 }
179 }
180 }
181
182 debug("id %d polling_delay %d, critical %d, alert %d\n", pdata->id,
183 pdata->polling_delay, pdata->critical, pdata->alert);
184
185 return 0;
186}
187
Ye Li4489a2e2020-05-03 22:19:45 +0800188static const sc_rsrc_t imx8qm_sensor_rsrc[] = {
189 SC_R_A53, SC_R_A72, SC_R_GPU_0_PID0, SC_R_GPU_1_PID0,
190 SC_R_DRC_0, SC_R_DRC_1, SC_R_VPU_PID0, SC_R_PMIC_0,
191 SC_R_PMIC_1, SC_R_PMIC_2,
192};
193
Peng Fan8a021112019-05-05 13:23:54 +0000194static const sc_rsrc_t imx8qxp_sensor_rsrc[] = {
195 SC_R_SYSTEM, SC_R_DRC_0, SC_R_PMIC_0,
196 SC_R_PMIC_1, SC_R_PMIC_2,
197};
198
199static const struct udevice_id imx_sc_thermal_ids[] = {
Ye Li4489a2e2020-05-03 22:19:45 +0800200 { .compatible = "nxp,imx8qm-sc-tsens", .data =
201 (ulong)&imx8qm_sensor_rsrc, },
Peng Fan8a021112019-05-05 13:23:54 +0000202 { .compatible = "nxp,imx8qxp-sc-tsens", .data =
203 (ulong)&imx8qxp_sensor_rsrc, },
204 { }
205};
206
207U_BOOT_DRIVER(imx_sc_thermal) = {
208 .name = "imx_sc_thermal",
209 .id = UCLASS_THERMAL,
210 .ops = &imx_sc_thermal_ops,
211 .of_match = imx_sc_thermal_ids,
212 .bind = imx_sc_thermal_bind,
213 .probe = imx_sc_thermal_probe,
Simon Glassaad29ae2020-12-03 16:55:21 -0700214 .of_to_plat = imx_sc_thermal_of_to_plat,
Simon Glass71fa5b42020-12-03 16:55:18 -0700215 .plat_auto = sizeof(struct imx_sc_thermal_plat),
Peng Fan8a021112019-05-05 13:23:54 +0000216 .flags = DM_FLAG_PRE_RELOC,
217};