summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/radeon/radeon_fb.c
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2010-03-30 07:34:14 +0200
committerDave Airlie <airlied@redhat.com>2010-04-07 02:24:56 +0200
commit8be48d924c307e72e3797ab5bde81b07a1ccc52d (patch)
tree7d2fec8d40b0a6e9f7bd8a5aef5bb100783ecd44 /drivers/gpu/drm/radeon/radeon_fb.c
parentdrm/fb: fix fbdev object model + cleanup properly. (diff)
downloadlinux-8be48d924c307e72e3797ab5bde81b07a1ccc52d.tar.xz
linux-8be48d924c307e72e3797ab5bde81b07a1ccc52d.zip
drm/kms/fb: move to using fb helper crtc grouping instead of core crtc list
This move to using the list of crtcs in the fb helper and cleans up the whole picking code, now we store the crtc/connectors we want directly into the modeset and we use the modeset directly to set the mode. Fixes from James Simmons and Ben Skeggs. Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/radeon/radeon_fb.c')
-rw-r--r--drivers/gpu/drm/radeon/radeon_fb.c240
1 files changed, 132 insertions, 108 deletions
diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c
index a7e4c2a89ee0..705425defba0 100644
--- a/drivers/gpu/drm/radeon/radeon_fb.c
+++ b/drivers/gpu/drm/radeon/radeon_fb.c
@@ -23,10 +23,6 @@
* Authors:
* David Airlie
*/
- /*
- * Modularization
- */
-
#include <linux/module.h>
#include <linux/fb.h>
@@ -45,7 +41,7 @@
this contains a helper + a radeon fb
the helper contains a pointer to radeon framebuffer baseclass.
*/
-struct radeon_kernel_fbdev {
+struct radeon_fbdev {
struct drm_fb_helper helper;
struct radeon_framebuffer rfb;
struct list_head fbdev_list;
@@ -95,49 +91,44 @@ static struct drm_fb_helper_funcs radeon_fb_helper_funcs = {
.gamma_get = radeon_crtc_fb_gamma_get,
};
-static int radeonfb_create(struct drm_device *dev,
- struct drm_fb_helper_surface_size *sizes,
- struct radeon_kernel_fbdev **rfbdev_p)
+static void radeonfb_destroy_pinned_object(struct drm_gem_object *gobj)
{
- struct radeon_device *rdev = dev->dev_private;
- struct fb_info *info;
- struct radeon_kernel_fbdev *rfbdev;
- struct drm_framebuffer *fb = NULL;
- struct drm_mode_fb_cmd mode_cmd;
+ struct radeon_bo *rbo = gobj->driver_private;
+ int ret;
+
+ ret = radeon_bo_reserve(rbo, false);
+ if (likely(ret == 0)) {
+ radeon_bo_kunmap(rbo);
+ radeon_bo_unreserve(rbo);
+ }
+ drm_gem_object_unreference_unlocked(gobj);
+}
+
+static int radeonfb_create_pinned_object(struct radeon_fbdev *rfbdev,
+ struct drm_mode_fb_cmd *mode_cmd,
+ struct drm_gem_object **gobj_p)
+{
+ struct radeon_device *rdev = rfbdev->rdev;
struct drm_gem_object *gobj = NULL;
struct radeon_bo *rbo = NULL;
- struct device *device = &rdev->pdev->dev;
- int size, aligned_size, ret;
- u64 fb_gpuaddr;
- void *fbptr = NULL;
- unsigned long tmp;
bool fb_tiled = false; /* useful for testing */
u32 tiling_flags = 0;
+ int ret;
+ int aligned_size, size;
- mode_cmd.width = sizes->surface_width;
- mode_cmd.height = sizes->surface_height;
-
- /* avivo can't scanout real 24bpp */
- if ((sizes->surface_bpp == 24) && ASIC_IS_AVIVO(rdev))
- sizes->surface_bpp = 32;
-
- mode_cmd.bpp = sizes->surface_bpp;
/* need to align pitch with crtc limits */
- mode_cmd.pitch = radeon_align_pitch(rdev, mode_cmd.width, mode_cmd.bpp, fb_tiled) * ((mode_cmd.bpp + 1) / 8);
- mode_cmd.depth = sizes->surface_depth;
+ mode_cmd->pitch = radeon_align_pitch(rdev, mode_cmd->width, mode_cmd->bpp, fb_tiled) * ((mode_cmd->bpp + 1) / 8);
- size = mode_cmd.pitch * mode_cmd.height;
+ size = mode_cmd->pitch * mode_cmd->height;
aligned_size = ALIGN(size, PAGE_SIZE);
-
ret = radeon_gem_object_create(rdev, aligned_size, 0,
- RADEON_GEM_DOMAIN_VRAM,
- false, ttm_bo_type_kernel,
- &gobj);
+ RADEON_GEM_DOMAIN_VRAM,
+ false, ttm_bo_type_kernel,
+ &gobj);
if (ret) {
- printk(KERN_ERR "failed to allocate framebuffer (%d %d)\n",
- sizes->surface_width, sizes->surface_height);
- ret = -ENOMEM;
- goto out;
+ printk(KERN_ERR "failed to allocate framebuffer (%d)\n",
+ aligned_size);
+ return -ENOMEM;
}
rbo = gobj->driver_private;
@@ -145,7 +136,7 @@ static int radeonfb_create(struct drm_device *dev,
tiling_flags = RADEON_TILING_MACRO;
#ifdef __BIG_ENDIAN
- switch (mode_cmd.bpp) {
+ switch (mode_cmd->bpp) {
case 32:
tiling_flags |= RADEON_TILING_SWAP_32BIT;
break;
@@ -158,54 +149,82 @@ static int radeonfb_create(struct drm_device *dev,
if (tiling_flags) {
ret = radeon_bo_set_tiling_flags(rbo,
- tiling_flags | RADEON_TILING_SURFACE,
- mode_cmd.pitch);
+ tiling_flags | RADEON_TILING_SURFACE,
+ mode_cmd->pitch);
if (ret)
dev_err(rdev->dev, "FB failed to set tiling flags\n");
}
- mutex_lock(&rdev->ddev->struct_mutex);
+
ret = radeon_bo_reserve(rbo, false);
if (unlikely(ret != 0))
goto out_unref;
- ret = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, &fb_gpuaddr);
+ ret = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, NULL);
if (ret) {
radeon_bo_unreserve(rbo);
goto out_unref;
}
if (fb_tiled)
radeon_bo_check_tiling(rbo, 0, 0);
- ret = radeon_bo_kmap(rbo, &fbptr);
+ ret = radeon_bo_kmap(rbo, NULL);
radeon_bo_unreserve(rbo);
if (ret) {
goto out_unref;
}
- info = framebuffer_alloc(sizeof(struct radeon_kernel_fbdev), device);
+ *gobj_p = gobj;
+ return 0;
+out_unref:
+ radeonfb_destroy_pinned_object(gobj);
+ *gobj_p = NULL;
+ return ret;
+}
+
+static int radeonfb_create(struct radeon_fbdev *rfbdev,
+ struct drm_fb_helper_surface_size *sizes)
+{
+ struct radeon_device *rdev = rfbdev->rdev;
+ struct fb_info *info;
+ struct drm_framebuffer *fb = NULL;
+ struct drm_mode_fb_cmd mode_cmd;
+ struct drm_gem_object *gobj = NULL;
+ struct radeon_bo *rbo = NULL;
+ struct device *device = &rdev->pdev->dev;
+ int ret;
+ unsigned long tmp;
+
+ mode_cmd.width = sizes->surface_width;
+ mode_cmd.height = sizes->surface_height;
+
+ /* avivo can't scanout real 24bpp */
+ if ((sizes->surface_bpp == 24) && ASIC_IS_AVIVO(rdev))
+ sizes->surface_bpp = 32;
+
+ mode_cmd.bpp = sizes->surface_bpp;
+ mode_cmd.depth = sizes->surface_depth;
+
+ ret = radeonfb_create_pinned_object(rfbdev, &mode_cmd, &gobj);
+ rbo = gobj->driver_private;
+
+ /* okay we have an object now allocate the framebuffer */
+ info = framebuffer_alloc(0, device);
if (info == NULL) {
ret = -ENOMEM;
goto out_unref;
}
- rfbdev = info->par;
- rfbdev->rdev = rdev;
- radeon_framebuffer_init(dev, &rfbdev->rfb, &mode_cmd, gobj);
+ info->par = rfbdev;
+
+ radeon_framebuffer_init(rdev->ddev, &rfbdev->rfb, &mode_cmd, gobj);
+
fb = &rfbdev->rfb.base;
/* setup helper */
rfbdev->helper.fb = fb;
rfbdev->helper.fbdev = info;
rfbdev->helper.funcs = &radeon_fb_helper_funcs;
- rfbdev->helper.dev = dev;
-
- *rfbdev_p = rfbdev;
- ret = drm_fb_helper_init_crtc_count(&rfbdev->helper, rdev->num_crtc,
- RADEONFB_CONN_LIMIT);
- if (ret)
- goto out_unref;
-
- memset_io(fbptr, 0x0, aligned_size);
+ memset_io(rbo->kptr, 0x0, radeon_bo_size(rbo));
strcpy(info->fix.id, "radeondrmfb");
@@ -214,11 +233,11 @@ static int radeonfb_create(struct drm_device *dev,
info->flags = FBINFO_DEFAULT;
info->fbops = &radeonfb_ops;
- tmp = fb_gpuaddr - rdev->mc.vram_start;
+ tmp = radeon_bo_gpu_offset(rbo) - rdev->mc.vram_start;
info->fix.smem_start = rdev->mc.aper_base + tmp;
- info->fix.smem_len = size;
- info->screen_base = fbptr;
- info->screen_size = size;
+ info->fix.smem_len = radeon_bo_size(rbo);
+ info->screen_base = rbo->kptr;
+ info->screen_size = radeon_bo_size(rbo);
drm_fb_helper_fill_var(info, &rfbdev->helper, sizes->fb_width, sizes->fb_height);
@@ -239,60 +258,40 @@ static int radeonfb_create(struct drm_device *dev,
}
DRM_INFO("fb mappable at 0x%lX\n", info->fix.smem_start);
DRM_INFO("vram apper at 0x%lX\n", (unsigned long)rdev->mc.aper_base);
- DRM_INFO("size %lu\n", (unsigned long)size);
+ DRM_INFO("size %lu\n", (unsigned long)radeon_bo_size(rbo));
DRM_INFO("fb depth is %d\n", fb->depth);
DRM_INFO(" pitch is %d\n", fb->pitch);
-
- mutex_unlock(&rdev->ddev->struct_mutex);
vga_switcheroo_client_fb_set(rdev->ddev->pdev, info);
return 0;
out_unref:
if (rbo) {
- ret = radeon_bo_reserve(rbo, false);
- if (likely(ret == 0)) {
- radeon_bo_kunmap(rbo);
- radeon_bo_unreserve(rbo);
- }
+
}
if (fb && ret) {
drm_gem_object_unreference(gobj);
drm_framebuffer_cleanup(fb);
kfree(fb);
}
- drm_gem_object_unreference(gobj);
- mutex_unlock(&rdev->ddev->struct_mutex);
+
out:
return ret;
}
-static int radeon_fb_find_or_create_single(struct drm_device *dev,
- struct drm_fb_helper_surface_size *sizes,
- struct drm_fb_helper **fb_ptr)
+static int radeon_fb_find_or_create_single(struct drm_fb_helper *helper,
+ struct drm_fb_helper_surface_size *sizes)
{
- struct radeon_device *rdev = dev->dev_private;
- struct radeon_kernel_fbdev *rfbdev = NULL;
+ struct radeon_fbdev *rfbdev = (struct radeon_fbdev *)helper;
int new_fb = 0;
int ret;
- if (!rdev->mode_info.rfbdev) {
- ret = radeonfb_create(dev, sizes,
- &rfbdev);
+ if (!helper->fb) {
+ ret = radeonfb_create(rfbdev, sizes);
if (ret)
return ret;
- rdev->mode_info.rfbdev = rfbdev;
new_fb = 1;
- } else {
- rfbdev = rdev->mode_info.rfbdev;
- if (rfbdev->rfb.base.width < sizes->surface_width ||
- rfbdev->rfb.base.height < sizes->surface_height) {
- DRM_ERROR("Framebuffer not large enough to scale console onto.\n");
- return -EINVAL;
- }
}
-
- *fb_ptr = &rfbdev->helper;
return new_fb;
}
@@ -312,48 +311,55 @@ int radeon_parse_options(char *options)
return 0;
}
-static int radeonfb_probe(struct drm_device *dev)
+static int radeonfb_probe(struct radeon_fbdev *rfbdev)
{
- struct radeon_device *rdev = dev->dev_private;
+ struct radeon_device *rdev = rfbdev->rdev;
int bpp_sel = 32;
/* select 8 bpp console on RN50 or 16MB cards */
if (ASIC_IS_RN50(rdev) || rdev->mc.real_vram_size <= (32*1024*1024))
bpp_sel = 8;
- return drm_fb_helper_single_fb_probe(dev, bpp_sel, &radeon_fb_find_or_create_single);
+ return drm_fb_helper_single_fb_probe(&rfbdev->helper, bpp_sel);
}
void radeonfb_hotplug(struct drm_device *dev)
{
- drm_helper_fb_hotplug_event(dev);
+ struct radeon_device *rdev = dev->dev_private;
+ int max_width, max_height;
+
+ max_width = rdev->mode_info.rfbdev->rfb.base.width;
+ max_height = rdev->mode_info.rfbdev->rfb.base.height;
+ drm_helper_fb_hotplug_event(&rdev->mode_info.rfbdev->helper, max_width, max_height);
- radeonfb_probe(dev);
+ radeonfb_probe(rdev->mode_info.rfbdev);
}
-static int radeon_fbdev_destroy(struct drm_device *dev, struct radeon_kernel_fbdev *rfbdev)
+static int radeon_fbdev_destroy(struct drm_device *dev, struct radeon_fbdev *rfbdev)
{
struct fb_info *info;
struct radeon_framebuffer *rfb = &rfbdev->rfb;
struct radeon_bo *rbo;
int r;
- rbo = rfb->obj->driver_private;
- info = rfbdev->helper.fbdev;
- unregister_framebuffer(info);
- r = radeon_bo_reserve(rbo, false);
- if (likely(r == 0)) {
- radeon_bo_kunmap(rbo);
- radeon_bo_unpin(rbo);
- radeon_bo_unreserve(rbo);
+ if (rfbdev->helper.fbdev) {
+ info = rfbdev->helper.fbdev;
+ unregister_framebuffer(info);
+ framebuffer_release(info);
}
+ if (rfb->obj) {
+ rbo = rfb->obj->driver_private;
+ r = radeon_bo_reserve(rbo, false);
+ if (likely(r == 0)) {
+ radeon_bo_kunmap(rbo);
+ radeon_bo_unpin(rbo);
+ radeon_bo_unreserve(rbo);
+ }
+ drm_gem_object_unreference_unlocked(rfb->obj);
+ }
drm_fb_helper_free(&rfbdev->helper);
drm_framebuffer_cleanup(&rfb->base);
- if (rfb->obj)
- drm_gem_object_unreference_unlocked(rfb->obj);
-
- framebuffer_release(info);
return 0;
}
@@ -361,14 +367,32 @@ MODULE_LICENSE("GPL");
int radeon_fbdev_init(struct radeon_device *rdev)
{
- drm_helper_initial_config(rdev->ddev);
- radeonfb_probe(rdev->ddev);
+ struct radeon_fbdev *rfbdev;
+
+ rfbdev = kzalloc(sizeof(struct radeon_fbdev), GFP_KERNEL);
+ if (!rfbdev)
+ return -ENOMEM;
+
+ rfbdev->rdev = rdev;
+ rdev->mode_info.rfbdev = rfbdev;
+
+ drm_fb_helper_init_crtc_count(rdev->ddev, &rfbdev->helper,
+ rdev->num_crtc,
+ RADEONFB_CONN_LIMIT);
+ rfbdev->helper.fb_probe = radeon_fb_find_or_create_single;
+ drm_fb_helper_initial_config(&rfbdev->helper);
+ radeonfb_probe(rfbdev);
return 0;
+
}
void radeon_fbdev_fini(struct radeon_device *rdev)
{
+ if (!rdev->mode_info.rfbdev)
+ return;
+
radeon_fbdev_destroy(rdev->ddev, rdev->mode_info.rfbdev);
+ kfree(rdev->mode_info.rfbdev);
rdev->mode_info.rfbdev = NULL;
}