File: | dev/pci/drm/i915/display/intel_dmc.c |
Warning: | line 588, column 27 Value stored to 'i915' during its initialization is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* |
2 | * Copyright © 2014 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 | |
25 | #include <linux/firmware.h> |
26 | |
27 | #include "i915_drv.h" |
28 | #include "i915_reg.h" |
29 | #include "intel_de.h" |
30 | #include "intel_dmc.h" |
31 | #include "intel_dmc_regs.h" |
32 | |
33 | /** |
34 | * DOC: DMC Firmware Support |
35 | * |
36 | * From gen9 onwards we have newly added DMC (Display microcontroller) in display |
37 | * engine to save and restore the state of display engine when it enter into |
38 | * low-power state and comes back to normal. |
39 | */ |
40 | |
41 | #define DMC_VERSION(major, minor)((major) << 16 | (minor)) ((major) << 16 | (minor)) |
42 | #define DMC_VERSION_MAJOR(version)((version) >> 16) ((version) >> 16) |
43 | #define DMC_VERSION_MINOR(version)((version) & 0xffff) ((version) & 0xffff) |
44 | |
45 | #define DMC_PATH(platform, major, minor)"i915/" "platform" "_dmc_ver" "major" "_" "minor" ".bin" \ |
46 | "i915/" \ |
47 | __stringify(platform)"platform" "_dmc_ver" \ |
48 | __stringify(major)"major" "_" \ |
49 | __stringify(minor)"minor" ".bin" |
50 | |
51 | #define DISPLAY_VER13_DMC_MAX_FW_SIZE0x20000 0x20000 |
52 | |
53 | #define DISPLAY_VER12_DMC_MAX_FW_SIZE0x6000 ICL_DMC_MAX_FW_SIZE0x6000 |
54 | |
55 | #define DG2_DMC_PATH"i915/" "dg2" "_dmc_ver" "2" "_" "07" ".bin" DMC_PATH(dg2, 2, 07)"i915/" "dg2" "_dmc_ver" "2" "_" "07" ".bin" |
56 | #define DG2_DMC_VERSION_REQUIRED((2) << 16 | (07)) DMC_VERSION(2, 07)((2) << 16 | (07)) |
57 | MODULE_FIRMWARE(DG2_DMC_PATH); |
58 | |
59 | #define ADLP_DMC_PATH"i915/" "adlp" "_dmc_ver" "2" "_" "16" ".bin" DMC_PATH(adlp, 2, 16)"i915/" "adlp" "_dmc_ver" "2" "_" "16" ".bin" |
60 | #define ADLP_DMC_VERSION_REQUIRED((2) << 16 | (16)) DMC_VERSION(2, 16)((2) << 16 | (16)) |
61 | MODULE_FIRMWARE(ADLP_DMC_PATH); |
62 | |
63 | #define ADLS_DMC_PATH"i915/" "adls" "_dmc_ver" "2" "_" "01" ".bin" DMC_PATH(adls, 2, 01)"i915/" "adls" "_dmc_ver" "2" "_" "01" ".bin" |
64 | #define ADLS_DMC_VERSION_REQUIRED((2) << 16 | (1)) DMC_VERSION(2, 1)((2) << 16 | (1)) |
65 | MODULE_FIRMWARE(ADLS_DMC_PATH); |
66 | |
67 | #define DG1_DMC_PATH"i915/" "dg1" "_dmc_ver" "2" "_" "02" ".bin" DMC_PATH(dg1, 2, 02)"i915/" "dg1" "_dmc_ver" "2" "_" "02" ".bin" |
68 | #define DG1_DMC_VERSION_REQUIRED((2) << 16 | (2)) DMC_VERSION(2, 2)((2) << 16 | (2)) |
69 | MODULE_FIRMWARE(DG1_DMC_PATH); |
70 | |
71 | #define RKL_DMC_PATH"i915/" "rkl" "_dmc_ver" "2" "_" "03" ".bin" DMC_PATH(rkl, 2, 03)"i915/" "rkl" "_dmc_ver" "2" "_" "03" ".bin" |
72 | #define RKL_DMC_VERSION_REQUIRED((2) << 16 | (3)) DMC_VERSION(2, 3)((2) << 16 | (3)) |
73 | MODULE_FIRMWARE(RKL_DMC_PATH); |
74 | |
75 | #define TGL_DMC_PATH"i915/" "tgl" "_dmc_ver" "2" "_" "12" ".bin" DMC_PATH(tgl, 2, 12)"i915/" "tgl" "_dmc_ver" "2" "_" "12" ".bin" |
76 | #define TGL_DMC_VERSION_REQUIRED((2) << 16 | (12)) DMC_VERSION(2, 12)((2) << 16 | (12)) |
77 | MODULE_FIRMWARE(TGL_DMC_PATH); |
78 | |
79 | #define ICL_DMC_PATH"i915/" "icl" "_dmc_ver" "1" "_" "09" ".bin" DMC_PATH(icl, 1, 09)"i915/" "icl" "_dmc_ver" "1" "_" "09" ".bin" |
80 | #define ICL_DMC_VERSION_REQUIRED((1) << 16 | (9)) DMC_VERSION(1, 9)((1) << 16 | (9)) |
81 | #define ICL_DMC_MAX_FW_SIZE0x6000 0x6000 |
82 | MODULE_FIRMWARE(ICL_DMC_PATH); |
83 | |
84 | #define GLK_DMC_PATH"i915/" "glk" "_dmc_ver" "1" "_" "04" ".bin" DMC_PATH(glk, 1, 04)"i915/" "glk" "_dmc_ver" "1" "_" "04" ".bin" |
85 | #define GLK_DMC_VERSION_REQUIRED((1) << 16 | (4)) DMC_VERSION(1, 4)((1) << 16 | (4)) |
86 | #define GLK_DMC_MAX_FW_SIZE0x4000 0x4000 |
87 | MODULE_FIRMWARE(GLK_DMC_PATH); |
88 | |
89 | #define KBL_DMC_PATH"i915/" "kbl" "_dmc_ver" "1" "_" "04" ".bin" DMC_PATH(kbl, 1, 04)"i915/" "kbl" "_dmc_ver" "1" "_" "04" ".bin" |
90 | #define KBL_DMC_VERSION_REQUIRED((1) << 16 | (4)) DMC_VERSION(1, 4)((1) << 16 | (4)) |
91 | #define KBL_DMC_MAX_FW_SIZE0x3000 BXT_DMC_MAX_FW_SIZE0x3000 |
92 | MODULE_FIRMWARE(KBL_DMC_PATH); |
93 | |
94 | #define SKL_DMC_PATH"i915/" "skl" "_dmc_ver" "1" "_" "27" ".bin" DMC_PATH(skl, 1, 27)"i915/" "skl" "_dmc_ver" "1" "_" "27" ".bin" |
95 | #define SKL_DMC_VERSION_REQUIRED((1) << 16 | (27)) DMC_VERSION(1, 27)((1) << 16 | (27)) |
96 | #define SKL_DMC_MAX_FW_SIZE0x3000 BXT_DMC_MAX_FW_SIZE0x3000 |
97 | MODULE_FIRMWARE(SKL_DMC_PATH); |
98 | |
99 | #define BXT_DMC_PATH"i915/" "bxt" "_dmc_ver" "1" "_" "07" ".bin" DMC_PATH(bxt, 1, 07)"i915/" "bxt" "_dmc_ver" "1" "_" "07" ".bin" |
100 | #define BXT_DMC_VERSION_REQUIRED((1) << 16 | (7)) DMC_VERSION(1, 7)((1) << 16 | (7)) |
101 | #define BXT_DMC_MAX_FW_SIZE0x3000 0x3000 |
102 | MODULE_FIRMWARE(BXT_DMC_PATH); |
103 | |
104 | #define DMC_DEFAULT_FW_OFFSET0xFFFFFFFF 0xFFFFFFFF |
105 | #define PACKAGE_MAX_FW_INFO_ENTRIES20 20 |
106 | #define PACKAGE_V2_MAX_FW_INFO_ENTRIES32 32 |
107 | #define DMC_V1_MAX_MMIO_COUNT8 8 |
108 | #define DMC_V3_MAX_MMIO_COUNT20 20 |
109 | #define DMC_V1_MMIO_START_RANGE0x80000 0x80000 |
110 | |
111 | struct intel_css_header { |
112 | /* 0x09 for DMC */ |
113 | u32 module_type; |
114 | |
115 | /* Includes the DMC specific header in dwords */ |
116 | u32 header_len; |
117 | |
118 | /* always value would be 0x10000 */ |
119 | u32 header_ver; |
120 | |
121 | /* Not used */ |
122 | u32 module_id; |
123 | |
124 | /* Not used */ |
125 | u32 module_vendor; |
126 | |
127 | /* in YYYYMMDD format */ |
128 | u32 date; |
129 | |
130 | /* Size in dwords (CSS_Headerlen + PackageHeaderLen + dmc FWsLen)/4 */ |
131 | u32 size; |
132 | |
133 | /* Not used */ |
134 | u32 key_size; |
135 | |
136 | /* Not used */ |
137 | u32 modulus_size; |
138 | |
139 | /* Not used */ |
140 | u32 exponent_size; |
141 | |
142 | /* Not used */ |
143 | u32 reserved1[12]; |
144 | |
145 | /* Major Minor */ |
146 | u32 version; |
147 | |
148 | /* Not used */ |
149 | u32 reserved2[8]; |
150 | |
151 | /* Not used */ |
152 | u32 kernel_header_info; |
153 | } __packed__attribute__((__packed__)); |
154 | |
155 | struct intel_fw_info { |
156 | u8 reserved1; |
157 | |
158 | /* reserved on package_header version 1, must be 0 on version 2 */ |
159 | u8 dmc_id; |
160 | |
161 | /* Stepping (A, B, C, ..., *). * is a wildcard */ |
162 | char stepping; |
163 | |
164 | /* Sub-stepping (0, 1, ..., *). * is a wildcard */ |
165 | char substepping; |
166 | |
167 | u32 offset; |
168 | u32 reserved2; |
169 | } __packed__attribute__((__packed__)); |
170 | |
171 | struct intel_package_header { |
172 | /* DMC container header length in dwords */ |
173 | u8 header_len; |
174 | |
175 | /* 0x01, 0x02 */ |
176 | u8 header_ver; |
177 | |
178 | u8 reserved[10]; |
179 | |
180 | /* Number of valid entries in the FWInfo array below */ |
181 | u32 num_entries; |
182 | } __packed__attribute__((__packed__)); |
183 | |
184 | struct intel_dmc_header_base { |
185 | /* always value would be 0x40403E3E */ |
186 | u32 signature; |
187 | |
188 | /* DMC binary header length */ |
189 | u8 header_len; |
190 | |
191 | /* 0x01 */ |
192 | u8 header_ver; |
193 | |
194 | /* Reserved */ |
195 | u16 dmcc_ver; |
196 | |
197 | /* Major, Minor */ |
198 | u32 project; |
199 | |
200 | /* Firmware program size (excluding header) in dwords */ |
201 | u32 fw_size; |
202 | |
203 | /* Major Minor version */ |
204 | u32 fw_version; |
205 | } __packed__attribute__((__packed__)); |
206 | |
207 | struct intel_dmc_header_v1 { |
208 | struct intel_dmc_header_base base; |
209 | |
210 | /* Number of valid MMIO cycles present. */ |
211 | u32 mmio_count; |
212 | |
213 | /* MMIO address */ |
214 | u32 mmioaddr[DMC_V1_MAX_MMIO_COUNT8]; |
215 | |
216 | /* MMIO data */ |
217 | u32 mmiodata[DMC_V1_MAX_MMIO_COUNT8]; |
218 | |
219 | /* FW filename */ |
220 | char dfile[32]; |
221 | |
222 | u32 reserved1[2]; |
223 | } __packed__attribute__((__packed__)); |
224 | |
225 | struct intel_dmc_header_v3 { |
226 | struct intel_dmc_header_base base; |
227 | |
228 | /* DMC RAM start MMIO address */ |
229 | u32 start_mmioaddr; |
230 | |
231 | u32 reserved[9]; |
232 | |
233 | /* FW filename */ |
234 | char dfile[32]; |
235 | |
236 | /* Number of valid MMIO cycles present. */ |
237 | u32 mmio_count; |
238 | |
239 | /* MMIO address */ |
240 | u32 mmioaddr[DMC_V3_MAX_MMIO_COUNT20]; |
241 | |
242 | /* MMIO data */ |
243 | u32 mmiodata[DMC_V3_MAX_MMIO_COUNT20]; |
244 | } __packed__attribute__((__packed__)); |
245 | |
246 | struct stepping_info { |
247 | char stepping; |
248 | char substepping; |
249 | }; |
250 | |
251 | static bool_Bool has_dmc_id_fw(struct drm_i915_privateinteldrm_softc *i915, int dmc_id) |
252 | { |
253 | return i915->display.dmc.dmc_info[dmc_id].payload; |
254 | } |
255 | |
256 | bool_Bool intel_dmc_has_payload(struct drm_i915_privateinteldrm_softc *i915) |
257 | { |
258 | return has_dmc_id_fw(i915, DMC_FW_MAIN); |
259 | } |
260 | |
261 | static const struct stepping_info * |
262 | intel_get_stepping_info(struct drm_i915_privateinteldrm_softc *i915, |
263 | struct stepping_info *si) |
264 | { |
265 | const char *step_name = intel_step_name(RUNTIME_INFO(i915)(&(i915)->__runtime)->step.display_step); |
266 | |
267 | si->stepping = step_name[0]; |
268 | si->substepping = step_name[1]; |
269 | return si; |
270 | } |
271 | |
272 | static void gen9_set_dc_state_debugmask(struct drm_i915_privateinteldrm_softc *dev_priv) |
273 | { |
274 | /* The below bit doesn't need to be cleared ever afterwards */ |
275 | intel_de_rmw(dev_priv, DC_STATE_DEBUG((const i915_reg_t){ .reg = (0x45520) }), 0, |
276 | DC_STATE_DEBUG_MASK_CORES(1 << 0) | DC_STATE_DEBUG_MASK_MEMORY_UP(1 << 1)); |
277 | intel_de_posting_read(dev_priv, DC_STATE_DEBUG((const i915_reg_t){ .reg = (0x45520) })); |
278 | } |
279 | |
280 | static void disable_event_handler(struct drm_i915_privateinteldrm_softc *i915, |
281 | i915_reg_t ctl_reg, i915_reg_t htp_reg) |
282 | { |
283 | intel_de_write(i915, ctl_reg, |
284 | REG_FIELD_PREP(DMC_EVT_CTL_TYPE_MASK,((u32)((((typeof(((u32)((((~0UL) >> (64 - (17) - 1)) & ((~0UL) << (16))) + 0))))(3) << (__builtin_ffsll (((u32)((((~0UL) >> (64 - (17) - 1)) & ((~0UL) << (16))) + 0))) - 1)) & (((u32)((((~0UL) >> (64 - (17 ) - 1)) & ((~0UL) << (16))) + 0)))) + 0 + 0 + 0 + 0 )) |
285 | DMC_EVT_CTL_TYPE_EDGE_0_1)((u32)((((typeof(((u32)((((~0UL) >> (64 - (17) - 1)) & ((~0UL) << (16))) + 0))))(3) << (__builtin_ffsll (((u32)((((~0UL) >> (64 - (17) - 1)) & ((~0UL) << (16))) + 0))) - 1)) & (((u32)((((~0UL) >> (64 - (17 ) - 1)) & ((~0UL) << (16))) + 0)))) + 0 + 0 + 0 + 0 )) | |
286 | REG_FIELD_PREP(DMC_EVT_CTL_EVENT_ID_MASK,((u32)((((typeof(((u32)((((~0UL) >> (64 - (15) - 1)) & ((~0UL) << (8))) + 0))))(0x01) << (__builtin_ffsll (((u32)((((~0UL) >> (64 - (15) - 1)) & ((~0UL) << (8))) + 0))) - 1)) & (((u32)((((~0UL) >> (64 - (15 ) - 1)) & ((~0UL) << (8))) + 0)))) + 0 + 0 + 0 + 0) ) |
287 | DMC_EVT_CTL_EVENT_ID_FALSE)((u32)((((typeof(((u32)((((~0UL) >> (64 - (15) - 1)) & ((~0UL) << (8))) + 0))))(0x01) << (__builtin_ffsll (((u32)((((~0UL) >> (64 - (15) - 1)) & ((~0UL) << (8))) + 0))) - 1)) & (((u32)((((~0UL) >> (64 - (15 ) - 1)) & ((~0UL) << (8))) + 0)))) + 0 + 0 + 0 + 0) )); |
288 | intel_de_write(i915, htp_reg, 0); |
289 | } |
290 | |
291 | static void |
292 | disable_flip_queue_event(struct drm_i915_privateinteldrm_softc *i915, |
293 | i915_reg_t ctl_reg, i915_reg_t htp_reg) |
294 | { |
295 | u32 event_ctl; |
296 | u32 event_htp; |
297 | |
298 | event_ctl = intel_de_read(i915, ctl_reg); |
299 | event_htp = intel_de_read(i915, htp_reg); |
300 | if (event_ctl != (DMC_EVT_CTL_ENABLE((u32)((1UL << (31)) + 0)) | |
301 | DMC_EVT_CTL_RECURRING((u32)((1UL << (30)) + 0)) | |
302 | REG_FIELD_PREP(DMC_EVT_CTL_TYPE_MASK,((u32)((((typeof(((u32)((((~0UL) >> (64 - (17) - 1)) & ((~0UL) << (16))) + 0))))(3) << (__builtin_ffsll (((u32)((((~0UL) >> (64 - (17) - 1)) & ((~0UL) << (16))) + 0))) - 1)) & (((u32)((((~0UL) >> (64 - (17 ) - 1)) & ((~0UL) << (16))) + 0)))) + 0 + 0 + 0 + 0 )) |
303 | DMC_EVT_CTL_TYPE_EDGE_0_1)((u32)((((typeof(((u32)((((~0UL) >> (64 - (17) - 1)) & ((~0UL) << (16))) + 0))))(3) << (__builtin_ffsll (((u32)((((~0UL) >> (64 - (17) - 1)) & ((~0UL) << (16))) + 0))) - 1)) & (((u32)((((~0UL) >> (64 - (17 ) - 1)) & ((~0UL) << (16))) + 0)))) + 0 + 0 + 0 + 0 )) | |
304 | REG_FIELD_PREP(DMC_EVT_CTL_EVENT_ID_MASK,((u32)((((typeof(((u32)((((~0UL) >> (64 - (15) - 1)) & ((~0UL) << (8))) + 0))))(0xbf) << (__builtin_ffsll (((u32)((((~0UL) >> (64 - (15) - 1)) & ((~0UL) << (8))) + 0))) - 1)) & (((u32)((((~0UL) >> (64 - (15 ) - 1)) & ((~0UL) << (8))) + 0)))) + 0 + 0 + 0 + 0) ) |
305 | DMC_EVT_CTL_EVENT_ID_CLK_MSEC)((u32)((((typeof(((u32)((((~0UL) >> (64 - (15) - 1)) & ((~0UL) << (8))) + 0))))(0xbf) << (__builtin_ffsll (((u32)((((~0UL) >> (64 - (15) - 1)) & ((~0UL) << (8))) + 0))) - 1)) & (((u32)((((~0UL) >> (64 - (15 ) - 1)) & ((~0UL) << (8))) + 0)))) + 0 + 0 + 0 + 0) )) || |
306 | !event_htp) { |
307 | drm_dbg_kms(&i915->drm,__drm_dev_dbg(((void *)0), (&i915->drm) ? (&i915-> drm)->dev : ((void *)0), DRM_UT_KMS, "Unexpected DMC event configuration (control %08x htp %08x)\n" , event_ctl, event_htp) |
308 | "Unexpected DMC event configuration (control %08x htp %08x)\n",__drm_dev_dbg(((void *)0), (&i915->drm) ? (&i915-> drm)->dev : ((void *)0), DRM_UT_KMS, "Unexpected DMC event configuration (control %08x htp %08x)\n" , event_ctl, event_htp) |
309 | event_ctl, event_htp)__drm_dev_dbg(((void *)0), (&i915->drm) ? (&i915-> drm)->dev : ((void *)0), DRM_UT_KMS, "Unexpected DMC event configuration (control %08x htp %08x)\n" , event_ctl, event_htp); |
310 | return; |
311 | } |
312 | |
313 | disable_event_handler(i915, ctl_reg, htp_reg); |
314 | } |
315 | |
316 | static bool_Bool |
317 | get_flip_queue_event_regs(struct drm_i915_privateinteldrm_softc *i915, int dmc_id, |
318 | i915_reg_t *ctl_reg, i915_reg_t *htp_reg) |
319 | { |
320 | switch (dmc_id) { |
321 | case DMC_FW_MAIN: |
322 | if (DISPLAY_VER(i915)((&(i915)->__runtime)->display.ip.ver) == 12) { |
323 | *ctl_reg = DMC_EVT_CTL(i915, dmc_id, 3)((const i915_reg_t){ .reg = (((0x8f034) - 0x8f000 + ((dmc_id) == DMC_FW_MAIN ? 0x8f000 : ((((&(i915)->__runtime)-> display.ip.ver) >= 13 ? 0x5f000 : 0x92000) + 0x400 * ((dmc_id ) - 1)))) + 4 * (3)) }); |
324 | *htp_reg = DMC_EVT_HTP(i915, dmc_id, 3)((const i915_reg_t){ .reg = (((0x8f004) - 0x8f000 + ((dmc_id) == DMC_FW_MAIN ? 0x8f000 : ((((&(i915)->__runtime)-> display.ip.ver) >= 13 ? 0x5f000 : 0x92000) + 0x400 * ((dmc_id ) - 1)))) + 4 * (3)) }); |
325 | |
326 | return true1; |
327 | } |
328 | break; |
329 | case DMC_FW_PIPEA ... DMC_FW_PIPED: |
330 | if (IS_DG2(i915)IS_PLATFORM(i915, INTEL_DG2)) { |
331 | *ctl_reg = DMC_EVT_CTL(i915, dmc_id, 2)((const i915_reg_t){ .reg = (((0x8f034) - 0x8f000 + ((dmc_id) == DMC_FW_MAIN ? 0x8f000 : ((((&(i915)->__runtime)-> display.ip.ver) >= 13 ? 0x5f000 : 0x92000) + 0x400 * ((dmc_id ) - 1)))) + 4 * (2)) }); |
332 | *htp_reg = DMC_EVT_HTP(i915, dmc_id, 2)((const i915_reg_t){ .reg = (((0x8f004) - 0x8f000 + ((dmc_id) == DMC_FW_MAIN ? 0x8f000 : ((((&(i915)->__runtime)-> display.ip.ver) >= 13 ? 0x5f000 : 0x92000) + 0x400 * ((dmc_id ) - 1)))) + 4 * (2)) }); |
333 | |
334 | return true1; |
335 | } |
336 | break; |
337 | } |
338 | |
339 | return false0; |
340 | } |
341 | |
342 | static void |
343 | disable_all_flip_queue_events(struct drm_i915_privateinteldrm_softc *i915) |
344 | { |
345 | int dmc_id; |
346 | |
347 | /* TODO: check if the following applies to all D13+ platforms. */ |
348 | if (!IS_DG2(i915)IS_PLATFORM(i915, INTEL_DG2) && !IS_TIGERLAKE(i915)IS_PLATFORM(i915, INTEL_TIGERLAKE)) |
349 | return; |
350 | |
351 | for (dmc_id = 0; dmc_id < DMC_FW_MAX; dmc_id++) { |
352 | i915_reg_t ctl_reg; |
353 | i915_reg_t htp_reg; |
354 | |
355 | if (!has_dmc_id_fw(i915, dmc_id)) |
356 | continue; |
357 | |
358 | if (!get_flip_queue_event_regs(i915, dmc_id, &ctl_reg, &htp_reg)) |
359 | continue; |
360 | |
361 | disable_flip_queue_event(i915, ctl_reg, htp_reg); |
362 | } |
363 | } |
364 | |
365 | static void disable_all_event_handlers(struct drm_i915_privateinteldrm_softc *i915) |
366 | { |
367 | int id; |
368 | |
369 | /* TODO: disable the event handlers on pre-GEN12 platforms as well */ |
370 | if (DISPLAY_VER(i915)((&(i915)->__runtime)->display.ip.ver) < 12) |
371 | return; |
372 | |
373 | for (id = DMC_FW_MAIN; id < DMC_FW_MAX; id++) { |
374 | int handler; |
375 | |
376 | if (!has_dmc_id_fw(i915, id)) |
377 | continue; |
378 | |
379 | for (handler = 0; handler < DMC_EVENT_HANDLER_COUNT_GEN128; handler++) |
380 | disable_event_handler(i915, |
381 | DMC_EVT_CTL(i915, id, handler)((const i915_reg_t){ .reg = (((0x8f034) - 0x8f000 + ((id) == DMC_FW_MAIN ? 0x8f000 : ((((&(i915)->__runtime)->display.ip.ver ) >= 13 ? 0x5f000 : 0x92000) + 0x400 * ((id) - 1)))) + 4 * (handler)) }), |
382 | DMC_EVT_HTP(i915, id, handler)((const i915_reg_t){ .reg = (((0x8f004) - 0x8f000 + ((id) == DMC_FW_MAIN ? 0x8f000 : ((((&(i915)->__runtime)->display.ip.ver ) >= 13 ? 0x5f000 : 0x92000) + 0x400 * ((id) - 1)))) + 4 * (handler)) })); |
383 | } |
384 | } |
385 | |
386 | static void pipedmc_clock_gating_wa(struct drm_i915_privateinteldrm_softc *i915, bool_Bool enable) |
387 | { |
388 | enum pipe pipe; |
389 | |
390 | if (DISPLAY_VER(i915)((&(i915)->__runtime)->display.ip.ver) != 13) |
391 | return; |
392 | |
393 | /* |
394 | * Wa_16015201720:adl-p,dg2 |
395 | * The WA requires clock gating to be disabled all the time |
396 | * for pipe A and B. |
397 | * For pipe C and D clock gating needs to be disabled only |
398 | * during initializing the firmware. |
399 | */ |
400 | if (enable) |
401 | for (pipe = PIPE_A; pipe <= PIPE_D; pipe++) |
402 | intel_de_rmw(i915, CLKGATE_DIS_PSL_EXT(pipe)((const i915_reg_t){ .reg = (((0x4654C) + (pipe) * ((0x46550) - (0x4654C)))) }), |
403 | 0, PIPEDMC_GATING_DIS((u32)((1UL << (12)) + 0))); |
404 | else |
405 | for (pipe = PIPE_C; pipe <= PIPE_D; pipe++) |
406 | intel_de_rmw(i915, CLKGATE_DIS_PSL_EXT(pipe)((const i915_reg_t){ .reg = (((0x4654C) + (pipe) * ((0x46550) - (0x4654C)))) }), |
407 | PIPEDMC_GATING_DIS((u32)((1UL << (12)) + 0)), 0); |
408 | } |
409 | |
410 | /** |
411 | * intel_dmc_load_program() - write the firmware from memory to register. |
412 | * @dev_priv: i915 drm device. |
413 | * |
414 | * DMC firmware is read from a .bin file and kept in internal memory one time. |
415 | * Everytime display comes back from low power state this function is called to |
416 | * copy the firmware from internal memory to registers. |
417 | */ |
418 | void intel_dmc_load_program(struct drm_i915_privateinteldrm_softc *dev_priv) |
419 | { |
420 | struct intel_dmc *dmc = &dev_priv->display.dmc; |
421 | u32 id, i; |
422 | |
423 | if (!intel_dmc_has_payload(dev_priv)) |
424 | return; |
425 | |
426 | pipedmc_clock_gating_wa(dev_priv, true1); |
427 | |
428 | disable_all_event_handlers(dev_priv); |
429 | |
430 | assert_rpm_wakelock_held(&dev_priv->runtime_pm); |
431 | |
432 | preempt_disable(); |
433 | |
434 | for (id = 0; id < DMC_FW_MAX; id++) { |
435 | for (i = 0; i < dmc->dmc_info[id].dmc_fw_size; i++) { |
436 | intel_uncore_write_fw(&dev_priv->uncore,__raw_uncore_write32(&dev_priv->uncore, ((const i915_reg_t ){ .reg = ((dmc->dmc_info[id].start_mmioaddr) + (i) * 4) } ), dmc->dmc_info[id].payload[i]) |
437 | DMC_PROGRAM(dmc->dmc_info[id].start_mmioaddr, i),__raw_uncore_write32(&dev_priv->uncore, ((const i915_reg_t ){ .reg = ((dmc->dmc_info[id].start_mmioaddr) + (i) * 4) } ), dmc->dmc_info[id].payload[i]) |
438 | dmc->dmc_info[id].payload[i])__raw_uncore_write32(&dev_priv->uncore, ((const i915_reg_t ){ .reg = ((dmc->dmc_info[id].start_mmioaddr) + (i) * 4) } ), dmc->dmc_info[id].payload[i]); |
439 | } |
440 | } |
441 | |
442 | preempt_enable(); |
443 | |
444 | for (id = 0; id < DMC_FW_MAX; id++) { |
445 | for (i = 0; i < dmc->dmc_info[id].mmio_count; i++) { |
446 | intel_de_write(dev_priv, dmc->dmc_info[id].mmioaddr[i], |
447 | dmc->dmc_info[id].mmiodata[i]); |
448 | } |
449 | } |
450 | |
451 | dev_priv->display.dmc.dc_state = 0; |
452 | |
453 | gen9_set_dc_state_debugmask(dev_priv); |
454 | |
455 | /* |
456 | * Flip queue events need to be disabled before enabling DC5/6. |
457 | * i915 doesn't use the flip queue feature, so disable it already |
458 | * here. |
459 | */ |
460 | disable_all_flip_queue_events(dev_priv); |
461 | |
462 | pipedmc_clock_gating_wa(dev_priv, false0); |
463 | } |
464 | |
465 | /** |
466 | * intel_dmc_disable_program() - disable the firmware |
467 | * @i915: i915 drm device |
468 | * |
469 | * Disable all event handlers in the firmware, making sure the firmware is |
470 | * inactive after the display is uninitialized. |
471 | */ |
472 | void intel_dmc_disable_program(struct drm_i915_privateinteldrm_softc *i915) |
473 | { |
474 | if (!intel_dmc_has_payload(i915)) |
475 | return; |
476 | |
477 | pipedmc_clock_gating_wa(i915, true1); |
478 | disable_all_event_handlers(i915); |
479 | pipedmc_clock_gating_wa(i915, false0); |
480 | } |
481 | |
482 | void assert_dmc_loaded(struct drm_i915_privateinteldrm_softc *i915) |
483 | { |
484 | drm_WARN_ONCE(&i915->drm,({ static int __warned; int __ret = !!(!intel_de_read(i915, ( (const i915_reg_t){ .reg = ((i915->display.dmc.dmc_info[DMC_FW_MAIN ].start_mmioaddr) + (0) * 4) }))); if (__ret && !__warned ) { printf("%s %s: " "DMC program storage start is NULL\n", dev_driver_string ((&i915->drm)->dev), ""); __warned = 1; } __builtin_expect (!!(__ret), 0); }) |
485 | !intel_de_read(i915, DMC_PROGRAM(i915->display.dmc.dmc_info[DMC_FW_MAIN].start_mmioaddr, 0)),({ static int __warned; int __ret = !!(!intel_de_read(i915, ( (const i915_reg_t){ .reg = ((i915->display.dmc.dmc_info[DMC_FW_MAIN ].start_mmioaddr) + (0) * 4) }))); if (__ret && !__warned ) { printf("%s %s: " "DMC program storage start is NULL\n", dev_driver_string ((&i915->drm)->dev), ""); __warned = 1; } __builtin_expect (!!(__ret), 0); }) |
486 | "DMC program storage start is NULL\n")({ static int __warned; int __ret = !!(!intel_de_read(i915, ( (const i915_reg_t){ .reg = ((i915->display.dmc.dmc_info[DMC_FW_MAIN ].start_mmioaddr) + (0) * 4) }))); if (__ret && !__warned ) { printf("%s %s: " "DMC program storage start is NULL\n", dev_driver_string ((&i915->drm)->dev), ""); __warned = 1; } __builtin_expect (!!(__ret), 0); }); |
487 | drm_WARN_ONCE(&i915->drm, !intel_de_read(i915, DMC_SSP_BASE),({ static int __warned; int __ret = !!(!intel_de_read(i915, ( (const i915_reg_t){ .reg = (0x8F074) }))); if (__ret && !__warned) { printf("%s %s: " "DMC SSP Base Not fine\n", dev_driver_string ((&i915->drm)->dev), ""); __warned = 1; } __builtin_expect (!!(__ret), 0); }) |
488 | "DMC SSP Base Not fine\n")({ static int __warned; int __ret = !!(!intel_de_read(i915, ( (const i915_reg_t){ .reg = (0x8F074) }))); if (__ret && !__warned) { printf("%s %s: " "DMC SSP Base Not fine\n", dev_driver_string ((&i915->drm)->dev), ""); __warned = 1; } __builtin_expect (!!(__ret), 0); }); |
489 | drm_WARN_ONCE(&i915->drm, !intel_de_read(i915, DMC_HTP_SKL),({ static int __warned; int __ret = !!(!intel_de_read(i915, ( (const i915_reg_t){ .reg = (0x8F004) }))); if (__ret && !__warned) { printf("%s %s: " "DMC HTP Not fine\n", dev_driver_string ((&i915->drm)->dev), ""); __warned = 1; } __builtin_expect (!!(__ret), 0); }) |
490 | "DMC HTP Not fine\n")({ static int __warned; int __ret = !!(!intel_de_read(i915, ( (const i915_reg_t){ .reg = (0x8F004) }))); if (__ret && !__warned) { printf("%s %s: " "DMC HTP Not fine\n", dev_driver_string ((&i915->drm)->dev), ""); __warned = 1; } __builtin_expect (!!(__ret), 0); }); |
491 | } |
492 | |
493 | static bool_Bool fw_info_matches_stepping(const struct intel_fw_info *fw_info, |
494 | const struct stepping_info *si) |
495 | { |
496 | if ((fw_info->substepping == '*' && si->stepping == fw_info->stepping) || |
497 | (si->stepping == fw_info->stepping && si->substepping == fw_info->substepping) || |
498 | /* |
499 | * If we don't find a more specific one from above two checks, we |
500 | * then check for the generic one to be sure to work even with |
501 | * "broken firmware" |
502 | */ |
503 | (si->stepping == '*' && si->substepping == fw_info->substepping) || |
504 | (fw_info->stepping == '*' && fw_info->substepping == '*')) |
505 | return true1; |
506 | |
507 | return false0; |
508 | } |
509 | |
510 | /* |
511 | * Search fw_info table for dmc_offset to find firmware binary: num_entries is |
512 | * already sanitized. |
513 | */ |
514 | static void dmc_set_fw_offset(struct intel_dmc *dmc, |
515 | const struct intel_fw_info *fw_info, |
516 | unsigned int num_entries, |
517 | const struct stepping_info *si, |
518 | u8 package_ver) |
519 | { |
520 | unsigned int i, id; |
521 | |
522 | struct drm_i915_privateinteldrm_softc *i915 = container_of(dmc, typeof(*i915), display.dmc)({ const __typeof( ((typeof(*i915) *)0)->display.dmc ) *__mptr = (dmc); (typeof(*i915) *)( (char *)__mptr - __builtin_offsetof (typeof(*i915), display.dmc) );}); |
523 | |
524 | for (i = 0; i < num_entries; i++) { |
525 | id = package_ver <= 1 ? DMC_FW_MAIN : fw_info[i].dmc_id; |
526 | |
527 | if (id >= DMC_FW_MAX) { |
528 | drm_dbg(&i915->drm, "Unsupported firmware id: %u\n", id)__drm_dev_dbg(((void *)0), (&i915->drm) ? (&i915-> drm)->dev : ((void *)0), DRM_UT_DRIVER, "Unsupported firmware id: %u\n" , id); |
529 | continue; |
530 | } |
531 | |
532 | /* More specific versions come first, so we don't even have to |
533 | * check for the stepping since we already found a previous FW |
534 | * for this id. |
535 | */ |
536 | if (dmc->dmc_info[id].present) |
537 | continue; |
538 | |
539 | if (fw_info_matches_stepping(&fw_info[i], si)) { |
540 | dmc->dmc_info[id].present = true1; |
541 | dmc->dmc_info[id].dmc_offset = fw_info[i].offset; |
542 | } |
543 | } |
544 | } |
545 | |
546 | static bool_Bool dmc_mmio_addr_sanity_check(struct intel_dmc *dmc, |
547 | const u32 *mmioaddr, u32 mmio_count, |
548 | int header_ver, u8 dmc_id) |
549 | { |
550 | struct drm_i915_privateinteldrm_softc *i915 = container_of(dmc, typeof(*i915), display.dmc)({ const __typeof( ((typeof(*i915) *)0)->display.dmc ) *__mptr = (dmc); (typeof(*i915) *)( (char *)__mptr - __builtin_offsetof (typeof(*i915), display.dmc) );}); |
551 | u32 start_range, end_range; |
552 | int i; |
553 | |
554 | if (dmc_id >= DMC_FW_MAX) { |
555 | drm_warn(&i915->drm, "Unsupported firmware id %u\n", dmc_id)printf("drm:pid%d:%s *WARNING* " "[drm] " "Unsupported firmware id %u\n" , ({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc->p_p->ps_pid, __func__ , dmc_id ); |
556 | return false0; |
557 | } |
558 | |
559 | if (header_ver == 1) { |
560 | start_range = DMC_MMIO_START_RANGE0x80000; |
561 | end_range = DMC_MMIO_END_RANGE0x8FFFF; |
562 | } else if (dmc_id == DMC_FW_MAIN) { |
563 | start_range = TGL_MAIN_MMIO_START0x8F000; |
564 | end_range = TGL_MAIN_MMIO_END0x8FFFF; |
565 | } else if (DISPLAY_VER(i915)((&(i915)->__runtime)->display.ip.ver) >= 13) { |
566 | start_range = ADLP_PIPE_MMIO_START0x5F000; |
567 | end_range = ADLP_PIPE_MMIO_END0x5FFFF; |
568 | } else if (DISPLAY_VER(i915)((&(i915)->__runtime)->display.ip.ver) >= 12) { |
569 | start_range = TGL_PIPE_MMIO_START(dmc_id)((0x92000) + (((dmc_id) - 1)) * ((0x96000) - (0x92000))); |
570 | end_range = TGL_PIPE_MMIO_END(dmc_id)((0x93FFF) + (((dmc_id) - 1)) * ((0x97FFF) - (0x93FFF))); |
571 | } else { |
572 | drm_warn(&i915->drm, "Unknown mmio range for sanity check")printf("drm:pid%d:%s *WARNING* " "[drm] " "Unknown mmio range for sanity check" , ({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc->p_p->ps_pid, __func__); |
573 | return false0; |
574 | } |
575 | |
576 | for (i = 0; i < mmio_count; i++) { |
577 | if (mmioaddr[i] < start_range || mmioaddr[i] > end_range) |
578 | return false0; |
579 | } |
580 | |
581 | return true1; |
582 | } |
583 | |
584 | static u32 parse_dmc_fw_header(struct intel_dmc *dmc, |
585 | const struct intel_dmc_header_base *dmc_header, |
586 | size_t rem_size, u8 dmc_id) |
587 | { |
588 | struct drm_i915_privateinteldrm_softc *i915 = container_of(dmc, typeof(*i915), display.dmc)({ const __typeof( ((typeof(*i915) *)0)->display.dmc ) *__mptr = (dmc); (typeof(*i915) *)( (char *)__mptr - __builtin_offsetof (typeof(*i915), display.dmc) );}); |
Value stored to 'i915' during its initialization is never read | |
589 | struct dmc_fw_info *dmc_info = &dmc->dmc_info[dmc_id]; |
590 | unsigned int header_len_bytes, dmc_header_size, payload_size, i; |
591 | const u32 *mmioaddr, *mmiodata; |
592 | u32 mmio_count, mmio_count_max, start_mmioaddr; |
593 | u8 *payload; |
594 | |
595 | BUILD_BUG_ON(ARRAY_SIZE(dmc_info->mmioaddr) < DMC_V3_MAX_MMIO_COUNT ||extern char _ctassert[(!((sizeof((dmc_info->mmioaddr)) / sizeof ((dmc_info->mmioaddr)[0])) < 20 || (sizeof((dmc_info-> mmioaddr)) / sizeof((dmc_info->mmioaddr)[0])) < 8)) ? 1 : -1 ] __attribute__((__unused__)) |
596 | ARRAY_SIZE(dmc_info->mmioaddr) < DMC_V1_MAX_MMIO_COUNT)extern char _ctassert[(!((sizeof((dmc_info->mmioaddr)) / sizeof ((dmc_info->mmioaddr)[0])) < 20 || (sizeof((dmc_info-> mmioaddr)) / sizeof((dmc_info->mmioaddr)[0])) < 8)) ? 1 : -1 ] __attribute__((__unused__)); |
597 | |
598 | /* |
599 | * Check if we can access common fields, we will checkc again below |
600 | * after we have read the version |
601 | */ |
602 | if (rem_size < sizeof(struct intel_dmc_header_base)) |
603 | goto error_truncated; |
604 | |
605 | /* Cope with small differences between v1 and v3 */ |
606 | if (dmc_header->header_ver == 3) { |
607 | const struct intel_dmc_header_v3 *v3 = |
608 | (const struct intel_dmc_header_v3 *)dmc_header; |
609 | |
610 | if (rem_size < sizeof(struct intel_dmc_header_v3)) |
611 | goto error_truncated; |
612 | |
613 | mmioaddr = v3->mmioaddr; |
614 | mmiodata = v3->mmiodata; |
615 | mmio_count = v3->mmio_count; |
616 | mmio_count_max = DMC_V3_MAX_MMIO_COUNT20; |
617 | /* header_len is in dwords */ |
618 | header_len_bytes = dmc_header->header_len * 4; |
619 | start_mmioaddr = v3->start_mmioaddr; |
620 | dmc_header_size = sizeof(*v3); |
621 | } else if (dmc_header->header_ver == 1) { |
622 | const struct intel_dmc_header_v1 *v1 = |
623 | (const struct intel_dmc_header_v1 *)dmc_header; |
624 | |
625 | if (rem_size < sizeof(struct intel_dmc_header_v1)) |
626 | goto error_truncated; |
627 | |
628 | mmioaddr = v1->mmioaddr; |
629 | mmiodata = v1->mmiodata; |
630 | mmio_count = v1->mmio_count; |
631 | mmio_count_max = DMC_V1_MAX_MMIO_COUNT8; |
632 | header_len_bytes = dmc_header->header_len; |
633 | start_mmioaddr = DMC_V1_MMIO_START_RANGE0x80000; |
634 | dmc_header_size = sizeof(*v1); |
635 | } else { |
636 | drm_err(&i915->drm, "Unknown DMC fw header version: %u\n",printf("drm:pid%d:%s *ERROR* " "[drm] " "*ERROR* " "Unknown DMC fw header version: %u\n" , ({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc->p_p->ps_pid, __func__ , dmc_header ->header_ver) |
637 | dmc_header->header_ver)printf("drm:pid%d:%s *ERROR* " "[drm] " "*ERROR* " "Unknown DMC fw header version: %u\n" , ({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc->p_p->ps_pid, __func__ , dmc_header ->header_ver); |
638 | return 0; |
639 | } |
640 | |
641 | if (header_len_bytes != dmc_header_size) { |
642 | drm_err(&i915->drm, "DMC firmware has wrong dmc header length "printf("drm:pid%d:%s *ERROR* " "[drm] " "*ERROR* " "DMC firmware has wrong dmc header length " "(%u bytes)\n", ({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self ))); __ci;})->ci_curproc->p_p->ps_pid, __func__ , header_len_bytes ) |
643 | "(%u bytes)\n", header_len_bytes)printf("drm:pid%d:%s *ERROR* " "[drm] " "*ERROR* " "DMC firmware has wrong dmc header length " "(%u bytes)\n", ({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self ))); __ci;})->ci_curproc->p_p->ps_pid, __func__ , header_len_bytes ); |
644 | return 0; |
645 | } |
646 | |
647 | /* Cache the dmc header info. */ |
648 | if (mmio_count > mmio_count_max) { |
649 | drm_err(&i915->drm, "DMC firmware has wrong mmio count %u\n", mmio_count)printf("drm:pid%d:%s *ERROR* " "[drm] " "*ERROR* " "DMC firmware has wrong mmio count %u\n" , ({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc->p_p->ps_pid, __func__ , mmio_count ); |
650 | return 0; |
651 | } |
652 | |
653 | if (!dmc_mmio_addr_sanity_check(dmc, mmioaddr, mmio_count, |
654 | dmc_header->header_ver, dmc_id)) { |
655 | drm_err(&i915->drm, "DMC firmware has Wrong MMIO Addresses\n")printf("drm:pid%d:%s *ERROR* " "[drm] " "*ERROR* " "DMC firmware has Wrong MMIO Addresses\n" , ({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc->p_p->ps_pid, __func__); |
656 | return 0; |
657 | } |
658 | |
659 | for (i = 0; i < mmio_count; i++) { |
660 | dmc_info->mmioaddr[i] = _MMIO(mmioaddr[i])((const i915_reg_t){ .reg = (mmioaddr[i]) }); |
661 | dmc_info->mmiodata[i] = mmiodata[i]; |
662 | } |
663 | dmc_info->mmio_count = mmio_count; |
664 | dmc_info->start_mmioaddr = start_mmioaddr; |
665 | |
666 | rem_size -= header_len_bytes; |
667 | |
668 | /* fw_size is in dwords, so multiplied by 4 to convert into bytes. */ |
669 | payload_size = dmc_header->fw_size * 4; |
670 | if (rem_size < payload_size) |
671 | goto error_truncated; |
672 | |
673 | if (payload_size > dmc->max_fw_size) { |
674 | drm_err(&i915->drm, "DMC FW too big (%u bytes)\n", payload_size)printf("drm:pid%d:%s *ERROR* " "[drm] " "*ERROR* " "DMC FW too big (%u bytes)\n" , ({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc->p_p->ps_pid, __func__ , payload_size ); |
675 | return 0; |
676 | } |
677 | dmc_info->dmc_fw_size = dmc_header->fw_size; |
678 | |
679 | dmc_info->payload = kmalloc(payload_size, GFP_KERNEL(0x0001 | 0x0004)); |
680 | if (!dmc_info->payload) |
681 | return 0; |
682 | |
683 | payload = (u8 *)(dmc_header) + header_len_bytes; |
684 | memcpy(dmc_info->payload, payload, payload_size)__builtin_memcpy((dmc_info->payload), (payload), (payload_size )); |
685 | |
686 | return header_len_bytes + payload_size; |
687 | |
688 | error_truncated: |
689 | drm_err(&i915->drm, "Truncated DMC firmware, refusing.\n")printf("drm:pid%d:%s *ERROR* " "[drm] " "*ERROR* " "Truncated DMC firmware, refusing.\n" , ({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc->p_p->ps_pid, __func__); |
690 | return 0; |
691 | } |
692 | |
693 | static u32 |
694 | parse_dmc_fw_package(struct intel_dmc *dmc, |
695 | const struct intel_package_header *package_header, |
696 | const struct stepping_info *si, |
697 | size_t rem_size) |
698 | { |
699 | struct drm_i915_privateinteldrm_softc *i915 = container_of(dmc, typeof(*i915), display.dmc)({ const __typeof( ((typeof(*i915) *)0)->display.dmc ) *__mptr = (dmc); (typeof(*i915) *)( (char *)__mptr - __builtin_offsetof (typeof(*i915), display.dmc) );}); |
700 | u32 package_size = sizeof(struct intel_package_header); |
701 | u32 num_entries, max_entries; |
702 | const struct intel_fw_info *fw_info; |
703 | |
704 | if (rem_size < package_size) |
705 | goto error_truncated; |
706 | |
707 | if (package_header->header_ver == 1) { |
708 | max_entries = PACKAGE_MAX_FW_INFO_ENTRIES20; |
709 | } else if (package_header->header_ver == 2) { |
710 | max_entries = PACKAGE_V2_MAX_FW_INFO_ENTRIES32; |
711 | } else { |
712 | drm_err(&i915->drm, "DMC firmware has unknown header version %u\n",printf("drm:pid%d:%s *ERROR* " "[drm] " "*ERROR* " "DMC firmware has unknown header version %u\n" , ({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc->p_p->ps_pid, __func__ , package_header ->header_ver) |
713 | package_header->header_ver)printf("drm:pid%d:%s *ERROR* " "[drm] " "*ERROR* " "DMC firmware has unknown header version %u\n" , ({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc->p_p->ps_pid, __func__ , package_header ->header_ver); |
714 | return 0; |
715 | } |
716 | |
717 | /* |
718 | * We should always have space for max_entries, |
719 | * even if not all are used |
720 | */ |
721 | package_size += max_entries * sizeof(struct intel_fw_info); |
722 | if (rem_size < package_size) |
723 | goto error_truncated; |
724 | |
725 | if (package_header->header_len * 4 != package_size) { |
726 | drm_err(&i915->drm, "DMC firmware has wrong package header length "printf("drm:pid%d:%s *ERROR* " "[drm] " "*ERROR* " "DMC firmware has wrong package header length " "(%u bytes)\n", ({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self ))); __ci;})->ci_curproc->p_p->ps_pid, __func__ , package_size ) |
727 | "(%u bytes)\n", package_size)printf("drm:pid%d:%s *ERROR* " "[drm] " "*ERROR* " "DMC firmware has wrong package header length " "(%u bytes)\n", ({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self ))); __ci;})->ci_curproc->p_p->ps_pid, __func__ , package_size ); |
728 | return 0; |
729 | } |
730 | |
731 | num_entries = package_header->num_entries; |
732 | if (WARN_ON(package_header->num_entries > max_entries)({ int __ret = !!(package_header->num_entries > max_entries ); if (__ret) printf("WARNING %s failed at %s:%d\n", "package_header->num_entries > max_entries" , "/usr/src/sys/dev/pci/drm/i915/display/intel_dmc.c", 732); __builtin_expect (!!(__ret), 0); })) |
733 | num_entries = max_entries; |
734 | |
735 | fw_info = (const struct intel_fw_info *) |
736 | ((u8 *)package_header + sizeof(*package_header)); |
737 | dmc_set_fw_offset(dmc, fw_info, num_entries, si, |
738 | package_header->header_ver); |
739 | |
740 | /* dmc_offset is in dwords */ |
741 | return package_size; |
742 | |
743 | error_truncated: |
744 | drm_err(&i915->drm, "Truncated DMC firmware, refusing.\n")printf("drm:pid%d:%s *ERROR* " "[drm] " "*ERROR* " "Truncated DMC firmware, refusing.\n" , ({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc->p_p->ps_pid, __func__); |
745 | return 0; |
746 | } |
747 | |
748 | /* Return number of bytes parsed or 0 on error */ |
749 | static u32 parse_dmc_fw_css(struct intel_dmc *dmc, |
750 | struct intel_css_header *css_header, |
751 | size_t rem_size) |
752 | { |
753 | struct drm_i915_privateinteldrm_softc *i915 = container_of(dmc, typeof(*i915), display.dmc)({ const __typeof( ((typeof(*i915) *)0)->display.dmc ) *__mptr = (dmc); (typeof(*i915) *)( (char *)__mptr - __builtin_offsetof (typeof(*i915), display.dmc) );}); |
754 | |
755 | if (rem_size < sizeof(struct intel_css_header)) { |
756 | drm_err(&i915->drm, "Truncated DMC firmware, refusing.\n")printf("drm:pid%d:%s *ERROR* " "[drm] " "*ERROR* " "Truncated DMC firmware, refusing.\n" , ({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc->p_p->ps_pid, __func__); |
757 | return 0; |
758 | } |
759 | |
760 | if (sizeof(struct intel_css_header) != |
761 | (css_header->header_len * 4)) { |
762 | drm_err(&i915->drm, "DMC firmware has wrong CSS header length "printf("drm:pid%d:%s *ERROR* " "[drm] " "*ERROR* " "DMC firmware has wrong CSS header length " "(%u bytes)\n", ({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self ))); __ci;})->ci_curproc->p_p->ps_pid, __func__ , (css_header ->header_len * 4)) |
763 | "(%u bytes)\n",printf("drm:pid%d:%s *ERROR* " "[drm] " "*ERROR* " "DMC firmware has wrong CSS header length " "(%u bytes)\n", ({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self ))); __ci;})->ci_curproc->p_p->ps_pid, __func__ , (css_header ->header_len * 4)) |
764 | (css_header->header_len * 4))printf("drm:pid%d:%s *ERROR* " "[drm] " "*ERROR* " "DMC firmware has wrong CSS header length " "(%u bytes)\n", ({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self ))); __ci;})->ci_curproc->p_p->ps_pid, __func__ , (css_header ->header_len * 4)); |
765 | return 0; |
766 | } |
767 | |
768 | if (dmc->required_version && |
769 | css_header->version != dmc->required_version) { |
770 | drm_info(&i915->drm, "Refusing to load DMC firmware v%u.%u,"do { } while(0) |
771 | " please use v%u.%u\n",do { } while(0) |
772 | DMC_VERSION_MAJOR(css_header->version),do { } while(0) |
773 | DMC_VERSION_MINOR(css_header->version),do { } while(0) |
774 | DMC_VERSION_MAJOR(dmc->required_version),do { } while(0) |
775 | DMC_VERSION_MINOR(dmc->required_version))do { } while(0); |
776 | return 0; |
777 | } |
778 | |
779 | dmc->version = css_header->version; |
780 | |
781 | return sizeof(struct intel_css_header); |
782 | } |
783 | |
784 | static void parse_dmc_fw(struct drm_i915_privateinteldrm_softc *dev_priv, |
785 | const struct firmware *fw) |
786 | { |
787 | struct intel_css_header *css_header; |
788 | struct intel_package_header *package_header; |
789 | struct intel_dmc_header_base *dmc_header; |
790 | struct intel_dmc *dmc = &dev_priv->display.dmc; |
791 | struct stepping_info display_info = { '*', '*'}; |
792 | const struct stepping_info *si = intel_get_stepping_info(dev_priv, &display_info); |
793 | u32 readcount = 0; |
794 | u32 r, offset; |
795 | int id; |
796 | |
797 | if (!fw) |
798 | return; |
799 | |
800 | /* Extract CSS Header information */ |
801 | css_header = (struct intel_css_header *)fw->data; |
802 | r = parse_dmc_fw_css(dmc, css_header, fw->size); |
803 | if (!r) |
804 | return; |
805 | |
806 | readcount += r; |
807 | |
808 | /* Extract Package Header information */ |
809 | package_header = (struct intel_package_header *)&fw->data[readcount]; |
810 | r = parse_dmc_fw_package(dmc, package_header, si, fw->size - readcount); |
811 | if (!r) |
812 | return; |
813 | |
814 | readcount += r; |
815 | |
816 | for (id = 0; id < DMC_FW_MAX; id++) { |
817 | if (!dev_priv->display.dmc.dmc_info[id].present) |
818 | continue; |
819 | |
820 | offset = readcount + dmc->dmc_info[id].dmc_offset * 4; |
821 | if (offset > fw->size) { |
822 | drm_err(&dev_priv->drm, "Reading beyond the fw_size\n")printf("drm:pid%d:%s *ERROR* " "[drm] " "*ERROR* " "Reading beyond the fw_size\n" , ({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc->p_p->ps_pid, __func__); |
823 | continue; |
824 | } |
825 | |
826 | dmc_header = (struct intel_dmc_header_base *)&fw->data[offset]; |
827 | parse_dmc_fw_header(dmc, dmc_header, fw->size - offset, id); |
828 | } |
829 | } |
830 | |
831 | static void intel_dmc_runtime_pm_get(struct drm_i915_privateinteldrm_softc *dev_priv) |
832 | { |
833 | drm_WARN_ON(&dev_priv->drm, dev_priv->display.dmc.wakeref)({ int __ret = !!((dev_priv->display.dmc.wakeref)); if (__ret ) printf("%s %s: " "%s", dev_driver_string(((&dev_priv-> drm))->dev), "", "drm_WARN_ON(" "dev_priv->display.dmc.wakeref" ")"); __builtin_expect(!!(__ret), 0); }); |
834 | dev_priv->display.dmc.wakeref = |
835 | intel_display_power_get(dev_priv, POWER_DOMAIN_INIT); |
836 | } |
837 | |
838 | static void intel_dmc_runtime_pm_put(struct drm_i915_privateinteldrm_softc *dev_priv) |
839 | { |
840 | intel_wakeref_t wakeref __maybe_unused__attribute__((__unused__)) = |
841 | fetch_and_zero(&dev_priv->display.dmc.wakeref)({ typeof(*&dev_priv->display.dmc.wakeref) __T = *(& dev_priv->display.dmc.wakeref); *(&dev_priv->display .dmc.wakeref) = (typeof(*&dev_priv->display.dmc.wakeref ))0; __T; }); |
842 | |
843 | intel_display_power_put(dev_priv, POWER_DOMAIN_INIT, wakeref); |
844 | } |
845 | |
846 | static void dmc_load_work_fn(struct work_struct *work) |
847 | { |
848 | struct drm_i915_privateinteldrm_softc *dev_priv; |
849 | struct intel_dmc *dmc; |
850 | const struct firmware *fw = NULL((void *)0); |
851 | |
852 | dev_priv = container_of(work, typeof(*dev_priv), display.dmc.work)({ const __typeof( ((typeof(*dev_priv) *)0)->display.dmc.work ) *__mptr = (work); (typeof(*dev_priv) *)( (char *)__mptr - __builtin_offsetof (typeof(*dev_priv), display.dmc.work) );}); |
853 | dmc = &dev_priv->display.dmc; |
854 | |
855 | #ifdef __linux__ |
856 | request_firmware(&fw, dev_priv->display.dmc.fw_path, dev_priv->drm.dev); |
857 | #else |
858 | request_firmware(&fw, dev_priv->display.dmc.fw_path, NULL((void *)0)); |
859 | #endif |
860 | parse_dmc_fw(dev_priv, fw); |
861 | |
862 | if (intel_dmc_has_payload(dev_priv)) { |
863 | intel_dmc_load_program(dev_priv); |
864 | intel_dmc_runtime_pm_put(dev_priv); |
865 | |
866 | drm_info(&dev_priv->drm,do { } while(0) |
867 | "Finished loading DMC firmware %s (v%u.%u)\n",do { } while(0) |
868 | dev_priv->display.dmc.fw_path, DMC_VERSION_MAJOR(dmc->version),do { } while(0) |
869 | DMC_VERSION_MINOR(dmc->version))do { } while(0); |
870 | } else { |
871 | drm_notice(&dev_priv->drm,printf("drm:pid%d:%s *NOTICE* " "[drm] " "Failed to load DMC firmware %s." " Disabling runtime power management.\n", ({struct cpu_info * __ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof (struct cpu_info, ci_self))); __ci;})->ci_curproc->p_p-> ps_pid, __func__ , dmc->fw_path) |
872 | "Failed to load DMC firmware %s."printf("drm:pid%d:%s *NOTICE* " "[drm] " "Failed to load DMC firmware %s." " Disabling runtime power management.\n", ({struct cpu_info * __ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof (struct cpu_info, ci_self))); __ci;})->ci_curproc->p_p-> ps_pid, __func__ , dmc->fw_path) |
873 | " Disabling runtime power management.\n",printf("drm:pid%d:%s *NOTICE* " "[drm] " "Failed to load DMC firmware %s." " Disabling runtime power management.\n", ({struct cpu_info * __ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof (struct cpu_info, ci_self))); __ci;})->ci_curproc->p_p-> ps_pid, __func__ , dmc->fw_path) |
874 | dmc->fw_path)printf("drm:pid%d:%s *NOTICE* " "[drm] " "Failed to load DMC firmware %s." " Disabling runtime power management.\n", ({struct cpu_info * __ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof (struct cpu_info, ci_self))); __ci;})->ci_curproc->p_p-> ps_pid, __func__ , dmc->fw_path); |
875 | #ifdef __linux__ |
876 | drm_notice(&dev_priv->drm, "DMC firmware homepage: %s",printf("drm:pid%d:%s *NOTICE* " "[drm] " "DMC firmware homepage: %s" , ({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc->p_p->ps_pid, __func__ , "https://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git/tree/i915" ) |
877 | INTEL_UC_FIRMWARE_URL)printf("drm:pid%d:%s *NOTICE* " "[drm] " "DMC firmware homepage: %s" , ({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc->p_p->ps_pid, __func__ , "https://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git/tree/i915" ); |
878 | #endif |
879 | } |
880 | |
881 | release_firmware(fw); |
882 | } |
883 | |
884 | /** |
885 | * intel_dmc_ucode_init() - initialize the firmware loading. |
886 | * @dev_priv: i915 drm device. |
887 | * |
888 | * This function is called at the time of loading the display driver to read |
889 | * firmware from a .bin file and copied into a internal memory. |
890 | */ |
891 | void intel_dmc_ucode_init(struct drm_i915_privateinteldrm_softc *dev_priv) |
892 | { |
893 | struct intel_dmc *dmc = &dev_priv->display.dmc; |
894 | |
895 | INIT_WORK(&dev_priv->display.dmc.work, dmc_load_work_fn); |
896 | |
897 | if (!HAS_DMC(dev_priv)((&(dev_priv)->__runtime)->has_dmc)) |
898 | return; |
899 | |
900 | /* |
901 | * Obtain a runtime pm reference, until DMC is loaded, to avoid entering |
902 | * runtime-suspend. |
903 | * |
904 | * On error, we return with the rpm wakeref held to prevent runtime |
905 | * suspend as runtime suspend *requires* a working DMC for whatever |
906 | * reason. |
907 | */ |
908 | intel_dmc_runtime_pm_get(dev_priv); |
909 | |
910 | if (IS_DG2(dev_priv)IS_PLATFORM(dev_priv, INTEL_DG2)) { |
911 | dmc->fw_path = DG2_DMC_PATH"i915/" "dg2" "_dmc_ver" "2" "_" "07" ".bin"; |
912 | dmc->required_version = DG2_DMC_VERSION_REQUIRED((2) << 16 | (07)); |
913 | dmc->max_fw_size = DISPLAY_VER13_DMC_MAX_FW_SIZE0x20000; |
914 | } else if (IS_ALDERLAKE_P(dev_priv)IS_PLATFORM(dev_priv, INTEL_ALDERLAKE_P)) { |
915 | dmc->fw_path = ADLP_DMC_PATH"i915/" "adlp" "_dmc_ver" "2" "_" "16" ".bin"; |
916 | dmc->required_version = ADLP_DMC_VERSION_REQUIRED((2) << 16 | (16)); |
917 | dmc->max_fw_size = DISPLAY_VER13_DMC_MAX_FW_SIZE0x20000; |
918 | } else if (IS_ALDERLAKE_S(dev_priv)IS_PLATFORM(dev_priv, INTEL_ALDERLAKE_S)) { |
919 | dmc->fw_path = ADLS_DMC_PATH"i915/" "adls" "_dmc_ver" "2" "_" "01" ".bin"; |
920 | dmc->required_version = ADLS_DMC_VERSION_REQUIRED((2) << 16 | (1)); |
921 | dmc->max_fw_size = DISPLAY_VER12_DMC_MAX_FW_SIZE0x6000; |
922 | } else if (IS_DG1(dev_priv)IS_PLATFORM(dev_priv, INTEL_DG1)) { |
923 | dmc->fw_path = DG1_DMC_PATH"i915/" "dg1" "_dmc_ver" "2" "_" "02" ".bin"; |
924 | dmc->required_version = DG1_DMC_VERSION_REQUIRED((2) << 16 | (2)); |
925 | dmc->max_fw_size = DISPLAY_VER12_DMC_MAX_FW_SIZE0x6000; |
926 | } else if (IS_ROCKETLAKE(dev_priv)IS_PLATFORM(dev_priv, INTEL_ROCKETLAKE)) { |
927 | dmc->fw_path = RKL_DMC_PATH"i915/" "rkl" "_dmc_ver" "2" "_" "03" ".bin"; |
928 | dmc->required_version = RKL_DMC_VERSION_REQUIRED((2) << 16 | (3)); |
929 | dmc->max_fw_size = DISPLAY_VER12_DMC_MAX_FW_SIZE0x6000; |
930 | } else if (IS_TIGERLAKE(dev_priv)IS_PLATFORM(dev_priv, INTEL_TIGERLAKE)) { |
931 | dmc->fw_path = TGL_DMC_PATH"i915/" "tgl" "_dmc_ver" "2" "_" "12" ".bin"; |
932 | dmc->required_version = TGL_DMC_VERSION_REQUIRED((2) << 16 | (12)); |
933 | dmc->max_fw_size = DISPLAY_VER12_DMC_MAX_FW_SIZE0x6000; |
934 | } else if (DISPLAY_VER(dev_priv)((&(dev_priv)->__runtime)->display.ip.ver) == 11) { |
935 | dmc->fw_path = ICL_DMC_PATH"i915/" "icl" "_dmc_ver" "1" "_" "09" ".bin"; |
936 | dmc->required_version = ICL_DMC_VERSION_REQUIRED((1) << 16 | (9)); |
937 | dmc->max_fw_size = ICL_DMC_MAX_FW_SIZE0x6000; |
938 | } else if (IS_GEMINILAKE(dev_priv)IS_PLATFORM(dev_priv, INTEL_GEMINILAKE)) { |
939 | dmc->fw_path = GLK_DMC_PATH"i915/" "glk" "_dmc_ver" "1" "_" "04" ".bin"; |
940 | dmc->required_version = GLK_DMC_VERSION_REQUIRED((1) << 16 | (4)); |
941 | dmc->max_fw_size = GLK_DMC_MAX_FW_SIZE0x4000; |
942 | } else if (IS_KABYLAKE(dev_priv)IS_PLATFORM(dev_priv, INTEL_KABYLAKE) || |
943 | IS_COFFEELAKE(dev_priv)IS_PLATFORM(dev_priv, INTEL_COFFEELAKE) || |
944 | IS_COMETLAKE(dev_priv)IS_PLATFORM(dev_priv, INTEL_COMETLAKE)) { |
945 | dmc->fw_path = KBL_DMC_PATH"i915/" "kbl" "_dmc_ver" "1" "_" "04" ".bin"; |
946 | dmc->required_version = KBL_DMC_VERSION_REQUIRED((1) << 16 | (4)); |
947 | dmc->max_fw_size = KBL_DMC_MAX_FW_SIZE0x3000; |
948 | } else if (IS_SKYLAKE(dev_priv)IS_PLATFORM(dev_priv, INTEL_SKYLAKE)) { |
949 | dmc->fw_path = SKL_DMC_PATH"i915/" "skl" "_dmc_ver" "1" "_" "27" ".bin"; |
950 | dmc->required_version = SKL_DMC_VERSION_REQUIRED((1) << 16 | (27)); |
951 | dmc->max_fw_size = SKL_DMC_MAX_FW_SIZE0x3000; |
952 | } else if (IS_BROXTON(dev_priv)IS_PLATFORM(dev_priv, INTEL_BROXTON)) { |
953 | dmc->fw_path = BXT_DMC_PATH"i915/" "bxt" "_dmc_ver" "1" "_" "07" ".bin"; |
954 | dmc->required_version = BXT_DMC_VERSION_REQUIRED((1) << 16 | (7)); |
955 | dmc->max_fw_size = BXT_DMC_MAX_FW_SIZE0x3000; |
956 | } |
957 | |
958 | if (dev_priv->params.dmc_firmware_path) { |
959 | if (strlen(dev_priv->params.dmc_firmware_path) == 0) { |
960 | dmc->fw_path = NULL((void *)0); |
961 | drm_info(&dev_priv->drm,do { } while(0) |
962 | "Disabling DMC firmware and runtime PM\n")do { } while(0); |
963 | return; |
964 | } |
965 | |
966 | dmc->fw_path = dev_priv->params.dmc_firmware_path; |
967 | /* Bypass version check for firmware override. */ |
968 | dmc->required_version = 0; |
969 | } |
970 | |
971 | if (!dmc->fw_path) { |
972 | drm_dbg_kms(&dev_priv->drm,__drm_dev_dbg(((void *)0), (&dev_priv->drm) ? (&dev_priv ->drm)->dev : ((void *)0), DRM_UT_KMS, "No known DMC firmware for platform, disabling runtime PM\n" ) |
973 | "No known DMC firmware for platform, disabling runtime PM\n")__drm_dev_dbg(((void *)0), (&dev_priv->drm) ? (&dev_priv ->drm)->dev : ((void *)0), DRM_UT_KMS, "No known DMC firmware for platform, disabling runtime PM\n" ); |
974 | return; |
975 | } |
976 | |
977 | drm_dbg_kms(&dev_priv->drm, "Loading %s\n", dmc->fw_path)__drm_dev_dbg(((void *)0), (&dev_priv->drm) ? (&dev_priv ->drm)->dev : ((void *)0), DRM_UT_KMS, "Loading %s\n", dmc ->fw_path); |
978 | schedule_work(&dev_priv->display.dmc.work); |
979 | } |
980 | |
981 | /** |
982 | * intel_dmc_ucode_suspend() - prepare DMC firmware before system suspend |
983 | * @dev_priv: i915 drm device |
984 | * |
985 | * Prepare the DMC firmware before entering system suspend. This includes |
986 | * flushing pending work items and releasing any resources acquired during |
987 | * init. |
988 | */ |
989 | void intel_dmc_ucode_suspend(struct drm_i915_privateinteldrm_softc *dev_priv) |
990 | { |
991 | if (!HAS_DMC(dev_priv)((&(dev_priv)->__runtime)->has_dmc)) |
992 | return; |
993 | |
994 | flush_work(&dev_priv->display.dmc.work); |
995 | |
996 | /* Drop the reference held in case DMC isn't loaded. */ |
997 | if (!intel_dmc_has_payload(dev_priv)) |
998 | intel_dmc_runtime_pm_put(dev_priv); |
999 | } |
1000 | |
1001 | /** |
1002 | * intel_dmc_ucode_resume() - init DMC firmware during system resume |
1003 | * @dev_priv: i915 drm device |
1004 | * |
1005 | * Reinitialize the DMC firmware during system resume, reacquiring any |
1006 | * resources released in intel_dmc_ucode_suspend(). |
1007 | */ |
1008 | void intel_dmc_ucode_resume(struct drm_i915_privateinteldrm_softc *dev_priv) |
1009 | { |
1010 | if (!HAS_DMC(dev_priv)((&(dev_priv)->__runtime)->has_dmc)) |
1011 | return; |
1012 | |
1013 | /* |
1014 | * Reacquire the reference to keep RPM disabled in case DMC isn't |
1015 | * loaded. |
1016 | */ |
1017 | if (!intel_dmc_has_payload(dev_priv)) |
1018 | intel_dmc_runtime_pm_get(dev_priv); |
1019 | } |
1020 | |
1021 | /** |
1022 | * intel_dmc_ucode_fini() - unload the DMC firmware. |
1023 | * @dev_priv: i915 drm device. |
1024 | * |
1025 | * Firmmware unloading includes freeing the internal memory and reset the |
1026 | * firmware loading status. |
1027 | */ |
1028 | void intel_dmc_ucode_fini(struct drm_i915_privateinteldrm_softc *dev_priv) |
1029 | { |
1030 | int id; |
1031 | |
1032 | if (!HAS_DMC(dev_priv)((&(dev_priv)->__runtime)->has_dmc)) |
1033 | return; |
1034 | |
1035 | intel_dmc_ucode_suspend(dev_priv); |
1036 | drm_WARN_ON(&dev_priv->drm, dev_priv->display.dmc.wakeref)({ int __ret = !!((dev_priv->display.dmc.wakeref)); if (__ret ) printf("%s %s: " "%s", dev_driver_string(((&dev_priv-> drm))->dev), "", "drm_WARN_ON(" "dev_priv->display.dmc.wakeref" ")"); __builtin_expect(!!(__ret), 0); }); |
1037 | |
1038 | for (id = 0; id < DMC_FW_MAX; id++) |
1039 | kfree(dev_priv->display.dmc.dmc_info[id].payload); |
1040 | } |
1041 | |
1042 | void intel_dmc_print_error_state(struct drm_i915_error_state_buf *m, |
1043 | struct drm_i915_privateinteldrm_softc *i915) |
1044 | { |
1045 | struct intel_dmc *dmc = &i915->display.dmc; |
1046 | |
1047 | if (!HAS_DMC(i915)((&(i915)->__runtime)->has_dmc)) |
1048 | return; |
1049 | |
1050 | i915_error_printf(m, "DMC loaded: %s\n", |
1051 | str_yes_no(intel_dmc_has_payload(i915))); |
1052 | i915_error_printf(m, "DMC fw version: %d.%d\n", |
1053 | DMC_VERSION_MAJOR(dmc->version)((dmc->version) >> 16), |
1054 | DMC_VERSION_MINOR(dmc->version)((dmc->version) & 0xffff)); |
1055 | } |
1056 | |
1057 | #ifdef notyet |
1058 | |
1059 | static int intel_dmc_debugfs_status_show(struct seq_file *m, void *unused) |
1060 | { |
1061 | struct drm_i915_privateinteldrm_softc *i915 = m->private; |
1062 | intel_wakeref_t wakeref; |
1063 | struct intel_dmc *dmc; |
1064 | i915_reg_t dc5_reg, dc6_reg = INVALID_MMIO_REG((const i915_reg_t){ .reg = (0) }); |
1065 | |
1066 | if (!HAS_DMC(i915)((&(i915)->__runtime)->has_dmc)) |
1067 | return -ENODEV19; |
1068 | |
1069 | dmc = &i915->display.dmc; |
1070 | |
1071 | wakeref = intel_runtime_pm_get(&i915->runtime_pm); |
1072 | |
1073 | seq_printf(m, "fw loaded: %s\n", |
1074 | str_yes_no(intel_dmc_has_payload(i915))); |
1075 | seq_printf(m, "path: %s\n", dmc->fw_path); |
1076 | seq_printf(m, "Pipe A fw support: %s\n", |
1077 | str_yes_no(GRAPHICS_VER(i915)((&(i915)->__runtime)->graphics.ip.ver) >= 12)); |
1078 | seq_printf(m, "Pipe A fw loaded: %s\n", |
1079 | str_yes_no(dmc->dmc_info[DMC_FW_PIPEA].payload)); |
1080 | seq_printf(m, "Pipe B fw support: %s\n", |
1081 | str_yes_no(IS_ALDERLAKE_P(i915)IS_PLATFORM(i915, INTEL_ALDERLAKE_P))); |
1082 | seq_printf(m, "Pipe B fw loaded: %s\n", |
1083 | str_yes_no(dmc->dmc_info[DMC_FW_PIPEB].payload)); |
1084 | |
1085 | if (!intel_dmc_has_payload(i915)) |
1086 | goto out; |
1087 | |
1088 | seq_printf(m, "version: %d.%d\n", DMC_VERSION_MAJOR(dmc->version)((dmc->version) >> 16), |
1089 | DMC_VERSION_MINOR(dmc->version)((dmc->version) & 0xffff)); |
1090 | |
1091 | if (DISPLAY_VER(i915)((&(i915)->__runtime)->display.ip.ver) >= 12) { |
1092 | if (IS_DGFX(i915)((&(i915)->__info)->is_dgfx)) { |
1093 | dc5_reg = DG1_DMC_DEBUG_DC5_COUNT((const i915_reg_t){ .reg = (0x134154) }); |
1094 | } else { |
1095 | dc5_reg = TGL_DMC_DEBUG_DC5_COUNT((const i915_reg_t){ .reg = (0x101084) }); |
1096 | dc6_reg = TGL_DMC_DEBUG_DC6_COUNT((const i915_reg_t){ .reg = (0x101088) }); |
1097 | } |
1098 | |
1099 | /* |
1100 | * NOTE: DMC_DEBUG3 is a general purpose reg. |
1101 | * According to B.Specs:49196 DMC f/w reuses DC5/6 counter |
1102 | * reg for DC3CO debugging and validation, |
1103 | * but TGL DMC f/w is using DMC_DEBUG3 reg for DC3CO counter. |
1104 | */ |
1105 | seq_printf(m, "DC3CO count: %d\n", |
1106 | intel_de_read(i915, IS_DGFX(i915)((&(i915)->__info)->is_dgfx) ? |
1107 | DG1_DMC_DEBUG3((const i915_reg_t){ .reg = (0x13415c) }) : TGL_DMC_DEBUG3((const i915_reg_t){ .reg = (0x101090) }))); |
1108 | } else { |
1109 | dc5_reg = IS_BROXTON(i915)IS_PLATFORM(i915, INTEL_BROXTON) ? BXT_DMC_DC3_DC5_COUNT((const i915_reg_t){ .reg = (0x80038) }) : |
1110 | SKL_DMC_DC3_DC5_COUNT((const i915_reg_t){ .reg = (0x80030) }); |
1111 | if (!IS_GEMINILAKE(i915)IS_PLATFORM(i915, INTEL_GEMINILAKE) && !IS_BROXTON(i915)IS_PLATFORM(i915, INTEL_BROXTON)) |
1112 | dc6_reg = SKL_DMC_DC5_DC6_COUNT((const i915_reg_t){ .reg = (0x8002C) }); |
1113 | } |
1114 | |
1115 | seq_printf(m, "DC3 -> DC5 count: %d\n", intel_de_read(i915, dc5_reg)); |
1116 | if (i915_mmio_reg_valid(dc6_reg)) |
1117 | seq_printf(m, "DC5 -> DC6 count: %d\n", |
1118 | intel_de_read(i915, dc6_reg)); |
1119 | |
1120 | out: |
1121 | seq_printf(m, "program base: 0x%08x\n", |
1122 | intel_de_read(i915, DMC_PROGRAM(dmc->dmc_info[DMC_FW_MAIN].start_mmioaddr, 0)((const i915_reg_t){ .reg = ((dmc->dmc_info[DMC_FW_MAIN].start_mmioaddr ) + (0) * 4) }))); |
1123 | seq_printf(m, "ssp base: 0x%08x\n", |
1124 | intel_de_read(i915, DMC_SSP_BASE((const i915_reg_t){ .reg = (0x8F074) }))); |
1125 | seq_printf(m, "htp: 0x%08x\n", intel_de_read(i915, DMC_HTP_SKL((const i915_reg_t){ .reg = (0x8F004) }))); |
1126 | |
1127 | intel_runtime_pm_put(&i915->runtime_pm, wakeref); |
1128 | |
1129 | return 0; |
1130 | } |
1131 | |
1132 | DEFINE_SHOW_ATTRIBUTE(intel_dmc_debugfs_status); |
1133 | |
1134 | #endif /* notyet */ |
1135 | |
1136 | void intel_dmc_debugfs_register(struct drm_i915_privateinteldrm_softc *i915) |
1137 | { |
1138 | struct drm_minor *minor = i915->drm.primary; |
1139 | |
1140 | debugfs_create_file("i915_dmc_info", 0444, minor->debugfs_root,ERR_PTR(-78) |
1141 | i915, &intel_dmc_debugfs_status_fops)ERR_PTR(-78); |
1142 | } |