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