Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1// SPDX-License-Identifier: MIT
2/*
3 * Copyright © 2022 Intel Corporation
4 */
5
6#include "xe_step.h"
7
8#include <drm/drm_print.h>
9#include <kunit/visibility.h>
10#include <linux/bitfield.h>
11
12#include "xe_device_types.h"
13#include "xe_platform_types.h"
14
15/*
16 * Provide mapping between PCI's revision ID to the individual GMD
17 * (Graphics/Media/Display) stepping values that can be compared numerically.
18 *
19 * Some platforms may have unusual ways of mapping PCI revision ID to GMD
20 * steppings. E.g., in some cases a higher PCI revision may translate to a
21 * lower stepping of the GT and/or display IP.
22 *
23 * Also note that some revisions/steppings may have been set aside as
24 * placeholders but never materialized in real hardware; in those cases there
25 * may be jumps in the revision IDs or stepping values in the tables below.
26 */
27
28/*
29 * Some platforms always have the same stepping value for GT and display;
30 * use a macro to define these to make it easier to identify the platforms
31 * where the two steppings can deviate.
32 */
33#define COMMON_STEP(x_) \
34 .graphics = STEP_##x_, \
35 .media = STEP_##x_
36
37__diag_push();
38__diag_ignore_all("-Woverride-init", "Allow field overrides in table");
39
40/* Same GT stepping between tgl_uy_revids and tgl_revids don't mean the same HW */
41static const struct xe_step_info tgl_revids[] = {
42 [0] = { COMMON_STEP(A0) },
43 [1] = { COMMON_STEP(B0) },
44};
45
46static const struct xe_step_info dg1_revids[] = {
47 [0] = { COMMON_STEP(A0) },
48 [1] = { COMMON_STEP(B0) },
49};
50
51static const struct xe_step_info adls_revids[] = {
52 [0x0] = { COMMON_STEP(A0) },
53 [0x1] = { COMMON_STEP(A0) },
54 [0x4] = { COMMON_STEP(B0) },
55 [0x8] = { COMMON_STEP(C0) },
56 [0xC] = { COMMON_STEP(D0) },
57};
58
59static const struct xe_step_info adls_rpls_revids[] = {
60 [0x4] = { COMMON_STEP(D0) },
61 [0xC] = { COMMON_STEP(D0) },
62};
63
64static const struct xe_step_info adlp_revids[] = {
65 [0x0] = { COMMON_STEP(A0) },
66 [0x4] = { COMMON_STEP(B0) },
67 [0x8] = { COMMON_STEP(C0) },
68 [0xC] = { COMMON_STEP(C0) },
69};
70
71static const struct xe_step_info adlp_rpl_revids[] = {
72 [0x4] = { COMMON_STEP(C0) },
73};
74
75static const struct xe_step_info adln_revids[] = {
76 [0x0] = { COMMON_STEP(A0) },
77};
78
79static const struct xe_step_info dg2_g10_revid_step_tbl[] = {
80 [0x0] = { COMMON_STEP(A0) },
81 [0x1] = { COMMON_STEP(A1) },
82 [0x4] = { COMMON_STEP(B0) },
83 [0x8] = { COMMON_STEP(C0) },
84};
85
86static const struct xe_step_info dg2_g11_revid_step_tbl[] = {
87 [0x0] = { COMMON_STEP(A0) },
88 [0x4] = { COMMON_STEP(B0) },
89 [0x5] = { COMMON_STEP(B1) },
90};
91
92static const struct xe_step_info dg2_g12_revid_step_tbl[] = {
93 [0x0] = { COMMON_STEP(A0) },
94 [0x1] = { COMMON_STEP(A1) },
95};
96
97static const struct xe_step_info pvc_revid_step_tbl[] = {
98 [0x5] = { .graphics = STEP_B0 },
99 [0x6] = { .graphics = STEP_B1 },
100 [0x7] = { .graphics = STEP_C0 },
101};
102
103static const int pvc_basedie_subids[] = {
104 [0x3] = STEP_B0,
105 [0x4] = STEP_B1,
106 [0x5] = STEP_B3,
107};
108
109__diag_pop();
110
111/**
112 * xe_step_platform_get - Determine platform-level stepping from PCI revid
113 * @xe: Xe device
114 *
115 * Convert the PCI revid into a platform-level stepping value and store that
116 * in the device info.
117 */
118void xe_step_platform_get(struct xe_device *xe)
119{
120 /*
121 * Not all platforms map PCI revid directly into our symbolic stepping
122 * enumeration. Some platforms will have a single PCI revid used for a
123 * range platform level steppings and some might even require specific
124 * mappings. So prefer to err on the side of caution and include only
125 * the platforms from which we need the stepping info for workaround
126 * checks.
127 */
128
129 if (xe->info.platform == XE_NOVALAKE_P)
130 xe->info.step.platform = STEP_A0 + xe->info.revid;
131}
132
133/**
134 * xe_step_pre_gmdid_get - Determine IP steppings from PCI revid
135 * @xe: Xe device
136 *
137 * Convert the PCI revid into proper IP steppings. This should only be
138 * used on platforms that do not have GMD_ID support.
139 */
140void xe_step_pre_gmdid_get(struct xe_device *xe)
141{
142 const struct xe_step_info *revids = NULL;
143 u16 revid = xe->info.revid;
144 int size = 0;
145 const int *basedie_info = NULL;
146 int basedie_size = 0;
147 int baseid = 0;
148 u8 graphics = STEP_NONE;
149 u8 media = STEP_NONE;
150 u8 basedie = STEP_NONE;
151
152 if (xe->info.platform == XE_PVC) {
153 baseid = FIELD_GET(GENMASK(5, 3), xe->info.revid);
154 revid = FIELD_GET(GENMASK(2, 0), xe->info.revid);
155 revids = pvc_revid_step_tbl;
156 size = ARRAY_SIZE(pvc_revid_step_tbl);
157 basedie_info = pvc_basedie_subids;
158 basedie_size = ARRAY_SIZE(pvc_basedie_subids);
159 } else if (xe->info.subplatform == XE_SUBPLATFORM_DG2_G10) {
160 revids = dg2_g10_revid_step_tbl;
161 size = ARRAY_SIZE(dg2_g10_revid_step_tbl);
162 } else if (xe->info.subplatform == XE_SUBPLATFORM_DG2_G11) {
163 revids = dg2_g11_revid_step_tbl;
164 size = ARRAY_SIZE(dg2_g11_revid_step_tbl);
165 } else if (xe->info.subplatform == XE_SUBPLATFORM_DG2_G12) {
166 revids = dg2_g12_revid_step_tbl;
167 size = ARRAY_SIZE(dg2_g12_revid_step_tbl);
168 } else if (xe->info.platform == XE_ALDERLAKE_N) {
169 revids = adln_revids;
170 size = ARRAY_SIZE(adln_revids);
171 } else if (xe->info.subplatform == XE_SUBPLATFORM_ALDERLAKE_S_RPLS) {
172 revids = adls_rpls_revids;
173 size = ARRAY_SIZE(adls_rpls_revids);
174 } else if (xe->info.subplatform == XE_SUBPLATFORM_ALDERLAKE_P_RPLU) {
175 revids = adlp_rpl_revids;
176 size = ARRAY_SIZE(adlp_rpl_revids);
177 } else if (xe->info.platform == XE_ALDERLAKE_P) {
178 revids = adlp_revids;
179 size = ARRAY_SIZE(adlp_revids);
180 } else if (xe->info.platform == XE_ALDERLAKE_S) {
181 revids = adls_revids;
182 size = ARRAY_SIZE(adls_revids);
183 } else if (xe->info.platform == XE_DG1) {
184 revids = dg1_revids;
185 size = ARRAY_SIZE(dg1_revids);
186 } else if (xe->info.platform == XE_TIGERLAKE) {
187 revids = tgl_revids;
188 size = ARRAY_SIZE(tgl_revids);
189 }
190
191 /* Not using the stepping scheme for the platform yet. */
192 if (!revids)
193 goto done;
194
195 if (revid < size && revids[revid].graphics != STEP_NONE) {
196 graphics = revids[revid].graphics;
197 media = revids[revid].media;
198 basedie = revids[revid].basedie;
199 } else {
200 drm_warn(&xe->drm, "Unknown revid 0x%02x\n", revid);
201
202 /*
203 * If we hit a gap in the revid array, use the information for
204 * the next revid.
205 *
206 * This may be wrong in all sorts of ways, especially if the
207 * steppings in the array are not monotonically increasing, but
208 * it's better than defaulting to 0.
209 */
210 while (revid < size && revids[revid].graphics == STEP_NONE)
211 revid++;
212
213 if (revid < size) {
214 drm_dbg(&xe->drm, "Using steppings for revid 0x%02x\n",
215 revid);
216 graphics = revids[revid].graphics;
217 media = revids[revid].media;
218 basedie = revids[revid].basedie;
219 } else {
220 drm_dbg(&xe->drm, "Using future steppings\n");
221 graphics = STEP_FUTURE;
222 }
223 }
224
225 drm_WARN_ON(&xe->drm, graphics == STEP_NONE);
226
227 if (basedie_info && basedie_size) {
228 if (baseid < basedie_size && basedie_info[baseid] != STEP_NONE) {
229 basedie = basedie_info[baseid];
230 } else {
231 drm_warn(&xe->drm, "Unknown baseid 0x%02x\n", baseid);
232 basedie = STEP_FUTURE;
233 }
234 }
235
236done:
237 xe->info.step.graphics = graphics;
238 xe->info.step.media = media;
239 xe->info.step.basedie = basedie;
240}
241
242/**
243 * xe_step_gmdid_get - Determine IP steppings from GMD_ID revid fields
244 * @xe: Xe device
245 * @graphics_gmdid_revid: value of graphics GMD_ID register's revid field
246 * @media_gmdid_revid: value of media GMD_ID register's revid field
247 *
248 * Convert the revid fields of the GMD_ID registers into proper IP steppings.
249 *
250 * GMD_ID revid values are currently expected to have consistent meanings on
251 * all platforms: major steppings (A0, B0, etc.) are 4 apart, with minor
252 * steppings (A1, A2, etc.) taking the values in between.
253 */
254void xe_step_gmdid_get(struct xe_device *xe,
255 u32 graphics_gmdid_revid,
256 u32 media_gmdid_revid)
257{
258 u8 graphics = STEP_A0 + graphics_gmdid_revid;
259 u8 media = STEP_A0 + media_gmdid_revid;
260
261 if (graphics >= STEP_FUTURE) {
262 graphics = STEP_FUTURE;
263 drm_dbg(&xe->drm, "Graphics GMD_ID revid value %d treated as future stepping\n",
264 graphics_gmdid_revid);
265 }
266
267 if (media >= STEP_FUTURE) {
268 media = STEP_FUTURE;
269 drm_dbg(&xe->drm, "Media GMD_ID revid value %d treated as future stepping\n",
270 media_gmdid_revid);
271 }
272
273 xe->info.step.graphics = graphics;
274 xe->info.step.media = media;
275}
276
277#define STEP_NAME_CASE(name) \
278 case STEP_##name: \
279 return #name;
280
281const char *xe_step_name(enum xe_step step)
282{
283 switch (step) {
284 STEP_NAME_LIST(STEP_NAME_CASE);
285
286 default:
287 return "**";
288 }
289}
290EXPORT_SYMBOL_IF_KUNIT(xe_step_name);