394 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * intel_soc_dts_iosf.c4 * Copyright (c) 2015, Intel Corporation.5 */6 7#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt8 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 0xB018#define SOC_DTS_OFFSET_TEMP 0xB119 20#define SOC_DTS_OFFSET_PTPS 0xB221#define SOC_DTS_OFFSET_PTTS 0xB322#define SOC_DTS_OFFSET_PTTSS 0xB423#define SOC_DTS_OFFSET_PTMC 0x8024#define SOC_DTS_TE_AUX0 0xB525#define SOC_DTS_TE_AUX1 0xB626 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 0x7F39 40/* Mask for two trips in status bits */41#define SOC_DTS_TRIP_MASK 0x0342 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 else97 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 else103 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 } else287 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");394