diff options
Diffstat (limited to 'drivers/video')
46 files changed, 1985 insertions, 195 deletions
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 99c0df1c7eb..5a5c303a637 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -614,6 +614,21 @@ config FB_BFIN_T350MCQB This display is a QVGA 320x240 24-bit RGB display interfaced by an 8-bit wide PPI It uses PPI[0..7] PPI_FS1, PPI_FS2 and PPI_CLK. +config FB_BFIN_LQ035Q1 + tristate "SHARP LQ035Q1DH02 TFT LCD" + depends on FB && BLACKFIN && SPI + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select BFIN_GPTIMERS + help + This is the framebuffer device driver for a SHARP LQ035Q1DH02 TFT display found on + the Blackfin Landscape LCD EZ-Extender Card. + This display is a QVGA 320x240 18-bit RGB display interfaced by an 16-bit wide PPI + It uses PPI[0..15] PPI_FS1, PPI_FS2 and PPI_CLK. + + To compile this driver as a module, choose M here: the + module will be called bfin-lq035q1-fb. config FB_STI tristate "HP STI frame buffer device support" diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 0f8da331ba0..4ecb30c4f3f 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -137,6 +137,7 @@ obj-$(CONFIG_FB_EFI) += efifb.o obj-$(CONFIG_FB_VGA16) += vga16fb.o obj-$(CONFIG_FB_OF) += offb.o obj-$(CONFIG_FB_BF54X_LQ043) += bf54x-lq043fb.o +obj-$(CONFIG_FB_BFIN_LQ035Q1) += bfin-lq035q1-fb.o obj-$(CONFIG_FB_BFIN_T350MCQB) += bfin-t350mcqb-fb.o obj-$(CONFIG_FB_MX3) += mx3fb.o obj-$(CONFIG_FB_DA8XX) += da8xx-fb.o diff --git a/drivers/video/backlight/adp5520_bl.c b/drivers/video/backlight/adp5520_bl.c index 4c10edecfb6..86d95c228ad 100644 --- a/drivers/video/backlight/adp5520_bl.c +++ b/drivers/video/backlight/adp5520_bl.c @@ -85,7 +85,7 @@ static int adp5520_bl_get_brightness(struct backlight_device *bl) return error ? data->current_brightness : reg_val; } -static struct backlight_ops adp5520_bl_ops = { +static const struct backlight_ops adp5520_bl_ops = { .update_status = adp5520_bl_update_status, .get_brightness = adp5520_bl_get_brightness, }; diff --git a/drivers/video/backlight/adx_bl.c b/drivers/video/backlight/adx_bl.c index 2c3bdfc620b..d769b0bab21 100644 --- a/drivers/video/backlight/adx_bl.c +++ b/drivers/video/backlight/adx_bl.c @@ -61,7 +61,7 @@ static int adx_backlight_check_fb(struct fb_info *fb) return 1; } -static struct backlight_ops adx_backlight_ops = { +static const struct backlight_ops adx_backlight_ops = { .options = 0, .update_status = adx_backlight_update_status, .get_brightness = adx_backlight_get_brightness, diff --git a/drivers/video/backlight/atmel-pwm-bl.c b/drivers/video/backlight/atmel-pwm-bl.c index 2cf7ba52f67..f625ffc69ad 100644 --- a/drivers/video/backlight/atmel-pwm-bl.c +++ b/drivers/video/backlight/atmel-pwm-bl.c @@ -113,7 +113,7 @@ static int atmel_pwm_bl_init_pwm(struct atmel_pwm_bl *pwmbl) return pwm_channel_enable(&pwmbl->pwmc); } -static struct backlight_ops atmel_pwm_bl_ops = { +static const struct backlight_ops atmel_pwm_bl_ops = { .get_brightness = atmel_pwm_bl_get_intensity, .update_status = atmel_pwm_bl_set_intensity, }; diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c index 6615ac7fa60..18829cf68b1 100644 --- a/drivers/video/backlight/backlight.c +++ b/drivers/video/backlight/backlight.c @@ -269,7 +269,7 @@ EXPORT_SYMBOL(backlight_force_update); * ERR_PTR() or a pointer to the newly allocated device. */ struct backlight_device *backlight_device_register(const char *name, - struct device *parent, void *devdata, struct backlight_ops *ops) + struct device *parent, void *devdata, const struct backlight_ops *ops) { struct backlight_device *new_bd; int rc; diff --git a/drivers/video/backlight/corgi_lcd.c b/drivers/video/backlight/corgi_lcd.c index 96774949cd3..b4bcf804379 100644 --- a/drivers/video/backlight/corgi_lcd.c +++ b/drivers/video/backlight/corgi_lcd.c @@ -451,7 +451,7 @@ void corgi_lcd_limit_intensity(int limit) } EXPORT_SYMBOL(corgi_lcd_limit_intensity); -static struct backlight_ops corgi_bl_ops = { +static const struct backlight_ops corgi_bl_ops = { .get_brightness = corgi_bl_get_intensity, .update_status = corgi_bl_update_status, }; diff --git a/drivers/video/backlight/cr_bllcd.c b/drivers/video/backlight/cr_bllcd.c index b9fe62b475c..da86db4374a 100644 --- a/drivers/video/backlight/cr_bllcd.c +++ b/drivers/video/backlight/cr_bllcd.c @@ -108,7 +108,7 @@ static int cr_backlight_get_intensity(struct backlight_device *bd) return intensity; } -static struct backlight_ops cr_backlight_ops = { +static const struct backlight_ops cr_backlight_ops = { .get_brightness = cr_backlight_get_intensity, .update_status = cr_backlight_set_intensity, }; @@ -201,7 +201,7 @@ static int cr_backlight_probe(struct platform_device *pdev) if (IS_ERR(ldp)) { backlight_device_unregister(bdp); pci_dev_put(lpc_dev); - return PTR_ERR(bdp); + return PTR_ERR(ldp); } pci_read_config_dword(lpc_dev, CRVML_REG_GPIOBAR, diff --git a/drivers/video/backlight/da903x_bl.c b/drivers/video/backlight/da903x_bl.c index f2d76dae1eb..74cdc640173 100644 --- a/drivers/video/backlight/da903x_bl.c +++ b/drivers/video/backlight/da903x_bl.c @@ -95,7 +95,7 @@ static int da903x_backlight_get_brightness(struct backlight_device *bl) return data->current_brightness; } -static struct backlight_ops da903x_backlight_ops = { +static const struct backlight_ops da903x_backlight_ops = { .update_status = da903x_backlight_update_status, .get_brightness = da903x_backlight_get_brightness, }; diff --git a/drivers/video/backlight/generic_bl.c b/drivers/video/backlight/generic_bl.c index 6d27f62fdcd..e6d348e6359 100644 --- a/drivers/video/backlight/generic_bl.c +++ b/drivers/video/backlight/generic_bl.c @@ -70,7 +70,7 @@ void corgibl_limit_intensity(int limit) } EXPORT_SYMBOL(corgibl_limit_intensity); -static struct backlight_ops genericbl_ops = { +static const struct backlight_ops genericbl_ops = { .options = BL_CORE_SUSPENDRESUME, .get_brightness = genericbl_get_intensity, .update_status = genericbl_send_intensity, diff --git a/drivers/video/backlight/hp680_bl.c b/drivers/video/backlight/hp680_bl.c index 7fb4eefff80..f7cc528d5be 100644 --- a/drivers/video/backlight/hp680_bl.c +++ b/drivers/video/backlight/hp680_bl.c @@ -98,7 +98,7 @@ static int hp680bl_get_intensity(struct backlight_device *bd) return current_intensity; } -static struct backlight_ops hp680bl_ops = { +static const struct backlight_ops hp680bl_ops = { .get_brightness = hp680bl_get_intensity, .update_status = hp680bl_set_intensity, }; diff --git a/drivers/video/backlight/jornada720_bl.c b/drivers/video/backlight/jornada720_bl.c index 7aed2565c1b..db9071fc566 100644 --- a/drivers/video/backlight/jornada720_bl.c +++ b/drivers/video/backlight/jornada720_bl.c @@ -93,7 +93,7 @@ out: return ret; } -static struct backlight_ops jornada_bl_ops = { +static const struct backlight_ops jornada_bl_ops = { .get_brightness = jornada_bl_get_brightness, .update_status = jornada_bl_update_status, .options = BL_CORE_SUSPENDRESUME, diff --git a/drivers/video/backlight/kb3886_bl.c b/drivers/video/backlight/kb3886_bl.c index a38fda1742d..939e7b830cf 100644 --- a/drivers/video/backlight/kb3886_bl.c +++ b/drivers/video/backlight/kb3886_bl.c @@ -134,7 +134,7 @@ static int kb3886bl_get_intensity(struct backlight_device *bd) return kb3886bl_intensity; } -static struct backlight_ops kb3886bl_ops = { +static const struct backlight_ops kb3886bl_ops = { .get_brightness = kb3886bl_get_intensity, .update_status = kb3886bl_send_intensity, }; diff --git a/drivers/video/backlight/locomolcd.c b/drivers/video/backlight/locomolcd.c index 6b488b8a7ee..00a9591b000 100644 --- a/drivers/video/backlight/locomolcd.c +++ b/drivers/video/backlight/locomolcd.c @@ -141,7 +141,7 @@ static int locomolcd_get_intensity(struct backlight_device *bd) return current_intensity; } -static struct backlight_ops locomobl_data = { +static const struct backlight_ops locomobl_data = { .get_brightness = locomolcd_get_intensity, .update_status = locomolcd_set_intensity, }; diff --git a/drivers/video/backlight/mbp_nvidia_bl.c b/drivers/video/backlight/mbp_nvidia_bl.c index 9edb8d7c295..2e78b0784bd 100644 --- a/drivers/video/backlight/mbp_nvidia_bl.c +++ b/drivers/video/backlight/mbp_nvidia_bl.c @@ -33,7 +33,7 @@ struct dmi_match_data { unsigned long iostart; unsigned long iolen; /* Backlight operations structure. */ - struct backlight_ops backlight_ops; + const struct backlight_ops backlight_ops; }; /* Module parameters. */ @@ -220,6 +220,24 @@ static const struct dmi_system_id __initdata mbp_device_table[] = { }, { .callback = mbp_dmi_match, + .ident = "MacBookPro 5,3", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5,3"), + }, + .driver_data = (void *)&nvidia_chipset_data, + }, + { + .callback = mbp_dmi_match, + .ident = "MacBookPro 5,4", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5,4"), + }, + .driver_data = (void *)&nvidia_chipset_data, + }, + { + .callback = mbp_dmi_match, .ident = "MacBookPro 5,5", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), diff --git a/drivers/video/backlight/omap1_bl.c b/drivers/video/backlight/omap1_bl.c index 8693e5fcd2e..409ca964352 100644 --- a/drivers/video/backlight/omap1_bl.c +++ b/drivers/video/backlight/omap1_bl.c @@ -125,7 +125,7 @@ static int omapbl_get_intensity(struct backlight_device *dev) return bl->current_intensity; } -static struct backlight_ops omapbl_ops = { +static const struct backlight_ops omapbl_ops = { .get_brightness = omapbl_get_intensity, .update_status = omapbl_update_status, }; diff --git a/drivers/video/backlight/progear_bl.c b/drivers/video/backlight/progear_bl.c index 9edaf24fd82..075786e0503 100644 --- a/drivers/video/backlight/progear_bl.c +++ b/drivers/video/backlight/progear_bl.c @@ -54,7 +54,7 @@ static int progearbl_get_intensity(struct backlight_device *bd) return intensity - HW_LEVEL_MIN; } -static struct backlight_ops progearbl_ops = { +static const struct backlight_ops progearbl_ops = { .get_brightness = progearbl_get_intensity, .update_status = progearbl_set_intensity, }; diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c index 88716626744..9d2ec2a1cce 100644 --- a/drivers/video/backlight/pwm_bl.c +++ b/drivers/video/backlight/pwm_bl.c @@ -22,8 +22,10 @@ struct pwm_bl_data { struct pwm_device *pwm; + struct device *dev; unsigned int period; - int (*notify)(int brightness); + int (*notify)(struct device *, + int brightness); }; static int pwm_backlight_update_status(struct backlight_device *bl) @@ -39,7 +41,7 @@ static int pwm_backlight_update_status(struct backlight_device *bl) brightness = 0; if (pb->notify) - brightness = pb->notify(brightness); + brightness = pb->notify(pb->dev, brightness); if (brightness == 0) { pwm_config(pb->pwm, 0, pb->period); @@ -56,7 +58,7 @@ static int pwm_backlight_get_brightness(struct backlight_device *bl) return bl->props.brightness; } -static struct backlight_ops pwm_backlight_ops = { +static const struct backlight_ops pwm_backlight_ops = { .update_status = pwm_backlight_update_status, .get_brightness = pwm_backlight_get_brightness, }; @@ -88,6 +90,7 @@ static int pwm_backlight_probe(struct platform_device *pdev) pb->period = data->pwm_period_ns; pb->notify = data->notify; + pb->dev = &pdev->dev; pb->pwm = pwm_request(data->pwm_id, "backlight"); if (IS_ERR(pb->pwm)) { @@ -146,7 +149,7 @@ static int pwm_backlight_suspend(struct platform_device *pdev, struct pwm_bl_data *pb = dev_get_drvdata(&bl->dev); if (pb->notify) - pb->notify(0); + pb->notify(pb->dev, 0); pwm_config(pb->pwm, 0, pb->period); pwm_disable(pb->pwm); return 0; diff --git a/drivers/video/backlight/tosa_bl.c b/drivers/video/backlight/tosa_bl.c index 43edbada12d..e14ce4d469f 100644 --- a/drivers/video/backlight/tosa_bl.c +++ b/drivers/video/backlight/tosa_bl.c @@ -72,7 +72,7 @@ static int tosa_bl_get_brightness(struct backlight_device *dev) return props->brightness; } -static struct backlight_ops bl_ops = { +static const struct backlight_ops bl_ops = { .get_brightness = tosa_bl_get_brightness, .update_status = tosa_bl_update_status, }; diff --git a/drivers/video/backlight/wm831x_bl.c b/drivers/video/backlight/wm831x_bl.c index 467bdb7efb2..e32add37a20 100644 --- a/drivers/video/backlight/wm831x_bl.c +++ b/drivers/video/backlight/wm831x_bl.c @@ -112,7 +112,7 @@ static int wm831x_backlight_get_brightness(struct backlight_device *bl) return data->current_brightness; } -static struct backlight_ops wm831x_backlight_ops = { +static const struct backlight_ops wm831x_backlight_ops = { .options = BL_CORE_SUSPENDRESUME, .update_status = wm831x_backlight_update_status, .get_brightness = wm831x_backlight_get_brightness, diff --git a/drivers/video/bfin-lq035q1-fb.c b/drivers/video/bfin-lq035q1-fb.c new file mode 100644 index 00000000000..b690c269784 --- /dev/null +++ b/drivers/video/bfin-lq035q1-fb.c @@ -0,0 +1,826 @@ +/* + * Blackfin LCD Framebuffer driver SHARP LQ035Q1DH02 + * + * Copyright 2008-2009 Analog Devices Inc. + * Licensed under the GPL-2 or later. + */ + +#define DRIVER_NAME "bfin-lq035q1" +#define pr_fmt(fmt) DRIVER_NAME ": " fmt + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <linux/types.h> +#include <linux/interrupt.h> +#include <linux/device.h> +#include <linux/backlight.h> +#include <linux/lcd.h> +#include <linux/dma-mapping.h> +#include <linux/platform_device.h> +#include <linux/spi/spi.h> +#include <linux/dma-mapping.h> + +#include <asm/blackfin.h> +#include <asm/irq.h> +#include <asm/dma.h> +#include <asm/portmux.h> +#include <asm/gptimers.h> + +#include <asm/bfin-lq035q1.h> + +#if defined(BF533_FAMILY) || defined(BF538_FAMILY) +#define TIMER_HSYNC_id TIMER1_id +#define TIMER_HSYNCbit TIMER1bit +#define TIMER_HSYNC_STATUS_TRUN TIMER_STATUS_TRUN1 +#define TIMER_HSYNC_STATUS_TIMIL TIMER_STATUS_TIMIL1 +#define TIMER_HSYNC_STATUS_TOVF TIMER_STATUS_TOVF1 + +#define TIMER_VSYNC_id TIMER2_id +#define TIMER_VSYNCbit TIMER2bit +#define TIMER_VSYNC_STATUS_TRUN TIMER_STATUS_TRUN2 +#define TIMER_VSYNC_STATUS_TIMIL TIMER_STATUS_TIMIL2 +#define TIMER_VSYNC_STATUS_TOVF TIMER_STATUS_TOVF2 +#else +#define TIMER_HSYNC_id TIMER0_id +#define TIMER_HSYNCbit TIMER0bit +#define TIMER_HSYNC_STATUS_TRUN TIMER_STATUS_TRUN0 +#define TIMER_HSYNC_STATUS_TIMIL TIMER_STATUS_TIMIL0 +#define TIMER_HSYNC_STATUS_TOVF TIMER_STATUS_TOVF0 + +#define TIMER_VSYNC_id TIMER1_id +#define TIMER_VSYNCbit TIMER1bit +#define TIMER_VSYNC_STATUS_TRUN TIMER_STATUS_TRUN1 +#define TIMER_VSYNC_STATUS_TIMIL TIMER_STATUS_TIMIL1 +#define TIMER_VSYNC_STATUS_TOVF TIMER_STATUS_TOVF1 +#endif + +#define LCD_X_RES 320 /* Horizontal Resolution */ +#define LCD_Y_RES 240 /* Vertical Resolution */ +#define DMA_BUS_SIZE 16 + +#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 + +#define PPI_TX_MODE 0x2 +#define PPI_XFER_TYPE_11 0xC +#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 + +#define LQ035_DRIVER_OUTPUT_CTL 0x1 +#define LQ035_SHUT_CTL 0x11 + +#define LQ035_DRIVER_OUTPUT_MASK (LQ035_LR | LQ035_TB | LQ035_BGR | LQ035_REV) +#define LQ035_DRIVER_OUTPUT_DEFAULT (0x2AEF & ~LQ035_DRIVER_OUTPUT_MASK) + +#define LQ035_SHUT (1 << 0) /* Shutdown */ +#define LQ035_ON (0 << 0) /* Shutdown */ + +struct bfin_lq035q1fb_info { + struct fb_info *fb; + struct device *dev; + struct spi_driver spidrv; + struct bfin_lq035q1fb_disp_info *disp_info; + unsigned char *fb_buffer; /* RGB Buffer */ + dma_addr_t dma_handle; + int lq035_open_cnt; + int irq; + spinlock_t lock; /* lock */ + u32 pseudo_pal[16]; +}; + +static int nocursor; +module_param(nocursor, int, 0644); +MODULE_PARM_DESC(nocursor, "cursor enable/disable"); + +struct spi_control { + unsigned short mode; +}; + +static int lq035q1_control(struct spi_device *spi, unsigned char reg, unsigned short value) +{ + int ret; + u8 regs[3] = { LQ035_INDEX, 0, 0 }; + u8 dat[3] = { LQ035_DATA, 0, 0 }; + + if (!spi) + return -ENODEV; + + regs[2] = reg; + dat[1] = value >> 8; + dat[2] = value & 0xFF; + + ret = spi_write(spi, regs, ARRAY_SIZE(regs)); + ret |= spi_write(spi, dat, ARRAY_SIZE(dat)); + return ret; +} + +static int __devinit lq035q1_spidev_probe(struct spi_device *spi) +{ + int ret; + struct spi_control *ctl; + struct bfin_lq035q1fb_info *info = container_of(spi->dev.driver, + struct bfin_lq035q1fb_info, + spidrv.driver); + + ctl = kzalloc(sizeof(*ctl), GFP_KERNEL); + + if (!ctl) + return -ENOMEM; + + ctl->mode = (info->disp_info->mode & + LQ035_DRIVER_OUTPUT_MASK) | LQ035_DRIVER_OUTPUT_DEFAULT; + + ret = lq035q1_control(spi, LQ035_SHUT_CTL, LQ035_ON); + ret |= lq035q1_control(spi, LQ035_DRIVER_OUTPUT_CTL, ctl->mode); + if (ret) + return ret; + + spi_set_drvdata(spi, ctl); + + return 0; +} + +static int lq035q1_spidev_remove(struct spi_device *spi) +{ + return lq035q1_control(spi, LQ035_SHUT_CTL, LQ035_SHUT); +} + +#ifdef CONFIG_PM +static int lq035q1_spidev_suspend(struct spi_device *spi, pm_message_t state) +{ + return lq035q1_control(spi, LQ035_SHUT_CTL, LQ035_SHUT); +} + +static int lq035q1_spidev_resume(struct spi_device *spi) +{ + int ret; + struct spi_control *ctl = spi_get_drvdata(spi); + + ret = lq035q1_control(spi, LQ035_DRIVER_OUTPUT_CTL, ctl->mode); + if (ret) + return ret; + + return lq035q1_control(spi, LQ035_SHUT_CTL, LQ035_ON); +} +#else +# define lq035q1_spidev_suspend NULL +# define lq035q1_spidev_resume NULL +#endif + +/* Power down all displays on reboot, poweroff or halt */ +static void lq035q1_spidev_shutdown(struct spi_device *spi) +{ + lq035q1_control(spi, LQ035_SHUT_CTL, LQ035_SHUT); +} + +static int lq035q1_backlight(struct bfin_lq035q1fb_info *info, unsigned arg) +{ + if (info->disp_info->use_bl) + gpio_set_value(info->disp_info->gpio_bl, arg); + + 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); + + 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_POLS_1); /* faling edge syncs POLS */ +} + +static inline void bfin_lq035q1_disable_ppi(void) +{ + bfin_write_PPI_CONTROL(bfin_read_PPI_CONTROL() & ~PORT_EN); +} + +static inline void bfin_lq035q1_enable_ppi(void) +{ + bfin_write_PPI_CONTROL(bfin_read_PPI_CONTROL() | PORT_EN); +} + +static void bfin_lq035q1_start_timers(void) +{ + enable_gptimers(TIMER_VSYNCbit | TIMER_HSYNCbit); +} + +static void bfin_lq035q1_stop_timers(void) +{ + disable_gptimers(TIMER_HSYNCbit | TIMER_VSYNCbit); + + set_gptimer_status(0, TIMER_HSYNC_STATUS_TRUN | TIMER_VSYNC_STATUS_TRUN | + TIMER_HSYNC_STATUS_TIMIL | TIMER_VSYNC_STATUS_TIMIL | + TIMER_HSYNC_STATUS_TOVF | TIMER_VSYNC_STATUS_TOVF); + +} + +static void bfin_lq035q1_init_timers(void) +{ + + bfin_lq035q1_stop_timers(); + + set_gptimer_period(TIMER_HSYNC_id, H_PERIOD); + set_gptimer_pwidth(TIMER_HSYNC_id, 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_config(TIMER_VSYNC_id, TIMER_MODE_PWM | TIMER_PERIOD_CNT | + TIMER_TIN_SEL | TIMER_CLK_SEL | + TIMER_EMU_RUN); + +} + +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_modify(CH_PPI, DMA_BUS_SIZE / 8); + set_dma_y_count(CH_PPI, 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, + P_PPI0_D6, P_PPI0_D7, P_PPI0_D8, + 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, + 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) +{ + peripheral_free_list(ppi0_req_16); + if (ANOMALY_05000400) + gpio_free(P_IDENT(P_PPI0_FS3)); +} + +static int __devinit bfin_lq035q1_request_ports(struct platform_device *pdev) +{ + /* ANOMALY_05000400 - PPI Does Not Start Properly In Specific Mode: + * Drive PPI_FS3 Low + */ + if (ANOMALY_05000400) { + int ret = gpio_request(P_IDENT(P_PPI0_FS3), "PPI_FS3"); + if (ret) + return ret; + gpio_direction_output(P_IDENT(P_PPI0_FS3), 0); + } + + if (peripheral_request_list(ppi0_req_16, DRIVER_NAME)) { + dev_err(&pdev->dev, "requesting peripherals failed\n"); + return -EFAULT; + } + + return 0; +} + +static int bfin_lq035q1_fb_open(struct fb_info *info, int user) +{ + struct bfin_lq035q1fb_info *fbi = info->par; + + spin_lock(&fbi->lock); + fbi->lq035_open_cnt++; + + if (fbi->lq035_open_cnt <= 1) { + + bfin_lq035q1_disable_ppi(); + SSYNC(); + + bfin_lq035q1_config_dma(fbi); + bfin_lq035q1_config_ppi(fbi); + bfin_lq035q1_init_timers(); + + /* start dma */ + enable_dma(CH_PPI); + bfin_lq035q1_enable_ppi(); + bfin_lq035q1_start_timers(); + lq035q1_backlight(fbi, 1); + } + + spin_unlock(&fbi->lock); + + return 0; +} + +static int bfin_lq035q1_fb_release(struct fb_info *info, int user) +{ + struct bfin_lq035q1fb_info *fbi = info->par; + + spin_lock(&fbi->lock); + + fbi->lq035_open_cnt--; + + if (fbi->lq035_open_cnt <= 0) { + lq035q1_backlight(fbi, 0); + bfin_lq035q1_disable_ppi(); + SSYNC(); + disable_dma(CH_PPI); + bfin_lq035q1_stop_timers(); + } + + spin_unlock(&fbi->lock); + + return 0; +} + +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 + var->red.offset = info->var.red.offset; + var->green.offset = info->var.green.offset; + var->blue.offset = info->var.blue.offset; + var->red.length = info->var.red.length; + var->green.length = info->var.green.length; + var->blue.length = info->var.blue.length; + var->transp.offset = 0; + var->transp.length = 0; + var->transp.msb_right = 0; + var->red.msb_right = 0; + var->green.msb_right = 0; + var->blue.msb_right = 0; + break; + default: + pr_debug("%s: depth not supported: %u BPP\n", __func__, + var->bits_per_pixel); + return -EINVAL; + } + + if (info->var.xres != var->xres || info->var.yres != var->yres || + info->var.xres_virtual != var->xres_virtual || + info->var.yres_virtual != var->yres_virtual) { + pr_debug("%s: Resolution not supported: X%u x Y%u \n", + __func__, var->xres, var->yres); + return -EINVAL; + } + + /* + * Memory limit + */ + + if ((info->fix.line_length * var->yres_virtual) > info->fix.smem_len) { + pr_debug("%s: Memory Limit requested yres_virtual = %u\n", + __func__, var->yres_virtual); + return -ENOMEM; + } + + + return 0; +} + +int bfin_lq035q1_fb_cursor(struct fb_info *info, struct fb_cursor *cursor) +{ + if (nocursor) + return 0; + else + return -EINVAL; /* just to force soft_cursor() call */ +} + +static int bfin_lq035q1_fb_setcolreg(u_int regno, u_int red, u_int green, + u_int blue, u_int transp, + struct fb_info *info) +{ + if (regno >= BFIN_LCD_NBR_PALETTE_ENTRIES) + return -EINVAL; + + if (info->var.grayscale) { + /* grayscale = 0.30*R + 0.59*G + 0.11*B */ + red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8; + } + + if (info->fix.visual == FB_VISUAL_TRUECOLOR) { + + u32 value; + /* Place color in the pseudopalette */ + if (regno > 16) + return -EINVAL; + + red >>= (16 - info->var.red.length); + green >>= (16 - info->var.green.length); + blue >>= (16 - info->var.blue.length); + + value = (red << info->var.red.offset) | + (green << info->var.green.offset) | + (blue << info->var.blue.offset); + value &= 0xFFFFFF; + + ((u32 *) (info->pseudo_palette))[regno] = value; + + } + + return 0; +} + +static struct fb_ops bfin_lq035q1_fb_ops = { + .owner = THIS_MODULE, + .fb_open = bfin_lq035q1_fb_open, + .fb_release = bfin_lq035q1_fb_release, + .fb_check_var = bfin_lq035q1_fb_check_var, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_cursor = bfin_lq035q1_fb_cursor, + .fb_setcolreg = bfin_lq035q1_fb_setcolreg, +}; + +static irqreturn_t bfin_lq035q1_irq_error(int irq, void *dev_id) +{ + /*struct bfin_lq035q1fb_info *info = (struct bfin_lq035q1fb_info *)dev_id;*/ + + u16 status = bfin_read_PPI_STATUS(); + bfin_write_PPI_STATUS(-1); + + if (status) { + bfin_lq035q1_disable_ppi(); + disable_dma(CH_PPI); + + /* start dma */ + enable_dma(CH_PPI); + bfin_lq035q1_enable_ppi(); + bfin_write_PPI_STATUS(-1); + } + + return IRQ_HANDLED; +} + +static int __devinit bfin_lq035q1_probe(struct platform_device *pdev) +{ + struct bfin_lq035q1fb_info *info; + struct fb_info *fbinfo; + int ret; + + ret = request_dma(CH_PPI, DRIVER_NAME"_CH_PPI"); + if (ret < 0) { + dev_err(&pdev->dev, "PPI DMA unavailable\n"); + goto out1; + } + + fbinfo = framebuffer_alloc(sizeof(*info), &pdev->dev); + if (!fbinfo) { + ret = -ENOMEM; + goto out2; + } + + info = fbinfo->par; + info->fb = fbinfo; + info->dev = &pdev->dev; + + info->disp_info = pdev->dev.platform_data; + + platform_set_drvdata(pdev, fbinfo); + + strcpy(fbinfo->fix.id, DRIVER_NAME); + + fbinfo->fix.type = FB_TYPE_PACKED_PIXELS; + fbinfo->fix.type_aux = 0; + fbinfo->fix.xpanstep = 0; + fbinfo->fix.ypanstep = 0; + fbinfo->fix.ywrapstep = 0; + fbinfo->fix.accel = FB_ACCEL_NONE; + fbinfo->fix.visual = FB_VISUAL_TRUECOLOR; + + fbinfo->var.nonstd = 0; + fbinfo->var.activate = FB_ACTIVATE_NOW; + fbinfo->var.height = -1; + fbinfo->var.width = -1; + fbinfo->var.accel_flags = 0; + fbinfo->var.vmode = FB_VMODE_NONINTERLACED; + + fbinfo->var.xres = LCD_X_RES; + 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; + + 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 + } 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 + } + + 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 + + fbinfo->var.transp.length = 0; + + fbinfo->fix.smem_len = LCD_X_RES * LCD_Y_RES * LCD_BPP / 8 + + ACTIVE_VIDEO_MEM_OFFSET; + + fbinfo->fix.line_length = fbinfo->var.xres_virtual * + fbinfo->var.bits_per_pixel / 8; + + + fbinfo->fbops = &bfin_lq035q1_fb_ops; + fbinfo->flags = FBINFO_FLAG_DEFAULT; + + info->fb_buffer = + dma_alloc_coherent(NULL, fbinfo->fix.smem_len, &info->dma_handle, + GFP_KERNEL); + + if (NULL == info->fb_buffer) { + dev_err(&pdev->dev, "couldn't allocate dma buffer\n"); + ret = -ENOMEM; + 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->fbops = &bfin_lq035q1_fb_ops; + + fbinfo->pseudo_palette = &info->pseudo_pal; + + ret = fb_alloc_cmap(&fbinfo->cmap, BFIN_LCD_NBR_PALETTE_ENTRIES, 0); + if (ret < 0) { + dev_err(&pdev->dev, "failed to allocate colormap (%d entries)\n", + BFIN_LCD_NBR_PALETTE_ENTRIES); + goto out4; + } + + ret = bfin_lq035q1_request_ports(pdev); + if (ret) { + dev_err(&pdev->dev, "couldn't request gpio port\n"); + goto out6; + } + + info->irq = platform_get_irq(pdev, 0); + if (info->irq < 0) { + ret = -EINVAL; + goto out7; + } + + ret = request_irq(info->irq, bfin_lq035q1_irq_error, IRQF_DISABLED, + DRIVER_NAME" PPI ERROR", info); + if (ret < 0) { + dev_err(&pdev->dev, "unable to request PPI ERROR IRQ\n"); + goto out7; + } + + info->spidrv.driver.name = DRIVER_NAME"-spi"; + info->spidrv.probe = lq035q1_spidev_probe; + info->spidrv.remove = __devexit_p(lq035q1_spidev_remove); + info->spidrv.shutdown = lq035q1_spidev_shutdown; + info->spidrv.suspend = lq035q1_spidev_suspend; + info->spidrv.resume = lq035q1_spidev_resume; + + ret = spi_register_driver(&info->spidrv); + if (ret < 0) { + dev_err(&pdev->dev, "couldn't register SPI Interface\n"); + goto out8; + } + + if (info->disp_info->use_bl) { + ret = gpio_request(info->disp_info->gpio_bl, "LQ035 Backlight"); + + if (ret) { + dev_err(&pdev->dev, "failed to request GPIO %d\n", + info->disp_info->gpio_bl); + goto out9; + } + gpio_direction_output(info->disp_info->gpio_bl, 0); + } + + ret = register_framebuffer(fbinfo); + if (ret < 0) { + dev_err(&pdev->dev, "unable to register framebuffer\n"); + goto out10; + } + + dev_info(&pdev->dev, "%dx%d %d-bit RGB FrameBuffer initialized\n", + LCD_X_RES, LCD_Y_RES, LCD_BPP); + + return 0; + + out10: + if (info->disp_info->use_bl) + gpio_free(info->disp_info->gpio_bl); + out9: + spi_unregister_driver(&info->spidrv); + out8: + free_irq(info->irq, info); + out7: + bfin_lq035q1_free_ports(); + out6: + fb_dealloc_cmap(&fbinfo->cmap); + out4: + dma_free_coherent(NULL, fbinfo->fix.smem_len, info->fb_buffer, + info->dma_handle); + out3: + framebuffer_release(fbinfo); + out2: + free_dma(CH_PPI); + out1: + platform_set_drvdata(pdev, NULL); + + return ret; +} + +static int __devexit bfin_lq035q1_remove(struct platform_device *pdev) +{ + struct fb_info *fbinfo = platform_get_drvdata(pdev); + struct bfin_lq035q1fb_info *info = fbinfo->par; + + if (info->disp_info->use_bl) + gpio_free(info->disp_info->gpio_bl); + + spi_unregister_driver(&info->spidrv); + + unregister_framebuffer(fbinfo); + + free_dma(CH_PPI); + free_irq(info->irq, info); + + if (info->fb_buffer != NULL) + dma_free_coherent(NULL, fbinfo->fix.smem_len, info->fb_buffer, + info->dma_handle); + + fb_dealloc_cmap(&fbinfo->cmap); + + bfin_lq035q1_free_ports(); + + platform_set_drvdata(pdev, NULL); + framebuffer_release(fbinfo); + + dev_info(&pdev->dev, "unregistered LCD driver\n"); + + return 0; +} + +#ifdef CONFIG_PM +static int bfin_lq035q1_suspend(struct device *dev) +{ + struct fb_info *fbinfo = dev_get_drvdata(dev); + struct bfin_lq035q1fb_info *info = fbinfo->par; + + if (info->lq035_open_cnt) { + lq035q1_backlight(info, 0); + bfin_lq035q1_disable_ppi(); + SSYNC(); + disable_dma(CH_PPI); + bfin_lq035q1_stop_timers(); + bfin_write_PPI_STATUS(-1); + } + + return 0; +} + +static int bfin_lq035q1_resume(struct device *dev) +{ + struct fb_info *fbinfo = dev_get_drvdata(dev); + struct bfin_lq035q1fb_info *info = fbinfo->par; + + if (info->lq035_open_cnt) { + bfin_lq035q1_disable_ppi(); + SSYNC(); + + bfin_lq035q1_config_dma(info); + bfin_lq035q1_config_ppi(info); + bfin_lq035q1_init_timers(); + + /* start dma */ + enable_dma(CH_PPI); + bfin_lq035q1_enable_ppi(); + bfin_lq035q1_start_timers(); + lq035q1_backlight(info, 1); + } + + return 0; +} + +static struct dev_pm_ops bfin_lq035q1_dev_pm_ops = { + .suspend = bfin_lq035q1_suspend, + .resume = bfin_lq035q1_resume, +}; +#endif + +static struct platform_driver bfin_lq035q1_driver = { + .probe = bfin_lq035q1_probe, + .remove = __devexit_p(bfin_lq035q1_remove), + .driver = { + .name = DRIVER_NAME, +#ifdef CONFIG_PM + .pm = &bfin_lq035q1_dev_pm_ops, +#endif + }, +}; + +static int __init bfin_lq035q1_driver_init(void) +{ + return platform_driver_register(&bfin_lq035q1_driver); +} +module_init(bfin_lq035q1_driver_init); + +static void __exit bfin_lq035q1_driver_cleanup(void) +{ + platform_driver_unregister(&bfin_lq035q1_driver); +} +module_exit(bfin_lq035q1_driver_cleanup); + +MODULE_DESCRIPTION("Blackfin TFT LCD Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/bfin-t350mcqb-fb.c b/drivers/video/bfin-t350mcqb-fb.c index 5cc36cfbf07..2549c53b26a 100644 --- a/drivers/video/bfin-t350mcqb-fb.c +++ b/drivers/video/bfin-t350mcqb-fb.c @@ -487,8 +487,8 @@ static int __devinit bfin_t350mcqb_probe(struct platform_device *pdev) fbinfo->var.nonstd = 0; fbinfo->var.activate = FB_ACTIVATE_NOW; - fbinfo->var.height = -1; - fbinfo->var.width = -1; + fbinfo->var.height = 53; + fbinfo->var.width = 70; fbinfo->var.accel_flags = 0; fbinfo->var.vmode = FB_VMODE_NONINTERLACED; @@ -634,17 +634,35 @@ static int __devexit bfin_t350mcqb_remove(struct platform_device *pdev) #ifdef CONFIG_PM static int bfin_t350mcqb_suspend(struct platform_device *pdev, pm_message_t state) { - bfin_t350mcqb_disable_ppi(); - disable_dma(CH_PPI); - bfin_write_PPI_STATUS(0xFFFF); + struct fb_info *fbinfo = platform_get_drvdata(pdev); + struct bfin_t350mcqbfb_info *fbi = fbinfo->par; + + if (fbi->lq043_open_cnt) { + bfin_t350mcqb_disable_ppi(); + disable_dma(CH_PPI); + bfin_t350mcqb_stop_timers(); + bfin_write_PPI_STATUS(-1); + } + return 0; } static int bfin_t350mcqb_resume(struct platform_device *pdev) { - enable_dma(CH_PPI); - bfin_t350mcqb_enable_ppi(); + struct fb_info *fbinfo = platform_get_drvdata(pdev); + struct bfin_t350mcqbfb_info *fbi = fbinfo->par; + + if (fbi->lq043_open_cnt) { + bfin_t350mcqb_config_dma(fbi); + bfin_t350mcqb_config_ppi(fbi); + bfin_t350mcqb_init_timers(); + + /* start dma */ + enable_dma(CH_PPI); + bfin_t350mcqb_enable_ppi(); + bfin_t350mcqb_start_timers(); + } return 0; } diff --git a/drivers/video/clps711xfb.c b/drivers/video/clps711xfb.c index 16f5db471ab..99b354b8e25 100644 --- a/drivers/video/clps711xfb.c +++ b/drivers/video/clps711xfb.c @@ -19,8 +19,10 @@ * * Framebuffer driver for the CLPS7111 and EP7212 processors. */ +#include <linux/mm.h> #include <linux/module.h> #include <linux/kernel.h> +#include <linux/seq_file.h> #include <linux/slab.h> #include <linux/fb.h> #include <linux/init.h> @@ -38,14 +40,6 @@ struct fb_info *cfb; #define CMAP_MAX_SIZE 16 -/* The /proc entry for the backlight. */ -static struct proc_dir_entry *clps7111fb_backlight_proc_entry = NULL; - -static int clps7111fb_proc_backlight_read(char *page, char **start, off_t off, - int count, int *eof, void *data); -static int clps7111fb_proc_backlight_write(struct file *file, - const char *buffer, unsigned long count, void *data); - /* * LCD AC Prescale. This comes from the LCD panel manufacturers specifications. * This determines how many clocks + 1 of CL1 before the M signal toggles. @@ -221,26 +215,23 @@ static struct fb_ops clps7111fb_ops = { .fb_imageblit = cfb_imageblit, }; -static int -clps7111fb_proc_backlight_read(char *page, char **start, off_t off, - int count, int *eof, void *data) +static int backlight_proc_show(struct seq_file *m, void *v) { - /* We need at least two characters, one for the digit, and one for - * the terminating NULL. */ - if (count < 2) - return -EINVAL; - if (machine_is_edb7211()) { - return sprintf(page, "%d\n", + seq_printf(m, "%d\n", (clps_readb(PDDR) & EDB_PD3_LCDBL) ? 1 : 0); } return 0; } -static int -clps7111fb_proc_backlight_write(struct file *file, const char *buffer, - unsigned long count, void *data) +static int backlight_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, backlight_proc_show, NULL); +} + +static ssize_t backlight_proc_write(struct file *file, const char *buffer, + size_t count, loff_t *pos) { unsigned char char_value; int value; @@ -271,6 +262,15 @@ clps7111fb_proc_backlight_write(struct file *file, const char *buffer, return count; } +static const struct file_operations backlight_proc_fops = { + .owner = THIS_MODULE, + .open = backlight_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .write = backlight_proc_write, +}; + static void __init clps711x_guess_lcd_params(struct fb_info *info) { unsigned int lcdcon, syscon, size; @@ -379,19 +379,11 @@ int __init clps711xfb_init(void) fb_alloc_cmap(&cfb->cmap, CMAP_MAX_SIZE, 0); - /* Register the /proc entries. */ - clps7111fb_backlight_proc_entry = create_proc_entry("backlight", 0444, - NULL); - if (clps7111fb_backlight_proc_entry == NULL) { + if (!proc_create("backlight", 0444, NULL, &backlight_proc_fops)) { printk("Couldn't create the /proc entry for the backlight.\n"); return -EINVAL; } - clps7111fb_backlight_proc_entry->read_proc = - &clps7111fb_proc_backlight_read; - clps7111fb_backlight_proc_entry->write_proc = - &clps7111fb_proc_backlight_write; - /* * Power up the LCD */ diff --git a/drivers/video/da8xx-fb.c b/drivers/video/da8xx-fb.c index ea1fd3f4751..369a5b3ac64 100644 --- a/drivers/video/da8xx-fb.c +++ b/drivers/video/da8xx-fb.c @@ -28,6 +28,8 @@ #include <linux/uaccess.h> #include <linux/interrupt.h> #include <linux/clk.h> +#include <linux/cpufreq.h> +#include <linux/console.h> #include <video/da8xx-fb.h> #define DRIVER_NAME "da8xx_lcdc" @@ -113,6 +115,12 @@ struct da8xx_fb_par { unsigned short pseudo_palette[16]; unsigned int databuf_sz; unsigned int palette_sz; + unsigned int pxl_clk; + int blank; +#ifdef CONFIG_CPU_FREQ + struct notifier_block freq_transition; +#endif + void (*panel_power_ctrl)(int); }; /* Variable Screen Information */ @@ -155,7 +163,7 @@ struct da8xx_panel { int vfp; /* Vertical front porch */ int vbp; /* Vertical back porch */ int vsw; /* Vertical Sync Pulse Width */ - int pxl_clk; /* Pixel clock */ + unsigned int pxl_clk; /* Pixel clock */ unsigned char invert_pxl_clk; /* Invert Pixel clock */ }; @@ -171,7 +179,7 @@ static struct da8xx_panel known_lcd_panels[] = { .vfp = 2, .vbp = 2, .vsw = 0, - .pxl_clk = 0x10, + .pxl_clk = 4608000, .invert_pxl_clk = 1, }, /* Sharp LK043T1DG01 */ @@ -185,13 +193,23 @@ static struct da8xx_panel known_lcd_panels[] = { .vfp = 2, .vbp = 2, .vsw = 10, - .pxl_clk = 0x12, + .pxl_clk = 7833600, .invert_pxl_clk = 0, }, }; +/* Enable the Raster Engine of the LCD Controller */ +static inline void lcd_enable_raster(void) +{ + u32 reg; + + reg = lcdc_read(LCD_RASTER_CTRL_REG); + if (!(reg & LCD_RASTER_ENABLE)) + lcdc_write(reg | LCD_RASTER_ENABLE, LCD_RASTER_CTRL_REG); +} + /* Disable the Raster Engine of the LCD Controller */ -static void lcd_disable_raster(struct da8xx_fb_par *par) +static inline void lcd_disable_raster(void) { u32 reg; @@ -443,14 +461,25 @@ static int fb_setcolreg(unsigned regno, unsigned red, unsigned green, static void lcd_reset(struct da8xx_fb_par *par) { /* Disable the Raster if previously Enabled */ - if (lcdc_read(LCD_RASTER_CTRL_REG) & LCD_RASTER_ENABLE) - lcd_disable_raster(par); + lcd_disable_raster(); /* DMA has to be disabled */ lcdc_write(0, LCD_DMA_CTRL_REG); lcdc_write(0, LCD_RASTER_CTRL_REG); } +static void lcd_calc_clk_divider(struct da8xx_fb_par *par) +{ + unsigned int lcd_clk, div; + + lcd_clk = clk_get_rate(par->lcdc_clk); + div = lcd_clk / par->pxl_clk; + + /* Configure the LCD clock divisor. */ + lcdc_write(LCD_CLK_DIVISOR(div) | + (LCD_RASTER_MODE & 0x1), LCD_CTRL_REG); +} + static int lcd_init(struct da8xx_fb_par *par, const struct lcd_ctrl_config *cfg, struct da8xx_panel *panel) { @@ -459,9 +488,8 @@ static int lcd_init(struct da8xx_fb_par *par, const struct lcd_ctrl_config *cfg, lcd_reset(par); - /* Configure the LCD clock divisor. */ - lcdc_write(LCD_CLK_DIVISOR(panel->pxl_clk) | - (LCD_RASTER_MODE & 0x1), LCD_CTRL_REG); + /* Calculate the divider */ + lcd_calc_clk_divider(par); if (panel->invert_pxl_clk) lcdc_write((lcdc_read(LCD_RASTER_TIMING_2_REG) | @@ -513,13 +541,11 @@ 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) { u32 stat = lcdc_read(LCD_STAT_REG); - u32 reg; if ((stat & LCD_SYNC_LOST) && (stat & LCD_FIFO_UNDERFLOW)) { - reg = lcdc_read(LCD_RASTER_CTRL_REG); - lcdc_write(reg & ~LCD_RASTER_ENABLE, LCD_RASTER_CTRL_REG); + lcd_disable_raster(); lcdc_write(stat, LCD_STAT_REG); - lcdc_write(reg | LCD_RASTER_ENABLE, LCD_RASTER_CTRL_REG); + lcd_enable_raster(); } else lcdc_write(stat, LCD_STAT_REG); @@ -574,6 +600,38 @@ static int fb_check_var(struct fb_var_screeninfo *var, return err; } +#ifdef CONFIG_CPU_FREQ +static int lcd_da8xx_cpufreq_transition(struct notifier_block *nb, + unsigned long val, void *data) +{ + struct da8xx_fb_par *par; + + par = container_of(nb, struct da8xx_fb_par, freq_transition); + if (val == CPUFREQ_PRECHANGE) { + lcd_disable_raster(); + } else if (val == CPUFREQ_POSTCHANGE) { + lcd_calc_clk_divider(par); + lcd_enable_raster(); + } + + return 0; +} + +static inline int lcd_da8xx_cpufreq_register(struct da8xx_fb_par *par) +{ + par->freq_transition.notifier_call = lcd_da8xx_cpufreq_transition; + + return cpufreq_register_notifier(&par->freq_transition, + CPUFREQ_TRANSITION_NOTIFIER); +} + +static inline void lcd_da8xx_cpufreq_deregister(struct da8xx_fb_par *par) +{ + cpufreq_unregister_notifier(&par->freq_transition, + CPUFREQ_TRANSITION_NOTIFIER); +} +#endif + static int __devexit fb_remove(struct platform_device *dev) { struct fb_info *info = dev_get_drvdata(&dev->dev); @@ -581,8 +639,13 @@ static int __devexit fb_remove(struct platform_device *dev) if (info) { struct da8xx_fb_par *par = info->par; - if (lcdc_read(LCD_RASTER_CTRL_REG) & LCD_RASTER_ENABLE) - lcd_disable_raster(par); +#ifdef CONFIG_CPU_FREQ + lcd_da8xx_cpufreq_deregister(par); +#endif + if (par->panel_power_ctrl) + par->panel_power_ctrl(0); + + lcd_disable_raster(); lcdc_write(0, LCD_RASTER_CTRL_REG); /* disable DMA */ @@ -639,6 +702,35 @@ static int fb_ioctl(struct fb_info *info, unsigned int cmd, return 0; } +static int cfb_blank(int blank, struct fb_info *info) +{ + struct da8xx_fb_par *par = info->par; + int ret = 0; + + if (par->blank == blank) + return 0; + + par->blank = blank; + switch (blank) { + case FB_BLANK_UNBLANK: + if (par->panel_power_ctrl) + par->panel_power_ctrl(1); + + lcd_enable_raster(); + break; + case FB_BLANK_POWERDOWN: + if (par->panel_power_ctrl) + par->panel_power_ctrl(0); + + lcd_disable_raster(); + break; + default: + ret = -EINVAL; + } + + return ret; +} + static struct fb_ops da8xx_fb_ops = { .owner = THIS_MODULE, .fb_check_var = fb_check_var, @@ -647,6 +739,7 @@ static struct fb_ops da8xx_fb_ops = { .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, + .fb_blank = cfb_blank, }; static int __init fb_probe(struct platform_device *device) @@ -721,6 +814,12 @@ static int __init fb_probe(struct platform_device *device) } par = da8xx_fb_info->par; + par->lcdc_clk = fb_clk; + par->pxl_clk = lcdc_info->pxl_clk; + if (fb_pdata->panel_power_ctrl) { + par->panel_power_ctrl = fb_pdata->panel_power_ctrl; + par->panel_power_ctrl(1); + } if (lcd_init(par, lcd_cfg, lcdc_info) < 0) { dev_err(&device->dev, "lcd_init failed\n"); @@ -754,8 +853,6 @@ static int __init fb_probe(struct platform_device *device) da8xx_fb_fix.smem_len = par->databuf_sz - par->palette_sz; da8xx_fb_fix.line_length = (lcdc_info->width * lcd_cfg->bpp) / 8; - par->lcdc_clk = fb_clk; - par->irq = platform_get_irq(device, 0); if (par->irq < 0) { ret = -ENOENT; @@ -814,12 +911,24 @@ static int __init fb_probe(struct platform_device *device) goto err_dealloc_cmap; } +#ifdef CONFIG_CPU_FREQ + ret = lcd_da8xx_cpufreq_register(par); + if (ret) { + dev_err(&device->dev, "failed to register cpufreq\n"); + goto err_cpu_freq; + } +#endif + /* enable raster engine */ - lcdc_write(lcdc_read(LCD_RASTER_CTRL_REG) | - LCD_RASTER_ENABLE, LCD_RASTER_CTRL_REG); + lcd_enable_raster(); return 0; +#ifdef CONFIG_CPU_FREQ +err_cpu_freq: + unregister_framebuffer(da8xx_fb_info); +#endif + err_dealloc_cmap: fb_dealloc_cmap(&da8xx_fb_info->cmap); @@ -852,11 +961,35 @@ err_request_mem: #ifdef CONFIG_PM static int fb_suspend(struct platform_device *dev, pm_message_t state) { - return -EBUSY; + struct fb_info *info = platform_get_drvdata(dev); + struct da8xx_fb_par *par = info->par; + + acquire_console_sem(); + if (par->panel_power_ctrl) + par->panel_power_ctrl(0); + + fb_set_suspend(info, 1); + lcd_disable_raster(); + clk_disable(par->lcdc_clk); + release_console_sem(); + + return 0; } static int fb_resume(struct platform_device *dev) { - return -EBUSY; + struct fb_info *info = platform_get_drvdata(dev); + struct da8xx_fb_par *par = info->par; + + acquire_console_sem(); + if (par->panel_power_ctrl) + par->panel_power_ctrl(1); + + clk_enable(par->lcdc_clk); + lcd_enable_raster(); + fb_set_suspend(info, 0); + release_console_sem(); + + return 0; } #else #define fb_suspend NULL diff --git a/drivers/video/ep93xx-fb.c b/drivers/video/ep93xx-fb.c index bd9d46f9529..27aab4a0619 100644 --- a/drivers/video/ep93xx-fb.c +++ b/drivers/video/ep93xx-fb.c @@ -358,6 +358,8 @@ static int ep93xxfb_setcolreg(unsigned int regno, unsigned int red, switch (info->fix.visual) { case FB_VISUAL_PSEUDOCOLOR: + if (regno > 255) + return 1; rgb = ((red & 0xff00) << 8) | (green & 0xff00) | ((blue & 0xff00) >> 8); diff --git a/drivers/video/geode/lxfb.h b/drivers/video/geode/lxfb.h index fc68a8b0a14..cc781c00f75 100644 --- a/drivers/video/geode/lxfb.h +++ b/drivers/video/geode/lxfb.h @@ -1,3 +1,13 @@ +/* Geode LX framebuffer driver + * + * Copyright (C) 2006-2007, Advanced Micro Devices,Inc. + * Copyright (c) 2008 Andres Salomon <dilinger@debian.org> + * + * 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 _LXFB_H_ #define _LXFB_H_ diff --git a/drivers/video/i810/i810_dvt.c b/drivers/video/i810/i810_dvt.c index 27fa703a2e0..b4b3670667a 100644 --- a/drivers/video/i810/i810_dvt.c +++ b/drivers/video/i810/i810_dvt.c @@ -212,24 +212,29 @@ inline void round_off_yres(u32 *xres, u32 *yres) *yres = (*xres * 3) >> 2; } -void i810fb_encode_registers(const struct fb_var_screeninfo *var, - struct i810fb_par *par, u32 xres, u32 yres) +static int i810fb_find_best_mode(u32 xres, u32 yres, u32 pixclock) { u32 diff = 0, diff_best = 0xFFFFFFFF, i = 0, i_best = 0; - u8 hfl; + u8 hfl = (u8) ((xres >> 3) - 1); - hfl = (u8) ((xres >> 3) - 1); for (i = 0; i < ARRAY_SIZE(std_modes); i++) { if (std_modes[i].cr01 == hfl) { - if (std_modes[i].pixclock <= par->regs.pixclock) - diff = par->regs.pixclock - - std_modes[i].pixclock; + if (std_modes[i].pixclock <= pixclock) + diff = pixclock - std_modes[i].pixclock; if (diff < diff_best) { i_best = i; diff_best = diff; } } } + return i_best; +} + +void i810fb_encode_registers(const struct fb_var_screeninfo *var, + struct i810fb_par *par, u32 xres, u32 yres) +{ + u32 i_best = i810fb_find_best_mode(xres, yres, par->regs.pixclock); + par->regs = std_modes[i_best]; /* overlay */ @@ -239,36 +244,36 @@ void i810fb_encode_registers(const struct fb_var_screeninfo *var, void i810fb_fill_var_timings(struct fb_var_screeninfo *var) { - struct i810fb_par par; u32 total, xres, yres; + u32 mode, pixclock; xres = var->xres; yres = var->yres; - par.regs.pixclock = 1000000000/var->pixclock; - i810fb_encode_registers(var, &par, xres, yres); + pixclock = 1000000000 / var->pixclock; + mode = i810fb_find_best_mode(xres, yres, pixclock); - total = ((par.regs.cr00 | (par.regs.cr35 & 1) << 8) + 3) << 3; + total = (std_modes[mode].cr00 | (std_modes[mode].cr35 & 1) << 8) + 3; + total <<= 3; - var->pixclock = 1000000000/par.regs.pixclock; - var->right_margin = (par.regs.cr04 << 3) - xres; - var->hsync_len = ((par.regs.cr05 & 0x1F) - - (par.regs.cr04 & 0x1F)) << 3; + var->pixclock = 1000000000 / std_modes[mode].pixclock; + var->right_margin = (std_modes[mode].cr04 << 3) - xres; + var->hsync_len = ((std_modes[mode].cr05 & 0x1F) - + (std_modes[mode].cr04 & 0x1F)) << 3; var->left_margin = (total - (xres + var->right_margin + var->hsync_len)); var->sync = FB_SYNC_ON_GREEN; - if (~(par.regs.msr & (1 << 6))) + if (~(std_modes[mode].msr & (1 << 6))) var->sync |= FB_SYNC_HOR_HIGH_ACT; - if (~(par.regs.msr & (1 << 7))) + if (~(std_modes[mode].msr & (1 << 7))) var->sync |= FB_SYNC_VERT_HIGH_ACT; - - total = ((par.regs.cr06 | (par.regs.cr30 & 0x0F) << 8)) + 2; - var->lower_margin = (par.regs.cr10 | - (par.regs.cr32 & 0x0F) << 8) - yres; - var->vsync_len = (par.regs.cr11 & 0x0F) - (var->lower_margin & 0x0F); - var->upper_margin = total - (yres + var->lower_margin + - var->vsync_len); + total = (std_modes[mode].cr06 | (std_modes[mode].cr30 & 0xF) << 8) + 2; + var->lower_margin = (std_modes[mode].cr10 | + (std_modes[mode].cr32 & 0x0F) << 8) - yres; + var->vsync_len = (std_modes[mode].cr11 & 0x0F) - + (var->lower_margin & 0x0F); + var->upper_margin = total - (yres + var->lower_margin + var->vsync_len); } u32 i810_get_watermark(struct fb_var_screeninfo *var, diff --git a/drivers/video/intelfb/intelfbdrv.c b/drivers/video/intelfb/intelfbdrv.c index 0cafd642fbc..5ba39999105 100644 --- a/drivers/video/intelfb/intelfbdrv.c +++ b/drivers/video/intelfb/intelfbdrv.c @@ -874,6 +874,9 @@ static int __devinit intelfb_pci_register(struct pci_dev *pdev, if (bailearly == 18) bailout(dinfo); + /* read active pipe */ + dinfo->pipe = intelfbhw_active_pipe(&dinfo->save_state); + /* Cursor initialisation */ if (dinfo->hwcursor) { intelfbhw_cursor_init(dinfo); diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c index 0689f97c523..81627466804 100644 --- a/drivers/video/intelfb/intelfbhw.c +++ b/drivers/video/intelfb/intelfbhw.c @@ -469,6 +469,32 @@ void intelfbhw_do_blank(int blank, struct fb_info *info) } +/* Check which pipe is connected to an active display plane. */ +int intelfbhw_active_pipe(const struct intelfb_hwstate *hw) +{ + int pipe = -1; + + /* keep old default behaviour - prefer PIPE_A */ + if (hw->disp_b_ctrl & DISPPLANE_PLANE_ENABLE) { + pipe = (hw->disp_b_ctrl >> DISPPLANE_SEL_PIPE_SHIFT); + pipe &= PIPE_MASK; + if (unlikely(pipe == PIPE_A)) + return PIPE_A; + } + if (hw->disp_a_ctrl & DISPPLANE_PLANE_ENABLE) { + pipe = (hw->disp_a_ctrl >> DISPPLANE_SEL_PIPE_SHIFT); + pipe &= PIPE_MASK; + if (likely(pipe == PIPE_A)) + return PIPE_A; + } + /* Impossible that no pipe is selected - return PIPE_A */ + WARN_ON(pipe == -1); + if (unlikely(pipe == -1)) + pipe = PIPE_A; + + return pipe; +} + void intelfbhw_setcolreg(struct intelfb_info *dinfo, unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp) @@ -1019,7 +1045,7 @@ int intelfbhw_mode_to_hw(struct intelfb_info *dinfo, struct intelfb_hwstate *hw, struct fb_var_screeninfo *var) { - int pipe = PIPE_A; + int pipe = intelfbhw_active_pipe(hw); u32 *dpll, *fp0, *fp1; u32 m1, m2, n, p1, p2, clock_target, clock; u32 hsync_start, hsync_end, hblank_start, hblank_end, htotal, hactive; @@ -1033,12 +1059,6 @@ int intelfbhw_mode_to_hw(struct intelfb_info *dinfo, /* Disable VGA */ hw->vgacntrl |= VGA_DISABLE; - /* Check whether pipe A or pipe B is enabled. */ - if (hw->pipe_a_conf & PIPECONF_ENABLE) - pipe = PIPE_A; - else if (hw->pipe_b_conf & PIPECONF_ENABLE) - pipe = PIPE_B; - /* Set which pipe's registers will be set. */ if (pipe == PIPE_B) { dpll = &hw->dpll_b; @@ -1262,7 +1282,6 @@ int intelfbhw_mode_to_hw(struct intelfb_info *dinfo, int intelfbhw_program_mode(struct intelfb_info *dinfo, const struct intelfb_hwstate *hw, int blank) { - int pipe = PIPE_A; u32 tmp; const u32 *dpll, *fp0, *fp1, *pipe_conf; const u32 *hs, *ht, *hb, *vs, *vt, *vb, *ss; @@ -1272,7 +1291,7 @@ int intelfbhw_program_mode(struct intelfb_info *dinfo, u32 src_size_reg; u32 count, tmp_val[3]; - /* Assume single pipe, display plane A, analog CRT. */ + /* Assume single pipe */ #if VERBOSE > 0 DBG_MSG("intelfbhw_program_mode\n"); @@ -1283,15 +1302,9 @@ int intelfbhw_program_mode(struct intelfb_info *dinfo, tmp |= VGA_DISABLE; OUTREG(VGACNTRL, tmp); - /* Check whether pipe A or pipe B is enabled. */ - if (hw->pipe_a_conf & PIPECONF_ENABLE) - pipe = PIPE_A; - else if (hw->pipe_b_conf & PIPECONF_ENABLE) - pipe = PIPE_B; - - dinfo->pipe = pipe; + dinfo->pipe = intelfbhw_active_pipe(hw); - if (pipe == PIPE_B) { + if (dinfo->pipe == PIPE_B) { dpll = &hw->dpll_b; fp0 = &hw->fpb0; fp1 = &hw->fpb1; diff --git a/drivers/video/intelfb/intelfbhw.h b/drivers/video/intelfb/intelfbhw.h index 0b076bac321..216ca20f259 100644 --- a/drivers/video/intelfb/intelfbhw.h +++ b/drivers/video/intelfb/intelfbhw.h @@ -604,5 +604,6 @@ extern void intelfbhw_cursor_reset(struct intelfb_info *dinfo); extern int intelfbhw_enable_irq(struct intelfb_info *dinfo); extern void intelfbhw_disable_irq(struct intelfb_info *dinfo); extern int intelfbhw_wait_for_vsync(struct intelfb_info *dinfo, u32 pipe); +extern int intelfbhw_active_pipe(const struct intelfb_hwstate *hw); #endif /* _INTELFBHW_H */ diff --git a/drivers/video/matrox/g450_pll.c b/drivers/video/matrox/g450_pll.c index 09f6e045d5b..c15f8a57498 100644 --- a/drivers/video/matrox/g450_pll.c +++ b/drivers/video/matrox/g450_pll.c @@ -368,7 +368,8 @@ static int __g450_setclk(struct matrox_fb_info *minfo, unsigned int fout, M1064_XDVICLKCTRL_C1DVICLKEN | M1064_XDVICLKCTRL_DVILOOPCTL | M1064_XDVICLKCTRL_P1LOOPBWDTCTL; - matroxfb_DAC_out(minfo, M1064_XDVICLKCTRL, tmp); + /* Setting this breaks PC systems so don't do it */ + /* matroxfb_DAC_out(minfo, M1064_XDVICLKCTRL, tmp); */ matroxfb_DAC_out(minfo, M1064_XPWRCTRL, xpwrctrl); diff --git a/drivers/video/maxinefb.c b/drivers/video/maxinefb.c index 5e91c2b30af..7854c7a37dc 100644 --- a/drivers/video/maxinefb.c +++ b/drivers/video/maxinefb.c @@ -92,6 +92,9 @@ static int maxinefb_setcolreg(unsigned regno, unsigned red, unsigned green, /* value to be written into the palette reg. */ unsigned long hw_colorvalue = 0; + if (regno > 255) + return 1; + red >>= 8; /* The cmap fields are 16 bits */ green >>= 8; /* wide, but the harware colormap */ blue >>= 8; /* registers are only 8 bits wide */ diff --git a/drivers/video/mb862xx/Makefile b/drivers/video/mb862xx/Makefile index 07664814bb1..d7777714166 100644 --- a/drivers/video/mb862xx/Makefile +++ b/drivers/video/mb862xx/Makefile @@ -2,4 +2,4 @@ # Makefile for the MB862xx framebuffer driver # -obj-$(CONFIG_FB_MB862XX) := mb862xxfb.o +obj-$(CONFIG_FB_MB862XX) := mb862xxfb.o mb862xxfb_accel.o diff --git a/drivers/video/mb862xx/mb862xxfb.c b/drivers/video/mb862xx/mb862xxfb.c index a28e3cfbbf7..fabb0c59a21 100644 --- a/drivers/video/mb862xx/mb862xxfb.c +++ b/drivers/video/mb862xx/mb862xxfb.c @@ -214,6 +214,8 @@ static int mb862xxfb_set_par(struct fb_info *fbi) unsigned long reg, sc; dev_dbg(par->dev, "%s\n", __func__); + if (par->type == BT_CORALP) + mb862xxfb_init_accel(fbi, fbi->var.xres); if (par->pre_init) return 0; @@ -453,6 +455,18 @@ static ssize_t mb862xxfb_show_dispregs(struct device *dev, ptr += sprintf(ptr, "%08x = %08x\n", reg, inreg(disp, reg)); + for (reg = 0x400; reg <= 0x410; reg += 4) + ptr += sprintf(ptr, "geo %08x = %08x\n", + reg, inreg(geo, reg)); + + for (reg = 0x400; reg <= 0x410; reg += 4) + ptr += sprintf(ptr, "draw %08x = %08x\n", + reg, inreg(draw, reg)); + + for (reg = 0x440; reg <= 0x450; reg += 4) + ptr += sprintf(ptr, "draw %08x = %08x\n", + reg, inreg(draw, reg)); + return ptr - buf; } diff --git a/drivers/video/mb862xx/mb862xxfb.h b/drivers/video/mb862xx/mb862xxfb.h index c4c8f4dd221..d7e7cb76bbf 100644 --- a/drivers/video/mb862xx/mb862xxfb.h +++ b/drivers/video/mb862xx/mb862xxfb.h @@ -61,6 +61,8 @@ struct mb862xxfb_par { u32 pseudo_palette[16]; }; +extern void mb862xxfb_init_accel(struct fb_info *info, int xres); + #if defined(CONFIG_FB_MB862XX_LIME) && defined(CONFIG_FB_MB862XX_PCI_GDC) #error "Select Lime GDC or CoralP/Carmine support, but not both together" #endif diff --git a/drivers/video/mb862xx/mb862xxfb_accel.c b/drivers/video/mb862xx/mb862xxfb_accel.c new file mode 100644 index 00000000000..049256052b1 --- /dev/null +++ b/drivers/video/mb862xx/mb862xxfb_accel.c @@ -0,0 +1,331 @@ +/* + * drivers/mb862xx/mb862xxfb_accel.c + * + * Fujitsu Carmine/Coral-P(A)/Lime framebuffer driver acceleration support + * + * (C) 2007 Alexander Shishkin <virtuoso@slind.org> + * (C) 2009 Valentin Sitdikov <valentin.sitdikov@siemens.com> + * (C) 2009 Siemens AG + * + * 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. + * + */ +#include <linux/fb.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/pci.h> +#if defined(CONFIG_OF) +#include <linux/of_platform.h> +#endif +#include "mb862xxfb.h" +#include "mb862xx_reg.h" +#include "mb862xxfb_accel.h" + +static void mb862xxfb_write_fifo(u32 count, u32 *data, struct fb_info *info) +{ + struct mb862xxfb_par *par = info->par; + static u32 free; + + u32 total = 0; + while (total < count) { + if (free) { + outreg(geo, GDC_GEO_REG_INPUT_FIFO, data[total]); + total++; + free--; + } else { + free = (u32) inreg(draw, GDC_REG_FIFO_COUNT); + } + } +} + +static void mb86290fb_copyarea(struct fb_info *info, + const struct fb_copyarea *area) +{ + __u32 cmd[6]; + + cmd[0] = (GDC_TYPE_SETREGISTER << 24) | (1 << 16) | GDC_REG_MODE_BITMAP; + /* Set raster operation */ + cmd[1] = (2 << 7) | (GDC_ROP_COPY << 9); + cmd[2] = GDC_TYPE_BLTCOPYP << 24; + + if (area->sx >= area->dx && area->sy >= area->dy) + cmd[2] |= GDC_CMD_BLTCOPY_TOP_LEFT << 16; + else if (area->sx >= area->dx && area->sy <= area->dy) + cmd[2] |= GDC_CMD_BLTCOPY_BOTTOM_LEFT << 16; + else if (area->sx <= area->dx && area->sy >= area->dy) + cmd[2] |= GDC_CMD_BLTCOPY_TOP_RIGHT << 16; + else + cmd[2] |= GDC_CMD_BLTCOPY_BOTTOM_RIGHT << 16; + + cmd[3] = (area->sy << 16) | area->sx; + cmd[4] = (area->dy << 16) | area->dx; + cmd[5] = (area->height << 16) | area->width; + mb862xxfb_write_fifo(6, cmd, info); +} + +/* + * Fill in the cmd array /GDC FIFO commands/ to draw a 1bit image. + * Make sure cmd has enough room! + */ +static void mb86290fb_imageblit1(u32 *cmd, u16 step, u16 dx, u16 dy, + u16 width, u16 height, u32 fgcolor, + u32 bgcolor, const struct fb_image *image, + struct fb_info *info) +{ + int i; + unsigned const char *line; + u16 bytes; + + /* set colors and raster operation regs */ + cmd[0] = (GDC_TYPE_SETREGISTER << 24) | (1 << 16) | GDC_REG_MODE_BITMAP; + /* Set raster operation */ + cmd[1] = (2 << 7) | (GDC_ROP_COPY << 9); + cmd[2] = + (GDC_TYPE_SETCOLORREGISTER << 24) | (GDC_CMD_BODY_FORE_COLOR << 16); + cmd[3] = fgcolor; + cmd[4] = + (GDC_TYPE_SETCOLORREGISTER << 24) | (GDC_CMD_BODY_BACK_COLOR << 16); + cmd[5] = bgcolor; + + i = 0; + line = image->data; + bytes = (image->width + 7) >> 3; + + /* and the image */ + cmd[6] = (GDC_TYPE_DRAWBITMAPP << 24) | + (GDC_CMD_BITMAP << 16) | (2 + (step * height)); + cmd[7] = (dy << 16) | dx; + cmd[8] = (height << 16) | width; + + while (i < height) { + memcpy(&cmd[9 + i * step], line, step << 2); +#ifdef __LITTLE_ENDIAN + { + int k = 0; + for (k = 0; k < step; k++) + cmd[9 + i * step + k] = + cpu_to_be32(cmd[9 + i * step + k]); + } +#endif + line += bytes; + i++; + } +} + +/* + * Fill in the cmd array /GDC FIFO commands/ to draw a 8bit image. + * Make sure cmd has enough room! + */ +static void mb86290fb_imageblit8(u32 *cmd, u16 step, u16 dx, u16 dy, + u16 width, u16 height, u32 fgcolor, + u32 bgcolor, const struct fb_image *image, + struct fb_info *info) +{ + int i, j; + unsigned const char *line, *ptr; + u16 bytes; + + cmd[0] = (GDC_TYPE_DRAWBITMAPP << 24) | + (GDC_CMD_BLT_DRAW << 16) | (2 + (height * step)); + cmd[1] = (dy << 16) | dx; + cmd[2] = (height << 16) | width; + + i = 0; + line = ptr = image->data; + bytes = image->width; + + while (i < height) { + ptr = line; + for (j = 0; j < step; j++) { + cmd[3 + i * step + j] = + (((u32 *) (info->pseudo_palette))[*ptr]) & 0xffff; + ptr++; + cmd[3 + i * step + j] |= + ((((u32 *) (info-> + pseudo_palette))[*ptr]) & 0xffff) << 16; + ptr++; + } + + line += bytes; + i++; + } +} + +/* + * Fill in the cmd array /GDC FIFO commands/ to draw a 16bit image. + * Make sure cmd has enough room! + */ +static void mb86290fb_imageblit16(u32 *cmd, u16 step, u16 dx, u16 dy, + u16 width, u16 height, u32 fgcolor, + u32 bgcolor, const struct fb_image *image, + struct fb_info *info) +{ + int i; + unsigned const char *line; + u16 bytes; + + i = 0; + line = image->data; + bytes = image->width << 1; + + cmd[0] = (GDC_TYPE_DRAWBITMAPP << 24) | + (GDC_CMD_BLT_DRAW << 16) | (2 + step * height); + cmd[1] = (dy << 16) | dx; + cmd[2] = (height << 16) | width; + + while (i < height) { + memcpy(&cmd[3 + i * step], line, step); + line += bytes; + i++; + } +} + +static void mb86290fb_imageblit(struct fb_info *info, + const struct fb_image *image) +{ + int mdr; + u32 *cmd = NULL; + void (*cmdfn) (u32 *, u16, u16, u16, u16, u16, u32, u32, + const struct fb_image *, struct fb_info *) = NULL; + u32 cmdlen; + u32 fgcolor = 0, bgcolor = 0; + u16 step; + + u16 width = image->width, height = image->height; + u16 dx = image->dx, dy = image->dy; + int x2, y2, vxres, vyres; + + mdr = (GDC_ROP_COPY << 9); + x2 = image->dx + image->width; + y2 = image->dy + image->height; + vxres = info->var.xres_virtual; + vyres = info->var.yres_virtual; + x2 = min(x2, vxres); + y2 = min(y2, vyres); + width = x2 - dx; + height = y2 - dy; + + switch (image->depth) { + case 1: + step = (width + 31) >> 5; + cmdlen = 9 + height * step; + cmdfn = mb86290fb_imageblit1; + if (info->fix.visual == FB_VISUAL_TRUECOLOR || + info->fix.visual == FB_VISUAL_DIRECTCOLOR) { + fgcolor = + ((u32 *) (info->pseudo_palette))[image->fg_color]; + bgcolor = + ((u32 *) (info->pseudo_palette))[image->bg_color]; + } else { + fgcolor = image->fg_color; + bgcolor = image->bg_color; + } + + break; + + case 8: + step = (width + 1) >> 1; + cmdlen = 3 + height * step; + cmdfn = mb86290fb_imageblit8; + break; + + case 16: + step = (width + 1) >> 1; + cmdlen = 3 + height * step; + cmdfn = mb86290fb_imageblit16; + break; + + default: + cfb_imageblit(info, image); + return; + } + + cmd = kmalloc(cmdlen * 4, GFP_DMA); + if (!cmd) + return cfb_imageblit(info, image); + cmdfn(cmd, step, dx, dy, width, height, fgcolor, bgcolor, image, info); + mb862xxfb_write_fifo(cmdlen, cmd, info); + kfree(cmd); +} + +static void mb86290fb_fillrect(struct fb_info *info, + const struct fb_fillrect *rect) +{ + + u32 x2, y2, vxres, vyres, height, width, fg; + u32 cmd[7]; + + vxres = info->var.xres_virtual; + vyres = info->var.yres_virtual; + + if (!rect->width || !rect->height || rect->dx > vxres + || rect->dy > vyres) + return; + + /* We could use hardware clipping but on many cards you get around + * hardware clipping by writing to framebuffer directly. */ + x2 = rect->dx + rect->width; + y2 = rect->dy + rect->height; + x2 = min(x2, vxres); + y2 = min(y2, vyres); + width = x2 - rect->dx; + height = y2 - rect->dy; + if (info->fix.visual == FB_VISUAL_TRUECOLOR || + info->fix.visual == FB_VISUAL_DIRECTCOLOR) + fg = ((u32 *) (info->pseudo_palette))[rect->color]; + else + fg = rect->color; + + switch (rect->rop) { + + case ROP_XOR: + /* Set raster operation */ + cmd[1] = (2 << 7) | (GDC_ROP_XOR << 9); + break; + + case ROP_COPY: + /* Set raster operation */ + cmd[1] = (2 << 7) | (GDC_ROP_COPY << 9); + break; + + } + + cmd[0] = (GDC_TYPE_SETREGISTER << 24) | (1 << 16) | GDC_REG_MODE_BITMAP; + /* cmd[1] set earlier */ + cmd[2] = + (GDC_TYPE_SETCOLORREGISTER << 24) | (GDC_CMD_BODY_FORE_COLOR << 16); + cmd[3] = fg; + cmd[4] = (GDC_TYPE_DRAWRECTP << 24) | (GDC_CMD_BLT_FILL << 16); + cmd[5] = (rect->dy << 16) | (rect->dx); + cmd[6] = (height << 16) | width; + + mb862xxfb_write_fifo(7, cmd, info); +} + +void mb862xxfb_init_accel(struct fb_info *info, int xres) +{ + struct mb862xxfb_par *par = info->par; + + if (info->var.bits_per_pixel == 32) { + info->fbops->fb_fillrect = cfb_fillrect; + info->fbops->fb_copyarea = cfb_copyarea; + info->fbops->fb_imageblit = cfb_imageblit; + } else { + outreg(disp, GC_L0EM, 3); + info->fbops->fb_fillrect = mb86290fb_fillrect; + info->fbops->fb_copyarea = mb86290fb_copyarea; + info->fbops->fb_imageblit = mb86290fb_imageblit; + } + outreg(draw, GDC_REG_DRAW_BASE, 0); + outreg(draw, GDC_REG_MODE_MISC, 0x8000); + outreg(draw, GDC_REG_X_RESOLUTION, xres); + + info->flags |= + FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT | + FBINFO_HWACCEL_IMAGEBLIT; + info->fix.accel = 0xff; /*FIXME: add right define */ +} +EXPORT_SYMBOL(mb862xxfb_init_accel); diff --git a/drivers/video/mb862xx/mb862xxfb_accel.h b/drivers/video/mb862xx/mb862xxfb_accel.h new file mode 100644 index 00000000000..96a2dfef0f6 --- /dev/null +++ b/drivers/video/mb862xx/mb862xxfb_accel.h @@ -0,0 +1,203 @@ +#ifndef __MB826XXFB_ACCEL_H__ +#define __MB826XXFB_ACCEL_H__ + +/* registers */ +#define GDC_GEO_REG_INPUT_FIFO 0x00000400L + +/* Special Registers */ +#define GDC_REG_CTRL 0x00000400L +#define GDC_REG_FIFO_STATUS 0x00000404L +#define GDC_REG_FIFO_COUNT 0x00000408L +#define GDC_REG_SETUP_STATUS 0x0000040CL +#define GDC_REG_DDA_STATUS 0x00000410L +#define GDC_REG_ENGINE_STATUS 0x00000414L +#define GDC_REG_ERROR_STATUS 0x00000418L +#define GDC_REG_MODE_MISC 0x00000420L /* MDR0 */ +#define GDC_REG_MODE_LINE 0x00000424L /* MDR1 */ +#define GDC_REG_MODE_POLYGON 0x00000428L /* MDR2 */ +#define GDC_REG_MODE_TEXTURE 0x0000042CL /* MDR3 */ +#define GDC_REG_MODE_BITMAP 0x00000430L /* MDR4 */ +#define GDC_REG_MODE_EXTENSION 0x0000043CL /* MDR7 */ + +/* Configuration Registers */ +#define GDC_REG_DRAW_BASE 0x00000440L +#define GDC_REG_X_RESOLUTION 0x00000444L +#define GDC_REG_Z_BASE 0x00000448L +#define GDC_REG_TEXTURE_BASE 0x0000044CL +#define GDC_REG_POLYGON_FLAG_BASE 0x00000450L +#define GDC_REG_CLIP_XMIN 0x00000454L +#define GDC_REG_CLIP_XMAX 0x00000458L +#define GDC_REG_CLIP_YMIN 0x0000045CL +#define GDC_REG_CLIP_YMAX 0x00000460L +#define GDC_REG_TEXURE_SIZE 0x00000464L +#define GDC_REG_TILE_SIZE 0x00000468L +#define GDC_REG_TEX_BUF_OFFSET 0x0000046CL + +/* for MB86293 or later */ +#define GDC_REG_ALPHA_MAP_BASE 0x00000474L /* ABR */ + +/* Constant Registers */ +#define GDC_REG_FOREGROUND_COLOR 0x00000480L +#define GDC_REG_BACKGROUND_COLOR 0x00000484L +#define GDC_REG_ALPHA 0x00000488L +#define GDC_REG_LINE_PATTERN 0x0000048CL +#define GDC_REG_TEX_BORDER_COLOR 0x00000494L +#define GDC_REG_LINE_PATTERN_OFFSET 0x000003E0L + +/* Coomand Code */ +#define GDC_CMD_PIXEL 0x00000000L +#define GDC_CMD_PIXEL_Z 0x00000001L + +#define GDC_CMD_X_VECTOR 0x00000020L +#define GDC_CMD_Y_VECTOR 0x00000021L +#define GDC_CMD_X_VECTOR_NOEND 0x00000022L +#define GDC_CMD_Y_VECTOR_NOEND 0x00000023L +#define GDC_CMD_X_VECTOR_BLPO 0x00000024L +#define GDC_CMD_Y_VECTOR_BLPO 0x00000025L +#define GDC_CMD_X_VECTOR_NOEND_BLPO 0x00000026L +#define GDC_CMD_Y_VECTOR_NOEND_BLPO 0x00000027L +#define GDC_CMD_AA_X_VECTOR 0x00000028L +#define GDC_CMD_AA_Y_VECTOR 0x00000029L +#define GDC_CMD_AA_X_VECTOR_NOEND 0x0000002AL +#define GDC_CMD_AA_Y_VECTOR_NOEND 0x0000002BL +#define GDC_CMD_AA_X_VECTOR_BLPO 0x0000002CL +#define GDC_CMD_AA_Y_VECTOR_BLPO 0x0000002DL +#define GDC_CMD_AA_X_VECTOR_NOEND_BLPO 0x0000002EL +#define GDC_CMD_AA_Y_VECTOR_NOEND_BLPO 0x0000002FL + +#define GDC_CMD_0_VECTOR 0x00000030L +#define GDC_CMD_1_VECTOR 0x00000031L +#define GDC_CMD_0_VECTOR_NOEND 0x00000032L +#define GDC_CMD_1_VECTOR_NOEND 0x00000033L +#define GDC_CMD_0_VECTOR_BLPO 0x00000034L +#define GDC_CMD_1_VECTOR_BLPO 0x00000035L +#define GDC_CMD_0_VECTOR_NOEND_BLPO 0x00000036L +#define GDC_CMD_1_VECTOR_NOEND_BLPO 0x00000037L +#define GDC_CMD_AA_0_VECTOR 0x00000038L +#define GDC_CMD_AA_1_VECTOR 0x00000039L +#define GDC_CMD_AA_0_VECTOR_NOEND 0x0000003AL +#define GDC_CMD_AA_1_VECTOR_NOEND 0x0000003BL +#define GDC_CMD_AA_0_VECTOR_BLPO 0x0000003CL +#define GDC_CMD_AA_1_VECTOR_BLPO 0x0000003DL +#define GDC_CMD_AA_0_VECTOR_NOEND_BLPO 0x0000003EL +#define GDC_CMD_AA_1_VECTOR_NOEND_BLPO 0x0000003FL + +#define GDC_CMD_BLT_FILL 0x00000041L +#define GDC_CMD_BLT_DRAW 0x00000042L +#define GDC_CMD_BITMAP 0x00000043L +#define GDC_CMD_BLTCOPY_TOP_LEFT 0x00000044L +#define GDC_CMD_BLTCOPY_TOP_RIGHT 0x00000045L +#define GDC_CMD_BLTCOPY_BOTTOM_LEFT 0x00000046L +#define GDC_CMD_BLTCOPY_BOTTOM_RIGHT 0x00000047L +#define GDC_CMD_LOAD_TEXTURE 0x00000048L +#define GDC_CMD_LOAD_TILE 0x00000049L + +#define GDC_CMD_TRAP_RIGHT 0x00000060L +#define GDC_CMD_TRAP_LEFT 0x00000061L +#define GDC_CMD_TRIANGLE_FAN 0x00000062L +#define GDC_CMD_FLAG_TRIANGLE_FAN 0x00000063L + +#define GDC_CMD_FLUSH_FB 0x000000C1L +#define GDC_CMD_FLUSH_Z 0x000000C2L + +#define GDC_CMD_POLYGON_BEGIN 0x000000E0L +#define GDC_CMD_POLYGON_END 0x000000E1L +#define GDC_CMD_CLEAR_POLY_FLAG 0x000000E2L +#define GDC_CMD_NORMAL 0x000000FFL + +#define GDC_CMD_VECTOR_BLPO_FLAG 0x00040000L +#define GDC_CMD_FAST_VECTOR_BLPO_FLAG 0x00000004L + +/* for MB86293 or later */ +#define GDC_CMD_MDR1 0x00000000L +#define GDC_CMD_MDR1S 0x00000002L +#define GDC_CMD_MDR1B 0x00000004L +#define GDC_CMD_MDR2 0x00000001L +#define GDC_CMD_MDR2S 0x00000003L +#define GDC_CMD_MDR2TL 0x00000007L +#define GDC_CMD_GMDR1E 0x00000010L +#define GDC_CMD_GMDR2E 0x00000020L +#define GDC_CMD_OVERLAP_SHADOW_XY 0x00000000L +#define GDC_CMD_OVERLAP_SHADOW_XY_COMPOSITION 0x00000001L +#define GDC_CMD_OVERLAP_Z_PACKED_ONBS 0x00000007L +#define GDC_CMD_OVERLAP_Z_ORIGIN 0x00000000L +#define GDC_CMD_OVERLAP_Z_NON_TOPLEFT 0x00000001L +#define GDC_CMD_OVERLAP_Z_BORDER 0x00000002L +#define GDC_CMD_OVERLAP_Z_SHADOW 0x00000003L +#define GDC_CMD_BLTCOPY_ALT_ALPHA 0x00000000L /* Reserverd */ +#define GDC_CMD_DC_LOGOUT 0x00000000L /* Reserverd */ +#define GDC_CMD_BODY_FORE_COLOR 0x00000000L +#define GDC_CMD_BODY_BACK_COLOR 0x00000001L +#define GDC_CMD_SHADOW_FORE_COLOR 0x00000002L +#define GDC_CMD_SHADOW_BACK_COLOR 0x00000003L +#define GDC_CMD_BORDER_FORE_COLOR 0x00000004L +#define GDC_CMD_BORDER_BACK_COLOR 0x00000005L + +/* Type Code Table */ +#define GDC_TYPE_G_NOP 0x00000020L +#define GDC_TYPE_G_BEGIN 0x00000021L +#define GDC_TYPE_G_BEGINCONT 0x00000022L +#define GDC_TYPE_G_END 0x00000023L +#define GDC_TYPE_G_VERTEX 0x00000030L +#define GDC_TYPE_G_VERTEXLOG 0x00000032L +#define GDC_TYPE_G_VERTEXNOPLOG 0x00000033L +#define GDC_TYPE_G_INIT 0x00000040L +#define GDC_TYPE_G_VIEWPORT 0x00000041L +#define GDC_TYPE_G_DEPTHRANGE 0x00000042L +#define GDC_TYPE_G_LOADMATRIX 0x00000043L +#define GDC_TYPE_G_VIEWVOLUMEXYCLIP 0x00000044L +#define GDC_TYPE_G_VIEWVOLUMEZCLIP 0x00000045L +#define GDC_TYPE_G_VIEWVOLUMEWCLIP 0x00000046L +#define GDC_TYPE_SETLVERTEX2I 0x00000072L +#define GDC_TYPE_SETLVERTEX2IP 0x00000073L +#define GDC_TYPE_SETMODEREGISTER 0x000000C0L +#define GDC_TYPE_SETGMODEREGISTER 0x000000C1L +#define GDC_TYPE_OVERLAPXYOFFT 0x000000C8L +#define GDC_TYPE_OVERLAPZOFFT 0x000000C9L +#define GDC_TYPE_DC_LOGOUTADDR 0x000000CCL +#define GDC_TYPE_SETCOLORREGISTER 0x000000CEL +#define GDC_TYPE_G_BEGINE 0x000000E1L +#define GDC_TYPE_G_BEGINCONTE 0x000000E2L +#define GDC_TYPE_G_ENDE 0x000000E3L +#define GDC_TYPE_DRAWPIXEL 0x00000000L +#define GDC_TYPE_DRAWPIXELZ 0x00000001L +#define GDC_TYPE_DRAWLINE 0x00000002L +#define GDC_TYPE_DRAWLINE2I 0x00000003L +#define GDC_TYPE_DRAWLINE2IP 0x00000004L +#define GDC_TYPE_DRAWTRAP 0x00000005L +#define GDC_TYPE_DRAWVERTEX2I 0x00000006L +#define GDC_TYPE_DRAWVERTEX2IP 0x00000007L +#define GDC_TYPE_DRAWRECTP 0x00000009L +#define GDC_TYPE_DRAWBITMAPP 0x0000000BL +#define GDC_TYPE_BLTCOPYP 0x0000000DL +#define GDC_TYPE_BLTCOPYALTERNATEP 0x0000000FL +#define GDC_TYPE_LOADTEXTUREP 0x00000011L +#define GDC_TYPE_BLTTEXTUREP 0x00000013L +#define GDC_TYPE_BLTCOPYALTALPHABLENDP 0x0000001FL +#define GDC_TYPE_SETVERTEX2I 0x00000070L +#define GDC_TYPE_SETVERTEX2IP 0x00000071L +#define GDC_TYPE_DRAW 0x000000F0L +#define GDC_TYPE_SETREGISTER 0x000000F1L +#define GDC_TYPE_SYNC 0x000000FCL +#define GDC_TYPE_INTERRUPT 0x000000FDL +#define GDC_TYPE_NOP 0x0 + +/* Raster operation */ +#define GDC_ROP_CLEAR 0x0000 +#define GDC_ROP_AND 0x0001 +#define GDC_ROP_AND_REVERSE 0x0002 +#define GDC_ROP_COPY 0x0003 +#define GDC_ROP_AND_INVERTED 0x0004 +#define GDC_ROP_NOP 0x0005 +#define GDC_ROP_XOR 0x0006 +#define GDC_ROP_OR 0x0007 +#define GDC_ROP_NOR 0x0008 +#define GDC_ROP_EQUIV 0x0009 +#define GDC_ROP_INVERT 0x000A +#define GDC_ROP_OR_REVERSE 0x000B +#define GDC_ROP_COPY_INVERTED 0x000C +#define GDC_ROP_OR_INVERTED 0x000D +#define GDC_ROP_NAND 0x000E +#define GDC_ROP_SET 0x000F + +#endif diff --git a/drivers/video/modedb.c b/drivers/video/modedb.c index 34e4e799516..0129f1bc352 100644 --- a/drivers/video/modedb.c +++ b/drivers/video/modedb.c @@ -13,6 +13,7 @@ #include <linux/module.h> #include <linux/fb.h> +#include <linux/kernel.h> #undef DEBUG @@ -402,21 +403,6 @@ const struct fb_videomode vesa_modes[] = { EXPORT_SYMBOL(vesa_modes); #endif /* CONFIG_FB_MODE_HELPERS */ -static int my_atoi(const char *name) -{ - int val = 0; - - for (;; name++) { - switch (*name) { - case '0' ... '9': - val = 10*val+(*name-'0'); - break; - default: - return val; - } - } -} - /** * fb_try_mode - test a video mode * @var: frame buffer user defined part of display @@ -539,7 +525,7 @@ int fb_find_mode(struct fb_var_screeninfo *var, namelen = i; if (!refresh_specified && !bpp_specified && !yres_specified) { - refresh = my_atoi(&name[i+1]); + refresh = simple_strtol(&name[i+1], NULL, 10); refresh_specified = 1; if (cvt || rb) cvt = 0; @@ -549,7 +535,7 @@ int fb_find_mode(struct fb_var_screeninfo *var, case '-': namelen = i; if (!bpp_specified && !yres_specified) { - bpp = my_atoi(&name[i+1]); + bpp = simple_strtol(&name[i+1], NULL, 10); bpp_specified = 1; if (cvt || rb) cvt = 0; @@ -558,7 +544,7 @@ int fb_find_mode(struct fb_var_screeninfo *var, break; case 'x': if (!yres_specified) { - yres = my_atoi(&name[i+1]); + yres = simple_strtol(&name[i+1], NULL, 10); yres_specified = 1; } else goto done; @@ -586,7 +572,7 @@ int fb_find_mode(struct fb_var_screeninfo *var, } } if (i < 0 && yres_specified) { - xres = my_atoi(name); + xres = simple_strtol(name, NULL, 10); res_specified = 1; } done: diff --git a/drivers/video/pmag-ba-fb.c b/drivers/video/pmag-ba-fb.c index 0573ec685a5..0f361b6100d 100644 --- a/drivers/video/pmag-ba-fb.c +++ b/drivers/video/pmag-ba-fb.c @@ -98,7 +98,8 @@ static int pmagbafb_setcolreg(unsigned int regno, unsigned int red, { struct pmagbafb_par *par = info->par; - BUG_ON(regno >= info->cmap.len); + if (regno >= info->cmap.len) + return 1; red >>= 8; /* The cmap fields are 16 bits */ green >>= 8; /* wide, but the hardware colormap */ diff --git a/drivers/video/pmagb-b-fb.c b/drivers/video/pmagb-b-fb.c index 98748723af9..2de0806421b 100644 --- a/drivers/video/pmagb-b-fb.c +++ b/drivers/video/pmagb-b-fb.c @@ -102,7 +102,8 @@ static int pmagbbfb_setcolreg(unsigned int regno, unsigned int red, { struct pmagbbfb_par *par = info->par; - BUG_ON(regno >= info->cmap.len); + if (regno >= info->cmap.len) + return 1; red >>= 8; /* The cmap fields are 16 bits */ green >>= 8; /* wide, but the hardware colormap */ diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c index b7e58059b59..415858b421b 100644 --- a/drivers/video/pxafb.c +++ b/drivers/video/pxafb.c @@ -1221,13 +1221,14 @@ static void setup_smart_timing(struct pxafb_info *fbi, static int pxafb_smart_thread(void *arg) { struct pxafb_info *fbi = arg; - struct pxafb_mach_info *inf = fbi->dev->platform_data; + struct pxafb_mach_info *inf; - if (!fbi || !inf->smart_update) { + if (!fbi || !fbi->dev->platform_data->smart_update) { pr_err("%s: not properly initialized, thread terminated\n", __func__); return -EINVAL; } + inf = fbi->dev->platform_data; pr_debug("%s(): task starting\n", __func__); diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c index 8a65fb6648a..a69830d26f7 100644 --- a/drivers/video/sh_mobile_lcdcfb.c +++ b/drivers/video/sh_mobile_lcdcfb.c @@ -281,6 +281,7 @@ static void sh_mobile_lcdc_deferred_io(struct fb_info *info, struct list_head *pagelist) { struct sh_mobile_lcdc_chan *ch = info->par; + struct sh_mobile_lcdc_board_cfg *bcfg = &ch->cfg.board_cfg; /* enable clocks before accessing hardware */ sh_mobile_lcdc_clk_on(ch->lcdc); @@ -305,10 +306,17 @@ static void sh_mobile_lcdc_deferred_io(struct fb_info *info, /* trigger panel update */ dma_map_sg(info->dev, ch->sglist, nr_pages, DMA_TO_DEVICE); + if (bcfg->start_transfer) + bcfg->start_transfer(bcfg->board_data, ch, + &sh_mobile_lcdc_sys_bus_ops); lcdc_write_chan(ch, LDSM2R, 1); dma_unmap_sg(info->dev, ch->sglist, nr_pages, DMA_TO_DEVICE); - } else + } else { + if (bcfg->start_transfer) + bcfg->start_transfer(bcfg->board_data, ch, + &sh_mobile_lcdc_sys_bus_ops); lcdc_write_chan(ch, LDSM2R, 1); + } } static void sh_mobile_lcdc_deferred_io_touch(struct fb_info *info) diff --git a/drivers/video/sis/sis_main.c b/drivers/video/sis/sis_main.c index a4e05e4d750..9d2b6bc4903 100644 --- a/drivers/video/sis/sis_main.c +++ b/drivers/video/sis/sis_main.c @@ -2115,7 +2115,7 @@ sisfb_detect_VB_connect(struct sis_video_info *ivideo) if( (!(ivideo->vbflags2 & VB2_SISBRIDGE)) && (!((ivideo->sisvga_engine == SIS_315_VGA) && (ivideo->vbflags2 & VB2_CHRONTEL))) ) { - if(ivideo->sisfb_tvstd & (TV_PALN | TV_PALN | TV_NTSCJ)) { + if(ivideo->sisfb_tvstd & (TV_PALM | TV_PALN | TV_NTSCJ)) { ivideo->sisfb_tvstd = -1; printk(KERN_ERR "sisfb: PALM/PALN/NTSCJ not supported\n"); } diff --git a/drivers/video/sm501fb.c b/drivers/video/sm501fb.c index 924d7946278..35370d0ecf0 100644 --- a/drivers/video/sm501fb.c +++ b/drivers/video/sm501fb.c @@ -29,8 +29,8 @@ #include <linux/platform_device.h> #include <linux/clk.h> #include <linux/console.h> +#include <linux/io.h> -#include <asm/io.h> #include <asm/uaccess.h> #include <asm/div64.h> @@ -66,6 +66,7 @@ struct sm501fb_info { struct fb_info *fb[2]; /* fb info for both heads */ struct resource *fbmem_res; /* framebuffer resource */ struct resource *regs_res; /* registers resource */ + struct resource *regs2d_res; /* 2d registers resource */ struct sm501_platdata_fb *pdata; /* our platform data */ unsigned long pm_crt_ctrl; /* pm: crt ctrl save */ @@ -73,6 +74,7 @@ struct sm501fb_info { int irq; int swap_endian; /* set to swap rgb=>bgr */ void __iomem *regs; /* remapped registers */ + void __iomem *regs2d; /* 2d remapped registers */ void __iomem *fbmem; /* remapped framebuffer */ size_t fbmem_len; /* length of remapped region */ }; @@ -123,9 +125,9 @@ static inline void sm501fb_sync_regs(struct sm501fb_info *info) * This is an attempt to lay out memory for the two framebuffers and * everything else * - * |fbmem_res->start fbmem_res->end| - * | | - * |fb[0].fix.smem_start | |fb[1].fix.smem_start | 2K | + * |fbmem_res->start fbmem_res->end| + * | | + * |fb[0].fix.smem_start | |fb[1].fix.smem_start | 2K | * |-> fb[0].fix.smem_len <-| spare |-> fb[1].fix.smem_len <-|-> cursors <-| * * The "spare" space is for the 2d engine data @@ -1246,7 +1248,173 @@ static ssize_t sm501fb_debug_show_pnl(struct device *dev, static DEVICE_ATTR(fbregs_pnl, 0444, sm501fb_debug_show_pnl, NULL); -/* framebuffer ops */ +/* acceleration operations */ +static int sm501fb_sync(struct fb_info *info) +{ + int count = 1000000; + struct sm501fb_par *par = info->par; + struct sm501fb_info *fbi = par->info; + + /* wait for the 2d engine to be ready */ + while ((count > 0) && + (readl(fbi->regs + SM501_SYSTEM_CONTROL) & + SM501_SYSCTRL_2D_ENGINE_STATUS) != 0) + count--; + + if (count <= 0) { + dev_err(info->dev, "Timeout waiting for 2d engine sync\n"); + return 1; + } + return 0; +} + +static void sm501fb_copyarea(struct fb_info *info, const struct fb_copyarea *area) +{ + struct sm501fb_par *par = info->par; + struct sm501fb_info *fbi = par->info; + int width = area->width; + int height = area->height; + int sx = area->sx; + int sy = area->sy; + int dx = area->dx; + int dy = area->dy; + unsigned long rtl = 0; + + /* source clip */ + if ((sx >= info->var.xres_virtual) || + (sy >= info->var.yres_virtual)) + /* source Area not within virtual screen, skipping */ + return; + if ((sx + width) >= info->var.xres_virtual) + width = info->var.xres_virtual - sx - 1; + if ((sy + height) >= info->var.yres_virtual) + height = info->var.yres_virtual - sy - 1; + + /* dest clip */ + if ((dx >= info->var.xres_virtual) || + (dy >= info->var.yres_virtual)) + /* Destination Area not within virtual screen, skipping */ + return; + if ((dx + width) >= info->var.xres_virtual) + width = info->var.xres_virtual - dx - 1; + if ((dy + height) >= info->var.yres_virtual) + height = info->var.yres_virtual - dy - 1; + + if ((sx < dx) || (sy < dy)) { + rtl = 1 << 27; + sx += width - 1; + dx += width - 1; + sy += height - 1; + dy += height - 1; + } + + if (sm501fb_sync(info)) + return; + + /* set the base addresses */ + writel(par->screen.sm_addr, fbi->regs2d + SM501_2D_SOURCE_BASE); + writel(par->screen.sm_addr, fbi->regs2d + SM501_2D_DESTINATION_BASE); + + /* set the window width */ + writel((info->var.xres << 16) | info->var.xres, + fbi->regs2d + SM501_2D_WINDOW_WIDTH); + + /* set window stride */ + writel((info->var.xres_virtual << 16) | info->var.xres_virtual, + fbi->regs2d + SM501_2D_PITCH); + + /* set data format */ + switch (info->var.bits_per_pixel) { + case 8: + writel(0, fbi->regs2d + SM501_2D_STRETCH); + break; + case 16: + writel(0x00100000, fbi->regs2d + SM501_2D_STRETCH); + break; + case 32: + writel(0x00200000, fbi->regs2d + SM501_2D_STRETCH); + break; + } + + /* 2d compare mask */ + writel(0xffffffff, fbi->regs2d + SM501_2D_COLOR_COMPARE_MASK); + + /* 2d mask */ + writel(0xffffffff, fbi->regs2d + SM501_2D_MASK); + + /* source and destination x y */ + writel((sx << 16) | sy, fbi->regs2d + SM501_2D_SOURCE); + writel((dx << 16) | dy, fbi->regs2d + SM501_2D_DESTINATION); + + /* w/h */ + writel((width << 16) | height, fbi->regs2d + SM501_2D_DIMENSION); + + /* do area move */ + writel(0x800000cc | rtl, fbi->regs2d + SM501_2D_CONTROL); +} + +static void sm501fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) +{ + struct sm501fb_par *par = info->par; + struct sm501fb_info *fbi = par->info; + int width = rect->width, height = rect->height; + + if ((rect->dx >= info->var.xres_virtual) || + (rect->dy >= info->var.yres_virtual)) + /* Rectangle not within virtual screen, skipping */ + return; + if ((rect->dx + width) >= info->var.xres_virtual) + width = info->var.xres_virtual - rect->dx - 1; + if ((rect->dy + height) >= info->var.yres_virtual) + height = info->var.yres_virtual - rect->dy - 1; + + if (sm501fb_sync(info)) + return; + + /* set the base addresses */ + writel(par->screen.sm_addr, fbi->regs2d + SM501_2D_SOURCE_BASE); + writel(par->screen.sm_addr, fbi->regs2d + SM501_2D_DESTINATION_BASE); + + /* set the window width */ + writel((info->var.xres << 16) | info->var.xres, + fbi->regs2d + SM501_2D_WINDOW_WIDTH); + + /* set window stride */ + writel((info->var.xres_virtual << 16) | info->var.xres_virtual, + fbi->regs2d + SM501_2D_PITCH); + + /* set data format */ + switch (info->var.bits_per_pixel) { + case 8: + writel(0, fbi->regs2d + SM501_2D_STRETCH); + break; + case 16: + writel(0x00100000, fbi->regs2d + SM501_2D_STRETCH); + break; + case 32: + writel(0x00200000, fbi->regs2d + SM501_2D_STRETCH); + break; + } + + /* 2d compare mask */ + writel(0xffffffff, fbi->regs2d + SM501_2D_COLOR_COMPARE_MASK); + + /* 2d mask */ + writel(0xffffffff, fbi->regs2d + SM501_2D_MASK); + + /* colour */ + writel(rect->color, fbi->regs2d + SM501_2D_FOREGROUND); + + /* x y */ + writel((rect->dx << 16) | rect->dy, fbi->regs2d + SM501_2D_DESTINATION); + + /* w/h */ + writel((width << 16) | height, fbi->regs2d + SM501_2D_DIMENSION); + + /* do rectangle fill */ + writel(0x800100cc, fbi->regs2d + SM501_2D_CONTROL); +} + static struct fb_ops sm501fb_ops_crt = { .owner = THIS_MODULE, @@ -1256,9 +1424,10 @@ static struct fb_ops sm501fb_ops_crt = { .fb_setcolreg = sm501fb_setcolreg, .fb_pan_display = sm501fb_pan_crt, .fb_cursor = sm501fb_cursor, - .fb_fillrect = cfb_fillrect, - .fb_copyarea = cfb_copyarea, + .fb_fillrect = sm501fb_fillrect, + .fb_copyarea = sm501fb_copyarea, .fb_imageblit = cfb_imageblit, + .fb_sync = sm501fb_sync, }; static struct fb_ops sm501fb_ops_pnl = { @@ -1269,9 +1438,10 @@ static struct fb_ops sm501fb_ops_pnl = { .fb_blank = sm501fb_blank_pnl, .fb_setcolreg = sm501fb_setcolreg, .fb_cursor = sm501fb_cursor, - .fb_fillrect = cfb_fillrect, - .fb_copyarea = cfb_copyarea, + .fb_fillrect = sm501fb_fillrect, + .fb_copyarea = sm501fb_copyarea, .fb_imageblit = cfb_imageblit, + .fb_sync = sm501fb_sync, }; /* sm501_init_cursor @@ -1329,7 +1499,8 @@ static int sm501fb_start(struct sm501fb_info *info, dev_warn(dev, "no irq for device\n"); } - /* allocate, reserve and remap resources for registers */ + /* allocate, reserve and remap resources for display + * controller registers */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (res == NULL) { dev_err(dev, "no resource definition for registers\n"); @@ -1338,7 +1509,7 @@ static int sm501fb_start(struct sm501fb_info *info, } info->regs_res = request_mem_region(res->start, - res->end - res->start, + resource_size(res), pdev->name); if (info->regs_res == NULL) { @@ -1347,37 +1518,63 @@ static int sm501fb_start(struct sm501fb_info *info, goto err_release; } - info->regs = ioremap(res->start, (res->end - res->start)+1); + info->regs = ioremap(res->start, resource_size(res)); if (info->regs == NULL) { dev_err(dev, "cannot remap registers\n"); ret = -ENXIO; goto err_regs_res; } + /* allocate, reserve and remap resources for 2d + * controller registers */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (res == NULL) { + dev_err(dev, "no resource definition for 2d registers\n"); + ret = -ENOENT; + goto err_regs_map; + } + + info->regs2d_res = request_mem_region(res->start, + resource_size(res), + pdev->name); + + if (info->regs2d_res == NULL) { + dev_err(dev, "cannot claim registers\n"); + ret = -ENXIO; + goto err_regs_map; + } + + info->regs2d = ioremap(res->start, resource_size(res)); + if (info->regs2d == NULL) { + dev_err(dev, "cannot remap registers\n"); + ret = -ENXIO; + goto err_regs2d_res; + } + /* allocate, reserve resources for framebuffer */ res = platform_get_resource(pdev, IORESOURCE_MEM, 2); if (res == NULL) { dev_err(dev, "no memory resource defined\n"); ret = -ENXIO; - goto err_regs_map; + goto err_regs2d_map; } info->fbmem_res = request_mem_region(res->start, - (res->end - res->start)+1, + resource_size(res), pdev->name); if (info->fbmem_res == NULL) { dev_err(dev, "cannot claim framebuffer\n"); ret = -ENXIO; - goto err_regs_map; + goto err_regs2d_map; } - info->fbmem = ioremap(res->start, (res->end - res->start)+1); + info->fbmem = ioremap(res->start, resource_size(res)); if (info->fbmem == NULL) { dev_err(dev, "cannot remap framebuffer\n"); goto err_mem_res; } - info->fbmem_len = (res->end - res->start)+1; + info->fbmem_len = resource_size(res); /* clear framebuffer memory - avoids garbage data on unused fb */ memset(info->fbmem, 0, info->fbmem_len); @@ -1389,8 +1586,10 @@ static int sm501fb_start(struct sm501fb_info *info, /* enable display controller */ sm501_unit_power(dev->parent, SM501_GATE_DISPLAY, 1); - /* setup cursors */ + /* enable 2d controller */ + sm501_unit_power(dev->parent, SM501_GATE_2D_ENGINE, 1); + /* setup cursors */ sm501_init_cursor(info->fb[HEAD_CRT], SM501_DC_CRT_HWC_ADDR); sm501_init_cursor(info->fb[HEAD_PANEL], SM501_DC_PANEL_HWC_ADDR); @@ -1400,6 +1599,13 @@ static int sm501fb_start(struct sm501fb_info *info, release_resource(info->fbmem_res); kfree(info->fbmem_res); + err_regs2d_map: + iounmap(info->regs2d); + + err_regs2d_res: + release_resource(info->regs2d_res); + kfree(info->regs2d_res); + err_regs_map: iounmap(info->regs); @@ -1420,6 +1626,10 @@ static void sm501fb_stop(struct sm501fb_info *info) release_resource(info->fbmem_res); kfree(info->fbmem_res); + iounmap(info->regs2d); + release_resource(info->regs2d_res); + kfree(info->regs2d_res); + iounmap(info->regs); release_resource(info->regs_res); kfree(info->regs_res); @@ -1486,7 +1696,8 @@ static int sm501fb_init_fb(struct fb_info *fb, par->ops.fb_cursor = NULL; fb->fbops = &par->ops; - fb->flags = FBINFO_FLAG_DEFAULT | + fb->flags = FBINFO_FLAG_DEFAULT | FBINFO_READS_FAST | + FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT | FBINFO_HWACCEL_XPAN | FBINFO_HWACCEL_YPAN; /* fixed data */ diff --git a/drivers/video/via/lcd.c b/drivers/video/via/lcd.c index e3e597f937a..09353e2b92f 100644 --- a/drivers/video/via/lcd.c +++ b/drivers/video/via/lcd.c @@ -1134,45 +1134,33 @@ static void integrated_lvds_enable(struct lvds_setting_information *plvds_setting_info, struct lvds_chip_information *plvds_chip_info) { - bool turn_on_first_powersequence = false; - bool turn_on_second_powersequence = false; - DEBUG_MSG(KERN_INFO "integrated_lvds_enable, out_interface:%d\n", plvds_chip_info->output_interface); if (plvds_setting_info->lcd_mode == LCD_SPWG) viafb_write_reg_mask(CRD2, VIACR, 0x00, BIT0 + BIT1); - else + else viafb_write_reg_mask(CRD2, VIACR, 0x03, BIT0 + BIT1); - if (INTERFACE_LVDS0LVDS1 == plvds_chip_info->output_interface) - turn_on_first_powersequence = true; - if (INTERFACE_LVDS0 == plvds_chip_info->output_interface) - turn_on_first_powersequence = true; - if (INTERFACE_LVDS1 == plvds_chip_info->output_interface) - turn_on_second_powersequence = true; - - if (turn_on_second_powersequence) { - /* Use second power sequence control: */ - - /* Use hardware control power sequence. */ - viafb_write_reg_mask(CRD3, VIACR, 0, BIT0); - - /* Turn on back light. */ - viafb_write_reg_mask(CRD3, VIACR, 0, BIT6 + BIT7); - /* Turn on hardware power sequence. */ - viafb_write_reg_mask(CRD4, VIACR, 0x02, BIT1); - } - if (turn_on_first_powersequence) { + switch (plvds_chip_info->output_interface) { + case INTERFACE_LVDS0LVDS1: + case INTERFACE_LVDS0: /* Use first power sequence control: */ - /* Use hardware control power sequence. */ viafb_write_reg_mask(CR91, VIACR, 0, BIT0); - /* Turn on back light. */ viafb_write_reg_mask(CR91, VIACR, 0, BIT6 + BIT7); - /* Turn on hardware power sequence. */ viafb_write_reg_mask(CR6A, VIACR, 0x08, BIT3); + break; + case INTERFACE_LVDS1: + /* Use second power sequence control: */ + /* Use hardware control power sequence. */ + viafb_write_reg_mask(CRD3, VIACR, 0, BIT0); + /* Turn on back light. */ + viafb_write_reg_mask(CRD3, VIACR, 0, BIT6 + BIT7); + /* Turn on hardware power sequence. */ + viafb_write_reg_mask(CRD4, VIACR, 0x02, BIT1); + break; } /* Turn DFP High/Low pad on. */ diff --git a/drivers/video/via/viafbdev.c b/drivers/video/via/viafbdev.c index 56ec696e8af..d8df17a7d5f 100644 --- a/drivers/video/via/viafbdev.c +++ b/drivers/video/via/viafbdev.c @@ -680,7 +680,7 @@ static int viafb_ioctl(struct fb_info *info, u_int cmd, u_long arg) if (!viafb_gamma_table) return -ENOMEM; if (copy_from_user(viafb_gamma_table, argp, - sizeof(viafb_gamma_table))) { + 256 * sizeof(u32))) { kfree(viafb_gamma_table); return -EFAULT; } @@ -694,7 +694,7 @@ static int viafb_ioctl(struct fb_info *info, u_int cmd, u_long arg) return -ENOMEM; viafb_get_gamma_table(viafb_gamma_table); if (copy_to_user(argp, viafb_gamma_table, - sizeof(viafb_gamma_table))) { + 256 * sizeof(u32))) { kfree(viafb_gamma_table); return -EFAULT; } @@ -1797,7 +1797,7 @@ static const struct file_operations viafb_vt1636_proc_fops = { static void viafb_init_proc(struct proc_dir_entry **viafb_entry) { *viafb_entry = proc_mkdir("viafb", NULL); - if (viafb_entry) { + if (*viafb_entry) { proc_create("dvp0", 0, *viafb_entry, &viafb_dvp0_proc_fops); proc_create("dvp1", 0, *viafb_entry, &viafb_dvp1_proc_fops); proc_create("dfph", 0, *viafb_entry, &viafb_dfph_proc_fops); |