Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /* intel_pch_thermal.c - Intel PCH Thermal driver
0003  *
0004  * Copyright (c) 2015, Intel Corporation.
0005  *
0006  * Authors:
0007  *     Tushar Dave <tushar.n.dave@intel.com>
0008  */
0009 
0010 #include <linux/acpi.h>
0011 #include <linux/delay.h>
0012 #include <linux/module.h>
0013 #include <linux/init.h>
0014 #include <linux/pci.h>
0015 #include <linux/pm.h>
0016 #include <linux/suspend.h>
0017 #include <linux/thermal.h>
0018 #include <linux/types.h>
0019 #include <linux/units.h>
0020 
0021 /* Intel PCH thermal Device IDs */
0022 #define PCH_THERMAL_DID_HSW_1   0x9C24 /* Haswell PCH */
0023 #define PCH_THERMAL_DID_HSW_2   0x8C24 /* Haswell PCH */
0024 #define PCH_THERMAL_DID_WPT 0x9CA4 /* Wildcat Point */
0025 #define PCH_THERMAL_DID_SKL 0x9D31 /* Skylake PCH */
0026 #define PCH_THERMAL_DID_SKL_H   0xA131 /* Skylake PCH 100 series */
0027 #define PCH_THERMAL_DID_CNL 0x9Df9 /* CNL PCH */
0028 #define PCH_THERMAL_DID_CNL_H   0xA379 /* CNL-H PCH */
0029 #define PCH_THERMAL_DID_CNL_LP  0x02F9 /* CNL-LP PCH */
0030 #define PCH_THERMAL_DID_CML_H   0X06F9 /* CML-H PCH */
0031 #define PCH_THERMAL_DID_LWB 0xA1B1 /* Lewisburg PCH */
0032 
0033 /* Wildcat Point-LP  PCH Thermal registers */
0034 #define WPT_TEMP    0x0000  /* Temperature */
0035 #define WPT_TSC 0x04    /* Thermal Sensor Control */
0036 #define WPT_TSS 0x06    /* Thermal Sensor Status */
0037 #define WPT_TSEL    0x08    /* Thermal Sensor Enable and Lock */
0038 #define WPT_TSREL   0x0A    /* Thermal Sensor Report Enable and Lock */
0039 #define WPT_TSMIC   0x0C    /* Thermal Sensor SMI Control */
0040 #define WPT_CTT 0x0010  /* Catastrophic Trip Point */
0041 #define WPT_TSPM    0x001C  /* Thermal Sensor Power Management */
0042 #define WPT_TAHV    0x0014  /* Thermal Alert High Value */
0043 #define WPT_TALV    0x0018  /* Thermal Alert Low Value */
0044 #define WPT_TL      0x00000040  /* Throttle Value */
0045 #define WPT_PHL 0x0060  /* PCH Hot Level */
0046 #define WPT_PHLC    0x62    /* PHL Control */
0047 #define WPT_TAS 0x80    /* Thermal Alert Status */
0048 #define WPT_TSPIEN  0x82    /* PCI Interrupt Event Enables */
0049 #define WPT_TSGPEN  0x84    /* General Purpose Event Enables */
0050 
0051 /*  Wildcat Point-LP  PCH Thermal Register bit definitions */
0052 #define WPT_TEMP_TSR    0x01ff  /* Temp TS Reading */
0053 #define WPT_TSC_CPDE    0x01    /* Catastrophic Power-Down Enable */
0054 #define WPT_TSS_TSDSS   0x10    /* Thermal Sensor Dynamic Shutdown Status */
0055 #define WPT_TSS_GPES    0x08    /* GPE status */
0056 #define WPT_TSEL_ETS    0x01    /* Enable TS */
0057 #define WPT_TSEL_PLDB   0x80    /* TSEL Policy Lock-Down Bit */
0058 #define WPT_TL_TOL  0x000001FF  /* T0 Level */
0059 #define WPT_TL_T1L  0x1ff00000  /* T1 Level */
0060 #define WPT_TL_TTEN 0x20000000  /* TT Enable */
0061 
0062 /* Resolution of 1/2 degree C and an offset of -50C */
0063 #define PCH_TEMP_OFFSET (-50)
0064 #define GET_WPT_TEMP(x) ((x) * MILLIDEGREE_PER_DEGREE / 2 + WPT_TEMP_OFFSET)
0065 #define WPT_TEMP_OFFSET (PCH_TEMP_OFFSET * MILLIDEGREE_PER_DEGREE)
0066 #define GET_PCH_TEMP(x) (((x) / 2) + PCH_TEMP_OFFSET)
0067 
0068 /* Amount of time for each cooling delay, 100ms by default for now */
0069 static unsigned int delay_timeout = 100;
0070 module_param(delay_timeout, int, 0644);
0071 MODULE_PARM_DESC(delay_timeout, "amount of time delay for each iteration.");
0072 
0073 /* Number of iterations for cooling delay, 600 counts by default for now */
0074 static unsigned int delay_cnt = 600;
0075 module_param(delay_cnt, int, 0644);
0076 MODULE_PARM_DESC(delay_cnt, "total number of iterations for time delay.");
0077 
0078 static char driver_name[] = "Intel PCH thermal driver";
0079 
0080 struct pch_thermal_device {
0081     void __iomem *hw_base;
0082     const struct pch_dev_ops *ops;
0083     struct pci_dev *pdev;
0084     struct thermal_zone_device *tzd;
0085     int crt_trip_id;
0086     unsigned long crt_temp;
0087     int hot_trip_id;
0088     unsigned long hot_temp;
0089     int psv_trip_id;
0090     unsigned long psv_temp;
0091     bool bios_enabled;
0092 };
0093 
0094 #ifdef CONFIG_ACPI
0095 
0096 /*
0097  * On some platforms, there is a companion ACPI device, which adds
0098  * passive trip temperature using _PSV method. There is no specific
0099  * passive temperature setting in MMIO interface of this PCI device.
0100  */
0101 static void pch_wpt_add_acpi_psv_trip(struct pch_thermal_device *ptd,
0102                       int *nr_trips)
0103 {
0104     struct acpi_device *adev;
0105 
0106     ptd->psv_trip_id = -1;
0107 
0108     adev = ACPI_COMPANION(&ptd->pdev->dev);
0109     if (adev) {
0110         unsigned long long r;
0111         acpi_status status;
0112 
0113         status = acpi_evaluate_integer(adev->handle, "_PSV", NULL,
0114                            &r);
0115         if (ACPI_SUCCESS(status)) {
0116             unsigned long trip_temp;
0117 
0118             trip_temp = deci_kelvin_to_millicelsius(r);
0119             if (trip_temp) {
0120                 ptd->psv_temp = trip_temp;
0121                 ptd->psv_trip_id = *nr_trips;
0122                 ++(*nr_trips);
0123             }
0124         }
0125     }
0126 }
0127 #else
0128 static void pch_wpt_add_acpi_psv_trip(struct pch_thermal_device *ptd,
0129                       int *nr_trips)
0130 {
0131     ptd->psv_trip_id = -1;
0132 
0133 }
0134 #endif
0135 
0136 static int pch_wpt_init(struct pch_thermal_device *ptd, int *nr_trips)
0137 {
0138     u8 tsel;
0139     u16 trip_temp;
0140 
0141     *nr_trips = 0;
0142 
0143     /* Check if BIOS has already enabled thermal sensor */
0144     if (WPT_TSEL_ETS & readb(ptd->hw_base + WPT_TSEL)) {
0145         ptd->bios_enabled = true;
0146         goto read_trips;
0147     }
0148 
0149     tsel = readb(ptd->hw_base + WPT_TSEL);
0150     /*
0151      * When TSEL's Policy Lock-Down bit is 1, TSEL become RO.
0152      * If so, thermal sensor cannot enable. Bail out.
0153      */
0154     if (tsel & WPT_TSEL_PLDB) {
0155         dev_err(&ptd->pdev->dev, "Sensor can't be enabled\n");
0156         return -ENODEV;
0157     }
0158 
0159     writeb(tsel|WPT_TSEL_ETS, ptd->hw_base + WPT_TSEL);
0160     if (!(WPT_TSEL_ETS & readb(ptd->hw_base + WPT_TSEL))) {
0161         dev_err(&ptd->pdev->dev, "Sensor can't be enabled\n");
0162         return -ENODEV;
0163     }
0164 
0165 read_trips:
0166     ptd->crt_trip_id = -1;
0167     trip_temp = readw(ptd->hw_base + WPT_CTT);
0168     trip_temp &= 0x1FF;
0169     if (trip_temp) {
0170         ptd->crt_temp = GET_WPT_TEMP(trip_temp);
0171         ptd->crt_trip_id = 0;
0172         ++(*nr_trips);
0173     }
0174 
0175     ptd->hot_trip_id = -1;
0176     trip_temp = readw(ptd->hw_base + WPT_PHL);
0177     trip_temp &= 0x1FF;
0178     if (trip_temp) {
0179         ptd->hot_temp = GET_WPT_TEMP(trip_temp);
0180         ptd->hot_trip_id = *nr_trips;
0181         ++(*nr_trips);
0182     }
0183 
0184     pch_wpt_add_acpi_psv_trip(ptd, nr_trips);
0185 
0186     return 0;
0187 }
0188 
0189 static int pch_wpt_get_temp(struct pch_thermal_device *ptd, int *temp)
0190 {
0191     *temp = GET_WPT_TEMP(WPT_TEMP_TSR & readw(ptd->hw_base + WPT_TEMP));
0192 
0193     return 0;
0194 }
0195 
0196 /* Cool the PCH when it's overheat in .suspend_noirq phase */
0197 static int pch_wpt_suspend(struct pch_thermal_device *ptd)
0198 {
0199     u8 tsel;
0200     int pch_delay_cnt = 0;
0201     u16 pch_thr_temp, pch_cur_temp;
0202 
0203     /* Shutdown the thermal sensor if it is not enabled by BIOS */
0204     if (!ptd->bios_enabled) {
0205         tsel = readb(ptd->hw_base + WPT_TSEL);
0206         writeb(tsel & 0xFE, ptd->hw_base + WPT_TSEL);
0207         return 0;
0208     }
0209 
0210     /* Do not check temperature if it is not s2idle */
0211     if (pm_suspend_via_firmware())
0212         return 0;
0213 
0214     /* Get the PCH temperature threshold value */
0215     pch_thr_temp = GET_PCH_TEMP(WPT_TEMP_TSR & readw(ptd->hw_base + WPT_TSPM));
0216 
0217     /* Get the PCH current temperature value */
0218     pch_cur_temp = GET_PCH_TEMP(WPT_TEMP_TSR & readw(ptd->hw_base + WPT_TEMP));
0219 
0220     /*
0221      * If current PCH temperature is higher than configured PCH threshold
0222      * value, run some delay loop with sleep to let the current temperature
0223      * go down below the threshold value which helps to allow system enter
0224      * lower power S0ix suspend state. Even after delay loop if PCH current
0225      * temperature stays above threshold, notify the warning message
0226      * which helps to indentify the reason why S0ix entry was rejected.
0227      */
0228     while (pch_delay_cnt < delay_cnt) {
0229         if (pch_cur_temp < pch_thr_temp)
0230             break;
0231 
0232         if (pm_wakeup_pending()) {
0233             dev_warn(&ptd->pdev->dev, "Wakeup event detected, abort cooling\n");
0234             return 0;
0235         }
0236 
0237         pch_delay_cnt++;
0238         dev_dbg(&ptd->pdev->dev,
0239             "CPU-PCH current temp [%dC] higher than the threshold temp [%dC], sleep %d times for %d ms duration\n",
0240             pch_cur_temp, pch_thr_temp, pch_delay_cnt, delay_timeout);
0241         msleep(delay_timeout);
0242         /* Read the PCH current temperature for next cycle. */
0243         pch_cur_temp = GET_PCH_TEMP(WPT_TEMP_TSR & readw(ptd->hw_base + WPT_TEMP));
0244     }
0245 
0246     if (pch_cur_temp >= pch_thr_temp)
0247         dev_warn(&ptd->pdev->dev,
0248             "CPU-PCH is hot [%dC] after %d ms delay. S0ix might fail\n",
0249             pch_cur_temp, pch_delay_cnt * delay_timeout);
0250     else {
0251         if (pch_delay_cnt)
0252             dev_info(&ptd->pdev->dev,
0253                 "CPU-PCH is cool [%dC] after %d ms delay\n",
0254                 pch_cur_temp, pch_delay_cnt * delay_timeout);
0255         else
0256             dev_info(&ptd->pdev->dev,
0257                 "CPU-PCH is cool [%dC]\n",
0258                 pch_cur_temp);
0259     }
0260 
0261     return 0;
0262 }
0263 
0264 static int pch_wpt_resume(struct pch_thermal_device *ptd)
0265 {
0266     u8 tsel;
0267 
0268     if (ptd->bios_enabled)
0269         return 0;
0270 
0271     tsel = readb(ptd->hw_base + WPT_TSEL);
0272 
0273     writeb(tsel | WPT_TSEL_ETS, ptd->hw_base + WPT_TSEL);
0274 
0275     return 0;
0276 }
0277 
0278 struct pch_dev_ops {
0279     int (*hw_init)(struct pch_thermal_device *ptd, int *nr_trips);
0280     int (*get_temp)(struct pch_thermal_device *ptd, int *temp);
0281     int (*suspend)(struct pch_thermal_device *ptd);
0282     int (*resume)(struct pch_thermal_device *ptd);
0283 };
0284 
0285 
0286 /* dev ops for Wildcat Point */
0287 static const struct pch_dev_ops pch_dev_ops_wpt = {
0288     .hw_init = pch_wpt_init,
0289     .get_temp = pch_wpt_get_temp,
0290     .suspend = pch_wpt_suspend,
0291     .resume = pch_wpt_resume,
0292 };
0293 
0294 static int pch_thermal_get_temp(struct thermal_zone_device *tzd, int *temp)
0295 {
0296     struct pch_thermal_device *ptd = tzd->devdata;
0297 
0298     return  ptd->ops->get_temp(ptd, temp);
0299 }
0300 
0301 static int pch_get_trip_type(struct thermal_zone_device *tzd, int trip,
0302                  enum thermal_trip_type *type)
0303 {
0304     struct pch_thermal_device *ptd = tzd->devdata;
0305 
0306     if (ptd->crt_trip_id == trip)
0307         *type = THERMAL_TRIP_CRITICAL;
0308     else if (ptd->hot_trip_id == trip)
0309         *type = THERMAL_TRIP_HOT;
0310     else if (ptd->psv_trip_id == trip)
0311         *type = THERMAL_TRIP_PASSIVE;
0312     else
0313         return -EINVAL;
0314 
0315     return 0;
0316 }
0317 
0318 static int pch_get_trip_temp(struct thermal_zone_device *tzd, int trip, int *temp)
0319 {
0320     struct pch_thermal_device *ptd = tzd->devdata;
0321 
0322     if (ptd->crt_trip_id == trip)
0323         *temp = ptd->crt_temp;
0324     else if (ptd->hot_trip_id == trip)
0325         *temp = ptd->hot_temp;
0326     else if (ptd->psv_trip_id == trip)
0327         *temp = ptd->psv_temp;
0328     else
0329         return -EINVAL;
0330 
0331     return 0;
0332 }
0333 
0334 static void pch_critical(struct thermal_zone_device *tzd)
0335 {
0336     dev_dbg(&tzd->device, "%s: critical temperature reached\n", tzd->type);
0337 }
0338 
0339 static struct thermal_zone_device_ops tzd_ops = {
0340     .get_temp = pch_thermal_get_temp,
0341     .get_trip_type = pch_get_trip_type,
0342     .get_trip_temp = pch_get_trip_temp,
0343     .critical = pch_critical,
0344 };
0345 
0346 enum board_ids {
0347     board_hsw,
0348     board_wpt,
0349     board_skl,
0350     board_cnl,
0351     board_cml,
0352     board_lwb,
0353 };
0354 
0355 static const struct board_info {
0356     const char *name;
0357     const struct pch_dev_ops *ops;
0358 } board_info[] = {
0359     [board_hsw] = {
0360         .name = "pch_haswell",
0361         .ops = &pch_dev_ops_wpt,
0362     },
0363     [board_wpt] = {
0364         .name = "pch_wildcat_point",
0365         .ops = &pch_dev_ops_wpt,
0366     },
0367     [board_skl] = {
0368         .name = "pch_skylake",
0369         .ops = &pch_dev_ops_wpt,
0370     },
0371     [board_cnl] = {
0372         .name = "pch_cannonlake",
0373         .ops = &pch_dev_ops_wpt,
0374     },
0375     [board_cml] = {
0376         .name = "pch_cometlake",
0377         .ops = &pch_dev_ops_wpt,
0378     },
0379     [board_lwb] = {
0380         .name = "pch_lewisburg",
0381         .ops = &pch_dev_ops_wpt,
0382     },
0383 };
0384 
0385 static int intel_pch_thermal_probe(struct pci_dev *pdev,
0386                    const struct pci_device_id *id)
0387 {
0388     enum board_ids board_id = id->driver_data;
0389     const struct board_info *bi = &board_info[board_id];
0390     struct pch_thermal_device *ptd;
0391     int err;
0392     int nr_trips;
0393 
0394     ptd = devm_kzalloc(&pdev->dev, sizeof(*ptd), GFP_KERNEL);
0395     if (!ptd)
0396         return -ENOMEM;
0397 
0398     ptd->ops = bi->ops;
0399 
0400     pci_set_drvdata(pdev, ptd);
0401     ptd->pdev = pdev;
0402 
0403     err = pci_enable_device(pdev);
0404     if (err) {
0405         dev_err(&pdev->dev, "failed to enable pci device\n");
0406         return err;
0407     }
0408 
0409     err = pci_request_regions(pdev, driver_name);
0410     if (err) {
0411         dev_err(&pdev->dev, "failed to request pci region\n");
0412         goto error_disable;
0413     }
0414 
0415     ptd->hw_base = pci_ioremap_bar(pdev, 0);
0416     if (!ptd->hw_base) {
0417         err = -ENOMEM;
0418         dev_err(&pdev->dev, "failed to map mem base\n");
0419         goto error_release;
0420     }
0421 
0422     err = ptd->ops->hw_init(ptd, &nr_trips);
0423     if (err)
0424         goto error_cleanup;
0425 
0426     ptd->tzd = thermal_zone_device_register(bi->name, nr_trips, 0, ptd,
0427                         &tzd_ops, NULL, 0, 0);
0428     if (IS_ERR(ptd->tzd)) {
0429         dev_err(&pdev->dev, "Failed to register thermal zone %s\n",
0430             bi->name);
0431         err = PTR_ERR(ptd->tzd);
0432         goto error_cleanup;
0433     }
0434     err = thermal_zone_device_enable(ptd->tzd);
0435     if (err)
0436         goto err_unregister;
0437 
0438     return 0;
0439 
0440 err_unregister:
0441     thermal_zone_device_unregister(ptd->tzd);
0442 error_cleanup:
0443     iounmap(ptd->hw_base);
0444 error_release:
0445     pci_release_regions(pdev);
0446 error_disable:
0447     pci_disable_device(pdev);
0448     dev_err(&pdev->dev, "pci device failed to probe\n");
0449     return err;
0450 }
0451 
0452 static void intel_pch_thermal_remove(struct pci_dev *pdev)
0453 {
0454     struct pch_thermal_device *ptd = pci_get_drvdata(pdev);
0455 
0456     thermal_zone_device_unregister(ptd->tzd);
0457     iounmap(ptd->hw_base);
0458     pci_set_drvdata(pdev, NULL);
0459     pci_release_regions(pdev);
0460     pci_disable_device(pdev);
0461 }
0462 
0463 static int intel_pch_thermal_suspend_noirq(struct device *device)
0464 {
0465     struct pch_thermal_device *ptd = dev_get_drvdata(device);
0466 
0467     return ptd->ops->suspend(ptd);
0468 }
0469 
0470 static int intel_pch_thermal_resume(struct device *device)
0471 {
0472     struct pch_thermal_device *ptd = dev_get_drvdata(device);
0473 
0474     return ptd->ops->resume(ptd);
0475 }
0476 
0477 static const struct pci_device_id intel_pch_thermal_id[] = {
0478     { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_HSW_1),
0479         .driver_data = board_hsw, },
0480     { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_HSW_2),
0481         .driver_data = board_hsw, },
0482     { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_WPT),
0483         .driver_data = board_wpt, },
0484     { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_SKL),
0485         .driver_data = board_skl, },
0486     { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_SKL_H),
0487         .driver_data = board_skl, },
0488     { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_CNL),
0489         .driver_data = board_cnl, },
0490     { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_CNL_H),
0491         .driver_data = board_cnl, },
0492     { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_CNL_LP),
0493         .driver_data = board_cnl, },
0494     { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_CML_H),
0495         .driver_data = board_cml, },
0496     { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_LWB),
0497         .driver_data = board_lwb, },
0498     { 0, },
0499 };
0500 MODULE_DEVICE_TABLE(pci, intel_pch_thermal_id);
0501 
0502 static const struct dev_pm_ops intel_pch_pm_ops = {
0503     .suspend_noirq = intel_pch_thermal_suspend_noirq,
0504     .resume = intel_pch_thermal_resume,
0505 };
0506 
0507 static struct pci_driver intel_pch_thermal_driver = {
0508     .name       = "intel_pch_thermal",
0509     .id_table   = intel_pch_thermal_id,
0510     .probe      = intel_pch_thermal_probe,
0511     .remove     = intel_pch_thermal_remove,
0512     .driver.pm  = &intel_pch_pm_ops,
0513 };
0514 
0515 module_pci_driver(intel_pch_thermal_driver);
0516 
0517 MODULE_LICENSE("GPL v2");
0518 MODULE_DESCRIPTION("Intel PCH Thermal driver");