aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/xe/xe_vram_freq.c
blob: c5f6b5a5d1176e516b4dd23db45ce736e04bb5d0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
// SPDX-License-Identifier: MIT
/*
 * Copyright © 2024 Intel Corporation
 */
#include <linux/sysfs.h>
#include <drm/drm_managed.h>

#include "xe_gt_types.h"
#include "xe_pcode.h"
#include "xe_pcode_api.h"
#include "xe_tile.h"
#include "xe_tile_sysfs.h"
#include "xe_vram_freq.h"

/**
 * DOC: Xe VRAM freq
 *
 * Provides sysfs entries for vram frequency in tile
 *
 * device/tile#/memory/freq0/max_freq - This is maximum frequency. This value is read-only as it
 *					is the fixed fuse point P0. It is not the system
 *					configuration.
 * device/tile#/memory/freq0/min_freq - This is minimum frequency. This value is read-only as it
 *					is the fixed fuse point PN. It is not the system
 *					configuration.
 */

static struct xe_tile *dev_to_tile(struct device *dev)
{
	return kobj_to_tile(dev->kobj.parent);
}

static ssize_t max_freq_show(struct device *dev, struct device_attribute *attr,
			     char *buf)
{
	struct xe_tile *tile = dev_to_tile(dev);
	struct xe_gt *gt = tile->primary_gt;
	u32 val, mbox;
	int err;

	mbox = REG_FIELD_PREP(PCODE_MB_COMMAND, PCODE_FREQUENCY_CONFIG)
		| REG_FIELD_PREP(PCODE_MB_PARAM1, PCODE_MBOX_FC_SC_READ_FUSED_P0)
		| REG_FIELD_PREP(PCODE_MB_PARAM2, PCODE_MBOX_DOMAIN_HBM);

	err = xe_pcode_read(gt, mbox, &val, NULL);
	if (err)
		return err;

	/* data_out - Fused P0 for domain ID in units of 50 MHz */
	val *= 50;

	return sysfs_emit(buf, "%u\n", val);
}
static DEVICE_ATTR_RO(max_freq);

static ssize_t min_freq_show(struct device *dev, struct device_attribute *attr,
			     char *buf)
{
	struct xe_tile *tile = dev_to_tile(dev);
	struct xe_gt *gt = tile->primary_gt;
	u32 val, mbox;
	int err;

	mbox = REG_FIELD_PREP(PCODE_MB_COMMAND, PCODE_FREQUENCY_CONFIG)
		| REG_FIELD_PREP(PCODE_MB_PARAM1, PCODE_MBOX_FC_SC_READ_FUSED_PN)
		| REG_FIELD_PREP(PCODE_MB_PARAM2, PCODE_MBOX_DOMAIN_HBM);

	err = xe_pcode_read(gt, mbox, &val, NULL);
	if (err)
		return err;

	/* data_out - Fused Pn for domain ID in units of 50 MHz */
	val *= 50;

	return sysfs_emit(buf, "%u\n", val);
}
static DEVICE_ATTR_RO(min_freq);

static struct attribute *freq_attrs[] = {
	&dev_attr_max_freq.attr,
	&dev_attr_min_freq.attr,
	NULL
};

static const struct attribute_group freq_group_attrs = {
	.name = "freq0",
	.attrs = freq_attrs,
};

static void vram_freq_sysfs_fini(struct drm_device *drm, void *arg)
{
	struct kobject *kobj = arg;

	sysfs_remove_group(kobj, &freq_group_attrs);
	kobject_put(kobj);
}

/**
 * xe_vram_freq_sysfs_init - Initialize vram frequency sysfs component
 * @tile: Xe Tile object
 *
 * It needs to be initialized after the main tile component is ready
 */
void xe_vram_freq_sysfs_init(struct xe_tile *tile)
{
	struct xe_device *xe = tile_to_xe(tile);
	struct kobject *kobj;
	int err;

	if (xe->info.platform != XE_PVC)
		return;

	kobj = kobject_create_and_add("memory", tile->sysfs);
	if (!kobj) {
		drm_warn(&xe->drm, "failed to add memory directory, err: %d\n", -ENOMEM);
		return;
	}

	err = sysfs_create_group(kobj, &freq_group_attrs);
	if (err) {
		kobject_put(kobj);
		drm_warn(&xe->drm, "failed to register vram freq sysfs, err: %d\n", err);
		return;
	}

	err = drmm_add_action_or_reset(&xe->drm, vram_freq_sysfs_fini, kobj);
	if (err)
		drm_warn(&xe->drm, "%s: drmm_add_action_or_reset failed, err: %d\n",
			 __func__, err);
}