12025cf9eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 23e8c4d31SAmit Kucheria /* 33e8c4d31SAmit Kucheria * intel_soc_dts_iosf.c 43e8c4d31SAmit Kucheria * Copyright (c) 2015, Intel Corporation. 53e8c4d31SAmit Kucheria */ 63e8c4d31SAmit Kucheria 73e8c4d31SAmit Kucheria #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 83e8c4d31SAmit Kucheria 99f00ebf5SWilliam Breathitt Gray #include <linux/bitops.h> 10955fb871SZhang Rui #include <linux/intel_tcc.h> 113e8c4d31SAmit Kucheria #include <linux/module.h> 123e8c4d31SAmit Kucheria #include <linux/slab.h> 133e8c4d31SAmit Kucheria #include <linux/interrupt.h> 143e8c4d31SAmit Kucheria #include <asm/iosf_mbi.h> 153e8c4d31SAmit Kucheria #include "intel_soc_dts_iosf.h" 163e8c4d31SAmit Kucheria 173e8c4d31SAmit Kucheria #define SOC_DTS_OFFSET_ENABLE 0xB0 183e8c4d31SAmit Kucheria #define SOC_DTS_OFFSET_TEMP 0xB1 193e8c4d31SAmit Kucheria 203e8c4d31SAmit Kucheria #define SOC_DTS_OFFSET_PTPS 0xB2 213e8c4d31SAmit Kucheria #define SOC_DTS_OFFSET_PTTS 0xB3 223e8c4d31SAmit Kucheria #define SOC_DTS_OFFSET_PTTSS 0xB4 233e8c4d31SAmit Kucheria #define SOC_DTS_OFFSET_PTMC 0x80 243e8c4d31SAmit Kucheria #define SOC_DTS_TE_AUX0 0xB5 253e8c4d31SAmit Kucheria #define SOC_DTS_TE_AUX1 0xB6 263e8c4d31SAmit Kucheria 273e8c4d31SAmit Kucheria #define SOC_DTS_AUX0_ENABLE_BIT BIT(0) 283e8c4d31SAmit Kucheria #define SOC_DTS_AUX1_ENABLE_BIT BIT(1) 293e8c4d31SAmit Kucheria #define SOC_DTS_CPU_MODULE0_ENABLE_BIT BIT(16) 303e8c4d31SAmit Kucheria #define SOC_DTS_CPU_MODULE1_ENABLE_BIT BIT(17) 313e8c4d31SAmit Kucheria #define SOC_DTS_TE_SCI_ENABLE BIT(9) 323e8c4d31SAmit Kucheria #define SOC_DTS_TE_SMI_ENABLE BIT(10) 333e8c4d31SAmit Kucheria #define SOC_DTS_TE_MSI_ENABLE BIT(11) 343e8c4d31SAmit Kucheria #define SOC_DTS_TE_APICA_ENABLE BIT(14) 353e8c4d31SAmit Kucheria #define SOC_DTS_PTMC_APIC_DEASSERT_BIT BIT(4) 363e8c4d31SAmit Kucheria 373e8c4d31SAmit Kucheria /* DTS encoding for TJ MAX temperature */ 383e8c4d31SAmit Kucheria #define SOC_DTS_TJMAX_ENCODING 0x7F 393e8c4d31SAmit Kucheria 403e8c4d31SAmit Kucheria /* Mask for two trips in status bits */ 413e8c4d31SAmit Kucheria #define SOC_DTS_TRIP_MASK 0x03 423e8c4d31SAmit Kucheria 433e8c4d31SAmit Kucheria static int sys_get_trip_temp(struct thermal_zone_device *tzd, int trip, 443e8c4d31SAmit Kucheria int *temp) 453e8c4d31SAmit Kucheria { 463e8c4d31SAmit Kucheria int status; 473e8c4d31SAmit Kucheria u32 out; 483e8c4d31SAmit Kucheria struct intel_soc_dts_sensor_entry *dts; 493e8c4d31SAmit Kucheria struct intel_soc_dts_sensors *sensors; 503e8c4d31SAmit Kucheria 515f68d078SDaniel Lezcano dts = thermal_zone_device_priv(tzd); 523e8c4d31SAmit Kucheria sensors = dts->sensors; 533e8c4d31SAmit Kucheria mutex_lock(&sensors->dts_update_lock); 543e8c4d31SAmit Kucheria status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, 553e8c4d31SAmit Kucheria SOC_DTS_OFFSET_PTPS, &out); 563e8c4d31SAmit Kucheria mutex_unlock(&sensors->dts_update_lock); 573e8c4d31SAmit Kucheria if (status) 583e8c4d31SAmit Kucheria return status; 593e8c4d31SAmit Kucheria 603e8c4d31SAmit Kucheria out = (out >> (trip * 8)) & SOC_DTS_TJMAX_ENCODING; 613e8c4d31SAmit Kucheria if (!out) 623e8c4d31SAmit Kucheria *temp = 0; 633e8c4d31SAmit Kucheria else 643e8c4d31SAmit Kucheria *temp = sensors->tj_max - out * 1000; 653e8c4d31SAmit Kucheria 663e8c4d31SAmit Kucheria return 0; 673e8c4d31SAmit Kucheria } 683e8c4d31SAmit Kucheria 69cbc28057SRafael J. Wysocki static int update_trip_temp(struct intel_soc_dts_sensors *sensors, 700b28ba27SRafael J. Wysocki int thres_index, int temp) 713e8c4d31SAmit Kucheria { 723e8c4d31SAmit Kucheria int status; 733e8c4d31SAmit Kucheria u32 temp_out; 743e8c4d31SAmit Kucheria u32 out; 759f00ebf5SWilliam Breathitt Gray unsigned long update_ptps; 763e8c4d31SAmit Kucheria u32 store_ptps; 773e8c4d31SAmit Kucheria u32 store_ptmc; 783e8c4d31SAmit Kucheria u32 store_te_out; 793e8c4d31SAmit Kucheria u32 te_out; 803e8c4d31SAmit Kucheria u32 int_enable_bit = SOC_DTS_TE_APICA_ENABLE; 813e8c4d31SAmit Kucheria 823e8c4d31SAmit Kucheria if (sensors->intr_type == INTEL_SOC_DTS_INTERRUPT_MSI) 833e8c4d31SAmit Kucheria int_enable_bit |= SOC_DTS_TE_MSI_ENABLE; 843e8c4d31SAmit Kucheria 853e8c4d31SAmit Kucheria temp_out = (sensors->tj_max - temp) / 1000; 863e8c4d31SAmit Kucheria 873e8c4d31SAmit Kucheria status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, 883e8c4d31SAmit Kucheria SOC_DTS_OFFSET_PTPS, &store_ptps); 893e8c4d31SAmit Kucheria if (status) 903e8c4d31SAmit Kucheria return status; 913e8c4d31SAmit Kucheria 929f00ebf5SWilliam Breathitt Gray update_ptps = store_ptps; 939f00ebf5SWilliam Breathitt Gray bitmap_set_value8(&update_ptps, temp_out & 0xFF, thres_index * 8); 949f00ebf5SWilliam Breathitt Gray out = update_ptps; 959f00ebf5SWilliam Breathitt Gray 963e8c4d31SAmit Kucheria status = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, 973e8c4d31SAmit Kucheria SOC_DTS_OFFSET_PTPS, out); 983e8c4d31SAmit Kucheria if (status) 993e8c4d31SAmit Kucheria return status; 1003e8c4d31SAmit Kucheria 1013e8c4d31SAmit Kucheria pr_debug("update_trip_temp PTPS = %x\n", out); 1023e8c4d31SAmit Kucheria status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, 1033e8c4d31SAmit Kucheria SOC_DTS_OFFSET_PTMC, &out); 1043e8c4d31SAmit Kucheria if (status) 1053e8c4d31SAmit Kucheria goto err_restore_ptps; 1063e8c4d31SAmit Kucheria 1073e8c4d31SAmit Kucheria store_ptmc = out; 1083e8c4d31SAmit Kucheria 1093e8c4d31SAmit Kucheria status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, 1103e8c4d31SAmit Kucheria SOC_DTS_TE_AUX0 + thres_index, 1113e8c4d31SAmit Kucheria &te_out); 1123e8c4d31SAmit Kucheria if (status) 1133e8c4d31SAmit Kucheria goto err_restore_ptmc; 1143e8c4d31SAmit Kucheria 1153e8c4d31SAmit Kucheria store_te_out = te_out; 1163e8c4d31SAmit Kucheria /* Enable for CPU module 0 and module 1 */ 1173e8c4d31SAmit Kucheria out |= (SOC_DTS_CPU_MODULE0_ENABLE_BIT | 1183e8c4d31SAmit Kucheria SOC_DTS_CPU_MODULE1_ENABLE_BIT); 1193e8c4d31SAmit Kucheria if (temp) { 1203e8c4d31SAmit Kucheria if (thres_index) 1213e8c4d31SAmit Kucheria out |= SOC_DTS_AUX1_ENABLE_BIT; 1223e8c4d31SAmit Kucheria else 1233e8c4d31SAmit Kucheria out |= SOC_DTS_AUX0_ENABLE_BIT; 1243e8c4d31SAmit Kucheria te_out |= int_enable_bit; 1253e8c4d31SAmit Kucheria } else { 1263e8c4d31SAmit Kucheria if (thres_index) 1273e8c4d31SAmit Kucheria out &= ~SOC_DTS_AUX1_ENABLE_BIT; 1283e8c4d31SAmit Kucheria else 1293e8c4d31SAmit Kucheria out &= ~SOC_DTS_AUX0_ENABLE_BIT; 1303e8c4d31SAmit Kucheria te_out &= ~int_enable_bit; 1313e8c4d31SAmit Kucheria } 1323e8c4d31SAmit Kucheria status = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, 1333e8c4d31SAmit Kucheria SOC_DTS_OFFSET_PTMC, out); 1343e8c4d31SAmit Kucheria if (status) 1353e8c4d31SAmit Kucheria goto err_restore_te_out; 1363e8c4d31SAmit Kucheria 1373e8c4d31SAmit Kucheria status = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, 1383e8c4d31SAmit Kucheria SOC_DTS_TE_AUX0 + thres_index, 1393e8c4d31SAmit Kucheria te_out); 1403e8c4d31SAmit Kucheria if (status) 1413e8c4d31SAmit Kucheria goto err_restore_te_out; 1423e8c4d31SAmit Kucheria 1433e8c4d31SAmit Kucheria return 0; 1443e8c4d31SAmit Kucheria err_restore_te_out: 1453e8c4d31SAmit Kucheria iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, 1463e8c4d31SAmit Kucheria SOC_DTS_OFFSET_PTMC, store_te_out); 1473e8c4d31SAmit Kucheria err_restore_ptmc: 1483e8c4d31SAmit Kucheria iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, 1493e8c4d31SAmit Kucheria SOC_DTS_OFFSET_PTMC, store_ptmc); 1503e8c4d31SAmit Kucheria err_restore_ptps: 1513e8c4d31SAmit Kucheria iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, 1523e8c4d31SAmit Kucheria SOC_DTS_OFFSET_PTPS, store_ptps); 1533e8c4d31SAmit Kucheria /* Nothing we can do if restore fails */ 1543e8c4d31SAmit Kucheria 1553e8c4d31SAmit Kucheria return status; 1563e8c4d31SAmit Kucheria } 1573e8c4d31SAmit Kucheria 1580b28ba27SRafael J. Wysocki static int configure_trip(struct intel_soc_dts_sensor_entry *dts, 1590b28ba27SRafael J. Wysocki int thres_index, enum thermal_trip_type trip_type, 1600b28ba27SRafael J. Wysocki int temp) 1610b28ba27SRafael J. Wysocki { 1620b28ba27SRafael J. Wysocki int ret; 1630b28ba27SRafael J. Wysocki 164cbc28057SRafael J. Wysocki ret = update_trip_temp(dts->sensors, thres_index, temp); 1650b28ba27SRafael J. Wysocki if (ret) 1660b28ba27SRafael J. Wysocki return ret; 1670b28ba27SRafael J. Wysocki 1680b28ba27SRafael J. Wysocki dts->trip_types[thres_index] = trip_type; 1690b28ba27SRafael J. Wysocki 1700b28ba27SRafael J. Wysocki return 0; 1710b28ba27SRafael J. Wysocki } 1720b28ba27SRafael J. Wysocki 1733e8c4d31SAmit Kucheria static int sys_set_trip_temp(struct thermal_zone_device *tzd, int trip, 1743e8c4d31SAmit Kucheria int temp) 1753e8c4d31SAmit Kucheria { 1765f68d078SDaniel Lezcano struct intel_soc_dts_sensor_entry *dts = thermal_zone_device_priv(tzd); 1773e8c4d31SAmit Kucheria struct intel_soc_dts_sensors *sensors = dts->sensors; 1783e8c4d31SAmit Kucheria int status; 1793e8c4d31SAmit Kucheria 1803e8c4d31SAmit Kucheria if (temp > sensors->tj_max) 1813e8c4d31SAmit Kucheria return -EINVAL; 1823e8c4d31SAmit Kucheria 1833e8c4d31SAmit Kucheria mutex_lock(&sensors->dts_update_lock); 184cbc28057SRafael J. Wysocki status = update_trip_temp(sensors, trip, temp); 1853e8c4d31SAmit Kucheria mutex_unlock(&sensors->dts_update_lock); 1863e8c4d31SAmit Kucheria 1873e8c4d31SAmit Kucheria return status; 1883e8c4d31SAmit Kucheria } 1893e8c4d31SAmit Kucheria 1903e8c4d31SAmit Kucheria static int sys_get_trip_type(struct thermal_zone_device *tzd, 1913e8c4d31SAmit Kucheria int trip, enum thermal_trip_type *type) 1923e8c4d31SAmit Kucheria { 1935f68d078SDaniel Lezcano struct intel_soc_dts_sensor_entry *dts = thermal_zone_device_priv(tzd); 1943e8c4d31SAmit Kucheria 1953e8c4d31SAmit Kucheria *type = dts->trip_types[trip]; 1963e8c4d31SAmit Kucheria 1973e8c4d31SAmit Kucheria return 0; 1983e8c4d31SAmit Kucheria } 1993e8c4d31SAmit Kucheria 2003e8c4d31SAmit Kucheria static int sys_get_curr_temp(struct thermal_zone_device *tzd, 2013e8c4d31SAmit Kucheria int *temp) 2023e8c4d31SAmit Kucheria { 2033e8c4d31SAmit Kucheria int status; 2043e8c4d31SAmit Kucheria u32 out; 2055f68d078SDaniel Lezcano struct intel_soc_dts_sensor_entry *dts = thermal_zone_device_priv(tzd); 2063e8c4d31SAmit Kucheria struct intel_soc_dts_sensors *sensors; 2079f00ebf5SWilliam Breathitt Gray unsigned long raw; 2083e8c4d31SAmit Kucheria 2093e8c4d31SAmit Kucheria sensors = dts->sensors; 2103e8c4d31SAmit Kucheria status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, 2113e8c4d31SAmit Kucheria SOC_DTS_OFFSET_TEMP, &out); 2123e8c4d31SAmit Kucheria if (status) 2133e8c4d31SAmit Kucheria return status; 2143e8c4d31SAmit Kucheria 2159f00ebf5SWilliam Breathitt Gray raw = out; 2169f00ebf5SWilliam Breathitt Gray out = bitmap_get_value8(&raw, dts->id * 8) - SOC_DTS_TJMAX_ENCODING; 2173e8c4d31SAmit Kucheria *temp = sensors->tj_max - out * 1000; 2183e8c4d31SAmit Kucheria 2193e8c4d31SAmit Kucheria return 0; 2203e8c4d31SAmit Kucheria } 2213e8c4d31SAmit Kucheria 2223e8c4d31SAmit Kucheria static struct thermal_zone_device_ops tzone_ops = { 2233e8c4d31SAmit Kucheria .get_temp = sys_get_curr_temp, 2243e8c4d31SAmit Kucheria .get_trip_temp = sys_get_trip_temp, 2253e8c4d31SAmit Kucheria .get_trip_type = sys_get_trip_type, 2263e8c4d31SAmit Kucheria .set_trip_temp = sys_set_trip_temp, 2273e8c4d31SAmit Kucheria }; 2283e8c4d31SAmit Kucheria 2293e8c4d31SAmit Kucheria static int soc_dts_enable(int id) 2303e8c4d31SAmit Kucheria { 2313e8c4d31SAmit Kucheria u32 out; 2323e8c4d31SAmit Kucheria int ret; 2333e8c4d31SAmit Kucheria 2343e8c4d31SAmit Kucheria ret = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, 2353e8c4d31SAmit Kucheria SOC_DTS_OFFSET_ENABLE, &out); 2363e8c4d31SAmit Kucheria if (ret) 2373e8c4d31SAmit Kucheria return ret; 2383e8c4d31SAmit Kucheria 2393e8c4d31SAmit Kucheria if (!(out & BIT(id))) { 2403e8c4d31SAmit Kucheria out |= BIT(id); 2413e8c4d31SAmit Kucheria ret = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, 2423e8c4d31SAmit Kucheria SOC_DTS_OFFSET_ENABLE, out); 2433e8c4d31SAmit Kucheria if (ret) 2443e8c4d31SAmit Kucheria return ret; 2453e8c4d31SAmit Kucheria } 2463e8c4d31SAmit Kucheria 2473e8c4d31SAmit Kucheria return ret; 2483e8c4d31SAmit Kucheria } 2493e8c4d31SAmit Kucheria 2503e8c4d31SAmit Kucheria static void remove_dts_thermal_zone(struct intel_soc_dts_sensor_entry *dts) 2513e8c4d31SAmit Kucheria { 2523e8c4d31SAmit Kucheria if (dts) { 2533e8c4d31SAmit Kucheria iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, 2543e8c4d31SAmit Kucheria SOC_DTS_OFFSET_ENABLE, dts->store_status); 2553e8c4d31SAmit Kucheria thermal_zone_device_unregister(dts->tzone); 2563e8c4d31SAmit Kucheria } 2573e8c4d31SAmit Kucheria } 2583e8c4d31SAmit Kucheria 2593e8c4d31SAmit Kucheria static int add_dts_thermal_zone(int id, struct intel_soc_dts_sensor_entry *dts, 2604f164435SRafael J. Wysocki int read_only_trip_cnt) 2613e8c4d31SAmit Kucheria { 2623e8c4d31SAmit Kucheria char name[10]; 2639f00ebf5SWilliam Breathitt Gray unsigned long trip; 2644f164435SRafael J. Wysocki int writable_trip_cnt; 2654f164435SRafael J. Wysocki int trip_mask; 2669f00ebf5SWilliam Breathitt Gray unsigned long ptps; 2673e8c4d31SAmit Kucheria u32 store_ptps; 2689f00ebf5SWilliam Breathitt Gray unsigned long i; 2693e8c4d31SAmit Kucheria int ret; 2703e8c4d31SAmit Kucheria 2713e8c4d31SAmit Kucheria /* Store status to restor on exit */ 2723e8c4d31SAmit Kucheria ret = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, 2733e8c4d31SAmit Kucheria SOC_DTS_OFFSET_ENABLE, &dts->store_status); 2743e8c4d31SAmit Kucheria if (ret) 2753e8c4d31SAmit Kucheria goto err_ret; 2763e8c4d31SAmit Kucheria 2773e8c4d31SAmit Kucheria dts->id = id; 2784f164435SRafael J. Wysocki 279b429b6ffSRafael J. Wysocki writable_trip_cnt = SOC_MAX_DTS_TRIPS - read_only_trip_cnt; 2809f00ebf5SWilliam Breathitt Gray trip_mask = GENMASK(writable_trip_cnt - 1, 0); 2813e8c4d31SAmit Kucheria 2823e8c4d31SAmit Kucheria /* Check if the writable trip we provide is not used by BIOS */ 2833e8c4d31SAmit Kucheria ret = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, 2843e8c4d31SAmit Kucheria SOC_DTS_OFFSET_PTPS, &store_ptps); 2853e8c4d31SAmit Kucheria if (ret) 2863e8c4d31SAmit Kucheria trip_mask = 0; 2873e8c4d31SAmit Kucheria else { 2889f00ebf5SWilliam Breathitt Gray ptps = store_ptps; 2899f00ebf5SWilliam Breathitt Gray for_each_set_clump8(i, trip, &ptps, writable_trip_cnt * 8) 2909f00ebf5SWilliam Breathitt Gray trip_mask &= ~BIT(i / 8); 2913e8c4d31SAmit Kucheria } 2923e8c4d31SAmit Kucheria dts->trip_mask = trip_mask; 2933e8c4d31SAmit Kucheria snprintf(name, sizeof(name), "soc_dts%d", id); 2943e8c4d31SAmit Kucheria dts->tzone = thermal_zone_device_register(name, 295b429b6ffSRafael J. Wysocki SOC_MAX_DTS_TRIPS, 2963e8c4d31SAmit Kucheria trip_mask, 2973e8c4d31SAmit Kucheria dts, &tzone_ops, 2983e8c4d31SAmit Kucheria NULL, 0, 0); 2993e8c4d31SAmit Kucheria if (IS_ERR(dts->tzone)) { 3003e8c4d31SAmit Kucheria ret = PTR_ERR(dts->tzone); 3013e8c4d31SAmit Kucheria goto err_ret; 3023e8c4d31SAmit Kucheria } 303bbcf90c0SAndrzej Pietrasiewicz ret = thermal_zone_device_enable(dts->tzone); 304bbcf90c0SAndrzej Pietrasiewicz if (ret) 305bbcf90c0SAndrzej Pietrasiewicz goto err_enable; 3063e8c4d31SAmit Kucheria 3073e8c4d31SAmit Kucheria ret = soc_dts_enable(id); 3083e8c4d31SAmit Kucheria if (ret) 3093e8c4d31SAmit Kucheria goto err_enable; 3103e8c4d31SAmit Kucheria 3113e8c4d31SAmit Kucheria return 0; 3123e8c4d31SAmit Kucheria err_enable: 3133e8c4d31SAmit Kucheria thermal_zone_device_unregister(dts->tzone); 3143e8c4d31SAmit Kucheria err_ret: 3153e8c4d31SAmit Kucheria return ret; 3163e8c4d31SAmit Kucheria } 3173e8c4d31SAmit Kucheria 3183e8c4d31SAmit Kucheria int intel_soc_dts_iosf_add_read_only_critical_trip( 3193e8c4d31SAmit Kucheria struct intel_soc_dts_sensors *sensors, int critical_offset) 3203e8c4d31SAmit Kucheria { 3213e8c4d31SAmit Kucheria int i, j; 3223e8c4d31SAmit Kucheria 3233e8c4d31SAmit Kucheria for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) { 324da5e562fSAndy Shevchenko struct intel_soc_dts_sensor_entry *entry = &sensors->soc_dts[i]; 325da5e562fSAndy Shevchenko int temp = sensors->tj_max - critical_offset; 326da5e562fSAndy Shevchenko unsigned long mask = entry->trip_mask; 327da5e562fSAndy Shevchenko 328b429b6ffSRafael J. Wysocki j = find_first_zero_bit(&mask, SOC_MAX_DTS_TRIPS); 329b429b6ffSRafael J. Wysocki if (j < SOC_MAX_DTS_TRIPS) 3300b28ba27SRafael J. Wysocki return configure_trip(entry, j, THERMAL_TRIP_CRITICAL, temp); 3313e8c4d31SAmit Kucheria } 3323e8c4d31SAmit Kucheria 3333e8c4d31SAmit Kucheria return -EINVAL; 3343e8c4d31SAmit Kucheria } 3353e8c4d31SAmit Kucheria EXPORT_SYMBOL_GPL(intel_soc_dts_iosf_add_read_only_critical_trip); 3363e8c4d31SAmit Kucheria 3373e8c4d31SAmit Kucheria void intel_soc_dts_iosf_interrupt_handler(struct intel_soc_dts_sensors *sensors) 3383e8c4d31SAmit Kucheria { 3393e8c4d31SAmit Kucheria u32 sticky_out; 3403e8c4d31SAmit Kucheria int status; 3413e8c4d31SAmit Kucheria u32 ptmc_out; 3423e8c4d31SAmit Kucheria unsigned long flags; 3433e8c4d31SAmit Kucheria 3443e8c4d31SAmit Kucheria spin_lock_irqsave(&sensors->intr_notify_lock, flags); 3453e8c4d31SAmit Kucheria 3463e8c4d31SAmit Kucheria status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, 3473e8c4d31SAmit Kucheria SOC_DTS_OFFSET_PTMC, &ptmc_out); 3483e8c4d31SAmit Kucheria ptmc_out |= SOC_DTS_PTMC_APIC_DEASSERT_BIT; 3493e8c4d31SAmit Kucheria status = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, 3503e8c4d31SAmit Kucheria SOC_DTS_OFFSET_PTMC, ptmc_out); 3513e8c4d31SAmit Kucheria 3523e8c4d31SAmit Kucheria status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, 3533e8c4d31SAmit Kucheria SOC_DTS_OFFSET_PTTSS, &sticky_out); 3543e8c4d31SAmit Kucheria pr_debug("status %d PTTSS %x\n", status, sticky_out); 3553e8c4d31SAmit Kucheria if (sticky_out & SOC_DTS_TRIP_MASK) { 3563e8c4d31SAmit Kucheria int i; 3573e8c4d31SAmit Kucheria /* reset sticky bit */ 3583e8c4d31SAmit Kucheria status = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, 3593e8c4d31SAmit Kucheria SOC_DTS_OFFSET_PTTSS, sticky_out); 3603e8c4d31SAmit Kucheria spin_unlock_irqrestore(&sensors->intr_notify_lock, flags); 3613e8c4d31SAmit Kucheria 3623e8c4d31SAmit Kucheria for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) { 3633e8c4d31SAmit Kucheria pr_debug("TZD update for zone %d\n", i); 3643e8c4d31SAmit Kucheria thermal_zone_device_update(sensors->soc_dts[i].tzone, 3653e8c4d31SAmit Kucheria THERMAL_EVENT_UNSPECIFIED); 3663e8c4d31SAmit Kucheria } 3673e8c4d31SAmit Kucheria } else 3683e8c4d31SAmit Kucheria spin_unlock_irqrestore(&sensors->intr_notify_lock, flags); 3693e8c4d31SAmit Kucheria } 3703e8c4d31SAmit Kucheria EXPORT_SYMBOL_GPL(intel_soc_dts_iosf_interrupt_handler); 3713e8c4d31SAmit Kucheria 3723e8c4d31SAmit Kucheria struct intel_soc_dts_sensors *intel_soc_dts_iosf_init( 373b429b6ffSRafael J. Wysocki enum intel_soc_dts_interrupt_type intr_type, int read_only_trip_count) 3743e8c4d31SAmit Kucheria { 3753e8c4d31SAmit Kucheria struct intel_soc_dts_sensors *sensors; 376e7fcfe67SYang Li int tj_max; 3773e8c4d31SAmit Kucheria int ret; 3783e8c4d31SAmit Kucheria int i; 3793e8c4d31SAmit Kucheria 3803e8c4d31SAmit Kucheria if (!iosf_mbi_available()) 3813e8c4d31SAmit Kucheria return ERR_PTR(-ENODEV); 3823e8c4d31SAmit Kucheria 383b429b6ffSRafael J. Wysocki if (read_only_trip_count > SOC_MAX_DTS_TRIPS) 3843e8c4d31SAmit Kucheria return ERR_PTR(-EINVAL); 3853e8c4d31SAmit Kucheria 386955fb871SZhang Rui tj_max = intel_tcc_get_tjmax(-1); 387955fb871SZhang Rui if (tj_max < 0) 388955fb871SZhang Rui return ERR_PTR(tj_max); 3893e8c4d31SAmit Kucheria 3903e8c4d31SAmit Kucheria sensors = kzalloc(sizeof(*sensors), GFP_KERNEL); 3913e8c4d31SAmit Kucheria if (!sensors) 3923e8c4d31SAmit Kucheria return ERR_PTR(-ENOMEM); 3933e8c4d31SAmit Kucheria 3943e8c4d31SAmit Kucheria spin_lock_init(&sensors->intr_notify_lock); 3953e8c4d31SAmit Kucheria mutex_init(&sensors->dts_update_lock); 3963e8c4d31SAmit Kucheria sensors->intr_type = intr_type; 3970bb619f9SHans de Goede sensors->tj_max = tj_max * 1000; 3984f164435SRafael J. Wysocki 3993e8c4d31SAmit Kucheria for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) { 4003e8c4d31SAmit Kucheria sensors->soc_dts[i].sensors = sensors; 4013e8c4d31SAmit Kucheria 4020b28ba27SRafael J. Wysocki ret = configure_trip(&sensors->soc_dts[i], 0, 4030b28ba27SRafael J. Wysocki THERMAL_TRIP_PASSIVE, 0); 4043e8c4d31SAmit Kucheria if (ret) 405*51f2aaf0SRafael J. Wysocki goto err_reset_trips; 4063e8c4d31SAmit Kucheria 4070b28ba27SRafael J. Wysocki ret = configure_trip(&sensors->soc_dts[i], 1, 4080b28ba27SRafael J. Wysocki THERMAL_TRIP_PASSIVE, 0); 4093e8c4d31SAmit Kucheria if (ret) 410*51f2aaf0SRafael J. Wysocki goto err_reset_trips; 411*51f2aaf0SRafael J. Wysocki } 412*51f2aaf0SRafael J. Wysocki 413*51f2aaf0SRafael J. Wysocki for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) { 414*51f2aaf0SRafael J. Wysocki ret = add_dts_thermal_zone(i, &sensors->soc_dts[i], 415*51f2aaf0SRafael J. Wysocki read_only_trip_count); 416*51f2aaf0SRafael J. Wysocki if (ret) 4173e8c4d31SAmit Kucheria goto err_remove_zone; 4183e8c4d31SAmit Kucheria } 4193e8c4d31SAmit Kucheria 4203e8c4d31SAmit Kucheria return sensors; 421*51f2aaf0SRafael J. Wysocki 4223e8c4d31SAmit Kucheria err_remove_zone: 4233e8c4d31SAmit Kucheria for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) 4243e8c4d31SAmit Kucheria remove_dts_thermal_zone(&sensors->soc_dts[i]); 4253e8c4d31SAmit Kucheria 426*51f2aaf0SRafael J. Wysocki err_reset_trips: 427*51f2aaf0SRafael J. Wysocki for (i = 0; i < SOC_MAX_DTS_SENSORS; i++) { 428*51f2aaf0SRafael J. Wysocki configure_trip(&sensors->soc_dts[i], 0, 0, 0); 429*51f2aaf0SRafael J. Wysocki configure_trip(&sensors->soc_dts[i], 1, 0, 0); 430*51f2aaf0SRafael J. Wysocki } 431*51f2aaf0SRafael J. Wysocki 4323e8c4d31SAmit Kucheria kfree(sensors); 4333e8c4d31SAmit Kucheria return ERR_PTR(ret); 4343e8c4d31SAmit Kucheria } 4353e8c4d31SAmit Kucheria EXPORT_SYMBOL_GPL(intel_soc_dts_iosf_init); 4363e8c4d31SAmit Kucheria 4373e8c4d31SAmit Kucheria void intel_soc_dts_iosf_exit(struct intel_soc_dts_sensors *sensors) 4383e8c4d31SAmit Kucheria { 4393e8c4d31SAmit Kucheria int i; 4403e8c4d31SAmit Kucheria 4413e8c4d31SAmit Kucheria for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) { 442*51f2aaf0SRafael J. Wysocki remove_dts_thermal_zone(&sensors->soc_dts[i]); 4430b28ba27SRafael J. Wysocki configure_trip(&sensors->soc_dts[i], 0, 0, 0); 4440b28ba27SRafael J. Wysocki configure_trip(&sensors->soc_dts[i], 1, 0, 0); 4453e8c4d31SAmit Kucheria } 4463e8c4d31SAmit Kucheria kfree(sensors); 4473e8c4d31SAmit Kucheria } 4483e8c4d31SAmit Kucheria EXPORT_SYMBOL_GPL(intel_soc_dts_iosf_exit); 4493e8c4d31SAmit Kucheria 450955fb871SZhang Rui MODULE_IMPORT_NS(INTEL_TCC); 4513e8c4d31SAmit Kucheria MODULE_LICENSE("GPL v2"); 452