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