brintos

brintos / linux-shallow public Read only

0
0
Text · 9.8 KiB · 43a2955 Raw
394 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * intel_soc_dts_iosf.c4 * Copyright (c) 2015, Intel Corporation.5 */6 7#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt8 9#include <linux/bitops.h>10#include <linux/intel_tcc.h>11#include <linux/module.h>12#include <linux/slab.h>13#include <linux/interrupt.h>14#include <asm/iosf_mbi.h>15#include "intel_soc_dts_iosf.h"16 17#define SOC_DTS_OFFSET_ENABLE		0xB018#define SOC_DTS_OFFSET_TEMP		0xB119 20#define SOC_DTS_OFFSET_PTPS		0xB221#define SOC_DTS_OFFSET_PTTS		0xB322#define SOC_DTS_OFFSET_PTTSS		0xB423#define SOC_DTS_OFFSET_PTMC		0x8024#define SOC_DTS_TE_AUX0			0xB525#define SOC_DTS_TE_AUX1			0xB626 27#define SOC_DTS_AUX0_ENABLE_BIT		BIT(0)28#define SOC_DTS_AUX1_ENABLE_BIT		BIT(1)29#define SOC_DTS_CPU_MODULE0_ENABLE_BIT	BIT(16)30#define SOC_DTS_CPU_MODULE1_ENABLE_BIT	BIT(17)31#define SOC_DTS_TE_SCI_ENABLE		BIT(9)32#define SOC_DTS_TE_SMI_ENABLE		BIT(10)33#define SOC_DTS_TE_MSI_ENABLE		BIT(11)34#define SOC_DTS_TE_APICA_ENABLE		BIT(14)35#define SOC_DTS_PTMC_APIC_DEASSERT_BIT	BIT(4)36 37/* DTS encoding for TJ MAX temperature */38#define SOC_DTS_TJMAX_ENCODING		0x7F39 40/* Mask for two trips in status bits */41#define SOC_DTS_TRIP_MASK		0x0342 43static int update_trip_temp(struct intel_soc_dts_sensors *sensors,44			    int thres_index, int temp)45{46	int status;47	u32 temp_out;48	u32 out;49	unsigned long update_ptps;50	u32 store_ptps;51	u32 store_ptmc;52	u32 store_te_out;53	u32 te_out;54	u32 int_enable_bit = SOC_DTS_TE_APICA_ENABLE;55 56	if (sensors->intr_type == INTEL_SOC_DTS_INTERRUPT_MSI)57		int_enable_bit |= SOC_DTS_TE_MSI_ENABLE;58 59	temp_out = (sensors->tj_max - temp) / 1000;60 61	status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,62			       SOC_DTS_OFFSET_PTPS, &store_ptps);63	if (status)64		return status;65 66	update_ptps = store_ptps;67	bitmap_set_value8(&update_ptps, temp_out & 0xFF, thres_index * 8);68	out = update_ptps;69 70	status = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,71				SOC_DTS_OFFSET_PTPS, out);72	if (status)73		return status;74 75	pr_debug("update_trip_temp PTPS = %x\n", out);76	status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,77			       SOC_DTS_OFFSET_PTMC, &out);78	if (status)79		goto err_restore_ptps;80 81	store_ptmc = out;82 83	status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,84			       SOC_DTS_TE_AUX0 + thres_index,85			       &te_out);86	if (status)87		goto err_restore_ptmc;88 89	store_te_out = te_out;90	/* Enable for CPU module 0 and module 1 */91	out |= (SOC_DTS_CPU_MODULE0_ENABLE_BIT |92					SOC_DTS_CPU_MODULE1_ENABLE_BIT);93	if (temp) {94		if (thres_index)95			out |= SOC_DTS_AUX1_ENABLE_BIT;96		else97			out |= SOC_DTS_AUX0_ENABLE_BIT;98		te_out |= int_enable_bit;99	} else {100		if (thres_index)101			out &= ~SOC_DTS_AUX1_ENABLE_BIT;102		else103			out &= ~SOC_DTS_AUX0_ENABLE_BIT;104		te_out &= ~int_enable_bit;105	}106	status = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,107				SOC_DTS_OFFSET_PTMC, out);108	if (status)109		goto err_restore_te_out;110 111	status = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,112				SOC_DTS_TE_AUX0 + thres_index,113				te_out);114	if (status)115		goto err_restore_te_out;116 117	return 0;118err_restore_te_out:119	iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,120		       SOC_DTS_OFFSET_PTMC, store_te_out);121err_restore_ptmc:122	iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,123		       SOC_DTS_OFFSET_PTMC, store_ptmc);124err_restore_ptps:125	iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,126		       SOC_DTS_OFFSET_PTPS, store_ptps);127	/* Nothing we can do if restore fails */128 129	return status;130}131 132static int sys_set_trip_temp(struct thermal_zone_device *tzd,133			     const struct thermal_trip *trip,134			     int temp)135{136	struct intel_soc_dts_sensor_entry *dts = thermal_zone_device_priv(tzd);137	struct intel_soc_dts_sensors *sensors = dts->sensors;138	unsigned int trip_index = THERMAL_TRIP_PRIV_TO_INT(trip->priv);139	int status;140 141	if (temp > sensors->tj_max)142		return -EINVAL;143 144	mutex_lock(&sensors->dts_update_lock);145	status = update_trip_temp(sensors, trip_index, temp);146	mutex_unlock(&sensors->dts_update_lock);147 148	return status;149}150 151static int sys_get_curr_temp(struct thermal_zone_device *tzd,152			     int *temp)153{154	int status;155	u32 out;156	struct intel_soc_dts_sensor_entry *dts = thermal_zone_device_priv(tzd);157	struct intel_soc_dts_sensors *sensors;158	unsigned long raw;159 160	sensors = dts->sensors;161	status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,162			       SOC_DTS_OFFSET_TEMP, &out);163	if (status)164		return status;165 166	raw = out;167	out = bitmap_get_value8(&raw, dts->id * 8) - SOC_DTS_TJMAX_ENCODING;168	*temp = sensors->tj_max - out * 1000;169 170	return 0;171}172 173static const struct thermal_zone_device_ops tzone_ops = {174	.get_temp = sys_get_curr_temp,175	.set_trip_temp = sys_set_trip_temp,176};177 178static int soc_dts_enable(int id)179{180	u32 out;181	int ret;182 183	ret = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,184			    SOC_DTS_OFFSET_ENABLE, &out);185	if (ret)186		return ret;187 188	if (!(out & BIT(id))) {189		out |= BIT(id);190		ret = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,191				     SOC_DTS_OFFSET_ENABLE, out);192		if (ret)193			return ret;194	}195 196	return ret;197}198 199static void remove_dts_thermal_zone(struct intel_soc_dts_sensor_entry *dts)200{201	iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,202		       SOC_DTS_OFFSET_ENABLE, dts->store_status);203	thermal_zone_device_unregister(dts->tzone);204}205 206static int add_dts_thermal_zone(int id, struct intel_soc_dts_sensor_entry *dts,207				struct thermal_trip *trips)208{209	char name[10];210	u32 store_ptps;211	int ret;212 213	/* Store status to restor on exit */214	ret = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,215			    SOC_DTS_OFFSET_ENABLE, &dts->store_status);216	if (ret)217		goto err_ret;218 219	dts->id = id;220 221	/* Check if the writable trip we provide is not used by BIOS */222	ret = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,223			    SOC_DTS_OFFSET_PTPS, &store_ptps);224	if (!ret) {225		int i;226 227		for (i = 0; i <= 1; i++) {228			if (store_ptps & (0xFFU << i * 8))229				trips[i].flags &= ~THERMAL_TRIP_FLAG_RW_TEMP;230		}231	}232	snprintf(name, sizeof(name), "soc_dts%d", id);233	dts->tzone = thermal_zone_device_register_with_trips(name, trips,234							     SOC_MAX_DTS_TRIPS,235							     dts, &tzone_ops,236							     NULL, 0, 0);237	if (IS_ERR(dts->tzone)) {238		ret = PTR_ERR(dts->tzone);239		goto err_ret;240	}241	ret = thermal_zone_device_enable(dts->tzone);242	if (ret)243		goto err_enable;244 245	ret = soc_dts_enable(id);246	if (ret)247		goto err_enable;248 249	return 0;250err_enable:251	thermal_zone_device_unregister(dts->tzone);252err_ret:253	return ret;254}255 256void intel_soc_dts_iosf_interrupt_handler(struct intel_soc_dts_sensors *sensors)257{258	u32 sticky_out;259	int status;260	u32 ptmc_out;261	unsigned long flags;262 263	spin_lock_irqsave(&sensors->intr_notify_lock, flags);264 265	status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,266			       SOC_DTS_OFFSET_PTMC, &ptmc_out);267	ptmc_out |= SOC_DTS_PTMC_APIC_DEASSERT_BIT;268	status = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,269				SOC_DTS_OFFSET_PTMC, ptmc_out);270 271	status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,272			       SOC_DTS_OFFSET_PTTSS, &sticky_out);273	pr_debug("status %d PTTSS %x\n", status, sticky_out);274	if (sticky_out & SOC_DTS_TRIP_MASK) {275		int i;276		/* reset sticky bit */277		status = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,278					SOC_DTS_OFFSET_PTTSS, sticky_out);279		spin_unlock_irqrestore(&sensors->intr_notify_lock, flags);280 281		for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) {282			pr_debug("TZD update for zone %d\n", i);283			thermal_zone_device_update(sensors->soc_dts[i].tzone,284						   THERMAL_EVENT_UNSPECIFIED);285		}286	} else287		spin_unlock_irqrestore(&sensors->intr_notify_lock, flags);288}289EXPORT_SYMBOL_GPL(intel_soc_dts_iosf_interrupt_handler);290 291static void dts_trips_reset(struct intel_soc_dts_sensors *sensors, int dts_index)292{293	update_trip_temp(sensors, 0, 0);294	update_trip_temp(sensors, 1, 0);295}296 297static void set_trip(struct thermal_trip *trip, enum thermal_trip_type type,298		     u8 flags, int temp, unsigned int index)299{300	trip->type = type;301	trip->flags = flags;302	trip->temperature = temp;303	trip->priv = THERMAL_INT_TO_TRIP_PRIV(index);304}305 306struct intel_soc_dts_sensors *307intel_soc_dts_iosf_init(enum intel_soc_dts_interrupt_type intr_type,308			bool critical_trip, int crit_offset)309{310	struct thermal_trip trips[SOC_MAX_DTS_SENSORS][SOC_MAX_DTS_TRIPS] = { 0 };311	struct intel_soc_dts_sensors *sensors;312	int tj_max;313	int ret;314	int i;315 316	if (!iosf_mbi_available())317		return ERR_PTR(-ENODEV);318 319	tj_max = intel_tcc_get_tjmax(-1);320	if (tj_max < 0)321		return ERR_PTR(tj_max);322 323	sensors = kzalloc(sizeof(*sensors), GFP_KERNEL);324	if (!sensors)325		return ERR_PTR(-ENOMEM);326 327	spin_lock_init(&sensors->intr_notify_lock);328	mutex_init(&sensors->dts_update_lock);329	sensors->intr_type = intr_type;330	sensors->tj_max = tj_max * 1000;331 332	for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) {333		int temp;334 335		sensors->soc_dts[i].sensors = sensors;336 337		set_trip(&trips[i][0], THERMAL_TRIP_PASSIVE,338			 THERMAL_TRIP_FLAG_RW_TEMP, 0, 0);339 340		ret = update_trip_temp(sensors, 0, 0);341		if (ret)342			goto err_reset_trips;343 344		if (critical_trip) {345			temp = sensors->tj_max - crit_offset;346			set_trip(&trips[i][1], THERMAL_TRIP_CRITICAL, 0, temp, 1);347		} else {348			set_trip(&trips[i][1], THERMAL_TRIP_PASSIVE,349				 THERMAL_TRIP_FLAG_RW_TEMP, 0, 1);350			temp = 0;351		}352 353		ret = update_trip_temp(sensors, 1, temp);354		if (ret)355			goto err_reset_trips;356	}357 358	for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) {359		ret = add_dts_thermal_zone(i, &sensors->soc_dts[i], trips[i]);360		if (ret)361			goto err_remove_zone;362	}363 364	return sensors;365 366err_remove_zone:367	for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i)368		remove_dts_thermal_zone(&sensors->soc_dts[i]);369 370err_reset_trips:371	for (i = 0; i < SOC_MAX_DTS_SENSORS; i++)372		dts_trips_reset(sensors, i);373 374	kfree(sensors);375	return ERR_PTR(ret);376}377EXPORT_SYMBOL_GPL(intel_soc_dts_iosf_init);378 379void intel_soc_dts_iosf_exit(struct intel_soc_dts_sensors *sensors)380{381	int i;382 383	for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) {384		remove_dts_thermal_zone(&sensors->soc_dts[i]);385		dts_trips_reset(sensors, i);386	}387	kfree(sensors);388}389EXPORT_SYMBOL_GPL(intel_soc_dts_iosf_exit);390 391MODULE_IMPORT_NS(INTEL_TCC);392MODULE_LICENSE("GPL v2");393MODULE_DESCRIPTION("SoC DTS driver using side band interface");394