X-Git-Url: https://git.openpandora.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=drivers%2Fstaging%2Fgma500%2Fpsb_fb.c;h=349fff850a1813ee80389e24ba07c2e1c2677cb8;hb=80f51c32c4b52e88c192de8471135dbbd158cc13;hp=99c03a2e06bdb32e8a20f579be0f4c975314805c;hpb=5f127133ee432d0b83ee26e8e3a3d7828ab5f2b1;p=pandora-kernel.git diff --git a/drivers/staging/gma500/psb_fb.c b/drivers/staging/gma500/psb_fb.c index 99c03a2e06bd..349fff850a18 100644 --- a/drivers/staging/gma500/psb_fb.c +++ b/drivers/staging/gma500/psb_fb.c @@ -1,5 +1,5 @@ /************************************************************************** - * Copyright (c) 2007, Intel Corporation. + * Copyright (c) 2007-2011, Intel Corporation. * All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it @@ -38,6 +38,8 @@ #include "psb_intel_drv.h" #include "psb_fb.h" +#include "mdfld_output.h" + static void psb_user_framebuffer_destroy(struct drm_framebuffer *fb); static int psb_user_framebuffer_create_handle(struct drm_framebuffer *fb, struct drm_file *file_priv, @@ -50,14 +52,6 @@ static const struct drm_framebuffer_funcs psb_fb_funcs = { #define CMAP_TOHW(_val, _width) ((((_val) << (_width)) + 0x7FFF - (_val)) >> 16) -void *psbfb_vdc_reg(struct drm_device *dev) -{ - struct drm_psb_private *dev_priv; - dev_priv = (struct drm_psb_private *) dev->dev_private; - return dev_priv->vdc_reg; -} -/*EXPORT_SYMBOL(psbfb_vdc_reg); */ - static int psbfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *info) @@ -97,109 +91,60 @@ static int psbfb_setcolreg(unsigned regno, unsigned red, unsigned green, return 0; } -static int psbfb_kms_off(struct drm_device *dev, int suspend) + +void psbfb_suspend(struct drm_device *dev) { struct drm_framebuffer *fb = 0; struct psb_framebuffer *psbfb = to_psb_fb(fb); - DRM_DEBUG("psbfb_kms_off_ioctl\n"); + console_lock(); mutex_lock(&dev->mode_config.mutex); list_for_each_entry(fb, &dev->mode_config.fb_list, head) { struct fb_info *info = psbfb->fbdev; - - if (suspend) { - fb_set_suspend(info, 1); - drm_fb_helper_blank(FB_BLANK_POWERDOWN, info); - } + fb_set_suspend(info, 1); + drm_fb_helper_blank(FB_BLANK_POWERDOWN, info); } mutex_unlock(&dev->mode_config.mutex); - return 0; -} - -int psbfb_kms_off_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - int ret; - - if (drm_psb_no_fb) - return 0; - console_lock(); - ret = psbfb_kms_off(dev, 0); console_unlock(); - - return ret; } -static int psbfb_kms_on(struct drm_device *dev, int resume) +void psbfb_resume(struct drm_device *dev) { struct drm_framebuffer *fb = 0; struct psb_framebuffer *psbfb = to_psb_fb(fb); - DRM_DEBUG("psbfb_kms_on_ioctl\n"); - + console_lock(); mutex_lock(&dev->mode_config.mutex); list_for_each_entry(fb, &dev->mode_config.fb_list, head) { struct fb_info *info = psbfb->fbdev; - - if (resume) { - fb_set_suspend(info, 0); - drm_fb_helper_blank(FB_BLANK_UNBLANK, info); - } + fb_set_suspend(info, 0); + drm_fb_helper_blank(FB_BLANK_UNBLANK, info); } mutex_unlock(&dev->mode_config.mutex); - - return 0; -} - -int psbfb_kms_on_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - int ret; - - if (drm_psb_no_fb) - return 0; - console_lock(); - ret = psbfb_kms_on(dev, 0); - console_unlock(); - drm_helper_disable_unused_functions(dev); - return ret; -} - -void psbfb_suspend(struct drm_device *dev) -{ - console_lock(); - psbfb_kms_off(dev, 1); - console_unlock(); -} - -void psbfb_resume(struct drm_device *dev) -{ - console_lock(); - psbfb_kms_on(dev, 1); console_unlock(); drm_helper_disable_unused_functions(dev); } static int psbfb_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) { - int page_num = 0; - int i; - unsigned long address = 0; - int ret; - unsigned long pfn; struct psb_framebuffer *psbfb = vma->vm_private_data; struct drm_device *dev = psbfb->base.dev; struct drm_psb_private *dev_priv = dev->dev_private; + int page_num; + int i; + unsigned long address; + int ret; + unsigned long pfn; + /* FIXME: assumes fb at stolen base which may not be true */ unsigned long phys_addr = (unsigned long)dev_priv->stolen_base; page_num = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; - address = (unsigned long)vmf->virtual_address; vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); for (i = 0; i < page_num; i++) { - pfn = (phys_addr >> PAGE_SHIFT); /* phys_to_pfn(phys_addr); */ + pfn = (phys_addr >> PAGE_SHIFT); ret = vm_insert_mixed(vma, address, pfn); if (unlikely((ret == -EBUSY) || (ret != 0 && i > 0))) @@ -208,22 +153,18 @@ static int psbfb_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) ret = (ret == -ENOMEM) ? VM_FAULT_OOM : VM_FAULT_SIGBUS; return ret; } - address += PAGE_SIZE; phys_addr += PAGE_SIZE; } - return VM_FAULT_NOPAGE; } static void psbfb_vm_open(struct vm_area_struct *vma) { - DRM_DEBUG("vm_open\n"); } static void psbfb_vm_close(struct vm_area_struct *vma) { - DRM_DEBUG("vm_close\n"); } static struct vm_operations_struct psbfb_vm_ops = { @@ -235,10 +176,7 @@ static struct vm_operations_struct psbfb_vm_ops = { static int psbfb_mmap(struct fb_info *info, struct vm_area_struct *vma) { struct psb_fbdev *fbdev = info->par; - struct psb_framebuffer *psbfb = fbdev->pfb; - char *fb_screen_base = NULL; - struct drm_device *dev = psbfb->base.dev; - struct drm_psb_private *dev_priv = dev->dev_private; + struct psb_framebuffer *psbfb = &fbdev->pfb; if (vma->vm_pgoff != 0) return -EINVAL; @@ -247,31 +185,23 @@ static int psbfb_mmap(struct fb_info *info, struct vm_area_struct *vma) if (!psbfb->addr_space) psbfb->addr_space = vma->vm_file->f_mapping; - - fb_screen_base = (char *)info->screen_base; - - DRM_DEBUG("vm_pgoff 0x%lx, screen base %p vram_addr %p\n", - vma->vm_pgoff, fb_screen_base, - dev_priv->vram_addr); - - /* FIXME: ultimately this needs to become 'if entirely stolen memory' */ - if (1 || fb_screen_base == dev_priv->vram_addr) { - vma->vm_ops = &psbfb_vm_ops; - vma->vm_private_data = (void *)psbfb; - vma->vm_flags |= VM_RESERVED | VM_IO | - VM_MIXEDMAP | VM_DONTEXPAND; - } else { - /* GTT memory backed by kernel/user pages, needs a different - approach ? - GEM ? */ - } - + /* + * If this is a GEM object then info->screen_base is the virtual + * kernel remapping of the object. FIXME: Review if this is + * suitable for our mmap work + */ + vma->vm_ops = &psbfb_vm_ops; + vma->vm_private_data = (void *)psbfb; + vma->vm_flags |= VM_RESERVED | VM_IO | + VM_MIXEDMAP | VM_DONTEXPAND; return 0; } -static int psbfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) +static int psbfb_ioctl(struct fb_info *info, unsigned int cmd, + unsigned long arg) { struct psb_fbdev *fbdev = info->par; - struct psb_framebuffer *psbfb = fbdev->pfb; + struct psb_framebuffer *psbfb = &fbdev->pfb; struct drm_device *dev = psbfb->base.dev; struct drm_psb_private *dev_priv = dev->dev_private; u32 __user *p = (u32 __user *)arg; @@ -281,6 +211,8 @@ static int psbfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg case 0x12345678: if (!capable(CAP_SYS_RAWIO)) return -EPERM; + if (!dev_priv->ops->accel_2d) + return -EOPNOTSUPP; if (get_user(l, p)) return -EFAULT; if (l > 32) @@ -300,16 +232,80 @@ static struct fb_ops psbfb_ops = { .fb_set_par = drm_fb_helper_set_par, .fb_blank = drm_fb_helper_blank, .fb_setcolreg = psbfb_setcolreg, - .fb_fillrect = psbfb_fillrect, + .fb_fillrect = cfb_fillrect, .fb_copyarea = psbfb_copyarea, - .fb_imageblit = psbfb_imageblit, + .fb_imageblit = cfb_imageblit, .fb_mmap = psbfb_mmap, .fb_sync = psbfb_sync, .fb_ioctl = psbfb_ioctl, }; +static struct fb_ops psbfb_unaccel_ops = { + .owner = THIS_MODULE, + .fb_check_var = drm_fb_helper_check_var, + .fb_set_par = drm_fb_helper_set_par, + .fb_blank = drm_fb_helper_blank, + .fb_setcolreg = psbfb_setcolreg, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_mmap = psbfb_mmap, + .fb_ioctl = psbfb_ioctl, +}; + +/** + * psb_framebuffer_init - initialize a framebuffer + * @dev: our DRM device + * @fb: framebuffer to set up + * @mode_cmd: mode description + * @gt: backing object + * + * Configure and fill in the boilerplate for our frame buffer. Return + * 0 on success or an error code if we fail. + */ +static int psb_framebuffer_init(struct drm_device *dev, + struct psb_framebuffer *fb, + struct drm_mode_fb_cmd *mode_cmd, + struct gtt_range *gt) +{ + int ret; + + if (mode_cmd->pitch & 63) + return -EINVAL; + switch (mode_cmd->bpp) { + case 8: + case 16: + case 24: + case 32: + break; + default: + return -EINVAL; + } + ret = drm_framebuffer_init(dev, &fb->base, &psb_fb_funcs); + if (ret) { + dev_err(dev->dev, "framebuffer init failed: %d\n", ret); + return ret; + } + drm_helper_mode_fill_fb_struct(&fb->base, mode_cmd); + fb->gtt = gt; + return 0; +} + +/** + * psb_framebuffer_create - create a framebuffer backed by gt + * @dev: our DRM device + * @mode_cmd: the description of the requested mode + * @gt: the backing object + * + * Create a framebuffer object backed by the gt, and fill in the + * boilerplate required + * + * TODO: review object references + */ + static struct drm_framebuffer *psb_framebuffer_create - (struct drm_device *dev, struct drm_mode_fb_cmd *r, + (struct drm_device *dev, + struct drm_mode_fb_cmd *mode_cmd, struct gtt_range *gt) { struct psb_framebuffer *fb; @@ -317,22 +313,14 @@ static struct drm_framebuffer *psb_framebuffer_create fb = kzalloc(sizeof(*fb), GFP_KERNEL); if (!fb) - return NULL; - - ret = drm_framebuffer_init(dev, &fb->base, &psb_fb_funcs); - - if (ret) - goto err; - - drm_helper_mode_fill_fb_struct(&fb->base, r); - - fb->gtt = gt; + return ERR_PTR(-ENOMEM); + ret = psb_framebuffer_init(dev, fb, mode_cmd, gt); + if (ret) { + kfree(fb); + return ERR_PTR(ret); + } return &fb->base; - -err: - kfree(fb); - return NULL; } /** @@ -345,15 +333,22 @@ err: * stolen memory or the system has no stolen memory we allocate a range * and back it with a GEM object. * - * In this case the GEM object has no handle. + * In this case the GEM object has no handle. + * + * FIXME: console speed up - allocate twice the space if room and use + * hardware scrolling for acceleration. */ static struct gtt_range *psbfb_alloc(struct drm_device *dev, int aligned_size) { struct gtt_range *backing; /* Begin by trying to use stolen memory backing */ backing = psb_gtt_alloc_range(dev, aligned_size, "fb", 1); - if (backing) - return backing; + if (backing) { + if (drm_gem_private_object_init(dev, + &backing->gem, aligned_size) == 0) + return backing; + psb_gtt_free_range(dev, backing); + } /* Next try using GEM host memory */ backing = psb_gtt_alloc_range(dev, aligned_size, "fb(gem)", 0); if (backing == NULL) @@ -366,7 +361,7 @@ static struct gtt_range *psbfb_alloc(struct drm_device *dev, int aligned_size) } return backing; } - + /** * psbfb_create - create a framebuffer * @fbdev: the framebuffer device @@ -381,65 +376,97 @@ static int psbfb_create(struct psb_fbdev *fbdev, struct drm_psb_private *dev_priv = dev->dev_private; struct fb_info *info; struct drm_framebuffer *fb; - struct psb_framebuffer *psbfb; + struct psb_framebuffer *psbfb = &fbdev->pfb; struct drm_mode_fb_cmd mode_cmd; struct device *device = &dev->pdev->dev; - int size, aligned_size; + int size; int ret; struct gtt_range *backing; mode_cmd.width = sizes->surface_width; mode_cmd.height = sizes->surface_height; + mode_cmd.bpp = sizes->surface_bpp; + + /* No 24bit packed */ + if (mode_cmd.bpp == 24) + mode_cmd.bpp = 32; - mode_cmd.bpp = 32; /* HW requires pitch to be 64 byte aligned */ - mode_cmd.pitch = ALIGN(mode_cmd.width * ((mode_cmd.bpp + 1) / 8), 64); - mode_cmd.depth = 24; + mode_cmd.pitch = ALIGN(mode_cmd.width * ((mode_cmd.bpp + 7) / 8), 64); + mode_cmd.depth = sizes->surface_depth; size = mode_cmd.pitch * mode_cmd.height; - aligned_size = ALIGN(size, PAGE_SIZE); + size = ALIGN(size, PAGE_SIZE); /* Allocate the framebuffer in the GTT with stolen page backing */ - backing = psbfb_alloc(dev, aligned_size); + backing = psbfb_alloc(dev, size); if (backing == NULL) - return -ENOMEM; + return -ENOMEM; mutex_lock(&dev->struct_mutex); - fb = psb_framebuffer_create(dev, &mode_cmd, backing); - if (!fb) { - DRM_ERROR("failed to allocate fb.\n"); - ret = -ENOMEM; - goto out_err1; - } - psbfb = to_psb_fb(fb); - info = framebuffer_alloc(sizeof(struct psb_fbdev), device); + info = framebuffer_alloc(0, device); if (!info) { ret = -ENOMEM; - goto out_err0; + goto out_err1; } - info->par = fbdev; + ret = psb_framebuffer_init(dev, psbfb, &mode_cmd, backing); + if (ret) + goto out_unref; + + fb = &psbfb->base; psbfb->fbdev = info; fbdev->psb_fb_helper.fb = fb; fbdev->psb_fb_helper.fbdev = info; - fbdev->pfb = psbfb; strcpy(info->fix.id, "psbfb"); info->flags = FBINFO_DEFAULT; - info->fbops = &psbfb_ops; + /* No 2D engine */ + if (!dev_priv->ops->accel_2d) + info->fbops = &psbfb_unaccel_ops; + else + info->fbops = &psbfb_ops; + + ret = fb_alloc_cmap(&info->cmap, 256, 0); + if (ret) { + ret = -ENOMEM; + goto out_unref; + } + info->fix.smem_start = dev->mode_config.fb_base; info->fix.smem_len = size; - /* Accessed via stolen memory directly, This only works for stolem - memory however. Need to address this once we start using gtt - pages we allocate */ - info->screen_base = (char *)dev_priv->vram_addr + backing->offset; + if (backing->stolen) { + /* Accessed stolen memory directly */ + info->screen_base = (char *)dev_priv->vram_addr + + backing->offset; + } else { + /* Pin the pages into the GTT and create a mapping to them */ + psb_gtt_pin(backing); + info->screen_base = vm_map_ram(backing->pages, backing->npage, + -1, PAGE_KERNEL); + if (info->screen_base == NULL) { + psb_gtt_unpin(backing); + ret = -ENOMEM; + goto out_unref; + } + psbfb->vm_map = 1; + } info->screen_size = size; - memset(info->screen_base, 0, size); + + if (dev_priv->pg->stolen_size) { + info->apertures = alloc_apertures(1); + if (!info->apertures) { + ret = -ENOMEM; + goto out_unref; + } + info->apertures->ranges[0].base = dev->mode_config.fb_base; + info->apertures->ranges[0].size = dev_priv->pg->stolen_size; + } drm_fb_helper_fill_fix(info, fb->pitch, fb->depth); drm_fb_helper_fill_var(info, &fbdev->psb_fb_helper, @@ -454,17 +481,19 @@ static int psbfb_create(struct psb_fbdev *fbdev, info->pixmap.flags = FB_PIXMAP_SYSTEM; info->pixmap.scan_align = 1; - DRM_DEBUG("fb depth is %d\n", fb->depth); - DRM_DEBUG(" pitch is %d\n", fb->pitch); - - printk(KERN_INFO"allocated %dx%d fb\n", - psbfb->base.width, psbfb->base.height); + dev_info(dev->dev, "allocated %dx%d fb\n", + psbfb->base.width, psbfb->base.height); mutex_unlock(&dev->struct_mutex); - return 0; -out_err0: - fb->funcs->destroy(fb); +out_unref: + if (backing->stolen) + psb_gtt_free_range(dev, backing); + else { + if (psbfb->vm_map) + vm_unmap_ram(info->screen_base, backing->npage); + drm_gem_object_unreference(&backing->gem); + } out_err1: mutex_unlock(&dev->struct_mutex); psb_gtt_free_range(dev, backing); @@ -483,45 +512,30 @@ static struct drm_framebuffer *psb_user_framebuffer_create (struct drm_device *dev, struct drm_file *filp, struct drm_mode_fb_cmd *cmd) { - struct gtt_range *r; - struct drm_gem_object *obj; - struct psb_framebuffer *psbfb; + struct gtt_range *r; + struct drm_gem_object *obj; - /* Find the GEM object and thus the gtt range object that is - to back this space */ + /* + * Find the GEM object and thus the gtt range object that is + * to back this space + */ obj = drm_gem_object_lookup(dev, filp, cmd->handle); if (obj == NULL) - return ERR_PTR(-ENOENT); - - /* Allocate a framebuffer */ - psbfb = kzalloc(sizeof(*psbfb), GFP_KERNEL); - if (psbfb == NULL) { - drm_gem_object_unreference_unlocked(obj); - return ERR_PTR(-ENOMEM); - } - - /* Let the core code do all the work */ - r = container_of(obj, struct gtt_range, gem); - if (psb_framebuffer_create(dev, cmd, r) == NULL) { - drm_gem_object_unreference_unlocked(obj); - kfree(psbfb); - return ERR_PTR(-EINVAL); - } - /* Return the drm_framebuffer contained within the psb fbdev which - has been initialized by the framebuffer creation */ - return &psbfb->base; + return ERR_PTR(-ENOENT); + + /* Let the core code do all the work */ + r = container_of(obj, struct gtt_range, gem); + return psb_framebuffer_create(dev, cmd, r); } static void psbfb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green, u16 blue, int regno) { - DRM_DEBUG("%s\n", __func__); } static void psbfb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green, u16 *blue, int regno) { - DRM_DEBUG("%s\n", __func__); } static int psbfb_probe(struct drm_fb_helper *helper, @@ -531,8 +545,6 @@ static int psbfb_probe(struct drm_fb_helper *helper, int new_fb = 0; int ret; - DRM_DEBUG("%s\n", __func__); - if (!helper->fb) { ret = psbfb_create(psb_fbdev, sizes); if (ret) @@ -551,24 +563,27 @@ struct drm_fb_helper_funcs psb_fb_helper_funcs = { int psb_fbdev_destroy(struct drm_device *dev, struct psb_fbdev *fbdev) { struct fb_info *info; - struct psb_framebuffer *psbfb = fbdev->pfb; + struct psb_framebuffer *psbfb = &fbdev->pfb; if (fbdev->psb_fb_helper.fbdev) { info = fbdev->psb_fb_helper.fbdev; - /* FIXME: this is a bit more inside knowledge than I'd like - but I don't see how to make a fake GEM object of the - stolen space nicely */ - if (psbfb->gtt->stolen) - psb_gtt_free_range(dev, psbfb->gtt); - else - drm_gem_object_unreference(&psbfb->gtt->gem); + + /* If this is our base framebuffer then kill any virtual map + for the framebuffer layer and unpin it */ + if (psbfb->vm_map) { + vm_unmap_ram(info->screen_base, psbfb->gtt->npage); + psb_gtt_unpin(psbfb->gtt); + } unregister_framebuffer(info); - iounmap(info->screen_base); + if (info->cmap.len) + fb_dealloc_cmap(&info->cmap); framebuffer_release(info); } - drm_fb_helper_fini(&fbdev->psb_fb_helper); drm_framebuffer_cleanup(&psbfb->base); + + if (psbfb->gtt) + drm_gem_object_unreference(&psbfb->gtt->gem); return 0; } @@ -580,13 +595,14 @@ int psb_fbdev_init(struct drm_device *dev) fbdev = kzalloc(sizeof(struct psb_fbdev), GFP_KERNEL); if (!fbdev) { - DRM_ERROR("no memory\n"); + dev_err(dev->dev, "no memory\n"); return -ENOMEM; } dev_priv->fbdev = fbdev; fbdev->psb_fb_helper.funcs = &psb_fb_helper_funcs; + /* FIXME: check Medfield */ num_crtc = 2; drm_fb_helper_init(dev, &fbdev->psb_fb_helper, num_crtc, @@ -616,22 +632,6 @@ static void psbfb_output_poll_changed(struct drm_device *dev) drm_fb_helper_hotplug_event(&fbdev->psb_fb_helper); } -int psbfb_remove(struct drm_device *dev, struct drm_framebuffer *fb) -{ - struct fb_info *info; - struct psb_framebuffer *psbfb = to_psb_fb(fb); - - if (drm_psb_no_fb) - return 0; - - info = psbfb->fbdev; - - if (info) - framebuffer_release(info); - return 0; -} -/*EXPORT_SYMBOL(psbfb_remove); */ - /** * psb_user_framebuffer_create_handle - add hamdle to a framebuffer * @fb: framebuffer @@ -646,11 +646,9 @@ static int psb_user_framebuffer_create_handle(struct drm_framebuffer *fb, struct drm_file *file_priv, unsigned int *handle) { - struct psb_framebuffer *psbfb = to_psb_fb(fb); - struct gtt_range *r = psbfb->gtt; - if (r->stolen) - return -EOPNOTSUPP; - return drm_gem_handle_create(file_priv, &r->gem, handle); + struct psb_framebuffer *psbfb = to_psb_fb(fb); + struct gtt_range *r = psbfb->gtt; + return drm_gem_handle_create(file_priv, &r->gem, handle); } /** @@ -662,18 +660,37 @@ static int psb_user_framebuffer_create_handle(struct drm_framebuffer *fb, */ static void psb_user_framebuffer_destroy(struct drm_framebuffer *fb) { - struct drm_device *dev = fb->dev; struct psb_framebuffer *psbfb = to_psb_fb(fb); struct gtt_range *r = psbfb->gtt; - - if (psbfb->fbdev) - psbfb_remove(dev, fb); - - /* Let DRM do its clean up */ + struct drm_device *dev = fb->dev; + struct drm_psb_private *dev_priv = dev->dev_private; + struct psb_fbdev *fbdev = dev_priv->fbdev; + struct drm_crtc *crtc; + int reset = 0; + + /* Should never get stolen memory for a user fb */ + WARN_ON(r->stolen); + + /* Check if we are erroneously live */ + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) + if (crtc->fb == fb) + reset = 1; + + if (reset) + /* + * Now force a sane response before we permit the DRM CRTC + * layer to do stupid things like blank the display. Instead + * we reset this framebuffer as if the user had forced a reset. + * We must do this before the cleanup so that the DRM layer + * doesn't get a chance to stick its oar in where it isn't + * wanted. + */ + drm_fb_helper_restore_fbdev_mode(&fbdev->psb_fb_helper); + + /* Let DRM do its clean up */ drm_framebuffer_cleanup(fb); /* We are no longer using the resource in GEM */ drm_gem_object_unreference_unlocked(&r->gem); - kfree(fb); } @@ -684,17 +701,14 @@ static const struct drm_mode_config_funcs psb_mode_funcs = { static int psb_create_backlight_property(struct drm_device *dev) { - struct drm_psb_private *dev_priv - = (struct drm_psb_private *) dev->dev_private; + struct drm_psb_private *dev_priv = dev->dev_private; struct drm_property *backlight; if (dev_priv->backlight_property) return 0; - backlight = drm_property_create(dev, - DRM_MODE_PROP_RANGE, - "backlight", - 2); + backlight = drm_property_create(dev, DRM_MODE_PROP_RANGE, + "backlight", 2); backlight->values[0] = 0; backlight->values[1] = 100; @@ -705,25 +719,13 @@ static int psb_create_backlight_property(struct drm_device *dev) static void psb_setup_outputs(struct drm_device *dev) { - struct drm_psb_private *dev_priv = - (struct drm_psb_private *) dev->dev_private; + struct drm_psb_private *dev_priv = dev->dev_private; struct drm_connector *connector; - PSB_DEBUG_ENTRY("\n"); - drm_mode_create_scaling_mode_property(dev); - psb_create_backlight_property(dev); - if (IS_MRST(dev)) { - if (dev_priv->iLVDS_enable) - mrst_lvds_init(dev, &dev_priv->mode_dev); - else - DRM_ERROR("DSI is not supported\n"); - } else { - psb_intel_lvds_init(dev, &dev_priv->mode_dev); - psb_intel_sdvo_init(dev, SDVOB); - } + dev_priv->ops->output_init(dev); list_for_each_entry(connector, &dev->mode_config.connector_list, head) { @@ -739,7 +741,6 @@ static void psb_setup_outputs(struct drm_device *dev) clone_mask = (1 << INTEL_OUTPUT_SDVO); break; case INTEL_OUTPUT_LVDS: - PSB_DEBUG_ENTRY("LVDS.\n"); if (IS_MRST(dev)) crtc_mask = (1 << 0); else @@ -747,26 +748,21 @@ static void psb_setup_outputs(struct drm_device *dev) clone_mask = (1 << INTEL_OUTPUT_LVDS); break; case INTEL_OUTPUT_MIPI: - PSB_DEBUG_ENTRY("MIPI.\n"); crtc_mask = (1 << 0); clone_mask = (1 << INTEL_OUTPUT_MIPI); break; case INTEL_OUTPUT_MIPI2: - PSB_DEBUG_ENTRY("MIPI2.\n"); crtc_mask = (1 << 2); clone_mask = (1 << INTEL_OUTPUT_MIPI2); break; case INTEL_OUTPUT_HDMI: - PSB_DEBUG_ENTRY("HDMI.\n"); crtc_mask = (1 << 1); clone_mask = (1 << INTEL_OUTPUT_HDMI); break; } - encoder->possible_crtcs = crtc_mask; encoder->possible_clones = psb_intel_connector_clones(dev, clone_mask); - } } @@ -777,8 +773,6 @@ void psb_modeset_init(struct drm_device *dev) struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev; int i; - PSB_DEBUG_ENTRY("\n"); - drm_mode_config_init(dev); dev->mode_config.min_width = 0; @@ -799,9 +793,6 @@ void psb_modeset_init(struct drm_device *dev) dev->mode_config.max_height = 2048; psb_setup_outputs(dev); - - /* setup fbs */ - /* drm_initial_config(dev); */ } void psb_modeset_cleanup(struct drm_device *dev) @@ -810,7 +801,6 @@ void psb_modeset_cleanup(struct drm_device *dev) drm_kms_helper_poll_fini(dev); psb_fbdev_fini(dev); - drm_mode_config_cleanup(dev); mutex_unlock(&dev->struct_mutex);