1 // SPDX-License-Identifier: GPL-2.0-only
2 /* intel_pch_thermal.c - Intel PCH Thermal driver
3  *
4  * Copyright (c) 2015, Intel Corporation.
5  *
6  * Authors:
7  *     Tushar Dave <tushar.n.dave@intel.com>
8  */
9 
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>
15 #include <linux/pm.h>
16 #include <linux/suspend.h>
17 #include <linux/thermal.h>
18 #include <linux/types.h>
19 #include <linux/units.h>
20 
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 */
33 
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 */
51 
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 */
62 
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)
68 
69 #define PCH_MAX_TRIPS 3 /* critical, hot, passive */
70 
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.");
75 
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.");
80 
81 static char driver_name[] = "Intel PCH thermal driver";
82 
83 struct pch_thermal_device {
84 	void __iomem *hw_base;
85 	const struct pch_dev_ops *ops;
86 	struct pci_dev *pdev;
87 	struct thermal_zone_device *tzd;
88 	struct thermal_trip trips[PCH_MAX_TRIPS];
89 	bool bios_enabled;
90 };
91 
92 #ifdef CONFIG_ACPI
93 
94 /*
95  * On some platforms, there is a companion ACPI device, which adds
96  * passive trip temperature using _PSV method. There is no specific
97  * passive temperature setting in MMIO interface of this PCI device.
98  */
99 static void pch_wpt_add_acpi_psv_trip(struct pch_thermal_device *ptd,
100 				      int *nr_trips)
101 {
102 	struct acpi_device *adev;
103 	int temp;
104 
105 	adev = ACPI_COMPANION(&ptd->pdev->dev);
106 	if (!adev)
107 		return;
108 
109 	if (thermal_acpi_passive_trip_temp(adev, &temp) || temp <= 0)
110 		return;
111 
112 	ptd->trips[*nr_trips].type = THERMAL_TRIP_PASSIVE;
113 	ptd->trips[*nr_trips].temperature = temp;
114 	++(*nr_trips);
115 }
116 #else
117 static void pch_wpt_add_acpi_psv_trip(struct pch_thermal_device *ptd,
118 				      int *nr_trips)
119 {
120 
121 }
122 #endif
123 
124 static int pch_wpt_init(struct pch_thermal_device *ptd, int *nr_trips)
125 {
126 	u8 tsel;
127 	u16 trip_temp;
128 
129 	*nr_trips = 0;
130 
131 	/* Check if BIOS has already enabled thermal sensor */
132 	if (WPT_TSEL_ETS & readb(ptd->hw_base + WPT_TSEL)) {
133 		ptd->bios_enabled = true;
134 		goto read_trips;
135 	}
136 
137 	tsel = readb(ptd->hw_base + WPT_TSEL);
138 	/*
139 	 * When TSEL's Policy Lock-Down bit is 1, TSEL become RO.
140 	 * If so, thermal sensor cannot enable. Bail out.
141 	 */
142 	if (tsel & WPT_TSEL_PLDB) {
143 		dev_err(&ptd->pdev->dev, "Sensor can't be enabled\n");
144 		return -ENODEV;
145 	}
146 
147 	writeb(tsel|WPT_TSEL_ETS, ptd->hw_base + WPT_TSEL);
148 	if (!(WPT_TSEL_ETS & readb(ptd->hw_base + WPT_TSEL))) {
149 		dev_err(&ptd->pdev->dev, "Sensor can't be enabled\n");
150 		return -ENODEV;
151 	}
152 
153 read_trips:
154 	trip_temp = readw(ptd->hw_base + WPT_CTT);
155 	trip_temp &= 0x1FF;
156 	if (trip_temp) {
157 		ptd->trips[*nr_trips].temperature = GET_WPT_TEMP(trip_temp);
158 		ptd->trips[*nr_trips].type = THERMAL_TRIP_CRITICAL;
159 		++(*nr_trips);
160 	}
161 
162 	trip_temp = readw(ptd->hw_base + WPT_PHL);
163 	trip_temp &= 0x1FF;
164 	if (trip_temp) {
165 		ptd->trips[*nr_trips].temperature = GET_WPT_TEMP(trip_temp);
166 		ptd->trips[*nr_trips].type = THERMAL_TRIP_HOT;
167 		++(*nr_trips);
168 	}
169 
170 	pch_wpt_add_acpi_psv_trip(ptd, nr_trips);
171 
172 	return 0;
173 }
174 
175 static int pch_wpt_get_temp(struct pch_thermal_device *ptd, int *temp)
176 {
177 	*temp = GET_WPT_TEMP(WPT_TEMP_TSR & readw(ptd->hw_base + WPT_TEMP));
178 
179 	return 0;
180 }
181 
182 /* Cool the PCH when it's overheat in .suspend_noirq phase */
183 static int pch_wpt_suspend(struct pch_thermal_device *ptd)
184 {
185 	u8 tsel;
186 	int pch_delay_cnt = 0;
187 	u16 pch_thr_temp, pch_cur_temp;
188 
189 	/* Shutdown the thermal sensor if it is not enabled by BIOS */
190 	if (!ptd->bios_enabled) {
191 		tsel = readb(ptd->hw_base + WPT_TSEL);
192 		writeb(tsel & 0xFE, ptd->hw_base + WPT_TSEL);
193 		return 0;
194 	}
195 
196 	/* Do not check temperature if it is not s2idle */
197 	if (pm_suspend_via_firmware())
198 		return 0;
199 
200 	/* Get the PCH temperature threshold value */
201 	pch_thr_temp = GET_PCH_TEMP(WPT_TEMP_TSR & readw(ptd->hw_base + WPT_TSPM));
202 
203 	/* Get the PCH current temperature value */
204 	pch_cur_temp = GET_PCH_TEMP(WPT_TEMP_TSR & readw(ptd->hw_base + WPT_TEMP));
205 
206 	/*
207 	 * If current PCH temperature is higher than configured PCH threshold
208 	 * value, run some delay loop with sleep to let the current temperature
209 	 * go down below the threshold value which helps to allow system enter
210 	 * lower power S0ix suspend state. Even after delay loop if PCH current
211 	 * temperature stays above threshold, notify the warning message
212 	 * which helps to indentify the reason why S0ix entry was rejected.
213 	 */
214 	while (pch_delay_cnt < delay_cnt) {
215 		if (pch_cur_temp < pch_thr_temp)
216 			break;
217 
218 		if (pm_wakeup_pending()) {
219 			dev_warn(&ptd->pdev->dev, "Wakeup event detected, abort cooling\n");
220 			return 0;
221 		}
222 
223 		pch_delay_cnt++;
224 		dev_dbg(&ptd->pdev->dev,
225 			"CPU-PCH current temp [%dC] higher than the threshold temp [%dC], sleep %d times for %d ms duration\n",
226 			pch_cur_temp, pch_thr_temp, pch_delay_cnt, delay_timeout);
227 		msleep(delay_timeout);
228 		/* Read the PCH current temperature for next cycle. */
229 		pch_cur_temp = GET_PCH_TEMP(WPT_TEMP_TSR & readw(ptd->hw_base + WPT_TEMP));
230 	}
231 
232 	if (pch_cur_temp >= pch_thr_temp)
233 		dev_warn(&ptd->pdev->dev,
234 			"CPU-PCH is hot [%dC] after %d ms delay. S0ix might fail\n",
235 			pch_cur_temp, pch_delay_cnt * delay_timeout);
236 	else {
237 		if (pch_delay_cnt)
238 			dev_info(&ptd->pdev->dev,
239 				"CPU-PCH is cool [%dC] after %d ms delay\n",
240 				pch_cur_temp, pch_delay_cnt * delay_timeout);
241 		else
242 			dev_info(&ptd->pdev->dev,
243 				"CPU-PCH is cool [%dC]\n",
244 				pch_cur_temp);
245 	}
246 
247 	return 0;
248 }
249 
250 static int pch_wpt_resume(struct pch_thermal_device *ptd)
251 {
252 	u8 tsel;
253 
254 	if (ptd->bios_enabled)
255 		return 0;
256 
257 	tsel = readb(ptd->hw_base + WPT_TSEL);
258 
259 	writeb(tsel | WPT_TSEL_ETS, ptd->hw_base + WPT_TSEL);
260 
261 	return 0;
262 }
263 
264 struct pch_dev_ops {
265 	int (*hw_init)(struct pch_thermal_device *ptd, int *nr_trips);
266 	int (*get_temp)(struct pch_thermal_device *ptd, int *temp);
267 	int (*suspend)(struct pch_thermal_device *ptd);
268 	int (*resume)(struct pch_thermal_device *ptd);
269 };
270 
271 
272 /* dev ops for Wildcat Point */
273 static const struct pch_dev_ops pch_dev_ops_wpt = {
274 	.hw_init = pch_wpt_init,
275 	.get_temp = pch_wpt_get_temp,
276 	.suspend = pch_wpt_suspend,
277 	.resume = pch_wpt_resume,
278 };
279 
280 static int pch_thermal_get_temp(struct thermal_zone_device *tzd, int *temp)
281 {
282 	struct pch_thermal_device *ptd = tzd->devdata;
283 
284 	return	ptd->ops->get_temp(ptd, temp);
285 }
286 
287 static void pch_critical(struct thermal_zone_device *tzd)
288 {
289 	dev_dbg(&tzd->device, "%s: critical temperature reached\n", tzd->type);
290 }
291 
292 static struct thermal_zone_device_ops tzd_ops = {
293 	.get_temp = pch_thermal_get_temp,
294 	.critical = pch_critical,
295 };
296 
297 enum board_ids {
298 	board_hsw,
299 	board_wpt,
300 	board_skl,
301 	board_cnl,
302 	board_cml,
303 	board_lwb,
304 	board_wbg,
305 };
306 
307 static const struct board_info {
308 	const char *name;
309 	const struct pch_dev_ops *ops;
310 } board_info[] = {
311 	[board_hsw] = {
312 		.name = "pch_haswell",
313 		.ops = &pch_dev_ops_wpt,
314 	},
315 	[board_wpt] = {
316 		.name = "pch_wildcat_point",
317 		.ops = &pch_dev_ops_wpt,
318 	},
319 	[board_skl] = {
320 		.name = "pch_skylake",
321 		.ops = &pch_dev_ops_wpt,
322 	},
323 	[board_cnl] = {
324 		.name = "pch_cannonlake",
325 		.ops = &pch_dev_ops_wpt,
326 	},
327 	[board_cml] = {
328 		.name = "pch_cometlake",
329 		.ops = &pch_dev_ops_wpt,
330 	},
331 	[board_lwb] = {
332 		.name = "pch_lewisburg",
333 		.ops = &pch_dev_ops_wpt,
334 	},
335 	[board_wbg] = {
336 		.name = "pch_wellsburg",
337 		.ops = &pch_dev_ops_wpt,
338 	},
339 };
340 
341 static int intel_pch_thermal_probe(struct pci_dev *pdev,
342 				   const struct pci_device_id *id)
343 {
344 	enum board_ids board_id = id->driver_data;
345 	const struct board_info *bi = &board_info[board_id];
346 	struct pch_thermal_device *ptd;
347 	int err;
348 	int nr_trips;
349 
350 	ptd = devm_kzalloc(&pdev->dev, sizeof(*ptd), GFP_KERNEL);
351 	if (!ptd)
352 		return -ENOMEM;
353 
354 	ptd->ops = bi->ops;
355 
356 	pci_set_drvdata(pdev, ptd);
357 	ptd->pdev = pdev;
358 
359 	err = pci_enable_device(pdev);
360 	if (err) {
361 		dev_err(&pdev->dev, "failed to enable pci device\n");
362 		return err;
363 	}
364 
365 	err = pci_request_regions(pdev, driver_name);
366 	if (err) {
367 		dev_err(&pdev->dev, "failed to request pci region\n");
368 		goto error_disable;
369 	}
370 
371 	ptd->hw_base = pci_ioremap_bar(pdev, 0);
372 	if (!ptd->hw_base) {
373 		err = -ENOMEM;
374 		dev_err(&pdev->dev, "failed to map mem base\n");
375 		goto error_release;
376 	}
377 
378 	err = ptd->ops->hw_init(ptd, &nr_trips);
379 	if (err)
380 		goto error_cleanup;
381 
382 	ptd->tzd = thermal_zone_device_register_with_trips(bi->name, ptd->trips,
383 							   nr_trips, 0, ptd,
384 							   &tzd_ops, NULL, 0, 0);
385 	if (IS_ERR(ptd->tzd)) {
386 		dev_err(&pdev->dev, "Failed to register thermal zone %s\n",
387 			bi->name);
388 		err = PTR_ERR(ptd->tzd);
389 		goto error_cleanup;
390 	}
391 	err = thermal_zone_device_enable(ptd->tzd);
392 	if (err)
393 		goto err_unregister;
394 
395 	return 0;
396 
397 err_unregister:
398 	thermal_zone_device_unregister(ptd->tzd);
399 error_cleanup:
400 	iounmap(ptd->hw_base);
401 error_release:
402 	pci_release_regions(pdev);
403 error_disable:
404 	pci_disable_device(pdev);
405 	dev_err(&pdev->dev, "pci device failed to probe\n");
406 	return err;
407 }
408 
409 static void intel_pch_thermal_remove(struct pci_dev *pdev)
410 {
411 	struct pch_thermal_device *ptd = pci_get_drvdata(pdev);
412 
413 	thermal_zone_device_unregister(ptd->tzd);
414 	iounmap(ptd->hw_base);
415 	pci_set_drvdata(pdev, NULL);
416 	pci_release_regions(pdev);
417 	pci_disable_device(pdev);
418 }
419 
420 static int intel_pch_thermal_suspend_noirq(struct device *device)
421 {
422 	struct pch_thermal_device *ptd = dev_get_drvdata(device);
423 
424 	return ptd->ops->suspend(ptd);
425 }
426 
427 static int intel_pch_thermal_resume(struct device *device)
428 {
429 	struct pch_thermal_device *ptd = dev_get_drvdata(device);
430 
431 	return ptd->ops->resume(ptd);
432 }
433 
434 static const struct pci_device_id intel_pch_thermal_id[] = {
435 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_HSW_1),
436 		.driver_data = board_hsw, },
437 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_HSW_2),
438 		.driver_data = board_hsw, },
439 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_WPT),
440 		.driver_data = board_wpt, },
441 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_SKL),
442 		.driver_data = board_skl, },
443 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_SKL_H),
444 		.driver_data = board_skl, },
445 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_CNL),
446 		.driver_data = board_cnl, },
447 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_CNL_H),
448 		.driver_data = board_cnl, },
449 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_CNL_LP),
450 		.driver_data = board_cnl, },
451 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_CML_H),
452 		.driver_data = board_cml, },
453 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_LWB),
454 		.driver_data = board_lwb, },
455 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_WBG),
456 		.driver_data = board_wbg, },
457 	{ 0, },
458 };
459 MODULE_DEVICE_TABLE(pci, intel_pch_thermal_id);
460 
461 static const struct dev_pm_ops intel_pch_pm_ops = {
462 	.suspend_noirq = intel_pch_thermal_suspend_noirq,
463 	.resume = intel_pch_thermal_resume,
464 };
465 
466 static struct pci_driver intel_pch_thermal_driver = {
467 	.name		= "intel_pch_thermal",
468 	.id_table	= intel_pch_thermal_id,
469 	.probe		= intel_pch_thermal_probe,
470 	.remove		= intel_pch_thermal_remove,
471 	.driver.pm	= &intel_pch_pm_ops,
472 };
473 
474 module_pci_driver(intel_pch_thermal_driver);
475 
476 MODULE_LICENSE("GPL v2");
477 MODULE_DESCRIPTION("Intel PCH Thermal driver");
478