diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-06-16 19:50:13 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-06-16 19:50:13 -0700 |
commit | 517d08699b250021303f9a7cf0d758b6dc0748ed (patch) | |
tree | 5e5b0134c3fffb78fe9d8b1641a64ff28fdd7bbc /drivers/video | |
parent | 8eeee4e2f04fc551f50c9d9847da2d73d7d33728 (diff) | |
parent | a34601c5d84134055782ee031d58d82f5440e918 (diff) |
Merge branch 'akpm'
* akpm: (182 commits)
fbdev: bf54x-lq043fb: use kzalloc over kmalloc/memset
fbdev: *bfin*: fix __dev{init,exit} markings
fbdev: *bfin*: drop unnecessary calls to memset
fbdev: bfin-t350mcqb-fb: drop unused local variables
fbdev: blackfin has __raw I/O accessors, so use them in fb.h
fbdev: s1d13xxxfb: add accelerated bitblt functions
tcx: use standard fields for framebuffer physical address and length
fbdev: add support for handoff from firmware to hw framebuffers
intelfb: fix a bug when changing video timing
fbdev: use framebuffer_release() for freeing fb_info structures
radeon: P2G2CLK_ALWAYS_ONb tested twice, should 2nd be P2G2CLK_DAC_ALWAYS_ONb?
s3c-fb: CPUFREQ frequency scaling support
s3c-fb: fix resource releasing on error during probing
carminefb: fix possible access beyond end of carmine_modedb[]
acornfb: remove fb_mmap function
mb862xxfb: use CONFIG_OF instead of CONFIG_PPC_OF
mb862xxfb: restrict compliation of platform driver to PPC
Samsung SoC Framebuffer driver: add Alpha Channel support
atmel-lcdc: fix pixclock upper bound detection
offb: use framebuffer_alloc() to allocate fb_info struct
...
Manually fix up conflicts due to kmemcheck in mm/slab.c
Diffstat (limited to 'drivers/video')
-rw-r--r-- | drivers/video/Kconfig | 1 | ||||
-rw-r--r-- | drivers/video/acornfb.c | 38 | ||||
-rw-r--r-- | drivers/video/atmel_lcdfb.c | 2 | ||||
-rw-r--r-- | drivers/video/aty/radeon_pm.c | 3 | ||||
-rw-r--r-- | drivers/video/bf54x-lq043fb.c | 15 | ||||
-rw-r--r-- | drivers/video/bfin-t350mcqb-fb.c | 15 | ||||
-rw-r--r-- | drivers/video/carminefb.c | 2 | ||||
-rw-r--r-- | drivers/video/chipsfb.c | 1 | ||||
-rw-r--r-- | drivers/video/efifb.c | 5 | ||||
-rw-r--r-- | drivers/video/fbmem.c | 31 | ||||
-rw-r--r-- | drivers/video/igafb.c | 8 | ||||
-rw-r--r-- | drivers/video/intelfb/intelfbdrv.c | 5 | ||||
-rw-r--r-- | drivers/video/logo/Makefile | 12 | ||||
-rw-r--r-- | drivers/video/logo/logo.c | 15 | ||||
-rw-r--r-- | drivers/video/mb862xx/mb862xxfb.c | 2 | ||||
-rw-r--r-- | drivers/video/modedb.c | 8 | ||||
-rw-r--r-- | drivers/video/offb.c | 8 | ||||
-rw-r--r-- | drivers/video/pm2fb.c | 2 | ||||
-rw-r--r-- | drivers/video/s1d13xxxfb.c | 341 | ||||
-rw-r--r-- | drivers/video/s3c-fb.c | 53 | ||||
-rw-r--r-- | drivers/video/s3c2410fb.c | 67 | ||||
-rw-r--r-- | drivers/video/s3c2410fb.h | 5 | ||||
-rw-r--r-- | drivers/video/sis/sis_main.c | 4 | ||||
-rw-r--r-- | drivers/video/stifb.c | 2 | ||||
-rw-r--r-- | drivers/video/tcx.c | 27 | ||||
-rw-r--r-- | drivers/video/vesafb.c | 15 |
26 files changed, 519 insertions, 168 deletions
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 2b5a691064b..932ffdbf86d 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -2104,6 +2104,7 @@ config FB_MB862XX_LIME bool "Lime GDC" depends on FB_MB862XX depends on OF && !FB_MB862XX_PCI_GDC + depends on PPC select FB_FOREIGN_ENDIAN select FB_LITTLE_ENDIAN ---help--- diff --git a/drivers/video/acornfb.c b/drivers/video/acornfb.c index 6995fe1e86d..0bcc59eb37f 100644 --- a/drivers/video/acornfb.c +++ b/drivers/video/acornfb.c @@ -859,43 +859,6 @@ acornfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) return 0; } -/* - * Note that we are entered with the kernel locked. - */ -static int -acornfb_mmap(struct fb_info *info, struct vm_area_struct *vma) -{ - unsigned long off, start; - u32 len; - - off = vma->vm_pgoff << PAGE_SHIFT; - - start = info->fix.smem_start; - len = PAGE_ALIGN(start & ~PAGE_MASK) + info->fix.smem_len; - start &= PAGE_MASK; - if ((vma->vm_end - vma->vm_start + off) > len) - return -EINVAL; - off += start; - vma->vm_pgoff = off >> PAGE_SHIFT; - - /* This is an IO map - tell maydump to skip this VMA */ - vma->vm_flags |= VM_IO; - - vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); - - /* - * Don't alter the page protection flags; we want to keep the area - * cached for better performance. This does mean that we may miss - * some updates to the screen occasionally, but process switches - * should cause the caches and buffers to be flushed often enough. - */ - if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT, - vma->vm_end - vma->vm_start, - vma->vm_page_prot)) - return -EAGAIN; - return 0; -} - static struct fb_ops acornfb_ops = { .owner = THIS_MODULE, .fb_check_var = acornfb_check_var, @@ -905,7 +868,6 @@ static struct fb_ops acornfb_ops = { .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, - .fb_mmap = acornfb_mmap, }; /* diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c index 2fb63f6ea2f..5afd64482f5 100644 --- a/drivers/video/atmel_lcdfb.c +++ b/drivers/video/atmel_lcdfb.c @@ -345,7 +345,7 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var, dev_dbg(dev, " bpp: %u\n", var->bits_per_pixel); dev_dbg(dev, " clk: %lu KHz\n", clk_value_khz); - if ((PICOS2KHZ(var->pixclock) * var->bits_per_pixel / 8) > clk_value_khz) { + if (PICOS2KHZ(var->pixclock) > clk_value_khz) { dev_err(dev, "%lu KHz pixel clock is too fast\n", PICOS2KHZ(var->pixclock)); return -EINVAL; } diff --git a/drivers/video/aty/radeon_pm.c b/drivers/video/aty/radeon_pm.c index 97a1f095f32..515cf1978d1 100644 --- a/drivers/video/aty/radeon_pm.c +++ b/drivers/video/aty/radeon_pm.c @@ -213,7 +213,6 @@ static void radeon_pm_disable_dynamic_mode(struct radeonfb_info *rinfo) PIXCLKS_CNTL__R300_PIXCLK_TRANS_ALWAYS_ONb | PIXCLKS_CNTL__R300_PIXCLK_TVO_ALWAYS_ONb | PIXCLKS_CNTL__R300_P2G2CLK_ALWAYS_ONb | - PIXCLKS_CNTL__R300_P2G2CLK_ALWAYS_ONb | PIXCLKS_CNTL__R300_DISP_DAC_PIXCLK_DAC2_BLANK_OFF); OUTPLL(pllPIXCLKS_CNTL, tmp); @@ -395,7 +394,7 @@ static void radeon_pm_enable_dynamic_mode(struct radeonfb_info *rinfo) PIXCLKS_CNTL__R300_PIXCLK_TRANS_ALWAYS_ONb | PIXCLKS_CNTL__R300_PIXCLK_TVO_ALWAYS_ONb | PIXCLKS_CNTL__R300_P2G2CLK_ALWAYS_ONb | - PIXCLKS_CNTL__R300_P2G2CLK_ALWAYS_ONb); + PIXCLKS_CNTL__R300_P2G2CLK_DAC_ALWAYS_ONb); OUTPLL(pllPIXCLKS_CNTL, tmp); tmp = INPLL(pllMCLK_MISC); diff --git a/drivers/video/bf54x-lq043fb.c b/drivers/video/bf54x-lq043fb.c index 37e60b1d2ed..e49ae5edcc0 100644 --- a/drivers/video/bf54x-lq043fb.c +++ b/drivers/video/bf54x-lq043fb.c @@ -323,7 +323,6 @@ static int bfin_bf54x_fb_release(struct fb_info *info, int user) bfin_write_EPPI0_CONTROL(0); SSYNC(); disable_dma(CH_EPPI0); - memset(fbi->fb_buffer, 0, info->fix.smem_len); } spin_unlock(&fbi->lock); @@ -530,7 +529,7 @@ static irqreturn_t bfin_bf54x_irq_error(int irq, void *dev_id) return IRQ_HANDLED; } -static int __init bfin_bf54x_probe(struct platform_device *pdev) +static int __devinit bfin_bf54x_probe(struct platform_device *pdev) { struct bfin_bf54xfb_info *info; struct fb_info *fbinfo; @@ -626,14 +625,12 @@ static int __init bfin_bf54x_probe(struct platform_device *pdev) goto out3; } - memset(info->fb_buffer, 0, fbinfo->fix.smem_len); - fbinfo->screen_base = (void *)info->fb_buffer; fbinfo->fix.smem_start = (int)info->fb_buffer; fbinfo->fbops = &bfin_bf54x_fb_ops; - fbinfo->pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL); + fbinfo->pseudo_palette = kzalloc(sizeof(u32) * 16, GFP_KERNEL); if (!fbinfo->pseudo_palette) { printk(KERN_ERR DRIVER_NAME "Fail to allocate pseudo_palette\n"); @@ -642,8 +639,6 @@ static int __init bfin_bf54x_probe(struct platform_device *pdev) goto out4; } - memset(fbinfo->pseudo_palette, 0, sizeof(u32) * 16); - if (fb_alloc_cmap(&fbinfo->cmap, BFIN_LCD_NBR_PALETTE_ENTRIES, 0) < 0) { printk(KERN_ERR DRIVER_NAME @@ -712,7 +707,7 @@ out1: return ret; } -static int bfin_bf54x_remove(struct platform_device *pdev) +static int __devexit bfin_bf54x_remove(struct platform_device *pdev) { struct fb_info *fbinfo = platform_get_drvdata(pdev); @@ -781,7 +776,7 @@ static int bfin_bf54x_resume(struct platform_device *pdev) static struct platform_driver bfin_bf54x_driver = { .probe = bfin_bf54x_probe, - .remove = bfin_bf54x_remove, + .remove = __devexit_p(bfin_bf54x_remove), .suspend = bfin_bf54x_suspend, .resume = bfin_bf54x_resume, .driver = { @@ -790,7 +785,7 @@ static struct platform_driver bfin_bf54x_driver = { }, }; -static int __devinit bfin_bf54x_driver_init(void) +static int __init bfin_bf54x_driver_init(void) { return platform_driver_register(&bfin_bf54x_driver); } diff --git a/drivers/video/bfin-t350mcqb-fb.c b/drivers/video/bfin-t350mcqb-fb.c index 90cfddabf1f..5cc36cfbf07 100644 --- a/drivers/video/bfin-t350mcqb-fb.c +++ b/drivers/video/bfin-t350mcqb-fb.c @@ -242,7 +242,6 @@ static int bfin_t350mcqb_fb_release(struct fb_info *info, int user) SSYNC(); disable_dma(CH_PPI); bfin_t350mcqb_stop_timers(); - memset(fbi->fb_buffer, 0, info->fix.smem_len); } spin_unlock(&fbi->lock); @@ -527,8 +526,6 @@ static int __devinit bfin_t350mcqb_probe(struct platform_device *pdev) goto out3; } - memset(info->fb_buffer, 0, fbinfo->fix.smem_len); - fbinfo->screen_base = (void *)info->fb_buffer + ACTIVE_VIDEO_MEM_OFFSET; fbinfo->fix.smem_start = (int)info->fb_buffer + ACTIVE_VIDEO_MEM_OFFSET; @@ -602,7 +599,7 @@ out1: return ret; } -static int bfin_t350mcqb_remove(struct platform_device *pdev) +static int __devexit bfin_t350mcqb_remove(struct platform_device *pdev) { struct fb_info *fbinfo = platform_get_drvdata(pdev); @@ -637,9 +634,6 @@ static int bfin_t350mcqb_remove(struct platform_device *pdev) #ifdef CONFIG_PM static int bfin_t350mcqb_suspend(struct platform_device *pdev, pm_message_t state) { - struct fb_info *fbinfo = platform_get_drvdata(pdev); - struct bfin_t350mcqbfb_info *info = fbinfo->par; - bfin_t350mcqb_disable_ppi(); disable_dma(CH_PPI); bfin_write_PPI_STATUS(0xFFFF); @@ -649,9 +643,6 @@ static int bfin_t350mcqb_suspend(struct platform_device *pdev, pm_message_t stat static int bfin_t350mcqb_resume(struct platform_device *pdev) { - struct fb_info *fbinfo = platform_get_drvdata(pdev); - struct bfin_t350mcqbfb_info *info = fbinfo->par; - enable_dma(CH_PPI); bfin_t350mcqb_enable_ppi(); @@ -664,7 +655,7 @@ static int bfin_t350mcqb_resume(struct platform_device *pdev) static struct platform_driver bfin_t350mcqb_driver = { .probe = bfin_t350mcqb_probe, - .remove = bfin_t350mcqb_remove, + .remove = __devexit_p(bfin_t350mcqb_remove), .suspend = bfin_t350mcqb_suspend, .resume = bfin_t350mcqb_resume, .driver = { @@ -673,7 +664,7 @@ static struct platform_driver bfin_t350mcqb_driver = { }, }; -static int __devinit bfin_t350mcqb_driver_init(void) +static int __init bfin_t350mcqb_driver_init(void) { return platform_driver_register(&bfin_t350mcqb_driver); } diff --git a/drivers/video/carminefb.c b/drivers/video/carminefb.c index c7ff3c1a266..0c02f8ec4bf 100644 --- a/drivers/video/carminefb.c +++ b/drivers/video/carminefb.c @@ -562,7 +562,7 @@ static int __devinit alloc_carmine_fb(void __iomem *regs, void __iomem *smem_bas if (ret < 0) goto err_free_fb; - if (fb_mode > ARRAY_SIZE(carmine_modedb)) + if (fb_mode >= ARRAY_SIZE(carmine_modedb)) fb_mode = CARMINEFB_DEFAULT_VIDEO_MODE; par->cur_mode = par->new_mode = ~0; diff --git a/drivers/video/chipsfb.c b/drivers/video/chipsfb.c index 777389c4098..57b9d276497 100644 --- a/drivers/video/chipsfb.c +++ b/drivers/video/chipsfb.c @@ -414,7 +414,6 @@ chipsfb_pci_init(struct pci_dev *dp, const struct pci_device_id *ent) } pci_set_drvdata(dp, p); - p->device = &dp->dev; init_chips(p, addr); diff --git a/drivers/video/efifb.c b/drivers/video/efifb.c index 8dea2bc9270..eb12182b205 100644 --- a/drivers/video/efifb.c +++ b/drivers/video/efifb.c @@ -280,6 +280,9 @@ static int __init efifb_probe(struct platform_device *dev) info->pseudo_palette = info->par; info->par = NULL; + info->aperture_base = efifb_fix.smem_start; + info->aperture_size = size_total; + info->screen_base = ioremap(efifb_fix.smem_start, efifb_fix.smem_len); if (!info->screen_base) { printk(KERN_ERR "efifb: abort, cannot ioremap video memory " @@ -337,7 +340,7 @@ static int __init efifb_probe(struct platform_device *dev) info->fbops = &efifb_ops; info->var = efifb_defined; info->fix = efifb_fix; - info->flags = FBINFO_FLAG_DEFAULT; + info->flags = FBINFO_FLAG_DEFAULT | FBINFO_MISC_FIRMWARE; if ((err = fb_alloc_cmap(&info->cmap, 256, 0)) < 0) { printk(KERN_ERR "efifb: cannot allocate colormap\n"); diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index d412a1ddc12..f8a09bf8d0c 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -1462,6 +1462,16 @@ static int fb_check_foreignness(struct fb_info *fi) return 0; } +static bool fb_do_apertures_overlap(struct fb_info *gen, struct fb_info *hw) +{ + /* is the generic aperture base the same as the HW one */ + if (gen->aperture_base == hw->aperture_base) + return true; + /* is the generic aperture base inside the hw base->hw base+size */ + if (gen->aperture_base > hw->aperture_base && gen->aperture_base <= hw->aperture_base + hw->aperture_size) + return true; + return false; +} /** * register_framebuffer - registers a frame buffer device * @fb_info: frame buffer info structure @@ -1485,6 +1495,23 @@ register_framebuffer(struct fb_info *fb_info) if (fb_check_foreignness(fb_info)) return -ENOSYS; + /* check all firmware fbs and kick off if the base addr overlaps */ + for (i = 0 ; i < FB_MAX; i++) { + if (!registered_fb[i]) + continue; + + if (registered_fb[i]->flags & FBINFO_MISC_FIRMWARE) { + if (fb_do_apertures_overlap(registered_fb[i], fb_info)) { + printk(KERN_ERR "fb: conflicting fb hw usage " + "%s vs %s - removing generic driver\n", + fb_info->fix.id, + registered_fb[i]->fix.id); + unregister_framebuffer(registered_fb[i]); + break; + } + } + } + num_registered_fb++; for (i = 0 ; i < FB_MAX; i++) if (!registered_fb[i]) @@ -1586,6 +1613,10 @@ unregister_framebuffer(struct fb_info *fb_info) device_destroy(fb_class, MKDEV(FB_MAJOR, i)); event.info = fb_info; fb_notifier_call_chain(FB_EVENT_FB_UNREGISTERED, &event); + + /* this may free fb info */ + if (fb_info->fbops->fb_destroy) + fb_info->fbops->fb_destroy(fb_info); done: return ret; } diff --git a/drivers/video/igafb.c b/drivers/video/igafb.c index 3a81060137a..15d20010944 100644 --- a/drivers/video/igafb.c +++ b/drivers/video/igafb.c @@ -395,17 +395,16 @@ int __init igafb_init(void) /* We leak a reference here but as it cannot be unloaded this is fine. If you write unload code remember to free it in unload */ - size = sizeof(struct fb_info) + sizeof(struct iga_par) + sizeof(u32)*16; + size = sizeof(struct iga_par) + sizeof(u32)*16; - info = kzalloc(size, GFP_ATOMIC); + info = framebuffer_alloc(size, &pdev->dev); if (!info) { printk("igafb_init: can't alloc fb_info\n"); pci_dev_put(pdev); return -ENOMEM; } - par = (struct iga_par *) (info + 1); - + par = info->par; if ((addr = pdev->resource[0].start) == 0) { printk("igafb_init: no memory start\n"); @@ -526,7 +525,6 @@ int __init igafb_init(void) info->var = default_var; info->fix = igafb_fix; info->pseudo_palette = (void *)(par + 1); - info->device = &pdev->dev; if (!iga_init(info, par)) { iounmap((void *)par->io_base); diff --git a/drivers/video/intelfb/intelfbdrv.c b/drivers/video/intelfb/intelfbdrv.c index ace14fe02fc..0cafd642fbc 100644 --- a/drivers/video/intelfb/intelfbdrv.c +++ b/drivers/video/intelfb/intelfbdrv.c @@ -1365,6 +1365,11 @@ static int intelfb_set_par(struct fb_info *info) DBG_MSG("intelfb_set_par (%dx%d-%d)\n", info->var.xres, info->var.yres, info->var.bits_per_pixel); + /* + * Disable VCO prior to timing register change. + */ + OUTREG(DPLL_A, INREG(DPLL_A) & ~DPLL_VCO_ENABLE); + intelfb_blank(FB_BLANK_POWERDOWN, info); if (ACCEL(dinfo, info)) diff --git a/drivers/video/logo/Makefile b/drivers/video/logo/Makefile index b91251d1fe4..3b437813584 100644 --- a/drivers/video/logo/Makefile +++ b/drivers/video/logo/Makefile @@ -37,22 +37,24 @@ extra-y += $(call logo-cfiles,_clut224,ppm) # Gray 256 extra-y += $(call logo-cfiles,_gray256,pgm) +pnmtologo := scripts/pnmtologo + # Create commands like "pnmtologo -t mono -n logo_mac_mono -o ..." quiet_cmd_logo = LOGO $@ - cmd_logo = scripts/pnmtologo \ + cmd_logo = $(pnmtologo) \ -t $(patsubst $*_%,%,$(notdir $(basename $<))) \ -n $(notdir $(basename $<)) -o $@ $< -$(obj)/%_mono.c: $(src)/%_mono.pbm FORCE +$(obj)/%_mono.c: $(src)/%_mono.pbm $(pnmtologo) FORCE $(call if_changed,logo) -$(obj)/%_vga16.c: $(src)/%_vga16.ppm FORCE +$(obj)/%_vga16.c: $(src)/%_vga16.ppm $(pnmtologo) FORCE $(call if_changed,logo) -$(obj)/%_clut224.c: $(src)/%_clut224.ppm FORCE +$(obj)/%_clut224.c: $(src)/%_clut224.ppm $(pnmtologo) FORCE $(call if_changed,logo) -$(obj)/%_gray256.c: $(src)/%_gray256.pgm FORCE +$(obj)/%_gray256.c: $(src)/%_gray256.pgm $(pnmtologo) FORCE $(call if_changed,logo) # Files generated that shall be removed upon make clean diff --git a/drivers/video/logo/logo.c b/drivers/video/logo/logo.c index 2e85a2b52d0..ea7a8ccc830 100644 --- a/drivers/video/logo/logo.c +++ b/drivers/video/logo/logo.c @@ -21,21 +21,6 @@ #include <asm/bootinfo.h> #endif -extern const struct linux_logo logo_linux_mono; -extern const struct linux_logo logo_linux_vga16; -extern const struct linux_logo logo_linux_clut224; -extern const struct linux_logo logo_blackfin_vga16; -extern const struct linux_logo logo_blackfin_clut224; -extern const struct linux_logo logo_dec_clut224; -extern const struct linux_logo logo_mac_clut224; -extern const struct linux_logo logo_parisc_clut224; -extern const struct linux_logo logo_sgi_clut224; -extern const struct linux_logo logo_sun_clut224; -extern const struct linux_logo logo_superh_mono; -extern const struct linux_logo logo_superh_vga16; -extern const struct linux_logo logo_superh_clut224; -extern const struct linux_logo logo_m32r_clut224; - static int nologo; module_param(nologo, bool, 0); MODULE_PARM_DESC(nologo, "Disables startup logo"); diff --git a/drivers/video/mb862xx/mb862xxfb.c b/drivers/video/mb862xx/mb862xxfb.c index fb64234a382..a28e3cfbbf7 100644 --- a/drivers/video/mb862xx/mb862xxfb.c +++ b/drivers/video/mb862xx/mb862xxfb.c @@ -19,7 +19,7 @@ #include <linux/init.h> #include <linux/interrupt.h> #include <linux/pci.h> -#if defined(CONFIG_PPC_OF) +#if defined(CONFIG_OF) #include <linux/of_platform.h> #endif #include "mb862xxfb.h" diff --git a/drivers/video/modedb.c b/drivers/video/modedb.c index 16186240c5f..34e4e799516 100644 --- a/drivers/video/modedb.c +++ b/drivers/video/modedb.c @@ -264,6 +264,14 @@ static const struct fb_videomode modedb[] = { /* 1280x800, 60 Hz, 47.403 kHz hsync, WXGA 16:10 aspect ratio */ NULL, 60, 1280, 800, 12048, 200, 64, 24, 1, 136, 3, 0, FB_VMODE_NONINTERLACED + }, { + /* 720x576i @ 50 Hz, 15.625 kHz hsync (PAL RGB) */ + NULL, 50, 720, 576, 74074, 64, 16, 39, 5, 64, 5, + 0, FB_VMODE_INTERLACED + }, { + /* 800x520i @ 50 Hz, 15.625 kHz hsync (PAL RGB) */ + NULL, 50, 800, 520, 58823, 144, 64, 72, 28, 80, 5, + 0, FB_VMODE_INTERLACED }, }; diff --git a/drivers/video/offb.c b/drivers/video/offb.c index e1d9eeb1aea..4d8c54c23dd 100644 --- a/drivers/video/offb.c +++ b/drivers/video/offb.c @@ -378,7 +378,6 @@ static void __init offb_init_fb(const char *name, const char *full_name, struct fb_fix_screeninfo *fix; struct fb_var_screeninfo *var; struct fb_info *info; - int size; if (!request_mem_region(res_start, res_size, "offb")) return; @@ -393,15 +392,12 @@ static void __init offb_init_fb(const char *name, const char *full_name, return; } - size = sizeof(struct fb_info) + sizeof(u32) * 16; - - info = kmalloc(size, GFP_ATOMIC); + info = framebuffer_alloc(sizeof(u32) * 16, NULL); if (info == 0) { release_mem_region(res_start, res_size); return; } - memset(info, 0, size); fix = &info->fix; var = &info->var; @@ -497,7 +493,7 @@ static void __init offb_init_fb(const char *name, const char *full_name, iounmap(par->cmap_adr); par->cmap_adr = NULL; iounmap(info->screen_base); - kfree(info); + framebuffer_release(info); release_mem_region(res_start, res_size); return; } diff --git a/drivers/video/pm2fb.c b/drivers/video/pm2fb.c index c6dd924976a..36436ee6c1a 100644 --- a/drivers/video/pm2fb.c +++ b/drivers/video/pm2fb.c @@ -1748,7 +1748,7 @@ static void __devexit pm2fb_remove(struct pci_dev *pdev) pci_set_drvdata(pdev, NULL); fb_dealloc_cmap(&info->cmap); kfree(info->pixmap.addr); - kfree(info); + framebuffer_release(info); } static struct pci_device_id pm2fb_id_table[] = { diff --git a/drivers/video/s1d13xxxfb.c b/drivers/video/s1d13xxxfb.c index 0726aecf3b7..0deb0a8867b 100644 --- a/drivers/video/s1d13xxxfb.c +++ b/drivers/video/s1d13xxxfb.c @@ -2,6 +2,7 @@ * * (c) 2004 Simtec Electronics * (c) 2005 Thibaut VARENE <varenet@parisc-linux.org> + * (c) 2009 Kristoffer Ericson <kristoffer.ericson@gmail.com> * * Driver for Epson S1D13xxx series framebuffer chips * @@ -10,18 +11,10 @@ * linux/drivers/video/epson1355fb.c * linux/drivers/video/epson/s1d13xxxfb.c (2.4 driver by Epson) * - * Note, currently only tested on S1D13806 with 16bit CRT. - * As such, this driver might still contain some hardcoded bits relating to - * S1D13806. - * Making it work on other S1D13XXX chips should merely be a matter of adding - * a few switch()s, some missing glue here and there maybe, and split header - * files. - * * TODO: - handle dual screen display (CRT and LCD at the same time). * - check_var(), mode change, etc. - * - PM untested. - * - Accelerated interfaces. - * - Probably not SMP safe :) + * - probably not SMP safe :) + * - support all bitblt operations on all cards * * This file is subject to the terms and conditions of the GNU General Public * License. See the file COPYING in the main directory of this archive for @@ -31,19 +24,24 @@ #include <linux/module.h> #include <linux/platform_device.h> #include <linux/delay.h> - #include <linux/types.h> #include <linux/errno.h> #include <linux/mm.h> #include <linux/mman.h> #include <linux/fb.h> +#include <linux/spinlock_types.h> +#include <linux/spinlock.h> #include <asm/io.h> #include <video/s1d13xxxfb.h> -#define PFX "s1d13xxxfb: " +#define PFX "s1d13xxxfb: " +#define BLIT "s1d13xxxfb_bitblt: " +/* + * set this to enable debugging on general functions + */ #if 0 #define dbg(fmt, args...) do { printk(KERN_INFO fmt, ## args); } while(0) #else @@ -51,7 +49,21 @@ #endif /* - * List of card production ids + * set this to enable debugging on 2D acceleration + */ +#if 0 +#define dbg_blit(fmt, args...) do { printk(KERN_INFO BLIT fmt, ## args); } while (0) +#else +#define dbg_blit(fmt, args...) do { } while (0) +#endif + +/* + * we make sure only one bitblt operation is running + */ +static DEFINE_SPINLOCK(s1d13xxxfb_bitblt_lock); + +/* + * list of card production ids */ static const int s1d13xxxfb_prod_ids[] = { S1D13505_PROD_ID, @@ -69,7 +81,7 @@ static const char *s1d13xxxfb_prod_names[] = { }; /* - * Here we define the default struct fb_fix_screeninfo + * here we define the default struct fb_fix_screeninfo */ static struct fb_fix_screeninfo __devinitdata s1d13xxxfb_fix = { .id = S1D_FBID, @@ -145,8 +157,10 @@ crt_enable(struct s1d13xxxfb_par *par, int enable) s1d13xxxfb_writereg(par, S1DREG_COM_DISP_MODE, mode); } -/* framebuffer control routines */ +/************************************************************* + framebuffer control functions + *************************************************************/ static inline void s1d13xxxfb_setup_pseudocolour(struct fb_info *info) { @@ -242,13 +256,13 @@ s1d13xxxfb_set_par(struct fb_info *info) } /** - * s1d13xxxfb_setcolreg - sets a color register. - * @regno: Which register in the CLUT we are programming - * @red: The red value which can be up to 16 bits wide + * s1d13xxxfb_setcolreg - sets a color register. + * @regno: Which register in the CLUT we are programming + * @red: The red value which can be up to 16 bits wide * @green: The green value which can be up to 16 bits wide * @blue: The blue value which can be up to 16 bits wide. * @transp: If supported the alpha value which can be up to 16 bits wide. - * @info: frame buffer info structure + * @info: frame buffer info structure * * Returns negative errno on error, or zero on success. */ @@ -351,15 +365,15 @@ s1d13xxxfb_blank(int blank_mode, struct fb_info *info) } /** - * s1d13xxxfb_pan_display - Pans the display. - * @var: frame buffer variable screen structure - * @info: frame buffer structure that represents a single frame buffer + * s1d13xxxfb_pan_display - Pans the display. + * @var: frame buffer variable screen structure + * @info: frame buffer structure that represents a single frame buffer * * Pan (or wrap, depending on the `vmode' field) the display using the - * `yoffset' field of the `var' structure (`xoffset' not yet supported). - * If the values don't fit, return -EINVAL. + * `yoffset' field of the `var' structure (`xoffset' not yet supported). + * If the values don't fit, return -EINVAL. * - * Returns negative errno on error, or zero on success. + * Returns negative errno on error, or zero on success. */ static int s1d13xxxfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) @@ -390,8 +404,259 @@ s1d13xxxfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) return 0; } -/* framebuffer information structures */ +/************************************************************ + functions to handle bitblt acceleration + ************************************************************/ + +/** + * bltbit_wait_bitset - waits for change in register value + * @info : framebuffer structure + * @bit : value expected in register + * @timeout : ... + * + * waits until value changes INTO bit + */ +static u8 +bltbit_wait_bitset(struct fb_info *info, u8 bit, int timeout) +{ + while (!(s1d13xxxfb_readreg(info->par, S1DREG_BBLT_CTL0) & bit)) { + udelay(10); + if (!--timeout) { + dbg_blit("wait_bitset timeout\n"); + break; + } + } + + return timeout; +} + +/** + * bltbit_wait_bitclear - waits for change in register value + * @info : frambuffer structure + * @bit : value currently in register + * @timeout : ... + * + * waits until value changes FROM bit + * + */ +static u8 +bltbit_wait_bitclear(struct fb_info *info, u8 bit, int timeout) +{ + while (s1d13xxxfb_readreg(info->par, S1DREG_BBLT_CTL0) & bit) { + udelay(10); + if (!--timeout) { + dbg_blit("wait_bitclear timeout\n"); + break; + } + } + + return timeout; +} + +/** + * bltbit_fifo_status - checks the current status of the fifo + * @info : framebuffer structure + * + * returns number of free words in buffer + */ +static u8 +bltbit_fifo_status(struct fb_info *info) +{ + u8 status; + status = s1d13xxxfb_readreg(info->par, S1DREG_BBLT_CTL0); + + /* its empty so room for 16 words */ + if (status & BBLT_FIFO_EMPTY) + return 16; + + /* its full so we dont want to add */ + if (status & BBLT_FIFO_FULL) + return 0; + + /* its atleast half full but we can add one atleast */ + if (status & BBLT_FIFO_NOT_FULL) + return 1; + + return 0; +} + +/* + * s1d13xxxfb_bitblt_copyarea - accelerated copyarea function + * @info : framebuffer structure + * @area : fb_copyarea structure + * + * supports (atleast) S1D13506 + * + */ +static void +s1d13xxxfb_bitblt_copyarea(struct fb_info *info, const struct fb_copyarea *area) +{ + u32 dst, src; + u32 stride; + u16 reverse = 0; + u16 sx = area->sx, sy = area->sy; + u16 dx = area->dx, dy = area->dy; + u16 width = area->width, height = area->height; + u16 bpp; + + spin_lock(&s1d13xxxfb_bitblt_lock); + + /* bytes per xres line */ + bpp = (info->var.bits_per_pixel >> 3); + stride = bpp * info->var.xres; + + /* reverse, calculate the last pixel in rectangle */ + if ((dy > sy) || ((dy == sy) && (dx >= sx))) { + dst = (((dy + height - 1) * stride) + (bpp * (dx + width - 1))); + src = (((sy + height - 1) * stride) + (bpp * (sx + width - 1))); + reverse = 1; + /* not reverse, calculate the first pixel in rectangle */ + } else { /* (y * xres) + (bpp * x) */ + dst = (dy * stride) + (bpp * dx); + src = (sy * stride) + (bpp * sx); + } + + /* set source adress */ + s1d13xxxfb_writereg(info->par, S1DREG_BBLT_SRC_START0, (src & 0xff)); + s1d13xxxfb_writereg(info->par, S1DREG_BBLT_SRC_START1, (src >> 8) & 0x00ff); + s1d13xxxfb_writereg(info->par, S1DREG_BBLT_SRC_START2, (src >> 16) & 0x00ff); + + /* set destination adress */ + s1d13xxxfb_writereg(info->par, S1DREG_BBLT_DST_START0, (dst & 0xff)); + s1d13xxxfb_writereg(info->par, S1DREG_BBLT_DST_START1, (dst >> 8) & 0x00ff); + s1d13xxxfb_writereg(info->par, S1DREG_BBLT_DST_START2, (dst >> 16) & 0x00ff); + + /* program height and width */ + s1d13xxxfb_writereg(info->par, S1DREG_BBLT_WIDTH0, (width & 0xff) - 1); + s1d13xxxfb_writereg(info->par, S1DREG_BBLT_WIDTH1, (width >> 8)); + + s1d13xxxfb_writereg(info->par, S1DREG_BBLT_HEIGHT0, (height & 0xff) - 1); + s1d13xxxfb_writereg(info->par, S1DREG_BBLT_HEIGHT1, (height >> 8)); + + /* negative direction ROP */ + if (reverse == 1) { + dbg_blit("(copyarea) negative rop\n"); + s1d13xxxfb_writereg(info->par, S1DREG_BBLT_OP, 0x03); + } else /* positive direction ROP */ { + s1d13xxxfb_writereg(info->par, S1DREG_BBLT_OP, 0x02); + dbg_blit("(copyarea) positive rop\n"); + } + + /* set for rectangel mode and not linear */ + s1d13xxxfb_writereg(info->par, S1DREG_BBLT_CTL0, 0x0); + + /* setup the bpp 1 = 16bpp, 0 = 8bpp*/ + s1d13xxxfb_writereg(info->par, S1DREG_BBLT_CTL1, (bpp >> 1)); + + /* set words per xres */ + s1d13xxxfb_writereg(info->par, S1DREG_BBLT_MEM_OFF0, (stride >> 1) & 0xff); + s1d13xxxfb_writereg(info->par, S1DREG_BBLT_MEM_OFF1, (stride >> 9)); + + dbg_blit("(copyarea) dx=%d, dy=%d\n", dx, dy); + dbg_blit("(copyarea) sx=%d, sy=%d\n", sx, sy); + dbg_blit("(copyarea) width=%d, height=%d\n", width - 1, height - 1); + dbg_blit("(copyarea) stride=%d\n", stride); + dbg_blit("(copyarea) bpp=%d=0x0%d, mem_offset1=%d, mem_offset2=%d\n", bpp, (bpp >> 1), + (stride >> 1) & 0xff, stride >> 9); + + s1d13xxxfb_writereg(info->par, S1DREG_BBLT_CC_EXP, 0x0c); + + /* initialize the engine */ + s1d13xxxfb_writereg(info->par, S1DREG_BBLT_CTL0, 0x80); + + /* wait to complete */ + bltbit_wait_bitclear(info, 0x80, 8000); + + spin_unlock(&s1d13xxxfb_bitblt_lock); +} + +/** + * + * s1d13xxxfb_bitblt_solidfill - accelerated solidfill function + * @info : framebuffer structure + * @rect : fb_fillrect structure + * + * supports (atleast 13506) + * + **/ +static void +s1d13xxxfb_bitblt_solidfill(struct fb_info *info, const struct fb_fillrect *rect) +{ + u32 screen_stride, dest; + u32 fg; + u16 bpp = (info->var.bits_per_pixel >> 3); + + /* grab spinlock */ + spin_lock(&s1d13xxxfb_bitblt_lock); + + /* bytes per x width */ + screen_stride = (bpp * info->var.xres); + + /* bytes to starting point */ + dest = ((rect->dy * screen_stride) + (bpp * rect->dx)); + + dbg_blit("(solidfill) dx=%d, dy=%d, stride=%d, dest=%d\n" + "(solidfill) : rect_width=%d, rect_height=%d\n", + rect->dx, rect->dy, screen_stride, dest, + rect->width - 1, rect->height - 1); + + dbg_blit("(solidfill) : xres=%d, yres=%d, bpp=%d\n", + info->var.xres, info->var.yres, + info->var.bits_per_pixel); + dbg_blit("(solidfill) : rop=%d\n", rect->rop); + + /* We split the destination into the three registers */ + s1d13xxxfb_writereg(info->par, S1DREG_BBLT_DST_START0, (dest & 0x00ff)); + s1d13xxxfb_writereg(info->par, S1DREG_BBLT_DST_START1, ((dest >> 8) & 0x00ff)); + s1d13xxxfb_writereg(info->par, S1DREG_BBLT_DST_START2, ((dest >> 16) & 0x00ff)); + + /* give information regarding rectangel width */ + s1d13xxxfb_writereg(info->par, S1DREG_BBLT_WIDTH0, ((rect->width) & 0x00ff) - 1); + s1d13xxxfb_writereg(info->par, S1DREG_BBLT_WIDTH1, (rect->width >> 8)); + + /* give information regarding rectangel height */ + s1d13xxxfb_writereg(info->par, S1DREG_BBLT_HEIGHT0, ((rect->height) & 0x00ff) - 1); + s1d13xxxfb_writereg(info->par, S1DREG_BBLT_HEIGHT1, (rect->height >> 8)); + + if (info->fix.visual == FB_VISUAL_TRUECOLOR || + info->fix.visual == FB_VISUAL_DIRECTCOLOR) { + fg = ((u32 *)info->pseudo_palette)[rect->color]; + dbg_blit("(solidfill) truecolor/directcolor\n"); + dbg_blit("(solidfill) pseudo_palette[%d] = %d\n", rect->color, fg); + } else { + fg = rect->color; + dbg_blit("(solidfill) color = %d\n", rect->color); + } + + /* set foreground color */ + s1d13xxxfb_writereg(info->par, S1DREG_BBLT_FGC0, (fg & 0xff)); + s1d13xxxfb_writereg(info->par, S1DREG_BBLT_FGC1, (fg >> 8) & 0xff); + + /* set rectangual region of memory (rectangle and not linear) */ + s1d13xxxfb_writereg(info->par, S1DREG_BBLT_CTL0, 0x0); + + /* set operation mode SOLID_FILL */ + s1d13xxxfb_writereg(info->par, S1DREG_BBLT_OP, BBLT_SOLID_FILL); + + /* set bits per pixel (1 = 16bpp, 0 = 8bpp) */ + s1d13xxxfb_writereg(info->par, S1DREG_BBLT_CTL1, (info->var.bits_per_pixel >> 4)); + + /* set the memory offset for the bblt in word sizes */ + s1d13xxxfb_writereg(info->par, S1DREG_BBLT_MEM_OFF0, (screen_stride >> 1) & 0x00ff); + s1d13xxxfb_writereg(info->par, S1DREG_BBLT_MEM_OFF1, (screen_stride >> 9)); + + /* and away we go.... */ + s1d13xxxfb_writereg(info->par, S1DREG_BBLT_CTL0, 0x80); + + /* wait until its done */ + bltbit_wait_bitclear(info, 0x80, 8000); + + /* let others play */ + spin_unlock(&s1d13xxxfb_bitblt_lock); +} + +/* framebuffer information structures */ static struct fb_ops s1d13xxxfb_fbops = { .owner = THIS_MODULE, .fb_set_par = s1d13xxxfb_set_par, @@ -400,7 +665,7 @@ static struct fb_ops s1d13xxxfb_fbops = { .fb_pan_display = s1d13xxxfb_pan_display, - /* to be replaced by any acceleration we can */ + /* gets replaced at chip detection time */ .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, @@ -412,9 +677,9 @@ static int s1d13xxxfb_width_tab[2][4] __devinitdata = { }; /** - * s1d13xxxfb_fetch_hw_state - Configure the framebuffer according to + * s1d13xxxfb_fetch_hw_state - Configure the framebuffer according to * hardware setup. - * @info: frame buffer structure + * @info: frame buffer structure * * We setup the framebuffer structures according to the current * hardware setup. On some machines, the BIOS will have filled @@ -569,7 +834,6 @@ s1d13xxxfb_probe(struct platform_device *pdev) if (pdata && pdata->platform_init_video) pdata->platform_init_video(); - if (pdev->num_resources != 2) { dev_err(&pdev->dev, "invalid num_resources: %i\n", pdev->num_resources); @@ -655,16 +919,27 @@ s1d13xxxfb_probe(struct platform_device *pdev) info->fix = s1d13xxxfb_fix; info->fix.mmio_start = pdev->resource[1].start; - info->fix.mmio_len = pdev->resource[1].end - pdev->resource[1].start +1; + info->fix.mmio_len = pdev->resource[1].end - pdev->resource[1].start + 1; info->fix.smem_start = pdev->resource[0].start; - info->fix.smem_len = pdev->resource[0].end - pdev->resource[0].start +1; + info->fix.smem_len = pdev->resource[0].end - pdev->resource[0].start + 1; printk(KERN_INFO PFX "regs mapped at 0x%p, fb %d KiB mapped at 0x%p\n", default_par->regs, info->fix.smem_len / 1024, info->screen_base); info->par = default_par; - info->fbops = &s1d13xxxfb_fbops; info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; + info->fbops = &s1d13xxxfb_fbops; + + switch(prod_id) { + case S1D13506_PROD_ID: /* activate acceleration */ + s1d13xxxfb_fbops.fb_fillrect = s1d13xxxfb_bitblt_solidfill; + s1d13xxxfb_fbops.fb_copyarea = s1d13xxxfb_bitblt_copyarea; + info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN | + FBINFO_HWACCEL_FILLRECT | FBINFO_HWACCEL_COPYAREA; + break; + default: + break; + } /* perform "manual" chip initialization, if needed */ if (pdata && pdata->initregs) diff --git a/drivers/video/s3c-fb.c b/drivers/video/s3c-fb.c index d3a568e6b16..43680e54542 100644 --- a/drivers/video/s3c-fb.c +++ b/drivers/video/s3c-fb.c @@ -358,9 +358,16 @@ static int s3c_fb_set_par(struct fb_info *info) writel(data, regs + VIDOSD_B(win_no)); data = var->xres * var->yres; + + u32 osdc_data = 0; + + osdc_data = VIDISD14C_ALPHA1_R(0xf) | + VIDISD14C_ALPHA1_G(0xf) | + VIDISD14C_ALPHA1_B(0xf); + if (s3c_fb_has_osd_d(win_no)) { writel(data, regs + VIDOSD_D(win_no)); - writel(0, regs + VIDOSD_C(win_no)); + writel(osdc_data, regs + VIDOSD_C(win_no)); } else writel(data, regs + VIDOSD_C(win_no)); @@ -409,8 +416,12 @@ static int s3c_fb_set_par(struct fb_info *info) data |= WINCON1_BPPMODE_19BPP_A1666; else data |= WINCON1_BPPMODE_18BPP_666; - } else if (var->transp.length != 0) - data |= WINCON1_BPPMODE_25BPP_A1888; + } else if (var->transp.length == 1) + data |= WINCON1_BPPMODE_25BPP_A1888 + | WINCON1_BLD_PIX; + else if (var->transp.length == 4) + data |= WINCON1_BPPMODE_28BPP_A4888 + | WINCON1_BLD_PIX | WINCON1_ALPHA_SEL; else data |= WINCON0_BPPMODE_24BPP_888; @@ -418,6 +429,20 @@ static int s3c_fb_set_par(struct fb_info *info) break; } + /* It has no color key control register for window0 */ + if (win_no > 0) { + u32 keycon0_data = 0, keycon1_data = 0; + + keycon0_data = ~(WxKEYCON0_KEYBL_EN | + WxKEYCON0_KEYEN_F | + WxKEYCON0_DIRCON) | WxKEYCON0_COMPKEY(0); + + keycon1_data = WxKEYCON1_COLVAL(0xffffff); + + writel(keycon0_data, regs + WxKEYCONy(win_no-1, 0)); + writel(keycon1_data, regs + WxKEYCONy(win_no-1, 1)); + } + writel(data, regs + WINCON(win_no)); writel(0x0, regs + WINxMAP(win_no)); @@ -700,9 +725,12 @@ static void s3c_fb_free_memory(struct s3c_fb *sfb, struct s3c_fb_win *win) */ static void s3c_fb_release_win(struct s3c_fb *sfb, struct s3c_fb_win *win) { - fb_dealloc_cmap(&win->fbinfo->cmap); - unregister_framebuffer(win->fbinfo); - s3c_fb_free_memory(sfb, win); + if (win->fbinfo) { + unregister_framebuffer(win->fbinfo); + fb_dealloc_cmap(&win->fbinfo->cmap); + s3c_fb_free_memory(sfb, win); + framebuffer_release(win->fbinfo); + } } /** @@ -753,7 +781,7 @@ static int __devinit s3c_fb_probe_win(struct s3c_fb *sfb, unsigned int win_no, ret = s3c_fb_alloc_memory(sfb, win); if (ret) { dev_err(sfb->dev, "failed to allocate display memory\n"); - goto err_framebuffer; + return ret; } /* setup the r/b/g positions for the window's palette */ @@ -776,7 +804,7 @@ static int __devinit s3c_fb_probe_win(struct s3c_fb *sfb, unsigned int win_no, ret = s3c_fb_check_var(&fbinfo->var, fbinfo); if (ret < 0) { dev_err(sfb->dev, "check_var failed on initial video params\n"); - goto err_alloc_mem; + return ret; } /* create initial colour map */ @@ -796,20 +824,13 @@ static int __devinit s3c_fb_probe_win(struct s3c_fb *sfb, unsigned int win_no, ret = register_framebuffer(fbinfo); if (ret < 0) { dev_err(sfb->dev, "failed to register framebuffer\n"); - goto err_alloc_mem; + return ret; } *res = win; dev_info(sfb->dev, "window %d: fb %s\n", win_no, fbinfo->fix.id); return 0; - -err_alloc_mem: - s3c_fb_free_memory(sfb, win); - -err_framebuffer: - unregister_framebuffer(fbinfo); - return ret; } /** diff --git a/drivers/video/s3c2410fb.c b/drivers/video/s3c2410fb.c index b0b4513ba53..7da0027e240 100644 --- a/drivers/video/s3c2410fb.c +++ b/drivers/video/s3c2410fb.c @@ -24,6 +24,7 @@ #include <linux/interrupt.h> #include <linux/platform_device.h> #include <linux/clk.h> +#include <linux/cpufreq.h> #include <asm/io.h> #include <asm/div64.h> @@ -89,7 +90,7 @@ static void s3c2410fb_set_lcdaddr(struct fb_info *info) static unsigned int s3c2410fb_calc_pixclk(struct s3c2410fb_info *fbi, unsigned long pixclk) { - unsigned long clk = clk_get_rate(fbi->clk); + unsigned long clk = fbi->clk_rate; unsigned long long div; /* pixclk is in picoseconds, our clock is in Hz @@ -758,6 +759,57 @@ static irqreturn_t s3c2410fb_irq(int irq, void *dev_id) return IRQ_HANDLED; } +#ifdef CONFIG_CPU_FREQ + +static int s3c2410fb_cpufreq_transition(struct notifier_block *nb, + unsigned long val, void *data) +{ + struct cpufreq_freqs *freqs = data; + struct s3c2410fb_info *info; + struct fb_info *fbinfo; + long delta_f; + + info = container_of(nb, struct s3c2410fb_info, freq_transition); + fbinfo = platform_get_drvdata(to_platform_device(info->dev)); + + /* work out change, <0 for speed-up */ + delta_f = info->clk_rate - clk_get_rate(info->clk); + + if ((val == CPUFREQ_POSTCHANGE && delta_f > 0) || + (val == CPUFREQ_PRECHANGE && delta_f < 0)) { + info->clk_rate = clk_get_rate(info->clk); + s3c2410fb_activate_var(fbinfo); + } + + return 0; +} + +static inline int s3c2410fb_cpufreq_register(struct s3c2410fb_info *info) +{ + info->freq_transition.notifier_call = s3c2410fb_cpufreq_transition; + + return cpufreq_register_notifier(&info->freq_transition, + CPUFREQ_TRANSITION_NOTIFIER); +} + +static inline void s3c2410fb_cpufreq_deregister(struct s3c2410fb_info *info) +{ + cpufreq_unregister_notifier(&info->freq_transition, + CPUFREQ_TRANSITION_NOTIFIER); +} + +#else +static inline int s3c2410fb_cpufreq_register(struct s3c2410fb_info *info) +{ + return 0; +} + +static inline void s3c2410fb_cpufreq_deregister(struct s3c2410fb_info *info) +{ +} +#endif + + static char driver_name[] = "s3c2410fb"; static int __init s3c24xxfb_probe(struct platform_device *pdev, @@ -875,6 +927,8 @@ static int __init s3c24xxfb_probe(struct platform_device *pdev, msleep(1); + info->clk_rate = clk_get_rate(info->clk); + /* find maximum required memory size for display */ for (i = 0; i < mach_info->num_displays; i++) { unsigned long smem_len = mach_info->displays[i].xres; @@ -904,11 +958,17 @@ static int __init s3c24xxfb_probe(struct platform_device *pdev, s3c2410fb_check_var(&fbinfo->var, fbinfo); + ret = s3c2410fb_cpufreq_register(info); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to register cpufreq\n"); + goto free_video_memory; + } + ret = register_framebuffer(fbinfo); if (ret < 0) { printk(KERN_ERR "Failed to register framebuffer device: %d\n", ret); - goto free_video_memory; + goto free_cpufreq; } /* create device files */ @@ -922,6 +982,8 @@ static int __init s3c24xxfb_probe(struct platform_device *pdev, return 0; + free_cpufreq: + s3c2410fb_cpufreq_deregister(info); free_video_memory: s3c2410fb_unmap_video_memory(fbinfo); release_clock: @@ -961,6 +1023,7 @@ static int s3c2410fb_remove(struct platform_device *pdev) int irq; unregister_framebuffer(fbinfo); + s3c2410fb_cpufreq_deregister(info); s3c2410fb_lcd_enable(info, 0); msleep(1); diff --git a/drivers/video/s3c2410fb.h b/drivers/video/s3c2410fb.h index 9a6ba3e9d1b..47a17bd2301 100644 --- a/drivers/video/s3c2410fb.h +++ b/drivers/video/s3c2410fb.h @@ -29,8 +29,13 @@ struct s3c2410fb_info { enum s3c_drv_type drv_type; struct s3c2410fb_hw regs; + unsigned long clk_rate; unsigned int palette_ready; +#ifdef CONFIG_CPU_FREQ + struct notifier_block freq_transition; +#endif + /* keep these registers in case we need to re-write palette */ u32 palette_buffer[256]; u32 pseudo_pal[16]; diff --git a/drivers/video/sis/sis_main.c b/drivers/video/sis/sis_main.c index 7e17ee95a97..7072d19080d 100644 --- a/drivers/video/sis/sis_main.c +++ b/drivers/video/sis/sis_main.c @@ -5928,7 +5928,7 @@ sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if(pci_enable_device(pdev)) { if(ivideo->nbridge) pci_dev_put(ivideo->nbridge); pci_set_drvdata(pdev, NULL); - kfree(sis_fb_info); + framebuffer_release(sis_fb_info); return -EIO; } } @@ -6134,7 +6134,7 @@ error_3: vfree(ivideo->bios_abase); pci_set_drvdata(pdev, NULL); if(!ivideo->sisvga_enabled) pci_disable_device(pdev); - kfree(sis_fb_info); + framebuffer_release(sis_fb_info); return ret; } diff --git a/drivers/video/stifb.c b/drivers/video/stifb.c index eabaad765ae..eec9dcb7f59 100644 --- a/drivers/video/stifb.c +++ b/drivers/video/stifb.c @@ -1380,7 +1380,7 @@ stifb_cleanup(void) if (info->screen_base) iounmap(info->screen_base); fb_dealloc_cmap(&info->cmap); - kfree(info); + framebuffer_release(info); } sti->info = NULL; } diff --git a/drivers/video/tcx.c b/drivers/video/tcx.c index 643afbfe827..45b883598bf 100644 --- a/drivers/video/tcx.c +++ b/drivers/video/tcx.c @@ -116,17 +116,16 @@ struct tcx_par { u32 flags; #define TCX_FLAG_BLANKED 0x00000001 - unsigned long physbase; unsigned long which_io; - unsigned long fbsize; struct sbus_mmap_map mmap_map[TCX_MMAP_ENTRIES]; int lowdepth; }; /* Reset control plane so that WID is 8-bit plane. */ -static void __tcx_set_control_plane(struct tcx_par *par) +static void __tcx_set_control_plane(struct fb_info *info) { + struct tcx_par *par = info->par; u32 __iomem *p, *pend; if (par->lowdepth) @@ -135,7 +134,7 @@ static void __tcx_set_control_plane(struct tcx_par *par) p = par->cplane; if (p == NULL) return; - for (pend = p + par->fbsize; p < pend; p++) { + for (pend = p + info->fix.smem_len; p < pend; p++) { u32 tmp = sbus_readl(p); tmp &= 0xffffff; @@ -149,7 +148,7 @@ static void tcx_reset(struct fb_info *info) unsigned long flags; spin_lock_irqsave(&par->lock, flags); - __tcx_set_control_plane(par); + __tcx_set_control_plane(info); spin_unlock_irqrestore(&par->lock, flags); } @@ -304,7 +303,7 @@ static int tcx_mmap(struct fb_info *info, struct vm_area_struct *vma) struct tcx_par *par = (struct tcx_par *)info->par; return sbusfb_mmap_helper(par->mmap_map, - par->physbase, par->fbsize, + info->fix.smem_start, info->fix.smem_len, par->which_io, vma); } @@ -316,7 +315,7 @@ static int tcx_ioctl(struct fb_info *info, unsigned int cmd, return sbusfb_ioctl_helper(cmd, arg, info, FBTYPE_TCXCOLOR, (par->lowdepth ? 8 : 24), - par->fbsize); + info->fix.smem_len); } /* @@ -358,10 +357,10 @@ static void tcx_unmap_regs(struct of_device *op, struct fb_info *info, par->bt, sizeof(struct bt_regs)); if (par->cplane) of_iounmap(&op->resource[4], - par->cplane, par->fbsize * sizeof(u32)); + par->cplane, info->fix.smem_len * sizeof(u32)); if (info->screen_base) of_iounmap(&op->resource[0], - info->screen_base, par->fbsize); + info->screen_base, info->fix.smem_len); } static int __devinit tcx_probe(struct of_device *op, @@ -391,7 +390,7 @@ static int __devinit tcx_probe(struct of_device *op, linebytes = of_getintprop_default(dp, "linebytes", info->var.xres); - par->fbsize = PAGE_ALIGN(linebytes * info->var.yres); + info->fix.smem_len = PAGE_ALIGN(linebytes * info->var.yres); par->tec = of_ioremap(&op->resource[7], 0, sizeof(struct tcx_tec), "tcx tec"); @@ -400,7 +399,7 @@ static int __devinit tcx_probe(struct of_device *op, par->bt = of_ioremap(&op->resource[8], 0, sizeof(struct bt_regs), "tcx dac"); info->screen_base = of_ioremap(&op->resource[0], 0, - par->fbsize, "tcx ram"); + info->fix.smem_len, "tcx ram"); if (!par->tec || !par->thc || !par->bt || !info->screen_base) goto out_unmap_regs; @@ -408,7 +407,7 @@ static int __devinit tcx_probe(struct of_device *op, memcpy(&par->mmap_map, &__tcx_mmap_map, sizeof(par->mmap_map)); if (!par->lowdepth) { par->cplane = of_ioremap(&op->resource[4], 0, - par->fbsize * sizeof(u32), + info->fix.smem_len * sizeof(u32), "tcx cplane"); if (!par->cplane) goto out_unmap_regs; @@ -419,7 +418,7 @@ static int __devinit tcx_probe(struct of_device *op, par->mmap_map[6].size = SBUS_MMAP_EMPTY; } - par->physbase = op->resource[0].start; + info->fix.smem_start = op->resource[0].start; par->which_io = op->resource[0].flags & IORESOURCE_BITS; for (i = 0; i < TCX_MMAP_ENTRIES; i++) { @@ -473,7 +472,7 @@ static int __devinit tcx_probe(struct of_device *op, printk(KERN_INFO "%s: TCX at %lx:%lx, %s\n", dp->full_name, par->which_io, - par->physbase, + info->fix.smem_start, par->lowdepth ? "8-bit only" : "24-bit depth"); return 0; diff --git a/drivers/video/vesafb.c b/drivers/video/vesafb.c index d6856f43d24..bd37ee1f6a2 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, return err; } +static void vesafb_destroy(struct fb_info *info) +{ + if (info->screen_base) + iounmap(info->screen_base); + release_mem_region(info->aperture_base, info->aperture_size); + framebuffer_release(info); +} + static struct fb_ops vesafb_ops = { .owner = THIS_MODULE, + .fb_destroy = vesafb_destroy, .fb_setcolreg = vesafb_setcolreg, .fb_pan_display = vesafb_pan_display, .fb_fillrect = cfb_fillrect, @@ -286,6 +295,10 @@ static int __init vesafb_probe(struct platform_device *dev) info->pseudo_palette = info->par; info->par = NULL; + /* set vesafb aperture size for generic probing */ + info->aperture_base = screen_info.lfb_base; + info->aperture_size = size_total; + info->screen_base = ioremap(vesafb_fix.smem_start, vesafb_fix.smem_len); if (!info->screen_base) { printk(KERN_ERR @@ -437,7 +450,7 @@ static int __init vesafb_probe(struct platform_device *dev) info->fbops = &vesafb_ops; info->var = vesafb_defined; info->fix = vesafb_fix; - info->flags = FBINFO_FLAG_DEFAULT | + info->flags = FBINFO_FLAG_DEFAULT | FBINFO_MISC_FIRMWARE | (ypan ? FBINFO_HWACCEL_YPAN : 0); if (!ypan) |