18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * intel_soc_dts_iosf.c 48c2ecf20Sopenharmony_ci * Copyright (c) 2015, Intel Corporation. 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/bitops.h> 108c2ecf20Sopenharmony_ci#include <linux/module.h> 118c2ecf20Sopenharmony_ci#include <linux/slab.h> 128c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 138c2ecf20Sopenharmony_ci#include <asm/iosf_mbi.h> 148c2ecf20Sopenharmony_ci#include "intel_soc_dts_iosf.h" 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#define SOC_DTS_OFFSET_ENABLE 0xB0 178c2ecf20Sopenharmony_ci#define SOC_DTS_OFFSET_TEMP 0xB1 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#define SOC_DTS_OFFSET_PTPS 0xB2 208c2ecf20Sopenharmony_ci#define SOC_DTS_OFFSET_PTTS 0xB3 218c2ecf20Sopenharmony_ci#define SOC_DTS_OFFSET_PTTSS 0xB4 228c2ecf20Sopenharmony_ci#define SOC_DTS_OFFSET_PTMC 0x80 238c2ecf20Sopenharmony_ci#define SOC_DTS_TE_AUX0 0xB5 248c2ecf20Sopenharmony_ci#define SOC_DTS_TE_AUX1 0xB6 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#define SOC_DTS_AUX0_ENABLE_BIT BIT(0) 278c2ecf20Sopenharmony_ci#define SOC_DTS_AUX1_ENABLE_BIT BIT(1) 288c2ecf20Sopenharmony_ci#define SOC_DTS_CPU_MODULE0_ENABLE_BIT BIT(16) 298c2ecf20Sopenharmony_ci#define SOC_DTS_CPU_MODULE1_ENABLE_BIT BIT(17) 308c2ecf20Sopenharmony_ci#define SOC_DTS_TE_SCI_ENABLE BIT(9) 318c2ecf20Sopenharmony_ci#define SOC_DTS_TE_SMI_ENABLE BIT(10) 328c2ecf20Sopenharmony_ci#define SOC_DTS_TE_MSI_ENABLE BIT(11) 338c2ecf20Sopenharmony_ci#define SOC_DTS_TE_APICA_ENABLE BIT(14) 348c2ecf20Sopenharmony_ci#define SOC_DTS_PTMC_APIC_DEASSERT_BIT BIT(4) 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci/* DTS encoding for TJ MAX temperature */ 378c2ecf20Sopenharmony_ci#define SOC_DTS_TJMAX_ENCODING 0x7F 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci/* Only 2 out of 4 is allowed for OSPM */ 408c2ecf20Sopenharmony_ci#define SOC_MAX_DTS_TRIPS 2 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci/* Mask for two trips in status bits */ 438c2ecf20Sopenharmony_ci#define SOC_DTS_TRIP_MASK 0x03 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci/* DTS0 and DTS 1 */ 468c2ecf20Sopenharmony_ci#define SOC_MAX_DTS_SENSORS 2 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistatic int get_tj_max(u32 *tj_max) 498c2ecf20Sopenharmony_ci{ 508c2ecf20Sopenharmony_ci u32 eax, edx; 518c2ecf20Sopenharmony_ci u32 val; 528c2ecf20Sopenharmony_ci int err; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci err = rdmsr_safe(MSR_IA32_TEMPERATURE_TARGET, &eax, &edx); 558c2ecf20Sopenharmony_ci if (err) 568c2ecf20Sopenharmony_ci goto err_ret; 578c2ecf20Sopenharmony_ci else { 588c2ecf20Sopenharmony_ci val = (eax >> 16) & 0xff; 598c2ecf20Sopenharmony_ci if (val) 608c2ecf20Sopenharmony_ci *tj_max = val * 1000; 618c2ecf20Sopenharmony_ci else { 628c2ecf20Sopenharmony_ci err = -EINVAL; 638c2ecf20Sopenharmony_ci goto err_ret; 648c2ecf20Sopenharmony_ci } 658c2ecf20Sopenharmony_ci } 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci return 0; 688c2ecf20Sopenharmony_cierr_ret: 698c2ecf20Sopenharmony_ci *tj_max = 0; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci return err; 728c2ecf20Sopenharmony_ci} 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_cistatic int sys_get_trip_temp(struct thermal_zone_device *tzd, int trip, 758c2ecf20Sopenharmony_ci int *temp) 768c2ecf20Sopenharmony_ci{ 778c2ecf20Sopenharmony_ci int status; 788c2ecf20Sopenharmony_ci u32 out; 798c2ecf20Sopenharmony_ci struct intel_soc_dts_sensor_entry *dts; 808c2ecf20Sopenharmony_ci struct intel_soc_dts_sensors *sensors; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci dts = tzd->devdata; 838c2ecf20Sopenharmony_ci sensors = dts->sensors; 848c2ecf20Sopenharmony_ci mutex_lock(&sensors->dts_update_lock); 858c2ecf20Sopenharmony_ci status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, 868c2ecf20Sopenharmony_ci SOC_DTS_OFFSET_PTPS, &out); 878c2ecf20Sopenharmony_ci mutex_unlock(&sensors->dts_update_lock); 888c2ecf20Sopenharmony_ci if (status) 898c2ecf20Sopenharmony_ci return status; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci out = (out >> (trip * 8)) & SOC_DTS_TJMAX_ENCODING; 928c2ecf20Sopenharmony_ci if (!out) 938c2ecf20Sopenharmony_ci *temp = 0; 948c2ecf20Sopenharmony_ci else 958c2ecf20Sopenharmony_ci *temp = sensors->tj_max - out * 1000; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci return 0; 988c2ecf20Sopenharmony_ci} 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_cistatic int update_trip_temp(struct intel_soc_dts_sensor_entry *dts, 1018c2ecf20Sopenharmony_ci int thres_index, int temp, 1028c2ecf20Sopenharmony_ci enum thermal_trip_type trip_type) 1038c2ecf20Sopenharmony_ci{ 1048c2ecf20Sopenharmony_ci int status; 1058c2ecf20Sopenharmony_ci u32 temp_out; 1068c2ecf20Sopenharmony_ci u32 out; 1078c2ecf20Sopenharmony_ci unsigned long update_ptps; 1088c2ecf20Sopenharmony_ci u32 store_ptps; 1098c2ecf20Sopenharmony_ci u32 store_ptmc; 1108c2ecf20Sopenharmony_ci u32 store_te_out; 1118c2ecf20Sopenharmony_ci u32 te_out; 1128c2ecf20Sopenharmony_ci u32 int_enable_bit = SOC_DTS_TE_APICA_ENABLE; 1138c2ecf20Sopenharmony_ci struct intel_soc_dts_sensors *sensors = dts->sensors; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci if (sensors->intr_type == INTEL_SOC_DTS_INTERRUPT_MSI) 1168c2ecf20Sopenharmony_ci int_enable_bit |= SOC_DTS_TE_MSI_ENABLE; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci temp_out = (sensors->tj_max - temp) / 1000; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, 1218c2ecf20Sopenharmony_ci SOC_DTS_OFFSET_PTPS, &store_ptps); 1228c2ecf20Sopenharmony_ci if (status) 1238c2ecf20Sopenharmony_ci return status; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci update_ptps = store_ptps; 1268c2ecf20Sopenharmony_ci bitmap_set_value8(&update_ptps, temp_out & 0xFF, thres_index * 8); 1278c2ecf20Sopenharmony_ci out = update_ptps; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci status = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, 1308c2ecf20Sopenharmony_ci SOC_DTS_OFFSET_PTPS, out); 1318c2ecf20Sopenharmony_ci if (status) 1328c2ecf20Sopenharmony_ci return status; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci pr_debug("update_trip_temp PTPS = %x\n", out); 1358c2ecf20Sopenharmony_ci status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, 1368c2ecf20Sopenharmony_ci SOC_DTS_OFFSET_PTMC, &out); 1378c2ecf20Sopenharmony_ci if (status) 1388c2ecf20Sopenharmony_ci goto err_restore_ptps; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci store_ptmc = out; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, 1438c2ecf20Sopenharmony_ci SOC_DTS_TE_AUX0 + thres_index, 1448c2ecf20Sopenharmony_ci &te_out); 1458c2ecf20Sopenharmony_ci if (status) 1468c2ecf20Sopenharmony_ci goto err_restore_ptmc; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci store_te_out = te_out; 1498c2ecf20Sopenharmony_ci /* Enable for CPU module 0 and module 1 */ 1508c2ecf20Sopenharmony_ci out |= (SOC_DTS_CPU_MODULE0_ENABLE_BIT | 1518c2ecf20Sopenharmony_ci SOC_DTS_CPU_MODULE1_ENABLE_BIT); 1528c2ecf20Sopenharmony_ci if (temp) { 1538c2ecf20Sopenharmony_ci if (thres_index) 1548c2ecf20Sopenharmony_ci out |= SOC_DTS_AUX1_ENABLE_BIT; 1558c2ecf20Sopenharmony_ci else 1568c2ecf20Sopenharmony_ci out |= SOC_DTS_AUX0_ENABLE_BIT; 1578c2ecf20Sopenharmony_ci te_out |= int_enable_bit; 1588c2ecf20Sopenharmony_ci } else { 1598c2ecf20Sopenharmony_ci if (thres_index) 1608c2ecf20Sopenharmony_ci out &= ~SOC_DTS_AUX1_ENABLE_BIT; 1618c2ecf20Sopenharmony_ci else 1628c2ecf20Sopenharmony_ci out &= ~SOC_DTS_AUX0_ENABLE_BIT; 1638c2ecf20Sopenharmony_ci te_out &= ~int_enable_bit; 1648c2ecf20Sopenharmony_ci } 1658c2ecf20Sopenharmony_ci status = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, 1668c2ecf20Sopenharmony_ci SOC_DTS_OFFSET_PTMC, out); 1678c2ecf20Sopenharmony_ci if (status) 1688c2ecf20Sopenharmony_ci goto err_restore_te_out; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci status = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, 1718c2ecf20Sopenharmony_ci SOC_DTS_TE_AUX0 + thres_index, 1728c2ecf20Sopenharmony_ci te_out); 1738c2ecf20Sopenharmony_ci if (status) 1748c2ecf20Sopenharmony_ci goto err_restore_te_out; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci dts->trip_types[thres_index] = trip_type; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci return 0; 1798c2ecf20Sopenharmony_cierr_restore_te_out: 1808c2ecf20Sopenharmony_ci iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, 1818c2ecf20Sopenharmony_ci SOC_DTS_OFFSET_PTMC, store_te_out); 1828c2ecf20Sopenharmony_cierr_restore_ptmc: 1838c2ecf20Sopenharmony_ci iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, 1848c2ecf20Sopenharmony_ci SOC_DTS_OFFSET_PTMC, store_ptmc); 1858c2ecf20Sopenharmony_cierr_restore_ptps: 1868c2ecf20Sopenharmony_ci iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, 1878c2ecf20Sopenharmony_ci SOC_DTS_OFFSET_PTPS, store_ptps); 1888c2ecf20Sopenharmony_ci /* Nothing we can do if restore fails */ 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci return status; 1918c2ecf20Sopenharmony_ci} 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_cistatic int sys_set_trip_temp(struct thermal_zone_device *tzd, int trip, 1948c2ecf20Sopenharmony_ci int temp) 1958c2ecf20Sopenharmony_ci{ 1968c2ecf20Sopenharmony_ci struct intel_soc_dts_sensor_entry *dts = tzd->devdata; 1978c2ecf20Sopenharmony_ci struct intel_soc_dts_sensors *sensors = dts->sensors; 1988c2ecf20Sopenharmony_ci int status; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci if (temp > sensors->tj_max) 2018c2ecf20Sopenharmony_ci return -EINVAL; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci mutex_lock(&sensors->dts_update_lock); 2048c2ecf20Sopenharmony_ci status = update_trip_temp(tzd->devdata, trip, temp, 2058c2ecf20Sopenharmony_ci dts->trip_types[trip]); 2068c2ecf20Sopenharmony_ci mutex_unlock(&sensors->dts_update_lock); 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci return status; 2098c2ecf20Sopenharmony_ci} 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_cistatic int sys_get_trip_type(struct thermal_zone_device *tzd, 2128c2ecf20Sopenharmony_ci int trip, enum thermal_trip_type *type) 2138c2ecf20Sopenharmony_ci{ 2148c2ecf20Sopenharmony_ci struct intel_soc_dts_sensor_entry *dts; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci dts = tzd->devdata; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci *type = dts->trip_types[trip]; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci return 0; 2218c2ecf20Sopenharmony_ci} 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_cistatic int sys_get_curr_temp(struct thermal_zone_device *tzd, 2248c2ecf20Sopenharmony_ci int *temp) 2258c2ecf20Sopenharmony_ci{ 2268c2ecf20Sopenharmony_ci int status; 2278c2ecf20Sopenharmony_ci u32 out; 2288c2ecf20Sopenharmony_ci struct intel_soc_dts_sensor_entry *dts; 2298c2ecf20Sopenharmony_ci struct intel_soc_dts_sensors *sensors; 2308c2ecf20Sopenharmony_ci unsigned long raw; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci dts = tzd->devdata; 2338c2ecf20Sopenharmony_ci sensors = dts->sensors; 2348c2ecf20Sopenharmony_ci status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, 2358c2ecf20Sopenharmony_ci SOC_DTS_OFFSET_TEMP, &out); 2368c2ecf20Sopenharmony_ci if (status) 2378c2ecf20Sopenharmony_ci return status; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci raw = out; 2408c2ecf20Sopenharmony_ci out = bitmap_get_value8(&raw, dts->id * 8) - SOC_DTS_TJMAX_ENCODING; 2418c2ecf20Sopenharmony_ci *temp = sensors->tj_max - out * 1000; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci return 0; 2448c2ecf20Sopenharmony_ci} 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_cistatic struct thermal_zone_device_ops tzone_ops = { 2478c2ecf20Sopenharmony_ci .get_temp = sys_get_curr_temp, 2488c2ecf20Sopenharmony_ci .get_trip_temp = sys_get_trip_temp, 2498c2ecf20Sopenharmony_ci .get_trip_type = sys_get_trip_type, 2508c2ecf20Sopenharmony_ci .set_trip_temp = sys_set_trip_temp, 2518c2ecf20Sopenharmony_ci}; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_cistatic int soc_dts_enable(int id) 2548c2ecf20Sopenharmony_ci{ 2558c2ecf20Sopenharmony_ci u32 out; 2568c2ecf20Sopenharmony_ci int ret; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci ret = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, 2598c2ecf20Sopenharmony_ci SOC_DTS_OFFSET_ENABLE, &out); 2608c2ecf20Sopenharmony_ci if (ret) 2618c2ecf20Sopenharmony_ci return ret; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci if (!(out & BIT(id))) { 2648c2ecf20Sopenharmony_ci out |= BIT(id); 2658c2ecf20Sopenharmony_ci ret = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, 2668c2ecf20Sopenharmony_ci SOC_DTS_OFFSET_ENABLE, out); 2678c2ecf20Sopenharmony_ci if (ret) 2688c2ecf20Sopenharmony_ci return ret; 2698c2ecf20Sopenharmony_ci } 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci return ret; 2728c2ecf20Sopenharmony_ci} 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_cistatic void remove_dts_thermal_zone(struct intel_soc_dts_sensor_entry *dts) 2758c2ecf20Sopenharmony_ci{ 2768c2ecf20Sopenharmony_ci if (dts) { 2778c2ecf20Sopenharmony_ci iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, 2788c2ecf20Sopenharmony_ci SOC_DTS_OFFSET_ENABLE, dts->store_status); 2798c2ecf20Sopenharmony_ci thermal_zone_device_unregister(dts->tzone); 2808c2ecf20Sopenharmony_ci } 2818c2ecf20Sopenharmony_ci} 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_cistatic int add_dts_thermal_zone(int id, struct intel_soc_dts_sensor_entry *dts, 2848c2ecf20Sopenharmony_ci bool notification_support, int trip_cnt, 2858c2ecf20Sopenharmony_ci int read_only_trip_cnt) 2868c2ecf20Sopenharmony_ci{ 2878c2ecf20Sopenharmony_ci char name[10]; 2888c2ecf20Sopenharmony_ci unsigned long trip; 2898c2ecf20Sopenharmony_ci int trip_count = 0; 2908c2ecf20Sopenharmony_ci int trip_mask = 0; 2918c2ecf20Sopenharmony_ci int writable_trip_cnt = 0; 2928c2ecf20Sopenharmony_ci unsigned long ptps; 2938c2ecf20Sopenharmony_ci u32 store_ptps; 2948c2ecf20Sopenharmony_ci unsigned long i; 2958c2ecf20Sopenharmony_ci int ret; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci /* Store status to restor on exit */ 2988c2ecf20Sopenharmony_ci ret = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, 2998c2ecf20Sopenharmony_ci SOC_DTS_OFFSET_ENABLE, &dts->store_status); 3008c2ecf20Sopenharmony_ci if (ret) 3018c2ecf20Sopenharmony_ci goto err_ret; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci dts->id = id; 3048c2ecf20Sopenharmony_ci if (notification_support) { 3058c2ecf20Sopenharmony_ci trip_count = min(SOC_MAX_DTS_TRIPS, trip_cnt); 3068c2ecf20Sopenharmony_ci writable_trip_cnt = trip_count - read_only_trip_cnt; 3078c2ecf20Sopenharmony_ci trip_mask = GENMASK(writable_trip_cnt - 1, 0); 3088c2ecf20Sopenharmony_ci } 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci /* Check if the writable trip we provide is not used by BIOS */ 3118c2ecf20Sopenharmony_ci ret = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, 3128c2ecf20Sopenharmony_ci SOC_DTS_OFFSET_PTPS, &store_ptps); 3138c2ecf20Sopenharmony_ci if (ret) 3148c2ecf20Sopenharmony_ci trip_mask = 0; 3158c2ecf20Sopenharmony_ci else { 3168c2ecf20Sopenharmony_ci ptps = store_ptps; 3178c2ecf20Sopenharmony_ci for_each_set_clump8(i, trip, &ptps, writable_trip_cnt * 8) 3188c2ecf20Sopenharmony_ci trip_mask &= ~BIT(i / 8); 3198c2ecf20Sopenharmony_ci } 3208c2ecf20Sopenharmony_ci dts->trip_mask = trip_mask; 3218c2ecf20Sopenharmony_ci dts->trip_count = trip_count; 3228c2ecf20Sopenharmony_ci snprintf(name, sizeof(name), "soc_dts%d", id); 3238c2ecf20Sopenharmony_ci dts->tzone = thermal_zone_device_register(name, 3248c2ecf20Sopenharmony_ci trip_count, 3258c2ecf20Sopenharmony_ci trip_mask, 3268c2ecf20Sopenharmony_ci dts, &tzone_ops, 3278c2ecf20Sopenharmony_ci NULL, 0, 0); 3288c2ecf20Sopenharmony_ci if (IS_ERR(dts->tzone)) { 3298c2ecf20Sopenharmony_ci ret = PTR_ERR(dts->tzone); 3308c2ecf20Sopenharmony_ci goto err_ret; 3318c2ecf20Sopenharmony_ci } 3328c2ecf20Sopenharmony_ci ret = thermal_zone_device_enable(dts->tzone); 3338c2ecf20Sopenharmony_ci if (ret) 3348c2ecf20Sopenharmony_ci goto err_enable; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci ret = soc_dts_enable(id); 3378c2ecf20Sopenharmony_ci if (ret) 3388c2ecf20Sopenharmony_ci goto err_enable; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci return 0; 3418c2ecf20Sopenharmony_cierr_enable: 3428c2ecf20Sopenharmony_ci thermal_zone_device_unregister(dts->tzone); 3438c2ecf20Sopenharmony_cierr_ret: 3448c2ecf20Sopenharmony_ci return ret; 3458c2ecf20Sopenharmony_ci} 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ciint intel_soc_dts_iosf_add_read_only_critical_trip( 3488c2ecf20Sopenharmony_ci struct intel_soc_dts_sensors *sensors, int critical_offset) 3498c2ecf20Sopenharmony_ci{ 3508c2ecf20Sopenharmony_ci int i, j; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) { 3538c2ecf20Sopenharmony_ci for (j = 0; j < sensors->soc_dts[i].trip_count; ++j) { 3548c2ecf20Sopenharmony_ci if (!(sensors->soc_dts[i].trip_mask & BIT(j))) { 3558c2ecf20Sopenharmony_ci return update_trip_temp(&sensors->soc_dts[i], j, 3568c2ecf20Sopenharmony_ci sensors->tj_max - critical_offset, 3578c2ecf20Sopenharmony_ci THERMAL_TRIP_CRITICAL); 3588c2ecf20Sopenharmony_ci } 3598c2ecf20Sopenharmony_ci } 3608c2ecf20Sopenharmony_ci } 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci return -EINVAL; 3638c2ecf20Sopenharmony_ci} 3648c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(intel_soc_dts_iosf_add_read_only_critical_trip); 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_civoid intel_soc_dts_iosf_interrupt_handler(struct intel_soc_dts_sensors *sensors) 3678c2ecf20Sopenharmony_ci{ 3688c2ecf20Sopenharmony_ci u32 sticky_out; 3698c2ecf20Sopenharmony_ci int status; 3708c2ecf20Sopenharmony_ci u32 ptmc_out; 3718c2ecf20Sopenharmony_ci unsigned long flags; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci spin_lock_irqsave(&sensors->intr_notify_lock, flags); 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, 3768c2ecf20Sopenharmony_ci SOC_DTS_OFFSET_PTMC, &ptmc_out); 3778c2ecf20Sopenharmony_ci ptmc_out |= SOC_DTS_PTMC_APIC_DEASSERT_BIT; 3788c2ecf20Sopenharmony_ci status = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, 3798c2ecf20Sopenharmony_ci SOC_DTS_OFFSET_PTMC, ptmc_out); 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, 3828c2ecf20Sopenharmony_ci SOC_DTS_OFFSET_PTTSS, &sticky_out); 3838c2ecf20Sopenharmony_ci pr_debug("status %d PTTSS %x\n", status, sticky_out); 3848c2ecf20Sopenharmony_ci if (sticky_out & SOC_DTS_TRIP_MASK) { 3858c2ecf20Sopenharmony_ci int i; 3868c2ecf20Sopenharmony_ci /* reset sticky bit */ 3878c2ecf20Sopenharmony_ci status = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, 3888c2ecf20Sopenharmony_ci SOC_DTS_OFFSET_PTTSS, sticky_out); 3898c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&sensors->intr_notify_lock, flags); 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) { 3928c2ecf20Sopenharmony_ci pr_debug("TZD update for zone %d\n", i); 3938c2ecf20Sopenharmony_ci thermal_zone_device_update(sensors->soc_dts[i].tzone, 3948c2ecf20Sopenharmony_ci THERMAL_EVENT_UNSPECIFIED); 3958c2ecf20Sopenharmony_ci } 3968c2ecf20Sopenharmony_ci } else 3978c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&sensors->intr_notify_lock, flags); 3988c2ecf20Sopenharmony_ci} 3998c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(intel_soc_dts_iosf_interrupt_handler); 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_cistruct intel_soc_dts_sensors *intel_soc_dts_iosf_init( 4028c2ecf20Sopenharmony_ci enum intel_soc_dts_interrupt_type intr_type, int trip_count, 4038c2ecf20Sopenharmony_ci int read_only_trip_count) 4048c2ecf20Sopenharmony_ci{ 4058c2ecf20Sopenharmony_ci struct intel_soc_dts_sensors *sensors; 4068c2ecf20Sopenharmony_ci bool notification; 4078c2ecf20Sopenharmony_ci int tj_max; 4088c2ecf20Sopenharmony_ci int ret; 4098c2ecf20Sopenharmony_ci int i; 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci if (!iosf_mbi_available()) 4128c2ecf20Sopenharmony_ci return ERR_PTR(-ENODEV); 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci if (!trip_count || read_only_trip_count > trip_count) 4158c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci if (get_tj_max(&tj_max)) 4188c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci sensors = kzalloc(sizeof(*sensors), GFP_KERNEL); 4218c2ecf20Sopenharmony_ci if (!sensors) 4228c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci spin_lock_init(&sensors->intr_notify_lock); 4258c2ecf20Sopenharmony_ci mutex_init(&sensors->dts_update_lock); 4268c2ecf20Sopenharmony_ci sensors->intr_type = intr_type; 4278c2ecf20Sopenharmony_ci sensors->tj_max = tj_max; 4288c2ecf20Sopenharmony_ci if (intr_type == INTEL_SOC_DTS_INTERRUPT_NONE) 4298c2ecf20Sopenharmony_ci notification = false; 4308c2ecf20Sopenharmony_ci else 4318c2ecf20Sopenharmony_ci notification = true; 4328c2ecf20Sopenharmony_ci for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) { 4338c2ecf20Sopenharmony_ci sensors->soc_dts[i].sensors = sensors; 4348c2ecf20Sopenharmony_ci ret = add_dts_thermal_zone(i, &sensors->soc_dts[i], 4358c2ecf20Sopenharmony_ci notification, trip_count, 4368c2ecf20Sopenharmony_ci read_only_trip_count); 4378c2ecf20Sopenharmony_ci if (ret) 4388c2ecf20Sopenharmony_ci goto err_free; 4398c2ecf20Sopenharmony_ci } 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) { 4428c2ecf20Sopenharmony_ci ret = update_trip_temp(&sensors->soc_dts[i], 0, 0, 4438c2ecf20Sopenharmony_ci THERMAL_TRIP_PASSIVE); 4448c2ecf20Sopenharmony_ci if (ret) 4458c2ecf20Sopenharmony_ci goto err_remove_zone; 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci ret = update_trip_temp(&sensors->soc_dts[i], 1, 0, 4488c2ecf20Sopenharmony_ci THERMAL_TRIP_PASSIVE); 4498c2ecf20Sopenharmony_ci if (ret) 4508c2ecf20Sopenharmony_ci goto err_remove_zone; 4518c2ecf20Sopenharmony_ci } 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci return sensors; 4548c2ecf20Sopenharmony_cierr_remove_zone: 4558c2ecf20Sopenharmony_ci for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) 4568c2ecf20Sopenharmony_ci remove_dts_thermal_zone(&sensors->soc_dts[i]); 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_cierr_free: 4598c2ecf20Sopenharmony_ci kfree(sensors); 4608c2ecf20Sopenharmony_ci return ERR_PTR(ret); 4618c2ecf20Sopenharmony_ci} 4628c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(intel_soc_dts_iosf_init); 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_civoid intel_soc_dts_iosf_exit(struct intel_soc_dts_sensors *sensors) 4658c2ecf20Sopenharmony_ci{ 4668c2ecf20Sopenharmony_ci int i; 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) { 4698c2ecf20Sopenharmony_ci update_trip_temp(&sensors->soc_dts[i], 0, 0, 0); 4708c2ecf20Sopenharmony_ci update_trip_temp(&sensors->soc_dts[i], 1, 0, 0); 4718c2ecf20Sopenharmony_ci remove_dts_thermal_zone(&sensors->soc_dts[i]); 4728c2ecf20Sopenharmony_ci } 4738c2ecf20Sopenharmony_ci kfree(sensors); 4748c2ecf20Sopenharmony_ci} 4758c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(intel_soc_dts_iosf_exit); 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 478