1 /* 2 * intel_quark_dts_thermal.c 3 * 4 * This file is provided under a dual BSD/GPLv2 license. When using or 5 * redistributing this file, you may do so under either license. 6 * 7 * GPL LICENSE SUMMARY 8 * 9 * Copyright(c) 2015 Intel Corporation. 10 * 11 * This program is free software; you can redistribute it and/or modify 12 * it under the terms of version 2 of the GNU General Public License as 13 * published by the Free Software Foundation. 14 * 15 * This program is distributed in the hope that it will be useful, but 16 * WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18 * General Public License for more details. 19 * 20 * Contact Information: 21 * Ong Boon Leong <boon.leong.ong@intel.com> 22 * Intel Malaysia, Penang 23 * 24 * BSD LICENSE 25 * 26 * Copyright(c) 2015 Intel Corporation. 27 * 28 * Redistribution and use in source and binary forms, with or without 29 * modification, are permitted provided that the following conditions 30 * are met: 31 * 32 * * Redistributions of source code must retain the above copyright 33 * notice, this list of conditions and the following disclaimer. 34 * * Redistributions in binary form must reproduce the above copyright 35 * notice, this list of conditions and the following disclaimer in 36 * the documentation and/or other materials provided with the 37 * distribution. 38 * * Neither the name of Intel Corporation nor the names of its 39 * contributors may be used to endorse or promote products derived 40 * from this software without specific prior written permission. 41 * 42 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 43 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 44 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 45 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 46 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 47 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 48 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 49 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 50 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 51 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 52 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 53 * 54 * Quark DTS thermal driver is implemented by referencing 55 * intel_soc_dts_thermal.c. 56 */ 57 58 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 59 60 #include <linux/module.h> 61 #include <linux/slab.h> 62 #include <linux/interrupt.h> 63 #include <linux/thermal.h> 64 #include <asm/cpu_device_id.h> 65 #include <asm/iosf_mbi.h> 66 67 /* DTS reset is programmed via QRK_MBI_UNIT_SOC */ 68 #define QRK_DTS_REG_OFFSET_RESET 0x34 69 #define QRK_DTS_RESET_BIT BIT(0) 70 71 /* DTS enable is programmed via QRK_MBI_UNIT_RMU */ 72 #define QRK_DTS_REG_OFFSET_ENABLE 0xB0 73 #define QRK_DTS_ENABLE_BIT BIT(15) 74 75 /* Temperature Register is read via QRK_MBI_UNIT_RMU */ 76 #define QRK_DTS_REG_OFFSET_TEMP 0xB1 77 #define QRK_DTS_MASK_TEMP 0xFF 78 #define QRK_DTS_OFFSET_TEMP 0 79 #define QRK_DTS_OFFSET_REL_TEMP 16 80 #define QRK_DTS_TEMP_BASE 50 81 82 /* Programmable Trip Point Register is configured via QRK_MBI_UNIT_RMU */ 83 #define QRK_DTS_REG_OFFSET_PTPS 0xB2 84 #define QRK_DTS_MASK_TP_THRES 0xFF 85 #define QRK_DTS_SHIFT_TP 8 86 #define QRK_DTS_ID_TP_CRITICAL 0 87 #define QRK_DTS_SAFE_TP_THRES 105 88 89 /* Thermal Sensor Register Lock */ 90 #define QRK_DTS_REG_OFFSET_LOCK 0x71 91 #define QRK_DTS_LOCK_BIT BIT(5) 92 93 /* Quark DTS has 2 trip points: hot & catastrophic */ 94 #define QRK_MAX_DTS_TRIPS 2 95 /* If DTS not locked, all trip points are configurable */ 96 #define QRK_DTS_WR_MASK_SET 0x3 97 /* If DTS locked, all trip points are not configurable */ 98 #define QRK_DTS_WR_MASK_CLR 0 99 100 #define DEFAULT_POLL_DELAY 2000 101 102 struct soc_sensor_entry { 103 bool locked; 104 u32 store_ptps; 105 u32 store_dts_enable; 106 struct thermal_zone_device *tzone; 107 }; 108 109 static struct soc_sensor_entry *soc_dts; 110 111 static int polling_delay = DEFAULT_POLL_DELAY; 112 module_param(polling_delay, int, 0644); 113 MODULE_PARM_DESC(polling_delay, 114 "Polling interval for checking trip points (in milliseconds)"); 115 116 static DEFINE_MUTEX(dts_update_mutex); 117 118 static int soc_dts_enable(struct thermal_zone_device *tzd) 119 { 120 u32 out; 121 struct soc_sensor_entry *aux_entry = tzd->devdata; 122 int ret; 123 124 ret = iosf_mbi_read(QRK_MBI_UNIT_RMU, MBI_REG_READ, 125 QRK_DTS_REG_OFFSET_ENABLE, &out); 126 if (ret) 127 return ret; 128 129 if (out & QRK_DTS_ENABLE_BIT) 130 return 0; 131 132 if (!aux_entry->locked) { 133 out |= QRK_DTS_ENABLE_BIT; 134 ret = iosf_mbi_write(QRK_MBI_UNIT_RMU, MBI_REG_WRITE, 135 QRK_DTS_REG_OFFSET_ENABLE, out); 136 if (ret) 137 return ret; 138 } else { 139 pr_info("DTS is locked. Cannot enable DTS\n"); 140 ret = -EPERM; 141 } 142 143 return ret; 144 } 145 146 static int soc_dts_disable(struct thermal_zone_device *tzd) 147 { 148 u32 out; 149 struct soc_sensor_entry *aux_entry = tzd->devdata; 150 int ret; 151 152 ret = iosf_mbi_read(QRK_MBI_UNIT_RMU, MBI_REG_READ, 153 QRK_DTS_REG_OFFSET_ENABLE, &out); 154 if (ret) 155 return ret; 156 157 if (!(out & QRK_DTS_ENABLE_BIT)) 158 return 0; 159 160 if (!aux_entry->locked) { 161 out &= ~QRK_DTS_ENABLE_BIT; 162 ret = iosf_mbi_write(QRK_MBI_UNIT_RMU, MBI_REG_WRITE, 163 QRK_DTS_REG_OFFSET_ENABLE, out); 164 165 if (ret) 166 return ret; 167 } else { 168 pr_info("DTS is locked. Cannot disable DTS\n"); 169 ret = -EPERM; 170 } 171 172 return ret; 173 } 174 175 static int _get_trip_temp(int trip, int *temp) 176 { 177 int status; 178 u32 out; 179 180 mutex_lock(&dts_update_mutex); 181 status = iosf_mbi_read(QRK_MBI_UNIT_RMU, MBI_REG_READ, 182 QRK_DTS_REG_OFFSET_PTPS, &out); 183 mutex_unlock(&dts_update_mutex); 184 185 if (status) 186 return status; 187 188 /* 189 * Thermal Sensor Programmable Trip Point Register has 8-bit 190 * fields for critical (catastrophic) and hot set trip point 191 * thresholds. The threshold value is always offset by its 192 * temperature base (50 degree Celsius). 193 */ 194 *temp = (out >> (trip * QRK_DTS_SHIFT_TP)) & QRK_DTS_MASK_TP_THRES; 195 *temp -= QRK_DTS_TEMP_BASE; 196 197 return 0; 198 } 199 200 static inline int sys_get_trip_temp(struct thermal_zone_device *tzd, 201 int trip, int *temp) 202 { 203 return _get_trip_temp(trip, temp); 204 } 205 206 static inline int sys_get_crit_temp(struct thermal_zone_device *tzd, int *temp) 207 { 208 return _get_trip_temp(QRK_DTS_ID_TP_CRITICAL, temp); 209 } 210 211 static int update_trip_temp(struct soc_sensor_entry *aux_entry, 212 int trip, int temp) 213 { 214 u32 out; 215 u32 temp_out; 216 u32 store_ptps; 217 int ret; 218 219 mutex_lock(&dts_update_mutex); 220 if (aux_entry->locked) { 221 ret = -EPERM; 222 goto failed; 223 } 224 225 ret = iosf_mbi_read(QRK_MBI_UNIT_RMU, MBI_REG_READ, 226 QRK_DTS_REG_OFFSET_PTPS, &store_ptps); 227 if (ret) 228 goto failed; 229 230 /* 231 * Protection against unsafe trip point thresdhold value. 232 * As Quark X1000 data-sheet does not provide any recommendation 233 * regarding the safe trip point threshold value to use, we choose 234 * the safe value according to the threshold value set by UEFI BIOS. 235 */ 236 if (temp > QRK_DTS_SAFE_TP_THRES) 237 temp = QRK_DTS_SAFE_TP_THRES; 238 239 /* 240 * Thermal Sensor Programmable Trip Point Register has 8-bit 241 * fields for critical (catastrophic) and hot set trip point 242 * thresholds. The threshold value is always offset by its 243 * temperature base (50 degree Celsius). 244 */ 245 temp_out = temp + QRK_DTS_TEMP_BASE; 246 out = (store_ptps & ~(QRK_DTS_MASK_TP_THRES << 247 (trip * QRK_DTS_SHIFT_TP))); 248 out |= (temp_out & QRK_DTS_MASK_TP_THRES) << 249 (trip * QRK_DTS_SHIFT_TP); 250 251 ret = iosf_mbi_write(QRK_MBI_UNIT_RMU, MBI_REG_WRITE, 252 QRK_DTS_REG_OFFSET_PTPS, out); 253 254 failed: 255 mutex_unlock(&dts_update_mutex); 256 return ret; 257 } 258 259 static inline int sys_set_trip_temp(struct thermal_zone_device *tzd, int trip, 260 int temp) 261 { 262 return update_trip_temp(tzd->devdata, trip, temp); 263 } 264 265 static int sys_get_trip_type(struct thermal_zone_device *thermal, 266 int trip, enum thermal_trip_type *type) 267 { 268 if (trip) 269 *type = THERMAL_TRIP_HOT; 270 else 271 *type = THERMAL_TRIP_CRITICAL; 272 273 return 0; 274 } 275 276 static int sys_get_curr_temp(struct thermal_zone_device *tzd, 277 int *temp) 278 { 279 u32 out; 280 int ret; 281 282 mutex_lock(&dts_update_mutex); 283 ret = iosf_mbi_read(QRK_MBI_UNIT_RMU, MBI_REG_READ, 284 QRK_DTS_REG_OFFSET_TEMP, &out); 285 mutex_unlock(&dts_update_mutex); 286 287 if (ret) 288 return ret; 289 290 /* 291 * Thermal Sensor Temperature Register has 8-bit field 292 * for temperature value (offset by temperature base 293 * 50 degree Celsius). 294 */ 295 out = (out >> QRK_DTS_OFFSET_TEMP) & QRK_DTS_MASK_TEMP; 296 *temp = out - QRK_DTS_TEMP_BASE; 297 298 return 0; 299 } 300 301 static int sys_change_mode(struct thermal_zone_device *tzd, 302 enum thermal_device_mode mode) 303 { 304 int ret; 305 306 mutex_lock(&dts_update_mutex); 307 if (mode == THERMAL_DEVICE_ENABLED) 308 ret = soc_dts_enable(tzd); 309 else 310 ret = soc_dts_disable(tzd); 311 mutex_unlock(&dts_update_mutex); 312 313 return ret; 314 } 315 316 static struct thermal_zone_device_ops tzone_ops = { 317 .get_temp = sys_get_curr_temp, 318 .get_trip_temp = sys_get_trip_temp, 319 .get_trip_type = sys_get_trip_type, 320 .set_trip_temp = sys_set_trip_temp, 321 .get_crit_temp = sys_get_crit_temp, 322 .change_mode = sys_change_mode, 323 }; 324 325 static void free_soc_dts(struct soc_sensor_entry *aux_entry) 326 { 327 if (aux_entry) { 328 if (!aux_entry->locked) { 329 mutex_lock(&dts_update_mutex); 330 iosf_mbi_write(QRK_MBI_UNIT_RMU, MBI_REG_WRITE, 331 QRK_DTS_REG_OFFSET_ENABLE, 332 aux_entry->store_dts_enable); 333 334 iosf_mbi_write(QRK_MBI_UNIT_RMU, MBI_REG_WRITE, 335 QRK_DTS_REG_OFFSET_PTPS, 336 aux_entry->store_ptps); 337 mutex_unlock(&dts_update_mutex); 338 } 339 thermal_zone_device_unregister(aux_entry->tzone); 340 kfree(aux_entry); 341 } 342 } 343 344 static struct soc_sensor_entry *alloc_soc_dts(void) 345 { 346 struct soc_sensor_entry *aux_entry; 347 int err; 348 u32 out; 349 int wr_mask; 350 351 aux_entry = kzalloc(sizeof(*aux_entry), GFP_KERNEL); 352 if (!aux_entry) { 353 err = -ENOMEM; 354 return ERR_PTR(-ENOMEM); 355 } 356 357 /* Check if DTS register is locked */ 358 err = iosf_mbi_read(QRK_MBI_UNIT_RMU, MBI_REG_READ, 359 QRK_DTS_REG_OFFSET_LOCK, &out); 360 if (err) 361 goto err_ret; 362 363 if (out & QRK_DTS_LOCK_BIT) { 364 aux_entry->locked = true; 365 wr_mask = QRK_DTS_WR_MASK_CLR; 366 } else { 367 aux_entry->locked = false; 368 wr_mask = QRK_DTS_WR_MASK_SET; 369 } 370 371 /* Store DTS default state if DTS registers are not locked */ 372 if (!aux_entry->locked) { 373 /* Store DTS default enable for restore on exit */ 374 err = iosf_mbi_read(QRK_MBI_UNIT_RMU, MBI_REG_READ, 375 QRK_DTS_REG_OFFSET_ENABLE, 376 &aux_entry->store_dts_enable); 377 if (err) 378 goto err_ret; 379 380 /* Store DTS default PTPS register for restore on exit */ 381 err = iosf_mbi_read(QRK_MBI_UNIT_RMU, MBI_REG_READ, 382 QRK_DTS_REG_OFFSET_PTPS, 383 &aux_entry->store_ptps); 384 if (err) 385 goto err_ret; 386 } 387 388 aux_entry->tzone = thermal_zone_device_register("quark_dts", 389 QRK_MAX_DTS_TRIPS, 390 wr_mask, 391 aux_entry, &tzone_ops, NULL, 0, polling_delay); 392 if (IS_ERR(aux_entry->tzone)) { 393 err = PTR_ERR(aux_entry->tzone); 394 goto err_ret; 395 } 396 397 err = thermal_zone_device_enable(aux_entry->tzone); 398 if (err) 399 goto err_aux_status; 400 401 return aux_entry; 402 403 err_aux_status: 404 thermal_zone_device_unregister(aux_entry->tzone); 405 err_ret: 406 kfree(aux_entry); 407 return ERR_PTR(err); 408 } 409 410 static const struct x86_cpu_id qrk_thermal_ids[] __initconst = { 411 X86_MATCH_VENDOR_FAM_MODEL(INTEL, 5, INTEL_FAM5_QUARK_X1000, NULL), 412 {} 413 }; 414 MODULE_DEVICE_TABLE(x86cpu, qrk_thermal_ids); 415 416 static int __init intel_quark_thermal_init(void) 417 { 418 int err = 0; 419 420 if (!x86_match_cpu(qrk_thermal_ids) || !iosf_mbi_available()) 421 return -ENODEV; 422 423 soc_dts = alloc_soc_dts(); 424 if (IS_ERR(soc_dts)) { 425 err = PTR_ERR(soc_dts); 426 goto err_free; 427 } 428 429 return 0; 430 431 err_free: 432 free_soc_dts(soc_dts); 433 return err; 434 } 435 436 static void __exit intel_quark_thermal_exit(void) 437 { 438 free_soc_dts(soc_dts); 439 } 440 441 module_init(intel_quark_thermal_init) 442 module_exit(intel_quark_thermal_exit) 443 444 MODULE_DESCRIPTION("Intel Quark DTS Thermal Driver"); 445 MODULE_AUTHOR("Ong Boon Leong <boon.leong.ong@intel.com>"); 446 MODULE_LICENSE("Dual BSD/GPL"); 447