diff --git a/drivers/gpu/drm/xe/xe_hwmon.c b/drivers/gpu/drm/xe/xe_hwmon.c index de3f2aeffc3f..49f7e0edcc4b 100644 --- a/drivers/gpu/drm/xe/xe_hwmon.c +++ b/drivers/gpu/drm/xe/xe_hwmon.c @@ -575,23 +575,36 @@ xe_hwmon_power_max_interval_show(struct device *dev, struct device_attribute *at mutex_unlock(&hwmon->hwmon_lock); - x = REG_FIELD_GET(PWR_LIM_TIME_X, reg_val); - y = REG_FIELD_GET(PWR_LIM_TIME_Y, reg_val); + if (hwmon->xe->info.platform >= XE_CRESCENTISLAND) { + /** + * On CRI and newer platforms, the interval encoding changed. + * The value is now stored directly in milliseconds as U5.2, + * replacing the older 1.x * 2^y representation. + * Bits [6:2] hold the integer part and bits [1:0] the fraction, + * so convert to milliseconds by extracting integer/fractional parts. + * Round fraction value to 1 when it is >= 0.5. + */ + reg_val = REG_FIELD_GET(PWR_LIM_TIME, reg_val); + out = (u64)((reg_val >> 2) + ((reg_val & 0x3) >= 2)); + } else { + x = REG_FIELD_GET(PWR_LIM_TIME_X, reg_val); + y = REG_FIELD_GET(PWR_LIM_TIME_Y, reg_val); - /* - * tau = (1 + (x / 4)) * power(2,y), x = bits(23:22), y = bits(21:17) - * = (4 | x) << (y - 2) - * - * Here (y - 2) ensures a 1.x fixed point representation of 1.x - * As x is 2 bits so 1.x can be 1.0, 1.25, 1.50, 1.75 - * - * As y can be < 2, we compute tau4 = (4 | x) << y - * and then add 2 when doing the final right shift to account for units - */ - tau4 = (u64)((1 << x_w) | x) << y; + /* + * tau = (1 + (x / 4)) * power(2,y), x = bits(23:22), y = bits(21:17) + * = (4 | x) << (y - 2) + * + * Here (y - 2) ensures a 1.x fixed point representation of 1.x + * As x is 2 bits so 1.x can be 1.0, 1.25, 1.50, 1.75 + * + * As y can be < 2, we compute tau4 = (4 | x) << y + * and then add 2 when doing the final right shift to account for units + */ + tau4 = (u64)((1 << x_w) | x) << y; - /* val in hwmon interface units (millisec) */ - out = mul_u64_u32_shr(tau4, SF_TIME, hwmon->scl_shift_time + x_w); + /* val in hwmon interface units (millisec) */ + out = mul_u64_u32_shr(tau4, SF_TIME, hwmon->scl_shift_time + x_w); + } return sysfs_emit(buf, "%llu\n", out); } @@ -637,24 +650,35 @@ xe_hwmon_power_max_interval_store(struct device *dev, struct device_attribute *a if (val > max_win) return -EINVAL; - /* val in hw units */ - val = DIV_ROUND_CLOSEST_ULL((u64)val << hwmon->scl_shift_time, SF_TIME) + 1; - - /* - * Convert val to 1.x * power(2,y) - * y = ilog2(val) - * x = (val - (1 << y)) >> (y - 2) - */ - if (!val) { - y = 0; - x = 0; + if (hwmon->xe->info.platform >= XE_CRESCENTISLAND) { + /** + * On CRI and newer platforms, the interval encoding changed. + * The value is now stored directly in milliseconds as U5.2, + * replacing the older 1.x * 2^y representation. + * Bits [6:2] hold the integer part and bits [1:0] the fraction,so + * convert from milliseconds by shifting the value left by 2 to fit into the field. + */ + rxy = REG_FIELD_PREP(PWR_LIM_TIME, (val << 2)); } else { - y = ilog2(val); - x = (val - (1ul << y)) << x_w >> y; - } + /* val in hw units */ + val = DIV_ROUND_CLOSEST_ULL((u64)val << hwmon->scl_shift_time, SF_TIME) + 1; - rxy = REG_FIELD_PREP(PWR_LIM_TIME_X, x) | - REG_FIELD_PREP(PWR_LIM_TIME_Y, y); + /* + * Convert val to 1.x * power(2,y) + * y = ilog2(val) + * x = (val - (1 << y)) >> (y - 2) + */ + if (!val) { + y = 0; + x = 0; + } else { + y = ilog2(val); + x = (val - (1ul << y)) << x_w >> y; + } + + rxy = REG_FIELD_PREP(PWR_LIM_TIME_X, x) | + REG_FIELD_PREP(PWR_LIM_TIME_Y, y); + } guard(xe_pm_runtime)(hwmon->xe);