]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/video/s3c2410fb.c
phy layer: fix phy_mii_ioctl for autonegotiation
[linux-2.6-omap-h63xx.git] / drivers / video / s3c2410fb.c
index 59407343cc731d25322d025e9b7485fb814551d5..8a4c6470d79941ab497f8dcf227af8c19f0a0eb8 100644 (file)
@@ -131,7 +131,7 @@ static void s3c2410fb_set_lcdaddr(struct s3c2410fb_info *fbi)
        saddr2 += (var->xres * var->yres * var->bits_per_pixel)/8;
        saddr2>>= 1;
 
-       saddr3 =  S3C2410_OFFSIZE(0) | S3C2410_PAGEWIDTH(var->xres);
+       saddr3 =  S3C2410_OFFSIZE(0) | S3C2410_PAGEWIDTH((var->xres * var->bits_per_pixel / 16) & 0x3ff);
 
        dprintk("LCDSADDR1 = 0x%08lx\n", saddr1);
        dprintk("LCDSADDR2 = 0x%08lx\n", saddr2);
@@ -199,28 +199,86 @@ static int s3c2410fb_check_var(struct fb_var_screeninfo *var,
                var->bits_per_pixel = fbi->mach_info->bpp.min;
 
        /* set r/g/b positions */
+       switch (var->bits_per_pixel) {
+               case 1:
+               case 2:
+               case 4:
+                       var->red.offset         = 0;
+                       var->red.length         = var->bits_per_pixel;
+                       var->green              = var->red;
+                       var->blue               = var->red;
+                       var->transp.offset      = 0;
+                       var->transp.length      = 0;
+                       break;
+               case 8:
+                       if ( fbi->mach_info->type != S3C2410_LCDCON1_TFT ) {
+                               /* 8 bpp 332 */
+                               var->red.length         = 3;
+                               var->red.offset         = 5;
+                               var->green.length       = 3;
+                               var->green.offset       = 2;
+                               var->blue.length        = 2;
+                               var->blue.offset        = 0;
+                               var->transp.length      = 0;
+                       } else {
+                               var->red.offset         = 0;
+                               var->red.length         = var->bits_per_pixel;
+                               var->green              = var->red;
+                               var->blue               = var->red;
+                               var->transp.offset      = 0;
+                               var->transp.length      = 0;
+                       }
+                       break;
+               case 12:
+                       /* 12 bpp 444 */
+                       var->red.length         = 4;
+                       var->red.offset         = 8;
+                       var->green.length       = 4;
+                       var->green.offset       = 4;
+                       var->blue.length        = 4;
+                       var->blue.offset        = 0;
+                       var->transp.length      = 0;
+                       break;
+
+               default:
+               case 16:
+                       if (fbi->regs.lcdcon5 & S3C2410_LCDCON5_FRM565 ) {
+                               /* 16 bpp, 565 format */
+                               var->red.offset         = 11;
+                               var->green.offset       = 5;
+                               var->blue.offset        = 0;
+                               var->red.length         = 5;
+                               var->green.length       = 6;
+                               var->blue.length        = 5;
+                               var->transp.length      = 0;
+                       } else {
+                               /* 16 bpp, 5551 format */
+                               var->red.offset         = 11;
+                               var->green.offset       = 6;
+                               var->blue.offset        = 1;
+                               var->red.length         = 5;
+                               var->green.length       = 5;
+                               var->blue.length        = 5;
+                               var->transp.length      = 0;
+                       }
+                       break;
+               case 24:
+                       /* 24 bpp 888 */
+                       var->red.length         = 8;
+                       var->red.offset         = 16;
+                       var->green.length       = 8;
+                       var->green.offset       = 8;
+                       var->blue.length        = 8;
+                       var->blue.offset        = 0;
+                       var->transp.length      = 0;
+                       break;
 
-       if (var->bits_per_pixel == 16) {
-               var->red.offset         = 11;
-               var->green.offset       = 5;
-               var->blue.offset        = 0;
-               var->red.length         = 5;
-               var->green.length       = 6;
-               var->blue.length        = 5;
-               var->transp.length      = 0;
-       } else {
-               var->red.length         = var->bits_per_pixel;
-               var->red.offset         = 0;
-               var->green.length       = var->bits_per_pixel;
-               var->green.offset       = 0;
-               var->blue.length        = var->bits_per_pixel;
-               var->blue.offset        = 0;
-               var->transp.length      = 0;
-       }
 
+       }
        return 0;
 }
 
+
 /* s3c2410fb_activate_var
  *
  * activate (set) the controller from the given framebuffer
@@ -230,29 +288,61 @@ static int s3c2410fb_check_var(struct fb_var_screeninfo *var,
 static void s3c2410fb_activate_var(struct s3c2410fb_info *fbi,
                                   struct fb_var_screeninfo *var)
 {
+       int hs;
+
        fbi->regs.lcdcon1 &= ~S3C2410_LCDCON1_MODEMASK;
+       fbi->regs.lcdcon1 &= ~S3C2410_LCDCON1_TFT;
 
        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);
 
-       switch (var->bits_per_pixel) {
-       case 1:
-               fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT1BPP;
-               break;
-       case 2:
-               fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT2BPP;
-               break;
-       case 4:
-               fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT4BPP;
-               break;
-       case 8:
-               fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT8BPP;
-               break;
-       case 16:
-               fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT16BPP;
-               break;
-       }
+       fbi->regs.lcdcon1 |= fbi->mach_info->type;
+
+       if (fbi->mach_info->type == S3C2410_LCDCON1_TFT)
+               switch (var->bits_per_pixel) {
+               case 1:
+                       fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT1BPP;
+                       break;
+               case 2:
+                       fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT2BPP;
+                       break;
+               case 4:
+                       fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT4BPP;
+                       break;
+               case 8:
+                       fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT8BPP;
+                       break;
+               case 16:
+                       fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT16BPP;
+                       break;
+
+               default:
+                       /* invalid pixel depth */
+                       dev_err(fbi->dev, "invalid bpp %d\n", var->bits_per_pixel);
+               }
+       else
+               switch (var->bits_per_pixel) {
+               case 1:
+                       fbi->regs.lcdcon1 |= S3C2410_LCDCON1_STN1BPP;
+                       break;
+               case 2:
+                       fbi->regs.lcdcon1 |= S3C2410_LCDCON1_STN2GREY;
+                       break;
+               case 4:
+                       fbi->regs.lcdcon1 |= S3C2410_LCDCON1_STN4GREY;
+                       break;
+               case 8:
+                       fbi->regs.lcdcon1 |= S3C2410_LCDCON1_STN8BPP;
+                       break;
+               case 12:
+                       fbi->regs.lcdcon1 |= S3C2410_LCDCON1_STN12BPP;
+                       break;
+
+               default:
+                       /* invalid pixel depth */
+                       dev_err(fbi->dev, "invalid bpp %d\n", var->bits_per_pixel);
+               }
 
        /* check to see if we need to update sync/borders */
 
@@ -283,15 +373,44 @@ static void s3c2410fb_activate_var(struct s3c2410fb_info *fbi,
        fbi->regs.lcdcon2 &= ~S3C2410_LCDCON2_LINEVAL(0x3ff);
        fbi->regs.lcdcon2 |=  S3C2410_LCDCON2_LINEVAL(var->yres - 1);
 
+       switch(fbi->mach_info->type) {
+               case S3C2410_LCDCON1_DSCAN4:
+               case S3C2410_LCDCON1_STN8:
+                       hs = var->xres / 8;
+                       break;
+               case S3C2410_LCDCON1_STN4:
+                       hs = var->xres / 4;
+                       break;
+               default:
+               case S3C2410_LCDCON1_TFT:
+                       hs = var->xres;
+                       break;
+
+       }
+
+       /* Special cases : STN color displays */
+       if ( ((fbi->regs.lcdcon1 & S3C2410_LCDCON1_MODEMASK) == S3C2410_LCDCON1_STN8BPP) \
+         || ((fbi->regs.lcdcon1 & S3C2410_LCDCON1_MODEMASK) == S3C2410_LCDCON1_STN12BPP) ) {
+               hs = hs * 3;
+       }
+
+
        fbi->regs.lcdcon3 &= ~S3C2410_LCDCON3_HOZVAL(0x7ff);
-       fbi->regs.lcdcon3 |=  S3C2410_LCDCON3_HOZVAL(var->xres - 1);
+       fbi->regs.lcdcon3 |=  S3C2410_LCDCON3_HOZVAL(hs - 1);
 
        if (var->pixclock > 0) {
                int clkdiv = s3c2410fb_calc_pixclk(fbi, var->pixclock);
 
-               clkdiv = (clkdiv / 2) -1;
-               if (clkdiv < 0)
-                       clkdiv = 0;
+               if (fbi->mach_info->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);
@@ -329,10 +448,18 @@ static int s3c2410fb_set_par(struct fb_info *info)
        struct s3c2410fb_info *fbi = info->par;
        struct fb_var_screeninfo *var = &info->var;
 
-       if (var->bits_per_pixel == 16)
-               fbi->fb->fix.visual = FB_VISUAL_TRUECOLOR;
-       else
-               fbi->fb->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+       switch (var->bits_per_pixel)
+       {
+               case 16:
+                       fbi->fb->fix.visual = FB_VISUAL_TRUECOLOR;
+                       break;
+               case 1:
+                        fbi->fb->fix.visual = FB_VISUAL_MONO01;
+                        break;
+               default:
+                        fbi->fb->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+                        break;
+       }
 
        fbi->fb->fix.line_length     = (var->width*var->bits_per_pixel)/8;
 
@@ -347,6 +474,7 @@ static void schedule_palette_update(struct s3c2410fb_info *fbi,
 {
        unsigned long flags;
        unsigned long irqen;
+       void __iomem *regs = fbi->io;
 
        local_irq_save(flags);
 
@@ -356,9 +484,9 @@ static void schedule_palette_update(struct s3c2410fb_info *fbi,
                fbi->palette_ready = 1;
 
                /* enable IRQ */
-               irqen = readl(S3C2410_LCDINTMSK);
+               irqen = readl(regs + S3C2410_LCDINTMSK);
                irqen &= ~S3C2410_LCDINT_FRSYNC;
-               writel(irqen, S3C2410_LCDINTMSK);
+               writel(irqen, regs + S3C2410_LCDINTMSK);
        }
 
        local_irq_restore(flags);
@@ -553,6 +681,7 @@ static inline void modify_gpio(void __iomem *reg,
 static int s3c2410fb_init_registers(struct s3c2410fb_info *fbi)
 {
        unsigned long flags;
+       void __iomem *regs = fbi->io;
 
        /* Initialise LCD with values from haret */
 
@@ -567,25 +696,25 @@ static int s3c2410fb_init_registers(struct s3c2410fb_info *fbi)
 
        local_irq_restore(flags);
 
-       writel(fbi->regs.lcdcon1, S3C2410_LCDCON1);
-       writel(fbi->regs.lcdcon2, S3C2410_LCDCON2);
-       writel(fbi->regs.lcdcon3, S3C2410_LCDCON3);
-       writel(fbi->regs.lcdcon4, S3C2410_LCDCON4);
-       writel(fbi->regs.lcdcon5, S3C2410_LCDCON5);
+       writel(fbi->regs.lcdcon1, regs + S3C2410_LCDCON1);
+       writel(fbi->regs.lcdcon2, regs + S3C2410_LCDCON2);
+       writel(fbi->regs.lcdcon3, regs + S3C2410_LCDCON3);
+       writel(fbi->regs.lcdcon4, regs + S3C2410_LCDCON4);
+       writel(fbi->regs.lcdcon5, regs + S3C2410_LCDCON5);
 
        s3c2410fb_set_lcdaddr(fbi);
 
        dprintk("LPCSEL    = 0x%08lx\n", mach_info->lpcsel);
-       writel(mach_info->lpcsel, S3C2410_LPCSEL);
+       writel(mach_info->lpcsel, regs + S3C2410_LPCSEL);
 
-       dprintk("replacing TPAL %08x\n", readl(S3C2410_TPAL));
+       dprintk("replacing TPAL %08x\n", readl(regs + S3C2410_TPAL));
 
        /* ensure temporary palette disabled */
-       writel(0x00, S3C2410_TPAL);
+       writel(0x00, regs + S3C2410_TPAL);
 
        /* Enable video by setting the ENVID bit to 1 */
        fbi->regs.lcdcon1 |= S3C2410_LCDCON1_ENVID;
-       writel(fbi->regs.lcdcon1, S3C2410_LCDCON1);
+       writel(fbi->regs.lcdcon1, regs + S3C2410_LCDCON1);
        return 0;
 }
 
@@ -593,6 +722,7 @@ static void s3c2410fb_write_palette(struct s3c2410fb_info *fbi)
 {
        unsigned int i;
        unsigned long ent;
+       void __iomem *regs = fbi->io;
 
        fbi->palette_ready = 0;
 
@@ -600,14 +730,14 @@ static void s3c2410fb_write_palette(struct s3c2410fb_info *fbi)
                if ((ent = fbi->palette_buffer[i]) == PALETTE_BUFF_CLEAR)
                        continue;
 
-               writel(ent, S3C2410_TFTPAL(i));
+               writel(ent, regs + S3C2410_TFTPAL(i));
 
                /* it seems the only way to know exactly
                 * if the palette wrote ok, is to check
                 * to see if the value verifies ok
                 */
 
-               if (readw(S3C2410_TFTPAL(i)) == ent)
+               if (readw(regs + S3C2410_TFTPAL(i)) == ent)
                        fbi->palette_buffer[i] = PALETTE_BUFF_CLEAR;
                else
                        fbi->palette_ready = 1;   /* retry */
@@ -617,14 +747,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;
-       unsigned long lcdirq = readl(S3C2410_LCDINTPND);
+       void __iomem *regs = fbi->io;
+       unsigned long lcdirq = readl(regs + S3C2410_LCDINTPND);
 
        if (lcdirq & S3C2410_LCDINT_FRSYNC) {
                if (fbi->palette_ready)
                        s3c2410fb_write_palette(fbi);
 
-               writel(S3C2410_LCDINT_FRSYNC, S3C2410_LCDINTPND);
-               writel(S3C2410_LCDINT_FRSYNC, S3C2410_LCDSRCPND);
+               writel(S3C2410_LCDINT_FRSYNC, regs + S3C2410_LCDINTPND);
+               writel(S3C2410_LCDINT_FRSYNC, regs + S3C2410_LCDSRCPND);
        }
 
        return IRQ_HANDLED;
@@ -637,9 +768,11 @@ static int __init s3c2410fb_probe(struct platform_device *pdev)
        struct s3c2410fb_info *info;
        struct fb_info     *fbinfo;
        struct s3c2410fb_hw *mregs;
+       struct resource *res;
        int ret;
        int irq;
        int i;
+       int size;
        u32 lcdcon1;
 
        mach_info = pdev->dev.platform_data;
@@ -661,9 +794,32 @@ static int __init s3c2410fb_probe(struct platform_device *pdev)
                return -ENOMEM;
        }
 
-
        info = fbinfo->par;
        info->fb = fbinfo;
+       info->dev = &pdev->dev;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (res == NULL) {
+               dev_err(&pdev->dev, "failed to get memory registersn");
+               ret = -ENXIO;
+               goto dealloc_fb;
+       }
+
+       size = (res->end - res->start)+1;
+       info->mem = request_mem_region(res->start, size, pdev->name);
+       if (info->mem == NULL) {
+               dev_err(&pdev->dev, "failed to get memory region\n");
+               ret = -ENOENT;
+               goto dealloc_fb;
+       }
+
+       info->io = ioremap(res->start, size);
+       if (info->io == NULL) {
+               dev_err(&pdev->dev, "ioremap() of registers failed\n");
+               ret = -ENXIO;
+               goto release_mem;
+       }
+
        platform_set_drvdata(pdev, fbinfo);
 
        dprintk("devinit\n");
@@ -674,8 +830,8 @@ static int __init s3c2410fb_probe(struct platform_device *pdev)
 
        /* Stop the video and unset ENVID if set */
        info->regs.lcdcon1 &= ~S3C2410_LCDCON1_ENVID;
-       lcdcon1 = readl(S3C2410_LCDCON1);
-       writel(lcdcon1 & ~S3C2410_LCDCON1_ENVID, S3C2410_LCDCON1);
+       lcdcon1 = readl(info->io + S3C2410_LCDCON1);
+       writel(lcdcon1 & ~S3C2410_LCDCON1_ENVID, info->io + S3C2410_LCDCON1);
 
        info->mach_info             = pdev->dev.platform_data;
 
@@ -726,19 +882,11 @@ static int __init s3c2410fb_probe(struct platform_device *pdev)
        for (i = 0; i < 256; i++)
                info->palette_buffer[i] = PALETTE_BUFF_CLEAR;
 
-       if (!request_mem_region((unsigned long)S3C24XX_VA_LCD, SZ_1M, "s3c2410-lcd")) {
-               ret = -EBUSY;
-               goto dealloc_fb;
-       }
-
-
-       dprintk("got LCD region\n");
-
        ret = request_irq(irq, s3c2410fb_irq, IRQF_DISABLED, pdev->name, info);
        if (ret) {
                dev_err(&pdev->dev, "cannot get irq %d - err %d\n", irq, ret);
                ret = -EBUSY;
-               goto release_mem;
+               goto release_regs;
        }
 
        info->clk = clk_get(NULL, "lcd");
@@ -760,6 +908,7 @@ static int __init s3c2410fb_probe(struct platform_device *pdev)
                ret = -ENOMEM;
                goto release_clock;
        }
+
        dprintk("got video memory\n");
 
        ret = s3c2410fb_init_registers(info);
@@ -787,8 +936,11 @@ release_clock:
        clk_put(info->clk);
 release_irq:
        free_irq(irq,info);
+release_regs:
+       iounmap(info->io);
 release_mem:
-       release_mem_region((unsigned long)S3C24XX_VA_LCD, S3C24XX_SZ_LCD);
+       release_resource(info->mem);
+       kfree(info->mem);
 dealloc_fb:
        framebuffer_release(fbinfo);
        return ret;
@@ -806,7 +958,7 @@ static void s3c2410fb_stop_lcd(struct s3c2410fb_info *fbi)
        local_irq_save(flags);
 
        fbi->regs.lcdcon1 &= ~S3C2410_LCDCON1_ENVID;
-       writel(fbi->regs.lcdcon1, S3C2410_LCDCON1);
+       writel(fbi->regs.lcdcon1, fbi->io + S3C2410_LCDCON1);
 
        local_irq_restore(flags);
 }
@@ -833,7 +985,10 @@ static int s3c2410fb_remove(struct platform_device *pdev)
 
        irq = platform_get_irq(pdev, 0);
        free_irq(irq,info);
-       release_mem_region((unsigned long)S3C24XX_VA_LCD, S3C24XX_SZ_LCD);
+
+       release_resource(info->mem);
+       kfree(info->mem);
+       iounmap(info->io);
        unregister_framebuffer(fbinfo);
 
        return 0;