aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/intelfb
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@g5.osdl.org>2006-09-30 12:36:56 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-09-30 12:36:56 -0400
commitdb1a19b38f3a85f475b4ad716c71be133d8ca48e (patch)
treecdc0599c20b52a472254720890727a3d9fbde957 /drivers/video/intelfb
parent369aa8395a5dcc89230f1de5459124c4b0db9fca (diff)
parent4dc3595f5c569021b1bd0109502acfca82036902 (diff)
Merge branch 'intelfb-patches' of master.kernel.org:/pub/scm/linux/kernel/git/airlied/intelfb-2.6
* 'intelfb-patches' of master.kernel.org:/pub/scm/linux/kernel/git/airlied/intelfb-2.6: intelfbhw.c: intelfbhw_get_p1p2 defined but not used intelfb: fix mtrr_reg signedness intelfb: update doc and Kconfig (supported devices) intelfb: add preliminary i2c support intelfb: add preliminary i2c support intelfb: add preliminary i2c support intelfb: add preliminary i2c support intelfb: add preliminary i2c support intelfb: add preliminary i2c support intelfb: add preliminary i2c support intelfb: add preliminary i2c support intelfb: add vsync interrupt support intelfb: add vsync interrupt support intelfb: add vsync interrupt support intelfb: add vsync interrupt support intelfb: add vsync interrupt support
Diffstat (limited to 'drivers/video/intelfb')
-rw-r--r--drivers/video/intelfb/Makefile4
-rw-r--r--drivers/video/intelfb/intelfb.h79
-rw-r--r--drivers/video/intelfb/intelfb_i2c.c200
-rw-r--r--drivers/video/intelfb/intelfbdrv.c64
-rw-r--r--drivers/video/intelfb/intelfbhw.c136
-rw-r--r--drivers/video/intelfb/intelfbhw.h25
6 files changed, 505 insertions, 3 deletions
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 @@
1obj-$(CONFIG_FB_INTEL) += intelfb.o 1obj-$(CONFIG_FB_INTEL) += intelfb.o
2 2
3intelfb-objs := intelfbdrv.o intelfbhw.o 3intelfb-y := intelfbdrv.o intelfbhw.o
4intelfb-$(CONFIG_FB_INTEL_I2C) += intelfb_i2c.o
5intelfb-objs := $(intelfb-y)
4 6
5ifdef CONFIG_FB_INTEL_DEBUG 7ifdef CONFIG_FB_INTEL_DEBUG
6#EXTRA_CFLAGS += -DDEBUG -DVERBOSE -DREGDUMP 8#EXTRA_CFLAGS += -DDEBUG -DVERBOSE -DREGDUMP
diff --git a/drivers/video/intelfb/intelfb.h b/drivers/video/intelfb/intelfb.h
index e290d7460e1b..80b94c19a9fa 100644
--- a/drivers/video/intelfb/intelfb.h
+++ b/drivers/video/intelfb/intelfb.h
@@ -6,6 +6,10 @@
6#include <linux/agp_backend.h> 6#include <linux/agp_backend.h>
7#include <linux/fb.h> 7#include <linux/fb.h>
8 8
9#ifdef CONFIG_FB_INTEL_I2C
10#include <linux/i2c.h>
11#include <linux/i2c-algo-bit.h>
12#endif
9 13
10/*** Version/name ***/ 14/*** Version/name ***/
11#define INTELFB_VERSION "0.9.4" 15#define INTELFB_VERSION "0.9.4"
@@ -115,6 +119,29 @@
115/* Intel agpgart driver */ 119/* Intel agpgart driver */
116#define AGP_PHYSICAL_MEMORY 2 120#define AGP_PHYSICAL_MEMORY 2
117 121
122/* store information about an Ixxx DVO */
123/* The i830->i865 use multiple DVOs with multiple i2cs */
124/* the i915, i945 have a single sDVO i2c bus - which is different */
125#define MAX_OUTPUTS 6
126
127/* these are outputs from the chip - integrated only
128 external chips are via DVO or SDVO output */
129#define INTELFB_OUTPUT_UNUSED 0
130#define INTELFB_OUTPUT_ANALOG 1
131#define INTELFB_OUTPUT_DVO 2
132#define INTELFB_OUTPUT_SDVO 3
133#define INTELFB_OUTPUT_LVDS 4
134#define INTELFB_OUTPUT_TVOUT 5
135
136#define INTELFB_DVO_CHIP_NONE 0
137#define INTELFB_DVO_CHIP_LVDS 1
138#define INTELFB_DVO_CHIP_TMDS 2
139#define INTELFB_DVO_CHIP_TVOUT 4
140
141#define INTELFB_OUTPUT_PIPE_NC 0
142#define INTELFB_OUTPUT_PIPE_A 1
143#define INTELFB_OUTPUT_PIPE_B 2
144
118/*** Data Types ***/ 145/*** Data Types ***/
119 146
120/* supported chipsets */ 147/* supported chipsets */
@@ -195,6 +222,10 @@ struct intelfb_hwstate {
195 u32 mem_mode; 222 u32 mem_mode;
196 u32 fw_blc_0; 223 u32 fw_blc_0;
197 u32 fw_blc_1; 224 u32 fw_blc_1;
225 u16 hwstam;
226 u16 ier;
227 u16 iir;
228 u16 imr;
198}; 229};
199 230
200struct intelfb_heap_data { 231struct intelfb_heap_data {
@@ -204,6 +235,33 @@ struct intelfb_heap_data {
204 u32 size; // in bytes 235 u32 size; // in bytes
205}; 236};
206 237
238#ifdef CONFIG_FB_INTEL_I2C
239struct intelfb_i2c_chan {
240 struct intelfb_info *dinfo;
241 u32 reg;
242 struct i2c_adapter adapter;
243 struct i2c_algo_bit_data algo;
244};
245#endif
246
247struct intelfb_output_rec {
248 int type;
249 int pipe;
250 int flags;
251
252#ifdef CONFIG_FB_INTEL_I2C
253 struct intelfb_i2c_chan i2c_bus;
254 struct intelfb_i2c_chan ddc_bus;
255#endif
256};
257
258struct intelfb_vsync {
259 wait_queue_head_t wait;
260 unsigned int count;
261 int pan_display;
262 u32 pan_offset;
263};
264
207struct intelfb_info { 265struct intelfb_info {
208 struct fb_info *info; 266 struct fb_info *info;
209 struct fb_ops *fbops; 267 struct fb_ops *fbops;
@@ -220,7 +278,7 @@ struct intelfb_info {
220 u8 fbmem_gart; 278 u8 fbmem_gart;
221 279
222 /* mtrr support */ 280 /* mtrr support */
223 u32 mtrr_reg; 281 int mtrr_reg;
224 u32 has_mtrr; 282 u32 has_mtrr;
225 283
226 /* heap data */ 284 /* heap data */
@@ -267,6 +325,12 @@ struct intelfb_info {
267 int fixed_mode; 325 int fixed_mode;
268 int ring_active; 326 int ring_active;
269 int flag; 327 int flag;
328 unsigned long irq_flags;
329 int open;
330
331 /* vsync */
332 struct intelfb_vsync vsync;
333 spinlock_t int_lock;
270 334
271 /* hw cursor */ 335 /* hw cursor */
272 int cursor_on; 336 int cursor_on;
@@ -285,12 +349,25 @@ struct intelfb_info {
285 349
286 /* index into plls */ 350 /* index into plls */
287 int pll_index; 351 int pll_index;
352
353 /* outputs */
354 int num_outputs;
355 struct intelfb_output_rec output[MAX_OUTPUTS];
288}; 356};
289 357
290#define IS_I9XX(dinfo) (((dinfo)->chipset == INTEL_915G)||(dinfo->chipset == INTEL_915GM)||((dinfo)->chipset == INTEL_945G)||(dinfo->chipset==INTEL_945GM)) 358#define IS_I9XX(dinfo) (((dinfo)->chipset == INTEL_915G)||(dinfo->chipset == INTEL_915GM)||((dinfo)->chipset == INTEL_945G)||(dinfo->chipset==INTEL_945GM))
291 359
360#ifndef FBIO_WAITFORVSYNC
361#define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32)
362#endif
363
292/*** function prototypes ***/ 364/*** function prototypes ***/
293 365
294extern int intelfb_var_to_depth(const struct fb_var_screeninfo *var); 366extern int intelfb_var_to_depth(const struct fb_var_screeninfo *var);
295 367
368#ifdef CONFIG_FB_INTEL_I2C
369extern void intelfb_create_i2c_busses(struct intelfb_info *dinfo);
370extern void intelfb_delete_i2c_busses(struct intelfb_info *dinfo);
371#endif
372
296#endif /* _INTELFB_H */ 373#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..c1113d6e941d
--- /dev/null
+++ b/drivers/video/intelfb/intelfb_i2c.c
@@ -0,0 +1,200 @@
1/**************************************************************************
2
3 Copyright 2006 Dave Airlie <airlied@linux.ie>
4
5All Rights Reserved.
6
7Permission is hereby granted, free of charge, to any person obtaining a
8copy of this software and associated documentation files (the "Software"),
9to deal in the Software without restriction, including without limitation
10on the rights to use, copy, modify, merge, publish, distribute, sub
11license, and/or sell copies of the Software, and to permit persons to whom
12the Software is furnished to do so, subject to the following conditions:
13
14The above copyright notice and this permission notice (including the next
15paragraph) shall be included in all copies or substantial portions of the
16Software.
17
18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
21THE COPYRIGHT HOLDERS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
22DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
24USE OR OTHER DEALINGS IN THE SOFTWARE.
25
26**************************************************************************/
27
28#include <linux/config.h>
29#include <linux/module.h>
30#include <linux/kernel.h>
31#include <linux/sched.h>
32#include <linux/delay.h>
33#include <linux/pci.h>
34#include <linux/fb.h>
35
36#include <linux/i2c.h>
37#include <linux/i2c-id.h>
38#include <linux/i2c-algo-bit.h>
39
40#include <asm/io.h>
41
42#include "intelfb.h"
43#include "intelfbhw.h"
44
45/* bit locations in the registers */
46#define SCL_DIR_MASK 0x0001
47#define SCL_DIR 0x0002
48#define SCL_VAL_MASK 0x0004
49#define SCL_VAL_OUT 0x0008
50#define SCL_VAL_IN 0x0010
51#define SDA_DIR_MASK 0x0100
52#define SDA_DIR 0x0200
53#define SDA_VAL_MASK 0x0400
54#define SDA_VAL_OUT 0x0800
55#define SDA_VAL_IN 0x1000
56
57static void intelfb_gpio_setscl(void *data, int state)
58{
59 struct intelfb_i2c_chan *chan = data;
60 struct intelfb_info *dinfo = chan->dinfo;
61 u32 val;
62
63 OUTREG(chan->reg, (state ? SCL_VAL_OUT : 0) | SCL_DIR | SCL_DIR_MASK | SCL_VAL_MASK);
64 val = INREG(chan->reg);
65}
66
67static void intelfb_gpio_setsda(void *data, int state)
68{
69 struct intelfb_i2c_chan *chan = data;
70 struct intelfb_info *dinfo = chan->dinfo;
71 u32 val;
72
73 OUTREG(chan->reg, (state ? SDA_VAL_OUT : 0) | SDA_DIR | SDA_DIR_MASK | SDA_VAL_MASK);
74 val = INREG(chan->reg);
75}
76
77static int intelfb_gpio_getscl(void *data)
78{
79 struct intelfb_i2c_chan *chan = data;
80 struct intelfb_info *dinfo = chan->dinfo;
81 u32 val;
82
83 OUTREG(chan->reg, SCL_DIR_MASK);
84 OUTREG(chan->reg, 0);
85 val = INREG(chan->reg);
86 return ((val & SCL_VAL_IN) != 0);
87}
88
89static int intelfb_gpio_getsda(void *data)
90{
91 struct intelfb_i2c_chan *chan = data;
92 struct intelfb_info *dinfo = chan->dinfo;
93 u32 val;
94
95 OUTREG(chan->reg, SDA_DIR_MASK);
96 OUTREG(chan->reg, 0);
97 val = INREG(chan->reg);
98 return ((val & SDA_VAL_IN) != 0);
99}
100
101static int intelfb_setup_i2c_bus(struct intelfb_info *dinfo,
102 struct intelfb_i2c_chan *chan,
103 const u32 reg, const char *name)
104{
105 int rc;
106
107 chan->dinfo = dinfo;
108 chan->reg = reg;
109 snprintf(chan->adapter.name, I2C_NAME_SIZE, "intelfb %s", name);
110 chan->adapter.owner = THIS_MODULE;
111 chan->adapter.id = I2C_HW_B_INTELFB;
112 chan->adapter.algo_data = &chan->algo;
113 chan->adapter.dev.parent = &chan->dinfo->pdev->dev;
114 chan->algo.setsda = intelfb_gpio_setsda;
115 chan->algo.setscl = intelfb_gpio_setscl;
116 chan->algo.getsda = intelfb_gpio_getsda;
117 chan->algo.getscl = intelfb_gpio_getscl;
118 chan->algo.udelay = 40;
119 chan->algo.timeout = 20;
120 chan->algo.data = chan;
121
122 i2c_set_adapdata(&chan->adapter, chan);
123
124 /* Raise SCL and SDA */
125 intelfb_gpio_setsda(chan, 1);
126 intelfb_gpio_setscl(chan, 1);
127 udelay(20);
128
129 rc = i2c_bit_add_bus(&chan->adapter);
130 if (rc == 0)
131 DBG_MSG("I2C bus %s registered.\n", name);
132 else
133 WRN_MSG("Failed to register I2C bus %s.\n", name);
134 return rc;
135}
136
137void intelfb_create_i2c_busses(struct intelfb_info *dinfo)
138{
139 int i = 0;
140
141 /* everyone has at least a single analog output */
142 dinfo->num_outputs = 1;
143 dinfo->output[i].type = INTELFB_OUTPUT_ANALOG;
144
145 /* setup the DDC bus for analog output */
146 intelfb_setup_i2c_bus(dinfo, &dinfo->output[i].ddc_bus, GPIOA, "CRTDDC_A");
147 i++;
148
149 /* need to add the output busses for each device
150 - this function is very incomplete
151 - i915GM has LVDS and TVOUT for example
152 */
153 switch(dinfo->chipset) {
154 case INTEL_830M:
155 case INTEL_845G:
156 case INTEL_855GM:
157 case INTEL_865G:
158 dinfo->output[i].type = INTELFB_OUTPUT_DVO;
159 intelfb_setup_i2c_bus(dinfo, &dinfo->output[i].ddc_bus, GPIOD, "DVODDC_D");
160 intelfb_setup_i2c_bus(dinfo, &dinfo->output[i].i2c_bus, GPIOE, "DVOI2C_E");
161 i++;
162 break;
163 case INTEL_915G:
164 case INTEL_915GM:
165 /* has some LVDS + tv-out */
166 case INTEL_945G:
167 case INTEL_945GM:
168 /* SDVO ports have a single control bus - 2 devices */
169 dinfo->output[i].type = INTELFB_OUTPUT_SDVO;
170 intelfb_setup_i2c_bus(dinfo, &dinfo->output[i].i2c_bus, GPIOE, "SDVOCTRL_E");
171 /* TODO: initialize the SDVO */
172// I830SDVOInit(pScrn, i, DVOB);
173 i++;
174
175 /* set up SDVOC */
176 dinfo->output[i].type = INTELFB_OUTPUT_SDVO;
177 dinfo->output[i].i2c_bus = dinfo->output[i - 1].i2c_bus;
178 /* TODO: initialize the SDVO */
179// I830SDVOInit(pScrn, i, DVOC);
180 i++;
181 break;
182 }
183 dinfo->num_outputs = i;
184}
185
186void intelfb_delete_i2c_busses(struct intelfb_info *dinfo)
187{
188 int i;
189
190 for (i = 0; i < MAX_OUTPUTS; i++) {
191 if (dinfo->output[i].i2c_bus.dinfo) {
192 i2c_bit_del_bus(&dinfo->output[i].i2c_bus.adapter);
193 dinfo->output[i].i2c_bus.dinfo = NULL;
194 }
195 if (dinfo->output[i].ddc_bus.dinfo) {
196 i2c_bit_del_bus(&dinfo->output[i].ddc_bus.adapter);
197 dinfo->output[i].ddc_bus.dinfo = NULL;
198 }
199 }
200}
diff --git a/drivers/video/intelfb/intelfbdrv.c b/drivers/video/intelfb/intelfbdrv.c
index 06af89d44a0d..6f9de04193d2 100644
--- a/drivers/video/intelfb/intelfbdrv.c
+++ b/drivers/video/intelfb/intelfbdrv.c
@@ -136,6 +136,8 @@
136static void __devinit get_initial_mode(struct intelfb_info *dinfo); 136static void __devinit get_initial_mode(struct intelfb_info *dinfo);
137static void update_dinfo(struct intelfb_info *dinfo, 137static void update_dinfo(struct intelfb_info *dinfo,
138 struct fb_var_screeninfo *var); 138 struct fb_var_screeninfo *var);
139static int intelfb_open(struct fb_info *info, int user);
140static int intelfb_release(struct fb_info *info, int user);
139static int intelfb_check_var(struct fb_var_screeninfo *var, 141static int intelfb_check_var(struct fb_var_screeninfo *var,
140 struct fb_info *info); 142 struct fb_info *info);
141static int intelfb_set_par(struct fb_info *info); 143static int intelfb_set_par(struct fb_info *info);
@@ -194,6 +196,8 @@ static int num_registered = 0;
194/* fb ops */ 196/* fb ops */
195static struct fb_ops intel_fb_ops = { 197static struct fb_ops intel_fb_ops = {
196 .owner = THIS_MODULE, 198 .owner = THIS_MODULE,
199 .fb_open = intelfb_open,
200 .fb_release = intelfb_release,
197 .fb_check_var = intelfb_check_var, 201 .fb_check_var = intelfb_check_var,
198 .fb_set_par = intelfb_set_par, 202 .fb_set_par = intelfb_set_par,
199 .fb_setcolreg = intelfb_setcolreg, 203 .fb_setcolreg = intelfb_setcolreg,
@@ -446,6 +450,8 @@ cleanup(struct intelfb_info *dinfo)
446 if (!dinfo) 450 if (!dinfo)
447 return; 451 return;
448 452
453 intelfbhw_disable_irq(dinfo);
454
449 fb_dealloc_cmap(&dinfo->info->cmap); 455 fb_dealloc_cmap(&dinfo->info->cmap);
450 kfree(dinfo->info->pixmap.addr); 456 kfree(dinfo->info->pixmap.addr);
451 457
@@ -467,6 +473,11 @@ cleanup(struct intelfb_info *dinfo)
467 agp_free_memory(dinfo->gtt_ring_mem); 473 agp_free_memory(dinfo->gtt_ring_mem);
468 } 474 }
469 475
476#ifdef CONFIG_FB_INTEL_I2C
477 /* un-register I2C bus */
478 intelfb_delete_i2c_busses(dinfo);
479#endif
480
470 if (dinfo->mmio_base) 481 if (dinfo->mmio_base)
471 iounmap((void __iomem *)dinfo->mmio_base); 482 iounmap((void __iomem *)dinfo->mmio_base);
472 if (dinfo->aperture.virtual) 483 if (dinfo->aperture.virtual)
@@ -844,6 +855,11 @@ intelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent)
844 if (bailearly == 5) 855 if (bailearly == 5)
845 bailout(dinfo); 856 bailout(dinfo);
846 857
858#ifdef CONFIG_FB_INTEL_I2C
859 /* register I2C bus */
860 intelfb_create_i2c_busses(dinfo);
861#endif
862
847 if (bailearly == 6) 863 if (bailearly == 6)
848 bailout(dinfo); 864 bailout(dinfo);
849 865
@@ -888,6 +904,13 @@ intelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent)
888 } 904 }
889 905
890 dinfo->registered = 1; 906 dinfo->registered = 1;
907 dinfo->open = 0;
908
909 init_waitqueue_head(&dinfo->vsync.wait);
910 spin_lock_init(&dinfo->int_lock);
911 dinfo->irq_flags = 0;
912 dinfo->vsync.pan_display = 0;
913 dinfo->vsync.pan_offset = 0;
891 914
892 return 0; 915 return 0;
893 916
@@ -1188,6 +1211,34 @@ update_dinfo(struct intelfb_info *dinfo, struct fb_var_screeninfo *var)
1188 ***************************************************************/ 1211 ***************************************************************/
1189 1212
1190static int 1213static int
1214intelfb_open(struct fb_info *info, int user)
1215{
1216 struct intelfb_info *dinfo = GET_DINFO(info);
1217
1218 if (user) {
1219 dinfo->open++;
1220 }
1221
1222 return 0;
1223}
1224
1225static int
1226intelfb_release(struct fb_info *info, int user)
1227{
1228 struct intelfb_info *dinfo = GET_DINFO(info);
1229
1230 if (user) {
1231 dinfo->open--;
1232 msleep(1);
1233 if (!dinfo->open) {
1234 intelfbhw_disable_irq(dinfo);
1235 }
1236 }
1237
1238 return 0;
1239}
1240
1241static int
1191intelfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) 1242intelfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
1192{ 1243{
1193 int change_var = 0; 1244 int change_var = 0;
@@ -1433,6 +1484,19 @@ static int
1433intelfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) 1484intelfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
1434{ 1485{
1435 int retval = 0; 1486 int retval = 0;
1487 struct intelfb_info *dinfo = GET_DINFO(info);
1488 u32 pipe = 0;
1489
1490 switch (cmd) {
1491 case FBIO_WAITFORVSYNC:
1492 if (get_user(pipe, (__u32 __user *)arg))
1493 return -EFAULT;
1494
1495 retval = intelfbhw_wait_for_vsync(dinfo, pipe);
1496 break;
1497 default:
1498 break;
1499 }
1436 1500
1437 return retval; 1501 return retval;
1438} 1502}
diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c
index 2a9322f9cfdc..f887f1efd3fe 100644
--- a/drivers/video/intelfb/intelfbhw.c
+++ b/drivers/video/intelfb/intelfbhw.c
@@ -32,6 +32,7 @@
32#include <linux/pci.h> 32#include <linux/pci.h>
33#include <linux/vmalloc.h> 33#include <linux/vmalloc.h>
34#include <linux/pagemap.h> 34#include <linux/pagemap.h>
35#include <linux/interrupt.h>
35 36
36#include <asm/io.h> 37#include <asm/io.h>
37 38
@@ -368,7 +369,13 @@ intelfbhw_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
368 369
369 offset += dinfo->fb.offset << 12; 370 offset += dinfo->fb.offset << 12;
370 371
371 OUTREG(DSPABASE, offset); 372 dinfo->vsync.pan_offset = offset;
373 if ((var->activate & FB_ACTIVATE_VBL) && !intelfbhw_enable_irq(dinfo, 0)) {
374 dinfo->vsync.pan_display = 1;
375 } else {
376 dinfo->vsync.pan_display = 0;
377 OUTREG(DSPABASE, offset);
378 }
372 379
373 return 0; 380 return 0;
374} 381}
@@ -585,6 +592,11 @@ intelfbhw_read_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw,
585 hw->fw_blc_0 = INREG(FW_BLC_0); 592 hw->fw_blc_0 = INREG(FW_BLC_0);
586 hw->fw_blc_1 = INREG(FW_BLC_1); 593 hw->fw_blc_1 = INREG(FW_BLC_1);
587 594
595 hw->hwstam = INREG16(HWSTAM);
596 hw->ier = INREG16(IER);
597 hw->iir = INREG16(IIR);
598 hw->imr = INREG16(IMR);
599
588 return 0; 600 return 0;
589} 601}
590 602
@@ -613,6 +625,7 @@ static int calc_vclock(int index, int m1, int m2, int n, int p1, int p2, int lvd
613 return vco / p; 625 return vco / p;
614} 626}
615 627
628#if REGDUMP
616static void 629static void
617intelfbhw_get_p1p2(struct intelfb_info *dinfo, int dpll, int *o_p1, int *o_p2) 630intelfbhw_get_p1p2(struct intelfb_info *dinfo, int dpll, int *o_p1, int *o_p2)
618{ 631{
@@ -638,6 +651,7 @@ intelfbhw_get_p1p2(struct intelfb_info *dinfo, int dpll, int *o_p1, int *o_p2)
638 *o_p1 = p1; 651 *o_p1 = p1;
639 *o_p2 = p2; 652 *o_p2 = p2;
640} 653}
654#endif
641 655
642 656
643void 657void
@@ -794,6 +808,10 @@ intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw)
794 printk(" FW_BLC_0 0x%08x\n", hw->fw_blc_0); 808 printk(" FW_BLC_0 0x%08x\n", hw->fw_blc_0);
795 printk(" FW_BLC_1 0x%08x\n", hw->fw_blc_1); 809 printk(" FW_BLC_1 0x%08x\n", hw->fw_blc_1);
796 810
811 printk(" HWSTAM 0x%04x\n", hw->hwstam);
812 printk(" IER 0x%04x\n", hw->ier);
813 printk(" IIR 0x%04x\n", hw->iir);
814 printk(" IMR 0x%04x\n", hw->imr);
797 printk("hw state dump end\n"); 815 printk("hw state dump end\n");
798#endif 816#endif
799} 817}
@@ -1932,3 +1950,119 @@ intelfbhw_cursor_reset(struct intelfb_info *dinfo) {
1932 addr += 16; 1950 addr += 16;
1933 } 1951 }
1934} 1952}
1953
1954static irqreturn_t
1955intelfbhw_irq(int irq, void *dev_id, struct pt_regs *fp) {
1956 int handled = 0;
1957 u16 tmp;
1958 struct intelfb_info *dinfo = (struct intelfb_info *)dev_id;
1959
1960 spin_lock(&dinfo->int_lock);
1961
1962 tmp = INREG16(IIR);
1963 tmp &= VSYNC_PIPE_A_INTERRUPT;
1964
1965 if (tmp == 0) {
1966 spin_unlock(&dinfo->int_lock);
1967 return IRQ_RETVAL(handled);
1968 }
1969
1970 OUTREG16(IIR, tmp);
1971
1972 if (tmp & VSYNC_PIPE_A_INTERRUPT) {
1973 dinfo->vsync.count++;
1974 if (dinfo->vsync.pan_display) {
1975 dinfo->vsync.pan_display = 0;
1976 OUTREG(DSPABASE, dinfo->vsync.pan_offset);
1977 }
1978 wake_up_interruptible(&dinfo->vsync.wait);
1979 handled = 1;
1980 }
1981
1982 spin_unlock(&dinfo->int_lock);
1983
1984 return IRQ_RETVAL(handled);
1985}
1986
1987int
1988intelfbhw_enable_irq(struct intelfb_info *dinfo, int reenable) {
1989
1990 if (!test_and_set_bit(0, &dinfo->irq_flags)) {
1991 if (request_irq(dinfo->pdev->irq, intelfbhw_irq, SA_SHIRQ, "intelfb", dinfo)) {
1992 clear_bit(0, &dinfo->irq_flags);
1993 return -EINVAL;
1994 }
1995
1996 spin_lock_irq(&dinfo->int_lock);
1997 OUTREG16(HWSTAM, 0xfffe);
1998 OUTREG16(IMR, 0x0);
1999 OUTREG16(IER, VSYNC_PIPE_A_INTERRUPT);
2000 spin_unlock_irq(&dinfo->int_lock);
2001 } else if (reenable) {
2002 u16 ier;
2003
2004 spin_lock_irq(&dinfo->int_lock);
2005 ier = INREG16(IER);
2006 if ((ier & VSYNC_PIPE_A_INTERRUPT)) {
2007 DBG_MSG("someone disabled the IRQ [%08X]\n", ier);
2008 OUTREG(IER, VSYNC_PIPE_A_INTERRUPT);
2009 }
2010 spin_unlock_irq(&dinfo->int_lock);
2011 }
2012 return 0;
2013}
2014
2015void
2016intelfbhw_disable_irq(struct intelfb_info *dinfo) {
2017 u16 tmp;
2018
2019 if (test_and_clear_bit(0, &dinfo->irq_flags)) {
2020 if (dinfo->vsync.pan_display) {
2021 dinfo->vsync.pan_display = 0;
2022 OUTREG(DSPABASE, dinfo->vsync.pan_offset);
2023 }
2024 spin_lock_irq(&dinfo->int_lock);
2025 OUTREG16(HWSTAM, 0xffff);
2026 OUTREG16(IMR, 0xffff);
2027 OUTREG16(IER, 0x0);
2028
2029 tmp = INREG16(IIR);
2030 OUTREG16(IIR, tmp);
2031 spin_unlock_irq(&dinfo->int_lock);
2032
2033 free_irq(dinfo->pdev->irq, dinfo);
2034 }
2035}
2036
2037int
2038intelfbhw_wait_for_vsync(struct intelfb_info *dinfo, u32 pipe) {
2039 struct intelfb_vsync *vsync;
2040 unsigned int count;
2041 int ret;
2042
2043 switch (pipe) {
2044 case 0:
2045 vsync = &dinfo->vsync;
2046 break;
2047 default:
2048 return -ENODEV;
2049 }
2050
2051 ret = intelfbhw_enable_irq(dinfo, 0);
2052 if (ret) {
2053 return ret;
2054 }
2055
2056 count = vsync->count;
2057 ret = wait_event_interruptible_timeout(vsync->wait, count != vsync->count, HZ/10);
2058 if (ret < 0) {
2059 return ret;
2060 }
2061 if (ret == 0) {
2062 intelfbhw_enable_irq(dinfo, 1);
2063 DBG_MSG("wait_for_vsync timed out!\n");
2064 return -ETIMEDOUT;
2065 }
2066
2067 return 0;
2068}
diff --git a/drivers/video/intelfb/intelfbhw.h b/drivers/video/intelfb/intelfbhw.h
index 10acda098b71..8c54ba8fbdda 100644
--- a/drivers/video/intelfb/intelfbhw.h
+++ b/drivers/video/intelfb/intelfbhw.h
@@ -88,6 +88,19 @@
88#define INSTDONE 0x2090 88#define INSTDONE 0x2090
89#define PRI_RING_EMPTY 1 89#define PRI_RING_EMPTY 1
90 90
91#define HWSTAM 0x2098
92#define IER 0x20A0
93#define IIR 0x20A4
94#define IMR 0x20A8
95#define VSYNC_PIPE_A_INTERRUPT (1 << 7)
96#define PIPE_A_EVENT_INTERRUPT (1 << 4)
97#define VSYNC_PIPE_B_INTERRUPT (1 << 5)
98#define PIPE_B_EVENT_INTERRUPT (1 << 4)
99#define HOST_PORT_EVENT_INTERRUPT (1 << 3)
100#define CAPTURE_EVENT_INTERRUPT (1 << 2)
101#define USER_DEFINED_INTERRUPT (1 << 1)
102#define BREAKPOINT_INTERRUPT 1
103
91#define INSTPM 0x20c0 104#define INSTPM 0x20c0
92#define SYNC_FLUSH_ENABLE (1 << 5) 105#define SYNC_FLUSH_ENABLE (1 << 5)
93 106
@@ -113,6 +126,12 @@
113#define FW_DISPC_BL_SHIFT 8 126#define FW_DISPC_BL_SHIFT 8
114#define FW_DISPC_BL_MASK 0x7 127#define FW_DISPC_BL_MASK 0x7
115 128
129#define GPIOA 0x5010
130#define GPIOB 0x5014
131#define GPIOC 0x5018 // this may be external DDC on i830
132#define GPIOD 0x501C // this is DVO DDC
133#define GPIOE 0x5020 // this is DVO i2C
134#define GPIOF 0x5024
116 135
117/* PLL registers */ 136/* PLL registers */
118#define VGA0_DIVISOR 0x06000 137#define VGA0_DIVISOR 0x06000
@@ -468,9 +487,12 @@
468 487
469/* I/O macros */ 488/* I/O macros */
470#define INREG8(addr) readb((u8 __iomem *)(dinfo->mmio_base + (addr))) 489#define INREG8(addr) readb((u8 __iomem *)(dinfo->mmio_base + (addr)))
490#define INREG16(addr) readw((u16 __iomem *)(dinfo->mmio_base + (addr)))
471#define INREG(addr) readl((u32 __iomem *)(dinfo->mmio_base + (addr))) 491#define INREG(addr) readl((u32 __iomem *)(dinfo->mmio_base + (addr)))
472#define OUTREG8(addr, val) writeb((val),(u8 __iomem *)(dinfo->mmio_base + \ 492#define OUTREG8(addr, val) writeb((val),(u8 __iomem *)(dinfo->mmio_base + \
473 (addr))) 493 (addr)))
494#define OUTREG16(addr, val) writew((val),(u16 __iomem *)(dinfo->mmio_base + \
495 (addr)))
474#define OUTREG(addr, val) writel((val),(u32 __iomem *)(dinfo->mmio_base + \ 496#define OUTREG(addr, val) writel((val),(u32 __iomem *)(dinfo->mmio_base + \
475 (addr))) 497 (addr)))
476 498
@@ -545,5 +567,8 @@ extern void intelfbhw_cursor_setcolor(struct intelfb_info *dinfo, u32 bg,
545extern void intelfbhw_cursor_load(struct intelfb_info *dinfo, int width, 567extern void intelfbhw_cursor_load(struct intelfb_info *dinfo, int width,
546 int height, u8 *data); 568 int height, u8 *data);
547extern void intelfbhw_cursor_reset(struct intelfb_info *dinfo); 569extern void intelfbhw_cursor_reset(struct intelfb_info *dinfo);
570extern int intelfbhw_enable_irq(struct intelfb_info *dinfo, int reenable);
571extern void intelfbhw_disable_irq(struct intelfb_info *dinfo);
572extern int intelfbhw_wait_for_vsync(struct intelfb_info *dinfo, u32 pipe);
548 573
549#endif /* _INTELFBHW_H */ 574#endif /* _INTELFBHW_H */