From 3ce6fb4358bce6aced489f798138795163ad3f7c Mon Sep 17 00:00:00 2001 From: Eric Hustvedt Date: Tue, 20 Jun 2006 14:36:41 -0400 Subject: [PATCH 01/16] 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 --- drivers/video/intelfb/intelfbhw.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/video/intelfb/intelfbhw.h b/drivers/video/intelfb/intelfbhw.h index 10acda098b71..258235149913 100644 --- a/drivers/video/intelfb/intelfbhw.h +++ b/drivers/video/intelfb/intelfbhw.h @@ -468,9 +468,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))) From 9a5f019b1a9ea6a75ba36d7c312ff069006ed479 Mon Sep 17 00:00:00 2001 From: Eric Hustvedt Date: Tue, 20 Jun 2006 14:36:41 -0400 Subject: [PATCH 02/16] 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 --- drivers/video/intelfb/intelfb.h | 4 ++++ drivers/video/intelfb/intelfbhw.c | 9 +++++++++ drivers/video/intelfb/intelfbhw.h | 13 +++++++++++++ 3 files changed, 26 insertions(+) diff --git a/drivers/video/intelfb/intelfb.h b/drivers/video/intelfb/intelfb.h index e290d7460e1b..cb016fe4d488 100644 --- a/drivers/video/intelfb/intelfb.h +++ b/drivers/video/intelfb/intelfb.h @@ -195,6 +195,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 { diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c index 7533b3dd08ac..05aded669cdb 100644 --- a/drivers/video/intelfb/intelfbhw.c +++ b/drivers/video/intelfb/intelfbhw.c @@ -587,6 +587,11 @@ intelfbhw_read_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw, 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; } @@ -796,6 +801,10 @@ intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw) 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 } diff --git a/drivers/video/intelfb/intelfbhw.h b/drivers/video/intelfb/intelfbhw.h index 258235149913..8d2e36972fc8 100644 --- a/drivers/video/intelfb/intelfbhw.h +++ b/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) From 7649757bd900bc900adcd95ab08903cdc28342fa Mon Sep 17 00:00:00 2001 From: Eric Hustvedt Date: Tue, 20 Jun 2006 14:36:41 -0400 Subject: [PATCH 03/16] 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 --- drivers/video/intelfb/intelfb.h | 11 +++++ drivers/video/intelfb/intelfbdrv.c | 39 +++++++++++++++ drivers/video/intelfb/intelfbhw.c | 76 ++++++++++++++++++++++++++++++ drivers/video/intelfb/intelfbhw.h | 2 + 4 files changed, 128 insertions(+) diff --git a/drivers/video/intelfb/intelfb.h b/drivers/video/intelfb/intelfb.h index cb016fe4d488..dab1f2d764d2 100644 --- a/drivers/video/intelfb/intelfb.h +++ b/drivers/video/intelfb/intelfb.h @@ -208,6 +208,11 @@ struct intelfb_heap_data { u32 size; // in bytes }; +struct intelfb_vsync { + wait_queue_head_t wait; + unsigned int count; +}; + struct intelfb_info { struct fb_info *info; struct fb_ops *fbops; @@ -271,6 +276,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; diff --git a/drivers/video/intelfb/intelfbdrv.c b/drivers/video/intelfb/intelfbdrv.c index 0a0a8b199ecc..068c56d4e652 100644 --- a/drivers/video/intelfb/intelfbdrv.c +++ b/drivers/video/intelfb/intelfbdrv.c @@ -137,6 +137,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); @@ -195,6 +197,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, @@ -447,6 +451,8 @@ cleanup(struct intelfb_info *dinfo) if (!dinfo) return; + intelfbhw_disable_irq(dinfo); + fb_dealloc_cmap(&dinfo->info->cmap); kfree(dinfo->info->pixmap.addr); @@ -889,6 +895,11 @@ intelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent) } dinfo->registered = 1; + dinfo->open = 0; + + init_waitqueue_head(&dinfo->vsync.wait); + spin_lock_init(&dinfo->int_lock); + dinfo->irq_flags = 0; return 0; @@ -1188,6 +1199,34 @@ update_dinfo(struct intelfb_info *dinfo, struct fb_var_screeninfo *var) * fbdev interface * ***************************************************************/ +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) { diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c index 05aded669cdb..1a698a7230e0 100644 --- a/drivers/video/intelfb/intelfbhw.c +++ b/drivers/video/intelfb/intelfbhw.c @@ -34,6 +34,7 @@ #include #include #include +#include #include @@ -1943,3 +1944,78 @@ intelfbhw_cursor_reset(struct intelfb_info *dinfo) { 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++; + 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)) { + 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); + } +} diff --git a/drivers/video/intelfb/intelfbhw.h b/drivers/video/intelfb/intelfbhw.h index 8d2e36972fc8..aa0c139a2301 100644 --- a/drivers/video/intelfb/intelfbhw.h +++ b/drivers/video/intelfb/intelfbhw.h @@ -561,5 +561,7 @@ extern void intelfbhw_cursor_setcolor(struct intelfb_info *dinfo, u32 bg, 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); #endif /* _INTELFBHW_H */ From 37bced38b3d09c3de7c871790eddde81a3ce57cb Mon Sep 17 00:00:00 2001 From: Eric Hustvedt Date: Tue, 20 Jun 2006 14:36:42 -0400 Subject: [PATCH 04/16] 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 --- drivers/video/intelfb/intelfb.h | 4 ++++ drivers/video/intelfb/intelfbdrv.c | 13 ++++++++++++ drivers/video/intelfb/intelfbhw.c | 33 ++++++++++++++++++++++++++++++ drivers/video/intelfb/intelfbhw.h | 1 + 4 files changed, 51 insertions(+) diff --git a/drivers/video/intelfb/intelfb.h b/drivers/video/intelfb/intelfb.h index dab1f2d764d2..65ac37071a02 100644 --- a/drivers/video/intelfb/intelfb.h +++ b/drivers/video/intelfb/intelfb.h @@ -304,6 +304,10 @@ struct intelfb_info { #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); diff --git a/drivers/video/intelfb/intelfbdrv.c b/drivers/video/intelfb/intelfbdrv.c index 068c56d4e652..08f8241bb92a 100644 --- a/drivers/video/intelfb/intelfbdrv.c +++ b/drivers/video/intelfb/intelfbdrv.c @@ -1473,6 +1473,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 --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c index 1a698a7230e0..0f9631c2ad33 100644 --- a/drivers/video/intelfb/intelfbhw.c +++ b/drivers/video/intelfb/intelfbhw.c @@ -2019,3 +2019,36 @@ intelfbhw_disable_irq(struct intelfb_info *dinfo) { 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 --git a/drivers/video/intelfb/intelfbhw.h b/drivers/video/intelfb/intelfbhw.h index aa0c139a2301..36980c785e13 100644 --- a/drivers/video/intelfb/intelfbhw.h +++ b/drivers/video/intelfb/intelfbhw.h @@ -563,5 +563,6 @@ extern void intelfbhw_cursor_load(struct intelfb_info *dinfo, int width, 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 */ From f80d0d23f2010b7682e06449345e8199a2b2619c Mon Sep 17 00:00:00 2001 From: Eric Hustvedt Date: Tue, 20 Jun 2006 14:36:42 -0400 Subject: [PATCH 05/16] 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 --- drivers/video/intelfb/intelfb.h | 2 ++ drivers/video/intelfb/intelfbdrv.c | 2 ++ drivers/video/intelfb/intelfbhw.c | 16 +++++++++++++++- 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/drivers/video/intelfb/intelfb.h b/drivers/video/intelfb/intelfb.h index 65ac37071a02..abd4c5632e38 100644 --- a/drivers/video/intelfb/intelfb.h +++ b/drivers/video/intelfb/intelfb.h @@ -211,6 +211,8 @@ struct intelfb_heap_data { struct intelfb_vsync { wait_queue_head_t wait; unsigned int count; + int pan_display; + u32 pan_offset; }; struct intelfb_info { diff --git a/drivers/video/intelfb/intelfbdrv.c b/drivers/video/intelfb/intelfbdrv.c index 08f8241bb92a..9e93f820a939 100644 --- a/drivers/video/intelfb/intelfbdrv.c +++ b/drivers/video/intelfb/intelfbdrv.c @@ -900,6 +900,8 @@ intelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent) 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; diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c index 0f9631c2ad33..8038f558611d 100644 --- a/drivers/video/intelfb/intelfbhw.c +++ b/drivers/video/intelfb/intelfbhw.c @@ -371,7 +371,13 @@ intelfbhw_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) 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; } @@ -1965,6 +1971,10 @@ intelfbhw_irq(int irq, void *dev_id, struct pt_regs *fp) { 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; } @@ -2007,6 +2017,10 @@ 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); From c37bb26654bb8981ea237076e333eb37d4aa2dc6 Mon Sep 17 00:00:00 2001 From: Dennis Munsie Date: Tue, 20 Jun 2006 14:55:55 -0400 Subject: [PATCH 06/16] 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 --- include/linux/i2c-id.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h index c8b81f419fd8..cce6074dd754 100644 --- a/include/linux/i2c-id.h +++ b/include/linux/i2c-id.h @@ -189,6 +189,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 */ From 82c10f07c2d7baf6f280f206f9067a4715777962 Mon Sep 17 00:00:00 2001 From: Dennis Munsie Date: Tue, 20 Jun 2006 14:55:55 -0400 Subject: [PATCH 07/16] intelfb: add preliminary i2c support [02/07] intelfb: add GPIO registers. Signed-off-by: Dennis Munsie --- drivers/video/intelfb/intelfbhw.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/video/intelfb/intelfbhw.h b/drivers/video/intelfb/intelfbhw.h index 36980c785e13..8c54ba8fbdda 100644 --- a/drivers/video/intelfb/intelfbhw.h +++ b/drivers/video/intelfb/intelfbhw.h @@ -126,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 From 183b1214402a205bf6eea2030686249c7d365fd1 Mon Sep 17 00:00:00 2001 From: Dennis Munsie Date: Tue, 20 Jun 2006 14:55:55 -0400 Subject: [PATCH 08/16] intelfb: add preliminary i2c support [03/07] intelfb: add intelfb_i2c_chan struct. Signed-off-by: Dennis Munsie --- drivers/video/intelfb/intelfb.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/video/intelfb/intelfb.h b/drivers/video/intelfb/intelfb.h index abd4c5632e38..5a216b81aa23 100644 --- a/drivers/video/intelfb/intelfb.h +++ b/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" @@ -208,6 +212,15 @@ 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_vsync { wait_queue_head_t wait; unsigned int count; From 399fb4316ab4fe4c46d1e4ed8b12d56c94b4c251 Mon Sep 17 00:00:00 2001 From: Dennis Munsie Date: Tue, 20 Jun 2006 14:55:55 -0400 Subject: [PATCH 09/16] 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 --- drivers/video/intelfb/intelfb.h | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/drivers/video/intelfb/intelfb.h b/drivers/video/intelfb/intelfb.h index 5a216b81aa23..179db05f1954 100644 --- a/drivers/video/intelfb/intelfb.h +++ b/drivers/video/intelfb/intelfb.h @@ -119,6 +119,24 @@ /* Intel agpgart driver */ #define AGP_PHYSICAL_MEMORY 2 +/* 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 */ @@ -221,6 +239,17 @@ struct intelfb_i2c_chan { }; #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; From dd696ec852dc34c40e2a18cc426c8f462c0715a5 Mon Sep 17 00:00:00 2001 From: Dennis Munsie Date: Tue, 20 Jun 2006 14:55:55 -0400 Subject: [PATCH 10/16] intelfb: add preliminary i2c support [05/07] intelfb: add output fields to dinfo. Signed-off-by: Dennis Munsie --- drivers/video/intelfb/intelfb.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/video/intelfb/intelfb.h b/drivers/video/intelfb/intelfb.h index 179db05f1954..9092bda9d4bf 100644 --- a/drivers/video/intelfb/intelfb.h +++ b/drivers/video/intelfb/intelfb.h @@ -119,6 +119,11 @@ /* 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 @@ -344,6 +349,10 @@ 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)) From 41c9480a1d22e8f28b8675a2d7ec7fd4c50bc900 Mon Sep 17 00:00:00 2001 From: Dennis Munsie Date: Tue, 20 Jun 2006 14:55:55 -0400 Subject: [PATCH 11/16] 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 --- drivers/video/intelfb/intelfb.h | 4 + drivers/video/intelfb/intelfb_i2c.c | 184 ++++++++++++++++++++++++++++ drivers/video/intelfb/intelfbdrv.c | 5 + 3 files changed, 193 insertions(+) create mode 100644 drivers/video/intelfb/intelfb_i2c.c diff --git a/drivers/video/intelfb/intelfb.h b/drivers/video/intelfb/intelfb.h index 9092bda9d4bf..6ef38c90c4d6 100644 --- a/drivers/video/intelfb/intelfb.h +++ b/drivers/video/intelfb/intelfb.h @@ -365,4 +365,8 @@ struct intelfb_info { 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); +#endif + #endif /* _INTELFB_H */ diff --git a/drivers/video/intelfb/intelfb_i2c.c b/drivers/video/intelfb/intelfb_i2c.c new file mode 100644 index 000000000000..d73572355c57 --- /dev/null +++ b/drivers/video/intelfb/intelfb_i2c.c @@ -0,0 +1,184 @@ +/************************************************************************** + + 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; +} diff --git a/drivers/video/intelfb/intelfbdrv.c b/drivers/video/intelfb/intelfbdrv.c index 9e93f820a939..f412b5ab8f98 100644 --- a/drivers/video/intelfb/intelfbdrv.c +++ b/drivers/video/intelfb/intelfbdrv.c @@ -851,6 +851,11 @@ intelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent) if (bailearly == 5) bailout(dinfo); +#ifdef CONFIG_FB_INTEL_I2C + /* register I2C bus */ + intelfb_create_i2c_busses(dinfo); +#endif + if (bailearly == 6) bailout(dinfo); From 1f6e8449e11fd79ee30456ce7ec973317b8dd6ae Mon Sep 17 00:00:00 2001 From: Dennis Munsie Date: Tue, 20 Jun 2006 14:55:55 -0400 Subject: [PATCH 12/16] 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 --- drivers/video/Kconfig | 20 ++++++++++++++++++-- drivers/video/intelfb/Makefile | 4 +++- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 5a2840aeb547..743c853ad150 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -809,6 +809,8 @@ config FB_INTEL depends on FB && EXPERIMENTAL && PCI && X86 select AGP select AGP_INTEL + select I2C_ALGOBIT if FB_INTEL_I2C + select I2C if FB_INTEL_I2C select FB_MODE_HELPERS select FB_CFB_FILLRECT select FB_CFB_COPYAREA @@ -818,17 +820,31 @@ config FB_INTEL 830M/845G/852GM/855GM/865G chipsets. Say Y if you have and plan to use such a board. - To compile this driver as a module, choose M here: the + If you say Y here and want DDC/I2C support you must first say Y to + "I2C support" and "I2C bit-banging support" in the character devices + section. + + If you say M here then "I2C support" and "I2C bit-banging support" + can be build either as modules or built-in. + + To compile this driver as a module, choose M here: the module will be called intelfb. config FB_INTEL_DEBUG - bool "Intel driver Debug Messages" + bool "Intel driver Debug Messages" depends on FB_INTEL ---help--- Say Y here if you want the Intel driver to output all sorts of debugging informations to provide to the maintainer when something goes wrong. +config FB_INTEL_I2C + bool "DDC/I2C for Intel framebuffer support" + depends on FB_INTEL + default y + help + Say Y here if you want DDC/I2C support for your on-board Intel graphics. + config FB_MATROX tristate "Matrox acceleration" depends on FB && PCI diff --git a/drivers/video/intelfb/Makefile b/drivers/video/intelfb/Makefile index 722d21d6e5cd..6c782d3ae1be 100644 --- a/drivers/video/intelfb/Makefile +++ b/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 From 7627899b11ece118b46fbf652e944f9a239f6cd1 Mon Sep 17 00:00:00 2001 From: Dennis Munsie Date: Tue, 20 Jun 2006 14:55:55 -0400 Subject: [PATCH 13/16] intelfb: add preliminary i2c support Adds code to unregister the I2C buses in the cleanup function. Signed-off-by: Dennis Munsie --- drivers/video/intelfb/intelfb.h | 1 + drivers/video/intelfb/intelfb_i2c.c | 16 ++++++++++++++++ drivers/video/intelfb/intelfbdrv.c | 5 +++++ 3 files changed, 22 insertions(+) diff --git a/drivers/video/intelfb/intelfb.h b/drivers/video/intelfb/intelfb.h index 6ef38c90c4d6..abdadc2a1b47 100644 --- a/drivers/video/intelfb/intelfb.h +++ b/drivers/video/intelfb/intelfb.h @@ -367,6 +367,7 @@ 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 --git a/drivers/video/intelfb/intelfb_i2c.c b/drivers/video/intelfb/intelfb_i2c.c index d73572355c57..c1113d6e941d 100644 --- a/drivers/video/intelfb/intelfb_i2c.c +++ b/drivers/video/intelfb/intelfb_i2c.c @@ -182,3 +182,19 @@ void intelfb_create_i2c_busses(struct intelfb_info *dinfo) } 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 --git a/drivers/video/intelfb/intelfbdrv.c b/drivers/video/intelfb/intelfbdrv.c index f412b5ab8f98..f6e30b3d1081 100644 --- a/drivers/video/intelfb/intelfbdrv.c +++ b/drivers/video/intelfb/intelfbdrv.c @@ -474,6 +474,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) From d463d34e7b336ae3645ac331adccb578ae5a4285 Mon Sep 17 00:00:00 2001 From: Christian Merkle Date: Tue, 22 Aug 2006 10:07:01 +1000 Subject: [PATCH 14/16] 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 --- Documentation/fb/intelfb.txt | 11 +++++++---- drivers/video/Kconfig | 6 ++++-- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/Documentation/fb/intelfb.txt b/Documentation/fb/intelfb.txt index c12d39a23c3d..aa0d322db171 100644 --- a/Documentation/fb/intelfb.txt +++ b/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 --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 743c853ad150..60c6773eaac4 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -805,7 +805,7 @@ config FB_I810_I2C help config FB_INTEL - tristate "Intel 830M/845G/852GM/855GM/865G support (EXPERIMENTAL)" + tristate "Intel 830M/845G/852GM/855GM/865G/915G/945G support (EXPERIMENTAL)" depends on FB && EXPERIMENTAL && PCI && X86 select AGP select AGP_INTEL @@ -817,7 +817,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 chipsets. + 830M/845G/852GM/855GM/865G/915G/915GM/945G/945GM 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 @@ -830,6 +830,8 @@ config FB_INTEL To compile this driver as a module, choose M here: the module will be called intelfb. + For more information, please read + config FB_INTEL_DEBUG bool "Intel driver Debug Messages" depends on FB_INTEL From d5afabcea215a828eb00df992b429486aae14c2f Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 22 Aug 2006 10:10:56 +1000 Subject: [PATCH 15/16] intelfb: fix mtrr_reg signedness This is my fix for gcc 4.1 sign issue reported by Eric Sesterhenn . Signed-off-by: Dave Airlie --- drivers/video/intelfb/intelfb.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/intelfb/intelfb.h b/drivers/video/intelfb/intelfb.h index abdadc2a1b47..80b94c19a9fa 100644 --- a/drivers/video/intelfb/intelfb.h +++ b/drivers/video/intelfb/intelfb.h @@ -278,7 +278,7 @@ struct intelfb_info { u8 fbmem_gart; /* mtrr support */ - u32 mtrr_reg; + int mtrr_reg; u32 has_mtrr; /* heap data */ From 4dc3595f5c569021b1bd0109502acfca82036902 Mon Sep 17 00:00:00 2001 From: Parag Warudkar Date: Tue, 22 Aug 2006 10:12:58 +1000 Subject: [PATCH 16/16] 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 --- drivers/video/intelfb/intelfbhw.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c index 8038f558611d..bbd82fffc3f6 100644 --- a/drivers/video/intelfb/intelfbhw.c +++ b/drivers/video/intelfb/intelfbhw.c @@ -627,6 +627,7 @@ static int calc_vclock(int index, int m1, int m2, int n, int p1, int p2, int lvd return vco / p; } +#if REGDUMP static void intelfbhw_get_p1p2(struct intelfb_info *dinfo, int dpll, int *o_p1, int *o_p2) { @@ -652,6 +653,7 @@ intelfbhw_get_p1p2(struct intelfb_info *dinfo, int dpll, int *o_p1, int *o_p2) *o_p1 = p1; *o_p2 = p2; } +#endif void