Commit db1a19b3 authored by Linus Torvalds's avatar Linus Torvalds

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
parents 369aa839 4dc3595f
Intel 830M/845G/852GM/855GM/865G/915G Framebuffer driver Intel 830M/845G/852GM/855GM/865G/915G/945G Framebuffer driver
================================================================ ================================================================
A. Introduction 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: graphics devices. These would include:
Intel 830M Intel 830M
Intel 810E845G Intel 845G
Intel 852GM Intel 852GM
Intel 855GM Intel 855GM
Intel 865G Intel 865G
Intel 915G Intel 915G
Intel 915GM
Intel 945G
Intel 945GM
B. List of available options B. List of available options
...@@ -78,7 +81,7 @@ C. Kernel booting ...@@ -78,7 +81,7 @@ C. Kernel booting
Separate each option/option-pair by commas (,) and the option from its value Separate each option/option-pair by commas (,) and the option from its value
with an equals sign (=) as in the following: with an equals sign (=) as in the following:
video=i810fb:option1,option2=value2 video=intelfb:option1,option2=value2
Sample Usage Sample Usage
------------ ------------
......
...@@ -825,22 +825,33 @@ config FB_I810_I2C ...@@ -825,22 +825,33 @@ config FB_I810_I2C
help help
config FB_INTEL 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 depends on FB && EXPERIMENTAL && PCI && X86
select AGP select AGP
select AGP_INTEL select AGP_INTEL
select I2C_ALGOBIT if FB_INTEL_I2C
select I2C if FB_INTEL_I2C
select FB_MODE_HELPERS select FB_MODE_HELPERS
select FB_CFB_FILLRECT select FB_CFB_FILLRECT
select FB_CFB_COPYAREA select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT select FB_CFB_IMAGEBLIT
help help
This driver supports the on-board graphics built in to the Intel 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. 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
"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 To compile this driver as a module, choose M here: the
module will be called intelfb. module will be called intelfb.
For more information, please read <file:Documentation/fb/intelfb.txt>
config FB_INTEL_DEBUG config FB_INTEL_DEBUG
bool "Intel driver Debug Messages" bool "Intel driver Debug Messages"
depends on FB_INTEL depends on FB_INTEL
...@@ -849,6 +860,13 @@ config FB_INTEL_DEBUG ...@@ -849,6 +860,13 @@ config FB_INTEL_DEBUG
of debugging informations to provide to the maintainer when of debugging informations to provide to the maintainer when
something goes wrong. 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 config FB_MATROX
tristate "Matrox acceleration" tristate "Matrox acceleration"
depends on FB && PCI depends on FB && PCI
......
obj-$(CONFIG_FB_INTEL) += intelfb.o 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 ifdef CONFIG_FB_INTEL_DEBUG
#EXTRA_CFLAGS += -DDEBUG -DVERBOSE -DREGDUMP #EXTRA_CFLAGS += -DDEBUG -DVERBOSE -DREGDUMP
......
...@@ -6,6 +6,10 @@ ...@@ -6,6 +6,10 @@
#include <linux/agp_backend.h> #include <linux/agp_backend.h>
#include <linux/fb.h> #include <linux/fb.h>
#ifdef CONFIG_FB_INTEL_I2C
#include <linux/i2c.h>
#include <linux/i2c-algo-bit.h>
#endif
/*** Version/name ***/ /*** Version/name ***/
#define INTELFB_VERSION "0.9.4" #define INTELFB_VERSION "0.9.4"
...@@ -115,6 +119,29 @@ ...@@ -115,6 +119,29 @@
/* Intel agpgart driver */ /* Intel agpgart driver */
#define AGP_PHYSICAL_MEMORY 2 #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 ***/ /*** Data Types ***/
/* supported chipsets */ /* supported chipsets */
...@@ -195,6 +222,10 @@ struct intelfb_hwstate { ...@@ -195,6 +222,10 @@ struct intelfb_hwstate {
u32 mem_mode; u32 mem_mode;
u32 fw_blc_0; u32 fw_blc_0;
u32 fw_blc_1; u32 fw_blc_1;
u16 hwstam;
u16 ier;
u16 iir;
u16 imr;
}; };
struct intelfb_heap_data { struct intelfb_heap_data {
...@@ -204,6 +235,33 @@ struct intelfb_heap_data { ...@@ -204,6 +235,33 @@ struct intelfb_heap_data {
u32 size; // in bytes 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 intelfb_info {
struct fb_info *info; struct fb_info *info;
struct fb_ops *fbops; struct fb_ops *fbops;
...@@ -220,7 +278,7 @@ struct intelfb_info { ...@@ -220,7 +278,7 @@ struct intelfb_info {
u8 fbmem_gart; u8 fbmem_gart;
/* mtrr support */ /* mtrr support */
u32 mtrr_reg; int mtrr_reg;
u32 has_mtrr; u32 has_mtrr;
/* heap data */ /* heap data */
...@@ -267,6 +325,12 @@ struct intelfb_info { ...@@ -267,6 +325,12 @@ struct intelfb_info {
int fixed_mode; int fixed_mode;
int ring_active; int ring_active;
int flag; int flag;
unsigned long irq_flags;
int open;
/* vsync */
struct intelfb_vsync vsync;
spinlock_t int_lock;
/* hw cursor */ /* hw cursor */
int cursor_on; int cursor_on;
...@@ -285,12 +349,25 @@ struct intelfb_info { ...@@ -285,12 +349,25 @@ struct intelfb_info {
/* index into plls */ /* index into plls */
int pll_index; 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)) #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 ***/ /*** function prototypes ***/
extern int intelfb_var_to_depth(const struct fb_var_screeninfo *var); 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 */ #endif /* _INTELFB_H */
/**************************************************************************
Copyright 2006 Dave Airlie <airlied@linux.ie>
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 <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/pci.h>
#include <linux/fb.h>
#include <linux/i2c.h>
#include <linux/i2c-id.h>
#include <linux/i2c-algo-bit.h>
#include <asm/io.h>
#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;
}
}
}
...@@ -136,6 +136,8 @@ ...@@ -136,6 +136,8 @@
static void __devinit get_initial_mode(struct intelfb_info *dinfo); static void __devinit get_initial_mode(struct intelfb_info *dinfo);
static void update_dinfo(struct intelfb_info *dinfo, static void update_dinfo(struct intelfb_info *dinfo,
struct fb_var_screeninfo *var); 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, static int intelfb_check_var(struct fb_var_screeninfo *var,
struct fb_info *info); struct fb_info *info);
static int intelfb_set_par(struct fb_info *info); static int intelfb_set_par(struct fb_info *info);
...@@ -194,6 +196,8 @@ static int num_registered = 0; ...@@ -194,6 +196,8 @@ static int num_registered = 0;
/* fb ops */ /* fb ops */
static struct fb_ops intel_fb_ops = { static struct fb_ops intel_fb_ops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.fb_open = intelfb_open,
.fb_release = intelfb_release,
.fb_check_var = intelfb_check_var, .fb_check_var = intelfb_check_var,
.fb_set_par = intelfb_set_par, .fb_set_par = intelfb_set_par,
.fb_setcolreg = intelfb_setcolreg, .fb_setcolreg = intelfb_setcolreg,
...@@ -446,6 +450,8 @@ cleanup(struct intelfb_info *dinfo) ...@@ -446,6 +450,8 @@ cleanup(struct intelfb_info *dinfo)
if (!dinfo) if (!dinfo)
return; return;
intelfbhw_disable_irq(dinfo);
fb_dealloc_cmap(&dinfo->info->cmap); fb_dealloc_cmap(&dinfo->info->cmap);
kfree(dinfo->info->pixmap.addr); kfree(dinfo->info->pixmap.addr);
...@@ -467,6 +473,11 @@ cleanup(struct intelfb_info *dinfo) ...@@ -467,6 +473,11 @@ cleanup(struct intelfb_info *dinfo)
agp_free_memory(dinfo->gtt_ring_mem); 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) if (dinfo->mmio_base)
iounmap((void __iomem *)dinfo->mmio_base); iounmap((void __iomem *)dinfo->mmio_base);
if (dinfo->aperture.virtual) if (dinfo->aperture.virtual)
...@@ -844,6 +855,11 @@ intelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -844,6 +855,11 @@ intelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent)
if (bailearly == 5) if (bailearly == 5)
bailout(dinfo); bailout(dinfo);
#ifdef CONFIG_FB_INTEL_I2C
/* register I2C bus */
intelfb_create_i2c_busses(dinfo);
#endif
if (bailearly == 6) if (bailearly == 6)
bailout(dinfo); bailout(dinfo);
...@@ -888,6 +904,13 @@ intelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -888,6 +904,13 @@ intelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent)
} }
dinfo->registered = 1; 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; return 0;
...@@ -1187,6 +1210,34 @@ update_dinfo(struct intelfb_info *dinfo, struct fb_var_screeninfo *var) ...@@ -1187,6 +1210,34 @@ update_dinfo(struct intelfb_info *dinfo, struct fb_var_screeninfo *var)
* fbdev interface * * 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 static int
intelfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) intelfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
{ {
...@@ -1433,6 +1484,19 @@ static int ...@@ -1433,6 +1484,19 @@ static int
intelfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) intelfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
{ {
int retval = 0; 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; return retval;
} }
......
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <linux/pagemap.h> #include <linux/pagemap.h>
#include <linux/interrupt.h>
#include <asm/io.h> #include <asm/io.h>
...@@ -368,7 +369,13 @@ intelfbhw_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) ...@@ -368,7 +369,13 @@ intelfbhw_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
offset += dinfo->fb.offset << 12; offset += dinfo->fb.offset << 12;
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); OUTREG(DSPABASE, offset);
}
return 0; return 0;
} }
...@@ -585,6 +592,11 @@ intelfbhw_read_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw, ...@@ -585,6 +592,11 @@ intelfbhw_read_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw,
hw->fw_blc_0 = INREG(FW_BLC_0); hw->fw_blc_0 = INREG(FW_BLC_0);
hw->fw_blc_1 = INREG(FW_BLC_1); 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; return 0;
} }
...@@ -613,6 +625,7 @@ static int calc_vclock(int index, int m1, int m2, int n, int p1, int p2, int lvd ...@@ -613,6 +625,7 @@ static int calc_vclock(int index, int m1, int m2, int n, int p1, int p2, int lvd
return vco / p; return vco / p;
} }
#if REGDUMP
static void static void
intelfbhw_get_p1p2(struct intelfb_info *dinfo, int dpll, int *o_p1, int *o_p2) 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 *dinfo, int dpll, int *o_p1, int *o_p2) ...@@ -638,6 +651,7 @@ intelfbhw_get_p1p2(struct intelfb_info *dinfo, int dpll, int *o_p1, int *o_p2)
*o_p1 = p1; *o_p1 = p1;
*o_p2 = p2; *o_p2 = p2;
} }
#endif
void void
...@@ -794,6 +808,10 @@ intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw) ...@@ -794,6 +808,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_0 0x%08x\n", hw->fw_blc_0);
printk(" FW_BLC_1 0x%08x\n", hw->fw_blc_1); 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"); printk("hw state dump end\n");
#endif #endif
} }
...@@ -1932,3 +1950,119 @@ intelfbhw_cursor_reset(struct intelfb_info *dinfo) { ...@@ -1932,3 +1950,119 @@ intelfbhw_cursor_reset(struct intelfb_info *dinfo) {
addr += 16; 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;
}
...@@ -88,6 +88,19 @@ ...@@ -88,6 +88,19 @@
#define INSTDONE 0x2090 #define INSTDONE 0x2090
#define PRI_RING_EMPTY 1 #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 INSTPM 0x20c0
#define SYNC_FLUSH_ENABLE (1 << 5) #define SYNC_FLUSH_ENABLE (1 << 5)
...@@ -113,6 +126,12 @@ ...@@ -113,6 +126,12 @@
#define FW_DISPC_BL_SHIFT 8 #define FW_DISPC_BL_SHIFT 8
#define FW_DISPC_BL_MASK 0x7 #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 */ /* PLL registers */
#define VGA0_DIVISOR 0x06000 #define VGA0_DIVISOR 0x06000
...@@ -468,9 +487,12 @@ ...@@ -468,9 +487,12 @@
/* I/O macros */ /* I/O macros */
#define INREG8(addr) readb((u8 __iomem *)(dinfo->mmio_base + (addr))) #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 INREG(addr) readl((u32 __iomem *)(dinfo->mmio_base + (addr)))
#define OUTREG8(addr, val) writeb((val),(u8 __iomem *)(dinfo->mmio_base + \ #define OUTREG8(addr, val) writeb((val),(u8 __iomem *)(dinfo->mmio_base + \
(addr))) (addr)))
#define OUTREG16(addr, val) writew((val),(u16 __iomem *)(dinfo->mmio_base + \
(addr)))
#define OUTREG(addr, val) writel((val),(u32 __iomem *)(dinfo->mmio_base + \ #define OUTREG(addr, val) writel((val),(u32 __iomem *)(dinfo->mmio_base + \
(addr))) (addr)))
...@@ -545,5 +567,8 @@ extern void intelfbhw_cursor_setcolor(struct intelfb_info *dinfo, u32 bg, ...@@ -545,5 +567,8 @@ extern void intelfbhw_cursor_setcolor(struct intelfb_info *dinfo, u32 bg,
extern void intelfbhw_cursor_load(struct intelfb_info *dinfo, int width, extern void intelfbhw_cursor_load(struct intelfb_info *dinfo, int width,
int height, u8 *data); int height, u8 *data);
extern void intelfbhw_cursor_reset(struct intelfb_info *dinfo); 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 */ #endif /* _INTELFBHW_H */
...@@ -193,6 +193,7 @@ ...@@ -193,6 +193,7 @@
#define I2C_HW_B_RADEON 0x01001e /* radeon framebuffer driver */ #define I2C_HW_B_RADEON 0x01001e /* radeon framebuffer driver */
#define I2C_HW_B_EM28XX 0x01001f /* em28xx video capture cards */ #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_CX2341X 0x010020 /* Conexant CX2341X MPEG encoder cards */
#define I2C_HW_B_INTELFB 0x010021 /* intel framebuffer driver */
/* --- PCF 8584 based algorithms */ /* --- PCF 8584 based algorithms */
#define I2C_HW_P_LP 0x020000 /* Parallel port interface */ #define I2C_HW_P_LP 0x020000 /* Parallel port interface */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment