Commit | Line | Data |
---|---|---|
94b4f3ba CW |
1 | /* |
2 | * Copyright © 2016 Intel Corporation | |
3 | * | |
4 | * Permission is hereby granted, free of charge, to any person obtaining a | |
5 | * copy of this software and associated documentation files (the "Software"), | |
6 | * to deal in the Software without restriction, including without limitation | |
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
8 | * and/or sell copies of the Software, and to permit persons to whom the | |
9 | * Software is furnished to do so, subject to the following conditions: | |
10 | * | |
11 | * The above copyright notice and this permission notice (including the next | |
12 | * paragraph) shall be included in all copies or substantial portions of the | |
13 | * Software. | |
14 | * | |
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | |
21 | * IN THE SOFTWARE. | |
22 | * | |
23 | */ | |
24 | ||
a8c9b849 MW |
25 | #include <drm/drm_print.h> |
26 | ||
b978520d | 27 | #include "intel_device_info.h" |
94b4f3ba CW |
28 | #include "i915_drv.h" |
29 | ||
2e0d26f8 JN |
30 | #define PLATFORM_NAME(x) [INTEL_##x] = #x |
31 | static const char * const platform_names[] = { | |
32 | PLATFORM_NAME(I830), | |
33 | PLATFORM_NAME(I845G), | |
34 | PLATFORM_NAME(I85X), | |
35 | PLATFORM_NAME(I865G), | |
36 | PLATFORM_NAME(I915G), | |
37 | PLATFORM_NAME(I915GM), | |
38 | PLATFORM_NAME(I945G), | |
39 | PLATFORM_NAME(I945GM), | |
40 | PLATFORM_NAME(G33), | |
41 | PLATFORM_NAME(PINEVIEW), | |
c0f86832 JN |
42 | PLATFORM_NAME(I965G), |
43 | PLATFORM_NAME(I965GM), | |
f69c11ae JN |
44 | PLATFORM_NAME(G45), |
45 | PLATFORM_NAME(GM45), | |
2e0d26f8 JN |
46 | PLATFORM_NAME(IRONLAKE), |
47 | PLATFORM_NAME(SANDYBRIDGE), | |
48 | PLATFORM_NAME(IVYBRIDGE), | |
49 | PLATFORM_NAME(VALLEYVIEW), | |
50 | PLATFORM_NAME(HASWELL), | |
51 | PLATFORM_NAME(BROADWELL), | |
52 | PLATFORM_NAME(CHERRYVIEW), | |
53 | PLATFORM_NAME(SKYLAKE), | |
54 | PLATFORM_NAME(BROXTON), | |
55 | PLATFORM_NAME(KABYLAKE), | |
56 | PLATFORM_NAME(GEMINILAKE), | |
71851fa8 | 57 | PLATFORM_NAME(COFFEELAKE), |
413f3c19 | 58 | PLATFORM_NAME(CANNONLAKE), |
41231001 | 59 | PLATFORM_NAME(ICELAKE), |
897f2961 | 60 | PLATFORM_NAME(ELKHARTLAKE), |
abd3a0fe | 61 | PLATFORM_NAME(TIGERLAKE), |
2e0d26f8 JN |
62 | }; |
63 | #undef PLATFORM_NAME | |
64 | ||
65 | const char *intel_platform_name(enum intel_platform platform) | |
66 | { | |
9160095c JN |
67 | BUILD_BUG_ON(ARRAY_SIZE(platform_names) != INTEL_MAX_PLATFORMS); |
68 | ||
2e0d26f8 JN |
69 | if (WARN_ON_ONCE(platform >= ARRAY_SIZE(platform_names) || |
70 | platform_names[platform] == NULL)) | |
71 | return "<unknown>"; | |
72 | ||
73 | return platform_names[platform]; | |
74 | } | |
75 | ||
72404978 | 76 | static const char *iommu_name(void) |
a8c9b849 | 77 | { |
72404978 CW |
78 | const char *msg = "n/a"; |
79 | ||
80 | #ifdef CONFIG_INTEL_IOMMU | |
81 | msg = enableddisabled(intel_iommu_gfx_mapped); | |
82 | #endif | |
83 | ||
84 | return msg; | |
85 | } | |
86 | ||
87 | void intel_device_info_print_static(const struct intel_device_info *info, | |
88 | struct drm_printer *p) | |
89 | { | |
90 | drm_printf(p, "engines: %x\n", info->engine_mask); | |
91 | drm_printf(p, "gen: %d\n", info->gen); | |
92 | drm_printf(p, "gt: %d\n", info->gt); | |
93 | drm_printf(p, "iommu: %s\n", iommu_name()); | |
94 | drm_printf(p, "memory-regions: %x\n", info->memory_regions); | |
95 | drm_printf(p, "page-sizes: %x\n", info->page_sizes); | |
96 | drm_printf(p, "platform: %s\n", intel_platform_name(info->platform)); | |
97 | drm_printf(p, "ppgtt-size: %d\n", info->ppgtt_size); | |
98 | drm_printf(p, "ppgtt-type: %d\n", info->ppgtt_type); | |
99 | ||
a8c9b849 MW |
100 | #define PRINT_FLAG(name) drm_printf(p, "%s: %s\n", #name, yesno(info->name)); |
101 | DEV_INFO_FOR_EACH_FLAG(PRINT_FLAG); | |
102 | #undef PRINT_FLAG | |
d53db442 JRS |
103 | |
104 | #define PRINT_FLAG(name) drm_printf(p, "%s: %s\n", #name, yesno(info->display.name)); | |
105 | DEV_INFO_DISPLAY_FOR_EACH_FLAG(PRINT_FLAG); | |
106 | #undef PRINT_FLAG | |
a8c9b849 MW |
107 | } |
108 | ||
5fbbe8d4 MW |
109 | static void sseu_dump(const struct sseu_dev_info *sseu, struct drm_printer *p) |
110 | { | |
8cc76693 LL |
111 | int s; |
112 | ||
0ef904bb TU |
113 | drm_printf(p, "slice total: %u, mask=%04x\n", |
114 | hweight8(sseu->slice_mask), sseu->slice_mask); | |
0040fd19 | 115 | drm_printf(p, "subslice total: %u\n", intel_sseu_subslice_total(sseu)); |
0ef904bb | 116 | for (s = 0; s < sseu->max_slices; s++) { |
100f5f7f | 117 | drm_printf(p, "slice%d: %u subslices, mask=%08x\n", |
b5ab1abe | 118 | s, intel_sseu_subslices_per_slice(sseu, s), |
100f5f7f | 119 | intel_sseu_get_subslices(sseu, s)); |
8cc76693 | 120 | } |
5fbbe8d4 MW |
121 | drm_printf(p, "EU total: %u\n", sseu->eu_total); |
122 | drm_printf(p, "EU per subslice: %u\n", sseu->eu_per_subslice); | |
123 | drm_printf(p, "has slice power gating: %s\n", | |
124 | yesno(sseu->has_slice_pg)); | |
125 | drm_printf(p, "has subslice power gating: %s\n", | |
126 | yesno(sseu->has_subslice_pg)); | |
127 | drm_printf(p, "has EU power gating: %s\n", yesno(sseu->has_eu_pg)); | |
128 | } | |
129 | ||
72404978 CW |
130 | void intel_device_info_print_runtime(const struct intel_runtime_info *info, |
131 | struct drm_printer *p) | |
5fbbe8d4 MW |
132 | { |
133 | sseu_dump(&info->sseu, p); | |
134 | ||
135 | drm_printf(p, "CS timestamp frequency: %u kHz\n", | |
136 | info->cs_timestamp_frequency_khz); | |
137 | } | |
138 | ||
0040fd19 SS |
139 | static int sseu_eu_idx(const struct sseu_dev_info *sseu, int slice, |
140 | int subslice) | |
141 | { | |
49610c37 | 142 | int slice_stride = sseu->max_subslices * sseu->eu_stride; |
0040fd19 | 143 | |
49610c37 | 144 | return slice * slice_stride + subslice * sseu->eu_stride; |
0040fd19 SS |
145 | } |
146 | ||
147 | static u16 sseu_get_eus(const struct sseu_dev_info *sseu, int slice, | |
148 | int subslice) | |
149 | { | |
150 | int i, offset = sseu_eu_idx(sseu, slice, subslice); | |
151 | u16 eu_mask = 0; | |
152 | ||
49610c37 | 153 | for (i = 0; i < sseu->eu_stride; i++) { |
0040fd19 SS |
154 | eu_mask |= ((u16)sseu->eu_mask[offset + i]) << |
155 | (i * BITS_PER_BYTE); | |
156 | } | |
157 | ||
158 | return eu_mask; | |
159 | } | |
160 | ||
161 | static void sseu_set_eus(struct sseu_dev_info *sseu, int slice, int subslice, | |
162 | u16 eu_mask) | |
163 | { | |
164 | int i, offset = sseu_eu_idx(sseu, slice, subslice); | |
165 | ||
49610c37 | 166 | for (i = 0; i < sseu->eu_stride; i++) { |
0040fd19 SS |
167 | sseu->eu_mask[offset + i] = |
168 | (eu_mask >> (BITS_PER_BYTE * i)) & 0xff; | |
169 | } | |
170 | } | |
171 | ||
72404978 CW |
172 | void intel_device_info_print_topology(const struct sseu_dev_info *sseu, |
173 | struct drm_printer *p) | |
79e9cd5f LL |
174 | { |
175 | int s, ss; | |
176 | ||
177 | if (sseu->max_slices == 0) { | |
178 | drm_printf(p, "Unavailable\n"); | |
179 | return; | |
180 | } | |
181 | ||
182 | for (s = 0; s < sseu->max_slices; s++) { | |
100f5f7f | 183 | drm_printf(p, "slice%d: %u subslice(s) (0x%08x):\n", |
b5ab1abe | 184 | s, intel_sseu_subslices_per_slice(sseu, s), |
100f5f7f | 185 | intel_sseu_get_subslices(sseu, s)); |
79e9cd5f LL |
186 | |
187 | for (ss = 0; ss < sseu->max_subslices; ss++) { | |
188 | u16 enabled_eus = sseu_get_eus(sseu, s, ss); | |
189 | ||
190 | drm_printf(p, "\tsubslice%d: %u EUs (0x%hx)\n", | |
191 | ss, hweight16(enabled_eus), enabled_eus); | |
192 | } | |
193 | } | |
194 | } | |
195 | ||
8cc76693 LL |
196 | static u16 compute_eu_total(const struct sseu_dev_info *sseu) |
197 | { | |
198 | u16 i, total = 0; | |
199 | ||
200 | for (i = 0; i < ARRAY_SIZE(sseu->eu_mask); i++) | |
201 | total += hweight8(sseu->eu_mask[i]); | |
202 | ||
203 | return total; | |
204 | } | |
205 | ||
601734f7 DCS |
206 | static void gen11_compute_sseu_info(struct sseu_dev_info *sseu, |
207 | u8 s_en, u32 ss_en, u16 eu_en) | |
208 | { | |
209 | int s, ss; | |
210 | ||
211 | /* ss_en represents entire subslice mask across all slices */ | |
212 | GEM_BUG_ON(sseu->max_slices * sseu->max_subslices > | |
213 | sizeof(ss_en) * BITS_PER_BYTE); | |
214 | ||
215 | for (s = 0; s < sseu->max_slices; s++) { | |
216 | if ((s_en & BIT(s)) == 0) | |
217 | continue; | |
218 | ||
219 | sseu->slice_mask |= BIT(s); | |
220 | ||
221 | intel_sseu_set_subslices(sseu, s, ss_en); | |
222 | ||
223 | for (ss = 0; ss < sseu->max_subslices; ss++) | |
224 | if (intel_sseu_has_subslice(sseu, s, ss)) | |
225 | sseu_set_eus(sseu, s, ss, eu_en); | |
226 | } | |
227 | sseu->eu_per_subslice = hweight16(eu_en); | |
228 | sseu->eu_total = compute_eu_total(sseu); | |
229 | } | |
230 | ||
231 | static void gen12_sseu_info_init(struct drm_i915_private *dev_priv) | |
232 | { | |
233 | struct sseu_dev_info *sseu = &RUNTIME_INFO(dev_priv)->sseu; | |
234 | u8 s_en; | |
235 | u32 dss_en; | |
236 | u16 eu_en = 0; | |
237 | u8 eu_en_fuse; | |
238 | int eu; | |
239 | ||
240 | /* | |
241 | * Gen12 has Dual-Subslices, which behave similarly to 2 gen11 SS. | |
242 | * Instead of splitting these, provide userspace with an array | |
243 | * of DSS to more closely represent the hardware resource. | |
244 | */ | |
245 | intel_sseu_set_info(sseu, 1, 6, 16); | |
246 | ||
247 | s_en = I915_READ(GEN11_GT_SLICE_ENABLE) & GEN11_GT_S_ENA_MASK; | |
248 | ||
249 | dss_en = I915_READ(GEN12_GT_DSS_ENABLE); | |
250 | ||
251 | /* one bit per pair of EUs */ | |
252 | eu_en_fuse = ~(I915_READ(GEN11_EU_DISABLE) & GEN11_EU_DIS_MASK); | |
253 | for (eu = 0; eu < sseu->max_eus_per_subslice / 2; eu++) | |
254 | if (eu_en_fuse & BIT(eu)) | |
255 | eu_en |= BIT(eu * 2) | BIT(eu * 2 + 1); | |
256 | ||
257 | gen11_compute_sseu_info(sseu, s_en, dss_en, eu_en); | |
258 | ||
259 | /* TGL only supports slice-level power gating */ | |
260 | sseu->has_slice_pg = 1; | |
261 | } | |
262 | ||
8b5eb5e2 KG |
263 | static void gen11_sseu_info_init(struct drm_i915_private *dev_priv) |
264 | { | |
0258404f | 265 | struct sseu_dev_info *sseu = &RUNTIME_INFO(dev_priv)->sseu; |
8b5eb5e2 | 266 | u8 s_en; |
601734f7 | 267 | u32 ss_en; |
8b5eb5e2 | 268 | u8 eu_en; |
8b5eb5e2 | 269 | |
8b355db9 SS |
270 | if (IS_ELKHARTLAKE(dev_priv)) |
271 | intel_sseu_set_info(sseu, 1, 4, 8); | |
272 | else | |
273 | intel_sseu_set_info(sseu, 1, 8, 8); | |
8b5eb5e2 KG |
274 | |
275 | s_en = I915_READ(GEN11_GT_SLICE_ENABLE) & GEN11_GT_S_ENA_MASK; | |
276 | ss_en = ~I915_READ(GEN11_GT_SUBSLICE_DISABLE); | |
8b5eb5e2 KG |
277 | eu_en = ~(I915_READ(GEN11_EU_DISABLE) & GEN11_EU_DIS_MASK); |
278 | ||
601734f7 | 279 | gen11_compute_sseu_info(sseu, s_en, ss_en, eu_en); |
8b5eb5e2 KG |
280 | |
281 | /* ICL has no power gating restrictions. */ | |
282 | sseu->has_slice_pg = 1; | |
283 | sseu->has_subslice_pg = 1; | |
284 | sseu->has_eu_pg = 1; | |
285 | } | |
286 | ||
4e9767bc BW |
287 | static void gen10_sseu_info_init(struct drm_i915_private *dev_priv) |
288 | { | |
0258404f | 289 | struct sseu_dev_info *sseu = &RUNTIME_INFO(dev_priv)->sseu; |
4e9767bc | 290 | const u32 fuse2 = I915_READ(GEN8_FUSE2); |
8cc76693 LL |
291 | int s, ss; |
292 | const int eu_mask = 0xff; | |
293 | u32 subslice_mask, eu_en; | |
4e9767bc | 294 | |
8b355db9 SS |
295 | intel_sseu_set_info(sseu, 6, 4, 8); |
296 | ||
4e9767bc BW |
297 | sseu->slice_mask = (fuse2 & GEN10_F2_S_ENA_MASK) >> |
298 | GEN10_F2_S_ENA_SHIFT; | |
a10f361d | 299 | |
8cc76693 LL |
300 | /* Slice0 */ |
301 | eu_en = ~I915_READ(GEN8_EU_DISABLE0); | |
302 | for (ss = 0; ss < sseu->max_subslices; ss++) | |
303 | sseu_set_eus(sseu, 0, ss, (eu_en >> (8 * ss)) & eu_mask); | |
304 | /* Slice1 */ | |
305 | sseu_set_eus(sseu, 1, 0, (eu_en >> 24) & eu_mask); | |
306 | eu_en = ~I915_READ(GEN8_EU_DISABLE1); | |
307 | sseu_set_eus(sseu, 1, 1, eu_en & eu_mask); | |
308 | /* Slice2 */ | |
309 | sseu_set_eus(sseu, 2, 0, (eu_en >> 8) & eu_mask); | |
310 | sseu_set_eus(sseu, 2, 1, (eu_en >> 16) & eu_mask); | |
311 | /* Slice3 */ | |
312 | sseu_set_eus(sseu, 3, 0, (eu_en >> 24) & eu_mask); | |
313 | eu_en = ~I915_READ(GEN8_EU_DISABLE2); | |
314 | sseu_set_eus(sseu, 3, 1, eu_en & eu_mask); | |
315 | /* Slice4 */ | |
316 | sseu_set_eus(sseu, 4, 0, (eu_en >> 8) & eu_mask); | |
317 | sseu_set_eus(sseu, 4, 1, (eu_en >> 16) & eu_mask); | |
318 | /* Slice5 */ | |
319 | sseu_set_eus(sseu, 5, 0, (eu_en >> 24) & eu_mask); | |
320 | eu_en = ~I915_READ(GEN10_EU_DISABLE3); | |
321 | sseu_set_eus(sseu, 5, 1, eu_en & eu_mask); | |
322 | ||
33ee9e86 SS |
323 | subslice_mask = (1 << 4) - 1; |
324 | subslice_mask &= ~((fuse2 & GEN10_F2_SS_DIS_MASK) >> | |
325 | GEN10_F2_SS_DIS_SHIFT); | |
326 | ||
8cc76693 | 327 | for (s = 0; s < sseu->max_slices; s++) { |
33ee9e86 SS |
328 | u32 subslice_mask_with_eus = subslice_mask; |
329 | ||
8cc76693 LL |
330 | for (ss = 0; ss < sseu->max_subslices; ss++) { |
331 | if (sseu_get_eus(sseu, s, ss) == 0) | |
33ee9e86 | 332 | subslice_mask_with_eus &= ~BIT(ss); |
8cc76693 | 333 | } |
33ee9e86 SS |
334 | |
335 | /* | |
336 | * Slice0 can have up to 3 subslices, but there are only 2 in | |
337 | * slice1/2. | |
338 | */ | |
9e8a135e SS |
339 | intel_sseu_set_subslices(sseu, s, s == 0 ? |
340 | subslice_mask_with_eus : | |
341 | subslice_mask_with_eus & 0x3); | |
8cc76693 LL |
342 | } |
343 | ||
344 | sseu->eu_total = compute_eu_total(sseu); | |
4e9767bc BW |
345 | |
346 | /* | |
347 | * CNL is expected to always have a uniform distribution | |
348 | * of EU across subslices with the exception that any one | |
349 | * EU in any one subslice may be fused off for die | |
350 | * recovery. | |
351 | */ | |
0040fd19 | 352 | sseu->eu_per_subslice = intel_sseu_subslice_total(sseu) ? |
4e9767bc | 353 | DIV_ROUND_UP(sseu->eu_total, |
0040fd19 SS |
354 | intel_sseu_subslice_total(sseu)) : |
355 | 0; | |
4e9767bc BW |
356 | |
357 | /* No restrictions on Power Gating */ | |
358 | sseu->has_slice_pg = 1; | |
359 | sseu->has_subslice_pg = 1; | |
360 | sseu->has_eu_pg = 1; | |
361 | } | |
362 | ||
94b4f3ba CW |
363 | static void cherryview_sseu_info_init(struct drm_i915_private *dev_priv) |
364 | { | |
0258404f | 365 | struct sseu_dev_info *sseu = &RUNTIME_INFO(dev_priv)->sseu; |
8cc76693 | 366 | u32 fuse; |
33ee9e86 | 367 | u8 subslice_mask = 0; |
94b4f3ba CW |
368 | |
369 | fuse = I915_READ(CHV_FUSE_GT); | |
370 | ||
f08a0c92 | 371 | sseu->slice_mask = BIT(0); |
8b355db9 | 372 | intel_sseu_set_info(sseu, 1, 2, 8); |
94b4f3ba CW |
373 | |
374 | if (!(fuse & CHV_FGT_DISABLE_SS0)) { | |
8cc76693 LL |
375 | u8 disabled_mask = |
376 | ((fuse & CHV_FGT_EU_DIS_SS0_R0_MASK) >> | |
377 | CHV_FGT_EU_DIS_SS0_R0_SHIFT) | | |
378 | (((fuse & CHV_FGT_EU_DIS_SS0_R1_MASK) >> | |
379 | CHV_FGT_EU_DIS_SS0_R1_SHIFT) << 4); | |
380 | ||
33ee9e86 | 381 | subslice_mask |= BIT(0); |
8cc76693 | 382 | sseu_set_eus(sseu, 0, 0, ~disabled_mask); |
94b4f3ba CW |
383 | } |
384 | ||
385 | if (!(fuse & CHV_FGT_DISABLE_SS1)) { | |
8cc76693 LL |
386 | u8 disabled_mask = |
387 | ((fuse & CHV_FGT_EU_DIS_SS1_R0_MASK) >> | |
388 | CHV_FGT_EU_DIS_SS1_R0_SHIFT) | | |
389 | (((fuse & CHV_FGT_EU_DIS_SS1_R1_MASK) >> | |
390 | CHV_FGT_EU_DIS_SS1_R1_SHIFT) << 4); | |
391 | ||
33ee9e86 | 392 | subslice_mask |= BIT(1); |
8cc76693 | 393 | sseu_set_eus(sseu, 0, 1, ~disabled_mask); |
94b4f3ba CW |
394 | } |
395 | ||
9e8a135e | 396 | intel_sseu_set_subslices(sseu, 0, subslice_mask); |
33ee9e86 | 397 | |
8cc76693 LL |
398 | sseu->eu_total = compute_eu_total(sseu); |
399 | ||
94b4f3ba CW |
400 | /* |
401 | * CHV expected to always have a uniform distribution of EU | |
402 | * across subslices. | |
403 | */ | |
0040fd19 SS |
404 | sseu->eu_per_subslice = intel_sseu_subslice_total(sseu) ? |
405 | sseu->eu_total / | |
406 | intel_sseu_subslice_total(sseu) : | |
94b4f3ba CW |
407 | 0; |
408 | /* | |
409 | * CHV supports subslice power gating on devices with more than | |
410 | * one subslice, and supports EU power gating on devices with | |
411 | * more than one EU pair per subslice. | |
412 | */ | |
43b67998 | 413 | sseu->has_slice_pg = 0; |
0040fd19 | 414 | sseu->has_subslice_pg = intel_sseu_subslice_total(sseu) > 1; |
43b67998 | 415 | sseu->has_eu_pg = (sseu->eu_per_subslice > 2); |
94b4f3ba CW |
416 | } |
417 | ||
418 | static void gen9_sseu_info_init(struct drm_i915_private *dev_priv) | |
419 | { | |
420 | struct intel_device_info *info = mkwrite_device_info(dev_priv); | |
0258404f | 421 | struct sseu_dev_info *sseu = &RUNTIME_INFO(dev_priv)->sseu; |
94b4f3ba | 422 | int s, ss; |
8cc76693 LL |
423 | u32 fuse2, eu_disable, subslice_mask; |
424 | const u8 eu_mask = 0xff; | |
94b4f3ba CW |
425 | |
426 | fuse2 = I915_READ(GEN8_FUSE2); | |
f08a0c92 | 427 | sseu->slice_mask = (fuse2 & GEN8_F2_S_ENA_MASK) >> GEN8_F2_S_ENA_SHIFT; |
94b4f3ba | 428 | |
8cc76693 | 429 | /* BXT has a single slice and at most 3 subslices. */ |
8b355db9 SS |
430 | intel_sseu_set_info(sseu, IS_GEN9_LP(dev_priv) ? 1 : 3, |
431 | IS_GEN9_LP(dev_priv) ? 3 : 4, 8); | |
8cc76693 | 432 | |
94b4f3ba CW |
433 | /* |
434 | * The subslice disable field is global, i.e. it applies | |
435 | * to each of the enabled slices. | |
436 | */ | |
8cc76693 LL |
437 | subslice_mask = (1 << sseu->max_subslices) - 1; |
438 | subslice_mask &= ~((fuse2 & GEN9_F2_SS_DIS_MASK) >> | |
439 | GEN9_F2_SS_DIS_SHIFT); | |
94b4f3ba CW |
440 | |
441 | /* | |
442 | * Iterate through enabled slices and subslices to | |
443 | * count the total enabled EU. | |
444 | */ | |
8cc76693 | 445 | for (s = 0; s < sseu->max_slices; s++) { |
f08a0c92 | 446 | if (!(sseu->slice_mask & BIT(s))) |
94b4f3ba CW |
447 | /* skip disabled slice */ |
448 | continue; | |
449 | ||
9e8a135e | 450 | intel_sseu_set_subslices(sseu, s, subslice_mask); |
8cc76693 | 451 | |
94b4f3ba | 452 | eu_disable = I915_READ(GEN9_EU_DISABLE(s)); |
8cc76693 | 453 | for (ss = 0; ss < sseu->max_subslices; ss++) { |
94b4f3ba | 454 | int eu_per_ss; |
8cc76693 | 455 | u8 eu_disabled_mask; |
94b4f3ba | 456 | |
e1210bbf | 457 | if (!intel_sseu_has_subslice(sseu, s, ss)) |
94b4f3ba CW |
458 | /* skip disabled subslice */ |
459 | continue; | |
460 | ||
b3e7f866 | 461 | eu_disabled_mask = (eu_disable >> (ss * 8)) & eu_mask; |
8cc76693 LL |
462 | |
463 | sseu_set_eus(sseu, s, ss, ~eu_disabled_mask); | |
464 | ||
465 | eu_per_ss = sseu->max_eus_per_subslice - | |
466 | hweight8(eu_disabled_mask); | |
94b4f3ba CW |
467 | |
468 | /* | |
469 | * Record which subslice(s) has(have) 7 EUs. we | |
470 | * can tune the hash used to spread work among | |
471 | * subslices if they are unbalanced. | |
472 | */ | |
473 | if (eu_per_ss == 7) | |
43b67998 | 474 | sseu->subslice_7eu[s] |= BIT(ss); |
94b4f3ba CW |
475 | } |
476 | } | |
477 | ||
8cc76693 LL |
478 | sseu->eu_total = compute_eu_total(sseu); |
479 | ||
94b4f3ba CW |
480 | /* |
481 | * SKL is expected to always have a uniform distribution | |
482 | * of EU across subslices with the exception that any one | |
483 | * EU in any one subslice may be fused off for die | |
484 | * recovery. BXT is expected to be perfectly uniform in EU | |
485 | * distribution. | |
486 | */ | |
0040fd19 | 487 | sseu->eu_per_subslice = intel_sseu_subslice_total(sseu) ? |
43b67998 | 488 | DIV_ROUND_UP(sseu->eu_total, |
0040fd19 SS |
489 | intel_sseu_subslice_total(sseu)) : |
490 | 0; | |
94b4f3ba | 491 | /* |
c7ae7e9a | 492 | * SKL+ supports slice power gating on devices with more than |
94b4f3ba | 493 | * one slice, and supports EU power gating on devices with |
c7ae7e9a | 494 | * more than one EU pair per subslice. BXT+ supports subslice |
94b4f3ba CW |
495 | * power gating on devices with more than one subslice, and |
496 | * supports EU power gating on devices with more than one EU | |
497 | * pair per subslice. | |
498 | */ | |
43b67998 | 499 | sseu->has_slice_pg = |
c7ae7e9a | 500 | !IS_GEN9_LP(dev_priv) && hweight8(sseu->slice_mask) > 1; |
43b67998 | 501 | sseu->has_subslice_pg = |
0040fd19 | 502 | IS_GEN9_LP(dev_priv) && intel_sseu_subslice_total(sseu) > 1; |
43b67998 | 503 | sseu->has_eu_pg = sseu->eu_per_subslice > 2; |
94b4f3ba | 504 | |
234516af | 505 | if (IS_GEN9_LP(dev_priv)) { |
8cc76693 LL |
506 | #define IS_SS_DISABLED(ss) (!(sseu->subslice_mask[0] & BIT(ss))) |
507 | info->has_pooled_eu = hweight8(sseu->subslice_mask[0]) == 3; | |
234516af | 508 | |
43b67998 | 509 | sseu->min_eu_in_pool = 0; |
94b4f3ba | 510 | if (info->has_pooled_eu) { |
57ec171e | 511 | if (IS_SS_DISABLED(2) || IS_SS_DISABLED(0)) |
43b67998 | 512 | sseu->min_eu_in_pool = 3; |
57ec171e | 513 | else if (IS_SS_DISABLED(1)) |
43b67998 | 514 | sseu->min_eu_in_pool = 6; |
94b4f3ba | 515 | else |
43b67998 | 516 | sseu->min_eu_in_pool = 9; |
94b4f3ba CW |
517 | } |
518 | #undef IS_SS_DISABLED | |
519 | } | |
520 | } | |
521 | ||
522 | static void broadwell_sseu_info_init(struct drm_i915_private *dev_priv) | |
523 | { | |
0258404f | 524 | struct sseu_dev_info *sseu = &RUNTIME_INFO(dev_priv)->sseu; |
94b4f3ba | 525 | int s, ss; |
8cc76693 | 526 | u32 fuse2, subslice_mask, eu_disable[3]; /* s_max */ |
94b4f3ba CW |
527 | |
528 | fuse2 = I915_READ(GEN8_FUSE2); | |
f08a0c92 | 529 | sseu->slice_mask = (fuse2 & GEN8_F2_S_ENA_MASK) >> GEN8_F2_S_ENA_SHIFT; |
8b355db9 | 530 | intel_sseu_set_info(sseu, 3, 3, 8); |
8cc76693 | 531 | |
57ec171e ID |
532 | /* |
533 | * The subslice disable field is global, i.e. it applies | |
534 | * to each of the enabled slices. | |
535 | */ | |
8cc76693 LL |
536 | subslice_mask = GENMASK(sseu->max_subslices - 1, 0); |
537 | subslice_mask &= ~((fuse2 & GEN8_F2_SS_DIS_MASK) >> | |
538 | GEN8_F2_SS_DIS_SHIFT); | |
94b4f3ba CW |
539 | |
540 | eu_disable[0] = I915_READ(GEN8_EU_DISABLE0) & GEN8_EU_DIS0_S0_MASK; | |
541 | eu_disable[1] = (I915_READ(GEN8_EU_DISABLE0) >> GEN8_EU_DIS0_S1_SHIFT) | | |
542 | ((I915_READ(GEN8_EU_DISABLE1) & GEN8_EU_DIS1_S1_MASK) << | |
543 | (32 - GEN8_EU_DIS0_S1_SHIFT)); | |
544 | eu_disable[2] = (I915_READ(GEN8_EU_DISABLE1) >> GEN8_EU_DIS1_S2_SHIFT) | | |
545 | ((I915_READ(GEN8_EU_DISABLE2) & GEN8_EU_DIS2_S2_MASK) << | |
546 | (32 - GEN8_EU_DIS1_S2_SHIFT)); | |
547 | ||
94b4f3ba CW |
548 | /* |
549 | * Iterate through enabled slices and subslices to | |
550 | * count the total enabled EU. | |
551 | */ | |
8cc76693 | 552 | for (s = 0; s < sseu->max_slices; s++) { |
f08a0c92 | 553 | if (!(sseu->slice_mask & BIT(s))) |
94b4f3ba CW |
554 | /* skip disabled slice */ |
555 | continue; | |
556 | ||
9e8a135e | 557 | intel_sseu_set_subslices(sseu, s, subslice_mask); |
8cc76693 LL |
558 | |
559 | for (ss = 0; ss < sseu->max_subslices; ss++) { | |
560 | u8 eu_disabled_mask; | |
94b4f3ba CW |
561 | u32 n_disabled; |
562 | ||
e1210bbf | 563 | if (!intel_sseu_has_subslice(sseu, s, ss)) |
94b4f3ba CW |
564 | /* skip disabled subslice */ |
565 | continue; | |
566 | ||
8cc76693 | 567 | eu_disabled_mask = |
a10f361d | 568 | eu_disable[s] >> (ss * sseu->max_eus_per_subslice); |
8cc76693 LL |
569 | |
570 | sseu_set_eus(sseu, s, ss, ~eu_disabled_mask); | |
571 | ||
572 | n_disabled = hweight8(eu_disabled_mask); | |
94b4f3ba CW |
573 | |
574 | /* | |
575 | * Record which subslices have 7 EUs. | |
576 | */ | |
8cc76693 | 577 | if (sseu->max_eus_per_subslice - n_disabled == 7) |
43b67998 | 578 | sseu->subslice_7eu[s] |= 1 << ss; |
94b4f3ba CW |
579 | } |
580 | } | |
581 | ||
8cc76693 LL |
582 | sseu->eu_total = compute_eu_total(sseu); |
583 | ||
94b4f3ba CW |
584 | /* |
585 | * BDW is expected to always have a uniform distribution of EU across | |
586 | * subslices with the exception that any one EU in any one subslice may | |
587 | * be fused off for die recovery. | |
588 | */ | |
0040fd19 | 589 | sseu->eu_per_subslice = intel_sseu_subslice_total(sseu) ? |
57ec171e | 590 | DIV_ROUND_UP(sseu->eu_total, |
0040fd19 SS |
591 | intel_sseu_subslice_total(sseu)) : |
592 | 0; | |
94b4f3ba CW |
593 | |
594 | /* | |
595 | * BDW supports slice power gating on devices with more than | |
596 | * one slice. | |
597 | */ | |
f08a0c92 | 598 | sseu->has_slice_pg = hweight8(sseu->slice_mask) > 1; |
43b67998 ID |
599 | sseu->has_subslice_pg = 0; |
600 | sseu->has_eu_pg = 0; | |
94b4f3ba CW |
601 | } |
602 | ||
b8ec759e LL |
603 | static void haswell_sseu_info_init(struct drm_i915_private *dev_priv) |
604 | { | |
0258404f | 605 | struct sseu_dev_info *sseu = &RUNTIME_INFO(dev_priv)->sseu; |
b8ec759e | 606 | u32 fuse1; |
33ee9e86 | 607 | u8 subslice_mask = 0; |
8cc76693 | 608 | int s, ss; |
b8ec759e LL |
609 | |
610 | /* | |
611 | * There isn't a register to tell us how many slices/subslices. We | |
612 | * work off the PCI-ids here. | |
613 | */ | |
0258404f | 614 | switch (INTEL_INFO(dev_priv)->gt) { |
b8ec759e | 615 | default: |
0258404f | 616 | MISSING_CASE(INTEL_INFO(dev_priv)->gt); |
b8ec759e LL |
617 | /* fall through */ |
618 | case 1: | |
619 | sseu->slice_mask = BIT(0); | |
33ee9e86 | 620 | subslice_mask = BIT(0); |
b8ec759e LL |
621 | break; |
622 | case 2: | |
623 | sseu->slice_mask = BIT(0); | |
33ee9e86 | 624 | subslice_mask = BIT(0) | BIT(1); |
b8ec759e LL |
625 | break; |
626 | case 3: | |
627 | sseu->slice_mask = BIT(0) | BIT(1); | |
33ee9e86 | 628 | subslice_mask = BIT(0) | BIT(1); |
b8ec759e LL |
629 | break; |
630 | } | |
631 | ||
632 | fuse1 = I915_READ(HSW_PAVP_FUSE1); | |
633 | switch ((fuse1 & HSW_F1_EU_DIS_MASK) >> HSW_F1_EU_DIS_SHIFT) { | |
634 | default: | |
635 | MISSING_CASE((fuse1 & HSW_F1_EU_DIS_MASK) >> | |
636 | HSW_F1_EU_DIS_SHIFT); | |
637 | /* fall through */ | |
638 | case HSW_F1_EU_DIS_10EUS: | |
639 | sseu->eu_per_subslice = 10; | |
640 | break; | |
641 | case HSW_F1_EU_DIS_8EUS: | |
642 | sseu->eu_per_subslice = 8; | |
643 | break; | |
644 | case HSW_F1_EU_DIS_6EUS: | |
645 | sseu->eu_per_subslice = 6; | |
646 | break; | |
647 | } | |
8b355db9 SS |
648 | |
649 | intel_sseu_set_info(sseu, hweight8(sseu->slice_mask), | |
33ee9e86 | 650 | hweight8(subslice_mask), |
8b355db9 | 651 | sseu->eu_per_subslice); |
8cc76693 LL |
652 | |
653 | for (s = 0; s < sseu->max_slices; s++) { | |
9e8a135e | 654 | intel_sseu_set_subslices(sseu, s, subslice_mask); |
33ee9e86 | 655 | |
8cc76693 LL |
656 | for (ss = 0; ss < sseu->max_subslices; ss++) { |
657 | sseu_set_eus(sseu, s, ss, | |
658 | (1UL << sseu->eu_per_subslice) - 1); | |
659 | } | |
660 | } | |
b8ec759e | 661 | |
8cc76693 | 662 | sseu->eu_total = compute_eu_total(sseu); |
b8ec759e LL |
663 | |
664 | /* No powergating for you. */ | |
665 | sseu->has_slice_pg = 0; | |
666 | sseu->has_subslice_pg = 0; | |
667 | sseu->has_eu_pg = 0; | |
668 | } | |
669 | ||
f577a03b | 670 | static u32 read_reference_ts_freq(struct drm_i915_private *dev_priv) |
dab91783 LL |
671 | { |
672 | u32 ts_override = I915_READ(GEN9_TIMESTAMP_OVERRIDE); | |
f577a03b | 673 | u32 base_freq, frac_freq; |
dab91783 LL |
674 | |
675 | base_freq = ((ts_override & GEN9_TIMESTAMP_OVERRIDE_US_COUNTER_DIVIDER_MASK) >> | |
676 | GEN9_TIMESTAMP_OVERRIDE_US_COUNTER_DIVIDER_SHIFT) + 1; | |
f577a03b | 677 | base_freq *= 1000; |
dab91783 LL |
678 | |
679 | frac_freq = ((ts_override & | |
680 | GEN9_TIMESTAMP_OVERRIDE_US_COUNTER_DENOMINATOR_MASK) >> | |
681 | GEN9_TIMESTAMP_OVERRIDE_US_COUNTER_DENOMINATOR_SHIFT); | |
f577a03b | 682 | frac_freq = 1000 / (frac_freq + 1); |
dab91783 LL |
683 | |
684 | return base_freq + frac_freq; | |
685 | } | |
686 | ||
d775a7b1 PZ |
687 | static u32 gen10_get_crystal_clock_freq(struct drm_i915_private *dev_priv, |
688 | u32 rpm_config_reg) | |
689 | { | |
690 | u32 f19_2_mhz = 19200; | |
691 | u32 f24_mhz = 24000; | |
692 | u32 crystal_clock = (rpm_config_reg & | |
693 | GEN9_RPM_CONFIG0_CRYSTAL_CLOCK_FREQ_MASK) >> | |
694 | GEN9_RPM_CONFIG0_CRYSTAL_CLOCK_FREQ_SHIFT; | |
695 | ||
696 | switch (crystal_clock) { | |
697 | case GEN9_RPM_CONFIG0_CRYSTAL_CLOCK_FREQ_19_2_MHZ: | |
698 | return f19_2_mhz; | |
699 | case GEN9_RPM_CONFIG0_CRYSTAL_CLOCK_FREQ_24_MHZ: | |
700 | return f24_mhz; | |
701 | default: | |
702 | MISSING_CASE(crystal_clock); | |
703 | return 0; | |
704 | } | |
705 | } | |
706 | ||
707 | static u32 gen11_get_crystal_clock_freq(struct drm_i915_private *dev_priv, | |
708 | u32 rpm_config_reg) | |
709 | { | |
710 | u32 f19_2_mhz = 19200; | |
711 | u32 f24_mhz = 24000; | |
712 | u32 f25_mhz = 25000; | |
713 | u32 f38_4_mhz = 38400; | |
714 | u32 crystal_clock = (rpm_config_reg & | |
715 | GEN11_RPM_CONFIG0_CRYSTAL_CLOCK_FREQ_MASK) >> | |
716 | GEN11_RPM_CONFIG0_CRYSTAL_CLOCK_FREQ_SHIFT; | |
717 | ||
718 | switch (crystal_clock) { | |
719 | case GEN11_RPM_CONFIG0_CRYSTAL_CLOCK_FREQ_24_MHZ: | |
720 | return f24_mhz; | |
721 | case GEN11_RPM_CONFIG0_CRYSTAL_CLOCK_FREQ_19_2_MHZ: | |
722 | return f19_2_mhz; | |
723 | case GEN11_RPM_CONFIG0_CRYSTAL_CLOCK_FREQ_38_4_MHZ: | |
724 | return f38_4_mhz; | |
725 | case GEN11_RPM_CONFIG0_CRYSTAL_CLOCK_FREQ_25_MHZ: | |
726 | return f25_mhz; | |
727 | default: | |
728 | MISSING_CASE(crystal_clock); | |
729 | return 0; | |
730 | } | |
731 | } | |
732 | ||
f577a03b | 733 | static u32 read_timestamp_frequency(struct drm_i915_private *dev_priv) |
dab91783 | 734 | { |
f577a03b LL |
735 | u32 f12_5_mhz = 12500; |
736 | u32 f19_2_mhz = 19200; | |
737 | u32 f24_mhz = 24000; | |
dab91783 LL |
738 | |
739 | if (INTEL_GEN(dev_priv) <= 4) { | |
740 | /* PRMs say: | |
741 | * | |
742 | * "The value in this register increments once every 16 | |
743 | * hclks." (through the “Clocking Configuration” | |
744 | * (“CLKCFG”) MCHBAR register) | |
745 | */ | |
f577a03b | 746 | return dev_priv->rawclk_freq / 16; |
dab91783 LL |
747 | } else if (INTEL_GEN(dev_priv) <= 8) { |
748 | /* PRMs say: | |
749 | * | |
750 | * "The PCU TSC counts 10ns increments; this timestamp | |
751 | * reflects bits 38:3 of the TSC (i.e. 80ns granularity, | |
752 | * rolling over every 1.5 hours). | |
753 | */ | |
754 | return f12_5_mhz; | |
755 | } else if (INTEL_GEN(dev_priv) <= 9) { | |
756 | u32 ctc_reg = I915_READ(CTC_MODE); | |
f577a03b | 757 | u32 freq = 0; |
dab91783 LL |
758 | |
759 | if ((ctc_reg & CTC_SOURCE_PARAMETER_MASK) == CTC_SOURCE_DIVIDE_LOGIC) { | |
760 | freq = read_reference_ts_freq(dev_priv); | |
761 | } else { | |
762 | freq = IS_GEN9_LP(dev_priv) ? f19_2_mhz : f24_mhz; | |
763 | ||
764 | /* Now figure out how the command stream's timestamp | |
765 | * register increments from this frequency (it might | |
766 | * increment only every few clock cycle). | |
767 | */ | |
768 | freq >>= 3 - ((ctc_reg & CTC_SHIFT_PARAMETER_MASK) >> | |
769 | CTC_SHIFT_PARAMETER_SHIFT); | |
770 | } | |
771 | ||
772 | return freq; | |
465242ee | 773 | } else if (INTEL_GEN(dev_priv) <= 12) { |
dab91783 | 774 | u32 ctc_reg = I915_READ(CTC_MODE); |
f577a03b | 775 | u32 freq = 0; |
dab91783 LL |
776 | |
777 | /* First figure out the reference frequency. There are 2 ways | |
778 | * we can compute the frequency, either through the | |
779 | * TIMESTAMP_OVERRIDE register or through RPM_CONFIG. CTC_MODE | |
780 | * tells us which one we should use. | |
781 | */ | |
782 | if ((ctc_reg & CTC_SOURCE_PARAMETER_MASK) == CTC_SOURCE_DIVIDE_LOGIC) { | |
783 | freq = read_reference_ts_freq(dev_priv); | |
784 | } else { | |
d775a7b1 PZ |
785 | u32 rpm_config_reg = I915_READ(RPM_CONFIG0); |
786 | ||
787 | if (INTEL_GEN(dev_priv) <= 10) | |
788 | freq = gen10_get_crystal_clock_freq(dev_priv, | |
789 | rpm_config_reg); | |
790 | else | |
791 | freq = gen11_get_crystal_clock_freq(dev_priv, | |
792 | rpm_config_reg); | |
dab91783 | 793 | |
53ff2641 LL |
794 | /* Now figure out how the command stream's timestamp |
795 | * register increments from this frequency (it might | |
796 | * increment only every few clock cycle). | |
797 | */ | |
798 | freq >>= 3 - ((rpm_config_reg & | |
799 | GEN10_RPM_CONFIG0_CTC_SHIFT_PARAMETER_MASK) >> | |
800 | GEN10_RPM_CONFIG0_CTC_SHIFT_PARAMETER_SHIFT); | |
801 | } | |
dab91783 LL |
802 | |
803 | return freq; | |
804 | } | |
805 | ||
fe66e928 | 806 | MISSING_CASE("Unknown gen, unable to read command streamer timestamp frequency\n"); |
dab91783 LL |
807 | return 0; |
808 | } | |
809 | ||
805446c8 TU |
810 | #undef INTEL_VGA_DEVICE |
811 | #define INTEL_VGA_DEVICE(id, info) (id) | |
812 | ||
813 | static const u16 subplatform_ult_ids[] = { | |
814 | INTEL_HSW_ULT_GT1_IDS(0), | |
815 | INTEL_HSW_ULT_GT2_IDS(0), | |
816 | INTEL_HSW_ULT_GT3_IDS(0), | |
817 | INTEL_BDW_ULT_GT1_IDS(0), | |
818 | INTEL_BDW_ULT_GT2_IDS(0), | |
819 | INTEL_BDW_ULT_GT3_IDS(0), | |
820 | INTEL_BDW_ULT_RSVD_IDS(0), | |
821 | INTEL_SKL_ULT_GT1_IDS(0), | |
822 | INTEL_SKL_ULT_GT2_IDS(0), | |
823 | INTEL_SKL_ULT_GT3_IDS(0), | |
824 | INTEL_KBL_ULT_GT1_IDS(0), | |
825 | INTEL_KBL_ULT_GT2_IDS(0), | |
826 | INTEL_KBL_ULT_GT3_IDS(0), | |
827 | INTEL_CFL_U_GT2_IDS(0), | |
828 | INTEL_CFL_U_GT3_IDS(0), | |
829 | INTEL_WHL_U_GT1_IDS(0), | |
830 | INTEL_WHL_U_GT2_IDS(0), | |
c3ad8d29 | 831 | INTEL_WHL_U_GT3_IDS(0), |
805446c8 TU |
832 | }; |
833 | ||
834 | static const u16 subplatform_ulx_ids[] = { | |
835 | INTEL_HSW_ULX_GT1_IDS(0), | |
836 | INTEL_HSW_ULX_GT2_IDS(0), | |
837 | INTEL_BDW_ULX_GT1_IDS(0), | |
838 | INTEL_BDW_ULX_GT2_IDS(0), | |
839 | INTEL_BDW_ULX_GT3_IDS(0), | |
840 | INTEL_BDW_ULX_RSVD_IDS(0), | |
841 | INTEL_SKL_ULX_GT1_IDS(0), | |
842 | INTEL_SKL_ULX_GT2_IDS(0), | |
843 | INTEL_KBL_ULX_GT1_IDS(0), | |
c3ad8d29 | 844 | INTEL_KBL_ULX_GT2_IDS(0), |
805446c8 | 845 | INTEL_AML_KBL_GT2_IDS(0), |
c3ad8d29 | 846 | INTEL_AML_CFL_GT2_IDS(0), |
805446c8 TU |
847 | }; |
848 | ||
849 | static const u16 subplatform_portf_ids[] = { | |
850 | INTEL_CNL_PORT_F_IDS(0), | |
c3ad8d29 | 851 | INTEL_ICL_PORT_F_IDS(0), |
805446c8 TU |
852 | }; |
853 | ||
854 | static bool find_devid(u16 id, const u16 *p, unsigned int num) | |
855 | { | |
856 | for (; num; num--, p++) { | |
857 | if (*p == id) | |
858 | return true; | |
859 | } | |
860 | ||
861 | return false; | |
862 | } | |
863 | ||
864 | void intel_device_info_subplatform_init(struct drm_i915_private *i915) | |
865 | { | |
866 | const struct intel_device_info *info = INTEL_INFO(i915); | |
867 | const struct intel_runtime_info *rinfo = RUNTIME_INFO(i915); | |
868 | const unsigned int pi = __platform_mask_index(rinfo, info->platform); | |
869 | const unsigned int pb = __platform_mask_bit(rinfo, info->platform); | |
870 | u16 devid = INTEL_DEVID(i915); | |
640cde65 | 871 | u32 mask = 0; |
805446c8 TU |
872 | |
873 | /* Make sure IS_<platform> checks are working. */ | |
874 | RUNTIME_INFO(i915)->platform_mask[pi] = BIT(pb); | |
875 | ||
876 | /* Find and mark subplatform bits based on the PCI device id. */ | |
877 | if (find_devid(devid, subplatform_ult_ids, | |
878 | ARRAY_SIZE(subplatform_ult_ids))) { | |
879 | mask = BIT(INTEL_SUBPLATFORM_ULT); | |
880 | } else if (find_devid(devid, subplatform_ulx_ids, | |
881 | ARRAY_SIZE(subplatform_ulx_ids))) { | |
882 | mask = BIT(INTEL_SUBPLATFORM_ULX); | |
883 | if (IS_HASWELL(i915) || IS_BROADWELL(i915)) { | |
884 | /* ULX machines are also considered ULT. */ | |
885 | mask |= BIT(INTEL_SUBPLATFORM_ULT); | |
886 | } | |
805446c8 TU |
887 | } else if (find_devid(devid, subplatform_portf_ids, |
888 | ARRAY_SIZE(subplatform_portf_ids))) { | |
889 | mask = BIT(INTEL_SUBPLATFORM_PORTF); | |
890 | } | |
891 | ||
892 | GEM_BUG_ON(mask & ~INTEL_SUBPLATFORM_BITS); | |
893 | ||
894 | RUNTIME_INFO(i915)->platform_mask[pi] |= mask; | |
895 | } | |
896 | ||
6a7e51f3 MW |
897 | /** |
898 | * intel_device_info_runtime_init - initialize runtime info | |
963cc126 | 899 | * @dev_priv: the i915 device |
6a7e51f3 | 900 | * |
94b4f3ba CW |
901 | * Determine various intel_device_info fields at runtime. |
902 | * | |
903 | * Use it when either: | |
904 | * - it's judged too laborious to fill n static structures with the limit | |
905 | * when a simple if statement does the job, | |
906 | * - run-time checks (eg read fuse/strap registers) are needed. | |
907 | * | |
908 | * This function needs to be called: | |
909 | * - after the MMIO has been setup as we are reading registers, | |
910 | * - after the PCH has been detected, | |
911 | * - before the first usage of the fields it can tweak. | |
912 | */ | |
1400cc7e | 913 | void intel_device_info_runtime_init(struct drm_i915_private *dev_priv) |
94b4f3ba | 914 | { |
1400cc7e | 915 | struct intel_device_info *info = mkwrite_device_info(dev_priv); |
0258404f | 916 | struct intel_runtime_info *runtime = RUNTIME_INFO(dev_priv); |
94b4f3ba CW |
917 | enum pipe pipe; |
918 | ||
6e7406db MK |
919 | if (INTEL_GEN(dev_priv) >= 10) { |
920 | for_each_pipe(dev_priv, pipe) | |
0258404f | 921 | runtime->num_scalers[pipe] = 2; |
cf819eff | 922 | } else if (IS_GEN(dev_priv, 9)) { |
0258404f JN |
923 | runtime->num_scalers[PIPE_A] = 2; |
924 | runtime->num_scalers[PIPE_B] = 2; | |
925 | runtime->num_scalers[PIPE_C] = 1; | |
0bf0230e ACO |
926 | } |
927 | ||
8a68d464 | 928 | BUILD_BUG_ON(BITS_PER_TYPE(intel_engine_mask_t) < I915_NUM_ENGINES); |
022d3093 | 929 | |
2dd24a9c | 930 | if (INTEL_GEN(dev_priv) >= 11) |
6711bd73 | 931 | for_each_pipe(dev_priv, pipe) |
0258404f | 932 | runtime->num_sprites[pipe] = 6; |
cf819eff | 933 | else if (IS_GEN(dev_priv, 10) || IS_GEMINILAKE(dev_priv)) |
e9c98825 | 934 | for_each_pipe(dev_priv, pipe) |
0258404f | 935 | runtime->num_sprites[pipe] = 3; |
e9c98825 | 936 | else if (IS_BROXTON(dev_priv)) { |
6711bd73 ML |
937 | /* |
938 | * Skylake and Broxton currently don't expose the topmost plane as its | |
939 | * use is exclusive with the legacy cursor and we only want to expose | |
940 | * one of those, not both. Until we can safely expose the topmost plane | |
941 | * as a DRM_PLANE_TYPE_CURSOR with all the features exposed/supported, | |
942 | * we don't expose the topmost plane at all to prevent ABI breakage | |
943 | * down the line. | |
944 | */ | |
945 | ||
0258404f JN |
946 | runtime->num_sprites[PIPE_A] = 2; |
947 | runtime->num_sprites[PIPE_B] = 2; | |
948 | runtime->num_sprites[PIPE_C] = 1; | |
33edc24d | 949 | } else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) { |
94b4f3ba | 950 | for_each_pipe(dev_priv, pipe) |
0258404f | 951 | runtime->num_sprites[pipe] = 2; |
ab33081a | 952 | } else if (INTEL_GEN(dev_priv) >= 5 || IS_G4X(dev_priv)) { |
94b4f3ba | 953 | for_each_pipe(dev_priv, pipe) |
0258404f | 954 | runtime->num_sprites[pipe] = 1; |
33edc24d | 955 | } |
94b4f3ba | 956 | |
ef404bc6 JN |
957 | if (HAS_DISPLAY(dev_priv) && IS_GEN_RANGE(dev_priv, 7, 8) && |
958 | HAS_PCH_SPLIT(dev_priv)) { | |
94b4f3ba CW |
959 | u32 fuse_strap = I915_READ(FUSE_STRAP); |
960 | u32 sfuse_strap = I915_READ(SFUSE_STRAP); | |
961 | ||
962 | /* | |
963 | * SFUSE_STRAP is supposed to have a bit signalling the display | |
964 | * is fused off. Unfortunately it seems that, at least in | |
965 | * certain cases, fused off display means that PCH display | |
966 | * reads don't land anywhere. In that case, we read 0s. | |
967 | * | |
968 | * On CPT/PPT, we can detect this case as SFUSE_STRAP_FUSE_LOCK | |
969 | * should be set when taking over after the firmware. | |
970 | */ | |
971 | if (fuse_strap & ILK_INTERNAL_DISPLAY_DISABLE || | |
972 | sfuse_strap & SFUSE_STRAP_DISPLAY_DISABLED || | |
b9eb89b2 | 973 | (HAS_PCH_CPT(dev_priv) && |
94b4f3ba CW |
974 | !(sfuse_strap & SFUSE_STRAP_FUSE_LOCK))) { |
975 | DRM_INFO("Display fused off, disabling\n"); | |
8d8b0031 | 976 | info->pipe_mask = 0; |
94b4f3ba CW |
977 | } else if (fuse_strap & IVB_PIPE_C_DISABLE) { |
978 | DRM_INFO("PipeC fused off\n"); | |
8d8b0031 | 979 | info->pipe_mask &= ~BIT(PIPE_C); |
94b4f3ba | 980 | } |
bea68f4a | 981 | } else if (HAS_DISPLAY(dev_priv) && INTEL_GEN(dev_priv) >= 9) { |
94b4f3ba | 982 | u32 dfsm = I915_READ(SKL_DFSM); |
8d8b0031 | 983 | u8 enabled_mask = info->pipe_mask; |
94b4f3ba CW |
984 | |
985 | if (dfsm & SKL_DFSM_PIPE_A_DISABLE) | |
501ec325 | 986 | enabled_mask &= ~BIT(PIPE_A); |
94b4f3ba | 987 | if (dfsm & SKL_DFSM_PIPE_B_DISABLE) |
501ec325 | 988 | enabled_mask &= ~BIT(PIPE_B); |
94b4f3ba | 989 | if (dfsm & SKL_DFSM_PIPE_C_DISABLE) |
501ec325 | 990 | enabled_mask &= ~BIT(PIPE_C); |
7ff0fca4 JRS |
991 | if (INTEL_GEN(dev_priv) >= 12 && |
992 | (dfsm & TGL_DFSM_PIPE_D_DISABLE)) | |
993 | enabled_mask &= ~BIT(PIPE_D); | |
94b4f3ba | 994 | |
501ec325 LDM |
995 | /* |
996 | * At least one pipe should be enabled and if there are | |
997 | * disabled pipes, they should be the last ones, with no holes | |
998 | * in the mask. | |
999 | */ | |
1000 | if (enabled_mask == 0 || !is_power_of_2(enabled_mask + 1)) | |
1001 | DRM_ERROR("invalid pipe fuse configuration: enabled_mask=0x%x\n", | |
1002 | enabled_mask); | |
94b4f3ba | 1003 | else |
8d8b0031 | 1004 | info->pipe_mask = enabled_mask; |
74393109 JRS |
1005 | |
1006 | if (dfsm & SKL_DFSM_DISPLAY_HDCP_DISABLE) | |
1007 | info->display.has_hdcp = 0; | |
7a40aac1 JRS |
1008 | |
1009 | if (dfsm & SKL_DFSM_DISPLAY_PM_DISABLE) | |
1010 | info->display.has_fbc = 0; | |
ee595888 JRS |
1011 | |
1012 | if (INTEL_GEN(dev_priv) >= 11 && (dfsm & ICL_DFSM_DMC_DISABLE)) | |
1013 | info->display.has_csr = 0; | |
0f9ed3b2 JRS |
1014 | |
1015 | if (INTEL_GEN(dev_priv) >= 10 && | |
1016 | (dfsm & CNL_DFSM_DISPLAY_DSC_DISABLE)) | |
1017 | info->display.has_dsc = 0; | |
94b4f3ba CW |
1018 | } |
1019 | ||
1020 | /* Initialize slice/subslice/EU info */ | |
b8ec759e LL |
1021 | if (IS_HASWELL(dev_priv)) |
1022 | haswell_sseu_info_init(dev_priv); | |
1023 | else if (IS_CHERRYVIEW(dev_priv)) | |
94b4f3ba CW |
1024 | cherryview_sseu_info_init(dev_priv); |
1025 | else if (IS_BROADWELL(dev_priv)) | |
1026 | broadwell_sseu_info_init(dev_priv); | |
cf819eff | 1027 | else if (IS_GEN(dev_priv, 9)) |
94b4f3ba | 1028 | gen9_sseu_info_init(dev_priv); |
cf819eff | 1029 | else if (IS_GEN(dev_priv, 10)) |
4e9767bc | 1030 | gen10_sseu_info_init(dev_priv); |
601734f7 | 1031 | else if (IS_GEN(dev_priv, 11)) |
8b5eb5e2 | 1032 | gen11_sseu_info_init(dev_priv); |
601734f7 DCS |
1033 | else if (INTEL_GEN(dev_priv) >= 12) |
1034 | gen12_sseu_info_init(dev_priv); | |
94b4f3ba | 1035 | |
cf819eff | 1036 | if (IS_GEN(dev_priv, 6) && intel_vtd_active()) { |
4bdafb9d | 1037 | DRM_INFO("Disabling ppGTT for VT-d support\n"); |
cbecbcca | 1038 | info->ppgtt_type = INTEL_PPGTT_NONE; |
4bdafb9d CW |
1039 | } |
1040 | ||
dab91783 | 1041 | /* Initialize command stream timestamp frequency */ |
0258404f | 1042 | runtime->cs_timestamp_frequency_khz = read_timestamp_frequency(dev_priv); |
94b4f3ba | 1043 | } |
3fed1808 CW |
1044 | |
1045 | void intel_driver_caps_print(const struct intel_driver_caps *caps, | |
1046 | struct drm_printer *p) | |
1047 | { | |
481827b4 CW |
1048 | drm_printf(p, "Has logical contexts? %s\n", |
1049 | yesno(caps->has_logical_contexts)); | |
3fed1808 CW |
1050 | drm_printf(p, "scheduler: %x\n", caps->scheduler); |
1051 | } | |
26376a7e OM |
1052 | |
1053 | /* | |
1054 | * Determine which engines are fused off in our particular hardware. Since the | |
1055 | * fuse register is in the blitter powerwell, we need forcewake to be ready at | |
1056 | * this point (but later we need to prune the forcewake domains for engines that | |
1057 | * are indeed fused off). | |
1058 | */ | |
1059 | void intel_device_info_init_mmio(struct drm_i915_private *dev_priv) | |
1060 | { | |
1061 | struct intel_device_info *info = mkwrite_device_info(dev_priv); | |
57b19d55 | 1062 | unsigned int logical_vdbox = 0; |
9213e4f5 | 1063 | unsigned int i; |
57b19d55 | 1064 | u32 media_fuse; |
97ee6e92 DCS |
1065 | u16 vdbox_mask; |
1066 | u16 vebox_mask; | |
26376a7e OM |
1067 | |
1068 | if (INTEL_GEN(dev_priv) < 11) | |
1069 | return; | |
1070 | ||
9213e4f5 | 1071 | media_fuse = ~I915_READ(GEN11_GT_VEBOX_VDBOX_DISABLE); |
26376a7e | 1072 | |
97ee6e92 DCS |
1073 | vdbox_mask = media_fuse & GEN11_GT_VDBOX_DISABLE_MASK; |
1074 | vebox_mask = (media_fuse & GEN11_GT_VEBOX_DISABLE_MASK) >> | |
1075 | GEN11_GT_VEBOX_DISABLE_SHIFT; | |
26376a7e | 1076 | |
26376a7e | 1077 | for (i = 0; i < I915_MAX_VCS; i++) { |
6da301e5 CW |
1078 | if (!HAS_ENGINE(dev_priv, _VCS(i))) { |
1079 | vdbox_mask &= ~BIT(i); | |
26376a7e | 1080 | continue; |
6da301e5 | 1081 | } |
26376a7e | 1082 | |
97ee6e92 | 1083 | if (!(BIT(i) & vdbox_mask)) { |
8a68d464 | 1084 | info->engine_mask &= ~BIT(_VCS(i)); |
9213e4f5 | 1085 | DRM_DEBUG_DRIVER("vcs%u fused off\n", i); |
57b19d55 | 1086 | continue; |
9213e4f5 | 1087 | } |
57b19d55 OM |
1088 | |
1089 | /* | |
1090 | * In Gen11, only even numbered logical VDBOXes are | |
1091 | * hooked up to an SFC (Scaler & Format Converter) unit. | |
bd3b3004 | 1092 | * In TGL each VDBOX has access to an SFC. |
57b19d55 | 1093 | */ |
bd3b3004 | 1094 | if (IS_TIGERLAKE(dev_priv) || logical_vdbox++ % 2 == 0) |
0258404f | 1095 | RUNTIME_INFO(dev_priv)->vdbox_sfc_access |= BIT(i); |
26376a7e | 1096 | } |
9511cb64 CW |
1097 | DRM_DEBUG_DRIVER("vdbox enable: %04x, instances: %04lx\n", |
1098 | vdbox_mask, VDBOX_MASK(dev_priv)); | |
1099 | GEM_BUG_ON(vdbox_mask != VDBOX_MASK(dev_priv)); | |
26376a7e | 1100 | |
26376a7e | 1101 | for (i = 0; i < I915_MAX_VECS; i++) { |
6da301e5 CW |
1102 | if (!HAS_ENGINE(dev_priv, _VECS(i))) { |
1103 | vebox_mask &= ~BIT(i); | |
26376a7e | 1104 | continue; |
6da301e5 | 1105 | } |
26376a7e | 1106 | |
97ee6e92 | 1107 | if (!(BIT(i) & vebox_mask)) { |
8a68d464 | 1108 | info->engine_mask &= ~BIT(_VECS(i)); |
9213e4f5 TU |
1109 | DRM_DEBUG_DRIVER("vecs%u fused off\n", i); |
1110 | } | |
26376a7e | 1111 | } |
9511cb64 CW |
1112 | DRM_DEBUG_DRIVER("vebox enable: %04x, instances: %04lx\n", |
1113 | vebox_mask, VEBOX_MASK(dev_priv)); | |
1114 | GEM_BUG_ON(vebox_mask != VEBOX_MASK(dev_priv)); | |
26376a7e | 1115 | } |