]>
Commit | Line | Data |
---|---|---|
5ef5b6d4 PF |
1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* | |
3 | * Copyright 2019 NXP | |
4 | */ | |
5 | ||
6 | #include <config.h> | |
d678a59d | 7 | #include <common.h> |
5ef5b6d4 PF |
8 | #include <dm.h> |
9 | #include <errno.h> | |
f7ae49fc | 10 | #include <log.h> |
5ef5b6d4 | 11 | #include <thermal.h> |
401d1c4f | 12 | #include <asm/global_data.h> |
5ef5b6d4 PF |
13 | #include <dm/device-internal.h> |
14 | #include <dm/device.h> | |
99ac6c76 | 15 | #include <firmware/imx/sci/sci.h> |
c05ed00a | 16 | #include <linux/delay.h> |
4d72caa5 | 17 | #include <linux/libfdt.h> |
5ef5b6d4 PF |
18 | |
19 | DECLARE_GLOBAL_DATA_PTR; | |
20 | ||
21 | struct imx_sc_thermal_plat { | |
22 | int critical; | |
23 | int alert; | |
24 | int polling_delay; | |
25 | int id; | |
26 | bool zone_node; | |
27 | }; | |
28 | ||
29 | static 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 | ||
c69cda25 | 37 | struct imx_sc_thermal_plat *pdata = dev_get_plat(dev); |
5ef5b6d4 PF |
38 | |
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 | ||
54 | int imx_sc_thermal_get_temp(struct udevice *dev, int *temp) | |
55 | { | |
c69cda25 | 56 | struct imx_sc_thermal_plat *pdata = dev_get_plat(dev); |
5ef5b6d4 PF |
57 | 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) { | |
4e7413a9 | 65 | printf("CPU Temperature (%dC) beyond alert (%dC), close to critical (%dC)", |
5ef5b6d4 PF |
66 | 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; | |
4e7413a9 AG |
72 | if (cpu_temp >= pdata->alert && !pdata->alert) |
73 | break; | |
5ef5b6d4 PF |
74 | } |
75 | ||
76 | *temp = cpu_temp / 1000; | |
77 | ||
78 | return 0; | |
79 | } | |
80 | ||
81 | static const struct dm_thermal_ops imx_sc_thermal_ops = { | |
82 | .get_temp = imx_sc_thermal_get_temp, | |
83 | }; | |
84 | ||
85 | static int imx_sc_thermal_probe(struct udevice *dev) | |
86 | { | |
87 | debug("%s dev name %s\n", __func__, dev->name); | |
88 | return 0; | |
89 | } | |
90 | ||
91 | static int imx_sc_thermal_bind(struct udevice *dev) | |
92 | { | |
c69cda25 | 93 | struct imx_sc_thermal_plat *pdata = dev_get_plat(dev); |
5ef5b6d4 PF |
94 | 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 | ||
d1998a9f | 130 | static int imx_sc_thermal_of_to_plat(struct udevice *dev) |
5ef5b6d4 | 131 | { |
c69cda25 | 132 | struct imx_sc_thermal_plat *pdata = dev_get_plat(dev); |
5ef5b6d4 PF |
133 | 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 | ||
6039d669 YL |
188 | static 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 | ||
5ef5b6d4 PF |
194 | static 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 | ||
199 | static const struct udevice_id imx_sc_thermal_ids[] = { | |
6039d669 YL |
200 | { .compatible = "nxp,imx8qm-sc-tsens", .data = |
201 | (ulong)&imx8qm_sensor_rsrc, }, | |
5ef5b6d4 PF |
202 | { .compatible = "nxp,imx8qxp-sc-tsens", .data = |
203 | (ulong)&imx8qxp_sensor_rsrc, }, | |
204 | { } | |
205 | }; | |
206 | ||
207 | U_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, | |
d1998a9f | 214 | .of_to_plat = imx_sc_thermal_of_to_plat, |
caa4daa2 | 215 | .plat_auto = sizeof(struct imx_sc_thermal_plat), |
5ef5b6d4 PF |
216 | .flags = DM_FLAG_PRE_RELOC, |
217 | }; |