xref: /linux/drivers/gpu/drm/i915/i915_hwmon.c (revision 36ec807b627b4c0a0a382f0ae48eac7187d14b2b)
1b3b088e2SDale B Stimson // SPDX-License-Identifier: MIT
2b3b088e2SDale B Stimson /*
3b3b088e2SDale B Stimson  * Copyright © 2022 Intel Corporation
4b3b088e2SDale B Stimson  */
5b3b088e2SDale B Stimson 
6b3b088e2SDale B Stimson #include <linux/hwmon.h>
7b3b088e2SDale B Stimson #include <linux/hwmon-sysfs.h>
8b3b088e2SDale B Stimson #include <linux/types.h>
9b3b088e2SDale B Stimson 
10b3b088e2SDale B Stimson #include "i915_drv.h"
11b3b088e2SDale B Stimson #include "i915_hwmon.h"
12b3b088e2SDale B Stimson #include "i915_reg.h"
13b3b088e2SDale B Stimson #include "intel_mchbar_regs.h"
14c8939848SAshutosh Dixit #include "intel_pcode.h"
15a6a924abSDale B Stimson #include "gt/intel_gt.h"
16f8572bb6SRiana Tauro #include "gt/intel_gt_regs.h"
17f8572bb6SRiana Tauro 
18f8572bb6SRiana Tauro /*
19f8572bb6SRiana Tauro  * SF_* - scale factors for particular quantities according to hwmon spec.
20f8572bb6SRiana Tauro  * - voltage  - millivolts
2199f55efbSDale B Stimson  * - power  - microwatts
22c8939848SAshutosh Dixit  * - curr   - milliamperes
23c41b8bdcSDale B Stimson  * - energy - microjoules
244c2572feSAshutosh Dixit  * - time   - milliseconds
25f8572bb6SRiana Tauro  */
26f8572bb6SRiana Tauro #define SF_VOLTAGE	1000
2799f55efbSDale B Stimson #define SF_POWER	1000000
28c8939848SAshutosh Dixit #define SF_CURR		1000
29c41b8bdcSDale B Stimson #define SF_ENERGY	1000000
304c2572feSAshutosh Dixit #define SF_TIME		1000
31b3b088e2SDale B Stimson 
32b3b088e2SDale B Stimson struct hwm_reg {
33f8572bb6SRiana Tauro 	i915_reg_t gt_perf_status;
3499f55efbSDale B Stimson 	i915_reg_t pkg_power_sku_unit;
3599f55efbSDale B Stimson 	i915_reg_t pkg_power_sku;
3699f55efbSDale B Stimson 	i915_reg_t pkg_rapl_limit;
37c41b8bdcSDale B Stimson 	i915_reg_t energy_status_all;
38a6a924abSDale B Stimson 	i915_reg_t energy_status_tile;
39c41b8bdcSDale B Stimson };
40c41b8bdcSDale B Stimson 
41c41b8bdcSDale B Stimson struct hwm_energy_info {
42c41b8bdcSDale B Stimson 	u32 reg_val_prev;
43c41b8bdcSDale B Stimson 	long accum_energy;			/* Accumulated energy for energy1_input */
44b3b088e2SDale B Stimson };
45b3b088e2SDale B Stimson 
46b3b088e2SDale B Stimson struct hwm_drvdata {
47b3b088e2SDale B Stimson 	struct i915_hwmon *hwmon;
48b3b088e2SDale B Stimson 	struct intel_uncore *uncore;
49b3b088e2SDale B Stimson 	struct device *hwmon_dev;
50c41b8bdcSDale B Stimson 	struct hwm_energy_info ei;		/*  Energy info for energy1_input */
51b3b088e2SDale B Stimson 	char name[12];
52a6a924abSDale B Stimson 	int gt_n;
531b44019aSAshutosh Dixit 	bool reset_in_progress;
54655bd3b9SAshutosh Dixit 	wait_queue_head_t waitq;
55b3b088e2SDale B Stimson };
56b3b088e2SDale B Stimson 
57b3b088e2SDale B Stimson struct i915_hwmon {
58b3b088e2SDale B Stimson 	struct hwm_drvdata ddat;
59a6a924abSDale B Stimson 	struct hwm_drvdata ddat_gt[I915_MAX_GT];
60b3b088e2SDale B Stimson 	struct mutex hwmon_lock;		/* counter overflow logic and rmw */
61b3b088e2SDale B Stimson 	struct hwm_reg rg;
6299f55efbSDale B Stimson 	int scl_shift_power;
63c41b8bdcSDale B Stimson 	int scl_shift_energy;
644c2572feSAshutosh Dixit 	int scl_shift_time;
65b3b088e2SDale B Stimson };
66b3b088e2SDale B Stimson 
6799f55efbSDale B Stimson static void
6899f55efbSDale B Stimson hwm_locked_with_pm_intel_uncore_rmw(struct hwm_drvdata *ddat,
6999f55efbSDale B Stimson 				    i915_reg_t reg, u32 clear, u32 set)
7099f55efbSDale B Stimson {
7199f55efbSDale B Stimson 	struct i915_hwmon *hwmon = ddat->hwmon;
7299f55efbSDale B Stimson 	struct intel_uncore *uncore = ddat->uncore;
7399f55efbSDale B Stimson 	intel_wakeref_t wakeref;
7499f55efbSDale B Stimson 
7571b21877SJanusz Krzysztofik 	with_intel_runtime_pm(uncore->rpm, wakeref) {
7699f55efbSDale B Stimson 		mutex_lock(&hwmon->hwmon_lock);
7799f55efbSDale B Stimson 
7899f55efbSDale B Stimson 		intel_uncore_rmw(uncore, reg, clear, set);
7999f55efbSDale B Stimson 
8099f55efbSDale B Stimson 		mutex_unlock(&hwmon->hwmon_lock);
8199f55efbSDale B Stimson 	}
8271b21877SJanusz Krzysztofik }
8399f55efbSDale B Stimson 
8499f55efbSDale B Stimson /*
8599f55efbSDale B Stimson  * This function's return type of u64 allows for the case where the scaling
8699f55efbSDale B Stimson  * of the field taken from the 32-bit register value might cause a result to
8799f55efbSDale B Stimson  * exceed 32 bits.
8899f55efbSDale B Stimson  */
8999f55efbSDale B Stimson static u64
9099f55efbSDale B Stimson hwm_field_read_and_scale(struct hwm_drvdata *ddat, i915_reg_t rgadr,
9199f55efbSDale B Stimson 			 u32 field_msk, int nshift, u32 scale_factor)
9299f55efbSDale B Stimson {
9399f55efbSDale B Stimson 	struct intel_uncore *uncore = ddat->uncore;
9499f55efbSDale B Stimson 	intel_wakeref_t wakeref;
9599f55efbSDale B Stimson 	u32 reg_value;
9699f55efbSDale B Stimson 
9799f55efbSDale B Stimson 	with_intel_runtime_pm(uncore->rpm, wakeref)
9899f55efbSDale B Stimson 		reg_value = intel_uncore_read(uncore, rgadr);
9999f55efbSDale B Stimson 
10099f55efbSDale B Stimson 	reg_value = REG_FIELD_GET(field_msk, reg_value);
10199f55efbSDale B Stimson 
10299f55efbSDale B Stimson 	return mul_u64_u32_shr(reg_value, scale_factor, nshift);
10399f55efbSDale B Stimson }
10499f55efbSDale B Stimson 
105c41b8bdcSDale B Stimson /*
106c41b8bdcSDale B Stimson  * hwm_energy - Obtain energy value
107c41b8bdcSDale B Stimson  *
108c41b8bdcSDale B Stimson  * The underlying energy hardware register is 32-bits and is subject to
109c41b8bdcSDale B Stimson  * overflow. How long before overflow? For example, with an example
110c41b8bdcSDale B Stimson  * scaling bit shift of 14 bits (see register *PACKAGE_POWER_SKU_UNIT) and
111c41b8bdcSDale B Stimson  * a power draw of 1000 watts, the 32-bit counter will overflow in
112c41b8bdcSDale B Stimson  * approximately 4.36 minutes.
113c41b8bdcSDale B Stimson  *
114c41b8bdcSDale B Stimson  * Examples:
115c41b8bdcSDale B Stimson  *    1 watt:  (2^32 >> 14) /    1 W / (60 * 60 * 24) secs/day -> 3 days
116c41b8bdcSDale B Stimson  * 1000 watts: (2^32 >> 14) / 1000 W / 60             secs/min -> 4.36 minutes
117c41b8bdcSDale B Stimson  *
118c41b8bdcSDale B Stimson  * The function significantly increases overflow duration (from 4.36
119c41b8bdcSDale B Stimson  * minutes) by accumulating the energy register into a 'long' as allowed by
120c41b8bdcSDale B Stimson  * the hwmon API. Using x86_64 128 bit arithmetic (see mul_u64_u32_shr()),
121c41b8bdcSDale B Stimson  * a 'long' of 63 bits, SF_ENERGY of 1e6 (~20 bits) and
122c41b8bdcSDale B Stimson  * hwmon->scl_shift_energy of 14 bits we have 57 (63 - 20 + 14) bits before
123c41b8bdcSDale B Stimson  * energy1_input overflows. This at 1000 W is an overflow duration of 278 years.
124c41b8bdcSDale B Stimson  */
125c41b8bdcSDale B Stimson static void
126c41b8bdcSDale B Stimson hwm_energy(struct hwm_drvdata *ddat, long *energy)
127c41b8bdcSDale B Stimson {
128c41b8bdcSDale B Stimson 	struct intel_uncore *uncore = ddat->uncore;
129c41b8bdcSDale B Stimson 	struct i915_hwmon *hwmon = ddat->hwmon;
130c41b8bdcSDale B Stimson 	struct hwm_energy_info *ei = &ddat->ei;
131c41b8bdcSDale B Stimson 	intel_wakeref_t wakeref;
132c41b8bdcSDale B Stimson 	i915_reg_t rgaddr;
133c41b8bdcSDale B Stimson 	u32 reg_val;
134c41b8bdcSDale B Stimson 
135a6a924abSDale B Stimson 	if (ddat->gt_n >= 0)
136a6a924abSDale B Stimson 		rgaddr = hwmon->rg.energy_status_tile;
137a6a924abSDale B Stimson 	else
138c41b8bdcSDale B Stimson 		rgaddr = hwmon->rg.energy_status_all;
139c41b8bdcSDale B Stimson 
14071b21877SJanusz Krzysztofik 	with_intel_runtime_pm(uncore->rpm, wakeref) {
141c41b8bdcSDale B Stimson 		mutex_lock(&hwmon->hwmon_lock);
142c41b8bdcSDale B Stimson 
143c41b8bdcSDale B Stimson 		reg_val = intel_uncore_read(uncore, rgaddr);
144c41b8bdcSDale B Stimson 
145c41b8bdcSDale B Stimson 		if (reg_val >= ei->reg_val_prev)
146c41b8bdcSDale B Stimson 			ei->accum_energy += reg_val - ei->reg_val_prev;
147c41b8bdcSDale B Stimson 		else
148c41b8bdcSDale B Stimson 			ei->accum_energy += UINT_MAX - ei->reg_val_prev + reg_val;
149c41b8bdcSDale B Stimson 		ei->reg_val_prev = reg_val;
150c41b8bdcSDale B Stimson 
151c41b8bdcSDale B Stimson 		*energy = mul_u64_u32_shr(ei->accum_energy, SF_ENERGY,
152c41b8bdcSDale B Stimson 					  hwmon->scl_shift_energy);
153c41b8bdcSDale B Stimson 		mutex_unlock(&hwmon->hwmon_lock);
154c41b8bdcSDale B Stimson 	}
15571b21877SJanusz Krzysztofik }
156c41b8bdcSDale B Stimson 
1574c2572feSAshutosh Dixit static ssize_t
1584c2572feSAshutosh Dixit hwm_power1_max_interval_show(struct device *dev, struct device_attribute *attr,
1594c2572feSAshutosh Dixit 			     char *buf)
1604c2572feSAshutosh Dixit {
1614c2572feSAshutosh Dixit 	struct hwm_drvdata *ddat = dev_get_drvdata(dev);
1624c2572feSAshutosh Dixit 	struct i915_hwmon *hwmon = ddat->hwmon;
1634c2572feSAshutosh Dixit 	intel_wakeref_t wakeref;
1644c2572feSAshutosh Dixit 	u32 r, x, y, x_w = 2; /* 2 bits */
1654c2572feSAshutosh Dixit 	u64 tau4, out;
1664c2572feSAshutosh Dixit 
1674c2572feSAshutosh Dixit 	with_intel_runtime_pm(ddat->uncore->rpm, wakeref)
1684c2572feSAshutosh Dixit 		r = intel_uncore_read(ddat->uncore, hwmon->rg.pkg_rapl_limit);
1694c2572feSAshutosh Dixit 
1704c2572feSAshutosh Dixit 	x = REG_FIELD_GET(PKG_PWR_LIM_1_TIME_X, r);
1714c2572feSAshutosh Dixit 	y = REG_FIELD_GET(PKG_PWR_LIM_1_TIME_Y, r);
1724c2572feSAshutosh Dixit 	/*
1734c2572feSAshutosh Dixit 	 * tau = 1.x * power(2,y), x = bits(23:22), y = bits(21:17)
1744c2572feSAshutosh Dixit 	 *     = (4 | x) << (y - 2)
1754c2572feSAshutosh Dixit 	 * where (y - 2) ensures a 1.x fixed point representation of 1.x
1764c2572feSAshutosh Dixit 	 * However because y can be < 2, we compute
1774c2572feSAshutosh Dixit 	 *     tau4 = (4 | x) << y
1784c2572feSAshutosh Dixit 	 * but add 2 when doing the final right shift to account for units
1794c2572feSAshutosh Dixit 	 */
180ac3420d3SKarthik Poosa 	tau4 = (u64)((1 << x_w) | x) << y;
1814c2572feSAshutosh Dixit 	/* val in hwmon interface units (millisec) */
1824c2572feSAshutosh Dixit 	out = mul_u64_u32_shr(tau4, SF_TIME, hwmon->scl_shift_time + x_w);
1834c2572feSAshutosh Dixit 
1844c2572feSAshutosh Dixit 	return sysfs_emit(buf, "%llu\n", out);
1854c2572feSAshutosh Dixit }
1864c2572feSAshutosh Dixit 
1874c2572feSAshutosh Dixit static ssize_t
1884c2572feSAshutosh Dixit hwm_power1_max_interval_store(struct device *dev,
1894c2572feSAshutosh Dixit 			      struct device_attribute *attr,
1904c2572feSAshutosh Dixit 			      const char *buf, size_t count)
1914c2572feSAshutosh Dixit {
1924c2572feSAshutosh Dixit 	struct hwm_drvdata *ddat = dev_get_drvdata(dev);
1934c2572feSAshutosh Dixit 	struct i915_hwmon *hwmon = ddat->hwmon;
1944c2572feSAshutosh Dixit 	u32 x, y, rxy, x_w = 2; /* 2 bits */
1954c2572feSAshutosh Dixit 	u64 tau4, r, max_win;
1964c2572feSAshutosh Dixit 	unsigned long val;
1974c2572feSAshutosh Dixit 	int ret;
1984c2572feSAshutosh Dixit 
1994c2572feSAshutosh Dixit 	ret = kstrtoul(buf, 0, &val);
2004c2572feSAshutosh Dixit 	if (ret)
2014c2572feSAshutosh Dixit 		return ret;
2024c2572feSAshutosh Dixit 
2034c2572feSAshutosh Dixit 	/*
2044c2572feSAshutosh Dixit 	 * Max HW supported tau in '1.x * power(2,y)' format, x = 0, y = 0x12
2054c2572feSAshutosh Dixit 	 * The hwmon->scl_shift_time default of 0xa results in a max tau of 256 seconds
2064c2572feSAshutosh Dixit 	 */
2074c2572feSAshutosh Dixit #define PKG_MAX_WIN_DEFAULT 0x12ull
2084c2572feSAshutosh Dixit 
2094c2572feSAshutosh Dixit 	/*
2104c2572feSAshutosh Dixit 	 * val must be < max in hwmon interface units. The steps below are
2114c2572feSAshutosh Dixit 	 * explained in i915_power1_max_interval_show()
2124c2572feSAshutosh Dixit 	 */
2134c2572feSAshutosh Dixit 	r = FIELD_PREP(PKG_MAX_WIN, PKG_MAX_WIN_DEFAULT);
2144c2572feSAshutosh Dixit 	x = REG_FIELD_GET(PKG_MAX_WIN_X, r);
2154c2572feSAshutosh Dixit 	y = REG_FIELD_GET(PKG_MAX_WIN_Y, r);
216ac3420d3SKarthik Poosa 	tau4 = (u64)((1 << x_w) | x) << y;
2174c2572feSAshutosh Dixit 	max_win = mul_u64_u32_shr(tau4, SF_TIME, hwmon->scl_shift_time + x_w);
2184c2572feSAshutosh Dixit 
2194c2572feSAshutosh Dixit 	if (val > max_win)
2204c2572feSAshutosh Dixit 		return -EINVAL;
2214c2572feSAshutosh Dixit 
2224c2572feSAshutosh Dixit 	/* val in hw units */
2234c2572feSAshutosh Dixit 	val = DIV_ROUND_CLOSEST_ULL((u64)val << hwmon->scl_shift_time, SF_TIME);
2244c2572feSAshutosh Dixit 	/* Convert to 1.x * power(2,y) */
22512e8ed96SAshutosh Dixit 	if (!val) {
22612e8ed96SAshutosh Dixit 		/* Avoid ilog2(0) */
22712e8ed96SAshutosh Dixit 		y = 0;
22812e8ed96SAshutosh Dixit 		x = 0;
22912e8ed96SAshutosh Dixit 	} else {
2304c2572feSAshutosh Dixit 		y = ilog2(val);
2314c2572feSAshutosh Dixit 		/* x = (val - (1 << y)) >> (y - 2); */
2324c2572feSAshutosh Dixit 		x = (val - (1ul << y)) << x_w >> y;
23312e8ed96SAshutosh Dixit 	}
2344c2572feSAshutosh Dixit 
2354c2572feSAshutosh Dixit 	rxy = REG_FIELD_PREP(PKG_PWR_LIM_1_TIME_X, x) | REG_FIELD_PREP(PKG_PWR_LIM_1_TIME_Y, y);
2364c2572feSAshutosh Dixit 
2374c2572feSAshutosh Dixit 	hwm_locked_with_pm_intel_uncore_rmw(ddat, hwmon->rg.pkg_rapl_limit,
2384c2572feSAshutosh Dixit 					    PKG_PWR_LIM_1_TIME, rxy);
2394c2572feSAshutosh Dixit 	return count;
2404c2572feSAshutosh Dixit }
2414c2572feSAshutosh Dixit 
2424c2572feSAshutosh Dixit static SENSOR_DEVICE_ATTR(power1_max_interval, 0664,
2434c2572feSAshutosh Dixit 			  hwm_power1_max_interval_show,
2444c2572feSAshutosh Dixit 			  hwm_power1_max_interval_store, 0);
2454c2572feSAshutosh Dixit 
2464c2572feSAshutosh Dixit static struct attribute *hwm_attributes[] = {
2474c2572feSAshutosh Dixit 	&sensor_dev_attr_power1_max_interval.dev_attr.attr,
2484c2572feSAshutosh Dixit 	NULL
2494c2572feSAshutosh Dixit };
2504c2572feSAshutosh Dixit 
2514c2572feSAshutosh Dixit static umode_t hwm_attributes_visible(struct kobject *kobj,
2524c2572feSAshutosh Dixit 				      struct attribute *attr, int index)
2534c2572feSAshutosh Dixit {
2544c2572feSAshutosh Dixit 	struct device *dev = kobj_to_dev(kobj);
2554c2572feSAshutosh Dixit 	struct hwm_drvdata *ddat = dev_get_drvdata(dev);
2564c2572feSAshutosh Dixit 	struct i915_hwmon *hwmon = ddat->hwmon;
2574c2572feSAshutosh Dixit 
2584c2572feSAshutosh Dixit 	if (attr == &sensor_dev_attr_power1_max_interval.dev_attr.attr)
2594c2572feSAshutosh Dixit 		return i915_mmio_reg_valid(hwmon->rg.pkg_rapl_limit) ? attr->mode : 0;
2604c2572feSAshutosh Dixit 
2614c2572feSAshutosh Dixit 	return 0;
2624c2572feSAshutosh Dixit }
2634c2572feSAshutosh Dixit 
2644c2572feSAshutosh Dixit static const struct attribute_group hwm_attrgroup = {
2654c2572feSAshutosh Dixit 	.attrs = hwm_attributes,
2664c2572feSAshutosh Dixit 	.is_visible = hwm_attributes_visible,
2674c2572feSAshutosh Dixit };
2684c2572feSAshutosh Dixit 
2694c2572feSAshutosh Dixit static const struct attribute_group *hwm_groups[] = {
2704c2572feSAshutosh Dixit 	&hwm_attrgroup,
2714c2572feSAshutosh Dixit 	NULL
2724c2572feSAshutosh Dixit };
2734c2572feSAshutosh Dixit 
274861601ffSKrzysztof Kozlowski static const struct hwmon_channel_info * const hwm_info[] = {
275f8572bb6SRiana Tauro 	HWMON_CHANNEL_INFO(in, HWMON_I_INPUT),
276c8939848SAshutosh Dixit 	HWMON_CHANNEL_INFO(power, HWMON_P_MAX | HWMON_P_RATED_MAX | HWMON_P_CRIT),
277c41b8bdcSDale B Stimson 	HWMON_CHANNEL_INFO(energy, HWMON_E_INPUT),
278c8939848SAshutosh Dixit 	HWMON_CHANNEL_INFO(curr, HWMON_C_CRIT),
279b3b088e2SDale B Stimson 	NULL
280b3b088e2SDale B Stimson };
281b3b088e2SDale B Stimson 
282861601ffSKrzysztof Kozlowski static const struct hwmon_channel_info * const hwm_gt_info[] = {
283a6a924abSDale B Stimson 	HWMON_CHANNEL_INFO(energy, HWMON_E_INPUT),
284a6a924abSDale B Stimson 	NULL
285a6a924abSDale B Stimson };
286a6a924abSDale B Stimson 
287c8939848SAshutosh Dixit /* I1 is exposed as power_crit or as curr_crit depending on bit 31 */
288c8939848SAshutosh Dixit static int hwm_pcode_read_i1(struct drm_i915_private *i915, u32 *uval)
289c8939848SAshutosh Dixit {
2903d0f98faSAshutosh Dixit 	/* Avoid ILLEGAL_SUBCOMMAND "mailbox access failed" warning in snb_pcode_read */
2913d0f98faSAshutosh Dixit 	if (IS_DG1(i915) || IS_DG2(i915))
2923d0f98faSAshutosh Dixit 		return -ENXIO;
2933d0f98faSAshutosh Dixit 
294c8939848SAshutosh Dixit 	return snb_pcode_read_p(&i915->uncore, PCODE_POWER_SETUP,
295c8939848SAshutosh Dixit 				POWER_SETUP_SUBCOMMAND_READ_I1, 0, uval);
296c8939848SAshutosh Dixit }
297c8939848SAshutosh Dixit 
298c8939848SAshutosh Dixit static int hwm_pcode_write_i1(struct drm_i915_private *i915, u32 uval)
299c8939848SAshutosh Dixit {
300c8939848SAshutosh Dixit 	return  snb_pcode_write_p(&i915->uncore, PCODE_POWER_SETUP,
301c8939848SAshutosh Dixit 				  POWER_SETUP_SUBCOMMAND_WRITE_I1, 0, uval);
302c8939848SAshutosh Dixit }
303c8939848SAshutosh Dixit 
304b3b088e2SDale B Stimson static umode_t
305f8572bb6SRiana Tauro hwm_in_is_visible(const struct hwm_drvdata *ddat, u32 attr)
306f8572bb6SRiana Tauro {
307f8572bb6SRiana Tauro 	struct drm_i915_private *i915 = ddat->uncore->i915;
308f8572bb6SRiana Tauro 
309f8572bb6SRiana Tauro 	switch (attr) {
310f8572bb6SRiana Tauro 	case hwmon_in_input:
311f8572bb6SRiana Tauro 		return IS_DG1(i915) || IS_DG2(i915) ? 0444 : 0;
312f8572bb6SRiana Tauro 	default:
313f8572bb6SRiana Tauro 		return 0;
314f8572bb6SRiana Tauro 	}
315f8572bb6SRiana Tauro }
316f8572bb6SRiana Tauro 
317f8572bb6SRiana Tauro static int
318f8572bb6SRiana Tauro hwm_in_read(struct hwm_drvdata *ddat, u32 attr, long *val)
319f8572bb6SRiana Tauro {
320f8572bb6SRiana Tauro 	struct i915_hwmon *hwmon = ddat->hwmon;
321f8572bb6SRiana Tauro 	intel_wakeref_t wakeref;
322f8572bb6SRiana Tauro 	u32 reg_value;
323f8572bb6SRiana Tauro 
324f8572bb6SRiana Tauro 	switch (attr) {
325f8572bb6SRiana Tauro 	case hwmon_in_input:
326f8572bb6SRiana Tauro 		with_intel_runtime_pm(ddat->uncore->rpm, wakeref)
327f8572bb6SRiana Tauro 			reg_value = intel_uncore_read(ddat->uncore, hwmon->rg.gt_perf_status);
328f8572bb6SRiana Tauro 		/* HW register value in units of 2.5 millivolt */
329f8572bb6SRiana Tauro 		*val = DIV_ROUND_CLOSEST(REG_FIELD_GET(GEN12_VOLTAGE_MASK, reg_value) * 25, 10);
330f8572bb6SRiana Tauro 		return 0;
331f8572bb6SRiana Tauro 	default:
332f8572bb6SRiana Tauro 		return -EOPNOTSUPP;
333f8572bb6SRiana Tauro 	}
334f8572bb6SRiana Tauro }
335f8572bb6SRiana Tauro 
336f8572bb6SRiana Tauro static umode_t
33799f55efbSDale B Stimson hwm_power_is_visible(const struct hwm_drvdata *ddat, u32 attr, int chan)
33899f55efbSDale B Stimson {
339c8939848SAshutosh Dixit 	struct drm_i915_private *i915 = ddat->uncore->i915;
34099f55efbSDale B Stimson 	struct i915_hwmon *hwmon = ddat->hwmon;
341c8939848SAshutosh Dixit 	u32 uval;
34299f55efbSDale B Stimson 
34399f55efbSDale B Stimson 	switch (attr) {
34499f55efbSDale B Stimson 	case hwmon_power_max:
34599f55efbSDale B Stimson 		return i915_mmio_reg_valid(hwmon->rg.pkg_rapl_limit) ? 0664 : 0;
34699f55efbSDale B Stimson 	case hwmon_power_rated_max:
34799f55efbSDale B Stimson 		return i915_mmio_reg_valid(hwmon->rg.pkg_power_sku) ? 0444 : 0;
348c8939848SAshutosh Dixit 	case hwmon_power_crit:
349c8939848SAshutosh Dixit 		return (hwm_pcode_read_i1(i915, &uval) ||
350c8939848SAshutosh Dixit 			!(uval & POWER_SETUP_I1_WATTS)) ? 0 : 0644;
35199f55efbSDale B Stimson 	default:
35299f55efbSDale B Stimson 		return 0;
35399f55efbSDale B Stimson 	}
35499f55efbSDale B Stimson }
35599f55efbSDale B Stimson 
3564ed22f1eSAshutosh Dixit #define PL1_DISABLE 0
3574ed22f1eSAshutosh Dixit 
358d2c3c8c3SAshutosh Dixit /*
359d2c3c8c3SAshutosh Dixit  * HW allows arbitrary PL1 limits to be set but silently clamps these values to
360d2c3c8c3SAshutosh Dixit  * "typical but not guaranteed" min/max values in rg.pkg_power_sku. Follow the
361d2c3c8c3SAshutosh Dixit  * same pattern for sysfs, allow arbitrary PL1 limits to be set but display
362d2c3c8c3SAshutosh Dixit  * clamped values when read. Write/read I1 also follows the same pattern.
363d2c3c8c3SAshutosh Dixit  */
364d2c3c8c3SAshutosh Dixit static int
365d2c3c8c3SAshutosh Dixit hwm_power_max_read(struct hwm_drvdata *ddat, long *val)
366d2c3c8c3SAshutosh Dixit {
367d2c3c8c3SAshutosh Dixit 	struct i915_hwmon *hwmon = ddat->hwmon;
368d2c3c8c3SAshutosh Dixit 	intel_wakeref_t wakeref;
369d2c3c8c3SAshutosh Dixit 	u64 r, min, max;
370d2c3c8c3SAshutosh Dixit 
3714ed22f1eSAshutosh Dixit 	/* Check if PL1 limit is disabled */
3724ed22f1eSAshutosh Dixit 	with_intel_runtime_pm(ddat->uncore->rpm, wakeref)
3734ed22f1eSAshutosh Dixit 		r = intel_uncore_read(ddat->uncore, hwmon->rg.pkg_rapl_limit);
3744ed22f1eSAshutosh Dixit 	if (!(r & PKG_PWR_LIM_1_EN)) {
3754ed22f1eSAshutosh Dixit 		*val = PL1_DISABLE;
3764ed22f1eSAshutosh Dixit 		return 0;
3774ed22f1eSAshutosh Dixit 	}
3784ed22f1eSAshutosh Dixit 
379d2c3c8c3SAshutosh Dixit 	*val = hwm_field_read_and_scale(ddat,
380d2c3c8c3SAshutosh Dixit 					hwmon->rg.pkg_rapl_limit,
381d2c3c8c3SAshutosh Dixit 					PKG_PWR_LIM_1,
382d2c3c8c3SAshutosh Dixit 					hwmon->scl_shift_power,
383d2c3c8c3SAshutosh Dixit 					SF_POWER);
384d2c3c8c3SAshutosh Dixit 
385d2c3c8c3SAshutosh Dixit 	with_intel_runtime_pm(ddat->uncore->rpm, wakeref)
386d2c3c8c3SAshutosh Dixit 		r = intel_uncore_read64(ddat->uncore, hwmon->rg.pkg_power_sku);
387d2c3c8c3SAshutosh Dixit 	min = REG_FIELD_GET(PKG_MIN_PWR, r);
388d2c3c8c3SAshutosh Dixit 	min = mul_u64_u32_shr(min, SF_POWER, hwmon->scl_shift_power);
389d2c3c8c3SAshutosh Dixit 	max = REG_FIELD_GET(PKG_MAX_PWR, r);
390d2c3c8c3SAshutosh Dixit 	max = mul_u64_u32_shr(max, SF_POWER, hwmon->scl_shift_power);
391d2c3c8c3SAshutosh Dixit 
392d2c3c8c3SAshutosh Dixit 	if (min && max)
393d2c3c8c3SAshutosh Dixit 		*val = clamp_t(u64, *val, min, max);
394d2c3c8c3SAshutosh Dixit 
395d2c3c8c3SAshutosh Dixit 	return 0;
396d2c3c8c3SAshutosh Dixit }
397d2c3c8c3SAshutosh Dixit 
39899f55efbSDale B Stimson static int
399f9992638SAshutosh Dixit hwm_power_max_write(struct hwm_drvdata *ddat, long val)
400f9992638SAshutosh Dixit {
401f9992638SAshutosh Dixit 	struct i915_hwmon *hwmon = ddat->hwmon;
4024ed22f1eSAshutosh Dixit 	intel_wakeref_t wakeref;
403655bd3b9SAshutosh Dixit 	DEFINE_WAIT(wait);
404d81268eeSAshutosh Dixit 	int ret = 0;
405f9992638SAshutosh Dixit 	u32 nval;
406f9992638SAshutosh Dixit 
407655bd3b9SAshutosh Dixit 	/* Block waiting for GuC reset to complete when needed */
408655bd3b9SAshutosh Dixit 	for (;;) {
40971b21877SJanusz Krzysztofik 		wakeref = intel_runtime_pm_get(ddat->uncore->rpm);
410d81268eeSAshutosh Dixit 		mutex_lock(&hwmon->hwmon_lock);
411655bd3b9SAshutosh Dixit 
412655bd3b9SAshutosh Dixit 		prepare_to_wait(&ddat->waitq, &wait, TASK_INTERRUPTIBLE);
413655bd3b9SAshutosh Dixit 
414655bd3b9SAshutosh Dixit 		if (!hwmon->ddat.reset_in_progress)
415655bd3b9SAshutosh Dixit 			break;
416655bd3b9SAshutosh Dixit 
417655bd3b9SAshutosh Dixit 		if (signal_pending(current)) {
418655bd3b9SAshutosh Dixit 			ret = -EINTR;
419655bd3b9SAshutosh Dixit 			break;
4201b44019aSAshutosh Dixit 		}
421655bd3b9SAshutosh Dixit 
422655bd3b9SAshutosh Dixit 		mutex_unlock(&hwmon->hwmon_lock);
42371b21877SJanusz Krzysztofik 		intel_runtime_pm_put(ddat->uncore->rpm, wakeref);
424655bd3b9SAshutosh Dixit 
425655bd3b9SAshutosh Dixit 		schedule();
426655bd3b9SAshutosh Dixit 	}
427655bd3b9SAshutosh Dixit 	finish_wait(&ddat->waitq, &wait);
428655bd3b9SAshutosh Dixit 	if (ret)
42971b21877SJanusz Krzysztofik 		goto exit;
430d81268eeSAshutosh Dixit 
4314ed22f1eSAshutosh Dixit 	/* Disable PL1 limit and verify, because the limit cannot be disabled on all platforms */
4324ed22f1eSAshutosh Dixit 	if (val == PL1_DISABLE) {
4334ed22f1eSAshutosh Dixit 		intel_uncore_rmw(ddat->uncore, hwmon->rg.pkg_rapl_limit,
4344ed22f1eSAshutosh Dixit 				 PKG_PWR_LIM_1_EN, 0);
4354ed22f1eSAshutosh Dixit 		nval = intel_uncore_read(ddat->uncore, hwmon->rg.pkg_rapl_limit);
4364ed22f1eSAshutosh Dixit 
4374ed22f1eSAshutosh Dixit 		if (nval & PKG_PWR_LIM_1_EN)
438d81268eeSAshutosh Dixit 			ret = -ENODEV;
439d81268eeSAshutosh Dixit 		goto exit;
4404ed22f1eSAshutosh Dixit 	}
4414ed22f1eSAshutosh Dixit 
442f9992638SAshutosh Dixit 	/* Computation in 64-bits to avoid overflow. Round to nearest. */
443f9992638SAshutosh Dixit 	nval = DIV_ROUND_CLOSEST_ULL((u64)val << hwmon->scl_shift_power, SF_POWER);
4446fd3d8bfSAshutosh Dixit 	nval = PKG_PWR_LIM_1_EN | REG_FIELD_PREP(PKG_PWR_LIM_1, nval);
445f9992638SAshutosh Dixit 
446d81268eeSAshutosh Dixit 	intel_uncore_rmw(ddat->uncore, hwmon->rg.pkg_rapl_limit,
447d81268eeSAshutosh Dixit 			 PKG_PWR_LIM_1_EN | PKG_PWR_LIM_1, nval);
448d81268eeSAshutosh Dixit exit:
449d81268eeSAshutosh Dixit 	mutex_unlock(&hwmon->hwmon_lock);
45071b21877SJanusz Krzysztofik 	intel_runtime_pm_put(ddat->uncore->rpm, wakeref);
451d81268eeSAshutosh Dixit 	return ret;
452f9992638SAshutosh Dixit }
453f9992638SAshutosh Dixit 
454f9992638SAshutosh Dixit static int
45599f55efbSDale B Stimson hwm_power_read(struct hwm_drvdata *ddat, u32 attr, int chan, long *val)
45699f55efbSDale B Stimson {
45799f55efbSDale B Stimson 	struct i915_hwmon *hwmon = ddat->hwmon;
458c8939848SAshutosh Dixit 	int ret;
459c8939848SAshutosh Dixit 	u32 uval;
46099f55efbSDale B Stimson 
46199f55efbSDale B Stimson 	switch (attr) {
46299f55efbSDale B Stimson 	case hwmon_power_max:
463d2c3c8c3SAshutosh Dixit 		return hwm_power_max_read(ddat, val);
46499f55efbSDale B Stimson 	case hwmon_power_rated_max:
46599f55efbSDale B Stimson 		*val = hwm_field_read_and_scale(ddat,
46699f55efbSDale B Stimson 						hwmon->rg.pkg_power_sku,
46799f55efbSDale B Stimson 						PKG_PKG_TDP,
46899f55efbSDale B Stimson 						hwmon->scl_shift_power,
46999f55efbSDale B Stimson 						SF_POWER);
47099f55efbSDale B Stimson 		return 0;
471c8939848SAshutosh Dixit 	case hwmon_power_crit:
472c8939848SAshutosh Dixit 		ret = hwm_pcode_read_i1(ddat->uncore->i915, &uval);
473c8939848SAshutosh Dixit 		if (ret)
474c8939848SAshutosh Dixit 			return ret;
475c8939848SAshutosh Dixit 		if (!(uval & POWER_SETUP_I1_WATTS))
476c8939848SAshutosh Dixit 			return -ENODEV;
477c8939848SAshutosh Dixit 		*val = mul_u64_u32_shr(REG_FIELD_GET(POWER_SETUP_I1_DATA_MASK, uval),
478c8939848SAshutosh Dixit 				       SF_POWER, POWER_SETUP_I1_SHIFT);
479c8939848SAshutosh Dixit 		return 0;
48099f55efbSDale B Stimson 	default:
48199f55efbSDale B Stimson 		return -EOPNOTSUPP;
48299f55efbSDale B Stimson 	}
48399f55efbSDale B Stimson }
48499f55efbSDale B Stimson 
48599f55efbSDale B Stimson static int
48699f55efbSDale B Stimson hwm_power_write(struct hwm_drvdata *ddat, u32 attr, int chan, long val)
48799f55efbSDale B Stimson {
488c8939848SAshutosh Dixit 	u32 uval;
48999f55efbSDale B Stimson 
49099f55efbSDale B Stimson 	switch (attr) {
49199f55efbSDale B Stimson 	case hwmon_power_max:
492f9992638SAshutosh Dixit 		return hwm_power_max_write(ddat, val);
493c8939848SAshutosh Dixit 	case hwmon_power_crit:
494c8939848SAshutosh Dixit 		uval = DIV_ROUND_CLOSEST_ULL(val << POWER_SETUP_I1_SHIFT, SF_POWER);
495c8939848SAshutosh Dixit 		return hwm_pcode_write_i1(ddat->uncore->i915, uval);
49699f55efbSDale B Stimson 	default:
49799f55efbSDale B Stimson 		return -EOPNOTSUPP;
49899f55efbSDale B Stimson 	}
49999f55efbSDale B Stimson }
50099f55efbSDale B Stimson 
5011b44019aSAshutosh Dixit void i915_hwmon_power_max_disable(struct drm_i915_private *i915, bool *old)
5021b44019aSAshutosh Dixit {
5031b44019aSAshutosh Dixit 	struct i915_hwmon *hwmon = i915->hwmon;
5041b44019aSAshutosh Dixit 	u32 r;
5051b44019aSAshutosh Dixit 
5061b44019aSAshutosh Dixit 	if (!hwmon || !i915_mmio_reg_valid(hwmon->rg.pkg_rapl_limit))
5071b44019aSAshutosh Dixit 		return;
5081b44019aSAshutosh Dixit 
5091b44019aSAshutosh Dixit 	mutex_lock(&hwmon->hwmon_lock);
5101b44019aSAshutosh Dixit 
5111b44019aSAshutosh Dixit 	hwmon->ddat.reset_in_progress = true;
5121b44019aSAshutosh Dixit 	r = intel_uncore_rmw(hwmon->ddat.uncore, hwmon->rg.pkg_rapl_limit,
5131b44019aSAshutosh Dixit 			     PKG_PWR_LIM_1_EN, 0);
5141b44019aSAshutosh Dixit 	*old = !!(r & PKG_PWR_LIM_1_EN);
5151b44019aSAshutosh Dixit 
5161b44019aSAshutosh Dixit 	mutex_unlock(&hwmon->hwmon_lock);
5171b44019aSAshutosh Dixit }
5181b44019aSAshutosh Dixit 
5191b44019aSAshutosh Dixit void i915_hwmon_power_max_restore(struct drm_i915_private *i915, bool old)
5201b44019aSAshutosh Dixit {
5211b44019aSAshutosh Dixit 	struct i915_hwmon *hwmon = i915->hwmon;
5221b44019aSAshutosh Dixit 
5231b44019aSAshutosh Dixit 	if (!hwmon || !i915_mmio_reg_valid(hwmon->rg.pkg_rapl_limit))
5241b44019aSAshutosh Dixit 		return;
5251b44019aSAshutosh Dixit 
5261b44019aSAshutosh Dixit 	mutex_lock(&hwmon->hwmon_lock);
5271b44019aSAshutosh Dixit 
5281b44019aSAshutosh Dixit 	intel_uncore_rmw(hwmon->ddat.uncore, hwmon->rg.pkg_rapl_limit,
5291b44019aSAshutosh Dixit 			 PKG_PWR_LIM_1_EN, old ? PKG_PWR_LIM_1_EN : 0);
5301b44019aSAshutosh Dixit 	hwmon->ddat.reset_in_progress = false;
531655bd3b9SAshutosh Dixit 	wake_up_all(&hwmon->ddat.waitq);
5321b44019aSAshutosh Dixit 
5331b44019aSAshutosh Dixit 	mutex_unlock(&hwmon->hwmon_lock);
5341b44019aSAshutosh Dixit }
5351b44019aSAshutosh Dixit 
53699f55efbSDale B Stimson static umode_t
537c41b8bdcSDale B Stimson hwm_energy_is_visible(const struct hwm_drvdata *ddat, u32 attr)
538c41b8bdcSDale B Stimson {
539c41b8bdcSDale B Stimson 	struct i915_hwmon *hwmon = ddat->hwmon;
540c41b8bdcSDale B Stimson 	i915_reg_t rgaddr;
541c41b8bdcSDale B Stimson 
542c41b8bdcSDale B Stimson 	switch (attr) {
543c41b8bdcSDale B Stimson 	case hwmon_energy_input:
544a6a924abSDale B Stimson 		if (ddat->gt_n >= 0)
545a6a924abSDale B Stimson 			rgaddr = hwmon->rg.energy_status_tile;
546a6a924abSDale B Stimson 		else
547c41b8bdcSDale B Stimson 			rgaddr = hwmon->rg.energy_status_all;
548c41b8bdcSDale B Stimson 		return i915_mmio_reg_valid(rgaddr) ? 0444 : 0;
549c41b8bdcSDale B Stimson 	default:
550c41b8bdcSDale B Stimson 		return 0;
551c41b8bdcSDale B Stimson 	}
552c41b8bdcSDale B Stimson }
553c41b8bdcSDale B Stimson 
554c41b8bdcSDale B Stimson static int
555c41b8bdcSDale B Stimson hwm_energy_read(struct hwm_drvdata *ddat, u32 attr, long *val)
556c41b8bdcSDale B Stimson {
557c41b8bdcSDale B Stimson 	switch (attr) {
558c41b8bdcSDale B Stimson 	case hwmon_energy_input:
559c41b8bdcSDale B Stimson 		hwm_energy(ddat, val);
560c41b8bdcSDale B Stimson 		return 0;
561c41b8bdcSDale B Stimson 	default:
562c41b8bdcSDale B Stimson 		return -EOPNOTSUPP;
563c41b8bdcSDale B Stimson 	}
564c41b8bdcSDale B Stimson }
565c41b8bdcSDale B Stimson 
566c41b8bdcSDale B Stimson static umode_t
567c8939848SAshutosh Dixit hwm_curr_is_visible(const struct hwm_drvdata *ddat, u32 attr)
568c8939848SAshutosh Dixit {
569c8939848SAshutosh Dixit 	struct drm_i915_private *i915 = ddat->uncore->i915;
570c8939848SAshutosh Dixit 	u32 uval;
571c8939848SAshutosh Dixit 
572c8939848SAshutosh Dixit 	switch (attr) {
573c8939848SAshutosh Dixit 	case hwmon_curr_crit:
574c8939848SAshutosh Dixit 		return (hwm_pcode_read_i1(i915, &uval) ||
575c8939848SAshutosh Dixit 			(uval & POWER_SETUP_I1_WATTS)) ? 0 : 0644;
576c8939848SAshutosh Dixit 	default:
577c8939848SAshutosh Dixit 		return 0;
578c8939848SAshutosh Dixit 	}
579c8939848SAshutosh Dixit }
580c8939848SAshutosh Dixit 
581c8939848SAshutosh Dixit static int
582c8939848SAshutosh Dixit hwm_curr_read(struct hwm_drvdata *ddat, u32 attr, long *val)
583c8939848SAshutosh Dixit {
584c8939848SAshutosh Dixit 	int ret;
585c8939848SAshutosh Dixit 	u32 uval;
586c8939848SAshutosh Dixit 
587c8939848SAshutosh Dixit 	switch (attr) {
588c8939848SAshutosh Dixit 	case hwmon_curr_crit:
589c8939848SAshutosh Dixit 		ret = hwm_pcode_read_i1(ddat->uncore->i915, &uval);
590c8939848SAshutosh Dixit 		if (ret)
591c8939848SAshutosh Dixit 			return ret;
592c8939848SAshutosh Dixit 		if (uval & POWER_SETUP_I1_WATTS)
593c8939848SAshutosh Dixit 			return -ENODEV;
594c8939848SAshutosh Dixit 		*val = mul_u64_u32_shr(REG_FIELD_GET(POWER_SETUP_I1_DATA_MASK, uval),
595c8939848SAshutosh Dixit 				       SF_CURR, POWER_SETUP_I1_SHIFT);
596c8939848SAshutosh Dixit 		return 0;
597c8939848SAshutosh Dixit 	default:
598c8939848SAshutosh Dixit 		return -EOPNOTSUPP;
599c8939848SAshutosh Dixit 	}
600c8939848SAshutosh Dixit }
601c8939848SAshutosh Dixit 
602c8939848SAshutosh Dixit static int
603c8939848SAshutosh Dixit hwm_curr_write(struct hwm_drvdata *ddat, u32 attr, long val)
604c8939848SAshutosh Dixit {
605c8939848SAshutosh Dixit 	u32 uval;
606c8939848SAshutosh Dixit 
607c8939848SAshutosh Dixit 	switch (attr) {
608c8939848SAshutosh Dixit 	case hwmon_curr_crit:
609c8939848SAshutosh Dixit 		uval = DIV_ROUND_CLOSEST_ULL(val << POWER_SETUP_I1_SHIFT, SF_CURR);
610c8939848SAshutosh Dixit 		return hwm_pcode_write_i1(ddat->uncore->i915, uval);
611c8939848SAshutosh Dixit 	default:
612c8939848SAshutosh Dixit 		return -EOPNOTSUPP;
613c8939848SAshutosh Dixit 	}
614c8939848SAshutosh Dixit }
615c8939848SAshutosh Dixit 
616c8939848SAshutosh Dixit static umode_t
617b3b088e2SDale B Stimson hwm_is_visible(const void *drvdata, enum hwmon_sensor_types type,
618b3b088e2SDale B Stimson 	       u32 attr, int channel)
619b3b088e2SDale B Stimson {
620f8572bb6SRiana Tauro 	struct hwm_drvdata *ddat = (struct hwm_drvdata *)drvdata;
621f8572bb6SRiana Tauro 
622b3b088e2SDale B Stimson 	switch (type) {
623f8572bb6SRiana Tauro 	case hwmon_in:
624f8572bb6SRiana Tauro 		return hwm_in_is_visible(ddat, attr);
62599f55efbSDale B Stimson 	case hwmon_power:
62699f55efbSDale B Stimson 		return hwm_power_is_visible(ddat, attr, channel);
627c41b8bdcSDale B Stimson 	case hwmon_energy:
628c41b8bdcSDale B Stimson 		return hwm_energy_is_visible(ddat, attr);
629c8939848SAshutosh Dixit 	case hwmon_curr:
630c8939848SAshutosh Dixit 		return hwm_curr_is_visible(ddat, attr);
631b3b088e2SDale B Stimson 	default:
632b3b088e2SDale B Stimson 		return 0;
633b3b088e2SDale B Stimson 	}
634b3b088e2SDale B Stimson }
635b3b088e2SDale B Stimson 
636b3b088e2SDale B Stimson static int
637b3b088e2SDale B Stimson hwm_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
638b3b088e2SDale B Stimson 	 int channel, long *val)
639b3b088e2SDale B Stimson {
640f8572bb6SRiana Tauro 	struct hwm_drvdata *ddat = dev_get_drvdata(dev);
641f8572bb6SRiana Tauro 
642b3b088e2SDale B Stimson 	switch (type) {
643f8572bb6SRiana Tauro 	case hwmon_in:
644f8572bb6SRiana Tauro 		return hwm_in_read(ddat, attr, val);
64599f55efbSDale B Stimson 	case hwmon_power:
64699f55efbSDale B Stimson 		return hwm_power_read(ddat, attr, channel, val);
647c41b8bdcSDale B Stimson 	case hwmon_energy:
648c41b8bdcSDale B Stimson 		return hwm_energy_read(ddat, attr, val);
649c8939848SAshutosh Dixit 	case hwmon_curr:
650c8939848SAshutosh Dixit 		return hwm_curr_read(ddat, attr, val);
651b3b088e2SDale B Stimson 	default:
652b3b088e2SDale B Stimson 		return -EOPNOTSUPP;
653b3b088e2SDale B Stimson 	}
654b3b088e2SDale B Stimson }
655b3b088e2SDale B Stimson 
656b3b088e2SDale B Stimson static int
657b3b088e2SDale B Stimson hwm_write(struct device *dev, enum hwmon_sensor_types type, u32 attr,
658b3b088e2SDale B Stimson 	  int channel, long val)
659b3b088e2SDale B Stimson {
66099f55efbSDale B Stimson 	struct hwm_drvdata *ddat = dev_get_drvdata(dev);
66199f55efbSDale B Stimson 
662b3b088e2SDale B Stimson 	switch (type) {
66399f55efbSDale B Stimson 	case hwmon_power:
66499f55efbSDale B Stimson 		return hwm_power_write(ddat, attr, channel, val);
665c8939848SAshutosh Dixit 	case hwmon_curr:
666c8939848SAshutosh Dixit 		return hwm_curr_write(ddat, attr, val);
667b3b088e2SDale B Stimson 	default:
668b3b088e2SDale B Stimson 		return -EOPNOTSUPP;
669b3b088e2SDale B Stimson 	}
670b3b088e2SDale B Stimson }
671b3b088e2SDale B Stimson 
672b3b088e2SDale B Stimson static const struct hwmon_ops hwm_ops = {
673b3b088e2SDale B Stimson 	.is_visible = hwm_is_visible,
674b3b088e2SDale B Stimson 	.read = hwm_read,
675b3b088e2SDale B Stimson 	.write = hwm_write,
676b3b088e2SDale B Stimson };
677b3b088e2SDale B Stimson 
678b3b088e2SDale B Stimson static const struct hwmon_chip_info hwm_chip_info = {
679b3b088e2SDale B Stimson 	.ops = &hwm_ops,
680b3b088e2SDale B Stimson 	.info = hwm_info,
681b3b088e2SDale B Stimson };
682b3b088e2SDale B Stimson 
683a6a924abSDale B Stimson static umode_t
684a6a924abSDale B Stimson hwm_gt_is_visible(const void *drvdata, enum hwmon_sensor_types type,
685a6a924abSDale B Stimson 		  u32 attr, int channel)
686a6a924abSDale B Stimson {
687a6a924abSDale B Stimson 	struct hwm_drvdata *ddat = (struct hwm_drvdata *)drvdata;
688a6a924abSDale B Stimson 
689a6a924abSDale B Stimson 	switch (type) {
690a6a924abSDale B Stimson 	case hwmon_energy:
691a6a924abSDale B Stimson 		return hwm_energy_is_visible(ddat, attr);
692a6a924abSDale B Stimson 	default:
693a6a924abSDale B Stimson 		return 0;
694a6a924abSDale B Stimson 	}
695a6a924abSDale B Stimson }
696a6a924abSDale B Stimson 
697a6a924abSDale B Stimson static int
698a6a924abSDale B Stimson hwm_gt_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
699a6a924abSDale B Stimson 	    int channel, long *val)
700a6a924abSDale B Stimson {
701a6a924abSDale B Stimson 	struct hwm_drvdata *ddat = dev_get_drvdata(dev);
702a6a924abSDale B Stimson 
703a6a924abSDale B Stimson 	switch (type) {
704a6a924abSDale B Stimson 	case hwmon_energy:
705a6a924abSDale B Stimson 		return hwm_energy_read(ddat, attr, val);
706a6a924abSDale B Stimson 	default:
707a6a924abSDale B Stimson 		return -EOPNOTSUPP;
708a6a924abSDale B Stimson 	}
709a6a924abSDale B Stimson }
710a6a924abSDale B Stimson 
711a6a924abSDale B Stimson static const struct hwmon_ops hwm_gt_ops = {
712a6a924abSDale B Stimson 	.is_visible = hwm_gt_is_visible,
713a6a924abSDale B Stimson 	.read = hwm_gt_read,
714a6a924abSDale B Stimson };
715a6a924abSDale B Stimson 
716a6a924abSDale B Stimson static const struct hwmon_chip_info hwm_gt_chip_info = {
717a6a924abSDale B Stimson 	.ops = &hwm_gt_ops,
718a6a924abSDale B Stimson 	.info = hwm_gt_info,
719a6a924abSDale B Stimson };
720a6a924abSDale B Stimson 
721b3b088e2SDale B Stimson static void
722b3b088e2SDale B Stimson hwm_get_preregistration_info(struct drm_i915_private *i915)
723b3b088e2SDale B Stimson {
724f8572bb6SRiana Tauro 	struct i915_hwmon *hwmon = i915->hwmon;
72599f55efbSDale B Stimson 	struct intel_uncore *uncore = &i915->uncore;
726c41b8bdcSDale B Stimson 	struct hwm_drvdata *ddat = &hwmon->ddat;
72799f55efbSDale B Stimson 	intel_wakeref_t wakeref;
72899f55efbSDale B Stimson 	u32 val_sku_unit = 0;
729a6a924abSDale B Stimson 	struct intel_gt *gt;
730c41b8bdcSDale B Stimson 	long energy;
731a6a924abSDale B Stimson 	int i;
732f8572bb6SRiana Tauro 
733f8572bb6SRiana Tauro 	/* Available for all Gen12+/dGfx */
734f8572bb6SRiana Tauro 	hwmon->rg.gt_perf_status = GEN12_RPSTAT1;
73599f55efbSDale B Stimson 
73699f55efbSDale B Stimson 	if (IS_DG1(i915) || IS_DG2(i915)) {
73799f55efbSDale B Stimson 		hwmon->rg.pkg_power_sku_unit = PCU_PACKAGE_POWER_SKU_UNIT;
73899f55efbSDale B Stimson 		hwmon->rg.pkg_power_sku = PCU_PACKAGE_POWER_SKU;
73999f55efbSDale B Stimson 		hwmon->rg.pkg_rapl_limit = PCU_PACKAGE_RAPL_LIMIT;
740c41b8bdcSDale B Stimson 		hwmon->rg.energy_status_all = PCU_PACKAGE_ENERGY_STATUS;
741a6a924abSDale B Stimson 		hwmon->rg.energy_status_tile = INVALID_MMIO_REG;
74299f55efbSDale B Stimson 	} else {
74399f55efbSDale B Stimson 		hwmon->rg.pkg_power_sku_unit = INVALID_MMIO_REG;
74499f55efbSDale B Stimson 		hwmon->rg.pkg_power_sku = INVALID_MMIO_REG;
74599f55efbSDale B Stimson 		hwmon->rg.pkg_rapl_limit = INVALID_MMIO_REG;
746c41b8bdcSDale B Stimson 		hwmon->rg.energy_status_all = INVALID_MMIO_REG;
747a6a924abSDale B Stimson 		hwmon->rg.energy_status_tile = INVALID_MMIO_REG;
74899f55efbSDale B Stimson 	}
74999f55efbSDale B Stimson 
75099f55efbSDale B Stimson 	with_intel_runtime_pm(uncore->rpm, wakeref) {
75199f55efbSDale B Stimson 		/*
75299f55efbSDale B Stimson 		 * The contents of register hwmon->rg.pkg_power_sku_unit do not change,
75399f55efbSDale B Stimson 		 * so read it once and store the shift values.
75499f55efbSDale B Stimson 		 */
75599f55efbSDale B Stimson 		if (i915_mmio_reg_valid(hwmon->rg.pkg_power_sku_unit))
75699f55efbSDale B Stimson 			val_sku_unit = intel_uncore_read(uncore,
75799f55efbSDale B Stimson 							 hwmon->rg.pkg_power_sku_unit);
758c41b8bdcSDale B Stimson 	}
75999f55efbSDale B Stimson 
76099f55efbSDale B Stimson 	hwmon->scl_shift_power = REG_FIELD_GET(PKG_PWR_UNIT, val_sku_unit);
761c41b8bdcSDale B Stimson 	hwmon->scl_shift_energy = REG_FIELD_GET(PKG_ENERGY_UNIT, val_sku_unit);
7624c2572feSAshutosh Dixit 	hwmon->scl_shift_time = REG_FIELD_GET(PKG_TIME_UNIT, val_sku_unit);
763c41b8bdcSDale B Stimson 
764c41b8bdcSDale B Stimson 	/*
765c41b8bdcSDale B Stimson 	 * Initialize 'struct hwm_energy_info', i.e. set fields to the
766c41b8bdcSDale B Stimson 	 * first value of the energy register read
767c41b8bdcSDale B Stimson 	 */
768c41b8bdcSDale B Stimson 	if (i915_mmio_reg_valid(hwmon->rg.energy_status_all))
769c41b8bdcSDale B Stimson 		hwm_energy(ddat, &energy);
770a6a924abSDale B Stimson 	if (i915_mmio_reg_valid(hwmon->rg.energy_status_tile)) {
771a6a924abSDale B Stimson 		for_each_gt(gt, i915, i)
772a6a924abSDale B Stimson 			hwm_energy(&hwmon->ddat_gt[i], &energy);
773a6a924abSDale B Stimson 	}
774b3b088e2SDale B Stimson }
775b3b088e2SDale B Stimson 
776b3b088e2SDale B Stimson void i915_hwmon_register(struct drm_i915_private *i915)
777b3b088e2SDale B Stimson {
778b3b088e2SDale B Stimson 	struct device *dev = i915->drm.dev;
779b3b088e2SDale B Stimson 	struct i915_hwmon *hwmon;
780b3b088e2SDale B Stimson 	struct device *hwmon_dev;
781b3b088e2SDale B Stimson 	struct hwm_drvdata *ddat;
782a6a924abSDale B Stimson 	struct hwm_drvdata *ddat_gt;
783a6a924abSDale B Stimson 	struct intel_gt *gt;
784a6a924abSDale B Stimson 	int i;
785b3b088e2SDale B Stimson 
786b3b088e2SDale B Stimson 	/* hwmon is available only for dGfx */
787b3b088e2SDale B Stimson 	if (!IS_DGFX(i915))
788b3b088e2SDale B Stimson 		return;
789b3b088e2SDale B Stimson 
790*5bc9de06SAshutosh Dixit 	hwmon = kzalloc(sizeof(*hwmon), GFP_KERNEL);
791b3b088e2SDale B Stimson 	if (!hwmon)
792b3b088e2SDale B Stimson 		return;
793b3b088e2SDale B Stimson 
794b3b088e2SDale B Stimson 	i915->hwmon = hwmon;
795b3b088e2SDale B Stimson 	mutex_init(&hwmon->hwmon_lock);
796b3b088e2SDale B Stimson 	ddat = &hwmon->ddat;
797b3b088e2SDale B Stimson 
798b3b088e2SDale B Stimson 	ddat->hwmon = hwmon;
799b3b088e2SDale B Stimson 	ddat->uncore = &i915->uncore;
800b3b088e2SDale B Stimson 	snprintf(ddat->name, sizeof(ddat->name), "i915");
801a6a924abSDale B Stimson 	ddat->gt_n = -1;
802655bd3b9SAshutosh Dixit 	init_waitqueue_head(&ddat->waitq);
803a6a924abSDale B Stimson 
804a6a924abSDale B Stimson 	for_each_gt(gt, i915, i) {
805a6a924abSDale B Stimson 		ddat_gt = hwmon->ddat_gt + i;
806a6a924abSDale B Stimson 
807a6a924abSDale B Stimson 		ddat_gt->hwmon = hwmon;
808a6a924abSDale B Stimson 		ddat_gt->uncore = gt->uncore;
809a6a924abSDale B Stimson 		snprintf(ddat_gt->name, sizeof(ddat_gt->name), "i915_gt%u", i);
810a6a924abSDale B Stimson 		ddat_gt->gt_n = i;
811a6a924abSDale B Stimson 	}
812b3b088e2SDale B Stimson 
813b3b088e2SDale B Stimson 	hwm_get_preregistration_info(i915);
814b3b088e2SDale B Stimson 
815b3b088e2SDale B Stimson 	/*  hwmon_dev points to device hwmon<i> */
816*5bc9de06SAshutosh Dixit 	hwmon_dev = hwmon_device_register_with_info(dev, ddat->name,
817b3b088e2SDale B Stimson 						    ddat,
818b3b088e2SDale B Stimson 						    &hwm_chip_info,
8194c2572feSAshutosh Dixit 						    hwm_groups);
820*5bc9de06SAshutosh Dixit 	if (IS_ERR(hwmon_dev))
821*5bc9de06SAshutosh Dixit 		goto err;
822b3b088e2SDale B Stimson 
823b3b088e2SDale B Stimson 	ddat->hwmon_dev = hwmon_dev;
824a6a924abSDale B Stimson 
825a6a924abSDale B Stimson 	for_each_gt(gt, i915, i) {
826a6a924abSDale B Stimson 		ddat_gt = hwmon->ddat_gt + i;
827a6a924abSDale B Stimson 		/*
828a6a924abSDale B Stimson 		 * Create per-gt directories only if a per-gt attribute is
829a6a924abSDale B Stimson 		 * visible. Currently this is only energy
830a6a924abSDale B Stimson 		 */
831a6a924abSDale B Stimson 		if (!hwm_gt_is_visible(ddat_gt, hwmon_energy, hwmon_energy_input, 0))
832a6a924abSDale B Stimson 			continue;
833a6a924abSDale B Stimson 
834*5bc9de06SAshutosh Dixit 		hwmon_dev = hwmon_device_register_with_info(dev, ddat_gt->name,
835a6a924abSDale B Stimson 							    ddat_gt,
836a6a924abSDale B Stimson 							    &hwm_gt_chip_info,
837a6a924abSDale B Stimson 							    NULL);
838a6a924abSDale B Stimson 		if (!IS_ERR(hwmon_dev))
839a6a924abSDale B Stimson 			ddat_gt->hwmon_dev = hwmon_dev;
840a6a924abSDale B Stimson 	}
841*5bc9de06SAshutosh Dixit 	return;
842*5bc9de06SAshutosh Dixit err:
843*5bc9de06SAshutosh Dixit 	i915_hwmon_unregister(i915);
844b3b088e2SDale B Stimson }
845b3b088e2SDale B Stimson 
846b3b088e2SDale B Stimson void i915_hwmon_unregister(struct drm_i915_private *i915)
847b3b088e2SDale B Stimson {
848*5bc9de06SAshutosh Dixit 	struct i915_hwmon *hwmon = i915->hwmon;
849*5bc9de06SAshutosh Dixit 	struct intel_gt *gt;
850*5bc9de06SAshutosh Dixit 	int i;
851*5bc9de06SAshutosh Dixit 
852*5bc9de06SAshutosh Dixit 	if (!hwmon)
853*5bc9de06SAshutosh Dixit 		return;
854*5bc9de06SAshutosh Dixit 
855*5bc9de06SAshutosh Dixit 	for_each_gt(gt, i915, i)
856*5bc9de06SAshutosh Dixit 		if (hwmon->ddat_gt[i].hwmon_dev)
857*5bc9de06SAshutosh Dixit 			hwmon_device_unregister(hwmon->ddat_gt[i].hwmon_dev);
858*5bc9de06SAshutosh Dixit 
859*5bc9de06SAshutosh Dixit 	if (hwmon->ddat.hwmon_dev)
860*5bc9de06SAshutosh Dixit 		hwmon_device_unregister(hwmon->ddat.hwmon_dev);
861*5bc9de06SAshutosh Dixit 
862*5bc9de06SAshutosh Dixit 	mutex_destroy(&hwmon->hwmon_lock);
863*5bc9de06SAshutosh Dixit 
864*5bc9de06SAshutosh Dixit 	kfree(i915->hwmon);
865*5bc9de06SAshutosh Dixit 	i915->hwmon = NULL;
866b3b088e2SDale B Stimson }
867