13e8c4d31SAmit Kucheria /* 23e8c4d31SAmit Kucheria * intel_soc_dts_iosf.c 33e8c4d31SAmit Kucheria * Copyright (c) 2015, Intel Corporation. 43e8c4d31SAmit Kucheria * 53e8c4d31SAmit Kucheria * This program is free software; you can redistribute it and/or modify it 63e8c4d31SAmit Kucheria * under the terms and conditions of the GNU General Public License, 73e8c4d31SAmit Kucheria * version 2, as published by the Free Software Foundation. 83e8c4d31SAmit Kucheria * 93e8c4d31SAmit Kucheria * This program is distributed in the hope it will be useful, but WITHOUT 103e8c4d31SAmit Kucheria * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 113e8c4d31SAmit Kucheria * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 123e8c4d31SAmit Kucheria * more details. 133e8c4d31SAmit Kucheria * 143e8c4d31SAmit Kucheria */ 153e8c4d31SAmit Kucheria 163e8c4d31SAmit Kucheria #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 173e8c4d31SAmit Kucheria 183e8c4d31SAmit Kucheria #include <linux/module.h> 193e8c4d31SAmit Kucheria #include <linux/slab.h> 203e8c4d31SAmit Kucheria #include <linux/interrupt.h> 213e8c4d31SAmit Kucheria #include <asm/iosf_mbi.h> 223e8c4d31SAmit Kucheria #include "intel_soc_dts_iosf.h" 233e8c4d31SAmit Kucheria 243e8c4d31SAmit Kucheria #define SOC_DTS_OFFSET_ENABLE 0xB0 253e8c4d31SAmit Kucheria #define SOC_DTS_OFFSET_TEMP 0xB1 263e8c4d31SAmit Kucheria 273e8c4d31SAmit Kucheria #define SOC_DTS_OFFSET_PTPS 0xB2 283e8c4d31SAmit Kucheria #define SOC_DTS_OFFSET_PTTS 0xB3 293e8c4d31SAmit Kucheria #define SOC_DTS_OFFSET_PTTSS 0xB4 303e8c4d31SAmit Kucheria #define SOC_DTS_OFFSET_PTMC 0x80 313e8c4d31SAmit Kucheria #define SOC_DTS_TE_AUX0 0xB5 323e8c4d31SAmit Kucheria #define SOC_DTS_TE_AUX1 0xB6 333e8c4d31SAmit Kucheria 343e8c4d31SAmit Kucheria #define SOC_DTS_AUX0_ENABLE_BIT BIT(0) 353e8c4d31SAmit Kucheria #define SOC_DTS_AUX1_ENABLE_BIT BIT(1) 363e8c4d31SAmit Kucheria #define SOC_DTS_CPU_MODULE0_ENABLE_BIT BIT(16) 373e8c4d31SAmit Kucheria #define SOC_DTS_CPU_MODULE1_ENABLE_BIT BIT(17) 383e8c4d31SAmit Kucheria #define SOC_DTS_TE_SCI_ENABLE BIT(9) 393e8c4d31SAmit Kucheria #define SOC_DTS_TE_SMI_ENABLE BIT(10) 403e8c4d31SAmit Kucheria #define SOC_DTS_TE_MSI_ENABLE BIT(11) 413e8c4d31SAmit Kucheria #define SOC_DTS_TE_APICA_ENABLE BIT(14) 423e8c4d31SAmit Kucheria #define SOC_DTS_PTMC_APIC_DEASSERT_BIT BIT(4) 433e8c4d31SAmit Kucheria 443e8c4d31SAmit Kucheria /* DTS encoding for TJ MAX temperature */ 453e8c4d31SAmit Kucheria #define SOC_DTS_TJMAX_ENCODING 0x7F 463e8c4d31SAmit Kucheria 473e8c4d31SAmit Kucheria /* Only 2 out of 4 is allowed for OSPM */ 483e8c4d31SAmit Kucheria #define SOC_MAX_DTS_TRIPS 2 493e8c4d31SAmit Kucheria 503e8c4d31SAmit Kucheria /* Mask for two trips in status bits */ 513e8c4d31SAmit Kucheria #define SOC_DTS_TRIP_MASK 0x03 523e8c4d31SAmit Kucheria 533e8c4d31SAmit Kucheria /* DTS0 and DTS 1 */ 543e8c4d31SAmit Kucheria #define SOC_MAX_DTS_SENSORS 2 553e8c4d31SAmit Kucheria 563e8c4d31SAmit Kucheria static int get_tj_max(u32 *tj_max) 573e8c4d31SAmit Kucheria { 583e8c4d31SAmit Kucheria u32 eax, edx; 593e8c4d31SAmit Kucheria u32 val; 603e8c4d31SAmit Kucheria int err; 613e8c4d31SAmit Kucheria 623e8c4d31SAmit Kucheria err = rdmsr_safe(MSR_IA32_TEMPERATURE_TARGET, &eax, &edx); 633e8c4d31SAmit Kucheria if (err) 643e8c4d31SAmit Kucheria goto err_ret; 653e8c4d31SAmit Kucheria else { 663e8c4d31SAmit Kucheria val = (eax >> 16) & 0xff; 673e8c4d31SAmit Kucheria if (val) 683e8c4d31SAmit Kucheria *tj_max = val * 1000; 693e8c4d31SAmit Kucheria else { 703e8c4d31SAmit Kucheria err = -EINVAL; 713e8c4d31SAmit Kucheria goto err_ret; 723e8c4d31SAmit Kucheria } 733e8c4d31SAmit Kucheria } 743e8c4d31SAmit Kucheria 753e8c4d31SAmit Kucheria return 0; 763e8c4d31SAmit Kucheria err_ret: 773e8c4d31SAmit Kucheria *tj_max = 0; 783e8c4d31SAmit Kucheria 793e8c4d31SAmit Kucheria return err; 803e8c4d31SAmit Kucheria } 813e8c4d31SAmit Kucheria 823e8c4d31SAmit Kucheria static int sys_get_trip_temp(struct thermal_zone_device *tzd, int trip, 833e8c4d31SAmit Kucheria int *temp) 843e8c4d31SAmit Kucheria { 853e8c4d31SAmit Kucheria int status; 863e8c4d31SAmit Kucheria u32 out; 873e8c4d31SAmit Kucheria struct intel_soc_dts_sensor_entry *dts; 883e8c4d31SAmit Kucheria struct intel_soc_dts_sensors *sensors; 893e8c4d31SAmit Kucheria 903e8c4d31SAmit Kucheria dts = tzd->devdata; 913e8c4d31SAmit Kucheria sensors = dts->sensors; 923e8c4d31SAmit Kucheria mutex_lock(&sensors->dts_update_lock); 933e8c4d31SAmit Kucheria status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, 943e8c4d31SAmit Kucheria SOC_DTS_OFFSET_PTPS, &out); 953e8c4d31SAmit Kucheria mutex_unlock(&sensors->dts_update_lock); 963e8c4d31SAmit Kucheria if (status) 973e8c4d31SAmit Kucheria return status; 983e8c4d31SAmit Kucheria 993e8c4d31SAmit Kucheria out = (out >> (trip * 8)) & SOC_DTS_TJMAX_ENCODING; 1003e8c4d31SAmit Kucheria if (!out) 1013e8c4d31SAmit Kucheria *temp = 0; 1023e8c4d31SAmit Kucheria else 1033e8c4d31SAmit Kucheria *temp = sensors->tj_max - out * 1000; 1043e8c4d31SAmit Kucheria 1053e8c4d31SAmit Kucheria return 0; 1063e8c4d31SAmit Kucheria } 1073e8c4d31SAmit Kucheria 1083e8c4d31SAmit Kucheria static int update_trip_temp(struct intel_soc_dts_sensor_entry *dts, 1093e8c4d31SAmit Kucheria int thres_index, int temp, 1103e8c4d31SAmit Kucheria enum thermal_trip_type trip_type) 1113e8c4d31SAmit Kucheria { 1123e8c4d31SAmit Kucheria int status; 1133e8c4d31SAmit Kucheria u32 temp_out; 1143e8c4d31SAmit Kucheria u32 out; 1153e8c4d31SAmit Kucheria u32 store_ptps; 1163e8c4d31SAmit Kucheria u32 store_ptmc; 1173e8c4d31SAmit Kucheria u32 store_te_out; 1183e8c4d31SAmit Kucheria u32 te_out; 1193e8c4d31SAmit Kucheria u32 int_enable_bit = SOC_DTS_TE_APICA_ENABLE; 1203e8c4d31SAmit Kucheria struct intel_soc_dts_sensors *sensors = dts->sensors; 1213e8c4d31SAmit Kucheria 1223e8c4d31SAmit Kucheria if (sensors->intr_type == INTEL_SOC_DTS_INTERRUPT_MSI) 1233e8c4d31SAmit Kucheria int_enable_bit |= SOC_DTS_TE_MSI_ENABLE; 1243e8c4d31SAmit Kucheria 1253e8c4d31SAmit Kucheria temp_out = (sensors->tj_max - temp) / 1000; 1263e8c4d31SAmit Kucheria 1273e8c4d31SAmit Kucheria status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, 1283e8c4d31SAmit Kucheria SOC_DTS_OFFSET_PTPS, &store_ptps); 1293e8c4d31SAmit Kucheria if (status) 1303e8c4d31SAmit Kucheria return status; 1313e8c4d31SAmit Kucheria 1323e8c4d31SAmit Kucheria out = (store_ptps & ~(0xFF << (thres_index * 8))); 1333e8c4d31SAmit Kucheria out |= (temp_out & 0xFF) << (thres_index * 8); 1343e8c4d31SAmit Kucheria status = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, 1353e8c4d31SAmit Kucheria SOC_DTS_OFFSET_PTPS, out); 1363e8c4d31SAmit Kucheria if (status) 1373e8c4d31SAmit Kucheria return status; 1383e8c4d31SAmit Kucheria 1393e8c4d31SAmit Kucheria pr_debug("update_trip_temp PTPS = %x\n", out); 1403e8c4d31SAmit Kucheria status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, 1413e8c4d31SAmit Kucheria SOC_DTS_OFFSET_PTMC, &out); 1423e8c4d31SAmit Kucheria if (status) 1433e8c4d31SAmit Kucheria goto err_restore_ptps; 1443e8c4d31SAmit Kucheria 1453e8c4d31SAmit Kucheria store_ptmc = out; 1463e8c4d31SAmit Kucheria 1473e8c4d31SAmit Kucheria status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, 1483e8c4d31SAmit Kucheria SOC_DTS_TE_AUX0 + thres_index, 1493e8c4d31SAmit Kucheria &te_out); 1503e8c4d31SAmit Kucheria if (status) 1513e8c4d31SAmit Kucheria goto err_restore_ptmc; 1523e8c4d31SAmit Kucheria 1533e8c4d31SAmit Kucheria store_te_out = te_out; 1543e8c4d31SAmit Kucheria /* Enable for CPU module 0 and module 1 */ 1553e8c4d31SAmit Kucheria out |= (SOC_DTS_CPU_MODULE0_ENABLE_BIT | 1563e8c4d31SAmit Kucheria SOC_DTS_CPU_MODULE1_ENABLE_BIT); 1573e8c4d31SAmit Kucheria if (temp) { 1583e8c4d31SAmit Kucheria if (thres_index) 1593e8c4d31SAmit Kucheria out |= SOC_DTS_AUX1_ENABLE_BIT; 1603e8c4d31SAmit Kucheria else 1613e8c4d31SAmit Kucheria out |= SOC_DTS_AUX0_ENABLE_BIT; 1623e8c4d31SAmit Kucheria te_out |= int_enable_bit; 1633e8c4d31SAmit Kucheria } else { 1643e8c4d31SAmit Kucheria if (thres_index) 1653e8c4d31SAmit Kucheria out &= ~SOC_DTS_AUX1_ENABLE_BIT; 1663e8c4d31SAmit Kucheria else 1673e8c4d31SAmit Kucheria out &= ~SOC_DTS_AUX0_ENABLE_BIT; 1683e8c4d31SAmit Kucheria te_out &= ~int_enable_bit; 1693e8c4d31SAmit Kucheria } 1703e8c4d31SAmit Kucheria status = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, 1713e8c4d31SAmit Kucheria SOC_DTS_OFFSET_PTMC, out); 1723e8c4d31SAmit Kucheria if (status) 1733e8c4d31SAmit Kucheria goto err_restore_te_out; 1743e8c4d31SAmit Kucheria 1753e8c4d31SAmit Kucheria status = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, 1763e8c4d31SAmit Kucheria SOC_DTS_TE_AUX0 + thres_index, 1773e8c4d31SAmit Kucheria te_out); 1783e8c4d31SAmit Kucheria if (status) 1793e8c4d31SAmit Kucheria goto err_restore_te_out; 1803e8c4d31SAmit Kucheria 1813e8c4d31SAmit Kucheria dts->trip_types[thres_index] = trip_type; 1823e8c4d31SAmit Kucheria 1833e8c4d31SAmit Kucheria return 0; 1843e8c4d31SAmit Kucheria err_restore_te_out: 1853e8c4d31SAmit Kucheria iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, 1863e8c4d31SAmit Kucheria SOC_DTS_OFFSET_PTMC, store_te_out); 1873e8c4d31SAmit Kucheria err_restore_ptmc: 1883e8c4d31SAmit Kucheria iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, 1893e8c4d31SAmit Kucheria SOC_DTS_OFFSET_PTMC, store_ptmc); 1903e8c4d31SAmit Kucheria err_restore_ptps: 1913e8c4d31SAmit Kucheria iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, 1923e8c4d31SAmit Kucheria SOC_DTS_OFFSET_PTPS, store_ptps); 1933e8c4d31SAmit Kucheria /* Nothing we can do if restore fails */ 1943e8c4d31SAmit Kucheria 1953e8c4d31SAmit Kucheria return status; 1963e8c4d31SAmit Kucheria } 1973e8c4d31SAmit Kucheria 1983e8c4d31SAmit Kucheria static int sys_set_trip_temp(struct thermal_zone_device *tzd, int trip, 1993e8c4d31SAmit Kucheria int temp) 2003e8c4d31SAmit Kucheria { 2013e8c4d31SAmit Kucheria struct intel_soc_dts_sensor_entry *dts = tzd->devdata; 2023e8c4d31SAmit Kucheria struct intel_soc_dts_sensors *sensors = dts->sensors; 2033e8c4d31SAmit Kucheria int status; 2043e8c4d31SAmit Kucheria 2053e8c4d31SAmit Kucheria if (temp > sensors->tj_max) 2063e8c4d31SAmit Kucheria return -EINVAL; 2073e8c4d31SAmit Kucheria 2083e8c4d31SAmit Kucheria mutex_lock(&sensors->dts_update_lock); 2093e8c4d31SAmit Kucheria status = update_trip_temp(tzd->devdata, trip, temp, 2103e8c4d31SAmit Kucheria dts->trip_types[trip]); 2113e8c4d31SAmit Kucheria mutex_unlock(&sensors->dts_update_lock); 2123e8c4d31SAmit Kucheria 2133e8c4d31SAmit Kucheria return status; 2143e8c4d31SAmit Kucheria } 2153e8c4d31SAmit Kucheria 2163e8c4d31SAmit Kucheria static int sys_get_trip_type(struct thermal_zone_device *tzd, 2173e8c4d31SAmit Kucheria int trip, enum thermal_trip_type *type) 2183e8c4d31SAmit Kucheria { 2193e8c4d31SAmit Kucheria struct intel_soc_dts_sensor_entry *dts; 2203e8c4d31SAmit Kucheria 2213e8c4d31SAmit Kucheria dts = tzd->devdata; 2223e8c4d31SAmit Kucheria 2233e8c4d31SAmit Kucheria *type = dts->trip_types[trip]; 2243e8c4d31SAmit Kucheria 2253e8c4d31SAmit Kucheria return 0; 2263e8c4d31SAmit Kucheria } 2273e8c4d31SAmit Kucheria 2283e8c4d31SAmit Kucheria static int sys_get_curr_temp(struct thermal_zone_device *tzd, 2293e8c4d31SAmit Kucheria int *temp) 2303e8c4d31SAmit Kucheria { 2313e8c4d31SAmit Kucheria int status; 2323e8c4d31SAmit Kucheria u32 out; 2333e8c4d31SAmit Kucheria struct intel_soc_dts_sensor_entry *dts; 2343e8c4d31SAmit Kucheria struct intel_soc_dts_sensors *sensors; 2353e8c4d31SAmit Kucheria 2363e8c4d31SAmit Kucheria dts = tzd->devdata; 2373e8c4d31SAmit Kucheria sensors = dts->sensors; 2383e8c4d31SAmit Kucheria status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, 2393e8c4d31SAmit Kucheria SOC_DTS_OFFSET_TEMP, &out); 2403e8c4d31SAmit Kucheria if (status) 2413e8c4d31SAmit Kucheria return status; 2423e8c4d31SAmit Kucheria 2433e8c4d31SAmit Kucheria out = (out & dts->temp_mask) >> dts->temp_shift; 2443e8c4d31SAmit Kucheria out -= SOC_DTS_TJMAX_ENCODING; 2453e8c4d31SAmit Kucheria *temp = sensors->tj_max - out * 1000; 2463e8c4d31SAmit Kucheria 2473e8c4d31SAmit Kucheria return 0; 2483e8c4d31SAmit Kucheria } 2493e8c4d31SAmit Kucheria 2503e8c4d31SAmit Kucheria static struct thermal_zone_device_ops tzone_ops = { 2513e8c4d31SAmit Kucheria .get_temp = sys_get_curr_temp, 2523e8c4d31SAmit Kucheria .get_trip_temp = sys_get_trip_temp, 2533e8c4d31SAmit Kucheria .get_trip_type = sys_get_trip_type, 2543e8c4d31SAmit Kucheria .set_trip_temp = sys_set_trip_temp, 2553e8c4d31SAmit Kucheria }; 2563e8c4d31SAmit Kucheria 2573e8c4d31SAmit Kucheria static int soc_dts_enable(int id) 2583e8c4d31SAmit Kucheria { 2593e8c4d31SAmit Kucheria u32 out; 2603e8c4d31SAmit Kucheria int ret; 2613e8c4d31SAmit Kucheria 2623e8c4d31SAmit Kucheria ret = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, 2633e8c4d31SAmit Kucheria SOC_DTS_OFFSET_ENABLE, &out); 2643e8c4d31SAmit Kucheria if (ret) 2653e8c4d31SAmit Kucheria return ret; 2663e8c4d31SAmit Kucheria 2673e8c4d31SAmit Kucheria if (!(out & BIT(id))) { 2683e8c4d31SAmit Kucheria out |= BIT(id); 2693e8c4d31SAmit Kucheria ret = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, 2703e8c4d31SAmit Kucheria SOC_DTS_OFFSET_ENABLE, out); 2713e8c4d31SAmit Kucheria if (ret) 2723e8c4d31SAmit Kucheria return ret; 2733e8c4d31SAmit Kucheria } 2743e8c4d31SAmit Kucheria 2753e8c4d31SAmit Kucheria return ret; 2763e8c4d31SAmit Kucheria } 2773e8c4d31SAmit Kucheria 2783e8c4d31SAmit Kucheria static void remove_dts_thermal_zone(struct intel_soc_dts_sensor_entry *dts) 2793e8c4d31SAmit Kucheria { 2803e8c4d31SAmit Kucheria if (dts) { 2813e8c4d31SAmit Kucheria iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, 2823e8c4d31SAmit Kucheria SOC_DTS_OFFSET_ENABLE, dts->store_status); 2833e8c4d31SAmit Kucheria thermal_zone_device_unregister(dts->tzone); 2843e8c4d31SAmit Kucheria } 2853e8c4d31SAmit Kucheria } 2863e8c4d31SAmit Kucheria 2873e8c4d31SAmit Kucheria static int add_dts_thermal_zone(int id, struct intel_soc_dts_sensor_entry *dts, 2883e8c4d31SAmit Kucheria bool notification_support, int trip_cnt, 2893e8c4d31SAmit Kucheria int read_only_trip_cnt) 2903e8c4d31SAmit Kucheria { 2913e8c4d31SAmit Kucheria char name[10]; 2923e8c4d31SAmit Kucheria int trip_count = 0; 2933e8c4d31SAmit Kucheria int trip_mask = 0; 2943e8c4d31SAmit Kucheria u32 store_ptps; 2953e8c4d31SAmit Kucheria int ret; 2963e8c4d31SAmit Kucheria int i; 2973e8c4d31SAmit Kucheria 2983e8c4d31SAmit Kucheria /* Store status to restor on exit */ 2993e8c4d31SAmit Kucheria ret = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, 3003e8c4d31SAmit Kucheria SOC_DTS_OFFSET_ENABLE, &dts->store_status); 3013e8c4d31SAmit Kucheria if (ret) 3023e8c4d31SAmit Kucheria goto err_ret; 3033e8c4d31SAmit Kucheria 3043e8c4d31SAmit Kucheria dts->id = id; 3053e8c4d31SAmit Kucheria dts->temp_mask = 0x00FF << (id * 8); 3063e8c4d31SAmit Kucheria dts->temp_shift = id * 8; 3073e8c4d31SAmit Kucheria if (notification_support) { 3083e8c4d31SAmit Kucheria trip_count = min(SOC_MAX_DTS_TRIPS, trip_cnt); 3093e8c4d31SAmit Kucheria trip_mask = BIT(trip_count - read_only_trip_cnt) - 1; 3103e8c4d31SAmit Kucheria } 3113e8c4d31SAmit Kucheria 3123e8c4d31SAmit Kucheria /* Check if the writable trip we provide is not used by BIOS */ 3133e8c4d31SAmit Kucheria ret = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, 3143e8c4d31SAmit Kucheria SOC_DTS_OFFSET_PTPS, &store_ptps); 3153e8c4d31SAmit Kucheria if (ret) 3163e8c4d31SAmit Kucheria trip_mask = 0; 3173e8c4d31SAmit Kucheria else { 3183e8c4d31SAmit Kucheria for (i = 0; i < trip_count; ++i) { 3193e8c4d31SAmit Kucheria if (trip_mask & BIT(i)) 3203e8c4d31SAmit Kucheria if (store_ptps & (0xff << (i * 8))) 3213e8c4d31SAmit Kucheria trip_mask &= ~BIT(i); 3223e8c4d31SAmit Kucheria } 3233e8c4d31SAmit Kucheria } 3243e8c4d31SAmit Kucheria dts->trip_mask = trip_mask; 3253e8c4d31SAmit Kucheria dts->trip_count = trip_count; 3263e8c4d31SAmit Kucheria snprintf(name, sizeof(name), "soc_dts%d", id); 3273e8c4d31SAmit Kucheria dts->tzone = thermal_zone_device_register(name, 3283e8c4d31SAmit Kucheria trip_count, 3293e8c4d31SAmit Kucheria trip_mask, 3303e8c4d31SAmit Kucheria dts, &tzone_ops, 3313e8c4d31SAmit Kucheria NULL, 0, 0); 3323e8c4d31SAmit Kucheria if (IS_ERR(dts->tzone)) { 3333e8c4d31SAmit Kucheria ret = PTR_ERR(dts->tzone); 3343e8c4d31SAmit Kucheria goto err_ret; 3353e8c4d31SAmit Kucheria } 3363e8c4d31SAmit Kucheria 3373e8c4d31SAmit Kucheria ret = soc_dts_enable(id); 3383e8c4d31SAmit Kucheria if (ret) 3393e8c4d31SAmit Kucheria goto err_enable; 3403e8c4d31SAmit Kucheria 3413e8c4d31SAmit Kucheria return 0; 3423e8c4d31SAmit Kucheria err_enable: 3433e8c4d31SAmit Kucheria thermal_zone_device_unregister(dts->tzone); 3443e8c4d31SAmit Kucheria err_ret: 3453e8c4d31SAmit Kucheria return ret; 3463e8c4d31SAmit Kucheria } 3473e8c4d31SAmit Kucheria 3483e8c4d31SAmit Kucheria int intel_soc_dts_iosf_add_read_only_critical_trip( 3493e8c4d31SAmit Kucheria struct intel_soc_dts_sensors *sensors, int critical_offset) 3503e8c4d31SAmit Kucheria { 3513e8c4d31SAmit Kucheria int i, j; 3523e8c4d31SAmit Kucheria 3533e8c4d31SAmit Kucheria for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) { 3543e8c4d31SAmit Kucheria for (j = 0; j < sensors->soc_dts[i].trip_count; ++j) { 3553e8c4d31SAmit Kucheria if (!(sensors->soc_dts[i].trip_mask & BIT(j))) { 3563e8c4d31SAmit Kucheria return update_trip_temp(&sensors->soc_dts[i], j, 3573e8c4d31SAmit Kucheria sensors->tj_max - critical_offset, 3583e8c4d31SAmit Kucheria THERMAL_TRIP_CRITICAL); 3593e8c4d31SAmit Kucheria } 3603e8c4d31SAmit Kucheria } 3613e8c4d31SAmit Kucheria } 3623e8c4d31SAmit Kucheria 3633e8c4d31SAmit Kucheria return -EINVAL; 3643e8c4d31SAmit Kucheria } 3653e8c4d31SAmit Kucheria EXPORT_SYMBOL_GPL(intel_soc_dts_iosf_add_read_only_critical_trip); 3663e8c4d31SAmit Kucheria 3673e8c4d31SAmit Kucheria void intel_soc_dts_iosf_interrupt_handler(struct intel_soc_dts_sensors *sensors) 3683e8c4d31SAmit Kucheria { 3693e8c4d31SAmit Kucheria u32 sticky_out; 3703e8c4d31SAmit Kucheria int status; 3713e8c4d31SAmit Kucheria u32 ptmc_out; 3723e8c4d31SAmit Kucheria unsigned long flags; 3733e8c4d31SAmit Kucheria 3743e8c4d31SAmit Kucheria spin_lock_irqsave(&sensors->intr_notify_lock, flags); 3753e8c4d31SAmit Kucheria 3763e8c4d31SAmit Kucheria status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, 3773e8c4d31SAmit Kucheria SOC_DTS_OFFSET_PTMC, &ptmc_out); 3783e8c4d31SAmit Kucheria ptmc_out |= SOC_DTS_PTMC_APIC_DEASSERT_BIT; 3793e8c4d31SAmit Kucheria status = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, 3803e8c4d31SAmit Kucheria SOC_DTS_OFFSET_PTMC, ptmc_out); 3813e8c4d31SAmit Kucheria 3823e8c4d31SAmit Kucheria status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, 3833e8c4d31SAmit Kucheria SOC_DTS_OFFSET_PTTSS, &sticky_out); 3843e8c4d31SAmit Kucheria pr_debug("status %d PTTSS %x\n", status, sticky_out); 3853e8c4d31SAmit Kucheria if (sticky_out & SOC_DTS_TRIP_MASK) { 3863e8c4d31SAmit Kucheria int i; 3873e8c4d31SAmit Kucheria /* reset sticky bit */ 3883e8c4d31SAmit Kucheria status = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, 3893e8c4d31SAmit Kucheria SOC_DTS_OFFSET_PTTSS, sticky_out); 3903e8c4d31SAmit Kucheria spin_unlock_irqrestore(&sensors->intr_notify_lock, flags); 3913e8c4d31SAmit Kucheria 3923e8c4d31SAmit Kucheria for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) { 3933e8c4d31SAmit Kucheria pr_debug("TZD update for zone %d\n", i); 3943e8c4d31SAmit Kucheria thermal_zone_device_update(sensors->soc_dts[i].tzone, 3953e8c4d31SAmit Kucheria THERMAL_EVENT_UNSPECIFIED); 3963e8c4d31SAmit Kucheria } 3973e8c4d31SAmit Kucheria } else 3983e8c4d31SAmit Kucheria spin_unlock_irqrestore(&sensors->intr_notify_lock, flags); 3993e8c4d31SAmit Kucheria } 4003e8c4d31SAmit Kucheria EXPORT_SYMBOL_GPL(intel_soc_dts_iosf_interrupt_handler); 4013e8c4d31SAmit Kucheria 4023e8c4d31SAmit Kucheria struct intel_soc_dts_sensors *intel_soc_dts_iosf_init( 4033e8c4d31SAmit Kucheria enum intel_soc_dts_interrupt_type intr_type, int trip_count, 4043e8c4d31SAmit Kucheria int read_only_trip_count) 4053e8c4d31SAmit Kucheria { 4063e8c4d31SAmit Kucheria struct intel_soc_dts_sensors *sensors; 4073e8c4d31SAmit Kucheria bool notification; 4083e8c4d31SAmit Kucheria u32 tj_max; 4093e8c4d31SAmit Kucheria int ret; 4103e8c4d31SAmit Kucheria int i; 4113e8c4d31SAmit Kucheria 4123e8c4d31SAmit Kucheria if (!iosf_mbi_available()) 4133e8c4d31SAmit Kucheria return ERR_PTR(-ENODEV); 4143e8c4d31SAmit Kucheria 4153e8c4d31SAmit Kucheria if (!trip_count || read_only_trip_count > trip_count) 4163e8c4d31SAmit Kucheria return ERR_PTR(-EINVAL); 4173e8c4d31SAmit Kucheria 4183e8c4d31SAmit Kucheria if (get_tj_max(&tj_max)) 4193e8c4d31SAmit Kucheria return ERR_PTR(-EINVAL); 4203e8c4d31SAmit Kucheria 4213e8c4d31SAmit Kucheria sensors = kzalloc(sizeof(*sensors), GFP_KERNEL); 4223e8c4d31SAmit Kucheria if (!sensors) 4233e8c4d31SAmit Kucheria return ERR_PTR(-ENOMEM); 4243e8c4d31SAmit Kucheria 4253e8c4d31SAmit Kucheria spin_lock_init(&sensors->intr_notify_lock); 4263e8c4d31SAmit Kucheria mutex_init(&sensors->dts_update_lock); 4273e8c4d31SAmit Kucheria sensors->intr_type = intr_type; 4283e8c4d31SAmit Kucheria sensors->tj_max = tj_max; 4293e8c4d31SAmit Kucheria if (intr_type == INTEL_SOC_DTS_INTERRUPT_NONE) 4303e8c4d31SAmit Kucheria notification = false; 4313e8c4d31SAmit Kucheria else 4323e8c4d31SAmit Kucheria notification = true; 4333e8c4d31SAmit Kucheria for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) { 4343e8c4d31SAmit Kucheria sensors->soc_dts[i].sensors = sensors; 4353e8c4d31SAmit Kucheria ret = add_dts_thermal_zone(i, &sensors->soc_dts[i], 4363e8c4d31SAmit Kucheria notification, trip_count, 4373e8c4d31SAmit Kucheria read_only_trip_count); 4383e8c4d31SAmit Kucheria if (ret) 4393e8c4d31SAmit Kucheria goto err_free; 4403e8c4d31SAmit Kucheria } 4413e8c4d31SAmit Kucheria 4423e8c4d31SAmit Kucheria for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) { 4433e8c4d31SAmit Kucheria ret = update_trip_temp(&sensors->soc_dts[i], 0, 0, 4443e8c4d31SAmit Kucheria THERMAL_TRIP_PASSIVE); 4453e8c4d31SAmit Kucheria if (ret) 4463e8c4d31SAmit Kucheria goto err_remove_zone; 4473e8c4d31SAmit Kucheria 4483e8c4d31SAmit Kucheria ret = update_trip_temp(&sensors->soc_dts[i], 1, 0, 4493e8c4d31SAmit Kucheria THERMAL_TRIP_PASSIVE); 4503e8c4d31SAmit Kucheria if (ret) 4513e8c4d31SAmit Kucheria goto err_remove_zone; 4523e8c4d31SAmit Kucheria } 4533e8c4d31SAmit Kucheria 4543e8c4d31SAmit Kucheria return sensors; 4553e8c4d31SAmit Kucheria err_remove_zone: 4563e8c4d31SAmit Kucheria for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) 4573e8c4d31SAmit Kucheria remove_dts_thermal_zone(&sensors->soc_dts[i]); 4583e8c4d31SAmit Kucheria 4593e8c4d31SAmit Kucheria err_free: 4603e8c4d31SAmit Kucheria kfree(sensors); 4613e8c4d31SAmit Kucheria return ERR_PTR(ret); 4623e8c4d31SAmit Kucheria } 4633e8c4d31SAmit Kucheria EXPORT_SYMBOL_GPL(intel_soc_dts_iosf_init); 4643e8c4d31SAmit Kucheria 4653e8c4d31SAmit Kucheria void intel_soc_dts_iosf_exit(struct intel_soc_dts_sensors *sensors) 4663e8c4d31SAmit Kucheria { 4673e8c4d31SAmit Kucheria int i; 4683e8c4d31SAmit Kucheria 4693e8c4d31SAmit Kucheria for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) { 4703e8c4d31SAmit Kucheria update_trip_temp(&sensors->soc_dts[i], 0, 0, 0); 4713e8c4d31SAmit Kucheria update_trip_temp(&sensors->soc_dts[i], 1, 0, 0); 4723e8c4d31SAmit Kucheria remove_dts_thermal_zone(&sensors->soc_dts[i]); 4733e8c4d31SAmit Kucheria } 4743e8c4d31SAmit Kucheria kfree(sensors); 4753e8c4d31SAmit Kucheria } 4763e8c4d31SAmit Kucheria EXPORT_SYMBOL_GPL(intel_soc_dts_iosf_exit); 4773e8c4d31SAmit Kucheria 4783e8c4d31SAmit Kucheria MODULE_LICENSE("GPL v2"); 479