| rtp-2610-fbdiff2.patch | | Files affected: | arch/arm/mach-s3c2410/mach-h1940.c | 50 20 + 30 - 0 ! | drivers/video/s3c2410fb.c | 361 275 + 86 - 0 ! | include/asm-arm/arch-s3c2410/s3c2410fb.h | 53 32 + 21 - 0 ! | 3 files changed, 327 insertions(+), 137 deletions(-) | | Ben Dooks, Wed, 03 Nov 2004 18:45:35 +0000 diff -urN -X ../dontdiff linux-2.6.10-rc1-bk2-set2-work1-pre-rtp-mod1/drivers/video/s3c2410fb.c linux-2.6.10-rc1-bk2-set2-work1/drivers/video/s3c2410fb.c --- linux-2.6.10-rc1-bk2-set2-work1-pre-rtp-mod1/drivers/video/s3c2410fb.c 2004-11-03 14:29:40.000000000 +0000 +++ linux-2.6.10-rc1-bk2-set2-work1/drivers/video/s3c2410fb.c 2004-11-03 18:28:47.000000000 +0000 @@ -11,6 +11,17 @@ * * ChangeLog * + * 2004-11-03: Ben Dooks + * - minor cleanups + * - add suspend/resume support + * - s3c2410fb_setcolreg() not valid in >8bpp modes + * - removed last CONFIG_FB_S3C2410_FIXED + * - ensure lcd controller stopped before cleanup + * - added sysfs interface for backlight power + * - added mask for gpio configuration + * - ensured IRQs disabled during GPIO configuration + * - disable TPAL before enabling video + * * 2004-09-20: Arnaud Patard * - Suppress command line options * @@ -49,6 +60,9 @@ #include #include #include +#include + +#include #include #include @@ -62,11 +76,45 @@ #define S3C2410_FBIO_SETBRIGHTNESS _IOW('F', 0x50, int) #define DEFAULT_BACKLIGHT_LEVEL 2 -static void (*s3c2410fb_backlight_power)(int); -static void (*s3c2410fb_lcd_power)(int); -static void (*s3c2410fb_set_brightness)(int); - static struct s3c2410fb_info info; +static struct s3c2410fb_mach_info *mach_info; + +/* backlight and power control functions */ + +static int backlight_level = DEFAULT_BACKLIGHT_LEVEL; +static int backlight_power = 1; + + +static inline void s3c2410fb_lcd_power(int to) +{ + if (mach_info == NULL) + return; + + if (mach_info->lcd_power) + (mach_info->lcd_power)(to); +} + +static inline void s3c2410fb_backlight_power(int to) +{ + if (mach_info == NULL) + return; + + backlight_power = to; + + if (mach_info->backlight_power) + (mach_info->backlight_power)(to); +} + +static inline void s3c2410fb_backlight_level(int to) +{ + if (mach_info == NULL) + return; + + backlight_level = to; + + if (mach_info->set_brightness) + (mach_info->set_brightness)(to); +} /* * s3c2410fb_check_var(): @@ -78,12 +126,12 @@ { dprintk("check_var(var=%p, info=%p)\n", var, info); - 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->red.offset = 11; + var->green.offset = 5; + var->blue.offset = 0; + var->red.length = 5; + var->green.length = 6; + var->blue.length = 5; return 0; } @@ -100,20 +148,21 @@ /* We support only 16BPP true color */ fbi->fb.fix.visual = FB_VISUAL_TRUECOLOR; - fbi->fb.fix.line_length = var->width*16/8; + fbi->fb.fix.line_length = (var->width*var->bits_per_pixel)/8; return 0; } static int s3c2410fb_setcolreg(unsigned regno, - unsigned red, unsigned green, unsigned blue, - unsigned transp, struct fb_info *info) + unsigned red, unsigned green, unsigned blue, + unsigned transp, struct fb_info *info) { struct s3c2410fb_info *fbi = (struct s3c2410fb_info *)info; int bpp, m = 0; bpp = fbi->fb.var.bits_per_pixel; m = 1 << bpp; + if (regno >= m) { return -EINVAL; } @@ -169,25 +218,24 @@ { dprintk("blank(mode=%d, info=%p)\n", blank_mode, info); + if (mach_info == NULL) + return -EINVAL; + switch (blank_mode) { case VESA_NO_BLANKING: /* lcd on, backlight on */ - if (s3c2410fb_lcd_power) - s3c2410fb_lcd_power(1); - if (s3c2410fb_backlight_power) - s3c2410fb_backlight_power(1); + s3c2410fb_lcd_power(1); + s3c2410fb_backlight_power(1); break; + case VESA_VSYNC_SUSPEND: /* lcd on, backlight off */ case VESA_HSYNC_SUSPEND: - if (s3c2410fb_lcd_power) - s3c2410fb_lcd_power(1); - if (s3c2410fb_backlight_power) - s3c2410fb_backlight_power(0); + s3c2410fb_lcd_power(1); + s3c2410fb_backlight_power(0); break; + case VESA_POWERDOWN: /* lcd and backlight off */ - if (s3c2410fb_lcd_power) - s3c2410fb_lcd_power(0); - if (s3c2410fb_backlight_power) - s3c2410fb_backlight_power(0); + s3c2410fb_lcd_power(0); + s3c2410fb_backlight_power(0); break; default: return -EINVAL; @@ -197,21 +245,21 @@ } /* - * s3c2410fb_ioctl - non standard ioctls (atm, only brightness) + * s3c2410fb_ioctl - non standard ioctls (atm, only level) */ static int s3c2410fb_ioctl(struct inode *inode, struct file *file, - u_int cmd, u_long arg, - struct fb_info *info) + u_int cmd, u_long arg, + struct fb_info *info) { int value; switch(cmd) { case S3C2410_FBIO_SETBRIGHTNESS: - if (copy_from_user(&value, (void *)arg, sizeof(int))) - return(-EFAULT); - if (s3c2410fb_set_brightness) - s3c2410fb_set_brightness(value); + if (copy_from_user(&value, (__user void *)arg, + sizeof(int))) + return(-EFAULT); + s3c2410fb_backlight_level(value); return(0); break; default: @@ -219,6 +267,66 @@ } } +/* sysfs export of baclight control */ + +static int s3c2410fb_backlight_level_show(struct device *dev, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", backlight_level); +} + +static int s3c2410fb_backlight_power_show(struct device *dev, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", backlight_power); +} + +static int s3c2410fb_backlight_level_store(struct device *dev, + const char *buf, size_t len) +{ + unsigned long value = simple_strtoul(buf, NULL, 10); + + if (mach_info == NULL) + return -EINVAL; + + if (value < mach_info->backlight_min || + value > mach_info->backlight_max) + return -ERANGE; + + s3c2410fb_backlight_level(value); + return len; +} + +static int s3c2410fb_backlight_power_store(struct device *dev, + const char *buf, size_t len) +{ + if (mach_info == NULL) + return -EINVAL; + + if (len < 1) + return -EINVAL; + + if (strnicmp(buf, "on", 2) == 0 || + strnicmp(buf, "1", 1) == 0) { + s3c2410fb_backlight_power(1); + } else if (strnicmp(buf, "off", 3) == 0 || + strnicmp(buf, "0", 1) == 0) { + s3c2410fb_backlight_power(0); + } else { + return -EINVAL; + } + + return len; +} + +static DEVICE_ATTR(backlight_level, 0644, + s3c2410fb_backlight_level_show, + s3c2410fb_backlight_level_store); + +static DEVICE_ATTR(backlight_power, 0644, + s3c2410fb_backlight_power_show, + s3c2410fb_backlight_power_store); + + + static struct fb_ops s3c2410fb_ops = { .owner = THIS_MODULE, .fb_check_var = s3c2410fb_check_var, @@ -278,32 +386,49 @@ return fbi->map_cpu ? 0 : -ENOMEM; } +static inline void modify_gpio(unsigned long reg, + unsigned long set, unsigned long mask) +{ + unsigned long tmp; + + tmp = __raw_readl(reg) & ~mask; + __raw_writel(tmp | set, reg); + + dprintk("%08lx set to %08lx\n", reg, __raw_readl(reg)); +} + /* * s3c2410fb_init_registers - Initialise all LCD-related registers */ -int __devinit s3c2410fb_init_registers(struct s3c2410fb_info *fbi, struct device *dev) +int __devinit s3c2410fb_init_registers(struct s3c2410fb_info *fbi) { - struct s3c2410fb_mach_info *mach_infos; unsigned long saddr1, saddr2, saddr3; + unsigned long flags; - mach_infos=dev->platform_data; - /* Initialise LCD with values from haret */ - __raw_writel(mach_infos->gpcup, S3C2410_GPCUP); - __raw_writel(mach_infos->gpccon, S3C2410_GPCCON); - __raw_writel(mach_infos->gpdup, S3C2410_GPDUP); - __raw_writel(mach_infos->gpdcon, S3C2410_GPDCON); - __raw_writel(mach_infos->lcdcon1, S3C2410_LCDCON1); - __raw_writel(mach_infos->lcdcon2, S3C2410_LCDCON2); - __raw_writel(mach_infos->lcdcon3, S3C2410_LCDCON3); - __raw_writel(mach_infos->lcdcon4, S3C2410_LCDCON4); - __raw_writel(mach_infos->lcdcon5, S3C2410_LCDCON5); - + + local_irq_save(flags); + + /* modify the gpio(s) with interrupts set (bjd) */ + + modify_gpio(S3C2410_GPCUP, mach_info->gpcup, mach_info->gpcup_mask); + modify_gpio(S3C2410_GPCCON, mach_info->gpccon, mach_info->gpccon_mask); + modify_gpio(S3C2410_GPDUP, mach_info->gpdup, mach_info->gpdup_mask); + modify_gpio(S3C2410_GPDCON, mach_info->gpdcon, mach_info->gpdcon_mask); + + local_irq_restore(flags); + + __raw_writel(mach_info->lcdcon1, S3C2410_LCDCON1); + __raw_writel(mach_info->lcdcon2, S3C2410_LCDCON2); + __raw_writel(mach_info->lcdcon3, S3C2410_LCDCON3); + __raw_writel(mach_info->lcdcon4, S3C2410_LCDCON4); + __raw_writel(mach_info->lcdcon5, S3C2410_LCDCON5); + saddr1 = S3C2410_LCDBANK(fbi->fb.fix.smem_start >> 22) | S3C2410_LCDBASEU(fbi->fb.fix.smem_start >> 1); - saddr2 = (fbi->fb.fix.smem_start+(mach_infos->width*mach_infos->height*2)) >> 1; - saddr3 = S3C2410_OFFSIZE(0) | S3C2410_PAGEWIDTH(mach_infos->width); + saddr2 = (fbi->fb.fix.smem_start+(mach_info->width*mach_info->height*2)) >> 1; + saddr3 = S3C2410_OFFSIZE(0) | S3C2410_PAGEWIDTH(mach_info->width); dprintk("LCDSADDR1 = 0x%08lx\n", saddr1); @@ -315,14 +440,19 @@ dprintk("LCDSADDR3 = 0x%08lx\n", saddr3); __raw_writel(saddr3, S3C2410_LCDSADDR3); - __raw_writel(mach_infos->lpcsel, S3C2410_LPCSEL); + dprintk("LPCSEL = 0x%08x\n", mach_info->lpcsel); + __raw_writel(mach_info->lpcsel, S3C2410_LPCSEL); + + dprintk("replacing TPAL %08x\n", __raw_readl(S3C2410_TPAL)); + + /* ensure temporary palette disabled */ + __raw_writel(0x00, S3C2410_TPAL); /* probably not required */ msleep(10); /* Enable video by setting the ENVID bit to 1 */ - __raw_writel(mach_infos->lcdcon1|S3C2410_LCDCON1_ENVID, S3C2410_LCDCON1); - + __raw_writel(mach_info->lcdcon1|S3C2410_LCDCON1_ENVID, S3C2410_LCDCON1); return 0; } @@ -330,34 +460,20 @@ int __init s3c2410fb_probe(struct device *dev) { - struct s3c2410fb_mach_info *mach_infos; char driver_name[]="s3c2410fb"; int ret; - mach_infos = dev->platform_data; - if (!mach_infos) + mach_info = dev->platform_data; + if (mach_info == NULL) { - dprintk("Unable to get platform_data !!!\n"); + printk(KERN_ERR "no platform data for lcd, cannot attach\n"); return -EINVAL; } - s3c2410fb_backlight_power=mach_infos->s3c2410fb_backlight_power; - s3c2410fb_lcd_power=mach_infos->s3c2410fb_lcd_power; - s3c2410fb_set_brightness=mach_infos->s3c2410fb_set_brightness; - - if (s3c2410fb_backlight_power) - { - /* Doing so, implies that set_brightness is also - * switching the backlight on - **/ - if (s3c2410fb_set_brightness) - s3c2410fb_set_brightness(DEFAULT_BACKLIGHT_LEVEL); - else - s3c2410fb_backlight_power(1); - } - - if (s3c2410fb_lcd_power) - s3c2410fb_lcd_power(1); + s3c2410fb_backlight_power(1); + s3c2410fb_lcd_power(1); + + s3c2410fb_backlight_level(DEFAULT_BACKLIGHT_LEVEL); dprintk("devinit\n"); @@ -371,8 +487,8 @@ info.fb.var.nonstd = 0; info.fb.var.activate = FB_ACTIVATE_NOW; - info.fb.var.height = mach_infos->height; - info.fb.var.width = mach_infos->width; + info.fb.var.height = mach_info->height; + info.fb.var.width = mach_info->width; info.fb.var.accel_flags = 0; info.fb.var.vmode = FB_VMODE_NONINTERLACED; @@ -383,11 +499,11 @@ info.fb.pseudo_palette = &info.pseudo_pal; - info.fb.var.xres = mach_infos->xres; - info.fb.var.xres_virtual = mach_infos->xres; - info.fb.var.yres = mach_infos->yres; - info.fb.var.yres_virtual = mach_infos->yres; - info.fb.var.bits_per_pixel = mach_infos->bpp; + info.fb.var.xres = mach_info->xres; + info.fb.var.xres_virtual = mach_info->xres; + info.fb.var.yres = mach_info->yres; + info.fb.var.yres_virtual = mach_info->yres; + info.fb.var.bits_per_pixel = mach_info->bpp; info.fb.var.red.offset = 11; @@ -428,7 +544,7 @@ } dprintk("got video memory\n"); - ret = s3c2410fb_init_registers(&info,dev); + ret = s3c2410fb_init_registers(&info); s3c2410fb_lcd_power(1); ret = s3c2410fb_check_var(&info.fb.var, &info.fb); @@ -439,6 +555,10 @@ goto failed; } + /* create device files */ + + device_create_file(dev, &dev_attr_backlight_power); + device_create_file(dev, &dev_attr_backlight_level); printk(KERN_INFO "fb%d: %s frame buffer device\n", info.fb.node, info.fb.fix.id); @@ -446,17 +566,35 @@ return 0; failed: release_mem_region(S3C2410_VA_LCD, S3C2410_SZ_LCD); -#ifdef CONFIG_FB_S3C2410_FIXED - release_mem_region(S3C2410_VA_FBMEM, S3C2410_SZ_FBMEM); -#endif return ret; } +/* s3c2410fb_stop_lcd + * + * shutdown the lcd controller +*/ + +static void s3c2410fb_stop_lcd(void) +{ + unsigned long flags; + unsigned long tmp; + + local_irq_save(flags); + + tmp = __raw_readl(S3C2410_LCDCON1); + __raw_writel(tmp & ~S3C2410_LCDCON1_ENVID, S3C2410_LCDCON1); + + local_irq_restore(flags); +} + /* * Cleanup */ static void __exit s3c2410fb_cleanup(void) { + s3c2410fb_stop_lcd(); + msleep(1); + if (lcd_clock) { clk_disable(lcd_clock); clk_unuse(lcd_clock); @@ -466,15 +604,66 @@ unregister_framebuffer(&info.fb); release_mem_region(S3C2410_VA_LCD, S3C2410_SZ_LCD); -#ifdef CONFIG_FB_S3C2410_FIXED - release_mem_region(S3C2410_VA_FBMEM, S3C2410_SZ_FBMEM); -#endif } +#ifdef CONFIG_PM + +/* suspend and resume support for the lcd controller */ + +static int s3c2410fb_suspend(struct device *dev, u32 state, u32 level) +{ + if (level == SUSPEND_DISABLE || level == SUSPEND_POWER_DOWN) { + s3c2410fb_stop_lcd(); + + /* sleep before disabling the clock, we need to ensure + * the LCD DMA engine is not going to get back on the bus + * before the clock goes off again (bjd) */ + + if (mach_info != NULL) { + /* don't use our helper functions in this file, + becuase we want to save the original values for + when the system wakes up + */ + + if (mach_info->lcd_power) + (mach_info->lcd_power)(0); + + if (mach_info->backlight_power) + (mach_info->backlight_power)(0); + } + + msleep(1); + clk_disable(lcd_clock); + } + + return 0; +} + +static int s3c2410fb_resume(struct device *dev, u32 level) +{ + if (level == RESUME_ENABLE) { + clk_enable(lcd_clock); + s3c2410fb_init_registers(&info); + + /* resume the backlight level */ + s3c2410fb_backlight_power(backlight_power); + s3c2410fb_backlight_level(backlight_level); + } + + return 0; +} + +#else +#define s3c2410fb_suspend NULL +#define s3c2410fb_resume NULL +#endif + static struct device_driver s3c2410fb_driver = { .name = "s3c2410-lcd", .bus = &platform_bus_type, .probe = s3c2410fb_probe, + .suspend = s3c2410fb_suspend, + .resume = s3c2410fb_resume, }; int __devinit s3c2410fb_init(void) --- linux-2.6.10-rc1-bk2-set2-work1-pre-rtp-mod1/arch/arm/mach-s3c2410/mach-h1940.c 2004-11-03 14:29:40.000000000 +0000 +++ linux-2.6.10-rc1-bk2-set2-work1/arch/arm/mach-s3c2410/mach-h1940.c 2004-11-03 18:25:48.000000000 +0000 @@ -20,6 +20,7 @@ * 04-Sep-2004 BJD Changed uart init, renamed ipaq_ -> h1940_ * 18-Oct-2004 BJD Updated new board structure name * 28-Oct-2004 BJD Changed UART clock info + * 03-Nov-2004 BJD Updated for new LCD bits */ #include @@ -28,6 +29,7 @@ #include #include #include +#include #include #include @@ -87,16 +89,11 @@ **/ static void h1940_backlight_power(int on) { - __raw_writel(__raw_readl(S3C2410_GPBUP)|1,S3C2410_GPBUP); - if (on) - { - __raw_writel((__raw_readl(S3C2410_GPBCON)&~0x03)|S3C2410_GPB0_TOUT0,S3C2410_GPBCON); - } - else - { - __raw_writel((__raw_readl(S3C2410_GPBCON)&~0x03)|S3C2410_GPB0_OUTP,S3C2410_GPBCON); - __raw_writel(__raw_readl(S3C2410_GPBDAT)&~1,S3C2410_GPBDAT); - } + s3c2410_gpio_setpin(S3C2410_GPB0, 0); + s3c2410_gpio_pullup(S3C2410_GPB0, 0); + + s3c2410_gpio_cfgpin(S3C2410_GPB0, + (on) ? S3C2410_GPB0_TOUT0 : S3C2410_GPB0_OUTP); } /* Set the backlight pwm according to the level from wince */ @@ -109,26 +106,24 @@ unsigned long tcmpb0=0x00; unsigned long tcon; + /* configure power on/off */ + h1940_backlight_power(level ? 1 : 0); + switch (level) { case 0: - h1940_backlight_power(0); break; case 1: - h1940_backlight_power(1); tcmpb0=0x0b; break; default: case 2: - h1940_backlight_power(1); tcmpb0=0x16; break; case 3: - h1940_backlight_power(1); tcmpb0=0x21; break; case 4: - h1940_backlight_power(1); tcmpb0=0x2c; break; } @@ -162,16 +157,8 @@ } #include -static void h1940_lcd_power(int on) -{ - if (on) - { - } - else - { - } -} -static struct s3c2410fb_mach_info h1940_lcdcfg __initdata = { + +static struct s3c2410fb_mach_info h1940_lcdcfg = { .lcdcon1= S3C2410_LCDCON1_TFT16BPP | \ S3C2410_LCDCON1_TFT | \ S3C2410_LCDCON1_CLKVAL(0x0C), @@ -202,10 +189,13 @@ .xres= 240, .yres= 320, .bpp= 16, - - .s3c2410fb_backlight_power = h1940_backlight_power, - .s3c2410fb_lcd_power = h1940_lcd_power, - .s3c2410fb_set_brightness = h1940_set_brightness, + + .backlight_min = 0, + .backlight_max = 4, + .backlight_default = 2, + + .backlight_power = h1940_backlight_power, + .set_brightness = h1940_set_brightness, }; static struct platform_device *h1940_devices[] __initdata = { @@ -236,7 +226,7 @@ void __init h1940_init(void) { - set_s3c2410fb_info(&h1940_lcdcfg); + s3c_device_lcd.dev.platform_data = &h1940_lcdcfg; } MACHINE_START(H1940, "IPAQ-H1940") diff -urN -X ../dontdiff linux-2.6.10-rc1-bk2-set2-work1-pre-rtp-mod1/include/asm-arm/arch-s3c2410/s3c2410fb.h linux-2.6.10-rc1-bk2-set2-work1/include/asm-arm/arch-s3c2410/s3c2410fb.h --- linux-2.6.10-rc1-bk2-set2-work1-pre-rtp-mod1/include/asm-arm/arch-s3c2410/s3c2410fb.h 2004-11-03 14:29:40.000000000 +0000 +++ linux-2.6.10-rc1-bk2-set2-work1/include/asm-arm/arch-s3c2410/s3c2410fb.h 2004-11-03 18:19:32.000000000 +0000 @@ -10,8 +10,10 @@ * * * Changelog: - * 07-Sep-2004 RTP Created file + * 07-Sep-2004 RTP Created file + * 03-Nov-2004 BJD Updated and minor cleanups */ + #ifndef __ASM_ARM_S3C2410FB_H #define __ASM_ARM_S3C2410FB_H @@ -20,34 +22,43 @@ struct s3c2410fb_mach_info { /* Screen size */ - int width; - int height; + int width; + int height; /* Screen info */ - int xres; - int yres; - int bpp; + int xres; + int yres; + int bpp; /* lcd configuration registers */ - unsigned long lcdcon1; - unsigned long lcdcon2; - unsigned long lcdcon3; - unsigned long lcdcon4; - unsigned long lcdcon5; + unsigned long lcdcon1; + unsigned long lcdcon2; + unsigned long lcdcon3; + unsigned long lcdcon4; + unsigned long lcdcon5; /* GPIOs */ - unsigned long gpcup; - unsigned long gpccon; - unsigned long gpdup; - unsigned long gpdcon; + unsigned long gpcup; + unsigned long gpcup_mask; + unsigned long gpccon; + unsigned long gpccon_mask; + unsigned long gpdup; + unsigned long gpdup_mask; + unsigned long gpdcon; + unsigned long gpdcon_mask; /* lpc3600 control register */ - unsigned long lpcsel; + unsigned long lpcsel; + + /* backlight info */ + int backlight_min; + int backlight_max; + int backlight_default; /* Utility fonctions */ - void (*s3c2410fb_backlight_power)(int); - void (*s3c2410fb_lcd_power)(int); - void (*s3c2410fb_set_brightness)(int); + void (*backlight_power)(int); + void (*lcd_power)(int); + void (*set_brightness)(int); }; -void set_s3c2410fb_info(struct s3c2410fb_mach_info *hard_s3c2410fb_info); -#endif + +#endif /* __ASM_ARM_S3C2410FB_H */