aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video')
-rw-r--r--drivers/video/Kconfig53
-rw-r--r--drivers/video/Makefile5
-rw-r--r--drivers/video/acornfb.c1
-rw-r--r--drivers/video/amifb.c24
-rw-r--r--drivers/video/atafb.c7
-rw-r--r--drivers/video/atmel_lcdfb.c92
-rw-r--r--drivers/video/aty/aty128fb.c8
-rw-r--r--drivers/video/aty/atyfb_base.c100
-rw-r--r--drivers/video/aty/radeon_base.c20
-rw-r--r--drivers/video/aty/radeonfb.h2
-rw-r--r--drivers/video/backlight/Kconfig45
-rw-r--r--drivers/video/backlight/Makefile8
-rw-r--r--drivers/video/backlight/atmel-pwm-bl.c244
-rw-r--r--drivers/video/backlight/backlight.c1
-rw-r--r--drivers/video/backlight/ili9320.c330
-rw-r--r--drivers/video/backlight/ili9320.h80
-rw-r--r--drivers/video/backlight/lcd.c2
-rw-r--r--drivers/video/backlight/mbp_nvidia_bl.c116
-rw-r--r--drivers/video/backlight/platform_lcd.c172
-rw-r--r--drivers/video/backlight/vgg2432a4.c284
-rw-r--r--drivers/video/bf54x-lq043fb.c2
-rw-r--r--drivers/video/bfin-t350mcqb-fb.c2
-rw-r--r--drivers/video/carminefb.c790
-rw-r--r--drivers/video/carminefb.h64
-rw-r--r--drivers/video/carminefb_regs.h159
-rw-r--r--drivers/video/cobalt_lcdfb.c371
-rw-r--r--drivers/video/console/fbcon.c8
-rw-r--r--drivers/video/console/fbcon.h8
-rw-r--r--drivers/video/console/mdacon.c4
-rw-r--r--drivers/video/console/sticon.c2
-rw-r--r--drivers/video/console/sticore.c33
-rw-r--r--drivers/video/fbmem.c15
-rw-r--r--drivers/video/fbmon.c2
-rw-r--r--drivers/video/fsl-diu-fb.c60
-rw-r--r--drivers/video/geode/lxfb.h2
-rw-r--r--drivers/video/geode/lxfb_ops.c28
-rw-r--r--drivers/video/hgafb.c36
-rw-r--r--drivers/video/imxfb.c1
-rw-r--r--drivers/video/macfb.c2
-rw-r--r--drivers/video/neofb.c215
-rw-r--r--drivers/video/offb.c192
-rw-r--r--drivers/video/omap/dispc.c1
-rw-r--r--drivers/video/omap/omapfb_main.c1
-rw-r--r--drivers/video/ps3fb.c1
-rw-r--r--drivers/video/pxafb.c72
-rw-r--r--drivers/video/pxafb.h2
-rw-r--r--drivers/video/sa1100fb.c8
-rw-r--r--drivers/video/sa1100fb.h2
-rw-r--r--drivers/video/sh7760fb.c658
-rw-r--r--drivers/video/sh_mobile_lcdcfb.c725
-rw-r--r--drivers/video/sis/init.h1
-rw-r--r--drivers/video/sis/init301.h1
-rw-r--r--drivers/video/sis/initextlfb.c1
-rw-r--r--drivers/video/sis/osdef.h1
-rw-r--r--drivers/video/sis/sis.h22
-rw-r--r--drivers/video/sis/sis_accel.c1
-rw-r--r--drivers/video/sis/sis_main.c44
-rw-r--r--drivers/video/sis/sis_main.h4
-rw-r--r--drivers/video/sis/vgatypes.h4
-rw-r--r--drivers/video/skeletonfb.c37
-rw-r--r--drivers/video/sm501fb.c329
-rw-r--r--drivers/video/sticore.h2
-rw-r--r--drivers/video/stifb.c6
-rw-r--r--drivers/video/tdfxfb.c8
-rw-r--r--drivers/video/tridentfb.c1350
-rw-r--r--drivers/video/uvesafb.c4
-rw-r--r--drivers/video/vfb.c14
-rw-r--r--drivers/video/vga16fb.c122
68 files changed, 5779 insertions, 1232 deletions
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 9b887ef64ff1..70d135e0cc47 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -1658,6 +1658,32 @@ config FB_PM3
1658 similar boards, 3DLabs Permedia3 Create!, Appian Jeronimo 2000 1658 similar boards, 3DLabs Permedia3 Create!, Appian Jeronimo 2000
1659 and maybe other boards. 1659 and maybe other boards.
1660 1660
1661config FB_CARMINE
1662 tristate "Fujitsu carmine frame buffer support"
1663 depends on FB && PCI
1664 select FB_CFB_FILLRECT
1665 select FB_CFB_COPYAREA
1666 select FB_CFB_IMAGEBLIT
1667 help
1668 This is the frame buffer device driver for the Fujitsu Carmine chip.
1669 The driver provides two independent frame buffer devices.
1670
1671choice
1672 depends on FB_CARMINE
1673 prompt "DRAM timing"
1674 default FB_CARMINE_DRAM_EVAL
1675
1676config FB_CARMINE_DRAM_EVAL
1677 bool "Eval board timings"
1678 help
1679 Use timings which work on the eval card.
1680
1681config CARMINE_DRAM_CUSTOM
1682 bool "Custom board timings"
1683 help
1684 Use custom board timings.
1685endchoice
1686
1661config FB_AU1100 1687config FB_AU1100
1662 bool "Au1100 LCD Driver" 1688 bool "Au1100 LCD Driver"
1663 depends on (FB = y) && MIPS && SOC_AU1100 1689 depends on (FB = y) && MIPS && SOC_AU1100
@@ -1840,6 +1866,16 @@ config FB_W100
1840 1866
1841 If unsure, say N. 1867 If unsure, say N.
1842 1868
1869config FB_SH_MOBILE_LCDC
1870 tristate "SuperH Mobile LCDC framebuffer support"
1871 depends on FB && SUPERH
1872 select FB_CFB_FILLRECT
1873 select FB_CFB_COPYAREA
1874 select FB_CFB_IMAGEBLIT
1875 default m
1876 ---help---
1877 Frame buffer driver for the on-chip SH-Mobile LCD controller.
1878
1843config FB_S3C2410 1879config FB_S3C2410
1844 tristate "S3C2410 LCD framebuffer support" 1880 tristate "S3C2410 LCD framebuffer support"
1845 depends on FB && ARCH_S3C2410 1881 depends on FB && ARCH_S3C2410
@@ -1951,6 +1987,23 @@ config FB_AM200EPD
1951 This enables support for the Metronome display controller used on 1987 This enables support for the Metronome display controller used on
1952 the E-Ink AM-200 EPD devkit. 1988 the E-Ink AM-200 EPD devkit.
1953 1989
1990config FB_COBALT
1991 tristate "Cobalt server LCD frame buffer support"
1992 depends on FB && MIPS_COBALT
1993
1994config FB_SH7760
1995 bool "SH7760/SH7763 LCDC support"
1996 depends on FB && (CPU_SUBTYPE_SH7760 || CPU_SUBTYPE_SH7763)
1997 select FB_CFB_FILLRECT
1998 select FB_CFB_COPYAREA
1999 select FB_CFB_IMAGEBLIT
2000 help
2001 Support for the SH7760/SH7763 integrated (D)STN/TFT LCD Controller.
2002 Supports display resolutions up to 1024x1024 pixel, grayscale and
2003 color operation, with depths ranging from 1 bpp to 8 bpp monochrome
2004 and 8, 15 or 16 bpp color; 90 degrees clockwise display rotation for
2005 panels <= 320 pixel horizontal resolution.
2006
1954config FB_VIRTUAL 2007config FB_VIRTUAL
1955 tristate "Virtual Frame Buffer support (ONLY FOR TESTING!)" 2008 tristate "Virtual Frame Buffer support (ONLY FOR TESTING!)"
1956 depends on FB 2009 depends on FB
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 04bca35403ff..0ebc1bfd2514 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -106,17 +106,22 @@ obj-$(CONFIG_FB_PMAGB_B) += pmagb-b-fb.o
106obj-$(CONFIG_FB_MAXINE) += maxinefb.o 106obj-$(CONFIG_FB_MAXINE) += maxinefb.o
107obj-$(CONFIG_FB_METRONOME) += metronomefb.o 107obj-$(CONFIG_FB_METRONOME) += metronomefb.o
108obj-$(CONFIG_FB_S1D13XXX) += s1d13xxxfb.o 108obj-$(CONFIG_FB_S1D13XXX) += s1d13xxxfb.o
109obj-$(CONFIG_FB_SH7760) += sh7760fb.o
109obj-$(CONFIG_FB_IMX) += imxfb.o 110obj-$(CONFIG_FB_IMX) += imxfb.o
110obj-$(CONFIG_FB_S3C2410) += s3c2410fb.o 111obj-$(CONFIG_FB_S3C2410) += s3c2410fb.o
111obj-$(CONFIG_FB_FSL_DIU) += fsl-diu-fb.o 112obj-$(CONFIG_FB_FSL_DIU) += fsl-diu-fb.o
113obj-$(CONFIG_FB_COBALT) += cobalt_lcdfb.o
112obj-$(CONFIG_FB_PNX4008_DUM) += pnx4008/ 114obj-$(CONFIG_FB_PNX4008_DUM) += pnx4008/
113obj-$(CONFIG_FB_PNX4008_DUM_RGB) += pnx4008/ 115obj-$(CONFIG_FB_PNX4008_DUM_RGB) += pnx4008/
114obj-$(CONFIG_FB_IBM_GXT4500) += gxt4500.o 116obj-$(CONFIG_FB_IBM_GXT4500) += gxt4500.o
115obj-$(CONFIG_FB_PS3) += ps3fb.o 117obj-$(CONFIG_FB_PS3) += ps3fb.o
116obj-$(CONFIG_FB_SM501) += sm501fb.o 118obj-$(CONFIG_FB_SM501) += sm501fb.o
117obj-$(CONFIG_FB_XILINX) += xilinxfb.o 119obj-$(CONFIG_FB_XILINX) += xilinxfb.o
120obj-$(CONFIG_FB_SH_MOBILE_LCDC) += sh_mobile_lcdcfb.o
121obj-$(CONFIG_FB_SH7343VOU) += sh7343_voufb.o
118obj-$(CONFIG_FB_OMAP) += omap/ 122obj-$(CONFIG_FB_OMAP) += omap/
119obj-$(CONFIG_XEN_FBDEV_FRONTEND) += xen-fbfront.o 123obj-$(CONFIG_XEN_FBDEV_FRONTEND) += xen-fbfront.o
124obj-$(CONFIG_FB_CARMINE) += carminefb.o
120 125
121# Platform or fallback drivers go here 126# Platform or fallback drivers go here
122obj-$(CONFIG_FB_UVESA) += uvesafb.o 127obj-$(CONFIG_FB_UVESA) += uvesafb.o
diff --git a/drivers/video/acornfb.c b/drivers/video/acornfb.c
index eedb8285e32f..017233d0c481 100644
--- a/drivers/video/acornfb.c
+++ b/drivers/video/acornfb.c
@@ -23,6 +23,7 @@
23#include <linux/string.h> 23#include <linux/string.h>
24#include <linux/ctype.h> 24#include <linux/ctype.h>
25#include <linux/slab.h> 25#include <linux/slab.h>
26#include <linux/mm.h>
26#include <linux/init.h> 27#include <linux/init.h>
27#include <linux/fb.h> 28#include <linux/fb.h>
28#include <linux/platform_device.h> 29#include <linux/platform_device.h>
diff --git a/drivers/video/amifb.c b/drivers/video/amifb.c
index 45c154ade9ca..b8e9a8682f2d 100644
--- a/drivers/video/amifb.c
+++ b/drivers/video/amifb.c
@@ -1136,7 +1136,6 @@ static int amifb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg
1136 * Interface to the low level console driver 1136 * Interface to the low level console driver
1137 */ 1137 */
1138 1138
1139int amifb_init(void);
1140static void amifb_deinit(void); 1139static void amifb_deinit(void);
1141 1140
1142 /* 1141 /*
@@ -2048,13 +2047,16 @@ static void amifb_copyarea(struct fb_info *info,
2048 width = x2 - dx; 2047 width = x2 - dx;
2049 height = y2 - dy; 2048 height = y2 - dy;
2050 2049
2050 if (area->sx + dx < area->dx || area->sy + dy < area->dy)
2051 return;
2052
2051 /* update sx,sy */ 2053 /* update sx,sy */
2052 sx = area->sx + (dx - area->dx); 2054 sx = area->sx + (dx - area->dx);
2053 sy = area->sy + (dy - area->dy); 2055 sy = area->sy + (dy - area->dy);
2054 2056
2055 /* the source must be completely inside the virtual screen */ 2057 /* the source must be completely inside the virtual screen */
2056 if (sx < 0 || sy < 0 || (sx + width) > info->var.xres_virtual || 2058 if (sx + width > info->var.xres_virtual ||
2057 (sy + height) > info->var.yres_virtual) 2059 sy + height > info->var.yres_virtual)
2058 return; 2060 return;
2059 2061
2060 if (dy > sy || (dy == sy && dx > sx)) { 2062 if (dy > sy || (dy == sy && dx > sx)) {
@@ -2245,7 +2247,7 @@ static inline void chipfree(void)
2245 * Initialisation 2247 * Initialisation
2246 */ 2248 */
2247 2249
2248int __init amifb_init(void) 2250static int __init amifb_init(void)
2249{ 2251{
2250 int tag, i, err = 0; 2252 int tag, i, err = 0;
2251 u_long chipptr; 2253 u_long chipptr;
@@ -3790,16 +3792,14 @@ static void ami_rebuild_copper(void)
3790 } 3792 }
3791} 3793}
3792 3794
3793 3795static void __exit amifb_exit(void)
3794module_init(amifb_init);
3795
3796#ifdef MODULE
3797MODULE_LICENSE("GPL");
3798
3799void cleanup_module(void)
3800{ 3796{
3801 unregister_framebuffer(&fb_info); 3797 unregister_framebuffer(&fb_info);
3802 amifb_deinit(); 3798 amifb_deinit();
3803 amifb_video_off(); 3799 amifb_video_off();
3804} 3800}
3805#endif /* MODULE */ 3801
3802module_init(amifb_init);
3803module_exit(amifb_exit);
3804
3805MODULE_LICENSE("GPL");
diff --git a/drivers/video/atafb.c b/drivers/video/atafb.c
index fa55d356b535..77eb8b34fbfa 100644
--- a/drivers/video/atafb.c
+++ b/drivers/video/atafb.c
@@ -2593,13 +2593,16 @@ static void atafb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
2593 width = x2 - dx; 2593 width = x2 - dx;
2594 height = y2 - dy; 2594 height = y2 - dy;
2595 2595
2596 if (area->sx + dx < area->dx || area->sy + dy < area->dy)
2597 return;
2598
2596 /* update sx,sy */ 2599 /* update sx,sy */
2597 sx = area->sx + (dx - area->dx); 2600 sx = area->sx + (dx - area->dx);
2598 sy = area->sy + (dy - area->dy); 2601 sy = area->sy + (dy - area->dy);
2599 2602
2600 /* the source must be completely inside the virtual screen */ 2603 /* the source must be completely inside the virtual screen */
2601 if (sx < 0 || sy < 0 || (sx + width) > info->var.xres_virtual || 2604 if (sx + width > info->var.xres_virtual ||
2602 (sy + height) > info->var.yres_virtual) 2605 sy + height > info->var.yres_virtual)
2603 return; 2606 return;
2604 2607
2605 if (dy > sy || (dy == sy && dx > sx)) { 2608 if (dy > sy || (dy == sy && dx > sx)) {
diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
index b004036d4087..5b3a15dffb5f 100644
--- a/drivers/video/atmel_lcdfb.c
+++ b/drivers/video/atmel_lcdfb.c
@@ -256,6 +256,20 @@ static int atmel_lcdfb_alloc_video_memory(struct atmel_lcdfb_info *sinfo)
256 return 0; 256 return 0;
257} 257}
258 258
259static const struct fb_videomode *atmel_lcdfb_choose_mode(struct fb_var_screeninfo *var,
260 struct fb_info *info)
261{
262 struct fb_videomode varfbmode;
263 const struct fb_videomode *fbmode = NULL;
264
265 fb_var_to_videomode(&varfbmode, var);
266 fbmode = fb_find_nearest_mode(&varfbmode, &info->modelist);
267 if (fbmode)
268 fb_videomode_to_var(var, fbmode);
269 return fbmode;
270}
271
272
259/** 273/**
260 * atmel_lcdfb_check_var - Validates a var passed in. 274 * atmel_lcdfb_check_var - Validates a var passed in.
261 * @var: frame buffer variable screen structure 275 * @var: frame buffer variable screen structure
@@ -289,6 +303,15 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var,
289 clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000; 303 clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000;
290 304
291 dev_dbg(dev, "%s:\n", __func__); 305 dev_dbg(dev, "%s:\n", __func__);
306
307 if (!(var->pixclock && var->bits_per_pixel)) {
308 /* choose a suitable mode if possible */
309 if (!atmel_lcdfb_choose_mode(var, info)) {
310 dev_err(dev, "needed value not specified\n");
311 return -EINVAL;
312 }
313 }
314
292 dev_dbg(dev, " resolution: %ux%u\n", var->xres, var->yres); 315 dev_dbg(dev, " resolution: %ux%u\n", var->xres, var->yres);
293 dev_dbg(dev, " pixclk: %lu KHz\n", PICOS2KHZ(var->pixclock)); 316 dev_dbg(dev, " pixclk: %lu KHz\n", PICOS2KHZ(var->pixclock));
294 dev_dbg(dev, " bpp: %u\n", var->bits_per_pixel); 317 dev_dbg(dev, " bpp: %u\n", var->bits_per_pixel);
@@ -299,6 +322,13 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var,
299 return -EINVAL; 322 return -EINVAL;
300 } 323 }
301 324
325 /* Do not allow to have real resoulution larger than virtual */
326 if (var->xres > var->xres_virtual)
327 var->xres_virtual = var->xres;
328
329 if (var->yres > var->yres_virtual)
330 var->yres_virtual = var->yres;
331
302 /* Force same alignment for each line */ 332 /* Force same alignment for each line */
303 var->xres = (var->xres + 3) & ~3UL; 333 var->xres = (var->xres + 3) & ~3UL;
304 var->xres_virtual = (var->xres_virtual + 3) & ~3UL; 334 var->xres_virtual = (var->xres_virtual + 3) & ~3UL;
@@ -379,6 +409,35 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var,
379 return 0; 409 return 0;
380} 410}
381 411
412/*
413 * LCD reset sequence
414 */
415static void atmel_lcdfb_reset(struct atmel_lcdfb_info *sinfo)
416{
417 might_sleep();
418
419 /* LCD power off */
420 lcdc_writel(sinfo, ATMEL_LCDC_PWRCON, sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET);
421
422 /* wait for the LCDC core to become idle */
423 while (lcdc_readl(sinfo, ATMEL_LCDC_PWRCON) & ATMEL_LCDC_BUSY)
424 msleep(10);
425
426 /* DMA disable */
427 lcdc_writel(sinfo, ATMEL_LCDC_DMACON, 0);
428
429 /* wait for DMA engine to become idle */
430 while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY)
431 msleep(10);
432
433 /* LCD power on */
434 lcdc_writel(sinfo, ATMEL_LCDC_PWRCON,
435 (sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET) | ATMEL_LCDC_PWR);
436
437 /* DMA enable */
438 lcdc_writel(sinfo, ATMEL_LCDC_DMACON, sinfo->default_dmacon);
439}
440
382/** 441/**
383 * atmel_lcdfb_set_par - Alters the hardware state. 442 * atmel_lcdfb_set_par - Alters the hardware state.
384 * @info: frame buffer structure that represents a single frame buffer 443 * @info: frame buffer structure that represents a single frame buffer
@@ -401,6 +460,8 @@ static int atmel_lcdfb_set_par(struct fb_info *info)
401 unsigned long clk_value_khz; 460 unsigned long clk_value_khz;
402 unsigned long bits_per_line; 461 unsigned long bits_per_line;
403 462
463 might_sleep();
464
404 dev_dbg(info->device, "%s:\n", __func__); 465 dev_dbg(info->device, "%s:\n", __func__);
405 dev_dbg(info->device, " * resolution: %ux%u (%ux%u virtual)\n", 466 dev_dbg(info->device, " * resolution: %ux%u (%ux%u virtual)\n",
406 info->var.xres, info->var.yres, 467 info->var.xres, info->var.yres,
@@ -511,6 +572,8 @@ static int atmel_lcdfb_set_par(struct fb_info *info)
511 572
512 /* Disable all interrupts */ 573 /* Disable all interrupts */
513 lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL); 574 lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL);
575 /* Enable FIFO & DMA errors */
576 lcdc_writel(sinfo, ATMEL_LCDC_IER, ATMEL_LCDC_UFLWI | ATMEL_LCDC_OWRI | ATMEL_LCDC_MERI);
514 577
515 /* ...wait for DMA engine to become idle... */ 578 /* ...wait for DMA engine to become idle... */
516 while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY) 579 while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY)
@@ -645,10 +708,26 @@ static irqreturn_t atmel_lcdfb_interrupt(int irq, void *dev_id)
645 u32 status; 708 u32 status;
646 709
647 status = lcdc_readl(sinfo, ATMEL_LCDC_ISR); 710 status = lcdc_readl(sinfo, ATMEL_LCDC_ISR);
648 lcdc_writel(sinfo, ATMEL_LCDC_IDR, status); 711 if (status & ATMEL_LCDC_UFLWI) {
712 dev_warn(info->device, "FIFO underflow %#x\n", status);
713 /* reset DMA and FIFO to avoid screen shifting */
714 schedule_work(&sinfo->task);
715 }
716 lcdc_writel(sinfo, ATMEL_LCDC_ICR, status);
649 return IRQ_HANDLED; 717 return IRQ_HANDLED;
650} 718}
651 719
720/*
721 * LCD controller task (to reset the LCD)
722 */
723static void atmel_lcdfb_task(struct work_struct *work)
724{
725 struct atmel_lcdfb_info *sinfo =
726 container_of(work, struct atmel_lcdfb_info, task);
727
728 atmel_lcdfb_reset(sinfo);
729}
730
652static int __init atmel_lcdfb_init_fbinfo(struct atmel_lcdfb_info *sinfo) 731static int __init atmel_lcdfb_init_fbinfo(struct atmel_lcdfb_info *sinfo)
653{ 732{
654 struct fb_info *info = sinfo->info; 733 struct fb_info *info = sinfo->info;
@@ -691,6 +770,7 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
691 struct fb_info *info; 770 struct fb_info *info;
692 struct atmel_lcdfb_info *sinfo; 771 struct atmel_lcdfb_info *sinfo;
693 struct atmel_lcdfb_info *pdata_sinfo; 772 struct atmel_lcdfb_info *pdata_sinfo;
773 struct fb_videomode fbmode;
694 struct resource *regs = NULL; 774 struct resource *regs = NULL;
695 struct resource *map = NULL; 775 struct resource *map = NULL;
696 int ret; 776 int ret;
@@ -824,6 +904,10 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
824 goto unmap_mmio; 904 goto unmap_mmio;
825 } 905 }
826 906
907 /* Some operations on the LCDC might sleep and
908 * require a preemptible task context */
909 INIT_WORK(&sinfo->task, atmel_lcdfb_task);
910
827 ret = atmel_lcdfb_init_fbinfo(sinfo); 911 ret = atmel_lcdfb_init_fbinfo(sinfo);
828 if (ret < 0) { 912 if (ret < 0) {
829 dev_err(dev, "init fbinfo failed: %d\n", ret); 913 dev_err(dev, "init fbinfo failed: %d\n", ret);
@@ -853,6 +937,10 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
853 goto free_cmap; 937 goto free_cmap;
854 } 938 }
855 939
940 /* add selected videomode to modelist */
941 fb_var_to_videomode(&fbmode, &info->var);
942 fb_add_videomode(&fbmode, &info->modelist);
943
856 /* Power up the LCDC screen */ 944 /* Power up the LCDC screen */
857 if (sinfo->atmel_lcdfb_power_control) 945 if (sinfo->atmel_lcdfb_power_control)
858 sinfo->atmel_lcdfb_power_control(1); 946 sinfo->atmel_lcdfb_power_control(1);
@@ -866,6 +954,7 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
866free_cmap: 954free_cmap:
867 fb_dealloc_cmap(&info->cmap); 955 fb_dealloc_cmap(&info->cmap);
868unregister_irqs: 956unregister_irqs:
957 cancel_work_sync(&sinfo->task);
869 free_irq(sinfo->irq_base, info); 958 free_irq(sinfo->irq_base, info);
870unmap_mmio: 959unmap_mmio:
871 exit_backlight(sinfo); 960 exit_backlight(sinfo);
@@ -903,6 +992,7 @@ static int __exit atmel_lcdfb_remove(struct platform_device *pdev)
903 if (!sinfo) 992 if (!sinfo)
904 return 0; 993 return 0;
905 994
995 cancel_work_sync(&sinfo->task);
906 exit_backlight(sinfo); 996 exit_backlight(sinfo);
907 if (sinfo->atmel_lcdfb_power_control) 997 if (sinfo->atmel_lcdfb_power_control)
908 sinfo->atmel_lcdfb_power_control(0); 998 sinfo->atmel_lcdfb_power_control(0);
diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c
index 24ee96c4e9e9..243ea4ab20c8 100644
--- a/drivers/video/aty/aty128fb.c
+++ b/drivers/video/aty/aty128fb.c
@@ -1339,10 +1339,8 @@ static int aty128_var_to_pll(u32 period_in_ps, struct aty128_pll *pll,
1339 if (vclk * 12 < c.ppll_min) 1339 if (vclk * 12 < c.ppll_min)
1340 vclk = c.ppll_min/12; 1340 vclk = c.ppll_min/12;
1341 1341
1342 pll->post_divider = -1;
1343
1344 /* now, find an acceptable divider */ 1342 /* now, find an acceptable divider */
1345 for (i = 0; i < sizeof(post_dividers); i++) { 1343 for (i = 0; i < ARRAY_SIZE(post_dividers); i++) {
1346 output_freq = post_dividers[i] * vclk; 1344 output_freq = post_dividers[i] * vclk;
1347 if (output_freq >= c.ppll_min && output_freq <= c.ppll_max) { 1345 if (output_freq >= c.ppll_min && output_freq <= c.ppll_max) {
1348 pll->post_divider = post_dividers[i]; 1346 pll->post_divider = post_dividers[i];
@@ -1350,7 +1348,7 @@ static int aty128_var_to_pll(u32 period_in_ps, struct aty128_pll *pll,
1350 } 1348 }
1351 } 1349 }
1352 1350
1353 if (pll->post_divider < 0) 1351 if (i == ARRAY_SIZE(post_dividers))
1354 return -EINVAL; 1352 return -EINVAL;
1355 1353
1356 /* calculate feedback divider */ 1354 /* calculate feedback divider */
@@ -1872,7 +1870,7 @@ static int __devinit aty128_init(struct pci_dev *pdev, const struct pci_device_i
1872 struct fb_info *info = pci_get_drvdata(pdev); 1870 struct fb_info *info = pci_get_drvdata(pdev);
1873 struct aty128fb_par *par = info->par; 1871 struct aty128fb_par *par = info->par;
1874 struct fb_var_screeninfo var; 1872 struct fb_var_screeninfo var;
1875 char video_card[DEVICE_NAME_SIZE]; 1873 char video_card[50];
1876 u8 chip_rev; 1874 u8 chip_rev;
1877 u32 dac; 1875 u32 dac;
1878 1876
diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c
index bd4ac0bafecb..620ba8120368 100644
--- a/drivers/video/aty/atyfb_base.c
+++ b/drivers/video/aty/atyfb_base.c
@@ -424,7 +424,6 @@ static struct {
424#endif /* CONFIG_FB_ATY_CT */ 424#endif /* CONFIG_FB_ATY_CT */
425}; 425};
426 426
427/* can not fail */
428static int __devinit correct_chipset(struct atyfb_par *par) 427static int __devinit correct_chipset(struct atyfb_par *par)
429{ 428{
430 u8 rev; 429 u8 rev;
@@ -437,6 +436,9 @@ static int __devinit correct_chipset(struct atyfb_par *par)
437 if (par->pci_id == aty_chips[i].pci_id) 436 if (par->pci_id == aty_chips[i].pci_id)
438 break; 437 break;
439 438
439 if (i < 0)
440 return -ENODEV;
441
440 name = aty_chips[i].name; 442 name = aty_chips[i].name;
441 par->pll_limits.pll_max = aty_chips[i].pll; 443 par->pll_limits.pll_max = aty_chips[i].pll;
442 par->pll_limits.mclk = aty_chips[i].mclk; 444 par->pll_limits.mclk = aty_chips[i].mclk;
@@ -2229,6 +2231,7 @@ static int __devinit aty_init(struct fb_info *info)
2229 const char *ramname = NULL, *xtal; 2231 const char *ramname = NULL, *xtal;
2230 int gtb_memsize, has_var = 0; 2232 int gtb_memsize, has_var = 0;
2231 struct fb_var_screeninfo var; 2233 struct fb_var_screeninfo var;
2234 int ret;
2232 2235
2233 init_waitqueue_head(&par->vblank.wait); 2236 init_waitqueue_head(&par->vblank.wait);
2234 spin_lock_init(&par->int_lock); 2237 spin_lock_init(&par->int_lock);
@@ -2610,7 +2613,8 @@ static int __devinit aty_init(struct fb_info *info)
2610 var.yres_virtual = var.yres; 2613 var.yres_virtual = var.yres;
2611 } 2614 }
2612 2615
2613 if (atyfb_check_var(&var, info)) { 2616 ret = atyfb_check_var(&var, info);
2617 if (ret) {
2614 PRINTKE("can't set default video mode\n"); 2618 PRINTKE("can't set default video mode\n");
2615 goto aty_init_exit; 2619 goto aty_init_exit;
2616 } 2620 }
@@ -2621,10 +2625,12 @@ static int __devinit aty_init(struct fb_info *info)
2621#endif /* CONFIG_FB_ATY_CT */ 2625#endif /* CONFIG_FB_ATY_CT */
2622 info->var = var; 2626 info->var = var;
2623 2627
2624 if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) 2628 ret = fb_alloc_cmap(&info->cmap, 256, 0);
2629 if (ret < 0)
2625 goto aty_init_exit; 2630 goto aty_init_exit;
2626 2631
2627 if (register_framebuffer(info) < 0) { 2632 ret = register_framebuffer(info);
2633 if (ret < 0) {
2628 fb_dealloc_cmap(&info->cmap); 2634 fb_dealloc_cmap(&info->cmap);
2629 goto aty_init_exit; 2635 goto aty_init_exit;
2630 } 2636 }
@@ -2650,7 +2656,7 @@ aty_init_exit:
2650 par->mtrr_aper = -1; 2656 par->mtrr_aper = -1;
2651 } 2657 }
2652#endif 2658#endif
2653 return -1; 2659 return ret;
2654} 2660}
2655 2661
2656static void aty_resume_chip(struct fb_info *info) 2662static void aty_resume_chip(struct fb_info *info)
@@ -2709,8 +2715,7 @@ static int atyfb_blank(int blank, struct fb_info *info)
2709 if (par->lock_blank || par->asleep) 2715 if (par->lock_blank || par->asleep)
2710 return 0; 2716 return 0;
2711 2717
2712#ifdef CONFIG_FB_ATY_BACKLIGHT 2718#ifdef CONFIG_FB_ATY_GENERIC_LCD
2713#elif defined(CONFIG_FB_ATY_GENERIC_LCD)
2714 if (par->lcd_table && blank > FB_BLANK_NORMAL && 2719 if (par->lcd_table && blank > FB_BLANK_NORMAL &&
2715 (aty_ld_lcd(LCD_GEN_CNTL, par) & LCD_ON)) { 2720 (aty_ld_lcd(LCD_GEN_CNTL, par) & LCD_ON)) {
2716 u32 pm = aty_ld_lcd(POWER_MANAGEMENT, par); 2721 u32 pm = aty_ld_lcd(POWER_MANAGEMENT, par);
@@ -2739,8 +2744,7 @@ static int atyfb_blank(int blank, struct fb_info *info)
2739 } 2744 }
2740 aty_st_le32(CRTC_GEN_CNTL, gen_cntl, par); 2745 aty_st_le32(CRTC_GEN_CNTL, gen_cntl, par);
2741 2746
2742#ifdef CONFIG_FB_ATY_BACKLIGHT 2747#ifdef CONFIG_FB_ATY_GENERIC_LCD
2743#elif defined(CONFIG_FB_ATY_GENERIC_LCD)
2744 if (par->lcd_table && blank <= FB_BLANK_NORMAL && 2748 if (par->lcd_table && blank <= FB_BLANK_NORMAL &&
2745 (aty_ld_lcd(LCD_GEN_CNTL, par) & LCD_ON)) { 2749 (aty_ld_lcd(LCD_GEN_CNTL, par) & LCD_ON)) {
2746 u32 pm = aty_ld_lcd(POWER_MANAGEMENT, par); 2750 u32 pm = aty_ld_lcd(POWER_MANAGEMENT, par);
@@ -3331,7 +3335,7 @@ static int __devinit init_from_bios(struct atyfb_par *par)
3331 PRINTKE("no BIOS frequency table found, use parameters\n"); 3335 PRINTKE("no BIOS frequency table found, use parameters\n");
3332 ret = -ENXIO; 3336 ret = -ENXIO;
3333 } 3337 }
3334 iounmap((void* __iomem )bios_base); 3338 iounmap((void __iomem *)bios_base);
3335 3339
3336 return ret; 3340 return ret;
3337} 3341}
@@ -3418,14 +3422,7 @@ static int __devinit atyfb_pci_probe(struct pci_dev *pdev, const struct pci_devi
3418 struct fb_info *info; 3422 struct fb_info *info;
3419 struct resource *rp; 3423 struct resource *rp;
3420 struct atyfb_par *par; 3424 struct atyfb_par *par;
3421 int i, rc = -ENOMEM; 3425 int rc = -ENOMEM;
3422
3423 for (i = ARRAY_SIZE(aty_chips) - 1; i >= 0; i--)
3424 if (pdev->device == aty_chips[i].pci_id)
3425 break;
3426
3427 if (i < 0)
3428 return -ENODEV;
3429 3426
3430 /* Enable device in PCI config */ 3427 /* Enable device in PCI config */
3431 if (pci_enable_device(pdev)) { 3428 if (pci_enable_device(pdev)) {
@@ -3456,7 +3453,7 @@ static int __devinit atyfb_pci_probe(struct pci_dev *pdev, const struct pci_devi
3456 par = info->par; 3453 par = info->par;
3457 info->fix = atyfb_fix; 3454 info->fix = atyfb_fix;
3458 info->device = &pdev->dev; 3455 info->device = &pdev->dev;
3459 par->pci_id = aty_chips[i].pci_id; 3456 par->pci_id = pdev->device;
3460 par->res_start = res_start; 3457 par->res_start = res_start;
3461 par->res_size = res_size; 3458 par->res_size = res_size;
3462 par->irq = pdev->irq; 3459 par->irq = pdev->irq;
@@ -3474,7 +3471,8 @@ static int __devinit atyfb_pci_probe(struct pci_dev *pdev, const struct pci_devi
3474 pci_set_drvdata(pdev, info); 3471 pci_set_drvdata(pdev, info);
3475 3472
3476 /* Init chip & register framebuffer */ 3473 /* Init chip & register framebuffer */
3477 if (aty_init(info)) 3474 rc = aty_init(info);
3475 if (rc)
3478 goto err_release_io; 3476 goto err_release_io;
3479 3477
3480#ifdef __sparc__ 3478#ifdef __sparc__
@@ -3655,18 +3653,62 @@ static void __devexit atyfb_pci_remove(struct pci_dev *pdev)
3655 atyfb_remove(info); 3653 atyfb_remove(info);
3656} 3654}
3657 3655
3658/*
3659 * This driver uses its own matching table. That will be more difficult
3660 * to fix, so for now, we just match against any ATI ID and let the
3661 * probe() function find out what's up. That also mean we don't have
3662 * a module ID table though.
3663 */
3664static struct pci_device_id atyfb_pci_tbl[] = { 3656static struct pci_device_id atyfb_pci_tbl[] = {
3665 { PCI_VENDOR_ID_ATI, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 3657#ifdef CONFIG_FB_ATY_GX
3666 PCI_BASE_CLASS_DISPLAY << 16, 0xff0000, 0 }, 3658 { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GX) },
3667 { 0, } 3659 { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64CX) },
3660#endif /* CONFIG_FB_ATY_GX */
3661
3662#ifdef CONFIG_FB_ATY_CT
3663 { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64CT) },
3664 { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64ET) },
3665
3666 { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64LT) },
3667
3668 { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64VT) },
3669 { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GT) },
3670
3671 { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64VU) },
3672 { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GU) },
3673
3674 { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64LG) },
3675
3676 { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64VV) },
3677
3678 { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GV) },
3679 { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GW) },
3680 { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GY) },
3681 { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GZ) },
3682
3683 { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GB) },
3684 { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GD) },
3685 { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GI) },
3686 { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GP) },
3687 { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GQ) },
3688
3689 { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64LB) },
3690 { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64LD) },
3691 { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64LI) },
3692 { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64LP) },
3693 { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64LQ) },
3694
3695 { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GM) },
3696 { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GN) },
3697 { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GO) },
3698 { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GL) },
3699 { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GR) },
3700 { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GS) },
3701
3702 { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64LM) },
3703 { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64LN) },
3704 { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64LR) },
3705 { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64LS) },
3706#endif /* CONFIG_FB_ATY_CT */
3707 { }
3668}; 3708};
3669 3709
3710MODULE_DEVICE_TABLE(pci, atyfb_pci_tbl);
3711
3670static struct pci_driver atyfb_driver = { 3712static struct pci_driver atyfb_driver = {
3671 .name = "atyfb", 3713 .name = "atyfb",
3672 .id_table = atyfb_pci_tbl, 3714 .id_table = atyfb_pci_tbl,
diff --git a/drivers/video/aty/radeon_base.c b/drivers/video/aty/radeon_base.c
index 400e9264e456..652273e9f5f9 100644
--- a/drivers/video/aty/radeon_base.c
+++ b/drivers/video/aty/radeon_base.c
@@ -2098,15 +2098,7 @@ static void radeon_identify_vram(struct radeonfb_info *rinfo)
2098 2098
2099static ssize_t radeon_show_one_edid(char *buf, loff_t off, size_t count, const u8 *edid) 2099static ssize_t radeon_show_one_edid(char *buf, loff_t off, size_t count, const u8 *edid)
2100{ 2100{
2101 if (off > EDID_LENGTH) 2101 return memory_read_from_buffer(buf, count, &off, edid, EDID_LENGTH);
2102 return 0;
2103
2104 if (off + count > EDID_LENGTH)
2105 count = EDID_LENGTH - off;
2106
2107 memcpy(buf, edid + off, count);
2108
2109 return count;
2110} 2102}
2111 2103
2112 2104
@@ -2161,6 +2153,7 @@ static int __devinit radeonfb_pci_register (struct pci_dev *pdev,
2161 struct radeonfb_info *rinfo; 2153 struct radeonfb_info *rinfo;
2162 int ret; 2154 int ret;
2163 unsigned char c1, c2; 2155 unsigned char c1, c2;
2156 int err = 0;
2164 2157
2165 pr_debug("radeonfb_pci_register BEGIN\n"); 2158 pr_debug("radeonfb_pci_register BEGIN\n");
2166 2159
@@ -2340,9 +2333,14 @@ static int __devinit radeonfb_pci_register (struct pci_dev *pdev,
2340 2333
2341 /* Register some sysfs stuff (should be done better) */ 2334 /* Register some sysfs stuff (should be done better) */
2342 if (rinfo->mon1_EDID) 2335 if (rinfo->mon1_EDID)
2343 sysfs_create_bin_file(&rinfo->pdev->dev.kobj, &edid1_attr); 2336 err |= sysfs_create_bin_file(&rinfo->pdev->dev.kobj,
2337 &edid1_attr);
2344 if (rinfo->mon2_EDID) 2338 if (rinfo->mon2_EDID)
2345 sysfs_create_bin_file(&rinfo->pdev->dev.kobj, &edid2_attr); 2339 err |= sysfs_create_bin_file(&rinfo->pdev->dev.kobj,
2340 &edid2_attr);
2341 if (err)
2342 pr_warning("%s() Creating sysfs files failed, continuing\n",
2343 __func__);
2346 2344
2347 /* save current mode regs before we switch into the new one 2345 /* save current mode regs before we switch into the new one
2348 * so we can restore this upon __exit 2346 * so we can restore this upon __exit
diff --git a/drivers/video/aty/radeonfb.h b/drivers/video/aty/radeonfb.h
index c347e38cd0b0..ccbfffd12805 100644
--- a/drivers/video/aty/radeonfb.h
+++ b/drivers/video/aty/radeonfb.h
@@ -289,7 +289,7 @@ struct radeonfb_info {
289 struct radeon_regs state; 289 struct radeon_regs state;
290 struct radeon_regs init_state; 290 struct radeon_regs init_state;
291 291
292 char name[DEVICE_NAME_SIZE]; 292 char name[50];
293 293
294 unsigned long mmio_base_phys; 294 unsigned long mmio_base_phys;
295 unsigned long fb_base_phys; 295 unsigned long fb_base_phys;
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index 30bf7f2f1635..452b770d8cc9 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -36,6 +36,30 @@ config LCD_LTV350QV
36 36
37 The LTV350QV panel is present on all ATSTK1000 boards. 37 The LTV350QV panel is present on all ATSTK1000 boards.
38 38
39config LCD_ILI9320
40 tristate
41 depends on LCD_CLASS_DEVICE && BACKLIGHT_LCD_SUPPORT
42 default n
43 help
44 If you have a panel based on the ILI9320 controller chip
45 then say y to include a power driver for it.
46
47config LCD_VGG2432A4
48 tristate "VGG2432A4 LCM device support"
49 depends on BACKLIGHT_LCD_SUPPORT && LCD_CLASS_DEVICE && SPI_MASTER
50 select LCD_ILI9320
51 default n
52 help
53 If you have a VGG2432A4 panel based on the ILI9320 controller chip
54 then say y to include a power driver for it.
55
56config LCD_PLATFORM
57 tristate "Platform LCD controls"
58 depends on LCD_CLASS_DEVICE
59 help
60 This driver provides a platform-device registered LCD power
61 control interface.
62
39# 63#
40# Backlight 64# Backlight
41# 65#
@@ -63,6 +87,18 @@ config BACKLIGHT_ATMEL_LCDC
63 If in doubt, it's safe to enable this option; it doesn't kick 87 If in doubt, it's safe to enable this option; it doesn't kick
64 in unless the board's description says it's wired that way. 88 in unless the board's description says it's wired that way.
65 89
90config BACKLIGHT_ATMEL_PWM
91 tristate "Atmel PWM backlight control"
92 depends on BACKLIGHT_CLASS_DEVICE && ATMEL_PWM
93 default n
94 help
95 Say Y here if you want to use the PWM peripheral in Atmel AT91 and
96 AVR32 devices. This driver will need additional platform data to know
97 which PWM instance to use and how to configure it.
98
99 To compile this driver as a module, choose M here: the module will be
100 called atmel-pwm-bl.
101
66config BACKLIGHT_CORGI 102config BACKLIGHT_CORGI
67 tristate "Generic (aka Sharp Corgi) Backlight Driver" 103 tristate "Generic (aka Sharp Corgi) Backlight Driver"
68 depends on BACKLIGHT_CLASS_DEVICE 104 depends on BACKLIGHT_CLASS_DEVICE
@@ -119,3 +155,12 @@ config BACKLIGHT_PWM
119 help 155 help
120 If you have a LCD backlight adjustable by PWM, say Y to enable 156 If you have a LCD backlight adjustable by PWM, say Y to enable
121 this driver. 157 this driver.
158
159config BACKLIGHT_MBP_NVIDIA
160 tristate "MacBook Pro Nvidia Backlight Driver"
161 depends on BACKLIGHT_CLASS_DEVICE && X86
162 default n
163 help
164 If you have an Apple Macbook Pro with Nvidia graphics hardware say Y
165 to enable a driver for its backlight
166
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
index b51a7cd12500..b405aace803f 100644
--- a/drivers/video/backlight/Makefile
+++ b/drivers/video/backlight/Makefile
@@ -1,9 +1,13 @@
1# Backlight & LCD drivers 1# Backlight & LCD drivers
2 2
3obj-$(CONFIG_LCD_CLASS_DEVICE) += lcd.o 3obj-$(CONFIG_LCD_CLASS_DEVICE) += lcd.o
4obj-$(CONFIG_LCD_LTV350QV) += ltv350qv.o 4obj-$(CONFIG_LCD_LTV350QV) += ltv350qv.o
5obj-$(CONFIG_LCD_ILI9320) += ili9320.o
6obj-$(CONFIG_LCD_PLATFORM) += platform_lcd.o
7obj-$(CONFIG_LCD_VGG2432A4) += vgg2432a4.o
5 8
6obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o 9obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o
10obj-$(CONFIG_BACKLIGHT_ATMEL_PWM) += atmel-pwm-bl.o
7obj-$(CONFIG_BACKLIGHT_CORGI) += corgi_bl.o 11obj-$(CONFIG_BACKLIGHT_CORGI) += corgi_bl.o
8obj-$(CONFIG_BACKLIGHT_HP680) += hp680_bl.o 12obj-$(CONFIG_BACKLIGHT_HP680) += hp680_bl.o
9obj-$(CONFIG_BACKLIGHT_LOCOMO) += locomolcd.o 13obj-$(CONFIG_BACKLIGHT_LOCOMO) += locomolcd.o
@@ -11,3 +15,5 @@ obj-$(CONFIG_BACKLIGHT_OMAP1) += omap1_bl.o
11obj-$(CONFIG_BACKLIGHT_PROGEAR) += progear_bl.o 15obj-$(CONFIG_BACKLIGHT_PROGEAR) += progear_bl.o
12obj-$(CONFIG_BACKLIGHT_CARILLO_RANCH) += cr_bllcd.o 16obj-$(CONFIG_BACKLIGHT_CARILLO_RANCH) += cr_bllcd.o
13obj-$(CONFIG_BACKLIGHT_PWM) += pwm_bl.o 17obj-$(CONFIG_BACKLIGHT_PWM) += pwm_bl.o
18obj-$(CONFIG_BACKLIGHT_MBP_NVIDIA) += mbp_nvidia_bl.o
19
diff --git a/drivers/video/backlight/atmel-pwm-bl.c b/drivers/video/backlight/atmel-pwm-bl.c
new file mode 100644
index 000000000000..505c0823a105
--- /dev/null
+++ b/drivers/video/backlight/atmel-pwm-bl.c
@@ -0,0 +1,244 @@
1/*
2 * Copyright (C) 2008 Atmel Corporation
3 *
4 * Backlight driver using Atmel PWM peripheral.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 2 as published by
8 * the Free Software Foundation.
9 */
10#include <linux/init.h>
11#include <linux/kernel.h>
12#include <linux/module.h>
13#include <linux/platform_device.h>
14#include <linux/fb.h>
15#include <linux/clk.h>
16#include <linux/gpio.h>
17#include <linux/backlight.h>
18#include <linux/atmel_pwm.h>
19#include <linux/atmel-pwm-bl.h>
20
21struct atmel_pwm_bl {
22 const struct atmel_pwm_bl_platform_data *pdata;
23 struct backlight_device *bldev;
24 struct platform_device *pdev;
25 struct pwm_channel pwmc;
26 int gpio_on;
27};
28
29static int atmel_pwm_bl_set_intensity(struct backlight_device *bd)
30{
31 struct atmel_pwm_bl *pwmbl = bl_get_data(bd);
32 int intensity = bd->props.brightness;
33 int pwm_duty;
34
35 if (bd->props.power != FB_BLANK_UNBLANK)
36 intensity = 0;
37 if (bd->props.fb_blank != FB_BLANK_UNBLANK)
38 intensity = 0;
39
40 if (pwmbl->pdata->pwm_active_low)
41 pwm_duty = pwmbl->pdata->pwm_duty_min + intensity;
42 else
43 pwm_duty = pwmbl->pdata->pwm_duty_max - intensity;
44
45 if (pwm_duty > pwmbl->pdata->pwm_duty_max)
46 pwm_duty = pwmbl->pdata->pwm_duty_max;
47 if (pwm_duty < pwmbl->pdata->pwm_duty_min)
48 pwm_duty = pwmbl->pdata->pwm_duty_min;
49
50 if (!intensity) {
51 if (pwmbl->gpio_on != -1) {
52 gpio_set_value(pwmbl->gpio_on,
53 0 ^ pwmbl->pdata->on_active_low);
54 }
55 pwm_channel_writel(&pwmbl->pwmc, PWM_CUPD, pwm_duty);
56 pwm_channel_disable(&pwmbl->pwmc);
57 } else {
58 pwm_channel_enable(&pwmbl->pwmc);
59 pwm_channel_writel(&pwmbl->pwmc, PWM_CUPD, pwm_duty);
60 if (pwmbl->gpio_on != -1) {
61 gpio_set_value(pwmbl->gpio_on,
62 1 ^ pwmbl->pdata->on_active_low);
63 }
64 }
65
66 return 0;
67}
68
69static int atmel_pwm_bl_get_intensity(struct backlight_device *bd)
70{
71 struct atmel_pwm_bl *pwmbl = bl_get_data(bd);
72 u8 intensity;
73
74 if (pwmbl->pdata->pwm_active_low) {
75 intensity = pwm_channel_readl(&pwmbl->pwmc, PWM_CDTY) -
76 pwmbl->pdata->pwm_duty_min;
77 } else {
78 intensity = pwmbl->pdata->pwm_duty_max -
79 pwm_channel_readl(&pwmbl->pwmc, PWM_CDTY);
80 }
81
82 return intensity;
83}
84
85static int atmel_pwm_bl_init_pwm(struct atmel_pwm_bl *pwmbl)
86{
87 unsigned long pwm_rate = pwmbl->pwmc.mck;
88 unsigned long prescale = DIV_ROUND_UP(pwm_rate,
89 (pwmbl->pdata->pwm_frequency *
90 pwmbl->pdata->pwm_compare_max)) - 1;
91
92 /*
93 * Prescale must be power of two and maximum 0xf in size because of
94 * hardware limit. PWM speed will be:
95 * PWM module clock speed / (2 ^ prescale).
96 */
97 prescale = fls(prescale);
98 if (prescale > 0xf)
99 prescale = 0xf;
100
101 pwm_channel_writel(&pwmbl->pwmc, PWM_CMR, prescale);
102 pwm_channel_writel(&pwmbl->pwmc, PWM_CDTY,
103 pwmbl->pdata->pwm_duty_min +
104 pwmbl->bldev->props.brightness);
105 pwm_channel_writel(&pwmbl->pwmc, PWM_CPRD,
106 pwmbl->pdata->pwm_compare_max);
107
108 dev_info(&pwmbl->pdev->dev, "Atmel PWM backlight driver "
109 "(%lu Hz)\n", pwmbl->pwmc.mck /
110 pwmbl->pdata->pwm_compare_max /
111 (1 << prescale));
112
113 return pwm_channel_enable(&pwmbl->pwmc);
114}
115
116static struct backlight_ops atmel_pwm_bl_ops = {
117 .get_brightness = atmel_pwm_bl_get_intensity,
118 .update_status = atmel_pwm_bl_set_intensity,
119};
120
121static int atmel_pwm_bl_probe(struct platform_device *pdev)
122{
123 const struct atmel_pwm_bl_platform_data *pdata;
124 struct backlight_device *bldev;
125 struct atmel_pwm_bl *pwmbl;
126 int retval;
127
128 pwmbl = kzalloc(sizeof(struct atmel_pwm_bl), GFP_KERNEL);
129 if (!pwmbl)
130 return -ENOMEM;
131
132 pwmbl->pdev = pdev;
133
134 pdata = pdev->dev.platform_data;
135 if (!pdata) {
136 retval = -ENODEV;
137 goto err_free_mem;
138 }
139
140 if (pdata->pwm_compare_max < pdata->pwm_duty_max ||
141 pdata->pwm_duty_min > pdata->pwm_duty_max ||
142 pdata->pwm_frequency == 0) {
143 retval = -EINVAL;
144 goto err_free_mem;
145 }
146
147 pwmbl->pdata = pdata;
148 pwmbl->gpio_on = pdata->gpio_on;
149
150 retval = pwm_channel_alloc(pdata->pwm_channel, &pwmbl->pwmc);
151 if (retval)
152 goto err_free_mem;
153
154 if (pwmbl->gpio_on != -1) {
155 retval = gpio_request(pwmbl->gpio_on, "gpio_atmel_pwm_bl");
156 if (retval) {
157 pwmbl->gpio_on = -1;
158 goto err_free_pwm;
159 }
160
161 /* Turn display off by defatult. */
162 retval = gpio_direction_output(pwmbl->gpio_on,
163 0 ^ pdata->on_active_low);
164 if (retval)
165 goto err_free_gpio;
166 }
167
168 bldev = backlight_device_register("atmel-pwm-bl",
169 &pdev->dev, pwmbl, &atmel_pwm_bl_ops);
170 if (IS_ERR(bldev)) {
171 retval = PTR_ERR(bldev);
172 goto err_free_gpio;
173 }
174
175 pwmbl->bldev = bldev;
176
177 platform_set_drvdata(pdev, pwmbl);
178
179 /* Power up the backlight by default at middle intesity. */
180 bldev->props.power = FB_BLANK_UNBLANK;
181 bldev->props.max_brightness = pdata->pwm_duty_max - pdata->pwm_duty_min;
182 bldev->props.brightness = bldev->props.max_brightness / 2;
183
184 retval = atmel_pwm_bl_init_pwm(pwmbl);
185 if (retval)
186 goto err_free_bl_dev;
187
188 atmel_pwm_bl_set_intensity(bldev);
189
190 return 0;
191
192err_free_bl_dev:
193 platform_set_drvdata(pdev, NULL);
194 backlight_device_unregister(bldev);
195err_free_gpio:
196 if (pwmbl->gpio_on != -1)
197 gpio_free(pwmbl->gpio_on);
198err_free_pwm:
199 pwm_channel_free(&pwmbl->pwmc);
200err_free_mem:
201 kfree(pwmbl);
202 return retval;
203}
204
205static int __exit atmel_pwm_bl_remove(struct platform_device *pdev)
206{
207 struct atmel_pwm_bl *pwmbl = platform_get_drvdata(pdev);
208
209 if (pwmbl->gpio_on != -1) {
210 gpio_set_value(pwmbl->gpio_on, 0);
211 gpio_free(pwmbl->gpio_on);
212 }
213 pwm_channel_disable(&pwmbl->pwmc);
214 pwm_channel_free(&pwmbl->pwmc);
215 backlight_device_unregister(pwmbl->bldev);
216 platform_set_drvdata(pdev, NULL);
217 kfree(pwmbl);
218
219 return 0;
220}
221
222static struct platform_driver atmel_pwm_bl_driver = {
223 .driver = {
224 .name = "atmel-pwm-bl",
225 },
226 /* REVISIT add suspend() and resume() */
227 .remove = __exit_p(atmel_pwm_bl_remove),
228};
229
230static int __init atmel_pwm_bl_init(void)
231{
232 return platform_driver_probe(&atmel_pwm_bl_driver, atmel_pwm_bl_probe);
233}
234module_init(atmel_pwm_bl_init);
235
236static void __exit atmel_pwm_bl_exit(void)
237{
238 platform_driver_unregister(&atmel_pwm_bl_driver);
239}
240module_exit(atmel_pwm_bl_exit);
241
242MODULE_AUTHOR("Hans-Christian egtvedt <hans-christian.egtvedt@atmel.com>");
243MODULE_DESCRIPTION("Atmel PWM backlight driver");
244MODULE_LICENSE("GPL");
diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c
index 39394757679c..fab0bc874b58 100644
--- a/drivers/video/backlight/backlight.c
+++ b/drivers/video/backlight/backlight.c
@@ -191,6 +191,7 @@ static struct device_attribute bl_device_attributes[] = {
191 * backlight_device class. 191 * backlight_device class.
192 * @name: the name of the new object(must be the same as the name of the 192 * @name: the name of the new object(must be the same as the name of the
193 * respective framebuffer device). 193 * respective framebuffer device).
194 * @parent: a pointer to the parent device
194 * @devdata: an optional pointer to be stored for private driver use. The 195 * @devdata: an optional pointer to be stored for private driver use. The
195 * methods may retrieve it by using bl_get_data(bd). 196 * methods may retrieve it by using bl_get_data(bd).
196 * @ops: the backlight operations structure. 197 * @ops: the backlight operations structure.
diff --git a/drivers/video/backlight/ili9320.c b/drivers/video/backlight/ili9320.c
new file mode 100644
index 000000000000..ba89b41b639c
--- /dev/null
+++ b/drivers/video/backlight/ili9320.c
@@ -0,0 +1,330 @@
1/* drivers/video/backlight/ili9320.c
2 *
3 * ILI9320 LCD controller driver core.
4 *
5 * Copyright 2007 Simtec Electronics
6 * http://armlinux.simtec.co.uk/
7 * Ben Dooks <ben@simtec.co.uk>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12*/
13
14#include <linux/delay.h>
15#include <linux/err.h>
16#include <linux/fb.h>
17#include <linux/init.h>
18#include <linux/lcd.h>
19#include <linux/module.h>
20
21#include <linux/spi/spi.h>
22
23#include <video/ili9320.h>
24
25#include "ili9320.h"
26
27
28static inline int ili9320_write_spi(struct ili9320 *ili,
29 unsigned int reg,
30 unsigned int value)
31{
32 struct ili9320_spi *spi = &ili->access.spi;
33 unsigned char *addr = spi->buffer_addr;
34 unsigned char *data = spi->buffer_data;
35
36 /* spi message consits of:
37 * first byte: ID and operation
38 */
39
40 addr[0] = spi->id | ILI9320_SPI_INDEX | ILI9320_SPI_WRITE;
41 addr[1] = reg >> 8;
42 addr[2] = reg;
43
44 /* second message is the data to transfer */
45
46 data[0] = spi->id | ILI9320_SPI_DATA | ILI9320_SPI_WRITE;
47 data[1] = value >> 8;
48 data[2] = value;
49
50 return spi_sync(spi->dev, &spi->message);
51}
52
53int ili9320_write(struct ili9320 *ili, unsigned int reg, unsigned int value)
54{
55 dev_dbg(ili->dev, "write: reg=%02x, val=%04x\n", reg, value);
56 return ili->write(ili, reg, value);
57}
58
59EXPORT_SYMBOL_GPL(ili9320_write);
60
61int ili9320_write_regs(struct ili9320 *ili,
62 struct ili9320_reg *values,
63 int nr_values)
64{
65 int index;
66 int ret;
67
68 for (index = 0; index < nr_values; index++, values++) {
69 ret = ili9320_write(ili, values->address, values->value);
70 if (ret != 0)
71 return ret;
72 }
73
74 return 0;
75}
76
77EXPORT_SYMBOL_GPL(ili9320_write_regs);
78
79static void ili9320_reset(struct ili9320 *lcd)
80{
81 struct ili9320_platdata *cfg = lcd->platdata;
82
83 cfg->reset(1);
84 mdelay(50);
85
86 cfg->reset(0);
87 mdelay(50);
88
89 cfg->reset(1);
90 mdelay(100);
91}
92
93static inline int ili9320_init_chip(struct ili9320 *lcd)
94{
95 int ret;
96
97 ili9320_reset(lcd);
98
99 ret = lcd->client->init(lcd, lcd->platdata);
100 if (ret != 0) {
101 dev_err(lcd->dev, "failed to initialise display\n");
102 return ret;
103 }
104
105 lcd->initialised = 1;
106 return 0;
107}
108
109static inline int ili9320_power_on(struct ili9320 *lcd)
110{
111 if (!lcd->initialised)
112 ili9320_init_chip(lcd);
113
114 lcd->display1 |= (ILI9320_DISPLAY1_D(3) | ILI9320_DISPLAY1_BASEE);
115 ili9320_write(lcd, ILI9320_DISPLAY1, lcd->display1);
116
117 return 0;
118}
119
120static inline int ili9320_power_off(struct ili9320 *lcd)
121{
122 lcd->display1 &= ~(ILI9320_DISPLAY1_D(3) | ILI9320_DISPLAY1_BASEE);
123 ili9320_write(lcd, ILI9320_DISPLAY1, lcd->display1);
124
125 return 0;
126}
127
128#define POWER_IS_ON(pwr) ((pwr) <= FB_BLANK_NORMAL)
129
130static int ili9320_power(struct ili9320 *lcd, int power)
131{
132 int ret = 0;
133
134 dev_dbg(lcd->dev, "power %d => %d\n", lcd->power, power);
135
136 if (POWER_IS_ON(power) && !POWER_IS_ON(lcd->power))
137 ret = ili9320_power_on(lcd);
138 else if (!POWER_IS_ON(power) && POWER_IS_ON(lcd->power))
139 ret = ili9320_power_off(lcd);
140
141 if (ret == 0)
142 lcd->power = power;
143 else
144 dev_warn(lcd->dev, "failed to set power mode %d\n", power);
145
146 return ret;
147}
148
149static inline struct ili9320 *to_our_lcd(struct lcd_device *lcd)
150{
151 return lcd_get_data(lcd);
152}
153
154static int ili9320_set_power(struct lcd_device *ld, int power)
155{
156 struct ili9320 *lcd = to_our_lcd(ld);
157
158 return ili9320_power(lcd, power);
159}
160
161static int ili9320_get_power(struct lcd_device *ld)
162{
163 struct ili9320 *lcd = to_our_lcd(ld);
164
165 return lcd->power;
166}
167
168static struct lcd_ops ili9320_ops = {
169 .get_power = ili9320_get_power,
170 .set_power = ili9320_set_power,
171};
172
173static void __devinit ili9320_setup_spi(struct ili9320 *ili,
174 struct spi_device *dev)
175{
176 struct ili9320_spi *spi = &ili->access.spi;
177
178 ili->write = ili9320_write_spi;
179 spi->dev = dev;
180
181 /* fill the two messages we are going to use to send the data
182 * with, the first the address followed by the data. The datasheet
183 * says they should be done as two distinct cycles of the SPI CS line.
184 */
185
186 spi->xfer[0].tx_buf = spi->buffer_addr;
187 spi->xfer[1].tx_buf = spi->buffer_data;
188 spi->xfer[0].len = 3;
189 spi->xfer[1].len = 3;
190 spi->xfer[0].bits_per_word = 8;
191 spi->xfer[1].bits_per_word = 8;
192 spi->xfer[0].cs_change = 1;
193
194 spi_message_init(&spi->message);
195 spi_message_add_tail(&spi->xfer[0], &spi->message);
196 spi_message_add_tail(&spi->xfer[1], &spi->message);
197}
198
199int __devinit ili9320_probe_spi(struct spi_device *spi,
200 struct ili9320_client *client)
201{
202 struct ili9320_platdata *cfg = spi->dev.platform_data;
203 struct device *dev = &spi->dev;
204 struct ili9320 *ili;
205 struct lcd_device *lcd;
206 int ret = 0;
207
208 /* verify we where given some information */
209
210 if (cfg == NULL) {
211 dev_err(dev, "no platform data supplied\n");
212 return -EINVAL;
213 }
214
215 if (cfg->hsize <= 0 || cfg->vsize <= 0 || cfg->reset == NULL) {
216 dev_err(dev, "invalid platform data supplied\n");
217 return -EINVAL;
218 }
219
220 /* allocate and initialse our state */
221
222 ili = kzalloc(sizeof(struct ili9320), GFP_KERNEL);
223 if (ili == NULL) {
224 dev_err(dev, "no memory for device\n");
225 return -ENOMEM;
226 }
227
228 ili->access.spi.id = ILI9320_SPI_IDCODE | ILI9320_SPI_ID(1);
229
230 ili->dev = dev;
231 ili->client = client;
232 ili->power = FB_BLANK_POWERDOWN;
233 ili->platdata = cfg;
234
235 dev_set_drvdata(&spi->dev, ili);
236
237 ili9320_setup_spi(ili, spi);
238
239 lcd = lcd_device_register("ili9320", dev, ili, &ili9320_ops);
240 if (IS_ERR(lcd)) {
241 dev_err(dev, "failed to register lcd device\n");
242 ret = PTR_ERR(lcd);
243 goto err_free;
244 }
245
246 ili->lcd = lcd;
247
248 dev_info(dev, "initialising %s\n", client->name);
249
250 ret = ili9320_power(ili, FB_BLANK_UNBLANK);
251 if (ret != 0) {
252 dev_err(dev, "failed to set lcd power state\n");
253 goto err_unregister;
254 }
255
256 return 0;
257
258 err_unregister:
259 lcd_device_unregister(lcd);
260
261 err_free:
262 kfree(ili);
263
264 return ret;
265}
266
267EXPORT_SYMBOL_GPL(ili9320_probe_spi);
268
269int __devexit ili9320_remove(struct ili9320 *ili)
270{
271 ili9320_power(ili, FB_BLANK_POWERDOWN);
272
273 lcd_device_unregister(ili->lcd);
274 kfree(ili);
275
276 return 0;
277}
278
279EXPORT_SYMBOL_GPL(ili9320_remove);
280
281#ifdef CONFIG_PM
282int ili9320_suspend(struct ili9320 *lcd, pm_message_t state)
283{
284 int ret;
285
286 dev_dbg(lcd->dev, "%s: event %d\n", __func__, state.event);
287
288 if (state.event == PM_EVENT_SUSPEND) {
289 ret = ili9320_power(lcd, FB_BLANK_POWERDOWN);
290
291 if (lcd->platdata->suspend == ILI9320_SUSPEND_DEEP) {
292 ili9320_write(lcd, ILI9320_POWER1, lcd->power1 |
293 ILI9320_POWER1_SLP |
294 ILI9320_POWER1_DSTB);
295 lcd->initialised = 0;
296 }
297
298 return ret;
299 }
300
301 return 0;
302}
303
304EXPORT_SYMBOL_GPL(ili9320_suspend);
305
306int ili9320_resume(struct ili9320 *lcd)
307{
308 dev_info(lcd->dev, "resuming from power state %d\n", lcd->power);
309
310 if (lcd->platdata->suspend == ILI9320_SUSPEND_DEEP) {
311 ili9320_write(lcd, ILI9320_POWER1, 0x00);
312 }
313
314 return ili9320_power(lcd, FB_BLANK_UNBLANK);
315}
316
317EXPORT_SYMBOL_GPL(ili9320_resume);
318#endif
319
320/* Power down all displays on reboot, poweroff or halt */
321void ili9320_shutdown(struct ili9320 *lcd)
322{
323 ili9320_power(lcd, FB_BLANK_POWERDOWN);
324}
325
326EXPORT_SYMBOL_GPL(ili9320_shutdown);
327
328MODULE_AUTHOR("Ben Dooks <ben-linux@fluff.org>");
329MODULE_DESCRIPTION("ILI9320 LCD Driver");
330MODULE_LICENSE("GPL v2");
diff --git a/drivers/video/backlight/ili9320.h b/drivers/video/backlight/ili9320.h
new file mode 100644
index 000000000000..e388eca7cac5
--- /dev/null
+++ b/drivers/video/backlight/ili9320.h
@@ -0,0 +1,80 @@
1/* drivers/video/backlight/ili9320.h
2 *
3 * ILI9320 LCD controller driver core.
4 *
5 * Copyright 2007 Simtec Electronics
6 * Ben Dooks <ben@simtec.co.uk>
7 *
8 * http://armlinux.simtec.co.uk/
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13*/
14
15/* Holder for register and value pairs. */
16struct ili9320_reg {
17 unsigned short address;
18 unsigned short value;
19};
20
21struct ili9320;
22
23struct ili9320_client {
24 const char *name;
25 int (*init)(struct ili9320 *ili, struct ili9320_platdata *cfg);
26
27};
28/* Device attached via an SPI bus. */
29struct ili9320_spi {
30 struct spi_device *dev;
31 struct spi_message message;
32 struct spi_transfer xfer[2];
33
34 unsigned char id;
35 unsigned char buffer_addr[4];
36 unsigned char buffer_data[4];
37};
38
39/* ILI9320 device state. */
40struct ili9320 {
41 union {
42 struct ili9320_spi spi; /* SPI attachged device. */
43 } access; /* Register access method. */
44
45 struct device *dev;
46 struct lcd_device *lcd; /* LCD device we created. */
47 struct ili9320_client *client;
48 struct ili9320_platdata *platdata;
49
50 int power; /* current power state. */
51 int initialised;
52
53 unsigned short display1;
54 unsigned short power1;
55
56 int (*write)(struct ili9320 *ili, unsigned int reg, unsigned int val);
57};
58
59
60/* ILI9320 register access routines */
61
62extern int ili9320_write(struct ili9320 *ili,
63 unsigned int reg, unsigned int value);
64
65extern int ili9320_write_regs(struct ili9320 *ili,
66 struct ili9320_reg *values,
67 int nr_values);
68
69/* Device probe */
70
71extern int ili9320_probe_spi(struct spi_device *spi,
72 struct ili9320_client *cli);
73
74extern int ili9320_remove(struct ili9320 *lcd);
75extern void ili9320_shutdown(struct ili9320 *lcd);
76
77/* PM */
78
79extern int ili9320_suspend(struct ili9320 *lcd, pm_message_t state);
80extern int ili9320_resume(struct ili9320 *lcd);
diff --git a/drivers/video/backlight/lcd.c b/drivers/video/backlight/lcd.c
index 299fd318dd45..b15b2b84a6f7 100644
--- a/drivers/video/backlight/lcd.c
+++ b/drivers/video/backlight/lcd.c
@@ -33,7 +33,7 @@ static int fb_notifier_callback(struct notifier_block *self,
33 ld = container_of(self, struct lcd_device, fb_notif); 33 ld = container_of(self, struct lcd_device, fb_notif);
34 mutex_lock(&ld->ops_lock); 34 mutex_lock(&ld->ops_lock);
35 if (ld->ops) 35 if (ld->ops)
36 if (!ld->ops->check_fb || ld->ops->check_fb(evdata->info)) 36 if (!ld->ops->check_fb || ld->ops->check_fb(ld, evdata->info))
37 ld->ops->set_power(ld, *(int *)evdata->data); 37 ld->ops->set_power(ld, *(int *)evdata->data);
38 mutex_unlock(&ld->ops_lock); 38 mutex_unlock(&ld->ops_lock);
39 return 0; 39 return 0;
diff --git a/drivers/video/backlight/mbp_nvidia_bl.c b/drivers/video/backlight/mbp_nvidia_bl.c
new file mode 100644
index 000000000000..385cba40ea87
--- /dev/null
+++ b/drivers/video/backlight/mbp_nvidia_bl.c
@@ -0,0 +1,116 @@
1/*
2 * Backlight Driver for Nvidia 8600 in Macbook Pro
3 *
4 * Copyright (c) Red Hat <mjg@redhat.com>
5 * Based on code from Pommed:
6 * Copyright (C) 2006 Nicolas Boichat <nicolas @boichat.ch>
7 * Copyright (C) 2006 Felipe Alfaro Solana <felipe_alfaro @linuxmail.org>
8 * Copyright (C) 2007 Julien BLACHE <jb@jblache.org>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 *
14 * This driver triggers SMIs which cause the firmware to change the
15 * backlight brightness. This is icky in many ways, but it's impractical to
16 * get at the firmware code in order to figure out what it's actually doing.
17 */
18
19#include <linux/module.h>
20#include <linux/kernel.h>
21#include <linux/init.h>
22#include <linux/platform_device.h>
23#include <linux/backlight.h>
24#include <linux/err.h>
25#include <linux/dmi.h>
26#include <linux/io.h>
27
28static struct backlight_device *mbp_backlight_device;
29
30static struct dmi_system_id __initdata mbp_device_table[] = {
31 {
32 .ident = "3,1",
33 .matches = {
34 DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
35 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro3,1"),
36 },
37 },
38 {
39 .ident = "3,2",
40 .matches = {
41 DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
42 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro3,2"),
43 },
44 },
45 {
46 .ident = "4,1",
47 .matches = {
48 DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
49 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro4,1"),
50 },
51 },
52 { }
53};
54
55static int mbp_send_intensity(struct backlight_device *bd)
56{
57 int intensity = bd->props.brightness;
58
59 outb(0x04 | (intensity << 4), 0xb3);
60 outb(0xbf, 0xb2);
61
62 return 0;
63}
64
65static int mbp_get_intensity(struct backlight_device *bd)
66{
67 outb(0x03, 0xb3);
68 outb(0xbf, 0xb2);
69 return inb(0xb3) >> 4;
70}
71
72static struct backlight_ops mbp_ops = {
73 .get_brightness = mbp_get_intensity,
74 .update_status = mbp_send_intensity,
75};
76
77static int __init mbp_init(void)
78{
79 if (!dmi_check_system(mbp_device_table))
80 return -ENODEV;
81
82 if (!request_region(0xb2, 2, "Macbook Pro backlight"))
83 return -ENXIO;
84
85 mbp_backlight_device = backlight_device_register("mbp_backlight",
86 NULL, NULL,
87 &mbp_ops);
88 if (IS_ERR(mbp_backlight_device)) {
89 release_region(0xb2, 2);
90 return PTR_ERR(mbp_backlight_device);
91 }
92
93 mbp_backlight_device->props.max_brightness = 15;
94 mbp_backlight_device->props.brightness =
95 mbp_get_intensity(mbp_backlight_device);
96 backlight_update_status(mbp_backlight_device);
97
98 return 0;
99}
100
101static void __exit mbp_exit(void)
102{
103 backlight_device_unregister(mbp_backlight_device);
104
105 release_region(0xb2, 2);
106}
107
108module_init(mbp_init);
109module_exit(mbp_exit);
110
111MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>");
112MODULE_DESCRIPTION("Nvidia-based Macbook Pro Backlight Driver");
113MODULE_LICENSE("GPL");
114MODULE_ALIAS("svnAppleInc.:pnMacBookPro3,1");
115MODULE_ALIAS("svnAppleInc.:pnMacBookPro3,2");
116MODULE_ALIAS("svnAppleInc.:pnMacBookPro4,1");
diff --git a/drivers/video/backlight/platform_lcd.c b/drivers/video/backlight/platform_lcd.c
new file mode 100644
index 000000000000..72d44dbfce82
--- /dev/null
+++ b/drivers/video/backlight/platform_lcd.c
@@ -0,0 +1,172 @@
1/* drivers/video/backlight/platform_lcd.c
2 *
3 * Copyright 2008 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk>
5 *
6 * Generic platform-device LCD power control interface.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 *
12*/
13
14#include <linux/module.h>
15#include <linux/platform_device.h>
16#include <linux/fb.h>
17#include <linux/backlight.h>
18#include <linux/lcd.h>
19
20#include <video/platform_lcd.h>
21
22struct platform_lcd {
23 struct device *us;
24 struct lcd_device *lcd;
25 struct plat_lcd_data *pdata;
26
27 unsigned int power;
28 unsigned int suspended : 1;
29};
30
31static inline struct platform_lcd *to_our_lcd(struct lcd_device *lcd)
32{
33 return lcd_get_data(lcd);
34}
35
36static int platform_lcd_get_power(struct lcd_device *lcd)
37{
38 struct platform_lcd *plcd = to_our_lcd(lcd);
39
40 return plcd->power;
41}
42
43static int platform_lcd_set_power(struct lcd_device *lcd, int power)
44{
45 struct platform_lcd *plcd = to_our_lcd(lcd);
46 int lcd_power = 1;
47
48 if (power == FB_BLANK_POWERDOWN || plcd->suspended)
49 lcd_power = 0;
50
51 plcd->pdata->set_power(plcd->pdata, lcd_power);
52 plcd->power = power;
53
54 return 0;
55}
56
57static int platform_lcd_match(struct lcd_device *lcd, struct fb_info *info)
58{
59 struct platform_lcd *plcd = to_our_lcd(lcd);
60 struct plat_lcd_data *pdata = plcd->pdata;
61
62 if (pdata->match_fb)
63 return pdata->match_fb(pdata, info);
64
65 return plcd->us->parent == info->device;
66}
67
68static struct lcd_ops platform_lcd_ops = {
69 .get_power = platform_lcd_get_power,
70 .set_power = platform_lcd_set_power,
71 .check_fb = platform_lcd_match,
72};
73
74static int __devinit platform_lcd_probe(struct platform_device *pdev)
75{
76 struct plat_lcd_data *pdata;
77 struct platform_lcd *plcd;
78 struct device *dev = &pdev->dev;
79 int err;
80
81 pdata = pdev->dev.platform_data;
82 if (!pdata) {
83 dev_err(dev, "no platform data supplied\n");
84 return -EINVAL;
85 }
86
87 plcd = kzalloc(sizeof(struct platform_lcd), GFP_KERNEL);
88 if (!plcd) {
89 dev_err(dev, "no memory for state\n");
90 return -ENOMEM;
91 }
92
93 plcd->us = dev;
94 plcd->pdata = pdata;
95 plcd->lcd = lcd_device_register("platform-lcd", dev,
96 plcd, &platform_lcd_ops);
97 if (IS_ERR(plcd->lcd)) {
98 dev_err(dev, "cannot register lcd device\n");
99 err = PTR_ERR(plcd->lcd);
100 goto err_mem;
101 }
102
103 platform_set_drvdata(pdev, plcd);
104 return 0;
105
106 err_mem:
107 kfree(plcd);
108 return err;
109}
110
111static int __devexit platform_lcd_remove(struct platform_device *pdev)
112{
113 struct platform_lcd *plcd = platform_get_drvdata(pdev);
114
115 lcd_device_unregister(plcd->lcd);
116 kfree(plcd);
117
118 return 0;
119}
120
121#ifdef CONFIG_PM
122static int platform_lcd_suspend(struct platform_device *pdev, pm_message_t st)
123{
124 struct platform_lcd *plcd = platform_get_drvdata(pdev);
125
126 plcd->suspended = 1;
127 platform_lcd_set_power(plcd->lcd, plcd->power);
128
129 return 0;
130}
131
132static int platform_lcd_resume(struct platform_device *pdev)
133{
134 struct platform_lcd *plcd = platform_get_drvdata(pdev);
135
136 plcd->suspended = 0;
137 platform_lcd_set_power(plcd->lcd, plcd->power);
138
139 return 0;
140}
141#else
142#define platform_lcd_suspend NULL
143#define platform_lcd_resume NULL
144#endif
145
146static struct platform_driver platform_lcd_driver = {
147 .driver = {
148 .name = "platform-lcd",
149 .owner = THIS_MODULE,
150 },
151 .probe = platform_lcd_probe,
152 .remove = __devexit_p(platform_lcd_remove),
153 .suspend = platform_lcd_suspend,
154 .resume = platform_lcd_resume,
155};
156
157static int __init platform_lcd_init(void)
158{
159 return platform_driver_register(&platform_lcd_driver);
160}
161
162static void __exit platform_lcd_cleanup(void)
163{
164 platform_driver_unregister(&platform_lcd_driver);
165}
166
167module_init(platform_lcd_init);
168module_exit(platform_lcd_cleanup);
169
170MODULE_AUTHOR("Ben Dooks <ben-linux@fluff.org>");
171MODULE_LICENSE("GPL v2");
172MODULE_ALIAS("platform:platform-lcd");
diff --git a/drivers/video/backlight/vgg2432a4.c b/drivers/video/backlight/vgg2432a4.c
new file mode 100644
index 000000000000..593c7687d54a
--- /dev/null
+++ b/drivers/video/backlight/vgg2432a4.c
@@ -0,0 +1,284 @@
1/* drivers/video/backlight/vgg2432a4.c
2 *
3 * VGG2432A4 (ILI9320) LCD controller driver.
4 *
5 * Copyright 2007 Simtec Electronics
6 * http://armlinux.simtec.co.uk/
7 * Ben Dooks <ben@simtec.co.uk>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12*/
13
14#include <linux/delay.h>
15#include <linux/err.h>
16#include <linux/fb.h>
17#include <linux/init.h>
18#include <linux/lcd.h>
19#include <linux/module.h>
20
21#include <linux/spi/spi.h>
22
23#include <video/ili9320.h>
24
25#include "ili9320.h"
26
27/* Device initialisation sequences */
28
29static struct ili9320_reg vgg_init1[] = {
30 {
31 .address = ILI9320_POWER1,
32 .value = ILI9320_POWER1_AP(0) | ILI9320_POWER1_BT(0),
33 }, {
34 .address = ILI9320_POWER2,
35 .value = (ILI9320_POWER2_VC(7) |
36 ILI9320_POWER2_DC0(0) | ILI9320_POWER2_DC1(0)),
37 }, {
38 .address = ILI9320_POWER3,
39 .value = ILI9320_POWER3_VRH(0),
40 }, {
41 .address = ILI9320_POWER4,
42 .value = ILI9320_POWER4_VREOUT(0),
43 },
44};
45
46static struct ili9320_reg vgg_init2[] = {
47 {
48 .address = ILI9320_POWER1,
49 .value = (ILI9320_POWER1_AP(3) | ILI9320_POWER1_APE |
50 ILI9320_POWER1_BT(7) | ILI9320_POWER1_SAP),
51 }, {
52 .address = ILI9320_POWER2,
53 .value = ILI9320_POWER2_VC(7) | ILI9320_POWER2_DC0(3),
54 }
55};
56
57static struct ili9320_reg vgg_gamma[] = {
58 {
59 .address = ILI9320_GAMMA1,
60 .value = 0x0000,
61 }, {
62 .address = ILI9320_GAMMA2,
63 .value = 0x0505,
64 }, {
65 .address = ILI9320_GAMMA3,
66 .value = 0x0004,
67 }, {
68 .address = ILI9320_GAMMA4,
69 .value = 0x0006,
70 }, {
71 .address = ILI9320_GAMMA5,
72 .value = 0x0707,
73 }, {
74 .address = ILI9320_GAMMA6,
75 .value = 0x0105,
76 }, {
77 .address = ILI9320_GAMMA7,
78 .value = 0x0002,
79 }, {
80 .address = ILI9320_GAMMA8,
81 .value = 0x0707,
82 }, {
83 .address = ILI9320_GAMMA9,
84 .value = 0x0704,
85 }, {
86 .address = ILI9320_GAMMA10,
87 .value = 0x807,
88 }
89
90};
91
92static struct ili9320_reg vgg_init0[] = {
93 [0] = {
94 /* set direction and scan mode gate */
95 .address = ILI9320_DRIVER,
96 .value = ILI9320_DRIVER_SS,
97 }, {
98 .address = ILI9320_DRIVEWAVE,
99 .value = (ILI9320_DRIVEWAVE_MUSTSET |
100 ILI9320_DRIVEWAVE_EOR | ILI9320_DRIVEWAVE_BC),
101 }, {
102 .address = ILI9320_ENTRYMODE,
103 .value = ILI9320_ENTRYMODE_ID(3) | ILI9320_ENTRYMODE_BGR,
104 }, {
105 .address = ILI9320_RESIZING,
106 .value = 0x0,
107 },
108};
109
110
111static int vgg2432a4_lcd_init(struct ili9320 *lcd,
112 struct ili9320_platdata *cfg)
113{
114 unsigned int addr;
115 int ret;
116
117 /* Set VCore before anything else (VGG243237-6UFLWA) */
118 ret = ili9320_write(lcd, 0x00e5, 0x8000);
119 if (ret)
120 goto err_initial;
121
122 /* Start the oscillator up before we can do anything else. */
123 ret = ili9320_write(lcd, ILI9320_OSCILATION, ILI9320_OSCILATION_OSC);
124 if (ret)
125 goto err_initial;
126
127 /* must wait at-lesat 10ms after starting */
128 mdelay(15);
129
130 ret = ili9320_write_regs(lcd, vgg_init0, ARRAY_SIZE(vgg_init0));
131 if (ret != 0)
132 goto err_initial;
133
134 ili9320_write(lcd, ILI9320_DISPLAY2, cfg->display2);
135 ili9320_write(lcd, ILI9320_DISPLAY3, cfg->display3);
136 ili9320_write(lcd, ILI9320_DISPLAY4, cfg->display4);
137
138 ili9320_write(lcd, ILI9320_RGB_IF1, cfg->rgb_if1);
139 ili9320_write(lcd, ILI9320_FRAMEMAKER, 0x0);
140 ili9320_write(lcd, ILI9320_RGB_IF2, ILI9320_RGBIF2_DPL);
141
142 ret = ili9320_write_regs(lcd, vgg_init1, ARRAY_SIZE(vgg_init1));
143 if (ret != 0)
144 goto err_vgg;
145
146 mdelay(300);
147
148 ret = ili9320_write_regs(lcd, vgg_init2, ARRAY_SIZE(vgg_init2));
149 if (ret != 0)
150 goto err_vgg2;
151
152 mdelay(100);
153
154 ili9320_write(lcd, ILI9320_POWER3, 0x13c);
155
156 mdelay(100);
157
158 ili9320_write(lcd, ILI9320_POWER4, 0x1c00);
159 ili9320_write(lcd, ILI9320_POWER7, 0x000e);
160
161 mdelay(100);
162
163 ili9320_write(lcd, ILI9320_GRAM_HORIZ_ADDR, 0x00);
164 ili9320_write(lcd, ILI9320_GRAM_VERT_ADD, 0x00);
165
166 ret = ili9320_write_regs(lcd, vgg_gamma, ARRAY_SIZE(vgg_gamma));
167 if (ret != 0)
168 goto err_vgg3;
169
170 ili9320_write(lcd, ILI9320_HORIZ_START, 0x0);
171 ili9320_write(lcd, ILI9320_HORIZ_END, cfg->hsize - 1);
172 ili9320_write(lcd, ILI9320_VERT_START, 0x0);
173 ili9320_write(lcd, ILI9320_VERT_END, cfg->vsize - 1);
174
175 ili9320_write(lcd, ILI9320_DRIVER2,
176 ILI9320_DRIVER2_NL(((cfg->vsize - 240) / 8) + 0x1D));
177
178 ili9320_write(lcd, ILI9320_BASE_IMAGE, 0x1);
179 ili9320_write(lcd, ILI9320_VERT_SCROLL, 0x00);
180
181 for (addr = ILI9320_PARTIAL1_POSITION; addr <= ILI9320_PARTIAL2_END;
182 addr++) {
183 ili9320_write(lcd, addr, 0x0);
184 }
185
186 ili9320_write(lcd, ILI9320_INTERFACE1, 0x10);
187 ili9320_write(lcd, ILI9320_INTERFACE2, cfg->interface2);
188 ili9320_write(lcd, ILI9320_INTERFACE3, cfg->interface3);
189 ili9320_write(lcd, ILI9320_INTERFACE4, cfg->interface4);
190 ili9320_write(lcd, ILI9320_INTERFACE5, cfg->interface5);
191 ili9320_write(lcd, ILI9320_INTERFACE6, cfg->interface6);
192
193 lcd->display1 = (ILI9320_DISPLAY1_D(3) | ILI9320_DISPLAY1_DTE |
194 ILI9320_DISPLAY1_GON | ILI9320_DISPLAY1_BASEE |
195 0x40);
196
197 ili9320_write(lcd, ILI9320_DISPLAY1, lcd->display1);
198
199 return 0;
200
201 err_vgg3:
202 err_vgg2:
203 err_vgg:
204 err_initial:
205 return ret;
206}
207
208#ifdef CONFIG_PM
209static int vgg2432a4_suspend(struct spi_device *spi, pm_message_t state)
210{
211 return ili9320_suspend(dev_get_drvdata(&spi->dev), state);
212}
213
214static int vgg2432a4_resume(struct spi_device *spi)
215{
216 return ili9320_resume(dev_get_drvdata(&spi->dev));
217}
218#else
219#define vgg2432a4_suspend NULL
220#define vgg2432a4_resume NULL
221#endif
222
223static struct ili9320_client vgg2432a4_client = {
224 .name = "VGG2432A4",
225 .init = vgg2432a4_lcd_init,
226};
227
228/* Device probe */
229
230static int __devinit vgg2432a4_probe(struct spi_device *spi)
231{
232 int ret;
233
234 ret = ili9320_probe_spi(spi, &vgg2432a4_client);
235 if (ret != 0) {
236 dev_err(&spi->dev, "failed to initialise ili9320\n");
237 return ret;
238 }
239
240 return 0;
241}
242
243static int __devexit vgg2432a4_remove(struct spi_device *spi)
244{
245 return ili9320_remove(dev_get_drvdata(&spi->dev));
246}
247
248static void vgg2432a4_shutdown(struct spi_device *spi)
249{
250 ili9320_shutdown(dev_get_drvdata(&spi->dev));
251}
252
253static struct spi_driver vgg2432a4_driver = {
254 .driver = {
255 .name = "VGG2432A4",
256 .owner = THIS_MODULE,
257 },
258 .probe = vgg2432a4_probe,
259 .remove = __devexit_p(vgg2432a4_remove),
260 .shutdown = vgg2432a4_shutdown,
261 .suspend = vgg2432a4_suspend,
262 .resume = vgg2432a4_resume,
263};
264
265/* Device driver initialisation */
266
267static int __init vgg2432a4_init(void)
268{
269 return spi_register_driver(&vgg2432a4_driver);
270}
271
272static void __exit vgg2432a4_exit(void)
273{
274 spi_unregister_driver(&vgg2432a4_driver);
275}
276
277module_init(vgg2432a4_init);
278module_exit(vgg2432a4_exit);
279
280MODULE_AUTHOR("Ben Dooks <ben-linux@fluff.org>");
281MODULE_DESCRIPTION("VGG2432A4 LCD Driver");
282MODULE_LICENSE("GPL v2");
283
284
diff --git a/drivers/video/bf54x-lq043fb.c b/drivers/video/bf54x-lq043fb.c
index 49834a67a623..940467aed13f 100644
--- a/drivers/video/bf54x-lq043fb.c
+++ b/drivers/video/bf54x-lq043fb.c
@@ -478,7 +478,7 @@ static int bfin_lcd_set_contrast(struct lcd_device *dev, int contrast)
478 return 0; 478 return 0;
479} 479}
480 480
481static int bfin_lcd_check_fb(struct fb_info *fi) 481static int bfin_lcd_check_fb(struct lcd_device *dev, struct fb_info *fi)
482{ 482{
483 if (!fi || (fi == &bfin_bf54x_fb)) 483 if (!fi || (fi == &bfin_bf54x_fb))
484 return 1; 484 return 1;
diff --git a/drivers/video/bfin-t350mcqb-fb.c b/drivers/video/bfin-t350mcqb-fb.c
index 135d6dd7e672..7d1b819e501c 100644
--- a/drivers/video/bfin-t350mcqb-fb.c
+++ b/drivers/video/bfin-t350mcqb-fb.c
@@ -396,7 +396,7 @@ static int bfin_lcd_set_contrast(struct lcd_device *dev, int contrast)
396 return 0; 396 return 0;
397} 397}
398 398
399static int bfin_lcd_check_fb(struct fb_info *fi) 399static int bfin_lcd_check_fb(struct lcd_device *dev, struct fb_info *fi)
400{ 400{
401 if (!fi || (fi == &bfin_t350mcqb_fb)) 401 if (!fi || (fi == &bfin_t350mcqb_fb))
402 return 1; 402 return 1;
diff --git a/drivers/video/carminefb.c b/drivers/video/carminefb.c
new file mode 100644
index 000000000000..e15bb447440a
--- /dev/null
+++ b/drivers/video/carminefb.c
@@ -0,0 +1,790 @@
1/*
2 * Frame buffer driver for the Carmine GPU.
3 *
4 * The driver configures the GPU as follows
5 * - FB0 is display 0 with unique memory area
6 * - FB1 is display 1 with unique memory area
7 * - both display use 32 bit colors
8 */
9#include <linux/delay.h>
10#include <linux/errno.h>
11#include <linux/fb.h>
12#include <linux/interrupt.h>
13#include <linux/pci.h>
14
15#include "carminefb.h"
16#include "carminefb_regs.h"
17
18#if !defined(__LITTLE_ENDIAN) && !defined(__BIG_ENDIAN)
19#error "The endianness of the target host has not been defined."
20#endif
21
22/*
23 * The initial video mode can be supplied via two different ways:
24 * - as a string that is passed to fb_find_mode() (module option fb_mode_str)
25 * - as an integer that picks the video mode from carmine_modedb[] (module
26 * option fb_mode)
27 *
28 * If nothing is used than the initial video mode will be the
29 * CARMINEFB_DEFAULT_VIDEO_MODE member of the carmine_modedb[].
30 */
31#define CARMINEFB_DEFAULT_VIDEO_MODE 1
32
33static unsigned int fb_mode = CARMINEFB_DEFAULT_VIDEO_MODE;
34module_param(fb_mode, uint, 444);
35MODULE_PARM_DESC(fb_mode, "Initial video mode as integer.");
36
37static char *fb_mode_str;
38module_param(fb_mode_str, charp, 444);
39MODULE_PARM_DESC(fb_mode_str, "Initial video mode in characters.");
40
41/*
42 * Carminefb displays:
43 * 0b000 None
44 * 0b001 Display 0
45 * 0b010 Display 1
46 */
47static int fb_displays = CARMINE_USE_DISPLAY0 | CARMINE_USE_DISPLAY1;
48module_param(fb_displays, int, 444);
49MODULE_PARM_DESC(fb_displays, "Bit mode, which displays are used");
50
51struct carmine_hw {
52 void __iomem *v_regs;
53 void __iomem *screen_mem;
54 struct fb_info *fb[MAX_DISPLAY];
55};
56
57struct carmine_resolution {
58 u32 htp;
59 u32 hsp;
60 u32 hsw;
61 u32 hdp;
62 u32 vtr;
63 u32 vsp;
64 u32 vsw;
65 u32 vdp;
66 u32 disp_mode;
67};
68
69struct carmine_fb {
70 void __iomem *display_reg;
71 void __iomem *screen_base;
72 u32 smem_offset;
73 u32 cur_mode;
74 u32 new_mode;
75 struct carmine_resolution *res;
76 u32 pseudo_palette[16];
77};
78
79static struct fb_fix_screeninfo carminefb_fix __devinitdata = {
80 .id = "Carmine",
81 .type = FB_TYPE_PACKED_PIXELS,
82 .visual = FB_VISUAL_TRUECOLOR,
83 .accel = FB_ACCEL_NONE,
84};
85
86static const struct fb_videomode carmine_modedb[] = {
87 {
88 .name = "640x480",
89 .xres = 640,
90 .yres = 480,
91 }, {
92 .name = "800x600",
93 .xres = 800,
94 .yres = 600,
95 },
96};
97
98static struct carmine_resolution car_modes[] = {
99 {
100 /* 640x480 */
101 .htp = 800,
102 .hsp = 672,
103 .hsw = 96,
104 .hdp = 640,
105 .vtr = 525,
106 .vsp = 490,
107 .vsw = 2,
108 .vdp = 480,
109 .disp_mode = 0x1400,
110 },
111 {
112 /* 800x600 */
113 .htp = 1060,
114 .hsp = 864,
115 .hsw = 72,
116 .hdp = 800,
117 .vtr = 628,
118 .vsp = 601,
119 .vsw = 2,
120 .vdp = 600,
121 .disp_mode = 0x0d00,
122 }
123};
124
125static int carmine_find_mode(const struct fb_var_screeninfo *var)
126{
127 int i;
128
129 for (i = 0; i < ARRAY_SIZE(car_modes); i++)
130 if (car_modes[i].hdp == var->xres &&
131 car_modes[i].vdp == var->yres)
132 return i;
133 return -EINVAL;
134}
135
136static void c_set_disp_reg(const struct carmine_fb *par,
137 u32 offset, u32 val)
138{
139 writel(val, par->display_reg + offset);
140}
141
142static u32 c_get_disp_reg(const struct carmine_fb *par,
143 u32 offset)
144{
145 return readl(par->display_reg + offset);
146}
147
148static void c_set_hw_reg(const struct carmine_hw *hw,
149 u32 offset, u32 val)
150{
151 writel(val, hw->v_regs + offset);
152}
153
154static u32 c_get_hw_reg(const struct carmine_hw *hw,
155 u32 offset)
156{
157 return readl(hw->v_regs + offset);
158}
159
160static int carmine_setcolreg(unsigned regno, unsigned red, unsigned green,
161 unsigned blue, unsigned transp, struct fb_info *info)
162{
163 if (regno >= 16)
164 return 1;
165
166 red >>= 8;
167 green >>= 8;
168 blue >>= 8;
169 transp >>= 8;
170
171 ((u32 *)info->pseudo_palette)[regno] = be32_to_cpu(transp << 24 |
172 red << 0 | green << 8 | blue << 16);
173 return 0;
174}
175
176static int carmine_check_var(struct fb_var_screeninfo *var,
177 struct fb_info *info)
178{
179 int ret;
180
181 ret = carmine_find_mode(var);
182 if (ret < 0)
183 return ret;
184
185 if (var->grayscale || var->rotate || var->nonstd)
186 return -EINVAL;
187
188 var->xres_virtual = var->xres;
189 var->yres_virtual = var->yres;
190
191 var->bits_per_pixel = 32;
192
193#ifdef __BIG_ENDIAN
194 var->transp.offset = 24;
195 var->red.offset = 0;
196 var->green.offset = 8;
197 var->blue.offset = 16;
198#else
199 var->transp.offset = 24;
200 var->red.offset = 16;
201 var->green.offset = 8;
202 var->blue.offset = 0;
203#endif
204
205 var->red.length = 8;
206 var->green.length = 8;
207 var->blue.length = 8;
208 var->transp.length = 8;
209
210 var->red.msb_right = 0;
211 var->green.msb_right = 0;
212 var->blue.msb_right = 0;
213 var->transp.msb_right = 0;
214 return 0;
215}
216
217static void carmine_init_display_param(struct carmine_fb *par)
218{
219 u32 width;
220 u32 height;
221 u32 param;
222 u32 window_size;
223 u32 soffset = par->smem_offset;
224
225 c_set_disp_reg(par, CARMINE_DISP_REG_C_TRANS, 0);
226 c_set_disp_reg(par, CARMINE_DISP_REG_MLMR_TRANS, 0);
227 c_set_disp_reg(par, CARMINE_DISP_REG_CURSOR_MODE,
228 CARMINE_CURSOR0_PRIORITY_MASK |
229 CARMINE_CURSOR1_PRIORITY_MASK |
230 CARMINE_CURSOR_CUTZ_MASK);
231
232 /* Set default cursor position */
233 c_set_disp_reg(par, CARMINE_DISP_REG_CUR1_POS, 0 << 16 | 0);
234 c_set_disp_reg(par, CARMINE_DISP_REG_CUR2_POS, 0 << 16 | 0);
235
236 /* Set default display mode */
237 c_set_disp_reg(par, CARMINE_DISP_REG_L0_EXT_MODE, CARMINE_WINDOW_MODE |
238 CARMINE_EXT_CMODE_DIRECT24_RGBA);
239 c_set_disp_reg(par, CARMINE_DISP_REG_L1_EXT_MODE,
240 CARMINE_EXT_CMODE_DIRECT24_RGBA);
241 c_set_disp_reg(par, CARMINE_DISP_REG_L2_EXT_MODE, CARMINE_EXTEND_MODE |
242 CARMINE_EXT_CMODE_DIRECT24_RGBA);
243 c_set_disp_reg(par, CARMINE_DISP_REG_L3_EXT_MODE, CARMINE_EXTEND_MODE |
244 CARMINE_EXT_CMODE_DIRECT24_RGBA);
245 c_set_disp_reg(par, CARMINE_DISP_REG_L4_EXT_MODE, CARMINE_EXTEND_MODE |
246 CARMINE_EXT_CMODE_DIRECT24_RGBA);
247 c_set_disp_reg(par, CARMINE_DISP_REG_L5_EXT_MODE, CARMINE_EXTEND_MODE |
248 CARMINE_EXT_CMODE_DIRECT24_RGBA);
249 c_set_disp_reg(par, CARMINE_DISP_REG_L6_EXT_MODE, CARMINE_EXTEND_MODE |
250 CARMINE_EXT_CMODE_DIRECT24_RGBA);
251 c_set_disp_reg(par, CARMINE_DISP_REG_L7_EXT_MODE, CARMINE_EXTEND_MODE |
252 CARMINE_EXT_CMODE_DIRECT24_RGBA);
253
254 /* Set default frame size to layer mode register */
255 width = par->res->hdp * 4 / CARMINE_DISP_WIDTH_UNIT;
256 width = width << CARMINE_DISP_WIDTH_SHIFT;
257
258 height = par->res->vdp - 1;
259 param = width | height;
260
261 c_set_disp_reg(par, CARMINE_DISP_REG_L0_MODE_W_H, param);
262 c_set_disp_reg(par, CARMINE_DISP_REG_L1_WIDTH, width);
263 c_set_disp_reg(par, CARMINE_DISP_REG_L2_MODE_W_H, param);
264 c_set_disp_reg(par, CARMINE_DISP_REG_L3_MODE_W_H, param);
265 c_set_disp_reg(par, CARMINE_DISP_REG_L4_MODE_W_H, param);
266 c_set_disp_reg(par, CARMINE_DISP_REG_L5_MODE_W_H, param);
267 c_set_disp_reg(par, CARMINE_DISP_REG_L6_MODE_W_H, param);
268 c_set_disp_reg(par, CARMINE_DISP_REG_L7_MODE_W_H, param);
269
270 /* Set default pos and size */
271 window_size = (par->res->vdp - 1) << CARMINE_DISP_WIN_H_SHIFT;
272 window_size |= par->res->hdp;
273
274 c_set_disp_reg(par, CARMINE_DISP_REG_L0_WIN_POS, 0);
275 c_set_disp_reg(par, CARMINE_DISP_REG_L0_WIN_SIZE, window_size);
276 c_set_disp_reg(par, CARMINE_DISP_REG_L1_WIN_POS, 0);
277 c_set_disp_reg(par, CARMINE_DISP_REG_L1_WIN_SIZE, window_size);
278 c_set_disp_reg(par, CARMINE_DISP_REG_L2_WIN_POS, 0);
279 c_set_disp_reg(par, CARMINE_DISP_REG_L2_WIN_SIZE, window_size);
280 c_set_disp_reg(par, CARMINE_DISP_REG_L3_WIN_POS, 0);
281 c_set_disp_reg(par, CARMINE_DISP_REG_L3_WIN_SIZE, window_size);
282 c_set_disp_reg(par, CARMINE_DISP_REG_L4_WIN_POS, 0);
283 c_set_disp_reg(par, CARMINE_DISP_REG_L4_WIN_SIZE, window_size);
284 c_set_disp_reg(par, CARMINE_DISP_REG_L5_WIN_POS, 0);
285 c_set_disp_reg(par, CARMINE_DISP_REG_L5_WIN_SIZE, window_size);
286 c_set_disp_reg(par, CARMINE_DISP_REG_L6_WIN_POS, 0);
287 c_set_disp_reg(par, CARMINE_DISP_REG_L6_WIN_SIZE, window_size);
288 c_set_disp_reg(par, CARMINE_DISP_REG_L7_WIN_POS, 0);
289 c_set_disp_reg(par, CARMINE_DISP_REG_L7_WIN_SIZE, window_size);
290
291 /* Set default origin address */
292 c_set_disp_reg(par, CARMINE_DISP_REG_L0_ORG_ADR, soffset);
293 c_set_disp_reg(par, CARMINE_DISP_REG_L1_ORG_ADR, soffset);
294 c_set_disp_reg(par, CARMINE_DISP_REG_L2_ORG_ADR1, soffset);
295 c_set_disp_reg(par, CARMINE_DISP_REG_L3_ORG_ADR1, soffset);
296 c_set_disp_reg(par, CARMINE_DISP_REG_L4_ORG_ADR1, soffset);
297 c_set_disp_reg(par, CARMINE_DISP_REG_L5_ORG_ADR1, soffset);
298 c_set_disp_reg(par, CARMINE_DISP_REG_L6_ORG_ADR1, soffset);
299 c_set_disp_reg(par, CARMINE_DISP_REG_L7_ORG_ADR1, soffset);
300
301 /* Set default display address */
302 c_set_disp_reg(par, CARMINE_DISP_REG_L0_DISP_ADR, soffset);
303 c_set_disp_reg(par, CARMINE_DISP_REG_L2_DISP_ADR1, soffset);
304 c_set_disp_reg(par, CARMINE_DISP_REG_L3_DISP_ADR1, soffset);
305 c_set_disp_reg(par, CARMINE_DISP_REG_L4_DISP_ADR1, soffset);
306 c_set_disp_reg(par, CARMINE_DISP_REG_L5_DISP_ADR1, soffset);
307 c_set_disp_reg(par, CARMINE_DISP_REG_L6_DISP_ADR0, soffset);
308 c_set_disp_reg(par, CARMINE_DISP_REG_L7_DISP_ADR0, soffset);
309
310 /* Set default display position */
311 c_set_disp_reg(par, CARMINE_DISP_REG_L0_DISP_POS, 0);
312 c_set_disp_reg(par, CARMINE_DISP_REG_L2_DISP_POS, 0);
313 c_set_disp_reg(par, CARMINE_DISP_REG_L3_DISP_POS, 0);
314 c_set_disp_reg(par, CARMINE_DISP_REG_L4_DISP_POS, 0);
315 c_set_disp_reg(par, CARMINE_DISP_REG_L5_DISP_POS, 0);
316 c_set_disp_reg(par, CARMINE_DISP_REG_L6_DISP_POS, 0);
317 c_set_disp_reg(par, CARMINE_DISP_REG_L7_DISP_POS, 0);
318
319 /* Set default blend mode */
320 c_set_disp_reg(par, CARMINE_DISP_REG_BLEND_MODE_L0, 0);
321 c_set_disp_reg(par, CARMINE_DISP_REG_BLEND_MODE_L1, 0);
322 c_set_disp_reg(par, CARMINE_DISP_REG_BLEND_MODE_L2, 0);
323 c_set_disp_reg(par, CARMINE_DISP_REG_BLEND_MODE_L3, 0);
324 c_set_disp_reg(par, CARMINE_DISP_REG_BLEND_MODE_L4, 0);
325 c_set_disp_reg(par, CARMINE_DISP_REG_BLEND_MODE_L5, 0);
326 c_set_disp_reg(par, CARMINE_DISP_REG_BLEND_MODE_L6, 0);
327 c_set_disp_reg(par, CARMINE_DISP_REG_BLEND_MODE_L7, 0);
328
329 /* default transparency mode */
330 c_set_disp_reg(par, CARMINE_DISP_REG_L0_TRANS, 0);
331 c_set_disp_reg(par, CARMINE_DISP_REG_L1_TRANS, 0);
332 c_set_disp_reg(par, CARMINE_DISP_REG_L2_TRANS, 0);
333 c_set_disp_reg(par, CARMINE_DISP_REG_L3_TRANS, 0);
334 c_set_disp_reg(par, CARMINE_DISP_REG_L4_TRANS, 0);
335 c_set_disp_reg(par, CARMINE_DISP_REG_L5_TRANS, 0);
336 c_set_disp_reg(par, CARMINE_DISP_REG_L6_TRANS, 0);
337 c_set_disp_reg(par, CARMINE_DISP_REG_L7_TRANS, 0);
338
339 /* Set default read skip parameter */
340 c_set_disp_reg(par, CARMINE_DISP_REG_L0RM, 0);
341 c_set_disp_reg(par, CARMINE_DISP_REG_L2RM, 0);
342 c_set_disp_reg(par, CARMINE_DISP_REG_L3RM, 0);
343 c_set_disp_reg(par, CARMINE_DISP_REG_L4RM, 0);
344 c_set_disp_reg(par, CARMINE_DISP_REG_L5RM, 0);
345 c_set_disp_reg(par, CARMINE_DISP_REG_L6RM, 0);
346 c_set_disp_reg(par, CARMINE_DISP_REG_L7RM, 0);
347
348 c_set_disp_reg(par, CARMINE_DISP_REG_L0PX, 0);
349 c_set_disp_reg(par, CARMINE_DISP_REG_L2PX, 0);
350 c_set_disp_reg(par, CARMINE_DISP_REG_L3PX, 0);
351 c_set_disp_reg(par, CARMINE_DISP_REG_L4PX, 0);
352 c_set_disp_reg(par, CARMINE_DISP_REG_L5PX, 0);
353 c_set_disp_reg(par, CARMINE_DISP_REG_L6PX, 0);
354 c_set_disp_reg(par, CARMINE_DISP_REG_L7PX, 0);
355
356 c_set_disp_reg(par, CARMINE_DISP_REG_L0PY, 0);
357 c_set_disp_reg(par, CARMINE_DISP_REG_L2PY, 0);
358 c_set_disp_reg(par, CARMINE_DISP_REG_L3PY, 0);
359 c_set_disp_reg(par, CARMINE_DISP_REG_L4PY, 0);
360 c_set_disp_reg(par, CARMINE_DISP_REG_L5PY, 0);
361 c_set_disp_reg(par, CARMINE_DISP_REG_L6PY, 0);
362 c_set_disp_reg(par, CARMINE_DISP_REG_L7PY, 0);
363}
364
365static void set_display_parameters(struct carmine_fb *par)
366{
367 u32 mode;
368 u32 hdp, vdp, htp, hsp, hsw, vtr, vsp, vsw;
369
370 /*
371 * display timing. Parameters are decreased by one because hardware
372 * spec is 0 to (n - 1)
373 * */
374 hdp = par->res->hdp - 1;
375 vdp = par->res->vdp - 1;
376 htp = par->res->htp - 1;
377 hsp = par->res->hsp - 1;
378 hsw = par->res->hsw - 1;
379 vtr = par->res->vtr - 1;
380 vsp = par->res->vsp - 1;
381 vsw = par->res->vsw - 1;
382
383 c_set_disp_reg(par, CARMINE_DISP_REG_H_TOTAL,
384 htp << CARMINE_DISP_HTP_SHIFT);
385 c_set_disp_reg(par, CARMINE_DISP_REG_H_PERIOD,
386 (hdp << CARMINE_DISP_HDB_SHIFT) | hdp);
387 c_set_disp_reg(par, CARMINE_DISP_REG_V_H_W_H_POS,
388 (vsw << CARMINE_DISP_VSW_SHIFT) |
389 (hsw << CARMINE_DISP_HSW_SHIFT) |
390 (hsp));
391 c_set_disp_reg(par, CARMINE_DISP_REG_V_TOTAL,
392 vtr << CARMINE_DISP_VTR_SHIFT);
393 c_set_disp_reg(par, CARMINE_DISP_REG_V_PERIOD_POS,
394 (vdp << CARMINE_DISP_VDP_SHIFT) | vsp);
395
396 /* clock */
397 mode = c_get_disp_reg(par, CARMINE_DISP_REG_DCM1);
398 mode = (mode & ~CARMINE_DISP_DCM_MASK) |
399 (par->res->disp_mode & CARMINE_DISP_DCM_MASK);
400 /* enable video output and layer 0 */
401 mode |= CARMINE_DEN | CARMINE_L0E;
402 c_set_disp_reg(par, CARMINE_DISP_REG_DCM1, mode);
403}
404
405static int carmine_set_par(struct fb_info *info)
406{
407 struct carmine_fb *par = info->par;
408 int ret;
409
410 ret = carmine_find_mode(&info->var);
411 if (ret < 0)
412 return ret;
413
414 par->new_mode = ret;
415 if (par->cur_mode != par->new_mode) {
416
417 par->cur_mode = par->new_mode;
418 par->res = &car_modes[par->new_mode];
419
420 carmine_init_display_param(par);
421 set_display_parameters(par);
422 }
423
424 info->fix.line_length = info->var.xres * info->var.bits_per_pixel / 8;
425 return 0;
426}
427
428static int init_hardware(struct carmine_hw *hw)
429{
430 u32 flags;
431 u32 loops;
432 u32 ret;
433
434 /* Initalize Carmine */
435 /* Sets internal clock */
436 c_set_hw_reg(hw, CARMINE_CTL_REG + CARMINE_CTL_REG_CLOCK_ENABLE,
437 CARMINE_DFLT_IP_CLOCK_ENABLE);
438
439 /* Video signal output is turned off */
440 c_set_hw_reg(hw, CARMINE_DISP0_REG + CARMINE_DISP_REG_DCM1, 0);
441 c_set_hw_reg(hw, CARMINE_DISP1_REG + CARMINE_DISP_REG_DCM1, 0);
442
443 /* Software reset */
444 c_set_hw_reg(hw, CARMINE_CTL_REG + CARMINE_CTL_REG_SOFTWARE_RESET, 1);
445 c_set_hw_reg(hw, CARMINE_CTL_REG + CARMINE_CTL_REG_SOFTWARE_RESET, 0);
446
447 /* I/O mode settings */
448 flags = CARMINE_DFLT_IP_DCTL_IO_CONT1 << 16 |
449 CARMINE_DFLT_IP_DCTL_IO_CONT0;
450 c_set_hw_reg(hw, CARMINE_DCTL_REG + CARMINE_DCTL_REG_IOCONT1_IOCONT0,
451 flags);
452
453 /* DRAM initial sequence */
454 flags = CARMINE_DFLT_IP_DCTL_MODE << 16 | CARMINE_DFLT_IP_DCTL_ADD;
455 c_set_hw_reg(hw, CARMINE_DCTL_REG + CARMINE_DCTL_REG_MODE_ADD,
456 flags);
457
458 flags = CARMINE_DFLT_IP_DCTL_SET_TIME1 << 16 |
459 CARMINE_DFLT_IP_DCTL_EMODE;
460 c_set_hw_reg(hw, CARMINE_DCTL_REG + CARMINE_DCTL_REG_SETTIME1_EMODE,
461 flags);
462
463 flags = CARMINE_DFLT_IP_DCTL_REFRESH << 16 |
464 CARMINE_DFLT_IP_DCTL_SET_TIME2;
465 c_set_hw_reg(hw, CARMINE_DCTL_REG + CARMINE_DCTL_REG_REFRESH_SETTIME2,
466 flags);
467
468 flags = CARMINE_DFLT_IP_DCTL_RESERVE2 << 16 |
469 CARMINE_DFLT_IP_DCTL_FIFO_DEPTH;
470 c_set_hw_reg(hw, CARMINE_DCTL_REG + CARMINE_DCTL_REG_RSV2_RSV1, flags);
471
472 flags = CARMINE_DFLT_IP_DCTL_DDRIF2 << 16 | CARMINE_DFLT_IP_DCTL_DDRIF1;
473 c_set_hw_reg(hw, CARMINE_DCTL_REG + CARMINE_DCTL_REG_DDRIF2_DDRIF1,
474 flags);
475
476 flags = CARMINE_DFLT_IP_DCTL_RESERVE0 << 16 |
477 CARMINE_DFLT_IP_DCTL_STATES;
478 c_set_hw_reg(hw, CARMINE_DCTL_REG + CARMINE_DCTL_REG_RSV0_STATES,
479 flags);
480
481 /* Executes DLL reset */
482 if (CARMINE_DCTL_DLL_RESET) {
483 for (loops = 0; loops < CARMINE_DCTL_INIT_WAIT_LIMIT; loops++) {
484
485 ret = c_get_hw_reg(hw, CARMINE_DCTL_REG +
486 CARMINE_DCTL_REG_RSV0_STATES);
487 ret &= CARMINE_DCTL_REG_STATES_MASK;
488 if (!ret)
489 break;
490
491 mdelay(CARMINE_DCTL_INIT_WAIT_INTERVAL);
492 }
493
494 if (loops >= CARMINE_DCTL_INIT_WAIT_LIMIT) {
495 printk(KERN_ERR "DRAM init failed\n");
496 return -EIO;
497 }
498 }
499
500 flags = CARMINE_DFLT_IP_DCTL_MODE_AFT_RST << 16 |
501 CARMINE_DFLT_IP_DCTL_ADD;
502 c_set_hw_reg(hw, CARMINE_DCTL_REG + CARMINE_DCTL_REG_MODE_ADD, flags);
503
504 flags = CARMINE_DFLT_IP_DCTL_RESERVE0 << 16 |
505 CARMINE_DFLT_IP_DCTL_STATES_AFT_RST;
506 c_set_hw_reg(hw, CARMINE_DCTL_REG + CARMINE_DCTL_REG_RSV0_STATES,
507 flags);
508
509 /* Initialize the write back register */
510 c_set_hw_reg(hw, CARMINE_WB_REG + CARMINE_WB_REG_WBM,
511 CARMINE_WB_REG_WBM_DEFAULT);
512
513 /* Initialize the Kottos registers */
514 c_set_hw_reg(hw, CARMINE_GRAPH_REG + CARMINE_GRAPH_REG_VRINTM, 0);
515 c_set_hw_reg(hw, CARMINE_GRAPH_REG + CARMINE_GRAPH_REG_VRERRM, 0);
516
517 /* Set DC offsets */
518 c_set_hw_reg(hw, CARMINE_GRAPH_REG + CARMINE_GRAPH_REG_DC_OFFSET_PX, 0);
519 c_set_hw_reg(hw, CARMINE_GRAPH_REG + CARMINE_GRAPH_REG_DC_OFFSET_PY, 0);
520 c_set_hw_reg(hw, CARMINE_GRAPH_REG + CARMINE_GRAPH_REG_DC_OFFSET_LX, 0);
521 c_set_hw_reg(hw, CARMINE_GRAPH_REG + CARMINE_GRAPH_REG_DC_OFFSET_LY, 0);
522 c_set_hw_reg(hw, CARMINE_GRAPH_REG + CARMINE_GRAPH_REG_DC_OFFSET_TX, 0);
523 c_set_hw_reg(hw, CARMINE_GRAPH_REG + CARMINE_GRAPH_REG_DC_OFFSET_TY, 0);
524 return 0;
525}
526
527static struct fb_ops carminefb_ops = {
528 .owner = THIS_MODULE,
529 .fb_fillrect = cfb_fillrect,
530 .fb_copyarea = cfb_copyarea,
531 .fb_imageblit = cfb_imageblit,
532
533 .fb_check_var = carmine_check_var,
534 .fb_set_par = carmine_set_par,
535 .fb_setcolreg = carmine_setcolreg,
536};
537
538static int alloc_carmine_fb(void __iomem *regs, void __iomem *smem_base,
539 int smem_offset, struct device *device, struct fb_info **rinfo)
540{
541 int ret;
542 struct fb_info *info;
543 struct carmine_fb *par;
544
545 info = framebuffer_alloc(sizeof *par, device);
546 if (!info)
547 return -ENOMEM;
548
549 par = info->par;
550 par->display_reg = regs;
551 par->smem_offset = smem_offset;
552
553 info->screen_base = smem_base + smem_offset;
554 info->screen_size = CARMINE_DISPLAY_MEM;
555 info->fbops = &carminefb_ops;
556
557 info->fix = carminefb_fix;
558 info->pseudo_palette = par->pseudo_palette;
559 info->flags = FBINFO_DEFAULT;
560
561 ret = fb_alloc_cmap(&info->cmap, 256, 1);
562 if (ret < 0)
563 goto err_free_fb;
564
565 if (fb_mode > ARRAY_SIZE(carmine_modedb))
566 fb_mode = CARMINEFB_DEFAULT_VIDEO_MODE;
567
568 par->cur_mode = par->new_mode = ~0;
569
570 ret = fb_find_mode(&info->var, info, fb_mode_str, carmine_modedb,
571 ARRAY_SIZE(carmine_modedb),
572 &carmine_modedb[fb_mode], 32);
573 if (!ret || ret == 4) {
574 ret = -EINVAL;
575 goto err_dealloc_cmap;
576 }
577
578 fb_videomode_to_modelist(carmine_modedb, ARRAY_SIZE(carmine_modedb),
579 &info->modelist);
580
581 ret = register_framebuffer(info);
582 if (ret < 0)
583 goto err_dealloc_cmap;
584
585 printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node,
586 info->fix.id);
587
588 *rinfo = info;
589 return 0;
590
591err_dealloc_cmap:
592 fb_dealloc_cmap(&info->cmap);
593err_free_fb:
594 framebuffer_release(info);
595 return ret;
596}
597
598static void cleanup_fb_device(struct fb_info *info)
599{
600 if (info) {
601 unregister_framebuffer(info);
602 fb_dealloc_cmap(&info->cmap);
603 framebuffer_release(info);
604 }
605}
606
607static int __devinit carminefb_probe(struct pci_dev *dev,
608 const struct pci_device_id *ent)
609{
610 struct carmine_hw *hw;
611 struct device *device = &dev->dev;
612 struct fb_info *info;
613 int ret;
614
615 ret = pci_enable_device(dev);
616 if (ret)
617 return ret;
618
619 ret = -ENOMEM;
620 hw = kzalloc(sizeof *hw, GFP_KERNEL);
621 if (!hw)
622 goto err_enable_pci;
623
624 carminefb_fix.mmio_start = pci_resource_start(dev, CARMINE_CONFIG_BAR);
625 carminefb_fix.mmio_len = pci_resource_len(dev, CARMINE_CONFIG_BAR);
626
627 if (!request_mem_region(carminefb_fix.mmio_start,
628 carminefb_fix.mmio_len,
629 "carminefb regbase")) {
630 printk(KERN_ERR "carminefb: Can't reserve regbase.\n");
631 ret = -EBUSY;
632 goto err_free_hw;
633 }
634 hw->v_regs = ioremap_nocache(carminefb_fix.mmio_start,
635 carminefb_fix.mmio_len);
636 if (!hw->v_regs) {
637 printk(KERN_ERR "carminefb: Can't remap %s register.\n",
638 carminefb_fix.id);
639 goto err_free_reg_mmio;
640 }
641
642 carminefb_fix.smem_start = pci_resource_start(dev, CARMINE_MEMORY_BAR);
643 carminefb_fix.smem_len = pci_resource_len(dev, CARMINE_MEMORY_BAR);
644
645 /* The memory area tends to be very large (256 MiB). Remap only what
646 * is required for that largest resolution to avoid remaps at run
647 * time
648 */
649 if (carminefb_fix.smem_len > CARMINE_TOTAL_DIPLAY_MEM)
650 carminefb_fix.smem_len = CARMINE_TOTAL_DIPLAY_MEM;
651
652 else if (carminefb_fix.smem_len < CARMINE_TOTAL_DIPLAY_MEM) {
653 printk(KERN_ERR "carminefb: Memory bar is only %d bytes, %d "
654 "are required.", carminefb_fix.smem_len,
655 CARMINE_TOTAL_DIPLAY_MEM);
656 goto err_free_reg_mmio;
657 }
658
659 if (!request_mem_region(carminefb_fix.smem_start,
660 carminefb_fix.smem_len, "carminefb smem")) {
661 printk(KERN_ERR "carminefb: Can't reserve smem.\n");
662 goto err_unmap_vregs;
663 }
664
665 hw->screen_mem = ioremap_nocache(carminefb_fix.smem_start,
666 carminefb_fix.smem_len);
667 if (!hw->screen_mem) {
668 printk(KERN_ERR "carmine: Can't ioremap smem area.\n");
669 release_mem_region(carminefb_fix.smem_start,
670 carminefb_fix.smem_len);
671 goto err_reg_smem;
672 }
673
674 ret = init_hardware(hw);
675 if (ret)
676 goto err_unmap_screen;
677
678 info = NULL;
679 if (fb_displays & CARMINE_USE_DISPLAY0) {
680 ret = alloc_carmine_fb(hw->v_regs + CARMINE_DISP0_REG,
681 hw->screen_mem, CARMINE_DISPLAY_MEM * 0,
682 device, &info);
683 if (ret)
684 goto err_deinit_hw;
685 }
686
687 hw->fb[0] = info;
688
689 info = NULL;
690 if (fb_displays & CARMINE_USE_DISPLAY1) {
691 ret = alloc_carmine_fb(hw->v_regs + CARMINE_DISP1_REG,
692 hw->screen_mem, CARMINE_DISPLAY_MEM * 1,
693 device, &info);
694 if (ret)
695 goto err_cleanup_fb0;
696 }
697
698 hw->fb[1] = info;
699 info = NULL;
700
701 pci_set_drvdata(dev, hw);
702 return 0;
703
704err_cleanup_fb0:
705 cleanup_fb_device(hw->fb[0]);
706err_deinit_hw:
707 /* disable clock, etc */
708 c_set_hw_reg(hw, CARMINE_CTL_REG + CARMINE_CTL_REG_CLOCK_ENABLE, 0);
709err_unmap_screen:
710 iounmap(hw->screen_mem);
711err_reg_smem:
712 release_mem_region(carminefb_fix.mmio_start, carminefb_fix.mmio_len);
713err_unmap_vregs:
714 iounmap(hw->v_regs);
715err_free_reg_mmio:
716 release_mem_region(carminefb_fix.mmio_start, carminefb_fix.mmio_len);
717err_free_hw:
718 kfree(hw);
719err_enable_pci:
720 pci_disable_device(dev);
721 return ret;
722}
723
724static void __devexit carminefb_remove(struct pci_dev *dev)
725{
726 struct carmine_hw *hw = pci_get_drvdata(dev);
727 struct fb_fix_screeninfo fix;
728 int i;
729
730 /* in case we use only fb1 and not fb1 */
731 if (hw->fb[0])
732 fix = hw->fb[0]->fix;
733 else
734 fix = hw->fb[1]->fix;
735
736 /* deactivate display(s) and switch clocks */
737 c_set_hw_reg(hw, CARMINE_DISP0_REG + CARMINE_DISP_REG_DCM1, 0);
738 c_set_hw_reg(hw, CARMINE_DISP1_REG + CARMINE_DISP_REG_DCM1, 0);
739 c_set_hw_reg(hw, CARMINE_CTL_REG + CARMINE_CTL_REG_CLOCK_ENABLE, 0);
740
741 for (i = 0; i < MAX_DISPLAY; i++)
742 cleanup_fb_device(hw->fb[i]);
743
744 iounmap(hw->screen_mem);
745 release_mem_region(fix.smem_start, fix.smem_len);
746 iounmap(hw->v_regs);
747 release_mem_region(fix.mmio_start, fix.mmio_len);
748
749 pci_set_drvdata(dev, NULL);
750 pci_disable_device(dev);
751 kfree(hw);
752}
753
754#define PCI_VENDOR_ID_FUJITU_LIMITED 0x10cf
755static struct pci_device_id carmine_devices[] __devinitdata = {
756{
757 PCI_DEVICE(PCI_VENDOR_ID_FUJITU_LIMITED, 0x202b)},
758 {0, 0, 0, 0, 0, 0, 0}
759};
760
761MODULE_DEVICE_TABLE(pci, carmine_devices);
762
763static struct pci_driver carmine_pci_driver = {
764 .name = "carminefb",
765 .id_table = carmine_devices,
766 .probe = carminefb_probe,
767 .remove = __devexit_p(carminefb_remove),
768};
769
770static int __init carminefb_init(void)
771{
772 if (!(fb_displays &
773 (CARMINE_USE_DISPLAY0 | CARMINE_USE_DISPLAY1))) {
774 printk(KERN_ERR "If you disable both displays than you don't "
775 "need the driver at all\n");
776 return -EINVAL;
777 }
778 return pci_register_driver(&carmine_pci_driver);
779}
780module_init(carminefb_init);
781
782static void __exit carminefb_cleanup(void)
783{
784 pci_unregister_driver(&carmine_pci_driver);
785}
786module_exit(carminefb_cleanup);
787
788MODULE_AUTHOR("Sebastian Siewior <bigeasy@linutronix.de>");
789MODULE_DESCRIPTION("Framebuffer driver for Fujitsu Carmine based devices");
790MODULE_LICENSE("GPL v2");
diff --git a/drivers/video/carminefb.h b/drivers/video/carminefb.h
new file mode 100644
index 000000000000..05306de0c6b6
--- /dev/null
+++ b/drivers/video/carminefb.h
@@ -0,0 +1,64 @@
1#ifndef CARMINE_CARMINE_H
2#define CARMINE_CARMINE_H
3
4#define CARMINE_MEMORY_BAR 2
5#define CARMINE_CONFIG_BAR 3
6
7#define MAX_DISPLAY 2
8#define CARMINE_DISPLAY_MEM (800 * 600 * 4)
9#define CARMINE_TOTAL_DIPLAY_MEM (CARMINE_DISPLAY_MEM * MAX_DISPLAY)
10
11#define CARMINE_USE_DISPLAY0 (1 << 0)
12#define CARMINE_USE_DISPLAY1 (1 << 1)
13
14/*
15 * This values work on the eval card. Custom boards may use different timings,
16 * here an example :)
17 */
18
19/* DRAM initialization values */
20#ifdef CONFIG_FB_CARMINE_DRAM_EVAL
21
22#define CARMINE_DFLT_IP_CLOCK_ENABLE (0x03ff)
23#define CARMINE_DFLT_IP_DCTL_ADD (0x05c3)
24#define CARMINE_DFLT_IP_DCTL_MODE (0x0121)
25#define CARMINE_DFLT_IP_DCTL_EMODE (0x8000)
26#define CARMINE_DFLT_IP_DCTL_SET_TIME1 (0x4749)
27#define CARMINE_DFLT_IP_DCTL_SET_TIME2 (0x2a22)
28#define CARMINE_DFLT_IP_DCTL_REFRESH (0x0042)
29#define CARMINE_DFLT_IP_DCTL_STATES (0x0003)
30#define CARMINE_DFLT_IP_DCTL_RESERVE0 (0x0020)
31#define CARMINE_DFLT_IP_DCTL_FIFO_DEPTH (0x000f)
32#define CARMINE_DFLT_IP_DCTL_RESERVE2 (0x0000)
33#define CARMINE_DFLT_IP_DCTL_DDRIF1 (0x6646)
34#define CARMINE_DFLT_IP_DCTL_DDRIF2 (0x0055)
35#define CARMINE_DFLT_IP_DCTL_MODE_AFT_RST (0x0021)
36#define CARMINE_DFLT_IP_DCTL_STATES_AFT_RST (0x0002)
37#define CARMINE_DFLT_IP_DCTL_IO_CONT0 (0x0555)
38#define CARMINE_DFLT_IP_DCTL_IO_CONT1 (0x0555)
39#define CARMINE_DCTL_DLL_RESET (1)
40#endif
41
42#ifdef CONFIG_CARMINE_DRAM_CUSTOM
43
44#define CARMINE_DFLT_IP_CLOCK_ENABLE (0x03ff)
45#define CARMINE_DFLT_IP_DCTL_ADD (0x03b2)
46#define CARMINE_DFLT_IP_DCTL_MODE (0x0161)
47#define CARMINE_DFLT_IP_DCTL_EMODE (0x8000)
48#define CARMINE_DFLT_IP_DCTL_SET_TIME1 (0x2628)
49#define CARMINE_DFLT_IP_DCTL_SET_TIME2 (0x1a09)
50#define CARMINE_DFLT_IP_DCTL_REFRESH (0x00fe)
51#define CARMINE_DFLT_IP_DCTL_STATES (0x0003)
52#define CARMINE_DFLT_IP_DCTL_RESERVE0 (0x0020)
53#define CARMINE_DFLT_IP_DCTL_FIFO_DEPTH (0x000f)
54#define CARMINE_DFLT_IP_DCTL_RESERVE2 (0x0000)
55#define CARMINE_DFLT_IP_DCTL_DDRIF1 (0x0646)
56#define CARMINE_DFLT_IP_DCTL_DDRIF2 (0x55aa)
57#define CARMINE_DFLT_IP_DCTL_MODE_AFT_RST (0x0061)
58#define CARMINE_DFLT_IP_DCTL_STATES_AFT_RST (0x0002)
59#define CARMINE_DFLT_IP_DCTL_IO_CONT0 (0x0555)
60#define CARMINE_DFLT_IP_DCTL_IO_CONT1 (0x0555)
61#define CARMINE_DCTL_DLL_RESET (1)
62#endif
63
64#endif
diff --git a/drivers/video/carminefb_regs.h b/drivers/video/carminefb_regs.h
new file mode 100644
index 000000000000..045215600b73
--- /dev/null
+++ b/drivers/video/carminefb_regs.h
@@ -0,0 +1,159 @@
1#ifndef _CARMINEFB_REGS_H
2#define _CARMINEFB_REGS_H
3
4#define CARMINE_OVERLAY_EXT_MODE (0x00000002)
5#define CARMINE_GRAPH_REG (0x00000000)
6#define CARMINE_DISP0_REG (0x00100000)
7#define CARMINE_DISP1_REG (0x00140000)
8#define CARMINE_WB_REG (0x00180000)
9#define CARMINE_DCTL_REG (0x00300000)
10#define CARMINE_CTL_REG (0x00400000)
11#define CARMINE_WINDOW_MODE (0x00000001)
12#define CARMINE_EXTEND_MODE (CARMINE_WINDOW_MODE | \
13 CARMINE_OVERLAY_EXT_MODE)
14#define CARMINE_L0E (1 << 16)
15#define CARMINE_L2E (1 << 18)
16#define CARMINE_DEN (1 << 31)
17
18#define CARMINE_EXT_CMODE_DIRECT24_RGBA (0xC0000000)
19#define CARMINE_DCTL_REG_MODE_ADD (0x00)
20#define CARMINE_DCTL_REG_SETTIME1_EMODE (0x04)
21#define CARMINE_DCTL_REG_REFRESH_SETTIME2 (0x08)
22#define CARMINE_DCTL_REG_RSV0_STATES (0x0C)
23#define CARMINE_DCTL_REG_RSV2_RSV1 (0x10)
24#define CARMINE_DCTL_REG_DDRIF2_DDRIF1 (0x14)
25#define CARMINE_DCTL_REG_IOCONT1_IOCONT0 (0x24)
26#define CARMINE_DCTL_REG_STATES_MASK (0x000F)
27#define CARMINE_DCTL_INIT_WAIT_INTERVAL (1)
28#define CARMINE_DCTL_INIT_WAIT_LIMIT (5000)
29#define CARMINE_WB_REG_WBM_DEFAULT (0x0001c020)
30#define CARMINE_DISP_REG_L0RM (0x1880)
31#define CARMINE_DISP_REG_L0PX (0x1884)
32#define CARMINE_DISP_REG_L0PY (0x1888)
33#define CARMINE_DISP_REG_L2RM (0x18A0)
34#define CARMINE_DISP_REG_L2PX (0x18A4)
35#define CARMINE_DISP_REG_L2PY (0x18A8)
36#define CARMINE_DISP_REG_L3RM (0x18B0)
37#define CARMINE_DISP_REG_L3PX (0x18B4)
38#define CARMINE_DISP_REG_L3PY (0x18B8)
39#define CARMINE_DISP_REG_L4RM (0x18C0)
40#define CARMINE_DISP_REG_L4PX (0x18C4)
41#define CARMINE_DISP_REG_L4PY (0x18C8)
42#define CARMINE_DISP_REG_L5RM (0x18D0)
43#define CARMINE_DISP_REG_L5PX (0x18D4)
44#define CARMINE_DISP_REG_L5PY (0x18D8)
45#define CARMINE_DISP_REG_L6RM (0x1924)
46#define CARMINE_DISP_REG_L6PX (0x1928)
47#define CARMINE_DISP_REG_L6PY (0x192C)
48#define CARMINE_DISP_REG_L7RM (0x1964)
49#define CARMINE_DISP_REG_L7PX (0x1968)
50#define CARMINE_DISP_REG_L7PY (0x196C)
51#define CARMINE_WB_REG_WBM (0x0004)
52#define CARMINE_DISP_HTP_SHIFT (16)
53#define CARMINE_DISP_HDB_SHIFT (16)
54#define CARMINE_DISP_HSW_SHIFT (16)
55#define CARMINE_DISP_VSW_SHIFT (24)
56#define CARMINE_DISP_VTR_SHIFT (16)
57#define CARMINE_DISP_VDP_SHIFT (16)
58#define CARMINE_CURSOR_CUTZ_MASK (0x00000100)
59#define CARMINE_CURSOR0_PRIORITY_MASK (0x00010000)
60#define CARMINE_CURSOR1_PRIORITY_MASK (0x00020000)
61#define CARMINE_DISP_WIDTH_SHIFT (16)
62#define CARMINE_DISP_WIN_H_SHIFT (16)
63#define CARMINE_DISP_REG_H_TOTAL (0x0004)
64#define CARMINE_DISP_REG_H_PERIOD (0x0008)
65#define CARMINE_DISP_REG_V_H_W_H_POS (0x000C)
66#define CARMINE_DISP_REG_V_TOTAL (0x0010)
67#define CARMINE_DISP_REG_V_PERIOD_POS (0x0014)
68#define CARMINE_DISP_REG_L0_MODE_W_H (0x0020)
69#define CARMINE_DISP_REG_L0_ORG_ADR (0x0024)
70#define CARMINE_DISP_REG_L0_DISP_ADR (0x0028)
71#define CARMINE_DISP_REG_L0_DISP_POS (0x002C)
72#define CARMINE_DISP_REG_L1_WIDTH (0x0030)
73#define CARMINE_DISP_REG_L1_ORG_ADR (0x0034)
74#define CARMINE_DISP_REG_L2_MODE_W_H (0x0040)
75#define CARMINE_DISP_REG_L2_ORG_ADR1 (0x0044)
76#define CARMINE_DISP_REG_L2_DISP_ADR1 (0x0048)
77#define CARMINE_DISP_REG_L2_DISP_POS (0x0054)
78#define CARMINE_DISP_REG_L3_MODE_W_H (0x0058)
79#define CARMINE_DISP_REG_L3_ORG_ADR1 (0x005C)
80#define CARMINE_DISP_REG_L3_DISP_ADR1 (0x0060)
81#define CARMINE_DISP_REG_L3_DISP_POS (0x006C)
82#define CARMINE_DISP_REG_L4_MODE_W_H (0x0070)
83#define CARMINE_DISP_REG_L4_ORG_ADR1 (0x0074)
84#define CARMINE_DISP_REG_L4_DISP_ADR1 (0x0078)
85#define CARMINE_DISP_REG_L4_DISP_POS (0x0084)
86#define CARMINE_DISP_REG_L5_MODE_W_H (0x0088)
87#define CARMINE_DISP_REG_L5_ORG_ADR1 (0x008C)
88#define CARMINE_DISP_REG_L5_DISP_ADR1 (0x0090)
89#define CARMINE_DISP_REG_L5_DISP_POS (0x009C)
90#define CARMINE_DISP_REG_CURSOR_MODE (0x00A0)
91#define CARMINE_DISP_REG_CUR1_POS (0x00A8)
92#define CARMINE_DISP_REG_CUR2_POS (0x00B0)
93#define CARMINE_DISP_REG_C_TRANS (0x00BC)
94#define CARMINE_DISP_REG_MLMR_TRANS (0x00C0)
95#define CARMINE_DISP_REG_L0_EXT_MODE (0x0110)
96#define CARMINE_DISP_REG_L0_WIN_POS (0x0114)
97#define CARMINE_DISP_REG_L0_WIN_SIZE (0x0118)
98#define CARMINE_DISP_REG_L1_EXT_MODE (0x0120)
99#define CARMINE_DISP_REG_L1_WIN_POS (0x0124)
100#define CARMINE_DISP_REG_L1_WIN_SIZE (0x0128)
101#define CARMINE_DISP_REG_L2_EXT_MODE (0x0130)
102#define CARMINE_DISP_REG_L2_WIN_POS (0x0134)
103#define CARMINE_DISP_REG_L2_WIN_SIZE (0x0138)
104#define CARMINE_DISP_REG_L3_EXT_MODE (0x0140)
105#define CARMINE_DISP_REG_L3_WIN_POS (0x0144)
106#define CARMINE_DISP_REG_L3_WIN_SIZE (0x0148)
107#define CARMINE_DISP_REG_L4_EXT_MODE (0x0150)
108#define CARMINE_DISP_REG_L4_WIN_POS (0x0154)
109#define CARMINE_DISP_REG_L4_WIN_SIZE (0x0158)
110#define CARMINE_DISP_REG_L5_EXT_MODE (0x0160)
111#define CARMINE_DISP_REG_L5_WIN_POS (0x0164)
112#define CARMINE_DISP_REG_L5_WIN_SIZE (0x0168)
113#define CARMINE_DISP_REG_L6_EXT_MODE (0x1918)
114#define CARMINE_DISP_REG_L6_WIN_POS (0x191c)
115#define CARMINE_DISP_REG_L6_WIN_SIZE (0x1920)
116#define CARMINE_DISP_REG_L7_EXT_MODE (0x1958)
117#define CARMINE_DISP_REG_L7_WIN_POS (0x195c)
118#define CARMINE_DISP_REG_L7_WIN_SIZE (0x1960)
119#define CARMINE_DISP_REG_BLEND_MODE_L0 (0x00B4)
120#define CARMINE_DISP_REG_BLEND_MODE_L1 (0x0188)
121#define CARMINE_DISP_REG_BLEND_MODE_L2 (0x018C)
122#define CARMINE_DISP_REG_BLEND_MODE_L3 (0x0190)
123#define CARMINE_DISP_REG_BLEND_MODE_L4 (0x0194)
124#define CARMINE_DISP_REG_BLEND_MODE_L5 (0x0198)
125#define CARMINE_DISP_REG_BLEND_MODE_L6 (0x1990)
126#define CARMINE_DISP_REG_BLEND_MODE_L7 (0x1994)
127#define CARMINE_DISP_REG_L0_TRANS (0x01A0)
128#define CARMINE_DISP_REG_L1_TRANS (0x01A4)
129#define CARMINE_DISP_REG_L2_TRANS (0x01A8)
130#define CARMINE_DISP_REG_L3_TRANS (0x01AC)
131#define CARMINE_DISP_REG_L4_TRANS (0x01B0)
132#define CARMINE_DISP_REG_L5_TRANS (0x01B4)
133#define CARMINE_DISP_REG_L6_TRANS (0x1998)
134#define CARMINE_DISP_REG_L7_TRANS (0x199c)
135#define CARMINE_EXTEND_MODE_MASK (0x00000003)
136#define CARMINE_DISP_DCM_MASK (0x0000FFFF)
137#define CARMINE_DISP_REG_DCM1 (0x0100)
138#define CARMINE_DISP_WIDTH_UNIT (64)
139#define CARMINE_DISP_REG_L6_MODE_W_H (0x1900)
140#define CARMINE_DISP_REG_L6_ORG_ADR1 (0x1904)
141#define CARMINE_DISP_REG_L6_DISP_ADR0 (0x1908)
142#define CARMINE_DISP_REG_L6_DISP_POS (0x1914)
143#define CARMINE_DISP_REG_L7_MODE_W_H (0x1940)
144#define CARMINE_DISP_REG_L7_ORG_ADR1 (0x1944)
145#define CARMINE_DISP_REG_L7_DISP_ADR0 (0x1948)
146#define CARMINE_DISP_REG_L7_DISP_POS (0x1954)
147#define CARMINE_CTL_REG_CLOCK_ENABLE (0x000C)
148#define CARMINE_CTL_REG_SOFTWARE_RESET (0x0010)
149#define CARMINE_CTL_REG_IST_MASK_ALL (0x07FFFFFF)
150#define CARMINE_GRAPH_REG_VRINTM (0x00028064)
151#define CARMINE_GRAPH_REG_VRERRM (0x0002806C)
152#define CARMINE_GRAPH_REG_DC_OFFSET_PX (0x0004005C)
153#define CARMINE_GRAPH_REG_DC_OFFSET_PY (0x00040060)
154#define CARMINE_GRAPH_REG_DC_OFFSET_LX (0x00040064)
155#define CARMINE_GRAPH_REG_DC_OFFSET_LY (0x00040068)
156#define CARMINE_GRAPH_REG_DC_OFFSET_TX (0x0004006C)
157#define CARMINE_GRAPH_REG_DC_OFFSET_TY (0x00040070)
158
159#endif
diff --git a/drivers/video/cobalt_lcdfb.c b/drivers/video/cobalt_lcdfb.c
new file mode 100644
index 000000000000..7bad24ed04ef
--- /dev/null
+++ b/drivers/video/cobalt_lcdfb.c
@@ -0,0 +1,371 @@
1/*
2 * Cobalt server LCD frame buffer driver.
3 *
4 * Copyright (C) 2008 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20#include <linux/delay.h>
21#include <linux/fb.h>
22#include <linux/init.h>
23#include <linux/io.h>
24#include <linux/ioport.h>
25#include <linux/uaccess.h>
26#include <linux/platform_device.h>
27
28/*
29 * Cursor position address
30 * \X 0 1 2 ... 14 15
31 * Y+----+----+----+---+----+----+
32 * 0|0x00|0x01|0x02|...|0x0e|0x0f|
33 * +----+----+----+---+----+----+
34 * 1|0x40|0x41|0x42|...|0x4e|0x4f|
35 * +----+----+----+---+----+----+
36 */
37#define LCD_DATA_REG_OFFSET 0x10
38#define LCD_XRES_MAX 16
39#define LCD_YRES_MAX 2
40#define LCD_CHARS_MAX 32
41
42#define LCD_CLEAR 0x01
43#define LCD_CURSOR_MOVE_HOME 0x02
44#define LCD_RESET 0x06
45#define LCD_OFF 0x08
46#define LCD_CURSOR_OFF 0x0c
47#define LCD_CURSOR_BLINK_OFF 0x0e
48#define LCD_CURSOR_ON 0x0f
49#define LCD_ON LCD_CURSOR_ON
50#define LCD_CURSOR_MOVE_LEFT 0x10
51#define LCD_CURSOR_MOVE_RIGHT 0x14
52#define LCD_DISPLAY_LEFT 0x18
53#define LCD_DISPLAY_RIGHT 0x1c
54#define LCD_PRERESET 0x3f /* execute 4 times continuously */
55#define LCD_BUSY 0x80
56
57#define LCD_GRAPHIC_MODE 0x40
58#define LCD_TEXT_MODE 0x80
59#define LCD_CUR_POS_MASK 0x7f
60
61#define LCD_CUR_POS(x) ((x) & LCD_CUR_POS_MASK)
62#define LCD_TEXT_POS(x) ((x) | LCD_TEXT_MODE)
63
64static inline void lcd_write_control(struct fb_info *info, u8 control)
65{
66 writel((u32)control << 24, info->screen_base);
67}
68
69static inline u8 lcd_read_control(struct fb_info *info)
70{
71 return readl(info->screen_base) >> 24;
72}
73
74static inline void lcd_write_data(struct fb_info *info, u8 data)
75{
76 writel((u32)data << 24, info->screen_base + LCD_DATA_REG_OFFSET);
77}
78
79static inline u8 lcd_read_data(struct fb_info *info)
80{
81 return readl(info->screen_base + LCD_DATA_REG_OFFSET) >> 24;
82}
83
84static int lcd_busy_wait(struct fb_info *info)
85{
86 u8 val = 0;
87 int timeout = 10, retval = 0;
88
89 do {
90 val = lcd_read_control(info);
91 val &= LCD_BUSY;
92 if (val != LCD_BUSY)
93 break;
94
95 if (msleep_interruptible(1))
96 return -EINTR;
97
98 timeout--;
99 } while (timeout);
100
101 if (val == LCD_BUSY)
102 retval = -EBUSY;
103
104 return retval;
105}
106
107static void lcd_clear(struct fb_info *info)
108{
109 int i;
110
111 for (i = 0; i < 4; i++) {
112 udelay(150);
113
114 lcd_write_control(info, LCD_PRERESET);
115 }
116
117 udelay(150);
118
119 lcd_write_control(info, LCD_CLEAR);
120
121 udelay(150);
122
123 lcd_write_control(info, LCD_RESET);
124}
125
126static struct fb_fix_screeninfo cobalt_lcdfb_fix __initdata = {
127 .id = "cobalt-lcd",
128 .type = FB_TYPE_TEXT,
129 .type_aux = FB_AUX_TEXT_MDA,
130 .visual = FB_VISUAL_MONO01,
131 .line_length = LCD_XRES_MAX,
132 .accel = FB_ACCEL_NONE,
133};
134
135static ssize_t cobalt_lcdfb_read(struct fb_info *info, char __user *buf,
136 size_t count, loff_t *ppos)
137{
138 char src[LCD_CHARS_MAX];
139 unsigned long pos;
140 int len, retval = 0;
141
142 pos = *ppos;
143 if (pos >= LCD_CHARS_MAX || count == 0)
144 return 0;
145
146 if (count > LCD_CHARS_MAX)
147 count = LCD_CHARS_MAX;
148
149 if (pos + count > LCD_CHARS_MAX)
150 count = LCD_CHARS_MAX - pos;
151
152 for (len = 0; len < count; len++) {
153 retval = lcd_busy_wait(info);
154 if (retval < 0)
155 break;
156
157 lcd_write_control(info, LCD_TEXT_POS(pos));
158
159 retval = lcd_busy_wait(info);
160 if (retval < 0)
161 break;
162
163 src[len] = lcd_read_data(info);
164 if (pos == 0x0f)
165 pos = 0x40;
166 else
167 pos++;
168 }
169
170 if (retval < 0 && signal_pending(current))
171 return -ERESTARTSYS;
172
173 if (copy_to_user(buf, src, len))
174 return -EFAULT;
175
176 *ppos += len;
177
178 return len;
179}
180
181static ssize_t cobalt_lcdfb_write(struct fb_info *info, const char __user *buf,
182 size_t count, loff_t *ppos)
183{
184 char dst[LCD_CHARS_MAX];
185 unsigned long pos;
186 int len, retval = 0;
187
188 pos = *ppos;
189 if (pos >= LCD_CHARS_MAX || count == 0)
190 return 0;
191
192 if (count > LCD_CHARS_MAX)
193 count = LCD_CHARS_MAX;
194
195 if (pos + count > LCD_CHARS_MAX)
196 count = LCD_CHARS_MAX - pos;
197
198 if (copy_from_user(dst, buf, count))
199 return -EFAULT;
200
201 for (len = 0; len < count; len++) {
202 retval = lcd_busy_wait(info);
203 if (retval < 0)
204 break;
205
206 lcd_write_control(info, LCD_TEXT_POS(pos));
207
208 retval = lcd_busy_wait(info);
209 if (retval < 0)
210 break;
211
212 lcd_write_data(info, dst[len]);
213 if (pos == 0x0f)
214 pos = 0x40;
215 else
216 pos++;
217 }
218
219 if (retval < 0 && signal_pending(current))
220 return -ERESTARTSYS;
221
222 *ppos += len;
223
224 return len;
225}
226
227static int cobalt_lcdfb_blank(int blank_mode, struct fb_info *info)
228{
229 int retval;
230
231 retval = lcd_busy_wait(info);
232 if (retval < 0)
233 return retval;
234
235 switch (blank_mode) {
236 case FB_BLANK_UNBLANK:
237 lcd_write_control(info, LCD_ON);
238 break;
239 default:
240 lcd_write_control(info, LCD_OFF);
241 break;
242 }
243
244 return 0;
245}
246
247static int cobalt_lcdfb_cursor(struct fb_info *info, struct fb_cursor *cursor)
248{
249 u32 x, y;
250 int retval;
251
252 switch (cursor->set) {
253 case FB_CUR_SETPOS:
254 x = cursor->image.dx;
255 y = cursor->image.dy;
256 if (x >= LCD_XRES_MAX || y >= LCD_YRES_MAX)
257 return -EINVAL;
258
259 retval = lcd_busy_wait(info);
260 if (retval < 0)
261 return retval;
262
263 lcd_write_control(info,
264 LCD_TEXT_POS(info->fix.line_length * y + x));
265 break;
266 default:
267 return -EINVAL;
268 }
269
270 retval = lcd_busy_wait(info);
271 if (retval < 0)
272 return retval;
273
274 if (cursor->enable)
275 lcd_write_control(info, LCD_CURSOR_ON);
276 else
277 lcd_write_control(info, LCD_CURSOR_OFF);
278
279 return 0;
280}
281
282static struct fb_ops cobalt_lcd_fbops = {
283 .owner = THIS_MODULE,
284 .fb_read = cobalt_lcdfb_read,
285 .fb_write = cobalt_lcdfb_write,
286 .fb_blank = cobalt_lcdfb_blank,
287 .fb_cursor = cobalt_lcdfb_cursor,
288};
289
290static int __init cobalt_lcdfb_probe(struct platform_device *dev)
291{
292 struct fb_info *info;
293 struct resource *res;
294 int retval;
295
296 info = framebuffer_alloc(0, &dev->dev);
297 if (!info)
298 return -ENOMEM;
299
300 res = platform_get_resource(dev, IORESOURCE_MEM, 0);
301 if (!res) {
302 framebuffer_release(info);
303 return -EBUSY;
304 }
305
306 info->screen_size = res->end - res->start + 1;
307 info->screen_base = ioremap(res->start, info->screen_size);
308 info->fbops = &cobalt_lcd_fbops;
309 info->fix = cobalt_lcdfb_fix;
310 info->fix.smem_start = res->start;
311 info->fix.smem_len = info->screen_size;
312 info->pseudo_palette = NULL;
313 info->par = NULL;
314 info->flags = FBINFO_DEFAULT;
315
316 retval = register_framebuffer(info);
317 if (retval < 0) {
318 iounmap(info->screen_base);
319 framebuffer_release(info);
320 return retval;
321 }
322
323 platform_set_drvdata(dev, info);
324
325 lcd_clear(info);
326
327 printk(KERN_INFO "fb%d: Cobalt server LCD frame buffer device\n",
328 info->node);
329
330 return 0;
331}
332
333static int __devexit cobalt_lcdfb_remove(struct platform_device *dev)
334{
335 struct fb_info *info;
336
337 info = platform_get_drvdata(dev);
338 if (info) {
339 iounmap(info->screen_base);
340 unregister_framebuffer(info);
341 framebuffer_release(info);
342 }
343
344 return 0;
345}
346
347static struct platform_driver cobalt_lcdfb_driver = {
348 .probe = cobalt_lcdfb_probe,
349 .remove = __devexit_p(cobalt_lcdfb_remove),
350 .driver = {
351 .name = "cobalt-lcd",
352 .owner = THIS_MODULE,
353 },
354};
355
356static int __init cobalt_lcdfb_init(void)
357{
358 return platform_driver_register(&cobalt_lcdfb_driver);
359}
360
361static void __exit cobalt_lcdfb_exit(void)
362{
363 platform_driver_unregister(&cobalt_lcdfb_driver);
364}
365
366module_init(cobalt_lcdfb_init);
367module_exit(cobalt_lcdfb_exit);
368
369MODULE_LICENSE("GPL v2");
370MODULE_AUTHOR("Yoichi Yuasa");
371MODULE_DESCRIPTION("Cobalt server LCD frame buffer driver");
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
index 97aff8db10bf..3ccfa76d9b2a 100644
--- a/drivers/video/console/fbcon.c
+++ b/drivers/video/console/fbcon.c
@@ -107,9 +107,7 @@ static struct display fb_display[MAX_NR_CONSOLES];
107 107
108static signed char con2fb_map[MAX_NR_CONSOLES]; 108static signed char con2fb_map[MAX_NR_CONSOLES];
109static signed char con2fb_map_boot[MAX_NR_CONSOLES]; 109static signed char con2fb_map_boot[MAX_NR_CONSOLES];
110#ifndef MODULE 110
111static int logo_height;
112#endif
113static int logo_lines; 111static int logo_lines;
114/* logo_shown is an index to vc_cons when >= 0; otherwise follows FBCON_LOGO 112/* logo_shown is an index to vc_cons when >= 0; otherwise follows FBCON_LOGO
115 enums. */ 113 enums. */
@@ -607,6 +605,7 @@ static void fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info,
607 struct fbcon_ops *ops = info->fbcon_par; 605 struct fbcon_ops *ops = info->fbcon_par;
608 int cnt, erase = vc->vc_video_erase_char, step; 606 int cnt, erase = vc->vc_video_erase_char, step;
609 unsigned short *save = NULL, *r, *q; 607 unsigned short *save = NULL, *r, *q;
608 int logo_height;
610 609
611 if (info->flags & FBINFO_MODULE) { 610 if (info->flags & FBINFO_MODULE) {
612 logo_shown = FBCON_LOGO_DONTSHOW; 611 logo_shown = FBCON_LOGO_DONTSHOW;
@@ -3586,7 +3585,8 @@ static int __init fb_console_init(void)
3586 3585
3587 acquire_console_sem(); 3586 acquire_console_sem();
3588 fb_register_client(&fbcon_event_notifier); 3587 fb_register_client(&fbcon_event_notifier);
3589 fbcon_device = device_create(fb_class, NULL, MKDEV(0, 0), "fbcon"); 3588 fbcon_device = device_create_drvdata(fb_class, NULL, MKDEV(0, 0),
3589 NULL, "fbcon");
3590 3590
3591 if (IS_ERR(fbcon_device)) { 3591 if (IS_ERR(fbcon_device)) {
3592 printk(KERN_WARNING "Unable to create device " 3592 printk(KERN_WARNING "Unable to create device "
diff --git a/drivers/video/console/fbcon.h b/drivers/video/console/fbcon.h
index 0135e0395456..de1b1365279b 100644
--- a/drivers/video/console/fbcon.h
+++ b/drivers/video/console/fbcon.h
@@ -92,7 +92,7 @@ struct fbcon_ops {
92#define attr_fgcol(fgshift,s) \ 92#define attr_fgcol(fgshift,s) \
93 (((s) >> (fgshift)) & 0x0f) 93 (((s) >> (fgshift)) & 0x0f)
94#define attr_bgcol(bgshift,s) \ 94#define attr_bgcol(bgshift,s) \
95 (((s) >> (bgshift)) & 0x0f) 95 (((s) >> (bgshift)) & 0x07)
96 96
97/* Monochrome */ 97/* Monochrome */
98#define attr_bold(s) \ 98#define attr_bold(s) \
@@ -146,10 +146,8 @@ static inline int attr_col_ec(int shift, struct vc_data *vc,
146 return is_fg ? fg : bg; 146 return is_fg ? fg : bg;
147} 147}
148 148
149#define attr_bgcol_ec(bgshift,vc,info) \ 149#define attr_bgcol_ec(bgshift, vc, info) attr_col_ec(bgshift, vc, info, 0)
150 attr_col_ec(bgshift,vc,info,0); 150#define attr_fgcol_ec(fgshift, vc, info) attr_col_ec(fgshift, vc, info, 1)
151#define attr_fgcol_ec(fgshift,vc,info) \
152 attr_col_ec(fgshift,vc,info,1);
153 151
154/* Font */ 152/* Font */
155#define REFCOUNT(fd) (((int *)(fd))[-1]) 153#define REFCOUNT(fd) (((int *)(fd))[-1])
diff --git a/drivers/video/console/mdacon.c b/drivers/video/console/mdacon.c
index 38a296bbdfc9..9901064199bd 100644
--- a/drivers/video/console/mdacon.c
+++ b/drivers/video/console/mdacon.c
@@ -71,13 +71,15 @@ static char *mda_type_name;
71 71
72/* console information */ 72/* console information */
73 73
74static int mda_first_vc = 1; 74static int mda_first_vc = 13;
75static int mda_last_vc = 16; 75static int mda_last_vc = 16;
76 76
77static struct vc_data *mda_display_fg = NULL; 77static struct vc_data *mda_display_fg = NULL;
78 78
79module_param(mda_first_vc, int, 0); 79module_param(mda_first_vc, int, 0);
80MODULE_PARM_DESC(mda_first_vc, "First virtual console. Default: 13");
80module_param(mda_last_vc, int, 0); 81module_param(mda_last_vc, int, 0);
82MODULE_PARM_DESC(mda_last_vc, "Last virtual console. Default: 16");
81 83
82/* MDA register values 84/* MDA register values
83 */ 85 */
diff --git a/drivers/video/console/sticon.c b/drivers/video/console/sticon.c
index a11cc2fdd4cd..4055dbdd1b42 100644
--- a/drivers/video/console/sticon.c
+++ b/drivers/video/console/sticon.c
@@ -370,7 +370,7 @@ static const struct consw sti_con = {
370 370
371 371
372 372
373int __init sticonsole_init(void) 373static int __init sticonsole_init(void)
374{ 374{
375 /* already initialized ? */ 375 /* already initialized ? */
376 if (sticon_sti) 376 if (sticon_sti)
diff --git a/drivers/video/console/sticore.c b/drivers/video/console/sticore.c
index e9ab657f0bb7..d7822af0e00a 100644
--- a/drivers/video/console/sticore.c
+++ b/drivers/video/console/sticore.c
@@ -29,7 +29,7 @@
29 29
30#define STI_DRIVERVERSION "Version 0.9a" 30#define STI_DRIVERVERSION "Version 0.9a"
31 31
32struct sti_struct *default_sti __read_mostly; 32static struct sti_struct *default_sti __read_mostly;
33 33
34/* number of STI ROMS found and their ptrs to each struct */ 34/* number of STI ROMS found and their ptrs to each struct */
35static int num_sti_roms __read_mostly; 35static int num_sti_roms __read_mostly;
@@ -68,8 +68,7 @@ static const struct sti_init_flags default_init_flags = {
68 .init_cmap_tx = 1, 68 .init_cmap_tx = 1,
69}; 69};
70 70
71int 71static int sti_init_graph(struct sti_struct *sti)
72sti_init_graph(struct sti_struct *sti)
73{ 72{
74 struct sti_init_inptr_ext inptr_ext = { 0, }; 73 struct sti_init_inptr_ext inptr_ext = { 0, };
75 struct sti_init_inptr inptr = { 74 struct sti_init_inptr inptr = {
@@ -100,8 +99,7 @@ static const struct sti_conf_flags default_conf_flags = {
100 .wait = STI_WAIT, 99 .wait = STI_WAIT,
101}; 100};
102 101
103void 102static void sti_inq_conf(struct sti_struct *sti)
104sti_inq_conf(struct sti_struct *sti)
105{ 103{
106 struct sti_conf_inptr inptr = { 0, }; 104 struct sti_conf_inptr inptr = { 0, };
107 unsigned long flags; 105 unsigned long flags;
@@ -237,8 +235,8 @@ static void sti_flush(unsigned long start, unsigned long end)
237 flush_icache_range(start, end); 235 flush_icache_range(start, end);
238} 236}
239 237
240void __devinit 238static void __devinit sti_rom_copy(unsigned long base, unsigned long count,
241sti_rom_copy(unsigned long base, unsigned long count, void *dest) 239 void *dest)
242{ 240{
243 unsigned long dest_start = (unsigned long) dest; 241 unsigned long dest_start = (unsigned long) dest;
244 242
@@ -478,8 +476,8 @@ sti_init_glob_cfg(struct sti_struct *sti,
478} 476}
479 477
480#ifdef CONFIG_FB 478#ifdef CONFIG_FB
481struct sti_cooked_font * __devinit 479static struct sti_cooked_font __devinit
482sti_select_fbfont(struct sti_cooked_rom *cooked_rom, const char *fbfont_name) 480*sti_select_fbfont(struct sti_cooked_rom *cooked_rom, const char *fbfont_name)
483{ 481{
484 const struct font_desc *fbfont; 482 const struct font_desc *fbfont;
485 unsigned int size, bpc; 483 unsigned int size, bpc;
@@ -534,16 +532,16 @@ sti_select_fbfont(struct sti_cooked_rom *cooked_rom, const char *fbfont_name)
534 return cooked_font; 532 return cooked_font;
535} 533}
536#else 534#else
537struct sti_cooked_font * __devinit 535static struct sti_cooked_font __devinit
538sti_select_fbfont(struct sti_cooked_rom *cooked_rom, const char *fbfont_name) 536*sti_select_fbfont(struct sti_cooked_rom *cooked_rom, const char *fbfont_name)
539{ 537{
540 return NULL; 538 return NULL;
541} 539}
542#endif 540#endif
543 541
544struct sti_cooked_font * __devinit 542static struct sti_cooked_font __devinit
545sti_select_font(struct sti_cooked_rom *rom, 543*sti_select_font(struct sti_cooked_rom *rom,
546 int (*search_font_fnc) (struct sti_cooked_rom *,int,int) ) 544 int (*search_font_fnc)(struct sti_cooked_rom *, int, int))
547{ 545{
548 struct sti_cooked_font *font; 546 struct sti_cooked_font *font;
549 int i; 547 int i;
@@ -707,8 +705,7 @@ sti_get_bmode_rom (unsigned long address)
707 return raw; 705 return raw;
708} 706}
709 707
710struct sti_rom * __devinit 708static struct sti_rom __devinit *sti_get_wmode_rom(unsigned long address)
711sti_get_wmode_rom (unsigned long address)
712{ 709{
713 struct sti_rom *raw; 710 struct sti_rom *raw;
714 unsigned long size; 711 unsigned long size;
@@ -723,8 +720,8 @@ sti_get_wmode_rom (unsigned long address)
723 return raw; 720 return raw;
724} 721}
725 722
726int __devinit 723static int __devinit sti_read_rom(int wordmode, struct sti_struct *sti,
727sti_read_rom(int wordmode, struct sti_struct *sti, unsigned long address) 724 unsigned long address)
728{ 725{
729 struct sti_cooked_rom *cooked; 726 struct sti_cooked_rom *cooked;
730 struct sti_rom *raw = NULL; 727 struct sti_rom *raw = NULL;
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
index 33ebdb198daf..5d84b3431098 100644
--- a/drivers/video/fbmem.c
+++ b/drivers/video/fbmem.c
@@ -35,6 +35,7 @@
35#include <linux/device.h> 35#include <linux/device.h>
36#include <linux/efi.h> 36#include <linux/efi.h>
37#include <linux/fb.h> 37#include <linux/fb.h>
38#include <linux/major.h>
38 39
39#include <asm/fb.h> 40#include <asm/fb.h>
40 41
@@ -848,9 +849,8 @@ int
848fb_pan_display(struct fb_info *info, struct fb_var_screeninfo *var) 849fb_pan_display(struct fb_info *info, struct fb_var_screeninfo *var)
849{ 850{
850 struct fb_fix_screeninfo *fix = &info->fix; 851 struct fb_fix_screeninfo *fix = &info->fix;
851 int xoffset = var->xoffset; 852 unsigned int yres = info->var.yres;
852 int yoffset = var->yoffset; 853 int err = 0;
853 int err = 0, yres = info->var.yres;
854 854
855 if (var->yoffset > 0) { 855 if (var->yoffset > 0) {
856 if (var->vmode & FB_VMODE_YWRAP) { 856 if (var->vmode & FB_VMODE_YWRAP) {
@@ -866,8 +866,8 @@ fb_pan_display(struct fb_info *info, struct fb_var_screeninfo *var)
866 (var->xoffset % fix->xpanstep))) 866 (var->xoffset % fix->xpanstep)))
867 err = -EINVAL; 867 err = -EINVAL;
868 868
869 if (err || !info->fbops->fb_pan_display || xoffset < 0 || 869 if (err || !info->fbops->fb_pan_display ||
870 yoffset < 0 || var->yoffset + yres > info->var.yres_virtual || 870 var->yoffset + yres > info->var.yres_virtual ||
871 var->xoffset + info->var.xres > info->var.xres_virtual) 871 var->xoffset + info->var.xres > info->var.xres_virtual)
872 return -EINVAL; 872 return -EINVAL;
873 873
@@ -1439,8 +1439,9 @@ register_framebuffer(struct fb_info *fb_info)
1439 break; 1439 break;
1440 fb_info->node = i; 1440 fb_info->node = i;
1441 1441
1442 fb_info->dev = device_create(fb_class, fb_info->device, 1442 fb_info->dev = device_create_drvdata(fb_class, fb_info->device,
1443 MKDEV(FB_MAJOR, i), "fb%d", i); 1443 MKDEV(FB_MAJOR, i), NULL,
1444 "fb%d", i);
1444 if (IS_ERR(fb_info->dev)) { 1445 if (IS_ERR(fb_info->dev)) {
1445 /* Not fatal */ 1446 /* Not fatal */
1446 printk(KERN_WARNING "Unable to create device for framebuffer %d; errno = %ld\n", i, PTR_ERR(fb_info->dev)); 1447 printk(KERN_WARNING "Unable to create device for framebuffer %d; errno = %ld\n", i, PTR_ERR(fb_info->dev));
diff --git a/drivers/video/fbmon.c b/drivers/video/fbmon.c
index 052e18058498..6a0aa180c266 100644
--- a/drivers/video/fbmon.c
+++ b/drivers/video/fbmon.c
@@ -879,7 +879,7 @@ int fb_parse_edid(unsigned char *edid, struct fb_var_screeninfo *var)
879 if (edid_is_timing_block(block)) { 879 if (edid_is_timing_block(block)) {
880 var->xres = var->xres_virtual = H_ACTIVE; 880 var->xres = var->xres_virtual = H_ACTIVE;
881 var->yres = var->yres_virtual = V_ACTIVE; 881 var->yres = var->yres_virtual = V_ACTIVE;
882 var->height = var->width = -1; 882 var->height = var->width = 0;
883 var->right_margin = H_SYNC_OFFSET; 883 var->right_margin = H_SYNC_OFFSET;
884 var->left_margin = (H_ACTIVE + H_BLANKING) - 884 var->left_margin = (H_ACTIVE + H_BLANKING) -
885 (H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH); 885 (H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH);
diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c
index 09d7e22c6fef..9cd36c223d33 100644
--- a/drivers/video/fsl-diu-fb.c
+++ b/drivers/video/fsl-diu-fb.c
@@ -279,58 +279,42 @@ static struct diu_hw dr = {
279 279
280static struct diu_pool pool; 280static struct diu_pool pool;
281 281
282/* To allocate memory for framebuffer. First try __get_free_pages(). If it 282/**
283 * fails, try rh_alloc. The reason is __get_free_pages() cannot allocate 283 * fsl_diu_alloc - allocate memory for the DIU
284 * very large memory (more than 4MB). We don't want to allocate all memory 284 * @size: number of bytes to allocate
285 * in rheap since small memory allocation/deallocation will fragment the 285 * @param: returned physical address of memory
286 * rheap and make the furture large allocation fail. 286 *
287 * This function allocates a physically-contiguous block of memory.
287 */ 288 */
288 289static void *fsl_diu_alloc(size_t size, phys_addr_t *phys)
289static void *fsl_diu_alloc(unsigned long size, phys_addr_t *phys)
290{ 290{
291 void *virt; 291 void *virt;
292 292
293 pr_debug("size=%lu\n", size); 293 pr_debug("size=%zu\n", size);
294 294
295 virt = (void *)__get_free_pages(GFP_DMA | __GFP_ZERO, get_order(size)); 295 virt = alloc_pages_exact(size, GFP_DMA | __GFP_ZERO);
296 if (virt) { 296 if (virt) {
297 *phys = virt_to_phys(virt); 297 *phys = virt_to_phys(virt);
298 pr_debug("virt %p, phys=%llx\n", virt, (uint64_t) *phys); 298 pr_debug("virt=%p phys=%llx\n", virt,
299 return virt; 299 (unsigned long long)*phys);
300 }
301 if (!diu_ops.diu_mem) {
302 printk(KERN_INFO "%s: no diu_mem."
303 " To reserve more memory, put 'diufb=15M' "
304 "in the command line\n", __func__);
305 return NULL;
306 }
307
308 virt = (void *)rh_alloc(&diu_ops.diu_rh_info, size, "DIU");
309 if (virt) {
310 *phys = virt_to_bus(virt);
311 memset(virt, 0, size);
312 } 300 }
313 301
314 pr_debug("rh virt=%p phys=%llx\n", virt, (unsigned long long)*phys);
315
316 return virt; 302 return virt;
317} 303}
318 304
319static void fsl_diu_free(void *p, unsigned long size) 305/**
306 * fsl_diu_free - release DIU memory
307 * @virt: pointer returned by fsl_diu_alloc()
308 * @size: number of bytes allocated by fsl_diu_alloc()
309 *
310 * This function releases memory allocated by fsl_diu_alloc().
311 */
312static void fsl_diu_free(void *virt, size_t size)
320{ 313{
321 pr_debug("p=%p size=%lu\n", p, size); 314 pr_debug("virt=%p size=%zu\n", virt, size);
322 315
323 if (!p) 316 if (virt && size)
324 return; 317 free_pages_exact(virt, size);
325
326 if ((p >= diu_ops.diu_mem) &&
327 (p < (diu_ops.diu_mem + diu_ops.diu_size))) {
328 pr_debug("rh\n");
329 rh_free(&diu_ops.diu_rh_info, (unsigned long) p);
330 } else {
331 pr_debug("dma\n");
332 free_pages((unsigned long)p, get_order(size));
333 }
334} 318}
335 319
336static int fsl_diu_enable_panel(struct fb_info *info) 320static int fsl_diu_enable_panel(struct fb_info *info)
diff --git a/drivers/video/geode/lxfb.h b/drivers/video/geode/lxfb.h
index 3b9416f4ee20..6a51448fd3f7 100644
--- a/drivers/video/geode/lxfb.h
+++ b/drivers/video/geode/lxfb.h
@@ -51,8 +51,6 @@ static inline unsigned int lx_get_pitch(unsigned int xres, int bpp)
51} 51}
52 52
53void lx_set_mode(struct fb_info *); 53void lx_set_mode(struct fb_info *);
54void lx_get_gamma(struct fb_info *, unsigned int *, int);
55void lx_set_gamma(struct fb_info *, unsigned int *, int);
56unsigned int lx_framebuffer_size(void); 54unsigned int lx_framebuffer_size(void);
57int lx_blank_display(struct fb_info *, int); 55int lx_blank_display(struct fb_info *, int);
58void lx_set_palette_reg(struct fb_info *, unsigned int, unsigned int, 56void lx_set_palette_reg(struct fb_info *, unsigned int, unsigned int,
diff --git a/drivers/video/geode/lxfb_ops.c b/drivers/video/geode/lxfb_ops.c
index aaef9165ec9b..b1cd49c99356 100644
--- a/drivers/video/geode/lxfb_ops.c
+++ b/drivers/video/geode/lxfb_ops.c
@@ -517,25 +517,25 @@ void lx_set_palette_reg(struct fb_info *info, unsigned regno,
517int lx_blank_display(struct fb_info *info, int blank_mode) 517int lx_blank_display(struct fb_info *info, int blank_mode)
518{ 518{
519 struct lxfb_par *par = info->par; 519 struct lxfb_par *par = info->par;
520 u32 dcfg, fp_pm; 520 u32 dcfg, misc, fp_pm;
521 int blank, hsync, vsync, crt; 521 int blank, hsync, vsync;
522 522
523 /* CRT power saving modes. */ 523 /* CRT power saving modes. */
524 switch (blank_mode) { 524 switch (blank_mode) {
525 case FB_BLANK_UNBLANK: 525 case FB_BLANK_UNBLANK:
526 blank = 0; hsync = 1; vsync = 1; crt = 1; 526 blank = 0; hsync = 1; vsync = 1;
527 break; 527 break;
528 case FB_BLANK_NORMAL: 528 case FB_BLANK_NORMAL:
529 blank = 1; hsync = 1; vsync = 1; crt = 1; 529 blank = 1; hsync = 1; vsync = 1;
530 break; 530 break;
531 case FB_BLANK_VSYNC_SUSPEND: 531 case FB_BLANK_VSYNC_SUSPEND:
532 blank = 1; hsync = 1; vsync = 0; crt = 1; 532 blank = 1; hsync = 1; vsync = 0;
533 break; 533 break;
534 case FB_BLANK_HSYNC_SUSPEND: 534 case FB_BLANK_HSYNC_SUSPEND:
535 blank = 1; hsync = 0; vsync = 1; crt = 1; 535 blank = 1; hsync = 0; vsync = 1;
536 break; 536 break;
537 case FB_BLANK_POWERDOWN: 537 case FB_BLANK_POWERDOWN:
538 blank = 1; hsync = 0; vsync = 0; crt = 0; 538 blank = 1; hsync = 0; vsync = 0;
539 break; 539 break;
540 default: 540 default:
541 return -EINVAL; 541 return -EINVAL;
@@ -545,15 +545,23 @@ int lx_blank_display(struct fb_info *info, int blank_mode)
545 dcfg &= ~(VP_DCFG_DAC_BL_EN | VP_DCFG_HSYNC_EN | VP_DCFG_VSYNC_EN | 545 dcfg &= ~(VP_DCFG_DAC_BL_EN | VP_DCFG_HSYNC_EN | VP_DCFG_VSYNC_EN |
546 VP_DCFG_CRT_EN); 546 VP_DCFG_CRT_EN);
547 if (!blank) 547 if (!blank)
548 dcfg |= VP_DCFG_DAC_BL_EN; 548 dcfg |= VP_DCFG_DAC_BL_EN | VP_DCFG_CRT_EN;
549 if (hsync) 549 if (hsync)
550 dcfg |= VP_DCFG_HSYNC_EN; 550 dcfg |= VP_DCFG_HSYNC_EN;
551 if (vsync) 551 if (vsync)
552 dcfg |= VP_DCFG_VSYNC_EN; 552 dcfg |= VP_DCFG_VSYNC_EN;
553 if (crt) 553
554 dcfg |= VP_DCFG_CRT_EN;
555 write_vp(par, VP_DCFG, dcfg); 554 write_vp(par, VP_DCFG, dcfg);
556 555
556 misc = read_vp(par, VP_MISC);
557
558 if (vsync && hsync)
559 misc &= ~VP_MISC_DACPWRDN;
560 else
561 misc |= VP_MISC_DACPWRDN;
562
563 write_vp(par, VP_MISC, misc);
564
557 /* Power on/off flat panel */ 565 /* Power on/off flat panel */
558 566
559 if (par->output & OUTPUT_PANEL) { 567 if (par->output & OUTPUT_PANEL) {
diff --git a/drivers/video/hgafb.c b/drivers/video/hgafb.c
index c18880d9db1f..0129c044f6d6 100644
--- a/drivers/video/hgafb.c
+++ b/drivers/video/hgafb.c
@@ -551,7 +551,7 @@ static struct fb_ops hgafb_ops = {
551 * Initialization 551 * Initialization
552 */ 552 */
553 553
554static int __init hgafb_probe(struct device *device) 554static int __init hgafb_probe(struct platform_device *pdev)
555{ 555{
556 struct fb_info *info; 556 struct fb_info *info;
557 557
@@ -565,7 +565,7 @@ static int __init hgafb_probe(struct device *device)
565 printk(KERN_INFO "hgafb: %s with %ldK of memory detected.\n", 565 printk(KERN_INFO "hgafb: %s with %ldK of memory detected.\n",
566 hga_type_name, hga_vram_len/1024); 566 hga_type_name, hga_vram_len/1024);
567 567
568 info = framebuffer_alloc(0, NULL); 568 info = framebuffer_alloc(0, &pdev->dev);
569 if (!info) { 569 if (!info) {
570 iounmap(hga_vram); 570 iounmap(hga_vram);
571 return -ENOMEM; 571 return -ENOMEM;
@@ -593,13 +593,13 @@ static int __init hgafb_probe(struct device *device)
593 593
594 printk(KERN_INFO "fb%d: %s frame buffer device\n", 594 printk(KERN_INFO "fb%d: %s frame buffer device\n",
595 info->node, info->fix.id); 595 info->node, info->fix.id);
596 dev_set_drvdata(device, info); 596 platform_set_drvdata(pdev, info);
597 return 0; 597 return 0;
598} 598}
599 599
600static int hgafb_remove(struct device *device) 600static int hgafb_remove(struct platform_device *pdev)
601{ 601{
602 struct fb_info *info = dev_get_drvdata(device); 602 struct fb_info *info = platform_get_drvdata(pdev);
603 603
604 hga_txt_mode(); 604 hga_txt_mode();
605 hga_clear_screen(); 605 hga_clear_screen();
@@ -620,16 +620,15 @@ static int hgafb_remove(struct device *device)
620 return 0; 620 return 0;
621} 621}
622 622
623static struct device_driver hgafb_driver = { 623static struct platform_driver hgafb_driver = {
624 .name = "hgafb",
625 .bus = &platform_bus_type,
626 .probe = hgafb_probe, 624 .probe = hgafb_probe,
627 .remove = hgafb_remove, 625 .remove = hgafb_remove,
626 .driver = {
627 .name = "hgafb",
628 },
628}; 629};
629 630
630static struct platform_device hgafb_device = { 631static struct platform_device *hgafb_device;
631 .name = "hgafb",
632};
633 632
634static int __init hgafb_init(void) 633static int __init hgafb_init(void)
635{ 634{
@@ -638,12 +637,15 @@ static int __init hgafb_init(void)
638 if (fb_get_options("hgafb", NULL)) 637 if (fb_get_options("hgafb", NULL))
639 return -ENODEV; 638 return -ENODEV;
640 639
641 ret = driver_register(&hgafb_driver); 640 ret = platform_driver_register(&hgafb_driver);
642 641
643 if (!ret) { 642 if (!ret) {
644 ret = platform_device_register(&hgafb_device); 643 hgafb_device = platform_device_register_simple("hgafb", 0, NULL, 0);
645 if (ret) 644
646 driver_unregister(&hgafb_driver); 645 if (IS_ERR(hgafb_device)) {
646 platform_driver_unregister(&hgafb_driver);
647 ret = PTR_ERR(hgafb_device);
648 }
647 } 649 }
648 650
649 return ret; 651 return ret;
@@ -651,8 +653,8 @@ static int __init hgafb_init(void)
651 653
652static void __exit hgafb_exit(void) 654static void __exit hgafb_exit(void)
653{ 655{
654 platform_device_unregister(&hgafb_device); 656 platform_device_unregister(hgafb_device);
655 driver_unregister(&hgafb_driver); 657 platform_driver_unregister(&hgafb_driver);
656} 658}
657 659
658/* ------------------------------------------------------------------------- 660/* -------------------------------------------------------------------------
diff --git a/drivers/video/imxfb.c b/drivers/video/imxfb.c
index 94e4d3ac1a05..0c5a475c1cae 100644
--- a/drivers/video/imxfb.c
+++ b/drivers/video/imxfb.c
@@ -24,6 +24,7 @@
24#include <linux/string.h> 24#include <linux/string.h>
25#include <linux/interrupt.h> 25#include <linux/interrupt.h>
26#include <linux/slab.h> 26#include <linux/slab.h>
27#include <linux/mm.h>
27#include <linux/fb.h> 28#include <linux/fb.h>
28#include <linux/delay.h> 29#include <linux/delay.h>
29#include <linux/init.h> 30#include <linux/init.h>
diff --git a/drivers/video/macfb.c b/drivers/video/macfb.c
index aa8c714d6245..b790ddff76f9 100644
--- a/drivers/video/macfb.c
+++ b/drivers/video/macfb.c
@@ -596,7 +596,7 @@ static struct fb_ops macfb_ops = {
596 .fb_imageblit = cfb_imageblit, 596 .fb_imageblit = cfb_imageblit,
597}; 597};
598 598
599void __init macfb_setup(char *options) 599static void __init macfb_setup(char *options)
600{ 600{
601 char *this_opt; 601 char *this_opt;
602 602
diff --git a/drivers/video/neofb.c b/drivers/video/neofb.c
index 5246b0402d76..25172b2a2a94 100644
--- a/drivers/video/neofb.c
+++ b/drivers/video/neofb.c
@@ -201,7 +201,6 @@ static int neoFindMode(int xres, int yres, int depth)
201 * 201 *
202 * Determine the closest clock frequency to the one requested. 202 * Determine the closest clock frequency to the one requested.
203 */ 203 */
204#define REF_FREQ 0xe517 /* 14.31818 in 20.12 fixed point */
205#define MAX_N 127 204#define MAX_N 127
206#define MAX_D 31 205#define MAX_D 31
207#define MAX_F 1 206#define MAX_F 1
@@ -211,27 +210,24 @@ static void neoCalcVCLK(const struct fb_info *info,
211{ 210{
212 int n, d, f; 211 int n, d, f;
213 int n_best = 0, d_best = 0, f_best = 0; 212 int n_best = 0, d_best = 0, f_best = 0;
214 long f_best_diff = (0x7ffff << 12); /* 20.12 */ 213 long f_best_diff = 0x7ffff;
215 long f_target = (freq << 12) / 1000; /* 20.12 */
216 214
217 for (f = 0; f <= MAX_F; f++) 215 for (f = 0; f <= MAX_F; f++)
218 for (n = 0; n <= MAX_N; n++) 216 for (d = 0; d <= MAX_D; d++)
219 for (d = 0; d <= MAX_D; d++) { 217 for (n = 0; n <= MAX_N; n++) {
220 long f_out; /* 20.12 */ 218 long f_out;
221 long f_diff; /* 20.12 */ 219 long f_diff;
222 220
223 f_out = 221 f_out = ((14318 * (n + 1)) / (d + 1)) >> f;
224 ((((n + 1) << 12) / ((d + 222 f_diff = abs(f_out - freq);
225 1) * 223 if (f_diff <= f_best_diff) {
226 (1 << f))) >> 12)
227 * REF_FREQ;
228 f_diff = abs(f_out - f_target);
229 if (f_diff < f_best_diff) {
230 f_best_diff = f_diff; 224 f_best_diff = f_diff;
231 n_best = n; 225 n_best = n;
232 d_best = d; 226 d_best = d;
233 f_best = f; 227 f_best = f;
234 } 228 }
229 if (f_out > freq)
230 break;
235 } 231 }
236 232
237 if (info->fix.accel == FB_ACCEL_NEOMAGIC_NM2200 || 233 if (info->fix.accel == FB_ACCEL_NEOMAGIC_NM2200 ||
@@ -248,11 +244,11 @@ static void neoCalcVCLK(const struct fb_info *info,
248 par->VCLK3Denominator = d_best; 244 par->VCLK3Denominator = d_best;
249 245
250#ifdef NEOFB_DEBUG 246#ifdef NEOFB_DEBUG
251 printk("neoVCLK: f:%d NumLow=%d NumHi=%d Den=%d Df=%d\n", 247 printk(KERN_DEBUG "neoVCLK: f:%ld NumLow=%d NumHi=%d Den=%d Df=%ld\n",
252 f_target >> 12, 248 freq,
253 par->VCLK3NumeratorLow, 249 par->VCLK3NumeratorLow,
254 par->VCLK3NumeratorHigh, 250 par->VCLK3NumeratorHigh,
255 par->VCLK3Denominator, f_best_diff >> 12); 251 par->VCLK3Denominator, f_best_diff);
256#endif 252#endif
257} 253}
258 254
@@ -263,15 +259,20 @@ static void neoCalcVCLK(const struct fb_info *info,
263 */ 259 */
264 260
265static int vgaHWInit(const struct fb_var_screeninfo *var, 261static int vgaHWInit(const struct fb_var_screeninfo *var,
266 const struct fb_info *info, 262 struct neofb_par *par)
267 struct neofb_par *par, struct xtimings *timings)
268{ 263{
264 int hsync_end = var->xres + var->right_margin + var->hsync_len;
265 int htotal = (hsync_end + var->left_margin) >> 3;
266 int vsync_start = var->yres + var->lower_margin;
267 int vsync_end = vsync_start + var->vsync_len;
268 int vtotal = vsync_end + var->upper_margin;
269
269 par->MiscOutReg = 0x23; 270 par->MiscOutReg = 0x23;
270 271
271 if (!(timings->sync & FB_SYNC_HOR_HIGH_ACT)) 272 if (!(var->sync & FB_SYNC_HOR_HIGH_ACT))
272 par->MiscOutReg |= 0x40; 273 par->MiscOutReg |= 0x40;
273 274
274 if (!(timings->sync & FB_SYNC_VERT_HIGH_ACT)) 275 if (!(var->sync & FB_SYNC_VERT_HIGH_ACT))
275 par->MiscOutReg |= 0x80; 276 par->MiscOutReg |= 0x80;
276 277
277 /* 278 /*
@@ -286,25 +287,25 @@ static int vgaHWInit(const struct fb_var_screeninfo *var,
286 /* 287 /*
287 * CRTC Controller 288 * CRTC Controller
288 */ 289 */
289 par->CRTC[0] = (timings->HTotal >> 3) - 5; 290 par->CRTC[0] = htotal - 5;
290 par->CRTC[1] = (timings->HDisplay >> 3) - 1; 291 par->CRTC[1] = (var->xres >> 3) - 1;
291 par->CRTC[2] = (timings->HDisplay >> 3) - 1; 292 par->CRTC[2] = (var->xres >> 3) - 1;
292 par->CRTC[3] = (((timings->HTotal >> 3) - 1) & 0x1F) | 0x80; 293 par->CRTC[3] = ((htotal - 1) & 0x1F) | 0x80;
293 par->CRTC[4] = (timings->HSyncStart >> 3); 294 par->CRTC[4] = ((var->xres + var->right_margin) >> 3);
294 par->CRTC[5] = ((((timings->HTotal >> 3) - 1) & 0x20) << 2) 295 par->CRTC[5] = (((htotal - 1) & 0x20) << 2)
295 | (((timings->HSyncEnd >> 3)) & 0x1F); 296 | (((hsync_end >> 3)) & 0x1F);
296 par->CRTC[6] = (timings->VTotal - 2) & 0xFF; 297 par->CRTC[6] = (vtotal - 2) & 0xFF;
297 par->CRTC[7] = (((timings->VTotal - 2) & 0x100) >> 8) 298 par->CRTC[7] = (((vtotal - 2) & 0x100) >> 8)
298 | (((timings->VDisplay - 1) & 0x100) >> 7) 299 | (((var->yres - 1) & 0x100) >> 7)
299 | ((timings->VSyncStart & 0x100) >> 6) 300 | ((vsync_start & 0x100) >> 6)
300 | (((timings->VDisplay - 1) & 0x100) >> 5) 301 | (((var->yres - 1) & 0x100) >> 5)
301 | 0x10 | (((timings->VTotal - 2) & 0x200) >> 4) 302 | 0x10 | (((vtotal - 2) & 0x200) >> 4)
302 | (((timings->VDisplay - 1) & 0x200) >> 3) 303 | (((var->yres - 1) & 0x200) >> 3)
303 | ((timings->VSyncStart & 0x200) >> 2); 304 | ((vsync_start & 0x200) >> 2);
304 par->CRTC[8] = 0x00; 305 par->CRTC[8] = 0x00;
305 par->CRTC[9] = (((timings->VDisplay - 1) & 0x200) >> 4) | 0x40; 306 par->CRTC[9] = (((var->yres - 1) & 0x200) >> 4) | 0x40;
306 307
307 if (timings->dblscan) 308 if (var->vmode & FB_VMODE_DOUBLE)
308 par->CRTC[9] |= 0x80; 309 par->CRTC[9] |= 0x80;
309 310
310 par->CRTC[10] = 0x00; 311 par->CRTC[10] = 0x00;
@@ -313,13 +314,13 @@ static int vgaHWInit(const struct fb_var_screeninfo *var,
313 par->CRTC[13] = 0x00; 314 par->CRTC[13] = 0x00;
314 par->CRTC[14] = 0x00; 315 par->CRTC[14] = 0x00;
315 par->CRTC[15] = 0x00; 316 par->CRTC[15] = 0x00;
316 par->CRTC[16] = timings->VSyncStart & 0xFF; 317 par->CRTC[16] = vsync_start & 0xFF;
317 par->CRTC[17] = (timings->VSyncEnd & 0x0F) | 0x20; 318 par->CRTC[17] = (vsync_end & 0x0F) | 0x20;
318 par->CRTC[18] = (timings->VDisplay - 1) & 0xFF; 319 par->CRTC[18] = (var->yres - 1) & 0xFF;
319 par->CRTC[19] = var->xres_virtual >> 4; 320 par->CRTC[19] = var->xres_virtual >> 4;
320 par->CRTC[20] = 0x00; 321 par->CRTC[20] = 0x00;
321 par->CRTC[21] = (timings->VDisplay - 1) & 0xFF; 322 par->CRTC[21] = (var->yres - 1) & 0xFF;
322 par->CRTC[22] = (timings->VTotal - 1) & 0xFF; 323 par->CRTC[22] = (vtotal - 1) & 0xFF;
323 par->CRTC[23] = 0xC3; 324 par->CRTC[23] = 0xC3;
324 par->CRTC[24] = 0xFF; 325 par->CRTC[24] = 0xFF;
325 326
@@ -483,7 +484,8 @@ static inline int neo2200_sync(struct fb_info *info)
483{ 484{
484 struct neofb_par *par = info->par; 485 struct neofb_par *par = info->par;
485 486
486 while (readl(&par->neo2200->bltStat) & 1); 487 while (readl(&par->neo2200->bltStat) & 1)
488 cpu_relax();
487 return 0; 489 return 0;
488} 490}
489 491
@@ -591,34 +593,14 @@ static int
591neofb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) 593neofb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
592{ 594{
593 struct neofb_par *par = info->par; 595 struct neofb_par *par = info->par;
594 unsigned int pixclock = var->pixclock;
595 struct xtimings timings;
596 int memlen, vramlen; 596 int memlen, vramlen;
597 int mode_ok = 0; 597 int mode_ok = 0;
598 598
599 DBG("neofb_check_var"); 599 DBG("neofb_check_var");
600 600
601 if (!pixclock) 601 if (PICOS2KHZ(var->pixclock) > par->maxClock)
602 pixclock = 10000; /* 10ns = 100MHz */
603 timings.pixclock = 1000000000 / pixclock;
604 if (timings.pixclock < 1)
605 timings.pixclock = 1;
606
607 if (timings.pixclock > par->maxClock)
608 return -EINVAL; 602 return -EINVAL;
609 603
610 timings.dblscan = var->vmode & FB_VMODE_DOUBLE;
611 timings.interlaced = var->vmode & FB_VMODE_INTERLACED;
612 timings.HDisplay = var->xres;
613 timings.HSyncStart = timings.HDisplay + var->right_margin;
614 timings.HSyncEnd = timings.HSyncStart + var->hsync_len;
615 timings.HTotal = timings.HSyncEnd + var->left_margin;
616 timings.VDisplay = var->yres;
617 timings.VSyncStart = timings.VDisplay + var->lower_margin;
618 timings.VSyncEnd = timings.VSyncStart + var->vsync_len;
619 timings.VTotal = timings.VSyncEnd + var->upper_margin;
620 timings.sync = var->sync;
621
622 /* Is the mode larger than the LCD panel? */ 604 /* Is the mode larger than the LCD panel? */
623 if (par->internal_display && 605 if (par->internal_display &&
624 ((var->xres > par->NeoPanelWidth) || 606 ((var->xres > par->NeoPanelWidth) ||
@@ -759,11 +741,11 @@ neofb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
759static int neofb_set_par(struct fb_info *info) 741static int neofb_set_par(struct fb_info *info)
760{ 742{
761 struct neofb_par *par = info->par; 743 struct neofb_par *par = info->par;
762 struct xtimings timings;
763 unsigned char temp; 744 unsigned char temp;
764 int i, clock_hi = 0; 745 int i, clock_hi = 0;
765 int lcd_stretch; 746 int lcd_stretch;
766 int hoffset, voffset; 747 int hoffset, voffset;
748 int vsync_start, vtotal;
767 749
768 DBG("neofb_set_par"); 750 DBG("neofb_set_par");
769 751
@@ -771,28 +753,15 @@ static int neofb_set_par(struct fb_info *info)
771 753
772 vgaHWProtect(1); /* Blank the screen */ 754 vgaHWProtect(1); /* Blank the screen */
773 755
774 timings.dblscan = info->var.vmode & FB_VMODE_DOUBLE; 756 vsync_start = info->var.yres + info->var.lower_margin;
775 timings.interlaced = info->var.vmode & FB_VMODE_INTERLACED; 757 vtotal = vsync_start + info->var.vsync_len + info->var.upper_margin;
776 timings.HDisplay = info->var.xres;
777 timings.HSyncStart = timings.HDisplay + info->var.right_margin;
778 timings.HSyncEnd = timings.HSyncStart + info->var.hsync_len;
779 timings.HTotal = timings.HSyncEnd + info->var.left_margin;
780 timings.VDisplay = info->var.yres;
781 timings.VSyncStart = timings.VDisplay + info->var.lower_margin;
782 timings.VSyncEnd = timings.VSyncStart + info->var.vsync_len;
783 timings.VTotal = timings.VSyncEnd + info->var.upper_margin;
784 timings.sync = info->var.sync;
785 timings.pixclock = PICOS2KHZ(info->var.pixclock);
786
787 if (timings.pixclock < 1)
788 timings.pixclock = 1;
789 758
790 /* 759 /*
791 * This will allocate the datastructure and initialize all of the 760 * This will allocate the datastructure and initialize all of the
792 * generic VGA registers. 761 * generic VGA registers.
793 */ 762 */
794 763
795 if (vgaHWInit(&info->var, info, par, &timings)) 764 if (vgaHWInit(&info->var, par))
796 return -EINVAL; 765 return -EINVAL;
797 766
798 /* 767 /*
@@ -831,10 +800,10 @@ static int neofb_set_par(struct fb_info *info)
831 par->ExtCRTDispAddr = 0x10; 800 par->ExtCRTDispAddr = 0x10;
832 801
833 /* Vertical Extension */ 802 /* Vertical Extension */
834 par->VerticalExt = (((timings.VTotal - 2) & 0x400) >> 10) 803 par->VerticalExt = (((vtotal - 2) & 0x400) >> 10)
835 | (((timings.VDisplay - 1) & 0x400) >> 9) 804 | (((info->var.yres - 1) & 0x400) >> 9)
836 | (((timings.VSyncStart) & 0x400) >> 8) 805 | (((vsync_start) & 0x400) >> 8)
837 | (((timings.VSyncStart) & 0x400) >> 7); 806 | (((vsync_start) & 0x400) >> 7);
838 807
839 /* Fast write bursts on unless disabled. */ 808 /* Fast write bursts on unless disabled. */
840 if (par->pci_burst) 809 if (par->pci_burst)
@@ -995,7 +964,7 @@ static int neofb_set_par(struct fb_info *info)
995 * Calculate the VCLK that most closely matches the requested dot 964 * Calculate the VCLK that most closely matches the requested dot
996 * clock. 965 * clock.
997 */ 966 */
998 neoCalcVCLK(info, par, timings.pixclock); 967 neoCalcVCLK(info, par, PICOS2KHZ(info->var.pixclock));
999 968
1000 /* Since we program the clocks ourselves, always use VCLK3. */ 969 /* Since we program the clocks ourselves, always use VCLK3. */
1001 par->MiscOutReg |= 0x0C; 970 par->MiscOutReg |= 0x0C;
@@ -1927,9 +1896,6 @@ static int __devinit neo_init_hw(struct fb_info *info)
1927 int maxClock = 65000; 1896 int maxClock = 65000;
1928 int CursorMem = 1024; 1897 int CursorMem = 1024;
1929 int CursorOff = 0x100; 1898 int CursorOff = 0x100;
1930 int linearSize = 1024;
1931 int maxWidth = 1024;
1932 int maxHeight = 1024;
1933 1899
1934 DBG("neo_init_hw"); 1900 DBG("neo_init_hw");
1935 1901
@@ -1948,81 +1914,52 @@ static int __devinit neo_init_hw(struct fb_info *info)
1948 case FB_ACCEL_NEOMAGIC_NM2070: 1914 case FB_ACCEL_NEOMAGIC_NM2070:
1949 videoRam = 896; 1915 videoRam = 896;
1950 maxClock = 65000; 1916 maxClock = 65000;
1951 CursorMem = 2048;
1952 CursorOff = 0x100;
1953 linearSize = 1024;
1954 maxWidth = 1024;
1955 maxHeight = 1024;
1956 break; 1917 break;
1957 case FB_ACCEL_NEOMAGIC_NM2090: 1918 case FB_ACCEL_NEOMAGIC_NM2090:
1958 case FB_ACCEL_NEOMAGIC_NM2093: 1919 case FB_ACCEL_NEOMAGIC_NM2093:
1959 videoRam = 1152;
1960 maxClock = 80000;
1961 CursorMem = 2048;
1962 CursorOff = 0x100;
1963 linearSize = 2048;
1964 maxWidth = 1024;
1965 maxHeight = 1024;
1966 break;
1967 case FB_ACCEL_NEOMAGIC_NM2097: 1920 case FB_ACCEL_NEOMAGIC_NM2097:
1968 videoRam = 1152; 1921 videoRam = 1152;
1969 maxClock = 80000; 1922 maxClock = 80000;
1970 CursorMem = 1024;
1971 CursorOff = 0x100;
1972 linearSize = 2048;
1973 maxWidth = 1024;
1974 maxHeight = 1024;
1975 break; 1923 break;
1976 case FB_ACCEL_NEOMAGIC_NM2160: 1924 case FB_ACCEL_NEOMAGIC_NM2160:
1977 videoRam = 2048; 1925 videoRam = 2048;
1978 maxClock = 90000; 1926 maxClock = 90000;
1979 CursorMem = 1024;
1980 CursorOff = 0x100;
1981 linearSize = 2048;
1982 maxWidth = 1024;
1983 maxHeight = 1024;
1984 break; 1927 break;
1985 case FB_ACCEL_NEOMAGIC_NM2200: 1928 case FB_ACCEL_NEOMAGIC_NM2200:
1986 videoRam = 2560; 1929 videoRam = 2560;
1987 maxClock = 110000; 1930 maxClock = 110000;
1988 CursorMem = 1024;
1989 CursorOff = 0x1000;
1990 linearSize = 4096;
1991 maxWidth = 1280;
1992 maxHeight = 1024; /* ???? */
1993
1994 par->neo2200 = (Neo2200 __iomem *) par->mmio_vbase;
1995 break; 1931 break;
1996 case FB_ACCEL_NEOMAGIC_NM2230: 1932 case FB_ACCEL_NEOMAGIC_NM2230:
1997 videoRam = 3008; 1933 videoRam = 3008;
1998 maxClock = 110000; 1934 maxClock = 110000;
1999 CursorMem = 1024;
2000 CursorOff = 0x1000;
2001 linearSize = 4096;
2002 maxWidth = 1280;
2003 maxHeight = 1024; /* ???? */
2004
2005 par->neo2200 = (Neo2200 __iomem *) par->mmio_vbase;
2006 break; 1935 break;
2007 case FB_ACCEL_NEOMAGIC_NM2360: 1936 case FB_ACCEL_NEOMAGIC_NM2360:
2008 videoRam = 4096; 1937 videoRam = 4096;
2009 maxClock = 110000; 1938 maxClock = 110000;
2010 CursorMem = 1024;
2011 CursorOff = 0x1000;
2012 linearSize = 4096;
2013 maxWidth = 1280;
2014 maxHeight = 1024; /* ???? */
2015
2016 par->neo2200 = (Neo2200 __iomem *) par->mmio_vbase;
2017 break; 1939 break;
2018 case FB_ACCEL_NEOMAGIC_NM2380: 1940 case FB_ACCEL_NEOMAGIC_NM2380:
2019 videoRam = 6144; 1941 videoRam = 6144;
2020 maxClock = 110000; 1942 maxClock = 110000;
1943 break;
1944 }
1945 switch (info->fix.accel) {
1946 case FB_ACCEL_NEOMAGIC_NM2070:
1947 case FB_ACCEL_NEOMAGIC_NM2090:
1948 case FB_ACCEL_NEOMAGIC_NM2093:
1949 CursorMem = 2048;
1950 CursorOff = 0x100;
1951 break;
1952 case FB_ACCEL_NEOMAGIC_NM2097:
1953 case FB_ACCEL_NEOMAGIC_NM2160:
1954 CursorMem = 1024;
1955 CursorOff = 0x100;
1956 break;
1957 case FB_ACCEL_NEOMAGIC_NM2200:
1958 case FB_ACCEL_NEOMAGIC_NM2230:
1959 case FB_ACCEL_NEOMAGIC_NM2360:
1960 case FB_ACCEL_NEOMAGIC_NM2380:
2021 CursorMem = 1024; 1961 CursorMem = 1024;
2022 CursorOff = 0x1000; 1962 CursorOff = 0x1000;
2023 linearSize = 8192;
2024 maxWidth = 1280;
2025 maxHeight = 1024; /* ???? */
2026 1963
2027 par->neo2200 = (Neo2200 __iomem *) par->mmio_vbase; 1964 par->neo2200 = (Neo2200 __iomem *) par->mmio_vbase;
2028 break; 1965 break;
@@ -2036,7 +1973,7 @@ static int __devinit neo_init_hw(struct fb_info *info)
2036*/ 1973*/
2037 par->maxClock = maxClock; 1974 par->maxClock = maxClock;
2038 par->cursorOff = CursorOff; 1975 par->cursorOff = CursorOff;
2039 return ((videoRam * 1024)); 1976 return videoRam * 1024;
2040} 1977}
2041 1978
2042 1979
diff --git a/drivers/video/offb.c b/drivers/video/offb.c
index d7b3dcc0dc43..e1d9eeb1aeaf 100644
--- a/drivers/video/offb.c
+++ b/drivers/video/offb.c
@@ -47,6 +47,7 @@ enum {
47 cmap_M3B, /* ATI Rage Mobility M3 Head B */ 47 cmap_M3B, /* ATI Rage Mobility M3 Head B */
48 cmap_radeon, /* ATI Radeon */ 48 cmap_radeon, /* ATI Radeon */
49 cmap_gxt2000, /* IBM GXT2000 */ 49 cmap_gxt2000, /* IBM GXT2000 */
50 cmap_avivo, /* ATI R5xx */
50}; 51};
51 52
52struct offb_par { 53struct offb_par {
@@ -58,26 +59,36 @@ struct offb_par {
58 59
59struct offb_par default_par; 60struct offb_par default_par;
60 61
61 /*
62 * Interface used by the world
63 */
64
65static int offb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
66 u_int transp, struct fb_info *info);
67static int offb_blank(int blank, struct fb_info *info);
68
69#ifdef CONFIG_PPC32 62#ifdef CONFIG_PPC32
70extern boot_infos_t *boot_infos; 63extern boot_infos_t *boot_infos;
71#endif 64#endif
72 65
73static struct fb_ops offb_ops = { 66/* Definitions used by the Avivo palette hack */
74 .owner = THIS_MODULE, 67#define AVIVO_DC_LUT_RW_SELECT 0x6480
75 .fb_setcolreg = offb_setcolreg, 68#define AVIVO_DC_LUT_RW_MODE 0x6484
76 .fb_blank = offb_blank, 69#define AVIVO_DC_LUT_RW_INDEX 0x6488
77 .fb_fillrect = cfb_fillrect, 70#define AVIVO_DC_LUT_SEQ_COLOR 0x648c
78 .fb_copyarea = cfb_copyarea, 71#define AVIVO_DC_LUT_PWL_DATA 0x6490
79 .fb_imageblit = cfb_imageblit, 72#define AVIVO_DC_LUT_30_COLOR 0x6494
80}; 73#define AVIVO_DC_LUT_READ_PIPE_SELECT 0x6498
74#define AVIVO_DC_LUT_WRITE_EN_MASK 0x649c
75#define AVIVO_DC_LUT_AUTOFILL 0x64a0
76
77#define AVIVO_DC_LUTA_CONTROL 0x64c0
78#define AVIVO_DC_LUTA_BLACK_OFFSET_BLUE 0x64c4
79#define AVIVO_DC_LUTA_BLACK_OFFSET_GREEN 0x64c8
80#define AVIVO_DC_LUTA_BLACK_OFFSET_RED 0x64cc
81#define AVIVO_DC_LUTA_WHITE_OFFSET_BLUE 0x64d0
82#define AVIVO_DC_LUTA_WHITE_OFFSET_GREEN 0x64d4
83#define AVIVO_DC_LUTA_WHITE_OFFSET_RED 0x64d8
84
85#define AVIVO_DC_LUTB_CONTROL 0x6cc0
86#define AVIVO_DC_LUTB_BLACK_OFFSET_BLUE 0x6cc4
87#define AVIVO_DC_LUTB_BLACK_OFFSET_GREEN 0x6cc8
88#define AVIVO_DC_LUTB_BLACK_OFFSET_RED 0x6ccc
89#define AVIVO_DC_LUTB_WHITE_OFFSET_BLUE 0x6cd0
90#define AVIVO_DC_LUTB_WHITE_OFFSET_GREEN 0x6cd4
91#define AVIVO_DC_LUTB_WHITE_OFFSET_RED 0x6cd8
81 92
82 /* 93 /*
83 * Set a single color register. The values supplied are already 94 * Set a single color register. The values supplied are already
@@ -160,6 +171,17 @@ static int offb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
160 out_le32(((unsigned __iomem *) par->cmap_adr) + regno, 171 out_le32(((unsigned __iomem *) par->cmap_adr) + regno,
161 (red << 16 | green << 8 | blue)); 172 (red << 16 | green << 8 | blue));
162 break; 173 break;
174 case cmap_avivo:
175 /* Write to both LUTs for now */
176 writel(1, par->cmap_adr + AVIVO_DC_LUT_RW_SELECT);
177 writeb(regno, par->cmap_adr + AVIVO_DC_LUT_RW_INDEX);
178 writel(((red) << 22) | ((green) << 12) | ((blue) << 2),
179 par->cmap_adr + AVIVO_DC_LUT_30_COLOR);
180 writel(0, par->cmap_adr + AVIVO_DC_LUT_RW_SELECT);
181 writeb(regno, par->cmap_adr + AVIVO_DC_LUT_RW_INDEX);
182 writel(((red) << 22) | ((green) << 12) | ((blue) << 2),
183 par->cmap_adr + AVIVO_DC_LUT_30_COLOR);
184 break;
163 } 185 }
164 186
165 return 0; 187 return 0;
@@ -216,12 +238,59 @@ static int offb_blank(int blank, struct fb_info *info)
216 out_le32(((unsigned __iomem *) par->cmap_adr) + i, 238 out_le32(((unsigned __iomem *) par->cmap_adr) + i,
217 0); 239 0);
218 break; 240 break;
241 case cmap_avivo:
242 writel(1, par->cmap_adr + AVIVO_DC_LUT_RW_SELECT);
243 writeb(i, par->cmap_adr + AVIVO_DC_LUT_RW_INDEX);
244 writel(0, par->cmap_adr + AVIVO_DC_LUT_30_COLOR);
245 writel(0, par->cmap_adr + AVIVO_DC_LUT_RW_SELECT);
246 writeb(i, par->cmap_adr + AVIVO_DC_LUT_RW_INDEX);
247 writel(0, par->cmap_adr + AVIVO_DC_LUT_30_COLOR);
248 break;
219 } 249 }
220 } else 250 } else
221 fb_set_cmap(&info->cmap, info); 251 fb_set_cmap(&info->cmap, info);
222 return 0; 252 return 0;
223} 253}
224 254
255static int offb_set_par(struct fb_info *info)
256{
257 struct offb_par *par = (struct offb_par *) info->par;
258
259 /* On avivo, initialize palette control */
260 if (par->cmap_type == cmap_avivo) {
261 writel(0, par->cmap_adr + AVIVO_DC_LUTA_CONTROL);
262 writel(0, par->cmap_adr + AVIVO_DC_LUTA_BLACK_OFFSET_BLUE);
263 writel(0, par->cmap_adr + AVIVO_DC_LUTA_BLACK_OFFSET_GREEN);
264 writel(0, par->cmap_adr + AVIVO_DC_LUTA_BLACK_OFFSET_RED);
265 writel(0x0000ffff, par->cmap_adr + AVIVO_DC_LUTA_WHITE_OFFSET_BLUE);
266 writel(0x0000ffff, par->cmap_adr + AVIVO_DC_LUTA_WHITE_OFFSET_GREEN);
267 writel(0x0000ffff, par->cmap_adr + AVIVO_DC_LUTA_WHITE_OFFSET_RED);
268 writel(0, par->cmap_adr + AVIVO_DC_LUTB_CONTROL);
269 writel(0, par->cmap_adr + AVIVO_DC_LUTB_BLACK_OFFSET_BLUE);
270 writel(0, par->cmap_adr + AVIVO_DC_LUTB_BLACK_OFFSET_GREEN);
271 writel(0, par->cmap_adr + AVIVO_DC_LUTB_BLACK_OFFSET_RED);
272 writel(0x0000ffff, par->cmap_adr + AVIVO_DC_LUTB_WHITE_OFFSET_BLUE);
273 writel(0x0000ffff, par->cmap_adr + AVIVO_DC_LUTB_WHITE_OFFSET_GREEN);
274 writel(0x0000ffff, par->cmap_adr + AVIVO_DC_LUTB_WHITE_OFFSET_RED);
275 writel(1, par->cmap_adr + AVIVO_DC_LUT_RW_SELECT);
276 writel(0, par->cmap_adr + AVIVO_DC_LUT_RW_MODE);
277 writel(0x0000003f, par->cmap_adr + AVIVO_DC_LUT_WRITE_EN_MASK);
278 writel(0, par->cmap_adr + AVIVO_DC_LUT_RW_SELECT);
279 writel(0, par->cmap_adr + AVIVO_DC_LUT_RW_MODE);
280 writel(0x0000003f, par->cmap_adr + AVIVO_DC_LUT_WRITE_EN_MASK);
281 }
282 return 0;
283}
284
285static struct fb_ops offb_ops = {
286 .owner = THIS_MODULE,
287 .fb_setcolreg = offb_setcolreg,
288 .fb_set_par = offb_set_par,
289 .fb_blank = offb_blank,
290 .fb_fillrect = cfb_fillrect,
291 .fb_copyarea = cfb_copyarea,
292 .fb_imageblit = cfb_imageblit,
293};
225 294
226static void __iomem *offb_map_reg(struct device_node *np, int index, 295static void __iomem *offb_map_reg(struct device_node *np, int index,
227 unsigned long offset, unsigned long size) 296 unsigned long offset, unsigned long size)
@@ -245,6 +314,59 @@ static void __iomem *offb_map_reg(struct device_node *np, int index,
245 return ioremap(taddr + offset, size); 314 return ioremap(taddr + offset, size);
246} 315}
247 316
317static void offb_init_palette_hacks(struct fb_info *info, struct device_node *dp,
318 const char *name, unsigned long address)
319{
320 struct offb_par *par = (struct offb_par *) info->par;
321
322 if (dp && !strncmp(name, "ATY,Rage128", 11)) {
323 par->cmap_adr = offb_map_reg(dp, 2, 0, 0x1fff);
324 if (par->cmap_adr)
325 par->cmap_type = cmap_r128;
326 } else if (dp && (!strncmp(name, "ATY,RageM3pA", 12)
327 || !strncmp(name, "ATY,RageM3p12A", 14))) {
328 par->cmap_adr = offb_map_reg(dp, 2, 0, 0x1fff);
329 if (par->cmap_adr)
330 par->cmap_type = cmap_M3A;
331 } else if (dp && !strncmp(name, "ATY,RageM3pB", 12)) {
332 par->cmap_adr = offb_map_reg(dp, 2, 0, 0x1fff);
333 if (par->cmap_adr)
334 par->cmap_type = cmap_M3B;
335 } else if (dp && !strncmp(name, "ATY,Rage6", 9)) {
336 par->cmap_adr = offb_map_reg(dp, 1, 0, 0x1fff);
337 if (par->cmap_adr)
338 par->cmap_type = cmap_radeon;
339 } else if (!strncmp(name, "ATY,", 4)) {
340 unsigned long base = address & 0xff000000UL;
341 par->cmap_adr =
342 ioremap(base + 0x7ff000, 0x1000) + 0xcc0;
343 par->cmap_data = par->cmap_adr + 1;
344 par->cmap_type = cmap_m64;
345 } else if (dp && (of_device_is_compatible(dp, "pci1014,b7") ||
346 of_device_is_compatible(dp, "pci1014,21c"))) {
347 par->cmap_adr = offb_map_reg(dp, 0, 0x6000, 0x1000);
348 if (par->cmap_adr)
349 par->cmap_type = cmap_gxt2000;
350 } else if (dp && !strncmp(name, "vga,Display-", 12)) {
351 /* Look for AVIVO initialized by SLOF */
352 struct device_node *pciparent = of_get_parent(dp);
353 const u32 *vid, *did;
354 vid = of_get_property(pciparent, "vendor-id", NULL);
355 did = of_get_property(pciparent, "device-id", NULL);
356 /* This will match most R5xx */
357 if (vid && did && *vid == 0x1002 &&
358 ((*did >= 0x7100 && *did < 0x7800) ||
359 (*did >= 0x9400))) {
360 par->cmap_adr = offb_map_reg(pciparent, 2, 0, 0x10000);
361 if (par->cmap_adr)
362 par->cmap_type = cmap_avivo;
363 }
364 of_node_put(pciparent);
365 }
366 info->fix.visual = (par->cmap_type != cmap_unknown) ?
367 FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_STATIC_PSEUDOCOLOR;
368}
369
248static void __init offb_init_fb(const char *name, const char *full_name, 370static void __init offb_init_fb(const char *name, const char *full_name,
249 int width, int height, int depth, 371 int width, int height, int depth,
250 int pitch, unsigned long address, 372 int pitch, unsigned long address,
@@ -283,6 +405,7 @@ static void __init offb_init_fb(const char *name, const char *full_name,
283 405
284 fix = &info->fix; 406 fix = &info->fix;
285 var = &info->var; 407 var = &info->var;
408 info->par = par;
286 409
287 strcpy(fix->id, "OFfb "); 410 strcpy(fix->id, "OFfb ");
288 strncat(fix->id, name, sizeof(fix->id) - sizeof("OFfb ")); 411 strncat(fix->id, name, sizeof(fix->id) - sizeof("OFfb "));
@@ -298,39 +421,9 @@ static void __init offb_init_fb(const char *name, const char *full_name,
298 fix->type_aux = 0; 421 fix->type_aux = 0;
299 422
300 par->cmap_type = cmap_unknown; 423 par->cmap_type = cmap_unknown;
301 if (depth == 8) { 424 if (depth == 8)
302 if (dp && !strncmp(name, "ATY,Rage128", 11)) { 425 offb_init_palette_hacks(info, dp, name, address);
303 par->cmap_adr = offb_map_reg(dp, 2, 0, 0x1fff); 426 else
304 if (par->cmap_adr)
305 par->cmap_type = cmap_r128;
306 } else if (dp && (!strncmp(name, "ATY,RageM3pA", 12)
307 || !strncmp(name, "ATY,RageM3p12A", 14))) {
308 par->cmap_adr = offb_map_reg(dp, 2, 0, 0x1fff);
309 if (par->cmap_adr)
310 par->cmap_type = cmap_M3A;
311 } else if (dp && !strncmp(name, "ATY,RageM3pB", 12)) {
312 par->cmap_adr = offb_map_reg(dp, 2, 0, 0x1fff);
313 if (par->cmap_adr)
314 par->cmap_type = cmap_M3B;
315 } else if (dp && !strncmp(name, "ATY,Rage6", 9)) {
316 par->cmap_adr = offb_map_reg(dp, 1, 0, 0x1fff);
317 if (par->cmap_adr)
318 par->cmap_type = cmap_radeon;
319 } else if (!strncmp(name, "ATY,", 4)) {
320 unsigned long base = address & 0xff000000UL;
321 par->cmap_adr =
322 ioremap(base + 0x7ff000, 0x1000) + 0xcc0;
323 par->cmap_data = par->cmap_adr + 1;
324 par->cmap_type = cmap_m64;
325 } else if (dp && (of_device_is_compatible(dp, "pci1014,b7") ||
326 of_device_is_compatible(dp, "pci1014,21c"))) {
327 par->cmap_adr = offb_map_reg(dp, 0, 0x6000, 0x1000);
328 if (par->cmap_adr)
329 par->cmap_type = cmap_gxt2000;
330 }
331 fix->visual = (par->cmap_type != cmap_unknown) ?
332 FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_STATIC_PSEUDOCOLOR;
333 } else
334 fix->visual = FB_VISUAL_TRUECOLOR; 427 fix->visual = FB_VISUAL_TRUECOLOR;
335 428
336 var->xoffset = var->yoffset = 0; 429 var->xoffset = var->yoffset = 0;
@@ -395,7 +488,6 @@ static void __init offb_init_fb(const char *name, const char *full_name,
395 488
396 info->fbops = &offb_ops; 489 info->fbops = &offb_ops;
397 info->screen_base = ioremap(address, fix->smem_len); 490 info->screen_base = ioremap(address, fix->smem_len);
398 info->par = par;
399 info->pseudo_palette = (void *) (info + 1); 491 info->pseudo_palette = (void *) (info + 1);
400 info->flags = FBINFO_DEFAULT | foreign_endian; 492 info->flags = FBINFO_DEFAULT | foreign_endian;
401 493
diff --git a/drivers/video/omap/dispc.c b/drivers/video/omap/dispc.c
index ab32ceb06178..ab77c51fe9d6 100644
--- a/drivers/video/omap/dispc.c
+++ b/drivers/video/omap/dispc.c
@@ -20,6 +20,7 @@
20 */ 20 */
21#include <linux/kernel.h> 21#include <linux/kernel.h>
22#include <linux/dma-mapping.h> 22#include <linux/dma-mapping.h>
23#include <linux/mm.h>
23#include <linux/vmalloc.h> 24#include <linux/vmalloc.h>
24#include <linux/clk.h> 25#include <linux/clk.h>
25#include <linux/io.h> 26#include <linux/io.h>
diff --git a/drivers/video/omap/omapfb_main.c b/drivers/video/omap/omapfb_main.c
index 14d0f7a11145..f85af5c4fa68 100644
--- a/drivers/video/omap/omapfb_main.c
+++ b/drivers/video/omap/omapfb_main.c
@@ -25,6 +25,7 @@
25 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 25 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26 */ 26 */
27#include <linux/platform_device.h> 27#include <linux/platform_device.h>
28#include <linux/mm.h>
28#include <linux/uaccess.h> 29#include <linux/uaccess.h>
29 30
30#include <asm/mach-types.h> 31#include <asm/mach-types.h>
diff --git a/drivers/video/ps3fb.c b/drivers/video/ps3fb.c
index dc3af1c78c56..4b5d80771904 100644
--- a/drivers/video/ps3fb.c
+++ b/drivers/video/ps3fb.c
@@ -1297,6 +1297,7 @@ static int ps3fb_shutdown(struct ps3_system_bus_device *dev)
1297 1297
1298static struct ps3_system_bus_driver ps3fb_driver = { 1298static struct ps3_system_bus_driver ps3fb_driver = {
1299 .match_id = PS3_MATCH_ID_GRAPHICS, 1299 .match_id = PS3_MATCH_ID_GRAPHICS,
1300 .match_sub_id = PS3_MATCH_SUB_ID_FB,
1300 .core.name = DEVICE_NAME, 1301 .core.name = DEVICE_NAME,
1301 .core.owner = THIS_MODULE, 1302 .core.owner = THIS_MODULE,
1302 .probe = ps3fb_probe, 1303 .probe = ps3fb_probe,
diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c
index d0746261c957..2b707a8ce5de 100644
--- a/drivers/video/pxafb.c
+++ b/drivers/video/pxafb.c
@@ -30,6 +30,7 @@
30#include <linux/string.h> 30#include <linux/string.h>
31#include <linux/interrupt.h> 31#include <linux/interrupt.h>
32#include <linux/slab.h> 32#include <linux/slab.h>
33#include <linux/mm.h>
33#include <linux/fb.h> 34#include <linux/fb.h>
34#include <linux/delay.h> 35#include <linux/delay.h>
35#include <linux/init.h> 36#include <linux/init.h>
@@ -40,6 +41,7 @@
40#include <linux/clk.h> 41#include <linux/clk.h>
41#include <linux/err.h> 42#include <linux/err.h>
42#include <linux/completion.h> 43#include <linux/completion.h>
44#include <linux/mutex.h>
43#include <linux/kthread.h> 45#include <linux/kthread.h>
44#include <linux/freezer.h> 46#include <linux/freezer.h>
45 47
@@ -227,6 +229,22 @@ static int pxafb_bpp_to_lccr3(struct fb_var_screeninfo *var)
227 case 4: ret = LCCR3_4BPP; break; 229 case 4: ret = LCCR3_4BPP; break;
228 case 8: ret = LCCR3_8BPP; break; 230 case 8: ret = LCCR3_8BPP; break;
229 case 16: ret = LCCR3_16BPP; break; 231 case 16: ret = LCCR3_16BPP; break;
232 case 24:
233 switch (var->red.length + var->green.length +
234 var->blue.length + var->transp.length) {
235 case 18: ret = LCCR3_18BPP_P | LCCR3_PDFOR_3; break;
236 case 19: ret = LCCR3_19BPP_P; break;
237 }
238 break;
239 case 32:
240 switch (var->red.length + var->green.length +
241 var->blue.length + var->transp.length) {
242 case 18: ret = LCCR3_18BPP | LCCR3_PDFOR_3; break;
243 case 19: ret = LCCR3_19BPP; break;
244 case 24: ret = LCCR3_24BPP | LCCR3_PDFOR_3; break;
245 case 25: ret = LCCR3_25BPP; break;
246 }
247 break;
230 } 248 }
231 return ret; 249 return ret;
232} 250}
@@ -345,6 +363,41 @@ static int pxafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
345 var->green.offset = 5; var->green.length = 6; 363 var->green.offset = 5; var->green.length = 6;
346 var->blue.offset = 0; var->blue.length = 5; 364 var->blue.offset = 0; var->blue.length = 5;
347 var->transp.offset = var->transp.length = 0; 365 var->transp.offset = var->transp.length = 0;
366 } else if (var->bits_per_pixel > 16) {
367 struct pxafb_mode_info *mode;
368
369 mode = pxafb_getmode(inf, var);
370 if (!mode)
371 return -EINVAL;
372
373 switch (mode->depth) {
374 case 18: /* RGB666 */
375 var->transp.offset = var->transp.length = 0;
376 var->red.offset = 12; var->red.length = 6;
377 var->green.offset = 6; var->green.length = 6;
378 var->blue.offset = 0; var->blue.length = 6;
379 break;
380 case 19: /* RGBT666 */
381 var->transp.offset = 18; var->transp.length = 1;
382 var->red.offset = 12; var->red.length = 6;
383 var->green.offset = 6; var->green.length = 6;
384 var->blue.offset = 0; var->blue.length = 6;
385 break;
386 case 24: /* RGB888 */
387 var->transp.offset = var->transp.length = 0;
388 var->red.offset = 16; var->red.length = 8;
389 var->green.offset = 8; var->green.length = 8;
390 var->blue.offset = 0; var->blue.length = 8;
391 break;
392 case 25: /* RGBT888 */
393 var->transp.offset = 24; var->transp.length = 1;
394 var->red.offset = 16; var->red.length = 8;
395 var->green.offset = 8; var->green.length = 8;
396 var->blue.offset = 0; var->blue.length = 8;
397 break;
398 default:
399 return -EINVAL;
400 }
348 } else { 401 } else {
349 var->red.offset = var->green.offset = 0; 402 var->red.offset = var->green.offset = 0;
350 var->blue.offset = var->transp.offset = 0; 403 var->blue.offset = var->transp.offset = 0;
@@ -376,7 +429,7 @@ static int pxafb_set_par(struct fb_info *info)
376 struct pxafb_info *fbi = (struct pxafb_info *)info; 429 struct pxafb_info *fbi = (struct pxafb_info *)info;
377 struct fb_var_screeninfo *var = &info->var; 430 struct fb_var_screeninfo *var = &info->var;
378 431
379 if (var->bits_per_pixel == 16) 432 if (var->bits_per_pixel >= 16)
380 fbi->fb.fix.visual = FB_VISUAL_TRUECOLOR; 433 fbi->fb.fix.visual = FB_VISUAL_TRUECOLOR;
381 else if (!fbi->cmap_static) 434 else if (!fbi->cmap_static)
382 fbi->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR; 435 fbi->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
@@ -391,7 +444,7 @@ static int pxafb_set_par(struct fb_info *info)
391 444
392 fbi->fb.fix.line_length = var->xres_virtual * 445 fbi->fb.fix.line_length = var->xres_virtual *
393 var->bits_per_pixel / 8; 446 var->bits_per_pixel / 8;
394 if (var->bits_per_pixel == 16) 447 if (var->bits_per_pixel >= 16)
395 fbi->palette_size = 0; 448 fbi->palette_size = 0;
396 else 449 else
397 fbi->palette_size = var->bits_per_pixel == 1 ? 450 fbi->palette_size = var->bits_per_pixel == 1 ?
@@ -404,7 +457,7 @@ static int pxafb_set_par(struct fb_info *info)
404 */ 457 */
405 pxafb_set_truecolor(fbi->fb.fix.visual == FB_VISUAL_TRUECOLOR); 458 pxafb_set_truecolor(fbi->fb.fix.visual == FB_VISUAL_TRUECOLOR);
406 459
407 if (fbi->fb.var.bits_per_pixel == 16) 460 if (fbi->fb.var.bits_per_pixel >= 16)
408 fb_dealloc_cmap(&fbi->fb.cmap); 461 fb_dealloc_cmap(&fbi->fb.cmap);
409 else 462 else
410 fb_alloc_cmap(&fbi->fb.cmap, 1<<fbi->fb.var.bits_per_pixel, 0); 463 fb_alloc_cmap(&fbi->fb.cmap, 1<<fbi->fb.var.bits_per_pixel, 0);
@@ -831,6 +884,8 @@ static int pxafb_activate_var(struct fb_var_screeninfo *var,
831 case 4: 884 case 4:
832 case 8: 885 case 8:
833 case 16: 886 case 16:
887 case 24:
888 case 32:
834 break; 889 break;
835 default: 890 default:
836 printk(KERN_ERR "%s: invalid bit depth %d\n", 891 printk(KERN_ERR "%s: invalid bit depth %d\n",
@@ -968,6 +1023,11 @@ static void pxafb_setup_gpio(struct pxafb_info *fbi)
968 1023
969 for (gpio = 58; ldd_bits; gpio++, ldd_bits--) 1024 for (gpio = 58; ldd_bits; gpio++, ldd_bits--)
970 pxa_gpio_mode(gpio | GPIO_ALT_FN_2_OUT); 1025 pxa_gpio_mode(gpio | GPIO_ALT_FN_2_OUT);
1026 /* 18 bit interface */
1027 if (fbi->fb.var.bits_per_pixel > 16) {
1028 pxa_gpio_mode(86 | GPIO_ALT_FN_2_OUT);
1029 pxa_gpio_mode(87 | GPIO_ALT_FN_2_OUT);
1030 }
971 pxa_gpio_mode(GPIO74_LCD_FCLK_MD); 1031 pxa_gpio_mode(GPIO74_LCD_FCLK_MD);
972 pxa_gpio_mode(GPIO75_LCD_LCLK_MD); 1032 pxa_gpio_mode(GPIO75_LCD_LCLK_MD);
973 pxa_gpio_mode(GPIO76_LCD_PCLK_MD); 1033 pxa_gpio_mode(GPIO76_LCD_PCLK_MD);
@@ -1058,7 +1118,7 @@ static void set_ctrlr_state(struct pxafb_info *fbi, u_int state)
1058{ 1118{
1059 u_int old_state; 1119 u_int old_state;
1060 1120
1061 down(&fbi->ctrlr_sem); 1121 mutex_lock(&fbi->ctrlr_lock);
1062 1122
1063 old_state = fbi->state; 1123 old_state = fbi->state;
1064 1124
@@ -1146,7 +1206,7 @@ static void set_ctrlr_state(struct pxafb_info *fbi, u_int state)
1146 } 1206 }
1147 break; 1207 break;
1148 } 1208 }
1149 up(&fbi->ctrlr_sem); 1209 mutex_unlock(&fbi->ctrlr_lock);
1150} 1210}
1151 1211
1152/* 1212/*
@@ -1399,7 +1459,7 @@ static struct pxafb_info * __devinit pxafb_init_fbinfo(struct device *dev)
1399 1459
1400 init_waitqueue_head(&fbi->ctrlr_wait); 1460 init_waitqueue_head(&fbi->ctrlr_wait);
1401 INIT_WORK(&fbi->task, pxafb_task); 1461 INIT_WORK(&fbi->task, pxafb_task);
1402 init_MUTEX(&fbi->ctrlr_sem); 1462 mutex_init(&fbi->ctrlr_lock);
1403 init_completion(&fbi->disable_done); 1463 init_completion(&fbi->disable_done);
1404#ifdef CONFIG_FB_PXA_SMARTPANEL 1464#ifdef CONFIG_FB_PXA_SMARTPANEL
1405 init_completion(&fbi->command_done); 1465 init_completion(&fbi->command_done);
diff --git a/drivers/video/pxafb.h b/drivers/video/pxafb.h
index 8238dc826429..31541b86f13d 100644
--- a/drivers/video/pxafb.h
+++ b/drivers/video/pxafb.h
@@ -106,7 +106,7 @@ struct pxafb_info {
106 106
107 volatile u_char state; 107 volatile u_char state;
108 volatile u_char task_state; 108 volatile u_char task_state;
109 struct semaphore ctrlr_sem; 109 struct mutex ctrlr_lock;
110 wait_queue_head_t ctrlr_wait; 110 wait_queue_head_t ctrlr_wait;
111 struct work_struct task; 111 struct work_struct task;
112 112
diff --git a/drivers/video/sa1100fb.c b/drivers/video/sa1100fb.c
index ab2b2110478b..78bcdbc3f484 100644
--- a/drivers/video/sa1100fb.c
+++ b/drivers/video/sa1100fb.c
@@ -167,6 +167,7 @@
167#include <linux/string.h> 167#include <linux/string.h>
168#include <linux/interrupt.h> 168#include <linux/interrupt.h>
169#include <linux/slab.h> 169#include <linux/slab.h>
170#include <linux/mm.h>
170#include <linux/fb.h> 171#include <linux/fb.h>
171#include <linux/delay.h> 172#include <linux/delay.h>
172#include <linux/init.h> 173#include <linux/init.h>
@@ -174,6 +175,7 @@
174#include <linux/cpufreq.h> 175#include <linux/cpufreq.h>
175#include <linux/platform_device.h> 176#include <linux/platform_device.h>
176#include <linux/dma-mapping.h> 177#include <linux/dma-mapping.h>
178#include <linux/mutex.h>
177 179
178#include <asm/hardware.h> 180#include <asm/hardware.h>
179#include <asm/io.h> 181#include <asm/io.h>
@@ -1107,7 +1109,7 @@ static void set_ctrlr_state(struct sa1100fb_info *fbi, u_int state)
1107{ 1109{
1108 u_int old_state; 1110 u_int old_state;
1109 1111
1110 down(&fbi->ctrlr_sem); 1112 mutex_lock(&fbi->ctrlr_lock);
1111 1113
1112 old_state = fbi->state; 1114 old_state = fbi->state;
1113 1115
@@ -1192,7 +1194,7 @@ static void set_ctrlr_state(struct sa1100fb_info *fbi, u_int state)
1192 } 1194 }
1193 break; 1195 break;
1194 } 1196 }
1195 up(&fbi->ctrlr_sem); 1197 mutex_unlock(&fbi->ctrlr_lock);
1196} 1198}
1197 1199
1198/* 1200/*
@@ -1444,7 +1446,7 @@ static struct sa1100fb_info * __init sa1100fb_init_fbinfo(struct device *dev)
1444 1446
1445 init_waitqueue_head(&fbi->ctrlr_wait); 1447 init_waitqueue_head(&fbi->ctrlr_wait);
1446 INIT_WORK(&fbi->task, sa1100fb_task); 1448 INIT_WORK(&fbi->task, sa1100fb_task);
1447 init_MUTEX(&fbi->ctrlr_sem); 1449 mutex_init(&fbi->ctrlr_lock);
1448 1450
1449 return fbi; 1451 return fbi;
1450} 1452}
diff --git a/drivers/video/sa1100fb.h b/drivers/video/sa1100fb.h
index f465b27ed860..86831db9a042 100644
--- a/drivers/video/sa1100fb.h
+++ b/drivers/video/sa1100fb.h
@@ -100,7 +100,7 @@ struct sa1100fb_info {
100 100
101 volatile u_char state; 101 volatile u_char state;
102 volatile u_char task_state; 102 volatile u_char task_state;
103 struct semaphore ctrlr_sem; 103 struct mutex ctrlr_lock;
104 wait_queue_head_t ctrlr_wait; 104 wait_queue_head_t ctrlr_wait;
105 struct work_struct task; 105 struct work_struct task;
106 106
diff --git a/drivers/video/sh7760fb.c b/drivers/video/sh7760fb.c
new file mode 100644
index 000000000000..4d0e28c5790b
--- /dev/null
+++ b/drivers/video/sh7760fb.c
@@ -0,0 +1,658 @@
1/*
2 * SH7760/SH7763 LCDC Framebuffer driver.
3 *
4 * (c) 2006-2008 MSC Vertriebsges.m.b.H.,
5 * Manuel Lauss <mano@roarinelk.homelinux.net>
6 * (c) 2008 Nobuhiro Iwamatsu <iwamatsu.nobuhiro@renesas.com>
7 *
8 * This file is subject to the terms and conditions of the GNU General
9 * Public License. See the file COPYING in the main directory of this
10 * archive for more details.
11 *
12 * PLEASE HAVE A LOOK AT Documentation/fb/sh7760fb.txt!
13 *
14 * Thanks to Siegfried Schaefer <s.schaefer at schaefer-edv.de>
15 * for his original source and testing!
16 */
17
18#include <linux/completion.h>
19#include <linux/delay.h>
20#include <linux/dma-mapping.h>
21#include <linux/fb.h>
22#include <linux/interrupt.h>
23#include <linux/io.h>
24#include <linux/kernel.h>
25#include <linux/module.h>
26#include <linux/platform_device.h>
27
28#include <asm/sh7760fb.h>
29
30struct sh7760fb_par {
31 void __iomem *base;
32 int irq;
33
34 struct sh7760fb_platdata *pd; /* display information */
35
36 dma_addr_t fbdma; /* physical address */
37
38 int rot; /* rotation enabled? */
39
40 u32 pseudo_palette[16];
41
42 struct platform_device *dev;
43 struct resource *ioarea;
44 struct completion vsync; /* vsync irq event */
45};
46
47static irqreturn_t sh7760fb_irq(int irq, void *data)
48{
49 struct completion *c = data;
50
51 complete(c);
52
53 return IRQ_HANDLED;
54}
55
56static void sh7760fb_wait_vsync(struct fb_info *info)
57{
58 struct sh7760fb_par *par = info->par;
59
60 if (par->pd->novsync)
61 return;
62
63 iowrite16(ioread16(par->base + LDINTR) & ~VINT_CHECK,
64 par->base + LDINTR);
65
66 if (par->irq < 0) {
67 /* poll for vert. retrace: status bit is sticky */
68 while (!(ioread16(par->base + LDINTR) & VINT_CHECK))
69 cpu_relax();
70 } else {
71 /* a "wait_for_irq_event(par->irq)" would be extremely nice */
72 init_completion(&par->vsync);
73 enable_irq(par->irq);
74 wait_for_completion(&par->vsync);
75 disable_irq_nosync(par->irq);
76 }
77}
78
79/* wait_for_lps - wait until power supply has reached a certain state. */
80static int wait_for_lps(struct sh7760fb_par *par, int val)
81{
82 int i = 100;
83 while (--i && ((ioread16(par->base + LDPMMR) & 3) != val))
84 msleep(1);
85
86 if (i <= 0)
87 return -ETIMEDOUT;
88
89 return 0;
90}
91
92/* en/disable the LCDC */
93static int sh7760fb_blank(int blank, struct fb_info *info)
94{
95 struct sh7760fb_par *par = info->par;
96 struct sh7760fb_platdata *pd = par->pd;
97 unsigned short cntr = ioread16(par->base + LDCNTR);
98 unsigned short intr = ioread16(par->base + LDINTR);
99 int lps;
100
101 if (blank == FB_BLANK_UNBLANK) {
102 intr |= VINT_START;
103 cntr = LDCNTR_DON2 | LDCNTR_DON;
104 lps = 3;
105 } else {
106 intr &= ~VINT_START;
107 cntr = LDCNTR_DON2;
108 lps = 0;
109 }
110
111 if (pd->blank)
112 pd->blank(blank);
113
114 iowrite16(intr, par->base + LDINTR);
115 iowrite16(cntr, par->base + LDCNTR);
116
117 return wait_for_lps(par, lps);
118}
119
120/* set color registers */
121static int sh7760fb_setcmap(struct fb_cmap *cmap, struct fb_info *info)
122{
123 struct sh7760fb_par *par = info->par;
124 u32 s = cmap->start;
125 u32 l = cmap->len;
126 u16 *r = cmap->red;
127 u16 *g = cmap->green;
128 u16 *b = cmap->blue;
129 u32 col, tmo;
130 int ret;
131
132 ret = 0;
133
134 sh7760fb_wait_vsync(info);
135
136 /* request palette access */
137 iowrite16(LDPALCR_PALEN, par->base + LDPALCR);
138
139 /* poll for access grant */
140 tmo = 100;
141 while (!(ioread16(par->base + LDPALCR) & LDPALCR_PALS) && (--tmo))
142 cpu_relax();
143
144 if (!tmo) {
145 ret = 1;
146 dev_dbg(info->dev, "no palette access!\n");
147 goto out;
148 }
149
150 while (l && (s < 256)) {
151 col = ((*r) & 0xff) << 16;
152 col |= ((*g) & 0xff) << 8;
153 col |= ((*b) & 0xff);
154 col &= SH7760FB_PALETTE_MASK;
155
156 if (s < 16)
157 ((u32 *) (info->pseudo_palette))[s] = s;
158
159 s++;
160 l--;
161 r++;
162 g++;
163 b++;
164 }
165out:
166 iowrite16(0, par->base + LDPALCR);
167 return ret;
168}
169
170static void encode_fix(struct fb_fix_screeninfo *fix, struct fb_info *info,
171 unsigned long stride)
172{
173 memset(fix, 0, sizeof(struct fb_fix_screeninfo));
174 strcpy(fix->id, "sh7760-lcdc");
175
176 fix->smem_start = (unsigned long)info->screen_base;
177 fix->smem_len = info->screen_size;
178
179 fix->line_length = stride;
180}
181
182static int sh7760fb_get_color_info(struct device *dev,
183 u16 lddfr, int *bpp, int *gray)
184{
185 int lbpp, lgray;
186
187 lgray = lbpp = 0;
188
189 switch (lddfr & LDDFR_COLOR_MASK) {
190 case LDDFR_1BPP_MONO:
191 lgray = 1;
192 lbpp = 1;
193 break;
194 case LDDFR_2BPP_MONO:
195 lgray = 1;
196 lbpp = 2;
197 break;
198 case LDDFR_4BPP_MONO:
199 lgray = 1;
200 case LDDFR_4BPP:
201 lbpp = 4;
202 break;
203 case LDDFR_6BPP_MONO:
204 lgray = 1;
205 case LDDFR_8BPP:
206 lbpp = 8;
207 break;
208 case LDDFR_16BPP_RGB555:
209 case LDDFR_16BPP_RGB565:
210 lbpp = 16;
211 lgray = 0;
212 break;
213 default:
214 dev_dbg(dev, "unsupported LDDFR bit depth.\n");
215 return -EINVAL;
216 }
217
218 if (bpp)
219 *bpp = lbpp;
220 if (gray)
221 *gray = lgray;
222
223 return 0;
224}
225
226static int sh7760fb_check_var(struct fb_var_screeninfo *var,
227 struct fb_info *info)
228{
229 struct fb_fix_screeninfo *fix = &info->fix;
230 struct sh7760fb_par *par = info->par;
231 int ret, bpp;
232
233 /* get color info from register value */
234 ret = sh7760fb_get_color_info(info->dev, par->pd->lddfr, &bpp, NULL);
235 if (ret)
236 return ret;
237
238 var->bits_per_pixel = bpp;
239
240 if ((var->grayscale) && (var->bits_per_pixel == 1))
241 fix->visual = FB_VISUAL_MONO10;
242 else if (var->bits_per_pixel >= 15)
243 fix->visual = FB_VISUAL_TRUECOLOR;
244 else
245 fix->visual = FB_VISUAL_PSEUDOCOLOR;
246
247 /* TODO: add some more validation here */
248 return 0;
249}
250
251/*
252 * sh7760fb_set_par - set videomode.
253 *
254 * NOTE: The rotation, grayscale and DSTN codepaths are
255 * totally untested!
256 */
257static int sh7760fb_set_par(struct fb_info *info)
258{
259 struct sh7760fb_par *par = info->par;
260 struct fb_videomode *vm = par->pd->def_mode;
261 unsigned long sbase, dstn_off, ldsarl, stride;
262 unsigned short hsynp, hsynw, htcn, hdcn;
263 unsigned short vsynp, vsynw, vtln, vdln;
264 unsigned short lddfr, ldmtr;
265 int ret, bpp, gray;
266
267 par->rot = par->pd->rotate;
268
269 /* rotate only works with xres <= 320 */
270 if (par->rot && (vm->xres > 320)) {
271 dev_dbg(info->dev, "rotation disabled due to display size\n");
272 par->rot = 0;
273 }
274
275 /* calculate LCDC reg vals from display parameters */
276 hsynp = vm->right_margin + vm->xres;
277 hsynw = vm->hsync_len;
278 htcn = vm->left_margin + hsynp + hsynw;
279 hdcn = vm->xres;
280 vsynp = vm->lower_margin + vm->yres;
281 vsynw = vm->vsync_len;
282 vtln = vm->upper_margin + vsynp + vsynw;
283 vdln = vm->yres;
284
285 /* get color info from register value */
286 ret = sh7760fb_get_color_info(info->dev, par->pd->lddfr, &bpp, &gray);
287 if (ret)
288 return ret;
289
290 dev_dbg(info->dev, "%dx%d %dbpp %s (orientation %s)\n", hdcn,
291 vdln, bpp, gray ? "grayscale" : "color",
292 par->rot ? "rotated" : "normal");
293
294#ifdef CONFIG_CPU_LITTLE_ENDIAN
295 lddfr = par->pd->lddfr | (1 << 8);
296#else
297 lddfr = par->pd->lddfr & ~(1 << 8);
298#endif
299
300 ldmtr = par->pd->ldmtr;
301
302 if (!(vm->sync & FB_SYNC_HOR_HIGH_ACT))
303 ldmtr |= LDMTR_CL1POL;
304 if (!(vm->sync & FB_SYNC_VERT_HIGH_ACT))
305 ldmtr |= LDMTR_FLMPOL;
306
307 /* shut down LCDC before changing display parameters */
308 sh7760fb_blank(FB_BLANK_POWERDOWN, info);
309
310 iowrite16(par->pd->ldickr, par->base + LDICKR); /* pixclock */
311 iowrite16(ldmtr, par->base + LDMTR); /* polarities */
312 iowrite16(lddfr, par->base + LDDFR); /* color/depth */
313 iowrite16((par->rot ? 1 << 13 : 0), par->base + LDSMR); /* rotate */
314 iowrite16(par->pd->ldpmmr, par->base + LDPMMR); /* Power Management */
315 iowrite16(par->pd->ldpspr, par->base + LDPSPR); /* Power Supply Ctrl */
316
317 /* display resolution */
318 iowrite16(((htcn >> 3) - 1) | (((hdcn >> 3) - 1) << 8),
319 par->base + LDHCNR);
320 iowrite16(vdln - 1, par->base + LDVDLNR);
321 iowrite16(vtln - 1, par->base + LDVTLNR);
322 /* h/v sync signals */
323 iowrite16((vsynp - 1) | ((vsynw - 1) << 12), par->base + LDVSYNR);
324 iowrite16(((hsynp >> 3) - 1) | (((hsynw >> 3) - 1) << 12),
325 par->base + LDHSYNR);
326 /* AC modulation sig */
327 iowrite16(par->pd->ldaclnr, par->base + LDACLNR);
328
329 stride = (par->rot) ? vtln : hdcn;
330 if (!gray)
331 stride *= (bpp + 7) >> 3;
332 else {
333 if (bpp == 1)
334 stride >>= 3;
335 else if (bpp == 2)
336 stride >>= 2;
337 else if (bpp == 4)
338 stride >>= 1;
339 /* 6 bpp == 8 bpp */
340 }
341
342 /* if rotated, stride must be power of 2 */
343 if (par->rot) {
344 unsigned long bit = 1 << 31;
345 while (bit) {
346 if (stride & bit)
347 break;
348 bit >>= 1;
349 }
350 if (stride & ~bit)
351 stride = bit << 1; /* not P-o-2, round up */
352 }
353 iowrite16(stride, par->base + LDLAOR);
354
355 /* set display mem start address */
356 sbase = (unsigned long)par->fbdma;
357 if (par->rot)
358 sbase += (hdcn - 1) * stride;
359
360 iowrite32(sbase, par->base + LDSARU);
361
362 /*
363 * for DSTN need to set address for lower half.
364 * I (mlau) don't know which address to set it to,
365 * so I guessed at (stride * yres/2).
366 */
367 if (((ldmtr & 0x003f) >= LDMTR_DSTN_MONO_8) &&
368 ((ldmtr & 0x003f) <= LDMTR_DSTN_COLOR_16)) {
369
370 dev_dbg(info->dev, " ***** DSTN untested! *****\n");
371
372 dstn_off = stride;
373 if (par->rot)
374 dstn_off *= hdcn >> 1;
375 else
376 dstn_off *= vdln >> 1;
377
378 ldsarl = sbase + dstn_off;
379 } else
380 ldsarl = 0;
381
382 iowrite32(ldsarl, par->base + LDSARL); /* mem for lower half of DSTN */
383
384 encode_fix(&info->fix, info, stride);
385 sh7760fb_check_var(&info->var, info);
386
387 sh7760fb_blank(FB_BLANK_UNBLANK, info); /* panel on! */
388
389 dev_dbg(info->dev, "hdcn : %6d htcn : %6d\n", hdcn, htcn);
390 dev_dbg(info->dev, "hsynw : %6d hsynp : %6d\n", hsynw, hsynp);
391 dev_dbg(info->dev, "vdln : %6d vtln : %6d\n", vdln, vtln);
392 dev_dbg(info->dev, "vsynw : %6d vsynp : %6d\n", vsynw, vsynp);
393 dev_dbg(info->dev, "clksrc: %6d clkdiv: %6d\n",
394 (par->pd->ldickr >> 12) & 3, par->pd->ldickr & 0x1f);
395 dev_dbg(info->dev, "ldpmmr: 0x%04x ldpspr: 0x%04x\n", par->pd->ldpmmr,
396 par->pd->ldpspr);
397 dev_dbg(info->dev, "ldmtr : 0x%04x lddfr : 0x%04x\n", ldmtr, lddfr);
398 dev_dbg(info->dev, "ldlaor: %ld\n", stride);
399 dev_dbg(info->dev, "ldsaru: 0x%08lx ldsarl: 0x%08lx\n", sbase, ldsarl);
400
401 return 0;
402}
403
404static struct fb_ops sh7760fb_ops = {
405 .owner = THIS_MODULE,
406 .fb_blank = sh7760fb_blank,
407 .fb_check_var = sh7760fb_check_var,
408 .fb_setcmap = sh7760fb_setcmap,
409 .fb_set_par = sh7760fb_set_par,
410 .fb_fillrect = cfb_fillrect,
411 .fb_copyarea = cfb_copyarea,
412 .fb_imageblit = cfb_imageblit,
413};
414
415static void sh7760fb_free_mem(struct fb_info *info)
416{
417 struct sh7760fb_par *par = info->par;
418
419 if (!info->screen_base)
420 return;
421
422 dma_free_coherent(info->dev, info->screen_size,
423 info->screen_base, par->fbdma);
424
425 par->fbdma = 0;
426 info->screen_base = NULL;
427 info->screen_size = 0;
428}
429
430/* allocate the framebuffer memory. This memory must be in Area3,
431 * (dictated by the DMA engine) and contiguous, at a 512 byte boundary.
432 */
433static int sh7760fb_alloc_mem(struct fb_info *info)
434{
435 struct sh7760fb_par *par = info->par;
436 void *fbmem;
437 unsigned long vram;
438 int ret, bpp;
439
440 if (info->screen_base)
441 return 0;
442
443 /* get color info from register value */
444 ret = sh7760fb_get_color_info(info->dev, par->pd->lddfr, &bpp, NULL);
445 if (ret) {
446 printk(KERN_ERR "colinfo\n");
447 return ret;
448 }
449
450 /* min VRAM: xres_min = 16, yres_min = 1, bpp = 1: 2byte -> 1 page
451 max VRAM: xres_max = 1024, yres_max = 1024, bpp = 16: 2MB */
452
453 vram = info->var.xres * info->var.yres;
454 if (info->var.grayscale) {
455 if (bpp == 1)
456 vram >>= 3;
457 else if (bpp == 2)
458 vram >>= 2;
459 else if (bpp == 4)
460 vram >>= 1;
461 } else if (bpp > 8)
462 vram *= 2;
463 if ((vram < 1) || (vram > 1024 * 2048)) {
464 dev_dbg(info->dev, "too much VRAM required. Check settings\n");
465 return -ENODEV;
466 }
467
468 if (vram < PAGE_SIZE)
469 vram = PAGE_SIZE;
470
471 fbmem = dma_alloc_coherent(info->dev, vram, &par->fbdma, GFP_KERNEL);
472
473 if (!fbmem)
474 return -ENOMEM;
475
476 if ((par->fbdma & SH7760FB_DMA_MASK) != SH7760FB_DMA_MASK) {
477 sh7760fb_free_mem(info);
478 dev_err(info->dev, "kernel gave me memory at 0x%08lx, which is"
479 "unusable for the LCDC\n", (unsigned long)par->fbdma);
480 return -ENOMEM;
481 }
482
483 info->screen_base = fbmem;
484 info->screen_size = vram;
485
486 return 0;
487}
488
489static int __devinit sh7760fb_probe(struct platform_device *pdev)
490{
491 struct fb_info *info;
492 struct resource *res;
493 struct sh7760fb_par *par;
494 int ret;
495
496 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
497 if (unlikely(res == NULL)) {
498 dev_err(&pdev->dev, "invalid resource\n");
499 return -EINVAL;
500 }
501
502 info = framebuffer_alloc(sizeof(struct sh7760fb_par), &pdev->dev);
503 if (!info)
504 return -ENOMEM;
505
506 par = info->par;
507 par->dev = pdev;
508
509 par->pd = pdev->dev.platform_data;
510 if (!par->pd) {
511 dev_dbg(info->dev, "no display setup data!\n");
512 ret = -ENODEV;
513 goto out_fb;
514 }
515
516 par->ioarea = request_mem_region(res->start,
517 (res->end - res->start), pdev->name);
518 if (!par->ioarea) {
519 dev_err(&pdev->dev, "mmio area busy\n");
520 ret = -EBUSY;
521 goto out_fb;
522 }
523
524 par->base = ioremap_nocache(res->start, res->end - res->start + 1);
525 if (!par->base) {
526 dev_err(&pdev->dev, "cannot remap\n");
527 ret = -ENODEV;
528 goto out_res;
529 }
530
531 iowrite16(0, par->base + LDINTR); /* disable vsync irq */
532 par->irq = platform_get_irq(pdev, 0);
533 if (par->irq >= 0) {
534 ret = request_irq(par->irq, sh7760fb_irq, 0,
535 "sh7760-lcdc", &par->vsync);
536 if (ret) {
537 dev_err(&pdev->dev, "cannot grab IRQ\n");
538 par->irq = -ENXIO;
539 } else
540 disable_irq_nosync(par->irq);
541 }
542
543 fb_videomode_to_var(&info->var, par->pd->def_mode);
544
545 ret = sh7760fb_alloc_mem(info);
546 if (ret) {
547 dev_dbg(info->dev, "framebuffer memory allocation failed!\n");
548 goto out_unmap;
549 }
550
551 info->pseudo_palette = par->pseudo_palette;
552
553 /* fixup color register bitpositions. These are fixed by hardware */
554 info->var.red.offset = 11;
555 info->var.red.length = 5;
556 info->var.red.msb_right = 0;
557
558 info->var.green.offset = 5;
559 info->var.green.length = 6;
560 info->var.green.msb_right = 0;
561
562 info->var.blue.offset = 0;
563 info->var.blue.length = 5;
564 info->var.blue.msb_right = 0;
565
566 info->var.transp.offset = 0;
567 info->var.transp.length = 0;
568 info->var.transp.msb_right = 0;
569
570 /* set the DON2 bit now, before cmap allocation, as it will randomize
571 * palette memory.
572 */
573 iowrite16(LDCNTR_DON2, par->base + LDCNTR);
574 info->fbops = &sh7760fb_ops;
575
576 ret = fb_alloc_cmap(&info->cmap, 256, 0);
577 if (ret) {
578 dev_dbg(info->dev, "Unable to allocate cmap memory\n");
579 goto out_mem;
580 }
581
582 ret = register_framebuffer(info);
583 if (ret < 0) {
584 dev_dbg(info->dev, "cannot register fb!\n");
585 goto out_cmap;
586 }
587 platform_set_drvdata(pdev, info);
588
589 printk(KERN_INFO "%s: memory at phys 0x%08lx-0x%08lx, size %ld KiB\n",
590 pdev->name,
591 (unsigned long)par->fbdma,
592 (unsigned long)(par->fbdma + info->screen_size - 1),
593 info->screen_size >> 10);
594
595 return 0;
596
597out_cmap:
598 sh7760fb_blank(FB_BLANK_POWERDOWN, info);
599 fb_dealloc_cmap(&info->cmap);
600out_mem:
601 sh7760fb_free_mem(info);
602out_unmap:
603 if (par->irq >= 0)
604 free_irq(par->irq, &par->vsync);
605 iounmap(par->base);
606out_res:
607 release_resource(par->ioarea);
608 kfree(par->ioarea);
609out_fb:
610 framebuffer_release(info);
611 return ret;
612}
613
614static int __devexit sh7760fb_remove(struct platform_device *dev)
615{
616 struct fb_info *info = platform_get_drvdata(dev);
617 struct sh7760fb_par *par = info->par;
618
619 sh7760fb_blank(FB_BLANK_POWERDOWN, info);
620 unregister_framebuffer(info);
621 fb_dealloc_cmap(&info->cmap);
622 sh7760fb_free_mem(info);
623 if (par->irq >= 0)
624 free_irq(par->irq, par);
625 iounmap(par->base);
626 release_resource(par->ioarea);
627 kfree(par->ioarea);
628 framebuffer_release(info);
629 platform_set_drvdata(dev, NULL);
630
631 return 0;
632}
633
634static struct platform_driver sh7760_lcdc_driver = {
635 .driver = {
636 .name = "sh7760-lcdc",
637 .owner = THIS_MODULE,
638 },
639 .probe = sh7760fb_probe,
640 .remove = __devexit_p(sh7760fb_remove),
641};
642
643static int __init sh7760fb_init(void)
644{
645 return platform_driver_register(&sh7760_lcdc_driver);
646}
647
648static void __exit sh7760fb_exit(void)
649{
650 platform_driver_unregister(&sh7760_lcdc_driver);
651}
652
653module_init(sh7760fb_init);
654module_exit(sh7760fb_exit);
655
656MODULE_AUTHOR("Nobuhiro Iwamatsu, Manuel Lauss");
657MODULE_DESCRIPTION("FBdev for SH7760/63 integrated LCD Controller");
658MODULE_LICENSE("GPL");
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
new file mode 100644
index 000000000000..f6ef6cca73cd
--- /dev/null
+++ b/drivers/video/sh_mobile_lcdcfb.c
@@ -0,0 +1,725 @@
1/*
2 * SuperH Mobile LCDC Framebuffer
3 *
4 * Copyright (c) 2008 Magnus Damm
5 *
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file "COPYING" in the main directory of this archive
8 * for more details.
9 */
10
11#include <linux/kernel.h>
12#include <linux/init.h>
13#include <linux/delay.h>
14#include <linux/mm.h>
15#include <linux/fb.h>
16#include <linux/clk.h>
17#include <linux/platform_device.h>
18#include <linux/dma-mapping.h>
19#include <asm/sh_mobile_lcdc.h>
20
21#define PALETTE_NR 16
22
23struct sh_mobile_lcdc_priv;
24struct sh_mobile_lcdc_chan {
25 struct sh_mobile_lcdc_priv *lcdc;
26 unsigned long *reg_offs;
27 unsigned long ldmt1r_value;
28 unsigned long enabled; /* ME and SE in LDCNT2R */
29 struct sh_mobile_lcdc_chan_cfg cfg;
30 u32 pseudo_palette[PALETTE_NR];
31 struct fb_info info;
32 dma_addr_t dma_handle;
33};
34
35struct sh_mobile_lcdc_priv {
36 void __iomem *base;
37 struct clk *clk;
38 unsigned long lddckr;
39 struct sh_mobile_lcdc_chan ch[2];
40};
41
42/* shared registers */
43#define _LDDCKR 0x410
44#define _LDDCKSTPR 0x414
45#define _LDINTR 0x468
46#define _LDSR 0x46c
47#define _LDCNT1R 0x470
48#define _LDCNT2R 0x474
49#define _LDDDSR 0x47c
50#define _LDDWD0R 0x800
51#define _LDDRDR 0x840
52#define _LDDWAR 0x900
53#define _LDDRAR 0x904
54
55/* per-channel registers */
56enum { LDDCKPAT1R, LDDCKPAT2R, LDMT1R, LDMT2R, LDMT3R, LDDFR, LDSM1R,
57 LDSA1R, LDMLSR, LDHCNR, LDHSYNR, LDVLNR, LDVSYNR, LDPMR };
58
59static unsigned long lcdc_offs_mainlcd[] = {
60 [LDDCKPAT1R] = 0x400,
61 [LDDCKPAT2R] = 0x404,
62 [LDMT1R] = 0x418,
63 [LDMT2R] = 0x41c,
64 [LDMT3R] = 0x420,
65 [LDDFR] = 0x424,
66 [LDSM1R] = 0x428,
67 [LDSA1R] = 0x430,
68 [LDMLSR] = 0x438,
69 [LDHCNR] = 0x448,
70 [LDHSYNR] = 0x44c,
71 [LDVLNR] = 0x450,
72 [LDVSYNR] = 0x454,
73 [LDPMR] = 0x460,
74};
75
76static unsigned long lcdc_offs_sublcd[] = {
77 [LDDCKPAT1R] = 0x408,
78 [LDDCKPAT2R] = 0x40c,
79 [LDMT1R] = 0x600,
80 [LDMT2R] = 0x604,
81 [LDMT3R] = 0x608,
82 [LDDFR] = 0x60c,
83 [LDSM1R] = 0x610,
84 [LDSA1R] = 0x618,
85 [LDMLSR] = 0x620,
86 [LDHCNR] = 0x624,
87 [LDHSYNR] = 0x628,
88 [LDVLNR] = 0x62c,
89 [LDVSYNR] = 0x630,
90 [LDPMR] = 0x63c,
91};
92
93#define START_LCDC 0x00000001
94#define LCDC_RESET 0x00000100
95#define DISPLAY_BEU 0x00000008
96#define LCDC_ENABLE 0x00000001
97
98static void lcdc_write_chan(struct sh_mobile_lcdc_chan *chan,
99 int reg_nr, unsigned long data)
100{
101 iowrite32(data, chan->lcdc->base + chan->reg_offs[reg_nr]);
102}
103
104static unsigned long lcdc_read_chan(struct sh_mobile_lcdc_chan *chan,
105 int reg_nr)
106{
107 return ioread32(chan->lcdc->base + chan->reg_offs[reg_nr]);
108}
109
110static void lcdc_write(struct sh_mobile_lcdc_priv *priv,
111 unsigned long reg_offs, unsigned long data)
112{
113 iowrite32(data, priv->base + reg_offs);
114}
115
116static unsigned long lcdc_read(struct sh_mobile_lcdc_priv *priv,
117 unsigned long reg_offs)
118{
119 return ioread32(priv->base + reg_offs);
120}
121
122static void lcdc_wait_bit(struct sh_mobile_lcdc_priv *priv,
123 unsigned long reg_offs,
124 unsigned long mask, unsigned long until)
125{
126 while ((lcdc_read(priv, reg_offs) & mask) != until)
127 cpu_relax();
128}
129
130static int lcdc_chan_is_sublcd(struct sh_mobile_lcdc_chan *chan)
131{
132 return chan->cfg.chan == LCDC_CHAN_SUBLCD;
133}
134
135static void lcdc_sys_write_index(void *handle, unsigned long data)
136{
137 struct sh_mobile_lcdc_chan *ch = handle;
138
139 lcdc_write(ch->lcdc, _LDDWD0R, data | 0x10000000);
140 lcdc_wait_bit(ch->lcdc, _LDSR, 2, 0);
141 lcdc_write(ch->lcdc, _LDDWAR, 1 | (lcdc_chan_is_sublcd(ch) ? 2 : 0));
142}
143
144static void lcdc_sys_write_data(void *handle, unsigned long data)
145{
146 struct sh_mobile_lcdc_chan *ch = handle;
147
148 lcdc_write(ch->lcdc, _LDDWD0R, data | 0x11000000);
149 lcdc_wait_bit(ch->lcdc, _LDSR, 2, 0);
150 lcdc_write(ch->lcdc, _LDDWAR, 1 | (lcdc_chan_is_sublcd(ch) ? 2 : 0));
151}
152
153static unsigned long lcdc_sys_read_data(void *handle)
154{
155 struct sh_mobile_lcdc_chan *ch = handle;
156
157 lcdc_write(ch->lcdc, _LDDRDR, 0x01000000);
158 lcdc_wait_bit(ch->lcdc, _LDSR, 2, 0);
159 lcdc_write(ch->lcdc, _LDDRAR, 1 | (lcdc_chan_is_sublcd(ch) ? 2 : 0));
160 udelay(1);
161
162 return lcdc_read(ch->lcdc, _LDDRDR) & 0xffff;
163}
164
165struct sh_mobile_lcdc_sys_bus_ops sh_mobile_lcdc_sys_bus_ops = {
166 lcdc_sys_write_index,
167 lcdc_sys_write_data,
168 lcdc_sys_read_data,
169};
170
171static void sh_mobile_lcdc_start_stop(struct sh_mobile_lcdc_priv *priv,
172 int start)
173{
174 unsigned long tmp = lcdc_read(priv, _LDCNT2R);
175 int k;
176
177 /* start or stop the lcdc */
178 if (start)
179 lcdc_write(priv, _LDCNT2R, tmp | START_LCDC);
180 else
181 lcdc_write(priv, _LDCNT2R, tmp & ~START_LCDC);
182
183 /* wait until power is applied/stopped on all channels */
184 for (k = 0; k < ARRAY_SIZE(priv->ch); k++)
185 if (lcdc_read(priv, _LDCNT2R) & priv->ch[k].enabled)
186 while (1) {
187 tmp = lcdc_read_chan(&priv->ch[k], LDPMR) & 3;
188 if (start && tmp == 3)
189 break;
190 if (!start && tmp == 0)
191 break;
192 cpu_relax();
193 }
194
195 if (!start)
196 lcdc_write(priv, _LDDCKSTPR, 1); /* stop dotclock */
197}
198
199static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
200{
201 struct sh_mobile_lcdc_chan *ch;
202 struct fb_videomode *lcd_cfg;
203 struct sh_mobile_lcdc_board_cfg *board_cfg;
204 unsigned long tmp;
205 int k, m;
206 int ret = 0;
207
208 /* reset */
209 lcdc_write(priv, _LDCNT2R, lcdc_read(priv, _LDCNT2R) | LCDC_RESET);
210 lcdc_wait_bit(priv, _LDCNT2R, LCDC_RESET, 0);
211
212 /* enable LCDC channels */
213 tmp = lcdc_read(priv, _LDCNT2R);
214 tmp |= priv->ch[0].enabled;
215 tmp |= priv->ch[1].enabled;
216 lcdc_write(priv, _LDCNT2R, tmp);
217
218 /* read data from external memory, avoid using the BEU for now */
219 lcdc_write(priv, _LDCNT2R, lcdc_read(priv, _LDCNT2R) & ~DISPLAY_BEU);
220
221 /* stop the lcdc first */
222 sh_mobile_lcdc_start_stop(priv, 0);
223
224 /* configure clocks */
225 tmp = priv->lddckr;
226 for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
227 ch = &priv->ch[k];
228
229 if (!priv->ch[k].enabled)
230 continue;
231
232 m = ch->cfg.clock_divider;
233 if (!m)
234 continue;
235
236 if (m == 1)
237 m = 1 << 6;
238 tmp |= m << (lcdc_chan_is_sublcd(ch) ? 8 : 0);
239
240 lcdc_write_chan(ch, LDDCKPAT1R, 0x00000000);
241 lcdc_write_chan(ch, LDDCKPAT2R, (1 << (m/2)) - 1);
242 }
243
244 lcdc_write(priv, _LDDCKR, tmp);
245
246 /* start dotclock again */
247 lcdc_write(priv, _LDDCKSTPR, 0);
248 lcdc_wait_bit(priv, _LDDCKSTPR, ~0, 0);
249
250 /* interrupts are disabled */
251 lcdc_write(priv, _LDINTR, 0);
252
253 for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
254 ch = &priv->ch[k];
255 lcd_cfg = &ch->cfg.lcd_cfg;
256
257 if (!ch->enabled)
258 continue;
259
260 tmp = ch->ldmt1r_value;
261 tmp |= (lcd_cfg->sync & FB_SYNC_VERT_HIGH_ACT) ? 0 : 1 << 28;
262 tmp |= (lcd_cfg->sync & FB_SYNC_HOR_HIGH_ACT) ? 0 : 1 << 27;
263 lcdc_write_chan(ch, LDMT1R, tmp);
264
265 /* setup SYS bus */
266 lcdc_write_chan(ch, LDMT2R, ch->cfg.sys_bus_cfg.ldmt2r);
267 lcdc_write_chan(ch, LDMT3R, ch->cfg.sys_bus_cfg.ldmt3r);
268
269 /* horizontal configuration */
270 tmp = lcd_cfg->xres + lcd_cfg->hsync_len;
271 tmp += lcd_cfg->left_margin;
272 tmp += lcd_cfg->right_margin;
273 tmp /= 8; /* HTCN */
274 tmp |= (lcd_cfg->xres / 8) << 16; /* HDCN */
275 lcdc_write_chan(ch, LDHCNR, tmp);
276
277 tmp = lcd_cfg->xres;
278 tmp += lcd_cfg->right_margin;
279 tmp /= 8; /* HSYNP */
280 tmp |= (lcd_cfg->hsync_len / 8) << 16; /* HSYNW */
281 lcdc_write_chan(ch, LDHSYNR, tmp);
282
283 /* power supply */
284 lcdc_write_chan(ch, LDPMR, 0);
285
286 /* vertical configuration */
287 tmp = lcd_cfg->yres + lcd_cfg->vsync_len;
288 tmp += lcd_cfg->upper_margin;
289 tmp += lcd_cfg->lower_margin; /* VTLN */
290 tmp |= lcd_cfg->yres << 16; /* VDLN */
291 lcdc_write_chan(ch, LDVLNR, tmp);
292
293 tmp = lcd_cfg->yres;
294 tmp += lcd_cfg->lower_margin; /* VSYNP */
295 tmp |= lcd_cfg->vsync_len << 16; /* VSYNW */
296 lcdc_write_chan(ch, LDVSYNR, tmp);
297
298 board_cfg = &ch->cfg.board_cfg;
299 if (board_cfg->setup_sys)
300 ret = board_cfg->setup_sys(board_cfg->board_data, ch,
301 &sh_mobile_lcdc_sys_bus_ops);
302 if (ret)
303 return ret;
304 }
305
306 /* --- display_lcdc_data() --- */
307 lcdc_write(priv, _LDINTR, 0x00000f00);
308
309 /* word and long word swap */
310 lcdc_write(priv, _LDDDSR, lcdc_read(priv, _LDDDSR) | 6);
311
312 for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
313 ch = &priv->ch[k];
314
315 if (!priv->ch[k].enabled)
316 continue;
317
318 /* set bpp format in PKF[4:0] */
319 tmp = lcdc_read_chan(ch, LDDFR);
320 tmp &= ~(0x0001001f);
321 tmp |= (priv->ch[k].info.var.bits_per_pixel == 16) ? 3 : 0;
322 lcdc_write_chan(ch, LDDFR, tmp);
323
324 /* point out our frame buffer */
325 lcdc_write_chan(ch, LDSA1R, ch->info.fix.smem_start);
326
327 /* set line size */
328 lcdc_write_chan(ch, LDMLSR, ch->info.fix.line_length);
329
330 /* continuous read mode */
331 lcdc_write_chan(ch, LDSM1R, 0);
332 }
333
334 /* display output */
335 lcdc_write(priv, _LDCNT1R, LCDC_ENABLE);
336
337 /* start the lcdc */
338 sh_mobile_lcdc_start_stop(priv, 1);
339
340 /* tell the board code to enable the panel */
341 for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
342 ch = &priv->ch[k];
343 board_cfg = &ch->cfg.board_cfg;
344 if (board_cfg->display_on)
345 board_cfg->display_on(board_cfg->board_data);
346 }
347
348 return 0;
349}
350
351static void sh_mobile_lcdc_stop(struct sh_mobile_lcdc_priv *priv)
352{
353 struct sh_mobile_lcdc_chan *ch;
354 struct sh_mobile_lcdc_board_cfg *board_cfg;
355 int k;
356
357 /* tell the board code to disable the panel */
358 for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
359 ch = &priv->ch[k];
360 board_cfg = &ch->cfg.board_cfg;
361 if (board_cfg->display_off)
362 board_cfg->display_off(board_cfg->board_data);
363 }
364
365 /* stop the lcdc */
366 sh_mobile_lcdc_start_stop(priv, 0);
367}
368
369static int sh_mobile_lcdc_check_interface(struct sh_mobile_lcdc_chan *ch)
370{
371 int ifm, miftyp;
372
373 switch (ch->cfg.interface_type) {
374 case RGB8: ifm = 0; miftyp = 0; break;
375 case RGB9: ifm = 0; miftyp = 4; break;
376 case RGB12A: ifm = 0; miftyp = 5; break;
377 case RGB12B: ifm = 0; miftyp = 6; break;
378 case RGB16: ifm = 0; miftyp = 7; break;
379 case RGB18: ifm = 0; miftyp = 10; break;
380 case RGB24: ifm = 0; miftyp = 11; break;
381 case SYS8A: ifm = 1; miftyp = 0; break;
382 case SYS8B: ifm = 1; miftyp = 1; break;
383 case SYS8C: ifm = 1; miftyp = 2; break;
384 case SYS8D: ifm = 1; miftyp = 3; break;
385 case SYS9: ifm = 1; miftyp = 4; break;
386 case SYS12: ifm = 1; miftyp = 5; break;
387 case SYS16A: ifm = 1; miftyp = 7; break;
388 case SYS16B: ifm = 1; miftyp = 8; break;
389 case SYS16C: ifm = 1; miftyp = 9; break;
390 case SYS18: ifm = 1; miftyp = 10; break;
391 case SYS24: ifm = 1; miftyp = 11; break;
392 default: goto bad;
393 }
394
395 /* SUBLCD only supports SYS interface */
396 if (lcdc_chan_is_sublcd(ch)) {
397 if (ifm == 0)
398 goto bad;
399 else
400 ifm = 0;
401 }
402
403 ch->ldmt1r_value = (ifm << 12) | miftyp;
404 return 0;
405 bad:
406 return -EINVAL;
407}
408
409static int sh_mobile_lcdc_setup_clocks(struct device *dev, int clock_source,
410 struct sh_mobile_lcdc_priv *priv)
411{
412 char *str;
413 int icksel;
414
415 switch (clock_source) {
416 case LCDC_CLK_BUS: str = "bus_clk"; icksel = 0; break;
417 case LCDC_CLK_PERIPHERAL: str = "peripheral_clk"; icksel = 1; break;
418 case LCDC_CLK_EXTERNAL: str = NULL; icksel = 2; break;
419 default:
420 return -EINVAL;
421 }
422
423 priv->lddckr = icksel << 16;
424
425 if (str) {
426 priv->clk = clk_get(dev, str);
427 if (IS_ERR(priv->clk)) {
428 dev_err(dev, "cannot get clock %s\n", str);
429 return PTR_ERR(priv->clk);
430 }
431
432 clk_enable(priv->clk);
433 }
434
435 return 0;
436}
437
438static int sh_mobile_lcdc_setcolreg(u_int regno,
439 u_int red, u_int green, u_int blue,
440 u_int transp, struct fb_info *info)
441{
442 u32 *palette = info->pseudo_palette;
443
444 if (regno >= PALETTE_NR)
445 return -EINVAL;
446
447 /* only FB_VISUAL_TRUECOLOR supported */
448
449 red >>= 16 - info->var.red.length;
450 green >>= 16 - info->var.green.length;
451 blue >>= 16 - info->var.blue.length;
452 transp >>= 16 - info->var.transp.length;
453
454 palette[regno] = (red << info->var.red.offset) |
455 (green << info->var.green.offset) |
456 (blue << info->var.blue.offset) |
457 (transp << info->var.transp.offset);
458
459 return 0;
460}
461
462static struct fb_fix_screeninfo sh_mobile_lcdc_fix = {
463 .id = "SH Mobile LCDC",
464 .type = FB_TYPE_PACKED_PIXELS,
465 .visual = FB_VISUAL_TRUECOLOR,
466 .accel = FB_ACCEL_NONE,
467};
468
469static struct fb_ops sh_mobile_lcdc_ops = {
470 .fb_setcolreg = sh_mobile_lcdc_setcolreg,
471 .fb_fillrect = cfb_fillrect,
472 .fb_copyarea = cfb_copyarea,
473 .fb_imageblit = cfb_imageblit,
474};
475
476static int sh_mobile_lcdc_set_bpp(struct fb_var_screeninfo *var, int bpp)
477{
478 switch (bpp) {
479 case 16: /* PKF[4:0] = 00011 - RGB 565 */
480 var->red.offset = 11;
481 var->red.length = 5;
482 var->green.offset = 5;
483 var->green.length = 6;
484 var->blue.offset = 0;
485 var->blue.length = 5;
486 var->transp.offset = 0;
487 var->transp.length = 0;
488 break;
489
490 case 32: /* PKF[4:0] = 00000 - RGB 888
491 * sh7722 pdf says 00RRGGBB but reality is GGBB00RR
492 * this may be because LDDDSR has word swap enabled..
493 */
494 var->red.offset = 0;
495 var->red.length = 8;
496 var->green.offset = 24;
497 var->green.length = 8;
498 var->blue.offset = 16;
499 var->blue.length = 8;
500 var->transp.offset = 0;
501 var->transp.length = 0;
502 break;
503 default:
504 return -EINVAL;
505 }
506 var->bits_per_pixel = bpp;
507 var->red.msb_right = 0;
508 var->green.msb_right = 0;
509 var->blue.msb_right = 0;
510 var->transp.msb_right = 0;
511 return 0;
512}
513
514static int sh_mobile_lcdc_remove(struct platform_device *pdev);
515
516static int __init sh_mobile_lcdc_probe(struct platform_device *pdev)
517{
518 struct fb_info *info;
519 struct sh_mobile_lcdc_priv *priv;
520 struct sh_mobile_lcdc_info *pdata;
521 struct sh_mobile_lcdc_chan_cfg *cfg;
522 struct resource *res;
523 int error;
524 void *buf;
525 int i, j;
526
527 if (!pdev->dev.platform_data) {
528 dev_err(&pdev->dev, "no platform data defined\n");
529 error = -EINVAL;
530 goto err0;
531 }
532
533 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
534 if (res == NULL) {
535 dev_err(&pdev->dev, "cannot find IO resource\n");
536 error = -ENOENT;
537 goto err0;
538 }
539
540 priv = kzalloc(sizeof(*priv), GFP_KERNEL);
541 if (!priv) {
542 dev_err(&pdev->dev, "cannot allocate device data\n");
543 error = -ENOMEM;
544 goto err0;
545 }
546
547 platform_set_drvdata(pdev, priv);
548 pdata = pdev->dev.platform_data;
549
550 j = 0;
551 for (i = 0; i < ARRAY_SIZE(pdata->ch); i++) {
552 priv->ch[j].lcdc = priv;
553 memcpy(&priv->ch[j].cfg, &pdata->ch[i], sizeof(pdata->ch[i]));
554
555 error = sh_mobile_lcdc_check_interface(&priv->ch[i]);
556 if (error) {
557 dev_err(&pdev->dev, "unsupported interface type\n");
558 goto err1;
559 }
560
561 switch (pdata->ch[i].chan) {
562 case LCDC_CHAN_MAINLCD:
563 priv->ch[j].enabled = 1 << 1;
564 priv->ch[j].reg_offs = lcdc_offs_mainlcd;
565 j++;
566 break;
567 case LCDC_CHAN_SUBLCD:
568 priv->ch[j].enabled = 1 << 2;
569 priv->ch[j].reg_offs = lcdc_offs_sublcd;
570 j++;
571 break;
572 }
573 }
574
575 if (!j) {
576 dev_err(&pdev->dev, "no channels defined\n");
577 error = -EINVAL;
578 goto err1;
579 }
580
581 error = sh_mobile_lcdc_setup_clocks(&pdev->dev,
582 pdata->clock_source, priv);
583 if (error) {
584 dev_err(&pdev->dev, "unable to setup clocks\n");
585 goto err1;
586 }
587
588 priv->lddckr = pdata->lddckr;
589 priv->base = ioremap_nocache(res->start, (res->end - res->start) + 1);
590
591 for (i = 0; i < j; i++) {
592 info = &priv->ch[i].info;
593 cfg = &priv->ch[i].cfg;
594
595 info->fbops = &sh_mobile_lcdc_ops;
596 info->var.xres = info->var.xres_virtual = cfg->lcd_cfg.xres;
597 info->var.yres = info->var.yres_virtual = cfg->lcd_cfg.yres;
598 info->var.activate = FB_ACTIVATE_NOW;
599 error = sh_mobile_lcdc_set_bpp(&info->var, cfg->bpp);
600 if (error)
601 break;
602
603 info->fix = sh_mobile_lcdc_fix;
604 info->fix.line_length = cfg->lcd_cfg.xres * (cfg->bpp / 8);
605 info->fix.smem_len = info->fix.line_length * cfg->lcd_cfg.yres;
606
607 buf = dma_alloc_coherent(&pdev->dev, info->fix.smem_len,
608 &priv->ch[i].dma_handle, GFP_KERNEL);
609 if (!buf) {
610 dev_err(&pdev->dev, "unable to allocate buffer\n");
611 error = -ENOMEM;
612 break;
613 }
614
615 info->pseudo_palette = &priv->ch[i].pseudo_palette;
616 info->flags = FBINFO_FLAG_DEFAULT;
617
618 error = fb_alloc_cmap(&info->cmap, PALETTE_NR, 0);
619 if (error < 0) {
620 dev_err(&pdev->dev, "unable to allocate cmap\n");
621 dma_free_coherent(&pdev->dev, info->fix.smem_len,
622 buf, priv->ch[i].dma_handle);
623 break;
624 }
625
626 memset(buf, 0, info->fix.smem_len);
627 info->fix.smem_start = priv->ch[i].dma_handle;
628 info->screen_base = buf;
629 info->device = &pdev->dev;
630 }
631
632 if (error)
633 goto err1;
634
635 error = sh_mobile_lcdc_start(priv);
636 if (error) {
637 dev_err(&pdev->dev, "unable to start hardware\n");
638 goto err1;
639 }
640
641 for (i = 0; i < j; i++) {
642 error = register_framebuffer(&priv->ch[i].info);
643 if (error < 0)
644 goto err1;
645 }
646
647 for (i = 0; i < j; i++) {
648 info = &priv->ch[i].info;
649 dev_info(info->dev,
650 "registered %s/%s as %dx%d %dbpp.\n",
651 pdev->name,
652 (priv->ch[i].cfg.chan == LCDC_CHAN_MAINLCD) ?
653 "mainlcd" : "sublcd",
654 (int) priv->ch[i].cfg.lcd_cfg.xres,
655 (int) priv->ch[i].cfg.lcd_cfg.yres,
656 priv->ch[i].cfg.bpp);
657 }
658
659 return 0;
660 err1:
661 sh_mobile_lcdc_remove(pdev);
662 err0:
663 return error;
664}
665
666static int sh_mobile_lcdc_remove(struct platform_device *pdev)
667{
668 struct sh_mobile_lcdc_priv *priv = platform_get_drvdata(pdev);
669 struct fb_info *info;
670 int i;
671
672 for (i = 0; i < ARRAY_SIZE(priv->ch); i++)
673 if (priv->ch[i].info.dev)
674 unregister_framebuffer(&priv->ch[i].info);
675
676 sh_mobile_lcdc_stop(priv);
677
678 for (i = 0; i < ARRAY_SIZE(priv->ch); i++) {
679 info = &priv->ch[i].info;
680
681 if (!info->device)
682 continue;
683
684 dma_free_coherent(&pdev->dev, info->fix.smem_len,
685 info->screen_base, priv->ch[i].dma_handle);
686 fb_dealloc_cmap(&info->cmap);
687 }
688
689 if (priv->clk) {
690 clk_disable(priv->clk);
691 clk_put(priv->clk);
692 }
693
694 if (priv->base)
695 iounmap(priv->base);
696
697 kfree(priv);
698 return 0;
699}
700
701static struct platform_driver sh_mobile_lcdc_driver = {
702 .driver = {
703 .name = "sh_mobile_lcdc_fb",
704 .owner = THIS_MODULE,
705 },
706 .probe = sh_mobile_lcdc_probe,
707 .remove = sh_mobile_lcdc_remove,
708};
709
710static int __init sh_mobile_lcdc_init(void)
711{
712 return platform_driver_register(&sh_mobile_lcdc_driver);
713}
714
715static void __exit sh_mobile_lcdc_exit(void)
716{
717 platform_driver_unregister(&sh_mobile_lcdc_driver);
718}
719
720module_init(sh_mobile_lcdc_init);
721module_exit(sh_mobile_lcdc_exit);
722
723MODULE_DESCRIPTION("SuperH Mobile LCDC Framebuffer driver");
724MODULE_AUTHOR("Magnus Damm <damm@opensource.se>");
725MODULE_LICENSE("GPL v2");
diff --git a/drivers/video/sis/init.h b/drivers/video/sis/init.h
index f40a680df86f..b96005c39c67 100644
--- a/drivers/video/sis/init.h
+++ b/drivers/video/sis/init.h
@@ -73,7 +73,6 @@
73#ifdef SIS_CP 73#ifdef SIS_CP
74#undef SIS_CP 74#undef SIS_CP
75#endif 75#endif
76#include <linux/version.h>
77#include <linux/types.h> 76#include <linux/types.h>
78#include <asm/io.h> 77#include <asm/io.h>
79#include <linux/fb.h> 78#include <linux/fb.h>
diff --git a/drivers/video/sis/init301.h b/drivers/video/sis/init301.h
index 7708e1e1d99e..51d99222375d 100644
--- a/drivers/video/sis/init301.h
+++ b/drivers/video/sis/init301.h
@@ -67,7 +67,6 @@
67#ifdef SIS_CP 67#ifdef SIS_CP
68#undef SIS_CP 68#undef SIS_CP
69#endif 69#endif
70#include <linux/version.h>
71#include <linux/types.h> 70#include <linux/types.h>
72#include <asm/io.h> 71#include <asm/io.h>
73#include <linux/fb.h> 72#include <linux/fb.h>
diff --git a/drivers/video/sis/initextlfb.c b/drivers/video/sis/initextlfb.c
index 47a33501549d..99c04a4855d1 100644
--- a/drivers/video/sis/initextlfb.c
+++ b/drivers/video/sis/initextlfb.c
@@ -30,7 +30,6 @@
30#include "vgatypes.h" 30#include "vgatypes.h"
31#include "vstruct.h" 31#include "vstruct.h"
32 32
33#include <linux/version.h>
34#include <linux/types.h> 33#include <linux/types.h>
35#include <linux/fb.h> 34#include <linux/fb.h>
36 35
diff --git a/drivers/video/sis/osdef.h b/drivers/video/sis/osdef.h
index c1492782cb18..6ff8f988a1a7 100644
--- a/drivers/video/sis/osdef.h
+++ b/drivers/video/sis/osdef.h
@@ -87,7 +87,6 @@
87/**********************************************************************/ 87/**********************************************************************/
88 88
89#ifdef SIS_LINUX_KERNEL 89#ifdef SIS_LINUX_KERNEL
90#include <linux/version.h>
91 90
92#ifdef CONFIG_FB_SIS_300 91#ifdef CONFIG_FB_SIS_300
93#define SIS300 92#define SIS300
diff --git a/drivers/video/sis/sis.h b/drivers/video/sis/sis.h
index a14e82211037..7c5710e3fb56 100644
--- a/drivers/video/sis/sis.h
+++ b/drivers/video/sis/sis.h
@@ -24,8 +24,6 @@
24#ifndef _SIS_H_ 24#ifndef _SIS_H_
25#define _SIS_H_ 25#define _SIS_H_
26 26
27#include <linux/version.h>
28
29#include "osdef.h" 27#include "osdef.h"
30#include <video/sisfb.h> 28#include <video/sisfb.h>
31 29
@@ -42,16 +40,6 @@
42#define SIS_NEW_CONFIG_COMPAT 40#define SIS_NEW_CONFIG_COMPAT
43#endif /* CONFIG_COMPAT */ 41#endif /* CONFIG_COMPAT */
44 42
45#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)
46#define SIS_IOTYPE1 void __iomem
47#define SIS_IOTYPE2 __iomem
48#define SISINITSTATIC static
49#else
50#define SIS_IOTYPE1 unsigned char
51#define SIS_IOTYPE2
52#define SISINITSTATIC
53#endif
54
55#undef SISFBDEBUG 43#undef SISFBDEBUG
56 44
57#ifdef SISFBDEBUG 45#ifdef SISFBDEBUG
@@ -505,8 +493,8 @@ struct sis_video_info {
505 493
506 unsigned long UMAsize, LFBsize; 494 unsigned long UMAsize, LFBsize;
507 495
508 SIS_IOTYPE1 *video_vbase; 496 void __iomem *video_vbase;
509 SIS_IOTYPE1 *mmio_vbase; 497 void __iomem *mmio_vbase;
510 498
511 unsigned char *bios_abase; 499 unsigned char *bios_abase;
512 500
@@ -533,8 +521,8 @@ struct sis_video_info {
533 int sisfb_nocrt2rate; 521 int sisfb_nocrt2rate;
534 522
535 u32 heapstart; /* offset */ 523 u32 heapstart; /* offset */
536 SIS_IOTYPE1 *sisfb_heap_start; /* address */ 524 void __iomem *sisfb_heap_start; /* address */
537 SIS_IOTYPE1 *sisfb_heap_end; /* address */ 525 void __iomem *sisfb_heap_end; /* address */
538 u32 sisfb_heap_size; 526 u32 sisfb_heap_size;
539 int havenoheap; 527 int havenoheap;
540 528
@@ -612,7 +600,7 @@ struct sis_video_info {
612 u8 detectedpdca; 600 u8 detectedpdca;
613 u8 detectedlcda; 601 u8 detectedlcda;
614 602
615 SIS_IOTYPE1 *hwcursor_vbase; 603 void __iomem *hwcursor_vbase;
616 604
617 int chronteltype; 605 int chronteltype;
618 int tvxpos, tvypos; 606 int tvxpos, tvypos;
diff --git a/drivers/video/sis/sis_accel.c b/drivers/video/sis/sis_accel.c
index 7addf91d2fea..ceb434c95c0d 100644
--- a/drivers/video/sis/sis_accel.c
+++ b/drivers/video/sis/sis_accel.c
@@ -28,7 +28,6 @@
28 * for more information and updates) 28 * for more information and updates)
29 */ 29 */
30 30
31#include <linux/version.h>
32#include <linux/module.h> 31#include <linux/module.h>
33#include <linux/kernel.h> 32#include <linux/kernel.h>
34#include <linux/fb.h> 33#include <linux/fb.h>
diff --git a/drivers/video/sis/sis_main.c b/drivers/video/sis/sis_main.c
index b9343844cd1f..346d6458cf76 100644
--- a/drivers/video/sis/sis_main.c
+++ b/drivers/video/sis/sis_main.c
@@ -33,7 +33,6 @@
33 * 33 *
34 */ 34 */
35 35
36#include <linux/version.h>
37#include <linux/module.h> 36#include <linux/module.h>
38#include <linux/moduleparam.h> 37#include <linux/moduleparam.h>
39#include <linux/kernel.h> 38#include <linux/kernel.h>
@@ -41,13 +40,7 @@
41#include <linux/errno.h> 40#include <linux/errno.h>
42#include <linux/string.h> 41#include <linux/string.h>
43#include <linux/mm.h> 42#include <linux/mm.h>
44
45#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
46#include <linux/tty.h>
47#else
48#include <linux/screen_info.h> 43#include <linux/screen_info.h>
49#endif
50
51#include <linux/slab.h> 44#include <linux/slab.h>
52#include <linux/fb.h> 45#include <linux/fb.h>
53#include <linux/selection.h> 46#include <linux/selection.h>
@@ -1167,11 +1160,7 @@ sisfb_set_mode(struct sis_video_info *ivideo, int clrscrn)
1167 unsigned short modeno = ivideo->mode_no; 1160 unsigned short modeno = ivideo->mode_no;
1168 1161
1169 /* >=2.6.12's fbcon clears the screen anyway */ 1162 /* >=2.6.12's fbcon clears the screen anyway */
1170#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12)
1171 if(!clrscrn) modeno |= 0x80;
1172#else
1173 modeno |= 0x80; 1163 modeno |= 0x80;
1174#endif
1175 1164
1176 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD); 1165 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
1177 1166
@@ -1436,11 +1425,8 @@ sisfb_set_par(struct fb_info *info)
1436 if((err = sisfb_do_set_var(&info->var, 1, info))) 1425 if((err = sisfb_do_set_var(&info->var, 1, info)))
1437 return err; 1426 return err;
1438 1427
1439#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
1440 sisfb_get_fix(&info->fix, info->currcon, info);
1441#else
1442 sisfb_get_fix(&info->fix, -1, info); 1428 sisfb_get_fix(&info->fix, -1, info);
1443#endif 1429
1444 return 0; 1430 return 0;
1445} 1431}
1446 1432
@@ -1676,14 +1662,8 @@ sisfb_blank(int blank, struct fb_info *info)
1676 1662
1677/* ----------- FBDev related routines for all series ---------- */ 1663/* ----------- FBDev related routines for all series ---------- */
1678 1664
1679#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15)
1680static int sisfb_ioctl(struct fb_info *info, unsigned int cmd, 1665static int sisfb_ioctl(struct fb_info *info, unsigned int cmd,
1681 unsigned long arg) 1666 unsigned long arg)
1682#else
1683static int sisfb_ioctl(struct inode *inode, struct file *file,
1684 unsigned int cmd, unsigned long arg,
1685 struct fb_info *info)
1686#endif
1687{ 1667{
1688 struct sis_video_info *ivideo = (struct sis_video_info *)info->par; 1668 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1689 struct sis_memreq sismemreq; 1669 struct sis_memreq sismemreq;
@@ -3986,8 +3966,7 @@ sisfb_handle_command(struct sis_video_info *ivideo, struct sisfb_cmd *sisfb_comm
3986} 3966}
3987 3967
3988#ifndef MODULE 3968#ifndef MODULE
3989SISINITSTATIC int __init 3969static int __init sisfb_setup(char *options)
3990sisfb_setup(char *options)
3991{ 3970{
3992 char *this_opt; 3971 char *this_opt;
3993 3972
@@ -4086,9 +4065,9 @@ sisfb_setup(char *options)
4086#endif 4065#endif
4087 4066
4088static int __devinit 4067static int __devinit
4089sisfb_check_rom(SIS_IOTYPE1 *rom_base, struct sis_video_info *ivideo) 4068sisfb_check_rom(void __iomem *rom_base, struct sis_video_info *ivideo)
4090{ 4069{
4091 SIS_IOTYPE1 *rom; 4070 void __iomem *rom;
4092 int romptr; 4071 int romptr;
4093 4072
4094 if((readb(rom_base) != 0x55) || (readb(rom_base + 1) != 0xaa)) 4073 if((readb(rom_base) != 0x55) || (readb(rom_base + 1) != 0xaa))
@@ -4117,10 +4096,9 @@ static unsigned char * __devinit
4117sisfb_find_rom(struct pci_dev *pdev) 4096sisfb_find_rom(struct pci_dev *pdev)
4118{ 4097{
4119 struct sis_video_info *ivideo = pci_get_drvdata(pdev); 4098 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4120 SIS_IOTYPE1 *rom_base; 4099 void __iomem *rom_base;
4121 unsigned char *myrombase = NULL; 4100 unsigned char *myrombase = NULL;
4122 u32 temp; 4101 u32 temp;
4123#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11)
4124 size_t romsize; 4102 size_t romsize;
4125 4103
4126 /* First, try the official pci ROM functions (except 4104 /* First, try the official pci ROM functions (except
@@ -4151,7 +4129,6 @@ sisfb_find_rom(struct pci_dev *pdev)
4151 } 4129 }
4152 4130
4153 if(myrombase) return myrombase; 4131 if(myrombase) return myrombase;
4154#endif
4155 4132
4156 /* Otherwise do it the conventional way. */ 4133 /* Otherwise do it the conventional way. */
4157 4134
@@ -4225,7 +4202,7 @@ sisfb_post_map_vram(struct sis_video_info *ivideo, unsigned int *mapsize,
4225static int __devinit 4202static int __devinit
4226sisfb_post_300_buswidth(struct sis_video_info *ivideo) 4203sisfb_post_300_buswidth(struct sis_video_info *ivideo)
4227{ 4204{
4228 SIS_IOTYPE1 *FBAddress = ivideo->video_vbase; 4205 void __iomem *FBAddress = ivideo->video_vbase;
4229 unsigned short temp; 4206 unsigned short temp;
4230 unsigned char reg; 4207 unsigned char reg;
4231 int i, j; 4208 int i, j;
@@ -4273,7 +4250,7 @@ sisfb_post_300_rwtest(struct sis_video_info *ivideo, int iteration, int buswidth
4273 int PseudoRankCapacity, int PseudoAdrPinCount, 4250 int PseudoRankCapacity, int PseudoAdrPinCount,
4274 unsigned int mapsize) 4251 unsigned int mapsize)
4275{ 4252{
4276 SIS_IOTYPE1 *FBAddr = ivideo->video_vbase; 4253 void __iomem *FBAddr = ivideo->video_vbase;
4277 unsigned short sr14; 4254 unsigned short sr14;
4278 unsigned int k, RankCapacity, PageCapacity, BankNumHigh, BankNumMid; 4255 unsigned int k, RankCapacity, PageCapacity, BankNumHigh, BankNumMid;
4279 unsigned int PhysicalAdrOtherPage, PhysicalAdrHigh, PhysicalAdrHalfPage; 4256 unsigned int PhysicalAdrOtherPage, PhysicalAdrHigh, PhysicalAdrHalfPage;
@@ -5829,7 +5806,7 @@ sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
5829 ivideo->engineok = 0; 5806 ivideo->engineok = 0;
5830 5807
5831 ivideo->sisfb_was_boot_device = 0; 5808 ivideo->sisfb_was_boot_device = 0;
5832#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12)) 5809
5833 if(pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW) { 5810 if(pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW) {
5834 if(ivideo->sisvga_enabled) 5811 if(ivideo->sisvga_enabled)
5835 ivideo->sisfb_was_boot_device = 1; 5812 ivideo->sisfb_was_boot_device = 1;
@@ -5840,7 +5817,6 @@ sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
5840 "as the primary VGA device\n"); 5817 "as the primary VGA device\n");
5841 } 5818 }
5842 } 5819 }
5843#endif
5844 5820
5845 ivideo->sisfb_parm_mem = sisfb_parm_mem; 5821 ivideo->sisfb_parm_mem = sisfb_parm_mem;
5846 ivideo->sisfb_accel = sisfb_accel; 5822 ivideo->sisfb_accel = sisfb_accel;
@@ -6010,7 +5986,7 @@ sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
6010 ivideo->modeprechange = reg & 0x7f; 5986 ivideo->modeprechange = reg & 0x7f;
6011 } else if(ivideo->sisvga_enabled) { 5987 } else if(ivideo->sisvga_enabled) {
6012#if defined(__i386__) || defined(__x86_64__) 5988#if defined(__i386__) || defined(__x86_64__)
6013 unsigned char SIS_IOTYPE2 *tt = ioremap(0x400, 0x100); 5989 unsigned char __iomem *tt = ioremap(0x400, 0x100);
6014 if(tt) { 5990 if(tt) {
6015 ivideo->modeprechange = readb(tt + 0x49); 5991 ivideo->modeprechange = readb(tt + 0x49);
6016 iounmap(tt); 5992 iounmap(tt);
@@ -6503,7 +6479,7 @@ static struct pci_driver sisfb_driver = {
6503 .remove = __devexit_p(sisfb_remove) 6479 .remove = __devexit_p(sisfb_remove)
6504}; 6480};
6505 6481
6506SISINITSTATIC int __init sisfb_init(void) 6482static int __init sisfb_init(void)
6507{ 6483{
6508#ifndef MODULE 6484#ifndef MODULE
6509 char *options = NULL; 6485 char *options = NULL;
diff --git a/drivers/video/sis/sis_main.h b/drivers/video/sis/sis_main.h
index 3e3b7fa05d6c..9540e977270e 100644
--- a/drivers/video/sis/sis_main.h
+++ b/drivers/video/sis/sis_main.h
@@ -665,11 +665,11 @@ static struct _customttable {
665 665
666/* Interface used by the world */ 666/* Interface used by the world */
667#ifndef MODULE 667#ifndef MODULE
668SISINITSTATIC int sisfb_setup(char *options); 668static int sisfb_setup(char *options);
669#endif 669#endif
670 670
671/* Interface to the low level console driver */ 671/* Interface to the low level console driver */
672SISINITSTATIC int sisfb_init(void); 672static int sisfb_init(void);
673 673
674/* fbdev routines */ 674/* fbdev routines */
675static int sisfb_get_fix(struct fb_fix_screeninfo *fix, int con, 675static int sisfb_get_fix(struct fb_fix_screeninfo *fix, int con,
diff --git a/drivers/video/sis/vgatypes.h b/drivers/video/sis/vgatypes.h
index b532fbd2b04c..81a22eaabfde 100644
--- a/drivers/video/sis/vgatypes.h
+++ b/drivers/video/sis/vgatypes.h
@@ -53,10 +53,6 @@
53#ifndef _VGATYPES_H_ 53#ifndef _VGATYPES_H_
54#define _VGATYPES_H_ 54#define _VGATYPES_H_
55 55
56#ifdef SIS_LINUX_KERNEL
57#include <linux/version.h>
58#endif
59
60#define SISIOMEMTYPE 56#define SISIOMEMTYPE
61 57
62#ifdef SIS_LINUX_KERNEL 58#ifdef SIS_LINUX_KERNEL
diff --git a/drivers/video/skeletonfb.c b/drivers/video/skeletonfb.c
index 62321458f71a..df5336561d13 100644
--- a/drivers/video/skeletonfb.c
+++ b/drivers/video/skeletonfb.c
@@ -675,13 +675,13 @@ static struct fb_ops xxxfb_ops = {
675 * Initialization 675 * Initialization
676 */ 676 */
677 677
678/* static int __init xxfb_probe (struct device *device) -- for platform devs */ 678/* static int __init xxfb_probe (struct platform_device *pdev) -- for platform devs */
679static int __devinit xxxfb_probe(struct pci_dev *dev, 679static int __devinit xxxfb_probe(struct pci_dev *dev,
680 const struct pci_device_id *ent) 680 const struct pci_device_id *ent)
681{ 681{
682 struct fb_info *info; 682 struct fb_info *info;
683 struct xxx_par *par; 683 struct xxx_par *par;
684 struct device* device = &dev->dev; /* for pci drivers */ 684 struct device *device = &dev->dev; /* or &pdev->dev */
685 int cmap_len, retval; 685 int cmap_len, retval;
686 686
687 /* 687 /*
@@ -824,18 +824,18 @@ static int __devinit xxxfb_probe(struct pci_dev *dev,
824 return -EINVAL; 824 return -EINVAL;
825 printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, 825 printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node,
826 info->fix.id); 826 info->fix.id);
827 pci_set_drvdata(dev, info); /* or dev_set_drvdata(device, info) */ 827 pci_set_drvdata(dev, info); /* or platform_set_drvdata(pdev, info) */
828 return 0; 828 return 0;
829} 829}
830 830
831 /* 831 /*
832 * Cleanup 832 * Cleanup
833 */ 833 */
834/* static void __devexit xxxfb_remove(struct device *device) */ 834/* static void __devexit xxxfb_remove(struct platform_device *pdev) */
835static void __devexit xxxfb_remove(struct pci_dev *dev) 835static void __devexit xxxfb_remove(struct pci_dev *dev)
836{ 836{
837 struct fb_info *info = pci_get_drvdata(dev); 837 struct fb_info *info = pci_get_drvdata(dev);
838 /* or dev_get_drvdata(device); */ 838 /* or platform_get_drvdata(pdev); */
839 839
840 if (info) { 840 if (info) {
841 unregister_framebuffer(info); 841 unregister_framebuffer(info);
@@ -961,18 +961,17 @@ static int xxxfb_resume(struct platform_dev *dev)
961#define xxxfb_resume NULL 961#define xxxfb_resume NULL
962#endif /* CONFIG_PM */ 962#endif /* CONFIG_PM */
963 963
964static struct device_driver xxxfb_driver = { 964static struct platform_device_driver xxxfb_driver = {
965 .name = "xxxfb",
966 .bus = &platform_bus_type,
967 .probe = xxxfb_probe, 965 .probe = xxxfb_probe,
968 .remove = xxxfb_remove, 966 .remove = xxxfb_remove,
969 .suspend = xxxfb_suspend, /* optional but recommended */ 967 .suspend = xxxfb_suspend, /* optional but recommended */
970 .resume = xxxfb_resume, /* optional but recommended */ 968 .resume = xxxfb_resume, /* optional but recommended */
969 .driver = {
970 .name = "xxxfb",
971 },
971}; 972};
972 973
973static struct platform_device xxxfb_device = { 974static struct platform_device *xxxfb_device;
974 .name = "xxxfb",
975};
976 975
977#ifndef MODULE 976#ifndef MODULE
978 /* 977 /*
@@ -1002,12 +1001,16 @@ static int __init xxxfb_init(void)
1002 return -ENODEV; 1001 return -ENODEV;
1003 xxxfb_setup(option); 1002 xxxfb_setup(option);
1004#endif 1003#endif
1005 ret = driver_register(&xxxfb_driver); 1004 ret = platform_driver_register(&xxxfb_driver);
1006 1005
1007 if (!ret) { 1006 if (!ret) {
1008 ret = platform_device_register(&xxxfb_device); 1007 xxxfb_device = platform_device_register_simple("xxxfb", 0,
1009 if (ret) 1008 NULL, 0);
1010 driver_unregister(&xxxfb_driver); 1009
1010 if (IS_ERR(xxxfb_device)) {
1011 platform_driver_unregister(&xxxfb_driver);
1012 ret = PTR_ERR(xxxfb_device);
1013 }
1011 } 1014 }
1012 1015
1013 return ret; 1016 return ret;
@@ -1015,8 +1018,8 @@ static int __init xxxfb_init(void)
1015 1018
1016static void __exit xxxfb_exit(void) 1019static void __exit xxxfb_exit(void)
1017{ 1020{
1018 platform_device_unregister(&xxxfb_device); 1021 platform_device_unregister(xxxfb_device);
1019 driver_unregister(&xxxfb_driver); 1022 platform_driver_unregister(&xxxfb_driver);
1020} 1023}
1021#endif /* CONFIG_PCI */ 1024#endif /* CONFIG_PCI */
1022 1025
diff --git a/drivers/video/sm501fb.c b/drivers/video/sm501fb.c
index 15d4a768b1f6..f94ae84a58cd 100644
--- a/drivers/video/sm501fb.c
+++ b/drivers/video/sm501fb.c
@@ -48,10 +48,15 @@ enum sm501_controller {
48 HEAD_PANEL = 1, 48 HEAD_PANEL = 1,
49}; 49};
50 50
51/* SM501 memory address */ 51/* SM501 memory address.
52 *
53 * This structure is used to track memory usage within the SM501 framebuffer
54 * allocation. The sm_addr field is stored as an offset as it is often used
55 * against both the physical and mapped addresses.
56 */
52struct sm501_mem { 57struct sm501_mem {
53 unsigned long size; 58 unsigned long size;
54 unsigned long sm_addr; 59 unsigned long sm_addr; /* offset from base of sm501 fb. */
55 void __iomem *k_addr; 60 void __iomem *k_addr;
56}; 61};
57 62
@@ -142,31 +147,68 @@ static inline void sm501fb_sync_regs(struct sm501fb_info *info)
142static int sm501_alloc_mem(struct sm501fb_info *inf, struct sm501_mem *mem, 147static int sm501_alloc_mem(struct sm501fb_info *inf, struct sm501_mem *mem,
143 unsigned int why, size_t size) 148 unsigned int why, size_t size)
144{ 149{
145 unsigned int ptr = 0; 150 struct sm501fb_par *par;
151 struct fb_info *fbi;
152 unsigned int ptr;
153 unsigned int end;
146 154
147 switch (why) { 155 switch (why) {
148 case SM501_MEMF_CURSOR: 156 case SM501_MEMF_CURSOR:
149 ptr = inf->fbmem_len - size; 157 ptr = inf->fbmem_len - size;
150 inf->fbmem_len = ptr; 158 inf->fbmem_len = ptr; /* adjust available memory. */
151 break; 159 break;
152 160
153 case SM501_MEMF_PANEL: 161 case SM501_MEMF_PANEL:
154 ptr = inf->fbmem_len - size; 162 ptr = inf->fbmem_len - size;
155 if (ptr < inf->fb[0]->fix.smem_len) 163 fbi = inf->fb[HEAD_CRT];
164
165 /* round down, some programs such as directfb do not draw
166 * 0,0 correctly unless the start is aligned to a page start.
167 */
168
169 if (ptr > 0)
170 ptr &= ~(PAGE_SIZE - 1);
171
172 if (fbi && ptr < fbi->fix.smem_len)
173 return -ENOMEM;
174
175 if (ptr < 0)
156 return -ENOMEM; 176 return -ENOMEM;
157 177
158 break; 178 break;
159 179
160 case SM501_MEMF_CRT: 180 case SM501_MEMF_CRT:
161 ptr = 0; 181 ptr = 0;
182
183 /* check to see if we have panel memory allocated
184 * which would put an limit on available memory. */
185
186 fbi = inf->fb[HEAD_PANEL];
187 if (fbi) {
188 par = fbi->par;
189 end = par->screen.k_addr ? par->screen.sm_addr : inf->fbmem_len;
190 } else
191 end = inf->fbmem_len;
192
193 if ((ptr + size) > end)
194 return -ENOMEM;
195
162 break; 196 break;
163 197
164 case SM501_MEMF_ACCEL: 198 case SM501_MEMF_ACCEL:
165 ptr = inf->fb[0]->fix.smem_len; 199 fbi = inf->fb[HEAD_CRT];
200 ptr = fbi ? fbi->fix.smem_len : 0;
201
202 fbi = inf->fb[HEAD_PANEL];
203 if (fbi) {
204 par = fbi->par;
205 end = par->screen.sm_addr;
206 } else
207 end = inf->fbmem_len;
166 208
167 if ((ptr + size) > 209 if ((ptr + size) > end)
168 (inf->fb[1]->fix.smem_start - inf->fbmem_res->start))
169 return -ENOMEM; 210 return -ENOMEM;
211
170 break; 212 break;
171 213
172 default: 214 default:
@@ -663,15 +705,25 @@ static void sm501fb_panel_power(struct sm501fb_info *fbi, int to)
663 sm501fb_sync_regs(fbi); 705 sm501fb_sync_regs(fbi);
664 mdelay(10); 706 mdelay(10);
665 707
708 /* VBIASEN */
709
666 if (!(pd->flags & SM501FB_FLAG_PANEL_NO_VBIASEN)) { 710 if (!(pd->flags & SM501FB_FLAG_PANEL_NO_VBIASEN)) {
667 control |= SM501_DC_PANEL_CONTROL_BIAS; /* VBIASEN */ 711 if (pd->flags & SM501FB_FLAG_PANEL_INV_VBIASEN)
712 control &= ~SM501_DC_PANEL_CONTROL_BIAS;
713 else
714 control |= SM501_DC_PANEL_CONTROL_BIAS;
715
668 writel(control, ctrl_reg); 716 writel(control, ctrl_reg);
669 sm501fb_sync_regs(fbi); 717 sm501fb_sync_regs(fbi);
670 mdelay(10); 718 mdelay(10);
671 } 719 }
672 720
673 if (!(pd->flags & SM501FB_FLAG_PANEL_NO_FPEN)) { 721 if (!(pd->flags & SM501FB_FLAG_PANEL_NO_FPEN)) {
674 control |= SM501_DC_PANEL_CONTROL_FPEN; 722 if (pd->flags & SM501FB_FLAG_PANEL_INV_FPEN)
723 control &= ~SM501_DC_PANEL_CONTROL_FPEN;
724 else
725 control |= SM501_DC_PANEL_CONTROL_FPEN;
726
675 writel(control, ctrl_reg); 727 writel(control, ctrl_reg);
676 sm501fb_sync_regs(fbi); 728 sm501fb_sync_regs(fbi);
677 mdelay(10); 729 mdelay(10);
@@ -679,14 +731,22 @@ static void sm501fb_panel_power(struct sm501fb_info *fbi, int to)
679 } else if (!to && (control & SM501_DC_PANEL_CONTROL_VDD) != 0) { 731 } else if (!to && (control & SM501_DC_PANEL_CONTROL_VDD) != 0) {
680 /* disable panel power */ 732 /* disable panel power */
681 if (!(pd->flags & SM501FB_FLAG_PANEL_NO_FPEN)) { 733 if (!(pd->flags & SM501FB_FLAG_PANEL_NO_FPEN)) {
682 control &= ~SM501_DC_PANEL_CONTROL_FPEN; 734 if (pd->flags & SM501FB_FLAG_PANEL_INV_FPEN)
735 control |= SM501_DC_PANEL_CONTROL_FPEN;
736 else
737 control &= ~SM501_DC_PANEL_CONTROL_FPEN;
738
683 writel(control, ctrl_reg); 739 writel(control, ctrl_reg);
684 sm501fb_sync_regs(fbi); 740 sm501fb_sync_regs(fbi);
685 mdelay(10); 741 mdelay(10);
686 } 742 }
687 743
688 if (!(pd->flags & SM501FB_FLAG_PANEL_NO_VBIASEN)) { 744 if (!(pd->flags & SM501FB_FLAG_PANEL_NO_VBIASEN)) {
689 control &= ~SM501_DC_PANEL_CONTROL_BIAS; 745 if (pd->flags & SM501FB_FLAG_PANEL_INV_VBIASEN)
746 control |= SM501_DC_PANEL_CONTROL_BIAS;
747 else
748 control &= ~SM501_DC_PANEL_CONTROL_BIAS;
749
690 writel(control, ctrl_reg); 750 writel(control, ctrl_reg);
691 sm501fb_sync_regs(fbi); 751 sm501fb_sync_regs(fbi);
692 mdelay(10); 752 mdelay(10);
@@ -1210,39 +1270,6 @@ static struct fb_ops sm501fb_ops_pnl = {
1210 .fb_imageblit = cfb_imageblit, 1270 .fb_imageblit = cfb_imageblit,
1211}; 1271};
1212 1272
1213/* sm501fb_info_alloc
1214 *
1215 * creates and initialises an sm501fb_info structure
1216*/
1217
1218static struct sm501fb_info *sm501fb_info_alloc(struct fb_info *fbinfo_crt,
1219 struct fb_info *fbinfo_pnl)
1220{
1221 struct sm501fb_info *info;
1222 struct sm501fb_par *par;
1223
1224 info = kzalloc(sizeof(struct sm501fb_info), GFP_KERNEL);
1225 if (info) {
1226 /* set the references back */
1227
1228 par = fbinfo_crt->par;
1229 par->info = info;
1230 par->head = HEAD_CRT;
1231 fbinfo_crt->pseudo_palette = &par->pseudo_palette;
1232
1233 par = fbinfo_pnl->par;
1234 par->info = info;
1235 par->head = HEAD_PANEL;
1236 fbinfo_pnl->pseudo_palette = &par->pseudo_palette;
1237
1238 /* store the two fbs into our info */
1239 info->fb[HEAD_CRT] = fbinfo_crt;
1240 info->fb[HEAD_PANEL] = fbinfo_pnl;
1241 }
1242
1243 return info;
1244}
1245
1246/* sm501_init_cursor 1273/* sm501_init_cursor
1247 * 1274 *
1248 * initialise hw cursor parameters 1275 * initialise hw cursor parameters
@@ -1250,10 +1277,16 @@ static struct sm501fb_info *sm501fb_info_alloc(struct fb_info *fbinfo_crt,
1250 1277
1251static int sm501_init_cursor(struct fb_info *fbi, unsigned int reg_base) 1278static int sm501_init_cursor(struct fb_info *fbi, unsigned int reg_base)
1252{ 1279{
1253 struct sm501fb_par *par = fbi->par; 1280 struct sm501fb_par *par;
1254 struct sm501fb_info *info = par->info; 1281 struct sm501fb_info *info;
1255 int ret; 1282 int ret;
1256 1283
1284 if (fbi == NULL)
1285 return 0;
1286
1287 par = fbi->par;
1288 info = par->info;
1289
1257 par->cursor_regs = info->regs + reg_base; 1290 par->cursor_regs = info->regs + reg_base;
1258 1291
1259 ret = sm501_alloc_mem(info, &par->cursor, SM501_MEMF_CURSOR, 1024); 1292 ret = sm501_alloc_mem(info, &par->cursor, SM501_MEMF_CURSOR, 1024);
@@ -1281,13 +1314,10 @@ static int sm501fb_start(struct sm501fb_info *info,
1281 struct platform_device *pdev) 1314 struct platform_device *pdev)
1282{ 1315{
1283 struct resource *res; 1316 struct resource *res;
1284 struct device *dev; 1317 struct device *dev = &pdev->dev;
1285 int k; 1318 int k;
1286 int ret; 1319 int ret;
1287 1320
1288 info->dev = dev = &pdev->dev;
1289 platform_set_drvdata(pdev, info);
1290
1291 info->irq = ret = platform_get_irq(pdev, 0); 1321 info->irq = ret = platform_get_irq(pdev, 0);
1292 if (ret < 0) { 1322 if (ret < 0) {
1293 /* we currently do not use the IRQ */ 1323 /* we currently do not use the IRQ */
@@ -1390,11 +1420,6 @@ static void sm501fb_stop(struct sm501fb_info *info)
1390 kfree(info->regs_res); 1420 kfree(info->regs_res);
1391} 1421}
1392 1422
1393static void sm501fb_info_release(struct sm501fb_info *info)
1394{
1395 kfree(info);
1396}
1397
1398static int sm501fb_init_fb(struct fb_info *fb, 1423static int sm501fb_init_fb(struct fb_info *fb,
1399 enum sm501_controller head, 1424 enum sm501_controller head,
1400 const char *fbname) 1425 const char *fbname)
@@ -1539,36 +1564,93 @@ static struct sm501_platdata_fb sm501fb_def_pdata = {
1539static char driver_name_crt[] = "sm501fb-crt"; 1564static char driver_name_crt[] = "sm501fb-crt";
1540static char driver_name_pnl[] = "sm501fb-panel"; 1565static char driver_name_pnl[] = "sm501fb-panel";
1541 1566
1542static int __init sm501fb_probe(struct platform_device *pdev) 1567static int __devinit sm501fb_probe_one(struct sm501fb_info *info,
1568 enum sm501_controller head)
1543{ 1569{
1544 struct sm501fb_info *info; 1570 unsigned char *name = (head == HEAD_CRT) ? "crt" : "panel";
1545 struct device *dev = &pdev->dev; 1571 struct sm501_platdata_fbsub *pd;
1546 struct fb_info *fbinfo_crt; 1572 struct sm501fb_par *par;
1547 struct fb_info *fbinfo_pnl; 1573 struct fb_info *fbi;
1548 int ret;
1549 1574
1550 /* allocate our framebuffers */ 1575 pd = (head == HEAD_CRT) ? info->pdata->fb_crt : info->pdata->fb_pnl;
1576
1577 /* Do not initialise if we've not been given any platform data */
1578 if (pd == NULL) {
1579 dev_info(info->dev, "no data for fb %s (disabled)\n", name);
1580 return 0;
1581 }
1551 1582
1552 fbinfo_crt = framebuffer_alloc(sizeof(struct sm501fb_par), dev); 1583 fbi = framebuffer_alloc(sizeof(struct sm501fb_par), info->dev);
1553 if (fbinfo_crt == NULL) { 1584 if (fbi == NULL) {
1554 dev_err(dev, "cannot allocate crt framebuffer\n"); 1585 dev_err(info->dev, "cannot allocate %s framebuffer\n", name);
1555 return -ENOMEM; 1586 return -ENOMEM;
1556 } 1587 }
1557 1588
1558 fbinfo_pnl = framebuffer_alloc(sizeof(struct sm501fb_par), dev); 1589 par = fbi->par;
1559 if (fbinfo_pnl == NULL) { 1590 par->info = info;
1560 dev_err(dev, "cannot allocate panel framebuffer\n"); 1591 par->head = head;
1561 ret = -ENOMEM; 1592 fbi->pseudo_palette = &par->pseudo_palette;
1562 goto fbinfo_crt_alloc_fail; 1593
1594 info->fb[head] = fbi;
1595
1596 return 0;
1597}
1598
1599/* Free up anything allocated by sm501fb_init_fb */
1600
1601static void sm501_free_init_fb(struct sm501fb_info *info,
1602 enum sm501_controller head)
1603{
1604 struct fb_info *fbi = info->fb[head];
1605
1606 fb_dealloc_cmap(&fbi->cmap);
1607}
1608
1609static int __devinit sm501fb_start_one(struct sm501fb_info *info,
1610 enum sm501_controller head,
1611 const char *drvname)
1612{
1613 struct fb_info *fbi = info->fb[head];
1614 int ret;
1615
1616 if (!fbi)
1617 return 0;
1618
1619 ret = sm501fb_init_fb(info->fb[head], head, drvname);
1620 if (ret) {
1621 dev_err(info->dev, "cannot initialise fb %s\n", drvname);
1622 return ret;
1623 }
1624
1625 ret = register_framebuffer(info->fb[head]);
1626 if (ret) {
1627 dev_err(info->dev, "failed to register fb %s\n", drvname);
1628 sm501_free_init_fb(info, head);
1629 return ret;
1563 } 1630 }
1564 1631
1565 info = sm501fb_info_alloc(fbinfo_crt, fbinfo_pnl); 1632 dev_info(info->dev, "fb%d: %s frame buffer\n", fbi->node, fbi->fix.id);
1566 if (info == NULL) { 1633
1567 dev_err(dev, "cannot allocate par\n"); 1634 return 0;
1568 ret = -ENOMEM; 1635}
1569 goto sm501fb_alloc_fail; 1636
1637static int __devinit sm501fb_probe(struct platform_device *pdev)
1638{
1639 struct sm501fb_info *info;
1640 struct device *dev = &pdev->dev;
1641 int ret;
1642
1643 /* allocate our framebuffers */
1644
1645 info = kzalloc(sizeof(struct sm501fb_info), GFP_KERNEL);
1646 if (!info) {
1647 dev_err(dev, "failed to allocate state\n");
1648 return -ENOMEM;
1570 } 1649 }
1571 1650
1651 info->dev = dev = &pdev->dev;
1652 platform_set_drvdata(pdev, info);
1653
1572 if (dev->parent->platform_data) { 1654 if (dev->parent->platform_data) {
1573 struct sm501_platdata *pd = dev->parent->platform_data; 1655 struct sm501_platdata *pd = dev->parent->platform_data;
1574 info->pdata = pd->fb; 1656 info->pdata = pd->fb;
@@ -1579,90 +1661,88 @@ static int __init sm501fb_probe(struct platform_device *pdev)
1579 info->pdata = &sm501fb_def_pdata; 1661 info->pdata = &sm501fb_def_pdata;
1580 } 1662 }
1581 1663
1582 /* start the framebuffers */ 1664 /* probe for the presence of each panel */
1583 1665
1584 ret = sm501fb_start(info, pdev); 1666 ret = sm501fb_probe_one(info, HEAD_CRT);
1585 if (ret) { 1667 if (ret < 0) {
1586 dev_err(dev, "cannot initialise SM501\n"); 1668 dev_err(dev, "failed to probe CRT\n");
1587 goto sm501fb_start_fail; 1669 goto err_alloc;
1588 } 1670 }
1589 1671
1590 /* CRT framebuffer setup */ 1672 ret = sm501fb_probe_one(info, HEAD_PANEL);
1673 if (ret < 0) {
1674 dev_err(dev, "failed to probe PANEL\n");
1675 goto err_probed_crt;
1676 }
1591 1677
1592 ret = sm501fb_init_fb(fbinfo_crt, HEAD_CRT, driver_name_crt); 1678 if (info->fb[HEAD_PANEL] == NULL &&
1593 if (ret) { 1679 info->fb[HEAD_CRT] == NULL) {
1594 dev_err(dev, "cannot initialise CRT fb\n"); 1680 dev_err(dev, "no framebuffers found\n");
1595 goto sm501fb_start_fail; 1681 goto err_alloc;
1596 } 1682 }
1597 1683
1598 /* Panel framebuffer setup */ 1684 /* get the resources for both of the framebuffers */
1599 1685
1600 ret = sm501fb_init_fb(fbinfo_pnl, HEAD_PANEL, driver_name_pnl); 1686 ret = sm501fb_start(info, pdev);
1601 if (ret) { 1687 if (ret) {
1602 dev_err(dev, "cannot initialise Panel fb\n"); 1688 dev_err(dev, "cannot initialise SM501\n");
1603 goto sm501fb_start_fail; 1689 goto err_probed_panel;
1604 } 1690 }
1605 1691
1606 /* register framebuffers */ 1692 ret = sm501fb_start_one(info, HEAD_CRT, driver_name_crt);
1607 1693 if (ret) {
1608 ret = register_framebuffer(fbinfo_crt); 1694 dev_err(dev, "failed to start CRT\n");
1609 if (ret < 0) { 1695 goto err_started;
1610 dev_err(dev, "failed to register CRT fb (%d)\n", ret);
1611 goto register_crt_fail;
1612 } 1696 }
1613 1697
1614 ret = register_framebuffer(fbinfo_pnl); 1698 ret = sm501fb_start_one(info, HEAD_PANEL, driver_name_pnl);
1615 if (ret < 0) { 1699 if (ret) {
1616 dev_err(dev, "failed to register panel fb (%d)\n", ret); 1700 dev_err(dev, "failed to start Panel\n");
1617 goto register_pnl_fail; 1701 goto err_started_crt;
1618 } 1702 }
1619 1703
1620 dev_info(dev, "fb%d: %s frame buffer device\n",
1621 fbinfo_crt->node, fbinfo_crt->fix.id);
1622
1623 dev_info(dev, "fb%d: %s frame buffer device\n",
1624 fbinfo_pnl->node, fbinfo_pnl->fix.id);
1625
1626 /* create device files */ 1704 /* create device files */
1627 1705
1628 ret = device_create_file(dev, &dev_attr_crt_src); 1706 ret = device_create_file(dev, &dev_attr_crt_src);
1629 if (ret) 1707 if (ret)
1630 goto crtsrc_fail; 1708 goto err_started_panel;
1631 1709
1632 ret = device_create_file(dev, &dev_attr_fbregs_pnl); 1710 ret = device_create_file(dev, &dev_attr_fbregs_pnl);
1633 if (ret) 1711 if (ret)
1634 goto fbregs_pnl_fail; 1712 goto err_attached_crtsrc_file;
1635 1713
1636 ret = device_create_file(dev, &dev_attr_fbregs_crt); 1714 ret = device_create_file(dev, &dev_attr_fbregs_crt);
1637 if (ret) 1715 if (ret)
1638 goto fbregs_crt_fail; 1716 goto err_attached_pnlregs_file;
1639 1717
1640 /* we registered, return ok */ 1718 /* we registered, return ok */
1641 return 0; 1719 return 0;
1642 1720
1643 fbregs_crt_fail: 1721err_attached_pnlregs_file:
1644 device_remove_file(dev, &dev_attr_fbregs_pnl); 1722 device_remove_file(dev, &dev_attr_fbregs_pnl);
1645 1723
1646 fbregs_pnl_fail: 1724err_attached_crtsrc_file:
1647 device_remove_file(dev, &dev_attr_crt_src); 1725 device_remove_file(dev, &dev_attr_crt_src);
1648 1726
1649 crtsrc_fail: 1727err_started_panel:
1650 unregister_framebuffer(fbinfo_pnl); 1728 unregister_framebuffer(info->fb[HEAD_PANEL]);
1729 sm501_free_init_fb(info, HEAD_PANEL);
1651 1730
1652 register_pnl_fail: 1731err_started_crt:
1653 unregister_framebuffer(fbinfo_crt); 1732 unregister_framebuffer(info->fb[HEAD_CRT]);
1733 sm501_free_init_fb(info, HEAD_CRT);
1654 1734
1655 register_crt_fail: 1735err_started:
1656 sm501fb_stop(info); 1736 sm501fb_stop(info);
1657 1737
1658 sm501fb_start_fail: 1738err_probed_panel:
1659 sm501fb_info_release(info); 1739 framebuffer_release(info->fb[HEAD_PANEL]);
1660 1740
1661 sm501fb_alloc_fail: 1741err_probed_crt:
1662 framebuffer_release(fbinfo_pnl); 1742 framebuffer_release(info->fb[HEAD_CRT]);
1663 1743
1664 fbinfo_crt_alloc_fail: 1744err_alloc:
1665 framebuffer_release(fbinfo_crt); 1745 kfree(info);
1666 1746
1667 return ret; 1747 return ret;
1668} 1748}
@@ -1681,11 +1761,14 @@ static int sm501fb_remove(struct platform_device *pdev)
1681 device_remove_file(&pdev->dev, &dev_attr_fbregs_pnl); 1761 device_remove_file(&pdev->dev, &dev_attr_fbregs_pnl);
1682 device_remove_file(&pdev->dev, &dev_attr_crt_src); 1762 device_remove_file(&pdev->dev, &dev_attr_crt_src);
1683 1763
1764 sm501_free_init_fb(info, HEAD_CRT);
1765 sm501_free_init_fb(info, HEAD_PANEL);
1766
1684 unregister_framebuffer(fbinfo_crt); 1767 unregister_framebuffer(fbinfo_crt);
1685 unregister_framebuffer(fbinfo_pnl); 1768 unregister_framebuffer(fbinfo_pnl);
1686 1769
1687 sm501fb_stop(info); 1770 sm501fb_stop(info);
1688 sm501fb_info_release(info); 1771 kfree(info);
1689 1772
1690 framebuffer_release(fbinfo_pnl); 1773 framebuffer_release(fbinfo_pnl);
1691 framebuffer_release(fbinfo_crt); 1774 framebuffer_release(fbinfo_crt);
diff --git a/drivers/video/sticore.h b/drivers/video/sticore.h
index 1a9a60c74be3..7fe5be4bc70e 100644
--- a/drivers/video/sticore.h
+++ b/drivers/video/sticore.h
@@ -352,8 +352,6 @@ struct sti_struct *sti_get_rom(unsigned int index); /* 0: default sti */
352 352
353/* functions to call the STI ROM directly */ 353/* functions to call the STI ROM directly */
354 354
355int sti_init_graph(struct sti_struct *sti);
356void sti_inq_conf(struct sti_struct *sti);
357void sti_putc(struct sti_struct *sti, int c, int y, int x); 355void sti_putc(struct sti_struct *sti, int c, int y, int x);
358void sti_set(struct sti_struct *sti, int src_y, int src_x, 356void sti_set(struct sti_struct *sti, int src_y, int src_x,
359 int height, int width, u8 color); 357 int height, int width, u8 color);
diff --git a/drivers/video/stifb.c b/drivers/video/stifb.c
index 598d35eff935..166481402412 100644
--- a/drivers/video/stifb.c
+++ b/drivers/video/stifb.c
@@ -1078,8 +1078,7 @@ static struct fb_ops stifb_ops = {
1078 * Initialization 1078 * Initialization
1079 */ 1079 */
1080 1080
1081int __init 1081static int __init stifb_init_fb(struct sti_struct *sti, int bpp_pref)
1082stifb_init_fb(struct sti_struct *sti, int bpp_pref)
1083{ 1082{
1084 struct fb_fix_screeninfo *fix; 1083 struct fb_fix_screeninfo *fix;
1085 struct fb_var_screeninfo *var; 1084 struct fb_var_screeninfo *var;
@@ -1315,8 +1314,7 @@ static int stifb_disabled __initdata;
1315int __init 1314int __init
1316stifb_setup(char *options); 1315stifb_setup(char *options);
1317 1316
1318int __init 1317static int __init stifb_init(void)
1319stifb_init(void)
1320{ 1318{
1321 struct sti_struct *sti; 1319 struct sti_struct *sti;
1322 struct sti_struct *def_sti; 1320 struct sti_struct *def_sti;
diff --git a/drivers/video/tdfxfb.c b/drivers/video/tdfxfb.c
index ea9f19d25597..77aafcfae037 100644
--- a/drivers/video/tdfxfb.c
+++ b/drivers/video/tdfxfb.c
@@ -836,16 +836,12 @@ static int tdfxfb_pan_display(struct fb_var_screeninfo *var,
836 struct tdfx_par *par = info->par; 836 struct tdfx_par *par = info->par;
837 u32 addr = var->yoffset * info->fix.line_length; 837 u32 addr = var->yoffset * info->fix.line_length;
838 838
839 if (nopan || var->xoffset || (var->yoffset > var->yres_virtual)) 839 if (nopan || var->xoffset)
840 return -EINVAL;
841 if ((var->yoffset + var->yres > var->yres_virtual && nowrap))
842 return -EINVAL; 840 return -EINVAL;
843 841
844 banshee_make_room(par, 1); 842 banshee_make_room(par, 1);
845 tdfx_outl(par, VIDDESKSTART, addr); 843 tdfx_outl(par, VIDDESKSTART, addr);
846 844
847 info->var.xoffset = var->xoffset;
848 info->var.yoffset = var->yoffset;
849 return 0; 845 return 0;
850} 846}
851 847
@@ -1426,6 +1422,8 @@ MODULE_LICENSE("GPL");
1426module_param(hwcursor, int, 0644); 1422module_param(hwcursor, int, 0644);
1427MODULE_PARM_DESC(hwcursor, "Enable hardware cursor " 1423MODULE_PARM_DESC(hwcursor, "Enable hardware cursor "
1428 "(1=enable, 0=disable, default=1)"); 1424 "(1=enable, 0=disable, default=1)");
1425module_param(mode_option, charp, 0);
1426MODULE_PARM_DESC(mode_option, "Initial video mode e.g. '648x480-8@60'");
1429#ifdef CONFIG_MTRR 1427#ifdef CONFIG_MTRR
1430module_param(nomtrr, bool, 0); 1428module_param(nomtrr, bool, 0);
1431MODULE_PARM_DESC(nomtrr, "Disable MTRR support (default: enabled)"); 1429MODULE_PARM_DESC(nomtrr, "Disable MTRR support (default: enabled)");
diff --git a/drivers/video/tridentfb.c b/drivers/video/tridentfb.c
index beefab2992c0..479b2e79ad68 100644
--- a/drivers/video/tridentfb.c
+++ b/drivers/video/tridentfb.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * Frame buffer driver for Trident Blade and Image series 2 * Frame buffer driver for Trident TGUI, Blade and Image series
3 * 3 *
4 * Copyright 2001, 2002 - Jani Monoses <jani@iv.ro> 4 * Copyright 2001, 2002 - Jani Monoses <jani@iv.ro>
5 * 5 *
@@ -13,7 +13,6 @@
13 * code, suggestions 13 * code, suggestions
14 * TODO: 14 * TODO:
15 * timing value tweaking so it looks good on every monitor in every mode 15 * timing value tweaking so it looks good on every monitor in every mode
16 * TGUI acceleration
17 */ 16 */
18 17
19#include <linux/module.h> 18#include <linux/module.h>
@@ -22,25 +21,26 @@
22#include <linux/pci.h> 21#include <linux/pci.h>
23 22
24#include <linux/delay.h> 23#include <linux/delay.h>
24#include <video/vga.h>
25#include <video/trident.h> 25#include <video/trident.h>
26 26
27#define VERSION "0.7.8-NEWAPI"
28
29struct tridentfb_par { 27struct tridentfb_par {
30 void __iomem *io_virt; /* iospace virtual memory address */ 28 void __iomem *io_virt; /* iospace virtual memory address */
29 u32 pseudo_pal[16];
30 int chip_id;
31 int flatpanel;
32 void (*init_accel) (struct tridentfb_par *, int, int);
33 void (*wait_engine) (struct tridentfb_par *);
34 void (*fill_rect)
35 (struct tridentfb_par *par, u32, u32, u32, u32, u32, u32);
36 void (*copy_rect)
37 (struct tridentfb_par *par, u32, u32, u32, u32, u32, u32);
38 void (*image_blit)
39 (struct tridentfb_par *par, const char*,
40 u32, u32, u32, u32, u32, u32);
41 unsigned char eng_oper; /* engine operation... */
31}; 42};
32 43
33static unsigned char eng_oper; /* engine operation... */
34static struct fb_ops tridentfb_ops;
35
36static struct tridentfb_par default_par;
37
38/* FIXME:kmalloc these 3 instead */
39static struct fb_info fb_info;
40static u32 pseudo_pal[16];
41
42static struct fb_var_screeninfo default_var;
43
44static struct fb_fix_screeninfo tridentfb_fix = { 44static struct fb_fix_screeninfo tridentfb_fix = {
45 .id = "Trident", 45 .id = "Trident",
46 .type = FB_TYPE_PACKED_PIXELS, 46 .type = FB_TYPE_PACKED_PIXELS,
@@ -49,27 +49,22 @@ static struct fb_fix_screeninfo tridentfb_fix = {
49 .accel = FB_ACCEL_NONE, 49 .accel = FB_ACCEL_NONE,
50}; 50};
51 51
52static int chip_id;
53
54static int defaultaccel;
55static int displaytype;
56
57/* defaults which are normally overriden by user values */ 52/* defaults which are normally overriden by user values */
58 53
59/* video mode */ 54/* video mode */
60static char *mode_option __devinitdata = "640x480"; 55static char *mode_option __devinitdata = "640x480-8@60";
61static int bpp = 8; 56static int bpp __devinitdata = 8;
62 57
63static int noaccel; 58static int noaccel __devinitdata;
64 59
65static int center; 60static int center;
66static int stretch; 61static int stretch;
67 62
68static int fp; 63static int fp __devinitdata;
69static int crt; 64static int crt __devinitdata;
70 65
71static int memsize; 66static int memsize __devinitdata;
72static int memdiff; 67static int memdiff __devinitdata;
73static int nativex; 68static int nativex;
74 69
75module_param(mode_option, charp, 0); 70module_param(mode_option, charp, 0);
@@ -84,25 +79,53 @@ module_param(memsize, int, 0);
84module_param(memdiff, int, 0); 79module_param(memdiff, int, 0);
85module_param(nativex, int, 0); 80module_param(nativex, int, 0);
86module_param(fp, int, 0); 81module_param(fp, int, 0);
82MODULE_PARM_DESC(fp, "Define if flatpanel is connected");
87module_param(crt, int, 0); 83module_param(crt, int, 0);
84MODULE_PARM_DESC(crt, "Define if CRT is connected");
85
86static inline int is_oldclock(int id)
87{
88 return (id == TGUI9440) ||
89 (id == TGUI9660) ||
90 (id == CYBER9320);
91}
92
93static inline int is_oldprotect(int id)
94{
95 return is_oldclock(id) ||
96 (id == PROVIDIA9685) ||
97 (id == CYBER9382) ||
98 (id == CYBER9385);
99}
100
101static inline int is_blade(int id)
102{
103 return (id == BLADE3D) ||
104 (id == CYBERBLADEE4) ||
105 (id == CYBERBLADEi7) ||
106 (id == CYBERBLADEi7D) ||
107 (id == CYBERBLADEi1) ||
108 (id == CYBERBLADEi1D) ||
109 (id == CYBERBLADEAi1) ||
110 (id == CYBERBLADEAi1D);
111}
88 112
89static int chip3D; 113static inline int is_xp(int id)
90static int chipcyber; 114{
115 return (id == CYBERBLADEXPAi1) ||
116 (id == CYBERBLADEXPm8) ||
117 (id == CYBERBLADEXPm16);
118}
91 119
92static int is3Dchip(int id) 120static inline int is3Dchip(int id)
93{ 121{
94 return ((id == BLADE3D) || (id == CYBERBLADEE4) || 122 return is_blade(id) || is_xp(id) ||
95 (id == CYBERBLADEi7) || (id == CYBERBLADEi7D) ||
96 (id == CYBER9397) || (id == CYBER9397DVD) || 123 (id == CYBER9397) || (id == CYBER9397DVD) ||
97 (id == CYBER9520) || (id == CYBER9525DVD) || 124 (id == CYBER9520) || (id == CYBER9525DVD) ||
98 (id == IMAGE975) || (id == IMAGE985) || 125 (id == IMAGE975) || (id == IMAGE985);
99 (id == CYBERBLADEi1) || (id == CYBERBLADEi1D) ||
100 (id == CYBERBLADEAi1) || (id == CYBERBLADEAi1D) ||
101 (id == CYBERBLADEXPm8) || (id == CYBERBLADEXPm16) ||
102 (id == CYBERBLADEXPAi1));
103} 126}
104 127
105static int iscyber(int id) 128static inline int iscyber(int id)
106{ 129{
107 switch (id) { 130 switch (id) {
108 case CYBER9388: 131 case CYBER9388:
@@ -122,12 +145,7 @@ static int iscyber(int id)
122 return 1; 145 return 1;
123 146
124 case CYBER9320: 147 case CYBER9320:
125 case TGUI9660:
126 case IMAGE975:
127 case IMAGE985:
128 case BLADE3D:
129 case CYBERBLADEi7: /* VIA MPV4 integrated version */ 148 case CYBERBLADEi7: /* VIA MPV4 integrated version */
130
131 default: 149 default:
132 /* case CYBERBLDAEXPm8: Strange */ 150 /* case CYBERBLDAEXPm8: Strange */
133 /* case CYBERBLDAEXPm16: Strange */ 151 /* case CYBERBLDAEXPm16: Strange */
@@ -135,147 +153,110 @@ static int iscyber(int id)
135 } 153 }
136} 154}
137 155
138#define CRT 0x3D0 /* CRTC registers offset for color display */ 156static inline void t_outb(struct tridentfb_par *p, u8 val, u16 reg)
139 157{
140#ifndef TRIDENT_MMIO 158 fb_writeb(val, p->io_virt + reg);
141 #define TRIDENT_MMIO 1 159}
142#endif
143
144#if TRIDENT_MMIO
145 #define t_outb(val, reg) writeb(val,((struct tridentfb_par *)(fb_info.par))->io_virt + reg)
146 #define t_inb(reg) readb(((struct tridentfb_par*)(fb_info.par))->io_virt + reg)
147#else
148 #define t_outb(val, reg) outb(val, reg)
149 #define t_inb(reg) inb(reg)
150#endif
151 160
161static inline u8 t_inb(struct tridentfb_par *p, u16 reg)
162{
163 return fb_readb(p->io_virt + reg);
164}
152 165
153static struct accel_switch { 166static inline void writemmr(struct tridentfb_par *par, u16 r, u32 v)
154 void (*init_accel) (int, int); 167{
155 void (*wait_engine) (void); 168 fb_writel(v, par->io_virt + r);
156 void (*fill_rect) (u32, u32, u32, u32, u32, u32); 169}
157 void (*copy_rect) (u32, u32, u32, u32, u32, u32);
158} *acc;
159 170
160#define writemmr(r, v) writel(v, ((struct tridentfb_par *)fb_info.par)->io_virt + r) 171static inline u32 readmmr(struct tridentfb_par *par, u16 r)
161#define readmmr(r) readl(((struct tridentfb_par *)fb_info.par)->io_virt + r) 172{
173 return fb_readl(par->io_virt + r);
174}
162 175
163/* 176/*
164 * Blade specific acceleration. 177 * Blade specific acceleration.
165 */ 178 */
166 179
167#define point(x, y) ((y) << 16 | (x)) 180#define point(x, y) ((y) << 16 | (x))
168#define STA 0x2120 181
169#define CMD 0x2144 182static void blade_init_accel(struct tridentfb_par *par, int pitch, int bpp)
170#define ROP 0x2148
171#define CLR 0x2160
172#define SR1 0x2100
173#define SR2 0x2104
174#define DR1 0x2108
175#define DR2 0x210C
176
177#define ROP_S 0xCC
178
179static void blade_init_accel(int pitch, int bpp)
180{ 183{
181 int v1 = (pitch >> 3) << 20; 184 int v1 = (pitch >> 3) << 20;
182 int tmp = 0, v2; 185 int tmp = bpp == 24 ? 2 : (bpp >> 4);
183 switch (bpp) { 186 int v2 = v1 | (tmp << 29);
184 case 8: 187
185 tmp = 0; 188 writemmr(par, 0x21C0, v2);
186 break; 189 writemmr(par, 0x21C4, v2);
187 case 15: 190 writemmr(par, 0x21B8, v2);
188 tmp = 5; 191 writemmr(par, 0x21BC, v2);
189 break; 192 writemmr(par, 0x21D0, v1);
190 case 16: 193 writemmr(par, 0x21D4, v1);
191 tmp = 1; 194 writemmr(par, 0x21C8, v1);
192 break; 195 writemmr(par, 0x21CC, v1);
193 case 24: 196 writemmr(par, 0x216C, 0);
194 case 32:
195 tmp = 2;
196 break;
197 }
198 v2 = v1 | (tmp << 29);
199 writemmr(0x21C0, v2);
200 writemmr(0x21C4, v2);
201 writemmr(0x21B8, v2);
202 writemmr(0x21BC, v2);
203 writemmr(0x21D0, v1);
204 writemmr(0x21D4, v1);
205 writemmr(0x21C8, v1);
206 writemmr(0x21CC, v1);
207 writemmr(0x216C, 0);
208} 197}
209 198
210static void blade_wait_engine(void) 199static void blade_wait_engine(struct tridentfb_par *par)
211{ 200{
212 while (readmmr(STA) & 0xFA800000) ; 201 while (readmmr(par, STATUS) & 0xFA800000)
202 cpu_relax();
213} 203}
214 204
215static void blade_fill_rect(u32 x, u32 y, u32 w, u32 h, u32 c, u32 rop) 205static void blade_fill_rect(struct tridentfb_par *par,
206 u32 x, u32 y, u32 w, u32 h, u32 c, u32 rop)
216{ 207{
217 writemmr(CLR, c); 208 writemmr(par, COLOR, c);
218 writemmr(ROP, rop ? 0x66 : ROP_S); 209 writemmr(par, ROP, rop ? ROP_X : ROP_S);
219 writemmr(CMD, 0x20000000 | 1 << 19 | 1 << 4 | 2 << 2); 210 writemmr(par, CMD, 0x20000000 | 1 << 19 | 1 << 4 | 2 << 2);
220 211
221 writemmr(DR1, point(x, y)); 212 writemmr(par, DST1, point(x, y));
222 writemmr(DR2, point(x + w - 1, y + h - 1)); 213 writemmr(par, DST2, point(x + w - 1, y + h - 1));
223} 214}
224 215
225static void blade_copy_rect(u32 x1, u32 y1, u32 x2, u32 y2, u32 w, u32 h) 216static void blade_image_blit(struct tridentfb_par *par, const char *data,
217 u32 x, u32 y, u32 w, u32 h, u32 c, u32 b)
218{
219 unsigned size = ((w + 31) >> 5) * h;
220
221 writemmr(par, COLOR, c);
222 writemmr(par, BGCOLOR, b);
223 writemmr(par, CMD, 0xa0000000 | 3 << 19);
224
225 writemmr(par, DST1, point(x, y));
226 writemmr(par, DST2, point(x + w - 1, y + h - 1));
227
228 memcpy(par->io_virt + 0x10000, data, 4 * size);
229}
230
231static void blade_copy_rect(struct tridentfb_par *par,
232 u32 x1, u32 y1, u32 x2, u32 y2, u32 w, u32 h)
226{ 233{
227 u32 s1, s2, d1, d2;
228 int direction = 2; 234 int direction = 2;
229 s1 = point(x1, y1); 235 u32 s1 = point(x1, y1);
230 s2 = point(x1 + w - 1, y1 + h - 1); 236 u32 s2 = point(x1 + w - 1, y1 + h - 1);
231 d1 = point(x2, y2); 237 u32 d1 = point(x2, y2);
232 d2 = point(x2 + w - 1, y2 + h - 1); 238 u32 d2 = point(x2 + w - 1, y2 + h - 1);
233 239
234 if ((y1 > y2) || ((y1 == y2) && (x1 > x2))) 240 if ((y1 > y2) || ((y1 == y2) && (x1 > x2)))
235 direction = 0; 241 direction = 0;
236 242
237 writemmr(ROP, ROP_S); 243 writemmr(par, ROP, ROP_S);
238 writemmr(CMD, 0xE0000000 | 1 << 19 | 1 << 4 | 1 << 2 | direction); 244 writemmr(par, CMD, 0xE0000000 | 1 << 19 | 1 << 4 | 1 << 2 | direction);
239 245
240 writemmr(SR1, direction ? s2 : s1); 246 writemmr(par, SRC1, direction ? s2 : s1);
241 writemmr(SR2, direction ? s1 : s2); 247 writemmr(par, SRC2, direction ? s1 : s2);
242 writemmr(DR1, direction ? d2 : d1); 248 writemmr(par, DST1, direction ? d2 : d1);
243 writemmr(DR2, direction ? d1 : d2); 249 writemmr(par, DST2, direction ? d1 : d2);
244} 250}
245 251
246static struct accel_switch accel_blade = {
247 blade_init_accel,
248 blade_wait_engine,
249 blade_fill_rect,
250 blade_copy_rect,
251};
252
253/* 252/*
254 * BladeXP specific acceleration functions 253 * BladeXP specific acceleration functions
255 */ 254 */
256 255
257#define ROP_P 0xF0 256static void xp_init_accel(struct tridentfb_par *par, int pitch, int bpp)
258#define masked_point(x, y) ((y & 0xffff)<<16|(x & 0xffff))
259
260static void xp_init_accel(int pitch, int bpp)
261{ 257{
262 int tmp = 0, v1; 258 unsigned char x = bpp == 24 ? 3 : (bpp >> 4);
263 unsigned char x = 0; 259 int v1 = pitch << (bpp == 24 ? 20 : (18 + x));
264
265 switch (bpp) {
266 case 8:
267 x = 0;
268 break;
269 case 16:
270 x = 1;
271 break;
272 case 24:
273 x = 3;
274 break;
275 case 32:
276 x = 2;
277 break;
278 }
279 260
280 switch (pitch << (bpp >> 3)) { 261 switch (pitch << (bpp >> 3)) {
281 case 8192: 262 case 8192:
@@ -293,42 +274,21 @@ static void xp_init_accel(int pitch, int bpp)
293 break; 274 break;
294 } 275 }
295 276
296 t_outb(x, 0x2125); 277 t_outb(par, x, 0x2125);
297
298 eng_oper = x | 0x40;
299
300 switch (bpp) {
301 case 8:
302 tmp = 18;
303 break;
304 case 15:
305 case 16:
306 tmp = 19;
307 break;
308 case 24:
309 case 32:
310 tmp = 20;
311 break;
312 }
313 278
314 v1 = pitch << tmp; 279 par->eng_oper = x | 0x40;
315 280
316 writemmr(0x2154, v1); 281 writemmr(par, 0x2154, v1);
317 writemmr(0x2150, v1); 282 writemmr(par, 0x2150, v1);
318 t_outb(3, 0x2126); 283 t_outb(par, 3, 0x2126);
319} 284}
320 285
321static void xp_wait_engine(void) 286static void xp_wait_engine(struct tridentfb_par *par)
322{ 287{
323 int busy; 288 int count = 0;
324 int count, timeout; 289 int timeout = 0;
325 290
326 count = 0; 291 while (t_inb(par, STATUS) & 0x80) {
327 timeout = 0;
328 for (;;) {
329 busy = t_inb(STA) & 0x80;
330 if (busy != 0x80)
331 return;
332 count++; 292 count++;
333 if (count == 10000000) { 293 if (count == 10000000) {
334 /* Timeout */ 294 /* Timeout */
@@ -336,30 +296,31 @@ static void xp_wait_engine(void)
336 timeout++; 296 timeout++;
337 if (timeout == 8) { 297 if (timeout == 8) {
338 /* Reset engine */ 298 /* Reset engine */
339 t_outb(0x00, 0x2120); 299 t_outb(par, 0x00, STATUS);
340 return; 300 return;
341 } 301 }
342 } 302 }
303 cpu_relax();
343 } 304 }
344} 305}
345 306
346static void xp_fill_rect(u32 x, u32 y, u32 w, u32 h, u32 c, u32 rop) 307static void xp_fill_rect(struct tridentfb_par *par,
308 u32 x, u32 y, u32 w, u32 h, u32 c, u32 rop)
347{ 309{
348 writemmr(0x2127, ROP_P); 310 writemmr(par, 0x2127, ROP_P);
349 writemmr(0x2158, c); 311 writemmr(par, 0x2158, c);
350 writemmr(0x2128, 0x4000); 312 writemmr(par, DRAWFL, 0x4000);
351 writemmr(0x2140, masked_point(h, w)); 313 writemmr(par, OLDDIM, point(h, w));
352 writemmr(0x2138, masked_point(y, x)); 314 writemmr(par, OLDDST, point(y, x));
353 t_outb(0x01, 0x2124); 315 t_outb(par, 0x01, OLDCMD);
354 t_outb(eng_oper, 0x2125); 316 t_outb(par, par->eng_oper, 0x2125);
355} 317}
356 318
357static void xp_copy_rect(u32 x1, u32 y1, u32 x2, u32 y2, u32 w, u32 h) 319static void xp_copy_rect(struct tridentfb_par *par,
320 u32 x1, u32 y1, u32 x2, u32 y2, u32 w, u32 h)
358{ 321{
359 int direction;
360 u32 x1_tmp, x2_tmp, y1_tmp, y2_tmp; 322 u32 x1_tmp, x2_tmp, y1_tmp, y2_tmp;
361 323 int direction = 0x0004;
362 direction = 0x0004;
363 324
364 if ((x1 < x2) && (y1 == y2)) { 325 if ((x1 < x2) && (y1 == y2)) {
365 direction |= 0x0200; 326 direction |= 0x0200;
@@ -379,103 +340,152 @@ static void xp_copy_rect(u32 x1, u32 y1, u32 x2, u32 y2, u32 w, u32 h)
379 y2_tmp = y2; 340 y2_tmp = y2;
380 } 341 }
381 342
382 writemmr(0x2128, direction); 343 writemmr(par, DRAWFL, direction);
383 t_outb(ROP_S, 0x2127); 344 t_outb(par, ROP_S, 0x2127);
384 writemmr(0x213C, masked_point(y1_tmp, x1_tmp)); 345 writemmr(par, OLDSRC, point(y1_tmp, x1_tmp));
385 writemmr(0x2138, masked_point(y2_tmp, x2_tmp)); 346 writemmr(par, OLDDST, point(y2_tmp, x2_tmp));
386 writemmr(0x2140, masked_point(h, w)); 347 writemmr(par, OLDDIM, point(h, w));
387 t_outb(0x01, 0x2124); 348 t_outb(par, 0x01, OLDCMD);
388} 349}
389 350
390static struct accel_switch accel_xp = {
391 xp_init_accel,
392 xp_wait_engine,
393 xp_fill_rect,
394 xp_copy_rect,
395};
396
397/* 351/*
398 * Image specific acceleration functions 352 * Image specific acceleration functions
399 */ 353 */
400static void image_init_accel(int pitch, int bpp) 354static void image_init_accel(struct tridentfb_par *par, int pitch, int bpp)
401{ 355{
402 int tmp = 0; 356 int tmp = bpp == 24 ? 2: (bpp >> 4);
403 switch (bpp) { 357
404 case 8: 358 writemmr(par, 0x2120, 0xF0000000);
405 tmp = 0; 359 writemmr(par, 0x2120, 0x40000000 | tmp);
406 break; 360 writemmr(par, 0x2120, 0x80000000);
407 case 15: 361 writemmr(par, 0x2144, 0x00000000);
408 tmp = 5; 362 writemmr(par, 0x2148, 0x00000000);
409 break; 363 writemmr(par, 0x2150, 0x00000000);
410 case 16: 364 writemmr(par, 0x2154, 0x00000000);
411 tmp = 1; 365 writemmr(par, 0x2120, 0x60000000 | (pitch << 16) | pitch);
412 break; 366 writemmr(par, 0x216C, 0x00000000);
413 case 24: 367 writemmr(par, 0x2170, 0x00000000);
414 case 32: 368 writemmr(par, 0x217C, 0x00000000);
415 tmp = 2; 369 writemmr(par, 0x2120, 0x10000000);
416 break; 370 writemmr(par, 0x2130, (2047 << 16) | 2047);
417 }
418 writemmr(0x2120, 0xF0000000);
419 writemmr(0x2120, 0x40000000 | tmp);
420 writemmr(0x2120, 0x80000000);
421 writemmr(0x2144, 0x00000000);
422 writemmr(0x2148, 0x00000000);
423 writemmr(0x2150, 0x00000000);
424 writemmr(0x2154, 0x00000000);
425 writemmr(0x2120, 0x60000000 | (pitch << 16) | pitch);
426 writemmr(0x216C, 0x00000000);
427 writemmr(0x2170, 0x00000000);
428 writemmr(0x217C, 0x00000000);
429 writemmr(0x2120, 0x10000000);
430 writemmr(0x2130, (2047 << 16) | 2047);
431} 371}
432 372
433static void image_wait_engine(void) 373static void image_wait_engine(struct tridentfb_par *par)
434{ 374{
435 while (readmmr(0x2164) & 0xF0000000) ; 375 while (readmmr(par, 0x2164) & 0xF0000000)
376 cpu_relax();
436} 377}
437 378
438static void image_fill_rect(u32 x, u32 y, u32 w, u32 h, u32 c, u32 rop) 379static void image_fill_rect(struct tridentfb_par *par,
380 u32 x, u32 y, u32 w, u32 h, u32 c, u32 rop)
439{ 381{
440 writemmr(0x2120, 0x80000000); 382 writemmr(par, 0x2120, 0x80000000);
441 writemmr(0x2120, 0x90000000 | ROP_S); 383 writemmr(par, 0x2120, 0x90000000 | ROP_S);
442 384
443 writemmr(0x2144, c); 385 writemmr(par, 0x2144, c);
444 386
445 writemmr(DR1, point(x, y)); 387 writemmr(par, DST1, point(x, y));
446 writemmr(DR2, point(x + w - 1, y + h - 1)); 388 writemmr(par, DST2, point(x + w - 1, y + h - 1));
447 389
448 writemmr(0x2124, 0x80000000 | 3 << 22 | 1 << 10 | 1 << 9); 390 writemmr(par, 0x2124, 0x80000000 | 3 << 22 | 1 << 10 | 1 << 9);
449} 391}
450 392
451static void image_copy_rect(u32 x1, u32 y1, u32 x2, u32 y2, u32 w, u32 h) 393static void image_copy_rect(struct tridentfb_par *par,
394 u32 x1, u32 y1, u32 x2, u32 y2, u32 w, u32 h)
452{ 395{
453 u32 s1, s2, d1, d2; 396 int direction = 0x4;
454 int direction = 2; 397 u32 s1 = point(x1, y1);
455 s1 = point(x1, y1); 398 u32 s2 = point(x1 + w - 1, y1 + h - 1);
456 s2 = point(x1 + w - 1, y1 + h - 1); 399 u32 d1 = point(x2, y2);
457 d1 = point(x2, y2); 400 u32 d2 = point(x2 + w - 1, y2 + h - 1);
458 d2 = point(x2 + w - 1, y2 + h - 1);
459 401
460 if ((y1 > y2) || ((y1 == y2) && (x1 > x2))) 402 if ((y1 > y2) || ((y1 == y2) && (x1 > x2)))
461 direction = 0; 403 direction = 0;
462 404
463 writemmr(0x2120, 0x80000000); 405 writemmr(par, 0x2120, 0x80000000);
464 writemmr(0x2120, 0x90000000 | ROP_S); 406 writemmr(par, 0x2120, 0x90000000 | ROP_S);
465 407
466 writemmr(SR1, direction ? s2 : s1); 408 writemmr(par, SRC1, direction ? s2 : s1);
467 writemmr(SR2, direction ? s1 : s2); 409 writemmr(par, SRC2, direction ? s1 : s2);
468 writemmr(DR1, direction ? d2 : d1); 410 writemmr(par, DST1, direction ? d2 : d1);
469 writemmr(DR2, direction ? d1 : d2); 411 writemmr(par, DST2, direction ? d1 : d2);
470 writemmr(0x2124, 0x80000000 | 1 << 22 | 1 << 10 | 1 << 7 | direction); 412 writemmr(par, 0x2124,
413 0x80000000 | 1 << 22 | 1 << 10 | 1 << 7 | direction);
471} 414}
472 415
473static struct accel_switch accel_image = { 416/*
474 image_init_accel, 417 * TGUI 9440/96XX acceleration
475 image_wait_engine, 418 */
476 image_fill_rect, 419
477 image_copy_rect, 420static void tgui_init_accel(struct tridentfb_par *par, int pitch, int bpp)
478}; 421{
422 unsigned char x = bpp == 24 ? 3 : (bpp >> 4);
423
424 /* disable clipping */
425 writemmr(par, 0x2148, 0);
426 writemmr(par, 0x214C, point(4095, 2047));
427
428 switch ((pitch * bpp) / 8) {
429 case 8192:
430 case 512:
431 x |= 0x00;
432 break;
433 case 1024:
434 x |= 0x04;
435 break;
436 case 2048:
437 x |= 0x08;
438 break;
439 case 4096:
440 x |= 0x0C;
441 break;
442 }
443
444 fb_writew(x, par->io_virt + 0x2122);
445}
446
447static void tgui_fill_rect(struct tridentfb_par *par,
448 u32 x, u32 y, u32 w, u32 h, u32 c, u32 rop)
449{
450 t_outb(par, ROP_P, 0x2127);
451 writemmr(par, OLDCLR, c);
452 writemmr(par, DRAWFL, 0x4020);
453 writemmr(par, OLDDIM, point(w - 1, h - 1));
454 writemmr(par, OLDDST, point(x, y));
455 t_outb(par, 1, OLDCMD);
456}
457
458static void tgui_copy_rect(struct tridentfb_par *par,
459 u32 x1, u32 y1, u32 x2, u32 y2, u32 w, u32 h)
460{
461 int flags = 0;
462 u16 x1_tmp, x2_tmp, y1_tmp, y2_tmp;
463
464 if ((x1 < x2) && (y1 == y2)) {
465 flags |= 0x0200;
466 x1_tmp = x1 + w - 1;
467 x2_tmp = x2 + w - 1;
468 } else {
469 x1_tmp = x1;
470 x2_tmp = x2;
471 }
472
473 if (y1 < y2) {
474 flags |= 0x0100;
475 y1_tmp = y1 + h - 1;
476 y2_tmp = y2 + h - 1;
477 } else {
478 y1_tmp = y1;
479 y2_tmp = y2;
480 }
481
482 writemmr(par, DRAWFL, 0x4 | flags);
483 t_outb(par, ROP_S, 0x2127);
484 writemmr(par, OLDSRC, point(x1_tmp, y1_tmp));
485 writemmr(par, OLDDST, point(x2_tmp, y2_tmp));
486 writemmr(par, OLDDIM, point(w - 1, h - 1));
487 t_outb(par, 1, OLDCMD);
488}
479 489
480/* 490/*
481 * Accel functions called by the upper layers 491 * Accel functions called by the upper layers
@@ -484,129 +494,162 @@ static struct accel_switch accel_image = {
484static void tridentfb_fillrect(struct fb_info *info, 494static void tridentfb_fillrect(struct fb_info *info,
485 const struct fb_fillrect *fr) 495 const struct fb_fillrect *fr)
486{ 496{
487 int bpp = info->var.bits_per_pixel; 497 struct tridentfb_par *par = info->par;
488 int col = 0; 498 int col;
489 499
490 switch (bpp) { 500 if (info->flags & FBINFO_HWACCEL_DISABLED) {
491 default: 501 cfb_fillrect(info, fr);
492 case 8: 502 return;
493 col |= fr->color; 503 }
504 if (info->var.bits_per_pixel == 8) {
505 col = fr->color;
494 col |= col << 8; 506 col |= col << 8;
495 col |= col << 16; 507 col |= col << 16;
496 break; 508 } else
497 case 16:
498 col = ((u32 *)(info->pseudo_palette))[fr->color]; 509 col = ((u32 *)(info->pseudo_palette))[fr->color];
499 break; 510
500 case 32: 511 par->wait_engine(par);
501 col = ((u32 *)(info->pseudo_palette))[fr->color]; 512 par->fill_rect(par, fr->dx, fr->dy, fr->width,
502 break; 513 fr->height, col, fr->rop);
514}
515
516static void tridentfb_imageblit(struct fb_info *info,
517 const struct fb_image *img)
518{
519 struct tridentfb_par *par = info->par;
520 int col, bgcol;
521
522 if ((info->flags & FBINFO_HWACCEL_DISABLED) || img->depth != 1) {
523 cfb_imageblit(info, img);
524 return;
525 }
526 if (info->var.bits_per_pixel == 8) {
527 col = img->fg_color;
528 col |= col << 8;
529 col |= col << 16;
530 bgcol = img->bg_color;
531 bgcol |= bgcol << 8;
532 bgcol |= bgcol << 16;
533 } else {
534 col = ((u32 *)(info->pseudo_palette))[img->fg_color];
535 bgcol = ((u32 *)(info->pseudo_palette))[img->bg_color];
503 } 536 }
504 537
505 acc->fill_rect(fr->dx, fr->dy, fr->width, fr->height, col, fr->rop); 538 par->wait_engine(par);
506 acc->wait_engine(); 539 if (par->image_blit)
540 par->image_blit(par, img->data, img->dx, img->dy,
541 img->width, img->height, col, bgcol);
542 else
543 cfb_imageblit(info, img);
507} 544}
545
508static void tridentfb_copyarea(struct fb_info *info, 546static void tridentfb_copyarea(struct fb_info *info,
509 const struct fb_copyarea *ca) 547 const struct fb_copyarea *ca)
510{ 548{
511 acc->copy_rect(ca->sx, ca->sy, ca->dx, ca->dy, ca->width, ca->height); 549 struct tridentfb_par *par = info->par;
512 acc->wait_engine(); 550
551 if (info->flags & FBINFO_HWACCEL_DISABLED) {
552 cfb_copyarea(info, ca);
553 return;
554 }
555 par->wait_engine(par);
556 par->copy_rect(par, ca->sx, ca->sy, ca->dx, ca->dy,
557 ca->width, ca->height);
558}
559
560static int tridentfb_sync(struct fb_info *info)
561{
562 struct tridentfb_par *par = info->par;
563
564 if (!(info->flags & FBINFO_HWACCEL_DISABLED))
565 par->wait_engine(par);
566 return 0;
513} 567}
514#else /* !CONFIG_FB_TRIDENT_ACCEL */ 568#else
515#define tridentfb_fillrect cfb_fillrect 569#define tridentfb_fillrect cfb_fillrect
516#define tridentfb_copyarea cfb_copyarea 570#define tridentfb_copyarea cfb_copyarea
571#define tridentfb_imageblit cfb_imageblit
517#endif /* CONFIG_FB_TRIDENT_ACCEL */ 572#endif /* CONFIG_FB_TRIDENT_ACCEL */
518 573
519
520/* 574/*
521 * Hardware access functions 575 * Hardware access functions
522 */ 576 */
523 577
524static inline unsigned char read3X4(int reg) 578static inline unsigned char read3X4(struct tridentfb_par *par, int reg)
525{ 579{
526 struct tridentfb_par *par = (struct tridentfb_par *)fb_info.par; 580 return vga_mm_rcrt(par->io_virt, reg);
527 writeb(reg, par->io_virt + CRT + 4);
528 return readb(par->io_virt + CRT + 5);
529} 581}
530 582
531static inline void write3X4(int reg, unsigned char val) 583static inline void write3X4(struct tridentfb_par *par, int reg,
584 unsigned char val)
532{ 585{
533 struct tridentfb_par *par = (struct tridentfb_par *)fb_info.par; 586 vga_mm_wcrt(par->io_virt, reg, val);
534 writeb(reg, par->io_virt + CRT + 4);
535 writeb(val, par->io_virt + CRT + 5);
536} 587}
537 588
538static inline unsigned char read3C4(int reg) 589static inline unsigned char read3CE(struct tridentfb_par *par,
590 unsigned char reg)
539{ 591{
540 t_outb(reg, 0x3C4); 592 return vga_mm_rgfx(par->io_virt, reg);
541 return t_inb(0x3C5);
542} 593}
543 594
544static inline void write3C4(int reg, unsigned char val) 595static inline void writeAttr(struct tridentfb_par *par, int reg,
596 unsigned char val)
545{ 597{
546 t_outb(reg, 0x3C4); 598 fb_readb(par->io_virt + VGA_IS1_RC); /* flip-flop to index */
547 t_outb(val, 0x3C5); 599 vga_mm_wattr(par->io_virt, reg, val);
548} 600}
549 601
550static inline unsigned char read3CE(int reg) 602static inline void write3CE(struct tridentfb_par *par, int reg,
603 unsigned char val)
551{ 604{
552 t_outb(reg, 0x3CE); 605 vga_mm_wgfx(par->io_virt, reg, val);
553 return t_inb(0x3CF);
554} 606}
555 607
556static inline void writeAttr(int reg, unsigned char val) 608static void enable_mmio(struct tridentfb_par *par)
557{
558 readb(((struct tridentfb_par *)fb_info.par)->io_virt + CRT + 0x0A); /* flip-flop to index */
559 t_outb(reg, 0x3C0);
560 t_outb(val, 0x3C0);
561}
562
563static inline void write3CE(int reg, unsigned char val)
564{
565 t_outb(reg, 0x3CE);
566 t_outb(val, 0x3CF);
567}
568
569static void enable_mmio(void)
570{ 609{
571 /* Goto New Mode */ 610 /* Goto New Mode */
572 outb(0x0B, 0x3C4); 611 vga_io_rseq(0x0B);
573 inb(0x3C5);
574 612
575 /* Unprotect registers */ 613 /* Unprotect registers */
576 outb(NewMode1, 0x3C4); 614 vga_io_wseq(NewMode1, 0x80);
577 outb(0x80, 0x3C5); 615 if (!is_oldprotect(par->chip_id))
616 vga_io_wseq(Protection, 0x92);
578 617
579 /* Enable MMIO */ 618 /* Enable MMIO */
580 outb(PCIReg, 0x3D4); 619 outb(PCIReg, 0x3D4);
581 outb(inb(0x3D5) | 0x01, 0x3D5); 620 outb(inb(0x3D5) | 0x01, 0x3D5);
582} 621}
583 622
584static void disable_mmio(void) 623static void disable_mmio(struct tridentfb_par *par)
585{ 624{
586 /* Goto New Mode */ 625 /* Goto New Mode */
587 t_outb(0x0B, 0x3C4); 626 vga_mm_rseq(par->io_virt, 0x0B);
588 t_inb(0x3C5);
589 627
590 /* Unprotect registers */ 628 /* Unprotect registers */
591 t_outb(NewMode1, 0x3C4); 629 vga_mm_wseq(par->io_virt, NewMode1, 0x80);
592 t_outb(0x80, 0x3C5); 630 if (!is_oldprotect(par->chip_id))
631 vga_mm_wseq(par->io_virt, Protection, 0x92);
593 632
594 /* Disable MMIO */ 633 /* Disable MMIO */
595 t_outb(PCIReg, 0x3D4); 634 t_outb(par, PCIReg, 0x3D4);
596 t_outb(t_inb(0x3D5) & ~0x01, 0x3D5); 635 t_outb(par, t_inb(par, 0x3D5) & ~0x01, 0x3D5);
597} 636}
598 637
599#define crtc_unlock() write3X4(CRTVSyncEnd, read3X4(CRTVSyncEnd) & 0x7F) 638static inline void crtc_unlock(struct tridentfb_par *par)
639{
640 write3X4(par, VGA_CRTC_V_SYNC_END,
641 read3X4(par, VGA_CRTC_V_SYNC_END) & 0x7F);
642}
600 643
601/* Return flat panel's maximum x resolution */ 644/* Return flat panel's maximum x resolution */
602static int __devinit get_nativex(void) 645static int __devinit get_nativex(struct tridentfb_par *par)
603{ 646{
604 int x, y, tmp; 647 int x, y, tmp;
605 648
606 if (nativex) 649 if (nativex)
607 return nativex; 650 return nativex;
608 651
609 tmp = (read3CE(VertStretch) >> 4) & 3; 652 tmp = (read3CE(par, VertStretch) >> 4) & 3;
610 653
611 switch (tmp) { 654 switch (tmp) {
612 case 0: 655 case 0:
@@ -632,77 +675,92 @@ static int __devinit get_nativex(void)
632} 675}
633 676
634/* Set pitch */ 677/* Set pitch */
635static void set_lwidth(int width) 678static inline void set_lwidth(struct tridentfb_par *par, int width)
636{ 679{
637 write3X4(Offset, width & 0xFF); 680 write3X4(par, VGA_CRTC_OFFSET, width & 0xFF);
638 write3X4(AddColReg, 681 write3X4(par, AddColReg,
639 (read3X4(AddColReg) & 0xCF) | ((width & 0x300) >> 4)); 682 (read3X4(par, AddColReg) & 0xCF) | ((width & 0x300) >> 4));
640} 683}
641 684
642/* For resolutions smaller than FP resolution stretch */ 685/* For resolutions smaller than FP resolution stretch */
643static void screen_stretch(void) 686static void screen_stretch(struct tridentfb_par *par)
644{ 687{
645 if (chip_id != CYBERBLADEXPAi1) 688 if (par->chip_id != CYBERBLADEXPAi1)
646 write3CE(BiosReg, 0); 689 write3CE(par, BiosReg, 0);
647 else 690 else
648 write3CE(BiosReg, 8); 691 write3CE(par, BiosReg, 8);
649 write3CE(VertStretch, (read3CE(VertStretch) & 0x7C) | 1); 692 write3CE(par, VertStretch, (read3CE(par, VertStretch) & 0x7C) | 1);
650 write3CE(HorStretch, (read3CE(HorStretch) & 0x7C) | 1); 693 write3CE(par, HorStretch, (read3CE(par, HorStretch) & 0x7C) | 1);
651} 694}
652 695
653/* For resolutions smaller than FP resolution center */ 696/* For resolutions smaller than FP resolution center */
654static void screen_center(void) 697static inline void screen_center(struct tridentfb_par *par)
655{ 698{
656 write3CE(VertStretch, (read3CE(VertStretch) & 0x7C) | 0x80); 699 write3CE(par, VertStretch, (read3CE(par, VertStretch) & 0x7C) | 0x80);
657 write3CE(HorStretch, (read3CE(HorStretch) & 0x7C) | 0x80); 700 write3CE(par, HorStretch, (read3CE(par, HorStretch) & 0x7C) | 0x80);
658} 701}
659 702
660/* Address of first shown pixel in display memory */ 703/* Address of first shown pixel in display memory */
661static void set_screen_start(int base) 704static void set_screen_start(struct tridentfb_par *par, int base)
662{ 705{
663 write3X4(StartAddrLow, base & 0xFF); 706 u8 tmp;
664 write3X4(StartAddrHigh, (base & 0xFF00) >> 8); 707 write3X4(par, VGA_CRTC_START_LO, base & 0xFF);
665 write3X4(CRTCModuleTest, 708 write3X4(par, VGA_CRTC_START_HI, (base & 0xFF00) >> 8);
666 (read3X4(CRTCModuleTest) & 0xDF) | ((base & 0x10000) >> 11)); 709 tmp = read3X4(par, CRTCModuleTest) & 0xDF;
667 write3X4(CRTHiOrd, 710 write3X4(par, CRTCModuleTest, tmp | ((base & 0x10000) >> 11));
668 (read3X4(CRTHiOrd) & 0xF8) | ((base & 0xE0000) >> 17)); 711 tmp = read3X4(par, CRTHiOrd) & 0xF8;
712 write3X4(par, CRTHiOrd, tmp | ((base & 0xE0000) >> 17));
669} 713}
670 714
671/* Set dotclock frequency */ 715/* Set dotclock frequency */
672static void set_vclk(unsigned long freq) 716static void set_vclk(struct tridentfb_par *par, unsigned long freq)
673{ 717{
674 int m, n, k; 718 int m, n, k;
675 unsigned long f, fi, d, di; 719 unsigned long fi, d, di;
676 unsigned char lo = 0, hi = 0; 720 unsigned char best_m = 0, best_n = 0, best_k = 0;
721 unsigned char hi, lo;
722 unsigned char shift = !is_oldclock(par->chip_id) ? 2 : 1;
677 723
678 d = 20000; 724 d = 20000;
679 for (k = 2; k >= 0; k--) 725 for (k = shift; k >= 0; k--)
680 for (m = 0; m < 63; m++) 726 for (m = 1; m < 32; m++) {
681 for (n = 0; n < 128; n++) { 727 n = ((m + 2) << shift) - 8;
728 for (n = (n < 0 ? 0 : n); n < 122; n++) {
682 fi = ((14318l * (n + 8)) / (m + 2)) >> k; 729 fi = ((14318l * (n + 8)) / (m + 2)) >> k;
683 if ((di = abs(fi - freq)) < d) { 730 di = abs(fi - freq);
731 if (di < d || (di == d && k == best_k)) {
684 d = di; 732 d = di;
685 f = fi; 733 best_n = n;
686 lo = n; 734 best_m = m;
687 hi = (k << 6) | m; 735 best_k = k;
688 } 736 }
689 if (fi > freq) 737 if (fi > freq)
690 break; 738 break;
691 } 739 }
692 if (chip3D) { 740 }
693 write3C4(ClockHigh, hi); 741
694 write3C4(ClockLow, lo); 742 if (is_oldclock(par->chip_id)) {
743 lo = best_n | (best_m << 7);
744 hi = (best_m >> 1) | (best_k << 4);
695 } else { 745 } else {
696 outb(lo, 0x43C8); 746 lo = best_n;
697 outb(hi, 0x43C9); 747 hi = best_m | (best_k << 6);
748 }
749
750 if (is3Dchip(par->chip_id)) {
751 vga_mm_wseq(par->io_virt, ClockHigh, hi);
752 vga_mm_wseq(par->io_virt, ClockLow, lo);
753 } else {
754 t_outb(par, lo, 0x43C8);
755 t_outb(par, hi, 0x43C9);
698 } 756 }
699 debug("VCLK = %X %X\n", hi, lo); 757 debug("VCLK = %X %X\n", hi, lo);
700} 758}
701 759
702/* Set number of lines for flat panels*/ 760/* Set number of lines for flat panels*/
703static void set_number_of_lines(int lines) 761static void set_number_of_lines(struct tridentfb_par *par, int lines)
704{ 762{
705 int tmp = read3CE(CyberEnhance) & 0x8F; 763 int tmp = read3CE(par, CyberEnhance) & 0x8F;
706 if (lines > 1024) 764 if (lines > 1024)
707 tmp |= 0x50; 765 tmp |= 0x50;
708 else if (lines > 768) 766 else if (lines > 768)
@@ -711,24 +769,24 @@ static void set_number_of_lines(int lines)
711 tmp |= 0x20; 769 tmp |= 0x20;
712 else if (lines > 480) 770 else if (lines > 480)
713 tmp |= 0x10; 771 tmp |= 0x10;
714 write3CE(CyberEnhance, tmp); 772 write3CE(par, CyberEnhance, tmp);
715} 773}
716 774
717/* 775/*
718 * If we see that FP is active we assume we have one. 776 * If we see that FP is active we assume we have one.
719 * Otherwise we have a CRT display.User can override. 777 * Otherwise we have a CRT display. User can override.
720 */ 778 */
721static unsigned int __devinit get_displaytype(void) 779static int __devinit is_flatpanel(struct tridentfb_par *par)
722{ 780{
723 if (fp) 781 if (fp)
724 return DISPLAY_FP; 782 return 1;
725 if (crt || !chipcyber) 783 if (crt || !iscyber(par->chip_id))
726 return DISPLAY_CRT; 784 return 0;
727 return (read3CE(FPConfig) & 0x10) ? DISPLAY_FP : DISPLAY_CRT; 785 return (read3CE(par, FPConfig) & 0x10) ? 1 : 0;
728} 786}
729 787
730/* Try detecting the video memory size */ 788/* Try detecting the video memory size */
731static unsigned int __devinit get_memsize(void) 789static unsigned int __devinit get_memsize(struct tridentfb_par *par)
732{ 790{
733 unsigned char tmp, tmp2; 791 unsigned char tmp, tmp2;
734 unsigned int k; 792 unsigned int k;
@@ -737,12 +795,12 @@ static unsigned int __devinit get_memsize(void)
737 if (memsize) 795 if (memsize)
738 k = memsize * Kb; 796 k = memsize * Kb;
739 else 797 else
740 switch (chip_id) { 798 switch (par->chip_id) {
741 case CYBER9525DVD: 799 case CYBER9525DVD:
742 k = 2560 * Kb; 800 k = 2560 * Kb;
743 break; 801 break;
744 default: 802 default:
745 tmp = read3X4(SPR) & 0x0F; 803 tmp = read3X4(par, SPR) & 0x0F;
746 switch (tmp) { 804 switch (tmp) {
747 805
748 case 0x01: 806 case 0x01:
@@ -774,7 +832,7 @@ static unsigned int __devinit get_memsize(void)
774 break; 832 break;
775 case 0x0E: /* XP */ 833 case 0x0E: /* XP */
776 834
777 tmp2 = read3C4(0xC1); 835 tmp2 = vga_mm_rseq(par->io_virt, 0xC1);
778 switch (tmp2) { 836 switch (tmp2) {
779 case 0x00: 837 case 0x00:
780 k = 20 * Mb; 838 k = 20 * Mb;
@@ -812,26 +870,67 @@ static unsigned int __devinit get_memsize(void)
812static int tridentfb_check_var(struct fb_var_screeninfo *var, 870static int tridentfb_check_var(struct fb_var_screeninfo *var,
813 struct fb_info *info) 871 struct fb_info *info)
814{ 872{
873 struct tridentfb_par *par = info->par;
815 int bpp = var->bits_per_pixel; 874 int bpp = var->bits_per_pixel;
875 int line_length;
876 int ramdac = 230000; /* 230MHz for most 3D chips */
816 debug("enter\n"); 877 debug("enter\n");
817 878
818 /* check color depth */ 879 /* check color depth */
819 if (bpp == 24) 880 if (bpp == 24)
820 bpp = var->bits_per_pixel = 32; 881 bpp = var->bits_per_pixel = 32;
882 if (bpp != 8 && bpp != 16 && bpp != 32)
883 return -EINVAL;
884 if (par->chip_id == TGUI9440 && bpp == 32)
885 return -EINVAL;
821 /* check whether resolution fits on panel and in memory */ 886 /* check whether resolution fits on panel and in memory */
822 if (flatpanel && nativex && var->xres > nativex) 887 if (par->flatpanel && nativex && var->xres > nativex)
888 return -EINVAL;
889 /* various resolution checks */
890 var->xres = (var->xres + 7) & ~0x7;
891 if (var->xres > var->xres_virtual)
892 var->xres_virtual = var->xres;
893 if (var->yres > var->yres_virtual)
894 var->yres_virtual = var->yres;
895 if (var->xres_virtual > 4095 || var->yres > 2048)
823 return -EINVAL; 896 return -EINVAL;
824 if (var->xres * var->yres_virtual * bpp / 8 > info->fix.smem_len) 897 /* prevent from position overflow for acceleration */
898 if (var->yres_virtual > 0xffff)
899 return -EINVAL;
900 line_length = var->xres_virtual * bpp / 8;
901
902 if (!is3Dchip(par->chip_id) &&
903 !(info->flags & FBINFO_HWACCEL_DISABLED)) {
904 /* acceleration requires line length to be power of 2 */
905 if (line_length <= 512)
906 var->xres_virtual = 512 * 8 / bpp;
907 else if (line_length <= 1024)
908 var->xres_virtual = 1024 * 8 / bpp;
909 else if (line_length <= 2048)
910 var->xres_virtual = 2048 * 8 / bpp;
911 else if (line_length <= 4096)
912 var->xres_virtual = 4096 * 8 / bpp;
913 else if (line_length <= 8192)
914 var->xres_virtual = 8192 * 8 / bpp;
915 else
916 return -EINVAL;
917
918 line_length = var->xres_virtual * bpp / 8;
919 }
920
921 /* datasheet specifies how to set panning only up to 4 MB */
922 if (line_length * (var->yres_virtual - var->yres) > (4 << 20))
923 var->yres_virtual = ((4 << 20) / line_length) + var->yres;
924
925 if (line_length * var->yres_virtual > info->fix.smem_len)
825 return -EINVAL; 926 return -EINVAL;
826 927
827 switch (bpp) { 928 switch (bpp) {
828 case 8: 929 case 8:
829 var->red.offset = 0; 930 var->red.offset = 0;
830 var->green.offset = 0; 931 var->red.length = 8;
831 var->blue.offset = 0; 932 var->green = var->red;
832 var->red.length = 6; 933 var->blue = var->red;
833 var->green.length = 6;
834 var->blue.length = 6;
835 break; 934 break;
836 case 16: 935 case 16:
837 var->red.offset = 11; 936 var->red.offset = 11;
@@ -852,6 +951,33 @@ static int tridentfb_check_var(struct fb_var_screeninfo *var,
852 default: 951 default:
853 return -EINVAL; 952 return -EINVAL;
854 } 953 }
954
955 if (is_xp(par->chip_id))
956 ramdac = 350000;
957
958 switch (par->chip_id) {
959 case TGUI9440:
960 ramdac = (bpp >= 16) ? 45000 : 90000;
961 break;
962 case CYBER9320:
963 case TGUI9660:
964 ramdac = 135000;
965 break;
966 case PROVIDIA9685:
967 case CYBER9388:
968 case CYBER9382:
969 case CYBER9385:
970 ramdac = 170000;
971 break;
972 }
973
974 /* The clock is doubled for 32 bpp */
975 if (bpp == 32)
976 ramdac /= 2;
977
978 if (PICOS2KHZ(var->pixclock) > ramdac)
979 return -EINVAL;
980
855 debug("exit\n"); 981 debug("exit\n");
856 982
857 return 0; 983 return 0;
@@ -862,25 +988,31 @@ static int tridentfb_check_var(struct fb_var_screeninfo *var,
862static int tridentfb_pan_display(struct fb_var_screeninfo *var, 988static int tridentfb_pan_display(struct fb_var_screeninfo *var,
863 struct fb_info *info) 989 struct fb_info *info)
864{ 990{
991 struct tridentfb_par *par = info->par;
865 unsigned int offset; 992 unsigned int offset;
866 993
867 debug("enter\n"); 994 debug("enter\n");
868 offset = (var->xoffset + (var->yoffset * var->xres)) 995 offset = (var->xoffset + (var->yoffset * var->xres_virtual))
869 * var->bits_per_pixel / 32; 996 * var->bits_per_pixel / 32;
870 info->var.xoffset = var->xoffset; 997 set_screen_start(par, offset);
871 info->var.yoffset = var->yoffset;
872 set_screen_start(offset);
873 debug("exit\n"); 998 debug("exit\n");
874 return 0; 999 return 0;
875} 1000}
876 1001
877#define shadowmode_on() write3CE(CyberControl, read3CE(CyberControl) | 0x81) 1002static inline void shadowmode_on(struct tridentfb_par *par)
878#define shadowmode_off() write3CE(CyberControl, read3CE(CyberControl) & 0x7E) 1003{
1004 write3CE(par, CyberControl, read3CE(par, CyberControl) | 0x81);
1005}
1006
1007static inline void shadowmode_off(struct tridentfb_par *par)
1008{
1009 write3CE(par, CyberControl, read3CE(par, CyberControl) & 0x7E);
1010}
879 1011
880/* Set the hardware to the requested video mode */ 1012/* Set the hardware to the requested video mode */
881static int tridentfb_set_par(struct fb_info *info) 1013static int tridentfb_set_par(struct fb_info *info)
882{ 1014{
883 struct tridentfb_par *par = (struct tridentfb_par *)(info->par); 1015 struct tridentfb_par *par = info->par;
884 u32 htotal, hdispend, hsyncstart, hsyncend, hblankstart, hblankend; 1016 u32 htotal, hdispend, hsyncstart, hsyncend, hblankstart, hblankend;
885 u32 vtotal, vdispend, vsyncstart, vsyncend, vblankstart, vblankend; 1017 u32 vtotal, vdispend, vsyncstart, vsyncend, vblankstart, vblankend;
886 struct fb_var_screeninfo *var = &info->var; 1018 struct fb_var_screeninfo *var = &info->var;
@@ -891,58 +1023,73 @@ static int tridentfb_set_par(struct fb_info *info)
891 debug("enter\n"); 1023 debug("enter\n");
892 hdispend = var->xres / 8 - 1; 1024 hdispend = var->xres / 8 - 1;
893 hsyncstart = (var->xres + var->right_margin) / 8; 1025 hsyncstart = (var->xres + var->right_margin) / 8;
894 hsyncend = var->hsync_len / 8; 1026 hsyncend = (var->xres + var->right_margin + var->hsync_len) / 8;
895 htotal = 1027 htotal = (var->xres + var->left_margin + var->right_margin +
896 (var->xres + var->left_margin + var->right_margin + 1028 var->hsync_len) / 8 - 5;
897 var->hsync_len) / 8 - 10;
898 hblankstart = hdispend + 1; 1029 hblankstart = hdispend + 1;
899 hblankend = htotal + 5; 1030 hblankend = htotal + 3;
900 1031
901 vdispend = var->yres - 1; 1032 vdispend = var->yres - 1;
902 vsyncstart = var->yres + var->lower_margin; 1033 vsyncstart = var->yres + var->lower_margin;
903 vsyncend = var->vsync_len; 1034 vsyncend = vsyncstart + var->vsync_len;
904 vtotal = var->upper_margin + vsyncstart + vsyncend - 2; 1035 vtotal = var->upper_margin + vsyncend - 2;
905 vblankstart = var->yres; 1036 vblankstart = vdispend + 1;
906 vblankend = vtotal + 2; 1037 vblankend = vtotal;
1038
1039 if (info->var.vmode & FB_VMODE_INTERLACED) {
1040 vtotal /= 2;
1041 vdispend /= 2;
1042 vsyncstart /= 2;
1043 vsyncend /= 2;
1044 vblankstart /= 2;
1045 vblankend /= 2;
1046 }
907 1047
908 crtc_unlock(); 1048 enable_mmio(par);
909 write3CE(CyberControl, 8); 1049 crtc_unlock(par);
1050 write3CE(par, CyberControl, 8);
1051 tmp = 0xEB;
1052 if (var->sync & FB_SYNC_HOR_HIGH_ACT)
1053 tmp &= ~0x40;
1054 if (var->sync & FB_SYNC_VERT_HIGH_ACT)
1055 tmp &= ~0x80;
910 1056
911 if (flatpanel && var->xres < nativex) { 1057 if (par->flatpanel && var->xres < nativex) {
912 /* 1058 /*
913 * on flat panels with native size larger 1059 * on flat panels with native size larger
914 * than requested resolution decide whether 1060 * than requested resolution decide whether
915 * we stretch or center 1061 * we stretch or center
916 */ 1062 */
917 t_outb(0xEB, 0x3C2); 1063 t_outb(par, tmp | 0xC0, VGA_MIS_W);
918 1064
919 shadowmode_on(); 1065 shadowmode_on(par);
920 1066
921 if (center) 1067 if (center)
922 screen_center(); 1068 screen_center(par);
923 else if (stretch) 1069 else if (stretch)
924 screen_stretch(); 1070 screen_stretch(par);
925 1071
926 } else { 1072 } else {
927 t_outb(0x2B, 0x3C2); 1073 t_outb(par, tmp, VGA_MIS_W);
928 write3CE(CyberControl, 8); 1074 write3CE(par, CyberControl, 8);
929 } 1075 }
930 1076
931 /* vertical timing values */ 1077 /* vertical timing values */
932 write3X4(CRTVTotal, vtotal & 0xFF); 1078 write3X4(par, VGA_CRTC_V_TOTAL, vtotal & 0xFF);
933 write3X4(CRTVDispEnd, vdispend & 0xFF); 1079 write3X4(par, VGA_CRTC_V_DISP_END, vdispend & 0xFF);
934 write3X4(CRTVSyncStart, vsyncstart & 0xFF); 1080 write3X4(par, VGA_CRTC_V_SYNC_START, vsyncstart & 0xFF);
935 write3X4(CRTVSyncEnd, (vsyncend & 0x0F)); 1081 write3X4(par, VGA_CRTC_V_SYNC_END, (vsyncend & 0x0F));
936 write3X4(CRTVBlankStart, vblankstart & 0xFF); 1082 write3X4(par, VGA_CRTC_V_BLANK_START, vblankstart & 0xFF);
937 write3X4(CRTVBlankEnd, 0 /* p->vblankend & 0xFF */ ); 1083 write3X4(par, VGA_CRTC_V_BLANK_END, vblankend & 0xFF);
938 1084
939 /* horizontal timing values */ 1085 /* horizontal timing values */
940 write3X4(CRTHTotal, htotal & 0xFF); 1086 write3X4(par, VGA_CRTC_H_TOTAL, htotal & 0xFF);
941 write3X4(CRTHDispEnd, hdispend & 0xFF); 1087 write3X4(par, VGA_CRTC_H_DISP, hdispend & 0xFF);
942 write3X4(CRTHSyncStart, hsyncstart & 0xFF); 1088 write3X4(par, VGA_CRTC_H_SYNC_START, hsyncstart & 0xFF);
943 write3X4(CRTHSyncEnd, (hsyncend & 0x1F) | ((hblankend & 0x20) << 2)); 1089 write3X4(par, VGA_CRTC_H_SYNC_END,
944 write3X4(CRTHBlankStart, hblankstart & 0xFF); 1090 (hsyncend & 0x1F) | ((hblankend & 0x20) << 2));
945 write3X4(CRTHBlankEnd, 0 /* (p->hblankend & 0x1F) */ ); 1091 write3X4(par, VGA_CRTC_H_BLANK_START, hblankstart & 0xFF);
1092 write3X4(par, VGA_CRTC_H_BLANK_END, hblankend & 0x1F);
946 1093
947 /* higher bits of vertical timing values */ 1094 /* higher bits of vertical timing values */
948 tmp = 0x10; 1095 tmp = 0x10;
@@ -954,39 +1101,43 @@ static int tridentfb_set_par(struct fb_info *info)
954 if (vtotal & 0x200) tmp |= 0x20; 1101 if (vtotal & 0x200) tmp |= 0x20;
955 if (vdispend & 0x200) tmp |= 0x40; 1102 if (vdispend & 0x200) tmp |= 0x40;
956 if (vsyncstart & 0x200) tmp |= 0x80; 1103 if (vsyncstart & 0x200) tmp |= 0x80;
957 write3X4(CRTOverflow, tmp); 1104 write3X4(par, VGA_CRTC_OVERFLOW, tmp);
958 1105
959 tmp = read3X4(CRTHiOrd) | 0x08; /* line compare bit 10 */ 1106 tmp = read3X4(par, CRTHiOrd) & 0x07;
1107 tmp |= 0x08; /* line compare bit 10 */
960 if (vtotal & 0x400) tmp |= 0x80; 1108 if (vtotal & 0x400) tmp |= 0x80;
961 if (vblankstart & 0x400) tmp |= 0x40; 1109 if (vblankstart & 0x400) tmp |= 0x40;
962 if (vsyncstart & 0x400) tmp |= 0x20; 1110 if (vsyncstart & 0x400) tmp |= 0x20;
963 if (vdispend & 0x400) tmp |= 0x10; 1111 if (vdispend & 0x400) tmp |= 0x10;
964 write3X4(CRTHiOrd, tmp); 1112 write3X4(par, CRTHiOrd, tmp);
965 1113
966 tmp = 0; 1114 tmp = (htotal >> 8) & 0x01;
967 if (htotal & 0x800) tmp |= 0x800 >> 11; 1115 tmp |= (hdispend >> 7) & 0x02;
968 if (hblankstart & 0x800) tmp |= 0x800 >> 7; 1116 tmp |= (hsyncstart >> 5) & 0x08;
969 write3X4(HorizOverflow, tmp); 1117 tmp |= (hblankstart >> 4) & 0x10;
1118 write3X4(par, HorizOverflow, tmp);
970 1119
971 tmp = 0x40; 1120 tmp = 0x40;
972 if (vblankstart & 0x200) tmp |= 0x20; 1121 if (vblankstart & 0x200) tmp |= 0x20;
973//FIXME if (info->var.vmode & FB_VMODE_DOUBLE) tmp |= 0x80; /* double scan for 200 line modes */ 1122//FIXME if (info->var.vmode & FB_VMODE_DOUBLE) tmp |= 0x80; /* double scan for 200 line modes */
974 write3X4(CRTMaxScanLine, tmp); 1123 write3X4(par, VGA_CRTC_MAX_SCAN, tmp);
975 1124
976 write3X4(CRTLineCompare, 0xFF); 1125 write3X4(par, VGA_CRTC_LINE_COMPARE, 0xFF);
977 write3X4(CRTPRowScan, 0); 1126 write3X4(par, VGA_CRTC_PRESET_ROW, 0);
978 write3X4(CRTModeControl, 0xC3); 1127 write3X4(par, VGA_CRTC_MODE, 0xC3);
979 1128
980 write3X4(LinearAddReg, 0x20); /* enable linear addressing */ 1129 write3X4(par, LinearAddReg, 0x20); /* enable linear addressing */
981 1130
982 tmp = (info->var.vmode & FB_VMODE_INTERLACED) ? 0x84 : 0x80; 1131 tmp = (info->var.vmode & FB_VMODE_INTERLACED) ? 0x84 : 0x80;
983 write3X4(CRTCModuleTest, tmp); /* enable access extended memory */ 1132 /* enable access extended memory */
984 1133 write3X4(par, CRTCModuleTest, tmp);
985 write3X4(GraphEngReg, 0x80); /* enable GE for text acceleration */ 1134 tmp = read3CE(par, MiscIntContReg) & ~0x4;
1135 if (info->var.vmode & FB_VMODE_INTERLACED)
1136 tmp |= 0x4;
1137 write3CE(par, MiscIntContReg, tmp);
986 1138
987#ifdef CONFIG_FB_TRIDENT_ACCEL 1139 /* enable GE for text acceleration */
988 acc->init_accel(info->var.xres, bpp); 1140 write3X4(par, GraphEngReg, 0x80);
989#endif
990 1141
991 switch (bpp) { 1142 switch (bpp) {
992 case 8: 1143 case 8:
@@ -1003,57 +1154,59 @@ static int tridentfb_set_par(struct fb_info *info)
1003 break; 1154 break;
1004 } 1155 }
1005 1156
1006 write3X4(PixelBusReg, tmp); 1157 write3X4(par, PixelBusReg, tmp);
1007 1158
1008 tmp = 0x10; 1159 tmp = read3X4(par, DRAMControl);
1009 if (chipcyber) 1160 if (!is_oldprotect(par->chip_id))
1161 tmp |= 0x10;
1162 if (iscyber(par->chip_id))
1010 tmp |= 0x20; 1163 tmp |= 0x20;
1011 write3X4(DRAMControl, tmp); /* both IO, linear enable */ 1164 write3X4(par, DRAMControl, tmp); /* both IO, linear enable */
1012 1165
1013 write3X4(InterfaceSel, read3X4(InterfaceSel) | 0x40); 1166 write3X4(par, InterfaceSel, read3X4(par, InterfaceSel) | 0x40);
1014 write3X4(Performance, 0x92); 1167 if (!is_xp(par->chip_id))
1015 write3X4(PCIReg, 0x07); /* MMIO & PCI read and write burst enable */ 1168 write3X4(par, Performance, read3X4(par, Performance) | 0x10);
1169 /* MMIO & PCI read and write burst enable */
1170 if (par->chip_id != TGUI9440 && par->chip_id != IMAGE975)
1171 write3X4(par, PCIReg, read3X4(par, PCIReg) | 0x06);
1172
1173 vga_mm_wseq(par->io_virt, 0, 3);
1174 vga_mm_wseq(par->io_virt, 1, 1); /* set char clock 8 dots wide */
1175 /* enable 4 maps because needed in chain4 mode */
1176 vga_mm_wseq(par->io_virt, 2, 0x0F);
1177 vga_mm_wseq(par->io_virt, 3, 0);
1178 vga_mm_wseq(par->io_virt, 4, 0x0E); /* memory mode enable bitmaps ?? */
1016 1179
1017 /* convert from picoseconds to kHz */ 1180 /* convert from picoseconds to kHz */
1018 vclk = PICOS2KHZ(info->var.pixclock); 1181 vclk = PICOS2KHZ(info->var.pixclock);
1019 if (bpp == 32) 1182
1183 /* divide clock by 2 if 32bpp chain4 mode display and CPU path */
1184 tmp = read3CE(par, MiscExtFunc) & 0xF0;
1185 if (bpp == 32 || (par->chip_id == TGUI9440 && bpp == 16)) {
1186 tmp |= 8;
1020 vclk *= 2; 1187 vclk *= 2;
1021 set_vclk(vclk);
1022
1023 write3C4(0, 3);
1024 write3C4(1, 1); /* set char clock 8 dots wide */
1025 write3C4(2, 0x0F); /* enable 4 maps because needed in chain4 mode */
1026 write3C4(3, 0);
1027 write3C4(4, 0x0E); /* memory mode enable bitmaps ?? */
1028
1029 write3CE(MiscExtFunc, (bpp == 32) ? 0x1A : 0x12); /* divide clock by 2 if 32bpp */
1030 /* chain4 mode display and CPU path */
1031 write3CE(0x5, 0x40); /* no CGA compat, allow 256 col */
1032 write3CE(0x6, 0x05); /* graphics mode */
1033 write3CE(0x7, 0x0F); /* planes? */
1034
1035 if (chip_id == CYBERBLADEXPAi1) {
1036 /* This fixes snow-effect in 32 bpp */
1037 write3X4(CRTHSyncStart, 0x84);
1038 } 1188 }
1189 set_vclk(par, vclk);
1190 write3CE(par, MiscExtFunc, tmp | 0x12);
1191 write3CE(par, 0x5, 0x40); /* no CGA compat, allow 256 col */
1192 write3CE(par, 0x6, 0x05); /* graphics mode */
1193 write3CE(par, 0x7, 0x0F); /* planes? */
1039 1194
1040 writeAttr(0x10, 0x41); /* graphics mode and support 256 color modes */ 1195 /* graphics mode and support 256 color modes */
1041 writeAttr(0x12, 0x0F); /* planes */ 1196 writeAttr(par, 0x10, 0x41);
1042 writeAttr(0x13, 0); /* horizontal pel panning */ 1197 writeAttr(par, 0x12, 0x0F); /* planes */
1198 writeAttr(par, 0x13, 0); /* horizontal pel panning */
1043 1199
1044 /* colors */ 1200 /* colors */
1045 for (tmp = 0; tmp < 0x10; tmp++) 1201 for (tmp = 0; tmp < 0x10; tmp++)
1046 writeAttr(tmp, tmp); 1202 writeAttr(par, tmp, tmp);
1047 readb(par->io_virt + CRT + 0x0A); /* flip-flop to index */ 1203 fb_readb(par->io_virt + VGA_IS1_RC); /* flip-flop to index */
1048 t_outb(0x20, 0x3C0); /* enable attr */ 1204 t_outb(par, 0x20, VGA_ATT_W); /* enable attr */
1049 1205
1050 switch (bpp) { 1206 switch (bpp) {
1051 case 8: 1207 case 8:
1052 tmp = 0; 1208 tmp = 0;
1053 break; 1209 break;
1054 case 15:
1055 tmp = 0x10;
1056 break;
1057 case 16: 1210 case 16:
1058 tmp = 0x30; 1211 tmp = 0x30;
1059 break; 1212 break;
@@ -1063,19 +1216,23 @@ static int tridentfb_set_par(struct fb_info *info)
1063 break; 1216 break;
1064 } 1217 }
1065 1218
1066 t_inb(0x3C8); 1219 t_inb(par, VGA_PEL_IW);
1067 t_inb(0x3C6); 1220 t_inb(par, VGA_PEL_MSK);
1068 t_inb(0x3C6); 1221 t_inb(par, VGA_PEL_MSK);
1069 t_inb(0x3C6); 1222 t_inb(par, VGA_PEL_MSK);
1070 t_inb(0x3C6); 1223 t_inb(par, VGA_PEL_MSK);
1071 t_outb(tmp, 0x3C6); 1224 t_outb(par, tmp, VGA_PEL_MSK);
1072 t_inb(0x3C8); 1225 t_inb(par, VGA_PEL_IW);
1073 1226
1074 if (flatpanel) 1227 if (par->flatpanel)
1075 set_number_of_lines(info->var.yres); 1228 set_number_of_lines(par, info->var.yres);
1076 set_lwidth(info->var.xres * bpp / (4 * 16)); 1229 info->fix.line_length = info->var.xres_virtual * bpp / 8;
1230 set_lwidth(par, info->fix.line_length / 8);
1231
1232 if (!(info->flags & FBINFO_HWACCEL_DISABLED))
1233 par->init_accel(par, info->var.xres_virtual, bpp);
1234
1077 info->fix.visual = (bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; 1235 info->fix.visual = (bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
1078 info->fix.line_length = info->var.xres * (bpp >> 3);
1079 info->cmap.len = (bpp == 8) ? 256 : 16; 1236 info->cmap.len = (bpp == 8) ? 256 : 16;
1080 debug("exit\n"); 1237 debug("exit\n");
1081 return 0; 1238 return 0;
@@ -1087,17 +1244,18 @@ static int tridentfb_setcolreg(unsigned regno, unsigned red, unsigned green,
1087 struct fb_info *info) 1244 struct fb_info *info)
1088{ 1245{
1089 int bpp = info->var.bits_per_pixel; 1246 int bpp = info->var.bits_per_pixel;
1247 struct tridentfb_par *par = info->par;
1090 1248
1091 if (regno >= info->cmap.len) 1249 if (regno >= info->cmap.len)
1092 return 1; 1250 return 1;
1093 1251
1094 if (bpp == 8) { 1252 if (bpp == 8) {
1095 t_outb(0xFF, 0x3C6); 1253 t_outb(par, 0xFF, VGA_PEL_MSK);
1096 t_outb(regno, 0x3C8); 1254 t_outb(par, regno, VGA_PEL_IW);
1097 1255
1098 t_outb(red >> 10, 0x3C9); 1256 t_outb(par, red >> 10, VGA_PEL_D);
1099 t_outb(green >> 10, 0x3C9); 1257 t_outb(par, green >> 10, VGA_PEL_D);
1100 t_outb(blue >> 10, 0x3C9); 1258 t_outb(par, blue >> 10, VGA_PEL_D);
1101 1259
1102 } else if (regno < 16) { 1260 } else if (regno < 16) {
1103 if (bpp == 16) { /* RGB 565 */ 1261 if (bpp == 16) { /* RGB 565 */
@@ -1108,28 +1266,28 @@ static int tridentfb_setcolreg(unsigned regno, unsigned red, unsigned green,
1108 col |= col << 16; 1266 col |= col << 16;
1109 ((u32 *)(info->pseudo_palette))[regno] = col; 1267 ((u32 *)(info->pseudo_palette))[regno] = col;
1110 } else if (bpp == 32) /* ARGB 8888 */ 1268 } else if (bpp == 32) /* ARGB 8888 */
1111 ((u32*)info->pseudo_palette)[regno] = 1269 ((u32 *)info->pseudo_palette)[regno] =
1112 ((transp & 0xFF00) << 16) | 1270 ((transp & 0xFF00) << 16) |
1113 ((red & 0xFF00) << 8) | 1271 ((red & 0xFF00) << 8) |
1114 ((green & 0xFF00)) | 1272 ((green & 0xFF00)) |
1115 ((blue & 0xFF00) >> 8); 1273 ((blue & 0xFF00) >> 8);
1116 } 1274 }
1117 1275
1118/* debug("exit\n"); */
1119 return 0; 1276 return 0;
1120} 1277}
1121 1278
1122/* Try blanking the screen.For flat panels it does nothing */ 1279/* Try blanking the screen. For flat panels it does nothing */
1123static int tridentfb_blank(int blank_mode, struct fb_info *info) 1280static int tridentfb_blank(int blank_mode, struct fb_info *info)
1124{ 1281{
1125 unsigned char PMCont, DPMSCont; 1282 unsigned char PMCont, DPMSCont;
1283 struct tridentfb_par *par = info->par;
1126 1284
1127 debug("enter\n"); 1285 debug("enter\n");
1128 if (flatpanel) 1286 if (par->flatpanel)
1129 return 0; 1287 return 0;
1130 t_outb(0x04, 0x83C8); /* Read DPMS Control */ 1288 t_outb(par, 0x04, 0x83C8); /* Read DPMS Control */
1131 PMCont = t_inb(0x83C6) & 0xFC; 1289 PMCont = t_inb(par, 0x83C6) & 0xFC;
1132 DPMSCont = read3CE(PowerStatus) & 0xFC; 1290 DPMSCont = read3CE(par, PowerStatus) & 0xFC;
1133 switch (blank_mode) { 1291 switch (blank_mode) {
1134 case FB_BLANK_UNBLANK: 1292 case FB_BLANK_UNBLANK:
1135 /* Screen: On, HSync: On, VSync: On */ 1293 /* Screen: On, HSync: On, VSync: On */
@@ -1155,9 +1313,9 @@ static int tridentfb_blank(int blank_mode, struct fb_info *info)
1155 break; 1313 break;
1156 } 1314 }
1157 1315
1158 write3CE(PowerStatus, DPMSCont); 1316 write3CE(par, PowerStatus, DPMSCont);
1159 t_outb(4, 0x83C8); 1317 t_outb(par, 4, 0x83C8);
1160 t_outb(PMCont, 0x83C6); 1318 t_outb(par, PMCont, 0x83C6);
1161 1319
1162 debug("exit\n"); 1320 debug("exit\n");
1163 1321
@@ -1174,33 +1332,46 @@ static struct fb_ops tridentfb_ops = {
1174 .fb_set_par = tridentfb_set_par, 1332 .fb_set_par = tridentfb_set_par,
1175 .fb_fillrect = tridentfb_fillrect, 1333 .fb_fillrect = tridentfb_fillrect,
1176 .fb_copyarea = tridentfb_copyarea, 1334 .fb_copyarea = tridentfb_copyarea,
1177 .fb_imageblit = cfb_imageblit, 1335 .fb_imageblit = tridentfb_imageblit,
1336#ifdef CONFIG_FB_TRIDENT_ACCEL
1337 .fb_sync = tridentfb_sync,
1338#endif
1178}; 1339};
1179 1340
1180static int __devinit trident_pci_probe(struct pci_dev * dev, 1341static int __devinit trident_pci_probe(struct pci_dev *dev,
1181 const struct pci_device_id * id) 1342 const struct pci_device_id *id)
1182{ 1343{
1183 int err; 1344 int err;
1184 unsigned char revision; 1345 unsigned char revision;
1346 struct fb_info *info;
1347 struct tridentfb_par *default_par;
1348 int chip3D;
1349 int chip_id;
1185 1350
1186 err = pci_enable_device(dev); 1351 err = pci_enable_device(dev);
1187 if (err) 1352 if (err)
1188 return err; 1353 return err;
1189 1354
1190 chip_id = id->device; 1355 info = framebuffer_alloc(sizeof(struct tridentfb_par), &dev->dev);
1356 if (!info)
1357 return -ENOMEM;
1358 default_par = info->par;
1191 1359
1192 if (chip_id == CYBERBLADEi1) 1360 chip_id = id->device;
1193 output("*** Please do use cyblafb, Cyberblade/i1 support "
1194 "will soon be removed from tridentfb!\n");
1195 1361
1362#ifndef CONFIG_FB_TRIDENT_ACCEL
1363 noaccel = 1;
1364#endif
1196 1365
1197 /* If PCI id is 0x9660 then further detect chip type */ 1366 /* If PCI id is 0x9660 then further detect chip type */
1198 1367
1199 if (chip_id == TGUI9660) { 1368 if (chip_id == TGUI9660) {
1200 outb(RevisionID, 0x3C4); 1369 revision = vga_io_rseq(RevisionID);
1201 revision = inb(0x3C5);
1202 1370
1203 switch (revision) { 1371 switch (revision) {
1372 case 0x21:
1373 chip_id = PROVIDIA9685;
1374 break;
1204 case 0x22: 1375 case 0x22:
1205 case 0x23: 1376 case 0x23:
1206 chip_id = CYBER9397; 1377 chip_id = CYBER9397;
@@ -1229,123 +1400,170 @@ static int __devinit trident_pci_probe(struct pci_dev * dev,
1229 } 1400 }
1230 1401
1231 chip3D = is3Dchip(chip_id); 1402 chip3D = is3Dchip(chip_id);
1232 chipcyber = iscyber(chip_id);
1233 1403
1234 if (is_xp(chip_id)) { 1404 if (is_xp(chip_id)) {
1235 acc = &accel_xp; 1405 default_par->init_accel = xp_init_accel;
1406 default_par->wait_engine = xp_wait_engine;
1407 default_par->fill_rect = xp_fill_rect;
1408 default_par->copy_rect = xp_copy_rect;
1409 tridentfb_fix.accel = FB_ACCEL_TRIDENT_BLADEXP;
1236 } else if (is_blade(chip_id)) { 1410 } else if (is_blade(chip_id)) {
1237 acc = &accel_blade; 1411 default_par->init_accel = blade_init_accel;
1238 } else { 1412 default_par->wait_engine = blade_wait_engine;
1239 acc = &accel_image; 1413 default_par->fill_rect = blade_fill_rect;
1414 default_par->copy_rect = blade_copy_rect;
1415 default_par->image_blit = blade_image_blit;
1416 tridentfb_fix.accel = FB_ACCEL_TRIDENT_BLADE3D;
1417 } else if (chip3D) { /* 3DImage family left */
1418 default_par->init_accel = image_init_accel;
1419 default_par->wait_engine = image_wait_engine;
1420 default_par->fill_rect = image_fill_rect;
1421 default_par->copy_rect = image_copy_rect;
1422 tridentfb_fix.accel = FB_ACCEL_TRIDENT_3DIMAGE;
1423 } else { /* TGUI 9440/96XX family */
1424 default_par->init_accel = tgui_init_accel;
1425 default_par->wait_engine = xp_wait_engine;
1426 default_par->fill_rect = tgui_fill_rect;
1427 default_par->copy_rect = tgui_copy_rect;
1428 tridentfb_fix.accel = FB_ACCEL_TRIDENT_TGUI;
1240 } 1429 }
1241 1430
1242 /* acceleration is on by default for 3D chips */ 1431 default_par->chip_id = chip_id;
1243 defaultaccel = chip3D && !noaccel;
1244
1245 fb_info.par = &default_par;
1246 1432
1247 /* setup MMIO region */ 1433 /* setup MMIO region */
1248 tridentfb_fix.mmio_start = pci_resource_start(dev, 1); 1434 tridentfb_fix.mmio_start = pci_resource_start(dev, 1);
1249 tridentfb_fix.mmio_len = chip3D ? 0x20000 : 0x10000; 1435 tridentfb_fix.mmio_len = pci_resource_len(dev, 1);
1250 1436
1251 if (!request_mem_region(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len, "tridentfb")) { 1437 if (!request_mem_region(tridentfb_fix.mmio_start,
1438 tridentfb_fix.mmio_len, "tridentfb")) {
1252 debug("request_region failed!\n"); 1439 debug("request_region failed!\n");
1440 framebuffer_release(info);
1253 return -1; 1441 return -1;
1254 } 1442 }
1255 1443
1256 default_par.io_virt = ioremap_nocache(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len); 1444 default_par->io_virt = ioremap_nocache(tridentfb_fix.mmio_start,
1445 tridentfb_fix.mmio_len);
1257 1446
1258 if (!default_par.io_virt) { 1447 if (!default_par->io_virt) {
1259 debug("ioremap failed\n"); 1448 debug("ioremap failed\n");
1260 err = -1; 1449 err = -1;
1261 goto out_unmap1; 1450 goto out_unmap1;
1262 } 1451 }
1263 1452
1264 enable_mmio(); 1453 enable_mmio(default_par);
1265 1454
1266 /* setup framebuffer memory */ 1455 /* setup framebuffer memory */
1267 tridentfb_fix.smem_start = pci_resource_start(dev, 0); 1456 tridentfb_fix.smem_start = pci_resource_start(dev, 0);
1268 tridentfb_fix.smem_len = get_memsize(); 1457 tridentfb_fix.smem_len = get_memsize(default_par);
1269 1458
1270 if (!request_mem_region(tridentfb_fix.smem_start, tridentfb_fix.smem_len, "tridentfb")) { 1459 if (!request_mem_region(tridentfb_fix.smem_start,
1460 tridentfb_fix.smem_len, "tridentfb")) {
1271 debug("request_mem_region failed!\n"); 1461 debug("request_mem_region failed!\n");
1272 disable_mmio(); 1462 disable_mmio(info->par);
1273 err = -1; 1463 err = -1;
1274 goto out_unmap1; 1464 goto out_unmap1;
1275 } 1465 }
1276 1466
1277 fb_info.screen_base = ioremap_nocache(tridentfb_fix.smem_start, 1467 info->screen_base = ioremap_nocache(tridentfb_fix.smem_start,
1278 tridentfb_fix.smem_len); 1468 tridentfb_fix.smem_len);
1279 1469
1280 if (!fb_info.screen_base) { 1470 if (!info->screen_base) {
1281 debug("ioremap failed\n"); 1471 debug("ioremap failed\n");
1282 err = -1; 1472 err = -1;
1283 goto out_unmap2; 1473 goto out_unmap2;
1284 } 1474 }
1285 1475
1286 output("%s board found\n", pci_name(dev)); 1476 default_par->flatpanel = is_flatpanel(default_par);
1287 displaytype = get_displaytype();
1288 1477
1289 if (flatpanel) 1478 if (default_par->flatpanel)
1290 nativex = get_nativex(); 1479 nativex = get_nativex(default_par);
1291 1480
1292 fb_info.fix = tridentfb_fix; 1481 info->fix = tridentfb_fix;
1293 fb_info.fbops = &tridentfb_ops; 1482 info->fbops = &tridentfb_ops;
1483 info->pseudo_palette = default_par->pseudo_pal;
1294 1484
1485 info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
1486 if (!noaccel && default_par->init_accel) {
1487 info->flags &= ~FBINFO_HWACCEL_DISABLED;
1488 info->flags |= FBINFO_HWACCEL_COPYAREA;
1489 info->flags |= FBINFO_HWACCEL_FILLRECT;
1490 } else
1491 info->flags |= FBINFO_HWACCEL_DISABLED;
1295 1492
1296 fb_info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; 1493 info->pixmap.addr = kmalloc(4096, GFP_KERNEL);
1297#ifdef CONFIG_FB_TRIDENT_ACCEL 1494 if (!info->pixmap.addr) {
1298 fb_info.flags |= FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT; 1495 err = -ENOMEM;
1299#endif 1496 goto out_unmap2;
1300 fb_info.pseudo_palette = pseudo_pal; 1497 }
1498
1499 info->pixmap.size = 4096;
1500 info->pixmap.buf_align = 4;
1501 info->pixmap.scan_align = 1;
1502 info->pixmap.access_align = 32;
1503 info->pixmap.flags = FB_PIXMAP_SYSTEM;
1301 1504
1302 if (!fb_find_mode(&default_var, &fb_info, 1505 if (default_par->image_blit) {
1506 info->flags |= FBINFO_HWACCEL_IMAGEBLIT;
1507 info->pixmap.scan_align = 4;
1508 }
1509
1510 if (noaccel) {
1511 printk(KERN_DEBUG "disabling acceleration\n");
1512 info->flags |= FBINFO_HWACCEL_DISABLED;
1513 info->pixmap.scan_align = 1;
1514 }
1515
1516 if (!fb_find_mode(&info->var, info,
1303 mode_option, NULL, 0, NULL, bpp)) { 1517 mode_option, NULL, 0, NULL, bpp)) {
1304 err = -EINVAL; 1518 err = -EINVAL;
1305 goto out_unmap2; 1519 goto out_unmap2;
1306 } 1520 }
1307 err = fb_alloc_cmap(&fb_info.cmap, 256, 0); 1521 err = fb_alloc_cmap(&info->cmap, 256, 0);
1308 if (err < 0) 1522 if (err < 0)
1309 goto out_unmap2; 1523 goto out_unmap2;
1310 1524
1311 if (defaultaccel && acc) 1525 info->var.activate |= FB_ACTIVATE_NOW;
1312 default_var.accel_flags |= FB_ACCELF_TEXT; 1526 info->device = &dev->dev;
1313 else 1527 if (register_framebuffer(info) < 0) {
1314 default_var.accel_flags &= ~FB_ACCELF_TEXT; 1528 printk(KERN_ERR "tridentfb: could not register framebuffer\n");
1315 default_var.activate |= FB_ACTIVATE_NOW; 1529 fb_dealloc_cmap(&info->cmap);
1316 fb_info.var = default_var;
1317 fb_info.device = &dev->dev;
1318 if (register_framebuffer(&fb_info) < 0) {
1319 printk(KERN_ERR "tridentfb: could not register Trident framebuffer\n");
1320 fb_dealloc_cmap(&fb_info.cmap);
1321 err = -EINVAL; 1530 err = -EINVAL;
1322 goto out_unmap2; 1531 goto out_unmap2;
1323 } 1532 }
1324 output("fb%d: %s frame buffer device %dx%d-%dbpp\n", 1533 output("fb%d: %s frame buffer device %dx%d-%dbpp\n",
1325 fb_info.node, fb_info.fix.id, default_var.xres, 1534 info->node, info->fix.id, info->var.xres,
1326 default_var.yres, default_var.bits_per_pixel); 1535 info->var.yres, info->var.bits_per_pixel);
1536
1537 pci_set_drvdata(dev, info);
1327 return 0; 1538 return 0;
1328 1539
1329out_unmap2: 1540out_unmap2:
1330 if (fb_info.screen_base) 1541 kfree(info->pixmap.addr);
1331 iounmap(fb_info.screen_base); 1542 if (info->screen_base)
1543 iounmap(info->screen_base);
1332 release_mem_region(tridentfb_fix.smem_start, tridentfb_fix.smem_len); 1544 release_mem_region(tridentfb_fix.smem_start, tridentfb_fix.smem_len);
1333 disable_mmio(); 1545 disable_mmio(info->par);
1334out_unmap1: 1546out_unmap1:
1335 if (default_par.io_virt) 1547 if (default_par->io_virt)
1336 iounmap(default_par.io_virt); 1548 iounmap(default_par->io_virt);
1337 release_mem_region(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len); 1549 release_mem_region(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len);
1550 framebuffer_release(info);
1338 return err; 1551 return err;
1339} 1552}
1340 1553
1341static void __devexit trident_pci_remove(struct pci_dev *dev) 1554static void __devexit trident_pci_remove(struct pci_dev *dev)
1342{ 1555{
1343 struct tridentfb_par *par = (struct tridentfb_par*)fb_info.par; 1556 struct fb_info *info = pci_get_drvdata(dev);
1344 unregister_framebuffer(&fb_info); 1557 struct tridentfb_par *par = info->par;
1558
1559 unregister_framebuffer(info);
1345 iounmap(par->io_virt); 1560 iounmap(par->io_virt);
1346 iounmap(fb_info.screen_base); 1561 iounmap(info->screen_base);
1347 release_mem_region(tridentfb_fix.smem_start, tridentfb_fix.smem_len); 1562 release_mem_region(tridentfb_fix.smem_start, tridentfb_fix.smem_len);
1348 release_mem_region(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len); 1563 release_mem_region(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len);
1564 pci_set_drvdata(dev, NULL);
1565 kfree(info->pixmap.addr);
1566 framebuffer_release(info);
1349} 1567}
1350 1568
1351/* List of boards that we are trying to support */ 1569/* List of boards that we are trying to support */
@@ -1358,6 +1576,7 @@ static struct pci_device_id trident_devices[] = {
1358 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEAi1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 1576 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEAi1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1359 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEAi1D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 1577 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEAi1D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1360 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEE4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 1578 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEE4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1579 {PCI_VENDOR_ID_TRIDENT, TGUI9440, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1361 {PCI_VENDOR_ID_TRIDENT, TGUI9660, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 1580 {PCI_VENDOR_ID_TRIDENT, TGUI9660, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1362 {PCI_VENDOR_ID_TRIDENT, IMAGE975, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 1581 {PCI_VENDOR_ID_TRIDENT, IMAGE975, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1363 {PCI_VENDOR_ID_TRIDENT, IMAGE985, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 1582 {PCI_VENDOR_ID_TRIDENT, IMAGE985, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
@@ -1399,9 +1618,9 @@ static int __init tridentfb_setup(char *options)
1399 if (!strncmp(opt, "noaccel", 7)) 1618 if (!strncmp(opt, "noaccel", 7))
1400 noaccel = 1; 1619 noaccel = 1;
1401 else if (!strncmp(opt, "fp", 2)) 1620 else if (!strncmp(opt, "fp", 2))
1402 displaytype = DISPLAY_FP; 1621 fp = 1;
1403 else if (!strncmp(opt, "crt", 3)) 1622 else if (!strncmp(opt, "crt", 3))
1404 displaytype = DISPLAY_CRT; 1623 fp = 0;
1405 else if (!strncmp(opt, "bpp=", 4)) 1624 else if (!strncmp(opt, "bpp=", 4))
1406 bpp = simple_strtoul(opt + 4, NULL, 0); 1625 bpp = simple_strtoul(opt + 4, NULL, 0);
1407 else if (!strncmp(opt, "center", 6)) 1626 else if (!strncmp(opt, "center", 6))
@@ -1430,7 +1649,6 @@ static int __init tridentfb_init(void)
1430 return -ENODEV; 1649 return -ENODEV;
1431 tridentfb_setup(option); 1650 tridentfb_setup(option);
1432#endif 1651#endif
1433 output("Trident framebuffer %s initializing\n", VERSION);
1434 return pci_register_driver(&tridentfb_pci_driver); 1652 return pci_register_driver(&tridentfb_pci_driver);
1435} 1653}
1436 1654
diff --git a/drivers/video/uvesafb.c b/drivers/video/uvesafb.c
index cdbb56edb6cb..50744229c7a9 100644
--- a/drivers/video/uvesafb.c
+++ b/drivers/video/uvesafb.c
@@ -2054,8 +2054,8 @@ MODULE_PARM_DESC(maxhf,
2054module_param(maxvf, ushort, 0); 2054module_param(maxvf, ushort, 0);
2055MODULE_PARM_DESC(maxvf, 2055MODULE_PARM_DESC(maxvf,
2056 "Maximum vertical frequency [Hz], overrides EDID data"); 2056 "Maximum vertical frequency [Hz], overrides EDID data");
2057module_param_named(mode, mode_option, charp, 0); 2057module_param(mode_option, charp, 0);
2058MODULE_PARM_DESC(mode, 2058MODULE_PARM_DESC(mode_option,
2059 "Specify initial video mode as \"<xres>x<yres>[-<bpp>][@<refresh>]\""); 2059 "Specify initial video mode as \"<xres>x<yres>[-<bpp>][@<refresh>]\"");
2060module_param(vbemode, ushort, 0); 2060module_param(vbemode, ushort, 0);
2061MODULE_PARM_DESC(vbemode, 2061MODULE_PARM_DESC(vbemode,
diff --git a/drivers/video/vfb.c b/drivers/video/vfb.c
index 072638a9528a..93fe08d6c78f 100644
--- a/drivers/video/vfb.c
+++ b/drivers/video/vfb.c
@@ -443,19 +443,29 @@ static int vfb_mmap(struct fb_info *info,
443} 443}
444 444
445#ifndef MODULE 445#ifndef MODULE
446/*
447 * The virtual framebuffer driver is only enabled if explicitly
448 * requested by passing 'video=vfb:' (or any actual options).
449 */
446static int __init vfb_setup(char *options) 450static int __init vfb_setup(char *options)
447{ 451{
448 char *this_opt; 452 char *this_opt;
449 453
454 vfb_enable = 0;
455
456 if (!options)
457 return 1;
458
450 vfb_enable = 1; 459 vfb_enable = 1;
451 460
452 if (!options || !*options) 461 if (!*options)
453 return 1; 462 return 1;
454 463
455 while ((this_opt = strsep(&options, ",")) != NULL) { 464 while ((this_opt = strsep(&options, ",")) != NULL) {
456 if (!*this_opt) 465 if (!*this_opt)
457 continue; 466 continue;
458 if (!strncmp(this_opt, "disable", 7)) 467 /* Test disable for backwards compatibility */
468 if (!strcmp(this_opt, "disable"))
459 vfb_enable = 0; 469 vfb_enable = 0;
460 } 470 }
461 return 1; 471 return 1;
diff --git a/drivers/video/vga16fb.c b/drivers/video/vga16fb.c
index 9b3c5923365e..e31bca8a0cb2 100644
--- a/drivers/video/vga16fb.c
+++ b/drivers/video/vga16fb.c
@@ -26,18 +26,6 @@
26#include <asm/io.h> 26#include <asm/io.h>
27#include <video/vga.h> 27#include <video/vga.h>
28 28
29#define GRAPHICS_ADDR_REG VGA_GFX_I /* Graphics address register. */
30#define GRAPHICS_DATA_REG VGA_GFX_D /* Graphics data register. */
31
32#define SET_RESET_INDEX VGA_GFX_SR_VALUE /* Set/Reset Register index. */
33#define ENABLE_SET_RESET_INDEX VGA_GFX_SR_ENABLE /* Enable Set/Reset Register index. */
34#define DATA_ROTATE_INDEX VGA_GFX_DATA_ROTATE /* Data Rotate Register index. */
35#define GRAPHICS_MODE_INDEX VGA_GFX_MODE /* Graphics Mode Register index. */
36#define BIT_MASK_INDEX VGA_GFX_BIT_MASK /* Bit Mask Register index. */
37
38#define dac_reg (VGA_PEL_IW)
39#define dac_val (VGA_PEL_D)
40
41#define VGA_FB_PHYS 0xA0000 29#define VGA_FB_PHYS 0xA0000
42#define VGA_FB_PHYS_LEN 65536 30#define VGA_FB_PHYS_LEN 65536
43 31
@@ -108,7 +96,7 @@ static struct fb_fix_screeninfo vga16fb_fix __initdata = {
108 .visual = FB_VISUAL_PSEUDOCOLOR, 96 .visual = FB_VISUAL_PSEUDOCOLOR,
109 .xpanstep = 8, 97 .xpanstep = 8,
110 .ypanstep = 1, 98 .ypanstep = 1,
111 .line_length = 640/8, 99 .line_length = 640 / 8,
112 .accel = FB_ACCEL_NONE 100 .accel = FB_ACCEL_NONE
113}; 101};
114 102
@@ -135,23 +123,22 @@ static inline int setmode(int mode)
135{ 123{
136 int oldmode; 124 int oldmode;
137 125
138 vga_io_w(GRAPHICS_ADDR_REG, GRAPHICS_MODE_INDEX); 126 oldmode = vga_io_rgfx(VGA_GFX_MODE);
139 oldmode = vga_io_r(GRAPHICS_DATA_REG); 127 vga_io_w(VGA_GFX_D, mode);
140 vga_io_w(GRAPHICS_DATA_REG, mode);
141 return oldmode; 128 return oldmode;
142} 129}
143 130
144/* Select the Bit Mask Register and return its value. */ 131/* Select the Bit Mask Register and return its value. */
145static inline int selectmask(void) 132static inline int selectmask(void)
146{ 133{
147 return vga_io_rgfx(BIT_MASK_INDEX); 134 return vga_io_rgfx(VGA_GFX_BIT_MASK);
148} 135}
149 136
150/* Set the value of the Bit Mask Register. It must already have been 137/* Set the value of the Bit Mask Register. It must already have been
151 selected with selectmask(). */ 138 selected with selectmask(). */
152static inline void setmask(int mask) 139static inline void setmask(int mask)
153{ 140{
154 vga_io_w(GRAPHICS_DATA_REG, mask); 141 vga_io_w(VGA_GFX_D, mask);
155} 142}
156 143
157/* Set the Data Rotate Register and return its old value. 144/* Set the Data Rotate Register and return its old value.
@@ -161,9 +148,8 @@ static inline int setop(int op)
161{ 148{
162 int oldop; 149 int oldop;
163 150
164 vga_io_w(GRAPHICS_ADDR_REG, DATA_ROTATE_INDEX); 151 oldop = vga_io_rgfx(VGA_GFX_DATA_ROTATE);
165 oldop = vga_io_r(GRAPHICS_DATA_REG); 152 vga_io_w(VGA_GFX_D, op);
166 vga_io_w(GRAPHICS_DATA_REG, op);
167 return oldop; 153 return oldop;
168} 154}
169 155
@@ -173,9 +159,8 @@ static inline int setsr(int sr)
173{ 159{
174 int oldsr; 160 int oldsr;
175 161
176 vga_io_w(GRAPHICS_ADDR_REG, ENABLE_SET_RESET_INDEX); 162 oldsr = vga_io_rgfx(VGA_GFX_SR_ENABLE);
177 oldsr = vga_io_r(GRAPHICS_DATA_REG); 163 vga_io_w(VGA_GFX_D, sr);
178 vga_io_w(GRAPHICS_DATA_REG, sr);
179 return oldsr; 164 return oldsr;
180} 165}
181 166
@@ -184,22 +169,21 @@ static inline int setcolor(int color)
184{ 169{
185 int oldcolor; 170 int oldcolor;
186 171
187 vga_io_w(GRAPHICS_ADDR_REG, SET_RESET_INDEX); 172 oldcolor = vga_io_rgfx(VGA_GFX_SR_VALUE);
188 oldcolor = vga_io_r(GRAPHICS_DATA_REG); 173 vga_io_w(VGA_GFX_D, color);
189 vga_io_w(GRAPHICS_DATA_REG, color);
190 return oldcolor; 174 return oldcolor;
191} 175}
192 176
193/* Return the value in the Graphics Address Register. */ 177/* Return the value in the Graphics Address Register. */
194static inline int getindex(void) 178static inline int getindex(void)
195{ 179{
196 return vga_io_r(GRAPHICS_ADDR_REG); 180 return vga_io_r(VGA_GFX_I);
197} 181}
198 182
199/* Set the value in the Graphics Address Register. */ 183/* Set the value in the Graphics Address Register. */
200static inline void setindex(int index) 184static inline void setindex(int index)
201{ 185{
202 vga_io_w(GRAPHICS_ADDR_REG, index); 186 vga_io_w(VGA_GFX_I, index);
203} 187}
204 188
205static void vga16fb_pan_var(struct fb_info *info, 189static void vga16fb_pan_var(struct fb_info *info,
@@ -672,10 +656,10 @@ static void ega16_setpalette(int regno, unsigned red, unsigned green, unsigned b
672 656
673static void vga16_setpalette(int regno, unsigned red, unsigned green, unsigned blue) 657static void vga16_setpalette(int regno, unsigned red, unsigned green, unsigned blue)
674{ 658{
675 outb(regno, dac_reg); 659 outb(regno, VGA_PEL_IW);
676 outb(red >> 10, dac_val); 660 outb(red >> 10, VGA_PEL_D);
677 outb(green >> 10, dac_val); 661 outb(green >> 10, VGA_PEL_D);
678 outb(blue >> 10, dac_val); 662 outb(blue >> 10, VGA_PEL_D);
679} 663}
680 664
681static int vga16fb_setcolreg(unsigned regno, unsigned red, unsigned green, 665static int vga16fb_setcolreg(unsigned regno, unsigned red, unsigned green,
@@ -719,28 +703,15 @@ static int vga16fb_pan_display(struct fb_var_screeninfo *var,
719 blanking code was originally by Huang shi chao, and modified by 703 blanking code was originally by Huang shi chao, and modified by
720 Christoph Rimek (chrimek@toppoint.de) and todd j. derr 704 Christoph Rimek (chrimek@toppoint.de) and todd j. derr
721 (tjd@barefoot.org) for Linux. */ 705 (tjd@barefoot.org) for Linux. */
722#define attrib_port VGA_ATC_IW
723#define seq_port_reg VGA_SEQ_I
724#define seq_port_val VGA_SEQ_D
725#define gr_port_reg VGA_GFX_I
726#define gr_port_val VGA_GFX_D
727#define video_misc_rd VGA_MIS_R
728#define video_misc_wr VGA_MIS_W
729#define vga_video_port_reg VGA_CRT_IC
730#define vga_video_port_val VGA_CRT_DC
731 706
732static void vga_vesa_blank(struct vga16fb_par *par, int mode) 707static void vga_vesa_blank(struct vga16fb_par *par, int mode)
733{ 708{
734 unsigned char SeqCtrlIndex; 709 unsigned char SeqCtrlIndex = vga_io_r(VGA_SEQ_I);
735 unsigned char CrtCtrlIndex; 710 unsigned char CrtCtrlIndex = vga_io_r(VGA_CRT_IC);
736 711
737 //cli();
738 SeqCtrlIndex = vga_io_r(seq_port_reg);
739 CrtCtrlIndex = vga_io_r(vga_video_port_reg);
740
741 /* save original values of VGA controller registers */ 712 /* save original values of VGA controller registers */
742 if(!par->vesa_blanked) { 713 if(!par->vesa_blanked) {
743 par->vga_state.CrtMiscIO = vga_io_r(video_misc_rd); 714 par->vga_state.CrtMiscIO = vga_io_r(VGA_MIS_R);
744 //sti(); 715 //sti();
745 716
746 par->vga_state.HorizontalTotal = vga_io_rcrt(0x00); /* HorizontalTotal */ 717 par->vga_state.HorizontalTotal = vga_io_rcrt(0x00); /* HorizontalTotal */
@@ -756,12 +727,11 @@ static void vga_vesa_blank(struct vga16fb_par *par, int mode)
756 727
757 /* assure that video is enabled */ 728 /* assure that video is enabled */
758 /* "0x20" is VIDEO_ENABLE_bit in register 01 of sequencer */ 729 /* "0x20" is VIDEO_ENABLE_bit in register 01 of sequencer */
759 //cli();
760 vga_io_wseq(0x01, par->vga_state.ClockingMode | 0x20); 730 vga_io_wseq(0x01, par->vga_state.ClockingMode | 0x20);
761 731
762 /* test for vertical retrace in process.... */ 732 /* test for vertical retrace in process.... */
763 if ((par->vga_state.CrtMiscIO & 0x80) == 0x80) 733 if ((par->vga_state.CrtMiscIO & 0x80) == 0x80)
764 vga_io_w(video_misc_wr, par->vga_state.CrtMiscIO & 0xef); 734 vga_io_w(VGA_MIS_W, par->vga_state.CrtMiscIO & 0xef);
765 735
766 /* 736 /*
767 * Set <End of vertical retrace> to minimum (0) and 737 * Set <End of vertical retrace> to minimum (0) and
@@ -769,12 +739,10 @@ static void vga_vesa_blank(struct vga16fb_par *par, int mode)
769 * Result: turn off vertical sync (VSync) pulse. 739 * Result: turn off vertical sync (VSync) pulse.
770 */ 740 */
771 if (mode & FB_BLANK_VSYNC_SUSPEND) { 741 if (mode & FB_BLANK_VSYNC_SUSPEND) {
772 outb_p(0x10,vga_video_port_reg); /* StartVertRetrace */ 742 vga_io_wcrt(VGA_CRTC_V_SYNC_START, 0xff);
773 outb_p(0xff,vga_video_port_val); /* maximum value */ 743 vga_io_wcrt(VGA_CRTC_V_SYNC_END, 0x40);
774 outb_p(0x11,vga_video_port_reg); /* EndVertRetrace */ 744 /* bits 9,10 of vert. retrace */
775 outb_p(0x40,vga_video_port_val); /* minimum (bits 0..3) */ 745 vga_io_wcrt(VGA_CRTC_OVERFLOW, par->vga_state.Overflow | 0x84);
776 outb_p(0x07,vga_video_port_reg); /* Overflow */
777 outb_p(par->vga_state.Overflow | 0x84,vga_video_port_val); /* bits 9,10 of vert. retrace */
778 } 746 }
779 747
780 if (mode & FB_BLANK_HSYNC_SUSPEND) { 748 if (mode & FB_BLANK_HSYNC_SUSPEND) {
@@ -783,29 +751,22 @@ static void vga_vesa_blank(struct vga16fb_par *par, int mode)
783 * <Start of horizontal Retrace> to maximum 751 * <Start of horizontal Retrace> to maximum
784 * Result: turn off horizontal sync (HSync) pulse. 752 * Result: turn off horizontal sync (HSync) pulse.
785 */ 753 */
786 outb_p(0x04,vga_video_port_reg); /* StartHorizRetrace */ 754 vga_io_wcrt(VGA_CRTC_H_SYNC_START, 0xff);
787 outb_p(0xff,vga_video_port_val); /* maximum */ 755 vga_io_wcrt(VGA_CRTC_H_SYNC_END, 0x00);
788 outb_p(0x05,vga_video_port_reg); /* EndHorizRetrace */
789 outb_p(0x00,vga_video_port_val); /* minimum (0) */
790 } 756 }
791 757
792 /* restore both index registers */ 758 /* restore both index registers */
793 outb_p(SeqCtrlIndex,seq_port_reg); 759 outb_p(SeqCtrlIndex, VGA_SEQ_I);
794 outb_p(CrtCtrlIndex,vga_video_port_reg); 760 outb_p(CrtCtrlIndex, VGA_CRT_IC);
795 //sti();
796} 761}
797 762
798static void vga_vesa_unblank(struct vga16fb_par *par) 763static void vga_vesa_unblank(struct vga16fb_par *par)
799{ 764{
800 unsigned char SeqCtrlIndex; 765 unsigned char SeqCtrlIndex = vga_io_r(VGA_SEQ_I);
801 unsigned char CrtCtrlIndex; 766 unsigned char CrtCtrlIndex = vga_io_r(VGA_CRT_IC);
802 767
803 //cli();
804 SeqCtrlIndex = vga_io_r(seq_port_reg);
805 CrtCtrlIndex = vga_io_r(vga_video_port_reg);
806
807 /* restore original values of VGA controller registers */ 768 /* restore original values of VGA controller registers */
808 vga_io_w(video_misc_wr, par->vga_state.CrtMiscIO); 769 vga_io_w(VGA_MIS_W, par->vga_state.CrtMiscIO);
809 770
810 /* HorizontalTotal */ 771 /* HorizontalTotal */
811 vga_io_wcrt(0x00, par->vga_state.HorizontalTotal); 772 vga_io_wcrt(0x00, par->vga_state.HorizontalTotal);
@@ -827,9 +788,8 @@ static void vga_vesa_unblank(struct vga16fb_par *par)
827 vga_io_wseq(0x01, par->vga_state.ClockingMode); 788 vga_io_wseq(0x01, par->vga_state.ClockingMode);
828 789
829 /* restore index/control registers */ 790 /* restore index/control registers */
830 vga_io_w(seq_port_reg, SeqCtrlIndex); 791 vga_io_w(VGA_SEQ_I, SeqCtrlIndex);
831 vga_io_w(vga_video_port_reg, CrtCtrlIndex); 792 vga_io_w(VGA_CRT_IC, CrtCtrlIndex);
832 //sti();
833} 793}
834 794
835static void vga_pal_blank(void) 795static void vga_pal_blank(void)
@@ -837,10 +797,10 @@ static void vga_pal_blank(void)
837 int i; 797 int i;
838 798
839 for (i=0; i<16; i++) { 799 for (i=0; i<16; i++) {
840 outb_p (i, dac_reg) ; 800 outb_p(i, VGA_PEL_IW);
841 outb_p (0, dac_val) ; 801 outb_p(0, VGA_PEL_D);
842 outb_p (0, dac_val) ; 802 outb_p(0, VGA_PEL_D);
843 outb_p (0, dac_val) ; 803 outb_p(0, VGA_PEL_D);
844 } 804 }
845} 805}
846 806
@@ -1087,12 +1047,15 @@ static void vga16fb_copyarea(struct fb_info *info, const struct fb_copyarea *are
1087 width = x2 - dx; 1047 width = x2 - dx;
1088 height = y2 - dy; 1048 height = y2 - dy;
1089 1049
1050 if (sx + dx < old_dx || sy + dy < old_dy)
1051 return;
1052
1090 /* update sx1,sy1 */ 1053 /* update sx1,sy1 */
1091 sx += (dx - old_dx); 1054 sx += (dx - old_dx);
1092 sy += (dy - old_dy); 1055 sy += (dy - old_dy);
1093 1056
1094 /* the source must be completely inside the virtual screen */ 1057 /* the source must be completely inside the virtual screen */
1095 if (sx < 0 || sy < 0 || (sx + width) > vxres || (sy + height) > vyres) 1058 if (sx + width > vxres || sy + height > vyres)
1096 return; 1059 return;
1097 1060
1098 switch (info->fix.type) { 1061 switch (info->fix.type) {
@@ -1482,6 +1445,7 @@ static void __exit vga16fb_exit(void)
1482 platform_driver_unregister(&vga16fb_driver); 1445 platform_driver_unregister(&vga16fb_driver);
1483} 1446}
1484 1447
1448MODULE_DESCRIPTION("Legacy VGA framebuffer device driver");
1485MODULE_LICENSE("GPL"); 1449MODULE_LICENSE("GPL");
1486module_init(vga16fb_init); 1450module_init(vga16fb_init);
1487module_exit(vga16fb_exit); 1451module_exit(vga16fb_exit);