Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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