drm/xe/hwmon: Expose input voltage attribute
[linux-block.git] / drivers / gpu / drm / xe / xe_hwmon.c
CommitLineData
fb1b7060
BN
1// SPDX-License-Identifier: MIT
2/*
3 * Copyright © 2023 Intel Corporation
4 */
5
fbcdc9d3 6#include <linux/hwmon-sysfs.h>
fb1b7060 7#include <linux/hwmon.h>
fbcdc9d3 8#include <linux/types.h>
fb1b7060
BN
9
10#include <drm/drm_managed.h>
11#include "regs/xe_gt_regs.h"
12#include "regs/xe_mchbar_regs.h"
13#include "xe_device.h"
14#include "xe_gt.h"
15#include "xe_hwmon.h"
16#include "xe_mmio.h"
92d44a42
BN
17#include "xe_pcode.h"
18#include "xe_pcode_api.h"
fb1b7060
BN
19
20enum xe_hwmon_reg {
21 REG_PKG_RAPL_LIMIT,
22 REG_PKG_POWER_SKU,
23 REG_PKG_POWER_SKU_UNIT,
fbcdc9d3 24 REG_GT_PERF_STATUS,
fb1b7060
BN
25};
26
27enum xe_hwmon_reg_operation {
28 REG_READ,
29 REG_WRITE,
30 REG_RMW,
31};
32
33/*
34 * SF_* - scale factors for particular quantities according to hwmon spec.
35 */
36#define SF_POWER 1000000 /* microwatts */
92d44a42 37#define SF_CURR 1000 /* milliamperes */
fbcdc9d3 38#define SF_VOLTAGE 1000 /* millivolts */
fb1b7060
BN
39
40struct xe_hwmon {
41 struct device *hwmon_dev;
42 struct xe_gt *gt;
43 struct mutex hwmon_lock; /* rmw operations*/
44 int scl_shift_power;
45};
46
47static u32 xe_hwmon_get_reg(struct xe_hwmon *hwmon, enum xe_hwmon_reg hwmon_reg)
48{
49 struct xe_device *xe = gt_to_xe(hwmon->gt);
50 struct xe_reg reg = XE_REG(0);
51
52 switch (hwmon_reg) {
53 case REG_PKG_RAPL_LIMIT:
54 if (xe->info.platform == XE_DG2)
55 reg = PCU_CR_PACKAGE_RAPL_LIMIT;
56 else if (xe->info.platform == XE_PVC)
57 reg = PVC_GT0_PACKAGE_RAPL_LIMIT;
58 break;
59 case REG_PKG_POWER_SKU:
60 if (xe->info.platform == XE_DG2)
61 reg = PCU_CR_PACKAGE_POWER_SKU;
62 else if (xe->info.platform == XE_PVC)
63 reg = PVC_GT0_PACKAGE_POWER_SKU;
64 break;
65 case REG_PKG_POWER_SKU_UNIT:
66 if (xe->info.platform == XE_DG2)
67 reg = PCU_CR_PACKAGE_POWER_SKU_UNIT;
68 else if (xe->info.platform == XE_PVC)
69 reg = PVC_GT0_PACKAGE_POWER_SKU_UNIT;
70 break;
fbcdc9d3
BN
71 case REG_GT_PERF_STATUS:
72 if (xe->info.platform == XE_DG2)
73 reg = GT_PERF_STATUS;
74 break;
fb1b7060
BN
75 default:
76 drm_warn(&xe->drm, "Unknown xe hwmon reg id: %d\n", hwmon_reg);
77 break;
78 }
79
80 return reg.raw;
81}
82
83static int xe_hwmon_process_reg(struct xe_hwmon *hwmon, enum xe_hwmon_reg hwmon_reg,
84 enum xe_hwmon_reg_operation operation, u32 *value,
85 u32 clr, u32 set)
86{
87 struct xe_reg reg;
88
89 reg.raw = xe_hwmon_get_reg(hwmon, hwmon_reg);
90
91 if (!reg.raw)
92 return -EOPNOTSUPP;
93
94 switch (operation) {
95 case REG_READ:
96 *value = xe_mmio_read32(hwmon->gt, reg);
97 return 0;
98 case REG_WRITE:
99 xe_mmio_write32(hwmon->gt, reg, *value);
100 return 0;
101 case REG_RMW:
102 *value = xe_mmio_rmw32(hwmon->gt, reg, clr, set);
103 return 0;
104 default:
105 drm_warn(&gt_to_xe(hwmon->gt)->drm, "Invalid xe hwmon reg operation: %d\n",
106 operation);
107 return -EOPNOTSUPP;
108 }
109}
110
111static int xe_hwmon_process_reg_read64(struct xe_hwmon *hwmon,
112 enum xe_hwmon_reg hwmon_reg, u64 *value)
113{
114 struct xe_reg reg;
115
116 reg.raw = xe_hwmon_get_reg(hwmon, hwmon_reg);
117
118 if (!reg.raw)
119 return -EOPNOTSUPP;
120
121 *value = xe_mmio_read64_2x32(hwmon->gt, reg);
122
123 return 0;
124}
125
126#define PL1_DISABLE 0
127
128/*
129 * HW allows arbitrary PL1 limits to be set but silently clamps these values to
130 * "typical but not guaranteed" min/max values in REG_PKG_POWER_SKU. Follow the
131 * same pattern for sysfs, allow arbitrary PL1 limits to be set but display
132 * clamped values when read.
133 */
134static int xe_hwmon_power_max_read(struct xe_hwmon *hwmon, long *value)
135{
136 u32 reg_val;
137 u64 reg_val64, min, max;
138
139 xe_hwmon_process_reg(hwmon, REG_PKG_RAPL_LIMIT, REG_READ, &reg_val, 0, 0);
140 /* Check if PL1 limit is disabled */
141 if (!(reg_val & PKG_PWR_LIM_1_EN)) {
142 *value = PL1_DISABLE;
143 return 0;
144 }
145
146 reg_val = REG_FIELD_GET(PKG_PWR_LIM_1, reg_val);
147 *value = mul_u64_u32_shr(reg_val, SF_POWER, hwmon->scl_shift_power);
148
149 xe_hwmon_process_reg_read64(hwmon, REG_PKG_POWER_SKU, &reg_val64);
150 min = REG_FIELD_GET(PKG_MIN_PWR, reg_val64);
151 min = mul_u64_u32_shr(min, SF_POWER, hwmon->scl_shift_power);
152 max = REG_FIELD_GET(PKG_MAX_PWR, reg_val64);
153 max = mul_u64_u32_shr(max, SF_POWER, hwmon->scl_shift_power);
154
155 if (min && max)
156 *value = clamp_t(u64, *value, min, max);
157
158 return 0;
159}
160
161static int xe_hwmon_power_max_write(struct xe_hwmon *hwmon, long value)
162{
163 u32 reg_val;
164
165 /* Disable PL1 limit and verify, as limit cannot be disabled on all platforms */
166 if (value == PL1_DISABLE) {
167 xe_hwmon_process_reg(hwmon, REG_PKG_RAPL_LIMIT, REG_RMW, &reg_val,
168 PKG_PWR_LIM_1_EN, 0);
169 xe_hwmon_process_reg(hwmon, REG_PKG_RAPL_LIMIT, REG_READ, &reg_val,
170 PKG_PWR_LIM_1_EN, 0);
171
172 if (reg_val & PKG_PWR_LIM_1_EN)
173 return -EOPNOTSUPP;
174 }
175
176 /* Computation in 64-bits to avoid overflow. Round to nearest. */
177 reg_val = DIV_ROUND_CLOSEST_ULL((u64)value << hwmon->scl_shift_power, SF_POWER);
178 reg_val = PKG_PWR_LIM_1_EN | REG_FIELD_PREP(PKG_PWR_LIM_1, reg_val);
179
180 xe_hwmon_process_reg(hwmon, REG_PKG_RAPL_LIMIT, REG_RMW, &reg_val,
181 PKG_PWR_LIM_1_EN | PKG_PWR_LIM_1, reg_val);
182
183 return 0;
184}
185
186static int xe_hwmon_power_rated_max_read(struct xe_hwmon *hwmon, long *value)
187{
188 u32 reg_val;
189
190 xe_hwmon_process_reg(hwmon, REG_PKG_POWER_SKU, REG_READ, &reg_val, 0, 0);
191 reg_val = REG_FIELD_GET(PKG_TDP, reg_val);
192 *value = mul_u64_u32_shr(reg_val, SF_POWER, hwmon->scl_shift_power);
193
194 return 0;
195}
196
197static const struct hwmon_channel_info *hwmon_info[] = {
92d44a42
BN
198 HWMON_CHANNEL_INFO(power, HWMON_P_MAX | HWMON_P_RATED_MAX | HWMON_P_CRIT),
199 HWMON_CHANNEL_INFO(curr, HWMON_C_CRIT),
fbcdc9d3 200 HWMON_CHANNEL_INFO(in, HWMON_I_INPUT),
fb1b7060
BN
201 NULL
202};
203
92d44a42
BN
204/* I1 is exposed as power_crit or as curr_crit depending on bit 31 */
205static int xe_hwmon_pcode_read_i1(struct xe_gt *gt, u32 *uval)
206{
207 /* Avoid Illegal Subcommand error */
208 if (gt_to_xe(gt)->info.platform == XE_DG2)
209 return -ENXIO;
210
211 return xe_pcode_read(gt, PCODE_MBOX(PCODE_POWER_SETUP,
212 POWER_SETUP_SUBCOMMAND_READ_I1, 0),
213 uval, 0);
214}
215
216static int xe_hwmon_pcode_write_i1(struct xe_gt *gt, u32 uval)
217{
218 return xe_pcode_write(gt, PCODE_MBOX(PCODE_POWER_SETUP,
219 POWER_SETUP_SUBCOMMAND_WRITE_I1, 0),
220 uval);
221}
222
fbcdc9d3
BN
223static int xe_hwmon_get_voltage(struct xe_hwmon *hwmon, long *value)
224{
225 u32 reg_val;
226
227 xe_hwmon_process_reg(hwmon, REG_GT_PERF_STATUS,
228 REG_READ, &reg_val, 0, 0);
229 /* HW register value in units of 2.5 millivolt */
230 *value = DIV_ROUND_CLOSEST(REG_FIELD_GET(VOLTAGE_MASK, reg_val) * 2500, SF_VOLTAGE);
231
232 return 0;
233}
234
fb1b7060
BN
235static umode_t
236xe_hwmon_power_is_visible(struct xe_hwmon *hwmon, u32 attr, int chan)
237{
92d44a42
BN
238 u32 uval;
239
fb1b7060
BN
240 switch (attr) {
241 case hwmon_power_max:
242 return xe_hwmon_get_reg(hwmon, REG_PKG_RAPL_LIMIT) ? 0664 : 0;
243 case hwmon_power_rated_max:
244 return xe_hwmon_get_reg(hwmon, REG_PKG_POWER_SKU) ? 0444 : 0;
92d44a42
BN
245 case hwmon_power_crit:
246 return (xe_hwmon_pcode_read_i1(hwmon->gt, &uval) ||
247 !(uval & POWER_SETUP_I1_WATTS)) ? 0 : 0644;
fb1b7060
BN
248 default:
249 return 0;
250 }
251}
252
253static int
254xe_hwmon_power_read(struct xe_hwmon *hwmon, u32 attr, int chan, long *val)
255{
92d44a42
BN
256 int ret;
257 u32 uval;
258
fb1b7060
BN
259 switch (attr) {
260 case hwmon_power_max:
261 return xe_hwmon_power_max_read(hwmon, val);
262 case hwmon_power_rated_max:
263 return xe_hwmon_power_rated_max_read(hwmon, val);
92d44a42
BN
264 case hwmon_power_crit:
265 ret = xe_hwmon_pcode_read_i1(hwmon->gt, &uval);
266 if (ret)
267 return ret;
268 if (!(uval & POWER_SETUP_I1_WATTS))
269 return -ENODEV;
270 *val = mul_u64_u32_shr(REG_FIELD_GET(POWER_SETUP_I1_DATA_MASK, uval),
271 SF_POWER, POWER_SETUP_I1_SHIFT);
272 return 0;
fb1b7060
BN
273 default:
274 return -EOPNOTSUPP;
275 }
276}
277
278static int
279xe_hwmon_power_write(struct xe_hwmon *hwmon, u32 attr, int chan, long val)
280{
92d44a42
BN
281 u32 uval;
282
fb1b7060
BN
283 switch (attr) {
284 case hwmon_power_max:
285 return xe_hwmon_power_max_write(hwmon, val);
92d44a42
BN
286 case hwmon_power_crit:
287 uval = DIV_ROUND_CLOSEST_ULL(val << POWER_SETUP_I1_SHIFT, SF_POWER);
288 return xe_hwmon_pcode_write_i1(hwmon->gt, uval);
289 default:
290 return -EOPNOTSUPP;
291 }
292}
293
294static umode_t
295xe_hwmon_curr_is_visible(const struct xe_hwmon *hwmon, u32 attr)
296{
297 u32 uval;
298
299 switch (attr) {
300 case hwmon_curr_crit:
301 return (xe_hwmon_pcode_read_i1(hwmon->gt, &uval) ||
302 (uval & POWER_SETUP_I1_WATTS)) ? 0 : 0644;
303 default:
304 return 0;
305 }
306}
307
308static int
309xe_hwmon_curr_read(struct xe_hwmon *hwmon, u32 attr, long *val)
310{
311 int ret;
312 u32 uval;
313
314 switch (attr) {
315 case hwmon_curr_crit:
316 ret = xe_hwmon_pcode_read_i1(hwmon->gt, &uval);
317 if (ret)
318 return ret;
319 if (uval & POWER_SETUP_I1_WATTS)
320 return -ENODEV;
321 *val = mul_u64_u32_shr(REG_FIELD_GET(POWER_SETUP_I1_DATA_MASK, uval),
322 SF_CURR, POWER_SETUP_I1_SHIFT);
323 return 0;
324 default:
325 return -EOPNOTSUPP;
326 }
327}
328
329static int
330xe_hwmon_curr_write(struct xe_hwmon *hwmon, u32 attr, long val)
331{
332 u32 uval;
333
334 switch (attr) {
335 case hwmon_curr_crit:
336 uval = DIV_ROUND_CLOSEST_ULL(val << POWER_SETUP_I1_SHIFT, SF_CURR);
337 return xe_hwmon_pcode_write_i1(hwmon->gt, uval);
fb1b7060
BN
338 default:
339 return -EOPNOTSUPP;
340 }
341}
342
fbcdc9d3
BN
343static umode_t
344xe_hwmon_in_is_visible(struct xe_hwmon *hwmon, u32 attr)
345{
346 switch (attr) {
347 case hwmon_in_input:
348 return xe_hwmon_get_reg(hwmon, REG_GT_PERF_STATUS) ? 0444 : 0;
349 default:
350 return 0;
351 }
352}
353
354static int
355xe_hwmon_in_read(struct xe_hwmon *hwmon, u32 attr, long *val)
356{
357 int ret;
358
359 xe_device_mem_access_get(gt_to_xe(hwmon->gt));
360
361 switch (attr) {
362 case hwmon_in_input:
363 ret = xe_hwmon_get_voltage(hwmon, val);
364 break;
365 default:
366 ret = -EOPNOTSUPP;
367 }
368
369 xe_device_mem_access_put(gt_to_xe(hwmon->gt));
370
371 return ret;
372}
373
fb1b7060
BN
374static umode_t
375xe_hwmon_is_visible(const void *drvdata, enum hwmon_sensor_types type,
376 u32 attr, int channel)
377{
378 struct xe_hwmon *hwmon = (struct xe_hwmon *)drvdata;
379 int ret;
380
381 xe_device_mem_access_get(gt_to_xe(hwmon->gt));
382
383 switch (type) {
384 case hwmon_power:
385 ret = xe_hwmon_power_is_visible(hwmon, attr, channel);
386 break;
92d44a42
BN
387 case hwmon_curr:
388 ret = xe_hwmon_curr_is_visible(hwmon, attr);
389 break;
fbcdc9d3
BN
390 case hwmon_in:
391 ret = xe_hwmon_in_is_visible(hwmon, attr);
392 break;
fb1b7060
BN
393 default:
394 ret = 0;
395 break;
396 }
397
398 xe_device_mem_access_put(gt_to_xe(hwmon->gt));
399
400 return ret;
401}
402
403static int
404xe_hwmon_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
405 int channel, long *val)
406{
407 struct xe_hwmon *hwmon = dev_get_drvdata(dev);
408 int ret;
409
410 xe_device_mem_access_get(gt_to_xe(hwmon->gt));
411
412 switch (type) {
413 case hwmon_power:
414 ret = xe_hwmon_power_read(hwmon, attr, channel, val);
415 break;
92d44a42
BN
416 case hwmon_curr:
417 ret = xe_hwmon_curr_read(hwmon, attr, val);
418 break;
fbcdc9d3
BN
419 case hwmon_in:
420 ret = xe_hwmon_in_read(hwmon, attr, val);
421 break;
fb1b7060
BN
422 default:
423 ret = -EOPNOTSUPP;
424 break;
425 }
426
427 xe_device_mem_access_put(gt_to_xe(hwmon->gt));
428
429 return ret;
430}
431
432static int
433xe_hwmon_write(struct device *dev, enum hwmon_sensor_types type, u32 attr,
434 int channel, long val)
435{
436 struct xe_hwmon *hwmon = dev_get_drvdata(dev);
437 int ret;
438
439 xe_device_mem_access_get(gt_to_xe(hwmon->gt));
440
441 switch (type) {
442 case hwmon_power:
443 ret = xe_hwmon_power_write(hwmon, attr, channel, val);
444 break;
92d44a42
BN
445 case hwmon_curr:
446 ret = xe_hwmon_curr_write(hwmon, attr, val);
447 break;
fb1b7060
BN
448 default:
449 ret = -EOPNOTSUPP;
450 break;
451 }
452
453 xe_device_mem_access_put(gt_to_xe(hwmon->gt));
454
455 return ret;
456}
457
458static const struct hwmon_ops hwmon_ops = {
459 .is_visible = xe_hwmon_is_visible,
460 .read = xe_hwmon_read,
461 .write = xe_hwmon_write,
462};
463
464static const struct hwmon_chip_info hwmon_chip_info = {
465 .ops = &hwmon_ops,
466 .info = hwmon_info,
467};
468
469static void
470xe_hwmon_get_preregistration_info(struct xe_device *xe)
471{
472 struct xe_hwmon *hwmon = xe->hwmon;
473 u32 val_sku_unit = 0;
474 int ret;
475
476 ret = xe_hwmon_process_reg(hwmon, REG_PKG_POWER_SKU_UNIT, REG_READ, &val_sku_unit, 0, 0);
477 /*
478 * The contents of register PKG_POWER_SKU_UNIT do not change,
479 * so read it once and store the shift values.
480 */
481 if (!ret)
482 hwmon->scl_shift_power = REG_FIELD_GET(PKG_PWR_UNIT, val_sku_unit);
483}
484
485void xe_hwmon_register(struct xe_device *xe)
486{
487 struct device *dev = xe->drm.dev;
488 struct xe_hwmon *hwmon;
489
490 /* hwmon is available only for dGfx */
491 if (!IS_DGFX(xe))
492 return;
493
494 hwmon = devm_kzalloc(dev, sizeof(*hwmon), GFP_KERNEL);
495 if (!hwmon)
496 return;
497
498 xe->hwmon = hwmon;
499
500 drmm_mutex_init(&xe->drm, &hwmon->hwmon_lock);
501
502 /* primary GT to access device level properties */
503 hwmon->gt = xe->tiles[0].primary_gt;
504
505 xe_hwmon_get_preregistration_info(xe);
506
507 drm_dbg(&xe->drm, "Register xe hwmon interface\n");
508
509 /* hwmon_dev points to device hwmon<i> */
510 hwmon->hwmon_dev = devm_hwmon_device_register_with_info(dev, "xe", hwmon,
511 &hwmon_chip_info,
512 NULL);
513 if (IS_ERR(hwmon->hwmon_dev)) {
514 drm_warn(&xe->drm, "Failed to register xe hwmon (%pe)\n", hwmon->hwmon_dev);
515 xe->hwmon = NULL;
516 return;
517 }
518}
519