X-Git-Url: http://pilppa.org/gitweb/gitweb.cgi?a=blobdiff_plain;f=drivers%2Fvideo%2Fs3c2410fb.c;h=8a4c6470d79941ab497f8dcf227af8c19f0a0eb8;hb=163642a24a44d7b1d1e1b3cb8da25a142a919e24;hp=ad3bdd6f1ac1fa39ca03896b9873cc1b56dd6639;hpb=a4b47ab9464a8200528fad3101668abdd7379cf9;p=linux-2.6-omap-h63xx.git diff --git a/drivers/video/s3c2410fb.c b/drivers/video/s3c2410fb.c index ad3bdd6f1ac..8a4c6470d79 100644 --- a/drivers/video/s3c2410fb.c +++ b/drivers/video/s3c2410fb.c @@ -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,31 +730,32 @@ 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 */ } } -static irqreturn_t s3c2410fb_irq(int irq, void *dev_id, struct pt_regs *r) +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;