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