FILE
intel_soc_dts_iosf.c
File preview with syntax highlighting.
linux-6.19.14/drivers/thermal/intel/intel_soc_dts_iosf.c
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * intel_soc_dts_iosf.c 4 * Copyright (c) 2015, Intel Corporation. 5 */ 6 7#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 8 9#include <linux/bitops.h> 10#include <linux/intel_tcc.h> 11#include <linux/module.h> 12#include <linux/slab.h> 13#include <linux/interrupt.h> 14#include <asm/iosf_mbi.h> 15#include "intel_soc_dts_iosf.h" 16 17#define SOC_DTS_OFFSET_ENABLE 0xB0 18#define SOC_DTS_OFFSET_TEMP 0xB1 19 20#define SOC_DTS_OFFSET_PTPS 0xB2 21#define SOC_DTS_OFFSET_PTTS 0xB3 22#define SOC_DTS_OFFSET_PTTSS 0xB4 23#define SOC_DTS_OFFSET_PTMC 0x80 24#define SOC_DTS_TE_AUX0 0xB5 25#define SOC_DTS_TE_AUX1 0xB6 26 27#define SOC_DTS_AUX0_ENABLE_BIT BIT(0) 28#define SOC_DTS_AUX1_ENABLE_BIT BIT(1) 29#define SOC_DTS_CPU_MODULE0_ENABLE_BIT BIT(16) 30#define SOC_DTS_CPU_MODULE1_ENABLE_BIT BIT(17) 31#define SOC_DTS_TE_SCI_ENABLE BIT(9) 32#define SOC_DTS_TE_SMI_ENABLE BIT(10) 33#define SOC_DTS_TE_MSI_ENABLE BIT(11) 34#define SOC_DTS_TE_APICA_ENABLE BIT(14) 35#define SOC_DTS_PTMC_APIC_DEASSERT_BIT BIT(4) 36 37/* DTS encoding for TJ MAX temperature */ 38#define SOC_DTS_TJMAX_ENCODING 0x7F 39 40/* Mask for two trips in status bits */ 41#define SOC_DTS_TRIP_MASK 0x03 42 43static int update_trip_temp(struct intel_soc_dts_sensors *sensors, 44 int thres_index, int temp) 45{ 46 int status; 47 u32 temp_out; 48 u32 out; 49 unsigned long update_ptps; 50 u32 store_ptps; 51 u32 store_ptmc; 52 u32 store_te_out; 53 u32 te_out; 54 u32 int_enable_bit = SOC_DTS_TE_APICA_ENABLE; 55 56 if (sensors->intr_type == INTEL_SOC_DTS_INTERRUPT_MSI) 57 int_enable_bit |= SOC_DTS_TE_MSI_ENABLE; 58 59 temp_out = (sensors->tj_max - temp) / 1000; 60 61 status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, 62 SOC_DTS_OFFSET_PTPS, &store_ptps); 63 if (status) 64 return status; 65 66 update_ptps = store_ptps; 67 bitmap_set_value8(&update_ptps, temp_out & 0xFF, thres_index * 8); 68 out = update_ptps; 69 70 status = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, 71 SOC_DTS_OFFSET_PTPS, out); 72 if (status) 73 return status; 74 75 pr_debug("update_trip_temp PTPS = %x\n", out); 76 status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, 77 SOC_DTS_OFFSET_PTMC, &out); 78 if (status) 79 goto err_restore_ptps; 80 81 store_ptmc = out; 82 83 status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, 84 SOC_DTS_TE_AUX0 + thres_index, 85 &te_out); 86 if (status) 87 goto err_restore_ptmc; 88 89 store_te_out = te_out; 90 /* Enable for CPU module 0 and module 1 */ 91 out |= (SOC_DTS_CPU_MODULE0_ENABLE_BIT | 92 SOC_DTS_CPU_MODULE1_ENABLE_BIT); 93 if (temp) { 94 if (thres_index) 95 out |= SOC_DTS_AUX1_ENABLE_BIT; 96 else 97 out |= SOC_DTS_AUX0_ENABLE_BIT; 98 te_out |= int_enable_bit; 99 } else { 100 if (thres_index) 101 out &= ~SOC_DTS_AUX1_ENABLE_BIT; 102 else 103 out &= ~SOC_DTS_AUX0_ENABLE_BIT; 104 te_out &= ~int_enable_bit; 105 } 106 status = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, 107 SOC_DTS_OFFSET_PTMC, out); 108 if (status) 109 goto err_restore_te_out; 110 111 status = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, 112 SOC_DTS_TE_AUX0 + thres_index, 113 te_out); 114 if (status) 115 goto err_restore_te_out; 116 117 return 0; 118err_restore_te_out: 119 iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, 120 SOC_DTS_OFFSET_PTMC, store_te_out); 121err_restore_ptmc: 122 iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, 123 SOC_DTS_OFFSET_PTMC, store_ptmc); 124err_restore_ptps: 125 iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, 126 SOC_DTS_OFFSET_PTPS, store_ptps); 127 /* Nothing we can do if restore fails */ 128 129 return status; 130} 131 132static int sys_set_trip_temp(struct thermal_zone_device *tzd, 133 const struct thermal_trip *trip, 134 int temp) 135{ 136 struct intel_soc_dts_sensor_entry *dts = thermal_zone_device_priv(tzd); 137 struct intel_soc_dts_sensors *sensors = dts->sensors; 138 unsigned int trip_index = THERMAL_TRIP_PRIV_TO_INT(trip->priv); 139 int status; 140 141 if (temp > sensors->tj_max) 142 return -EINVAL; 143 144 mutex_lock(&sensors->dts_update_lock); 145 status = update_trip_temp(sensors, trip_index, temp); 146 mutex_unlock(&sensors->dts_update_lock); 147 148 return status; 149} 150 151static int sys_get_curr_temp(struct thermal_zone_device *tzd, 152 int *temp) 153{ 154 int status; 155 u32 out; 156 struct intel_soc_dts_sensor_entry *dts = thermal_zone_device_priv(tzd); 157 struct intel_soc_dts_sensors *sensors; 158 unsigned long raw; 159 160 sensors = dts->sensors; 161 status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, 162 SOC_DTS_OFFSET_TEMP, &out); 163 if (status) 164 return status; 165 166 raw = out; 167 out = bitmap_get_value8(&raw, dts->id * 8) - SOC_DTS_TJMAX_ENCODING; 168 *temp = sensors->tj_max - out * 1000; 169 170 return 0; 171} 172 173static const struct thermal_zone_device_ops tzone_ops = { 174 .get_temp = sys_get_curr_temp, 175 .set_trip_temp = sys_set_trip_temp, 176}; 177 178static int soc_dts_enable(int id) 179{ 180 u32 out; 181 int ret; 182 183 ret = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, 184 SOC_DTS_OFFSET_ENABLE, &out); 185 if (ret) 186 return ret; 187 188 if (!(out & BIT(id))) { 189 out |= BIT(id); 190 ret = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, 191 SOC_DTS_OFFSET_ENABLE, out); 192 if (ret) 193 return ret; 194 } 195 196 return ret; 197} 198 199static void remove_dts_thermal_zone(struct intel_soc_dts_sensor_entry *dts) 200{ 201 iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, 202 SOC_DTS_OFFSET_ENABLE, dts->store_status); 203 thermal_zone_device_unregister(dts->tzone); 204} 205 206static int add_dts_thermal_zone(int id, struct intel_soc_dts_sensor_entry *dts, 207 struct thermal_trip *trips) 208{ 209 char name[10]; 210 u32 store_ptps; 211 int ret; 212 213 /* Store status to restor on exit */ 214 ret = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, 215 SOC_DTS_OFFSET_ENABLE, &dts->store_status); 216 if (ret) 217 goto err_ret; 218 219 dts->id = id; 220 221 /* Check if the writable trip we provide is not used by BIOS */ 222 ret = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, 223 SOC_DTS_OFFSET_PTPS, &store_ptps); 224 if (!ret) { 225 int i; 226 227 for (i = 0; i <= 1; i++) { 228 if (store_ptps & (0xFFU << i * 8)) 229 trips[i].flags &= ~THERMAL_TRIP_FLAG_RW_TEMP; 230 } 231 } 232 snprintf(name, sizeof(name), "soc_dts%d", id); 233 dts->tzone = thermal_zone_device_register_with_trips(name, trips, 234 SOC_MAX_DTS_TRIPS, 235 dts, &tzone_ops, 236 NULL, 0, 0); 237 if (IS_ERR(dts->tzone)) { 238 ret = PTR_ERR(dts->tzone); 239 goto err_ret; 240 } 241 ret = thermal_zone_device_enable(dts->tzone); 242 if (ret) 243 goto err_enable; 244 245 ret = soc_dts_enable(id); 246 if (ret) 247 goto err_enable; 248 249 return 0; 250err_enable: 251 thermal_zone_device_unregister(dts->tzone); 252err_ret: 253 return ret; 254} 255 256void intel_soc_dts_iosf_interrupt_handler(struct intel_soc_dts_sensors *sensors) 257{ 258 u32 sticky_out; 259 int status; 260 u32 ptmc_out; 261 unsigned long flags; 262 263 spin_lock_irqsave(&sensors->intr_notify_lock, flags); 264 265 status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, 266 SOC_DTS_OFFSET_PTMC, &ptmc_out); 267 ptmc_out |= SOC_DTS_PTMC_APIC_DEASSERT_BIT; 268 status = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, 269 SOC_DTS_OFFSET_PTMC, ptmc_out); 270 271 status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, 272 SOC_DTS_OFFSET_PTTSS, &sticky_out); 273 pr_debug("status %d PTTSS %x\n", status, sticky_out); 274 if (sticky_out & SOC_DTS_TRIP_MASK) { 275 int i; 276 /* reset sticky bit */ 277 status = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, 278 SOC_DTS_OFFSET_PTTSS, sticky_out); 279 spin_unlock_irqrestore(&sensors->intr_notify_lock, flags); 280 281 for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) { 282 pr_debug("TZD update for zone %d\n", i); 283 thermal_zone_device_update(sensors->soc_dts[i].tzone, 284 THERMAL_EVENT_UNSPECIFIED); 285 } 286 } else 287 spin_unlock_irqrestore(&sensors->intr_notify_lock, flags); 288} 289EXPORT_SYMBOL_GPL(intel_soc_dts_iosf_interrupt_handler); 290 291static void dts_trips_reset(struct intel_soc_dts_sensors *sensors, int dts_index) 292{ 293 update_trip_temp(sensors, 0, 0); 294 update_trip_temp(sensors, 1, 0); 295} 296 297static void set_trip(struct thermal_trip *trip, enum thermal_trip_type type, 298 u8 flags, int temp, unsigned int index) 299{ 300 trip->type = type; 301 trip->flags = flags; 302 trip->temperature = temp; 303 trip->priv = THERMAL_INT_TO_TRIP_PRIV(index); 304} 305 306struct intel_soc_dts_sensors * 307intel_soc_dts_iosf_init(enum intel_soc_dts_interrupt_type intr_type, 308 bool critical_trip, int crit_offset) 309{ 310 struct thermal_trip trips[SOC_MAX_DTS_SENSORS][SOC_MAX_DTS_TRIPS] = { 0 }; 311 struct intel_soc_dts_sensors *sensors; 312 int tj_max; 313 int ret; 314 int i; 315 316 if (!iosf_mbi_available()) 317 return ERR_PTR(-ENODEV); 318 319 tj_max = intel_tcc_get_tjmax(-1); 320 if (tj_max < 0) 321 return ERR_PTR(tj_max); 322 323 sensors = kzalloc(sizeof(*sensors), GFP_KERNEL); 324 if (!sensors) 325 return ERR_PTR(-ENOMEM); 326 327 spin_lock_init(&sensors->intr_notify_lock); 328 mutex_init(&sensors->dts_update_lock); 329 sensors->intr_type = intr_type; 330 sensors->tj_max = tj_max * 1000; 331 332 for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) { 333 int temp; 334 335 sensors->soc_dts[i].sensors = sensors; 336 337 set_trip(&trips[i][0], THERMAL_TRIP_PASSIVE, 338 THERMAL_TRIP_FLAG_RW_TEMP, 0, 0); 339 340 ret = update_trip_temp(sensors, 0, 0); 341 if (ret) 342 goto err_reset_trips; 343 344 if (critical_trip) { 345 temp = sensors->tj_max - crit_offset; 346 set_trip(&trips[i][1], THERMAL_TRIP_CRITICAL, 0, temp, 1); 347 } else { 348 set_trip(&trips[i][1], THERMAL_TRIP_PASSIVE, 349 THERMAL_TRIP_FLAG_RW_TEMP, 0, 1); 350 temp = 0; 351 } 352 353 ret = update_trip_temp(sensors, 1, temp); 354 if (ret) 355 goto err_reset_trips; 356 } 357 358 for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) { 359 ret = add_dts_thermal_zone(i, &sensors->soc_dts[i], trips[i]); 360 if (ret) 361 goto err_remove_zone; 362 } 363 364 return sensors; 365 366err_remove_zone: 367 for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) 368 remove_dts_thermal_zone(&sensors->soc_dts[i]); 369 370err_reset_trips: 371 for (i = 0; i < SOC_MAX_DTS_SENSORS; i++) 372 dts_trips_reset(sensors, i); 373 374 kfree(sensors); 375 return ERR_PTR(ret); 376} 377EXPORT_SYMBOL_GPL(intel_soc_dts_iosf_init); 378 379void intel_soc_dts_iosf_exit(struct intel_soc_dts_sensors *sensors) 380{ 381 int i; 382 383 for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) { 384 remove_dts_thermal_zone(&sensors->soc_dts[i]); 385 dts_trips_reset(sensors, i); 386 } 387 kfree(sensors); 388} 389EXPORT_SYMBOL_GPL(intel_soc_dts_iosf_exit); 390 391MODULE_IMPORT_NS("INTEL_TCC"); 392MODULE_LICENSE("GPL v2"); 393MODULE_DESCRIPTION("SoC DTS driver using side band interface");
~/
Read-only file preview.