linux/drivers/thermal/intel/intel_soc_dts_iosf.c
<<
>>
Prefs
   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/module.h>
  11#include <linux/slab.h>
  12#include <linux/interrupt.h>
  13#include <asm/iosf_mbi.h>
  14#include "intel_soc_dts_iosf.h"
  15
  16#define SOC_DTS_OFFSET_ENABLE           0xB0
  17#define SOC_DTS_OFFSET_TEMP             0xB1
  18
  19#define SOC_DTS_OFFSET_PTPS             0xB2
  20#define SOC_DTS_OFFSET_PTTS             0xB3
  21#define SOC_DTS_OFFSET_PTTSS            0xB4
  22#define SOC_DTS_OFFSET_PTMC             0x80
  23#define SOC_DTS_TE_AUX0                 0xB5
  24#define SOC_DTS_TE_AUX1                 0xB6
  25
  26#define SOC_DTS_AUX0_ENABLE_BIT         BIT(0)
  27#define SOC_DTS_AUX1_ENABLE_BIT         BIT(1)
  28#define SOC_DTS_CPU_MODULE0_ENABLE_BIT  BIT(16)
  29#define SOC_DTS_CPU_MODULE1_ENABLE_BIT  BIT(17)
  30#define SOC_DTS_TE_SCI_ENABLE           BIT(9)
  31#define SOC_DTS_TE_SMI_ENABLE           BIT(10)
  32#define SOC_DTS_TE_MSI_ENABLE           BIT(11)
  33#define SOC_DTS_TE_APICA_ENABLE         BIT(14)
  34#define SOC_DTS_PTMC_APIC_DEASSERT_BIT  BIT(4)
  35
  36/* DTS encoding for TJ MAX temperature */
  37#define SOC_DTS_TJMAX_ENCODING          0x7F
  38
  39/* Only 2 out of 4 is allowed for OSPM */
  40#define SOC_MAX_DTS_TRIPS               2
  41
  42/* Mask for two trips in status bits */
  43#define SOC_DTS_TRIP_MASK               0x03
  44
  45/* DTS0 and DTS 1 */
  46#define SOC_MAX_DTS_SENSORS             2
  47
  48static int get_tj_max(u32 *tj_max)
  49{
  50        u32 eax, edx;
  51        u32 val;
  52        int err;
  53
  54        err = rdmsr_safe(MSR_IA32_TEMPERATURE_TARGET, &eax, &edx);
  55        if (err)
  56                goto err_ret;
  57        else {
  58                val = (eax >> 16) & 0xff;
  59                if (val)
  60                        *tj_max = val * 1000;
  61                else {
  62                        err = -EINVAL;
  63                        goto err_ret;
  64                }
  65        }
  66
  67        return 0;
  68err_ret:
  69        *tj_max = 0;
  70
  71        return err;
  72}
  73
  74static int sys_get_trip_temp(struct thermal_zone_device *tzd, int trip,
  75                             int *temp)
  76{
  77        int status;
  78        u32 out;
  79        struct intel_soc_dts_sensor_entry *dts;
  80        struct intel_soc_dts_sensors *sensors;
  81
  82        dts = tzd->devdata;
  83        sensors = dts->sensors;
  84        mutex_lock(&sensors->dts_update_lock);
  85        status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,
  86                               SOC_DTS_OFFSET_PTPS, &out);
  87        mutex_unlock(&sensors->dts_update_lock);
  88        if (status)
  89                return status;
  90
  91        out = (out >> (trip * 8)) & SOC_DTS_TJMAX_ENCODING;
  92        if (!out)
  93                *temp = 0;
  94        else
  95                *temp = sensors->tj_max - out * 1000;
  96
  97        return 0;
  98}
  99
 100static int update_trip_temp(struct intel_soc_dts_sensor_entry *dts,
 101                            int thres_index, int temp,
 102                            enum thermal_trip_type trip_type)
 103{
 104        int status;
 105        u32 temp_out;
 106        u32 out;
 107        unsigned long update_ptps;
 108        u32 store_ptps;
 109        u32 store_ptmc;
 110        u32 store_te_out;
 111        u32 te_out;
 112        u32 int_enable_bit = SOC_DTS_TE_APICA_ENABLE;
 113        struct intel_soc_dts_sensors *sensors = dts->sensors;
 114
 115        if (sensors->intr_type == INTEL_SOC_DTS_INTERRUPT_MSI)
 116                int_enable_bit |= SOC_DTS_TE_MSI_ENABLE;
 117
 118        temp_out = (sensors->tj_max - temp) / 1000;
 119
 120        status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,
 121                               SOC_DTS_OFFSET_PTPS, &store_ptps);
 122        if (status)
 123                return status;
 124
 125        update_ptps = store_ptps;
 126        bitmap_set_value8(&update_ptps, temp_out & 0xFF, thres_index * 8);
 127        out = update_ptps;
 128
 129        status = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,
 130                                SOC_DTS_OFFSET_PTPS, out);
 131        if (status)
 132                return status;
 133
 134        pr_debug("update_trip_temp PTPS = %x\n", out);
 135        status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,
 136                               SOC_DTS_OFFSET_PTMC, &out);
 137        if (status)
 138                goto err_restore_ptps;
 139
 140        store_ptmc = out;
 141
 142        status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,
 143                               SOC_DTS_TE_AUX0 + thres_index,
 144                               &te_out);
 145        if (status)
 146                goto err_restore_ptmc;
 147
 148        store_te_out = te_out;
 149        /* Enable for CPU module 0 and module 1 */
 150        out |= (SOC_DTS_CPU_MODULE0_ENABLE_BIT |
 151                                        SOC_DTS_CPU_MODULE1_ENABLE_BIT);
 152        if (temp) {
 153                if (thres_index)
 154                        out |= SOC_DTS_AUX1_ENABLE_BIT;
 155                else
 156                        out |= SOC_DTS_AUX0_ENABLE_BIT;
 157                te_out |= int_enable_bit;
 158        } else {
 159                if (thres_index)
 160                        out &= ~SOC_DTS_AUX1_ENABLE_BIT;
 161                else
 162                        out &= ~SOC_DTS_AUX0_ENABLE_BIT;
 163                te_out &= ~int_enable_bit;
 164        }
 165        status = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,
 166                                SOC_DTS_OFFSET_PTMC, out);
 167        if (status)
 168                goto err_restore_te_out;
 169
 170        status = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,
 171                                SOC_DTS_TE_AUX0 + thres_index,
 172                                te_out);
 173        if (status)
 174                goto err_restore_te_out;
 175
 176        dts->trip_types[thres_index] = trip_type;
 177
 178        return 0;
 179err_restore_te_out:
 180        iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,
 181                       SOC_DTS_OFFSET_PTMC, store_te_out);
 182err_restore_ptmc:
 183        iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,
 184                       SOC_DTS_OFFSET_PTMC, store_ptmc);
 185err_restore_ptps:
 186        iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,
 187                       SOC_DTS_OFFSET_PTPS, store_ptps);
 188        /* Nothing we can do if restore fails */
 189
 190        return status;
 191}
 192
 193static int sys_set_trip_temp(struct thermal_zone_device *tzd, int trip,
 194                             int temp)
 195{
 196        struct intel_soc_dts_sensor_entry *dts = tzd->devdata;
 197        struct intel_soc_dts_sensors *sensors = dts->sensors;
 198        int status;
 199
 200        if (temp > sensors->tj_max)
 201                return -EINVAL;
 202
 203        mutex_lock(&sensors->dts_update_lock);
 204        status = update_trip_temp(tzd->devdata, trip, temp,
 205                                  dts->trip_types[trip]);
 206        mutex_unlock(&sensors->dts_update_lock);
 207
 208        return status;
 209}
 210
 211static int sys_get_trip_type(struct thermal_zone_device *tzd,
 212                             int trip, enum thermal_trip_type *type)
 213{
 214        struct intel_soc_dts_sensor_entry *dts;
 215
 216        dts = tzd->devdata;
 217
 218        *type = dts->trip_types[trip];
 219
 220        return 0;
 221}
 222
 223static int sys_get_curr_temp(struct thermal_zone_device *tzd,
 224                             int *temp)
 225{
 226        int status;
 227        u32 out;
 228        struct intel_soc_dts_sensor_entry *dts;
 229        struct intel_soc_dts_sensors *sensors;
 230        unsigned long raw;
 231
 232        dts = tzd->devdata;
 233        sensors = dts->sensors;
 234        status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,
 235                               SOC_DTS_OFFSET_TEMP, &out);
 236        if (status)
 237                return status;
 238
 239        raw = out;
 240        out = bitmap_get_value8(&raw, dts->id * 8) - SOC_DTS_TJMAX_ENCODING;
 241        *temp = sensors->tj_max - out * 1000;
 242
 243        return 0;
 244}
 245
 246static struct thermal_zone_device_ops tzone_ops = {
 247        .get_temp = sys_get_curr_temp,
 248        .get_trip_temp = sys_get_trip_temp,
 249        .get_trip_type = sys_get_trip_type,
 250        .set_trip_temp = sys_set_trip_temp,
 251};
 252
 253static int soc_dts_enable(int id)
 254{
 255        u32 out;
 256        int ret;
 257
 258        ret = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,
 259                            SOC_DTS_OFFSET_ENABLE, &out);
 260        if (ret)
 261                return ret;
 262
 263        if (!(out & BIT(id))) {
 264                out |= BIT(id);
 265                ret = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,
 266                                     SOC_DTS_OFFSET_ENABLE, out);
 267                if (ret)
 268                        return ret;
 269        }
 270
 271        return ret;
 272}
 273
 274static void remove_dts_thermal_zone(struct intel_soc_dts_sensor_entry *dts)
 275{
 276        if (dts) {
 277                iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,
 278                               SOC_DTS_OFFSET_ENABLE, dts->store_status);
 279                thermal_zone_device_unregister(dts->tzone);
 280        }
 281}
 282
 283static int add_dts_thermal_zone(int id, struct intel_soc_dts_sensor_entry *dts,
 284                                bool notification_support, int trip_cnt,
 285                                int read_only_trip_cnt)
 286{
 287        char name[10];
 288        unsigned long trip;
 289        int trip_count = 0;
 290        int trip_mask = 0;
 291        int writable_trip_cnt = 0;
 292        unsigned long ptps;
 293        u32 store_ptps;
 294        unsigned long i;
 295        int ret;
 296
 297        /* Store status to restor on exit */
 298        ret = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,
 299                            SOC_DTS_OFFSET_ENABLE, &dts->store_status);
 300        if (ret)
 301                goto err_ret;
 302
 303        dts->id = id;
 304        if (notification_support) {
 305                trip_count = min(SOC_MAX_DTS_TRIPS, trip_cnt);
 306                writable_trip_cnt = trip_count - read_only_trip_cnt;
 307                trip_mask = GENMASK(writable_trip_cnt - 1, 0);
 308        }
 309
 310        /* Check if the writable trip we provide is not used by BIOS */
 311        ret = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,
 312                            SOC_DTS_OFFSET_PTPS, &store_ptps);
 313        if (ret)
 314                trip_mask = 0;
 315        else {
 316                ptps = store_ptps;
 317                for_each_set_clump8(i, trip, &ptps, writable_trip_cnt * 8)
 318                        trip_mask &= ~BIT(i / 8);
 319        }
 320        dts->trip_mask = trip_mask;
 321        dts->trip_count = trip_count;
 322        snprintf(name, sizeof(name), "soc_dts%d", id);
 323        dts->tzone = thermal_zone_device_register(name,
 324                                                  trip_count,
 325                                                  trip_mask,
 326                                                  dts, &tzone_ops,
 327                                                  NULL, 0, 0);
 328        if (IS_ERR(dts->tzone)) {
 329                ret = PTR_ERR(dts->tzone);
 330                goto err_ret;
 331        }
 332        ret = thermal_zone_device_enable(dts->tzone);
 333        if (ret)
 334                goto err_enable;
 335
 336        ret = soc_dts_enable(id);
 337        if (ret)
 338                goto err_enable;
 339
 340        return 0;
 341err_enable:
 342        thermal_zone_device_unregister(dts->tzone);
 343err_ret:
 344        return ret;
 345}
 346
 347int intel_soc_dts_iosf_add_read_only_critical_trip(
 348        struct intel_soc_dts_sensors *sensors, int critical_offset)
 349{
 350        int i, j;
 351
 352        for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) {
 353                struct intel_soc_dts_sensor_entry *entry = &sensors->soc_dts[i];
 354                int temp = sensors->tj_max - critical_offset;
 355                unsigned long count = entry->trip_count;
 356                unsigned long mask = entry->trip_mask;
 357
 358                j = find_first_zero_bit(&mask, count);
 359                if (j < count)
 360                        return update_trip_temp(entry, j, temp, THERMAL_TRIP_CRITICAL);
 361        }
 362
 363        return -EINVAL;
 364}
 365EXPORT_SYMBOL_GPL(intel_soc_dts_iosf_add_read_only_critical_trip);
 366
 367void intel_soc_dts_iosf_interrupt_handler(struct intel_soc_dts_sensors *sensors)
 368{
 369        u32 sticky_out;
 370        int status;
 371        u32 ptmc_out;
 372        unsigned long flags;
 373
 374        spin_lock_irqsave(&sensors->intr_notify_lock, flags);
 375
 376        status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,
 377                               SOC_DTS_OFFSET_PTMC, &ptmc_out);
 378        ptmc_out |= SOC_DTS_PTMC_APIC_DEASSERT_BIT;
 379        status = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,
 380                                SOC_DTS_OFFSET_PTMC, ptmc_out);
 381
 382        status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,
 383                               SOC_DTS_OFFSET_PTTSS, &sticky_out);
 384        pr_debug("status %d PTTSS %x\n", status, sticky_out);
 385        if (sticky_out & SOC_DTS_TRIP_MASK) {
 386                int i;
 387                /* reset sticky bit */
 388                status = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,
 389                                        SOC_DTS_OFFSET_PTTSS, sticky_out);
 390                spin_unlock_irqrestore(&sensors->intr_notify_lock, flags);
 391
 392                for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) {
 393                        pr_debug("TZD update for zone %d\n", i);
 394                        thermal_zone_device_update(sensors->soc_dts[i].tzone,
 395                                                   THERMAL_EVENT_UNSPECIFIED);
 396                }
 397        } else
 398                spin_unlock_irqrestore(&sensors->intr_notify_lock, flags);
 399}
 400EXPORT_SYMBOL_GPL(intel_soc_dts_iosf_interrupt_handler);
 401
 402struct intel_soc_dts_sensors *intel_soc_dts_iosf_init(
 403        enum intel_soc_dts_interrupt_type intr_type, int trip_count,
 404        int read_only_trip_count)
 405{
 406        struct intel_soc_dts_sensors *sensors;
 407        bool notification;
 408        u32 tj_max;
 409        int ret;
 410        int i;
 411
 412        if (!iosf_mbi_available())
 413                return ERR_PTR(-ENODEV);
 414
 415        if (!trip_count || read_only_trip_count > trip_count)
 416                return ERR_PTR(-EINVAL);
 417
 418        if (get_tj_max(&tj_max))
 419                return ERR_PTR(-EINVAL);
 420
 421        sensors = kzalloc(sizeof(*sensors), GFP_KERNEL);
 422        if (!sensors)
 423                return ERR_PTR(-ENOMEM);
 424
 425        spin_lock_init(&sensors->intr_notify_lock);
 426        mutex_init(&sensors->dts_update_lock);
 427        sensors->intr_type = intr_type;
 428        sensors->tj_max = tj_max;
 429        if (intr_type == INTEL_SOC_DTS_INTERRUPT_NONE)
 430                notification = false;
 431        else
 432                notification = true;
 433        for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) {
 434                sensors->soc_dts[i].sensors = sensors;
 435                ret = add_dts_thermal_zone(i, &sensors->soc_dts[i],
 436                                           notification, trip_count,
 437                                           read_only_trip_count);
 438                if (ret)
 439                        goto err_free;
 440        }
 441
 442        for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) {
 443                ret = update_trip_temp(&sensors->soc_dts[i], 0, 0,
 444                                       THERMAL_TRIP_PASSIVE);
 445                if (ret)
 446                        goto err_remove_zone;
 447
 448                ret = update_trip_temp(&sensors->soc_dts[i], 1, 0,
 449                                       THERMAL_TRIP_PASSIVE);
 450                if (ret)
 451                        goto err_remove_zone;
 452        }
 453
 454        return sensors;
 455err_remove_zone:
 456        for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i)
 457                remove_dts_thermal_zone(&sensors->soc_dts[i]);
 458
 459err_free:
 460        kfree(sensors);
 461        return ERR_PTR(ret);
 462}
 463EXPORT_SYMBOL_GPL(intel_soc_dts_iosf_init);
 464
 465void intel_soc_dts_iosf_exit(struct intel_soc_dts_sensors *sensors)
 466{
 467        int i;
 468
 469        for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) {
 470                update_trip_temp(&sensors->soc_dts[i], 0, 0, 0);
 471                update_trip_temp(&sensors->soc_dts[i], 1, 0, 0);
 472                remove_dts_thermal_zone(&sensors->soc_dts[i]);
 473        }
 474        kfree(sensors);
 475}
 476EXPORT_SYMBOL_GPL(intel_soc_dts_iosf_exit);
 477
 478MODULE_LICENSE("GPL v2");
 479