Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * intel_soc_dts_iosf.c
  4 * Copyright (c) 2015, Intel Corporation.
  5 */
  6
  7#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  8
  9#include <linux/module.h>
 10#include <linux/slab.h>
 11#include <linux/interrupt.h>
 12#include <asm/iosf_mbi.h>
 13#include "intel_soc_dts_iosf.h"
 14
 15#define SOC_DTS_OFFSET_ENABLE		0xB0
 16#define SOC_DTS_OFFSET_TEMP		0xB1
 17
 18#define SOC_DTS_OFFSET_PTPS		0xB2
 19#define SOC_DTS_OFFSET_PTTS		0xB3
 20#define SOC_DTS_OFFSET_PTTSS		0xB4
 21#define SOC_DTS_OFFSET_PTMC		0x80
 22#define SOC_DTS_TE_AUX0			0xB5
 23#define SOC_DTS_TE_AUX1			0xB6
 24
 25#define SOC_DTS_AUX0_ENABLE_BIT		BIT(0)
 26#define SOC_DTS_AUX1_ENABLE_BIT		BIT(1)
 27#define SOC_DTS_CPU_MODULE0_ENABLE_BIT	BIT(16)
 28#define SOC_DTS_CPU_MODULE1_ENABLE_BIT	BIT(17)
 29#define SOC_DTS_TE_SCI_ENABLE		BIT(9)
 30#define SOC_DTS_TE_SMI_ENABLE		BIT(10)
 31#define SOC_DTS_TE_MSI_ENABLE		BIT(11)
 32#define SOC_DTS_TE_APICA_ENABLE		BIT(14)
 33#define SOC_DTS_PTMC_APIC_DEASSERT_BIT	BIT(4)
 34
 35/* DTS encoding for TJ MAX temperature */
 36#define SOC_DTS_TJMAX_ENCODING		0x7F
 37
 38/* Only 2 out of 4 is allowed for OSPM */
 39#define SOC_MAX_DTS_TRIPS		2
 40
 41/* Mask for two trips in status bits */
 42#define SOC_DTS_TRIP_MASK		0x03
 43
 44/* DTS0 and DTS 1 */
 45#define SOC_MAX_DTS_SENSORS		2
 46
 47static int get_tj_max(u32 *tj_max)
 48{
 49	u32 eax, edx;
 50	u32 val;
 51	int err;
 52
 53	err = rdmsr_safe(MSR_IA32_TEMPERATURE_TARGET, &eax, &edx);
 54	if (err)
 55		goto err_ret;
 56	else {
 57		val = (eax >> 16) & 0xff;
 58		if (val)
 59			*tj_max = val * 1000;
 60		else {
 61			err = -EINVAL;
 62			goto err_ret;
 63		}
 64	}
 65
 66	return 0;
 67err_ret:
 68	*tj_max = 0;
 69
 70	return err;
 71}
 72
 73static int sys_get_trip_temp(struct thermal_zone_device *tzd, int trip,
 74			     int *temp)
 75{
 76	int status;
 77	u32 out;
 78	struct intel_soc_dts_sensor_entry *dts;
 79	struct intel_soc_dts_sensors *sensors;
 80
 81	dts = tzd->devdata;
 82	sensors = dts->sensors;
 83	mutex_lock(&sensors->dts_update_lock);
 84	status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,
 85			       SOC_DTS_OFFSET_PTPS, &out);
 86	mutex_unlock(&sensors->dts_update_lock);
 87	if (status)
 88		return status;
 89
 90	out = (out >> (trip * 8)) & SOC_DTS_TJMAX_ENCODING;
 91	if (!out)
 92		*temp = 0;
 93	else
 94		*temp = sensors->tj_max - out * 1000;
 95
 96	return 0;
 97}
 98
 99static int update_trip_temp(struct intel_soc_dts_sensor_entry *dts,
100			    int thres_index, int temp,
101			    enum thermal_trip_type trip_type)
102{
103	int status;
104	u32 temp_out;
105	u32 out;
106	u32 store_ptps;
107	u32 store_ptmc;
108	u32 store_te_out;
109	u32 te_out;
110	u32 int_enable_bit = SOC_DTS_TE_APICA_ENABLE;
111	struct intel_soc_dts_sensors *sensors = dts->sensors;
112
113	if (sensors->intr_type == INTEL_SOC_DTS_INTERRUPT_MSI)
114		int_enable_bit |= SOC_DTS_TE_MSI_ENABLE;
115
116	temp_out = (sensors->tj_max - temp) / 1000;
117
118	status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,
119			       SOC_DTS_OFFSET_PTPS, &store_ptps);
120	if (status)
121		return status;
122
123	out = (store_ptps & ~(0xFF << (thres_index * 8)));
124	out |= (temp_out & 0xFF) << (thres_index * 8);
125	status = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,
126				SOC_DTS_OFFSET_PTPS, out);
127	if (status)
128		return status;
129
130	pr_debug("update_trip_temp PTPS = %x\n", out);
131	status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,
132			       SOC_DTS_OFFSET_PTMC, &out);
133	if (status)
134		goto err_restore_ptps;
135
136	store_ptmc = out;
137
138	status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,
139			       SOC_DTS_TE_AUX0 + thres_index,
140			       &te_out);
141	if (status)
142		goto err_restore_ptmc;
143
144	store_te_out = te_out;
145	/* Enable for CPU module 0 and module 1 */
146	out |= (SOC_DTS_CPU_MODULE0_ENABLE_BIT |
147					SOC_DTS_CPU_MODULE1_ENABLE_BIT);
148	if (temp) {
149		if (thres_index)
150			out |= SOC_DTS_AUX1_ENABLE_BIT;
151		else
152			out |= SOC_DTS_AUX0_ENABLE_BIT;
153		te_out |= int_enable_bit;
154	} else {
155		if (thres_index)
156			out &= ~SOC_DTS_AUX1_ENABLE_BIT;
157		else
158			out &= ~SOC_DTS_AUX0_ENABLE_BIT;
159		te_out &= ~int_enable_bit;
160	}
161	status = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,
162				SOC_DTS_OFFSET_PTMC, out);
163	if (status)
164		goto err_restore_te_out;
165
166	status = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,
167				SOC_DTS_TE_AUX0 + thres_index,
168				te_out);
169	if (status)
170		goto err_restore_te_out;
171
172	dts->trip_types[thres_index] = trip_type;
173
174	return 0;
175err_restore_te_out:
176	iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,
177		       SOC_DTS_OFFSET_PTMC, store_te_out);
178err_restore_ptmc:
179	iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,
180		       SOC_DTS_OFFSET_PTMC, store_ptmc);
181err_restore_ptps:
182	iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,
183		       SOC_DTS_OFFSET_PTPS, store_ptps);
184	/* Nothing we can do if restore fails */
185
186	return status;
187}
188
189static int sys_set_trip_temp(struct thermal_zone_device *tzd, int trip,
190			     int temp)
191{
192	struct intel_soc_dts_sensor_entry *dts = tzd->devdata;
193	struct intel_soc_dts_sensors *sensors = dts->sensors;
194	int status;
195
196	if (temp > sensors->tj_max)
197		return -EINVAL;
198
199	mutex_lock(&sensors->dts_update_lock);
200	status = update_trip_temp(tzd->devdata, trip, temp,
201				  dts->trip_types[trip]);
202	mutex_unlock(&sensors->dts_update_lock);
203
204	return status;
205}
206
207static int sys_get_trip_type(struct thermal_zone_device *tzd,
208			     int trip, enum thermal_trip_type *type)
209{
210	struct intel_soc_dts_sensor_entry *dts;
211
212	dts = tzd->devdata;
213
214	*type = dts->trip_types[trip];
215
216	return 0;
217}
218
219static int sys_get_curr_temp(struct thermal_zone_device *tzd,
220			     int *temp)
221{
222	int status;
223	u32 out;
224	struct intel_soc_dts_sensor_entry *dts;
225	struct intel_soc_dts_sensors *sensors;
226
227	dts = tzd->devdata;
228	sensors = dts->sensors;
229	status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,
230			       SOC_DTS_OFFSET_TEMP, &out);
231	if (status)
232		return status;
233
234	out = (out & dts->temp_mask) >> dts->temp_shift;
235	out -= SOC_DTS_TJMAX_ENCODING;
236	*temp = sensors->tj_max - out * 1000;
237
238	return 0;
239}
240
241static struct thermal_zone_device_ops tzone_ops = {
242	.get_temp = sys_get_curr_temp,
243	.get_trip_temp = sys_get_trip_temp,
244	.get_trip_type = sys_get_trip_type,
245	.set_trip_temp = sys_set_trip_temp,
246};
247
248static int soc_dts_enable(int id)
249{
250	u32 out;
251	int ret;
252
253	ret = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,
254			    SOC_DTS_OFFSET_ENABLE, &out);
255	if (ret)
256		return ret;
257
258	if (!(out & BIT(id))) {
259		out |= BIT(id);
260		ret = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,
261				     SOC_DTS_OFFSET_ENABLE, out);
262		if (ret)
263			return ret;
264	}
265
266	return ret;
267}
268
269static void remove_dts_thermal_zone(struct intel_soc_dts_sensor_entry *dts)
270{
271	if (dts) {
272		iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,
273			       SOC_DTS_OFFSET_ENABLE, dts->store_status);
274		thermal_zone_device_unregister(dts->tzone);
275	}
276}
277
278static int add_dts_thermal_zone(int id, struct intel_soc_dts_sensor_entry *dts,
279				bool notification_support, int trip_cnt,
280				int read_only_trip_cnt)
281{
282	char name[10];
283	int trip_count = 0;
284	int trip_mask = 0;
285	u32 store_ptps;
286	int ret;
287	int i;
288
289	/* Store status to restor on exit */
290	ret = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,
291			    SOC_DTS_OFFSET_ENABLE, &dts->store_status);
292	if (ret)
293		goto err_ret;
294
295	dts->id = id;
296	dts->temp_mask = 0x00FF << (id * 8);
297	dts->temp_shift = id * 8;
298	if (notification_support) {
299		trip_count = min(SOC_MAX_DTS_TRIPS, trip_cnt);
300		trip_mask = BIT(trip_count - read_only_trip_cnt) - 1;
301	}
302
303	/* Check if the writable trip we provide is not used by BIOS */
304	ret = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,
305			    SOC_DTS_OFFSET_PTPS, &store_ptps);
306	if (ret)
307		trip_mask = 0;
308	else {
309		for (i = 0; i < trip_count; ++i) {
310			if (trip_mask & BIT(i))
311				if (store_ptps & (0xff << (i * 8)))
312					trip_mask &= ~BIT(i);
313		}
314	}
315	dts->trip_mask = trip_mask;
316	dts->trip_count = trip_count;
317	snprintf(name, sizeof(name), "soc_dts%d", id);
318	dts->tzone = thermal_zone_device_register(name,
319						  trip_count,
320						  trip_mask,
321						  dts, &tzone_ops,
322						  NULL, 0, 0);
323	if (IS_ERR(dts->tzone)) {
324		ret = PTR_ERR(dts->tzone);
325		goto err_ret;
326	}
327
328	ret = soc_dts_enable(id);
329	if (ret)
330		goto err_enable;
331
332	return 0;
333err_enable:
334	thermal_zone_device_unregister(dts->tzone);
335err_ret:
336	return ret;
337}
338
339int intel_soc_dts_iosf_add_read_only_critical_trip(
340	struct intel_soc_dts_sensors *sensors, int critical_offset)
341{
342	int i, j;
343
344	for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) {
345		for (j = 0; j < sensors->soc_dts[i].trip_count; ++j) {
346			if (!(sensors->soc_dts[i].trip_mask & BIT(j))) {
347				return update_trip_temp(&sensors->soc_dts[i], j,
348					sensors->tj_max - critical_offset,
349					THERMAL_TRIP_CRITICAL);
350			}
351		}
352	}
353
354	return -EINVAL;
355}
356EXPORT_SYMBOL_GPL(intel_soc_dts_iosf_add_read_only_critical_trip);
357
358void intel_soc_dts_iosf_interrupt_handler(struct intel_soc_dts_sensors *sensors)
359{
360	u32 sticky_out;
361	int status;
362	u32 ptmc_out;
363	unsigned long flags;
364
365	spin_lock_irqsave(&sensors->intr_notify_lock, flags);
366
367	status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,
368			       SOC_DTS_OFFSET_PTMC, &ptmc_out);
369	ptmc_out |= SOC_DTS_PTMC_APIC_DEASSERT_BIT;
370	status = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,
371				SOC_DTS_OFFSET_PTMC, ptmc_out);
372
373	status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,
374			       SOC_DTS_OFFSET_PTTSS, &sticky_out);
375	pr_debug("status %d PTTSS %x\n", status, sticky_out);
376	if (sticky_out & SOC_DTS_TRIP_MASK) {
377		int i;
378		/* reset sticky bit */
379		status = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,
380					SOC_DTS_OFFSET_PTTSS, sticky_out);
381		spin_unlock_irqrestore(&sensors->intr_notify_lock, flags);
382
383		for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) {
384			pr_debug("TZD update for zone %d\n", i);
385			thermal_zone_device_update(sensors->soc_dts[i].tzone,
386						   THERMAL_EVENT_UNSPECIFIED);
387		}
388	} else
389		spin_unlock_irqrestore(&sensors->intr_notify_lock, flags);
390}
391EXPORT_SYMBOL_GPL(intel_soc_dts_iosf_interrupt_handler);
392
393struct intel_soc_dts_sensors *intel_soc_dts_iosf_init(
394	enum intel_soc_dts_interrupt_type intr_type, int trip_count,
395	int read_only_trip_count)
396{
397	struct intel_soc_dts_sensors *sensors;
398	bool notification;
399	u32 tj_max;
400	int ret;
401	int i;
402
403	if (!iosf_mbi_available())
404		return ERR_PTR(-ENODEV);
405
406	if (!trip_count || read_only_trip_count > trip_count)
407		return ERR_PTR(-EINVAL);
408
409	if (get_tj_max(&tj_max))
410		return ERR_PTR(-EINVAL);
411
412	sensors = kzalloc(sizeof(*sensors), GFP_KERNEL);
413	if (!sensors)
414		return ERR_PTR(-ENOMEM);
415
416	spin_lock_init(&sensors->intr_notify_lock);
417	mutex_init(&sensors->dts_update_lock);
418	sensors->intr_type = intr_type;
419	sensors->tj_max = tj_max;
420	if (intr_type == INTEL_SOC_DTS_INTERRUPT_NONE)
421		notification = false;
422	else
423		notification = true;
424	for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) {
425		sensors->soc_dts[i].sensors = sensors;
426		ret = add_dts_thermal_zone(i, &sensors->soc_dts[i],
427					   notification, trip_count,
428					   read_only_trip_count);
429		if (ret)
430			goto err_free;
431	}
432
433	for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) {
434		ret = update_trip_temp(&sensors->soc_dts[i], 0, 0,
435				       THERMAL_TRIP_PASSIVE);
436		if (ret)
437			goto err_remove_zone;
438
439		ret = update_trip_temp(&sensors->soc_dts[i], 1, 0,
440				       THERMAL_TRIP_PASSIVE);
441		if (ret)
442			goto err_remove_zone;
443	}
444
445	return sensors;
446err_remove_zone:
447	for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i)
448		remove_dts_thermal_zone(&sensors->soc_dts[i]);
449
450err_free:
451	kfree(sensors);
452	return ERR_PTR(ret);
453}
454EXPORT_SYMBOL_GPL(intel_soc_dts_iosf_init);
455
456void intel_soc_dts_iosf_exit(struct intel_soc_dts_sensors *sensors)
457{
458	int i;
459
460	for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) {
461		update_trip_temp(&sensors->soc_dts[i], 0, 0, 0);
462		update_trip_temp(&sensors->soc_dts[i], 1, 0, 0);
463		remove_dts_thermal_zone(&sensors->soc_dts[i]);
464	}
465	kfree(sensors);
466}
467EXPORT_SYMBOL_GPL(intel_soc_dts_iosf_exit);
468
469MODULE_LICENSE("GPL v2");