]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/video/s3c2410fb.c
sata_mv: Define module alias for platform device
[linux-2.6-omap-h63xx.git] / drivers / video / s3c2410fb.c
index 09d19633d3bcd8f1d7cfa199b8b2fef03a492d47..71fa6edb5c477d64cd255b9fd866ec9dbe070d28 100644 (file)
@@ -56,7 +56,7 @@
  *     - Add support for different devices
  *     - Backlight support
  *
- * 2004-09-05: Herbert Pötzl <herbert@13thfloor.at>
+ * 2004-09-05: Herbert Pötzl <herbert@13thfloor.at>
  *     - added clock (de-)allocation code
  *     - added fixem fbmem option
  *
@@ -64,7 +64,7 @@
  *     - code cleanup
  *     - added a forgotten return in h1940fb_init
  *
- * 2004-07-19: Herbert Pötzl <herbert@13thfloor.at>
+ * 2004-07-19: Herbert Pötzl <herbert@13thfloor.at>
  *     - code cleanup and extended debugging
  *
  * 2004-07-15: Arnaud Patard <arnaud.patard@rtp-net.org>
@@ -110,6 +110,11 @@ static int debug   = 0;
 
 /* useful functions */
 
+static int is_s3c2412(struct s3c2410fb_info *fbi)
+{
+       return (fbi->drv_type == DRV_S3C2412);
+}
+
 /* s3c2410fb_set_lcdaddr
  *
  * initialise lcd controller address pointers
@@ -172,19 +177,28 @@ static int s3c2410fb_check_var(struct fb_var_screeninfo *var,
        struct s3c2410fb_info *fbi = info->par;
        struct s3c2410fb_mach_info *mach_info = fbi->dev->platform_data;
        struct s3c2410fb_display *display = NULL;
+       struct s3c2410fb_display *default_display = mach_info->displays +
+                                                   mach_info->default_display;
+       int type = default_display->type;
        unsigned i;
 
        dprintk("check_var(var=%p, info=%p)\n", var, info);
 
        /* validate x/y resolution */
-
-       for (i = 0; i < mach_info->num_displays; i++)
-               if (var->yres == mach_info->displays[i].yres &&
-                   var->xres == mach_info->displays[i].xres &&
-                   var->bits_per_pixel == mach_info->displays[i].bpp) {
-                       display = mach_info->displays + i;
-                       break;
-               }
+       /* choose default mode if possible */
+       if (var->yres == default_display->yres &&
+           var->xres == default_display->xres &&
+           var->bits_per_pixel == default_display->bpp)
+               display = default_display;
+       else
+               for (i = 0; i < mach_info->num_displays; i++)
+                       if (type == mach_info->displays[i].type &&
+                           var->yres == mach_info->displays[i].yres &&
+                           var->xres == mach_info->displays[i].xres &&
+                           var->bits_per_pixel == mach_info->displays[i].bpp) {
+                               display = mach_info->displays + i;
+                               break;
+                       }
 
        if (!display) {
                dprintk("wrong resolution or depth %dx%d at %d bpp\n",
@@ -199,6 +213,7 @@ static int s3c2410fb_check_var(struct fb_var_screeninfo *var,
        var->width = display->width;
 
        /* copy lcd settings */
+       var->pixclock = display->pixclock;
        var->left_margin = display->left_margin;
        var->right_margin = display->right_margin;
        var->upper_margin = display->upper_margin;
@@ -206,11 +221,9 @@ static int s3c2410fb_check_var(struct fb_var_screeninfo *var,
        var->vsync_len = display->vsync_len;
        var->hsync_len = display->hsync_len;
 
-       fbi->regs.lcdcon1 = display->lcdcon1;
        fbi->regs.lcdcon5 = display->lcdcon5;
        /* set display type */
-       fbi->regs.lcdcon1 &= ~S3C2410_LCDCON1_TFT;
-       fbi->regs.lcdcon1 |= display->type;
+       fbi->regs.lcdcon1 = display->type;
 
        var->transp.offset = 0;
        var->transp.length = 0;
@@ -297,15 +310,9 @@ static void s3c2410fb_calculate_stn_lcd_regs(const struct fb_info *info,
        unsigned wdly = (var->left_margin >> 4) - 1;
        unsigned wlh = (var->hsync_len >> 4) - 1;
 
-       dprintk("%s: var->xres  = %d\n", __FUNCTION__, var->xres);
-       dprintk("%s: var->yres  = %d\n", __FUNCTION__, var->yres);
-       dprintk("%s: var->bpp   = %d\n", __FUNCTION__, var->bits_per_pixel);
-
        if (type != S3C2410_LCDCON1_STN4)
                hs >>= 1;
 
-       regs->lcdcon1 &= ~S3C2410_LCDCON1_MODEMASK;
-
        switch (var->bits_per_pixel) {
        case 1:
                regs->lcdcon1 |= S3C2410_LCDCON1_STN1BPP;
@@ -359,12 +366,6 @@ static void s3c2410fb_calculate_tft_lcd_regs(const struct fb_info *info,
        const struct s3c2410fb_info *fbi = info->par;
        const struct fb_var_screeninfo *var = &info->var;
 
-       dprintk("%s: var->xres  = %d\n", __FUNCTION__, var->xres);
-       dprintk("%s: var->yres  = %d\n", __FUNCTION__, var->yres);
-       dprintk("%s: var->bpp   = %d\n", __FUNCTION__, var->bits_per_pixel);
-
-       regs->lcdcon1 &= ~S3C2410_LCDCON1_MODEMASK;
-
        switch (var->bits_per_pixel) {
        case 1:
                regs->lcdcon1 |= S3C2410_LCDCON1_TFT1BPP;
@@ -427,28 +428,24 @@ static void s3c2410fb_activate_var(struct fb_info *info)
        void __iomem *regs = fbi->io;
        int type = fbi->regs.lcdcon1 & S3C2410_LCDCON1_TFT;
        struct fb_var_screeninfo *var = &info->var;
+       int clkdiv = s3c2410fb_calc_pixclk(fbi, var->pixclock) / 2;
 
-       if (var->pixclock > 0) {
-               int clkdiv = s3c2410fb_calc_pixclk(fbi, var->pixclock);
-
-               if (type == S3C2410_LCDCON1_TFT) {
-                       clkdiv = (clkdiv / 2) - 1;
-                       if (clkdiv < 0)
-                               clkdiv = 0;
-               } else {
-                       clkdiv = (clkdiv / 2);
-                       if (clkdiv < 2)
-                               clkdiv = 2;
-               }
-
-               fbi->regs.lcdcon1 &= ~S3C2410_LCDCON1_CLKVAL(0x3ff);
-               fbi->regs.lcdcon1 |=  S3C2410_LCDCON1_CLKVAL(clkdiv);
-       }
+       dprintk("%s: var->xres  = %d\n", __FUNCTION__, var->xres);
+       dprintk("%s: var->yres  = %d\n", __FUNCTION__, var->yres);
+       dprintk("%s: var->bpp   = %d\n", __FUNCTION__, var->bits_per_pixel);
 
-       if (type == S3C2410_LCDCON1_TFT)
+       if (type == S3C2410_LCDCON1_TFT) {
                s3c2410fb_calculate_tft_lcd_regs(info, &fbi->regs);
-       else
+               --clkdiv;
+               if (clkdiv < 0)
+                       clkdiv = 0;
+       } else {
                s3c2410fb_calculate_stn_lcd_regs(info, &fbi->regs);
+               if (clkdiv < 2)
+                       clkdiv = 2;
+       }
+
+       fbi->regs.lcdcon1 |=  S3C2410_LCDCON1_CLKVAL(clkdiv);
 
        /* write new registers */
 
@@ -496,7 +493,7 @@ static int s3c2410fb_set_par(struct fb_info *info)
                break;
        }
 
-       info->fix.line_length = (var->width * var->bits_per_pixel) / 8;
+       info->fix.line_length = (var->xres_virtual * var->bits_per_pixel) / 8;
 
        /* activate this new configuration */
 
@@ -509,7 +506,7 @@ static void schedule_palette_update(struct s3c2410fb_info *fbi,
 {
        unsigned long flags;
        unsigned long irqen;
-       void __iomem *regs = fbi->io;
+       void __iomem *irq_base = fbi->irq_base;
 
        local_irq_save(flags);
 
@@ -519,9 +516,9 @@ static void schedule_palette_update(struct s3c2410fb_info *fbi,
                fbi->palette_ready = 1;
 
                /* enable IRQ */
-               irqen = readl(regs + S3C2410_LCDINTMSK);
+               irqen = readl(irq_base + S3C24XX_LCDINTMSK);
                irqen &= ~S3C2410_LCDINT_FRSYNC;
-               writel(irqen, regs + S3C2410_LCDINTMSK);
+               writel(irqen, irq_base + S3C24XX_LCDINTMSK);
        }
 
        local_irq_restore(flags);
@@ -602,15 +599,17 @@ static int s3c2410fb_setcolreg(unsigned regno,
 static int s3c2410fb_blank(int blank_mode, struct fb_info *info)
 {
        struct s3c2410fb_info *fbi = info->par;
-       void __iomem *regs = fbi->io;
+       void __iomem *tpal_reg = fbi->io;
 
        dprintk("blank(mode=%d, info=%p)\n", blank_mode, info);
 
+       tpal_reg += is_s3c2412(fbi) ? S3C2412_TPAL : S3C2410_TPAL;
+
        if (blank_mode == FB_BLANK_UNBLANK)
-               writel(0x0, regs + S3C2410_TPAL);
+               writel(0x0, tpal_reg);
        else {
                dprintk("setting TPAL to output 0x000000\n");
-               writel(S3C2410_TPAL_EN, regs + S3C2410_TPAL);
+               writel(S3C2410_TPAL_EN, tpal_reg);
        }
 
        return 0;
@@ -671,7 +670,7 @@ static int __init s3c2410fb_map_video_memory(struct fb_info *info)
        dma_addr_t map_dma;
        unsigned map_size = PAGE_ALIGN(info->fix.smem_len);
 
-       dprintk("map_video_memory(fbi=%p)\n", fbi);
+       dprintk("map_video_memory(fbi=%p) map_size %u\n", fbi, map_size);
 
        info->screen_base = dma_alloc_writecombine(fbi->dev, map_size,
                                                   &map_dma, GFP_KERNEL);
@@ -680,7 +679,7 @@ static int __init s3c2410fb_map_video_memory(struct fb_info *info)
                /* prevent initial garbage on screen */
                dprintk("map_video_memory: clear %p:%08x\n",
                        info->screen_base, map_size);
-               memset(info->screen_base, 0xf0, map_size);
+               memset(info->screen_base, 0x00, map_size);
 
                info->fix.smem_start = map_dma;
 
@@ -717,6 +716,16 @@ static int s3c2410fb_init_registers(struct fb_info *info)
        struct s3c2410fb_mach_info *mach_info = fbi->dev->platform_data;
        unsigned long flags;
        void __iomem *regs = fbi->io;
+       void __iomem *tpal;
+       void __iomem *lpcsel;
+
+       if (is_s3c2412(fbi)) {
+               tpal = regs + S3C2412_TPAL;
+               lpcsel = regs + S3C2412_TCONSEL;
+       } else {
+               tpal = regs + S3C2410_TPAL;
+               lpcsel = regs + S3C2410_LPCSEL;
+       }
 
        /* Initialise LCD with values from haret */
 
@@ -732,12 +741,12 @@ static int s3c2410fb_init_registers(struct fb_info *info)
        local_irq_restore(flags);
 
        dprintk("LPCSEL    = 0x%08lx\n", mach_info->lpcsel);
-       writel(mach_info->lpcsel, regs + S3C2410_LPCSEL);
+       writel(mach_info->lpcsel, lpcsel);
 
-       dprintk("replacing TPAL %08x\n", readl(regs + S3C2410_TPAL));
+       dprintk("replacing TPAL %08x\n", readl(tpal));
 
        /* ensure temporary palette disabled */
-       writel(0x00, regs + S3C2410_TPAL);
+       writel(0x00, tpal);
 
        return 0;
 }
@@ -771,15 +780,15 @@ static void s3c2410fb_write_palette(struct s3c2410fb_info *fbi)
 static irqreturn_t s3c2410fb_irq(int irq, void *dev_id)
 {
        struct s3c2410fb_info *fbi = dev_id;
-       void __iomem *regs = fbi->io;
-       unsigned long lcdirq = readl(regs + S3C2410_LCDINTPND);
+       void __iomem *irq_base = fbi->irq_base;
+       unsigned long lcdirq = readl(irq_base + S3C24XX_LCDINTPND);
 
        if (lcdirq & S3C2410_LCDINT_FRSYNC) {
                if (fbi->palette_ready)
                        s3c2410fb_write_palette(fbi);
 
-               writel(S3C2410_LCDINT_FRSYNC, regs + S3C2410_LCDINTPND);
-               writel(S3C2410_LCDINT_FRSYNC, regs + S3C2410_LCDSRCPND);
+               writel(S3C2410_LCDINT_FRSYNC, irq_base + S3C24XX_LCDINTPND);
+               writel(S3C2410_LCDINT_FRSYNC, irq_base + S3C24XX_LCDSRCPND);
        }
 
        return IRQ_HANDLED;
@@ -787,7 +796,8 @@ static irqreturn_t s3c2410fb_irq(int irq, void *dev_id)
 
 static char driver_name[] = "s3c2410fb";
 
-static int __init s3c2410fb_probe(struct platform_device *pdev)
+static int __init s3c24xxfb_probe(struct platform_device *pdev,
+                                 enum s3c_drv_type drv_type)
 {
        struct s3c2410fb_info *info;
        struct s3c2410fb_display *display;
@@ -807,6 +817,12 @@ static int __init s3c2410fb_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
+       if (mach_info->default_display >= mach_info->num_displays) {
+               dev_err(&pdev->dev, "default is %d but only %d displays\n",
+                       mach_info->default_display, mach_info->num_displays);
+               return -EINVAL;
+       }
+
        display = mach_info->displays + mach_info->default_display;
 
        irq = platform_get_irq(pdev, 0);
@@ -823,6 +839,7 @@ static int __init s3c2410fb_probe(struct platform_device *pdev)
 
        info = fbinfo->par;
        info->dev = &pdev->dev;
+       info->drv_type = drv_type;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (res == NULL) {
@@ -846,6 +863,8 @@ static int __init s3c2410fb_probe(struct platform_device *pdev)
                goto release_mem;
        }
 
+       info->irq_base = info->io + ((drv_type == DRV_S3C2412) ? S3C2412_LCDINTBASE : S3C2410_LCDINTBASE);
+
        dprintk("devinit\n");
 
        strcpy(fbinfo->fix.id, driver_name);
@@ -954,6 +973,16 @@ dealloc_fb:
        return ret;
 }
 
+static int __init s3c2410fb_probe(struct platform_device *pdev)
+{
+       return s3c24xxfb_probe(pdev, DRV_S3C2410);
+}
+
+static int __init s3c2412fb_probe(struct platform_device *pdev)
+{
+       return s3c24xxfb_probe(pdev, DRV_S3C2412);
+}
+
 /* s3c2410fb_stop_lcd
  *
  * shutdown the lcd controller
@@ -1034,7 +1063,7 @@ static int s3c2410fb_resume(struct platform_device *dev)
        clk_enable(info->clk);
        msleep(1);
 
-       s3c2410fb_init_registers(info);
+       s3c2410fb_init_registers(fbinfo);
 
        return 0;
 }
@@ -1055,14 +1084,31 @@ static struct platform_driver s3c2410fb_driver = {
        },
 };
 
+static struct platform_driver s3c2412fb_driver = {
+       .probe          = s3c2412fb_probe,
+       .remove         = s3c2410fb_remove,
+       .suspend        = s3c2410fb_suspend,
+       .resume         = s3c2410fb_resume,
+       .driver         = {
+               .name   = "s3c2412-lcd",
+               .owner  = THIS_MODULE,
+       },
+};
+
 int __init s3c2410fb_init(void)
 {
-       return platform_driver_register(&s3c2410fb_driver);
+       int ret = platform_driver_register(&s3c2410fb_driver);
+
+       if (ret == 0)
+               ret = platform_driver_register(&s3c2412fb_driver);;
+
+       return ret;
 }
 
 static void __exit s3c2410fb_cleanup(void)
 {
        platform_driver_unregister(&s3c2410fb_driver);
+       platform_driver_unregister(&s3c2412fb_driver);
 }
 
 module_init(s3c2410fb_init);