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#define X86_FAMILY_QUARK 0x5 68#define X86_MODEL_QUARK_X1000 0x9 69 70/* DTS reset is programmed via QRK_MBI_UNIT_SOC */ 71#define QRK_DTS_REG_OFFSET_RESET 0x34 72#define QRK_DTS_RESET_BIT BIT(0) 73 74/* DTS enable is programmed via QRK_MBI_UNIT_RMU */ 75#define QRK_DTS_REG_OFFSET_ENABLE 0xB0 76#define QRK_DTS_ENABLE_BIT BIT(15) 77 78/* Temperature Register is read via QRK_MBI_UNIT_RMU */ 79#define QRK_DTS_REG_OFFSET_TEMP 0xB1 80#define QRK_DTS_MASK_TEMP 0xFF 81#define QRK_DTS_OFFSET_TEMP 0 82#define QRK_DTS_OFFSET_REL_TEMP 16 83#define QRK_DTS_TEMP_BASE 50 84 85/* Programmable Trip Point Register is configured via QRK_MBI_UNIT_RMU */ 86#define QRK_DTS_REG_OFFSET_PTPS 0xB2 87#define QRK_DTS_MASK_TP_THRES 0xFF 88#define QRK_DTS_SHIFT_TP 8 89#define QRK_DTS_ID_TP_CRITICAL 0 90#define QRK_DTS_SAFE_TP_THRES 105 91 92/* Thermal Sensor Register Lock */ 93#define QRK_DTS_REG_OFFSET_LOCK 0x71 94#define QRK_DTS_LOCK_BIT BIT(5) 95 96/* Quark DTS has 2 trip points: hot & catastrophic */ 97#define QRK_MAX_DTS_TRIPS 2 98/* If DTS not locked, all trip points are configurable */ 99#define QRK_DTS_WR_MASK_SET 0x3 100/* If DTS locked, all trip points are not configurable */ 101#define QRK_DTS_WR_MASK_CLR 0 102 103#define DEFAULT_POLL_DELAY 2000 104 105struct soc_sensor_entry { 106 bool locked; 107 u32 store_ptps; 108 u32 store_dts_enable; 109 enum thermal_device_mode mode; 110 struct thermal_zone_device *tzone; 111}; 112 113static struct soc_sensor_entry *soc_dts; 114 115static int polling_delay = DEFAULT_POLL_DELAY; 116module_param(polling_delay, int, 0644); 117MODULE_PARM_DESC(polling_delay, 118 "Polling interval for checking trip points (in milliseconds)"); 119 120static DEFINE_MUTEX(dts_update_mutex); 121 122static int soc_dts_enable(struct thermal_zone_device *tzd) 123{ 124 u32 out; 125 struct soc_sensor_entry *aux_entry = tzd->devdata; 126 int ret; 127 128 ret = iosf_mbi_read(QRK_MBI_UNIT_RMU, QRK_MBI_RMU_READ, 129 QRK_DTS_REG_OFFSET_ENABLE, &out); 130 if (ret) 131 return ret; 132 133 if (out & QRK_DTS_ENABLE_BIT) { 134 aux_entry->mode = THERMAL_DEVICE_ENABLED; 135 return 0; 136 } 137 138 if (!aux_entry->locked) { 139 out |= QRK_DTS_ENABLE_BIT; 140 ret = iosf_mbi_write(QRK_MBI_UNIT_RMU, QRK_MBI_RMU_WRITE, 141 QRK_DTS_REG_OFFSET_ENABLE, out); 142 if (ret) 143 return ret; 144 145 aux_entry->mode = THERMAL_DEVICE_ENABLED; 146 } else { 147 aux_entry->mode = THERMAL_DEVICE_DISABLED; 148 pr_info("DTS is locked. Cannot enable DTS\n"); 149 ret = -EPERM; 150 } 151 152 return ret; 153} 154 155static int soc_dts_disable(struct thermal_zone_device *tzd) 156{ 157 u32 out; 158 struct soc_sensor_entry *aux_entry = tzd->devdata; 159 int ret; 160 161 ret = iosf_mbi_read(QRK_MBI_UNIT_RMU, QRK_MBI_RMU_READ, 162 QRK_DTS_REG_OFFSET_ENABLE, &out); 163 if (ret) 164 return ret; 165 166 if (!(out & QRK_DTS_ENABLE_BIT)) { 167 aux_entry->mode = THERMAL_DEVICE_DISABLED; 168 return 0; 169 } 170 171 if (!aux_entry->locked) { 172 out &= ~QRK_DTS_ENABLE_BIT; 173 ret = iosf_mbi_write(QRK_MBI_UNIT_RMU, QRK_MBI_RMU_WRITE, 174 QRK_DTS_REG_OFFSET_ENABLE, out); 175 176 if (ret) 177 return ret; 178 179 aux_entry->mode = THERMAL_DEVICE_DISABLED; 180 } else { 181 aux_entry->mode = THERMAL_DEVICE_ENABLED; 182 pr_info("DTS is locked. Cannot disable DTS\n"); 183 ret = -EPERM; 184 } 185 186 return ret; 187} 188 189static int _get_trip_temp(int trip, int *temp) 190{ 191 int status; 192 u32 out; 193 194 mutex_lock(&dts_update_mutex); 195 status = iosf_mbi_read(QRK_MBI_UNIT_RMU, QRK_MBI_RMU_READ, 196 QRK_DTS_REG_OFFSET_PTPS, &out); 197 mutex_unlock(&dts_update_mutex); 198 199 if (status) 200 return status; 201 202 /* 203 * Thermal Sensor Programmable Trip Point Register has 8-bit 204 * fields for critical (catastrophic) and hot set trip point 205 * thresholds. The threshold value is always offset by its 206 * temperature base (50 degree Celsius). 207 */ 208 *temp = (out >> (trip * QRK_DTS_SHIFT_TP)) & QRK_DTS_MASK_TP_THRES; 209 *temp -= QRK_DTS_TEMP_BASE; 210 211 return 0; 212} 213 214static inline int sys_get_trip_temp(struct thermal_zone_device *tzd, 215 int trip, int *temp) 216{ 217 return _get_trip_temp(trip, temp); 218} 219 220static inline int sys_get_crit_temp(struct thermal_zone_device *tzd, int *temp) 221{ 222 return _get_trip_temp(QRK_DTS_ID_TP_CRITICAL, temp); 223} 224 225static int update_trip_temp(struct soc_sensor_entry *aux_entry, 226 int trip, int temp) 227{ 228 u32 out; 229 u32 temp_out; 230 u32 store_ptps; 231 int ret; 232 233 mutex_lock(&dts_update_mutex); 234 if (aux_entry->locked) { 235 ret = -EPERM; 236 goto failed; 237 } 238 239 ret = iosf_mbi_read(QRK_MBI_UNIT_RMU, QRK_MBI_RMU_READ, 240 QRK_DTS_REG_OFFSET_PTPS, &store_ptps); 241 if (ret) 242 goto failed; 243 244 /* 245 * Protection against unsafe trip point thresdhold value. 246 * As Quark X1000 data-sheet does not provide any recommendation 247 * regarding the safe trip point threshold value to use, we choose 248 * the safe value according to the threshold value set by UEFI BIOS. 249 */ 250 if (temp > QRK_DTS_SAFE_TP_THRES) 251 temp = QRK_DTS_SAFE_TP_THRES; 252 253 /* 254 * Thermal Sensor Programmable Trip Point Register has 8-bit 255 * fields for critical (catastrophic) and hot set trip point 256 * thresholds. The threshold value is always offset by its 257 * temperature base (50 degree Celsius). 258 */ 259 temp_out = temp + QRK_DTS_TEMP_BASE; 260 out = (store_ptps & ~(QRK_DTS_MASK_TP_THRES << 261 (trip * QRK_DTS_SHIFT_TP))); 262 out |= (temp_out & QRK_DTS_MASK_TP_THRES) << 263 (trip * QRK_DTS_SHIFT_TP); 264 265 ret = iosf_mbi_write(QRK_MBI_UNIT_RMU, QRK_MBI_RMU_WRITE, 266 QRK_DTS_REG_OFFSET_PTPS, out); 267 268failed: 269 mutex_unlock(&dts_update_mutex); 270 return ret; 271} 272 273static inline int sys_set_trip_temp(struct thermal_zone_device *tzd, int trip, 274 int temp) 275{ 276 return update_trip_temp(tzd->devdata, trip, temp); 277} 278 279static int sys_get_trip_type(struct thermal_zone_device *thermal, 280 int trip, enum thermal_trip_type *type) 281{ 282 if (trip) 283 *type = THERMAL_TRIP_HOT; 284 else 285 *type = THERMAL_TRIP_CRITICAL; 286 287 return 0; 288} 289 290static int sys_get_curr_temp(struct thermal_zone_device *tzd, 291 int *temp) 292{ 293 u32 out; 294 int ret; 295 296 mutex_lock(&dts_update_mutex); 297 ret = iosf_mbi_read(QRK_MBI_UNIT_RMU, QRK_MBI_RMU_READ, 298 QRK_DTS_REG_OFFSET_TEMP, &out); 299 mutex_unlock(&dts_update_mutex); 300 301 if (ret) 302 return ret; 303 304 /* 305 * Thermal Sensor Temperature Register has 8-bit field 306 * for temperature value (offset by temperature base 307 * 50 degree Celsius). 308 */ 309 out = (out >> QRK_DTS_OFFSET_TEMP) & QRK_DTS_MASK_TEMP; 310 *temp = out - QRK_DTS_TEMP_BASE; 311 312 return 0; 313} 314 315static int sys_get_mode(struct thermal_zone_device *tzd, 316 enum thermal_device_mode *mode) 317{ 318 struct soc_sensor_entry *aux_entry = tzd->devdata; 319 *mode = aux_entry->mode; 320 return 0; 321} 322 323static int sys_set_mode(struct thermal_zone_device *tzd, 324 enum thermal_device_mode mode) 325{ 326 int ret; 327 328 mutex_lock(&dts_update_mutex); 329 if (mode == THERMAL_DEVICE_ENABLED) 330 ret = soc_dts_enable(tzd); 331 else 332 ret = soc_dts_disable(tzd); 333 mutex_unlock(&dts_update_mutex); 334 335 return ret; 336} 337 338static struct thermal_zone_device_ops tzone_ops = { 339 .get_temp = sys_get_curr_temp, 340 .get_trip_temp = sys_get_trip_temp, 341 .get_trip_type = sys_get_trip_type, 342 .set_trip_temp = sys_set_trip_temp, 343 .get_crit_temp = sys_get_crit_temp, 344 .get_mode = sys_get_mode, 345 .set_mode = sys_set_mode, 346}; 347 348static void free_soc_dts(struct soc_sensor_entry *aux_entry) 349{ 350 if (aux_entry) { 351 if (!aux_entry->locked) { 352 mutex_lock(&dts_update_mutex); 353 iosf_mbi_write(QRK_MBI_UNIT_RMU, QRK_MBI_RMU_WRITE, 354 QRK_DTS_REG_OFFSET_ENABLE, 355 aux_entry->store_dts_enable); 356 357 iosf_mbi_write(QRK_MBI_UNIT_RMU, QRK_MBI_RMU_WRITE, 358 QRK_DTS_REG_OFFSET_PTPS, 359 aux_entry->store_ptps); 360 mutex_unlock(&dts_update_mutex); 361 } 362 thermal_zone_device_unregister(aux_entry->tzone); 363 kfree(aux_entry); 364 } 365} 366 367static struct soc_sensor_entry *alloc_soc_dts(void) 368{ 369 struct soc_sensor_entry *aux_entry; 370 int err; 371 u32 out; 372 int wr_mask; 373 374 aux_entry = kzalloc(sizeof(*aux_entry), GFP_KERNEL); 375 if (!aux_entry) { 376 err = -ENOMEM; 377 return ERR_PTR(-ENOMEM); 378 } 379 380 /* Check if DTS register is locked */ 381 err = iosf_mbi_read(QRK_MBI_UNIT_RMU, QRK_MBI_RMU_READ, 382 QRK_DTS_REG_OFFSET_LOCK, 383 &out); 384 if (err) 385 goto err_ret; 386 387 if (out & QRK_DTS_LOCK_BIT) { 388 aux_entry->locked = true; 389 wr_mask = QRK_DTS_WR_MASK_CLR; 390 } else { 391 aux_entry->locked = false; 392 wr_mask = QRK_DTS_WR_MASK_SET; 393 } 394 395 /* Store DTS default state if DTS registers are not locked */ 396 if (!aux_entry->locked) { 397 /* Store DTS default enable for restore on exit */ 398 err = iosf_mbi_read(QRK_MBI_UNIT_RMU, QRK_MBI_RMU_READ, 399 QRK_DTS_REG_OFFSET_ENABLE, 400 &aux_entry->store_dts_enable); 401 if (err) 402 goto err_ret; 403 404 /* Store DTS default PTPS register for restore on exit */ 405 err = iosf_mbi_read(QRK_MBI_UNIT_RMU, QRK_MBI_RMU_READ, 406 QRK_DTS_REG_OFFSET_PTPS, 407 &aux_entry->store_ptps); 408 if (err) 409 goto err_ret; 410 } 411 412 aux_entry->tzone = thermal_zone_device_register("quark_dts", 413 QRK_MAX_DTS_TRIPS, 414 wr_mask, 415 aux_entry, &tzone_ops, NULL, 0, polling_delay); 416 if (IS_ERR(aux_entry->tzone)) { 417 err = PTR_ERR(aux_entry->tzone); 418 goto err_ret; 419 } 420 421 mutex_lock(&dts_update_mutex); 422 err = soc_dts_enable(aux_entry->tzone); 423 mutex_unlock(&dts_update_mutex); 424 if (err) 425 goto err_aux_status; 426 427 return aux_entry; 428 429err_aux_status: 430 thermal_zone_device_unregister(aux_entry->tzone); 431err_ret: 432 kfree(aux_entry); 433 return ERR_PTR(err); 434} 435 436static const struct x86_cpu_id qrk_thermal_ids[] __initconst = { 437 { X86_VENDOR_INTEL, X86_FAMILY_QUARK, X86_MODEL_QUARK_X1000 }, 438 {} 439}; 440MODULE_DEVICE_TABLE(x86cpu, qrk_thermal_ids); 441 442static int __init intel_quark_thermal_init(void) 443{ 444 int err = 0; 445 446 if (!x86_match_cpu(qrk_thermal_ids) || !iosf_mbi_available()) 447 return -ENODEV; 448 449 soc_dts = alloc_soc_dts(); 450 if (IS_ERR(soc_dts)) { 451 err = PTR_ERR(soc_dts); 452 goto err_free; 453 } 454 455 return 0; 456 457err_free: 458 free_soc_dts(soc_dts); 459 return err; 460} 461 462static void __exit intel_quark_thermal_exit(void) 463{ 464 free_soc_dts(soc_dts); 465} 466 467module_init(intel_quark_thermal_init) 468module_exit(intel_quark_thermal_exit) 469 470MODULE_DESCRIPTION("Intel Quark DTS Thermal Driver"); 471MODULE_AUTHOR("Ong Boon Leong <boon.leong.ong@intel.com>"); 472MODULE_LICENSE("Dual BSD/GPL"); 473