Rev 6937 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
6084 | serge | 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 |
||
25 | #include "i915_drv.h" |
||
26 | #include "i915_reg.h" |
||
27 | |||
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. |
||
35 | * |
||
36 | * Firmware loading status will be one of the below states: FW_UNINITIALIZED, |
||
37 | * FW_LOADED, FW_FAILED. |
||
38 | * |
||
39 | * Once the firmware is written into the registers status will be moved from |
||
40 | * FW_UNINITIALIZED to FW_LOADED and for any erroneous condition status will |
||
41 | * be moved to FW_FAILED. |
||
42 | */ |
||
43 | |||
44 | #define I915_CSR_SKL "i915/skl_dmc_ver1.bin" |
||
45 | #define I915_CSR_BXT "i915/bxt_dmc_ver1.bin" |
||
46 | |||
7144 | serge | 47 | #define FIRMWARE_URL "https://01.org/linuxgraphics/intel-linux-graphics-firmwares" |
48 | |||
6084 | serge | 49 | MODULE_FIRMWARE(I915_CSR_SKL); |
50 | MODULE_FIRMWARE(I915_CSR_BXT); |
||
51 | |||
6937 | serge | 52 | #define SKL_CSR_VERSION_REQUIRED CSR_VERSION(1, 23) |
53 | |||
6084 | serge | 54 | #define CSR_MAX_FW_SIZE 0x2FFF |
55 | #define CSR_DEFAULT_FW_OFFSET 0xFFFFFFFF |
||
56 | |||
57 | struct intel_css_header { |
||
58 | /* 0x09 for DMC */ |
||
59 | uint32_t module_type; |
||
60 | |||
61 | /* Includes the DMC specific header in dwords */ |
||
62 | uint32_t header_len; |
||
63 | |||
64 | /* always value would be 0x10000 */ |
||
65 | uint32_t header_ver; |
||
66 | |||
67 | /* Not used */ |
||
68 | uint32_t module_id; |
||
69 | |||
70 | /* Not used */ |
||
71 | uint32_t module_vendor; |
||
72 | |||
73 | /* in YYYYMMDD format */ |
||
74 | uint32_t date; |
||
75 | |||
76 | /* Size in dwords (CSS_Headerlen + PackageHeaderLen + dmc FWsLen)/4 */ |
||
77 | uint32_t size; |
||
78 | |||
79 | /* Not used */ |
||
80 | uint32_t key_size; |
||
81 | |||
82 | /* Not used */ |
||
83 | uint32_t modulus_size; |
||
84 | |||
85 | /* Not used */ |
||
86 | uint32_t exponent_size; |
||
87 | |||
88 | /* Not used */ |
||
89 | uint32_t reserved1[12]; |
||
90 | |||
91 | /* Major Minor */ |
||
92 | uint32_t version; |
||
93 | |||
94 | /* Not used */ |
||
95 | uint32_t reserved2[8]; |
||
96 | |||
97 | /* Not used */ |
||
98 | uint32_t kernel_header_info; |
||
99 | } __packed; |
||
100 | |||
101 | struct intel_fw_info { |
||
102 | uint16_t reserved1; |
||
103 | |||
104 | /* Stepping (A, B, C, ..., *). * is a wildcard */ |
||
105 | char stepping; |
||
106 | |||
107 | /* Sub-stepping (0, 1, ..., *). * is a wildcard */ |
||
108 | char substepping; |
||
109 | |||
110 | uint32_t offset; |
||
111 | uint32_t reserved2; |
||
112 | } __packed; |
||
113 | |||
114 | struct intel_package_header { |
||
115 | /* DMC container header length in dwords */ |
||
116 | unsigned char header_len; |
||
117 | |||
118 | /* always value would be 0x01 */ |
||
119 | unsigned char header_ver; |
||
120 | |||
121 | unsigned char reserved[10]; |
||
122 | |||
123 | /* Number of valid entries in the FWInfo array below */ |
||
124 | uint32_t num_entries; |
||
125 | |||
126 | struct intel_fw_info fw_info[20]; |
||
127 | } __packed; |
||
128 | |||
129 | struct intel_dmc_header { |
||
130 | /* always value would be 0x40403E3E */ |
||
131 | uint32_t signature; |
||
132 | |||
133 | /* DMC binary header length */ |
||
134 | unsigned char header_len; |
||
135 | |||
136 | /* 0x01 */ |
||
137 | unsigned char header_ver; |
||
138 | |||
139 | /* Reserved */ |
||
140 | uint16_t dmcc_ver; |
||
141 | |||
142 | /* Major, Minor */ |
||
143 | uint32_t project; |
||
144 | |||
145 | /* Firmware program size (excluding header) in dwords */ |
||
146 | uint32_t fw_size; |
||
147 | |||
148 | /* Major Minor version */ |
||
149 | uint32_t fw_version; |
||
150 | |||
151 | /* Number of valid MMIO cycles present. */ |
||
152 | uint32_t mmio_count; |
||
153 | |||
154 | /* MMIO address */ |
||
155 | uint32_t mmioaddr[8]; |
||
156 | |||
157 | /* MMIO data */ |
||
158 | uint32_t mmiodata[8]; |
||
159 | |||
160 | /* FW filename */ |
||
161 | unsigned char dfile[32]; |
||
162 | |||
163 | uint32_t reserved1[2]; |
||
164 | } __packed; |
||
165 | |||
166 | struct stepping_info { |
||
167 | char stepping; |
||
168 | char substepping; |
||
169 | }; |
||
170 | |||
6937 | serge | 171 | /* |
172 | * Kabylake derivated from Skylake H0, so SKL H0 |
||
173 | * is the right firmware for KBL A0 (revid 0). |
||
174 | */ |
||
175 | static const struct stepping_info kbl_stepping_info[] = { |
||
176 | {'H', '0'}, {'I', '0'} |
||
177 | }; |
||
178 | |||
6084 | serge | 179 | static const struct stepping_info skl_stepping_info[] = { |
7144 | serge | 180 | {'A', '0'}, {'B', '0'}, {'C', '0'}, |
181 | {'D', '0'}, {'E', '0'}, {'F', '0'}, |
||
182 | {'G', '0'}, {'H', '0'}, {'I', '0'}, |
||
183 | {'J', '0'}, {'K', '0'} |
||
6084 | serge | 184 | }; |
185 | |||
6937 | serge | 186 | static const struct stepping_info bxt_stepping_info[] = { |
6084 | serge | 187 | {'A', '0'}, {'A', '1'}, {'A', '2'}, |
188 | {'B', '0'}, {'B', '1'}, {'B', '2'} |
||
189 | }; |
||
190 | |||
6937 | serge | 191 | static const struct stepping_info *intel_get_stepping_info(struct drm_device *dev) |
6084 | serge | 192 | { |
6937 | serge | 193 | const struct stepping_info *si; |
194 | unsigned int size; |
||
6084 | serge | 195 | |
6937 | serge | 196 | if (IS_KABYLAKE(dev)) { |
197 | size = ARRAY_SIZE(kbl_stepping_info); |
||
198 | si = kbl_stepping_info; |
||
199 | } else if (IS_SKYLAKE(dev)) { |
||
200 | size = ARRAY_SIZE(skl_stepping_info); |
||
201 | si = skl_stepping_info; |
||
202 | } else if (IS_BROXTON(dev)) { |
||
203 | size = ARRAY_SIZE(bxt_stepping_info); |
||
204 | si = bxt_stepping_info; |
||
205 | } else { |
||
206 | return NULL; |
||
207 | } |
||
6084 | serge | 208 | |
6937 | serge | 209 | if (INTEL_REVID(dev) < size) |
210 | return si + INTEL_REVID(dev); |
||
6084 | serge | 211 | |
6937 | serge | 212 | return NULL; |
6084 | serge | 213 | } |
214 | |||
215 | /** |
||
216 | * intel_csr_load_program() - write the firmware from memory to register. |
||
6937 | serge | 217 | * @dev_priv: i915 drm device. |
6084 | serge | 218 | * |
219 | * CSR firmware is read from a .bin file and kept in internal memory one time. |
||
220 | * Everytime display comes back from low power state this function is called to |
||
221 | * copy the firmware from internal memory to registers. |
||
222 | */ |
||
7144 | serge | 223 | bool intel_csr_load_program(struct drm_i915_private *dev_priv) |
6084 | serge | 224 | { |
225 | u32 *payload = dev_priv->csr.dmc_payload; |
||
226 | uint32_t i, fw_size; |
||
227 | |||
6937 | serge | 228 | if (!IS_GEN9(dev_priv)) { |
6084 | serge | 229 | DRM_ERROR("No CSR support available for this platform\n"); |
7144 | serge | 230 | return false; |
6084 | serge | 231 | } |
232 | |||
6937 | serge | 233 | if (!dev_priv->csr.dmc_payload) { |
234 | DRM_ERROR("Tried to program CSR with empty payload\n"); |
||
7144 | serge | 235 | return false; |
6937 | serge | 236 | } |
6084 | serge | 237 | |
238 | fw_size = dev_priv->csr.dmc_fw_size; |
||
239 | for (i = 0; i < fw_size; i++) |
||
240 | I915_WRITE(CSR_PROGRAM(i), payload[i]); |
||
241 | |||
242 | for (i = 0; i < dev_priv->csr.mmio_count; i++) { |
||
243 | I915_WRITE(dev_priv->csr.mmioaddr[i], |
||
7144 | serge | 244 | dev_priv->csr.mmiodata[i]); |
6084 | serge | 245 | } |
246 | |||
6937 | serge | 247 | dev_priv->csr.dc_state = 0; |
7144 | serge | 248 | |
249 | return true; |
||
6084 | serge | 250 | } |
251 | |||
6937 | serge | 252 | static uint32_t *parse_csr_fw(struct drm_i915_private *dev_priv, |
253 | const struct firmware *fw) |
||
6084 | serge | 254 | { |
255 | struct drm_device *dev = dev_priv->dev; |
||
256 | struct intel_css_header *css_header; |
||
257 | struct intel_package_header *package_header; |
||
258 | struct intel_dmc_header *dmc_header; |
||
259 | struct intel_csr *csr = &dev_priv->csr; |
||
6937 | serge | 260 | const struct stepping_info *stepping_info = intel_get_stepping_info(dev); |
261 | char stepping, substepping; |
||
6084 | serge | 262 | uint32_t dmc_offset = CSR_DEFAULT_FW_OFFSET, readcount = 0, nbytes; |
263 | uint32_t i; |
||
264 | uint32_t *dmc_payload; |
||
265 | |||
6937 | serge | 266 | if (!fw) |
267 | return NULL; |
||
6084 | serge | 268 | |
6937 | serge | 269 | if (!stepping_info) { |
6084 | serge | 270 | DRM_ERROR("Unknown stepping info, firmware loading failed\n"); |
6937 | serge | 271 | return NULL; |
6084 | serge | 272 | } |
273 | |||
6937 | serge | 274 | stepping = stepping_info->stepping; |
275 | substepping = stepping_info->substepping; |
||
276 | |||
6084 | serge | 277 | /* Extract CSS Header information*/ |
278 | css_header = (struct intel_css_header *)fw->data; |
||
279 | if (sizeof(struct intel_css_header) != |
||
7144 | serge | 280 | (css_header->header_len * 4)) { |
6084 | serge | 281 | DRM_ERROR("Firmware has wrong CSS header length %u bytes\n", |
7144 | serge | 282 | (css_header->header_len * 4)); |
6937 | serge | 283 | return NULL; |
6084 | serge | 284 | } |
6937 | serge | 285 | |
286 | csr->version = css_header->version; |
||
287 | |||
7144 | serge | 288 | if ((IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) && |
289 | csr->version < SKL_CSR_VERSION_REQUIRED) { |
||
6937 | serge | 290 | DRM_INFO("Refusing to load old Skylake DMC firmware v%u.%u," |
291 | " please upgrade to v%u.%u or later" |
||
7144 | serge | 292 | " [" FIRMWARE_URL "].\n", |
6937 | serge | 293 | CSR_VERSION_MAJOR(csr->version), |
294 | CSR_VERSION_MINOR(csr->version), |
||
295 | CSR_VERSION_MAJOR(SKL_CSR_VERSION_REQUIRED), |
||
296 | CSR_VERSION_MINOR(SKL_CSR_VERSION_REQUIRED)); |
||
297 | return NULL; |
||
298 | } |
||
299 | |||
6084 | serge | 300 | readcount += sizeof(struct intel_css_header); |
301 | |||
302 | /* Extract Package Header information*/ |
||
303 | package_header = (struct intel_package_header *) |
||
7144 | serge | 304 | &fw->data[readcount]; |
6084 | serge | 305 | if (sizeof(struct intel_package_header) != |
7144 | serge | 306 | (package_header->header_len * 4)) { |
6084 | serge | 307 | DRM_ERROR("Firmware has wrong package header length %u bytes\n", |
7144 | serge | 308 | (package_header->header_len * 4)); |
6937 | serge | 309 | return NULL; |
6084 | serge | 310 | } |
311 | readcount += sizeof(struct intel_package_header); |
||
312 | |||
313 | /* Search for dmc_offset to find firware binary. */ |
||
314 | for (i = 0; i < package_header->num_entries; i++) { |
||
315 | if (package_header->fw_info[i].substepping == '*' && |
||
7144 | serge | 316 | stepping == package_header->fw_info[i].stepping) { |
6084 | serge | 317 | dmc_offset = package_header->fw_info[i].offset; |
318 | break; |
||
319 | } else if (stepping == package_header->fw_info[i].stepping && |
||
320 | substepping == package_header->fw_info[i].substepping) { |
||
321 | dmc_offset = package_header->fw_info[i].offset; |
||
322 | break; |
||
323 | } else if (package_header->fw_info[i].stepping == '*' && |
||
7144 | serge | 324 | package_header->fw_info[i].substepping == '*') |
6084 | serge | 325 | dmc_offset = package_header->fw_info[i].offset; |
326 | } |
||
327 | if (dmc_offset == CSR_DEFAULT_FW_OFFSET) { |
||
328 | DRM_ERROR("Firmware not supported for %c stepping\n", stepping); |
||
6937 | serge | 329 | return NULL; |
6084 | serge | 330 | } |
331 | readcount += dmc_offset; |
||
332 | |||
333 | /* Extract dmc_header information. */ |
||
334 | dmc_header = (struct intel_dmc_header *)&fw->data[readcount]; |
||
335 | if (sizeof(struct intel_dmc_header) != (dmc_header->header_len)) { |
||
336 | DRM_ERROR("Firmware has wrong dmc header length %u bytes\n", |
||
7144 | serge | 337 | (dmc_header->header_len)); |
6937 | serge | 338 | return NULL; |
6084 | serge | 339 | } |
340 | readcount += sizeof(struct intel_dmc_header); |
||
341 | |||
342 | /* Cache the dmc header info. */ |
||
343 | if (dmc_header->mmio_count > ARRAY_SIZE(csr->mmioaddr)) { |
||
344 | DRM_ERROR("Firmware has wrong mmio count %u\n", |
||
7144 | serge | 345 | dmc_header->mmio_count); |
6937 | serge | 346 | return NULL; |
6084 | serge | 347 | } |
348 | csr->mmio_count = dmc_header->mmio_count; |
||
349 | for (i = 0; i < dmc_header->mmio_count; i++) { |
||
350 | if (dmc_header->mmioaddr[i] < CSR_MMIO_START_RANGE || |
||
7144 | serge | 351 | dmc_header->mmioaddr[i] > CSR_MMIO_END_RANGE) { |
6084 | serge | 352 | DRM_ERROR(" Firmware has wrong mmio address 0x%x\n", |
7144 | serge | 353 | dmc_header->mmioaddr[i]); |
6937 | serge | 354 | return NULL; |
6084 | serge | 355 | } |
6937 | serge | 356 | csr->mmioaddr[i] = _MMIO(dmc_header->mmioaddr[i]); |
6084 | serge | 357 | csr->mmiodata[i] = dmc_header->mmiodata[i]; |
358 | } |
||
359 | |||
360 | /* fw_size is in dwords, so multiplied by 4 to convert into bytes. */ |
||
361 | nbytes = dmc_header->fw_size * 4; |
||
362 | if (nbytes > CSR_MAX_FW_SIZE) { |
||
363 | DRM_ERROR("CSR firmware too big (%u) bytes\n", nbytes); |
||
6937 | serge | 364 | return NULL; |
6084 | serge | 365 | } |
366 | csr->dmc_fw_size = dmc_header->fw_size; |
||
367 | |||
6937 | serge | 368 | dmc_payload = kmalloc(nbytes, GFP_KERNEL); |
369 | if (!dmc_payload) { |
||
6084 | serge | 370 | DRM_ERROR("Memory allocation failed for dmc payload\n"); |
6937 | serge | 371 | return NULL; |
6084 | serge | 372 | } |
373 | |||
374 | memcpy(dmc_payload, &fw->data[readcount], nbytes); |
||
375 | |||
6937 | serge | 376 | return dmc_payload; |
377 | } |
||
378 | |||
7144 | serge | 379 | static void csr_load_work_fn(struct work_struct *work) |
6937 | serge | 380 | { |
7144 | serge | 381 | struct drm_i915_private *dev_priv; |
6937 | serge | 382 | struct intel_csr *csr; |
383 | const struct firmware *fw; |
||
384 | int ret; |
||
385 | |||
7144 | serge | 386 | dev_priv = container_of(work, typeof(*dev_priv), csr.work); |
6937 | serge | 387 | csr = &dev_priv->csr; |
388 | |||
389 | ret = request_firmware(&fw, dev_priv->csr.fw_path, |
||
390 | &dev_priv->dev->pdev->dev); |
||
391 | if (!fw) |
||
392 | goto out; |
||
393 | |||
394 | dev_priv->csr.dmc_payload = parse_csr_fw(dev_priv, fw); |
||
395 | if (!dev_priv->csr.dmc_payload) |
||
396 | goto out; |
||
397 | |||
6084 | serge | 398 | /* load csr program during system boot, as needed for DC states */ |
6937 | serge | 399 | intel_csr_load_program(dev_priv); |
6084 | serge | 400 | |
401 | out: |
||
6937 | serge | 402 | if (dev_priv->csr.dmc_payload) { |
403 | intel_display_power_put(dev_priv, POWER_DOMAIN_INIT); |
||
6084 | serge | 404 | |
6937 | serge | 405 | DRM_INFO("Finished loading %s (v%u.%u)\n", |
406 | dev_priv->csr.fw_path, |
||
407 | CSR_VERSION_MAJOR(csr->version), |
||
408 | CSR_VERSION_MINOR(csr->version)); |
||
409 | } else { |
||
7144 | serge | 410 | dev_notice(dev_priv->dev->dev, |
411 | "Failed to load DMC firmware" |
||
412 | " [" FIRMWARE_URL "]," |
||
413 | " disabling runtime power management.\n"); |
||
414 | } |
||
6937 | serge | 415 | |
6084 | serge | 416 | release_firmware(fw); |
417 | } |
||
418 | |||
419 | /** |
||
420 | * intel_csr_ucode_init() - initialize the firmware loading. |
||
6937 | serge | 421 | * @dev_priv: i915 drm device. |
6084 | serge | 422 | * |
423 | * This function is called at the time of loading the display driver to read |
||
424 | * firmware from a .bin file and copied into a internal memory. |
||
425 | */ |
||
6937 | serge | 426 | void intel_csr_ucode_init(struct drm_i915_private *dev_priv) |
6084 | serge | 427 | { |
428 | struct intel_csr *csr = &dev_priv->csr; |
||
429 | |||
7144 | serge | 430 | INIT_WORK(&dev_priv->csr.work, csr_load_work_fn); |
431 | |||
6937 | serge | 432 | if (!HAS_CSR(dev_priv)) |
6084 | serge | 433 | return; |
434 | |||
7144 | serge | 435 | if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) |
6084 | serge | 436 | csr->fw_path = I915_CSR_SKL; |
437 | else if (IS_BROXTON(dev_priv)) |
||
438 | csr->fw_path = I915_CSR_BXT; |
||
439 | else { |
||
440 | DRM_ERROR("Unexpected: no known CSR firmware for platform\n"); |
||
441 | return; |
||
442 | } |
||
6937 | serge | 443 | |
6660 | serge | 444 | DRM_DEBUG_KMS("Loading %s\n", csr->fw_path); |
445 | |||
6084 | serge | 446 | /* |
447 | * Obtain a runtime pm reference, until CSR is loaded, |
||
448 | * to avoid entering runtime-suspend. |
||
449 | */ |
||
6937 | serge | 450 | intel_display_power_get(dev_priv, POWER_DOMAIN_INIT); |
6084 | serge | 451 | |
7144 | serge | 452 | schedule_work(&dev_priv->csr.work); |
6084 | serge | 453 | } |
454 | |||
455 | /** |
||
456 | * intel_csr_ucode_fini() - unload the CSR firmware. |
||
6937 | serge | 457 | * @dev_priv: i915 drm device. |
6084 | serge | 458 | * |
459 | * Firmmware unloading includes freeing the internal momory and reset the |
||
460 | * firmware loading status. |
||
461 | */ |
||
6937 | serge | 462 | void intel_csr_ucode_fini(struct drm_i915_private *dev_priv) |
6084 | serge | 463 | { |
6937 | serge | 464 | if (!HAS_CSR(dev_priv)) |
6084 | serge | 465 | return; |
466 | |||
6937 | serge | 467 | |
6084 | serge | 468 | kfree(dev_priv->csr.dmc_payload); |
469 | }>>>>>>> |