#include "i915_hwmon.h"
#include "i915_reg.h"
#include "intel_mchbar_regs.h"
+#include "gt/intel_gt_regs.h"
+
+/*
+ * SF_* - scale factors for particular quantities according to hwmon spec.
+ * - voltage - millivolts
+ */
+#define SF_VOLTAGE 1000
struct hwm_reg {
+ i915_reg_t gt_perf_status;
};
struct hwm_drvdata {
};
static const struct hwmon_channel_info *hwm_info[] = {
+ HWMON_CHANNEL_INFO(in, HWMON_I_INPUT),
NULL
};
+static umode_t
+hwm_in_is_visible(const struct hwm_drvdata *ddat, u32 attr)
+{
+ struct drm_i915_private *i915 = ddat->uncore->i915;
+
+ switch (attr) {
+ case hwmon_in_input:
+ return IS_DG1(i915) || IS_DG2(i915) ? 0444 : 0;
+ default:
+ return 0;
+ }
+}
+
+static int
+hwm_in_read(struct hwm_drvdata *ddat, u32 attr, long *val)
+{
+ struct i915_hwmon *hwmon = ddat->hwmon;
+ intel_wakeref_t wakeref;
+ u32 reg_value;
+
+ switch (attr) {
+ case hwmon_in_input:
+ with_intel_runtime_pm(ddat->uncore->rpm, wakeref)
+ reg_value = intel_uncore_read(ddat->uncore, hwmon->rg.gt_perf_status);
+ /* HW register value in units of 2.5 millivolt */
+ *val = DIV_ROUND_CLOSEST(REG_FIELD_GET(GEN12_VOLTAGE_MASK, reg_value) * 25, 10);
+ return 0;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
static umode_t
hwm_is_visible(const void *drvdata, enum hwmon_sensor_types type,
u32 attr, int channel)
{
+ struct hwm_drvdata *ddat = (struct hwm_drvdata *)drvdata;
+
switch (type) {
+ case hwmon_in:
+ return hwm_in_is_visible(ddat, attr);
default:
return 0;
}
hwm_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
int channel, long *val)
{
+ struct hwm_drvdata *ddat = dev_get_drvdata(dev);
+
switch (type) {
+ case hwmon_in:
+ return hwm_in_read(ddat, attr, val);
default:
return -EOPNOTSUPP;
}
static void
hwm_get_preregistration_info(struct drm_i915_private *i915)
{
+ struct i915_hwmon *hwmon = i915->hwmon;
+
+ /* Available for all Gen12+/dGfx */
+ hwmon->rg.gt_perf_status = GEN12_RPSTAT1;
}
void i915_hwmon_register(struct drm_i915_private *i915)