diff options
Diffstat (limited to 'drivers/video')
50 files changed, 2271 insertions, 596 deletions
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 0048f1185a60..932ffdbf86d9 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -397,7 +397,7 @@ config FB_SA1100 config FB_IMX tristate "Motorola i.MX LCD support" - depends on FB && (ARCH_IMX || ARCH_MX2) + depends on FB && (ARCH_MX1 || ARCH_MX2) select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT @@ -1759,6 +1759,16 @@ config FB_68328 Say Y here if you want to support the built-in frame buffer of the Motorola 68328 CPU family. +config FB_PXA168 + tristate "PXA168/910 LCD framebuffer support" + depends on FB && (CPU_PXA168 || CPU_PXA910) + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + ---help--- + Frame buffer driver for the built-in LCD controller in the Marvell + MMP processor. + config FB_PXA tristate "PXA LCD framebuffer support" depends on FB && ARCH_PXA @@ -1996,7 +2006,7 @@ config FB_PS3_DEFAULT_SIZE_M config FB_XILINX tristate "Xilinx frame buffer support" - depends on FB && XILINX_VIRTEX + depends on FB && (XILINX_VIRTEX || MICROBLAZE) select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT @@ -2094,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/Makefile b/drivers/video/Makefile index d8d0be5151e3..01a819f47371 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -97,6 +97,7 @@ obj-$(CONFIG_FB_GBE) += gbefb.o obj-$(CONFIG_FB_CIRRUS) += cirrusfb.o obj-$(CONFIG_FB_ASILIANT) += asiliantfb.o obj-$(CONFIG_FB_PXA) += pxafb.o +obj-$(CONFIG_FB_PXA168) += pxa168fb.o obj-$(CONFIG_FB_W100) += w100fb.o obj-$(CONFIG_FB_TMIO) += tmiofb.o obj-$(CONFIG_FB_AU1100) += au1100fb.o diff --git a/drivers/video/acornfb.c b/drivers/video/acornfb.c index 6995fe1e86d4..0bcc59eb37fa 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/amba-clcd.c b/drivers/video/amba-clcd.c index 61050ab14128..fb8163d181ab 100644 --- a/drivers/video/amba-clcd.c +++ b/drivers/video/amba-clcd.c @@ -351,7 +351,7 @@ static int clcdfb_register(struct clcd_fb *fb) } fb->fb.fix.mmio_start = fb->dev->res.start; - fb->fb.fix.mmio_len = 4096; + fb->fb.fix.mmio_len = resource_size(&fb->dev->res); fb->regs = ioremap(fb->fb.fix.mmio_start, fb->fb.fix.mmio_len); if (!fb->regs) { @@ -437,7 +437,7 @@ static int clcdfb_register(struct clcd_fb *fb) return ret; } -static int clcdfb_probe(struct amba_device *dev, void *id) +static int clcdfb_probe(struct amba_device *dev, struct amba_id *id) { struct clcd_board *board = dev->dev.platform_data; struct clcd_fb *fb; diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c index 9a577a800db5..5afd64482f55 100644 --- a/drivers/video/atmel_lcdfb.c +++ b/drivers/video/atmel_lcdfb.c @@ -29,14 +29,8 @@ /* configurable parameters */ #define ATMEL_LCDC_CVAL_DEFAULT 0xc8 -#define ATMEL_LCDC_DMA_BURST_LEN 8 - -#if defined(CONFIG_ARCH_AT91SAM9263) || defined(CONFIG_ARCH_AT91CAP9) || \ - defined(CONFIG_ARCH_AT91SAM9RL) -#define ATMEL_LCDC_FIFO_SIZE 2048 -#else -#define ATMEL_LCDC_FIFO_SIZE 512 -#endif +#define ATMEL_LCDC_DMA_BURST_LEN 8 /* words */ +#define ATMEL_LCDC_FIFO_SIZE 512 /* words */ #if defined(CONFIG_ARCH_AT91) #define ATMEL_LCDFB_FBINFO_DEFAULT (FBINFO_DEFAULT \ @@ -351,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/aty128fb.c b/drivers/video/aty/aty128fb.c index 35e8eb02b9e9..e4e4d433b007 100644 --- a/drivers/video/aty/aty128fb.c +++ b/drivers/video/aty/aty128fb.c @@ -354,7 +354,7 @@ static int default_crt_on __devinitdata = 0; static int default_lcd_on __devinitdata = 1; #ifdef CONFIG_MTRR -static int mtrr = 1; +static bool mtrr = true; #endif #ifdef CONFIG_PMAC_BACKLIGHT diff --git a/drivers/video/aty/radeon_pm.c b/drivers/video/aty/radeon_pm.c index 97a1f095f327..515cf1978d19 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 37e60b1d2ed9..e49ae5edcc00 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 90cfddabf1f7..5cc36cfbf07b 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/bw2.c b/drivers/video/bw2.c index 1e35ba6f18e0..b0b147cb4cb3 100644 --- a/drivers/video/bw2.c +++ b/drivers/video/bw2.c @@ -111,9 +111,7 @@ struct bw2_par { u32 flags; #define BW2_FLAG_BLANKED 0x00000001 - unsigned long physbase; unsigned long which_io; - unsigned long fbsize; }; /** @@ -167,17 +165,15 @@ static int bw2_mmap(struct fb_info *info, struct vm_area_struct *vma) struct bw2_par *par = (struct bw2_par *)info->par; return sbusfb_mmap_helper(bw2_mmap_map, - par->physbase, par->fbsize, + info->fix.smem_start, info->fix.smem_len, par->which_io, vma); } static int bw2_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) { - struct bw2_par *par = (struct bw2_par *) info->par; - return sbusfb_ioctl_helper(cmd, arg, info, - FBTYPE_SUN2BW, 1, par->fbsize); + FBTYPE_SUN2BW, 1, info->fix.smem_len); } /* @@ -294,7 +290,7 @@ static int __devinit bw2_probe(struct of_device *op, const struct of_device_id * spin_lock_init(&par->lock); - par->physbase = op->resource[0].start; + info->fix.smem_start = op->resource[0].start; par->which_io = op->resource[0].flags & IORESOURCE_BITS; sbusfb_fill_var(&info->var, dp, 1); @@ -317,13 +313,13 @@ static int __devinit bw2_probe(struct of_device *op, const struct of_device_id * goto out_unmap_regs; } - par->fbsize = PAGE_ALIGN(linebytes * info->var.yres); + info->fix.smem_len = PAGE_ALIGN(linebytes * info->var.yres); info->flags = FBINFO_DEFAULT; info->fbops = &bw2_ops; info->screen_base = of_ioremap(&op->resource[0], 0, - par->fbsize, "bw2 ram"); + info->fix.smem_len, "bw2 ram"); if (!info->screen_base) goto out_unmap_regs; @@ -338,12 +334,12 @@ static int __devinit bw2_probe(struct of_device *op, const struct of_device_id * dev_set_drvdata(&op->dev, info); printk(KERN_INFO "%s: bwtwo at %lx:%lx\n", - dp->full_name, par->which_io, par->physbase); + dp->full_name, par->which_io, info->fix.smem_start); return 0; out_unmap_screen: - of_iounmap(&op->resource[0], info->screen_base, par->fbsize); + of_iounmap(&op->resource[0], info->screen_base, info->fix.smem_len); out_unmap_regs: of_iounmap(&op->resource[0], par->regs, sizeof(struct bw2_regs)); @@ -363,7 +359,7 @@ static int __devexit bw2_remove(struct of_device *op) unregister_framebuffer(info); of_iounmap(&op->resource[0], par->regs, sizeof(struct bw2_regs)); - of_iounmap(&op->resource[0], info->screen_base, par->fbsize); + of_iounmap(&op->resource[0], info->screen_base, info->fix.smem_len); framebuffer_release(info); diff --git a/drivers/video/carminefb.c b/drivers/video/carminefb.c index c7ff3c1a266a..0c02f8ec4bf3 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/cg14.c b/drivers/video/cg14.c index a2d1882791a5..fe45a3b8d0e0 100644 --- a/drivers/video/cg14.c +++ b/drivers/video/cg14.c @@ -196,9 +196,7 @@ struct cg14_par { u32 flags; #define CG14_FLAG_BLANKED 0x00000001 - unsigned long physbase; unsigned long iospace; - unsigned long fbsize; struct sbus_mmap_map mmap_map[CG14_MMAP_ENTRIES]; @@ -271,7 +269,7 @@ static int cg14_mmap(struct fb_info *info, struct vm_area_struct *vma) struct cg14_par *par = (struct cg14_par *) info->par; return sbusfb_mmap_helper(par->mmap_map, - par->physbase, par->fbsize, + info->fix.smem_start, info->fix.smem_len, par->iospace, vma); } @@ -343,7 +341,8 @@ static int cg14_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) default: ret = sbusfb_ioctl_helper(cmd, arg, info, - FBTYPE_MDICOLOR, 8, par->fbsize); + FBTYPE_MDICOLOR, 8, + info->fix.smem_len); break; }; @@ -462,7 +461,7 @@ static void cg14_unmap_regs(struct of_device *op, struct fb_info *info, par->cursor, sizeof(struct cg14_cursor)); if (info->screen_base) of_iounmap(&op->resource[1], - info->screen_base, par->fbsize); + info->screen_base, info->fix.smem_len); } static int __devinit cg14_probe(struct of_device *op, const struct of_device_id *match) @@ -488,14 +487,14 @@ static int __devinit cg14_probe(struct of_device *op, const struct of_device_id 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); if (!strcmp(dp->parent->name, "sbus") || !strcmp(dp->parent->name, "sbi")) { - par->physbase = op->resource[0].start; + info->fix.smem_start = op->resource[0].start; par->iospace = op->resource[0].flags & IORESOURCE_BITS; } else { - par->physbase = op->resource[1].start; + info->fix.smem_start = op->resource[1].start; par->iospace = op->resource[0].flags & IORESOURCE_BITS; } @@ -507,7 +506,7 @@ static int __devinit cg14_probe(struct of_device *op, const struct of_device_id sizeof(struct cg14_cursor), "cg14 cursor"); info->screen_base = of_ioremap(&op->resource[1], 0, - par->fbsize, "cg14 ram"); + info->fix.smem_len, "cg14 ram"); if (!par->regs || !par->clut || !par->cursor || !info->screen_base) goto out_unmap_regs; @@ -557,7 +556,7 @@ static int __devinit cg14_probe(struct of_device *op, const struct of_device_id printk(KERN_INFO "%s: cgfourteen at %lx:%lx, %dMB\n", dp->full_name, - par->iospace, par->physbase, + par->iospace, info->fix.smem_start, par->ramsize >> 20); return 0; diff --git a/drivers/video/cg3.c b/drivers/video/cg3.c index 99f87fb61d05..b2319fa7286f 100644 --- a/drivers/video/cg3.c +++ b/drivers/video/cg3.c @@ -118,9 +118,7 @@ struct cg3_par { #define CG3_FLAG_BLANKED 0x00000001 #define CG3_FLAG_RDI 0x00000002 - unsigned long physbase; unsigned long which_io; - unsigned long fbsize; }; /** @@ -231,17 +229,15 @@ static int cg3_mmap(struct fb_info *info, struct vm_area_struct *vma) struct cg3_par *par = (struct cg3_par *)info->par; return sbusfb_mmap_helper(cg3_mmap_map, - par->physbase, par->fbsize, + info->fix.smem_start, info->fix.smem_len, par->which_io, vma); } static int cg3_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) { - struct cg3_par *par = (struct cg3_par *) info->par; - return sbusfb_ioctl_helper(cmd, arg, info, - FBTYPE_SUN3COLOR, 8, par->fbsize); + FBTYPE_SUN3COLOR, 8, info->fix.smem_len); } /* @@ -368,7 +364,7 @@ static int __devinit cg3_probe(struct of_device *op, spin_lock_init(&par->lock); - par->physbase = op->resource[0].start; + info->fix.smem_start = op->resource[0].start; par->which_io = op->resource[0].flags & IORESOURCE_BITS; sbusfb_fill_var(&info->var, dp, 8); @@ -382,7 +378,7 @@ static int __devinit cg3_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->regs = of_ioremap(&op->resource[0], CG3_REGS_OFFSET, sizeof(struct cg3_regs), "cg3 regs"); @@ -392,7 +388,7 @@ static int __devinit cg3_probe(struct of_device *op, info->flags = FBINFO_DEFAULT; info->fbops = &cg3_ops; info->screen_base = of_ioremap(&op->resource[0], CG3_RAM_OFFSET, - par->fbsize, "cg3 ram"); + info->fix.smem_len, "cg3 ram"); if (!info->screen_base) goto out_unmap_regs; @@ -418,7 +414,7 @@ static int __devinit cg3_probe(struct of_device *op, dev_set_drvdata(&op->dev, info); printk(KERN_INFO "%s: cg3 at %lx:%lx\n", - dp->full_name, par->which_io, par->physbase); + dp->full_name, par->which_io, info->fix.smem_start); return 0; @@ -426,7 +422,7 @@ out_dealloc_cmap: fb_dealloc_cmap(&info->cmap); out_unmap_screen: - of_iounmap(&op->resource[0], info->screen_base, par->fbsize); + of_iounmap(&op->resource[0], info->screen_base, info->fix.smem_len); out_unmap_regs: of_iounmap(&op->resource[0], par->regs, sizeof(struct cg3_regs)); @@ -447,7 +443,7 @@ static int __devexit cg3_remove(struct of_device *op) fb_dealloc_cmap(&info->cmap); of_iounmap(&op->resource[0], par->regs, sizeof(struct cg3_regs)); - of_iounmap(&op->resource[0], info->screen_base, par->fbsize); + of_iounmap(&op->resource[0], info->screen_base, info->fix.smem_len); framebuffer_release(info); diff --git a/drivers/video/cg6.c b/drivers/video/cg6.c index 940ec04f0f1b..0d47c6030e3d 100644 --- a/drivers/video/cg6.c +++ b/drivers/video/cg6.c @@ -263,9 +263,7 @@ struct cg6_par { u32 flags; #define CG6_FLAG_BLANKED 0x00000001 - unsigned long physbase; unsigned long which_io; - unsigned long fbsize; }; static int cg6_sync(struct fb_info *info) @@ -596,16 +594,14 @@ static int cg6_mmap(struct fb_info *info, struct vm_area_struct *vma) struct cg6_par *par = (struct cg6_par *)info->par; return sbusfb_mmap_helper(cg6_mmap_map, - par->physbase, par->fbsize, + info->fix.smem_start, info->fix.smem_len, par->which_io, vma); } static int cg6_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) { - struct cg6_par *par = (struct cg6_par *)info->par; - return sbusfb_ioctl_helper(cmd, arg, info, - FBTYPE_SUNFAST_COLOR, 8, par->fbsize); + FBTYPE_SUNFAST_COLOR, 8, info->fix.smem_len); } /* @@ -631,12 +627,12 @@ static void __devinit cg6_init_fix(struct fb_info *info, int linebytes) break; }; if (((conf >> CG6_FHC_REV_SHIFT) & CG6_FHC_REV_MASK) >= 11) { - if (par->fbsize <= 0x100000) + if (info->fix.smem_len <= 0x100000) cg6_card_name = "TGX"; else cg6_card_name = "TGX+"; } else { - if (par->fbsize <= 0x100000) + if (info->fix.smem_len <= 0x100000) cg6_card_name = "GX"; else cg6_card_name = "GX+"; @@ -738,7 +734,8 @@ static void cg6_unmap_regs(struct of_device *op, struct fb_info *info, of_iounmap(&op->resource[0], par->fhc, sizeof(u32)); if (info->screen_base) - of_iounmap(&op->resource[0], info->screen_base, par->fbsize); + of_iounmap(&op->resource[0], info->screen_base, + info->fix.smem_len); } static int __devinit cg6_probe(struct of_device *op, @@ -759,7 +756,7 @@ static int __devinit cg6_probe(struct of_device *op, spin_lock_init(&par->lock); - par->physbase = op->resource[0].start; + info->fix.smem_start = op->resource[0].start; par->which_io = op->resource[0].flags & IORESOURCE_BITS; sbusfb_fill_var(&info->var, dp, 8); @@ -769,11 +766,11 @@ static int __devinit cg6_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); dblbuf = of_getintprop_default(dp, "dblbuf", 0); if (dblbuf) - par->fbsize *= 4; + info->fix.smem_len *= 4; par->fbc = of_ioremap(&op->resource[0], CG6_FBC_OFFSET, 4096, "cgsix fbc"); @@ -792,7 +789,7 @@ static int __devinit cg6_probe(struct of_device *op, info->fbops = &cg6_ops; info->screen_base = of_ioremap(&op->resource[0], CG6_RAM_OFFSET, - par->fbsize, "cgsix ram"); + info->fix.smem_len, "cgsix ram"); if (!par->fbc || !par->tec || !par->thc || !par->bt || !par->fhc || !info->screen_base) goto out_unmap_regs; @@ -817,7 +814,7 @@ static int __devinit cg6_probe(struct of_device *op, printk(KERN_INFO "%s: CGsix [%s] at %lx:%lx\n", dp->full_name, info->fix.id, - par->which_io, par->physbase); + par->which_io, info->fix.smem_start); return 0; diff --git a/drivers/video/chipsfb.c b/drivers/video/chipsfb.c index 777389c40988..57b9d276497e 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/console/vgacon.c b/drivers/video/console/vgacon.c index 38e86b84dce0..59d7d5ec17a4 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -180,7 +180,7 @@ static inline void vga_set_mem_top(struct vc_data *c) } #ifdef CONFIG_VGACON_SOFT_SCROLLBACK -#include <linux/bootmem.h> +#include <linux/slab.h> /* software scrollback */ static void *vgacon_scrollback; static int vgacon_scrollback_tail; @@ -210,8 +210,7 @@ static void vgacon_scrollback_init(int pitch) */ static void __init_refok vgacon_scrollback_startup(void) { - vgacon_scrollback = alloc_bootmem(CONFIG_VGACON_SOFT_SCROLLBACK_SIZE - * 1024); + vgacon_scrollback = kcalloc(CONFIG_VGACON_SOFT_SCROLLBACK_SIZE, 1024, GFP_NOWAIT); vgacon_scrollback_init(vga_video_num_columns * 2); } diff --git a/drivers/video/cyber2000fb.c b/drivers/video/cyber2000fb.c index 83c5cefc266c..da7c01b39be2 100644 --- a/drivers/video/cyber2000fb.c +++ b/drivers/video/cyber2000fb.c @@ -1736,10 +1736,8 @@ static int __init cyber2000fb_init(void) #ifdef CONFIG_ARCH_SHARK err = cyberpro_vl_probe(); - if (!err) { + if (!err) ret = 0; - __module_get(THIS_MODULE); - } #endif #ifdef CONFIG_PCI err = pci_register_driver(&cyberpro_driver); @@ -1749,14 +1747,15 @@ static int __init cyber2000fb_init(void) return ret ? err : 0; } +module_init(cyber2000fb_init); +#ifndef CONFIG_ARCH_SHARK static void __exit cyberpro_exit(void) { pci_unregister_driver(&cyberpro_driver); } - -module_init(cyber2000fb_init); module_exit(cyberpro_exit); +#endif MODULE_AUTHOR("Russell King"); MODULE_DESCRIPTION("CyberPro 2000, 2010 and 5000 framebuffer driver"); 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) 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 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) 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/hitfb.c b/drivers/video/hitfb.c index e6467cf9f19f..020db7fc9153 100644 --- a/drivers/video/hitfb.c +++ b/drivers/video/hitfb.c @@ -335,9 +335,9 @@ static int __init hitfb_probe(struct platform_device *dev) if (fb_get_options("hitfb", NULL)) return -ENODEV; - hitfb_fix.mmio_start = CONFIG_HD64461_IOBASE+0x1000; + hitfb_fix.mmio_start = HD64461_IO_OFFSET(0x1000); hitfb_fix.mmio_len = 0x1000; - hitfb_fix.smem_start = CONFIG_HD64461_IOBASE + 0x02000000; + hitfb_fix.smem_start = HD64461_IO_OFFSET(0x02000000); hitfb_fix.smem_len = 512 * 1024; lcdclor = fb_readw(HD64461_LCDCLOR); diff --git a/drivers/video/igafb.c b/drivers/video/igafb.c index 3a81060137a2..15d200109446 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 ace14fe02fc4..0cafd642fbc0 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/leo.c b/drivers/video/leo.c index 7c7e8c2da9d9..e145e2d16fe3 100644 --- a/drivers/video/leo.c +++ b/drivers/video/leo.c @@ -191,9 +191,7 @@ struct leo_par { u32 flags; #define LEO_FLAG_BLANKED 0x00000001 - unsigned long physbase; unsigned long which_io; - unsigned long fbsize; }; static void leo_wait(struct leo_lx_krn __iomem *lx_krn) @@ -420,16 +418,14 @@ static int leo_mmap(struct fb_info *info, struct vm_area_struct *vma) struct leo_par *par = (struct leo_par *)info->par; return sbusfb_mmap_helper(leo_mmap_map, - par->physbase, par->fbsize, + info->fix.smem_start, info->fix.smem_len, par->which_io, vma); } static int leo_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) { - struct leo_par *par = (struct leo_par *) info->par; - return sbusfb_ioctl_helper(cmd, arg, info, - FBTYPE_SUNLEO, 32, par->fbsize); + FBTYPE_SUNLEO, 32, info->fix.smem_len); } /* @@ -569,7 +565,7 @@ static int __devinit leo_probe(struct of_device *op, spin_lock_init(&par->lock); - par->physbase = op->resource[0].start; + info->fix.smem_start = op->resource[0].start; par->which_io = op->resource[0].flags & IORESOURCE_BITS; sbusfb_fill_var(&info->var, dp, 32); @@ -577,7 +573,7 @@ static int __devinit leo_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->lc_ss0_usr = of_ioremap(&op->resource[0], LEO_OFF_LC_SS0_USR, @@ -627,7 +623,7 @@ static int __devinit leo_probe(struct of_device *op, printk(KERN_INFO "%s: leo at %lx:%lx\n", dp->full_name, - par->which_io, par->physbase); + par->which_io, info->fix.smem_start); return 0; diff --git a/drivers/video/logo/Makefile b/drivers/video/logo/Makefile index b91251d1fe41..3b437813584c 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 2e85a2b52d05..ea7a8ccc830c 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 fb64234a3825..a28e3cfbbf70 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 16186240c5f2..34e4e7995169 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/mx3fb.c b/drivers/video/mx3fb.c index 9894de1c9b9f..b7af5256e887 100644 --- a/drivers/video/mx3fb.c +++ b/drivers/video/mx3fb.c @@ -706,7 +706,7 @@ static void mx3fb_dma_done(void *arg) dev_dbg(mx3fb->dev, "irq %d callback\n", ichannel->eof_irq); /* We only need one interrupt, it will be re-enabled as needed */ - disable_irq(ichannel->eof_irq); + disable_irq_nosync(ichannel->eof_irq); complete(&mx3_fbi->flip_cmpl); } @@ -1366,7 +1366,7 @@ static int init_fb_chan(struct mx3fb_data *mx3fb, struct idmac_channel *ichan) mx3fb_blank(FB_BLANK_UNBLANK, fbi); - dev_info(dev, "mx3fb: fb registered, using mode %s\n", fb_mode); + dev_info(dev, "registered, using mode %s\n", fb_mode); ret = register_framebuffer(fbi); if (ret < 0) diff --git a/drivers/video/offb.c b/drivers/video/offb.c index e1d9eeb1aeaf..4d8c54c23dd7 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/omap/dispc.c b/drivers/video/omap/dispc.c index dfb72f5e4c96..148cbcc39602 100644 --- a/drivers/video/omap/dispc.c +++ b/drivers/video/omap/dispc.c @@ -880,20 +880,22 @@ static irqreturn_t omap_dispc_irq_handler(int irq, void *dev) static int get_dss_clocks(void) { - if (IS_ERR((dispc.dss_ick = clk_get(dispc.fbdev->dev, "dss_ick")))) { - dev_err(dispc.fbdev->dev, "can't get dss_ick\n"); + dispc.dss_ick = clk_get(dispc.fbdev->dev, "ick"); + if (IS_ERR(dispc.dss_ick)) { + dev_err(dispc.fbdev->dev, "can't get ick\n"); return PTR_ERR(dispc.dss_ick); } - if (IS_ERR((dispc.dss1_fck = clk_get(dispc.fbdev->dev, "dss1_fck")))) { + dispc.dss1_fck = clk_get(dispc.fbdev->dev, "dss1_fck"); + if (IS_ERR(dispc.dss1_fck)) { dev_err(dispc.fbdev->dev, "can't get dss1_fck\n"); clk_put(dispc.dss_ick); return PTR_ERR(dispc.dss1_fck); } - if (IS_ERR((dispc.dss_54m_fck = - clk_get(dispc.fbdev->dev, "dss_54m_fck")))) { - dev_err(dispc.fbdev->dev, "can't get dss_54m_fck\n"); + dispc.dss_54m_fck = clk_get(dispc.fbdev->dev, "tv_fck"); + if (IS_ERR(dispc.dss_54m_fck)) { + dev_err(dispc.fbdev->dev, "can't get tv_fck\n"); clk_put(dispc.dss_ick); clk_put(dispc.dss1_fck); return PTR_ERR(dispc.dss_54m_fck); diff --git a/drivers/video/omap/hwa742.c b/drivers/video/omap/hwa742.c index 8aa6e47202b9..5d4f34887a22 100644 --- a/drivers/video/omap/hwa742.c +++ b/drivers/video/omap/hwa742.c @@ -133,8 +133,7 @@ struct { struct lcd_ctrl_extif *extif; struct lcd_ctrl *int_ctrl; - void (*power_up)(struct device *dev); - void (*power_down)(struct device *dev); + struct clk *sys_ck; } hwa742; struct lcd_ctrl hwa742_ctrl; @@ -915,14 +914,13 @@ static void hwa742_suspend(void) hwa742_set_update_mode(OMAPFB_UPDATE_DISABLED); /* Enable sleep mode */ hwa742_write_reg(HWA742_POWER_SAVE, 1 << 1); - if (hwa742.power_down != NULL) - hwa742.power_down(hwa742.fbdev->dev); + clk_disable(hwa742.sys_ck); } static void hwa742_resume(void) { - if (hwa742.power_up != NULL) - hwa742.power_up(hwa742.fbdev->dev); + clk_enable(hwa742.sys_ck); + /* Disable sleep mode */ hwa742_write_reg(HWA742_POWER_SAVE, 0); while (1) { @@ -955,14 +953,13 @@ static int hwa742_init(struct omapfb_device *fbdev, int ext_mode, omapfb_conf = fbdev->dev->platform_data; ctrl_conf = omapfb_conf->ctrl_platform_data; - if (ctrl_conf == NULL || ctrl_conf->get_clock_rate == NULL) { + if (ctrl_conf == NULL) { dev_err(fbdev->dev, "HWA742: missing platform data\n"); r = -ENOENT; goto err1; } - hwa742.power_down = ctrl_conf->power_down; - hwa742.power_up = ctrl_conf->power_up; + hwa742.sys_ck = clk_get(NULL, "hwa_sys_ck"); spin_lock_init(&hwa742.req_lock); @@ -972,12 +969,11 @@ static int hwa742_init(struct omapfb_device *fbdev, int ext_mode, if ((r = hwa742.extif->init(fbdev)) < 0) goto err2; - ext_clk = ctrl_conf->get_clock_rate(fbdev->dev); + ext_clk = clk_get_rate(hwa742.sys_ck); if ((r = calc_extif_timings(ext_clk, &extif_mem_div)) < 0) goto err3; hwa742.extif->set_timings(&hwa742.reg_timings); - if (hwa742.power_up != NULL) - hwa742.power_up(fbdev->dev); + clk_enable(hwa742.sys_ck); calc_hwa742_clk_rates(ext_clk, &sys_clk, &pix_clk); if ((r = calc_extif_timings(sys_clk, &extif_mem_div)) < 0) @@ -1040,8 +1036,7 @@ static int hwa742_init(struct omapfb_device *fbdev, int ext_mode, return 0; err4: - if (hwa742.power_down != NULL) - hwa742.power_down(fbdev->dev); + clk_disable(hwa742.sys_ck); err3: hwa742.extif->cleanup(); err2: @@ -1055,8 +1050,7 @@ static void hwa742_cleanup(void) hwa742_set_update_mode(OMAPFB_UPDATE_DISABLED); hwa742.extif->cleanup(); hwa742.int_ctrl->cleanup(); - if (hwa742.power_down != NULL) - hwa742.power_down(hwa742.fbdev->dev); + clk_disable(hwa742.sys_ck); } struct lcd_ctrl hwa742_ctrl = { diff --git a/drivers/video/omap/rfbi.c b/drivers/video/omap/rfbi.c index a13c8dcad2a8..9332d6ca6456 100644 --- a/drivers/video/omap/rfbi.c +++ b/drivers/video/omap/rfbi.c @@ -83,12 +83,14 @@ static inline u32 rfbi_read_reg(int idx) static int rfbi_get_clocks(void) { - if (IS_ERR((rfbi.dss_ick = clk_get(rfbi.fbdev->dev, "dss_ick")))) { - dev_err(rfbi.fbdev->dev, "can't get dss_ick\n"); + rfbi.dss_ick = clk_get(rfbi.fbdev->dev, "ick"); + if (IS_ERR(rfbi.dss_ick)) { + dev_err(rfbi.fbdev->dev, "can't get ick\n"); return PTR_ERR(rfbi.dss_ick); } - if (IS_ERR((rfbi.dss1_fck = clk_get(rfbi.fbdev->dev, "dss1_fck")))) { + rfbi.dss1_fck = clk_get(rfbi.fbdev->dev, "dss1_fck"); + if (IS_ERR(rfbi.dss1_fck)) { dev_err(rfbi.fbdev->dev, "can't get dss1_fck\n"); clk_put(rfbi.dss_ick); return PTR_ERR(rfbi.dss1_fck); diff --git a/drivers/video/p9100.c b/drivers/video/p9100.c index 7000f2cd5854..7fa4ab01b0d3 100644 --- a/drivers/video/p9100.c +++ b/drivers/video/p9100.c @@ -134,9 +134,7 @@ struct p9100_par { u32 flags; #define P9100_FLAG_BLANKED 0x00000001 - unsigned long physbase; unsigned long which_io; - unsigned long fbsize; }; /** @@ -224,18 +222,16 @@ static int p9100_mmap(struct fb_info *info, struct vm_area_struct *vma) struct p9100_par *par = (struct p9100_par *)info->par; return sbusfb_mmap_helper(p9100_mmap_map, - par->physbase, par->fbsize, + info->fix.smem_start, info->fix.smem_len, par->which_io, vma); } static int p9100_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) { - struct p9100_par *par = (struct p9100_par *) info->par; - /* Make it look like a cg3. */ return sbusfb_ioctl_helper(cmd, arg, info, - FBTYPE_SUN3COLOR, 8, par->fbsize); + FBTYPE_SUN3COLOR, 8, info->fix.smem_len); } /* @@ -271,7 +267,7 @@ static int __devinit p9100_probe(struct of_device *op, const struct of_device_id spin_lock_init(&par->lock); /* This is the framebuffer and the only resource apps can mmap. */ - par->physbase = op->resource[2].start; + info->fix.smem_start = op->resource[2].start; par->which_io = op->resource[2].flags & IORESOURCE_BITS; sbusfb_fill_var(&info->var, dp, 8); @@ -280,7 +276,7 @@ static int __devinit p9100_probe(struct of_device *op, const struct of_device_id info->var.blue.length = 8; 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->regs = of_ioremap(&op->resource[0], 0, sizeof(struct p9100_regs), "p9100 regs"); @@ -290,7 +286,7 @@ static int __devinit p9100_probe(struct of_device *op, const struct of_device_id info->flags = FBINFO_DEFAULT; info->fbops = &p9100_ops; info->screen_base = of_ioremap(&op->resource[2], 0, - par->fbsize, "p9100 ram"); + info->fix.smem_len, "p9100 ram"); if (!info->screen_base) goto out_unmap_regs; @@ -311,7 +307,7 @@ static int __devinit p9100_probe(struct of_device *op, const struct of_device_id printk(KERN_INFO "%s: p9100 at %lx:%lx\n", dp->full_name, - par->which_io, par->physbase); + par->which_io, info->fix.smem_start); return 0; @@ -319,7 +315,7 @@ out_dealloc_cmap: fb_dealloc_cmap(&info->cmap); out_unmap_screen: - of_iounmap(&op->resource[2], info->screen_base, par->fbsize); + of_iounmap(&op->resource[2], info->screen_base, info->fix.smem_len); out_unmap_regs: of_iounmap(&op->resource[0], par->regs, sizeof(struct p9100_regs)); @@ -340,7 +336,7 @@ static int __devexit p9100_remove(struct of_device *op) fb_dealloc_cmap(&info->cmap); of_iounmap(&op->resource[0], par->regs, sizeof(struct p9100_regs)); - of_iounmap(&op->resource[2], info->screen_base, par->fbsize); + of_iounmap(&op->resource[2], info->screen_base, info->fix.smem_len); framebuffer_release(info); diff --git a/drivers/video/pm2fb.c b/drivers/video/pm2fb.c index c6dd924976a4..36436ee6c1a4 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/ps3fb.c b/drivers/video/ps3fb.c index e00c1dff55de..c0af638fe702 100644 --- a/drivers/video/ps3fb.c +++ b/drivers/video/ps3fb.c @@ -32,25 +32,16 @@ #include <linux/init.h> #include <asm/abs_addr.h> +#include <asm/iommu.h> #include <asm/lv1call.h> #include <asm/ps3av.h> #include <asm/ps3fb.h> #include <asm/ps3.h> +#include <asm/ps3gpu.h> #define DEVICE_NAME "ps3fb" -#define L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC 0x101 -#define L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP 0x102 -#define L1GPU_CONTEXT_ATTRIBUTE_FB_SETUP 0x600 -#define L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT 0x601 -#define L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT_SYNC 0x602 - -#define L1GPU_FB_BLIT_WAIT_FOR_COMPLETION (1ULL << 32) - -#define L1GPU_DISPLAY_SYNC_HSYNC 1 -#define L1GPU_DISPLAY_SYNC_VSYNC 2 - #define GPU_CMD_BUF_SIZE (2 * 1024 * 1024) #define GPU_FB_START (64 * 1024) #define GPU_IOIF (0x0d000000UL) @@ -462,33 +453,27 @@ static void ps3fb_sync_image(struct device *dev, u64 frame_offset, src_offset += GPU_FB_START; mutex_lock(&ps3_gpu_mutex); - status = lv1_gpu_context_attribute(ps3fb.context_handle, - L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT, - dst_offset, GPU_IOIF + src_offset, - L1GPU_FB_BLIT_WAIT_FOR_COMPLETION | - (width << 16) | height, - line_length); + status = lv1_gpu_fb_blit(ps3fb.context_handle, dst_offset, + GPU_IOIF + src_offset, + L1GPU_FB_BLIT_WAIT_FOR_COMPLETION | + (width << 16) | height, + line_length); mutex_unlock(&ps3_gpu_mutex); if (status) - dev_err(dev, - "%s: lv1_gpu_context_attribute FB_BLIT failed: %d\n", - __func__, status); + dev_err(dev, "%s: lv1_gpu_fb_blit failed: %d\n", __func__, + status); #ifdef HEAD_A - status = lv1_gpu_context_attribute(ps3fb.context_handle, - L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP, - 0, frame_offset, 0, 0); + status = lv1_gpu_display_flip(ps3fb.context_handle, 0, frame_offset); if (status) - dev_err(dev, "%s: lv1_gpu_context_attribute FLIP failed: %d\n", - __func__, status); + dev_err(dev, "%s: lv1_gpu_display_flip failed: %d\n", __func__, + status); #endif #ifdef HEAD_B - status = lv1_gpu_context_attribute(ps3fb.context_handle, - L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP, - 1, frame_offset, 0, 0); + status = lv1_gpu_display_flip(ps3fb.context_handle, 1, frame_offset); if (status) - dev_err(dev, "%s: lv1_gpu_context_attribute FLIP failed: %d\n", - __func__, status); + dev_err(dev, "%s: lv1_gpu_display_flip failed: %d\n", __func__, + status); #endif } @@ -956,73 +941,6 @@ static irqreturn_t ps3fb_vsync_interrupt(int irq, void *ptr) } -static int ps3fb_vsync_settings(struct gpu_driver_info *dinfo, - struct device *dev) -{ - int error; - - dev_dbg(dev, "version_driver:%x\n", dinfo->version_driver); - dev_dbg(dev, "irq outlet:%x\n", dinfo->irq.irq_outlet); - dev_dbg(dev, - "version_gpu: %x memory_size: %x ch: %x core_freq: %d " - "mem_freq:%d\n", - dinfo->version_gpu, dinfo->memory_size, dinfo->hardware_channel, - dinfo->nvcore_frequency/1000000, dinfo->memory_frequency/1000000); - - if (dinfo->version_driver != GPU_DRIVER_INFO_VERSION) { - dev_err(dev, "%s: version_driver err:%x\n", __func__, - dinfo->version_driver); - return -EINVAL; - } - - error = ps3_irq_plug_setup(PS3_BINDING_CPU_ANY, dinfo->irq.irq_outlet, - &ps3fb.irq_no); - if (error) { - dev_err(dev, "%s: ps3_alloc_irq failed %d\n", __func__, error); - return error; - } - - error = request_irq(ps3fb.irq_no, ps3fb_vsync_interrupt, IRQF_DISABLED, - DEVICE_NAME, dev); - if (error) { - dev_err(dev, "%s: request_irq failed %d\n", __func__, error); - ps3_irq_plug_destroy(ps3fb.irq_no); - return error; - } - - dinfo->irq.mask = (1 << GPU_INTR_STATUS_VSYNC_1) | - (1 << GPU_INTR_STATUS_FLIP_1); - return 0; -} - -static int ps3fb_xdr_settings(u64 xdr_lpar, struct device *dev) -{ - int status; - - status = lv1_gpu_context_iomap(ps3fb.context_handle, GPU_IOIF, - xdr_lpar, ps3fb_videomemory.size, 0); - if (status) { - dev_err(dev, "%s: lv1_gpu_context_iomap failed: %d\n", - __func__, status); - return -ENXIO; - } - dev_dbg(dev, "video:%p ioif:%lx lpar:%llx size:%lx\n", - ps3fb_videomemory.address, GPU_IOIF, xdr_lpar, - ps3fb_videomemory.size); - - status = lv1_gpu_context_attribute(ps3fb.context_handle, - L1GPU_CONTEXT_ATTRIBUTE_FB_SETUP, - xdr_lpar, GPU_CMD_BUF_SIZE, - GPU_IOIF, 0); - if (status) { - dev_err(dev, - "%s: lv1_gpu_context_attribute FB_SETUP failed: %d\n", - __func__, status); - return -ENXIO; - } - return 0; -} - static struct fb_ops ps3fb_ops = { .fb_open = ps3fb_open, .fb_release = ps3fb_release, @@ -1048,49 +966,18 @@ static struct fb_fix_screeninfo ps3fb_fix __initdata = { .accel = FB_ACCEL_NONE, }; -static int ps3fb_set_sync(struct device *dev) -{ - int status; - -#ifdef HEAD_A - status = lv1_gpu_context_attribute(0x0, - L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC, - 0, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0); - if (status) { - dev_err(dev, - "%s: lv1_gpu_context_attribute DISPLAY_SYNC failed: " - "%d\n", - __func__, status); - return -1; - } -#endif -#ifdef HEAD_B - status = lv1_gpu_context_attribute(0x0, - L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC, - 1, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0); - - if (status) { - dev_err(dev, - "%s: lv1_gpu_context_attribute DISPLAY_SYNC failed: " - "%d\n", - __func__, status); - return -1; - } -#endif - return 0; -} - static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) { struct fb_info *info; struct ps3fb_par *par; - int retval = -ENOMEM; + int retval; u64 ddr_lpar = 0; u64 lpar_dma_control = 0; u64 lpar_driver_info = 0; u64 lpar_reports = 0; u64 lpar_reports_size = 0; u64 xdr_lpar; + struct gpu_driver_info *dinfo; void *fb_start; int status; struct task_struct *task; @@ -1101,8 +988,8 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) return -ENOMEM; } - status = ps3_open_hv_device(dev); - if (status) { + retval = ps3_open_hv_device(dev); + if (retval) { dev_err(&dev->core, "%s: ps3_open_hv_device failed\n", __func__); goto err; @@ -1116,7 +1003,24 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) atomic_set(&ps3fb.ext_flip, 0); /* for flip with vsync */ init_waitqueue_head(&ps3fb.wait_vsync); - ps3fb_set_sync(&dev->core); +#ifdef HEAD_A + status = lv1_gpu_display_sync(0x0, 0, L1GPU_DISPLAY_SYNC_VSYNC); + if (status) { + dev_err(&dev->core, "%s: lv1_gpu_display_sync failed: %d\n", + __func__, status); + retval = -ENODEV; + goto err_close_device; + } +#endif +#ifdef HEAD_B + status = lv1_gpu_display_sync(0x0, 1, L1GPU_DISPLAY_SYNC_VSYNC); + if (status) { + dev_err(&dev->core, "%s: lv1_gpu_display_sync failed: %d\n", + __func__, status); + retval = -ENODEV; + goto err_close_device; + } +#endif max_ps3fb_size = _ALIGN_UP(GPU_IOIF, 256*1024*1024) - GPU_IOIF; if (ps3fb_videomemory.size > max_ps3fb_size) { @@ -1131,7 +1035,7 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) if (status) { dev_err(&dev->core, "%s: lv1_gpu_memory_allocate failed: %d\n", __func__, status); - goto err; + goto err_close_device; } dev_dbg(&dev->core, "ddr:lpar:0x%llx\n", ddr_lpar); @@ -1141,33 +1045,85 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) &lpar_reports, &lpar_reports_size); if (status) { dev_err(&dev->core, - "%s: lv1_gpu_context_attribute failed: %d\n", __func__, + "%s: lv1_gpu_context_allocate failed: %d\n", __func__, status); goto err_gpu_memory_free; } /* vsync interrupt */ - ps3fb.dinfo = (void __force *)ioremap(lpar_driver_info, 128 * 1024); - if (!ps3fb.dinfo) { + dinfo = (void __force *)ioremap(lpar_driver_info, 128 * 1024); + if (!dinfo) { dev_err(&dev->core, "%s: ioremap failed\n", __func__); goto err_gpu_context_free; } - retval = ps3fb_vsync_settings(ps3fb.dinfo, &dev->core); - if (retval) + ps3fb.dinfo = dinfo; + dev_dbg(&dev->core, "version_driver:%x\n", dinfo->version_driver); + dev_dbg(&dev->core, "irq outlet:%x\n", dinfo->irq.irq_outlet); + dev_dbg(&dev->core, "version_gpu: %x memory_size: %x ch: %x " + "core_freq: %d mem_freq:%d\n", dinfo->version_gpu, + dinfo->memory_size, dinfo->hardware_channel, + dinfo->nvcore_frequency/1000000, + dinfo->memory_frequency/1000000); + + if (dinfo->version_driver != GPU_DRIVER_INFO_VERSION) { + dev_err(&dev->core, "%s: version_driver err:%x\n", __func__, + dinfo->version_driver); + retval = -EINVAL; + goto err_iounmap_dinfo; + } + + retval = ps3_irq_plug_setup(PS3_BINDING_CPU_ANY, dinfo->irq.irq_outlet, + &ps3fb.irq_no); + if (retval) { + dev_err(&dev->core, "%s: ps3_alloc_irq failed %d\n", __func__, + retval); goto err_iounmap_dinfo; + } + + retval = request_irq(ps3fb.irq_no, ps3fb_vsync_interrupt, + IRQF_DISABLED, DEVICE_NAME, &dev->core); + if (retval) { + dev_err(&dev->core, "%s: request_irq failed %d\n", __func__, + retval); + goto err_destroy_plug; + } + + dinfo->irq.mask = (1 << GPU_INTR_STATUS_VSYNC_1) | + (1 << GPU_INTR_STATUS_FLIP_1); /* Clear memory to prevent kernel info leakage into userspace */ memset(ps3fb_videomemory.address, 0, ps3fb_videomemory.size); xdr_lpar = ps3_mm_phys_to_lpar(__pa(ps3fb_videomemory.address)); - retval = ps3fb_xdr_settings(xdr_lpar, &dev->core); - if (retval) + + status = lv1_gpu_context_iomap(ps3fb.context_handle, GPU_IOIF, + xdr_lpar, ps3fb_videomemory.size, + CBE_IOPTE_PP_W | CBE_IOPTE_PP_R | + CBE_IOPTE_M); + if (status) { + dev_err(&dev->core, "%s: lv1_gpu_context_iomap failed: %d\n", + __func__, status); + retval = -ENXIO; goto err_free_irq; + } + + dev_dbg(&dev->core, "video:%p ioif:%lx lpar:%llx size:%lx\n", + ps3fb_videomemory.address, GPU_IOIF, xdr_lpar, + ps3fb_videomemory.size); + + status = lv1_gpu_fb_setup(ps3fb.context_handle, xdr_lpar, + GPU_CMD_BUF_SIZE, GPU_IOIF); + if (status) { + dev_err(&dev->core, "%s: lv1_gpu_fb_setup failed: %d\n", + __func__, status); + retval = -ENXIO; + goto err_context_unmap; + } info = framebuffer_alloc(sizeof(struct ps3fb_par), &dev->core); if (!info) - goto err_free_irq; + goto err_context_fb_close; par = info->par; par->mode_id = ~ps3fb_mode; /* != ps3fb_mode, to trigger change */ @@ -1210,7 +1166,7 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) if (retval < 0) goto err_fb_dealloc; - dev->core.driver_data = info; + ps3_system_bus_set_drvdata(dev, info); dev_info(info->device, "%s %s, using %u KiB of video memory\n", dev_driver_string(info->dev), dev_name(info->dev), @@ -1232,8 +1188,14 @@ err_fb_dealloc: fb_dealloc_cmap(&info->cmap); err_framebuffer_release: framebuffer_release(info); +err_context_fb_close: + lv1_gpu_fb_close(ps3fb.context_handle); +err_context_unmap: + lv1_gpu_context_iomap(ps3fb.context_handle, GPU_IOIF, xdr_lpar, + ps3fb_videomemory.size, CBE_IOPTE_M); err_free_irq: free_irq(ps3fb.irq_no, &dev->core); +err_destroy_plug: ps3_irq_plug_destroy(ps3fb.irq_no); err_iounmap_dinfo: iounmap((u8 __force __iomem *)ps3fb.dinfo); @@ -1241,14 +1203,16 @@ err_gpu_context_free: lv1_gpu_context_free(ps3fb.context_handle); err_gpu_memory_free: lv1_gpu_memory_free(ps3fb.memory_handle); +err_close_device: + ps3_close_hv_device(dev); err: return retval; } static int ps3fb_shutdown(struct ps3_system_bus_device *dev) { - int status; - struct fb_info *info = dev->core.driver_data; + struct fb_info *info = ps3_system_bus_get_drvdata(dev); + u64 xdr_lpar = ps3_mm_phys_to_lpar(__pa(ps3fb_videomemory.address)); dev_dbg(&dev->core, " -> %s:%d\n", __func__, __LINE__); @@ -1268,20 +1232,14 @@ static int ps3fb_shutdown(struct ps3_system_bus_device *dev) unregister_framebuffer(info); fb_dealloc_cmap(&info->cmap); framebuffer_release(info); - info = dev->core.driver_data = NULL; + ps3_system_bus_set_drvdata(dev, NULL); } iounmap((u8 __force __iomem *)ps3fb.dinfo); - - status = lv1_gpu_context_free(ps3fb.context_handle); - if (status) - dev_dbg(&dev->core, "lv1_gpu_context_free failed: %d\n", - status); - - status = lv1_gpu_memory_free(ps3fb.memory_handle); - if (status) - dev_dbg(&dev->core, "lv1_gpu_memory_free failed: %d\n", - status); - + lv1_gpu_fb_close(ps3fb.context_handle); + lv1_gpu_context_iomap(ps3fb.context_handle, GPU_IOIF, xdr_lpar, + ps3fb_videomemory.size, CBE_IOPTE_M); + lv1_gpu_context_free(ps3fb.context_handle); + lv1_gpu_memory_free(ps3fb.memory_handle); ps3_close_hv_device(dev); dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__); diff --git a/drivers/video/pxa168fb.c b/drivers/video/pxa168fb.c new file mode 100644 index 000000000000..84d8327e47db --- /dev/null +++ b/drivers/video/pxa168fb.c @@ -0,0 +1,803 @@ +/* + * linux/drivers/video/pxa168fb.c -- Marvell PXA168 LCD Controller + * + * Copyright (C) 2008 Marvell International Ltd. + * All rights reserved. + * + * 2009-02-16 adapted from original version for PXA168/910 + * Jun Nie <njun@marvell.com> + * + * 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 + * more details. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/string.h> +#include <linux/interrupt.h> +#include <linux/slab.h> +#include <linux/fb.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/ioport.h> +#include <linux/platform_device.h> +#include <linux/dma-mapping.h> +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/uaccess.h> +#include <video/pxa168fb.h> + +#include "pxa168fb.h" + +#define DEFAULT_REFRESH 60 /* Hz */ + +static int determine_best_pix_fmt(struct fb_var_screeninfo *var) +{ + /* + * Pseudocolor mode? + */ + if (var->bits_per_pixel == 8) + return PIX_FMT_PSEUDOCOLOR; + + /* + * Check for 565/1555. + */ + if (var->bits_per_pixel == 16 && var->red.length <= 5 && + var->green.length <= 6 && var->blue.length <= 5) { + if (var->transp.length == 0) { + if (var->red.offset >= var->blue.offset) + return PIX_FMT_RGB565; + else + return PIX_FMT_BGR565; + } + + if (var->transp.length == 1 && var->green.length <= 5) { + if (var->red.offset >= var->blue.offset) + return PIX_FMT_RGB1555; + else + return PIX_FMT_BGR1555; + } + + /* fall through */ + } + + /* + * Check for 888/A888. + */ + if (var->bits_per_pixel <= 32 && var->red.length <= 8 && + var->green.length <= 8 && var->blue.length <= 8) { + if (var->bits_per_pixel == 24 && var->transp.length == 0) { + if (var->red.offset >= var->blue.offset) + return PIX_FMT_RGB888PACK; + else + return PIX_FMT_BGR888PACK; + } + + if (var->bits_per_pixel == 32 && var->transp.length == 8) { + if (var->red.offset >= var->blue.offset) + return PIX_FMT_RGBA888; + else + return PIX_FMT_BGRA888; + } else { + if (var->red.offset >= var->blue.offset) + return PIX_FMT_RGB888UNPACK; + else + return PIX_FMT_BGR888UNPACK; + } + + /* fall through */ + } + + return -EINVAL; +} + +static void set_pix_fmt(struct fb_var_screeninfo *var, int pix_fmt) +{ + switch (pix_fmt) { + case PIX_FMT_RGB565: + var->bits_per_pixel = 16; + var->red.offset = 11; var->red.length = 5; + var->green.offset = 5; var->green.length = 6; + var->blue.offset = 0; var->blue.length = 5; + var->transp.offset = 0; var->transp.length = 0; + break; + case PIX_FMT_BGR565: + var->bits_per_pixel = 16; + var->red.offset = 0; var->red.length = 5; + var->green.offset = 5; var->green.length = 6; + var->blue.offset = 11; var->blue.length = 5; + var->transp.offset = 0; var->transp.length = 0; + break; + case PIX_FMT_RGB1555: + var->bits_per_pixel = 16; + var->red.offset = 10; var->red.length = 5; + var->green.offset = 5; var->green.length = 5; + var->blue.offset = 0; var->blue.length = 5; + var->transp.offset = 15; var->transp.length = 1; + break; + case PIX_FMT_BGR1555: + var->bits_per_pixel = 16; + var->red.offset = 0; var->red.length = 5; + var->green.offset = 5; var->green.length = 5; + var->blue.offset = 10; var->blue.length = 5; + var->transp.offset = 15; var->transp.length = 1; + break; + case PIX_FMT_RGB888PACK: + var->bits_per_pixel = 24; + var->red.offset = 16; var->red.length = 8; + var->green.offset = 8; var->green.length = 8; + var->blue.offset = 0; var->blue.length = 8; + var->transp.offset = 0; var->transp.length = 0; + break; + case PIX_FMT_BGR888PACK: + var->bits_per_pixel = 24; + var->red.offset = 0; var->red.length = 8; + var->green.offset = 8; var->green.length = 8; + var->blue.offset = 16; var->blue.length = 8; + var->transp.offset = 0; var->transp.length = 0; + break; + case PIX_FMT_RGBA888: + var->bits_per_pixel = 32; + var->red.offset = 16; var->red.length = 8; + var->green.offset = 8; var->green.length = 8; + var->blue.offset = 0; var->blue.length = 8; + var->transp.offset = 24; var->transp.length = 8; + break; + case PIX_FMT_BGRA888: + var->bits_per_pixel = 32; + var->red.offset = 0; var->red.length = 8; + var->green.offset = 8; var->green.length = 8; + var->blue.offset = 16; var->blue.length = 8; + var->transp.offset = 24; var->transp.length = 8; + break; + case PIX_FMT_PSEUDOCOLOR: + var->bits_per_pixel = 8; + var->red.offset = 0; var->red.length = 8; + var->green.offset = 0; var->green.length = 8; + var->blue.offset = 0; var->blue.length = 8; + var->transp.offset = 0; var->transp.length = 0; + break; + } +} + +static void set_mode(struct pxa168fb_info *fbi, struct fb_var_screeninfo *var, + struct fb_videomode *mode, int pix_fmt, int ystretch) +{ + struct fb_info *info = fbi->info; + + set_pix_fmt(var, pix_fmt); + + var->xres = mode->xres; + var->yres = mode->yres; + var->xres_virtual = max(var->xres, var->xres_virtual); + if (ystretch) + var->yres_virtual = info->fix.smem_len / + (var->xres_virtual * (var->bits_per_pixel >> 3)); + else + var->yres_virtual = max(var->yres, var->yres_virtual); + var->grayscale = 0; + var->accel_flags = FB_ACCEL_NONE; + var->pixclock = mode->pixclock; + var->left_margin = mode->left_margin; + var->right_margin = mode->right_margin; + var->upper_margin = mode->upper_margin; + var->lower_margin = mode->lower_margin; + var->hsync_len = mode->hsync_len; + var->vsync_len = mode->vsync_len; + var->sync = mode->sync; + var->vmode = FB_VMODE_NONINTERLACED; + var->rotate = FB_ROTATE_UR; +} + +static int pxa168fb_check_var(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + struct pxa168fb_info *fbi = info->par; + int pix_fmt; + + /* + * Determine which pixel format we're going to use. + */ + pix_fmt = determine_best_pix_fmt(var); + if (pix_fmt < 0) + return pix_fmt; + set_pix_fmt(var, pix_fmt); + fbi->pix_fmt = pix_fmt; + + /* + * Basic geometry sanity checks. + */ + if (var->xoffset + var->xres > var->xres_virtual) + return -EINVAL; + if (var->yoffset + var->yres > var->yres_virtual) + return -EINVAL; + if (var->xres + var->right_margin + + var->hsync_len + var->left_margin > 2048) + return -EINVAL; + if (var->yres + var->lower_margin + + var->vsync_len + var->upper_margin > 2048) + return -EINVAL; + + /* + * Check size of framebuffer. + */ + if (var->xres_virtual * var->yres_virtual * + (var->bits_per_pixel >> 3) > info->fix.smem_len) + return -EINVAL; + + return 0; +} + +/* + * The hardware clock divider has an integer and a fractional + * stage: + * + * clk2 = clk_in / integer_divider + * clk_out = clk2 * (1 - (fractional_divider >> 12)) + * + * Calculate integer and fractional divider for given clk_in + * and clk_out. + */ +static void set_clock_divider(struct pxa168fb_info *fbi, + const struct fb_videomode *m) +{ + int divider_int; + int needed_pixclk; + u64 div_result; + u32 x = 0; + + /* + * Notice: The field pixclock is used by linux fb + * is in pixel second. E.g. struct fb_videomode & + * struct fb_var_screeninfo + */ + + /* + * Check input values. + */ + if (!m || !m->pixclock || !m->refresh) { + dev_err(fbi->dev, "Input refresh or pixclock is wrong.\n"); + return; + } + + /* + * Using PLL/AXI clock. + */ + x = 0x80000000; + + /* + * Calc divider according to refresh rate. + */ + div_result = 1000000000000ll; + do_div(div_result, m->pixclock); + needed_pixclk = (u32)div_result; + + divider_int = clk_get_rate(fbi->clk) / needed_pixclk; + + /* check whether divisor is too small. */ + if (divider_int < 2) { + dev_warn(fbi->dev, "Warning: clock source is too slow." + "Try smaller resolution\n"); + divider_int = 2; + } + + /* + * Set setting to reg. + */ + x |= divider_int; + writel(x, fbi->reg_base + LCD_CFG_SCLK_DIV); +} + +static void set_dma_control0(struct pxa168fb_info *fbi) +{ + u32 x; + + /* + * Set bit to enable graphics DMA. + */ + x = readl(fbi->reg_base + LCD_SPU_DMA_CTRL0); + x |= fbi->active ? 0x00000100 : 0; + fbi->active = 0; + + /* + * If we are in a pseudo-color mode, we need to enable + * palette lookup. + */ + if (fbi->pix_fmt == PIX_FMT_PSEUDOCOLOR) + x |= 0x10000000; + + /* + * Configure hardware pixel format. + */ + x &= ~(0xF << 16); + x |= (fbi->pix_fmt >> 1) << 16; + + /* + * Check red and blue pixel swap. + * 1. source data swap + * 2. panel output data swap + */ + x &= ~(1 << 12); + x |= ((fbi->pix_fmt & 1) ^ (fbi->panel_rbswap)) << 12; + + writel(x, fbi->reg_base + LCD_SPU_DMA_CTRL0); +} + +static void set_dma_control1(struct pxa168fb_info *fbi, int sync) +{ + u32 x; + + /* + * Configure default bits: vsync triggers DMA, gated clock + * enable, power save enable, configure alpha registers to + * display 100% graphics, and set pixel command. + */ + x = readl(fbi->reg_base + LCD_SPU_DMA_CTRL1); + x |= 0x2032ff81; + + /* + * We trigger DMA on the falling edge of vsync if vsync is + * active low, or on the rising edge if vsync is active high. + */ + if (!(sync & FB_SYNC_VERT_HIGH_ACT)) + x |= 0x08000000; + + writel(x, fbi->reg_base + LCD_SPU_DMA_CTRL1); +} + +static void set_graphics_start(struct fb_info *info, int xoffset, int yoffset) +{ + struct pxa168fb_info *fbi = info->par; + struct fb_var_screeninfo *var = &info->var; + int pixel_offset; + unsigned long addr; + + pixel_offset = (yoffset * var->xres_virtual) + xoffset; + + addr = fbi->fb_start_dma + (pixel_offset * (var->bits_per_pixel >> 3)); + writel(addr, fbi->reg_base + LCD_CFG_GRA_START_ADDR0); +} + +static void set_dumb_panel_control(struct fb_info *info) +{ + struct pxa168fb_info *fbi = info->par; + struct pxa168fb_mach_info *mi = fbi->dev->platform_data; + u32 x; + + /* + * Preserve enable flag. + */ + x = readl(fbi->reg_base + LCD_SPU_DUMB_CTRL) & 0x00000001; + + x |= (fbi->is_blanked ? 0x7 : mi->dumb_mode) << 28; + x |= mi->gpio_output_data << 20; + x |= mi->gpio_output_mask << 12; + x |= mi->panel_rgb_reverse_lanes ? 0x00000080 : 0; + x |= mi->invert_composite_blank ? 0x00000040 : 0; + x |= (info->var.sync & FB_SYNC_COMP_HIGH_ACT) ? 0x00000020 : 0; + x |= mi->invert_pix_val_ena ? 0x00000010 : 0; + x |= (info->var.sync & FB_SYNC_VERT_HIGH_ACT) ? 0 : 0x00000008; + x |= (info->var.sync & FB_SYNC_HOR_HIGH_ACT) ? 0 : 0x00000004; + x |= mi->invert_pixclock ? 0x00000002 : 0; + + writel(x, fbi->reg_base + LCD_SPU_DUMB_CTRL); +} + +static void set_dumb_screen_dimensions(struct fb_info *info) +{ + struct pxa168fb_info *fbi = info->par; + struct fb_var_screeninfo *v = &info->var; + int x; + int y; + + x = v->xres + v->right_margin + v->hsync_len + v->left_margin; + y = v->yres + v->lower_margin + v->vsync_len + v->upper_margin; + + writel((y << 16) | x, fbi->reg_base + LCD_SPUT_V_H_TOTAL); +} + +static int pxa168fb_set_par(struct fb_info *info) +{ + struct pxa168fb_info *fbi = info->par; + struct fb_var_screeninfo *var = &info->var; + struct fb_videomode mode; + u32 x; + struct pxa168fb_mach_info *mi; + + mi = fbi->dev->platform_data; + + /* + * Set additional mode info. + */ + if (fbi->pix_fmt == PIX_FMT_PSEUDOCOLOR) + info->fix.visual = FB_VISUAL_PSEUDOCOLOR; + else + info->fix.visual = FB_VISUAL_TRUECOLOR; + info->fix.line_length = var->xres_virtual * var->bits_per_pixel / 8; + info->fix.ypanstep = var->yres; + + /* + * Disable panel output while we setup the display. + */ + x = readl(fbi->reg_base + LCD_SPU_DUMB_CTRL); + writel(x & ~1, fbi->reg_base + LCD_SPU_DUMB_CTRL); + + /* + * Configure global panel parameters. + */ + writel((var->yres << 16) | var->xres, + fbi->reg_base + LCD_SPU_V_H_ACTIVE); + + /* + * convet var to video mode + */ + fb_var_to_videomode(&mode, &info->var); + + /* Calculate clock divisor. */ + set_clock_divider(fbi, &mode); + + /* Configure dma ctrl regs. */ + set_dma_control0(fbi); + set_dma_control1(fbi, info->var.sync); + + /* + * Configure graphics DMA parameters. + */ + x = readl(fbi->reg_base + LCD_CFG_GRA_PITCH); + x = (x & ~0xFFFF) | ((var->xres_virtual * var->bits_per_pixel) >> 3); + writel(x, fbi->reg_base + LCD_CFG_GRA_PITCH); + writel((var->yres << 16) | var->xres, + fbi->reg_base + LCD_SPU_GRA_HPXL_VLN); + writel((var->yres << 16) | var->xres, + fbi->reg_base + LCD_SPU_GZM_HPXL_VLN); + + /* + * Configure dumb panel ctrl regs & timings. + */ + set_dumb_panel_control(info); + set_dumb_screen_dimensions(info); + + writel((var->left_margin << 16) | var->right_margin, + fbi->reg_base + LCD_SPU_H_PORCH); + writel((var->upper_margin << 16) | var->lower_margin, + fbi->reg_base + LCD_SPU_V_PORCH); + + /* + * Re-enable panel output. + */ + x = readl(fbi->reg_base + LCD_SPU_DUMB_CTRL); + writel(x | 1, fbi->reg_base + LCD_SPU_DUMB_CTRL); + + return 0; +} + +static unsigned int chan_to_field(unsigned int chan, struct fb_bitfield *bf) +{ + return ((chan & 0xffff) >> (16 - bf->length)) << bf->offset; +} + +static u32 to_rgb(u16 red, u16 green, u16 blue) +{ + red >>= 8; + green >>= 8; + blue >>= 8; + + return (red << 16) | (green << 8) | blue; +} + +static int +pxa168fb_setcolreg(unsigned int regno, unsigned int red, unsigned int green, + unsigned int blue, unsigned int trans, struct fb_info *info) +{ + struct pxa168fb_info *fbi = info->par; + u32 val; + + if (info->var.grayscale) + red = green = blue = (19595 * red + 38470 * green + + 7471 * blue) >> 16; + + if (info->fix.visual == FB_VISUAL_TRUECOLOR && regno < 16) { + val = chan_to_field(red, &info->var.red); + val |= chan_to_field(green, &info->var.green); + val |= chan_to_field(blue , &info->var.blue); + fbi->pseudo_palette[regno] = val; + } + + if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR && regno < 256) { + val = to_rgb(red, green, blue); + writel(val, fbi->reg_base + LCD_SPU_SRAM_WRDAT); + writel(0x8300 | regno, fbi->reg_base + LCD_SPU_SRAM_CTRL); + } + + return 0; +} + +static int pxa168fb_blank(int blank, struct fb_info *info) +{ + struct pxa168fb_info *fbi = info->par; + + fbi->is_blanked = (blank == FB_BLANK_UNBLANK) ? 0 : 1; + set_dumb_panel_control(info); + + return 0; +} + +static int pxa168fb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + set_graphics_start(info, var->xoffset, var->yoffset); + + return 0; +} + +static irqreturn_t pxa168fb_handle_irq(int irq, void *dev_id) +{ + struct pxa168fb_info *fbi = dev_id; + u32 isr = readl(fbi->reg_base + SPU_IRQ_ISR); + + if ((isr & GRA_FRAME_IRQ0_ENA_MASK)) { + + writel(isr & (~GRA_FRAME_IRQ0_ENA_MASK), + fbi->reg_base + SPU_IRQ_ISR); + + return IRQ_HANDLED; + } + return IRQ_NONE; +} + +static struct fb_ops pxa168fb_ops = { + .owner = THIS_MODULE, + .fb_check_var = pxa168fb_check_var, + .fb_set_par = pxa168fb_set_par, + .fb_setcolreg = pxa168fb_setcolreg, + .fb_blank = pxa168fb_blank, + .fb_pan_display = pxa168fb_pan_display, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, +}; + +static int __init pxa168fb_init_mode(struct fb_info *info, + struct pxa168fb_mach_info *mi) +{ + struct pxa168fb_info *fbi = info->par; + struct fb_var_screeninfo *var = &info->var; + int ret = 0; + u32 total_w, total_h, refresh; + u64 div_result; + const struct fb_videomode *m; + + /* + * Set default value + */ + refresh = DEFAULT_REFRESH; + + /* try to find best video mode. */ + m = fb_find_best_mode(&info->var, &info->modelist); + if (m) + fb_videomode_to_var(&info->var, m); + + /* Init settings. */ + var->xres_virtual = var->xres; + var->yres_virtual = info->fix.smem_len / + (var->xres_virtual * (var->bits_per_pixel >> 3)); + dev_dbg(fbi->dev, "pxa168fb: find best mode: res = %dx%d\n", + var->xres, var->yres); + + /* correct pixclock. */ + total_w = var->xres + var->left_margin + var->right_margin + + var->hsync_len; + total_h = var->yres + var->upper_margin + var->lower_margin + + var->vsync_len; + + div_result = 1000000000000ll; + do_div(div_result, total_w * total_h * refresh); + var->pixclock = (u32)div_result; + + return ret; +} + +static int __init pxa168fb_probe(struct platform_device *pdev) +{ + struct pxa168fb_mach_info *mi; + struct fb_info *info = 0; + struct pxa168fb_info *fbi = 0; + struct resource *res; + struct clk *clk; + int irq, ret; + + mi = pdev->dev.platform_data; + if (mi == NULL) { + dev_err(&pdev->dev, "no platform data defined\n"); + return -EINVAL; + } + + clk = clk_get(&pdev->dev, "LCDCLK"); + if (IS_ERR(clk)) { + dev_err(&pdev->dev, "unable to get LCDCLK"); + return PTR_ERR(clk); + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res == NULL) { + dev_err(&pdev->dev, "no IO memory defined\n"); + return -ENOENT; + } + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "no IRQ defined\n"); + return -ENOENT; + } + + info = framebuffer_alloc(sizeof(struct pxa168fb_info), &pdev->dev); + if (info == NULL) { + clk_put(clk); + return -ENOMEM; + } + + /* Initialize private data */ + fbi = info->par; + fbi->info = info; + fbi->clk = clk; + fbi->dev = info->dev = &pdev->dev; + fbi->panel_rbswap = mi->panel_rbswap; + fbi->is_blanked = 0; + fbi->active = mi->active; + + /* + * Initialise static fb parameters. + */ + info->flags = FBINFO_DEFAULT | FBINFO_PARTIAL_PAN_OK | + FBINFO_HWACCEL_XPAN | FBINFO_HWACCEL_YPAN; + info->node = -1; + strlcpy(info->fix.id, mi->id, 16); + info->fix.type = FB_TYPE_PACKED_PIXELS; + info->fix.type_aux = 0; + info->fix.xpanstep = 0; + info->fix.ypanstep = 0; + info->fix.ywrapstep = 0; + info->fix.mmio_start = res->start; + info->fix.mmio_len = res->end - res->start + 1; + info->fix.accel = FB_ACCEL_NONE; + info->fbops = &pxa168fb_ops; + info->pseudo_palette = fbi->pseudo_palette; + + /* + * Map LCD controller registers. + */ + fbi->reg_base = ioremap_nocache(res->start, res->end - res->start); + if (fbi->reg_base == NULL) { + ret = -ENOMEM; + goto failed; + } + + /* + * Allocate framebuffer memory. + */ + info->fix.smem_len = PAGE_ALIGN(DEFAULT_FB_SIZE); + + info->screen_base = dma_alloc_writecombine(fbi->dev, info->fix.smem_len, + &fbi->fb_start_dma, GFP_KERNEL); + if (info->screen_base == NULL) { + ret = -ENOMEM; + goto failed; + } + + info->fix.smem_start = (unsigned long)fbi->fb_start_dma; + + /* + * Set video mode according to platform data. + */ + set_mode(fbi, &info->var, mi->modes, mi->pix_fmt, 1); + + fb_videomode_to_modelist(mi->modes, mi->num_modes, &info->modelist); + + /* + * init video mode data. + */ + pxa168fb_init_mode(info, mi); + + ret = pxa168fb_check_var(&info->var, info); + if (ret) + goto failed_free_fbmem; + + /* + * Fill in sane defaults. + */ + ret = pxa168fb_check_var(&info->var, info); + if (ret) + goto failed; + + /* + * enable controller clock + */ + clk_enable(fbi->clk); + + pxa168fb_set_par(info); + + /* + * Configure default register values. + */ + writel(0, fbi->reg_base + LCD_SPU_BLANKCOLOR); + writel(mi->io_pin_allocation_mode, fbi->reg_base + SPU_IOPAD_CONTROL); + writel(0, fbi->reg_base + LCD_CFG_GRA_START_ADDR1); + writel(0, fbi->reg_base + LCD_SPU_GRA_OVSA_HPXL_VLN); + writel(0, fbi->reg_base + LCD_SPU_SRAM_PARA0); + writel(CFG_CSB_256x32(0x1)|CFG_CSB_256x24(0x1)|CFG_CSB_256x8(0x1), + fbi->reg_base + LCD_SPU_SRAM_PARA1); + + /* + * Allocate color map. + */ + if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) { + ret = -ENOMEM; + goto failed_free_clk; + } + + /* + * Register irq handler. + */ + ret = request_irq(irq, pxa168fb_handle_irq, IRQF_SHARED, + info->fix.id, fbi); + if (ret < 0) { + dev_err(&pdev->dev, "unable to request IRQ\n"); + ret = -ENXIO; + goto failed_free_cmap; + } + + /* + * Enable GFX interrupt + */ + writel(GRA_FRAME_IRQ0_ENA(0x1), fbi->reg_base + SPU_IRQ_ENA); + + /* + * Register framebuffer. + */ + ret = register_framebuffer(info); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to register pxa168-fb: %d\n", ret); + ret = -ENXIO; + goto failed_free_irq; + } + + platform_set_drvdata(pdev, fbi); + return 0; + +failed_free_irq: + free_irq(irq, fbi); +failed_free_cmap: + fb_dealloc_cmap(&info->cmap); +failed_free_clk: + clk_disable(fbi->clk); +failed_free_fbmem: + dma_free_coherent(fbi->dev, info->fix.smem_len, + info->screen_base, fbi->fb_start_dma); +failed: + kfree(info); + clk_put(clk); + + dev_err(&pdev->dev, "frame buffer device init failed with %d\n", ret); + return ret; +} + +static struct platform_driver pxa168fb_driver = { + .driver = { + .name = "pxa168-fb", + .owner = THIS_MODULE, + }, + .probe = pxa168fb_probe, +}; + +static int __devinit pxa168fb_init(void) +{ + return platform_driver_register(&pxa168fb_driver); +} +module_init(pxa168fb_init); + +MODULE_AUTHOR("Lennert Buytenhek <buytenh@marvell.com> " + "Green Wan <gwan@marvell.com>"); +MODULE_DESCRIPTION("Framebuffer driver for PXA168/910"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/pxa168fb.h b/drivers/video/pxa168fb.h new file mode 100644 index 000000000000..eee09279c524 --- /dev/null +++ b/drivers/video/pxa168fb.h @@ -0,0 +1,558 @@ +#ifndef __PXA168FB_H__ +#define __PXA168FB_H__ + +/* ------------< LCD register >------------ */ +/* Video Frame 0&1 start address registers */ +#define LCD_SPU_DMA_START_ADDR_Y0 0x00C0 +#define LCD_SPU_DMA_START_ADDR_U0 0x00C4 +#define LCD_SPU_DMA_START_ADDR_V0 0x00C8 +#define LCD_CFG_DMA_START_ADDR_0 0x00CC /* Cmd address */ +#define LCD_SPU_DMA_START_ADDR_Y1 0x00D0 +#define LCD_SPU_DMA_START_ADDR_U1 0x00D4 +#define LCD_SPU_DMA_START_ADDR_V1 0x00D8 +#define LCD_CFG_DMA_START_ADDR_1 0x00DC /* Cmd address */ + +/* YC & UV Pitch */ +#define LCD_SPU_DMA_PITCH_YC 0x00E0 +#define SPU_DMA_PITCH_C(c) ((c) << 16) +#define SPU_DMA_PITCH_Y(y) (y) +#define LCD_SPU_DMA_PITCH_UV 0x00E4 +#define SPU_DMA_PITCH_V(v) ((v) << 16) +#define SPU_DMA_PITCH_U(u) (u) + +/* Video Starting Point on Screen Register */ +#define LCD_SPUT_DMA_OVSA_HPXL_VLN 0x00E8 +#define CFG_DMA_OVSA_VLN(y) ((y) << 16) /* 0~0xfff */ +#define CFG_DMA_OVSA_HPXL(x) (x) /* 0~0xfff */ + +/* Video Size Register */ +#define LCD_SPU_DMA_HPXL_VLN 0x00EC +#define CFG_DMA_VLN(y) ((y) << 16) +#define CFG_DMA_HPXL(x) (x) + +/* Video Size After zooming Register */ +#define LCD_SPU_DZM_HPXL_VLN 0x00F0 +#define CFG_DZM_VLN(y) ((y) << 16) +#define CFG_DZM_HPXL(x) (x) + +/* Graphic Frame 0&1 Starting Address Register */ +#define LCD_CFG_GRA_START_ADDR0 0x00F4 +#define LCD_CFG_GRA_START_ADDR1 0x00F8 + +/* Graphic Frame Pitch */ +#define LCD_CFG_GRA_PITCH 0x00FC + +/* Graphic Starting Point on Screen Register */ +#define LCD_SPU_GRA_OVSA_HPXL_VLN 0x0100 +#define CFG_GRA_OVSA_VLN(y) ((y) << 16) +#define CFG_GRA_OVSA_HPXL(x) (x) + +/* Graphic Size Register */ +#define LCD_SPU_GRA_HPXL_VLN 0x0104 +#define CFG_GRA_VLN(y) ((y) << 16) +#define CFG_GRA_HPXL(x) (x) + +/* Graphic Size after Zooming Register */ +#define LCD_SPU_GZM_HPXL_VLN 0x0108 +#define CFG_GZM_VLN(y) ((y) << 16) +#define CFG_GZM_HPXL(x) (x) + +/* HW Cursor Starting Point on Screen Register */ +#define LCD_SPU_HWC_OVSA_HPXL_VLN 0x010C +#define CFG_HWC_OVSA_VLN(y) ((y) << 16) +#define CFG_HWC_OVSA_HPXL(x) (x) + +/* HW Cursor Size */ +#define LCD_SPU_HWC_HPXL_VLN 0x0110 +#define CFG_HWC_VLN(y) ((y) << 16) +#define CFG_HWC_HPXL(x) (x) + +/* Total Screen Size Register */ +#define LCD_SPUT_V_H_TOTAL 0x0114 +#define CFG_V_TOTAL(y) ((y) << 16) +#define CFG_H_TOTAL(x) (x) + +/* Total Screen Active Size Register */ +#define LCD_SPU_V_H_ACTIVE 0x0118 +#define CFG_V_ACTIVE(y) ((y) << 16) +#define CFG_H_ACTIVE(x) (x) + +/* Screen H&V Porch Register */ +#define LCD_SPU_H_PORCH 0x011C +#define CFG_H_BACK_PORCH(b) ((b) << 16) +#define CFG_H_FRONT_PORCH(f) (f) +#define LCD_SPU_V_PORCH 0x0120 +#define CFG_V_BACK_PORCH(b) ((b) << 16) +#define CFG_V_FRONT_PORCH(f) (f) + +/* Screen Blank Color Register */ +#define LCD_SPU_BLANKCOLOR 0x0124 +#define CFG_BLANKCOLOR_MASK 0x00FFFFFF +#define CFG_BLANKCOLOR_R_MASK 0x000000FF +#define CFG_BLANKCOLOR_G_MASK 0x0000FF00 +#define CFG_BLANKCOLOR_B_MASK 0x00FF0000 + +/* HW Cursor Color 1&2 Register */ +#define LCD_SPU_ALPHA_COLOR1 0x0128 +#define CFG_HWC_COLOR1 0x00FFFFFF +#define CFG_HWC_COLOR1_R(red) ((red) << 16) +#define CFG_HWC_COLOR1_G(green) ((green) << 8) +#define CFG_HWC_COLOR1_B(blue) (blue) +#define CFG_HWC_COLOR1_R_MASK 0x000000FF +#define CFG_HWC_COLOR1_G_MASK 0x0000FF00 +#define CFG_HWC_COLOR1_B_MASK 0x00FF0000 +#define LCD_SPU_ALPHA_COLOR2 0x012C +#define CFG_HWC_COLOR2 0x00FFFFFF +#define CFG_HWC_COLOR2_R_MASK 0x000000FF +#define CFG_HWC_COLOR2_G_MASK 0x0000FF00 +#define CFG_HWC_COLOR2_B_MASK 0x00FF0000 + +/* Video YUV Color Key Control */ +#define LCD_SPU_COLORKEY_Y 0x0130 +#define CFG_CKEY_Y2(y2) ((y2) << 24) +#define CFG_CKEY_Y2_MASK 0xFF000000 +#define CFG_CKEY_Y1(y1) ((y1) << 16) +#define CFG_CKEY_Y1_MASK 0x00FF0000 +#define CFG_CKEY_Y(y) ((y) << 8) +#define CFG_CKEY_Y_MASK 0x0000FF00 +#define CFG_ALPHA_Y(y) (y) +#define CFG_ALPHA_Y_MASK 0x000000FF +#define LCD_SPU_COLORKEY_U 0x0134 +#define CFG_CKEY_U2(u2) ((u2) << 24) +#define CFG_CKEY_U2_MASK 0xFF000000 +#define CFG_CKEY_U1(u1) ((u1) << 16) +#define CFG_CKEY_U1_MASK 0x00FF0000 +#define CFG_CKEY_U(u) ((u) << 8) +#define CFG_CKEY_U_MASK 0x0000FF00 +#define CFG_ALPHA_U(u) (u) +#define CFG_ALPHA_U_MASK 0x000000FF +#define LCD_SPU_COLORKEY_V 0x0138 +#define CFG_CKEY_V2(v2) ((v2) << 24) +#define CFG_CKEY_V2_MASK 0xFF000000 +#define CFG_CKEY_V1(v1) ((v1) << 16) +#define CFG_CKEY_V1_MASK 0x00FF0000 +#define CFG_CKEY_V(v) ((v) << 8) +#define CFG_CKEY_V_MASK 0x0000FF00 +#define CFG_ALPHA_V(v) (v) +#define CFG_ALPHA_V_MASK 0x000000FF + +/* SPI Read Data Register */ +#define LCD_SPU_SPI_RXDATA 0x0140 + +/* Smart Panel Read Data Register */ +#define LCD_SPU_ISA_RSDATA 0x0144 +#define ISA_RXDATA_16BIT_1_DATA_MASK 0x000000FF +#define ISA_RXDATA_16BIT_2_DATA_MASK 0x0000FF00 +#define ISA_RXDATA_16BIT_3_DATA_MASK 0x00FF0000 +#define ISA_RXDATA_16BIT_4_DATA_MASK 0xFF000000 +#define ISA_RXDATA_32BIT_1_DATA_MASK 0x00FFFFFF + +/* HWC SRAM Read Data Register */ +#define LCD_SPU_HWC_RDDAT 0x0158 + +/* Gamma Table SRAM Read Data Register */ +#define LCD_SPU_GAMMA_RDDAT 0x015c +#define CFG_GAMMA_RDDAT_MASK 0x000000FF + +/* Palette Table SRAM Read Data Register */ +#define LCD_SPU_PALETTE_RDDAT 0x0160 +#define CFG_PALETTE_RDDAT_MASK 0x00FFFFFF + +/* I/O Pads Input Read Only Register */ +#define LCD_SPU_IOPAD_IN 0x0178 +#define CFG_IOPAD_IN_MASK 0x0FFFFFFF + +/* Reserved Read Only Registers */ +#define LCD_CFG_RDREG5F 0x017C +#define IRE_FRAME_CNT_MASK 0x000000C0 +#define IPE_FRAME_CNT_MASK 0x00000030 +#define GRA_FRAME_CNT_MASK 0x0000000C /* Graphic */ +#define DMA_FRAME_CNT_MASK 0x00000003 /* Video */ + +/* SPI Control Register. */ +#define LCD_SPU_SPI_CTRL 0x0180 +#define CFG_SCLKCNT(div) ((div) << 24) /* 0xFF~0x2 */ +#define CFG_SCLKCNT_MASK 0xFF000000 +#define CFG_RXBITS(rx) ((rx) << 16) /* 0x1F~0x1 */ +#define CFG_RXBITS_MASK 0x00FF0000 +#define CFG_TXBITS(tx) ((tx) << 8) /* 0x1F~0x1 */ +#define CFG_TXBITS_MASK 0x0000FF00 +#define CFG_CLKINV(clk) ((clk) << 7) +#define CFG_CLKINV_MASK 0x00000080 +#define CFG_KEEPXFER(transfer) ((transfer) << 6) +#define CFG_KEEPXFER_MASK 0x00000040 +#define CFG_RXBITSTO0(rx) ((rx) << 5) +#define CFG_RXBITSTO0_MASK 0x00000020 +#define CFG_TXBITSTO0(tx) ((tx) << 4) +#define CFG_TXBITSTO0_MASK 0x00000010 +#define CFG_SPI_ENA(spi) ((spi) << 3) +#define CFG_SPI_ENA_MASK 0x00000008 +#define CFG_SPI_SEL(spi) ((spi) << 2) +#define CFG_SPI_SEL_MASK 0x00000004 +#define CFG_SPI_3W4WB(wire) ((wire) << 1) +#define CFG_SPI_3W4WB_MASK 0x00000002 +#define CFG_SPI_START(start) (start) +#define CFG_SPI_START_MASK 0x00000001 + +/* SPI Tx Data Register */ +#define LCD_SPU_SPI_TXDATA 0x0184 + +/* + 1. Smart Pannel 8-bit Bus Control Register. + 2. AHB Slave Path Data Port Register +*/ +#define LCD_SPU_SMPN_CTRL 0x0188 + +/* DMA Control 0 Register */ +#define LCD_SPU_DMA_CTRL0 0x0190 +#define CFG_NOBLENDING(nb) ((nb) << 31) +#define CFG_NOBLENDING_MASK 0x80000000 +#define CFG_GAMMA_ENA(gn) ((gn) << 30) +#define CFG_GAMMA_ENA_MASK 0x40000000 +#define CFG_CBSH_ENA(cn) ((cn) << 29) +#define CFG_CBSH_ENA_MASK 0x20000000 +#define CFG_PALETTE_ENA(pn) ((pn) << 28) +#define CFG_PALETTE_ENA_MASK 0x10000000 +#define CFG_ARBFAST_ENA(an) ((an) << 27) +#define CFG_ARBFAST_ENA_MASK 0x08000000 +#define CFG_HWC_1BITMOD(mode) ((mode) << 26) +#define CFG_HWC_1BITMOD_MASK 0x04000000 +#define CFG_HWC_1BITENA(mn) ((mn) << 25) +#define CFG_HWC_1BITENA_MASK 0x02000000 +#define CFG_HWC_ENA(cn) ((cn) << 24) +#define CFG_HWC_ENA_MASK 0x01000000 +#define CFG_DMAFORMAT(dmaformat) ((dmaformat) << 20) +#define CFG_DMAFORMAT_MASK 0x00F00000 +#define CFG_GRAFORMAT(graformat) ((graformat) << 16) +#define CFG_GRAFORMAT_MASK 0x000F0000 +/* for graphic part */ +#define CFG_GRA_FTOGGLE(toggle) ((toggle) << 15) +#define CFG_GRA_FTOGGLE_MASK 0x00008000 +#define CFG_GRA_HSMOOTH(smooth) ((smooth) << 14) +#define CFG_GRA_HSMOOTH_MASK 0x00004000 +#define CFG_GRA_TSTMODE(test) ((test) << 13) +#define CFG_GRA_TSTMODE_MASK 0x00002000 +#define CFG_GRA_SWAPRB(swap) ((swap) << 12) +#define CFG_GRA_SWAPRB_MASK 0x00001000 +#define CFG_GRA_SWAPUV(swap) ((swap) << 11) +#define CFG_GRA_SWAPUV_MASK 0x00000800 +#define CFG_GRA_SWAPYU(swap) ((swap) << 10) +#define CFG_GRA_SWAPYU_MASK 0x00000400 +#define CFG_YUV2RGB_GRA(cvrt) ((cvrt) << 9) +#define CFG_YUV2RGB_GRA_MASK 0x00000200 +#define CFG_GRA_ENA(gra) ((gra) << 8) +#define CFG_GRA_ENA_MASK 0x00000100 +/* for video part */ +#define CFG_DMA_FTOGGLE(toggle) ((toggle) << 7) +#define CFG_DMA_FTOGGLE_MASK 0x00000080 +#define CFG_DMA_HSMOOTH(smooth) ((smooth) << 6) +#define CFG_DMA_HSMOOTH_MASK 0x00000040 +#define CFG_DMA_TSTMODE(test) ((test) << 5) +#define CFG_DMA_TSTMODE_MASK 0x00000020 +#define CFG_DMA_SWAPRB(swap) ((swap) << 4) +#define CFG_DMA_SWAPRB_MASK 0x00000010 +#define CFG_DMA_SWAPUV(swap) ((swap) << 3) +#define CFG_DMA_SWAPUV_MASK 0x00000008 +#define CFG_DMA_SWAPYU(swap) ((swap) << 2) +#define CFG_DMA_SWAPYU_MASK 0x00000004 +#define CFG_DMA_SWAP_MASK 0x0000001C +#define CFG_YUV2RGB_DMA(cvrt) ((cvrt) << 1) +#define CFG_YUV2RGB_DMA_MASK 0x00000002 +#define CFG_DMA_ENA(video) (video) +#define CFG_DMA_ENA_MASK 0x00000001 + +/* DMA Control 1 Register */ +#define LCD_SPU_DMA_CTRL1 0x0194 +#define CFG_FRAME_TRIG(trig) ((trig) << 31) +#define CFG_FRAME_TRIG_MASK 0x80000000 +#define CFG_VSYNC_TRIG(trig) ((trig) << 28) +#define CFG_VSYNC_TRIG_MASK 0x70000000 +#define CFG_VSYNC_INV(inv) ((inv) << 27) +#define CFG_VSYNC_INV_MASK 0x08000000 +#define CFG_COLOR_KEY_MODE(cmode) ((cmode) << 24) +#define CFG_COLOR_KEY_MASK 0x07000000 +#define CFG_CARRY(carry) ((carry) << 23) +#define CFG_CARRY_MASK 0x00800000 +#define CFG_LNBUF_ENA(lnbuf) ((lnbuf) << 22) +#define CFG_LNBUF_ENA_MASK 0x00400000 +#define CFG_GATED_ENA(gated) ((gated) << 21) +#define CFG_GATED_ENA_MASK 0x00200000 +#define CFG_PWRDN_ENA(power) ((power) << 20) +#define CFG_PWRDN_ENA_MASK 0x00100000 +#define CFG_DSCALE(dscale) ((dscale) << 18) +#define CFG_DSCALE_MASK 0x000C0000 +#define CFG_ALPHA_MODE(amode) ((amode) << 16) +#define CFG_ALPHA_MODE_MASK 0x00030000 +#define CFG_ALPHA(alpha) ((alpha) << 8) +#define CFG_ALPHA_MASK 0x0000FF00 +#define CFG_PXLCMD(pxlcmd) (pxlcmd) +#define CFG_PXLCMD_MASK 0x000000FF + +/* SRAM Control Register */ +#define LCD_SPU_SRAM_CTRL 0x0198 +#define CFG_SRAM_INIT_WR_RD(mode) ((mode) << 14) +#define CFG_SRAM_INIT_WR_RD_MASK 0x0000C000 +#define CFG_SRAM_ADDR_LCDID(id) ((id) << 8) +#define CFG_SRAM_ADDR_LCDID_MASK 0x00000F00 +#define CFG_SRAM_ADDR(addr) (addr) +#define CFG_SRAM_ADDR_MASK 0x000000FF + +/* SRAM Write Data Register */ +#define LCD_SPU_SRAM_WRDAT 0x019C + +/* SRAM RTC/WTC Control Register */ +#define LCD_SPU_SRAM_PARA0 0x01A0 + +/* SRAM Power Down Control Register */ +#define LCD_SPU_SRAM_PARA1 0x01A4 +#define CFG_CSB_256x32(hwc) ((hwc) << 15) /* HWC */ +#define CFG_CSB_256x32_MASK 0x00008000 +#define CFG_CSB_256x24(palette) ((palette) << 14) /* Palette */ +#define CFG_CSB_256x24_MASK 0x00004000 +#define CFG_CSB_256x8(gamma) ((gamma) << 13) /* Gamma */ +#define CFG_CSB_256x8_MASK 0x00002000 +#define CFG_PDWN256x32(pdwn) ((pdwn) << 7) /* HWC */ +#define CFG_PDWN256x32_MASK 0x00000080 +#define CFG_PDWN256x24(pdwn) ((pdwn) << 6) /* Palette */ +#define CFG_PDWN256x24_MASK 0x00000040 +#define CFG_PDWN256x8(pdwn) ((pdwn) << 5) /* Gamma */ +#define CFG_PDWN256x8_MASK 0x00000020 +#define CFG_PDWN32x32(pdwn) ((pdwn) << 3) +#define CFG_PDWN32x32_MASK 0x00000008 +#define CFG_PDWN16x66(pdwn) ((pdwn) << 2) +#define CFG_PDWN16x66_MASK 0x00000004 +#define CFG_PDWN32x66(pdwn) ((pdwn) << 1) +#define CFG_PDWN32x66_MASK 0x00000002 +#define CFG_PDWN64x66(pdwn) (pdwn) +#define CFG_PDWN64x66_MASK 0x00000001 + +/* Smart or Dumb Panel Clock Divider */ +#define LCD_CFG_SCLK_DIV 0x01A8 +#define SCLK_SOURCE_SELECT(src) ((src) << 31) +#define SCLK_SOURCE_SELECT_MASK 0x80000000 +#define CLK_FRACDIV(frac) ((frac) << 16) +#define CLK_FRACDIV_MASK 0x0FFF0000 +#define CLK_INT_DIV(div) (div) +#define CLK_INT_DIV_MASK 0x0000FFFF + +/* Video Contrast Register */ +#define LCD_SPU_CONTRAST 0x01AC +#define CFG_BRIGHTNESS(bright) ((bright) << 16) +#define CFG_BRIGHTNESS_MASK 0xFFFF0000 +#define CFG_CONTRAST(contrast) (contrast) +#define CFG_CONTRAST_MASK 0x0000FFFF + +/* Video Saturation Register */ +#define LCD_SPU_SATURATION 0x01B0 +#define CFG_C_MULTS(mult) ((mult) << 16) +#define CFG_C_MULTS_MASK 0xFFFF0000 +#define CFG_SATURATION(sat) (sat) +#define CFG_SATURATION_MASK 0x0000FFFF + +/* Video Hue Adjust Register */ +#define LCD_SPU_CBSH_HUE 0x01B4 +#define CFG_SIN0(sin0) ((sin0) << 16) +#define CFG_SIN0_MASK 0xFFFF0000 +#define CFG_COS0(con0) (con0) +#define CFG_COS0_MASK 0x0000FFFF + +/* Dump LCD Panel Control Register */ +#define LCD_SPU_DUMB_CTRL 0x01B8 +#define CFG_DUMBMODE(mode) ((mode) << 28) +#define CFG_DUMBMODE_MASK 0xF0000000 +#define CFG_LCDGPIO_O(data) ((data) << 20) +#define CFG_LCDGPIO_O_MASK 0x0FF00000 +#define CFG_LCDGPIO_ENA(gpio) ((gpio) << 12) +#define CFG_LCDGPIO_ENA_MASK 0x000FF000 +#define CFG_BIAS_OUT(bias) ((bias) << 8) +#define CFG_BIAS_OUT_MASK 0x00000100 +#define CFG_REVERSE_RGB(rRGB) ((rRGB) << 7) +#define CFG_REVERSE_RGB_MASK 0x00000080 +#define CFG_INV_COMPBLANK(blank) ((blank) << 6) +#define CFG_INV_COMPBLANK_MASK 0x00000040 +#define CFG_INV_COMPSYNC(sync) ((sync) << 5) +#define CFG_INV_COMPSYNC_MASK 0x00000020 +#define CFG_INV_HENA(hena) ((hena) << 4) +#define CFG_INV_HENA_MASK 0x00000010 +#define CFG_INV_VSYNC(vsync) ((vsync) << 3) +#define CFG_INV_VSYNC_MASK 0x00000008 +#define CFG_INV_HSYNC(hsync) ((hsync) << 2) +#define CFG_INV_HSYNC_MASK 0x00000004 +#define CFG_INV_PCLK(pclk) ((pclk) << 1) +#define CFG_INV_PCLK_MASK 0x00000002 +#define CFG_DUMB_ENA(dumb) (dumb) +#define CFG_DUMB_ENA_MASK 0x00000001 + +/* LCD I/O Pads Control Register */ +#define SPU_IOPAD_CONTROL 0x01BC +#define CFG_GRA_VM_ENA(vm) ((vm) << 15) /* gfx */ +#define CFG_GRA_VM_ENA_MASK 0x00008000 +#define CFG_DMA_VM_ENA(vm) ((vm) << 13) /* video */ +#define CFG_DMA_VM_ENA_MASK 0x00002000 +#define CFG_CMD_VM_ENA(vm) ((vm) << 13) +#define CFG_CMD_VM_ENA_MASK 0x00000800 +#define CFG_CSC(csc) ((csc) << 8) /* csc */ +#define CFG_CSC_MASK 0x00000300 +#define CFG_AXICTRL(axi) ((axi) << 4) +#define CFG_AXICTRL_MASK 0x000000F0 +#define CFG_IOPADMODE(iopad) (iopad) +#define CFG_IOPADMODE_MASK 0x0000000F + +/* LCD Interrupt Control Register */ +#define SPU_IRQ_ENA 0x01C0 +#define DMA_FRAME_IRQ0_ENA(irq) ((irq) << 31) +#define DMA_FRAME_IRQ0_ENA_MASK 0x80000000 +#define DMA_FRAME_IRQ1_ENA(irq) ((irq) << 30) +#define DMA_FRAME_IRQ1_ENA_MASK 0x40000000 +#define DMA_FF_UNDERFLOW_ENA(ff) ((ff) << 29) +#define DMA_FF_UNDERFLOW_ENA_MASK 0x20000000 +#define GRA_FRAME_IRQ0_ENA(irq) ((irq) << 27) +#define GRA_FRAME_IRQ0_ENA_MASK 0x08000000 +#define GRA_FRAME_IRQ1_ENA(irq) ((irq) << 26) +#define GRA_FRAME_IRQ1_ENA_MASK 0x04000000 +#define GRA_FF_UNDERFLOW_ENA(ff) ((ff) << 25) +#define GRA_FF_UNDERFLOW_ENA_MASK 0x02000000 +#define VSYNC_IRQ_ENA(vsync_irq) ((vsync_irq) << 23) +#define VSYNC_IRQ_ENA_MASK 0x00800000 +#define DUMB_FRAMEDONE_ENA(fdone) ((fdone) << 22) +#define DUMB_FRAMEDONE_ENA_MASK 0x00400000 +#define TWC_FRAMEDONE_ENA(fdone) ((fdone) << 21) +#define TWC_FRAMEDONE_ENA_MASK 0x00200000 +#define HWC_FRAMEDONE_ENA(fdone) ((fdone) << 20) +#define HWC_FRAMEDONE_ENA_MASK 0x00100000 +#define SLV_IRQ_ENA(irq) ((irq) << 19) +#define SLV_IRQ_ENA_MASK 0x00080000 +#define SPI_IRQ_ENA(irq) ((irq) << 18) +#define SPI_IRQ_ENA_MASK 0x00040000 +#define PWRDN_IRQ_ENA(irq) ((irq) << 17) +#define PWRDN_IRQ_ENA_MASK 0x00020000 +#define ERR_IRQ_ENA(irq) ((irq) << 16) +#define ERR_IRQ_ENA_MASK 0x00010000 +#define CLEAN_SPU_IRQ_ISR(irq) (irq) +#define CLEAN_SPU_IRQ_ISR_MASK 0x0000FFFF + +/* LCD Interrupt Status Register */ +#define SPU_IRQ_ISR 0x01C4 +#define DMA_FRAME_IRQ0(irq) ((irq) << 31) +#define DMA_FRAME_IRQ0_MASK 0x80000000 +#define DMA_FRAME_IRQ1(irq) ((irq) << 30) +#define DMA_FRAME_IRQ1_MASK 0x40000000 +#define DMA_FF_UNDERFLOW(ff) ((ff) << 29) +#define DMA_FF_UNDERFLOW_MASK 0x20000000 +#define GRA_FRAME_IRQ0(irq) ((irq) << 27) +#define GRA_FRAME_IRQ0_MASK 0x08000000 +#define GRA_FRAME_IRQ1(irq) ((irq) << 26) +#define GRA_FRAME_IRQ1_MASK 0x04000000 +#define GRA_FF_UNDERFLOW(ff) ((ff) << 25) +#define GRA_FF_UNDERFLOW_MASK 0x02000000 +#define VSYNC_IRQ(vsync_irq) ((vsync_irq) << 23) +#define VSYNC_IRQ_MASK 0x00800000 +#define DUMB_FRAMEDONE(fdone) ((fdone) << 22) +#define DUMB_FRAMEDONE_MASK 0x00400000 +#define TWC_FRAMEDONE(fdone) ((fdone) << 21) +#define TWC_FRAMEDONE_MASK 0x00200000 +#define HWC_FRAMEDONE(fdone) ((fdone) << 20) +#define HWC_FRAMEDONE_MASK 0x00100000 +#define SLV_IRQ(irq) ((irq) << 19) +#define SLV_IRQ_MASK 0x00080000 +#define SPI_IRQ(irq) ((irq) << 18) +#define SPI_IRQ_MASK 0x00040000 +#define PWRDN_IRQ(irq) ((irq) << 17) +#define PWRDN_IRQ_MASK 0x00020000 +#define ERR_IRQ(irq) ((irq) << 16) +#define ERR_IRQ_MASK 0x00010000 +/* read-only */ +#define DMA_FRAME_IRQ0_LEVEL_MASK 0x00008000 +#define DMA_FRAME_IRQ1_LEVEL_MASK 0x00004000 +#define DMA_FRAME_CNT_ISR_MASK 0x00003000 +#define GRA_FRAME_IRQ0_LEVEL_MASK 0x00000800 +#define GRA_FRAME_IRQ1_LEVEL_MASK 0x00000400 +#define GRA_FRAME_CNT_ISR_MASK 0x00000300 +#define VSYNC_IRQ_LEVEL_MASK 0x00000080 +#define DUMB_FRAMEDONE_LEVEL_MASK 0x00000040 +#define TWC_FRAMEDONE_LEVEL_MASK 0x00000020 +#define HWC_FRAMEDONE_LEVEL_MASK 0x00000010 +#define SLV_FF_EMPTY_MASK 0x00000008 +#define DMA_FF_ALLEMPTY_MASK 0x00000004 +#define GRA_FF_ALLEMPTY_MASK 0x00000002 +#define PWRDN_IRQ_LEVEL_MASK 0x00000001 + + +/* + * defined Video Memory Color format for DMA control 0 register + * DMA0 bit[23:20] + */ +#define VMODE_RGB565 0x0 +#define VMODE_RGB1555 0x1 +#define VMODE_RGB888PACKED 0x2 +#define VMODE_RGB888UNPACKED 0x3 +#define VMODE_RGBA888 0x4 +#define VMODE_YUV422PACKED 0x5 +#define VMODE_YUV422PLANAR 0x6 +#define VMODE_YUV420PLANAR 0x7 +#define VMODE_SMPNCMD 0x8 +#define VMODE_PALETTE4BIT 0x9 +#define VMODE_PALETTE8BIT 0xa +#define VMODE_RESERVED 0xb + +/* + * defined Graphic Memory Color format for DMA control 0 register + * DMA0 bit[19:16] + */ +#define GMODE_RGB565 0x0 +#define GMODE_RGB1555 0x1 +#define GMODE_RGB888PACKED 0x2 +#define GMODE_RGB888UNPACKED 0x3 +#define GMODE_RGBA888 0x4 +#define GMODE_YUV422PACKED 0x5 +#define GMODE_YUV422PLANAR 0x6 +#define GMODE_YUV420PLANAR 0x7 +#define GMODE_SMPNCMD 0x8 +#define GMODE_PALETTE4BIT 0x9 +#define GMODE_PALETTE8BIT 0xa +#define GMODE_RESERVED 0xb + +/* + * define for DMA control 1 register + */ +#define DMA1_FRAME_TRIG 31 /* bit location */ +#define DMA1_VSYNC_MODE 28 +#define DMA1_VSYNC_INV 27 +#define DMA1_CKEY 24 +#define DMA1_CARRY 23 +#define DMA1_LNBUF_ENA 22 +#define DMA1_GATED_ENA 21 +#define DMA1_PWRDN_ENA 20 +#define DMA1_DSCALE 18 +#define DMA1_ALPHA_MODE 16 +#define DMA1_ALPHA 08 +#define DMA1_PXLCMD 00 + +/* + * defined for Configure Dumb Mode + * DUMB LCD Panel bit[31:28] + */ +#define DUMB16_RGB565_0 0x0 +#define DUMB16_RGB565_1 0x1 +#define DUMB18_RGB666_0 0x2 +#define DUMB18_RGB666_1 0x3 +#define DUMB12_RGB444_0 0x4 +#define DUMB12_RGB444_1 0x5 +#define DUMB24_RGB888_0 0x6 +#define DUMB_BLANK 0x7 + +/* + * defined for Configure I/O Pin Allocation Mode + * LCD LCD I/O Pads control register bit[3:0] + */ +#define IOPAD_DUMB24 0x0 +#define IOPAD_DUMB18SPI 0x1 +#define IOPAD_DUMB18GPIO 0x2 +#define IOPAD_DUMB16SPI 0x3 +#define IOPAD_DUMB16GPIO 0x4 +#define IOPAD_DUMB12 0x5 +#define IOPAD_SMART18SPI 0x6 +#define IOPAD_SMART16SPI 0x7 +#define IOPAD_SMART8BOTH 0x8 + +#endif /* __PXA168FB_H__ */ diff --git a/drivers/video/s1d13xxxfb.c b/drivers/video/s1d13xxxfb.c index 0726aecf3b7e..0deb0a8867b7 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 5e9c6302433b..43680e545427 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; } /** @@ -947,7 +968,8 @@ static int __devexit s3c_fb_remove(struct platform_device *pdev) int win; for (win = 0; win <= S3C_FB_MAX_WIN; win++) - s3c_fb_release_win(sfb, sfb->windows[win]); + if (sfb->windows[win]) + s3c_fb_release_win(sfb, sfb->windows[win]); iounmap(sfb->regs); @@ -985,11 +1007,20 @@ static int s3c_fb_suspend(struct platform_device *pdev, pm_message_t state) static int s3c_fb_resume(struct platform_device *pdev) { struct s3c_fb *sfb = platform_get_drvdata(pdev); + struct s3c_fb_platdata *pd = sfb->pdata; struct s3c_fb_win *win; int win_no; clk_enable(sfb->bus_clk); + /* setup registers */ + writel(pd->vidcon1, sfb->regs + VIDCON1); + + /* zero all windows before we do anything */ + for (win_no = 0; win_no < S3C_FB_MAX_WIN; win_no++) + s3c_fb_clear_win(sfb, win_no); + + /* restore framebuffers */ for (win_no = 0; win_no < S3C_FB_MAX_WIN; win_no++) { win = sfb->windows[win_no]; if (!win) diff --git a/drivers/video/s3c2410fb.c b/drivers/video/s3c2410fb.c index b0b4513ba537..7da0027e2409 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 9a6ba3e9d1b8..47a17bd23011 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/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c index 92ea0ab44ce2..f10d2fbeda06 100644 --- a/drivers/video/sh_mobile_lcdcfb.c +++ b/drivers/video/sh_mobile_lcdcfb.c @@ -47,6 +47,7 @@ struct sh_mobile_lcdc_priv { #endif unsigned long lddckr; struct sh_mobile_lcdc_chan ch[2]; + int started; }; /* shared registers */ @@ -451,6 +452,7 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) /* start the lcdc */ sh_mobile_lcdc_start_stop(priv, 1); + priv->started = 1; /* tell the board code to enable the panel */ for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { @@ -493,7 +495,10 @@ static void sh_mobile_lcdc_stop(struct sh_mobile_lcdc_priv *priv) } /* stop the lcdc */ - sh_mobile_lcdc_start_stop(priv, 0); + if (priv->started) { + sh_mobile_lcdc_start_stop(priv, 0); + priv->started = 0; + } /* stop clocks */ for (k = 0; k < ARRAY_SIZE(priv->ch); k++) diff --git a/drivers/video/sis/sis_main.c b/drivers/video/sis/sis_main.c index 7e17ee95a97a..7072d19080d5 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 eabaad765aeb..eec9dcb7f599 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 643afbfe8277..45b883598bf0 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/tdfxfb.c b/drivers/video/tdfxfb.c index 89f231dc443f..ff43c8885028 100644 --- a/drivers/video/tdfxfb.c +++ b/drivers/video/tdfxfb.c @@ -1315,7 +1315,6 @@ static int __devinit tdfxfb_setup_i2c_bus(struct tdfxfb_i2c_chan *chan, strlcpy(chan->adapter.name, name, sizeof(chan->adapter.name)); chan->adapter.owner = THIS_MODULE; - chan->adapter.class = I2C_CLASS_TV_ANALOG; chan->adapter.algo_data = &chan->algo; chan->adapter.dev.parent = dev; chan->algo.setsda = tdfxfb_i2c_setsda; diff --git a/drivers/video/uvesafb.c b/drivers/video/uvesafb.c index 421770b5e6ab..ca5b4643a401 100644 --- a/drivers/video/uvesafb.c +++ b/drivers/video/uvesafb.c @@ -45,7 +45,7 @@ static struct fb_fix_screeninfo uvesafb_fix __devinitdata = { static int mtrr __devinitdata = 3; /* enable mtrr by default */ static int blank = 1; /* enable blanking by default */ static int ypan = 1; /* 0: scroll, 1: ypan, 2: ywrap */ -static int pmi_setpal __devinitdata = 1; /* use PMI for palette changes */ +static bool pmi_setpal __devinitdata = true; /* use PMI for palette changes */ static int nocrtc __devinitdata; /* ignore CRTC settings */ static int noedid __devinitdata; /* don't try DDC transfers */ static int vram_remap __devinitdata; /* set amt. of memory to be used */ @@ -2002,11 +2002,7 @@ static void __devexit uvesafb_exit(void) module_exit(uvesafb_exit); -static int param_get_scroll(char *buffer, struct kernel_param *kp) -{ - return 0; -} - +#define param_get_scroll NULL static int param_set_scroll(const char *val, struct kernel_param *kp) { ypan = 0; @@ -2017,6 +2013,8 @@ static int param_set_scroll(const char *val, struct kernel_param *kp) ypan = 1; else if (!strcmp(val, "ywrap")) ypan = 2; + else + return -EINVAL; return 0; } 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, 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) diff --git a/drivers/video/xen-fbfront.c b/drivers/video/xen-fbfront.c index 2493f05e9f61..15502d5e3641 100644 --- a/drivers/video/xen-fbfront.c +++ b/drivers/video/xen-fbfront.c @@ -384,7 +384,7 @@ static int __devinit xenfb_probe(struct xenbus_device *dev, fb_size = XENFB_DEFAULT_FB_LEN; } - dev->dev.driver_data = info; + dev_set_drvdata(&dev->dev, info); info->xbdev = dev; info->irq = -1; info->x1 = info->y1 = INT_MAX; @@ -503,7 +503,7 @@ xenfb_make_preferred_console(void) static int xenfb_resume(struct xenbus_device *dev) { - struct xenfb_info *info = dev->dev.driver_data; + struct xenfb_info *info = dev_get_drvdata(&dev->dev); xenfb_disconnect_backend(info); xenfb_init_shared_page(info, info->fb_info); @@ -512,7 +512,7 @@ static int xenfb_resume(struct xenbus_device *dev) static int xenfb_remove(struct xenbus_device *dev) { - struct xenfb_info *info = dev->dev.driver_data; + struct xenfb_info *info = dev_get_drvdata(&dev->dev); xenfb_disconnect_backend(info); if (info->fb_info) { @@ -621,7 +621,7 @@ static void xenfb_disconnect_backend(struct xenfb_info *info) static void xenfb_backend_changed(struct xenbus_device *dev, enum xenbus_state backend_state) { - struct xenfb_info *info = dev->dev.driver_data; + struct xenfb_info *info = dev_get_drvdata(&dev->dev); int val; switch (backend_state) { diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c index 40a3a2afbfe7..7a868bd16e0e 100644 --- a/drivers/video/xilinxfb.c +++ b/drivers/video/xilinxfb.c @@ -1,13 +1,12 @@ /* - * xilinxfb.c - * - * Xilinx TFT LCD frame buffer driver + * Xilinx TFT frame buffer driver * * Author: MontaVista Software, Inc. * source@mvista.com * * 2002-2007 (c) MontaVista Software, Inc. * 2007 (c) Secret Lab Technologies, Ltd. + * 2009 (c) Xilinx Inc. * * This file is licensed under the terms of the GNU General Public License * version 2. This program is licensed "as is" without any warranty of any @@ -24,33 +23,38 @@ #include <linux/device.h> #include <linux/module.h> #include <linux/kernel.h> +#include <linux/version.h> #include <linux/errno.h> #include <linux/string.h> #include <linux/mm.h> #include <linux/fb.h> #include <linux/init.h> #include <linux/dma-mapping.h> -#include <linux/platform_device.h> -#if defined(CONFIG_OF) #include <linux/of_device.h> #include <linux/of_platform.h> -#endif -#include <asm/io.h> +#include <linux/io.h> #include <linux/xilinxfb.h> +#include <asm/dcr.h> #define DRIVER_NAME "xilinxfb" -#define DRIVER_DESCRIPTION "Xilinx TFT LCD frame buffer driver" + /* * Xilinx calls it "PLB TFT LCD Controller" though it can also be used for - * the VGA port on the Xilinx ML40x board. This is a hardware display controller - * for a 640x480 resolution TFT or VGA screen. + * the VGA port on the Xilinx ML40x board. This is a hardware display + * controller for a 640x480 resolution TFT or VGA screen. * * The interface to the framebuffer is nice and simple. There are two * control registers. The first tells the LCD interface where in memory * the frame buffer is (only the 11 most significant bits are used, so * don't start thinking about scrolling). The second allows the LCD to * be turned on or off as well as rotated 180 degrees. + * + * In case of direct PLB access the second control register will be at + * an offset of 4 as compared to the DCR access where the offset is 1 + * i.e. REG_CTRL. So this is taken care in the function + * xilinx_fb_out_be32 where it left shifts the offset 2 times in case of + * direct PLB access. */ #define NUM_REGS 2 #define REG_FB_ADDR 0 @@ -107,17 +111,28 @@ static struct fb_var_screeninfo xilinx_fb_var = { .activate = FB_ACTIVATE_NOW }; + +#define PLB_ACCESS_FLAG 0x1 /* 1 = PLB, 0 = DCR */ + struct xilinxfb_drvdata { struct fb_info info; /* FB driver info record */ - u32 regs_phys; /* phys. address of the control registers */ - u32 __iomem *regs; /* virt. address of the control registers */ + phys_addr_t regs_phys; /* phys. address of the control + registers */ + void __iomem *regs; /* virt. address of the control + registers */ + + dcr_host_t dcr_host; + unsigned int dcr_start; + unsigned int dcr_len; void *fb_virt; /* virt. address of the frame buffer */ dma_addr_t fb_phys; /* phys. address of the frame buffer */ int fb_alloced; /* Flag, was the fb memory alloced? */ + u8 flags; /* features of the driver */ + u32 reg_ctrl_default; u32 pseudo_palette[PALETTE_ENTRIES_NO]; @@ -128,14 +143,19 @@ struct xilinxfb_drvdata { container_of(_info, struct xilinxfb_drvdata, info) /* - * The LCD controller has DCR interface to its registers, but all - * the boards and configurations the driver has been tested with - * use opb2dcr bridge. So the registers are seen as memory mapped. - * This macro is to make it simple to add the direct DCR access - * when it's needed. + * The XPS TFT Controller can be accessed through PLB or DCR interface. + * To perform the read/write on the registers we need to check on + * which bus its connected and call the appropriate write API. */ -#define xilinx_fb_out_be32(driverdata, offset, val) \ - out_be32(driverdata->regs + offset, val) +static void xilinx_fb_out_be32(struct xilinxfb_drvdata *drvdata, u32 offset, + u32 val) +{ + if (drvdata->flags & PLB_ACCESS_FLAG) + out_be32(drvdata->regs + (offset << 2), val); + else + dcr_write(drvdata->dcr_host, offset, val); + +} static int xilinx_fb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, @@ -203,35 +223,34 @@ static struct fb_ops xilinxfb_ops = * Bus independent setup/teardown */ -static int xilinxfb_assign(struct device *dev, unsigned long physaddr, +static int xilinxfb_assign(struct device *dev, + struct xilinxfb_drvdata *drvdata, + unsigned long physaddr, struct xilinxfb_platform_data *pdata) { - struct xilinxfb_drvdata *drvdata; int rc; int fbsize = pdata->xvirt * pdata->yvirt * BYTES_PER_PIXEL; - /* Allocate the driver data region */ - drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL); - if (!drvdata) { - dev_err(dev, "Couldn't allocate device private record\n"); - return -ENOMEM; - } - dev_set_drvdata(dev, drvdata); - - /* Map the control registers in */ - if (!request_mem_region(physaddr, 8, DRIVER_NAME)) { - dev_err(dev, "Couldn't lock memory region at 0x%08lX\n", - physaddr); - rc = -ENODEV; - goto err_region; - } - drvdata->regs_phys = physaddr; - drvdata->regs = ioremap(physaddr, 8); - if (!drvdata->regs) { - dev_err(dev, "Couldn't lock memory region at 0x%08lX\n", - physaddr); - rc = -ENODEV; - goto err_map; + if (drvdata->flags & PLB_ACCESS_FLAG) { + /* + * Map the control registers in if the controller + * is on direct PLB interface. + */ + if (!request_mem_region(physaddr, 8, DRIVER_NAME)) { + dev_err(dev, "Couldn't lock memory region at 0x%08lX\n", + physaddr); + rc = -ENODEV; + goto err_region; + } + + drvdata->regs_phys = physaddr; + drvdata->regs = ioremap(physaddr, 8); + if (!drvdata->regs) { + dev_err(dev, "Couldn't lock memory region at 0x%08lX\n", + physaddr); + rc = -ENODEV; + goto err_map; + } } /* Allocate the framebuffer memory */ @@ -247,7 +266,10 @@ static int xilinxfb_assign(struct device *dev, unsigned long physaddr, if (!drvdata->fb_virt) { dev_err(dev, "Could not allocate frame buffer memory\n"); rc = -ENOMEM; - goto err_fbmem; + if (drvdata->flags & PLB_ACCESS_FLAG) + goto err_fbmem; + else + goto err_region; } /* Clear (turn to black) the framebuffer */ @@ -260,7 +282,8 @@ static int xilinxfb_assign(struct device *dev, unsigned long physaddr, drvdata->reg_ctrl_default = REG_CTRL_ENABLE; if (pdata->rotate_screen) drvdata->reg_ctrl_default |= REG_CTRL_ROTATE; - xilinx_fb_out_be32(drvdata, REG_CTRL, drvdata->reg_ctrl_default); + xilinx_fb_out_be32(drvdata, REG_CTRL, + drvdata->reg_ctrl_default); /* Fill struct fb_info */ drvdata->info.device = dev; @@ -296,11 +319,14 @@ static int xilinxfb_assign(struct device *dev, unsigned long physaddr, goto err_regfb; } + if (drvdata->flags & PLB_ACCESS_FLAG) { + /* Put a banner in the log (for DEBUG) */ + dev_dbg(dev, "regs: phys=%lx, virt=%p\n", physaddr, + drvdata->regs); + } /* Put a banner in the log (for DEBUG) */ - dev_dbg(dev, "regs: phys=%lx, virt=%p\n", physaddr, drvdata->regs); - dev_dbg(dev, "fb: phys=%llx, virt=%p, size=%x\n", - (unsigned long long) drvdata->fb_phys, drvdata->fb_virt, - fbsize); + dev_dbg(dev, "fb: phys=%p, virt=%p, size=%x\n", + (void *)drvdata->fb_phys, drvdata->fb_virt, fbsize); return 0; /* success */ @@ -311,14 +337,19 @@ err_cmap: if (drvdata->fb_alloced) dma_free_coherent(dev, PAGE_ALIGN(fbsize), drvdata->fb_virt, drvdata->fb_phys); + else + iounmap(drvdata->fb_virt); + /* Turn off the display */ xilinx_fb_out_be32(drvdata, REG_CTRL, 0); err_fbmem: - iounmap(drvdata->regs); + if (drvdata->flags & PLB_ACCESS_FLAG) + iounmap(drvdata->regs); err_map: - release_mem_region(physaddr, 8); + if (drvdata->flags & PLB_ACCESS_FLAG) + release_mem_region(physaddr, 8); err_region: kfree(drvdata); @@ -342,12 +373,18 @@ static int xilinxfb_release(struct device *dev) if (drvdata->fb_alloced) dma_free_coherent(dev, PAGE_ALIGN(drvdata->info.fix.smem_len), drvdata->fb_virt, drvdata->fb_phys); + else + iounmap(drvdata->fb_virt); /* Turn off the display */ xilinx_fb_out_be32(drvdata, REG_CTRL, 0); - iounmap(drvdata->regs); - release_mem_region(drvdata->regs_phys, 8); + /* Release the resources, as allocated based on interface */ + if (drvdata->flags & PLB_ACCESS_FLAG) { + iounmap(drvdata->regs); + release_mem_region(drvdata->regs_phys, 8); + } else + dcr_unmap(drvdata->dcr_host, drvdata->dcr_len); kfree(drvdata); dev_set_drvdata(dev, NULL); @@ -356,77 +393,57 @@ static int xilinxfb_release(struct device *dev) } /* --------------------------------------------------------------------- - * Platform bus binding - */ - -static int -xilinxfb_platform_probe(struct platform_device *pdev) -{ - struct xilinxfb_platform_data *pdata; - struct resource *res; - - /* Find the registers address */ - res = platform_get_resource(pdev, IORESOURCE_IO, 0); - if (!res) { - dev_err(&pdev->dev, "Couldn't get registers resource\n"); - return -ENODEV; - } - - /* If a pdata structure is provided, then extract the parameters */ - pdata = &xilinx_fb_default_pdata; - if (pdev->dev.platform_data) { - pdata = pdev->dev.platform_data; - if (!pdata->xres) - pdata->xres = xilinx_fb_default_pdata.xres; - if (!pdata->yres) - pdata->yres = xilinx_fb_default_pdata.yres; - if (!pdata->xvirt) - pdata->xvirt = xilinx_fb_default_pdata.xvirt; - if (!pdata->yvirt) - pdata->yvirt = xilinx_fb_default_pdata.yvirt; - } - - return xilinxfb_assign(&pdev->dev, res->start, pdata); -} - -static int -xilinxfb_platform_remove(struct platform_device *pdev) -{ - return xilinxfb_release(&pdev->dev); -} - - -static struct platform_driver xilinxfb_platform_driver = { - .probe = xilinxfb_platform_probe, - .remove = xilinxfb_platform_remove, - .driver = { - .owner = THIS_MODULE, - .name = DRIVER_NAME, - }, -}; - -/* --------------------------------------------------------------------- * OF bus binding */ -#if defined(CONFIG_OF) static int __devinit xilinxfb_of_probe(struct of_device *op, const struct of_device_id *match) { - struct resource res; const u32 *prop; + u32 *p; + u32 tft_access; struct xilinxfb_platform_data pdata; + struct resource res; int size, rc; + int start = 0, len = 0; + dcr_host_t dcr_host; + struct xilinxfb_drvdata *drvdata; /* Copy with the default pdata (not a ptr reference!) */ pdata = xilinx_fb_default_pdata; dev_dbg(&op->dev, "xilinxfb_of_probe(%p, %p)\n", op, match); - rc = of_address_to_resource(op->node, 0, &res); - if (rc) { - dev_err(&op->dev, "invalid address\n"); - return rc; + /* + * To check whether the core is connected directly to DCR or PLB + * interface and initialize the tft_access accordingly. + */ + p = (u32 *)of_get_property(op->node, "xlnx,dcr-splb-slave-if", NULL); + + if (p) + tft_access = *p; + else + tft_access = 0; /* For backward compatibility */ + + /* + * Fill the resource structure if its direct PLB interface + * otherwise fill the dcr_host structure. + */ + if (tft_access) { + rc = of_address_to_resource(op->node, 0, &res); + if (rc) { + dev_err(&op->dev, "invalid address\n"); + return -ENODEV; + } + + } else { + start = dcr_resource_start(op->node, 0); + len = dcr_resource_len(op->node, 0); + dcr_host = dcr_map(op->node, start, len); + if (!DCR_MAP_OK(dcr_host)) { + dev_err(&op->dev, "invalid address\n"); + return -ENODEV; + } } prop = of_get_property(op->node, "phys-size", &size); @@ -450,7 +467,26 @@ xilinxfb_of_probe(struct of_device *op, const struct of_device_id *match) if (of_find_property(op->node, "rotate-display", NULL)) pdata.rotate_screen = 1; - return xilinxfb_assign(&op->dev, res.start, &pdata); + /* Allocate the driver data region */ + drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL); + if (!drvdata) { + dev_err(&op->dev, "Couldn't allocate device private record\n"); + return -ENOMEM; + } + dev_set_drvdata(&op->dev, drvdata); + + if (tft_access) + drvdata->flags |= PLB_ACCESS_FLAG; + + /* Arguments are passed based on the interface */ + if (drvdata->flags & PLB_ACCESS_FLAG) { + return xilinxfb_assign(&op->dev, drvdata, res.start, &pdata); + } else { + drvdata->dcr_start = start; + drvdata->dcr_len = len; + drvdata->dcr_host = dcr_host; + return xilinxfb_assign(&op->dev, drvdata, 0, &pdata); + } } static int __devexit xilinxfb_of_remove(struct of_device *op) @@ -460,7 +496,9 @@ static int __devexit xilinxfb_of_remove(struct of_device *op) /* Match table for of_platform binding */ static struct of_device_id xilinxfb_of_match[] __devinitdata = { + { .compatible = "xlnx,xps-tft-1.00.a", }, { .compatible = "xlnx,plb-tft-cntlr-ref-1.00.a", }, + { .compatible = "xlnx,plb-dvi-cntlr-ref-1.00.c", }, {}, }; MODULE_DEVICE_TABLE(of, xilinxfb_of_match); @@ -476,22 +514,6 @@ static struct of_platform_driver xilinxfb_of_driver = { }, }; -/* Registration helpers to keep the number of #ifdefs to a minimum */ -static inline int __init xilinxfb_of_register(void) -{ - pr_debug("xilinxfb: calling of_register_platform_driver()\n"); - return of_register_platform_driver(&xilinxfb_of_driver); -} - -static inline void __exit xilinxfb_of_unregister(void) -{ - of_unregister_platform_driver(&xilinxfb_of_driver); -} -#else /* CONFIG_OF */ -/* CONFIG_OF not enabled; do nothing helpers */ -static inline int __init xilinxfb_of_register(void) { return 0; } -static inline void __exit xilinxfb_of_unregister(void) { } -#endif /* CONFIG_OF */ /* --------------------------------------------------------------------- * Module setup and teardown @@ -500,28 +522,18 @@ static inline void __exit xilinxfb_of_unregister(void) { } static int __init xilinxfb_init(void) { - int rc; - rc = xilinxfb_of_register(); - if (rc) - return rc; - - rc = platform_driver_register(&xilinxfb_platform_driver); - if (rc) - xilinxfb_of_unregister(); - - return rc; + return of_register_platform_driver(&xilinxfb_of_driver); } static void __exit xilinxfb_cleanup(void) { - platform_driver_unregister(&xilinxfb_platform_driver); - xilinxfb_of_unregister(); + of_unregister_platform_driver(&xilinxfb_of_driver); } module_init(xilinxfb_init); module_exit(xilinxfb_cleanup); MODULE_AUTHOR("MontaVista Software, Inc. <source@mvista.com>"); -MODULE_DESCRIPTION(DRIVER_DESCRIPTION); +MODULE_DESCRIPTION("Xilinx TFT frame buffer driver"); MODULE_LICENSE("GPL"); |