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