162306a36Sopenharmony_ci// SPDX-License-Identifier: MIT 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright © 2022 Intel Corporation 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <linux/hwmon.h> 762306a36Sopenharmony_ci#include <linux/hwmon-sysfs.h> 862306a36Sopenharmony_ci#include <linux/types.h> 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include "i915_drv.h" 1162306a36Sopenharmony_ci#include "i915_hwmon.h" 1262306a36Sopenharmony_ci#include "i915_reg.h" 1362306a36Sopenharmony_ci#include "intel_mchbar_regs.h" 1462306a36Sopenharmony_ci#include "intel_pcode.h" 1562306a36Sopenharmony_ci#include "gt/intel_gt.h" 1662306a36Sopenharmony_ci#include "gt/intel_gt_regs.h" 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci/* 1962306a36Sopenharmony_ci * SF_* - scale factors for particular quantities according to hwmon spec. 2062306a36Sopenharmony_ci * - voltage - millivolts 2162306a36Sopenharmony_ci * - power - microwatts 2262306a36Sopenharmony_ci * - curr - milliamperes 2362306a36Sopenharmony_ci * - energy - microjoules 2462306a36Sopenharmony_ci * - time - milliseconds 2562306a36Sopenharmony_ci */ 2662306a36Sopenharmony_ci#define SF_VOLTAGE 1000 2762306a36Sopenharmony_ci#define SF_POWER 1000000 2862306a36Sopenharmony_ci#define SF_CURR 1000 2962306a36Sopenharmony_ci#define SF_ENERGY 1000000 3062306a36Sopenharmony_ci#define SF_TIME 1000 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_cistruct hwm_reg { 3362306a36Sopenharmony_ci i915_reg_t gt_perf_status; 3462306a36Sopenharmony_ci i915_reg_t pkg_power_sku_unit; 3562306a36Sopenharmony_ci i915_reg_t pkg_power_sku; 3662306a36Sopenharmony_ci i915_reg_t pkg_rapl_limit; 3762306a36Sopenharmony_ci i915_reg_t energy_status_all; 3862306a36Sopenharmony_ci i915_reg_t energy_status_tile; 3962306a36Sopenharmony_ci}; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_cistruct hwm_energy_info { 4262306a36Sopenharmony_ci u32 reg_val_prev; 4362306a36Sopenharmony_ci long accum_energy; /* Accumulated energy for energy1_input */ 4462306a36Sopenharmony_ci}; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cistruct hwm_drvdata { 4762306a36Sopenharmony_ci struct i915_hwmon *hwmon; 4862306a36Sopenharmony_ci struct intel_uncore *uncore; 4962306a36Sopenharmony_ci struct device *hwmon_dev; 5062306a36Sopenharmony_ci struct hwm_energy_info ei; /* Energy info for energy1_input */ 5162306a36Sopenharmony_ci char name[12]; 5262306a36Sopenharmony_ci int gt_n; 5362306a36Sopenharmony_ci bool reset_in_progress; 5462306a36Sopenharmony_ci wait_queue_head_t waitq; 5562306a36Sopenharmony_ci}; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_cistruct i915_hwmon { 5862306a36Sopenharmony_ci struct hwm_drvdata ddat; 5962306a36Sopenharmony_ci struct hwm_drvdata ddat_gt[I915_MAX_GT]; 6062306a36Sopenharmony_ci struct mutex hwmon_lock; /* counter overflow logic and rmw */ 6162306a36Sopenharmony_ci struct hwm_reg rg; 6262306a36Sopenharmony_ci int scl_shift_power; 6362306a36Sopenharmony_ci int scl_shift_energy; 6462306a36Sopenharmony_ci int scl_shift_time; 6562306a36Sopenharmony_ci}; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_cistatic void 6862306a36Sopenharmony_cihwm_locked_with_pm_intel_uncore_rmw(struct hwm_drvdata *ddat, 6962306a36Sopenharmony_ci i915_reg_t reg, u32 clear, u32 set) 7062306a36Sopenharmony_ci{ 7162306a36Sopenharmony_ci struct i915_hwmon *hwmon = ddat->hwmon; 7262306a36Sopenharmony_ci struct intel_uncore *uncore = ddat->uncore; 7362306a36Sopenharmony_ci intel_wakeref_t wakeref; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci mutex_lock(&hwmon->hwmon_lock); 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci with_intel_runtime_pm(uncore->rpm, wakeref) 7862306a36Sopenharmony_ci intel_uncore_rmw(uncore, reg, clear, set); 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci mutex_unlock(&hwmon->hwmon_lock); 8162306a36Sopenharmony_ci} 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci/* 8462306a36Sopenharmony_ci * This function's return type of u64 allows for the case where the scaling 8562306a36Sopenharmony_ci * of the field taken from the 32-bit register value might cause a result to 8662306a36Sopenharmony_ci * exceed 32 bits. 8762306a36Sopenharmony_ci */ 8862306a36Sopenharmony_cistatic u64 8962306a36Sopenharmony_cihwm_field_read_and_scale(struct hwm_drvdata *ddat, i915_reg_t rgadr, 9062306a36Sopenharmony_ci u32 field_msk, int nshift, u32 scale_factor) 9162306a36Sopenharmony_ci{ 9262306a36Sopenharmony_ci struct intel_uncore *uncore = ddat->uncore; 9362306a36Sopenharmony_ci intel_wakeref_t wakeref; 9462306a36Sopenharmony_ci u32 reg_value; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci with_intel_runtime_pm(uncore->rpm, wakeref) 9762306a36Sopenharmony_ci reg_value = intel_uncore_read(uncore, rgadr); 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci reg_value = REG_FIELD_GET(field_msk, reg_value); 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci return mul_u64_u32_shr(reg_value, scale_factor, nshift); 10262306a36Sopenharmony_ci} 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci/* 10562306a36Sopenharmony_ci * hwm_energy - Obtain energy value 10662306a36Sopenharmony_ci * 10762306a36Sopenharmony_ci * The underlying energy hardware register is 32-bits and is subject to 10862306a36Sopenharmony_ci * overflow. How long before overflow? For example, with an example 10962306a36Sopenharmony_ci * scaling bit shift of 14 bits (see register *PACKAGE_POWER_SKU_UNIT) and 11062306a36Sopenharmony_ci * a power draw of 1000 watts, the 32-bit counter will overflow in 11162306a36Sopenharmony_ci * approximately 4.36 minutes. 11262306a36Sopenharmony_ci * 11362306a36Sopenharmony_ci * Examples: 11462306a36Sopenharmony_ci * 1 watt: (2^32 >> 14) / 1 W / (60 * 60 * 24) secs/day -> 3 days 11562306a36Sopenharmony_ci * 1000 watts: (2^32 >> 14) / 1000 W / 60 secs/min -> 4.36 minutes 11662306a36Sopenharmony_ci * 11762306a36Sopenharmony_ci * The function significantly increases overflow duration (from 4.36 11862306a36Sopenharmony_ci * minutes) by accumulating the energy register into a 'long' as allowed by 11962306a36Sopenharmony_ci * the hwmon API. Using x86_64 128 bit arithmetic (see mul_u64_u32_shr()), 12062306a36Sopenharmony_ci * a 'long' of 63 bits, SF_ENERGY of 1e6 (~20 bits) and 12162306a36Sopenharmony_ci * hwmon->scl_shift_energy of 14 bits we have 57 (63 - 20 + 14) bits before 12262306a36Sopenharmony_ci * energy1_input overflows. This at 1000 W is an overflow duration of 278 years. 12362306a36Sopenharmony_ci */ 12462306a36Sopenharmony_cistatic void 12562306a36Sopenharmony_cihwm_energy(struct hwm_drvdata *ddat, long *energy) 12662306a36Sopenharmony_ci{ 12762306a36Sopenharmony_ci struct intel_uncore *uncore = ddat->uncore; 12862306a36Sopenharmony_ci struct i915_hwmon *hwmon = ddat->hwmon; 12962306a36Sopenharmony_ci struct hwm_energy_info *ei = &ddat->ei; 13062306a36Sopenharmony_ci intel_wakeref_t wakeref; 13162306a36Sopenharmony_ci i915_reg_t rgaddr; 13262306a36Sopenharmony_ci u32 reg_val; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci if (ddat->gt_n >= 0) 13562306a36Sopenharmony_ci rgaddr = hwmon->rg.energy_status_tile; 13662306a36Sopenharmony_ci else 13762306a36Sopenharmony_ci rgaddr = hwmon->rg.energy_status_all; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci mutex_lock(&hwmon->hwmon_lock); 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci with_intel_runtime_pm(uncore->rpm, wakeref) 14262306a36Sopenharmony_ci reg_val = intel_uncore_read(uncore, rgaddr); 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci if (reg_val >= ei->reg_val_prev) 14562306a36Sopenharmony_ci ei->accum_energy += reg_val - ei->reg_val_prev; 14662306a36Sopenharmony_ci else 14762306a36Sopenharmony_ci ei->accum_energy += UINT_MAX - ei->reg_val_prev + reg_val; 14862306a36Sopenharmony_ci ei->reg_val_prev = reg_val; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci *energy = mul_u64_u32_shr(ei->accum_energy, SF_ENERGY, 15162306a36Sopenharmony_ci hwmon->scl_shift_energy); 15262306a36Sopenharmony_ci mutex_unlock(&hwmon->hwmon_lock); 15362306a36Sopenharmony_ci} 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_cistatic ssize_t 15662306a36Sopenharmony_cihwm_power1_max_interval_show(struct device *dev, struct device_attribute *attr, 15762306a36Sopenharmony_ci char *buf) 15862306a36Sopenharmony_ci{ 15962306a36Sopenharmony_ci struct hwm_drvdata *ddat = dev_get_drvdata(dev); 16062306a36Sopenharmony_ci struct i915_hwmon *hwmon = ddat->hwmon; 16162306a36Sopenharmony_ci intel_wakeref_t wakeref; 16262306a36Sopenharmony_ci u32 r, x, y, x_w = 2; /* 2 bits */ 16362306a36Sopenharmony_ci u64 tau4, out; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci with_intel_runtime_pm(ddat->uncore->rpm, wakeref) 16662306a36Sopenharmony_ci r = intel_uncore_read(ddat->uncore, hwmon->rg.pkg_rapl_limit); 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci x = REG_FIELD_GET(PKG_PWR_LIM_1_TIME_X, r); 16962306a36Sopenharmony_ci y = REG_FIELD_GET(PKG_PWR_LIM_1_TIME_Y, r); 17062306a36Sopenharmony_ci /* 17162306a36Sopenharmony_ci * tau = 1.x * power(2,y), x = bits(23:22), y = bits(21:17) 17262306a36Sopenharmony_ci * = (4 | x) << (y - 2) 17362306a36Sopenharmony_ci * where (y - 2) ensures a 1.x fixed point representation of 1.x 17462306a36Sopenharmony_ci * However because y can be < 2, we compute 17562306a36Sopenharmony_ci * tau4 = (4 | x) << y 17662306a36Sopenharmony_ci * but add 2 when doing the final right shift to account for units 17762306a36Sopenharmony_ci */ 17862306a36Sopenharmony_ci tau4 = (u64)((1 << x_w) | x) << y; 17962306a36Sopenharmony_ci /* val in hwmon interface units (millisec) */ 18062306a36Sopenharmony_ci out = mul_u64_u32_shr(tau4, SF_TIME, hwmon->scl_shift_time + x_w); 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci return sysfs_emit(buf, "%llu\n", out); 18362306a36Sopenharmony_ci} 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_cistatic ssize_t 18662306a36Sopenharmony_cihwm_power1_max_interval_store(struct device *dev, 18762306a36Sopenharmony_ci struct device_attribute *attr, 18862306a36Sopenharmony_ci const char *buf, size_t count) 18962306a36Sopenharmony_ci{ 19062306a36Sopenharmony_ci struct hwm_drvdata *ddat = dev_get_drvdata(dev); 19162306a36Sopenharmony_ci struct i915_hwmon *hwmon = ddat->hwmon; 19262306a36Sopenharmony_ci u32 x, y, rxy, x_w = 2; /* 2 bits */ 19362306a36Sopenharmony_ci u64 tau4, r, max_win; 19462306a36Sopenharmony_ci unsigned long val; 19562306a36Sopenharmony_ci int ret; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci ret = kstrtoul(buf, 0, &val); 19862306a36Sopenharmony_ci if (ret) 19962306a36Sopenharmony_ci return ret; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci /* 20262306a36Sopenharmony_ci * Max HW supported tau in '1.x * power(2,y)' format, x = 0, y = 0x12 20362306a36Sopenharmony_ci * The hwmon->scl_shift_time default of 0xa results in a max tau of 256 seconds 20462306a36Sopenharmony_ci */ 20562306a36Sopenharmony_ci#define PKG_MAX_WIN_DEFAULT 0x12ull 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci /* 20862306a36Sopenharmony_ci * val must be < max in hwmon interface units. The steps below are 20962306a36Sopenharmony_ci * explained in i915_power1_max_interval_show() 21062306a36Sopenharmony_ci */ 21162306a36Sopenharmony_ci r = FIELD_PREP(PKG_MAX_WIN, PKG_MAX_WIN_DEFAULT); 21262306a36Sopenharmony_ci x = REG_FIELD_GET(PKG_MAX_WIN_X, r); 21362306a36Sopenharmony_ci y = REG_FIELD_GET(PKG_MAX_WIN_Y, r); 21462306a36Sopenharmony_ci tau4 = (u64)((1 << x_w) | x) << y; 21562306a36Sopenharmony_ci max_win = mul_u64_u32_shr(tau4, SF_TIME, hwmon->scl_shift_time + x_w); 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci if (val > max_win) 21862306a36Sopenharmony_ci return -EINVAL; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci /* val in hw units */ 22162306a36Sopenharmony_ci val = DIV_ROUND_CLOSEST_ULL((u64)val << hwmon->scl_shift_time, SF_TIME); 22262306a36Sopenharmony_ci /* Convert to 1.x * power(2,y) */ 22362306a36Sopenharmony_ci if (!val) { 22462306a36Sopenharmony_ci /* Avoid ilog2(0) */ 22562306a36Sopenharmony_ci y = 0; 22662306a36Sopenharmony_ci x = 0; 22762306a36Sopenharmony_ci } else { 22862306a36Sopenharmony_ci y = ilog2(val); 22962306a36Sopenharmony_ci /* x = (val - (1 << y)) >> (y - 2); */ 23062306a36Sopenharmony_ci x = (val - (1ul << y)) << x_w >> y; 23162306a36Sopenharmony_ci } 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci rxy = REG_FIELD_PREP(PKG_PWR_LIM_1_TIME_X, x) | REG_FIELD_PREP(PKG_PWR_LIM_1_TIME_Y, y); 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci hwm_locked_with_pm_intel_uncore_rmw(ddat, hwmon->rg.pkg_rapl_limit, 23662306a36Sopenharmony_ci PKG_PWR_LIM_1_TIME, rxy); 23762306a36Sopenharmony_ci return count; 23862306a36Sopenharmony_ci} 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(power1_max_interval, 0664, 24162306a36Sopenharmony_ci hwm_power1_max_interval_show, 24262306a36Sopenharmony_ci hwm_power1_max_interval_store, 0); 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_cistatic struct attribute *hwm_attributes[] = { 24562306a36Sopenharmony_ci &sensor_dev_attr_power1_max_interval.dev_attr.attr, 24662306a36Sopenharmony_ci NULL 24762306a36Sopenharmony_ci}; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_cistatic umode_t hwm_attributes_visible(struct kobject *kobj, 25062306a36Sopenharmony_ci struct attribute *attr, int index) 25162306a36Sopenharmony_ci{ 25262306a36Sopenharmony_ci struct device *dev = kobj_to_dev(kobj); 25362306a36Sopenharmony_ci struct hwm_drvdata *ddat = dev_get_drvdata(dev); 25462306a36Sopenharmony_ci struct i915_hwmon *hwmon = ddat->hwmon; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci if (attr == &sensor_dev_attr_power1_max_interval.dev_attr.attr) 25762306a36Sopenharmony_ci return i915_mmio_reg_valid(hwmon->rg.pkg_rapl_limit) ? attr->mode : 0; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci return 0; 26062306a36Sopenharmony_ci} 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_cistatic const struct attribute_group hwm_attrgroup = { 26362306a36Sopenharmony_ci .attrs = hwm_attributes, 26462306a36Sopenharmony_ci .is_visible = hwm_attributes_visible, 26562306a36Sopenharmony_ci}; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_cistatic const struct attribute_group *hwm_groups[] = { 26862306a36Sopenharmony_ci &hwm_attrgroup, 26962306a36Sopenharmony_ci NULL 27062306a36Sopenharmony_ci}; 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_cistatic const struct hwmon_channel_info * const hwm_info[] = { 27362306a36Sopenharmony_ci HWMON_CHANNEL_INFO(in, HWMON_I_INPUT), 27462306a36Sopenharmony_ci HWMON_CHANNEL_INFO(power, HWMON_P_MAX | HWMON_P_RATED_MAX | HWMON_P_CRIT), 27562306a36Sopenharmony_ci HWMON_CHANNEL_INFO(energy, HWMON_E_INPUT), 27662306a36Sopenharmony_ci HWMON_CHANNEL_INFO(curr, HWMON_C_CRIT), 27762306a36Sopenharmony_ci NULL 27862306a36Sopenharmony_ci}; 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_cistatic const struct hwmon_channel_info * const hwm_gt_info[] = { 28162306a36Sopenharmony_ci HWMON_CHANNEL_INFO(energy, HWMON_E_INPUT), 28262306a36Sopenharmony_ci NULL 28362306a36Sopenharmony_ci}; 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci/* I1 is exposed as power_crit or as curr_crit depending on bit 31 */ 28662306a36Sopenharmony_cistatic int hwm_pcode_read_i1(struct drm_i915_private *i915, u32 *uval) 28762306a36Sopenharmony_ci{ 28862306a36Sopenharmony_ci /* Avoid ILLEGAL_SUBCOMMAND "mailbox access failed" warning in snb_pcode_read */ 28962306a36Sopenharmony_ci if (IS_DG1(i915) || IS_DG2(i915)) 29062306a36Sopenharmony_ci return -ENXIO; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci return snb_pcode_read_p(&i915->uncore, PCODE_POWER_SETUP, 29362306a36Sopenharmony_ci POWER_SETUP_SUBCOMMAND_READ_I1, 0, uval); 29462306a36Sopenharmony_ci} 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_cistatic int hwm_pcode_write_i1(struct drm_i915_private *i915, u32 uval) 29762306a36Sopenharmony_ci{ 29862306a36Sopenharmony_ci return snb_pcode_write_p(&i915->uncore, PCODE_POWER_SETUP, 29962306a36Sopenharmony_ci POWER_SETUP_SUBCOMMAND_WRITE_I1, 0, uval); 30062306a36Sopenharmony_ci} 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_cistatic umode_t 30362306a36Sopenharmony_cihwm_in_is_visible(const struct hwm_drvdata *ddat, u32 attr) 30462306a36Sopenharmony_ci{ 30562306a36Sopenharmony_ci struct drm_i915_private *i915 = ddat->uncore->i915; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci switch (attr) { 30862306a36Sopenharmony_ci case hwmon_in_input: 30962306a36Sopenharmony_ci return IS_DG1(i915) || IS_DG2(i915) ? 0444 : 0; 31062306a36Sopenharmony_ci default: 31162306a36Sopenharmony_ci return 0; 31262306a36Sopenharmony_ci } 31362306a36Sopenharmony_ci} 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_cistatic int 31662306a36Sopenharmony_cihwm_in_read(struct hwm_drvdata *ddat, u32 attr, long *val) 31762306a36Sopenharmony_ci{ 31862306a36Sopenharmony_ci struct i915_hwmon *hwmon = ddat->hwmon; 31962306a36Sopenharmony_ci intel_wakeref_t wakeref; 32062306a36Sopenharmony_ci u32 reg_value; 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci switch (attr) { 32362306a36Sopenharmony_ci case hwmon_in_input: 32462306a36Sopenharmony_ci with_intel_runtime_pm(ddat->uncore->rpm, wakeref) 32562306a36Sopenharmony_ci reg_value = intel_uncore_read(ddat->uncore, hwmon->rg.gt_perf_status); 32662306a36Sopenharmony_ci /* HW register value in units of 2.5 millivolt */ 32762306a36Sopenharmony_ci *val = DIV_ROUND_CLOSEST(REG_FIELD_GET(GEN12_VOLTAGE_MASK, reg_value) * 25, 10); 32862306a36Sopenharmony_ci return 0; 32962306a36Sopenharmony_ci default: 33062306a36Sopenharmony_ci return -EOPNOTSUPP; 33162306a36Sopenharmony_ci } 33262306a36Sopenharmony_ci} 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_cistatic umode_t 33562306a36Sopenharmony_cihwm_power_is_visible(const struct hwm_drvdata *ddat, u32 attr, int chan) 33662306a36Sopenharmony_ci{ 33762306a36Sopenharmony_ci struct drm_i915_private *i915 = ddat->uncore->i915; 33862306a36Sopenharmony_ci struct i915_hwmon *hwmon = ddat->hwmon; 33962306a36Sopenharmony_ci u32 uval; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci switch (attr) { 34262306a36Sopenharmony_ci case hwmon_power_max: 34362306a36Sopenharmony_ci return i915_mmio_reg_valid(hwmon->rg.pkg_rapl_limit) ? 0664 : 0; 34462306a36Sopenharmony_ci case hwmon_power_rated_max: 34562306a36Sopenharmony_ci return i915_mmio_reg_valid(hwmon->rg.pkg_power_sku) ? 0444 : 0; 34662306a36Sopenharmony_ci case hwmon_power_crit: 34762306a36Sopenharmony_ci return (hwm_pcode_read_i1(i915, &uval) || 34862306a36Sopenharmony_ci !(uval & POWER_SETUP_I1_WATTS)) ? 0 : 0644; 34962306a36Sopenharmony_ci default: 35062306a36Sopenharmony_ci return 0; 35162306a36Sopenharmony_ci } 35262306a36Sopenharmony_ci} 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci#define PL1_DISABLE 0 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci/* 35762306a36Sopenharmony_ci * HW allows arbitrary PL1 limits to be set but silently clamps these values to 35862306a36Sopenharmony_ci * "typical but not guaranteed" min/max values in rg.pkg_power_sku. Follow the 35962306a36Sopenharmony_ci * same pattern for sysfs, allow arbitrary PL1 limits to be set but display 36062306a36Sopenharmony_ci * clamped values when read. Write/read I1 also follows the same pattern. 36162306a36Sopenharmony_ci */ 36262306a36Sopenharmony_cistatic int 36362306a36Sopenharmony_cihwm_power_max_read(struct hwm_drvdata *ddat, long *val) 36462306a36Sopenharmony_ci{ 36562306a36Sopenharmony_ci struct i915_hwmon *hwmon = ddat->hwmon; 36662306a36Sopenharmony_ci intel_wakeref_t wakeref; 36762306a36Sopenharmony_ci u64 r, min, max; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci /* Check if PL1 limit is disabled */ 37062306a36Sopenharmony_ci with_intel_runtime_pm(ddat->uncore->rpm, wakeref) 37162306a36Sopenharmony_ci r = intel_uncore_read(ddat->uncore, hwmon->rg.pkg_rapl_limit); 37262306a36Sopenharmony_ci if (!(r & PKG_PWR_LIM_1_EN)) { 37362306a36Sopenharmony_ci *val = PL1_DISABLE; 37462306a36Sopenharmony_ci return 0; 37562306a36Sopenharmony_ci } 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci *val = hwm_field_read_and_scale(ddat, 37862306a36Sopenharmony_ci hwmon->rg.pkg_rapl_limit, 37962306a36Sopenharmony_ci PKG_PWR_LIM_1, 38062306a36Sopenharmony_ci hwmon->scl_shift_power, 38162306a36Sopenharmony_ci SF_POWER); 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci with_intel_runtime_pm(ddat->uncore->rpm, wakeref) 38462306a36Sopenharmony_ci r = intel_uncore_read64(ddat->uncore, hwmon->rg.pkg_power_sku); 38562306a36Sopenharmony_ci min = REG_FIELD_GET(PKG_MIN_PWR, r); 38662306a36Sopenharmony_ci min = mul_u64_u32_shr(min, SF_POWER, hwmon->scl_shift_power); 38762306a36Sopenharmony_ci max = REG_FIELD_GET(PKG_MAX_PWR, r); 38862306a36Sopenharmony_ci max = mul_u64_u32_shr(max, SF_POWER, hwmon->scl_shift_power); 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci if (min && max) 39162306a36Sopenharmony_ci *val = clamp_t(u64, *val, min, max); 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci return 0; 39462306a36Sopenharmony_ci} 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_cistatic int 39762306a36Sopenharmony_cihwm_power_max_write(struct hwm_drvdata *ddat, long val) 39862306a36Sopenharmony_ci{ 39962306a36Sopenharmony_ci struct i915_hwmon *hwmon = ddat->hwmon; 40062306a36Sopenharmony_ci intel_wakeref_t wakeref; 40162306a36Sopenharmony_ci DEFINE_WAIT(wait); 40262306a36Sopenharmony_ci int ret = 0; 40362306a36Sopenharmony_ci u32 nval; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci /* Block waiting for GuC reset to complete when needed */ 40662306a36Sopenharmony_ci for (;;) { 40762306a36Sopenharmony_ci mutex_lock(&hwmon->hwmon_lock); 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci prepare_to_wait(&ddat->waitq, &wait, TASK_INTERRUPTIBLE); 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci if (!hwmon->ddat.reset_in_progress) 41262306a36Sopenharmony_ci break; 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci if (signal_pending(current)) { 41562306a36Sopenharmony_ci ret = -EINTR; 41662306a36Sopenharmony_ci break; 41762306a36Sopenharmony_ci } 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci mutex_unlock(&hwmon->hwmon_lock); 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci schedule(); 42262306a36Sopenharmony_ci } 42362306a36Sopenharmony_ci finish_wait(&ddat->waitq, &wait); 42462306a36Sopenharmony_ci if (ret) 42562306a36Sopenharmony_ci goto unlock; 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci wakeref = intel_runtime_pm_get(ddat->uncore->rpm); 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci /* Disable PL1 limit and verify, because the limit cannot be disabled on all platforms */ 43062306a36Sopenharmony_ci if (val == PL1_DISABLE) { 43162306a36Sopenharmony_ci intel_uncore_rmw(ddat->uncore, hwmon->rg.pkg_rapl_limit, 43262306a36Sopenharmony_ci PKG_PWR_LIM_1_EN, 0); 43362306a36Sopenharmony_ci nval = intel_uncore_read(ddat->uncore, hwmon->rg.pkg_rapl_limit); 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci if (nval & PKG_PWR_LIM_1_EN) 43662306a36Sopenharmony_ci ret = -ENODEV; 43762306a36Sopenharmony_ci goto exit; 43862306a36Sopenharmony_ci } 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci /* Computation in 64-bits to avoid overflow. Round to nearest. */ 44162306a36Sopenharmony_ci nval = DIV_ROUND_CLOSEST_ULL((u64)val << hwmon->scl_shift_power, SF_POWER); 44262306a36Sopenharmony_ci nval = PKG_PWR_LIM_1_EN | REG_FIELD_PREP(PKG_PWR_LIM_1, nval); 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci intel_uncore_rmw(ddat->uncore, hwmon->rg.pkg_rapl_limit, 44562306a36Sopenharmony_ci PKG_PWR_LIM_1_EN | PKG_PWR_LIM_1, nval); 44662306a36Sopenharmony_ciexit: 44762306a36Sopenharmony_ci intel_runtime_pm_put(ddat->uncore->rpm, wakeref); 44862306a36Sopenharmony_ciunlock: 44962306a36Sopenharmony_ci mutex_unlock(&hwmon->hwmon_lock); 45062306a36Sopenharmony_ci return ret; 45162306a36Sopenharmony_ci} 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_cistatic int 45462306a36Sopenharmony_cihwm_power_read(struct hwm_drvdata *ddat, u32 attr, int chan, long *val) 45562306a36Sopenharmony_ci{ 45662306a36Sopenharmony_ci struct i915_hwmon *hwmon = ddat->hwmon; 45762306a36Sopenharmony_ci int ret; 45862306a36Sopenharmony_ci u32 uval; 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci switch (attr) { 46162306a36Sopenharmony_ci case hwmon_power_max: 46262306a36Sopenharmony_ci return hwm_power_max_read(ddat, val); 46362306a36Sopenharmony_ci case hwmon_power_rated_max: 46462306a36Sopenharmony_ci *val = hwm_field_read_and_scale(ddat, 46562306a36Sopenharmony_ci hwmon->rg.pkg_power_sku, 46662306a36Sopenharmony_ci PKG_PKG_TDP, 46762306a36Sopenharmony_ci hwmon->scl_shift_power, 46862306a36Sopenharmony_ci SF_POWER); 46962306a36Sopenharmony_ci return 0; 47062306a36Sopenharmony_ci case hwmon_power_crit: 47162306a36Sopenharmony_ci ret = hwm_pcode_read_i1(ddat->uncore->i915, &uval); 47262306a36Sopenharmony_ci if (ret) 47362306a36Sopenharmony_ci return ret; 47462306a36Sopenharmony_ci if (!(uval & POWER_SETUP_I1_WATTS)) 47562306a36Sopenharmony_ci return -ENODEV; 47662306a36Sopenharmony_ci *val = mul_u64_u32_shr(REG_FIELD_GET(POWER_SETUP_I1_DATA_MASK, uval), 47762306a36Sopenharmony_ci SF_POWER, POWER_SETUP_I1_SHIFT); 47862306a36Sopenharmony_ci return 0; 47962306a36Sopenharmony_ci default: 48062306a36Sopenharmony_ci return -EOPNOTSUPP; 48162306a36Sopenharmony_ci } 48262306a36Sopenharmony_ci} 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_cistatic int 48562306a36Sopenharmony_cihwm_power_write(struct hwm_drvdata *ddat, u32 attr, int chan, long val) 48662306a36Sopenharmony_ci{ 48762306a36Sopenharmony_ci u32 uval; 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci switch (attr) { 49062306a36Sopenharmony_ci case hwmon_power_max: 49162306a36Sopenharmony_ci return hwm_power_max_write(ddat, val); 49262306a36Sopenharmony_ci case hwmon_power_crit: 49362306a36Sopenharmony_ci uval = DIV_ROUND_CLOSEST_ULL(val << POWER_SETUP_I1_SHIFT, SF_POWER); 49462306a36Sopenharmony_ci return hwm_pcode_write_i1(ddat->uncore->i915, uval); 49562306a36Sopenharmony_ci default: 49662306a36Sopenharmony_ci return -EOPNOTSUPP; 49762306a36Sopenharmony_ci } 49862306a36Sopenharmony_ci} 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_civoid i915_hwmon_power_max_disable(struct drm_i915_private *i915, bool *old) 50162306a36Sopenharmony_ci{ 50262306a36Sopenharmony_ci struct i915_hwmon *hwmon = i915->hwmon; 50362306a36Sopenharmony_ci u32 r; 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci if (!hwmon || !i915_mmio_reg_valid(hwmon->rg.pkg_rapl_limit)) 50662306a36Sopenharmony_ci return; 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci mutex_lock(&hwmon->hwmon_lock); 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci hwmon->ddat.reset_in_progress = true; 51162306a36Sopenharmony_ci r = intel_uncore_rmw(hwmon->ddat.uncore, hwmon->rg.pkg_rapl_limit, 51262306a36Sopenharmony_ci PKG_PWR_LIM_1_EN, 0); 51362306a36Sopenharmony_ci *old = !!(r & PKG_PWR_LIM_1_EN); 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci mutex_unlock(&hwmon->hwmon_lock); 51662306a36Sopenharmony_ci} 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_civoid i915_hwmon_power_max_restore(struct drm_i915_private *i915, bool old) 51962306a36Sopenharmony_ci{ 52062306a36Sopenharmony_ci struct i915_hwmon *hwmon = i915->hwmon; 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci if (!hwmon || !i915_mmio_reg_valid(hwmon->rg.pkg_rapl_limit)) 52362306a36Sopenharmony_ci return; 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci mutex_lock(&hwmon->hwmon_lock); 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci intel_uncore_rmw(hwmon->ddat.uncore, hwmon->rg.pkg_rapl_limit, 52862306a36Sopenharmony_ci PKG_PWR_LIM_1_EN, old ? PKG_PWR_LIM_1_EN : 0); 52962306a36Sopenharmony_ci hwmon->ddat.reset_in_progress = false; 53062306a36Sopenharmony_ci wake_up_all(&hwmon->ddat.waitq); 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci mutex_unlock(&hwmon->hwmon_lock); 53362306a36Sopenharmony_ci} 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_cistatic umode_t 53662306a36Sopenharmony_cihwm_energy_is_visible(const struct hwm_drvdata *ddat, u32 attr) 53762306a36Sopenharmony_ci{ 53862306a36Sopenharmony_ci struct i915_hwmon *hwmon = ddat->hwmon; 53962306a36Sopenharmony_ci i915_reg_t rgaddr; 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci switch (attr) { 54262306a36Sopenharmony_ci case hwmon_energy_input: 54362306a36Sopenharmony_ci if (ddat->gt_n >= 0) 54462306a36Sopenharmony_ci rgaddr = hwmon->rg.energy_status_tile; 54562306a36Sopenharmony_ci else 54662306a36Sopenharmony_ci rgaddr = hwmon->rg.energy_status_all; 54762306a36Sopenharmony_ci return i915_mmio_reg_valid(rgaddr) ? 0444 : 0; 54862306a36Sopenharmony_ci default: 54962306a36Sopenharmony_ci return 0; 55062306a36Sopenharmony_ci } 55162306a36Sopenharmony_ci} 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_cistatic int 55462306a36Sopenharmony_cihwm_energy_read(struct hwm_drvdata *ddat, u32 attr, long *val) 55562306a36Sopenharmony_ci{ 55662306a36Sopenharmony_ci switch (attr) { 55762306a36Sopenharmony_ci case hwmon_energy_input: 55862306a36Sopenharmony_ci hwm_energy(ddat, val); 55962306a36Sopenharmony_ci return 0; 56062306a36Sopenharmony_ci default: 56162306a36Sopenharmony_ci return -EOPNOTSUPP; 56262306a36Sopenharmony_ci } 56362306a36Sopenharmony_ci} 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_cistatic umode_t 56662306a36Sopenharmony_cihwm_curr_is_visible(const struct hwm_drvdata *ddat, u32 attr) 56762306a36Sopenharmony_ci{ 56862306a36Sopenharmony_ci struct drm_i915_private *i915 = ddat->uncore->i915; 56962306a36Sopenharmony_ci u32 uval; 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci switch (attr) { 57262306a36Sopenharmony_ci case hwmon_curr_crit: 57362306a36Sopenharmony_ci return (hwm_pcode_read_i1(i915, &uval) || 57462306a36Sopenharmony_ci (uval & POWER_SETUP_I1_WATTS)) ? 0 : 0644; 57562306a36Sopenharmony_ci default: 57662306a36Sopenharmony_ci return 0; 57762306a36Sopenharmony_ci } 57862306a36Sopenharmony_ci} 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_cistatic int 58162306a36Sopenharmony_cihwm_curr_read(struct hwm_drvdata *ddat, u32 attr, long *val) 58262306a36Sopenharmony_ci{ 58362306a36Sopenharmony_ci int ret; 58462306a36Sopenharmony_ci u32 uval; 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci switch (attr) { 58762306a36Sopenharmony_ci case hwmon_curr_crit: 58862306a36Sopenharmony_ci ret = hwm_pcode_read_i1(ddat->uncore->i915, &uval); 58962306a36Sopenharmony_ci if (ret) 59062306a36Sopenharmony_ci return ret; 59162306a36Sopenharmony_ci if (uval & POWER_SETUP_I1_WATTS) 59262306a36Sopenharmony_ci return -ENODEV; 59362306a36Sopenharmony_ci *val = mul_u64_u32_shr(REG_FIELD_GET(POWER_SETUP_I1_DATA_MASK, uval), 59462306a36Sopenharmony_ci SF_CURR, POWER_SETUP_I1_SHIFT); 59562306a36Sopenharmony_ci return 0; 59662306a36Sopenharmony_ci default: 59762306a36Sopenharmony_ci return -EOPNOTSUPP; 59862306a36Sopenharmony_ci } 59962306a36Sopenharmony_ci} 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_cistatic int 60262306a36Sopenharmony_cihwm_curr_write(struct hwm_drvdata *ddat, u32 attr, long val) 60362306a36Sopenharmony_ci{ 60462306a36Sopenharmony_ci u32 uval; 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci switch (attr) { 60762306a36Sopenharmony_ci case hwmon_curr_crit: 60862306a36Sopenharmony_ci uval = DIV_ROUND_CLOSEST_ULL(val << POWER_SETUP_I1_SHIFT, SF_CURR); 60962306a36Sopenharmony_ci return hwm_pcode_write_i1(ddat->uncore->i915, uval); 61062306a36Sopenharmony_ci default: 61162306a36Sopenharmony_ci return -EOPNOTSUPP; 61262306a36Sopenharmony_ci } 61362306a36Sopenharmony_ci} 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_cistatic umode_t 61662306a36Sopenharmony_cihwm_is_visible(const void *drvdata, enum hwmon_sensor_types type, 61762306a36Sopenharmony_ci u32 attr, int channel) 61862306a36Sopenharmony_ci{ 61962306a36Sopenharmony_ci struct hwm_drvdata *ddat = (struct hwm_drvdata *)drvdata; 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci switch (type) { 62262306a36Sopenharmony_ci case hwmon_in: 62362306a36Sopenharmony_ci return hwm_in_is_visible(ddat, attr); 62462306a36Sopenharmony_ci case hwmon_power: 62562306a36Sopenharmony_ci return hwm_power_is_visible(ddat, attr, channel); 62662306a36Sopenharmony_ci case hwmon_energy: 62762306a36Sopenharmony_ci return hwm_energy_is_visible(ddat, attr); 62862306a36Sopenharmony_ci case hwmon_curr: 62962306a36Sopenharmony_ci return hwm_curr_is_visible(ddat, attr); 63062306a36Sopenharmony_ci default: 63162306a36Sopenharmony_ci return 0; 63262306a36Sopenharmony_ci } 63362306a36Sopenharmony_ci} 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_cistatic int 63662306a36Sopenharmony_cihwm_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, 63762306a36Sopenharmony_ci int channel, long *val) 63862306a36Sopenharmony_ci{ 63962306a36Sopenharmony_ci struct hwm_drvdata *ddat = dev_get_drvdata(dev); 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci switch (type) { 64262306a36Sopenharmony_ci case hwmon_in: 64362306a36Sopenharmony_ci return hwm_in_read(ddat, attr, val); 64462306a36Sopenharmony_ci case hwmon_power: 64562306a36Sopenharmony_ci return hwm_power_read(ddat, attr, channel, val); 64662306a36Sopenharmony_ci case hwmon_energy: 64762306a36Sopenharmony_ci return hwm_energy_read(ddat, attr, val); 64862306a36Sopenharmony_ci case hwmon_curr: 64962306a36Sopenharmony_ci return hwm_curr_read(ddat, attr, val); 65062306a36Sopenharmony_ci default: 65162306a36Sopenharmony_ci return -EOPNOTSUPP; 65262306a36Sopenharmony_ci } 65362306a36Sopenharmony_ci} 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_cistatic int 65662306a36Sopenharmony_cihwm_write(struct device *dev, enum hwmon_sensor_types type, u32 attr, 65762306a36Sopenharmony_ci int channel, long val) 65862306a36Sopenharmony_ci{ 65962306a36Sopenharmony_ci struct hwm_drvdata *ddat = dev_get_drvdata(dev); 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci switch (type) { 66262306a36Sopenharmony_ci case hwmon_power: 66362306a36Sopenharmony_ci return hwm_power_write(ddat, attr, channel, val); 66462306a36Sopenharmony_ci case hwmon_curr: 66562306a36Sopenharmony_ci return hwm_curr_write(ddat, attr, val); 66662306a36Sopenharmony_ci default: 66762306a36Sopenharmony_ci return -EOPNOTSUPP; 66862306a36Sopenharmony_ci } 66962306a36Sopenharmony_ci} 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_cistatic const struct hwmon_ops hwm_ops = { 67262306a36Sopenharmony_ci .is_visible = hwm_is_visible, 67362306a36Sopenharmony_ci .read = hwm_read, 67462306a36Sopenharmony_ci .write = hwm_write, 67562306a36Sopenharmony_ci}; 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_cistatic const struct hwmon_chip_info hwm_chip_info = { 67862306a36Sopenharmony_ci .ops = &hwm_ops, 67962306a36Sopenharmony_ci .info = hwm_info, 68062306a36Sopenharmony_ci}; 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_cistatic umode_t 68362306a36Sopenharmony_cihwm_gt_is_visible(const void *drvdata, enum hwmon_sensor_types type, 68462306a36Sopenharmony_ci u32 attr, int channel) 68562306a36Sopenharmony_ci{ 68662306a36Sopenharmony_ci struct hwm_drvdata *ddat = (struct hwm_drvdata *)drvdata; 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci switch (type) { 68962306a36Sopenharmony_ci case hwmon_energy: 69062306a36Sopenharmony_ci return hwm_energy_is_visible(ddat, attr); 69162306a36Sopenharmony_ci default: 69262306a36Sopenharmony_ci return 0; 69362306a36Sopenharmony_ci } 69462306a36Sopenharmony_ci} 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_cistatic int 69762306a36Sopenharmony_cihwm_gt_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, 69862306a36Sopenharmony_ci int channel, long *val) 69962306a36Sopenharmony_ci{ 70062306a36Sopenharmony_ci struct hwm_drvdata *ddat = dev_get_drvdata(dev); 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci switch (type) { 70362306a36Sopenharmony_ci case hwmon_energy: 70462306a36Sopenharmony_ci return hwm_energy_read(ddat, attr, val); 70562306a36Sopenharmony_ci default: 70662306a36Sopenharmony_ci return -EOPNOTSUPP; 70762306a36Sopenharmony_ci } 70862306a36Sopenharmony_ci} 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_cistatic const struct hwmon_ops hwm_gt_ops = { 71162306a36Sopenharmony_ci .is_visible = hwm_gt_is_visible, 71262306a36Sopenharmony_ci .read = hwm_gt_read, 71362306a36Sopenharmony_ci}; 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_cistatic const struct hwmon_chip_info hwm_gt_chip_info = { 71662306a36Sopenharmony_ci .ops = &hwm_gt_ops, 71762306a36Sopenharmony_ci .info = hwm_gt_info, 71862306a36Sopenharmony_ci}; 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_cistatic void 72162306a36Sopenharmony_cihwm_get_preregistration_info(struct drm_i915_private *i915) 72262306a36Sopenharmony_ci{ 72362306a36Sopenharmony_ci struct i915_hwmon *hwmon = i915->hwmon; 72462306a36Sopenharmony_ci struct intel_uncore *uncore = &i915->uncore; 72562306a36Sopenharmony_ci struct hwm_drvdata *ddat = &hwmon->ddat; 72662306a36Sopenharmony_ci intel_wakeref_t wakeref; 72762306a36Sopenharmony_ci u32 val_sku_unit = 0; 72862306a36Sopenharmony_ci struct intel_gt *gt; 72962306a36Sopenharmony_ci long energy; 73062306a36Sopenharmony_ci int i; 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci /* Available for all Gen12+/dGfx */ 73362306a36Sopenharmony_ci hwmon->rg.gt_perf_status = GEN12_RPSTAT1; 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci if (IS_DG1(i915) || IS_DG2(i915)) { 73662306a36Sopenharmony_ci hwmon->rg.pkg_power_sku_unit = PCU_PACKAGE_POWER_SKU_UNIT; 73762306a36Sopenharmony_ci hwmon->rg.pkg_power_sku = PCU_PACKAGE_POWER_SKU; 73862306a36Sopenharmony_ci hwmon->rg.pkg_rapl_limit = PCU_PACKAGE_RAPL_LIMIT; 73962306a36Sopenharmony_ci hwmon->rg.energy_status_all = PCU_PACKAGE_ENERGY_STATUS; 74062306a36Sopenharmony_ci hwmon->rg.energy_status_tile = INVALID_MMIO_REG; 74162306a36Sopenharmony_ci } else if (IS_XEHPSDV(i915)) { 74262306a36Sopenharmony_ci hwmon->rg.pkg_power_sku_unit = GT0_PACKAGE_POWER_SKU_UNIT; 74362306a36Sopenharmony_ci hwmon->rg.pkg_power_sku = INVALID_MMIO_REG; 74462306a36Sopenharmony_ci hwmon->rg.pkg_rapl_limit = GT0_PACKAGE_RAPL_LIMIT; 74562306a36Sopenharmony_ci hwmon->rg.energy_status_all = GT0_PLATFORM_ENERGY_STATUS; 74662306a36Sopenharmony_ci hwmon->rg.energy_status_tile = GT0_PACKAGE_ENERGY_STATUS; 74762306a36Sopenharmony_ci } else { 74862306a36Sopenharmony_ci hwmon->rg.pkg_power_sku_unit = INVALID_MMIO_REG; 74962306a36Sopenharmony_ci hwmon->rg.pkg_power_sku = INVALID_MMIO_REG; 75062306a36Sopenharmony_ci hwmon->rg.pkg_rapl_limit = INVALID_MMIO_REG; 75162306a36Sopenharmony_ci hwmon->rg.energy_status_all = INVALID_MMIO_REG; 75262306a36Sopenharmony_ci hwmon->rg.energy_status_tile = INVALID_MMIO_REG; 75362306a36Sopenharmony_ci } 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci with_intel_runtime_pm(uncore->rpm, wakeref) { 75662306a36Sopenharmony_ci /* 75762306a36Sopenharmony_ci * The contents of register hwmon->rg.pkg_power_sku_unit do not change, 75862306a36Sopenharmony_ci * so read it once and store the shift values. 75962306a36Sopenharmony_ci */ 76062306a36Sopenharmony_ci if (i915_mmio_reg_valid(hwmon->rg.pkg_power_sku_unit)) 76162306a36Sopenharmony_ci val_sku_unit = intel_uncore_read(uncore, 76262306a36Sopenharmony_ci hwmon->rg.pkg_power_sku_unit); 76362306a36Sopenharmony_ci } 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci hwmon->scl_shift_power = REG_FIELD_GET(PKG_PWR_UNIT, val_sku_unit); 76662306a36Sopenharmony_ci hwmon->scl_shift_energy = REG_FIELD_GET(PKG_ENERGY_UNIT, val_sku_unit); 76762306a36Sopenharmony_ci hwmon->scl_shift_time = REG_FIELD_GET(PKG_TIME_UNIT, val_sku_unit); 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci /* 77062306a36Sopenharmony_ci * Initialize 'struct hwm_energy_info', i.e. set fields to the 77162306a36Sopenharmony_ci * first value of the energy register read 77262306a36Sopenharmony_ci */ 77362306a36Sopenharmony_ci if (i915_mmio_reg_valid(hwmon->rg.energy_status_all)) 77462306a36Sopenharmony_ci hwm_energy(ddat, &energy); 77562306a36Sopenharmony_ci if (i915_mmio_reg_valid(hwmon->rg.energy_status_tile)) { 77662306a36Sopenharmony_ci for_each_gt(gt, i915, i) 77762306a36Sopenharmony_ci hwm_energy(&hwmon->ddat_gt[i], &energy); 77862306a36Sopenharmony_ci } 77962306a36Sopenharmony_ci} 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_civoid i915_hwmon_register(struct drm_i915_private *i915) 78262306a36Sopenharmony_ci{ 78362306a36Sopenharmony_ci struct device *dev = i915->drm.dev; 78462306a36Sopenharmony_ci struct i915_hwmon *hwmon; 78562306a36Sopenharmony_ci struct device *hwmon_dev; 78662306a36Sopenharmony_ci struct hwm_drvdata *ddat; 78762306a36Sopenharmony_ci struct hwm_drvdata *ddat_gt; 78862306a36Sopenharmony_ci struct intel_gt *gt; 78962306a36Sopenharmony_ci int i; 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci /* hwmon is available only for dGfx */ 79262306a36Sopenharmony_ci if (!IS_DGFX(i915)) 79362306a36Sopenharmony_ci return; 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci hwmon = devm_kzalloc(dev, sizeof(*hwmon), GFP_KERNEL); 79662306a36Sopenharmony_ci if (!hwmon) 79762306a36Sopenharmony_ci return; 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci i915->hwmon = hwmon; 80062306a36Sopenharmony_ci mutex_init(&hwmon->hwmon_lock); 80162306a36Sopenharmony_ci ddat = &hwmon->ddat; 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci ddat->hwmon = hwmon; 80462306a36Sopenharmony_ci ddat->uncore = &i915->uncore; 80562306a36Sopenharmony_ci snprintf(ddat->name, sizeof(ddat->name), "i915"); 80662306a36Sopenharmony_ci ddat->gt_n = -1; 80762306a36Sopenharmony_ci init_waitqueue_head(&ddat->waitq); 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci for_each_gt(gt, i915, i) { 81062306a36Sopenharmony_ci ddat_gt = hwmon->ddat_gt + i; 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci ddat_gt->hwmon = hwmon; 81362306a36Sopenharmony_ci ddat_gt->uncore = gt->uncore; 81462306a36Sopenharmony_ci snprintf(ddat_gt->name, sizeof(ddat_gt->name), "i915_gt%u", i); 81562306a36Sopenharmony_ci ddat_gt->gt_n = i; 81662306a36Sopenharmony_ci } 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci hwm_get_preregistration_info(i915); 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci /* hwmon_dev points to device hwmon<i> */ 82162306a36Sopenharmony_ci hwmon_dev = devm_hwmon_device_register_with_info(dev, ddat->name, 82262306a36Sopenharmony_ci ddat, 82362306a36Sopenharmony_ci &hwm_chip_info, 82462306a36Sopenharmony_ci hwm_groups); 82562306a36Sopenharmony_ci if (IS_ERR(hwmon_dev)) { 82662306a36Sopenharmony_ci i915->hwmon = NULL; 82762306a36Sopenharmony_ci return; 82862306a36Sopenharmony_ci } 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_ci ddat->hwmon_dev = hwmon_dev; 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci for_each_gt(gt, i915, i) { 83362306a36Sopenharmony_ci ddat_gt = hwmon->ddat_gt + i; 83462306a36Sopenharmony_ci /* 83562306a36Sopenharmony_ci * Create per-gt directories only if a per-gt attribute is 83662306a36Sopenharmony_ci * visible. Currently this is only energy 83762306a36Sopenharmony_ci */ 83862306a36Sopenharmony_ci if (!hwm_gt_is_visible(ddat_gt, hwmon_energy, hwmon_energy_input, 0)) 83962306a36Sopenharmony_ci continue; 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci hwmon_dev = devm_hwmon_device_register_with_info(dev, ddat_gt->name, 84262306a36Sopenharmony_ci ddat_gt, 84362306a36Sopenharmony_ci &hwm_gt_chip_info, 84462306a36Sopenharmony_ci NULL); 84562306a36Sopenharmony_ci if (!IS_ERR(hwmon_dev)) 84662306a36Sopenharmony_ci ddat_gt->hwmon_dev = hwmon_dev; 84762306a36Sopenharmony_ci } 84862306a36Sopenharmony_ci} 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_civoid i915_hwmon_unregister(struct drm_i915_private *i915) 85162306a36Sopenharmony_ci{ 85262306a36Sopenharmony_ci fetch_and_zero(&i915->hwmon); 85362306a36Sopenharmony_ci} 854