Merge branch 'modesetting' into crestline

This works for analog, but SDVO output appears to not work yet.

Conflicts:

	src/i830_driver.c
This commit is contained in:
Eric Anholt 2006-11-17 11:48:53 -08:00
commit 15ff17c756
54 changed files with 10599 additions and 7241 deletions

2
.gitignore vendored
View File

@ -4,6 +4,7 @@ Makefile
Makefile.in
*.la
*.lo
*.o
aclocal.m4
autom4te.cache
compile
@ -20,3 +21,4 @@ libtool
ltmain.sh
missing
stamp-h1
i810.4

3
TODO Normal file
View File

@ -0,0 +1,3 @@
- licensing of new files
- Figure out what exactly doublescan, interlace mean, and see if we support them.
- Remove VbeModeInfoData

View File

@ -118,8 +118,6 @@ if test "x$GCC" = "xyes"; then
-Wnested-externs -fno-strict-aliasing"
fi
CFLAGS="$CFLAGS $WARN_CFLAGS"
AM_CONDITIONAL(DRI, test x$DRI = xyes)
if test "$DRI" = yes; then
PKG_CHECK_MODULES(DRI, [libdrm >= 2.2 xf86driproto])
@ -134,6 +132,7 @@ fi
AC_SUBST([DRI_CFLAGS])
AC_SUBST([XORG_CFLAGS])
AC_SUBST([WARN_CFLAGS])
AC_SUBST([moduledir])
DRIVER_NAME=i810
@ -148,5 +147,8 @@ AC_OUTPUT([
Makefile
src/Makefile
src/xvmc/Makefile
src/bios_reader/Makefile
src/ch7xxx/Makefile
src/sil164/Makefile
man/Makefile
])

View File

@ -1,2 +0,0 @@
Makefile
Makefile.in

View File

@ -116,13 +116,6 @@ The following driver
.B Options
are supported for the 830M and later chipsets:
.TP
.BI "Option \*qVBERestore\*q \*q" boolean \*q
Enable or disable the use of VBE save/restore for saving and restoring
the initial text mode. This is disabled by default because it causes
lockups on some platforms. However, there are some cases where it must
enabled for the correct restoration of the initial video mode. If you are
having a problem with that, try enabling this option. Default: Disabled.
.TP
.BI "Option \*qVideoKey\*q \*q" integer \*q
This is the same as the
.B \*qColorKey\*q
@ -178,19 +171,6 @@ NOTE: Using this option may cause text mode to be restored incorrectly,
and thus should be used with caution.
Default: disabled.
.TP
.BI "Option \*qDisplayInfo\*q \*q" boolean \*q
It has been found that a certain BIOS call can lockup the Xserver because
of a problem in the Video BIOS. The log file will identify if you are
suffering from this problem and tell you to turn this option off.
Default: enabled
.TP
.BI "Option \*qDevicePresence\*q \*q" boolean \*q
Tell the driver to perform an active detect of the currently connected
monitors. This option is useful if the monitor was not connected when
the machine has booted, but unfortunately it doesn't always work and
is extremely dependent upon the Video BIOS.
Default: disabled
.TP
.BI "Option \*qRotate\*q \*q90\*q"
Rotate the desktop 90 degrees counterclockwise. Other valid options are
0, 90, 180 and 270 degrees. The RandR extension is used for rotation

View File

@ -18,13 +18,13 @@
# 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.
SUBDIRS = xvmc
SUBDIRS = xvmc bios_reader ch7xxx sil164
# this is obnoxious:
# -module lets us name the module exactly how we want
# -avoid-version prevents gratuitous .0.0.0 version numbers on the end
# _ladir passes a dummy rpath to libtool so the thing will actually link
# TODO: -nostdlib/-Bstatic/-lgcc platform magic, not installing the .a, etc.
AM_CFLAGS = @XORG_CFLAGS@ @DRI_CFLAGS@ -DI830_XV
AM_CFLAGS = @WARN_CFLAGS@ @XORG_CFLAGS@ @DRI_CFLAGS@ -DI830_XV
i810_drv_la_LTLIBRARIES = i810_drv.la
i810_drv_la_LDFLAGS = -module -avoid-version
@ -36,6 +36,7 @@ i810_drv_la_SOURCES = \
sf_prog.h \
wm_prog.h \
common.h \
i2c_vid.h \
i810_accel.c \
i810_common.h \
i810_cursor.c \
@ -47,21 +48,38 @@ i810_drv_la_SOURCES = \
i810_reg.h \
i810_video.c \
i810_wmark.c \
i830_3d.c \
i830_accel.c \
i830_bios.c \
i830_bios.h \
i830_common.h \
i830_crt.c \
i830_cursor.c \
i830_debug.c \
i830_debug.h \
i830_dga.c \
i830_display.c \
i830_display.h \
i830_driver.c \
i830_dvo.c \
i830.h \
i830_gtf.c \
i830_i2c.c \
i830_io.c \
i830_lvds.c \
i830_memory.c \
i830_modes.c \
i830_video.c \
i830_video.h \
i830_reg.h \
i830_rotate.c \
i830_randr.c \
i830_3d.c \
i830_reg.h \
i830_sdvo.c \
i830_sdvo.h \
i830_sdvo_regs.h \
i830_tv.c \
i830_xf86Modes.h \
i830_xf86Modes.c \
i915_3d.c \
i915_3d.h \
i915_reg.h \

1
src/bios_reader/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
bios_reader

View File

@ -0,0 +1,4 @@
AM_CFLAGS = @XORG_CFLAGS@
noinst_PROGRAMS = bios_reader

View File

@ -0,0 +1,163 @@
/*
* Copyright © 2006 Intel Corporation
*
* 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
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* 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 NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS 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.
*
* Authors:
* Eric Anholt <eric@anholt.net>
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#define _PARSE_EDID_
#include "edid.h"
/* Define some types so we can reuse i830_bios.h */
typedef void *ScrnInfoPtr;
typedef int Bool;
#define TRUE 1
#define FALSE 0
#include "../i830_bios.h"
/* Make a fake pI830 so we can easily pull i830_bios.c code in here. */
struct _fake_i830 {
CARD8 *VBIOS;
};
struct _fake_i830 I830;
struct _fake_i830 *pI830 = &I830;
#define INTEL_BIOS_8(_addr) (pI830->VBIOS[_addr])
#define INTEL_BIOS_16(_addr) (pI830->VBIOS[_addr] | \
(pI830->VBIOS[_addr + 1] << 8))
#define INTEL_BIOS_32(_addr) (pI830->VBIOS[_addr] | \
(pI830->VBIOS[_addr + 1] << 8) \
(pI830->VBIOS[_addr + 2] << 16) \
(pI830->VBIOS[_addr + 3] << 24))
int main(int argc, char **argv)
{
FILE *f;
int bios_size = 65536;
struct vbt_header *vbt;
struct bdb_header *bdb;
int vbt_off, bdb_off, bdb_block_off, block_size;
int panel_type = -1, i;
char *filename = "bios";
if (argc == 2)
filename = argv[1];
f = fopen(filename, "r");
if (!f) {
printf("Couldn't open %s\n", filename);
return 1;
}
pI830->VBIOS = calloc(1, bios_size);
if (fread(pI830->VBIOS, 1, bios_size, f) != bios_size)
return 1;
vbt_off = INTEL_BIOS_16(0x1a);
printf("VBT offset: %08x\n", vbt_off);
vbt = (struct vbt_header *)(pI830->VBIOS + vbt_off);
printf("VBT sig: %20s\n", vbt->signature);
printf("VBT vers: %d.%d\n", vbt->version / 100, vbt->version % 100);
bdb_off = vbt_off + vbt->bdb_offset;
bdb = (struct bdb_header *)(pI830->VBIOS + bdb_off);
printf("BDB sig: %16s\n", bdb->signature);
printf("BDB vers: %d.%d\n", bdb->version / 100, bdb->version % 100);
for (bdb_block_off = bdb->header_size; bdb_block_off < bdb->bdb_size;
bdb_block_off += block_size)
{
int start = bdb_off + bdb_block_off;
int id;
struct lvds_bdb_1 *lvds1;
struct lvds_bdb_2 *lvds2;
struct lvds_bdb_2_fp_params *fpparam;
struct lvds_bdb_2_fp_edid_dtd *fptiming;
CARD8 *timing_ptr;
id = INTEL_BIOS_8(start);
block_size = INTEL_BIOS_16(start + 1) + 3;
printf("BDB block type %03d size %d\n", id, block_size);
switch (id) {
case 40:
lvds1 = (struct lvds_bdb_1 *)(pI830->VBIOS + start);
panel_type = lvds1->panel_type;
printf("Panel type: %d, caps %04x\n", panel_type, lvds1->caps);
break;
case 41:
if (panel_type == -1) {
printf("Found panel block with no panel type\n");
break;
}
lvds2 = (struct lvds_bdb_2 *)(pI830->VBIOS + start);
printf("Entries per table: %d\n", lvds2->table_size);
for (i = 0; i < 16; i++) {
char marker;
fpparam = (struct lvds_bdb_2_fp_params *)(pI830->VBIOS +
bdb_off + lvds2->panels[i].fp_params_offset);
fptiming = (struct lvds_bdb_2_fp_edid_dtd *)(pI830->VBIOS +
bdb_off + lvds2->panels[i].fp_edid_dtd_offset);
timing_ptr = pI830->VBIOS + bdb_off +
lvds2->panels[i].fp_edid_dtd_offset;
if (fpparam->terminator != 0xffff) {
/* Apparently the offsets are wrong for some BIOSes, so we
* try the other offsets if we find a bad terminator.
*/
fpparam = (struct lvds_bdb_2_fp_params *)(pI830->VBIOS +
bdb_off + lvds2->panels[i].fp_params_offset + 8);
fptiming = (struct lvds_bdb_2_fp_edid_dtd *)(pI830->VBIOS +
bdb_off + lvds2->panels[i].fp_edid_dtd_offset + 8);
timing_ptr = pI830->VBIOS + bdb_off +
lvds2->panels[i].fp_edid_dtd_offset + 8;
if (fpparam->terminator != 0xffff)
continue;
}
if (i == panel_type)
marker = '*';
else
marker = ' ';
printf("%c Panel index %02i xres %d yres %d clock %d\n", marker,
i, fpparam->x_res, fpparam->y_res,
_PIXEL_CLOCK(timing_ptr));
printf(" %d %d %d %d %d %d %d %d\n",
_H_ACTIVE(timing_ptr), _H_BLANK(timing_ptr),
_H_SYNC_OFF(timing_ptr), _H_SYNC_WIDTH(timing_ptr),
_V_ACTIVE(timing_ptr), _V_BLANK(timing_ptr),
_V_SYNC_OFF(timing_ptr), _V_SYNC_WIDTH(timing_ptr));
}
printf("Panel of size %dx%d\n", fpparam->x_res, fpparam->y_res);
break;
}
}
return 0;
}

16
src/ch7xxx/Makefile.am Normal file
View File

@ -0,0 +1,16 @@
# this is obnoxious:
# -module lets us name the module exactly how we want
# -avoid-version prevents gratuitous .0.0.0 version numbers on the end
# _ladir passes a dummy rpath to libtool so the thing will actually link
# TODO: -nostdlib/-Bstatic/-lgcc platform magic, not installing the .a, etc.
AM_CFLAGS = @XORG_CFLAGS@ @DRI_CFLAGS@
ch7xxx_la_LTLIBRARIES = ch7xxx.la
ch7xxx_la_LDFLAGS = -module -avoid-version
ch7xxx_ladir = @moduledir@/drivers
ch7xxx_la_SOURCES = \
ch7xxx.c \
ch7xxx_module.c \
ch7xxx.h \
ch7xxx_reg.h

272
src/ch7xxx/ch7xxx.c Normal file
View File

@ -0,0 +1,272 @@
/**************************************************************************
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 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 AUTHOR 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 <string.h>
#include "xf86.h"
#include "xf86_OSproc.h"
#include "xf86Resources.h"
#include "compiler.h"
#include "miscstruct.h"
#include "xf86i2c.h"
#include "../i2c_vid.h"
#include "ch7xxx.h"
#include "ch7xxx_reg.h"
static void ch7xxxSaveRegs(I2CDevPtr d);
static CARD8 ch7xxxFreqRegs[][7] =
{ { 0, 0x23, 0x08, 0x16, 0x30, 0x60, 0x00 },
{ 0, 0x23, 0x04, 0x26, 0x30, 0x60, 0x00 },
{ 0, 0x2D, 0x07, 0x26, 0x30, 0xE0, 0x00 } };
static Bool ch7xxxReadByte(CH7xxxPtr ch7xxx, int addr, unsigned char *ch)
{
if (!xf86I2CReadByte(&(ch7xxx->d), addr, ch)) {
xf86DrvMsg(ch7xxx->d.pI2CBus->scrnIndex, X_ERROR, "Unable to read from %s Slave %d.\n", ch7xxx->d.pI2CBus->BusName, ch7xxx->d.SlaveAddr);
return FALSE;
}
return TRUE;
}
static Bool ch7xxxWriteByte(CH7xxxPtr ch7xxx, int addr, unsigned char ch)
{
if (!xf86I2CWriteByte(&(ch7xxx->d), addr, ch)) {
xf86DrvMsg(ch7xxx->d.pI2CBus->scrnIndex, X_ERROR, "Unable to write to %s Slave %d.\n", ch7xxx->d.pI2CBus->BusName, ch7xxx->d.SlaveAddr);
return FALSE;
}
return TRUE;
}
/* Ch7xxxicon Image 164 driver for chip on i2c bus */
static void *ch7xxxDetect(I2CBusPtr b, I2CSlaveAddr addr)
{
/* this will detect the CH7xxx chip on the specified i2c bus */
CH7xxxPtr ch7xxx;
unsigned char ch;
xf86DrvMsg(b->scrnIndex, X_ERROR, "detecting ch7xxx\n");
ch7xxx = xcalloc(1, sizeof(CH7xxxRec));
if (ch7xxx == NULL)
return NULL;
ch7xxx->d.DevName = "CH7xxx TMDS Controller";
ch7xxx->d.SlaveAddr = addr;
ch7xxx->d.pI2CBus = b;
ch7xxx->d.StartTimeout = b->StartTimeout;
ch7xxx->d.BitTimeout = b->BitTimeout;
ch7xxx->d.AcknTimeout = b->AcknTimeout;
ch7xxx->d.ByteTimeout = b->ByteTimeout;
ch7xxx->d.DriverPrivate.ptr = ch7xxx;
if (!ch7xxxReadByte(ch7xxx, CH7xxx_REG_VID, &ch))
goto out;
ErrorF("VID is %02X", ch);
if (ch!=(CH7xxx_VID & 0xFF))
{
xf86DrvMsg(ch7xxx->d.pI2CBus->scrnIndex, X_ERROR, "ch7xxx not detected got %d: from %s Slave %d.\n", ch, ch7xxx->d.pI2CBus->BusName, ch7xxx->d.SlaveAddr);
goto out;
}
if (!ch7xxxReadByte(ch7xxx, CH7xxx_REG_DID, &ch))
goto out;
ErrorF("DID is %02X", ch);
if (ch!=(CH7xxx_DID & 0xFF))
{
xf86DrvMsg(ch7xxx->d.pI2CBus->scrnIndex, X_ERROR, "ch7xxx not detected got %d: from %s Slave %d.\n", ch, ch7xxx->d.pI2CBus->BusName, ch7xxx->d.SlaveAddr);
goto out;
}
if (!xf86I2CDevInit(&(ch7xxx->d)))
{
goto out;
}
return ch7xxx;
out:
xfree(ch7xxx);
return NULL;
}
static Bool ch7xxxInit(I2CDevPtr d)
{
CH7xxxPtr ch7xxx = CH7PTR(d);
/* not much to do */
return TRUE;
}
static ModeStatus ch7xxxModeValid(I2CDevPtr d, DisplayModePtr mode)
{
CH7xxxPtr ch7xxx = CH7PTR(d);
return MODE_OK;
}
static void ch7xxxMode(I2CDevPtr d, DisplayModePtr mode)
{
CH7xxxPtr ch7xxx = CH7PTR(d);
int ret;
unsigned char pm, idf;
unsigned char tpcp, tpd, tpf, cm;
CARD8 *freq_regs;
int i;
ErrorF("Clock is %d\n", mode->Clock);
if (mode->Clock < 75000)
freq_regs = ch7xxxFreqRegs[0];
else if (mode->Clock < 125000)
freq_regs = ch7xxxFreqRegs[1];
else
freq_regs = ch7xxxFreqRegs[2];
for (i = 0x31; i < 0x37; i++) {
ch7xxx->ModeReg.regs[i] = freq_regs[i - 0x31];
ch7xxxWriteByte(ch7xxx, i, ch7xxx->ModeReg.regs[i]);
}
#if 0
xf86DrvMsg(ch7xxx->d.pI2CBus->scrnIndex, X_ERROR, "ch7xxx idf is 0x%02x, 0x%02x, 0x%02x, 0x%02x\n", idf, tpcp, tpd, tpf);
xf86DrvMsg(ch7xxx->d.pI2CBus->scrnIndex, X_ERROR, "ch7xxx pm is %02X\n", pm);
if (mode->Clock < 65000) {
tpcp = 0x08;
tpd = 0x16;
tpf = 0x60;
} else {
tpcp = 0x06;
tpd = 0x26;
tpf = 0xa0;
}
idf &= ~(CH7xxx_IDF_HSP | CH7xxx_IDF_VSP);
if (mode->Flags & V_PHSYNC)
idf |= CH7xxx_IDF_HSP;
if (mode->Flags & V_PVSYNC)
idf |= CH7xxx_IDF_HSP;
/* setup PM Registers */
pm &= ~CH7xxx_PM_FPD;
pm |= CH7xxx_PM_DVIL | CH7xxx_PM_DVIP;
// cm |= 1;
ch7xxxWriteByte(ch7xxx, CH7xxx_CM, cm);
ch7xxxWriteByte(ch7xxx, CH7xxx_TPCP, tpcp);
ch7xxxWriteByte(ch7xxx, CH7xxx_TPD, tpd);
ch7xxxWriteByte(ch7xxx, CH7xxx_TPF, tpf);
ch7xxxWriteByte(ch7xxx, CH7xxx_TPF, idf);
ch7xxxWriteByte(ch7xxx, CH7xxx_PM, pm);
#endif
/* don't do much */
return;
}
/* set the CH7xxx power state */
static void ch7xxxPower(I2CDevPtr d, Bool On)
{
CH7xxxPtr ch7xxx = CH7PTR(d);
int ret;
unsigned char ch;
ret = ch7xxxReadByte(ch7xxx, CH7xxx_PM, &ch);
if (ret == FALSE)
return;
xf86DrvMsg(ch7xxx->d.pI2CBus->scrnIndex, X_ERROR, "ch7xxx pm is %02X\n", ch);
#if 0
ret = ch7xxxReadByte(ch7xxx, CH7xxx_REG8, &ch);
if (ret)
return;
if (On)
ch |= CH7xxx_8_PD;
else
ch &= ~CH7xxx_8_PD;
ch7xxxWriteByte(ch7xxx, CH7xxx_REG8, ch);
#endif
return;
}
static void ch7xxxPrintRegs(I2CDevPtr d)
{
CH7xxxPtr ch7xxx = CH7PTR(d);
int i;
ch7xxxSaveRegs(d);
for (i = 0; i < CH7xxx_NUM_REGS; i++) {
if (( i % 8 ) == 0 )
ErrorF("\n %02X: ", i);
ErrorF("%02X ", ch7xxx->ModeReg.regs[i]);
}
}
static void ch7xxxSaveRegs(I2CDevPtr d)
{
CH7xxxPtr ch7xxx = CH7PTR(d);
int ret;
int i;
for (i = 0; i < CH7xxx_NUM_REGS; i++) {
ret = ch7xxxReadByte(ch7xxx, i, &ch7xxx->SavedReg.regs[i]);
if (ret == FALSE)
break;
}
memcpy(ch7xxx->ModeReg.regs, ch7xxx->SavedReg.regs, CH7xxx_NUM_REGS);
return;
}
I830I2CVidOutputRec CH7xxxVidOutput = {
ch7xxxDetect,
ch7xxxInit,
ch7xxxModeValid,
ch7xxxMode,
ch7xxxPower,
ch7xxxPrintRegs,
ch7xxxSaveRegs,
NULL,
};

31
src/ch7xxx/ch7xxx.h Normal file
View File

@ -0,0 +1,31 @@
/**************************************************************************
Copyright 2006 Dave Airlie <airlied@linux.ie>
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.
**************************************************************************/
#ifndef CH7xxx_H
#define CH7xxx_H
#define CH7xxx_ADDR_1 0x76
#endif

View File

@ -0,0 +1,36 @@
#ifdef HAVE_XORG_CONFIG_H
#include <xorg-config.h>
#endif
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "xf86Module.h"
static MODULESETUPPROTO(ch7xxxSetup);
static XF86ModuleVersionInfo ch7xxxVersRec =
{
"ch7xxx",
MODULEVENDORSTRING,
MODINFOSTRING1,
MODINFOSTRING2,
XORG_VERSION_CURRENT,
1, 0, 0,
ABI_CLASS_VIDEODRV,
ABI_VIDEODRV_VERSION,
MOD_CLASS_NONE,
{ 0,0,0,0 }
};
_X_EXPORT XF86ModuleData ch7xxxModuleData = {
&ch7xxxVersRec,
ch7xxxSetup,
NULL
};
static pointer
ch7xxxSetup(pointer module, pointer opts, int *errmaj, int *errmin) {
return (pointer)1;
}

91
src/ch7xxx/ch7xxx_reg.h Normal file
View File

@ -0,0 +1,91 @@
/**************************************************************************
Copyright 2006 Dave Airlie <airlied@linux.ie>
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.
**************************************************************************/
#ifndef CH7xxx_REG_H
#define CH7xxx_REG_H
#define CH7xxx_REG_VID 0x4a
#define CH7xxx_REG_DID 0x4b
#define CH7011_VID 0x83
#define CH7009A_VID 0x84
#define CH7009B_VID 0x85
#define CH7301_VID 0x95
#define CH7xxx_VID 0x84
#define CH7xxx_DID 0x17
#define CH7xxx_NUM_REGS 0x4c
typedef struct _CH7xxxSaveRec {
CARD8 regs[CH7xxx_NUM_REGS];
} CH7xxxSaveRec;
typedef struct {
I2CDevRec d;
CH7xxxSaveRec SavedReg;
CH7xxxSaveRec ModeReg;
} CH7xxxRec, *CH7xxxPtr;
#define CH7PTR(d) ((CH7xxxPtr)(d->DriverPrivate.ptr))
#define CH7xxx_CM 0x1C
#define CH7xxx_CM_XCM (1<<0)
#define CH7xxx_CM_MCP (1<<2)
#define CH7xxx_INPUT_CLOCK 0x1D
#define CH7xxx_GPIO 0x1E
#define CH7xxx_IDF 0x1F
#define CH7xxx_IDF_HSP (1<<3)
#define CH7xxx_IDF_VSP (1<<4)
#define CH7301_CONNECTION_DETECT 0x20
#define CH7301_DAC_CNTL 0x21
#define CH7301_HOTPLUG 0x23
#define CH7xxx_TCTL 0x31
#define CH7xxx_TPCP 0x33
#define CH7xxx_TPD 0x34
#define CH7xxx_TPVT 0x35
#define CH7xxx_TPF 0x36
#define CH7301_TCT 0x37
#define CH7301_TEST_PATTERN 0x48
#define CH7xxx_PM 0x49
#define CH7xxx_PM_FPD (1<<0)
#define CH7301_PM_DACPD0 (1<<1)
#define CH7301_PM_DACPD1 (1<<2)
#define CH7301_PM_DACPD2 (1<<3)
#define CH7xxx_PM_DVIL (1<<6)
#define CH7xxx_PM_DVIP (1<<7)
#define CH7301_SYNC_POLARITY 0x56
#define CH7301_SYNC_RGB_YUV (1<<0)
#define CH7301_SYNC_POL_DVI (1<<5)
#endif

View File

@ -73,7 +73,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#endif
/* I830 hooks for the I810 driver setup/probe. */
extern const OptionInfoRec *I830BIOSAvailableOptions(int chipid, int busid);
extern const OptionInfoRec *I830AvailableOptions(int chipid, int busid);
extern void I830InitpScrn(ScrnInfoPtr pScrn);
/* Symbol lists shared by the i810 and i830 parts. */
@ -90,6 +90,7 @@ extern const char *I810shadowSymbols[];
extern const char *I810driSymbols[];
extern const char *I810drmSymbols[];
#endif
extern const char *I810i2cSymbols[];
extern void I830DPRINTF_stub(const char *filename, int line,
const char *function, const char *fmt, ...);
@ -106,8 +107,8 @@ extern void I830DPRINTF_stub(const char *filename, int line,
/* BIOS debug macro */
#define xf86ExecX86int10_wrapper(pInt, pScrn) do { \
ErrorF("Executing (ax == 0x%x) BIOS call at %s:%d\n", pInt->ax, __FILE__, __LINE__); \
if (I810_DEBUG & DEBUG_VERBOSE_BIOS) { \
ErrorF("\n\n\n\nExecuting (ax == 0x%x) BIOS call\n", pInt->ax); \
ErrorF("Checking Error state before execution\n"); \
PrintErrorState(pScrn); \
} \

16
src/i2c_vid.h Normal file
View File

@ -0,0 +1,16 @@
/* this needs to go in the server */
#ifndef I2C_VID_H
#define I2C_VID_H
typedef struct _I830I2CVidOutputRec {
void *(*Detect)(I2CBusPtr b, I2CSlaveAddr addr);
Bool (*Init)(I2CDevPtr d);
ModeStatus (*ModeValid)(I2CDevPtr d, DisplayModePtr mode);
void (*Mode)(I2CDevPtr d, DisplayModePtr mode);
void (*Power)(I2CDevPtr d, Bool On);
void (*PrintRegs)(I2CDevPtr d);
void (*SaveRegs)(I2CDevPtr d);
void (*RestoreRegs)(I2CDevPtr d);
} I830I2CVidOutputRec, *I830I2CVidOutputPtr;
#endif

View File

@ -347,6 +347,14 @@ const char *I810shadowSymbols[] = {
"shadowInit",
"shadowSetup",
"shadowAdd",
"shadowRemove",
"shadowUpdateRotatePacked",
NULL
};
const char *I810i2cSymbols[] = {
"xf86CreateI2CBusRec",
"xf86I2CBusInit",
NULL
};
@ -486,11 +494,11 @@ I810AvailableOptions(int chipid, int busid)
#ifndef I830_ONLY
const OptionInfoRec *pOptions;
if ((pOptions = I830BIOSAvailableOptions(chipid, busid)))
if ((pOptions = I830AvailableOptions(chipid, busid)))
return pOptions;
return I810Options;
#else
return I830BIOSAvailableOptions(chipid, busid);
return I830AvailableOptions(chipid, busid);
#endif
}

View File

@ -26,9 +26,14 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
**************************************************************************/
/** @file
* Register names and fields for Intel graphics.
*/
/*
* Authors:
* Keith Whitwell <keith@tungstengraphics.com>
* Eric Anholt <eric@anholt.net>
*
* based on the i740 driver by
* Kevin E. Martin <kevin@precisioninsight.com>
@ -94,6 +99,10 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#define LINEAR_MODE_ENABLE 0x02
#define PAGE_MAPPING_ENABLE 0x01
#define HOTKEY_VBIOS_SWITCH_BLOCK 0x80
#define HOTKEY_SWITCH 0x20
#define HOTKEY_TOGGLE 0x10
/* Blitter control, p378
*/
#define BITBLT_CNTL 0x7000c
@ -258,7 +267,26 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#define HSYNC_ON 0x00
#define HSYNC_OFF 0x02
#define GPIOA 0x5010
#define GPIOB 0x5014
#define GPIOC 0x5018
#define GPIOD 0x501c
#define GPIOE 0x5020
#define GPIOF 0x5024
#define GPIOG 0x5028
#define GPIOH 0x502c
# define GPIO_CLOCK_DIR_MASK (1 << 0)
# define GPIO_CLOCK_DIR_IN (0 << 1)
# define GPIO_CLOCK_DIR_OUT (1 << 1)
# define GPIO_CLOCK_VAL_MASK (1 << 2)
# define GPIO_CLOCK_VAL_OUT (1 << 3)
# define GPIO_CLOCK_VAL_IN (1 << 4)
# define GPIO_DATA_DIR_MASK (1 << 8)
# define GPIO_DATA_DIR_IN (0 << 9)
# define GPIO_DATA_DIR_OUT (1 << 9)
# define GPIO_DATA_VAL_MASK (1 << 10)
# define GPIO_DATA_VAL_OUT (1 << 11)
# define GPIO_DATA_VAL_IN (1 << 12)
/* p317, 319
*/
@ -713,6 +741,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#define VSYNC_A 0x60014
#define PIPEASRC 0x6001c
#define BCLRPAT_A 0x60020
#define VSYNCSHIFT_A 0x60028
#define HTOTAL_B 0x61000
#define HBLANK_B 0x61004
@ -722,11 +751,206 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#define VSYNC_B 0x61014
#define PIPEBSRC 0x6101c
#define BCLRPAT_B 0x61020
#define VSYNCSHIFT_B 0x61028
#define PP_STATUS 0x61200
# define PP_ON (1 << 31)
#define PP_CONTROL 0x61204
# define POWER_TARGET_ON (1 << 0)
#define LVDSPP_ON 0x61208
#define LVDSPP_OFF 0x6120c
#define PP_CYCLE 0x61210
#define PFIT_CONTROL 0x61230
# define PFIT_ENABLE (1 << 31)
# define VERT_INTERP_DISABLE (0 << 10)
# define VERT_INTERP_BILINEAR (1 << 10)
# define VERT_INTERP_MASK (3 << 10)
# define VERT_AUTO_SCALE (1 << 9)
# define HORIZ_INTERP_DISABLE (0 << 6)
# define HORIZ_INTERP_BILINEAR (1 << 6)
# define HORIZ_INTERP_MASK (3 << 6)
# define HORIZ_AUTO_SCALE (1 << 5)
# define PANEL_8TO6_DITHER_ENABLE (1 << 3)
#define PFIT_PGM_RATIOS 0x61234
# define PFIT_VERT_SCALE_MASK 0xfff00000
# define PFIT_HORIZ_SCALE_MASK 0x0000fff0
#define PFIT_AUTO_RATIOS 0x61238
#define DPLL_A 0x06014
#define DPLL_B 0x06018
# define DPLL_VCO_ENABLE (1 << 31)
# define DPLL_DVO_HIGH_SPEED (1 << 30)
# define DPLL_SYNCLOCK_ENABLE (1 << 29)
# define DPLL_VGA_MODE_DIS (1 << 28)
# define DPLLB_MODE_DAC_SERIAL (1 << 26) /* i915 */
# define DPLLB_MODE_LVDS (2 << 26) /* i915 */
# define DPLL_DAC_SERIAL_P2_CLOCK_DIV_10 (0 << 24) /* i915 */
# define DPLL_DAC_SERIAL_P2_CLOCK_DIV_5 (1 << 24) /* i915 */
# define DPLLB_LVDS_P2_CLOCK_DIV_14 (0 << 24) /* i915 */
# define DPLLB_LVDS_P2_CLOCK_DIV_7 (1 << 24) /* i915 */
# define DPLL_P2_CLOCK_DIV_MASK 0x03000000 /* i915 */
# define DPLL_FPA01_P1_POST_DIV_MASK 0x00ff0000 /* i915 */
# define PLL_P2_DIVIDE_BY_4 (1 << 23) /* i830, required in DVO non-gang */
# define DPLL_FPA01_P1_POS_DIV_MASK_I830 0x001f0000 /* i830 */
# define PLL_P1_DIVIDE_BY_TWO (1 << 21) /* i830 */
# define PLL_REF_INPUT_DREFCLK (0 << 13)
# define PLL_REF_INPUT_TVCLKINA (1 << 13) /* i830 */
# define PLL_REF_INPUT_TVCLKINBC (2 << 13) /* SDVO TVCLKIN */
# define PLLB_REF_INPUT_SPREADSPECTRUMIN (3 << 13)
# define PLL_LOAD_PULSE_PHASE_SHIFT 9
/*
* Parallel to Serial Load Pulse phase selection.
* Selects the phase for the 10X DPLL clock for the PCIe
* digital display port. The range is 4 to 13; 10 or more
* is just a flip delay. The default is 6
*/
# define PLL_LOAD_PULSE_PHASE_MASK (0xf << PLL_LOAD_PULSE_PHASE_SHIFT)
# define DISPLAY_RATE_SELECT_FPA1 (1 << 8)
/**
* SDVO multiplier for 945G/GM. Not used on 965.
*
* \sa DPLL_MD_UDI_MULTIPLIER_MASK
*/
# define SDVO_MULTIPLIER_MASK 0x000000ff
# define SDVO_MULTIPLIER_SHIFT_HIRES 4
# define SDVO_MULTIPLIER_SHIFT_VGA 0
/** @defgroup DPLL_MD
* @{
*/
/** Pipe A SDVO/UDI clock multiplier/divider register for G965. */
#define DPLL_A_MD 0x0601c
/** Pipe B SDVO/UDI clock multiplier/divider register for G965. */
#define DPLL_B_MD 0x06020
/**
* UDI pixel divider, controlling how many pixels are stuffed into a packet.
*
* Value is pixels minus 1. Must be set to 1 pixel for SDVO.
*/
# define DPLL_MD_UDI_DIVIDER_MASK 0x3f000000
# define DPLL_MD_UDI_DIVIDER_SHIFT 24
/** UDI pixel divider for VGA, same as DPLL_MD_UDI_DIVIDER_MASK. */
# define DPLL_MD_VGA_UDI_DIVIDER_MASK 0x003f0000
# define DPLL_MD_VGA_UDI_DIVIDER_SHIFT 16
/**
* SDVO/UDI pixel multiplier.
*
* SDVO requires that the bus clock rate be between 1 and 2 Ghz, and the bus
* clock rate is 10 times the DPLL clock. At low resolution/refresh rate
* modes, the bus rate would be below the limits, so SDVO allows for stuffing
* dummy bytes in the datastream at an increased clock rate, with both sides of
* the link knowing how many bytes are fill.
*
* So, for a mode with a dotclock of 65Mhz, we would want to double the clock
* rate to 130Mhz to get a bus rate of 1.30Ghz. The DPLL clock rate would be
* set to 130Mhz, and the SDVO multiplier set to 2x in this register and
* through an SDVO command.
*
* This register field has values of multiplication factor minus 1, with
* a maximum multiplier of 5 for SDVO.
*/
# define DPLL_MD_UDI_MULTIPLIER_MASK 0x00003f00
# define DPLL_MD_UDI_MULTIPLIER_SHIFT 8
/** SDVO/UDI pixel multiplier for VGA, same as DPLL_MD_UDI_MULTIPLIER_MASK.
* This best be set to the default value (3) or the CRT won't work. No,
* I don't entirely understand what this does...
*/
# define DPLL_MD_VGA_UDI_MULTIPLIER_MASK 0x0000003f
# define DPLL_MD_VGA_UDI_MULTIPLIER_SHIFT 0
/** @} */
#define DPLL_TEST 0x606c
#define D_STATE 0x6104
#define DSPCLK_GATE_D 0x6200
#define RENCLK_GATE_D1 0x6204
#define RENCLK_GATE_D2 0x6208
#define RAMCLK_GATE_D 0x6210 /* CRL only */
#define BLC_PWM_CTL 0x61254
#define BACKLIGHT_MODULATION_FREQ_SHIFT (17)
#define BACKLIGHT_MODULATION_FREQ_MASK (0x7fff << 17)
#define BLM_LEGACY_MODE (1 << 16)
#define BACKLIGHT_DUTY_CYCLE_SHIFT (0)
#define BACKLIGHT_DUTY_CYCLE_MASK (0xffff)
#define BLM_CTL 0x61260
#define BLM_THRESHOLD_0 0x61270
#define BLM_THRESHOLD_1 0x61274
#define BLM_THRESHOLD_2 0x61278
#define BLM_THRESHOLD_3 0x6127c
#define BLM_THRESHOLD_4 0x61280
#define BLM_THRESHOLD_5 0x61284
#define BLM_ACCUMULATOR_0 0x61290
#define BLM_ACCUMULATOR_1 0x61294
#define BLM_ACCUMULATOR_2 0x61298
#define BLM_ACCUMULATOR_3 0x6129c
#define BLM_ACCUMULATOR_4 0x612a0
#define BLM_ACCUMULATOR_5 0x612a4
#define FPA0 0x06040
#define FPA1 0x06044
#define FPB0 0x06048
#define FPB1 0x0604c
# define FP_N_DIV_MASK 0x003f0000
# define FP_M1_DIV_MASK 0x00003f00
# define FP_M2_DIV_MASK 0x0000003f
#define PORT_HOTPLUG_EN 0x61110
# define SDVOB_HOTPLUG_INT_EN (1 << 26)
# define SDVOC_HOTPLUG_INT_EN (1 << 25)
# define TV_HOTPLUG_INT_EN (1 << 18)
# define CRT_HOTPLUG_INT_EN (1 << 9)
# define CRT_HOTPLUG_FORCE_DETECT (1 << 3)
#define PORT_HOTPLUG_STAT 0x61114
# define CRT_HOTPLUG_INT_STATUS (1 << 11)
# define TV_HOTPLUG_INT_STATUS (1 << 10)
# define CRT_HOTPLUG_MONITOR_MASK (3 << 8)
# define CRT_HOTPLUG_MONITOR_COLOR (3 << 8)
# define CRT_HOTPLUG_MONITOR_MONO (2 << 8)
# define CRT_HOTPLUG_MONITOR_NONE (0 << 8)
# define SDVOC_HOTPLUG_INT_STATUS (1 << 7)
# define SDVOB_HOTPLUG_INT_STATUS (1 << 6)
#define SDVOB 0x61140
#define SDVOC 0x61160
#define SDVO_ENABLE (1 << 31)
#define SDVO_PIPE_B_SELECT (1 << 30)
#define SDVO_STALL_SELECT (1 << 29)
#define SDVO_INTERRUPT_ENABLE (1 << 26)
/**
* 915G/GM SDVO pixel multiplier.
*
* Programmed value is multiplier - 1, up to 5x.
*
* \sa DPLL_MD_UDI_MULTIPLIER_MASK
*/
#define SDVO_PORT_MULTIPLY_MASK (7 << 23)
#define SDVO_PORT_MULTIPLY_SHIFT 23
#define SDVO_PHASE_SELECT_MASK (15 << 19)
#define SDVO_PHASE_SELECT_DEFAULT (6 << 19)
#define SDVO_CLOCK_OUTPUT_INVERT (1 << 18)
#define SDVOC_GANG_MODE (1 << 16)
#define SDVO_BORDER_ENABLE (1 << 7)
#define SDVOB_PCIE_CONCURRENCY (1 << 3)
#define SDVO_DETECTED (1 << 2)
/* Bits to be preserved when writing */
#define SDVOB_PRESERVE_MASK ((1 << 17) | (1 << 16) | (1 << 14))
#define SDVOC_PRESERVE_MASK (1 << 17)
#define UDIB_SVB_SHB_CODES 0x61144
#define UDIB_SHA_BLANK_CODES 0x61148
#define UDIB_START_END_FILL_CODES 0x6114c
#define SDVOUDI 0x61150
#define I830_HTOTAL_MASK 0xfff0000
#define I830_HACTIVE_MASK 0x7ff
@ -770,13 +994,599 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#define DVOA 0x61120
#define DVOB 0x61140
#define DVOC 0x61160
#define DVO_ENABLE (1<<31)
#define DVO_ENABLE (1 << 31)
#define DVO_PIPE_B_SELECT (1 << 30)
#define DVO_PIPE_STALL_UNUSED (0 << 28)
#define DVO_PIPE_STALL (1 << 28)
#define DVO_PIPE_STALL_TV (2 << 28)
#define DVO_USE_VGA_SYNC (1 << 15)
#define DVO_DATA_ORDER_I740 (0 << 14)
#define DVO_DATA_ORDER_FP (1 << 14)
#define DVO_VSYNC_DISABLE (1 << 11)
#define DVO_HSYNC_DISABLE (1 << 10)
#define DVO_VSYNC_TRISTATE (1 << 9)
#define DVO_HSYNC_TRISTATE (1 << 8)
#define DVO_BORDER_ENABLE (1 << 7)
#define DVO_DATA_ORDER_GBRG (1 << 6)
#define DVO_DATA_ORDER_RGGB (0 << 6)
#define DVO_DATA_ORDER_GBRG_ERRATA (0 << 6)
#define DVO_DATA_ORDER_RGGB_ERRATA (1 << 6)
#define DVO_VSYNC_ACTIVE_HIGH (1 << 4)
#define DVO_HSYNC_ACTIVE_HIGH (1 << 3)
#define DVO_BLANK_ACTIVE_HIGH (1 << 2)
#define DVO_OUTPUT_CSTATE_PIXELS (1 << 1) /* SDG only */
#define DVO_OUTPUT_SOURCE_SIZE_PIXELS (1 << 0) /* SDG only */
#define DVO_PRESERVE_MASK (0x7<<24)
#define DVOA_SRCDIM 0x61124
#define DVOB_SRCDIM 0x61144
#define DVOC_SRCDIM 0x61164
#define DVO_SRCDIM_HORIZONTAL_SHIFT 12
#define DVO_SRCDIM_VERTICAL_SHIFT 0
#define LVDS 0x61180
# define LVDS_PORT_EN (1 << 31)
# define LVDS_PIPEB_SELECT (1 << 30)
# define LVDS_CLKA_POWER_DOWN (0 << 8)
# define LVDS_CLKA_POWER_UP (3 << 8)
/** @defgroup TV_CTL
* @{
*/
#define TV_CTL 0x68000
/** Enables the TV encoder */
# define TV_ENC_ENABLE (1 << 31)
/** Sources the TV encoder input from pipe B instead of A. */
# define TV_ENC_PIPEB_SELECT (1 << 30)
/** Outputs composite video (DAC A only) */
# define TV_ENC_OUTPUT_COMPOSITE (0 << 28)
/** Outputs SVideo video (DAC B/C) */
# define TV_ENC_OUTPUT_SVIDEO (1 << 28)
/** Outputs Component video (DAC A/B/C) */
# define TV_ENC_OUTPUT_COMPONENT (2 << 28)
# define TV_TRILEVEL_SYNC (1 << 21)
/** Enables slow sync generation (945GM only) */
# define TV_SLOW_SYNC (1 << 20)
/** Selects 4x oversampling for 480i and 576p */
# define TV_OVERSAMPLE_4X (0 << 18)
/** Selects 2x oversampling for 720p and 1080i */
# define TV_OVERSAMPLE_2X (1 << 18)
/** Selects no oversampling for 1080p */
# define TV_OVERSAMPLE_NONE (2 << 18)
/** Selects 8x oversampling */
# define TV_OVERSAMPLE_8X (3 << 18)
/** Selects progressive mode rather than interlaced */
# define TV_PROGRESSIVE (1 << 17)
/** Sets the colorburst to PAL mode. Required for non-M PAL modes. */
# define TV_PAL_BURST (1 << 16)
/** Field for setting delay of Y compared to C */
# define TV_YC_SKEW_MASK (7 << 12)
/** Enables a fix for 480p/576p standard definition modes on the 915GM only */
# define TV_ENC_SDP_FIX (1 << 11)
/**
* Enables a fix for the 915GM only.
*
* Not sure what it does.
*/
# define TV_ENC_C0_FIX (1 << 10)
/** Bits that must be preserved by software */
# define TV_CTL_SAVE ((3 << 8) | (3 << 6))
# define TV_FUSE_STATE_MASK (3 << 4)
/** Read-only state that reports all features enabled */
# define TV_FUSE_STATE_ENABLED (0 << 4)
/** Read-only state that reports that Macrovision is disabled in hardware*/
# define TV_FUSE_STATE_NO_MACROVISION (1 << 4)
/** Read-only state that reports that TV-out is disabled in hardware. */
# define TV_FUSE_STATE_DISABLED (2 << 4)
/**
* This test mode forces the DACs to 50% of full output.
*
* This is used for load detection in combination with TVDAC_SENSE_MASK
*/
# define TV_TEST_MODE_MONITOR_DETECT (7 << 0)
/** @} */
/** @defgroup TV_DAC
* @{
*/
#define TV_DAC 0x68004
/**
* Reports that DAC state change logic has reported change (RO).
*
* This gets cleared when TV_DAC_STATE_EN is cleared
*/
# define TVDAC_STATE_CHG (1 << 31)
# define TVDAC_SENSE_MASK (7 << 28)
/** Reports that DAC A voltage is above the detect threshold */
# define TVDAC_A_SENSE (1 << 30)
/** Reports that DAC B voltage is above the detect threshold */
# define TVDAC_B_SENSE (1 << 29)
/** Reports that DAC C voltage is above the detect threshold */
# define TVDAC_C_SENSE (1 << 28)
/**
* Enables DAC state detection logic, for load-based TV detection.
*
* The PLL of the chosen pipe (in TV_CTL) must be running, and the encoder set
* to off, for load detection to work.
*/
# define TVDAC_STATE_CHG_EN (1 << 27)
/** Sets the DAC A sense value to high */
# define TVDAC_A_SENSE_CTL (1 << 26)
/** Sets the DAC B sense value to high */
# define TVDAC_B_SENSE_CTL (1 << 25)
/** Sets the DAC C sense value to high */
# define TVDAC_C_SENSE_CTL (1 << 24)
/** Overrides the ENC_ENABLE and DAC voltage levels */
# define DAC_CTL_OVERRIDE (1 << 7)
/** Sets the slew rate. Must be preserved in software */
# define ENC_TVDAC_SLEW_FAST (1 << 6)
# define DAC_A_1_3_V (0 << 4)
# define DAC_A_1_1_V (1 << 4)
# define DAC_A_0_7_V (2 << 4)
# define DAC_A_OFF (3 << 4)
# define DAC_B_1_3_V (0 << 2)
# define DAC_B_1_1_V (1 << 2)
# define DAC_B_0_7_V (2 << 2)
# define DAC_B_OFF (3 << 2)
# define DAC_C_1_3_V (0 << 0)
# define DAC_C_1_1_V (1 << 0)
# define DAC_C_0_7_V (2 << 0)
# define DAC_C_OFF (3 << 0)
/** @} */
/**
* CSC coefficients are stored in a floating point format with 9 bits of
* mantissa and 2 or 3 bits of exponent. The exponent is represented as 2**-n,
* where 2-bit exponents are unsigned n, and 3-bit exponents are signed n with
* -1 (0x3) being the only legal negative value.
*/
#define TV_CSC_Y 0x68010
# define TV_RY_MASK 0x07ff0000
# define TV_RY_SHIFT 16
# define TV_GY_MASK 0x00000fff
# define TV_GY_SHIFT 0
#define TV_CSC_Y2 0x68014
# define TV_BY_MASK 0x07ff0000
# define TV_BY_SHIFT 16
/**
* Y attenuation for component video.
*
* Stored in 1.9 fixed point.
*/
# define TV_AY_MASK 0x000003ff
# define TV_AY_SHIFT 0
#define TV_CSC_U 0x68018
# define TV_RU_MASK 0x07ff0000
# define TV_RU_SHIFT 16
# define TV_GU_MASK 0x000007ff
# define TV_GU_SHIFT 0
#define TV_CSC_U2 0x6801c
# define TV_BU_MASK 0x07ff0000
# define TV_BU_SHIFT 16
/**
* U attenuation for component video.
*
* Stored in 1.9 fixed point.
*/
# define TV_AU_MASK 0x000003ff
# define TV_AU_SHIFT 0
#define TV_CSC_V 0x68020
# define TV_RV_MASK 0x0fff0000
# define TV_RV_SHIFT 16
# define TV_GV_MASK 0x000007ff
# define TV_GV_SHIFT 0
#define TV_CSC_V2 0x68024
# define TV_BV_MASK 0x07ff0000
# define TV_BV_SHIFT 16
/**
* V attenuation for component video.
*
* Stored in 1.9 fixed point.
*/
# define TV_AV_MASK 0x000007ff
# define TV_AV_SHIFT 0
/** @defgroup TV_CSC_KNOBS
* @{
*/
#define TV_CLR_KNOBS 0x68028
/** 2s-complement brightness adjustment */
# define TV_BRIGHTNESS_MASK 0xff000000
# define TV_BRIGHTNESS_SHIFT 24
/** Contrast adjustment, as a 2.6 unsigned floating point number */
# define TV_CONTRAST_MASK 0x00ff0000
# define TV_CONTRAST_SHIFT 16
/** Saturation adjustment, as a 2.6 unsigned floating point number */
# define TV_SATURATION_MASK 0x0000ff00
# define TV_SATURATION_SHIFT 8
/** Hue adjustment, as an integer phase angle in degrees */
# define TV_HUE_MASK 0x000000ff
# define TV_HUE_SHIFT 0
/** @} */
/** @defgroup TV_CLR_LEVEL
* @{
*/
#define TV_CLR_LEVEL 0x6802c
/** Controls the DAC level for black */
# define TV_BLACK_LEVEL_MASK 0x01ff0000
# define TV_BLACK_LEVEL_SHIFT 16
/** Controls the DAC level for blanking */
# define TV_BLANK_LEVEL_MASK 0x000001ff
# define TV_BLANK_LEVEL_SHIFT 0
/* @} */
/** @defgroup TV_H_CTL_1
* @{
*/
#define TV_H_CTL_1 0x68030
/** Number of pixels in the hsync. */
# define TV_HSYNC_END_MASK 0x1fff0000
# define TV_HSYNC_END_SHIFT 16
/** Total number of pixels minus one in the line (display and blanking). */
# define TV_HTOTAL_MASK 0x00001fff
# define TV_HTOTAL_SHIFT 0
/** @} */
/** @defgroup TV_H_CTL_2
* @{
*/
#define TV_H_CTL_2 0x68034
/** Enables the colorburst (needed for non-component color) */
# define TV_BURST_ENA (1 << 31)
/** Offset of the colorburst from the start of hsync, in pixels minus one. */
# define TV_HBURST_START_SHIFT 16
# define TV_HBURST_START_MASK 0x1fff0000
/** Length of the colorburst */
# define TV_HBURST_LEN_SHIFT 0
# define TV_HBURST_LEN_MASK 0x0001fff
/** @} */
/** @defgroup TV_H_CTL_3
* @{
*/
#define TV_H_CTL_3 0x68038
/** End of hblank, measured in pixels minus one from start of hsync */
# define TV_HBLANK_END_SHIFT 16
# define TV_HBLANK_END_MASK 0x1fff0000
/** Start of hblank, measured in pixels minus one from start of hsync */
# define TV_HBLANK_START_SHIFT 0
# define TV_HBLANK_START_MASK 0x0001fff
/** @} */
/** @defgroup TV_V_CTL_1
* @{
*/
#define TV_V_CTL_1 0x6803c
/** XXX */
# define TV_NBR_END_SHIFT 16
# define TV_NBR_END_MASK 0x07ff0000
/** XXX */
# define TV_VI_END_F1_SHIFT 8
# define TV_VI_END_F1_MASK 0x00003f00
/** XXX */
# define TV_VI_END_F2_SHIFT 0
# define TV_VI_END_F2_MASK 0x0000003f
/** @} */
/** @defgroup TV_V_CTL_2
* @{
*/
#define TV_V_CTL_2 0x68040
/** Length of vsync, in half lines */
# define TV_VSYNC_LEN_MASK 0x07ff0000
# define TV_VSYNC_LEN_SHIFT 16
/** Offset of the start of vsync in field 1, measured in one less than the
* number of half lines.
*/
# define TV_VSYNC_START_F1_MASK 0x00007f00
# define TV_VSYNC_START_F1_SHIFT 8
/**
* Offset of the start of vsync in field 2, measured in one less than the
* number of half lines.
*/
# define TV_VSYNC_START_F2_MASK 0x0000007f
# define TV_VSYNC_START_F2_SHIFT 0
/** @} */
/** @defgroup TV_V_CTL_3
* @{
*/
#define TV_V_CTL_3 0x68044
/** Enables generation of the equalization signal */
# define TV_EQUAL_ENA (1 << 31)
/** Length of vsync, in half lines */
# define TV_VEQ_LEN_MASK 0x007f0000
# define TV_VEQ_LEN_SHIFT 16
/** Offset of the start of equalization in field 1, measured in one less than
* the number of half lines.
*/
# define TV_VEQ_START_F1_MASK 0x0007f00
# define TV_VEQ_START_F1_SHIFT 8
/**
* Offset of the start of equalization in field 2, measured in one less than
* the number of half lines.
*/
# define TV_VEQ_START_F2_MASK 0x000007f
# define TV_VEQ_START_F2_SHIFT 0
/** @} */
/** @defgroup TV_V_CTL_4
* @{
*/
#define TV_V_CTL_4 0x68048
/**
* Offset to start of vertical colorburst, measured in one less than the
* number of lines from vertical start.
*/
# define TV_VBURST_START_F1_MASK 0x003f0000
# define TV_VBURST_START_F1_SHIFT 16
/**
* Offset to the end of vertical colorburst, measured in one less than the
* number of lines from the start of NBR.
*/
# define TV_VBURST_END_F1_MASK 0x000000ff
# define TV_VBURST_END_F1_SHIFT 0
/** @} */
/** @defgroup TV_V_CTL_5
* @{
*/
#define TV_V_CTL_5 0x6804c
/**
* Offset to start of vertical colorburst, measured in one less than the
* number of lines from vertical start.
*/
# define TV_VBURST_START_F2_MASK 0x003f0000
# define TV_VBURST_START_F2_SHIFT 16
/**
* Offset to the end of vertical colorburst, measured in one less than the
* number of lines from the start of NBR.
*/
# define TV_VBURST_END_F2_MASK 0x000000ff
# define TV_VBURST_END_F2_SHIFT 0
/** @} */
/** @defgroup TV_V_CTL_6
* @{
*/
#define TV_V_CTL_6 0x68050
/**
* Offset to start of vertical colorburst, measured in one less than the
* number of lines from vertical start.
*/
# define TV_VBURST_START_F3_MASK 0x003f0000
# define TV_VBURST_START_F3_SHIFT 16
/**
* Offset to the end of vertical colorburst, measured in one less than the
* number of lines from the start of NBR.
*/
# define TV_VBURST_END_F3_MASK 0x000000ff
# define TV_VBURST_END_F3_SHIFT 0
/** @} */
/** @defgroup TV_V_CTL_7
* @{
*/
#define TV_V_CTL_7 0x68054
/**
* Offset to start of vertical colorburst, measured in one less than the
* number of lines from vertical start.
*/
# define TV_VBURST_START_F4_MASK 0x003f0000
# define TV_VBURST_START_F4_SHIFT 16
/**
* Offset to the end of vertical colorburst, measured in one less than the
* number of lines from the start of NBR.
*/
# define TV_VBURST_END_F4_MASK 0x000000ff
# define TV_VBURST_END_F4_SHIFT 0
/** @} */
/** @defgroup TV_SC_CTL_1
* @{
*/
#define TV_SC_CTL_1 0x68060
/** Turns on the first subcarrier phase generation DDA */
# define TV_SC_DDA1_EN (1 << 31)
/** Turns on the first subcarrier phase generation DDA */
# define TV_SC_DDA2_EN (2 << 31)
/** Turns on the first subcarrier phase generation DDA */
# define TV_SC_DDA3_EN (3 << 31)
/** Sets the subcarrier DDA to reset frequency every other field */
# define TV_SC_RESET_EVERY_2 (0 << 24)
/** Sets the subcarrier DDA to reset frequency every fourth field */
# define TV_SC_RESET_EVERY_4 (1 << 24)
/** Sets the subcarrier DDA to reset frequency every eighth field */
# define TV_SC_RESET_EVERY_8 (2 << 24)
/** Sets the subcarrier DDA to never reset the frequency */
# define TV_SC_RESET_NEVER (3 << 24)
/** Sets the peak amplitude of the colorburst.*/
# define TV_BURST_LEVEL_MASK 0x00ff0000
# define TV_BURST_LEVEL_SHIFT 16
/** Sets the increment of the first subcarrier phase generation DDA */
# define TV_SCDDA1_INC_MASK 0x00000fff
# define TV_SCDDA1_INC_SHIFT 0
/** @} */
/** @defgroup TV_SC_CTL_2
* @{
*/
#define TV_SC_CTL_2 0x68068
/** Sets the rollover for the second subcarrier phase generation DDA */
# define TV_SCDDA2_SIZE_MASK 0x7fff0000
# define TV_SCDDA2_SIZE_SHIFT 16
/** Sets the increent of the second subcarrier phase generation DDA */
# define TV_SCDDA2_INC_MASK 0x00007fff
# define TV_SCDDA2_INC_SHIFT 0
/** @} */
/** @defgroup TV_SC_CTL_3
* @{
*/
#define TV_SC_CTL_3 0x68068
/** Sets the rollover for the third subcarrier phase generation DDA */
# define TV_SCDDA3_SIZE_MASK 0x7fff0000
# define TV_SCDDA3_SIZE_SHIFT 16
/** Sets the increent of the third subcarrier phase generation DDA */
# define TV_SCDDA3_INC_MASK 0x00007fff
# define TV_SCDDA3_INC_SHIFT 0
/** @} */
/** @defgroup TV_WIN_POS
* @{
*/
#define TV_WIN_POS 0x68070
/** X coordinate of the display from the start of horizontal active */
# define TV_XPOS_MASK 0x1fff0000
# define TV_XPOS_SHIFT 16
/** Y coordinate of the display from the start of vertical active (NBR) */
# define TV_YPOS_MASK 0x00000fff
# define TV_YPOS_SHIFT 0
/** @} */
/** @defgroup TV_WIN_SIZE
* @{
*/
#define TV_WIN_SIZE 0x68074
/** Horizontal size of the display window, measured in pixels*/
# define TV_XSIZE_MASK 0x1fff0000
# define TV_XSIZE_SHIFT 16
/**
* Vertical size of the display window, measured in pixels.
*
* Must be even for interlaced modes.
*/
# define TV_YSIZE_MASK 0x00000fff
# define TV_YSIZE_SHIFT 0
/** @} */
/** @defgroup TV_FILTER_CTL_1
* @{
*/
#define TV_FILTER_CTL_1 0x68080
/**
* Enables automatic scaling calculation.
*
* If set, the rest of the registers are ignored, and the calculated values can
* be read back from the register.
*/
# define TV_AUTO_SCALE (1 << 31)
/**
* Disables the vertical filter.
*
* This is required on modes more than 1024 pixels wide */
# define TV_V_FILTER_BYPASS (1 << 29)
/** Enables adaptive vertical filtering */
# define TV_VADAPT (1 << 28)
# define TV_VADAPT_MODE_MASK (3 << 26)
/** Selects the least adaptive vertical filtering mode */
# define TV_VADAPT_MODE_LEAST (0 << 26)
/** Selects the moderately adaptive vertical filtering mode */
# define TV_VADAPT_MODE_MODERATE (1 << 26)
/** Selects the most adaptive vertical filtering mode */
# define TV_VADAPT_MODE_MOST (3 << 26)
/**
* Sets the horizontal scaling factor.
*
* This should be the fractional part of the horizontal scaling factor divided
* by the oversampling rate. TV_HSCALE should be less than 1, and set to:
*
* (src width - 1) / ((oversample * dest width) - 1)
*/
# define TV_HSCALE_FRAC_MASK 0x00003fff
# define TV_HSCALE_FRAC_SHIFT 0
/** @} */
/** @defgroup TV_FILTER_CTL_2
* @{
*/
#define TV_FILTER_CTL_2 0x68084
/**
* Sets the integer part of the 3.15 fixed-point vertical scaling factor.
*
* TV_VSCALE should be (src height - 1) / ((interlace * dest height) - 1)
*/
# define TV_VSCALE_INT_MASK 0x00038000
# define TV_VSCALE_INT_SHIFT 15
/**
* Sets the fractional part of the 3.15 fixed-point vertical scaling factor.
*
* \sa TV_VSCALE_INT_MASK
*/
# define TV_VSCALE_FRAC_MASK 0x00007fff
# define TV_VSCALE_FRAC_SHIFT 0
/** @} */
/** @defgroup TV_FILTER_CTL_3
* @{
*/
#define TV_FILTER_CTL_3 0x68088
/**
* Sets the integer part of the 3.15 fixed-point vertical scaling factor.
*
* TV_VSCALE should be (src height - 1) / (1/4 * (dest height - 1))
*
* For progressive modes, TV_VSCALE_IP_INT should be set to zeroes.
*/
# define TV_VSCALE_IP_INT_MASK 0x00038000
# define TV_VSCALE_IP_INT_SHIFT 15
/**
* Sets the fractional part of the 3.15 fixed-point vertical scaling factor.
*
* For progressive modes, TV_VSCALE_IP_INT should be set to zeroes.
*
* \sa TV_VSCALE_IP_INT_MASK
*/
# define TV_VSCALE_IP_FRAC_MASK 0x00007fff
# define TV_VSCALE_IP_FRAC_SHIFT 0
/** @} */
/** @defgroup TV_CC_CONTROL
* @{
*/
#define TV_CC_CONTROL 0x68090
# define TV_CC_ENABLE (1 << 31)
/**
* Specifies which field to send the CC data in.
*
* CC data is usually sent in field 0.
*/
# define TV_CC_FID_MASK (1 << 27)
# define TV_CC_FID_SHIFT 27
/** Sets the horizontal position of the CC data. Usually 135. */
# define TV_CC_HOFF_MASK 0x03ff0000
# define TV_CC_HOFF_SHIFT 16
/** Sets the vertical position of the CC data. Usually 21 */
# define TV_CC_LINE_MASK 0x0000003f
# define TV_CC_LINE_SHIFT 0
/** @} */
/** @defgroup TV_CC_DATA
* @{
*/
#define TV_CC_DATA 0x68094
# define TV_CC_RDY (1 << 31)
/** Second word of CC data to be transmitted. */
# define TV_CC_DATA_2_MASK 0x007f0000
# define TV_CC_DATA_2_SHIFT 16
/** First word of CC data to be transmitted. */
# define TV_CC_DATA_1_MASK 0x0000007f
# define TV_CC_DATA_1_SHIFT 0
/** @}
*/
/** @{ */
#define TV_H_LUMA_0 0x68100
#define TV_H_LUMA_59 0x681ec
#define TV_H_CHROMA_0 0x68200
#define TV_H_CHROMA_59 0x682ec
/** @} */
#define PIPEACONF 0x70008
#define PIPEACONF_ENABLE (1<<31)
@ -787,6 +1597,20 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#define PIPEACONF_PIPE_LOCKED (1<<25)
#define PIPEACONF_PALETTE 0
#define PIPEACONF_GAMMA (1<<24)
#define PIPECONF_FORCE_BORDER (1<<25)
#define PIPEAGCMAXRED 0x70010
#define PIPEAGCMAXGREEN 0x70014
#define PIPEAGCMAXBLUE 0x70018
#define PIPEASTAT 0x70024
#define DSPARB 0x70030
#define DSPFW1 0x70034
#define DSPFW2 0x70038
#define DSPFW3 0x7003c
#define PIPEAFRAMEHIGH 0x70040
#define PIPEAFRAMEPIXEL 0x70044
#define PIPEBCONF 0x71008
#define PIPEBCONF_ENABLE (1<<31)
@ -796,6 +1620,13 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#define PIPEBCONF_GAMMA (1<<24)
#define PIPEBCONF_PALETTE 0
#define PIPEBGCMAXRED 0x71010
#define PIPEBGCMAXGREEN 0x71014
#define PIPEBGCMAXBLUE 0x71018
#define PIPEBSTAT 0x71024
#define PIPEBFRAMEHIGH 0x71040
#define PIPEBFRAMEPIXEL 0x71044
#define DSPACNTR 0x70180
#define DSPBCNTR 0x71180
#define DISPLAY_PLANE_ENABLE (1<<31)
@ -832,6 +1663,9 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#define DSPBADDR DSPBBASE
#define DSPBSTRIDE 0x71188
#define DSPAKEYVAL 0x70194
#define DSPAKEYMASK 0x70198
#define DSPAPOS 0x7018C /* reserved */
#define DSPASIZE 0x70190
#define DSPBPOS 0x7118C
@ -843,6 +1677,11 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#define DSPBSURF 0x7119C
#define DSPBTILEOFF 0x711A4
#define VGACNTRL 0x71400
# define VGA_DISP_DISABLE (1 << 31)
# define VGA_2X_MODE (1 << 30)
# define VGA_PIPE_B_SELECT (1 << 29)
/* Various masks for reserved bits, etc. */
#define I830_FWATER1_MASK (~((1<<11)|(1<<10)|(1<<9)| \
(1<<8)|(1<<26)|(1<<25)|(1<<24)|(1<<5)|(1<<4)|(1<<3)| \

View File

@ -57,7 +57,6 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include "xf86xv.h"
#include "xf86int10.h"
#include "vbe.h"
#include "vbeModes.h"
#include "vgaHW.h"
#include "randrstr.h"
@ -70,43 +69,23 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include "i830_dri.h"
#endif
#include "common.h"
typedef struct _I830OutputRec I830OutputRec, *I830OutputPtr;
#include "common.h"
#include "i830_sdvo.h"
#include "i2c_vid.h"
/* I830 Video support */
#define NEED_REPLIES /* ? */
#define EXTENSION_PROC_ARGS void *
#include "extnsionst.h" /* required */
#include <X11/extensions/panoramiXproto.h> /* required */
/* I830 Video BIOS support */
/*
* The mode handling is based upon the VESA driver written by
* Paulo César Pereira de Andrade <pcpa@conectiva.com.br>.
*/
#define PIPE_NONE 0<<0
#define PIPE_CRT 1<<0
#define PIPE_TV 1<<1
#define PIPE_DFP 1<<2
#define PIPE_LFP 1<<3
#define PIPE_CRT2 1<<4
#define PIPE_TV2 1<<5
#define PIPE_DFP2 1<<6
#define PIPE_LFP2 1<<7
typedef struct _VESARec {
/* SVGA state */
pointer state, pstate;
int statePage, stateSize, stateMode, stateRefresh;
CARD32 *savedPal;
int savedScanlinePitch;
/* Don't try to set the refresh rate for any modes. */
Bool useDefaultRefresh;
/* display start */
int x, y;
} VESARec, *VESAPtr;
#ifdef XF86DRI
#define I830_MM_MINPAGES 512
#define I830_MM_MAXSIZE (32*1024)
@ -168,43 +147,165 @@ typedef struct {
#endif
} I830EntRec, *I830EntPtr;
typedef struct _MergedDisplayModeRec {
DisplayModePtr First;
DisplayModePtr Second;
int SecondPosition;
} I830MergedDisplayModeRec, *I830MergedDisplayModePtr;
/* 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
typedef struct _I830XineramaData {
int x;
int y;
int width;
int height;
} I830XineramaData;
#define I830_I2C_BUS_DVO 1
#define I830_I2C_BUS_SDVO 2
typedef struct _ModePrivateRec {
I830MergedDisplayModeRec merged;
VbeModeInfoData vbeData;
} I830ModePrivateRec, *I830ModePrivatePtr;
/* these are outputs from the chip - integrated only
external chips are via DVO or SDVO output */
#define I830_OUTPUT_UNUSED 0
#define I830_OUTPUT_ANALOG 1
#define I830_OUTPUT_DVO 2
#define I830_OUTPUT_SDVO 3
#define I830_OUTPUT_LVDS 4
#define I830_OUTPUT_TVOUT 5
typedef struct _region {
int x0,x1,y0,y1;
} region;
#define I830_DVO_CHIP_NONE 0
#define I830_DVO_CHIP_LVDS 1
#define I830_DVO_CHIP_TMDS 2
#define I830_DVO_CHIP_TVOUT 4
struct _I830DVODriver {
int type;
char *modulename;
char *fntablename;
int address;
const char **symbols;
I830I2CVidOutputRec *vid_rec;
void *dev_priv;
pointer modhandle;
};
extern const char *i830_output_type_names[];
enum detect_status {
OUTPUT_STATUS_CONNECTED,
OUTPUT_STATUS_DISCONNECTED,
OUTPUT_STATUS_UNKNOWN
};
struct _I830OutputRec {
int type;
int pipe;
Bool enabled;
/**
* Marks that the output and associated pipe is temporarily enabled for
* load detection.
*/
Bool load_detect_temp;
/**
* Turns the output on/off, or sets intermediate power levels if available.
*
* Unsupported intermediate modes drop to the lower power setting. If the
* mode is DPMSModeOff, the output must be disabled, as the DPLL may be
* disabled afterwards.
*/
void (*dpms)(ScrnInfoPtr pScrn, I830OutputPtr output, int mode);
/**
* Saves the output's state for restoration on VT switch.
*/
void (*save)(ScrnInfoPtr pScrn, I830OutputPtr output);
/**
* Restore's the output's state at VT switch.
*/
void (*restore)(ScrnInfoPtr pScrn, I830OutputPtr output);
/**
* Callback for testing a video mode for a given output.
*
* This function should only check for cases where a mode can't be supported
* on the pipe specifically, and not represent generic CRTC limitations.
*
* \return MODE_OK if the mode is valid, or another MODE_* otherwise.
*/
int (*mode_valid)(ScrnInfoPtr pScrn, I830OutputPtr output,
DisplayModePtr pMode);
/**
* Callback for setting up a video mode before any pipe/dpll changes.
*
* \param pMode the mode that will be set, or NULL if the mode to be set is
* unknown (such as the restore path of VT switching).
*/
void (*pre_set_mode)(ScrnInfoPtr pScrn, I830OutputPtr output,
DisplayModePtr pMode);
/**
* Callback for setting up a video mode after the DPLL update but before
* the plane is enabled.
*/
void (*post_set_mode)(ScrnInfoPtr pScrn, I830OutputPtr output,
DisplayModePtr pMode);
/**
* Probe for a connected output, and return detect_status.
*/
enum detect_status (*detect)(ScrnInfoPtr pScrn, I830OutputPtr output);
/**
* Query the device for the modes it provides.
*
* This function may also update MonInfo, mm_width, and mm_height.
*
* \return singly-linked list of modes or NULL if no modes found.
*/
DisplayModePtr (*get_modes)(ScrnInfoPtr pScrn, I830OutputPtr output);
/**
* List of available modes on this output.
*
* This should be the list from get_modes(), plus perhaps additional
* compatible modes added later.
*/
DisplayModePtr probed_modes;
/** EDID monitor information */
xf86MonPtr MonInfo;
/** Physical size of the output currently attached. */
int mm_width, mm_height;
I2CBusPtr pI2CBus;
I2CBusPtr pDDCBus;
struct _I830DVODriver *i2c_drv;
/** Output-private structure. Should replace i2c_drv */
void *dev_priv;
#ifdef RANDR_12_INTERFACE
RROutputPtr randr_output;
#endif
};
typedef struct _I830PipeRec {
Bool enabled;
Bool gammaEnabled;
int x;
int y;
Bool cursorInRange;
Bool cursorShown;
DisplayModeRec curMode;
DisplayModeRec desiredMode;
#ifdef RANDR_12_INTERFACE
RRCrtcPtr randr_crtc;
#endif
} I830PipeRec, *I830PipePtr;
typedef struct _I830Rec {
unsigned char *MMIOBase;
unsigned char *FbBase;
int cpp;
unsigned int bios_version;
Bool newPipeSwitch;
Bool fakeSwitch;
int fixedPipe;
DisplayModePtr currentMode;
/* Mode saved during randr reprobe, which will need to be freed at the point
* of the next SwitchMode, when we lose this last reference to it.
*/
DisplayModePtr savedCurrentMode;
Bool Clone;
int CloneRefresh;
@ -212,7 +313,9 @@ typedef struct _I830Rec {
int CloneVDisplay;
I830EntPtr entityPrivate;
#if 0
int pipe, origPipe;
#endif
int init;
unsigned int bufferOffset; /* for I830SelectBuffer */
@ -224,8 +327,6 @@ typedef struct _I830Rec {
long FbMapSize;
long TotalVideoRam;
I830MemRange StolenMemory; /* pre-allocated memory */
long BIOSMemorySize; /* min stolen pool size */
int BIOSMemSizeLoc;
/* These change according to what has been allocated. */
long FreeMemory;
@ -254,26 +355,7 @@ typedef struct _I830Rec {
I830MemRange *OverlayMem;
I830MemRange LinearMem;
#endif
int LinearAlloc;
Bool MergedFB;
ScrnInfoPtr pScrn_2;
char *SecondHSync;
char *SecondVRefresh;
char *MetaModes;
int SecondPosition;
int FirstXOffs, FirstYOffs, SecondXOffs, SecondYOffs;
int FirstframeX0, FirstframeX1, FirstframeY0, FirstframeY1;
int MBXNR1XMAX, MBXNR1YMAX, MBXNR2XMAX, MBXNR2YMAX;
Bool NonRect, HaveNonRect, HaveOffsRegions, MouseRestrictions;
int maxFirst_X1, maxFirst_X2, maxFirst_Y1, maxFirst_Y2;
int maxSecond_X1, maxSecond_X2, maxSecond_Y1, maxSecond_Y2;
region NonRectDead, OffDead1, OffDead2;
Bool IntelXinerama;
Bool SecondIsScrn0;
ExtensionEntry *XineramaExtEntry;
int I830XineramaVX, I830XineramaVY;
unsigned long LinearAlloc;
XF86ModReqInfo shadowReq; /* to test for later libshadow */
I830MemRange RotatedMem;
I830MemRange RotatedMem2;
@ -312,10 +394,6 @@ typedef struct _I830Rec {
Bool CursorIsARGB;
CursorPtr pCurs;
int MonType1;
int MonType2;
Bool specifiedMonitor;
DGAModePtr DGAModes;
int numDGAModes;
Bool DGAactive;
@ -338,7 +416,6 @@ typedef struct _I830Rec {
int NumScanlineColorExpandBuffers;
int nextColorExpandBuf;
I830RegRec SavedReg;
I830RegRec ModeReg;
Bool noAccel;
@ -384,44 +461,17 @@ typedef struct _I830Rec {
/* Stolen memory support */
Bool StolenOnly;
/* Video BIOS support. */
vbeInfoPtr pVbe;
VbeInfoBlock *vbeInfo;
VESAPtr vesa;
Bool overrideBIOSMemSize;
int saveBIOSMemSize;
int newBIOSMemSize;
Bool useSWF1;
int saveSWF1;
Bool swfSaved;
CARD32 saveSWF0;
CARD32 saveSWF4;
/* Use BIOS call 0x5f05 to set the refresh rate. */
Bool useExtendedRefresh;
Bool checkDevices;
int monitorSwitch;
int operatingDevices;
int toggleDevices;
int savedDevices;
int lastDevice0, lastDevice1, lastDevice2;
/* These are indexed by the display types */
Bool displayAttached[NumDisplayTypes];
Bool displayPresent[NumDisplayTypes];
BoxRec displaySize[NumDisplayTypes];
/* [0] is Pipe A, [1] is Pipe B. */
int availablePipes;
int pipeDevices[MAX_DISPLAY_PIPES];
int num_pipes;
/* [0] is display plane A, [1] is display plane B. */
Bool pipeEnabled[MAX_DISPLAY_PIPES];
BoxRec pipeDisplaySize[MAX_DISPLAY_PIPES];
int planeEnabled[MAX_DISPLAY_PIPES];
I830PipeRec pipes[MAX_DISPLAY_PIPES];
/* Driver phase/state information */
Bool preinit;
Bool starting;
@ -434,14 +484,85 @@ typedef struct _I830Rec {
int yoffset;
unsigned int SaveGeneration;
Bool vbeRestoreWorkaround;
Bool displayInfo;
Bool devicePresence;
OsTimerPtr devicesTimer;
CARD32 savedAsurf;
CARD32 savedBsurf;
int ddc2;
int num_outputs;
struct _I830OutputRec output[MAX_OUTPUTS];
/* Panel size pulled from the BIOS */
int PanelXRes, PanelYRes;
/* The BIOS's fixed timings for the LVDS */
int panel_fixed_clock;
int panel_fixed_hactive;
int panel_fixed_hblank;
int panel_fixed_hsyncoff;
int panel_fixed_hsyncwidth;
int panel_fixed_vactive;
int panel_fixed_vblank;
int panel_fixed_vsyncoff;
int panel_fixed_vsyncwidth;
int backlight_duty_cycle; /* restore backlight to this value */
Bool panel_wants_dither;
CARD32 saveDSPACNTR;
CARD32 saveDSPBCNTR;
CARD32 savePIPEACONF;
CARD32 savePIPEBCONF;
CARD32 savePIPEASRC;
CARD32 savePIPEBSRC;
CARD32 saveFPA0;
CARD32 saveFPA1;
CARD32 saveDPLL_A;
CARD32 saveDPLL_A_MD;
CARD32 saveHTOTAL_A;
CARD32 saveHBLANK_A;
CARD32 saveHSYNC_A;
CARD32 saveVTOTAL_A;
CARD32 saveVBLANK_A;
CARD32 saveVSYNC_A;
CARD32 saveDSPASTRIDE;
CARD32 saveDSPASIZE;
CARD32 saveDSPAPOS;
CARD32 saveDSPABASE;
CARD32 saveDSPASURF;
CARD32 saveFPB0;
CARD32 saveFPB1;
CARD32 saveDPLL_B;
CARD32 saveDPLL_B_MD;
CARD32 saveHTOTAL_B;
CARD32 saveHBLANK_B;
CARD32 saveHSYNC_B;
CARD32 saveVTOTAL_B;
CARD32 saveVBLANK_B;
CARD32 saveVSYNC_B;
CARD32 saveDSPBSTRIDE;
CARD32 saveDSPBSIZE;
CARD32 saveDSPBPOS;
CARD32 saveDSPBBASE;
CARD32 saveDSPBSURF;
CARD32 saveVCLK_DIVISOR_VGA0;
CARD32 saveVCLK_DIVISOR_VGA1;
CARD32 saveVCLK_POST_DIV;
CARD32 saveVGACNTRL;
CARD32 saveADPA;
CARD32 saveLVDS;
CARD32 saveDVOA;
CARD32 saveDVOB;
CARD32 saveDVOC;
CARD32 savePP_ON;
CARD32 savePP_OFF;
CARD32 savePP_CONTROL;
CARD32 savePP_CYCLE;
CARD32 savePFIT_CONTROL;
CARD32 savePaletteA[256];
CARD32 savePaletteB[256];
CARD32 saveSWF[17];
CARD32 saveBLC_PWM_CTL;
} I830Rec;
#define I830PTR(p) ((I830Ptr)((p)->driverPrivate))
@ -459,6 +580,7 @@ extern void I830PrintErrorState(ScrnInfoPtr pScrn);
extern void I965PrintErrorState(ScrnInfoPtr pScrn);
extern void I830Sync(ScrnInfoPtr pScrn);
extern void I830InitHWCursor(ScrnInfoPtr pScrn);
extern void I830SetPipeCursor (ScrnInfoPtr pScrn, int pipe, Bool force);
extern Bool I830CursorInit(ScreenPtr pScreen);
extern void IntelEmitInvarientState(ScrnInfoPtr pScrn);
extern void I830EmitInvarientState(ScrnInfoPtr pScrn);
@ -530,25 +652,52 @@ extern void I830ReadAllRegisters(I830Ptr pI830, I830RegPtr i830Reg);
extern void I830ChangeFrontbuffer(ScrnInfoPtr pScrn,int buffer);
extern Bool I830IsPrimary(ScrnInfoPtr pScrn);
extern DisplayModePtr I830GetModePool(ScrnInfoPtr pScrn, vbeInfoPtr pVbe,
VbeInfoBlock *vbe);
extern void I830SetModeParameters(ScrnInfoPtr pScrn, vbeInfoPtr pVbe);
extern void I830UnsetModeParameters(ScrnInfoPtr pScrn, vbeInfoPtr pVbe);
extern void I830PrintModes(ScrnInfoPtr pScrn);
extern int I830GetBestRefresh(ScrnInfoPtr pScrn, int refresh);
extern Bool I830CheckModeSupport(ScrnInfoPtr pScrn, int x, int y, int mode);
extern Bool I830Rotate(ScrnInfoPtr pScrn, DisplayModePtr mode);
extern Bool I830FixOffset(ScrnInfoPtr pScrn, I830MemRange *mem);
extern Bool I830I2CInit(ScrnInfoPtr pScrn, I2CBusPtr *bus_ptr, int i2c_reg,
char *name);
/* i830_display.c */
Bool
i830PipeHasType (ScrnInfoPtr pScrn, int pipe, int type);
/* i830_crt.c */
void i830_crt_init(ScrnInfoPtr pScrn);
/* i830_dvo.c */
void i830_dvo_init(ScrnInfoPtr pScrn);
/* i830_lvds.c */
void i830_lvds_init(ScrnInfoPtr pScrn);
/* i830_memory.c */
Bool I830BindAGPMemory(ScrnInfoPtr pScrn);
Bool I830UnbindAGPMemory(ScrnInfoPtr pScrn);
/* i830_gtf.c */
DisplayModePtr i830GetGTF(int h_pixels, int v_lines, float freq,
int interlaced, int margins);
/* i830_modes.c */
int I830ValidateXF86ModeList(ScrnInfoPtr pScrn, Bool first_time);
void i830_reprobe_output_modes(ScrnInfoPtr pScrn);
void i830_set_xf86_modes_from_outputs(ScrnInfoPtr pScrn);
void i830_set_default_screen_size(ScrnInfoPtr pScrn);
DisplayModePtr i830_ddc_get_modes(ScrnInfoPtr pScrn, I830OutputPtr output);
/* i830_randr.c */
Bool I830RandRCreateScreenResources (ScreenPtr pScreen);
Bool I830RandRInit(ScreenPtr pScreen, int rotation);
Bool I830RandRSetConfig(ScreenPtr pScreen, Rotation rotation, int rate,
RRScreenSizePtr pSize);
Rotation I830GetRotation(ScreenPtr pScreen);
void I830GetOriginalVirtualSize(ScrnInfoPtr pScrn, int *x, int *y);
Bool I830RandRPreInit (ScrnInfoPtr pScrn);
/* i830_tv.c */
void i830_tv_init(ScrnInfoPtr pScrn);
/*
* 12288 is set as the maximum, chosen because it is enough for
@ -582,6 +731,14 @@ Rotation I830GetRotation(ScreenPtr pScreen);
#define _845_DRAM_RW_CONTROL 0x90
#define DRAM_WRITE 0x33330000
/* Compat definitions for older X Servers. */
#ifndef M_T_PREFERRED
#define M_T_PREFERRED 0x08
#endif
#ifndef M_T_DRIVER
#define M_T_DRIVER 0x40
#endif
/*
* Xserver MM compatibility. Remove code guarded by this when the
* XServer contains the libdrm mm code

233
src/i830_bios.c Normal file
View File

@ -0,0 +1,233 @@
/*
* Copyright © 2006 Intel Corporation
*
* 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
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* 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 NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS 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.
*
* Authors:
* Eric Anholt <eric@anholt.net>
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#undef VERSION /* XXX edid.h has a VERSION too */
#endif
#include <stdio.h>
#include <string.h>
#define _PARSE_EDID_
#include "xf86.h"
#include "i830.h"
#include "i830_bios.h"
#include "edid.h"
#define INTEL_BIOS_8(_addr) (bios[_addr])
#define INTEL_BIOS_16(_addr) (bios[_addr] | \
(bios[_addr + 1] << 8))
#define INTEL_BIOS_32(_addr) (bios[_addr] | \
(bios[_addr + 1] << 8) \
(bios[_addr + 2] << 16) \
(bios[_addr + 3] << 24))
/* XXX */
#define INTEL_VBIOS_SIZE (64 * 1024)
static void
i830DumpBIOSToFile(ScrnInfoPtr pScrn, unsigned char *bios)
{
const char *filename = "/tmp/xf86-video-intel-VBIOS";
FILE *f;
f = fopen(filename, "w");
if (f == NULL) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Couldn't open %s\n", filename);
return;
}
if (fwrite(bios, INTEL_VBIOS_SIZE, 1, f) != 1) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Couldn't write BIOS data\n");
}
xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Wrote BIOS contents to %s\n",
filename);
fclose(f);
}
/**
* Loads the Video BIOS and checks that the VBT exists.
*
* VBT existence is a sanity check that is relied on by other i830_bios.c code.
* Note that it would be better to use a BIOS call to get the VBT, as BIOSes may
* feed an updated VBT back through that, compared to what we'll fetch using
* this method of groping around in the BIOS data.
*/
static unsigned char *
i830GetBIOS(ScrnInfoPtr pScrn)
{
I830Ptr pI830 = I830PTR(pScrn);
struct vbt_header *vbt;
int vbt_off;
unsigned char *bios;
vbeInfoPtr pVbe;
bios = xalloc(INTEL_VBIOS_SIZE);
if (bios == NULL)
return NULL;
pVbe = VBEInit (NULL, pI830->pEnt->index);
if (pVbe != NULL) {
memcpy(bios, xf86int10Addr(pVbe->pInt10,
pVbe->pInt10->BIOSseg << 4),
INTEL_VBIOS_SIZE);
vbeFree (pVbe);
} else {
xf86ReadPciBIOS(0, pI830->PciTag, 0, bios, INTEL_VBIOS_SIZE);
}
if (0)
i830DumpBIOSToFile(pScrn, bios);
vbt_off = INTEL_BIOS_16(0x1a);
if (vbt_off >= INTEL_VBIOS_SIZE) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Bad VBT offset: 0x%x\n",
vbt_off);
xfree(bios);
return NULL;
}
vbt = (struct vbt_header *)(bios + vbt_off);
if (memcmp(vbt->signature, "$VBT", 4) != 0) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Bad VBT signature\n");
xfree(bios);
return NULL;
}
return bios;
}
Bool
i830GetLVDSInfoFromBIOS(ScrnInfoPtr pScrn)
{
I830Ptr pI830 = I830PTR(pScrn);
struct vbt_header *vbt;
struct bdb_header *bdb;
int vbt_off, bdb_off, bdb_block_off, block_size;
int panel_type = -1;
unsigned char *bios;
Bool found_panel_info = FALSE;
bios = i830GetBIOS(pScrn);
if (bios == NULL)
return FALSE;
vbt_off = INTEL_BIOS_16(0x1a);
vbt = (struct vbt_header *)(bios + vbt_off);
bdb_off = vbt_off + vbt->bdb_offset;
bdb = (struct bdb_header *)(bios + bdb_off);
if (memcmp(bdb->signature, "BIOS_DATA_BLOCK ", 16) != 0) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Bad BDB signature\n");
xfree(bios);
return FALSE;
}
for (bdb_block_off = bdb->header_size; bdb_block_off < bdb->bdb_size;
bdb_block_off += block_size)
{
int start = bdb_off + bdb_block_off;
int id;
struct lvds_bdb_1 *lvds1;
struct lvds_bdb_2 *lvds2;
struct lvds_bdb_2_fp_params *fpparam;
struct lvds_bdb_2_fp_edid_dtd *fptiming;
CARD8 *timing_ptr;
id = INTEL_BIOS_8(start);
block_size = INTEL_BIOS_16(start + 1) + 3;
xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Found BDB block type %d\n", id);
switch (id) {
case 40:
lvds1 = (struct lvds_bdb_1 *)(bios + start);
panel_type = lvds1->panel_type;
if (lvds1->caps & LVDS_CAP_DITHER)
pI830->panel_wants_dither = TRUE;
break;
case 41:
if (panel_type == -1)
break;
lvds2 = (struct lvds_bdb_2 *)(bios + start);
fpparam = (struct lvds_bdb_2_fp_params *)(bios +
bdb_off + lvds2->panels[panel_type].fp_params_offset);
fptiming = (struct lvds_bdb_2_fp_edid_dtd *)(bios +
bdb_off + lvds2->panels[panel_type].fp_edid_dtd_offset);
timing_ptr = bios + bdb_off +
lvds2->panels[panel_type].fp_edid_dtd_offset;
if (fpparam->terminator != 0xffff) {
/* Apparently the offsets are wrong for some BIOSes, so we
* try the other offsets if we find a bad terminator.
*/
fpparam = (struct lvds_bdb_2_fp_params *)(bios +
bdb_off + lvds2->panels[panel_type].fp_params_offset + 8);
fptiming = (struct lvds_bdb_2_fp_edid_dtd *)(bios +
bdb_off + lvds2->panels[panel_type].fp_edid_dtd_offset + 8);
timing_ptr = bios + bdb_off +
lvds2->panels[panel_type].fp_edid_dtd_offset + 8;
if (fpparam->terminator != 0xffff)
continue;
}
pI830->PanelXRes = fpparam->x_res;
pI830->PanelYRes = fpparam->y_res;
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
"Found panel of size %dx%d in BIOS VBT tables\n",
pI830->PanelXRes, pI830->PanelYRes);
/* Since lvds_bdb_2_fp_edid_dtd is just an EDID detailed timing
* block, pull the contents out using EDID macros.
*/
pI830->panel_fixed_clock = _PIXEL_CLOCK(timing_ptr) / 1000;
pI830->panel_fixed_hactive = _H_ACTIVE(timing_ptr);
pI830->panel_fixed_hblank = _H_BLANK(timing_ptr);
pI830->panel_fixed_hsyncoff = _H_SYNC_OFF(timing_ptr);
pI830->panel_fixed_hsyncwidth = _H_SYNC_WIDTH(timing_ptr);
pI830->panel_fixed_vactive = _V_ACTIVE(timing_ptr);
pI830->panel_fixed_vblank = _V_BLANK(timing_ptr);
pI830->panel_fixed_vsyncoff = _V_SYNC_OFF(timing_ptr);
pI830->panel_fixed_vsyncwidth = _V_SYNC_WIDTH(timing_ptr);
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
"Panel mode h active %d blank %d rate %f v active %d blank %d rate %f\n",
pI830->panel_fixed_hactive, pI830->panel_fixed_hblank,
(double) pI830->panel_fixed_clock / (pI830->panel_fixed_hactive + pI830->panel_fixed_hblank),
pI830->panel_fixed_vactive, pI830->panel_fixed_vblank,
(double) pI830->panel_fixed_clock /
((pI830->panel_fixed_hactive + pI830->panel_fixed_hblank) * (pI830->panel_fixed_vactive + pI830->panel_fixed_vblank)));
found_panel_info = TRUE;
break;
}
}
xfree(bios);
return found_panel_info;
}

119
src/i830_bios.h Normal file
View File

@ -0,0 +1,119 @@
/*
* Copyright © 2006 Intel Corporation
*
* 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
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* 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 NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS 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.
*
* Authors:
* Eric Anholt <eric@anholt.net>
*
*/
struct vbt_header {
char signature[20]; /**< Always starts with 'VBT$' */
CARD16 version; /**< decimal */
CARD16 header_size; /**< in bytes */
CARD16 vbt_size; /**< in bytes */
CARD8 vbt_checksum;
CARD8 reserved0;
CARD32 bdb_offset; /**< from beginning of VBT */
CARD32 aim1_offset; /**< from beginning of VBT */
CARD32 aim2_offset; /**< from beginning of VBT */
CARD32 aim3_offset; /**< from beginning of VBT */
CARD32 aim4_offset; /**< from beginning of VBT */
} __attribute__((packed));
struct bdb_header {
char signature[16]; /**< Always 'BIOS_DATA_BLOCK' */
CARD16 version; /**< decimal */
CARD16 header_size; /**< in bytes */
CARD16 bdb_size; /**< in bytes */
} __attribute__((packed));
#define LVDS_CAP_EDID (1 << 6)
#define LVDS_CAP_DITHER (1 << 5)
#define LVDS_CAP_PFIT_AUTO_RATIO (1 << 4)
#define LVDS_CAP_PFIT_GRAPHICS_MODE (1 << 3)
#define LVDS_CAP_PFIT_TEXT_MODE (1 << 2)
#define LVDS_CAP_PFIT_GRAPHICS (1 << 1)
#define LVDS_CAP_PFIT_TEXT (1 << 0)
struct lvds_bdb_1 {
CARD8 id; /**< 40 */
CARD16 size;
CARD8 panel_type;
CARD8 reserved0;
CARD16 caps;
} __attribute__((packed));
struct lvds_bdb_2_fp_params {
CARD16 x_res;
CARD16 y_res;
CARD32 lvds_reg;
CARD32 lvds_reg_val;
CARD32 pp_on_reg;
CARD32 pp_on_reg_val;
CARD32 pp_off_reg;
CARD32 pp_off_reg_val;
CARD32 pp_cycle_reg;
CARD32 pp_cycle_reg_val;
CARD32 pfit_reg;
CARD32 pfit_reg_val;
CARD16 terminator;
} __attribute__((packed));
struct lvds_bdb_2_fp_edid_dtd {
CARD16 dclk; /**< In 10khz */
CARD8 hactive;
CARD8 hblank;
CARD8 high_h; /**< 7:4 = hactive 11:8, 3:0 = hblank 11:8 */
CARD8 vactive;
CARD8 vblank;
CARD8 high_v; /**< 7:4 = vactive 11:8, 3:0 = vblank 11:8 */
CARD8 hsync_off;
CARD8 hsync_pulse_width;
CARD8 vsync_off;
CARD8 high_hsync_off; /**< 7:6 = hsync off 9:8 */
CARD8 h_image;
CARD8 v_image;
CARD8 max_hv;
CARD8 h_border;
CARD8 v_border;
CARD8 flags;
#define FP_EDID_FLAG_VSYNC_POSITIVE (1 << 2)
#define FP_EDID_FLAG_HSYNC_POSITIVE (1 << 1)
} __attribute__((packed));
struct lvds_bdb_2_entry {
CARD16 fp_params_offset; /**< From beginning of BDB */
CARD8 fp_params_size;
CARD16 fp_edid_dtd_offset;
CARD8 fp_edid_dtd_size;
CARD16 fp_edid_pid_offset;
CARD8 fp_edid_pid_size;
} __attribute__((packed));
struct lvds_bdb_2 {
CARD8 id; /**< 41 */
CARD16 size;
CARD8 table_size; /* not sure on this one */
struct lvds_bdb_2_entry panels[16];
} __attribute__((packed));
Bool
i830GetLVDSInfoFromBIOS(ScrnInfoPtr pScrn);

346
src/i830_crt.c Normal file
View File

@ -0,0 +1,346 @@
/*
* Copyright © 2006 Intel Corporation
*
* 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
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* 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 NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS 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.
*
* Authors:
* Eric Anholt <eric@anholt.net>
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "xf86.h"
#include "i830.h"
#include "i830_xf86Modes.h"
#include "i830_display.h"
static void
i830_crt_dpms(ScrnInfoPtr pScrn, I830OutputPtr output, int mode)
{
I830Ptr pI830 = I830PTR(pScrn);
CARD32 temp;
temp = INREG(ADPA);
temp &= ~(ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE);
temp &= ~ADPA_DAC_ENABLE;
switch(mode) {
case DPMSModeOn:
temp |= ADPA_DAC_ENABLE;
break;
case DPMSModeStandby:
temp |= ADPA_DAC_ENABLE | ADPA_HSYNC_CNTL_DISABLE;
break;
case DPMSModeSuspend:
temp |= ADPA_DAC_ENABLE | ADPA_VSYNC_CNTL_DISABLE;
break;
case DPMSModeOff:
temp |= ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE;
break;
}
OUTREG(ADPA, temp);
}
static void
i830_crt_save(ScrnInfoPtr pScrn, I830OutputPtr output)
{
I830Ptr pI830 = I830PTR(pScrn);
pI830->saveADPA = INREG(ADPA);
}
static void
i830_crt_restore(ScrnInfoPtr pScrn, I830OutputPtr output)
{
I830Ptr pI830 = I830PTR(pScrn);
OUTREG(ADPA, pI830->saveADPA);
}
static int
i830_crt_mode_valid(ScrnInfoPtr pScrn, I830OutputPtr output,
DisplayModePtr pMode)
{
if (pMode->Flags & V_DBLSCAN)
return MODE_NO_DBLESCAN;
if (pMode->Clock > 400000 || pMode->Clock < 25000)
return MODE_CLOCK_RANGE;
return MODE_OK;
}
static void
i830_crt_pre_set_mode(ScrnInfoPtr pScrn, I830OutputPtr output,
DisplayModePtr pMode)
{
}
static void
i830_crt_post_set_mode(ScrnInfoPtr pScrn, I830OutputPtr output,
DisplayModePtr pMode)
{
I830Ptr pI830 = I830PTR(pScrn);
int dpll_md_reg = (output->pipe == 0) ? DPLL_A_MD : DPLL_B_MD;
CARD32 adpa, dpll_md;
/*
* Disable separate mode multiplier used when cloning SDVO to CRT
* XXX this needs to be adjusted when we really are cloning
*/
if (IS_I965G(pI830))
{
dpll_md = INREG(dpll_md_reg);
OUTREG(dpll_md_reg, dpll_md & ~DPLL_MD_UDI_MULTIPLIER_MASK);
}
adpa = ADPA_DAC_ENABLE;
if (pMode->Flags & V_PHSYNC)
adpa |= ADPA_HSYNC_ACTIVE_HIGH;
if (pMode->Flags & V_PVSYNC)
adpa |= ADPA_VSYNC_ACTIVE_HIGH;
if (output->pipe == 0)
adpa |= ADPA_PIPE_A_SELECT;
else
adpa |= ADPA_PIPE_B_SELECT;
OUTREG(ADPA, adpa);
}
/**
* Uses CRT_HOTPLUG_EN and CRT_HOTPLUG_STAT to detect CRT presence.
*
* Only for I945G/GM.
*
* \return TRUE if CRT is connected.
* \return FALSE if CRT is disconnected.
*/
static Bool
i830_crt_detect_hotplug(ScrnInfoPtr pScrn)
{
I830Ptr pI830 = I830PTR(pScrn);
CARD32 temp;
const int timeout_ms = 1000;
int starttime, curtime;
temp = INREG(PORT_HOTPLUG_EN);
OUTREG(PORT_HOTPLUG_EN, temp | CRT_HOTPLUG_FORCE_DETECT | (1 << 5));
for (curtime = starttime = GetTimeInMillis();
(curtime - starttime) < timeout_ms; curtime = GetTimeInMillis())
{
if ((INREG(PORT_HOTPLUG_EN) & CRT_HOTPLUG_FORCE_DETECT) == 0)
break;
}
if ((INREG(PORT_HOTPLUG_STAT) & CRT_HOTPLUG_MONITOR_MASK) ==
CRT_HOTPLUG_MONITOR_COLOR)
{
return TRUE;
} else {
return FALSE;
}
}
/**
* Detects CRT presence by checking for load.
*
* Requires that the current pipe's DPLL is active. This will cause flicker
* on the CRT, so it should not be used while the display is being used. Only
* color (not monochrome) displays are detected.
*
* \return TRUE if CRT is connected.
* \return FALSE if CRT is disconnected.
*/
static Bool
i830_crt_detect_load(ScrnInfoPtr pScrn, I830OutputPtr output)
{
I830Ptr pI830 = I830PTR(pScrn);
CARD32 save_adpa, adpa, pipeconf, bclrpat;
CARD8 st00;
int pipeconf_reg, bclrpat_reg, dpll_reg;
int pipe;
pipe = output->pipe;
if (pipe == 0) {
bclrpat_reg = BCLRPAT_A;
pipeconf_reg = PIPEACONF;
dpll_reg = DPLL_A;
} else {
bclrpat_reg = BCLRPAT_B;
pipeconf_reg = PIPEBCONF;
dpll_reg = DPLL_B;
}
adpa = INREG(ADPA);
save_adpa = adpa;
/* Enable CRT output. */
adpa |= ADPA_DAC_ENABLE;
if (pipe == 1)
adpa |= ADPA_PIPE_B_SELECT;
else
adpa &= ~ADPA_PIPE_B_SELECT;
adpa |= ADPA_VSYNC_CNTL_ENABLE | ADPA_HSYNC_CNTL_ENABLE;
OUTREG(ADPA, adpa);
/* Set the border color to purple. Maybe we should save/restore this
* reg.
*/
bclrpat = INREG(bclrpat_reg);
OUTREG(bclrpat_reg, 0x00500050);
i830WaitForVblank(pScrn);
/* Force the border color through the active region */
pipeconf = INREG(pipeconf_reg);
OUTREG(pipeconf_reg, pipeconf | PIPECONF_FORCE_BORDER);
/* Read the ST00 VGA status register */
st00 = pI830->readStandard(pI830, 0x3c2);
/* Restore previous settings */
OUTREG(bclrpat_reg, bclrpat);
OUTREG(pipeconf_reg, pipeconf);
OUTREG(ADPA, save_adpa);
if (st00 & (1 << 4))
return TRUE;
else
return FALSE;
}
/**
* Detects CRT presence by probing for a response on the DDC address.
*
* This takes approximately 5ms in testing on an i915GM, with CRT connected or
* not.
*
* \return TRUE if the CRT is connected and responded to DDC.
* \return FALSE if no DDC response was detected.
*/
static Bool
i830_crt_detect_ddc(ScrnInfoPtr pScrn)
{
I830Ptr pI830 = I830PTR(pScrn);
struct _I830OutputRec *output;
output = &pI830->output[0];
/* CRT should always be at 0, but check anyway */
if (output->type != I830_OUTPUT_ANALOG)
return FALSE;
return xf86I2CProbeAddress(output->pDDCBus, 0x00A0);
}
/**
* Attempts to detect CRT presence through any method available.
*
* @param allow_disturb enables detection methods that may cause flickering
* on active displays.
*/
static enum detect_status
i830_crt_detect(ScrnInfoPtr pScrn, I830OutputPtr output)
{
I830Ptr pI830 = I830PTR(pScrn);
if (IS_I945G(pI830) || IS_I945GM(pI830) || IS_I965G(pI830)) {
if (i830_crt_detect_hotplug(pScrn))
return OUTPUT_STATUS_CONNECTED;
else
return OUTPUT_STATUS_DISCONNECTED;
}
if (i830_crt_detect_ddc(pScrn))
return OUTPUT_STATUS_CONNECTED;
/* Use the load-detect method if we have no other way of telling. */
if (i830GetLoadDetectPipe(pScrn, output) != -1) {
Bool connected = i830_crt_detect_load(pScrn, output);
i830ReleaseLoadDetectPipe(pScrn, output);
if (connected)
return OUTPUT_STATUS_CONNECTED;
else
return OUTPUT_STATUS_DISCONNECTED;
}
return OUTPUT_STATUS_UNKNOWN;
}
static DisplayModePtr
i830_crt_get_modes(ScrnInfoPtr pScrn, I830OutputPtr output)
{
DisplayModePtr modes;
MonRec fixed_mon;
modes = i830_ddc_get_modes(pScrn, output);
if (modes != NULL)
return modes;
if (output->detect(pScrn, output) == OUTPUT_STATUS_DISCONNECTED)
return NULL;
/* We've got a potentially-connected monitor that we can't DDC. Return a
* fixed set of VESA plus user modes for a presumed multisync monitor with
* some reasonable limits.
*/
fixed_mon.nHsync = 1;
fixed_mon.hsync[0].lo = 31.0;
fixed_mon.hsync[0].hi = 100.0;
fixed_mon.nVrefresh = 1;
fixed_mon.vrefresh[0].lo = 50.0;
fixed_mon.vrefresh[0].hi = 70.0;
modes = i830xf86DuplicateModes(pScrn, pScrn->monitor->Modes);
i830xf86ValidateModesSync(pScrn, modes, &fixed_mon);
i830xf86PruneInvalidModes(pScrn, &modes, TRUE);
return modes;
}
void
i830_crt_init(ScrnInfoPtr pScrn)
{
I830Ptr pI830 = I830PTR(pScrn);
pI830->output[pI830->num_outputs].type = I830_OUTPUT_ANALOG;
pI830->output[pI830->num_outputs].dpms = i830_crt_dpms;
pI830->output[pI830->num_outputs].save = i830_crt_save;
pI830->output[pI830->num_outputs].restore = i830_crt_restore;
pI830->output[pI830->num_outputs].mode_valid = i830_crt_mode_valid;
pI830->output[pI830->num_outputs].pre_set_mode = i830_crt_pre_set_mode;
pI830->output[pI830->num_outputs].post_set_mode = i830_crt_post_set_mode;
pI830->output[pI830->num_outputs].detect = i830_crt_detect;
pI830->output[pI830->num_outputs].get_modes = i830_crt_get_modes;
/* Set up the DDC bus. */
I830I2CInit(pScrn, &pI830->output[pI830->num_outputs].pDDCBus,
GPIOA, "CRTDDC_A");
pI830->num_outputs++;
}

View File

@ -1,4 +1,4 @@
/* -*- c-basic-offset: 3 -*- */
/**************************************************************************
Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
@ -79,52 +79,126 @@ static void I830LoadCursorARGB(ScrnInfoPtr pScrn, CursorPtr pCurs);
static Bool I830UseHWCursorARGB(ScreenPtr pScrn, CursorPtr pCurs);
#endif
static void
I830SetPipeCursorBase (ScrnInfoPtr pScrn, int pipe)
{
I830Ptr pI830 = I830PTR(pScrn);
int cursor_base = (pipe == 0 ? CURSOR_A_BASE : CURSOR_B_BASE);
I830MemRange *cursor_mem;
if (pipe >= pI830->num_pipes)
FatalError("Bad pipe number for cursor base setting\n");
if (pI830->CursorIsARGB)
cursor_mem = pI830->CursorMemARGB;
else
cursor_mem = pI830->CursorMem;
if (pI830->CursorNeedsPhysical) {
OUTREG(cursor_base, cursor_mem->Physical);
} else {
OUTREG(cursor_base, cursor_mem->Start);
}
}
void
I830SetPipeCursor (ScrnInfoPtr pScrn, int pipe, Bool force)
{
I830Ptr pI830 = I830PTR(pScrn);
I830PipePtr pI830Pipe = &pI830->pipes[pipe];
CARD32 temp;
Bool show;
if (!pI830Pipe->enabled)
return;
show = pI830->cursorOn && pI830Pipe->cursorInRange;
if (show && (force || !pI830Pipe->cursorShown))
{
if (IS_MOBILE(pI830) || IS_I9XX(pI830)) {
int cursor_control;
if (pipe == 0)
cursor_control = CURSOR_A_CONTROL;
else
cursor_control = CURSOR_B_CONTROL;
temp = INREG(cursor_control);
temp &= ~(CURSOR_MODE | MCURSOR_PIPE_SELECT);
if (pI830->CursorIsARGB) {
temp |= CURSOR_MODE_64_ARGB_AX;
if (pI830Pipe->gammaEnabled)
temp |= MCURSOR_GAMMA_ENABLE;
} else
temp |= CURSOR_MODE_64_4C_AX;
temp |= (pipe << 28); /* Connect to correct pipe */
/* Need to set mode, then address. */
OUTREG(cursor_control, temp);
} else {
temp = INREG(CURSOR_CONTROL);
temp &= ~(CURSOR_FORMAT_MASK);
temp |= CURSOR_ENABLE;
if (pI830->CursorIsARGB) {
temp |= CURSOR_FORMAT_ARGB;
if (pI830Pipe->gammaEnabled)
temp |= CURSOR_GAMMA_ENABLE;
} else
temp |= CURSOR_FORMAT_3C;
OUTREG(CURSOR_CONTROL, temp);
}
pI830Pipe->cursorShown = TRUE;
}
else if (!show && (force || pI830Pipe->cursorShown))
{
if (IS_MOBILE(pI830) || IS_I9XX(pI830))
{
int cursor_control;
if (pipe == 0)
cursor_control = CURSOR_A_CONTROL;
else
cursor_control = CURSOR_B_CONTROL;
temp = INREG(cursor_control);
temp &= ~(CURSOR_MODE|MCURSOR_GAMMA_ENABLE);
temp |= CURSOR_MODE_DISABLE;
OUTREG(cursor_control, temp);
} else {
temp = INREG(CURSOR_CONTROL);
temp &= ~(CURSOR_ENABLE|CURSOR_GAMMA_ENABLE);
OUTREG(CURSOR_CONTROL, temp);
}
pI830Pipe->cursorShown = FALSE;
}
/* Flush cursor changes. */
I830SetPipeCursorBase(pScrn, pipe);
}
void
I830InitHWCursor(ScrnInfoPtr pScrn)
{
I830Ptr pI830 = I830PTR(pScrn);
CARD32 temp;
int i;
DPRINTF(PFX, "I830InitHWCursor\n");
for (i = 0; i < pI830->num_pipes; i++)
pI830->pipes[i].cursorShown = FALSE;
/* Initialise the HW cursor registers, leaving the cursor hidden. */
if (IS_MOBILE(pI830) || IS_I9XX(pI830)) {
temp = INREG(CURSOR_A_CONTROL);
temp &= ~(CURSOR_MODE | MCURSOR_GAMMA_ENABLE | MCURSOR_MEM_TYPE_LOCAL |
MCURSOR_PIPE_SELECT);
temp |= CURSOR_MODE_DISABLE;
temp |= (pI830->pipe << 28);
if (pI830->CursorIsARGB)
temp |= CURSOR_MODE_64_ARGB_AX | MCURSOR_GAMMA_ENABLE;
else
temp |= CURSOR_MODE_64_4C_AX;
/* Need to set control, then address. */
OUTREG(CURSOR_A_CONTROL, temp);
if (pI830->CursorNeedsPhysical) {
if (pI830->CursorIsARGB)
OUTREG(CURSOR_A_BASE, pI830->CursorMemARGB->Physical);
else
OUTREG(CURSOR_A_BASE, pI830->CursorMem->Physical);
} else {
if (pI830->CursorIsARGB)
OUTREG(CURSOR_A_BASE, pI830->CursorMemARGB->Start);
else
OUTREG(CURSOR_A_BASE, pI830->CursorMem->Start);
}
if (pI830->Clone || pI830->MergedFB) {
temp &= ~MCURSOR_PIPE_SELECT;
temp |= (!pI830->pipe << 28);
OUTREG(CURSOR_B_CONTROL, temp);
if (pI830->CursorNeedsPhysical) {
if (pI830->CursorIsARGB)
OUTREG(CURSOR_B_BASE, pI830->CursorMemARGB->Physical);
else
OUTREG(CURSOR_B_BASE, pI830->CursorMem->Physical);
} else {
if (pI830->CursorIsARGB)
OUTREG(CURSOR_B_BASE, pI830->CursorMemARGB->Start);
else
OUTREG(CURSOR_B_BASE, pI830->CursorMem->Start);
}
for (i = 0; i < pI830->num_pipes; i++)
{
int cursor_control = i == 0 ? CURSOR_A_CONTROL : CURSOR_B_CONTROL;
temp = INREG(cursor_control);
temp &= ~(CURSOR_MODE | MCURSOR_GAMMA_ENABLE |
MCURSOR_MEM_TYPE_LOCAL |
MCURSOR_PIPE_SELECT);
temp |= (i << 28);
if (pI830->CursorIsARGB)
temp |= CURSOR_MODE_64_ARGB_AX | MCURSOR_GAMMA_ENABLE;
else
temp |= CURSOR_MODE_64_4C_AX;
/* Need to set control, then address. */
OUTREG(cursor_control, temp);
I830SetPipeCursorBase(pScrn, i);
}
} else {
temp = INREG(CURSOR_CONTROL);
@ -137,10 +211,7 @@ I830InitHWCursor(ScrnInfoPtr pScrn)
/* This initialises the format and leave the cursor disabled. */
OUTREG(CURSOR_CONTROL, temp);
/* Need to set address and size after disabling. */
if (pI830->CursorIsARGB)
OUTREG(CURSOR_BASEADDR, pI830->CursorMemARGB->Start);
else
OUTREG(CURSOR_BASEADDR, pI830->CursorMem->Start);
I830SetPipeCursorBase(pScrn, 0);
temp = ((I810_CURSOR_X & CURSOR_SIZE_MASK) << CURSOR_SIZE_HSHIFT) |
((I810_CURSOR_Y & CURSOR_SIZE_MASK) << CURSOR_SIZE_VSHIFT);
OUTREG(CURSOR_SIZE, temp);
@ -374,239 +445,99 @@ static void I830LoadCursorARGB (ScrnInfoPtr pScrn, CursorPtr pCurs)
}
#endif
#define CDMPTR ((I830ModePrivatePtr)pI830->currentMode->Private)->merged
static void
I830SetCursorPositionMerged(ScrnInfoPtr pScrn, int x, int y)
{
I830Ptr pI830 = I830PTR(pScrn);
ScrnInfoPtr pScrn2 = pI830->pScrn_2;
DisplayModePtr mode1 = CDMPTR.First;
Bool hide = FALSE, show = FALSE;
DisplayModePtr mode2 = CDMPTR.Second;
int x1, y1, x2, y2;
int total_y1 = pScrn->frameY1 - pScrn->frameY0;
int total_y2 = pScrn2->frameY1 - pScrn2->frameY0;
CARD32 temp = 0, temp2 = 0;
x += pScrn->frameX0;
y += pScrn->frameY0;
x1 = x - pI830->FirstframeX0;
y1 = y - pI830->FirstframeY0;
x2 = x - pScrn2->frameX0;
y2 = y - pScrn2->frameY0;
if (y1 > total_y1)
y1 = total_y1;
if (y2 > total_y2)
y2 = total_y2;
/* move cursor offscreen */
if (y1 >= 0 && y2 >= mode2->VDisplay) {
y2 = -I810_CURSOR_Y;
} else if (y2 >= 0 && y1 >= mode1->VDisplay) {
y1 = -I810_CURSOR_Y;
}
if (x1 >= 0 && x2 >= mode2->HDisplay) {
x2 = -I810_CURSOR_X;
} else if (x2 >= 0 && x1 >= mode1->HDisplay) {
x1 = -I810_CURSOR_X;
}
/* Clamp the cursor position to the visible screen area */
if (x1 >= mode1->HDisplay) x1 = mode1->HDisplay - 1;
if (y1 >= mode1->VDisplay) y1 = mode1->VDisplay - 1;
if (x1 <= -I810_CURSOR_X) x1 = -I810_CURSOR_X + 1;
if (y1 <= -I810_CURSOR_Y) y1 = -I810_CURSOR_Y + 1;
if (x2 >= mode2->HDisplay) x2 = mode2->HDisplay - 1;
if (y2 >= mode2->VDisplay) y2 = mode2->VDisplay - 1;
if (x2 <= -I810_CURSOR_X) x2 = -I810_CURSOR_X + 1;
if (y2 <= -I810_CURSOR_Y) y2 = -I810_CURSOR_Y + 1;
if (x1 < 0) {
temp |= (CURSOR_POS_SIGN << CURSOR_X_SHIFT);
x1 = -x1;
}
if (y1 < 0) {
temp |= (CURSOR_POS_SIGN << CURSOR_Y_SHIFT);
y1 = -y1;
}
if (x2 < 0) {
temp2 |= (CURSOR_POS_SIGN << CURSOR_X_SHIFT);
x2 = -x2;
}
if (y2 < 0) {
temp2 |= (CURSOR_POS_SIGN << CURSOR_Y_SHIFT);
y2 = -y2;
}
temp |= ((x1 & CURSOR_POS_MASK) << CURSOR_X_SHIFT);
temp |= ((y1 & CURSOR_POS_MASK) << CURSOR_Y_SHIFT);
temp2 |= ((x2 & CURSOR_POS_MASK) << CURSOR_X_SHIFT);
temp2 |= ((y2 & CURSOR_POS_MASK) << CURSOR_Y_SHIFT);
OUTREG(CURSOR_A_POSITION, temp);
OUTREG(CURSOR_B_POSITION, temp2);
if (pI830->cursorOn) {
if (hide)
pI830->CursorInfoRec->HideCursor(pScrn);
else if (show)
pI830->CursorInfoRec->ShowCursor(pScrn);
pI830->cursorOn = TRUE;
}
/* have to upload the base for the new position */
if (IS_I9XX(pI830)) {
if (pI830->CursorIsARGB) {
OUTREG(CURSOR_A_BASE, pI830->CursorMemARGB->Physical);
OUTREG(CURSOR_B_BASE, pI830->CursorMemARGB->Physical);
} else {
OUTREG(CURSOR_A_BASE, pI830->CursorMem->Physical);
OUTREG(CURSOR_B_BASE, pI830->CursorMem->Physical);
}
}
}
static void
I830SetCursorPosition(ScrnInfoPtr pScrn, int x, int y)
{
I830Ptr pI830 = I830PTR(pScrn);
CARD32 temp = 0;
Bool hide = FALSE, show = FALSE;
int oldx = x, oldy = y;
int hotspotx = 0, hotspoty = 0;
#if 0
static Bool outsideViewport = FALSE;
#endif
I830Ptr pI830 = I830PTR(pScrn);
CARD32 temp;
Bool inrange;
int oldx = x, oldy = y;
int hotspotx = 0, hotspoty = 0;
int pipe;
if (pI830->MergedFB) {
I830SetCursorPositionMerged(pScrn, x, y);
return;
}
oldx += pScrn->frameX0; /* undo what xf86HWCurs did */
oldy += pScrn->frameY0;
oldx += pScrn->frameX0; /* undo what xf86HWCurs did */
oldy += pScrn->frameY0;
switch (pI830->rotation) {
case RR_Rotate_0:
x = oldx;
y = oldy;
break;
case RR_Rotate_90:
x = oldy;
y = pScrn->pScreen->width - oldx;
hotspoty = I810_CURSOR_X;
break;
case RR_Rotate_180:
x = pScrn->pScreen->width - oldx;
y = pScrn->pScreen->height - oldy;
hotspotx = I810_CURSOR_X;
hotspoty = I810_CURSOR_Y;
break;
case RR_Rotate_270:
x = pScrn->pScreen->height - oldy;
y = oldx;
hotspotx = I810_CURSOR_Y;
break;
}
switch (pI830->rotation) {
case RR_Rotate_0:
x = oldx;
y = oldy;
break;
case RR_Rotate_90:
x = oldy;
y = pScrn->pScreen->width - oldx;
hotspoty = I810_CURSOR_X;
break;
case RR_Rotate_180:
x = pScrn->pScreen->width - oldx;
y = pScrn->pScreen->height - oldy;
hotspotx = I810_CURSOR_X;
hotspoty = I810_CURSOR_Y;
break;
case RR_Rotate_270:
x = pScrn->pScreen->height - oldy;
y = oldx;
hotspotx = I810_CURSOR_Y;
break;
}
x -= hotspotx;
y -= hotspoty;
x -= hotspotx;
y -= hotspoty;
for (pipe = 0; pipe < pI830->num_pipes; pipe++)
{
I830PipePtr pI830Pipe = &pI830->pipes[pipe];
DisplayModePtr mode = &pI830Pipe->curMode;
int thisx = x - pI830Pipe->x;
int thisy = y - pI830Pipe->y;
/* Now, readjust */
x -= pScrn->frameX0;
y -= pScrn->frameY0;
if (!pI830Pipe->enabled)
continue;
if (pScrn->currentMode) {
/* Clamp the cursor position to the visible screen area */
if (x >= pScrn->currentMode->HDisplay) x = pScrn->currentMode->HDisplay - 1;
if (y >= pScrn->currentMode->VDisplay) y = pScrn->currentMode->VDisplay - 1;
if (x <= -I810_CURSOR_X) x = -I810_CURSOR_X + 1;
if (y <= -I810_CURSOR_Y) y = -I810_CURSOR_Y + 1;
} else {
/* Can't ensure the cursor will be visible, so hide it */
hide = TRUE;
show = FALSE;
}
/*
* There is a screen display problem when the cursor position is set
* wholely outside of the viewport. We trap that here, turning the
* cursor off when that happens, and back on when it comes back into
* the viewport.
*/
inrange = TRUE;
if (thisx >= mode->HDisplay ||
thisy >= mode->VDisplay ||
thisx <= -I810_CURSOR_X || thisy <= -I810_CURSOR_Y)
{
inrange = FALSE;
thisx = 0;
thisy = 0;
}
#if 0
/*
* There is a screen display problem when the cursor position is set
* wholely outside of the viewport. We trap that here, turning the
* cursor off when that happens, and back on when it comes back into
* the viewport.
*/
if (x >= pScrn->currentMode->HDisplay ||
y >= pScrn->currentMode->VDisplay ||
x <= -I810_CURSOR_X || y <= -I810_CURSOR_Y) {
hide = TRUE;
outsideViewport = TRUE;
} else if (outsideViewport) {
show = TRUE;
outsideViewport = FALSE;
}
#endif
temp = 0;
if (thisx < 0) {
temp |= (CURSOR_POS_SIGN << CURSOR_X_SHIFT);
thisx = -thisx;
}
if (thisy < 0) {
temp |= (CURSOR_POS_SIGN << CURSOR_Y_SHIFT);
thisy = -thisy;
}
temp |= ((thisx & CURSOR_POS_MASK) << CURSOR_X_SHIFT);
temp |= ((thisy & CURSOR_POS_MASK) << CURSOR_Y_SHIFT);
if (x < 0) {
temp |= (CURSOR_POS_SIGN << CURSOR_X_SHIFT);
x = -x;
}
if (y < 0) {
temp |= (CURSOR_POS_SIGN << CURSOR_Y_SHIFT);
y = -y;
}
temp |= ((x & CURSOR_POS_MASK) << CURSOR_X_SHIFT);
temp |= ((y & CURSOR_POS_MASK) << CURSOR_Y_SHIFT);
if (pipe == 0)
OUTREG(CURSOR_A_POSITION, temp);
if (pipe == 1)
OUTREG(CURSOR_B_POSITION, temp);
OUTREG(CURSOR_A_POSITION, temp);
if (pI830->Clone)
OUTREG(CURSOR_B_POSITION, temp);
if (pI830->cursorOn) {
if (hide)
pI830->CursorInfoRec->HideCursor(pScrn);
else if (show)
pI830->CursorInfoRec->ShowCursor(pScrn);
pI830->cursorOn = TRUE;
}
/* have to upload the base for the new position */
if (IS_I9XX(pI830)) {
if (pI830->CursorNeedsPhysical) {
if (pI830->CursorIsARGB)
OUTREG(CURSOR_A_BASE, pI830->CursorMemARGB->Physical);
else
OUTREG(CURSOR_A_BASE, pI830->CursorMem->Physical);
} else {
if (pI830->CursorIsARGB)
OUTREG(CURSOR_A_BASE, pI830->CursorMemARGB->Start);
else
OUTREG(CURSOR_A_BASE, pI830->CursorMem->Start);
}
if (pI830->Clone) {
if (pI830->CursorNeedsPhysical) {
if (pI830->CursorIsARGB)
OUTREG(CURSOR_B_BASE, pI830->CursorMemARGB->Physical);
else
OUTREG(CURSOR_B_BASE, pI830->CursorMem->Physical);
} else {
if (pI830->CursorIsARGB)
OUTREG(CURSOR_B_BASE, pI830->CursorMemARGB->Start);
else
OUTREG(CURSOR_B_BASE, pI830->CursorMem->Start);
}
}
}
pI830Pipe->cursorInRange = inrange;
I830SetPipeCursor (pScrn, pipe, FALSE);
}
}
static void
I830ShowCursor(ScrnInfoPtr pScrn)
{
I830Ptr pI830 = I830PTR(pScrn);
CARD32 temp;
int pipe;
DPRINTF(PFX, "I830ShowCursor\n");
DPRINTF(PFX,
@ -618,91 +549,22 @@ I830ShowCursor(ScrnInfoPtr pScrn)
" Value of CursorMemARGB->Start is %x ",
pI830->CursorMemARGB->Physical, pI830->CursorMemARGB->Start);
pI830->cursorOn = TRUE;
if (IS_MOBILE(pI830) || IS_I9XX(pI830)) {
temp = INREG(CURSOR_A_CONTROL);
temp &= ~(CURSOR_MODE | MCURSOR_PIPE_SELECT | MCURSOR_GAMMA_ENABLE);
if (pI830->CursorIsARGB)
temp |= CURSOR_MODE_64_ARGB_AX | MCURSOR_GAMMA_ENABLE;
else
temp |= CURSOR_MODE_64_4C_AX;
temp |= (pI830->pipe << 28); /* Connect to correct pipe */
/* Need to set mode, then address. */
OUTREG(CURSOR_A_CONTROL, temp);
if (pI830->CursorNeedsPhysical) {
if (pI830->CursorIsARGB)
OUTREG(CURSOR_A_BASE, pI830->CursorMemARGB->Physical);
else
OUTREG(CURSOR_A_BASE, pI830->CursorMem->Physical);
} else {
if (pI830->CursorIsARGB)
OUTREG(CURSOR_A_BASE, pI830->CursorMemARGB->Start);
else
OUTREG(CURSOR_A_BASE, pI830->CursorMem->Start);
}
if (pI830->Clone || pI830->MergedFB) {
temp &= ~MCURSOR_PIPE_SELECT;
temp |= (!pI830->pipe << 28);
OUTREG(CURSOR_B_CONTROL, temp);
if (pI830->CursorNeedsPhysical) {
if (pI830->CursorIsARGB)
OUTREG(CURSOR_B_BASE, pI830->CursorMemARGB->Physical);
else
OUTREG(CURSOR_B_BASE, pI830->CursorMem->Physical);
} else {
if (pI830->CursorIsARGB)
OUTREG(CURSOR_B_BASE, pI830->CursorMemARGB->Start);
else
OUTREG(CURSOR_B_BASE, pI830->CursorMem->Start);
}
}
} else {
temp = INREG(CURSOR_CONTROL);
temp &= ~(CURSOR_FORMAT_MASK | CURSOR_GAMMA_ENABLE);
temp |= CURSOR_ENABLE;
if (pI830->CursorIsARGB)
temp |= CURSOR_FORMAT_ARGB | CURSOR_GAMMA_ENABLE;
else
temp |= CURSOR_FORMAT_3C;
OUTREG(CURSOR_CONTROL, temp);
if (pI830->CursorIsARGB)
OUTREG(CURSOR_BASEADDR, pI830->CursorMemARGB->Start);
else
OUTREG(CURSOR_BASEADDR, pI830->CursorMem->Start);
}
pI830->cursorOn = TRUE;
for (pipe = 0; pipe < pI830->num_pipes; pipe++)
I830SetPipeCursor (pScrn, pipe, TRUE);
}
static void
I830HideCursor(ScrnInfoPtr pScrn)
{
CARD32 temp;
I830Ptr pI830 = I830PTR(pScrn);
int pipe;
DPRINTF(PFX, "I830HideCursor\n");
pI830->cursorOn = FALSE;
if (IS_MOBILE(pI830) || IS_I9XX(pI830)) {
temp = INREG(CURSOR_A_CONTROL);
temp &= ~CURSOR_MODE;
temp |= CURSOR_MODE_DISABLE;
OUTREG(CURSOR_A_CONTROL, temp);
/* This is needed to flush the above change. */
if (pI830->CursorIsARGB)
OUTREG(CURSOR_A_BASE, pI830->CursorMemARGB->Physical);
else
OUTREG(CURSOR_A_BASE, pI830->CursorMem->Physical);
if (pI830->Clone || pI830->MergedFB) {
OUTREG(CURSOR_B_CONTROL, temp);
if (pI830->CursorIsARGB)
OUTREG(CURSOR_B_BASE, pI830->CursorMemARGB->Physical);
else
OUTREG(CURSOR_B_BASE, pI830->CursorMem->Physical);
}
} else {
temp = INREG(CURSOR_CONTROL);
temp &= ~CURSOR_ENABLE;
OUTREG(CURSOR_CONTROL, temp);
}
for (pipe = 0; pipe < pI830->num_pipes; pipe++)
I830SetPipeCursor (pScrn, pipe, TRUE);
}
static void
@ -718,11 +580,15 @@ I830SetCursorColors(ScrnInfoPtr pScrn, int bg, int fg)
DPRINTF(PFX, "I830SetCursorColors\n");
OUTREG(CURSOR_A_PALETTE0, bg & 0x00ffffff);
OUTREG(CURSOR_A_PALETTE1, fg & 0x00ffffff);
OUTREG(CURSOR_A_PALETTE2, fg & 0x00ffffff);
OUTREG(CURSOR_A_PALETTE3, bg & 0x00ffffff);
if (pI830->Clone || pI830->MergedFB) {
if (pI830->pipes[0].enabled)
{
OUTREG(CURSOR_A_PALETTE0, bg & 0x00ffffff);
OUTREG(CURSOR_A_PALETTE1, fg & 0x00ffffff);
OUTREG(CURSOR_A_PALETTE2, fg & 0x00ffffff);
OUTREG(CURSOR_A_PALETTE3, bg & 0x00ffffff);
}
if (pI830->pipes[1].enabled)
{
OUTREG(CURSOR_B_PALETTE0, bg & 0x00ffffff);
OUTREG(CURSOR_B_PALETTE1, fg & 0x00ffffff);
OUTREG(CURSOR_B_PALETTE2, fg & 0x00ffffff);

272
src/i830_debug.c Normal file
View File

@ -0,0 +1,272 @@
/*
* Copyright © 2006 Intel Corporation
*
* 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
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* 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 NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS 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.
*
* Authors:
* Eric Anholt <eric@anholt.net>
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "xf86.h"
#include "i830.h"
#include "i830_debug.h"
#define DEFINEREG(reg) \
{ reg, #reg, 0 }
static struct i830SnapshotRec {
int reg;
char *name;
CARD32 regval;
} i830_snapshot[] = {
DEFINEREG(VCLK_DIVISOR_VGA0),
DEFINEREG(VCLK_DIVISOR_VGA1),
DEFINEREG(VCLK_POST_DIV),
DEFINEREG(DPLL_TEST),
DEFINEREG(D_STATE),
DEFINEREG(DSPCLK_GATE_D),
DEFINEREG(RENCLK_GATE_D1),
DEFINEREG(RENCLK_GATE_D2),
/* DEFINEREG(RAMCLK_GATE_D), CRL only */
DEFINEREG(SDVOB),
DEFINEREG(SDVOC),
/* DEFINEREG(UDIB_SVB_SHB_CODES), CRL only */
/* DEFINEREG(UDIB_SHA_BLANK_CODES), CRL only */
DEFINEREG(SDVOUDI),
DEFINEREG(DSPARB),
DEFINEREG(DSPFW1),
DEFINEREG(DSPFW2),
DEFINEREG(DSPFW3),
DEFINEREG(ADPA),
DEFINEREG(LVDS),
DEFINEREG(DVOA),
DEFINEREG(DVOB),
DEFINEREG(DVOC),
DEFINEREG(DVOA_SRCDIM),
DEFINEREG(DVOB_SRCDIM),
DEFINEREG(DVOC_SRCDIM),
DEFINEREG(PP_CONTROL),
DEFINEREG(PP_STATUS),
DEFINEREG(PFIT_CONTROL),
DEFINEREG(PFIT_PGM_RATIOS),
DEFINEREG(PORT_HOTPLUG_EN),
DEFINEREG(PORT_HOTPLUG_STAT),
DEFINEREG(DSPACNTR),
DEFINEREG(DSPASTRIDE),
DEFINEREG(DSPAPOS),
DEFINEREG(DSPASIZE),
DEFINEREG(DSPABASE),
DEFINEREG(DSPASURF),
DEFINEREG(DSPATILEOFF),
DEFINEREG(PIPEACONF),
DEFINEREG(PIPEASRC),
DEFINEREG(FPA0),
DEFINEREG(FPA1),
DEFINEREG(DPLL_A),
DEFINEREG(DPLL_A_MD),
DEFINEREG(HTOTAL_A),
DEFINEREG(HBLANK_A),
DEFINEREG(HSYNC_A),
DEFINEREG(VTOTAL_A),
DEFINEREG(VBLANK_A),
DEFINEREG(VSYNC_A),
DEFINEREG(BCLRPAT_A),
DEFINEREG(VSYNCSHIFT_A),
DEFINEREG(DSPBCNTR),
DEFINEREG(DSPBSTRIDE),
DEFINEREG(DSPBPOS),
DEFINEREG(DSPBSIZE),
DEFINEREG(DSPBBASE),
DEFINEREG(DSPBSURF),
DEFINEREG(DSPBTILEOFF),
DEFINEREG(PIPEBCONF),
DEFINEREG(PIPEBSRC),
DEFINEREG(FPB0),
DEFINEREG(FPB1),
DEFINEREG(DPLL_B),
DEFINEREG(DPLL_B_MD),
DEFINEREG(HTOTAL_B),
DEFINEREG(HBLANK_B),
DEFINEREG(HSYNC_B),
DEFINEREG(VTOTAL_B),
DEFINEREG(VBLANK_B),
DEFINEREG(VSYNC_B),
DEFINEREG(BCLRPAT_B),
DEFINEREG(VSYNCSHIFT_B),
DEFINEREG(VCLK_DIVISOR_VGA0),
DEFINEREG(VCLK_DIVISOR_VGA1),
DEFINEREG(VCLK_POST_DIV),
DEFINEREG(VGACNTRL),
};
#undef DEFINEREG
#define NUM_I830_SNAPSHOTREGS (sizeof(i830_snapshot) / sizeof(i830_snapshot[0]))
void i830TakeRegSnapshot(ScrnInfoPtr pScrn)
{
I830Ptr pI830 = I830PTR(pScrn);
int i;
for (i = 0; i < NUM_I830_SNAPSHOTREGS; i++) {
i830_snapshot[i].regval = INREG(i830_snapshot[i].reg);
}
}
void i830CompareRegsToSnapshot(ScrnInfoPtr pScrn)
{
I830Ptr pI830 = I830PTR(pScrn);
int i;
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
"Comparing regs before/after X's VT usage\n");
for (i = 0; i < NUM_I830_SNAPSHOTREGS; i++) {
CARD32 val = INREG(i830_snapshot[i].reg);
if (i830_snapshot[i].regval != val) {
xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
"Register 0x%x (%s) changed from 0x%08x to 0x%08x\n",
i830_snapshot[i].reg, i830_snapshot[i].name,
(int)i830_snapshot[i].regval, (int)val);
}
}
}
static void i830DumpIndexed (ScrnInfoPtr pScrn, char *name, int id, int val, int min, int max)
{
I830Ptr pI830 = I830PTR(pScrn);
int i;
for (i = min; i <= max; i++) {
OUTREG8 (id, i);
xf86DrvMsg (pScrn->scrnIndex, X_WARNING, "%18.18s%02x: 0x%02x\n",
name, i, INREG8(val));
}
}
void i830DumpRegs (ScrnInfoPtr pScrn)
{
I830Ptr pI830 = I830PTR(pScrn);
int i;
int fp, dpll;
int pipe;
int n, m1, m2, m, p1, p2;
int ref;
int dot;
int phase;
int msr;
int crt;
xf86DrvMsg (pScrn->scrnIndex, X_WARNING, "DumpRegsBegin\n");
for (i = 0; i < NUM_I830_SNAPSHOTREGS; i++) {
xf86DrvMsg (pScrn->scrnIndex, X_WARNING, "%20.20s: 0x%08x\n",
i830_snapshot[i].name, (unsigned int) INREG(i830_snapshot[i].reg));
}
i830DumpIndexed (pScrn, "SR", 0x3c4, 0x3c5, 0, 7);
msr = INREG8(0x3cc);
xf86DrvMsg (pScrn->scrnIndex, X_WARNING, "%20.20s: 0x%02x\n",
"MSR", (unsigned int) msr);
if (msr & 1)
crt = 0x3d0;
else
crt = 0x3b0;
i830DumpIndexed (pScrn, "CR", crt + 4, crt + 5, 0, 0x24);
for (pipe = 0; pipe <= 1; pipe++)
{
fp = INREG(pipe == 0 ? FPA0 : FPB0);
dpll = INREG(pipe == 0 ? DPLL_A : DPLL_B);
switch ((dpll >> 24) & 0x3) {
case 0:
p2 = 10;
break;
case 1:
p2 = 5;
break;
default:
p2 = 1;
xf86DrvMsg (pScrn->scrnIndex, X_ERROR, "p2 out of range\n");
break;
}
switch ((dpll >> 16) & 0xff) {
case 1:
p1 = 1; break;
case 2:
p1 = 2; break;
case 4:
p1 = 3; break;
case 8:
p1 = 4; break;
case 16:
p1 = 5; break;
case 32:
p1 = 6; break;
case 64:
p1 = 7; break;
case 128:
p1 = 8; break;
default:
p1 = 1;
xf86DrvMsg (pScrn->scrnIndex, X_ERROR, "p1 out of range\n");
break;
}
switch ((dpll >> 13) & 0x3) {
case 0:
ref = 96000;
break;
default:
ref = 0;
xf86DrvMsg (pScrn->scrnIndex, X_ERROR, "ref out of range\n");
break;
}
phase = (dpll >> 9) & 0xf;
switch (phase) {
case 6:
break;
default:
xf86DrvMsg (pScrn->scrnIndex, X_ERROR, "phase %d out of range\n", phase);
break;
}
switch ((dpll >> 8) & 1) {
case 0:
break;
default:
xf86DrvMsg (pScrn->scrnIndex, X_ERROR, "fp select out of range\n");
break;
}
n = ((fp >> 16) & 0x3f);
m1 = ((fp >> 8) & 0x3f);
m2 = ((fp >> 0) & 0x3f);
m = 5 * (m1 + 2) + (m2 + 2);
dot = (ref * (5 * (m1 + 2) + (m2 + 2)) / (n + 2)) / (p1 * p2);
xf86DrvMsg (pScrn->scrnIndex, X_WARNING, "pipe %s dot %d n %d m1 %d m2 %d p1 %d p2 %d\n",
pipe == 0 ? "A" : "B", dot, n, m1, m2, p1, p2);
}
xf86DrvMsg (pScrn->scrnIndex, X_WARNING, "DumpRegsEnd\n");
}

30
src/i830_debug.h Normal file
View File

@ -0,0 +1,30 @@
/*
* Copyright © 2006 Intel Corporation
*
* 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
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* 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 NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS 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.
*
* Authors:
* Eric Anholt <eric@anholt.net>
*
*/
void i830TakeRegSnapshot(ScrnInfoPtr pScrn);
void i830CompareRegsToSnapshot(ScrnInfoPtr pScrn);
void i830DumpRegs (ScrnInfoPtr pScrn);

View File

@ -99,31 +99,6 @@ I830DGAInit(ScreenPtr pScreen)
while (pMode) {
if(pI830->MergedFB) {
Bool nogood = FALSE;
/* Filter out all meta modes that would require driver-side panning */
switch(((I830ModePrivatePtr)pMode->Private)->merged.SecondPosition) {
case PosRightOf:
case PosLeftOf:
if( (((I830ModePrivatePtr)pMode->Private)->merged.First->VDisplay !=
((I830ModePrivatePtr)pMode->Private)->merged.Second->VDisplay) ||
(((I830ModePrivatePtr)pMode->Private)->merged.First->VDisplay != pMode->VDisplay) )
nogood = TRUE;
break;
default:
if( (((I830ModePrivatePtr)pMode->Private)->merged.First->HDisplay !=
((I830ModePrivatePtr)pMode->Private)->merged.Second->HDisplay) ||
(((I830ModePrivatePtr)pMode->Private)->merged.First->HDisplay != pMode->HDisplay) )
nogood = TRUE;
}
if(nogood) {
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
"DGA: MetaMode %dx%d not suitable for DGA, skipping\n",
pMode->HDisplay, pMode->VDisplay);
goto mode_nogood;
}
}
newmodes = xrealloc(modes, (num + 1) * sizeof(DGAModeRec));
if (!newmodes) {
@ -180,7 +155,6 @@ I830DGAInit(ScreenPtr pScreen)
currentMode->maxViewportY = currentMode->imageHeight -
currentMode->viewportHeight;
mode_nogood:
pMode = pMode->next;
if (pMode == firstMode)
break;

971
src/i830_display.c Normal file
View File

@ -0,0 +1,971 @@
/* -*- c-basic-offset: 4 -*- */
/*
* Copyright © 2006 Intel Corporation
*
* 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
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* 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 NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS 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.
*
* Authors:
* Eric Anholt <eric@anholt.net>
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <stdlib.h>
#include <math.h>
#include "xf86.h"
#include "i830.h"
#include "i830_bios.h"
#include "i830_display.h"
#include "i830_debug.h"
#include "i830_xf86Modes.h"
/** Returns the pixel clock for the given refclk and divisors. */
static int i830_clock(int refclk, int m1, int m2, int n, int p1, int p2)
{
return refclk * (5 * m1 + m2) / n / (p1 * p2);
}
static void
i830PrintPll(char *prefix, int refclk, int m1, int m2, int n, int p1, int p2)
{
int dotclock;
dotclock = i830_clock(refclk, m1, m2, n, p1, p2);
ErrorF("%s: dotclock %d ((%d, %d), %d, (%d, %d))\n", prefix, dotclock,
m1, m2, n, p1, p2);
}
/**
* Returns whether any output on the specified pipe is an LVDS output
*/
Bool
i830PipeHasType (ScrnInfoPtr pScrn, int pipe, int type)
{
I830Ptr pI830 = I830PTR(pScrn);
int i;
for (i = 0; i < pI830->num_outputs; i++)
if (pI830->output[i].enabled && pI830->output[i].pipe == pipe)
{
if (pI830->output[i].type == type)
return TRUE;
}
return FALSE;
}
/**
* Returns whether the given set of divisors are valid for a given refclk with
* the given outputs.
*
* The equation for these divisors would be:
* clk = refclk * (5 * m1 + m2) / n / (p1 * p2)
*/
static Bool
i830PllIsValid(ScrnInfoPtr pScrn, int pipe, int refclk, int m1, int m2,
int n, int p1, int p2)
{
I830Ptr pI830 = I830PTR(pScrn);
int p, m, vco, dotclock;
int min_m1, max_m1, min_m2, max_m2, min_m, max_m, min_n, max_n;
int min_p1, max_p1, min_p, max_p, min_vco, max_vco, min_dot, max_dot;
if (IS_I9XX(pI830)) {
min_m1 = 10;
max_m1 = 20;
min_m2 = 5;
max_m2 = 9;
min_m = 70;
max_m = 120;
min_n = 3;
max_n = 8;
min_p1 = 1;
max_p1 = 8;
if (i830PipeHasType (pScrn, pipe, I830_OUTPUT_LVDS)) {
min_p = 7;
max_p = 98;
} else {
min_p = 5;
max_p = 80;
}
min_vco = 1400000;
max_vco = 2800000;
min_dot = 20000;
max_dot = 400000;
} else {
min_m1 = 18;
max_m1 = 26;
min_m2 = 6;
max_m2 = 16;
min_m = 96;
max_m = 140;
min_n = 3;
max_n = 16;
min_p1 = 2;
max_p1 = 18;
min_vco = 930000;
max_vco = 1400000;
min_dot = 20000;
max_dot = 350000;
min_p = 4;
max_p = 128;
}
p = p1 * p2;
m = 5 * m1 + m2;
vco = refclk * m / n;
dotclock = i830_clock(refclk, m1, m2, n, p1, p2);
if (p1 < min_p1 || p1 > max_p1)
return FALSE;
if (p < min_p || p > max_p)
return FALSE;
if (m2 < min_m2 || m2 > max_m2)
return FALSE;
if (m1 < min_m1 || m1 > max_m1)
return FALSE;
if (m1 <= m2)
return FALSE;
if (m < min_m || m > max_m)
return FALSE;
if (n < min_n || n > max_n)
return FALSE;
if (vco < min_vco || vco > max_vco)
return FALSE;
/* XXX: We may need to be checking "Dot clock" depending on the multiplier,
* output, etc., rather than just a single range.
*/
if (dotclock < min_dot || dotclock > max_dot)
return FALSE;
return TRUE;
}
/**
* Returns a set of divisors for the desired target clock with the given refclk,
* or FALSE. Divisor values are the actual divisors for
* clk = refclk * (5 * m1 + m2) / n / (p1 * p2)
*/
static Bool
i830FindBestPLL(ScrnInfoPtr pScrn, int pipe, int target, int refclk,
int *outm1, int *outm2, int *outn, int *outp1, int *outp2)
{
I830Ptr pI830 = I830PTR(pScrn);
int m1, m2, n, p1, p2;
int err = target;
int min_m1, max_m1, min_m2, max_m2, min_n, max_n, min_p1, max_p1;
if (IS_I9XX(pI830)) {
min_m1 = 10;
max_m1 = 20;
min_m2 = 5;
max_m2 = 9;
min_n = 3;
max_n = 8;
min_p1 = 1;
max_p1 = 8;
if (i830PipeHasType (pScrn, pipe, I830_OUTPUT_LVDS)) {
/* The single-channel range is 25-112Mhz, and dual-channel
* is 80-224Mhz. Prefer single channel as much as possible.
*/
if (target < 112000)
p2 = 14;
else
p2 = 7;
} else {
if (target < 200000)
p2 = 10;
else
p2 = 5;
}
} else {
min_m1 = 18;
max_m1 = 26;
min_m2 = 6;
max_m2 = 16;
min_n = 3;
max_n = 16;
min_p1 = 2;
max_p1 = 18;
if (target < 165000)
p2 = 4;
else
p2 = 2;
}
for (m1 = min_m1; m1 <= max_m1; m1++) {
for (m2 = min_m2; m2 < max_m2; m2++) {
for (n = min_n; n <= max_n; n++) {
for (p1 = min_p1; p1 <= max_p1; p1++) {
int clock, this_err;
if (!i830PllIsValid(pScrn, pipe, refclk, m1, m2, n,
p1, p2)) {
continue;
}
clock = i830_clock(refclk, m1, m2, n, p1, p2);
this_err = abs(clock - target);
if (this_err < err) {
*outm1 = m1;
*outm2 = m2;
*outn = n;
*outp1 = p1;
*outp2 = p2;
err = this_err;
}
}
}
}
}
return (err != target);
}
void
i830WaitForVblank(ScrnInfoPtr pScreen)
{
/* Wait for 20ms, i.e. one cycle at 50hz. */
usleep(20000);
}
void
i830PipeSetBase(ScrnInfoPtr pScrn, int pipe, int x, int y)
{
I830Ptr pI830 = I830PTR(pScrn);
I830PipePtr pI830Pipe = &pI830->pipes[pipe];
unsigned long Start;
int dspbase = (pipe == 0 ? DSPABASE : DSPBBASE);
int dspsurf = (pipe == 0 ? DSPASURF : DSPBSURF);
if (I830IsPrimary(pScrn))
Start = pI830->FrontBuffer.Start;
else {
I830Ptr pI8301 = I830PTR(pI830->entityPrivate->pScrn_1);
Start = pI8301->FrontBuffer2.Start;
}
if (IS_I965G(pI830)) {
OUTREG(dspbase, ((y * pScrn->displayWidth + x) * pI830->cpp));
OUTREG(dspsurf, Start);
} else {
OUTREG(dspbase, Start + ((y * pScrn->displayWidth + x) * pI830->cpp));
}
pI830Pipe->x = x;
pI830Pipe->y = y;
}
/**
* In the current world order, there are lists of modes per output, which may
* or may not include the mode that was asked to be set by XFree86's mode
* selection. Find the closest one, in the following preference order:
*
* - Equality
* - Closer in size to the requested mode, but no larger
* - Closer in refresh rate to the requested mode.
*/
DisplayModePtr
i830PipeFindClosestMode(ScrnInfoPtr pScrn, int pipe, DisplayModePtr pMode)
{
I830Ptr pI830 = I830PTR(pScrn);
DisplayModePtr pBest = NULL, pScan = NULL;
int i;
/* Assume that there's only one output connected to the given CRTC. */
for (i = 0; i < pI830->num_outputs; i++) {
if (pI830->output[i].pipe == pipe &&
pI830->output[i].enabled &&
pI830->output[i].probed_modes != NULL)
{
pScan = pI830->output[i].probed_modes;
}
}
/* If the pipe doesn't have any detected modes, just let the system try to
* spam the desired mode in.
*/
if (pScan == NULL) {
xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
"No pipe mode list for pipe %d,"
"continuing with desired mode\n", pipe);
return pMode;
}
for (; pScan != NULL; pScan = pScan->next) {
assert(pScan->VRefresh != 0.0);
/* If there's an exact match, we're done. */
if (I830ModesEqual(pScan, pMode)) {
pBest = pMode;
break;
}
/* Reject if it's larger than the desired mode. */
if (pScan->HDisplay > pMode->HDisplay ||
pScan->VDisplay > pMode->VDisplay)
{
continue;
}
if (pBest == NULL) {
pBest = pScan;
continue;
}
/* Find if it's closer to the right size than the current best
* option.
*/
if ((pScan->HDisplay > pBest->HDisplay &&
pScan->VDisplay >= pBest->VDisplay) ||
(pScan->HDisplay >= pBest->HDisplay &&
pScan->VDisplay > pBest->VDisplay))
{
pBest = pScan;
continue;
}
/* Find if it's still closer to the right refresh than the current
* best resolution.
*/
if (pScan->HDisplay == pBest->HDisplay &&
pScan->VDisplay == pBest->VDisplay &&
(fabs(pScan->VRefresh - pMode->VRefresh) <
fabs(pBest->VRefresh - pMode->VRefresh))) {
pBest = pScan;
}
}
if (pBest == NULL) {
xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
"No suitable mode found to program for the pipe.\n"
" continuing with desired mode %dx%d@%.1f\n",
pMode->HDisplay, pMode->VDisplay, pMode->VRefresh);
} else if (!I830ModesEqual(pBest, pMode)) {
xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
"Choosing pipe %d's mode %dx%d@%.1f instead of xf86 "
"mode %dx%d@%.1f\n", pipe,
pBest->HDisplay, pBest->VDisplay, pBest->VRefresh,
pMode->HDisplay, pMode->VDisplay, pMode->VRefresh);
pMode = pBest;
}
return pMode;
}
/**
* Return whether any outputs are connected to the specified pipe
*/
Bool
i830PipeInUse (ScrnInfoPtr pScrn, int pipe)
{
I830Ptr pI830 = I830PTR(pScrn);
int i;
for (i = 0; i < pI830->num_outputs; i++)
if (pI830->output[i].enabled && pI830->output[i].pipe == pipe)
return TRUE;
return FALSE;
}
/**
* Sets the given video mode on the given pipe.
*
* Plane A is always output to pipe A, and plane B to pipe B. The plane
* will not be enabled if plane_enable is FALSE, which is used for
* load detection, when something else will be output to the pipe other than
* display data.
*/
Bool
i830PipeSetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode, int pipe,
Bool plane_enable)
{
I830Ptr pI830 = I830PTR(pScrn);
I830PipePtr pI830Pipe = &pI830->pipes[pipe];
int m1 = 0, m2 = 0, n = 0, p1 = 0, p2 = 0;
CARD32 dpll = 0, fp = 0, temp;
CARD32 htot, hblank, hsync, vtot, vblank, vsync, dspcntr;
CARD32 pipesrc, dspsize;
Bool ok, is_sdvo = FALSE, is_dvo = FALSE;
Bool is_crt = FALSE, is_lvds = FALSE, is_tv = FALSE;
int refclk, pixel_clock;
int i;
int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR;
int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
int fp_reg = (pipe == 0) ? FPA0 : FPB0;
int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B;
int htot_reg = (pipe == 0) ? HTOTAL_A : HTOTAL_B;
int hblank_reg = (pipe == 0) ? HBLANK_A : HBLANK_B;
int hsync_reg = (pipe == 0) ? HSYNC_A : HSYNC_B;
int vtot_reg = (pipe == 0) ? VTOTAL_A : VTOTAL_B;
int vblank_reg = (pipe == 0) ? VBLANK_A : VBLANK_B;
int vsync_reg = (pipe == 0) ? VSYNC_A : VSYNC_B;
int dspsize_reg = (pipe == 0) ? DSPASIZE : DSPBSIZE;
int dspstride_reg = (pipe == 0) ? DSPASTRIDE : DSPBSTRIDE;
int dsppos_reg = (pipe == 0) ? DSPAPOS : DSPBPOS;
int pipesrc_reg = (pipe == 0) ? PIPEASRC : PIPEBSRC;
Bool ret = FALSE;
#ifdef XF86DRI
Bool didLock = FALSE;
#endif
if (I830ModesEqual(&pI830Pipe->curMode, pMode))
return TRUE;
xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Requested pix clock: %d\n",
pMode->Clock);
pI830->pipes[pipe].enabled = i830PipeInUse (pScrn, pipe);
if (!pI830->pipes[pipe].enabled)
return TRUE;
#ifdef XF86DRI
didLock = I830DRILock(pScrn);
#endif
for (i = 0; i < pI830->num_outputs; i++) {
if (pI830->output[i].pipe != pipe || !pI830->output[i].enabled)
continue;
pI830->output[i].pre_set_mode(pScrn, &pI830->output[i], pMode);
switch (pI830->output[i].type) {
case I830_OUTPUT_LVDS:
is_lvds = TRUE;
break;
case I830_OUTPUT_SDVO:
is_sdvo = TRUE;
break;
case I830_OUTPUT_DVO:
is_dvo = TRUE;
break;
case I830_OUTPUT_TVOUT:
is_tv = TRUE;
break;
case I830_OUTPUT_ANALOG:
is_crt = TRUE;
break;
}
}
if (is_lvds && (is_sdvo || is_dvo || is_tv || is_crt)) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
"Can't enable LVDS and non-LVDS on the same pipe\n");
goto done;
}
if (is_tv && (is_sdvo || is_dvo || is_crt || is_lvds)) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
"Can't enable a TV and any other output on the same "
"pipe\n");
goto done;
}
if (pipe == 0 && is_lvds) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
"Can't support LVDS on pipe A\n");
goto done;
}
htot = (pMode->CrtcHDisplay - 1) | ((pMode->CrtcHTotal - 1) << 16);
hblank = (pMode->CrtcHBlankStart - 1) | ((pMode->CrtcHBlankEnd - 1) << 16);
hsync = (pMode->CrtcHSyncStart - 1) | ((pMode->CrtcHSyncEnd - 1) << 16);
vtot = (pMode->CrtcVDisplay - 1) | ((pMode->CrtcVTotal - 1) << 16);
vblank = (pMode->CrtcVBlankStart - 1) | ((pMode->CrtcVBlankEnd - 1) << 16);
vsync = (pMode->CrtcVSyncStart - 1) | ((pMode->CrtcVSyncEnd - 1) << 16);
pipesrc = ((pMode->HDisplay - 1) << 16) | (pMode->VDisplay - 1);
dspsize = ((pMode->VDisplay - 1) << 16) | (pMode->HDisplay - 1);
pixel_clock = pMode->Clock;
if (is_lvds && pI830->panel_fixed_hactive != 0) {
/* To enable panel fitting, we need to set the pipe timings to that of
* the screen at its full resolution. So, drop the timings from the
* BIOS VBT tables here.
*/
htot = (pI830->panel_fixed_hactive - 1) |
((pI830->panel_fixed_hactive + pI830->panel_fixed_hblank - 1)
<< 16);
hblank = (pI830->panel_fixed_hactive - 1) |
((pI830->panel_fixed_hactive + pI830->panel_fixed_hblank - 1)
<< 16);
hsync = (pI830->panel_fixed_hactive + pI830->panel_fixed_hsyncoff - 1) |
((pI830->panel_fixed_hactive + pI830->panel_fixed_hsyncoff +
pI830->panel_fixed_hsyncwidth - 1) << 16);
vtot = (pI830->panel_fixed_vactive - 1) |
((pI830->panel_fixed_vactive + pI830->panel_fixed_vblank - 1)
<< 16);
vblank = (pI830->panel_fixed_vactive - 1) |
((pI830->panel_fixed_vactive + pI830->panel_fixed_vblank - 1)
<< 16);
vsync = (pI830->panel_fixed_vactive + pI830->panel_fixed_vsyncoff - 1) |
((pI830->panel_fixed_vactive + pI830->panel_fixed_vsyncoff +
pI830->panel_fixed_vsyncwidth - 1) << 16);
pixel_clock = pI830->panel_fixed_clock;
if (pMode->HDisplay <= pI830->panel_fixed_hactive &&
pMode->HDisplay <= pI830->panel_fixed_vactive)
{
pipesrc = ((pMode->HDisplay - 1) << 16) |
(pMode->VDisplay - 1);
dspsize = ((pMode->VDisplay - 1) << 16) |
(pMode->HDisplay - 1);
}
}
/* Adjust the clock for pixel multiplication.
* See DPLL_MD_UDI_MULTIPLIER_MASK.
*/
if (is_sdvo) {
pixel_clock *= i830_sdvo_get_pixel_multiplier(pMode);
}
if (IS_I9XX(pI830)) {
refclk = 96000;
} else {
refclk = 48000;
}
ok = i830FindBestPLL(pScrn, pipe, pixel_clock, refclk, &m1, &m2, &n,
&p1, &p2);
if (!ok) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
"Couldn't find PLL settings for mode!\n");
goto done;
}
dpll = DPLL_VCO_ENABLE | DPLL_VGA_MODE_DIS;
if (IS_I9XX(pI830)) {
if (is_lvds)
dpll |= DPLLB_MODE_LVDS;
else
dpll |= DPLLB_MODE_DAC_SERIAL;
dpll |= (1 << (p1 - 1)) << 16;
switch (p2) {
case 5:
dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_5;
break;
case 7:
dpll |= DPLLB_LVDS_P2_CLOCK_DIV_7;
break;
case 10:
dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_10;
break;
case 14:
dpll |= DPLLB_LVDS_P2_CLOCK_DIV_14;
break;
}
if (IS_I965G(pI830))
dpll |= (6 << PLL_LOAD_PULSE_PHASE_SHIFT);
} else {
dpll |= (p1 - 2) << 16;
if (p2 == 4)
dpll |= PLL_P2_DIVIDE_BY_4;
}
if (is_tv)
dpll |= PLL_REF_INPUT_TVCLKINBC;
#if 0
else if (is_lvds)
dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN;
#endif
else
dpll |= PLL_REF_INPUT_DREFCLK;
fp = ((n - 2) << 16) | ((m1 - 2) << 8) | (m2 - 2);
#if 1
ErrorF("hact: %d htot: %d hbstart: %d hbend: %d hsyncstart: %d hsyncend: %d\n",
(int)(htot & 0xffff) + 1, (int)(htot >> 16) + 1,
(int)(hblank & 0xffff) + 1, (int)(hblank >> 16) + 1,
(int)(hsync & 0xffff) + 1, (int)(hsync >> 16) + 1);
ErrorF("vact: %d vtot: %d vbstart: %d vbend: %d vsyncstart: %d vsyncend: %d\n",
(int)(vtot & 0xffff) + 1, (int)(vtot >> 16) + 1,
(int)(vblank & 0xffff) + 1, (int)(vblank >> 16) + 1,
(int)(vsync & 0xffff) + 1, (int)(vsync >> 16) + 1);
ErrorF("pipesrc: %dx%d, dspsize: %dx%d\n",
(int)(pipesrc >> 16) + 1, (int)(pipesrc & 0xffff) + 1,
(int)(dspsize & 0xffff) + 1, (int)(dspsize >> 16) + 1);
#endif
i830PrintPll("chosen", refclk, m1, m2, n, p1, p2);
ErrorF("clock regs: 0x%08x, 0x%08x\n", (int)dpll, (int)fp);
dspcntr = DISPLAY_PLANE_ENABLE;
switch (pScrn->bitsPerPixel) {
case 8:
dspcntr |= DISPPLANE_8BPP | DISPPLANE_GAMMA_ENABLE;
break;
case 16:
if (pScrn->depth == 15)
dspcntr |= DISPPLANE_15_16BPP;
else
dspcntr |= DISPPLANE_16BPP;
break;
case 32:
dspcntr |= DISPPLANE_32BPP_NO_ALPHA;
break;
default:
FatalError("unknown display bpp\n");
}
if (pI830Pipe->gammaEnabled) {
dspcntr |= DISPPLANE_GAMMA_ENABLE;
}
if (pipe == 0)
dspcntr |= DISPPLANE_SEL_PIPE_A;
else
dspcntr |= DISPPLANE_SEL_PIPE_B;
OUTREG(VGACNTRL, VGA_DISP_DISABLE);
/* Finally, set the mode. */
/* First, disable display planes */
temp = INREG(dspcntr_reg);
OUTREG(dspcntr_reg, temp & ~DISPLAY_PLANE_ENABLE);
/* Wait for vblank for the disable to take effect */
i830WaitForVblank(pScrn);
/* Next, disable display pipes */
temp = INREG(pipeconf_reg);
OUTREG(pipeconf_reg, temp & ~PIPEACONF_ENABLE);
OUTREG(fp_reg, fp);
OUTREG(dpll_reg, dpll);
/*
* If the panel fitter is stuck on our pipe, turn it off.
* The LVDS output will set it as necessary in post_set_mode.
*/
if (!IS_I830(pI830)) {
if (((INREG(PFIT_CONTROL) >> 29) & 0x3) == pipe)
OUTREG(PFIT_CONTROL, 0);
}
for (i = 0; i < pI830->num_outputs; i++) {
if (pI830->output[i].pipe == pipe)
pI830->output[i].post_set_mode(pScrn, &pI830->output[i], pMode);
}
OUTREG(htot_reg, htot);
OUTREG(hblank_reg, hblank);
OUTREG(hsync_reg, hsync);
OUTREG(vtot_reg, vtot);
OUTREG(vblank_reg, vblank);
OUTREG(vsync_reg, vsync);
OUTREG(dspstride_reg, pScrn->displayWidth * pI830->cpp);
OUTREG(dspsize_reg, dspsize);
OUTREG(dsppos_reg, 0);
i830PipeSetBase(pScrn, pipe, pI830Pipe->x, pI830Pipe->y);
OUTREG(pipesrc_reg, pipesrc);
/* Then, turn the pipe on first */
temp = INREG(pipeconf_reg);
OUTREG(pipeconf_reg, temp | PIPEACONF_ENABLE);
if (plane_enable) {
/* And then turn the plane on */
OUTREG(dspcntr_reg, dspcntr);
}
pI830Pipe->curMode = *pMode;
ret = TRUE;
done:
#ifdef XF86DRI
if (didLock)
I830DRIUnlock(pScrn);
#endif
return ret;
}
void
i830DisableUnusedFunctions(ScrnInfoPtr pScrn)
{
I830Ptr pI830 = I830PTR(pScrn);
int output, pipe;
xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Disabling unused functions\n");
for (output = 0; output < pI830->num_outputs; output++) {
if (!pI830->output[output].enabled)
pI830->output[output].dpms(pScrn, &pI830->output[output], DPMSModeOff);
}
/* Now, any unused plane, pipe, and DPLL (FIXME: except for DVO, i915
* internal TV) should have no outputs trying to pull data out of it, so
* we're ready to turn those off.
*/
for (pipe = 0; pipe < pI830->num_pipes; pipe++) {
I830PipePtr pI830Pipe = &pI830->pipes[pipe];
int dspcntr_reg = pipe == 0 ? DSPACNTR : DSPBCNTR;
int pipeconf_reg = pipe == 0 ? PIPEACONF : PIPEBCONF;
int dpll_reg = pipe == 0 ? DPLL_A : DPLL_B;
CARD32 dspcntr, pipeconf, dpll;
char *pipe_name = pipe == 0 ? "A" : "B";
if (pI830Pipe->enabled)
continue;
dspcntr = INREG(dspcntr_reg);
if (dspcntr & DISPLAY_PLANE_ENABLE) {
xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Disabling plane %s\n",
pipe_name);
OUTREG(dspcntr_reg, dspcntr & ~DISPLAY_PLANE_ENABLE);
/* Wait for vblank for the disable to take effect */
i830WaitForVblank(pScrn);
}
pipeconf = INREG(pipeconf_reg);
if (pipeconf & PIPEACONF_ENABLE) {
xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Disabling pipe %s\n",
pipe_name);
OUTREG(pipeconf_reg, pipeconf & ~PIPEACONF_ENABLE);
}
dpll = INREG(dpll_reg);
if (dpll & DPLL_VCO_ENABLE) {
xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Disabling DPLL %s\n",
pipe_name);
OUTREG(dpll_reg, dpll & ~DPLL_VCO_ENABLE);
}
memset(&pI830Pipe->curMode, 0, sizeof(pI830Pipe->curMode));
}
}
/**
* This function configures the screens in clone mode on
* all active outputs using a mode similar to the specified mode.
*/
Bool
i830SetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode)
{
I830Ptr pI830 = I830PTR(pScrn);
Bool ok = TRUE;
int i;
DPRINTF(PFX, "i830SetMode\n");
for (i = 0; i < pI830->num_pipes; i++)
{
ok = i830PipeSetMode(pScrn,
i830PipeFindClosestMode(pScrn, i, pMode),
i, TRUE);
if (!ok)
goto done;
}
xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Mode bandwidth is %d Mpixel/s\n",
(int)(pMode->HDisplay * pMode->VDisplay *
pMode->VRefresh / 1000000));
if (pI830->savedCurrentMode) {
/* We're done with the currentMode that the last randr probe had left
* behind, so free it.
*/
xfree(pI830->savedCurrentMode->name);
xfree(pI830->savedCurrentMode);
pI830->savedCurrentMode = NULL;
/* If we might have enabled/disabled some pipes, we need to reset
* cloning mode support.
*/
if (pI830->pipes[0].enabled && pI830->pipes[1].enabled)
pI830->Clone = TRUE;
else
pI830->Clone = FALSE;
/* If HW cursor currently showing, reset cursor state */
if (pI830->CursorInfoRec && !pI830->SWCursor && pI830->cursorOn)
pI830->CursorInfoRec->ShowCursor(pScrn);
}
i830DisableUnusedFunctions(pScrn);
i830DescribeOutputConfiguration(pScrn);
#ifdef XF86DRI
I830DRISetVBlankInterrupt (pScrn, TRUE);
#endif
done:
i830DumpRegs (pScrn);
i830_sdvo_dump(pScrn);
return ok;
}
void
i830DescribeOutputConfiguration(ScrnInfoPtr pScrn)
{
I830Ptr pI830 = I830PTR(pScrn);
int i;
xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Output configuration:\n");
for (i = 0; i < pI830->num_pipes; i++) {
CARD32 dspcntr = INREG(DSPACNTR + (DSPBCNTR - DSPACNTR) * i);
CARD32 pipeconf = INREG(PIPEACONF + (PIPEBCONF - PIPEACONF) * i);
Bool hw_plane_enable = (dspcntr & DISPLAY_PLANE_ENABLE) != 0;
Bool hw_pipe_enable = (pipeconf & PIPEACONF_ENABLE) != 0;
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
" Pipe %c is %s\n",
'A' + i, pI830->pipes[i].enabled ? "on" : "off");
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
" Display plane %c is now %s and connected to pipe %c.\n",
'A' + i,
pI830->pipes[i].enabled ? "enabled" : "disabled",
dspcntr & DISPPLANE_SEL_PIPE_MASK ? 'B' : 'A');
if (hw_pipe_enable != pI830->pipes[i].enabled) {
xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
" Hardware claims pipe %c is %s while software "
"believes it is %s\n",
'A' + i, hw_pipe_enable ? "on" : "off",
pI830->pipes[i].enabled ? "on" : "off");
}
if (hw_plane_enable != pI830->pipes[i].enabled) {
xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
" Hardware claims plane %c is %s while software "
"believes it is %s\n",
'A' + i, hw_plane_enable ? "on" : "off",
pI830->pipes[i].enabled ? "on" : "off");
}
}
for (i = 0; i < pI830->num_outputs; i++) {
const char *name = NULL;
switch (pI830->output[i].type) {
case I830_OUTPUT_ANALOG:
name = "CRT";
break;
case I830_OUTPUT_LVDS:
name = "LVDS";
break;
case I830_OUTPUT_SDVO:
name = "SDVO";
break;
case I830_OUTPUT_DVO:
name = "DVO";
break;
case I830_OUTPUT_TVOUT:
name = "TV";
break;
}
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
" Output %s is %sabled and connected to pipe %c\n",
name, pI830->output[i].enabled ? "en" : "dis",
pI830->output[i].pipe == 0 ? 'A' : 'B');
}
}
/**
* Get a pipe with a simple mode set on it for doing load-based monitor
* detection.
*
* It will be up to the load-detect code to adjust the pipe as appropriate for
* its requirements. The pipe will be connected to no other outputs.
*
* Currently this code will only succeed if there is a pipe with no outputs
* configured for it. In the future, it could choose to temporarily disable
* some outputs to free up a pipe for its use.
*
* \return monitor number, or -1 if no pipes are available.
*/
int
i830GetLoadDetectPipe(ScrnInfoPtr pScrn, I830OutputPtr output)
{
I830Ptr pI830 = I830PTR(pScrn);
int i;
/* VESA 640x480x72Hz mode to set on the pipe */
DisplayModeRec mode = {
NULL, NULL, "640x480", MODE_OK, M_T_DEFAULT,
31500,
640, 664, 704, 832, 0,
480, 489, 491, 520, 0,
V_NHSYNC | V_NVSYNC,
0, 0,
0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
FALSE, FALSE, 0, NULL, 0, 0.0, 0.0
};
/* If the output is not marked disabled, check if it's already assigned
* to an active pipe, and is alone on that pipe. If so, we're done.
*/
if (output->enabled) {
int pipeconf_reg = (output->pipe == 0) ? PIPEACONF : PIPEBCONF;
if (INREG(pipeconf_reg) & PIPEACONF_ENABLE) {
/* Actually, maybe we don't need to be all alone on the pipe.
* The worst that should happen is false positives. Need to test,
* but actually fixing this during server startup is messy.
*/
#if 0
for (i = 0; i < pI830->num_outputs; i++) {
if (&pI830->output[i] != output &&
pI830->output[i].pipe == output->pipe)
{
return -1;
}
}
#endif
return output->pipe;
}
}
for (i = 0; i < pI830->num_pipes; i++)
if (!i830PipeInUse(pScrn, i))
break;
if (i == pI830->num_pipes)
return -1;
output->load_detect_temp = TRUE;
output->pipe = i;
output->enabled = TRUE;
I830xf86SetModeCrtc(&mode, INTERLACE_HALVE_V);
i830PipeSetMode(pScrn, &mode, i, FALSE);
return i;
}
void
i830ReleaseLoadDetectPipe(ScrnInfoPtr pScrn, I830OutputPtr output)
{
if (output->load_detect_temp) {
output->enabled = FALSE;
i830DisableUnusedFunctions(pScrn);
output->load_detect_temp = FALSE;
}
}

40
src/i830_display.h Normal file
View File

@ -0,0 +1,40 @@
/*
* Copyright © 2006 Intel Corporation
*
* 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
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* 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 NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS 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.
*
* Authors:
* Eric Anholt <eric@anholt.net>
*
*/
/* i830_display.c */
DisplayModePtr
i830PipeFindClosestMode(ScrnInfoPtr pScrn, int pipe, DisplayModePtr pMode);
Bool i830PipeSetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode, int pipe,
Bool plane_enable);
void i830DisableUnusedFunctions(ScrnInfoPtr pScrn);
Bool i830SetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode);
void i830PipeSetBase(ScrnInfoPtr pScrn, int pipe, int x, int y);
void i830WaitForVblank(ScrnInfoPtr pScrn);
void i830DescribeOutputConfiguration(ScrnInfoPtr pScrn);
int i830GetLoadDetectPipe(ScrnInfoPtr pScrn, I830OutputPtr output);
void i830ReleaseLoadDetectPipe(ScrnInfoPtr pScrn, I830OutputPtr output);
Bool i830PipeInUse(ScrnInfoPtr pScrn, int pipe);

View File

@ -1513,11 +1513,12 @@ I830DRISetVBlankInterrupt (ScrnInfoPtr pScrn, Bool on)
if (pI830->directRenderingEnabled && pI830->drmMinor >= 5) {
if (on) {
if (pI830->planeEnabled[1]) {
if (pI830->pipes[1].enabled) {
if (pI830->drmMinor >= 6)
pipe.pipe = DRM_I830_VBLANK_PIPE_A | DRM_I830_VBLANK_PIPE_B;
else
pipe.pipe = DRM_I830_VBLANK_PIPE_B;
pipe.pipe = DRM_I830_VBLANK_PIPE_B;
} else
pipe.pipe = DRM_I830_VBLANK_PIPE_A;
} else {

File diff suppressed because it is too large Load Diff

236
src/i830_dvo.c Normal file
View File

@ -0,0 +1,236 @@
/**************************************************************************
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.
******
********************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "xf86.h"
#include "i830.h"
#include "i810_reg.h"
#include "sil164/sil164.h"
#include "ch7xxx/ch7xxx.h"
static const char *SIL164Symbols[] = {
"Sil164VidOutput",
NULL
};
static const char *CH7xxxSymbols[] = {
"CH7xxxVidOutput",
NULL
};
/* driver list */
struct _I830DVODriver i830_dvo_drivers[] =
{
{ I830_DVO_CHIP_TMDS, "sil164", "SIL164VidOutput",
(SIL164_ADDR_1<<1), SIL164Symbols, NULL , NULL, NULL},
{ I830_DVO_CHIP_TMDS | I830_DVO_CHIP_TVOUT, "ch7xxx", "CH7xxxVidOutput",
(CH7xxx_ADDR_1<<1), CH7xxxSymbols, NULL , NULL, NULL}
};
#define I830_NUM_DVO_DRIVERS (sizeof(i830_dvo_drivers)/sizeof(struct _I830DVODriver))
static void
i830_dvo_dpms(ScrnInfoPtr pScrn, I830OutputPtr output, int mode)
{
if (mode == DPMSModeOn)
output->i2c_drv->vid_rec->Power(output->i2c_drv->dev_priv, TRUE);
else
output->i2c_drv->vid_rec->Power(output->i2c_drv->dev_priv, FALSE);
}
static void
i830_dvo_save(ScrnInfoPtr pScrn, I830OutputPtr output)
{
I830Ptr pI830 = I830PTR(pScrn);
/* Each output should probably just save the registers it touches, but for
* now, use more overkill.
*/
pI830->saveDVOA = INREG(DVOA);
pI830->saveDVOB = INREG(DVOB);
pI830->saveDVOC = INREG(DVOC);
output->i2c_drv->vid_rec->SaveRegs(output->i2c_drv->dev_priv);
}
static void
i830_dvo_restore(ScrnInfoPtr pScrn, I830OutputPtr output)
{
I830Ptr pI830 = I830PTR(pScrn);
OUTREG(DVOA, pI830->saveDVOA);
OUTREG(DVOB, pI830->saveDVOB);
OUTREG(DVOC, pI830->saveDVOC);
output->i2c_drv->vid_rec->RestoreRegs(output->i2c_drv->dev_priv);
}
static int
i830_dvo_mode_valid(ScrnInfoPtr pScrn, I830OutputPtr output,
DisplayModePtr pMode)
{
if (pMode->Flags & V_DBLSCAN)
return MODE_NO_DBLESCAN;
/* XXX: Validate clock range */
if (output->i2c_drv->vid_rec->ModeValid(output->i2c_drv->dev_priv, pMode))
return MODE_OK;
else
return MODE_BAD;
}
static void
i830_dvo_pre_set_mode(ScrnInfoPtr pScrn, I830OutputPtr output,
DisplayModePtr pMode)
{
I830Ptr pI830 = I830PTR(pScrn);
output->i2c_drv->vid_rec->Mode(output->i2c_drv->dev_priv, pMode);
OUTREG(DVOC, INREG(DVOC) & ~DVO_ENABLE);
}
static void
i830_dvo_post_set_mode(ScrnInfoPtr pScrn, I830OutputPtr output,
DisplayModePtr pMode)
{
I830Ptr pI830 = I830PTR(pScrn);
CARD32 dvo;
int dpll_reg = (output->pipe == 0) ? DPLL_A : DPLL_B;
/* Save the data order, since I don't know what it should be set to. */
dvo = INREG(DVOC) & (DVO_PRESERVE_MASK | DVO_DATA_ORDER_GBRG);
dvo |= DVO_ENABLE;
dvo |= DVO_DATA_ORDER_FP | DVO_BORDER_ENABLE | DVO_BLANK_ACTIVE_HIGH;
if (output->pipe == 1)
dvo |= DVO_PIPE_B_SELECT;
if (pMode->Flags & V_PHSYNC)
dvo |= DVO_HSYNC_ACTIVE_HIGH;
if (pMode->Flags & V_PVSYNC)
dvo |= DVO_VSYNC_ACTIVE_HIGH;
OUTREG(dpll_reg, INREG(dpll_reg) | DPLL_DVO_HIGH_SPEED);
/*OUTREG(DVOB_SRCDIM, (pMode->HDisplay << DVO_SRCDIM_HORIZONTAL_SHIFT) |
(pMode->VDisplay << DVO_SRCDIM_VERTICAL_SHIFT));*/
OUTREG(DVOC_SRCDIM, (pMode->HDisplay << DVO_SRCDIM_HORIZONTAL_SHIFT) |
(pMode->VDisplay << DVO_SRCDIM_VERTICAL_SHIFT));
/*OUTREG(DVOB, dvo);*/
OUTREG(DVOC, dvo);
}
/**
* Detect the output connection on our DVO device.
*
* Unimplemented.
*/
static enum detect_status
i830_dvo_detect(ScrnInfoPtr pScrn, I830OutputPtr output)
{
return OUTPUT_STATUS_UNKNOWN;
}
static Bool
I830I2CDetectDVOControllers(ScrnInfoPtr pScrn, I2CBusPtr pI2CBus,
struct _I830DVODriver **retdrv)
{
int i;
void *ret_ptr;
struct _I830DVODriver *drv;
for (i = 0; i < I830_NUM_DVO_DRIVERS; i++) {
drv = &i830_dvo_drivers[i];
drv->modhandle = xf86LoadSubModule(pScrn, drv->modulename);
if (drv->modhandle == NULL)
continue;
xf86LoaderReqSymLists(drv->symbols, NULL);
ret_ptr = NULL;
drv->vid_rec = LoaderSymbol(drv->fntablename);
if (drv->vid_rec != NULL)
ret_ptr = drv->vid_rec->Detect(pI2CBus, drv->address);
if (ret_ptr != NULL) {
drv->dev_priv = ret_ptr;
*retdrv = drv;
return TRUE;
}
xf86UnloadSubModule(drv->modhandle);
}
return FALSE;
}
void
i830_dvo_init(ScrnInfoPtr pScrn)
{
I830Ptr pI830 = I830PTR(pScrn);
Bool ret;
int i = pI830->num_outputs;
pI830->output[i].type = I830_OUTPUT_DVO;
pI830->output[i].dpms = i830_dvo_dpms;
pI830->output[i].save = i830_dvo_save;
pI830->output[i].restore = i830_dvo_restore;
pI830->output[i].mode_valid = i830_dvo_mode_valid;
pI830->output[i].pre_set_mode = i830_dvo_pre_set_mode;
pI830->output[i].post_set_mode = i830_dvo_post_set_mode;
pI830->output[i].detect = i830_dvo_detect;
pI830->output[i].get_modes = i830_ddc_get_modes;
/* Set up the I2C and DDC buses */
ret = I830I2CInit(pScrn, &pI830->output[i].pI2CBus, GPIOE, "DVOI2C_E");
if (!ret)
return;
ret = I830I2CInit(pScrn, &pI830->output[i].pDDCBus, GPIOD, "DVODDC_D");
if (!ret) {
xf86DestroyI2CBusRec(pI830->output[i].pI2CBus, TRUE, TRUE);
return;
}
/* Now, try to find a controller */
ret = I830I2CDetectDVOControllers(pScrn, pI830->output[i].pI2CBus,
&pI830->output[i].i2c_drv);
if (ret) {
xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Found i2c %s on %08lX\n",
pI830->output[i].i2c_drv->modulename,
pI830->output[i].pI2CBus->DriverPrivate.uval);
} else {
xf86DestroyI2CBusRec(pI830->output[i].pI2CBus, TRUE, TRUE);
xf86DestroyI2CBusRec(pI830->output[i].pDDCBus, TRUE, TRUE);
return;
}
pI830->num_outputs++;
}

353
src/i830_gtf.c Normal file
View File

@ -0,0 +1,353 @@
#define DEBUG_VERB 2
/*
* Copyright © 2002 David Dawes
*
* 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
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* 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 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 NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHOR(S) 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.
*
* Except as contained in this notice, the name of the author(s) shall
* not be used in advertising or otherwise to promote the sale, use or other
* dealings in this Software without prior written authorization from
* the author(s).
*
* Authors: David Dawes <dawes@xfree86.org>
*
* $XFree86: xc/programs/Xserver/hw/xfree86/os-support/vbe/vbeModes.c,v 1.6 2002/11/02 01:38:25 dawes Exp $
*/
/*
* Modified by Alan Hourihane <alanh@tungstengraphics.com>
* to support extended BIOS modes for the Intel chipsets
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <string.h>
#include "xf86.h"
#include "vbe.h"
#include "vbeModes.h"
#include "i830.h"
#include "i830_xf86Modes.h"
#include <math.h>
#define rint(x) floor(x)
#define MARGIN_PERCENT 1.8 /* % of active vertical image */
#define CELL_GRAN 8.0 /* assumed character cell granularity */
#define MIN_PORCH 1 /* minimum front porch */
#define V_SYNC_RQD 3 /* width of vsync in lines */
#define H_SYNC_PERCENT 8.0 /* width of hsync as % of total line */
#define MIN_VSYNC_PLUS_BP 550.0 /* min time of vsync + back porch (microsec) */
#define M 600.0 /* blanking formula gradient */
#define C 40.0 /* blanking formula offset */
#define K 128.0 /* blanking formula scaling factor */
#define J 20.0 /* blanking formula scaling factor */
/* C' and M' are part of the Blanking Duty Cycle computation */
#define C_PRIME (((C - J) * K/256.0) + J)
#define M_PRIME (K/256.0 * M)
DisplayModePtr
i830GetGTF(int h_pixels, int v_lines, float freq, int interlaced, int margins)
{
float h_pixels_rnd;
float v_lines_rnd;
float v_field_rate_rqd;
float top_margin;
float bottom_margin;
float interlace;
float h_period_est;
float vsync_plus_bp;
float v_back_porch;
float total_v_lines;
float v_field_rate_est;
float h_period;
float v_field_rate;
float v_frame_rate;
float left_margin;
float right_margin;
float total_active_pixels;
float ideal_duty_cycle;
float h_blank;
float total_pixels;
float pixel_freq;
float h_freq;
float h_sync;
float h_front_porch;
float v_odd_front_porch_lines;
DisplayModePtr m;
m = xnfcalloc(sizeof(DisplayModeRec), 1);
/* 1. In order to give correct results, the number of horizontal
* pixels requested is first processed to ensure that it is divisible
* by the character size, by rounding it to the nearest character
* cell boundary:
*
* [H PIXELS RND] = ((ROUND([H PIXELS]/[CELL GRAN RND],0))*[CELLGRAN RND])
*/
h_pixels_rnd = rint((float) h_pixels / CELL_GRAN) * CELL_GRAN;
/* 2. If interlace is requested, the number of vertical lines assumed
* by the calculation must be halved, as the computation calculates
* the number of vertical lines per field. In either case, the
* number of lines is rounded to the nearest integer.
*
* [V LINES RND] = IF([INT RQD?]="y", ROUND([V LINES]/2,0),
* ROUND([V LINES],0))
*/
v_lines_rnd = interlaced ?
rint((float) v_lines) / 2.0 :
rint((float) v_lines);
/* 3. Find the frame rate required:
*
* [V FIELD RATE RQD] = IF([INT RQD?]="y", [I/P FREQ RQD]*2,
* [I/P FREQ RQD])
*/
v_field_rate_rqd = interlaced ? (freq * 2.0) : (freq);
/* 4. Find number of lines in Top margin:
*
* [TOP MARGIN (LINES)] = IF([MARGINS RQD?]="Y",
* ROUND(([MARGIN%]/100*[V LINES RND]),0),
* 0)
*/
top_margin = margins ? rint(MARGIN_PERCENT / 100.0 * v_lines_rnd) : (0.0);
/* 5. Find number of lines in Bottom margin:
*
* [BOT MARGIN (LINES)] = IF([MARGINS RQD?]="Y",
* ROUND(([MARGIN%]/100*[V LINES RND]),0),
* 0)
*/
bottom_margin = margins ? rint(MARGIN_PERCENT/100.0 * v_lines_rnd) : (0.0);
/* 6. If interlace is required, then set variable [INTERLACE]=0.5:
*
* [INTERLACE]=(IF([INT RQD?]="y",0.5,0))
*/
interlace = interlaced ? 0.5 : 0.0;
/* 7. Estimate the Horizontal period
*
* [H PERIOD EST] = ((1/[V FIELD RATE RQD]) - [MIN VSYNC+BP]/1000000) /
* ([V LINES RND] + (2*[TOP MARGIN (LINES)]) +
* [MIN PORCH RND]+[INTERLACE]) * 1000000
*/
h_period_est = (((1.0/v_field_rate_rqd) - (MIN_VSYNC_PLUS_BP/1000000.0))
/ (v_lines_rnd + (2*top_margin) + MIN_PORCH + interlace)
* 1000000.0);
/* 8. Find the number of lines in V sync + back porch:
*
* [V SYNC+BP] = ROUND(([MIN VSYNC+BP]/[H PERIOD EST]),0)
*/
vsync_plus_bp = rint(MIN_VSYNC_PLUS_BP/h_period_est);
/* 9. Find the number of lines in V back porch alone:
*
* [V BACK PORCH] = [V SYNC+BP] - [V SYNC RND]
*
* XXX is "[V SYNC RND]" a typo? should be [V SYNC RQD]?
*/
v_back_porch = vsync_plus_bp - V_SYNC_RQD;
/* 10. Find the total number of lines in Vertical field period:
*
* [TOTAL V LINES] = [V LINES RND] + [TOP MARGIN (LINES)] +
* [BOT MARGIN (LINES)] + [V SYNC+BP] + [INTERLACE] +
* [MIN PORCH RND]
*/
total_v_lines = v_lines_rnd + top_margin + bottom_margin + vsync_plus_bp +
interlace + MIN_PORCH;
/* 11. Estimate the Vertical field frequency:
*
* [V FIELD RATE EST] = 1 / [H PERIOD EST] / [TOTAL V LINES] * 1000000
*/
v_field_rate_est = 1.0 / h_period_est / total_v_lines * 1000000.0;
/* 12. Find the actual horizontal period:
*
* [H PERIOD] = [H PERIOD EST] / ([V FIELD RATE RQD] / [V FIELD RATE EST])
*/
h_period = h_period_est / (v_field_rate_rqd / v_field_rate_est);
/* 13. Find the actual Vertical field frequency:
*
* [V FIELD RATE] = 1 / [H PERIOD] / [TOTAL V LINES] * 1000000
*/
v_field_rate = 1.0 / h_period / total_v_lines * 1000000.0;
/* 14. Find the Vertical frame frequency:
*
* [V FRAME RATE] = (IF([INT RQD?]="y", [V FIELD RATE]/2, [V FIELD RATE]))
*/
v_frame_rate = interlaced ? v_field_rate / 2.0 : v_field_rate;
/* 15. Find number of pixels in left margin:
*
* [LEFT MARGIN (PIXELS)] = (IF( [MARGINS RQD?]="Y",
* (ROUND( ([H PIXELS RND] * [MARGIN%] / 100 /
* [CELL GRAN RND]),0)) * [CELL GRAN RND],
* 0))
*/
left_margin = margins ?
rint(h_pixels_rnd * MARGIN_PERCENT / 100.0 / CELL_GRAN) * CELL_GRAN :
0.0;
/* 16. Find number of pixels in right margin:
*
* [RIGHT MARGIN (PIXELS)] = (IF( [MARGINS RQD?]="Y",
* (ROUND( ([H PIXELS RND] * [MARGIN%] / 100 /
* [CELL GRAN RND]),0)) * [CELL GRAN RND],
* 0))
*/
right_margin = margins ?
rint(h_pixels_rnd * MARGIN_PERCENT / 100.0 / CELL_GRAN) * CELL_GRAN :
0.0;
/* 17. Find total number of active pixels in image and left and right
* margins:
*
* [TOTAL ACTIVE PIXELS] = [H PIXELS RND] + [LEFT MARGIN (PIXELS)] +
* [RIGHT MARGIN (PIXELS)]
*/
total_active_pixels = h_pixels_rnd + left_margin + right_margin;
/* 18. Find the ideal blanking duty cycle from the blanking duty cycle
* equation:
*
* [IDEAL DUTY CYCLE] = [C'] - ([M']*[H PERIOD]/1000)
*/
ideal_duty_cycle = C_PRIME - (M_PRIME * h_period / 1000.0);
/* 19. Find the number of pixels in the blanking time to the nearest
* double character cell:
*
* [H BLANK (PIXELS)] = (ROUND(([TOTAL ACTIVE PIXELS] *
* [IDEAL DUTY CYCLE] /
* (100-[IDEAL DUTY CYCLE]) /
* (2*[CELL GRAN RND])), 0))
* * (2*[CELL GRAN RND])
*/
h_blank = rint(total_active_pixels *
ideal_duty_cycle /
(100.0 - ideal_duty_cycle) /
(2.0 * CELL_GRAN)) * (2.0 * CELL_GRAN);
/* 20. Find total number of pixels:
*
* [TOTAL PIXELS] = [TOTAL ACTIVE PIXELS] + [H BLANK (PIXELS)]
*/
total_pixels = total_active_pixels + h_blank;
/* 21. Find pixel clock frequency:
*
* [PIXEL FREQ] = [TOTAL PIXELS] / [H PERIOD]
*/
pixel_freq = total_pixels / h_period;
/* 22. Find horizontal frequency:
*
* [H FREQ] = 1000 / [H PERIOD]
*/
h_freq = 1000.0 / h_period;
/* Stage 1 computations are now complete; I should really pass
the results to another function and do the Stage 2
computations, but I only need a few more values so I'll just
append the computations here for now */
/* 17. Find the number of pixels in the horizontal sync period:
*
* [H SYNC (PIXELS)] =(ROUND(([H SYNC%] / 100 * [TOTAL PIXELS] /
* [CELL GRAN RND]),0))*[CELL GRAN RND]
*/
h_sync = rint(H_SYNC_PERCENT/100.0 * total_pixels / CELL_GRAN) * CELL_GRAN;
/* 18. Find the number of pixels in the horizontal front porch period:
*
* [H FRONT PORCH (PIXELS)] = ([H BLANK (PIXELS)]/2)-[H SYNC (PIXELS)]
*/
h_front_porch = (h_blank / 2.0) - h_sync;
/* 36. Find the number of lines in the odd front porch period:
*
* [V ODD FRONT PORCH(LINES)]=([MIN PORCH RND]+[INTERLACE])
*/
v_odd_front_porch_lines = MIN_PORCH + interlace;
/* finally, pack the results in the DisplayMode struct */
m->HDisplay = (int) (h_pixels_rnd);
m->HSyncStart = (int) (h_pixels_rnd + h_front_porch);
m->HSyncEnd = (int) (h_pixels_rnd + h_front_porch + h_sync);
m->HTotal = (int) (total_pixels);
m->VDisplay = (int) (v_lines_rnd);
m->VSyncStart = (int) (v_lines_rnd + v_odd_front_porch_lines);
m->VSyncEnd = (int) (int) (v_lines_rnd + v_odd_front_porch_lines + V_SYNC_RQD);
m->VTotal = (int) (total_v_lines);
m->Clock = (int)(pixel_freq * 1000);
m->SynthClock = m->Clock;
m->HSync = h_freq;
m->VRefresh = v_frame_rate /* freq */;
i830xf86SetModeDefaultName(m);
return (m);
}

324
src/i830_i2c.c Normal file
View File

@ -0,0 +1,324 @@
/**************************************************************************
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.
**************************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "xf86.h"
#include "xf86_OSproc.h"
#include "xf86Resources.h"
#include "xf86RAC.h"
#include "xf86cmap.h"
#include "compiler.h"
#include "mibstore.h"
#include "vgaHW.h"
#include "mipointer.h"
#include "micmap.h"
#include "shadowfb.h"
#include <X11/extensions/randr.h>
#include "fb.h"
#include "miscstruct.h"
#include "xf86xv.h"
#include <X11/extensions/Xv.h>
#include "shadow.h"
#include "i830.h"
#define AIRLIED_I2C 0
#if AIRLIED_I2C
#define I2C_TIMEOUT(x) /*(x)*/ /* Report timeouts */
#define I2C_TRACE(x) /*(x)*/ /* Report progress */
static void i830_setscl(I2CBusPtr b, int state)
{
ScrnInfoPtr pScrn = xf86Screens[b->scrnIndex];
I830Ptr pI830 = I830PTR(pScrn);
CARD32 val;
OUTREG(b->DriverPrivate.uval,
(state ? GPIO_CLOCK_VAL_OUT : 0) | GPIO_CLOCK_DIR_OUT |
GPIO_CLOCK_DIR_MASK | GPIO_CLOCK_VAL_MASK);
val = INREG(b->DriverPrivate.uval);
}
static void i830_setsda(I2CBusPtr b, int state)
{
ScrnInfoPtr pScrn = xf86Screens[b->scrnIndex];
I830Ptr pI830 = I830PTR(pScrn);
CARD32 val;
OUTREG(b->DriverPrivate.uval,
(state ? GPIO_DATA_VAL_OUT : 0) | GPIO_DATA_DIR_OUT |
GPIO_DATA_DIR_MASK | GPIO_DATA_VAL_MASK);
val = INREG(b->DriverPrivate.uval);
}
static void i830_getscl(I2CBusPtr b, int *state)
{
ScrnInfoPtr pScrn = xf86Screens[b->scrnIndex];
I830Ptr pI830 = I830PTR(pScrn);
CARD32 val;
OUTREG(b->DriverPrivate.uval, GPIO_CLOCK_DIR_IN | GPIO_CLOCK_DIR_MASK);
OUTREG(b->DriverPrivate.uval, 0);
val = INREG(b->DriverPrivate.uval);
*state = ((val & GPIO_DATA_VAL_IN) != 0);
}
static int i830_getsda(I2CBusPtr b)
{
ScrnInfoPtr pScrn = xf86Screens[b->scrnIndex];
I830Ptr pI830 = I830PTR(pScrn);
CARD32 val;
OUTREG(b->DriverPrivate.uval, GPIO_DATA_DIR_IN | GPIO_DATA_DIR_MASK);
OUTREG(b->DriverPrivate.uval, 0);
val = INREG(b->DriverPrivate.uval);
return ((val & GPIO_DATA_VAL_IN) != 0);
}
static inline void sdalo(I2CBusPtr b)
{
i830_setsda(b, 0);
b->I2CUDelay(b, b->RiseFallTime);
}
static inline void sdahi(I2CBusPtr b)
{
i830_setsda(b, 1);
b->I2CUDelay(b, b->RiseFallTime);
}
static inline void scllo(I2CBusPtr b)
{
i830_setscl(b, 0);
b->I2CUDelay(b, b->RiseFallTime);
}
static inline int sclhi(I2CBusPtr b, int timeout)
{
int scl = 0;
int i;
i830_setscl(b, 1);
b->I2CUDelay(b, b->RiseFallTime);
for (i = timeout; i > 0; i -= b->RiseFallTime) {
i830_getscl(b, &scl);
if (scl) break;
b->I2CUDelay(b, b->RiseFallTime);
}
if (i <= 0) {
I2C_TIMEOUT(ErrorF("[I2CRaiseSCL(<%s>, %d) timeout]",
b->BusName, timeout));
return FALSE;
}
return TRUE;
}
static Bool
I830I2CGetByte(I2CDevPtr d, I2CByte *data, Bool last)
{
I2CBusPtr b = d->pI2CBus;
int i, sda;
unsigned char indata = 0;
sdahi(b);
for (i = 0; i < 8; i++) {
if (sclhi(b, d->BitTimeout) == FALSE) {
I2C_TRACE(ErrorF("timeout at bit #%d\n", 7-i));
return FALSE;
};
indata *= 2;
if (i830_getsda(b))
indata |= 0x01;
scllo(b);
}
if (last) {
sdahi(b);
} else {
sdalo(b);
}
if (sclhi(b, d->BitTimeout) == FALSE) {
sdahi(b);
return FALSE;
};
scllo(b);
sdahi(b);
*data = indata & 0xff;
I2C_TRACE(ErrorF("R%02x ", (int) *data));
return TRUE;
}
static Bool
I830I2CPutByte(I2CDevPtr d, I2CByte c)
{
Bool r;
int i, scl, sda;
int sb, ack;
I2CBusPtr b = d->pI2CBus;
for (i = 7; i >= 0; i--) {
sb = c & (1 << i);
i830_setsda(b, sb);
b->I2CUDelay(b, b->RiseFallTime);
if (sclhi(b, d->ByteTimeout) == FALSE) {
sdahi(b);
return FALSE;
}
i830_setscl(b, 0);
b->I2CUDelay(b, b->RiseFallTime);
}
sdahi(b);
if (sclhi(b, d->ByteTimeout) == FALSE) {
I2C_TIMEOUT(ErrorF("[I2CPutByte(<%s>, 0x%02x, %d, %d, %d) timeout]",
b->BusName, c, d->BitTimeout,
d->ByteTimeout, d->AcknTimeout));
return FALSE;
}
ack = i830_getsda(b);
I2C_TRACE(ErrorF("Put byte 0x%02x , getsda() = %d\n", c & 0xff, ack));
scllo(b);
return (0 == ack);
}
static Bool
I830I2CStart(I2CBusPtr b, int timeout)
{
if (sclhi(b, timeout) == FALSE)
return FALSE;
sdalo(b);
scllo(b);
return TRUE;
}
static void
I830I2CStop(I2CDevPtr d)
{
I2CBusPtr b = d->pI2CBus;
sdalo(b);
sclhi(b, d->ByteTimeout);
sdahi(b);
}
static Bool
I830I2CAddress(I2CDevPtr d, I2CSlaveAddr addr)
{
if (I830I2CStart(d->pI2CBus, d->StartTimeout)) {
if (I830I2CPutByte(d, addr & 0xFF)) {
if ((addr & 0xF8) != 0xF0 &&
(addr & 0xFE) != 0x00)
return TRUE;
if (I830I2CPutByte(d, (addr >> 8) & 0xFF))
return TRUE;
}
I830I2CStop(d);
}
return FALSE;
}
#else
static void
i830I2CGetBits(I2CBusPtr b, int *clock, int *data)
{
ScrnInfoPtr pScrn = xf86Screens[b->scrnIndex];
I830Ptr pI830 = I830PTR(pScrn);
CARD32 val;
val = INREG(b->DriverPrivate.uval);
*data = (val & GPIO_DATA_VAL_IN) != 0;
*clock = (val & GPIO_CLOCK_VAL_IN) != 0;
}
static void
i830I2CPutBits(I2CBusPtr b, int clock, int data)
{
ScrnInfoPtr pScrn = xf86Screens[b->scrnIndex];
I830Ptr pI830 = I830PTR(pScrn);
OUTREG(b->DriverPrivate.uval,
(data ? GPIO_DATA_VAL_OUT : 0) |
(clock ? GPIO_CLOCK_VAL_OUT : 0) |
GPIO_CLOCK_DIR_OUT |
GPIO_DATA_DIR_OUT |
GPIO_CLOCK_DIR_MASK |
GPIO_CLOCK_VAL_MASK |
GPIO_DATA_DIR_MASK |
GPIO_DATA_VAL_MASK);
}
#endif
/* the i830 has a number of I2C Buses */
Bool
I830I2CInit(ScrnInfoPtr pScrn, I2CBusPtr *bus_ptr, int i2c_reg, char *name)
{
I2CBusPtr pI2CBus;
pI2CBus = xf86CreateI2CBusRec();
if (!pI2CBus)
return FALSE;
pI2CBus->BusName = name;
pI2CBus->scrnIndex = pScrn->scrnIndex;
#if AIRLIED_I2C
pI2CBus->I2CGetByte = I830I2CGetByte;
pI2CBus->I2CPutByte = I830I2CPutByte;
pI2CBus->I2CStart = I830I2CStart;
pI2CBus->I2CStop = I830I2CStop;
pI2CBus->I2CAddress = I830I2CAddress;
#else
pI2CBus->I2CGetBits = i830I2CGetBits;
pI2CBus->I2CPutBits = i830I2CPutBits;
#endif
pI2CBus->DriverPrivate.uval = i2c_reg;
if (!xf86I2CBusInit(pI2CBus))
return FALSE;
*bus_ptr = pI2CBus;
return TRUE;
}

278
src/i830_lvds.c Normal file
View File

@ -0,0 +1,278 @@
/*
* Copyright © 2006 Intel Corporation
*
* 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
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* 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 NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS 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.
*
* Authors:
* Eric Anholt <eric@anholt.net>
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "xf86.h"
#include "i830.h"
#include "i830_bios.h"
/**
* Sets the power state for the panel.
*/
static void
i830SetLVDSPanelPower(ScrnInfoPtr pScrn, Bool on)
{
I830Ptr pI830 = I830PTR(pScrn);
CARD32 pp_status, pp_control;
CARD32 blc_pwm_ctl;
int backlight_duty_cycle;
blc_pwm_ctl = INREG (BLC_PWM_CTL);
backlight_duty_cycle = blc_pwm_ctl & BACKLIGHT_DUTY_CYCLE_MASK;
if (backlight_duty_cycle)
pI830->backlight_duty_cycle = backlight_duty_cycle;
if (on) {
OUTREG(PP_STATUS, INREG(PP_STATUS) | PP_ON);
OUTREG(PP_CONTROL, INREG(PP_CONTROL) | POWER_TARGET_ON);
do {
pp_status = INREG(PP_STATUS);
pp_control = INREG(PP_CONTROL);
} while (!(pp_status & PP_ON) && !(pp_control & POWER_TARGET_ON));
OUTREG(BLC_PWM_CTL,
(blc_pwm_ctl & ~BACKLIGHT_DUTY_CYCLE_MASK) |
pI830->backlight_duty_cycle);
} else {
OUTREG(BLC_PWM_CTL,
(blc_pwm_ctl & ~BACKLIGHT_DUTY_CYCLE_MASK));
OUTREG(PP_STATUS, INREG(PP_STATUS) & ~PP_ON);
OUTREG(PP_CONTROL, INREG(PP_CONTROL) & ~POWER_TARGET_ON);
do {
pp_status = INREG(PP_STATUS);
pp_control = INREG(PP_CONTROL);
} while ((pp_status & PP_ON) || (pp_control & POWER_TARGET_ON));
}
}
static void
i830_lvds_dpms(ScrnInfoPtr pScrn, I830OutputPtr output, int mode)
{
if (mode == DPMSModeOn)
i830SetLVDSPanelPower(pScrn, TRUE);
else
i830SetLVDSPanelPower(pScrn, FALSE);
}
static void
i830_lvds_save(ScrnInfoPtr pScrn, I830OutputPtr output)
{
I830Ptr pI830 = I830PTR(pScrn);
pI830->savePP_ON = INREG(LVDSPP_ON);
pI830->savePP_OFF = INREG(LVDSPP_OFF);
pI830->saveLVDS = INREG(LVDS);
pI830->savePP_CONTROL = INREG(PP_CONTROL);
pI830->savePP_CYCLE = INREG(PP_CYCLE);
pI830->saveBLC_PWM_CTL = INREG(BLC_PWM_CTL);
pI830->backlight_duty_cycle = (pI830->saveBLC_PWM_CTL &
BACKLIGHT_DUTY_CYCLE_MASK);
/*
* If the light is off at server startup, just make it full brightness
*/
if (pI830->backlight_duty_cycle == 0) {
pI830->backlight_duty_cycle =
(pI830->saveBLC_PWM_CTL & BACKLIGHT_MODULATION_FREQ_MASK) >>
BACKLIGHT_MODULATION_FREQ_SHIFT;
}
}
static void
i830_lvds_restore(ScrnInfoPtr pScrn, I830OutputPtr output)
{
I830Ptr pI830 = I830PTR(pScrn);
OUTREG(BLC_PWM_CTL, pI830->saveBLC_PWM_CTL);
OUTREG(LVDSPP_ON, pI830->savePP_ON);
OUTREG(LVDSPP_OFF, pI830->savePP_OFF);
OUTREG(PP_CYCLE, pI830->savePP_CYCLE);
OUTREG(LVDS, pI830->saveLVDS);
OUTREG(PP_CONTROL, pI830->savePP_CONTROL);
if (pI830->savePP_CONTROL & POWER_TARGET_ON)
i830SetLVDSPanelPower(pScrn, TRUE);
else
i830SetLVDSPanelPower(pScrn, FALSE);
}
static int
i830_lvds_mode_valid(ScrnInfoPtr pScrn, I830OutputPtr output,
DisplayModePtr pMode)
{
return MODE_OK;
}
static void
i830_lvds_pre_set_mode(ScrnInfoPtr pScrn, I830OutputPtr output,
DisplayModePtr pMode)
{
/* Always make sure the LVDS is off before we play with DPLLs and pipe
* configuration. We can skip this in some cases (for example, going
* between hi-res modes with automatic panel scaling are fine), but be
* conservative for now.
*/
i830SetLVDSPanelPower(pScrn, FALSE);
}
static void
i830_lvds_post_set_mode(ScrnInfoPtr pScrn, I830OutputPtr output,
DisplayModePtr pMode)
{
I830Ptr pI830 = I830PTR(pScrn);
CARD32 pfit_control;
/* Enable automatic panel scaling so that non-native modes fill the
* screen. Should be enabled before the pipe is enabled, according to
* register description.
*/
pfit_control = (PFIT_ENABLE |
VERT_AUTO_SCALE | HORIZ_AUTO_SCALE |
VERT_INTERP_BILINEAR | HORIZ_INTERP_BILINEAR);
if (pI830->panel_wants_dither)
pfit_control |= PANEL_8TO6_DITHER_ENABLE;
OUTREG(PFIT_CONTROL, pfit_control);
/* Disable the PLL before messing with LVDS enable */
OUTREG(FPB0, INREG(FPB0) & ~DPLL_VCO_ENABLE);
/* LVDS must be powered on before PLL is enabled and before power
* sequencing the panel.
*/
OUTREG(LVDS, INREG(LVDS) | LVDS_PORT_EN | LVDS_PIPEB_SELECT);
/* Re-enable the PLL */
OUTREG(FPB0, INREG(FPB0) | DPLL_VCO_ENABLE);
i830SetLVDSPanelPower(pScrn, TRUE);
}
/**
* Detect the LVDS connection.
*
* This always returns OUTPUT_STATUS_CONNECTED. This output should only have
* been set up if the LVDS was actually connected anyway.
*/
static enum detect_status
i830_lvds_detect(ScrnInfoPtr pScrn, I830OutputPtr output)
{
return OUTPUT_STATUS_CONNECTED;
}
/**
* Return the list of DDC modes if available, or the BIOS fixed mode otherwise.
*/
static DisplayModePtr
i830_lvds_get_modes(ScrnInfoPtr pScrn, I830OutputPtr output)
{
I830Ptr pI830 = I830PTR(pScrn);
DisplayModePtr modes, new;
char stmp[32];
modes = i830_ddc_get_modes(pScrn, output);
if (modes != NULL)
return modes;
new = xnfcalloc(1, sizeof (DisplayModeRec));
sprintf(stmp, "%dx%d", pI830->PanelXRes, pI830->PanelYRes);
new->name = xnfalloc(strlen(stmp) + 1);
strcpy(new->name, stmp);
new->HDisplay = pI830->PanelXRes;
new->VDisplay = pI830->PanelYRes;
new->HSyncStart = pI830->panel_fixed_hactive + pI830->panel_fixed_hsyncoff;
new->HSyncEnd = new->HSyncStart + pI830->panel_fixed_hsyncwidth;
new->HTotal = new->HSyncEnd + 1;
new->VSyncStart = pI830->panel_fixed_vactive + pI830->panel_fixed_vsyncoff;
new->VSyncEnd = new->VSyncStart + pI830->panel_fixed_vsyncwidth;
new->VTotal = new->VSyncEnd + 1;
new->Clock = pI830->panel_fixed_clock;
new->type = M_T_PREFERRED;
return new;
}
void
i830_lvds_init(ScrnInfoPtr pScrn)
{
I830Ptr pI830 = I830PTR(pScrn);
/* Get the LVDS fixed mode out of the BIOS. We should support LVDS with
* the BIOS being unavailable or broken, but lack the configuration options
* for now.
*/
if (!i830GetLVDSInfoFromBIOS(pScrn))
return;
/* Blacklist machines with BIOSes that list an LVDS panel without actually
* having one.
*/
if (pI830->PciInfo->chipType == PCI_CHIP_I945_GM) {
if (pI830->PciInfo->subsysVendor == 0xa0a0) /* aopen mini pc */
return;
if ((pI830->PciInfo->subsysVendor == 0x8086) &&
(pI830->PciInfo->subsysCard == 0x7270)) {
/* It's a Mac Mini or Macbook Pro.
*
* Apple hardware is out to get us. The macbook pro has a real
* LVDS panel, but the mac mini does not, and they have the same
* device IDs. We'll distinguish by panel size, on the assumption
* that Apple isn't about to make any machines with an 800x600
* display.
*/
if (pI830->PanelXRes == 800 && pI830->PanelYRes == 600) {
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
"Suspected Mac Mini, ignoring the LVDS\n");
return;
}
}
}
pI830->output[pI830->num_outputs].type = I830_OUTPUT_LVDS;
pI830->output[pI830->num_outputs].dpms = i830_lvds_dpms;
pI830->output[pI830->num_outputs].save = i830_lvds_save;
pI830->output[pI830->num_outputs].restore = i830_lvds_restore;
pI830->output[pI830->num_outputs].mode_valid = i830_lvds_mode_valid;
pI830->output[pI830->num_outputs].pre_set_mode = i830_lvds_pre_set_mode;
pI830->output[pI830->num_outputs].post_set_mode = i830_lvds_post_set_mode;
pI830->output[pI830->num_outputs].detect = i830_lvds_detect;
pI830->output[pI830->num_outputs].get_modes = i830_lvds_get_modes;
/* Set up the LVDS DDC channel. Most panels won't support it, but it can
* be useful if available.
*/
I830I2CInit(pScrn, &pI830->output[pI830->num_outputs].pDDCBus,
GPIOC, "LVDSDDC_C");
pI830->num_outputs++;
}

View File

@ -65,10 +65,6 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
static int nextTile = 0;
static unsigned int tileGeneration = -1;
#ifndef ALLOCATE_ALL_BIOSMEM
#define ALLOCATE_ALL_BIOSMEM 1
#endif
static unsigned long
GetBestTileAlignment(unsigned long size)
{
@ -252,11 +248,7 @@ I830FreeVidMem(ScrnInfoPtr pScrn, I830MemRange *range)
* USE CAUTION when changing anything here...
*/
I830MemPool *Pool = range->Pool;
if (pI830->overrideBIOSMemSize &&
pI830->BIOSMemorySize > pI830->StolenMemory.Size)
Pool->Total.End = pI830->BIOSMemorySize;
else
Pool->Total.End = pI830->StolenMemory.End;
Pool->Total.End = pI830->StolenMemory.End;
if (pI830->StolenOnly)
Pool->Free.End += range->Size;
@ -783,7 +775,7 @@ I830Allocate2DMemory(ScrnInfoPtr pScrn, const int flags)
pI830->FbMemBox.x1 = 0;
pI830->FbMemBox.x2 = pScrn->displayWidth;
pI830->FbMemBox.y1 = 0;
if (!pI830->MergedFB && pScrn->virtualX > pScrn->virtualY)
if (pScrn->virtualX > pScrn->virtualY)
pI830->FbMemBox.y2 = pScrn->virtualX;
else
pI830->FbMemBox.y2 = pScrn->virtualY;
@ -855,7 +847,7 @@ I830Allocate2DMemory(ScrnInfoPtr pScrn, const int flags)
}
#if 1 /* ROTATION */
if (!pI830->MergedFB && pScrn->virtualX > pScrn->virtualY)
if (pScrn->virtualX > pScrn->virtualY)
size = lineSize * (pScrn->virtualX + cacheLines);
else
size = lineSize * (pScrn->virtualY + cacheLines);
@ -1115,13 +1107,6 @@ I830ResetAllocations(ScrnInfoPtr pScrn, const int flags)
#endif
pI830->StolenPool.Fixed = pI830->StolenMemory;
pI830->StolenPool.Total = pI830->StolenMemory;
#if ALLOCATE_ALL_BIOSMEM
if (pI830->overrideBIOSMemSize &&
pI830->BIOSMemorySize > pI830->StolenMemory.Size) {
pI830->StolenPool.Total.End = pI830->BIOSMemorySize;
pI830->StolenPool.Total.Size = pI830->BIOSMemorySize;
}
#endif
pI830->StolenPool.Free = pI830->StolenPool.Total;
pI830->FreeMemory = pI830->TotalVideoRam - pI830->StolenPool.Total.Size;
pI830->allocatedMemory = 0;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1067
src/i830_sdvo.c Normal file

File diff suppressed because it is too large Load Diff

35
src/i830_sdvo.h Normal file
View File

@ -0,0 +1,35 @@
/*
* Copyright © 2006 Intel Corporation
*
* 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
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* 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 NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS 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.
*
* Authors:
* Eric Anholt <eric@anholt.net>
*
*/
void
i830_sdvo_init(ScrnInfoPtr pScrn, int output_device);
int
i830_sdvo_get_pixel_multiplier(DisplayModePtr pMode);
void
i830_sdvo_dump(ScrnInfoPtr pScrn);

320
src/i830_sdvo_regs.h Normal file
View File

@ -0,0 +1,320 @@
/*
* Copyright © 2006 Intel Corporation
*
* 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
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* 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 NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS 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.
*
* Authors:
* Eric Anholt <eric@anholt.net>
*
*/
/**
* @file SDVO command definitions and structures.
*/
struct i830_sdvo_output_flags {
unsigned int tmds0:1;
unsigned int rgb0:1;
unsigned int cvbs0:1;
unsigned int svid0:1;
unsigned int yprpb0:1;
unsigned int scart0:1;
unsigned int lvds0:1;
unsigned int pad0:1;
unsigned int tmds1:1;
unsigned int pad1:4;
unsigned int rgb1:1;
unsigned int lvds1:1;
unsigned int pad2:1;
} __attribute__((packed));
struct i830_sdvo_caps {
CARD8 vendor_id;
CARD8 device_id;
CARD8 device_rev_id;
CARD8 sdvo_version_major;
CARD8 sdvo_version_minor;
unsigned int sdvo_inputs_mask:2;
unsigned int smooth_scaling:1;
unsigned int sharp_scaling:1;
unsigned int up_scaling:1;
unsigned int down_scaling:1;
unsigned int stall_support:1;
unsigned int pad:1;
struct i830_sdvo_output_flags output_flags;
} __attribute__((packed));
/** This matches the EDID DTD structure, more or less */
struct i830_sdvo_dtd {
struct {
CARD16 clock; /**< pixel clock, in 10kHz units */
CARD8 h_active; /**< lower 8 bits (pixels) */
CARD8 h_blank; /**< lower 8 bits (pixels) */
CARD8 h_high; /**< upper 4 bits each h_active, h_blank */
CARD8 v_active; /**< lower 8 bits (lines) */
CARD8 v_blank; /**< lower 8 bits (lines) */
CARD8 v_high; /**< upper 4 bits each v_active, v_blank */
} part1;
struct {
CARD8 h_sync_off; /**< lower 8 bits, from hblank start */
CARD8 h_sync_width; /**< lower 8 bits (pixels) */
/** lower 4 bits each vsync offset, vsync width */
CARD8 v_sync_off_width;
/**
* 2 high bits of hsync offset, 2 high bits of hsync width,
* bits 4-5 of vsync offset, and 2 high bits of vsync width.
*/
CARD8 sync_off_width_high;
CARD8 dtd_flags;
CARD8 sdvo_flags;
/** bits 6-7 of vsync offset at bits 6-7 */
CARD8 v_sync_off_high;
CARD8 reserved;
} part2;
} __attribute__((packed));
struct i830_sdvo_pixel_clock_range {
CARD16 min; /**< pixel clock, in 10kHz units */
CARD16 max; /**< pixel clock, in 10kHz units */
} __attribute__((packed));
struct i830_sdvo_preferred_input_timing_args {
CARD16 clock;
CARD16 width;
CARD16 height;
} __attribute__((packed));
/* I2C registers for SDVO */
#define SDVO_I2C_ARG_0 0x07
#define SDVO_I2C_ARG_1 0x06
#define SDVO_I2C_ARG_2 0x05
#define SDVO_I2C_ARG_3 0x04
#define SDVO_I2C_ARG_4 0x03
#define SDVO_I2C_ARG_5 0x02
#define SDVO_I2C_ARG_6 0x01
#define SDVO_I2C_ARG_7 0x00
#define SDVO_I2C_OPCODE 0x08
#define SDVO_I2C_CMD_STATUS 0x09
#define SDVO_I2C_RETURN_0 0x0a
#define SDVO_I2C_RETURN_1 0x0b
#define SDVO_I2C_RETURN_2 0x0c
#define SDVO_I2C_RETURN_3 0x0d
#define SDVO_I2C_RETURN_4 0x0e
#define SDVO_I2C_RETURN_5 0x0f
#define SDVO_I2C_RETURN_6 0x10
#define SDVO_I2C_RETURN_7 0x11
#define SDVO_I2C_VENDOR_BEGIN 0x20
/* Status results */
#define SDVO_CMD_STATUS_POWER_ON 0x0
#define SDVO_CMD_STATUS_SUCCESS 0x1
#define SDVO_CMD_STATUS_NOTSUPP 0x2
#define SDVO_CMD_STATUS_INVALID_ARG 0x3
#define SDVO_CMD_STATUS_PENDING 0x4
#define SDVO_CMD_STATUS_TARGET_NOT_SPECIFIED 0x5
#define SDVO_CMD_STATUS_SCALING_NOT_SUPP 0x6
/* SDVO commands, argument/result registers */
#define SDVO_CMD_RESET 0x01
/** Returns a struct i830_sdvo_caps */
#define SDVO_CMD_GET_DEVICE_CAPS 0x02
#define SDVO_CMD_GET_FIRMWARE_REV 0x86
# define SDVO_DEVICE_FIRMWARE_MINOR SDVO_I2C_RETURN_0
# define SDVO_DEVICE_FIRMWARE_MAJOR SDVO_I2C_RETURN_1
# define SDVO_DEVICE_FIRMWARE_PATCH SDVO_I2C_RETURN_2
/**
* Reports which inputs are trained (managed to sync).
*
* Devices must have trained within 2 vsyncs of a mode change.
*/
#define SDVO_CMD_GET_TRAINED_INPUTS 0x03
struct i830_sdvo_get_trained_inputs_response {
unsigned int input0_trained:1;
unsigned int input1_trained:1;
unsigned int pad:6;
} __attribute__((packed));
/** Returns a struct i830_sdvo_output_flags of active outputs. */
#define SDVO_CMD_GET_ACTIVE_OUTPUTS 0x04
/**
* Sets the current set of active outputs.
*
* Takes a struct i830_sdvo_output_flags. Must be preceded by a SET_IN_OUT_MAP
* on multi-output devices.
*/
#define SDVO_CMD_SET_ACTIVE_OUTPUTS 0x05
/**
* Returns the current mapping of SDVO inputs to outputs on the device.
*
* Returns two struct i830_sdvo_output_flags structures.
*/
#define SDVO_CMD_GET_IN_OUT_MAP 0x06
/**
* Sets the current mapping of SDVO inputs to outputs on the device.
*
* Takes two struct i380_sdvo_output_flags structures.
*/
#define SDVO_CMD_SET_IN_OUT_MAP 0x07
/**
* Returns a struct i830_sdvo_output_flags of attached displays.
*/
#define SDVO_CMD_GET_ATTACHED_DISPLAYS 0x0b
/**
* Returns a struct i830_sdvo_ouptut_flags of displays supporting hot plugging.
*/
#define SDVO_CMD_GET_HOT_PLUG_SUPPORT 0x0c
/**
* Takes a struct i830_sdvo_output_flags.
*/
#define SDVO_CMD_SET_ACTIVE_HOT_PLUG 0x0d
/**
* Returns a struct i830_sdvo_output_flags of displays with hot plug
* interrupts enabled.
*/
#define SDVO_CMD_GET_ACTIVE_HOT_PLUG 0x0e
#define SDVO_CMD_GET_INTERRUPT_EVENT_SOURCE 0x0f
struct i830_sdvo_get_interrupt_event_source_response {
struct i830_sdvo_output_flags interrupt_status;
unsigned int ambient_light_interrupt:1;
unsigned int pad:7;
} __attribute__((packed));
/**
* Selects which input is affected by future input commands.
*
* Commands affected include SET_INPUT_TIMINGS_PART[12],
* GET_INPUT_TIMINGS_PART[12], GET_PREFERRED_INPUT_TIMINGS_PART[12],
* GET_INPUT_PIXEL_CLOCK_RANGE, and CREATE_PREFERRED_INPUT_TIMINGS.
*/
#define SDVO_CMD_SET_TARGET_INPUT 0x10
struct i830_sdvo_set_target_input_args {
unsigned int target_1:1;
unsigned int pad:7;
} __attribute__((packed));
/**
* Takes a struct i830_sdvo_output_flags of which outputs are targetted by
* future output commands.
*
* Affected commands inclue SET_OUTPUT_TIMINGS_PART[12],
* GET_OUTPUT_TIMINGS_PART[12], and GET_OUTPUT_PIXEL_CLOCK_RANGE.
*/
#define SDVO_CMD_SET_TARGET_OUTPUT 0x11
#define SDVO_CMD_GET_INPUT_TIMINGS_PART1 0x12
#define SDVO_CMD_GET_INPUT_TIMINGS_PART2 0x13
#define SDVO_CMD_SET_INPUT_TIMINGS_PART1 0x14
#define SDVO_CMD_SET_INPUT_TIMINGS_PART2 0x15
#define SDVO_CMD_SET_OUTPUT_TIMINGS_PART1 0x16
#define SDVO_CMD_SET_OUTPUT_TIMINGS_PART2 0x17
#define SDVO_CMD_GET_OUTPUT_TIMINGS_PART1 0x18
#define SDVO_CMD_GET_OUTPUT_TIMINGS_PART2 0x19
/* Part 1 */
# define SDVO_DTD_CLOCK_LOW SDVO_I2C_ARG_0
# define SDVO_DTD_CLOCK_HIGH SDVO_I2C_ARG_1
# define SDVO_DTD_H_ACTIVE SDVO_I2C_ARG_2
# define SDVO_DTD_H_BLANK SDVO_I2C_ARG_3
# define SDVO_DTD_H_HIGH SDVO_I2C_ARG_4
# define SDVO_DTD_V_ACTIVE SDVO_I2C_ARG_5
# define SDVO_DTD_V_BLANK SDVO_I2C_ARG_6
# define SDVO_DTD_V_HIGH SDVO_I2C_ARG_7
/* Part 2 */
# define SDVO_DTD_HSYNC_OFF SDVO_I2C_ARG_0
# define SDVO_DTD_HSYNC_WIDTH SDVO_I2C_ARG_1
# define SDVO_DTD_VSYNC_OFF_WIDTH SDVO_I2C_ARG_2
# define SDVO_DTD_SYNC_OFF_WIDTH_HIGH SDVO_I2C_ARG_3
# define SDVO_DTD_DTD_FLAGS SDVO_I2C_ARG_4
# define SDVO_DTD_DTD_FLAG_INTERLACED (1 << 7)
# define SDVO_DTD_DTD_FLAG_STEREO_MASK (3 << 5)
# define SDVO_DTD_DTD_FLAG_INPUT_MASK (3 << 3)
# define SDVO_DTD_DTD_FLAG_SYNC_MASK (3 << 1)
# define SDVO_DTD_SDVO_FLAS SDVO_I2C_ARG_5
# define SDVO_DTD_SDVO_FLAG_STALL (1 << 7)
# define SDVO_DTD_SDVO_FLAG_CENTERED (0 << 6)
# define SDVO_DTD_SDVO_FLAG_UPPER_LEFT (1 << 6)
# define SDVO_DTD_SDVO_FLAG_SCALING_MASK (3 << 4)
# define SDVO_DTD_SDVO_FLAG_SCALING_NONE (0 << 4)
# define SDVO_DTD_SDVO_FLAG_SCALING_SHARP (1 << 4)
# define SDVO_DTD_SDVO_FLAG_SCALING_SMOOTH (2 << 4)
# define SDVO_DTD_VSYNC_OFF_HIGH SDVO_I2C_ARG_6
/**
* Generates a DTD based on the given width, height, and flags.
*
* This will be supported by any device supporting scaling or interlaced
* modes.
*/
#define SDVO_CMD_CREATE_PREFERRED_INPUT_TIMING 0x1a
# define SDVO_PREFERRED_INPUT_TIMING_CLOCK_LOW SDVO_I2C_ARG_0
# define SDVO_PREFERRED_INPUT_TIMING_CLOCK_HIGH SDVO_I2C_ARG_1
# define SDVO_PREFERRED_INPUT_TIMING_WIDTH_LOW SDVO_I2C_ARG_2
# define SDVO_PREFERRED_INPUT_TIMING_WIDTH_HIGH SDVO_I2C_ARG_3
# define SDVO_PREFERRED_INPUT_TIMING_HEIGHT_LOW SDVO_I2C_ARG_4
# define SDVO_PREFERRED_INPUT_TIMING_HEIGHT_HIGH SDVO_I2C_ARG_5
# define SDVO_PREFERRED_INPUT_TIMING_FLAGS SDVO_I2C_ARG_6
# define SDVO_PREFERRED_INPUT_TIMING_FLAGS_INTERLACED (1 << 0)
# define SDVO_PREFERRED_INPUT_TIMING_FLAGS_SCALED (1 << 1)
#define SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART1 0x1b
#define SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART2 0x1c
/** Returns a struct i830_sdvo_pixel_clock_range */
#define SDVO_CMD_GET_INPUT_PIXEL_CLOCK_RANGE 0x1d
/** Returns a struct i830_sdvo_pixel_clock_range */
#define SDVO_CMD_GET_OUTPUT_PIXEL_CLOCK_RANGE 0x1e
/** Returns a byte bitfield containing SDVO_CLOCK_RATE_MULT_* flags */
#define SDVO_CMD_GET_SUPPORTED_CLOCK_RATE_MULTS 0x1f
/** Returns a byte containing a SDVO_CLOCK_RATE_MULT_* flag */
#define SDVO_CMD_GET_CLOCK_RATE_MULT 0x20
/** Takes a byte containing a SDVO_CLOCK_RATE_MULT_* flag */
#define SDVO_CMD_SET_CLOCK_RATE_MULT 0x21
# define SDVO_CLOCK_RATE_MULT_1X (1 << 0)
# define SDVO_CLOCK_RATE_MULT_2X (1 << 1)
# define SDVO_CLOCK_RATE_MULT_4X (1 << 3)
#define SDVO_CMD_GET_SUPPORTED_TV_FORMATS 0x27
#define SDVO_CMD_GET_TV_FORMAT 0x28
#define SDVO_CMD_SET_TV_FORMAT 0x29
#define SDVO_CMD_SET_TV_RESOLUTION_SUPPORT 0x93
#define SDVO_CMD_SET_CONTROL_BUS_SWITCH 0x7a
# define SDVO_CONTROL_BUS_PROM 0x0
# define SDVO_CONTROL_BUS_DDC1 0x1
# define SDVO_CONTROL_BUS_DDC2 0x2
# define SDVO_CONTROL_BUS_DDC3 0x3

456
src/i830_tv.c Normal file
View File

@ -0,0 +1,456 @@
/*
* Copyright © 2006 Intel Corporation
*
* 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
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* 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 NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS 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.
*
* Authors:
* Eric Anholt <eric@anholt.net>
*
*/
/** @file
* Integrated TV-out support for the 915GM and 945GM.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "xf86.h"
#include "i830.h"
#include "i830_display.h"
enum tv_type {
TV_TYPE_UNKNOWN,
TV_TYPE_COMPOSITE,
TV_TYPE_SVIDEO,
TV_TYPE_COMPONENT
};
/** Private structure for the integrated TV support */
struct i830_tv_priv {
CARD32 save_TV_H_CTL_1;
CARD32 save_TV_H_CTL_2;
CARD32 save_TV_H_CTL_3;
CARD32 save_TV_V_CTL_1;
CARD32 save_TV_V_CTL_2;
CARD32 save_TV_V_CTL_3;
CARD32 save_TV_V_CTL_4;
CARD32 save_TV_V_CTL_5;
CARD32 save_TV_V_CTL_6;
CARD32 save_TV_V_CTL_7;
CARD32 save_TV_SC_CTL_1, save_TV_SC_CTL_2, save_TV_SC_CTL_3;
CARD32 save_TV_DAC;
CARD32 save_TV_CTL;
};
enum burst_modes {
TV_SC_NTSC_MJ,
TV_SC_PAL,
TV_SC_PAL_NC,
TV_SC_PAL_M,
TV_SC_NTSC_443
};
const struct tv_sc_mode {
char *name;
int dda2_size, dda3_size, dda1_inc, dda2_inc, dda3_inc;
CARD32 sc_reset;
Bool pal_burst;
} tv_sc_modes[] = {
[TV_SC_NTSC_MJ] = {
"NTSC M/J",
27456, 0, 135, 20800, 0,
TV_SC_RESET_EVERY_4,
FALSE
},
[TV_SC_PAL] = {
"PAL",
27648, 625, 168, 4122, 67,
TV_SC_RESET_EVERY_8,
TRUE
},
[TV_SC_PAL_NC] = {
"PAL Nc",
27648, 625, 135, 23578, 134,
TV_SC_RESET_EVERY_8,
TRUE
},
[TV_SC_PAL_M] = {
"PAL M",
27456, 0, 135, 16704, 0,
TV_SC_RESET_EVERY_8,
TRUE
},
[TV_SC_NTSC_443] = {
"NTSC-4.43",
27456, 525, 168, 4093, 310,
TV_SC_RESET_NEVER,
FALSE
},
};
/**
* Register programming values for TV modes.
*
* These values account for -1s required.
*/
const struct tv_mode {
char *name;
CARD32 oversample;
int hsync_end, hblank_end, hblank_start, htotal;
Bool progressive;
int vsync_start_f1, vsync_start_f2, vsync_len;
Bool veq_ena;
int veq_start_f1, veq_start_f2, veq_len;
int vi_end_f1, vi_end_f2, nbr_end;
Bool burst_ena;
int hburst_start, hburst_len;
int vburst_start_f1, vburst_end_f1;
int vburst_start_f2, vburst_end_f2;
int vburst_start_f3, vburst_end_f3;
int vburst_start_f4, vburst_end_f4;
} tv_modes[] = {
{
"480i",
TV_OVERSAMPLE_8X,
64, 124, 836, 857,
FALSE,
6, 7, 6,
TRUE, 0, 1, 18,
20, 21, 240,
TRUE,
72, 34, 9, 240, 10, 240, 9, 240, 10, 240
}
};
static int
i830_tv_detect_type(ScrnInfoPtr pScrn, I830OutputPtr output)
{
CARD32 save_tv_ctl, save_tv_dac;
CARD32 tv_ctl, tv_dac;
I830Ptr pI830 = I830PTR(pScrn);
save_tv_ctl = INREG(TV_CTL);
save_tv_dac = INREG(TV_DAC);
/* First, we have to disable the encoder but source from the right pipe,
* which is already enabled.
*/
tv_ctl = INREG(TV_CTL) & ~(TV_ENC_ENABLE | TV_ENC_PIPEB_SELECT);
if (output->pipe == 1)
tv_ctl |= TV_ENC_PIPEB_SELECT;
OUTREG(TV_CTL, tv_ctl);
/* Then set the voltage overrides. */
tv_dac = DAC_CTL_OVERRIDE | DAC_A_0_7_V | DAC_B_0_7_V | DAC_C_0_7_V;
OUTREG(TV_DAC, tv_dac);
/* Enable sensing of the load. */
tv_ctl |= TV_TEST_MODE_MONITOR_DETECT;
OUTREG(TV_CTL, tv_ctl);
tv_dac |= TVDAC_STATE_CHG_EN | TVDAC_A_SENSE_CTL | TVDAC_B_SENSE_CTL |
TVDAC_C_SENSE_CTL;
OUTREG(TV_DAC, tv_dac);
/* Wait for things to take effect. */
i830WaitForVblank(pScrn);
tv_dac = INREG(TV_DAC);
OUTREG(TV_DAC, save_tv_dac);
OUTREG(TV_CTL, save_tv_ctl);
if ((tv_dac & TVDAC_SENSE_MASK) == (TVDAC_B_SENSE | TVDAC_C_SENSE)) {
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
"Detected Composite TV connection\n");
return TV_TYPE_COMPOSITE;
} else if ((tv_dac & TVDAC_SENSE_MASK) == TVDAC_A_SENSE) {
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
"Detected S-Video TV connection\n");
return TV_TYPE_SVIDEO;
} else if ((tv_dac & TVDAC_SENSE_MASK) == 0) {
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
"Detected Component TV connection\n");
return TV_TYPE_COMPONENT;
} else {
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
"Couldn't detect TV connection\n");
return TV_TYPE_UNKNOWN;
}
}
static void
i830_tv_dpms(ScrnInfoPtr pScrn, I830OutputPtr output, int mode)
{
I830Ptr pI830 = I830PTR(pScrn);
switch(mode) {
case DPMSModeOn:
OUTREG(TV_CTL, INREG(TV_CTL) | TV_ENC_ENABLE);
break;
case DPMSModeStandby:
case DPMSModeSuspend:
case DPMSModeOff:
OUTREG(TV_CTL, INREG(TV_CTL) & ~TV_ENC_ENABLE);
break;
}
}
static void
i830_tv_save(ScrnInfoPtr pScrn, I830OutputPtr output)
{
I830Ptr pI830 = I830PTR(pScrn);
struct i830_tv_priv *dev_priv = output->dev_priv;
dev_priv->save_TV_H_CTL_1 = INREG(TV_H_CTL_1);
dev_priv->save_TV_H_CTL_2 = INREG(TV_H_CTL_2);
dev_priv->save_TV_H_CTL_3 = INREG(TV_H_CTL_3);
dev_priv->save_TV_V_CTL_1 = INREG(TV_V_CTL_1);
dev_priv->save_TV_V_CTL_2 = INREG(TV_V_CTL_2);
dev_priv->save_TV_V_CTL_3 = INREG(TV_V_CTL_3);
dev_priv->save_TV_V_CTL_4 = INREG(TV_V_CTL_4);
dev_priv->save_TV_V_CTL_5 = INREG(TV_V_CTL_5);
dev_priv->save_TV_V_CTL_6 = INREG(TV_V_CTL_6);
dev_priv->save_TV_V_CTL_7 = INREG(TV_V_CTL_7);
dev_priv->save_TV_SC_CTL_1 = INREG(TV_SC_CTL_1);
dev_priv->save_TV_SC_CTL_2 = INREG(TV_SC_CTL_2);
dev_priv->save_TV_SC_CTL_3 = INREG(TV_SC_CTL_3);
dev_priv->save_TV_DAC = INREG(TV_DAC);
dev_priv->save_TV_CTL = INREG(TV_CTL);
}
static void
i830_tv_restore(ScrnInfoPtr pScrn, I830OutputPtr output)
{
I830Ptr pI830 = I830PTR(pScrn);
struct i830_tv_priv *dev_priv = output->dev_priv;
OUTREG(TV_H_CTL_1, dev_priv->save_TV_H_CTL_1);
OUTREG(TV_H_CTL_2, dev_priv->save_TV_H_CTL_2);
OUTREG(TV_H_CTL_3, dev_priv->save_TV_H_CTL_3);
OUTREG(TV_V_CTL_1, dev_priv->save_TV_V_CTL_1);
OUTREG(TV_V_CTL_2, dev_priv->save_TV_V_CTL_2);
OUTREG(TV_V_CTL_3, dev_priv->save_TV_V_CTL_3);
OUTREG(TV_V_CTL_4, dev_priv->save_TV_V_CTL_4);
OUTREG(TV_V_CTL_5, dev_priv->save_TV_V_CTL_5);
OUTREG(TV_V_CTL_6, dev_priv->save_TV_V_CTL_6);
OUTREG(TV_V_CTL_7, dev_priv->save_TV_V_CTL_7);
OUTREG(TV_SC_CTL_1, dev_priv->save_TV_SC_CTL_1);
OUTREG(TV_SC_CTL_2, dev_priv->save_TV_SC_CTL_2);
OUTREG(TV_SC_CTL_3, dev_priv->save_TV_SC_CTL_3);
OUTREG(TV_DAC, dev_priv->save_TV_DAC);
OUTREG(TV_CTL, dev_priv->save_TV_CTL);
}
static int
i830_tv_mode_valid(ScrnInfoPtr pScrn, I830OutputPtr output,
DisplayModePtr pMode)
{
return MODE_OK;
}
static void
i830_tv_pre_set_mode(ScrnInfoPtr pScrn, I830OutputPtr output,
DisplayModePtr pMode)
{
I830Ptr pI830 = I830PTR(pScrn);
/* Disable the encoder while we set up the pipe. */
OUTREG(TV_CTL, INREG(TV_CTL) & ~TV_ENC_ENABLE);
}
static void
i830_tv_post_set_mode(ScrnInfoPtr pScrn, I830OutputPtr output,
DisplayModePtr pMode)
{
I830Ptr pI830 = I830PTR(pScrn);
enum tv_type type;
const struct tv_mode *tv_mode;
const struct tv_sc_mode *sc_mode;
CARD32 tv_ctl, tv_filter_ctl;
CARD32 hctl1, hctl2, hctl3;
CARD32 vctl1, vctl2, vctl3, vctl4, vctl5, vctl6, vctl7;
CARD32 scctl1, scctl2, scctl3;
/* Need to actually choose or construct the appropriate
* mode. For now, just set the first one in the list, with
* NTSC format.
*/
tv_mode = &tv_modes[0];
sc_mode = &tv_sc_modes[TV_SC_NTSC_MJ];
type = i830_tv_detect_type(pScrn, output);
if (type == TV_TYPE_UNKNOWN) {
xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Defaulting TV to SVIDEO\n");
type = TV_TYPE_SVIDEO;
}
hctl1 = (tv_mode->hsync_end << TV_HSYNC_END_SHIFT) |
(tv_mode->htotal << TV_HTOTAL_SHIFT);
hctl2 = (tv_mode->hburst_start << 16) |
(tv_mode->hburst_len << TV_HBURST_LEN_SHIFT);
if (tv_mode->burst_ena)
hctl2 |= TV_BURST_ENA;
hctl3 = (tv_mode->hblank_start << TV_HBLANK_START_SHIFT) |
(tv_mode->hblank_end << TV_HBLANK_END_SHIFT);
vctl1 = (tv_mode->nbr_end << TV_NBR_END_SHIFT) |
(tv_mode->vi_end_f1 << TV_VI_END_F1_SHIFT) |
(tv_mode->vi_end_f2 << TV_VI_END_F2_SHIFT);
vctl2 = (tv_mode->vsync_len << TV_VSYNC_LEN_SHIFT) |
(tv_mode->vsync_start_f1 << TV_VSYNC_START_F1_SHIFT) |
(tv_mode->vsync_start_f2 << TV_VSYNC_START_F2_SHIFT);
vctl3 = (tv_mode->veq_len << TV_VEQ_LEN_SHIFT) |
(tv_mode->veq_start_f1 << TV_VEQ_START_F1_SHIFT) |
(tv_mode->veq_start_f2 << TV_VEQ_START_F2_SHIFT);
if (tv_mode->veq_ena)
vctl3 |= TV_EQUAL_ENA;
vctl4 = (tv_mode->vburst_start_f1 << TV_VBURST_START_F1_SHIFT) |
(tv_mode->vburst_end_f1 << TV_VBURST_END_F1_SHIFT);
vctl5 = (tv_mode->vburst_start_f2 << TV_VBURST_START_F2_SHIFT) |
(tv_mode->vburst_end_f2 << TV_VBURST_END_F2_SHIFT);
vctl6 = (tv_mode->vburst_start_f3 << TV_VBURST_START_F3_SHIFT) |
(tv_mode->vburst_end_f3 << TV_VBURST_END_F3_SHIFT);
vctl7 = (tv_mode->vburst_start_f4 << TV_VBURST_START_F4_SHIFT) |
(tv_mode->vburst_end_f4 << TV_VBURST_END_F4_SHIFT);
tv_ctl = TV_ENC_ENABLE;
if (output->pipe == 1)
tv_ctl |= TV_ENC_PIPEB_SELECT;
switch (type) {
case TV_TYPE_COMPOSITE:
tv_ctl |= TV_ENC_OUTPUT_COMPOSITE;
break;
case TV_TYPE_COMPONENT:
tv_ctl |= TV_ENC_OUTPUT_COMPONENT;
break;
default:
case TV_TYPE_SVIDEO:
tv_ctl |= TV_ENC_OUTPUT_SVIDEO;
break;
}
tv_ctl |= tv_mode->oversample;
if (tv_mode->progressive)
tv_ctl |= TV_PROGRESSIVE;
if (sc_mode->pal_burst)
tv_ctl |= TV_PAL_BURST;
scctl1 = TV_SC_DDA1_EN | TV_SC_DDA1_EN;
if (sc_mode->dda3_size != 0)
scctl1 |= TV_SC_DDA3_EN;
scctl1 |= sc_mode->sc_reset;
/* XXX: set the burst level */
scctl1 |= sc_mode->dda1_inc << TV_SCDDA1_INC_SHIFT;
scctl2 = sc_mode->dda2_size << TV_SCDDA2_SIZE_SHIFT |
sc_mode->dda2_inc << TV_SCDDA2_INC_SHIFT;
scctl3 = sc_mode->dda3_size << TV_SCDDA3_SIZE_SHIFT |
sc_mode->dda3_inc << TV_SCDDA3_INC_SHIFT;
/* Enable two fixes for the chips that need them. */
if (pI830->PciInfo->chipType < PCI_CHIP_I945_G)
tv_ctl |= TV_ENC_C0_FIX | TV_ENC_SDP_FIX;
tv_filter_ctl = TV_AUTO_SCALE;
if (pMode->HDisplay > 1024)
tv_ctl |= TV_V_FILTER_BYPASS;
OUTREG(TV_H_CTL_1, hctl1);
OUTREG(TV_H_CTL_2, hctl2);
OUTREG(TV_H_CTL_3, hctl3);
OUTREG(TV_V_CTL_1, vctl1);
OUTREG(TV_V_CTL_2, vctl2);
OUTREG(TV_V_CTL_3, vctl3);
OUTREG(TV_V_CTL_4, vctl4);
OUTREG(TV_V_CTL_5, vctl5);
OUTREG(TV_V_CTL_6, vctl6);
OUTREG(TV_V_CTL_7, vctl7);
OUTREG(TV_SC_CTL_1, scctl1);
OUTREG(TV_SC_CTL_2, scctl2);
OUTREG(TV_SC_CTL_3, scctl3);
OUTREG(TV_DAC, 0);
OUTREG(TV_CTL, tv_ctl);
}
/**
* Detect the TV connection.
*
* Currently this always returns OUTPUT_STATUS_UNKNOWN, as we need to be sure
* we have a pipe programmed in order to probe the TV.
*/
static enum detect_status
i830_tv_detect(ScrnInfoPtr pScrn, I830OutputPtr output)
{
return OUTPUT_STATUS_UNKNOWN;
}
/**
* Stub get_modes function.
*
* This should probably return a set of fixed modes, unless we can figure out
* how to probe modes off of TV connections.
*/
static DisplayModePtr
i830_tv_get_modes(ScrnInfoPtr pScrn, I830OutputPtr output)
{
return NULL;
}
void
i830_tv_init(ScrnInfoPtr pScrn)
{
I830Ptr pI830 = I830PTR(pScrn);
if ((INREG(TV_CTL) & TV_FUSE_STATE_MASK) == TV_FUSE_STATE_DISABLED)
return;
pI830->output[pI830->num_outputs].dev_priv =
malloc(sizeof(struct i830_tv_priv));
if (pI830->output[pI830->num_outputs].dev_priv == NULL)
return;
pI830->output[pI830->num_outputs].type = I830_OUTPUT_ANALOG;
pI830->output[pI830->num_outputs].dpms = i830_tv_dpms;
pI830->output[pI830->num_outputs].save = i830_tv_save;
pI830->output[pI830->num_outputs].restore = i830_tv_restore;
pI830->output[pI830->num_outputs].mode_valid = i830_tv_mode_valid;
pI830->output[pI830->num_outputs].pre_set_mode = i830_tv_pre_set_mode;
pI830->output[pI830->num_outputs].post_set_mode = i830_tv_post_set_mode;
pI830->output[pI830->num_outputs].detect = i830_tv_detect;
pI830->output[pI830->num_outputs].get_modes = i830_tv_get_modes;
pI830->num_outputs++;
}

View File

@ -125,7 +125,7 @@ I830AllocateMemory(ScrnInfoPtr pScrn, FBLinearPtr linear, int size);
#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE)
static Atom xvBrightness, xvContrast, xvColorKey, xvPipe, xvDoubleBuffer;
static Atom xvBrightness, xvContrast, xvSaturation, xvColorKey, xvPipe, xvDoubleBuffer;
static Atom xvGamma0, xvGamma1, xvGamma2, xvGamma3, xvGamma4, xvGamma5;
#define IMAGE_MAX_WIDTH 1920
@ -294,11 +294,12 @@ static XF86AttributeRec CloneAttributes[CLONE_ATTRIBUTES] = {
{XvSettable | XvGettable, 0, 1, "XV_PIPE"}
};
#define NUM_ATTRIBUTES 4
#define NUM_ATTRIBUTES 5
static XF86AttributeRec Attributes[NUM_ATTRIBUTES] = {
{XvSettable | XvGettable, 0, (1 << 24) - 1, "XV_COLORKEY"},
{XvSettable | XvGettable, -128, 127, "XV_BRIGHTNESS"},
{XvSettable | XvGettable, 0, 255, "XV_CONTRAST"},
{XvSettable | XvGettable, 0, 1023, "XV_SATURATION"},
{XvSettable | XvGettable, 0, 1, "XV_DOUBLE_BUFFER"}
};
@ -445,19 +446,6 @@ I830InitVideo(ScreenPtr pScreen)
xvBrightness = MAKE_ATOM("XV_BRIGHTNESS");
xvContrast = MAKE_ATOM("XV_CONTRAST");
/* Set up overlay video if we can do it at this depth. */
if (!IS_I965G(pI830) && pScrn->bitsPerPixel != 8) {
overlayAdaptor = I830SetupImageVideoOverlay(pScreen);
if (overlayAdaptor != NULL) {
adaptors[num_adaptors++] = overlayAdaptor;
xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Set up overlay video\n");
} else {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
"Failed to set up overlay video\n");
}
I830InitOffscreenImages(pScreen);
}
/* Set up textured video if we can do it at this depth and we are on
* supported hardware.
*/
@ -472,6 +460,19 @@ I830InitVideo(ScreenPtr pScreen)
}
}
/* Set up overlay video if we can do it at this depth. */
if (!IS_I965G(pI830) && pScrn->bitsPerPixel != 8) {
overlayAdaptor = I830SetupImageVideoOverlay(pScreen);
if (overlayAdaptor != NULL) {
adaptors[num_adaptors++] = overlayAdaptor;
xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Set up overlay video\n");
} else {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
"Failed to set up overlay video\n");
}
I830InitOffscreenImages(pScreen);
}
if (num_adaptors)
xf86XVScreenInit(pScreen, adaptors, num_adaptors);
@ -503,7 +504,7 @@ I830ResetVideo(ScrnInfoPtr pScrn)
overlay->SWIDTHSW = 0;
overlay->SHEIGHT = 0;
overlay->OCLRC0 = (pPriv->contrast << 18) | (pPriv->brightness & 0xff);
overlay->OCLRC1 = 0x00000080; /* saturation: bypass */
overlay->OCLRC1 = pPriv->saturation;
#if 0
overlay->AWINPOS = 0;
overlay->AWINSZ = 0;
@ -712,7 +713,8 @@ I830SetupImageVideoOverlay(ScreenPtr pScreen)
pPriv->videoStatus = 0;
pPriv->brightness = 0;
pPriv->contrast = 64;
pPriv->pipe = pI830->pipe; /* default to current pipe */
pPriv->saturation = 128;
pPriv->pipe = 0; /* XXX must choose pipe wisely */
pPriv->linear = NULL;
pPriv->currentBuf = 0;
pPriv->gamma5 = 0xc0c0c0;
@ -745,6 +747,9 @@ I830SetupImageVideoOverlay(ScreenPtr pScreen)
pScreen->BlockHandler = I830BlockHandler;
xvColorKey = MAKE_ATOM("XV_COLORKEY");
xvBrightness = MAKE_ATOM("XV_BRIGHTNESS");
xvContrast = MAKE_ATOM("XV_CONTRAST");
xvSaturation = MAKE_ATOM("XV_SATURATION");
xvDoubleBuffer = MAKE_ATOM("XV_DOUBLE_BUFFER");
/* Allow the pipe to be switched from pipe A to B when in clone mode */
@ -942,6 +947,13 @@ I830SetPortAttribute(ScrnInfoPtr pScrn,
overlay->OCLRC0 = (pPriv->contrast << 18) | (pPriv->brightness & 0xff);
ErrorF("CONTRAST\n");
OVERLAY_UPDATE;
} else if (attribute == xvSaturation) {
if ((value < 0) || (value > 1023))
return BadValue;
pPriv->saturation = value;
overlay->OCLRC1 = pPriv->saturation;
overlay->OCMD &= ~OVERLAY_ENABLE;
OVERLAY_UPDATE;
} else if (pI830->Clone && attribute == xvPipe) {
if ((value < 0) || (value > 1))
return BadValue;
@ -1023,6 +1035,8 @@ I830GetPortAttribute(ScrnInfoPtr pScrn,
*value = pPriv->brightness;
} else if (attribute == xvContrast) {
*value = pPriv->contrast;
} else if (attribute == xvSaturation) {
*value = pPriv->saturation;
} else if (attribute == xvPipe) {
*value = pPriv->pipe;
} else if (attribute == xvGamma0 && (IS_I9XX(pI830))) {
@ -1528,7 +1542,6 @@ I830DisplayVideo(ScrnInfoPtr pScrn, int id, short width, short height,
unsigned int swidth;
unsigned int mask, shift, offsety, offsetu;
int tmp;
BoxRec dstBox2;
ErrorF("I830DisplayVideo: %dx%d (pitch %d)\n", width, height,
dstPitch);
@ -1542,22 +1555,10 @@ I830DisplayVideo(ScrnInfoPtr pScrn, int id, short width, short height,
switch (pI830->rotation) {
case RR_Rotate_0:
if (pI830->MergedFB) {
memcpy(&dstBox2, dstBox, sizeof(BoxRec));
dstBox->x1 -= pI830->FirstframeX0;
dstBox->x2 -= pI830->FirstframeX0;
dstBox->y1 -= pI830->FirstframeY0;
dstBox->y2 -= pI830->FirstframeY0;
dstBox2.x1 -= pI830->pScrn_2->frameX0;
dstBox2.x2 -= pI830->pScrn_2->frameX0;
dstBox2.y1 -= pI830->pScrn_2->frameY0;
dstBox2.y2 -= pI830->pScrn_2->frameY0;
} else {
dstBox->x1 -= pScrn->frameX0;
dstBox->x2 -= pScrn->frameX0;
dstBox->y1 -= pScrn->frameY0;
dstBox->y2 -= pScrn->frameY0;
}
dstBox->x1 -= pScrn->frameX0;
dstBox->x2 -= pScrn->frameX0;
dstBox->y1 -= pScrn->frameY0;
dstBox->y2 -= pScrn->frameY0;
break;
case RR_Rotate_90:
tmp = dstBox->x1;
@ -1591,66 +1592,10 @@ I830DisplayVideo(ScrnInfoPtr pScrn, int id, short width, short height,
break;
}
if (pI830->MergedFB) {
I830ModePrivatePtr mp = (I830ModePrivatePtr)pScrn->currentMode->Private;
int w1, h1, w2, h2;
/* Clip the video to the independent modes of the merged screens */
if (dstBox->x1 > mp->merged.First->HDisplay) dstBox->x1 = mp->merged.First->HDisplay - 1;
if (dstBox->x2 > mp->merged.First->HDisplay) dstBox->x2 = mp->merged.First->HDisplay - 1;
if (dstBox2.x1 > mp->merged.Second->HDisplay) dstBox2.x1 = mp->merged.Second->HDisplay - 1;
if (dstBox2.x2 > mp->merged.Second->HDisplay) dstBox2.x2 = mp->merged.Second->HDisplay - 1;
if (dstBox->y1 > mp->merged.First->VDisplay) dstBox->y1 = mp->merged.First->VDisplay - 1;
if (dstBox->y2 > mp->merged.First->VDisplay) dstBox->y2 = mp->merged.First->VDisplay - 1;
if (dstBox2.y1 > mp->merged.Second->VDisplay) dstBox2.y1 = mp->merged.Second->VDisplay - 1;
if (dstBox2.y2 > mp->merged.Second->VDisplay) dstBox2.y2 = mp->merged.Second->VDisplay - 1;
if (dstBox->y1 < 0) dstBox->y1 = 0;
if (dstBox->y2 < 0) dstBox->y2 = 0;
if (dstBox->x1 < 0) dstBox->x1 = 0;
if (dstBox->x2 < 0) dstBox->x2 = 0;
if (dstBox2.y1 < 0) dstBox2.y1 = 0;
if (dstBox2.y2 < 0) dstBox2.y2 = 0;
if (dstBox2.x1 < 0) dstBox2.x1 = 0;
if (dstBox2.x2 < 0) dstBox2.x2 = 0;
w1 = dstBox->x2 - dstBox->x1;
w2 = dstBox2.x2 - dstBox2.x1;
h1 = dstBox->y2 - dstBox->y1;
h2 = dstBox2.y2 - dstBox2.y1;
switch (pI830->SecondPosition) {
case PosRightOf:
case PosBelow:
if ((w2 > 0 && w1 == 0) ||
(h2 > 0 && h1 == 0)) {
pPriv->pipe = !pI830->pipe;
dstBox->x1 = dstBox2.x1;
dstBox->y1 = dstBox2.y1;
dstBox->x2 = dstBox2.x2;
dstBox->y2 = dstBox2.y2;
} else
pPriv->pipe = pI830->pipe;
break;
case PosLeftOf:
case PosAbove:
if ((w1 > 0 && w2 == 0) ||
(h1 > 0 && h2 == 0)) {
pPriv->pipe = pI830->pipe;
} else {
pPriv->pipe = !pI830->pipe;
dstBox->x1 = dstBox2.x1;
dstBox->y1 = dstBox2.y1;
dstBox->x2 = dstBox2.x2;
dstBox->y2 = dstBox2.y2;
}
break;
}
}
/* When in dual head with different bpp setups we need to refresh the
* color key, so let's reset the video parameters and refresh here.
* In MergedFB mode, we may need to flip pipes too. */
if (pI830->entityPrivate || pI830->MergedFB)
if (pI830->entityPrivate)
I830ResetVideo(pScrn);
/* Ensure overlay is turned on with OVERLAY_ENABLE at 0 */
@ -3611,6 +3556,8 @@ I830VideoSwitchModeAfter(ScrnInfoPtr pScrn, DisplayModePtr mode)
pPriv->overlayOK = TRUE;
#if 0
/* XXX Must choose pipe wisely */
/* ensure pipe is updated on mode switch */
if (!pI830->Clone) {
if (pPriv->pipe != pI830->pipe) {
@ -3619,6 +3566,7 @@ I830VideoSwitchModeAfter(ScrnInfoPtr pScrn, DisplayModePtr mode)
pPriv->pipe = pI830->pipe;
}
}
#endif
if (!IS_I965G(pI830)) {
if (pPriv->pipe == 0) {
@ -3647,8 +3595,8 @@ I830VideoSwitchModeAfter(ScrnInfoPtr pScrn, DisplayModePtr mode)
}
/* Check we have an LFP connected */
if ((pPriv->pipe == 1 && pI830->operatingDevices & (PIPE_LFP << 8)) ||
(pPriv->pipe == 0 && pI830->operatingDevices & PIPE_LFP) ) {
if (i830PipeHasType (pScrn, pPriv->pipe, I830_OUTPUT_LVDS))
{
size = pPriv->pipe ? INREG(PIPEBSRC) : INREG(PIPEASRC);
hsize = (size >> 16) & 0x7FF;
vsize = size & 0x7FF;

View File

@ -40,6 +40,7 @@ typedef struct {
int brightness;
int contrast;
int saturation;
int pipe;
int doubleBuffer;

641
src/i830_xf86Modes.c Normal file
View File

@ -0,0 +1,641 @@
/* -*- c-basic-offset: 4 -*- */
/* $XdotOrg: xserver/xorg/hw/xfree86/common/xf86Mode.c,v 1.10 2006/03/07 16:00:57 libv Exp $ */
/* $XFree86: xc/programs/Xserver/hw/xfree86/common/xf86Mode.c,v 1.69 2003/10/08 14:58:28 dawes Exp $ */
/*
* Copyright (c) 1997-2003 by The XFree86 Project, Inc.
*
* 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
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* 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 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 NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
*
* Except as contained in this notice, the name of the copyright holder(s)
* and author(s) shall not be used in advertising or otherwise to promote
* the sale, use or other dealings in this Software without prior written
* authorization from the copyright holder(s) and author(s).
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stddef.h>
#include <string.h>
#include <stdio.h>
#include "xf86.h"
#include "i830.h"
#include "i830_xf86Modes.h"
/**
* @file this file contains symbols from xf86Mode.c and friends that are static
* there but we still want to use. We need to come up with better API here.
*/
/**
* Calculates the horizontal sync rate of a mode.
*
* Exact copy of xf86Mode.c's.
*/
double
i830xf86ModeHSync(DisplayModePtr mode)
{
double hsync = 0.0;
if (mode->HSync > 0.0)
hsync = mode->HSync;
else if (mode->HTotal > 0)
hsync = (float)mode->Clock / (float)mode->HTotal;
return hsync;
}
/**
* Calculates the vertical refresh rate of a mode.
*
* Exact copy of xf86Mode.c's.
*/
double
i830xf86ModeVRefresh(DisplayModePtr mode)
{
double refresh = 0.0;
if (mode->VRefresh > 0.0)
refresh = mode->VRefresh;
else if (mode->HTotal > 0 && mode->VTotal > 0) {
refresh = mode->Clock * 1000.0 / mode->HTotal / mode->VTotal;
if (mode->Flags & V_INTERLACE)
refresh *= 2.0;
if (mode->Flags & V_DBLSCAN)
refresh /= 2.0;
if (mode->VScan > 1)
refresh /= (float)(mode->VScan);
}
return refresh;
}
/**
* Sets a default mode name of <width>x<height>x<refresh> on a mode.
*
* The refresh rate doesn't contain decimals, as that's expected to be
* unimportant from the user's perspective for non-custom modelines.
*/
void
i830xf86SetModeDefaultName(DisplayModePtr mode)
{
if (mode->name != NULL)
xfree(mode->name);
mode->name = XNFprintf("%dx%d", mode->HDisplay, mode->VDisplay);
}
/*
* I830xf86SetModeCrtc
*
* Initialises the Crtc parameters for a mode. The initialisation includes
* adjustments for interlaced and double scan modes.
*
* Exact copy of xf86Mode.c's.
*/
void
I830xf86SetModeCrtc(DisplayModePtr p, int adjustFlags)
{
if ((p == NULL) || ((p->type & M_T_CRTC_C) == M_T_BUILTIN))
return;
p->CrtcHDisplay = p->HDisplay;
p->CrtcHSyncStart = p->HSyncStart;
p->CrtcHSyncEnd = p->HSyncEnd;
p->CrtcHTotal = p->HTotal;
p->CrtcHSkew = p->HSkew;
p->CrtcVDisplay = p->VDisplay;
p->CrtcVSyncStart = p->VSyncStart;
p->CrtcVSyncEnd = p->VSyncEnd;
p->CrtcVTotal = p->VTotal;
if (p->Flags & V_INTERLACE) {
if (adjustFlags & INTERLACE_HALVE_V) {
p->CrtcVDisplay /= 2;
p->CrtcVSyncStart /= 2;
p->CrtcVSyncEnd /= 2;
p->CrtcVTotal /= 2;
}
/* Force interlaced modes to have an odd VTotal */
/* maybe we should only do this when INTERLACE_HALVE_V is set? */
p->CrtcVTotal |= 1;
}
if (p->Flags & V_DBLSCAN) {
p->CrtcVDisplay *= 2;
p->CrtcVSyncStart *= 2;
p->CrtcVSyncEnd *= 2;
p->CrtcVTotal *= 2;
}
if (p->VScan > 1) {
p->CrtcVDisplay *= p->VScan;
p->CrtcVSyncStart *= p->VScan;
p->CrtcVSyncEnd *= p->VScan;
p->CrtcVTotal *= p->VScan;
}
p->CrtcHAdjusted = FALSE;
p->CrtcVAdjusted = FALSE;
/*
* XXX
*
* The following is taken from VGA, but applies to other cores as well.
*/
p->CrtcVBlankStart = min(p->CrtcVSyncStart, p->CrtcVDisplay);
p->CrtcVBlankEnd = max(p->CrtcVSyncEnd, p->CrtcVTotal);
if ((p->CrtcVBlankEnd - p->CrtcVBlankStart) >= 127) {
/*
* V Blanking size must be < 127.
* Moving blank start forward is safer than moving blank end
* back, since monitors clamp just AFTER the sync pulse (or in
* the sync pulse), but never before.
*/
p->CrtcVBlankStart = p->CrtcVBlankEnd - 127;
/*
* If VBlankStart is now > VSyncStart move VBlankStart
* to VSyncStart using the maximum width that fits into
* VTotal.
*/
if (p->CrtcVBlankStart > p->CrtcVSyncStart) {
p->CrtcVBlankStart = p->CrtcVSyncStart;
p->CrtcVBlankEnd = min(p->CrtcHBlankStart + 127, p->CrtcVTotal);
}
}
p->CrtcHBlankStart = min(p->CrtcHSyncStart, p->CrtcHDisplay);
p->CrtcHBlankEnd = max(p->CrtcHSyncEnd, p->CrtcHTotal);
if ((p->CrtcHBlankEnd - p->CrtcHBlankStart) >= 63 * 8) {
/*
* H Blanking size must be < 63*8. Same remark as above.
*/
p->CrtcHBlankStart = p->CrtcHBlankEnd - 63 * 8;
if (p->CrtcHBlankStart > p->CrtcHSyncStart) {
p->CrtcHBlankStart = p->CrtcHSyncStart;
p->CrtcHBlankEnd = min(p->CrtcHBlankStart + 63 * 8, p->CrtcHTotal);
}
}
}
/**
* Allocates and returns a copy of pMode, including pointers within pMode.
*/
DisplayModePtr
i830xf86DuplicateMode(DisplayModePtr pMode)
{
DisplayModePtr pNew;
pNew = xnfalloc(sizeof(DisplayModeRec));
*pNew = *pMode;
pNew->next = NULL;
pNew->prev = NULL;
if (pNew->name == NULL) {
i830xf86SetModeDefaultName(pMode);
} else {
pNew->name = xnfstrdup(pMode->name);
}
return pNew;
}
/**
* Duplicates every mode in the given list and returns a pointer to the first
* mode.
*
* \param modeList doubly-linked mode list
*/
DisplayModePtr
i830xf86DuplicateModes(ScrnInfoPtr pScrn, DisplayModePtr modeList)
{
DisplayModePtr first = NULL, last = NULL;
DisplayModePtr mode;
for (mode = modeList; mode != NULL; mode = mode->next) {
DisplayModePtr new;
new = i830xf86DuplicateMode(mode);
/* Insert pNew into modeList */
if (last) {
last->next = new;
new->prev = last;
} else {
first = new;
new->prev = NULL;
}
new->next = NULL;
last = new;
}
return first;
}
/**
* Returns true if the given modes should program to the same timings.
*
* This doesn't use Crtc values, as it might be used on ModeRecs without the
* Crtc values set. So, it's assumed that the other numbers are enough.
*
* This isn't in xf86Modes.c, but it might deserve to be there.
*/
Bool
I830ModesEqual(DisplayModePtr pMode1, DisplayModePtr pMode2)
{
if (pMode1->Clock == pMode2->Clock &&
pMode1->HDisplay == pMode2->HDisplay &&
pMode1->HSyncStart == pMode2->HSyncStart &&
pMode1->HSyncEnd == pMode2->HSyncEnd &&
pMode1->HTotal == pMode2->HTotal &&
pMode1->HSkew == pMode2->HSkew &&
pMode1->VDisplay == pMode2->VDisplay &&
pMode1->VSyncStart == pMode2->VSyncStart &&
pMode1->VSyncEnd == pMode2->VSyncEnd &&
pMode1->VTotal == pMode2->VTotal &&
pMode1->VScan == pMode2->VScan &&
pMode1->Flags == pMode2->Flags)
{
return TRUE;
} else {
return FALSE;
}
}
/* exact copy of xf86Mode.c */
static void
add(char **p, char *new)
{
*p = xnfrealloc(*p, strlen(*p) + strlen(new) + 2);
strcat(*p, " ");
strcat(*p, new);
}
/**
* Print out a modeline.
*
* Convenient VRefresh printing was added, though, compared to xf86Mode.c
*/
void
PrintModeline(int scrnIndex,DisplayModePtr mode)
{
char tmp[256];
char *flags = xnfcalloc(1, 1);
if (mode->HSkew) {
snprintf(tmp, 256, "hskew %i", mode->HSkew);
add(&flags, tmp);
}
if (mode->VScan) {
snprintf(tmp, 256, "vscan %i", mode->VScan);
add(&flags, tmp);
}
if (mode->Flags & V_INTERLACE) add(&flags, "interlace");
if (mode->Flags & V_CSYNC) add(&flags, "composite");
if (mode->Flags & V_DBLSCAN) add(&flags, "doublescan");
if (mode->Flags & V_BCAST) add(&flags, "bcast");
if (mode->Flags & V_PHSYNC) add(&flags, "+hsync");
if (mode->Flags & V_NHSYNC) add(&flags, "-hsync");
if (mode->Flags & V_PVSYNC) add(&flags, "+vsync");
if (mode->Flags & V_NVSYNC) add(&flags, "-vsync");
if (mode->Flags & V_PCSYNC) add(&flags, "+csync");
if (mode->Flags & V_NCSYNC) add(&flags, "-csync");
#if 0
if (mode->Flags & V_CLKDIV2) add(&flags, "vclk/2");
#endif
xf86DrvMsg(scrnIndex, X_INFO,
"Modeline \"%s\"x%.01f %6.2f %i %i %i %i %i %i %i %i%s "
"(%.01f kHz)\n",
mode->name, mode->VRefresh, mode->Clock/1000., mode->HDisplay,
mode->HSyncStart, mode->HSyncEnd, mode->HTotal,
mode->VDisplay, mode->VSyncStart, mode->VSyncEnd,
mode->VTotal, flags, i830xf86ModeHSync(mode));
xfree(flags);
}
/**
* Marks as bad any modes with unsupported flags.
*
* \param modeList doubly-linked or circular list of modes.
* \param flags flags supported by the driver.
*
* \bug only V_INTERLACE and V_DBLSCAN are supported. Is that enough?
*
* This is not in xf86Modes.c, but would be part of the proposed new API.
*/
void
i830xf86ValidateModesFlags(ScrnInfoPtr pScrn, DisplayModePtr modeList,
int flags)
{
DisplayModePtr mode;
for (mode = modeList; mode != NULL; mode = mode->next) {
if (mode->Flags & V_INTERLACE && !(flags & V_INTERLACE))
mode->status = MODE_NO_INTERLACE;
if (mode->Flags & V_DBLSCAN && !(flags & V_DBLSCAN))
mode->status = MODE_NO_DBLESCAN;
}
}
/**
* Marks as bad any modes extending beyond the given max X, Y, or pitch.
*
* \param modeList doubly-linked or circular list of modes.
*
* This is not in xf86Modes.c, but would be part of the proposed new API.
*/
void
i830xf86ValidateModesSize(ScrnInfoPtr pScrn, DisplayModePtr modeList,
int maxX, int maxY, int maxPitch)
{
DisplayModePtr mode;
for (mode = modeList; mode != NULL; mode = mode->next) {
if (maxPitch > 0 && mode->HDisplay > maxPitch)
mode->status = MODE_BAD_WIDTH;
if (maxX > 0 && mode->HDisplay > maxX)
mode->status = MODE_VIRTUAL_X;
if (maxY > 0 && mode->VDisplay > maxY)
mode->status = MODE_VIRTUAL_Y;
if (mode->next == modeList)
break;
}
}
/**
* Marks as bad any modes that aren't supported by the given monitor's
* hsync and vrefresh ranges.
*
* \param modeList doubly-linked or circular list of modes.
*
* This is not in xf86Modes.c, but would be part of the proposed new API.
*/
void
i830xf86ValidateModesSync(ScrnInfoPtr pScrn, DisplayModePtr modeList,
MonPtr mon)
{
DisplayModePtr mode;
for (mode = modeList; mode != NULL; mode = mode->next) {
Bool bad;
int i;
bad = TRUE;
for (i = 0; i < mon->nHsync; i++) {
if (i830xf86ModeHSync(mode) >= mon->hsync[i].lo &&
i830xf86ModeHSync(mode) <= mon->hsync[i].hi)
{
bad = FALSE;
}
}
if (bad)
mode->status = MODE_HSYNC;
bad = TRUE;
for (i = 0; i < mon->nVrefresh; i++) {
if (i830xf86ModeVRefresh(mode) >= mon->vrefresh[i].lo &&
i830xf86ModeVRefresh(mode) <= mon->vrefresh[i].hi)
{
bad = FALSE;
}
}
if (bad)
mode->status = MODE_VSYNC;
if (mode->next == modeList)
break;
}
}
/**
* Marks as bad any modes extending beyond outside of the given clock ranges.
*
* \param modeList doubly-linked or circular list of modes.
* \param min pointer to minimums of clock ranges
* \param max pointer to maximums of clock ranges
* \param n_ranges number of ranges.
*
* This is not in xf86Modes.c, but would be part of the proposed new API.
*/
void
i830xf86ValidateModesClocks(ScrnInfoPtr pScrn, DisplayModePtr modeList,
int *min, int *max, int n_ranges)
{
DisplayModePtr mode;
int i;
for (mode = modeList; mode != NULL; mode = mode->next) {
Bool good = FALSE;
for (i = 0; i < n_ranges; i++) {
if (mode->Clock >= min[i] && mode->Clock <= max[i]) {
good = TRUE;
break;
}
}
if (!good)
mode->status = MODE_CLOCK_RANGE;
}
}
/**
* If the user has specified a set of mode names to use, mark as bad any modes
* not listed.
*
* The user mode names specified are prefixes to names of modes, so "1024x768"
* will match modes named "1024x768", "1024x768x75", "1024x768-good", but
* "1024x768x75" would only match "1024x768x75" from that list.
*
* MODE_BAD is used as the rejection flag, for lack of a better flag.
*
* \param modeList doubly-linked or circular list of modes.
*
* This is not in xf86Modes.c, but would be part of the proposed new API.
*/
void
i830xf86ValidateModesUserConfig(ScrnInfoPtr pScrn, DisplayModePtr modeList)
{
DisplayModePtr mode;
if (pScrn->display->modes[0] == NULL)
return;
for (mode = modeList; mode != NULL; mode = mode->next) {
int i;
Bool good = FALSE;
for (i = 0; pScrn->display->modes[i] != NULL; i++) {
if (strncmp(pScrn->display->modes[i], mode->name,
strlen(pScrn->display->modes[i])) == 0) {
good = TRUE;
break;
}
}
if (!good)
mode->status = MODE_BAD;
}
}
/**
* Frees any modes from the list with a status other than MODE_OK.
*
* \param modeList pointer to a doubly-linked or circular list of modes.
* \param verbose determines whether the reason for mode invalidation is
* printed.
*
* This is not in xf86Modes.c, but would be part of the proposed new API.
*/
void
i830xf86PruneInvalidModes(ScrnInfoPtr pScrn, DisplayModePtr *modeList,
Bool verbose)
{
DisplayModePtr mode;
for (mode = *modeList; mode != NULL;) {
DisplayModePtr next = mode->next, first = *modeList;
if (mode->status != MODE_OK) {
if (verbose) {
char *type = "";
if (mode->type & M_T_BUILTIN)
type = "built-in ";
else if (mode->type & M_T_DEFAULT)
type = "default ";
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
"Not using %smode \"%s\" (%s)\n", type, mode->name,
xf86ModeStatusToString(mode->status));
}
xf86DeleteMode(modeList, mode);
}
if (next == first)
break;
mode = next;
}
}
#define MODEPREFIX(name) NULL, NULL, name, MODE_OK, M_T_DEFAULT
#define MODESUFFIX 0,0, 0,0,0,0,0,0,0, 0,0,0,0,0,0,FALSE,FALSE,0,NULL,0,0.0,0.0
/**
* List of VESA established modes, taken from xf86DefaultModes but trimmed down.
* (not trimming should be harmless).
*/
DisplayModeRec I830xf86DefaultModes[] = {
/* 640x350 @ 85Hz (VESA) hsync: 37.9kHz */
{MODEPREFIX("640x350"),31500, 640,672,736,832,0, 350,382,385,445,0, V_PHSYNC | V_NVSYNC, MODESUFFIX},
{MODEPREFIX("320x175"),15750, 320,336,368,416,0, 175,191,192,222,0, V_PHSYNC | V_NVSYNC | V_DBLSCAN, MODESUFFIX},
/* 640x400 @ 85Hz (VESA) hsync: 37.9kHz */
{MODEPREFIX("640x400"),31500, 640,672,736,832,0, 400,401,404,445,0, V_NHSYNC | V_PVSYNC, MODESUFFIX},
{MODEPREFIX("320x200"),15750, 320,336,368,416,0, 200,200,202,222,0, V_NHSYNC | V_PVSYNC | V_DBLSCAN, MODESUFFIX},
/* 720x400 @ 85Hz (VESA) hsync: 37.9kHz */
{MODEPREFIX("720x400"),35500, 720,756,828,936,0, 400,401,404,446,0, V_NHSYNC | V_PVSYNC, MODESUFFIX},
{MODEPREFIX("360x200"),17750, 360,378,414,468,0, 200,200,202,223,0, V_NHSYNC | V_PVSYNC | V_DBLSCAN, MODESUFFIX},
/* 640x480 @ 72Hz (VESA) hsync: 37.9kHz */
{MODEPREFIX("640x480"),31500, 640,664,704,832,0, 480,489,491,520,0, V_NHSYNC | V_NVSYNC, MODESUFFIX},
{MODEPREFIX("320x240"),15750, 320,332,352,416,0, 240,244,245,260,0, V_NHSYNC | V_NVSYNC | V_DBLSCAN, MODESUFFIX},
/* 640x480 @ 75Hz (VESA) hsync: 37.5kHz */
{MODEPREFIX("640x480"),31500, 640,656,720,840,0, 480,481,484,500,0, V_NHSYNC | V_NVSYNC, MODESUFFIX},
{MODEPREFIX("320x240"),15750, 320,328,360,420,0, 240,240,242,250,0, V_NHSYNC | V_NVSYNC | V_DBLSCAN, MODESUFFIX},
/* 640x480 @ 85Hz (VESA) hsync: 43.3kHz */
{MODEPREFIX("640x480"),36000, 640,696,752,832,0, 480,481,484,509,0, V_NHSYNC | V_NVSYNC, MODESUFFIX},
{MODEPREFIX("320x240"),18000, 320,348,376,416,0, 240,240,242,254,0, V_NHSYNC | V_NVSYNC | V_DBLSCAN, MODESUFFIX},
/* 800x600 @ 56Hz (VESA) hsync: 35.2kHz */
{MODEPREFIX("800x600"),36000, 800,824,896,1024,0, 600,601,603,625,0, V_PHSYNC | V_PVSYNC, MODESUFFIX},
{MODEPREFIX("400x300"),18000, 400,412,448,512,0, 300,300,301,312,0, V_PHSYNC | V_PVSYNC | V_DBLSCAN, MODESUFFIX},
/* 800x600 @ 60Hz (VESA) hsync: 37.9kHz */
{MODEPREFIX("800x600"),40000, 800,840,968,1056,0, 600,601,605,628,0, V_PHSYNC | V_PVSYNC, MODESUFFIX},
{MODEPREFIX("400x300"),20000, 400,420,484,528,0, 300,300,302,314,0, V_PHSYNC | V_PVSYNC | V_DBLSCAN, MODESUFFIX},
/* 800x600 @ 72Hz (VESA) hsync: 48.1kHz */
{MODEPREFIX("800x600"),50000, 800,856,976,1040,0, 600,637,643,666,0, V_PHSYNC | V_PVSYNC, MODESUFFIX},
{MODEPREFIX("400x300"),25000, 400,428,488,520,0, 300,318,321,333,0, V_PHSYNC | V_PVSYNC | V_DBLSCAN, MODESUFFIX},
/* 800x600 @ 75Hz (VESA) hsync: 46.9kHz */
{MODEPREFIX("800x600"),49500, 800,816,896,1056,0, 600,601,604,625,0, V_PHSYNC | V_PVSYNC, MODESUFFIX},
{MODEPREFIX("400x300"),24750, 400,408,448,528,0, 300,300,302,312,0, V_PHSYNC | V_PVSYNC | V_DBLSCAN, MODESUFFIX},
/* 800x600 @ 85Hz (VESA) hsync: 53.7kHz */
{MODEPREFIX("800x600"),56300, 800,832,896,1048,0, 600,601,604,631,0, V_PHSYNC | V_PVSYNC, MODESUFFIX},
{MODEPREFIX("400x300"),28150, 400,416,448,524,0, 300,300,302,315,0, V_PHSYNC | V_PVSYNC | V_DBLSCAN, MODESUFFIX},
/* 1024x768 @ 60Hz (VESA) hsync: 48.4kHz */
{MODEPREFIX("1024x768"),65000, 1024,1048,1184,1344,0, 768,771,777,806,0, V_NHSYNC | V_NVSYNC, MODESUFFIX},
{MODEPREFIX("512x384"),32500, 512,524,592,672,0, 384,385,388,403,0, V_NHSYNC | V_NVSYNC | V_DBLSCAN, MODESUFFIX},
/* 1024x768 @ 70Hz (VESA) hsync: 56.5kHz */
{MODEPREFIX("1024x768"),75000, 1024,1048,1184,1328,0, 768,771,777,806,0, V_NHSYNC | V_NVSYNC, MODESUFFIX},
{MODEPREFIX("512x384"),37500, 512,524,592,664,0, 384,385,388,403,0, V_NHSYNC | V_NVSYNC | V_DBLSCAN, MODESUFFIX},
/* 1024x768 @ 75Hz (VESA) hsync: 60.0kHz */
{MODEPREFIX("1024x768"),78800, 1024,1040,1136,1312,0, 768,769,772,800,0, V_PHSYNC | V_PVSYNC, MODESUFFIX},
{MODEPREFIX("512x384"),39400, 512,520,568,656,0, 384,384,386,400,0, V_PHSYNC | V_PVSYNC | V_DBLSCAN, MODESUFFIX},
/* 1024x768 @ 85Hz (VESA) hsync: 68.7kHz */
{MODEPREFIX("1024x768"),94500, 1024,1072,1168,1376,0, 768,769,772,808,0, V_PHSYNC | V_PVSYNC, MODESUFFIX},
{MODEPREFIX("512x384"),47250, 512,536,584,688,0, 384,384,386,404,0, V_PHSYNC | V_PVSYNC | V_DBLSCAN, MODESUFFIX},
/* 1152x864 @ 75Hz (VESA) hsync: 67.5kHz */
{MODEPREFIX("1152x864"),108000, 1152,1216,1344,1600,0, 864,865,868,900,0, V_PHSYNC | V_PVSYNC, MODESUFFIX},
{MODEPREFIX("576x432"),54000, 576,608,672,800,0, 432,432,434,450,0, V_PHSYNC | V_PVSYNC | V_DBLSCAN, MODESUFFIX},
/* 1280x960 @ 60Hz (VESA) hsync: 60.0kHz */
{MODEPREFIX("1280x960"),108000, 1280,1376,1488,1800,0, 960,961,964,1000,0, V_PHSYNC | V_PVSYNC, MODESUFFIX},
{MODEPREFIX("640x480"),54000, 640,688,744,900,0, 480,480,482,500,0, V_PHSYNC | V_PVSYNC | V_DBLSCAN, MODESUFFIX},
/* 1280x960 @ 85Hz (VESA) hsync: 85.9kHz */
{MODEPREFIX("1280x960"),148500, 1280,1344,1504,1728,0, 960,961,964,1011,0, V_PHSYNC | V_PVSYNC, MODESUFFIX},
{MODEPREFIX("640x480"),74250, 640,672,752,864,0, 480,480,482,505,0, V_PHSYNC | V_PVSYNC | V_DBLSCAN, MODESUFFIX},
/* 1280x1024 @ 60Hz (VESA) hsync: 64.0kHz */
{MODEPREFIX("1280x1024"),108000, 1280,1328,1440,1688,0, 1024,1025,1028,1066,0, V_PHSYNC | V_PVSYNC, MODESUFFIX},
{MODEPREFIX("640x512"),54000, 640,664,720,844,0, 512,512,514,533,0, V_PHSYNC | V_PVSYNC | V_DBLSCAN, MODESUFFIX},
/* 1280x1024 @ 75Hz (VESA) hsync: 80.0kHz */
{MODEPREFIX("1280x1024"),135000, 1280,1296,1440,1688,0, 1024,1025,1028,1066,0, V_PHSYNC | V_PVSYNC, MODESUFFIX},
{MODEPREFIX("640x512"),67500, 640,648,720,844,0, 512,512,514,533,0, V_PHSYNC | V_PVSYNC | V_DBLSCAN, MODESUFFIX},
/* 1280x1024 @ 85Hz (VESA) hsync: 91.1kHz */
{MODEPREFIX("1280x1024"),157500, 1280,1344,1504,1728,0, 1024,1025,1028,1072,0, V_PHSYNC | V_PVSYNC, MODESUFFIX},
{MODEPREFIX("640x512"),78750, 640,672,752,864,0, 512,512,514,536,0, V_PHSYNC | V_PVSYNC | V_DBLSCAN, MODESUFFIX},
/* 1600x1200 @ 60Hz (VESA) hsync: 75.0kHz */
{MODEPREFIX("1600x1200"),162000, 1600,1664,1856,2160,0, 1200,1201,1204,1250,0, V_PHSYNC | V_PVSYNC, MODESUFFIX},
{MODEPREFIX("800x600"),81000, 800,832,928,1080,0, 600,600,602,625,0, V_PHSYNC | V_PVSYNC | V_DBLSCAN, MODESUFFIX},
/* 1600x1200 @ 65Hz (VESA) hsync: 81.3kHz */
{MODEPREFIX("1600x1200"),175500, 1600,1664,1856,2160,0, 1200,1201,1204,1250,0, V_PHSYNC | V_PVSYNC, MODESUFFIX},
{MODEPREFIX("800x600"),87750, 800,832,928,1080,0, 600,600,602,625,0, V_PHSYNC | V_PVSYNC | V_DBLSCAN, MODESUFFIX},
/* 1600x1200 @ 70Hz (VESA) hsync: 87.5kHz */
{MODEPREFIX("1600x1200"),189000, 1600,1664,1856,2160,0, 1200,1201,1204,1250,0, V_PHSYNC | V_PVSYNC, MODESUFFIX},
{MODEPREFIX("800x600"),94500, 800,832,928,1080,0, 600,600,602,625,0, V_PHSYNC | V_PVSYNC | V_DBLSCAN, MODESUFFIX},
/* 1600x1200 @ 75Hz (VESA) hsync: 93.8kHz */
{MODEPREFIX("1600x1200"),202500, 1600,1664,1856,2160,0, 1200,1201,1204,1250,0, V_PHSYNC | V_PVSYNC, MODESUFFIX},
{MODEPREFIX("800x600"),101250, 800,832,928,1080,0, 600,600,602,625,0, V_PHSYNC | V_PVSYNC | V_DBLSCAN, MODESUFFIX},
/* 1600x1200 @ 85Hz (VESA) hsync: 106.3kHz */
{MODEPREFIX("1600x1200"),229500, 1600,1664,1856,2160,0, 1200,1201,1204,1250,0, V_PHSYNC | V_PVSYNC, MODESUFFIX},
{MODEPREFIX("800x600"),114750, 800,832,928,1080,0, 600,600,602,625,0, V_PHSYNC | V_PVSYNC | V_DBLSCAN, MODESUFFIX},
/* 1792x1344 @ 60Hz (VESA) hsync: 83.6kHz */
{MODEPREFIX("1792x1344"),204800, 1792,1920,2120,2448,0, 1344,1345,1348,1394,0, V_NHSYNC | V_PVSYNC, MODESUFFIX},
{MODEPREFIX("896x672"),102400, 896,960,1060,1224,0, 672,672,674,697,0, V_NHSYNC | V_PVSYNC | V_DBLSCAN, MODESUFFIX},
/* 1792x1344 @ 75Hz (VESA) hsync: 106.3kHz */
{MODEPREFIX("1792x1344"),261000, 1792,1888,2104,2456,0, 1344,1345,1348,1417,0, V_NHSYNC | V_PVSYNC, MODESUFFIX},
{MODEPREFIX("896x672"),130500, 896,944,1052,1228,0, 672,672,674,708,0, V_NHSYNC | V_PVSYNC | V_DBLSCAN, MODESUFFIX},
/* 1856x1392 @ 60Hz (VESA) hsync: 86.3kHz */
{MODEPREFIX("1856x1392"),218300, 1856,1952,2176,2528,0, 1392,1393,1396,1439,0, V_NHSYNC | V_PVSYNC, MODESUFFIX},
{MODEPREFIX("928x696"),109150, 928,976,1088,1264,0, 696,696,698,719,0, V_NHSYNC | V_PVSYNC | V_DBLSCAN, MODESUFFIX},
/* 1856x1392 @ 75Hz (VESA) hsync: 112.5kHz */
{MODEPREFIX("1856x1392"),288000, 1856,1984,2208,2560,0, 1392,1393,1396,1500,0, V_NHSYNC | V_PVSYNC, MODESUFFIX},
{MODEPREFIX("928x696"),144000, 928,992,1104,1280,0, 696,696,698,750,0, V_NHSYNC | V_PVSYNC | V_DBLSCAN, MODESUFFIX},
/* 1920x1440 @ 60Hz (VESA) hsync: 90.0kHz */
{MODEPREFIX("1920x1440"),234000, 1920,2048,2256,2600,0, 1440,1441,1444,1500,0, V_NHSYNC | V_PVSYNC, MODESUFFIX},
{MODEPREFIX("960x720"),117000, 960,1024,1128,1300,0, 720,720,722,750,0, V_NHSYNC | V_PVSYNC | V_DBLSCAN, MODESUFFIX},
/* 1920x1440 @ 75Hz (VESA) hsync: 112.5kHz */
{MODEPREFIX("1920x1440"),297000, 1920,2064,2288,2640,0, 1440,1441,1444,1500,0, V_NHSYNC | V_PVSYNC, MODESUFFIX},
{MODEPREFIX("960x720"),148500, 960,1032,1144,1320,0, 720,720,722,750,0, V_NHSYNC | V_PVSYNC | V_DBLSCAN, MODESUFFIX},
/* Terminator */
{MODEPREFIX(NULL), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, MODESUFFIX}
};

79
src/i830_xf86Modes.h Normal file
View File

@ -0,0 +1,79 @@
/*
* Copyright © 2006 Intel Corporation
*
* 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
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* 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 NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS 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.
*
* Authors:
* Eric Anholt <eric@anholt.net>
*
*/
double
i830xf86ModeHSync(DisplayModePtr mode);
double
i830xf86ModeVRefresh(DisplayModePtr mode);
DisplayModePtr
i830xf86DuplicateMode(DisplayModePtr pMode);
DisplayModePtr
i830xf86DuplicateModes(ScrnInfoPtr pScrn, DisplayModePtr modeList);
void
i830xf86SetModeDefaultName(DisplayModePtr mode);
void
I830xf86SetModeCrtc(DisplayModePtr p, int adjustFlags);
Bool
I830ModesEqual(DisplayModePtr pMode1, DisplayModePtr pMode2);
void
i830xf86ValidateModesFlags(ScrnInfoPtr pScrn, DisplayModePtr modeList,
int flags);
void
i830xf86ValidateModesClocks(ScrnInfoPtr pScrn, DisplayModePtr modeList,
int *min, int *max, int n_ranges);
void
i830xf86ValidateModesSize(ScrnInfoPtr pScrn, DisplayModePtr modeList,
int maxX, int maxY, int maxPitch);
void
i830xf86ValidateModesSync(ScrnInfoPtr pScrn, DisplayModePtr modeList,
MonPtr mon);
void
i830xf86PruneInvalidModes(ScrnInfoPtr pScrn, DisplayModePtr *modeList,
Bool verbose);
void
i830xf86ValidateModesFlags(ScrnInfoPtr pScrn, DisplayModePtr modeList,
int flags);
void
i830xf86ValidateModesUserConfig(ScrnInfoPtr pScrn, DisplayModePtr modeList);
void
PrintModeline(int scrnIndex,DisplayModePtr mode);
extern DisplayModeRec I830xf86DefaultModes[];

View File

@ -65,8 +65,10 @@ I915DisplayVideoTextured(ScrnInfoPtr pScrn, I830PortPrivPtr pPriv, int id,
int nbox, dxo, dyo;
Bool planar;
#if 0
ErrorF("I915DisplayVideo: %dx%d (pitch %d)\n", width, height,
video_pitch);
#endif
switch (id) {
case FOURCC_UYVY:
@ -78,7 +80,9 @@ I915DisplayVideoTextured(ScrnInfoPtr pScrn, I830PortPrivPtr pPriv, int id,
planar = TRUE;
break;
default:
#if 0
ErrorF("Unknown format 0x%x\n", id);
#endif
planar = FALSE;
break;
}

16
src/sil164/Makefile.am Normal file
View File

@ -0,0 +1,16 @@
# this is obnoxious:
# -module lets us name the module exactly how we want
# -avoid-version prevents gratuitous .0.0.0 version numbers on the end
# _ladir passes a dummy rpath to libtool so the thing will actually link
# TODO: -nostdlib/-Bstatic/-lgcc platform magic, not installing the .a, etc.
AM_CFLAGS = @XORG_CFLAGS@ @DRI_CFLAGS@
sil164_la_LTLIBRARIES = sil164.la
sil164_la_LDFLAGS = -module -avoid-version
sil164_ladir = @moduledir@/drivers
sil164_la_SOURCES = \
sil164.c \
sil164_module.c \
sil164.h \
sil164_reg.h

235
src/sil164/sil164.c Normal file
View File

@ -0,0 +1,235 @@
/* -*- c-basic-offset: 4 -*- */
/**************************************************************************
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 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 AUTHOR 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 "xf86.h"
#include "xf86_OSproc.h"
#include "xf86Resources.h"
#include "compiler.h"
#include "miscstruct.h"
#include "xf86i2c.h"
#include "../i2c_vid.h"
#include "sil164.h"
#include "sil164_reg.h"
static void
sil164PrintRegs(I2CDevPtr d);
static void
sil164Power(I2CDevPtr d, Bool On);
static Bool
sil164ReadByte(SIL164Ptr sil, int addr, CARD8 *ch)
{
if (!xf86I2CReadByte(&(sil->d), addr, ch)) {
xf86DrvMsg(sil->d.pI2CBus->scrnIndex, X_ERROR,
"Unable to read from %s Slave %d.\n",
sil->d.pI2CBus->BusName, sil->d.SlaveAddr);
return FALSE;
}
return TRUE;
}
static Bool
sil164WriteByte(SIL164Ptr sil, int addr, CARD8 ch)
{
if (!xf86I2CWriteByte(&(sil->d), addr, ch)) {
xf86DrvMsg(sil->d.pI2CBus->scrnIndex, X_ERROR,
"Unable to write to %s Slave %d.\n",
sil->d.pI2CBus->BusName, sil->d.SlaveAddr);
return FALSE;
}
return TRUE;
}
/* Silicon Image 164 driver for chip on i2c bus */
static void *
sil164Detect(I2CBusPtr b, I2CSlaveAddr addr)
{
/* this will detect the SIL164 chip on the specified i2c bus */
SIL164Ptr sil;
unsigned char ch;
xf86DrvMsg(b->scrnIndex, X_ERROR, "detecting sil164\n");
sil = xcalloc(1, sizeof(SIL164Rec));
if (sil == NULL)
return NULL;
sil->d.DevName = "SIL164 TMDS Controller";
sil->d.SlaveAddr = addr;
sil->d.pI2CBus = b;
sil->d.StartTimeout = b->StartTimeout;
sil->d.BitTimeout = b->BitTimeout;
sil->d.AcknTimeout = b->AcknTimeout;
sil->d.ByteTimeout = b->ByteTimeout;
sil->d.DriverPrivate.ptr = sil;
if (!sil164ReadByte(sil, SIL164_VID_LO, &ch))
goto out;
if (ch!=(SIL164_VID & 0xFF)) {
xf86DrvMsg(sil->d.pI2CBus->scrnIndex, X_ERROR,
"sil164 not detected got %d: from %s Slave %d.\n",
ch, sil->d.pI2CBus->BusName, sil->d.SlaveAddr);
goto out;
}
if (!sil164ReadByte(sil, SIL164_DID_LO, &ch))
goto out;
if (ch!=(SIL164_DID & 0xFF)) {
xf86DrvMsg(sil->d.pI2CBus->scrnIndex, X_ERROR,
"sil164 not detected got %d: from %s Slave %d.\n",
ch, sil->d.pI2CBus->BusName, sil->d.SlaveAddr);
goto out;
}
if (!xf86I2CDevInit(&(sil->d))) {
goto out;
}
return sil;
out:
xfree(sil);
return NULL;
}
static Bool
sil164Init(I2CDevPtr d)
{
/* not much to do */
return TRUE;
}
static ModeStatus
sil164ModeValid(I2CDevPtr d, DisplayModePtr mode)
{
return MODE_OK;
}
static void
sil164Mode(I2CDevPtr d, DisplayModePtr mode)
{
sil164Power(d, TRUE);
sil164PrintRegs(d);
/* recommended programming sequence from doc */
/*sil164WriteByte(sil, 0x08, 0x30);
sil164WriteByte(sil, 0x09, 0x00);
sil164WriteByte(sil, 0x0a, 0x90);
sil164WriteByte(sil, 0x0c, 0x89);
sil164WriteByte(sil, 0x08, 0x31);*/
/* don't do much */
return;
}
/* set the SIL164 power state */
static void
sil164Power(I2CDevPtr d, Bool On)
{
SIL164Ptr sil = SILPTR(d);
int ret;
unsigned char ch;
ret = sil164ReadByte(sil, SIL164_REG8, &ch);
if (ret == FALSE)
return;
if (On)
ch |= SIL164_8_PD;
else
ch &= ~SIL164_8_PD;
sil164WriteByte(sil, SIL164_REG8, ch);
return;
}
static void
sil164PrintRegs(I2CDevPtr d)
{
SIL164Ptr sil = SILPTR(d);
CARD8 val;
sil164ReadByte(sil, SIL164_FREQ_LO, &val);
xf86DrvMsg(sil->d.pI2CBus->scrnIndex, X_INFO, "SIL164_FREQ_LO: 0x%02x\n",
val);
sil164ReadByte(sil, SIL164_FREQ_HI, &val);
xf86DrvMsg(sil->d.pI2CBus->scrnIndex, X_INFO, "SIL164_FREQ_HI: 0x%02x\n",
val);
sil164ReadByte(sil, SIL164_REG8, &val);
xf86DrvMsg(sil->d.pI2CBus->scrnIndex, X_INFO, "SIL164_REG8: 0x%02x\n", val);
sil164ReadByte(sil, SIL164_REG9, &val);
xf86DrvMsg(sil->d.pI2CBus->scrnIndex, X_INFO, "SIL164_REG9: 0x%02x\n", val);
sil164ReadByte(sil, SIL164_REGC, &val);
xf86DrvMsg(sil->d.pI2CBus->scrnIndex, X_INFO, "SIL164_REGC: 0x%02x\n", val);
}
static void
sil164SaveRegs(I2CDevPtr d)
{
SIL164Ptr sil = SILPTR(d);
if (!sil164ReadByte(sil, SIL164_REG8, &sil->SavedReg.reg8))
return;
if (!sil164ReadByte(sil, SIL164_REG9, &sil->SavedReg.reg9))
return;
if (!sil164ReadByte(sil, SIL164_REGC, &sil->SavedReg.regc))
return;
return;
}
static void
sil164RestoreRegs(I2CDevPtr d)
{
SIL164Ptr sil = SILPTR(d);
/* Restore it powered down initially */
sil164WriteByte(sil, SIL164_REG8, sil->SavedReg.reg8 & ~0x1);
sil164WriteByte(sil, SIL164_REG9, sil->SavedReg.reg9);
sil164WriteByte(sil, SIL164_REGC, sil->SavedReg.regc);
sil164WriteByte(sil, SIL164_REG8, sil->SavedReg.reg8);
}
I830I2CVidOutputRec SIL164VidOutput = {
sil164Detect,
sil164Init,
sil164ModeValid,
sil164Mode,
sil164Power,
sil164PrintRegs,
sil164SaveRegs,
sil164RestoreRegs,
};

31
src/sil164/sil164.h Normal file
View File

@ -0,0 +1,31 @@
/**************************************************************************
Copyright 2006 Dave Airlie <airlied@linux.ie>
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.
**************************************************************************/
#ifndef SIL164_H
#define SIL164_H
#define SIL164_ADDR_1 0x38
#endif

View File

@ -0,0 +1,38 @@
/* -*- c-basic-offset: 4 -*- */
#ifdef HAVE_XORG_CONFIG_H
#include <xorg-config.h>
#endif
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "xf86Module.h"
static MODULESETUPPROTO(sil164Setup);
static XF86ModuleVersionInfo sil164VersRec = {
"sil164",
MODULEVENDORSTRING,
MODINFOSTRING1,
MODINFOSTRING2,
XORG_VERSION_CURRENT,
1, 0, 0,
ABI_CLASS_VIDEODRV,
ABI_VIDEODRV_VERSION,
MOD_CLASS_NONE,
{ 0,0,0,0 }
};
_X_EXPORT XF86ModuleData sil164ModuleData = {
&sil164VersRec,
sil164Setup,
NULL
};
static pointer
sil164Setup(pointer module, pointer opts, int *errmaj, int *errmin)
{
return (pointer)1;
}

74
src/sil164/sil164_reg.h Normal file
View File

@ -0,0 +1,74 @@
/* -*- c-basic-offset: 4 -*- */
/**************************************************************************
Copyright 2006 Dave Airlie <airlied@linux.ie>
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.
**************************************************************************/
#ifndef SIL164_REG_H
#define SIL164_REG_H
#define SIL164_VID 0x0001
#define SIL164_DID 0x0006
#define SIL164_VID_LO 0x00
#define SIL164_VID_HI 0x01
#define SIL164_DID_LO 0x02
#define SIL164_DID_HI 0x03
#define SIL164_REV 0x04
#define SIL164_RSVD 0x05
#define SIL164_FREQ_LO 0x06
#define SIL164_FREQ_HI 0x07
#define SIL164_REG8 0x08
#define SIL164_8_VEN (1<<5)
#define SIL164_8_HEN (1<<4)
#define SIL164_8_DSEL (1<<3)
#define SIL164_8_BSEL (1<<2)
#define SIL164_8_EDGE (1<<1)
#define SIL164_8_PD (1<<0)
#define SIL164_REG9 0x09
#define SIL164_9_VLOW (1<<7)
#define SIL164_9_MSEL_MASK (0x7<<4)
#define SIL164_9_TSEL (1<<3)
#define SIL164_9_RSEN (1<<2)
#define SIL164_9_HTPLG (1<<1)
#define SIL164_9_MDI (1<<0)
#define SIL164_REGC 0x0c
typedef struct _Sil164SaveRec {
CARD8 reg8;
CARD8 reg9;
CARD8 regc;
} SIL164SaveRec;
typedef struct {
I2CDevRec d;
SIL164SaveRec SavedReg;
SIL164SaveRec ModeReg;
} SIL164Rec, *SIL164Ptr;
#define SILPTR(d) ((SIL164Ptr)(d->DriverPrivate.ptr))
#endif

6
src/xvmc/.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
.deps
.libs
Makefile
Makefile.in
*.la
*.lo

View File

@ -1558,6 +1558,11 @@ static __inline__ void renderDualPrimeinField(uint **datay,uint **datau,
// Description: inline function that sets hardware parameters for a Field
// encoded macroblock in a frame picture.
***************************************************************************/
typedef union {
short s[4];
uint u[2];
} su_t;
static __inline__ void renderFieldinFrame(uint **datay,uint **datau,
uint **datav,
XvMCMacroBlock *mb,short *block_ptr,
@ -1568,8 +1573,8 @@ static __inline__ void renderFieldinFrame(uint **datay,uint **datau,
register uint *dv = *datav;
/* Motion Vectors */
short fmv[4];
short bmv[4];
su_t fmv;
su_t bmv;
/* gfxblock dword 1 */
uint dw1[2];
@ -1589,23 +1594,23 @@ static __inline__ void renderFieldinFrame(uint **datay,uint **datau,
(((mb->coded_block_pattern & 0x3) |
((mb->coded_block_pattern & 0xc)<<2))<<22);
fmv[0] = mb->PMV[0][0][1]/2;
fmv[1] = mb->PMV[0][0][0];
fmv[2] = mb->PMV[1][0][1]/2;
fmv[3] = mb->PMV[1][0][0];
fmv.s[0] = mb->PMV[0][0][1]/2;
fmv.s[1] = mb->PMV[0][0][0];
fmv.s[2] = mb->PMV[1][0][1]/2;
fmv.s[3] = mb->PMV[1][0][0];
bmv[0] = mb->PMV[0][1][1]/2;
bmv[1] = mb->PMV[0][1][0];
bmv[2] = mb->PMV[1][1][1]/2;
bmv[3] = mb->PMV[1][1][0];
bmv.s[0] = mb->PMV[0][1][1]/2;
bmv.s[1] = mb->PMV[0][1][0];
bmv.s[2] = mb->PMV[1][1][1]/2;
bmv.s[3] = mb->PMV[1][1][0];
/* First Y Block */
*dy++ = GFXBLOCK + 4 + (y1size>>2);
*dy++ = (1<<30) | (2<<28) | dw1[0];
*dy++ = xy;
*dy++ = (8<<16) | 16;
*dy++ = *(uint *)&fmv[0];
*dy++ = *(uint *)&bmv[0];
*dy++ = fmv.u[0];
*dy++ = bmv.u[0];
PACK_CORR_DATA(dy,block_ptr,y1size);
block_ptr = (short *)((unsigned long)block_ptr + y1size);
@ -1614,21 +1619,21 @@ static __inline__ void renderFieldinFrame(uint **datay,uint **datau,
*dy++ = (1<<30) | (2<<28) | dw1[1];
*dy++ = xy;
*dy++ = (8<<16) | 16;
*dy++ = *(uint *)&fmv[2];
*dy++ = *(uint *)&bmv[2];
*dy++ = fmv.u[1];
*dy++ = bmv.u[1];
PACK_CORR_DATA(dy,block_ptr,y2size);
block_ptr = (short *)((unsigned long)block_ptr + y2size);
/* End Y Blocks */
fmv[0] /= 2;
fmv[1] /= 2;
fmv[2] /= 2;
fmv[3] /= 2;
fmv.s[0] /= 2;
fmv.s[1] /= 2;
fmv.s[2] /= 2;
fmv.s[3] /= 2;
bmv[0] /= 2;
bmv[1] /= 2;
bmv[2] /= 2;
bmv[3] /= 2;
bmv.s[0] /= 2;
bmv.s[1] /= 2;
bmv.s[2] /= 2;
bmv.s[3] /= 2;
xy >>= 1;
@ -1637,8 +1642,8 @@ static __inline__ void renderFieldinFrame(uint **datay,uint **datau,
*du++ = (2<<30) | (1<<28) | dw1[0];
*du++ = xy;
*du++ = (4<<16) | 8;
*du++ = *(uint *)&fmv[0];
*du++ = *(uint *)&bmv[0];
*du++ = fmv.u[0];
*du++ = bmv.u[0];
if(usize) {
PACK_CORR_DATA_SHORT(du,block_ptr);
}
@ -1648,8 +1653,8 @@ static __inline__ void renderFieldinFrame(uint **datay,uint **datau,
*du++ = (2<<30) | (1<<28) | dw1[1];
*du++ = xy;
*du++ = (4<<16) | 8;
*du++ = *(uint *)&fmv[2];
*du++ = *(uint *)&bmv[2];
*du++ = fmv.u[1];
*du++ = bmv.u[1];
if(usize) {
block_ptr = (short *)((unsigned long)block_ptr + 16);
PACK_CORR_DATA_SHORT(du,block_ptr);
@ -1662,8 +1667,8 @@ static __inline__ void renderFieldinFrame(uint **datay,uint **datau,
*dv++ = (3<<30) | (1<<28) | dw1[0];
*dv++ = xy;
*dv++ = (4<<16) | 8;
*dv++ = *(uint *)&fmv[0];
*dv++ = *(uint *)&bmv[0];
*dv++ = fmv.u[0];
*dv++ = bmv.u[0];
if(vsize) {
PACK_CORR_DATA_SHORT(dv,block_ptr);
}
@ -1673,8 +1678,8 @@ static __inline__ void renderFieldinFrame(uint **datay,uint **datau,
*dv++ = (3<<30) | (1<<28) | dw1[1];
*dv++ = xy;
*dv++ = (4<<16) | 8;
*dv++ = *(uint *)&fmv[2];
*dv++ = *(uint *)&bmv[2];
*dv++ = fmv.u[1];
*dv++ = bmv.u[1];
if(vsize) {
block_ptr = (short *)((unsigned long)block_ptr + 16);
PACK_CORR_DATA_SHORT(dv,block_ptr);
@ -1701,8 +1706,8 @@ static __inline__ void renderFieldinFrameDCT0(uint **datay,uint **datau,
register uint *dv = *datav;
/* Motion Vectors */
short fmv[4];
short bmv[4];
su_t fmv;
su_t bmv;
/* CBP */
uint cbp = (uint)mb->coded_block_pattern;
/* gfxblock dword 1 */
@ -1728,15 +1733,15 @@ static __inline__ void renderFieldinFrameDCT0(uint **datay,uint **datau,
((cbp | ((cbp<<2) & 0x30))<<22);
fmv[0] = mb->PMV[0][0][1]/2;
fmv[1] = mb->PMV[0][0][0];
fmv[2] = mb->PMV[1][0][1]/2;
fmv[3] = mb->PMV[1][0][0];
fmv.s[0] = mb->PMV[0][0][1]/2;
fmv.s[1] = mb->PMV[0][0][0];
fmv.s[2] = mb->PMV[1][0][1]/2;
fmv.s[3] = mb->PMV[1][0][0];
bmv[0] = mb->PMV[0][1][1]/2;
bmv[1] = mb->PMV[0][1][0];
bmv[2] = mb->PMV[1][1][1]/2;
bmv[3] = mb->PMV[1][1][0];
bmv.s[0] = mb->PMV[0][1][1]/2;
bmv.s[1] = mb->PMV[0][1][0];
bmv.s[2] = mb->PMV[1][1][1]/2;
bmv.s[3] = mb->PMV[1][1][0];
/*
The i810 cannot use DCT0 directly with field motion, we have to
@ -1772,8 +1777,8 @@ static __inline__ void renderFieldinFrameDCT0(uint **datay,uint **datau,
*dy++ = (1<<30) | (2<<28) | dw1[0];
*dy++ = xy;
*dy++ = (8<<16) | 16;
*dy++ = *(uint *)&fmv[0];
*dy++ = *(uint *)&bmv[0];
*dy++ = fmv.u[0];
*dy++ = bmv.u[0];
if(dw1[0] & (1<<27)) {
PACK_CORR_DATA_0to1(dy,top_left_b,bottom_left_b);
}
@ -1786,8 +1791,8 @@ static __inline__ void renderFieldinFrameDCT0(uint **datay,uint **datau,
*dy++ = (1<<30) | (2<<28) | dw1[1];
*dy++ = xy;
*dy++ = (8<<16) | 16;
*dy++ = *(uint *)&fmv[2];
*dy++ = *(uint *)&bmv[2];
*dy++ = fmv.u[1];
*dy++ = bmv.u[1];
if(dw1[1] & (1<<27)) {
top_left_b = (short *)((unsigned long)top_left_b + 16);
bottom_left_b = (short *)((unsigned long)bottom_left_b + 16);
@ -1800,15 +1805,15 @@ static __inline__ void renderFieldinFrameDCT0(uint **datay,uint **datau,
}
/* End Y Blocks */
fmv[0] /= 2;
fmv[1] /= 2;
fmv[2] /= 2;
fmv[3] /= 2;
fmv.s[0] /= 2;
fmv.s[1] /= 2;
fmv.s[2] /= 2;
fmv.s[3] /= 2;
bmv[0] /= 2;
bmv[1] /= 2;
bmv[2] /= 2;
bmv[3] /= 2;
bmv.s[0] /= 2;
bmv.s[1] /= 2;
bmv.s[2] /= 2;
bmv.s[3] /= 2;
xy >>= 1;
@ -1817,8 +1822,8 @@ static __inline__ void renderFieldinFrameDCT0(uint **datay,uint **datau,
*du++ = (2<<30) | (1<<28) | dw1[0];
*du++ = xy;
*du++ = (4<<16) | 8;
*du++ = *(uint *)&fmv[0];
*du++ = *(uint *)&bmv[0];
*du++ = fmv.u[0];
*du++ = bmv.u[0];
if(usize) {
PACK_CORR_DATA_SHORT(du,block_ptr);
}
@ -1828,8 +1833,8 @@ static __inline__ void renderFieldinFrameDCT0(uint **datay,uint **datau,
*du++ = (2<<30) | (1<<28) | dw1[1];
*du++ = xy;
*du++ = (4<<16) | 8;
*du++ = *(uint *)&fmv[2];
*du++ = *(uint *)&bmv[2];
*du++ = fmv.u[1];
*du++ = bmv.u[1];
if(usize) {
block_ptr = (short *)((unsigned long)block_ptr + 16);
PACK_CORR_DATA_SHORT(du,block_ptr);
@ -1842,8 +1847,8 @@ static __inline__ void renderFieldinFrameDCT0(uint **datay,uint **datau,
*dv++ = (3<<30) | (1<<28) | dw1[0];
*dv++ = xy;
*dv++ = (4<<16) | 8;
*dv++ = *(uint *)&fmv[0];
*dv++ = *(uint *)&bmv[0];
*dv++ = fmv.u[0];
*dv++ = bmv.u[0];
if(vsize) {
PACK_CORR_DATA_SHORT(dv,block_ptr);
}
@ -1853,8 +1858,8 @@ static __inline__ void renderFieldinFrameDCT0(uint **datay,uint **datau,
*dv++ = (3<<30) | (1<<28) | dw1[1];
*dv++ = xy;
*dv++ = (4<<16) | 8;
*dv++ = *(uint *)&fmv[2];
*dv++ = *(uint *)&bmv[2];
*dv++ = fmv.u[1];
*dv++ = bmv.u[1];
if(vsize) {
block_ptr = (short *)((unsigned long)block_ptr + 16);
PACK_CORR_DATA_SHORT(dv,block_ptr);
@ -1882,8 +1887,8 @@ static __inline__ void renderFrameinFrame(uint **datay,uint **datau,
register uint *dv = *datav;
/* Motion Vectors */
short fmv[2];
short bmv[2];
su_t fmv;
su_t bmv;
/* gfxblock dword 1 */
uint dw1;
@ -1897,28 +1902,28 @@ static __inline__ void renderFrameinFrame(uint **datay,uint **datau,
(((uint)mb->coded_block_pattern)<<22);
fmv[0] = mb->PMV[0][0][1];
fmv[1] = mb->PMV[0][0][0];
fmv.s[0] = mb->PMV[0][0][1];
fmv.s[1] = mb->PMV[0][0][0];
bmv[0] = mb->PMV[0][1][1];
bmv[1] = mb->PMV[0][1][0];
bmv.s[0] = mb->PMV[0][1][1];
bmv.s[1] = mb->PMV[0][1][0];
/* Y Block */
*dy++ = GFXBLOCK + 4 + (ysize>>2);
*dy++ = (1<<30) | (3<<28) | dw1;
*dy++ = xy;
*dy++ = (16<<16) | 16;
*dy++ = *(uint *)fmv;
*dy++ = *(uint *)bmv;
*dy++ = fmv.u[0];
*dy++ = bmv.u[0];
PACK_CORR_DATA(dy,block_ptr,ysize);
block_ptr = (short *)((unsigned long)block_ptr + ysize);
/* End Y Blocks */
fmv[0] /= 2;
fmv[1] /= 2;
fmv.s[0] /= 2;
fmv.s[1] /= 2;
bmv[0] /= 2;
bmv[1] /= 2;
bmv.s[0] /= 2;
bmv.s[1] /= 2;
xy >>= 1;
@ -1927,8 +1932,8 @@ static __inline__ void renderFrameinFrame(uint **datay,uint **datau,
*du++ = (2<<30) | (1<<28) | dw1;
*du++ = xy;
*du++ = (8<<16) | 8;
*du++ = *(uint *)fmv;
*du++ = *(uint *)bmv;
*du++ = fmv.u[0];
*du++ = bmv.u[0];
PACK_CORR_DATA(du,block_ptr,usize);
block_ptr = (short *)((unsigned long)block_ptr + usize);
/* End U Block */
@ -1938,8 +1943,8 @@ static __inline__ void renderFrameinFrame(uint **datay,uint **datau,
*dv++ = (3<<30) | (1<<28) | dw1;
*dv++ = xy;
*dv++ = (8<<16) | 8;
*dv++ = *(uint *)fmv;
*dv++ = *(uint *)bmv;
*dv++ = fmv.u[0];
*dv++ = bmv.u[0];
PACK_CORR_DATA(dv,block_ptr,vsize);
block_ptr = (short *)((unsigned long)block_ptr + vsize);
/* End V Block */
@ -1963,8 +1968,8 @@ static __inline__ void renderFrameinFrameDCT1(uint **datay,uint **datau,
register uint *dv = *datav;
/* Motion Vectors */
short fmv[4];
short bmv[4];
su_t fmv;
su_t bmv;
short * top_left_b = NULL;
short * top_right_b = NULL;
@ -1982,11 +1987,11 @@ static __inline__ void renderFrameinFrameDCT1(uint **datay,uint **datau,
uint dw1 = type_table[mb->macroblock_type & 0xf] |
(((uint)mb->coded_block_pattern)<<22);
fmv[0] = mb->PMV[0][0][1];
fmv[1] = mb->PMV[0][0][0];
fmv.s[0] = mb->PMV[0][0][1];
fmv.s[1] = mb->PMV[0][0][0];
bmv[0] = mb->PMV[0][1][1];
bmv[1] = mb->PMV[0][1][0];
bmv.s[0] = mb->PMV[0][1][1];
bmv.s[1] = mb->PMV[0][1][0];
/*
It is easiest to find out what blocks are in need of reading first
@ -2026,8 +2031,8 @@ static __inline__ void renderFrameinFrameDCT1(uint **datay,uint **datau,
*dy++ = (1<<30) | (3<<28) | dw1;
*dy++ = xy;
*dy++ = (16<<16) | 16;
*dy++ = *(uint *)fmv;
*dy++ = *(uint *)bmv;
*dy++ = fmv.u[0];
*dy++ = bmv.u[0];
if(dw1 & (1<<27)) {
PACK_CORR_DATA_1to0(dy,top_left_b,bottom_left_b);
top_left_b = (short *)((unsigned long)top_left_b + 64);
@ -2046,11 +2051,11 @@ static __inline__ void renderFrameinFrameDCT1(uint **datay,uint **datau,
}
/* End Y Block */
fmv[0] /= 2;
fmv[1] /= 2;
fmv.s[0] /= 2;
fmv.s[1] /= 2;
bmv[0] /= 2;
bmv[1] /= 2;
bmv.s[0] /= 2;
bmv.s[1] /= 2;
xy >>= 1;
@ -2059,8 +2064,8 @@ static __inline__ void renderFrameinFrameDCT1(uint **datay,uint **datau,
*du++ = (2<<30) | (1<<28) | dw1;
*du++ = xy;
*du++ = (8<<16) | 8;
*du++ = *(uint *)fmv;
*du++ = *(uint *)bmv;
*du++ = fmv.u[0];
*du++ = bmv.u[0];
PACK_CORR_DATA(du,block_ptr,usize);
block_ptr = (short *)((unsigned long)block_ptr + usize);
@ -2069,8 +2074,8 @@ static __inline__ void renderFrameinFrameDCT1(uint **datay,uint **datau,
*dv++ = (3<<30) | (1<<28) | dw1;
*dv++ = xy;
*dv++ = (8<<16) | 8;
*dv++ = *(uint *)fmv;
*dv++ = *(uint *)bmv;
*dv++ = fmv.u[0];
*dv++ = bmv.u[0];
PACK_CORR_DATA(dv,block_ptr,vsize);
block_ptr = (short *)((unsigned long)block_ptr + vsize);
@ -2093,8 +2098,8 @@ static __inline__ void renderDualPrimeinFrame(uint **datay,uint **datau,
register uint *dv = *datav;
/* Motion Vectors */
short fmv[4];
short bmv[4];
su_t fmv;
su_t bmv;
/* gfxblock dword 1 */
uint dw1[2];
@ -2115,23 +2120,23 @@ static __inline__ void renderDualPrimeinFrame(uint **datay,uint **datau,
((mb->coded_block_pattern & 0xc)<<2))<<22) |
3<<12 | 3<<6 | 3<<3 | 2;
fmv[0] = mb->PMV[0][0][1];
fmv[1] = mb->PMV[0][0][0];
bmv[0] = mb->PMV[1][0][1];
bmv[1] = mb->PMV[1][0][0];
fmv.s[0] = mb->PMV[0][0][1];
fmv.s[1] = mb->PMV[0][0][0];
bmv.s[0] = mb->PMV[1][0][1];
bmv.s[1] = mb->PMV[1][0][0];
fmv[2] = mb->PMV[0][0][1];
fmv[3] = mb->PMV[0][0][0];
bmv[2] = mb->PMV[1][1][1];
bmv[3] = mb->PMV[1][1][0];
fmv.s[2] = mb->PMV[0][0][1];
fmv.s[3] = mb->PMV[0][0][0];
bmv.s[2] = mb->PMV[1][1][1];
bmv.s[3] = mb->PMV[1][1][0];
/* First Y Block */
*dy++ = GFXBLOCK + 4 + (y1size>>2);
*dy++ = (1<<30) | (2<<28) | dw1[0];
*dy++ = xy;
*dy++ = (8<<16) | 16;
*dy++ = *(uint *)fmv;
*dy++ = *(uint *)bmv;;
*dy++ = fmv.u[0];
*dy++ = bmv.u[0];;
PACK_CORR_DATA(dy,block_ptr,y1size);
block_ptr = (short *)((unsigned long)block_ptr + y1size);
@ -2140,20 +2145,20 @@ static __inline__ void renderDualPrimeinFrame(uint **datay,uint **datau,
*dy++ = (1<<30) | (2<<28) | dw1[1];
*dy++ = xy;
*dy++ = (8<<16) | 16;
*dy++ = *(uint *)&fmv[2];
*dy++ = *(uint *)&bmv[2];
*dy++ = fmv.u[1];
*dy++ = bmv.u[1];
PACK_CORR_DATA(dy,block_ptr,y2size);
block_ptr = (short *)((unsigned long)block_ptr + y2size);
fmv[0] /= 2;
fmv[1] /= 2;
bmv[0] /= 2;
bmv[1] /= 2;
fmv.s[0] /= 2;
fmv.s[1] /= 2;
bmv.s[0] /= 2;
bmv.s[1] /= 2;
fmv[2] /= 2;
fmv[3] /= 2;
bmv[2] /= 2;
bmv[3] /= 2;
fmv.s[2] /= 2;
fmv.s[3] /= 2;
bmv.s[2] /= 2;
bmv.s[3] /= 2;
xy >>= 1;
@ -2162,8 +2167,8 @@ static __inline__ void renderDualPrimeinFrame(uint **datay,uint **datau,
*du++ = (2<<30) | (1<<28) | dw1[0];
*du++ = xy;
*du++ = (4<<16) | 8;
*du++ = *(uint *)fmv;
*du++ = *(uint *)bmv;
*du++ = fmv.u[0];
*du++ = bmv.u[0];
if(dw1[0] & (1<<23)) {
PACK_CORR_DATA_SHORT(du,block_ptr);
}
@ -2173,8 +2178,8 @@ static __inline__ void renderDualPrimeinFrame(uint **datay,uint **datau,
*du++ = (2<<30) | (1<<28) | dw1[1];
*du++ = xy;
*du++ = (4<<16) | 8;
*du++ = *(uint *)&fmv[2];
*du++ = *(uint *)&bmv[2];
*du++ = fmv.u[1];
*du++ = bmv.u[1];
if(dw1[1] & (1<<23)) {
block_ptr = (short *)((unsigned long)block_ptr + 16);
PACK_CORR_DATA_SHORT(du,block_ptr);
@ -2187,8 +2192,8 @@ static __inline__ void renderDualPrimeinFrame(uint **datay,uint **datau,
*dv++ = (3<<30) | (1<<28) | dw1[0];
*dv++ = xy;
*dv++ = (4<<16) | 8;
*dv++ = *(uint *)fmv;
*dv++ = *(uint *)bmv;
*dv++ = fmv.u[0];
*dv++ = bmv.u[0];
if(dw1[0] & (1<<22)) {
PACK_CORR_DATA_SHORT(dv,block_ptr);
}
@ -2198,8 +2203,8 @@ static __inline__ void renderDualPrimeinFrame(uint **datay,uint **datau,
*dv++ = (3<<30) | (1<<28) | dw1[1];
*dv++ = xy;
*dv++ = (4<<16) | 8;
*dv++ = *(uint *)&fmv[2];
*dv++ = *(uint *)&bmv[2];
*dv++ = fmv.u[1];
*dv++ = bmv.u[1];
if(dw1[1] & (1<<22)) {
block_ptr = (short *)((unsigned long)block_ptr + 16);
PACK_CORR_DATA_SHORT(dv,block_ptr);
@ -2228,8 +2233,8 @@ static __inline__ void renderDualPrimeinFrameDCT0(uint **datay,uint **datau,
register uint *dv = *datav;
/* Motion Vectors */
short fmv[4];
short bmv[4];
su_t fmv;
su_t bmv;
/* gfxblock dword 1 */
uint dw1[2];
@ -2255,15 +2260,15 @@ static __inline__ void renderDualPrimeinFrameDCT0(uint **datay,uint **datau,
dw1[1] = ((cbp | ((cbp<<2) & 0x30))<<22) |
3<<12 | 3<<6 | 3<<3 | 2;
fmv[0] = mb->PMV[0][0][1];
fmv[1] = mb->PMV[0][0][0];
bmv[0] = mb->PMV[1][0][1];
bmv[1] = mb->PMV[1][0][0];
fmv.s[0] = mb->PMV[0][0][1];
fmv.s[1] = mb->PMV[0][0][0];
bmv.s[0] = mb->PMV[1][0][1];
bmv.s[1] = mb->PMV[1][0][0];
fmv[2] = mb->PMV[0][0][1];
fmv[3] = mb->PMV[0][0][0];
bmv[2] = mb->PMV[1][1][1];
bmv[3] = mb->PMV[1][1][0];
fmv.s[2] = mb->PMV[0][0][1];
fmv.s[3] = mb->PMV[0][0][0];
bmv.s[2] = mb->PMV[1][1][1];
bmv.s[3] = mb->PMV[1][1][0];
/*
The i810 cannot use DCT0 directly with field motion, we have to
@ -2299,8 +2304,8 @@ static __inline__ void renderDualPrimeinFrameDCT0(uint **datay,uint **datau,
*dy++ = (1<<30) | (2<<28) | dw1[0];
*dy++ = xy;
*dy++ = (8<<16) | 16;
*dy++ = *(uint *)fmv;
*dy++ = *(uint *)bmv;
*dy++ = fmv.u[0];
*dy++ = bmv.u[0];
if(cbp & 0x20) {
PACK_CORR_DATA_0to1(dy,top_left_b,bottom_left_b);
}
@ -2313,8 +2318,8 @@ static __inline__ void renderDualPrimeinFrameDCT0(uint **datay,uint **datau,
*dy++ = (1<<30) | (2<<28) | dw1[1];
*dy++ = xy;
*dy++ = (8<<16) | 16;
*dy++ = *(uint *)&fmv[2];
*dy++ = *(uint *)&bmv[2];
*dy++ = fmv.u[1];
*dy++ = bmv.u[1];
if(cbp & 0x20) {
top_left_b = (short *)((unsigned long)top_left_b + 16);
bottom_left_b = (short *)((unsigned long)bottom_left_b + 16);
@ -2328,15 +2333,15 @@ static __inline__ void renderDualPrimeinFrameDCT0(uint **datay,uint **datau,
/* End Y Blocks */
fmv[0] /= 2;
fmv[1] /= 2;
bmv[0] /= 2;
bmv[1] /= 2;
fmv.s[0] /= 2;
fmv.s[1] /= 2;
bmv.s[0] /= 2;
bmv.s[1] /= 2;
fmv[2] /= 2;
fmv[3] /= 2;
bmv[2] /= 2;
bmv[3] /= 2;
fmv.s[2] /= 2;
fmv.s[3] /= 2;
bmv.s[2] /= 2;
bmv.s[3] /= 2;
xy >>= 1;
@ -2345,8 +2350,8 @@ static __inline__ void renderDualPrimeinFrameDCT0(uint **datay,uint **datau,
*du++ = (2<<30) | (1<<28) | dw1[0];
*du++ = xy;
*du++ = (4<<16) | 8;
*du++ = *(uint *)fmv;
*du++ = *(uint *)bmv;
*du++ = fmv.u[0];
*du++ = bmv.u[0];
if(cbp & (1<<23)) {
PACK_CORR_DATA_SHORT(du,block_ptr);
}
@ -2356,8 +2361,8 @@ static __inline__ void renderDualPrimeinFrameDCT0(uint **datay,uint **datau,
*du++ = (2<<30) | (1<<28) | dw1[1];
*du++ = xy;
*du++ = (4<<16) | 8;
*du++ = *(uint *)&fmv[2];
*du++ = *(uint *)&bmv[2];
*du++ = fmv.u[1];
*du++ = bmv.u[1];
if(cbp & (1<<23)) {
block_ptr = (short *)((unsigned long)block_ptr + 16);
PACK_CORR_DATA_SHORT(du,block_ptr);
@ -2370,8 +2375,8 @@ static __inline__ void renderDualPrimeinFrameDCT0(uint **datay,uint **datau,
*dv++ = (3<<30) | (1<<28) | dw1[0];
*dv++ = xy;
*dv++ = (4<<16) | 8;
*dv++ = *(uint *)fmv;
*dv++ = *(uint *)bmv;
*dv++ = fmv.u[0];
*dv++ = bmv.u[0];
if(cbp & (1<<22)) {
PACK_CORR_DATA_SHORT(dv,block_ptr);
}
@ -2381,8 +2386,8 @@ static __inline__ void renderDualPrimeinFrameDCT0(uint **datay,uint **datau,
*dv++ = (3<<30) | (1<<28) | dw1[1];
*dv++ = xy;
*dv++ = (4<<16) | 8;
*dv++ = *(uint *)&fmv[2];
*dv++ = *(uint *)&bmv[2];
*dv++ = fmv.u[1];
*dv++ = bmv.u[1];
if(cbp & (1<<22)) {
block_ptr = (short *)((unsigned long)block_ptr + 16);
PACK_CORR_DATA_SHORT(dv,block_ptr);