1 // SPDX-License-Identifier: GPL-2.0-only
2 /* intel_pch_thermal.c - Intel PCH Thermal driver
4 * Copyright (c) 2015, Intel Corporation.
7 * Tushar Dave <tushar.n.dave@intel.com>
10 #include <linux/acpi.h>
11 #include <linux/delay.h>
12 #include <linux/module.h>
13 #include <linux/init.h>
14 #include <linux/pci.h>
16 #include <linux/suspend.h>
17 #include <linux/thermal.h>
18 #include <linux/types.h>
19 #include <linux/units.h>
21 /* Intel PCH thermal Device IDs */
22 #define PCH_THERMAL_DID_HSW_1 0x9C24 /* Haswell PCH */
23 #define PCH_THERMAL_DID_HSW_2 0x8C24 /* Haswell PCH */
24 #define PCH_THERMAL_DID_WPT 0x9CA4 /* Wildcat Point */
25 #define PCH_THERMAL_DID_SKL 0x9D31 /* Skylake PCH */
26 #define PCH_THERMAL_DID_SKL_H 0xA131 /* Skylake PCH 100 series */
27 #define PCH_THERMAL_DID_CNL 0x9Df9 /* CNL PCH */
28 #define PCH_THERMAL_DID_CNL_H 0xA379 /* CNL-H PCH */
29 #define PCH_THERMAL_DID_CNL_LP 0x02F9 /* CNL-LP PCH */
30 #define PCH_THERMAL_DID_CML_H 0X06F9 /* CML-H PCH */
31 #define PCH_THERMAL_DID_LWB 0xA1B1 /* Lewisburg PCH */
32 #define PCH_THERMAL_DID_WBG 0x8D24 /* Wellsburg PCH */
34 /* Wildcat Point-LP PCH Thermal registers */
35 #define WPT_TEMP 0x0000 /* Temperature */
36 #define WPT_TSC 0x04 /* Thermal Sensor Control */
37 #define WPT_TSS 0x06 /* Thermal Sensor Status */
38 #define WPT_TSEL 0x08 /* Thermal Sensor Enable and Lock */
39 #define WPT_TSREL 0x0A /* Thermal Sensor Report Enable and Lock */
40 #define WPT_TSMIC 0x0C /* Thermal Sensor SMI Control */
41 #define WPT_CTT 0x0010 /* Catastrophic Trip Point */
42 #define WPT_TSPM 0x001C /* Thermal Sensor Power Management */
43 #define WPT_TAHV 0x0014 /* Thermal Alert High Value */
44 #define WPT_TALV 0x0018 /* Thermal Alert Low Value */
45 #define WPT_TL 0x00000040 /* Throttle Value */
46 #define WPT_PHL 0x0060 /* PCH Hot Level */
47 #define WPT_PHLC 0x62 /* PHL Control */
48 #define WPT_TAS 0x80 /* Thermal Alert Status */
49 #define WPT_TSPIEN 0x82 /* PCI Interrupt Event Enables */
50 #define WPT_TSGPEN 0x84 /* General Purpose Event Enables */
52 /* Wildcat Point-LP PCH Thermal Register bit definitions */
53 #define WPT_TEMP_TSR 0x01ff /* Temp TS Reading */
54 #define WPT_TSC_CPDE 0x01 /* Catastrophic Power-Down Enable */
55 #define WPT_TSS_TSDSS 0x10 /* Thermal Sensor Dynamic Shutdown Status */
56 #define WPT_TSS_GPES 0x08 /* GPE status */
57 #define WPT_TSEL_ETS 0x01 /* Enable TS */
58 #define WPT_TSEL_PLDB 0x80 /* TSEL Policy Lock-Down Bit */
59 #define WPT_TL_TOL 0x000001FF /* T0 Level */
60 #define WPT_TL_T1L 0x1ff00000 /* T1 Level */
61 #define WPT_TL_TTEN 0x20000000 /* TT Enable */
63 /* Resolution of 1/2 degree C and an offset of -50C */
64 #define PCH_TEMP_OFFSET (-50)
65 #define GET_WPT_TEMP(x) ((x) * MILLIDEGREE_PER_DEGREE / 2 + WPT_TEMP_OFFSET)
66 #define WPT_TEMP_OFFSET (PCH_TEMP_OFFSET * MILLIDEGREE_PER_DEGREE)
67 #define GET_PCH_TEMP(x) (((x) / 2) + PCH_TEMP_OFFSET)
69 #define PCH_MAX_TRIPS 3 /* critical, hot, passive */
71 /* Amount of time for each cooling delay, 100ms by default for now */
72 static unsigned int delay_timeout
= 100;
73 module_param(delay_timeout
, int, 0644);
74 MODULE_PARM_DESC(delay_timeout
, "amount of time delay for each iteration.");
76 /* Number of iterations for cooling delay, 600 counts by default for now */
77 static unsigned int delay_cnt
= 600;
78 module_param(delay_cnt
, int, 0644);
79 MODULE_PARM_DESC(delay_cnt
, "total number of iterations for time delay.");
81 static char driver_name
[] = "Intel PCH thermal driver";
83 struct pch_thermal_device
{
84 void __iomem
*hw_base
;
86 struct thermal_zone_device
*tzd
;
92 * On some platforms, there is a companion ACPI device, which adds
93 * passive trip temperature using _PSV method. There is no specific
94 * passive temperature setting in MMIO interface of this PCI device.
96 static int pch_wpt_add_acpi_psv_trip(struct pch_thermal_device
*ptd
,
97 struct thermal_trip
*trip
)
99 struct acpi_device
*adev
;
102 adev
= ACPI_COMPANION(&ptd
->pdev
->dev
);
106 if (thermal_acpi_passive_trip_temp(adev
, &temp
) || temp
<= 0)
109 trip
->type
= THERMAL_TRIP_PASSIVE
;
110 trip
->temperature
= temp
;
114 static int pch_wpt_add_acpi_psv_trip(struct pch_thermal_device
*ptd
,
115 struct thermal_trip
*trip
)
121 static int pch_thermal_get_temp(struct thermal_zone_device
*tzd
, int *temp
)
123 struct pch_thermal_device
*ptd
= thermal_zone_device_priv(tzd
);
125 *temp
= GET_WPT_TEMP(WPT_TEMP_TSR
& readw(ptd
->hw_base
+ WPT_TEMP
));
129 static void pch_critical(struct thermal_zone_device
*tzd
)
131 dev_dbg(thermal_zone_device(tzd
), "%s: critical temperature reached\n",
132 thermal_zone_device_type(tzd
));
135 static const struct thermal_zone_device_ops tzd_ops
= {
136 .get_temp
= pch_thermal_get_temp
,
137 .critical
= pch_critical
,
150 static const char *board_names
[] = {
151 [PCH_BOARD_HSW
] = "pch_haswell",
152 [PCH_BOARD_WPT
] = "pch_wildcat_point",
153 [PCH_BOARD_SKL
] = "pch_skylake",
154 [PCH_BOARD_CNL
] = "pch_cannonlake",
155 [PCH_BOARD_CML
] = "pch_cometlake",
156 [PCH_BOARD_LWB
] = "pch_lewisburg",
157 [PCH_BOARD_WBG
] = "pch_wellsburg",
160 static int intel_pch_thermal_probe(struct pci_dev
*pdev
,
161 const struct pci_device_id
*id
)
163 struct thermal_trip ptd_trips
[PCH_MAX_TRIPS
] = { 0 };
164 enum pch_board_ids board_id
= id
->driver_data
;
165 struct pch_thermal_device
*ptd
;
171 ptd
= devm_kzalloc(&pdev
->dev
, sizeof(*ptd
), GFP_KERNEL
);
175 pci_set_drvdata(pdev
, ptd
);
178 err
= pci_enable_device(pdev
);
180 dev_err(&pdev
->dev
, "failed to enable pci device\n");
184 err
= pci_request_regions(pdev
, driver_name
);
186 dev_err(&pdev
->dev
, "failed to request pci region\n");
190 ptd
->hw_base
= pci_ioremap_bar(pdev
, 0);
193 dev_err(&pdev
->dev
, "failed to map mem base\n");
197 /* Check if BIOS has already enabled thermal sensor */
198 if (WPT_TSEL_ETS
& readb(ptd
->hw_base
+ WPT_TSEL
)) {
199 ptd
->bios_enabled
= true;
203 tsel
= readb(ptd
->hw_base
+ WPT_TSEL
);
205 * When TSEL's Policy Lock-Down bit is 1, TSEL become RO.
206 * If so, thermal sensor cannot enable. Bail out.
208 if (tsel
& WPT_TSEL_PLDB
) {
209 dev_err(&ptd
->pdev
->dev
, "Sensor can't be enabled\n");
214 writeb(tsel
|WPT_TSEL_ETS
, ptd
->hw_base
+ WPT_TSEL
);
215 if (!(WPT_TSEL_ETS
& readb(ptd
->hw_base
+ WPT_TSEL
))) {
216 dev_err(&ptd
->pdev
->dev
, "Sensor can't be enabled\n");
222 trip_temp
= readw(ptd
->hw_base
+ WPT_CTT
);
225 ptd_trips
[nr_trips
].temperature
= GET_WPT_TEMP(trip_temp
);
226 ptd_trips
[nr_trips
++].type
= THERMAL_TRIP_CRITICAL
;
229 trip_temp
= readw(ptd
->hw_base
+ WPT_PHL
);
232 ptd_trips
[nr_trips
].temperature
= GET_WPT_TEMP(trip_temp
);
233 ptd_trips
[nr_trips
++].type
= THERMAL_TRIP_HOT
;
236 nr_trips
+= pch_wpt_add_acpi_psv_trip(ptd
, &ptd_trips
[nr_trips
]);
238 ptd
->tzd
= thermal_zone_device_register_with_trips(board_names
[board_id
],
242 if (IS_ERR(ptd
->tzd
)) {
243 dev_err(&pdev
->dev
, "Failed to register thermal zone %s\n",
244 board_names
[board_id
]);
245 err
= PTR_ERR(ptd
->tzd
);
248 err
= thermal_zone_device_enable(ptd
->tzd
);
255 thermal_zone_device_unregister(ptd
->tzd
);
257 iounmap(ptd
->hw_base
);
259 pci_release_regions(pdev
);
261 pci_disable_device(pdev
);
262 dev_err(&pdev
->dev
, "pci device failed to probe\n");
266 static void intel_pch_thermal_remove(struct pci_dev
*pdev
)
268 struct pch_thermal_device
*ptd
= pci_get_drvdata(pdev
);
270 thermal_zone_device_unregister(ptd
->tzd
);
271 iounmap(ptd
->hw_base
);
272 pci_set_drvdata(pdev
, NULL
);
273 pci_release_regions(pdev
);
274 pci_disable_device(pdev
);
277 static int intel_pch_thermal_suspend_noirq(struct device
*device
)
279 struct pch_thermal_device
*ptd
= dev_get_drvdata(device
);
280 u16 pch_thr_temp
, pch_cur_temp
;
281 int pch_delay_cnt
= 0;
284 /* Shutdown the thermal sensor if it is not enabled by BIOS */
285 if (!ptd
->bios_enabled
) {
286 tsel
= readb(ptd
->hw_base
+ WPT_TSEL
);
287 writeb(tsel
& 0xFE, ptd
->hw_base
+ WPT_TSEL
);
291 /* Do not check temperature if it is not s2idle */
292 if (pm_suspend_via_firmware())
295 /* Get the PCH temperature threshold value */
296 pch_thr_temp
= GET_PCH_TEMP(WPT_TEMP_TSR
& readw(ptd
->hw_base
+ WPT_TSPM
));
298 /* Get the PCH current temperature value */
299 pch_cur_temp
= GET_PCH_TEMP(WPT_TEMP_TSR
& readw(ptd
->hw_base
+ WPT_TEMP
));
301 if (pch_cur_temp
>= pch_thr_temp
)
302 dev_warn(&ptd
->pdev
->dev
,
303 "CPU-PCH current temp [%dC] higher than the threshold temp [%dC], S0ix might fail. Start cooling...\n",
304 pch_cur_temp
, pch_thr_temp
);
307 * If current PCH temperature is higher than configured PCH threshold
308 * value, run some delay loop with sleep to let the current temperature
309 * go down below the threshold value which helps to allow system enter
310 * lower power S0ix suspend state. Even after delay loop if PCH current
311 * temperature stays above threshold, notify the warning message
312 * which helps to indentify the reason why S0ix entry was rejected.
314 while (pch_delay_cnt
< delay_cnt
) {
315 if (pch_cur_temp
< pch_thr_temp
)
318 if (pm_wakeup_pending()) {
319 dev_warn(&ptd
->pdev
->dev
, "Wakeup event detected, abort cooling\n");
324 dev_dbg(&ptd
->pdev
->dev
,
325 "CPU-PCH current temp [%dC] higher than the threshold temp [%dC], sleep %d times for %d ms duration\n",
326 pch_cur_temp
, pch_thr_temp
, pch_delay_cnt
, delay_timeout
);
327 msleep(delay_timeout
);
328 /* Read the PCH current temperature for next cycle. */
329 pch_cur_temp
= GET_PCH_TEMP(WPT_TEMP_TSR
& readw(ptd
->hw_base
+ WPT_TEMP
));
332 if (pch_cur_temp
>= pch_thr_temp
)
333 dev_warn(&ptd
->pdev
->dev
,
334 "CPU-PCH is hot [%dC] after %d ms delay. S0ix might fail\n",
335 pch_cur_temp
, pch_delay_cnt
* delay_timeout
);
338 dev_info(&ptd
->pdev
->dev
,
339 "CPU-PCH is cool [%dC] after %d ms delay\n",
340 pch_cur_temp
, pch_delay_cnt
* delay_timeout
);
342 dev_info(&ptd
->pdev
->dev
,
343 "CPU-PCH is cool [%dC]\n",
350 static int intel_pch_thermal_resume(struct device
*device
)
352 struct pch_thermal_device
*ptd
= dev_get_drvdata(device
);
355 if (ptd
->bios_enabled
)
358 tsel
= readb(ptd
->hw_base
+ WPT_TSEL
);
360 writeb(tsel
| WPT_TSEL_ETS
, ptd
->hw_base
+ WPT_TSEL
);
365 static const struct pci_device_id intel_pch_thermal_id
[] = {
366 { PCI_DEVICE(PCI_VENDOR_ID_INTEL
, PCH_THERMAL_DID_HSW_1
),
367 .driver_data
= PCH_BOARD_HSW
, },
368 { PCI_DEVICE(PCI_VENDOR_ID_INTEL
, PCH_THERMAL_DID_HSW_2
),
369 .driver_data
= PCH_BOARD_HSW
, },
370 { PCI_DEVICE(PCI_VENDOR_ID_INTEL
, PCH_THERMAL_DID_WPT
),
371 .driver_data
= PCH_BOARD_WPT
, },
372 { PCI_DEVICE(PCI_VENDOR_ID_INTEL
, PCH_THERMAL_DID_SKL
),
373 .driver_data
= PCH_BOARD_SKL
, },
374 { PCI_DEVICE(PCI_VENDOR_ID_INTEL
, PCH_THERMAL_DID_SKL_H
),
375 .driver_data
= PCH_BOARD_SKL
, },
376 { PCI_DEVICE(PCI_VENDOR_ID_INTEL
, PCH_THERMAL_DID_CNL
),
377 .driver_data
= PCH_BOARD_CNL
, },
378 { PCI_DEVICE(PCI_VENDOR_ID_INTEL
, PCH_THERMAL_DID_CNL_H
),
379 .driver_data
= PCH_BOARD_CNL
, },
380 { PCI_DEVICE(PCI_VENDOR_ID_INTEL
, PCH_THERMAL_DID_CNL_LP
),
381 .driver_data
= PCH_BOARD_CNL
, },
382 { PCI_DEVICE(PCI_VENDOR_ID_INTEL
, PCH_THERMAL_DID_CML_H
),
383 .driver_data
= PCH_BOARD_CML
, },
384 { PCI_DEVICE(PCI_VENDOR_ID_INTEL
, PCH_THERMAL_DID_LWB
),
385 .driver_data
= PCH_BOARD_LWB
, },
386 { PCI_DEVICE(PCI_VENDOR_ID_INTEL
, PCH_THERMAL_DID_WBG
),
387 .driver_data
= PCH_BOARD_WBG
, },
390 MODULE_DEVICE_TABLE(pci
, intel_pch_thermal_id
);
392 static const struct dev_pm_ops intel_pch_pm_ops
= {
393 .suspend_noirq
= intel_pch_thermal_suspend_noirq
,
394 .resume
= intel_pch_thermal_resume
,
397 static struct pci_driver intel_pch_thermal_driver
= {
398 .name
= "intel_pch_thermal",
399 .id_table
= intel_pch_thermal_id
,
400 .probe
= intel_pch_thermal_probe
,
401 .remove
= intel_pch_thermal_remove
,
402 .driver
.pm
= &intel_pch_pm_ops
,
405 module_pci_driver(intel_pch_thermal_driver
);
407 MODULE_LICENSE("GPL v2");
408 MODULE_DESCRIPTION("Intel PCH Thermal driver");