diff options
Diffstat (limited to 'drivers/gpu/drm/i915/intel_fbdev.c')
-rw-r--r-- | drivers/gpu/drm/i915/intel_fbdev.c | 390 |
1 files changed, 370 insertions, 20 deletions
diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c index 39eac9937a4a..f73ba5e6b7a8 100644 --- a/drivers/gpu/drm/i915/intel_fbdev.c +++ b/drivers/gpu/drm/i915/intel_fbdev.c | |||
@@ -62,6 +62,7 @@ static int intelfb_alloc(struct drm_fb_helper *helper, | |||
62 | { | 62 | { |
63 | struct intel_fbdev *ifbdev = | 63 | struct intel_fbdev *ifbdev = |
64 | container_of(helper, struct intel_fbdev, helper); | 64 | container_of(helper, struct intel_fbdev, helper); |
65 | struct drm_framebuffer *fb; | ||
65 | struct drm_device *dev = helper->dev; | 66 | struct drm_device *dev = helper->dev; |
66 | struct drm_mode_fb_cmd2 mode_cmd = {}; | 67 | struct drm_mode_fb_cmd2 mode_cmd = {}; |
67 | struct drm_i915_gem_object *obj; | 68 | struct drm_i915_gem_object *obj; |
@@ -93,18 +94,22 @@ static int intelfb_alloc(struct drm_fb_helper *helper, | |||
93 | /* Flush everything out, we'll be doing GTT only from now on */ | 94 | /* Flush everything out, we'll be doing GTT only from now on */ |
94 | ret = intel_pin_and_fence_fb_obj(dev, obj, NULL); | 95 | ret = intel_pin_and_fence_fb_obj(dev, obj, NULL); |
95 | if (ret) { | 96 | if (ret) { |
96 | DRM_ERROR("failed to pin fb: %d\n", ret); | 97 | DRM_ERROR("failed to pin obj: %d\n", ret); |
97 | goto out_unref; | 98 | goto out_unref; |
98 | } | 99 | } |
99 | 100 | ||
100 | ret = intel_framebuffer_init(dev, &ifbdev->ifb, &mode_cmd, obj); | 101 | fb = __intel_framebuffer_create(dev, &mode_cmd, obj); |
101 | if (ret) | 102 | if (IS_ERR(fb)) { |
103 | ret = PTR_ERR(fb); | ||
102 | goto out_unpin; | 104 | goto out_unpin; |
105 | } | ||
106 | |||
107 | ifbdev->fb = to_intel_framebuffer(fb); | ||
103 | 108 | ||
104 | return 0; | 109 | return 0; |
105 | 110 | ||
106 | out_unpin: | 111 | out_unpin: |
107 | i915_gem_object_unpin(obj); | 112 | i915_gem_object_ggtt_unpin(obj); |
108 | out_unref: | 113 | out_unref: |
109 | drm_gem_object_unreference(&obj->base); | 114 | drm_gem_object_unreference(&obj->base); |
110 | out: | 115 | out: |
@@ -116,23 +121,36 @@ static int intelfb_create(struct drm_fb_helper *helper, | |||
116 | { | 121 | { |
117 | struct intel_fbdev *ifbdev = | 122 | struct intel_fbdev *ifbdev = |
118 | container_of(helper, struct intel_fbdev, helper); | 123 | container_of(helper, struct intel_fbdev, helper); |
119 | struct intel_framebuffer *intel_fb = &ifbdev->ifb; | 124 | struct intel_framebuffer *intel_fb = ifbdev->fb; |
120 | struct drm_device *dev = helper->dev; | 125 | struct drm_device *dev = helper->dev; |
121 | struct drm_i915_private *dev_priv = dev->dev_private; | 126 | struct drm_i915_private *dev_priv = dev->dev_private; |
122 | struct fb_info *info; | 127 | struct fb_info *info; |
123 | struct drm_framebuffer *fb; | 128 | struct drm_framebuffer *fb; |
124 | struct drm_i915_gem_object *obj; | 129 | struct drm_i915_gem_object *obj; |
125 | int size, ret; | 130 | int size, ret; |
131 | bool prealloc = false; | ||
126 | 132 | ||
127 | mutex_lock(&dev->struct_mutex); | 133 | mutex_lock(&dev->struct_mutex); |
128 | 134 | ||
129 | if (!intel_fb->obj) { | 135 | if (intel_fb && |
136 | (sizes->fb_width > intel_fb->base.width || | ||
137 | sizes->fb_height > intel_fb->base.height)) { | ||
138 | DRM_DEBUG_KMS("BIOS fb too small (%dx%d), we require (%dx%d)," | ||
139 | " releasing it\n", | ||
140 | intel_fb->base.width, intel_fb->base.height, | ||
141 | sizes->fb_width, sizes->fb_height); | ||
142 | drm_framebuffer_unreference(&intel_fb->base); | ||
143 | intel_fb = ifbdev->fb = NULL; | ||
144 | } | ||
145 | if (!intel_fb || WARN_ON(!intel_fb->obj)) { | ||
130 | DRM_DEBUG_KMS("no BIOS fb, allocating a new one\n"); | 146 | DRM_DEBUG_KMS("no BIOS fb, allocating a new one\n"); |
131 | ret = intelfb_alloc(helper, sizes); | 147 | ret = intelfb_alloc(helper, sizes); |
132 | if (ret) | 148 | if (ret) |
133 | goto out_unlock; | 149 | goto out_unlock; |
150 | intel_fb = ifbdev->fb; | ||
134 | } else { | 151 | } else { |
135 | DRM_DEBUG_KMS("re-using BIOS fb\n"); | 152 | DRM_DEBUG_KMS("re-using BIOS fb\n"); |
153 | prealloc = true; | ||
136 | sizes->fb_width = intel_fb->base.width; | 154 | sizes->fb_width = intel_fb->base.width; |
137 | sizes->fb_height = intel_fb->base.height; | 155 | sizes->fb_height = intel_fb->base.height; |
138 | } | 156 | } |
@@ -148,7 +166,7 @@ static int intelfb_create(struct drm_fb_helper *helper, | |||
148 | 166 | ||
149 | info->par = helper; | 167 | info->par = helper; |
150 | 168 | ||
151 | fb = &ifbdev->ifb.base; | 169 | fb = &ifbdev->fb->base; |
152 | 170 | ||
153 | ifbdev->helper.fb = fb; | 171 | ifbdev->helper.fb = fb; |
154 | ifbdev->helper.fbdev = info; | 172 | ifbdev->helper.fbdev = info; |
@@ -194,7 +212,7 @@ static int intelfb_create(struct drm_fb_helper *helper, | |||
194 | * If the object is stolen however, it will be full of whatever | 212 | * If the object is stolen however, it will be full of whatever |
195 | * garbage was left in there. | 213 | * garbage was left in there. |
196 | */ | 214 | */ |
197 | if (ifbdev->ifb.obj->stolen) | 215 | if (ifbdev->fb->obj->stolen && !prealloc) |
198 | memset_io(info->screen_base, 0, info->screen_size); | 216 | memset_io(info->screen_base, 0, info->screen_size); |
199 | 217 | ||
200 | /* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */ | 218 | /* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */ |
@@ -208,7 +226,7 @@ static int intelfb_create(struct drm_fb_helper *helper, | |||
208 | return 0; | 226 | return 0; |
209 | 227 | ||
210 | out_unpin: | 228 | out_unpin: |
211 | i915_gem_object_unpin(obj); | 229 | i915_gem_object_ggtt_unpin(obj); |
212 | drm_gem_object_unreference(&obj->base); | 230 | drm_gem_object_unreference(&obj->base); |
213 | out_unlock: | 231 | out_unlock: |
214 | mutex_unlock(&dev->struct_mutex); | 232 | mutex_unlock(&dev->struct_mutex); |
@@ -236,7 +254,202 @@ static void intel_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green, | |||
236 | *blue = intel_crtc->lut_b[regno] << 8; | 254 | *blue = intel_crtc->lut_b[regno] << 8; |
237 | } | 255 | } |
238 | 256 | ||
257 | static struct drm_fb_helper_crtc * | ||
258 | intel_fb_helper_crtc(struct drm_fb_helper *fb_helper, struct drm_crtc *crtc) | ||
259 | { | ||
260 | int i; | ||
261 | |||
262 | for (i = 0; i < fb_helper->crtc_count; i++) | ||
263 | if (fb_helper->crtc_info[i].mode_set.crtc == crtc) | ||
264 | return &fb_helper->crtc_info[i]; | ||
265 | |||
266 | return NULL; | ||
267 | } | ||
268 | |||
269 | /* | ||
270 | * Try to read the BIOS display configuration and use it for the initial | ||
271 | * fb configuration. | ||
272 | * | ||
273 | * The BIOS or boot loader will generally create an initial display | ||
274 | * configuration for us that includes some set of active pipes and displays. | ||
275 | * This routine tries to figure out which pipes and connectors are active | ||
276 | * and stuffs them into the crtcs and modes array given to us by the | ||
277 | * drm_fb_helper code. | ||
278 | * | ||
279 | * The overall sequence is: | ||
280 | * intel_fbdev_init - from driver load | ||
281 | * intel_fbdev_init_bios - initialize the intel_fbdev using BIOS data | ||
282 | * drm_fb_helper_init - build fb helper structs | ||
283 | * drm_fb_helper_single_add_all_connectors - more fb helper structs | ||
284 | * intel_fbdev_initial_config - apply the config | ||
285 | * drm_fb_helper_initial_config - call ->probe then register_framebuffer() | ||
286 | * drm_setup_crtcs - build crtc config for fbdev | ||
287 | * intel_fb_initial_config - find active connectors etc | ||
288 | * drm_fb_helper_single_fb_probe - set up fbdev | ||
289 | * intelfb_create - re-use or alloc fb, build out fbdev structs | ||
290 | * | ||
291 | * Note that we don't make special consideration whether we could actually | ||
292 | * switch to the selected modes without a full modeset. E.g. when the display | ||
293 | * is in VGA mode we need to recalculate watermarks and set a new high-res | ||
294 | * framebuffer anyway. | ||
295 | */ | ||
296 | static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper, | ||
297 | struct drm_fb_helper_crtc **crtcs, | ||
298 | struct drm_display_mode **modes, | ||
299 | bool *enabled, int width, int height) | ||
300 | { | ||
301 | struct drm_device *dev = fb_helper->dev; | ||
302 | int i, j; | ||
303 | bool *save_enabled; | ||
304 | bool fallback = true; | ||
305 | int num_connectors_enabled = 0; | ||
306 | int num_connectors_detected = 0; | ||
307 | |||
308 | /* | ||
309 | * If the user specified any force options, just bail here | ||
310 | * and use that config. | ||
311 | */ | ||
312 | for (i = 0; i < fb_helper->connector_count; i++) { | ||
313 | struct drm_fb_helper_connector *fb_conn; | ||
314 | struct drm_connector *connector; | ||
315 | |||
316 | fb_conn = fb_helper->connector_info[i]; | ||
317 | connector = fb_conn->connector; | ||
318 | |||
319 | if (!enabled[i]) | ||
320 | continue; | ||
321 | |||
322 | if (connector->force != DRM_FORCE_UNSPECIFIED) | ||
323 | return false; | ||
324 | } | ||
325 | |||
326 | save_enabled = kcalloc(dev->mode_config.num_connector, sizeof(bool), | ||
327 | GFP_KERNEL); | ||
328 | if (!save_enabled) | ||
329 | return false; | ||
330 | |||
331 | memcpy(save_enabled, enabled, dev->mode_config.num_connector); | ||
332 | |||
333 | for (i = 0; i < fb_helper->connector_count; i++) { | ||
334 | struct drm_fb_helper_connector *fb_conn; | ||
335 | struct drm_connector *connector; | ||
336 | struct drm_encoder *encoder; | ||
337 | struct drm_fb_helper_crtc *new_crtc; | ||
338 | |||
339 | fb_conn = fb_helper->connector_info[i]; | ||
340 | connector = fb_conn->connector; | ||
341 | |||
342 | if (connector->status == connector_status_connected) | ||
343 | num_connectors_detected++; | ||
344 | |||
345 | if (!enabled[i]) { | ||
346 | DRM_DEBUG_KMS("connector %d not enabled, skipping\n", | ||
347 | connector->base.id); | ||
348 | continue; | ||
349 | } | ||
350 | |||
351 | encoder = connector->encoder; | ||
352 | if (!encoder || WARN_ON(!encoder->crtc)) { | ||
353 | DRM_DEBUG_KMS("connector %d has no encoder or crtc, skipping\n", | ||
354 | connector->base.id); | ||
355 | enabled[i] = false; | ||
356 | continue; | ||
357 | } | ||
358 | |||
359 | num_connectors_enabled++; | ||
360 | |||
361 | new_crtc = intel_fb_helper_crtc(fb_helper, encoder->crtc); | ||
362 | |||
363 | /* | ||
364 | * Make sure we're not trying to drive multiple connectors | ||
365 | * with a single CRTC, since our cloning support may not | ||
366 | * match the BIOS. | ||
367 | */ | ||
368 | for (j = 0; j < fb_helper->connector_count; j++) { | ||
369 | if (crtcs[j] == new_crtc) { | ||
370 | DRM_DEBUG_KMS("fallback: cloned configuration\n"); | ||
371 | fallback = true; | ||
372 | goto out; | ||
373 | } | ||
374 | } | ||
375 | |||
376 | DRM_DEBUG_KMS("looking for cmdline mode on connector %d\n", | ||
377 | fb_conn->connector->base.id); | ||
378 | |||
379 | /* go for command line mode first */ | ||
380 | modes[i] = drm_pick_cmdline_mode(fb_conn, width, height); | ||
381 | |||
382 | /* try for preferred next */ | ||
383 | if (!modes[i]) { | ||
384 | DRM_DEBUG_KMS("looking for preferred mode on connector %d\n", | ||
385 | fb_conn->connector->base.id); | ||
386 | modes[i] = drm_has_preferred_mode(fb_conn, width, | ||
387 | height); | ||
388 | } | ||
389 | |||
390 | /* No preferred mode marked by the EDID? Are there any modes? */ | ||
391 | if (!modes[i] && !list_empty(&connector->modes)) { | ||
392 | DRM_DEBUG_KMS("using first mode listed on connector %s\n", | ||
393 | drm_get_connector_name(connector)); | ||
394 | modes[i] = list_first_entry(&connector->modes, | ||
395 | struct drm_display_mode, | ||
396 | head); | ||
397 | } | ||
398 | |||
399 | /* last resort: use current mode */ | ||
400 | if (!modes[i]) { | ||
401 | /* | ||
402 | * IMPORTANT: We want to use the adjusted mode (i.e. | ||
403 | * after the panel fitter upscaling) as the initial | ||
404 | * config, not the input mode, which is what crtc->mode | ||
405 | * usually contains. But since our current fastboot | ||
406 | * code puts a mode derived from the post-pfit timings | ||
407 | * into crtc->mode this works out correctly. We don't | ||
408 | * use hwmode anywhere right now, so use it for this | ||
409 | * since the fb helper layer wants a pointer to | ||
410 | * something we own. | ||
411 | */ | ||
412 | intel_mode_from_pipe_config(&encoder->crtc->hwmode, | ||
413 | &to_intel_crtc(encoder->crtc)->config); | ||
414 | modes[i] = &encoder->crtc->hwmode; | ||
415 | } | ||
416 | crtcs[i] = new_crtc; | ||
417 | |||
418 | DRM_DEBUG_KMS("connector %s on crtc %d: %s\n", | ||
419 | drm_get_connector_name(connector), | ||
420 | encoder->crtc->base.id, | ||
421 | modes[i]->name); | ||
422 | |||
423 | fallback = false; | ||
424 | } | ||
425 | |||
426 | /* | ||
427 | * If the BIOS didn't enable everything it could, fall back to have the | ||
428 | * same user experiencing of lighting up as much as possible like the | ||
429 | * fbdev helper library. | ||
430 | */ | ||
431 | if (num_connectors_enabled != num_connectors_detected && | ||
432 | num_connectors_enabled < INTEL_INFO(dev)->num_pipes) { | ||
433 | DRM_DEBUG_KMS("fallback: Not all outputs enabled\n"); | ||
434 | DRM_DEBUG_KMS("Enabled: %i, detected: %i\n", num_connectors_enabled, | ||
435 | num_connectors_detected); | ||
436 | fallback = true; | ||
437 | } | ||
438 | |||
439 | out: | ||
440 | if (fallback) { | ||
441 | DRM_DEBUG_KMS("Not using firmware configuration\n"); | ||
442 | memcpy(enabled, save_enabled, dev->mode_config.num_connector); | ||
443 | kfree(save_enabled); | ||
444 | return false; | ||
445 | } | ||
446 | |||
447 | kfree(save_enabled); | ||
448 | return true; | ||
449 | } | ||
450 | |||
239 | static struct drm_fb_helper_funcs intel_fb_helper_funcs = { | 451 | static struct drm_fb_helper_funcs intel_fb_helper_funcs = { |
452 | .initial_config = intel_fb_initial_config, | ||
240 | .gamma_set = intel_crtc_fb_gamma_set, | 453 | .gamma_set = intel_crtc_fb_gamma_set, |
241 | .gamma_get = intel_crtc_fb_gamma_get, | 454 | .gamma_get = intel_crtc_fb_gamma_get, |
242 | .fb_probe = intelfb_create, | 455 | .fb_probe = intelfb_create, |
@@ -258,8 +471,139 @@ static void intel_fbdev_destroy(struct drm_device *dev, | |||
258 | 471 | ||
259 | drm_fb_helper_fini(&ifbdev->helper); | 472 | drm_fb_helper_fini(&ifbdev->helper); |
260 | 473 | ||
261 | drm_framebuffer_unregister_private(&ifbdev->ifb.base); | 474 | drm_framebuffer_unregister_private(&ifbdev->fb->base); |
262 | intel_framebuffer_fini(&ifbdev->ifb); | 475 | drm_framebuffer_remove(&ifbdev->fb->base); |
476 | } | ||
477 | |||
478 | /* | ||
479 | * Build an intel_fbdev struct using a BIOS allocated framebuffer, if possible. | ||
480 | * The core display code will have read out the current plane configuration, | ||
481 | * so we use that to figure out if there's an object for us to use as the | ||
482 | * fb, and if so, we re-use it for the fbdev configuration. | ||
483 | * | ||
484 | * Note we only support a single fb shared across pipes for boot (mostly for | ||
485 | * fbcon), so we just find the biggest and use that. | ||
486 | */ | ||
487 | static bool intel_fbdev_init_bios(struct drm_device *dev, | ||
488 | struct intel_fbdev *ifbdev) | ||
489 | { | ||
490 | struct intel_framebuffer *fb = NULL; | ||
491 | struct drm_crtc *crtc; | ||
492 | struct intel_crtc *intel_crtc; | ||
493 | struct intel_plane_config *plane_config = NULL; | ||
494 | unsigned int max_size = 0; | ||
495 | |||
496 | if (!i915.fastboot) | ||
497 | return false; | ||
498 | |||
499 | /* Find the largest fb */ | ||
500 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { | ||
501 | intel_crtc = to_intel_crtc(crtc); | ||
502 | |||
503 | if (!intel_crtc->active || !crtc->primary->fb) { | ||
504 | DRM_DEBUG_KMS("pipe %c not active or no fb, skipping\n", | ||
505 | pipe_name(intel_crtc->pipe)); | ||
506 | continue; | ||
507 | } | ||
508 | |||
509 | if (intel_crtc->plane_config.size > max_size) { | ||
510 | DRM_DEBUG_KMS("found possible fb from plane %c\n", | ||
511 | pipe_name(intel_crtc->pipe)); | ||
512 | plane_config = &intel_crtc->plane_config; | ||
513 | fb = to_intel_framebuffer(crtc->primary->fb); | ||
514 | max_size = plane_config->size; | ||
515 | } | ||
516 | } | ||
517 | |||
518 | if (!fb) { | ||
519 | DRM_DEBUG_KMS("no active fbs found, not using BIOS config\n"); | ||
520 | goto out; | ||
521 | } | ||
522 | |||
523 | /* Now make sure all the pipes will fit into it */ | ||
524 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { | ||
525 | unsigned int cur_size; | ||
526 | |||
527 | intel_crtc = to_intel_crtc(crtc); | ||
528 | |||
529 | if (!intel_crtc->active) { | ||
530 | DRM_DEBUG_KMS("pipe %c not active, skipping\n", | ||
531 | pipe_name(intel_crtc->pipe)); | ||
532 | continue; | ||
533 | } | ||
534 | |||
535 | DRM_DEBUG_KMS("checking plane %c for BIOS fb\n", | ||
536 | pipe_name(intel_crtc->pipe)); | ||
537 | |||
538 | /* | ||
539 | * See if the plane fb we found above will fit on this | ||
540 | * pipe. Note we need to use the selected fb's pitch and bpp | ||
541 | * rather than the current pipe's, since they differ. | ||
542 | */ | ||
543 | cur_size = intel_crtc->config.adjusted_mode.crtc_hdisplay; | ||
544 | cur_size = cur_size * fb->base.bits_per_pixel / 8; | ||
545 | if (fb->base.pitches[0] < cur_size) { | ||
546 | DRM_DEBUG_KMS("fb not wide enough for plane %c (%d vs %d)\n", | ||
547 | pipe_name(intel_crtc->pipe), | ||
548 | cur_size, fb->base.pitches[0]); | ||
549 | plane_config = NULL; | ||
550 | fb = NULL; | ||
551 | break; | ||
552 | } | ||
553 | |||
554 | cur_size = intel_crtc->config.adjusted_mode.crtc_vdisplay; | ||
555 | cur_size = ALIGN(cur_size, plane_config->tiled ? (IS_GEN2(dev) ? 16 : 8) : 1); | ||
556 | cur_size *= fb->base.pitches[0]; | ||
557 | DRM_DEBUG_KMS("pipe %c area: %dx%d, bpp: %d, size: %d\n", | ||
558 | pipe_name(intel_crtc->pipe), | ||
559 | intel_crtc->config.adjusted_mode.crtc_hdisplay, | ||
560 | intel_crtc->config.adjusted_mode.crtc_vdisplay, | ||
561 | fb->base.bits_per_pixel, | ||
562 | cur_size); | ||
563 | |||
564 | if (cur_size > max_size) { | ||
565 | DRM_DEBUG_KMS("fb not big enough for plane %c (%d vs %d)\n", | ||
566 | pipe_name(intel_crtc->pipe), | ||
567 | cur_size, max_size); | ||
568 | plane_config = NULL; | ||
569 | fb = NULL; | ||
570 | break; | ||
571 | } | ||
572 | |||
573 | DRM_DEBUG_KMS("fb big enough for plane %c (%d >= %d)\n", | ||
574 | pipe_name(intel_crtc->pipe), | ||
575 | max_size, cur_size); | ||
576 | } | ||
577 | |||
578 | if (!fb) { | ||
579 | DRM_DEBUG_KMS("BIOS fb not suitable for all pipes, not using\n"); | ||
580 | goto out; | ||
581 | } | ||
582 | |||
583 | ifbdev->preferred_bpp = fb->base.bits_per_pixel; | ||
584 | ifbdev->fb = fb; | ||
585 | |||
586 | drm_framebuffer_reference(&ifbdev->fb->base); | ||
587 | |||
588 | /* Final pass to check if any active pipes don't have fbs */ | ||
589 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { | ||
590 | intel_crtc = to_intel_crtc(crtc); | ||
591 | |||
592 | if (!intel_crtc->active) | ||
593 | continue; | ||
594 | |||
595 | WARN(!crtc->primary->fb, | ||
596 | "re-used BIOS config but lost an fb on crtc %d\n", | ||
597 | crtc->base.id); | ||
598 | } | ||
599 | |||
600 | |||
601 | DRM_DEBUG_KMS("using BIOS fb for initial console\n"); | ||
602 | return true; | ||
603 | |||
604 | out: | ||
605 | |||
606 | return false; | ||
263 | } | 607 | } |
264 | 608 | ||
265 | int intel_fbdev_init(struct drm_device *dev) | 609 | int intel_fbdev_init(struct drm_device *dev) |
@@ -268,21 +612,25 @@ int intel_fbdev_init(struct drm_device *dev) | |||
268 | struct drm_i915_private *dev_priv = dev->dev_private; | 612 | struct drm_i915_private *dev_priv = dev->dev_private; |
269 | int ret; | 613 | int ret; |
270 | 614 | ||
271 | ifbdev = kzalloc(sizeof(*ifbdev), GFP_KERNEL); | 615 | if (WARN_ON(INTEL_INFO(dev)->num_pipes == 0)) |
272 | if (!ifbdev) | 616 | return -ENODEV; |
617 | |||
618 | ifbdev = kzalloc(sizeof(struct intel_fbdev), GFP_KERNEL); | ||
619 | if (ifbdev == NULL) | ||
273 | return -ENOMEM; | 620 | return -ENOMEM; |
274 | 621 | ||
275 | dev_priv->fbdev = ifbdev; | ||
276 | ifbdev->helper.funcs = &intel_fb_helper_funcs; | 622 | ifbdev->helper.funcs = &intel_fb_helper_funcs; |
623 | if (!intel_fbdev_init_bios(dev, ifbdev)) | ||
624 | ifbdev->preferred_bpp = 32; | ||
277 | 625 | ||
278 | ret = drm_fb_helper_init(dev, &ifbdev->helper, | 626 | ret = drm_fb_helper_init(dev, &ifbdev->helper, |
279 | INTEL_INFO(dev)->num_pipes, | 627 | INTEL_INFO(dev)->num_pipes, 4); |
280 | 4); | ||
281 | if (ret) { | 628 | if (ret) { |
282 | kfree(ifbdev); | 629 | kfree(ifbdev); |
283 | return ret; | 630 | return ret; |
284 | } | 631 | } |
285 | 632 | ||
633 | dev_priv->fbdev = ifbdev; | ||
286 | drm_fb_helper_single_add_all_connectors(&ifbdev->helper); | 634 | drm_fb_helper_single_add_all_connectors(&ifbdev->helper); |
287 | 635 | ||
288 | return 0; | 636 | return 0; |
@@ -291,9 +639,10 @@ int intel_fbdev_init(struct drm_device *dev) | |||
291 | void intel_fbdev_initial_config(struct drm_device *dev) | 639 | void intel_fbdev_initial_config(struct drm_device *dev) |
292 | { | 640 | { |
293 | struct drm_i915_private *dev_priv = dev->dev_private; | 641 | struct drm_i915_private *dev_priv = dev->dev_private; |
642 | struct intel_fbdev *ifbdev = dev_priv->fbdev; | ||
294 | 643 | ||
295 | /* Due to peculiar init order wrt to hpd handling this is separate. */ | 644 | /* Due to peculiar init order wrt to hpd handling this is separate. */ |
296 | drm_fb_helper_initial_config(&dev_priv->fbdev->helper, 32); | 645 | drm_fb_helper_initial_config(&ifbdev->helper, ifbdev->preferred_bpp); |
297 | } | 646 | } |
298 | 647 | ||
299 | void intel_fbdev_fini(struct drm_device *dev) | 648 | void intel_fbdev_fini(struct drm_device *dev) |
@@ -322,7 +671,7 @@ void intel_fbdev_set_suspend(struct drm_device *dev, int state) | |||
322 | * been restored from swap. If the object is stolen however, it will be | 671 | * been restored from swap. If the object is stolen however, it will be |
323 | * full of whatever garbage was left in there. | 672 | * full of whatever garbage was left in there. |
324 | */ | 673 | */ |
325 | if (state == FBINFO_STATE_RUNNING && ifbdev->ifb.obj->stolen) | 674 | if (state == FBINFO_STATE_RUNNING && ifbdev->fb->obj->stolen) |
326 | memset_io(info->screen_base, 0, info->screen_size); | 675 | memset_io(info->screen_base, 0, info->screen_size); |
327 | 676 | ||
328 | fb_set_suspend(info, state); | 677 | fb_set_suspend(info, state); |
@@ -331,7 +680,8 @@ void intel_fbdev_set_suspend(struct drm_device *dev, int state) | |||
331 | void intel_fbdev_output_poll_changed(struct drm_device *dev) | 680 | void intel_fbdev_output_poll_changed(struct drm_device *dev) |
332 | { | 681 | { |
333 | struct drm_i915_private *dev_priv = dev->dev_private; | 682 | struct drm_i915_private *dev_priv = dev->dev_private; |
334 | drm_fb_helper_hotplug_event(&dev_priv->fbdev->helper); | 683 | if (dev_priv->fbdev) |
684 | drm_fb_helper_hotplug_event(&dev_priv->fbdev->helper); | ||
335 | } | 685 | } |
336 | 686 | ||
337 | void intel_fbdev_restore_mode(struct drm_device *dev) | 687 | void intel_fbdev_restore_mode(struct drm_device *dev) |
@@ -339,7 +689,7 @@ void intel_fbdev_restore_mode(struct drm_device *dev) | |||
339 | int ret; | 689 | int ret; |
340 | struct drm_i915_private *dev_priv = dev->dev_private; | 690 | struct drm_i915_private *dev_priv = dev->dev_private; |
341 | 691 | ||
342 | if (INTEL_INFO(dev)->num_pipes == 0) | 692 | if (!dev_priv->fbdev) |
343 | return; | 693 | return; |
344 | 694 | ||
345 | drm_modeset_lock_all(dev); | 695 | drm_modeset_lock_all(dev); |