]>
Commit | Line | Data |
---|---|---|
eb805623 DV |
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 | #include <linux/firmware.h> | |
25 | #include "i915_drv.h" | |
26 | #include "i915_reg.h" | |
27 | ||
aa9145c4 AM |
28 | /** |
29 | * DOC: csr support for dmc | |
30 | * | |
31 | * Display Context Save and Restore (CSR) firmware support added from gen9 | |
32 | * onwards to drive newly added DMC (Display microcontroller) in display | |
33 | * engine to save and restore the state of display engine when it enter into | |
34 | * low-power state and comes back to normal. | |
aa9145c4 AM |
35 | */ |
36 | ||
02c07b76 LDM |
37 | #define GEN12_CSR_MAX_FW_SIZE ICL_CSR_MAX_FW_SIZE |
38 | ||
7fe78985 | 39 | #define ICL_CSR_PATH "i915/icl_dmc_ver1_07.bin" |
4445930f | 40 | #define ICL_CSR_VERSION_REQUIRED CSR_VERSION(1, 7) |
7fe78985 | 41 | #define ICL_CSR_MAX_FW_SIZE 0x6000 |
00e5d8b1 | 42 | MODULE_FIRMWARE(ICL_CSR_PATH); |
4445930f | 43 | |
7fe78985 | 44 | #define CNL_CSR_PATH "i915/cnl_dmc_ver1_07.bin" |
fe9a9da6 | 45 | #define CNL_CSR_VERSION_REQUIRED CSR_VERSION(1, 7) |
7fe78985 JN |
46 | #define CNL_CSR_MAX_FW_SIZE GLK_CSR_MAX_FW_SIZE |
47 | MODULE_FIRMWARE(CNL_CSR_PATH); | |
cebfcead | 48 | |
7fe78985 JN |
49 | #define GLK_CSR_PATH "i915/glk_dmc_ver1_04.bin" |
50 | #define GLK_CSR_VERSION_REQUIRED CSR_VERSION(1, 4) | |
51 | #define GLK_CSR_MAX_FW_SIZE 0x4000 | |
52 | MODULE_FIRMWARE(GLK_CSR_PATH); | |
53 | ||
54 | #define KBL_CSR_PATH "i915/kbl_dmc_ver1_04.bin" | |
4f0aa1fa | 55 | #define KBL_CSR_VERSION_REQUIRED CSR_VERSION(1, 4) |
7fe78985 JN |
56 | #define KBL_CSR_MAX_FW_SIZE BXT_CSR_MAX_FW_SIZE |
57 | MODULE_FIRMWARE(KBL_CSR_PATH); | |
4922d491 | 58 | |
7fe78985 | 59 | #define SKL_CSR_PATH "i915/skl_dmc_ver1_27.bin" |
39ccc985 | 60 | #define SKL_CSR_VERSION_REQUIRED CSR_VERSION(1, 27) |
7fe78985 JN |
61 | #define SKL_CSR_MAX_FW_SIZE BXT_CSR_MAX_FW_SIZE |
62 | MODULE_FIRMWARE(SKL_CSR_PATH); | |
4922d491 | 63 | |
7fe78985 | 64 | #define BXT_CSR_PATH "i915/bxt_dmc_ver1_07.bin" |
4922d491 | 65 | #define BXT_CSR_VERSION_REQUIRED CSR_VERSION(1, 7) |
a64f8887 | 66 | #define BXT_CSR_MAX_FW_SIZE 0x3000 |
7fe78985 JN |
67 | MODULE_FIRMWARE(BXT_CSR_PATH); |
68 | ||
eb805623 | 69 | #define CSR_DEFAULT_FW_OFFSET 0xFFFFFFFF |
eb805623 DV |
70 | |
71 | struct intel_css_header { | |
72 | /* 0x09 for DMC */ | |
5a01892a | 73 | u32 module_type; |
eb805623 DV |
74 | |
75 | /* Includes the DMC specific header in dwords */ | |
5a01892a | 76 | u32 header_len; |
eb805623 DV |
77 | |
78 | /* always value would be 0x10000 */ | |
5a01892a | 79 | u32 header_ver; |
eb805623 DV |
80 | |
81 | /* Not used */ | |
5a01892a | 82 | u32 module_id; |
eb805623 DV |
83 | |
84 | /* Not used */ | |
5a01892a | 85 | u32 module_vendor; |
eb805623 DV |
86 | |
87 | /* in YYYYMMDD format */ | |
5a01892a | 88 | u32 date; |
eb805623 DV |
89 | |
90 | /* Size in dwords (CSS_Headerlen + PackageHeaderLen + dmc FWsLen)/4 */ | |
5a01892a | 91 | u32 size; |
eb805623 DV |
92 | |
93 | /* Not used */ | |
5a01892a | 94 | u32 key_size; |
eb805623 DV |
95 | |
96 | /* Not used */ | |
5a01892a | 97 | u32 modulus_size; |
eb805623 DV |
98 | |
99 | /* Not used */ | |
5a01892a | 100 | u32 exponent_size; |
eb805623 DV |
101 | |
102 | /* Not used */ | |
5a01892a | 103 | u32 reserved1[12]; |
eb805623 DV |
104 | |
105 | /* Major Minor */ | |
5a01892a | 106 | u32 version; |
eb805623 DV |
107 | |
108 | /* Not used */ | |
5a01892a | 109 | u32 reserved2[8]; |
eb805623 DV |
110 | |
111 | /* Not used */ | |
5a01892a | 112 | u32 kernel_header_info; |
eb805623 DV |
113 | } __packed; |
114 | ||
115 | struct intel_fw_info { | |
5a01892a | 116 | u16 reserved1; |
eb805623 DV |
117 | |
118 | /* Stepping (A, B, C, ..., *). * is a wildcard */ | |
119 | char stepping; | |
120 | ||
121 | /* Sub-stepping (0, 1, ..., *). * is a wildcard */ | |
122 | char substepping; | |
123 | ||
5a01892a JN |
124 | u32 offset; |
125 | u32 reserved2; | |
eb805623 DV |
126 | } __packed; |
127 | ||
128 | struct intel_package_header { | |
129 | /* DMC container header length in dwords */ | |
130 | unsigned char header_len; | |
131 | ||
132 | /* always value would be 0x01 */ | |
133 | unsigned char header_ver; | |
134 | ||
135 | unsigned char reserved[10]; | |
136 | ||
137 | /* Number of valid entries in the FWInfo array below */ | |
5a01892a | 138 | u32 num_entries; |
eb805623 DV |
139 | |
140 | struct intel_fw_info fw_info[20]; | |
141 | } __packed; | |
142 | ||
143 | struct intel_dmc_header { | |
144 | /* always value would be 0x40403E3E */ | |
5a01892a | 145 | u32 signature; |
eb805623 DV |
146 | |
147 | /* DMC binary header length */ | |
148 | unsigned char header_len; | |
149 | ||
150 | /* 0x01 */ | |
151 | unsigned char header_ver; | |
152 | ||
153 | /* Reserved */ | |
5a01892a | 154 | u16 dmcc_ver; |
eb805623 DV |
155 | |
156 | /* Major, Minor */ | |
5a01892a | 157 | u32 project; |
eb805623 DV |
158 | |
159 | /* Firmware program size (excluding header) in dwords */ | |
5a01892a | 160 | u32 fw_size; |
eb805623 DV |
161 | |
162 | /* Major Minor version */ | |
5a01892a | 163 | u32 fw_version; |
eb805623 DV |
164 | |
165 | /* Number of valid MMIO cycles present. */ | |
5a01892a | 166 | u32 mmio_count; |
eb805623 DV |
167 | |
168 | /* MMIO address */ | |
5a01892a | 169 | u32 mmioaddr[8]; |
eb805623 DV |
170 | |
171 | /* MMIO data */ | |
5a01892a | 172 | u32 mmiodata[8]; |
eb805623 DV |
173 | |
174 | /* FW filename */ | |
175 | unsigned char dfile[32]; | |
176 | ||
5a01892a | 177 | u32 reserved1[2]; |
eb805623 DV |
178 | } __packed; |
179 | ||
180 | struct stepping_info { | |
181 | char stepping; | |
182 | char substepping; | |
183 | }; | |
184 | ||
185 | static const struct stepping_info skl_stepping_info[] = { | |
84cb00ec JN |
186 | {'A', '0'}, {'B', '0'}, {'C', '0'}, |
187 | {'D', '0'}, {'E', '0'}, {'F', '0'}, | |
a41c8882 MM |
188 | {'G', '0'}, {'H', '0'}, {'I', '0'}, |
189 | {'J', '0'}, {'K', '0'} | |
eb805623 DV |
190 | }; |
191 | ||
b9cd5bfd | 192 | static const struct stepping_info bxt_stepping_info[] = { |
cff765fb AM |
193 | {'A', '0'}, {'A', '1'}, {'A', '2'}, |
194 | {'B', '0'}, {'B', '1'}, {'B', '2'} | |
195 | }; | |
196 | ||
7569bf95 JY |
197 | static const struct stepping_info icl_stepping_info[] = { |
198 | {'A', '0'}, {'A', '1'}, {'A', '2'}, | |
199 | {'B', '0'}, {'B', '2'}, | |
200 | {'C', '0'} | |
201 | }; | |
202 | ||
1bb4308e CW |
203 | static const struct stepping_info no_stepping_info = { '*', '*' }; |
204 | ||
205 | static const struct stepping_info * | |
206 | intel_get_stepping_info(struct drm_i915_private *dev_priv) | |
eb805623 | 207 | { |
b1a14c6e JN |
208 | const struct stepping_info *si; |
209 | unsigned int size; | |
210 | ||
7569bf95 JY |
211 | if (IS_ICELAKE(dev_priv)) { |
212 | size = ARRAY_SIZE(icl_stepping_info); | |
213 | si = icl_stepping_info; | |
214 | } else if (IS_SKYLAKE(dev_priv)) { | |
b1a14c6e JN |
215 | size = ARRAY_SIZE(skl_stepping_info); |
216 | si = skl_stepping_info; | |
1bb4308e | 217 | } else if (IS_BROXTON(dev_priv)) { |
b1a14c6e JN |
218 | size = ARRAY_SIZE(bxt_stepping_info); |
219 | si = bxt_stepping_info; | |
220 | } else { | |
1bb4308e | 221 | size = 0; |
2f59f1b3 | 222 | si = NULL; |
b1a14c6e | 223 | } |
eb805623 | 224 | |
1bb4308e CW |
225 | if (INTEL_REVID(dev_priv) < size) |
226 | return si + INTEL_REVID(dev_priv); | |
b1a14c6e | 227 | |
1bb4308e | 228 | return &no_stepping_info; |
eb805623 DV |
229 | } |
230 | ||
2abc525b ID |
231 | static void gen9_set_dc_state_debugmask(struct drm_i915_private *dev_priv) |
232 | { | |
5a01892a | 233 | u32 val, mask; |
2abc525b ID |
234 | |
235 | mask = DC_STATE_DEBUG_MASK_MEMORY_UP; | |
236 | ||
b7208a3f | 237 | if (IS_GEN9_LP(dev_priv)) |
2abc525b ID |
238 | mask |= DC_STATE_DEBUG_MASK_CORES; |
239 | ||
240 | /* The below bit doesn't need to be cleared ever afterwards */ | |
241 | val = I915_READ(DC_STATE_DEBUG); | |
242 | if ((val & mask) != mask) { | |
243 | val |= mask; | |
244 | I915_WRITE(DC_STATE_DEBUG, val); | |
245 | POSTING_READ(DC_STATE_DEBUG); | |
246 | } | |
247 | } | |
248 | ||
aa9145c4 AM |
249 | /** |
250 | * intel_csr_load_program() - write the firmware from memory to register. | |
f4448375 | 251 | * @dev_priv: i915 drm device. |
aa9145c4 AM |
252 | * |
253 | * CSR firmware is read from a .bin file and kept in internal memory one time. | |
254 | * Everytime display comes back from low power state this function is called to | |
255 | * copy the firmware from internal memory to registers. | |
256 | */ | |
2abc525b | 257 | void intel_csr_load_program(struct drm_i915_private *dev_priv) |
eb805623 | 258 | { |
a7f749f9 | 259 | u32 *payload = dev_priv->csr.dmc_payload; |
5a01892a | 260 | u32 i, fw_size; |
eb805623 | 261 | |
1a7399aa | 262 | if (!HAS_CSR(dev_priv)) { |
eb805623 | 263 | DRM_ERROR("No CSR support available for this platform\n"); |
2abc525b | 264 | return; |
eb805623 DV |
265 | } |
266 | ||
fc131bf2 PJ |
267 | if (!dev_priv->csr.dmc_payload) { |
268 | DRM_ERROR("Tried to program CSR with empty payload\n"); | |
2abc525b | 269 | return; |
fc131bf2 | 270 | } |
4b7ab5fc | 271 | |
eb805623 | 272 | fw_size = dev_priv->csr.dmc_fw_size; |
dff457d7 DW |
273 | assert_rpm_wakelock_held(dev_priv); |
274 | ||
275 | preempt_disable(); | |
276 | ||
eb805623 | 277 | for (i = 0; i < fw_size; i++) |
dff457d7 DW |
278 | I915_WRITE_FW(CSR_PROGRAM(i), payload[i]); |
279 | ||
280 | preempt_enable(); | |
eb805623 DV |
281 | |
282 | for (i = 0; i < dev_priv->csr.mmio_count; i++) { | |
283 | I915_WRITE(dev_priv->csr.mmioaddr[i], | |
f98f70d9 | 284 | dev_priv->csr.mmiodata[i]); |
eb805623 | 285 | } |
832dba88 PJ |
286 | |
287 | dev_priv->csr.dc_state = 0; | |
1e657ad7 | 288 | |
2abc525b | 289 | gen9_set_dc_state_debugmask(dev_priv); |
eb805623 DV |
290 | } |
291 | ||
5a01892a JN |
292 | static u32 *parse_csr_fw(struct drm_i915_private *dev_priv, |
293 | const struct firmware *fw) | |
eb805623 | 294 | { |
eb805623 DV |
295 | struct intel_css_header *css_header; |
296 | struct intel_package_header *package_header; | |
297 | struct intel_dmc_header *dmc_header; | |
298 | struct intel_csr *csr = &dev_priv->csr; | |
1bb4308e | 299 | const struct stepping_info *si = intel_get_stepping_info(dev_priv); |
5a01892a JN |
300 | u32 dmc_offset = CSR_DEFAULT_FW_OFFSET, readcount = 0, nbytes; |
301 | u32 i; | |
302 | u32 *dmc_payload; | |
eb805623 | 303 | |
9c5308ea | 304 | if (!fw) |
6a6582bf | 305 | return NULL; |
eb805623 | 306 | |
eb805623 DV |
307 | /* Extract CSS Header information*/ |
308 | css_header = (struct intel_css_header *)fw->data; | |
309 | if (sizeof(struct intel_css_header) != | |
f98f70d9 | 310 | (css_header->header_len * 4)) { |
f1e86cec MW |
311 | DRM_ERROR("DMC firmware has wrong CSS header length " |
312 | "(%u bytes)\n", | |
f98f70d9 | 313 | (css_header->header_len * 4)); |
6a6582bf | 314 | return NULL; |
eb805623 | 315 | } |
b6e7d894 | 316 | |
180e9d23 JN |
317 | if (csr->required_version && |
318 | css_header->version != csr->required_version) { | |
4aa7fb9c | 319 | DRM_INFO("Refusing to load DMC firmware v%u.%u," |
f1e86cec | 320 | " please use v%u.%u\n", |
180e9d23 JN |
321 | CSR_VERSION_MAJOR(css_header->version), |
322 | CSR_VERSION_MINOR(css_header->version), | |
323 | CSR_VERSION_MAJOR(csr->required_version), | |
324 | CSR_VERSION_MINOR(csr->required_version)); | |
6a6582bf | 325 | return NULL; |
9c5308ea MK |
326 | } |
327 | ||
180e9d23 JN |
328 | csr->version = css_header->version; |
329 | ||
eb805623 DV |
330 | readcount += sizeof(struct intel_css_header); |
331 | ||
332 | /* Extract Package Header information*/ | |
333 | package_header = (struct intel_package_header *) | |
f98f70d9 | 334 | &fw->data[readcount]; |
eb805623 | 335 | if (sizeof(struct intel_package_header) != |
f98f70d9 | 336 | (package_header->header_len * 4)) { |
f1e86cec MW |
337 | DRM_ERROR("DMC firmware has wrong package header length " |
338 | "(%u bytes)\n", | |
f98f70d9 | 339 | (package_header->header_len * 4)); |
6a6582bf | 340 | return NULL; |
eb805623 DV |
341 | } |
342 | readcount += sizeof(struct intel_package_header); | |
343 | ||
344 | /* Search for dmc_offset to find firware binary. */ | |
345 | for (i = 0; i < package_header->num_entries; i++) { | |
346 | if (package_header->fw_info[i].substepping == '*' && | |
1bb4308e | 347 | si->stepping == package_header->fw_info[i].stepping) { |
eb805623 DV |
348 | dmc_offset = package_header->fw_info[i].offset; |
349 | break; | |
1bb4308e CW |
350 | } else if (si->stepping == package_header->fw_info[i].stepping && |
351 | si->substepping == package_header->fw_info[i].substepping) { | |
eb805623 DV |
352 | dmc_offset = package_header->fw_info[i].offset; |
353 | break; | |
354 | } else if (package_header->fw_info[i].stepping == '*' && | |
f98f70d9 | 355 | package_header->fw_info[i].substepping == '*') |
eb805623 DV |
356 | dmc_offset = package_header->fw_info[i].offset; |
357 | } | |
358 | if (dmc_offset == CSR_DEFAULT_FW_OFFSET) { | |
f1e86cec | 359 | DRM_ERROR("DMC firmware not supported for %c stepping\n", |
1bb4308e | 360 | si->stepping); |
6a6582bf | 361 | return NULL; |
eb805623 | 362 | } |
a64f8887 JY |
363 | /* Convert dmc_offset into number of bytes. By default it is in dwords*/ |
364 | dmc_offset *= 4; | |
eb805623 DV |
365 | readcount += dmc_offset; |
366 | ||
367 | /* Extract dmc_header information. */ | |
368 | dmc_header = (struct intel_dmc_header *)&fw->data[readcount]; | |
369 | if (sizeof(struct intel_dmc_header) != (dmc_header->header_len)) { | |
f1e86cec MW |
370 | DRM_ERROR("DMC firmware has wrong dmc header length " |
371 | "(%u bytes)\n", | |
f98f70d9 | 372 | (dmc_header->header_len)); |
6a6582bf | 373 | return NULL; |
eb805623 DV |
374 | } |
375 | readcount += sizeof(struct intel_dmc_header); | |
376 | ||
377 | /* Cache the dmc header info. */ | |
378 | if (dmc_header->mmio_count > ARRAY_SIZE(csr->mmioaddr)) { | |
f1e86cec | 379 | DRM_ERROR("DMC firmware has wrong mmio count %u\n", |
f98f70d9 | 380 | dmc_header->mmio_count); |
6a6582bf | 381 | return NULL; |
eb805623 DV |
382 | } |
383 | csr->mmio_count = dmc_header->mmio_count; | |
384 | for (i = 0; i < dmc_header->mmio_count; i++) { | |
982b0b2d | 385 | if (dmc_header->mmioaddr[i] < CSR_MMIO_START_RANGE || |
f98f70d9 | 386 | dmc_header->mmioaddr[i] > CSR_MMIO_END_RANGE) { |
f1e86cec | 387 | DRM_ERROR("DMC firmware has wrong mmio address 0x%x\n", |
f98f70d9 | 388 | dmc_header->mmioaddr[i]); |
6a6582bf | 389 | return NULL; |
eb805623 | 390 | } |
f0f59a00 | 391 | csr->mmioaddr[i] = _MMIO(dmc_header->mmioaddr[i]); |
eb805623 DV |
392 | csr->mmiodata[i] = dmc_header->mmiodata[i]; |
393 | } | |
394 | ||
395 | /* fw_size is in dwords, so multiplied by 4 to convert into bytes. */ | |
396 | nbytes = dmc_header->fw_size * 4; | |
d8a5b7d7 | 397 | if (nbytes > csr->max_fw_size) { |
a64f8887 | 398 | DRM_ERROR("DMC FW too big (%u bytes)\n", nbytes); |
6a6582bf | 399 | return NULL; |
eb805623 DV |
400 | } |
401 | csr->dmc_fw_size = dmc_header->fw_size; | |
402 | ||
6a6582bf DV |
403 | dmc_payload = kmalloc(nbytes, GFP_KERNEL); |
404 | if (!dmc_payload) { | |
eb805623 | 405 | DRM_ERROR("Memory allocation failed for dmc payload\n"); |
6a6582bf | 406 | return NULL; |
eb805623 DV |
407 | } |
408 | ||
1bb4308e | 409 | return memcpy(dmc_payload, &fw->data[readcount], nbytes); |
6a6582bf DV |
410 | } |
411 | ||
0e6e0be4 CW |
412 | static void intel_csr_runtime_pm_get(struct drm_i915_private *dev_priv) |
413 | { | |
414 | WARN_ON(dev_priv->csr.wakeref); | |
415 | dev_priv->csr.wakeref = | |
416 | intel_display_power_get(dev_priv, POWER_DOMAIN_INIT); | |
417 | } | |
418 | ||
419 | static void intel_csr_runtime_pm_put(struct drm_i915_private *dev_priv) | |
420 | { | |
421 | intel_wakeref_t wakeref __maybe_unused = | |
422 | fetch_and_zero(&dev_priv->csr.wakeref); | |
423 | ||
424 | intel_display_power_put(dev_priv, POWER_DOMAIN_INIT, wakeref); | |
425 | } | |
426 | ||
8144ac59 | 427 | static void csr_load_work_fn(struct work_struct *work) |
6a6582bf | 428 | { |
8144ac59 DV |
429 | struct drm_i915_private *dev_priv; |
430 | struct intel_csr *csr; | |
3aaa8aba | 431 | const struct firmware *fw = NULL; |
8144ac59 DV |
432 | |
433 | dev_priv = container_of(work, typeof(*dev_priv), csr.work); | |
434 | csr = &dev_priv->csr; | |
6a6582bf | 435 | |
ec78828e | 436 | request_firmware(&fw, dev_priv->csr.fw_path, &dev_priv->drm.pdev->dev); |
2abc525b ID |
437 | if (fw) |
438 | dev_priv->csr.dmc_payload = parse_csr_fw(dev_priv, fw); | |
6a6582bf | 439 | |
6a6582bf | 440 | if (dev_priv->csr.dmc_payload) { |
2abc525b | 441 | intel_csr_load_program(dev_priv); |
0e6e0be4 | 442 | intel_csr_runtime_pm_put(dev_priv); |
9c5308ea | 443 | |
b2251c08 | 444 | DRM_INFO("Finished loading DMC firmware %s (v%u.%u)\n", |
9c5308ea MK |
445 | dev_priv->csr.fw_path, |
446 | CSR_VERSION_MAJOR(csr->version), | |
447 | CSR_VERSION_MINOR(csr->version)); | |
448 | } else { | |
91c8a326 | 449 | dev_notice(dev_priv->drm.dev, |
f1e86cec MW |
450 | "Failed to load DMC firmware %s." |
451 | " Disabling runtime power management.\n", | |
452 | csr->fw_path); | |
453 | dev_notice(dev_priv->drm.dev, "DMC firmware homepage: %s", | |
454 | INTEL_UC_FIRMWARE_URL); | |
9c5308ea MK |
455 | } |
456 | ||
eb805623 DV |
457 | release_firmware(fw); |
458 | } | |
459 | ||
aa9145c4 AM |
460 | /** |
461 | * intel_csr_ucode_init() - initialize the firmware loading. | |
f4448375 | 462 | * @dev_priv: i915 drm device. |
aa9145c4 AM |
463 | * |
464 | * This function is called at the time of loading the display driver to read | |
465 | * firmware from a .bin file and copied into a internal memory. | |
466 | */ | |
f4448375 | 467 | void intel_csr_ucode_init(struct drm_i915_private *dev_priv) |
eb805623 | 468 | { |
eb805623 | 469 | struct intel_csr *csr = &dev_priv->csr; |
8144ac59 DV |
470 | |
471 | INIT_WORK(&dev_priv->csr.work, csr_load_work_fn); | |
eb805623 | 472 | |
f4448375 | 473 | if (!HAS_CSR(dev_priv)) |
eb805623 DV |
474 | return; |
475 | ||
d8a5b7d7 JN |
476 | /* |
477 | * Obtain a runtime pm reference, until CSR is loaded, to avoid entering | |
478 | * runtime-suspend. | |
479 | * | |
480 | * On error, we return with the rpm wakeref held to prevent runtime | |
481 | * suspend as runtime suspend *requires* a working CSR for whatever | |
482 | * reason. | |
483 | */ | |
0e6e0be4 | 484 | intel_csr_runtime_pm_get(dev_priv); |
d8a5b7d7 | 485 | |
02c07b76 LDM |
486 | if (INTEL_GEN(dev_priv) >= 12) { |
487 | /* Allow to load fw via parameter using the last known size */ | |
488 | csr->max_fw_size = GEN12_CSR_MAX_FW_SIZE; | |
489 | } else if (IS_ICELAKE(dev_priv)) { | |
7fe78985 | 490 | csr->fw_path = ICL_CSR_PATH; |
180e9d23 | 491 | csr->required_version = ICL_CSR_VERSION_REQUIRED; |
d8a5b7d7 | 492 | csr->max_fw_size = ICL_CSR_MAX_FW_SIZE; |
180e9d23 | 493 | } else if (IS_CANNONLAKE(dev_priv)) { |
7fe78985 | 494 | csr->fw_path = CNL_CSR_PATH; |
180e9d23 | 495 | csr->required_version = CNL_CSR_VERSION_REQUIRED; |
7fe78985 | 496 | csr->max_fw_size = CNL_CSR_MAX_FW_SIZE; |
180e9d23 | 497 | } else if (IS_GEMINILAKE(dev_priv)) { |
7fe78985 | 498 | csr->fw_path = GLK_CSR_PATH; |
180e9d23 | 499 | csr->required_version = GLK_CSR_VERSION_REQUIRED; |
d8a5b7d7 | 500 | csr->max_fw_size = GLK_CSR_MAX_FW_SIZE; |
180e9d23 | 501 | } else if (IS_KABYLAKE(dev_priv) || IS_COFFEELAKE(dev_priv)) { |
7fe78985 | 502 | csr->fw_path = KBL_CSR_PATH; |
180e9d23 | 503 | csr->required_version = KBL_CSR_VERSION_REQUIRED; |
7fe78985 | 504 | csr->max_fw_size = KBL_CSR_MAX_FW_SIZE; |
180e9d23 | 505 | } else if (IS_SKYLAKE(dev_priv)) { |
7fe78985 | 506 | csr->fw_path = SKL_CSR_PATH; |
180e9d23 | 507 | csr->required_version = SKL_CSR_VERSION_REQUIRED; |
7fe78985 | 508 | csr->max_fw_size = SKL_CSR_MAX_FW_SIZE; |
180e9d23 | 509 | } else if (IS_BROXTON(dev_priv)) { |
7fe78985 | 510 | csr->fw_path = BXT_CSR_PATH; |
180e9d23 | 511 | csr->required_version = BXT_CSR_VERSION_REQUIRED; |
d8a5b7d7 | 512 | csr->max_fw_size = BXT_CSR_MAX_FW_SIZE; |
180e9d23 | 513 | } |
abd41dc9 | 514 | |
d8a5b7d7 | 515 | if (i915_modparams.dmc_firmware_path) { |
e7351a84 JN |
516 | if (strlen(i915_modparams.dmc_firmware_path) == 0) { |
517 | csr->fw_path = NULL; | |
b598a88e | 518 | DRM_INFO("Disabling CSR firmware and runtime PM\n"); |
e7351a84 JN |
519 | return; |
520 | } | |
521 | ||
d8a5b7d7 JN |
522 | csr->fw_path = i915_modparams.dmc_firmware_path; |
523 | /* Bypass version check for firmware override. */ | |
524 | csr->required_version = 0; | |
525 | } | |
dc174300 | 526 | |
ad3c776b ID |
527 | if (csr->fw_path == NULL) { |
528 | DRM_DEBUG_KMS("No known CSR firmware for platform, disabling runtime PM\n"); | |
529 | WARN_ON(!IS_ALPHA_SUPPORT(INTEL_INFO(dev_priv))); | |
530 | ||
531 | return; | |
532 | } | |
533 | ||
534 | DRM_DEBUG_KMS("Loading %s\n", csr->fw_path); | |
8144ac59 | 535 | schedule_work(&dev_priv->csr.work); |
eb805623 DV |
536 | } |
537 | ||
f74ed08d ID |
538 | /** |
539 | * intel_csr_ucode_suspend() - prepare CSR firmware before system suspend | |
540 | * @dev_priv: i915 drm device | |
541 | * | |
542 | * Prepare the DMC firmware before entering system suspend. This includes | |
543 | * flushing pending work items and releasing any resources acquired during | |
544 | * init. | |
545 | */ | |
546 | void intel_csr_ucode_suspend(struct drm_i915_private *dev_priv) | |
547 | { | |
548 | if (!HAS_CSR(dev_priv)) | |
549 | return; | |
550 | ||
551 | flush_work(&dev_priv->csr.work); | |
552 | ||
553 | /* Drop the reference held in case DMC isn't loaded. */ | |
554 | if (!dev_priv->csr.dmc_payload) | |
0e6e0be4 | 555 | intel_csr_runtime_pm_put(dev_priv); |
f74ed08d ID |
556 | } |
557 | ||
558 | /** | |
559 | * intel_csr_ucode_resume() - init CSR firmware during system resume | |
560 | * @dev_priv: i915 drm device | |
561 | * | |
562 | * Reinitialize the DMC firmware during system resume, reacquiring any | |
563 | * resources released in intel_csr_ucode_suspend(). | |
564 | */ | |
565 | void intel_csr_ucode_resume(struct drm_i915_private *dev_priv) | |
566 | { | |
567 | if (!HAS_CSR(dev_priv)) | |
568 | return; | |
569 | ||
570 | /* | |
571 | * Reacquire the reference to keep RPM disabled in case DMC isn't | |
572 | * loaded. | |
573 | */ | |
574 | if (!dev_priv->csr.dmc_payload) | |
0e6e0be4 | 575 | intel_csr_runtime_pm_get(dev_priv); |
f74ed08d ID |
576 | } |
577 | ||
aa9145c4 AM |
578 | /** |
579 | * intel_csr_ucode_fini() - unload the CSR firmware. | |
f4448375 | 580 | * @dev_priv: i915 drm device. |
aa9145c4 | 581 | * |
f74ed08d | 582 | * Firmmware unloading includes freeing the internal memory and reset the |
aa9145c4 AM |
583 | * firmware loading status. |
584 | */ | |
f4448375 | 585 | void intel_csr_ucode_fini(struct drm_i915_private *dev_priv) |
eb805623 | 586 | { |
f4448375 | 587 | if (!HAS_CSR(dev_priv)) |
eb805623 DV |
588 | return; |
589 | ||
f74ed08d | 590 | intel_csr_ucode_suspend(dev_priv); |
0e6e0be4 | 591 | WARN_ON(dev_priv->csr.wakeref); |
15e72c1f | 592 | |
eb805623 DV |
593 | kfree(dev_priv->csr.dmc_payload); |
594 | } |