GIT 4dc3595f5c569021b1bd0109502acfca82036902 git+ssh://master.kernel.org/pub/scm/linux/kernel/git/airlied/intelfb-2.6#intelfb-mm commit 4dc3595f5c569021b1bd0109502acfca82036902 Author: Parag Warudkar Date: Tue Aug 22 10:12:58 2006 +1000 intelfbhw.c: intelfbhw_get_p1p2 defined but not used intelfbhw_get_p1p2 is used only if REGDUMP is defined - compile it in only if REGDUMP is defined - one less compiler warning. Signed-off-by: Dave Airlie commit d5afabcea215a828eb00df992b429486aae14c2f Author: Dave Airlie Date: Tue Aug 22 10:10:56 2006 +1000 intelfb: fix mtrr_reg signedness This is my fix for gcc 4.1 sign issue reported by Eric Sesterhenn . Signed-off-by: Dave Airlie commit d463d34e7b336ae3645ac331adccb578ae5a4285 Author: Christian Merkle Date: Tue Aug 22 10:07:01 2006 +1000 intelfb: update doc and Kconfig (supported devices) According to drivers/video/intelfb/intelfb.h, the intelfb driver supportes the following devices: 830M/845G/852GM/855GM/865G/915G/915GM/945G/945GM. So the description in drivers/video/Kconfig and the documentation in Documentation/fb/intelfb.txt is outdated. airlied: cleaned up some other obvious mistakes in intelfb.txt. Signed-off-by: Christian Merkle Signed-off-by: Dave Airlie commit 7627899b11ece118b46fbf652e944f9a239f6cd1 Author: Dennis Munsie Date: Tue Jun 20 14:55:55 2006 -0400 intelfb: add preliminary i2c support Adds code to unregister the I2C buses in the cleanup function. Signed-off-by: Dennis Munsie commit 1f6e8449e11fd79ee30456ce7ec973317b8dd6ae Author: Dennis Munsie Date: Tue Jun 20 14:55:55 2006 -0400 intelfb: add preliminary i2c support [07/07] intelfb: adds an option to enable I2C support in the intelfb driver. Also adds the intel_i2c.c file to the Makefile. Signed-off-by: Dennis Munsie commit 41c9480a1d22e8f28b8675a2d7ec7fd4c50bc900 Author: Dennis Munsie Date: Tue Jun 20 14:55:55 2006 -0400 intelfb: add preliminary i2c support [06/07] intelfb: adds intelfb_i2c.c which contains the infrastructure needed to enumerate the i2c busses on the intelfb. Signed-off-by: Dennis Munsie commit dd696ec852dc34c40e2a18cc426c8f462c0715a5 Author: Dennis Munsie Date: Tue Jun 20 14:55:55 2006 -0400 intelfb: add preliminary i2c support [05/07] intelfb: add output fields to dinfo. Signed-off-by: Dennis Munsie commit 399fb4316ab4fe4c46d1e4ed8b12d56c94b4c251 Author: Dennis Munsie Date: Tue Jun 20 14:55:55 2006 -0400 intelfb: add preliminary i2c support [04/07] intelfb: add intelfb_output_rec struct and the constants for it's fields. Signed-off-by: Dennis Munsie commit 183b1214402a205bf6eea2030686249c7d365fd1 Author: Dennis Munsie Date: Tue Jun 20 14:55:55 2006 -0400 intelfb: add preliminary i2c support [03/07] intelfb: add intelfb_i2c_chan struct. Signed-off-by: Dennis Munsie commit 82c10f07c2d7baf6f280f206f9067a4715777962 Author: Dennis Munsie Date: Tue Jun 20 14:55:55 2006 -0400 intelfb: add preliminary i2c support [02/07] intelfb: add GPIO registers. Signed-off-by: Dennis Munsie commit c37bb26654bb8981ea237076e333eb37d4aa2dc6 Author: Dennis Munsie Date: Tue Jun 20 14:55:55 2006 -0400 intelfb: add preliminary i2c support [01/07] i2c: add intelfb bit algorithm id Adds the intelfb bit algorithm id to i2c-id.h. Signed-off-by: Dennis Munsie commit f80d0d23f2010b7682e06449345e8199a2b2619c Author: Eric Hustvedt Date: Tue Jun 20 14:36:42 2006 -0400 intelfb: add vsync interrupt support [05/05] intelfb: Honor FB_ACTIVATE_VBL for display panning Extends the intelfb_vsync struct to store panning offset. The interrupt service routine uses the stored panning offset if a pan is requested for the vsync. intelfbhw_disable_irq also pans the display if there is a pending request. Signed-off-by: Eric Hustvedt commit 37bced38b3d09c3de7c871790eddde81a3ce57cb Author: Eric Hustvedt Date: Tue Jun 20 14:36:42 2006 -0400 intelfb: add vsync interrupt support [04/05] intelfb: implement FBIO_WAITFORVSYNC ioctl The (unofficial) FBIO_WAITFORVSYNC ioctl is implemented by sleeping on the appropriate waitqueue, as defined in my earlier patch. Currently, only display 0 (aka pipe A) is supported. Signed-off-by: Eric Hustvedt commit 7649757bd900bc900adcd95ab08903cdc28342fa Author: Eric Hustvedt Date: Tue Jun 20 14:36:41 2006 -0400 intelfb: add vsync interrupt support [03/05] intelfb: Implement basic interrupt handling Functions have been added to enable and disable interrupts using the MMIO registers. Currently only pipe A vsync interrupts are enabled. A generalized vsync accounting struct is defined, with the intent that it can encapsulate per-pipe vsync related info in the future. Currently a single instance is hard-coded. The interrupt service routine currently only looks for vsync interrupts on pipe A, and increments a counter and wakes up anyone waiting on it. This implementation is heavily influenced by similar implementations in the atyfb and matroxfb drivers. Signed-off-by: Eric Hustvedt commit 9a5f019b1a9ea6a75ba36d7c312ff069006ed479 Author: Eric Hustvedt Date: Tue Jun 20 14:36:41 2006 -0400 intelfb: add vsync interrupt support [02/05] intelfb: Add interrupt related register definitions Add constants for accessing HWSTAM, IER, IIR, and IMR registers. Add constants for interrupt types supported by the 8xx and 9xx chipsets. The registers are also stored in the hwstate struct and dumped in the debug routine. Signed-off-by: Eric Hustvedt commit 3ce6fb4358bce6aced489f798138795163ad3f7c Author: Eric Hustvedt Date: Tue Jun 20 14:36:41 2006 -0400 intelfb: add vsync interrupt support [01/05] intelfb: Add 16-bit register access macros This patch adds macros to read and write two-byte MMIO registers. The interrupt-related registers are all word-sized, rather than long-sized. Signed-off-by: Eric Hustvedt Signed-off-by: Andrew Morton --- Documentation/fb/intelfb.txt | 11 - drivers/video/intelfb/Makefile | 4 drivers/video/intelfb/intelfb.h | 79 ++++++++++ drivers/video/intelfb/intelfb_i2c.c | 200 ++++++++++++++++++++++++++ drivers/video/intelfb/intelfbdrv.c | 64 ++++++++ drivers/video/intelfb/intelfbhw.c | 136 +++++++++++++++++ drivers/video/intelfb/intelfbhw.h | 25 +++ include/linux/i2c-id.h | 1 8 files changed, 513 insertions(+), 7 deletions(-) diff -puN Documentation/fb/intelfb.txt~git-intelfb Documentation/fb/intelfb.txt --- a/Documentation/fb/intelfb.txt~git-intelfb +++ a/Documentation/fb/intelfb.txt @@ -1,16 +1,19 @@ -Intel 830M/845G/852GM/855GM/865G/915G Framebuffer driver +Intel 830M/845G/852GM/855GM/865G/915G/945G Framebuffer driver ================================================================ A. Introduction - This is a framebuffer driver for various Intel 810/815 compatible + This is a framebuffer driver for various Intel 8xx/9xx compatible graphics devices. These would include: Intel 830M - Intel 810E845G + Intel 845G Intel 852GM Intel 855GM Intel 865G Intel 915G + Intel 915GM + Intel 945G + Intel 945GM B. List of available options @@ -78,7 +81,7 @@ C. Kernel booting Separate each option/option-pair by commas (,) and the option from its value with an equals sign (=) as in the following: -video=i810fb:option1,option2=value2 +video=intelfb:option1,option2=value2 Sample Usage ------------ diff -puN drivers/video/Kconfig~git-intelfb drivers/video/Kconfig diff -puN drivers/video/intelfb/Makefile~git-intelfb drivers/video/intelfb/Makefile --- a/drivers/video/intelfb/Makefile~git-intelfb +++ a/drivers/video/intelfb/Makefile @@ -1,6 +1,8 @@ obj-$(CONFIG_FB_INTEL) += intelfb.o -intelfb-objs := intelfbdrv.o intelfbhw.o +intelfb-y := intelfbdrv.o intelfbhw.o +intelfb-$(CONFIG_FB_INTEL_I2C) += intelfb_i2c.o +intelfb-objs := $(intelfb-y) ifdef CONFIG_FB_INTEL_DEBUG #EXTRA_CFLAGS += -DDEBUG -DVERBOSE -DREGDUMP diff -puN drivers/video/intelfb/intelfb.h~git-intelfb drivers/video/intelfb/intelfb.h --- a/drivers/video/intelfb/intelfb.h~git-intelfb +++ a/drivers/video/intelfb/intelfb.h @@ -6,6 +6,10 @@ #include #include +#ifdef CONFIG_FB_INTEL_I2C +#include +#include +#endif /*** Version/name ***/ #define INTELFB_VERSION "0.9.4" @@ -115,6 +119,29 @@ /* Intel agpgart driver */ #define AGP_PHYSICAL_MEMORY 2 +/* store information about an Ixxx DVO */ +/* The i830->i865 use multiple DVOs with multiple i2cs */ +/* the i915, i945 have a single sDVO i2c bus - which is different */ +#define MAX_OUTPUTS 6 + +/* these are outputs from the chip - integrated only + external chips are via DVO or SDVO output */ +#define INTELFB_OUTPUT_UNUSED 0 +#define INTELFB_OUTPUT_ANALOG 1 +#define INTELFB_OUTPUT_DVO 2 +#define INTELFB_OUTPUT_SDVO 3 +#define INTELFB_OUTPUT_LVDS 4 +#define INTELFB_OUTPUT_TVOUT 5 + +#define INTELFB_DVO_CHIP_NONE 0 +#define INTELFB_DVO_CHIP_LVDS 1 +#define INTELFB_DVO_CHIP_TMDS 2 +#define INTELFB_DVO_CHIP_TVOUT 4 + +#define INTELFB_OUTPUT_PIPE_NC 0 +#define INTELFB_OUTPUT_PIPE_A 1 +#define INTELFB_OUTPUT_PIPE_B 2 + /*** Data Types ***/ /* supported chipsets */ @@ -195,6 +222,10 @@ struct intelfb_hwstate { u32 mem_mode; u32 fw_blc_0; u32 fw_blc_1; + u16 hwstam; + u16 ier; + u16 iir; + u16 imr; }; struct intelfb_heap_data { @@ -204,6 +235,33 @@ struct intelfb_heap_data { u32 size; // in bytes }; +#ifdef CONFIG_FB_INTEL_I2C +struct intelfb_i2c_chan { + struct intelfb_info *dinfo; + u32 reg; + struct i2c_adapter adapter; + struct i2c_algo_bit_data algo; +}; +#endif + +struct intelfb_output_rec { + int type; + int pipe; + int flags; + +#ifdef CONFIG_FB_INTEL_I2C + struct intelfb_i2c_chan i2c_bus; + struct intelfb_i2c_chan ddc_bus; +#endif +}; + +struct intelfb_vsync { + wait_queue_head_t wait; + unsigned int count; + int pan_display; + u32 pan_offset; +}; + struct intelfb_info { struct fb_info *info; struct fb_ops *fbops; @@ -220,7 +278,7 @@ struct intelfb_info { u8 fbmem_gart; /* mtrr support */ - u32 mtrr_reg; + int mtrr_reg; u32 has_mtrr; /* heap data */ @@ -267,6 +325,12 @@ struct intelfb_info { int fixed_mode; int ring_active; int flag; + unsigned long irq_flags; + int open; + + /* vsync */ + struct intelfb_vsync vsync; + spinlock_t int_lock; /* hw cursor */ int cursor_on; @@ -285,12 +349,25 @@ struct intelfb_info { /* index into plls */ int pll_index; + + /* outputs */ + int num_outputs; + struct intelfb_output_rec output[MAX_OUTPUTS]; }; #define IS_I9XX(dinfo) (((dinfo)->chipset == INTEL_915G)||(dinfo->chipset == INTEL_915GM)||((dinfo)->chipset == INTEL_945G)||(dinfo->chipset==INTEL_945GM)) +#ifndef FBIO_WAITFORVSYNC +#define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32) +#endif + /*** function prototypes ***/ extern int intelfb_var_to_depth(const struct fb_var_screeninfo *var); +#ifdef CONFIG_FB_INTEL_I2C +extern void intelfb_create_i2c_busses(struct intelfb_info *dinfo); +extern void intelfb_delete_i2c_busses(struct intelfb_info *dinfo); +#endif + #endif /* _INTELFB_H */ diff -puN /dev/null drivers/video/intelfb/intelfb_i2c.c --- /dev/null +++ a/drivers/video/intelfb/intelfb_i2c.c @@ -0,0 +1,200 @@ +/************************************************************************** + + Copyright 2006 Dave Airlie + +All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +on the rights to use, copy, modify, merge, publish, distribute, sub +license, and/or sell copies of the Software, and to permit persons to whom +the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice (including the next +paragraph) shall be included in all copies or substantial portions of the +Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +THE COPYRIGHT HOLDERS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +USE OR OTHER DEALINGS IN THE SOFTWARE. + +**************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include "intelfb.h" +#include "intelfbhw.h" + +/* bit locations in the registers */ +#define SCL_DIR_MASK 0x0001 +#define SCL_DIR 0x0002 +#define SCL_VAL_MASK 0x0004 +#define SCL_VAL_OUT 0x0008 +#define SCL_VAL_IN 0x0010 +#define SDA_DIR_MASK 0x0100 +#define SDA_DIR 0x0200 +#define SDA_VAL_MASK 0x0400 +#define SDA_VAL_OUT 0x0800 +#define SDA_VAL_IN 0x1000 + +static void intelfb_gpio_setscl(void *data, int state) +{ + struct intelfb_i2c_chan *chan = data; + struct intelfb_info *dinfo = chan->dinfo; + u32 val; + + OUTREG(chan->reg, (state ? SCL_VAL_OUT : 0) | SCL_DIR | SCL_DIR_MASK | SCL_VAL_MASK); + val = INREG(chan->reg); +} + +static void intelfb_gpio_setsda(void *data, int state) +{ + struct intelfb_i2c_chan *chan = data; + struct intelfb_info *dinfo = chan->dinfo; + u32 val; + + OUTREG(chan->reg, (state ? SDA_VAL_OUT : 0) | SDA_DIR | SDA_DIR_MASK | SDA_VAL_MASK); + val = INREG(chan->reg); +} + +static int intelfb_gpio_getscl(void *data) +{ + struct intelfb_i2c_chan *chan = data; + struct intelfb_info *dinfo = chan->dinfo; + u32 val; + + OUTREG(chan->reg, SCL_DIR_MASK); + OUTREG(chan->reg, 0); + val = INREG(chan->reg); + return ((val & SCL_VAL_IN) != 0); +} + +static int intelfb_gpio_getsda(void *data) +{ + struct intelfb_i2c_chan *chan = data; + struct intelfb_info *dinfo = chan->dinfo; + u32 val; + + OUTREG(chan->reg, SDA_DIR_MASK); + OUTREG(chan->reg, 0); + val = INREG(chan->reg); + return ((val & SDA_VAL_IN) != 0); +} + +static int intelfb_setup_i2c_bus(struct intelfb_info *dinfo, + struct intelfb_i2c_chan *chan, + const u32 reg, const char *name) +{ + int rc; + + chan->dinfo = dinfo; + chan->reg = reg; + snprintf(chan->adapter.name, I2C_NAME_SIZE, "intelfb %s", name); + chan->adapter.owner = THIS_MODULE; + chan->adapter.id = I2C_HW_B_INTELFB; + chan->adapter.algo_data = &chan->algo; + chan->adapter.dev.parent = &chan->dinfo->pdev->dev; + chan->algo.setsda = intelfb_gpio_setsda; + chan->algo.setscl = intelfb_gpio_setscl; + chan->algo.getsda = intelfb_gpio_getsda; + chan->algo.getscl = intelfb_gpio_getscl; + chan->algo.udelay = 40; + chan->algo.timeout = 20; + chan->algo.data = chan; + + i2c_set_adapdata(&chan->adapter, chan); + + /* Raise SCL and SDA */ + intelfb_gpio_setsda(chan, 1); + intelfb_gpio_setscl(chan, 1); + udelay(20); + + rc = i2c_bit_add_bus(&chan->adapter); + if (rc == 0) + DBG_MSG("I2C bus %s registered.\n", name); + else + WRN_MSG("Failed to register I2C bus %s.\n", name); + return rc; +} + +void intelfb_create_i2c_busses(struct intelfb_info *dinfo) +{ + int i = 0; + + /* everyone has at least a single analog output */ + dinfo->num_outputs = 1; + dinfo->output[i].type = INTELFB_OUTPUT_ANALOG; + + /* setup the DDC bus for analog output */ + intelfb_setup_i2c_bus(dinfo, &dinfo->output[i].ddc_bus, GPIOA, "CRTDDC_A"); + i++; + + /* need to add the output busses for each device + - this function is very incomplete + - i915GM has LVDS and TVOUT for example + */ + switch(dinfo->chipset) { + case INTEL_830M: + case INTEL_845G: + case INTEL_855GM: + case INTEL_865G: + dinfo->output[i].type = INTELFB_OUTPUT_DVO; + intelfb_setup_i2c_bus(dinfo, &dinfo->output[i].ddc_bus, GPIOD, "DVODDC_D"); + intelfb_setup_i2c_bus(dinfo, &dinfo->output[i].i2c_bus, GPIOE, "DVOI2C_E"); + i++; + break; + case INTEL_915G: + case INTEL_915GM: + /* has some LVDS + tv-out */ + case INTEL_945G: + case INTEL_945GM: + /* 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, GPIOE, "SDVOCTRL_E"); + /* TODO: initialize the SDVO */ +// I830SDVOInit(pScrn, i, DVOB); + i++; + + /* set up SDVOC */ + dinfo->output[i].type = INTELFB_OUTPUT_SDVO; + dinfo->output[i].i2c_bus = dinfo->output[i - 1].i2c_bus; + /* TODO: initialize the SDVO */ +// I830SDVOInit(pScrn, i, DVOC); + i++; + break; + } + dinfo->num_outputs = i; +} + +void intelfb_delete_i2c_busses(struct intelfb_info *dinfo) +{ + int i; + + for (i = 0; i < MAX_OUTPUTS; i++) { + if (dinfo->output[i].i2c_bus.dinfo) { + i2c_bit_del_bus(&dinfo->output[i].i2c_bus.adapter); + dinfo->output[i].i2c_bus.dinfo = NULL; + } + if (dinfo->output[i].ddc_bus.dinfo) { + i2c_bit_del_bus(&dinfo->output[i].ddc_bus.adapter); + dinfo->output[i].ddc_bus.dinfo = NULL; + } + } +} diff -puN drivers/video/intelfb/intelfbdrv.c~git-intelfb drivers/video/intelfb/intelfbdrv.c --- a/drivers/video/intelfb/intelfbdrv.c~git-intelfb +++ a/drivers/video/intelfb/intelfbdrv.c @@ -136,6 +136,8 @@ static void __devinit get_initial_mode(struct intelfb_info *dinfo); static void update_dinfo(struct intelfb_info *dinfo, struct fb_var_screeninfo *var); +static int intelfb_open(struct fb_info *info, int user); +static int intelfb_release(struct fb_info *info, int user); static int intelfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info); static int intelfb_set_par(struct fb_info *info); @@ -194,6 +196,8 @@ static int num_registered = 0; /* fb ops */ static struct fb_ops intel_fb_ops = { .owner = THIS_MODULE, + .fb_open = intelfb_open, + .fb_release = intelfb_release, .fb_check_var = intelfb_check_var, .fb_set_par = intelfb_set_par, .fb_setcolreg = intelfb_setcolreg, @@ -446,6 +450,8 @@ cleanup(struct intelfb_info *dinfo) if (!dinfo) return; + intelfbhw_disable_irq(dinfo); + fb_dealloc_cmap(&dinfo->info->cmap); kfree(dinfo->info->pixmap.addr); @@ -467,6 +473,11 @@ cleanup(struct intelfb_info *dinfo) agp_free_memory(dinfo->gtt_ring_mem); } +#ifdef CONFIG_FB_INTEL_I2C + /* un-register I2C bus */ + intelfb_delete_i2c_busses(dinfo); +#endif + if (dinfo->mmio_base) iounmap((void __iomem *)dinfo->mmio_base); if (dinfo->aperture.virtual) @@ -844,6 +855,11 @@ intelfb_pci_register(struct pci_dev *pde if (bailearly == 5) bailout(dinfo); +#ifdef CONFIG_FB_INTEL_I2C + /* register I2C bus */ + intelfb_create_i2c_busses(dinfo); +#endif + if (bailearly == 6) bailout(dinfo); @@ -888,6 +904,13 @@ intelfb_pci_register(struct pci_dev *pde } dinfo->registered = 1; + dinfo->open = 0; + + init_waitqueue_head(&dinfo->vsync.wait); + spin_lock_init(&dinfo->int_lock); + dinfo->irq_flags = 0; + dinfo->vsync.pan_display = 0; + dinfo->vsync.pan_offset = 0; return 0; @@ -1188,6 +1211,34 @@ update_dinfo(struct intelfb_info *dinfo, ***************************************************************/ static int +intelfb_open(struct fb_info *info, int user) +{ + struct intelfb_info *dinfo = GET_DINFO(info); + + if (user) { + dinfo->open++; + } + + return 0; +} + +static int +intelfb_release(struct fb_info *info, int user) +{ + struct intelfb_info *dinfo = GET_DINFO(info); + + if (user) { + dinfo->open--; + msleep(1); + if (!dinfo->open) { + intelfbhw_disable_irq(dinfo); + } + } + + return 0; +} + +static int intelfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { int change_var = 0; @@ -1433,6 +1484,19 @@ static int intelfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) { int retval = 0; + struct intelfb_info *dinfo = GET_DINFO(info); + u32 pipe = 0; + + switch (cmd) { + case FBIO_WAITFORVSYNC: + if (get_user(pipe, (__u32 __user *)arg)) + return -EFAULT; + + retval = intelfbhw_wait_for_vsync(dinfo, pipe); + break; + default: + break; + } return retval; } diff -puN drivers/video/intelfb/intelfbhw.c~git-intelfb drivers/video/intelfb/intelfbhw.c --- a/drivers/video/intelfb/intelfbhw.c~git-intelfb +++ a/drivers/video/intelfb/intelfbhw.c @@ -32,6 +32,7 @@ #include #include #include +#include #include @@ -368,7 +369,13 @@ intelfbhw_pan_display(struct fb_var_scre offset += dinfo->fb.offset << 12; - OUTREG(DSPABASE, offset); + dinfo->vsync.pan_offset = offset; + if ((var->activate & FB_ACTIVATE_VBL) && !intelfbhw_enable_irq(dinfo, 0)) { + dinfo->vsync.pan_display = 1; + } else { + dinfo->vsync.pan_display = 0; + OUTREG(DSPABASE, offset); + } return 0; } @@ -585,6 +592,11 @@ intelfbhw_read_hw_state(struct intelfb_i hw->fw_blc_0 = INREG(FW_BLC_0); hw->fw_blc_1 = INREG(FW_BLC_1); + hw->hwstam = INREG16(HWSTAM); + hw->ier = INREG16(IER); + hw->iir = INREG16(IIR); + hw->imr = INREG16(IMR); + return 0; } @@ -613,6 +625,7 @@ static int calc_vclock(int index, int m1 return vco / p; } +#if REGDUMP static void intelfbhw_get_p1p2(struct intelfb_info *dinfo, int dpll, int *o_p1, int *o_p2) { @@ -638,6 +651,7 @@ intelfbhw_get_p1p2(struct intelfb_info * *o_p1 = p1; *o_p2 = p2; } +#endif void @@ -794,6 +808,10 @@ intelfbhw_print_hw_state(struct intelfb_ printk(" FW_BLC_0 0x%08x\n", hw->fw_blc_0); printk(" FW_BLC_1 0x%08x\n", hw->fw_blc_1); + printk(" HWSTAM 0x%04x\n", hw->hwstam); + printk(" IER 0x%04x\n", hw->ier); + printk(" IIR 0x%04x\n", hw->iir); + printk(" IMR 0x%04x\n", hw->imr); printk("hw state dump end\n"); #endif } @@ -1932,3 +1950,119 @@ intelfbhw_cursor_reset(struct intelfb_in addr += 16; } } + +static irqreturn_t +intelfbhw_irq(int irq, void *dev_id, struct pt_regs *fp) { + int handled = 0; + u16 tmp; + struct intelfb_info *dinfo = (struct intelfb_info *)dev_id; + + spin_lock(&dinfo->int_lock); + + tmp = INREG16(IIR); + tmp &= VSYNC_PIPE_A_INTERRUPT; + + if (tmp == 0) { + spin_unlock(&dinfo->int_lock); + return IRQ_RETVAL(handled); + } + + OUTREG16(IIR, tmp); + + if (tmp & VSYNC_PIPE_A_INTERRUPT) { + dinfo->vsync.count++; + if (dinfo->vsync.pan_display) { + dinfo->vsync.pan_display = 0; + OUTREG(DSPABASE, dinfo->vsync.pan_offset); + } + wake_up_interruptible(&dinfo->vsync.wait); + handled = 1; + } + + spin_unlock(&dinfo->int_lock); + + return IRQ_RETVAL(handled); +} + +int +intelfbhw_enable_irq(struct intelfb_info *dinfo, int reenable) { + + if (!test_and_set_bit(0, &dinfo->irq_flags)) { + if (request_irq(dinfo->pdev->irq, intelfbhw_irq, SA_SHIRQ, "intelfb", dinfo)) { + clear_bit(0, &dinfo->irq_flags); + return -EINVAL; + } + + spin_lock_irq(&dinfo->int_lock); + OUTREG16(HWSTAM, 0xfffe); + OUTREG16(IMR, 0x0); + OUTREG16(IER, VSYNC_PIPE_A_INTERRUPT); + spin_unlock_irq(&dinfo->int_lock); + } else if (reenable) { + u16 ier; + + spin_lock_irq(&dinfo->int_lock); + ier = INREG16(IER); + if ((ier & VSYNC_PIPE_A_INTERRUPT)) { + DBG_MSG("someone disabled the IRQ [%08X]\n", ier); + OUTREG(IER, VSYNC_PIPE_A_INTERRUPT); + } + spin_unlock_irq(&dinfo->int_lock); + } + return 0; +} + +void +intelfbhw_disable_irq(struct intelfb_info *dinfo) { + u16 tmp; + + if (test_and_clear_bit(0, &dinfo->irq_flags)) { + if (dinfo->vsync.pan_display) { + dinfo->vsync.pan_display = 0; + OUTREG(DSPABASE, dinfo->vsync.pan_offset); + } + spin_lock_irq(&dinfo->int_lock); + OUTREG16(HWSTAM, 0xffff); + OUTREG16(IMR, 0xffff); + OUTREG16(IER, 0x0); + + tmp = INREG16(IIR); + OUTREG16(IIR, tmp); + spin_unlock_irq(&dinfo->int_lock); + + free_irq(dinfo->pdev->irq, dinfo); + } +} + +int +intelfbhw_wait_for_vsync(struct intelfb_info *dinfo, u32 pipe) { + struct intelfb_vsync *vsync; + unsigned int count; + int ret; + + switch (pipe) { + case 0: + vsync = &dinfo->vsync; + break; + default: + return -ENODEV; + } + + ret = intelfbhw_enable_irq(dinfo, 0); + if (ret) { + return ret; + } + + count = vsync->count; + ret = wait_event_interruptible_timeout(vsync->wait, count != vsync->count, HZ/10); + if (ret < 0) { + return ret; + } + if (ret == 0) { + intelfbhw_enable_irq(dinfo, 1); + DBG_MSG("wait_for_vsync timed out!\n"); + return -ETIMEDOUT; + } + + return 0; +} diff -puN drivers/video/intelfb/intelfbhw.h~git-intelfb drivers/video/intelfb/intelfbhw.h --- a/drivers/video/intelfb/intelfbhw.h~git-intelfb +++ a/drivers/video/intelfb/intelfbhw.h @@ -88,6 +88,19 @@ #define INSTDONE 0x2090 #define PRI_RING_EMPTY 1 +#define HWSTAM 0x2098 +#define IER 0x20A0 +#define IIR 0x20A4 +#define IMR 0x20A8 +#define VSYNC_PIPE_A_INTERRUPT (1 << 7) +#define PIPE_A_EVENT_INTERRUPT (1 << 4) +#define VSYNC_PIPE_B_INTERRUPT (1 << 5) +#define PIPE_B_EVENT_INTERRUPT (1 << 4) +#define HOST_PORT_EVENT_INTERRUPT (1 << 3) +#define CAPTURE_EVENT_INTERRUPT (1 << 2) +#define USER_DEFINED_INTERRUPT (1 << 1) +#define BREAKPOINT_INTERRUPT 1 + #define INSTPM 0x20c0 #define SYNC_FLUSH_ENABLE (1 << 5) @@ -113,6 +126,12 @@ #define FW_DISPC_BL_SHIFT 8 #define FW_DISPC_BL_MASK 0x7 +#define GPIOA 0x5010 +#define GPIOB 0x5014 +#define GPIOC 0x5018 // this may be external DDC on i830 +#define GPIOD 0x501C // this is DVO DDC +#define GPIOE 0x5020 // this is DVO i2C +#define GPIOF 0x5024 /* PLL registers */ #define VGA0_DIVISOR 0x06000 @@ -468,9 +487,12 @@ /* I/O macros */ #define INREG8(addr) readb((u8 __iomem *)(dinfo->mmio_base + (addr))) +#define INREG16(addr) readw((u16 __iomem *)(dinfo->mmio_base + (addr))) #define INREG(addr) readl((u32 __iomem *)(dinfo->mmio_base + (addr))) #define OUTREG8(addr, val) writeb((val),(u8 __iomem *)(dinfo->mmio_base + \ (addr))) +#define OUTREG16(addr, val) writew((val),(u16 __iomem *)(dinfo->mmio_base + \ + (addr))) #define OUTREG(addr, val) writel((val),(u32 __iomem *)(dinfo->mmio_base + \ (addr))) @@ -545,5 +567,8 @@ extern void intelfbhw_cursor_setcolor(st extern void intelfbhw_cursor_load(struct intelfb_info *dinfo, int width, int height, u8 *data); extern void intelfbhw_cursor_reset(struct intelfb_info *dinfo); +extern int intelfbhw_enable_irq(struct intelfb_info *dinfo, int reenable); +extern void intelfbhw_disable_irq(struct intelfb_info *dinfo); +extern int intelfbhw_wait_for_vsync(struct intelfb_info *dinfo, u32 pipe); #endif /* _INTELFBHW_H */ diff -puN include/linux/i2c-id.h~git-intelfb include/linux/i2c-id.h --- a/include/linux/i2c-id.h~git-intelfb +++ a/include/linux/i2c-id.h @@ -193,6 +193,7 @@ #define I2C_HW_B_RADEON 0x01001e /* radeon framebuffer driver */ #define I2C_HW_B_EM28XX 0x01001f /* em28xx video capture cards */ #define I2C_HW_B_CX2341X 0x010020 /* Conexant CX2341X MPEG encoder cards */ +#define I2C_HW_B_INTELFB 0x010021 /* intel framebuffer driver */ /* --- PCF 8584 based algorithms */ #define I2C_HW_P_LP 0x020000 /* Parallel port interface */ _