Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * intel_quark_dts_thermal.c
0003  *
0004  * This file is provided under a dual BSD/GPLv2 license.  When using or
0005  * redistributing this file, you may do so under either license.
0006  *
0007  * GPL LICENSE SUMMARY
0008  *
0009  * Copyright(c) 2015 Intel Corporation.
0010  *
0011  * This program is free software; you can redistribute it and/or modify
0012  * it under the terms of version 2 of the GNU General Public License as
0013  * published by the Free Software Foundation.
0014  *
0015  * This program is distributed in the hope that it will be useful, but
0016  *  WITHOUT ANY WARRANTY; without even the implied warranty of
0017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0018  * General Public License for more details.
0019  *
0020  * Contact Information:
0021  *  Ong Boon Leong <boon.leong.ong@intel.com>
0022  *  Intel Malaysia, Penang
0023  *
0024  * BSD LICENSE
0025  *
0026  * Copyright(c) 2015 Intel Corporation.
0027  *
0028  * Redistribution and use in source and binary forms, with or without
0029  * modification, are permitted provided that the following conditions
0030  * are met:
0031  *
0032  *   * Redistributions of source code must retain the above copyright
0033  *     notice, this list of conditions and the following disclaimer.
0034  *   * Redistributions in binary form must reproduce the above copyright
0035  *     notice, this list of conditions and the following disclaimer in
0036  *     the documentation and/or other materials provided with the
0037  *     distribution.
0038  *   * Neither the name of Intel Corporation nor the names of its
0039  *     contributors may be used to endorse or promote products derived
0040  *     from this software without specific prior written permission.
0041  *
0042  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
0043  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
0044  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
0045  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
0046  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
0047  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
0048  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
0049  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
0050  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
0051  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
0052  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0053  *
0054  * Quark DTS thermal driver is implemented by referencing
0055  * intel_soc_dts_thermal.c.
0056  */
0057 
0058 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0059 
0060 #include <linux/module.h>
0061 #include <linux/slab.h>
0062 #include <linux/interrupt.h>
0063 #include <linux/thermal.h>
0064 #include <asm/cpu_device_id.h>
0065 #include <asm/iosf_mbi.h>
0066 
0067 /* DTS reset is programmed via QRK_MBI_UNIT_SOC */
0068 #define QRK_DTS_REG_OFFSET_RESET    0x34
0069 #define QRK_DTS_RESET_BIT       BIT(0)
0070 
0071 /* DTS enable is programmed via QRK_MBI_UNIT_RMU */
0072 #define QRK_DTS_REG_OFFSET_ENABLE   0xB0
0073 #define QRK_DTS_ENABLE_BIT      BIT(15)
0074 
0075 /* Temperature Register is read via QRK_MBI_UNIT_RMU */
0076 #define QRK_DTS_REG_OFFSET_TEMP     0xB1
0077 #define QRK_DTS_MASK_TEMP       0xFF
0078 #define QRK_DTS_OFFSET_TEMP     0
0079 #define QRK_DTS_OFFSET_REL_TEMP     16
0080 #define QRK_DTS_TEMP_BASE       50
0081 
0082 /* Programmable Trip Point Register is configured via QRK_MBI_UNIT_RMU */
0083 #define QRK_DTS_REG_OFFSET_PTPS     0xB2
0084 #define QRK_DTS_MASK_TP_THRES       0xFF
0085 #define QRK_DTS_SHIFT_TP        8
0086 #define QRK_DTS_ID_TP_CRITICAL      0
0087 #define QRK_DTS_SAFE_TP_THRES       105
0088 
0089 /* Thermal Sensor Register Lock */
0090 #define QRK_DTS_REG_OFFSET_LOCK     0x71
0091 #define QRK_DTS_LOCK_BIT        BIT(5)
0092 
0093 /* Quark DTS has 2 trip points: hot & catastrophic */
0094 #define QRK_MAX_DTS_TRIPS   2
0095 /* If DTS not locked, all trip points are configurable */
0096 #define QRK_DTS_WR_MASK_SET 0x3
0097 /* If DTS locked, all trip points are not configurable */
0098 #define QRK_DTS_WR_MASK_CLR 0
0099 
0100 #define DEFAULT_POLL_DELAY  2000
0101 
0102 struct soc_sensor_entry {
0103     bool locked;
0104     u32 store_ptps;
0105     u32 store_dts_enable;
0106     struct thermal_zone_device *tzone;
0107 };
0108 
0109 static struct soc_sensor_entry *soc_dts;
0110 
0111 static int polling_delay = DEFAULT_POLL_DELAY;
0112 module_param(polling_delay, int, 0644);
0113 MODULE_PARM_DESC(polling_delay,
0114     "Polling interval for checking trip points (in milliseconds)");
0115 
0116 static DEFINE_MUTEX(dts_update_mutex);
0117 
0118 static int soc_dts_enable(struct thermal_zone_device *tzd)
0119 {
0120     u32 out;
0121     struct soc_sensor_entry *aux_entry = tzd->devdata;
0122     int ret;
0123 
0124     ret = iosf_mbi_read(QRK_MBI_UNIT_RMU, MBI_REG_READ,
0125                 QRK_DTS_REG_OFFSET_ENABLE, &out);
0126     if (ret)
0127         return ret;
0128 
0129     if (out & QRK_DTS_ENABLE_BIT)
0130         return 0;
0131 
0132     if (!aux_entry->locked) {
0133         out |= QRK_DTS_ENABLE_BIT;
0134         ret = iosf_mbi_write(QRK_MBI_UNIT_RMU, MBI_REG_WRITE,
0135                      QRK_DTS_REG_OFFSET_ENABLE, out);
0136         if (ret)
0137             return ret;
0138     } else {
0139         pr_info("DTS is locked. Cannot enable DTS\n");
0140         ret = -EPERM;
0141     }
0142 
0143     return ret;
0144 }
0145 
0146 static int soc_dts_disable(struct thermal_zone_device *tzd)
0147 {
0148     u32 out;
0149     struct soc_sensor_entry *aux_entry = tzd->devdata;
0150     int ret;
0151 
0152     ret = iosf_mbi_read(QRK_MBI_UNIT_RMU, MBI_REG_READ,
0153                 QRK_DTS_REG_OFFSET_ENABLE, &out);
0154     if (ret)
0155         return ret;
0156 
0157     if (!(out & QRK_DTS_ENABLE_BIT))
0158         return 0;
0159 
0160     if (!aux_entry->locked) {
0161         out &= ~QRK_DTS_ENABLE_BIT;
0162         ret = iosf_mbi_write(QRK_MBI_UNIT_RMU, MBI_REG_WRITE,
0163                      QRK_DTS_REG_OFFSET_ENABLE, out);
0164 
0165         if (ret)
0166             return ret;
0167     } else {
0168         pr_info("DTS is locked. Cannot disable DTS\n");
0169         ret = -EPERM;
0170     }
0171 
0172     return ret;
0173 }
0174 
0175 static int _get_trip_temp(int trip, int *temp)
0176 {
0177     int status;
0178     u32 out;
0179 
0180     mutex_lock(&dts_update_mutex);
0181     status = iosf_mbi_read(QRK_MBI_UNIT_RMU, MBI_REG_READ,
0182                    QRK_DTS_REG_OFFSET_PTPS, &out);
0183     mutex_unlock(&dts_update_mutex);
0184 
0185     if (status)
0186         return status;
0187 
0188     /*
0189      * Thermal Sensor Programmable Trip Point Register has 8-bit
0190      * fields for critical (catastrophic) and hot set trip point
0191      * thresholds. The threshold value is always offset by its
0192      * temperature base (50 degree Celsius).
0193      */
0194     *temp = (out >> (trip * QRK_DTS_SHIFT_TP)) & QRK_DTS_MASK_TP_THRES;
0195     *temp -= QRK_DTS_TEMP_BASE;
0196 
0197     return 0;
0198 }
0199 
0200 static inline int sys_get_trip_temp(struct thermal_zone_device *tzd,
0201                 int trip, int *temp)
0202 {
0203     return _get_trip_temp(trip, temp);
0204 }
0205 
0206 static inline int sys_get_crit_temp(struct thermal_zone_device *tzd, int *temp)
0207 {
0208     return _get_trip_temp(QRK_DTS_ID_TP_CRITICAL, temp);
0209 }
0210 
0211 static int update_trip_temp(struct soc_sensor_entry *aux_entry,
0212                 int trip, int temp)
0213 {
0214     u32 out;
0215     u32 temp_out;
0216     u32 store_ptps;
0217     int ret;
0218 
0219     mutex_lock(&dts_update_mutex);
0220     if (aux_entry->locked) {
0221         ret = -EPERM;
0222         goto failed;
0223     }
0224 
0225     ret = iosf_mbi_read(QRK_MBI_UNIT_RMU, MBI_REG_READ,
0226                 QRK_DTS_REG_OFFSET_PTPS, &store_ptps);
0227     if (ret)
0228         goto failed;
0229 
0230     /*
0231      * Protection against unsafe trip point thresdhold value.
0232      * As Quark X1000 data-sheet does not provide any recommendation
0233      * regarding the safe trip point threshold value to use, we choose
0234      * the safe value according to the threshold value set by UEFI BIOS.
0235      */
0236     if (temp > QRK_DTS_SAFE_TP_THRES)
0237         temp = QRK_DTS_SAFE_TP_THRES;
0238 
0239     /*
0240      * Thermal Sensor Programmable Trip Point Register has 8-bit
0241      * fields for critical (catastrophic) and hot set trip point
0242      * thresholds. The threshold value is always offset by its
0243      * temperature base (50 degree Celsius).
0244      */
0245     temp_out = temp + QRK_DTS_TEMP_BASE;
0246     out = (store_ptps & ~(QRK_DTS_MASK_TP_THRES <<
0247         (trip * QRK_DTS_SHIFT_TP)));
0248     out |= (temp_out & QRK_DTS_MASK_TP_THRES) <<
0249         (trip * QRK_DTS_SHIFT_TP);
0250 
0251     ret = iosf_mbi_write(QRK_MBI_UNIT_RMU, MBI_REG_WRITE,
0252                  QRK_DTS_REG_OFFSET_PTPS, out);
0253 
0254 failed:
0255     mutex_unlock(&dts_update_mutex);
0256     return ret;
0257 }
0258 
0259 static inline int sys_set_trip_temp(struct thermal_zone_device *tzd, int trip,
0260                 int temp)
0261 {
0262     return update_trip_temp(tzd->devdata, trip, temp);
0263 }
0264 
0265 static int sys_get_trip_type(struct thermal_zone_device *thermal,
0266         int trip, enum thermal_trip_type *type)
0267 {
0268     if (trip)
0269         *type = THERMAL_TRIP_HOT;
0270     else
0271         *type = THERMAL_TRIP_CRITICAL;
0272 
0273     return 0;
0274 }
0275 
0276 static int sys_get_curr_temp(struct thermal_zone_device *tzd,
0277                 int *temp)
0278 {
0279     u32 out;
0280     int ret;
0281 
0282     mutex_lock(&dts_update_mutex);
0283     ret = iosf_mbi_read(QRK_MBI_UNIT_RMU, MBI_REG_READ,
0284                 QRK_DTS_REG_OFFSET_TEMP, &out);
0285     mutex_unlock(&dts_update_mutex);
0286 
0287     if (ret)
0288         return ret;
0289 
0290     /*
0291      * Thermal Sensor Temperature Register has 8-bit field
0292      * for temperature value (offset by temperature base
0293      * 50 degree Celsius).
0294      */
0295     out = (out >> QRK_DTS_OFFSET_TEMP) & QRK_DTS_MASK_TEMP;
0296     *temp = out - QRK_DTS_TEMP_BASE;
0297 
0298     return 0;
0299 }
0300 
0301 static int sys_change_mode(struct thermal_zone_device *tzd,
0302                enum thermal_device_mode mode)
0303 {
0304     int ret;
0305 
0306     mutex_lock(&dts_update_mutex);
0307     if (mode == THERMAL_DEVICE_ENABLED)
0308         ret = soc_dts_enable(tzd);
0309     else
0310         ret = soc_dts_disable(tzd);
0311     mutex_unlock(&dts_update_mutex);
0312 
0313     return ret;
0314 }
0315 
0316 static struct thermal_zone_device_ops tzone_ops = {
0317     .get_temp = sys_get_curr_temp,
0318     .get_trip_temp = sys_get_trip_temp,
0319     .get_trip_type = sys_get_trip_type,
0320     .set_trip_temp = sys_set_trip_temp,
0321     .get_crit_temp = sys_get_crit_temp,
0322     .change_mode = sys_change_mode,
0323 };
0324 
0325 static void free_soc_dts(struct soc_sensor_entry *aux_entry)
0326 {
0327     if (aux_entry) {
0328         if (!aux_entry->locked) {
0329             mutex_lock(&dts_update_mutex);
0330             iosf_mbi_write(QRK_MBI_UNIT_RMU, MBI_REG_WRITE,
0331                        QRK_DTS_REG_OFFSET_ENABLE,
0332                        aux_entry->store_dts_enable);
0333 
0334             iosf_mbi_write(QRK_MBI_UNIT_RMU, MBI_REG_WRITE,
0335                        QRK_DTS_REG_OFFSET_PTPS,
0336                        aux_entry->store_ptps);
0337             mutex_unlock(&dts_update_mutex);
0338         }
0339         thermal_zone_device_unregister(aux_entry->tzone);
0340         kfree(aux_entry);
0341     }
0342 }
0343 
0344 static struct soc_sensor_entry *alloc_soc_dts(void)
0345 {
0346     struct soc_sensor_entry *aux_entry;
0347     int err;
0348     u32 out;
0349     int wr_mask;
0350 
0351     aux_entry = kzalloc(sizeof(*aux_entry), GFP_KERNEL);
0352     if (!aux_entry) {
0353         err = -ENOMEM;
0354         return ERR_PTR(-ENOMEM);
0355     }
0356 
0357     /* Check if DTS register is locked */
0358     err = iosf_mbi_read(QRK_MBI_UNIT_RMU, MBI_REG_READ,
0359                 QRK_DTS_REG_OFFSET_LOCK, &out);
0360     if (err)
0361         goto err_ret;
0362 
0363     if (out & QRK_DTS_LOCK_BIT) {
0364         aux_entry->locked = true;
0365         wr_mask = QRK_DTS_WR_MASK_CLR;
0366     } else {
0367         aux_entry->locked = false;
0368         wr_mask = QRK_DTS_WR_MASK_SET;
0369     }
0370 
0371     /* Store DTS default state if DTS registers are not locked */
0372     if (!aux_entry->locked) {
0373         /* Store DTS default enable for restore on exit */
0374         err = iosf_mbi_read(QRK_MBI_UNIT_RMU, MBI_REG_READ,
0375                     QRK_DTS_REG_OFFSET_ENABLE,
0376                     &aux_entry->store_dts_enable);
0377         if (err)
0378             goto err_ret;
0379 
0380         /* Store DTS default PTPS register for restore on exit */
0381         err = iosf_mbi_read(QRK_MBI_UNIT_RMU, MBI_REG_READ,
0382                     QRK_DTS_REG_OFFSET_PTPS,
0383                     &aux_entry->store_ptps);
0384         if (err)
0385             goto err_ret;
0386     }
0387 
0388     aux_entry->tzone = thermal_zone_device_register("quark_dts",
0389             QRK_MAX_DTS_TRIPS,
0390             wr_mask,
0391             aux_entry, &tzone_ops, NULL, 0, polling_delay);
0392     if (IS_ERR(aux_entry->tzone)) {
0393         err = PTR_ERR(aux_entry->tzone);
0394         goto err_ret;
0395     }
0396 
0397     err = thermal_zone_device_enable(aux_entry->tzone);
0398     if (err)
0399         goto err_aux_status;
0400 
0401     return aux_entry;
0402 
0403 err_aux_status:
0404     thermal_zone_device_unregister(aux_entry->tzone);
0405 err_ret:
0406     kfree(aux_entry);
0407     return ERR_PTR(err);
0408 }
0409 
0410 static const struct x86_cpu_id qrk_thermal_ids[] __initconst  = {
0411     X86_MATCH_VENDOR_FAM_MODEL(INTEL, 5, INTEL_FAM5_QUARK_X1000, NULL),
0412     {}
0413 };
0414 MODULE_DEVICE_TABLE(x86cpu, qrk_thermal_ids);
0415 
0416 static int __init intel_quark_thermal_init(void)
0417 {
0418     int err = 0;
0419 
0420     if (!x86_match_cpu(qrk_thermal_ids) || !iosf_mbi_available())
0421         return -ENODEV;
0422 
0423     soc_dts = alloc_soc_dts();
0424     if (IS_ERR(soc_dts)) {
0425         err = PTR_ERR(soc_dts);
0426         goto err_free;
0427     }
0428 
0429     return 0;
0430 
0431 err_free:
0432     free_soc_dts(soc_dts);
0433     return err;
0434 }
0435 
0436 static void __exit intel_quark_thermal_exit(void)
0437 {
0438     free_soc_dts(soc_dts);
0439 }
0440 
0441 module_init(intel_quark_thermal_init)
0442 module_exit(intel_quark_thermal_exit)
0443 
0444 MODULE_DESCRIPTION("Intel Quark DTS Thermal Driver");
0445 MODULE_AUTHOR("Ong Boon Leong <boon.leong.ong@intel.com>");
0446 MODULE_LICENSE("Dual BSD/GPL");