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