Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk> --- drivers/gpu/drm/i915/i915_dma.c | 4 ++ drivers/gpu/drm/i915/intel_display.c | 3 - drivers/gpu/drm/i915/intel_drv.h | 1 + drivers/gpu/drm/i915/intel_fb.c | 118 ++++++++++++++++++++++++++++++++-- 4 files changed, 119 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index f947926..51c8200 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1312,6 +1312,9 @@ static int i915_load_modeset_init(struct drm_device *dev) intel_modeset_init(dev); + /* Wrap existing BIOS mode configuration prior to GEM takeover */ + intel_fbdev_init_bios(dev); + ret = i915_gem_init(dev); if (ret) goto cleanup_gem_stolen; @@ -1326,6 +1329,7 @@ static int i915_load_modeset_init(struct drm_device *dev) /* FIXME: do pre/post-mode set stuff in core KMS code */ dev->vblank_disable_allowed = 1; + /* Install a default KMS/GEM fbcon if we failed to wrap the BIOS fb */ ret = intel_fbdev_init(dev); if (ret) goto cleanup_irq; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 1a0ded5..97f294e 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6506,9 +6506,6 @@ static void intel_setup_outputs(struct drm_device *dev) intel_encoder_clones(dev, encoder->clone_mask); } - /* disable all the possible outputs/crtcs before entering KMS mode */ - drm_helper_disable_unused_functions(dev); - if (HAS_PCH_SPLIT(dev)) ironlake_init_pch_refclk(dev); } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 094f31e..762d580 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -436,6 +436,7 @@ extern int intel_framebuffer_init(struct drm_device *dev, struct intel_framebuffer *ifb, struct drm_mode_fb_cmd2 *mode_cmd, struct drm_i915_gem_object *obj); +extern void intel_fbdev_init_bios(struct drm_device *dev); extern int intel_fbdev_init(struct drm_device *dev); extern void intel_fbdev_fini(struct drm_device *dev); extern void intel_fbdev_set_suspend(struct drm_device *dev, int state); diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c index 7835297..9be61b5 100644 --- a/drivers/gpu/drm/i915/intel_fb.c +++ b/drivers/gpu/drm/i915/intel_fb.c @@ -233,19 +233,127 @@ static void intel_fbdev_destroy(struct drm_device *dev, } } -int intel_fbdev_init(struct drm_device *dev) +void intel_fbdev_init_bios(struct drm_device *dev) { + struct drm_i915_private *dev_priv = dev->dev_private; struct intel_fbdev *ifbdev; + int pipe, ret; + + for_each_pipe(pipe) { + struct intel_crtc *crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]); + struct drm_mode_fb_cmd2 mode_cmd; + struct drm_i915_gem_object *obj; + struct fb_info *info; + u32 val, bpp, depth; + u32 size, offset; + + val = I915_READ(DSPCNTR(crtc->plane)); + if ((val & DISPLAY_PLANE_ENABLE) == 0) + continue; + + if (INTEL_INFO(dev)->gen >= 4) { + if (val & DISPPLANE_TILED) + continue; /* unexpected! */ + } + + switch (val & DISPPLANE_PIXFORMAT_MASK) { + default: + case DISPPLANE_8BPP: + continue; /* ignore palettes */ + case DISPPLANE_15_16BPP: + depth = 15; bpp = 16; + break; + case DISPPLANE_16BPP: + depth = bpp = 16; + break; + case DISPPLANE_32BPP_NO_ALPHA: + depth = 24; bpp = 32; + break; + } + + if (INTEL_INFO(dev)->gen >= 4) + offset = I915_READ(DSPSURF(crtc->plane)); + else + offset = I915_READ(DSPADDR(crtc->plane)); + mode_cmd.pitches[0] = I915_READ(DSPSTRIDE(crtc->plane)); + + val = I915_READ(PIPESRC(crtc->pipe)); + mode_cmd.width = ((val >> 16) & 0xfff) + 1; + mode_cmd.height = ((val >> 0) & 0xfff) + 1; + mode_cmd.pixel_format = drm_mode_legacy_fb_format(bpp, depth); + + DRM_DEBUG_KMS("Found active pipe [%d/%d]: size=%dx%d@%d, offset=%x\n", + crtc->pipe, crtc->plane, + mode_cmd.width, mode_cmd.height, depth, offset); + + size = mode_cmd.pitches[0] * mode_cmd.height; + size = ALIGN(size, PAGE_SIZE); + + ifbdev = kzalloc(sizeof(struct intel_fbdev), GFP_KERNEL); + if (!ifbdev) + continue; + + ifbdev->helper.funcs = &intel_fb_helper_funcs; + ret = drm_fb_helper_init(dev, &ifbdev->helper, + dev_priv->num_pipe, + INTELFB_CONN_LIMIT); + if (ret) { + kfree(ifbdev); + continue; + } + + /* assume a 1:1 linear mapping between stolen and GTT */ + obj = i915_gem_object_create_stolen_for_preallocated + (dev, offset, offset, size); + if (obj == NULL) { + kfree(ifbdev); + continue; + } + + ret = intel_framebuffer_init(dev, &ifbdev->ifb, &mode_cmd, obj); + if (ret) { + drm_gem_object_unreference(&obj->base); + kfree(ifbdev); + continue; + } + + info = intelfb_create_info(ifbdev); + if (info == NULL) { + drm_gem_object_unreference(&obj->base); + kfree(ifbdev); + continue; + } + + crtc->base.fb = &ifbdev->ifb.base; + obj->pin_count++; + + drm_fb_helper_single_add_all_connectors(&ifbdev->helper); + drm_fb_helper_hotplug_event(&ifbdev->helper); + + vga_switcheroo_client_fb_set(dev->pdev, info); + dev_priv->fbdev = ifbdev; + return; + } + + /* otherwise disable all the possible crtcs before KMS */ + DRM_DEBUG_KMS("No active planes found\n"); + drm_helper_disable_unused_functions(dev); +} + +int intel_fbdev_init(struct drm_device *dev) +{ drm_i915_private_t *dev_priv = dev->dev_private; + struct intel_fbdev *ifbdev; int ret; + if (dev_priv->fbdev) + return 0; + ifbdev = kzalloc(sizeof(struct intel_fbdev), GFP_KERNEL); - if (!ifbdev) + if (ifbdev == NULL) return -ENOMEM; - dev_priv->fbdev = ifbdev; ifbdev->helper.funcs = &intel_fb_helper_funcs; - ret = drm_fb_helper_init(dev, &ifbdev->helper, dev_priv->num_pipe, INTELFB_CONN_LIMIT); @@ -254,6 +362,8 @@ int intel_fbdev_init(struct drm_device *dev) return ret; } + dev_priv->fbdev = ifbdev; + drm_fb_helper_single_add_all_connectors(&ifbdev->helper); drm_fb_helper_initial_config(&ifbdev->helper, 32); return 0; -- 1.7.10