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 */
33 /* Wildcat Point-LP PCH Thermal registers */
34 #define WPT_TEMP 0x0000 /* Temperature */
35 #define WPT_TSC 0x04 /* Thermal Sensor Control */
36 #define WPT_TSS 0x06 /* Thermal Sensor Status */
37 #define WPT_TSEL 0x08 /* Thermal Sensor Enable and Lock */
38 #define WPT_TSREL 0x0A /* Thermal Sensor Report Enable and Lock */
39 #define WPT_TSMIC 0x0C /* Thermal Sensor SMI Control */
40 #define WPT_CTT 0x0010 /* Catastrophic Trip Point */
41 #define WPT_TSPM 0x001C /* Thermal Sensor Power Management */
42 #define WPT_TAHV 0x0014 /* Thermal Alert High Value */
43 #define WPT_TALV 0x0018 /* Thermal Alert Low Value */
44 #define WPT_TL 0x00000040 /* Throttle Value */
45 #define WPT_PHL 0x0060 /* PCH Hot Level */
46 #define WPT_PHLC 0x62 /* PHL Control */
47 #define WPT_TAS 0x80 /* Thermal Alert Status */
48 #define WPT_TSPIEN 0x82 /* PCI Interrupt Event Enables */
49 #define WPT_TSGPEN 0x84 /* General Purpose Event Enables */
51 /* Wildcat Point-LP PCH Thermal Register bit definitions */
52 #define WPT_TEMP_TSR 0x01ff /* Temp TS Reading */
53 #define WPT_TSC_CPDE 0x01 /* Catastrophic Power-Down Enable */
54 #define WPT_TSS_TSDSS 0x10 /* Thermal Sensor Dynamic Shutdown Status */
55 #define WPT_TSS_GPES 0x08 /* GPE status */
56 #define WPT_TSEL_ETS 0x01 /* Enable TS */
57 #define WPT_TSEL_PLDB 0x80 /* TSEL Policy Lock-Down Bit */
58 #define WPT_TL_TOL 0x000001FF /* T0 Level */
59 #define WPT_TL_T1L 0x1ff00000 /* T1 Level */
60 #define WPT_TL_TTEN 0x20000000 /* TT Enable */
62 /* Resolution of 1/2 degree C and an offset of -50C */
63 #define PCH_TEMP_OFFSET (-50)
64 #define GET_WPT_TEMP(x) ((x) * MILLIDEGREE_PER_DEGREE / 2 + WPT_TEMP_OFFSET)
65 #define WPT_TEMP_OFFSET (PCH_TEMP_OFFSET * MILLIDEGREE_PER_DEGREE)
66 #define GET_PCH_TEMP(x) (((x) / 2) + PCH_TEMP_OFFSET)
68 /* Amount of time for each cooling delay, 100ms by default for now */
69 static unsigned int delay_timeout
= 100;
70 module_param(delay_timeout
, int, 0644);
71 MODULE_PARM_DESC(delay_timeout
, "amount of time delay for each iteration.");
73 /* Number of iterations for cooling delay, 10 counts by default for now */
74 static unsigned int delay_cnt
= 10;
75 module_param(delay_cnt
, int, 0644);
76 MODULE_PARM_DESC(delay_cnt
, "total number of iterations for time delay.");
78 static char driver_name
[] = "Intel PCH thermal driver";
80 struct pch_thermal_device
{
81 void __iomem
*hw_base
;
82 const struct pch_dev_ops
*ops
;
84 struct thermal_zone_device
*tzd
;
86 unsigned long crt_temp
;
88 unsigned long hot_temp
;
90 unsigned long psv_temp
;
97 * On some platforms, there is a companion ACPI device, which adds
98 * passive trip temperature using _PSV method. There is no specific
99 * passive temperature setting in MMIO interface of this PCI device.
101 static void pch_wpt_add_acpi_psv_trip(struct pch_thermal_device
*ptd
,
104 struct acpi_device
*adev
;
106 ptd
->psv_trip_id
= -1;
108 adev
= ACPI_COMPANION(&ptd
->pdev
->dev
);
110 unsigned long long r
;
113 status
= acpi_evaluate_integer(adev
->handle
, "_PSV", NULL
,
115 if (ACPI_SUCCESS(status
)) {
116 unsigned long trip_temp
;
118 trip_temp
= deci_kelvin_to_millicelsius(r
);
120 ptd
->psv_temp
= trip_temp
;
121 ptd
->psv_trip_id
= *nr_trips
;
128 static void pch_wpt_add_acpi_psv_trip(struct pch_thermal_device
*ptd
,
131 ptd
->psv_trip_id
= -1;
136 static int pch_wpt_init(struct pch_thermal_device
*ptd
, int *nr_trips
)
143 /* Check if BIOS has already enabled thermal sensor */
144 if (WPT_TSEL_ETS
& readb(ptd
->hw_base
+ WPT_TSEL
)) {
145 ptd
->bios_enabled
= true;
149 tsel
= readb(ptd
->hw_base
+ WPT_TSEL
);
151 * When TSEL's Policy Lock-Down bit is 1, TSEL become RO.
152 * If so, thermal sensor cannot enable. Bail out.
154 if (tsel
& WPT_TSEL_PLDB
) {
155 dev_err(&ptd
->pdev
->dev
, "Sensor can't be enabled\n");
159 writeb(tsel
|WPT_TSEL_ETS
, ptd
->hw_base
+ WPT_TSEL
);
160 if (!(WPT_TSEL_ETS
& readb(ptd
->hw_base
+ WPT_TSEL
))) {
161 dev_err(&ptd
->pdev
->dev
, "Sensor can't be enabled\n");
166 ptd
->crt_trip_id
= -1;
167 trip_temp
= readw(ptd
->hw_base
+ WPT_CTT
);
170 ptd
->crt_temp
= GET_WPT_TEMP(trip_temp
);
171 ptd
->crt_trip_id
= 0;
175 ptd
->hot_trip_id
= -1;
176 trip_temp
= readw(ptd
->hw_base
+ WPT_PHL
);
179 ptd
->hot_temp
= GET_WPT_TEMP(trip_temp
);
180 ptd
->hot_trip_id
= *nr_trips
;
184 pch_wpt_add_acpi_psv_trip(ptd
, nr_trips
);
189 static int pch_wpt_get_temp(struct pch_thermal_device
*ptd
, int *temp
)
191 *temp
= GET_WPT_TEMP(WPT_TEMP_TSR
& readw(ptd
->hw_base
+ WPT_TEMP
));
196 static int pch_wpt_suspend(struct pch_thermal_device
*ptd
)
199 u8 pch_delay_cnt
= 1;
200 u16 pch_thr_temp
, pch_cur_temp
;
202 /* Shutdown the thermal sensor if it is not enabled by BIOS */
203 if (!ptd
->bios_enabled
) {
204 tsel
= readb(ptd
->hw_base
+ WPT_TSEL
);
205 writeb(tsel
& 0xFE, ptd
->hw_base
+ WPT_TSEL
);
209 /* Do not check temperature if it is not a S0ix capable platform */
211 if (!(acpi_gbl_FADT
.flags
& ACPI_FADT_LOW_POWER_S0
))
217 /* Do not check temperature if it is not s2idle */
218 if (pm_suspend_via_firmware())
221 /* Get the PCH temperature threshold value */
222 pch_thr_temp
= GET_PCH_TEMP(WPT_TEMP_TSR
& readw(ptd
->hw_base
+ WPT_TSPM
));
224 /* Get the PCH current temperature value */
225 pch_cur_temp
= GET_PCH_TEMP(WPT_TEMP_TSR
& readw(ptd
->hw_base
+ WPT_TEMP
));
228 * If current PCH temperature is higher than configured PCH threshold
229 * value, run some delay loop with sleep to let the current temperature
230 * go down below the threshold value which helps to allow system enter
231 * lower power S0ix suspend state. Even after delay loop if PCH current
232 * temperature stays above threshold, notify the warning message
233 * which helps to indentify the reason why S0ix entry was rejected.
235 while (pch_delay_cnt
<= delay_cnt
) {
236 if (pch_cur_temp
<= pch_thr_temp
)
239 dev_warn(&ptd
->pdev
->dev
,
240 "CPU-PCH current temp [%dC] higher than the threshold temp [%dC], sleep %d times for %d ms duration\n",
241 pch_cur_temp
, pch_thr_temp
, pch_delay_cnt
, delay_timeout
);
242 msleep(delay_timeout
);
243 /* Read the PCH current temperature for next cycle. */
244 pch_cur_temp
= GET_PCH_TEMP(WPT_TEMP_TSR
& readw(ptd
->hw_base
+ WPT_TEMP
));
248 if (pch_cur_temp
> pch_thr_temp
)
249 dev_warn(&ptd
->pdev
->dev
,
250 "CPU-PCH is hot [%dC] even after delay, continue to suspend. S0ix might fail\n",
253 dev_info(&ptd
->pdev
->dev
,
254 "CPU-PCH is cool [%dC], continue to suspend\n", pch_cur_temp
);
259 static int pch_wpt_resume(struct pch_thermal_device
*ptd
)
263 if (ptd
->bios_enabled
)
266 tsel
= readb(ptd
->hw_base
+ WPT_TSEL
);
268 writeb(tsel
| WPT_TSEL_ETS
, ptd
->hw_base
+ WPT_TSEL
);
274 int (*hw_init
)(struct pch_thermal_device
*ptd
, int *nr_trips
);
275 int (*get_temp
)(struct pch_thermal_device
*ptd
, int *temp
);
276 int (*suspend
)(struct pch_thermal_device
*ptd
);
277 int (*resume
)(struct pch_thermal_device
*ptd
);
281 /* dev ops for Wildcat Point */
282 static const struct pch_dev_ops pch_dev_ops_wpt
= {
283 .hw_init
= pch_wpt_init
,
284 .get_temp
= pch_wpt_get_temp
,
285 .suspend
= pch_wpt_suspend
,
286 .resume
= pch_wpt_resume
,
289 static int pch_thermal_get_temp(struct thermal_zone_device
*tzd
, int *temp
)
291 struct pch_thermal_device
*ptd
= tzd
->devdata
;
293 return ptd
->ops
->get_temp(ptd
, temp
);
296 static int pch_get_trip_type(struct thermal_zone_device
*tzd
, int trip
,
297 enum thermal_trip_type
*type
)
299 struct pch_thermal_device
*ptd
= tzd
->devdata
;
301 if (ptd
->crt_trip_id
== trip
)
302 *type
= THERMAL_TRIP_CRITICAL
;
303 else if (ptd
->hot_trip_id
== trip
)
304 *type
= THERMAL_TRIP_HOT
;
305 else if (ptd
->psv_trip_id
== trip
)
306 *type
= THERMAL_TRIP_PASSIVE
;
313 static int pch_get_trip_temp(struct thermal_zone_device
*tzd
, int trip
, int *temp
)
315 struct pch_thermal_device
*ptd
= tzd
->devdata
;
317 if (ptd
->crt_trip_id
== trip
)
318 *temp
= ptd
->crt_temp
;
319 else if (ptd
->hot_trip_id
== trip
)
320 *temp
= ptd
->hot_temp
;
321 else if (ptd
->psv_trip_id
== trip
)
322 *temp
= ptd
->psv_temp
;
329 static struct thermal_zone_device_ops tzd_ops
= {
330 .get_temp
= pch_thermal_get_temp
,
331 .get_trip_type
= pch_get_trip_type
,
332 .get_trip_temp
= pch_get_trip_temp
,
344 static const struct board_info
{
346 const struct pch_dev_ops
*ops
;
349 .name
= "pch_haswell",
350 .ops
= &pch_dev_ops_wpt
,
353 .name
= "pch_wildcat_point",
354 .ops
= &pch_dev_ops_wpt
,
357 .name
= "pch_skylake",
358 .ops
= &pch_dev_ops_wpt
,
361 .name
= "pch_cannonlake",
362 .ops
= &pch_dev_ops_wpt
,
365 .name
= "pch_cometlake",
366 .ops
= &pch_dev_ops_wpt
,
369 .name
= "pch_lewisburg",
370 .ops
= &pch_dev_ops_wpt
,
374 static int intel_pch_thermal_probe(struct pci_dev
*pdev
,
375 const struct pci_device_id
*id
)
377 enum board_ids board_id
= id
->driver_data
;
378 const struct board_info
*bi
= &board_info
[board_id
];
379 struct pch_thermal_device
*ptd
;
383 ptd
= devm_kzalloc(&pdev
->dev
, sizeof(*ptd
), GFP_KERNEL
);
389 pci_set_drvdata(pdev
, ptd
);
392 err
= pci_enable_device(pdev
);
394 dev_err(&pdev
->dev
, "failed to enable pci device\n");
398 err
= pci_request_regions(pdev
, driver_name
);
400 dev_err(&pdev
->dev
, "failed to request pci region\n");
404 ptd
->hw_base
= pci_ioremap_bar(pdev
, 0);
407 dev_err(&pdev
->dev
, "failed to map mem base\n");
411 err
= ptd
->ops
->hw_init(ptd
, &nr_trips
);
415 ptd
->tzd
= thermal_zone_device_register(bi
->name
, nr_trips
, 0, ptd
,
416 &tzd_ops
, NULL
, 0, 0);
417 if (IS_ERR(ptd
->tzd
)) {
418 dev_err(&pdev
->dev
, "Failed to register thermal zone %s\n",
420 err
= PTR_ERR(ptd
->tzd
);
423 err
= thermal_zone_device_enable(ptd
->tzd
);
430 thermal_zone_device_unregister(ptd
->tzd
);
432 iounmap(ptd
->hw_base
);
434 pci_release_regions(pdev
);
436 pci_disable_device(pdev
);
437 dev_err(&pdev
->dev
, "pci device failed to probe\n");
441 static void intel_pch_thermal_remove(struct pci_dev
*pdev
)
443 struct pch_thermal_device
*ptd
= pci_get_drvdata(pdev
);
445 thermal_zone_device_unregister(ptd
->tzd
);
446 iounmap(ptd
->hw_base
);
447 pci_set_drvdata(pdev
, NULL
);
448 pci_release_regions(pdev
);
449 pci_disable_device(pdev
);
452 static int intel_pch_thermal_suspend(struct device
*device
)
454 struct pch_thermal_device
*ptd
= dev_get_drvdata(device
);
456 return ptd
->ops
->suspend(ptd
);
459 static int intel_pch_thermal_resume(struct device
*device
)
461 struct pch_thermal_device
*ptd
= dev_get_drvdata(device
);
463 return ptd
->ops
->resume(ptd
);
466 static const struct pci_device_id intel_pch_thermal_id
[] = {
467 { PCI_DEVICE(PCI_VENDOR_ID_INTEL
, PCH_THERMAL_DID_HSW_1
),
468 .driver_data
= board_hsw
, },
469 { PCI_DEVICE(PCI_VENDOR_ID_INTEL
, PCH_THERMAL_DID_HSW_2
),
470 .driver_data
= board_hsw
, },
471 { PCI_DEVICE(PCI_VENDOR_ID_INTEL
, PCH_THERMAL_DID_WPT
),
472 .driver_data
= board_wpt
, },
473 { PCI_DEVICE(PCI_VENDOR_ID_INTEL
, PCH_THERMAL_DID_SKL
),
474 .driver_data
= board_skl
, },
475 { PCI_DEVICE(PCI_VENDOR_ID_INTEL
, PCH_THERMAL_DID_SKL_H
),
476 .driver_data
= board_skl
, },
477 { PCI_DEVICE(PCI_VENDOR_ID_INTEL
, PCH_THERMAL_DID_CNL
),
478 .driver_data
= board_cnl
, },
479 { PCI_DEVICE(PCI_VENDOR_ID_INTEL
, PCH_THERMAL_DID_CNL_H
),
480 .driver_data
= board_cnl
, },
481 { PCI_DEVICE(PCI_VENDOR_ID_INTEL
, PCH_THERMAL_DID_CNL_LP
),
482 .driver_data
= board_cnl
, },
483 { PCI_DEVICE(PCI_VENDOR_ID_INTEL
, PCH_THERMAL_DID_CML_H
),
484 .driver_data
= board_cml
, },
485 { PCI_DEVICE(PCI_VENDOR_ID_INTEL
, PCH_THERMAL_DID_LWB
),
486 .driver_data
= board_lwb
, },
489 MODULE_DEVICE_TABLE(pci
, intel_pch_thermal_id
);
491 static const struct dev_pm_ops intel_pch_pm_ops
= {
492 .suspend
= intel_pch_thermal_suspend
,
493 .resume
= intel_pch_thermal_resume
,
496 static struct pci_driver intel_pch_thermal_driver
= {
497 .name
= "intel_pch_thermal",
498 .id_table
= intel_pch_thermal_id
,
499 .probe
= intel_pch_thermal_probe
,
500 .remove
= intel_pch_thermal_remove
,
501 .driver
.pm
= &intel_pch_pm_ops
,
504 module_pci_driver(intel_pch_thermal_driver
);
506 MODULE_LICENSE("GPL v2");
507 MODULE_DESCRIPTION("Intel PCH Thermal driver");