From 9a5f019b1a9ea6a75ba36d7c312ff069006ed479 Mon Sep 17 00:00:00 2001 From: Eric Hustvedt Date: Tue, 20 Jun 2006 14:36:41 -0400 Subject: 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 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/video/intelfb/intelfb.h') diff --git a/drivers/video/intelfb/intelfb.h b/drivers/video/intelfb/intelfb.h index e290d7460e1..cb016fe4d48 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 { -- cgit v1.2.3-70-g09d2 From 7649757bd900bc900adcd95ab08903cdc28342fa Mon Sep 17 00:00:00 2001 From: Eric Hustvedt Date: Tue, 20 Jun 2006 14:36:41 -0400 Subject: 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(+) (limited to 'drivers/video/intelfb/intelfb.h') diff --git a/drivers/video/intelfb/intelfb.h b/drivers/video/intelfb/intelfb.h index cb016fe4d48..dab1f2d764d 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 0a0a8b199ec..068c56d4e65 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 05aded669cd..1a698a7230e 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 8d2e36972fc..aa0c139a230 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 */ -- cgit v1.2.3-70-g09d2 From 37bced38b3d09c3de7c871790eddde81a3ce57cb Mon Sep 17 00:00:00 2001 From: Eric Hustvedt Date: Tue, 20 Jun 2006 14:36:42 -0400 Subject: 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(+) (limited to 'drivers/video/intelfb/intelfb.h') diff --git a/drivers/video/intelfb/intelfb.h b/drivers/video/intelfb/intelfb.h index dab1f2d764d..65ac37071a0 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 068c56d4e65..08f8241bb92 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 1a698a7230e..0f9631c2ad3 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 aa0c139a230..36980c785e1 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 */ -- cgit v1.2.3-70-g09d2 From f80d0d23f2010b7682e06449345e8199a2b2619c Mon Sep 17 00:00:00 2001 From: Eric Hustvedt Date: Tue, 20 Jun 2006 14:36:42 -0400 Subject: 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(-) (limited to 'drivers/video/intelfb/intelfb.h') diff --git a/drivers/video/intelfb/intelfb.h b/drivers/video/intelfb/intelfb.h index 65ac37071a0..abd4c5632e3 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 08f8241bb92..9e93f820a93 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 0f9631c2ad3..8038f558611 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); -- cgit v1.2.3-70-g09d2 From 183b1214402a205bf6eea2030686249c7d365fd1 Mon Sep 17 00:00:00 2001 From: Dennis Munsie Date: Tue, 20 Jun 2006 14:55:55 -0400 Subject: 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(+) (limited to 'drivers/video/intelfb/intelfb.h') diff --git a/drivers/video/intelfb/intelfb.h b/drivers/video/intelfb/intelfb.h index abd4c5632e3..5a216b81aa2 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; -- cgit v1.2.3-70-g09d2 From 399fb4316ab4fe4c46d1e4ed8b12d56c94b4c251 Mon Sep 17 00:00:00 2001 From: Dennis Munsie Date: Tue, 20 Jun 2006 14:55:55 -0400 Subject: 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(+) (limited to 'drivers/video/intelfb/intelfb.h') diff --git a/drivers/video/intelfb/intelfb.h b/drivers/video/intelfb/intelfb.h index 5a216b81aa2..179db05f195 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; -- cgit v1.2.3-70-g09d2 From dd696ec852dc34c40e2a18cc426c8f462c0715a5 Mon Sep 17 00:00:00 2001 From: Dennis Munsie Date: Tue, 20 Jun 2006 14:55:55 -0400 Subject: 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(+) (limited to 'drivers/video/intelfb/intelfb.h') diff --git a/drivers/video/intelfb/intelfb.h b/drivers/video/intelfb/intelfb.h index 179db05f195..9092bda9d4b 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)) -- cgit v1.2.3-70-g09d2 From 41c9480a1d22e8f28b8675a2d7ec7fd4c50bc900 Mon Sep 17 00:00:00 2001 From: Dennis Munsie Date: Tue, 20 Jun 2006 14:55:55 -0400 Subject: 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 (limited to 'drivers/video/intelfb/intelfb.h') diff --git a/drivers/video/intelfb/intelfb.h b/drivers/video/intelfb/intelfb.h index 9092bda9d4b..6ef38c90c4d 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 00000000000..d73572355c5 --- /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 9e93f820a93..f412b5ab8f9 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); -- cgit v1.2.3-70-g09d2 From 7627899b11ece118b46fbf652e944f9a239f6cd1 Mon Sep 17 00:00:00 2001 From: Dennis Munsie Date: Tue, 20 Jun 2006 14:55:55 -0400 Subject: 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(+) (limited to 'drivers/video/intelfb/intelfb.h') diff --git a/drivers/video/intelfb/intelfb.h b/drivers/video/intelfb/intelfb.h index 6ef38c90c4d..abdadc2a1b4 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 d73572355c5..c1113d6e941 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 f412b5ab8f9..f6e30b3d108 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) -- cgit v1.2.3-70-g09d2 From d5afabcea215a828eb00df992b429486aae14c2f Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 22 Aug 2006 10:10:56 +1000 Subject: 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(-) (limited to 'drivers/video/intelfb/intelfb.h') diff --git a/drivers/video/intelfb/intelfb.h b/drivers/video/intelfb/intelfb.h index abdadc2a1b4..80b94c19a9f 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 */ -- cgit v1.2.3-70-g09d2