diff options
Diffstat (limited to 'drivers/video')
112 files changed, 7291 insertions, 2339 deletions
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index fd55c279915c..a9ca72f301bf 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -8,6 +8,9 @@ menu "Graphics support" config HAVE_FB_ATMEL bool +config HAVE_FB_IMX + bool + source "drivers/char/agp/Kconfig" source "drivers/gpu/vga/Kconfig" @@ -400,9 +403,6 @@ config FB_SA1100 If you plan to use the LCD display with your SA-1100 system, say Y here. -config HAVE_FB_IMX - bool - config FB_IMX tristate "Motorola i.MX LCD support" depends on FB && (HAVE_FB_IMX || ARCH_MX1 || ARCH_MX2) @@ -1505,7 +1505,7 @@ config FB_SIS_315 config FB_VIA tristate "VIA UniChrome (Pro) and Chrome9 display support" - depends on FB && PCI + depends on FB && PCI && X86 select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT @@ -1871,6 +1871,7 @@ config FB_MBX_DEBUG config FB_FSL_DIU tristate "Freescale DIU framebuffer support" depends on FB && FSL_SOC + select FB_MODE_HELPERS select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT @@ -2202,7 +2203,6 @@ config FB_MSM select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - default y config FB_MX3 tristate "MX3 Framebuffer support" @@ -2230,6 +2230,15 @@ config FB_BROADSHEET and could also have been called by other names when coupled with a bridge adapter. +config FB_JZ4740 + tristate "JZ4740 LCD framebuffer support" + depends on FB && MACH_JZ4740 + select FB_SYS_FILLRECT + select FB_SYS_COPYAREA + select FB_SYS_IMAGEBLIT + help + Framebuffer support for the JZ4740 SoC. + source "drivers/video/omap/Kconfig" source "drivers/video/omap2/Kconfig" diff --git a/drivers/video/Makefile b/drivers/video/Makefile index ddc2af2ba45b..f56a9cae2157 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -131,6 +131,7 @@ obj-$(CONFIG_FB_CARMINE) += carminefb.o obj-$(CONFIG_FB_MB862XX) += mb862xx/ obj-$(CONFIG_FB_MSM) += msm/ obj-$(CONFIG_FB_NUC900) += nuc900fb.o +obj-$(CONFIG_FB_JZ4740) += jz4740_fb.o # Platform or fallback drivers go here obj-$(CONFIG_FB_UVESA) += uvesafb.o diff --git a/drivers/video/arcfb.c b/drivers/video/arcfb.c index 8d406fb689c1..f3d7440f0072 100644 --- a/drivers/video/arcfb.c +++ b/drivers/video/arcfb.c @@ -80,7 +80,7 @@ struct arcfb_par { spinlock_t lock; }; -static struct fb_fix_screeninfo arcfb_fix __initdata = { +static struct fb_fix_screeninfo arcfb_fix __devinitdata = { .id = "arcfb", .type = FB_TYPE_PACKED_PIXELS, .visual = FB_VISUAL_MONO01, @@ -90,7 +90,7 @@ static struct fb_fix_screeninfo arcfb_fix __initdata = { .accel = FB_ACCEL_NONE, }; -static struct fb_var_screeninfo arcfb_var __initdata = { +static struct fb_var_screeninfo arcfb_var __devinitdata = { .xres = 128, .yres = 64, .xres_virtual = 128, @@ -588,7 +588,7 @@ err: return retval; } -static int arcfb_remove(struct platform_device *dev) +static int __devexit arcfb_remove(struct platform_device *dev) { struct fb_info *info = platform_get_drvdata(dev); @@ -602,7 +602,7 @@ static int arcfb_remove(struct platform_device *dev) static struct platform_driver arcfb_driver = { .probe = arcfb_probe, - .remove = arcfb_remove, + .remove = __devexit_p(arcfb_remove), .driver = { .name = "arcfb", }, diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c index 29d72851f85b..f8d69ad36830 100644 --- a/drivers/video/aty/atyfb_base.c +++ b/drivers/video/aty/atyfb_base.c @@ -1820,10 +1820,6 @@ struct atyclk { #define ATYIO_FEATW 0x41545903 /* ATY\03 */ #endif -#ifndef FBIO_WAITFORVSYNC -#define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32) -#endif - static int atyfb_ioctl(struct fb_info *info, u_int cmd, u_long arg) { struct atyfb_par *par = (struct atyfb_par *) info->par; diff --git a/drivers/video/aty/mach64_accel.c b/drivers/video/aty/mach64_accel.c index 51fcc0a2c94a..e45833ce975b 100644 --- a/drivers/video/aty/mach64_accel.c +++ b/drivers/video/aty/mach64_accel.c @@ -242,7 +242,7 @@ void atyfb_copyarea(struct fb_info *info, const struct fb_copyarea *area) void atyfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) { struct atyfb_par *par = (struct atyfb_par *) info->par; - u32 color = rect->color, dx = rect->dx, width = rect->width, rotation = 0; + u32 color, dx = rect->dx, width = rect->width, rotation = 0; if (par->asleep) return; @@ -253,8 +253,11 @@ void atyfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) return; } - color |= (rect->color << 8); - color |= (rect->color << 16); + if (info->fix.visual == FB_VISUAL_TRUECOLOR || + info->fix.visual == FB_VISUAL_DIRECTCOLOR) + color = ((u32 *)(info->pseudo_palette))[rect->color]; + else + color = rect->color; if (info->var.bits_per_pixel == 24) { /* In 24 bpp, the engine is in 8 bpp - this requires that all */ diff --git a/drivers/video/aty/radeon_base.c b/drivers/video/aty/radeon_base.c index 6c37e8ee5efe..3c1e13ed1cba 100644 --- a/drivers/video/aty/radeon_base.c +++ b/drivers/video/aty/radeon_base.c @@ -2099,7 +2099,7 @@ static ssize_t radeon_show_one_edid(char *buf, loff_t off, size_t count, const u } -static ssize_t radeon_show_edid1(struct kobject *kobj, +static ssize_t radeon_show_edid1(struct file *filp, struct kobject *kobj, struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) { @@ -2112,7 +2112,7 @@ static ssize_t radeon_show_edid1(struct kobject *kobj, } -static ssize_t radeon_show_edid2(struct kobject *kobj, +static ssize_t radeon_show_edid2(struct file *filp, struct kobject *kobj, struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) { diff --git a/drivers/video/aty/radeon_pm.c b/drivers/video/aty/radeon_pm.c index 515cf1978d19..c4e17642d9c5 100644 --- a/drivers/video/aty/radeon_pm.c +++ b/drivers/video/aty/radeon_pm.c @@ -2872,7 +2872,7 @@ void radeonfb_pm_init(struct radeonfb_info *rinfo, int dynclk, int ignore_devlis } #if 0 - /* Power down TV DAC, taht saves a significant amount of power, + /* Power down TV DAC, that saves a significant amount of power, * we'll have something better once we actually have some TVOut * support */ diff --git a/drivers/video/au1100fb.c b/drivers/video/au1100fb.c index 40f61320ce16..34b2fc472fe8 100644 --- a/drivers/video/au1100fb.c +++ b/drivers/video/au1100fb.c @@ -95,7 +95,7 @@ struct fb_bitfield rgb_bitfields[][4] = { { 8, 4, 0 }, { 4, 4, 0 }, { 0, 4, 0 }, { 0, 0, 0 } }, }; -static struct fb_fix_screeninfo au1100fb_fix __initdata = { +static struct fb_fix_screeninfo au1100fb_fix __devinitdata = { .id = "AU1100 FB", .xpanstep = 1, .ypanstep = 1, @@ -103,7 +103,7 @@ static struct fb_fix_screeninfo au1100fb_fix __initdata = { .accel = FB_ACCEL_NONE, }; -static struct fb_var_screeninfo au1100fb_var __initdata = { +static struct fb_var_screeninfo au1100fb_var __devinitdata = { .activate = FB_ACTIVATE_NOW, .height = -1, .width = -1, @@ -458,7 +458,7 @@ static struct fb_ops au1100fb_ops = /* AU1100 LCD controller device driver */ -static int __init au1100fb_drv_probe(struct platform_device *dev) +static int __devinit au1100fb_drv_probe(struct platform_device *dev) { struct au1100fb_device *fbdev = NULL; struct resource *regs_res; diff --git a/drivers/video/backlight/88pm860x_bl.c b/drivers/video/backlight/88pm860x_bl.c index 68d2518fadaa..38ffc3fbcbe4 100644 --- a/drivers/video/backlight/88pm860x_bl.c +++ b/drivers/video/backlight/88pm860x_bl.c @@ -222,6 +222,7 @@ static int pm860x_backlight_probe(struct platform_device *pdev) data->port = __check_device(pdata, name); if (data->port < 0) { dev_err(&pdev->dev, "wrong platform data is assigned"); + kfree(data); return -EINVAL; } @@ -266,6 +267,7 @@ static int pm860x_backlight_probe(struct platform_device *pdev) backlight_update_status(bl); return 0; out: + backlight_device_unregister(bl); kfree(data); return ret; } diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index c025c84601b0..e54a337227ea 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig @@ -8,12 +8,13 @@ menuconfig BACKLIGHT_LCD_SUPPORT Enable this to be able to choose the drivers for controlling the backlight and the LCD panel on some platforms, for example on PDAs. +if BACKLIGHT_LCD_SUPPORT + # # LCD # config LCD_CLASS_DEVICE tristate "Lowlevel LCD controls" - depends on BACKLIGHT_LCD_SUPPORT default m help This framework adds support for low-level control of LCD. @@ -24,31 +25,32 @@ config LCD_CLASS_DEVICE To have support for your specific LCD panel you will have to select the proper drivers which depend on this option. +if LCD_CLASS_DEVICE + config LCD_CORGI tristate "LCD Panel support for SHARP corgi/spitz model" - depends on LCD_CLASS_DEVICE && SPI_MASTER && PXA_SHARPSL + depends on SPI_MASTER && PXA_SHARPSL help Say y here to support the LCD panels usually found on SHARP corgi (C7x0) and spitz (Cxx00) models. config LCD_L4F00242T03 tristate "Epson L4F00242T03 LCD" - depends on LCD_CLASS_DEVICE && SPI_MASTER && GENERIC_GPIO + depends on SPI_MASTER && GENERIC_GPIO help SPI driver for Epson L4F00242T03. This provides basic support for init and powering the LCD up/down through a sysfs interface. config LCD_LMS283GF05 tristate "Samsung LMS283GF05 LCD" - depends on LCD_CLASS_DEVICE && SPI_MASTER && GENERIC_GPIO + depends on SPI_MASTER && GENERIC_GPIO help SPI driver for Samsung LMS283GF05. This provides basic support for powering the LCD up/down through a sysfs interface. config LCD_LTV350QV tristate "Samsung LTV350QV LCD Panel" - depends on LCD_CLASS_DEVICE && SPI_MASTER - default n + depends on SPI_MASTER help If you have a Samsung LTV350QV LCD panel, say y to include a power control driver for it. The panel starts up in power @@ -59,60 +61,61 @@ config LCD_LTV350QV config LCD_ILI9320 tristate - depends on LCD_CLASS_DEVICE && BACKLIGHT_LCD_SUPPORT - default n help If you have a panel based on the ILI9320 controller chip then say y to include a power driver for it. config LCD_TDO24M tristate "Toppoly TDO24M and TDO35S LCD Panels support" - depends on LCD_CLASS_DEVICE && SPI_MASTER - default n + depends on SPI_MASTER help If you have a Toppoly TDO24M/TDO35S series LCD panel, say y here to include the support for it. config LCD_VGG2432A4 tristate "VGG2432A4 LCM device support" - depends on BACKLIGHT_LCD_SUPPORT && LCD_CLASS_DEVICE && SPI_MASTER + depends on SPI_MASTER select LCD_ILI9320 - default n help If you have a VGG2432A4 panel based on the ILI9320 controller chip then say y to include a power driver for it. config LCD_PLATFORM tristate "Platform LCD controls" - depends on LCD_CLASS_DEVICE help This driver provides a platform-device registered LCD power control interface. config LCD_TOSA tristate "Sharp SL-6000 LCD Driver" - depends on LCD_CLASS_DEVICE && SPI - depends on MACH_TOSA - default n + depends on SPI && MACH_TOSA help If you have an Sharp SL-6000 Zaurus say Y to enable a driver for its LCD. config LCD_HP700 tristate "HP Jornada 700 series LCD Driver" - depends on LCD_CLASS_DEVICE depends on SA1100_JORNADA720_SSP && !PREEMPT default y help If you have an HP Jornada 700 series handheld (710/720/728) say Y to enable LCD control driver. +config LCD_S6E63M0 + tristate "S6E63M0 AMOLED LCD Driver" + depends on SPI && BACKLIGHT_CLASS_DEVICE + default n + help + If you have an S6E63M0 LCD Panel, say Y to enable its + LCD control driver. + +endif # LCD_CLASS_DEVICE + # # Backlight # config BACKLIGHT_CLASS_DEVICE tristate "Lowlevel Backlight controls" - depends on BACKLIGHT_LCD_SUPPORT default m help This framework adds support for low-level control of the LCD @@ -121,9 +124,11 @@ config BACKLIGHT_CLASS_DEVICE To have support for your specific LCD panel you will have to select the proper drivers which depend on this option. +if BACKLIGHT_CLASS_DEVICE + config BACKLIGHT_ATMEL_LCDC bool "Atmel LCDC Contrast-as-Backlight control" - depends on BACKLIGHT_CLASS_DEVICE && FB_ATMEL + depends on FB_ATMEL default y if MACH_SAM9261EK || MACH_SAM9G10EK || MACH_SAM9263EK help This provides a backlight control internal to the Atmel LCDC @@ -136,8 +141,7 @@ config BACKLIGHT_ATMEL_LCDC config BACKLIGHT_ATMEL_PWM tristate "Atmel PWM backlight control" - depends on BACKLIGHT_CLASS_DEVICE && ATMEL_PWM - default n + depends on ATMEL_PWM help Say Y here if you want to use the PWM peripheral in Atmel AT91 and AVR32 devices. This driver will need additional platform data to know @@ -146,9 +150,18 @@ config BACKLIGHT_ATMEL_PWM To compile this driver as a module, choose M here: the module will be called atmel-pwm-bl. +config BACKLIGHT_EP93XX + tristate "Cirrus EP93xx Backlight Driver" + depends on FB_EP93XX + help + If you have a LCD backlight connected to the BRIGHT output of + the EP93xx, say Y here to enable this driver. + + To compile this driver as a module, choose M here: the module will + be called ep93xx_bl. + config BACKLIGHT_GENERIC tristate "Generic (aka Sharp Corgi) Backlight Driver" - depends on BACKLIGHT_CLASS_DEVICE default y help Say y to enable the generic platform backlight driver previously @@ -157,7 +170,7 @@ config BACKLIGHT_GENERIC config BACKLIGHT_LOCOMO tristate "Sharp LOCOMO LCD/Backlight Driver" - depends on BACKLIGHT_CLASS_DEVICE && SHARP_LOCOMO + depends on SHARP_LOCOMO default y help If you have a Sharp Zaurus SL-5500 (Collie) or SL-5600 (Poodle) say y to @@ -165,7 +178,7 @@ config BACKLIGHT_LOCOMO config BACKLIGHT_OMAP1 tristate "OMAP1 PWL-based LCD Backlight" - depends on BACKLIGHT_CLASS_DEVICE && ARCH_OMAP1 + depends on ARCH_OMAP1 default y help This driver controls the LCD backlight level and power for @@ -174,7 +187,7 @@ config BACKLIGHT_OMAP1 config BACKLIGHT_HP680 tristate "HP Jornada 680 Backlight Driver" - depends on BACKLIGHT_CLASS_DEVICE && SH_HP6XX + depends on SH_HP6XX default y help If you have a HP Jornada 680, say y to enable the @@ -182,7 +195,6 @@ config BACKLIGHT_HP680 config BACKLIGHT_HP700 tristate "HP Jornada 700 series Backlight Driver" - depends on BACKLIGHT_CLASS_DEVICE depends on SA1100_JORNADA720_SSP && !PREEMPT default y help @@ -191,76 +203,70 @@ config BACKLIGHT_HP700 config BACKLIGHT_PROGEAR tristate "Frontpath ProGear Backlight Driver" - depends on BACKLIGHT_CLASS_DEVICE && PCI && X86 - default n + depends on PCI && X86 help If you have a Frontpath ProGear say Y to enable the backlight driver. config BACKLIGHT_CARILLO_RANCH tristate "Intel Carillo Ranch Backlight Driver" - depends on BACKLIGHT_CLASS_DEVICE && LCD_CLASS_DEVICE && PCI && X86 && FB_LE80578 - default n + depends on LCD_CLASS_DEVICE && PCI && X86 && FB_LE80578 help If you have a Intel LE80578 (Carillo Ranch) say Y to enable the backlight driver. config BACKLIGHT_PWM tristate "Generic PWM based Backlight Driver" - depends on BACKLIGHT_CLASS_DEVICE && HAVE_PWM + depends on HAVE_PWM help If you have a LCD backlight adjustable by PWM, say Y to enable this driver. config BACKLIGHT_DA903X tristate "Backlight Driver for DA9030/DA9034 using WLED" - depends on BACKLIGHT_CLASS_DEVICE && PMIC_DA903X + depends on PMIC_DA903X help If you have a LCD backlight connected to the WLED output of DA9030 or DA9034 WLED output, say Y here to enable this driver. config BACKLIGHT_MAX8925 tristate "Backlight driver for MAX8925" - depends on BACKLIGHT_CLASS_DEVICE && MFD_MAX8925 + depends on MFD_MAX8925 help If you have a LCD backlight connected to the WLED output of MAX8925 WLED output, say Y here to enable this driver. config BACKLIGHT_MBP_NVIDIA tristate "MacBook Pro Nvidia Backlight Driver" - depends on BACKLIGHT_CLASS_DEVICE && X86 - default n + depends on X86 help If you have an Apple Macbook Pro with Nvidia graphics hardware say Y to enable a driver for its backlight config BACKLIGHT_TOSA tristate "Sharp SL-6000 Backlight Driver" - depends on BACKLIGHT_CLASS_DEVICE && I2C - depends on MACH_TOSA && LCD_TOSA - default n + depends on I2C && MACH_TOSA && LCD_TOSA help If you have an Sharp SL-6000 Zaurus say Y to enable a driver for its backlight config BACKLIGHT_SAHARA tristate "Tabletkiosk Sahara Touch-iT Backlight Driver" - depends on BACKLIGHT_CLASS_DEVICE && X86 - default n + depends on X86 help If you have a Tabletkiosk Sahara Touch-iT, say y to enable the backlight driver. config BACKLIGHT_WM831X tristate "WM831x PMIC Backlight Driver" - depends on BACKLIGHT_CLASS_DEVICE && MFD_WM831X + depends on MFD_WM831X help If you have a backlight driven by the ISINK and DCDC of a WM831x PMIC say y to enable the backlight driver for it. config BACKLIGHT_ADX tristate "Avionic Design Xanthos Backlight Driver" - depends on BACKLIGHT_CLASS_DEVICE && ARCH_PXA_ADX + depends on ARCH_PXA_ADX default y help Say Y to enable the backlight driver on Avionic Design Xanthos-based @@ -268,7 +274,7 @@ config BACKLIGHT_ADX config BACKLIGHT_ADP5520 tristate "Backlight Driver for ADP5520/ADP5501 using WLED" - depends on BACKLIGHT_CLASS_DEVICE && PMIC_ADP5520 + depends on PMIC_ADP5520 help If you have a LCD backlight connected to the BST/BL_SNK output of ADP5520 or ADP5501, say Y here to enable this driver. @@ -276,9 +282,31 @@ config BACKLIGHT_ADP5520 To compile this driver as a module, choose M here: the module will be called adp5520_bl. +config BACKLIGHT_ADP8860 + tristate "Backlight Driver for ADP8860/ADP8861/ADP8863 using WLED" + depends on BACKLIGHT_CLASS_DEVICE && I2C + select NEW_LEDS + select LEDS_CLASS + help + If you have a LCD backlight connected to the ADP8860, ADP8861 or + ADP8863 say Y here to enable this driver. + + To compile this driver as a module, choose M here: the module will + be called adp8860_bl. + config BACKLIGHT_88PM860X tristate "Backlight Driver for 88PM8606 using WLED" - depends on BACKLIGHT_CLASS_DEVICE && MFD_88PM860X + depends on MFD_88PM860X help Say Y to enable the backlight driver for Marvell 88PM8606. +config BACKLIGHT_PCF50633 + tristate "Backlight driver for NXP PCF50633 MFD" + depends on BACKLIGHT_CLASS_DEVICE && MFD_PCF50633 + help + If you have a backlight driven by a NXP PCF50633 MFD, say Y here to + enable its driver. + +endif # BACKLIGHT_CLASS_DEVICE + +endif # BACKLIGHT_LCD_SUPPORT diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile index 09d1f14d6257..44c0f81ad85d 100644 --- a/drivers/video/backlight/Makefile +++ b/drivers/video/backlight/Makefile @@ -11,9 +11,11 @@ obj-$(CONFIG_LCD_PLATFORM) += platform_lcd.o obj-$(CONFIG_LCD_VGG2432A4) += vgg2432a4.o obj-$(CONFIG_LCD_TDO24M) += tdo24m.o obj-$(CONFIG_LCD_TOSA) += tosa_lcd.o +obj-$(CONFIG_LCD_S6E63M0) += s6e63m0.o obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o obj-$(CONFIG_BACKLIGHT_ATMEL_PWM) += atmel-pwm-bl.o +obj-$(CONFIG_BACKLIGHT_EP93XX) += ep93xx_bl.o obj-$(CONFIG_BACKLIGHT_GENERIC) += generic_bl.o obj-$(CONFIG_BACKLIGHT_HP700) += jornada720_bl.o obj-$(CONFIG_BACKLIGHT_HP680) += hp680_bl.o @@ -30,5 +32,7 @@ obj-$(CONFIG_BACKLIGHT_SAHARA) += kb3886_bl.o obj-$(CONFIG_BACKLIGHT_WM831X) += wm831x_bl.o obj-$(CONFIG_BACKLIGHT_ADX) += adx_bl.o obj-$(CONFIG_BACKLIGHT_ADP5520) += adp5520_bl.o +obj-$(CONFIG_BACKLIGHT_ADP8860) += adp8860_bl.o obj-$(CONFIG_BACKLIGHT_88PM860X) += 88pm860x_bl.o +obj-$(CONFIG_BACKLIGHT_PCF50633) += pcf50633-backlight.o diff --git a/drivers/video/backlight/adp8860_bl.c b/drivers/video/backlight/adp8860_bl.c new file mode 100644 index 000000000000..3ec24609151e --- /dev/null +++ b/drivers/video/backlight/adp8860_bl.c @@ -0,0 +1,836 @@ +/* + * Backlight driver for Analog Devices ADP8860 Backlight Devices + * + * Copyright 2009-2010 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include <linux/module.h> +#include <linux/version.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/pm.h> +#include <linux/platform_device.h> +#include <linux/i2c.h> +#include <linux/fb.h> +#include <linux/backlight.h> +#include <linux/leds.h> +#include <linux/slab.h> +#include <linux/workqueue.h> + +#include <linux/i2c/adp8860.h> +#define ADP8860_EXT_FEATURES +#define ADP8860_USE_LEDS + +#define ADP8860_MFDVID 0x00 /* Manufacturer and device ID */ +#define ADP8860_MDCR 0x01 /* Device mode and status */ +#define ADP8860_MDCR2 0x02 /* Device mode and Status Register 2 */ +#define ADP8860_INTR_EN 0x03 /* Interrupts enable */ +#define ADP8860_CFGR 0x04 /* Configuration register */ +#define ADP8860_BLSEN 0x05 /* Sink enable backlight or independent */ +#define ADP8860_BLOFF 0x06 /* Backlight off timeout */ +#define ADP8860_BLDIM 0x07 /* Backlight dim timeout */ +#define ADP8860_BLFR 0x08 /* Backlight fade in and out rates */ +#define ADP8860_BLMX1 0x09 /* Backlight (Brightness Level 1-daylight) maximum current */ +#define ADP8860_BLDM1 0x0A /* Backlight (Brightness Level 1-daylight) dim current */ +#define ADP8860_BLMX2 0x0B /* Backlight (Brightness Level 2-office) maximum current */ +#define ADP8860_BLDM2 0x0C /* Backlight (Brightness Level 2-office) dim current */ +#define ADP8860_BLMX3 0x0D /* Backlight (Brightness Level 3-dark) maximum current */ +#define ADP8860_BLDM3 0x0E /* Backlight (Brightness Level 3-dark) dim current */ +#define ADP8860_ISCFR 0x0F /* Independent sink current fade control register */ +#define ADP8860_ISCC 0x10 /* Independent sink current control register */ +#define ADP8860_ISCT1 0x11 /* Independent Sink Current Timer Register LED[7:5] */ +#define ADP8860_ISCT2 0x12 /* Independent Sink Current Timer Register LED[4:1] */ +#define ADP8860_ISCF 0x13 /* Independent sink current fade register */ +#define ADP8860_ISC7 0x14 /* Independent Sink Current LED7 */ +#define ADP8860_ISC6 0x15 /* Independent Sink Current LED6 */ +#define ADP8860_ISC5 0x16 /* Independent Sink Current LED5 */ +#define ADP8860_ISC4 0x17 /* Independent Sink Current LED4 */ +#define ADP8860_ISC3 0x18 /* Independent Sink Current LED3 */ +#define ADP8860_ISC2 0x19 /* Independent Sink Current LED2 */ +#define ADP8860_ISC1 0x1A /* Independent Sink Current LED1 */ +#define ADP8860_CCFG 0x1B /* Comparator configuration */ +#define ADP8860_CCFG2 0x1C /* Second comparator configuration */ +#define ADP8860_L2_TRP 0x1D /* L2 comparator reference */ +#define ADP8860_L2_HYS 0x1E /* L2 hysteresis */ +#define ADP8860_L3_TRP 0x1F /* L3 comparator reference */ +#define ADP8860_L3_HYS 0x20 /* L3 hysteresis */ +#define ADP8860_PH1LEVL 0x21 /* First phototransistor ambient light level-low byte register */ +#define ADP8860_PH1LEVH 0x22 /* First phototransistor ambient light level-high byte register */ +#define ADP8860_PH2LEVL 0x23 /* Second phototransistor ambient light level-low byte register */ +#define ADP8860_PH2LEVH 0x24 /* Second phototransistor ambient light level-high byte register */ + +#define ADP8860_MANUFID 0x0 /* Analog Devices ADP8860 Manufacturer ID */ +#define ADP8861_MANUFID 0x4 /* Analog Devices ADP8861 Manufacturer ID */ +#define ADP8863_MANUFID 0x2 /* Analog Devices ADP8863 Manufacturer ID */ + +#define ADP8860_DEVID(x) ((x) & 0xF) +#define ADP8860_MANID(x) ((x) >> 4) + +/* MDCR Device mode and status */ +#define INT_CFG (1 << 6) +#define NSTBY (1 << 5) +#define DIM_EN (1 << 4) +#define GDWN_DIS (1 << 3) +#define SIS_EN (1 << 2) +#define CMP_AUTOEN (1 << 1) +#define BLEN (1 << 0) + +/* ADP8860_CCFG Main ALS comparator level enable */ +#define L3_EN (1 << 1) +#define L2_EN (1 << 0) + +#define CFGR_BLV_SHIFT 3 +#define CFGR_BLV_MASK 0x3 +#define ADP8860_FLAG_LED_MASK 0xFF + +#define FADE_VAL(in, out) ((0xF & (in)) | ((0xF & (out)) << 4)) +#define BL_CFGR_VAL(law, blv) ((((blv) & CFGR_BLV_MASK) << CFGR_BLV_SHIFT) | ((0x3 & (law)) << 1)) +#define ALS_CCFG_VAL(filt) ((0x7 & filt) << 5) + +enum { + adp8860, + adp8861, + adp8863 +}; + +struct adp8860_led { + struct led_classdev cdev; + struct work_struct work; + struct i2c_client *client; + enum led_brightness new_brightness; + int id; + int flags; +}; + +struct adp8860_bl { + struct i2c_client *client; + struct backlight_device *bl; + struct adp8860_led *led; + struct adp8860_backlight_platform_data *pdata; + struct mutex lock; + unsigned long cached_daylight_max; + int id; + int revid; + int current_brightness; + unsigned en_ambl_sens:1; + unsigned gdwn_dis:1; +}; + +static int adp8860_read(struct i2c_client *client, int reg, uint8_t *val) +{ + int ret; + + ret = i2c_smbus_read_byte_data(client, reg); + if (ret < 0) { + dev_err(&client->dev, "failed reading at 0x%02x\n", reg); + return ret; + } + + *val = (uint8_t)ret; + return 0; +} + +static int adp8860_write(struct i2c_client *client, u8 reg, u8 val) +{ + return i2c_smbus_write_byte_data(client, reg, val); +} + +static int adp8860_set_bits(struct i2c_client *client, int reg, uint8_t bit_mask) +{ + struct adp8860_bl *data = i2c_get_clientdata(client); + uint8_t reg_val; + int ret; + + mutex_lock(&data->lock); + + ret = adp8860_read(client, reg, ®_val); + + if (!ret && ((reg_val & bit_mask) == 0)) { + reg_val |= bit_mask; + ret = adp8860_write(client, reg, reg_val); + } + + mutex_unlock(&data->lock); + return ret; +} + +static int adp8860_clr_bits(struct i2c_client *client, int reg, uint8_t bit_mask) +{ + struct adp8860_bl *data = i2c_get_clientdata(client); + uint8_t reg_val; + int ret; + + mutex_lock(&data->lock); + + ret = adp8860_read(client, reg, ®_val); + + if (!ret && (reg_val & bit_mask)) { + reg_val &= ~bit_mask; + ret = adp8860_write(client, reg, reg_val); + } + + mutex_unlock(&data->lock); + return ret; +} + +/* + * Independent sink / LED + */ +#if defined(ADP8860_USE_LEDS) +static void adp8860_led_work(struct work_struct *work) +{ + struct adp8860_led *led = container_of(work, struct adp8860_led, work); + adp8860_write(led->client, ADP8860_ISC1 - led->id + 1, + led->new_brightness >> 1); +} + +static void adp8860_led_set(struct led_classdev *led_cdev, + enum led_brightness value) +{ + struct adp8860_led *led; + + led = container_of(led_cdev, struct adp8860_led, cdev); + led->new_brightness = value; + schedule_work(&led->work); +} + +static int adp8860_led_setup(struct adp8860_led *led) +{ + struct i2c_client *client = led->client; + int ret = 0; + + ret = adp8860_write(client, ADP8860_ISC1 - led->id + 1, 0); + ret |= adp8860_set_bits(client, ADP8860_ISCC, 1 << (led->id - 1)); + + if (led->id > 4) + ret |= adp8860_set_bits(client, ADP8860_ISCT1, + (led->flags & 0x3) << ((led->id - 5) * 2)); + else + ret |= adp8860_set_bits(client, ADP8860_ISCT2, + (led->flags & 0x3) << ((led->id - 1) * 2)); + + return ret; +} + +static int __devinit adp8860_led_probe(struct i2c_client *client) +{ + struct adp8860_backlight_platform_data *pdata = + client->dev.platform_data; + struct adp8860_bl *data = i2c_get_clientdata(client); + struct adp8860_led *led, *led_dat; + struct led_info *cur_led; + int ret, i; + + led = kzalloc(sizeof(*led) * pdata->num_leds, GFP_KERNEL); + if (led == NULL) { + dev_err(&client->dev, "failed to alloc memory\n"); + return -ENOMEM; + } + + ret = adp8860_write(client, ADP8860_ISCFR, pdata->led_fade_law); + ret = adp8860_write(client, ADP8860_ISCT1, + (pdata->led_on_time & 0x3) << 6); + ret |= adp8860_write(client, ADP8860_ISCF, + FADE_VAL(pdata->led_fade_in, pdata->led_fade_out)); + + if (ret) { + dev_err(&client->dev, "failed to write\n"); + goto err_free; + } + + for (i = 0; i < pdata->num_leds; ++i) { + cur_led = &pdata->leds[i]; + led_dat = &led[i]; + + led_dat->id = cur_led->flags & ADP8860_FLAG_LED_MASK; + + if (led_dat->id > 7 || led_dat->id < 1) { + dev_err(&client->dev, "Invalid LED ID %d\n", + led_dat->id); + goto err; + } + + if (pdata->bl_led_assign & (1 << (led_dat->id - 1))) { + dev_err(&client->dev, "LED %d used by Backlight\n", + led_dat->id); + goto err; + } + + led_dat->cdev.name = cur_led->name; + led_dat->cdev.default_trigger = cur_led->default_trigger; + led_dat->cdev.brightness_set = adp8860_led_set; + led_dat->cdev.brightness = LED_OFF; + led_dat->flags = cur_led->flags >> FLAG_OFFT_SHIFT; + led_dat->client = client; + led_dat->new_brightness = LED_OFF; + INIT_WORK(&led_dat->work, adp8860_led_work); + + ret = led_classdev_register(&client->dev, &led_dat->cdev); + if (ret) { + dev_err(&client->dev, "failed to register LED %d\n", + led_dat->id); + goto err; + } + + ret = adp8860_led_setup(led_dat); + if (ret) { + dev_err(&client->dev, "failed to write\n"); + i++; + goto err; + } + } + + data->led = led; + + return 0; + + err: + for (i = i - 1; i >= 0; --i) { + led_classdev_unregister(&led[i].cdev); + cancel_work_sync(&led[i].work); + } + + err_free: + kfree(led); + + return ret; +} + +static int __devexit adp8860_led_remove(struct i2c_client *client) +{ + struct adp8860_backlight_platform_data *pdata = + client->dev.platform_data; + struct adp8860_bl *data = i2c_get_clientdata(client); + int i; + + for (i = 0; i < pdata->num_leds; i++) { + led_classdev_unregister(&data->led[i].cdev); + cancel_work_sync(&data->led[i].work); + } + + kfree(data->led); + return 0; +} +#else +static int __devinit adp8860_led_probe(struct i2c_client *client) +{ + return 0; +} + +static int __devexit adp8860_led_remove(struct i2c_client *client) +{ + return 0; +} +#endif + +static int adp8860_bl_set(struct backlight_device *bl, int brightness) +{ + struct adp8860_bl *data = bl_get_data(bl); + struct i2c_client *client = data->client; + int ret = 0; + + if (data->en_ambl_sens) { + if ((brightness > 0) && (brightness < ADP8860_MAX_BRIGHTNESS)) { + /* Disable Ambient Light auto adjust */ + ret |= adp8860_clr_bits(client, ADP8860_MDCR, + CMP_AUTOEN); + ret |= adp8860_write(client, ADP8860_BLMX1, brightness); + } else { + /* + * MAX_BRIGHTNESS -> Enable Ambient Light auto adjust + * restore daylight l1 sysfs brightness + */ + ret |= adp8860_write(client, ADP8860_BLMX1, + data->cached_daylight_max); + ret |= adp8860_set_bits(client, ADP8860_MDCR, + CMP_AUTOEN); + } + } else + ret |= adp8860_write(client, ADP8860_BLMX1, brightness); + + if (data->current_brightness && brightness == 0) + ret |= adp8860_set_bits(client, + ADP8860_MDCR, DIM_EN); + else if (data->current_brightness == 0 && brightness) + ret |= adp8860_clr_bits(client, + ADP8860_MDCR, DIM_EN); + + if (!ret) + data->current_brightness = brightness; + + return ret; +} + +static int adp8860_bl_update_status(struct backlight_device *bl) +{ + int brightness = bl->props.brightness; + if (bl->props.power != FB_BLANK_UNBLANK) + brightness = 0; + + if (bl->props.fb_blank != FB_BLANK_UNBLANK) + brightness = 0; + + return adp8860_bl_set(bl, brightness); +} + +static int adp8860_bl_get_brightness(struct backlight_device *bl) +{ + struct adp8860_bl *data = bl_get_data(bl); + + return data->current_brightness; +} + +static const struct backlight_ops adp8860_bl_ops = { + .update_status = adp8860_bl_update_status, + .get_brightness = adp8860_bl_get_brightness, +}; + +static int adp8860_bl_setup(struct backlight_device *bl) +{ + struct adp8860_bl *data = bl_get_data(bl); + struct i2c_client *client = data->client; + struct adp8860_backlight_platform_data *pdata = data->pdata; + int ret = 0; + + ret |= adp8860_write(client, ADP8860_BLSEN, ~pdata->bl_led_assign); + ret |= adp8860_write(client, ADP8860_BLMX1, pdata->l1_daylight_max); + ret |= adp8860_write(client, ADP8860_BLDM1, pdata->l1_daylight_dim); + + if (data->en_ambl_sens) { + data->cached_daylight_max = pdata->l1_daylight_max; + ret |= adp8860_write(client, ADP8860_BLMX2, + pdata->l2_office_max); + ret |= adp8860_write(client, ADP8860_BLDM2, + pdata->l2_office_dim); + ret |= adp8860_write(client, ADP8860_BLMX3, + pdata->l3_dark_max); + ret |= adp8860_write(client, ADP8860_BLDM3, + pdata->l3_dark_dim); + + ret |= adp8860_write(client, ADP8860_L2_TRP, pdata->l2_trip); + ret |= adp8860_write(client, ADP8860_L2_HYS, pdata->l2_hyst); + ret |= adp8860_write(client, ADP8860_L3_TRP, pdata->l3_trip); + ret |= adp8860_write(client, ADP8860_L3_HYS, pdata->l3_hyst); + ret |= adp8860_write(client, ADP8860_CCFG, L2_EN | L3_EN | + ALS_CCFG_VAL(pdata->abml_filt)); + } + + ret |= adp8860_write(client, ADP8860_CFGR, + BL_CFGR_VAL(pdata->bl_fade_law, 0)); + + ret |= adp8860_write(client, ADP8860_BLFR, FADE_VAL(pdata->bl_fade_in, + pdata->bl_fade_out)); + + ret |= adp8860_set_bits(client, ADP8860_MDCR, BLEN | DIM_EN | NSTBY | + (data->gdwn_dis ? GDWN_DIS : 0)); + + return ret; +} + +static ssize_t adp8860_show(struct device *dev, char *buf, int reg) +{ + struct adp8860_bl *data = dev_get_drvdata(dev); + int error; + uint8_t reg_val; + + mutex_lock(&data->lock); + error = adp8860_read(data->client, reg, ®_val); + mutex_unlock(&data->lock); + + if (error < 0) + return error; + + return sprintf(buf, "%u\n", reg_val); +} + +static ssize_t adp8860_store(struct device *dev, const char *buf, + size_t count, int reg) +{ + struct adp8860_bl *data = dev_get_drvdata(dev); + unsigned long val; + int ret; + + ret = strict_strtoul(buf, 10, &val); + if (ret) + return ret; + + mutex_lock(&data->lock); + adp8860_write(data->client, reg, val); + mutex_unlock(&data->lock); + + return count; +} + +static ssize_t adp8860_bl_l3_dark_max_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return adp8860_show(dev, buf, ADP8860_BLMX3); +} + +static ssize_t adp8860_bl_l3_dark_max_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + return adp8860_store(dev, buf, count, ADP8860_BLMX3); +} + +static DEVICE_ATTR(l3_dark_max, 0664, adp8860_bl_l3_dark_max_show, + adp8860_bl_l3_dark_max_store); + +static ssize_t adp8860_bl_l2_office_max_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return adp8860_show(dev, buf, ADP8860_BLMX2); +} + +static ssize_t adp8860_bl_l2_office_max_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + return adp8860_store(dev, buf, count, ADP8860_BLMX2); +} +static DEVICE_ATTR(l2_office_max, 0664, adp8860_bl_l2_office_max_show, + adp8860_bl_l2_office_max_store); + +static ssize_t adp8860_bl_l1_daylight_max_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return adp8860_show(dev, buf, ADP8860_BLMX1); +} + +static ssize_t adp8860_bl_l1_daylight_max_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct adp8860_bl *data = dev_get_drvdata(dev); + + strict_strtoul(buf, 10, &data->cached_daylight_max); + return adp8860_store(dev, buf, count, ADP8860_BLMX1); +} +static DEVICE_ATTR(l1_daylight_max, 0664, adp8860_bl_l1_daylight_max_show, + adp8860_bl_l1_daylight_max_store); + +static ssize_t adp8860_bl_l3_dark_dim_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return adp8860_show(dev, buf, ADP8860_BLDM3); +} + +static ssize_t adp8860_bl_l3_dark_dim_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + return adp8860_store(dev, buf, count, ADP8860_BLDM3); +} +static DEVICE_ATTR(l3_dark_dim, 0664, adp8860_bl_l3_dark_dim_show, + adp8860_bl_l3_dark_dim_store); + +static ssize_t adp8860_bl_l2_office_dim_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return adp8860_show(dev, buf, ADP8860_BLDM2); +} + +static ssize_t adp8860_bl_l2_office_dim_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + return adp8860_store(dev, buf, count, ADP8860_BLDM2); +} +static DEVICE_ATTR(l2_office_dim, 0664, adp8860_bl_l2_office_dim_show, + adp8860_bl_l2_office_dim_store); + +static ssize_t adp8860_bl_l1_daylight_dim_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return adp8860_show(dev, buf, ADP8860_BLDM1); +} + +static ssize_t adp8860_bl_l1_daylight_dim_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + return adp8860_store(dev, buf, count, ADP8860_BLDM1); +} +static DEVICE_ATTR(l1_daylight_dim, 0664, adp8860_bl_l1_daylight_dim_show, + adp8860_bl_l1_daylight_dim_store); + +#ifdef ADP8860_EXT_FEATURES +static ssize_t adp8860_bl_ambient_light_level_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct adp8860_bl *data = dev_get_drvdata(dev); + int error; + uint8_t reg_val; + uint16_t ret_val; + + mutex_lock(&data->lock); + error = adp8860_read(data->client, ADP8860_PH1LEVL, ®_val); + ret_val = reg_val; + error |= adp8860_read(data->client, ADP8860_PH1LEVH, ®_val); + mutex_unlock(&data->lock); + + if (error < 0) + return error; + + /* Return 13-bit conversion value for the first light sensor */ + ret_val += (reg_val & 0x1F) << 8; + + return sprintf(buf, "%u\n", ret_val); +} +static DEVICE_ATTR(ambient_light_level, 0444, + adp8860_bl_ambient_light_level_show, NULL); + +static ssize_t adp8860_bl_ambient_light_zone_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct adp8860_bl *data = dev_get_drvdata(dev); + int error; + uint8_t reg_val; + + mutex_lock(&data->lock); + error = adp8860_read(data->client, ADP8860_CFGR, ®_val); + mutex_unlock(&data->lock); + + if (error < 0) + return error; + + return sprintf(buf, "%u\n", + ((reg_val >> CFGR_BLV_SHIFT) & CFGR_BLV_MASK) + 1); +} + +static ssize_t adp8860_bl_ambient_light_zone_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct adp8860_bl *data = dev_get_drvdata(dev); + unsigned long val; + uint8_t reg_val; + int ret; + + ret = strict_strtoul(buf, 10, &val); + if (ret) + return ret; + + if (val == 0) { + /* Enable automatic ambient light sensing */ + adp8860_set_bits(data->client, ADP8860_MDCR, CMP_AUTOEN); + } else if ((val > 0) && (val < 6)) { + /* Disable automatic ambient light sensing */ + adp8860_clr_bits(data->client, ADP8860_MDCR, CMP_AUTOEN); + + /* Set user supplied ambient light zone */ + mutex_lock(&data->lock); + adp8860_read(data->client, ADP8860_CFGR, ®_val); + reg_val &= ~(CFGR_BLV_MASK << CFGR_BLV_SHIFT); + reg_val |= val << CFGR_BLV_SHIFT; + adp8860_write(data->client, ADP8860_CFGR, reg_val); + mutex_unlock(&data->lock); + } + + return count; +} +static DEVICE_ATTR(ambient_light_zone, 0664, + adp8860_bl_ambient_light_zone_show, + adp8860_bl_ambient_light_zone_store); +#endif + +static struct attribute *adp8860_bl_attributes[] = { + &dev_attr_l3_dark_max.attr, + &dev_attr_l3_dark_dim.attr, + &dev_attr_l2_office_max.attr, + &dev_attr_l2_office_dim.attr, + &dev_attr_l1_daylight_max.attr, + &dev_attr_l1_daylight_dim.attr, +#ifdef ADP8860_EXT_FEATURES + &dev_attr_ambient_light_level.attr, + &dev_attr_ambient_light_zone.attr, +#endif + NULL +}; + +static const struct attribute_group adp8860_bl_attr_group = { + .attrs = adp8860_bl_attributes, +}; + +static int __devinit adp8860_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct backlight_device *bl; + struct adp8860_bl *data; + struct adp8860_backlight_platform_data *pdata = + client->dev.platform_data; + struct backlight_properties props; + uint8_t reg_val; + int ret; + + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_BYTE_DATA)) { + dev_err(&client->dev, "SMBUS Byte Data not Supported\n"); + return -EIO; + } + + if (!pdata) { + dev_err(&client->dev, "no platform data?\n"); + return -EINVAL; + } + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (data == NULL) + return -ENOMEM; + + ret = adp8860_read(client, ADP8860_MFDVID, ®_val); + if (ret < 0) + goto out2; + + switch (ADP8860_MANID(reg_val)) { + case ADP8863_MANUFID: + data->gdwn_dis = !!pdata->gdwn_dis; + case ADP8860_MANUFID: + data->en_ambl_sens = !!pdata->en_ambl_sens; + break; + case ADP8861_MANUFID: + data->gdwn_dis = !!pdata->gdwn_dis; + break; + default: + dev_err(&client->dev, "failed to probe\n"); + ret = -ENODEV; + goto out2; + } + + /* It's confirmed that the DEVID field is actually a REVID */ + + data->revid = ADP8860_DEVID(reg_val); + data->client = client; + data->pdata = pdata; + data->id = id->driver_data; + data->current_brightness = 0; + i2c_set_clientdata(client, data); + + memset(&props, 0, sizeof(props)); + props.max_brightness = ADP8860_MAX_BRIGHTNESS; + + mutex_init(&data->lock); + + bl = backlight_device_register(dev_driver_string(&client->dev), + &client->dev, data, &adp8860_bl_ops, &props); + if (IS_ERR(bl)) { + dev_err(&client->dev, "failed to register backlight\n"); + ret = PTR_ERR(bl); + goto out2; + } + + bl->props.max_brightness = + bl->props.brightness = ADP8860_MAX_BRIGHTNESS; + + data->bl = bl; + + if (data->en_ambl_sens) + ret = sysfs_create_group(&bl->dev.kobj, + &adp8860_bl_attr_group); + + if (ret) { + dev_err(&client->dev, "failed to register sysfs\n"); + goto out1; + } + + ret = adp8860_bl_setup(bl); + if (ret) { + ret = -EIO; + goto out; + } + + backlight_update_status(bl); + + dev_info(&client->dev, "%s Rev.%d Backlight\n", + client->name, data->revid); + + if (pdata->num_leds) + adp8860_led_probe(client); + + return 0; + +out: + if (data->en_ambl_sens) + sysfs_remove_group(&data->bl->dev.kobj, + &adp8860_bl_attr_group); +out1: + backlight_device_unregister(bl); +out2: + kfree(data); + + return ret; +} + +static int __devexit adp8860_remove(struct i2c_client *client) +{ + struct adp8860_bl *data = i2c_get_clientdata(client); + + adp8860_clr_bits(client, ADP8860_MDCR, NSTBY); + + if (data->led) + adp8860_led_remove(client); + + if (data->en_ambl_sens) + sysfs_remove_group(&data->bl->dev.kobj, + &adp8860_bl_attr_group); + + backlight_device_unregister(data->bl); + kfree(data); + + return 0; +} + +#ifdef CONFIG_PM +static int adp8860_i2c_suspend(struct i2c_client *client, pm_message_t message) +{ + adp8860_clr_bits(client, ADP8860_MDCR, NSTBY); + + return 0; +} + +static int adp8860_i2c_resume(struct i2c_client *client) +{ + adp8860_set_bits(client, ADP8860_MDCR, NSTBY); + + return 0; +} +#else +#define adp8860_i2c_suspend NULL +#define adp8860_i2c_resume NULL +#endif + +static const struct i2c_device_id adp8860_id[] = { + { "adp8860", adp8860 }, + { "adp8861", adp8861 }, + { "adp8863", adp8863 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, adp8860_id); + +static struct i2c_driver adp8860_driver = { + .driver = { + .name = KBUILD_MODNAME, + }, + .probe = adp8860_probe, + .remove = __devexit_p(adp8860_remove), + .suspend = adp8860_i2c_suspend, + .resume = adp8860_i2c_resume, + .id_table = adp8860_id, +}; + +static int __init adp8860_init(void) +{ + return i2c_add_driver(&adp8860_driver); +} +module_init(adp8860_init); + +static void __exit adp8860_exit(void) +{ + i2c_del_driver(&adp8860_driver); +} +module_exit(adp8860_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); +MODULE_DESCRIPTION("ADP8860 Backlight driver"); +MODULE_ALIAS("i2c:adp8860-backlight"); diff --git a/drivers/video/backlight/adx_bl.c b/drivers/video/backlight/adx_bl.c index 7f4a7c30a98b..fe9af129c5dd 100644 --- a/drivers/video/backlight/adx_bl.c +++ b/drivers/video/backlight/adx_bl.c @@ -107,8 +107,8 @@ static int __devinit adx_backlight_probe(struct platform_device *pdev) props.max_brightness = 0xff; bldev = backlight_device_register(dev_name(&pdev->dev), &pdev->dev, bl, &adx_backlight_ops, &props); - if (!bldev) { - ret = -ENOMEM; + if (IS_ERR(bldev)) { + ret = PTR_ERR(bldev); goto out; } diff --git a/drivers/video/backlight/ep93xx_bl.c b/drivers/video/backlight/ep93xx_bl.c new file mode 100644 index 000000000000..b0cc49184803 --- /dev/null +++ b/drivers/video/backlight/ep93xx_bl.c @@ -0,0 +1,160 @@ +/* + * Driver for the Cirrus EP93xx lcd backlight + * + * Copyright (c) 2010 H Hartley Sweeten <hsweeten@visionengravers.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This driver controls the pulse width modulated brightness control output, + * BRIGHT, on the Cirrus EP9307, EP9312, and EP9315 processors. + */ + + +#include <linux/platform_device.h> +#include <linux/io.h> +#include <linux/fb.h> +#include <linux/backlight.h> + +#include <mach/hardware.h> + +#define EP93XX_RASTER_REG(x) (EP93XX_RASTER_BASE + (x)) +#define EP93XX_RASTER_BRIGHTNESS EP93XX_RASTER_REG(0x20) + +#define EP93XX_MAX_COUNT 255 +#define EP93XX_MAX_BRIGHT 255 +#define EP93XX_DEF_BRIGHT 128 + +struct ep93xxbl { + void __iomem *mmio; + int brightness; +}; + +static int ep93xxbl_set(struct backlight_device *bl, int brightness) +{ + struct ep93xxbl *ep93xxbl = bl_get_data(bl); + + __raw_writel((brightness << 8) | EP93XX_MAX_COUNT, ep93xxbl->mmio); + + ep93xxbl->brightness = brightness; + + return 0; +} + +static int ep93xxbl_update_status(struct backlight_device *bl) +{ + int brightness = bl->props.brightness; + + if (bl->props.power != FB_BLANK_UNBLANK || + bl->props.fb_blank != FB_BLANK_UNBLANK) + brightness = 0; + + return ep93xxbl_set(bl, brightness); +} + +static int ep93xxbl_get_brightness(struct backlight_device *bl) +{ + struct ep93xxbl *ep93xxbl = bl_get_data(bl); + + return ep93xxbl->brightness; +} + +static const struct backlight_ops ep93xxbl_ops = { + .update_status = ep93xxbl_update_status, + .get_brightness = ep93xxbl_get_brightness, +}; + +static int __init ep93xxbl_probe(struct platform_device *dev) +{ + struct ep93xxbl *ep93xxbl; + struct backlight_device *bl; + struct backlight_properties props; + + ep93xxbl = devm_kzalloc(&dev->dev, sizeof(*ep93xxbl), GFP_KERNEL); + if (!ep93xxbl) + return -ENOMEM; + + /* + * This register is located in the range already ioremap'ed by + * the framebuffer driver. A MFD driver seems a bit of overkill + * to handle this so use the static I/O mapping; this address + * is already virtual. + * + * NOTE: No locking is required; the framebuffer does not touch + * this register. + */ + ep93xxbl->mmio = EP93XX_RASTER_BRIGHTNESS; + + memset(&props, 0, sizeof(struct backlight_properties)); + props.max_brightness = EP93XX_MAX_BRIGHT; + bl = backlight_device_register(dev->name, &dev->dev, ep93xxbl, + &ep93xxbl_ops, &props); + if (IS_ERR(bl)) + return PTR_ERR(bl); + + bl->props.brightness = EP93XX_DEF_BRIGHT; + + platform_set_drvdata(dev, bl); + + ep93xxbl_update_status(bl); + + return 0; +} + +static int ep93xxbl_remove(struct platform_device *dev) +{ + struct backlight_device *bl = platform_get_drvdata(dev); + + backlight_device_unregister(bl); + platform_set_drvdata(dev, NULL); + return 0; +} + +#ifdef CONFIG_PM +static int ep93xxbl_suspend(struct platform_device *dev, pm_message_t state) +{ + struct backlight_device *bl = platform_get_drvdata(dev); + + return ep93xxbl_set(bl, 0); +} + +static int ep93xxbl_resume(struct platform_device *dev) +{ + struct backlight_device *bl = platform_get_drvdata(dev); + + backlight_update_status(bl); + return 0; +} +#else +#define ep93xxbl_suspend NULL +#define ep93xxbl_resume NULL +#endif + +static struct platform_driver ep93xxbl_driver = { + .driver = { + .name = "ep93xx-bl", + .owner = THIS_MODULE, + }, + .probe = ep93xxbl_probe, + .remove = __devexit_p(ep93xxbl_remove), + .suspend = ep93xxbl_suspend, + .resume = ep93xxbl_resume, +}; + +static int __init ep93xxbl_init(void) +{ + return platform_driver_register(&ep93xxbl_driver); +} +module_init(ep93xxbl_init); + +static void __exit ep93xxbl_exit(void) +{ + platform_driver_unregister(&ep93xxbl_driver); +} +module_exit(ep93xxbl_exit); + +MODULE_DESCRIPTION("EP93xx Backlight Driver"); +MODULE_AUTHOR("H Hartley Sweeten <hsweeten@visionengravers.com>"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:ep93xx-bl"); diff --git a/drivers/video/backlight/l4f00242t03.c b/drivers/video/backlight/l4f00242t03.c index bcdb12c93efd..9093ef0fa869 100644 --- a/drivers/video/backlight/l4f00242t03.c +++ b/drivers/video/backlight/l4f00242t03.c @@ -125,8 +125,7 @@ static int __devinit l4f00242t03_probe(struct spi_device *spi) if (priv == NULL) { dev_err(&spi->dev, "No memory for this device.\n"); - ret = -ENOMEM; - goto err; + return -ENOMEM; } dev_set_drvdata(&spi->dev, priv); @@ -139,7 +138,7 @@ static int __devinit l4f00242t03_probe(struct spi_device *spi) if (ret) { dev_err(&spi->dev, "Unable to get the lcd l4f00242t03 reset gpio.\n"); - return ret; + goto err; } ret = gpio_direction_output(pdata->reset_gpio, 1); @@ -151,7 +150,7 @@ static int __devinit l4f00242t03_probe(struct spi_device *spi) if (ret) { dev_err(&spi->dev, "Unable to get the lcd l4f00242t03 data en gpio.\n"); - return ret; + goto err2; } ret = gpio_direction_output(pdata->data_enable_gpio, 0); @@ -222,9 +221,9 @@ static int __devexit l4f00242t03_remove(struct spi_device *spi) gpio_free(pdata->reset_gpio); if (priv->io_reg) - regulator_put(priv->core_reg); - if (priv->core_reg) regulator_put(priv->io_reg); + if (priv->core_reg) + regulator_put(priv->core_reg); kfree(priv); diff --git a/drivers/video/backlight/locomolcd.c b/drivers/video/backlight/locomolcd.c index 7571bc26071e..d2f59015d517 100644 --- a/drivers/video/backlight/locomolcd.c +++ b/drivers/video/backlight/locomolcd.c @@ -2,7 +2,7 @@ * Backlight control code for Sharp Zaurus SL-5500 * * Copyright 2005 John Lenz <lenz@cs.wisc.edu> - * Maintainer: Pavel Machek <pavel@suse.cz> (unless John wants to :-) + * Maintainer: Pavel Machek <pavel@ucw.cz> (unless John wants to :-) * GPL v2 * * This driver assumes single CPU. That's okay, because collie is @@ -246,6 +246,6 @@ static void __exit locomolcd_exit(void) module_init(locomolcd_init); module_exit(locomolcd_exit); -MODULE_AUTHOR("John Lenz <lenz@cs.wisc.edu>, Pavel Machek <pavel@suse.cz>"); +MODULE_AUTHOR("John Lenz <lenz@cs.wisc.edu>, Pavel Machek <pavel@ucw.cz>"); MODULE_DESCRIPTION("Collie LCD driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/video/backlight/max8925_bl.c b/drivers/video/backlight/max8925_bl.c index b5accc957ad3..b2b2c7ba1f63 100644 --- a/drivers/video/backlight/max8925_bl.c +++ b/drivers/video/backlight/max8925_bl.c @@ -162,6 +162,7 @@ static int __devinit max8925_backlight_probe(struct platform_device *pdev) backlight_update_status(bl); return 0; out: + backlight_device_unregister(bl); kfree(data); return ret; } diff --git a/drivers/video/backlight/mbp_nvidia_bl.c b/drivers/video/backlight/mbp_nvidia_bl.c index 1b5d3fe6bbbc..9fb533f6373e 100644 --- a/drivers/video/backlight/mbp_nvidia_bl.c +++ b/drivers/video/backlight/mbp_nvidia_bl.c @@ -141,7 +141,7 @@ static const struct dmi_system_id __initdata mbp_device_table[] = { .callback = mbp_dmi_match, .ident = "MacBook 1,1", .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), + DMI_MATCH(DMI_SYS_VENDOR, "Apple Computer, Inc."), DMI_MATCH(DMI_PRODUCT_NAME, "MacBook1,1"), }, .driver_data = (void *)&intel_chipset_data, @@ -184,6 +184,42 @@ static const struct dmi_system_id __initdata mbp_device_table[] = { }, { .callback = mbp_dmi_match, + .ident = "MacBookPro 1,1", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro1,1"), + }, + .driver_data = (void *)&intel_chipset_data, + }, + { + .callback = mbp_dmi_match, + .ident = "MacBookPro 1,2", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro1,2"), + }, + .driver_data = (void *)&intel_chipset_data, + }, + { + .callback = mbp_dmi_match, + .ident = "MacBookPro 2,1", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro2,1"), + }, + .driver_data = (void *)&intel_chipset_data, + }, + { + .callback = mbp_dmi_match, + .ident = "MacBookPro 2,2", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro2,2"), + }, + .driver_data = (void *)&intel_chipset_data, + }, + { + .callback = mbp_dmi_match, .ident = "MacBookPro 3,1", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), @@ -238,6 +274,15 @@ static const struct dmi_system_id __initdata mbp_device_table[] = { }, { .callback = mbp_dmi_match, + .ident = "MacBook 6,1", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "MacBook6,1"), + }, + .driver_data = (void *)&nvidia_chipset_data, + }, + { + .callback = mbp_dmi_match, .ident = "MacBookAir 2,1", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), diff --git a/drivers/video/backlight/pcf50633-backlight.c b/drivers/video/backlight/pcf50633-backlight.c new file mode 100644 index 000000000000..3c424f7efdcc --- /dev/null +++ b/drivers/video/backlight/pcf50633-backlight.c @@ -0,0 +1,190 @@ +/* + * Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de> + * PCF50633 backlight device driver + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/platform_device.h> + +#include <linux/backlight.h> +#include <linux/fb.h> + +#include <linux/mfd/pcf50633/core.h> +#include <linux/mfd/pcf50633/backlight.h> + +struct pcf50633_bl { + struct pcf50633 *pcf; + struct backlight_device *bl; + + unsigned int brightness; + unsigned int brightness_limit; +}; + +/* + * pcf50633_bl_set_brightness_limit + * + * Update the brightness limit for the pc50633 backlight. The actual brightness + * will not go above the limit. This is useful to limit power drain for example + * on low battery. + * + * @dev: Pointer to a pcf50633 device + * @limit: The brightness limit. Valid values are 0-63 + */ +int pcf50633_bl_set_brightness_limit(struct pcf50633 *pcf, unsigned int limit) +{ + struct pcf50633_bl *pcf_bl = platform_get_drvdata(pcf->bl_pdev); + + if (!pcf_bl) + return -ENODEV; + + pcf_bl->brightness_limit = limit & 0x3f; + backlight_update_status(pcf_bl->bl); + + return 0; +} + +static int pcf50633_bl_update_status(struct backlight_device *bl) +{ + struct pcf50633_bl *pcf_bl = bl_get_data(bl); + unsigned int new_brightness; + + + if (bl->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK) || + bl->props.power != FB_BLANK_UNBLANK) + new_brightness = 0; + else if (bl->props.brightness < pcf_bl->brightness_limit) + new_brightness = bl->props.brightness; + else + new_brightness = pcf_bl->brightness_limit; + + + if (pcf_bl->brightness == new_brightness) + return 0; + + if (new_brightness) { + pcf50633_reg_write(pcf_bl->pcf, PCF50633_REG_LEDOUT, + new_brightness); + if (!pcf_bl->brightness) + pcf50633_reg_write(pcf_bl->pcf, PCF50633_REG_LEDENA, 1); + } else { + pcf50633_reg_write(pcf_bl->pcf, PCF50633_REG_LEDENA, 0); + } + + pcf_bl->brightness = new_brightness; + + return 0; +} + +static int pcf50633_bl_get_brightness(struct backlight_device *bl) +{ + struct pcf50633_bl *pcf_bl = bl_get_data(bl); + return pcf_bl->brightness; +} + +static const struct backlight_ops pcf50633_bl_ops = { + .get_brightness = pcf50633_bl_get_brightness, + .update_status = pcf50633_bl_update_status, + .options = BL_CORE_SUSPENDRESUME, +}; + +static int __devinit pcf50633_bl_probe(struct platform_device *pdev) +{ + int ret; + struct pcf50633_bl *pcf_bl; + struct device *parent = pdev->dev.parent; + struct pcf50633_platform_data *pcf50633_data = parent->platform_data; + struct pcf50633_bl_platform_data *pdata = pcf50633_data->backlight_data; + struct backlight_properties bl_props; + + pcf_bl = kzalloc(sizeof(*pcf_bl), GFP_KERNEL); + if (!pcf_bl) + return -ENOMEM; + + bl_props.max_brightness = 0x3f; + bl_props.power = FB_BLANK_UNBLANK; + + if (pdata) { + bl_props.brightness = pdata->default_brightness; + pcf_bl->brightness_limit = pdata->default_brightness_limit; + } else { + bl_props.brightness = 0x3f; + pcf_bl->brightness_limit = 0x3f; + } + + pcf_bl->pcf = dev_to_pcf50633(pdev->dev.parent); + + pcf_bl->bl = backlight_device_register(pdev->name, &pdev->dev, pcf_bl, + &pcf50633_bl_ops, &bl_props); + + if (IS_ERR(pcf_bl->bl)) { + ret = PTR_ERR(pcf_bl->bl); + goto err_free; + } + + platform_set_drvdata(pdev, pcf_bl); + + pcf50633_reg_write(pcf_bl->pcf, PCF50633_REG_LEDDIM, pdata->ramp_time); + + /* Should be different from bl_props.brightness, so we do not exit + * update_status early the first time it's called */ + pcf_bl->brightness = pcf_bl->bl->props.brightness + 1; + + backlight_update_status(pcf_bl->bl); + + return 0; + +err_free: + kfree(pcf_bl); + + return ret; +} + +static int __devexit pcf50633_bl_remove(struct platform_device *pdev) +{ + struct pcf50633_bl *pcf_bl = platform_get_drvdata(pdev); + + backlight_device_unregister(pcf_bl->bl); + + platform_set_drvdata(pdev, NULL); + + kfree(pcf_bl); + + return 0; +} + +static struct platform_driver pcf50633_bl_driver = { + .probe = pcf50633_bl_probe, + .remove = __devexit_p(pcf50633_bl_remove), + .driver = { + .name = "pcf50633-backlight", + }, +}; + +static int __init pcf50633_bl_init(void) +{ + return platform_driver_register(&pcf50633_bl_driver); +} +module_init(pcf50633_bl_init); + +static void __exit pcf50633_bl_exit(void) +{ + platform_driver_unregister(&pcf50633_bl_driver); +} +module_exit(pcf50633_bl_exit); + +MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); +MODULE_DESCRIPTION("PCF50633 backlight driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:pcf50633-backlight"); diff --git a/drivers/video/backlight/s6e63m0.c b/drivers/video/backlight/s6e63m0.c new file mode 100644 index 000000000000..a3128c9cb7ad --- /dev/null +++ b/drivers/video/backlight/s6e63m0.c @@ -0,0 +1,920 @@ +/* + * S6E63M0 AMOLED LCD panel driver. + * + * Author: InKi Dae <inki.dae@samsung.com> + * + * Derived from drivers/video/omap/lcd-apollon.c + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <linux/wait.h> +#include <linux/fb.h> +#include <linux/delay.h> +#include <linux/gpio.h> +#include <linux/spi/spi.h> +#include <linux/irq.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/lcd.h> +#include <linux/backlight.h> + +#include "s6e63m0_gamma.h" + +#define SLEEPMSEC 0x1000 +#define ENDDEF 0x2000 +#define DEFMASK 0xFF00 +#define COMMAND_ONLY 0xFE +#define DATA_ONLY 0xFF + +#define MIN_BRIGHTNESS 0 +#define MAX_BRIGHTNESS 10 + +#define POWER_IS_ON(pwr) ((pwr) <= FB_BLANK_NORMAL) + +struct s6e63m0 { + struct device *dev; + struct spi_device *spi; + unsigned int power; + unsigned int current_brightness; + unsigned int gamma_mode; + unsigned int gamma_table_count; + struct lcd_device *ld; + struct backlight_device *bd; + struct lcd_platform_data *lcd_pd; +}; + +static const unsigned short SEQ_PANEL_CONDITION_SET[] = { + 0xF8, 0x01, + DATA_ONLY, 0x27, + DATA_ONLY, 0x27, + DATA_ONLY, 0x07, + DATA_ONLY, 0x07, + DATA_ONLY, 0x54, + DATA_ONLY, 0x9f, + DATA_ONLY, 0x63, + DATA_ONLY, 0x86, + DATA_ONLY, 0x1a, + DATA_ONLY, 0x33, + DATA_ONLY, 0x0d, + DATA_ONLY, 0x00, + DATA_ONLY, 0x00, + + ENDDEF, 0x0000 +}; + +static const unsigned short SEQ_DISPLAY_CONDITION_SET[] = { + 0xf2, 0x02, + DATA_ONLY, 0x03, + DATA_ONLY, 0x1c, + DATA_ONLY, 0x10, + DATA_ONLY, 0x10, + + 0xf7, 0x03, + DATA_ONLY, 0x00, + DATA_ONLY, 0x00, + + ENDDEF, 0x0000 +}; + +static const unsigned short SEQ_GAMMA_SETTING[] = { + 0xfa, 0x00, + DATA_ONLY, 0x18, + DATA_ONLY, 0x08, + DATA_ONLY, 0x24, + DATA_ONLY, 0x64, + DATA_ONLY, 0x56, + DATA_ONLY, 0x33, + DATA_ONLY, 0xb6, + DATA_ONLY, 0xba, + DATA_ONLY, 0xa8, + DATA_ONLY, 0xac, + DATA_ONLY, 0xb1, + DATA_ONLY, 0x9d, + DATA_ONLY, 0xc1, + DATA_ONLY, 0xc1, + DATA_ONLY, 0xb7, + DATA_ONLY, 0x00, + DATA_ONLY, 0x9c, + DATA_ONLY, 0x00, + DATA_ONLY, 0x9f, + DATA_ONLY, 0x00, + DATA_ONLY, 0xd6, + + 0xfa, 0x01, + + ENDDEF, 0x0000 +}; + +static const unsigned short SEQ_ETC_CONDITION_SET[] = { + 0xf6, 0x00, + DATA_ONLY, 0x8c, + DATA_ONLY, 0x07, + + 0xb3, 0xc, + + 0xb5, 0x2c, + DATA_ONLY, 0x12, + DATA_ONLY, 0x0c, + DATA_ONLY, 0x0a, + DATA_ONLY, 0x10, + DATA_ONLY, 0x0e, + DATA_ONLY, 0x17, + DATA_ONLY, 0x13, + DATA_ONLY, 0x1f, + DATA_ONLY, 0x1a, + DATA_ONLY, 0x2a, + DATA_ONLY, 0x24, + DATA_ONLY, 0x1f, + DATA_ONLY, 0x1b, + DATA_ONLY, 0x1a, + DATA_ONLY, 0x17, + + DATA_ONLY, 0x2b, + DATA_ONLY, 0x26, + DATA_ONLY, 0x22, + DATA_ONLY, 0x20, + DATA_ONLY, 0x3a, + DATA_ONLY, 0x34, + DATA_ONLY, 0x30, + DATA_ONLY, 0x2c, + DATA_ONLY, 0x29, + DATA_ONLY, 0x26, + DATA_ONLY, 0x25, + DATA_ONLY, 0x23, + DATA_ONLY, 0x21, + DATA_ONLY, 0x20, + DATA_ONLY, 0x1e, + DATA_ONLY, 0x1e, + + 0xb6, 0x00, + DATA_ONLY, 0x00, + DATA_ONLY, 0x11, + DATA_ONLY, 0x22, + DATA_ONLY, 0x33, + DATA_ONLY, 0x44, + DATA_ONLY, 0x44, + DATA_ONLY, 0x44, + + DATA_ONLY, 0x55, + DATA_ONLY, 0x55, + DATA_ONLY, 0x66, + DATA_ONLY, 0x66, + DATA_ONLY, 0x66, + DATA_ONLY, 0x66, + DATA_ONLY, 0x66, + DATA_ONLY, 0x66, + + 0xb7, 0x2c, + DATA_ONLY, 0x12, + DATA_ONLY, 0x0c, + DATA_ONLY, 0x0a, + DATA_ONLY, 0x10, + DATA_ONLY, 0x0e, + DATA_ONLY, 0x17, + DATA_ONLY, 0x13, + DATA_ONLY, 0x1f, + DATA_ONLY, 0x1a, + DATA_ONLY, 0x2a, + DATA_ONLY, 0x24, + DATA_ONLY, 0x1f, + DATA_ONLY, 0x1b, + DATA_ONLY, 0x1a, + DATA_ONLY, 0x17, + + DATA_ONLY, 0x2b, + DATA_ONLY, 0x26, + DATA_ONLY, 0x22, + DATA_ONLY, 0x20, + DATA_ONLY, 0x3a, + DATA_ONLY, 0x34, + DATA_ONLY, 0x30, + DATA_ONLY, 0x2c, + DATA_ONLY, 0x29, + DATA_ONLY, 0x26, + DATA_ONLY, 0x25, + DATA_ONLY, 0x23, + DATA_ONLY, 0x21, + DATA_ONLY, 0x20, + DATA_ONLY, 0x1e, + DATA_ONLY, 0x1e, + + 0xb8, 0x00, + DATA_ONLY, 0x00, + DATA_ONLY, 0x11, + DATA_ONLY, 0x22, + DATA_ONLY, 0x33, + DATA_ONLY, 0x44, + DATA_ONLY, 0x44, + DATA_ONLY, 0x44, + + DATA_ONLY, 0x55, + DATA_ONLY, 0x55, + DATA_ONLY, 0x66, + DATA_ONLY, 0x66, + DATA_ONLY, 0x66, + DATA_ONLY, 0x66, + DATA_ONLY, 0x66, + DATA_ONLY, 0x66, + + 0xb9, 0x2c, + DATA_ONLY, 0x12, + DATA_ONLY, 0x0c, + DATA_ONLY, 0x0a, + DATA_ONLY, 0x10, + DATA_ONLY, 0x0e, + DATA_ONLY, 0x17, + DATA_ONLY, 0x13, + DATA_ONLY, 0x1f, + DATA_ONLY, 0x1a, + DATA_ONLY, 0x2a, + DATA_ONLY, 0x24, + DATA_ONLY, 0x1f, + DATA_ONLY, 0x1b, + DATA_ONLY, 0x1a, + DATA_ONLY, 0x17, + + DATA_ONLY, 0x2b, + DATA_ONLY, 0x26, + DATA_ONLY, 0x22, + DATA_ONLY, 0x20, + DATA_ONLY, 0x3a, + DATA_ONLY, 0x34, + DATA_ONLY, 0x30, + DATA_ONLY, 0x2c, + DATA_ONLY, 0x29, + DATA_ONLY, 0x26, + DATA_ONLY, 0x25, + DATA_ONLY, 0x23, + DATA_ONLY, 0x21, + DATA_ONLY, 0x20, + DATA_ONLY, 0x1e, + DATA_ONLY, 0x1e, + + 0xba, 0x00, + DATA_ONLY, 0x00, + DATA_ONLY, 0x11, + DATA_ONLY, 0x22, + DATA_ONLY, 0x33, + DATA_ONLY, 0x44, + DATA_ONLY, 0x44, + DATA_ONLY, 0x44, + + DATA_ONLY, 0x55, + DATA_ONLY, 0x55, + DATA_ONLY, 0x66, + DATA_ONLY, 0x66, + DATA_ONLY, 0x66, + DATA_ONLY, 0x66, + DATA_ONLY, 0x66, + DATA_ONLY, 0x66, + + 0xc1, 0x4d, + DATA_ONLY, 0x96, + DATA_ONLY, 0x1d, + DATA_ONLY, 0x00, + DATA_ONLY, 0x00, + DATA_ONLY, 0x01, + DATA_ONLY, 0xdf, + DATA_ONLY, 0x00, + DATA_ONLY, 0x00, + DATA_ONLY, 0x03, + DATA_ONLY, 0x1f, + DATA_ONLY, 0x00, + DATA_ONLY, 0x00, + DATA_ONLY, 0x00, + DATA_ONLY, 0x00, + DATA_ONLY, 0x00, + DATA_ONLY, 0x00, + DATA_ONLY, 0x00, + DATA_ONLY, 0x00, + DATA_ONLY, 0x03, + DATA_ONLY, 0x06, + DATA_ONLY, 0x09, + DATA_ONLY, 0x0d, + DATA_ONLY, 0x0f, + DATA_ONLY, 0x12, + DATA_ONLY, 0x15, + DATA_ONLY, 0x18, + + 0xb2, 0x10, + DATA_ONLY, 0x10, + DATA_ONLY, 0x0b, + DATA_ONLY, 0x05, + + ENDDEF, 0x0000 +}; + +static const unsigned short SEQ_ACL_ON[] = { + /* ACL on */ + 0xc0, 0x01, + + ENDDEF, 0x0000 +}; + +static const unsigned short SEQ_ACL_OFF[] = { + /* ACL off */ + 0xc0, 0x00, + + ENDDEF, 0x0000 +}; + +static const unsigned short SEQ_ELVSS_ON[] = { + /* ELVSS on */ + 0xb1, 0x0b, + + ENDDEF, 0x0000 +}; + +static const unsigned short SEQ_ELVSS_OFF[] = { + /* ELVSS off */ + 0xb1, 0x0a, + + ENDDEF, 0x0000 +}; + +static const unsigned short SEQ_STAND_BY_OFF[] = { + 0x11, COMMAND_ONLY, + + ENDDEF, 0x0000 +}; + +static const unsigned short SEQ_STAND_BY_ON[] = { + 0x10, COMMAND_ONLY, + + ENDDEF, 0x0000 +}; + +static const unsigned short SEQ_DISPLAY_ON[] = { + 0x29, COMMAND_ONLY, + + ENDDEF, 0x0000 +}; + + +static int s6e63m0_spi_write_byte(struct s6e63m0 *lcd, int addr, int data) +{ + u16 buf[1]; + struct spi_message msg; + + struct spi_transfer xfer = { + .len = 2, + .tx_buf = buf, + }; + + buf[0] = (addr << 8) | data; + + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + + return spi_sync(lcd->spi, &msg); +} + +static int s6e63m0_spi_write(struct s6e63m0 *lcd, unsigned char address, + unsigned char command) +{ + int ret = 0; + + if (address != DATA_ONLY) + ret = s6e63m0_spi_write_byte(lcd, 0x0, address); + if (command != COMMAND_ONLY) + ret = s6e63m0_spi_write_byte(lcd, 0x1, command); + + return ret; +} + +static int s6e63m0_panel_send_sequence(struct s6e63m0 *lcd, + const unsigned short *wbuf) +{ + int ret = 0, i = 0; + + while ((wbuf[i] & DEFMASK) != ENDDEF) { + if ((wbuf[i] & DEFMASK) != SLEEPMSEC) { + ret = s6e63m0_spi_write(lcd, wbuf[i], wbuf[i+1]); + if (ret) + break; + } else + udelay(wbuf[i+1]*1000); + i += 2; + } + + return ret; +} + +static int _s6e63m0_gamma_ctl(struct s6e63m0 *lcd, const unsigned int *gamma) +{ + unsigned int i = 0; + int ret = 0; + + /* disable gamma table updating. */ + ret = s6e63m0_spi_write(lcd, 0xfa, 0x00); + if (ret) { + dev_err(lcd->dev, "failed to disable gamma table updating.\n"); + goto gamma_err; + } + + for (i = 0 ; i < GAMMA_TABLE_COUNT; i++) { + ret = s6e63m0_spi_write(lcd, DATA_ONLY, gamma[i]); + if (ret) { + dev_err(lcd->dev, "failed to set gamma table.\n"); + goto gamma_err; + } + } + + /* update gamma table. */ + ret = s6e63m0_spi_write(lcd, 0xfa, 0x01); + if (ret) + dev_err(lcd->dev, "failed to update gamma table.\n"); + +gamma_err: + return ret; +} + +static int s6e63m0_gamma_ctl(struct s6e63m0 *lcd, int gamma) +{ + int ret = 0; + + ret = _s6e63m0_gamma_ctl(lcd, gamma_table.gamma_22_table[gamma]); + + return ret; +} + + +static int s6e63m0_ldi_init(struct s6e63m0 *lcd) +{ + int ret, i; + const unsigned short *init_seq[] = { + SEQ_PANEL_CONDITION_SET, + SEQ_DISPLAY_CONDITION_SET, + SEQ_GAMMA_SETTING, + SEQ_ETC_CONDITION_SET, + SEQ_ACL_ON, + SEQ_ELVSS_ON, + }; + + for (i = 0; i < ARRAY_SIZE(init_seq); i++) { + ret = s6e63m0_panel_send_sequence(lcd, init_seq[i]); + if (ret) + break; + } + + return ret; +} + +static int s6e63m0_ldi_enable(struct s6e63m0 *lcd) +{ + int ret = 0, i; + const unsigned short *enable_seq[] = { + SEQ_STAND_BY_OFF, + SEQ_DISPLAY_ON, + }; + + for (i = 0; i < ARRAY_SIZE(enable_seq); i++) { + ret = s6e63m0_panel_send_sequence(lcd, enable_seq[i]); + if (ret) + break; + } + + return ret; +} + +static int s6e63m0_ldi_disable(struct s6e63m0 *lcd) +{ + int ret; + + ret = s6e63m0_panel_send_sequence(lcd, SEQ_STAND_BY_ON); + + return ret; +} + +static int s6e63m0_power_on(struct s6e63m0 *lcd) +{ + int ret = 0; + struct lcd_platform_data *pd = NULL; + struct backlight_device *bd = NULL; + + pd = lcd->lcd_pd; + if (!pd) { + dev_err(lcd->dev, "platform data is NULL.\n"); + return -EFAULT; + } + + bd = lcd->bd; + if (!bd) { + dev_err(lcd->dev, "backlight device is NULL.\n"); + return -EFAULT; + } + + if (!pd->power_on) { + dev_err(lcd->dev, "power_on is NULL.\n"); + return -EFAULT; + } else { + pd->power_on(lcd->ld, 1); + mdelay(pd->power_on_delay); + } + + if (!pd->reset) { + dev_err(lcd->dev, "reset is NULL.\n"); + return -EFAULT; + } else { + pd->reset(lcd->ld); + mdelay(pd->reset_delay); + } + + ret = s6e63m0_ldi_init(lcd); + if (ret) { + dev_err(lcd->dev, "failed to initialize ldi.\n"); + return ret; + } + + ret = s6e63m0_ldi_enable(lcd); + if (ret) { + dev_err(lcd->dev, "failed to enable ldi.\n"); + return ret; + } + + /* set brightness to current value after power on or resume. */ + ret = s6e63m0_gamma_ctl(lcd, bd->props.brightness); + if (ret) { + dev_err(lcd->dev, "lcd gamma setting failed.\n"); + return ret; + } + + return 0; +} + +static int s6e63m0_power_off(struct s6e63m0 *lcd) +{ + int ret = 0; + struct lcd_platform_data *pd = NULL; + + pd = lcd->lcd_pd; + if (!pd) { + dev_err(lcd->dev, "platform data is NULL.\n"); + return -EFAULT; + } + + ret = s6e63m0_ldi_disable(lcd); + if (ret) { + dev_err(lcd->dev, "lcd setting failed.\n"); + return -EIO; + } + + mdelay(pd->power_off_delay); + + if (!pd->power_on) { + dev_err(lcd->dev, "power_on is NULL.\n"); + return -EFAULT; + } else + pd->power_on(lcd->ld, 0); + + return 0; +} + +static int s6e63m0_power(struct s6e63m0 *lcd, int power) +{ + int ret = 0; + + if (POWER_IS_ON(power) && !POWER_IS_ON(lcd->power)) + ret = s6e63m0_power_on(lcd); + else if (!POWER_IS_ON(power) && POWER_IS_ON(lcd->power)) + ret = s6e63m0_power_off(lcd); + + if (!ret) + lcd->power = power; + + return ret; +} + +static int s6e63m0_set_power(struct lcd_device *ld, int power) +{ + struct s6e63m0 *lcd = lcd_get_data(ld); + + if (power != FB_BLANK_UNBLANK && power != FB_BLANK_POWERDOWN && + power != FB_BLANK_NORMAL) { + dev_err(lcd->dev, "power value should be 0, 1 or 4.\n"); + return -EINVAL; + } + + return s6e63m0_power(lcd, power); +} + +static int s6e63m0_get_power(struct lcd_device *ld) +{ + struct s6e63m0 *lcd = lcd_get_data(ld); + + return lcd->power; +} + +static int s6e63m0_get_brightness(struct backlight_device *bd) +{ + return bd->props.brightness; +} + +static int s6e63m0_set_brightness(struct backlight_device *bd) +{ + int ret = 0, brightness = bd->props.brightness; + struct s6e63m0 *lcd = bl_get_data(bd); + + if (brightness < MIN_BRIGHTNESS || + brightness > bd->props.max_brightness) { + dev_err(&bd->dev, "lcd brightness should be %d to %d.\n", + MIN_BRIGHTNESS, MAX_BRIGHTNESS); + return -EINVAL; + } + + ret = s6e63m0_gamma_ctl(lcd, bd->props.brightness); + if (ret) { + dev_err(&bd->dev, "lcd brightness setting failed.\n"); + return -EIO; + } + + return ret; +} + +static struct lcd_ops s6e63m0_lcd_ops = { + .set_power = s6e63m0_set_power, + .get_power = s6e63m0_get_power, +}; + +static const struct backlight_ops s6e63m0_backlight_ops = { + .get_brightness = s6e63m0_get_brightness, + .update_status = s6e63m0_set_brightness, +}; + +static ssize_t s6e63m0_sysfs_show_gamma_mode(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct s6e63m0 *lcd = dev_get_drvdata(dev); + char temp[10]; + + switch (lcd->gamma_mode) { + case 0: + sprintf(temp, "2.2 mode\n"); + strcat(buf, temp); + break; + case 1: + sprintf(temp, "1.9 mode\n"); + strcat(buf, temp); + break; + case 2: + sprintf(temp, "1.7 mode\n"); + strcat(buf, temp); + break; + default: + dev_info(dev, "gamma mode could be 0:2.2, 1:1.9 or 2:1.7)n"); + break; + } + + return strlen(buf); +} + +static ssize_t s6e63m0_sysfs_store_gamma_mode(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct s6e63m0 *lcd = dev_get_drvdata(dev); + struct backlight_device *bd = NULL; + int brightness, rc; + + rc = strict_strtoul(buf, 0, (unsigned long *)&lcd->gamma_mode); + if (rc < 0) + return rc; + + bd = lcd->bd; + + brightness = bd->props.brightness; + + switch (lcd->gamma_mode) { + case 0: + _s6e63m0_gamma_ctl(lcd, gamma_table.gamma_22_table[brightness]); + break; + case 1: + _s6e63m0_gamma_ctl(lcd, gamma_table.gamma_19_table[brightness]); + break; + case 2: + _s6e63m0_gamma_ctl(lcd, gamma_table.gamma_17_table[brightness]); + break; + default: + dev_info(dev, "gamma mode could be 0:2.2, 1:1.9 or 2:1.7\n"); + _s6e63m0_gamma_ctl(lcd, gamma_table.gamma_22_table[brightness]); + break; + } + return len; +} + +static DEVICE_ATTR(gamma_mode, 0644, + s6e63m0_sysfs_show_gamma_mode, s6e63m0_sysfs_store_gamma_mode); + +static ssize_t s6e63m0_sysfs_show_gamma_table(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct s6e63m0 *lcd = dev_get_drvdata(dev); + char temp[3]; + + sprintf(temp, "%d\n", lcd->gamma_table_count); + strcpy(buf, temp); + + return strlen(buf); +} +static DEVICE_ATTR(gamma_table, 0644, + s6e63m0_sysfs_show_gamma_table, NULL); + +static int __init s6e63m0_probe(struct spi_device *spi) +{ + int ret = 0; + struct s6e63m0 *lcd = NULL; + struct lcd_device *ld = NULL; + struct backlight_device *bd = NULL; + + lcd = kzalloc(sizeof(struct s6e63m0), GFP_KERNEL); + if (!lcd) + return -ENOMEM; + + /* s6e63m0 lcd panel uses 3-wire 9bits SPI Mode. */ + spi->bits_per_word = 9; + + ret = spi_setup(spi); + if (ret < 0) { + dev_err(&spi->dev, "spi setup failed.\n"); + goto out_free_lcd; + } + + lcd->spi = spi; + lcd->dev = &spi->dev; + + lcd->lcd_pd = (struct lcd_platform_data *)spi->dev.platform_data; + if (!lcd->lcd_pd) { + dev_err(&spi->dev, "platform data is NULL.\n"); + goto out_free_lcd; + } + + ld = lcd_device_register("s6e63m0", &spi->dev, lcd, &s6e63m0_lcd_ops); + if (IS_ERR(ld)) { + ret = PTR_ERR(ld); + goto out_free_lcd; + } + + lcd->ld = ld; + + bd = backlight_device_register("s6e63m0bl-bl", &spi->dev, lcd, + &s6e63m0_backlight_ops, NULL); + if (IS_ERR(bd)) { + ret = PTR_ERR(bd); + goto out_lcd_unregister; + } + + bd->props.max_brightness = MAX_BRIGHTNESS; + bd->props.brightness = MAX_BRIGHTNESS; + lcd->bd = bd; + + /* + * it gets gamma table count available so it gets user + * know that. + */ + lcd->gamma_table_count = + sizeof(gamma_table) / (MAX_GAMMA_LEVEL * sizeof(int)); + + ret = device_create_file(&(spi->dev), &dev_attr_gamma_mode); + if (ret < 0) + dev_err(&(spi->dev), "failed to add sysfs entries\n"); + + ret = device_create_file(&(spi->dev), &dev_attr_gamma_table); + if (ret < 0) + dev_err(&(spi->dev), "failed to add sysfs entries\n"); + + /* + * if lcd panel was on from bootloader like u-boot then + * do not lcd on. + */ + if (!lcd->lcd_pd->lcd_enabled) { + /* + * if lcd panel was off from bootloader then + * current lcd status is powerdown and then + * it enables lcd panel. + */ + lcd->power = FB_BLANK_POWERDOWN; + + s6e63m0_power(lcd, FB_BLANK_UNBLANK); + } else + lcd->power = FB_BLANK_UNBLANK; + + dev_set_drvdata(&spi->dev, lcd); + + dev_info(&spi->dev, "s6e63m0 panel driver has been probed.\n"); + + return 0; + +out_lcd_unregister: + lcd_device_unregister(ld); +out_free_lcd: + kfree(lcd); + return ret; +} + +static int __devexit s6e63m0_remove(struct spi_device *spi) +{ + struct s6e63m0 *lcd = dev_get_drvdata(&spi->dev); + + s6e63m0_power(lcd, FB_BLANK_POWERDOWN); + lcd_device_unregister(lcd->ld); + kfree(lcd); + + return 0; +} + +#if defined(CONFIG_PM) +unsigned int before_power; + +static int s6e63m0_suspend(struct spi_device *spi, pm_message_t mesg) +{ + int ret = 0; + struct s6e63m0 *lcd = dev_get_drvdata(&spi->dev); + + dev_dbg(&spi->dev, "lcd->power = %d\n", lcd->power); + + before_power = lcd->power; + + /* + * when lcd panel is suspend, lcd panel becomes off + * regardless of status. + */ + ret = s6e63m0_power(lcd, FB_BLANK_POWERDOWN); + + return ret; +} + +static int s6e63m0_resume(struct spi_device *spi) +{ + int ret = 0; + struct s6e63m0 *lcd = dev_get_drvdata(&spi->dev); + + /* + * after suspended, if lcd panel status is FB_BLANK_UNBLANK + * (at that time, before_power is FB_BLANK_UNBLANK) then + * it changes that status to FB_BLANK_POWERDOWN to get lcd on. + */ + if (before_power == FB_BLANK_UNBLANK) + lcd->power = FB_BLANK_POWERDOWN; + + dev_dbg(&spi->dev, "before_power = %d\n", before_power); + + ret = s6e63m0_power(lcd, before_power); + + return ret; +} +#else +#define s6e63m0_suspend NULL +#define s6e63m0_resume NULL +#endif + +/* Power down all displays on reboot, poweroff or halt. */ +static void s6e63m0_shutdown(struct spi_device *spi) +{ + struct s6e63m0 *lcd = dev_get_drvdata(&spi->dev); + + s6e63m0_power(lcd, FB_BLANK_POWERDOWN); +} + +static struct spi_driver s6e63m0_driver = { + .driver = { + .name = "s6e63m0", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + .probe = s6e63m0_probe, + .remove = __devexit_p(s6e63m0_remove), + .shutdown = s6e63m0_shutdown, + .suspend = s6e63m0_suspend, + .resume = s6e63m0_resume, +}; + +static int __init s6e63m0_init(void) +{ + return spi_register_driver(&s6e63m0_driver); +} + +static void __exit s6e63m0_exit(void) +{ + spi_unregister_driver(&s6e63m0_driver); +} + +module_init(s6e63m0_init); +module_exit(s6e63m0_exit); + +MODULE_AUTHOR("InKi Dae <inki.dae@samsung.com>"); +MODULE_DESCRIPTION("S6E63M0 LCD Driver"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/video/backlight/s6e63m0_gamma.h b/drivers/video/backlight/s6e63m0_gamma.h new file mode 100644 index 000000000000..2c44bdb0696b --- /dev/null +++ b/drivers/video/backlight/s6e63m0_gamma.h @@ -0,0 +1,266 @@ +/* linux/drivers/video/samsung/s6e63m0_brightness.h + * + * Gamma level definitions. + * + * Copyright (c) 2009 Samsung Electronics + * InKi Dae <inki.dae@samsung.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#ifndef _S6E63M0_BRIGHTNESS_H +#define _S6E63M0_BRIGHTNESS_H + +#define MAX_GAMMA_LEVEL 11 +#define GAMMA_TABLE_COUNT 21 + +/* gamma value: 2.2 */ +static const unsigned int s6e63m0_22_300[] = { + 0x18, 0x08, 0x24, 0x5f, 0x50, 0x2d, 0xB6, + 0xB9, 0xA7, 0xAd, 0xB1, 0x9f, 0xbe, 0xC0, + 0xB5, 0x00, 0xa0, 0x00, 0xa4, 0x00, 0xdb +}; + +static const unsigned int s6e63m0_22_280[] = { + 0x18, 0x08, 0x24, 0x64, 0x56, 0x33, 0xB6, + 0xBA, 0xA8, 0xAC, 0xB1, 0x9D, 0xC1, 0xC1, + 0xB7, 0x00, 0x9C, 0x00, 0x9F, 0x00, 0xD6 +}; + +static const unsigned int s6e63m0_22_260[] = { + 0x18, 0x08, 0x24, 0x66, 0x58, 0x34, 0xB6, + 0xBA, 0xA7, 0xAF, 0xB3, 0xA0, 0xC1, 0xC2, + 0xB7, 0x00, 0x97, 0x00, 0x9A, 0x00, 0xD1 + +}; + +static const unsigned int s6e63m0_22_240[] = { + 0x18, 0x08, 0x24, 0x62, 0x54, 0x30, 0xB9, + 0xBB, 0xA9, 0xB0, 0xB3, 0xA1, 0xC1, 0xC3, + 0xB7, 0x00, 0x91, 0x00, 0x95, 0x00, 0xDA + +}; +static const unsigned int s6e63m0_22_220[] = { + 0x18, 0x08, 0x24, 0x63, 0x53, 0x31, 0xB8, + 0xBC, 0xA9, 0xB0, 0xB5, 0xA2, 0xC4, 0xC4, + 0xB8, 0x00, 0x8B, 0x00, 0x8E, 0x00, 0xC2 +}; + +static const unsigned int s6e63m0_22_200[] = { + 0x18, 0x08, 0x24, 0x66, 0x55, 0x34, 0xBA, + 0xBD, 0xAB, 0xB1, 0xB5, 0xA3, 0xC5, 0xC6, + 0xB9, 0x00, 0x85, 0x00, 0x88, 0x00, 0xBA +}; + +static const unsigned int s6e63m0_22_170[] = { + 0x18, 0x08, 0x24, 0x69, 0x54, 0x37, 0xBB, + 0xBE, 0xAC, 0xB4, 0xB7, 0xA6, 0xC7, 0xC8, + 0xBC, 0x00, 0x7B, 0x00, 0x7E, 0x00, 0xAB +}; + +static const unsigned int s6e63m0_22_140[] = { + 0x18, 0x08, 0x24, 0x6C, 0x54, 0x3A, 0xBC, + 0xBF, 0xAC, 0xB7, 0xBB, 0xA9, 0xC9, 0xC9, + 0xBE, 0x00, 0x71, 0x00, 0x73, 0x00, 0x9E +}; + +static const unsigned int s6e63m0_22_110[] = { + 0x18, 0x08, 0x24, 0x70, 0x51, 0x3E, 0xBF, + 0xC1, 0xAF, 0xB9, 0xBC, 0xAB, 0xCC, 0xCC, + 0xC2, 0x00, 0x65, 0x00, 0x67, 0x00, 0x8D +}; + +static const unsigned int s6e63m0_22_90[] = { + 0x18, 0x08, 0x24, 0x73, 0x4A, 0x3D, 0xC0, + 0xC2, 0xB1, 0xBB, 0xBE, 0xAC, 0xCE, 0xCF, + 0xC5, 0x00, 0x5D, 0x00, 0x5E, 0x00, 0x82 +}; + +static const unsigned int s6e63m0_22_30[] = { + 0x18, 0x08, 0x24, 0x78, 0xEC, 0x3D, 0xC8, + 0xC2, 0xB6, 0xC4, 0xC7, 0xB6, 0xD5, 0xD7, + 0xCC, 0x00, 0x39, 0x00, 0x36, 0x00, 0x51 +}; + +/* gamma value: 1.9 */ +static const unsigned int s6e63m0_19_300[] = { + 0x18, 0x08, 0x24, 0x61, 0x5F, 0x39, 0xBA, + 0xBD, 0xAD, 0xB1, 0xB6, 0xA5, 0xC4, 0xC5, + 0xBC, 0x00, 0xA0, 0x00, 0xA4, 0x00, 0xDB +}; + +static const unsigned int s6e63m0_19_280[] = { + 0x18, 0x08, 0x24, 0x61, 0x60, 0x39, 0xBB, + 0xBE, 0xAD, 0xB2, 0xB6, 0xA6, 0xC5, 0xC7, + 0xBD, 0x00, 0x9B, 0x00, 0x9E, 0x00, 0xD5 +}; + +static const unsigned int s6e63m0_19_260[] = { + 0x18, 0x08, 0x24, 0x63, 0x61, 0x3B, 0xBA, + 0xBE, 0xAC, 0xB3, 0xB8, 0xA7, 0xC6, 0xC8, + 0xBD, 0x00, 0x96, 0x00, 0x98, 0x00, 0xCF +}; + +static const unsigned int s6e63m0_19_240[] = { + 0x18, 0x08, 0x24, 0x67, 0x64, 0x3F, 0xBB, + 0xBE, 0xAD, 0xB3, 0xB9, 0xA7, 0xC8, 0xC9, + 0xBE, 0x00, 0x90, 0x00, 0x92, 0x00, 0xC8 +}; + +static const unsigned int s6e63m0_19_220[] = { + 0x18, 0x08, 0x24, 0x68, 0x64, 0x40, 0xBC, + 0xBF, 0xAF, 0xB4, 0xBA, 0xA9, 0xC8, 0xCA, + 0xBE, 0x00, 0x8B, 0x00, 0x8C, 0x00, 0xC0 +}; + +static const unsigned int s6e63m0_19_200[] = { + 0x18, 0x08, 0x24, 0x68, 0x64, 0x3F, 0xBE, + 0xC0, 0xB0, 0xB6, 0xBB, 0xAB, 0xC8, 0xCB, + 0xBF, 0x00, 0x85, 0x00, 0x86, 0x00, 0xB8 +}; + +static const unsigned int s6e63m0_19_170[] = { + 0x18, 0x08, 0x24, 0x69, 0x64, 0x40, 0xBF, + 0xC1, 0xB0, 0xB9, 0xBE, 0xAD, 0xCB, 0xCD, + 0xC2, 0x00, 0x7A, 0x00, 0x7B, 0x00, 0xAA +}; + +static const unsigned int s6e63m0_19_140[] = { + 0x18, 0x08, 0x24, 0x6E, 0x65, 0x45, 0xC0, + 0xC3, 0xB2, 0xBA, 0xBE, 0xAE, 0xCD, 0xD0, + 0xC4, 0x00, 0x70, 0x00, 0x70, 0x00, 0x9C +}; + +static const unsigned int s6e63m0_19_110[] = { + 0x18, 0x08, 0x24, 0x6F, 0x65, 0x46, 0xC2, + 0xC4, 0xB3, 0xBF, 0xC2, 0xB2, 0xCF, 0xD1, + 0xC6, 0x00, 0x64, 0x00, 0x64, 0x00, 0x8D +}; + +static const unsigned int s6e63m0_19_90[] = { + 0x18, 0x08, 0x24, 0x74, 0x60, 0x4A, 0xC3, + 0xC6, 0xB5, 0xBF, 0xC3, 0xB2, 0xD2, 0xD3, + 0xC8, 0x00, 0x5B, 0x00, 0x5B, 0x00, 0x81 +}; + +static const unsigned int s6e63m0_19_30[] = { + 0x18, 0x08, 0x24, 0x84, 0x45, 0x4F, 0xCA, + 0xCB, 0xBC, 0xC9, 0xCB, 0xBC, 0xDA, 0xDA, + 0xD0, 0x00, 0x35, 0x00, 0x34, 0x00, 0x4E +}; + +/* gamma value: 1.7 */ +static const unsigned int s6e63m0_17_300[] = { + 0x18, 0x08, 0x24, 0x70, 0x70, 0x4F, 0xBF, + 0xC2, 0xB2, 0xB8, 0xBC, 0xAC, 0xCB, 0xCD, + 0xC3, 0x00, 0xA0, 0x00, 0xA4, 0x00, 0xDB +}; + +static const unsigned int s6e63m0_17_280[] = { + 0x18, 0x08, 0x24, 0x71, 0x71, 0x50, 0xBF, + 0xC2, 0xB2, 0xBA, 0xBE, 0xAE, 0xCB, 0xCD, + 0xC3, 0x00, 0x9C, 0x00, 0x9F, 0x00, 0xD6 +}; + +static const unsigned int s6e63m0_17_260[] = { + 0x18, 0x08, 0x24, 0x72, 0x72, 0x50, 0xC0, + 0xC3, 0xB4, 0xB9, 0xBE, 0xAE, 0xCC, 0xCF, + 0xC4, 0x00, 0x97, 0x00, 0x9A, 0x00, 0xD1 +}; + +static const unsigned int s6e63m0_17_240[] = { + 0x18, 0x08, 0x24, 0x71, 0x72, 0x4F, 0xC2, + 0xC4, 0xB5, 0xBB, 0xBF, 0xB0, 0xCC, 0xCF, + 0xC3, 0x00, 0x91, 0x00, 0x95, 0x00, 0xCA +}; + +static const unsigned int s6e63m0_17_220[] = { + 0x18, 0x08, 0x24, 0x71, 0x73, 0x4F, 0xC2, + 0xC5, 0xB5, 0xBD, 0xC0, 0xB2, 0xCD, 0xD1, + 0xC5, 0x00, 0x8B, 0x00, 0x8E, 0x00, 0xC2 +}; + +static const unsigned int s6e63m0_17_200[] = { + 0x18, 0x08, 0x24, 0x72, 0x75, 0x51, 0xC2, + 0xC6, 0xB5, 0xBF, 0xC1, 0xB3, 0xCE, 0xD1, + 0xC6, 0x00, 0x85, 0x00, 0x88, 0x00, 0xBA +}; + +static const unsigned int s6e63m0_17_170[] = { + 0x18, 0x08, 0x24, 0x75, 0x77, 0x54, 0xC3, + 0xC7, 0xB7, 0xC0, 0xC3, 0xB4, 0xD1, 0xD3, + 0xC9, 0x00, 0x7B, 0x00, 0x7E, 0x00, 0xAB +}; + +static const unsigned int s6e63m0_17_140[] = { + 0x18, 0x08, 0x24, 0x7B, 0x77, 0x58, 0xC3, + 0xC8, 0xB8, 0xC2, 0xC6, 0xB6, 0xD3, 0xD4, + 0xCA, 0x00, 0x71, 0x00, 0x73, 0x00, 0x9E +}; + +static const unsigned int s6e63m0_17_110[] = { + 0x18, 0x08, 0x24, 0x81, 0x7B, 0x5D, 0xC6, + 0xCA, 0xBB, 0xC3, 0xC7, 0xB8, 0xD6, 0xD8, + 0xCD, 0x00, 0x65, 0x00, 0x67, 0x00, 0x8D +}; + +static const unsigned int s6e63m0_17_90[] = { + 0x18, 0x08, 0x24, 0x82, 0x7A, 0x5B, 0xC8, + 0xCB, 0xBD, 0xC5, 0xCA, 0xBA, 0xD6, 0xD8, + 0xCE, 0x00, 0x5D, 0x00, 0x5E, 0x00, 0x82 +}; + +static const unsigned int s6e63m0_17_30[] = { + 0x18, 0x08, 0x24, 0x8F, 0x73, 0x63, 0xD1, + 0xD0, 0xC5, 0xCC, 0xD1, 0xC2, 0xDE, 0xE0, + 0xD6, 0x00, 0x39, 0x00, 0x36, 0x00, 0x51 +}; + +struct s6e63m0_gamma { + unsigned int *gamma_22_table[MAX_GAMMA_LEVEL]; + unsigned int *gamma_19_table[MAX_GAMMA_LEVEL]; + unsigned int *gamma_17_table[MAX_GAMMA_LEVEL]; +}; + +static struct s6e63m0_gamma gamma_table = { + .gamma_22_table[0] = (unsigned int *)&s6e63m0_22_30, + .gamma_22_table[1] = (unsigned int *)&s6e63m0_22_90, + .gamma_22_table[2] = (unsigned int *)&s6e63m0_22_110, + .gamma_22_table[3] = (unsigned int *)&s6e63m0_22_140, + .gamma_22_table[4] = (unsigned int *)&s6e63m0_22_170, + .gamma_22_table[5] = (unsigned int *)&s6e63m0_22_200, + .gamma_22_table[6] = (unsigned int *)&s6e63m0_22_220, + .gamma_22_table[7] = (unsigned int *)&s6e63m0_22_240, + .gamma_22_table[8] = (unsigned int *)&s6e63m0_22_260, + .gamma_22_table[9] = (unsigned int *)&s6e63m0_22_280, + .gamma_22_table[10] = (unsigned int *)&s6e63m0_22_300, + + .gamma_19_table[0] = (unsigned int *)&s6e63m0_19_30, + .gamma_19_table[1] = (unsigned int *)&s6e63m0_19_90, + .gamma_19_table[2] = (unsigned int *)&s6e63m0_19_110, + .gamma_19_table[3] = (unsigned int *)&s6e63m0_19_140, + .gamma_19_table[4] = (unsigned int *)&s6e63m0_19_170, + .gamma_19_table[5] = (unsigned int *)&s6e63m0_19_200, + .gamma_19_table[6] = (unsigned int *)&s6e63m0_19_220, + .gamma_19_table[7] = (unsigned int *)&s6e63m0_19_240, + .gamma_19_table[8] = (unsigned int *)&s6e63m0_19_260, + .gamma_19_table[9] = (unsigned int *)&s6e63m0_19_280, + .gamma_19_table[10] = (unsigned int *)&s6e63m0_19_300, + + .gamma_17_table[0] = (unsigned int *)&s6e63m0_17_30, + .gamma_17_table[1] = (unsigned int *)&s6e63m0_17_90, + .gamma_17_table[2] = (unsigned int *)&s6e63m0_17_110, + .gamma_17_table[3] = (unsigned int *)&s6e63m0_17_140, + .gamma_17_table[4] = (unsigned int *)&s6e63m0_17_170, + .gamma_17_table[5] = (unsigned int *)&s6e63m0_17_200, + .gamma_17_table[6] = (unsigned int *)&s6e63m0_17_220, + .gamma_17_table[7] = (unsigned int *)&s6e63m0_17_240, + .gamma_17_table[8] = (unsigned int *)&s6e63m0_17_260, + .gamma_17_table[9] = (unsigned int *)&s6e63m0_17_280, + .gamma_17_table[10] = (unsigned int *)&s6e63m0_17_300, +}; + +#endif + diff --git a/drivers/video/backlight/tosa_bl.c b/drivers/video/backlight/tosa_bl.c index e03e60bbfd85..2a04b382ec48 100644 --- a/drivers/video/backlight/tosa_bl.c +++ b/drivers/video/backlight/tosa_bl.c @@ -119,7 +119,6 @@ static int __devinit tosa_bl_probe(struct i2c_client *client, err_reg: data->bl = NULL; - i2c_set_clientdata(client, NULL); err_gpio_dir: gpio_free(TOSA_GPIO_BL_C20MA); err_gpio_bl: @@ -133,7 +132,6 @@ static int __devexit tosa_bl_remove(struct i2c_client *client) backlight_device_unregister(data->bl); data->bl = NULL; - i2c_set_clientdata(client, NULL); gpio_free(TOSA_GPIO_BL_C20MA); diff --git a/drivers/video/bf54x-lq043fb.c b/drivers/video/bf54x-lq043fb.c index 23b2a8c0dbfc..b020ba7f1cf2 100644 --- a/drivers/video/bf54x-lq043fb.c +++ b/drivers/video/bf54x-lq043fb.c @@ -501,7 +501,9 @@ static irqreturn_t bfin_bf54x_irq_error(int irq, void *dev_id) static int __devinit bfin_bf54x_probe(struct platform_device *pdev) { +#ifndef NO_BL_SUPPORT struct backlight_properties props; +#endif struct bfin_bf54xfb_info *info; struct fb_info *fbinfo; int ret; @@ -654,7 +656,8 @@ static int __devinit bfin_bf54x_probe(struct platform_device *pdev) printk(KERN_ERR DRIVER_NAME ": unable to register backlight.\n"); ret = -EINVAL; - goto out9; + unregister_framebuffer(fbinfo); + goto out8; } lcd_dev = lcd_device_register(DRIVER_NAME, &pdev->dev, NULL, &bfin_lcd_ops); @@ -663,8 +666,6 @@ static int __devinit bfin_bf54x_probe(struct platform_device *pdev) return 0; -out9: - unregister_framebuffer(fbinfo); out8: free_irq(info->irq, info); out7: diff --git a/drivers/video/bfin-lq035q1-fb.c b/drivers/video/bfin-lq035q1-fb.c index 2baac7cc1425..c8e1f04941bd 100644 --- a/drivers/video/bfin-lq035q1-fb.c +++ b/drivers/video/bfin-lq035q1-fb.c @@ -61,47 +61,13 @@ #define LCD_X_RES 320 /* Horizontal Resolution */ #define LCD_Y_RES 240 /* Vertical Resolution */ #define DMA_BUS_SIZE 16 +#define U_LINE 4 /* Blanking Lines */ -#define USE_RGB565_16_BIT_PPI - -#ifdef USE_RGB565_16_BIT_PPI -#define LCD_BPP 16 /* Bit Per Pixel */ -#define CLOCKS_PER_PIX 1 -#define CPLD_PIPELINE_DELAY_COR 0 /* NO CPLB */ -#endif /* Interface 16/18-bit TFT over an 8-bit wide PPI using a small Programmable Logic Device (CPLD) * http://blackfin.uclinux.org/gf/project/stamp/frs/?action=FrsReleaseBrowse&frs_package_id=165 */ -#ifdef USE_RGB565_8_BIT_PPI -#define LCD_BPP 16 /* Bit Per Pixel */ -#define CLOCKS_PER_PIX 2 -#define CPLD_PIPELINE_DELAY_COR 3 /* RGB565 */ -#endif - -#ifdef USE_RGB888_8_BIT_PPI -#define LCD_BPP 24 /* Bit Per Pixel */ -#define CLOCKS_PER_PIX 3 -#define CPLD_PIPELINE_DELAY_COR 5 /* RGB888 */ -#endif - - /* - * HS and VS timing parameters (all in number of PPI clk ticks) - */ - -#define U_LINE 4 /* Blanking Lines */ - -#define H_ACTPIX (LCD_X_RES * CLOCKS_PER_PIX) /* active horizontal pixel */ -#define H_PERIOD (336 * CLOCKS_PER_PIX) /* HS period */ -#define H_PULSE (2 * CLOCKS_PER_PIX) /* HS pulse width */ -#define H_START (7 * CLOCKS_PER_PIX + CPLD_PIPELINE_DELAY_COR) /* first valid pixel */ - -#define V_LINES (LCD_Y_RES + U_LINE) /* total vertical lines */ -#define V_PULSE (2 * CLOCKS_PER_PIX) /* VS pulse width (1-5 H_PERIODs) */ -#define V_PERIOD (H_PERIOD * V_LINES) /* VS period */ - -#define ACTIVE_VIDEO_MEM_OFFSET ((U_LINE / 2) * LCD_X_RES * (LCD_BPP / 8)) #define BFIN_LCD_NBR_PALETTE_ENTRIES 256 @@ -110,12 +76,6 @@ #define PPI_PORT_CFG_01 0x10 #define PPI_POLS_1 0x8000 -#if (CLOCKS_PER_PIX > 1) -#define PPI_PMODE (DLEN_8 | PACK_EN) -#else -#define PPI_PMODE (DLEN_16) -#endif - #define LQ035_INDEX 0x74 #define LQ035_DATA 0x76 @@ -139,6 +99,15 @@ struct bfin_lq035q1fb_info { int irq; spinlock_t lock; /* lock */ u32 pseudo_pal[16]; + + u32 lcd_bpp; + u32 h_actpix; + u32 h_period; + u32 h_pulse; + u32 h_start; + u32 v_lines; + u32 v_pulse; + u32 v_period; }; static int nocursor; @@ -234,16 +203,69 @@ static int lq035q1_backlight(struct bfin_lq035q1fb_info *info, unsigned arg) return 0; } +static int bfin_lq035q1_calc_timing(struct bfin_lq035q1fb_info *fbi) +{ + unsigned long clocks_per_pix, cpld_pipeline_delay_cor; + + /* + * Interface 16/18-bit TFT over an 8-bit wide PPI using a small + * Programmable Logic Device (CPLD) + * http://blackfin.uclinux.org/gf/project/stamp/frs/?action=FrsReleaseBrowse&frs_package_id=165 + */ + + switch (fbi->disp_info->ppi_mode) { + case USE_RGB565_16_BIT_PPI: + fbi->lcd_bpp = 16; + clocks_per_pix = 1; + cpld_pipeline_delay_cor = 0; + break; + case USE_RGB565_8_BIT_PPI: + fbi->lcd_bpp = 16; + clocks_per_pix = 2; + cpld_pipeline_delay_cor = 3; + break; + case USE_RGB888_8_BIT_PPI: + fbi->lcd_bpp = 24; + clocks_per_pix = 3; + cpld_pipeline_delay_cor = 5; + break; + default: + return -EINVAL; + } + + /* + * HS and VS timing parameters (all in number of PPI clk ticks) + */ + + fbi->h_actpix = (LCD_X_RES * clocks_per_pix); /* active horizontal pixel */ + fbi->h_period = (336 * clocks_per_pix); /* HS period */ + fbi->h_pulse = (2 * clocks_per_pix); /* HS pulse width */ + fbi->h_start = (7 * clocks_per_pix + cpld_pipeline_delay_cor); /* first valid pixel */ + + fbi->v_lines = (LCD_Y_RES + U_LINE); /* total vertical lines */ + fbi->v_pulse = (2 * clocks_per_pix); /* VS pulse width (1-5 H_PERIODs) */ + fbi->v_period = (fbi->h_period * fbi->v_lines); /* VS period */ + + return 0; +} + static void bfin_lq035q1_config_ppi(struct bfin_lq035q1fb_info *fbi) { - bfin_write_PPI_DELAY(H_START); - bfin_write_PPI_COUNT(H_ACTPIX - 1); - bfin_write_PPI_FRAME(V_LINES); + unsigned ppi_pmode; + + if (fbi->disp_info->ppi_mode == USE_RGB565_16_BIT_PPI) + ppi_pmode = DLEN_16; + else + ppi_pmode = (DLEN_8 | PACK_EN); + + bfin_write_PPI_DELAY(fbi->h_start); + bfin_write_PPI_COUNT(fbi->h_actpix - 1); + bfin_write_PPI_FRAME(fbi->v_lines); bfin_write_PPI_CONTROL(PPI_TX_MODE | /* output mode , PORT_DIR */ PPI_XFER_TYPE_11 | /* sync mode XFR_TYPE */ PPI_PORT_CFG_01 | /* two frame sync PORT_CFG */ - PPI_PMODE | /* 8/16 bit data length / PACK_EN? */ + ppi_pmode | /* 8/16 bit data length / PACK_EN? */ PPI_POLS_1); /* faling edge syncs POLS */ } @@ -272,19 +294,19 @@ static void bfin_lq035q1_stop_timers(void) } -static void bfin_lq035q1_init_timers(void) +static void bfin_lq035q1_init_timers(struct bfin_lq035q1fb_info *fbi) { bfin_lq035q1_stop_timers(); - set_gptimer_period(TIMER_HSYNC_id, H_PERIOD); - set_gptimer_pwidth(TIMER_HSYNC_id, H_PULSE); + set_gptimer_period(TIMER_HSYNC_id, fbi->h_period); + set_gptimer_pwidth(TIMER_HSYNC_id, fbi->h_pulse); set_gptimer_config(TIMER_HSYNC_id, TIMER_MODE_PWM | TIMER_PERIOD_CNT | TIMER_TIN_SEL | TIMER_CLK_SEL| TIMER_EMU_RUN); - set_gptimer_period(TIMER_VSYNC_id, V_PERIOD); - set_gptimer_pwidth(TIMER_VSYNC_id, V_PULSE); + set_gptimer_period(TIMER_VSYNC_id, fbi->v_period); + set_gptimer_pwidth(TIMER_VSYNC_id, fbi->v_pulse); set_gptimer_config(TIMER_VSYNC_id, TIMER_MODE_PWM | TIMER_PERIOD_CNT | TIMER_TIN_SEL | TIMER_CLK_SEL | TIMER_EMU_RUN); @@ -294,21 +316,21 @@ static void bfin_lq035q1_init_timers(void) static void bfin_lq035q1_config_dma(struct bfin_lq035q1fb_info *fbi) { + set_dma_config(CH_PPI, set_bfin_dma_config(DIR_READ, DMA_FLOW_AUTO, INTR_DISABLE, DIMENSION_2D, DATA_SIZE_16, DMA_NOSYNC_KEEP_DMA_BUF)); - set_dma_x_count(CH_PPI, (LCD_X_RES * LCD_BPP) / DMA_BUS_SIZE); + set_dma_x_count(CH_PPI, (LCD_X_RES * fbi->lcd_bpp) / DMA_BUS_SIZE); set_dma_x_modify(CH_PPI, DMA_BUS_SIZE / 8); - set_dma_y_count(CH_PPI, V_LINES); + set_dma_y_count(CH_PPI, fbi->v_lines); set_dma_y_modify(CH_PPI, DMA_BUS_SIZE / 8); set_dma_start_addr(CH_PPI, (unsigned long)fbi->fb_buffer); } -#if (CLOCKS_PER_PIX == 1) static const u16 ppi0_req_16[] = {P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2, P_PPI0_D0, P_PPI0_D1, P_PPI0_D2, P_PPI0_D3, P_PPI0_D4, P_PPI0_D5, @@ -316,22 +338,27 @@ static const u16 ppi0_req_16[] = {P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2, P_PPI0_D9, P_PPI0_D10, P_PPI0_D11, P_PPI0_D12, P_PPI0_D13, P_PPI0_D14, P_PPI0_D15, 0}; -#else -static const u16 ppi0_req_16[] = {P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2, + +static const u16 ppi0_req_8[] = {P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2, P_PPI0_D0, P_PPI0_D1, P_PPI0_D2, P_PPI0_D3, P_PPI0_D4, P_PPI0_D5, P_PPI0_D6, P_PPI0_D7, 0}; -#endif -static inline void bfin_lq035q1_free_ports(void) +static inline void bfin_lq035q1_free_ports(unsigned ppi16) { - peripheral_free_list(ppi0_req_16); + if (ppi16) + peripheral_free_list(ppi0_req_16); + else + peripheral_free_list(ppi0_req_8); + if (ANOMALY_05000400) gpio_free(P_IDENT(P_PPI0_FS3)); } -static int __devinit bfin_lq035q1_request_ports(struct platform_device *pdev) +static int __devinit bfin_lq035q1_request_ports(struct platform_device *pdev, + unsigned ppi16) { + int ret; /* ANOMALY_05000400 - PPI Does Not Start Properly In Specific Mode: * Drive PPI_FS3 Low */ @@ -342,7 +369,12 @@ static int __devinit bfin_lq035q1_request_ports(struct platform_device *pdev) gpio_direction_output(P_IDENT(P_PPI0_FS3), 0); } - if (peripheral_request_list(ppi0_req_16, DRIVER_NAME)) { + if (ppi16) + ret = peripheral_request_list(ppi0_req_16, DRIVER_NAME); + else + ret = peripheral_request_list(ppi0_req_8, DRIVER_NAME); + + if (ret) { dev_err(&pdev->dev, "requesting peripherals failed\n"); return -EFAULT; } @@ -364,7 +396,7 @@ static int bfin_lq035q1_fb_open(struct fb_info *info, int user) bfin_lq035q1_config_dma(fbi); bfin_lq035q1_config_ppi(fbi); - bfin_lq035q1_init_timers(); + bfin_lq035q1_init_timers(fbi); /* start dma */ enable_dma(CH_PPI); @@ -402,12 +434,9 @@ static int bfin_lq035q1_fb_release(struct fb_info *info, int user) static int bfin_lq035q1_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { - switch (var->bits_per_pixel) { -#if (LCD_BPP == 24) - case 24:/* TRUECOLOUR, 16m */ -#else - case 16:/* DIRECTCOLOUR, 64k */ -#endif + struct bfin_lq035q1fb_info *fbi = info->par; + + if (var->bits_per_pixel == fbi->lcd_bpp) { var->red.offset = info->var.red.offset; var->green.offset = info->var.green.offset; var->blue.offset = info->var.blue.offset; @@ -420,8 +449,7 @@ static int bfin_lq035q1_fb_check_var(struct fb_var_screeninfo *var, var->red.msb_right = 0; var->green.msb_right = 0; var->blue.msb_right = 0; - break; - default: + } else { pr_debug("%s: depth not supported: %u BPP\n", __func__, var->bits_per_pixel); return -EINVAL; @@ -528,6 +556,7 @@ static int __devinit bfin_lq035q1_probe(struct platform_device *pdev) { struct bfin_lq035q1fb_info *info; struct fb_info *fbinfo; + u32 active_video_mem_offset; int ret; ret = request_dma(CH_PPI, DRIVER_NAME"_CH_PPI"); @@ -550,6 +579,12 @@ static int __devinit bfin_lq035q1_probe(struct platform_device *pdev) platform_set_drvdata(pdev, fbinfo); + ret = bfin_lq035q1_calc_timing(info); + if (ret < 0) { + dev_err(&pdev->dev, "Failed PPI Mode\n"); + goto out3; + } + strcpy(fbinfo->fix.id, DRIVER_NAME); fbinfo->fix.type = FB_TYPE_PACKED_PIXELS; @@ -571,46 +606,48 @@ static int __devinit bfin_lq035q1_probe(struct platform_device *pdev) fbinfo->var.xres_virtual = LCD_X_RES; fbinfo->var.yres = LCD_Y_RES; fbinfo->var.yres_virtual = LCD_Y_RES; - fbinfo->var.bits_per_pixel = LCD_BPP; + fbinfo->var.bits_per_pixel = info->lcd_bpp; if (info->disp_info->mode & LQ035_BGR) { -#if (LCD_BPP == 24) - fbinfo->var.red.offset = 0; - fbinfo->var.green.offset = 8; - fbinfo->var.blue.offset = 16; -#else - fbinfo->var.red.offset = 0; - fbinfo->var.green.offset = 5; - fbinfo->var.blue.offset = 11; -#endif + if (info->lcd_bpp == 24) { + fbinfo->var.red.offset = 0; + fbinfo->var.green.offset = 8; + fbinfo->var.blue.offset = 16; + } else { + fbinfo->var.red.offset = 0; + fbinfo->var.green.offset = 5; + fbinfo->var.blue.offset = 11; + } } else { -#if (LCD_BPP == 24) - fbinfo->var.red.offset = 16; - fbinfo->var.green.offset = 8; - fbinfo->var.blue.offset = 0; -#else - fbinfo->var.red.offset = 11; - fbinfo->var.green.offset = 5; - fbinfo->var.blue.offset = 0; -#endif + if (info->lcd_bpp == 24) { + fbinfo->var.red.offset = 16; + fbinfo->var.green.offset = 8; + fbinfo->var.blue.offset = 0; + } else { + fbinfo->var.red.offset = 11; + fbinfo->var.green.offset = 5; + fbinfo->var.blue.offset = 0; + } } fbinfo->var.transp.offset = 0; -#if (LCD_BPP == 24) - fbinfo->var.red.length = 8; - fbinfo->var.green.length = 8; - fbinfo->var.blue.length = 8; -#else - fbinfo->var.red.length = 5; - fbinfo->var.green.length = 6; - fbinfo->var.blue.length = 5; -#endif + if (info->lcd_bpp == 24) { + fbinfo->var.red.length = 8; + fbinfo->var.green.length = 8; + fbinfo->var.blue.length = 8; + } else { + fbinfo->var.red.length = 5; + fbinfo->var.green.length = 6; + fbinfo->var.blue.length = 5; + } fbinfo->var.transp.length = 0; - fbinfo->fix.smem_len = LCD_X_RES * LCD_Y_RES * LCD_BPP / 8 - + ACTIVE_VIDEO_MEM_OFFSET; + active_video_mem_offset = ((U_LINE / 2) * LCD_X_RES * (info->lcd_bpp / 8)); + + fbinfo->fix.smem_len = LCD_X_RES * LCD_Y_RES * info->lcd_bpp / 8 + + active_video_mem_offset; fbinfo->fix.line_length = fbinfo->var.xres_virtual * fbinfo->var.bits_per_pixel / 8; @@ -629,8 +666,8 @@ static int __devinit bfin_lq035q1_probe(struct platform_device *pdev) goto out3; } - fbinfo->screen_base = (void *)info->fb_buffer + ACTIVE_VIDEO_MEM_OFFSET; - fbinfo->fix.smem_start = (int)info->fb_buffer + ACTIVE_VIDEO_MEM_OFFSET; + fbinfo->screen_base = (void *)info->fb_buffer + active_video_mem_offset; + fbinfo->fix.smem_start = (int)info->fb_buffer + active_video_mem_offset; fbinfo->fbops = &bfin_lq035q1_fb_ops; @@ -643,7 +680,8 @@ static int __devinit bfin_lq035q1_probe(struct platform_device *pdev) goto out4; } - ret = bfin_lq035q1_request_ports(pdev); + ret = bfin_lq035q1_request_ports(pdev, + info->disp_info->ppi_mode == USE_RGB565_16_BIT_PPI); if (ret) { dev_err(&pdev->dev, "couldn't request gpio port\n"); goto out6; @@ -693,7 +731,7 @@ static int __devinit bfin_lq035q1_probe(struct platform_device *pdev) } dev_info(&pdev->dev, "%dx%d %d-bit RGB FrameBuffer initialized\n", - LCD_X_RES, LCD_Y_RES, LCD_BPP); + LCD_X_RES, LCD_Y_RES, info->lcd_bpp); return 0; @@ -705,7 +743,8 @@ static int __devinit bfin_lq035q1_probe(struct platform_device *pdev) out8: free_irq(info->irq, info); out7: - bfin_lq035q1_free_ports(); + bfin_lq035q1_free_ports(info->disp_info->ppi_mode == + USE_RGB565_16_BIT_PPI); out6: fb_dealloc_cmap(&fbinfo->cmap); out4: @@ -742,7 +781,8 @@ static int __devexit bfin_lq035q1_remove(struct platform_device *pdev) fb_dealloc_cmap(&fbinfo->cmap); - bfin_lq035q1_free_ports(); + bfin_lq035q1_free_ports(info->disp_info->ppi_mode == + USE_RGB565_16_BIT_PPI); platform_set_drvdata(pdev, NULL); framebuffer_release(fbinfo); @@ -781,7 +821,7 @@ static int bfin_lq035q1_resume(struct device *dev) bfin_lq035q1_config_dma(info); bfin_lq035q1_config_ppi(info); - bfin_lq035q1_init_timers(); + bfin_lq035q1_init_timers(info); /* start dma */ enable_dma(CH_PPI); diff --git a/drivers/video/bfin-t350mcqb-fb.c b/drivers/video/bfin-t350mcqb-fb.c index c2ec3dcd4e91..7a50272eaab9 100644 --- a/drivers/video/bfin-t350mcqb-fb.c +++ b/drivers/video/bfin-t350mcqb-fb.c @@ -420,7 +420,9 @@ static irqreturn_t bfin_t350mcqb_irq_error(int irq, void *dev_id) static int __devinit bfin_t350mcqb_probe(struct platform_device *pdev) { +#ifndef NO_BL_SUPPORT struct backlight_properties props; +#endif struct bfin_t350mcqbfb_info *info; struct fb_info *fbinfo; int ret; @@ -550,7 +552,8 @@ static int __devinit bfin_t350mcqb_probe(struct platform_device *pdev) printk(KERN_ERR DRIVER_NAME ": unable to register backlight.\n"); ret = -EINVAL; - goto out9; + unregister_framebuffer(fbinfo); + goto out8; } lcd_dev = lcd_device_register(DRIVER_NAME, NULL, &bfin_lcd_ops); @@ -559,8 +562,6 @@ static int __devinit bfin_t350mcqb_probe(struct platform_device *pdev) return 0; -out9: - unregister_framebuffer(fbinfo); out8: free_irq(info->irq, info); out7: diff --git a/drivers/video/bw2.c b/drivers/video/bw2.c index 43320925c4ce..c7796637bafd 100644 --- a/drivers/video/bw2.c +++ b/drivers/video/bw2.c @@ -275,7 +275,7 @@ static int __devinit bw2_do_default_mode(struct bw2_par *par, static int __devinit bw2_probe(struct of_device *op, const struct of_device_id *match) { - struct device_node *dp = op->node; + struct device_node *dp = op->dev.of_node; struct fb_info *info; struct bw2_par *par; int linebytes, err; @@ -376,8 +376,11 @@ static const struct of_device_id bw2_match[] = { MODULE_DEVICE_TABLE(of, bw2_match); static struct of_platform_driver bw2_driver = { - .name = "bw2", - .match_table = bw2_match, + .driver = { + .name = "bw2", + .owner = THIS_MODULE, + .of_match_table = bw2_match, + }, .probe = bw2_probe, .remove = __devexit_p(bw2_remove), }; @@ -387,12 +390,12 @@ static int __init bw2_init(void) if (fb_get_options("bw2fb", NULL)) return -ENODEV; - return of_register_driver(&bw2_driver, &of_bus_type); + return of_register_platform_driver(&bw2_driver); } static void __exit bw2_exit(void) { - of_unregister_driver(&bw2_driver); + of_unregister_platform_driver(&bw2_driver); } module_init(bw2_init); diff --git a/drivers/video/carminefb.c b/drivers/video/carminefb.c index d8345fcc4fe3..6b19136aa181 100644 --- a/drivers/video/carminefb.c +++ b/drivers/video/carminefb.c @@ -432,7 +432,7 @@ static int init_hardware(struct carmine_hw *hw) u32 loops; u32 ret; - /* Initalize Carmine */ + /* Initialize Carmine */ /* Sets internal clock */ c_set_hw_reg(hw, CARMINE_CTL_REG + CARMINE_CTL_REG_CLOCK_ENABLE, CARMINE_DFLT_IP_CLOCK_ENABLE); diff --git a/drivers/video/cg14.c b/drivers/video/cg14.c index 77a040af20a7..d09fde8beb69 100644 --- a/drivers/video/cg14.c +++ b/drivers/video/cg14.c @@ -465,7 +465,7 @@ static void cg14_unmap_regs(struct of_device *op, struct fb_info *info, static int __devinit cg14_probe(struct of_device *op, const struct of_device_id *match) { - struct device_node *dp = op->node; + struct device_node *dp = op->dev.of_node; struct fb_info *info; struct cg14_par *par; int is_8mb, linebytes, i, err; @@ -596,8 +596,11 @@ static const struct of_device_id cg14_match[] = { MODULE_DEVICE_TABLE(of, cg14_match); static struct of_platform_driver cg14_driver = { - .name = "cg14", - .match_table = cg14_match, + .driver = { + .name = "cg14", + .owner = THIS_MODULE, + .of_match_table = cg14_match, + }, .probe = cg14_probe, .remove = __devexit_p(cg14_remove), }; @@ -607,12 +610,12 @@ static int __init cg14_init(void) if (fb_get_options("cg14fb", NULL)) return -ENODEV; - return of_register_driver(&cg14_driver, &of_bus_type); + return of_register_platform_driver(&cg14_driver); } static void __exit cg14_exit(void) { - of_unregister_driver(&cg14_driver); + of_unregister_platform_driver(&cg14_driver); } module_init(cg14_init); diff --git a/drivers/video/cg3.c b/drivers/video/cg3.c index 30eedf79322c..64aa29809fb9 100644 --- a/drivers/video/cg3.c +++ b/drivers/video/cg3.c @@ -349,7 +349,7 @@ static int __devinit cg3_do_default_mode(struct cg3_par *par) static int __devinit cg3_probe(struct of_device *op, const struct of_device_id *match) { - struct device_node *dp = op->node; + struct device_node *dp = op->dev.of_node; struct fb_info *info; struct cg3_par *par; int linebytes, err; @@ -463,8 +463,11 @@ static const struct of_device_id cg3_match[] = { MODULE_DEVICE_TABLE(of, cg3_match); static struct of_platform_driver cg3_driver = { - .name = "cg3", - .match_table = cg3_match, + .driver = { + .name = "cg3", + .owner = THIS_MODULE, + .of_match_table = cg3_match, + }, .probe = cg3_probe, .remove = __devexit_p(cg3_remove), }; @@ -474,12 +477,12 @@ static int __init cg3_init(void) if (fb_get_options("cg3fb", NULL)) return -ENODEV; - return of_register_driver(&cg3_driver, &of_bus_type); + return of_register_platform_driver(&cg3_driver); } static void __exit cg3_exit(void) { - of_unregister_driver(&cg3_driver); + of_unregister_platform_driver(&cg3_driver); } module_init(cg3_init); diff --git a/drivers/video/cg6.c b/drivers/video/cg6.c index 6d0fcb43696e..2389a719dcc7 100644 --- a/drivers/video/cg6.c +++ b/drivers/video/cg6.c @@ -740,7 +740,7 @@ static void cg6_unmap_regs(struct of_device *op, struct fb_info *info, static int __devinit cg6_probe(struct of_device *op, const struct of_device_id *match) { - struct device_node *dp = op->node; + struct device_node *dp = op->dev.of_node; struct fb_info *info; struct cg6_par *par; int linebytes, err; @@ -856,8 +856,11 @@ static const struct of_device_id cg6_match[] = { MODULE_DEVICE_TABLE(of, cg6_match); static struct of_platform_driver cg6_driver = { - .name = "cg6", - .match_table = cg6_match, + .driver = { + .name = "cg6", + .owner = THIS_MODULE, + .of_match_table = cg6_match, + }, .probe = cg6_probe, .remove = __devexit_p(cg6_remove), }; @@ -867,12 +870,12 @@ static int __init cg6_init(void) if (fb_get_options("cg6fb", NULL)) return -ENODEV; - return of_register_driver(&cg6_driver, &of_bus_type); + return of_register_platform_driver(&cg6_driver); } static void __exit cg6_exit(void) { - of_unregister_driver(&cg6_driver); + of_unregister_platform_driver(&cg6_driver); } module_init(cg6_init); diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig index 8e8f18d29d7a..5a35f22372b9 100644 --- a/drivers/video/console/Kconfig +++ b/drivers/video/console/Kconfig @@ -6,7 +6,7 @@ menu "Console display driver support" config VGA_CONSOLE bool "VGA text console" if EMBEDDED || !X86 - depends on !ARCH_ACORN && !ARCH_EBSA110 && !4xx && !8xx && !SPARC && !M68K && !PARISC && !FRV && !ARCH_VERSATILE && !SUPERH && !BLACKFIN && !AVR32 && !MN10300 + depends on !4xx && !8xx && !SPARC && !M68K && !PARISC && !FRV && !SUPERH && !BLACKFIN && !AVR32 && !MN10300 && (!ARM || ARCH_FOOTBRIDGE || ARCH_INTEGRATOR || ARCH_NETWINDER) default y help Saying Y here will allow you to use Linux in text mode through a diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index b0a3fa00706d..3b3f5749af92 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -2342,6 +2342,30 @@ static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch) return 0; } +static int fbcon_debug_enter(struct vc_data *vc) +{ + struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; + struct fbcon_ops *ops = info->fbcon_par; + + ops->save_graphics = ops->graphics; + ops->graphics = 0; + if (info->fbops->fb_debug_enter) + info->fbops->fb_debug_enter(info); + fbcon_set_palette(vc, color_table); + return 0; +} + +static int fbcon_debug_leave(struct vc_data *vc) +{ + struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; + struct fbcon_ops *ops = info->fbcon_par; + + ops->graphics = ops->save_graphics; + if (info->fbops->fb_debug_leave) + info->fbops->fb_debug_leave(info); + return 0; +} + static int fbcon_get_font(struct vc_data *vc, struct console_font *font) { u8 *fontdata = vc->vc_font.data; @@ -3276,6 +3300,8 @@ static const struct consw fb_con = { .con_screen_pos = fbcon_screen_pos, .con_getxy = fbcon_getxy, .con_resize = fbcon_resize, + .con_debug_enter = fbcon_debug_enter, + .con_debug_leave = fbcon_debug_leave, }; static struct notifier_block fbcon_event_notifier = { diff --git a/drivers/video/console/fbcon.h b/drivers/video/console/fbcon.h index 89a346880ec0..6bd2e0c7f209 100644 --- a/drivers/video/console/fbcon.h +++ b/drivers/video/console/fbcon.h @@ -74,6 +74,7 @@ struct fbcon_ops { int cursor_reset; int blank_state; int graphics; + int save_graphics; /* for debug enter/leave */ int flags; int rotate; int cur_rotate; diff --git a/drivers/video/controlfb.c b/drivers/video/controlfb.c index 49fcbe8f18ac..c225dcce89e7 100644 --- a/drivers/video/controlfb.c +++ b/drivers/video/controlfb.c @@ -40,6 +40,8 @@ #include <linux/vmalloc.h> #include <linux/delay.h> #include <linux/interrupt.h> +#include <linux/of.h> +#include <linux/of_address.h> #include <linux/fb.h> #include <linux/init.h> #include <linux/pci.h> diff --git a/drivers/video/cyber2000fb.c b/drivers/video/cyber2000fb.c index 3a561df2e8a2..0c1afd13ddd3 100644 --- a/drivers/video/cyber2000fb.c +++ b/drivers/video/cyber2000fb.c @@ -388,6 +388,7 @@ cyber2000fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, pseudo_val |= convert_bitfield(red, &var->red); pseudo_val |= convert_bitfield(green, &var->green); pseudo_val |= convert_bitfield(blue, &var->blue); + ret = 0; break; } @@ -436,6 +437,8 @@ static void cyber2000fb_write_ramdac_ctrl(struct cfb_info *cfb) cyber2000fb_writeb(i | 4, 0x3cf, cfb); cyber2000fb_writeb(val, 0x3c6, cfb); cyber2000fb_writeb(i, 0x3cf, cfb); + /* prevent card lock-up observed on x86 with CyberPro 2000 */ + cyber2000fb_readb(0x3cf, cfb); } static void cyber2000fb_set_timing(struct cfb_info *cfb, struct par_info *hw) diff --git a/drivers/video/da8xx-fb.c b/drivers/video/da8xx-fb.c index 8d244ba0f601..cad7d45c8bac 100644 --- a/drivers/video/da8xx-fb.c +++ b/drivers/video/da8xx-fb.c @@ -36,7 +36,9 @@ #define DRIVER_NAME "da8xx_lcdc" /* LCD Status Register */ +#define LCD_END_OF_FRAME1 BIT(9) #define LCD_END_OF_FRAME0 BIT(8) +#define LCD_PL_LOAD_DONE BIT(6) #define LCD_FIFO_UNDERFLOW BIT(5) #define LCD_SYNC_LOST BIT(2) @@ -58,11 +60,13 @@ #define LCD_PALETTE_LOAD_MODE(x) ((x) << 20) #define PALETTE_AND_DATA 0x00 #define PALETTE_ONLY 0x01 +#define DATA_ONLY 0x02 #define LCD_MONO_8BIT_MODE BIT(9) #define LCD_RASTER_ORDER BIT(8) #define LCD_TFT_MODE BIT(7) #define LCD_UNDERFLOW_INT_ENA BIT(6) +#define LCD_PL_ENABLE BIT(4) #define LCD_MONOCHROME_MODE BIT(1) #define LCD_RASTER_ENABLE BIT(0) #define LCD_TFT_ALT_ENABLE BIT(23) @@ -87,6 +91,10 @@ #define LCD_DMA_CTRL_REG 0x40 #define LCD_DMA_FRM_BUF_BASE_ADDR_0_REG 0x44 #define LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG 0x48 +#define LCD_DMA_FRM_BUF_BASE_ADDR_1_REG 0x4C +#define LCD_DMA_FRM_BUF_CEILING_ADDR_1_REG 0x50 + +#define LCD_NUM_BUFFERS 2 #define WSI_TIMEOUT 50 #define PALETTE_SIZE 256 @@ -111,13 +119,20 @@ static inline void lcdc_write(unsigned int val, unsigned int addr) struct da8xx_fb_par { resource_size_t p_palette_base; unsigned char *v_palette_base; + dma_addr_t vram_phys; + unsigned long vram_size; + void *vram_virt; + unsigned int dma_start; + unsigned int dma_end; struct clk *lcdc_clk; int irq; unsigned short pseudo_palette[16]; - unsigned int databuf_sz; unsigned int palette_sz; unsigned int pxl_clk; int blank; + wait_queue_head_t vsync_wait; + int vsync_flag; + int vsync_timeout; #ifdef CONFIG_CPU_FREQ struct notifier_block freq_transition; #endif @@ -148,9 +163,9 @@ static struct fb_fix_screeninfo da8xx_fb_fix __devinitdata = { .type = FB_TYPE_PACKED_PIXELS, .type_aux = 0, .visual = FB_VISUAL_PSEUDOCOLOR, - .xpanstep = 1, + .xpanstep = 0, .ypanstep = 1, - .ywrapstep = 1, + .ywrapstep = 0, .accel = FB_ACCEL_NONE }; @@ -221,22 +236,48 @@ static inline void lcd_disable_raster(void) static void lcd_blit(int load_mode, struct da8xx_fb_par *par) { - u32 tmp = par->p_palette_base + par->databuf_sz - 4; - u32 reg; + u32 start; + u32 end; + u32 reg_ras; + u32 reg_dma; + + /* init reg to clear PLM (loading mode) fields */ + reg_ras = lcdc_read(LCD_RASTER_CTRL_REG); + reg_ras &= ~(3 << 20); + + reg_dma = lcdc_read(LCD_DMA_CTRL_REG); + + if (load_mode == LOAD_DATA) { + start = par->dma_start; + end = par->dma_end; + + reg_ras |= LCD_PALETTE_LOAD_MODE(DATA_ONLY); + reg_dma |= LCD_END_OF_FRAME_INT_ENA; + reg_dma |= LCD_DUAL_FRAME_BUFFER_ENABLE; + + lcdc_write(start, LCD_DMA_FRM_BUF_BASE_ADDR_0_REG); + lcdc_write(end, LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG); + lcdc_write(start, LCD_DMA_FRM_BUF_BASE_ADDR_1_REG); + lcdc_write(end, LCD_DMA_FRM_BUF_CEILING_ADDR_1_REG); + } else if (load_mode == LOAD_PALETTE) { + start = par->p_palette_base; + end = start + par->palette_sz - 1; + + reg_ras |= LCD_PALETTE_LOAD_MODE(PALETTE_ONLY); + reg_ras |= LCD_PL_ENABLE; + + lcdc_write(start, LCD_DMA_FRM_BUF_BASE_ADDR_0_REG); + lcdc_write(end, LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG); + } - /* Update the databuf in the hw. */ - lcdc_write(par->p_palette_base, LCD_DMA_FRM_BUF_BASE_ADDR_0_REG); - lcdc_write(tmp, LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG); + lcdc_write(reg_dma, LCD_DMA_CTRL_REG); + lcdc_write(reg_ras, LCD_RASTER_CTRL_REG); - /* Start the DMA. */ - reg = lcdc_read(LCD_RASTER_CTRL_REG); - reg &= ~(3 << 20); - if (load_mode == LOAD_DATA) - reg |= LCD_PALETTE_LOAD_MODE(PALETTE_AND_DATA); - else if (load_mode == LOAD_PALETTE) - reg |= LCD_PALETTE_LOAD_MODE(PALETTE_ONLY); - - lcdc_write(reg, LCD_RASTER_CTRL_REG); + /* + * The Raster enable bit must be set after all other control fields are + * set. + */ + lcd_enable_raster(); } /* Configure the Burst Size of DMA */ @@ -368,12 +409,8 @@ static int lcd_cfg_display(const struct lcd_ctrl_config *cfg) static int lcd_cfg_frame_buffer(struct da8xx_fb_par *par, u32 width, u32 height, u32 bpp, u32 raster_order) { - u32 bpl, reg; + u32 reg; - /* Disable Dual Frame Buffer. */ - reg = lcdc_read(LCD_DMA_CTRL_REG); - lcdc_write(reg & ~LCD_DUAL_FRAME_BUFFER_ENABLE, - LCD_DMA_CTRL_REG); /* Set the Panel Width */ /* Pixels per line = (PPL + 1)*16 */ /*0x3F in bits 4..9 gives max horisontal resolution = 1024 pixels*/ @@ -410,9 +447,6 @@ static int lcd_cfg_frame_buffer(struct da8xx_fb_par *par, u32 width, u32 height, return -EINVAL; } - bpl = width * bpp / 8; - par->databuf_sz = height * bpl + par->palette_sz; - return 0; } @@ -421,8 +455,9 @@ static int fb_setcolreg(unsigned regno, unsigned red, unsigned green, struct fb_info *info) { struct da8xx_fb_par *par = info->par; - unsigned short *palette = (unsigned short *)par->v_palette_base; + unsigned short *palette = (unsigned short *) par->v_palette_base; u_short pal; + int update_hw = 0; if (regno > 255) return 1; @@ -439,8 +474,10 @@ static int fb_setcolreg(unsigned regno, unsigned red, unsigned green, pal |= (green & 0x00f0); pal |= (blue & 0x000f); - palette[regno] = pal; - + if (palette[regno] != pal) { + update_hw = 1; + palette[regno] = pal; + } } else if ((info->var.bits_per_pixel == 16) && regno < 16) { red >>= (16 - info->var.red.length); red <<= info->var.red.offset; @@ -453,9 +490,16 @@ static int fb_setcolreg(unsigned regno, unsigned red, unsigned green, par->pseudo_palette[regno] = red | green | blue; - palette[0] = 0x4000; + if (palette[0] != 0x4000) { + update_hw = 1; + palette[0] = 0x4000; + } } + /* Update the palette in the h/w as needed. */ + if (update_hw) + lcd_blit(LOAD_PALETTE, par); + return 0; } @@ -541,15 +585,54 @@ static int lcd_init(struct da8xx_fb_par *par, const struct lcd_ctrl_config *cfg, static irqreturn_t lcdc_irq_handler(int irq, void *arg) { + struct da8xx_fb_par *par = arg; u32 stat = lcdc_read(LCD_STAT_REG); + u32 reg_ras; if ((stat & LCD_SYNC_LOST) && (stat & LCD_FIFO_UNDERFLOW)) { lcd_disable_raster(); lcdc_write(stat, LCD_STAT_REG); lcd_enable_raster(); - } else + } else if (stat & LCD_PL_LOAD_DONE) { + /* + * Must disable raster before changing state of any control bit. + * And also must be disabled before clearing the PL loading + * interrupt via the following write to the status register. If + * this is done after then one gets multiple PL done interrupts. + */ + lcd_disable_raster(); + lcdc_write(stat, LCD_STAT_REG); + /* Disable PL completion inerrupt */ + reg_ras = lcdc_read(LCD_RASTER_CTRL_REG); + reg_ras &= ~LCD_PL_ENABLE; + lcdc_write(reg_ras, LCD_RASTER_CTRL_REG); + + /* Setup and start data loading mode */ + lcd_blit(LOAD_DATA, par); + } else { + lcdc_write(stat, LCD_STAT_REG); + + if (stat & LCD_END_OF_FRAME0) { + lcdc_write(par->dma_start, + LCD_DMA_FRM_BUF_BASE_ADDR_0_REG); + lcdc_write(par->dma_end, + LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG); + par->vsync_flag = 1; + wake_up_interruptible(&par->vsync_wait); + } + + if (stat & LCD_END_OF_FRAME1) { + lcdc_write(par->dma_start, + LCD_DMA_FRM_BUF_BASE_ADDR_1_REG); + lcdc_write(par->dma_end, + LCD_DMA_FRM_BUF_CEILING_ADDR_1_REG); + par->vsync_flag = 1; + wake_up_interruptible(&par->vsync_wait); + } + } + return IRQ_HANDLED; } @@ -654,9 +737,10 @@ static int __devexit fb_remove(struct platform_device *dev) unregister_framebuffer(info); fb_dealloc_cmap(&info->cmap); - dma_free_coherent(NULL, par->databuf_sz + PAGE_SIZE, - info->screen_base - PAGE_SIZE, - info->fix.smem_start); + dma_free_coherent(NULL, PALETTE_SIZE, par->v_palette_base, + par->p_palette_base); + dma_free_coherent(NULL, par->vram_size, par->vram_virt, + par->vram_phys); free_irq(par->irq, par); clk_disable(par->lcdc_clk); clk_put(par->lcdc_clk); @@ -668,6 +752,39 @@ static int __devexit fb_remove(struct platform_device *dev) return 0; } +/* + * Function to wait for vertical sync which for this LCD peripheral + * translates into waiting for the current raster frame to complete. + */ +static int fb_wait_for_vsync(struct fb_info *info) +{ + struct da8xx_fb_par *par = info->par; + int ret; + + /* + * Set flag to 0 and wait for isr to set to 1. It would seem there is a + * race condition here where the ISR could have occured just before or + * just after this set. But since we are just coarsely waiting for + * a frame to complete then that's OK. i.e. if the frame completed + * just before this code executed then we have to wait another full + * frame time but there is no way to avoid such a situation. On the + * other hand if the frame completed just after then we don't need + * to wait long at all. Either way we are guaranteed to return to the + * user immediately after a frame completion which is all that is + * required. + */ + par->vsync_flag = 0; + ret = wait_event_interruptible_timeout(par->vsync_wait, + par->vsync_flag != 0, + par->vsync_timeout); + if (ret < 0) + return ret; + if (ret == 0) + return -ETIMEDOUT; + + return 0; +} + static int fb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) { @@ -697,6 +814,8 @@ static int fb_ioctl(struct fb_info *info, unsigned int cmd, sync_arg.pulse_width, sync_arg.front_porch); break; + case FBIO_WAITFORVSYNC: + return fb_wait_for_vsync(info); default: return -EINVAL; } @@ -732,10 +851,47 @@ static int cfb_blank(int blank, struct fb_info *info) return ret; } +/* + * Set new x,y offsets in the virtual display for the visible area and switch + * to the new mode. + */ +static int da8xx_pan_display(struct fb_var_screeninfo *var, + struct fb_info *fbi) +{ + int ret = 0; + struct fb_var_screeninfo new_var; + struct da8xx_fb_par *par = fbi->par; + struct fb_fix_screeninfo *fix = &fbi->fix; + unsigned int end; + unsigned int start; + + if (var->xoffset != fbi->var.xoffset || + var->yoffset != fbi->var.yoffset) { + memcpy(&new_var, &fbi->var, sizeof(new_var)); + new_var.xoffset = var->xoffset; + new_var.yoffset = var->yoffset; + if (fb_check_var(&new_var, fbi)) + ret = -EINVAL; + else { + memcpy(&fbi->var, &new_var, sizeof(new_var)); + + start = fix->smem_start + + new_var.yoffset * fix->line_length + + new_var.xoffset * var->bits_per_pixel / 8; + end = start + var->yres * fix->line_length - 1; + par->dma_start = start; + par->dma_end = end; + } + } + + return ret; +} + static struct fb_ops da8xx_fb_ops = { .owner = THIS_MODULE, .fb_check_var = fb_check_var, .fb_setcolreg = fb_setcolreg, + .fb_pan_display = da8xx_pan_display, .fb_ioctl = fb_ioctl, .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, @@ -829,40 +985,53 @@ static int __init fb_probe(struct platform_device *device) } /* allocate frame buffer */ - da8xx_fb_info->screen_base = dma_alloc_coherent(NULL, - par->databuf_sz + PAGE_SIZE, - (resource_size_t *) - &da8xx_fb_info->fix.smem_start, - GFP_KERNEL | GFP_DMA); - - if (!da8xx_fb_info->screen_base) { + par->vram_size = lcdc_info->width * lcdc_info->height * lcd_cfg->bpp; + par->vram_size = PAGE_ALIGN(par->vram_size/8); + par->vram_size = par->vram_size * LCD_NUM_BUFFERS; + + par->vram_virt = dma_alloc_coherent(NULL, + par->vram_size, + (resource_size_t *) &par->vram_phys, + GFP_KERNEL | GFP_DMA); + if (!par->vram_virt) { dev_err(&device->dev, "GLCD: kmalloc for frame buffer failed\n"); ret = -EINVAL; goto err_release_fb; } - /* move palette base pointer by (PAGE_SIZE - palette_sz) bytes */ - par->v_palette_base = da8xx_fb_info->screen_base + - (PAGE_SIZE - par->palette_sz); - par->p_palette_base = da8xx_fb_info->fix.smem_start + - (PAGE_SIZE - par->palette_sz); - - /* the rest of the frame buffer is pixel data */ - da8xx_fb_info->screen_base = par->v_palette_base + par->palette_sz; - da8xx_fb_fix.smem_start = par->p_palette_base + par->palette_sz; - da8xx_fb_fix.smem_len = par->databuf_sz - par->palette_sz; - da8xx_fb_fix.line_length = (lcdc_info->width * lcd_cfg->bpp) / 8; + da8xx_fb_info->screen_base = (char __iomem *) par->vram_virt; + da8xx_fb_fix.smem_start = par->vram_phys; + da8xx_fb_fix.smem_len = par->vram_size; + da8xx_fb_fix.line_length = (lcdc_info->width * lcd_cfg->bpp) / 8; + + par->dma_start = par->vram_phys; + par->dma_end = par->dma_start + lcdc_info->height * + da8xx_fb_fix.line_length - 1; + + /* allocate palette buffer */ + par->v_palette_base = dma_alloc_coherent(NULL, + PALETTE_SIZE, + (resource_size_t *) + &par->p_palette_base, + GFP_KERNEL | GFP_DMA); + if (!par->v_palette_base) { + dev_err(&device->dev, + "GLCD: kmalloc for palette buffer failed\n"); + ret = -EINVAL; + goto err_release_fb_mem; + } + memset(par->v_palette_base, 0, PALETTE_SIZE); par->irq = platform_get_irq(device, 0); if (par->irq < 0) { ret = -ENOENT; - goto err_release_fb_mem; + goto err_release_pl_mem; } ret = request_irq(par->irq, lcdc_irq_handler, 0, DRIVER_NAME, par); if (ret) - goto err_release_fb_mem; + goto err_release_pl_mem; /* Initialize par */ da8xx_fb_info->var.bits_per_pixel = lcd_cfg->bpp; @@ -870,8 +1039,8 @@ static int __init fb_probe(struct platform_device *device) da8xx_fb_var.xres = lcdc_info->width; da8xx_fb_var.xres_virtual = lcdc_info->width; - da8xx_fb_var.yres = lcdc_info->height; - da8xx_fb_var.yres_virtual = lcdc_info->height; + da8xx_fb_var.yres = lcdc_info->height; + da8xx_fb_var.yres_virtual = lcdc_info->height * LCD_NUM_BUFFERS; da8xx_fb_var.grayscale = lcd_cfg->p_disp_panel->panel_shade == MONOCHROME ? 1 : 0; @@ -892,18 +1061,18 @@ static int __init fb_probe(struct platform_device *device) ret = fb_alloc_cmap(&da8xx_fb_info->cmap, PALETTE_SIZE, 0); if (ret) goto err_free_irq; - - /* First palette_sz byte of the frame buffer is the palette */ da8xx_fb_info->cmap.len = par->palette_sz; - /* Flush the buffer to the screen. */ - lcd_blit(LOAD_DATA, par); - /* initialize var_screeninfo */ da8xx_fb_var.activate = FB_ACTIVATE_FORCE; fb_set_var(da8xx_fb_info, &da8xx_fb_var); dev_set_drvdata(&device->dev, da8xx_fb_info); + + /* initialize the vsync wait queue */ + init_waitqueue_head(&par->vsync_wait); + par->vsync_timeout = HZ / 5; + /* Register the Frame Buffer */ if (register_framebuffer(da8xx_fb_info) < 0) { dev_err(&device->dev, @@ -919,10 +1088,6 @@ static int __init fb_probe(struct platform_device *device) goto err_cpu_freq; } #endif - - /* enable raster engine */ - lcd_enable_raster(); - return 0; #ifdef CONFIG_CPU_FREQ @@ -936,10 +1101,12 @@ err_dealloc_cmap: err_free_irq: free_irq(par->irq, par); +err_release_pl_mem: + dma_free_coherent(NULL, PALETTE_SIZE, par->v_palette_base, + par->p_palette_base); + err_release_fb_mem: - dma_free_coherent(NULL, par->databuf_sz + PAGE_SIZE, - da8xx_fb_info->screen_base - PAGE_SIZE, - da8xx_fb_info->fix.smem_start); + dma_free_coherent(NULL, par->vram_size, par->vram_virt, par->vram_phys); err_release_fb: framebuffer_release(da8xx_fb_info); diff --git a/drivers/video/efifb.c b/drivers/video/efifb.c index ecf405562f5c..4a56f46af40a 100644 --- a/drivers/video/efifb.c +++ b/drivers/video/efifb.c @@ -168,7 +168,7 @@ static void efifb_destroy(struct fb_info *info) { if (info->screen_base) iounmap(info->screen_base); - release_mem_region(info->aperture_base, info->aperture_size); + release_mem_region(info->apertures->ranges[0].base, info->apertures->ranges[0].size); framebuffer_release(info); } @@ -292,8 +292,13 @@ static int __devinit efifb_probe(struct platform_device *dev) info->pseudo_palette = info->par; info->par = NULL; - info->aperture_base = efifb_fix.smem_start; - info->aperture_size = size_remap; + info->apertures = alloc_apertures(1); + if (!info->apertures) { + err = -ENOMEM; + goto err_release_fb; + } + info->apertures->ranges[0].base = efifb_fix.smem_start; + info->apertures->ranges[0].size = size_remap; info->screen_base = ioremap(efifb_fix.smem_start, efifb_fix.smem_len); if (!info->screen_base) { diff --git a/drivers/video/fb_defio.c b/drivers/video/fb_defio.c index 6113c47e095a..6b93ef93cb12 100644 --- a/drivers/video/fb_defio.c +++ b/drivers/video/fb_defio.c @@ -66,7 +66,7 @@ static int fb_deferred_io_fault(struct vm_area_struct *vma, return 0; } -int fb_deferred_io_fsync(struct file *file, struct dentry *dentry, int datasync) +int fb_deferred_io_fsync(struct file *file, int datasync) { struct fb_info *info = file->private_data; @@ -100,6 +100,16 @@ static int fb_deferred_io_mkwrite(struct vm_area_struct *vma, /* protect against the workqueue changing the page list */ mutex_lock(&fbdefio->lock); + /* + * We want the page to remain locked from ->page_mkwrite until + * the PTE is marked dirty to avoid page_mkclean() being called + * before the PTE is updated, which would leave the page ignored + * by defio. + * Do this by locking the page here and informing the caller + * about it with VM_FAULT_LOCKED. + */ + lock_page(page); + /* we loop through the pagelist before adding in order to keep the pagelist sorted */ list_for_each_entry(cur, &fbdefio->pagelist, lru) { @@ -121,7 +131,7 @@ page_already_added: /* come back after delay to process the deferred IO */ schedule_delayed_work(&info->deferred_work, fbdefio->delay); - return 0; + return VM_FAULT_LOCKED; } static const struct vm_operations_struct fb_deferred_io_vm_ops = { diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index a15b44e9c003..731fce64df9d 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -1468,16 +1468,70 @@ static int fb_check_foreignness(struct fb_info *fi) return 0; } -static bool fb_do_apertures_overlap(struct fb_info *gen, struct fb_info *hw) +static bool apertures_overlap(struct aperture *gen, struct aperture *hw) { /* is the generic aperture base the same as the HW one */ - if (gen->aperture_base == hw->aperture_base) + if (gen->base == hw->base) return true; /* is the generic aperture base inside the hw base->hw base+size */ - if (gen->aperture_base > hw->aperture_base && gen->aperture_base <= hw->aperture_base + hw->aperture_size) + if (gen->base > hw->base && gen->base <= hw->base + hw->size) return true; return false; } + +static bool fb_do_apertures_overlap(struct apertures_struct *gena, + struct apertures_struct *hwa) +{ + int i, j; + if (!hwa || !gena) + return false; + + for (i = 0; i < hwa->count; ++i) { + struct aperture *h = &hwa->ranges[i]; + for (j = 0; j < gena->count; ++j) { + struct aperture *g = &gena->ranges[j]; + printk(KERN_DEBUG "checking generic (%llx %llx) vs hw (%llx %llx)\n", + (unsigned long long)g->base, + (unsigned long long)g->size, + (unsigned long long)h->base, + (unsigned long long)h->size); + if (apertures_overlap(g, h)) + return true; + } + } + + return false; +} + +#define VGA_FB_PHYS 0xA0000 +void remove_conflicting_framebuffers(struct apertures_struct *a, + const char *name, bool primary) +{ + int i; + + /* check all firmware fbs and kick off if the base addr overlaps */ + for (i = 0 ; i < FB_MAX; i++) { + struct apertures_struct *gen_aper; + if (!registered_fb[i]) + continue; + + if (!(registered_fb[i]->flags & FBINFO_MISC_FIRMWARE)) + continue; + + gen_aper = registered_fb[i]->apertures; + if (fb_do_apertures_overlap(gen_aper, a) || + (primary && gen_aper && gen_aper->count && + gen_aper->ranges[0].base == VGA_FB_PHYS)) { + + printk(KERN_ERR "fb: conflicting fb hw usage " + "%s vs %s - removing generic driver\n", + name, registered_fb[i]->fix.id); + unregister_framebuffer(registered_fb[i]); + } + } +} +EXPORT_SYMBOL(remove_conflicting_framebuffers); + /** * register_framebuffer - registers a frame buffer device * @fb_info: frame buffer info structure @@ -1501,21 +1555,8 @@ register_framebuffer(struct fb_info *fb_info) if (fb_check_foreignness(fb_info)) return -ENOSYS; - /* check all firmware fbs and kick off if the base addr overlaps */ - for (i = 0 ; i < FB_MAX; i++) { - if (!registered_fb[i]) - continue; - - if (registered_fb[i]->flags & FBINFO_MISC_FIRMWARE) { - if (fb_do_apertures_overlap(registered_fb[i], fb_info)) { - printk(KERN_ERR "fb: conflicting fb hw usage " - "%s vs %s - removing generic driver\n", - fb_info->fix.id, - registered_fb[i]->fix.id); - unregister_framebuffer(registered_fb[i]); - } - } - } + remove_conflicting_framebuffers(fb_info->apertures, fb_info->fix.id, + fb_is_primary_device(fb_info)); num_registered_fb++; for (i = 0 ; i < FB_MAX; i++) diff --git a/drivers/video/fbsysfs.c b/drivers/video/fbsysfs.c index 81aa3129c17d..0a08f1341227 100644 --- a/drivers/video/fbsysfs.c +++ b/drivers/video/fbsysfs.c @@ -80,6 +80,7 @@ EXPORT_SYMBOL(framebuffer_alloc); */ void framebuffer_release(struct fb_info *info) { + kfree(info->apertures); kfree(info); } EXPORT_SYMBOL(framebuffer_release); diff --git a/drivers/video/ffb.c b/drivers/video/ffb.c index a42fabab69df..f6ecfab296d3 100644 --- a/drivers/video/ffb.c +++ b/drivers/video/ffb.c @@ -896,7 +896,7 @@ static void ffb_init_fix(struct fb_info *info) static int __devinit ffb_probe(struct of_device *op, const struct of_device_id *match) { - struct device_node *dp = op->node; + struct device_node *dp = op->dev.of_node; struct ffb_fbc __iomem *fbc; struct ffb_dac __iomem *dac; struct fb_info *info; @@ -1053,8 +1053,11 @@ static const struct of_device_id ffb_match[] = { MODULE_DEVICE_TABLE(of, ffb_match); static struct of_platform_driver ffb_driver = { - .name = "ffb", - .match_table = ffb_match, + .driver = { + .name = "ffb", + .owner = THIS_MODULE, + .of_match_table = ffb_match, + }, .probe = ffb_probe, .remove = __devexit_p(ffb_remove), }; @@ -1064,12 +1067,12 @@ static int __init ffb_init(void) if (fb_get_options("ffb", NULL)) return -ENODEV; - return of_register_driver(&ffb_driver, &of_bus_type); + return of_register_platform_driver(&ffb_driver); } static void __exit ffb_exit(void) { - of_unregister_driver(&ffb_driver); + of_unregister_platform_driver(&ffb_driver); } module_init(ffb_init); diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c index 994358a4f302..e38ad2224540 100644 --- a/drivers/video/fsl-diu-fb.c +++ b/drivers/video/fsl-diu-fb.c @@ -34,7 +34,8 @@ #include <linux/of_platform.h> #include <sysdev/fsl_soc.h> -#include "fsl-diu-fb.h" +#include <linux/fsl-diu-fb.h> +#include "edid.h" /* * These parameters give default parameters @@ -217,6 +218,7 @@ struct mfb_info { int x_aoi_d; /* aoi display x offset to physical screen */ int y_aoi_d; /* aoi display y offset to physical screen */ struct fsl_diu_data *parent; + u8 *edid_data; }; @@ -317,6 +319,17 @@ static void fsl_diu_free(void *virt, size_t size) free_pages_exact(virt, size); } +/* + * Workaround for failed writing desc register of planes. + * Needed with MPC5121 DIU rev 2.0 silicon. + */ +void wr_reg_wa(u32 *reg, u32 val) +{ + do { + out_be32(reg, val); + } while (in_be32(reg) != val); +} + static int fsl_diu_enable_panel(struct fb_info *info) { struct mfb_info *pmfbi, *cmfbi, *mfbi = info->par; @@ -330,7 +343,7 @@ static int fsl_diu_enable_panel(struct fb_info *info) switch (mfbi->index) { case 0: /* plane 0 */ if (hw->desc[0] != ad->paddr) - out_be32(&hw->desc[0], ad->paddr); + wr_reg_wa(&hw->desc[0], ad->paddr); break; case 1: /* plane 1 AOI 0 */ cmfbi = machine_data->fsl_diu_info[2]->par; @@ -340,7 +353,7 @@ static int fsl_diu_enable_panel(struct fb_info *info) cpu_to_le32(cmfbi->ad->paddr); else ad->next_ad = 0; - out_be32(&hw->desc[1], ad->paddr); + wr_reg_wa(&hw->desc[1], ad->paddr); } break; case 3: /* plane 2 AOI 0 */ @@ -351,14 +364,14 @@ static int fsl_diu_enable_panel(struct fb_info *info) cpu_to_le32(cmfbi->ad->paddr); else ad->next_ad = 0; - out_be32(&hw->desc[2], ad->paddr); + wr_reg_wa(&hw->desc[2], ad->paddr); } break; case 2: /* plane 1 AOI 1 */ pmfbi = machine_data->fsl_diu_info[1]->par; ad->next_ad = 0; if (hw->desc[1] == machine_data->dummy_ad->paddr) - out_be32(&hw->desc[1], ad->paddr); + wr_reg_wa(&hw->desc[1], ad->paddr); else /* AOI0 open */ pmfbi->ad->next_ad = cpu_to_le32(ad->paddr); break; @@ -366,7 +379,7 @@ static int fsl_diu_enable_panel(struct fb_info *info) pmfbi = machine_data->fsl_diu_info[3]->par; ad->next_ad = 0; if (hw->desc[2] == machine_data->dummy_ad->paddr) - out_be32(&hw->desc[2], ad->paddr); + wr_reg_wa(&hw->desc[2], ad->paddr); else /* AOI0 was open */ pmfbi->ad->next_ad = cpu_to_le32(ad->paddr); break; @@ -390,27 +403,24 @@ static int fsl_diu_disable_panel(struct fb_info *info) switch (mfbi->index) { case 0: /* plane 0 */ if (hw->desc[0] != machine_data->dummy_ad->paddr) - out_be32(&hw->desc[0], - machine_data->dummy_ad->paddr); + wr_reg_wa(&hw->desc[0], machine_data->dummy_ad->paddr); break; case 1: /* plane 1 AOI 0 */ cmfbi = machine_data->fsl_diu_info[2]->par; if (cmfbi->count > 0) /* AOI1 is open */ - out_be32(&hw->desc[1], cmfbi->ad->paddr); + wr_reg_wa(&hw->desc[1], cmfbi->ad->paddr); /* move AOI1 to the first */ else /* AOI1 was closed */ - out_be32(&hw->desc[1], - machine_data->dummy_ad->paddr); + wr_reg_wa(&hw->desc[1], machine_data->dummy_ad->paddr); /* close AOI 0 */ break; case 3: /* plane 2 AOI 0 */ cmfbi = machine_data->fsl_diu_info[4]->par; if (cmfbi->count > 0) /* AOI1 is open */ - out_be32(&hw->desc[2], cmfbi->ad->paddr); + wr_reg_wa(&hw->desc[2], cmfbi->ad->paddr); /* move AOI1 to the first */ else /* AOI1 was closed */ - out_be32(&hw->desc[2], - machine_data->dummy_ad->paddr); + wr_reg_wa(&hw->desc[2], machine_data->dummy_ad->paddr); /* close AOI 0 */ break; case 2: /* plane 1 AOI 1 */ @@ -421,7 +431,7 @@ static int fsl_diu_disable_panel(struct fb_info *info) /* AOI0 is open, must be the first */ pmfbi->ad->next_ad = 0; } else /* AOI1 is the first in the chain */ - out_be32(&hw->desc[1], machine_data->dummy_ad->paddr); + wr_reg_wa(&hw->desc[1], machine_data->dummy_ad->paddr); /* close AOI 1 */ break; case 4: /* plane 2 AOI 1 */ @@ -432,7 +442,7 @@ static int fsl_diu_disable_panel(struct fb_info *info) /* AOI0 is open, must be the first */ pmfbi->ad->next_ad = 0; } else /* AOI1 is the first in the chain */ - out_be32(&hw->desc[2], machine_data->dummy_ad->paddr); + wr_reg_wa(&hw->desc[2], machine_data->dummy_ad->paddr); /* close AOI 1 */ break; default: @@ -1100,6 +1110,10 @@ static int fsl_diu_open(struct fb_info *info, int user) struct mfb_info *mfbi = info->par; int res = 0; + /* free boot splash memory on first /dev/fb0 open */ + if (!mfbi->index && diu_ops.release_bootmem) + diu_ops.release_bootmem(); + spin_lock(&diu_lock); mfbi->count++; if (mfbi->count == 1) { @@ -1173,18 +1187,30 @@ static int __devinit install_fb(struct fb_info *info) int rc; struct mfb_info *mfbi = info->par; const char *aoi_mode, *init_aoi_mode = "320x240"; + struct fb_videomode *db = fsl_diu_mode_db; + unsigned int dbsize = ARRAY_SIZE(fsl_diu_mode_db); + int has_default_mode = 1; if (init_fbinfo(info)) return -EINVAL; - if (mfbi->index == 0) /* plane 0 */ + if (mfbi->index == 0) { /* plane 0 */ + if (mfbi->edid_data) { + /* Now build modedb from EDID */ + fb_edid_to_monspecs(mfbi->edid_data, &info->monspecs); + fb_videomode_to_modelist(info->monspecs.modedb, + info->monspecs.modedb_len, + &info->modelist); + db = info->monspecs.modedb; + dbsize = info->monspecs.modedb_len; + } aoi_mode = fb_mode; - else + } else { aoi_mode = init_aoi_mode; + } pr_debug("mode used = %s\n", aoi_mode); - rc = fb_find_mode(&info->var, info, aoi_mode, fsl_diu_mode_db, - ARRAY_SIZE(fsl_diu_mode_db), &fsl_diu_default_mode, default_bpp); - + rc = fb_find_mode(&info->var, info, aoi_mode, db, dbsize, + &fsl_diu_default_mode, default_bpp); switch (rc) { case 1: pr_debug("using mode specified in @mode\n"); @@ -1202,10 +1228,50 @@ static int __devinit install_fb(struct fb_info *info) default: pr_debug("rc = %d\n", rc); pr_debug("failed to find mode\n"); - return -EINVAL; + /* + * For plane 0 we continue and look into + * driver's internal modedb. + */ + if (mfbi->index == 0 && mfbi->edid_data) + has_default_mode = 0; + else + return -EINVAL; break; } + if (!has_default_mode) { + rc = fb_find_mode(&info->var, info, aoi_mode, fsl_diu_mode_db, + ARRAY_SIZE(fsl_diu_mode_db), + &fsl_diu_default_mode, + default_bpp); + if (rc > 0 && rc < 5) + has_default_mode = 1; + } + + /* Still not found, use preferred mode from database if any */ + if (!has_default_mode && info->monspecs.modedb) { + struct fb_monspecs *specs = &info->monspecs; + struct fb_videomode *modedb = &specs->modedb[0]; + + /* + * Get preferred timing. If not found, + * first mode in database will be used. + */ + if (specs->misc & FB_MISC_1ST_DETAIL) { + int i; + + for (i = 0; i < specs->modedb_len; i++) { + if (specs->modedb[i].flag & FB_MODE_IS_FIRST) { + modedb = &specs->modedb[i]; + break; + } + } + } + + info->var.bits_per_pixel = default_bpp; + fb_videomode_to_var(&info->var, modedb); + } + pr_debug("xres_virtual %d\n", info->var.xres_virtual); pr_debug("bits_per_pixel %d\n", info->var.bits_per_pixel); @@ -1244,6 +1310,9 @@ static void uninstall_fb(struct fb_info *info) if (!mfbi->registered) return; + if (mfbi->index == 0) + kfree(mfbi->edid_data); + unregister_framebuffer(info); unmap_video_memory(info); if (&info->cmap) @@ -1421,12 +1490,13 @@ static ssize_t show_monitor(struct device *device, static int __devinit fsl_diu_probe(struct of_device *ofdev, const struct of_device_id *match) { - struct device_node *np = ofdev->node; + struct device_node *np = ofdev->dev.of_node; struct mfb_info *mfbi; phys_addr_t dummy_ad_addr; int ret, i, error = 0; struct resource res; struct fsl_diu_data *machine_data; + int diu_mode; machine_data = kzalloc(sizeof(struct fsl_diu_data), GFP_KERNEL); if (!machine_data) @@ -1443,6 +1513,17 @@ static int __devinit fsl_diu_probe(struct of_device *ofdev, mfbi = machine_data->fsl_diu_info[i]->par; memcpy(mfbi, &mfb_template[i], sizeof(struct mfb_info)); mfbi->parent = machine_data; + + if (mfbi->index == 0) { + const u8 *prop; + int len; + + /* Get EDID */ + prop = of_get_property(np, "edid", &len); + if (prop && len == EDID_LENGTH) + mfbi->edid_data = kmemdup(prop, EDID_LENGTH, + GFP_KERNEL); + } } ret = of_address_to_resource(np, 0, &res); @@ -1463,7 +1544,9 @@ static int __devinit fsl_diu_probe(struct of_device *ofdev, goto error2; } - out_be32(&dr.diu_reg->diu_mode, 0); /* disable DIU anyway*/ + diu_mode = in_be32(&dr.diu_reg->diu_mode); + if (diu_mode != MFB_MODE1) + out_be32(&dr.diu_reg->diu_mode, 0); /* disable DIU */ /* Get the IRQ of the DIU */ machine_data->irq = irq_of_parse_and_map(np, 0); @@ -1511,7 +1594,13 @@ static int __devinit fsl_diu_probe(struct of_device *ofdev, machine_data->dummy_ad->offset_xyd = 0; machine_data->dummy_ad->next_ad = 0; - out_be32(&dr.diu_reg->desc[0], machine_data->dummy_ad->paddr); + /* + * Let DIU display splash screen if it was pre-initialized + * by the bootloader, set dummy area descriptor otherwise. + */ + if (diu_mode != MFB_MODE1) + out_be32(&dr.diu_reg->desc[0], machine_data->dummy_ad->paddr); + out_be32(&dr.diu_reg->desc[1], machine_data->dummy_ad->paddr); out_be32(&dr.diu_reg->desc[2], machine_data->dummy_ad->paddr); @@ -1647,9 +1736,11 @@ static struct of_device_id fsl_diu_match[] = { MODULE_DEVICE_TABLE(of, fsl_diu_match); static struct of_platform_driver fsl_diu_driver = { - .owner = THIS_MODULE, - .name = "fsl_diu", - .match_table = fsl_diu_match, + .driver = { + .name = "fsl_diu", + .owner = THIS_MODULE, + .of_match_table = fsl_diu_match, + }, .probe = fsl_diu_probe, .remove = fsl_diu_remove, .suspend = fsl_diu_suspend, diff --git a/drivers/video/fsl-diu-fb.h b/drivers/video/fsl-diu-fb.h deleted file mode 100644 index fc295d7ea463..000000000000 --- a/drivers/video/fsl-diu-fb.h +++ /dev/null @@ -1,223 +0,0 @@ -/* - * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved. - * - * Freescale DIU Frame Buffer device driver - * - * Authors: Hongjun Chen <hong-jun.chen@freescale.com> - * Paul Widmer <paul.widmer@freescale.com> - * Srikanth Srinivasan <srikanth.srinivasan@freescale.com> - * York Sun <yorksun@freescale.com> - * - * Based on imxfb.c Copyright (C) 2004 S.Hauer, Pengutronix - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - */ - -#ifndef __FSL_DIU_FB_H__ -#define __FSL_DIU_FB_H__ - -/* Arbitrary threshold to determine the allocation method - * See mpc8610fb_set_par(), map_video_memory(), and unmap_video_memory() - */ -#define MEM_ALLOC_THRESHOLD (1024*768*4+32) -/* Minimum value that the pixel clock can be set to in pico seconds - * This is determined by platform clock/3 where the minimum platform - * clock is 533MHz. This gives 5629 pico seconds. - */ -#define MIN_PIX_CLK 5629 -#define MAX_PIX_CLK 96096 - -#include <linux/types.h> - -struct mfb_alpha { - int enable; - int alpha; -}; - -struct mfb_chroma_key { - int enable; - __u8 red_max; - __u8 green_max; - __u8 blue_max; - __u8 red_min; - __u8 green_min; - __u8 blue_min; -}; - -struct aoi_display_offset { - int x_aoi_d; - int y_aoi_d; -}; - -#define MFB_SET_CHROMA_KEY _IOW('M', 1, struct mfb_chroma_key) -#define MFB_WAIT_FOR_VSYNC _IOW('F', 0x20, u_int32_t) -#define MFB_SET_BRIGHTNESS _IOW('M', 3, __u8) - -#define MFB_SET_ALPHA 0x80014d00 -#define MFB_GET_ALPHA 0x40014d00 -#define MFB_SET_AOID 0x80084d04 -#define MFB_GET_AOID 0x40084d04 -#define MFB_SET_PIXFMT 0x80014d08 -#define MFB_GET_PIXFMT 0x40014d08 - -#define FBIOGET_GWINFO 0x46E0 -#define FBIOPUT_GWINFO 0x46E1 - -#ifdef __KERNEL__ -#include <linux/spinlock.h> - -/* - * These are the fields of area descriptor(in DDR memory) for every plane - */ -struct diu_ad { - /* Word 0(32-bit) in DDR memory */ -/* __u16 comp; */ -/* __u16 pixel_s:2; */ -/* __u16 pallete:1; */ -/* __u16 red_c:2; */ -/* __u16 green_c:2; */ -/* __u16 blue_c:2; */ -/* __u16 alpha_c:3; */ -/* __u16 byte_f:1; */ -/* __u16 res0:3; */ - - __be32 pix_fmt; /* hard coding pixel format */ - - /* Word 1(32-bit) in DDR memory */ - __le32 addr; - - /* Word 2(32-bit) in DDR memory */ -/* __u32 delta_xs:11; */ -/* __u32 res1:1; */ -/* __u32 delta_ys:11; */ -/* __u32 res2:1; */ -/* __u32 g_alpha:8; */ - __le32 src_size_g_alpha; - - /* Word 3(32-bit) in DDR memory */ -/* __u32 delta_xi:11; */ -/* __u32 res3:5; */ -/* __u32 delta_yi:11; */ -/* __u32 res4:3; */ -/* __u32 flip:2; */ - __le32 aoi_size; - - /* Word 4(32-bit) in DDR memory */ - /*__u32 offset_xi:11; - __u32 res5:5; - __u32 offset_yi:11; - __u32 res6:5; - */ - __le32 offset_xyi; - - /* Word 5(32-bit) in DDR memory */ - /*__u32 offset_xd:11; - __u32 res7:5; - __u32 offset_yd:11; - __u32 res8:5; */ - __le32 offset_xyd; - - - /* Word 6(32-bit) in DDR memory */ - __u8 ckmax_r; - __u8 ckmax_g; - __u8 ckmax_b; - __u8 res9; - - /* Word 7(32-bit) in DDR memory */ - __u8 ckmin_r; - __u8 ckmin_g; - __u8 ckmin_b; - __u8 res10; -/* __u32 res10:8; */ - - /* Word 8(32-bit) in DDR memory */ - __le32 next_ad; - - /* Word 9(32-bit) in DDR memory, just for 64-bit aligned */ - __u32 paddr; -} __attribute__ ((packed)); - -/* DIU register map */ -struct diu { - __be32 desc[3]; - __be32 gamma; - __be32 pallete; - __be32 cursor; - __be32 curs_pos; - __be32 diu_mode; - __be32 bgnd; - __be32 bgnd_wb; - __be32 disp_size; - __be32 wb_size; - __be32 wb_mem_addr; - __be32 hsyn_para; - __be32 vsyn_para; - __be32 syn_pol; - __be32 thresholds; - __be32 int_status; - __be32 int_mask; - __be32 colorbar[8]; - __be32 filling; - __be32 plut; -} __attribute__ ((packed)); - -struct diu_hw { - struct diu *diu_reg; - spinlock_t reg_lock; - - __u32 mode; /* DIU operation mode */ -}; - -struct diu_addr { - __u8 __iomem *vaddr; /* Virtual address */ - dma_addr_t paddr; /* Physical address */ - __u32 offset; -}; - -struct diu_pool { - struct diu_addr ad; - struct diu_addr gamma; - struct diu_addr pallete; - struct diu_addr cursor; -}; - -#define FSL_DIU_BASE_OFFSET 0x2C000 /* Offset of DIU */ -#define INT_LCDC 64 /* DIU interrupt number */ - -#define FSL_AOI_NUM 6 /* 5 AOIs and one dummy AOI */ - /* 1 for plane 0, 2 for plane 1&2 each */ - -/* Minimum X and Y resolutions */ -#define MIN_XRES 64 -#define MIN_YRES 64 - -/* HW cursor parameters */ -#define MAX_CURS 32 - -/* Modes of operation of DIU */ -#define MFB_MODE0 0 /* DIU off */ -#define MFB_MODE1 1 /* All three planes output to display */ -#define MFB_MODE2 2 /* Plane 1 to display, planes 2+3 written back*/ -#define MFB_MODE3 3 /* All three planes written back to memory */ -#define MFB_MODE4 4 /* Color bar generation */ - -/* INT_STATUS/INT_MASK field descriptions */ -#define INT_VSYNC 0x01 /* Vsync interrupt */ -#define INT_VSYNC_WB 0x02 /* Vsync interrupt for write back operation */ -#define INT_UNDRUN 0x04 /* Under run exception interrupt */ -#define INT_PARERR 0x08 /* Display parameters error interrupt */ -#define INT_LS_BF_VS 0x10 /* Lines before vsync. interrupt */ - -/* Panels'operation modes */ -#define MFB_TYPE_OUTPUT 0 /* Panel output to display */ -#define MFB_TYPE_OFF 1 /* Panel off */ -#define MFB_TYPE_WB 2 /* Panel written back to memory */ -#define MFB_TYPE_TEST 3 /* Panel generate color bar */ - -#endif /* __KERNEL__ */ -#endif /* __FSL_DIU_FB_H__ */ diff --git a/drivers/video/gbefb.c b/drivers/video/gbefb.c index 7d8c55d7fd28..ca3355e430bf 100644 --- a/drivers/video/gbefb.c +++ b/drivers/video/gbefb.c @@ -91,10 +91,10 @@ static uint32_t pseudo_palette[16]; static uint32_t gbe_cmap[256]; static int gbe_turned_on; /* 0 turned off, 1 turned on */ -static char *mode_option __initdata = NULL; +static char *mode_option __devinitdata = NULL; /* default CRT mode */ -static struct fb_var_screeninfo default_var_CRT __initdata = { +static struct fb_var_screeninfo default_var_CRT __devinitdata = { /* 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) */ .xres = 640, .yres = 480, @@ -125,7 +125,7 @@ static struct fb_var_screeninfo default_var_CRT __initdata = { }; /* default LCD mode */ -static struct fb_var_screeninfo default_var_LCD __initdata = { +static struct fb_var_screeninfo default_var_LCD __devinitdata = { /* 1600x1024, 8 bpp */ .xres = 1600, .yres = 1024, @@ -157,7 +157,7 @@ static struct fb_var_screeninfo default_var_LCD __initdata = { /* default modedb mode */ /* 640x480, 60 Hz, Non-Interlaced (25.172 MHz dotclock) */ -static struct fb_videomode default_mode_CRT __initdata = { +static struct fb_videomode default_mode_CRT __devinitdata = { .refresh = 60, .xres = 640, .yres = 480, @@ -172,7 +172,7 @@ static struct fb_videomode default_mode_CRT __initdata = { .vmode = FB_VMODE_NONINTERLACED, }; /* 1600x1024 SGI flatpanel 1600sw */ -static struct fb_videomode default_mode_LCD __initdata = { +static struct fb_videomode default_mode_LCD __devinitdata = { /* 1600x1024, 8 bpp */ .xres = 1600, .yres = 1024, @@ -186,8 +186,8 @@ static struct fb_videomode default_mode_LCD __initdata = { .vmode = FB_VMODE_NONINTERLACED, }; -static struct fb_videomode *default_mode __initdata = &default_mode_CRT; -static struct fb_var_screeninfo *default_var __initdata = &default_var_CRT; +static struct fb_videomode *default_mode __devinitdata = &default_mode_CRT; +static struct fb_var_screeninfo *default_var __devinitdata = &default_var_CRT; static int flat_panel_enabled = 0; @@ -1098,7 +1098,7 @@ static void gbefb_create_sysfs(struct device *dev) * Initialization */ -static int __init gbefb_setup(char *options) +static int __devinit gbefb_setup(char *options) { char *this_opt; diff --git a/drivers/video/geode/gxfb_core.c b/drivers/video/geode/gxfb_core.c index 76e7dac6f259..70b1d9d51c96 100644 --- a/drivers/video/geode/gxfb_core.c +++ b/drivers/video/geode/gxfb_core.c @@ -40,7 +40,7 @@ static int vram; static int vt_switch; /* Modes relevant to the GX (taken from modedb.c) */ -static struct fb_videomode gx_modedb[] __initdata = { +static struct fb_videomode gx_modedb[] __devinitdata = { /* 640x480-60 VESA */ { NULL, 60, 640, 480, 39682, 48, 16, 33, 10, 96, 2, 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, @@ -110,14 +110,15 @@ static struct fb_videomode gx_modedb[] __initdata = { #ifdef CONFIG_OLPC #include <asm/olpc.h> -static struct fb_videomode gx_dcon_modedb[] __initdata = { +static struct fb_videomode gx_dcon_modedb[] __devinitdata = { /* The only mode the DCON has is 1200x900 */ { NULL, 50, 1200, 900, 17460, 24, 8, 4, 5, 8, 3, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, 0 } }; -static void __init get_modedb(struct fb_videomode **modedb, unsigned int *size) +static void __devinit get_modedb(struct fb_videomode **modedb, + unsigned int *size) { if (olpc_has_dcon()) { *modedb = (struct fb_videomode *) gx_dcon_modedb; @@ -129,7 +130,8 @@ static void __init get_modedb(struct fb_videomode **modedb, unsigned int *size) } #else -static void __init get_modedb(struct fb_videomode **modedb, unsigned int *size) +static void __devinit get_modedb(struct fb_videomode **modedb, + unsigned int *size) { *modedb = (struct fb_videomode *) gx_modedb; *size = ARRAY_SIZE(gx_modedb); @@ -226,7 +228,8 @@ static int gxfb_blank(int blank_mode, struct fb_info *info) return gx_blank_display(info, blank_mode); } -static int __init gxfb_map_video_memory(struct fb_info *info, struct pci_dev *dev) +static int __devinit gxfb_map_video_memory(struct fb_info *info, + struct pci_dev *dev) { struct gxfb_par *par = info->par; int ret; @@ -290,7 +293,7 @@ static struct fb_ops gxfb_ops = { .fb_imageblit = cfb_imageblit, }; -static struct fb_info * __init gxfb_init_fbinfo(struct device *dev) +static struct fb_info *__devinit gxfb_init_fbinfo(struct device *dev) { struct gxfb_par *par; struct fb_info *info; @@ -371,7 +374,8 @@ static int gxfb_resume(struct pci_dev *pdev) } #endif -static int __init gxfb_probe(struct pci_dev *pdev, const struct pci_device_id *id) +static int __devinit gxfb_probe(struct pci_dev *pdev, + const struct pci_device_id *id) { struct gxfb_par *par; struct fb_info *info; @@ -451,7 +455,7 @@ static int __init gxfb_probe(struct pci_dev *pdev, const struct pci_device_id *i return ret; } -static void gxfb_remove(struct pci_dev *pdev) +static void __devexit gxfb_remove(struct pci_dev *pdev) { struct fb_info *info = pci_get_drvdata(pdev); struct gxfb_par *par = info->par; diff --git a/drivers/video/geode/lxfb_core.c b/drivers/video/geode/lxfb_core.c index 1a18da86d3fa..39bdbedf43b4 100644 --- a/drivers/video/geode/lxfb_core.c +++ b/drivers/video/geode/lxfb_core.c @@ -35,7 +35,7 @@ static int vt_switch; * we try to make it something sane - 640x480-60 is sane */ -static struct fb_videomode geode_modedb[] __initdata = { +static struct fb_videomode geode_modedb[] __devinitdata = { /* 640x480-60 */ { NULL, 60, 640, 480, 39682, 48, 8, 25, 2, 88, 2, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, @@ -219,14 +219,15 @@ static struct fb_videomode geode_modedb[] __initdata = { #ifdef CONFIG_OLPC #include <asm/olpc.h> -static struct fb_videomode olpc_dcon_modedb[] __initdata = { +static struct fb_videomode olpc_dcon_modedb[] __devinitdata = { /* The only mode the DCON has is 1200x900 */ { NULL, 50, 1200, 900, 17460, 24, 8, 4, 5, 8, 3, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, 0 } }; -static void __init get_modedb(struct fb_videomode **modedb, unsigned int *size) +static void __devinit get_modedb(struct fb_videomode **modedb, + unsigned int *size) { if (olpc_has_dcon()) { *modedb = (struct fb_videomode *) olpc_dcon_modedb; @@ -238,7 +239,8 @@ static void __init get_modedb(struct fb_videomode **modedb, unsigned int *size) } #else -static void __init get_modedb(struct fb_videomode **modedb, unsigned int *size) +static void __devinit get_modedb(struct fb_videomode **modedb, + unsigned int *size) { *modedb = (struct fb_videomode *) geode_modedb; *size = ARRAY_SIZE(geode_modedb); @@ -334,7 +336,7 @@ static int lxfb_blank(int blank_mode, struct fb_info *info) } -static int __init lxfb_map_video_memory(struct fb_info *info, +static int __devinit lxfb_map_video_memory(struct fb_info *info, struct pci_dev *dev) { struct lxfb_par *par = info->par; @@ -412,7 +414,7 @@ static struct fb_ops lxfb_ops = { .fb_imageblit = cfb_imageblit, }; -static struct fb_info * __init lxfb_init_fbinfo(struct device *dev) +static struct fb_info * __devinit lxfb_init_fbinfo(struct device *dev) { struct lxfb_par *par; struct fb_info *info; @@ -496,7 +498,7 @@ static int lxfb_resume(struct pci_dev *pdev) #define lxfb_resume NULL #endif -static int __init lxfb_probe(struct pci_dev *pdev, +static int __devinit lxfb_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct lxfb_par *par; @@ -588,7 +590,7 @@ err: return ret; } -static void lxfb_remove(struct pci_dev *pdev) +static void __devexit lxfb_remove(struct pci_dev *pdev) { struct fb_info *info = pci_get_drvdata(pdev); struct lxfb_par *par = info->par; diff --git a/drivers/video/hgafb.c b/drivers/video/hgafb.c index 8bbf251f83d9..af8f0f2cc782 100644 --- a/drivers/video/hgafb.c +++ b/drivers/video/hgafb.c @@ -106,7 +106,7 @@ static DEFINE_SPINLOCK(hga_reg_lock); /* Framebuffer driver structures */ -static struct fb_var_screeninfo __initdata hga_default_var = { +static struct fb_var_screeninfo hga_default_var __devinitdata = { .xres = 720, .yres = 348, .xres_virtual = 720, @@ -120,7 +120,7 @@ static struct fb_var_screeninfo __initdata hga_default_var = { .width = -1, }; -static struct fb_fix_screeninfo __initdata hga_fix = { +static struct fb_fix_screeninfo hga_fix __devinitdata = { .id = "HGA", .type = FB_TYPE_PACKED_PIXELS, /* (not sure) */ .visual = FB_VISUAL_MONO10, @@ -276,7 +276,7 @@ static void hga_blank(int blank_mode) spin_unlock_irqrestore(&hga_reg_lock, flags); } -static int __init hga_card_detect(void) +static int __devinit hga_card_detect(void) { int count = 0; void __iomem *p, *q; @@ -596,7 +596,7 @@ static int __devinit hgafb_probe(struct platform_device *pdev) return 0; } -static int hgafb_remove(struct platform_device *pdev) +static int __devexit hgafb_remove(struct platform_device *pdev) { struct fb_info *info = platform_get_drvdata(pdev); @@ -621,7 +621,7 @@ static int hgafb_remove(struct platform_device *pdev) static struct platform_driver hgafb_driver = { .probe = hgafb_probe, - .remove = hgafb_remove, + .remove = __devexit_p(hgafb_remove), .driver = { .name = "hgafb", }, diff --git a/drivers/video/hitfb.c b/drivers/video/hitfb.c index 393f3f3d3dfe..cfb8d6451014 100644 --- a/drivers/video/hitfb.c +++ b/drivers/video/hitfb.c @@ -30,14 +30,14 @@ #define WIDTH 640 -static struct fb_var_screeninfo hitfb_var __initdata = { +static struct fb_var_screeninfo hitfb_var __devinitdata = { .activate = FB_ACTIVATE_NOW, .height = -1, .width = -1, .vmode = FB_VMODE_NONINTERLACED, }; -static struct fb_fix_screeninfo hitfb_fix __initdata = { +static struct fb_fix_screeninfo hitfb_fix __devinitdata = { .id = "Hitachi HD64461", .type = FB_TYPE_PACKED_PIXELS, .accel = FB_ACCEL_NONE, @@ -417,7 +417,7 @@ err_fb: return ret; } -static int __exit hitfb_remove(struct platform_device *dev) +static int __devexit hitfb_remove(struct platform_device *dev) { struct fb_info *info = platform_get_drvdata(dev); @@ -462,7 +462,7 @@ static const struct dev_pm_ops hitfb_dev_pm_ops = { static struct platform_driver hitfb_driver = { .probe = hitfb_probe, - .remove = __exit_p(hitfb_remove), + .remove = __devexit_p(hitfb_remove), .driver = { .name = "hitfb", .owner = THIS_MODULE, diff --git a/drivers/video/imxfb.c b/drivers/video/imxfb.c index b4b6deceed15..43f0639b1c10 100644 --- a/drivers/video/imxfb.c +++ b/drivers/video/imxfb.c @@ -175,6 +175,7 @@ struct imxfb_info { struct imx_fb_videomode *mode; int num_modes; + struct backlight_device *bl; void (*lcd_power)(int); void (*backlight_power)(int); @@ -449,6 +450,73 @@ static int imxfb_set_par(struct fb_info *info) return 0; } + + +static int imxfb_bl_get_brightness(struct backlight_device *bl) +{ + struct imxfb_info *fbi = bl_get_data(bl); + + return readl(fbi->regs + LCDC_PWMR) & 0xFF; +} + +static int imxfb_bl_update_status(struct backlight_device *bl) +{ + struct imxfb_info *fbi = bl_get_data(bl); + int brightness = bl->props.brightness; + + if (bl->props.power != FB_BLANK_UNBLANK) + brightness = 0; + if (bl->props.fb_blank != FB_BLANK_UNBLANK) + brightness = 0; + + fbi->pwmr = (fbi->pwmr & ~0xFF) | brightness; + + if (bl->props.fb_blank != FB_BLANK_UNBLANK) + clk_enable(fbi->clk); + writel(fbi->pwmr, fbi->regs + LCDC_PWMR); + if (bl->props.fb_blank != FB_BLANK_UNBLANK) + clk_disable(fbi->clk); + + return 0; +} + +static const struct backlight_ops imxfb_lcdc_bl_ops = { + .update_status = imxfb_bl_update_status, + .get_brightness = imxfb_bl_get_brightness, +}; + +static void imxfb_init_backlight(struct imxfb_info *fbi) +{ + struct backlight_properties props; + struct backlight_device *bl; + + if (fbi->bl) + return; + + memset(&props, 0, sizeof(struct backlight_properties)); + props.max_brightness = 0xff; + writel(fbi->pwmr, fbi->regs + LCDC_PWMR); + + bl = backlight_device_register("imxfb-bl", &fbi->pdev->dev, fbi, + &imxfb_lcdc_bl_ops, &props); + if (IS_ERR(bl)) { + dev_err(&fbi->pdev->dev, "error %ld on backlight register\n", + PTR_ERR(bl)); + return; + } + + fbi->bl = bl; + bl->props.power = FB_BLANK_UNBLANK; + bl->props.fb_blank = FB_BLANK_UNBLANK; + bl->props.brightness = imxfb_bl_get_brightness(bl); +} + +static void imxfb_exit_backlight(struct imxfb_info *fbi) +{ + if (fbi->bl) + backlight_device_unregister(fbi->bl); +} + static void imxfb_enable_controller(struct imxfb_info *fbi) { pr_debug("Enabling LCD controller\n"); @@ -579,7 +647,6 @@ static int imxfb_activate_var(struct fb_var_screeninfo *var, struct fb_info *inf fbi->regs + LCDC_SIZE); writel(fbi->pcr, fbi->regs + LCDC_PCR); - writel(fbi->pwmr, fbi->regs + LCDC_PWMR); writel(fbi->lscr1, fbi->regs + LCDC_LSCR1); writel(fbi->dmacr, fbi->regs + LCDC_DMACR); @@ -779,6 +846,8 @@ static int __init imxfb_probe(struct platform_device *pdev) } imxfb_enable_controller(fbi); + fbi->pdev = pdev; + imxfb_init_backlight(fbi); return 0; @@ -816,6 +885,7 @@ static int __devexit imxfb_remove(struct platform_device *pdev) imxfb_disable_controller(fbi); + imxfb_exit_backlight(fbi); unregister_framebuffer(info); pdata = pdev->dev.platform_data; diff --git a/drivers/video/intelfb/intelfb.h b/drivers/video/intelfb/intelfb.h index 40984551c927..6b51175629c7 100644 --- a/drivers/video/intelfb/intelfb.h +++ b/drivers/video/intelfb/intelfb.h @@ -371,10 +371,6 @@ struct intelfb_info { ((dinfo)->chipset == INTEL_965G) || \ ((dinfo)->chipset == INTEL_965GM)) -#ifndef FBIO_WAITFORVSYNC -#define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32) -#endif - /*** function prototypes ***/ extern int intelfb_var_to_depth(const struct fb_var_screeninfo *var); diff --git a/drivers/video/jz4740_fb.c b/drivers/video/jz4740_fb.c new file mode 100644 index 000000000000..670ecaa0385a --- /dev/null +++ b/drivers/video/jz4740_fb.c @@ -0,0 +1,847 @@ +/* + * Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de> + * JZ4740 SoC LCD framebuffer driver + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/platform_device.h> + +#include <linux/clk.h> +#include <linux/delay.h> + +#include <linux/console.h> +#include <linux/fb.h> + +#include <linux/dma-mapping.h> + +#include <asm/mach-jz4740/jz4740_fb.h> +#include <asm/mach-jz4740/gpio.h> + +#define JZ_REG_LCD_CFG 0x00 +#define JZ_REG_LCD_VSYNC 0x04 +#define JZ_REG_LCD_HSYNC 0x08 +#define JZ_REG_LCD_VAT 0x0C +#define JZ_REG_LCD_DAH 0x10 +#define JZ_REG_LCD_DAV 0x14 +#define JZ_REG_LCD_PS 0x18 +#define JZ_REG_LCD_CLS 0x1C +#define JZ_REG_LCD_SPL 0x20 +#define JZ_REG_LCD_REV 0x24 +#define JZ_REG_LCD_CTRL 0x30 +#define JZ_REG_LCD_STATE 0x34 +#define JZ_REG_LCD_IID 0x38 +#define JZ_REG_LCD_DA0 0x40 +#define JZ_REG_LCD_SA0 0x44 +#define JZ_REG_LCD_FID0 0x48 +#define JZ_REG_LCD_CMD0 0x4C +#define JZ_REG_LCD_DA1 0x50 +#define JZ_REG_LCD_SA1 0x54 +#define JZ_REG_LCD_FID1 0x58 +#define JZ_REG_LCD_CMD1 0x5C + +#define JZ_LCD_CFG_SLCD BIT(31) +#define JZ_LCD_CFG_PS_DISABLE BIT(23) +#define JZ_LCD_CFG_CLS_DISABLE BIT(22) +#define JZ_LCD_CFG_SPL_DISABLE BIT(21) +#define JZ_LCD_CFG_REV_DISABLE BIT(20) +#define JZ_LCD_CFG_HSYNCM BIT(19) +#define JZ_LCD_CFG_PCLKM BIT(18) +#define JZ_LCD_CFG_INV BIT(17) +#define JZ_LCD_CFG_SYNC_DIR BIT(16) +#define JZ_LCD_CFG_PS_POLARITY BIT(15) +#define JZ_LCD_CFG_CLS_POLARITY BIT(14) +#define JZ_LCD_CFG_SPL_POLARITY BIT(13) +#define JZ_LCD_CFG_REV_POLARITY BIT(12) +#define JZ_LCD_CFG_HSYNC_ACTIVE_LOW BIT(11) +#define JZ_LCD_CFG_PCLK_FALLING_EDGE BIT(10) +#define JZ_LCD_CFG_DE_ACTIVE_LOW BIT(9) +#define JZ_LCD_CFG_VSYNC_ACTIVE_LOW BIT(8) +#define JZ_LCD_CFG_18_BIT BIT(7) +#define JZ_LCD_CFG_PDW (BIT(5) | BIT(4)) +#define JZ_LCD_CFG_MODE_MASK 0xf + +#define JZ_LCD_CTRL_BURST_4 (0x0 << 28) +#define JZ_LCD_CTRL_BURST_8 (0x1 << 28) +#define JZ_LCD_CTRL_BURST_16 (0x2 << 28) +#define JZ_LCD_CTRL_RGB555 BIT(27) +#define JZ_LCD_CTRL_OFUP BIT(26) +#define JZ_LCD_CTRL_FRC_GRAYSCALE_16 (0x0 << 24) +#define JZ_LCD_CTRL_FRC_GRAYSCALE_4 (0x1 << 24) +#define JZ_LCD_CTRL_FRC_GRAYSCALE_2 (0x2 << 24) +#define JZ_LCD_CTRL_PDD_MASK (0xff << 16) +#define JZ_LCD_CTRL_EOF_IRQ BIT(13) +#define JZ_LCD_CTRL_SOF_IRQ BIT(12) +#define JZ_LCD_CTRL_OFU_IRQ BIT(11) +#define JZ_LCD_CTRL_IFU0_IRQ BIT(10) +#define JZ_LCD_CTRL_IFU1_IRQ BIT(9) +#define JZ_LCD_CTRL_DD_IRQ BIT(8) +#define JZ_LCD_CTRL_QDD_IRQ BIT(7) +#define JZ_LCD_CTRL_REVERSE_ENDIAN BIT(6) +#define JZ_LCD_CTRL_LSB_FISRT BIT(5) +#define JZ_LCD_CTRL_DISABLE BIT(4) +#define JZ_LCD_CTRL_ENABLE BIT(3) +#define JZ_LCD_CTRL_BPP_1 0x0 +#define JZ_LCD_CTRL_BPP_2 0x1 +#define JZ_LCD_CTRL_BPP_4 0x2 +#define JZ_LCD_CTRL_BPP_8 0x3 +#define JZ_LCD_CTRL_BPP_15_16 0x4 +#define JZ_LCD_CTRL_BPP_18_24 0x5 + +#define JZ_LCD_CMD_SOF_IRQ BIT(15) +#define JZ_LCD_CMD_EOF_IRQ BIT(16) +#define JZ_LCD_CMD_ENABLE_PAL BIT(12) + +#define JZ_LCD_SYNC_MASK 0x3ff + +#define JZ_LCD_STATE_DISABLED BIT(0) + +struct jzfb_framedesc { + uint32_t next; + uint32_t addr; + uint32_t id; + uint32_t cmd; +} __packed; + +struct jzfb { + struct fb_info *fb; + struct platform_device *pdev; + void __iomem *base; + struct resource *mem; + struct jz4740_fb_platform_data *pdata; + + size_t vidmem_size; + void *vidmem; + dma_addr_t vidmem_phys; + struct jzfb_framedesc *framedesc; + dma_addr_t framedesc_phys; + + struct clk *ldclk; + struct clk *lpclk; + + unsigned is_enabled:1; + struct mutex lock; + + uint32_t pseudo_palette[16]; +}; + +static const struct fb_fix_screeninfo jzfb_fix __devinitdata = { + .id = "JZ4740 FB", + .type = FB_TYPE_PACKED_PIXELS, + .visual = FB_VISUAL_TRUECOLOR, + .xpanstep = 0, + .ypanstep = 0, + .ywrapstep = 0, + .accel = FB_ACCEL_NONE, +}; + +static const struct jz_gpio_bulk_request jz_lcd_ctrl_pins[] = { + JZ_GPIO_BULK_PIN(LCD_PCLK), + JZ_GPIO_BULK_PIN(LCD_HSYNC), + JZ_GPIO_BULK_PIN(LCD_VSYNC), + JZ_GPIO_BULK_PIN(LCD_DE), + JZ_GPIO_BULK_PIN(LCD_PS), + JZ_GPIO_BULK_PIN(LCD_REV), + JZ_GPIO_BULK_PIN(LCD_CLS), + JZ_GPIO_BULK_PIN(LCD_SPL), +}; + +static const struct jz_gpio_bulk_request jz_lcd_data_pins[] = { + JZ_GPIO_BULK_PIN(LCD_DATA0), + JZ_GPIO_BULK_PIN(LCD_DATA1), + JZ_GPIO_BULK_PIN(LCD_DATA2), + JZ_GPIO_BULK_PIN(LCD_DATA3), + JZ_GPIO_BULK_PIN(LCD_DATA4), + JZ_GPIO_BULK_PIN(LCD_DATA5), + JZ_GPIO_BULK_PIN(LCD_DATA6), + JZ_GPIO_BULK_PIN(LCD_DATA7), + JZ_GPIO_BULK_PIN(LCD_DATA8), + JZ_GPIO_BULK_PIN(LCD_DATA9), + JZ_GPIO_BULK_PIN(LCD_DATA10), + JZ_GPIO_BULK_PIN(LCD_DATA11), + JZ_GPIO_BULK_PIN(LCD_DATA12), + JZ_GPIO_BULK_PIN(LCD_DATA13), + JZ_GPIO_BULK_PIN(LCD_DATA14), + JZ_GPIO_BULK_PIN(LCD_DATA15), + JZ_GPIO_BULK_PIN(LCD_DATA16), + JZ_GPIO_BULK_PIN(LCD_DATA17), +}; + +static unsigned int jzfb_num_ctrl_pins(struct jzfb *jzfb) +{ + unsigned int num; + + switch (jzfb->pdata->lcd_type) { + case JZ_LCD_TYPE_GENERIC_16_BIT: + num = 4; + break; + case JZ_LCD_TYPE_GENERIC_18_BIT: + num = 4; + break; + case JZ_LCD_TYPE_8BIT_SERIAL: + num = 3; + break; + case JZ_LCD_TYPE_SPECIAL_TFT_1: + case JZ_LCD_TYPE_SPECIAL_TFT_2: + case JZ_LCD_TYPE_SPECIAL_TFT_3: + num = 8; + break; + default: + num = 0; + break; + } + return num; +} + +static unsigned int jzfb_num_data_pins(struct jzfb *jzfb) +{ + unsigned int num; + + switch (jzfb->pdata->lcd_type) { + case JZ_LCD_TYPE_GENERIC_16_BIT: + num = 16; + break; + case JZ_LCD_TYPE_GENERIC_18_BIT: + num = 18; + break; + case JZ_LCD_TYPE_8BIT_SERIAL: + num = 8; + break; + case JZ_LCD_TYPE_SPECIAL_TFT_1: + case JZ_LCD_TYPE_SPECIAL_TFT_2: + case JZ_LCD_TYPE_SPECIAL_TFT_3: + if (jzfb->pdata->bpp == 18) + num = 18; + else + num = 16; + break; + default: + num = 0; + break; + } + return num; +} + +/* Based on CNVT_TOHW macro from skeletonfb.c */ +static inline uint32_t jzfb_convert_color_to_hw(unsigned val, + struct fb_bitfield *bf) +{ + return (((val << bf->length) + 0x7FFF - val) >> 16) << bf->offset; +} + +static int jzfb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, struct fb_info *fb) +{ + uint32_t color; + + if (regno >= 16) + return -EINVAL; + + color = jzfb_convert_color_to_hw(red, &fb->var.red); + color |= jzfb_convert_color_to_hw(green, &fb->var.green); + color |= jzfb_convert_color_to_hw(blue, &fb->var.blue); + color |= jzfb_convert_color_to_hw(transp, &fb->var.transp); + + ((uint32_t *)(fb->pseudo_palette))[regno] = color; + + return 0; +} + +static int jzfb_get_controller_bpp(struct jzfb *jzfb) +{ + switch (jzfb->pdata->bpp) { + case 18: + case 24: + return 32; + case 15: + return 16; + default: + return jzfb->pdata->bpp; + } +} + +static struct fb_videomode *jzfb_get_mode(struct jzfb *jzfb, + struct fb_var_screeninfo *var) +{ + size_t i; + struct fb_videomode *mode = jzfb->pdata->modes; + + for (i = 0; i < jzfb->pdata->num_modes; ++i, ++mode) { + if (mode->xres == var->xres && mode->yres == var->yres) + return mode; + } + + return NULL; +} + +static int jzfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fb) +{ + struct jzfb *jzfb = fb->par; + struct fb_videomode *mode; + + if (var->bits_per_pixel != jzfb_get_controller_bpp(jzfb) && + var->bits_per_pixel != jzfb->pdata->bpp) + return -EINVAL; + + mode = jzfb_get_mode(jzfb, var); + if (mode == NULL) + return -EINVAL; + + fb_videomode_to_var(var, mode); + + switch (jzfb->pdata->bpp) { + case 8: + break; + case 15: + var->red.offset = 10; + var->red.length = 5; + var->green.offset = 6; + var->green.length = 5; + var->blue.offset = 0; + var->blue.length = 5; + break; + case 16: + var->red.offset = 11; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 6; + var->blue.offset = 0; + var->blue.length = 5; + break; + case 18: + var->red.offset = 16; + var->red.length = 6; + var->green.offset = 8; + var->green.length = 6; + var->blue.offset = 0; + var->blue.length = 6; + var->bits_per_pixel = 32; + break; + case 32: + case 24: + var->transp.offset = 24; + var->transp.length = 8; + var->red.offset = 16; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + var->bits_per_pixel = 32; + break; + default: + break; + } + + return 0; +} + +static int jzfb_set_par(struct fb_info *info) +{ + struct jzfb *jzfb = info->par; + struct jz4740_fb_platform_data *pdata = jzfb->pdata; + struct fb_var_screeninfo *var = &info->var; + struct fb_videomode *mode; + uint16_t hds, vds; + uint16_t hde, vde; + uint16_t ht, vt; + uint32_t ctrl; + uint32_t cfg; + unsigned long rate; + + mode = jzfb_get_mode(jzfb, var); + if (mode == NULL) + return -EINVAL; + + if (mode == info->mode) + return 0; + + info->mode = mode; + + hds = mode->hsync_len + mode->left_margin; + hde = hds + mode->xres; + ht = hde + mode->right_margin; + + vds = mode->vsync_len + mode->upper_margin; + vde = vds + mode->yres; + vt = vde + mode->lower_margin; + + ctrl = JZ_LCD_CTRL_OFUP | JZ_LCD_CTRL_BURST_16; + + switch (pdata->bpp) { + case 1: + ctrl |= JZ_LCD_CTRL_BPP_1; + break; + case 2: + ctrl |= JZ_LCD_CTRL_BPP_2; + break; + case 4: + ctrl |= JZ_LCD_CTRL_BPP_4; + break; + case 8: + ctrl |= JZ_LCD_CTRL_BPP_8; + break; + case 15: + ctrl |= JZ_LCD_CTRL_RGB555; /* Falltrough */ + case 16: + ctrl |= JZ_LCD_CTRL_BPP_15_16; + break; + case 18: + case 24: + case 32: + ctrl |= JZ_LCD_CTRL_BPP_18_24; + break; + default: + break; + } + + cfg = pdata->lcd_type & 0xf; + + if (!(mode->sync & FB_SYNC_HOR_HIGH_ACT)) + cfg |= JZ_LCD_CFG_HSYNC_ACTIVE_LOW; + + if (!(mode->sync & FB_SYNC_VERT_HIGH_ACT)) + cfg |= JZ_LCD_CFG_VSYNC_ACTIVE_LOW; + + if (pdata->pixclk_falling_edge) + cfg |= JZ_LCD_CFG_PCLK_FALLING_EDGE; + + if (pdata->date_enable_active_low) + cfg |= JZ_LCD_CFG_DE_ACTIVE_LOW; + + if (pdata->lcd_type == JZ_LCD_TYPE_GENERIC_18_BIT) + cfg |= JZ_LCD_CFG_18_BIT; + + if (mode->pixclock) { + rate = PICOS2KHZ(mode->pixclock) * 1000; + mode->refresh = rate / vt / ht; + } else { + if (pdata->lcd_type == JZ_LCD_TYPE_8BIT_SERIAL) + rate = mode->refresh * (vt + 2 * mode->xres) * ht; + else + rate = mode->refresh * vt * ht; + + mode->pixclock = KHZ2PICOS(rate / 1000); + } + + mutex_lock(&jzfb->lock); + if (!jzfb->is_enabled) + clk_enable(jzfb->ldclk); + else + ctrl |= JZ_LCD_CTRL_ENABLE; + + switch (pdata->lcd_type) { + case JZ_LCD_TYPE_SPECIAL_TFT_1: + case JZ_LCD_TYPE_SPECIAL_TFT_2: + case JZ_LCD_TYPE_SPECIAL_TFT_3: + writel(pdata->special_tft_config.spl, jzfb->base + JZ_REG_LCD_SPL); + writel(pdata->special_tft_config.cls, jzfb->base + JZ_REG_LCD_CLS); + writel(pdata->special_tft_config.ps, jzfb->base + JZ_REG_LCD_PS); + writel(pdata->special_tft_config.ps, jzfb->base + JZ_REG_LCD_REV); + break; + default: + cfg |= JZ_LCD_CFG_PS_DISABLE; + cfg |= JZ_LCD_CFG_CLS_DISABLE; + cfg |= JZ_LCD_CFG_SPL_DISABLE; + cfg |= JZ_LCD_CFG_REV_DISABLE; + break; + } + + writel(mode->hsync_len, jzfb->base + JZ_REG_LCD_HSYNC); + writel(mode->vsync_len, jzfb->base + JZ_REG_LCD_VSYNC); + + writel((ht << 16) | vt, jzfb->base + JZ_REG_LCD_VAT); + + writel((hds << 16) | hde, jzfb->base + JZ_REG_LCD_DAH); + writel((vds << 16) | vde, jzfb->base + JZ_REG_LCD_DAV); + + writel(cfg, jzfb->base + JZ_REG_LCD_CFG); + + writel(ctrl, jzfb->base + JZ_REG_LCD_CTRL); + + if (!jzfb->is_enabled) + clk_disable(jzfb->ldclk); + + mutex_unlock(&jzfb->lock); + + clk_set_rate(jzfb->lpclk, rate); + clk_set_rate(jzfb->ldclk, rate * 3); + + return 0; +} + +static void jzfb_enable(struct jzfb *jzfb) +{ + uint32_t ctrl; + + clk_enable(jzfb->ldclk); + + jz_gpio_bulk_resume(jz_lcd_ctrl_pins, jzfb_num_ctrl_pins(jzfb)); + jz_gpio_bulk_resume(jz_lcd_data_pins, jzfb_num_data_pins(jzfb)); + + writel(0, jzfb->base + JZ_REG_LCD_STATE); + + writel(jzfb->framedesc->next, jzfb->base + JZ_REG_LCD_DA0); + + ctrl = readl(jzfb->base + JZ_REG_LCD_CTRL); + ctrl |= JZ_LCD_CTRL_ENABLE; + ctrl &= ~JZ_LCD_CTRL_DISABLE; + writel(ctrl, jzfb->base + JZ_REG_LCD_CTRL); +} + +static void jzfb_disable(struct jzfb *jzfb) +{ + uint32_t ctrl; + + ctrl = readl(jzfb->base + JZ_REG_LCD_CTRL); + ctrl |= JZ_LCD_CTRL_DISABLE; + writel(ctrl, jzfb->base + JZ_REG_LCD_CTRL); + do { + ctrl = readl(jzfb->base + JZ_REG_LCD_STATE); + } while (!(ctrl & JZ_LCD_STATE_DISABLED)); + + jz_gpio_bulk_suspend(jz_lcd_ctrl_pins, jzfb_num_ctrl_pins(jzfb)); + jz_gpio_bulk_suspend(jz_lcd_data_pins, jzfb_num_data_pins(jzfb)); + + clk_disable(jzfb->ldclk); +} + +static int jzfb_blank(int blank_mode, struct fb_info *info) +{ + struct jzfb *jzfb = info->par; + + switch (blank_mode) { + case FB_BLANK_UNBLANK: + mutex_lock(&jzfb->lock); + if (jzfb->is_enabled) { + mutex_unlock(&jzfb->lock); + return 0; + } + + jzfb_enable(jzfb); + jzfb->is_enabled = 1; + + mutex_unlock(&jzfb->lock); + break; + default: + mutex_lock(&jzfb->lock); + if (!jzfb->is_enabled) { + mutex_unlock(&jzfb->lock); + return 0; + } + + jzfb_disable(jzfb); + jzfb->is_enabled = 0; + + mutex_unlock(&jzfb->lock); + break; + } + + return 0; +} + +static int jzfb_alloc_devmem(struct jzfb *jzfb) +{ + int max_videosize = 0; + struct fb_videomode *mode = jzfb->pdata->modes; + void *page; + int i; + + for (i = 0; i < jzfb->pdata->num_modes; ++mode, ++i) { + if (max_videosize < mode->xres * mode->yres) + max_videosize = mode->xres * mode->yres; + } + + max_videosize *= jzfb_get_controller_bpp(jzfb) >> 3; + + jzfb->framedesc = dma_alloc_coherent(&jzfb->pdev->dev, + sizeof(*jzfb->framedesc), + &jzfb->framedesc_phys, GFP_KERNEL); + + if (!jzfb->framedesc) + return -ENOMEM; + + jzfb->vidmem_size = PAGE_ALIGN(max_videosize); + jzfb->vidmem = dma_alloc_coherent(&jzfb->pdev->dev, + jzfb->vidmem_size, + &jzfb->vidmem_phys, GFP_KERNEL); + + if (!jzfb->vidmem) + goto err_free_framedesc; + + for (page = jzfb->vidmem; + page < jzfb->vidmem + PAGE_ALIGN(jzfb->vidmem_size); + page += PAGE_SIZE) { + SetPageReserved(virt_to_page(page)); + } + + jzfb->framedesc->next = jzfb->framedesc_phys; + jzfb->framedesc->addr = jzfb->vidmem_phys; + jzfb->framedesc->id = 0xdeafbead; + jzfb->framedesc->cmd = 0; + jzfb->framedesc->cmd |= max_videosize / 4; + + return 0; + +err_free_framedesc: + dma_free_coherent(&jzfb->pdev->dev, sizeof(*jzfb->framedesc), + jzfb->framedesc, jzfb->framedesc_phys); + return -ENOMEM; +} + +static void jzfb_free_devmem(struct jzfb *jzfb) +{ + dma_free_coherent(&jzfb->pdev->dev, jzfb->vidmem_size, + jzfb->vidmem, jzfb->vidmem_phys); + dma_free_coherent(&jzfb->pdev->dev, sizeof(*jzfb->framedesc), + jzfb->framedesc, jzfb->framedesc_phys); +} + +static struct fb_ops jzfb_ops = { + .owner = THIS_MODULE, + .fb_check_var = jzfb_check_var, + .fb_set_par = jzfb_set_par, + .fb_blank = jzfb_blank, + .fb_fillrect = sys_fillrect, + .fb_copyarea = sys_copyarea, + .fb_imageblit = sys_imageblit, + .fb_setcolreg = jzfb_setcolreg, +}; + +static int __devinit jzfb_probe(struct platform_device *pdev) +{ + int ret; + struct jzfb *jzfb; + struct fb_info *fb; + struct jz4740_fb_platform_data *pdata = pdev->dev.platform_data; + struct resource *mem; + + if (!pdata) { + dev_err(&pdev->dev, "Missing platform data\n"); + return -ENXIO; + } + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!mem) { + dev_err(&pdev->dev, "Failed to get register memory resource\n"); + return -ENXIO; + } + + mem = request_mem_region(mem->start, resource_size(mem), pdev->name); + if (!mem) { + dev_err(&pdev->dev, "Failed to request register memory region\n"); + return -EBUSY; + } + + fb = framebuffer_alloc(sizeof(struct jzfb), &pdev->dev); + if (!fb) { + dev_err(&pdev->dev, "Failed to allocate framebuffer device\n"); + ret = -ENOMEM; + goto err_release_mem_region; + } + + fb->fbops = &jzfb_ops; + fb->flags = FBINFO_DEFAULT; + + jzfb = fb->par; + jzfb->pdev = pdev; + jzfb->pdata = pdata; + jzfb->mem = mem; + + jzfb->ldclk = clk_get(&pdev->dev, "lcd"); + if (IS_ERR(jzfb->ldclk)) { + ret = PTR_ERR(jzfb->ldclk); + dev_err(&pdev->dev, "Failed to get lcd clock: %d\n", ret); + goto err_framebuffer_release; + } + + jzfb->lpclk = clk_get(&pdev->dev, "lcd_pclk"); + if (IS_ERR(jzfb->lpclk)) { + ret = PTR_ERR(jzfb->lpclk); + dev_err(&pdev->dev, "Failed to get lcd pixel clock: %d\n", ret); + goto err_put_ldclk; + } + + jzfb->base = ioremap(mem->start, resource_size(mem)); + if (!jzfb->base) { + dev_err(&pdev->dev, "Failed to ioremap register memory region\n"); + ret = -EBUSY; + goto err_put_lpclk; + } + + platform_set_drvdata(pdev, jzfb); + + mutex_init(&jzfb->lock); + + fb_videomode_to_modelist(pdata->modes, pdata->num_modes, + &fb->modelist); + fb_videomode_to_var(&fb->var, pdata->modes); + fb->var.bits_per_pixel = pdata->bpp; + jzfb_check_var(&fb->var, fb); + + ret = jzfb_alloc_devmem(jzfb); + if (ret) { + dev_err(&pdev->dev, "Failed to allocate video memory\n"); + goto err_iounmap; + } + + fb->fix = jzfb_fix; + fb->fix.line_length = fb->var.bits_per_pixel * fb->var.xres / 8; + fb->fix.mmio_start = mem->start; + fb->fix.mmio_len = resource_size(mem); + fb->fix.smem_start = jzfb->vidmem_phys; + fb->fix.smem_len = fb->fix.line_length * fb->var.yres; + fb->screen_base = jzfb->vidmem; + fb->pseudo_palette = jzfb->pseudo_palette; + + fb_alloc_cmap(&fb->cmap, 256, 0); + + clk_enable(jzfb->ldclk); + jzfb->is_enabled = 1; + + writel(jzfb->framedesc->next, jzfb->base + JZ_REG_LCD_DA0); + + fb->mode = NULL; + jzfb_set_par(fb); + + jz_gpio_bulk_request(jz_lcd_ctrl_pins, jzfb_num_ctrl_pins(jzfb)); + jz_gpio_bulk_request(jz_lcd_data_pins, jzfb_num_data_pins(jzfb)); + + ret = register_framebuffer(fb); + if (ret) { + dev_err(&pdev->dev, "Failed to register framebuffer: %d\n", ret); + goto err_free_devmem; + } + + jzfb->fb = fb; + + return 0; + +err_free_devmem: + jz_gpio_bulk_free(jz_lcd_ctrl_pins, jzfb_num_ctrl_pins(jzfb)); + jz_gpio_bulk_free(jz_lcd_data_pins, jzfb_num_data_pins(jzfb)); + + fb_dealloc_cmap(&fb->cmap); + jzfb_free_devmem(jzfb); +err_iounmap: + iounmap(jzfb->base); +err_put_lpclk: + clk_put(jzfb->lpclk); +err_put_ldclk: + clk_put(jzfb->ldclk); +err_framebuffer_release: + framebuffer_release(fb); +err_release_mem_region: + release_mem_region(mem->start, resource_size(mem)); + return ret; +} + +static int __devexit jzfb_remove(struct platform_device *pdev) +{ + struct jzfb *jzfb = platform_get_drvdata(pdev); + + jzfb_blank(FB_BLANK_POWERDOWN, jzfb->fb); + + jz_gpio_bulk_free(jz_lcd_ctrl_pins, jzfb_num_ctrl_pins(jzfb)); + jz_gpio_bulk_free(jz_lcd_data_pins, jzfb_num_data_pins(jzfb)); + + iounmap(jzfb->base); + release_mem_region(jzfb->mem->start, resource_size(jzfb->mem)); + + fb_dealloc_cmap(&jzfb->fb->cmap); + jzfb_free_devmem(jzfb); + + platform_set_drvdata(pdev, NULL); + + clk_put(jzfb->lpclk); + clk_put(jzfb->ldclk); + + framebuffer_release(jzfb->fb); + + return 0; +} + +#ifdef CONFIG_PM + +static int jzfb_suspend(struct device *dev) +{ + struct jzfb *jzfb = dev_get_drvdata(dev); + + acquire_console_sem(); + fb_set_suspend(jzfb->fb, 1); + release_console_sem(); + + mutex_lock(&jzfb->lock); + if (jzfb->is_enabled) + jzfb_disable(jzfb); + mutex_unlock(&jzfb->lock); + + return 0; +} + +static int jzfb_resume(struct device *dev) +{ + struct jzfb *jzfb = dev_get_drvdata(dev); + clk_enable(jzfb->ldclk); + + mutex_lock(&jzfb->lock); + if (jzfb->is_enabled) + jzfb_enable(jzfb); + mutex_unlock(&jzfb->lock); + + acquire_console_sem(); + fb_set_suspend(jzfb->fb, 0); + release_console_sem(); + + return 0; +} + +static const struct dev_pm_ops jzfb_pm_ops = { + .suspend = jzfb_suspend, + .resume = jzfb_resume, + .poweroff = jzfb_suspend, + .restore = jzfb_resume, +}; + +#define JZFB_PM_OPS (&jzfb_pm_ops) + +#else +#define JZFB_PM_OPS NULL +#endif + +static struct platform_driver jzfb_driver = { + .probe = jzfb_probe, + .remove = __devexit_p(jzfb_remove), + .driver = { + .name = "jz4740-fb", + .pm = JZFB_PM_OPS, + }, +}; + +static int __init jzfb_init(void) +{ + return platform_driver_register(&jzfb_driver); +} +module_init(jzfb_init); + +static void __exit jzfb_exit(void) +{ + platform_driver_unregister(&jzfb_driver); +} +module_exit(jzfb_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); +MODULE_DESCRIPTION("JZ4740 SoC LCD framebuffer driver"); +MODULE_ALIAS("platform:jz4740-fb"); diff --git a/drivers/video/leo.c b/drivers/video/leo.c index 1db55f128490..ad677637ffbb 100644 --- a/drivers/video/leo.c +++ b/drivers/video/leo.c @@ -550,7 +550,7 @@ static void leo_unmap_regs(struct of_device *op, struct fb_info *info, static int __devinit leo_probe(struct of_device *op, const struct of_device_id *match) { - struct device_node *dp = op->node; + struct device_node *dp = op->dev.of_node; struct fb_info *info; struct leo_par *par; int linebytes, err; @@ -663,8 +663,11 @@ static const struct of_device_id leo_match[] = { MODULE_DEVICE_TABLE(of, leo_match); static struct of_platform_driver leo_driver = { - .name = "leo", - .match_table = leo_match, + .driver = { + .name = "leo", + .owner = THIS_MODULE, + .of_match_table = leo_match, + }, .probe = leo_probe, .remove = __devexit_p(leo_remove), }; @@ -674,12 +677,12 @@ static int __init leo_init(void) if (fb_get_options("leofb", NULL)) return -ENODEV; - return of_register_driver(&leo_driver, &of_bus_type); + return of_register_platform_driver(&leo_driver); } static void __exit leo_exit(void) { - of_unregister_driver(&leo_driver); + of_unregister_platform_driver(&leo_driver); } module_init(leo_init); diff --git a/drivers/video/mb862xx/mb862xxfb.c b/drivers/video/mb862xx/mb862xxfb.c index 8280a58a0e55..4e2b8cc3d460 100644 --- a/drivers/video/mb862xx/mb862xxfb.c +++ b/drivers/video/mb862xx/mb862xxfb.c @@ -553,7 +553,7 @@ static int mb862xx_gdc_init(struct mb862xxfb_par *par) static int __devinit of_platform_mb862xx_probe(struct of_device *ofdev, const struct of_device_id *id) { - struct device_node *np = ofdev->node; + struct device_node *np = ofdev->dev.of_node; struct device *dev = &ofdev->dev; struct mb862xxfb_par *par; struct fb_info *info; @@ -718,9 +718,11 @@ static struct of_device_id __devinitdata of_platform_mb862xx_tbl[] = { }; static struct of_platform_driver of_platform_mb862xxfb_driver = { - .owner = THIS_MODULE, - .name = DRV_NAME, - .match_table = of_platform_mb862xx_tbl, + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + .of_match_table = of_platform_mb862xx_tbl, + }, .probe = of_platform_mb862xx_probe, .remove = __devexit_p(of_platform_mb862xx_remove), }; diff --git a/drivers/video/mx3fb.c b/drivers/video/mx3fb.c index 772ba3f45e6f..7cfc170bce19 100644 --- a/drivers/video/mx3fb.c +++ b/drivers/video/mx3fb.c @@ -387,7 +387,8 @@ static void sdc_disable_channel(struct mx3fb_info *mx3_fbi) spin_unlock_irqrestore(&mx3fb->lock, flags); - mx3_fbi->txd->chan->device->device_terminate_all(mx3_fbi->txd->chan); + mx3_fbi->txd->chan->device->device_control(mx3_fbi->txd->chan, + DMA_TERMINATE_ALL, 0); mx3_fbi->txd = NULL; mx3_fbi->cookie = -EINVAL; } diff --git a/drivers/video/nuc900fb.c b/drivers/video/nuc900fb.c index 6bf0d460a738..81687ed26ba9 100644 --- a/drivers/video/nuc900fb.c +++ b/drivers/video/nuc900fb.c @@ -596,8 +596,6 @@ static int __devinit nuc900fb_probe(struct platform_device *pdev) goto release_regs; } - nuc900_driver_clksrc_div(&pdev->dev, "ext", 0x2); - fbi->clk = clk_get(&pdev->dev, NULL); if (!fbi->clk || IS_ERR(fbi->clk)) { printk(KERN_ERR "nuc900-lcd:failed to get lcd clock source\n"); @@ -667,7 +665,7 @@ release_irq: release_regs: iounmap(fbi->io); release_mem_region: - release_mem_region((unsigned long)fbi->mem, size); + release_mem_region(res->start, size); free_fb: framebuffer_release(fbinfo); return ret; diff --git a/drivers/video/offb.c b/drivers/video/offb.c index 61f8b8f919b0..cb163a5397be 100644 --- a/drivers/video/offb.c +++ b/drivers/video/offb.c @@ -19,13 +19,14 @@ #include <linux/mm.h> #include <linux/vmalloc.h> #include <linux/delay.h> +#include <linux/of.h> +#include <linux/of_address.h> #include <linux/interrupt.h> #include <linux/fb.h> #include <linux/init.h> #include <linux/ioport.h> #include <linux/pci.h> #include <asm/io.h> -#include <asm/prom.h> #ifdef CONFIG_PPC64 #include <asm/pci-bridge.h> @@ -285,7 +286,7 @@ static void offb_destroy(struct fb_info *info) { if (info->screen_base) iounmap(info->screen_base); - release_mem_region(info->aperture_base, info->aperture_size); + release_mem_region(info->apertures->ranges[0].base, info->apertures->ranges[0].size); framebuffer_release(info); } @@ -491,8 +492,11 @@ static void __init offb_init_fb(const char *name, const char *full_name, var->vmode = FB_VMODE_NONINTERLACED; /* set offb aperture size for generic probing */ - info->aperture_base = address; - info->aperture_size = fix->smem_len; + info->apertures = alloc_apertures(1); + if (!info->apertures) + goto out_aper; + info->apertures->ranges[0].base = address; + info->apertures->ranges[0].size = fix->smem_len; info->fbops = &offb_ops; info->screen_base = ioremap(address, fix->smem_len); @@ -501,17 +505,20 @@ static void __init offb_init_fb(const char *name, const char *full_name, fb_alloc_cmap(&info->cmap, 256, 0); - if (register_framebuffer(info) < 0) { - iounmap(par->cmap_adr); - par->cmap_adr = NULL; - iounmap(info->screen_base); - framebuffer_release(info); - release_mem_region(res_start, res_size); - return; - } + if (register_framebuffer(info) < 0) + goto out_err; printk(KERN_INFO "fb%d: Open Firmware frame buffer device on %s\n", info->node, full_name); + return; + +out_err: + iounmap(info->screen_base); +out_aper: + iounmap(par->cmap_adr); + par->cmap_adr = NULL; + framebuffer_release(info); + release_mem_region(res_start, res_size); } diff --git a/drivers/video/omap/lcd_apollon.c b/drivers/video/omap/lcd_apollon.c index 2be94eb3bbf5..10459d8bd9a0 100644 --- a/drivers/video/omap/lcd_apollon.c +++ b/drivers/video/omap/lcd_apollon.c @@ -25,7 +25,6 @@ #include <linux/platform_device.h> #include <mach/gpio.h> -#include <plat/mux.h> #include "omapfb.h" @@ -34,8 +33,6 @@ static int apollon_panel_init(struct lcd_panel *panel, struct omapfb_device *fbdev) { - /* configure LCD PWR_EN */ - omap_cfg_reg(M21_242X_GPIO11); return 0; } diff --git a/drivers/video/omap/lcdc.c b/drivers/video/omap/lcdc.c index 43ab7d8b66b2..7767338f8b14 100644 --- a/drivers/video/omap/lcdc.c +++ b/drivers/video/omap/lcdc.c @@ -572,22 +572,12 @@ static enum omapfb_update_mode omap_lcdc_get_update_mode(void) /* PM code called only in internal controller mode */ static void omap_lcdc_suspend(void) { - if (lcdc.update_mode == OMAPFB_AUTO_UPDATE) { - disable_controller(); - omap_stop_lcd_dma(); - } + omap_lcdc_set_update_mode(OMAPFB_UPDATE_DISABLED); } static void omap_lcdc_resume(void) { - if (lcdc.update_mode == OMAPFB_AUTO_UPDATE) { - setup_regs(); - load_palette(); - setup_lcd_dma(); - set_load_mode(OMAP_LCDC_LOAD_FRAME); - enable_irqs(OMAP_LCDC_IRQ_DONE); - enable_controller(); - } + omap_lcdc_set_update_mode(OMAPFB_AUTO_UPDATE); } static void omap_lcdc_get_caps(int plane, struct omapfb_caps *caps) diff --git a/drivers/video/omap/rfbi.c b/drivers/video/omap/rfbi.c index 1162603c72e5..eada9f12efc7 100644 --- a/drivers/video/omap/rfbi.c +++ b/drivers/video/omap/rfbi.c @@ -26,6 +26,7 @@ #include <linux/interrupt.h> #include <linux/clk.h> #include <linux/io.h> +#include <linux/platform_device.h> #include "omapfb.h" #include "dispc.h" @@ -83,13 +84,13 @@ static inline u32 rfbi_read_reg(int idx) static int rfbi_get_clocks(void) { - rfbi.dss_ick = clk_get(&dispc.fbdev->dssdev->dev, "ick"); + rfbi.dss_ick = clk_get(&rfbi.fbdev->dssdev->dev, "ick"); if (IS_ERR(rfbi.dss_ick)) { dev_err(rfbi.fbdev->dev, "can't get ick\n"); return PTR_ERR(rfbi.dss_ick); } - rfbi.dss1_fck = clk_get(&dispc.fbdev->dssdev->dev, "dss1_fck"); + rfbi.dss1_fck = clk_get(&rfbi.fbdev->dssdev->dev, "dss1_fck"); if (IS_ERR(rfbi.dss1_fck)) { dev_err(rfbi.fbdev->dev, "can't get dss1_fck\n"); clk_put(rfbi.dss_ick); diff --git a/drivers/video/omap2/displays/Kconfig b/drivers/video/omap2/displays/Kconfig index dfb57ee50861..881c9f77c75a 100644 --- a/drivers/video/omap2/displays/Kconfig +++ b/drivers/video/omap2/displays/Kconfig @@ -10,6 +10,7 @@ config PANEL_GENERIC config PANEL_SHARP_LS037V7DW01 tristate "Sharp LS037V7DW01 LCD Panel" depends on OMAP2_DSS + select BACKLIGHT_CLASS_DEVICE help LCD Panel used in TI's SDP3430 and EVM boards @@ -33,8 +34,14 @@ config PANEL_TOPPOLY_TDO35S config PANEL_TPO_TD043MTEA1 tristate "TPO TD043MTEA1 LCD Panel" - depends on OMAP2_DSS && I2C + depends on OMAP2_DSS && SPI help LCD Panel used in OMAP3 Pandora +config PANEL_ACX565AKM + tristate "ACX565AKM Panel" + depends on OMAP2_DSS_SDI + select BACKLIGHT_CLASS_DEVICE + help + This is the LCD panel used on Nokia N900 endmenu diff --git a/drivers/video/omap2/displays/Makefile b/drivers/video/omap2/displays/Makefile index e2bb32168dee..aa386095d7c4 100644 --- a/drivers/video/omap2/displays/Makefile +++ b/drivers/video/omap2/displays/Makefile @@ -5,3 +5,4 @@ obj-$(CONFIG_PANEL_SHARP_LQ043T1DG01) += panel-sharp-lq043t1dg01.o obj-$(CONFIG_PANEL_TAAL) += panel-taal.o obj-$(CONFIG_PANEL_TOPPOLY_TDO35S) += panel-toppoly-tdo35s.o obj-$(CONFIG_PANEL_TPO_TD043MTEA1) += panel-tpo-td043mtea1.o +obj-$(CONFIG_PANEL_ACX565AKM) += panel-acx565akm.o diff --git a/drivers/video/omap2/displays/panel-acx565akm.c b/drivers/video/omap2/displays/panel-acx565akm.c new file mode 100644 index 000000000000..07fbb8a733bb --- /dev/null +++ b/drivers/video/omap2/displays/panel-acx565akm.c @@ -0,0 +1,821 @@ +/* + * Support for ACX565AKM LCD Panel used on Nokia N900 + * + * Copyright (C) 2010 Nokia Corporation + * + * Original Driver Author: Imre Deak <imre.deak@nokia.com> + * Based on panel-generic.c by Tomi Valkeinen <tomi.valkeinen@nokia.com> + * Adapted to new DSS2 framework: Roger Quadros <roger.quadros@nokia.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/delay.h> +#include <linux/spi/spi.h> +#include <linux/jiffies.h> +#include <linux/sched.h> +#include <linux/backlight.h> +#include <linux/fb.h> + +#include <plat/display.h> + +#define MIPID_CMD_READ_DISP_ID 0x04 +#define MIPID_CMD_READ_RED 0x06 +#define MIPID_CMD_READ_GREEN 0x07 +#define MIPID_CMD_READ_BLUE 0x08 +#define MIPID_CMD_READ_DISP_STATUS 0x09 +#define MIPID_CMD_RDDSDR 0x0F +#define MIPID_CMD_SLEEP_IN 0x10 +#define MIPID_CMD_SLEEP_OUT 0x11 +#define MIPID_CMD_DISP_OFF 0x28 +#define MIPID_CMD_DISP_ON 0x29 +#define MIPID_CMD_WRITE_DISP_BRIGHTNESS 0x51 +#define MIPID_CMD_READ_DISP_BRIGHTNESS 0x52 +#define MIPID_CMD_WRITE_CTRL_DISP 0x53 + +#define CTRL_DISP_BRIGHTNESS_CTRL_ON (1 << 5) +#define CTRL_DISP_AMBIENT_LIGHT_CTRL_ON (1 << 4) +#define CTRL_DISP_BACKLIGHT_ON (1 << 2) +#define CTRL_DISP_AUTO_BRIGHTNESS_ON (1 << 1) + +#define MIPID_CMD_READ_CTRL_DISP 0x54 +#define MIPID_CMD_WRITE_CABC 0x55 +#define MIPID_CMD_READ_CABC 0x56 + +#define MIPID_VER_LPH8923 3 +#define MIPID_VER_LS041Y3 4 +#define MIPID_VER_L4F00311 8 +#define MIPID_VER_ACX565AKM 9 + +struct acx565akm_device { + char *name; + int enabled; + int model; + int revision; + u8 display_id[3]; + unsigned has_bc:1; + unsigned has_cabc:1; + unsigned cabc_mode; + unsigned long hw_guard_end; /* next value of jiffies + when we can issue the + next sleep in/out command */ + unsigned long hw_guard_wait; /* max guard time in jiffies */ + + struct spi_device *spi; + struct mutex mutex; + + struct omap_dss_device *dssdev; + struct backlight_device *bl_dev; +}; + +static struct acx565akm_device acx_dev; +static int acx565akm_bl_update_status(struct backlight_device *dev); + +/*--------------------MIPID interface-----------------------------*/ + +static void acx565akm_transfer(struct acx565akm_device *md, int cmd, + const u8 *wbuf, int wlen, u8 *rbuf, int rlen) +{ + struct spi_message m; + struct spi_transfer *x, xfer[5]; + int r; + + BUG_ON(md->spi == NULL); + + spi_message_init(&m); + + memset(xfer, 0, sizeof(xfer)); + x = &xfer[0]; + + cmd &= 0xff; + x->tx_buf = &cmd; + x->bits_per_word = 9; + x->len = 2; + + if (rlen > 1 && wlen == 0) { + /* + * Between the command and the response data there is a + * dummy clock cycle. Add an extra bit after the command + * word to account for this. + */ + x->bits_per_word = 10; + cmd <<= 1; + } + spi_message_add_tail(x, &m); + + if (wlen) { + x++; + x->tx_buf = wbuf; + x->len = wlen; + x->bits_per_word = 9; + spi_message_add_tail(x, &m); + } + + if (rlen) { + x++; + x->rx_buf = rbuf; + x->len = rlen; + spi_message_add_tail(x, &m); + } + + r = spi_sync(md->spi, &m); + if (r < 0) + dev_dbg(&md->spi->dev, "spi_sync %d\n", r); +} + +static inline void acx565akm_cmd(struct acx565akm_device *md, int cmd) +{ + acx565akm_transfer(md, cmd, NULL, 0, NULL, 0); +} + +static inline void acx565akm_write(struct acx565akm_device *md, + int reg, const u8 *buf, int len) +{ + acx565akm_transfer(md, reg, buf, len, NULL, 0); +} + +static inline void acx565akm_read(struct acx565akm_device *md, + int reg, u8 *buf, int len) +{ + acx565akm_transfer(md, reg, NULL, 0, buf, len); +} + +static void hw_guard_start(struct acx565akm_device *md, int guard_msec) +{ + md->hw_guard_wait = msecs_to_jiffies(guard_msec); + md->hw_guard_end = jiffies + md->hw_guard_wait; +} + +static void hw_guard_wait(struct acx565akm_device *md) +{ + unsigned long wait = md->hw_guard_end - jiffies; + + if ((long)wait > 0 && wait <= md->hw_guard_wait) { + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(wait); + } +} + +/*----------------------MIPID wrappers----------------------------*/ + +static void set_sleep_mode(struct acx565akm_device *md, int on) +{ + int cmd; + + if (on) + cmd = MIPID_CMD_SLEEP_IN; + else + cmd = MIPID_CMD_SLEEP_OUT; + /* + * We have to keep 120msec between sleep in/out commands. + * (8.2.15, 8.2.16). + */ + hw_guard_wait(md); + acx565akm_cmd(md, cmd); + hw_guard_start(md, 120); +} + +static void set_display_state(struct acx565akm_device *md, int enabled) +{ + int cmd = enabled ? MIPID_CMD_DISP_ON : MIPID_CMD_DISP_OFF; + + acx565akm_cmd(md, cmd); +} + +static int panel_enabled(struct acx565akm_device *md) +{ + u32 disp_status; + int enabled; + + acx565akm_read(md, MIPID_CMD_READ_DISP_STATUS, (u8 *)&disp_status, 4); + disp_status = __be32_to_cpu(disp_status); + enabled = (disp_status & (1 << 17)) && (disp_status & (1 << 10)); + dev_dbg(&md->spi->dev, + "LCD panel %senabled by bootloader (status 0x%04x)\n", + enabled ? "" : "not ", disp_status); + return enabled; +} + +static int panel_detect(struct acx565akm_device *md) +{ + acx565akm_read(md, MIPID_CMD_READ_DISP_ID, md->display_id, 3); + dev_dbg(&md->spi->dev, "MIPI display ID: %02x%02x%02x\n", + md->display_id[0], md->display_id[1], md->display_id[2]); + + switch (md->display_id[0]) { + case 0x10: + md->model = MIPID_VER_ACX565AKM; + md->name = "acx565akm"; + md->has_bc = 1; + md->has_cabc = 1; + break; + case 0x29: + md->model = MIPID_VER_L4F00311; + md->name = "l4f00311"; + break; + case 0x45: + md->model = MIPID_VER_LPH8923; + md->name = "lph8923"; + break; + case 0x83: + md->model = MIPID_VER_LS041Y3; + md->name = "ls041y3"; + break; + default: + md->name = "unknown"; + dev_err(&md->spi->dev, "invalid display ID\n"); + return -ENODEV; + } + + md->revision = md->display_id[1]; + + dev_info(&md->spi->dev, "omapfb: %s rev %02x LCD detected\n", + md->name, md->revision); + + return 0; +} + +/*----------------------Backlight Control-------------------------*/ + +static void enable_backlight_ctrl(struct acx565akm_device *md, int enable) +{ + u16 ctrl; + + acx565akm_read(md, MIPID_CMD_READ_CTRL_DISP, (u8 *)&ctrl, 1); + if (enable) { + ctrl |= CTRL_DISP_BRIGHTNESS_CTRL_ON | + CTRL_DISP_BACKLIGHT_ON; + } else { + ctrl &= ~(CTRL_DISP_BRIGHTNESS_CTRL_ON | + CTRL_DISP_BACKLIGHT_ON); + } + + ctrl |= 1 << 8; + acx565akm_write(md, MIPID_CMD_WRITE_CTRL_DISP, (u8 *)&ctrl, 2); +} + +static void set_cabc_mode(struct acx565akm_device *md, unsigned mode) +{ + u16 cabc_ctrl; + + md->cabc_mode = mode; + if (!md->enabled) + return; + cabc_ctrl = 0; + acx565akm_read(md, MIPID_CMD_READ_CABC, (u8 *)&cabc_ctrl, 1); + cabc_ctrl &= ~3; + cabc_ctrl |= (1 << 8) | (mode & 3); + acx565akm_write(md, MIPID_CMD_WRITE_CABC, (u8 *)&cabc_ctrl, 2); +} + +static unsigned get_cabc_mode(struct acx565akm_device *md) +{ + return md->cabc_mode; +} + +static unsigned get_hw_cabc_mode(struct acx565akm_device *md) +{ + u8 cabc_ctrl; + + acx565akm_read(md, MIPID_CMD_READ_CABC, &cabc_ctrl, 1); + return cabc_ctrl & 3; +} + +static void acx565akm_set_brightness(struct acx565akm_device *md, int level) +{ + int bv; + + bv = level | (1 << 8); + acx565akm_write(md, MIPID_CMD_WRITE_DISP_BRIGHTNESS, (u8 *)&bv, 2); + + if (level) + enable_backlight_ctrl(md, 1); + else + enable_backlight_ctrl(md, 0); +} + +static int acx565akm_get_actual_brightness(struct acx565akm_device *md) +{ + u8 bv; + + acx565akm_read(md, MIPID_CMD_READ_DISP_BRIGHTNESS, &bv, 1); + + return bv; +} + + +static int acx565akm_bl_update_status(struct backlight_device *dev) +{ + struct acx565akm_device *md = dev_get_drvdata(&dev->dev); + int r; + int level; + + dev_dbg(&md->spi->dev, "%s\n", __func__); + + mutex_lock(&md->mutex); + + if (dev->props.fb_blank == FB_BLANK_UNBLANK && + dev->props.power == FB_BLANK_UNBLANK) + level = dev->props.brightness; + else + level = 0; + + r = 0; + if (md->has_bc) + acx565akm_set_brightness(md, level); + else if (md->dssdev->set_backlight) + r = md->dssdev->set_backlight(md->dssdev, level); + else + r = -ENODEV; + + mutex_unlock(&md->mutex); + + return r; +} + +static int acx565akm_bl_get_intensity(struct backlight_device *dev) +{ + struct acx565akm_device *md = dev_get_drvdata(&dev->dev); + + dev_dbg(&dev->dev, "%s\n", __func__); + + if (!md->has_bc && md->dssdev->set_backlight == NULL) + return -ENODEV; + + if (dev->props.fb_blank == FB_BLANK_UNBLANK && + dev->props.power == FB_BLANK_UNBLANK) { + if (md->has_bc) + return acx565akm_get_actual_brightness(md); + else + return dev->props.brightness; + } + + return 0; +} + +static const struct backlight_ops acx565akm_bl_ops = { + .get_brightness = acx565akm_bl_get_intensity, + .update_status = acx565akm_bl_update_status, +}; + +/*--------------------Auto Brightness control via Sysfs---------------------*/ + +static const char *cabc_modes[] = { + "off", /* always used when CABC is not supported */ + "ui", + "still-image", + "moving-image", +}; + +static ssize_t show_cabc_mode(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct acx565akm_device *md = dev_get_drvdata(dev); + const char *mode_str; + int mode; + int len; + + if (!md->has_cabc) + mode = 0; + else + mode = get_cabc_mode(md); + mode_str = "unknown"; + if (mode >= 0 && mode < ARRAY_SIZE(cabc_modes)) + mode_str = cabc_modes[mode]; + len = snprintf(buf, PAGE_SIZE, "%s\n", mode_str); + + return len < PAGE_SIZE - 1 ? len : PAGE_SIZE - 1; +} + +static ssize_t store_cabc_mode(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct acx565akm_device *md = dev_get_drvdata(dev); + int i; + + for (i = 0; i < ARRAY_SIZE(cabc_modes); i++) { + const char *mode_str = cabc_modes[i]; + int cmp_len = strlen(mode_str); + + if (count > 0 && buf[count - 1] == '\n') + count--; + if (count != cmp_len) + continue; + + if (strncmp(buf, mode_str, cmp_len) == 0) + break; + } + + if (i == ARRAY_SIZE(cabc_modes)) + return -EINVAL; + + if (!md->has_cabc && i != 0) + return -EINVAL; + + mutex_lock(&md->mutex); + set_cabc_mode(md, i); + mutex_unlock(&md->mutex); + + return count; +} + +static ssize_t show_cabc_available_modes(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct acx565akm_device *md = dev_get_drvdata(dev); + int len; + int i; + + if (!md->has_cabc) + return snprintf(buf, PAGE_SIZE, "%s\n", cabc_modes[0]); + + for (i = 0, len = 0; + len < PAGE_SIZE && i < ARRAY_SIZE(cabc_modes); i++) + len += snprintf(&buf[len], PAGE_SIZE - len, "%s%s%s", + i ? " " : "", cabc_modes[i], + i == ARRAY_SIZE(cabc_modes) - 1 ? "\n" : ""); + + return len < PAGE_SIZE ? len : PAGE_SIZE - 1; +} + +static DEVICE_ATTR(cabc_mode, S_IRUGO | S_IWUSR, + show_cabc_mode, store_cabc_mode); +static DEVICE_ATTR(cabc_available_modes, S_IRUGO, + show_cabc_available_modes, NULL); + +static struct attribute *bldev_attrs[] = { + &dev_attr_cabc_mode.attr, + &dev_attr_cabc_available_modes.attr, + NULL, +}; + +static struct attribute_group bldev_attr_group = { + .attrs = bldev_attrs, +}; + + +/*---------------------------ACX Panel----------------------------*/ + +static int acx_get_recommended_bpp(struct omap_dss_device *dssdev) +{ + return 16; +} + +static struct omap_video_timings acx_panel_timings = { + .x_res = 800, + .y_res = 480, + .pixel_clock = 24000, + .hfp = 28, + .hsw = 4, + .hbp = 24, + .vfp = 3, + .vsw = 3, + .vbp = 4, +}; + +static int acx_panel_probe(struct omap_dss_device *dssdev) +{ + int r; + struct acx565akm_device *md = &acx_dev; + struct backlight_device *bldev; + int max_brightness, brightness; + struct backlight_properties props; + + dev_dbg(&dssdev->dev, "%s\n", __func__); + dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS | + OMAP_DSS_LCD_IHS; + /* FIXME AC bias ? */ + dssdev->panel.timings = acx_panel_timings; + + if (dssdev->platform_enable) + dssdev->platform_enable(dssdev); + /* + * After reset we have to wait 5 msec before the first + * command can be sent. + */ + msleep(5); + + md->enabled = panel_enabled(md); + + r = panel_detect(md); + if (r) { + dev_err(&dssdev->dev, "%s panel detect error\n", __func__); + if (!md->enabled && dssdev->platform_disable) + dssdev->platform_disable(dssdev); + return r; + } + + mutex_lock(&acx_dev.mutex); + acx_dev.dssdev = dssdev; + mutex_unlock(&acx_dev.mutex); + + if (!md->enabled) { + if (dssdev->platform_disable) + dssdev->platform_disable(dssdev); + } + + /*------- Backlight control --------*/ + + props.fb_blank = FB_BLANK_UNBLANK; + props.power = FB_BLANK_UNBLANK; + + bldev = backlight_device_register("acx565akm", &md->spi->dev, + md, &acx565akm_bl_ops, &props); + md->bl_dev = bldev; + if (md->has_cabc) { + r = sysfs_create_group(&bldev->dev.kobj, &bldev_attr_group); + if (r) { + dev_err(&bldev->dev, + "%s failed to create sysfs files\n", __func__); + backlight_device_unregister(bldev); + return r; + } + md->cabc_mode = get_hw_cabc_mode(md); + } + + if (md->has_bc) + max_brightness = 255; + else + max_brightness = dssdev->max_backlight_level; + + if (md->has_bc) + brightness = acx565akm_get_actual_brightness(md); + else if (dssdev->get_backlight) + brightness = dssdev->get_backlight(dssdev); + else + brightness = 0; + + bldev->props.max_brightness = max_brightness; + bldev->props.brightness = brightness; + + acx565akm_bl_update_status(bldev); + return 0; +} + +static void acx_panel_remove(struct omap_dss_device *dssdev) +{ + struct acx565akm_device *md = &acx_dev; + + dev_dbg(&dssdev->dev, "%s\n", __func__); + sysfs_remove_group(&md->bl_dev->dev.kobj, &bldev_attr_group); + backlight_device_unregister(md->bl_dev); + mutex_lock(&acx_dev.mutex); + acx_dev.dssdev = NULL; + mutex_unlock(&acx_dev.mutex); +} + +static int acx_panel_power_on(struct omap_dss_device *dssdev) +{ + struct acx565akm_device *md = &acx_dev; + int r; + + dev_dbg(&dssdev->dev, "%s\n", __func__); + + mutex_lock(&md->mutex); + + r = omapdss_sdi_display_enable(dssdev); + if (r) { + pr_err("%s sdi enable failed\n", __func__); + goto fail_unlock; + } + + /*FIXME tweak me */ + msleep(50); + + if (dssdev->platform_enable) { + r = dssdev->platform_enable(dssdev); + if (r) + goto fail; + } + + if (md->enabled) { + dev_dbg(&md->spi->dev, "panel already enabled\n"); + mutex_unlock(&md->mutex); + return 0; + } + + /* + * We have to meet all the following delay requirements: + * 1. tRW: reset pulse width 10usec (7.12.1) + * 2. tRT: reset cancel time 5msec (7.12.1) + * 3. Providing PCLK,HS,VS signals for 2 frames = ~50msec worst + * case (7.6.2) + * 4. 120msec before the sleep out command (7.12.1) + */ + msleep(120); + + set_sleep_mode(md, 0); + md->enabled = 1; + + /* 5msec between sleep out and the next command. (8.2.16) */ + msleep(5); + set_display_state(md, 1); + set_cabc_mode(md, md->cabc_mode); + + mutex_unlock(&md->mutex); + + return acx565akm_bl_update_status(md->bl_dev); +fail: + omapdss_sdi_display_disable(dssdev); +fail_unlock: + mutex_unlock(&md->mutex); + return r; +} + +static void acx_panel_power_off(struct omap_dss_device *dssdev) +{ + struct acx565akm_device *md = &acx_dev; + + dev_dbg(&dssdev->dev, "%s\n", __func__); + + mutex_lock(&md->mutex); + + if (!md->enabled) { + mutex_unlock(&md->mutex); + return; + } + set_display_state(md, 0); + set_sleep_mode(md, 1); + md->enabled = 0; + /* + * We have to provide PCLK,HS,VS signals for 2 frames (worst case + * ~50msec) after sending the sleep in command and asserting the + * reset signal. We probably could assert the reset w/o the delay + * but we still delay to avoid possible artifacts. (7.6.1) + */ + msleep(50); + + if (dssdev->platform_disable) + dssdev->platform_disable(dssdev); + + /* FIXME need to tweak this delay */ + msleep(100); + + omapdss_sdi_display_disable(dssdev); + + mutex_unlock(&md->mutex); +} + +static int acx_panel_enable(struct omap_dss_device *dssdev) +{ + int r; + + dev_dbg(&dssdev->dev, "%s\n", __func__); + r = acx_panel_power_on(dssdev); + + if (r) + return r; + + dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; + return 0; +} + +static void acx_panel_disable(struct omap_dss_device *dssdev) +{ + dev_dbg(&dssdev->dev, "%s\n", __func__); + acx_panel_power_off(dssdev); + dssdev->state = OMAP_DSS_DISPLAY_DISABLED; +} + +static int acx_panel_suspend(struct omap_dss_device *dssdev) +{ + dev_dbg(&dssdev->dev, "%s\n", __func__); + acx_panel_power_off(dssdev); + dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; + return 0; +} + +static int acx_panel_resume(struct omap_dss_device *dssdev) +{ + int r; + + dev_dbg(&dssdev->dev, "%s\n", __func__); + r = acx_panel_power_on(dssdev); + if (r) + return r; + + dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; + return 0; +} + +static void acx_panel_set_timings(struct omap_dss_device *dssdev, + struct omap_video_timings *timings) +{ + int r; + + if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) + omapdss_sdi_display_disable(dssdev); + + dssdev->panel.timings = *timings; + + if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) { + r = omapdss_sdi_display_enable(dssdev); + if (r) + dev_err(&dssdev->dev, "%s enable failed\n", __func__); + } +} + +static void acx_panel_get_timings(struct omap_dss_device *dssdev, + struct omap_video_timings *timings) +{ + *timings = dssdev->panel.timings; +} + +static int acx_panel_check_timings(struct omap_dss_device *dssdev, + struct omap_video_timings *timings) +{ + return 0; +} + + +static struct omap_dss_driver acx_panel_driver = { + .probe = acx_panel_probe, + .remove = acx_panel_remove, + + .enable = acx_panel_enable, + .disable = acx_panel_disable, + .suspend = acx_panel_suspend, + .resume = acx_panel_resume, + + .set_timings = acx_panel_set_timings, + .get_timings = acx_panel_get_timings, + .check_timings = acx_panel_check_timings, + + .get_recommended_bpp = acx_get_recommended_bpp, + + .driver = { + .name = "panel-acx565akm", + .owner = THIS_MODULE, + }, +}; + +/*--------------------SPI probe-------------------------*/ + +static int acx565akm_spi_probe(struct spi_device *spi) +{ + struct acx565akm_device *md = &acx_dev; + + dev_dbg(&spi->dev, "%s\n", __func__); + + spi->mode = SPI_MODE_3; + md->spi = spi; + mutex_init(&md->mutex); + dev_set_drvdata(&spi->dev, md); + + omap_dss_register_driver(&acx_panel_driver); + + return 0; +} + +static int acx565akm_spi_remove(struct spi_device *spi) +{ + struct acx565akm_device *md = dev_get_drvdata(&spi->dev); + + dev_dbg(&md->spi->dev, "%s\n", __func__); + omap_dss_unregister_driver(&acx_panel_driver); + + return 0; +} + +static struct spi_driver acx565akm_spi_driver = { + .driver = { + .name = "acx565akm", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + .probe = acx565akm_spi_probe, + .remove = __devexit_p(acx565akm_spi_remove), +}; + +static int __init acx565akm_init(void) +{ + return spi_register_driver(&acx565akm_spi_driver); +} + +static void __exit acx565akm_exit(void) +{ + spi_unregister_driver(&acx565akm_spi_driver); +} + +module_init(acx565akm_init); +module_exit(acx565akm_exit); + +MODULE_AUTHOR("Nokia Corporation"); +MODULE_DESCRIPTION("acx565akm LCD Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c b/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c index 8d51a5e6341c..7d9eb2b1f5af 100644 --- a/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c +++ b/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c @@ -20,10 +20,17 @@ #include <linux/module.h> #include <linux/delay.h> #include <linux/device.h> +#include <linux/backlight.h> +#include <linux/fb.h> #include <linux/err.h> +#include <linux/slab.h> #include <plat/display.h> +struct sharp_data { + struct backlight_device *bl; +}; + static struct omap_video_timings sharp_ls_timings = { .x_res = 480, .y_res = 640, @@ -39,18 +46,89 @@ static struct omap_video_timings sharp_ls_timings = { .vbp = 1, }; +static int sharp_ls_bl_update_status(struct backlight_device *bl) +{ + struct omap_dss_device *dssdev = dev_get_drvdata(&bl->dev); + int level; + + if (!dssdev->set_backlight) + return -EINVAL; + + if (bl->props.fb_blank == FB_BLANK_UNBLANK && + bl->props.power == FB_BLANK_UNBLANK) + level = bl->props.brightness; + else + level = 0; + + return dssdev->set_backlight(dssdev, level); +} + +static int sharp_ls_bl_get_brightness(struct backlight_device *bl) +{ + if (bl->props.fb_blank == FB_BLANK_UNBLANK && + bl->props.power == FB_BLANK_UNBLANK) + return bl->props.brightness; + + return 0; +} + +static const struct backlight_ops sharp_ls_bl_ops = { + .get_brightness = sharp_ls_bl_get_brightness, + .update_status = sharp_ls_bl_update_status, +}; + + + static int sharp_ls_panel_probe(struct omap_dss_device *dssdev) { + struct backlight_properties props; + struct backlight_device *bl; + struct sharp_data *sd; + int r; + dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS | OMAP_DSS_LCD_IHS; dssdev->panel.acb = 0x28; dssdev->panel.timings = sharp_ls_timings; + sd = kzalloc(sizeof(*sd), GFP_KERNEL); + if (!sd) + return -ENOMEM; + + dev_set_drvdata(&dssdev->dev, sd); + + memset(&props, 0, sizeof(struct backlight_properties)); + props.max_brightness = dssdev->max_backlight_level; + + bl = backlight_device_register("sharp-ls", &dssdev->dev, dssdev, + &sharp_ls_bl_ops, &props); + if (IS_ERR(bl)) { + r = PTR_ERR(bl); + kfree(sd); + return r; + } + sd->bl = bl; + + bl->props.fb_blank = FB_BLANK_UNBLANK; + bl->props.power = FB_BLANK_UNBLANK; + bl->props.brightness = dssdev->max_backlight_level; + r = sharp_ls_bl_update_status(bl); + if (r < 0) + dev_err(&dssdev->dev, "failed to set lcd brightness\n"); + return 0; } static void sharp_ls_panel_remove(struct omap_dss_device *dssdev) { + struct sharp_data *sd = dev_get_drvdata(&dssdev->dev); + struct backlight_device *bl = sd->bl; + + bl->props.power = FB_BLANK_POWERDOWN; + sharp_ls_bl_update_status(bl); + backlight_device_unregister(bl); + + kfree(sd); } static int sharp_ls_power_on(struct omap_dss_device *dssdev) diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c index 4f3988a41082..e1c765d11419 100644 --- a/drivers/video/omap2/displays/panel-taal.c +++ b/drivers/video/omap2/displays/panel-taal.c @@ -28,11 +28,13 @@ #include <linux/fb.h> #include <linux/interrupt.h> #include <linux/gpio.h> -#include <linux/completion.h> #include <linux/workqueue.h> #include <linux/slab.h> +#include <linux/regulator/consumer.h> +#include <linux/mutex.h> #include <plat/display.h> +#include <plat/nokia-dsi-panel.h> /* DSI Virtual channel. Hardcoded for now. */ #define TCH 0 @@ -61,12 +63,139 @@ #define DCS_GET_ID2 0xdb #define DCS_GET_ID3 0xdc -/* #define TAAL_USE_ESD_CHECK */ #define TAAL_ESD_CHECK_PERIOD msecs_to_jiffies(5000) +static irqreturn_t taal_te_isr(int irq, void *data); +static void taal_te_timeout_work_callback(struct work_struct *work); static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable); +struct panel_regulator { + struct regulator *regulator; + const char *name; + int min_uV; + int max_uV; +}; + +static void free_regulators(struct panel_regulator *regulators, int n) +{ + int i; + + for (i = 0; i < n; i++) { + /* disable/put in reverse order */ + regulator_disable(regulators[n - i - 1].regulator); + regulator_put(regulators[n - i - 1].regulator); + } +} + +static int init_regulators(struct omap_dss_device *dssdev, + struct panel_regulator *regulators, int n) +{ + int r, i, v; + + for (i = 0; i < n; i++) { + struct regulator *reg; + + reg = regulator_get(&dssdev->dev, regulators[i].name); + if (IS_ERR(reg)) { + dev_err(&dssdev->dev, "failed to get regulator %s\n", + regulators[i].name); + r = PTR_ERR(reg); + goto err; + } + + /* FIXME: better handling of fixed vs. variable regulators */ + v = regulator_get_voltage(reg); + if (v < regulators[i].min_uV || v > regulators[i].max_uV) { + r = regulator_set_voltage(reg, regulators[i].min_uV, + regulators[i].max_uV); + if (r) { + dev_err(&dssdev->dev, + "failed to set regulator %s voltage\n", + regulators[i].name); + regulator_put(reg); + goto err; + } + } + + r = regulator_enable(reg); + if (r) { + dev_err(&dssdev->dev, "failed to enable regulator %s\n", + regulators[i].name); + regulator_put(reg); + goto err; + } + + regulators[i].regulator = reg; + } + + return 0; + +err: + free_regulators(regulators, i); + + return r; +} + +/** + * struct panel_config - panel configuration + * @name: panel name + * @type: panel type + * @timings: panel resolution + * @sleep: various panel specific delays, passed to msleep() if non-zero + * @reset_sequence: reset sequence timings, passed to udelay() if non-zero + * @regulators: array of panel regulators + * @num_regulators: number of regulators in the array + */ +struct panel_config { + const char *name; + int type; + + struct omap_video_timings timings; + + struct { + unsigned int sleep_in; + unsigned int sleep_out; + unsigned int hw_reset; + unsigned int enable_te; + } sleep; + + struct { + unsigned int high; + unsigned int low; + } reset_sequence; + + struct panel_regulator *regulators; + int num_regulators; +}; + +enum { + PANEL_TAAL, +}; + +static struct panel_config panel_configs[] = { + { + .name = "taal", + .type = PANEL_TAAL, + .timings = { + .x_res = 864, + .y_res = 480, + }, + .sleep = { + .sleep_in = 5, + .sleep_out = 5, + .hw_reset = 5, + .enable_te = 100, /* possible panel bug */ + }, + .reset_sequence = { + .high = 10, + .low = 10, + }, + }, +}; + struct taal_data { + struct mutex lock; + struct backlight_device *bldev; unsigned long hw_guard_end; /* next value of jiffies when we can @@ -81,8 +210,15 @@ struct taal_data { bool mirror; bool te_enabled; - bool use_ext_te; - struct completion te_completion; + + atomic_t do_update; + struct { + u16 x; + u16 y; + u16 w; + u16 h; + } update_region; + struct delayed_work te_timeout_work; bool use_dsi_bl; @@ -93,8 +229,16 @@ struct taal_data { struct workqueue_struct *esd_wq; struct delayed_work esd_work; + + struct panel_config *panel_config; }; +static inline struct nokia_dsi_panel_data +*get_panel_data(const struct omap_dss_device *dssdev) +{ + return (struct nokia_dsi_panel_data *) dssdev->data; +} + static void taal_esd_work(struct work_struct *work); static void hw_guard_start(struct taal_data *td, int guard_msec) @@ -156,7 +300,8 @@ static int taal_sleep_in(struct taal_data *td) hw_guard_start(td, 120); - msleep(5); + if (td->panel_config->sleep.sleep_in) + msleep(td->panel_config->sleep.sleep_in); return 0; } @@ -173,7 +318,8 @@ static int taal_sleep_out(struct taal_data *td) hw_guard_start(td, 120); - msleep(5); + if (td->panel_config->sleep.sleep_out) + msleep(td->panel_config->sleep.sleep_out); return 0; } @@ -276,6 +422,7 @@ static int taal_bl_update_status(struct backlight_device *dev) { struct omap_dss_device *dssdev = dev_get_drvdata(&dev->dev); struct taal_data *td = dev_get_drvdata(&dssdev->dev); + struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); int r; int level; @@ -287,24 +434,26 @@ static int taal_bl_update_status(struct backlight_device *dev) dev_dbg(&dssdev->dev, "update brightness to %d\n", level); + mutex_lock(&td->lock); + if (td->use_dsi_bl) { if (td->enabled) { dsi_bus_lock(); r = taal_dcs_write_1(DCS_BRIGHTNESS, level); dsi_bus_unlock(); - if (r) - return r; + } else { + r = 0; } } else { - if (!dssdev->set_backlight) - return -EINVAL; - - r = dssdev->set_backlight(dssdev, level); - if (r) - return r; + if (!panel_data->set_backlight) + r = -EINVAL; + else + r = panel_data->set_backlight(dssdev, level); } - return 0; + mutex_unlock(&td->lock); + + return r; } static int taal_bl_get_intensity(struct backlight_device *dev) @@ -341,16 +490,6 @@ static void taal_get_resolution(struct omap_dss_device *dssdev, } } -static irqreturn_t taal_te_isr(int irq, void *data) -{ - struct omap_dss_device *dssdev = data; - struct taal_data *td = dev_get_drvdata(&dssdev->dev); - - complete_all(&td->te_completion); - - return IRQ_HANDLED; -} - static ssize_t taal_num_errors_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -359,6 +498,8 @@ static ssize_t taal_num_errors_show(struct device *dev, u8 errors; int r; + mutex_lock(&td->lock); + if (td->enabled) { dsi_bus_lock(); r = taal_dcs_read_1(DCS_READ_NUM_ERRORS, &errors); @@ -367,6 +508,8 @@ static ssize_t taal_num_errors_show(struct device *dev, r = -ENODEV; } + mutex_unlock(&td->lock); + if (r) return r; @@ -381,6 +524,8 @@ static ssize_t taal_hw_revision_show(struct device *dev, u8 id1, id2, id3; int r; + mutex_lock(&td->lock); + if (td->enabled) { dsi_bus_lock(); r = taal_get_id(&id1, &id2, &id3); @@ -389,6 +534,8 @@ static ssize_t taal_hw_revision_show(struct device *dev, r = -ENODEV; } + mutex_unlock(&td->lock); + if (r) return r; @@ -438,6 +585,8 @@ static ssize_t store_cabc_mode(struct device *dev, if (i == ARRAY_SIZE(cabc_modes)) return -EINVAL; + mutex_lock(&td->lock); + if (td->enabled) { dsi_bus_lock(); if (!td->cabc_broken) @@ -447,6 +596,8 @@ static ssize_t store_cabc_mode(struct device *dev, td->cabc_mode = i; + mutex_unlock(&td->lock); + return count; } @@ -485,45 +636,93 @@ static struct attribute_group taal_attr_group = { .attrs = taal_attrs, }; +static void taal_hw_reset(struct omap_dss_device *dssdev) +{ + struct taal_data *td = dev_get_drvdata(&dssdev->dev); + struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); + + if (panel_data->reset_gpio == -1) + return; + + gpio_set_value(panel_data->reset_gpio, 1); + if (td->panel_config->reset_sequence.high) + udelay(td->panel_config->reset_sequence.high); + /* reset the panel */ + gpio_set_value(panel_data->reset_gpio, 0); + /* assert reset */ + if (td->panel_config->reset_sequence.low) + udelay(td->panel_config->reset_sequence.low); + gpio_set_value(panel_data->reset_gpio, 1); + /* wait after releasing reset */ + if (td->panel_config->sleep.hw_reset) + msleep(td->panel_config->sleep.hw_reset); +} + static int taal_probe(struct omap_dss_device *dssdev) { struct backlight_properties props; struct taal_data *td; struct backlight_device *bldev; - int r; - - const struct omap_video_timings taal_panel_timings = { - .x_res = 864, - .y_res = 480, - }; + struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); + struct panel_config *panel_config = NULL; + int r, i; dev_dbg(&dssdev->dev, "probe\n"); + if (!panel_data || !panel_data->name) { + r = -EINVAL; + goto err; + } + + for (i = 0; i < ARRAY_SIZE(panel_configs); i++) { + if (strcmp(panel_data->name, panel_configs[i].name) == 0) { + panel_config = &panel_configs[i]; + break; + } + } + + if (!panel_config) { + r = -EINVAL; + goto err; + } + dssdev->panel.config = OMAP_DSS_LCD_TFT; - dssdev->panel.timings = taal_panel_timings; + dssdev->panel.timings = panel_config->timings; dssdev->ctrl.pixel_size = 24; td = kzalloc(sizeof(*td), GFP_KERNEL); if (!td) { r = -ENOMEM; - goto err0; + goto err; } td->dssdev = dssdev; + td->panel_config = panel_config; + + mutex_init(&td->lock); + + atomic_set(&td->do_update, 0); + + r = init_regulators(dssdev, panel_config->regulators, + panel_config->num_regulators); + if (r) + goto err_reg; td->esd_wq = create_singlethread_workqueue("taal_esd"); if (td->esd_wq == NULL) { dev_err(&dssdev->dev, "can't create ESD workqueue\n"); r = -ENOMEM; - goto err1; + goto err_wq; } INIT_DELAYED_WORK_DEFERRABLE(&td->esd_work, taal_esd_work); dev_set_drvdata(&dssdev->dev, td); + taal_hw_reset(dssdev); + /* if no platform set_backlight() defined, presume DSI backlight * control */ memset(&props, 0, sizeof(struct backlight_properties)); - if (!dssdev->set_backlight) + if (!panel_data->set_backlight) td->use_dsi_bl = true; if (td->use_dsi_bl) @@ -534,7 +733,7 @@ static int taal_probe(struct omap_dss_device *dssdev) &taal_bl_ops, &props); if (IS_ERR(bldev)) { r = PTR_ERR(bldev); - goto err2; + goto err_bl; } td->bldev = bldev; @@ -548,13 +747,13 @@ static int taal_probe(struct omap_dss_device *dssdev) taal_bl_update_status(bldev); - if (dssdev->phy.dsi.ext_te) { - int gpio = dssdev->phy.dsi.ext_te_gpio; + if (panel_data->use_ext_te) { + int gpio = panel_data->ext_te_gpio; r = gpio_request(gpio, "taal irq"); if (r) { dev_err(&dssdev->dev, "GPIO request failed\n"); - goto err3; + goto err_gpio; } gpio_direction_input(gpio); @@ -566,49 +765,52 @@ static int taal_probe(struct omap_dss_device *dssdev) if (r) { dev_err(&dssdev->dev, "IRQ request failed\n"); gpio_free(gpio); - goto err3; + goto err_irq; } - init_completion(&td->te_completion); + INIT_DELAYED_WORK_DEFERRABLE(&td->te_timeout_work, + taal_te_timeout_work_callback); - td->use_ext_te = true; + dev_dbg(&dssdev->dev, "Using GPIO TE\n"); } r = sysfs_create_group(&dssdev->dev.kobj, &taal_attr_group); if (r) { dev_err(&dssdev->dev, "failed to create sysfs files\n"); - goto err4; + goto err_sysfs; } return 0; -err4: - if (td->use_ext_te) { - int gpio = dssdev->phy.dsi.ext_te_gpio; - free_irq(gpio_to_irq(gpio), dssdev); - gpio_free(gpio); - } -err3: +err_sysfs: + if (panel_data->use_ext_te) + free_irq(gpio_to_irq(panel_data->ext_te_gpio), dssdev); +err_irq: + if (panel_data->use_ext_te) + gpio_free(panel_data->ext_te_gpio); +err_gpio: backlight_device_unregister(bldev); -err2: - cancel_delayed_work_sync(&td->esd_work); +err_bl: destroy_workqueue(td->esd_wq); -err1: +err_wq: + free_regulators(panel_config->regulators, panel_config->num_regulators); +err_reg: kfree(td); -err0: +err: return r; } static void taal_remove(struct omap_dss_device *dssdev) { struct taal_data *td = dev_get_drvdata(&dssdev->dev); + struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); struct backlight_device *bldev; dev_dbg(&dssdev->dev, "remove\n"); sysfs_remove_group(&dssdev->dev.kobj, &taal_attr_group); - if (td->use_ext_te) { - int gpio = dssdev->phy.dsi.ext_te_gpio; + if (panel_data->use_ext_te) { + int gpio = panel_data->ext_te_gpio; free_irq(gpio_to_irq(gpio), dssdev); gpio_free(gpio); } @@ -618,9 +820,15 @@ static void taal_remove(struct omap_dss_device *dssdev) taal_bl_update_status(bldev); backlight_device_unregister(bldev); - cancel_delayed_work_sync(&td->esd_work); + cancel_delayed_work(&td->esd_work); destroy_workqueue(td->esd_wq); + /* reset, to be sure that the panel is in a valid state */ + taal_hw_reset(dssdev); + + free_regulators(td->panel_config->regulators, + td->panel_config->num_regulators); + kfree(td); } @@ -630,23 +838,14 @@ static int taal_power_on(struct omap_dss_device *dssdev) u8 id1, id2, id3; int r; - if (dssdev->platform_enable) { - r = dssdev->platform_enable(dssdev); - if (r) - return r; - } - - /* it seems we have to wait a bit until taal is ready */ - msleep(5); - - dsi_bus_lock(); - r = omapdss_dsi_display_enable(dssdev); if (r) { dev_err(&dssdev->dev, "failed to enable DSI\n"); goto err0; } + taal_hw_reset(dssdev); + omapdss_dsi_vc_enable_hs(TCH, false); r = taal_sleep_out(td); @@ -657,34 +856,47 @@ static int taal_power_on(struct omap_dss_device *dssdev) if (r) goto err; - /* on early revisions CABC is broken */ - if (id2 == 0x00 || id2 == 0xff || id2 == 0x81) + /* on early Taal revisions CABC is broken */ + if (td->panel_config->type == PANEL_TAAL && + (id2 == 0x00 || id2 == 0xff || id2 == 0x81)) td->cabc_broken = true; - taal_dcs_write_1(DCS_BRIGHTNESS, 0xff); - taal_dcs_write_1(DCS_CTRL_DISPLAY, (1<<2) | (1<<5)); /* BL | BCTRL */ + r = taal_dcs_write_1(DCS_BRIGHTNESS, 0xff); + if (r) + goto err; + + r = taal_dcs_write_1(DCS_CTRL_DISPLAY, + (1<<2) | (1<<5)); /* BL | BCTRL */ + if (r) + goto err; + + r = taal_dcs_write_1(DCS_PIXEL_FORMAT, 0x7); /* 24bit/pixel */ + if (r) + goto err; - taal_dcs_write_1(DCS_PIXEL_FORMAT, 0x7); /* 24bit/pixel */ + r = taal_set_addr_mode(td->rotate, td->mirror); + if (r) + goto err; - taal_set_addr_mode(td->rotate, td->mirror); - if (!td->cabc_broken) - taal_dcs_write_1(DCS_WRITE_CABC, td->cabc_mode); + if (!td->cabc_broken) { + r = taal_dcs_write_1(DCS_WRITE_CABC, td->cabc_mode); + if (r) + goto err; + } - taal_dcs_write_0(DCS_DISPLAY_ON); + r = taal_dcs_write_0(DCS_DISPLAY_ON); + if (r) + goto err; r = _taal_enable_te(dssdev, td->te_enabled); if (r) goto err; -#ifdef TAAL_USE_ESD_CHECK - queue_delayed_work(td->esd_wq, &td->esd_work, TAAL_ESD_CHECK_PERIOD); -#endif - td->enabled = 1; if (!td->intro_printed) { - dev_info(&dssdev->dev, "revision %02x.%02x.%02x\n", - id1, id2, id3); + dev_info(&dssdev->dev, "%s panel revision %02x.%02x.%02x\n", + td->panel_config->name, id1, id2, id3); if (td->cabc_broken) dev_info(&dssdev->dev, "old Taal version, CABC disabled\n"); @@ -693,94 +905,168 @@ static int taal_power_on(struct omap_dss_device *dssdev) omapdss_dsi_vc_enable_hs(TCH, true); - dsi_bus_unlock(); - return 0; err: - dsi_bus_unlock(); + dev_err(&dssdev->dev, "error while enabling panel, issuing HW reset\n"); + + taal_hw_reset(dssdev); omapdss_dsi_display_disable(dssdev); err0: - if (dssdev->platform_disable) - dssdev->platform_disable(dssdev); - return r; } static void taal_power_off(struct omap_dss_device *dssdev) { struct taal_data *td = dev_get_drvdata(&dssdev->dev); + int r; - dsi_bus_lock(); - - cancel_delayed_work(&td->esd_work); - - taal_dcs_write_0(DCS_DISPLAY_OFF); - taal_sleep_in(td); + r = taal_dcs_write_0(DCS_DISPLAY_OFF); + if (!r) { + r = taal_sleep_in(td); + /* HACK: wait a bit so that the message goes through */ + msleep(10); + } - /* wait a bit so that the message goes through */ - msleep(10); + if (r) { + dev_err(&dssdev->dev, + "error disabling panel, issuing HW reset\n"); + taal_hw_reset(dssdev); + } omapdss_dsi_display_disable(dssdev); - if (dssdev->platform_disable) - dssdev->platform_disable(dssdev); - td->enabled = 0; - - dsi_bus_unlock(); } static int taal_enable(struct omap_dss_device *dssdev) { + struct taal_data *td = dev_get_drvdata(&dssdev->dev); + struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); int r; + dev_dbg(&dssdev->dev, "enable\n"); - if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) - return -EINVAL; + mutex_lock(&td->lock); + + if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) { + r = -EINVAL; + goto err; + } + + dsi_bus_lock(); r = taal_power_on(dssdev); + + dsi_bus_unlock(); + if (r) - return r; + goto err; + + if (panel_data->use_esd_check) + queue_delayed_work(td->esd_wq, &td->esd_work, + TAAL_ESD_CHECK_PERIOD); dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; + mutex_unlock(&td->lock); + + return 0; +err: + dev_dbg(&dssdev->dev, "enable failed\n"); + mutex_unlock(&td->lock); return r; } static void taal_disable(struct omap_dss_device *dssdev) { + struct taal_data *td = dev_get_drvdata(&dssdev->dev); + dev_dbg(&dssdev->dev, "disable\n"); + mutex_lock(&td->lock); + + cancel_delayed_work(&td->esd_work); + + dsi_bus_lock(); + if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) taal_power_off(dssdev); + dsi_bus_unlock(); + dssdev->state = OMAP_DSS_DISPLAY_DISABLED; + + mutex_unlock(&td->lock); } static int taal_suspend(struct omap_dss_device *dssdev) { + struct taal_data *td = dev_get_drvdata(&dssdev->dev); + int r; + dev_dbg(&dssdev->dev, "suspend\n"); - if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) - return -EINVAL; + mutex_lock(&td->lock); + + if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) { + r = -EINVAL; + goto err; + } + + cancel_delayed_work(&td->esd_work); + + dsi_bus_lock(); taal_power_off(dssdev); + + dsi_bus_unlock(); + dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; + mutex_unlock(&td->lock); + return 0; +err: + mutex_unlock(&td->lock); + return r; } static int taal_resume(struct omap_dss_device *dssdev) { + struct taal_data *td = dev_get_drvdata(&dssdev->dev); + struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); int r; + dev_dbg(&dssdev->dev, "resume\n"); - if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED) - return -EINVAL; + mutex_lock(&td->lock); + + if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED) { + r = -EINVAL; + goto err; + } + + dsi_bus_lock(); r = taal_power_on(dssdev); - dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; + + dsi_bus_unlock(); + + if (r) { + dssdev->state = OMAP_DSS_DISPLAY_DISABLED; + } else { + dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; + if (panel_data->use_esd_check) + queue_delayed_work(td->esd_wq, &td->esd_work, + TAAL_ESD_CHECK_PERIOD); + } + + mutex_unlock(&td->lock); + + return r; +err: + mutex_unlock(&td->lock); return r; } @@ -791,14 +1077,57 @@ static void taal_framedone_cb(int err, void *data) dsi_bus_unlock(); } +static irqreturn_t taal_te_isr(int irq, void *data) +{ + struct omap_dss_device *dssdev = data; + struct taal_data *td = dev_get_drvdata(&dssdev->dev); + int old; + int r; + + old = atomic_cmpxchg(&td->do_update, 1, 0); + + if (old) { + cancel_delayed_work(&td->te_timeout_work); + + r = omap_dsi_update(dssdev, TCH, + td->update_region.x, + td->update_region.y, + td->update_region.w, + td->update_region.h, + taal_framedone_cb, dssdev); + if (r) + goto err; + } + + return IRQ_HANDLED; +err: + dev_err(&dssdev->dev, "start update failed\n"); + dsi_bus_unlock(); + return IRQ_HANDLED; +} + +static void taal_te_timeout_work_callback(struct work_struct *work) +{ + struct taal_data *td = container_of(work, struct taal_data, + te_timeout_work.work); + struct omap_dss_device *dssdev = td->dssdev; + + dev_err(&dssdev->dev, "TE not received for 250ms!\n"); + + atomic_set(&td->do_update, 0); + dsi_bus_unlock(); +} + static int taal_update(struct omap_dss_device *dssdev, u16 x, u16 y, u16 w, u16 h) { struct taal_data *td = dev_get_drvdata(&dssdev->dev); + struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); int r; dev_dbg(&dssdev->dev, "update %d, %d, %d x %d\n", x, y, w, h); + mutex_lock(&td->lock); dsi_bus_lock(); if (!td->enabled) { @@ -806,7 +1135,7 @@ static int taal_update(struct omap_dss_device *dssdev, goto err; } - r = omap_dsi_prepare_update(dssdev, &x, &y, &w, &h); + r = omap_dsi_prepare_update(dssdev, &x, &y, &w, &h, true); if (r) goto err; @@ -814,24 +1143,41 @@ static int taal_update(struct omap_dss_device *dssdev, if (r) goto err; - r = omap_dsi_update(dssdev, TCH, x, y, w, h, - taal_framedone_cb, dssdev); - if (r) - goto err; + if (td->te_enabled && panel_data->use_ext_te) { + td->update_region.x = x; + td->update_region.y = y; + td->update_region.w = w; + td->update_region.h = h; + barrier(); + schedule_delayed_work(&td->te_timeout_work, + msecs_to_jiffies(250)); + atomic_set(&td->do_update, 1); + } else { + r = omap_dsi_update(dssdev, TCH, x, y, w, h, + taal_framedone_cb, dssdev); + if (r) + goto err; + } /* note: no bus_unlock here. unlock is in framedone_cb */ + mutex_unlock(&td->lock); return 0; err: dsi_bus_unlock(); + mutex_unlock(&td->lock); return r; } static int taal_sync(struct omap_dss_device *dssdev) { + struct taal_data *td = dev_get_drvdata(&dssdev->dev); + dev_dbg(&dssdev->dev, "sync\n"); + mutex_lock(&td->lock); dsi_bus_lock(); dsi_bus_unlock(); + mutex_unlock(&td->lock); dev_dbg(&dssdev->dev, "sync done\n"); @@ -841,33 +1187,51 @@ static int taal_sync(struct omap_dss_device *dssdev) static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable) { struct taal_data *td = dev_get_drvdata(&dssdev->dev); + struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); int r; - td->te_enabled = enable; - if (enable) r = taal_dcs_write_1(DCS_TEAR_ON, 0); else r = taal_dcs_write_0(DCS_TEAR_OFF); - omapdss_dsi_enable_te(dssdev, enable); + if (!panel_data->use_ext_te) + omapdss_dsi_enable_te(dssdev, enable); - /* XXX for some reason, DSI TE breaks if we don't wait here. - * Panel bug? Needs more studying */ - msleep(100); + if (td->panel_config->sleep.enable_te) + msleep(td->panel_config->sleep.enable_te); return r; } static int taal_enable_te(struct omap_dss_device *dssdev, bool enable) { + struct taal_data *td = dev_get_drvdata(&dssdev->dev); int r; + mutex_lock(&td->lock); + + if (td->te_enabled == enable) + goto end; + dsi_bus_lock(); - r = _taal_enable_te(dssdev, enable); + if (td->enabled) { + r = _taal_enable_te(dssdev, enable); + if (r) + goto err; + } + + td->te_enabled = enable; dsi_bus_unlock(); +end: + mutex_unlock(&td->lock); + + return 0; +err: + dsi_bus_unlock(); + mutex_unlock(&td->lock); return r; } @@ -875,7 +1239,13 @@ static int taal_enable_te(struct omap_dss_device *dssdev, bool enable) static int taal_get_te(struct omap_dss_device *dssdev) { struct taal_data *td = dev_get_drvdata(&dssdev->dev); - return td->te_enabled; + int r; + + mutex_lock(&td->lock); + r = td->te_enabled; + mutex_unlock(&td->lock); + + return r; } static int taal_rotate(struct omap_dss_device *dssdev, u8 rotate) @@ -885,6 +1255,11 @@ static int taal_rotate(struct omap_dss_device *dssdev, u8 rotate) dev_dbg(&dssdev->dev, "rotate %d\n", rotate); + mutex_lock(&td->lock); + + if (td->rotate == rotate) + goto end; + dsi_bus_lock(); if (td->enabled) { @@ -896,16 +1271,25 @@ static int taal_rotate(struct omap_dss_device *dssdev, u8 rotate) td->rotate = rotate; dsi_bus_unlock(); +end: + mutex_unlock(&td->lock); return 0; err: dsi_bus_unlock(); + mutex_unlock(&td->lock); return r; } static u8 taal_get_rotate(struct omap_dss_device *dssdev) { struct taal_data *td = dev_get_drvdata(&dssdev->dev); - return td->rotate; + int r; + + mutex_lock(&td->lock); + r = td->rotate; + mutex_unlock(&td->lock); + + return r; } static int taal_mirror(struct omap_dss_device *dssdev, bool enable) @@ -915,6 +1299,11 @@ static int taal_mirror(struct omap_dss_device *dssdev, bool enable) dev_dbg(&dssdev->dev, "mirror %d\n", enable); + mutex_lock(&td->lock); + + if (td->mirror == enable) + goto end; + dsi_bus_lock(); if (td->enabled) { r = taal_set_addr_mode(td->rotate, enable); @@ -925,39 +1314,59 @@ static int taal_mirror(struct omap_dss_device *dssdev, bool enable) td->mirror = enable; dsi_bus_unlock(); +end: + mutex_unlock(&td->lock); return 0; err: dsi_bus_unlock(); + mutex_unlock(&td->lock); return r; } static bool taal_get_mirror(struct omap_dss_device *dssdev) { struct taal_data *td = dev_get_drvdata(&dssdev->dev); - return td->mirror; + int r; + + mutex_lock(&td->lock); + r = td->mirror; + mutex_unlock(&td->lock); + + return r; } static int taal_run_test(struct omap_dss_device *dssdev, int test_num) { + struct taal_data *td = dev_get_drvdata(&dssdev->dev); u8 id1, id2, id3; int r; + mutex_lock(&td->lock); + + if (!td->enabled) { + r = -ENODEV; + goto err1; + } + dsi_bus_lock(); r = taal_dcs_read_1(DCS_GET_ID1, &id1); if (r) - goto err; + goto err2; r = taal_dcs_read_1(DCS_GET_ID2, &id2); if (r) - goto err; + goto err2; r = taal_dcs_read_1(DCS_GET_ID3, &id3); if (r) - goto err; + goto err2; dsi_bus_unlock(); + mutex_unlock(&td->lock); return 0; -err: +err2: dsi_bus_unlock(); +err1: + mutex_unlock(&td->lock); return r; } @@ -971,12 +1380,16 @@ static int taal_memory_read(struct omap_dss_device *dssdev, unsigned buf_used = 0; struct taal_data *td = dev_get_drvdata(&dssdev->dev); - if (!td->enabled) - return -ENODEV; - if (size < w * h * 3) return -ENOMEM; + mutex_lock(&td->lock); + + if (!td->enabled) { + r = -ENODEV; + goto err1; + } + size = min(w * h * 3, dssdev->panel.timings.x_res * dssdev->panel.timings.y_res * 3); @@ -995,7 +1408,7 @@ static int taal_memory_read(struct omap_dss_device *dssdev, r = dsi_vc_set_max_rx_packet_size(TCH, plen); if (r) - goto err0; + goto err2; while (buf_used < size) { u8 dcs_cmd = first ? 0x2e : 0x3e; @@ -1006,7 +1419,7 @@ static int taal_memory_read(struct omap_dss_device *dssdev, if (r < 0) { dev_err(&dssdev->dev, "read error\n"); - goto err; + goto err3; } buf_used += r; @@ -1020,16 +1433,18 @@ static int taal_memory_read(struct omap_dss_device *dssdev, dev_err(&dssdev->dev, "signal pending, " "aborting memory read\n"); r = -ERESTARTSYS; - goto err; + goto err3; } } r = buf_used; -err: +err3: dsi_vc_set_max_rx_packet_size(TCH, 1); -err0: +err2: dsi_bus_unlock(); +err1: + mutex_unlock(&td->lock); return r; } @@ -1038,11 +1453,16 @@ static void taal_esd_work(struct work_struct *work) struct taal_data *td = container_of(work, struct taal_data, esd_work.work); struct omap_dss_device *dssdev = td->dssdev; + struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); u8 state1, state2; int r; - if (!td->enabled) + mutex_lock(&td->lock); + + if (!td->enabled) { + mutex_unlock(&td->lock); return; + } dsi_bus_lock(); @@ -1074,7 +1494,7 @@ static void taal_esd_work(struct work_struct *work) } /* Self-diagnostics result is also shown on TE GPIO line. We need * to re-enable TE after self diagnostics */ - if (td->use_ext_te && td->te_enabled) { + if (td->te_enabled && panel_data->use_ext_te) { r = taal_dcs_write_1(DCS_TEAR_ON, 0); if (r) goto err; @@ -1084,16 +1504,20 @@ static void taal_esd_work(struct work_struct *work) queue_delayed_work(td->esd_wq, &td->esd_work, TAAL_ESD_CHECK_PERIOD); + mutex_unlock(&td->lock); return; err: dev_err(&dssdev->dev, "performing LCD reset\n"); - taal_disable(dssdev); - taal_enable(dssdev); + taal_power_off(dssdev); + taal_hw_reset(dssdev); + taal_power_on(dssdev); dsi_bus_unlock(); queue_delayed_work(td->esd_wq, &td->esd_work, TAAL_ESD_CHECK_PERIOD); + + mutex_unlock(&td->lock); } static int taal_set_update_mode(struct omap_dss_device *dssdev, diff --git a/drivers/video/omap2/displays/panel-toppoly-tdo35s.c b/drivers/video/omap2/displays/panel-toppoly-tdo35s.c index fa434ca6e4b7..e320e67d06f3 100644 --- a/drivers/video/omap2/displays/panel-toppoly-tdo35s.c +++ b/drivers/video/omap2/displays/panel-toppoly-tdo35s.c @@ -73,8 +73,12 @@ static void toppoly_tdo_panel_power_off(struct omap_dss_device *dssdev) static int toppoly_tdo_panel_probe(struct omap_dss_device *dssdev) { - dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS | - OMAP_DSS_LCD_IHS; + dssdev->panel.config = OMAP_DSS_LCD_TFT | + OMAP_DSS_LCD_IVS | + OMAP_DSS_LCD_IHS | + OMAP_DSS_LCD_IPC | + OMAP_DSS_LCD_ONOFF; + dssdev->panel.timings = toppoly_tdo_panel_timings; return 0; diff --git a/drivers/video/omap2/dss/Kconfig b/drivers/video/omap2/dss/Kconfig index 87afb81b2c44..43b64403eaa4 100644 --- a/drivers/video/omap2/dss/Kconfig +++ b/drivers/video/omap2/dss/Kconfig @@ -36,6 +36,12 @@ config OMAP2_DSS_COLLECT_IRQ_STATS <debugfs>/omapdss/dispc_irq for DISPC interrupts, and <debugfs>/omapdss/dsi_irq for DSI interrupts. +config OMAP2_DSS_DPI + bool "DPI support" + default y + help + DPI Interface. This is the Parallel Display Interface. + config OMAP2_DSS_RFBI bool "RFBI support" default n diff --git a/drivers/video/omap2/dss/Makefile b/drivers/video/omap2/dss/Makefile index 980c72c2db98..d71b5d9d71b1 100644 --- a/drivers/video/omap2/dss/Makefile +++ b/drivers/video/omap2/dss/Makefile @@ -1,5 +1,6 @@ obj-$(CONFIG_OMAP2_DSS) += omapdss.o -omapdss-y := core.o dss.o dispc.o dpi.o display.o manager.o overlay.o +omapdss-y := core.o dss.o dispc.o display.o manager.o overlay.o +omapdss-$(CONFIG_OMAP2_DSS_DPI) += dpi.o omapdss-$(CONFIG_OMAP2_DSS_RFBI) += rfbi.o omapdss-$(CONFIG_OMAP2_DSS_VENC) += venc.o omapdss-$(CONFIG_OMAP2_DSS_SDI) += sdi.o diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c index 7ebe50b335ed..b3a498f22d36 100644 --- a/drivers/video/omap2/dss/core.c +++ b/drivers/video/omap2/dss/core.c @@ -482,6 +482,14 @@ static void dss_uninitialize_debugfs(void) if (dss_debugfs_dir) debugfs_remove_recursive(dss_debugfs_dir); } +#else /* CONFIG_DEBUG_FS && CONFIG_OMAP2_DSS_DEBUG_SUPPORT */ +static inline int dss_initialize_debugfs(void) +{ + return 0; +} +static inline void dss_uninitialize_debugfs(void) +{ +} #endif /* CONFIG_DEBUG_FS && CONFIG_OMAP2_DSS_DEBUG_SUPPORT */ /* PLATFORM DEVICE */ @@ -499,7 +507,7 @@ static int omap_dss_probe(struct platform_device *pdev) r = dss_get_clocks(); if (r) - goto fail0; + goto err_clocks; dss_clk_enable_all_no_ctx(); @@ -515,64 +523,64 @@ static int omap_dss_probe(struct platform_device *pdev) r = dss_init(skip_init); if (r) { DSSERR("Failed to initialize DSS\n"); - goto fail0; + goto err_dss; } -#ifdef CONFIG_OMAP2_DSS_RFBI r = rfbi_init(); if (r) { DSSERR("Failed to initialize rfbi\n"); - goto fail0; + goto err_rfbi; } -#endif r = dpi_init(pdev); if (r) { DSSERR("Failed to initialize dpi\n"); - goto fail0; + goto err_dpi; } r = dispc_init(); if (r) { DSSERR("Failed to initialize dispc\n"); - goto fail0; + goto err_dispc; } -#ifdef CONFIG_OMAP2_DSS_VENC + r = venc_init(pdev); if (r) { DSSERR("Failed to initialize venc\n"); - goto fail0; + goto err_venc; } -#endif + if (cpu_is_omap34xx()) { -#ifdef CONFIG_OMAP2_DSS_SDI r = sdi_init(skip_init); if (r) { DSSERR("Failed to initialize SDI\n"); - goto fail0; + goto err_sdi; } -#endif -#ifdef CONFIG_OMAP2_DSS_DSI + r = dsi_init(pdev); if (r) { DSSERR("Failed to initialize DSI\n"); - goto fail0; + goto err_dsi; } -#endif } -#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT) r = dss_initialize_debugfs(); if (r) - goto fail0; -#endif + goto err_debugfs; for (i = 0; i < pdata->num_devices; ++i) { struct omap_dss_device *dssdev = pdata->devices[i]; r = omap_dss_register_device(dssdev); - if (r) - DSSERR("device reg failed %d\n", i); + if (r) { + DSSERR("device %d %s register failed %d\n", i, + dssdev->name ?: "unnamed", r); + + while (--i >= 0) + omap_dss_unregister_device(pdata->devices[i]); + + goto err_register; + } if (def_disp_name && strcmp(def_disp_name, dssdev->name) == 0) pdata->default_device = dssdev; @@ -582,8 +590,29 @@ static int omap_dss_probe(struct platform_device *pdev) return 0; - /* XXX fail correctly */ -fail0: +err_register: + dss_uninitialize_debugfs(); +err_debugfs: + if (cpu_is_omap34xx()) + dsi_exit(); +err_dsi: + if (cpu_is_omap34xx()) + sdi_exit(); +err_sdi: + venc_exit(); +err_venc: + dispc_exit(); +err_dispc: + dpi_exit(); +err_dpi: + rfbi_exit(); +err_rfbi: + dss_exit(); +err_dss: + dss_clk_disable_all_no_ctx(); + dss_put_clocks(); +err_clocks: + return r; } @@ -593,25 +622,15 @@ static int omap_dss_remove(struct platform_device *pdev) int i; int c; -#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT) dss_uninitialize_debugfs(); -#endif -#ifdef CONFIG_OMAP2_DSS_VENC venc_exit(); -#endif dispc_exit(); dpi_exit(); -#ifdef CONFIG_OMAP2_DSS_RFBI rfbi_exit(); -#endif if (cpu_is_omap34xx()) { -#ifdef CONFIG_OMAP2_DSS_DSI dsi_exit(); -#endif -#ifdef CONFIG_OMAP2_DSS_SDI sdi_exit(); -#endif } dss_exit(); diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index e777e352dbcd..5ecdc0004094 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c @@ -31,6 +31,7 @@ #include <linux/seq_file.h> #include <linux/delay.h> #include <linux/workqueue.h> +#include <linux/hardirq.h> #include <plat/sram.h> #include <plat/clock.h> @@ -335,7 +336,7 @@ void dispc_save_context(void) void dispc_restore_context(void) { RR(SYSCONFIG); - RR(IRQENABLE); + /*RR(IRQENABLE);*/ /*RR(CONTROL);*/ RR(CONFIG); RR(DEFAULT_COLOR0); @@ -472,6 +473,15 @@ void dispc_restore_context(void) /* enable last, because LCD & DIGIT enable are here */ RR(CONTROL); + + /* clear spurious SYNC_LOST_DIGIT interrupts */ + dispc_write_reg(DISPC_IRQSTATUS, DISPC_IRQ_SYNC_LOST_DIGIT); + + /* + * enable last so IRQs won't trigger before + * the context is fully restored + */ + RR(IRQENABLE); } #undef SR @@ -3019,7 +3029,7 @@ void dispc_fake_vsync_irq(void) u32 irqstatus = DISPC_IRQ_VSYNC; int i; - local_irq_disable(); + WARN_ON(!in_interrupt()); for (i = 0; i < DISPC_MAX_NR_ISRS; i++) { struct omap_dispc_isr_data *isr_data; @@ -3031,8 +3041,6 @@ void dispc_fake_vsync_irq(void) if (isr_data->mask & irqstatus) isr_data->isr(isr_data->arg, irqstatus); } - - local_irq_enable(); } #endif diff --git a/drivers/video/omap2/dss/display.c b/drivers/video/omap2/dss/display.c index 6a74ea116d29..22dd7a474f79 100644 --- a/drivers/video/omap2/dss/display.c +++ b/drivers/video/omap2/dss/display.c @@ -82,6 +82,9 @@ static ssize_t display_upd_mode_store(struct device *dev, int val, r; enum omap_dss_update_mode mode; + if (!dssdev->driver->set_update_mode) + return -EINVAL; + val = simple_strtoul(buf, NULL, 10); switch (val) { @@ -343,7 +346,6 @@ int omapdss_default_get_recommended_bpp(struct omap_dss_device *dssdev) case OMAP_DISPLAY_TYPE_VENC: case OMAP_DISPLAY_TYPE_SDI: return 24; - return 24; default: BUG(); } @@ -392,7 +394,9 @@ void dss_init_device(struct platform_device *pdev, int r; switch (dssdev->type) { +#ifdef CONFIG_OMAP2_DSS_DPI case OMAP_DISPLAY_TYPE_DPI: +#endif #ifdef CONFIG_OMAP2_DSS_RFBI case OMAP_DISPLAY_TYPE_DBI: #endif @@ -413,9 +417,11 @@ void dss_init_device(struct platform_device *pdev, } switch (dssdev->type) { +#ifdef CONFIG_OMAP2_DSS_DPI case OMAP_DISPLAY_TYPE_DPI: r = dpi_init_display(dssdev); break; +#endif #ifdef CONFIG_OMAP2_DSS_RFBI case OMAP_DISPLAY_TYPE_DBI: r = rfbi_init_display(dssdev); @@ -541,7 +547,10 @@ int dss_resume_all_devices(void) static int dss_disable_device(struct device *dev, void *data) { struct omap_dss_device *dssdev = to_dss_device(dev); - dssdev->driver->disable(dssdev); + + if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) + dssdev->driver->disable(dssdev); + return 0; } diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index 3af207b2bde3..b3fa3a7db911 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -165,6 +165,14 @@ struct dsi_reg { u16 idx; }; #define DSI_CIO_IRQ_ERRCONTENTIONLP1_3 (1 << 25) #define DSI_CIO_IRQ_ULPSACTIVENOT_ALL0 (1 << 30) #define DSI_CIO_IRQ_ULPSACTIVENOT_ALL1 (1 << 31) +#define DSI_CIO_IRQ_ERROR_MASK \ + (DSI_CIO_IRQ_ERRSYNCESC1 | DSI_CIO_IRQ_ERRSYNCESC2 | \ + DSI_CIO_IRQ_ERRSYNCESC3 | DSI_CIO_IRQ_ERRESC1 | DSI_CIO_IRQ_ERRESC2 | \ + DSI_CIO_IRQ_ERRESC3 | DSI_CIO_IRQ_ERRCONTROL1 | \ + DSI_CIO_IRQ_ERRCONTROL2 | DSI_CIO_IRQ_ERRCONTROL3 | \ + DSI_CIO_IRQ_ERRCONTENTIONLP0_1 | DSI_CIO_IRQ_ERRCONTENTIONLP1_1 | \ + DSI_CIO_IRQ_ERRCONTENTIONLP0_2 | DSI_CIO_IRQ_ERRCONTENTIONLP1_2 | \ + DSI_CIO_IRQ_ERRCONTENTIONLP0_3 | DSI_CIO_IRQ_ERRCONTENTIONLP1_3) #define DSI_DT_DCS_SHORT_WRITE_0 0x05 #define DSI_DT_DCS_SHORT_WRITE_1 0x15 @@ -232,13 +240,15 @@ static struct unsigned pll_locked; struct completion bta_completion; + void (*bta_callback)(void); int update_channel; struct dsi_update_region update_region; bool te_enabled; - struct work_struct framedone_work; + struct workqueue_struct *workqueue; + void (*framedone_callback)(int, void *); void *framedone_data; @@ -509,9 +519,13 @@ void dsi_irq_handler(void) dss_collect_irq_stats(vcstatus, dsi.irq_stats.vc_irqs[i]); #endif - if (vcstatus & DSI_VC_IRQ_BTA) + if (vcstatus & DSI_VC_IRQ_BTA) { complete(&dsi.bta_completion); + if (dsi.bta_callback) + dsi.bta_callback(); + } + if (vcstatus & DSI_VC_IRQ_ERROR_MASK) { DSSERR("DSI VC(%d) error, vc irqstatus %x\n", i, vcstatus); @@ -536,8 +550,12 @@ void dsi_irq_handler(void) /* flush posted write */ dsi_read_reg(DSI_COMPLEXIO_IRQ_STATUS); - DSSERR("DSI CIO error, cio irqstatus %x\n", ciostatus); - print_irq_status_cio(ciostatus); + if (ciostatus & DSI_CIO_IRQ_ERROR_MASK) { + DSSERR("DSI CIO error, cio irqstatus %x\n", ciostatus); + print_irq_status_cio(ciostatus); + } else if (debug_irq) { + print_irq_status_cio(ciostatus); + } } dsi_write_reg(DSI_IRQSTATUS, irqstatus & ~DSI_IRQ_CHANNEL_MASK); @@ -584,11 +602,8 @@ static void _dsi_initialize_irq(void) for (i = 0; i < 4; ++i) dsi_write_reg(DSI_VC_IRQENABLE(i), l); - /* XXX zonda responds incorrectly, causing control error: - Exit from LP-ESC mode to LP11 uses wrong transition states on the - data lines LP0 and LN0. */ - dsi_write_reg(DSI_COMPLEXIO_IRQ_ENABLE, - -1 & (~DSI_CIO_IRQ_ERRCONTROL2)); + l = DSI_CIO_IRQ_ERROR_MASK; + dsi_write_reg(DSI_COMPLEXIO_IRQ_ENABLE, l); } static u32 dsi_get_errors(void) @@ -1098,6 +1113,7 @@ int dsi_pll_init(struct omap_dss_device *dssdev, bool enable_hsclk, if (wait_for_bit_change(DSI_PLL_STATUS, 0, 1) != 1) { DSSERR("PLL not coming out of reset.\n"); r = -ENODEV; + dispc_pck_free_enable(0); goto err1; } @@ -1740,42 +1756,52 @@ static void dsi_vc_initial_config(int channel) dsi.vc[channel].mode = DSI_VC_MODE_L4; } -static void dsi_vc_config_l4(int channel) +static int dsi_vc_config_l4(int channel) { if (dsi.vc[channel].mode == DSI_VC_MODE_L4) - return; + return 0; DSSDBGF("%d", channel); dsi_vc_enable(channel, 0); - if (REG_GET(DSI_VC_CTRL(channel), 15, 15)) /* VC_BUSY */ + /* VC_BUSY */ + if (wait_for_bit_change(DSI_VC_CTRL(channel), 15, 0) != 0) { DSSERR("vc(%d) busy when trying to config for L4\n", channel); + return -EIO; + } REG_FLD_MOD(DSI_VC_CTRL(channel), 0, 1, 1); /* SOURCE, 0 = L4 */ dsi_vc_enable(channel, 1); dsi.vc[channel].mode = DSI_VC_MODE_L4; + + return 0; } -static void dsi_vc_config_vp(int channel) +static int dsi_vc_config_vp(int channel) { if (dsi.vc[channel].mode == DSI_VC_MODE_VP) - return; + return 0; DSSDBGF("%d", channel); dsi_vc_enable(channel, 0); - if (REG_GET(DSI_VC_CTRL(channel), 15, 15)) /* VC_BUSY */ + /* VC_BUSY */ + if (wait_for_bit_change(DSI_VC_CTRL(channel), 15, 0) != 0) { DSSERR("vc(%d) busy when trying to config for VP\n", channel); + return -EIO; + } REG_FLD_MOD(DSI_VC_CTRL(channel), 1, 1, 1); /* SOURCE, 1 = video port */ dsi_vc_enable(channel, 1); dsi.vc[channel].mode = DSI_VC_MODE_VP; + + return 0; } @@ -1854,19 +1880,19 @@ static u16 dsi_vc_flush_receive_data(int channel) u32 val; u8 dt; val = dsi_read_reg(DSI_VC_SHORT_PACKET_HEADER(channel)); - DSSDBG("\trawval %#08x\n", val); + DSSERR("\trawval %#08x\n", val); dt = FLD_GET(val, 5, 0); if (dt == DSI_DT_RX_ACK_WITH_ERR) { u16 err = FLD_GET(val, 23, 8); dsi_show_rx_ack_with_err(err); } else if (dt == DSI_DT_RX_SHORT_READ_1) { - DSSDBG("\tDCS short response, 1 byte: %#x\n", + DSSERR("\tDCS short response, 1 byte: %#x\n", FLD_GET(val, 23, 8)); } else if (dt == DSI_DT_RX_SHORT_READ_2) { - DSSDBG("\tDCS short response, 2 byte: %#x\n", + DSSERR("\tDCS short response, 2 byte: %#x\n", FLD_GET(val, 23, 8)); } else if (dt == DSI_DT_RX_DCS_LONG_READ) { - DSSDBG("\tDCS long response, len %d\n", + DSSERR("\tDCS long response, len %d\n", FLD_GET(val, 23, 8)); dsi_vc_flush_long_data(channel); } else { @@ -2087,6 +2113,13 @@ int dsi_vc_dcs_write(int channel, u8 *data, int len) if (r) goto err; + if (REG_GET(DSI_VC_CTRL(channel), 20, 20)) { /* RX_FIFO_NOT_EMPTY */ + DSSERR("rx fifo not empty after write, dumping data:\n"); + dsi_vc_flush_receive_data(channel); + r = -EIO; + goto err; + } + return 0; err: DSSERR("dsi_vc_dcs_write(ch %d, cmd 0x%02x, len %d) failed\n", @@ -2233,11 +2266,12 @@ int dsi_vc_dcs_read_1(int channel, u8 dcs_cmd, u8 *data) } EXPORT_SYMBOL(dsi_vc_dcs_read_1); -int dsi_vc_dcs_read_2(int channel, u8 dcs_cmd, u16 *data) +int dsi_vc_dcs_read_2(int channel, u8 dcs_cmd, u8 *data1, u8 *data2) { + u8 buf[2]; int r; - r = dsi_vc_dcs_read(channel, dcs_cmd, (u8 *)data, 2); + r = dsi_vc_dcs_read(channel, dcs_cmd, buf, 2); if (r < 0) return r; @@ -2245,231 +2279,122 @@ int dsi_vc_dcs_read_2(int channel, u8 dcs_cmd, u16 *data) if (r != 2) return -EIO; + *data1 = buf[0]; + *data2 = buf[1]; + return 0; } EXPORT_SYMBOL(dsi_vc_dcs_read_2); int dsi_vc_set_max_rx_packet_size(int channel, u16 len) { - int r; - r = dsi_vc_send_short(channel, DSI_DT_SET_MAX_RET_PKG_SIZE, + return dsi_vc_send_short(channel, DSI_DT_SET_MAX_RET_PKG_SIZE, len, 0); - - if (r) - return r; - - r = dsi_vc_send_bta_sync(channel); - - return r; } EXPORT_SYMBOL(dsi_vc_set_max_rx_packet_size); -static void dsi_set_lp_rx_timeout(unsigned long ns) +static void dsi_set_lp_rx_timeout(unsigned ticks, bool x4, bool x16) { - u32 r; - unsigned x4, x16; unsigned long fck; - unsigned long ticks; + unsigned long total_ticks; + u32 r; - /* ticks in DSI_FCK */ + BUG_ON(ticks > 0x1fff); + /* ticks in DSI_FCK */ fck = dsi_fclk_rate(); - ticks = (fck / 1000 / 1000) * ns / 1000; - x4 = 0; - x16 = 0; - - if (ticks > 0x1fff) { - ticks = (fck / 1000 / 1000) * ns / 1000 / 4; - x4 = 1; - x16 = 0; - } - - if (ticks > 0x1fff) { - ticks = (fck / 1000 / 1000) * ns / 1000 / 16; - x4 = 0; - x16 = 1; - } - - if (ticks > 0x1fff) { - ticks = (fck / 1000 / 1000) * ns / 1000 / (4 * 16); - x4 = 1; - x16 = 1; - } - - if (ticks > 0x1fff) { - DSSWARN("LP_TX_TO over limit, setting it to max\n"); - ticks = 0x1fff; - x4 = 1; - x16 = 1; - } r = dsi_read_reg(DSI_TIMING2); r = FLD_MOD(r, 1, 15, 15); /* LP_RX_TO */ - r = FLD_MOD(r, x16, 14, 14); /* LP_RX_TO_X16 */ - r = FLD_MOD(r, x4, 13, 13); /* LP_RX_TO_X4 */ + r = FLD_MOD(r, x16 ? 1 : 0, 14, 14); /* LP_RX_TO_X16 */ + r = FLD_MOD(r, x4 ? 1 : 0, 13, 13); /* LP_RX_TO_X4 */ r = FLD_MOD(r, ticks, 12, 0); /* LP_RX_COUNTER */ dsi_write_reg(DSI_TIMING2, r); - DSSDBG("LP_RX_TO %lu ns (%#lx ticks%s%s)\n", - (ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1) * 1000) / - (fck / 1000 / 1000), - ticks, x4 ? " x4" : "", x16 ? " x16" : ""); + total_ticks = ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1); + + DSSDBG("LP_RX_TO %lu ticks (%#x%s%s) = %lu ns\n", + total_ticks, + ticks, x4 ? " x4" : "", x16 ? " x16" : "", + (total_ticks * 1000) / (fck / 1000 / 1000)); } -static void dsi_set_ta_timeout(unsigned long ns) +static void dsi_set_ta_timeout(unsigned ticks, bool x8, bool x16) { - u32 r; - unsigned x8, x16; unsigned long fck; - unsigned long ticks; + unsigned long total_ticks; + u32 r; + + BUG_ON(ticks > 0x1fff); /* ticks in DSI_FCK */ fck = dsi_fclk_rate(); - ticks = (fck / 1000 / 1000) * ns / 1000; - x8 = 0; - x16 = 0; - - if (ticks > 0x1fff) { - ticks = (fck / 1000 / 1000) * ns / 1000 / 8; - x8 = 1; - x16 = 0; - } - - if (ticks > 0x1fff) { - ticks = (fck / 1000 / 1000) * ns / 1000 / 16; - x8 = 0; - x16 = 1; - } - - if (ticks > 0x1fff) { - ticks = (fck / 1000 / 1000) * ns / 1000 / (8 * 16); - x8 = 1; - x16 = 1; - } - - if (ticks > 0x1fff) { - DSSWARN("TA_TO over limit, setting it to max\n"); - ticks = 0x1fff; - x8 = 1; - x16 = 1; - } r = dsi_read_reg(DSI_TIMING1); r = FLD_MOD(r, 1, 31, 31); /* TA_TO */ - r = FLD_MOD(r, x16, 30, 30); /* TA_TO_X16 */ - r = FLD_MOD(r, x8, 29, 29); /* TA_TO_X8 */ + r = FLD_MOD(r, x16 ? 1 : 0, 30, 30); /* TA_TO_X16 */ + r = FLD_MOD(r, x8 ? 1 : 0, 29, 29); /* TA_TO_X8 */ r = FLD_MOD(r, ticks, 28, 16); /* TA_TO_COUNTER */ dsi_write_reg(DSI_TIMING1, r); - DSSDBG("TA_TO %lu ns (%#lx ticks%s%s)\n", - (ticks * (x16 ? 16 : 1) * (x8 ? 8 : 1) * 1000) / - (fck / 1000 / 1000), - ticks, x8 ? " x8" : "", x16 ? " x16" : ""); + total_ticks = ticks * (x16 ? 16 : 1) * (x8 ? 8 : 1); + + DSSDBG("TA_TO %lu ticks (%#x%s%s) = %lu ns\n", + total_ticks, + ticks, x8 ? " x8" : "", x16 ? " x16" : "", + (total_ticks * 1000) / (fck / 1000 / 1000)); } -static void dsi_set_stop_state_counter(unsigned long ns) +static void dsi_set_stop_state_counter(unsigned ticks, bool x4, bool x16) { - u32 r; - unsigned x4, x16; unsigned long fck; - unsigned long ticks; + unsigned long total_ticks; + u32 r; - /* ticks in DSI_FCK */ + BUG_ON(ticks > 0x1fff); + /* ticks in DSI_FCK */ fck = dsi_fclk_rate(); - ticks = (fck / 1000 / 1000) * ns / 1000; - x4 = 0; - x16 = 0; - - if (ticks > 0x1fff) { - ticks = (fck / 1000 / 1000) * ns / 1000 / 4; - x4 = 1; - x16 = 0; - } - - if (ticks > 0x1fff) { - ticks = (fck / 1000 / 1000) * ns / 1000 / 16; - x4 = 0; - x16 = 1; - } - - if (ticks > 0x1fff) { - ticks = (fck / 1000 / 1000) * ns / 1000 / (4 * 16); - x4 = 1; - x16 = 1; - } - - if (ticks > 0x1fff) { - DSSWARN("STOP_STATE_COUNTER_IO over limit, " - "setting it to max\n"); - ticks = 0x1fff; - x4 = 1; - x16 = 1; - } r = dsi_read_reg(DSI_TIMING1); r = FLD_MOD(r, 1, 15, 15); /* FORCE_TX_STOP_MODE_IO */ - r = FLD_MOD(r, x16, 14, 14); /* STOP_STATE_X16_IO */ - r = FLD_MOD(r, x4, 13, 13); /* STOP_STATE_X4_IO */ + r = FLD_MOD(r, x16 ? 1 : 0, 14, 14); /* STOP_STATE_X16_IO */ + r = FLD_MOD(r, x4 ? 1 : 0, 13, 13); /* STOP_STATE_X4_IO */ r = FLD_MOD(r, ticks, 12, 0); /* STOP_STATE_COUNTER_IO */ dsi_write_reg(DSI_TIMING1, r); - DSSDBG("STOP_STATE_COUNTER %lu ns (%#lx ticks%s%s)\n", - (ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1) * 1000) / - (fck / 1000 / 1000), - ticks, x4 ? " x4" : "", x16 ? " x16" : ""); + total_ticks = ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1); + + DSSDBG("STOP_STATE_COUNTER %lu ticks (%#x%s%s) = %lu ns\n", + total_ticks, + ticks, x4 ? " x4" : "", x16 ? " x16" : "", + (total_ticks * 1000) / (fck / 1000 / 1000)); } -static void dsi_set_hs_tx_timeout(unsigned long ns) +static void dsi_set_hs_tx_timeout(unsigned ticks, bool x4, bool x16) { - u32 r; - unsigned x4, x16; unsigned long fck; - unsigned long ticks; + unsigned long total_ticks; + u32 r; - /* ticks in TxByteClkHS */ + BUG_ON(ticks > 0x1fff); + /* ticks in TxByteClkHS */ fck = dsi_get_txbyteclkhs(); - ticks = (fck / 1000 / 1000) * ns / 1000; - x4 = 0; - x16 = 0; - - if (ticks > 0x1fff) { - ticks = (fck / 1000 / 1000) * ns / 1000 / 4; - x4 = 1; - x16 = 0; - } - - if (ticks > 0x1fff) { - ticks = (fck / 1000 / 1000) * ns / 1000 / 16; - x4 = 0; - x16 = 1; - } - - if (ticks > 0x1fff) { - ticks = (fck / 1000 / 1000) * ns / 1000 / (4 * 16); - x4 = 1; - x16 = 1; - } - - if (ticks > 0x1fff) { - DSSWARN("HS_TX_TO over limit, setting it to max\n"); - ticks = 0x1fff; - x4 = 1; - x16 = 1; - } r = dsi_read_reg(DSI_TIMING2); r = FLD_MOD(r, 1, 31, 31); /* HS_TX_TO */ - r = FLD_MOD(r, x16, 30, 30); /* HS_TX_TO_X16 */ - r = FLD_MOD(r, x4, 29, 29); /* HS_TX_TO_X8 (4 really) */ + r = FLD_MOD(r, x16 ? 1 : 0, 30, 30); /* HS_TX_TO_X16 */ + r = FLD_MOD(r, x4 ? 1 : 0, 29, 29); /* HS_TX_TO_X8 (4 really) */ r = FLD_MOD(r, ticks, 28, 16); /* HS_TX_TO_COUNTER */ dsi_write_reg(DSI_TIMING2, r); - DSSDBG("HS_TX_TO %lu ns (%#lx ticks%s%s)\n", - (ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1) * 1000) / - (fck / 1000 / 1000), - ticks, x4 ? " x4" : "", x16 ? " x16" : ""); + total_ticks = ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1); + + DSSDBG("HS_TX_TO %lu ticks (%#x%s%s) = %lu ns\n", + total_ticks, + ticks, x4 ? " x4" : "", x16 ? " x16" : "", + (total_ticks * 1000) / (fck / 1000 / 1000)); } static int dsi_proto_config(struct omap_dss_device *dssdev) { @@ -2487,10 +2412,10 @@ static int dsi_proto_config(struct omap_dss_device *dssdev) DSI_FIFO_SIZE_32); /* XXX what values for the timeouts? */ - dsi_set_stop_state_counter(1000); - dsi_set_ta_timeout(6400000); - dsi_set_lp_rx_timeout(48000); - dsi_set_hs_tx_timeout(1000000); + dsi_set_stop_state_counter(0x1000, false, false); + dsi_set_ta_timeout(0x1fff, true, true); + dsi_set_lp_rx_timeout(0x1fff, true, true); + dsi_set_hs_tx_timeout(0x1fff, true, true); switch (dssdev->ctrl.pixel_size) { case 16: @@ -2759,6 +2684,7 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev, unsigned packet_payload; unsigned packet_len; u32 l; + int r; const unsigned channel = dsi.update_channel; /* line buffer is 1024 x 24bits */ /* XXX: for some reason using full buffer size causes considerable TX @@ -2809,8 +2735,9 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev, dsi_perf_mark_start(); - schedule_delayed_work(&dsi.framedone_timeout_work, + r = queue_delayed_work(dsi.workqueue, &dsi.framedone_timeout_work, msecs_to_jiffies(250)); + BUG_ON(r == 0); dss_start_update(dssdev); @@ -2834,62 +2761,70 @@ static void dsi_te_timeout(unsigned long arg) } #endif -static void dsi_framedone_timeout_work_callback(struct work_struct *work) +static void dsi_handle_framedone(int error) { - int r; const int channel = dsi.update_channel; - DSSERR("Framedone not received for 250ms!\n"); + cancel_delayed_work(&dsi.framedone_timeout_work); + + dsi_vc_disable_bta_irq(channel); /* SIDLEMODE back to smart-idle */ dispc_enable_sidle(); + dsi.bta_callback = NULL; + if (dsi.te_enabled) { /* enable LP_RX_TO again after the TE */ REG_FLD_MOD(DSI_TIMING2, 1, 15, 15); /* LP_RX_TO */ } - /* Send BTA after the frame. We need this for the TE to work, as TE - * trigger is only sent for BTAs without preceding packet. Thus we need - * to BTA after the pixel packets so that next BTA will cause TE - * trigger. - * - * This is not needed when TE is not in use, but we do it anyway to - * make sure that the transfer has been completed. It would be more - * optimal, but more complex, to wait only just before starting next - * transfer. */ - r = dsi_vc_send_bta_sync(channel); - if (r) - DSSERR("BTA after framedone failed\n"); - /* RX_FIFO_NOT_EMPTY */ if (REG_GET(DSI_VC_CTRL(channel), 20, 20)) { DSSERR("Received error during frame transfer:\n"); dsi_vc_flush_receive_data(channel); + if (!error) + error = -EIO; } - dsi.framedone_callback(-ETIMEDOUT, dsi.framedone_data); + dsi.framedone_callback(error, dsi.framedone_data); + + if (!error) + dsi_perf_show("DISPC"); } -static void dsi_framedone_irq_callback(void *data, u32 mask) +static void dsi_framedone_timeout_work_callback(struct work_struct *work) { - /* Note: We get FRAMEDONE when DISPC has finished sending pixels and - * turns itself off. However, DSI still has the pixels in its buffers, - * and is sending the data. - */ + /* XXX While extremely unlikely, we could get FRAMEDONE interrupt after + * 250ms which would conflict with this timeout work. What should be + * done is first cancel the transfer on the HW, and then cancel the + * possibly scheduled framedone work. However, cancelling the transfer + * on the HW is buggy, and would probably require resetting the whole + * DSI */ - /* SIDLEMODE back to smart-idle */ - dispc_enable_sidle(); + DSSERR("Framedone not received for 250ms!\n"); - schedule_work(&dsi.framedone_work); + dsi_handle_framedone(-ETIMEDOUT); } -static void dsi_handle_framedone(void) +static void dsi_framedone_bta_callback(void) +{ + dsi_handle_framedone(0); + +#ifdef CONFIG_OMAP2_DSS_FAKE_VSYNC + dispc_fake_vsync_irq(); +#endif +} + +static void dsi_framedone_irq_callback(void *data, u32 mask) { - int r; const int channel = dsi.update_channel; + int r; - DSSDBG("FRAMEDONE\n"); + /* Note: We get FRAMEDONE when DISPC has finished sending pixels and + * turns itself off. However, DSI still has the pixels in its buffers, + * and is sending the data. + */ if (dsi.te_enabled) { /* enable LP_RX_TO again after the TE */ @@ -2904,37 +2839,30 @@ static void dsi_handle_framedone(void) * This is not needed when TE is not in use, but we do it anyway to * make sure that the transfer has been completed. It would be more * optimal, but more complex, to wait only just before starting next - * transfer. */ - r = dsi_vc_send_bta_sync(channel); - if (r) - DSSERR("BTA after framedone failed\n"); - - /* RX_FIFO_NOT_EMPTY */ - if (REG_GET(DSI_VC_CTRL(channel), 20, 20)) { - DSSERR("Received error during frame transfer:\n"); - dsi_vc_flush_receive_data(channel); - } - -#ifdef CONFIG_OMAP2_DSS_FAKE_VSYNC - dispc_fake_vsync_irq(); -#endif -} - -static void dsi_framedone_work_callback(struct work_struct *work) -{ - DSSDBGF(); + * transfer. + * + * Also, as there's no interrupt telling when the transfer has been + * done and the channel could be reconfigured, the only way is to + * busyloop until TE_SIZE is zero. With BTA we can do this + * asynchronously. + * */ - cancel_delayed_work_sync(&dsi.framedone_timeout_work); + dsi.bta_callback = dsi_framedone_bta_callback; - dsi_handle_framedone(); + barrier(); - dsi_perf_show("DISPC"); + dsi_vc_enable_bta_irq(channel); - dsi.framedone_callback(0, dsi.framedone_data); + r = dsi_vc_send_bta(channel); + if (r) { + DSSERR("BTA after framedone failed\n"); + dsi_handle_framedone(-EIO); + } } int omap_dsi_prepare_update(struct omap_dss_device *dssdev, - u16 *x, u16 *y, u16 *w, u16 *h) + u16 *x, u16 *y, u16 *w, u16 *h, + bool enlarge_update_area) { u16 dw, dh; @@ -2958,7 +2886,8 @@ int omap_dsi_prepare_update(struct omap_dss_device *dssdev, dsi_perf_mark_setup(); if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) { - dss_setup_partial_planes(dssdev, x, y, w, h); + dss_setup_partial_planes(dssdev, x, y, w, h, + enlarge_update_area); dispc_set_lcd_size(*w, *h); } @@ -2973,6 +2902,12 @@ int omap_dsi_update(struct omap_dss_device *dssdev, { dsi.update_channel = channel; + /* OMAP DSS cannot send updates of odd widths. + * omap_dsi_prepare_update() makes the widths even, but add a BUG_ON + * here to make sure we catch erroneous updates. Otherwise we'll only + * see rather obscure HW error happening, as DSS halts. */ + BUG_ON(x % 2 == 1); + if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) { dsi.framedone_callback = callback; dsi.framedone_data = data; @@ -2985,7 +2920,12 @@ int omap_dsi_update(struct omap_dss_device *dssdev, dsi_update_screen_dispc(dssdev, x, y, w, h); } else { - dsi_update_screen_l4(dssdev, x, y, w, h); + int r; + + r = dsi_update_screen_l4(dssdev, x, y, w, h); + if (r) + return r; + dsi_perf_show("L4"); callback(0, data); } @@ -3048,8 +2988,10 @@ static int dsi_configure_dsi_clocks(struct omap_dss_device *dssdev) cinfo.regm3 = dssdev->phy.dsi.div.regm3; cinfo.regm4 = dssdev->phy.dsi.div.regm4; r = dsi_calc_clock_rates(&cinfo); - if (r) + if (r) { + DSSERR("Failed to calc dsi clocks\n"); return r; + } r = dsi_pll_set_clock_div(&cinfo); if (r) { @@ -3147,6 +3089,13 @@ err0: static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev) { + /* disable interface */ + dsi_if_enable(0); + dsi_vc_enable(0, 0); + dsi_vc_enable(1, 0); + dsi_vc_enable(2, 0); + dsi_vc_enable(3, 0); + dss_select_dispc_clk_source(DSS_SRC_DSS1_ALWON_FCLK); dss_select_dsi_clk_source(DSS_SRC_DSS1_ALWON_FCLK); dsi_complexio_uninit(); @@ -3257,7 +3206,7 @@ void dsi_get_overlay_fifo_thresholds(enum omap_plane plane, burst_size_bytes = 16 * 32 / 8; *fifo_high = fifo_size - burst_size_bytes; - *fifo_low = fifo_size - burst_size_bytes * 8; + *fifo_low = fifo_size - burst_size_bytes * 2; } int dsi_init_display(struct omap_dss_device *dssdev) @@ -3274,6 +3223,18 @@ int dsi_init_display(struct omap_dss_device *dssdev) return 0; } +void dsi_wait_dsi1_pll_active(void) +{ + if (wait_for_bit_change(DSI_PLL_STATUS, 7, 1) != 1) + DSSERR("DSI1 PLL clock not active\n"); +} + +void dsi_wait_dsi2_pll_active(void) +{ + if (wait_for_bit_change(DSI_PLL_STATUS, 8, 1) != 1) + DSSERR("DSI2 PLL clock not active\n"); +} + int dsi_init(struct platform_device *pdev) { u32 rev; @@ -3292,7 +3253,10 @@ int dsi_init(struct platform_device *pdev) mutex_init(&dsi.lock); sema_init(&dsi.bus_lock, 1); - INIT_WORK(&dsi.framedone_work, dsi_framedone_work_callback); + dsi.workqueue = create_singlethread_workqueue("dsi"); + if (dsi.workqueue == NULL) + return -ENOMEM; + INIT_DELAYED_WORK_DEFERRABLE(&dsi.framedone_timeout_work, dsi_framedone_timeout_work_callback); @@ -3328,6 +3292,7 @@ int dsi_init(struct platform_device *pdev) err2: iounmap(dsi.base); err1: + destroy_workqueue(dsi.workqueue); return r; } @@ -3335,6 +3300,8 @@ void dsi_exit(void) { iounmap(dsi.base); + destroy_workqueue(dsi.workqueue); + DSSDBG("omap_dsi_exit\n"); } diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c index 54344184dd73..77c3621c9171 100644 --- a/drivers/video/omap2/dss/dss.c +++ b/drivers/video/omap2/dss/dss.c @@ -223,7 +223,13 @@ void dss_dump_clocks(struct seq_file *s) seq_printf(s, "dpll4_ck %lu\n", dpll4_ck_rate); - seq_printf(s, "dss1_alwon_fclk = %lu / %lu * 2 = %lu\n", + if (cpu_is_omap3630()) + seq_printf(s, "dss1_alwon_fclk = %lu / %lu = %lu\n", + dpll4_ck_rate, + dpll4_ck_rate / dpll4_m4_ck_rate, + dss_clk_get_rate(DSS_CLK_FCK1)); + else + seq_printf(s, "dss1_alwon_fclk = %lu / %lu * 2 = %lu\n", dpll4_ck_rate, dpll4_ck_rate / dpll4_m4_ck_rate, dss_clk_get_rate(DSS_CLK_FCK1)); @@ -259,6 +265,9 @@ void dss_select_dispc_clk_source(enum dss_clk_source clk_src) b = clk_src == DSS_SRC_DSS1_ALWON_FCLK ? 0 : 1; + if (clk_src == DSS_SRC_DSI1_PLL_FCLK) + dsi_wait_dsi1_pll_active(); + REG_FLD_MOD(DSS_CONTROL, b, 0, 0); /* DISPC_CLK_SWITCH */ dss.dispc_clk_source = clk_src; @@ -273,6 +282,9 @@ void dss_select_dsi_clk_source(enum dss_clk_source clk_src) b = clk_src == DSS_SRC_DSS1_ALWON_FCLK ? 0 : 1; + if (clk_src == DSS_SRC_DSI2_PLL_FCLK) + dsi_wait_dsi2_pll_active(); + REG_FLD_MOD(DSS_CONTROL, b, 1, 1); /* DSI_CLK_SWITCH */ dss.dsi_clk_source = clk_src; @@ -293,7 +305,8 @@ int dss_calc_clock_rates(struct dss_clock_info *cinfo) { unsigned long prate; - if (cinfo->fck_div > 16 || cinfo->fck_div == 0) + if (cinfo->fck_div > (cpu_is_omap3630() ? 32 : 16) || + cinfo->fck_div == 0) return -EINVAL; prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck)); @@ -329,7 +342,10 @@ int dss_get_clock_div(struct dss_clock_info *cinfo) if (cpu_is_omap34xx()) { unsigned long prate; prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck)); - cinfo->fck_div = prate / (cinfo->fck / 2); + if (cpu_is_omap3630()) + cinfo->fck_div = prate / (cinfo->fck); + else + cinfo->fck_div = prate / (cinfo->fck / 2); } else { cinfo->fck_div = 0; } @@ -402,10 +418,14 @@ retry: goto found; } else if (cpu_is_omap34xx()) { - for (fck_div = 16; fck_div > 0; --fck_div) { + for (fck_div = (cpu_is_omap3630() ? 32 : 16); + fck_div > 0; --fck_div) { struct dispc_clock_info cur_dispc; - fck = prate / fck_div * 2; + if (cpu_is_omap3630()) + fck = prate / fck_div; + else + fck = prate / fck_div * 2; if (fck > DISPC_MAX_FCK) continue; diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index 24326a5fd292..5c7940d5f282 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h @@ -199,7 +199,8 @@ int dss_init_overlay_managers(struct platform_device *pdev); void dss_uninit_overlay_managers(struct platform_device *pdev); int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl); void dss_setup_partial_planes(struct omap_dss_device *dssdev, - u16 *x, u16 *y, u16 *w, u16 *h); + u16 *x, u16 *y, u16 *w, u16 *h, + bool enlarge_update_area); void dss_start_update(struct omap_dss_device *dssdev); /* overlay */ @@ -242,11 +243,22 @@ int dss_calc_clock_div(bool is_tft, unsigned long req_pck, struct dispc_clock_info *dispc_cinfo); /* SDI */ +#ifdef CONFIG_OMAP2_DSS_SDI int sdi_init(bool skip_init); void sdi_exit(void); int sdi_init_display(struct omap_dss_device *display); +#else +static inline int sdi_init(bool skip_init) +{ + return 0; +} +static inline void sdi_exit(void) +{ +} +#endif /* DSI */ +#ifdef CONFIG_OMAP2_DSS_DSI int dsi_init(struct platform_device *pdev); void dsi_exit(void); @@ -270,11 +282,38 @@ void dsi_pll_uninit(void); void dsi_get_overlay_fifo_thresholds(enum omap_plane plane, u32 fifo_size, enum omap_burst_size *burst_size, u32 *fifo_low, u32 *fifo_high); +void dsi_wait_dsi1_pll_active(void); +void dsi_wait_dsi2_pll_active(void); +#else +static inline int dsi_init(struct platform_device *pdev) +{ + return 0; +} +static inline void dsi_exit(void) +{ +} +static inline void dsi_wait_dsi1_pll_active(void) +{ +} +static inline void dsi_wait_dsi2_pll_active(void) +{ +} +#endif /* DPI */ +#ifdef CONFIG_OMAP2_DSS_DPI int dpi_init(struct platform_device *pdev); void dpi_exit(void); int dpi_init_display(struct omap_dss_device *dssdev); +#else +static inline int dpi_init(struct platform_device *pdev) +{ + return 0; +} +static inline void dpi_exit(void) +{ +} +#endif /* DISPC */ int dispc_init(void); @@ -362,12 +401,23 @@ int dispc_get_clock_div(struct dispc_clock_info *cinfo); /* VENC */ +#ifdef CONFIG_OMAP2_DSS_VENC int venc_init(struct platform_device *pdev); void venc_exit(void); void venc_dump_regs(struct seq_file *s); int venc_init_display(struct omap_dss_device *display); +#else +static inline int venc_init(struct platform_device *pdev) +{ + return 0; +} +static inline void venc_exit(void) +{ +} +#endif /* RFBI */ +#ifdef CONFIG_OMAP2_DSS_RFBI int rfbi_init(void); void rfbi_exit(void); void rfbi_dump_regs(struct seq_file *s); @@ -379,6 +429,15 @@ void rfbi_transfer_area(u16 width, u16 height, void rfbi_set_timings(int rfbi_module, struct rfbi_timings *t); unsigned long rfbi_get_max_tx_rate(void); int rfbi_init_display(struct omap_dss_device *display); +#else +static inline int rfbi_init(void) +{ + return 0; +} +static inline void rfbi_exit(void) +{ +} +#endif #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS diff --git a/drivers/video/omap2/dss/manager.c b/drivers/video/omap2/dss/manager.c index 0820986d4a68..6a649ab5539e 100644 --- a/drivers/video/omap2/dss/manager.c +++ b/drivers/video/omap2/dss/manager.c @@ -440,6 +440,10 @@ struct manager_cache_data { /* manual update region */ u16 x, y, w, h; + + /* enlarge the update area if the update area contains scaled + * overlays */ + bool enlarge_update_area; }; static struct { @@ -525,7 +529,7 @@ static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr) int i; struct omap_dss_device *dssdev = mgr->device; - if (!dssdev) + if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) return 0; if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) { @@ -596,11 +600,14 @@ int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl) int r; int i; - if (!ovl->manager || !ovl->manager->device) + if (!ovl->manager) return 0; dssdev = ovl->manager->device; + if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) + return 0; + if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) { irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN; channel = OMAP_DSS_CHANNEL_DIGIT; @@ -718,6 +725,7 @@ static int configure_overlay(enum omap_plane plane) u16 x, y, w, h; u32 paddr; int r; + u16 orig_w, orig_h, orig_outw, orig_outh; DSSDBGF("%d", plane); @@ -738,8 +746,16 @@ static int configure_overlay(enum omap_plane plane) outh = c->out_height == 0 ? c->height : c->out_height; paddr = c->paddr; + orig_w = w; + orig_h = h; + orig_outw = outw; + orig_outh = outh; + if (c->manual_update && mc->do_manual_update) { unsigned bpp; + unsigned scale_x_m = w, scale_x_d = outw; + unsigned scale_y_m = h, scale_y_d = outh; + /* If the overlay is outside the update region, disable it */ if (!rectangle_intersects(mc->x, mc->y, mc->w, mc->h, x, y, outw, outh)) { @@ -770,38 +786,47 @@ static int configure_overlay(enum omap_plane plane) BUG(); } - if (dispc_is_overlay_scaled(c)) { - /* If the overlay is scaled, the update area has - * already been enlarged to cover the whole overlay. We - * only need to adjust x/y here */ - x = c->pos_x - mc->x; - y = c->pos_y - mc->y; + if (mc->x > c->pos_x) { + x = 0; + outw -= (mc->x - c->pos_x); + paddr += (mc->x - c->pos_x) * + scale_x_m / scale_x_d * bpp / 8; } else { - if (mc->x > c->pos_x) { - x = 0; - w -= (mc->x - c->pos_x); - paddr += (mc->x - c->pos_x) * bpp / 8; - } else { - x = c->pos_x - mc->x; - } - - if (mc->y > c->pos_y) { - y = 0; - h -= (mc->y - c->pos_y); - paddr += (mc->y - c->pos_y) * c->screen_width * - bpp / 8; - } else { - y = c->pos_y - mc->y; - } - - if (mc->w < (x+w)) - w -= (x+w) - (mc->w); + x = c->pos_x - mc->x; + } - if (mc->h < (y+h)) - h -= (y+h) - (mc->h); + if (mc->y > c->pos_y) { + y = 0; + outh -= (mc->y - c->pos_y); + paddr += (mc->y - c->pos_y) * + scale_y_m / scale_y_d * + c->screen_width * bpp / 8; + } else { + y = c->pos_y - mc->y; + } - outw = w; - outh = h; + if (mc->w < (x + outw)) + outw -= (x + outw) - (mc->w); + + if (mc->h < (y + outh)) + outh -= (y + outh) - (mc->h); + + w = w * outw / orig_outw; + h = h * outh / orig_outh; + + /* YUV mode overlay's input width has to be even and the + * algorithm above may adjust the width to be odd. + * + * Here we adjust the width if needed, preferring to increase + * the width if the original width was bigger. + */ + if ((w & 1) && + (c->color_mode == OMAP_DSS_COLOR_YUV2 || + c->color_mode == OMAP_DSS_COLOR_UYVY)) { + if (orig_w > w) + w += 1; + else + w -= 1; } } @@ -843,6 +868,7 @@ static void configure_manager(enum omap_channel channel) c = &dss_cache.manager_cache[channel]; + dispc_set_default_color(channel, c->default_color); dispc_set_trans_key(channel, c->trans_key_type, c->trans_key); dispc_enable_trans_key(channel, c->trans_enabled); dispc_enable_alpha_blending(channel, c->alpha_enabled); @@ -940,10 +966,26 @@ static int configure_dispc(void) return r; } +/* Make the coordinates even. There are some strange problems with OMAP and + * partial DSI update when the update widths are odd. */ +static void make_even(u16 *x, u16 *w) +{ + u16 x1, x2; + + x1 = *x; + x2 = *x + *w; + + x1 &= ~1; + x2 = ALIGN(x2, 2); + + *x = x1; + *w = x2 - x1; +} + /* Configure dispc for partial update. Return possibly modified update * area */ void dss_setup_partial_planes(struct omap_dss_device *dssdev, - u16 *xi, u16 *yi, u16 *wi, u16 *hi) + u16 *xi, u16 *yi, u16 *wi, u16 *hi, bool enlarge_update_area) { struct overlay_cache_data *oc; struct manager_cache_data *mc; @@ -952,6 +994,7 @@ void dss_setup_partial_planes(struct omap_dss_device *dssdev, int i; u16 x, y, w, h; unsigned long flags; + bool area_changed; x = *xi; y = *yi; @@ -968,73 +1011,95 @@ void dss_setup_partial_planes(struct omap_dss_device *dssdev, return; } + make_even(&x, &w); + spin_lock_irqsave(&dss_cache.lock, flags); - /* We need to show the whole overlay if it is scaled. So look for - * those, and make the update area larger if found. - * Also mark the overlay cache dirty */ - for (i = 0; i < num_ovls; ++i) { - unsigned x1, y1, x2, y2; - unsigned outw, outh; + /* + * Execute the outer loop until the inner loop has completed + * once without increasing the update area. This will ensure that + * all scaled overlays end up completely within the update area. + */ + do { + area_changed = false; - oc = &dss_cache.overlay_cache[i]; + /* We need to show the whole overlay if it is scaled. So look + * for those, and make the update area larger if found. + * Also mark the overlay cache dirty */ + for (i = 0; i < num_ovls; ++i) { + unsigned x1, y1, x2, y2; + unsigned outw, outh; - if (oc->channel != mgr->id) - continue; + oc = &dss_cache.overlay_cache[i]; - oc->dirty = true; + if (oc->channel != mgr->id) + continue; - if (!oc->enabled) - continue; + oc->dirty = true; - if (!dispc_is_overlay_scaled(oc)) - continue; + if (!enlarge_update_area) + continue; - outw = oc->out_width == 0 ? oc->width : oc->out_width; - outh = oc->out_height == 0 ? oc->height : oc->out_height; + if (!oc->enabled) + continue; - /* is the overlay outside the update region? */ - if (!rectangle_intersects(x, y, w, h, - oc->pos_x, oc->pos_y, - outw, outh)) - continue; + if (!dispc_is_overlay_scaled(oc)) + continue; - /* if the overlay totally inside the update region? */ - if (rectangle_subset(oc->pos_x, oc->pos_y, outw, outh, - x, y, w, h)) - continue; + outw = oc->out_width == 0 ? + oc->width : oc->out_width; + outh = oc->out_height == 0 ? + oc->height : oc->out_height; + + /* is the overlay outside the update region? */ + if (!rectangle_intersects(x, y, w, h, + oc->pos_x, oc->pos_y, + outw, outh)) + continue; - if (x > oc->pos_x) - x1 = oc->pos_x; - else - x1 = x; + /* if the overlay totally inside the update region? */ + if (rectangle_subset(oc->pos_x, oc->pos_y, outw, outh, + x, y, w, h)) + continue; - if (y > oc->pos_y) - y1 = oc->pos_y; - else - y1 = y; + if (x > oc->pos_x) + x1 = oc->pos_x; + else + x1 = x; - if ((x + w) < (oc->pos_x + outw)) - x2 = oc->pos_x + outw; - else - x2 = x + w; + if (y > oc->pos_y) + y1 = oc->pos_y; + else + y1 = y; - if ((y + h) < (oc->pos_y + outh)) - y2 = oc->pos_y + outh; - else - y2 = y + h; + if ((x + w) < (oc->pos_x + outw)) + x2 = oc->pos_x + outw; + else + x2 = x + w; - x = x1; - y = y1; - w = x2 - x1; - h = y2 - y1; + if ((y + h) < (oc->pos_y + outh)) + y2 = oc->pos_y + outh; + else + y2 = y + h; - DSSDBG("changing upd area due to ovl(%d) scaling %d,%d %dx%d\n", + x = x1; + y = y1; + w = x2 - x1; + h = y2 - y1; + + make_even(&x, &w); + + DSSDBG("changing upd area due to ovl(%d) " + "scaling %d,%d %dx%d\n", i, x, y, w, h); - } + + area_changed = true; + } + } while (area_changed); mc = &dss_cache.manager_cache[mgr->id]; mc->do_manual_update = true; + mc->enlarge_update_area = enlarge_update_area; mc->x = x; mc->y = y; mc->w = w; diff --git a/drivers/video/omap2/dss/overlay.c b/drivers/video/omap2/dss/overlay.c index 82336583adef..244dca81a399 100644 --- a/drivers/video/omap2/dss/overlay.c +++ b/drivers/video/omap2/dss/overlay.c @@ -65,7 +65,7 @@ static ssize_t overlay_manager_store(struct omap_overlay *ovl, const char *buf, for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) { mgr = omap_dss_get_overlay_manager(i); - if (strncmp(buf, mgr->name, len) == 0) + if (sysfs_streq(buf, mgr->name)) break; mgr = NULL; diff --git a/drivers/video/omap2/dss/rfbi.c b/drivers/video/omap2/dss/rfbi.c index cc23f53cc62d..bbe62464e92d 100644 --- a/drivers/video/omap2/dss/rfbi.c +++ b/drivers/video/omap2/dss/rfbi.c @@ -886,7 +886,7 @@ int omap_rfbi_prepare_update(struct omap_dss_device *dssdev, return -EINVAL; if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) { - dss_setup_partial_planes(dssdev, x, y, w, h); + dss_setup_partial_planes(dssdev, x, y, w, h, true); dispc_set_lcd_size(*w, *h); } diff --git a/drivers/video/omap2/dss/sdi.c b/drivers/video/omap2/dss/sdi.c index 12eb4042dd82..ee07a3cc22ef 100644 --- a/drivers/video/omap2/dss/sdi.c +++ b/drivers/video/omap2/dss/sdi.c @@ -23,13 +23,16 @@ #include <linux/clk.h> #include <linux/delay.h> #include <linux/err.h> +#include <linux/regulator/consumer.h> #include <plat/display.h> +#include <plat/cpu.h> #include "dss.h" static struct { bool skip_init; bool update_enabled; + struct regulator *vdds_sdi_reg; } sdi; static void sdi_basic_init(void) @@ -57,6 +60,10 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev) goto err0; } + r = regulator_enable(sdi.vdds_sdi_reg); + if (r) + goto err1; + /* In case of skip_init sdi_init has already enabled the clocks */ if (!sdi.skip_init) dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1); @@ -115,19 +122,12 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev) dssdev->manager->enable(dssdev->manager); - if (dssdev->driver->enable) { - r = dssdev->driver->enable(dssdev); - if (r) - goto err3; - } - sdi.skip_init = 0; return 0; -err3: - dssdev->manager->disable(dssdev->manager); err2: dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1); + regulator_disable(sdi.vdds_sdi_reg); err1: omap_dss_stop_device(dssdev); err0: @@ -137,15 +137,14 @@ EXPORT_SYMBOL(omapdss_sdi_display_enable); void omapdss_sdi_display_disable(struct omap_dss_device *dssdev) { - if (dssdev->driver->disable) - dssdev->driver->disable(dssdev); - dssdev->manager->disable(dssdev->manager); dss_sdi_disable(); dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1); + regulator_disable(sdi.vdds_sdi_reg); + omap_dss_stop_device(dssdev); } EXPORT_SYMBOL(omapdss_sdi_display_disable); @@ -162,6 +161,11 @@ int sdi_init(bool skip_init) /* we store this for first display enable, then clear it */ sdi.skip_init = skip_init; + sdi.vdds_sdi_reg = dss_get_vdds_sdi(); + if (IS_ERR(sdi.vdds_sdi_reg)) { + DSSERR("can't get VDDS_SDI regulator\n"); + return PTR_ERR(sdi.vdds_sdi_reg); + } /* * Enable clocks already here, otherwise there would be a toggle * of them until sdi_display_enable is called. diff --git a/drivers/video/omap2/dss/venc.c b/drivers/video/omap2/dss/venc.c index f0ba5732d84a..eff35050e28a 100644 --- a/drivers/video/omap2/dss/venc.c +++ b/drivers/video/omap2/dss/venc.c @@ -479,12 +479,6 @@ static int venc_panel_enable(struct omap_dss_device *dssdev) goto err1; } - if (dssdev->platform_enable) { - r = dssdev->platform_enable(dssdev); - if (r) - goto err2; - } - venc_power_on(dssdev); venc.wss_data = 0; @@ -494,13 +488,9 @@ static int venc_panel_enable(struct omap_dss_device *dssdev) /* wait couple of vsyncs until enabling the LCD */ msleep(50); - mutex_unlock(&venc.venc_lock); - - return r; -err2: - venc_power_off(dssdev); err1: mutex_unlock(&venc.venc_lock); + return r; } @@ -524,9 +514,6 @@ static void venc_panel_disable(struct omap_dss_device *dssdev) /* wait at least 5 vsyncs after disabling the LCD */ msleep(100); - if (dssdev->platform_disable) - dssdev->platform_disable(dssdev); - dssdev->state = OMAP_DSS_DISPLAY_DISABLED; end: mutex_unlock(&venc.venc_lock); diff --git a/drivers/video/omap2/omapfb/omapfb-ioctl.c b/drivers/video/omap2/omapfb/omapfb-ioctl.c index 1ffa760b8545..6f435450987e 100644 --- a/drivers/video/omap2/omapfb/omapfb-ioctl.c +++ b/drivers/video/omap2/omapfb/omapfb-ioctl.c @@ -34,12 +34,37 @@ #include "omapfb.h" +static u8 get_mem_idx(struct omapfb_info *ofbi) +{ + if (ofbi->id == ofbi->region->id) + return 0; + + return OMAPFB_MEM_IDX_ENABLED | ofbi->region->id; +} + +static struct omapfb2_mem_region *get_mem_region(struct omapfb_info *ofbi, + u8 mem_idx) +{ + struct omapfb2_device *fbdev = ofbi->fbdev; + + if (mem_idx & OMAPFB_MEM_IDX_ENABLED) + mem_idx &= OMAPFB_MEM_IDX_MASK; + else + mem_idx = ofbi->id; + + if (mem_idx >= fbdev->num_fbs) + return NULL; + + return &fbdev->regions[mem_idx]; +} + static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) { struct omapfb_info *ofbi = FB2OFB(fbi); struct omapfb2_device *fbdev = ofbi->fbdev; struct omap_overlay *ovl; - struct omap_overlay_info info; + struct omap_overlay_info old_info; + struct omapfb2_mem_region *old_rg, *new_rg; int r = 0; DBG("omapfb_setup_plane\n"); @@ -52,36 +77,106 @@ static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) /* XXX uses only the first overlay */ ovl = ofbi->overlays[0]; - if (pi->enabled && !ofbi->region.size) { + old_rg = ofbi->region; + new_rg = get_mem_region(ofbi, pi->mem_idx); + if (!new_rg) { + r = -EINVAL; + goto out; + } + + /* Take the locks in a specific order to keep lockdep happy */ + if (old_rg->id < new_rg->id) { + omapfb_get_mem_region(old_rg); + omapfb_get_mem_region(new_rg); + } else if (new_rg->id < old_rg->id) { + omapfb_get_mem_region(new_rg); + omapfb_get_mem_region(old_rg); + } else + omapfb_get_mem_region(old_rg); + + if (pi->enabled && !new_rg->size) { /* * This plane's memory was freed, can't enable it * until it's reallocated. */ r = -EINVAL; - goto out; + goto put_mem; } - ovl->get_overlay_info(ovl, &info); + ovl->get_overlay_info(ovl, &old_info); - info.pos_x = pi->pos_x; - info.pos_y = pi->pos_y; - info.out_width = pi->out_width; - info.out_height = pi->out_height; - info.enabled = pi->enabled; + if (old_rg != new_rg) { + ofbi->region = new_rg; + set_fb_fix(fbi); + } - r = ovl->set_overlay_info(ovl, &info); - if (r) - goto out; + if (pi->enabled) { + struct omap_overlay_info info; - if (ovl->manager) { - r = ovl->manager->apply(ovl->manager); + r = omapfb_setup_overlay(fbi, ovl, pi->pos_x, pi->pos_y, + pi->out_width, pi->out_height); if (r) - goto out; + goto undo; + + ovl->get_overlay_info(ovl, &info); + + if (!info.enabled) { + info.enabled = pi->enabled; + r = ovl->set_overlay_info(ovl, &info); + if (r) + goto undo; + } + } else { + struct omap_overlay_info info; + + ovl->get_overlay_info(ovl, &info); + + info.enabled = pi->enabled; + info.pos_x = pi->pos_x; + info.pos_y = pi->pos_y; + info.out_width = pi->out_width; + info.out_height = pi->out_height; + + r = ovl->set_overlay_info(ovl, &info); + if (r) + goto undo; } -out: - if (r) - dev_err(fbdev->dev, "setup_plane failed\n"); + if (ovl->manager) + ovl->manager->apply(ovl->manager); + + /* Release the locks in a specific order to keep lockdep happy */ + if (old_rg->id > new_rg->id) { + omapfb_put_mem_region(old_rg); + omapfb_put_mem_region(new_rg); + } else if (new_rg->id > old_rg->id) { + omapfb_put_mem_region(new_rg); + omapfb_put_mem_region(old_rg); + } else + omapfb_put_mem_region(old_rg); + + return 0; + + undo: + if (old_rg != new_rg) { + ofbi->region = old_rg; + set_fb_fix(fbi); + } + + ovl->set_overlay_info(ovl, &old_info); + put_mem: + /* Release the locks in a specific order to keep lockdep happy */ + if (old_rg->id > new_rg->id) { + omapfb_put_mem_region(old_rg); + omapfb_put_mem_region(new_rg); + } else if (new_rg->id > old_rg->id) { + omapfb_put_mem_region(new_rg); + omapfb_put_mem_region(old_rg); + } else + omapfb_put_mem_region(old_rg); + out: + dev_err(fbdev->dev, "setup_plane failed\n"); + return r; } @@ -92,8 +187,8 @@ static int omapfb_query_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) if (ofbi->num_overlays != 1) { memset(pi, 0, sizeof(*pi)); } else { - struct omap_overlay_info *ovli; struct omap_overlay *ovl; + struct omap_overlay_info *ovli; ovl = ofbi->overlays[0]; ovli = &ovl->info; @@ -103,6 +198,7 @@ static int omapfb_query_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) pi->enabled = ovli->enabled; pi->channel_out = 0; /* xxx */ pi->mirror = 0; + pi->mem_idx = get_mem_idx(ofbi); pi->out_width = ovli->out_width; pi->out_height = ovli->out_height; } @@ -115,7 +211,7 @@ static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi) struct omapfb_info *ofbi = FB2OFB(fbi); struct omapfb2_device *fbdev = ofbi->fbdev; struct omapfb2_mem_region *rg; - int r, i; + int r = 0, i; size_t size; if (mi->type > OMAPFB_MEMTYPE_MAX) @@ -123,22 +219,44 @@ static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi) size = PAGE_ALIGN(mi->size); - rg = &ofbi->region; + rg = ofbi->region; - for (i = 0; i < ofbi->num_overlays; i++) { - if (ofbi->overlays[i]->info.enabled) - return -EBUSY; + down_write_nested(&rg->lock, rg->id); + atomic_inc(&rg->lock_count); + + if (atomic_read(&rg->map_count)) { + r = -EBUSY; + goto out; + } + + for (i = 0; i < fbdev->num_fbs; i++) { + struct omapfb_info *ofbi2 = FB2OFB(fbdev->fbs[i]); + int j; + + if (ofbi2->region != rg) + continue; + + for (j = 0; j < ofbi2->num_overlays; j++) { + if (ofbi2->overlays[j]->info.enabled) { + r = -EBUSY; + goto out; + } + } } if (rg->size != size || rg->type != mi->type) { r = omapfb_realloc_fbmem(fbi, size, mi->type); if (r) { dev_err(fbdev->dev, "realloc fbmem failed\n"); - return r; + goto out; } } - return 0; + out: + atomic_dec(&rg->lock_count); + up_write(&rg->lock); + + return r; } static int omapfb_query_mem(struct fb_info *fbi, struct omapfb_mem_info *mi) @@ -146,12 +264,14 @@ static int omapfb_query_mem(struct fb_info *fbi, struct omapfb_mem_info *mi) struct omapfb_info *ofbi = FB2OFB(fbi); struct omapfb2_mem_region *rg; - rg = &ofbi->region; + rg = omapfb_get_mem_region(ofbi->region); memset(mi, 0, sizeof(*mi)); mi->size = rg->size; mi->type = rg->type; + omapfb_put_mem_region(rg); + return 0; } @@ -183,13 +303,14 @@ int omapfb_update_window(struct fb_info *fbi, struct omapfb2_device *fbdev = ofbi->fbdev; int r; + if (!lock_fb_info(fbi)) + return -ENODEV; omapfb_lock(fbdev); - lock_fb_info(fbi); r = omapfb_update_window_nolock(fbi, x, y, w, h); - unlock_fb_info(fbi); omapfb_unlock(fbdev); + unlock_fb_info(fbi); return r; } @@ -489,6 +610,7 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg) struct omapfb_vram_info vram_info; struct omapfb_tearsync_info tearsync_info; struct omapfb_display_info display_info; + u32 crt; } p; int r = 0; @@ -647,6 +769,17 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg) r = -EFAULT; break; + case FBIO_WAITFORVSYNC: + if (get_user(p.crt, (__u32 __user *)arg)) { + r = -EFAULT; + break; + } + if (p.crt != 0) { + r = -ENODEV; + break; + } + /* FALLTHROUGH */ + case OMAPFB_WAITFORVSYNC: DBG("ioctl WAITFORVSYNC\n"); if (!display) { @@ -737,7 +870,7 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg) break; } - if (!display->driver->enable_te) { + if (!display || !display->driver->enable_te) { r = -ENODEV; break; } diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c index 4b4506da96da..04034d410d6d 100644 --- a/drivers/video/omap2/omapfb/omapfb-main.c +++ b/drivers/video/omap2/omapfb/omapfb-main.c @@ -157,7 +157,7 @@ static void fill_fb(struct fb_info *fbi) static unsigned omapfb_get_vrfb_offset(const struct omapfb_info *ofbi, int rot) { - const struct vrfb *vrfb = &ofbi->region.vrfb; + const struct vrfb *vrfb = &ofbi->region->vrfb; unsigned offset; switch (rot) { @@ -185,27 +185,27 @@ static unsigned omapfb_get_vrfb_offset(const struct omapfb_info *ofbi, int rot) static u32 omapfb_get_region_rot_paddr(const struct omapfb_info *ofbi, int rot) { if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) { - return ofbi->region.vrfb.paddr[rot] + return ofbi->region->vrfb.paddr[rot] + omapfb_get_vrfb_offset(ofbi, rot); } else { - return ofbi->region.paddr; + return ofbi->region->paddr; } } static u32 omapfb_get_region_paddr(const struct omapfb_info *ofbi) { if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) - return ofbi->region.vrfb.paddr[0]; + return ofbi->region->vrfb.paddr[0]; else - return ofbi->region.paddr; + return ofbi->region->paddr; } static void __iomem *omapfb_get_region_vaddr(const struct omapfb_info *ofbi) { if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) - return ofbi->region.vrfb.vaddr[0]; + return ofbi->region->vrfb.vaddr[0]; else - return ofbi->region.vaddr; + return ofbi->region->vaddr; } static struct omapfb_colormode omapfb_colormodes[] = { @@ -450,7 +450,7 @@ static int check_vrfb_fb_size(unsigned long region_size, static int check_fb_size(const struct omapfb_info *ofbi, struct fb_var_screeninfo *var) { - unsigned long max_frame_size = ofbi->region.size; + unsigned long max_frame_size = ofbi->region->size; int bytespp = var->bits_per_pixel >> 3; unsigned long line_size = var->xres_virtual * bytespp; @@ -497,7 +497,7 @@ static int check_fb_size(const struct omapfb_info *ofbi, static int setup_vrfb_rotation(struct fb_info *fbi) { struct omapfb_info *ofbi = FB2OFB(fbi); - struct omapfb2_mem_region *rg = &ofbi->region; + struct omapfb2_mem_region *rg = ofbi->region; struct vrfb *vrfb = &rg->vrfb; struct fb_var_screeninfo *var = &fbi->var; struct fb_fix_screeninfo *fix = &fbi->fix; @@ -558,9 +558,9 @@ static int setup_vrfb_rotation(struct fb_info *fbi) return r; /* used by open/write in fbmem.c */ - fbi->screen_base = ofbi->region.vrfb.vaddr[0]; + fbi->screen_base = ofbi->region->vrfb.vaddr[0]; - fix->smem_start = ofbi->region.vrfb.paddr[0]; + fix->smem_start = ofbi->region->vrfb.paddr[0]; switch (var->nonstd) { case OMAPFB_COLOR_YUV422: @@ -599,7 +599,7 @@ void set_fb_fix(struct fb_info *fbi) struct fb_fix_screeninfo *fix = &fbi->fix; struct fb_var_screeninfo *var = &fbi->var; struct omapfb_info *ofbi = FB2OFB(fbi); - struct omapfb2_mem_region *rg = &ofbi->region; + struct omapfb2_mem_region *rg = ofbi->region; DBG("set_fb_fix\n"); @@ -668,8 +668,7 @@ int check_fb_var(struct fb_info *fbi, struct fb_var_screeninfo *var) DBG("check_fb_var %d\n", ofbi->id); - if (ofbi->region.size == 0) - return 0; + WARN_ON(!atomic_read(&ofbi->region->lock_count)); r = fb_mode_to_dss_mode(var, &mode); if (r) { @@ -684,13 +683,14 @@ int check_fb_var(struct fb_info *fbi, struct fb_var_screeninfo *var) } } - if (var->rotate < 0 || var->rotate > 3) + if (var->rotate > 3) return -EINVAL; if (check_fb_res_bounds(var)) return -EINVAL; - if (check_fb_size(ofbi, var)) + /* When no memory is allocated ignore the size check */ + if (ofbi->region->size != 0 && check_fb_size(ofbi, var)) return -EINVAL; if (var->xres + var->xoffset > var->xres_virtual) @@ -822,9 +822,43 @@ static unsigned calc_rotation_offset_vrfb(const struct fb_var_screeninfo *var, return offset; } +static void omapfb_calc_addr(const struct omapfb_info *ofbi, + const struct fb_var_screeninfo *var, + const struct fb_fix_screeninfo *fix, + int rotation, u32 *paddr, void __iomem **vaddr) +{ + u32 data_start_p; + void __iomem *data_start_v; + int offset; + + if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) { + data_start_p = omapfb_get_region_rot_paddr(ofbi, rotation); + data_start_v = NULL; + } else { + data_start_p = omapfb_get_region_paddr(ofbi); + data_start_v = omapfb_get_region_vaddr(ofbi); + } + + if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) + offset = calc_rotation_offset_vrfb(var, fix, rotation); + else + offset = calc_rotation_offset_dma(var, fix, rotation); + + data_start_p += offset; + data_start_v += offset; + + if (offset) + DBG("offset %d, %d = %d\n", + var->xoffset, var->yoffset, offset); + + DBG("paddr %x, vaddr %p\n", data_start_p, data_start_v); + + *paddr = data_start_p; + *vaddr = data_start_v; +} /* setup overlay according to the fb */ -static int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl, +int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl, u16 posx, u16 posy, u16 outw, u16 outh) { int r = 0; @@ -832,9 +866,8 @@ static int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl, struct fb_var_screeninfo *var = &fbi->var; struct fb_fix_screeninfo *fix = &fbi->fix; enum omap_color_mode mode = 0; - int offset; - u32 data_start_p; - void __iomem *data_start_v; + u32 data_start_p = 0; + void __iomem *data_start_v = NULL; struct omap_overlay_info info; int xres, yres; int screen_width; @@ -842,6 +875,8 @@ static int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl, int rotation = var->rotate; int i; + WARN_ON(!atomic_read(&ofbi->region->lock_count)); + for (i = 0; i < ofbi->num_overlays; i++) { if (ovl != ofbi->overlays[i]) continue; @@ -861,28 +896,9 @@ static int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl, yres = var->yres; } - - if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) { - data_start_p = omapfb_get_region_rot_paddr(ofbi, rotation); - data_start_v = NULL; - } else { - data_start_p = omapfb_get_region_paddr(ofbi); - data_start_v = omapfb_get_region_vaddr(ofbi); - } - - if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) - offset = calc_rotation_offset_vrfb(var, fix, rotation); - else - offset = calc_rotation_offset_dma(var, fix, rotation); - - data_start_p += offset; - data_start_v += offset; - - if (offset) - DBG("offset %d, %d = %d\n", - var->xoffset, var->yoffset, offset); - - DBG("paddr %x, vaddr %p\n", data_start_p, data_start_v); + if (ofbi->region->size) + omapfb_calc_addr(ofbi, var, fix, rotation, + &data_start_p, &data_start_v); r = fb_mode_to_dss_mode(var, &mode); if (r) { @@ -954,12 +970,14 @@ int omapfb_apply_changes(struct fb_info *fbi, int init) fill_fb(fbi); #endif + WARN_ON(!atomic_read(&ofbi->region->lock_count)); + for (i = 0; i < ofbi->num_overlays; i++) { ovl = ofbi->overlays[i]; DBG("apply_changes, fb %d, ovl %d\n", ofbi->id, ovl->id); - if (ofbi->region.size == 0) { + if (ofbi->region->size == 0) { /* the fb is not available. disable the overlay */ omapfb_overlay_enable(ovl, 0); if (!init && ovl->manager) @@ -1007,36 +1025,48 @@ err: * DO NOT MODIFY PAR */ static int omapfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fbi) { + struct omapfb_info *ofbi = FB2OFB(fbi); int r; DBG("check_var(%d)\n", FB2OFB(fbi)->id); + omapfb_get_mem_region(ofbi->region); + r = check_fb_var(fbi, var); + omapfb_put_mem_region(ofbi->region); + return r; } /* set the video mode according to info->var */ static int omapfb_set_par(struct fb_info *fbi) { + struct omapfb_info *ofbi = FB2OFB(fbi); int r; DBG("set_par(%d)\n", FB2OFB(fbi)->id); + omapfb_get_mem_region(ofbi->region); + set_fb_fix(fbi); r = setup_vrfb_rotation(fbi); if (r) - return r; + goto out; r = omapfb_apply_changes(fbi, 0); + out: + omapfb_put_mem_region(ofbi->region); + return r; } static int omapfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *fbi) { + struct omapfb_info *ofbi = FB2OFB(fbi); struct fb_var_screeninfo new_var; int r; @@ -1052,23 +1082,31 @@ static int omapfb_pan_display(struct fb_var_screeninfo *var, fbi->var = new_var; + omapfb_get_mem_region(ofbi->region); + r = omapfb_apply_changes(fbi, 0); + omapfb_put_mem_region(ofbi->region); + return r; } static void mmap_user_open(struct vm_area_struct *vma) { - struct omapfb_info *ofbi = (struct omapfb_info *)vma->vm_private_data; + struct omapfb2_mem_region *rg = vma->vm_private_data; - atomic_inc(&ofbi->map_count); + omapfb_get_mem_region(rg); + atomic_inc(&rg->map_count); + omapfb_put_mem_region(rg); } static void mmap_user_close(struct vm_area_struct *vma) { - struct omapfb_info *ofbi = (struct omapfb_info *)vma->vm_private_data; + struct omapfb2_mem_region *rg = vma->vm_private_data; - atomic_dec(&ofbi->map_count); + omapfb_get_mem_region(rg); + atomic_dec(&rg->map_count); + omapfb_put_mem_region(rg); } static struct vm_operations_struct mmap_user_ops = { @@ -1080,9 +1118,11 @@ static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma) { struct omapfb_info *ofbi = FB2OFB(fbi); struct fb_fix_screeninfo *fix = &fbi->fix; + struct omapfb2_mem_region *rg; unsigned long off; unsigned long start; u32 len; + int r = -EINVAL; if (vma->vm_end - vma->vm_start == 0) return 0; @@ -1090,12 +1130,14 @@ static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma) return -EINVAL; off = vma->vm_pgoff << PAGE_SHIFT; + rg = omapfb_get_mem_region(ofbi->region); + start = omapfb_get_region_paddr(ofbi); len = fix->smem_len; if (off >= len) - return -EINVAL; + goto error; if ((vma->vm_end - vma->vm_start + off) > len) - return -EINVAL; + goto error; off += start; @@ -1105,13 +1147,25 @@ static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma) vma->vm_flags |= VM_IO | VM_RESERVED; vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); vma->vm_ops = &mmap_user_ops; - vma->vm_private_data = ofbi; + vma->vm_private_data = rg; if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT, - vma->vm_end - vma->vm_start, vma->vm_page_prot)) - return -EAGAIN; + vma->vm_end - vma->vm_start, + vma->vm_page_prot)) { + r = -EAGAIN; + goto error; + } + /* vm_ops.open won't be called for mmap itself. */ - atomic_inc(&ofbi->map_count); + atomic_inc(&rg->map_count); + + omapfb_put_mem_region(rg); + return 0; + + error: + omapfb_put_mem_region(ofbi->region); + + return r; } /* Store a single color palette entry into a pseudo palette or the hardware @@ -1154,11 +1208,6 @@ static int _setcolreg(struct fb_info *fbi, u_int regno, u_int red, u_int green, if (r != 0) break; - if (regno < 0) { - r = -EINVAL; - break; - } - if (regno < 16) { u16 pal; pal = ((red >> (16 - var->red.length)) << @@ -1217,6 +1266,9 @@ static int omapfb_blank(int blank, struct fb_info *fbi) int do_update = 0; int r = 0; + if (!display) + return -EINVAL; + omapfb_lock(fbdev); switch (blank) { @@ -1300,7 +1352,9 @@ static void omapfb_free_fbmem(struct fb_info *fbi) struct omapfb2_device *fbdev = ofbi->fbdev; struct omapfb2_mem_region *rg; - rg = &ofbi->region; + rg = ofbi->region; + + WARN_ON(atomic_read(&rg->map_count)); if (rg->paddr) if (omap_vram_free(rg->paddr, rg->size)) @@ -1355,8 +1409,15 @@ static int omapfb_alloc_fbmem(struct fb_info *fbi, unsigned long size, void __iomem *vaddr; int r; - rg = &ofbi->region; - memset(rg, 0, sizeof(*rg)); + rg = ofbi->region; + + rg->paddr = 0; + rg->vaddr = NULL; + memset(&rg->vrfb, 0, sizeof rg->vrfb); + rg->size = 0; + rg->type = 0; + rg->alloc = false; + rg->map = false; size = PAGE_ALIGN(size); @@ -1609,7 +1670,7 @@ static int omapfb_allocate_all_fbs(struct omapfb2_device *fbdev) for (i = 0; i < fbdev->num_fbs; i++) { struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]); struct omapfb2_mem_region *rg; - rg = &ofbi->region; + rg = ofbi->region; DBG("region%d phys %08x virt %p size=%lu\n", i, @@ -1626,7 +1687,7 @@ int omapfb_realloc_fbmem(struct fb_info *fbi, unsigned long size, int type) struct omapfb_info *ofbi = FB2OFB(fbi); struct omapfb2_device *fbdev = ofbi->fbdev; struct omap_dss_device *display = fb2display(fbi); - struct omapfb2_mem_region *rg = &ofbi->region; + struct omapfb2_mem_region *rg = ofbi->region; unsigned long old_size = rg->size; unsigned long old_paddr = rg->paddr; int old_type = rg->type; @@ -1709,7 +1770,7 @@ static int omapfb_fb_init(struct omapfb2_device *fbdev, struct fb_info *fbi) fbi->flags = FBINFO_FLAG_DEFAULT; fbi->pseudo_palette = fbdev->pseudo_palette; - if (ofbi->region.size == 0) { + if (ofbi->region->size == 0) { clear_fb_info(fbi); return 0; } @@ -1871,6 +1932,10 @@ static int omapfb_create_framebuffers(struct omapfb2_device *fbdev) ofbi->fbdev = fbdev; ofbi->id = i; + ofbi->region = &fbdev->regions[i]; + ofbi->region->id = i; + init_rwsem(&ofbi->region->lock); + /* assign these early, so that fb alloc can use them */ ofbi->rotation_type = def_vrfb ? OMAP_DSS_ROT_VRFB : OMAP_DSS_ROT_DMA; @@ -1900,7 +1965,13 @@ static int omapfb_create_framebuffers(struct omapfb2_device *fbdev) /* setup fb_infos */ for (i = 0; i < fbdev->num_fbs; i++) { - r = omapfb_fb_init(fbdev, fbdev->fbs[i]); + struct fb_info *fbi = fbdev->fbs[i]; + struct omapfb_info *ofbi = FB2OFB(fbi); + + omapfb_get_mem_region(ofbi->region); + r = omapfb_fb_init(fbdev, fbi); + omapfb_put_mem_region(ofbi->region); + if (r) { dev_err(fbdev->dev, "failed to setup fb_info\n"); return r; @@ -1921,20 +1992,19 @@ static int omapfb_create_framebuffers(struct omapfb2_device *fbdev) DBG("framebuffers registered\n"); for (i = 0; i < fbdev->num_fbs; i++) { - r = omapfb_apply_changes(fbdev->fbs[i], 1); + struct fb_info *fbi = fbdev->fbs[i]; + struct omapfb_info *ofbi = FB2OFB(fbi); + + omapfb_get_mem_region(ofbi->region); + r = omapfb_apply_changes(fbi, 1); + omapfb_put_mem_region(ofbi->region); + if (r) { dev_err(fbdev->dev, "failed to change mode\n"); return r; } } - DBG("create sysfs for fbs\n"); - r = omapfb_create_sysfs(fbdev); - if (r) { - dev_err(fbdev->dev, "failed to create sysfs entries\n"); - return r; - } - /* Enable fb0 */ if (fbdev->num_fbs > 0) { struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[0]); @@ -1968,11 +2038,11 @@ static int omapfb_mode_to_timings(const char *mode_str, #ifdef CONFIG_OMAP2_DSS_VENC if (strcmp(mode_str, "pal") == 0) { *timings = omap_dss_pal_timings; - *bpp = 0; + *bpp = 24; return 0; } else if (strcmp(mode_str, "ntsc") == 0) { *timings = omap_dss_ntsc_timings; - *bpp = 0; + *bpp = 24; return 0; } #endif @@ -2220,6 +2290,13 @@ static int omapfb_probe(struct platform_device *pdev) } } + DBG("create sysfs for fbs\n"); + r = omapfb_create_sysfs(fbdev); + if (r) { + dev_err(fbdev->dev, "failed to create sysfs entries\n"); + goto cleanup; + } + return 0; cleanup: diff --git a/drivers/video/omap2/omapfb/omapfb-sysfs.c b/drivers/video/omap2/omapfb/omapfb-sysfs.c index 62bb88f5c192..6f9c72cd6bb0 100644 --- a/drivers/video/omap2/omapfb/omapfb-sysfs.c +++ b/drivers/video/omap2/omapfb/omapfb-sysfs.c @@ -49,6 +49,7 @@ static ssize_t store_rotate_type(struct device *dev, { struct fb_info *fbi = dev_get_drvdata(dev); struct omapfb_info *ofbi = FB2OFB(fbi); + struct omapfb2_mem_region *rg; enum omap_dss_rotation_type rot_type; int r; @@ -57,15 +58,18 @@ static ssize_t store_rotate_type(struct device *dev, if (rot_type != OMAP_DSS_ROT_DMA && rot_type != OMAP_DSS_ROT_VRFB) return -EINVAL; - lock_fb_info(fbi); + if (!lock_fb_info(fbi)) + return -ENODEV; r = 0; if (rot_type == ofbi->rotation_type) goto out; - if (ofbi->region.size) { + rg = omapfb_get_mem_region(ofbi->region); + + if (rg->size) { r = -EBUSY; - goto out; + goto put_region; } ofbi->rotation_type = rot_type; @@ -74,6 +78,8 @@ static ssize_t store_rotate_type(struct device *dev, * Since the VRAM for this FB is not allocated at the moment we don't * need to do any further parameter checking at this point. */ +put_region: + omapfb_put_mem_region(rg); out: unlock_fb_info(fbi); @@ -96,7 +102,7 @@ static ssize_t store_mirror(struct device *dev, { struct fb_info *fbi = dev_get_drvdata(dev); struct omapfb_info *ofbi = FB2OFB(fbi); - bool mirror; + unsigned long mirror; int r; struct fb_var_screeninfo new_var; @@ -105,10 +111,13 @@ static ssize_t store_mirror(struct device *dev, if (mirror != 0 && mirror != 1) return -EINVAL; - lock_fb_info(fbi); + if (!lock_fb_info(fbi)) + return -ENODEV; ofbi->mirror = mirror; + omapfb_get_mem_region(ofbi->region); + memcpy(&new_var, &fbi->var, sizeof(new_var)); r = check_fb_var(fbi, &new_var); if (r) @@ -123,6 +132,8 @@ static ssize_t store_mirror(struct device *dev, r = count; out: + omapfb_put_mem_region(ofbi->region); + unlock_fb_info(fbi); return r; @@ -137,8 +148,9 @@ static ssize_t show_overlays(struct device *dev, ssize_t l = 0; int t; + if (!lock_fb_info(fbi)) + return -ENODEV; omapfb_lock(fbdev); - lock_fb_info(fbi); for (t = 0; t < ofbi->num_overlays; t++) { struct omap_overlay *ovl = ofbi->overlays[t]; @@ -154,8 +166,8 @@ static ssize_t show_overlays(struct device *dev, l += snprintf(buf + l, PAGE_SIZE - l, "\n"); - unlock_fb_info(fbi); omapfb_unlock(fbdev); + unlock_fb_info(fbi); return l; } @@ -195,8 +207,9 @@ static ssize_t store_overlays(struct device *dev, struct device_attribute *attr, if (buf[len - 1] == '\n') len = len - 1; + if (!lock_fb_info(fbi)) + return -ENODEV; omapfb_lock(fbdev); - lock_fb_info(fbi); if (len > 0) { char *p = (char *)buf; @@ -259,11 +272,15 @@ static ssize_t store_overlays(struct device *dev, struct device_attribute *attr, DBG("detaching %d\n", ofbi->overlays[i]->id); + omapfb_get_mem_region(ofbi->region); + omapfb_overlay_enable(ovl, 0); if (ovl->manager) ovl->manager->apply(ovl->manager); + omapfb_put_mem_region(ofbi->region); + for (t = i + 1; t < ofbi->num_overlays; t++) { ofbi->rotation[t-1] = ofbi->rotation[t]; ofbi->overlays[t-1] = ofbi->overlays[t]; @@ -296,15 +313,20 @@ static ssize_t store_overlays(struct device *dev, struct device_attribute *attr, } if (added) { + omapfb_get_mem_region(ofbi->region); + r = omapfb_apply_changes(fbi, 0); + + omapfb_put_mem_region(ofbi->region); + if (r) goto out; } r = count; out: - unlock_fb_info(fbi); omapfb_unlock(fbdev); + unlock_fb_info(fbi); return r; } @@ -317,7 +339,8 @@ static ssize_t show_overlays_rotate(struct device *dev, ssize_t l = 0; int t; - lock_fb_info(fbi); + if (!lock_fb_info(fbi)) + return -ENODEV; for (t = 0; t < ofbi->num_overlays; t++) { l += snprintf(buf + l, PAGE_SIZE - l, "%s%d", @@ -345,7 +368,8 @@ static ssize_t store_overlays_rotate(struct device *dev, if (buf[len - 1] == '\n') len = len - 1; - lock_fb_info(fbi); + if (!lock_fb_info(fbi)) + return -ENODEV; if (len > 0) { char *p = (char *)buf; @@ -382,7 +406,12 @@ static ssize_t store_overlays_rotate(struct device *dev, for (i = 0; i < num_ovls; ++i) ofbi->rotation[i] = rotation[i]; + omapfb_get_mem_region(ofbi->region); + r = omapfb_apply_changes(fbi, 0); + + omapfb_put_mem_region(ofbi->region); + if (r) goto out; @@ -402,7 +431,7 @@ static ssize_t show_size(struct device *dev, struct fb_info *fbi = dev_get_drvdata(dev); struct omapfb_info *ofbi = FB2OFB(fbi); - return snprintf(buf, PAGE_SIZE, "%lu\n", ofbi->region.size); + return snprintf(buf, PAGE_SIZE, "%lu\n", ofbi->region->size); } static ssize_t store_size(struct device *dev, struct device_attribute *attr, @@ -410,23 +439,44 @@ static ssize_t store_size(struct device *dev, struct device_attribute *attr, { struct fb_info *fbi = dev_get_drvdata(dev); struct omapfb_info *ofbi = FB2OFB(fbi); + struct omapfb2_device *fbdev = ofbi->fbdev; + struct omapfb2_mem_region *rg; unsigned long size; int r; int i; size = PAGE_ALIGN(simple_strtoul(buf, NULL, 0)); - lock_fb_info(fbi); + if (!lock_fb_info(fbi)) + return -ENODEV; - for (i = 0; i < ofbi->num_overlays; i++) { - if (ofbi->overlays[i]->info.enabled) { - r = -EBUSY; - goto out; + rg = ofbi->region; + + down_write_nested(&rg->lock, rg->id); + atomic_inc(&rg->lock_count); + + if (atomic_read(&rg->map_count)) { + r = -EBUSY; + goto out; + } + + for (i = 0; i < fbdev->num_fbs; i++) { + struct omapfb_info *ofbi2 = FB2OFB(fbdev->fbs[i]); + int j; + + if (ofbi2->region != rg) + continue; + + for (j = 0; j < ofbi2->num_overlays; j++) { + if (ofbi2->overlays[j]->info.enabled) { + r = -EBUSY; + goto out; + } } } - if (size != ofbi->region.size) { - r = omapfb_realloc_fbmem(fbi, size, ofbi->region.type); + if (size != ofbi->region->size) { + r = omapfb_realloc_fbmem(fbi, size, ofbi->region->type); if (r) { dev_err(dev, "realloc fbmem failed\n"); goto out; @@ -435,6 +485,9 @@ static ssize_t store_size(struct device *dev, struct device_attribute *attr, r = count; out: + atomic_dec(&rg->lock_count); + up_write(&rg->lock); + unlock_fb_info(fbi); return r; @@ -446,7 +499,7 @@ static ssize_t show_phys(struct device *dev, struct fb_info *fbi = dev_get_drvdata(dev); struct omapfb_info *ofbi = FB2OFB(fbi); - return snprintf(buf, PAGE_SIZE, "%0x\n", ofbi->region.paddr); + return snprintf(buf, PAGE_SIZE, "%0x\n", ofbi->region->paddr); } static ssize_t show_virt(struct device *dev, @@ -455,7 +508,7 @@ static ssize_t show_virt(struct device *dev, struct fb_info *fbi = dev_get_drvdata(dev); struct omapfb_info *ofbi = FB2OFB(fbi); - return snprintf(buf, PAGE_SIZE, "%p\n", ofbi->region.vaddr); + return snprintf(buf, PAGE_SIZE, "%p\n", ofbi->region->vaddr); } static struct device_attribute omapfb_attrs[] = { diff --git a/drivers/video/omap2/omapfb/omapfb.h b/drivers/video/omap2/omapfb/omapfb.h index cd54fdbfd8bb..1305fc9880ba 100644 --- a/drivers/video/omap2/omapfb/omapfb.h +++ b/drivers/video/omap2/omapfb/omapfb.h @@ -27,6 +27,8 @@ #define DEBUG #endif +#include <linux/rwsem.h> + #include <plat/display.h> #ifdef DEBUG @@ -44,6 +46,7 @@ extern unsigned int omapfb_debug; #define OMAPFB_MAX_OVL_PER_FB 3 struct omapfb2_mem_region { + int id; u32 paddr; void __iomem *vaddr; struct vrfb vrfb; @@ -51,13 +54,15 @@ struct omapfb2_mem_region { u8 type; /* OMAPFB_PLANE_MEM_* */ bool alloc; /* allocated by the driver */ bool map; /* kernel mapped by the driver */ + atomic_t map_count; + struct rw_semaphore lock; + atomic_t lock_count; }; /* appended to fb_info */ struct omapfb_info { int id; - struct omapfb2_mem_region region; - atomic_t map_count; + struct omapfb2_mem_region *region; int num_overlays; struct omap_overlay *overlays[OMAPFB_MAX_OVL_PER_FB]; struct omapfb2_device *fbdev; @@ -76,6 +81,7 @@ struct omapfb2_device { unsigned num_fbs; struct fb_info *fbs[10]; + struct omapfb2_mem_region regions[10]; unsigned num_displays; struct omap_dss_device *displays[10]; @@ -117,6 +123,9 @@ int omapfb_update_window(struct fb_info *fbi, int dss_mode_to_fb_mode(enum omap_color_mode dssmode, struct fb_var_screeninfo *var); +int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl, + u16 posx, u16 posy, u16 outw, u16 outh); + /* find the display connected to this fb, if any */ static inline struct omap_dss_device *fb2display(struct fb_info *fbi) { @@ -148,8 +157,24 @@ static inline int omapfb_overlay_enable(struct omap_overlay *ovl, struct omap_overlay_info info; ovl->get_overlay_info(ovl, &info); + if (info.enabled == enable) + return 0; info.enabled = enable; return ovl->set_overlay_info(ovl, &info); } +static inline struct omapfb2_mem_region * +omapfb_get_mem_region(struct omapfb2_mem_region *rg) +{ + down_read_nested(&rg->lock, rg->id); + atomic_inc(&rg->lock_count); + return rg; +} + +static inline void omapfb_put_mem_region(struct omapfb2_mem_region *rg) +{ + atomic_dec(&rg->lock_count); + up_read(&rg->lock); +} + #endif diff --git a/drivers/video/omap2/vram.c b/drivers/video/omap2/vram.c index 3b1237ad85ed..f6fdc2085f3e 100644 --- a/drivers/video/omap2/vram.c +++ b/drivers/video/omap2/vram.c @@ -25,7 +25,7 @@ #include <linux/list.h> #include <linux/slab.h> #include <linux/seq_file.h> -#include <linux/bootmem.h> +#include <linux/memblock.h> #include <linux/completion.h> #include <linux/debugfs.h> #include <linux/jiffies.h> @@ -525,10 +525,8 @@ early_param("vram", omap_vram_early_vram); * Called from map_io. We need to call to this early enough so that we * can reserve the fixed SDRAM regions before VM could get hold of them. */ -void __init omap_vram_reserve_sdram(void) +void __init omap_vram_reserve_sdram_memblock(void) { - struct bootmem_data *bdata; - unsigned long sdram_start, sdram_size; u32 paddr; u32 size = 0; @@ -555,29 +553,28 @@ void __init omap_vram_reserve_sdram(void) size = PAGE_ALIGN(size); - bdata = NODE_DATA(0)->bdata; - sdram_start = bdata->node_min_pfn << PAGE_SHIFT; - sdram_size = (bdata->node_low_pfn << PAGE_SHIFT) - sdram_start; - if (paddr) { - if ((paddr & ~PAGE_MASK) || paddr < sdram_start || - paddr + size > sdram_start + sdram_size) { + struct memblock_property res; + + res.base = paddr; + res.size = size; + if ((paddr & ~PAGE_MASK) || memblock_find(&res) || + res.base != paddr || res.size != size) { pr_err("Illegal SDRAM region for VRAM\n"); return; } - if (reserve_bootmem(paddr, size, BOOTMEM_EXCLUSIVE) < 0) { - pr_err("FB: failed to reserve VRAM\n"); + if (memblock_is_region_reserved(paddr, size)) { + pr_err("FB: failed to reserve VRAM - busy\n"); return; } - } else { - if (size > sdram_size) { - pr_err("Illegal SDRAM size for VRAM\n"); + + if (memblock_reserve(paddr, size) < 0) { + pr_err("FB: failed to reserve VRAM - no memory\n"); return; } - - paddr = virt_to_phys(alloc_bootmem_pages(size)); - BUG_ON(paddr & ~PAGE_MASK); + } else { + paddr = memblock_alloc_base(size, PAGE_SIZE, MEMBLOCK_REAL_LIMIT); } omap_vram_add_region(paddr, size); diff --git a/drivers/video/p9100.c b/drivers/video/p9100.c index 81440f2b9091..688b055abab2 100644 --- a/drivers/video/p9100.c +++ b/drivers/video/p9100.c @@ -251,7 +251,7 @@ static void p9100_init_fix(struct fb_info *info, int linebytes, struct device_no static int __devinit p9100_probe(struct of_device *op, const struct of_device_id *match) { - struct device_node *dp = op->node; + struct device_node *dp = op->dev.of_node; struct fb_info *info; struct p9100_par *par; int linebytes, err; @@ -353,8 +353,11 @@ static const struct of_device_id p9100_match[] = { MODULE_DEVICE_TABLE(of, p9100_match); static struct of_platform_driver p9100_driver = { - .name = "p9100", - .match_table = p9100_match, + .driver = { + .name = "p9100", + .owner = THIS_MODULE, + .of_match_table = p9100_match, + }, .probe = p9100_probe, .remove = __devexit_p(p9100_remove), }; @@ -364,12 +367,12 @@ static int __init p9100_init(void) if (fb_get_options("p9100fb", NULL)) return -ENODEV; - return of_register_driver(&p9100_driver, &of_bus_type); + return of_register_platform_driver(&p9100_driver); } static void __exit p9100_exit(void) { - of_unregister_driver(&p9100_driver); + of_unregister_platform_driver(&p9100_driver); } module_init(p9100_init); diff --git a/drivers/video/platinumfb.c b/drivers/video/platinumfb.c index 8a204e7a5b5b..72a1f4c04732 100644 --- a/drivers/video/platinumfb.c +++ b/drivers/video/platinumfb.c @@ -536,7 +536,7 @@ static int __init platinumfb_setup(char *options) static int __devinit platinumfb_probe(struct of_device* odev, const struct of_device_id *match) { - struct device_node *dp = odev->node; + struct device_node *dp = odev->dev.of_node; struct fb_info *info; struct fb_info_platinum *pinfo; volatile __u8 *fbuffer; @@ -679,8 +679,11 @@ static struct of_device_id platinumfb_match[] = static struct of_platform_driver platinum_driver = { - .name = "platinumfb", - .match_table = platinumfb_match, + .driver = { + .name = "platinumfb", + .owner = THIS_MODULE, + .of_match_table = platinumfb_match, + }, .probe = platinumfb_probe, .remove = platinumfb_remove, }; diff --git a/drivers/video/pmag-ba-fb.c b/drivers/video/pmag-ba-fb.c index 0f361b6100d2..0c69fa20251b 100644 --- a/drivers/video/pmag-ba-fb.c +++ b/drivers/video/pmag-ba-fb.c @@ -44,7 +44,7 @@ struct pmagbafb_par { }; -static struct fb_var_screeninfo pmagbafb_defined __initdata = { +static struct fb_var_screeninfo pmagbafb_defined __devinitdata = { .xres = 1024, .yres = 864, .xres_virtual = 1024, @@ -68,7 +68,7 @@ static struct fb_var_screeninfo pmagbafb_defined __initdata = { .vmode = FB_VMODE_NONINTERLACED, }; -static struct fb_fix_screeninfo pmagbafb_fix __initdata = { +static struct fb_fix_screeninfo pmagbafb_fix __devinitdata = { .id = "PMAG-BA", .smem_len = (1024 * 1024), .type = FB_TYPE_PACKED_PIXELS, @@ -142,7 +142,7 @@ static void __init pmagbafb_erase_cursor(struct fb_info *info) } -static int __init pmagbafb_probe(struct device *dev) +static int __devinit pmagbafb_probe(struct device *dev) { struct tc_dev *tdev = to_tc_dev(dev); resource_size_t start, len; diff --git a/drivers/video/pmagb-b-fb.c b/drivers/video/pmagb-b-fb.c index 2de0806421b4..22fcb9a3d5c0 100644 --- a/drivers/video/pmagb-b-fb.c +++ b/drivers/video/pmagb-b-fb.c @@ -45,7 +45,7 @@ struct pmagbbfb_par { }; -static struct fb_var_screeninfo pmagbbfb_defined __initdata = { +static struct fb_var_screeninfo pmagbbfb_defined __devinitdata = { .bits_per_pixel = 8, .red.length = 8, .green.length = 8, @@ -58,7 +58,7 @@ static struct fb_var_screeninfo pmagbbfb_defined __initdata = { .vmode = FB_VMODE_NONINTERLACED, }; -static struct fb_fix_screeninfo pmagbbfb_fix __initdata = { +static struct fb_fix_screeninfo pmagbbfb_fix __devinitdata = { .id = "PMAGB-BA", .smem_len = (2048 * 1024), .type = FB_TYPE_PACKED_PIXELS, @@ -148,7 +148,7 @@ static void __init pmagbbfb_erase_cursor(struct fb_info *info) /* * Set up screen parameters. */ -static void __init pmagbbfb_screen_setup(struct fb_info *info) +static void __devinit pmagbbfb_screen_setup(struct fb_info *info) { struct pmagbbfb_par *par = info->par; @@ -180,9 +180,9 @@ static void __init pmagbbfb_screen_setup(struct fb_info *info) /* * Determine oscillator configuration. */ -static void __init pmagbbfb_osc_setup(struct fb_info *info) +static void __devinit pmagbbfb_osc_setup(struct fb_info *info) { - static unsigned int pmagbbfb_freqs[] __initdata = { + static unsigned int pmagbbfb_freqs[] __devinitdata = { 130808, 119843, 104000, 92980, 74370, 72800, 69197, 66000, 65000, 50350, 36000, 32000, 25175 }; @@ -247,7 +247,7 @@ static void __init pmagbbfb_osc_setup(struct fb_info *info) }; -static int __init pmagbbfb_probe(struct device *dev) +static int __devinit pmagbbfb_probe(struct device *dev) { struct tc_dev *tdev = to_tc_dev(dev); resource_size_t start, len; diff --git a/drivers/video/s3c2410fb.c b/drivers/video/s3c2410fb.c index 2b094dec4a56..46b430978bcc 100644 --- a/drivers/video/s3c2410fb.c +++ b/drivers/video/s3c2410fb.c @@ -631,7 +631,7 @@ static struct fb_ops s3c2410fb_ops = { * cache. Once this area is remapped, all virtual memory * access to the video memory should occur at the new region. */ -static int __init s3c2410fb_map_video_memory(struct fb_info *info) +static int __devinit s3c2410fb_map_video_memory(struct fb_info *info) { struct s3c2410fb_info *fbi = info->par; dma_addr_t map_dma; @@ -814,7 +814,7 @@ static inline void s3c2410fb_cpufreq_deregister(struct s3c2410fb_info *info) static char driver_name[] = "s3c2410fb"; -static int __init s3c24xxfb_probe(struct platform_device *pdev, +static int __devinit s3c24xxfb_probe(struct platform_device *pdev, enum s3c_drv_type drv_type) { struct s3c2410fb_info *info; @@ -1018,7 +1018,7 @@ static int __devinit s3c2412fb_probe(struct platform_device *pdev) /* * Cleanup */ -static int s3c2410fb_remove(struct platform_device *pdev) +static int __devexit s3c2410fb_remove(struct platform_device *pdev) { struct fb_info *fbinfo = platform_get_drvdata(pdev); struct s3c2410fb_info *info = fbinfo->par; @@ -1096,7 +1096,7 @@ static int s3c2410fb_resume(struct platform_device *dev) static struct platform_driver s3c2410fb_driver = { .probe = s3c2410fb_probe, - .remove = s3c2410fb_remove, + .remove = __devexit_p(s3c2410fb_remove), .suspend = s3c2410fb_suspend, .resume = s3c2410fb_resume, .driver = { @@ -1107,7 +1107,7 @@ static struct platform_driver s3c2410fb_driver = { static struct platform_driver s3c2412fb_driver = { .probe = s3c2412fb_probe, - .remove = s3c2410fb_remove, + .remove = __devexit_p(s3c2410fb_remove), .suspend = s3c2410fb_suspend, .resume = s3c2410fb_resume, .driver = { diff --git a/drivers/video/s3fb.c b/drivers/video/s3fb.c index d4471b4c0374..dce8c97b4333 100644 --- a/drivers/video/s3fb.c +++ b/drivers/video/s3fb.c @@ -71,7 +71,8 @@ static const char * const s3_names[] = {"S3 Unknown", "S3 Trio32", "S3 Trio64", "S3 Trio64UV+", "S3 Trio64V2/DX", "S3 Trio64V2/GX", "S3 Plato/PX", "S3 Aurora64VP", "S3 Virge", "S3 Virge/VX", "S3 Virge/DX", "S3 Virge/GX", - "S3 Virge/GX2", "S3 Virge/GX2P", "S3 Virge/GX2P"}; + "S3 Virge/GX2", "S3 Virge/GX2P", "S3 Virge/GX2P", + "S3 Trio3D/1X", "S3 Trio3D/2X", "S3 Trio3D/2X"}; #define CHIP_UNKNOWN 0x00 #define CHIP_732_TRIO32 0x01 @@ -89,10 +90,14 @@ static const char * const s3_names[] = {"S3 Unknown", "S3 Trio32", "S3 Trio64", #define CHIP_356_VIRGE_GX2 0x0D #define CHIP_357_VIRGE_GX2P 0x0E #define CHIP_359_VIRGE_GX2P 0x0F +#define CHIP_360_TRIO3D_1X 0x10 +#define CHIP_362_TRIO3D_2X 0x11 +#define CHIP_368_TRIO3D_2X 0x12 #define CHIP_XXX_TRIO 0x80 #define CHIP_XXX_TRIO64V2_DXGX 0x81 #define CHIP_XXX_VIRGE_DXGX 0x82 +#define CHIP_36X_TRIO3D_1X_2X 0x83 #define CHIP_UNDECIDED_FLAG 0x80 #define CHIP_MASK 0xFF @@ -324,6 +329,7 @@ static void s3fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) static void s3_set_pixclock(struct fb_info *info, u32 pixclock) { + struct s3fb_info *par = info->par; u16 m, n, r; u8 regval; int rv; @@ -339,7 +345,13 @@ static void s3_set_pixclock(struct fb_info *info, u32 pixclock) vga_w(NULL, VGA_MIS_W, regval | VGA_MIS_ENB_PLL_LOAD); /* Set S3 clock registers */ - vga_wseq(NULL, 0x12, ((n - 2) | (r << 5))); + if (par->chip == CHIP_360_TRIO3D_1X || + par->chip == CHIP_362_TRIO3D_2X || + par->chip == CHIP_368_TRIO3D_2X) { + vga_wseq(NULL, 0x12, (n - 2) | ((r & 3) << 6)); /* n and two bits of r */ + vga_wseq(NULL, 0x29, r >> 2); /* remaining highest bit of r */ + } else + vga_wseq(NULL, 0x12, (n - 2) | (r << 5)); vga_wseq(NULL, 0x13, m - 2); udelay(1000); @@ -456,7 +468,7 @@ static int s3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) static int s3fb_set_par(struct fb_info *info) { struct s3fb_info *par = info->par; - u32 value, mode, hmul, offset_value, screen_size, multiplex; + u32 value, mode, hmul, offset_value, screen_size, multiplex, dbytes; u32 bpp = info->var.bits_per_pixel; if (bpp != 0) { @@ -518,7 +530,7 @@ static int s3fb_set_par(struct fb_info *info) svga_wcrt_mask(0x33, 0x00, 0x08); /* no DDR ? */ svga_wcrt_mask(0x43, 0x00, 0x01); /* no DDR ? */ - svga_wcrt_mask(0x5D, 0x00, 0x28); // Clear strange HSlen bits + svga_wcrt_mask(0x5D, 0x00, 0x28); /* Clear strange HSlen bits */ /* svga_wcrt_mask(0x58, 0x03, 0x03); */ @@ -530,10 +542,14 @@ static int s3fb_set_par(struct fb_info *info) pr_debug("fb%d: offset register : %d\n", info->node, offset_value); svga_wcrt_multi(s3_offset_regs, offset_value); - vga_wcrt(NULL, 0x54, 0x18); /* M parameter */ - vga_wcrt(NULL, 0x60, 0xff); /* N parameter */ - vga_wcrt(NULL, 0x61, 0xff); /* L parameter */ - vga_wcrt(NULL, 0x62, 0xff); /* L parameter */ + if (par->chip != CHIP_360_TRIO3D_1X && + par->chip != CHIP_362_TRIO3D_2X && + par->chip != CHIP_368_TRIO3D_2X) { + vga_wcrt(NULL, 0x54, 0x18); /* M parameter */ + vga_wcrt(NULL, 0x60, 0xff); /* N parameter */ + vga_wcrt(NULL, 0x61, 0xff); /* L parameter */ + vga_wcrt(NULL, 0x62, 0xff); /* L parameter */ + } vga_wcrt(NULL, 0x3A, 0x35); svga_wattr(0x33, 0x00); @@ -570,6 +586,16 @@ static int s3fb_set_par(struct fb_info *info) vga_wcrt(NULL, 0x66, 0x90); } + if (par->chip == CHIP_360_TRIO3D_1X || + par->chip == CHIP_362_TRIO3D_2X || + par->chip == CHIP_368_TRIO3D_2X) { + dbytes = info->var.xres * ((bpp+7)/8); + vga_wcrt(NULL, 0x91, (dbytes + 7) / 8); + vga_wcrt(NULL, 0x90, (((dbytes + 7) / 8) >> 8) | 0x80); + + vga_wcrt(NULL, 0x66, 0x81); + } + svga_wcrt_mask(0x31, 0x00, 0x40); multiplex = 0; hmul = 1; @@ -615,11 +641,13 @@ static int s3fb_set_par(struct fb_info *info) break; case 3: pr_debug("fb%d: 8 bit pseudocolor\n", info->node); - if (info->var.pixclock > 20000) { - svga_wcrt_mask(0x50, 0x00, 0x30); + svga_wcrt_mask(0x50, 0x00, 0x30); + if (info->var.pixclock > 20000 || + par->chip == CHIP_360_TRIO3D_1X || + par->chip == CHIP_362_TRIO3D_2X || + par->chip == CHIP_368_TRIO3D_2X) svga_wcrt_mask(0x67, 0x00, 0xF0); - } else { - svga_wcrt_mask(0x50, 0x00, 0x30); + else { svga_wcrt_mask(0x67, 0x10, 0xF0); multiplex = 1; } @@ -634,7 +662,10 @@ static int s3fb_set_par(struct fb_info *info) } else { svga_wcrt_mask(0x50, 0x10, 0x30); svga_wcrt_mask(0x67, 0x30, 0xF0); - hmul = 2; + if (par->chip != CHIP_360_TRIO3D_1X && + par->chip != CHIP_362_TRIO3D_2X && + par->chip != CHIP_368_TRIO3D_2X) + hmul = 2; } break; case 5: @@ -647,7 +678,10 @@ static int s3fb_set_par(struct fb_info *info) } else { svga_wcrt_mask(0x50, 0x10, 0x30); svga_wcrt_mask(0x67, 0x50, 0xF0); - hmul = 2; + if (par->chip != CHIP_360_TRIO3D_1X && + par->chip != CHIP_362_TRIO3D_2X && + par->chip != CHIP_368_TRIO3D_2X) + hmul = 2; } break; case 6: @@ -866,6 +900,17 @@ static int __devinit s3_identification(int chip) return CHIP_385_VIRGE_GX; } + if (chip == CHIP_36X_TRIO3D_1X_2X) { + switch (vga_rcrt(NULL, 0x2f)) { + case 0x00: + return CHIP_360_TRIO3D_1X; + case 0x01: + return CHIP_362_TRIO3D_2X; + case 0x02: + return CHIP_368_TRIO3D_2X; + } + } + return CHIP_UNKNOWN; } @@ -930,17 +975,32 @@ static int __devinit s3_pci_probe(struct pci_dev *dev, const struct pci_device_i vga_wcrt(NULL, 0x38, 0x48); vga_wcrt(NULL, 0x39, 0xA5); - /* Find how many physical memory there is on card */ - /* 0x36 register is accessible even if other registers are locked */ - regval = vga_rcrt(NULL, 0x36); - info->screen_size = s3_memsizes[regval >> 5] << 10; - info->fix.smem_len = info->screen_size; - + /* Identify chip type */ par->chip = id->driver_data & CHIP_MASK; par->rev = vga_rcrt(NULL, 0x2f); if (par->chip & CHIP_UNDECIDED_FLAG) par->chip = s3_identification(par->chip); + /* Find how many physical memory there is on card */ + /* 0x36 register is accessible even if other registers are locked */ + regval = vga_rcrt(NULL, 0x36); + if (par->chip == CHIP_360_TRIO3D_1X || + par->chip == CHIP_362_TRIO3D_2X || + par->chip == CHIP_368_TRIO3D_2X) { + switch ((regval & 0xE0) >> 5) { + case 0: /* 8MB -- only 4MB usable for display */ + case 1: /* 4MB with 32-bit bus */ + case 2: /* 4MB */ + info->screen_size = 4 << 20; + break; + case 6: /* 2MB */ + info->screen_size = 2 << 20; + break; + } + } else + info->screen_size = s3_memsizes[regval >> 5] << 10; + info->fix.smem_len = info->screen_size; + /* Find MCLK frequency */ regval = vga_rseq(NULL, 0x10); par->mclk_freq = ((vga_rseq(NULL, 0x11) + 2) * 14318) / ((regval & 0x1F) + 2); @@ -1131,6 +1191,7 @@ static struct pci_device_id s3_devices[] __devinitdata = { {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8A10), .driver_data = CHIP_356_VIRGE_GX2}, {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8A11), .driver_data = CHIP_357_VIRGE_GX2P}, {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8A12), .driver_data = CHIP_359_VIRGE_GX2P}, + {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8A13), .driver_data = CHIP_36X_TRIO3D_1X_2X}, {0, 0, 0, 0, 0, 0, 0} }; diff --git a/drivers/video/sgivwfb.c b/drivers/video/sgivwfb.c index 7a3a5e28eca1..53455f295510 100644 --- a/drivers/video/sgivwfb.c +++ b/drivers/video/sgivwfb.c @@ -47,7 +47,7 @@ static int ywrap = 0; static int flatpanel_id = -1; -static struct fb_fix_screeninfo sgivwfb_fix __initdata = { +static struct fb_fix_screeninfo sgivwfb_fix __devinitdata = { .id = "SGI Vis WS FB", .type = FB_TYPE_PACKED_PIXELS, .visual = FB_VISUAL_PSEUDOCOLOR, @@ -57,7 +57,7 @@ static struct fb_fix_screeninfo sgivwfb_fix __initdata = { .line_length = 640, }; -static struct fb_var_screeninfo sgivwfb_var __initdata = { +static struct fb_var_screeninfo sgivwfb_var __devinitdata = { /* 640x480, 8 bpp */ .xres = 640, .yres = 480, @@ -79,7 +79,7 @@ static struct fb_var_screeninfo sgivwfb_var __initdata = { .vmode = FB_VMODE_NONINTERLACED }; -static struct fb_var_screeninfo sgivwfb_var1600sw __initdata = { +static struct fb_var_screeninfo sgivwfb_var1600sw __devinitdata = { /* 1600x1024, 8 bpp */ .xres = 1600, .yres = 1024, @@ -825,7 +825,7 @@ fail_ioremap_regs: return -ENXIO; } -static int sgivwfb_remove(struct platform_device *dev) +static int __devexit sgivwfb_remove(struct platform_device *dev) { struct fb_info *info = platform_get_drvdata(dev); @@ -845,7 +845,7 @@ static int sgivwfb_remove(struct platform_device *dev) static struct platform_driver sgivwfb_driver = { .probe = sgivwfb_probe, - .remove = sgivwfb_remove, + .remove = __devexit_p(sgivwfb_remove), .driver = { .name = "sgivwfb", }, diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c index e8c769944812..12c451a711e9 100644 --- a/drivers/video/sh_mobile_lcdcfb.c +++ b/drivers/video/sh_mobile_lcdcfb.c @@ -991,13 +991,13 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) priv->ch[j].lcdc = priv; memcpy(&priv->ch[j].cfg, &pdata->ch[i], sizeof(pdata->ch[i])); - error = sh_mobile_lcdc_check_interface(&priv->ch[i]); + error = sh_mobile_lcdc_check_interface(&priv->ch[j]); if (error) { dev_err(&pdev->dev, "unsupported interface type\n"); goto err1; } - init_waitqueue_head(&priv->ch[i].frame_end_wait); - init_completion(&priv->ch[i].vsync_completion); + init_waitqueue_head(&priv->ch[j].frame_end_wait); + init_completion(&priv->ch[j].vsync_completion); priv->ch[j].pan_offset = 0; switch (pdata->ch[i].chan) { diff --git a/drivers/video/sis/sis_main.c b/drivers/video/sis/sis_main.c index a531a0f7cdf2..559bf1727a2b 100644 --- a/drivers/video/sis/sis_main.c +++ b/drivers/video/sis/sis_main.c @@ -1845,7 +1845,7 @@ sisfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info) memset(fix, 0, sizeof(struct fb_fix_screeninfo)); - strcpy(fix->id, ivideo->myid); + strlcpy(fix->id, ivideo->myid, sizeof(fix->id)); mutex_lock(&info->mm_lock); fix->smem_start = ivideo->video_base + ivideo->video_offset; diff --git a/drivers/video/sunxvr1000.c b/drivers/video/sunxvr1000.c index 23e69e834a18..7288934c0d49 100644 --- a/drivers/video/sunxvr1000.c +++ b/drivers/video/sunxvr1000.c @@ -114,7 +114,7 @@ static int __devinit gfb_set_fbinfo(struct gfb_info *gp) static int __devinit gfb_probe(struct of_device *op, const struct of_device_id *match) { - struct device_node *dp = op->node; + struct device_node *dp = op->dev.of_node; struct fb_info *info; struct gfb_info *gp; int err; @@ -199,10 +199,13 @@ static const struct of_device_id gfb_match[] = { MODULE_DEVICE_TABLE(of, ffb_match); static struct of_platform_driver gfb_driver = { - .name = "gfb", - .match_table = gfb_match, .probe = gfb_probe, .remove = __devexit_p(gfb_remove), + .driver = { + .name = "gfb", + .owner = THIS_MODULE, + .of_match_table = gfb_match, + }, }; static int __init gfb_init(void) @@ -210,12 +213,12 @@ static int __init gfb_init(void) if (fb_get_options("gfb", NULL)) return -ENODEV; - return of_register_driver(&gfb_driver, &of_bus_type); + return of_register_platform_driver(&gfb_driver); } static void __exit gfb_exit(void) { - of_unregister_driver(&gfb_driver); + of_unregister_platform_driver(&gfb_driver); } module_init(gfb_init); diff --git a/drivers/video/tcx.c b/drivers/video/tcx.c index c0c2b18fcdcf..f375e0db6776 100644 --- a/drivers/video/tcx.c +++ b/drivers/video/tcx.c @@ -365,7 +365,7 @@ static void tcx_unmap_regs(struct of_device *op, struct fb_info *info, static int __devinit tcx_probe(struct of_device *op, const struct of_device_id *match) { - struct device_node *dp = op->node; + struct device_node *dp = op->dev.of_node; struct fb_info *info; struct tcx_par *par; int linebytes, i, err; @@ -512,8 +512,11 @@ static const struct of_device_id tcx_match[] = { MODULE_DEVICE_TABLE(of, tcx_match); static struct of_platform_driver tcx_driver = { - .name = "tcx", - .match_table = tcx_match, + .driver = { + .name = "tcx", + .owner = THIS_MODULE, + .of_match_table = tcx_match, + }, .probe = tcx_probe, .remove = __devexit_p(tcx_remove), }; @@ -523,12 +526,12 @@ static int __init tcx_init(void) if (fb_get_options("tcxfb", NULL)) return -ENODEV; - return of_register_driver(&tcx_driver, &of_bus_type); + return of_register_platform_driver(&tcx_driver); } static void __exit tcx_exit(void) { - of_unregister_driver(&tcx_driver); + of_unregister_platform_driver(&tcx_driver); } module_init(tcx_init); diff --git a/drivers/video/tdfxfb.c b/drivers/video/tdfxfb.c index 980548390048..3ee5e63cfa4f 100644 --- a/drivers/video/tdfxfb.c +++ b/drivers/video/tdfxfb.c @@ -1571,8 +1571,8 @@ out_err_iobase: if (default_par->mtrr_handle >= 0) mtrr_del(default_par->mtrr_handle, info->fix.smem_start, info->fix.smem_len); - release_mem_region(pci_resource_start(pdev, 2), - pci_resource_len(pdev, 2)); + release_region(pci_resource_start(pdev, 2), + pci_resource_len(pdev, 2)); out_err_screenbase: if (info->screen_base) iounmap(info->screen_base); diff --git a/drivers/video/tgafb.c b/drivers/video/tgafb.c index 1b3b1c718e80..aba7686b1a32 100644 --- a/drivers/video/tgafb.c +++ b/drivers/video/tgafb.c @@ -305,7 +305,7 @@ tgafb_set_par(struct fb_info *info) TGA_WRITE_REG(par, htimings, TGA_HORIZ_REG); TGA_WRITE_REG(par, vtimings, TGA_VERT_REG); - /* Initalise RAMDAC. */ + /* Initialise RAMDAC. */ if (tga_type == TGA_TYPE_8PLANE && tga_bus_pci) { /* Init BT485 RAMDAC registers. */ diff --git a/drivers/video/vesafb.c b/drivers/video/vesafb.c index 0cadf7aee27e..090aa1a9be6e 100644 --- a/drivers/video/vesafb.c +++ b/drivers/video/vesafb.c @@ -177,7 +177,7 @@ static void vesafb_destroy(struct fb_info *info) { if (info->screen_base) iounmap(info->screen_base); - release_mem_region(info->aperture_base, info->aperture_size); + release_mem_region(info->apertures->ranges[0].base, info->apertures->ranges[0].size); framebuffer_release(info); } @@ -295,8 +295,13 @@ static int __init vesafb_probe(struct platform_device *dev) info->par = NULL; /* set vesafb aperture size for generic probing */ - info->aperture_base = screen_info.lfb_base; - info->aperture_size = size_total; + info->apertures = alloc_apertures(1); + if (!info->apertures) { + err = -ENOMEM; + goto err; + } + info->apertures->ranges[0].base = screen_info.lfb_base; + info->apertures->ranges[0].size = size_total; info->screen_base = ioremap(vesafb_fix.smem_start, vesafb_fix.smem_len); if (!info->screen_base) { diff --git a/drivers/video/vfb.c b/drivers/video/vfb.c index 9b5532b4de35..bc67251f1a2f 100644 --- a/drivers/video/vfb.c +++ b/drivers/video/vfb.c @@ -78,7 +78,7 @@ static void rvfree(void *mem, unsigned long size) vfree(mem); } -static struct fb_var_screeninfo vfb_default __initdata = { +static struct fb_var_screeninfo vfb_default __devinitdata = { .xres = 640, .yres = 480, .xres_virtual = 640, @@ -100,7 +100,7 @@ static struct fb_var_screeninfo vfb_default __initdata = { .vmode = FB_VMODE_NONINTERLACED, }; -static struct fb_fix_screeninfo vfb_fix __initdata = { +static struct fb_fix_screeninfo vfb_fix __devinitdata = { .id = "Virtual FB", .type = FB_TYPE_PACKED_PIXELS, .visual = FB_VISUAL_PSEUDOCOLOR, diff --git a/drivers/video/vga16fb.c b/drivers/video/vga16fb.c index bf638a47a5b3..28ccab44a391 100644 --- a/drivers/video/vga16fb.c +++ b/drivers/video/vga16fb.c @@ -65,7 +65,7 @@ struct vga16fb_par { /* --------------------------------------------------------------------- */ -static struct fb_var_screeninfo vga16fb_defined __initdata = { +static struct fb_var_screeninfo vga16fb_defined __devinitdata = { .xres = 640, .yres = 480, .xres_virtual = 640, @@ -85,7 +85,7 @@ static struct fb_var_screeninfo vga16fb_defined __initdata = { }; /* name should not depend on EGA/VGA */ -static struct fb_fix_screeninfo vga16fb_fix __initdata = { +static struct fb_fix_screeninfo vga16fb_fix __devinitdata = { .id = "VGA16 VGA", .smem_start = VGA_FB_PHYS, .smem_len = VGA_FB_PHYS_LEN, @@ -1263,10 +1263,19 @@ static void vga16fb_imageblit(struct fb_info *info, const struct fb_image *image vga_imageblit_color(info, image); } +static void vga16fb_destroy(struct fb_info *info) +{ + iounmap(info->screen_base); + fb_dealloc_cmap(&info->cmap); + /* XXX unshare VGA regions */ + framebuffer_release(info); +} + static struct fb_ops vga16fb_ops = { .owner = THIS_MODULE, .fb_open = vga16fb_open, .fb_release = vga16fb_release, + .fb_destroy = vga16fb_destroy, .fb_check_var = vga16fb_check_var, .fb_set_par = vga16fb_set_par, .fb_setcolreg = vga16fb_setcolreg, @@ -1278,7 +1287,7 @@ static struct fb_ops vga16fb_ops = { }; #ifndef MODULE -static int vga16fb_setup(char *options) +static int __init vga16fb_setup(char *options) { char *this_opt; @@ -1306,6 +1315,11 @@ static int __devinit vga16fb_probe(struct platform_device *dev) ret = -ENOMEM; goto err_fb_alloc; } + info->apertures = alloc_apertures(1); + if (!info->apertures) { + ret = -ENOMEM; + goto err_ioremap; + } /* XXX share VGA_FB_PHYS and I/O region with vgacon and others */ info->screen_base = (void __iomem *)VGA_MAP_MEM(VGA_FB_PHYS, 0); @@ -1335,7 +1349,7 @@ static int __devinit vga16fb_probe(struct platform_device *dev) info->fix = vga16fb_fix; /* supports rectangles with widths of multiples of 8 */ info->pixmap.blit_x = 1 << 7 | 1 << 15 | 1 << 23 | 1 << 31; - info->flags = FBINFO_FLAG_DEFAULT | + info->flags = FBINFO_FLAG_DEFAULT | FBINFO_MISC_FIRMWARE | FBINFO_HWACCEL_YPAN; i = (info->var.bits_per_pixel == 8) ? 256 : 16; @@ -1354,6 +1368,9 @@ static int __devinit vga16fb_probe(struct platform_device *dev) vga16fb_update_fix(info); + info->apertures->ranges[0].base = VGA_FB_PHYS; + info->apertures->ranges[0].size = VGA_FB_PHYS_LEN; + if (register_framebuffer(info) < 0) { printk(KERN_ERR "vga16fb: unable to register framebuffer\n"); ret = -EINVAL; @@ -1376,24 +1393,19 @@ static int __devinit vga16fb_probe(struct platform_device *dev) return ret; } -static int vga16fb_remove(struct platform_device *dev) +static int __devexit vga16fb_remove(struct platform_device *dev) { struct fb_info *info = platform_get_drvdata(dev); - if (info) { + if (info) unregister_framebuffer(info); - iounmap(info->screen_base); - fb_dealloc_cmap(&info->cmap); - /* XXX unshare VGA regions */ - framebuffer_release(info); - } return 0; } static struct platform_driver vga16fb_driver = { .probe = vga16fb_probe, - .remove = vga16fb_remove, + .remove = __devexit_p(vga16fb_remove), .driver = { .name = "vga16fb", }, diff --git a/drivers/video/via/chip.h b/drivers/video/via/chip.h index d9b6e06e0700..ef1f3de2e052 100644 --- a/drivers/video/via/chip.h +++ b/drivers/video/via/chip.h @@ -160,7 +160,6 @@ struct lvds_setting_information { int v_active; int bpp; int refresh_rate; - int get_lcd_size_method; int lcd_panel_id; int lcd_panel_hres; int lcd_panel_vres; diff --git a/drivers/video/via/hw.c b/drivers/video/via/hw.c index b996803ae2c1..7dcb4d5bb9c3 100644 --- a/drivers/video/via/hw.c +++ b/drivers/video/via/hw.c @@ -23,143 +23,341 @@ #include "global.h" static struct pll_map pll_value[] = { - {CLK_25_175M, CLE266_PLL_25_175M, K800_PLL_25_175M, - CX700_25_175M, VX855_25_175M}, - {CLK_29_581M, CLE266_PLL_29_581M, K800_PLL_29_581M, - CX700_29_581M, VX855_29_581M}, - {CLK_26_880M, CLE266_PLL_26_880M, K800_PLL_26_880M, - CX700_26_880M, VX855_26_880M}, - {CLK_31_490M, CLE266_PLL_31_490M, K800_PLL_31_490M, - CX700_31_490M, VX855_31_490M}, - {CLK_31_500M, CLE266_PLL_31_500M, K800_PLL_31_500M, - CX700_31_500M, VX855_31_500M}, - {CLK_31_728M, CLE266_PLL_31_728M, K800_PLL_31_728M, - CX700_31_728M, VX855_31_728M}, - {CLK_32_668M, CLE266_PLL_32_668M, K800_PLL_32_668M, - CX700_32_668M, VX855_32_668M}, - {CLK_36_000M, CLE266_PLL_36_000M, K800_PLL_36_000M, - CX700_36_000M, VX855_36_000M}, - {CLK_40_000M, CLE266_PLL_40_000M, K800_PLL_40_000M, - CX700_40_000M, VX855_40_000M}, - {CLK_41_291M, CLE266_PLL_41_291M, K800_PLL_41_291M, - CX700_41_291M, VX855_41_291M}, - {CLK_43_163M, CLE266_PLL_43_163M, K800_PLL_43_163M, - CX700_43_163M, VX855_43_163M}, - {CLK_45_250M, CLE266_PLL_45_250M, K800_PLL_45_250M, - CX700_45_250M, VX855_45_250M}, - {CLK_46_000M, CLE266_PLL_46_000M, K800_PLL_46_000M, - CX700_46_000M, VX855_46_000M}, - {CLK_46_996M, CLE266_PLL_46_996M, K800_PLL_46_996M, - CX700_46_996M, VX855_46_996M}, - {CLK_48_000M, CLE266_PLL_48_000M, K800_PLL_48_000M, - CX700_48_000M, VX855_48_000M}, - {CLK_48_875M, CLE266_PLL_48_875M, K800_PLL_48_875M, - CX700_48_875M, VX855_48_875M}, - {CLK_49_500M, CLE266_PLL_49_500M, K800_PLL_49_500M, - CX700_49_500M, VX855_49_500M}, - {CLK_52_406M, CLE266_PLL_52_406M, K800_PLL_52_406M, - CX700_52_406M, VX855_52_406M}, - {CLK_52_977M, CLE266_PLL_52_977M, K800_PLL_52_977M, - CX700_52_977M, VX855_52_977M}, - {CLK_56_250M, CLE266_PLL_56_250M, K800_PLL_56_250M, - CX700_56_250M, VX855_56_250M}, - {CLK_57_275M, 0, 0, 0, VX855_57_275M}, - {CLK_60_466M, CLE266_PLL_60_466M, K800_PLL_60_466M, - CX700_60_466M, VX855_60_466M}, - {CLK_61_500M, CLE266_PLL_61_500M, K800_PLL_61_500M, - CX700_61_500M, VX855_61_500M}, - {CLK_65_000M, CLE266_PLL_65_000M, K800_PLL_65_000M, - CX700_65_000M, VX855_65_000M}, - {CLK_65_178M, CLE266_PLL_65_178M, K800_PLL_65_178M, - CX700_65_178M, VX855_65_178M}, - {CLK_66_750M, CLE266_PLL_66_750M, K800_PLL_66_750M, - CX700_66_750M, VX855_66_750M}, - {CLK_68_179M, CLE266_PLL_68_179M, K800_PLL_68_179M, - CX700_68_179M, VX855_68_179M}, - {CLK_69_924M, CLE266_PLL_69_924M, K800_PLL_69_924M, - CX700_69_924M, VX855_69_924M}, - {CLK_70_159M, CLE266_PLL_70_159M, K800_PLL_70_159M, - CX700_70_159M, VX855_70_159M}, - {CLK_72_000M, CLE266_PLL_72_000M, K800_PLL_72_000M, - CX700_72_000M, VX855_72_000M}, - {CLK_78_750M, CLE266_PLL_78_750M, K800_PLL_78_750M, - CX700_78_750M, VX855_78_750M}, - {CLK_80_136M, CLE266_PLL_80_136M, K800_PLL_80_136M, - CX700_80_136M, VX855_80_136M}, - {CLK_83_375M, CLE266_PLL_83_375M, K800_PLL_83_375M, - CX700_83_375M, VX855_83_375M}, - {CLK_83_950M, CLE266_PLL_83_950M, K800_PLL_83_950M, - CX700_83_950M, VX855_83_950M}, - {CLK_84_750M, CLE266_PLL_84_750M, K800_PLL_84_750M, - CX700_84_750M, VX855_84_750M}, - {CLK_85_860M, CLE266_PLL_85_860M, K800_PLL_85_860M, - CX700_85_860M, VX855_85_860M}, - {CLK_88_750M, CLE266_PLL_88_750M, K800_PLL_88_750M, - CX700_88_750M, VX855_88_750M}, - {CLK_94_500M, CLE266_PLL_94_500M, K800_PLL_94_500M, - CX700_94_500M, VX855_94_500M}, - {CLK_97_750M, CLE266_PLL_97_750M, K800_PLL_97_750M, - CX700_97_750M, VX855_97_750M}, - {CLK_101_000M, CLE266_PLL_101_000M, K800_PLL_101_000M, - CX700_101_000M, VX855_101_000M}, - {CLK_106_500M, CLE266_PLL_106_500M, K800_PLL_106_500M, - CX700_106_500M, VX855_106_500M}, - {CLK_108_000M, CLE266_PLL_108_000M, K800_PLL_108_000M, - CX700_108_000M, VX855_108_000M}, - {CLK_113_309M, CLE266_PLL_113_309M, K800_PLL_113_309M, - CX700_113_309M, VX855_113_309M}, - {CLK_118_840M, CLE266_PLL_118_840M, K800_PLL_118_840M, - CX700_118_840M, VX855_118_840M}, - {CLK_119_000M, CLE266_PLL_119_000M, K800_PLL_119_000M, - CX700_119_000M, VX855_119_000M}, - {CLK_121_750M, CLE266_PLL_121_750M, K800_PLL_121_750M, - CX700_121_750M, 0}, - {CLK_125_104M, CLE266_PLL_125_104M, K800_PLL_125_104M, - CX700_125_104M, 0}, - {CLK_133_308M, CLE266_PLL_133_308M, K800_PLL_133_308M, - CX700_133_308M, 0}, - {CLK_135_000M, CLE266_PLL_135_000M, K800_PLL_135_000M, - CX700_135_000M, VX855_135_000M}, - {CLK_136_700M, CLE266_PLL_136_700M, K800_PLL_136_700M, - CX700_136_700M, VX855_136_700M}, - {CLK_138_400M, CLE266_PLL_138_400M, K800_PLL_138_400M, - CX700_138_400M, VX855_138_400M}, - {CLK_146_760M, CLE266_PLL_146_760M, K800_PLL_146_760M, - CX700_146_760M, VX855_146_760M}, - {CLK_153_920M, CLE266_PLL_153_920M, K800_PLL_153_920M, - CX700_153_920M, VX855_153_920M}, - {CLK_156_000M, CLE266_PLL_156_000M, K800_PLL_156_000M, - CX700_156_000M, VX855_156_000M}, - {CLK_157_500M, CLE266_PLL_157_500M, K800_PLL_157_500M, - CX700_157_500M, VX855_157_500M}, - {CLK_162_000M, CLE266_PLL_162_000M, K800_PLL_162_000M, - CX700_162_000M, VX855_162_000M}, - {CLK_187_000M, CLE266_PLL_187_000M, K800_PLL_187_000M, - CX700_187_000M, VX855_187_000M}, - {CLK_193_295M, CLE266_PLL_193_295M, K800_PLL_193_295M, - CX700_193_295M, VX855_193_295M}, - {CLK_202_500M, CLE266_PLL_202_500M, K800_PLL_202_500M, - CX700_202_500M, VX855_202_500M}, - {CLK_204_000M, CLE266_PLL_204_000M, K800_PLL_204_000M, - CX700_204_000M, VX855_204_000M}, - {CLK_218_500M, CLE266_PLL_218_500M, K800_PLL_218_500M, - CX700_218_500M, VX855_218_500M}, - {CLK_234_000M, CLE266_PLL_234_000M, K800_PLL_234_000M, - CX700_234_000M, VX855_234_000M}, - {CLK_267_250M, CLE266_PLL_267_250M, K800_PLL_267_250M, - CX700_267_250M, VX855_267_250M}, - {CLK_297_500M, CLE266_PLL_297_500M, K800_PLL_297_500M, - CX700_297_500M, VX855_297_500M}, - {CLK_74_481M, CLE266_PLL_74_481M, K800_PLL_74_481M, - CX700_74_481M, VX855_74_481M}, - {CLK_172_798M, CLE266_PLL_172_798M, K800_PLL_172_798M, - CX700_172_798M, VX855_172_798M}, - {CLK_122_614M, CLE266_PLL_122_614M, K800_PLL_122_614M, - CX700_122_614M, VX855_122_614M}, - {CLK_74_270M, CLE266_PLL_74_270M, K800_PLL_74_270M, - CX700_74_270M, 0}, - {CLK_148_500M, CLE266_PLL_148_500M, K800_PLL_148_500M, - CX700_148_500M, VX855_148_500M} + {25175000, + {99, 7, 3}, + {85, 3, 4}, /* ignoring bit difference: 0x00008000 */ + {141, 5, 4}, + {141, 5, 4} }, + {29581000, + {33, 4, 2}, + {66, 2, 4}, /* ignoring bit difference: 0x00808000 */ + {166, 5, 4}, /* ignoring bit difference: 0x00008000 */ + {165, 5, 4} }, + {26880000, + {15, 4, 1}, + {30, 2, 3}, /* ignoring bit difference: 0x00808000 */ + {150, 5, 4}, + {150, 5, 4} }, + {31500000, + {53, 3, 3}, /* ignoring bit difference: 0x00008000 */ + {141, 4, 4}, /* ignoring bit difference: 0x00008000 */ + {176, 5, 4}, + {176, 5, 4} }, + {31728000, + {31, 7, 1}, + {177, 5, 4}, /* ignoring bit difference: 0x00008000 */ + {177, 5, 4}, + {142, 4, 4} }, + {32688000, + {73, 4, 3}, + {146, 4, 4}, /* ignoring bit difference: 0x00008000 */ + {183, 5, 4}, + {146, 4, 4} }, + {36000000, + {101, 5, 3}, /* ignoring bit difference: 0x00008000 */ + {161, 4, 4}, /* ignoring bit difference: 0x00008000 */ + {202, 5, 4}, + {161, 4, 4} }, + {40000000, + {89, 4, 3}, + {89, 4, 3}, /* ignoring bit difference: 0x00008000 */ + {112, 5, 3}, + {112, 5, 3} }, + {41291000, + {23, 4, 1}, + {69, 3, 3}, /* ignoring bit difference: 0x00008000 */ + {115, 5, 3}, + {115, 5, 3} }, + {43163000, + {121, 5, 3}, + {121, 5, 3}, /* ignoring bit difference: 0x00008000 */ + {121, 5, 3}, + {121, 5, 3} }, + {45250000, + {127, 5, 3}, + {127, 5, 3}, /* ignoring bit difference: 0x00808000 */ + {127, 5, 3}, + {127, 5, 3} }, + {46000000, + {90, 7, 2}, + {103, 4, 3}, /* ignoring bit difference: 0x00008000 */ + {129, 5, 3}, + {103, 4, 3} }, + {46996000, + {105, 4, 3}, /* ignoring bit difference: 0x00008000 */ + {131, 5, 3}, /* ignoring bit difference: 0x00808000 */ + {131, 5, 3}, /* ignoring bit difference: 0x00808000 */ + {105, 4, 3} }, + {48000000, + {67, 20, 0}, + {134, 5, 3}, /* ignoring bit difference: 0x00808000 */ + {134, 5, 3}, + {134, 5, 3} }, + {48875000, + {99, 29, 0}, + {82, 3, 3}, /* ignoring bit difference: 0x00808000 */ + {82, 3, 3}, /* ignoring bit difference: 0x00808000 */ + {137, 5, 3} }, + {49500000, + {83, 6, 2}, + {83, 3, 3}, /* ignoring bit difference: 0x00008000 */ + {138, 5, 3}, + {83, 3, 3} }, + {52406000, + {117, 4, 3}, + {117, 4, 3}, /* ignoring bit difference: 0x00008000 */ + {117, 4, 3}, + {88, 3, 3} }, + {52977000, + {37, 5, 1}, + {148, 5, 3}, /* ignoring bit difference: 0x00808000 */ + {148, 5, 3}, + {148, 5, 3} }, + {56250000, + {55, 7, 1}, /* ignoring bit difference: 0x00008000 */ + {126, 4, 3}, /* ignoring bit difference: 0x00008000 */ + {157, 5, 3}, + {157, 5, 3} }, + {57275000, + {0, 0, 0}, + {2, 2, 0}, + {2, 2, 0}, + {157, 5, 3} }, /* ignoring bit difference: 0x00808000 */ + {60466000, + {76, 9, 1}, + {169, 5, 3}, /* ignoring bit difference: 0x00808000 */ + {169, 5, 3}, /* FIXED: old = {72, 2, 3} */ + {169, 5, 3} }, + {61500000, + {86, 20, 0}, + {172, 5, 3}, /* ignoring bit difference: 0x00808000 */ + {172, 5, 3}, + {172, 5, 3} }, + {65000000, + {109, 6, 2}, /* ignoring bit difference: 0x00008000 */ + {109, 3, 3}, /* ignoring bit difference: 0x00008000 */ + {109, 3, 3}, + {109, 3, 3} }, + {65178000, + {91, 5, 2}, + {182, 5, 3}, /* ignoring bit difference: 0x00808000 */ + {109, 3, 3}, + {182, 5, 3} }, + {66750000, + {75, 4, 2}, + {150, 4, 3}, /* ignoring bit difference: 0x00808000 */ + {150, 4, 3}, + {112, 3, 3} }, + {68179000, + {19, 4, 0}, + {114, 3, 3}, /* ignoring bit difference: 0x00008000 */ + {190, 5, 3}, + {191, 5, 3} }, + {69924000, + {83, 17, 0}, + {195, 5, 3}, /* ignoring bit difference: 0x00808000 */ + {195, 5, 3}, + {195, 5, 3} }, + {70159000, + {98, 20, 0}, + {196, 5, 3}, /* ignoring bit difference: 0x00808000 */ + {196, 5, 3}, + {195, 5, 3} }, + {72000000, + {121, 24, 0}, + {161, 4, 3}, /* ignoring bit difference: 0x00808000 */ + {161, 4, 3}, + {161, 4, 3} }, + {78750000, + {33, 3, 1}, + {66, 3, 2}, /* ignoring bit difference: 0x00008000 */ + {110, 5, 2}, + {110, 5, 2} }, + {80136000, + {28, 5, 0}, + {68, 3, 2}, /* ignoring bit difference: 0x00008000 */ + {112, 5, 2}, + {112, 5, 2} }, + {83375000, + {93, 2, 3}, + {93, 4, 2}, /* ignoring bit difference: 0x00800000 */ + {93, 4, 2}, /* ignoring bit difference: 0x00800000 */ + {117, 5, 2} }, + {83950000, + {41, 7, 0}, + {117, 5, 2}, /* ignoring bit difference: 0x00008000 */ + {117, 5, 2}, + {117, 5, 2} }, + {84750000, + {118, 5, 2}, + {118, 5, 2}, /* ignoring bit difference: 0x00808000 */ + {118, 5, 2}, + {118, 5, 2} }, + {85860000, + {84, 7, 1}, + {120, 5, 2}, /* ignoring bit difference: 0x00808000 */ + {120, 5, 2}, + {118, 5, 2} }, + {88750000, + {31, 5, 0}, + {124, 5, 2}, /* ignoring bit difference: 0x00808000 */ + {174, 7, 2}, /* ignoring bit difference: 0x00808000 */ + {124, 5, 2} }, + {94500000, + {33, 5, 0}, + {132, 5, 2}, /* ignoring bit difference: 0x00008000 */ + {132, 5, 2}, + {132, 5, 2} }, + {97750000, + {82, 6, 1}, + {137, 5, 2}, /* ignoring bit difference: 0x00808000 */ + {137, 5, 2}, + {137, 5, 2} }, + {101000000, + {127, 9, 1}, + {141, 5, 2}, /* ignoring bit difference: 0x00808000 */ + {141, 5, 2}, + {141, 5, 2} }, + {106500000, + {119, 4, 2}, + {119, 4, 2}, /* ignoring bit difference: 0x00808000 */ + {119, 4, 2}, + {149, 5, 2} }, + {108000000, + {121, 4, 2}, + {121, 4, 2}, /* ignoring bit difference: 0x00808000 */ + {151, 5, 2}, + {151, 5, 2} }, + {113309000, + {95, 12, 0}, + {95, 3, 2}, /* ignoring bit difference: 0x00808000 */ + {95, 3, 2}, + {159, 5, 2} }, + {118840000, + {83, 5, 1}, + {166, 5, 2}, /* ignoring bit difference: 0x00808000 */ + {166, 5, 2}, + {166, 5, 2} }, + {119000000, + {108, 13, 0}, + {133, 4, 2}, /* ignoring bit difference: 0x00808000 */ + {133, 4, 2}, + {167, 5, 2} }, + {121750000, + {85, 5, 1}, + {170, 5, 2}, /* ignoring bit difference: 0x00808000 */ + {68, 2, 2}, + {0, 0, 0} }, + {125104000, + {53, 6, 0}, /* ignoring bit difference: 0x00008000 */ + {106, 3, 2}, /* ignoring bit difference: 0x00008000 */ + {175, 5, 2}, + {0, 0, 0} }, + {135000000, + {94, 5, 1}, + {28, 3, 0}, /* ignoring bit difference: 0x00804000 */ + {151, 4, 2}, + {189, 5, 2} }, + {136700000, + {115, 12, 0}, + {191, 5, 2}, /* ignoring bit difference: 0x00808000 */ + {191, 5, 2}, + {191, 5, 2} }, + {138400000, + {87, 9, 0}, + {116, 3, 2}, /* ignoring bit difference: 0x00808000 */ + {116, 3, 2}, + {194, 5, 2} }, + {146760000, + {103, 5, 1}, + {206, 5, 2}, /* ignoring bit difference: 0x00808000 */ + {206, 5, 2}, + {206, 5, 2} }, + {153920000, + {86, 8, 0}, + {86, 4, 1}, /* ignoring bit difference: 0x00808000 */ + {86, 4, 1}, + {86, 4, 1} }, /* FIXED: old = {84, 2, 1} */ + {156000000, + {109, 5, 1}, + {109, 5, 1}, /* ignoring bit difference: 0x00808000 */ + {109, 5, 1}, + {108, 5, 1} }, + {157500000, + {55, 5, 0}, /* ignoring bit difference: 0x00008000 */ + {22, 2, 0}, /* ignoring bit difference: 0x00802000 */ + {110, 5, 1}, + {110, 5, 1} }, + {162000000, + {113, 5, 1}, + {113, 5, 1}, /* ignoring bit difference: 0x00808000 */ + {113, 5, 1}, + {113, 5, 1} }, + {187000000, + {118, 9, 0}, + {131, 5, 1}, /* ignoring bit difference: 0x00808000 */ + {131, 5, 1}, + {131, 5, 1} }, + {193295000, + {108, 8, 0}, + {81, 3, 1}, /* ignoring bit difference: 0x00808000 */ + {135, 5, 1}, + {135, 5, 1} }, + {202500000, + {99, 7, 0}, + {85, 3, 1}, /* ignoring bit difference: 0x00808000 */ + {142, 5, 1}, + {142, 5, 1} }, + {204000000, + {100, 7, 0}, + {143, 5, 1}, /* ignoring bit difference: 0x00808000 */ + {143, 5, 1}, + {143, 5, 1} }, + {218500000, + {92, 6, 0}, + {153, 5, 1}, /* ignoring bit difference: 0x00808000 */ + {153, 5, 1}, + {153, 5, 1} }, + {234000000, + {98, 6, 0}, + {98, 3, 1}, /* ignoring bit difference: 0x00008000 */ + {98, 3, 1}, + {164, 5, 1} }, + {267250000, + {112, 6, 0}, + {112, 3, 1}, /* ignoring bit difference: 0x00808000 */ + {187, 5, 1}, + {187, 5, 1} }, + {297500000, + {102, 5, 0}, /* ignoring bit difference: 0x00008000 */ + {166, 4, 1}, /* ignoring bit difference: 0x00008000 */ + {208, 5, 1}, + {208, 5, 1} }, + {74481000, + {26, 5, 0}, + {125, 3, 3}, /* ignoring bit difference: 0x00808000 */ + {208, 5, 3}, + {209, 5, 3} }, + {172798000, + {121, 5, 1}, + {121, 5, 1}, /* ignoring bit difference: 0x00808000 */ + {121, 5, 1}, + {121, 5, 1} }, + {122614000, + {60, 7, 0}, + {137, 4, 2}, /* ignoring bit difference: 0x00808000 */ + {137, 4, 2}, + {172, 5, 2} }, + {74270000, + {83, 8, 1}, + {208, 5, 3}, + {208, 5, 3}, + {0, 0, 0} }, + {148500000, + {83, 8, 0}, + {208, 5, 2}, + {166, 4, 2}, + {208, 5, 2} } }; static struct fifo_depth_select display_fifo_depth_reg = { @@ -1360,40 +1558,70 @@ void viafb_load_FIFO_reg(int set_iga, int hor_active, int ver_active) } +static u32 cle266_encode_pll(struct pll_config pll) +{ + return (pll.multiplier << 8) + | (pll.rshift << 6) + | pll.divisor; +} + +static u32 k800_encode_pll(struct pll_config pll) +{ + return ((pll.divisor - 2) << 16) + | (pll.rshift << 10) + | (pll.multiplier - 2); +} + +static u32 vx855_encode_pll(struct pll_config pll) +{ + return (pll.divisor << 16) + | (pll.rshift << 10) + | pll.multiplier; +} + u32 viafb_get_clk_value(int clk) { - int i; + u32 value = 0; + int i = 0; - for (i = 0; i < NUM_TOTAL_PLL_TABLE; i++) { - if (clk == pll_value[i].clk) { - switch (viaparinfo->chip_info->gfx_chip_name) { - case UNICHROME_CLE266: - case UNICHROME_K400: - return pll_value[i].cle266_pll; - - case UNICHROME_K800: - case UNICHROME_PM800: - case UNICHROME_CN700: - return pll_value[i].k800_pll; - - case UNICHROME_CX700: - case UNICHROME_K8M890: - case UNICHROME_P4M890: - case UNICHROME_P4M900: - case UNICHROME_VX800: - return pll_value[i].cx700_pll; - case UNICHROME_VX855: - return pll_value[i].vx855_pll; - } + while (i < NUM_TOTAL_PLL_TABLE && clk != pll_value[i].clk) + i++; + + if (i == NUM_TOTAL_PLL_TABLE) { + printk(KERN_WARNING "viafb_get_clk_value: PLL lookup failed!"); + } else { + switch (viaparinfo->chip_info->gfx_chip_name) { + case UNICHROME_CLE266: + case UNICHROME_K400: + value = cle266_encode_pll(pll_value[i].cle266_pll); + break; + + case UNICHROME_K800: + case UNICHROME_PM800: + case UNICHROME_CN700: + value = k800_encode_pll(pll_value[i].k800_pll); + break; + + case UNICHROME_CX700: + case UNICHROME_CN750: + case UNICHROME_K8M890: + case UNICHROME_P4M890: + case UNICHROME_P4M900: + case UNICHROME_VX800: + value = k800_encode_pll(pll_value[i].cx700_pll); + break; + + case UNICHROME_VX855: + value = vx855_encode_pll(pll_value[i].vx855_pll); + break; } } - DEBUG_MSG(KERN_INFO "Can't find match PLL value\n\n"); - return 0; + return value; } /* Set VCLK*/ -void viafb_set_vclock(u32 CLK, int set_iga) +void viafb_set_vclock(u32 clk, int set_iga) { /* H.W. Reset : ON */ viafb_write_reg_mask(CR17, VIACR, 0x00, BIT7); @@ -1403,26 +1631,23 @@ void viafb_set_vclock(u32 CLK, int set_iga) switch (viaparinfo->chip_info->gfx_chip_name) { case UNICHROME_CLE266: case UNICHROME_K400: - viafb_write_reg(SR46, VIASR, CLK / 0x100); - viafb_write_reg(SR47, VIASR, CLK % 0x100); + via_write_reg(VIASR, SR46, (clk & 0x00FF)); + via_write_reg(VIASR, SR47, (clk & 0xFF00) >> 8); break; case UNICHROME_K800: case UNICHROME_PM800: case UNICHROME_CN700: case UNICHROME_CX700: + case UNICHROME_CN750: case UNICHROME_K8M890: case UNICHROME_P4M890: case UNICHROME_P4M900: case UNICHROME_VX800: case UNICHROME_VX855: - viafb_write_reg(SR44, VIASR, CLK / 0x10000); - DEBUG_MSG(KERN_INFO "\nSR44=%x", CLK / 0x10000); - viafb_write_reg(SR45, VIASR, (CLK & 0xFFFF) / 0x100); - DEBUG_MSG(KERN_INFO "\nSR45=%x", - (CLK & 0xFFFF) / 0x100); - viafb_write_reg(SR46, VIASR, CLK % 0x100); - DEBUG_MSG(KERN_INFO "\nSR46=%x", CLK % 0x100); + via_write_reg(VIASR, SR44, (clk & 0x0000FF)); + via_write_reg(VIASR, SR45, (clk & 0x00FF00) >> 8); + via_write_reg(VIASR, SR46, (clk & 0xFF0000) >> 16); break; } } @@ -1432,22 +1657,23 @@ void viafb_set_vclock(u32 CLK, int set_iga) switch (viaparinfo->chip_info->gfx_chip_name) { case UNICHROME_CLE266: case UNICHROME_K400: - viafb_write_reg(SR44, VIASR, CLK / 0x100); - viafb_write_reg(SR45, VIASR, CLK % 0x100); + via_write_reg(VIASR, SR44, (clk & 0x00FF)); + via_write_reg(VIASR, SR45, (clk & 0xFF00) >> 8); break; case UNICHROME_K800: case UNICHROME_PM800: case UNICHROME_CN700: case UNICHROME_CX700: + case UNICHROME_CN750: case UNICHROME_K8M890: case UNICHROME_P4M890: case UNICHROME_P4M900: case UNICHROME_VX800: case UNICHROME_VX855: - viafb_write_reg(SR4A, VIASR, CLK / 0x10000); - viafb_write_reg(SR4B, VIASR, (CLK & 0xFFFF) / 0x100); - viafb_write_reg(SR4C, VIASR, CLK % 0x100); + via_write_reg(VIASR, SR4A, (clk & 0x0000FF)); + via_write_reg(VIASR, SR4B, (clk & 0x00FF00) >> 8); + via_write_reg(VIASR, SR4C, (clk & 0xFF0000) >> 16); break; } } @@ -1791,8 +2017,6 @@ void viafb_init_chip_info(int chip_type) viafb_set_iga_path(); viaparinfo->lvds_setting_info->display_method = viafb_lcd_dsp_method; - viaparinfo->lvds_setting_info->get_lcd_size_method = - GET_LCD_SIZE_BY_USER_SETTING; viaparinfo->lvds_setting_info->lcd_mode = viafb_lcd_mode; viaparinfo->lvds_setting_info2->display_method = viaparinfo->lvds_setting_info->display_method; @@ -1946,13 +2170,6 @@ static void init_tmds_chip_info(void) static void init_lvds_chip_info(void) { - if (viafb_lcd_panel_id > LCD_PANEL_ID_MAXIMUM) - viaparinfo->lvds_setting_info->get_lcd_size_method = - GET_LCD_SIZE_BY_VGA_BIOS; - else - viaparinfo->lvds_setting_info->get_lcd_size_method = - GET_LCD_SIZE_BY_USER_SETTING; - viafb_lvds_trasmitter_identify(); viafb_init_lcd_size(); viafb_init_lvds_output_interface(&viaparinfo->chip_info->lvds_chip_info, diff --git a/drivers/video/via/hw.h b/drivers/video/via/hw.h index a109de379816..c44399895294 100644 --- a/drivers/video/via/hw.h +++ b/drivers/video/via/hw.h @@ -700,12 +700,18 @@ struct _lcd_scaling_factor { struct _lcd_ver_scaling_factor lcd_ver_scaling_factor; }; +struct pll_config { + u16 multiplier; + u8 divisor; + u8 rshift; +}; + struct pll_map { u32 clk; - u32 cle266_pll; - u32 k800_pll; - u32 cx700_pll; - u32 vx855_pll; + struct pll_config cle266_pll; + struct pll_config k800_pll; + struct pll_config cx700_pll; + struct pll_config vx855_pll; }; struct rgbLUT { diff --git a/drivers/video/via/ioctl.h b/drivers/video/via/ioctl.h index c430fa23008a..6010d10b59e8 100644 --- a/drivers/video/via/ioctl.h +++ b/drivers/video/via/ioctl.h @@ -35,11 +35,9 @@ #define VIAFB_GET_SAMM_INFO 0x56494107 /* 'VIA\07' */ #define VIAFB_TURN_ON_OUTPUT_DEVICE 0x56494108 /* 'VIA\08' */ #define VIAFB_TURN_OFF_OUTPUT_DEVICE 0x56494109 /* 'VIA\09' */ -#define VIAFB_SET_DEVICE 0x5649410A #define VIAFB_GET_DEVICE 0x5649410B #define VIAFB_GET_DRIVER_VERSION 0x56494112 /* 'VIA\12' */ #define VIAFB_GET_CHIP_INFO 0x56494113 /* 'VIA\13' */ -#define VIAFB_SET_DEVICE_INFO 0x56494114 #define VIAFB_GET_DEVICE_INFO 0x56494115 #define VIAFB_GET_DEVICE_SUPPORT 0x56494118 @@ -50,7 +48,6 @@ #define VIAFB_GET_GAMMA_LUT 0x56494124 #define VIAFB_SET_GAMMA_LUT 0x56494125 #define VIAFB_GET_GAMMA_SUPPORT_STATE 0x56494126 -#define VIAFB_SET_SECOND_MODE 0x56494129 #define VIAFB_SYNC_SURFACE 0x56494130 #define VIAFB_GET_DRIVER_CAPS 0x56494131 #define VIAFB_GET_IGA_SCALING_INFO 0x56494132 diff --git a/drivers/video/via/lcd.c b/drivers/video/via/lcd.c index 2ab0f156439a..fc25ae30c5f6 100644 --- a/drivers/video/via/lcd.c +++ b/drivers/video/via/lcd.c @@ -75,8 +75,6 @@ static void check_diport_of_integrated_lvds( static struct display_timing lcd_centering_timging(struct display_timing mode_crt_reg, struct display_timing panel_crt_reg); -static void viafb_load_scaling_factor_for_p4m900(int set_hres, - int set_vres, int panel_hres, int panel_vres); static int check_lvds_chip(int device_id_subaddr, int device_id) { @@ -89,33 +87,8 @@ static int check_lvds_chip(int device_id_subaddr, int device_id) void viafb_init_lcd_size(void) { DEBUG_MSG(KERN_INFO "viafb_init_lcd_size()\n"); - DEBUG_MSG(KERN_INFO - "viaparinfo->lvds_setting_info->get_lcd_size_method %d\n", - viaparinfo->lvds_setting_info->get_lcd_size_method); - switch (viaparinfo->lvds_setting_info->get_lcd_size_method) { - case GET_LCD_SIZE_BY_SYSTEM_BIOS: - break; - case GET_LCD_SZIE_BY_HW_STRAPPING: - break; - case GET_LCD_SIZE_BY_VGA_BIOS: - DEBUG_MSG(KERN_INFO "Get LCD Size method by VGA BIOS !!\n"); - fp_id_to_vindex(viafb_lcd_panel_id); - DEBUG_MSG(KERN_INFO "LCD Panel_ID = %d\n", - viaparinfo->lvds_setting_info->lcd_panel_id); - break; - case GET_LCD_SIZE_BY_USER_SETTING: - DEBUG_MSG(KERN_INFO "Get LCD Size method by user setting !!\n"); - fp_id_to_vindex(viafb_lcd_panel_id); - DEBUG_MSG(KERN_INFO "LCD Panel_ID = %d\n", - viaparinfo->lvds_setting_info->lcd_panel_id); - break; - default: - DEBUG_MSG(KERN_INFO "viafb_init_lcd_size fail\n"); - viaparinfo->lvds_setting_info->lcd_panel_id = - LCD_PANEL_ID1_800X600; - fp_id_to_vindex(LCD_PANEL_ID1_800X600); - } + fp_id_to_vindex(viafb_lcd_panel_id); viaparinfo->lvds_setting_info2->lcd_panel_id = viaparinfo->lvds_setting_info->lcd_panel_id; viaparinfo->lvds_setting_info2->lcd_panel_hres = @@ -437,14 +410,9 @@ static void load_lcd_scaling(int set_hres, int set_vres, int panel_hres, /* LCD Scaling Enable */ viafb_write_reg_mask(CR79, VIACR, 0x07, BIT0 + BIT1 + BIT2); - if (UNICHROME_P4M900 == viaparinfo->chip_info->gfx_chip_name) { - viafb_load_scaling_factor_for_p4m900(set_hres, set_vres, - panel_hres, panel_vres); - return; - } /* Check if expansion for horizontal */ - if (set_hres != panel_hres) { + if (set_hres < panel_hres) { /* Load Horizontal Scaling Factor */ switch (viaparinfo->chip_info->gfx_chip_name) { case UNICHROME_CLE266: @@ -464,6 +432,10 @@ static void load_lcd_scaling(int set_hres, int set_vres, int panel_hres, case UNICHROME_CX700: case UNICHROME_K8M890: case UNICHROME_P4M890: + case UNICHROME_P4M900: + case UNICHROME_CN750: + case UNICHROME_VX800: + case UNICHROME_VX855: reg_value = K800_LCD_HOR_SCF_FORMULA(set_hres, panel_hres); /* Horizontal scaling enabled */ @@ -483,7 +455,7 @@ static void load_lcd_scaling(int set_hres, int set_vres, int panel_hres, } /* Check if expansion for vertical */ - if (set_vres != panel_vres) { + if (set_vres < panel_vres) { /* Load Vertical Scaling Factor */ switch (viaparinfo->chip_info->gfx_chip_name) { case UNICHROME_CLE266: @@ -503,6 +475,10 @@ static void load_lcd_scaling(int set_hres, int set_vres, int panel_hres, case UNICHROME_CX700: case UNICHROME_K8M890: case UNICHROME_P4M890: + case UNICHROME_P4M900: + case UNICHROME_CN750: + case UNICHROME_VX800: + case UNICHROME_VX855: reg_value = K800_LCD_VER_SCF_FORMULA(set_vres, panel_vres); /* Vertical scaling enabled */ @@ -648,9 +624,8 @@ void viafb_lcd_set_mode(struct crt_mode_table *mode_crt_table, (mode_crt_reg, panel_crt_reg), IGA1); } else { /* Expansion */ - if ((plvds_setting_info->display_method == - LCD_EXPANDSION) & ((set_hres != panel_hres) - || (set_vres != panel_vres))) { + if (plvds_setting_info->display_method == LCD_EXPANDSION + && (set_hres < panel_hres || set_vres < panel_vres)) { /* expansion timing IGA2 loaded panel set timing*/ viafb_load_crtc_timing(panel_crt_reg, IGA2); DEBUG_MSG(KERN_INFO "viafb_load_crtc_timing!!\n"); @@ -1139,69 +1114,3 @@ bool viafb_lcd_get_mobile_state(bool *mobile) return false; } } - -static void viafb_load_scaling_factor_for_p4m900(int set_hres, - int set_vres, int panel_hres, int panel_vres) -{ - int h_scaling_factor; - int v_scaling_factor; - u8 cra2 = 0; - u8 cr77 = 0; - u8 cr78 = 0; - u8 cr79 = 0; - u8 cr9f = 0; - /* Check if expansion for horizontal */ - if (set_hres < panel_hres) { - /* Load Horizontal Scaling Factor */ - - /* For VIA_K8M800 or later chipsets. */ - h_scaling_factor = - K800_LCD_HOR_SCF_FORMULA(set_hres, panel_hres); - /* HSCaleFactor[1:0] at CR9F[1:0] */ - cr9f = h_scaling_factor & 0x0003; - /* HSCaleFactor[9:2] at CR77[7:0] */ - cr77 = (h_scaling_factor & 0x03FC) >> 2; - /* HSCaleFactor[11:10] at CR79[5:4] */ - cr79 = (h_scaling_factor & 0x0C00) >> 10; - cr79 <<= 4; - - /* Horizontal scaling enabled */ - cra2 = 0xC0; - - DEBUG_MSG(KERN_INFO "Horizontal Scaling value = %d\n", - h_scaling_factor); - } else { - /* Horizontal scaling disabled */ - cra2 = 0x00; - } - - /* Check if expansion for vertical */ - if (set_vres < panel_vres) { - /* Load Vertical Scaling Factor */ - - /* For VIA_K8M800 or later chipsets. */ - v_scaling_factor = - K800_LCD_VER_SCF_FORMULA(set_vres, panel_vres); - - /* Vertical scaling enabled */ - cra2 |= 0x08; - /* VSCaleFactor[0] at CR79[3] */ - cr79 |= ((v_scaling_factor & 0x0001) << 3); - /* VSCaleFactor[8:1] at CR78[7:0] */ - cr78 |= (v_scaling_factor & 0x01FE) >> 1; - /* VSCaleFactor[10:9] at CR79[7:6] */ - cr79 |= ((v_scaling_factor & 0x0600) >> 9) << 6; - - DEBUG_MSG(KERN_INFO "Vertical Scaling value = %d\n", - v_scaling_factor); - } else { - /* Vertical scaling disabled */ - cra2 |= 0x00; - } - - viafb_write_reg_mask(CRA2, VIACR, cra2, BIT3 + BIT6 + BIT7); - viafb_write_reg_mask(CR77, VIACR, cr77, 0xFF); - viafb_write_reg_mask(CR78, VIACR, cr78, 0xFF); - viafb_write_reg_mask(CR79, VIACR, cr79, 0xF8); - viafb_write_reg_mask(CR9F, VIACR, cr9f, BIT0 + BIT1); -} diff --git a/drivers/video/via/lcd.h b/drivers/video/via/lcd.h index 9762ec62b495..b348efc360b8 100644 --- a/drivers/video/via/lcd.h +++ b/drivers/video/via/lcd.h @@ -28,11 +28,6 @@ #define VT3271_DEVICE_ID_REG 0x02 #define VT3271_DEVICE_ID 0x71 -#define GET_LCD_SIZE_BY_SYSTEM_BIOS 0x01 -#define GET_LCD_SIZE_BY_VGA_BIOS 0x02 -#define GET_LCD_SZIE_BY_HW_STRAPPING 0x03 -#define GET_LCD_SIZE_BY_USER_SETTING 0x04 - /* Definition DVI Panel ID*/ /* Resolution: 640x480, Channel: single, Dithering: Enable */ #define LCD_PANEL_ID0_640X480 0x00 diff --git a/drivers/video/via/share.h b/drivers/video/via/share.h index 7f0de7f006ad..2cbe1031b421 100644 --- a/drivers/video/via/share.h +++ b/drivers/video/via/share.h @@ -631,7 +631,6 @@ #define CLK_25_175M 25175000 #define CLK_26_880M 26880000 #define CLK_29_581M 29581000 -#define CLK_31_490M 31490000 #define CLK_31_500M 31500000 #define CLK_31_728M 31728000 #define CLK_32_668M 32688000 @@ -676,7 +675,6 @@ #define CLK_119_000M 119000000 #define CLK_121_750M 121750000 /* 121.704MHz */ #define CLK_125_104M 125104000 -#define CLK_133_308M 133308000 #define CLK_135_000M 135000000 #define CLK_136_700M 136700000 #define CLK_138_400M 138400000 @@ -699,313 +697,6 @@ #define CLK_172_798M 172798000 #define CLK_122_614M 122614000 -/* CLE266 PLL value -*/ -#define CLE266_PLL_25_175M 0x0000C763 -#define CLE266_PLL_26_880M 0x0000440F -#define CLE266_PLL_29_581M 0x00008421 -#define CLE266_PLL_31_490M 0x00004721 -#define CLE266_PLL_31_500M 0x0000C3B5 -#define CLE266_PLL_31_728M 0x0000471F -#define CLE266_PLL_32_668M 0x0000C449 -#define CLE266_PLL_36_000M 0x0000C5E5 -#define CLE266_PLL_40_000M 0x0000C459 -#define CLE266_PLL_41_291M 0x00004417 -#define CLE266_PLL_43_163M 0x0000C579 -#define CLE266_PLL_45_250M 0x0000C57F /* 45.46MHz */ -#define CLE266_PLL_46_000M 0x0000875A -#define CLE266_PLL_46_996M 0x0000C4E9 -#define CLE266_PLL_48_000M 0x00001443 -#define CLE266_PLL_48_875M 0x00001D63 -#define CLE266_PLL_49_500M 0x00008653 -#define CLE266_PLL_52_406M 0x0000C475 -#define CLE266_PLL_52_977M 0x00004525 -#define CLE266_PLL_56_250M 0x000047B7 -#define CLE266_PLL_60_466M 0x0000494C -#define CLE266_PLL_61_500M 0x00001456 -#define CLE266_PLL_65_000M 0x000086ED -#define CLE266_PLL_65_178M 0x0000855B -#define CLE266_PLL_66_750M 0x0000844B /* 67.116MHz */ -#define CLE266_PLL_68_179M 0x00000413 -#define CLE266_PLL_69_924M 0x00001153 -#define CLE266_PLL_70_159M 0x00001462 -#define CLE266_PLL_72_000M 0x00001879 -#define CLE266_PLL_74_270M 0x00004853 -#define CLE266_PLL_78_750M 0x00004321 -#define CLE266_PLL_80_136M 0x0000051C -#define CLE266_PLL_83_375M 0x0000C25D -#define CLE266_PLL_83_950M 0x00000729 -#define CLE266_PLL_84_750M 0x00008576 /* 84.537MHz */ -#define CLE266_PLL_85_860M 0x00004754 -#define CLE266_PLL_88_750M 0x0000051F -#define CLE266_PLL_94_500M 0x00000521 -#define CLE266_PLL_97_750M 0x00004652 -#define CLE266_PLL_101_000M 0x0000497F -#define CLE266_PLL_106_500M 0x00008477 /* 106.491463 MHz */ -#define CLE266_PLL_108_000M 0x00008479 -#define CLE266_PLL_113_309M 0x00000C5F -#define CLE266_PLL_118_840M 0x00004553 -#define CLE266_PLL_119_000M 0x00000D6C -#define CLE266_PLL_121_750M 0x00004555 /* 121.704MHz */ -#define CLE266_PLL_125_104M 0x000006B5 -#define CLE266_PLL_133_308M 0x0000465F -#define CLE266_PLL_135_000M 0x0000455E -#define CLE266_PLL_136_700M 0x00000C73 -#define CLE266_PLL_138_400M 0x00000957 -#define CLE266_PLL_146_760M 0x00004567 -#define CLE266_PLL_148_500M 0x00000853 -#define CLE266_PLL_153_920M 0x00000856 -#define CLE266_PLL_156_000M 0x0000456D -#define CLE266_PLL_157_500M 0x000005B7 -#define CLE266_PLL_162_000M 0x00004571 -#define CLE266_PLL_187_000M 0x00000976 -#define CLE266_PLL_193_295M 0x0000086C -#define CLE266_PLL_202_500M 0x00000763 -#define CLE266_PLL_204_000M 0x00000764 -#define CLE266_PLL_218_500M 0x0000065C -#define CLE266_PLL_234_000M 0x00000662 -#define CLE266_PLL_267_250M 0x00000670 -#define CLE266_PLL_297_500M 0x000005E6 -#define CLE266_PLL_74_481M 0x0000051A -#define CLE266_PLL_172_798M 0x00004579 -#define CLE266_PLL_122_614M 0x0000073C - -/* K800 PLL value -*/ -#define K800_PLL_25_175M 0x00539001 -#define K800_PLL_26_880M 0x001C8C80 -#define K800_PLL_29_581M 0x00409080 -#define K800_PLL_31_490M 0x006F9001 -#define K800_PLL_31_500M 0x008B9002 -#define K800_PLL_31_728M 0x00AF9003 -#define K800_PLL_32_668M 0x00909002 -#define K800_PLL_36_000M 0x009F9002 -#define K800_PLL_40_000M 0x00578C02 -#define K800_PLL_41_291M 0x00438C01 -#define K800_PLL_43_163M 0x00778C03 -#define K800_PLL_45_250M 0x007D8C83 /* 45.46MHz */ -#define K800_PLL_46_000M 0x00658C02 -#define K800_PLL_46_996M 0x00818C83 -#define K800_PLL_48_000M 0x00848C83 -#define K800_PLL_48_875M 0x00508C81 -#define K800_PLL_49_500M 0x00518C01 -#define K800_PLL_52_406M 0x00738C02 -#define K800_PLL_52_977M 0x00928C83 -#define K800_PLL_56_250M 0x007C8C02 -#define K800_PLL_60_466M 0x00A78C83 -#define K800_PLL_61_500M 0x00AA8C83 -#define K800_PLL_65_000M 0x006B8C01 -#define K800_PLL_65_178M 0x00B48C83 -#define K800_PLL_66_750M 0x00948C82 /* 67.116MHz */ -#define K800_PLL_68_179M 0x00708C01 -#define K800_PLL_69_924M 0x00C18C83 -#define K800_PLL_70_159M 0x00C28C83 -#define K800_PLL_72_000M 0x009F8C82 -#define K800_PLL_74_270M 0x00ce0c03 -#define K800_PLL_78_750M 0x00408801 -#define K800_PLL_80_136M 0x00428801 -#define K800_PLL_83_375M 0x005B0882 -#define K800_PLL_83_950M 0x00738803 -#define K800_PLL_84_750M 0x00748883 /* 84.477MHz */ -#define K800_PLL_85_860M 0x00768883 -#define K800_PLL_88_750M 0x007A8883 -#define K800_PLL_94_500M 0x00828803 -#define K800_PLL_97_750M 0x00878883 -#define K800_PLL_101_000M 0x008B8883 -#define K800_PLL_106_500M 0x00758882 /* 106.491463 MHz */ -#define K800_PLL_108_000M 0x00778882 -#define K800_PLL_113_309M 0x005D8881 -#define K800_PLL_118_840M 0x00A48883 -#define K800_PLL_119_000M 0x00838882 -#define K800_PLL_121_750M 0x00A88883 /* 121.704MHz */ -#define K800_PLL_125_104M 0x00688801 -#define K800_PLL_133_308M 0x005D8801 -#define K800_PLL_135_000M 0x001A4081 -#define K800_PLL_136_700M 0x00BD8883 -#define K800_PLL_138_400M 0x00728881 -#define K800_PLL_146_760M 0x00CC8883 -#define K800_PLL_148_500M 0x00ce0803 -#define K800_PLL_153_920M 0x00548482 -#define K800_PLL_156_000M 0x006B8483 -#define K800_PLL_157_500M 0x00142080 -#define K800_PLL_162_000M 0x006F8483 -#define K800_PLL_187_000M 0x00818483 -#define K800_PLL_193_295M 0x004F8481 -#define K800_PLL_202_500M 0x00538481 -#define K800_PLL_204_000M 0x008D8483 -#define K800_PLL_218_500M 0x00978483 -#define K800_PLL_234_000M 0x00608401 -#define K800_PLL_267_250M 0x006E8481 -#define K800_PLL_297_500M 0x00A48402 -#define K800_PLL_74_481M 0x007B8C81 -#define K800_PLL_172_798M 0x00778483 -#define K800_PLL_122_614M 0x00878882 - -/* PLL for VT3324 */ -#define CX700_25_175M 0x008B1003 -#define CX700_26_719M 0x00931003 -#define CX700_26_880M 0x00941003 -#define CX700_29_581M 0x00A49003 -#define CX700_31_490M 0x00AE1003 -#define CX700_31_500M 0x00AE1003 -#define CX700_31_728M 0x00AF1003 -#define CX700_32_668M 0x00B51003 -#define CX700_36_000M 0x00C81003 -#define CX700_40_000M 0x006E0C03 -#define CX700_41_291M 0x00710C03 -#define CX700_43_163M 0x00770C03 -#define CX700_45_250M 0x007D0C03 /* 45.46MHz */ -#define CX700_46_000M 0x007F0C03 -#define CX700_46_996M 0x00818C83 -#define CX700_48_000M 0x00840C03 -#define CX700_48_875M 0x00508C81 -#define CX700_49_500M 0x00880C03 -#define CX700_52_406M 0x00730C02 -#define CX700_52_977M 0x00920C03 -#define CX700_56_250M 0x009B0C03 -#define CX700_60_466M 0x00460C00 -#define CX700_61_500M 0x00AA0C03 -#define CX700_65_000M 0x006B0C01 -#define CX700_65_178M 0x006B0C01 -#define CX700_66_750M 0x00940C02 /*67.116MHz */ -#define CX700_68_179M 0x00BC0C03 -#define CX700_69_924M 0x00C10C03 -#define CX700_70_159M 0x00C20C03 -#define CX700_72_000M 0x009F0C02 -#define CX700_74_270M 0x00CE0C03 -#define CX700_74_481M 0x00CE0C03 -#define CX700_78_750M 0x006C0803 -#define CX700_80_136M 0x006E0803 -#define CX700_83_375M 0x005B0882 -#define CX700_83_950M 0x00730803 -#define CX700_84_750M 0x00740803 /* 84.537Mhz */ -#define CX700_85_860M 0x00760803 -#define CX700_88_750M 0x00AC8885 -#define CX700_94_500M 0x00820803 -#define CX700_97_750M 0x00870803 -#define CX700_101_000M 0x008B0803 -#define CX700_106_500M 0x00750802 -#define CX700_108_000M 0x00950803 -#define CX700_113_309M 0x005D0801 -#define CX700_118_840M 0x00A40803 -#define CX700_119_000M 0x00830802 -#define CX700_121_750M 0x00420800 /* 121.704MHz */ -#define CX700_125_104M 0x00AD0803 -#define CX700_133_308M 0x00930802 -#define CX700_135_000M 0x00950802 -#define CX700_136_700M 0x00BD0803 -#define CX700_138_400M 0x00720801 -#define CX700_146_760M 0x00CC0803 -#define CX700_148_500M 0x00a40802 -#define CX700_153_920M 0x00540402 -#define CX700_156_000M 0x006B0403 -#define CX700_157_500M 0x006C0403 -#define CX700_162_000M 0x006F0403 -#define CX700_172_798M 0x00770403 -#define CX700_187_000M 0x00810403 -#define CX700_193_295M 0x00850403 -#define CX700_202_500M 0x008C0403 -#define CX700_204_000M 0x008D0403 -#define CX700_218_500M 0x00970403 -#define CX700_234_000M 0x00600401 -#define CX700_267_250M 0x00B90403 -#define CX700_297_500M 0x00CE0403 -#define CX700_122_614M 0x00870802 - -/* PLL for VX855 */ -#define VX855_22_000M 0x007B1005 -#define VX855_25_175M 0x008D1005 -#define VX855_26_719M 0x00961005 -#define VX855_26_880M 0x00961005 -#define VX855_27_000M 0x00971005 -#define VX855_29_581M 0x00A51005 -#define VX855_29_829M 0x00641003 -#define VX855_31_490M 0x00B01005 -#define VX855_31_500M 0x00B01005 -#define VX855_31_728M 0x008E1004 -#define VX855_32_668M 0x00921004 -#define VX855_36_000M 0x00A11004 -#define VX855_40_000M 0x00700C05 -#define VX855_41_291M 0x00730C05 -#define VX855_43_163M 0x00790C05 -#define VX855_45_250M 0x007F0C05 /* 45.46MHz */ -#define VX855_46_000M 0x00670C04 -#define VX855_46_996M 0x00690C04 -#define VX855_48_000M 0x00860C05 -#define VX855_48_875M 0x00890C05 -#define VX855_49_500M 0x00530C03 -#define VX855_52_406M 0x00580C03 -#define VX855_52_977M 0x00940C05 -#define VX855_56_250M 0x009D0C05 -#define VX855_57_275M 0x009D8C85 /* Used by XO panel */ -#define VX855_60_466M 0x00A90C05 -#define VX855_61_500M 0x00AC0C05 -#define VX855_65_000M 0x006D0C03 -#define VX855_65_178M 0x00B60C05 -#define VX855_66_750M 0x00700C03 /*67.116MHz */ -#define VX855_67_295M 0x00BC0C05 -#define VX855_68_179M 0x00BF0C05 -#define VX855_68_369M 0x00BF0C05 -#define VX855_69_924M 0x00C30C05 -#define VX855_70_159M 0x00C30C05 -#define VX855_72_000M 0x00A10C04 -#define VX855_73_023M 0x00CC0C05 -#define VX855_74_481M 0x00D10C05 -#define VX855_78_750M 0x006E0805 -#define VX855_79_466M 0x006F0805 -#define VX855_80_136M 0x00700805 -#define VX855_81_627M 0x00720805 -#define VX855_83_375M 0x00750805 -#define VX855_83_527M 0x00750805 -#define VX855_83_950M 0x00750805 -#define VX855_84_537M 0x00760805 -#define VX855_84_750M 0x00760805 /* 84.537Mhz */ -#define VX855_85_500M 0x00760805 /* 85.909080 MHz*/ -#define VX855_85_860M 0x00760805 -#define VX855_85_909M 0x00760805 -#define VX855_88_750M 0x007C0805 -#define VX855_89_489M 0x007D0805 -#define VX855_94_500M 0x00840805 -#define VX855_96_648M 0x00870805 -#define VX855_97_750M 0x00890805 -#define VX855_101_000M 0x008D0805 -#define VX855_106_500M 0x00950805 -#define VX855_108_000M 0x00970805 -#define VX855_110_125M 0x00990805 -#define VX855_112_000M 0x009D0805 -#define VX855_113_309M 0x009F0805 -#define VX855_115_000M 0x00A10805 -#define VX855_118_840M 0x00A60805 -#define VX855_119_000M 0x00A70805 -#define VX855_121_750M 0x00AA0805 /* 121.704MHz */ -#define VX855_122_614M 0x00AC0805 -#define VX855_126_266M 0x00B10805 -#define VX855_130_250M 0x00B60805 /* 130.250 */ -#define VX855_135_000M 0x00BD0805 -#define VX855_136_700M 0x00BF0805 -#define VX855_137_750M 0x00C10805 -#define VX855_138_400M 0x00C20805 -#define VX855_144_300M 0x00CA0805 -#define VX855_146_760M 0x00CE0805 -#define VX855_148_500M 0x00D00805 -#define VX855_153_920M 0x00540402 -#define VX855_156_000M 0x006C0405 -#define VX855_156_867M 0x006E0405 -#define VX855_157_500M 0x006E0405 -#define VX855_162_000M 0x00710405 -#define VX855_172_798M 0x00790405 -#define VX855_187_000M 0x00830405 -#define VX855_193_295M 0x00870405 -#define VX855_202_500M 0x008E0405 -#define VX855_204_000M 0x008F0405 -#define VX855_218_500M 0x00990405 -#define VX855_229_500M 0x00A10405 -#define VX855_234_000M 0x00A40405 -#define VX855_267_250M 0x00BB0405 -#define VX855_297_500M 0x00D00405 -#define VX855_339_500M 0x00770005 -#define VX855_340_772M 0x00770005 - /* Definition CRTC Timing Index */ #define H_TOTAL_INDEX 0 diff --git a/drivers/video/via/via-core.c b/drivers/video/via/via-core.c index e8cfe8392110..66f403033111 100644 --- a/drivers/video/via/via-core.c +++ b/drivers/video/via/via-core.c @@ -64,7 +64,7 @@ static inline int viafb_mmio_read(int reg) */ static u32 viafb_enabled_ints; -static void viafb_int_init(void) +static void __devinit viafb_int_init(void) { viafb_enabled_ints = 0; @@ -489,7 +489,7 @@ out_unmap: return ret; } -static void __devexit via_pci_teardown_mmio(struct viafb_dev *vdev) +static void via_pci_teardown_mmio(struct viafb_dev *vdev) { iounmap(vdev->fbmem); iounmap(vdev->engine_mmio); @@ -548,7 +548,7 @@ static int __devinit via_setup_subdevs(struct viafb_dev *vdev) return 0; } -static void __devexit via_teardown_subdevs(void) +static void via_teardown_subdevs(void) { int i; @@ -613,22 +613,24 @@ static void __devexit via_pci_remove(struct pci_dev *pdev) static struct pci_device_id via_pci_table[] __devinitdata = { { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_CLE266_DID), .driver_data = UNICHROME_CLE266 }, - { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_PM800_DID), - .driver_data = UNICHROME_PM800 }, { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_K400_DID), .driver_data = UNICHROME_K400 }, { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_K800_DID), .driver_data = UNICHROME_K800 }, - { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_P4M890_DID), + { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_PM800_DID), + .driver_data = UNICHROME_PM800 }, + { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_CN700_DID), .driver_data = UNICHROME_CN700 }, - { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_K8M890_DID), - .driver_data = UNICHROME_K8M890 }, { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_CX700_DID), .driver_data = UNICHROME_CX700 }, - { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_P4M900_DID), - .driver_data = UNICHROME_P4M900 }, { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_CN750_DID), .driver_data = UNICHROME_CN750 }, + { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_K8M890_DID), + .driver_data = UNICHROME_K8M890 }, + { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_P4M890_DID), + .driver_data = UNICHROME_P4M890 }, + { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_P4M900_DID), + .driver_data = UNICHROME_P4M900 }, { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_VX800_DID), .driver_data = UNICHROME_VX800 }, { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_VX855_DID), diff --git a/drivers/video/via/via-gpio.c b/drivers/video/via/via-gpio.c index 595516aea691..39acb37e7a1d 100644 --- a/drivers/video/via/via-gpio.c +++ b/drivers/video/via/via-gpio.c @@ -73,7 +73,7 @@ struct viafb_gpio_cfg { struct gpio_chip gpio_chip; struct viafb_dev *vdev; struct viafb_gpio *active_gpios[VIAFB_NUM_GPIOS]; - char *gpio_names[VIAFB_NUM_GPIOS]; + const char *gpio_names[VIAFB_NUM_GPIOS]; }; /* diff --git a/drivers/video/via/viafbdev.c b/drivers/video/via/viafbdev.c index 2bc40e682f95..bdd0e4130f4e 100644 --- a/drivers/video/via/viafbdev.c +++ b/drivers/video/via/viafbdev.c @@ -49,11 +49,6 @@ char *viafb_active_dev; char *viafb_lcd_port = ""; char *viafb_dvi_port = ""; -static void viafb_set_device(struct device_t active_dev); -static int apply_device_setting(struct viafb_ioctl_setting setting_info, - struct fb_info *info); -static void apply_second_mode_setting(struct fb_var_screeninfo - *sec_var); static void retrieve_device_setting(struct viafb_ioctl_setting *setting_info); static int viafb_pan_display(struct fb_var_screeninfo *var, @@ -221,9 +216,9 @@ static int viafb_check_var(struct fb_var_screeninfo *var, /* Adjust var according to our driver's own table */ viafb_fill_var_timing_info(var, viafb_refresh, vmode_entry); - if (info->var.accel_flags & FB_ACCELF_TEXT && + if (var->accel_flags & FB_ACCELF_TEXT && !ppar->shared->vdev->engine_mmio) - info->var.accel_flags = 0; + var->accel_flags = 0; return 0; } @@ -234,6 +229,7 @@ static int viafb_set_par(struct fb_info *info) struct VideoModeTable *vmode_entry, *vmode_entry1 = NULL; DEBUG_MSG(KERN_INFO "viafb_set_par!\n"); + viafb_update_fix(info); viapar->depth = fb_get_color_depth(&info->var, &info->fix); viafb_update_device_setting(viafbinfo->var.xres, viafbinfo->var.yres, viafbinfo->var.bits_per_pixel, viafb_refresh, 0); @@ -257,7 +253,6 @@ static int viafb_set_par(struct fb_info *info) } if (vmode_entry) { - viafb_update_fix(info); if (viafb_dual_fb && viapar->iga_path == IGA2) viafb_bpp1 = info->var.bits_per_pixel; else @@ -478,13 +473,6 @@ static int viafb_ioctl(struct fb_info *info, u_int cmd, u_long arg) if (gpu32 & LCD_Device) viafb_lcd_disable(); break; - case VIAFB_SET_DEVICE: - if (copy_from_user(&u.active_dev, (void *)argp, - sizeof(u.active_dev))) - return -EFAULT; - viafb_set_device(u.active_dev); - viafb_set_par(info); - break; case VIAFB_GET_DEVICE: u.active_dev.crt = viafb_CRT_ON; u.active_dev.dvi = viafb_DVI_ON; @@ -527,21 +515,6 @@ static int viafb_ioctl(struct fb_info *info, u_int cmd, u_long arg) break; - case VIAFB_SET_DEVICE_INFO: - if (copy_from_user(&u.viafb_setting, - argp, sizeof(u.viafb_setting))) - return -EFAULT; - if (apply_device_setting(u.viafb_setting, info) < 0) - return -EINVAL; - - break; - - case VIAFB_SET_SECOND_MODE: - if (copy_from_user(&u.sec_var, argp, sizeof(u.sec_var))) - return -EFAULT; - apply_second_mode_setting(&u.sec_var); - break; - case VIAFB_GET_DEVICE_INFO: retrieve_device_setting(&u.viafb_setting); @@ -578,14 +551,9 @@ static int viafb_ioctl(struct fb_info *info, u_int cmd, u_long arg) break; case VIAFB_SET_GAMMA_LUT: - viafb_gamma_table = kmalloc(256 * sizeof(u32), GFP_KERNEL); - if (!viafb_gamma_table) - return -ENOMEM; - if (copy_from_user(viafb_gamma_table, argp, - 256 * sizeof(u32))) { - kfree(viafb_gamma_table); - return -EFAULT; - } + viafb_gamma_table = memdup_user(argp, 256 * sizeof(u32)); + if (IS_ERR(viafb_gamma_table)) + return PTR_ERR(viafb_gamma_table); viafb_set_gamma_table(viafb_bpp, viafb_gamma_table); kfree(viafb_gamma_table); break; @@ -918,112 +886,6 @@ static int viafb_sync(struct fb_info *info) return 0; } -static void check_available_device_to_enable(int device_id) -{ - int device_num = 0; - - /* Initialize: */ - viafb_CRT_ON = STATE_OFF; - viafb_DVI_ON = STATE_OFF; - viafb_LCD_ON = STATE_OFF; - viafb_LCD2_ON = STATE_OFF; - viafb_DeviceStatus = None_Device; - - if ((device_id & CRT_Device) && (device_num < MAX_ACTIVE_DEV_NUM)) { - viafb_CRT_ON = STATE_ON; - device_num++; - viafb_DeviceStatus |= CRT_Device; - } - - if ((device_id & DVI_Device) && (device_num < MAX_ACTIVE_DEV_NUM)) { - viafb_DVI_ON = STATE_ON; - device_num++; - viafb_DeviceStatus |= DVI_Device; - } - - if ((device_id & LCD_Device) && (device_num < MAX_ACTIVE_DEV_NUM)) { - viafb_LCD_ON = STATE_ON; - device_num++; - viafb_DeviceStatus |= LCD_Device; - } - - if ((device_id & LCD2_Device) && (device_num < MAX_ACTIVE_DEV_NUM)) { - viafb_LCD2_ON = STATE_ON; - device_num++; - viafb_DeviceStatus |= LCD2_Device; - } - - if (viafb_DeviceStatus == None_Device) { - /* Use CRT as default active device: */ - viafb_CRT_ON = STATE_ON; - viafb_DeviceStatus = CRT_Device; - } - DEBUG_MSG(KERN_INFO "Device Status:%x", viafb_DeviceStatus); -} - -static void viafb_set_device(struct device_t active_dev) -{ - /* Check available device to enable: */ - int device_id = None_Device; - if (active_dev.crt) - device_id |= CRT_Device; - if (active_dev.dvi) - device_id |= DVI_Device; - if (active_dev.lcd) - device_id |= LCD_Device; - - check_available_device_to_enable(device_id); - - /* Check property of LCD: */ - if (viafb_LCD_ON) { - if (active_dev.lcd_dsp_cent) { - viaparinfo->lvds_setting_info->display_method = - viafb_lcd_dsp_method = LCD_CENTERING; - } else { - viaparinfo->lvds_setting_info->display_method = - viafb_lcd_dsp_method = LCD_EXPANDSION; - } - - if (active_dev.lcd_mode == LCD_SPWG) { - viaparinfo->lvds_setting_info->lcd_mode = - viafb_lcd_mode = LCD_SPWG; - } else { - viaparinfo->lvds_setting_info->lcd_mode = - viafb_lcd_mode = LCD_OPENLDI; - } - - if (active_dev.lcd_panel_id <= LCD_PANEL_ID_MAXIMUM) { - viafb_lcd_panel_id = active_dev.lcd_panel_id; - viafb_init_lcd_size(); - } - } - - /* Check property of mode: */ - if (!active_dev.xres1) - viafb_second_xres = 640; - else - viafb_second_xres = active_dev.xres1; - if (!active_dev.yres1) - viafb_second_yres = 480; - else - viafb_second_yres = active_dev.yres1; - if (active_dev.bpp != 0) - viafb_bpp = active_dev.bpp; - if (active_dev.bpp1 != 0) - viafb_bpp1 = active_dev.bpp1; - if (active_dev.refresh != 0) - viafb_refresh = active_dev.refresh; - if (active_dev.refresh1 != 0) - viafb_refresh1 = active_dev.refresh1; - if ((active_dev.samm == STATE_OFF) || (active_dev.samm == STATE_ON)) - viafb_SAMM_ON = active_dev.samm; - viafb_primary_dev = active_dev.primary_dev; - - via_set_primary_address(0); - via_set_secondary_address(viafb_SAMM_ON ? viafb_second_offset : 0); - viafb_set_iga_path(); -} - static int get_primary_device(void) { int primary_device = 0; @@ -1065,124 +927,6 @@ static int get_primary_device(void) return primary_device; } -static void apply_second_mode_setting(struct fb_var_screeninfo - *sec_var) -{ - u32 htotal, vtotal, long_refresh; - - htotal = sec_var->xres + sec_var->left_margin + - sec_var->right_margin + sec_var->hsync_len; - vtotal = sec_var->yres + sec_var->upper_margin + - sec_var->lower_margin + sec_var->vsync_len; - if ((sec_var->xres_virtual * (sec_var->bits_per_pixel >> 3)) & 0x1F) { - /*Is 32 bytes alignment? */ - /*32 pixel alignment */ - sec_var->xres_virtual = (sec_var->xres_virtual + 31) & ~31; - } - - htotal = sec_var->xres + sec_var->left_margin + - sec_var->right_margin + sec_var->hsync_len; - vtotal = sec_var->yres + sec_var->upper_margin + - sec_var->lower_margin + sec_var->vsync_len; - long_refresh = 1000000000UL / sec_var->pixclock * 1000; - long_refresh /= (htotal * vtotal); - - viafb_second_xres = sec_var->xres; - viafb_second_yres = sec_var->yres; - viafb_second_virtual_xres = sec_var->xres_virtual; - viafb_second_virtual_yres = sec_var->yres_virtual; - viafb_bpp1 = sec_var->bits_per_pixel; - viafb_refresh1 = viafb_get_refresh(sec_var->xres, sec_var->yres, - long_refresh); -} - -static int apply_device_setting(struct viafb_ioctl_setting setting_info, - struct fb_info *info) -{ - int need_set_mode = 0; - DEBUG_MSG(KERN_INFO "apply_device_setting\n"); - - if (setting_info.device_flag) { - need_set_mode = 1; - check_available_device_to_enable(setting_info.device_status); - } - - /* Unlock LCD's operation according to LCD flag - and check if the setting value is valid. */ - /* If the value is valid, apply the new setting value to the device. */ - if (viafb_LCD_ON) { - if (setting_info.lcd_operation_flag & OP_LCD_CENTERING) { - need_set_mode = 1; - if (setting_info.lcd_attributes.display_center) { - /* Centering */ - viaparinfo->lvds_setting_info->display_method = - LCD_CENTERING; - viafb_lcd_dsp_method = LCD_CENTERING; - viaparinfo->lvds_setting_info2->display_method = - viafb_lcd_dsp_method = LCD_CENTERING; - } else { - /* expandsion */ - viaparinfo->lvds_setting_info->display_method = - LCD_EXPANDSION; - viafb_lcd_dsp_method = LCD_EXPANDSION; - viaparinfo->lvds_setting_info2->display_method = - LCD_EXPANDSION; - viafb_lcd_dsp_method = LCD_EXPANDSION; - } - } - - if (setting_info.lcd_operation_flag & OP_LCD_MODE) { - need_set_mode = 1; - if (setting_info.lcd_attributes.lcd_mode == - LCD_SPWG) { - viaparinfo->lvds_setting_info->lcd_mode = - viafb_lcd_mode = LCD_SPWG; - } else { - viaparinfo->lvds_setting_info->lcd_mode = - viafb_lcd_mode = LCD_OPENLDI; - } - viaparinfo->lvds_setting_info2->lcd_mode = - viaparinfo->lvds_setting_info->lcd_mode; - } - - if (setting_info.lcd_operation_flag & OP_LCD_PANEL_ID) { - need_set_mode = 1; - if (setting_info.lcd_attributes.panel_id <= - LCD_PANEL_ID_MAXIMUM) { - viafb_lcd_panel_id = - setting_info.lcd_attributes.panel_id; - viafb_init_lcd_size(); - } - } - } - - if (0 != (setting_info.samm_status & OP_SAMM)) { - setting_info.samm_status = - setting_info.samm_status & (~OP_SAMM); - if (setting_info.samm_status == 0 - || setting_info.samm_status == 1) { - viafb_SAMM_ON = setting_info.samm_status; - - if (viafb_SAMM_ON) - viafb_primary_dev = setting_info.primary_device; - - via_set_primary_address(0); - via_set_secondary_address(viafb_SAMM_ON ? - viafb_second_offset : 0); - viafb_set_iga_path(); - } - need_set_mode = 1; - } - - if (!need_set_mode) { - ; - } else { - viafb_set_iga_path(); - viafb_set_par(info); - } - return true; -} - static void retrieve_device_setting(struct viafb_ioctl_setting *setting_info) { @@ -1781,10 +1525,6 @@ int __devinit via_fb_pci_probe(struct viafb_dev *vdev) parse_lcd_port(); parse_dvi_port(); - /* for dual-fb must viafb_SAMM_ON=1 and viafb_dual_fb=1 */ - if (!viafb_SAMM_ON) - viafb_dual_fb = 0; - viafb_init_chip_info(vdev->chip_type); /* * The framebuffer will have been successfully mapped by @@ -1828,30 +1568,13 @@ int __devinit via_fb_pci_probe(struct viafb_dev *vdev) parse_mode(viafb_mode1, &viafb_second_xres, &viafb_second_yres); - if (0 == viafb_second_virtual_xres) { - switch (viafb_second_xres) { - case 1400: - viafb_second_virtual_xres = 1408; - break; - default: - viafb_second_virtual_xres = viafb_second_xres; - break; - } - } - if (0 == viafb_second_virtual_yres) - viafb_second_virtual_yres = viafb_second_yres; + viafb_second_virtual_xres = viafb_second_xres; + viafb_second_virtual_yres = viafb_second_yres; } default_var.xres = default_xres; default_var.yres = default_yres; - switch (default_xres) { - case 1400: - default_var.xres_virtual = 1408; - break; - default: - default_var.xres_virtual = default_xres; - break; - } + default_var.xres_virtual = default_xres; default_var.yres_virtual = default_yres; default_var.bits_per_pixel = viafb_bpp; default_var.pixclock = diff --git a/drivers/video/w100fb.c b/drivers/video/w100fb.c index 31b0e17ed090..d8b12c32e3ef 100644 --- a/drivers/video/w100fb.c +++ b/drivers/video/w100fb.c @@ -53,7 +53,7 @@ static void w100_update_enable(void); static void w100_update_disable(void); static void calc_hsync(struct w100fb_par *par); static void w100_init_graphic_engine(struct w100fb_par *par); -struct w100_pll_info *w100_get_xtal_table(unsigned int freq); +struct w100_pll_info *w100_get_xtal_table(unsigned int freq) __devinit; /* Pseudo palette size */ #define MAX_PALETTES 16 @@ -782,7 +782,7 @@ out: } -static int w100fb_remove(struct platform_device *pdev) +static int __devexit w100fb_remove(struct platform_device *pdev) { struct fb_info *info = platform_get_drvdata(pdev); struct w100fb_par *par=info->par; @@ -858,9 +858,9 @@ unsigned long w100fb_gpio_read(int port) void w100fb_gpio_write(int port, unsigned long value) { if (port==W100_GPIO_PORT_A) - value = writel(value, remapped_regs + mmGPIO_DATA); + writel(value, remapped_regs + mmGPIO_DATA); else - value = writel(value, remapped_regs + mmGPIO_DATA2); + writel(value, remapped_regs + mmGPIO_DATA2); } EXPORT_SYMBOL(w100fb_gpio_read); EXPORT_SYMBOL(w100fb_gpio_write); @@ -1020,7 +1020,7 @@ static struct pll_entries { { 0 }, }; -struct w100_pll_info *w100_get_xtal_table(unsigned int freq) +struct w100_pll_info __devinit *w100_get_xtal_table(unsigned int freq) { struct pll_entries *pll_entry = w100_pll_tables; @@ -1611,7 +1611,7 @@ static void w100_vsync(void) static struct platform_driver w100fb_driver = { .probe = w100fb_probe, - .remove = w100fb_remove, + .remove = __devexit_p(w100fb_remove), .suspend = w100fb_suspend, .resume = w100fb_resume, .driver = { @@ -1619,7 +1619,7 @@ static struct platform_driver w100fb_driver = { }, }; -int __devinit w100fb_init(void) +int __init w100fb_init(void) { return platform_driver_register(&w100fb_driver); } diff --git a/drivers/video/xen-fbfront.c b/drivers/video/xen-fbfront.c index fa97d3e7c21a..7c7f42a12796 100644 --- a/drivers/video/xen-fbfront.c +++ b/drivers/video/xen-fbfront.c @@ -684,7 +684,7 @@ static struct xenbus_driver xenfb_driver = { static int __init xenfb_init(void) { - if (!xen_domain()) + if (!xen_pv_domain()) return -ENODEV; /* Nothing to do if running in dom0. */ diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c index 3fcb83f03881..29b5daacc217 100644 --- a/drivers/video/xilinxfb.c +++ b/drivers/video/xilinxfb.c @@ -423,7 +423,7 @@ xilinxfb_of_probe(struct of_device *op, const struct of_device_id *match) * To check whether the core is connected directly to DCR or PLB * interface and initialize the tft_access accordingly. */ - p = (u32 *)of_get_property(op->node, "xlnx,dcr-splb-slave-if", NULL); + p = (u32 *)of_get_property(op->dev.of_node, "xlnx,dcr-splb-slave-if", NULL); tft_access = p ? *p : 0; /* @@ -432,41 +432,41 @@ xilinxfb_of_probe(struct of_device *op, const struct of_device_id *match) */ if (tft_access) { drvdata->flags |= PLB_ACCESS_FLAG; - rc = of_address_to_resource(op->node, 0, &res); + rc = of_address_to_resource(op->dev.of_node, 0, &res); if (rc) { dev_err(&op->dev, "invalid address\n"); goto err; } } else { res.start = 0; - start = dcr_resource_start(op->node, 0); - drvdata->dcr_len = dcr_resource_len(op->node, 0); - drvdata->dcr_host = dcr_map(op->node, start, drvdata->dcr_len); + start = dcr_resource_start(op->dev.of_node, 0); + drvdata->dcr_len = dcr_resource_len(op->dev.of_node, 0); + drvdata->dcr_host = dcr_map(op->dev.of_node, start, drvdata->dcr_len); if (!DCR_MAP_OK(drvdata->dcr_host)) { dev_err(&op->dev, "invalid DCR address\n"); goto err; } } - prop = of_get_property(op->node, "phys-size", &size); + prop = of_get_property(op->dev.of_node, "phys-size", &size); if ((prop) && (size >= sizeof(u32)*2)) { pdata.screen_width_mm = prop[0]; pdata.screen_height_mm = prop[1]; } - prop = of_get_property(op->node, "resolution", &size); + prop = of_get_property(op->dev.of_node, "resolution", &size); if ((prop) && (size >= sizeof(u32)*2)) { pdata.xres = prop[0]; pdata.yres = prop[1]; } - prop = of_get_property(op->node, "virtual-resolution", &size); + prop = of_get_property(op->dev.of_node, "virtual-resolution", &size); if ((prop) && (size >= sizeof(u32)*2)) { pdata.xvirt = prop[0]; pdata.yvirt = prop[1]; } - if (of_find_property(op->node, "rotate-display", NULL)) + if (of_find_property(op->dev.of_node, "rotate-display", NULL)) pdata.rotate_screen = 1; dev_set_drvdata(&op->dev, drvdata); @@ -485,6 +485,8 @@ static int __devexit xilinxfb_of_remove(struct of_device *op) /* Match table for of_platform binding */ static struct of_device_id xilinxfb_of_match[] __devinitdata = { { .compatible = "xlnx,xps-tft-1.00.a", }, + { .compatible = "xlnx,xps-tft-2.00.a", }, + { .compatible = "xlnx,xps-tft-2.01.a", }, { .compatible = "xlnx,plb-tft-cntlr-ref-1.00.a", }, { .compatible = "xlnx,plb-dvi-cntlr-ref-1.00.c", }, {}, @@ -492,13 +494,12 @@ static struct of_device_id xilinxfb_of_match[] __devinitdata = { MODULE_DEVICE_TABLE(of, xilinxfb_of_match); static struct of_platform_driver xilinxfb_of_driver = { - .owner = THIS_MODULE, - .name = DRIVER_NAME, - .match_table = xilinxfb_of_match, .probe = xilinxfb_of_probe, .remove = __devexit_p(xilinxfb_of_remove), .driver = { .name = DRIVER_NAME, + .owner = THIS_MODULE, + .of_match_table = xilinxfb_of_match, }, }; |