linux/drivers/thermal/intel_soc_dts_iosf.c
<<
>>
Prefs
   1/*
   2 * intel_soc_dts_iosf.c
   3 * Copyright (c) 2015, Intel Corporation.
   4 *
   5 * This program is free software; you can redistribute it and/or modify it
   6 * under the terms and conditions of the GNU General Public License,
   7 * version 2, as published by the Free Software Foundation.
   8 *
   9 * This program is distributed in the hope it will be useful, but WITHOUT
  10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  12 * more details.
  13 *
  14 */
  15
  16#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  17
  18#include <linux/module.h>
  19#include <linux/slab.h>
  20#include <linux/interrupt.h>
  21#include <asm/iosf_mbi.h>
  22#include "intel_soc_dts_iosf.h"
  23
  24#define SOC_DTS_OFFSET_ENABLE           0xB0
  25#define SOC_DTS_OFFSET_TEMP             0xB1
  26
  27#define SOC_DTS_OFFSET_PTPS             0xB2
  28#define SOC_DTS_OFFSET_PTTS             0xB3
  29#define SOC_DTS_OFFSET_PTTSS            0xB4
  30#define SOC_DTS_OFFSET_PTMC             0x80
  31#define SOC_DTS_TE_AUX0                 0xB5
  32#define SOC_DTS_TE_AUX1                 0xB6
  33
  34#define SOC_DTS_AUX0_ENABLE_BIT         BIT(0)
  35#define SOC_DTS_AUX1_ENABLE_BIT         BIT(1)
  36#define SOC_DTS_CPU_MODULE0_ENABLE_BIT  BIT(16)
  37#define SOC_DTS_CPU_MODULE1_ENABLE_BIT  BIT(17)
  38#define SOC_DTS_TE_SCI_ENABLE           BIT(9)
  39#define SOC_DTS_TE_SMI_ENABLE           BIT(10)
  40#define SOC_DTS_TE_MSI_ENABLE           BIT(11)
  41#define SOC_DTS_TE_APICA_ENABLE         BIT(14)
  42#define SOC_DTS_PTMC_APIC_DEASSERT_BIT  BIT(4)
  43
  44/* DTS encoding for TJ MAX temperature */
  45#define SOC_DTS_TJMAX_ENCODING          0x7F
  46
  47/* Only 2 out of 4 is allowed for OSPM */
  48#define SOC_MAX_DTS_TRIPS               2
  49
  50/* Mask for two trips in status bits */
  51#define SOC_DTS_TRIP_MASK               0x03
  52
  53/* DTS0 and DTS 1 */
  54#define SOC_MAX_DTS_SENSORS             2
  55
  56static int get_tj_max(u32 *tj_max)
  57{
  58        u32 eax, edx;
  59        u32 val;
  60        int err;
  61
  62        err = rdmsr_safe(MSR_IA32_TEMPERATURE_TARGET, &eax, &edx);
  63        if (err)
  64                goto err_ret;
  65        else {
  66                val = (eax >> 16) & 0xff;
  67                if (val)
  68                        *tj_max = val * 1000;
  69                else {
  70                        err = -EINVAL;
  71                        goto err_ret;
  72                }
  73        }
  74
  75        return 0;
  76err_ret:
  77        *tj_max = 0;
  78
  79        return err;
  80}
  81
  82static int sys_get_trip_temp(struct thermal_zone_device *tzd, int trip,
  83                             int *temp)
  84{
  85        int status;
  86        u32 out;
  87        struct intel_soc_dts_sensor_entry *dts;
  88        struct intel_soc_dts_sensors *sensors;
  89
  90        dts = tzd->devdata;
  91        sensors = dts->sensors;
  92        mutex_lock(&sensors->dts_update_lock);
  93        status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,
  94                               SOC_DTS_OFFSET_PTPS, &out);
  95        mutex_unlock(&sensors->dts_update_lock);
  96        if (status)
  97                return status;
  98
  99        out = (out >> (trip * 8)) & SOC_DTS_TJMAX_ENCODING;
 100        if (!out)
 101                *temp = 0;
 102        else
 103                *temp = sensors->tj_max - out * 1000;
 104
 105        return 0;
 106}
 107
 108static int update_trip_temp(struct intel_soc_dts_sensor_entry *dts,
 109                            int thres_index, int temp,
 110                            enum thermal_trip_type trip_type)
 111{
 112        int status;
 113        u32 temp_out;
 114        u32 out;
 115        u32 store_ptps;
 116        u32 store_ptmc;
 117        u32 store_te_out;
 118        u32 te_out;
 119        u32 int_enable_bit = SOC_DTS_TE_APICA_ENABLE;
 120        struct intel_soc_dts_sensors *sensors = dts->sensors;
 121
 122        if (sensors->intr_type == INTEL_SOC_DTS_INTERRUPT_MSI)
 123                int_enable_bit |= SOC_DTS_TE_MSI_ENABLE;
 124
 125        temp_out = (sensors->tj_max - temp) / 1000;
 126
 127        status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,
 128                               SOC_DTS_OFFSET_PTPS, &store_ptps);
 129        if (status)
 130                return status;
 131
 132        out = (store_ptps & ~(0xFF << (thres_index * 8)));
 133        out |= (temp_out & 0xFF) << (thres_index * 8);
 134        status = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,
 135                                SOC_DTS_OFFSET_PTPS, out);
 136        if (status)
 137                return status;
 138
 139        pr_debug("update_trip_temp PTPS = %x\n", out);
 140        status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,
 141                               SOC_DTS_OFFSET_PTMC, &out);
 142        if (status)
 143                goto err_restore_ptps;
 144
 145        store_ptmc = out;
 146
 147        status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,
 148                               SOC_DTS_TE_AUX0 + thres_index,
 149                               &te_out);
 150        if (status)
 151                goto err_restore_ptmc;
 152
 153        store_te_out = te_out;
 154        /* Enable for CPU module 0 and module 1 */
 155        out |= (SOC_DTS_CPU_MODULE0_ENABLE_BIT |
 156                                        SOC_DTS_CPU_MODULE1_ENABLE_BIT);
 157        if (temp) {
 158                if (thres_index)
 159                        out |= SOC_DTS_AUX1_ENABLE_BIT;
 160                else
 161                        out |= SOC_DTS_AUX0_ENABLE_BIT;
 162                te_out |= int_enable_bit;
 163        } else {
 164                if (thres_index)
 165                        out &= ~SOC_DTS_AUX1_ENABLE_BIT;
 166                else
 167                        out &= ~SOC_DTS_AUX0_ENABLE_BIT;
 168                te_out &= ~int_enable_bit;
 169        }
 170        status = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,
 171                                SOC_DTS_OFFSET_PTMC, out);
 172        if (status)
 173                goto err_restore_te_out;
 174
 175        status = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,
 176                                SOC_DTS_TE_AUX0 + thres_index,
 177                                te_out);
 178        if (status)
 179                goto err_restore_te_out;
 180
 181        dts->trip_types[thres_index] = trip_type;
 182
 183        return 0;
 184err_restore_te_out:
 185        iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,
 186                       SOC_DTS_OFFSET_PTMC, store_te_out);
 187err_restore_ptmc:
 188        iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,
 189                       SOC_DTS_OFFSET_PTMC, store_ptmc);
 190err_restore_ptps:
 191        iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,
 192                       SOC_DTS_OFFSET_PTPS, store_ptps);
 193        /* Nothing we can do if restore fails */
 194
 195        return status;
 196}
 197
 198static int sys_set_trip_temp(struct thermal_zone_device *tzd, int trip,
 199                             int temp)
 200{
 201        struct intel_soc_dts_sensor_entry *dts = tzd->devdata;
 202        struct intel_soc_dts_sensors *sensors = dts->sensors;
 203        int status;
 204
 205        if (temp > sensors->tj_max)
 206                return -EINVAL;
 207
 208        mutex_lock(&sensors->dts_update_lock);
 209        status = update_trip_temp(tzd->devdata, trip, temp,
 210                                  dts->trip_types[trip]);
 211        mutex_unlock(&sensors->dts_update_lock);
 212
 213        return status;
 214}
 215
 216static int sys_get_trip_type(struct thermal_zone_device *tzd,
 217                             int trip, enum thermal_trip_type *type)
 218{
 219        struct intel_soc_dts_sensor_entry *dts;
 220
 221        dts = tzd->devdata;
 222
 223        *type = dts->trip_types[trip];
 224
 225        return 0;
 226}
 227
 228static int sys_get_curr_temp(struct thermal_zone_device *tzd,
 229                             int *temp)
 230{
 231        int status;
 232        u32 out;
 233        struct intel_soc_dts_sensor_entry *dts;
 234        struct intel_soc_dts_sensors *sensors;
 235
 236        dts = tzd->devdata;
 237        sensors = dts->sensors;
 238        status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,
 239                               SOC_DTS_OFFSET_TEMP, &out);
 240        if (status)
 241                return status;
 242
 243        out = (out & dts->temp_mask) >> dts->temp_shift;
 244        out -= SOC_DTS_TJMAX_ENCODING;
 245        *temp = sensors->tj_max - out * 1000;
 246
 247        return 0;
 248}
 249
 250static struct thermal_zone_device_ops tzone_ops = {
 251        .get_temp = sys_get_curr_temp,
 252        .get_trip_temp = sys_get_trip_temp,
 253        .get_trip_type = sys_get_trip_type,
 254        .set_trip_temp = sys_set_trip_temp,
 255};
 256
 257static int soc_dts_enable(int id)
 258{
 259        u32 out;
 260        int ret;
 261
 262        ret = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,
 263                            SOC_DTS_OFFSET_ENABLE, &out);
 264        if (ret)
 265                return ret;
 266
 267        if (!(out & BIT(id))) {
 268                out |= BIT(id);
 269                ret = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,
 270                                     SOC_DTS_OFFSET_ENABLE, out);
 271                if (ret)
 272                        return ret;
 273        }
 274
 275        return ret;
 276}
 277
 278static void remove_dts_thermal_zone(struct intel_soc_dts_sensor_entry *dts)
 279{
 280        if (dts) {
 281                iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,
 282                               SOC_DTS_OFFSET_ENABLE, dts->store_status);
 283                thermal_zone_device_unregister(dts->tzone);
 284        }
 285}
 286
 287static int add_dts_thermal_zone(int id, struct intel_soc_dts_sensor_entry *dts,
 288                                bool notification_support, int trip_cnt,
 289                                int read_only_trip_cnt)
 290{
 291        char name[10];
 292        int trip_count = 0;
 293        int trip_mask = 0;
 294        u32 store_ptps;
 295        int ret;
 296        int i;
 297
 298        /* Store status to restor on exit */
 299        ret = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,
 300                            SOC_DTS_OFFSET_ENABLE, &dts->store_status);
 301        if (ret)
 302                goto err_ret;
 303
 304        dts->id = id;
 305        dts->temp_mask = 0x00FF << (id * 8);
 306        dts->temp_shift = id * 8;
 307        if (notification_support) {
 308                trip_count = min(SOC_MAX_DTS_TRIPS, trip_cnt);
 309                trip_mask = BIT(trip_count - read_only_trip_cnt) - 1;
 310        }
 311
 312        /* Check if the writable trip we provide is not used by BIOS */
 313        ret = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,
 314                            SOC_DTS_OFFSET_PTPS, &store_ptps);
 315        if (ret)
 316                trip_mask = 0;
 317        else {
 318                for (i = 0; i < trip_count; ++i) {
 319                        if (trip_mask & BIT(i))
 320                                if (store_ptps & (0xff << (i * 8)))
 321                                        trip_mask &= ~BIT(i);
 322                }
 323        }
 324        dts->trip_mask = trip_mask;
 325        dts->trip_count = trip_count;
 326        snprintf(name, sizeof(name), "soc_dts%d", id);
 327        dts->tzone = thermal_zone_device_register(name,
 328                                                  trip_count,
 329                                                  trip_mask,
 330                                                  dts, &tzone_ops,
 331                                                  NULL, 0, 0);
 332        if (IS_ERR(dts->tzone)) {
 333                ret = PTR_ERR(dts->tzone);
 334                goto err_ret;
 335        }
 336
 337        ret = soc_dts_enable(id);
 338        if (ret)
 339                goto err_enable;
 340
 341        return 0;
 342err_enable:
 343        thermal_zone_device_unregister(dts->tzone);
 344err_ret:
 345        return ret;
 346}
 347
 348int intel_soc_dts_iosf_add_read_only_critical_trip(
 349        struct intel_soc_dts_sensors *sensors, int critical_offset)
 350{
 351        int i, j;
 352
 353        for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) {
 354                for (j = 0; j < sensors->soc_dts[i].trip_count; ++j) {
 355                        if (!(sensors->soc_dts[i].trip_mask & BIT(j))) {
 356                                return update_trip_temp(&sensors->soc_dts[i], j,
 357                                        sensors->tj_max - critical_offset,
 358                                        THERMAL_TRIP_CRITICAL);
 359                        }
 360                }
 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