diff options
Diffstat (limited to 'drivers/video')
90 files changed, 5735 insertions, 1726 deletions
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 1bd5fb30237d..a576dc261732 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -139,6 +139,30 @@ config FB_SYS_IMAGEBLIT blitting. This is used by drivers that don't provide their own (accelerated) version and the framebuffer is in system RAM. +menuconfig FB_FOREIGN_ENDIAN + bool "Framebuffer foreign endianness support" + depends on FB + ---help--- + This menu will let you enable support for the framebuffers with + non-native endianness (e.g. Little-Endian framebuffer on a + Big-Endian machine). Most probably you don't have such hardware, + so it's safe to say "n" here. + +choice + prompt "Choice endianness support" + depends on FB_FOREIGN_ENDIAN + +config FB_BOTH_ENDIAN + bool "Support for Big- and Little-Endian framebuffers" + +config FB_BIG_ENDIAN + bool "Support for Big-Endian framebuffers only" + +config FB_LITTLE_ENDIAN + bool "Support for Little-Endian framebuffers only" + +endchoice + config FB_SYS_FOPS tristate depends on FB @@ -149,6 +173,16 @@ config FB_DEFERRED_IO depends on FB default y +config FB_METRONOME + tristate + depends on FB + depends on FB_DEFERRED_IO + +config FB_HECUBA + tristate + depends on FB + depends on FB_DEFERRED_IO + config FB_SVGALIB tristate depends on FB @@ -546,7 +580,7 @@ config FB_VGA16 config FB_BF54X_LQ043 tristate "SHARP LQ043 TFT LCD (BF548 EZKIT)" - depends on FB && (BF54x) + depends on FB && (BF54x) && !BF542 select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT @@ -674,20 +708,18 @@ config FB_IMAC help This is the frame buffer device driver for the Intel-based Macintosh -config FB_HECUBA - tristate "Hecuba board support" +config FB_N411 + tristate "N411 Apollo/Hecuba devkit support" depends on FB && X86 && MMU select FB_SYS_FILLRECT select FB_SYS_COPYAREA select FB_SYS_IMAGEBLIT select FB_SYS_FOPS select FB_DEFERRED_IO + select FB_HECUBA help - This enables support for the Hecuba board. This driver was tested - with an E-Ink 800x600 display and x86 SBCs through a 16 bit GPIO - interface (8 bit data, 4 bit control). If you anticipate using - this driver, say Y or M; otherwise say N. You must specify the - GPIO IO address to be used for setting control and data. + This enables support for the Apollo display controller in its + Hecuba form using the n411 devkit. config FB_HGA tristate "Hercules mono graphics support" @@ -1087,7 +1119,7 @@ config FB_CARILLO_RANCH This driver supports the LE80578 (Carillo Ranch) board config FB_INTEL - tristate "Intel 830M/845G/852GM/855GM/865G/915G/945G support (EXPERIMENTAL)" + tristate "Intel 830M/845G/852GM/855GM/865G/915G/945G/945GM/965G/965GM support (EXPERIMENTAL)" depends on FB && EXPERIMENTAL && PCI && X86 select AGP select AGP_INTEL @@ -1097,7 +1129,7 @@ config FB_INTEL select FB_CFB_IMAGEBLIT help This driver supports the on-board graphics built in to the Intel - 830M/845G/852GM/855GM/865G/915G/915GM/945G/945GM chipsets. + 830M/845G/852GM/855GM/865G/915G/915GM/945G/945GM/965G/965GM chipsets. Say Y if you have and plan to use such a board. If you say Y here and want DDC/I2C support you must first say Y to @@ -1779,6 +1811,16 @@ config FB_MBX_DEBUG If unsure, say N. +config FB_FSL_DIU + tristate "Freescale DIU framebuffer support" + depends on FB && FSL_SOC + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select PPC_LIB_RHEAP + ---help--- + Framebuffer driver for the Freescale SoC DIU + config FB_W100 tristate "W100 frame buffer support" depends on FB && PXA_SHARPSL @@ -1893,19 +1935,18 @@ config FB_XILINX framebuffer. ML300 carries a 640*480 LCD display on the board, ML403 uses a standard DB15 VGA connector. -config FB_METRONOME - tristate "Metronome display controller support" +config FB_AM200EPD + tristate "AM-200 E-Ink EPD devkit support" depends on FB && ARCH_PXA && MMU select FB_SYS_FILLRECT select FB_SYS_COPYAREA select FB_SYS_IMAGEBLIT select FB_SYS_FOPS select FB_DEFERRED_IO + select FB_METRONOME help - This enables support for the Metronome display controller. Tested - with an E-Ink 800x600 display and Gumstix Connex through an AMLCD - interface. Please read <file:Documentation/fb/metronomefb.txt> - for more information. + This enables support for the Metronome display controller used on + the E-Ink AM-200 EPD devkit. config FB_VIRTUAL tristate "Virtual Frame Buffer support (ONLY FOR TESTING!)" @@ -1930,6 +1971,20 @@ config FB_VIRTUAL If unsure, say N. +config XEN_FBDEV_FRONTEND + tristate "Xen virtual frame buffer support" + depends on FB && XEN + select FB_SYS_FILLRECT + select FB_SYS_COPYAREA + select FB_SYS_IMAGEBLIT + select FB_SYS_FOPS + select FB_DEFERRED_IO + default y + help + This driver implements the front-end of the Xen virtual + frame buffer driver. It communicates with a back-end + in another domain. + source "drivers/video/omap/Kconfig" source "drivers/video/backlight/Kconfig" diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 11c0e5e05f21..04bca35403ff 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -29,6 +29,7 @@ obj-$(CONFIG_FB_DEFERRED_IO) += fb_defio.o # Hardware specific drivers go first obj-$(CONFIG_FB_AMIGA) += amifb.o c2p.o +obj-$(CONFIG_FB_AM200EPD) += am200epd.o obj-$(CONFIG_FB_ARC) += arcfb.o obj-$(CONFIG_FB_CLPS711X) += clps711xfb.o obj-$(CONFIG_FB_CYBER2000) += cyber2000fb.o @@ -107,6 +108,7 @@ obj-$(CONFIG_FB_METRONOME) += metronomefb.o obj-$(CONFIG_FB_S1D13XXX) += s1d13xxxfb.o obj-$(CONFIG_FB_IMX) += imxfb.o obj-$(CONFIG_FB_S3C2410) += s3c2410fb.o +obj-$(CONFIG_FB_FSL_DIU) += fsl-diu-fb.o obj-$(CONFIG_FB_PNX4008_DUM) += pnx4008/ obj-$(CONFIG_FB_PNX4008_DUM_RGB) += pnx4008/ obj-$(CONFIG_FB_IBM_GXT4500) += gxt4500.o @@ -114,6 +116,7 @@ obj-$(CONFIG_FB_PS3) += ps3fb.o obj-$(CONFIG_FB_SM501) += sm501fb.o obj-$(CONFIG_FB_XILINX) += xilinxfb.o obj-$(CONFIG_FB_OMAP) += omap/ +obj-$(CONFIG_XEN_FBDEV_FRONTEND) += xen-fbfront.o # Platform or fallback drivers go here obj-$(CONFIG_FB_UVESA) += uvesafb.o diff --git a/drivers/video/am200epd.c b/drivers/video/am200epd.c new file mode 100644 index 000000000000..51e26c1f5e8b --- /dev/null +++ b/drivers/video/am200epd.c @@ -0,0 +1,295 @@ +/* + * linux/drivers/video/am200epd.c -- Platform device for AM200 EPD kit + * + * Copyright (C) 2008, Jaya Kumar + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + * + * Layout is based on skeletonfb.c by James Simmons and Geert Uytterhoeven. + * + * This work was made possible by help and equipment support from E-Ink + * Corporation. http://support.eink.com/community + * + * This driver is written to be used with the Metronome display controller. + * on the AM200 EPD prototype kit/development kit with an E-Ink 800x600 + * Vizplex EPD on a Gumstix board using the Lyre interface board. + * + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/list.h> +#include <linux/uaccess.h> +#include <linux/irq.h> + +#include <video/metronomefb.h> + +#include <asm/arch/pxa-regs.h> + +/* register offsets for gpio control */ +#define LED_GPIO_PIN 51 +#define STDBY_GPIO_PIN 48 +#define RST_GPIO_PIN 49 +#define RDY_GPIO_PIN 32 +#define ERR_GPIO_PIN 17 +#define PCBPWR_GPIO_PIN 16 + +#define AF_SEL_GPIO_N 0x3 +#define GAFR0_U_OFFSET(pin) ((pin - 16) * 2) +#define GAFR1_L_OFFSET(pin) ((pin - 32) * 2) +#define GAFR1_U_OFFSET(pin) ((pin - 48) * 2) +#define GPDR1_OFFSET(pin) (pin - 32) +#define GPCR1_OFFSET(pin) (pin - 32) +#define GPSR1_OFFSET(pin) (pin - 32) +#define GPCR0_OFFSET(pin) (pin) +#define GPSR0_OFFSET(pin) (pin) + +static void am200_set_gpio_output(int pin, int val) +{ + u8 index; + + index = pin >> 4; + + switch (index) { + case 1: + if (val) + GPSR0 |= (1 << GPSR0_OFFSET(pin)); + else + GPCR0 |= (1 << GPCR0_OFFSET(pin)); + break; + case 2: + break; + case 3: + if (val) + GPSR1 |= (1 << GPSR1_OFFSET(pin)); + else + GPCR1 |= (1 << GPCR1_OFFSET(pin)); + break; + default: + printk(KERN_ERR "unimplemented\n"); + } +} + +static void __devinit am200_init_gpio_pin(int pin, int dir) +{ + u8 index; + /* dir 0 is output, 1 is input + - do 2 things here: + - set gpio alternate function to standard gpio + - set gpio direction to input or output */ + + index = pin >> 4; + switch (index) { + case 1: + GAFR0_U &= ~(AF_SEL_GPIO_N << GAFR0_U_OFFSET(pin)); + + if (dir) + GPDR0 &= ~(1 << pin); + else + GPDR0 |= (1 << pin); + break; + case 2: + GAFR1_L &= ~(AF_SEL_GPIO_N << GAFR1_L_OFFSET(pin)); + + if (dir) + GPDR1 &= ~(1 << GPDR1_OFFSET(pin)); + else + GPDR1 |= (1 << GPDR1_OFFSET(pin)); + break; + case 3: + GAFR1_U &= ~(AF_SEL_GPIO_N << GAFR1_U_OFFSET(pin)); + + if (dir) + GPDR1 &= ~(1 << GPDR1_OFFSET(pin)); + else + GPDR1 |= (1 << GPDR1_OFFSET(pin)); + break; + default: + printk(KERN_ERR "unimplemented\n"); + } +} + +static void am200_init_gpio_regs(struct metronomefb_par *par) +{ + am200_init_gpio_pin(LED_GPIO_PIN, 0); + am200_set_gpio_output(LED_GPIO_PIN, 0); + + am200_init_gpio_pin(STDBY_GPIO_PIN, 0); + am200_set_gpio_output(STDBY_GPIO_PIN, 0); + + am200_init_gpio_pin(RST_GPIO_PIN, 0); + am200_set_gpio_output(RST_GPIO_PIN, 0); + + am200_init_gpio_pin(RDY_GPIO_PIN, 1); + + am200_init_gpio_pin(ERR_GPIO_PIN, 1); + + am200_init_gpio_pin(PCBPWR_GPIO_PIN, 0); + am200_set_gpio_output(PCBPWR_GPIO_PIN, 0); +} + +static void am200_disable_lcd_controller(struct metronomefb_par *par) +{ + LCSR = 0xffffffff; /* Clear LCD Status Register */ + LCCR0 |= LCCR0_DIS; /* Disable LCD Controller */ + + /* we reset and just wait for things to settle */ + msleep(200); +} + +static void am200_enable_lcd_controller(struct metronomefb_par *par) +{ + LCSR = 0xffffffff; + FDADR0 = par->metromem_desc_dma; + LCCR0 |= LCCR0_ENB; +} + +static void am200_init_lcdc_regs(struct metronomefb_par *par) +{ + /* here we do: + - disable the lcd controller + - setup lcd control registers + - setup dma descriptor + - reenable lcd controller + */ + + /* disable the lcd controller */ + am200_disable_lcd_controller(par); + + /* setup lcd control registers */ + LCCR0 = LCCR0_LDM | LCCR0_SFM | LCCR0_IUM | LCCR0_EFM | LCCR0_PAS + | LCCR0_QDM | LCCR0_BM | LCCR0_OUM; + + LCCR1 = (par->info->var.xres/2 - 1) /* pixels per line */ + | (27 << 10) /* hsync pulse width - 1 */ + | (33 << 16) /* eol pixel count */ + | (33 << 24); /* bol pixel count */ + + LCCR2 = (par->info->var.yres - 1) /* lines per panel */ + | (24 << 10) /* vsync pulse width - 1 */ + | (2 << 16) /* eof pixel count */ + | (0 << 24); /* bof pixel count */ + + LCCR3 = 2 /* pixel clock divisor */ + | (24 << 8) /* AC Bias pin freq */ + | LCCR3_16BPP /* BPP */ + | LCCR3_PCP; /* PCP falling edge */ + +} + +static void am200_post_dma_setup(struct metronomefb_par *par) +{ + par->metromem_desc->mFDADR0 = par->metromem_desc_dma; + par->metromem_desc->mFSADR0 = par->metromem_dma; + par->metromem_desc->mFIDR0 = 0; + par->metromem_desc->mLDCMD0 = par->info->var.xres + * par->info->var.yres; + am200_enable_lcd_controller(par); +} + +static void am200_free_irq(struct fb_info *info) +{ + free_irq(IRQ_GPIO(RDY_GPIO_PIN), info); +} + +static irqreturn_t am200_handle_irq(int irq, void *dev_id) +{ + struct fb_info *info = dev_id; + struct metronomefb_par *par = info->par; + + wake_up_interruptible(&par->waitq); + return IRQ_HANDLED; +} + +static int am200_setup_irq(struct fb_info *info) +{ + int retval; + + retval = request_irq(IRQ_GPIO(RDY_GPIO_PIN), am200_handle_irq, + IRQF_DISABLED, "AM200", info); + if (retval) { + printk(KERN_ERR "am200epd: request_irq failed: %d\n", retval); + return retval; + } + + return set_irq_type(IRQ_GPIO(RDY_GPIO_PIN), IRQT_FALLING); +} + +static void am200_set_rst(struct metronomefb_par *par, int state) +{ + am200_set_gpio_output(RST_GPIO_PIN, state); +} + +static void am200_set_stdby(struct metronomefb_par *par, int state) +{ + am200_set_gpio_output(STDBY_GPIO_PIN, state); +} + +static int am200_wait_event(struct metronomefb_par *par) +{ + return wait_event_timeout(par->waitq, (GPLR1 & 0x01), HZ); +} + +static int am200_wait_event_intr(struct metronomefb_par *par) +{ + return wait_event_interruptible_timeout(par->waitq, (GPLR1 & 0x01), HZ); +} + +static struct metronome_board am200_board = { + .owner = THIS_MODULE, + .free_irq = am200_free_irq, + .setup_irq = am200_setup_irq, + .init_gpio_regs = am200_init_gpio_regs, + .init_lcdc_regs = am200_init_lcdc_regs, + .post_dma_setup = am200_post_dma_setup, + .set_rst = am200_set_rst, + .set_stdby = am200_set_stdby, + .met_wait_event = am200_wait_event, + .met_wait_event_intr = am200_wait_event_intr, +}; + +static struct platform_device *am200_device; + +static int __init am200_init(void) +{ + int ret; + + /* request our platform independent driver */ + request_module("metronomefb"); + + am200_device = platform_device_alloc("metronomefb", -1); + if (!am200_device) + return -ENOMEM; + + platform_device_add_data(am200_device, &am200_board, + sizeof(am200_board)); + + /* this _add binds metronomefb to am200. metronomefb refcounts am200 */ + ret = platform_device_add(am200_device); + + if (ret) + platform_device_put(am200_device); + + return ret; +} + +static void __exit am200_exit(void) +{ + platform_device_unregister(am200_device); +} + +module_init(am200_init); +module_exit(am200_exit); + +MODULE_DESCRIPTION("board driver for am200 metronome epd kit"); +MODULE_AUTHOR("Jaya Kumar"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/amifb.c b/drivers/video/amifb.c index 4c9ec3f58c52..e6492c1048bf 100644 --- a/drivers/video/amifb.c +++ b/drivers/video/amifb.c @@ -96,7 +96,7 @@ #endif #ifdef DEBUG -# define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args) +# define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __func__ , ## args) #else # define DPRINTK(fmt, args...) #endif diff --git a/drivers/video/arkfb.c b/drivers/video/arkfb.c index 8a1b07c74394..5001bd4ef466 100644 --- a/drivers/video/arkfb.c +++ b/drivers/video/arkfb.c @@ -101,7 +101,7 @@ static const struct svga_timing_regs ark_timing_regs = { /* Module parameters */ -static char *mode = "640x480-8@60"; +static char *mode_option __devinitdata = "640x480-8@60"; #ifdef CONFIG_MTRR static int mtrr = 1; @@ -111,8 +111,10 @@ MODULE_AUTHOR("(c) 2007 Ondrej Zajicek <santiago@crfreenet.org>"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("fbdev driver for ARK 2000PV"); -module_param(mode, charp, 0444); -MODULE_PARM_DESC(mode, "Default video mode ('640x480-8@60', etc)"); +module_param(mode_option, charp, 0444); +MODULE_PARM_DESC(mode_option, "Default video mode ('640x480-8@60', etc)"); +module_param_named(mode, mode_option, charp, 0444); +MODULE_PARM_DESC(mode, "Default video mode ('640x480-8@60', etc) (deprecated)"); #ifdef CONFIG_MTRR module_param(mtrr, int, 0444); @@ -941,7 +943,7 @@ static int __devinit ark_pci_probe(struct pci_dev *dev, const struct pci_device_ } /* Allocate and fill driver data structure */ - info = framebuffer_alloc(sizeof(struct arkfb_info), NULL); + info = framebuffer_alloc(sizeof(struct arkfb_info), &(dev->dev)); if (! info) { dev_err(&(dev->dev), "cannot allocate memory\n"); return -ENOMEM; @@ -956,20 +958,20 @@ static int __devinit ark_pci_probe(struct pci_dev *dev, const struct pci_device_ /* Prepare PCI device */ rc = pci_enable_device(dev); if (rc < 0) { - dev_err(&(dev->dev), "cannot enable PCI device\n"); + dev_err(info->dev, "cannot enable PCI device\n"); goto err_enable_device; } rc = pci_request_regions(dev, "arkfb"); if (rc < 0) { - dev_err(&(dev->dev), "cannot reserve framebuffer region\n"); + dev_err(info->dev, "cannot reserve framebuffer region\n"); goto err_request_regions; } par->dac = ics5342_init(ark_dac_read_regs, ark_dac_write_regs, info); if (! par->dac) { rc = -ENOMEM; - dev_err(&(dev->dev), "RAMDAC initialization failed\n"); + dev_err(info->dev, "RAMDAC initialization failed\n"); goto err_dac; } @@ -980,7 +982,7 @@ static int __devinit ark_pci_probe(struct pci_dev *dev, const struct pci_device_ info->screen_base = pci_iomap(dev, 0, 0); if (! info->screen_base) { rc = -ENOMEM; - dev_err(&(dev->dev), "iomap for framebuffer failed\n"); + dev_err(info->dev, "iomap for framebuffer failed\n"); goto err_iomap; } @@ -999,22 +1001,22 @@ static int __devinit ark_pci_probe(struct pci_dev *dev, const struct pci_device_ info->pseudo_palette = (void*) (par->pseudo_palette); /* Prepare startup mode */ - rc = fb_find_mode(&(info->var), info, mode, NULL, 0, NULL, 8); + rc = fb_find_mode(&(info->var), info, mode_option, NULL, 0, NULL, 8); if (! ((rc == 1) || (rc == 2))) { rc = -EINVAL; - dev_err(&(dev->dev), "mode %s not found\n", mode); + dev_err(info->dev, "mode %s not found\n", mode_option); goto err_find_mode; } rc = fb_alloc_cmap(&info->cmap, 256, 0); if (rc < 0) { - dev_err(&(dev->dev), "cannot allocate colormap\n"); + dev_err(info->dev, "cannot allocate colormap\n"); goto err_alloc_cmap; } rc = register_framebuffer(info); if (rc < 0) { - dev_err(&(dev->dev), "cannot register framebugger\n"); + dev_err(info->dev, "cannot register framebugger\n"); goto err_reg_fb; } @@ -1088,7 +1090,7 @@ static int ark_pci_suspend (struct pci_dev* dev, pm_message_t state) struct fb_info *info = pci_get_drvdata(dev); struct arkfb_info *par = info->par; - dev_info(&(dev->dev), "suspend\n"); + dev_info(info->dev, "suspend\n"); acquire_console_sem(); mutex_lock(&(par->open_lock)); @@ -1119,7 +1121,7 @@ static int ark_pci_resume (struct pci_dev* dev) struct fb_info *info = pci_get_drvdata(dev); struct arkfb_info *par = info->par; - dev_info(&(dev->dev), "resume\n"); + dev_info(info->dev, "resume\n"); acquire_console_sem(); mutex_lock(&(par->open_lock)); @@ -1190,7 +1192,7 @@ static int __init arkfb_init(void) return -ENODEV; if (option && *option) - mode = option; + mode_option = option; #endif pr_debug("arkfb: initializing\n"); diff --git a/drivers/video/atafb.c b/drivers/video/atafb.c index 5d4fbaa53a6c..dff35474b854 100644 --- a/drivers/video/atafb.c +++ b/drivers/video/atafb.c @@ -1270,7 +1270,7 @@ again: gstart = (prescale / 2 + plen * left_margin) / prescale; /* gend1 is for hde (gend-gstart multiple of align), shifter's xres */ - gend1 = gstart + ((xres + align - 1) / align) * align * plen / prescale; + gend1 = gstart + roundup(xres, align) * plen / prescale; /* gend2 is for hbb, visible xres (rest to gend1 is cut off by hblank) */ gend2 = gstart + xres * plen / prescale; par->HHT = plen * (left_margin + xres + right_margin) / diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c index fc65c02306dd..8ffdf3578768 100644 --- a/drivers/video/atmel_lcdfb.c +++ b/drivers/video/atmel_lcdfb.c @@ -31,7 +31,8 @@ #define ATMEL_LCDC_CVAL_DEFAULT 0xc8 #define ATMEL_LCDC_DMA_BURST_LEN 8 -#if defined(CONFIG_ARCH_AT91SAM9263) || defined(CONFIG_ARCH_AT91CAP9) +#if defined(CONFIG_ARCH_AT91SAM9263) || defined(CONFIG_ARCH_AT91CAP9) || \ + defined(CONFIG_ARCH_AT91SAM9RL) #define ATMEL_LCDC_FIFO_SIZE 2048 #else #define ATMEL_LCDC_FIFO_SIZE 512 @@ -250,6 +251,8 @@ static int atmel_lcdfb_alloc_video_memory(struct atmel_lcdfb_info *sinfo) return -ENOMEM; } + memset(info->screen_base, 0, info->fix.smem_len); + return 0; } @@ -336,19 +339,35 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var, break; case 15: case 16: - var->red.offset = 0; + if (sinfo->lcd_wiring_mode == ATMEL_LCDC_WIRING_RGB) { + /* RGB:565 mode */ + var->red.offset = 11; + var->blue.offset = 0; + var->green.length = 6; + } else { + /* BGR:555 mode */ + var->red.offset = 0; + var->blue.offset = 10; + var->green.length = 5; + } var->green.offset = 5; - var->blue.offset = 10; - var->red.length = var->green.length = var->blue.length = 5; + var->red.length = var->blue.length = 5; break; case 32: var->transp.offset = 24; var->transp.length = 8; /* fall through */ case 24: - var->red.offset = 0; + if (sinfo->lcd_wiring_mode == ATMEL_LCDC_WIRING_RGB) { + /* RGB:888 mode */ + var->red.offset = 16; + var->blue.offset = 0; + } else { + /* BGR:888 mode */ + var->red.offset = 0; + var->blue.offset = 16; + } var->green.offset = 8; - var->blue.offset = 16; var->red.length = var->green.length = var->blue.length = 8; break; default: @@ -634,7 +653,6 @@ static int __init atmel_lcdfb_init_fbinfo(struct atmel_lcdfb_info *sinfo) struct fb_info *info = sinfo->info; int ret = 0; - memset_io(info->screen_base, 0, info->fix.smem_len); info->var.activate |= FB_ACTIVATE_FORCE | FB_ACTIVATE_NOW; dev_info(info->device, @@ -696,6 +714,7 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev) sinfo->atmel_lcdfb_power_control = pdata_sinfo->atmel_lcdfb_power_control; sinfo->guard_time = pdata_sinfo->guard_time; sinfo->lcdcon_is_backlight = pdata_sinfo->lcdcon_is_backlight; + sinfo->lcd_wiring_mode = pdata_sinfo->lcd_wiring_mode; } else { dev_err(dev, "cannot get default configuration\n"); goto free_info; @@ -764,6 +783,11 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev) info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len); if (!info->screen_base) goto release_intmem; + + /* + * Don't clear the framebuffer -- someone may have set + * up a splash image. + */ } else { /* alocate memory buffer */ ret = atmel_lcdfb_alloc_video_memory(sinfo); @@ -903,10 +927,42 @@ static int __exit atmel_lcdfb_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM + +static int atmel_lcdfb_suspend(struct platform_device *pdev, pm_message_t mesg) +{ + struct fb_info *info = platform_get_drvdata(pdev); + struct atmel_lcdfb_info *sinfo = info->par; + + sinfo->saved_lcdcon = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL); + lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, 0); + if (sinfo->atmel_lcdfb_power_control) + sinfo->atmel_lcdfb_power_control(0); + atmel_lcdfb_stop_clock(sinfo); + return 0; +} + +static int atmel_lcdfb_resume(struct platform_device *pdev) +{ + struct fb_info *info = platform_get_drvdata(pdev); + struct atmel_lcdfb_info *sinfo = info->par; + + atmel_lcdfb_start_clock(sinfo); + if (sinfo->atmel_lcdfb_power_control) + sinfo->atmel_lcdfb_power_control(1); + lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, sinfo->saved_lcdcon); + return 0; +} + +#else +#define atmel_lcdfb_suspend NULL +#define atmel_lcdfb_resume NULL +#endif + static struct platform_driver atmel_lcdfb_driver = { .remove = __exit_p(atmel_lcdfb_remove), - -// FIXME need suspend, resume + .suspend = atmel_lcdfb_suspend, + .resume = atmel_lcdfb_resume, .driver = { .name = "atmel_lcdfb", diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c index cbd3308b6690..24ee96c4e9e9 100644 --- a/drivers/video/aty/aty128fb.c +++ b/drivers/video/aty/aty128fb.c @@ -91,7 +91,7 @@ #undef DEBUG #ifdef DEBUG -#define DBG(fmt, args...) printk(KERN_DEBUG "aty128fb: %s " fmt, __FUNCTION__, ##args); +#define DBG(fmt, args...) printk(KERN_DEBUG "aty128fb: %s " fmt, __func__, ##args); #else #define DBG(fmt, args...) #endif @@ -1885,7 +1885,7 @@ static int __devinit aty128_init(struct pci_dev *pdev, const struct pci_device_i /* range check to make sure */ if (ent->driver_data < ARRAY_SIZE(r128_family)) - strncat(video_card, r128_family[ent->driver_data], sizeof(video_card)); + strlcat(video_card, r128_family[ent->driver_data], sizeof(video_card)); printk(KERN_INFO "aty128fb: %s [chip rev 0x%x] ", video_card, chip_rev); diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c index 62f9c6e387cc..e4bcf5376a99 100644 --- a/drivers/video/aty/atyfb_base.c +++ b/drivers/video/aty/atyfb_base.c @@ -2621,10 +2621,13 @@ static int __devinit aty_init(struct fb_info *info) #endif /* CONFIG_FB_ATY_CT */ info->var = var; - fb_alloc_cmap(&info->cmap, 256, 0); + if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) + goto aty_init_exit; - if (register_framebuffer(info) < 0) + if (register_framebuffer(info) < 0) { + fb_dealloc_cmap(&info->cmap); goto aty_init_exit; + } fb_list = info; diff --git a/drivers/video/aty/mach64_ct.c b/drivers/video/aty/mach64_ct.c index cc9e9779b75f..c50c7cf26fe9 100644 --- a/drivers/video/aty/mach64_ct.c +++ b/drivers/video/aty/mach64_ct.c @@ -197,7 +197,7 @@ static int aty_dsp_gt(const struct fb_info *info, u32 bpp, struct pll_ct *pll) pll->dsp_config = (dsp_precision << 20) | (pll->dsp_loop_latency << 16) | dsp_xclks; #ifdef DEBUG printk("atyfb(%s): dsp_config 0x%08x, dsp_on_off 0x%08x\n", - __FUNCTION__, pll->dsp_config, pll->dsp_on_off); + __func__, pll->dsp_config, pll->dsp_on_off); #endif return 0; } @@ -225,7 +225,7 @@ static int aty_valid_pll_ct(const struct fb_info *info, u32 vclk_per, struct pll (par->ref_clk_per * pll->pll_ref_div); #ifdef DEBUG printk("atyfb(%s): pllvclk=%d MHz, vclk=%d MHz\n", - __FUNCTION__, pllvclk, pllvclk / pll->vclk_post_div_real); + __func__, pllvclk, pllvclk / pll->vclk_post_div_real); #endif pll->pll_vclk_cntl = 0x03; /* VCLK = PLL_VCLK/VCLKx_POST */ @@ -269,7 +269,7 @@ static u32 aty_pll_to_var_ct(const struct fb_info *info, const union aty_pll *pl } #endif #ifdef DEBUG - printk("atyfb(%s): calculated 0x%08X(%i)\n", __FUNCTION__, ret, ret); + printk("atyfb(%s): calculated 0x%08X(%i)\n", __func__, ret, ret); #endif return ret; } @@ -284,11 +284,11 @@ void aty_set_pll_ct(const struct fb_info *info, const union aty_pll *pll) #ifdef DEBUG printk("atyfb(%s): about to program:\n" "pll_ext_cntl=0x%02x pll_gen_cntl=0x%02x pll_vclk_cntl=0x%02x\n", - __FUNCTION__, + __func__, pll->ct.pll_ext_cntl, pll->ct.pll_gen_cntl, pll->ct.pll_vclk_cntl); printk("atyfb(%s): setting clock %lu for FeedBackDivider %i, ReferenceDivider %i, PostDivider %i(%i)\n", - __FUNCTION__, + __func__, par->clk_wr_offset, pll->ct.vclk_fb_div, pll->ct.pll_ref_div, pll->ct.vclk_post_div, pll->ct.vclk_post_div_real); #endif @@ -428,7 +428,7 @@ static int __devinit aty_init_pll_ct(const struct fb_info *info, #ifdef DEBUG printk("atyfb(%s): mclk_fb_mult=%d, xclk_post_div=%d\n", - __FUNCTION__, pll->ct.mclk_fb_mult, pll->ct.xclk_post_div); + __func__, pll->ct.mclk_fb_mult, pll->ct.xclk_post_div); #endif memcntl = aty_ld_le32(MEM_CNTL, par); @@ -540,7 +540,7 @@ static int __devinit aty_init_pll_ct(const struct fb_info *info, pllmclk = (1000000 * pll->ct.mclk_fb_mult * pll->ct.mclk_fb_div) / (par->ref_clk_per * pll->ct.pll_ref_div); printk("atyfb(%s): pllmclk=%d MHz, xclk=%d MHz\n", - __FUNCTION__, pllmclk, pllmclk / pll->ct.xclk_post_div_real); + __func__, pllmclk, pllmclk / pll->ct.xclk_post_div_real); #endif if (M64_HAS(SDRAM_MAGIC_PLL) && (par->ram_type >= SDRAM)) @@ -581,7 +581,7 @@ static int __devinit aty_init_pll_ct(const struct fb_info *info, pllsclk = (1000000 * 2 * pll->ct.sclk_fb_div) / (par->ref_clk_per * pll->ct.pll_ref_div); printk("atyfb(%s): use sclk, pllsclk=%d MHz, sclk=mclk=%d MHz\n", - __FUNCTION__, pllsclk, pllsclk / sclk_post_div_real); + __func__, pllsclk, pllsclk / sclk_post_div_real); #endif } diff --git a/drivers/video/aty/radeon_base.c b/drivers/video/aty/radeon_base.c index 62867cb63fef..72cd0d2f14ec 100644 --- a/drivers/video/aty/radeon_base.c +++ b/drivers/video/aty/radeon_base.c @@ -52,11 +52,14 @@ #define RADEON_VERSION "0.2.0" +#include "radeonfb.h" + #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/kernel.h> #include <linux/errno.h> #include <linux/string.h> +#include <linux/ctype.h> #include <linux/mm.h> #include <linux/slab.h> #include <linux/delay.h> @@ -91,7 +94,6 @@ #include "../edid.h" // MOVE THAT TO include/video #include "ati_ids.h" -#include "radeonfb.h" #define MAX_MAPPED_VRAM (2048*2048*4) #define MIN_MAPPED_VRAM (1024*768*1) @@ -1488,7 +1490,7 @@ static void radeon_calc_pll_regs(struct radeonfb_info *rinfo, struct radeon_regs freq = rinfo->pll.ppll_max; if (freq*12 < rinfo->pll.ppll_min) freq = rinfo->pll.ppll_min / 12; - RTRACE("freq = %lu, PLL min = %u, PLL max = %u\n", + pr_debug("freq = %lu, PLL min = %u, PLL max = %u\n", freq, rinfo->pll.ppll_min, rinfo->pll.ppll_max); for (post_div = &post_divs[0]; post_div->divider; ++post_div) { @@ -1509,7 +1511,7 @@ static void radeon_calc_pll_regs(struct radeonfb_info *rinfo, struct radeon_regs post_div = &post_divs[post_div->bitvalue]; pll_output_freq = post_div->divider * freq; } - RTRACE("ref_div = %d, ref_clk = %d, output_freq = %d\n", + pr_debug("ref_div = %d, ref_clk = %d, output_freq = %d\n", rinfo->pll.ref_div, rinfo->pll.ref_clk, pll_output_freq); @@ -1519,7 +1521,7 @@ static void radeon_calc_pll_regs(struct radeonfb_info *rinfo, struct radeon_regs post_div = &post_divs[post_div->bitvalue]; pll_output_freq = post_div->divider * freq; } - RTRACE("ref_div = %d, ref_clk = %d, output_freq = %d\n", + pr_debug("ref_div = %d, ref_clk = %d, output_freq = %d\n", rinfo->pll.ref_div, rinfo->pll.ref_clk, pll_output_freq); @@ -1528,9 +1530,9 @@ static void radeon_calc_pll_regs(struct radeonfb_info *rinfo, struct radeon_regs regs->ppll_ref_div = rinfo->pll.ref_div; regs->ppll_div_3 = fb_div | (post_div->bitvalue << 16); - RTRACE("post div = 0x%x\n", post_div->bitvalue); - RTRACE("fb_div = 0x%x\n", fb_div); - RTRACE("ppll_div_3 = 0x%x\n", regs->ppll_div_3); + pr_debug("post div = 0x%x\n", post_div->bitvalue); + pr_debug("fb_div = 0x%x\n", fb_div); + pr_debug("ppll_div_3 = 0x%x\n", regs->ppll_div_3); } static int radeonfb_set_par(struct fb_info *info) @@ -1602,9 +1604,9 @@ static int radeonfb_set_par(struct fb_info *info) dotClock = 1000000000 / pixClock; freq = dotClock / 10; /* x100 */ - RTRACE("hStart = %d, hEnd = %d, hTotal = %d\n", + pr_debug("hStart = %d, hEnd = %d, hTotal = %d\n", hSyncStart, hSyncEnd, hTotal); - RTRACE("vStart = %d, vEnd = %d, vTotal = %d\n", + pr_debug("vStart = %d, vEnd = %d, vTotal = %d\n", vSyncStart, vSyncEnd, vTotal); hsync_wid = (hSyncEnd - hSyncStart) / 8; @@ -1713,16 +1715,16 @@ static int radeonfb_set_par(struct fb_info *info) newmode->surf_info[i] = 0; } - RTRACE("h_total_disp = 0x%x\t hsync_strt_wid = 0x%x\n", + pr_debug("h_total_disp = 0x%x\t hsync_strt_wid = 0x%x\n", newmode->crtc_h_total_disp, newmode->crtc_h_sync_strt_wid); - RTRACE("v_total_disp = 0x%x\t vsync_strt_wid = 0x%x\n", + pr_debug("v_total_disp = 0x%x\t vsync_strt_wid = 0x%x\n", newmode->crtc_v_total_disp, newmode->crtc_v_sync_strt_wid); rinfo->bpp = mode->bits_per_pixel; rinfo->depth = depth; - RTRACE("pixclock = %lu\n", (unsigned long)pixClock); - RTRACE("freq = %lu\n", (unsigned long)freq); + pr_debug("pixclock = %lu\n", (unsigned long)pixClock); + pr_debug("freq = %lu\n", (unsigned long)freq); /* We use PPLL_DIV_3 */ newmode->clk_cntl_index = 0x300; @@ -1986,7 +1988,7 @@ static void fixup_memory_mappings(struct radeonfb_info *rinfo) if (rinfo->has_CRTC2) OUTREG(CRTC2_GEN_CNTL, save_crtc2_gen_cntl); - RTRACE("aper_base: %08x MC_FB_LOC to: %08x, MC_AGP_LOC to: %08x\n", + pr_debug("aper_base: %08x MC_FB_LOC to: %08x, MC_AGP_LOC to: %08x\n", aper_base, ((aper_base + aper_size - 1) & 0xffff0000) | (aper_base >> 16), 0xffff0000 | (agp_base >> 16)); @@ -2083,7 +2085,7 @@ static void radeon_identify_vram(struct radeonfb_info *rinfo) * ToDo: identify these cases */ - RTRACE("radeonfb (%s): Found %ldk of %s %d bits wide videoram\n", + pr_debug("radeonfb (%s): Found %ldk of %s %d bits wide videoram\n", pci_name(rinfo->pdev), rinfo->video_ram / 1024, rinfo->vram_ddr ? "DDR" : "SDRAM", @@ -2158,8 +2160,9 @@ static int __devinit radeonfb_pci_register (struct pci_dev *pdev, struct fb_info *info; struct radeonfb_info *rinfo; int ret; + unsigned char c1, c2; - RTRACE("radeonfb_pci_register BEGIN\n"); + pr_debug("radeonfb_pci_register BEGIN\n"); /* Enable device in PCI config */ ret = pci_enable_device(pdev); @@ -2185,9 +2188,15 @@ static int __devinit radeonfb_pci_register (struct pci_dev *pdev, rinfo->lvds_timer.function = radeon_lvds_timer_func; rinfo->lvds_timer.data = (unsigned long)rinfo; - strcpy(rinfo->name, "ATI Radeon XX "); - rinfo->name[11] = ent->device >> 8; - rinfo->name[12] = ent->device & 0xFF; + c1 = ent->device >> 8; + c2 = ent->device & 0xff; + if (isprint(c1) && isprint(c2)) + snprintf(rinfo->name, sizeof(rinfo->name), + "ATI Radeon %x \"%c%c\"", ent->device & 0xffff, c1, c2); + else + snprintf(rinfo->name, sizeof(rinfo->name), + "ATI Radeon %x", ent->device & 0xffff); + rinfo->family = ent->driver_data & CHIP_FAMILY_MASK; rinfo->chipset = pdev->device; rinfo->has_CRTC2 = (ent->driver_data & CHIP_HAS_CRTC2) != 0; @@ -2278,7 +2287,7 @@ static int __devinit radeonfb_pci_register (struct pci_dev *pdev, goto err_unmap_rom; } - RTRACE("radeonfb (%s): mapped %ldk videoram\n", pci_name(rinfo->pdev), + pr_debug("radeonfb (%s): mapped %ldk videoram\n", pci_name(rinfo->pdev), rinfo->mapped_vram/1024); /* @@ -2373,7 +2382,7 @@ static int __devinit radeonfb_pci_register (struct pci_dev *pdev, if (rinfo->bios_seg) radeon_unmap_ROM(rinfo, pdev); - RTRACE("radeonfb_pci_register END\n"); + pr_debug("radeonfb_pci_register END\n"); return 0; err_unmap_fb: diff --git a/drivers/video/aty/radeon_i2c.c b/drivers/video/aty/radeon_i2c.c index 7db9de681716..f9e7c29ad9bf 100644 --- a/drivers/video/aty/radeon_i2c.c +++ b/drivers/video/aty/radeon_i2c.c @@ -1,3 +1,5 @@ +#include "radeonfb.h" + #include <linux/module.h> #include <linux/kernel.h> #include <linux/delay.h> @@ -11,7 +13,6 @@ #include <asm/io.h> #include <video/radeon.h> -#include "radeonfb.h" #include "../edid.h" static void radeon_gpio_setscl(void* data, int state) @@ -77,7 +78,7 @@ static int radeon_setup_i2c_bus(struct radeon_i2c_chan *chan, const char *name) chan->algo.setscl = radeon_gpio_setscl; chan->algo.getsda = radeon_gpio_getsda; chan->algo.getscl = radeon_gpio_getscl; - chan->algo.udelay = 40; + chan->algo.udelay = 10; chan->algo.timeout = 20; chan->algo.data = chan; @@ -148,21 +149,21 @@ int radeon_probe_i2c_connector(struct radeonfb_info *rinfo, int conn, if (out_edid) *out_edid = edid; if (!edid) { - RTRACE("radeonfb: I2C (port %d) ... not found\n", conn); + pr_debug("radeonfb: I2C (port %d) ... not found\n", conn); return MT_NONE; } if (edid[0x14] & 0x80) { /* Fix detection using BIOS tables */ if (rinfo->is_mobility /*&& conn == ddc_dvi*/ && (INREG(LVDS_GEN_CNTL) & LVDS_ON)) { - RTRACE("radeonfb: I2C (port %d) ... found LVDS panel\n", conn); + pr_debug("radeonfb: I2C (port %d) ... found LVDS panel\n", conn); return MT_LCD; } else { - RTRACE("radeonfb: I2C (port %d) ... found TMDS panel\n", conn); + pr_debug("radeonfb: I2C (port %d) ... found TMDS panel\n", conn); return MT_DFP; } } - RTRACE("radeonfb: I2C (port %d) ... found CRT display\n", conn); + pr_debug("radeonfb: I2C (port %d) ... found CRT display\n", conn); return MT_CRT; } diff --git a/drivers/video/aty/radeon_monitor.c b/drivers/video/aty/radeon_monitor.c index 2030ed813429..b4d4b88afc09 100644 --- a/drivers/video/aty/radeon_monitor.c +++ b/drivers/video/aty/radeon_monitor.c @@ -69,11 +69,11 @@ static int __devinit radeon_parse_montype_prop(struct device_node *dp, u8 **out_ u8 *tmp; int i, mt = MT_NONE; - RTRACE("analyzing OF properties...\n"); + pr_debug("analyzing OF properties...\n"); pmt = of_get_property(dp, "display-type", NULL); if (!pmt) return MT_NONE; - RTRACE("display-type: %s\n", pmt); + pr_debug("display-type: %s\n", pmt); /* OF says "LCD" for DFP as well, we discriminate from the caller of this * function */ @@ -117,7 +117,7 @@ static int __devinit radeon_probe_OF_head(struct radeonfb_info *rinfo, int head_ { struct device_node *dp; - RTRACE("radeon_probe_OF_head\n"); + pr_debug("radeon_probe_OF_head\n"); dp = rinfo->of_node; while (dp == NULL) @@ -135,7 +135,7 @@ static int __devinit radeon_probe_OF_head(struct radeonfb_info *rinfo, int head_ if (!pname) return MT_NONE; len = strlen(pname); - RTRACE("head: %s (letter: %c, head_no: %d)\n", + pr_debug("head: %s (letter: %c, head_no: %d)\n", pname, pname[len-1], head_no); if (pname[len-1] == 'A' && head_no == 0) { int mt = radeon_parse_montype_prop(dp, out_EDID, 0); @@ -185,7 +185,7 @@ static int __devinit radeon_get_panel_info_BIOS(struct radeonfb_info *rinfo) rinfo->panel_info.xres, rinfo->panel_info.yres); rinfo->panel_info.pwr_delay = BIOS_IN16(tmp + 44); - RTRACE("BIOS provided panel power delay: %d\n", rinfo->panel_info.pwr_delay); + pr_debug("BIOS provided panel power delay: %d\n", rinfo->panel_info.pwr_delay); if (rinfo->panel_info.pwr_delay > 2000 || rinfo->panel_info.pwr_delay <= 0) rinfo->panel_info.pwr_delay = 2000; @@ -199,16 +199,16 @@ static int __devinit radeon_get_panel_info_BIOS(struct radeonfb_info *rinfo) rinfo->panel_info.fbk_divider > 3) { rinfo->panel_info.use_bios_dividers = 1; printk(KERN_INFO "radeondb: BIOS provided dividers will be used\n"); - RTRACE("ref_divider = %x\n", rinfo->panel_info.ref_divider); - RTRACE("post_divider = %x\n", rinfo->panel_info.post_divider); - RTRACE("fbk_divider = %x\n", rinfo->panel_info.fbk_divider); + pr_debug("ref_divider = %x\n", rinfo->panel_info.ref_divider); + pr_debug("post_divider = %x\n", rinfo->panel_info.post_divider); + pr_debug("fbk_divider = %x\n", rinfo->panel_info.fbk_divider); } - RTRACE("Scanning BIOS table ...\n"); + pr_debug("Scanning BIOS table ...\n"); for(i=0; i<32; i++) { tmp0 = BIOS_IN16(tmp+64+i*2); if (tmp0 == 0) break; - RTRACE(" %d x %d\n", BIOS_IN16(tmp0), BIOS_IN16(tmp0+2)); + pr_debug(" %d x %d\n", BIOS_IN16(tmp0), BIOS_IN16(tmp0+2)); if ((BIOS_IN16(tmp0) == rinfo->panel_info.xres) && (BIOS_IN16(tmp0+2) == rinfo->panel_info.yres)) { rinfo->panel_info.hblank = (BIOS_IN16(tmp0+17) - BIOS_IN16(tmp0+19)) * 8; @@ -227,19 +227,19 @@ static int __devinit radeon_get_panel_info_BIOS(struct radeonfb_info *rinfo) /* Mark panel infos valid */ rinfo->panel_info.valid = 1; - RTRACE("Found panel in BIOS table:\n"); - RTRACE(" hblank: %d\n", rinfo->panel_info.hblank); - RTRACE(" hOver_plus: %d\n", rinfo->panel_info.hOver_plus); - RTRACE(" hSync_width: %d\n", rinfo->panel_info.hSync_width); - RTRACE(" vblank: %d\n", rinfo->panel_info.vblank); - RTRACE(" vOver_plus: %d\n", rinfo->panel_info.vOver_plus); - RTRACE(" vSync_width: %d\n", rinfo->panel_info.vSync_width); - RTRACE(" clock: %d\n", rinfo->panel_info.clock); + pr_debug("Found panel in BIOS table:\n"); + pr_debug(" hblank: %d\n", rinfo->panel_info.hblank); + pr_debug(" hOver_plus: %d\n", rinfo->panel_info.hOver_plus); + pr_debug(" hSync_width: %d\n", rinfo->panel_info.hSync_width); + pr_debug(" vblank: %d\n", rinfo->panel_info.vblank); + pr_debug(" vOver_plus: %d\n", rinfo->panel_info.vOver_plus); + pr_debug(" vSync_width: %d\n", rinfo->panel_info.vSync_width); + pr_debug(" clock: %d\n", rinfo->panel_info.clock); return 1; } } - RTRACE("Didn't find panel in BIOS table !\n"); + pr_debug("Didn't find panel in BIOS table !\n"); return 0; } @@ -271,18 +271,18 @@ static void __devinit radeon_parse_connector_info(struct radeonfb_info *rinfo) * DEBUG is enabled */ chips = BIOS_IN8(offset++) >> 4; - RTRACE("%d chips in connector info\n", chips); + pr_debug("%d chips in connector info\n", chips); for (i = 0; i < chips; i++) { tmp = BIOS_IN8(offset++); connectors = tmp & 0x0f; - RTRACE(" - chip %d has %d connectors\n", tmp >> 4, connectors); + pr_debug(" - chip %d has %d connectors\n", tmp >> 4, connectors); for (conn = 0; ; conn++) { tmp = BIOS_IN16(offset); if (tmp == 0) break; offset += 2; type = (tmp >> 12) & 0x0f; - RTRACE(" * connector %d of type %d (%s) : %04x\n", + pr_debug(" * connector %d of type %d (%s) : %04x\n", conn, type, __conn_type_table[type], tmp); } } @@ -449,7 +449,7 @@ void __devinit radeon_probe_screens(struct radeonfb_info *rinfo, * a layout for each card ? */ - RTRACE("Using specified monitor layout: %s", monitor_layout); + pr_debug("Using specified monitor layout: %s", monitor_layout); #ifdef CONFIG_FB_RADEON_I2C if (!ignore_edid) { if (rinfo->mon1_type != MT_NONE) @@ -479,9 +479,9 @@ void __devinit radeon_probe_screens(struct radeonfb_info *rinfo, * Auto-detecting display type (well... trying to ...) */ - RTRACE("Starting monitor auto detection...\n"); + pr_debug("Starting monitor auto detection...\n"); -#if DEBUG && defined(CONFIG_FB_RADEON_I2C) +#if defined(DEBUG) && defined(CONFIG_FB_RADEON_I2C) { u8 *EDIDs[4] = { NULL, NULL, NULL, NULL }; int mon_types[4] = {MT_NONE, MT_NONE, MT_NONE, MT_NONE}; @@ -756,7 +756,7 @@ void __devinit radeon_check_modes(struct radeonfb_info *rinfo, const char *mode_ if (!rinfo->panel_info.use_bios_dividers && rinfo->mon1_type != MT_CRT && rinfo->mon1_EDID) { struct fb_var_screeninfo var; - RTRACE("Parsing EDID data for panel info\n"); + pr_debug("Parsing EDID data for panel info\n"); if (fb_parse_edid(rinfo->mon1_EDID, &var) == 0) { if (var.xres >= rinfo->panel_info.xres && var.yres >= rinfo->panel_info.yres) @@ -776,7 +776,7 @@ void __devinit radeon_check_modes(struct radeonfb_info *rinfo, const char *mode_ if (rinfo->mon1_type != MT_CRT && rinfo->panel_info.valid) { struct fb_var_screeninfo *var = &info->var; - RTRACE("Setting up default mode based on panel info\n"); + pr_debug("Setting up default mode based on panel info\n"); var->xres = rinfo->panel_info.xres; var->yres = rinfo->panel_info.yres; var->xres_virtual = rinfo->panel_info.xres; @@ -824,7 +824,7 @@ void __devinit radeon_check_modes(struct radeonfb_info *rinfo, const char *mode_ int dbsize; char modename[32]; - RTRACE("Guessing panel info...\n"); + pr_debug("Guessing panel info...\n"); if (rinfo->panel_info.xres == 0 || rinfo->panel_info.yres == 0) { u32 tmp = INREG(FP_HORZ_STRETCH) & HORZ_PANEL_SIZE; rinfo->panel_info.xres = ((tmp >> HORZ_PANEL_SHIFT) + 1) * 8; diff --git a/drivers/video/aty/radeonfb.h b/drivers/video/aty/radeonfb.h index 5eac1ce52e72..c347e38cd0b0 100644 --- a/drivers/video/aty/radeonfb.h +++ b/drivers/video/aty/radeonfb.h @@ -1,6 +1,10 @@ #ifndef __RADEONFB_H__ #define __RADEONFB_H__ +#ifdef CONFIG_FB_RADEON_DEBUG +#define DEBUG 1 +#endif + #include <linux/module.h> #include <linux/kernel.h> #include <linux/sched.h> @@ -365,22 +369,6 @@ struct radeonfb_info { /* - * Debugging stuffs - */ -#ifdef CONFIG_FB_RADEON_DEBUG -#define DEBUG 1 -#else -#define DEBUG 0 -#endif - -#if DEBUG -#define RTRACE printk -#else -#define RTRACE if(0) printk -#endif - - -/* * IO macros */ diff --git a/drivers/video/bf54x-lq043fb.c b/drivers/video/bf54x-lq043fb.c index eefba3d0e4b9..49834a67a623 100644 --- a/drivers/video/bf54x-lq043fb.c +++ b/drivers/video/bf54x-lq043fb.c @@ -336,7 +336,7 @@ static int bfin_bf54x_fb_check_var(struct fb_var_screeninfo *var, { if (var->bits_per_pixel != LCD_BPP) { - pr_debug("%s: depth not supported: %u BPP\n", __FUNCTION__, + pr_debug("%s: depth not supported: %u BPP\n", __func__, var->bits_per_pixel); return -EINVAL; } @@ -345,7 +345,7 @@ static int bfin_bf54x_fb_check_var(struct fb_var_screeninfo *var, 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", - __FUNCTION__, var->xres, var->yres); + __func__, var->xres, var->yres); return -EINVAL; } @@ -355,7 +355,7 @@ static int bfin_bf54x_fb_check_var(struct fb_var_screeninfo *var, if ((info->fix.line_length * var->yres_virtual) > info->fix.smem_len) { pr_debug("%s: Memory Limit requested yres_virtual = %u\n", - __FUNCTION__, var->yres_virtual); + __func__, var->yres_virtual); return -ENOMEM; } @@ -652,7 +652,7 @@ static int __init bfin_bf54x_probe(struct platform_device *pdev) goto out7; } - if (request_irq(info->irq, (void *)bfin_bf54x_irq_error, IRQF_DISABLED, + if (request_irq(info->irq, bfin_bf54x_irq_error, IRQF_DISABLED, "PPI ERROR", info) < 0) { printk(KERN_ERR DRIVER_NAME ": unable to request PPI ERROR IRQ\n"); diff --git a/drivers/video/bw2.c b/drivers/video/bw2.c index 833b10c84064..275d9dab0c61 100644 --- a/drivers/video/bw2.c +++ b/drivers/video/bw2.c @@ -339,7 +339,7 @@ static int __devinit bw2_probe(struct of_device *op, const struct of_device_id * dev_set_drvdata(&op->dev, info); - printk("%s: bwtwo at %lx:%lx\n", + printk(KERN_INFO "%s: bwtwo at %lx:%lx\n", dp->full_name, par->which_io, par->physbase); return 0; @@ -399,10 +399,9 @@ static int __init bw2_init(void) static void __exit bw2_exit(void) { - return of_unregister_driver(&bw2_driver); + of_unregister_driver(&bw2_driver); } - module_init(bw2_init); module_exit(bw2_exit); diff --git a/drivers/video/cfbcopyarea.c b/drivers/video/cfbcopyarea.c index b07e419b12d2..df03f3776dcc 100644 --- a/drivers/video/cfbcopyarea.c +++ b/drivers/video/cfbcopyarea.c @@ -44,15 +44,16 @@ */ static void -bitcpy(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src, - int src_idx, int bits, unsigned n, u32 bswapmask) +bitcpy(struct fb_info *p, unsigned long __iomem *dst, int dst_idx, + const unsigned long __iomem *src, int src_idx, int bits, + unsigned n, u32 bswapmask) { unsigned long first, last; int const shift = dst_idx-src_idx; int left, right; - first = fb_shifted_pixels_mask_long(dst_idx, bswapmask); - last = ~fb_shifted_pixels_mask_long((dst_idx+n) % bits, bswapmask); + first = fb_shifted_pixels_mask_long(p, dst_idx, bswapmask); + last = ~fb_shifted_pixels_mask_long(p, (dst_idx+n) % bits, bswapmask); if (!shift) { // Same alignment for source and dest @@ -202,8 +203,9 @@ bitcpy(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src */ static void -bitcpy_rev(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src, - int src_idx, int bits, unsigned n, u32 bswapmask) +bitcpy_rev(struct fb_info *p, unsigned long __iomem *dst, int dst_idx, + const unsigned long __iomem *src, int src_idx, int bits, + unsigned n, u32 bswapmask) { unsigned long first, last; int shift; @@ -221,8 +223,9 @@ bitcpy_rev(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem shift = dst_idx-src_idx; - first = fb_shifted_pixels_mask_long(bits - 1 - dst_idx, bswapmask); - last = ~fb_shifted_pixels_mask_long(bits - 1 - ((dst_idx-n) % bits), bswapmask); + first = fb_shifted_pixels_mask_long(p, bits - 1 - dst_idx, bswapmask); + last = ~fb_shifted_pixels_mask_long(p, bits - 1 - ((dst_idx-n) % bits), + bswapmask); if (!shift) { // Same alignment for source and dest @@ -404,7 +407,7 @@ void cfb_copyarea(struct fb_info *p, const struct fb_copyarea *area) dst_idx &= (bytes - 1); src += src_idx >> (ffs(bits) - 1); src_idx &= (bytes - 1); - bitcpy_rev(dst, dst_idx, src, src_idx, bits, + bitcpy_rev(p, dst, dst_idx, src, src_idx, bits, width*p->var.bits_per_pixel, bswapmask); } } else { @@ -413,7 +416,7 @@ void cfb_copyarea(struct fb_info *p, const struct fb_copyarea *area) dst_idx &= (bytes - 1); src += src_idx >> (ffs(bits) - 1); src_idx &= (bytes - 1); - bitcpy(dst, dst_idx, src, src_idx, bits, + bitcpy(p, dst, dst_idx, src, src_idx, bits, width*p->var.bits_per_pixel, bswapmask); dst_idx += bits_per_line; src_idx += bits_per_line; diff --git a/drivers/video/cfbfillrect.c b/drivers/video/cfbfillrect.c index 23d70a12e4da..64b35766b2a2 100644 --- a/drivers/video/cfbfillrect.c +++ b/drivers/video/cfbfillrect.c @@ -36,16 +36,16 @@ */ static void -bitfill_aligned(unsigned long __iomem *dst, int dst_idx, unsigned long pat, - unsigned n, int bits, u32 bswapmask) +bitfill_aligned(struct fb_info *p, unsigned long __iomem *dst, int dst_idx, + unsigned long pat, unsigned n, int bits, u32 bswapmask) { unsigned long first, last; if (!n) return; - first = fb_shifted_pixels_mask_long(dst_idx, bswapmask); - last = ~fb_shifted_pixels_mask_long((dst_idx+n) % bits, bswapmask); + first = fb_shifted_pixels_mask_long(p, dst_idx, bswapmask); + last = ~fb_shifted_pixels_mask_long(p, (dst_idx+n) % bits, bswapmask); if (dst_idx+n <= bits) { // Single word @@ -93,16 +93,16 @@ bitfill_aligned(unsigned long __iomem *dst, int dst_idx, unsigned long pat, */ static void -bitfill_unaligned(unsigned long __iomem *dst, int dst_idx, unsigned long pat, - int left, int right, unsigned n, int bits) +bitfill_unaligned(struct fb_info *p, unsigned long __iomem *dst, int dst_idx, + unsigned long pat, int left, int right, unsigned n, int bits) { unsigned long first, last; if (!n) return; - first = FB_SHIFT_HIGH(~0UL, dst_idx); - last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits)); + first = FB_SHIFT_HIGH(p, ~0UL, dst_idx); + last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits)); if (dst_idx+n <= bits) { // Single word @@ -147,8 +147,9 @@ bitfill_unaligned(unsigned long __iomem *dst, int dst_idx, unsigned long pat, * Aligned pattern invert using 32/64-bit memory accesses */ static void -bitfill_aligned_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat, - unsigned n, int bits, u32 bswapmask) +bitfill_aligned_rev(struct fb_info *p, unsigned long __iomem *dst, + int dst_idx, unsigned long pat, unsigned n, int bits, + u32 bswapmask) { unsigned long val = pat, dat; unsigned long first, last; @@ -156,8 +157,8 @@ bitfill_aligned_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat, if (!n) return; - first = fb_shifted_pixels_mask_long(dst_idx, bswapmask); - last = ~fb_shifted_pixels_mask_long((dst_idx+n) % bits, bswapmask); + first = fb_shifted_pixels_mask_long(p, dst_idx, bswapmask); + last = ~fb_shifted_pixels_mask_long(p, (dst_idx+n) % bits, bswapmask); if (dst_idx+n <= bits) { // Single word @@ -217,16 +218,17 @@ bitfill_aligned_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat, */ static void -bitfill_unaligned_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat, - int left, int right, unsigned n, int bits) +bitfill_unaligned_rev(struct fb_info *p, unsigned long __iomem *dst, + int dst_idx, unsigned long pat, int left, int right, + unsigned n, int bits) { unsigned long first, last, dat; if (!n) return; - first = FB_SHIFT_HIGH(~0UL, dst_idx); - last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits)); + first = FB_SHIFT_HIGH(p, ~0UL, dst_idx); + last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits)); if (dst_idx+n <= bits) { // Single word @@ -306,7 +308,8 @@ void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect) p->fbops->fb_sync(p); if (!left) { u32 bswapmask = fb_compute_bswapmask(p); - void (*fill_op32)(unsigned long __iomem *dst, int dst_idx, + void (*fill_op32)(struct fb_info *p, + unsigned long __iomem *dst, int dst_idx, unsigned long pat, unsigned n, int bits, u32 bswapmask) = NULL; @@ -325,16 +328,17 @@ void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect) while (height--) { dst += dst_idx >> (ffs(bits) - 1); dst_idx &= (bits - 1); - fill_op32(dst, dst_idx, pat, width*bpp, bits, bswapmask); + fill_op32(p, dst, dst_idx, pat, width*bpp, bits, + bswapmask); dst_idx += p->fix.line_length*8; } } else { int right; int r; int rot = (left-dst_idx) % bpp; - void (*fill_op)(unsigned long __iomem *dst, int dst_idx, - unsigned long pat, int left, int right, - unsigned n, int bits) = NULL; + void (*fill_op)(struct fb_info *p, unsigned long __iomem *dst, + int dst_idx, unsigned long pat, int left, + int right, unsigned n, int bits) = NULL; /* rotate pattern to correct start position */ pat = pat << rot | pat >> (bpp-rot); @@ -355,7 +359,7 @@ void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect) while (height--) { dst += dst_idx >> (ffs(bits) - 1); dst_idx &= (bits - 1); - fill_op(dst, dst_idx, pat, left, right, + fill_op(p, dst, dst_idx, pat, left, right, width*bpp, bits); r = (p->fix.line_length*8) % bpp; pat = pat << (bpp-r) | pat >> r; diff --git a/drivers/video/cfbimgblt.c b/drivers/video/cfbimgblt.c index f598907b42ad..baed57d3cfff 100644 --- a/drivers/video/cfbimgblt.c +++ b/drivers/video/cfbimgblt.c @@ -38,35 +38,31 @@ #define DEBUG #ifdef DEBUG -#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt,__FUNCTION__,## args) +#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt,__func__,## args) #else #define DPRINTK(fmt, args...) #endif -static const u32 cfb_tab8[] = { -#if defined(__BIG_ENDIAN) +static const u32 cfb_tab8_be[] = { 0x00000000,0x000000ff,0x0000ff00,0x0000ffff, 0x00ff0000,0x00ff00ff,0x00ffff00,0x00ffffff, 0xff000000,0xff0000ff,0xff00ff00,0xff00ffff, 0xffff0000,0xffff00ff,0xffffff00,0xffffffff -#elif defined(__LITTLE_ENDIAN) +}; + +static const u32 cfb_tab8_le[] = { 0x00000000,0xff000000,0x00ff0000,0xffff0000, 0x0000ff00,0xff00ff00,0x00ffff00,0xffffff00, 0x000000ff,0xff0000ff,0x00ff00ff,0xffff00ff, 0x0000ffff,0xff00ffff,0x00ffffff,0xffffffff -#else -#error FIXME: No endianness?? -#endif }; -static const u32 cfb_tab16[] = { -#if defined(__BIG_ENDIAN) +static const u32 cfb_tab16_be[] = { 0x00000000, 0x0000ffff, 0xffff0000, 0xffffffff -#elif defined(__LITTLE_ENDIAN) +}; + +static const u32 cfb_tab16_le[] = { 0x00000000, 0xffff0000, 0x0000ffff, 0xffffffff -#else -#error FIXME: No endianness?? -#endif }; static const u32 cfb_tab32[] = { @@ -98,7 +94,8 @@ static inline void color_imageblit(const struct fb_image *image, val = 0; if (start_index) { - u32 start_mask = ~fb_shifted_pixels_mask_u32(start_index, bswapmask); + u32 start_mask = ~fb_shifted_pixels_mask_u32(p, + start_index, bswapmask); val = FB_READL(dst) & start_mask; shift = start_index; } @@ -108,20 +105,21 @@ static inline void color_imageblit(const struct fb_image *image, color = palette[*src]; else color = *src; - color <<= FB_LEFT_POS(bpp); - val |= FB_SHIFT_HIGH(color, shift ^ bswapmask); + color <<= FB_LEFT_POS(p, bpp); + val |= FB_SHIFT_HIGH(p, color, shift ^ bswapmask); if (shift >= null_bits) { FB_WRITEL(val, dst++); val = (shift == null_bits) ? 0 : - FB_SHIFT_LOW(color, 32 - shift); + FB_SHIFT_LOW(p, color, 32 - shift); } shift += bpp; shift &= (32 - 1); src++; } if (shift) { - u32 end_mask = fb_shifted_pixels_mask_u32(shift, bswapmask); + u32 end_mask = fb_shifted_pixels_mask_u32(p, shift, + bswapmask); FB_WRITEL((FB_READL(dst) & end_mask) | val, dst); } @@ -152,8 +150,8 @@ static inline void slow_imageblit(const struct fb_image *image, struct fb_info * u32 bswapmask = fb_compute_bswapmask(p); dst2 = (u32 __iomem *) dst1; - fgcolor <<= FB_LEFT_POS(bpp); - bgcolor <<= FB_LEFT_POS(bpp); + fgcolor <<= FB_LEFT_POS(p, bpp); + bgcolor <<= FB_LEFT_POS(p, bpp); for (i = image->height; i--; ) { shift = val = 0; @@ -164,7 +162,8 @@ static inline void slow_imageblit(const struct fb_image *image, struct fb_info * /* write leading bits */ if (start_index) { - u32 start_mask = ~fb_shifted_pixels_mask_u32(start_index, bswapmask); + u32 start_mask = ~fb_shifted_pixels_mask_u32(p, + start_index, bswapmask); val = FB_READL(dst) & start_mask; shift = start_index; } @@ -172,13 +171,13 @@ static inline void slow_imageblit(const struct fb_image *image, struct fb_info * while (j--) { l--; color = (*s & (1 << l)) ? fgcolor : bgcolor; - val |= FB_SHIFT_HIGH(color, shift ^ bswapmask); + val |= FB_SHIFT_HIGH(p, color, shift ^ bswapmask); /* Did the bitshift spill bits to the next long? */ if (shift >= null_bits) { FB_WRITEL(val, dst++); val = (shift == null_bits) ? 0 : - FB_SHIFT_LOW(color,32 - shift); + FB_SHIFT_LOW(p, color, 32 - shift); } shift += bpp; shift &= (32 - 1); @@ -187,7 +186,8 @@ static inline void slow_imageblit(const struct fb_image *image, struct fb_info * /* write trailing bits */ if (shift) { - u32 end_mask = fb_shifted_pixels_mask_u32(shift, bswapmask); + u32 end_mask = fb_shifted_pixels_mask_u32(p, shift, + bswapmask); FB_WRITEL((FB_READL(dst) & end_mask) | val, dst); } @@ -223,13 +223,13 @@ static inline void fast_imageblit(const struct fb_image *image, struct fb_info * u32 __iomem *dst; const u32 *tab = NULL; int i, j, k; - + switch (bpp) { case 8: - tab = cfb_tab8; + tab = fb_be_math(p) ? cfb_tab8_be : cfb_tab8_le; break; case 16: - tab = cfb_tab16; + tab = fb_be_math(p) ? cfb_tab16_be : cfb_tab16_le; break; case 32: default: diff --git a/drivers/video/cg14.c b/drivers/video/cg14.c index fdc9f43ec30a..0db0fecba93b 100644 --- a/drivers/video/cg14.c +++ b/drivers/video/cg14.c @@ -556,7 +556,7 @@ static int __devinit cg14_probe(struct of_device *op, const struct of_device_id dev_set_drvdata(&op->dev, info); - printk("%s: cgfourteen at %lx:%lx, %dMB\n", + printk(KERN_INFO "%s: cgfourteen at %lx:%lx, %dMB\n", dp->full_name, par->iospace, par->physbase, par->ramsize >> 20); @@ -605,7 +605,7 @@ static struct of_platform_driver cg14_driver = { .remove = __devexit_p(cg14_remove), }; -int __init cg14_init(void) +static int __init cg14_init(void) { if (fb_get_options("cg14fb", NULL)) return -ENODEV; @@ -613,7 +613,7 @@ int __init cg14_init(void) return of_register_driver(&cg14_driver, &of_bus_type); } -void __exit cg14_exit(void) +static void __exit cg14_exit(void) { of_unregister_driver(&cg14_driver); } diff --git a/drivers/video/cg3.c b/drivers/video/cg3.c index a5c7fb331527..010ea53978f8 100644 --- a/drivers/video/cg3.c +++ b/drivers/video/cg3.c @@ -419,7 +419,7 @@ static int __devinit cg3_probe(struct of_device *op, dev_set_drvdata(&op->dev, info); - printk("%s: cg3 at %lx:%lx\n", + printk(KERN_INFO "%s: cg3 at %lx:%lx\n", dp->full_name, par->which_io, par->physbase); return 0; diff --git a/drivers/video/cg6.c b/drivers/video/cg6.c index 549891d76ef5..fc90db6da65a 100644 --- a/drivers/video/cg6.c +++ b/drivers/video/cg6.c @@ -781,7 +781,7 @@ static int __devinit cg6_probe(struct of_device *op, dev_set_drvdata(&op->dev, info); - printk("%s: CGsix [%s] at %lx:%lx\n", + printk(KERN_INFO "%s: CGsix [%s] at %lx:%lx\n", dp->full_name, info->fix.id, par->which_io, par->physbase); diff --git a/drivers/video/cirrusfb.c b/drivers/video/cirrusfb.c index f7e2d5add831..35ac9d956b3d 100644 --- a/drivers/video/cirrusfb.c +++ b/drivers/video/cirrusfb.c @@ -81,7 +81,7 @@ /* debug output */ #ifdef CIRRUSFB_DEBUG #define DPRINTK(fmt, args...) \ - printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args) + printk(KERN_DEBUG "%s: " fmt, __func__ , ## args) #else #define DPRINTK(fmt, args...) #endif @@ -91,7 +91,7 @@ #define assert(expr) \ if (!(expr)) { \ printk("Assertion failed! %s,%s,%s,line=%d\n", \ - #expr, __FILE__, __FUNCTION__, __LINE__); \ + #expr, __FILE__, __func__, __LINE__); \ } #else #define assert(expr) @@ -3117,7 +3117,7 @@ static void bestclock(long freq, long *best, long *nom, } } } - d = ((143181 * n) + f - 1) / f; + d = DIV_ROUND_UP(143181 * n, f); if ((d >= 7) && (d <= 63)) { if (d > 31) d = (d / 2) * 2; diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index 022282494d3f..8eda7b60df8f 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -92,7 +92,7 @@ #include "fbcon.h" #ifdef FBCONDEBUG -# define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args) +# define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __func__ , ## args) #else # define DPRINTK(fmt, args...) #endif @@ -620,8 +620,7 @@ static void fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info, if (fb_get_color_depth(&info->var, &info->fix) == 1) erase &= ~0x400; logo_height = fb_prepare_logo(info, ops->rotate); - logo_lines = (logo_height + vc->vc_font.height - 1) / - vc->vc_font.height; + logo_lines = DIV_ROUND_UP(logo_height, vc->vc_font.height); q = (unsigned short *) (vc->vc_origin + vc->vc_size_row * rows); step = logo_lines * cols; diff --git a/drivers/video/console/fbcon.h b/drivers/video/console/fbcon.h index 3706307e70ed..0135e0395456 100644 --- a/drivers/video/console/fbcon.h +++ b/drivers/video/console/fbcon.h @@ -104,10 +104,14 @@ struct fbcon_ops { #define attr_blink(s) \ ((s) & 0x8000) -#define mono_col(info) \ - (~(0xfff << (max((info)->var.green.length, \ - max((info)->var.red.length, \ - (info)->var.blue.length)))) & 0xff) + +static inline int mono_col(const struct fb_info *info) +{ + __u32 max_len; + max_len = max(info->var.green.length, info->var.red.length); + max_len = max(info->var.blue.length, max_len); + return ~(0xfff << (max_len & 0xff)); +} static inline int attr_col_ec(int shift, struct vc_data *vc, struct fb_info *info, int is_fg) diff --git a/drivers/video/fb_draw.h b/drivers/video/fb_draw.h index a2a0618d86a5..1db622192bde 100644 --- a/drivers/video/fb_draw.h +++ b/drivers/video/fb_draw.h @@ -94,41 +94,44 @@ static inline unsigned long fb_rev_pixels_in_long(unsigned long val, return val; } -static inline u32 fb_shifted_pixels_mask_u32(u32 index, u32 bswapmask) +static inline u32 fb_shifted_pixels_mask_u32(struct fb_info *p, u32 index, + u32 bswapmask) { u32 mask; if (!bswapmask) { - mask = FB_SHIFT_HIGH(~(u32)0, index); + mask = FB_SHIFT_HIGH(p, ~(u32)0, index); } else { - mask = 0xff << FB_LEFT_POS(8); - mask = FB_SHIFT_LOW(mask, index & (bswapmask)) & mask; - mask = FB_SHIFT_HIGH(mask, index & ~(bswapmask)); + mask = 0xff << FB_LEFT_POS(p, 8); + mask = FB_SHIFT_LOW(p, mask, index & (bswapmask)) & mask; + mask = FB_SHIFT_HIGH(p, mask, index & ~(bswapmask)); #if defined(__i386__) || defined(__x86_64__) /* Shift argument is limited to 0 - 31 on x86 based CPU's */ if(index + bswapmask < 32) #endif - mask |= FB_SHIFT_HIGH(~(u32)0, + mask |= FB_SHIFT_HIGH(p, ~(u32)0, (index + bswapmask) & ~(bswapmask)); } return mask; } -static inline unsigned long fb_shifted_pixels_mask_long(u32 index, u32 bswapmask) +static inline unsigned long fb_shifted_pixels_mask_long(struct fb_info *p, + u32 index, + u32 bswapmask) { unsigned long mask; if (!bswapmask) { - mask = FB_SHIFT_HIGH(~0UL, index); + mask = FB_SHIFT_HIGH(p, ~0UL, index); } else { - mask = 0xff << FB_LEFT_POS(8); - mask = FB_SHIFT_LOW(mask, index & (bswapmask)) & mask; - mask = FB_SHIFT_HIGH(mask, index & ~(bswapmask)); + mask = 0xff << FB_LEFT_POS(p, 8); + mask = FB_SHIFT_LOW(p, mask, index & (bswapmask)) & mask; + mask = FB_SHIFT_HIGH(p, mask, index & ~(bswapmask)); #if defined(__i386__) || defined(__x86_64__) /* Shift argument is limited to 0 - 31 on x86 based CPU's */ if(index + bswapmask < BITS_PER_LONG) #endif - mask |= FB_SHIFT_HIGH(~0UL, + mask |= FB_SHIFT_HIGH(p, ~0UL, (index + bswapmask) & ~(bswapmask)); } return mask; @@ -158,8 +161,8 @@ static inline unsigned long fb_rev_pixels_in_long(unsigned long val, return val; } -#define fb_shifted_pixels_mask_u32(i, b) FB_SHIFT_HIGH(~(u32)0, (i)) -#define fb_shifted_pixels_mask_long(i, b) FB_SHIFT_HIGH(~0UL, (i)) +#define fb_shifted_pixels_mask_u32(p, i, b) FB_SHIFT_HIGH((p), ~(u32)0, (i)) +#define fb_shifted_pixels_mask_long(p, i, b) FB_SHIFT_HIGH((p), ~0UL, (i)) #define fb_compute_bswapmask(...) 0 #endif /* CONFIG_FB_CFB_REV_PIXELS_IN_BYTE */ diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index 01072f4b3e8f..776f7fcd2fbf 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -26,6 +26,7 @@ #include <linux/init.h> #include <linux/linux_logo.h> #include <linux/proc_fs.h> +#include <linux/seq_file.h> #include <linux/console.h> #ifdef CONFIG_KMOD #include <linux/kmod.h> @@ -632,27 +633,51 @@ int fb_prepare_logo(struct fb_info *info, int rotate) { return 0; } int fb_show_logo(struct fb_info *info, int rotate) { return 0; } #endif /* CONFIG_LOGO */ -static int fbmem_read_proc(char *buf, char **start, off_t offset, - int len, int *eof, void *private) +static void *fb_seq_start(struct seq_file *m, loff_t *pos) { - struct fb_info **fi; - int clen; - - clen = 0; - for (fi = registered_fb; fi < ®istered_fb[FB_MAX] && clen < 4000; - fi++) - if (*fi) - clen += sprintf(buf + clen, "%d %s\n", - (*fi)->node, - (*fi)->fix.id); - *start = buf + offset; - if (clen > offset) - clen -= offset; - else - clen = 0; - return clen < len ? clen : len; + return (*pos < FB_MAX) ? pos : NULL; +} + +static void *fb_seq_next(struct seq_file *m, void *v, loff_t *pos) +{ + (*pos)++; + return (*pos < FB_MAX) ? pos : NULL; +} + +static void fb_seq_stop(struct seq_file *m, void *v) +{ +} + +static int fb_seq_show(struct seq_file *m, void *v) +{ + int i = *(loff_t *)v; + struct fb_info *fi = registered_fb[i]; + + if (fi) + seq_printf(m, "%d %s\n", fi->node, fi->fix.id); + return 0; +} + +static const struct seq_operations proc_fb_seq_ops = { + .start = fb_seq_start, + .next = fb_seq_next, + .stop = fb_seq_stop, + .show = fb_seq_show, +}; + +static int proc_fb_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &proc_fb_seq_ops); } +static const struct file_operations fb_proc_fops = { + .owner = THIS_MODULE, + .open = proc_fb_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + static ssize_t fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { @@ -1057,7 +1082,7 @@ fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, case FBIOPUT_CON2FBMAP: if (copy_from_user(&con2fb, argp, sizeof(con2fb))) return - EFAULT; - if (con2fb.console < 0 || con2fb.console > MAX_NR_CONSOLES) + if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES) return -EINVAL; if (con2fb.framebuffer < 0 || con2fb.framebuffer >= FB_MAX) return -EINVAL; @@ -1352,6 +1377,32 @@ static const struct file_operations fb_fops = { struct class *fb_class; EXPORT_SYMBOL(fb_class); + +static int fb_check_foreignness(struct fb_info *fi) +{ + const bool foreign_endian = fi->flags & FBINFO_FOREIGN_ENDIAN; + + fi->flags &= ~FBINFO_FOREIGN_ENDIAN; + +#ifdef __BIG_ENDIAN + fi->flags |= foreign_endian ? 0 : FBINFO_BE_MATH; +#else + fi->flags |= foreign_endian ? FBINFO_BE_MATH : 0; +#endif /* __BIG_ENDIAN */ + + if (fi->flags & FBINFO_BE_MATH && !fb_be_math(fi)) { + pr_err("%s: enable CONFIG_FB_BIG_ENDIAN to " + "support this framebuffer\n", fi->fix.id); + return -ENOSYS; + } else if (!(fi->flags & FBINFO_BE_MATH) && fb_be_math(fi)) { + pr_err("%s: enable CONFIG_FB_LITTLE_ENDIAN to " + "support this framebuffer\n", fi->fix.id); + return -ENOSYS; + } + + return 0; +} + /** * register_framebuffer - registers a frame buffer device * @fb_info: frame buffer info structure @@ -1371,6 +1422,10 @@ register_framebuffer(struct fb_info *fb_info) if (num_registered_fb == FB_MAX) return -ENXIO; + + if (fb_check_foreignness(fb_info)) + return -ENOSYS; + num_registered_fb++; for (i = 0 ; i < FB_MAX; i++) if (!registered_fb[i]) @@ -1503,7 +1558,7 @@ void fb_set_suspend(struct fb_info *info, int state) static int __init fbmem_init(void) { - create_proc_read_entry("fb", 0, NULL, fbmem_read_proc, NULL); + proc_create("fb", 0, NULL, &fb_proc_fops); if (register_chrdev(FB_MAJOR,"fb",&fb_fops)) printk("unable to get major %d for fb devs\n", FB_MAJOR); diff --git a/drivers/video/ffb.c b/drivers/video/ffb.c index d7e24889650e..93dca3e2aa50 100644 --- a/drivers/video/ffb.c +++ b/drivers/video/ffb.c @@ -32,7 +32,6 @@ static int ffb_setcolreg(unsigned, unsigned, unsigned, unsigned, unsigned, struct fb_info *); static int ffb_blank(int, struct fb_info *); -static void ffb_init_fix(struct fb_info *); static void ffb_imageblit(struct fb_info *, const struct fb_image *); static void ffb_fillrect(struct fb_info *, const struct fb_fillrect *); @@ -1001,7 +1000,7 @@ static int __devinit ffb_probe(struct of_device *op, dev_set_drvdata(&op->dev, info); - printk("%s: %s at %016lx, type %d, " + printk(KERN_INFO "%s: %s at %016lx, type %d, " "DAC pnum[%x] rev[%d] manuf_rev[%d]\n", dp->full_name, ((par->flags & FFB_FLAG_AFB) ? "AFB" : "FFB"), @@ -1062,7 +1061,7 @@ static struct of_platform_driver ffb_driver = { .remove = __devexit_p(ffb_remove), }; -int __init ffb_init(void) +static int __init ffb_init(void) { if (fb_get_options("ffb", NULL)) return -ENODEV; @@ -1070,7 +1069,7 @@ int __init ffb_init(void) return of_register_driver(&ffb_driver, &of_bus_type); } -void __exit ffb_exit(void) +static void __exit ffb_exit(void) { of_unregister_driver(&ffb_driver); } diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c new file mode 100644 index 000000000000..b50bb03cb5ab --- /dev/null +++ b/drivers/video/fsl-diu-fb.c @@ -0,0 +1,1721 @@ +/* + * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved. + * + * Freescale DIU Frame Buffer device driver + * + * Authors: Hongjun Chen <hong-jun.chen@freescale.com> + * Paul Widmer <paul.widmer@freescale.com> + * Srikanth Srinivasan <srikanth.srinivasan@freescale.com> + * York Sun <yorksun@freescale.com> + * + * Based on imxfb.c Copyright (C) 2004 S.Hauer, Pengutronix + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/slab.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <linux/dma-mapping.h> +#include <linux/platform_device.h> +#include <linux/interrupt.h> +#include <linux/clk.h> +#include <linux/uaccess.h> +#include <linux/vmalloc.h> + +#include <linux/of_platform.h> + +#include <sysdev/fsl_soc.h> +#include "fsl-diu-fb.h" + +/* + * These parameters give default parameters + * for video output 1024x768, + * FIXME - change timing to proper amounts + * hsync 31.5kHz, vsync 60Hz + */ +static struct fb_videomode __devinitdata fsl_diu_default_mode = { + .refresh = 60, + .xres = 1024, + .yres = 768, + .pixclock = 15385, + .left_margin = 160, + .right_margin = 24, + .upper_margin = 29, + .lower_margin = 3, + .hsync_len = 136, + .vsync_len = 6, + .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + .vmode = FB_VMODE_NONINTERLACED +}; + +static struct fb_videomode __devinitdata fsl_diu_mode_db[] = { + { + .name = "1024x768-60", + .refresh = 60, + .xres = 1024, + .yres = 768, + .pixclock = 15385, + .left_margin = 160, + .right_margin = 24, + .upper_margin = 29, + .lower_margin = 3, + .hsync_len = 136, + .vsync_len = 6, + .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + .vmode = FB_VMODE_NONINTERLACED + }, + { + .name = "1024x768-70", + .refresh = 70, + .xres = 1024, + .yres = 768, + .pixclock = 16886, + .left_margin = 3, + .right_margin = 3, + .upper_margin = 2, + .lower_margin = 2, + .hsync_len = 40, + .vsync_len = 18, + .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + .vmode = FB_VMODE_NONINTERLACED + }, + { + .name = "1024x768-75", + .refresh = 75, + .xres = 1024, + .yres = 768, + .pixclock = 15009, + .left_margin = 3, + .right_margin = 3, + .upper_margin = 2, + .lower_margin = 2, + .hsync_len = 80, + .vsync_len = 32, + .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + .vmode = FB_VMODE_NONINTERLACED + }, + { + .name = "1280x1024-60", + .refresh = 60, + .xres = 1280, + .yres = 1024, + .pixclock = 9375, + .left_margin = 38, + .right_margin = 128, + .upper_margin = 2, + .lower_margin = 7, + .hsync_len = 216, + .vsync_len = 37, + .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + .vmode = FB_VMODE_NONINTERLACED + }, + { + .name = "1280x1024-70", + .refresh = 70, + .xres = 1280, + .yres = 1024, + .pixclock = 9380, + .left_margin = 6, + .right_margin = 6, + .upper_margin = 4, + .lower_margin = 4, + .hsync_len = 60, + .vsync_len = 94, + .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + .vmode = FB_VMODE_NONINTERLACED + }, + { + .name = "1280x1024-75", + .refresh = 75, + .xres = 1280, + .yres = 1024, + .pixclock = 9380, + .left_margin = 6, + .right_margin = 6, + .upper_margin = 4, + .lower_margin = 4, + .hsync_len = 60, + .vsync_len = 15, + .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + .vmode = FB_VMODE_NONINTERLACED + }, + { + .name = "320x240", /* for AOI only */ + .refresh = 60, + .xres = 320, + .yres = 240, + .pixclock = 15385, + .left_margin = 0, + .right_margin = 0, + .upper_margin = 0, + .lower_margin = 0, + .hsync_len = 0, + .vsync_len = 0, + .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + .vmode = FB_VMODE_NONINTERLACED + }, + { + .name = "1280x480-60", + .refresh = 60, + .xres = 1280, + .yres = 480, + .pixclock = 18939, + .left_margin = 353, + .right_margin = 47, + .upper_margin = 39, + .lower_margin = 4, + .hsync_len = 8, + .vsync_len = 2, + .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + .vmode = FB_VMODE_NONINTERLACED + }, +}; + +static char *fb_mode = "1024x768-32@60"; +static unsigned long default_bpp = 32; +static int monitor_port; + +#if defined(CONFIG_NOT_COHERENT_CACHE) +static u8 *coherence_data; +static size_t coherence_data_size; +static unsigned int d_cache_line_size; +#endif + +static DEFINE_SPINLOCK(diu_lock); + +struct fsl_diu_data { + struct fb_info *fsl_diu_info[FSL_AOI_NUM - 1]; + /*FSL_AOI_NUM has one dummy AOI */ + struct device_attribute dev_attr; + struct diu_ad *dummy_ad; + void *dummy_aoi_virt; + unsigned int irq; + int fb_enabled; + int monitor_port; +}; + +struct mfb_info { + int index; + int type; + char *id; + int registered; + int blank; + unsigned long pseudo_palette[16]; + struct diu_ad *ad; + int cursor_reset; + unsigned char g_alpha; + unsigned int count; + int x_aoi_d; /* aoi display x offset to physical screen */ + int y_aoi_d; /* aoi display y offset to physical screen */ + struct fsl_diu_data *parent; +}; + + +static struct mfb_info mfb_template[] = { + { /* AOI 0 for plane 0 */ + .index = 0, + .type = MFB_TYPE_OUTPUT, + .id = "Panel0", + .registered = 0, + .count = 0, + .x_aoi_d = 0, + .y_aoi_d = 0, + }, + { /* AOI 0 for plane 1 */ + .index = 1, + .type = MFB_TYPE_OUTPUT, + .id = "Panel1 AOI0", + .registered = 0, + .g_alpha = 0xff, + .count = 0, + .x_aoi_d = 0, + .y_aoi_d = 0, + }, + { /* AOI 1 for plane 1 */ + .index = 2, + .type = MFB_TYPE_OUTPUT, + .id = "Panel1 AOI1", + .registered = 0, + .g_alpha = 0xff, + .count = 0, + .x_aoi_d = 0, + .y_aoi_d = 480, + }, + { /* AOI 0 for plane 2 */ + .index = 3, + .type = MFB_TYPE_OUTPUT, + .id = "Panel2 AOI0", + .registered = 0, + .g_alpha = 0xff, + .count = 0, + .x_aoi_d = 640, + .y_aoi_d = 0, + }, + { /* AOI 1 for plane 2 */ + .index = 4, + .type = MFB_TYPE_OUTPUT, + .id = "Panel2 AOI1", + .registered = 0, + .g_alpha = 0xff, + .count = 0, + .x_aoi_d = 640, + .y_aoi_d = 480, + }, +}; + +static struct diu_hw dr = { + .mode = MFB_MODE1, + .reg_lock = __SPIN_LOCK_UNLOCKED(diu_hw.reg_lock), +}; + +static struct diu_pool pool; + +/* To allocate memory for framebuffer. First try __get_free_pages(). If it + * fails, try rh_alloc. The reason is __get_free_pages() cannot allocate + * very large memory (more than 4MB). We don't want to allocate all memory + * in rheap since small memory allocation/deallocation will fragment the + * rheap and make the furture large allocation fail. + */ + +void *fsl_diu_alloc(unsigned long size, phys_addr_t *phys) +{ + void *virt; + + pr_debug("size=%lu\n", size); + + virt = (void *)__get_free_pages(GFP_DMA | __GFP_ZERO, get_order(size)); + if (virt) { + *phys = virt_to_phys(virt); + pr_debug("virt %p, phys=%llx\n", virt, (uint64_t) *phys); + return virt; + } + if (!diu_ops.diu_mem) { + printk(KERN_INFO "%s: no diu_mem." + " To reserve more memory, put 'diufb=15M' " + "in the command line\n", __func__); + return NULL; + } + + virt = (void *)rh_alloc(&diu_ops.diu_rh_info, size, "DIU"); + if (virt) { + *phys = virt_to_bus(virt); + memset(virt, 0, size); + } + + pr_debug("rh virt=%p phys=%lx\n", virt, *phys); + + return virt; +} + +void fsl_diu_free(void *p, unsigned long size) +{ + pr_debug("p=%p size=%lu\n", p, size); + + if (!p) + return; + + if ((p >= diu_ops.diu_mem) && + (p < (diu_ops.diu_mem + diu_ops.diu_size))) { + pr_debug("rh\n"); + rh_free(&diu_ops.diu_rh_info, (unsigned long) p); + } else { + pr_debug("dma\n"); + free_pages((unsigned long)p, get_order(size)); + } +} + +static int fsl_diu_enable_panel(struct fb_info *info) +{ + struct mfb_info *pmfbi, *cmfbi, *mfbi = info->par; + struct diu *hw = dr.diu_reg; + struct diu_ad *ad = mfbi->ad; + struct fsl_diu_data *machine_data = mfbi->parent; + int res = 0; + + pr_debug("enable_panel index %d\n", mfbi->index); + if (mfbi->type != MFB_TYPE_OFF) { + switch (mfbi->index) { + case 0: /* plane 0 */ + if (hw->desc[0] != ad->paddr) + out_be32(&hw->desc[0], ad->paddr); + break; + case 1: /* plane 1 AOI 0 */ + cmfbi = machine_data->fsl_diu_info[2]->par; + if (hw->desc[1] != ad->paddr) { /* AOI0 closed */ + if (cmfbi->count > 0) /* AOI1 open */ + ad->next_ad = + cpu_to_le32(cmfbi->ad->paddr); + else + ad->next_ad = 0; + out_be32(&hw->desc[1], ad->paddr); + } + break; + case 3: /* plane 2 AOI 0 */ + cmfbi = machine_data->fsl_diu_info[4]->par; + if (hw->desc[2] != ad->paddr) { /* AOI0 closed */ + if (cmfbi->count > 0) /* AOI1 open */ + ad->next_ad = + cpu_to_le32(cmfbi->ad->paddr); + else + ad->next_ad = 0; + out_be32(&hw->desc[2], ad->paddr); + } + break; + case 2: /* plane 1 AOI 1 */ + pmfbi = machine_data->fsl_diu_info[1]->par; + ad->next_ad = 0; + if (hw->desc[1] == machine_data->dummy_ad->paddr) + out_be32(&hw->desc[1], ad->paddr); + else /* AOI0 open */ + pmfbi->ad->next_ad = cpu_to_le32(ad->paddr); + break; + case 4: /* plane 2 AOI 1 */ + pmfbi = machine_data->fsl_diu_info[3]->par; + ad->next_ad = 0; + if (hw->desc[2] == machine_data->dummy_ad->paddr) + out_be32(&hw->desc[2], ad->paddr); + else /* AOI0 was open */ + pmfbi->ad->next_ad = cpu_to_le32(ad->paddr); + break; + default: + res = -EINVAL; + break; + } + } else + res = -EINVAL; + return res; +} + +static int fsl_diu_disable_panel(struct fb_info *info) +{ + struct mfb_info *pmfbi, *cmfbi, *mfbi = info->par; + struct diu *hw = dr.diu_reg; + struct diu_ad *ad = mfbi->ad; + struct fsl_diu_data *machine_data = mfbi->parent; + int res = 0; + + switch (mfbi->index) { + case 0: /* plane 0 */ + if (hw->desc[0] != machine_data->dummy_ad->paddr) + out_be32(&hw->desc[0], + machine_data->dummy_ad->paddr); + break; + case 1: /* plane 1 AOI 0 */ + cmfbi = machine_data->fsl_diu_info[2]->par; + if (cmfbi->count > 0) /* AOI1 is open */ + out_be32(&hw->desc[1], cmfbi->ad->paddr); + /* move AOI1 to the first */ + else /* AOI1 was closed */ + out_be32(&hw->desc[1], + machine_data->dummy_ad->paddr); + /* close AOI 0 */ + break; + case 3: /* plane 2 AOI 0 */ + cmfbi = machine_data->fsl_diu_info[4]->par; + if (cmfbi->count > 0) /* AOI1 is open */ + out_be32(&hw->desc[2], cmfbi->ad->paddr); + /* move AOI1 to the first */ + else /* AOI1 was closed */ + out_be32(&hw->desc[2], + machine_data->dummy_ad->paddr); + /* close AOI 0 */ + break; + case 2: /* plane 1 AOI 1 */ + pmfbi = machine_data->fsl_diu_info[1]->par; + if (hw->desc[1] != ad->paddr) { + /* AOI1 is not the first in the chain */ + if (pmfbi->count > 0) + /* AOI0 is open, must be the first */ + pmfbi->ad->next_ad = 0; + } else /* AOI1 is the first in the chain */ + out_be32(&hw->desc[1], machine_data->dummy_ad->paddr); + /* close AOI 1 */ + break; + case 4: /* plane 2 AOI 1 */ + pmfbi = machine_data->fsl_diu_info[3]->par; + if (hw->desc[2] != ad->paddr) { + /* AOI1 is not the first in the chain */ + if (pmfbi->count > 0) + /* AOI0 is open, must be the first */ + pmfbi->ad->next_ad = 0; + } else /* AOI1 is the first in the chain */ + out_be32(&hw->desc[2], machine_data->dummy_ad->paddr); + /* close AOI 1 */ + break; + default: + res = -EINVAL; + break; + } + + return res; +} + +static void enable_lcdc(struct fb_info *info) +{ + struct diu *hw = dr.diu_reg; + struct mfb_info *mfbi = info->par; + struct fsl_diu_data *machine_data = mfbi->parent; + + if (!machine_data->fb_enabled) { + out_be32(&hw->diu_mode, dr.mode); + machine_data->fb_enabled++; + } +} + +static void disable_lcdc(struct fb_info *info) +{ + struct diu *hw = dr.diu_reg; + struct mfb_info *mfbi = info->par; + struct fsl_diu_data *machine_data = mfbi->parent; + + if (machine_data->fb_enabled) { + out_be32(&hw->diu_mode, 0); + machine_data->fb_enabled = 0; + } +} + +static void adjust_aoi_size_position(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + struct mfb_info *lower_aoi_mfbi, *upper_aoi_mfbi, *mfbi = info->par; + struct fsl_diu_data *machine_data = mfbi->parent; + int available_height, upper_aoi_bottom, index = mfbi->index; + int lower_aoi_is_open, upper_aoi_is_open; + __u32 base_plane_width, base_plane_height, upper_aoi_height; + + base_plane_width = machine_data->fsl_diu_info[0]->var.xres; + base_plane_height = machine_data->fsl_diu_info[0]->var.yres; + + switch (index) { + case 0: + if (mfbi->x_aoi_d != 0) + mfbi->x_aoi_d = 0; + if (mfbi->y_aoi_d != 0) + mfbi->y_aoi_d = 0; + break; + case 1: /* AOI 0 */ + case 3: + lower_aoi_mfbi = machine_data->fsl_diu_info[index+1]->par; + lower_aoi_is_open = lower_aoi_mfbi->count > 0 ? 1 : 0; + if (var->xres > base_plane_width) + var->xres = base_plane_width; + if ((mfbi->x_aoi_d + var->xres) > base_plane_width) + mfbi->x_aoi_d = base_plane_width - var->xres; + + if (lower_aoi_is_open) + available_height = lower_aoi_mfbi->y_aoi_d; + else + available_height = base_plane_height; + if (var->yres > available_height) + var->yres = available_height; + if ((mfbi->y_aoi_d + var->yres) > available_height) + mfbi->y_aoi_d = available_height - var->yres; + break; + case 2: /* AOI 1 */ + case 4: + upper_aoi_mfbi = machine_data->fsl_diu_info[index-1]->par; + upper_aoi_height = + machine_data->fsl_diu_info[index-1]->var.yres; + upper_aoi_bottom = upper_aoi_mfbi->y_aoi_d + upper_aoi_height; + upper_aoi_is_open = upper_aoi_mfbi->count > 0 ? 1 : 0; + if (var->xres > base_plane_width) + var->xres = base_plane_width; + if ((mfbi->x_aoi_d + var->xres) > base_plane_width) + mfbi->x_aoi_d = base_plane_width - var->xres; + if (mfbi->y_aoi_d < 0) + mfbi->y_aoi_d = 0; + if (upper_aoi_is_open) { + if (mfbi->y_aoi_d < upper_aoi_bottom) + mfbi->y_aoi_d = upper_aoi_bottom; + available_height = base_plane_height + - upper_aoi_bottom; + } else + available_height = base_plane_height; + if (var->yres > available_height) + var->yres = available_height; + if ((mfbi->y_aoi_d + var->yres) > base_plane_height) + mfbi->y_aoi_d = base_plane_height - var->yres; + break; + } +} +/* + * Checks to see if the hardware supports the state requested by var passed + * in. This function does not alter the hardware state! If the var passed in + * is slightly off by what the hardware can support then we alter the var + * PASSED in to what we can do. If the hardware doesn't support mode change + * a -EINVAL will be returned by the upper layers. + */ +static int fsl_diu_check_var(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + unsigned long htotal, vtotal; + + pr_debug("check_var xres: %d\n", var->xres); + pr_debug("check_var yres: %d\n", var->yres); + + if (var->xres_virtual < var->xres) + var->xres_virtual = var->xres; + if (var->yres_virtual < var->yres) + var->yres_virtual = var->yres; + + if (var->xoffset < 0) + var->xoffset = 0; + + if (var->yoffset < 0) + var->yoffset = 0; + + if (var->xoffset + info->var.xres > info->var.xres_virtual) + var->xoffset = info->var.xres_virtual - info->var.xres; + + if (var->yoffset + info->var.yres > info->var.yres_virtual) + var->yoffset = info->var.yres_virtual - info->var.yres; + + if ((var->bits_per_pixel != 32) && (var->bits_per_pixel != 24) && + (var->bits_per_pixel != 16)) + var->bits_per_pixel = default_bpp; + + switch (var->bits_per_pixel) { + case 16: + var->red.length = 5; + var->red.offset = 11; + var->red.msb_right = 0; + + var->green.length = 6; + var->green.offset = 5; + var->green.msb_right = 0; + + var->blue.length = 5; + var->blue.offset = 0; + var->blue.msb_right = 0; + + var->transp.length = 0; + var->transp.offset = 0; + var->transp.msb_right = 0; + break; + case 24: + var->red.length = 8; + var->red.offset = 0; + var->red.msb_right = 0; + + var->green.length = 8; + var->green.offset = 8; + var->green.msb_right = 0; + + var->blue.length = 8; + var->blue.offset = 16; + var->blue.msb_right = 0; + + var->transp.length = 0; + var->transp.offset = 0; + var->transp.msb_right = 0; + break; + case 32: + var->red.length = 8; + var->red.offset = 16; + var->red.msb_right = 0; + + var->green.length = 8; + var->green.offset = 8; + var->green.msb_right = 0; + + var->blue.length = 8; + var->blue.offset = 0; + var->blue.msb_right = 0; + + var->transp.length = 8; + var->transp.offset = 24; + var->transp.msb_right = 0; + + break; + } + /* If the pixclock is below the minimum spec'd value then set to + * refresh rate for 60Hz since this is supported by most monitors. + * Refer to Documentation/fb/ for calculations. + */ + if ((var->pixclock < MIN_PIX_CLK) || (var->pixclock > MAX_PIX_CLK)) { + htotal = var->xres + var->right_margin + var->hsync_len + + var->left_margin; + vtotal = var->yres + var->lower_margin + var->vsync_len + + var->upper_margin; + var->pixclock = (vtotal * htotal * 6UL) / 100UL; + var->pixclock = KHZ2PICOS(var->pixclock); + pr_debug("pixclock set for 60Hz refresh = %u ps\n", + var->pixclock); + } + + var->height = -1; + var->width = -1; + var->grayscale = 0; + + /* Copy nonstd field to/from sync for fbset usage */ + var->sync |= var->nonstd; + var->nonstd |= var->sync; + + adjust_aoi_size_position(var, info); + return 0; +} + +static void set_fix(struct fb_info *info) +{ + struct fb_fix_screeninfo *fix = &info->fix; + struct fb_var_screeninfo *var = &info->var; + struct mfb_info *mfbi = info->par; + + strncpy(fix->id, mfbi->id, strlen(mfbi->id)); + fix->line_length = var->xres_virtual * var->bits_per_pixel / 8; + fix->type = FB_TYPE_PACKED_PIXELS; + fix->accel = FB_ACCEL_NONE; + fix->visual = FB_VISUAL_TRUECOLOR; + fix->xpanstep = 1; + fix->ypanstep = 1; +} + +static void update_lcdc(struct fb_info *info) +{ + struct fb_var_screeninfo *var = &info->var; + struct mfb_info *mfbi = info->par; + struct fsl_diu_data *machine_data = mfbi->parent; + struct diu *hw; + int i, j; + char __iomem *cursor_base, *gamma_table_base; + + u32 temp; + + hw = dr.diu_reg; + + if (mfbi->type == MFB_TYPE_OFF) { + fsl_diu_disable_panel(info); + return; + } + + diu_ops.set_monitor_port(machine_data->monitor_port); + gamma_table_base = pool.gamma.vaddr; + cursor_base = pool.cursor.vaddr; + /* Prep for DIU init - gamma table, cursor table */ + + for (i = 0; i <= 2; i++) + for (j = 0; j <= 255; j++) + *gamma_table_base++ = j; + + diu_ops.set_gamma_table(machine_data->monitor_port, pool.gamma.vaddr); + + pr_debug("update-lcdc: HW - %p\n Disabling DIU\n", hw); + disable_lcdc(info); + + /* Program DIU registers */ + + out_be32(&hw->gamma, pool.gamma.paddr); + out_be32(&hw->cursor, pool.cursor.paddr); + + out_be32(&hw->bgnd, 0x007F7F7F); /* BGND */ + out_be32(&hw->bgnd_wb, 0); /* BGND_WB */ + out_be32(&hw->disp_size, (var->yres << 16 | var->xres)); + /* DISP SIZE */ + pr_debug("DIU xres: %d\n", var->xres); + pr_debug("DIU yres: %d\n", var->yres); + + out_be32(&hw->wb_size, 0); /* WB SIZE */ + out_be32(&hw->wb_mem_addr, 0); /* WB MEM ADDR */ + + /* Horizontal and vertical configuration register */ + temp = var->left_margin << 22 | /* BP_H */ + var->hsync_len << 11 | /* PW_H */ + var->right_margin; /* FP_H */ + + out_be32(&hw->hsyn_para, temp); + + temp = var->upper_margin << 22 | /* BP_V */ + var->vsync_len << 11 | /* PW_V */ + var->lower_margin; /* FP_V */ + + out_be32(&hw->vsyn_para, temp); + + pr_debug("DIU right_margin - %d\n", var->right_margin); + pr_debug("DIU left_margin - %d\n", var->left_margin); + pr_debug("DIU hsync_len - %d\n", var->hsync_len); + pr_debug("DIU upper_margin - %d\n", var->upper_margin); + pr_debug("DIU lower_margin - %d\n", var->lower_margin); + pr_debug("DIU vsync_len - %d\n", var->vsync_len); + pr_debug("DIU HSYNC - 0x%08x\n", hw->hsyn_para); + pr_debug("DIU VSYNC - 0x%08x\n", hw->vsyn_para); + + diu_ops.set_pixel_clock(var->pixclock); + + out_be32(&hw->syn_pol, 0); /* SYNC SIGNALS POLARITY */ + out_be32(&hw->thresholds, 0x00037800); /* The Thresholds */ + out_be32(&hw->int_status, 0); /* INTERRUPT STATUS */ + out_be32(&hw->plut, 0x01F5F666); + + /* Enable the DIU */ + enable_lcdc(info); +} + +static int map_video_memory(struct fb_info *info) +{ + phys_addr_t phys; + + pr_debug("info->var.xres_virtual = %d\n", info->var.xres_virtual); + pr_debug("info->var.yres_virtual = %d\n", info->var.yres_virtual); + pr_debug("info->fix.line_length = %d\n", info->fix.line_length); + + info->fix.smem_len = info->fix.line_length * info->var.yres_virtual; + pr_debug("MAP_VIDEO_MEMORY: smem_len = %d\n", info->fix.smem_len); + info->screen_base = fsl_diu_alloc(info->fix.smem_len, &phys); + if (info->screen_base == 0) { + printk(KERN_ERR "Unable to allocate fb memory\n"); + return -ENOMEM; + } + info->fix.smem_start = (unsigned long) phys; + info->screen_size = info->fix.smem_len; + + pr_debug("Allocated fb @ paddr=0x%08lx, size=%d.\n", + info->fix.smem_start, + info->fix.smem_len); + pr_debug("screen base %p\n", info->screen_base); + + return 0; +} + +static void unmap_video_memory(struct fb_info *info) +{ + fsl_diu_free(info->screen_base, info->fix.smem_len); + info->screen_base = 0; + info->fix.smem_start = 0; + info->fix.smem_len = 0; +} + +/* + * Using the fb_var_screeninfo in fb_info we set the resolution of this + * particular framebuffer. This function alters the fb_fix_screeninfo stored + * in fb_info. It does not alter var in fb_info since we are using that + * data. This means we depend on the data in var inside fb_info to be + * supported by the hardware. fsl_diu_check_var is always called before + * fsl_diu_set_par to ensure this. + */ +static int fsl_diu_set_par(struct fb_info *info) +{ + unsigned long len; + struct fb_var_screeninfo *var = &info->var; + struct mfb_info *mfbi = info->par; + struct fsl_diu_data *machine_data = mfbi->parent; + struct diu_ad *ad = mfbi->ad; + struct diu *hw; + + hw = dr.diu_reg; + + set_fix(info); + mfbi->cursor_reset = 1; + + len = info->var.yres_virtual * info->fix.line_length; + /* Alloc & dealloc each time resolution/bpp change */ + if (len != info->fix.smem_len) { + if (info->fix.smem_start) + unmap_video_memory(info); + pr_debug("SET PAR: smem_len = %d\n", info->fix.smem_len); + + /* Memory allocation for framebuffer */ + if (map_video_memory(info)) { + printk(KERN_ERR "Unable to allocate fb memory 1\n"); + return -ENOMEM; + } + } + + ad->pix_fmt = + diu_ops.get_pixel_format(var->bits_per_pixel, + machine_data->monitor_port); + ad->addr = cpu_to_le32(info->fix.smem_start); + ad->src_size_g_alpha = cpu_to_le32((var->yres << 12) | + var->xres) | mfbi->g_alpha; + /* fix me. AOI should not be greater than display size */ + ad->aoi_size = cpu_to_le32((var->yres << 16) | var->xres); + ad->offset_xyi = 0; + ad->offset_xyd = cpu_to_le32((mfbi->y_aoi_d << 16) | mfbi->x_aoi_d); + + /* Disable chroma keying function */ + ad->ckmax_r = 0; + ad->ckmax_g = 0; + ad->ckmax_b = 0; + + ad->ckmin_r = 255; + ad->ckmin_g = 255; + ad->ckmin_b = 255; + + if (mfbi->index == 0) + update_lcdc(info); + return 0; +} + +static inline __u32 CNVT_TOHW(__u32 val, __u32 width) +{ + return ((val<<width) + 0x7FFF - val)>>16; +} + +/* + * Set a single color register. The values supplied have a 16 bit magnitude + * which needs to be scaled in this function for the hardware. Things to take + * into consideration are how many color registers, if any, are supported with + * the current color visual. With truecolor mode no color palettes are + * supported. Here a psuedo palette is created which we store the value in + * pseudo_palette in struct fb_info. For pseudocolor mode we have a limited + * color palette. + */ +static int fsl_diu_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, struct fb_info *info) +{ + int ret = 1; + + /* + * If greyscale is true, then we convert the RGB value + * to greyscale no matter what visual we are using. + */ + if (info->var.grayscale) + red = green = blue = (19595 * red + 38470 * green + + 7471 * blue) >> 16; + switch (info->fix.visual) { + case FB_VISUAL_TRUECOLOR: + /* + * 16-bit True Colour. We encode the RGB value + * according to the RGB bitfield information. + */ + if (regno < 16) { + u32 *pal = info->pseudo_palette; + u32 v; + + red = CNVT_TOHW(red, info->var.red.length); + green = CNVT_TOHW(green, info->var.green.length); + blue = CNVT_TOHW(blue, info->var.blue.length); + transp = CNVT_TOHW(transp, info->var.transp.length); + + v = (red << info->var.red.offset) | + (green << info->var.green.offset) | + (blue << info->var.blue.offset) | + (transp << info->var.transp.offset); + + pal[regno] = v; + ret = 0; + } + break; + case FB_VISUAL_STATIC_PSEUDOCOLOR: + case FB_VISUAL_PSEUDOCOLOR: + break; + } + + return ret; +} + +/* + * Pan (or wrap, depending on the `vmode' field) the display using the + * 'xoffset' and 'yoffset' fields of the 'var' structure. If the values + * don't fit, return -EINVAL. + */ +static int fsl_diu_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + if ((info->var.xoffset == var->xoffset) && + (info->var.yoffset == var->yoffset)) + return 0; /* No change, do nothing */ + + if (var->xoffset < 0 || var->yoffset < 0 + || var->xoffset + info->var.xres > info->var.xres_virtual + || var->yoffset + info->var.yres > info->var.yres_virtual) + return -EINVAL; + + info->var.xoffset = var->xoffset; + info->var.yoffset = var->yoffset; + + if (var->vmode & FB_VMODE_YWRAP) + info->var.vmode |= FB_VMODE_YWRAP; + else + info->var.vmode &= ~FB_VMODE_YWRAP; + + return 0; +} + +/* + * Blank the screen if blank_mode != 0, else unblank. Return 0 if blanking + * succeeded, != 0 if un-/blanking failed. + * blank_mode == 2: suspend vsync + * blank_mode == 3: suspend hsync + * blank_mode == 4: powerdown + */ +static int fsl_diu_blank(int blank_mode, struct fb_info *info) +{ + struct mfb_info *mfbi = info->par; + + mfbi->blank = blank_mode; + + switch (blank_mode) { + case FB_BLANK_VSYNC_SUSPEND: + case FB_BLANK_HSYNC_SUSPEND: + /* FIXME: fixes to enable_panel and enable lcdc needed */ + case FB_BLANK_NORMAL: + /* fsl_diu_disable_panel(info);*/ + break; + case FB_BLANK_POWERDOWN: + /* disable_lcdc(info); */ + break; + case FB_BLANK_UNBLANK: + /* fsl_diu_enable_panel(info);*/ + break; + } + + return 0; +} + +static int fsl_diu_ioctl(struct fb_info *info, unsigned int cmd, + unsigned long arg) +{ + struct mfb_info *mfbi = info->par; + struct diu_ad *ad = mfbi->ad; + struct mfb_chroma_key ck; + unsigned char global_alpha; + struct aoi_display_offset aoi_d; + __u32 pix_fmt; + void __user *buf = (void __user *)arg; + + if (!arg) + return -EINVAL; + switch (cmd) { + case MFB_SET_PIXFMT: + if (copy_from_user(&pix_fmt, buf, sizeof(pix_fmt))) + return -EFAULT; + ad->pix_fmt = pix_fmt; + pr_debug("Set pixel format to 0x%08x\n", ad->pix_fmt); + break; + case MFB_GET_PIXFMT: + pix_fmt = ad->pix_fmt; + if (copy_to_user(buf, &pix_fmt, sizeof(pix_fmt))) + return -EFAULT; + pr_debug("get pixel format 0x%08x\n", ad->pix_fmt); + break; + case MFB_SET_AOID: + if (copy_from_user(&aoi_d, buf, sizeof(aoi_d))) + return -EFAULT; + mfbi->x_aoi_d = aoi_d.x_aoi_d; + mfbi->y_aoi_d = aoi_d.y_aoi_d; + pr_debug("set AOI display offset of index %d to (%d,%d)\n", + mfbi->index, aoi_d.x_aoi_d, aoi_d.y_aoi_d); + fsl_diu_check_var(&info->var, info); + fsl_diu_set_par(info); + break; + case MFB_GET_AOID: + aoi_d.x_aoi_d = mfbi->x_aoi_d; + aoi_d.y_aoi_d = mfbi->y_aoi_d; + if (copy_to_user(buf, &aoi_d, sizeof(aoi_d))) + return -EFAULT; + pr_debug("get AOI display offset of index %d (%d,%d)\n", + mfbi->index, aoi_d.x_aoi_d, aoi_d.y_aoi_d); + break; + case MFB_GET_ALPHA: + global_alpha = mfbi->g_alpha; + if (copy_to_user(buf, &global_alpha, sizeof(global_alpha))) + return -EFAULT; + pr_debug("get global alpha of index %d\n", mfbi->index); + break; + case MFB_SET_ALPHA: + /* set panel information */ + if (copy_from_user(&global_alpha, buf, sizeof(global_alpha))) + return -EFAULT; + ad->src_size_g_alpha = (ad->src_size_g_alpha & (~0xff)) | + (global_alpha & 0xff); + mfbi->g_alpha = global_alpha; + pr_debug("set global alpha for index %d\n", mfbi->index); + break; + case MFB_SET_CHROMA_KEY: + /* set panel winformation */ + if (copy_from_user(&ck, buf, sizeof(ck))) + return -EFAULT; + + if (ck.enable && + (ck.red_max < ck.red_min || + ck.green_max < ck.green_min || + ck.blue_max < ck.blue_min)) + return -EINVAL; + + if (!ck.enable) { + ad->ckmax_r = 0; + ad->ckmax_g = 0; + ad->ckmax_b = 0; + ad->ckmin_r = 255; + ad->ckmin_g = 255; + ad->ckmin_b = 255; + } else { + ad->ckmax_r = ck.red_max; + ad->ckmax_g = ck.green_max; + ad->ckmax_b = ck.blue_max; + ad->ckmin_r = ck.red_min; + ad->ckmin_g = ck.green_min; + ad->ckmin_b = ck.blue_min; + } + pr_debug("set chroma key\n"); + break; + case FBIOGET_GWINFO: + if (mfbi->type == MFB_TYPE_OFF) + return -ENODEV; + /* get graphic window information */ + if (copy_to_user(buf, ad, sizeof(*ad))) + return -EFAULT; + break; + case FBIOGET_HWCINFO: + pr_debug("FBIOGET_HWCINFO:0x%08x\n", FBIOGET_HWCINFO); + break; + case FBIOPUT_MODEINFO: + pr_debug("FBIOPUT_MODEINFO:0x%08x\n", FBIOPUT_MODEINFO); + break; + case FBIOGET_DISPINFO: + pr_debug("FBIOGET_DISPINFO:0x%08x\n", FBIOGET_DISPINFO); + break; + + default: + printk(KERN_ERR "Unknown ioctl command (0x%08X)\n", cmd); + return -ENOIOCTLCMD; + } + + return 0; +} + +/* turn on fb if count == 1 + */ +static int fsl_diu_open(struct fb_info *info, int user) +{ + struct mfb_info *mfbi = info->par; + int res = 0; + + spin_lock(&diu_lock); + mfbi->count++; + if (mfbi->count == 1) { + pr_debug("open plane index %d\n", mfbi->index); + fsl_diu_check_var(&info->var, info); + res = fsl_diu_set_par(info); + if (res < 0) + mfbi->count--; + else { + res = fsl_diu_enable_panel(info); + if (res < 0) + mfbi->count--; + } + } + + spin_unlock(&diu_lock); + return res; +} + +/* turn off fb if count == 0 + */ +static int fsl_diu_release(struct fb_info *info, int user) +{ + struct mfb_info *mfbi = info->par; + int res = 0; + + spin_lock(&diu_lock); + mfbi->count--; + if (mfbi->count == 0) { + pr_debug("release plane index %d\n", mfbi->index); + res = fsl_diu_disable_panel(info); + if (res < 0) + mfbi->count++; + } + spin_unlock(&diu_lock); + return res; +} + +static struct fb_ops fsl_diu_ops = { + .owner = THIS_MODULE, + .fb_check_var = fsl_diu_check_var, + .fb_set_par = fsl_diu_set_par, + .fb_setcolreg = fsl_diu_setcolreg, + .fb_blank = fsl_diu_blank, + .fb_pan_display = fsl_diu_pan_display, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_ioctl = fsl_diu_ioctl, + .fb_open = fsl_diu_open, + .fb_release = fsl_diu_release, +}; + +static int init_fbinfo(struct fb_info *info) +{ + struct mfb_info *mfbi = info->par; + + info->device = NULL; + info->var.activate = FB_ACTIVATE_NOW; + info->fbops = &fsl_diu_ops; + info->flags = FBINFO_FLAG_DEFAULT; + info->pseudo_palette = &mfbi->pseudo_palette; + + /* Allocate colormap */ + fb_alloc_cmap(&info->cmap, 16, 0); + return 0; +} + +static int install_fb(struct fb_info *info) +{ + int rc; + struct mfb_info *mfbi = info->par; + const char *aoi_mode, *init_aoi_mode = "320x240"; + + if (init_fbinfo(info)) + return -EINVAL; + + if (mfbi->index == 0) /* plane 0 */ + aoi_mode = fb_mode; + else + aoi_mode = init_aoi_mode; + pr_debug("mode used = %s\n", aoi_mode); + rc = fb_find_mode(&info->var, info, aoi_mode, fsl_diu_mode_db, + ARRAY_SIZE(fsl_diu_mode_db), &fsl_diu_default_mode, default_bpp); + + switch (rc) { + case 1: + pr_debug("using mode specified in @mode\n"); + break; + case 2: + pr_debug("using mode specified in @mode " + "with ignored refresh rate\n"); + break; + case 3: + pr_debug("using mode default mode\n"); + break; + case 4: + pr_debug("using mode from list\n"); + break; + default: + pr_debug("rc = %d\n", rc); + pr_debug("failed to find mode\n"); + return -EINVAL; + break; + } + + pr_debug("xres_virtual %d\n", info->var.xres_virtual); + pr_debug("bits_per_pixel %d\n", info->var.bits_per_pixel); + + pr_debug("info->var.yres_virtual = %d\n", info->var.yres_virtual); + pr_debug("info->fix.line_length = %d\n", info->fix.line_length); + + if (mfbi->type == MFB_TYPE_OFF) + mfbi->blank = FB_BLANK_NORMAL; + else + mfbi->blank = FB_BLANK_UNBLANK; + + if (fsl_diu_check_var(&info->var, info)) { + printk(KERN_ERR "fb_check_var failed"); + fb_dealloc_cmap(&info->cmap); + return -EINVAL; + } + + if (fsl_diu_set_par(info)) { + printk(KERN_ERR "fb_set_par failed"); + fb_dealloc_cmap(&info->cmap); + return -EINVAL; + } + + if (register_framebuffer(info) < 0) { + printk(KERN_ERR "register_framebuffer failed"); + unmap_video_memory(info); + fb_dealloc_cmap(&info->cmap); + return -EINVAL; + } + + mfbi->registered = 1; + printk(KERN_INFO "fb%d: %s fb device registered successfully.\n", + info->node, info->fix.id); + + return 0; +} + +static void __exit uninstall_fb(struct fb_info *info) +{ + struct mfb_info *mfbi = info->par; + + if (!mfbi->registered) + return; + + unregister_framebuffer(info); + unmap_video_memory(info); + if (&info->cmap) + fb_dealloc_cmap(&info->cmap); + + mfbi->registered = 0; +} + +static irqreturn_t fsl_diu_isr(int irq, void *dev_id) +{ + struct diu *hw = dr.diu_reg; + unsigned int status = in_be32(&hw->int_status); + + if (status) { + /* This is the workaround for underrun */ + if (status & INT_UNDRUN) { + out_be32(&hw->diu_mode, 0); + pr_debug("Err: DIU occurs underrun!\n"); + udelay(1); + out_be32(&hw->diu_mode, 1); + } +#if defined(CONFIG_NOT_COHERENT_CACHE) + else if (status & INT_VSYNC) { + unsigned int i; + for (i = 0; i < coherence_data_size; + i += d_cache_line_size) + __asm__ __volatile__ ( + "dcbz 0, %[input]" + ::[input]"r"(&coherence_data[i])); + } +#endif + return IRQ_HANDLED; + } + return IRQ_NONE; +} + +static int request_irq_local(int irq) +{ + unsigned long status, ints; + struct diu *hw; + int ret; + + hw = dr.diu_reg; + + /* Read to clear the status */ + status = in_be32(&hw->int_status); + + ret = request_irq(irq, fsl_diu_isr, 0, "diu", 0); + if (ret) + pr_info("Request diu IRQ failed.\n"); + else { + ints = INT_PARERR | INT_LS_BF_VS; +#if !defined(CONFIG_NOT_COHERENT_CACHE) + ints |= INT_VSYNC; +#endif + if (dr.mode == MFB_MODE2 || dr.mode == MFB_MODE3) + ints |= INT_VSYNC_WB; + + /* Read to clear the status */ + status = in_be32(&hw->int_status); + out_be32(&hw->int_mask, ints); + } + return ret; +} + +static void free_irq_local(int irq) +{ + struct diu *hw = dr.diu_reg; + + /* Disable all LCDC interrupt */ + out_be32(&hw->int_mask, 0x1f); + + free_irq(irq, 0); +} + +#ifdef CONFIG_PM +/* + * Power management hooks. Note that we won't be called from IRQ context, + * unlike the blank functions above, so we may sleep. + */ +static int fsl_diu_suspend(struct of_device *dev, pm_message_t state) +{ + struct fsl_diu_data *machine_data; + + machine_data = dev_get_drvdata(&ofdev->dev); + disable_lcdc(machine_data->fsl_diu_info[0]); + + return 0; +} + +static int fsl_diu_resume(struct of_device *dev) +{ + struct fsl_diu_data *machine_data; + + machine_data = dev_get_drvdata(&ofdev->dev); + enable_lcdc(machine_data->fsl_diu_info[0]); + + return 0; +} + +#else +#define fsl_diu_suspend NULL +#define fsl_diu_resume NULL +#endif /* CONFIG_PM */ + +/* Align to 64-bit(8-byte), 32-byte, etc. */ +static int allocate_buf(struct diu_addr *buf, u32 size, u32 bytes_align) +{ + u32 offset, ssize; + u32 mask; + dma_addr_t paddr = 0; + + ssize = size + bytes_align; + buf->vaddr = dma_alloc_coherent(0, ssize, &paddr, GFP_DMA | __GFP_ZERO); + if (!buf->vaddr) + return -ENOMEM; + + buf->paddr = (__u32) paddr; + + mask = bytes_align - 1; + offset = (u32)buf->paddr & mask; + if (offset) { + buf->offset = bytes_align - offset; + buf->paddr = (u32)buf->paddr + offset; + } else + buf->offset = 0; + return 0; +} + +static void free_buf(struct diu_addr *buf, u32 size, u32 bytes_align) +{ + dma_free_coherent(0, size + bytes_align, + buf->vaddr, (buf->paddr - buf->offset)); + return; +} + +static ssize_t store_monitor(struct device *device, + struct device_attribute *attr, const char *buf, size_t count) +{ + int old_monitor_port; + unsigned long val; + struct fsl_diu_data *machine_data = + container_of(attr, struct fsl_diu_data, dev_attr); + + if (strict_strtoul(buf, 10, &val)) + return 0; + + old_monitor_port = machine_data->monitor_port; + machine_data->monitor_port = diu_ops.set_sysfs_monitor_port(val); + + if (old_monitor_port != machine_data->monitor_port) { + /* All AOIs need adjust pixel format + * fsl_diu_set_par only change the pixsel format here + * unlikely to fail. */ + fsl_diu_set_par(machine_data->fsl_diu_info[0]); + fsl_diu_set_par(machine_data->fsl_diu_info[1]); + fsl_diu_set_par(machine_data->fsl_diu_info[2]); + fsl_diu_set_par(machine_data->fsl_diu_info[3]); + fsl_diu_set_par(machine_data->fsl_diu_info[4]); + } + return count; +} + +static ssize_t show_monitor(struct device *device, + struct device_attribute *attr, char *buf) +{ + struct fsl_diu_data *machine_data = + container_of(attr, struct fsl_diu_data, dev_attr); + return diu_ops.show_monitor_port(machine_data->monitor_port, buf); +} + +static int fsl_diu_probe(struct of_device *ofdev, + const struct of_device_id *match) +{ + struct device_node *np = ofdev->node; + struct mfb_info *mfbi; + phys_addr_t dummy_ad_addr; + int ret, i, error = 0; + struct resource res; + struct fsl_diu_data *machine_data; + + machine_data = kzalloc(sizeof(struct fsl_diu_data), GFP_KERNEL); + if (!machine_data) + return -ENOMEM; + + for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++) { + machine_data->fsl_diu_info[i] = + framebuffer_alloc(sizeof(struct mfb_info), &ofdev->dev); + if (!machine_data->fsl_diu_info[i]) { + dev_err(&ofdev->dev, "cannot allocate memory\n"); + ret = -ENOMEM; + goto error2; + } + mfbi = machine_data->fsl_diu_info[i]->par; + memcpy(mfbi, &mfb_template[i], sizeof(struct mfb_info)); + mfbi->parent = machine_data; + } + + ret = of_address_to_resource(np, 0, &res); + if (ret) { + dev_err(&ofdev->dev, "could not obtain DIU address\n"); + goto error; + } + if (!res.start) { + dev_err(&ofdev->dev, "invalid DIU address\n"); + goto error; + } + dev_dbg(&ofdev->dev, "%s, res.start: 0x%08x\n", __func__, res.start); + + dr.diu_reg = ioremap(res.start, sizeof(struct diu)); + if (!dr.diu_reg) { + dev_err(&ofdev->dev, "Err: can't map DIU registers!\n"); + ret = -EFAULT; + goto error2; + } + + out_be32(&dr.diu_reg->diu_mode, 0); /* disable DIU anyway*/ + + /* Get the IRQ of the DIU */ + machine_data->irq = irq_of_parse_and_map(np, 0); + + if (!machine_data->irq) { + dev_err(&ofdev->dev, "could not get DIU IRQ\n"); + ret = -EINVAL; + goto error; + } + machine_data->monitor_port = monitor_port; + + /* Area descriptor memory pool aligns to 64-bit boundary */ + if (allocate_buf(&pool.ad, sizeof(struct diu_ad) * FSL_AOI_NUM, 8)) + return -ENOMEM; + + /* Get memory for Gamma Table - 32-byte aligned memory */ + if (allocate_buf(&pool.gamma, 768, 32)) { + ret = -ENOMEM; + goto error; + } + + /* For performance, cursor bitmap buffer aligns to 32-byte boundary */ + if (allocate_buf(&pool.cursor, MAX_CURS * MAX_CURS * 2, 32)) { + ret = -ENOMEM; + goto error; + } + + i = ARRAY_SIZE(machine_data->fsl_diu_info); + machine_data->dummy_ad = (struct diu_ad *) + ((u32)pool.ad.vaddr + pool.ad.offset) + i; + machine_data->dummy_ad->paddr = pool.ad.paddr + + i * sizeof(struct diu_ad); + machine_data->dummy_aoi_virt = fsl_diu_alloc(64, &dummy_ad_addr); + if (!machine_data->dummy_aoi_virt) { + ret = -ENOMEM; + goto error; + } + machine_data->dummy_ad->addr = cpu_to_le32(dummy_ad_addr); + machine_data->dummy_ad->pix_fmt = 0x88882317; + machine_data->dummy_ad->src_size_g_alpha = cpu_to_le32((4 << 12) | 4); + machine_data->dummy_ad->aoi_size = cpu_to_le32((4 << 16) | 2); + machine_data->dummy_ad->offset_xyi = 0; + machine_data->dummy_ad->offset_xyd = 0; + machine_data->dummy_ad->next_ad = 0; + + out_be32(&dr.diu_reg->desc[0], machine_data->dummy_ad->paddr); + out_be32(&dr.diu_reg->desc[1], machine_data->dummy_ad->paddr); + out_be32(&dr.diu_reg->desc[2], machine_data->dummy_ad->paddr); + + for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++) { + machine_data->fsl_diu_info[i]->fix.smem_start = 0; + mfbi = machine_data->fsl_diu_info[i]->par; + mfbi->ad = (struct diu_ad *)((u32)pool.ad.vaddr + + pool.ad.offset) + i; + mfbi->ad->paddr = pool.ad.paddr + i * sizeof(struct diu_ad); + ret = install_fb(machine_data->fsl_diu_info[i]); + if (ret) { + dev_err(&ofdev->dev, + "Failed to register framebuffer %d\n", + i); + goto error; + } + } + + if (request_irq_local(machine_data->irq)) { + dev_err(machine_data->fsl_diu_info[0]->dev, + "could not request irq for diu."); + goto error; + } + + machine_data->dev_attr.attr.name = "monitor"; + machine_data->dev_attr.attr.mode = S_IRUGO|S_IWUSR; + machine_data->dev_attr.show = show_monitor; + machine_data->dev_attr.store = store_monitor; + error = device_create_file(machine_data->fsl_diu_info[0]->dev, + &machine_data->dev_attr); + if (error) { + dev_err(machine_data->fsl_diu_info[0]->dev, + "could not create sysfs %s file\n", + machine_data->dev_attr.attr.name); + } + + dev_set_drvdata(&ofdev->dev, machine_data); + return 0; + +error: + for (i = ARRAY_SIZE(machine_data->fsl_diu_info); + i > 0; i--) + uninstall_fb(machine_data->fsl_diu_info[i - 1]); + if (pool.ad.vaddr) + free_buf(&pool.ad, sizeof(struct diu_ad) * FSL_AOI_NUM, 8); + if (pool.gamma.vaddr) + free_buf(&pool.gamma, 768, 32); + if (pool.cursor.vaddr) + free_buf(&pool.cursor, MAX_CURS * MAX_CURS * 2, 32); + if (machine_data->dummy_aoi_virt) + fsl_diu_free(machine_data->dummy_aoi_virt, 64); + iounmap(dr.diu_reg); + +error2: + for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++) + if (machine_data->fsl_diu_info[i]) + framebuffer_release(machine_data->fsl_diu_info[i]); + kfree(machine_data); + + return ret; +} + + +static int fsl_diu_remove(struct of_device *ofdev) +{ + struct fsl_diu_data *machine_data; + int i; + + machine_data = dev_get_drvdata(&ofdev->dev); + disable_lcdc(machine_data->fsl_diu_info[0]); + free_irq_local(machine_data->irq); + for (i = ARRAY_SIZE(machine_data->fsl_diu_info); i > 0; i--) + uninstall_fb(machine_data->fsl_diu_info[i - 1]); + if (pool.ad.vaddr) + free_buf(&pool.ad, sizeof(struct diu_ad) * FSL_AOI_NUM, 8); + if (pool.gamma.vaddr) + free_buf(&pool.gamma, 768, 32); + if (pool.cursor.vaddr) + free_buf(&pool.cursor, MAX_CURS * MAX_CURS * 2, 32); + if (machine_data->dummy_aoi_virt) + fsl_diu_free(machine_data->dummy_aoi_virt, 64); + iounmap(dr.diu_reg); + for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++) + if (machine_data->fsl_diu_info[i]) + framebuffer_release(machine_data->fsl_diu_info[i]); + kfree(machine_data); + + return 0; +} + +#ifndef MODULE +static int __init fsl_diu_setup(char *options) +{ + char *opt; + unsigned long val; + + if (!options || !*options) + return 0; + + while ((opt = strsep(&options, ",")) != NULL) { + if (!*opt) + continue; + if (!strncmp(opt, "monitor=", 8)) { + if (!strict_strtoul(opt + 8, 10, &val) && (val <= 2)) + monitor_port = val; + } else if (!strncmp(opt, "bpp=", 4)) { + if (!strict_strtoul(opt + 4, 10, &val)) + default_bpp = val; + } else + fb_mode = opt; + } + + return 0; +} +#endif + +static struct of_device_id fsl_diu_match[] = { + { + .compatible = "fsl,diu", + }, + {} +}; +MODULE_DEVICE_TABLE(of, fsl_diu_match); + +static struct of_platform_driver fsl_diu_driver = { + .owner = THIS_MODULE, + .name = "fsl_diu", + .match_table = fsl_diu_match, + .probe = fsl_diu_probe, + .remove = fsl_diu_remove, + .suspend = fsl_diu_suspend, + .resume = fsl_diu_resume, +}; + +static int __init fsl_diu_init(void) +{ +#ifdef CONFIG_NOT_COHERENT_CACHE + struct device_node *np; + const u32 *prop; +#endif + int ret; +#ifndef MODULE + char *option; + + /* + * For kernel boot options (in 'video=xxxfb:<options>' format) + */ + if (fb_get_options("fslfb", &option)) + return -ENODEV; + fsl_diu_setup(option); +#endif + printk(KERN_INFO "Freescale DIU driver\n"); + +#ifdef CONFIG_NOT_COHERENT_CACHE + np = of_find_node_by_type(NULL, "cpu"); + if (!np) { + printk(KERN_ERR "Err: can't find device node 'cpu'\n"); + return -ENODEV; + } + + prop = of_get_property(np, "d-cache-size", NULL); + if (prop == NULL) + return -ENODEV; + + /* Freescale PLRU requires 13/8 times the cache size to do a proper + displacement flush + */ + coherence_data_size = *prop * 13; + coherence_data_size /= 8; + + prop = of_get_property(np, "d-cache-line-size", NULL); + if (prop == NULL) + return -ENODEV; + d_cache_line_size = *prop; + + of_node_put(np); + coherence_data = vmalloc(coherence_data_size); + if (!coherence_data) + return -ENOMEM; +#endif + ret = of_register_platform_driver(&fsl_diu_driver); + if (ret) { + printk(KERN_ERR + "fsl-diu: failed to register platform driver\n"); +#if defined(CONFIG_NOT_COHERENT_CACHE) + vfree(coherence_data); +#endif + iounmap(dr.diu_reg); + } + return ret; +} + +static void __exit fsl_diu_exit(void) +{ + of_unregister_platform_driver(&fsl_diu_driver); +#if defined(CONFIG_NOT_COHERENT_CACHE) + vfree(coherence_data); +#endif +} + +module_init(fsl_diu_init); +module_exit(fsl_diu_exit); + +MODULE_AUTHOR("York Sun <yorksun@freescale.com>"); +MODULE_DESCRIPTION("Freescale DIU framebuffer driver"); +MODULE_LICENSE("GPL"); + +module_param_named(mode, fb_mode, charp, 0); +MODULE_PARM_DESC(mode, + "Specify resolution as \"<xres>x<yres>[-<bpp>][@<refresh>]\" "); +module_param_named(bpp, default_bpp, ulong, 0); +MODULE_PARM_DESC(bpp, "Specify bit-per-pixel if not specified mode"); +module_param_named(monitor, monitor_port, int, 0); +MODULE_PARM_DESC(monitor, + "Specify the monitor port (0, 1 or 2) if supported by the platform"); + diff --git a/drivers/video/fsl-diu-fb.h b/drivers/video/fsl-diu-fb.h new file mode 100644 index 000000000000..fc295d7ea463 --- /dev/null +++ b/drivers/video/fsl-diu-fb.h @@ -0,0 +1,223 @@ +/* + * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved. + * + * Freescale DIU Frame Buffer device driver + * + * Authors: Hongjun Chen <hong-jun.chen@freescale.com> + * Paul Widmer <paul.widmer@freescale.com> + * Srikanth Srinivasan <srikanth.srinivasan@freescale.com> + * York Sun <yorksun@freescale.com> + * + * Based on imxfb.c Copyright (C) 2004 S.Hauer, Pengutronix + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#ifndef __FSL_DIU_FB_H__ +#define __FSL_DIU_FB_H__ + +/* Arbitrary threshold to determine the allocation method + * See mpc8610fb_set_par(), map_video_memory(), and unmap_video_memory() + */ +#define MEM_ALLOC_THRESHOLD (1024*768*4+32) +/* Minimum value that the pixel clock can be set to in pico seconds + * This is determined by platform clock/3 where the minimum platform + * clock is 533MHz. This gives 5629 pico seconds. + */ +#define MIN_PIX_CLK 5629 +#define MAX_PIX_CLK 96096 + +#include <linux/types.h> + +struct mfb_alpha { + int enable; + int alpha; +}; + +struct mfb_chroma_key { + int enable; + __u8 red_max; + __u8 green_max; + __u8 blue_max; + __u8 red_min; + __u8 green_min; + __u8 blue_min; +}; + +struct aoi_display_offset { + int x_aoi_d; + int y_aoi_d; +}; + +#define MFB_SET_CHROMA_KEY _IOW('M', 1, struct mfb_chroma_key) +#define MFB_WAIT_FOR_VSYNC _IOW('F', 0x20, u_int32_t) +#define MFB_SET_BRIGHTNESS _IOW('M', 3, __u8) + +#define MFB_SET_ALPHA 0x80014d00 +#define MFB_GET_ALPHA 0x40014d00 +#define MFB_SET_AOID 0x80084d04 +#define MFB_GET_AOID 0x40084d04 +#define MFB_SET_PIXFMT 0x80014d08 +#define MFB_GET_PIXFMT 0x40014d08 + +#define FBIOGET_GWINFO 0x46E0 +#define FBIOPUT_GWINFO 0x46E1 + +#ifdef __KERNEL__ +#include <linux/spinlock.h> + +/* + * These are the fields of area descriptor(in DDR memory) for every plane + */ +struct diu_ad { + /* Word 0(32-bit) in DDR memory */ +/* __u16 comp; */ +/* __u16 pixel_s:2; */ +/* __u16 pallete:1; */ +/* __u16 red_c:2; */ +/* __u16 green_c:2; */ +/* __u16 blue_c:2; */ +/* __u16 alpha_c:3; */ +/* __u16 byte_f:1; */ +/* __u16 res0:3; */ + + __be32 pix_fmt; /* hard coding pixel format */ + + /* Word 1(32-bit) in DDR memory */ + __le32 addr; + + /* Word 2(32-bit) in DDR memory */ +/* __u32 delta_xs:11; */ +/* __u32 res1:1; */ +/* __u32 delta_ys:11; */ +/* __u32 res2:1; */ +/* __u32 g_alpha:8; */ + __le32 src_size_g_alpha; + + /* Word 3(32-bit) in DDR memory */ +/* __u32 delta_xi:11; */ +/* __u32 res3:5; */ +/* __u32 delta_yi:11; */ +/* __u32 res4:3; */ +/* __u32 flip:2; */ + __le32 aoi_size; + + /* Word 4(32-bit) in DDR memory */ + /*__u32 offset_xi:11; + __u32 res5:5; + __u32 offset_yi:11; + __u32 res6:5; + */ + __le32 offset_xyi; + + /* Word 5(32-bit) in DDR memory */ + /*__u32 offset_xd:11; + __u32 res7:5; + __u32 offset_yd:11; + __u32 res8:5; */ + __le32 offset_xyd; + + + /* Word 6(32-bit) in DDR memory */ + __u8 ckmax_r; + __u8 ckmax_g; + __u8 ckmax_b; + __u8 res9; + + /* Word 7(32-bit) in DDR memory */ + __u8 ckmin_r; + __u8 ckmin_g; + __u8 ckmin_b; + __u8 res10; +/* __u32 res10:8; */ + + /* Word 8(32-bit) in DDR memory */ + __le32 next_ad; + + /* Word 9(32-bit) in DDR memory, just for 64-bit aligned */ + __u32 paddr; +} __attribute__ ((packed)); + +/* DIU register map */ +struct diu { + __be32 desc[3]; + __be32 gamma; + __be32 pallete; + __be32 cursor; + __be32 curs_pos; + __be32 diu_mode; + __be32 bgnd; + __be32 bgnd_wb; + __be32 disp_size; + __be32 wb_size; + __be32 wb_mem_addr; + __be32 hsyn_para; + __be32 vsyn_para; + __be32 syn_pol; + __be32 thresholds; + __be32 int_status; + __be32 int_mask; + __be32 colorbar[8]; + __be32 filling; + __be32 plut; +} __attribute__ ((packed)); + +struct diu_hw { + struct diu *diu_reg; + spinlock_t reg_lock; + + __u32 mode; /* DIU operation mode */ +}; + +struct diu_addr { + __u8 __iomem *vaddr; /* Virtual address */ + dma_addr_t paddr; /* Physical address */ + __u32 offset; +}; + +struct diu_pool { + struct diu_addr ad; + struct diu_addr gamma; + struct diu_addr pallete; + struct diu_addr cursor; +}; + +#define FSL_DIU_BASE_OFFSET 0x2C000 /* Offset of DIU */ +#define INT_LCDC 64 /* DIU interrupt number */ + +#define FSL_AOI_NUM 6 /* 5 AOIs and one dummy AOI */ + /* 1 for plane 0, 2 for plane 1&2 each */ + +/* Minimum X and Y resolutions */ +#define MIN_XRES 64 +#define MIN_YRES 64 + +/* HW cursor parameters */ +#define MAX_CURS 32 + +/* Modes of operation of DIU */ +#define MFB_MODE0 0 /* DIU off */ +#define MFB_MODE1 1 /* All three planes output to display */ +#define MFB_MODE2 2 /* Plane 1 to display, planes 2+3 written back*/ +#define MFB_MODE3 3 /* All three planes written back to memory */ +#define MFB_MODE4 4 /* Color bar generation */ + +/* INT_STATUS/INT_MASK field descriptions */ +#define INT_VSYNC 0x01 /* Vsync interrupt */ +#define INT_VSYNC_WB 0x02 /* Vsync interrupt for write back operation */ +#define INT_UNDRUN 0x04 /* Under run exception interrupt */ +#define INT_PARERR 0x08 /* Display parameters error interrupt */ +#define INT_LS_BF_VS 0x10 /* Lines before vsync. interrupt */ + +/* Panels'operation modes */ +#define MFB_TYPE_OUTPUT 0 /* Panel output to display */ +#define MFB_TYPE_OFF 1 /* Panel off */ +#define MFB_TYPE_WB 2 /* Panel written back to memory */ +#define MFB_TYPE_TEST 3 /* Panel generate color bar */ + +#endif /* __KERNEL__ */ +#endif /* __FSL_DIU_FB_H__ */ diff --git a/drivers/video/geode/Kconfig b/drivers/video/geode/Kconfig index 7608429b3943..c5d8ba4b9fc3 100644 --- a/drivers/video/geode/Kconfig +++ b/drivers/video/geode/Kconfig @@ -38,26 +38,6 @@ config FB_GEODE_GX If unsure, say N. -config FB_GEODE_GX_SET_FBSIZE - bool "Manually specify the Geode GX framebuffer size" - depends on FB_GEODE_GX - default n - ---help--- - If you want to manually specify the size of your GX framebuffer, - say Y here, otherwise say N to dynamically probe it. - - Say N unless you know what you are doing. - -config FB_GEODE_GX_FBSIZE - hex "Size of the GX framebuffer, in bytes" - depends on FB_GEODE_GX_SET_FBSIZE - default "0x1600000" - ---help--- - Specify the size of the GX framebuffer. Normally, you will - want this to be MB aligned. Common values are 0x80000 (8MB) - and 0x1600000 (16MB). Don't change this unless you know what - you are doing - config FB_GEODE_GX1 tristate "AMD Geode GX1 framebuffer support (EXPERIMENTAL)" depends on FB && FB_GEODE && EXPERIMENTAL diff --git a/drivers/video/geode/Makefile b/drivers/video/geode/Makefile index 957304b45fba..5c98da126883 100644 --- a/drivers/video/geode/Makefile +++ b/drivers/video/geode/Makefile @@ -5,5 +5,5 @@ obj-$(CONFIG_FB_GEODE_GX) += gxfb.o obj-$(CONFIG_FB_GEODE_LX) += lxfb.o gx1fb-objs := gx1fb_core.o display_gx1.o video_cs5530.o -gxfb-objs := gxfb_core.o display_gx.o video_gx.o +gxfb-objs := gxfb_core.o display_gx.o video_gx.o suspend_gx.o lxfb-objs := lxfb_core.o lxfb_ops.o diff --git a/drivers/video/geode/display_gx.c b/drivers/video/geode/display_gx.c index 0f16e4bffc6c..e759895bf3d3 100644 --- a/drivers/video/geode/display_gx.c +++ b/drivers/video/geode/display_gx.c @@ -17,31 +17,40 @@ #include <asm/io.h> #include <asm/div64.h> #include <asm/delay.h> +#include <asm/geode.h> -#include "geodefb.h" -#include "display_gx.h" +#include "gxfb.h" -#ifdef CONFIG_FB_GEODE_GX_SET_FBSIZE -unsigned int gx_frame_buffer_size(void) -{ - return CONFIG_FB_GEODE_GX_FBSIZE; -} -#else unsigned int gx_frame_buffer_size(void) { unsigned int val; - /* FB size is reported by a virtual register */ + if (!geode_has_vsa2()) { + uint32_t hi, lo; + + /* The number of pages is (PMAX - PMIN)+1 */ + rdmsr(MSR_GLIU_P2D_RO0, lo, hi); + + /* PMAX */ + val = ((hi & 0xff) << 12) | ((lo & 0xfff00000) >> 20); + /* PMIN */ + val -= (lo & 0x000fffff); + val += 1; + + /* The page size is 4k */ + return (val << 12); + } + + /* FB size can be obtained from the VSA II */ /* Virtual register class = 0x02 */ /* VG_MEM_SIZE(512Kb units) = 0x00 */ - outw(0xFC53, 0xAC1C); - outw(0x0200, 0xAC1C); + outw(VSA_VR_UNLOCK, VSA_VRC_INDEX); + outw(VSA_VR_MEM_SIZE, VSA_VRC_INDEX); - val = (unsigned int)(inw(0xAC1E)) & 0xFFl; + val = (unsigned int)(inw(VSA_VRC_DATA)) & 0xFFl; return (val << 19); } -#endif int gx_line_delta(int xres, int bpp) { @@ -49,75 +58,76 @@ int gx_line_delta(int xres, int bpp) return (xres * (bpp >> 3) + 7) & ~0x7; } -static void gx_set_mode(struct fb_info *info) +void gx_set_mode(struct fb_info *info) { - struct geodefb_par *par = info->par; + struct gxfb_par *par = info->par; u32 gcfg, dcfg; int hactive, hblankstart, hsyncstart, hsyncend, hblankend, htotal; int vactive, vblankstart, vsyncstart, vsyncend, vblankend, vtotal; /* Unlock the display controller registers. */ - readl(par->dc_regs + DC_UNLOCK); - writel(DC_UNLOCK_CODE, par->dc_regs + DC_UNLOCK); + write_dc(par, DC_UNLOCK, DC_UNLOCK_UNLOCK); - gcfg = readl(par->dc_regs + DC_GENERAL_CFG); - dcfg = readl(par->dc_regs + DC_DISPLAY_CFG); + gcfg = read_dc(par, DC_GENERAL_CFG); + dcfg = read_dc(par, DC_DISPLAY_CFG); /* Disable the timing generator. */ - dcfg &= ~(DC_DCFG_TGEN); - writel(dcfg, par->dc_regs + DC_DISPLAY_CFG); + dcfg &= ~DC_DISPLAY_CFG_TGEN; + write_dc(par, DC_DISPLAY_CFG, dcfg); /* Wait for pending memory requests before disabling the FIFO load. */ udelay(100); /* Disable FIFO load and compression. */ - gcfg &= ~(DC_GCFG_DFLE | DC_GCFG_CMPE | DC_GCFG_DECE); - writel(gcfg, par->dc_regs + DC_GENERAL_CFG); + gcfg &= ~(DC_GENERAL_CFG_DFLE | DC_GENERAL_CFG_CMPE | + DC_GENERAL_CFG_DECE); + write_dc(par, DC_GENERAL_CFG, gcfg); /* Setup DCLK and its divisor. */ - par->vid_ops->set_dclk(info); + gx_set_dclk_frequency(info); /* * Setup new mode. */ /* Clear all unused feature bits. */ - gcfg &= DC_GCFG_YUVM | DC_GCFG_VDSE; + gcfg &= DC_GENERAL_CFG_YUVM | DC_GENERAL_CFG_VDSE; dcfg = 0; /* Set FIFO priority (default 6/5) and enable. */ /* FIXME: increase fifo priority for 1280x1024 and higher modes? */ - gcfg |= (6 << DC_GCFG_DFHPEL_POS) | (5 << DC_GCFG_DFHPSL_POS) | DC_GCFG_DFLE; + gcfg |= (6 << DC_GENERAL_CFG_DFHPEL_SHIFT) | + (5 << DC_GENERAL_CFG_DFHPSL_SHIFT) | DC_GENERAL_CFG_DFLE; /* Framebuffer start offset. */ - writel(0, par->dc_regs + DC_FB_ST_OFFSET); + write_dc(par, DC_FB_ST_OFFSET, 0); /* Line delta and line buffer length. */ - writel(info->fix.line_length >> 3, par->dc_regs + DC_GFX_PITCH); - writel(((info->var.xres * info->var.bits_per_pixel/8) >> 3) + 2, - par->dc_regs + DC_LINE_SIZE); + write_dc(par, DC_GFX_PITCH, info->fix.line_length >> 3); + write_dc(par, DC_LINE_SIZE, + ((info->var.xres * info->var.bits_per_pixel/8) >> 3) + 2); /* Enable graphics and video data and unmask address lines. */ - dcfg |= DC_DCFG_GDEN | DC_DCFG_VDEN | DC_DCFG_A20M | DC_DCFG_A18M; + dcfg |= DC_DISPLAY_CFG_GDEN | DC_DISPLAY_CFG_VDEN | + DC_DISPLAY_CFG_A20M | DC_DISPLAY_CFG_A18M; /* Set pixel format. */ switch (info->var.bits_per_pixel) { case 8: - dcfg |= DC_DCFG_DISP_MODE_8BPP; + dcfg |= DC_DISPLAY_CFG_DISP_MODE_8BPP; break; case 16: - dcfg |= DC_DCFG_DISP_MODE_16BPP; - dcfg |= DC_DCFG_16BPP_MODE_565; + dcfg |= DC_DISPLAY_CFG_DISP_MODE_16BPP; break; case 32: - dcfg |= DC_DCFG_DISP_MODE_24BPP; - dcfg |= DC_DCFG_PALB; + dcfg |= DC_DISPLAY_CFG_DISP_MODE_24BPP; + dcfg |= DC_DISPLAY_CFG_PALB; break; } /* Enable timing generator. */ - dcfg |= DC_DCFG_TGEN; + dcfg |= DC_DISPLAY_CFG_TGEN; /* Horizontal and vertical timings. */ hactive = info->var.xres; @@ -134,28 +144,34 @@ static void gx_set_mode(struct fb_info *info) vblankend = vsyncend + info->var.upper_margin; vtotal = vblankend; - writel((hactive - 1) | ((htotal - 1) << 16), par->dc_regs + DC_H_ACTIVE_TIMING); - writel((hblankstart - 1) | ((hblankend - 1) << 16), par->dc_regs + DC_H_BLANK_TIMING); - writel((hsyncstart - 1) | ((hsyncend - 1) << 16), par->dc_regs + DC_H_SYNC_TIMING); + write_dc(par, DC_H_ACTIVE_TIMING, (hactive - 1) | + ((htotal - 1) << 16)); + write_dc(par, DC_H_BLANK_TIMING, (hblankstart - 1) | + ((hblankend - 1) << 16)); + write_dc(par, DC_H_SYNC_TIMING, (hsyncstart - 1) | + ((hsyncend - 1) << 16)); - writel((vactive - 1) | ((vtotal - 1) << 16), par->dc_regs + DC_V_ACTIVE_TIMING); - writel((vblankstart - 1) | ((vblankend - 1) << 16), par->dc_regs + DC_V_BLANK_TIMING); - writel((vsyncstart - 1) | ((vsyncend - 1) << 16), par->dc_regs + DC_V_SYNC_TIMING); + write_dc(par, DC_V_ACTIVE_TIMING, (vactive - 1) | + ((vtotal - 1) << 16)); + write_dc(par, DC_V_BLANK_TIMING, (vblankstart - 1) | + ((vblankend - 1) << 16)); + write_dc(par, DC_V_SYNC_TIMING, (vsyncstart - 1) | + ((vsyncend - 1) << 16)); /* Write final register values. */ - writel(dcfg, par->dc_regs + DC_DISPLAY_CFG); - writel(gcfg, par->dc_regs + DC_GENERAL_CFG); + write_dc(par, DC_DISPLAY_CFG, dcfg); + write_dc(par, DC_GENERAL_CFG, gcfg); - par->vid_ops->configure_display(info); + gx_configure_display(info); /* Relock display controller registers */ - writel(0, par->dc_regs + DC_UNLOCK); + write_dc(par, DC_UNLOCK, DC_UNLOCK_LOCK); } -static void gx_set_hw_palette_reg(struct fb_info *info, unsigned regno, - unsigned red, unsigned green, unsigned blue) +void gx_set_hw_palette_reg(struct fb_info *info, unsigned regno, + unsigned red, unsigned green, unsigned blue) { - struct geodefb_par *par = info->par; + struct gxfb_par *par = info->par; int val; /* Hardware palette is in RGB 8-8-8 format. */ @@ -163,11 +179,6 @@ static void gx_set_hw_palette_reg(struct fb_info *info, unsigned regno, val |= (green) & 0x00ff00; val |= (blue >> 8) & 0x0000ff; - writel(regno, par->dc_regs + DC_PAL_ADDRESS); - writel(val, par->dc_regs + DC_PAL_DATA); + write_dc(par, DC_PAL_ADDRESS, regno); + write_dc(par, DC_PAL_DATA, val); } - -struct geode_dc_ops gx_dc_ops = { - .set_mode = gx_set_mode, - .set_palette_reg = gx_set_hw_palette_reg, -}; diff --git a/drivers/video/geode/display_gx.h b/drivers/video/geode/display_gx.h deleted file mode 100644 index 0af33f329e88..000000000000 --- a/drivers/video/geode/display_gx.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Geode GX display controller - * - * Copyright (C) 2006 Arcom Control Systems Ltd. - * - * 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 __DISPLAY_GX_H__ -#define __DISPLAY_GX_H__ - -unsigned int gx_frame_buffer_size(void); -int gx_line_delta(int xres, int bpp); - -extern struct geode_dc_ops gx_dc_ops; - -/* MSR that tells us if a TFT or CRT is attached */ -#define GLD_MSR_CONFIG 0xC0002001 -#define GLD_MSR_CONFIG_DM_FP 0x40 - -/* Display controller registers */ - -#define DC_UNLOCK 0x00 -# define DC_UNLOCK_CODE 0x00004758 - -#define DC_GENERAL_CFG 0x04 -# define DC_GCFG_DFLE 0x00000001 -# define DC_GCFG_CURE 0x00000002 -# define DC_GCFG_ICNE 0x00000004 -# define DC_GCFG_VIDE 0x00000008 -# define DC_GCFG_CMPE 0x00000020 -# define DC_GCFG_DECE 0x00000040 -# define DC_GCFG_VGAE 0x00000080 -# define DC_GCFG_DFHPSL_MASK 0x00000F00 -# define DC_GCFG_DFHPSL_POS 8 -# define DC_GCFG_DFHPEL_MASK 0x0000F000 -# define DC_GCFG_DFHPEL_POS 12 -# define DC_GCFG_STFM 0x00010000 -# define DC_GCFG_FDTY 0x00020000 -# define DC_GCFG_VGAFT 0x00040000 -# define DC_GCFG_VDSE 0x00080000 -# define DC_GCFG_YUVM 0x00100000 -# define DC_GCFG_VFSL 0x00800000 -# define DC_GCFG_SIGE 0x01000000 -# define DC_GCFG_SGRE 0x02000000 -# define DC_GCFG_SGFR 0x04000000 -# define DC_GCFG_CRC_MODE 0x08000000 -# define DC_GCFG_DIAG 0x10000000 -# define DC_GCFG_CFRW 0x20000000 - -#define DC_DISPLAY_CFG 0x08 -# define DC_DCFG_TGEN 0x00000001 -# define DC_DCFG_GDEN 0x00000008 -# define DC_DCFG_VDEN 0x00000010 -# define DC_DCFG_TRUP 0x00000040 -# define DC_DCFG_DISP_MODE_MASK 0x00000300 -# define DC_DCFG_DISP_MODE_8BPP 0x00000000 -# define DC_DCFG_DISP_MODE_16BPP 0x00000100 -# define DC_DCFG_DISP_MODE_24BPP 0x00000200 -# define DC_DCFG_16BPP_MODE_MASK 0x00000c00 -# define DC_DCFG_16BPP_MODE_565 0x00000000 -# define DC_DCFG_16BPP_MODE_555 0x00000100 -# define DC_DCFG_16BPP_MODE_444 0x00000200 -# define DC_DCFG_DCEN 0x00080000 -# define DC_DCFG_PALB 0x02000000 -# define DC_DCFG_FRLK 0x04000000 -# define DC_DCFG_VISL 0x08000000 -# define DC_DCFG_FRSL 0x20000000 -# define DC_DCFG_A18M 0x40000000 -# define DC_DCFG_A20M 0x80000000 - -#define DC_FB_ST_OFFSET 0x10 - -#define DC_LINE_SIZE 0x30 -# define DC_LINE_SIZE_FB_LINE_SIZE_MASK 0x000007ff -# define DC_LINE_SIZE_FB_LINE_SIZE_POS 0 -# define DC_LINE_SIZE_CB_LINE_SIZE_MASK 0x007f0000 -# define DC_LINE_SIZE_CB_LINE_SIZE_POS 16 -# define DC_LINE_SIZE_VID_LINE_SIZE_MASK 0xff000000 -# define DC_LINE_SIZE_VID_LINE_SIZE_POS 24 - -#define DC_GFX_PITCH 0x34 -# define DC_GFX_PITCH_FB_PITCH_MASK 0x0000ffff -# define DC_GFX_PITCH_FB_PITCH_POS 0 -# define DC_GFX_PITCH_CB_PITCH_MASK 0xffff0000 -# define DC_GFX_PITCH_CB_PITCH_POS 16 - -#define DC_H_ACTIVE_TIMING 0x40 -#define DC_H_BLANK_TIMING 0x44 -#define DC_H_SYNC_TIMING 0x48 -#define DC_V_ACTIVE_TIMING 0x50 -#define DC_V_BLANK_TIMING 0x54 -#define DC_V_SYNC_TIMING 0x58 - -#define DC_PAL_ADDRESS 0x70 -#define DC_PAL_DATA 0x74 - -#define DC_GLIU0_MEM_OFFSET 0x84 -#endif /* !__DISPLAY_GX1_H__ */ diff --git a/drivers/video/geode/gxfb.h b/drivers/video/geode/gxfb.h new file mode 100644 index 000000000000..16a96f8fd8c5 --- /dev/null +++ b/drivers/video/geode/gxfb.h @@ -0,0 +1,358 @@ +/* + * Copyright (C) 2008 Andres Salomon <dilinger@debian.org> + * + * Geode GX2 header information + * + * 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 _GXFB_H_ +#define _GXFB_H_ + +#include <linux/io.h> + +#define GP_REG_COUNT (0x50 / 4) +#define DC_REG_COUNT (0x90 / 4) +#define VP_REG_COUNT (0x138 / 8) +#define FP_REG_COUNT (0x68 / 8) + +#define DC_PAL_COUNT 0x104 + +struct gxfb_par { + int enable_crt; + void __iomem *dc_regs; + void __iomem *vid_regs; + void __iomem *gp_regs; +#ifdef CONFIG_PM + int powered_down; + + /* register state, for power management functionality */ + struct { + uint64_t padsel; + uint64_t dotpll; + } msr; + + uint32_t gp[GP_REG_COUNT]; + uint32_t dc[DC_REG_COUNT]; + uint64_t vp[VP_REG_COUNT]; + uint64_t fp[FP_REG_COUNT]; + + uint32_t pal[DC_PAL_COUNT]; +#endif +}; + +unsigned int gx_frame_buffer_size(void); +int gx_line_delta(int xres, int bpp); +void gx_set_mode(struct fb_info *info); +void gx_set_hw_palette_reg(struct fb_info *info, unsigned regno, + unsigned red, unsigned green, unsigned blue); + +void gx_set_dclk_frequency(struct fb_info *info); +void gx_configure_display(struct fb_info *info); +int gx_blank_display(struct fb_info *info, int blank_mode); + +#ifdef CONFIG_PM +int gx_powerdown(struct fb_info *info); +int gx_powerup(struct fb_info *info); +#endif + + +/* Graphics Processor registers (table 6-23 from the data book) */ +enum gp_registers { + GP_DST_OFFSET = 0, + GP_SRC_OFFSET, + GP_STRIDE, + GP_WID_HEIGHT, + + GP_SRC_COLOR_FG, + GP_SRC_COLOR_BG, + GP_PAT_COLOR_0, + GP_PAT_COLOR_1, + + GP_PAT_COLOR_2, + GP_PAT_COLOR_3, + GP_PAT_COLOR_4, + GP_PAT_COLOR_5, + + GP_PAT_DATA_0, + GP_PAT_DATA_1, + GP_RASTER_MODE, + GP_VECTOR_MODE, + + GP_BLT_MODE, + GP_BLT_STATUS, + GP_HST_SRC, + GP_BASE_OFFSET, /* 0x4c */ +}; + +#define GP_BLT_STATUS_BLT_PENDING (1 << 2) +#define GP_BLT_STATUS_BLT_BUSY (1 << 0) + + +/* Display Controller registers (table 6-38 from the data book) */ +enum dc_registers { + DC_UNLOCK = 0, + DC_GENERAL_CFG, + DC_DISPLAY_CFG, + DC_RSVD_0, + + DC_FB_ST_OFFSET, + DC_CB_ST_OFFSET, + DC_CURS_ST_OFFSET, + DC_ICON_ST_OFFSET, + + DC_VID_Y_ST_OFFSET, + DC_VID_U_ST_OFFSET, + DC_VID_V_ST_OFFSET, + DC_RSVD_1, + + DC_LINE_SIZE, + DC_GFX_PITCH, + DC_VID_YUV_PITCH, + DC_RSVD_2, + + DC_H_ACTIVE_TIMING, + DC_H_BLANK_TIMING, + DC_H_SYNC_TIMING, + DC_RSVD_3, + + DC_V_ACTIVE_TIMING, + DC_V_BLANK_TIMING, + DC_V_SYNC_TIMING, + DC_RSVD_4, + + DC_CURSOR_X, + DC_CURSOR_Y, + DC_ICON_X, + DC_LINE_CNT, + + DC_PAL_ADDRESS, + DC_PAL_DATA, + DC_DFIFO_DIAG, + DC_CFIFO_DIAG, + + DC_VID_DS_DELTA, + DC_GLIU0_MEM_OFFSET, + DC_RSVD_5, + DC_DV_ACC, /* 0x8c */ +}; + +#define DC_UNLOCK_LOCK 0x00000000 +#define DC_UNLOCK_UNLOCK 0x00004758 /* magic value */ + +#define DC_GENERAL_CFG_YUVM (1 << 20) +#define DC_GENERAL_CFG_VDSE (1 << 19) +#define DC_GENERAL_CFG_DFHPEL_SHIFT 12 +#define DC_GENERAL_CFG_DFHPSL_SHIFT 8 +#define DC_GENERAL_CFG_DECE (1 << 6) +#define DC_GENERAL_CFG_CMPE (1 << 5) +#define DC_GENERAL_CFG_VIDE (1 << 3) +#define DC_GENERAL_CFG_ICNE (1 << 2) +#define DC_GENERAL_CFG_CURE (1 << 1) +#define DC_GENERAL_CFG_DFLE (1 << 0) + +#define DC_DISPLAY_CFG_A20M (1 << 31) +#define DC_DISPLAY_CFG_A18M (1 << 30) +#define DC_DISPLAY_CFG_PALB (1 << 25) +#define DC_DISPLAY_CFG_DISP_MODE_24BPP (1 << 9) +#define DC_DISPLAY_CFG_DISP_MODE_16BPP (1 << 8) +#define DC_DISPLAY_CFG_DISP_MODE_8BPP (0) +#define DC_DISPLAY_CFG_VDEN (1 << 4) +#define DC_DISPLAY_CFG_GDEN (1 << 3) +#define DC_DISPLAY_CFG_TGEN (1 << 0) + + +/* + * Video Processor registers (table 6-54). + * There is space for 64 bit values, but we never use more than the + * lower 32 bits. The actual register save/restore code only bothers + * to restore those 32 bits. + */ +enum vp_registers { + VP_VCFG = 0, + VP_DCFG, + + VP_VX, + VP_VY, + + VP_VS, + VP_VCK, + + VP_VCM, + VP_GAR, + + VP_GDR, + VP_RSVD_0, + + VP_MISC, + VP_CCS, + + VP_RSVD_1, + VP_RSVD_2, + + VP_RSVD_3, + VP_VDC, + + VP_VCO, + VP_CRC, + + VP_CRC32, + VP_VDE, + + VP_CCK, + VP_CCM, + + VP_CC1, + VP_CC2, + + VP_A1X, + VP_A1Y, + + VP_A1C, + VP_A1T, + + VP_A2X, + VP_A2Y, + + VP_A2C, + VP_A2T, + + VP_A3X, + VP_A3Y, + + VP_A3C, + VP_A3T, + + VP_VRR, + VP_AWT, + + VP_VTM, /* 0x130 */ +}; + +#define VP_VCFG_VID_EN (1 << 0) + +#define VP_DCFG_DAC_VREF (1 << 26) +#define VP_DCFG_GV_GAM (1 << 21) +#define VP_DCFG_VG_CK (1 << 20) +#define VP_DCFG_CRT_SYNC_SKW_DEFAULT (1 << 16) +#define VP_DCFG_CRT_SYNC_SKW ((1 << 14) | (1 << 15) | (1 << 16)) +#define VP_DCFG_CRT_VSYNC_POL (1 << 9) +#define VP_DCFG_CRT_HSYNC_POL (1 << 8) +#define VP_DCFG_FP_DATA_EN (1 << 7) /* undocumented */ +#define VP_DCFG_FP_PWR_EN (1 << 6) /* undocumented */ +#define VP_DCFG_DAC_BL_EN (1 << 3) +#define VP_DCFG_VSYNC_EN (1 << 2) +#define VP_DCFG_HSYNC_EN (1 << 1) +#define VP_DCFG_CRT_EN (1 << 0) + +#define VP_MISC_GAM_EN (1 << 0) +#define VP_MISC_DACPWRDN (1 << 10) +#define VP_MISC_APWRDN (1 << 11) + + +/* + * Flat Panel registers (table 6-55). + * Also 64 bit registers; see above note about 32-bit handling. + */ + +/* we're actually in the VP register space, starting at address 0x400 */ +#define VP_FP_START 0x400 + +enum fp_registers { + FP_PT1 = 0, + FP_PT2, + + FP_PM, + FP_DFC, + + FP_BLFSR, + FP_RLFSR, + + FP_FMI, + FP_FMD, + + FP_RSVD_0, + FP_DCA, + + FP_DMD, + FP_CRC, + + FP_FBB, /* 0x460 */ +}; + +#define FP_PT1_VSIZE_SHIFT 16 /* undocumented? */ +#define FP_PT1_VSIZE_MASK 0x7FF0000 /* undocumented? */ + +#define FP_PT2_HSP (1 << 22) +#define FP_PT2_VSP (1 << 23) + +#define FP_PM_P (1 << 24) /* panel power on */ +#define FP_PM_PANEL_PWR_UP (1 << 3) /* r/o */ +#define FP_PM_PANEL_PWR_DOWN (1 << 2) /* r/o */ +#define FP_PM_PANEL_OFF (1 << 1) /* r/o */ +#define FP_PM_PANEL_ON (1 << 0) /* r/o */ + +#define FP_DFC_NFI ((1 << 4) | (1 << 5) | (1 << 6)) + + +/* register access functions */ + +static inline uint32_t read_gp(struct gxfb_par *par, int reg) +{ + return readl(par->gp_regs + 4*reg); +} + +static inline void write_gp(struct gxfb_par *par, int reg, uint32_t val) +{ + writel(val, par->gp_regs + 4*reg); +} + +static inline uint32_t read_dc(struct gxfb_par *par, int reg) +{ + return readl(par->dc_regs + 4*reg); +} + +static inline void write_dc(struct gxfb_par *par, int reg, uint32_t val) +{ + writel(val, par->dc_regs + 4*reg); +} + +static inline uint32_t read_vp(struct gxfb_par *par, int reg) +{ + return readl(par->vid_regs + 8*reg); +} + +static inline void write_vp(struct gxfb_par *par, int reg, uint32_t val) +{ + writel(val, par->vid_regs + 8*reg); +} + +static inline uint32_t read_fp(struct gxfb_par *par, int reg) +{ + return readl(par->vid_regs + 8*reg + VP_FP_START); +} + +static inline void write_fp(struct gxfb_par *par, int reg, uint32_t val) +{ + writel(val, par->vid_regs + 8*reg + VP_FP_START); +} + + +/* MSRs are defined in asm/geode.h; their bitfields are here */ + +#define MSR_GLCP_SYS_RSTPLL_DOTPOSTDIV3 (1 << 3) +#define MSR_GLCP_SYS_RSTPLL_DOTPREMULT2 (1 << 2) +#define MSR_GLCP_SYS_RSTPLL_DOTPREDIV2 (1 << 1) + +#define MSR_GLCP_DOTPLL_LOCK (1 << 25) /* r/o */ +#define MSR_GLCP_DOTPLL_BYPASS (1 << 15) +#define MSR_GLCP_DOTPLL_DOTRESET (1 << 0) + +#define MSR_GX_MSR_PADSEL_MASK 0x3FFFFFFF /* undocumented? */ +#define MSR_GX_MSR_PADSEL_TFT 0x1FFFFFFF /* undocumented? */ + +#define MSR_GX_GLD_MSR_CONFIG_FP (1 << 3) + +#endif diff --git a/drivers/video/geode/gxfb_core.c b/drivers/video/geode/gxfb_core.c index cf841efa229a..de2b8f9876a5 100644 --- a/drivers/video/geode/gxfb_core.c +++ b/drivers/video/geode/gxfb_core.c @@ -28,17 +28,20 @@ #include <linux/slab.h> #include <linux/delay.h> #include <linux/fb.h> +#include <linux/console.h> +#include <linux/suspend.h> #include <linux/init.h> #include <linux/pci.h> +#include <asm/geode.h> -#include "geodefb.h" -#include "display_gx.h" -#include "video_gx.h" +#include "gxfb.h" static char *mode_option; +static int vram; +static int vt_switch; /* Modes relevant to the GX (taken from modedb.c) */ -static const struct fb_videomode gx_modedb[] __initdata = { +static struct fb_videomode gx_modedb[] __initdata = { /* 640x480-60 VESA */ { NULL, 60, 640, 480, 39682, 48, 16, 33, 10, 96, 2, 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, @@ -105,6 +108,35 @@ static const struct fb_videomode gx_modedb[] __initdata = { FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, }; +#ifdef CONFIG_OLPC +#include <asm/olpc.h> + +static struct fb_videomode gx_dcon_modedb[] __initdata = { + /* The only mode the DCON has is 1200x900 */ + { NULL, 50, 1200, 900, 17460, 24, 8, 4, 5, 8, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, 0 } +}; + +static void __init get_modedb(struct fb_videomode **modedb, unsigned int *size) +{ + if (olpc_has_dcon()) { + *modedb = (struct fb_videomode *) gx_dcon_modedb; + *size = ARRAY_SIZE(gx_dcon_modedb); + } else { + *modedb = (struct fb_videomode *) gx_modedb; + *size = ARRAY_SIZE(gx_modedb); + } +} + +#else +static void __init get_modedb(struct fb_videomode **modedb, unsigned int *size) +{ + *modedb = (struct fb_videomode *) gx_modedb; + *size = ARRAY_SIZE(gx_modedb); +} +#endif + static int gxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { if (var->xres > 1600 || var->yres > 1200) @@ -139,8 +171,6 @@ static int gxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) static int gxfb_set_par(struct fb_info *info) { - struct geodefb_par *par = info->par; - if (info->var.bits_per_pixel > 8) { info->fix.visual = FB_VISUAL_TRUECOLOR; fb_dealloc_cmap(&info->cmap); @@ -151,7 +181,7 @@ static int gxfb_set_par(struct fb_info *info) info->fix.line_length = gx_line_delta(info->var.xres, info->var.bits_per_pixel); - par->dc_ops->set_mode(info); + gx_set_mode(info); return 0; } @@ -167,8 +197,6 @@ static int gxfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *info) { - struct geodefb_par *par = info->par; - if (info->var.grayscale) { /* grayscale = 0.30*R + 0.59*G + 0.11*B */ red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8; @@ -191,7 +219,7 @@ static int gxfb_setcolreg(unsigned regno, unsigned red, unsigned green, if (regno >= 256) return -EINVAL; - par->dc_ops->set_palette_reg(info, regno, red, green, blue); + gx_set_hw_palette_reg(info, regno, red, green, blue); } return 0; @@ -199,15 +227,12 @@ static int gxfb_setcolreg(unsigned regno, unsigned red, unsigned green, static int gxfb_blank(int blank_mode, struct fb_info *info) { - struct geodefb_par *par = info->par; - - return par->vid_ops->blank_display(info, blank_mode); + return gx_blank_display(info, blank_mode); } static int __init gxfb_map_video_memory(struct fb_info *info, struct pci_dev *dev) { - struct geodefb_par *par = info->par; - int fb_len; + struct gxfb_par *par = info->par; int ret; ret = pci_enable_device(dev); @@ -229,24 +254,31 @@ static int __init gxfb_map_video_memory(struct fb_info *info, struct pci_dev *de if (!par->dc_regs) return -ENOMEM; - ret = pci_request_region(dev, 0, "gxfb (framebuffer)"); + ret = pci_request_region(dev, 1, "gxfb (graphics processor)"); if (ret < 0) return ret; - if ((fb_len = gx_frame_buffer_size()) < 0) + par->gp_regs = ioremap(pci_resource_start(dev, 1), + pci_resource_len(dev, 1)); + + if (!par->gp_regs) return -ENOMEM; + + ret = pci_request_region(dev, 0, "gxfb (framebuffer)"); + if (ret < 0) + return ret; + info->fix.smem_start = pci_resource_start(dev, 0); - info->fix.smem_len = fb_len; + info->fix.smem_len = vram ? vram : gx_frame_buffer_size(); info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len); if (!info->screen_base) return -ENOMEM; - /* Set the 16MB aligned base address of the graphics memory region + /* Set the 16MiB aligned base address of the graphics memory region * in the display controller */ - writel(info->fix.smem_start & 0xFF000000, - par->dc_regs + DC_GLIU0_MEM_OFFSET); + write_dc(par, DC_GLIU0_MEM_OFFSET, info->fix.smem_start & 0xFF000000); - dev_info(&dev->dev, "%d Kibyte of video memory at 0x%lx\n", + dev_info(&dev->dev, "%d KiB of video memory at 0x%lx\n", info->fix.smem_len / 1024, info->fix.smem_start); return 0; @@ -266,11 +298,12 @@ static struct fb_ops gxfb_ops = { static struct fb_info * __init gxfb_init_fbinfo(struct device *dev) { - struct geodefb_par *par; + struct gxfb_par *par; struct fb_info *info; /* Alloc enough space for the pseudo palette. */ - info = framebuffer_alloc(sizeof(struct geodefb_par) + sizeof(u32) * 16, dev); + info = framebuffer_alloc(sizeof(struct gxfb_par) + sizeof(u32) * 16, + dev); if (!info) return NULL; @@ -296,29 +329,64 @@ static struct fb_info * __init gxfb_init_fbinfo(struct device *dev) info->flags = FBINFO_DEFAULT; info->node = -1; - info->pseudo_palette = (void *)par + sizeof(struct geodefb_par); + info->pseudo_palette = (void *)par + sizeof(struct gxfb_par); info->var.grayscale = 0; return info; } +#ifdef CONFIG_PM +static int gxfb_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct fb_info *info = pci_get_drvdata(pdev); + + if (state.event == PM_EVENT_SUSPEND) { + acquire_console_sem(); + gx_powerdown(info); + fb_set_suspend(info, 1); + release_console_sem(); + } + + /* there's no point in setting PCI states; we emulate PCI, so + * we don't end up getting power savings anyways */ + + return 0; +} + +static int gxfb_resume(struct pci_dev *pdev) +{ + struct fb_info *info = pci_get_drvdata(pdev); + int ret; + + acquire_console_sem(); + ret = gx_powerup(info); + if (ret) { + printk(KERN_ERR "gxfb: power up failed!\n"); + return ret; + } + + fb_set_suspend(info, 0); + release_console_sem(); + return 0; +} +#endif + static int __init gxfb_probe(struct pci_dev *pdev, const struct pci_device_id *id) { - struct geodefb_par *par; + struct gxfb_par *par; struct fb_info *info; int ret; unsigned long val; + struct fb_videomode *modedb_ptr; + unsigned int modedb_size; + info = gxfb_init_fbinfo(&pdev->dev); if (!info) return -ENOMEM; par = info->par; - /* GX display controller and GX video device. */ - par->dc_ops = &gx_dc_ops; - par->vid_ops = &gx_vid_ops; - if ((ret = gxfb_map_video_memory(info, pdev)) < 0) { dev_err(&pdev->dev, "failed to map frame buffer or controller registers\n"); goto err; @@ -326,15 +394,16 @@ static int __init gxfb_probe(struct pci_dev *pdev, const struct pci_device_id *i /* Figure out if this is a TFT or CRT part */ - rdmsrl(GLD_MSR_CONFIG, val); + rdmsrl(MSR_GX_GLD_MSR_CONFIG, val); - if ((val & GLD_MSR_CONFIG_DM_FP) == GLD_MSR_CONFIG_DM_FP) + if ((val & MSR_GX_GLD_MSR_CONFIG_FP) == MSR_GX_GLD_MSR_CONFIG_FP) par->enable_crt = 0; else par->enable_crt = 1; + get_modedb(&modedb_ptr, &modedb_size); ret = fb_find_mode(&info->var, info, mode_option, - gx_modedb, ARRAY_SIZE(gx_modedb), NULL, 16); + modedb_ptr, modedb_size, NULL, 16); if (ret == 0 || ret == 4) { dev_err(&pdev->dev, "could not find valid video mode\n"); ret = -EINVAL; @@ -348,6 +417,8 @@ static int __init gxfb_probe(struct pci_dev *pdev, const struct pci_device_id *i gxfb_check_var(&info->var, info); gxfb_set_par(info); + pm_set_vt_switch(vt_switch); + if (register_framebuffer(info) < 0) { ret = -EINVAL; goto err; @@ -369,6 +440,10 @@ static int __init gxfb_probe(struct pci_dev *pdev, const struct pci_device_id *i iounmap(par->dc_regs); pci_release_region(pdev, 2); } + if (par->gp_regs) { + iounmap(par->gp_regs); + pci_release_region(pdev, 1); + } if (info) framebuffer_release(info); @@ -378,7 +453,7 @@ static int __init gxfb_probe(struct pci_dev *pdev, const struct pci_device_id *i static void gxfb_remove(struct pci_dev *pdev) { struct fb_info *info = pci_get_drvdata(pdev); - struct geodefb_par *par = info->par; + struct gxfb_par *par = info->par; unregister_framebuffer(info); @@ -391,15 +466,16 @@ static void gxfb_remove(struct pci_dev *pdev) iounmap(par->dc_regs); pci_release_region(pdev, 2); + iounmap(par->gp_regs); + pci_release_region(pdev, 1); + pci_set_drvdata(pdev, NULL); framebuffer_release(info); } static struct pci_device_id gxfb_id_table[] = { - { PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_GX_VIDEO, - PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16, - 0xff0000, 0 }, + { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_GX_VIDEO) }, { 0, } }; @@ -410,6 +486,10 @@ static struct pci_driver gxfb_driver = { .id_table = gxfb_id_table, .probe = gxfb_probe, .remove = gxfb_remove, +#ifdef CONFIG_PM + .suspend = gxfb_suspend, + .resume = gxfb_resume, +#endif }; #ifndef MODULE @@ -456,5 +536,11 @@ module_exit(gxfb_cleanup); module_param(mode_option, charp, 0); MODULE_PARM_DESC(mode_option, "video mode (<x>x<y>[-<bpp>][@<refr>])"); +module_param(vram, int, 0); +MODULE_PARM_DESC(vram, "video memory size"); + +module_param(vt_switch, int, 0); +MODULE_PARM_DESC(vt_switch, "enable VT switch during suspend/resume"); + MODULE_DESCRIPTION("Framebuffer driver for the AMD Geode GX"); MODULE_LICENSE("GPL"); diff --git a/drivers/video/geode/lxfb.h b/drivers/video/geode/lxfb.h index ca13c48d19b0..3b9416f4ee20 100644 --- a/drivers/video/geode/lxfb.h +++ b/drivers/video/geode/lxfb.h @@ -3,17 +3,46 @@ #include <linux/fb.h> +#define GP_REG_COUNT (0x7c / 4) +#define DC_REG_COUNT (0xf0 / 4) +#define VP_REG_COUNT (0x158 / 8) +#define FP_REG_COUNT (0x60 / 8) + +#define DC_PAL_COUNT 0x104 +#define DC_HFILT_COUNT 0x100 +#define DC_VFILT_COUNT 0x100 +#define VP_COEFF_SIZE 0x1000 + #define OUTPUT_CRT 0x01 #define OUTPUT_PANEL 0x02 struct lxfb_par { int output; - int panel_width; - int panel_height; void __iomem *gp_regs; void __iomem *dc_regs; - void __iomem *df_regs; + void __iomem *vp_regs; +#ifdef CONFIG_PM + int powered_down; + + /* register state, for power mgmt functionality */ + struct { + uint64_t padsel; + uint64_t dotpll; + uint64_t dfglcfg; + uint64_t dcspare; + } msr; + + uint32_t gp[GP_REG_COUNT]; + uint32_t dc[DC_REG_COUNT]; + uint64_t vp[VP_REG_COUNT]; + uint64_t fp[FP_REG_COUNT]; + + uint32_t pal[DC_PAL_COUNT]; + uint32_t hcoeff[DC_HFILT_COUNT * 2]; + uint32_t vcoeff[DC_VFILT_COUNT]; + uint32_t vp_coeff[VP_COEFF_SIZE / 4]; +#endif }; static inline unsigned int lx_get_pitch(unsigned int xres, int bpp) @@ -29,171 +58,383 @@ int lx_blank_display(struct fb_info *, int); void lx_set_palette_reg(struct fb_info *, unsigned int, unsigned int, unsigned int, unsigned int); -/* MSRS */ +#ifdef CONFIG_PM +int lx_powerdown(struct fb_info *info); +int lx_powerup(struct fb_info *info); +#endif + + +/* Graphics Processor registers (table 6-29 from the data book) */ +enum gp_registers { + GP_DST_OFFSET = 0, + GP_SRC_OFFSET, + GP_STRIDE, + GP_WID_HEIGHT, + + GP_SRC_COLOR_FG, + GP_SRC_COLOR_BG, + GP_PAT_COLOR_0, + GP_PAT_COLOR_1, + + GP_PAT_COLOR_2, + GP_PAT_COLOR_3, + GP_PAT_COLOR_4, + GP_PAT_COLOR_5, + + GP_PAT_DATA_0, + GP_PAT_DATA_1, + GP_RASTER_MODE, + GP_VECTOR_MODE, + + GP_BLT_MODE, + GP_BLT_STATUS, + GP_HST_SRC, + GP_BASE_OFFSET, + + GP_CMD_TOP, + GP_CMD_BOT, + GP_CMD_READ, + GP_CMD_WRITE, + + GP_CH3_OFFSET, + GP_CH3_MODE_STR, + GP_CH3_WIDHI, + GP_CH3_HSRC, + + GP_LUT_INDEX, + GP_LUT_DATA, + GP_INT_CNTRL, /* 0x78 */ +}; + +#define GP_BLT_STATUS_CE (1 << 4) /* cmd buf empty */ +#define GP_BLT_STATUS_PB (1 << 0) /* primative busy */ + + +/* Display Controller registers (table 6-47 from the data book) */ +enum dc_registers { + DC_UNLOCK = 0, + DC_GENERAL_CFG, + DC_DISPLAY_CFG, + DC_ARB_CFG, + + DC_FB_ST_OFFSET, + DC_CB_ST_OFFSET, + DC_CURS_ST_OFFSET, + DC_RSVD_0, + + DC_VID_Y_ST_OFFSET, + DC_VID_U_ST_OFFSET, + DC_VID_V_ST_OFFSET, + DC_DV_TOP, + + DC_LINE_SIZE, + DC_GFX_PITCH, + DC_VID_YUV_PITCH, + DC_RSVD_1, + + DC_H_ACTIVE_TIMING, + DC_H_BLANK_TIMING, + DC_H_SYNC_TIMING, + DC_RSVD_2, + + DC_V_ACTIVE_TIMING, + DC_V_BLANK_TIMING, + DC_V_SYNC_TIMING, + DC_FB_ACTIVE, + + DC_CURSOR_X, + DC_CURSOR_Y, + DC_RSVD_3, + DC_LINE_CNT, + + DC_PAL_ADDRESS, + DC_PAL_DATA, + DC_DFIFO_DIAG, + DC_CFIFO_DIAG, + + DC_VID_DS_DELTA, + DC_GLIU0_MEM_OFFSET, + DC_DV_CTL, + DC_DV_ACCESS, + + DC_GFX_SCALE, + DC_IRQ_FILT_CTL, + DC_FILT_COEFF1, + DC_FILT_COEFF2, + + DC_VBI_EVEN_CTL, + DC_VBI_ODD_CTL, + DC_VBI_HOR, + DC_VBI_LN_ODD, + + DC_VBI_LN_EVEN, + DC_VBI_PITCH, + DC_CLR_KEY, + DC_CLR_KEY_MASK, + + DC_CLR_KEY_X, + DC_CLR_KEY_Y, + DC_IRQ, + DC_RSVD_4, + + DC_RSVD_5, + DC_GENLK_CTL, + DC_VID_EVEN_Y_ST_OFFSET, + DC_VID_EVEN_U_ST_OFFSET, + + DC_VID_EVEN_V_ST_OFFSET, + DC_V_ACTIVE_EVEN_TIMING, + DC_V_BLANK_EVEN_TIMING, + DC_V_SYNC_EVEN_TIMING, /* 0xec */ +}; + +#define DC_UNLOCK_LOCK 0x00000000 +#define DC_UNLOCK_UNLOCK 0x00004758 /* magic value */ + +#define DC_GENERAL_CFG_FDTY (1 << 17) +#define DC_GENERAL_CFG_DFHPEL_SHIFT (12) +#define DC_GENERAL_CFG_DFHPSL_SHIFT (8) +#define DC_GENERAL_CFG_VGAE (1 << 7) +#define DC_GENERAL_CFG_DECE (1 << 6) +#define DC_GENERAL_CFG_CMPE (1 << 5) +#define DC_GENERAL_CFG_VIDE (1 << 3) +#define DC_GENERAL_CFG_DFLE (1 << 0) + +#define DC_DISPLAY_CFG_VISL (1 << 27) +#define DC_DISPLAY_CFG_PALB (1 << 25) +#define DC_DISPLAY_CFG_DCEN (1 << 24) +#define DC_DISPLAY_CFG_DISP_MODE_24BPP (1 << 9) +#define DC_DISPLAY_CFG_DISP_MODE_16BPP (1 << 8) +#define DC_DISPLAY_CFG_DISP_MODE_8BPP (0) +#define DC_DISPLAY_CFG_TRUP (1 << 6) +#define DC_DISPLAY_CFG_VDEN (1 << 4) +#define DC_DISPLAY_CFG_GDEN (1 << 3) +#define DC_DISPLAY_CFG_TGEN (1 << 0) + +#define DC_DV_TOP_DV_TOP_EN (1 << 0) + +#define DC_DV_CTL_DV_LINE_SIZE ((1 << 10) | (1 << 11)) +#define DC_DV_CTL_DV_LINE_SIZE_1K (0) +#define DC_DV_CTL_DV_LINE_SIZE_2K (1 << 10) +#define DC_DV_CTL_DV_LINE_SIZE_4K (1 << 11) +#define DC_DV_CTL_DV_LINE_SIZE_8K ((1 << 10) | (1 << 11)) +#define DC_DV_CTL_CLEAR_DV_RAM (1 << 0) + +#define DC_IRQ_FILT_CTL_H_FILT_SEL (1 << 10) + +#define DC_CLR_KEY_CLR_KEY_EN (1 << 24) + +#define DC_IRQ_VIP_VSYNC_IRQ_STATUS (1 << 21) /* undocumented? */ +#define DC_IRQ_STATUS (1 << 20) /* undocumented? */ +#define DC_IRQ_VIP_VSYNC_LOSS_IRQ_MASK (1 << 1) +#define DC_IRQ_MASK (1 << 0) -#define MSR_LX_GLD_CONFIG 0x48002001 -#define MSR_LX_GLCP_DOTPLL 0x4c000015 -#define MSR_LX_DF_PADSEL 0x48002011 -#define MSR_LX_DC_SPARE 0x80000011 -#define MSR_LX_DF_GLCONFIG 0x48002001 - -#define MSR_LX_GLIU0_P2D_RO0 0x10000029 - -#define GLCP_DOTPLL_RESET (1 << 0) -#define GLCP_DOTPLL_BYPASS (1 << 15) -#define GLCP_DOTPLL_HALFPIX (1 << 24) -#define GLCP_DOTPLL_LOCK (1 << 25) - -#define DF_CONFIG_OUTPUT_MASK 0x38 -#define DF_OUTPUT_PANEL 0x08 -#define DF_OUTPUT_CRT 0x00 -#define DF_SIMULTANEOUS_CRT_AND_FP (1 << 15) - -#define DF_DEFAULT_TFT_PAD_SEL_LOW 0xDFFFFFFF -#define DF_DEFAULT_TFT_PAD_SEL_HIGH 0x0000003F - -#define DC_SPARE_DISABLE_CFIFO_HGO 0x00000800 -#define DC_SPARE_VFIFO_ARB_SELECT 0x00000400 -#define DC_SPARE_WM_LPEN_OVRD 0x00000200 -#define DC_SPARE_LOAD_WM_LPEN_MASK 0x00000100 -#define DC_SPARE_DISABLE_INIT_VID_PRI 0x00000080 -#define DC_SPARE_DISABLE_VFIFO_WM 0x00000040 -#define DC_SPARE_DISABLE_CWD_CHECK 0x00000020 -#define DC_SPARE_PIX8_PAN_FIX 0x00000010 -#define DC_SPARE_FIRST_REQ_MASK 0x00000002 - -/* Registers */ - -#define DC_UNLOCK 0x00 -#define DC_UNLOCK_CODE 0x4758 +#define DC_GENLK_CTL_FLICK_SEL_MASK (0x0F << 28) +#define DC_GENLK_CTL_ALPHA_FLICK_EN (1 << 25) +#define DC_GENLK_CTL_FLICK_EN (1 << 24) +#define DC_GENLK_CTL_GENLK_EN (1 << 18) -#define DC_GENERAL_CFG 0x04 -#define DC_GCFG_DFLE (1 << 0) -#define DC_GCFG_VIDE (1 << 3) -#define DC_GCFG_VGAE (1 << 7) -#define DC_GCFG_CMPE (1 << 5) -#define DC_GCFG_DECE (1 << 6) -#define DC_GCFG_FDTY (1 << 17) -#define DC_DISPLAY_CFG 0x08 -#define DC_DCFG_TGEN (1 << 0) -#define DC_DCFG_GDEN (1 << 3) -#define DC_DCFG_VDEN (1 << 4) -#define DC_DCFG_TRUP (1 << 6) -#define DC_DCFG_DCEN (1 << 24) -#define DC_DCFG_PALB (1 << 25) -#define DC_DCFG_VISL (1 << 27) +/* + * Video Processor registers (table 6-71). + * There is space for 64 bit values, but we never use more than the + * lower 32 bits. The actual register save/restore code only bothers + * to restore those 32 bits. + */ +enum vp_registers { + VP_VCFG = 0, + VP_DCFG, -#define DC_DCFG_16BPP 0x0 + VP_VX, + VP_VY, -#define DC_DCFG_DISP_MODE_MASK 0x00000300 -#define DC_DCFG_DISP_MODE_8BPP 0x00000000 -#define DC_DCFG_DISP_MODE_16BPP 0x00000100 -#define DC_DCFG_DISP_MODE_24BPP 0x00000200 -#define DC_DCFG_DISP_MODE_32BPP 0x00000300 + VP_SCL, + VP_VCK, + VP_VCM, + VP_PAR, -#define DC_ARB_CFG 0x0C + VP_PDR, + VP_SLR, -#define DC_FB_START 0x10 -#define DC_CB_START 0x14 -#define DC_CURSOR_START 0x18 + VP_MISC, + VP_CCS, -#define DC_DV_TOP 0x2C -#define DC_DV_TOP_ENABLE (1 << 0) + VP_VYS, + VP_VXS, -#define DC_LINE_SIZE 0x30 -#define DC_GRAPHICS_PITCH 0x34 -#define DC_H_ACTIVE_TIMING 0x40 -#define DC_H_BLANK_TIMING 0x44 -#define DC_H_SYNC_TIMING 0x48 -#define DC_V_ACTIVE_TIMING 0x50 -#define DC_V_BLANK_TIMING 0x54 -#define DC_V_SYNC_TIMING 0x58 -#define DC_FB_ACTIVE 0x5C + VP_RSVD_0, + VP_VDC, + + VP_RSVD_1, + VP_CRC, + + VP_CRC32, + VP_VDE, + + VP_CCK, + VP_CCM, + + VP_CC1, + VP_CC2, + + VP_A1X, + VP_A1Y, + + VP_A1C, + VP_A1T, + + VP_A2X, + VP_A2Y, + + VP_A2C, + VP_A2T, + + VP_A3X, + VP_A3Y, + + VP_A3C, + VP_A3T, + + VP_VRR, + VP_AWT, + + VP_VTM, + VP_VYE, + + VP_A1YE, + VP_A2YE, + + VP_A3YE, /* 0x150 */ + + VP_VCR = 0x1000, /* 0x1000 - 0x1fff */ +}; -#define DC_PAL_ADDRESS 0x70 -#define DC_PAL_DATA 0x74 +#define VP_VCFG_VID_EN (1 << 0) -#define DC_PHY_MEM_OFFSET 0x84 +#define VP_DCFG_GV_GAM (1 << 21) +#define VP_DCFG_PWR_SEQ_DELAY ((1 << 17) | (1 << 18) | (1 << 19)) +#define VP_DCFG_PWR_SEQ_DELAY_DEFAULT (1 << 19) /* undocumented */ +#define VP_DCFG_CRT_SYNC_SKW ((1 << 14) | (1 << 15) | (1 << 16)) +#define VP_DCFG_CRT_SYNC_SKW_DEFAULT (1 << 16) +#define VP_DCFG_CRT_VSYNC_POL (1 << 9) +#define VP_DCFG_CRT_HSYNC_POL (1 << 8) +#define VP_DCFG_DAC_BL_EN (1 << 3) +#define VP_DCFG_VSYNC_EN (1 << 2) +#define VP_DCFG_HSYNC_EN (1 << 1) +#define VP_DCFG_CRT_EN (1 << 0) -#define DC_DV_CTL 0x88 -#define DC_DV_LINE_SIZE_MASK 0x00000C00 -#define DC_DV_LINE_SIZE_1024 0x00000000 -#define DC_DV_LINE_SIZE_2048 0x00000400 -#define DC_DV_LINE_SIZE_4096 0x00000800 -#define DC_DV_LINE_SIZE_8192 0x00000C00 +#define VP_MISC_APWRDN (1 << 11) +#define VP_MISC_DACPWRDN (1 << 10) +#define VP_MISC_BYP_BOTH (1 << 0) -#define DC_GFX_SCALE 0x90 -#define DC_IRQ_FILT_CTL 0x94 +/* + * Flat Panel registers (table 6-71). + * Also 64 bit registers; see above note about 32-bit handling. + */ +/* we're actually in the VP register space, starting at address 0x400 */ +#define VP_FP_START 0x400 -#define DC_IRQ 0xC8 -#define DC_IRQ_MASK (1 << 0) -#define DC_VSYNC_IRQ_MASK (1 << 1) -#define DC_IRQ_STATUS (1 << 20) -#define DC_VSYNC_IRQ_STATUS (1 << 21) - -#define DC_GENLCK_CTRL 0xD4 -#define DC_GENLCK_ENABLE (1 << 18) -#define DC_GC_ALPHA_FLICK_ENABLE (1 << 25) -#define DC_GC_FLICKER_FILTER_ENABLE (1 << 24) -#define DC_GC_FLICKER_FILTER_MASK (0x0F << 28) - -#define DC_COLOR_KEY 0xB8 -#define DC_CLR_KEY_ENABLE (1 << 24) - - -#define DC3_DV_LINE_SIZE_MASK 0x00000C00 -#define DC3_DV_LINE_SIZE_1024 0x00000000 -#define DC3_DV_LINE_SIZE_2048 0x00000400 -#define DC3_DV_LINE_SIZE_4096 0x00000800 -#define DC3_DV_LINE_SIZE_8192 0x00000C00 - -#define DF_VIDEO_CFG 0x0 -#define DF_VCFG_VID_EN (1 << 0) - -#define DF_DISPLAY_CFG 0x08 - -#define DF_DCFG_CRT_EN (1 << 0) -#define DF_DCFG_HSYNC_EN (1 << 1) -#define DF_DCFG_VSYNC_EN (1 << 2) -#define DF_DCFG_DAC_BL_EN (1 << 3) -#define DF_DCFG_CRT_HSYNC_POL (1 << 8) -#define DF_DCFG_CRT_VSYNC_POL (1 << 9) -#define DF_DCFG_GV_PAL_BYP (1 << 21) +enum fp_registers { + FP_PT1 = 0, + FP_PT2, -#define DF_DCFG_CRT_SYNC_SKW_INIT 0x10000 -#define DF_DCFG_CRT_SYNC_SKW_MASK 0x1c000 + FP_PM, + FP_DFC, -#define DF_DCFG_PWR_SEQ_DLY_INIT 0x80000 -#define DF_DCFG_PWR_SEQ_DLY_MASK 0xe0000 + FP_RSVD_0, + FP_RSVD_1, -#define DF_MISC 0x50 + FP_RSVD_2, + FP_RSVD_3, + + FP_RSVD_4, + FP_DCA, + + FP_DMD, + FP_CRC, /* 0x458 */ +}; + +#define FP_PT2_SCRC (1 << 27) /* shfclk free */ + +#define FP_PM_P (1 << 24) /* panel power ctl */ +#define FP_PM_PANEL_PWR_UP (1 << 3) /* r/o */ +#define FP_PM_PANEL_PWR_DOWN (1 << 2) /* r/o */ +#define FP_PM_PANEL_OFF (1 << 1) /* r/o */ +#define FP_PM_PANEL_ON (1 << 0) /* r/o */ + +#define FP_DFC_BC ((1 << 4) | (1 << 5) | (1 << 6)) + + +/* register access functions */ + +static inline uint32_t read_gp(struct lxfb_par *par, int reg) +{ + return readl(par->gp_regs + 4*reg); +} + +static inline void write_gp(struct lxfb_par *par, int reg, uint32_t val) +{ + writel(val, par->gp_regs + 4*reg); +} + +static inline uint32_t read_dc(struct lxfb_par *par, int reg) +{ + return readl(par->dc_regs + 4*reg); +} + +static inline void write_dc(struct lxfb_par *par, int reg, uint32_t val) +{ + writel(val, par->dc_regs + 4*reg); +} + +static inline uint32_t read_vp(struct lxfb_par *par, int reg) +{ + return readl(par->vp_regs + 8*reg); +} + +static inline void write_vp(struct lxfb_par *par, int reg, uint32_t val) +{ + writel(val, par->vp_regs + 8*reg); +} + +static inline uint32_t read_fp(struct lxfb_par *par, int reg) +{ + return readl(par->vp_regs + 8*reg + VP_FP_START); +} + +static inline void write_fp(struct lxfb_par *par, int reg, uint32_t val) +{ + writel(val, par->vp_regs + 8*reg + VP_FP_START); +} -#define DF_MISC_GAM_BYPASS (1 << 0) -#define DF_MISC_DAC_PWRDN (1 << 10) -#define DF_MISC_A_PWRDN (1 << 11) -#define DF_PAR 0x38 -#define DF_PDR 0x40 -#define DF_ALPHA_CONTROL_1 0xD8 -#define DF_VIDEO_REQUEST 0x120 +/* MSRs are defined in asm/geode.h; their bitfields are here */ -#define DF_PANEL_TIM1 0x400 -#define DF_DEFAULT_TFT_PMTIM1 0x0 +#define MSR_GLCP_DOTPLL_LOCK (1 << 25) /* r/o */ +#define MSR_GLCP_DOTPLL_HALFPIX (1 << 24) +#define MSR_GLCP_DOTPLL_BYPASS (1 << 15) +#define MSR_GLCP_DOTPLL_DOTRESET (1 << 0) -#define DF_PANEL_TIM2 0x408 -#define DF_DEFAULT_TFT_PMTIM2 0x08000000 +/* note: this is actually the VP's GLD_MSR_CONFIG */ +#define MSR_LX_GLD_MSR_CONFIG_FMT ((1 << 3) | (1 << 4) | (1 << 5)) +#define MSR_LX_GLD_MSR_CONFIG_FMT_FP (1 << 3) +#define MSR_LX_GLD_MSR_CONFIG_FMT_CRT (0) +#define MSR_LX_GLD_MSR_CONFIG_FPC (1 << 15) /* FP *and* CRT */ -#define DF_FP_PM 0x410 -#define DF_FP_PM_P (1 << 24) +#define MSR_LX_MSR_PADSEL_TFT_SEL_LOW 0xDFFFFFFF /* ??? */ +#define MSR_LX_MSR_PADSEL_TFT_SEL_HIGH 0x0000003F /* ??? */ -#define DF_DITHER_CONTROL 0x418 -#define DF_DEFAULT_TFT_DITHCTL 0x00000070 -#define GP_BLT_STATUS 0x44 -#define GP_BS_BLT_BUSY (1 << 0) -#define GP_BS_CB_EMPTY (1 << 4) +#define MSR_LX_SPARE_MSR_DIS_CFIFO_HGO (1 << 11) /* undocumented */ +#define MSR_LX_SPARE_MSR_VFIFO_ARB_SEL (1 << 10) /* undocumented */ +#define MSR_LX_SPARE_MSR_WM_LPEN_OVRD (1 << 9) /* undocumented */ +#define MSR_LX_SPARE_MSR_LOAD_WM_LPEN_M (1 << 8) /* undocumented */ +#define MSR_LX_SPARE_MSR_DIS_INIT_V_PRI (1 << 7) /* undocumented */ +#define MSR_LX_SPARE_MSR_DIS_VIFO_WM (1 << 6) +#define MSR_LX_SPARE_MSR_DIS_CWD_CHECK (1 << 5) /* undocumented */ +#define MSR_LX_SPARE_MSR_PIX8_PAN_FIX (1 << 4) /* undocumented */ +#define MSR_LX_SPARE_MSR_FIRST_REQ_MASK (1 << 1) /* undocumented */ #endif diff --git a/drivers/video/geode/lxfb_core.c b/drivers/video/geode/lxfb_core.c index eb6b88171538..2cd9b74d2225 100644 --- a/drivers/video/geode/lxfb_core.c +++ b/drivers/video/geode/lxfb_core.c @@ -17,6 +17,7 @@ #include <linux/console.h> #include <linux/mm.h> #include <linux/slab.h> +#include <linux/suspend.h> #include <linux/delay.h> #include <linux/fb.h> #include <linux/init.h> @@ -27,14 +28,15 @@ static char *mode_option; static int noclear, nopanel, nocrt; -static int fbsize; +static int vram; +static int vt_switch; /* Most of these modes are sorted in ascending order, but * since the first entry in this table is the "default" mode, * we try to make it something sane - 640x480-60 is sane */ -static const struct fb_videomode geode_modedb[] __initdata = { +static struct fb_videomode geode_modedb[] __initdata = { /* 640x480-60 */ { NULL, 60, 640, 480, 39682, 48, 8, 25, 2, 88, 2, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, @@ -215,6 +217,35 @@ static const struct fb_videomode geode_modedb[] __initdata = { 0, FB_VMODE_NONINTERLACED, 0 }, }; +#ifdef CONFIG_OLPC +#include <asm/olpc.h> + +static struct fb_videomode olpc_dcon_modedb[] __initdata = { + /* The only mode the DCON has is 1200x900 */ + { NULL, 50, 1200, 900, 17460, 24, 8, 4, 5, 8, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, 0 } +}; + +static void __init get_modedb(struct fb_videomode **modedb, unsigned int *size) +{ + if (olpc_has_dcon()) { + *modedb = (struct fb_videomode *) olpc_dcon_modedb; + *size = ARRAY_SIZE(olpc_dcon_modedb); + } else { + *modedb = (struct fb_videomode *) geode_modedb; + *size = ARRAY_SIZE(geode_modedb); + } +} + +#else +static void __init get_modedb(struct fb_videomode **modedb, unsigned int *size) +{ + *modedb = (struct fb_videomode *) geode_modedb; + *size = ARRAY_SIZE(geode_modedb); +} +#endif + static int lxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { if (var->xres > 1920 || var->yres > 1440) @@ -333,13 +364,13 @@ static int __init lxfb_map_video_memory(struct fb_info *info, if (ret) return ret; - ret = pci_request_region(dev, 3, "lxfb-vip"); + ret = pci_request_region(dev, 3, "lxfb-vp"); if (ret) return ret; info->fix.smem_start = pci_resource_start(dev, 0); - info->fix.smem_len = fbsize ? fbsize : lx_framebuffer_size(); + info->fix.smem_len = vram ? vram : lx_framebuffer_size(); info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len); @@ -360,18 +391,15 @@ static int __init lxfb_map_video_memory(struct fb_info *info, if (par->dc_regs == NULL) return ret; - par->df_regs = ioremap(pci_resource_start(dev, 3), + par->vp_regs = ioremap(pci_resource_start(dev, 3), pci_resource_len(dev, 3)); - if (par->df_regs == NULL) + if (par->vp_regs == NULL) return ret; - writel(DC_UNLOCK_CODE, par->dc_regs + DC_UNLOCK); - - writel(info->fix.smem_start & 0xFF000000, - par->dc_regs + DC_PHY_MEM_OFFSET); - - writel(0, par->dc_regs + DC_UNLOCK); + write_dc(par, DC_UNLOCK, DC_UNLOCK_UNLOCK); + write_dc(par, DC_GLIU0_MEM_OFFSET, info->fix.smem_start & 0xFF000000); + write_dc(par, DC_UNLOCK, DC_UNLOCK_LOCK); dev_info(&dev->dev, "%d KB of video memory at 0x%lx\n", info->fix.smem_len / 1024, info->fix.smem_start); @@ -431,6 +459,45 @@ static struct fb_info * __init lxfb_init_fbinfo(struct device *dev) return info; } +#ifdef CONFIG_PM +static int lxfb_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct fb_info *info = pci_get_drvdata(pdev); + + if (state.event == PM_EVENT_SUSPEND) { + acquire_console_sem(); + lx_powerdown(info); + fb_set_suspend(info, 1); + release_console_sem(); + } + + /* there's no point in setting PCI states; we emulate PCI, so + * we don't end up getting power savings anyways */ + + return 0; +} + +static int lxfb_resume(struct pci_dev *pdev) +{ + struct fb_info *info = pci_get_drvdata(pdev); + int ret; + + acquire_console_sem(); + ret = lx_powerup(info); + if (ret) { + printk(KERN_ERR "lxfb: power up failed!\n"); + return ret; + } + + fb_set_suspend(info, 0); + release_console_sem(); + return 0; +} +#else +#define lxfb_suspend NULL +#define lxfb_resume NULL +#endif + static int __init lxfb_probe(struct pci_dev *pdev, const struct pci_device_id *id) { @@ -439,7 +506,7 @@ static int __init lxfb_probe(struct pci_dev *pdev, int ret; struct fb_videomode *modedb_ptr; - int modedb_size; + unsigned int modedb_size; info = lxfb_init_fbinfo(&pdev->dev); @@ -464,9 +531,7 @@ static int __init lxfb_probe(struct pci_dev *pdev, /* Set up the mode database */ - modedb_ptr = (struct fb_videomode *) geode_modedb; - modedb_size = ARRAY_SIZE(geode_modedb); - + get_modedb(&modedb_ptr, &modedb_size); ret = fb_find_mode(&info->var, info, mode_option, modedb_ptr, modedb_size, NULL, 16); @@ -487,6 +552,8 @@ static int __init lxfb_probe(struct pci_dev *pdev, lxfb_check_var(&info->var, info); lxfb_set_par(info); + pm_set_vt_switch(vt_switch); + if (register_framebuffer(info) < 0) { ret = -EINVAL; goto err; @@ -510,8 +577,8 @@ err: iounmap(par->dc_regs); pci_release_region(pdev, 2); } - if (par->df_regs) { - iounmap(par->df_regs); + if (par->vp_regs) { + iounmap(par->vp_regs); pci_release_region(pdev, 3); } @@ -537,7 +604,7 @@ static void lxfb_remove(struct pci_dev *pdev) iounmap(par->dc_regs); pci_release_region(pdev, 2); - iounmap(par->df_regs); + iounmap(par->vp_regs); pci_release_region(pdev, 3); pci_set_drvdata(pdev, NULL); @@ -556,6 +623,8 @@ static struct pci_driver lxfb_driver = { .id_table = lxfb_id_table, .probe = lxfb_probe, .remove = lxfb_remove, + .suspend = lxfb_suspend, + .resume = lxfb_resume, }; #ifndef MODULE @@ -570,9 +639,7 @@ static int __init lxfb_setup(char *options) if (!*opt) continue; - if (!strncmp(opt, "fbsize:", 7)) - fbsize = simple_strtoul(opt+7, NULL, 0); - else if (!strcmp(opt, "noclear")) + if (!strcmp(opt, "noclear")) noclear = 1; else if (!strcmp(opt, "nopanel")) nopanel = 1; @@ -609,8 +676,11 @@ module_exit(lxfb_cleanup); module_param(mode_option, charp, 0); MODULE_PARM_DESC(mode_option, "video mode (<x>x<y>[-<bpp>][@<refr>])"); -module_param(fbsize, int, 0); -MODULE_PARM_DESC(fbsize, "video memory size"); +module_param(vram, int, 0); +MODULE_PARM_DESC(vram, "video memory size"); + +module_param(vt_switch, int, 0); +MODULE_PARM_DESC(vt_switch, "enable VT switch during suspend/resume"); MODULE_DESCRIPTION("Framebuffer driver for the AMD Geode LX"); MODULE_LICENSE("GPL"); diff --git a/drivers/video/geode/lxfb_ops.c b/drivers/video/geode/lxfb_ops.c index 4fbc99be96ef..cd9d4cc26954 100644 --- a/drivers/video/geode/lxfb_ops.c +++ b/drivers/video/geode/lxfb_ops.c @@ -13,6 +13,7 @@ #include <linux/fb.h> #include <linux/uaccess.h> #include <linux/delay.h> +#include <asm/geode.h> #include "lxfb.h" @@ -34,35 +35,85 @@ static const struct { unsigned int pllval; unsigned int freq; } pll_table[] = { - { 0x000031AC, 24923 }, - { 0x0000215D, 25175 }, - { 0x00001087, 27000 }, - { 0x0000216C, 28322 }, - { 0x0000218D, 28560 }, - { 0x000010C9, 31200 }, - { 0x00003147, 31500 }, - { 0x000010A7, 33032 }, - { 0x00002159, 35112 }, - { 0x00004249, 35500 }, - { 0x00000057, 36000 }, - { 0x0000219A, 37889 }, - { 0x00002158, 39168 }, - { 0x00000045, 40000 }, - { 0x00000089, 43163 }, - { 0x000010E7, 44900 }, - { 0x00002136, 45720 }, - { 0x00003207, 49500 }, - { 0x00002187, 50000 }, - { 0x00004286, 56250 }, - { 0x000010E5, 60065 }, - { 0x00004214, 65000 }, - { 0x00001105, 68179 }, - { 0x000031E4, 74250 }, - { 0x00003183, 75000 }, - { 0x00004284, 78750 }, - { 0x00001104, 81600 }, - { 0x00006363, 94500 }, - { 0x00005303, 97520 }, + { 0x000131AC, 6231 }, + { 0x0001215D, 6294 }, + { 0x00011087, 6750 }, + { 0x0001216C, 7081 }, + { 0x0001218D, 7140 }, + { 0x000110C9, 7800 }, + { 0x00013147, 7875 }, + { 0x000110A7, 8258 }, + { 0x00012159, 8778 }, + { 0x00014249, 8875 }, + { 0x00010057, 9000 }, + { 0x0001219A, 9472 }, + { 0x00012158, 9792 }, + { 0x00010045, 10000 }, + { 0x00010089, 10791 }, + { 0x000110E7, 11225 }, + { 0x00012136, 11430 }, + { 0x00013207, 12375 }, + { 0x00012187, 12500 }, + { 0x00014286, 14063 }, + { 0x000110E5, 15016 }, + { 0x00014214, 16250 }, + { 0x00011105, 17045 }, + { 0x000131E4, 18563 }, + { 0x00013183, 18750 }, + { 0x00014284, 19688 }, + { 0x00011104, 20400 }, + { 0x00016363, 23625 }, + { 0x00015303, 24380 }, + { 0x000031AC, 24923 }, + { 0x0000215D, 25175 }, + { 0x00001087, 27000 }, + { 0x0000216C, 28322 }, + { 0x0000218D, 28560 }, + { 0x00010041, 29913 }, + { 0x000010C9, 31200 }, + { 0x00003147, 31500 }, + { 0x000141A1, 32400 }, + { 0x000010A7, 33032 }, + { 0x00012182, 33375 }, + { 0x000141B1, 33750 }, + { 0x00002159, 35112 }, + { 0x00004249, 35500 }, + { 0x00000057, 36000 }, + { 0x000141E1, 37125 }, + { 0x0000219A, 37889 }, + { 0x00002158, 39168 }, + { 0x00000045, 40000 }, + { 0x000131A1, 40500 }, + { 0x00010061, 42301 }, + { 0x00000089, 43163 }, + { 0x00012151, 43875 }, + { 0x000010E7, 44900 }, + { 0x00002136, 45720 }, + { 0x000152E1, 47250 }, + { 0x00010071, 48000 }, + { 0x00003207, 49500 }, + { 0x00002187, 50000 }, + { 0x00014291, 50625 }, + { 0x00011101, 51188 }, + { 0x00017481, 54563 }, + { 0x00004286, 56250 }, + { 0x00014170, 57375 }, + { 0x00016210, 58500 }, + { 0x000010E5, 60065 }, + { 0x00013140, 62796 }, + { 0x00004214, 65000 }, + { 0x00016250, 65250 }, + { 0x00001105, 68179 }, + { 0x000141C0, 69600 }, + { 0x00015220, 70160 }, + { 0x00010050, 72000 }, + { 0x000031E4, 74250 }, + { 0x00003183, 75000 }, + { 0x00004284, 78750 }, + { 0x00012130, 80052 }, + { 0x00001104, 81600 }, + { 0x00006363, 94500 }, + { 0x00005303, 97520 }, { 0x00002183, 100187 }, { 0x00002122, 101420 }, { 0x00001081, 108000 }, @@ -101,16 +152,16 @@ static void lx_set_dotpll(u32 pllval) u32 dotpll_lo, dotpll_hi; int i; - rdmsr(MSR_LX_GLCP_DOTPLL, dotpll_lo, dotpll_hi); + rdmsr(MSR_GLCP_DOTPLL, dotpll_lo, dotpll_hi); - if ((dotpll_lo & GLCP_DOTPLL_LOCK) && (dotpll_hi == pllval)) + if ((dotpll_lo & MSR_GLCP_DOTPLL_LOCK) && (dotpll_hi == pllval)) return; dotpll_hi = pllval; - dotpll_lo &= ~(GLCP_DOTPLL_BYPASS | GLCP_DOTPLL_HALFPIX); - dotpll_lo |= GLCP_DOTPLL_RESET; + dotpll_lo &= ~(MSR_GLCP_DOTPLL_BYPASS | MSR_GLCP_DOTPLL_HALFPIX); + dotpll_lo |= MSR_GLCP_DOTPLL_DOTRESET; - wrmsr(MSR_LX_GLCP_DOTPLL, dotpll_lo, dotpll_hi); + wrmsr(MSR_GLCP_DOTPLL, dotpll_lo, dotpll_hi); /* Wait 100us for the PLL to lock */ @@ -119,15 +170,15 @@ static void lx_set_dotpll(u32 pllval) /* Now, loop for the lock bit */ for (i = 0; i < 1000; i++) { - rdmsr(MSR_LX_GLCP_DOTPLL, dotpll_lo, dotpll_hi); - if (dotpll_lo & GLCP_DOTPLL_LOCK) + rdmsr(MSR_GLCP_DOTPLL, dotpll_lo, dotpll_hi); + if (dotpll_lo & MSR_GLCP_DOTPLL_LOCK) break; } /* Clear the reset bit */ - dotpll_lo &= ~GLCP_DOTPLL_RESET; - wrmsr(MSR_LX_GLCP_DOTPLL, dotpll_lo, dotpll_hi); + dotpll_lo &= ~MSR_GLCP_DOTPLL_DOTRESET; + wrmsr(MSR_GLCP_DOTPLL, dotpll_lo, dotpll_hi); } /* Set the clock based on the frequency specified by the current mode */ @@ -137,7 +188,7 @@ static void lx_set_clock(struct fb_info *info) unsigned int diff, min, best = 0; unsigned int freq, i; - freq = (unsigned int) (0x3b9aca00 / info->var.pixclock); + freq = (unsigned int) (1000000000 / info->var.pixclock); min = abs(pll_table[0].freq - freq); @@ -149,7 +200,7 @@ static void lx_set_clock(struct fb_info *info) } } - lx_set_dotpll(pll_table[best].pllval & 0x7FFF); + lx_set_dotpll(pll_table[best].pllval & 0x00017FFF); } static void lx_graphics_disable(struct fb_info *info) @@ -159,63 +210,62 @@ static void lx_graphics_disable(struct fb_info *info) /* Note: This assumes that the video is in a quitet state */ - writel(0, par->df_regs + DF_ALPHA_CONTROL_1); - writel(0, par->df_regs + DF_ALPHA_CONTROL_1 + 32); - writel(0, par->df_regs + DF_ALPHA_CONTROL_1 + 64); + write_vp(par, VP_A1T, 0); + write_vp(par, VP_A2T, 0); + write_vp(par, VP_A3T, 0); /* Turn off the VGA and video enable */ - val = readl (par->dc_regs + DC_GENERAL_CFG) & - ~(DC_GCFG_VGAE | DC_GCFG_VIDE); + val = read_dc(par, DC_GENERAL_CFG) & ~(DC_GENERAL_CFG_VGAE | + DC_GENERAL_CFG_VIDE); - writel(val, par->dc_regs + DC_GENERAL_CFG); + write_dc(par, DC_GENERAL_CFG, val); - val = readl(par->df_regs + DF_VIDEO_CFG) & ~DF_VCFG_VID_EN; - writel(val, par->df_regs + DF_VIDEO_CFG); + val = read_vp(par, VP_VCFG) & ~VP_VCFG_VID_EN; + write_vp(par, VP_VCFG, val); - writel( DC_IRQ_MASK | DC_VSYNC_IRQ_MASK | - DC_IRQ_STATUS | DC_VSYNC_IRQ_STATUS, - par->dc_regs + DC_IRQ); + write_dc(par, DC_IRQ, DC_IRQ_MASK | DC_IRQ_VIP_VSYNC_LOSS_IRQ_MASK | + DC_IRQ_STATUS | DC_IRQ_VIP_VSYNC_IRQ_STATUS); - val = readl(par->dc_regs + DC_GENLCK_CTRL) & ~DC_GENLCK_ENABLE; - writel(val, par->dc_regs + DC_GENLCK_CTRL); + val = read_dc(par, DC_GENLK_CTL) & ~DC_GENLK_CTL_GENLK_EN; + write_dc(par, DC_GENLK_CTL, val); - val = readl(par->dc_regs + DC_COLOR_KEY) & ~DC_CLR_KEY_ENABLE; - writel(val & ~DC_CLR_KEY_ENABLE, par->dc_regs + DC_COLOR_KEY); + val = read_dc(par, DC_CLR_KEY); + write_dc(par, DC_CLR_KEY, val & ~DC_CLR_KEY_CLR_KEY_EN); - /* We don't actually blank the panel, due to the long latency - involved with bringing it back */ + /* turn off the panel */ + write_fp(par, FP_PM, read_fp(par, FP_PM) & ~FP_PM_P); - val = readl(par->df_regs + DF_MISC) | DF_MISC_DAC_PWRDN; - writel(val, par->df_regs + DF_MISC); + val = read_vp(par, VP_MISC) | VP_MISC_DACPWRDN; + write_vp(par, VP_MISC, val); /* Turn off the display */ - val = readl(par->df_regs + DF_DISPLAY_CFG); - writel(val & ~(DF_DCFG_CRT_EN | DF_DCFG_HSYNC_EN | DF_DCFG_VSYNC_EN | - DF_DCFG_DAC_BL_EN), par->df_regs + DF_DISPLAY_CFG); + val = read_vp(par, VP_DCFG); + write_vp(par, VP_DCFG, val & ~(VP_DCFG_CRT_EN | VP_DCFG_HSYNC_EN | + VP_DCFG_VSYNC_EN | VP_DCFG_DAC_BL_EN)); - gcfg = readl(par->dc_regs + DC_GENERAL_CFG); - gcfg &= ~(DC_GCFG_CMPE | DC_GCFG_DECE); - writel(gcfg, par->dc_regs + DC_GENERAL_CFG); + gcfg = read_dc(par, DC_GENERAL_CFG); + gcfg &= ~(DC_GENERAL_CFG_CMPE | DC_GENERAL_CFG_DECE); + write_dc(par, DC_GENERAL_CFG, gcfg); /* Turn off the TGEN */ - val = readl(par->dc_regs + DC_DISPLAY_CFG); - val &= ~DC_DCFG_TGEN; - writel(val, par->dc_regs + DC_DISPLAY_CFG); + val = read_dc(par, DC_DISPLAY_CFG); + val &= ~DC_DISPLAY_CFG_TGEN; + write_dc(par, DC_DISPLAY_CFG, val); /* Wait 1000 usecs to ensure that the TGEN is clear */ udelay(1000); /* Turn off the FIFO loader */ - gcfg &= ~DC_GCFG_DFLE; - writel(gcfg, par->dc_regs + DC_GENERAL_CFG); + gcfg &= ~DC_GENERAL_CFG_DFLE; + write_dc(par, DC_GENERAL_CFG, gcfg); /* Lastly, wait for the GP to go idle */ do { - val = readl(par->gp_regs + GP_BLT_STATUS); - } while ((val & GP_BS_BLT_BUSY) || !(val & GP_BS_CB_EMPTY)); + val = read_gp(par, GP_BLT_STATUS); + } while ((val & GP_BLT_STATUS_PB) || !(val & GP_BLT_STATUS_CE)); } static void lx_graphics_enable(struct fb_info *info) @@ -224,80 +274,85 @@ static void lx_graphics_enable(struct fb_info *info) u32 temp, config; /* Set the video request register */ - writel(0, par->df_regs + DF_VIDEO_REQUEST); + write_vp(par, VP_VRR, 0); /* Set up the polarities */ - config = readl(par->df_regs + DF_DISPLAY_CFG); + config = read_vp(par, VP_DCFG); - config &= ~(DF_DCFG_CRT_SYNC_SKW_MASK | DF_DCFG_PWR_SEQ_DLY_MASK | - DF_DCFG_CRT_HSYNC_POL | DF_DCFG_CRT_VSYNC_POL); + config &= ~(VP_DCFG_CRT_SYNC_SKW | VP_DCFG_PWR_SEQ_DELAY | + VP_DCFG_CRT_HSYNC_POL | VP_DCFG_CRT_VSYNC_POL); - config |= (DF_DCFG_CRT_SYNC_SKW_INIT | DF_DCFG_PWR_SEQ_DLY_INIT | - DF_DCFG_GV_PAL_BYP); + config |= (VP_DCFG_CRT_SYNC_SKW_DEFAULT | VP_DCFG_PWR_SEQ_DELAY_DEFAULT + | VP_DCFG_GV_GAM); if (info->var.sync & FB_SYNC_HOR_HIGH_ACT) - config |= DF_DCFG_CRT_HSYNC_POL; + config |= VP_DCFG_CRT_HSYNC_POL; if (info->var.sync & FB_SYNC_VERT_HIGH_ACT) - config |= DF_DCFG_CRT_VSYNC_POL; + config |= VP_DCFG_CRT_VSYNC_POL; if (par->output & OUTPUT_PANEL) { u32 msrlo, msrhi; - writel(DF_DEFAULT_TFT_PMTIM1, - par->df_regs + DF_PANEL_TIM1); - writel(DF_DEFAULT_TFT_PMTIM2, - par->df_regs + DF_PANEL_TIM2); - writel(DF_DEFAULT_TFT_DITHCTL, - par->df_regs + DF_DITHER_CONTROL); + write_fp(par, FP_PT1, 0); + write_fp(par, FP_PT2, FP_PT2_SCRC); + write_fp(par, FP_DFC, FP_DFC_BC); - msrlo = DF_DEFAULT_TFT_PAD_SEL_LOW; - msrhi = DF_DEFAULT_TFT_PAD_SEL_HIGH; + msrlo = MSR_LX_MSR_PADSEL_TFT_SEL_LOW; + msrhi = MSR_LX_MSR_PADSEL_TFT_SEL_HIGH; - wrmsr(MSR_LX_DF_PADSEL, msrlo, msrhi); + wrmsr(MSR_LX_MSR_PADSEL, msrlo, msrhi); } if (par->output & OUTPUT_CRT) { - config |= DF_DCFG_CRT_EN | DF_DCFG_HSYNC_EN | - DF_DCFG_VSYNC_EN | DF_DCFG_DAC_BL_EN; + config |= VP_DCFG_CRT_EN | VP_DCFG_HSYNC_EN | + VP_DCFG_VSYNC_EN | VP_DCFG_DAC_BL_EN; } - writel(config, par->df_regs + DF_DISPLAY_CFG); + write_vp(par, VP_DCFG, config); /* Turn the CRT dacs back on */ if (par->output & OUTPUT_CRT) { - temp = readl(par->df_regs + DF_MISC); - temp &= ~(DF_MISC_DAC_PWRDN | DF_MISC_A_PWRDN); - writel(temp, par->df_regs + DF_MISC); + temp = read_vp(par, VP_MISC); + temp &= ~(VP_MISC_DACPWRDN | VP_MISC_APWRDN); + write_vp(par, VP_MISC, temp); } /* Turn the panel on (if it isn't already) */ - - if (par->output & OUTPUT_PANEL) { - temp = readl(par->df_regs + DF_FP_PM); - - if (!(temp & 0x09)) - writel(temp | DF_FP_PM_P, par->df_regs + DF_FP_PM); - } - - temp = readl(par->df_regs + DF_MISC); - temp = readl(par->df_regs + DF_DISPLAY_CFG); + if (par->output & OUTPUT_PANEL) + write_fp(par, FP_PM, read_fp(par, FP_PM) | FP_PM_P); } unsigned int lx_framebuffer_size(void) { unsigned int val; + if (!geode_has_vsa2()) { + uint32_t hi, lo; + + /* The number of pages is (PMAX - PMIN)+1 */ + rdmsr(MSR_GLIU_P2D_RO0, lo, hi); + + /* PMAX */ + val = ((hi & 0xff) << 12) | ((lo & 0xfff00000) >> 20); + /* PMIN */ + val -= (lo & 0x000fffff); + val += 1; + + /* The page size is 4k */ + return (val << 12); + } + /* The frame buffer size is reported by a VSM in VSA II */ /* Virtual Register Class = 0x02 */ /* VG_MEM_SIZE (1MB units) = 0x00 */ - outw(0xFC53, 0xAC1C); - outw(0x0200, 0xAC1C); + outw(VSA_VR_UNLOCK, VSA_VRC_INDEX); + outw(VSA_VR_MEM_SIZE, VSA_VRC_INDEX); - val = (unsigned int)(inw(0xAC1E)) & 0xFE; + val = (unsigned int)(inw(VSA_VRC_DATA)) & 0xFE; return (val << 20); } @@ -313,7 +368,7 @@ void lx_set_mode(struct fb_info *info) int vactive, vblankstart, vsyncstart, vsyncend, vblankend, vtotal; /* Unlock the DC registers */ - writel(DC_UNLOCK_CODE, par->dc_regs + DC_UNLOCK); + write_dc(par, DC_UNLOCK, DC_UNLOCK_UNLOCK); lx_graphics_disable(info); @@ -321,102 +376,104 @@ void lx_set_mode(struct fb_info *info) /* Set output mode */ - rdmsrl(MSR_LX_DF_GLCONFIG, msrval); - msrval &= ~DF_CONFIG_OUTPUT_MASK; + rdmsrl(MSR_LX_GLD_MSR_CONFIG, msrval); + msrval &= ~MSR_LX_GLD_MSR_CONFIG_FMT; if (par->output & OUTPUT_PANEL) { - msrval |= DF_OUTPUT_PANEL; + msrval |= MSR_LX_GLD_MSR_CONFIG_FMT_FP; if (par->output & OUTPUT_CRT) - msrval |= DF_SIMULTANEOUS_CRT_AND_FP; + msrval |= MSR_LX_GLD_MSR_CONFIG_FPC; else - msrval &= ~DF_SIMULTANEOUS_CRT_AND_FP; - } else { - msrval |= DF_OUTPUT_CRT; - } + msrval &= ~MSR_LX_GLD_MSR_CONFIG_FPC; + } else + msrval |= MSR_LX_GLD_MSR_CONFIG_FMT_CRT; - wrmsrl(MSR_LX_DF_GLCONFIG, msrval); + wrmsrl(MSR_LX_GLD_MSR_CONFIG, msrval); /* Clear the various buffers */ /* FIXME: Adjust for panning here */ - writel(0, par->dc_regs + DC_FB_START); - writel(0, par->dc_regs + DC_CB_START); - writel(0, par->dc_regs + DC_CURSOR_START); + write_dc(par, DC_FB_ST_OFFSET, 0); + write_dc(par, DC_CB_ST_OFFSET, 0); + write_dc(par, DC_CURS_ST_OFFSET, 0); /* FIXME: Add support for interlacing */ /* FIXME: Add support for scaling */ - val = readl(par->dc_regs + DC_GENLCK_CTRL); - val &= ~(DC_GC_ALPHA_FLICK_ENABLE | - DC_GC_FLICKER_FILTER_ENABLE | DC_GC_FLICKER_FILTER_MASK); + val = read_dc(par, DC_GENLK_CTL); + val &= ~(DC_GENLK_CTL_ALPHA_FLICK_EN | DC_GENLK_CTL_FLICK_EN | + DC_GENLK_CTL_FLICK_SEL_MASK); /* Default scaling params */ - writel((0x4000 << 16) | 0x4000, par->dc_regs + DC_GFX_SCALE); - writel(0, par->dc_regs + DC_IRQ_FILT_CTL); - writel(val, par->dc_regs + DC_GENLCK_CTRL); + write_dc(par, DC_GFX_SCALE, (0x4000 << 16) | 0x4000); + write_dc(par, DC_IRQ_FILT_CTL, 0); + write_dc(par, DC_GENLK_CTL, val); /* FIXME: Support compression */ if (info->fix.line_length > 4096) - dv = DC_DV_LINE_SIZE_8192; + dv = DC_DV_CTL_DV_LINE_SIZE_8K; else if (info->fix.line_length > 2048) - dv = DC_DV_LINE_SIZE_4096; + dv = DC_DV_CTL_DV_LINE_SIZE_4K; else if (info->fix.line_length > 1024) - dv = DC_DV_LINE_SIZE_2048; + dv = DC_DV_CTL_DV_LINE_SIZE_2K; else - dv = DC_DV_LINE_SIZE_1024; + dv = DC_DV_CTL_DV_LINE_SIZE_1K; max = info->fix.line_length * info->var.yres; max = (max + 0x3FF) & 0xFFFFFC00; - writel(max | DC_DV_TOP_ENABLE, par->dc_regs + DC_DV_TOP); + write_dc(par, DC_DV_TOP, max | DC_DV_TOP_DV_TOP_EN); - val = readl(par->dc_regs + DC_DV_CTL) & ~DC_DV_LINE_SIZE_MASK; - writel(val | dv, par->dc_regs + DC_DV_CTL); + val = read_dc(par, DC_DV_CTL) & ~DC_DV_CTL_DV_LINE_SIZE; + write_dc(par, DC_DV_CTL, val | dv); size = info->var.xres * (info->var.bits_per_pixel >> 3); - writel(info->fix.line_length >> 3, par->dc_regs + DC_GRAPHICS_PITCH); - writel((size + 7) >> 3, par->dc_regs + DC_LINE_SIZE); + write_dc(par, DC_GFX_PITCH, info->fix.line_length >> 3); + write_dc(par, DC_LINE_SIZE, (size + 7) >> 3); /* Set default watermark values */ - rdmsrl(MSR_LX_DC_SPARE, msrval); - - msrval &= ~(DC_SPARE_DISABLE_CFIFO_HGO | DC_SPARE_VFIFO_ARB_SELECT | - DC_SPARE_LOAD_WM_LPEN_MASK | DC_SPARE_WM_LPEN_OVRD | - DC_SPARE_DISABLE_INIT_VID_PRI | DC_SPARE_DISABLE_VFIFO_WM); - msrval |= DC_SPARE_DISABLE_VFIFO_WM | DC_SPARE_DISABLE_INIT_VID_PRI; - wrmsrl(MSR_LX_DC_SPARE, msrval); - - gcfg = DC_GCFG_DFLE; /* Display fifo enable */ - gcfg |= 0xB600; /* Set default priority */ - gcfg |= DC_GCFG_FDTY; /* Set the frame dirty mode */ - - dcfg = DC_DCFG_VDEN; /* Enable video data */ - dcfg |= DC_DCFG_GDEN; /* Enable graphics */ - dcfg |= DC_DCFG_TGEN; /* Turn on the timing generator */ - dcfg |= DC_DCFG_TRUP; /* Update timings immediately */ - dcfg |= DC_DCFG_PALB; /* Palette bypass in > 8 bpp modes */ - dcfg |= DC_DCFG_VISL; - dcfg |= DC_DCFG_DCEN; /* Always center the display */ + rdmsrl(MSR_LX_SPARE_MSR, msrval); + + msrval &= ~(MSR_LX_SPARE_MSR_DIS_CFIFO_HGO + | MSR_LX_SPARE_MSR_VFIFO_ARB_SEL + | MSR_LX_SPARE_MSR_LOAD_WM_LPEN_M + | MSR_LX_SPARE_MSR_WM_LPEN_OVRD); + msrval |= MSR_LX_SPARE_MSR_DIS_VIFO_WM | + MSR_LX_SPARE_MSR_DIS_INIT_V_PRI; + wrmsrl(MSR_LX_SPARE_MSR, msrval); + + gcfg = DC_GENERAL_CFG_DFLE; /* Display fifo enable */ + gcfg |= (0x6 << DC_GENERAL_CFG_DFHPSL_SHIFT) | /* default priority */ + (0xb << DC_GENERAL_CFG_DFHPEL_SHIFT); + gcfg |= DC_GENERAL_CFG_FDTY; /* Set the frame dirty mode */ + + dcfg = DC_DISPLAY_CFG_VDEN; /* Enable video data */ + dcfg |= DC_DISPLAY_CFG_GDEN; /* Enable graphics */ + dcfg |= DC_DISPLAY_CFG_TGEN; /* Turn on the timing generator */ + dcfg |= DC_DISPLAY_CFG_TRUP; /* Update timings immediately */ + dcfg |= DC_DISPLAY_CFG_PALB; /* Palette bypass in > 8 bpp modes */ + dcfg |= DC_DISPLAY_CFG_VISL; + dcfg |= DC_DISPLAY_CFG_DCEN; /* Always center the display */ /* Set the current BPP mode */ switch (info->var.bits_per_pixel) { case 8: - dcfg |= DC_DCFG_DISP_MODE_8BPP; + dcfg |= DC_DISPLAY_CFG_DISP_MODE_8BPP; break; case 16: - dcfg |= DC_DCFG_DISP_MODE_16BPP | DC_DCFG_16BPP; + dcfg |= DC_DISPLAY_CFG_DISP_MODE_16BPP; break; case 32: case 24: - dcfg |= DC_DCFG_DISP_MODE_24BPP; + dcfg |= DC_DISPLAY_CFG_DISP_MODE_24BPP; break; } @@ -436,35 +493,31 @@ void lx_set_mode(struct fb_info *info) vblankend = vsyncend + info->var.upper_margin; vtotal = vblankend; - writel((hactive - 1) | ((htotal - 1) << 16), - par->dc_regs + DC_H_ACTIVE_TIMING); - writel((hblankstart - 1) | ((hblankend - 1) << 16), - par->dc_regs + DC_H_BLANK_TIMING); - writel((hsyncstart - 1) | ((hsyncend - 1) << 16), - par->dc_regs + DC_H_SYNC_TIMING); - - writel((vactive - 1) | ((vtotal - 1) << 16), - par->dc_regs + DC_V_ACTIVE_TIMING); + write_dc(par, DC_H_ACTIVE_TIMING, (hactive - 1) | ((htotal - 1) << 16)); + write_dc(par, DC_H_BLANK_TIMING, + (hblankstart - 1) | ((hblankend - 1) << 16)); + write_dc(par, DC_H_SYNC_TIMING, + (hsyncstart - 1) | ((hsyncend - 1) << 16)); - writel((vblankstart - 1) | ((vblankend - 1) << 16), - par->dc_regs + DC_V_BLANK_TIMING); + write_dc(par, DC_V_ACTIVE_TIMING, (vactive - 1) | ((vtotal - 1) << 16)); + write_dc(par, DC_V_BLANK_TIMING, + (vblankstart - 1) | ((vblankend - 1) << 16)); + write_dc(par, DC_V_SYNC_TIMING, + (vsyncstart - 1) | ((vsyncend - 1) << 16)); - writel((vsyncstart - 1) | ((vsyncend - 1) << 16), - par->dc_regs + DC_V_SYNC_TIMING); - - writel( (info->var.xres - 1) << 16 | (info->var.yres - 1), - par->dc_regs + DC_FB_ACTIVE); + write_dc(par, DC_FB_ACTIVE, + (info->var.xres - 1) << 16 | (info->var.yres - 1)); /* And re-enable the graphics output */ lx_graphics_enable(info); /* Write the two main configuration registers */ - writel(dcfg, par->dc_regs + DC_DISPLAY_CFG); - writel(0, par->dc_regs + DC_ARB_CFG); - writel(gcfg, par->dc_regs + DC_GENERAL_CFG); + write_dc(par, DC_DISPLAY_CFG, dcfg); + write_dc(par, DC_ARB_CFG, 0); + write_dc(par, DC_GENERAL_CFG, gcfg); /* Lock the DC registers */ - writel(0, par->dc_regs + DC_UNLOCK); + write_dc(par, DC_UNLOCK, DC_UNLOCK_LOCK); } void lx_set_palette_reg(struct fb_info *info, unsigned regno, @@ -479,58 +532,310 @@ void lx_set_palette_reg(struct fb_info *info, unsigned regno, val |= (green) & 0x00ff00; val |= (blue >> 8) & 0x0000ff; - writel(regno, par->dc_regs + DC_PAL_ADDRESS); - writel(val, par->dc_regs + DC_PAL_DATA); + write_dc(par, DC_PAL_ADDRESS, regno); + write_dc(par, DC_PAL_DATA, val); } int lx_blank_display(struct fb_info *info, int blank_mode) { struct lxfb_par *par = info->par; u32 dcfg, fp_pm; - int blank, hsync, vsync; + int blank, hsync, vsync, crt; /* CRT power saving modes. */ switch (blank_mode) { case FB_BLANK_UNBLANK: - blank = 0; hsync = 1; vsync = 1; + blank = 0; hsync = 1; vsync = 1; crt = 1; break; case FB_BLANK_NORMAL: - blank = 1; hsync = 1; vsync = 1; + blank = 1; hsync = 1; vsync = 1; crt = 1; break; case FB_BLANK_VSYNC_SUSPEND: - blank = 1; hsync = 1; vsync = 0; + blank = 1; hsync = 1; vsync = 0; crt = 1; break; case FB_BLANK_HSYNC_SUSPEND: - blank = 1; hsync = 0; vsync = 1; + blank = 1; hsync = 0; vsync = 1; crt = 1; break; case FB_BLANK_POWERDOWN: - blank = 1; hsync = 0; vsync = 0; + blank = 1; hsync = 0; vsync = 0; crt = 0; break; default: return -EINVAL; } - dcfg = readl(par->df_regs + DF_DISPLAY_CFG); - dcfg &= ~(DF_DCFG_DAC_BL_EN - | DF_DCFG_HSYNC_EN | DF_DCFG_VSYNC_EN); + dcfg = read_vp(par, VP_DCFG); + dcfg &= ~(VP_DCFG_DAC_BL_EN | VP_DCFG_HSYNC_EN | VP_DCFG_VSYNC_EN | + VP_DCFG_CRT_EN); if (!blank) - dcfg |= DF_DCFG_DAC_BL_EN; + dcfg |= VP_DCFG_DAC_BL_EN; if (hsync) - dcfg |= DF_DCFG_HSYNC_EN; + dcfg |= VP_DCFG_HSYNC_EN; if (vsync) - dcfg |= DF_DCFG_VSYNC_EN; - writel(dcfg, par->df_regs + DF_DISPLAY_CFG); + dcfg |= VP_DCFG_VSYNC_EN; + if (crt) + dcfg |= VP_DCFG_CRT_EN; + write_vp(par, VP_DCFG, dcfg); /* Power on/off flat panel */ if (par->output & OUTPUT_PANEL) { - fp_pm = readl(par->df_regs + DF_FP_PM); + fp_pm = read_fp(par, FP_PM); if (blank_mode == FB_BLANK_POWERDOWN) - fp_pm &= ~DF_FP_PM_P; + fp_pm &= ~FP_PM_P; else - fp_pm |= DF_FP_PM_P; - writel(fp_pm, par->df_regs + DF_FP_PM); + fp_pm |= FP_PM_P; + write_fp(par, FP_PM, fp_pm); } return 0; } + +#ifdef CONFIG_PM + +static void lx_save_regs(struct lxfb_par *par) +{ + uint32_t filt; + int i; + + /* wait for the BLT engine to stop being busy */ + do { + i = read_gp(par, GP_BLT_STATUS); + } while ((i & GP_BLT_STATUS_PB) || !(i & GP_BLT_STATUS_CE)); + + /* save MSRs */ + rdmsrl(MSR_LX_MSR_PADSEL, par->msr.padsel); + rdmsrl(MSR_GLCP_DOTPLL, par->msr.dotpll); + rdmsrl(MSR_LX_GLD_MSR_CONFIG, par->msr.dfglcfg); + rdmsrl(MSR_LX_SPARE_MSR, par->msr.dcspare); + + write_dc(par, DC_UNLOCK, DC_UNLOCK_UNLOCK); + + /* save registers */ + memcpy(par->gp, par->gp_regs, sizeof(par->gp)); + memcpy(par->dc, par->dc_regs, sizeof(par->dc)); + memcpy(par->vp, par->vp_regs, sizeof(par->vp)); + memcpy(par->fp, par->vp_regs + VP_FP_START, sizeof(par->fp)); + + /* save the palette */ + write_dc(par, DC_PAL_ADDRESS, 0); + for (i = 0; i < ARRAY_SIZE(par->pal); i++) + par->pal[i] = read_dc(par, DC_PAL_DATA); + + /* save the horizontal filter coefficients */ + filt = par->dc[DC_IRQ_FILT_CTL] | DC_IRQ_FILT_CTL_H_FILT_SEL; + for (i = 0; i < ARRAY_SIZE(par->hcoeff); i += 2) { + write_dc(par, DC_IRQ_FILT_CTL, (filt & 0xffffff00) | i); + par->hcoeff[i] = read_dc(par, DC_FILT_COEFF1); + par->hcoeff[i + 1] = read_dc(par, DC_FILT_COEFF2); + } + + /* save the vertical filter coefficients */ + filt &= ~DC_IRQ_FILT_CTL_H_FILT_SEL; + for (i = 0; i < ARRAY_SIZE(par->vcoeff); i++) { + write_dc(par, DC_IRQ_FILT_CTL, (filt & 0xffffff00) | i); + par->vcoeff[i] = read_dc(par, DC_FILT_COEFF1); + } + + /* save video coeff ram */ + memcpy(par->vp_coeff, par->vp_regs + VP_VCR, sizeof(par->vp_coeff)); +} + +static void lx_restore_gfx_proc(struct lxfb_par *par) +{ + int i; + + /* a bunch of registers require GP_RASTER_MODE to be set first */ + write_gp(par, GP_RASTER_MODE, par->gp[GP_RASTER_MODE]); + + for (i = 0; i < ARRAY_SIZE(par->gp); i++) { + switch (i) { + case GP_RASTER_MODE: + case GP_VECTOR_MODE: + case GP_BLT_MODE: + case GP_BLT_STATUS: + case GP_HST_SRC: + /* FIXME: restore LUT data */ + case GP_LUT_INDEX: + case GP_LUT_DATA: + /* don't restore these registers */ + break; + + default: + write_gp(par, i, par->gp[i]); + } + } +} + +static void lx_restore_display_ctlr(struct lxfb_par *par) +{ + uint32_t filt; + int i; + + wrmsrl(MSR_LX_SPARE_MSR, par->msr.dcspare); + + for (i = 0; i < ARRAY_SIZE(par->dc); i++) { + switch (i) { + case DC_UNLOCK: + /* unlock the DC; runs first */ + write_dc(par, DC_UNLOCK, DC_UNLOCK_UNLOCK); + break; + + case DC_GENERAL_CFG: + case DC_DISPLAY_CFG: + /* disable all while restoring */ + write_dc(par, i, 0); + break; + + case DC_DV_CTL: + /* set all ram to dirty */ + write_dc(par, i, par->dc[i] | DC_DV_CTL_CLEAR_DV_RAM); + + case DC_RSVD_1: + case DC_RSVD_2: + case DC_RSVD_3: + case DC_LINE_CNT: + case DC_PAL_ADDRESS: + case DC_PAL_DATA: + case DC_DFIFO_DIAG: + case DC_CFIFO_DIAG: + case DC_FILT_COEFF1: + case DC_FILT_COEFF2: + case DC_RSVD_4: + case DC_RSVD_5: + /* don't restore these registers */ + break; + + default: + write_dc(par, i, par->dc[i]); + } + } + + /* restore the palette */ + write_dc(par, DC_PAL_ADDRESS, 0); + for (i = 0; i < ARRAY_SIZE(par->pal); i++) + write_dc(par, DC_PAL_DATA, par->pal[i]); + + /* restore the horizontal filter coefficients */ + filt = par->dc[DC_IRQ_FILT_CTL] | DC_IRQ_FILT_CTL_H_FILT_SEL; + for (i = 0; i < ARRAY_SIZE(par->hcoeff); i += 2) { + write_dc(par, DC_IRQ_FILT_CTL, (filt & 0xffffff00) | i); + write_dc(par, DC_FILT_COEFF1, par->hcoeff[i]); + write_dc(par, DC_FILT_COEFF2, par->hcoeff[i + 1]); + } + + /* restore the vertical filter coefficients */ + filt &= ~DC_IRQ_FILT_CTL_H_FILT_SEL; + for (i = 0; i < ARRAY_SIZE(par->vcoeff); i++) { + write_dc(par, DC_IRQ_FILT_CTL, (filt & 0xffffff00) | i); + write_dc(par, DC_FILT_COEFF1, par->vcoeff[i]); + } +} + +static void lx_restore_video_proc(struct lxfb_par *par) +{ + int i; + + wrmsrl(MSR_LX_GLD_MSR_CONFIG, par->msr.dfglcfg); + wrmsrl(MSR_LX_MSR_PADSEL, par->msr.padsel); + + for (i = 0; i < ARRAY_SIZE(par->vp); i++) { + switch (i) { + case VP_VCFG: + case VP_DCFG: + case VP_PAR: + case VP_PDR: + case VP_CCS: + case VP_RSVD_0: + /* case VP_VDC: */ /* why should this not be restored? */ + case VP_RSVD_1: + case VP_CRC32: + /* don't restore these registers */ + break; + + default: + write_vp(par, i, par->vp[i]); + } + } + + /* restore video coeff ram */ + memcpy(par->vp_regs + VP_VCR, par->vp_coeff, sizeof(par->vp_coeff)); +} + +static void lx_restore_regs(struct lxfb_par *par) +{ + int i; + + lx_set_dotpll((u32) (par->msr.dotpll >> 32)); + lx_restore_gfx_proc(par); + lx_restore_display_ctlr(par); + lx_restore_video_proc(par); + + /* Flat Panel */ + for (i = 0; i < ARRAY_SIZE(par->fp); i++) { + switch (i) { + case FP_PM: + case FP_RSVD_0: + case FP_RSVD_1: + case FP_RSVD_2: + case FP_RSVD_3: + case FP_RSVD_4: + /* don't restore these registers */ + break; + + default: + write_fp(par, i, par->fp[i]); + } + } + + /* control the panel */ + if (par->fp[FP_PM] & FP_PM_P) { + /* power on the panel if not already power{ed,ing} on */ + if (!(read_fp(par, FP_PM) & + (FP_PM_PANEL_ON|FP_PM_PANEL_PWR_UP))) + write_fp(par, FP_PM, par->fp[FP_PM]); + } else { + /* power down the panel if not already power{ed,ing} down */ + if (!(read_fp(par, FP_PM) & + (FP_PM_PANEL_OFF|FP_PM_PANEL_PWR_DOWN))) + write_fp(par, FP_PM, par->fp[FP_PM]); + } + + /* turn everything on */ + write_vp(par, VP_VCFG, par->vp[VP_VCFG]); + write_vp(par, VP_DCFG, par->vp[VP_DCFG]); + write_dc(par, DC_DISPLAY_CFG, par->dc[DC_DISPLAY_CFG]); + /* do this last; it will enable the FIFO load */ + write_dc(par, DC_GENERAL_CFG, par->dc[DC_GENERAL_CFG]); + + /* lock the door behind us */ + write_dc(par, DC_UNLOCK, DC_UNLOCK_LOCK); +} + +int lx_powerdown(struct fb_info *info) +{ + struct lxfb_par *par = info->par; + + if (par->powered_down) + return 0; + + lx_save_regs(par); + lx_graphics_disable(info); + + par->powered_down = 1; + return 0; +} + +int lx_powerup(struct fb_info *info) +{ + struct lxfb_par *par = info->par; + + if (!par->powered_down) + return 0; + + lx_restore_regs(par); + + par->powered_down = 0; + return 0; +} + +#endif diff --git a/drivers/video/geode/suspend_gx.c b/drivers/video/geode/suspend_gx.c new file mode 100644 index 000000000000..9aff32ef8bb6 --- /dev/null +++ b/drivers/video/geode/suspend_gx.c @@ -0,0 +1,267 @@ +/* + * Copyright (C) 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. + */ +#include <linux/fb.h> +#include <asm/io.h> +#include <asm/msr.h> +#include <asm/geode.h> +#include <asm/delay.h> + +#include "gxfb.h" + +#ifdef CONFIG_PM + +static void gx_save_regs(struct gxfb_par *par) +{ + int i; + + /* wait for the BLT engine to stop being busy */ + do { + i = read_gp(par, GP_BLT_STATUS); + } while (i & (GP_BLT_STATUS_BLT_PENDING | GP_BLT_STATUS_BLT_BUSY)); + + /* save MSRs */ + rdmsrl(MSR_GX_MSR_PADSEL, par->msr.padsel); + rdmsrl(MSR_GLCP_DOTPLL, par->msr.dotpll); + + write_dc(par, DC_UNLOCK, DC_UNLOCK_UNLOCK); + + /* save registers */ + memcpy(par->gp, par->gp_regs, sizeof(par->gp)); + memcpy(par->dc, par->dc_regs, sizeof(par->dc)); + memcpy(par->vp, par->vid_regs, sizeof(par->vp)); + memcpy(par->fp, par->vid_regs + VP_FP_START, sizeof(par->fp)); + + /* save the palette */ + write_dc(par, DC_PAL_ADDRESS, 0); + for (i = 0; i < ARRAY_SIZE(par->pal); i++) + par->pal[i] = read_dc(par, DC_PAL_DATA); +} + +static void gx_set_dotpll(uint32_t dotpll_hi) +{ + uint32_t dotpll_lo; + int i; + + rdmsrl(MSR_GLCP_DOTPLL, dotpll_lo); + dotpll_lo |= MSR_GLCP_DOTPLL_DOTRESET; + dotpll_lo &= ~MSR_GLCP_DOTPLL_BYPASS; + wrmsr(MSR_GLCP_DOTPLL, dotpll_lo, dotpll_hi); + + /* wait for the PLL to lock */ + for (i = 0; i < 200; i++) { + rdmsrl(MSR_GLCP_DOTPLL, dotpll_lo); + if (dotpll_lo & MSR_GLCP_DOTPLL_LOCK) + break; + udelay(1); + } + + /* PLL set, unlock */ + dotpll_lo &= ~MSR_GLCP_DOTPLL_DOTRESET; + wrmsr(MSR_GLCP_DOTPLL, dotpll_lo, dotpll_hi); +} + +static void gx_restore_gfx_proc(struct gxfb_par *par) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(par->gp); i++) { + switch (i) { + case GP_VECTOR_MODE: + case GP_BLT_MODE: + case GP_BLT_STATUS: + case GP_HST_SRC: + /* don't restore these registers */ + break; + default: + write_gp(par, i, par->gp[i]); + } + } +} + +static void gx_restore_display_ctlr(struct gxfb_par *par) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(par->dc); i++) { + switch (i) { + case DC_UNLOCK: + /* unlock the DC; runs first */ + write_dc(par, DC_UNLOCK, DC_UNLOCK_UNLOCK); + break; + + case DC_GENERAL_CFG: + /* write without the enables */ + write_dc(par, i, par->dc[i] & ~(DC_GENERAL_CFG_VIDE | + DC_GENERAL_CFG_ICNE | + DC_GENERAL_CFG_CURE | + DC_GENERAL_CFG_DFLE)); + break; + + case DC_DISPLAY_CFG: + /* write without the enables */ + write_dc(par, i, par->dc[i] & ~(DC_DISPLAY_CFG_VDEN | + DC_DISPLAY_CFG_GDEN | + DC_DISPLAY_CFG_TGEN)); + break; + + case DC_RSVD_0: + case DC_RSVD_1: + case DC_RSVD_2: + case DC_RSVD_3: + case DC_RSVD_4: + case DC_LINE_CNT: + case DC_PAL_ADDRESS: + case DC_PAL_DATA: + case DC_DFIFO_DIAG: + case DC_CFIFO_DIAG: + case DC_RSVD_5: + /* don't restore these registers */ + break; + default: + write_dc(par, i, par->dc[i]); + } + } + + /* restore the palette */ + write_dc(par, DC_PAL_ADDRESS, 0); + for (i = 0; i < ARRAY_SIZE(par->pal); i++) + write_dc(par, DC_PAL_DATA, par->pal[i]); +} + +static void gx_restore_video_proc(struct gxfb_par *par) +{ + int i; + + wrmsrl(MSR_GX_MSR_PADSEL, par->msr.padsel); + + for (i = 0; i < ARRAY_SIZE(par->vp); i++) { + switch (i) { + case VP_VCFG: + /* don't enable video yet */ + write_vp(par, i, par->vp[i] & ~VP_VCFG_VID_EN); + break; + + case VP_DCFG: + /* don't enable CRT yet */ + write_vp(par, i, par->vp[i] & + ~(VP_DCFG_DAC_BL_EN | VP_DCFG_VSYNC_EN | + VP_DCFG_HSYNC_EN | VP_DCFG_CRT_EN)); + break; + + case VP_GAR: + case VP_GDR: + case VP_RSVD_0: + case VP_RSVD_1: + case VP_RSVD_2: + case VP_RSVD_3: + case VP_CRC32: + case VP_AWT: + case VP_VTM: + /* don't restore these registers */ + break; + default: + write_vp(par, i, par->vp[i]); + } + } +} + +static void gx_restore_regs(struct gxfb_par *par) +{ + int i; + + gx_set_dotpll((uint32_t) (par->msr.dotpll >> 32)); + gx_restore_gfx_proc(par); + gx_restore_display_ctlr(par); + gx_restore_video_proc(par); + + /* Flat Panel */ + for (i = 0; i < ARRAY_SIZE(par->fp); i++) { + if (i != FP_PM && i != FP_RSVD_0) + write_fp(par, i, par->fp[i]); + } +} + +static void gx_disable_graphics(struct gxfb_par *par) +{ + /* shut down the engine */ + write_vp(par, VP_VCFG, par->vp[VP_VCFG] & ~VP_VCFG_VID_EN); + write_vp(par, VP_DCFG, par->vp[VP_DCFG] & ~(VP_DCFG_DAC_BL_EN | + VP_DCFG_VSYNC_EN | VP_DCFG_HSYNC_EN | VP_DCFG_CRT_EN)); + + /* turn off the flat panel */ + write_fp(par, FP_PM, par->fp[FP_PM] & ~FP_PM_P); + + + /* turn off display */ + write_dc(par, DC_UNLOCK, DC_UNLOCK_UNLOCK); + write_dc(par, DC_GENERAL_CFG, par->dc[DC_GENERAL_CFG] & + ~(DC_GENERAL_CFG_VIDE | DC_GENERAL_CFG_ICNE | + DC_GENERAL_CFG_CURE | DC_GENERAL_CFG_DFLE)); + write_dc(par, DC_DISPLAY_CFG, par->dc[DC_DISPLAY_CFG] & + ~(DC_DISPLAY_CFG_VDEN | DC_DISPLAY_CFG_GDEN | + DC_DISPLAY_CFG_TGEN)); + write_dc(par, DC_UNLOCK, DC_UNLOCK_LOCK); +} + +static void gx_enable_graphics(struct gxfb_par *par) +{ + uint32_t fp; + + fp = read_fp(par, FP_PM); + if (par->fp[FP_PM] & FP_PM_P) { + /* power on the panel if not already power{ed,ing} on */ + if (!(fp & (FP_PM_PANEL_ON|FP_PM_PANEL_PWR_UP))) + write_fp(par, FP_PM, par->fp[FP_PM]); + } else { + /* power down the panel if not already power{ed,ing} down */ + if (!(fp & (FP_PM_PANEL_OFF|FP_PM_PANEL_PWR_DOWN))) + write_fp(par, FP_PM, par->fp[FP_PM]); + } + + /* turn everything on */ + write_vp(par, VP_VCFG, par->vp[VP_VCFG]); + write_vp(par, VP_DCFG, par->vp[VP_DCFG]); + write_dc(par, DC_DISPLAY_CFG, par->dc[DC_DISPLAY_CFG]); + /* do this last; it will enable the FIFO load */ + write_dc(par, DC_GENERAL_CFG, par->dc[DC_GENERAL_CFG]); + + /* lock the door behind us */ + write_dc(par, DC_UNLOCK, DC_UNLOCK_LOCK); +} + +int gx_powerdown(struct fb_info *info) +{ + struct gxfb_par *par = info->par; + + if (par->powered_down) + return 0; + + gx_save_regs(par); + gx_disable_graphics(par); + + par->powered_down = 1; + return 0; +} + +int gx_powerup(struct fb_info *info) +{ + struct gxfb_par *par = info->par; + + if (!par->powered_down) + return 0; + + gx_restore_regs(par); + gx_enable_graphics(par); + + par->powered_down = 0; + return 0; +} + +#endif diff --git a/drivers/video/geode/video_gx.c b/drivers/video/geode/video_gx.c index febf09c63492..b8d52a8360db 100644 --- a/drivers/video/geode/video_gx.c +++ b/drivers/video/geode/video_gx.c @@ -16,9 +16,9 @@ #include <asm/io.h> #include <asm/delay.h> #include <asm/msr.h> +#include <asm/geode.h> -#include "geodefb.h" -#include "video_gx.h" +#include "gxfb.h" /* @@ -117,7 +117,7 @@ static const struct gx_pll_entry gx_pll_table_14MHz[] = { { 4357, 0, 0x0000057D }, /* 229.5000 */ }; -static void gx_set_dclk_frequency(struct fb_info *info) +void gx_set_dclk_frequency(struct fb_info *info) { const struct gx_pll_entry *pll_table; int pll_table_len; @@ -178,110 +178,116 @@ static void gx_set_dclk_frequency(struct fb_info *info) static void gx_configure_tft(struct fb_info *info) { - struct geodefb_par *par = info->par; + struct gxfb_par *par = info->par; unsigned long val; unsigned long fp; /* Set up the DF pad select MSR */ - rdmsrl(GX_VP_MSR_PAD_SELECT, val); - val &= ~GX_VP_PAD_SELECT_MASK; - val |= GX_VP_PAD_SELECT_TFT; - wrmsrl(GX_VP_MSR_PAD_SELECT, val); + rdmsrl(MSR_GX_MSR_PADSEL, val); + val &= ~MSR_GX_MSR_PADSEL_MASK; + val |= MSR_GX_MSR_PADSEL_TFT; + wrmsrl(MSR_GX_MSR_PADSEL, val); /* Turn off the panel */ - fp = readl(par->vid_regs + GX_FP_PM); - fp &= ~GX_FP_PM_P; - writel(fp, par->vid_regs + GX_FP_PM); + fp = read_fp(par, FP_PM); + fp &= ~FP_PM_P; + write_fp(par, FP_PM, fp); /* Set timing 1 */ - fp = readl(par->vid_regs + GX_FP_PT1); - fp &= GX_FP_PT1_VSIZE_MASK; - fp |= info->var.yres << GX_FP_PT1_VSIZE_SHIFT; - writel(fp, par->vid_regs + GX_FP_PT1); + fp = read_fp(par, FP_PT1); + fp &= FP_PT1_VSIZE_MASK; + fp |= info->var.yres << FP_PT1_VSIZE_SHIFT; + write_fp(par, FP_PT1, fp); /* Timing 2 */ /* Set bits that are always on for TFT */ fp = 0x0F100000; - /* Add sync polarity */ + /* Configure sync polarity */ if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT)) - fp |= GX_FP_PT2_VSP; + fp |= FP_PT2_VSP; if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT)) - fp |= GX_FP_PT2_HSP; + fp |= FP_PT2_HSP; - writel(fp, par->vid_regs + GX_FP_PT2); + write_fp(par, FP_PT2, fp); /* Set the dither control */ - writel(0x70, par->vid_regs + GX_FP_DFC); + write_fp(par, FP_DFC, FP_DFC_NFI); /* Enable the FP data and power (in case the BIOS didn't) */ - fp = readl(par->vid_regs + GX_DCFG); - fp |= GX_DCFG_FP_PWR_EN | GX_DCFG_FP_DATA_EN; - writel(fp, par->vid_regs + GX_DCFG); + fp = read_vp(par, VP_DCFG); + fp |= VP_DCFG_FP_PWR_EN | VP_DCFG_FP_DATA_EN; + write_vp(par, VP_DCFG, fp); /* Unblank the panel */ - fp = readl(par->vid_regs + GX_FP_PM); - fp |= GX_FP_PM_P; - writel(fp, par->vid_regs + GX_FP_PM); + fp = read_fp(par, FP_PM); + fp |= FP_PM_P; + write_fp(par, FP_PM, fp); } -static void gx_configure_display(struct fb_info *info) +void gx_configure_display(struct fb_info *info) { - struct geodefb_par *par = info->par; + struct gxfb_par *par = info->par; u32 dcfg, misc; - /* Set up the MISC register */ - - misc = readl(par->vid_regs + GX_MISC); - - /* Power up the DAC */ - misc &= ~(GX_MISC_A_PWRDN | GX_MISC_DAC_PWRDN); - - /* Disable gamma correction */ - misc |= GX_MISC_GAM_EN; - - writel(misc, par->vid_regs + GX_MISC); - /* Write the display configuration */ - dcfg = readl(par->vid_regs + GX_DCFG); + dcfg = read_vp(par, VP_DCFG); /* Disable hsync and vsync */ - dcfg &= ~(GX_DCFG_VSYNC_EN | GX_DCFG_HSYNC_EN); - writel(dcfg, par->vid_regs + GX_DCFG); + dcfg &= ~(VP_DCFG_VSYNC_EN | VP_DCFG_HSYNC_EN); + write_vp(par, VP_DCFG, dcfg); /* Clear bits from existing mode. */ - dcfg &= ~(GX_DCFG_CRT_SYNC_SKW_MASK - | GX_DCFG_CRT_HSYNC_POL | GX_DCFG_CRT_VSYNC_POL - | GX_DCFG_VSYNC_EN | GX_DCFG_HSYNC_EN); + dcfg &= ~(VP_DCFG_CRT_SYNC_SKW + | VP_DCFG_CRT_HSYNC_POL | VP_DCFG_CRT_VSYNC_POL + | VP_DCFG_VSYNC_EN | VP_DCFG_HSYNC_EN); /* Set default sync skew. */ - dcfg |= GX_DCFG_CRT_SYNC_SKW_DFLT; + dcfg |= VP_DCFG_CRT_SYNC_SKW_DEFAULT; /* Enable hsync and vsync. */ - dcfg |= GX_DCFG_HSYNC_EN | GX_DCFG_VSYNC_EN; + dcfg |= VP_DCFG_HSYNC_EN | VP_DCFG_VSYNC_EN; - /* Sync polarities. */ - if (info->var.sync & FB_SYNC_HOR_HIGH_ACT) - dcfg |= GX_DCFG_CRT_HSYNC_POL; - if (info->var.sync & FB_SYNC_VERT_HIGH_ACT) - dcfg |= GX_DCFG_CRT_VSYNC_POL; + misc = read_vp(par, VP_MISC); + + /* Disable gamma correction */ + misc |= VP_MISC_GAM_EN; + + if (par->enable_crt) { + + /* Power up the CRT DACs */ + misc &= ~(VP_MISC_APWRDN | VP_MISC_DACPWRDN); + write_vp(par, VP_MISC, misc); + + /* Only change the sync polarities if we are running + * in CRT mode. The FP polarities will be handled in + * gxfb_configure_tft */ + if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT)) + dcfg |= VP_DCFG_CRT_HSYNC_POL; + if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT)) + dcfg |= VP_DCFG_CRT_VSYNC_POL; + } else { + /* Power down the CRT DACs if in FP mode */ + misc |= (VP_MISC_APWRDN | VP_MISC_DACPWRDN); + write_vp(par, VP_MISC, misc); + } /* Enable the display logic */ /* Set up the DACS to blank normally */ - dcfg |= GX_DCFG_CRT_EN | GX_DCFG_DAC_BL_EN; + dcfg |= VP_DCFG_CRT_EN | VP_DCFG_DAC_BL_EN; /* Enable the external DAC VREF? */ - writel(dcfg, par->vid_regs + GX_DCFG); + write_vp(par, VP_DCFG, dcfg); /* Set up the flat panel (if it is enabled) */ @@ -289,59 +295,55 @@ static void gx_configure_display(struct fb_info *info) gx_configure_tft(info); } -static int gx_blank_display(struct fb_info *info, int blank_mode) +int gx_blank_display(struct fb_info *info, int blank_mode) { - struct geodefb_par *par = info->par; + struct gxfb_par *par = info->par; u32 dcfg, fp_pm; - int blank, hsync, vsync; + int blank, hsync, vsync, crt; /* CRT power saving modes. */ switch (blank_mode) { case FB_BLANK_UNBLANK: - blank = 0; hsync = 1; vsync = 1; + blank = 0; hsync = 1; vsync = 1; crt = 1; break; case FB_BLANK_NORMAL: - blank = 1; hsync = 1; vsync = 1; + blank = 1; hsync = 1; vsync = 1; crt = 1; break; case FB_BLANK_VSYNC_SUSPEND: - blank = 1; hsync = 1; vsync = 0; + blank = 1; hsync = 1; vsync = 0; crt = 1; break; case FB_BLANK_HSYNC_SUSPEND: - blank = 1; hsync = 0; vsync = 1; + blank = 1; hsync = 0; vsync = 1; crt = 1; break; case FB_BLANK_POWERDOWN: - blank = 1; hsync = 0; vsync = 0; + blank = 1; hsync = 0; vsync = 0; crt = 0; break; default: return -EINVAL; } - dcfg = readl(par->vid_regs + GX_DCFG); - dcfg &= ~(GX_DCFG_DAC_BL_EN - | GX_DCFG_HSYNC_EN | GX_DCFG_VSYNC_EN); + dcfg = read_vp(par, VP_DCFG); + dcfg &= ~(VP_DCFG_DAC_BL_EN | VP_DCFG_HSYNC_EN | VP_DCFG_VSYNC_EN | + VP_DCFG_CRT_EN); if (!blank) - dcfg |= GX_DCFG_DAC_BL_EN; + dcfg |= VP_DCFG_DAC_BL_EN; if (hsync) - dcfg |= GX_DCFG_HSYNC_EN; + dcfg |= VP_DCFG_HSYNC_EN; if (vsync) - dcfg |= GX_DCFG_VSYNC_EN; - writel(dcfg, par->vid_regs + GX_DCFG); + dcfg |= VP_DCFG_VSYNC_EN; + if (crt) + dcfg |= VP_DCFG_CRT_EN; + write_vp(par, VP_DCFG, dcfg); /* Power on/off flat panel. */ if (par->enable_crt == 0) { - fp_pm = readl(par->vid_regs + GX_FP_PM); + fp_pm = read_fp(par, FP_PM); if (blank_mode == FB_BLANK_POWERDOWN) - fp_pm &= ~GX_FP_PM_P; + fp_pm &= ~FP_PM_P; else - fp_pm |= GX_FP_PM_P; - writel(fp_pm, par->vid_regs + GX_FP_PM); + fp_pm |= FP_PM_P; + write_fp(par, FP_PM, fp_pm); } return 0; } - -struct geode_vid_ops gx_vid_ops = { - .set_dclk = gx_set_dclk_frequency, - .configure_display = gx_configure_display, - .blank_display = gx_blank_display, -}; diff --git a/drivers/video/geode/video_gx.h b/drivers/video/geode/video_gx.h deleted file mode 100644 index ce28d8f382dc..000000000000 --- a/drivers/video/geode/video_gx.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Geode GX video device - * - * Copyright (C) 2006 Arcom Control Systems Ltd. - * - * 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 __VIDEO_GX_H__ -#define __VIDEO_GX_H__ - -extern struct geode_vid_ops gx_vid_ops; - -/* GX Flatpanel control MSR */ -#define GX_VP_MSR_PAD_SELECT 0xC0002011 -#define GX_VP_PAD_SELECT_MASK 0x3FFFFFFF -#define GX_VP_PAD_SELECT_TFT 0x1FFFFFFF - -/* Geode GX video processor registers */ - -#define GX_DCFG 0x0008 -# define GX_DCFG_CRT_EN 0x00000001 -# define GX_DCFG_HSYNC_EN 0x00000002 -# define GX_DCFG_VSYNC_EN 0x00000004 -# define GX_DCFG_DAC_BL_EN 0x00000008 -# define GX_DCFG_FP_PWR_EN 0x00000040 -# define GX_DCFG_FP_DATA_EN 0x00000080 -# define GX_DCFG_CRT_HSYNC_POL 0x00000100 -# define GX_DCFG_CRT_VSYNC_POL 0x00000200 -# define GX_DCFG_CRT_SYNC_SKW_MASK 0x0001C000 -# define GX_DCFG_CRT_SYNC_SKW_DFLT 0x00010000 -# define GX_DCFG_VG_CK 0x00100000 -# define GX_DCFG_GV_GAM 0x00200000 -# define GX_DCFG_DAC_VREF 0x04000000 - -/* Geode GX MISC video configuration */ - -#define GX_MISC 0x50 -#define GX_MISC_GAM_EN 0x00000001 -#define GX_MISC_DAC_PWRDN 0x00000400 -#define GX_MISC_A_PWRDN 0x00000800 - -/* Geode GX flat panel display control registers */ - -#define GX_FP_PT1 0x0400 -#define GX_FP_PT1_VSIZE_MASK 0x7FF0000 -#define GX_FP_PT1_VSIZE_SHIFT 16 - -#define GX_FP_PT2 0x408 -#define GX_FP_PT2_VSP (1 << 23) -#define GX_FP_PT2_HSP (1 << 22) - -#define GX_FP_PM 0x410 -# define GX_FP_PM_P 0x01000000 - -#define GX_FP_DFC 0x418 - -/* Geode GX clock control MSRs */ - -#define MSR_GLCP_SYS_RSTPLL 0x4c000014 -# define MSR_GLCP_SYS_RSTPLL_DOTPREDIV2 (0x0000000000000002ull) -# define MSR_GLCP_SYS_RSTPLL_DOTPREMULT2 (0x0000000000000004ull) -# define MSR_GLCP_SYS_RSTPLL_DOTPOSTDIV3 (0x0000000000000008ull) - -#define MSR_GLCP_DOTPLL 0x4c000015 -# define MSR_GLCP_DOTPLL_DOTRESET (0x0000000000000001ull) -# define MSR_GLCP_DOTPLL_BYPASS (0x0000000000008000ull) -# define MSR_GLCP_DOTPLL_LOCK (0x0000000002000000ull) - -#endif /* !__VIDEO_GX_H__ */ diff --git a/drivers/video/gxt4500.c b/drivers/video/gxt4500.c index e92337bef50d..564557792bed 100644 --- a/drivers/video/gxt4500.c +++ b/drivers/video/gxt4500.c @@ -238,7 +238,7 @@ static int calc_pll(int period_ps, struct gxt4500_par *par) for (pdiv1 = 1; pdiv1 <= 8; ++pdiv1) { for (pdiv2 = 1; pdiv2 <= pdiv1; ++pdiv2) { postdiv = pdiv1 * pdiv2; - pll_period = (period_ps + postdiv - 1) / postdiv; + pll_period = DIV_ROUND_UP(period_ps, postdiv); /* keep pll in range 350..600 MHz */ if (pll_period < 1666 || pll_period > 2857) continue; diff --git a/drivers/video/hecubafb.c b/drivers/video/hecubafb.c index 94e0df8a6f60..0b4bffbe67c8 100644 --- a/drivers/video/hecubafb.c +++ b/drivers/video/hecubafb.c @@ -1,5 +1,5 @@ /* - * linux/drivers/video/hecubafb.c -- FB driver for Hecuba controller + * linux/drivers/video/hecubafb.c -- FB driver for Hecuba/Apollo controller * * Copyright (C) 2006, Jaya Kumar * This work was sponsored by CIS(M) Sdn Bhd @@ -17,18 +17,13 @@ * values. There are other commands that the display is capable of, * beyond the 5 used here but they are more complex. * - * This driver is written to be used with the Hecuba display controller - * board, and tested with the EInk 800x600 display in 1 bit mode. - * The interface between Hecuba and the host is TTL based GPIO. The - * GPIO requirements are 8 writable data lines and 6 lines for control. - * Only 4 of the controls are actually used here but 6 for future use. - * The driver requires the IO addresses for data and control GPIO at - * load time. It is also possible to use this display with a standard - * PC parallel port. + * This driver is written to be used with the Hecuba display architecture. + * The actual display chip is called Apollo and the interface electronics + * it needs is called Hecuba. * - * General notes: - * - User must set hecubafb_enable=1 to enable it - * - User must set dio_addr=0xIOADDR cio_addr=0xIOADDR c2io_addr=0xIOADDR + * It is intended to be architecture independent. A board specific driver + * must be used to perform all the physical IO interactions. An example + * is provided as n411.c * */ @@ -47,34 +42,12 @@ #include <linux/list.h> #include <linux/uaccess.h> -/* Apollo controller specific defines */ -#define APOLLO_START_NEW_IMG 0xA0 -#define APOLLO_STOP_IMG_DATA 0xA1 -#define APOLLO_DISPLAY_IMG 0xA2 -#define APOLLO_ERASE_DISPLAY 0xA3 -#define APOLLO_INIT_DISPLAY 0xA4 - -/* Hecuba interface specific defines */ -/* WUP is inverted, CD is inverted, DS is inverted */ -#define HCB_NWUP_BIT 0x01 -#define HCB_NDS_BIT 0x02 -#define HCB_RW_BIT 0x04 -#define HCB_NCD_BIT 0x08 -#define HCB_ACK_BIT 0x80 +#include <video/hecubafb.h> /* Display specific information */ #define DPY_W 600 #define DPY_H 800 -struct hecubafb_par { - unsigned long dio_addr; - unsigned long cio_addr; - unsigned long c2io_addr; - unsigned char ctl; - struct fb_info *info; - unsigned int irq; -}; - static struct fb_fix_screeninfo hecubafb_fix __devinitdata = { .id = "hecubafb", .type = FB_TYPE_PACKED_PIXELS, @@ -82,6 +55,7 @@ static struct fb_fix_screeninfo hecubafb_fix __devinitdata = { .xpanstep = 0, .ypanstep = 0, .ywrapstep = 0, + .line_length = DPY_W, .accel = FB_ACCEL_NONE, }; @@ -94,136 +68,51 @@ static struct fb_var_screeninfo hecubafb_var __devinitdata = { .nonstd = 1, }; -static unsigned long dio_addr; -static unsigned long cio_addr; -static unsigned long c2io_addr; -static unsigned long splashval; -static unsigned int nosplash; -static unsigned int hecubafb_enable; -static unsigned int irq; - -static DECLARE_WAIT_QUEUE_HEAD(hecubafb_waitq); - -static void hcb_set_ctl(struct hecubafb_par *par) -{ - outb(par->ctl, par->cio_addr); -} - -static unsigned char hcb_get_ctl(struct hecubafb_par *par) -{ - return inb(par->c2io_addr); -} - -static void hcb_set_data(struct hecubafb_par *par, unsigned char value) -{ - outb(value, par->dio_addr); -} - -static int __devinit apollo_init_control(struct hecubafb_par *par) -{ - unsigned char ctl; - /* for init, we want the following setup to be set: - WUP = lo - ACK = hi - DS = hi - RW = hi - CD = lo - */ - - /* write WUP to lo, DS to hi, RW to hi, CD to lo */ - par->ctl = HCB_NWUP_BIT | HCB_RW_BIT | HCB_NCD_BIT ; - par->ctl &= ~HCB_NDS_BIT; - hcb_set_ctl(par); - - /* check ACK is not lo */ - ctl = hcb_get_ctl(par); - if ((ctl & HCB_ACK_BIT)) { - printk(KERN_ERR "Fail because ACK is already low\n"); - return -ENXIO; - } - - return 0; -} - -static void hcb_wait_for_ack(struct hecubafb_par *par) -{ - - int timeout; - unsigned char ctl; - - timeout=500; - do { - ctl = hcb_get_ctl(par); - if ((ctl & HCB_ACK_BIT)) - return; - udelay(1); - } while (timeout--); - printk(KERN_ERR "timed out waiting for ack\n"); -} - -static void hcb_wait_for_ack_clear(struct hecubafb_par *par) -{ - - int timeout; - unsigned char ctl; - - timeout=500; - do { - ctl = hcb_get_ctl(par); - if (!(ctl & HCB_ACK_BIT)) - return; - udelay(1); - } while (timeout--); - printk(KERN_ERR "timed out waiting for clear\n"); -} +/* main hecubafb functions */ static void apollo_send_data(struct hecubafb_par *par, unsigned char data) { /* set data */ - hcb_set_data(par, data); + par->board->set_data(par, data); /* set DS low */ - par->ctl |= HCB_NDS_BIT; - hcb_set_ctl(par); + par->board->set_ctl(par, HCB_DS_BIT, 0); - hcb_wait_for_ack(par); + /* wait for ack */ + par->board->wait_for_ack(par, 0); /* set DS hi */ - par->ctl &= ~(HCB_NDS_BIT); - hcb_set_ctl(par); + par->board->set_ctl(par, HCB_DS_BIT, 1); - hcb_wait_for_ack_clear(par); + /* wait for ack to clear */ + par->board->wait_for_ack(par, 1); } static void apollo_send_command(struct hecubafb_par *par, unsigned char data) { /* command so set CD to high */ - par->ctl &= ~(HCB_NCD_BIT); - hcb_set_ctl(par); + par->board->set_ctl(par, HCB_CD_BIT, 1); /* actually strobe with command */ apollo_send_data(par, data); /* clear CD back to low */ - par->ctl |= (HCB_NCD_BIT); - hcb_set_ctl(par); + par->board->set_ctl(par, HCB_CD_BIT, 0); } -/* main hecubafb functions */ - static void hecubafb_dpy_update(struct hecubafb_par *par) { int i; unsigned char *buf = (unsigned char __force *)par->info->screen_base; - apollo_send_command(par, 0xA0); + apollo_send_command(par, APOLLO_START_NEW_IMG); for (i=0; i < (DPY_W*DPY_H/8); i++) { apollo_send_data(par, *(buf++)); } - apollo_send_command(par, 0xA1); - apollo_send_command(par, 0xA2); + apollo_send_command(par, APOLLO_STOP_IMG_DATA); + apollo_send_command(par, APOLLO_DISPLAY_IMG); } /* this is called back from the deferred io workqueue */ @@ -270,41 +159,43 @@ static void hecubafb_imageblit(struct fb_info *info, static ssize_t hecubafb_write(struct fb_info *info, const char __user *buf, size_t count, loff_t *ppos) { - unsigned long p; - int err=-EINVAL; - struct hecubafb_par *par; - unsigned int xres; - unsigned int fbmemlength; + struct hecubafb_par *par = info->par; + unsigned long p = *ppos; + void *dst; + int err = 0; + unsigned long total_size; - p = *ppos; - par = info->par; - xres = info->var.xres; - fbmemlength = (xres * info->var.yres)/8; + if (info->state != FBINFO_STATE_RUNNING) + return -EPERM; - if (p > fbmemlength) - return -ENOSPC; + total_size = info->fix.smem_len; - err = 0; - if ((count + p) > fbmemlength) { - count = fbmemlength - p; - err = -ENOSPC; + if (p > total_size) + return -EFBIG; + + if (count > total_size) { + err = -EFBIG; + count = total_size; } - if (count) { - char *base_addr; + if (count + p > total_size) { + if (!err) + err = -ENOSPC; - base_addr = (char __force *)info->screen_base; - count -= copy_from_user(base_addr + p, buf, count); - *ppos += count; - err = -EFAULT; + count = total_size - p; } - hecubafb_dpy_update(par); + dst = (void __force *) (info->screen_base + p); + + if (copy_from_user(dst, buf, count)) + err = -EFAULT; - if (count) - return count; + if (!err) + *ppos += count; - return err; + hecubafb_dpy_update(par); + + return (err) ? err : count; } static struct fb_ops hecubafb_ops = { @@ -324,11 +215,21 @@ static struct fb_deferred_io hecubafb_defio = { static int __devinit hecubafb_probe(struct platform_device *dev) { struct fb_info *info; + struct hecuba_board *board; int retval = -ENOMEM; int videomemorysize; unsigned char *videomemory; struct hecubafb_par *par; + /* pick up board specific routines */ + board = dev->dev.platform_data; + if (!board) + return -EINVAL; + + /* try to count device specific driver, if can't, platform recalls */ + if (!try_module_get(board->owner)) + return -ENODEV; + videomemorysize = (DPY_W*DPY_H)/8; if (!(videomemory = vmalloc(videomemorysize))) @@ -338,9 +239,9 @@ static int __devinit hecubafb_probe(struct platform_device *dev) info = framebuffer_alloc(sizeof(struct hecubafb_par), &dev->dev); if (!info) - goto err; + goto err_fballoc; - info->screen_base = (char __iomem *) videomemory; + info->screen_base = (char __force __iomem *)videomemory; info->fbops = &hecubafb_ops; info->var = hecubafb_var; @@ -348,14 +249,10 @@ static int __devinit hecubafb_probe(struct platform_device *dev) info->fix.smem_len = videomemorysize; par = info->par; par->info = info; + par->board = board; + par->send_command = apollo_send_command; + par->send_data = apollo_send_data; - if (!dio_addr || !cio_addr || !c2io_addr) { - printk(KERN_WARNING "no IO addresses supplied\n"); - goto err1; - } - par->dio_addr = dio_addr; - par->cio_addr = cio_addr; - par->c2io_addr = c2io_addr; info->flags = FBINFO_FLAG_DEFAULT; info->fbdefio = &hecubafb_defio; @@ -363,7 +260,7 @@ static int __devinit hecubafb_probe(struct platform_device *dev) retval = register_framebuffer(info); if (retval < 0) - goto err1; + goto err_fbreg; platform_set_drvdata(dev, info); printk(KERN_INFO @@ -371,25 +268,16 @@ static int __devinit hecubafb_probe(struct platform_device *dev) info->node, videomemorysize >> 10); /* this inits the dpy */ - apollo_init_control(par); - - apollo_send_command(par, APOLLO_INIT_DISPLAY); - apollo_send_data(par, 0x81); - - /* have to wait while display resets */ - udelay(1000); - - /* if we were told to splash the screen, we just clear it */ - if (!nosplash) { - apollo_send_command(par, APOLLO_ERASE_DISPLAY); - apollo_send_data(par, splashval); - } + retval = par->board->init(par); + if (retval < 0) + goto err_fbreg; return 0; -err1: +err_fbreg: framebuffer_release(info); -err: +err_fballoc: vfree(videomemory); + module_put(board->owner); return retval; } @@ -398,9 +286,13 @@ static int __devexit hecubafb_remove(struct platform_device *dev) struct fb_info *info = platform_get_drvdata(dev); if (info) { + struct hecubafb_par *par = info->par; fb_deferred_io_cleanup(info); unregister_framebuffer(info); vfree((void __force *)info->screen_base); + if (par->board->remove) + par->board->remove(par); + module_put(par->board->owner); framebuffer_release(info); } return 0; @@ -410,62 +302,24 @@ static struct platform_driver hecubafb_driver = { .probe = hecubafb_probe, .remove = hecubafb_remove, .driver = { + .owner = THIS_MODULE, .name = "hecubafb", }, }; -static struct platform_device *hecubafb_device; - static int __init hecubafb_init(void) { - int ret; - - if (!hecubafb_enable) { - printk(KERN_ERR "Use hecubafb_enable to enable the device\n"); - return -ENXIO; - } - - ret = platform_driver_register(&hecubafb_driver); - if (!ret) { - hecubafb_device = platform_device_alloc("hecubafb", 0); - if (hecubafb_device) - ret = platform_device_add(hecubafb_device); - else - ret = -ENOMEM; - - if (ret) { - platform_device_put(hecubafb_device); - platform_driver_unregister(&hecubafb_driver); - } - } - return ret; - + return platform_driver_register(&hecubafb_driver); } static void __exit hecubafb_exit(void) { - platform_device_unregister(hecubafb_device); platform_driver_unregister(&hecubafb_driver); } -module_param(nosplash, uint, 0); -MODULE_PARM_DESC(nosplash, "Disable doing the splash screen"); -module_param(hecubafb_enable, uint, 0); -MODULE_PARM_DESC(hecubafb_enable, "Enable communication with Hecuba board"); -module_param(dio_addr, ulong, 0); -MODULE_PARM_DESC(dio_addr, "IO address for data, eg: 0x480"); -module_param(cio_addr, ulong, 0); -MODULE_PARM_DESC(cio_addr, "IO address for control, eg: 0x400"); -module_param(c2io_addr, ulong, 0); -MODULE_PARM_DESC(c2io_addr, "IO address for secondary control, eg: 0x408"); -module_param(splashval, ulong, 0); -MODULE_PARM_DESC(splashval, "Splash pattern: 0x00 is black, 0x01 is white"); -module_param(irq, uint, 0); -MODULE_PARM_DESC(irq, "IRQ for the Hecuba board"); - module_init(hecubafb_init); module_exit(hecubafb_exit); -MODULE_DESCRIPTION("fbdev driver for Hecuba board"); +MODULE_DESCRIPTION("fbdev driver for Hecuba/Apollo controller"); MODULE_AUTHOR("Jaya Kumar"); MODULE_LICENSE("GPL"); diff --git a/drivers/video/imsttfb.c b/drivers/video/imsttfb.c index 3ab91bf21576..15d50b9906ce 100644 --- a/drivers/video/imsttfb.c +++ b/drivers/video/imsttfb.c @@ -1151,8 +1151,10 @@ imsttfb_load_cursor_image(struct imstt_par *par, int width, int height, __u8 fgc par->cmap_regs[TVPCRDAT] = 0xff; eieio(); } par->cmap_regs[TVPCADRW] = 0x00; eieio(); - for (x = 0; x < 12; x++) - par->cmap_regs[TVPCDATA] = fgc; eieio(); + for (x = 0; x < 12; x++) { + par->cmap_regs[TVPCDATA] = fgc; + eieio(); + } } return 1; } @@ -1476,7 +1478,7 @@ imsttfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent) dp = pci_device_to_OF_node(pdev); if(dp) - printk(KERN_INFO "%s: OF name %s\n",__FUNCTION__, dp->name); + printk(KERN_INFO "%s: OF name %s\n",__func__, dp->name); else printk(KERN_ERR "imsttfb: no OF node for pci device\n"); #endif /* CONFIG_PPC_OF */ diff --git a/drivers/video/imxfb.c b/drivers/video/imxfb.c index 11609552a387..94e4d3ac1a05 100644 --- a/drivers/video/imxfb.c +++ b/drivers/video/imxfb.c @@ -415,7 +415,7 @@ static void imxfb_setup_gpio(struct imxfb_info *fbi) static int imxfb_suspend(struct platform_device *dev, pm_message_t state) { struct imxfb_info *fbi = platform_get_drvdata(dev); - pr_debug("%s\n",__FUNCTION__); + pr_debug("%s\n",__func__); imxfb_disable_controller(fbi); return 0; @@ -424,7 +424,7 @@ static int imxfb_suspend(struct platform_device *dev, pm_message_t state) static int imxfb_resume(struct platform_device *dev) { struct imxfb_info *fbi = platform_get_drvdata(dev); - pr_debug("%s\n",__FUNCTION__); + pr_debug("%s\n",__func__); imxfb_enable_controller(fbi); return 0; @@ -440,7 +440,7 @@ static int __init imxfb_init_fbinfo(struct device *dev) struct fb_info *info = dev_get_drvdata(dev); struct imxfb_info *fbi = info->par; - pr_debug("%s\n",__FUNCTION__); + pr_debug("%s\n",__func__); info->pseudo_palette = kmalloc( sizeof(u32) * 16, GFP_KERNEL); if (!info->pseudo_palette) diff --git a/drivers/video/intelfb/intelfb.h b/drivers/video/intelfb/intelfb.h index 836796177942..3325fbd68ab3 100644 --- a/drivers/video/intelfb/intelfb.h +++ b/drivers/video/intelfb/intelfb.h @@ -12,9 +12,9 @@ #endif /*** Version/name ***/ -#define INTELFB_VERSION "0.9.4" +#define INTELFB_VERSION "0.9.5" #define INTELFB_MODULE_NAME "intelfb" -#define SUPPORTED_CHIPSETS "830M/845G/852GM/855GM/865G/915G/915GM/945G/945GM" +#define SUPPORTED_CHIPSETS "830M/845G/852GM/855GM/865G/915G/915GM/945G/945GM/965G/965GM" /*** Debug/feature defines ***/ @@ -58,6 +58,8 @@ #define PCI_DEVICE_ID_INTEL_915GM 0x2592 #define PCI_DEVICE_ID_INTEL_945G 0x2772 #define PCI_DEVICE_ID_INTEL_945GM 0x27A2 +#define PCI_DEVICE_ID_INTEL_965G 0x29A2 +#define PCI_DEVICE_ID_INTEL_965GM 0x2A02 /* Size of MMIO region */ #define INTEL_REG_SIZE 0x80000 @@ -158,6 +160,8 @@ enum intel_chips { INTEL_915GM, INTEL_945G, INTEL_945GM, + INTEL_965G, + INTEL_965GM, }; struct intelfb_hwstate { @@ -358,7 +362,9 @@ struct intelfb_info { #define IS_I9XX(dinfo) (((dinfo)->chipset == INTEL_915G) || \ ((dinfo)->chipset == INTEL_915GM) || \ ((dinfo)->chipset == INTEL_945G) || \ - ((dinfo)->chipset==INTEL_945GM)) + ((dinfo)->chipset == INTEL_945GM) || \ + ((dinfo)->chipset == INTEL_965G) || \ + ((dinfo)->chipset == INTEL_965GM)) #ifndef FBIO_WAITFORVSYNC #define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32) diff --git a/drivers/video/intelfb/intelfb_i2c.c b/drivers/video/intelfb/intelfb_i2c.c index 94c08bb5acf1..ca95f09d8b43 100644 --- a/drivers/video/intelfb/intelfb_i2c.c +++ b/drivers/video/intelfb/intelfb_i2c.c @@ -169,6 +169,8 @@ void intelfb_create_i2c_busses(struct intelfb_info *dinfo) /* has some LVDS + tv-out */ case INTEL_945G: case INTEL_945GM: + case INTEL_965G: + case INTEL_965GM: /* SDVO ports have a single control bus - 2 devices */ dinfo->output[i].type = INTELFB_OUTPUT_SDVO; intelfb_setup_i2c_bus(dinfo, &dinfo->output[i].i2c_bus, diff --git a/drivers/video/intelfb/intelfbdrv.c b/drivers/video/intelfb/intelfbdrv.c index 481d58f7535d..e44303f9bc52 100644 --- a/drivers/video/intelfb/intelfbdrv.c +++ b/drivers/video/intelfb/intelfbdrv.c @@ -2,7 +2,7 @@ * intelfb * * Linux framebuffer driver for Intel(R) 830M/845G/852GM/855GM/865G/915G/915GM/ - * 945G/945GM integrated graphics chips. + * 945G/945GM/965G/965GM integrated graphics chips. * * Copyright © 2002, 2003 David Dawes <dawes@xfree86.org> * 2004 Sylvain Meyer @@ -99,6 +99,9 @@ * Add vram option to reserve more memory than stolen by BIOS * Fix intelfbhw_pan_display typo * Add __initdata annotations + * + * 04/2008 - Version 0.9.5 + * Add support for 965G/965GM. (Maik Broemme <mbroemme@plusserver.de>) */ #include <linux/module.h> @@ -180,6 +183,8 @@ static struct pci_device_id intelfb_pci_table[] __devinitdata = { { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_915GM, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_915GM }, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_945G, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_945G }, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_945GM, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_945GM }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_965G, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_965G }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_965GM, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_965GM }, { 0, } }; @@ -549,7 +554,10 @@ static int __devinit intelfb_pci_register(struct pci_dev *pdev, if ((ent->device == PCI_DEVICE_ID_INTEL_915G) || (ent->device == PCI_DEVICE_ID_INTEL_915GM) || (ent->device == PCI_DEVICE_ID_INTEL_945G) || - (ent->device == PCI_DEVICE_ID_INTEL_945GM)) { + (ent->device == PCI_DEVICE_ID_INTEL_945GM) || + (ent->device == PCI_DEVICE_ID_INTEL_965G) || + (ent->device == PCI_DEVICE_ID_INTEL_965GM)) { + aperture_bar = 2; mmio_bar = 0; } diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c index fa1fff553565..8e6d6a4db0ad 100644 --- a/drivers/video/intelfb/intelfbhw.c +++ b/drivers/video/intelfb/intelfbhw.c @@ -143,6 +143,18 @@ int intelfbhw_get_chipset(struct pci_dev *pdev, struct intelfb_info *dinfo) dinfo->mobile = 1; dinfo->pll_index = PLLS_I9xx; return 0; + case PCI_DEVICE_ID_INTEL_965G: + dinfo->name = "Intel(R) 965G"; + dinfo->chipset = INTEL_965G; + dinfo->mobile = 0; + dinfo->pll_index = PLLS_I9xx; + return 0; + case PCI_DEVICE_ID_INTEL_965GM: + dinfo->name = "Intel(R) 965GM"; + dinfo->chipset = INTEL_965GM; + dinfo->mobile = 1; + dinfo->pll_index = PLLS_I9xx; + return 0; default: return 1; } @@ -174,7 +186,9 @@ int intelfbhw_get_memory(struct pci_dev *pdev, int *aperture_size, case PCI_DEVICE_ID_INTEL_915GM: case PCI_DEVICE_ID_INTEL_945G: case PCI_DEVICE_ID_INTEL_945GM: - /* 915 and 945 chipsets support a 256MB aperture. + case PCI_DEVICE_ID_INTEL_965G: + case PCI_DEVICE_ID_INTEL_965GM: + /* 915, 945 and 965 chipsets support a 256MB aperture. Aperture size is determined by inspected the base address of the aperture. */ if (pci_resource_start(pdev, 2) & 0x08000000) diff --git a/drivers/video/leo.c b/drivers/video/leo.c index 45b9a5d55dec..f3160fc29795 100644 --- a/drivers/video/leo.c +++ b/drivers/video/leo.c @@ -614,7 +614,7 @@ static int __devinit leo_probe(struct of_device *op, const struct of_device_id * dev_set_drvdata(&op->dev, info); - printk("%s: leo at %lx:%lx\n", + printk(KERN_INFO "%s: leo at %lx:%lx\n", dp->full_name, par->which_io, par->physbase); diff --git a/drivers/video/matrox/matroxfb_DAC1064.c b/drivers/video/matrox/matroxfb_DAC1064.c index c4b570b4a4df..0ce3b0a89798 100644 --- a/drivers/video/matrox/matroxfb_DAC1064.c +++ b/drivers/video/matrox/matroxfb_DAC1064.c @@ -37,7 +37,7 @@ static void DAC1064_calcclock(CPMINFO unsigned int freq, unsigned int fmax, unsi unsigned int fvco; unsigned int p; - DBG(__FUNCTION__) + DBG(__func__) /* only for devices older than G450 */ @@ -83,7 +83,7 @@ static const unsigned char MGA1064_DAC[] = { static void DAC1064_setpclk(WPMINFO unsigned long fout) { unsigned int m, n, p; - DBG(__FUNCTION__) + DBG(__func__) DAC1064_calcclock(PMINFO fout, ACCESS_FBINFO(max_pixel_clock), &m, &n, &p); ACCESS_FBINFO(hw).DACclk[0] = m; @@ -95,7 +95,7 @@ static void DAC1064_setmclk(WPMINFO int oscinfo, unsigned long fmem) { u_int32_t mx; struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); - DBG(__FUNCTION__) + DBG(__func__) if (ACCESS_FBINFO(devflags.noinit)) { /* read MCLK and give up... */ @@ -338,7 +338,7 @@ void DAC1064_global_restore(WPMINFO2) { static int DAC1064_init_1(WPMINFO struct my_timming* m) { struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); - DBG(__FUNCTION__) + DBG(__func__) memcpy(hw->DACreg, MGA1064_DAC, sizeof(MGA1064_DAC_regs)); switch (ACCESS_FBINFO(fbcon).var.bits_per_pixel) { @@ -374,7 +374,7 @@ static int DAC1064_init_1(WPMINFO struct my_timming* m) { static int DAC1064_init_2(WPMINFO struct my_timming* m) { struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); - DBG(__FUNCTION__) + DBG(__func__) if (ACCESS_FBINFO(fbcon).var.bits_per_pixel > 16) { /* 256 entries */ int i; @@ -418,7 +418,7 @@ static void DAC1064_restore_1(WPMINFO2) { CRITFLAGS - DBG(__FUNCTION__) + DBG(__func__) CRITBEGIN @@ -448,7 +448,7 @@ static void DAC1064_restore_2(WPMINFO2) { unsigned int i; #endif - DBG(__FUNCTION__) + DBG(__func__) #ifdef DEBUG dprintk(KERN_DEBUG "DAC1064regs "); @@ -521,7 +521,7 @@ static struct matrox_altout g450out = { static int MGA1064_init(WPMINFO struct my_timming* m) { struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); - DBG(__FUNCTION__) + DBG(__func__) if (DAC1064_init_1(PMINFO m)) return 1; if (matroxfb_vgaHWinit(PMINFO m)) return 1; @@ -543,7 +543,7 @@ static int MGA1064_init(WPMINFO struct my_timming* m) { static int MGAG100_init(WPMINFO struct my_timming* m) { struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); - DBG(__FUNCTION__) + DBG(__func__) if (DAC1064_init_1(PMINFO m)) return 1; hw->MXoptionReg &= ~0x2000; @@ -565,7 +565,7 @@ static int MGAG100_init(WPMINFO struct my_timming* m) { #ifdef CONFIG_FB_MATROX_MYSTIQUE static void MGA1064_ramdac_init(WPMINFO2) { - DBG(__FUNCTION__) + DBG(__func__) /* ACCESS_FBINFO(features.DAC1064.vco_freq_min) = 120000; */ ACCESS_FBINFO(features.pll.vco_freq_min) = 62000; @@ -594,7 +594,7 @@ static void MGAG100_progPixClock(CPMINFO int flags, int m, int n, int p) { int selClk; int clk; - DBG(__FUNCTION__) + DBG(__func__) outDAC1064(PMINFO M1064_XPIXCLKCTRL, inDAC1064(PMINFO M1064_XPIXCLKCTRL) | M1064_XPIXCLKCTRL_DIS | M1064_XPIXCLKCTRL_PLL_UP); @@ -636,7 +636,7 @@ static void MGAG100_progPixClock(CPMINFO int flags, int m, int n, int p) { static void MGAG100_setPixClock(CPMINFO int flags, int freq) { unsigned int m, n, p; - DBG(__FUNCTION__) + DBG(__func__) DAC1064_calcclock(PMINFO freq, ACCESS_FBINFO(max_pixel_clock), &m, &n, &p); MGAG100_progPixClock(PMINFO flags, m, n, p); @@ -650,7 +650,7 @@ static int MGA1064_preinit(WPMINFO2) { 2048, 0}; struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); - DBG(__FUNCTION__) + DBG(__func__) /* ACCESS_FBINFO(capable.cfb4) = 0; ... preinitialized by 0 */ ACCESS_FBINFO(capable.text) = 1; @@ -683,7 +683,7 @@ static int MGA1064_preinit(WPMINFO2) { static void MGA1064_reset(WPMINFO2) { - DBG(__FUNCTION__); + DBG(__func__); MGA1064_ramdac_init(PMINFO2); } @@ -819,7 +819,7 @@ static int MGAG100_preinit(WPMINFO2) { u_int32_t q; #endif - DBG(__FUNCTION__) + DBG(__func__) /* there are some instabilities if in_div > 19 && vco < 61000 */ if (ACCESS_FBINFO(devflags.g450dac)) { @@ -956,7 +956,7 @@ static void MGAG100_reset(WPMINFO2) { u_int8_t b; struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); - DBG(__FUNCTION__) + DBG(__func__) { #ifdef G100_BROKEN_IBM_82351 @@ -1015,7 +1015,7 @@ static void MGA1064_restore(WPMINFO2) { CRITFLAGS - DBG(__FUNCTION__) + DBG(__func__) CRITBEGIN @@ -1041,7 +1041,7 @@ static void MGAG100_restore(WPMINFO2) { CRITFLAGS - DBG(__FUNCTION__) + DBG(__func__) CRITBEGIN diff --git a/drivers/video/matrox/matroxfb_Ti3026.c b/drivers/video/matrox/matroxfb_Ti3026.c index 9445cdb759b1..13524821e242 100644 --- a/drivers/video/matrox/matroxfb_Ti3026.c +++ b/drivers/video/matrox/matroxfb_Ti3026.c @@ -283,7 +283,7 @@ static int Ti3026_calcclock(CPMINFO unsigned int freq, unsigned int fmax, int* i unsigned int fvco; unsigned int lin, lfeed, lpost; - DBG(__FUNCTION__) + DBG(__func__) fvco = PLL_calcclock(PMINFO freq, fmax, &lin, &lfeed, &lpost); fvco >>= (*post = lpost); @@ -297,7 +297,7 @@ static int Ti3026_setpclk(WPMINFO int clk) { unsigned int pixfeed, pixin, pixpost; struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); - DBG(__FUNCTION__) + DBG(__func__) f_pll = Ti3026_calcclock(PMINFO clk, ACCESS_FBINFO(max_pixel_clock), &pixin, &pixfeed, &pixpost); @@ -365,7 +365,7 @@ static int Ti3026_init(WPMINFO struct my_timming* m) { u_int8_t muxctrl = isInterleave(MINFO) ? TVP3026_XMUXCTRL_MEMORY_64BIT : TVP3026_XMUXCTRL_MEMORY_32BIT; struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); - DBG(__FUNCTION__) + DBG(__func__) memcpy(hw->DACreg, MGADACbpp32, sizeof(hw->DACreg)); switch (ACCESS_FBINFO(fbcon).var.bits_per_pixel) { @@ -440,7 +440,7 @@ static void ti3026_setMCLK(WPMINFO int fout){ unsigned int rfhcnt, mclk_ctl; int tmout; - DBG(__FUNCTION__) + DBG(__func__) f_pll = Ti3026_calcclock(PMINFO fout, ACCESS_FBINFO(max_pixel_clock), &mclk_n, &mclk_m, &mclk_p); @@ -534,7 +534,7 @@ static void ti3026_setMCLK(WPMINFO int fout){ static void ti3026_ramdac_init(WPMINFO2) { - DBG(__FUNCTION__) + DBG(__func__) ACCESS_FBINFO(features.pll.vco_freq_min) = 110000; ACCESS_FBINFO(features.pll.ref_freq) = 114545; @@ -554,7 +554,7 @@ static void Ti3026_restore(WPMINFO2) { struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); CRITFLAGS - DBG(__FUNCTION__) + DBG(__func__) #ifdef DEBUG dprintk(KERN_INFO "EXTVGA regs: "); @@ -662,7 +662,7 @@ static void Ti3026_restore(WPMINFO2) { static void Ti3026_reset(WPMINFO2) { - DBG(__FUNCTION__) + DBG(__func__) ti3026_ramdac_init(PMINFO2); } @@ -680,7 +680,7 @@ static int Ti3026_preinit(WPMINFO2) { 2048, 0}; struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); - DBG(__FUNCTION__) + DBG(__func__) ACCESS_FBINFO(millenium) = 1; ACCESS_FBINFO(milleniumII) = (ACCESS_FBINFO(pcidev)->device != PCI_DEVICE_ID_MATROX_MIL); diff --git a/drivers/video/matrox/matroxfb_accel.c b/drivers/video/matrox/matroxfb_accel.c index 3660d2673bdc..9c3aeee1cc4f 100644 --- a/drivers/video/matrox/matroxfb_accel.c +++ b/drivers/video/matrox/matroxfb_accel.c @@ -113,7 +113,7 @@ void matrox_cfbX_init(WPMINFO2) { u_int32_t mopmode; int accel; - DBG(__FUNCTION__) + DBG(__func__) mpitch = ACCESS_FBINFO(fbcon).var.xres_virtual; @@ -199,7 +199,7 @@ static void matrox_accel_bmove(WPMINFO int vxres, int sy, int sx, int dy, int dx int start, end; CRITFLAGS - DBG(__FUNCTION__) + DBG(__func__) CRITBEGIN @@ -235,7 +235,7 @@ static void matrox_accel_bmove_lin(WPMINFO int vxres, int sy, int sx, int dy, in int start, end; CRITFLAGS - DBG(__FUNCTION__) + DBG(__func__) CRITBEGIN @@ -287,7 +287,7 @@ static void matroxfb_accel_clear(WPMINFO u_int32_t color, int sy, int sx, int he int width) { CRITFLAGS - DBG(__FUNCTION__) + DBG(__func__) CRITBEGIN @@ -315,7 +315,7 @@ static void matroxfb_cfb4_clear(WPMINFO u_int32_t bgx, int sy, int sx, int heigh int whattodo; CRITFLAGS - DBG(__FUNCTION__) + DBG(__func__) CRITBEGIN @@ -388,7 +388,7 @@ static void matroxfb_1bpp_imageblit(WPMINFO u_int32_t fgx, u_int32_t bgx, int easy; CRITFLAGS - DBG_HEAVY(__FUNCTION__); + DBG_HEAVY(__func__); step = (width + 7) >> 3; charcell = height * step; @@ -469,7 +469,7 @@ static void matroxfb_1bpp_imageblit(WPMINFO u_int32_t fgx, u_int32_t bgx, static void matroxfb_imageblit(struct fb_info* info, const struct fb_image* image) { MINFO_FROM_INFO(info); - DBG_HEAVY(__FUNCTION__); + DBG_HEAVY(__func__); if (image->depth == 1) { u_int32_t fgx, bgx; diff --git a/drivers/video/matrox/matroxfb_base.c b/drivers/video/matrox/matroxfb_base.c index b25972ac6eeb..54e82f35353d 100644 --- a/drivers/video/matrox/matroxfb_base.c +++ b/drivers/video/matrox/matroxfb_base.c @@ -312,7 +312,7 @@ static void matrox_pan_var(WPMINFO struct fb_var_screeninfo *var) { CRITFLAGS - DBG(__FUNCTION__) + DBG(__func__) if (ACCESS_FBINFO(dead)) return; @@ -392,7 +392,7 @@ static int matroxfb_open(struct fb_info *info, int user) { MINFO_FROM_INFO(info); - DBG_LOOP(__FUNCTION__) + DBG_LOOP(__func__) if (ACCESS_FBINFO(dead)) { return -ENXIO; @@ -408,7 +408,7 @@ static int matroxfb_release(struct fb_info *info, int user) { MINFO_FROM_INFO(info); - DBG_LOOP(__FUNCTION__) + DBG_LOOP(__func__) if (user) { if (0 == --ACCESS_FBINFO(userusecount)) { @@ -425,7 +425,7 @@ static int matroxfb_pan_display(struct fb_var_screeninfo *var, struct fb_info* info) { MINFO_FROM_INFO(info); - DBG(__FUNCTION__) + DBG(__func__) matrox_pan_var(PMINFO var); return 0; @@ -434,7 +434,7 @@ static int matroxfb_pan_display(struct fb_var_screeninfo *var, static int matroxfb_get_final_bppShift(CPMINFO int bpp) { int bppshft2; - DBG(__FUNCTION__) + DBG(__func__) bppshft2 = bpp; if (!bppshft2) { @@ -451,7 +451,7 @@ static int matroxfb_test_and_set_rounding(CPMINFO int xres, int bpp) { int over; int rounding; - DBG(__FUNCTION__) + DBG(__func__) switch (bpp) { case 0: return xres; @@ -482,7 +482,7 @@ static int matroxfb_pitch_adjust(CPMINFO int xres, int bpp) { const int* width; int xres_new; - DBG(__FUNCTION__) + DBG(__func__) if (!bpp) return xres; @@ -504,7 +504,7 @@ static int matroxfb_pitch_adjust(CPMINFO int xres, int bpp) { static int matroxfb_get_cmap_len(struct fb_var_screeninfo *var) { - DBG(__FUNCTION__) + DBG(__func__) switch (var->bits_per_pixel) { case 4: @@ -548,7 +548,7 @@ static int matroxfb_decode_var(CPMINFO struct fb_var_screeninfo *var, int *visua unsigned int vramlen; unsigned int memlen; - DBG(__FUNCTION__) + DBG(__func__) switch (bpp) { case 4: if (!ACCESS_FBINFO(capable.cfb4)) return -EINVAL; @@ -648,7 +648,7 @@ static int matroxfb_setcolreg(unsigned regno, unsigned red, unsigned green, struct matrox_fb_info* minfo = container_of(fb_info, struct matrox_fb_info, fbcon); #endif - DBG(__FUNCTION__) + DBG(__func__) /* * Set a single color register. The values supplied are @@ -707,7 +707,7 @@ static int matroxfb_setcolreg(unsigned regno, unsigned red, unsigned green, static void matroxfb_init_fix(WPMINFO2) { struct fb_fix_screeninfo *fix = &ACCESS_FBINFO(fbcon).fix; - DBG(__FUNCTION__) + DBG(__func__) strcpy(fix->id,"MATROX"); @@ -722,7 +722,7 @@ static void matroxfb_init_fix(WPMINFO2) static void matroxfb_update_fix(WPMINFO2) { struct fb_fix_screeninfo *fix = &ACCESS_FBINFO(fbcon).fix; - DBG(__FUNCTION__) + DBG(__func__) fix->smem_start = ACCESS_FBINFO(video.base) + ACCESS_FBINFO(curr.ydstorg.bytes); fix->smem_len = ACCESS_FBINFO(video.len_usable) - ACCESS_FBINFO(curr.ydstorg.bytes); @@ -753,7 +753,7 @@ static int matroxfb_set_par(struct fb_info *info) struct fb_var_screeninfo *var; MINFO_FROM_INFO(info); - DBG(__FUNCTION__) + DBG(__func__) if (ACCESS_FBINFO(dead)) { return -ENXIO; @@ -876,7 +876,7 @@ static int matroxfb_ioctl(struct fb_info *info, void __user *argp = (void __user *)arg; MINFO_FROM_INFO(info); - DBG(__FUNCTION__) + DBG(__func__) if (ACCESS_FBINFO(dead)) { return -ENXIO; @@ -1175,7 +1175,7 @@ static int matroxfb_blank(int blank, struct fb_info *info) CRITFLAGS MINFO_FROM_INFO(info); - DBG(__FUNCTION__) + DBG(__func__) if (ACCESS_FBINFO(dead)) return 1; @@ -1287,7 +1287,7 @@ static int matroxfb_getmemory(WPMINFO unsigned int maxSize, unsigned int *realSi unsigned char bytes[32]; unsigned char* tmp; - DBG(__FUNCTION__) + DBG(__func__) vm = ACCESS_FBINFO(video.vbase); maxSize &= ~0x1FFFFF; /* must be X*2MB (really it must be 2 or X*4MB) */ @@ -1593,7 +1593,7 @@ static int initMatrox2(WPMINFO struct board* b){ { }, }; - DBG(__FUNCTION__) + DBG(__func__) /* set default values... */ vesafb_defined.accel_flags = FB_ACCELF_TEXT; @@ -2006,7 +2006,7 @@ static int matroxfb_probe(struct pci_dev* pdev, const struct pci_device_id* dumm #ifndef CONFIG_FB_MATROX_MULTIHEAD static int registered = 0; #endif - DBG(__FUNCTION__) + DBG(__func__) svid = pdev->subsystem_vendor; sid = pdev->subsystem_device; @@ -2301,7 +2301,7 @@ static void __exit matrox_done(void) { static int __init matroxfb_setup(char *options) { char *this_opt; - DBG(__FUNCTION__) + DBG(__func__) if (!options || !*options) return 0; @@ -2444,7 +2444,7 @@ static int __init matroxfb_init(void) char *option = NULL; int err = 0; - DBG(__FUNCTION__) + DBG(__func__) if (fb_get_options("matroxfb", &option)) return -ENODEV; @@ -2556,7 +2556,7 @@ MODULE_PARM_DESC(cmode, "Specify the video depth that should be used (8bit defau int __init init_module(void){ - DBG(__FUNCTION__) + DBG(__func__) if (disabled) return -ENXIO; diff --git a/drivers/video/matrox/matroxfb_crtc2.c b/drivers/video/matrox/matroxfb_crtc2.c index a6ab5b6a58d0..7ac4c5f6145d 100644 --- a/drivers/video/matrox/matroxfb_crtc2.c +++ b/drivers/video/matrox/matroxfb_crtc2.c @@ -420,7 +420,7 @@ static int matroxfb_dh_ioctl(struct fb_info *info, #define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon)) MINFO_FROM(m2info->primary_dev); - DBG(__FUNCTION__) + DBG(__func__) switch (cmd) { case FBIOGET_VBLANK: diff --git a/drivers/video/matrox/matroxfb_maven.c b/drivers/video/matrox/matroxfb_maven.c index 0cd58f84fb46..89da27bd5c49 100644 --- a/drivers/video/matrox/matroxfb_maven.c +++ b/drivers/video/matrox/matroxfb_maven.c @@ -220,7 +220,7 @@ static int matroxfb_PLL_mavenclock(const struct matrox_pll_features2* pll, unsigned int scrlen; unsigned int fmax; - DBG(__FUNCTION__) + DBG(__func__) scrlen = htotal * (vtotal - 1); fwant = htotal * vtotal; diff --git a/drivers/video/matrox/matroxfb_misc.c b/drivers/video/matrox/matroxfb_misc.c index ab7fb50bc1de..aaa3e538e5da 100644 --- a/drivers/video/matrox/matroxfb_misc.c +++ b/drivers/video/matrox/matroxfb_misc.c @@ -90,13 +90,13 @@ #include <linux/matroxfb.h> void matroxfb_DAC_out(CPMINFO int reg, int val) { - DBG_REG(__FUNCTION__) + DBG_REG(__func__) mga_outb(M_RAMDAC_BASE+M_X_INDEX, reg); mga_outb(M_RAMDAC_BASE+M_X_DATAREG, val); } int matroxfb_DAC_in(CPMINFO int reg) { - DBG_REG(__FUNCTION__) + DBG_REG(__func__) mga_outb(M_RAMDAC_BASE+M_X_INDEX, reg); return mga_inb(M_RAMDAC_BASE+M_X_DATAREG); } @@ -104,7 +104,7 @@ int matroxfb_DAC_in(CPMINFO int reg) { void matroxfb_var2my(struct fb_var_screeninfo* var, struct my_timming* mt) { unsigned int pixclock = var->pixclock; - DBG(__FUNCTION__) + DBG(__func__) if (!pixclock) pixclock = 10000; /* 10ns = 100MHz */ mt->pixclock = 1000000000 / pixclock; @@ -131,7 +131,7 @@ int matroxfb_PLL_calcclock(const struct matrox_pll_features* pll, unsigned int f unsigned int fwant; unsigned int p; - DBG(__FUNCTION__) + DBG(__func__) fwant = freq; @@ -192,7 +192,7 @@ int matroxfb_vgaHWinit(WPMINFO struct my_timming* m) { int i; struct matrox_hw_state * const hw = &ACCESS_FBINFO(hw); - DBG(__FUNCTION__) + DBG(__func__) hw->SEQ[0] = 0x00; hw->SEQ[1] = 0x01; /* or 0x09 */ @@ -336,7 +336,7 @@ void matroxfb_vgaHWrestore(WPMINFO2) { struct matrox_hw_state * const hw = &ACCESS_FBINFO(hw); CRITFLAGS - DBG(__FUNCTION__) + DBG(__func__) dprintk(KERN_INFO "MiscOutReg: %02X\n", hw->MiscOutReg); dprintk(KERN_INFO "SEQ regs: "); diff --git a/drivers/video/metronomefb.c b/drivers/video/metronomefb.c index e9a89fd82757..249791286367 100644 --- a/drivers/video/metronomefb.c +++ b/drivers/video/metronomefb.c @@ -13,12 +13,10 @@ * Corporation. http://support.eink.com/community * * This driver is written to be used with the Metronome display controller. - * It was tested with an E-Ink 800x600 Vizplex EPD on a Gumstix Connex board - * using the Lyre interface board. + * It is intended to be architecture independent. A board specific driver + * must be used to perform all the physical IO interactions. An example + * is provided as am200epd.c * - * General notes: - * - User must set metronomefb_enable=1 to enable it. - * - See Documentation/fb/metronomefb.txt for how metronome works. */ #include <linux/module.h> #include <linux/kernel.h> @@ -38,9 +36,11 @@ #include <linux/uaccess.h> #include <linux/irq.h> -#include <asm/arch/pxa-regs.h> +#include <video/metronomefb.h> + #include <asm/unaligned.h> + #define DEBUG 1 #ifdef DEBUG #define DPRINTK(f, a...) printk(KERN_DEBUG "%s: " f, __func__ , ## a) @@ -53,35 +53,6 @@ #define DPY_W 832 #define DPY_H 622 -struct metromem_desc { - u32 mFDADR0; - u32 mFSADR0; - u32 mFIDR0; - u32 mLDCMD0; -}; - -struct metromem_cmd { - u16 opcode; - u16 args[((64-2)/2)]; - u16 csum; -}; - -struct metronomefb_par { - unsigned char *metromem; - struct metromem_desc *metromem_desc; - struct metromem_cmd *metromem_cmd; - unsigned char *metromem_wfm; - unsigned char *metromem_img; - u16 *metromem_img_csum; - u16 *csum_table; - int metromemsize; - dma_addr_t metromem_dma; - dma_addr_t metromem_desc_dma; - struct fb_info *info; - wait_queue_head_t waitq; - u8 frame_count; -}; - /* frame differs from image. frame includes non-visible pixels */ struct epd_frame { int fw; /* frame width */ @@ -120,8 +91,7 @@ static struct fb_var_screeninfo metronomefb_var __devinitdata = { .transp = { 0, 0, 0 }, }; -static unsigned int metronomefb_enable; - +/* the waveform structure that is coming from userspace firmware */ struct waveform_hdr { u8 stuff[32]; @@ -301,165 +271,6 @@ static int load_waveform(u8 *mem, size_t size, u8 *metromem, int m, int t, return 0; } -/* register offsets for gpio control */ -#define LED_GPIO_PIN 51 -#define STDBY_GPIO_PIN 48 -#define RST_GPIO_PIN 49 -#define RDY_GPIO_PIN 32 -#define ERR_GPIO_PIN 17 -#define PCBPWR_GPIO_PIN 16 - -#define AF_SEL_GPIO_N 0x3 -#define GAFR0_U_OFFSET(pin) ((pin - 16) * 2) -#define GAFR1_L_OFFSET(pin) ((pin - 32) * 2) -#define GAFR1_U_OFFSET(pin) ((pin - 48) * 2) -#define GPDR1_OFFSET(pin) (pin - 32) -#define GPCR1_OFFSET(pin) (pin - 32) -#define GPSR1_OFFSET(pin) (pin - 32) -#define GPCR0_OFFSET(pin) (pin) -#define GPSR0_OFFSET(pin) (pin) - -static void metronome_set_gpio_output(int pin, int val) -{ - u8 index; - - index = pin >> 4; - - switch (index) { - case 1: - if (val) - GPSR0 |= (1 << GPSR0_OFFSET(pin)); - else - GPCR0 |= (1 << GPCR0_OFFSET(pin)); - break; - case 2: - break; - case 3: - if (val) - GPSR1 |= (1 << GPSR1_OFFSET(pin)); - else - GPCR1 |= (1 << GPCR1_OFFSET(pin)); - break; - default: - printk(KERN_ERR "unimplemented\n"); - } -} - -static void __devinit metronome_init_gpio_pin(int pin, int dir) -{ - u8 index; - /* dir 0 is output, 1 is input - - do 2 things here: - - set gpio alternate function to standard gpio - - set gpio direction to input or output */ - - index = pin >> 4; - switch (index) { - case 1: - GAFR0_U &= ~(AF_SEL_GPIO_N << GAFR0_U_OFFSET(pin)); - - if (dir) - GPDR0 &= ~(1 << pin); - else - GPDR0 |= (1 << pin); - break; - case 2: - GAFR1_L &= ~(AF_SEL_GPIO_N << GAFR1_L_OFFSET(pin)); - - if (dir) - GPDR1 &= ~(1 << GPDR1_OFFSET(pin)); - else - GPDR1 |= (1 << GPDR1_OFFSET(pin)); - break; - case 3: - GAFR1_U &= ~(AF_SEL_GPIO_N << GAFR1_U_OFFSET(pin)); - - if (dir) - GPDR1 &= ~(1 << GPDR1_OFFSET(pin)); - else - GPDR1 |= (1 << GPDR1_OFFSET(pin)); - break; - default: - printk(KERN_ERR "unimplemented\n"); - } -} - -static void __devinit metronome_init_gpio_regs(void) -{ - metronome_init_gpio_pin(LED_GPIO_PIN, 0); - metronome_set_gpio_output(LED_GPIO_PIN, 0); - - metronome_init_gpio_pin(STDBY_GPIO_PIN, 0); - metronome_set_gpio_output(STDBY_GPIO_PIN, 0); - - metronome_init_gpio_pin(RST_GPIO_PIN, 0); - metronome_set_gpio_output(RST_GPIO_PIN, 0); - - metronome_init_gpio_pin(RDY_GPIO_PIN, 1); - - metronome_init_gpio_pin(ERR_GPIO_PIN, 1); - - metronome_init_gpio_pin(PCBPWR_GPIO_PIN, 0); - metronome_set_gpio_output(PCBPWR_GPIO_PIN, 0); -} - -static void metronome_disable_lcd_controller(struct metronomefb_par *par) -{ - LCSR = 0xffffffff; /* Clear LCD Status Register */ - LCCR0 |= LCCR0_DIS; /* Disable LCD Controller */ - - /* we reset and just wait for things to settle */ - msleep(200); -} - -static void metronome_enable_lcd_controller(struct metronomefb_par *par) -{ - LCSR = 0xffffffff; - FDADR0 = par->metromem_desc_dma; - LCCR0 |= LCCR0_ENB; -} - -static void __devinit metronome_init_lcdc_regs(struct metronomefb_par *par) -{ - /* here we do: - - disable the lcd controller - - setup lcd control registers - - setup dma descriptor - - reenable lcd controller - */ - - /* disable the lcd controller */ - metronome_disable_lcd_controller(par); - - /* setup lcd control registers */ - LCCR0 = LCCR0_LDM | LCCR0_SFM | LCCR0_IUM | LCCR0_EFM | LCCR0_PAS - | LCCR0_QDM | LCCR0_BM | LCCR0_OUM; - - LCCR1 = (epd_frame_table[0].fw/2 - 1) /* pixels per line */ - | (27 << 10) /* hsync pulse width - 1 */ - | (33 << 16) /* eol pixel count */ - | (33 << 24); /* bol pixel count */ - - LCCR2 = (epd_frame_table[0].fh - 1) /* lines per panel */ - | (24 << 10) /* vsync pulse width - 1 */ - | (2 << 16) /* eof pixel count */ - | (0 << 24); /* bof pixel count */ - - LCCR3 = 2 /* pixel clock divisor */ - | (24 << 8) /* AC Bias pin freq */ - | LCCR3_16BPP /* BPP */ - | LCCR3_PCP; /* PCP falling edge */ - - /* setup dma descriptor */ - par->metromem_desc->mFDADR0 = par->metromem_desc_dma; - par->metromem_desc->mFSADR0 = par->metromem_dma; - par->metromem_desc->mFIDR0 = 0; - par->metromem_desc->mLDCMD0 = epd_frame_table[0].fw - * epd_frame_table[0].fh; - /* reenable lcd controller */ - metronome_enable_lcd_controller(par); -} - static int metronome_display_cmd(struct metronomefb_par *par) { int i; @@ -493,8 +304,7 @@ static int metronome_display_cmd(struct metronomefb_par *par) par->metromem_cmd->csum = cs; par->metromem_cmd->opcode = opcode; /* display cmd */ - i = wait_event_interruptible_timeout(par->waitq, (GPLR1 & 0x01), HZ); - return i; + return par->board->met_wait_event_intr(par); } static int __devinit metronome_powerup_cmd(struct metronomefb_par *par) @@ -518,13 +328,12 @@ static int __devinit metronome_powerup_cmd(struct metronomefb_par *par) par->metromem_cmd->csum = cs; msleep(1); - metronome_set_gpio_output(RST_GPIO_PIN, 1); + par->board->set_rst(par, 1); msleep(1); - metronome_set_gpio_output(STDBY_GPIO_PIN, 1); + par->board->set_stdby(par, 1); - i = wait_event_timeout(par->waitq, (GPLR1 & 0x01), HZ); - return i; + return par->board->met_wait_event(par); } static int __devinit metronome_config_cmd(struct metronomefb_par *par) @@ -569,8 +378,7 @@ static int __devinit metronome_config_cmd(struct metronomefb_par *par) par->metromem_cmd->csum = cs; par->metromem_cmd->opcode = 0xCC10; /* config cmd */ - i = wait_event_timeout(par->waitq, (GPLR1 & 0x01), HZ); - return i; + return par->board->met_wait_event(par); } static int __devinit metronome_init_cmd(struct metronomefb_par *par) @@ -596,16 +404,19 @@ static int __devinit metronome_init_cmd(struct metronomefb_par *par) par->metromem_cmd->csum = cs; par->metromem_cmd->opcode = 0xCC20; /* init cmd */ - i = wait_event_timeout(par->waitq, (GPLR1 & 0x01), HZ); - return i; + return par->board->met_wait_event(par); } static int __devinit metronome_init_regs(struct metronomefb_par *par) { int res; - metronome_init_gpio_regs(); - metronome_init_lcdc_regs(par); + par->board->init_gpio_regs(par); + + par->board->init_lcdc_regs(par); + + /* now that lcd is setup, setup dma descriptor */ + par->board->post_dma_setup(par); res = metronome_powerup_cmd(par); if (res) @@ -616,8 +427,6 @@ static int __devinit metronome_init_regs(struct metronomefb_par *par) return res; res = metronome_init_cmd(par); - if (res) - return res; return res; } @@ -632,7 +441,7 @@ static void metronomefb_dpy_update(struct metronomefb_par *par) cksum = calc_img_cksum((u16 *) par->metromem_img, (epd_frame_table[0].fw * DPY_H)/2); - *((u16 *) (par->metromem_img) + + *((u16 *)(par->metromem_img) + (epd_frame_table[0].fw * DPY_H)/2) = cksum; metronome_display_cmd(par); } @@ -641,8 +450,8 @@ static u16 metronomefb_dpy_update_page(struct metronomefb_par *par, int index) { int i; u16 csum = 0; - u16 *buf = (u16 __force *) (par->info->screen_base + index); - u16 *img = (u16 *) (par->metromem_img + index); + u16 *buf = (u16 __force *)(par->info->screen_base + index); + u16 *img = (u16 *)(par->metromem_img + index); /* swizzle from vm to metromem and recalc cksum at the same time*/ for (i = 0; i < PAGE_SIZE/2; i++) { @@ -678,7 +487,7 @@ static void metronomefb_fillrect(struct fb_info *info, { struct metronomefb_par *par = info->par; - cfb_fillrect(info, rect); + sys_fillrect(info, rect); metronomefb_dpy_update(par); } @@ -687,7 +496,7 @@ static void metronomefb_copyarea(struct fb_info *info, { struct metronomefb_par *par = info->par; - cfb_copyarea(info, area); + sys_copyarea(info, area); metronomefb_dpy_update(par); } @@ -696,7 +505,7 @@ static void metronomefb_imageblit(struct fb_info *info, { struct metronomefb_par *par = info->par; - cfb_imageblit(info, image); + sys_imageblit(info, image); metronomefb_dpy_update(par); } @@ -733,7 +542,7 @@ static ssize_t metronomefb_write(struct fb_info *info, const char __user *buf, count = total_size - p; } - dst = (void __force *) (info->screen_base + p); + dst = (void __force *)(info->screen_base + p); if (copy_from_user(dst, buf, count)) err = -EFAULT; @@ -759,18 +568,10 @@ static struct fb_deferred_io metronomefb_defio = { .deferred_io = metronomefb_dpy_deferred_io, }; -static irqreturn_t metronome_handle_irq(int irq, void *dev_id) -{ - struct fb_info *info = dev_id; - struct metronomefb_par *par = info->par; - - wake_up_interruptible(&par->waitq); - return IRQ_HANDLED; -} - static int __devinit metronomefb_probe(struct platform_device *dev) { struct fb_info *info; + struct metronome_board *board; int retval = -ENOMEM; int videomemorysize; unsigned char *videomemory; @@ -779,17 +580,26 @@ static int __devinit metronomefb_probe(struct platform_device *dev) int cmd_size, wfm_size, img_size, padding_size, totalsize; int i; + /* pick up board specific routines */ + board = dev->dev.platform_data; + if (!board) + return -EINVAL; + + /* try to count device specific driver, if can't, platform recalls */ + if (!try_module_get(board->owner)) + return -ENODEV; + /* we have two blocks of memory. info->screen_base which is vm, and is the fb used by apps. par->metromem which is physically contiguous memory and contains the display controller commands, waveform, processed image data and padding. this is the data pulled - by the pxa255's LCD controller and pushed to Metronome */ + by the device's LCD controller and pushed to Metronome */ videomemorysize = (DPY_W*DPY_H); videomemory = vmalloc(videomemorysize); if (!videomemory) - return retval; + return -ENOMEM; memset(videomemory, 0, videomemorysize); @@ -797,7 +607,7 @@ static int __devinit metronomefb_probe(struct platform_device *dev) if (!info) goto err_vfree; - info->screen_base = (char __iomem *) videomemory; + info->screen_base = (char __force __iomem *)videomemory; info->fbops = &metronomefb_ops; info->var = metronomefb_var; @@ -805,6 +615,7 @@ static int __devinit metronomefb_probe(struct platform_device *dev) info->fix.smem_len = videomemorysize; par = info->par; par->info = info; + par->board = board; init_waitqueue_head(&par->waitq); /* this table caches per page csum values. */ @@ -849,11 +660,10 @@ static int __devinit metronomefb_probe(struct platform_device *dev) par->metromem_desc_dma = par->metromem_dma + cmd_size + wfm_size + img_size + padding_size; - /* load the waveform in. assume mode 3, temp 31 for now */ - /* a) request the waveform file from userspace + /* load the waveform in. assume mode 3, temp 31 for now + a) request the waveform file from userspace b) process waveform and decode into metromem */ - - retval = request_firmware(&fw_entry, "waveform.wbf", &dev->dev); + retval = request_firmware(&fw_entry, "metronome.wbf", &dev->dev); if (retval < 0) { printk(KERN_ERR "metronomefb: couldn't get waveform\n"); goto err_dma_free; @@ -861,19 +671,14 @@ static int __devinit metronomefb_probe(struct platform_device *dev) retval = load_waveform((u8 *) fw_entry->data, fw_entry->size, par->metromem_wfm, 3, 31, &par->frame_count); + release_firmware(fw_entry); if (retval < 0) { printk(KERN_ERR "metronomefb: couldn't process waveform\n"); - goto err_ld_wfm; + goto err_dma_free; } - release_firmware(fw_entry); - retval = request_irq(IRQ_GPIO(RDY_GPIO_PIN), metronome_handle_irq, - IRQF_DISABLED, "Metronome", info); - if (retval) { - dev_err(&dev->dev, "request_irq failed: %d\n", retval); - goto err_ld_wfm; - } - set_irq_type(IRQ_GPIO(RDY_GPIO_PIN), IRQT_FALLING); + if (board->setup_irq(info)) + goto err_dma_free; retval = metronome_init_regs(par); if (retval < 0) @@ -913,9 +718,7 @@ err_cmap: err_fb_rel: framebuffer_release(info); err_free_irq: - free_irq(IRQ_GPIO(RDY_GPIO_PIN), info); -err_ld_wfm: - release_firmware(fw_entry); + board->free_irq(info); err_dma_free: dma_free_writecombine(&dev->dev, par->metromemsize, par->metromem, par->metromem_dma); @@ -923,6 +726,7 @@ err_csum_table: vfree(par->csum_table); err_vfree: vfree(videomemory); + module_put(board->owner); return retval; } @@ -939,7 +743,8 @@ static int __devexit metronomefb_remove(struct platform_device *dev) vfree(par->csum_table); unregister_framebuffer(info); vfree((void __force *)info->screen_base); - free_irq(IRQ_GPIO(RDY_GPIO_PIN), info); + par->board->free_irq(info); + module_put(par->board->owner); framebuffer_release(info); } return 0; @@ -949,48 +754,21 @@ static struct platform_driver metronomefb_driver = { .probe = metronomefb_probe, .remove = metronomefb_remove, .driver = { + .owner = THIS_MODULE, .name = "metronomefb", }, }; -static struct platform_device *metronomefb_device; - static int __init metronomefb_init(void) { - int ret; - - if (!metronomefb_enable) { - printk(KERN_ERR - "Use metronomefb_enable to enable the device\n"); - return -ENXIO; - } - - ret = platform_driver_register(&metronomefb_driver); - if (!ret) { - metronomefb_device = platform_device_alloc("metronomefb", 0); - if (metronomefb_device) - ret = platform_device_add(metronomefb_device); - else - ret = -ENOMEM; - - if (ret) { - platform_device_put(metronomefb_device); - platform_driver_unregister(&metronomefb_driver); - } - } - return ret; - + return platform_driver_register(&metronomefb_driver); } static void __exit metronomefb_exit(void) { - platform_device_unregister(metronomefb_device); platform_driver_unregister(&metronomefb_driver); } -module_param(metronomefb_enable, uint, 0); -MODULE_PARM_DESC(metronomefb_enable, "Enable communication with Metronome"); - module_init(metronomefb_init); module_exit(metronomefb_exit); diff --git a/drivers/video/modedb.c b/drivers/video/modedb.c index 08d072552233..473562191586 100644 --- a/drivers/video/modedb.c +++ b/drivers/video/modedb.c @@ -22,7 +22,7 @@ ((v).xres == (x) && (v).yres == (y)) #ifdef DEBUG -#define DPRINTK(fmt, args...) printk("modedb %s: " fmt, __FUNCTION__ , ## args) +#define DPRINTK(fmt, args...) printk("modedb %s: " fmt, __func__ , ## args) #else #define DPRINTK(fmt, args...) #endif @@ -522,7 +522,7 @@ int fb_find_mode(struct fb_var_screeninfo *var, int res_specified = 0, bpp_specified = 0, refresh_specified = 0; unsigned int xres = 0, yres = 0, bpp = default_bpp, refresh = 0; int yres_specified = 0, cvt = 0, rb = 0, interlace = 0, margins = 0; - u32 best, diff; + u32 best, diff, tdiff; for (i = namelen-1; i >= 0; i--) { switch (name[i]) { @@ -651,19 +651,27 @@ done: return (refresh_specified) ? 2 : 1; } - diff = xres + yres; + diff = 2 * (xres + yres); best = -1; DPRINTK("Trying best-fit modes\n"); for (i = 0; i < dbsize; i++) { - if (xres <= db[i].xres && yres <= db[i].yres) { DPRINTK("Trying %ix%i\n", db[i].xres, db[i].yres); if (!fb_try_mode(var, info, &db[i], bpp)) { - if (diff > (db[i].xres - xres) + (db[i].yres - yres)) { - diff = (db[i].xres - xres) + (db[i].yres - yres); - best = i; - } + tdiff = abs(db[i].xres - xres) + + abs(db[i].yres - yres); + + /* + * Penalize modes with resolutions smaller + * than requested. + */ + if (xres > db[i].xres || yres > db[i].yres) + tdiff += xres + yres; + + if (diff > tdiff) { + diff = tdiff; + best = i; + } } - } } if (best != -1) { fb_try_mode(var, info, &db[best], bpp); diff --git a/drivers/video/n411.c b/drivers/video/n411.c new file mode 100644 index 000000000000..935830fea7b6 --- /dev/null +++ b/drivers/video/n411.c @@ -0,0 +1,202 @@ +/* + * linux/drivers/video/n411.c -- Platform device for N411 EPD kit + * + * Copyright (C) 2008, Jaya Kumar + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + * + * Layout is based on skeletonfb.c by James Simmons and Geert Uytterhoeven. + * + * This driver is written to be used with the Hecuba display controller + * board, and tested with the EInk 800x600 display in 1 bit mode. + * The interface between Hecuba and the host is TTL based GPIO. The + * GPIO requirements are 8 writable data lines and 6 lines for control. + * Only 4 of the controls are actually used here but 6 for future use. + * The driver requires the IO addresses for data and control GPIO at + * load time. It is also possible to use this display with a standard + * PC parallel port. + * + * General notes: + * - User must set dio_addr=0xIOADDR cio_addr=0xIOADDR c2io_addr=0xIOADDR + * + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/list.h> +#include <linux/uaccess.h> +#include <linux/irq.h> + +#include <video/hecubafb.h> + +static unsigned long dio_addr; +static unsigned long cio_addr; +static unsigned long c2io_addr; +static unsigned long splashval; +static unsigned int nosplash; +static unsigned char ctl; + +static void n411_set_ctl(struct hecubafb_par *par, unsigned char bit, unsigned + char state) +{ + switch (bit) { + case HCB_CD_BIT: + if (state) + ctl &= ~(HCB_CD_BIT); + else + ctl |= HCB_CD_BIT; + break; + case HCB_DS_BIT: + if (state) + ctl &= ~(HCB_DS_BIT); + else + ctl |= HCB_DS_BIT; + break; + } + outb(ctl, cio_addr); +} + +static unsigned char n411_get_ctl(struct hecubafb_par *par) +{ + return inb(c2io_addr); +} + +static void n411_set_data(struct hecubafb_par *par, unsigned char value) +{ + outb(value, dio_addr); +} + +static void n411_wait_for_ack(struct hecubafb_par *par, int clear) +{ + int timeout; + unsigned char tmp; + + timeout = 500; + do { + tmp = n411_get_ctl(par); + if ((tmp & HCB_ACK_BIT) && (!clear)) + return; + else if (!(tmp & HCB_ACK_BIT) && (clear)) + return; + udelay(1); + } while (timeout--); + printk(KERN_ERR "timed out waiting for ack\n"); +} + +static int n411_init_control(struct hecubafb_par *par) +{ + unsigned char tmp; + /* for init, we want the following setup to be set: + WUP = lo + ACK = hi + DS = hi + RW = hi + CD = lo + */ + + /* write WUP to lo, DS to hi, RW to hi, CD to lo */ + ctl = HCB_WUP_BIT | HCB_RW_BIT | HCB_CD_BIT ; + n411_set_ctl(par, HCB_DS_BIT, 1); + + /* check ACK is not lo */ + tmp = n411_get_ctl(par); + if (tmp & HCB_ACK_BIT) { + printk(KERN_ERR "Fail because ACK is already low\n"); + return -ENXIO; + } + + return 0; +} + + +static int n411_init_board(struct hecubafb_par *par) +{ + int retval; + + retval = n411_init_control(par); + if (retval) + return retval; + + par->send_command(par, APOLLO_INIT_DISPLAY); + par->send_data(par, 0x81); + + /* have to wait while display resets */ + udelay(1000); + + /* if we were told to splash the screen, we just clear it */ + if (!nosplash) { + par->send_command(par, APOLLO_ERASE_DISPLAY); + par->send_data(par, splashval); + } + + return 0; +} + +static struct hecuba_board n411_board = { + .owner = THIS_MODULE, + .init = n411_init_board, + .set_ctl = n411_set_ctl, + .set_data = n411_set_data, + .wait_for_ack = n411_wait_for_ack, +}; + +static struct platform_device *n411_device; +static int __init n411_init(void) +{ + int ret; + if (!dio_addr || !cio_addr || !c2io_addr) { + printk(KERN_WARNING "no IO addresses supplied\n"); + return -EINVAL; + } + + /* request our platform independent driver */ + request_module("hecubafb"); + + n411_device = platform_device_alloc("hecubafb", -1); + if (!n411_device) + return -ENOMEM; + + platform_device_add_data(n411_device, &n411_board, sizeof(n411_board)); + + /* this _add binds hecubafb to n411. hecubafb refcounts n411 */ + ret = platform_device_add(n411_device); + + if (ret) + platform_device_put(n411_device); + + return ret; + +} + +static void __exit n411_exit(void) +{ + platform_device_unregister(n411_device); +} + +module_init(n411_init); +module_exit(n411_exit); + +module_param(nosplash, uint, 0); +MODULE_PARM_DESC(nosplash, "Disable doing the splash screen"); +module_param(dio_addr, ulong, 0); +MODULE_PARM_DESC(dio_addr, "IO address for data, eg: 0x480"); +module_param(cio_addr, ulong, 0); +MODULE_PARM_DESC(cio_addr, "IO address for control, eg: 0x400"); +module_param(c2io_addr, ulong, 0); +MODULE_PARM_DESC(c2io_addr, "IO address for secondary control, eg: 0x408"); +module_param(splashval, ulong, 0); +MODULE_PARM_DESC(splashval, "Splash pattern: 0x00 is black, 0x01 is white"); + +MODULE_DESCRIPTION("board driver for n411 hecuba/apollo epd kit"); +MODULE_AUTHOR("Jaya Kumar"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/video/nvidia/nv_hw.c b/drivers/video/nvidia/nv_hw.c index d1a10549f543..ed20a9871b33 100644 --- a/drivers/video/nvidia/nv_hw.c +++ b/drivers/video/nvidia/nv_hw.c @@ -129,7 +129,7 @@ typedef struct { int nvclk_khz; char mem_page_miss; char mem_latency; - int memory_type; + u32 memory_type; int memory_width; char enable_video; char gr_during_vid; @@ -719,7 +719,7 @@ static void nForceUpdateArbitrationSettings(unsigned VClk, memctrl >>= 16; if ((memctrl == 0x1A9) || (memctrl == 0x1AB) || (memctrl == 0x1ED)) { - int dimm[3]; + u32 dimm[3]; dev = pci_get_bus_and_slot(0, 2); pci_read_config_dword(dev, 0x40, &dimm[0]); diff --git a/drivers/video/nvidia/nv_setup.c b/drivers/video/nvidia/nv_setup.c index 82579d3a9970..d9627b57eb4d 100644 --- a/drivers/video/nvidia/nv_setup.c +++ b/drivers/video/nvidia/nv_setup.c @@ -265,12 +265,12 @@ static void nv10GetConfig(struct nvidia_par *par) dev = pci_get_bus_and_slot(0, 1); if ((par->Chipset & 0xffff) == 0x01a0) { - int amt = 0; + u32 amt; pci_read_config_dword(dev, 0x7c, &amt); par->RamAmountKBytes = (((amt >> 6) & 31) + 1) * 1024; } else if ((par->Chipset & 0xffff) == 0x01f0) { - int amt = 0; + u32 amt; pci_read_config_dword(dev, 0x84, &amt); par->RamAmountKBytes = (((amt >> 4) & 127) + 1) * 1024; diff --git a/drivers/video/nvidia/nvidia.c b/drivers/video/nvidia/nvidia.c index 596652d2831f..9dbb5a5a267b 100644 --- a/drivers/video/nvidia/nvidia.c +++ b/drivers/video/nvidia/nvidia.c @@ -43,14 +43,14 @@ #define NVTRACE if (0) printk #endif -#define NVTRACE_ENTER(...) NVTRACE("%s START\n", __FUNCTION__) -#define NVTRACE_LEAVE(...) NVTRACE("%s END\n", __FUNCTION__) +#define NVTRACE_ENTER(...) NVTRACE("%s START\n", __func__) +#define NVTRACE_LEAVE(...) NVTRACE("%s END\n", __func__) #ifdef CONFIG_FB_NVIDIA_DEBUG #define assert(expr) \ if (!(expr)) { \ printk( "Assertion failed! %s,%s,%s,line=%d\n",\ - #expr,__FILE__,__FUNCTION__,__LINE__); \ + #expr,__FILE__,__func__,__LINE__); \ BUG(); \ } #else @@ -1559,7 +1559,6 @@ static int __devinit nvidiafb_init(void) module_init(nvidiafb_init); -#ifdef MODULE static void __exit nvidiafb_exit(void) { pci_unregister_driver(&nvidiafb_driver); @@ -1615,5 +1614,3 @@ MODULE_PARM_DESC(nomtrr, "Disables MTRR support (0 or 1=disabled) " MODULE_AUTHOR("Antonino Daplas"); MODULE_DESCRIPTION("Framebuffer driver for nVidia graphics chipset"); MODULE_LICENSE("GPL"); -#endif /* MODULE */ - diff --git a/drivers/video/offb.c b/drivers/video/offb.c index 452433d46973..d7b3dcc0dc43 100644 --- a/drivers/video/offb.c +++ b/drivers/video/offb.c @@ -248,7 +248,7 @@ static void __iomem *offb_map_reg(struct device_node *np, int index, static void __init offb_init_fb(const char *name, const char *full_name, int width, int height, int depth, int pitch, unsigned long address, - struct device_node *dp) + int foreign_endian, struct device_node *dp) { unsigned long res_size = pitch * height * (depth + 7) / 8; struct offb_par *par = &default_par; @@ -397,7 +397,7 @@ static void __init offb_init_fb(const char *name, const char *full_name, info->screen_base = ioremap(address, fix->smem_len); info->par = par; info->pseudo_palette = (void *) (info + 1); - info->flags = FBINFO_DEFAULT; + info->flags = FBINFO_DEFAULT | foreign_endian; fb_alloc_cmap(&info->cmap, 256, 0); @@ -424,6 +424,15 @@ static void __init offb_init_nodriver(struct device_node *dp, int no_real_node) u64 rstart, address = OF_BAD_ADDR; const u32 *pp, *addrp, *up; u64 asize; + int foreign_endian = 0; + +#ifdef __BIG_ENDIAN + if (of_get_property(dp, "little-endian", NULL)) + foreign_endian = FBINFO_FOREIGN_ENDIAN; +#else + if (of_get_property(dp, "big-endian", NULL)) + foreign_endian = FBINFO_FOREIGN_ENDIAN; +#endif pp = of_get_property(dp, "linux,bootx-depth", &len); if (pp == NULL) @@ -509,7 +518,7 @@ static void __init offb_init_nodriver(struct device_node *dp, int no_real_node) offb_init_fb(no_real_node ? "bootx" : dp->name, no_real_node ? "display" : dp->full_name, width, height, depth, pitch, address, - no_real_node ? NULL : dp); + foreign_endian, no_real_node ? NULL : dp); } } diff --git a/drivers/video/p9100.c b/drivers/video/p9100.c index 58496061142d..c95874fe9076 100644 --- a/drivers/video/p9100.c +++ b/drivers/video/p9100.c @@ -310,7 +310,7 @@ static int __devinit p9100_probe(struct of_device *op, const struct of_device_id dev_set_drvdata(&op->dev, info); - printk("%s: p9100 at %lx:%lx\n", + printk(KERN_INFO "%s: p9100 at %lx:%lx\n", dp->full_name, par->which_io, par->physbase); diff --git a/drivers/video/pm2fb.c b/drivers/video/pm2fb.c index 30181b593829..3f1ca2adda3d 100644 --- a/drivers/video/pm2fb.c +++ b/drivers/video/pm2fb.c @@ -56,7 +56,7 @@ #undef PM2FB_MASTER_DEBUG #ifdef PM2FB_MASTER_DEBUG #define DPRINTK(a, b...) \ - printk(KERN_DEBUG "pm2fb: %s: " a, __FUNCTION__ , ## b) + printk(KERN_DEBUG "pm2fb: %s: " a, __func__ , ## b) #else #define DPRINTK(a, b...) #endif @@ -67,7 +67,7 @@ * Driver data */ static int hwcursor = 1; -static char *mode __devinitdata; +static char *mode_option __devinitdata; /* * The XFree GLINT driver will (I think to implement hardware cursor @@ -1680,17 +1680,19 @@ static int __devinit pm2fb_probe(struct pci_dev *pdev, info->pixmap.scan_align = 1; } - if (!mode) - mode = "640x480@60"; + if (!mode_option) + mode_option = "640x480@60"; - err = fb_find_mode(&info->var, info, mode, NULL, 0, NULL, 8); + err = fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 8); if (!err || err == 4) info->var = pm2fb_var; - if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) + retval = fb_alloc_cmap(&info->cmap, 256, 0); + if (retval < 0) goto err_exit_both; - if (register_framebuffer(info) < 0) + retval = register_framebuffer(info); + if (retval < 0) goto err_exit_all; printk(KERN_INFO "fb%d: %s frame buffer device, memory = %dK.\n", @@ -1797,7 +1799,7 @@ static int __init pm2fb_setup(char *options) else if (!strncmp(this_opt, "noaccel", 7)) noaccel = 1; else - mode = this_opt; + mode_option = this_opt; } return 0; } @@ -1833,8 +1835,10 @@ static void __exit pm2fb_exit(void) #ifdef MODULE module_exit(pm2fb_exit); -module_param(mode, charp, 0); -MODULE_PARM_DESC(mode, "Preferred video mode e.g. '648x480-8@60'"); +module_param(mode_option, charp, 0); +MODULE_PARM_DESC(mode_option, "Initial video mode e.g. '648x480-8@60'"); +module_param_named(mode, mode_option, charp, 0); +MODULE_PARM_DESC(mode, "Initial video mode e.g. '648x480-8@60' (deprecated)"); module_param(lowhsync, bool, 0); MODULE_PARM_DESC(lowhsync, "Force horizontal sync low regardless of mode"); module_param(lowvsync, bool, 0); diff --git a/drivers/video/pm3fb.c b/drivers/video/pm3fb.c index 5dba8cdd0517..68089d1456c2 100644 --- a/drivers/video/pm3fb.c +++ b/drivers/video/pm3fb.c @@ -45,7 +45,7 @@ #undef PM3FB_MASTER_DEBUG #ifdef PM3FB_MASTER_DEBUG #define DPRINTK(a, b...) \ - printk(KERN_DEBUG "pm3fb: %s: " a, __FUNCTION__ , ## b) + printk(KERN_DEBUG "pm3fb: %s: " a, __func__ , ## b) #else #define DPRINTK(a, b...) #endif @@ -1571,6 +1571,8 @@ module_exit(pm3fb_exit); #endif module_init(pm3fb_init); +module_param(mode_option, charp, 0); +MODULE_PARM_DESC(mode_option, "Initial video mode e.g. '648x480-8@60'"); module_param(noaccel, bool, 0); MODULE_PARM_DESC(noaccel, "Disable acceleration"); module_param(hwcursor, int, 0644); diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c index 97facb121c73..757651954e6c 100644 --- a/drivers/video/pxafb.c +++ b/drivers/video/pxafb.c @@ -45,6 +45,7 @@ #include <asm/irq.h> #include <asm/div64.h> #include <asm/arch/pxa-regs.h> +#include <asm/arch/pxa2xx-gpio.h> #include <asm/arch/bitfield.h> #include <asm/arch/pxafb.h> diff --git a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c index 5c47968e7f21..d94c57ffbdb1 100644 --- a/drivers/video/riva/fbdev.c +++ b/drivers/video/riva/fbdev.c @@ -56,10 +56,6 @@ #include "rivafb.h" #include "nvreg.h" -#ifndef CONFIG_PCI /* sanity check */ -#error This driver requires PCI support. -#endif - /* version number of this driver */ #define RIVAFB_VERSION "0.9.5b" @@ -74,14 +70,14 @@ #define NVTRACE if(0) printk #endif -#define NVTRACE_ENTER(...) NVTRACE("%s START\n", __FUNCTION__) -#define NVTRACE_LEAVE(...) NVTRACE("%s END\n", __FUNCTION__) +#define NVTRACE_ENTER(...) NVTRACE("%s START\n", __func__) +#define NVTRACE_LEAVE(...) NVTRACE("%s END\n", __func__) #ifdef CONFIG_FB_RIVA_DEBUG #define assert(expr) \ if(!(expr)) { \ printk( "Assertion failed! %s,%s,%s,line=%d\n",\ - #expr,__FILE__,__FUNCTION__,__LINE__); \ + #expr,__FILE__,__func__,__LINE__); \ BUG(); \ } #else @@ -2213,14 +2209,12 @@ static int __devinit rivafb_init(void) module_init(rivafb_init); -#ifdef MODULE static void __exit rivafb_exit(void) { pci_unregister_driver(&rivafb_driver); } module_exit(rivafb_exit); -#endif /* MODULE */ module_param(noaccel, bool, 0); MODULE_PARM_DESC(noaccel, "bool: disable acceleration"); diff --git a/drivers/video/riva/nv_driver.c b/drivers/video/riva/nv_driver.c index a11026812d1b..f3694cf17e58 100644 --- a/drivers/video/riva/nv_driver.c +++ b/drivers/video/riva/nv_driver.c @@ -41,11 +41,6 @@ #include "rivafb.h" #include "nvreg.h" - -#ifndef CONFIG_PCI /* sanity check */ -#error This driver requires PCI support. -#endif - #define PFX "rivafb: " static inline unsigned char MISCin(struct riva_par *par) @@ -163,7 +158,7 @@ unsigned long riva_get_memlen(struct riva_par *par) unsigned long memlen = 0; unsigned int chipset = par->Chipset; struct pci_dev* dev; - int amt; + u32 amt; switch (chip->Architecture) { case NV_ARCH_03: diff --git a/drivers/video/riva/riva_hw.c b/drivers/video/riva/riva_hw.c index 13307703a9f0..78fdbf5178d7 100644 --- a/drivers/video/riva/riva_hw.c +++ b/drivers/video/riva/riva_hw.c @@ -231,7 +231,7 @@ typedef struct { int nvclk_khz; char mem_page_miss; char mem_latency; - int memory_type; + u32 memory_type; int memory_width; char enable_video; char gr_during_vid; @@ -2107,7 +2107,7 @@ static void nv10GetConfig ) { struct pci_dev* dev; - int amt; + u32 amt; #ifdef __BIG_ENDIAN /* turn on big endian register access */ diff --git a/drivers/video/s3c2410fb.c b/drivers/video/s3c2410fb.c index 71fa6edb5c47..13b38cbbe4cf 100644 --- a/drivers/video/s3c2410fb.c +++ b/drivers/video/s3c2410fb.c @@ -430,9 +430,9 @@ static void s3c2410fb_activate_var(struct fb_info *info) struct fb_var_screeninfo *var = &info->var; int clkdiv = s3c2410fb_calc_pixclk(fbi, var->pixclock) / 2; - dprintk("%s: var->xres = %d\n", __FUNCTION__, var->xres); - dprintk("%s: var->yres = %d\n", __FUNCTION__, var->yres); - dprintk("%s: var->bpp = %d\n", __FUNCTION__, var->bits_per_pixel); + dprintk("%s: var->xres = %d\n", __func__, var->xres); + dprintk("%s: var->yres = %d\n", __func__, var->yres); + dprintk("%s: var->bpp = %d\n", __func__, var->bits_per_pixel); if (type == S3C2410_LCDCON1_TFT) { s3c2410fb_calculate_tft_lcd_regs(info, &fbi->regs); diff --git a/drivers/video/s3fb.c b/drivers/video/s3fb.c index 7d53bc23b9c7..2972f112dbed 100644 --- a/drivers/video/s3fb.c +++ b/drivers/video/s3fb.c @@ -132,10 +132,10 @@ static const struct svga_timing_regs s3_timing_regs = { /* Module parameters */ -static char *mode = "640x480-8@60"; +static char *mode_option __devinitdata = "640x480-8@60"; #ifdef CONFIG_MTRR -static int mtrr = 1; +static int mtrr __devinitdata = 1; #endif static int fasttext = 1; @@ -145,8 +145,10 @@ MODULE_AUTHOR("(c) 2006-2007 Ondrej Zajicek <santiago@crfreenet.org>"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("fbdev driver for S3 Trio/Virge"); -module_param(mode, charp, 0444); -MODULE_PARM_DESC(mode, "Default video mode ('640x480-8@60', etc)"); +module_param(mode_option, charp, 0444); +MODULE_PARM_DESC(mode_option, "Default video mode ('640x480-8@60', etc)"); +module_param_named(mode, mode_option, charp, 0444); +MODULE_PARM_DESC(mode, "Default video mode ('640x480-8@60', etc) (deprecated)"); #ifdef CONFIG_MTRR module_param(mtrr, int, 0444); @@ -886,7 +888,7 @@ static int __devinit s3_pci_probe(struct pci_dev *dev, const struct pci_device_i } /* Allocate and fill driver data structure */ - info = framebuffer_alloc(sizeof(struct s3fb_info), NULL); + info = framebuffer_alloc(sizeof(struct s3fb_info), &(dev->dev)); if (!info) { dev_err(&(dev->dev), "cannot allocate memory\n"); return -ENOMEM; @@ -901,13 +903,13 @@ static int __devinit s3_pci_probe(struct pci_dev *dev, const struct pci_device_i /* Prepare PCI device */ rc = pci_enable_device(dev); if (rc < 0) { - dev_err(&(dev->dev), "cannot enable PCI device\n"); + dev_err(info->dev, "cannot enable PCI device\n"); goto err_enable_device; } rc = pci_request_regions(dev, "s3fb"); if (rc < 0) { - dev_err(&(dev->dev), "cannot reserve framebuffer region\n"); + dev_err(info->dev, "cannot reserve framebuffer region\n"); goto err_request_regions; } @@ -919,7 +921,7 @@ static int __devinit s3_pci_probe(struct pci_dev *dev, const struct pci_device_i info->screen_base = pci_iomap(dev, 0, 0); if (! info->screen_base) { rc = -ENOMEM; - dev_err(&(dev->dev), "iomap for framebuffer failed\n"); + dev_err(info->dev, "iomap for framebuffer failed\n"); goto err_iomap; } @@ -960,22 +962,22 @@ static int __devinit s3_pci_probe(struct pci_dev *dev, const struct pci_device_i info->pseudo_palette = (void*) (par->pseudo_palette); /* Prepare startup mode */ - rc = fb_find_mode(&(info->var), info, mode, NULL, 0, NULL, 8); + rc = fb_find_mode(&(info->var), info, mode_option, NULL, 0, NULL, 8); if (! ((rc == 1) || (rc == 2))) { rc = -EINVAL; - dev_err(&(dev->dev), "mode %s not found\n", mode); + dev_err(info->dev, "mode %s not found\n", mode_option); goto err_find_mode; } rc = fb_alloc_cmap(&info->cmap, 256, 0); if (rc < 0) { - dev_err(&(dev->dev), "cannot allocate colormap\n"); + dev_err(info->dev, "cannot allocate colormap\n"); goto err_alloc_cmap; } rc = register_framebuffer(info); if (rc < 0) { - dev_err(&(dev->dev), "cannot register framebuffer\n"); + dev_err(info->dev, "cannot register framebuffer\n"); goto err_reg_fb; } @@ -1051,7 +1053,7 @@ static int s3_pci_suspend(struct pci_dev* dev, pm_message_t state) struct fb_info *info = pci_get_drvdata(dev); struct s3fb_info *par = info->par; - dev_info(&(dev->dev), "suspend\n"); + dev_info(info->dev, "suspend\n"); acquire_console_sem(); mutex_lock(&(par->open_lock)); @@ -1083,7 +1085,7 @@ static int s3_pci_resume(struct pci_dev* dev) struct s3fb_info *par = info->par; int err; - dev_info(&(dev->dev), "resume\n"); + dev_info(info->dev, "resume\n"); acquire_console_sem(); mutex_lock(&(par->open_lock)); @@ -1100,7 +1102,7 @@ static int s3_pci_resume(struct pci_dev* dev) if (err) { mutex_unlock(&(par->open_lock)); release_console_sem(); - dev_err(&(dev->dev), "error %d enabling device for resume\n", err); + dev_err(info->dev, "error %d enabling device for resume\n", err); return err; } pci_set_master(dev); @@ -1168,7 +1170,7 @@ static int __init s3fb_setup(char *options) else if (!strncmp(opt, "fasttext:", 9)) fasttext = simple_strtoul(opt + 9, NULL, 0); else - mode = opt; + mode_option = opt; } return 0; diff --git a/drivers/video/sa1100fb.h b/drivers/video/sa1100fb.h index 48066ef3af05..f465b27ed860 100644 --- a/drivers/video/sa1100fb.h +++ b/drivers/video/sa1100fb.h @@ -132,7 +132,7 @@ struct sa1100fb_info { * Debug macros */ #if DEBUG -# define DPRINTK(fmt, args...) printk("%s: " fmt, __FUNCTION__ , ## args) +# define DPRINTK(fmt, args...) printk("%s: " fmt, __func__ , ## args) #else # define DPRINTK(fmt, args...) #endif diff --git a/drivers/video/savage/savagefb-i2c.c b/drivers/video/savage/savagefb-i2c.c index 35c1ce62b216..783d4adffb93 100644 --- a/drivers/video/savage/savagefb-i2c.c +++ b/drivers/video/savage/savagefb-i2c.c @@ -140,7 +140,7 @@ static int savage_setup_i2c_bus(struct savagefb_i2c_chan *chan, chan->adapter.id = I2C_HW_B_SAVAGE; chan->adapter.algo_data = &chan->algo; chan->adapter.dev.parent = &chan->par->pcidev->dev; - chan->algo.udelay = 40; + chan->algo.udelay = 10; chan->algo.timeout = 20; chan->algo.data = chan; diff --git a/drivers/video/sis/sis.h b/drivers/video/sis/sis.h index 9b05da6268f7..a14e82211037 100644 --- a/drivers/video/sis/sis.h +++ b/drivers/video/sis/sis.h @@ -55,7 +55,7 @@ #undef SISFBDEBUG #ifdef SISFBDEBUG -#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args) +#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __func__ , ## args) #define TWDEBUG(x) printk(KERN_INFO x "\n"); #else #define DPRINTK(fmt, args...) diff --git a/drivers/video/sstfb.c b/drivers/video/sstfb.c index 97784f9c184d..5b11a00f49bc 100644 --- a/drivers/video/sstfb.c +++ b/drivers/video/sstfb.c @@ -1006,7 +1006,7 @@ static int sst_set_pll_att_ti(struct fb_info *info, break; default: dprintk("%s: wrong clock code '%d'\n", - __FUNCTION__, clock); + __func__, clock); return 0; } udelay(300); @@ -1048,7 +1048,7 @@ static int sst_set_pll_ics(struct fb_info *info, break; default: dprintk("%s: wrong clock code '%d'\n", - __FUNCTION__, clock); + __func__, clock); return 0; } udelay(300); @@ -1079,7 +1079,7 @@ static void sst_set_vidmod_att_ti(struct fb_info *info, const int bpp) sst_dac_write(DACREG_RMR, (cr0 & 0x0f) | DACREG_CR0_16BPP); break; default: - dprintk("%s: bad depth '%u'\n", __FUNCTION__, bpp); + dprintk("%s: bad depth '%u'\n", __func__, bpp); break; } } @@ -1093,7 +1093,7 @@ static void sst_set_vidmod_ics(struct fb_info *info, const int bpp) sst_dac_write(DACREG_ICS_CMD, DACREG_ICS_CMD_16BPP); break; default: - dprintk("%s: bad depth '%u'\n", __FUNCTION__, bpp); + dprintk("%s: bad depth '%u'\n", __func__, bpp); break; } } @@ -1133,7 +1133,7 @@ static int __devinit sst_detect_dactype(struct fb_info *info, struct sstfb_par * } if (!ret) return 0; - f_dprintk("%s found %s\n", __FUNCTION__, dacs[i].name); + f_dprintk("%s found %s\n", __func__, dacs[i].name); par->dac_sw = dacs[i]; return 1; } diff --git a/drivers/video/stifb.c b/drivers/video/stifb.c index f98be301140c..598d35eff935 100644 --- a/drivers/video/stifb.c +++ b/drivers/video/stifb.c @@ -164,11 +164,11 @@ static int __initdata stifb_bpp_pref[MAX_STI_ROMS]; # define DEBUG_ON() debug_on=1 # define WRITE_BYTE(value,fb,reg) do { if (debug_on) \ printk(KERN_DEBUG "%30s: WRITE_BYTE(0x%06x) = 0x%02x (old=0x%02x)\n", \ - __FUNCTION__, reg, value, READ_BYTE(fb,reg)); \ + __func__, reg, value, READ_BYTE(fb,reg)); \ gsc_writeb((value),(fb)->info.fix.mmio_start + (reg)); } while (0) # define WRITE_WORD(value,fb,reg) do { if (debug_on) \ printk(KERN_DEBUG "%30s: WRITE_WORD(0x%06x) = 0x%08x (old=0x%08x)\n", \ - __FUNCTION__, reg, value, READ_WORD(fb,reg)); \ + __func__, reg, value, READ_WORD(fb,reg)); \ gsc_writel((value),(fb)->info.fix.mmio_start + (reg)); } while (0) #endif /* DEBUG_STIFB_REGS */ diff --git a/drivers/video/syscopyarea.c b/drivers/video/syscopyarea.c index 37af10ab8f52..a352d5f46bbf 100644 --- a/drivers/video/syscopyarea.c +++ b/drivers/video/syscopyarea.c @@ -26,15 +26,15 @@ */ static void -bitcpy(unsigned long *dst, int dst_idx, const unsigned long *src, - int src_idx, int bits, unsigned n) +bitcpy(struct fb_info *p, unsigned long *dst, int dst_idx, + const unsigned long *src, int src_idx, int bits, unsigned n) { unsigned long first, last; int const shift = dst_idx-src_idx; int left, right; - first = FB_SHIFT_HIGH(~0UL, dst_idx); - last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits)); + first = FB_SHIFT_HIGH(p, ~0UL, dst_idx); + last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits)); if (!shift) { /* Same alignment for source and dest */ @@ -167,8 +167,8 @@ bitcpy(unsigned long *dst, int dst_idx, const unsigned long *src, */ static void -bitcpy_rev(unsigned long *dst, int dst_idx, const unsigned long *src, - int src_idx, int bits, unsigned n) +bitcpy_rev(struct fb_info *p, unsigned long *dst, int dst_idx, + const unsigned long *src, int src_idx, int bits, unsigned n) { unsigned long first, last; int shift; @@ -186,8 +186,8 @@ bitcpy_rev(unsigned long *dst, int dst_idx, const unsigned long *src, shift = dst_idx-src_idx; - first = FB_SHIFT_LOW(~0UL, bits - 1 - dst_idx); - last = ~(FB_SHIFT_LOW(~0UL, bits - 1 - ((dst_idx-n) % bits))); + first = FB_SHIFT_LOW(p, ~0UL, bits - 1 - dst_idx); + last = ~(FB_SHIFT_LOW(p, ~0UL, bits - 1 - ((dst_idx-n) % bits))); if (!shift) { /* Same alignment for source and dest */ @@ -353,7 +353,7 @@ void sys_copyarea(struct fb_info *p, const struct fb_copyarea *area) dst_idx &= (bytes - 1); src += src_idx >> (ffs(bits) - 1); src_idx &= (bytes - 1); - bitcpy_rev(dst, dst_idx, src, src_idx, bits, + bitcpy_rev(p, dst, dst_idx, src, src_idx, bits, width*p->var.bits_per_pixel); } } else { @@ -362,7 +362,7 @@ void sys_copyarea(struct fb_info *p, const struct fb_copyarea *area) dst_idx &= (bytes - 1); src += src_idx >> (ffs(bits) - 1); src_idx &= (bytes - 1); - bitcpy(dst, dst_idx, src, src_idx, bits, + bitcpy(p, dst, dst_idx, src, src_idx, bits, width*p->var.bits_per_pixel); dst_idx += bits_per_line; src_idx += bits_per_line; diff --git a/drivers/video/sysfillrect.c b/drivers/video/sysfillrect.c index a261e9e6a675..f94d6b6e29ee 100644 --- a/drivers/video/sysfillrect.c +++ b/drivers/video/sysfillrect.c @@ -22,16 +22,16 @@ */ static void -bitfill_aligned(unsigned long *dst, int dst_idx, unsigned long pat, - unsigned n, int bits) +bitfill_aligned(struct fb_info *p, unsigned long *dst, int dst_idx, + unsigned long pat, unsigned n, int bits) { unsigned long first, last; if (!n) return; - first = FB_SHIFT_HIGH(~0UL, dst_idx); - last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits)); + first = FB_SHIFT_HIGH(p, ~0UL, dst_idx); + last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits)); if (dst_idx+n <= bits) { /* Single word */ @@ -78,16 +78,16 @@ bitfill_aligned(unsigned long *dst, int dst_idx, unsigned long pat, */ static void -bitfill_unaligned(unsigned long *dst, int dst_idx, unsigned long pat, - int left, int right, unsigned n, int bits) +bitfill_unaligned(struct fb_info *p, unsigned long *dst, int dst_idx, + unsigned long pat, int left, int right, unsigned n, int bits) { unsigned long first, last; if (!n) return; - first = FB_SHIFT_HIGH(~0UL, dst_idx); - last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits)); + first = FB_SHIFT_HIGH(p, ~0UL, dst_idx); + last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits)); if (dst_idx+n <= bits) { /* Single word */ @@ -132,8 +132,8 @@ bitfill_unaligned(unsigned long *dst, int dst_idx, unsigned long pat, * Aligned pattern invert using 32/64-bit memory accesses */ static void -bitfill_aligned_rev(unsigned long *dst, int dst_idx, unsigned long pat, - unsigned n, int bits) +bitfill_aligned_rev(struct fb_info *p, unsigned long *dst, int dst_idx, + unsigned long pat, unsigned n, int bits) { unsigned long val = pat; unsigned long first, last; @@ -141,8 +141,8 @@ bitfill_aligned_rev(unsigned long *dst, int dst_idx, unsigned long pat, if (!n) return; - first = FB_SHIFT_HIGH(~0UL, dst_idx); - last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits)); + first = FB_SHIFT_HIGH(p, ~0UL, dst_idx); + last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits)); if (dst_idx+n <= bits) { /* Single word */ @@ -188,16 +188,17 @@ bitfill_aligned_rev(unsigned long *dst, int dst_idx, unsigned long pat, */ static void -bitfill_unaligned_rev(unsigned long *dst, int dst_idx, unsigned long pat, - int left, int right, unsigned n, int bits) +bitfill_unaligned_rev(struct fb_info *p, unsigned long *dst, int dst_idx, + unsigned long pat, int left, int right, unsigned n, + int bits) { unsigned long first, last; if (!n) return; - first = FB_SHIFT_HIGH(~0UL, dst_idx); - last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits)); + first = FB_SHIFT_HIGH(p, ~0UL, dst_idx); + last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits)); if (dst_idx+n <= bits) { /* Single word */ @@ -267,9 +268,9 @@ void sys_fillrect(struct fb_info *p, const struct fb_fillrect *rect) if (p->fbops->fb_sync) p->fbops->fb_sync(p); if (!left) { - void (*fill_op32)(unsigned long *dst, int dst_idx, - unsigned long pat, unsigned n, int bits) = - NULL; + void (*fill_op32)(struct fb_info *p, unsigned long *dst, + int dst_idx, unsigned long pat, unsigned n, + int bits) = NULL; switch (rect->rop) { case ROP_XOR: @@ -287,16 +288,16 @@ void sys_fillrect(struct fb_info *p, const struct fb_fillrect *rect) while (height--) { dst += dst_idx >> (ffs(bits) - 1); dst_idx &= (bits - 1); - fill_op32(dst, dst_idx, pat, width*bpp, bits); + fill_op32(p, dst, dst_idx, pat, width*bpp, bits); dst_idx += p->fix.line_length*8; } } else { int right; int r; int rot = (left-dst_idx) % bpp; - void (*fill_op)(unsigned long *dst, int dst_idx, - unsigned long pat, int left, int right, - unsigned n, int bits) = NULL; + void (*fill_op)(struct fb_info *p, unsigned long *dst, + int dst_idx, unsigned long pat, int left, + int right, unsigned n, int bits) = NULL; /* rotate pattern to correct start position */ pat = pat << rot | pat >> (bpp-rot); @@ -318,7 +319,7 @@ void sys_fillrect(struct fb_info *p, const struct fb_fillrect *rect) while (height--) { dst += dst_idx >> (ffs(bits) - 1); dst_idx &= (bits - 1); - fill_op(dst, dst_idx, pat, left, right, + fill_op(p, dst, dst_idx, pat, left, right, width*bpp, bits); r = (p->fix.line_length*8) % bpp; pat = pat << (bpp-r) | pat >> r; diff --git a/drivers/video/sysimgblt.c b/drivers/video/sysimgblt.c index bd7e7e9d155f..186c6f607be2 100644 --- a/drivers/video/sysimgblt.c +++ b/drivers/video/sysimgblt.c @@ -18,35 +18,31 @@ #define DEBUG #ifdef DEBUG -#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt,__FUNCTION__,## args) +#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt,__func__,## args) #else #define DPRINTK(fmt, args...) #endif -static const u32 cfb_tab8[] = { -#if defined(__BIG_ENDIAN) +static const u32 cfb_tab8_be[] = { 0x00000000,0x000000ff,0x0000ff00,0x0000ffff, 0x00ff0000,0x00ff00ff,0x00ffff00,0x00ffffff, 0xff000000,0xff0000ff,0xff00ff00,0xff00ffff, 0xffff0000,0xffff00ff,0xffffff00,0xffffffff -#elif defined(__LITTLE_ENDIAN) +}; + +static const u32 cfb_tab8_le[] = { 0x00000000,0xff000000,0x00ff0000,0xffff0000, 0x0000ff00,0xff00ff00,0x00ffff00,0xffffff00, 0x000000ff,0xff0000ff,0x00ff00ff,0xffff00ff, 0x0000ffff,0xff00ffff,0x00ffffff,0xffffffff -#else -#error FIXME: No endianness?? -#endif }; -static const u32 cfb_tab16[] = { -#if defined(__BIG_ENDIAN) +static const u32 cfb_tab16_be[] = { 0x00000000, 0x0000ffff, 0xffff0000, 0xffffffff -#elif defined(__LITTLE_ENDIAN) +}; + +static const u32 cfb_tab16_le[] = { 0x00000000, 0xffff0000, 0x0000ffff, 0xffffffff -#else -#error FIXME: No endianness?? -#endif }; static const u32 cfb_tab32[] = { @@ -72,7 +68,7 @@ static void color_imageblit(const struct fb_image *image, struct fb_info *p, val = 0; if (start_index) { - u32 start_mask = ~(FB_SHIFT_HIGH(~(u32)0, + u32 start_mask = ~(FB_SHIFT_HIGH(p, ~(u32)0, start_index)); val = *dst & start_mask; shift = start_index; @@ -83,20 +79,20 @@ static void color_imageblit(const struct fb_image *image, struct fb_info *p, color = palette[*src]; else color = *src; - color <<= FB_LEFT_POS(bpp); - val |= FB_SHIFT_HIGH(color, shift); + color <<= FB_LEFT_POS(p, bpp); + val |= FB_SHIFT_HIGH(p, color, shift); if (shift >= null_bits) { *dst++ = val; val = (shift == null_bits) ? 0 : - FB_SHIFT_LOW(color, 32 - shift); + FB_SHIFT_LOW(p, color, 32 - shift); } shift += bpp; shift &= (32 - 1); src++; } if (shift) { - u32 end_mask = FB_SHIFT_HIGH(~(u32)0, shift); + u32 end_mask = FB_SHIFT_HIGH(p, ~(u32)0, shift); *dst &= end_mask; *dst |= val; @@ -125,8 +121,8 @@ static void slow_imageblit(const struct fb_image *image, struct fb_info *p, u32 i, j, l; dst2 = dst1; - fgcolor <<= FB_LEFT_POS(bpp); - bgcolor <<= FB_LEFT_POS(bpp); + fgcolor <<= FB_LEFT_POS(p, bpp); + bgcolor <<= FB_LEFT_POS(p, bpp); for (i = image->height; i--; ) { shift = val = 0; @@ -137,7 +133,8 @@ static void slow_imageblit(const struct fb_image *image, struct fb_info *p, /* write leading bits */ if (start_index) { - u32 start_mask = ~(FB_SHIFT_HIGH(~(u32)0,start_index)); + u32 start_mask = ~(FB_SHIFT_HIGH(p, ~(u32)0, + start_index)); val = *dst & start_mask; shift = start_index; } @@ -145,13 +142,13 @@ static void slow_imageblit(const struct fb_image *image, struct fb_info *p, while (j--) { l--; color = (*s & (1 << l)) ? fgcolor : bgcolor; - val |= FB_SHIFT_HIGH(color, shift); + val |= FB_SHIFT_HIGH(p, color, shift); /* Did the bitshift spill bits to the next long? */ if (shift >= null_bits) { *dst++ = val; val = (shift == null_bits) ? 0 : - FB_SHIFT_LOW(color,32 - shift); + FB_SHIFT_LOW(p, color, 32 - shift); } shift += bpp; shift &= (32 - 1); @@ -160,7 +157,7 @@ static void slow_imageblit(const struct fb_image *image, struct fb_info *p, /* write trailing bits */ if (shift) { - u32 end_mask = FB_SHIFT_HIGH(~(u32)0, shift); + u32 end_mask = FB_SHIFT_HIGH(p, ~(u32)0, shift); *dst &= end_mask; *dst |= val; @@ -199,10 +196,10 @@ static void fast_imageblit(const struct fb_image *image, struct fb_info *p, switch (bpp) { case 8: - tab = cfb_tab8; + tab = fb_be_math(p) ? cfb_tab8_be : cfb_tab8_le; break; case 16: - tab = cfb_tab16; + tab = fb_be_math(p) ? cfb_tab16_be : cfb_tab16_le; break; case 32: default: diff --git a/drivers/video/tcx.c b/drivers/video/tcx.c index e5a9ddb3c8be..a71774305772 100644 --- a/drivers/video/tcx.c +++ b/drivers/video/tcx.c @@ -419,7 +419,7 @@ static int __devinit tcx_init_one(struct of_device *op) par->mmap_map[6].size = SBUS_MMAP_EMPTY; } - par->physbase = 0; + par->physbase = op->resource[0].start; par->which_io = op->resource[0].flags & IORESOURCE_BITS; for (i = 0; i < TCX_MMAP_ENTRIES; i++) { @@ -470,10 +470,10 @@ static int __devinit tcx_init_one(struct of_device *op) dev_set_drvdata(&op->dev, info); - printk("%s: TCX at %lx:%lx, %s\n", + printk(KERN_INFO "%s: TCX at %lx:%lx, %s\n", dp->full_name, par->which_io, - op->resource[0].start, + par->physbase, par->lowdepth ? "8-bit only" : "24-bit depth"); return 0; @@ -527,7 +527,7 @@ static struct of_platform_driver tcx_driver = { .remove = __devexit_p(tcx_remove), }; -int __init tcx_init(void) +static int __init tcx_init(void) { if (fb_get_options("tcxfb", NULL)) return -ENODEV; @@ -535,7 +535,7 @@ int __init tcx_init(void) return of_register_driver(&tcx_driver, &of_bus_type); } -void __exit tcx_exit(void) +static void __exit tcx_exit(void) { of_unregister_driver(&tcx_driver); } diff --git a/drivers/video/tdfxfb.c b/drivers/video/tdfxfb.c index 71e179ea5f95..ea9f19d25597 100644 --- a/drivers/video/tdfxfb.c +++ b/drivers/video/tdfxfb.c @@ -70,7 +70,7 @@ #include <video/tdfx.h> -#define DPRINTK(a, b...) pr_debug("fb: %s: " a, __FUNCTION__ , ## b) +#define DPRINTK(a, b...) pr_debug("fb: %s: " a, __func__ , ## b) #ifdef CONFIG_MTRR #include <asm/mtrr.h> diff --git a/drivers/video/tridentfb.c b/drivers/video/tridentfb.c index 0a4e07d43d2d..bd54cd0de39a 100644 --- a/drivers/video/tridentfb.c +++ b/drivers/video/tridentfb.c @@ -58,7 +58,7 @@ static int displaytype; /* defaults which are normally overriden by user values */ /* video mode */ -static char *mode = "640x480"; +static char *mode_option __devinitdata = "640x480"; static int bpp = 8; static int noaccel; @@ -73,7 +73,10 @@ static int memsize; static int memdiff; static int nativex; -module_param(mode, charp, 0); +module_param(mode_option, charp, 0); +MODULE_PARM_DESC(mode_option, "Initial video mode e.g. '648x480-8@60'"); +module_param_named(mode, mode_option, charp, 0); +MODULE_PARM_DESC(mode, "Initial video mode e.g. '648x480-8@60' (deprecated)"); module_param(bpp, int, 0); module_param(center, int, 0); module_param(stretch, int, 0); @@ -1297,7 +1300,8 @@ static int __devinit trident_pci_probe(struct pci_dev * dev, #endif fb_info.pseudo_palette = pseudo_pal; - if (!fb_find_mode(&default_var, &fb_info, mode, NULL, 0, NULL, bpp)) { + if (!fb_find_mode(&default_var, &fb_info, + mode_option, NULL, 0, NULL, bpp)) { err = -EINVAL; goto out_unmap2; } @@ -1385,7 +1389,7 @@ static struct pci_driver tridentfb_pci_driver = { * video=trident:800x600,bpp=16,noaccel */ #ifndef MODULE -static int tridentfb_setup(char *options) +static int __init tridentfb_setup(char *options) { char *opt; if (!options || !*options) @@ -1412,7 +1416,7 @@ static int tridentfb_setup(char *options) else if (!strncmp(opt, "nativex=", 8)) nativex = simple_strtoul(opt + 8, NULL, 0); else - mode = opt; + mode_option = opt; } return 0; } diff --git a/drivers/video/uvesafb.c b/drivers/video/uvesafb.c index 93361656316c..cdbb56edb6cb 100644 --- a/drivers/video/uvesafb.c +++ b/drivers/video/uvesafb.c @@ -181,7 +181,8 @@ static int uvesafb_exec(struct uvesafb_ktask *task) /* If all slots are taken -- bail out. */ if (uvfb_tasks[seq]) { mutex_unlock(&uvfb_lock); - return -EBUSY; + err = -EBUSY; + goto out; } /* Save a pointer to the kernel part of the task struct. */ @@ -205,7 +206,6 @@ static int uvesafb_exec(struct uvesafb_ktask *task) err = cn_netlink_send(m, 0, gfp_any()); } } - kfree(m); if (!err && !(task->t.flags & TF_EXIT)) err = !wait_for_completion_timeout(task->done, @@ -218,7 +218,8 @@ static int uvesafb_exec(struct uvesafb_ktask *task) seq++; if (seq >= UVESAFB_TASKS_MAX) seq = 0; - +out: + kfree(m); return err; } @@ -885,7 +886,7 @@ static int __devinit uvesafb_vbe_init_mode(struct fb_info *info) } /* fb_find_mode() failed */ - if (i == 0 || i >= 3) { + if (i == 0) { info->var.xres = 640; info->var.yres = 480; mode = (struct fb_videomode *) diff --git a/drivers/video/vermilion/vermilion.c b/drivers/video/vermilion/vermilion.c index 2aa71eb67c2b..c18f1884b550 100644 --- a/drivers/video/vermilion/vermilion.c +++ b/drivers/video/vermilion/vermilion.c @@ -112,8 +112,9 @@ static int vmlfb_alloc_vram_area(struct vram_area *va, unsigned max_order, /* * It seems like __get_free_pages only ups the usage count - * of the first page. This doesn't work with nopage mapping, so - * up the usage count once more. + * of the first page. This doesn't work with fault mapping, so + * up the usage count once more (XXX: should use split_page or + * compound page). */ memset((void *)va->logical, 0x00, va->size); diff --git a/drivers/video/vt8623fb.c b/drivers/video/vt8623fb.c index 4c3a63308df1..536ab11623f0 100644 --- a/drivers/video/vt8623fb.c +++ b/drivers/video/vt8623fb.c @@ -100,7 +100,7 @@ static struct svga_timing_regs vt8623_timing_regs = { /* Module parameters */ -static char *mode = "640x480-8@60"; +static char *mode_option = "640x480-8@60"; #ifdef CONFIG_MTRR static int mtrr = 1; @@ -110,8 +110,10 @@ MODULE_AUTHOR("(c) 2006 Ondrej Zajicek <santiago@crfreenet.org>"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("fbdev driver for integrated graphics core in VIA VT8623 [CLE266]"); -module_param(mode, charp, 0644); -MODULE_PARM_DESC(mode, "Default video mode ('640x480-8@60', etc)"); +module_param(mode_option, charp, 0644); +MODULE_PARM_DESC(mode_option, "Default video mode ('640x480-8@60', etc)"); +module_param_named(mode, mode_option, charp, 0); +MODULE_PARM_DESC(mode, "Default video mode e.g. '648x480-8@60' (deprecated)"); #ifdef CONFIG_MTRR module_param(mtrr, int, 0444); @@ -434,6 +436,10 @@ static int vt8623fb_set_par(struct fb_info *info) svga_wcrt_multi(vt8623_offset_regs, offset_value); svga_wseq_multi(vt8623_fetch_count_regs, fetch_value); + /* Clear H/V Skew */ + svga_wcrt_mask(0x03, 0x00, 0x60); + svga_wcrt_mask(0x05, 0x00, 0x60); + if (info->var.vmode & FB_VMODE_DOUBLE) svga_wcrt_mask(0x09, 0x80, 0x80); else @@ -655,7 +661,7 @@ static int __devinit vt8623_pci_probe(struct pci_dev *dev, const struct pci_devi } /* Allocate and fill driver data structure */ - info = framebuffer_alloc(sizeof(struct vt8623fb_info), NULL); + info = framebuffer_alloc(sizeof(struct vt8623fb_info), &(dev->dev)); if (! info) { dev_err(&(dev->dev), "cannot allocate memory\n"); return -ENOMEM; @@ -671,13 +677,13 @@ static int __devinit vt8623_pci_probe(struct pci_dev *dev, const struct pci_devi rc = pci_enable_device(dev); if (rc < 0) { - dev_err(&(dev->dev), "cannot enable PCI device\n"); + dev_err(info->dev, "cannot enable PCI device\n"); goto err_enable_device; } rc = pci_request_regions(dev, "vt8623fb"); if (rc < 0) { - dev_err(&(dev->dev), "cannot reserve framebuffer region\n"); + dev_err(info->dev, "cannot reserve framebuffer region\n"); goto err_request_regions; } @@ -690,14 +696,14 @@ static int __devinit vt8623_pci_probe(struct pci_dev *dev, const struct pci_devi info->screen_base = pci_iomap(dev, 0, 0); if (! info->screen_base) { rc = -ENOMEM; - dev_err(&(dev->dev), "iomap for framebuffer failed\n"); + dev_err(info->dev, "iomap for framebuffer failed\n"); goto err_iomap_1; } par->mmio_base = pci_iomap(dev, 1, 0); if (! par->mmio_base) { rc = -ENOMEM; - dev_err(&(dev->dev), "iomap for MMIO failed\n"); + dev_err(info->dev, "iomap for MMIO failed\n"); goto err_iomap_2; } @@ -708,7 +714,7 @@ static int __devinit vt8623_pci_probe(struct pci_dev *dev, const struct pci_devi if ((16 <= memsize1) && (memsize1 <= 64) && (memsize1 == memsize2)) info->screen_size = memsize1 << 20; else { - dev_err(&(dev->dev), "memory size detection failed (%x %x), suppose 16 MB\n", memsize1, memsize2); + dev_err(info->dev, "memory size detection failed (%x %x), suppose 16 MB\n", memsize1, memsize2); info->screen_size = 16 << 20; } @@ -722,22 +728,22 @@ static int __devinit vt8623_pci_probe(struct pci_dev *dev, const struct pci_devi /* Prepare startup mode */ - rc = fb_find_mode(&(info->var), info, mode, NULL, 0, NULL, 8); + rc = fb_find_mode(&(info->var), info, mode_option, NULL, 0, NULL, 8); if (! ((rc == 1) || (rc == 2))) { rc = -EINVAL; - dev_err(&(dev->dev), "mode %s not found\n", mode); + dev_err(info->dev, "mode %s not found\n", mode_option); goto err_find_mode; } rc = fb_alloc_cmap(&info->cmap, 256, 0); if (rc < 0) { - dev_err(&(dev->dev), "cannot allocate colormap\n"); + dev_err(info->dev, "cannot allocate colormap\n"); goto err_alloc_cmap; } rc = register_framebuffer(info); if (rc < 0) { - dev_err(&(dev->dev), "cannot register framebugger\n"); + dev_err(info->dev, "cannot register framebugger\n"); goto err_reg_fb; } @@ -811,7 +817,7 @@ static int vt8623_pci_suspend(struct pci_dev* dev, pm_message_t state) struct fb_info *info = pci_get_drvdata(dev); struct vt8623fb_info *par = info->par; - dev_info(&(dev->dev), "suspend\n"); + dev_info(info->dev, "suspend\n"); acquire_console_sem(); mutex_lock(&(par->open_lock)); @@ -842,7 +848,7 @@ static int vt8623_pci_resume(struct pci_dev* dev) struct fb_info *info = pci_get_drvdata(dev); struct vt8623fb_info *par = info->par; - dev_info(&(dev->dev), "resume\n"); + dev_info(info->dev, "resume\n"); acquire_console_sem(); mutex_lock(&(par->open_lock)); @@ -913,7 +919,7 @@ static int __init vt8623fb_init(void) return -ENODEV; if (option && *option) - mode = option; + mode_option = option; #endif pr_debug("vt8623fb: initializing\n"); diff --git a/drivers/video/w100fb.c b/drivers/video/w100fb.c index 003c49a490eb..30469bf906e5 100644 --- a/drivers/video/w100fb.c +++ b/drivers/video/w100fb.c @@ -765,8 +765,10 @@ int __init w100fb_probe(struct platform_device *pdev) printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, info->fix.id); return 0; out: - fb_dealloc_cmap(&info->cmap); - kfree(info->pseudo_palette); + if (info) { + fb_dealloc_cmap(&info->cmap); + kfree(info->pseudo_palette); + } if (remapped_fbuf != NULL) iounmap(remapped_fbuf); if (remapped_regs != NULL) diff --git a/drivers/video/xen-fbfront.c b/drivers/video/xen-fbfront.c new file mode 100644 index 000000000000..619a6f8d65a2 --- /dev/null +++ b/drivers/video/xen-fbfront.c @@ -0,0 +1,550 @@ +/* + * Xen para-virtual frame buffer device + * + * Copyright (C) 2005-2006 Anthony Liguori <aliguori@us.ibm.com> + * Copyright (C) 2006-2008 Red Hat, Inc., Markus Armbruster <armbru@redhat.com> + * + * Based on linux/drivers/video/q40fb.c + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + */ + +/* + * TODO: + * + * Switch to grant tables when they become capable of dealing with the + * frame buffer. + */ + +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/fb.h> +#include <linux/module.h> +#include <linux/vmalloc.h> +#include <linux/mm.h> +#include <asm/xen/hypervisor.h> +#include <xen/events.h> +#include <xen/page.h> +#include <xen/interface/io/fbif.h> +#include <xen/interface/io/protocols.h> +#include <xen/xenbus.h> + +struct xenfb_info { + unsigned char *fb; + struct fb_info *fb_info; + int x1, y1, x2, y2; /* dirty rectangle, + protected by dirty_lock */ + spinlock_t dirty_lock; + int nr_pages; + int irq; + struct xenfb_page *page; + unsigned long *mfns; + int update_wanted; /* XENFB_TYPE_UPDATE wanted */ + + struct xenbus_device *xbdev; +}; + +static u32 xenfb_mem_len = XENFB_WIDTH * XENFB_HEIGHT * XENFB_DEPTH / 8; + +static int xenfb_remove(struct xenbus_device *); +static void xenfb_init_shared_page(struct xenfb_info *); +static int xenfb_connect_backend(struct xenbus_device *, struct xenfb_info *); +static void xenfb_disconnect_backend(struct xenfb_info *); + +static void xenfb_do_update(struct xenfb_info *info, + int x, int y, int w, int h) +{ + union xenfb_out_event event; + u32 prod; + + event.type = XENFB_TYPE_UPDATE; + event.update.x = x; + event.update.y = y; + event.update.width = w; + event.update.height = h; + + prod = info->page->out_prod; + /* caller ensures !xenfb_queue_full() */ + mb(); /* ensure ring space available */ + XENFB_OUT_RING_REF(info->page, prod) = event; + wmb(); /* ensure ring contents visible */ + info->page->out_prod = prod + 1; + + notify_remote_via_irq(info->irq); +} + +static int xenfb_queue_full(struct xenfb_info *info) +{ + u32 cons, prod; + + prod = info->page->out_prod; + cons = info->page->out_cons; + return prod - cons == XENFB_OUT_RING_LEN; +} + +static void xenfb_refresh(struct xenfb_info *info, + int x1, int y1, int w, int h) +{ + unsigned long flags; + int y2 = y1 + h - 1; + int x2 = x1 + w - 1; + + if (!info->update_wanted) + return; + + spin_lock_irqsave(&info->dirty_lock, flags); + + /* Combine with dirty rectangle: */ + if (info->y1 < y1) + y1 = info->y1; + if (info->y2 > y2) + y2 = info->y2; + if (info->x1 < x1) + x1 = info->x1; + if (info->x2 > x2) + x2 = info->x2; + + if (xenfb_queue_full(info)) { + /* Can't send right now, stash it in the dirty rectangle */ + info->x1 = x1; + info->x2 = x2; + info->y1 = y1; + info->y2 = y2; + spin_unlock_irqrestore(&info->dirty_lock, flags); + return; + } + + /* Clear dirty rectangle: */ + info->x1 = info->y1 = INT_MAX; + info->x2 = info->y2 = 0; + + spin_unlock_irqrestore(&info->dirty_lock, flags); + + if (x1 <= x2 && y1 <= y2) + xenfb_do_update(info, x1, y1, x2 - x1 + 1, y2 - y1 + 1); +} + +static void xenfb_deferred_io(struct fb_info *fb_info, + struct list_head *pagelist) +{ + struct xenfb_info *info = fb_info->par; + struct page *page; + unsigned long beg, end; + int y1, y2, miny, maxy; + + miny = INT_MAX; + maxy = 0; + list_for_each_entry(page, pagelist, lru) { + beg = page->index << PAGE_SHIFT; + end = beg + PAGE_SIZE - 1; + y1 = beg / fb_info->fix.line_length; + y2 = end / fb_info->fix.line_length; + if (y2 >= fb_info->var.yres) + y2 = fb_info->var.yres - 1; + if (miny > y1) + miny = y1; + if (maxy < y2) + maxy = y2; + } + xenfb_refresh(info, 0, miny, fb_info->var.xres, maxy - miny + 1); +} + +static struct fb_deferred_io xenfb_defio = { + .delay = HZ / 20, + .deferred_io = xenfb_deferred_io, +}; + +static int xenfb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *info) +{ + u32 v; + + if (regno > info->cmap.len) + return 1; + +#define CNVT_TOHW(val, width) ((((val)<<(width))+0x7FFF-(val))>>16) + red = CNVT_TOHW(red, info->var.red.length); + green = CNVT_TOHW(green, info->var.green.length); + blue = CNVT_TOHW(blue, info->var.blue.length); + transp = CNVT_TOHW(transp, info->var.transp.length); +#undef CNVT_TOHW + + v = (red << info->var.red.offset) | + (green << info->var.green.offset) | + (blue << info->var.blue.offset); + + switch (info->var.bits_per_pixel) { + case 16: + case 24: + case 32: + ((u32 *)info->pseudo_palette)[regno] = v; + break; + } + + return 0; +} + +static void xenfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect) +{ + struct xenfb_info *info = p->par; + + sys_fillrect(p, rect); + xenfb_refresh(info, rect->dx, rect->dy, rect->width, rect->height); +} + +static void xenfb_imageblit(struct fb_info *p, const struct fb_image *image) +{ + struct xenfb_info *info = p->par; + + sys_imageblit(p, image); + xenfb_refresh(info, image->dx, image->dy, image->width, image->height); +} + +static void xenfb_copyarea(struct fb_info *p, const struct fb_copyarea *area) +{ + struct xenfb_info *info = p->par; + + sys_copyarea(p, area); + xenfb_refresh(info, area->dx, area->dy, area->width, area->height); +} + +static ssize_t xenfb_write(struct fb_info *p, const char __user *buf, + size_t count, loff_t *ppos) +{ + struct xenfb_info *info = p->par; + ssize_t res; + + res = fb_sys_write(p, buf, count, ppos); + xenfb_refresh(info, 0, 0, info->page->width, info->page->height); + return res; +} + +static struct fb_ops xenfb_fb_ops = { + .owner = THIS_MODULE, + .fb_read = fb_sys_read, + .fb_write = xenfb_write, + .fb_setcolreg = xenfb_setcolreg, + .fb_fillrect = xenfb_fillrect, + .fb_copyarea = xenfb_copyarea, + .fb_imageblit = xenfb_imageblit, +}; + +static irqreturn_t xenfb_event_handler(int rq, void *dev_id) +{ + /* + * No in events recognized, simply ignore them all. + * If you need to recognize some, see xen-kbdfront's + * input_handler() for how to do that. + */ + struct xenfb_info *info = dev_id; + struct xenfb_page *page = info->page; + + if (page->in_cons != page->in_prod) { + info->page->in_cons = info->page->in_prod; + notify_remote_via_irq(info->irq); + } + + /* Flush dirty rectangle: */ + xenfb_refresh(info, INT_MAX, INT_MAX, -INT_MAX, -INT_MAX); + + return IRQ_HANDLED; +} + +static int __devinit xenfb_probe(struct xenbus_device *dev, + const struct xenbus_device_id *id) +{ + struct xenfb_info *info; + struct fb_info *fb_info; + int ret; + + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (info == NULL) { + xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure"); + return -ENOMEM; + } + dev->dev.driver_data = info; + info->xbdev = dev; + info->irq = -1; + info->x1 = info->y1 = INT_MAX; + spin_lock_init(&info->dirty_lock); + + info->fb = vmalloc(xenfb_mem_len); + if (info->fb == NULL) + goto error_nomem; + memset(info->fb, 0, xenfb_mem_len); + + info->nr_pages = (xenfb_mem_len + PAGE_SIZE - 1) >> PAGE_SHIFT; + + info->mfns = vmalloc(sizeof(unsigned long) * info->nr_pages); + if (!info->mfns) + goto error_nomem; + + /* set up shared page */ + info->page = (void *)__get_free_page(GFP_KERNEL | __GFP_ZERO); + if (!info->page) + goto error_nomem; + + xenfb_init_shared_page(info); + + /* abusing framebuffer_alloc() to allocate pseudo_palette */ + fb_info = framebuffer_alloc(sizeof(u32) * 256, NULL); + if (fb_info == NULL) + goto error_nomem; + + /* complete the abuse: */ + fb_info->pseudo_palette = fb_info->par; + fb_info->par = info; + + fb_info->screen_base = info->fb; + + fb_info->fbops = &xenfb_fb_ops; + fb_info->var.xres_virtual = fb_info->var.xres = info->page->width; + fb_info->var.yres_virtual = fb_info->var.yres = info->page->height; + fb_info->var.bits_per_pixel = info->page->depth; + + fb_info->var.red = (struct fb_bitfield){16, 8, 0}; + fb_info->var.green = (struct fb_bitfield){8, 8, 0}; + fb_info->var.blue = (struct fb_bitfield){0, 8, 0}; + + fb_info->var.activate = FB_ACTIVATE_NOW; + fb_info->var.height = -1; + fb_info->var.width = -1; + fb_info->var.vmode = FB_VMODE_NONINTERLACED; + + fb_info->fix.visual = FB_VISUAL_TRUECOLOR; + fb_info->fix.line_length = info->page->line_length; + fb_info->fix.smem_start = 0; + fb_info->fix.smem_len = xenfb_mem_len; + strcpy(fb_info->fix.id, "xen"); + fb_info->fix.type = FB_TYPE_PACKED_PIXELS; + fb_info->fix.accel = FB_ACCEL_NONE; + + fb_info->flags = FBINFO_FLAG_DEFAULT; + + ret = fb_alloc_cmap(&fb_info->cmap, 256, 0); + if (ret < 0) { + framebuffer_release(fb_info); + xenbus_dev_fatal(dev, ret, "fb_alloc_cmap"); + goto error; + } + + fb_info->fbdefio = &xenfb_defio; + fb_deferred_io_init(fb_info); + + ret = register_framebuffer(fb_info); + if (ret) { + fb_deferred_io_cleanup(fb_info); + fb_dealloc_cmap(&fb_info->cmap); + framebuffer_release(fb_info); + xenbus_dev_fatal(dev, ret, "register_framebuffer"); + goto error; + } + info->fb_info = fb_info; + + ret = xenfb_connect_backend(dev, info); + if (ret < 0) + goto error; + + return 0; + + error_nomem: + ret = -ENOMEM; + xenbus_dev_fatal(dev, ret, "allocating device memory"); + error: + xenfb_remove(dev); + return ret; +} + +static int xenfb_resume(struct xenbus_device *dev) +{ + struct xenfb_info *info = dev->dev.driver_data; + + xenfb_disconnect_backend(info); + xenfb_init_shared_page(info); + return xenfb_connect_backend(dev, info); +} + +static int xenfb_remove(struct xenbus_device *dev) +{ + struct xenfb_info *info = dev->dev.driver_data; + + xenfb_disconnect_backend(info); + if (info->fb_info) { + fb_deferred_io_cleanup(info->fb_info); + unregister_framebuffer(info->fb_info); + fb_dealloc_cmap(&info->fb_info->cmap); + framebuffer_release(info->fb_info); + } + free_page((unsigned long)info->page); + vfree(info->mfns); + vfree(info->fb); + kfree(info); + + return 0; +} + +static unsigned long vmalloc_to_mfn(void *address) +{ + return pfn_to_mfn(vmalloc_to_pfn(address)); +} + +static void xenfb_init_shared_page(struct xenfb_info *info) +{ + int i; + + for (i = 0; i < info->nr_pages; i++) + info->mfns[i] = vmalloc_to_mfn(info->fb + i * PAGE_SIZE); + + info->page->pd[0] = vmalloc_to_mfn(info->mfns); + info->page->pd[1] = 0; + info->page->width = XENFB_WIDTH; + info->page->height = XENFB_HEIGHT; + info->page->depth = XENFB_DEPTH; + info->page->line_length = (info->page->depth / 8) * info->page->width; + info->page->mem_length = xenfb_mem_len; + info->page->in_cons = info->page->in_prod = 0; + info->page->out_cons = info->page->out_prod = 0; +} + +static int xenfb_connect_backend(struct xenbus_device *dev, + struct xenfb_info *info) +{ + int ret, evtchn; + struct xenbus_transaction xbt; + + ret = xenbus_alloc_evtchn(dev, &evtchn); + if (ret) + return ret; + ret = bind_evtchn_to_irqhandler(evtchn, xenfb_event_handler, + 0, dev->devicetype, info); + if (ret < 0) { + xenbus_free_evtchn(dev, evtchn); + xenbus_dev_fatal(dev, ret, "bind_evtchn_to_irqhandler"); + return ret; + } + info->irq = ret; + + again: + ret = xenbus_transaction_start(&xbt); + if (ret) { + xenbus_dev_fatal(dev, ret, "starting transaction"); + return ret; + } + ret = xenbus_printf(xbt, dev->nodename, "page-ref", "%lu", + virt_to_mfn(info->page)); + if (ret) + goto error_xenbus; + ret = xenbus_printf(xbt, dev->nodename, "event-channel", "%u", + evtchn); + if (ret) + goto error_xenbus; + ret = xenbus_printf(xbt, dev->nodename, "protocol", "%s", + XEN_IO_PROTO_ABI_NATIVE); + if (ret) + goto error_xenbus; + ret = xenbus_printf(xbt, dev->nodename, "feature-update", "1"); + if (ret) + goto error_xenbus; + ret = xenbus_transaction_end(xbt, 0); + if (ret) { + if (ret == -EAGAIN) + goto again; + xenbus_dev_fatal(dev, ret, "completing transaction"); + return ret; + } + + xenbus_switch_state(dev, XenbusStateInitialised); + return 0; + + error_xenbus: + xenbus_transaction_end(xbt, 1); + xenbus_dev_fatal(dev, ret, "writing xenstore"); + return ret; +} + +static void xenfb_disconnect_backend(struct xenfb_info *info) +{ + if (info->irq >= 0) + unbind_from_irqhandler(info->irq, info); + info->irq = -1; +} + +static void xenfb_backend_changed(struct xenbus_device *dev, + enum xenbus_state backend_state) +{ + struct xenfb_info *info = dev->dev.driver_data; + int val; + + switch (backend_state) { + case XenbusStateInitialising: + case XenbusStateInitialised: + case XenbusStateUnknown: + case XenbusStateClosed: + break; + + case XenbusStateInitWait: +InitWait: + xenbus_switch_state(dev, XenbusStateConnected); + break; + + case XenbusStateConnected: + /* + * Work around xenbus race condition: If backend goes + * through InitWait to Connected fast enough, we can + * get Connected twice here. + */ + if (dev->state != XenbusStateConnected) + goto InitWait; /* no InitWait seen yet, fudge it */ + + if (xenbus_scanf(XBT_NIL, info->xbdev->otherend, + "request-update", "%d", &val) < 0) + val = 0; + if (val) + info->update_wanted = 1; + break; + + case XenbusStateClosing: + xenbus_frontend_closed(dev); + break; + } +} + +static struct xenbus_device_id xenfb_ids[] = { + { "vfb" }, + { "" } +}; + +static struct xenbus_driver xenfb = { + .name = "vfb", + .owner = THIS_MODULE, + .ids = xenfb_ids, + .probe = xenfb_probe, + .remove = xenfb_remove, + .resume = xenfb_resume, + .otherend_changed = xenfb_backend_changed, +}; + +static int __init xenfb_init(void) +{ + if (!is_running_on_xen()) + return -ENODEV; + + /* Nothing to do if running in dom0. */ + if (is_initial_xendomain()) + return -ENODEV; + + return xenbus_register_frontend(&xenfb); +} + +static void __exit xenfb_cleanup(void) +{ + xenbus_unregister_driver(&xenfb); +} + +module_init(xenfb_init); +module_exit(xenfb_cleanup); + +MODULE_LICENSE("GPL"); |