aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2009-06-16 18:34:38 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-06-16 22:48:00 -0400
commit4410f3910947dcea8672280b3adecd53cec4e85e (patch)
tree814e1823cf773d8911b946df780faaec5c89d593
parentb586640141ab5f4ab3b194419bc2c0f039e91dbc (diff)
fbdev: add support for handoff from firmware to hw framebuffers
With KMS we have ran into an issue where we really want the KMS fb driver to be the one running the console, so panics etc can be shown by switching out of X etc. However with vesafb/efifb built-in, we end up with those on fb0 and the KMS fb driver on fb1, driving the same piece of hw, so this adds an fb info flag to denote a firmware fbdev, and adds a new aperture base/size range which can be compared when the hw drivers are installed to see if there is a conflict with a firmware driver, and if there is the firmware driver is unregistered and the hw driver takes over. It uses new aperture_base/size members instead of comparing on the fix smem_start/length, as smem_start/length might for example only cover the first 1MB of the PCI aperture, and we could allocate the kms fb from 8MB into the aperture, thus they would never overlap. [akpm@linux-foundation.org: coding-style fixes] Signed-off-by: Dave Airlie <airlied@redhat.com> Acked-by: Peter Jones <pjones@redhat.com> Cc: Geert Uytterhoeven <geert@linux-m68k.org> Cc: Krzysztof Helt <krzysztof.h1@poczta.fm> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--drivers/gpu/drm/i915/intel_fb.c8
-rw-r--r--drivers/video/efifb.c5
-rw-r--r--drivers/video/fbmem.c31
-rw-r--r--drivers/video/vesafb.c15
-rw-r--r--include/linux/fb.h12
5 files changed, 68 insertions, 3 deletions
diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c
index 0ecf6b76a401..8e28e5993df5 100644
--- a/drivers/gpu/drm/i915/intel_fb.c
+++ b/drivers/gpu/drm/i915/intel_fb.c
@@ -504,6 +504,14 @@ static int intelfb_create(struct drm_device *dev, uint32_t fb_width,
504 info->fbops = &intelfb_ops; 504 info->fbops = &intelfb_ops;
505 505
506 info->fix.line_length = fb->pitch; 506 info->fix.line_length = fb->pitch;
507
508 /* setup aperture base/size for vesafb takeover */
509 info->aperture_base = dev->mode_config.fb_base;
510 if (IS_I9XX(dev))
511 info->aperture_size = pci_resource_len(dev->pdev, 2);
512 else
513 info->aperture_size = pci_resource_len(dev->pdev, 0);
514
507 info->fix.smem_start = dev->mode_config.fb_base + obj_priv->gtt_offset; 515 info->fix.smem_start = dev->mode_config.fb_base + obj_priv->gtt_offset;
508 info->fix.smem_len = size; 516 info->fix.smem_len = size;
509 517
diff --git a/drivers/video/efifb.c b/drivers/video/efifb.c
index 8dea2bc92705..eb12182b2059 100644
--- a/drivers/video/efifb.c
+++ b/drivers/video/efifb.c
@@ -280,6 +280,9 @@ static int __init efifb_probe(struct platform_device *dev)
280 info->pseudo_palette = info->par; 280 info->pseudo_palette = info->par;
281 info->par = NULL; 281 info->par = NULL;
282 282
283 info->aperture_base = efifb_fix.smem_start;
284 info->aperture_size = size_total;
285
283 info->screen_base = ioremap(efifb_fix.smem_start, efifb_fix.smem_len); 286 info->screen_base = ioremap(efifb_fix.smem_start, efifb_fix.smem_len);
284 if (!info->screen_base) { 287 if (!info->screen_base) {
285 printk(KERN_ERR "efifb: abort, cannot ioremap video memory " 288 printk(KERN_ERR "efifb: abort, cannot ioremap video memory "
@@ -337,7 +340,7 @@ static int __init efifb_probe(struct platform_device *dev)
337 info->fbops = &efifb_ops; 340 info->fbops = &efifb_ops;
338 info->var = efifb_defined; 341 info->var = efifb_defined;
339 info->fix = efifb_fix; 342 info->fix = efifb_fix;
340 info->flags = FBINFO_FLAG_DEFAULT; 343 info->flags = FBINFO_FLAG_DEFAULT | FBINFO_MISC_FIRMWARE;
341 344
342 if ((err = fb_alloc_cmap(&info->cmap, 256, 0)) < 0) { 345 if ((err = fb_alloc_cmap(&info->cmap, 256, 0)) < 0) {
343 printk(KERN_ERR "efifb: cannot allocate colormap\n"); 346 printk(KERN_ERR "efifb: cannot allocate colormap\n");
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
index d412a1ddc12f..f8a09bf8d0cd 100644
--- a/drivers/video/fbmem.c
+++ b/drivers/video/fbmem.c
@@ -1462,6 +1462,16 @@ static int fb_check_foreignness(struct fb_info *fi)
1462 return 0; 1462 return 0;
1463} 1463}
1464 1464
1465static bool fb_do_apertures_overlap(struct fb_info *gen, struct fb_info *hw)
1466{
1467 /* is the generic aperture base the same as the HW one */
1468 if (gen->aperture_base == hw->aperture_base)
1469 return true;
1470 /* is the generic aperture base inside the hw base->hw base+size */
1471 if (gen->aperture_base > hw->aperture_base && gen->aperture_base <= hw->aperture_base + hw->aperture_size)
1472 return true;
1473 return false;
1474}
1465/** 1475/**
1466 * register_framebuffer - registers a frame buffer device 1476 * register_framebuffer - registers a frame buffer device
1467 * @fb_info: frame buffer info structure 1477 * @fb_info: frame buffer info structure
@@ -1485,6 +1495,23 @@ register_framebuffer(struct fb_info *fb_info)
1485 if (fb_check_foreignness(fb_info)) 1495 if (fb_check_foreignness(fb_info))
1486 return -ENOSYS; 1496 return -ENOSYS;
1487 1497
1498 /* check all firmware fbs and kick off if the base addr overlaps */
1499 for (i = 0 ; i < FB_MAX; i++) {
1500 if (!registered_fb[i])
1501 continue;
1502
1503 if (registered_fb[i]->flags & FBINFO_MISC_FIRMWARE) {
1504 if (fb_do_apertures_overlap(registered_fb[i], fb_info)) {
1505 printk(KERN_ERR "fb: conflicting fb hw usage "
1506 "%s vs %s - removing generic driver\n",
1507 fb_info->fix.id,
1508 registered_fb[i]->fix.id);
1509 unregister_framebuffer(registered_fb[i]);
1510 break;
1511 }
1512 }
1513 }
1514
1488 num_registered_fb++; 1515 num_registered_fb++;
1489 for (i = 0 ; i < FB_MAX; i++) 1516 for (i = 0 ; i < FB_MAX; i++)
1490 if (!registered_fb[i]) 1517 if (!registered_fb[i])
@@ -1586,6 +1613,10 @@ unregister_framebuffer(struct fb_info *fb_info)
1586 device_destroy(fb_class, MKDEV(FB_MAJOR, i)); 1613 device_destroy(fb_class, MKDEV(FB_MAJOR, i));
1587 event.info = fb_info; 1614 event.info = fb_info;
1588 fb_notifier_call_chain(FB_EVENT_FB_UNREGISTERED, &event); 1615 fb_notifier_call_chain(FB_EVENT_FB_UNREGISTERED, &event);
1616
1617 /* this may free fb info */
1618 if (fb_info->fbops->fb_destroy)
1619 fb_info->fbops->fb_destroy(fb_info);
1589done: 1620done:
1590 return ret; 1621 return ret;
1591} 1622}
diff --git a/drivers/video/vesafb.c b/drivers/video/vesafb.c
index d6856f43d241..bd37ee1f6a25 100644
--- a/drivers/video/vesafb.c
+++ b/drivers/video/vesafb.c
@@ -174,8 +174,17 @@ static int vesafb_setcolreg(unsigned regno, unsigned red, unsigned green,
174 return err; 174 return err;
175} 175}
176 176
177static void vesafb_destroy(struct fb_info *info)
178{
179 if (info->screen_base)
180 iounmap(info->screen_base);
181 release_mem_region(info->aperture_base, info->aperture_size);
182 framebuffer_release(info);
183}
184
177static struct fb_ops vesafb_ops = { 185static struct fb_ops vesafb_ops = {
178 .owner = THIS_MODULE, 186 .owner = THIS_MODULE,
187 .fb_destroy = vesafb_destroy,
179 .fb_setcolreg = vesafb_setcolreg, 188 .fb_setcolreg = vesafb_setcolreg,
180 .fb_pan_display = vesafb_pan_display, 189 .fb_pan_display = vesafb_pan_display,
181 .fb_fillrect = cfb_fillrect, 190 .fb_fillrect = cfb_fillrect,
@@ -286,6 +295,10 @@ static int __init vesafb_probe(struct platform_device *dev)
286 info->pseudo_palette = info->par; 295 info->pseudo_palette = info->par;
287 info->par = NULL; 296 info->par = NULL;
288 297
298 /* set vesafb aperture size for generic probing */
299 info->aperture_base = screen_info.lfb_base;
300 info->aperture_size = size_total;
301
289 info->screen_base = ioremap(vesafb_fix.smem_start, vesafb_fix.smem_len); 302 info->screen_base = ioremap(vesafb_fix.smem_start, vesafb_fix.smem_len);
290 if (!info->screen_base) { 303 if (!info->screen_base) {
291 printk(KERN_ERR 304 printk(KERN_ERR
@@ -437,7 +450,7 @@ static int __init vesafb_probe(struct platform_device *dev)
437 info->fbops = &vesafb_ops; 450 info->fbops = &vesafb_ops;
438 info->var = vesafb_defined; 451 info->var = vesafb_defined;
439 info->fix = vesafb_fix; 452 info->fix = vesafb_fix;
440 info->flags = FBINFO_FLAG_DEFAULT | 453 info->flags = FBINFO_FLAG_DEFAULT | FBINFO_MISC_FIRMWARE |
441 (ypan ? FBINFO_HWACCEL_YPAN : 0); 454 (ypan ? FBINFO_HWACCEL_YPAN : 0);
442 455
443 if (!ypan) 456 if (!ypan)
diff --git a/include/linux/fb.h b/include/linux/fb.h
index 330c4b1bfcaa..3c5562a52167 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -677,6 +677,9 @@ struct fb_ops {
677 /* get capability given var */ 677 /* get capability given var */
678 void (*fb_get_caps)(struct fb_info *info, struct fb_blit_caps *caps, 678 void (*fb_get_caps)(struct fb_info *info, struct fb_blit_caps *caps,
679 struct fb_var_screeninfo *var); 679 struct fb_var_screeninfo *var);
680
681 /* teardown any resources to do with this framebuffer */
682 void (*fb_destroy)(struct fb_info *info);
680}; 683};
681 684
682#ifdef CONFIG_FB_TILEBLITTING 685#ifdef CONFIG_FB_TILEBLITTING
@@ -786,6 +789,8 @@ struct fb_tile_ops {
786#define FBINFO_MISC_USEREVENT 0x10000 /* event request 789#define FBINFO_MISC_USEREVENT 0x10000 /* event request
787 from userspace */ 790 from userspace */
788#define FBINFO_MISC_TILEBLITTING 0x20000 /* use tile blitting */ 791#define FBINFO_MISC_TILEBLITTING 0x20000 /* use tile blitting */
792#define FBINFO_MISC_FIRMWARE 0x40000 /* a replaceable firmware
793 inited framebuffer */
789 794
790/* A driver may set this flag to indicate that it does want a set_par to be 795/* A driver may set this flag to indicate that it does want a set_par to be
791 * called every time when fbcon_switch is executed. The advantage is that with 796 * called every time when fbcon_switch is executed. The advantage is that with
@@ -854,7 +859,12 @@ struct fb_info {
854 u32 state; /* Hardware state i.e suspend */ 859 u32 state; /* Hardware state i.e suspend */
855 void *fbcon_par; /* fbcon use-only private area */ 860 void *fbcon_par; /* fbcon use-only private area */
856 /* From here on everything is device dependent */ 861 /* From here on everything is device dependent */
857 void *par; 862 void *par;
863 /* we need the PCI or similiar aperture base/size not
864 smem_start/size as smem_start may just be an object
865 allocated inside the aperture so may not actually overlap */
866 resource_size_t aperture_base;
867 resource_size_t aperture_size;
858}; 868};
859 869
860#ifdef MODULE 870#ifdef MODULE