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), |
2e0d26f8 JN |
59 | }; |
60 | #undef PLATFORM_NAME | |
61 | ||
62 | const char *intel_platform_name(enum intel_platform platform) | |
63 | { | |
9160095c JN |
64 | BUILD_BUG_ON(ARRAY_SIZE(platform_names) != INTEL_MAX_PLATFORMS); |
65 | ||
2e0d26f8 JN |
66 | if (WARN_ON_ONCE(platform >= ARRAY_SIZE(platform_names) || |
67 | platform_names[platform] == NULL)) | |
68 | return "<unknown>"; | |
69 | ||
70 | return platform_names[platform]; | |
71 | } | |
72 | ||
a8c9b849 MW |
73 | void intel_device_info_dump_flags(const struct intel_device_info *info, |
74 | struct drm_printer *p) | |
75 | { | |
76 | #define PRINT_FLAG(name) drm_printf(p, "%s: %s\n", #name, yesno(info->name)); | |
77 | DEV_INFO_FOR_EACH_FLAG(PRINT_FLAG); | |
78 | #undef PRINT_FLAG | |
79 | } | |
80 | ||
eb10ed9a MW |
81 | void intel_device_info_dump(const struct intel_device_info *info, |
82 | struct drm_printer *p) | |
94b4f3ba | 83 | { |
eb10ed9a MW |
84 | struct drm_i915_private *dev_priv = |
85 | container_of(info, struct drm_i915_private, info); | |
94b4f3ba | 86 | |
eb10ed9a MW |
87 | drm_printf(p, "pciid=0x%04x rev=0x%02x platform=%s gen=%i\n", |
88 | INTEL_DEVID(dev_priv), | |
89 | INTEL_REVID(dev_priv), | |
90 | intel_platform_name(info->platform), | |
91 | info->gen); | |
a8c9b849 | 92 | |
eb10ed9a | 93 | intel_device_info_dump_flags(info, p); |
94b4f3ba CW |
94 | } |
95 | ||
4e9767bc BW |
96 | static void gen10_sseu_info_init(struct drm_i915_private *dev_priv) |
97 | { | |
98 | struct sseu_dev_info *sseu = &mkwrite_device_info(dev_priv)->sseu; | |
99 | const u32 fuse2 = I915_READ(GEN8_FUSE2); | |
100 | ||
101 | sseu->slice_mask = (fuse2 & GEN10_F2_S_ENA_MASK) >> | |
102 | GEN10_F2_S_ENA_SHIFT; | |
103 | sseu->subslice_mask = (1 << 4) - 1; | |
104 | sseu->subslice_mask &= ~((fuse2 & GEN10_F2_SS_DIS_MASK) >> | |
105 | GEN10_F2_SS_DIS_SHIFT); | |
106 | ||
107 | sseu->eu_total = hweight32(~I915_READ(GEN8_EU_DISABLE0)); | |
108 | sseu->eu_total += hweight32(~I915_READ(GEN8_EU_DISABLE1)); | |
109 | sseu->eu_total += hweight32(~I915_READ(GEN8_EU_DISABLE2)); | |
110 | sseu->eu_total += hweight8(~(I915_READ(GEN10_EU_DISABLE3) & | |
111 | GEN10_EU_DIS_SS_MASK)); | |
112 | ||
113 | /* | |
114 | * CNL is expected to always have a uniform distribution | |
115 | * of EU across subslices with the exception that any one | |
116 | * EU in any one subslice may be fused off for die | |
117 | * recovery. | |
118 | */ | |
119 | sseu->eu_per_subslice = sseu_subslice_total(sseu) ? | |
120 | DIV_ROUND_UP(sseu->eu_total, | |
121 | sseu_subslice_total(sseu)) : 0; | |
122 | ||
123 | /* No restrictions on Power Gating */ | |
124 | sseu->has_slice_pg = 1; | |
125 | sseu->has_subslice_pg = 1; | |
126 | sseu->has_eu_pg = 1; | |
127 | } | |
128 | ||
94b4f3ba CW |
129 | static void cherryview_sseu_info_init(struct drm_i915_private *dev_priv) |
130 | { | |
43b67998 | 131 | struct sseu_dev_info *sseu = &mkwrite_device_info(dev_priv)->sseu; |
94b4f3ba CW |
132 | u32 fuse, eu_dis; |
133 | ||
134 | fuse = I915_READ(CHV_FUSE_GT); | |
135 | ||
f08a0c92 | 136 | sseu->slice_mask = BIT(0); |
94b4f3ba CW |
137 | |
138 | if (!(fuse & CHV_FGT_DISABLE_SS0)) { | |
57ec171e | 139 | sseu->subslice_mask |= BIT(0); |
94b4f3ba CW |
140 | eu_dis = fuse & (CHV_FGT_EU_DIS_SS0_R0_MASK | |
141 | CHV_FGT_EU_DIS_SS0_R1_MASK); | |
43b67998 | 142 | sseu->eu_total += 8 - hweight32(eu_dis); |
94b4f3ba CW |
143 | } |
144 | ||
145 | if (!(fuse & CHV_FGT_DISABLE_SS1)) { | |
57ec171e | 146 | sseu->subslice_mask |= BIT(1); |
94b4f3ba CW |
147 | eu_dis = fuse & (CHV_FGT_EU_DIS_SS1_R0_MASK | |
148 | CHV_FGT_EU_DIS_SS1_R1_MASK); | |
43b67998 | 149 | sseu->eu_total += 8 - hweight32(eu_dis); |
94b4f3ba CW |
150 | } |
151 | ||
94b4f3ba CW |
152 | /* |
153 | * CHV expected to always have a uniform distribution of EU | |
154 | * across subslices. | |
155 | */ | |
57ec171e ID |
156 | sseu->eu_per_subslice = sseu_subslice_total(sseu) ? |
157 | sseu->eu_total / sseu_subslice_total(sseu) : | |
94b4f3ba CW |
158 | 0; |
159 | /* | |
160 | * CHV supports subslice power gating on devices with more than | |
161 | * one subslice, and supports EU power gating on devices with | |
162 | * more than one EU pair per subslice. | |
163 | */ | |
43b67998 | 164 | sseu->has_slice_pg = 0; |
57ec171e | 165 | sseu->has_subslice_pg = sseu_subslice_total(sseu) > 1; |
43b67998 | 166 | sseu->has_eu_pg = (sseu->eu_per_subslice > 2); |
94b4f3ba CW |
167 | } |
168 | ||
169 | static void gen9_sseu_info_init(struct drm_i915_private *dev_priv) | |
170 | { | |
171 | struct intel_device_info *info = mkwrite_device_info(dev_priv); | |
43b67998 | 172 | struct sseu_dev_info *sseu = &info->sseu; |
94b4f3ba CW |
173 | int s_max = 3, ss_max = 4, eu_max = 8; |
174 | int s, ss; | |
57ec171e | 175 | u32 fuse2, eu_disable; |
94b4f3ba CW |
176 | u8 eu_mask = 0xff; |
177 | ||
178 | fuse2 = I915_READ(GEN8_FUSE2); | |
f08a0c92 | 179 | sseu->slice_mask = (fuse2 & GEN8_F2_S_ENA_MASK) >> GEN8_F2_S_ENA_SHIFT; |
94b4f3ba | 180 | |
94b4f3ba CW |
181 | /* |
182 | * The subslice disable field is global, i.e. it applies | |
183 | * to each of the enabled slices. | |
184 | */ | |
57ec171e ID |
185 | sseu->subslice_mask = (1 << ss_max) - 1; |
186 | sseu->subslice_mask &= ~((fuse2 & GEN9_F2_SS_DIS_MASK) >> | |
187 | GEN9_F2_SS_DIS_SHIFT); | |
94b4f3ba CW |
188 | |
189 | /* | |
190 | * Iterate through enabled slices and subslices to | |
191 | * count the total enabled EU. | |
192 | */ | |
193 | for (s = 0; s < s_max; s++) { | |
f08a0c92 | 194 | if (!(sseu->slice_mask & BIT(s))) |
94b4f3ba CW |
195 | /* skip disabled slice */ |
196 | continue; | |
197 | ||
198 | eu_disable = I915_READ(GEN9_EU_DISABLE(s)); | |
199 | for (ss = 0; ss < ss_max; ss++) { | |
200 | int eu_per_ss; | |
201 | ||
57ec171e | 202 | if (!(sseu->subslice_mask & BIT(ss))) |
94b4f3ba CW |
203 | /* skip disabled subslice */ |
204 | continue; | |
205 | ||
206 | eu_per_ss = eu_max - hweight8((eu_disable >> (ss*8)) & | |
207 | eu_mask); | |
208 | ||
209 | /* | |
210 | * Record which subslice(s) has(have) 7 EUs. we | |
211 | * can tune the hash used to spread work among | |
212 | * subslices if they are unbalanced. | |
213 | */ | |
214 | if (eu_per_ss == 7) | |
43b67998 | 215 | sseu->subslice_7eu[s] |= BIT(ss); |
94b4f3ba | 216 | |
43b67998 | 217 | sseu->eu_total += eu_per_ss; |
94b4f3ba CW |
218 | } |
219 | } | |
220 | ||
221 | /* | |
222 | * SKL is expected to always have a uniform distribution | |
223 | * of EU across subslices with the exception that any one | |
224 | * EU in any one subslice may be fused off for die | |
225 | * recovery. BXT is expected to be perfectly uniform in EU | |
226 | * distribution. | |
227 | */ | |
57ec171e | 228 | sseu->eu_per_subslice = sseu_subslice_total(sseu) ? |
43b67998 | 229 | DIV_ROUND_UP(sseu->eu_total, |
57ec171e | 230 | sseu_subslice_total(sseu)) : 0; |
94b4f3ba | 231 | /* |
c7ae7e9a | 232 | * SKL+ supports slice power gating on devices with more than |
94b4f3ba | 233 | * one slice, and supports EU power gating on devices with |
c7ae7e9a | 234 | * more than one EU pair per subslice. BXT+ supports subslice |
94b4f3ba CW |
235 | * power gating on devices with more than one subslice, and |
236 | * supports EU power gating on devices with more than one EU | |
237 | * pair per subslice. | |
238 | */ | |
43b67998 | 239 | sseu->has_slice_pg = |
c7ae7e9a | 240 | !IS_GEN9_LP(dev_priv) && hweight8(sseu->slice_mask) > 1; |
43b67998 | 241 | sseu->has_subslice_pg = |
254e0931 | 242 | IS_GEN9_LP(dev_priv) && sseu_subslice_total(sseu) > 1; |
43b67998 | 243 | sseu->has_eu_pg = sseu->eu_per_subslice > 2; |
94b4f3ba | 244 | |
234516af | 245 | if (IS_GEN9_LP(dev_priv)) { |
57ec171e | 246 | #define IS_SS_DISABLED(ss) (!(sseu->subslice_mask & BIT(ss))) |
234516af ACO |
247 | info->has_pooled_eu = hweight8(sseu->subslice_mask) == 3; |
248 | ||
43b67998 | 249 | sseu->min_eu_in_pool = 0; |
94b4f3ba | 250 | if (info->has_pooled_eu) { |
57ec171e | 251 | if (IS_SS_DISABLED(2) || IS_SS_DISABLED(0)) |
43b67998 | 252 | sseu->min_eu_in_pool = 3; |
57ec171e | 253 | else if (IS_SS_DISABLED(1)) |
43b67998 | 254 | sseu->min_eu_in_pool = 6; |
94b4f3ba | 255 | else |
43b67998 | 256 | sseu->min_eu_in_pool = 9; |
94b4f3ba CW |
257 | } |
258 | #undef IS_SS_DISABLED | |
259 | } | |
260 | } | |
261 | ||
262 | static void broadwell_sseu_info_init(struct drm_i915_private *dev_priv) | |
263 | { | |
43b67998 | 264 | struct sseu_dev_info *sseu = &mkwrite_device_info(dev_priv)->sseu; |
94b4f3ba CW |
265 | const int s_max = 3, ss_max = 3, eu_max = 8; |
266 | int s, ss; | |
ff64aa1e | 267 | u32 fuse2, eu_disable[3]; /* s_max */ |
94b4f3ba CW |
268 | |
269 | fuse2 = I915_READ(GEN8_FUSE2); | |
f08a0c92 | 270 | sseu->slice_mask = (fuse2 & GEN8_F2_S_ENA_MASK) >> GEN8_F2_S_ENA_SHIFT; |
57ec171e ID |
271 | /* |
272 | * The subslice disable field is global, i.e. it applies | |
273 | * to each of the enabled slices. | |
274 | */ | |
3c779a49 | 275 | sseu->subslice_mask = GENMASK(ss_max - 1, 0); |
57ec171e ID |
276 | sseu->subslice_mask &= ~((fuse2 & GEN8_F2_SS_DIS_MASK) >> |
277 | GEN8_F2_SS_DIS_SHIFT); | |
94b4f3ba CW |
278 | |
279 | eu_disable[0] = I915_READ(GEN8_EU_DISABLE0) & GEN8_EU_DIS0_S0_MASK; | |
280 | eu_disable[1] = (I915_READ(GEN8_EU_DISABLE0) >> GEN8_EU_DIS0_S1_SHIFT) | | |
281 | ((I915_READ(GEN8_EU_DISABLE1) & GEN8_EU_DIS1_S1_MASK) << | |
282 | (32 - GEN8_EU_DIS0_S1_SHIFT)); | |
283 | eu_disable[2] = (I915_READ(GEN8_EU_DISABLE1) >> GEN8_EU_DIS1_S2_SHIFT) | | |
284 | ((I915_READ(GEN8_EU_DISABLE2) & GEN8_EU_DIS2_S2_MASK) << | |
285 | (32 - GEN8_EU_DIS1_S2_SHIFT)); | |
286 | ||
94b4f3ba CW |
287 | /* |
288 | * Iterate through enabled slices and subslices to | |
289 | * count the total enabled EU. | |
290 | */ | |
291 | for (s = 0; s < s_max; s++) { | |
f08a0c92 | 292 | if (!(sseu->slice_mask & BIT(s))) |
94b4f3ba CW |
293 | /* skip disabled slice */ |
294 | continue; | |
295 | ||
296 | for (ss = 0; ss < ss_max; ss++) { | |
297 | u32 n_disabled; | |
298 | ||
57ec171e | 299 | if (!(sseu->subslice_mask & BIT(ss))) |
94b4f3ba CW |
300 | /* skip disabled subslice */ |
301 | continue; | |
302 | ||
303 | n_disabled = hweight8(eu_disable[s] >> (ss * eu_max)); | |
304 | ||
305 | /* | |
306 | * Record which subslices have 7 EUs. | |
307 | */ | |
308 | if (eu_max - n_disabled == 7) | |
43b67998 | 309 | sseu->subslice_7eu[s] |= 1 << ss; |
94b4f3ba | 310 | |
43b67998 | 311 | sseu->eu_total += eu_max - n_disabled; |
94b4f3ba CW |
312 | } |
313 | } | |
314 | ||
315 | /* | |
316 | * BDW is expected to always have a uniform distribution of EU across | |
317 | * subslices with the exception that any one EU in any one subslice may | |
318 | * be fused off for die recovery. | |
319 | */ | |
57ec171e ID |
320 | sseu->eu_per_subslice = sseu_subslice_total(sseu) ? |
321 | DIV_ROUND_UP(sseu->eu_total, | |
322 | sseu_subslice_total(sseu)) : 0; | |
94b4f3ba CW |
323 | |
324 | /* | |
325 | * BDW supports slice power gating on devices with more than | |
326 | * one slice. | |
327 | */ | |
f08a0c92 | 328 | sseu->has_slice_pg = hweight8(sseu->slice_mask) > 1; |
43b67998 ID |
329 | sseu->has_subslice_pg = 0; |
330 | sseu->has_eu_pg = 0; | |
94b4f3ba CW |
331 | } |
332 | ||
f577a03b | 333 | static u32 read_reference_ts_freq(struct drm_i915_private *dev_priv) |
dab91783 LL |
334 | { |
335 | u32 ts_override = I915_READ(GEN9_TIMESTAMP_OVERRIDE); | |
f577a03b | 336 | u32 base_freq, frac_freq; |
dab91783 LL |
337 | |
338 | base_freq = ((ts_override & GEN9_TIMESTAMP_OVERRIDE_US_COUNTER_DIVIDER_MASK) >> | |
339 | GEN9_TIMESTAMP_OVERRIDE_US_COUNTER_DIVIDER_SHIFT) + 1; | |
f577a03b | 340 | base_freq *= 1000; |
dab91783 LL |
341 | |
342 | frac_freq = ((ts_override & | |
343 | GEN9_TIMESTAMP_OVERRIDE_US_COUNTER_DENOMINATOR_MASK) >> | |
344 | GEN9_TIMESTAMP_OVERRIDE_US_COUNTER_DENOMINATOR_SHIFT); | |
f577a03b | 345 | frac_freq = 1000 / (frac_freq + 1); |
dab91783 LL |
346 | |
347 | return base_freq + frac_freq; | |
348 | } | |
349 | ||
f577a03b | 350 | static u32 read_timestamp_frequency(struct drm_i915_private *dev_priv) |
dab91783 | 351 | { |
f577a03b LL |
352 | u32 f12_5_mhz = 12500; |
353 | u32 f19_2_mhz = 19200; | |
354 | u32 f24_mhz = 24000; | |
dab91783 LL |
355 | |
356 | if (INTEL_GEN(dev_priv) <= 4) { | |
357 | /* PRMs say: | |
358 | * | |
359 | * "The value in this register increments once every 16 | |
360 | * hclks." (through the “Clocking Configuration” | |
361 | * (“CLKCFG”) MCHBAR register) | |
362 | */ | |
f577a03b | 363 | return dev_priv->rawclk_freq / 16; |
dab91783 LL |
364 | } else if (INTEL_GEN(dev_priv) <= 8) { |
365 | /* PRMs say: | |
366 | * | |
367 | * "The PCU TSC counts 10ns increments; this timestamp | |
368 | * reflects bits 38:3 of the TSC (i.e. 80ns granularity, | |
369 | * rolling over every 1.5 hours). | |
370 | */ | |
371 | return f12_5_mhz; | |
372 | } else if (INTEL_GEN(dev_priv) <= 9) { | |
373 | u32 ctc_reg = I915_READ(CTC_MODE); | |
f577a03b | 374 | u32 freq = 0; |
dab91783 LL |
375 | |
376 | if ((ctc_reg & CTC_SOURCE_PARAMETER_MASK) == CTC_SOURCE_DIVIDE_LOGIC) { | |
377 | freq = read_reference_ts_freq(dev_priv); | |
378 | } else { | |
379 | freq = IS_GEN9_LP(dev_priv) ? f19_2_mhz : f24_mhz; | |
380 | ||
381 | /* Now figure out how the command stream's timestamp | |
382 | * register increments from this frequency (it might | |
383 | * increment only every few clock cycle). | |
384 | */ | |
385 | freq >>= 3 - ((ctc_reg & CTC_SHIFT_PARAMETER_MASK) >> | |
386 | CTC_SHIFT_PARAMETER_SHIFT); | |
387 | } | |
388 | ||
389 | return freq; | |
390 | } else if (INTEL_GEN(dev_priv) <= 10) { | |
391 | u32 ctc_reg = I915_READ(CTC_MODE); | |
f577a03b | 392 | u32 freq = 0; |
dab91783 LL |
393 | u32 rpm_config_reg = 0; |
394 | ||
395 | /* First figure out the reference frequency. There are 2 ways | |
396 | * we can compute the frequency, either through the | |
397 | * TIMESTAMP_OVERRIDE register or through RPM_CONFIG. CTC_MODE | |
398 | * tells us which one we should use. | |
399 | */ | |
400 | if ((ctc_reg & CTC_SOURCE_PARAMETER_MASK) == CTC_SOURCE_DIVIDE_LOGIC) { | |
401 | freq = read_reference_ts_freq(dev_priv); | |
402 | } else { | |
403 | u32 crystal_clock; | |
404 | ||
405 | rpm_config_reg = I915_READ(RPM_CONFIG0); | |
406 | crystal_clock = (rpm_config_reg & | |
407 | GEN9_RPM_CONFIG0_CRYSTAL_CLOCK_FREQ_MASK) >> | |
408 | GEN9_RPM_CONFIG0_CRYSTAL_CLOCK_FREQ_SHIFT; | |
409 | switch (crystal_clock) { | |
410 | case GEN9_RPM_CONFIG0_CRYSTAL_CLOCK_FREQ_19_2_MHZ: | |
411 | freq = f19_2_mhz; | |
412 | break; | |
413 | case GEN9_RPM_CONFIG0_CRYSTAL_CLOCK_FREQ_24_MHZ: | |
414 | freq = f24_mhz; | |
415 | break; | |
416 | } | |
dab91783 | 417 | |
53ff2641 LL |
418 | /* Now figure out how the command stream's timestamp |
419 | * register increments from this frequency (it might | |
420 | * increment only every few clock cycle). | |
421 | */ | |
422 | freq >>= 3 - ((rpm_config_reg & | |
423 | GEN10_RPM_CONFIG0_CTC_SHIFT_PARAMETER_MASK) >> | |
424 | GEN10_RPM_CONFIG0_CTC_SHIFT_PARAMETER_SHIFT); | |
425 | } | |
dab91783 LL |
426 | |
427 | return freq; | |
428 | } | |
429 | ||
fe66e928 | 430 | MISSING_CASE("Unknown gen, unable to read command streamer timestamp frequency\n"); |
dab91783 LL |
431 | return 0; |
432 | } | |
433 | ||
94b4f3ba CW |
434 | /* |
435 | * Determine various intel_device_info fields at runtime. | |
436 | * | |
437 | * Use it when either: | |
438 | * - it's judged too laborious to fill n static structures with the limit | |
439 | * when a simple if statement does the job, | |
440 | * - run-time checks (eg read fuse/strap registers) are needed. | |
441 | * | |
442 | * This function needs to be called: | |
443 | * - after the MMIO has been setup as we are reading registers, | |
444 | * - after the PCH has been detected, | |
445 | * - before the first usage of the fields it can tweak. | |
446 | */ | |
447 | void intel_device_info_runtime_init(struct drm_i915_private *dev_priv) | |
448 | { | |
449 | struct intel_device_info *info = mkwrite_device_info(dev_priv); | |
450 | enum pipe pipe; | |
451 | ||
6e7406db MK |
452 | if (INTEL_GEN(dev_priv) >= 10) { |
453 | for_each_pipe(dev_priv, pipe) | |
454 | info->num_scalers[pipe] = 2; | |
455 | } else if (INTEL_GEN(dev_priv) == 9) { | |
0bf0230e ACO |
456 | info->num_scalers[PIPE_A] = 2; |
457 | info->num_scalers[PIPE_B] = 2; | |
458 | info->num_scalers[PIPE_C] = 1; | |
459 | } | |
460 | ||
94b4f3ba CW |
461 | /* |
462 | * Skylake and Broxton currently don't expose the topmost plane as its | |
463 | * use is exclusive with the legacy cursor and we only want to expose | |
464 | * one of those, not both. Until we can safely expose the topmost plane | |
465 | * as a DRM_PLANE_TYPE_CURSOR with all the features exposed/supported, | |
466 | * we don't expose the topmost plane at all to prevent ABI breakage | |
467 | * down the line. | |
468 | */ | |
8366be98 | 469 | if (IS_GEN10(dev_priv) || IS_GEMINILAKE(dev_priv)) |
e9c98825 ACO |
470 | for_each_pipe(dev_priv, pipe) |
471 | info->num_sprites[pipe] = 3; | |
472 | else if (IS_BROXTON(dev_priv)) { | |
94b4f3ba CW |
473 | info->num_sprites[PIPE_A] = 2; |
474 | info->num_sprites[PIPE_B] = 2; | |
475 | info->num_sprites[PIPE_C] = 1; | |
33edc24d | 476 | } else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) { |
94b4f3ba CW |
477 | for_each_pipe(dev_priv, pipe) |
478 | info->num_sprites[pipe] = 2; | |
ab33081a | 479 | } else if (INTEL_GEN(dev_priv) >= 5 || IS_G4X(dev_priv)) { |
94b4f3ba CW |
480 | for_each_pipe(dev_priv, pipe) |
481 | info->num_sprites[pipe] = 1; | |
33edc24d | 482 | } |
94b4f3ba | 483 | |
4f044a88 | 484 | if (i915_modparams.disable_display) { |
94b4f3ba CW |
485 | DRM_INFO("Display disabled (module parameter)\n"); |
486 | info->num_pipes = 0; | |
487 | } else if (info->num_pipes > 0 && | |
488 | (IS_GEN7(dev_priv) || IS_GEN8(dev_priv)) && | |
489 | HAS_PCH_SPLIT(dev_priv)) { | |
490 | u32 fuse_strap = I915_READ(FUSE_STRAP); | |
491 | u32 sfuse_strap = I915_READ(SFUSE_STRAP); | |
492 | ||
493 | /* | |
494 | * SFUSE_STRAP is supposed to have a bit signalling the display | |
495 | * is fused off. Unfortunately it seems that, at least in | |
496 | * certain cases, fused off display means that PCH display | |
497 | * reads don't land anywhere. In that case, we read 0s. | |
498 | * | |
499 | * On CPT/PPT, we can detect this case as SFUSE_STRAP_FUSE_LOCK | |
500 | * should be set when taking over after the firmware. | |
501 | */ | |
502 | if (fuse_strap & ILK_INTERNAL_DISPLAY_DISABLE || | |
503 | sfuse_strap & SFUSE_STRAP_DISPLAY_DISABLED || | |
b9eb89b2 | 504 | (HAS_PCH_CPT(dev_priv) && |
94b4f3ba CW |
505 | !(sfuse_strap & SFUSE_STRAP_FUSE_LOCK))) { |
506 | DRM_INFO("Display fused off, disabling\n"); | |
507 | info->num_pipes = 0; | |
508 | } else if (fuse_strap & IVB_PIPE_C_DISABLE) { | |
509 | DRM_INFO("PipeC fused off\n"); | |
510 | info->num_pipes -= 1; | |
511 | } | |
512 | } else if (info->num_pipes > 0 && IS_GEN9(dev_priv)) { | |
513 | u32 dfsm = I915_READ(SKL_DFSM); | |
514 | u8 disabled_mask = 0; | |
515 | bool invalid; | |
516 | int num_bits; | |
517 | ||
518 | if (dfsm & SKL_DFSM_PIPE_A_DISABLE) | |
519 | disabled_mask |= BIT(PIPE_A); | |
520 | if (dfsm & SKL_DFSM_PIPE_B_DISABLE) | |
521 | disabled_mask |= BIT(PIPE_B); | |
522 | if (dfsm & SKL_DFSM_PIPE_C_DISABLE) | |
523 | disabled_mask |= BIT(PIPE_C); | |
524 | ||
525 | num_bits = hweight8(disabled_mask); | |
526 | ||
527 | switch (disabled_mask) { | |
528 | case BIT(PIPE_A): | |
529 | case BIT(PIPE_B): | |
530 | case BIT(PIPE_A) | BIT(PIPE_B): | |
531 | case BIT(PIPE_A) | BIT(PIPE_C): | |
532 | invalid = true; | |
533 | break; | |
534 | default: | |
535 | invalid = false; | |
536 | } | |
537 | ||
538 | if (num_bits > info->num_pipes || invalid) | |
539 | DRM_ERROR("invalid pipe fuse configuration: 0x%x\n", | |
540 | disabled_mask); | |
541 | else | |
542 | info->num_pipes -= num_bits; | |
543 | } | |
544 | ||
545 | /* Initialize slice/subslice/EU info */ | |
546 | if (IS_CHERRYVIEW(dev_priv)) | |
547 | cherryview_sseu_info_init(dev_priv); | |
548 | else if (IS_BROADWELL(dev_priv)) | |
549 | broadwell_sseu_info_init(dev_priv); | |
4e9767bc | 550 | else if (INTEL_GEN(dev_priv) == 9) |
94b4f3ba | 551 | gen9_sseu_info_init(dev_priv); |
4e9767bc BW |
552 | else if (INTEL_GEN(dev_priv) >= 10) |
553 | gen10_sseu_info_init(dev_priv); | |
94b4f3ba | 554 | |
dab91783 | 555 | /* Initialize command stream timestamp frequency */ |
f577a03b | 556 | info->cs_timestamp_frequency_khz = read_timestamp_frequency(dev_priv); |
dab91783 | 557 | |
c67ba538 | 558 | DRM_DEBUG_DRIVER("slice mask: %04x\n", info->sseu.slice_mask); |
f08a0c92 | 559 | DRM_DEBUG_DRIVER("slice total: %u\n", hweight8(info->sseu.slice_mask)); |
57ec171e ID |
560 | DRM_DEBUG_DRIVER("subslice total: %u\n", |
561 | sseu_subslice_total(&info->sseu)); | |
c67ba538 | 562 | DRM_DEBUG_DRIVER("subslice mask %04x\n", info->sseu.subslice_mask); |
43b67998 | 563 | DRM_DEBUG_DRIVER("subslice per slice: %u\n", |
57ec171e | 564 | hweight8(info->sseu.subslice_mask)); |
43b67998 ID |
565 | DRM_DEBUG_DRIVER("EU total: %u\n", info->sseu.eu_total); |
566 | DRM_DEBUG_DRIVER("EU per subslice: %u\n", info->sseu.eu_per_subslice); | |
94b4f3ba | 567 | DRM_DEBUG_DRIVER("has slice power gating: %s\n", |
43b67998 | 568 | info->sseu.has_slice_pg ? "y" : "n"); |
94b4f3ba | 569 | DRM_DEBUG_DRIVER("has subslice power gating: %s\n", |
43b67998 | 570 | info->sseu.has_subslice_pg ? "y" : "n"); |
94b4f3ba | 571 | DRM_DEBUG_DRIVER("has EU power gating: %s\n", |
43b67998 | 572 | info->sseu.has_eu_pg ? "y" : "n"); |
f577a03b LL |
573 | DRM_DEBUG_DRIVER("CS timestamp frequency: %u kHz\n", |
574 | info->cs_timestamp_frequency_khz); | |
94b4f3ba | 575 | } |