mirror of
https://github.com/adulau/aha.git
synced 2024-12-28 11:46:19 +00:00
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
This commit is contained in:
commit
db1a19b38f
9 changed files with 535 additions and 11 deletions
|
@ -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
|
||||
------------
|
||||
|
|
|
@ -825,22 +825,33 @@ 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
|
||||
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
|
||||
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
|
||||
"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.
|
||||
|
||||
For more information, please read <file:Documentation/fb/intelfb.txt>
|
||||
|
||||
config FB_INTEL_DEBUG
|
||||
bool "Intel driver Debug Messages"
|
||||
depends on FB_INTEL
|
||||
|
@ -849,6 +860,13 @@ config FB_INTEL_DEBUG
|
|||
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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -6,6 +6,10 @@
|
|||
#include <linux/agp_backend.h>
|
||||
#include <linux/fb.h>
|
||||
|
||||
#ifdef CONFIG_FB_INTEL_I2C
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-algo-bit.h>
|
||||
#endif
|
||||
|
||||
/*** Version/name ***/
|
||||
#define INTELFB_VERSION "0.9.4"
|
||||
|
@ -115,6 +119,29 @@
|
|||
/* Intel agpgart driver */
|
||||
#define AGP_PHYSICAL_MEMORY 2
|
||||
|
||||
/* store information about an Ixxx DVO */
|
||||
/* The i830->i865 use multiple DVOs with multiple i2cs */
|
||||
/* the i915, i945 have a single sDVO i2c bus - which is different */
|
||||
#define MAX_OUTPUTS 6
|
||||
|
||||
/* these are outputs from the chip - integrated only
|
||||
external chips are via DVO or SDVO output */
|
||||
#define INTELFB_OUTPUT_UNUSED 0
|
||||
#define INTELFB_OUTPUT_ANALOG 1
|
||||
#define INTELFB_OUTPUT_DVO 2
|
||||
#define INTELFB_OUTPUT_SDVO 3
|
||||
#define INTELFB_OUTPUT_LVDS 4
|
||||
#define INTELFB_OUTPUT_TVOUT 5
|
||||
|
||||
#define INTELFB_DVO_CHIP_NONE 0
|
||||
#define INTELFB_DVO_CHIP_LVDS 1
|
||||
#define INTELFB_DVO_CHIP_TMDS 2
|
||||
#define INTELFB_DVO_CHIP_TVOUT 4
|
||||
|
||||
#define INTELFB_OUTPUT_PIPE_NC 0
|
||||
#define INTELFB_OUTPUT_PIPE_A 1
|
||||
#define INTELFB_OUTPUT_PIPE_B 2
|
||||
|
||||
/*** Data Types ***/
|
||||
|
||||
/* supported chipsets */
|
||||
|
@ -195,6 +222,10 @@ struct intelfb_hwstate {
|
|||
u32 mem_mode;
|
||||
u32 fw_blc_0;
|
||||
u32 fw_blc_1;
|
||||
u16 hwstam;
|
||||
u16 ier;
|
||||
u16 iir;
|
||||
u16 imr;
|
||||
};
|
||||
|
||||
struct intelfb_heap_data {
|
||||
|
@ -204,6 +235,33 @@ struct intelfb_heap_data {
|
|||
u32 size; // in bytes
|
||||
};
|
||||
|
||||
#ifdef CONFIG_FB_INTEL_I2C
|
||||
struct intelfb_i2c_chan {
|
||||
struct intelfb_info *dinfo;
|
||||
u32 reg;
|
||||
struct i2c_adapter adapter;
|
||||
struct i2c_algo_bit_data algo;
|
||||
};
|
||||
#endif
|
||||
|
||||
struct intelfb_output_rec {
|
||||
int type;
|
||||
int pipe;
|
||||
int flags;
|
||||
|
||||
#ifdef CONFIG_FB_INTEL_I2C
|
||||
struct intelfb_i2c_chan i2c_bus;
|
||||
struct intelfb_i2c_chan ddc_bus;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct intelfb_vsync {
|
||||
wait_queue_head_t wait;
|
||||
unsigned int count;
|
||||
int pan_display;
|
||||
u32 pan_offset;
|
||||
};
|
||||
|
||||
struct intelfb_info {
|
||||
struct fb_info *info;
|
||||
struct fb_ops *fbops;
|
||||
|
@ -220,7 +278,7 @@ struct intelfb_info {
|
|||
u8 fbmem_gart;
|
||||
|
||||
/* mtrr support */
|
||||
u32 mtrr_reg;
|
||||
int mtrr_reg;
|
||||
u32 has_mtrr;
|
||||
|
||||
/* heap data */
|
||||
|
@ -267,6 +325,12 @@ struct intelfb_info {
|
|||
int fixed_mode;
|
||||
int ring_active;
|
||||
int flag;
|
||||
unsigned long irq_flags;
|
||||
int open;
|
||||
|
||||
/* vsync */
|
||||
struct intelfb_vsync vsync;
|
||||
spinlock_t int_lock;
|
||||
|
||||
/* hw cursor */
|
||||
int cursor_on;
|
||||
|
@ -285,12 +349,25 @@ struct intelfb_info {
|
|||
|
||||
/* index into plls */
|
||||
int pll_index;
|
||||
|
||||
/* outputs */
|
||||
int num_outputs;
|
||||
struct intelfb_output_rec output[MAX_OUTPUTS];
|
||||
};
|
||||
|
||||
#define IS_I9XX(dinfo) (((dinfo)->chipset == INTEL_915G)||(dinfo->chipset == INTEL_915GM)||((dinfo)->chipset == INTEL_945G)||(dinfo->chipset==INTEL_945GM))
|
||||
|
||||
#ifndef FBIO_WAITFORVSYNC
|
||||
#define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32)
|
||||
#endif
|
||||
|
||||
/*** function prototypes ***/
|
||||
|
||||
extern int intelfb_var_to_depth(const struct fb_var_screeninfo *var);
|
||||
|
||||
#ifdef CONFIG_FB_INTEL_I2C
|
||||
extern void intelfb_create_i2c_busses(struct intelfb_info *dinfo);
|
||||
extern void intelfb_delete_i2c_busses(struct intelfb_info *dinfo);
|
||||
#endif
|
||||
|
||||
#endif /* _INTELFB_H */
|
||||
|
|
200
drivers/video/intelfb/intelfb_i2c.c
Normal file
200
drivers/video/intelfb/intelfb_i2c.c
Normal file
|
@ -0,0 +1,200 @@
|
|||
/**************************************************************************
|
||||
|
||||
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 @@
|
|||
static void __devinit get_initial_mode(struct intelfb_info *dinfo);
|
||||
static void update_dinfo(struct intelfb_info *dinfo,
|
||||
struct fb_var_screeninfo *var);
|
||||
static int intelfb_open(struct fb_info *info, int user);
|
||||
static int intelfb_release(struct fb_info *info, int user);
|
||||
static int intelfb_check_var(struct fb_var_screeninfo *var,
|
||||
struct fb_info *info);
|
||||
static int intelfb_set_par(struct fb_info *info);
|
||||
|
@ -194,6 +196,8 @@ static int num_registered = 0;
|
|||
/* fb ops */
|
||||
static struct fb_ops intel_fb_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.fb_open = intelfb_open,
|
||||
.fb_release = intelfb_release,
|
||||
.fb_check_var = intelfb_check_var,
|
||||
.fb_set_par = intelfb_set_par,
|
||||
.fb_setcolreg = intelfb_setcolreg,
|
||||
|
@ -446,6 +450,8 @@ cleanup(struct intelfb_info *dinfo)
|
|||
if (!dinfo)
|
||||
return;
|
||||
|
||||
intelfbhw_disable_irq(dinfo);
|
||||
|
||||
fb_dealloc_cmap(&dinfo->info->cmap);
|
||||
kfree(dinfo->info->pixmap.addr);
|
||||
|
||||
|
@ -467,6 +473,11 @@ cleanup(struct intelfb_info *dinfo)
|
|||
agp_free_memory(dinfo->gtt_ring_mem);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_FB_INTEL_I2C
|
||||
/* un-register I2C bus */
|
||||
intelfb_delete_i2c_busses(dinfo);
|
||||
#endif
|
||||
|
||||
if (dinfo->mmio_base)
|
||||
iounmap((void __iomem *)dinfo->mmio_base);
|
||||
if (dinfo->aperture.virtual)
|
||||
|
@ -844,6 +855,11 @@ intelfb_pci_register(struct pci_dev *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);
|
||||
|
||||
|
@ -888,6 +904,13 @@ 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;
|
||||
dinfo->vsync.pan_display = 0;
|
||||
dinfo->vsync.pan_offset = 0;
|
||||
|
||||
return 0;
|
||||
|
||||
|
@ -1187,6 +1210,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)
|
||||
{
|
||||
|
@ -1433,6 +1484,19 @@ static int
|
|||
intelfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
int retval = 0;
|
||||
struct intelfb_info *dinfo = GET_DINFO(info);
|
||||
u32 pipe = 0;
|
||||
|
||||
switch (cmd) {
|
||||
case FBIO_WAITFORVSYNC:
|
||||
if (get_user(pipe, (__u32 __user *)arg))
|
||||
return -EFAULT;
|
||||
|
||||
retval = intelfbhw_wait_for_vsync(dinfo, pipe);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include <linux/pci.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
|
||||
|
@ -368,7 +369,13 @@ intelfbhw_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
|
|||
|
||||
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);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -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_1 = INREG(FW_BLC_1);
|
||||
|
||||
hw->hwstam = INREG16(HWSTAM);
|
||||
hw->ier = INREG16(IER);
|
||||
hw->iir = INREG16(IIR);
|
||||
hw->imr = INREG16(IMR);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -613,6 +625,7 @@ static int calc_vclock(int index, int m1, 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)
|
||||
{
|
||||
|
@ -638,6 +651,7 @@ intelfbhw_get_p1p2(struct intelfb_info *dinfo, int dpll, int *o_p1, int *o_p2)
|
|||
*o_p1 = p1;
|
||||
*o_p2 = p2;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void
|
||||
|
@ -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_1 0x%08x\n", hw->fw_blc_1);
|
||||
|
||||
printk(" HWSTAM 0x%04x\n", hw->hwstam);
|
||||
printk(" IER 0x%04x\n", hw->ier);
|
||||
printk(" IIR 0x%04x\n", hw->iir);
|
||||
printk(" IMR 0x%04x\n", hw->imr);
|
||||
printk("hw state dump end\n");
|
||||
#endif
|
||||
}
|
||||
|
@ -1932,3 +1950,119 @@ intelfbhw_cursor_reset(struct intelfb_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++;
|
||||
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 @@
|
|||
#define INSTDONE 0x2090
|
||||
#define PRI_RING_EMPTY 1
|
||||
|
||||
#define HWSTAM 0x2098
|
||||
#define IER 0x20A0
|
||||
#define IIR 0x20A4
|
||||
#define IMR 0x20A8
|
||||
#define VSYNC_PIPE_A_INTERRUPT (1 << 7)
|
||||
#define PIPE_A_EVENT_INTERRUPT (1 << 4)
|
||||
#define VSYNC_PIPE_B_INTERRUPT (1 << 5)
|
||||
#define PIPE_B_EVENT_INTERRUPT (1 << 4)
|
||||
#define HOST_PORT_EVENT_INTERRUPT (1 << 3)
|
||||
#define CAPTURE_EVENT_INTERRUPT (1 << 2)
|
||||
#define USER_DEFINED_INTERRUPT (1 << 1)
|
||||
#define BREAKPOINT_INTERRUPT 1
|
||||
|
||||
#define INSTPM 0x20c0
|
||||
#define SYNC_FLUSH_ENABLE (1 << 5)
|
||||
|
||||
|
@ -113,6 +126,12 @@
|
|||
#define FW_DISPC_BL_SHIFT 8
|
||||
#define FW_DISPC_BL_MASK 0x7
|
||||
|
||||
#define GPIOA 0x5010
|
||||
#define GPIOB 0x5014
|
||||
#define GPIOC 0x5018 // this may be external DDC on i830
|
||||
#define GPIOD 0x501C // this is DVO DDC
|
||||
#define GPIOE 0x5020 // this is DVO i2C
|
||||
#define GPIOF 0x5024
|
||||
|
||||
/* PLL registers */
|
||||
#define VGA0_DIVISOR 0x06000
|
||||
|
@ -468,9 +487,12 @@
|
|||
|
||||
/* I/O macros */
|
||||
#define INREG8(addr) readb((u8 __iomem *)(dinfo->mmio_base + (addr)))
|
||||
#define INREG16(addr) readw((u16 __iomem *)(dinfo->mmio_base + (addr)))
|
||||
#define INREG(addr) readl((u32 __iomem *)(dinfo->mmio_base + (addr)))
|
||||
#define OUTREG8(addr, val) writeb((val),(u8 __iomem *)(dinfo->mmio_base + \
|
||||
(addr)))
|
||||
#define OUTREG16(addr, val) writew((val),(u16 __iomem *)(dinfo->mmio_base + \
|
||||
(addr)))
|
||||
#define OUTREG(addr, val) writel((val),(u32 __iomem *)(dinfo->mmio_base + \
|
||||
(addr)))
|
||||
|
||||
|
@ -545,5 +567,8 @@ extern void intelfbhw_cursor_setcolor(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);
|
||||
extern int intelfbhw_wait_for_vsync(struct intelfb_info *dinfo, u32 pipe);
|
||||
|
||||
#endif /* _INTELFBHW_H */
|
||||
|
|
|
@ -193,6 +193,7 @@
|
|||
#define I2C_HW_B_RADEON 0x01001e /* radeon framebuffer driver */
|
||||
#define I2C_HW_B_EM28XX 0x01001f /* em28xx video capture cards */
|
||||
#define I2C_HW_B_CX2341X 0x010020 /* Conexant CX2341X MPEG encoder cards */
|
||||
#define I2C_HW_B_INTELFB 0x010021 /* intel framebuffer driver */
|
||||
|
||||
/* --- PCF 8584 based algorithms */
|
||||
#define I2C_HW_P_LP 0x020000 /* Parallel port interface */
|
||||
|
|
Loading…
Reference in a new issue