diff --git a/.gitignore b/.gitignore index 6f660b9c..cb52e9fa 100644 --- a/.gitignore +++ b/.gitignore @@ -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 diff --git a/TODO b/TODO new file mode 100644 index 00000000..17e1449f --- /dev/null +++ b/TODO @@ -0,0 +1,3 @@ +- licensing of new files +- Figure out what exactly doublescan, interlace mean, and see if we support them. +- Remove VbeModeInfoData diff --git a/configure.ac b/configure.ac index fc0f9cd8..b1dd287f 100644 --- a/configure.ac +++ b/configure.ac @@ -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 ]) diff --git a/man/.cvsignore b/man/.cvsignore deleted file mode 100644 index 282522db..00000000 --- a/man/.cvsignore +++ /dev/null @@ -1,2 +0,0 @@ -Makefile -Makefile.in diff --git a/man/i810.man b/man/i810.man index a3f25ec6..fa588fb9 100644 --- a/man/i810.man +++ b/man/i810.man @@ -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 diff --git a/src/xvmc/.cvsignore b/src/.gitignore similarity index 100% rename from src/xvmc/.cvsignore rename to src/.gitignore diff --git a/src/Makefile.am b/src/Makefile.am index ce7b40e4..0fce5e4f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -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 \ diff --git a/src/bios_reader/.gitignore b/src/bios_reader/.gitignore new file mode 100644 index 00000000..3e325072 --- /dev/null +++ b/src/bios_reader/.gitignore @@ -0,0 +1 @@ +bios_reader diff --git a/src/bios_reader/Makefile.am b/src/bios_reader/Makefile.am new file mode 100644 index 00000000..f18a00c3 --- /dev/null +++ b/src/bios_reader/Makefile.am @@ -0,0 +1,4 @@ +AM_CFLAGS = @XORG_CFLAGS@ + +noinst_PROGRAMS = bios_reader + diff --git a/src/bios_reader/bios_reader.c b/src/bios_reader/bios_reader.c new file mode 100644 index 00000000..a52bcc72 --- /dev/null +++ b/src/bios_reader/bios_reader.c @@ -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 + * + */ + +#include +#include +#include +#include + +#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; +} diff --git a/src/ch7xxx/Makefile.am b/src/ch7xxx/Makefile.am new file mode 100644 index 00000000..645ac692 --- /dev/null +++ b/src/ch7xxx/Makefile.am @@ -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 diff --git a/src/ch7xxx/ch7xxx.c b/src/ch7xxx/ch7xxx.c new file mode 100644 index 00000000..d11c3550 --- /dev/null +++ b/src/ch7xxx/ch7xxx.c @@ -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 +#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, +}; diff --git a/src/ch7xxx/ch7xxx.h b/src/ch7xxx/ch7xxx.h new file mode 100644 index 00000000..679c5313 --- /dev/null +++ b/src/ch7xxx/ch7xxx.h @@ -0,0 +1,31 @@ +/************************************************************************** + + Copyright 2006 Dave Airlie + +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 diff --git a/src/ch7xxx/ch7xxx_module.c b/src/ch7xxx/ch7xxx_module.c new file mode 100644 index 00000000..19dc6cd1 --- /dev/null +++ b/src/ch7xxx/ch7xxx_module.c @@ -0,0 +1,36 @@ +#ifdef HAVE_XORG_CONFIG_H +#include +#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; +} diff --git a/src/ch7xxx/ch7xxx_reg.h b/src/ch7xxx/ch7xxx_reg.h new file mode 100644 index 00000000..59de13b8 --- /dev/null +++ b/src/ch7xxx/ch7xxx_reg.h @@ -0,0 +1,91 @@ +/************************************************************************** + + Copyright 2006 Dave Airlie + +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 diff --git a/src/common.h b/src/common.h index d808b214..47d564d0 100644 --- a/src/common.h +++ b/src/common.h @@ -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); \ } \ diff --git a/src/i2c_vid.h b/src/i2c_vid.h new file mode 100644 index 00000000..5a743d29 --- /dev/null +++ b/src/i2c_vid.h @@ -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 diff --git a/src/i810_driver.c b/src/i810_driver.c index a31e4cf8..63a24d7c 100644 --- a/src/i810_driver.c +++ b/src/i810_driver.c @@ -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 } diff --git a/src/i810_reg.h b/src/i810_reg.h index 4bb5bf14..0ece7ee8 100644 --- a/src/i810_reg.h +++ b/src/i810_reg.h @@ -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 + * Eric Anholt * * based on the i740 driver by * Kevin E. Martin @@ -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)| \ diff --git a/src/i830.h b/src/i830.h index 0df41e33..32a540ef 100644 --- a/src/i830.h +++ b/src/i830.h @@ -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 /* required */ -/* I830 Video BIOS support */ - /* * The mode handling is based upon the VESA driver written by * Paulo César Pereira de Andrade . */ -#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 diff --git a/src/i830_bios.c b/src/i830_bios.c new file mode 100644 index 00000000..0821845a --- /dev/null +++ b/src/i830_bios.c @@ -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 + * + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#undef VERSION /* XXX edid.h has a VERSION too */ +#endif + +#include +#include + +#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; +} diff --git a/src/i830_bios.h b/src/i830_bios.h new file mode 100644 index 00000000..9bd0db8a --- /dev/null +++ b/src/i830_bios.h @@ -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 + * + */ + +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); diff --git a/src/i830_crt.c b/src/i830_crt.c new file mode 100644 index 00000000..f067260d --- /dev/null +++ b/src/i830_crt.c @@ -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 + * + */ + +#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++; +} diff --git a/src/i830_cursor.c b/src/i830_cursor.c index 8343b6b1..517bd3e0 100644 --- a/src/i830_cursor.c +++ b/src/i830_cursor.c @@ -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); diff --git a/src/i830_debug.c b/src/i830_debug.c new file mode 100644 index 00000000..7922af0a --- /dev/null +++ b/src/i830_debug.c @@ -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 + * + */ + +#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"); +} diff --git a/src/i830_debug.h b/src/i830_debug.h new file mode 100644 index 00000000..a8e38398 --- /dev/null +++ b/src/i830_debug.h @@ -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 + * + */ + +void i830TakeRegSnapshot(ScrnInfoPtr pScrn); +void i830CompareRegsToSnapshot(ScrnInfoPtr pScrn); +void i830DumpRegs (ScrnInfoPtr pScrn); diff --git a/src/i830_dga.c b/src/i830_dga.c index bd45d61d..1a6e4e69 100644 --- a/src/i830_dga.c +++ b/src/i830_dga.c @@ -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; diff --git a/src/i830_display.c b/src/i830_display.c new file mode 100644 index 00000000..bd40e4ee --- /dev/null +++ b/src/i830_display.c @@ -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 + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include + +#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; + } +} diff --git a/src/i830_display.h b/src/i830_display.h new file mode 100644 index 00000000..361a3c67 --- /dev/null +++ b/src/i830_display.h @@ -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 + * + */ + +/* 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); diff --git a/src/i830_dri.c b/src/i830_dri.c index 524c4de7..6b17f466 100644 --- a/src/i830_dri.c +++ b/src/i830_dri.c @@ -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 { diff --git a/src/i830_driver.c b/src/i830_driver.c index 287217aa..75239c3f 100644 --- a/src/i830_driver.c +++ b/src/i830_driver.c @@ -169,6 +169,7 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. #include #include #include +#include #include "xf86.h" #include "xf86_OSproc.h" @@ -190,10 +191,9 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. #include "vbe.h" #include "shadow.h" #include "i830.h" - -#ifdef HAS_MTRR_SUPPORT -#include -#endif +#include "i830_display.h" +#include "i830_debug.h" +#include "i830_bios.h" #ifdef XF86DRI #include "dri.h" @@ -206,7 +206,7 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. #define NB_OF(x) (sizeof (x) / sizeof (*x)) /* *INDENT-OFF* */ -static SymTabRec I830BIOSChipsets[] = { +static SymTabRec I830Chipsets[] = { {PCI_CHIP_I830_M, "i830"}, {PCI_CHIP_845_G, "845G"}, {PCI_CHIP_I855_GM, "852GM/855GM"}, @@ -224,7 +224,7 @@ static SymTabRec I830BIOSChipsets[] = { {-1, NULL} }; -static PciChipsets I830BIOSPciChipsets[] = { +static PciChipsets I830PciChipsets[] = { {PCI_CHIP_I830_M, PCI_CHIP_I830_M, RES_SHARED_VGA}, {PCI_CHIP_845_G, PCI_CHIP_845_G, RES_SHARED_VGA}, {PCI_CHIP_I855_GM, PCI_CHIP_I855_GM, RES_SHARED_VGA}, @@ -267,17 +267,11 @@ typedef enum { OPTION_FIXEDPIPE, OPTION_ROTATE, OPTION_LINEARALLOC, - OPTION_MERGEDFB, - OPTION_METAMODES, - OPTION_SECONDHSYNC, - OPTION_SECONDVREFRESH, - OPTION_SECONDPOSITION, - OPTION_INTELXINERAMA, OPTION_INTELTEXPOOL, OPTION_INTELMMSIZE } I830Opts; -static OptionInfoRec I830BIOSOptions[] = { +static OptionInfoRec I830Options[] = { {OPTION_NOACCEL, "NoAccel", OPTV_BOOLEAN, {0}, FALSE}, {OPTION_SW_CURSOR, "SWcursor", OPTV_BOOLEAN, {0}, FALSE}, {OPTION_CACHE_LINES, "CacheLines", OPTV_INTEGER, {0}, FALSE}, @@ -286,9 +280,6 @@ static OptionInfoRec I830BIOSOptions[] = { {OPTION_XVIDEO, "XVideo", OPTV_BOOLEAN, {0}, TRUE}, {OPTION_COLOR_KEY, "ColorKey", OPTV_INTEGER, {0}, FALSE}, {OPTION_VIDEO_KEY, "VideoKey", OPTV_INTEGER, {0}, FALSE}, - {OPTION_VBE_RESTORE, "VBERestore", OPTV_BOOLEAN, {0}, FALSE}, - {OPTION_DISPLAY_INFO,"DisplayInfo", OPTV_BOOLEAN, {0}, FALSE}, - {OPTION_DEVICE_PRESENCE,"DevicePresence",OPTV_BOOLEAN,{0}, FALSE}, {OPTION_MONITOR_LAYOUT, "MonitorLayout", OPTV_ANYSTR,{0}, FALSE}, {OPTION_CLONE, "Clone", OPTV_BOOLEAN, {0}, FALSE}, {OPTION_CLONE_REFRESH,"CloneRefresh",OPTV_INTEGER, {0}, FALSE}, @@ -296,50 +287,34 @@ static OptionInfoRec I830BIOSOptions[] = { {OPTION_FIXEDPIPE, "FixedPipe", OPTV_ANYSTR, {0}, FALSE}, {OPTION_ROTATE, "Rotate", OPTV_ANYSTR, {0}, FALSE}, {OPTION_LINEARALLOC, "LinearAlloc", OPTV_INTEGER, {0}, FALSE}, - {OPTION_MERGEDFB, "MergedFB", OPTV_BOOLEAN, {0}, FALSE}, - {OPTION_METAMODES, "MetaModes", OPTV_STRING, {0}, FALSE}, - {OPTION_SECONDHSYNC, "SecondMonitorHorizSync",OPTV_STRING, {0}, FALSE }, - {OPTION_SECONDVREFRESH,"SecondMonitorVertRefresh",OPTV_STRING,{0}, FALSE }, - {OPTION_SECONDPOSITION,"SecondPosition",OPTV_STRING, {0}, FALSE }, - {OPTION_INTELXINERAMA,"MergedXinerama",OPTV_BOOLEAN, {0}, TRUE}, {OPTION_INTELTEXPOOL,"Legacy3D", OPTV_BOOLEAN, {0}, FALSE}, {OPTION_INTELMMSIZE, "AperTexSize", OPTV_INTEGER, {0}, FALSE}, {-1, NULL, OPTV_NONE, {0}, FALSE} }; /* *INDENT-ON* */ +const char *i830_output_type_names[] = { + "Unused", + "Analog", + "DVO", + "SDVO", + "LVDS", + "TVOUT", +}; + static void I830DisplayPowerManagementSet(ScrnInfoPtr pScrn, int PowerManagementMode, int flags); -static void I830AdjustFrame(int scrnIndex, int x, int y, int flags); -static Bool I830BIOSCloseScreen(int scrnIndex, ScreenPtr pScreen); -static Bool I830BIOSSaveScreen(ScreenPtr pScreen, int unblack); -static Bool I830BIOSEnterVT(int scrnIndex, int flags); -static Bool I830VESASetVBEMode(ScrnInfoPtr pScrn, int mode, - VbeCRTCInfoBlock *block); +static void i830AdjustFrame(int scrnIndex, int x, int y, int flags); +static Bool I830CloseScreen(int scrnIndex, ScreenPtr pScreen); +static Bool I830SaveScreen(ScreenPtr pScreen, int unblack); +static Bool I830EnterVT(int scrnIndex, int flags); static CARD32 I830CheckDevicesTimer(OsTimerPtr timer, CARD32 now, pointer arg); -static Bool SetPipeAccess(ScrnInfoPtr pScrn); extern int I830EntityIndex; -static Bool I830noPanoramiXExtension = TRUE; -static int I830XineramaNumScreens = 0; -static I830XineramaData *I830XineramadataPtr = NULL; -static int I830XineramaGeneration; - -static int I830ProcXineramaQueryVersion(ClientPtr client); -static int I830ProcXineramaGetState(ClientPtr client); -static int I830ProcXineramaGetScreenCount(ClientPtr client); -static int I830ProcXineramaGetScreenSize(ClientPtr client); -static int I830ProcXineramaIsActive(ClientPtr client); -static int I830ProcXineramaQueryScreens(ClientPtr client); -static int I830SProcXineramaDispatch(ClientPtr client); - /* temporary */ extern void xf86SetCursor(ScreenPtr pScreen, CursorPtr pCurs, int x, int y); -static const char *SecondMonitorName = "MergedFBMonitor"; - - #ifdef I830DEBUG void I830DPRINTF_stub(const char *filename, int line, const char *function, @@ -364,37 +339,34 @@ I830DPRINTF_stub(const char *filename, int line, const char *function, } #endif /* #ifdef I830DEBUG */ -/* XXX Check if this is still needed. */ +/* Export I830 options to i830 driver where necessary */ const OptionInfoRec * -I830BIOSAvailableOptions(int chipid, int busid) +I830AvailableOptions(int chipid, int busid) { int i; - for (i = 0; I830BIOSPciChipsets[i].PCIid > 0; i++) { - if (chipid == I830BIOSPciChipsets[i].PCIid) - return I830BIOSOptions; + for (i = 0; I830PciChipsets[i].PCIid > 0; i++) { + if (chipid == I830PciChipsets[i].PCIid) + return I830Options; } return NULL; } static Bool -I830BIOSGetRec(ScrnInfoPtr pScrn) +I830GetRec(ScrnInfoPtr pScrn) { I830Ptr pI830; if (pScrn->driverPrivate) return TRUE; pI830 = pScrn->driverPrivate = xnfcalloc(sizeof(I830Rec), 1); - pI830->vesa = xnfcalloc(sizeof(VESARec), 1); return TRUE; } static void -I830BIOSFreeRec(ScrnInfoPtr pScrn) +I830FreeRec(ScrnInfoPtr pScrn) { I830Ptr pI830; - VESAPtr pVesa; - DisplayModePtr mode; if (!pScrn) return; @@ -402,1680 +374,13 @@ I830BIOSFreeRec(ScrnInfoPtr pScrn) return; pI830 = I830PTR(pScrn); - mode = pScrn->modes; - - if (mode) { - do { - if (mode->Private) { - I830ModePrivatePtr mp = (I830ModePrivatePtr) mode->Private; - - xfree(mp); - mode->Private = NULL; - } - mode = mode->next; - } while (mode && mode != pScrn->modes); - } - - if (I830IsPrimary(pScrn)) { - if (pI830->vbeInfo) - VBEFreeVBEInfo(pI830->vbeInfo); - if (pI830->pVbe) - vbeFree(pI830->pVbe); - } - - pVesa = pI830->vesa; - if (pVesa->savedPal) - xfree(pVesa->savedPal); - xfree(pVesa); xfree(pScrn->driverPrivate); pScrn->driverPrivate = NULL; } -static Bool -InRegion(int x, int y, region r) -{ - return (r.x0 <= x) && (x <= r.x1) && (r.y0 <= y) && (y <= r.y1); -} - -static int -I830StrToRanges(range *r, char *s, int max) -{ - float num = 0.0; - int rangenum = 0; - Bool gotdash = FALSE; - Bool nextdash = FALSE; - char *strnum = NULL; - do { - switch(*s) { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - case '.': - if(strnum == NULL) { - strnum = s; - gotdash = nextdash; - nextdash = FALSE; - } - break; - case '-': - case ' ': - case 0: - if(strnum == NULL) break; - sscanf(strnum, "%f", &num); - strnum = NULL; - if(gotdash) { - r[rangenum - 1].hi = num; - } else { - r[rangenum].lo = num; - r[rangenum].hi = num; - rangenum++; - } - if(*s == '-') nextdash = (rangenum != 0); - else if(rangenum >= max) return rangenum; - break; - default: - return 0; - } - - } while(*(s++) != 0); - - return rangenum; -} - -/* Calculate the vertical refresh rate from a mode */ -static float -I830CalcVRate(DisplayModePtr mode) -{ - float hsync, refresh = 0; - - if(mode->HSync > 0.0) - hsync = mode->HSync; - else if(mode->HTotal > 0) - hsync = (float)mode->Clock / (float)mode->HTotal; - else - hsync = 0.0; - - if(mode->VTotal > 0) - refresh = hsync * 1000.0 / mode->VTotal; - - if(mode->Flags & V_INTERLACE) - refresh *= 2.0; - - if(mode->Flags & V_DBLSCAN) - refresh /= 2.0; - - if(mode->VScan > 1) - refresh /= mode->VScan; - - if(mode->VRefresh > 0.0) - refresh = mode->VRefresh; - - if(hsync == 0.0 || refresh == 0.0) return 0.0; - - return refresh; -} - -/* Copy and link two modes (i, j) for mergedfb mode - * (Code base taken from mga driver) - * - * - Copy mode i, merge j to copy of i, link the result to dest - * - Link i and j in private record. - * - If dest is NULL, return value is copy of i linked to itself. - * - For mergedfb auto-config, we only check the dimension - * against virtualX/Y, if they were user-provided. - * - No special treatment required for CRTxxOffs. - * - Provide fake dotclock in order to distinguish between similar - * looking MetaModes (for RandR and VidMode extensions) - * - Set unique VRefresh of dest mode for RandR - */ -static DisplayModePtr -I830CopyModeNLink(ScrnInfoPtr pScrn, DisplayModePtr dest, - DisplayModePtr i, DisplayModePtr j, - int pos) -{ - DisplayModePtr mode; - int dx = 0,dy = 0; - - if(!((mode = xalloc(sizeof(DisplayModeRec))))) return dest; - memcpy(mode, i, sizeof(DisplayModeRec)); - if(!((mode->Private = xalloc(sizeof(I830ModePrivateRec))))) { - xfree(mode); - return dest; - } - ((I830ModePrivatePtr)mode->Private)->merged.First = i; - ((I830ModePrivatePtr)mode->Private)->merged.Second = j; - ((I830ModePrivatePtr)mode->Private)->merged.SecondPosition = pos; - if (((I830ModePrivatePtr)i->Private)->vbeData.mode > 0x30) { - ((I830ModePrivatePtr)mode->Private)->vbeData.mode = ((I830ModePrivatePtr)i->Private)->vbeData.mode; - ((I830ModePrivatePtr)mode->Private)->vbeData.data = ((I830ModePrivatePtr)i->Private)->vbeData.data; - } else { - ((I830ModePrivatePtr)mode->Private)->vbeData.mode = ((I830ModePrivatePtr)j->Private)->vbeData.mode; - ((I830ModePrivatePtr)mode->Private)->vbeData.data = ((I830ModePrivatePtr)j->Private)->vbeData.data; - } - mode->PrivSize = sizeof(I830ModePrivateRec); - - switch(pos) { - case PosLeftOf: - case PosRightOf: - if(!(pScrn->display->virtualX)) { - dx = i->HDisplay + j->HDisplay; - } else { - dx = min(pScrn->virtualX, i->HDisplay + j->HDisplay); - } - dx -= mode->HDisplay; - if(!(pScrn->display->virtualY)) { - dy = max(i->VDisplay, j->VDisplay); - } else { - dy = min(pScrn->virtualY, max(i->VDisplay, j->VDisplay)); - } - dy -= mode->VDisplay; - break; - case PosAbove: - case PosBelow: - if(!(pScrn->display->virtualY)) { - dy = i->VDisplay + j->VDisplay; - } else { - dy = min(pScrn->virtualY, i->VDisplay + j->VDisplay); - } - dy -= mode->VDisplay; - if(!(pScrn->display->virtualX)) { - dx = max(i->HDisplay, j->HDisplay); - } else { - dx = min(pScrn->virtualX, max(i->HDisplay, j->HDisplay)); - } - dx -= mode->HDisplay; - break; - } - mode->HDisplay += dx; - mode->HSyncStart += dx; - mode->HSyncEnd += dx; - mode->HTotal += dx; - mode->VDisplay += dy; - mode->VSyncStart += dy; - mode->VSyncEnd += dy; - mode->VTotal += dy; - - mode->type = M_T_DEFAULT; - - /* Set up as user defined (ie fake that the mode has been named in the - * Modes-list in the screen section; corrects cycling with CTRL-ALT-[-+] - * when source mode has not been listed there.) - */ - mode->type |= M_T_USERDEF; - - /* Set the VRefresh field (in order to make RandR use it for the rates). We - * simply set this to the refresh rate for the First mode (since Second will - * mostly be LCD or TV anyway). - */ - mode->VRefresh = I830CalcVRate(i); - - if( ((mode->HDisplay * ((pScrn->bitsPerPixel + 7) / 8) * mode->VDisplay) > (pScrn->videoRam * 1024)) || - (mode->HDisplay > 4088) || - (mode->VDisplay > 4096) ) { - - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, - "Skipped \"%s\" (%dx%d), not enough video RAM or beyond hardware specs\n", - mode->name, mode->HDisplay, mode->VDisplay); - xfree(mode->Private); - xfree(mode); - - return dest; - } - - /* Now see if the resulting mode would be discarded as a "size" by the - * RandR extension, and increase its clock by 1000 in case it does. - */ - if(dest) { - DisplayModePtr t = dest; - do { - if((t->HDisplay == mode->HDisplay) && - (t->VDisplay == mode->VDisplay) && - ((int)(t->VRefresh + .5) == (int)(mode->VRefresh + .5))) { - mode->VRefresh += 1000.0; - } - t = t->next; - } while((t) && (t != dest)); - } - - /* Provide a fake but unique DotClock in order to trick the vidmode - * extension to allow selecting among a number of modes whose merged result - * looks identical but consists of different modes for First and Second - */ - mode->Clock = (int)(mode->VRefresh * 1000.0); - - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Merged \"%s\" (%dx%d) and \"%s\" (%dx%d) to %dx%d (%d)\n", - i->name, i->HDisplay, i->VDisplay, j->name, j->HDisplay, j->VDisplay, - mode->HDisplay, mode->VDisplay, (int)mode->VRefresh); - - mode->next = mode; - mode->prev = mode; - - if(dest) { - mode->next = dest->next; /* Insert node after "dest" */ - dest->next->prev = mode; - mode->prev = dest; - dest->next = mode; - } - - return mode; -} - -/* Helper function to find a mode from a given name - * (Code base taken from mga driver) - */ -static DisplayModePtr -I830GetModeFromName(char* str, DisplayModePtr i) -{ - DisplayModePtr c = i; - if(!i) return NULL; - do { - if(strcmp(str, c->name) == 0) return c; - c = c->next; - } while(c != i); - return NULL; -} - -static DisplayModePtr -I830FindWidestTallestMode(DisplayModePtr i, Bool tallest) -{ - DisplayModePtr c = i, d = NULL; - int max = 0; - if(!i) return NULL; - do { - if(tallest) { - if(c->VDisplay > max) { - max = c->VDisplay; - d = c; - } - } else { - if(c->HDisplay > max) { - max = c->HDisplay; - d = c; - } - } - c = c->next; - } while(c != i); - return d; -} - static void -I830FindWidestTallestCommonMode(DisplayModePtr i, DisplayModePtr j, Bool tallest, - DisplayModePtr *a, DisplayModePtr *b) -{ - DisplayModePtr c = i, d; - int max = 0; - Bool foundone; - - (*a) = (*b) = NULL; - - if(!i || !j) return; - - do { - d = j; - foundone = FALSE; - do { - if( (c->HDisplay == d->HDisplay) && - (c->VDisplay == d->VDisplay) ) { - foundone = TRUE; - break; - } - d = d->next; - } while(d != j); - if(foundone) { - if(tallest) { - if(c->VDisplay > max) { - max = c->VDisplay; - (*a) = c; - (*b) = d; - } - } else { - if(c->HDisplay > max) { - max = c->HDisplay; - (*a) = c; - (*b) = d; - } - } - } - c = c->next; - } while(c != i); -} - -static DisplayModePtr -I830GenerateModeListFromLargestModes(ScrnInfoPtr pScrn, - DisplayModePtr i, DisplayModePtr j, - int pos) -{ - I830Ptr pI830 = I830PTR(pScrn); - DisplayModePtr mode1 = NULL; - DisplayModePtr mode2 = NULL; - DisplayModePtr mode3 = NULL; - DisplayModePtr mode4 = NULL; - DisplayModePtr result = NULL; - - /* Now build a default list of MetaModes. - * - Non-clone: If the user enabled NonRectangular, we use the - * largest mode for each First and Second. If not, we use the largest - * common mode for First and Second (if available). Additionally, and - * regardless if the above, we produce a clone mode consisting of - * the largest common mode (if available) in order to use DGA. - */ - - switch(pos) { - case PosLeftOf: - case PosRightOf: - mode1 = I830FindWidestTallestMode(i, FALSE); - mode2 = I830FindWidestTallestMode(j, FALSE); - I830FindWidestTallestCommonMode(i, j, FALSE, &mode3, &mode4); - break; - case PosAbove: - case PosBelow: - mode1 = I830FindWidestTallestMode(i, TRUE); - mode2 = I830FindWidestTallestMode(j, TRUE); - I830FindWidestTallestCommonMode(i, j, TRUE, &mode3, &mode4); - break; - } - - if(mode3 && mode4 && !pI830->NonRect) { - mode1 = mode3; - mode2 = mode2; - } - - if(mode1 && mode2) { - result = I830CopyModeNLink(pScrn, result, mode1, mode2, pos); - } - - return result; -} - -/* Generate the merged-fb mode modelist - * (Taken from mga driver) - */ -static DisplayModePtr -I830GenerateModeListFromMetaModes(ScrnInfoPtr pScrn, char* str, - DisplayModePtr i, DisplayModePtr j, - int pos) -{ - char* strmode = str; - char modename[256]; - Bool gotdash = FALSE; - char gotsep = 0; - int p; - DisplayModePtr mode1 = NULL; - DisplayModePtr mode2 = NULL; - DisplayModePtr result = NULL; - int myslen; - - do { - switch(*str) { - case 0: - case '-': - case '+': - case ' ': - case ',': - case ';': - if(strmode != str) { - - myslen = str - strmode; - if(myslen > 255) myslen = 255; - strncpy(modename, strmode, myslen); - modename[myslen] = 0; - - if(gotdash) { - if(mode1 == NULL) { - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, - "Error parsing MetaModes parameter\n"); - return NULL; - } - mode2 = I830GetModeFromName(modename, j); - if(!mode2) { - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "Mode \"%s\" is not a supported mode for Second\n", modename); - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "\t(Skipping metamode \"%s%c%s\")\n", mode1->name, gotsep, modename); - mode1 = NULL; - gotsep = 0; - } - } else { - mode1 = I830GetModeFromName(modename, i); - if(!mode1) { - char* tmps = str; - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "Mode \"%s\" is not a supported mode for First\n", modename); - while(*tmps == ' ' || *tmps == ';') tmps++; - /* skip the next mode */ - if(*tmps == '-' || *tmps == '+' || *tmps == ',') { - tmps++; - /* skip spaces */ - while(*tmps == ' ' || *tmps == ';') tmps++; - /* skip modename */ - while(*tmps && *tmps != ' ' && *tmps != ';' && *tmps != '-' && *tmps != '+' && *tmps != ',') tmps++; - myslen = tmps - strmode; - if(myslen > 255) myslen = 255; - strncpy(modename,strmode,myslen); - modename[myslen] = 0; - str = tmps - 1; - } - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "\t(Skipping metamode \"%s\")\n", modename); - mode1 = NULL; - gotsep = 0; - } - } - gotdash = FALSE; - } - strmode = str + 1; - gotdash |= (*str == '-' || *str == '+' || *str == ','); - if (*str == '-' || *str == '+' || *str == ',') - gotsep = *str; - - if(*str != 0) break; - /* Fall through otherwise */ - - default: - if(!gotdash && mode1) { - p = pos ; - if(!mode2) { - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "Mode \"%s\" is not a supported mode for Second\n", mode1->name); - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "\t(Skipping metamode \"%s\")\n", modename); - mode1 = NULL; - } else { - result = I830CopyModeNLink(pScrn, result, mode1, mode2, p); - mode1 = NULL; - mode2 = NULL; - } - gotsep = 0; - } - break; - - } - - } while(*(str++) != 0); - - return result; -} - -static DisplayModePtr -I830GenerateModeList(ScrnInfoPtr pScrn, char* str, - DisplayModePtr i, DisplayModePtr j, - int pos) -{ - I830Ptr pI830 = I830PTR(pScrn); - - if(str != NULL) { - return(I830GenerateModeListFromMetaModes(pScrn, str, i, j, pos)); - } else { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "No MetaModes given, linking %s modes by default\n", - (pI830->NonRect ? - (((pos == PosLeftOf) || (pos == PosRightOf)) ? "widest" : "tallest") - : - (((pos == PosLeftOf) || (pos == PosRightOf)) ? "widest common" : "tallest common")) ); - return(I830GenerateModeListFromLargestModes(pScrn, i, j, pos)); - } -} - -static void -I830RecalcDefaultVirtualSize(ScrnInfoPtr pScrn) -{ - I830Ptr pI830 = I830PTR(pScrn); - DisplayModePtr mode, bmode; - int maxh, maxv; - static const char *str = "MergedFB: Virtual %s %d\n"; - static const char *errstr = "Virtual %s to small for given SecondPosition offset\n"; - - mode = bmode = pScrn->modes; - maxh = maxv = 0; - do { - if(mode->HDisplay > maxh) maxh = mode->HDisplay; - if(mode->VDisplay > maxv) maxv = mode->VDisplay; - mode = mode->next; - } while(mode != bmode); - - maxh += pI830->FirstXOffs + pI830->SecondXOffs; - maxv += pI830->FirstYOffs + pI830->SecondYOffs; - - if(!(pScrn->display->virtualX)) { - if(maxh > 4088) { - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, - "Virtual width with SecondPosition offset beyond hardware specs\n"); - pI830->FirstXOffs = pI830->SecondXOffs = 0; - maxh -= (pI830->FirstXOffs + pI830->SecondXOffs); - } - pScrn->virtualX = maxh; - pScrn->displayWidth = maxh; - xf86DrvMsg(pScrn->scrnIndex, X_PROBED, str, "width", maxh); - } else { - if(maxh < pScrn->display->virtualX) { - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, errstr, "width"); - pI830->FirstXOffs = pI830->SecondXOffs = 0; - } - } - - if(!(pScrn->display->virtualY)) { - pScrn->virtualY = maxv; - xf86DrvMsg(pScrn->scrnIndex, X_PROBED, str, "height", maxv); - } else { - if(maxv < pScrn->display->virtualY) { - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, errstr, "height"); - pI830->FirstYOffs = pI830->SecondYOffs = 0; - } - } -} - -#define SDMPTR(x) ((I830ModePrivatePtr)x->currentMode->Private)->merged -#define CDMPTR ((I830ModePrivatePtr)pI830->currentMode->Private)->merged - -#define BOUND(test,low,hi) \ - { \ - if((test) < (low)) (test) = (low); \ - if((test) > (hi)) (test) = (hi); \ - } - -#define REBOUND(low,hi,test) \ - { \ - if((test) < (low)) { \ - (hi) += (test)-(low); \ - (low) = (test); \ - } \ - if((test) > (hi)) { \ - (low) += (test)-(hi); \ - (hi) = (test); \ - } \ - } - - -static void -I830MergedPointerMoved(int scrnIndex, int x, int y) -{ - ScrnInfoPtr pScrn1 = xf86Screens[scrnIndex]; - I830Ptr pI830 = I830PTR(pScrn1); - ScrnInfoPtr pScrn2 = pI830->pScrn_2; - region out, in1, in2, f2, f1; - int deltax, deltay; - int temp1, temp2; - int old1x0, old1y0, old2x0, old2y0; - int FirstXOffs = 0, FirstYOffs = 0, SecondXOffs = 0, SecondYOffs = 0; - int HVirt = pScrn1->virtualX; - int VVirt = pScrn1->virtualY; - int sigstate; - Bool doit = FALSE, HaveNonRect = FALSE, HaveOffsRegions = FALSE; - int pos = ((I830MergedDisplayModePtr)pI830->currentMode->Private)->SecondPosition; - - if(pI830->DGAactive) { - return; - /* DGA: There is no cursor and no panning while DGA is active. */ - } else { - FirstXOffs = pI830->FirstXOffs; - FirstYOffs = pI830->FirstYOffs; - SecondXOffs = pI830->SecondXOffs; - SecondYOffs = pI830->SecondYOffs; - HaveNonRect = pI830->HaveNonRect; - HaveOffsRegions = pI830->HaveOffsRegions; - } - - /* Check if the pointer is inside our dead areas */ - if((pI830->MouseRestrictions) && !I830noPanoramiXExtension) { - if(HaveNonRect) { - if(InRegion(x, y, pI830->NonRectDead)) { - switch(pos) { - case PosLeftOf: - case PosRightOf: y = pI830->NonRectDead.y0 - 1; - doit = TRUE; - break; - case PosAbove: - case PosBelow: x = pI830->NonRectDead.x0 - 1; - doit = TRUE; - default: break; - } - } - } - if(HaveOffsRegions) { - if(InRegion(x, y, pI830->OffDead1)) { - switch(pos) { - case PosLeftOf: - case PosRightOf: y = pI830->OffDead1.y1; - doit = TRUE; - break; - case PosAbove: - case PosBelow: x = pI830->OffDead1.x1; - doit = TRUE; - default: break; - } - } else if(InRegion(x, y, pI830->OffDead2)) { - switch(pos) { - case PosLeftOf: - case PosRightOf: y = pI830->OffDead2.y0 - 1; - doit = TRUE; - break; - case PosAbove: - case PosBelow: x = pI830->OffDead2.x0 - 1; - doit = TRUE; - default: break; - } - } - } - if(doit) { - UpdateCurrentTime(); - sigstate = xf86BlockSIGIO(); - miPointerAbsoluteCursor(x, y, currentTime.milliseconds); - xf86UnblockSIGIO(sigstate); - return; - } - } - - f1.x0 = old1x0 = pI830->FirstframeX0; - f1.x1 = pI830->FirstframeX1; - f1.y0 = old1y0 = pI830->FirstframeY0; - f1.y1 = pI830->FirstframeY1; - f2.x0 = old2x0 = pScrn2->frameX0; - f2.x1 = pScrn2->frameX1; - f2.y0 = old2y0 = pScrn2->frameY0; - f2.y1 = pScrn2->frameY1; - - /* Define the outer region. Crossing this causes all frames to move */ - out.x0 = pScrn1->frameX0; - out.x1 = pScrn1->frameX1; - out.y0 = pScrn1->frameY0; - out.y1 = pScrn1->frameY1; - - /* - * Define the inner sliding window. Being outsize both frames but - * inside the outer clipping window will slide corresponding frame - */ - in1 = out; - in2 = out; - switch(pos) { - case PosLeftOf: - in1.x0 = f1.x0; - in2.x1 = f2.x1; - break; - case PosRightOf: - in1.x1 = f1.x1; - in2.x0 = f2.x0; - break; - case PosBelow: - in1.y1 = f1.y1; - in2.y0 = f2.y0; - break; - case PosAbove: - in1.y0 = f1.y0; - in2.y1 = f2.y1; - break; - } - - deltay = 0; - deltax = 0; - - if(InRegion(x, y, out)) { /* inside outer region */ - - if(InRegion(x, y, in1) && !InRegion(x, y, f1)) { - REBOUND(f1.x0, f1.x1, x); - REBOUND(f1.y0, f1.y1, y); - deltax = 1; - } - if(InRegion(x, y, in2) && !InRegion(x, y, f2)) { - REBOUND(f2.x0, f2.x1, x); - REBOUND(f2.y0, f2.y1, y); - deltax = 1; - } - - } else { /* outside outer region */ - - if(out.x0 > x) { - deltax = x - out.x0; - } - if(out.x1 < x) { - deltax = x - out.x1; - } - if(deltax) { - pScrn1->frameX0 += deltax; - pScrn1->frameX1 += deltax; - f1.x0 += deltax; - f1.x1 += deltax; - f2.x0 += deltax; - f2.x1 += deltax; - } - - if(out.y0 > y) { - deltay = y - out.y0; - } - if(out.y1 < y) { - deltay = y - out.y1; - } - if(deltay) { - pScrn1->frameY0 += deltay; - pScrn1->frameY1 += deltay; - f1.y0 += deltay; - f1.y1 += deltay; - f2.y0 += deltay; - f2.y1 += deltay; - } - - switch(pos) { - case PosLeftOf: - if(x >= f1.x0) { REBOUND(f1.y0, f1.y1, y); } - if(x <= f2.x1) { REBOUND(f2.y0, f2.y1, y); } - break; - case PosRightOf: - if(x <= f1.x1) { REBOUND(f1.y0, f1.y1, y); } - if(x >= f2.x0) { REBOUND(f2.y0, f2.y1, y); } - break; - case PosBelow: - if(y <= f1.y1) { REBOUND(f1.x0, f1.x1, x); } - if(y >= f2.y0) { REBOUND(f2.x0, f2.x1, x); } - break; - case PosAbove: - if(y >= f1.y0) { REBOUND(f1.x0, f1.x1, x); } - if(y <= f2.y1) { REBOUND(f2.x0, f2.x1, x); } - break; - } - - } - - if(deltax || deltay) { - pI830->FirstframeX0 = f1.x0; - pI830->FirstframeY0 = f1.y0; - pScrn2->frameX0 = f2.x0; - pScrn2->frameY0 = f2.y0; - - switch(pos) { - case PosLeftOf: - case PosRightOf: - if(FirstYOffs || SecondYOffs || HaveNonRect) { - if(pI830->FirstframeY0 != old1y0) { - if(pI830->FirstframeY0 < FirstYOffs) - pI830->FirstframeY0 = FirstYOffs; - - temp1 = pI830->FirstframeY0 + CDMPTR.First->VDisplay; - temp2 = min((VVirt - SecondYOffs), (FirstYOffs + pI830->MBXNR1YMAX)); - if(temp1 > temp2) - pI830->FirstframeY0 -= (temp1 - temp2); - } - if(pScrn2->frameY0 != old2y0) { - if(pScrn2->frameY0 < SecondYOffs) - pScrn2->frameY0 = SecondYOffs; - - temp1 = pScrn2->frameY0 + CDMPTR.Second->VDisplay; - temp2 = min((VVirt - FirstYOffs), (SecondYOffs + pI830->MBXNR2YMAX)); - if(temp1 > temp2) - pScrn2->frameY0 -= (temp1 - temp2); - } - } - break; - case PosBelow: - case PosAbove: - if(FirstXOffs || SecondXOffs || HaveNonRect) { - if(pI830->FirstframeX0 != old1x0) { - if(pI830->FirstframeX0 < FirstXOffs) - pI830->FirstframeX0 = FirstXOffs; - - temp1 = pI830->FirstframeX0 + CDMPTR.First->HDisplay; - temp2 = min((HVirt - SecondXOffs), (FirstXOffs + pI830->MBXNR1XMAX)); - if(temp1 > temp2) - pI830->FirstframeX0 -= (temp1 - temp2); - } - if(pScrn2->frameX0 != old2x0) { - if(pScrn2->frameX0 < SecondXOffs) - pScrn2->frameX0 = SecondXOffs; - - temp1 = pScrn2->frameX0 + CDMPTR.Second->HDisplay; - temp2 = min((HVirt - FirstXOffs), (SecondXOffs + pI830->MBXNR2XMAX)); - if(temp1 > temp2) - pScrn2->frameX0 -= (temp1 - temp2); - } - } - break; - } - - pI830->FirstframeX1 = pI830->FirstframeX0 + CDMPTR.First->HDisplay - 1; - pI830->FirstframeY1 = pI830->FirstframeY0 + CDMPTR.First->VDisplay - 1; - pScrn2->frameX1 = pScrn2->frameX0 + CDMPTR.Second->HDisplay - 1; - pScrn2->frameY1 = pScrn2->frameY0 + CDMPTR.Second->VDisplay - 1; - - /* No need to update pScrn1->frame?1, done above */ - if (pI830->pipe == 0) { - OUTREG(DSPABASE, pI830->FrontBuffer.Start + ((pI830->FirstframeY0 * pScrn1->displayWidth + pI830->FirstframeX0) * pI830->cpp)); - OUTREG(DSPBBASE, pI830->FrontBuffer.Start + ((pScrn2->frameY0 * pScrn1->displayWidth + pScrn2->frameX0) * pI830->cpp)); - } else { - OUTREG(DSPBBASE, pI830->FrontBuffer.Start + ((pI830->FirstframeY0 * pScrn1->displayWidth + pI830->FirstframeX0) * pI830->cpp)); - OUTREG(DSPABASE, pI830->FrontBuffer.Start + ((pScrn2->frameY0 * pScrn1->displayWidth + pScrn2->frameX0) * pI830->cpp)); - } - } -} - -static void -I830AdjustFrameMerged(int scrnIndex, int x, int y, int flags) -{ - ScrnInfoPtr pScrn1 = xf86Screens[scrnIndex]; - I830Ptr pI830 = I830PTR(pScrn1); - ScrnInfoPtr pScrn2 = pI830->pScrn_2; - int HTotal = pI830->currentMode->HDisplay; - int VTotal = pI830->currentMode->VDisplay; - int HMax = HTotal; - int VMax = VTotal; - int HVirt = pScrn1->virtualX; - int VVirt = pScrn1->virtualY; - int x1 = x, x2 = x; - int y1 = y, y2 = y; - int FirstXOffs = 0, FirstYOffs = 0, SecondXOffs = 0, SecondYOffs = 0; - int MBXNR1XMAX = 65536, MBXNR1YMAX = 65536, MBXNR2XMAX = 65536, MBXNR2YMAX = 65536; - - if(pI830->DGAactive) { - HVirt = pScrn1->displayWidth; - VVirt = pScrn1->virtualY; - } else { - FirstXOffs = pI830->FirstXOffs; - FirstYOffs = pI830->FirstYOffs; - SecondXOffs = pI830->SecondXOffs; - SecondYOffs = pI830->SecondYOffs; - MBXNR1XMAX = pI830->MBXNR1XMAX; - MBXNR1YMAX = pI830->MBXNR1YMAX; - MBXNR2XMAX = pI830->MBXNR2XMAX; - MBXNR2YMAX = pI830->MBXNR2YMAX; - } - - BOUND(x, 0, HVirt - HTotal); - BOUND(y, 0, VVirt - VTotal); - BOUND(x1, FirstXOffs, min(HVirt, MBXNR1XMAX + FirstXOffs) - min(HTotal, MBXNR1XMAX) - SecondXOffs); - BOUND(y1, FirstYOffs, min(VVirt, MBXNR1YMAX + FirstYOffs) - min(VTotal, MBXNR1YMAX) - SecondYOffs); - BOUND(x2, SecondXOffs, min(HVirt, MBXNR2XMAX + SecondXOffs) - min(HTotal, MBXNR2XMAX) - FirstXOffs); - BOUND(y2, SecondYOffs, min(VVirt, MBXNR2YMAX + SecondYOffs) - min(VTotal, MBXNR2YMAX) - FirstYOffs); - - switch(SDMPTR(pScrn1).SecondPosition) { - case PosLeftOf: - pScrn2->frameX0 = x2; - BOUND(pScrn2->frameY0, y2, y2 + min(VMax, MBXNR2YMAX) - CDMPTR.Second->VDisplay); - pI830->FirstframeX0 = x1 + CDMPTR.Second->HDisplay; - BOUND(pI830->FirstframeY0, y1, y1 + min(VMax, MBXNR1YMAX) - CDMPTR.First->VDisplay); - break; - case PosRightOf: - pI830->FirstframeX0 = x1; - BOUND(pI830->FirstframeY0, y1, y1 + min(VMax, MBXNR1YMAX) - CDMPTR.First->VDisplay); - pScrn2->frameX0 = x2 + CDMPTR.First->HDisplay; - BOUND(pScrn2->frameY0, y2, y2 + min(VMax, MBXNR2YMAX) - CDMPTR.Second->VDisplay); - break; - case PosAbove: - BOUND(pScrn2->frameX0, x2, x2 + min(HMax, MBXNR2XMAX) - CDMPTR.Second->HDisplay); - pScrn2->frameY0 = y2; - BOUND(pI830->FirstframeX0, x1, x1 + min(HMax, MBXNR1XMAX) - CDMPTR.First->HDisplay); - pI830->FirstframeY0 = y1 + CDMPTR.Second->VDisplay; - break; - case PosBelow: - BOUND(pI830->FirstframeX0, x1, x1 + min(HMax, MBXNR1XMAX) - CDMPTR.First->HDisplay); - pI830->FirstframeY0 = y1; - BOUND(pScrn2->frameX0, x2, x2 + min(HMax, MBXNR2XMAX) - CDMPTR.Second->HDisplay); - pScrn2->frameY0 = y2 + CDMPTR.First->VDisplay; - break; - } - - BOUND(pI830->FirstframeX0, 0, HVirt - CDMPTR.First->HDisplay); - BOUND(pI830->FirstframeY0, 0, VVirt - CDMPTR.First->VDisplay); - BOUND(pScrn2->frameX0, 0, HVirt - CDMPTR.Second->HDisplay); - BOUND(pScrn2->frameY0, 0, VVirt - CDMPTR.Second->VDisplay); - - pScrn1->frameX0 = x; - pScrn1->frameY0 = y; - - pI830->FirstframeX1 = pI830->FirstframeX0 + CDMPTR.First->HDisplay - 1; - pI830->FirstframeY1 = pI830->FirstframeY0 + CDMPTR.First->VDisplay - 1; - pScrn2->frameX1 = pScrn2->frameX0 + CDMPTR.Second->HDisplay - 1; - pScrn2->frameY1 = pScrn2->frameY0 + CDMPTR.Second->VDisplay - 1; - - pScrn1->frameX1 = pScrn1->frameX0 + pI830->currentMode->HDisplay - 1; - pScrn1->frameY1 = pScrn1->frameY0 + pI830->currentMode->VDisplay - 1; - pScrn1->frameX1 += FirstXOffs + SecondXOffs; - pScrn1->frameY1 += FirstYOffs + SecondYOffs; -} - -/* Pseudo-Xinerama extension for MergedFB mode */ -static void -I830UpdateXineramaScreenInfo(ScrnInfoPtr pScrn1) -{ - I830Ptr pI830 = I830PTR(pScrn1); - int scrnnum1 = 0, scrnnum2 = 1; - int x1=0, x2=0, y1=0, y2=0, h1=0, h2=0, w1=0, w2=0; - int realvirtX, realvirtY; - DisplayModePtr currentMode, firstMode; - Bool infochanged = FALSE; - Bool usenonrect = pI830->NonRect; - const char *rectxine = "\t... setting up rectangular Xinerama layout\n"; -#ifdef XF86DRI - drmI830Sarea *sarea = NULL; - - if (pI830->directRenderingEnabled) { - sarea = (drmI830Sarea *) DRIGetSAREAPrivate(pScrn1->pScreen); - } -#endif - - pI830->MBXNR1XMAX = pI830->MBXNR1YMAX = pI830->MBXNR2XMAX = pI830->MBXNR2YMAX = 65536; - pI830->HaveNonRect = pI830->HaveOffsRegions = FALSE; - - if(!pI830->MergedFB) { -#ifdef XF86DRI - if (pI830->directRenderingEnabled) { - sarea->pipeA_x = sarea->pipeA_y = sarea->pipeB_x = sarea->pipeB_y = 0; - - if (pI830->planeEnabled[0]) { - sarea->pipeA_w = pScrn1->virtualX; - sarea->pipeA_h = pScrn1->virtualY; - } else { - sarea->pipeA_w = 0; - sarea->pipeA_h = 0; - } - - if (pI830->planeEnabled[1]) { - sarea->pipeB_w = pScrn1->virtualX; - sarea->pipeB_h = pScrn1->virtualY; - } else { - sarea->pipeB_w = 0; - sarea->pipeB_h = 0; - } - } -#endif - - return; - } - - if (I830noPanoramiXExtension || !I830XineramadataPtr) { -#ifdef XF86DRI - if (!pI830->directRenderingEnabled) -#endif - return; - } - - if(pI830->SecondIsScrn0) { - scrnnum1 = 1; - scrnnum2 = 0; - } - - /* Attention: Usage of RandR may lead to virtual X and Y dimensions - * actually smaller than our MetaModes. To avoid this, we calculate - * the max* fields here (and not somewhere else, like in CopyNLink) - * - * *** Note: RandR is disabled if one of CRTxxOffs is non-zero. - */ - - /* "Real" virtual: Virtual without the Offset */ - realvirtX = pScrn1->virtualX - pI830->FirstXOffs - pI830->SecondXOffs; - realvirtY = pScrn1->virtualY - pI830->FirstYOffs - pI830->SecondYOffs; - - if((pI830->I830XineramaVX != pScrn1->virtualX) || (pI830->I830XineramaVY != pScrn1->virtualY)) { - - if(!(pScrn1->modes)) return; - - pI830->maxFirst_X1 = pI830->maxFirst_X2 = 0; - pI830->maxFirst_Y1 = pI830->maxFirst_Y2 = 0; - pI830->maxSecond_X1 = pI830->maxSecond_X2 = 0; - pI830->maxSecond_Y1 = pI830->maxSecond_Y2 = 0; - - currentMode = firstMode = pScrn1->modes; - - do { - - DisplayModePtr p = currentMode->next; - DisplayModePtr i = ((I830ModePrivatePtr)currentMode->Private)->merged.First; - DisplayModePtr j = ((I830ModePrivatePtr)currentMode->Private)->merged.Second; - - if((currentMode->HDisplay <= realvirtX) && (currentMode->VDisplay <= realvirtY) && - (i->HDisplay <= realvirtX) && (j->HDisplay <= realvirtX) && - (i->VDisplay <= realvirtY) && (j->VDisplay <= realvirtY)) { - - if(pI830->maxFirst_X1 == i->HDisplay) { - if(pI830->maxFirst_X2 < j->HDisplay) { - pI830->maxFirst_X2 = j->HDisplay; /* Widest Second mode displayed with widest CRT1 mode */ - } - } else if(pI830->maxFirst_X1 < i->HDisplay) { - pI830->maxFirst_X1 = i->HDisplay; /* Widest CRT1 mode */ - pI830->maxFirst_X2 = j->HDisplay; - } - if(pI830->maxSecond_X2 == j->HDisplay) { - if(pI830->maxSecond_X1 < i->HDisplay) { - pI830->maxSecond_X1 = i->HDisplay; /* Widest First mode displayed with widest Second mode */ - } - } else if(pI830->maxSecond_X2 < j->HDisplay) { - pI830->maxSecond_X2 = j->HDisplay; /* Widest Second mode */ - pI830->maxSecond_X1 = i->HDisplay; - } - if(pI830->maxFirst_Y1 == i->VDisplay) { /* Same as above, but tallest instead of widest */ - if(pI830->maxFirst_Y2 < j->VDisplay) { - pI830->maxFirst_Y2 = j->VDisplay; - } - } else if(pI830->maxFirst_Y1 < i->VDisplay) { - pI830->maxFirst_Y1 = i->VDisplay; - pI830->maxFirst_Y2 = j->VDisplay; - } - if(pI830->maxSecond_Y2 == j->VDisplay) { - if(pI830->maxSecond_Y1 < i->VDisplay) { - pI830->maxSecond_Y1 = i->VDisplay; - } - } else if(pI830->maxSecond_Y2 < j->VDisplay) { - pI830->maxSecond_Y2 = j->VDisplay; - pI830->maxSecond_Y1 = i->VDisplay; - } - } - currentMode = p; - - } while((currentMode) && (currentMode != firstMode)); - - pI830->I830XineramaVX = pScrn1->virtualX; - pI830->I830XineramaVY = pScrn1->virtualY; - infochanged = TRUE; - - } - - if((usenonrect) && pI830->maxFirst_X1) { - switch(pI830->SecondPosition) { - case PosLeftOf: - case PosRightOf: - if((pI830->maxFirst_Y1 != realvirtY) && (pI830->maxSecond_Y2 != realvirtY)) { - usenonrect = FALSE; - } - break; - case PosAbove: - case PosBelow: - if((pI830->maxFirst_X1 != realvirtX) && (pI830->maxSecond_X2 != realvirtX)) { - usenonrect = FALSE; - } - break; - } - if(infochanged && !usenonrect) { - xf86DrvMsg(pScrn1->scrnIndex, X_INFO, - "Virtual screen size does not match maximum display modes...\n"); - xf86DrvMsg(pScrn1->scrnIndex, X_INFO, rectxine); - - } - } else if(infochanged && usenonrect) { - usenonrect = FALSE; - xf86DrvMsg(pScrn1->scrnIndex, X_INFO, - "Only clone modes available for this virtual screen size...\n"); - xf86DrvMsg(pScrn1->scrnIndex, X_INFO, rectxine); - } - - if(pI830->maxFirst_X1) { /* Means we have at least one non-clone mode */ - switch(pI830->SecondPosition) { - case PosLeftOf: - x1 = min(pI830->maxFirst_X2, pScrn1->virtualX - pI830->maxFirst_X1); - if(x1 < 0) x1 = 0; - y1 = pI830->FirstYOffs; - w1 = pScrn1->virtualX - x1; - h1 = realvirtY; - if((usenonrect) && (pI830->maxFirst_Y1 != realvirtY)) { - h1 = pI830->MBXNR1YMAX = pI830->maxFirst_Y1; - pI830->NonRectDead.x0 = x1; - pI830->NonRectDead.x1 = x1 + w1 - 1; - pI830->NonRectDead.y0 = y1 + h1; - pI830->NonRectDead.y1 = pScrn1->virtualY - 1; - pI830->HaveNonRect = TRUE; - } - x2 = 0; - y2 = pI830->SecondYOffs; - w2 = max(pI830->maxSecond_X2, pScrn1->virtualX - pI830->maxSecond_X1); - if(w2 > pScrn1->virtualX) w2 = pScrn1->virtualX; - h2 = realvirtY; - if((usenonrect) && (pI830->maxSecond_Y2 != realvirtY)) { - h2 = pI830->MBXNR2YMAX = pI830->maxSecond_Y2; - pI830->NonRectDead.x0 = x2; - pI830->NonRectDead.x1 = x2 + w2 - 1; - pI830->NonRectDead.y0 = y2 + h2; - pI830->NonRectDead.y1 = pScrn1->virtualY - 1; - pI830->HaveNonRect = TRUE; - } - break; - case PosRightOf: - x1 = 0; - y1 = pI830->FirstYOffs; - w1 = max(pI830->maxFirst_X1, pScrn1->virtualX - pI830->maxFirst_X2); - if(w1 > pScrn1->virtualX) w1 = pScrn1->virtualX; - h1 = realvirtY; - if((usenonrect) && (pI830->maxFirst_Y1 != realvirtY)) { - h1 = pI830->MBXNR1YMAX = pI830->maxFirst_Y1; - pI830->NonRectDead.x0 = x1; - pI830->NonRectDead.x1 = x1 + w1 - 1; - pI830->NonRectDead.y0 = y1 + h1; - pI830->NonRectDead.y1 = pScrn1->virtualY - 1; - pI830->HaveNonRect = TRUE; - } - x2 = min(pI830->maxSecond_X1, pScrn1->virtualX - pI830->maxSecond_X2); - if(x2 < 0) x2 = 0; - y2 = pI830->SecondYOffs; - w2 = pScrn1->virtualX - x2; - h2 = realvirtY; - if((usenonrect) && (pI830->maxSecond_Y2 != realvirtY)) { - h2 = pI830->MBXNR2YMAX = pI830->maxSecond_Y2; - pI830->NonRectDead.x0 = x2; - pI830->NonRectDead.x1 = x2 + w2 - 1; - pI830->NonRectDead.y0 = y2 + h2; - pI830->NonRectDead.y1 = pScrn1->virtualY - 1; - pI830->HaveNonRect = TRUE; - } - break; - case PosAbove: - x1 = pI830->FirstXOffs; - y1 = min(pI830->maxFirst_Y2, pScrn1->virtualY - pI830->maxFirst_Y1); - if(y1 < 0) y1 = 0; - w1 = realvirtX; - h1 = pScrn1->virtualY - y1; - if((usenonrect) && (pI830->maxFirst_X1 != realvirtX)) { - w1 = pI830->MBXNR1XMAX = pI830->maxFirst_X1; - pI830->NonRectDead.x0 = x1 + w1; - pI830->NonRectDead.x1 = pScrn1->virtualX - 1; - pI830->NonRectDead.y0 = y1; - pI830->NonRectDead.y1 = y1 + h1 - 1; - pI830->HaveNonRect = TRUE; - } - x2 = pI830->SecondXOffs; - y2 = 0; - w2 = realvirtX; - h2 = max(pI830->maxSecond_Y2, pScrn1->virtualY - pI830->maxSecond_Y1); - if(h2 > pScrn1->virtualY) h2 = pScrn1->virtualY; - if((usenonrect) && (pI830->maxSecond_X2 != realvirtX)) { - w2 = pI830->MBXNR2XMAX = pI830->maxSecond_X2; - pI830->NonRectDead.x0 = x2 + w2; - pI830->NonRectDead.x1 = pScrn1->virtualX - 1; - pI830->NonRectDead.y0 = y2; - pI830->NonRectDead.y1 = y2 + h2 - 1; - pI830->HaveNonRect = TRUE; - } - break; - case PosBelow: - x1 = pI830->FirstXOffs; - y1 = 0; - w1 = realvirtX; - h1 = max(pI830->maxFirst_Y1, pScrn1->virtualY - pI830->maxFirst_Y2); - if(h1 > pScrn1->virtualY) h1 = pScrn1->virtualY; - if((usenonrect) && (pI830->maxFirst_X1 != realvirtX)) { - w1 = pI830->MBXNR1XMAX = pI830->maxFirst_X1; - pI830->NonRectDead.x0 = x1 + w1; - pI830->NonRectDead.x1 = pScrn1->virtualX - 1; - pI830->NonRectDead.y0 = y1; - pI830->NonRectDead.y1 = y1 + h1 - 1; - pI830->HaveNonRect = TRUE; - } - x2 = pI830->SecondXOffs; - y2 = min(pI830->maxSecond_Y1, pScrn1->virtualY - pI830->maxSecond_Y2); - if(y2 < 0) y2 = 0; - w2 = realvirtX; - h2 = pScrn1->virtualY - y2; - if((usenonrect) && (pI830->maxSecond_X2 != realvirtX)) { - w2 = pI830->MBXNR2XMAX = pI830->maxSecond_X2; - pI830->NonRectDead.x0 = x2 + w2; - pI830->NonRectDead.x1 = pScrn1->virtualX - 1; - pI830->NonRectDead.y0 = y2; - pI830->NonRectDead.y1 = y2 + h2 - 1; - pI830->HaveNonRect = TRUE; - } - default: - break; - } - - switch(pI830->SecondPosition) { - case PosLeftOf: - case PosRightOf: - if(pI830->FirstYOffs) { - pI830->OffDead1.x0 = x1; - pI830->OffDead1.x1 = x1 + w1 - 1; - pI830->OffDead1.y0 = 0; - pI830->OffDead1.y1 = y1 - 1; - pI830->OffDead2.x0 = x2; - pI830->OffDead2.x1 = x2 + w2 - 1; - pI830->OffDead2.y0 = y2 + h2; - pI830->OffDead2.y1 = pScrn1->virtualY - 1; - pI830->HaveOffsRegions = TRUE; - } else if(pI830->SecondYOffs) { - pI830->OffDead1.x0 = x2; - pI830->OffDead1.x1 = x2 + w2 - 1; - pI830->OffDead1.y0 = 0; - pI830->OffDead1.y1 = y2 - 1; - pI830->OffDead2.x0 = x1; - pI830->OffDead2.x1 = x1 + w1 - 1; - pI830->OffDead2.y0 = y1 + h1; - pI830->OffDead2.y1 = pScrn1->virtualY - 1; - pI830->HaveOffsRegions = TRUE; - } - break; - case PosAbove: - case PosBelow: - if(pI830->FirstXOffs) { - pI830->OffDead1.x0 = x2 + w2; - pI830->OffDead1.x1 = pScrn1->virtualX - 1; - pI830->OffDead1.y0 = y2; - pI830->OffDead1.y1 = y2 + h2 - 1; - pI830->OffDead2.x0 = 0; - pI830->OffDead2.x1 = x1 - 1; - pI830->OffDead2.y0 = y1; - pI830->OffDead2.y1 = y1 + h1 - 1; - pI830->HaveOffsRegions = TRUE; - } else if(pI830->SecondXOffs) { - pI830->OffDead1.x0 = x1 + w1; - pI830->OffDead1.x1 = pScrn1->virtualX - 1; - pI830->OffDead1.y0 = y1; - pI830->OffDead1.y1 = y1 + h1 - 1; - pI830->OffDead2.x0 = 0; - pI830->OffDead2.x1 = x2 - 1; - pI830->OffDead2.y0 = y2; - pI830->OffDead2.y1 = y2 + h2 - 1; - pI830->HaveOffsRegions = TRUE; - } - default: - break; - } - - } - -#ifdef XF86DRI - if (pI830->directRenderingEnabled) { - sarea->pipeA_x = x1; - sarea->pipeA_y = y1; - sarea->pipeA_w = w1; - sarea->pipeA_h = h1; - sarea->pipeB_x = x2; - sarea->pipeB_y = y2; - sarea->pipeB_w = w2; - sarea->pipeB_h = h2; - } -#endif - - if (I830XineramadataPtr && !I830noPanoramiXExtension) { - I830XineramadataPtr[scrnnum1].x = x1; - I830XineramadataPtr[scrnnum1].y = y1; - I830XineramadataPtr[scrnnum1].width = w1; - I830XineramadataPtr[scrnnum1].height = h1; - I830XineramadataPtr[scrnnum2].x = x2; - I830XineramadataPtr[scrnnum2].y = y2; - I830XineramadataPtr[scrnnum2].width = w2; - I830XineramadataPtr[scrnnum2].height = h2; - } else - return; - - if(infochanged) { - xf86DrvMsg(pScrn1->scrnIndex, X_INFO, - "Pseudo-Xinerama: First (Screen %d) (%d,%d)-(%d,%d)\n", - scrnnum1, x1, y1, w1+x1-1, h1+y1-1); - xf86DrvMsg(pScrn1->scrnIndex, X_INFO, - "Pseudo-Xinerama: Second (Screen %d) (%d,%d)-(%d,%d)\n", - scrnnum2, x2, y2, w2+x2-1, h2+y2-1); - if(pI830->HaveNonRect) { - xf86DrvMsg(pScrn1->scrnIndex, X_INFO, - "Pseudo-Xinerama: Inaccessible area (%d,%d)-(%d,%d)\n", - pI830->NonRectDead.x0, pI830->NonRectDead.y0, - pI830->NonRectDead.x1, pI830->NonRectDead.y1); - } - if(pI830->HaveOffsRegions) { - xf86DrvMsg(pScrn1->scrnIndex, X_INFO, - "Pseudo-Xinerama: Inaccessible offset area (%d,%d)-(%d,%d)\n", - pI830->OffDead1.x0, pI830->OffDead1.y0, - pI830->OffDead1.x1, pI830->OffDead1.y1); - xf86DrvMsg(pScrn1->scrnIndex, X_INFO, - "Pseudo-Xinerama: Inaccessible offset area (%d,%d)-(%d,%d)\n", - pI830->OffDead2.x0, pI830->OffDead2.y0, - pI830->OffDead2.x1, pI830->OffDead2.y1); - } - if(pI830->HaveNonRect || pI830->HaveOffsRegions) { - xf86DrvMsg(pScrn1->scrnIndex, X_INFO, - "Mouse restriction for inaccessible areas is %s\n", - pI830->MouseRestrictions ? "enabled" : "disabled"); - } - } -} - -/* Proc */ - -int -I830ProcXineramaQueryVersion(ClientPtr client) -{ - xPanoramiXQueryVersionReply rep; - register int n; - - REQUEST_SIZE_MATCH(xPanoramiXQueryVersionReq); - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - rep.majorVersion = 1; - rep.minorVersion = 0; - if(client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swaps(&rep.majorVersion, n); - swaps(&rep.minorVersion, n); - } - WriteToClient(client, sizeof(xPanoramiXQueryVersionReply), (char *)&rep); - return (client->noClientException); -} - -int -I830ProcXineramaGetState(ClientPtr client) -{ - REQUEST(xPanoramiXGetStateReq); - WindowPtr pWin; - xPanoramiXGetStateReply rep; - register int n; - - REQUEST_SIZE_MATCH(xPanoramiXGetStateReq); - pWin = LookupWindow(stuff->window, client); - if(!pWin) return BadWindow; - - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - rep.state = !I830noPanoramiXExtension; - if(client->swapped) { - swaps (&rep.sequenceNumber, n); - swapl (&rep.length, n); - swaps (&rep.state, n); - } - WriteToClient(client, sizeof(xPanoramiXGetStateReply), (char *)&rep); - return client->noClientException; -} - -int -I830ProcXineramaGetScreenCount(ClientPtr client) -{ - REQUEST(xPanoramiXGetScreenCountReq); - WindowPtr pWin; - xPanoramiXGetScreenCountReply rep; - register int n; - - REQUEST_SIZE_MATCH(xPanoramiXGetScreenCountReq); - pWin = LookupWindow(stuff->window, client); - if(!pWin) return BadWindow; - - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - rep.ScreenCount = I830XineramaNumScreens; - if(client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swaps(&rep.ScreenCount, n); - } - WriteToClient(client, sizeof(xPanoramiXGetScreenCountReply), (char *)&rep); - return client->noClientException; -} - -int -I830ProcXineramaGetScreenSize(ClientPtr client) -{ - REQUEST(xPanoramiXGetScreenSizeReq); - WindowPtr pWin; - xPanoramiXGetScreenSizeReply rep; - register int n; - - REQUEST_SIZE_MATCH(xPanoramiXGetScreenSizeReq); - pWin = LookupWindow (stuff->window, client); - if(!pWin) return BadWindow; - - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - rep.width = I830XineramadataPtr[stuff->screen].width; - rep.height = I830XineramadataPtr[stuff->screen].height; - if(client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swaps(&rep.width, n); - swaps(&rep.height, n); - } - WriteToClient(client, sizeof(xPanoramiXGetScreenSizeReply), (char *)&rep); - return client->noClientException; -} - -int -I830ProcXineramaIsActive(ClientPtr client) -{ - xXineramaIsActiveReply rep; - - REQUEST_SIZE_MATCH(xXineramaIsActiveReq); - - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - rep.state = !I830noPanoramiXExtension; - if(client->swapped) { - register int n; - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swapl(&rep.state, n); - } - WriteToClient(client, sizeof(xXineramaIsActiveReply), (char *) &rep); - return client->noClientException; -} - -int -I830ProcXineramaQueryScreens(ClientPtr client) -{ - xXineramaQueryScreensReply rep; - - REQUEST_SIZE_MATCH(xXineramaQueryScreensReq); - - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.number = (I830noPanoramiXExtension) ? 0 : I830XineramaNumScreens; - rep.length = rep.number * sz_XineramaScreenInfo >> 2; - if(client->swapped) { - register int n; - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swapl(&rep.number, n); - } - WriteToClient(client, sizeof(xXineramaQueryScreensReply), (char *)&rep); - - if(!I830noPanoramiXExtension) { - xXineramaScreenInfo scratch; - int i; - - for(i = 0; i < I830XineramaNumScreens; i++) { - scratch.x_org = I830XineramadataPtr[i].x; - scratch.y_org = I830XineramadataPtr[i].y; - scratch.width = I830XineramadataPtr[i].width; - scratch.height = I830XineramadataPtr[i].height; - if(client->swapped) { - register int n; - swaps(&scratch.x_org, n); - swaps(&scratch.y_org, n); - swaps(&scratch.width, n); - swaps(&scratch.height, n); - } - WriteToClient(client, sz_XineramaScreenInfo, (char *)&scratch); - } - } - - return client->noClientException; -} - -static int -I830ProcXineramaDispatch(ClientPtr client) -{ - REQUEST(xReq); - switch (stuff->data) { - case X_PanoramiXQueryVersion: - return I830ProcXineramaQueryVersion(client); - case X_PanoramiXGetState: - return I830ProcXineramaGetState(client); - case X_PanoramiXGetScreenCount: - return I830ProcXineramaGetScreenCount(client); - case X_PanoramiXGetScreenSize: - return I830ProcXineramaGetScreenSize(client); - case X_XineramaIsActive: - return I830ProcXineramaIsActive(client); - case X_XineramaQueryScreens: - return I830ProcXineramaQueryScreens(client); - } - return BadRequest; -} - -/* SProc */ - -static int -I830SProcXineramaQueryVersion (ClientPtr client) -{ - REQUEST(xPanoramiXQueryVersionReq); - register int n; - swaps(&stuff->length,n); - REQUEST_SIZE_MATCH (xPanoramiXQueryVersionReq); - return I830ProcXineramaQueryVersion(client); -} - -static int -I830SProcXineramaGetState(ClientPtr client) -{ - REQUEST(xPanoramiXGetStateReq); - register int n; - swaps (&stuff->length, n); - REQUEST_SIZE_MATCH(xPanoramiXGetStateReq); - return I830ProcXineramaGetState(client); -} - -static int -I830SProcXineramaGetScreenCount(ClientPtr client) -{ - REQUEST(xPanoramiXGetScreenCountReq); - register int n; - swaps (&stuff->length, n); - REQUEST_SIZE_MATCH(xPanoramiXGetScreenCountReq); - return I830ProcXineramaGetScreenCount(client); -} - -static int -I830SProcXineramaGetScreenSize(ClientPtr client) -{ - REQUEST(xPanoramiXGetScreenSizeReq); - register int n; - swaps (&stuff->length, n); - REQUEST_SIZE_MATCH(xPanoramiXGetScreenSizeReq); - return I830ProcXineramaGetScreenSize(client); -} - -static int -I830SProcXineramaIsActive(ClientPtr client) -{ - REQUEST(xXineramaIsActiveReq); - register int n; - swaps (&stuff->length, n); - REQUEST_SIZE_MATCH(xXineramaIsActiveReq); - return I830ProcXineramaIsActive(client); -} - -static int -I830SProcXineramaQueryScreens(ClientPtr client) -{ - REQUEST(xXineramaQueryScreensReq); - register int n; - swaps (&stuff->length, n); - REQUEST_SIZE_MATCH(xXineramaQueryScreensReq); - return I830ProcXineramaQueryScreens(client); -} - -int -I830SProcXineramaDispatch(ClientPtr client) -{ - REQUEST(xReq); - switch (stuff->data) { - case X_PanoramiXQueryVersion: - return I830SProcXineramaQueryVersion(client); - case X_PanoramiXGetState: - return I830SProcXineramaGetState(client); - case X_PanoramiXGetScreenCount: - return I830SProcXineramaGetScreenCount(client); - case X_PanoramiXGetScreenSize: - return I830SProcXineramaGetScreenSize(client); - case X_XineramaIsActive: - return I830SProcXineramaIsActive(client); - case X_XineramaQueryScreens: - return I830SProcXineramaQueryScreens(client); - } - return BadRequest; -} - -static void -I830XineramaResetProc(ExtensionEntry* extEntry) -{ - /* Called by CloseDownExtensions() */ - if(I830XineramadataPtr) { - Xfree(I830XineramadataPtr); - I830XineramadataPtr = NULL; - } -} - -static void -I830XineramaExtensionInit(ScrnInfoPtr pScrn) -{ - I830Ptr pI830 = I830PTR(pScrn); - Bool success = FALSE; - - if(!(I830XineramadataPtr)) { - - if(!pI830->MergedFB) { - I830noPanoramiXExtension = TRUE; - pI830->MouseRestrictions = FALSE; - return; - } - -#ifdef PANORAMIX - if(!noPanoramiXExtension) { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Xinerama active, not initializing Intel Pseudo-Xinerama\n"); - I830noPanoramiXExtension = TRUE; - pI830->MouseRestrictions = FALSE; - return; - } -#endif - - if(I830noPanoramiXExtension) { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Intel Pseudo-Xinerama disabled\n"); - pI830->MouseRestrictions = FALSE; - return; - } - - I830XineramaNumScreens = 2; - - while(I830XineramaGeneration != serverGeneration) { - - pI830->XineramaExtEntry = AddExtension(PANORAMIX_PROTOCOL_NAME, 0,0, - I830ProcXineramaDispatch, - I830SProcXineramaDispatch, - I830XineramaResetProc, - StandardMinorOpcode); - - if(!pI830->XineramaExtEntry) break; - - if(!(I830XineramadataPtr = (I830XineramaData *) - xcalloc(I830XineramaNumScreens, sizeof(I830XineramaData)))) break; - - I830XineramaGeneration = serverGeneration; - success = TRUE; - } - - if(!success) { - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "Failed to initialize Intel Pseudo-Xinerama extension\n"); - I830noPanoramiXExtension = TRUE; - pI830->MouseRestrictions = FALSE; - return; - } - - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Intel Pseudo-Xinerama extension initialized\n"); - - pI830->I830XineramaVX = 0; - pI830->I830XineramaVY = 0; - - } -} - -static void -I830BIOSProbeDDC(ScrnInfoPtr pScrn, int index) +I830ProbeDDC(ScrnInfoPtr pScrn, int index) { vbeInfoPtr pVbe; @@ -2085,1018 +390,6 @@ I830BIOSProbeDDC(ScrnInfoPtr pScrn, int index) ConfiguredMonitor = vbeDoEDID(pVbe, NULL); } -/* Various extended video BIOS functions. - * 100 and 120Hz aren't really supported, they work but only get close - * to the requested refresh, and really not close enough. - * I've seen 100Hz come out at 104Hz, and 120Hz come out at 128Hz */ -const int i830refreshes[] = { - 43, 56, 60, 70, 72, 75, 85 /* 100, 120 */ -}; -static const int nrefreshes = sizeof(i830refreshes) / sizeof(i830refreshes[0]); - -static Bool -Check5fStatus(ScrnInfoPtr pScrn, int func, int ax) -{ - if (ax == 0x005f) - return TRUE; - else if (ax == 0x015f) { - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "Extended BIOS function 0x%04x failed.\n", func); - return FALSE; - } else if ((ax & 0xff) != 0x5f) { - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "Extended BIOS function 0x%04x not supported.\n", func); - return FALSE; - } else { - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "Extended BIOS function 0x%04x returns 0x%04x.\n", - func, ax & 0xffff); - return FALSE; - } -} - -static int -GetToggleList(ScrnInfoPtr pScrn, int toggle) -{ - vbeInfoPtr pVbe = I830PTR(pScrn)->pVbe; - - DPRINTF(PFX, "GetToggleList\n"); - - pVbe->pInt10->num = 0x10; - pVbe->pInt10->ax = 0x5f64; - pVbe->pInt10->bx = 0x500; - - pVbe->pInt10->bx |= toggle; - - xf86ExecX86int10_wrapper(pVbe->pInt10, pScrn); - if (Check5fStatus(pScrn, 0x5f64, pVbe->pInt10->ax)) { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Toggle (%d) 0x%x\n", toggle, pVbe->pInt10->cx); - return pVbe->pInt10->cx & 0xffff; - } - - return 0; -} - -static int -GetNextDisplayDeviceList(ScrnInfoPtr pScrn, int toggle) -{ - vbeInfoPtr pVbe = I830PTR(pScrn)->pVbe; - int devices = 0; - int pipe = 0; - int i; - - DPRINTF(PFX, "GetNextDisplayDeviceList\n"); - - pVbe->pInt10->num = 0x10; - pVbe->pInt10->ax = 0x5f64; - pVbe->pInt10->bx = 0xA00; - pVbe->pInt10->bx |= toggle; - pVbe->pInt10->es = SEG_ADDR(pVbe->real_mode_base); - pVbe->pInt10->di = SEG_OFF(pVbe->real_mode_base); - - xf86ExecX86int10_wrapper(pVbe->pInt10, pScrn); - if (!Check5fStatus(pScrn, 0x5f64, pVbe->pInt10->ax)) - return 0; - - for (i=0; i<(pVbe->pInt10->cx & 0xff); i++) { - CARD32 VODA = (CARD32)((CARD32*)pVbe->memory)[i]; - - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Next ACPI _DGS [%d] 0x%lx\n", - i, VODA); - - /* Check if it's a custom Video Output Device Attribute */ - if (!(VODA & 0x80000000)) - continue; - - pipe = (VODA & 0x000000F0) >> 4; - - if (pipe != 0 && pipe != 1) { - pipe = 0; -#if 0 - ErrorF("PIPE %d\n",pipe); -#endif - } - - switch ((VODA & 0x00000F00) >> 8) { - case 0x0: - case 0x1: /* CRT */ - devices |= PIPE_CRT << (pipe == 1 ? 8 : 0); - break; - case 0x2: /* TV/HDTV */ - devices |= PIPE_TV << (pipe == 1 ? 8 : 0); - break; - case 0x3: /* DFP */ - devices |= PIPE_DFP << (pipe == 1 ? 8 : 0); - break; - case 0x4: /* LFP */ - devices |= PIPE_LFP << (pipe == 1 ? 8 : 0); - break; - } - } - - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "ACPI Toggle devices 0x%x\n", devices); - - return devices; -} - -static int -GetAttachableDisplayDeviceList(ScrnInfoPtr pScrn) -{ - vbeInfoPtr pVbe = I830PTR(pScrn)->pVbe; - int i; - - DPRINTF(PFX, "GetAttachableDisplayDeviceList\n"); - - pVbe->pInt10->num = 0x10; - pVbe->pInt10->ax = 0x5f64; - pVbe->pInt10->bx = 0x900; - pVbe->pInt10->es = SEG_ADDR(pVbe->real_mode_base); - pVbe->pInt10->di = SEG_OFF(pVbe->real_mode_base); - - xf86ExecX86int10_wrapper(pVbe->pInt10, pScrn); - if (!Check5fStatus(pScrn, 0x5f64, pVbe->pInt10->ax)) - return 0; - - for (i=0; i<(pVbe->pInt10->cx & 0xff); i++) - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Attachable device 0x%lx.\n", ((CARD32*)pVbe->memory)[i]); - - return pVbe->pInt10->cx & 0xffff; -} - -static int -BitToRefresh(int bits) -{ - int i; - - for (i = 0; i < nrefreshes; i++) - if (bits & (1 << i)) - return i830refreshes[i]; - return 0; -} - -static int -GetRefreshRate(ScrnInfoPtr pScrn, int mode, int *availRefresh) -{ - vbeInfoPtr pVbe = I830PTR(pScrn)->pVbe; - - DPRINTF(PFX, "GetRefreshRate\n"); - - /* Only 8-bit mode numbers are supported. */ - if (mode & 0x100) - return 0; - - pVbe->pInt10->num = 0x10; - pVbe->pInt10->ax = 0x5f05; - pVbe->pInt10->bx = (mode & 0xff) | 0x100; - - xf86ExecX86int10_wrapper(pVbe->pInt10, pScrn); - if (Check5fStatus(pScrn, 0x5f05, pVbe->pInt10->ax)) { - if (availRefresh) - *availRefresh = pVbe->pInt10->bx; - return BitToRefresh(pVbe->pInt10->cx); - } else - return 0; -} - -struct panelid { - short hsize; - short vsize; - short fptype; - char redbpp; - char greenbpp; - char bluebpp; - char reservedbpp; - int rsvdoffscrnmemsize; - int rsvdoffscrnmemptr; - char reserved[14]; -}; - -static void -I830InterpretPanelID(int scrnIndex, unsigned char *tmp) -{ - ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; - struct panelid *block = (struct panelid *)tmp; - -#define PANEL_DEFAULT_HZ 60 - - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "PanelID returned panel resolution : %dx%d\n", - block->hsize, block->vsize); - - /* If we get bogus values from this, don't accept it */ - if (block->hsize == 0 || block->vsize == 0) { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Bad Panel resolution - ignoring panelID\n"); - - return; - } - - /* If we have monitor timings then don't overwrite them */ - if (pScrn->monitor->nHsync > 0 && - pScrn->monitor->nVrefresh > 0) - return; - - /* With panels, we're always assuming a refresh of 60Hz */ - - pScrn->monitor->nHsync = 1; - pScrn->monitor->nVrefresh = 1; - - /* Give a little tolerance for the selected panel */ - pScrn->monitor->hsync[0].lo = (float)((PANEL_DEFAULT_HZ/1.05)*block->vsize)/1000; - pScrn->monitor->hsync[0].hi = (float)((PANEL_DEFAULT_HZ/0.95)*block->vsize)/1000; - pScrn->monitor->vrefresh[0].lo = (float)PANEL_DEFAULT_HZ; - pScrn->monitor->vrefresh[0].hi = (float)PANEL_DEFAULT_HZ; -} - -/* This should probably go into the VBE layer */ -static unsigned char * -vbeReadPanelID(vbeInfoPtr pVbe) -{ - int RealOff = pVbe->real_mode_base; - pointer page = pVbe->memory; - unsigned char *tmp = NULL; - int screen = pVbe->pInt10->scrnIndex; - - pVbe->pInt10->ax = 0x4F11; - pVbe->pInt10->bx = 0x01; - pVbe->pInt10->cx = 0; - pVbe->pInt10->dx = 0; - pVbe->pInt10->es = SEG_ADDR(RealOff); - pVbe->pInt10->di = SEG_OFF(RealOff); - pVbe->pInt10->num = 0x10; - - xf86ExecX86int10(pVbe->pInt10); - - if ((pVbe->pInt10->ax & 0xff) != 0x4f) { - xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE PanelID invalid\n"); - goto error; - } - switch (pVbe->pInt10->ax & 0xff00) { - case 0x0: - xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE PanelID read successfully\n"); - tmp = (unsigned char *)xnfalloc(32); - memcpy(tmp,page,32); - break; - case 0x100: - xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE PanelID read failed\n"); - break; - default: - xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE PanelID unknown failure %i\n", - pVbe->pInt10->ax & 0xff00); - break; - } - - error: - return tmp; -} - -static void -vbeDoPanelID(vbeInfoPtr pVbe) -{ - unsigned char *PanelID_data; - - if (!pVbe) return; - - PanelID_data = vbeReadPanelID(pVbe); - - if (!PanelID_data) - return; - - I830InterpretPanelID(pVbe->pInt10->scrnIndex, PanelID_data); -} - -int -I830GetBestRefresh(ScrnInfoPtr pScrn, int refresh) -{ - int i; - - for (i = nrefreshes - 1; i >= 0; i--) { - /* - * Look for the highest value that the requested (refresh + 2) is - * greater than or equal to. - */ - if (i830refreshes[i] <= (refresh + 2)) - break; - } - /* i can be 0 if the requested refresh was higher than the max. */ - if (i == 0) { - if (refresh >= i830refreshes[nrefreshes - 1]) - i = nrefreshes - 1; - } - - return i; -} - -static int -SetRefreshRate(ScrnInfoPtr pScrn, int mode, int refresh) -{ - vbeInfoPtr pVbe = I830PTR(pScrn)->pVbe; - int i = I830GetBestRefresh(pScrn, refresh); - - DPRINTF(PFX, "SetRefreshRate: mode 0x%x, refresh: %d\n", mode, refresh); - - DPRINTF(PFX, "Setting refresh rate to %dHz for mode 0x%02x\n", - i830refreshes[i], mode & 0xff); - - /* Only 8-bit mode numbers are supported. */ - if (mode & 0x100) - return 0; - - pVbe->pInt10->num = 0x10; - pVbe->pInt10->ax = 0x5f05; - pVbe->pInt10->bx = mode & 0xff; - - pVbe->pInt10->cx = 1 << i; - xf86ExecX86int10_wrapper(pVbe->pInt10, pScrn); - if (Check5fStatus(pScrn, 0x5f05, pVbe->pInt10->ax)) - return i830refreshes[i]; - else - return 0; -} - -#if 0 -static Bool -SetPowerStatus(ScrnInfoPtr pScrn, int mode) -{ - vbeInfoPtr pVbe = I830PTR(pScrn)->pVbe; - - pVbe->pInt10->num = 0x10; - pVbe->pInt10->ax = 0x5f64; - pVbe->pInt10->bx = 0x0800 | mode; - pVbe->pInt10->cx = 0x0000; - - xf86ExecX86int10_wrapper(pVbe->pInt10, pScrn); - if (Check5fStatus(pScrn, 0x5f64, pVbe->pInt10->ax)) - return TRUE; - - return FALSE; -} -#endif - -static Bool -GetModeSupport(ScrnInfoPtr pScrn, int modePipeA, int modePipeB, - int devicesPipeA, int devicesPipeB, int *maxBandwidth, - int *bandwidthPipeA, int *bandwidthPipeB) -{ - vbeInfoPtr pVbe = I830PTR(pScrn)->pVbe; - - DPRINTF(PFX, "GetModeSupport: modes 0x%x, 0x%x, devices: 0x%x, 0x%x\n", - modePipeA, modePipeB, devicesPipeA, devicesPipeB); - - /* Only 8-bit mode numbers are supported. */ - if ((modePipeA & 0x100) || (modePipeB & 0x100)) - return FALSE; - - pVbe->pInt10->num = 0x10; - pVbe->pInt10->ax = 0x5f28; - pVbe->pInt10->bx = (modePipeA & 0xff) | ((modePipeB & 0xff) << 8); - if ((devicesPipeA & 0x80) || (devicesPipeB & 0x80)) - pVbe->pInt10->cx = 0x8000; - else - pVbe->pInt10->cx = (devicesPipeA & 0xff) | ((devicesPipeB & 0xff) << 8); - - xf86ExecX86int10_wrapper(pVbe->pInt10, pScrn); - if (Check5fStatus(pScrn, 0x5f28, pVbe->pInt10->ax)) { - if (maxBandwidth) - *maxBandwidth = pVbe->pInt10->cx; - if (bandwidthPipeA) - *bandwidthPipeA = pVbe->pInt10->dx & 0xffff; - /* XXX For XFree86 4.2.0 and earlier, ->dx is truncated to 16 bits. */ - if (bandwidthPipeB) - *bandwidthPipeB = (pVbe->pInt10->dx >> 16) & 0xffff; - return TRUE; - } else - return FALSE; -} - -#if 0 -static int -GetLFPCompMode(ScrnInfoPtr pScrn) -{ - vbeInfoPtr pVbe = I830PTR(pScrn)->pVbe; - - DPRINTF(PFX, "GetLFPCompMode\n"); - - pVbe->pInt10->num = 0x10; - pVbe->pInt10->ax = 0x5f61; - pVbe->pInt10->bx = 0x100; - - xf86ExecX86int10_wrapper(pVbe->pInt10, pScrn); - if (Check5fStatus(pScrn, 0x5f61, pVbe->pInt10->ax)) - return pVbe->pInt10->cx & 0xffff; - else - return -1; -} - -static Bool -SetLFPCompMode(ScrnInfoPtr pScrn, int compMode) -{ - vbeInfoPtr pVbe = I830PTR(pScrn)->pVbe; - - DPRINTF(PFX, "SetLFPCompMode: compMode %d\n", compMode); - - pVbe->pInt10->num = 0x10; - pVbe->pInt10->ax = 0x5f61; - pVbe->pInt10->bx = 0; - pVbe->pInt10->cx = compMode; - - xf86ExecX86int10_wrapper(pVbe->pInt10, pScrn); - return Check5fStatus(pScrn, 0x5f61, pVbe->pInt10->ax); -} -#endif - -static int -GetDisplayDevices(ScrnInfoPtr pScrn) -{ - I830Ptr pI830 = I830PTR(pScrn); - vbeInfoPtr pVbe = pI830->pVbe; - - DPRINTF(PFX, "GetDisplayDevices\n"); - -#if 0 - { - CARD32 temp; - ErrorF("ADPA is 0x%08x\n", INREG(ADPA)); - ErrorF("DVOA is 0x%08x\n", INREG(DVOA)); - ErrorF("DVOB is 0x%08x\n", INREG(DVOB)); - ErrorF("DVOC is 0x%08x\n", INREG(DVOC)); - ErrorF("LVDS is 0x%08x\n", INREG(LVDS)); - temp = INREG(DVOA_SRCDIM); - ErrorF("DVOA_SRCDIM is 0x%08x (%d x %d)\n", temp, - (temp >> 12) & 0xfff, temp & 0xfff); - temp = INREG(DVOB_SRCDIM); - ErrorF("DVOB_SRCDIM is 0x%08x (%d x %d)\n", temp, - (temp >> 12) & 0xfff, temp & 0xfff); - temp = INREG(DVOC_SRCDIM); - ErrorF("DVOC_SRCDIM is 0x%08x (%d x %d)\n", temp, - (temp >> 12) & 0xfff, temp & 0xfff); - ErrorF("SWF0 is 0x%08x\n", INREG(SWF0)); - ErrorF("SWF4 is 0x%08x\n", INREG(SWF4)); - } -#endif - - pVbe->pInt10->num = 0x10; - pVbe->pInt10->ax = 0x5f64; - pVbe->pInt10->bx = 0x100; - - xf86ExecX86int10_wrapper(pVbe->pInt10, pScrn); - if (Check5fStatus(pScrn, 0x5f64, pVbe->pInt10->ax)) { - return pVbe->pInt10->cx & 0xffff; - } else { - if (pI830->PciInfo->chipType == PCI_CHIP_E7221_G) /* FIXED CONFIG */ - return PIPE_CRT; - else - return -1; - } -} - -static int -GetBIOSPipe(ScrnInfoPtr pScrn) -{ - I830Ptr pI830 = I830PTR(pScrn); - vbeInfoPtr pVbe = pI830->pVbe; - int pipe; - - DPRINTF(PFX, "GetBIOSPipe:\n"); - - /* single pipe machines should always return Pipe A */ - if (pI830->availablePipes == 1) return 0; - - pVbe->pInt10->num = 0x10; - pVbe->pInt10->ax = 0x5f1c; - pVbe->pInt10->bx = 0x100; - - xf86ExecX86int10_wrapper(pVbe->pInt10, pScrn); - if (Check5fStatus(pScrn, 0x5f1c, pVbe->pInt10->ax)) { - if (pI830->newPipeSwitch) { - pipe = ((pVbe->pInt10->bx & 0x0001)); - } else { - pipe = ((pVbe->pInt10->cx & 0x0100) >> 8); - } - return pipe; - } - - /* failed, assume pipe A */ - return 0; -} - -static Bool -SetBIOSPipe(ScrnInfoPtr pScrn, int pipe) -{ - I830Ptr pI830 = I830PTR(pScrn); - vbeInfoPtr pVbe = pI830->pVbe; - - DPRINTF(PFX, "SetBIOSPipe: pipe 0x%x\n", pipe); - - /* single pipe machines should always return TRUE */ - if (pI830->availablePipes == 1) return TRUE; - - pVbe->pInt10->num = 0x10; - pVbe->pInt10->ax = 0x5f1c; - if (pI830->newPipeSwitch) { - pVbe->pInt10->bx = pipe; - pVbe->pInt10->cx = 0; - } else { - pVbe->pInt10->bx = 0x0; - pVbe->pInt10->cx = pipe << 8; - } - - xf86ExecX86int10_wrapper(pVbe->pInt10, pScrn); - if (Check5fStatus(pScrn, 0x5f1c, pVbe->pInt10->ax)) { - return TRUE; - } - - return FALSE; -} - -static Bool -SetPipeAccess(ScrnInfoPtr pScrn) -{ - I830Ptr pI830 = I830PTR(pScrn); - - /* Don't try messing with the pipe, unless we're dual head */ - if (xf86IsEntityShared(pScrn->entityList[0]) || pI830->Clone || pI830->MergedFB || pI830->origPipe != pI830->pipe) { - if (!SetBIOSPipe(pScrn, pI830->pipe)) - return FALSE; - } - - return TRUE; -} - -static Bool -I830Set640x480(ScrnInfoPtr pScrn) -{ - I830Ptr pI830 = I830PTR(pScrn); - int m; - - /* 640x480 8bpp */ - m = 0x30 | (1 << 15) | (1 << 14); - if (VBESetVBEMode(pI830->pVbe, m, NULL)) - return TRUE; - - /* if the first failed, let's try the next - usually 800x600 */ - m = 0x32 | (1 << 15) | (1 << 14); - - if (VBESetVBEMode(pI830->pVbe, m, NULL)) - return TRUE; - - return FALSE; -} - -/* This is needed for SetDisplayDevices to work correctly on I915G. - * Enable for all chipsets now as it has no bad side effects, apart - * from slightly longer startup time. - */ -#define I915G_WORKAROUND - -static Bool -SetDisplayDevices(ScrnInfoPtr pScrn, int devices) -{ - I830Ptr pI830 = I830PTR(pScrn); - vbeInfoPtr pVbe = pI830->pVbe; - CARD32 temp; - int singlepipe = 0; -#ifdef I915G_WORKAROUND - int getmode1; - Bool setmode = FALSE; -#endif - - DPRINTF(PFX, "SetDisplayDevices: devices 0x%x\n", devices); - - if (!pI830->specifiedMonitor) - return TRUE; - -#ifdef I915G_WORKAROUND - if (pI830->preinit) - setmode = TRUE; - if (pI830->leaving) - setmode = FALSE; - if (pI830->closing) - setmode = FALSE; - - if (setmode) { - VBEGetVBEMode(pVbe, &getmode1); - I830Set640x480(pScrn); - } -#endif - - pVbe->pInt10->num = 0x10; - pVbe->pInt10->ax = 0x5f64; - pVbe->pInt10->bx = 0x1; - pVbe->pInt10->cx = devices; - - xf86ExecX86int10_wrapper(pVbe->pInt10, pScrn); - if (Check5fStatus(pScrn, 0x5f64, pVbe->pInt10->ax)) { -#ifdef I915G_WORKAROUND - if (setmode) { - VBESetVBEMode(pI830->pVbe, getmode1 | 1<<15, NULL); - } -#endif - pI830->pipeEnabled[0] = (devices & 0xff) ? TRUE : FALSE; - pI830->pipeEnabled[1] = (devices & 0xff00) ? TRUE : FALSE; - - return TRUE; - } - -#ifdef I915G_WORKAROUND - if (setmode) - VBESetVBEMode(pI830->pVbe, getmode1 | 1<<15, NULL); -#endif - - if (devices & 0xff) { - pVbe->pInt10->num = 0x10; - pVbe->pInt10->ax = 0x5f64; - pVbe->pInt10->bx = 0x1; - pVbe->pInt10->cx = devices & 0xff; - - xf86ExecX86int10_wrapper(pVbe->pInt10, pScrn); - if (Check5fStatus(pScrn, 0x5f64, pVbe->pInt10->ax)) { - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "Successfully set display devices to 0x%x.\n",devices & 0xff); - singlepipe = devices & 0xff00; /* set alternate */ - } else { - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "Failed to set display devices to 0x%x.\n",devices & 0xff); - singlepipe = devices; - } - } else - singlepipe = devices; - - if (singlepipe == devices && devices & 0xff00) { - pVbe->pInt10->num = 0x10; - pVbe->pInt10->ax = 0x5f64; - pVbe->pInt10->bx = 0x1; - pVbe->pInt10->cx = devices & 0xff00; - - xf86ExecX86int10_wrapper(pVbe->pInt10, pScrn); - if (Check5fStatus(pScrn, 0x5f64, pVbe->pInt10->ax)) { - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "Successfully set display devices to 0x%x.\n",devices & 0xff00); - singlepipe = devices & 0xff; /* set alternate */ - } else { - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "Failed to set display devices to 0x%x.\n",devices & 0xff00); - singlepipe = devices; - } - } - - /* LVDS doesn't exist on these */ - if (IS_I830(pI830) || IS_845G(pI830) || IS_I865G(pI830) || IS_I915G(pI830) || IS_I945G(pI830) || IS_I965G(pI830)) - singlepipe &= ~(PIPE_LFP | (PIPE_LFP<<8)); - - if (pI830->availablePipes == 1) - singlepipe &= 0xFF; - - /* Disable LVDS */ - if (singlepipe & PIPE_LFP) { - /* LFP on PipeA is unlikely! */ - OUTREG(0x61200, INREG(0x61200) & ~0x80000000); - OUTREG(0x61204, INREG(0x61204) & ~0x00000001); - while ((INREG(0x61200) & 0x80000000) || (INREG(0x61204) & 1)); - /* Fix up LVDS */ - OUTREG(LVDS, (INREG(LVDS) & ~1<<30) | 0x80000300); - /* Enable LVDS */ - OUTREG(0x61200, INREG(0x61200) | 0x80000000); - OUTREG(0x61204, INREG(0x61204) | 0x00000001); - while (!(INREG(0x61200) & 0x80000000) && !(INREG(0x61204) & 1)); - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "Enabling LVDS directly. Pipe A.\n"); - } else - if (singlepipe & (PIPE_LFP << 8)) { - OUTREG(0x61200, INREG(0x61200) & ~0x80000000); - OUTREG(0x61204, INREG(0x61204) & ~0x00000001); - while ((INREG(0x61200) & 0x80000000) || (INREG(0x61204) & 1)); - /* Fix up LVDS */ - OUTREG(LVDS, (INREG(LVDS) | 1<<30) | 0x80000300); - /* Enable LVDS */ - OUTREG(0x61200, INREG(0x61200) | 0x80000000); - OUTREG(0x61204, INREG(0x61204) | 0x00000001); - while (!(INREG(0x61200) & 0x80000000) && !(INREG(0x61204) & 1)); - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "Enabling LVDS directly. Pipe B.\n"); - } - else if (!(IS_I830(pI830) || IS_845G(pI830) || IS_I865G(pI830))) { - if (!(devices & (PIPE_LFP | PIPE_LFP<<8))) { - OUTREG(0x61200, INREG(0x61200) & ~0x80000000); - OUTREG(0x61204, INREG(0x61204) & ~0x00000001); - while ((INREG(0x61200) & 0x80000000) || (INREG(0x61204) & 1)); - /* Fix up LVDS */ - OUTREG(LVDS, (INREG(LVDS) | 1<<30) & ~0x80000300); - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "Disabling LVDS directly.\n"); - } - } - - /* Now try to program the registers directly if the BIOS failed. */ - temp = INREG(ADPA); - temp &= ~(ADPA_DAC_ENABLE | ADPA_PIPE_SELECT_MASK); - temp &= ~(ADPA_VSYNC_CNTL_DISABLE | ADPA_HSYNC_CNTL_DISABLE); - /* Turn on ADPA */ - if (singlepipe & PIPE_CRT) { - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "Enabling ADPA directly. Pipe A.\n"); - temp |= ADPA_DAC_ENABLE | ADPA_PIPE_A_SELECT; - OUTREG(ADPA, temp); - } else - if (singlepipe & (PIPE_CRT << 8)) { - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "Enabling ADPA directly. Pipe B.\n"); - temp |= ADPA_DAC_ENABLE | ADPA_PIPE_B_SELECT; - OUTREG(ADPA, temp); - } - else { - if (!(devices & (PIPE_CRT | PIPE_CRT<<8))) { - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "Disabling ADPA directly.\n"); - temp |= ADPA_VSYNC_CNTL_DISABLE | ADPA_HSYNC_CNTL_DISABLE; - OUTREG(ADPA, temp); - } - } - - xf86DrvMsg(pScrn->scrnIndex, X_WARNING,"Writing config directly to SWF0.\n"); - temp = INREG(SWF0); - OUTREG(SWF0, (temp & ~(0xffff)) | (devices & 0xffff)); - - if (GetDisplayDevices(pScrn) != devices) { - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "SetDisplayDevices failed with devices 0x%x instead of 0x%x\n", - GetDisplayDevices(pScrn), devices); - return FALSE; - } - - pI830->pipeEnabled[0] = (devices & 0xff) ? TRUE : FALSE; - pI830->pipeEnabled[1] = (devices & 0xff00) ? TRUE : FALSE; - - return TRUE; -} - -static Bool -GetBIOSVersion(ScrnInfoPtr pScrn, unsigned int *version) -{ - vbeInfoPtr pVbe = I830PTR(pScrn)->pVbe; - - DPRINTF(PFX, "GetBIOSVersion\n"); - - pVbe->pInt10->num = 0x10; - pVbe->pInt10->ax = 0x5f01; - - xf86ExecX86int10_wrapper(pVbe->pInt10, pScrn); - if (Check5fStatus(pScrn, 0x5f01, pVbe->pInt10->ax)) { - *version = pVbe->pInt10->bx; - return TRUE; - } - - *version = 0; - return FALSE; -} - -static Bool -GetDevicePresence(ScrnInfoPtr pScrn, Bool *required, int *attached, - int *encoderPresent) -{ - vbeInfoPtr pVbe = I830PTR(pScrn)->pVbe; - - DPRINTF(PFX, "GetDevicePresence\n"); - - pVbe->pInt10->num = 0x10; - pVbe->pInt10->ax = 0x5f64; - pVbe->pInt10->bx = 0x200; - - xf86ExecX86int10_wrapper(pVbe->pInt10, pScrn); - if (Check5fStatus(pScrn, 0x5f64, pVbe->pInt10->ax)) { - if (required) - *required = ((pVbe->pInt10->bx & 0x1) == 0); - if (attached) - *attached = (pVbe->pInt10->cx >> 8) & 0xff; - if (encoderPresent) - *encoderPresent = pVbe->pInt10->cx & 0xff; - return TRUE; - } else - return FALSE; -} - -static Bool -GetDisplayInfo(ScrnInfoPtr pScrn, int device, Bool *attached, Bool *present, - short *x, short *y) -{ - vbeInfoPtr pVbe = I830PTR(pScrn)->pVbe; - - DPRINTF(PFX, "GetDisplayInfo: device: 0x%x\n", device); - - switch (device & 0xff) { - case PIPE_CRT: - case PIPE_TV: - case PIPE_DFP: - case PIPE_LFP: - case PIPE_CRT2: - case PIPE_TV2: - case PIPE_DFP2: - case PIPE_LFP2: - break; - default: - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, - "GetDisplayInfo: invalid device: 0x%x\n", device & 0xff); - return FALSE; - } - - pVbe->pInt10->num = 0x10; - pVbe->pInt10->ax = 0x5f64; - pVbe->pInt10->bx = 0x300; - pVbe->pInt10->cx = device & 0xff; - - xf86ExecX86int10_wrapper(pVbe->pInt10, pScrn); - if (Check5fStatus(pScrn, 0x5f64, pVbe->pInt10->ax)) { - if (attached) - *attached = ((pVbe->pInt10->bx & 0x2) != 0); - if (present) - *present = ((pVbe->pInt10->bx & 0x1) != 0); - if (pVbe->pInt10->cx != (device & 0xff)) { - if (y) { - *y = pVbe->pInt10->cx & 0xffff; - } - if (x) { - *x = (pVbe->pInt10->cx >> 16) & 0xffff; - } - } - return TRUE; - } else - return FALSE; -} - -/* - * Returns a string matching the device corresponding to the first bit set - * in "device". savedDevice is then set to device with that bit cleared. - * Subsequent calls with device == -1 will use savedDevice. - */ - -static const char *displayDevices[] = { - "CRT", - "TV", - "DFP (digital flat panel)", - "LFP (local flat panel)", - "Second (second CRT)", - "TV2 (second TV)", - "DFP2 (second digital flat panel)", - "LFP2 (second local flat panel)", - NULL -}; - -static const char * -DeviceToString(int device) -{ - static int savedDevice = -1; - int bit = 0; - const char *name; - - if (device == -1) { - device = savedDevice; - bit = 0; - } - - if (device == -1) - return NULL; - - while (displayDevices[bit]) { - if (device & (1 << bit)) { - name = displayDevices[bit]; - savedDevice = device & ~(1 << bit); - bit++; - return name; - } - bit++; - } - return NULL; -} - -static void -PrintDisplayDeviceInfo(ScrnInfoPtr pScrn) -{ - I830Ptr pI830 = I830PTR(pScrn); - int pipe, n; - int displays; - - DPRINTF(PFX, "PrintDisplayDeviceInfo\n"); - - displays = pI830->operatingDevices; - if (displays == -1) { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "No active display devices.\n"); - return; - } - - /* Check for active devices connected to each display pipe. */ - for (n = 0; n < pI830->availablePipes; n++) { - pipe = ((displays >> PIPE_SHIFT(n)) & PIPE_ACTIVE_MASK); - if (pipe) { - const char *name; - - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Currently active displays on Pipe %c:\n", PIPE_NAME(n)); - name = DeviceToString(pipe); - do { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "\t%s\n", name); - name = DeviceToString(-1); - } while (name); - - } else { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "No active displays on Pipe %c.\n", PIPE_NAME(n)); - } - - if (pI830->pipeDisplaySize[n].x2 != 0) { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Lowest common panel size for pipe %c is %d x %d\n", - PIPE_NAME(n), pI830->pipeDisplaySize[n].x2, - pI830->pipeDisplaySize[n].y2); - } else if (pI830->pipeEnabled[n] && pipe & ~PIPE_CRT_ACTIVE) { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "No display size information available for pipe %c.\n", - PIPE_NAME(n)); - } - } -} - -static void -GetPipeSizes(ScrnInfoPtr pScrn) -{ - I830Ptr pI830 = I830PTR(pScrn); - int pipe, n; - DisplayType i; - - DPRINTF(PFX, "GetPipeSizes\n"); - - - for (n = 0; n < pI830->availablePipes; n++) { - pipe = (pI830->operatingDevices >> PIPE_SHIFT(n)) & PIPE_ACTIVE_MASK; - pI830->pipeDisplaySize[n].x1 = pI830->pipeDisplaySize[n].y1 = 0; - pI830->pipeDisplaySize[n].x2 = pI830->pipeDisplaySize[n].y2 = 4096; - for (i = 0; i < NumDisplayTypes; i++) { - if (pipe & (1 << i) & PIPE_SIZED_DISP_MASK) { - if (pI830->displaySize[i].x2 != 0) { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Size of device %s is %d x %d\n", - displayDevices[i], - pI830->displaySize[i].x2, - pI830->displaySize[i].y2); - if (pI830->displaySize[i].x2 < pI830->pipeDisplaySize[n].x2) - pI830->pipeDisplaySize[n].x2 = pI830->displaySize[i].x2; - if (pI830->displaySize[i].y2 < pI830->pipeDisplaySize[n].y2) - pI830->pipeDisplaySize[n].y2 = pI830->displaySize[i].y2; - } - } - } - - if (pI830->pipeDisplaySize[n].x2 == 4096) - pI830->pipeDisplaySize[n].x2 = 0; - if (pI830->pipeDisplaySize[n].y2 == 4096) - pI830->pipeDisplaySize[n].y2 = 0; - } -} - -static Bool -I830DetectDisplayDevice(ScrnInfoPtr pScrn) -{ - I830Ptr pI830 = I830PTR(pScrn); - int pipe, n; - DisplayType i; - - /* This seems to lockup some Dell BIOS'. So it's on option to turn on */ - if (pI830->displayInfo) { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Broken BIOSes cause the system to hang here.\n" - "\t If you encounter this problem please add \n" - "\t\t Option \"DisplayInfo\" \"FALSE\"\n" - "\t to the Device section of your XF86Config file.\n"); - for (i = 0; i < NumDisplayTypes; i++) { - if (GetDisplayInfo(pScrn, 1 << i, &pI830->displayAttached[i], - &pI830->displayPresent[i], - &pI830->displaySize[i].x2, - &pI830->displaySize[i].y2)) { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Display Info: %s: attached: %s, present: %s, size: " - "(%d,%d)\n", displayDevices[i], - BOOLTOSTRING(pI830->displayAttached[i]), - BOOLTOSTRING(pI830->displayPresent[i]), - pI830->displaySize[i].x2, pI830->displaySize[i].y2); - } - } - } - - /* Check for active devices connected to each display pipe. */ - for (n = 0; n < pI830->availablePipes; n++) { - pipe = ((pI830->operatingDevices >> PIPE_SHIFT(n)) & PIPE_ACTIVE_MASK); - if (pipe) - pI830->pipeEnabled[n] = TRUE; - else - pI830->pipeEnabled[n] = FALSE; - } - - GetPipeSizes(pScrn); - - return TRUE; -} - static int I830DetectMemory(ScrnInfoPtr pScrn) { @@ -3105,16 +398,16 @@ I830DetectMemory(ScrnInfoPtr pScrn) CARD16 gmch_ctrl; int memsize = 0; int range; +#if 0 + VbeInfoBlock *vbeInfo; +#endif bridge = pciTag(0, 0, 0); /* This is always the host bridge */ gmch_ctrl = pciReadWord(bridge, I830_GMCH_CTRL); /* We need to reduce the stolen size, by the GTT and the popup. - * The GTT varying according the the FbMapSize and the popup is 4KB. */ - if (IS_I965G(pI830)) - range = 512 + 4; /* Fixed 512KB size for i965 */ - else - range = (pI830->FbMapSize / MB(1)) + 4; + * The GTT varying according the the FbMapSize and the popup is 4KB */ + range = (pI830->FbMapSize / (1024*1024)) + 4; if (IS_I85X(pI830) || IS_I865G(pI830) || IS_I9XX(pI830)) { switch (gmch_ctrl & I830_GMCH_GMS_MASK) { @@ -3172,6 +465,7 @@ I830DetectMemory(ScrnInfoPtr pScrn) } else { xf86DrvMsg(pScrn->scrnIndex, X_INFO, "no video memory detected.\n"); } + return memsize; } @@ -3241,293 +535,6 @@ I830UnmapMem(ScrnInfoPtr pScrn) return TRUE; } -#ifndef HAVE_GET_PUT_BIOSMEMSIZE -#define HAVE_GET_PUT_BIOSMEMSIZE 1 -#endif - -#if HAVE_GET_PUT_BIOSMEMSIZE -/* - * Tell the BIOS how much video memory is available. The BIOS call used - * here won't always be available. - */ -static Bool -PutBIOSMemSize(ScrnInfoPtr pScrn, int memSize) -{ - vbeInfoPtr pVbe = I830PTR(pScrn)->pVbe; - - DPRINTF(PFX, "PutBIOSMemSize: %d kB\n", memSize / 1024); - - pVbe->pInt10->num = 0x10; - pVbe->pInt10->ax = 0x5f11; - pVbe->pInt10->bx = 0; - pVbe->pInt10->cx = memSize / GTT_PAGE_SIZE; - - xf86ExecX86int10_wrapper(pVbe->pInt10, pScrn); - return Check5fStatus(pScrn, 0x5f11, pVbe->pInt10->ax); -} - -/* - * This reports what the previous VBEGetVBEInfo() found. Be sure to call - * VBEGetVBEInfo() after changing the BIOS memory size view. If - * a separate BIOS call is added for this, it can be put here. Only - * return a valid value if the funtionality for PutBIOSMemSize() - * is available. - */ -static int -GetBIOSMemSize(ScrnInfoPtr pScrn) -{ - I830Ptr pI830 = I830PTR(pScrn); - int memSize = KB(pI830->vbeInfo->TotalMemory * 64); - - DPRINTF(PFX, "GetBIOSMemSize\n"); - - if (PutBIOSMemSize(pScrn, memSize)) - return memSize; - else - return -1; -} -#endif - -/* - * These three functions allow the video BIOS's view of the available video - * memory to be changed. This is currently implemented only for the 830 - * and 845G, which can do this via a BIOS scratch register that holds the - * BIOS's view of the (pre-reserved) memory size. If another mechanism - * is available in the future, it can be plugged in here. - * - * The mapping used for the 830/845G scratch register's low 4 bits is: - * - * 320k => 0 - * 832k => 1 - * 8000k => 8 - * - * The "unusual" values are the 512k, 1M, 8M pre-reserved memory, less - * overhead, rounded down to the BIOS-reported 64k granularity. - */ - -static Bool -SaveBIOSMemSize(ScrnInfoPtr pScrn) -{ - I830Ptr pI830 = I830PTR(pScrn); - - DPRINTF(PFX, "SaveBIOSMemSize\n"); - - if (!I830IsPrimary(pScrn)) - return FALSE; - - pI830->useSWF1 = FALSE; - -#if HAVE_GET_PUT_BIOSMEMSIZE - if ((pI830->saveBIOSMemSize = GetBIOSMemSize(pScrn)) != -1) - return TRUE; -#endif - - if (IS_I830(pI830) || IS_845G(pI830)) { - pI830->useSWF1 = TRUE; - pI830->saveSWF1 = INREG(SWF1) & 0x0f; - - /* - * This is for sample purposes only. pI830->saveBIOSMemSize isn't used - * when pI830->useSWF1 is TRUE. - */ - switch (pI830->saveSWF1) { - case 0: - pI830->saveBIOSMemSize = KB(320); - break; - case 1: - pI830->saveBIOSMemSize = KB(832); - break; - case 8: - pI830->saveBIOSMemSize = KB(8000); - break; - default: - pI830->saveBIOSMemSize = 0; - break; - } - return TRUE; - } - return FALSE; -} - -/* - * TweakMemorySize() tweaks the BIOS image to set the correct size. - * Original implementation by Christian Zietz in a stand-alone tool. - */ -static CARD32 -TweakMemorySize(ScrnInfoPtr pScrn, CARD32 newsize, Bool preinit) -{ -#define SIZE 0x10000 -#define _855_IDOFFSET (-23) -#define _845_IDOFFSET (-19) - - const char *MAGICstring = "Total time for VGA POST:"; - const int len = strlen(MAGICstring); - I830Ptr pI830 = I830PTR(pScrn); - volatile char *position; - char *biosAddr; - CARD32 oldsize; - CARD32 oldpermission; - CARD32 ret = 0; - int i,j = 0; - int reg = (IS_845G(pI830) || IS_I865G(pI830)) ? _845_DRAM_RW_CONTROL - : _855_DRAM_RW_CONTROL; - - PCITAG tag =pciTag(0,0,0); - - if (!I830IsPrimary(pScrn)) - return 0; - - if(!pI830->PciInfo - || !(IS_845G(pI830) || IS_I85X(pI830) || IS_I865G(pI830))) - return 0; - - if (!pI830->pVbe) - return 0; - - biosAddr = xf86int10Addr(pI830->pVbe->pInt10, - pI830->pVbe->pInt10->BIOSseg << 4); - - if (!pI830->BIOSMemSizeLoc) { - if (!preinit) - return 0; - - /* Search for MAGIC string */ - for (i = 0; i < SIZE; i++) { - if (biosAddr[i] == MAGICstring[j]) { - if (++j == len) - break; - } else { - i -= j; - j = 0; - } - } - if (j < len) return 0; - - pI830->BIOSMemSizeLoc = (i - j + 1 + (IS_845G(pI830) - ? _845_IDOFFSET : _855_IDOFFSET)); - } - - position = biosAddr + pI830->BIOSMemSizeLoc; - oldsize = *(CARD32 *)position; - - ret = oldsize - 0x21000; - - /* verify that register really contains current size */ - if (preinit && ((ret >> 16) != pI830->vbeInfo->TotalMemory)) - return 0; - - oldpermission = pciReadLong(tag, reg); - pciWriteLong(tag, reg, DRAM_WRITE | (oldpermission & 0xffff)); - - *(CARD32 *)position = newsize + 0x21000; - - if (preinit) { - /* reinitialize VBE for new size */ - if (I830IsPrimary(pScrn)) { - VBEFreeVBEInfo(pI830->vbeInfo); - vbeFree(pI830->pVbe); - pI830->pVbe = VBEInit(NULL, pI830->pEnt->index); - pI830->vbeInfo = VBEGetVBEInfo(pI830->pVbe); - } else { - I830Ptr pI8301 = I830PTR(pI830->entityPrivate->pScrn_1); - pI830->pVbe = pI8301->pVbe; - pI830->vbeInfo = pI8301->vbeInfo; - } - - /* verify that change was successful */ - if (pI830->vbeInfo->TotalMemory != (newsize >> 16)){ - ret = 0; - *(CARD32 *)position = oldsize; - } else { - pI830->BIOSMemorySize = KB(pI830->vbeInfo->TotalMemory * 64); - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Tweak BIOS image to %d kB VideoRAM\n", - (int)(pI830->BIOSMemorySize / 1024)); - } - } - - pciWriteLong(tag, reg, oldpermission); - - return ret; -} - -static void -RestoreBIOSMemSize(ScrnInfoPtr pScrn) -{ - I830Ptr pI830 = I830PTR(pScrn); - CARD32 swf1; - - DPRINTF(PFX, "RestoreBIOSMemSize\n"); - - if (!I830IsPrimary(pScrn)) - return; - - if (TweakMemorySize(pScrn, pI830->saveBIOSMemSize,FALSE)) - return; - - if (!pI830->overrideBIOSMemSize) - return; - -#if HAVE_GET_PUT_BIOSMEMSIZE - if (!pI830->useSWF1) { - PutBIOSMemSize(pScrn, pI830->saveBIOSMemSize); - return; - } -#endif - - if ((IS_I830(pI830) || IS_845G(pI830)) && pI830->useSWF1) { - swf1 = INREG(SWF1); - swf1 &= ~0x0f; - swf1 |= (pI830->saveSWF1 & 0x0f); - OUTREG(SWF1, swf1); - } -} - -static void -SetBIOSMemSize(ScrnInfoPtr pScrn, int newSize) -{ - I830Ptr pI830 = I830PTR(pScrn); - unsigned long swf1; - Bool mapped; - - DPRINTF(PFX, "SetBIOSMemSize: %d kB\n", newSize / 1024); - - if (!pI830->overrideBIOSMemSize) - return; - -#if HAVE_GET_PUT_BIOSMEMSIZE - if (!pI830->useSWF1) { - PutBIOSMemSize(pScrn, newSize); - return; - } -#endif - - if ((IS_I830(pI830) || IS_845G(pI830)) && pI830->useSWF1) { - unsigned long newSWF1; - - /* Need MMIO access here. */ - mapped = (pI830->MMIOBase != NULL); - if (!mapped) - I830MapMMIO(pScrn); - - if (newSize <= KB(832)) - newSWF1 = 1; - else - newSWF1 = 8; - - swf1 = INREG(SWF1); - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Before: SWF1 is 0x%08lx\n", swf1); - swf1 &= ~0x0f; - swf1 |= (newSWF1 & 0x0f); - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "After: SWF1 is 0x%08lx\n", swf1); - OUTREG(SWF1, swf1); - if (!mapped) - I830UnmapMMIO(pScrn); - } -} - -static CARD32 val8[256]; - static void I830LoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices, LOCO * colors, VisualPtr pVisual) @@ -3538,34 +545,46 @@ I830LoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices, CARD32 val, temp; int palreg; int dspreg, dspbase, dspsurf; + int p; DPRINTF(PFX, "I830LoadPalette: numColors: %d\n", numColors); pI830 = I830PTR(pScrn); - if (pI830->Clone || pI830->MergedFB) { - if (!pI830->pipe == 0) { + for(p=0; p < pI830->num_pipes; p++) { + I830PipePtr pI830Pipe = &pI830->pipes[p]; + + if (p == 0) { palreg = PALETTE_A; dspreg = DSPACNTR; dspbase = DSPABASE; + dspsurf = DSPASURF; } else { palreg = PALETTE_B; dspreg = DSPBCNTR; dspbase = DSPBBASE; + dspsurf = DSPBSURF; } - + + if (pI830Pipe->enabled == 0) + continue; + + pI830Pipe->gammaEnabled = 1; + /* To ensure gamma is enabled we need to turn off and on the plane */ temp = INREG(dspreg); OUTREG(dspreg, temp & ~(1<<31)); OUTREG(dspbase, INREG(dspbase)); OUTREG(dspreg, temp | DISPPLANE_GAMMA_ENABLE); OUTREG(dspbase, INREG(dspbase)); + if (IS_I965G(pI830)) + OUTREG(dspsurf, INREG(dspsurf)); /* It seems that an initial read is needed. */ temp = INREG(palreg); switch(pScrn->depth) { case 15: - for (i = 0; i < numColors; i++) { + for (i = 0; i < numColors; i++) { index = indices[i]; r = colors[index].red; g = colors[index].green; @@ -3574,209 +593,109 @@ I830LoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices, for (j = 0; j < 8; j++) { OUTREG(palreg + index * 32 + (j * 4), val); } - } - break; - case 16: - for (i = 0; i < numColors; i++) { - index = indices[i]; - r = colors[index / 2].red; - g = colors[index].green; - b = colors[index / 2].blue; - - val = (r << 16) | (g << 8) | b; - OUTREG(palreg + index * 16, val); - OUTREG(palreg + index * 16 + 4, val); - OUTREG(palreg + index * 16 + 8, val); - OUTREG(palreg + index * 16 + 12, val); - - if (index <= 31) { - r = colors[index].red; - g = colors[(index * 2) + 1].green; - b = colors[index].blue; - - val = (r << 16) | (g << 8) | b; - OUTREG(palreg + index * 32, val); - OUTREG(palreg + index * 32 + 4, val); - OUTREG(palreg + index * 32 + 8, val); - OUTREG(palreg + index * 32 + 12, val); - } - } - break; - default: - for(i = 0; i < numColors; i++) { - index = indices[i]; - r = colors[index].red; - g = colors[index].green; - b = colors[index].blue; - val = (r << 16) | (g << 8) | b; - OUTREG(palreg + index * 4, val); - } - break; - } - } - - if (pI830->pipe == 0) { - palreg = PALETTE_A; - dspreg = DSPACNTR; - dspbase = DSPABASE; - dspsurf = DSPASURF; - } else { - palreg = PALETTE_B; - dspreg = DSPBCNTR; - dspbase = DSPBBASE; - dspsurf = DSPBSURF; - } - - /* To ensure gamma is enabled we need to turn off and on the plane */ - temp = INREG(dspreg); - OUTREG(dspreg, temp & ~(1<<31)); - OUTREG(dspbase, INREG(dspbase)); - OUTREG(dspreg, temp | DISPPLANE_GAMMA_ENABLE); - OUTREG(dspbase, INREG(dspbase)); - if (IS_I965G(pI830)) - OUTREG(dspsurf, INREG(dspsurf)); - - /* It seems that an initial read is needed. */ - temp = INREG(palreg); - - switch(pScrn->depth) { - case 15: - for (i = 0; i < numColors; i++) { - index = indices[i]; - r = colors[index].red; - g = colors[index].green; - b = colors[index].blue; - val = (r << 16) | (g << 8) | b; - for (j = 0; j < 8; j++) { - OUTREG(palreg + index * 32 + (j * 4), val); - } - } - break; - case 16: - for (i = 0; i < numColors; i++) { - index = indices[i]; - r = colors[index / 2].red; - g = colors[index].green; - b = colors[index / 2].blue; - - val = (r << 16) | (g << 8) | b; - OUTREG(palreg + index * 16, val); - OUTREG(palreg + index * 16 + 4, val); - OUTREG(palreg + index * 16 + 8, val); - OUTREG(palreg + index * 16 + 12, val); - - if (index <= 31) { - r = colors[index].red; - g = colors[(index * 2) + 1].green; - b = colors[index].blue; - - val = (r << 16) | (g << 8) | b; - OUTREG(palreg + index * 32, val); - OUTREG(palreg + index * 32 + 4, val); - OUTREG(palreg + index * 32 + 8, val); - OUTREG(palreg + index * 32 + 12, val); - } - } - break; - default: -#if 1 - /* Dual head 8bpp modes seem to squish the primary's cmap - reload */ - if (I830IsPrimary(pScrn) && xf86IsEntityShared(pScrn->entityList[0]) && - pScrn->depth == 8) { - for(i = 0; i < numColors; i++) { - index = indices[i]; - r = colors[index].red; - g = colors[index].green; - b = colors[index].blue; - val8[index] = (r << 16) | (g << 8) | b; } - } -#endif - for(i = 0; i < numColors; i++) { + break; + case 16: + for (i = 0; i < numColors; i++) { + index = indices[i]; + r = colors[index / 2].red; + g = colors[index].green; + b = colors[index / 2].blue; + + val = (r << 16) | (g << 8) | b; + OUTREG(palreg + index * 16, val); + OUTREG(palreg + index * 16 + 4, val); + OUTREG(palreg + index * 16 + 8, val); + OUTREG(palreg + index * 16 + 12, val); + + if (index <= 31) { + r = colors[index].red; + g = colors[(index * 2) + 1].green; + b = colors[index].blue; + + val = (r << 16) | (g << 8) | b; + OUTREG(palreg + index * 32, val); + OUTREG(palreg + index * 32 + 4, val); + OUTREG(palreg + index * 32 + 8, val); + OUTREG(palreg + index * 32 + 12, val); + } + } + break; + default: + for(i = 0; i < numColors; i++) { index = indices[i]; r = colors[index].red; g = colors[index].green; b = colors[index].blue; val = (r << 16) | (g << 8) | b; OUTREG(palreg + index * 4, val); -#if 1 - /* Dual head 8bpp modes seem to squish the primary's cmap - reload */ - if (!I830IsPrimary(pScrn) && xf86IsEntityShared(pScrn->entityList[0]) && - pScrn->depth == 8) { - if (palreg == PALETTE_A) - OUTREG(PALETTE_B + index * 4, val8[index]); - else - OUTREG(PALETTE_A + index * 4, val8[index]); - } -#endif - } - break; + } + break; + } + } + + /* Enable gamma for Cursor if ARGB */ + if (pI830->CursorInfoRec && !pI830->SWCursor && pI830->cursorOn) + pI830->CursorInfoRec->ShowCursor(pScrn); +} + +/** + * Set up the outputs according to what type of chip we are. + * + * Some outputs may not initialize, due to allocation failure or because a + * controller chip isn't found. + */ +static void +I830SetupOutputs(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + + /* everyone has at least a single analog output */ + i830_crt_init(pScrn); + + /* Set up integrated LVDS */ + if (IS_MOBILE(pI830) && !IS_I830(pI830)) + i830_lvds_init(pScrn); + + if (IS_I9XX(pI830)) { + i830_sdvo_init(pScrn, SDVOB); + + /* Don't initialize the second SDVO port for now. We have issues with + * dealing with two ports, where we stomp both SDVO channels' registers + * when interacting with each, channel, and commands to one SDVO + * device appear to be affecting the other. + */ + /* i830_sdvo_init(pScrn, SDVOC); */ + } else { + i830_dvo_init(pScrn); } } -static int -I830UseDDC(ScrnInfoPtr pScrn) +static void +I830PreInitDDC(ScrnInfoPtr pScrn) { - xf86MonPtr DDC = (xf86MonPtr)(pScrn->monitor->DDC); - struct detailed_monitor_section* detMon; - struct monitor_ranges *mon_range = NULL; - int i; + I830Ptr pI830 = I830PTR(pScrn); - if (!DDC) return 0; - - /* Now change the hsync/vrefresh values of the current monitor to - * match those of DDC */ - for (i = 0; i < 4; i++) { - detMon = &DDC->det_mon[i]; - if(detMon->type == DS_RANGES) - mon_range = &detMon->section.ranges; + if (!xf86LoadSubModule(pScrn, "ddc")) { + pI830->ddc2 = FALSE; + } else { + xf86LoaderReqSymLists(I810ddcSymbols, NULL); + pI830->ddc2 = TRUE; } - if (!mon_range || mon_range->min_h == 0 || mon_range->max_h == 0 || - mon_range->min_v == 0 || mon_range->max_v == 0) - return 0; /* bad ddc */ + /* DDC can use I2C bus */ + /* Load I2C if we have the code to use it */ + if (pI830->ddc2) { + if (xf86LoadSubModule(pScrn, "i2c")) { + xf86LoaderReqSymLists(I810i2cSymbols, NULL); - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Using detected DDC timings\n"); - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "\tHorizSync %d-%d\n", - mon_range->min_h, mon_range->max_h); - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "\tVertRefresh %d-%d\n", - mon_range->min_v, mon_range->max_v); -#define DDC_SYNC_TOLERANCE SYNC_TOLERANCE - if (pScrn->monitor->nHsync > 0) { - for (i = 0; i < pScrn->monitor->nHsync; i++) { - if ((1.0 - DDC_SYNC_TOLERANCE) * mon_range->min_h > - pScrn->monitor->hsync[i].lo || - (1.0 + DDC_SYNC_TOLERANCE) * mon_range->max_h < - pScrn->monitor->hsync[i].hi) { - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "config file hsync range %g-%gkHz not within DDC " - "hsync range %d-%dkHz\n", - pScrn->monitor->hsync[i].lo, pScrn->monitor->hsync[i].hi, - mon_range->min_h, mon_range->max_h); - } - pScrn->monitor->hsync[i].lo = mon_range->min_h; - pScrn->monitor->hsync[i].hi = mon_range->max_h; + I830SetupOutputs(pScrn); + + pI830->ddc2 = TRUE; + } else { + pI830->ddc2 = FALSE; } } - - if (pScrn->monitor->nVrefresh > 0) { - for (i=0; imonitor->nVrefresh; i++) { - if ((1.0 - DDC_SYNC_TOLERANCE) * mon_range->min_v > - pScrn->monitor->vrefresh[i].lo || - (1.0 + DDC_SYNC_TOLERANCE) * mon_range->max_v < - pScrn->monitor->vrefresh[i].hi) { - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "config file vrefresh range %g-%gHz not within DDC " - "vrefresh range %d-%dHz\n", - pScrn->monitor->vrefresh[i].lo, pScrn->monitor->vrefresh[i].hi, - mon_range->min_v, mon_range->max_v); - } - pScrn->monitor->vrefresh[i].lo = mon_range->min_v; - pScrn->monitor->vrefresh[i].hi = mon_range->max_v; - } - } - - return mon_range->max_clock; } static void @@ -3785,8 +704,6 @@ PreInitCleanup(ScrnInfoPtr pScrn) I830Ptr pI830 = I830PTR(pScrn); if (I830IsPrimary(pScrn)) { - SetPipeAccess(pScrn); - pI830->entityPrivate->pScrn_1 = NULL; if (pI830->LpRing) xfree(pI830->LpRing); @@ -3810,14 +727,13 @@ PreInitCleanup(ScrnInfoPtr pScrn) if (pI830->entityPrivate) pI830->entityPrivate->pScrn_2 = NULL; } - RestoreBIOSMemSize(pScrn); if (pI830->swfSaved) { OUTREG(SWF0, pI830->saveSWF0); OUTREG(SWF4, pI830->saveSWF4); } if (pI830->MMIOBase) I830UnmapMMIO(pScrn); - I830BIOSFreeRec(pScrn); + I830FreeRec(pScrn); } Bool @@ -3833,6 +749,31 @@ I830IsPrimary(ScrnInfoPtr pScrn) return TRUE; } +#define HOTKEY_BIOS_SWITCH 0 +#define HOTKEY_DRIVER_NOTIFY 1 + +/** + * Controls the BIOS's behavior on hotkey switch. + * + * If the mode is HOTKEY_BIOS_SWITCH, the BIOS will be set to do a mode switch + * on its own and update the state in the scratch register. + * If the mode is HOTKEY_DRIVER_NOTIFY, the BIOS won't do a mode switch and + * will just update the state to represent what it would have been switched to. + */ +static void +i830SetHotkeyControl(ScrnInfoPtr pScrn, int mode) +{ + I830Ptr pI830 = I830PTR(pScrn); + CARD8 gr18; + + gr18 = pI830->readControl(pI830, GRX, 0x18); + if (mode == HOTKEY_BIOS_SWITCH) + gr18 &= ~HOTKEY_VBIOS_SWITCH_BLOCK; + else + gr18 |= HOTKEY_VBIOS_SWITCH_BLOCK; + pI830->writeControl(pI830, GRX, 0x18, gr18); +} + #ifdef XF86DRI static void I830ReduceMMSize(ScrnInfoPtr pScrn, unsigned long newSize, @@ -3854,9 +795,8 @@ I830ReduceMMSize(ScrnInfoPtr pScrn, unsigned long newSize, } #endif - static Bool -I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) +I830PreInit(ScrnInfoPtr pScrn, int flags) { vgaHWPtr hwp; I830Ptr pI830; @@ -3864,19 +804,14 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) rgb defaultWeight = { 0, 0, 0 }; EntityInfoPtr pEnt; I830EntPtr pI830Ent = NULL; - int mem, memsize; + int mem; int flags24; - int defmon = 0; - int i, n; - int DDCclock = 0, DDCclock2 = 0; + int i; char *s; - DisplayModePtr p, pMon; - xf86MonPtr monitor = NULL; - pointer pDDCModule = NULL, pVBEModule = NULL; + pointer pVBEModule = NULL; Bool enable; const char *chipname; - unsigned int ver; - char v[5]; + int mem_skip; #ifdef XF86DRI unsigned long savedMMSize; #endif @@ -3897,7 +832,7 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) pEnt = xf86GetEntityInfo(pScrn->entityList[0]); if (flags & PROBE_DETECT) { - I830BIOSProbeDDC(pScrn, pEnt->index); + I830ProbeDDC(pScrn, pEnt->index); return TRUE; } @@ -3911,7 +846,7 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) return FALSE; /* Allocate driverPrivate */ - if (!I830BIOSGetRec(pScrn)) + if (!I830GetRec(pScrn)) return FALSE; pI830 = I830PTR(pScrn); @@ -4000,25 +935,14 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) /* Process the options */ xf86CollectOptions(pScrn, NULL); - if (!(pI830->Options = xalloc(sizeof(I830BIOSOptions)))) + if (!(pI830->Options = xalloc(sizeof(I830Options)))) return FALSE; - memcpy(pI830->Options, I830BIOSOptions, sizeof(I830BIOSOptions)); + memcpy(pI830->Options, I830Options, sizeof(I830Options)); xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, pI830->Options); /* We have to use PIO to probe, because we haven't mapped yet. */ I830SetPIOAccess(pI830); - /* Initialize VBE record */ - if (I830IsPrimary(pScrn)) { - if ((pI830->pVbe = VBEInit(NULL, pI830->pEnt->index)) == NULL) { - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "VBE initialization failed.\n"); - return FALSE; - } - } else { - I830Ptr pI8301 = I830PTR(pI830->entityPrivate->pScrn_1); - pI830->pVbe = pI8301->pVbe; - } - switch (pI830->PciInfo->chipType) { case PCI_CHIP_I830_M: chipname = "830M"; @@ -4088,19 +1012,12 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Integrated Graphics Chipset: Intel(R) %s\n", chipname); - if (I830IsPrimary(pScrn)) { - pI830->vbeInfo = VBEGetVBEInfo(pI830->pVbe); - } else { - I830Ptr pI8301 = I830PTR(pI830->entityPrivate->pScrn_1); - pI830->vbeInfo = pI8301->vbeInfo; - } - /* Set the Chipset and ChipRev, allowing config file entries to override. */ if (pI830->pEnt->device->chipset && *pI830->pEnt->device->chipset) { pScrn->chipset = pI830->pEnt->device->chipset; from = X_CONFIG; } else if (pI830->pEnt->device->chipID >= 0) { - pScrn->chipset = (char *)xf86TokenToString(I830BIOSChipsets, + pScrn->chipset = (char *)xf86TokenToString(I830Chipsets, pI830->pEnt->device->chipID); from = X_CONFIG; xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipID override: 0x%04X\n", @@ -4108,7 +1025,7 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) pI830->PciInfo->chipType = pI830->pEnt->device->chipID; } else { from = X_PROBED; - pScrn->chipset = (char *)xf86TokenToString(I830BIOSChipsets, + pScrn->chipset = (char *)xf86TokenToString(I830Chipsets, pI830->PciInfo->chipType); } @@ -4201,31 +1118,29 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) } if (pI830->PciInfo->chipType == PCI_CHIP_E7221_G) - pI830->availablePipes = 1; + pI830->num_pipes = 1; else if (IS_MOBILE(pI830) || IS_I9XX(pI830)) - pI830->availablePipes = 2; + pI830->num_pipes = 2; else - pI830->availablePipes = 1; + pI830->num_pipes = 1; xf86DrvMsg(pScrn->scrnIndex, X_INFO, "%d display pipe%s available.\n", - pI830->availablePipes, pI830->availablePipes > 1 ? "s" : ""); + pI830->num_pipes, pI830->num_pipes > 1 ? "s" : ""); /* * Get the pre-allocated (stolen) memory size. */ - pI830->StolenMemory.Size = I830DetectMemory(pScrn); - pI830->StolenMemory.Start = 0; + + mem_skip = 0; + + /* On 965, it looks like the GATT table is inside the aperture? */ + if (IS_I965G(pI830)) + mem_skip = pI830->FbMapSize >> 10; + + pI830->StolenMemory.Size = I830DetectMemory(pScrn) - mem_skip; + pI830->StolenMemory.Start = mem_skip; pI830->StolenMemory.End = pI830->StolenMemory.Size; - /* Sanity check: compare with what the BIOS thinks. */ - if (pI830->vbeInfo->TotalMemory != pI830->StolenMemory.Size / 1024 / 64) { - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "Detected stolen memory (%ld kB) doesn't match what the BIOS" - " reports (%d kB)\n", - ROUND_DOWN_TO(pI830->StolenMemory.Size / 1024, 64), - pI830->vbeInfo->TotalMemory * 64); - } - /* Find the maximum amount of agpgart memory available. */ if (I830IsPrimary(pScrn)) { mem = I830CheckAvailableMemory(pScrn); @@ -4318,35 +1233,21 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) #endif pI830->LinearAlloc = 0; - if (xf86GetOptValInteger(pI830->Options, OPTION_LINEARALLOC, + if (xf86GetOptValULong(pI830->Options, OPTION_LINEARALLOC, &(pI830->LinearAlloc))) { if (pI830->LinearAlloc > 0) - xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Allocating %dKbytes of memory\n", + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Allocating %luKbytes of memory\n", pI830->LinearAlloc); else pI830->LinearAlloc = 0; } - pI830->fixedPipe = -1; - if ((s = xf86GetOptValString(pI830->Options, OPTION_FIXEDPIPE)) && - I830IsPrimary(pScrn)) { - - if (strstr(s, "A") || strstr(s, "a") || strstr(s, "0")) - pI830->fixedPipe = 0; - else if (strstr(s, "B") || strstr(s, "b") || strstr(s, "1")) - pI830->fixedPipe = 1; - } - - pI830->MergedFB = - xf86ReturnOptValBool(pI830->Options, OPTION_MERGEDFB, FALSE); - - pI830->IntelXinerama = - xf86ReturnOptValBool(pI830->Options, OPTION_INTELXINERAMA, TRUE); - - pI830->MonType1 = PIPE_NONE; - pI830->MonType2 = PIPE_NONE; - pI830->specifiedMonitor = FALSE; + I830PreInitDDC(pScrn); +#if 0 + /* + * This moves to generic RandR-based configuration code + */ if ((s = xf86GetOptValString(pI830->Options, OPTION_MONITOR_LAYOUT)) && I830IsPrimary(pScrn)) { char *Mon1; @@ -4414,7 +1315,7 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) } while (sub); } - if (pI830->availablePipes == 1 && pI830->MonType2 != PIPE_NONE) { + if (pI830->num_pipes == 1 && pI830->MonType2 != PIPE_NONE) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Monitor 2 cannot be specified on single pipe devices\n"); return FALSE; @@ -4426,12 +1327,72 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) return FALSE; } - pI830->specifiedMonitor = TRUE; - } + if (pI830->MonType1 != PIPE_NONE) + pI830->pipe = 0; + else + pI830->pipe = 1; - if (!pI830->MergedFB && - xf86ReturnOptValBool(pI830->Options, OPTION_CLONE, FALSE)) { - if (pI830->availablePipes == 1) { + } else if (I830IsPrimary(pScrn)) { + /* Choose a default set of outputs to use based on what we've detected. + * + * Assume that SDVO outputs are flat panels for now. It's just a name + * at the moment, since we don't treat different SDVO outputs + * differently. + */ + for (i = 0; i < pI830->num_outputs; i++) { + if (pI830->output[i].type == I830_OUTPUT_LVDS) + pI830->MonType2 = PIPE_LFP; + + if (pI830->output[i].type == I830_OUTPUT_SDVO || + pI830->output[i].type == I830_OUTPUT_ANALOG) + { + int pipetype; + + if (pI830->output[i].detect(pScrn, &pI830->output[i]) == + OUTPUT_STATUS_DISCONNECTED) + { + continue; + } + + if (pI830->output[i].type == I830_OUTPUT_SDVO) + pipetype = PIPE_DFP; + else + pipetype = PIPE_CRT; + + if (pI830->MonType1 == PIPE_NONE) + pI830->MonType1 |= pipetype; + else if (pI830->MonType2 == PIPE_NONE) + pI830->MonType2 |= pipetype; + } + } + + /* And, if we haven't found anything (including CRT through DDC), assume + * that there's a CRT and that the user has set up some appropriate modes + * or something. + */ + if (pI830->MonType1 == PIPE_NONE && pI830->MonType2 == PIPE_NONE) + pI830->MonType1 |= PIPE_CRT; + + if (pI830->MonType1 != PIPE_NONE) + pI830->pipe = 0; + else + pI830->pipe = 1; + + if (pI830->MonType1 != 0 && pI830->MonType2 != 0) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Enabling clone mode by default\n"); + pI830->Clone = TRUE; + } + } else { + I830Ptr pI8301 = I830PTR(pI830->entityPrivate->pScrn_1); + pI830->pipe = !pI8301->pipe; + pI830->MonType1 = pI8301->MonType1; + pI830->MonType2 = pI8301->MonType2; + } +#endif + + if (xf86ReturnOptValBool(pI830->Options, OPTION_CLONE, FALSE)) { + if (pI830->num_pipes == 1) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Can't enable Clone Mode because this is a single pipe device\n"); PreInitCleanup(pScrn); @@ -4447,6 +1408,44 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) pI830->Clone = TRUE; } + + /* Perform the pipe assignment of outputs. This is a kludge until + * we have better configuration support in the generic RandR code + */ + for (i = 0; i < pI830->num_outputs; i++) { + pI830->output[i].enabled = FALSE; + + switch (pI830->output[i].type) { + case I830_OUTPUT_LVDS: + /* LVDS must live on pipe B for two-pipe devices */ + pI830->output[i].pipe = pI830->num_pipes - 1; + pI830->output[i].enabled = TRUE; + break; + case I830_OUTPUT_ANALOG: + case I830_OUTPUT_DVO: + case I830_OUTPUT_SDVO: + if (pI830->output[i].detect(pScrn, &pI830->output[i]) != + OUTPUT_STATUS_DISCONNECTED) { + if (!i830PipeInUse(pScrn, 0)) { + pI830->output[i].pipe = 0; + pI830->output[i].enabled = TRUE; + } else if (!i830PipeInUse(pScrn, 1)) { + pI830->output[i].pipe = 1; + pI830->output[i].enabled = TRUE; + } + } + break; + default: + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Unhandled output type\n"); + break; + } + } + + for (i = 0; i < pI830->num_pipes; i++) { + pI830->pipes[i].enabled = i830PipeInUse(pScrn, i); + } + +#if 0 pI830->CloneRefresh = 60; /* default to 60Hz */ if (xf86GetOptValInteger(pI830->Options, OPTION_CLONE_REFRESH, &(pI830->CloneRefresh))) { @@ -4461,22 +1460,15 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) return FALSE; } - if ((pI830->entityPrivate && I830IsPrimary(pScrn)) || pI830->Clone || - pI830->MergedFB) { - if ((!xf86GetOptValString(pI830->Options, OPTION_MONITOR_LAYOUT))) { - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "You must have a MonitorLayout " - "defined for use in a DualHead, Clone or MergedFB setup.\n"); - PreInitCleanup(pScrn); - return FALSE; - } - + if ((pI830->entityPrivate && I830IsPrimary(pScrn)) || pI830->Clone) { if (pI830->MonType1 == PIPE_NONE || pI830->MonType2 == PIPE_NONE) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Monitor 1 or Monitor 2 " - "cannot be type NONE in DualHead, Clone or MergedFB setup.\n"); + "cannot be type NONE in DualHead or Clone setup.\n"); PreInitCleanup(pScrn); return FALSE; } } +#endif pI830->rotation = RR_Rotate_0; if ((s = xf86GetOptValString(pI830->Options, OPTION_ROTATE))) { @@ -4492,7 +1484,7 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) /* * Let's setup the mobile systems to check the lid status */ - if (IS_MOBILE(pI830) && !pI830->MergedFB) { + if (IS_MOBILE(pI830)) { pI830->checkDevices = TRUE; if (!xf86ReturnOptValBool(pI830->Options, OPTION_CHECKDEVICES, TRUE)) { @@ -4583,67 +1575,6 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) pScrn->videoRam); } - if (mem > 0) { - /* - * If the reserved (BIOS accessible) memory is less than the desired - * amount, try to increase it. So far this is only implemented for - * the 845G and 830, but those details are handled in SetBIOSMemSize(). - * - * The BIOS-accessible amount is only important for setting video - * modes. The maximum amount we try to set is limited to what would - * be enough for 1920x1440 with a 2048 pitch. - * - * If ALLOCATE_ALL_BIOSMEM is enabled in i830_memory.c, all of the - * BIOS-aware memory will get allocated. If it isn't then it may - * not be, and in that case there is an assumption that the video - * BIOS won't attempt to access memory beyond what is needed for - * modes that are actually used. ALLOCATE_ALL_BIOSMEM is enabled by - * default. - */ - - /* Try to keep HW cursor and Overlay amounts separate from this. */ - int reserve = (HWCURSOR_SIZE + HWCURSOR_SIZE_ARGB + OVERLAY_SIZE) / 1024; - - if (pScrn->videoRam - reserve >= I830_MAXIMUM_VBIOS_MEM) - pI830->newBIOSMemSize = KB(I830_MAXIMUM_VBIOS_MEM); - else - pI830->newBIOSMemSize = - KB(ROUND_DOWN_TO(pScrn->videoRam - reserve, 64)); - if (pI830->vbeInfo->TotalMemory * 64 < pI830->newBIOSMemSize / 1024) { - - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Will attempt to tell the BIOS that there is " - "%d kB VideoRAM\n", pI830->newBIOSMemSize / 1024); - if (SaveBIOSMemSize(pScrn)) { - pI830->overrideBIOSMemSize = TRUE; - SetBIOSMemSize(pScrn, pI830->newBIOSMemSize); - - if (I830IsPrimary(pScrn)) { - VBEFreeVBEInfo(pI830->vbeInfo); - vbeFree(pI830->pVbe); - pI830->pVbe = VBEInit(NULL, pI830->pEnt->index); - pI830->vbeInfo = VBEGetVBEInfo(pI830->pVbe); - } else { - I830Ptr pI8301 = I830PTR(pI830->entityPrivate->pScrn_1); - pI830->pVbe = pI8301->pVbe; - pI830->vbeInfo = pI8301->vbeInfo; - } - - pI830->BIOSMemorySize = KB(pI830->vbeInfo->TotalMemory * 64); - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "BIOS now sees %ld kB VideoRAM\n", - pI830->BIOSMemorySize / 1024); - } else if ((pI830->saveBIOSMemSize - = TweakMemorySize(pScrn, pI830->newBIOSMemSize,TRUE)) != 0) - pI830->overrideBIOSMemSize = TRUE; - else { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "BIOS view of memory size can't be changed " - "(this is not an error).\n"); - } - } - } - xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Pre-allocated VideoRAM: %ld kByte\n", pI830->StolenMemory.Size / 1024); @@ -4700,80 +1631,6 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) } #endif - if (pI830->MergedFB) { - pI830->pScrn_2 = xalloc(sizeof(ScrnInfoRec)); - - if(!pI830->pScrn_2) { - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Failed to allocate memory for MergedFB mode. Disabling.\n"); - pI830->MergedFB = FALSE; - } else { - memcpy(pI830->pScrn_2, pScrn, sizeof(ScrnInfoRec)); - } - if((s = (char *)xf86GetOptValString(pI830->Options, OPTION_SECONDPOSITION))) { - int result; - int ival; - Bool valid = FALSE; - char *tempstr = xalloc(strlen(s) + 1); - result = sscanf(s, "%s %d", tempstr, &ival); - if(result >= 1) { - if(!xf86NameCmp(tempstr,"LeftOf")) { - pI830->SecondPosition = PosLeftOf; - valid = TRUE; - if(result == 2) { - if(ival < 0) pI830->FirstYOffs = -ival; - else pI830->SecondYOffs = ival; - } - pI830->SecondIsScrn0 = TRUE; - } else if(!xf86NameCmp(tempstr,"RightOf")) { - pI830->SecondPosition = PosRightOf; - valid = TRUE; - if(result == 2) { - if(ival < 0) pI830->FirstYOffs = -ival; - else pI830->SecondYOffs = ival; - } - pI830->SecondIsScrn0 = FALSE; - } else if(!xf86NameCmp(tempstr,"Above")) { - pI830->SecondPosition = PosAbove; - valid = TRUE; - if(result == 2) { - if(ival < 0) pI830->FirstXOffs = -ival; - else pI830->SecondXOffs = ival; - } - pI830->SecondIsScrn0 = FALSE; - } else if(!xf86NameCmp(tempstr,"Below")) { - pI830->SecondPosition = PosBelow; - valid = TRUE; - if(result == 2) { - if(ival < 0) pI830->FirstXOffs = -ival; - else pI830->SecondXOffs = ival; - } - pI830->SecondIsScrn0 = TRUE; - } - } - if(!valid) { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Valid parameters are: \"RightOf\", \"LeftOf\", \"Above\" or \"Below\"\n"); - } - xfree(tempstr); - } - if((s = (char *)xf86GetOptValString(pI830->Options, OPTION_METAMODES))) { - pI830->MetaModes = xalloc(strlen(s) + 1); - if(pI830->MetaModes) - memcpy(pI830->MetaModes, s, strlen(s) + 1); - } - if((s = (char *)xf86GetOptValString(pI830->Options, OPTION_SECONDHSYNC))) { - pI830->SecondHSync = xalloc(strlen(s) + 1); - if(pI830->SecondHSync) - memcpy(pI830->SecondHSync, s, strlen(s) + 1); - } - if((s = (char *)xf86GetOptValString(pI830->Options, OPTION_SECONDVREFRESH))) { - pI830->SecondVRefresh = xalloc(strlen(s) + 1); - if(pI830->SecondVRefresh) - memcpy(pI830->SecondVRefresh, s, strlen(s) + 1); - } - } - - /* * If the driver can do gamma correction, it should call xf86SetGamma() here. */ @@ -4787,148 +1644,7 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) } } - GetBIOSVersion(pScrn, &ver); - - v[0] = (ver & 0xff000000) >> 24; - v[1] = (ver & 0x00ff0000) >> 16; - v[2] = (ver & 0x0000ff00) >> 8; - v[3] = (ver & 0x000000ff) >> 0; - v[4] = 0; - - pI830->bios_version = atoi(v); - - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "BIOS Build: %d\n",pI830->bios_version); - - if (IS_I9XX(pI830)) - pI830->newPipeSwitch = TRUE; - else - if (pI830->availablePipes == 2 && pI830->bios_version >= 3062) { - /* BIOS build 3062 changed the pipe switching functionality */ - pI830->newPipeSwitch = TRUE; - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Using new Pipe switch code\n"); - } else - pI830->newPipeSwitch = FALSE; - - pI830->devicePresence = FALSE; - from = X_DEFAULT; - if (xf86ReturnOptValBool(pI830->Options, OPTION_DEVICE_PRESENCE, FALSE)) { - pI830->devicePresence = TRUE; - from = X_CONFIG; - } - xf86DrvMsg(pScrn->scrnIndex, from, "Device Presence: %s.\n", - pI830->devicePresence ? "enabled" : "disabled"); - - /* This performs an active detect of the currently attached monitors - * or, at least it's meant to..... alas it doesn't seem to always work. - */ - if (pI830->devicePresence) { - int req, att, enc; - GetDevicePresence(pScrn, &req, &att, &enc); - for (i = 0; i < NumDisplayTypes; i++) { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Display Presence: %s: attached: %s, encoder: %s\n", - displayDevices[i], - BOOLTOSTRING(((1<>i), - BOOLTOSTRING(((1<>i)); - } - } - - /* Save old configuration of detected devices */ - pI830->savedDevices = GetDisplayDevices(pScrn); - - if (I830IsPrimary(pScrn)) { - pI830->pipe = pI830->origPipe = GetBIOSPipe(pScrn); - - /* Override */ - if (pI830->fixedPipe != -1) { - if (xf86IsEntityShared(pScrn->entityList[0]) || pI830->Clone || - pI830->MergedFB) { - pI830->pipe = pI830->fixedPipe; - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Fixed Pipe setting primary to pipe %s.\n", - pI830->fixedPipe ? "B" : "A"); - } - } - - /* If the monitors aren't setup, read from the current config */ - if (pI830->MonType1 == PIPE_NONE && pI830->MonType2 == PIPE_NONE) { - pI830->MonType1 = pI830->savedDevices & 0xff; - pI830->MonType2 = (pI830->savedDevices & 0xff00) >> 8; - } else { - /* Here, we've switched pipes from our primary */ - if (pI830->MonType1 == PIPE_NONE && pI830->pipe == 0) - pI830->pipe = 1; - if (pI830->MonType2 == PIPE_NONE && pI830->pipe == 1) - pI830->pipe = 0; - } - - pI830->operatingDevices = (pI830->MonType2 << 8) | pI830->MonType1; - - if (!xf86IsEntityShared(pScrn->entityList[0]) && !pI830->Clone && - !pI830->MergedFB) { - /* If we're not dual head, clone or mergedfb, turn off the - * second head if monitorlayout is also specified. - */ - - if (pI830->pipe == 0) - pI830->operatingDevices = pI830->MonType1; - else - pI830->operatingDevices = pI830->MonType2 << 8; - } - - if (pI830->pipe != pI830->origPipe) - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "Primary Pipe has been switched from original pipe (%s to %s)\n", - pI830->origPipe ? "B" : "A", pI830->pipe ? "B" : "A"); - } else { - I830Ptr pI8301 = I830PTR(pI830->entityPrivate->pScrn_1); - pI830->operatingDevices = pI8301->operatingDevices; - pI830->pipe = !pI8301->pipe; - pI830->MonType1 = pI8301->MonType1; - pI830->MonType2 = pI8301->MonType2; - } - - /* Buggy BIOS 3066 is known to cause this, so turn this off */ - if (pI830->bios_version == 3066) { - pI830->displayInfo = FALSE; - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Detected Broken Video BIOS, turning off displayInfo.\n"); - } else - pI830->displayInfo = TRUE; - from = X_DEFAULT; - if (!xf86ReturnOptValBool(pI830->Options, OPTION_DISPLAY_INFO, TRUE)) { - pI830->displayInfo = FALSE; - from = X_CONFIG; - } - if (xf86ReturnOptValBool(pI830->Options, OPTION_DISPLAY_INFO, FALSE)) { - pI830->displayInfo = TRUE; - from = X_CONFIG; - } - xf86DrvMsg(pScrn->scrnIndex, from, "Display Info: %s.\n", - pI830->displayInfo ? "enabled" : "disabled"); - - if (!I830DetectDisplayDevice(pScrn)) { - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, - "Couldn't detect display devices.\n"); - PreInitCleanup(pScrn); - return FALSE; - } - - if (I830IsPrimary(pScrn)) { - if (!SetDisplayDevices(pScrn, pI830->operatingDevices)) { - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, - "Failed to switch to monitor configuration (0x%x)\n", - pI830->operatingDevices); - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, - "Please check the devices specified in your MonitorLayout\n"); - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, - "is configured correctly.\n"); - PreInitCleanup(pScrn); - return FALSE; - } - } - - PrintDisplayDeviceInfo(pScrn); - +#if 0 if (xf86IsEntityShared(pScrn->entityList[0])) { if (!I830IsPrimary(pScrn)) { /* This could be made to work with a little more fiddling */ @@ -4944,6 +1660,7 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) xf86DrvMsg(pScrn->scrnIndex, from, "Display is using Pipe %s\n", pI830->pipe ? "B" : "A"); } +#endif /* Alloc our pointers for the primary head */ if (I830IsPrimary(pScrn)) { @@ -5013,341 +1730,12 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Maximum frambuffer space: %d kByte\n", pScrn->videoRam); - SetPipeAccess(pScrn); - - /* Check we have an LFP connected, before trying to - * read PanelID information. */ - if ( (pI830->pipe == 1 && pI830->operatingDevices & (PIPE_LFP << 8)) || - (pI830->pipe == 0 && pI830->operatingDevices & PIPE_LFP) ) - vbeDoPanelID(pI830->pVbe); - - pDDCModule = xf86LoadSubModule(pScrn, "ddc"); - - monitor = vbeDoEDID(pI830->pVbe, pDDCModule); - - if ((pScrn->monitor->DDC = monitor) != NULL) { - xf86PrintEDID(monitor); - xf86SetDDCproperties(pScrn, monitor); - } - - if(pI830->MergedFB) { - pI830->pScrn_2->monitor = xalloc(sizeof(MonRec)); - if(pI830->pScrn_2->monitor) { - DisplayModePtr tempm = NULL, currentm = NULL, newm = NULL; - memcpy(pI830->pScrn_2->monitor, pScrn->monitor, sizeof(MonRec)); - pI830->pScrn_2->monitor->DDC = NULL; - pI830->pScrn_2->monitor->Modes = NULL; - pI830->pScrn_2->monitor->id = (char *)SecondMonitorName; - tempm = pScrn->monitor->Modes; - while(tempm) { - if(!(newm = xalloc(sizeof(DisplayModeRec)))) break; - memcpy(newm, tempm, sizeof(DisplayModeRec)); - if(!(newm->name = xalloc(strlen(tempm->name) + 1))) { - xfree(newm); - break; - } - strcpy(newm->name, tempm->name); - if(!pI830->pScrn_2->monitor->Modes) - pI830->pScrn_2->monitor->Modes = newm; - if(currentm) { - currentm->next = newm; - newm->prev = currentm; - } - currentm = newm; - tempm = tempm->next; - } - if(pI830->SecondHSync) { - pI830->pScrn_2->monitor->nHsync = - I830StrToRanges(pI830->pScrn_2->monitor->hsync, pI830->SecondHSync, MAX_HSYNC); - } - if(pI830->SecondVRefresh) { - pI830->pScrn_2->monitor->nVrefresh = - I830StrToRanges(pI830->pScrn_2->monitor->vrefresh, pI830->SecondVRefresh, MAX_VREFRESH); - } - SetBIOSPipe(pScrn, !pI830->pipe); - pI830->pVbe->ddc = DDC_UNCHECKED; - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Probing DDC data for second head\n"); - if((monitor = vbeDoEDID(pI830->pVbe, pDDCModule))) { - xf86PrintEDID(monitor); - xf86SetDDCproperties(pI830->pScrn_2, monitor); - pI830->pScrn_2->monitor->DDC = monitor; - /* use DDC data if no ranges in config file */ - if(!pI830->SecondHSync) { - pI830->pScrn_2->monitor->nHsync = 0; - } - if(!pI830->SecondVRefresh) { - pI830->pScrn_2->monitor->nVrefresh = 0; - } - } - SetPipeAccess(pScrn); - } else { - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, - "Failed to allocate memory for second monitor.\n"); - if(pI830->pScrn_2) - xfree(pI830->pScrn_2); - pI830->pScrn_2 = NULL; - pI830->MergedFB = FALSE; - } - } - - xf86UnloadSubModule(pDDCModule); - - /* XXX Move this to a header. */ -#define VIDEO_BIOS_SCRATCH 0x18 - -#if 1 - /* - * XXX This should be in ScreenInit/EnterVT. PreInit should not leave the - * state changed. - */ - /* Enable hot keys by writing the proper value to GR18 */ + if (!I830RandRPreInit (pScrn)) { - CARD8 gr18; - - gr18 = pI830->readControl(pI830, GRX, VIDEO_BIOS_SCRATCH); - gr18 &= ~0x80; /* - * Clear Hot key bit so that Video - * BIOS performs the hot key - * servicing - */ - pI830->writeControl(pI830, GRX, VIDEO_BIOS_SCRATCH, gr18); - } -#endif - - pI830->useExtendedRefresh = FALSE; - - if (xf86IsEntityShared(pScrn->entityList[0]) || pI830->Clone || - pI830->MergedFB) { - int pipe = - (pI830->operatingDevices >> PIPE_SHIFT(pI830->pipe)) & PIPE_ACTIVE_MASK; - if (pipe & ~PIPE_CRT_ACTIVE) { - xf86DrvMsg(pScrn->scrnIndex, X_PROBED, - "A non-CRT device is attached to pipe %c.\n" - "\tNo refresh rate overrides will be attempted.\n", - PIPE_NAME(pI830->pipe)); - pI830->vesa->useDefaultRefresh = TRUE; - } - /* - * Some desktop platforms might not have 0x5f05, so useExtendedRefresh - * would need to be set to FALSE for those cases. - */ - if (!pI830->vesa->useDefaultRefresh) - pI830->useExtendedRefresh = TRUE; - } else { - for (i = 0; i < pI830->availablePipes; i++) { - int pipe = - (pI830->operatingDevices >> PIPE_SHIFT(i)) & PIPE_ACTIVE_MASK; - if (pipe & ~PIPE_CRT_ACTIVE) { - xf86DrvMsg(pScrn->scrnIndex, X_PROBED, - "A non-CRT device is attached to pipe %c.\n" - "\tNo refresh rate overrides will be attempted.\n", - PIPE_NAME(i)); - pI830->vesa->useDefaultRefresh = TRUE; - } - /* - * Some desktop platforms might not have 0x5f05, so useExtendedRefresh - * would need to be set to FALSE for those cases. - */ - if (!pI830->vesa->useDefaultRefresh) - pI830->useExtendedRefresh = TRUE; - } - } - - if (pI830->useExtendedRefresh && !pI830->vesa->useDefaultRefresh) { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Will use BIOS call 0x5f05 to set refresh rates for CRTs.\n"); - } - - /* - * Limit videoram available for mode selection to what the video - * BIOS can see. - */ - if (pScrn->videoRam > (pI830->vbeInfo->TotalMemory * 64)) - memsize = pI830->vbeInfo->TotalMemory * 64; - else - memsize = pScrn->videoRam; - xf86DrvMsg(pScrn->scrnIndex, X_PROBED, - "Maximum space available for video modes: %d kByte\n", memsize); - - /* By now, we should have had some monitor settings, but if not, we - * need to setup some defaults. These are used in common/xf86Modes.c - * so we'll use them here for GetModePool, and that's all. - * We unset them after the call, so we can report 'defaults' as being - * used through the common layer. - */ -#define DEFAULT_HSYNC_LO 28 -#define DEFAULT_HSYNC_HI 33 -#define DEFAULT_VREFRESH_LO 43 -#define DEFAULT_VREFRESH_HI 72 - - if (pScrn->monitor->nHsync == 0) { - pScrn->monitor->hsync[0].lo = DEFAULT_HSYNC_LO; - pScrn->monitor->hsync[0].hi = DEFAULT_HSYNC_HI; - pScrn->monitor->nHsync = 1; - defmon |= 1; - } - - if (pScrn->monitor->nVrefresh == 0) { - pScrn->monitor->vrefresh[0].lo = DEFAULT_VREFRESH_LO; - pScrn->monitor->vrefresh[0].hi = DEFAULT_VREFRESH_HI; - pScrn->monitor->nVrefresh = 1; - defmon |= 2; - } - - DDCclock = I830UseDDC(pScrn); - - if (pI830->MergedFB) - DDCclock2 = I830UseDDC(pI830->pScrn_2); - - /* - * Note: VBE modes (> 0x7f) won't work with Intel's extended BIOS - * functions. - */ - pScrn->modePool = I830GetModePool(pScrn, pI830->pVbe, pI830->vbeInfo); - - if (!pScrn->modePool) { - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, - "No Video BIOS modes for chosen depth.\n"); - PreInitCleanup(pScrn); - return FALSE; - } - - if (pI830->MergedFB) { - SetBIOSPipe(pScrn, !pI830->pipe); - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Retrieving mode pool for second head.\n"); - pI830->pScrn_2->modePool = I830GetModePool(pI830->pScrn_2, pI830->pVbe, pI830->vbeInfo); - - if (!pI830->pScrn_2->modePool) { - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, - "No Video BIOS modes for chosen depth.\n"); - PreInitCleanup(pScrn); - return FALSE; - } - SetPipeAccess(pScrn); - } - - /* This may look a little weird, but to notify that we're using the - * default hsync/vrefresh we need to unset what we just set ..... - */ - if (defmon & 1) { - pScrn->monitor->hsync[0].lo = 0; - pScrn->monitor->hsync[0].hi = 0; - pScrn->monitor->nHsync = 0; - } - - if (defmon & 2) { - pScrn->monitor->vrefresh[0].lo = 0; - pScrn->monitor->vrefresh[0].hi = 0; - pScrn->monitor->nVrefresh = 0; - } - - SetPipeAccess(pScrn); - VBESetModeNames(pScrn->modePool); - if (pI830->MergedFB) - VBESetModeNames(pI830->pScrn_2->modePool); - - - /* - * XXX DDC information: There's code in xf86ValidateModes - * (VBEValidateModes) to set monitor defaults based on DDC information - * where available. If we need something that does better than this, - * there's code in vesa/vesa.c. - */ - - /* XXX Need to get relevant modes and virtual parameters. */ - /* Do the mode validation without regard to special scanline pitches. */ - SetPipeAccess(pScrn); - n = VBEValidateModes(pScrn, NULL, pScrn->display->modes, NULL, - NULL, 0, MAX_DISPLAY_PITCH, 1, - 0, MAX_DISPLAY_HEIGHT, - pScrn->display->virtualX, - pScrn->display->virtualY, - memsize, LOOKUP_BEST_REFRESH); - if (n <= 0) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes.\n"); PreInitCleanup(pScrn); return FALSE; - } - - if (pI830->MergedFB) { - n = VBEValidateModes(pI830->pScrn_2, NULL, pI830->pScrn_2->display->modes, NULL, - NULL, 0, MAX_DISPLAY_PITCH, 1, - 0, MAX_DISPLAY_HEIGHT, - pScrn->display->virtualX, - pScrn->display->virtualY, - memsize, LOOKUP_BEST_REFRESH); - if (n <= 0) { - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes.\n"); - PreInitCleanup(pScrn); - return FALSE; - } - } - - /* Only use this if we've got DDC available */ - if (DDCclock > 0) { - p = pScrn->modes; - if (p == NULL) - return FALSE; - do { - int Clock = 100000000; /* incredible value */ - - if (p->status == MODE_OK) { - for (pMon = pScrn->monitor->Modes; pMon != NULL; pMon = pMon->next) { - if ((pMon->HDisplay != p->HDisplay) || - (pMon->VDisplay != p->VDisplay) || - (pMon->Flags & (V_INTERLACE | V_DBLSCAN | V_CLKDIV2))) - continue; - - /* Find lowest supported Clock for this resolution */ - if (Clock > pMon->Clock) - Clock = pMon->Clock; - } - - if (Clock != 100000000 && DDCclock < 2550 && Clock / 1000.0 > DDCclock) { - ErrorF("(%s,%s) mode clock %gMHz exceeds DDC maximum %dMHz\n", - p->name, pScrn->monitor->id, - Clock/1000.0, DDCclock); - p->status = MODE_BAD; - } - } - p = p->next; - } while (p != NULL && p != pScrn->modes); - } - - /* Only use this if we've got DDC available */ - if (DDCclock2 > 0) { - p = pI830->pScrn_2->modes; - if (p == NULL) - return FALSE; - do { - int Clock = 100000000; /* incredible value */ - - if (p->status == MODE_OK) { - for (pMon = pI830->pScrn_2->monitor->Modes; pMon != NULL; pMon = pMon->next) { - if ((pMon->HDisplay != p->HDisplay) || - (pMon->VDisplay != p->VDisplay) || - (pMon->Flags & (V_INTERLACE | V_DBLSCAN | V_CLKDIV2))) - continue; - - /* Find lowest supported Clock for this resolution */ - if (Clock > pMon->Clock) - Clock = pMon->Clock; - } - - if (Clock != 100000000 && DDCclock2 < 2550 && Clock / 1000.0 > DDCclock2) { - ErrorF("(%s,%s) mode clock %gMHz exceeds DDC maximum %dMHz\n", - p->name, pI830->pScrn_2->monitor->id, - Clock/1000.0, DDCclock2); - p->status = MODE_BAD; - } - } - p = p->next; - } while (p != NULL && p != pI830->pScrn_2->modes); - } - - xf86PruneDriverModes(pScrn); + } if (pScrn->modes == NULL) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No modes.\n"); @@ -5355,64 +1743,26 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) return FALSE; } - if (pI830->MergedFB) { - DisplayModePtr old_modes, cur_mode; - - xf86PruneDriverModes(pI830->pScrn_2); - - if (pI830->pScrn_2->modes == NULL) { - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No modes.\n"); - PreInitCleanup(pScrn); - return FALSE; - } - - old_modes = pScrn->modes; - cur_mode = pScrn->currentMode; - - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "MergedFB: Generating mode list\n"); - - pScrn->modes = I830GenerateModeList(pScrn, pI830->MetaModes, - old_modes, pI830->pScrn_2->modes, - pI830->SecondPosition); - - if(!pScrn->modes) { - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No modes. Disabling MergedFB.\n"); - pScrn->modes = old_modes; - pScrn->currentMode = cur_mode; - pI830->MergedFB = FALSE; - } - } - - /* Now we check the VESA BIOS's displayWidth and reset if necessary */ - p = pScrn->modes; - do { - I830ModePrivatePtr mp = (I830ModePrivatePtr) p->Private; - VbeModeInfoBlock *modeInfo; - - /* Get BytesPerScanline so we can reset displayWidth */ - if ((modeInfo = VBEGetModeInfo(pI830->pVbe, mp->vbeData.mode))) { - if (pScrn->displayWidth < modeInfo->BytesPerScanline / pI830->cpp) { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Correcting stride (%d -> %d)\n", pScrn->displayWidth, modeInfo->BytesPerScanline); - pScrn->displayWidth = modeInfo->BytesPerScanline / pI830->cpp; - } - } - p = p->next; - } while (p != NULL && p != pScrn->modes); + /* + * Fix up modes to make hblank start at hsync start. + * I don't know why the xf86 code mangles this... + */ + { + DisplayModePtr p; + for (p = pScrn->modes; p;) { + xf86DrvMsg (pScrn->scrnIndex, + X_INFO, "move blank start from %d to %d\n", + p->CrtcHBlankStart, p->CrtcHDisplay); + p->CrtcHBlankStart = p->CrtcHDisplay; + p = p->next; + if (p == pScrn->modes) + break; + } + } + pScrn->currentMode = pScrn->modes; - if (pI830->MergedFB) { - /* If no virtual dimension was given by the user, - * calculate a sane one now. Adapts pScrn->virtualX, - * pScrn->virtualY and pScrn->displayWidth. - */ - I830RecalcDefaultVirtualSize(pScrn); - - pScrn->modes = pScrn->modes->next; /* We get the last from GenerateModeList(), skip to first */ - pScrn->currentMode = pScrn->modes; - pI830->currentMode = pScrn->currentMode; - } - #ifndef USE_PITCHES #define USE_PITCHES 1 #endif @@ -5573,24 +1923,8 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) pI830->displayWidth = pScrn->displayWidth; - SetPipeAccess(pScrn); I830PrintModes(pScrn); - if (!pI830->vesa->useDefaultRefresh) { - /* - * This sets the parameters for the VBE modes according to the best - * usable parameters from the Monitor sections modes (usually the - * default VESA modes), allowing for better than default refresh rates. - * This only works for VBE 3.0 and later. Also, we only do this - * if there are no non-CRT devices attached. - */ - SetPipeAccess(pScrn); - I830SetModeParameters(pScrn, pI830->pVbe); - } - - /* PreInit shouldn't leave any state changes, so restore this. */ - RestoreBIOSMemSize(pScrn); - /* Don't need MMIO access anymore. */ if (pI830->swfSaved) { OUTREG(SWF0, pI830->saveSWF0); @@ -5633,23 +1967,11 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) #if 0 if (I830IsPrimary(pScrn)) { - VBEFreeVBEInfo(pI830->vbeInfo); vbeFree(pI830->pVbe); } - pI830->vbeInfo = NULL; pI830->pVbe = NULL; #endif - /* Use the VBE mode restore workaround by default. */ - pI830->vbeRestoreWorkaround = TRUE; - from = X_DEFAULT; - if (xf86ReturnOptValBool(pI830->Options, OPTION_VBE_RESTORE, FALSE)) { - pI830->vbeRestoreWorkaround = FALSE; - from = X_CONFIG; - } - xf86DrvMsg(pScrn->scrnIndex, from, "VBE Restore workaround: %s.\n", - pI830->vbeRestoreWorkaround ? "enabled" : "disabled"); - #if defined(XF86DRI) /* Load the dri module if requested. */ if (xf86ReturnOptValBool(pI830->Options, OPTION_DRI, FALSE) && @@ -5886,80 +2208,101 @@ static Bool SaveHWState(ScrnInfoPtr pScrn) { I830Ptr pI830 = I830PTR(pScrn); - vbeInfoPtr pVbe = pI830->pVbe; vgaHWPtr hwp = VGAHWPTR(pScrn); vgaRegPtr vgaReg = &hwp->SavedReg; - VbeModeInfoBlock *modeInfo; - VESAPtr pVesa; + CARD32 temp; + int i; - DPRINTF(PFX, "SaveHWState\n"); + /* + * Print out the PIPEACONF and PIPEBCONF registers. + */ + temp = INREG(PIPEACONF); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "PIPEACONF is 0x%08lx\n", + (unsigned long) temp); + if (pI830->num_pipes == 2) { + temp = INREG(PIPEBCONF); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "PIPEBCONF is 0x%08lx\n", + (unsigned long) temp); + } - if (I830IsPrimary(pScrn) && pI830->pipe != pI830->origPipe) - SetBIOSPipe(pScrn, pI830->origPipe); - else - SetPipeAccess(pScrn); + i830TakeRegSnapshot(pScrn); - pVesa = pI830->vesa; + /* Save video mode information for native mode-setting. */ + pI830->saveDSPACNTR = INREG(DSPACNTR); + pI830->savePIPEACONF = INREG(PIPEACONF); + pI830->savePIPEASRC = INREG(PIPEASRC); + pI830->saveFPA0 = INREG(FPA0); + pI830->saveFPA1 = INREG(FPA1); + pI830->saveDPLL_A = INREG(DPLL_A); + if (IS_I965G(pI830)) + pI830->saveDPLL_A_MD = INREG(DPLL_A_MD); + pI830->saveHTOTAL_A = INREG(HTOTAL_A); + pI830->saveHBLANK_A = INREG(HBLANK_A); + pI830->saveHSYNC_A = INREG(HSYNC_A); + pI830->saveVTOTAL_A = INREG(VTOTAL_A); + pI830->saveVBLANK_A = INREG(VBLANK_A); + pI830->saveVSYNC_A = INREG(VSYNC_A); + pI830->saveDSPASTRIDE = INREG(DSPASTRIDE); + pI830->saveDSPASIZE = INREG(DSPASIZE); + pI830->saveDSPAPOS = INREG(DSPAPOS); + pI830->saveDSPABASE = INREG(DSPABASE); - /* Make sure we save at least this information in case of failure. */ - VBEGetVBEMode(pVbe, &pVesa->stateMode); - pVesa->stateRefresh = GetRefreshRate(pScrn, pVesa->stateMode, NULL); - modeInfo = VBEGetModeInfo(pVbe, pVesa->stateMode); - pVesa->savedScanlinePitch = 0; - if (modeInfo) { - if (VBE_MODE_GRAPHICS(modeInfo)) { - VBEGetLogicalScanline(pVbe, &pVesa->savedScanlinePitch, NULL, NULL); + for(i= 0; i < 256; i++) { + pI830->savePaletteA[i] = INREG(PALETTE_A + (i << 2)); + } + + if(pI830->num_pipes == 2) { + pI830->savePIPEBCONF = INREG(PIPEBCONF); + pI830->savePIPEBSRC = INREG(PIPEBSRC); + pI830->saveDSPBCNTR = INREG(DSPBCNTR); + pI830->saveFPB0 = INREG(FPB0); + pI830->saveFPB1 = INREG(FPB1); + pI830->saveDPLL_B = INREG(DPLL_B); + if (IS_I965G(pI830)) + pI830->saveDPLL_B_MD = INREG(DPLL_B_MD); + pI830->saveHTOTAL_B = INREG(HTOTAL_B); + pI830->saveHBLANK_B = INREG(HBLANK_B); + pI830->saveHSYNC_B = INREG(HSYNC_B); + pI830->saveVTOTAL_B = INREG(VTOTAL_B); + pI830->saveVBLANK_B = INREG(VBLANK_B); + pI830->saveVSYNC_B = INREG(VSYNC_B); + pI830->saveDSPBSTRIDE = INREG(DSPBSTRIDE); + pI830->saveDSPBSIZE = INREG(DSPBSIZE); + pI830->saveDSPBPOS = INREG(DSPBPOS); + pI830->saveDSPBBASE = INREG(DSPBBASE); + for(i= 0; i < 256; i++) { + pI830->savePaletteB[i] = INREG(PALETTE_B + (i << 2)); } - VBEFreeModeInfo(modeInfo); + } + + if (IS_I965G(pI830)) { + pI830->saveDSPASURF = INREG(DSPASURF); + pI830->saveDSPBSURF = INREG(DSPBSURF); + } + + pI830->saveVCLK_DIVISOR_VGA0 = INREG(VCLK_DIVISOR_VGA0); + pI830->saveVCLK_DIVISOR_VGA1 = INREG(VCLK_DIVISOR_VGA1); + pI830->saveVCLK_POST_DIV = INREG(VCLK_POST_DIV); + pI830->saveVGACNTRL = INREG(VGACNTRL); + + for(i = 0; i < 7; i++) { + pI830->saveSWF[i] = INREG(SWF0 + (i << 2)); + pI830->saveSWF[i+7] = INREG(SWF00 + (i << 2)); + } + pI830->saveSWF[14] = INREG(SWF30); + pI830->saveSWF[15] = INREG(SWF31); + pI830->saveSWF[16] = INREG(SWF32); + + pI830->savePFIT_CONTROL = INREG(PFIT_CONTROL); + + for (i = 0; i < pI830->num_outputs; i++) { + if (pI830->output[i].save != NULL) + pI830->output[i].save(pScrn, &pI830->output[i]); } vgaHWUnlock(hwp); vgaHWSave(pScrn, vgaReg, VGA_SR_FONTS); - pVesa = pI830->vesa; - - if (IS_I965G(pI830)) { - pI830->savedAsurf = INREG(DSPASURF); - pI830->savedBsurf = INREG(DSPBSURF); - } - - /* - * This save/restore method doesn't work for 845G BIOS, or for some - * other platforms. Enable it in all cases. - */ - /* - * KW: This may have been because of the behaviour I've found on my - * board: The 'save' command actually modifies the interrupt - * registers, turning off the irq & breaking the kernel module - * behaviour. - */ - if (!pI830->vbeRestoreWorkaround) { - CARD16 imr = INREG16(IMR); - CARD16 ier = INREG16(IER); - CARD16 hwstam = INREG16(HWSTAM); - - if (!VBESaveRestore(pVbe, MODE_SAVE, &pVesa->state, &pVesa->stateSize, - &pVesa->statePage)) { - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, - "SaveHWState: VBESaveRestore(MODE_SAVE) failed.\n"); - return FALSE; - } - - OUTREG16(IMR, imr); - OUTREG16(IER, ier); - OUTREG16(HWSTAM, hwstam); - } - - pVesa->savedPal = VBESetGetPaletteData(pVbe, FALSE, 0, 256, - NULL, FALSE, FALSE); - if (!pVesa->savedPal) { - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, - "SaveHWState: VBESetGetPaletteData(GET) failed.\n"); - return FALSE; - } - - VBEGetDisplayStart(pVbe, &pVesa->x, &pVesa->y); - return TRUE; } @@ -5967,716 +2310,113 @@ static Bool RestoreHWState(ScrnInfoPtr pScrn) { I830Ptr pI830 = I830PTR(pScrn); - vbeInfoPtr pVbe = pI830->pVbe; vgaHWPtr hwp = VGAHWPTR(pScrn); vgaRegPtr vgaReg = &hwp->SavedReg; - VESAPtr pVesa; - Bool restored = FALSE; + CARD32 temp; + int i; DPRINTF(PFX, "RestoreHWState\n"); - if (I830IsPrimary(pScrn) && pI830->pipe != pI830->origPipe) - SetBIOSPipe(pScrn, pI830->origPipe); - else - SetPipeAccess(pScrn); - - pVesa = pI830->vesa; - - /* - * Workaround for text mode restoration with some flat panels. - * Temporarily program a 640x480 mode before switching back to - * text mode. - */ - if (pVesa->useDefaultRefresh) - I830Set640x480(pScrn); - - if (pVesa->state && pVesa->stateSize) { - CARD16 imr = INREG16(IMR); - CARD16 ier = INREG16(IER); - CARD16 hwstam = INREG16(HWSTAM); - - /* Make a copy of the state. Don't rely on it not being touched. */ - if (!pVesa->pstate) { - pVesa->pstate = xalloc(pVesa->stateSize); - if (pVesa->pstate) - memcpy(pVesa->pstate, pVesa->state, pVesa->stateSize); - } - restored = VBESaveRestore(pVbe, MODE_RESTORE, &pVesa->state, - &pVesa->stateSize, &pVesa->statePage); - if (!restored) { - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "RestoreHWState: VBESaveRestore failed.\n"); - } - /* Copy back */ - if (pVesa->pstate) - memcpy(pVesa->state, pVesa->pstate, pVesa->stateSize); - - OUTREG16(IMR, imr); - OUTREG16(IER, ier); - OUTREG16(HWSTAM, hwstam); - } - /* If that failed, restore the original mode. */ - if (!restored) { - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "Setting the original video mode instead of restoring\n\t" - "the saved state\n"); - I830VESASetVBEMode(pScrn, pVesa->stateMode, NULL); - if (!pVesa->useDefaultRefresh && pI830->useExtendedRefresh) { - SetRefreshRate(pScrn, pVesa->stateMode, pVesa->stateRefresh); - } - } - if (pVesa->savedScanlinePitch) - VBESetLogicalScanline(pVbe, pVesa->savedScanlinePitch); - - if (pVesa->savedPal) - VBESetGetPaletteData(pVbe, TRUE, 0, 256, pVesa->savedPal, FALSE, TRUE); - - VBESetDisplayStart(pVbe, pVesa->x, pVesa->y, TRUE); - - if (IS_I965G(pI830)) { - OUTREG(DSPASURF, pI830->savedAsurf); - OUTREG(DSPBSURF, pI830->savedBsurf); - } - +#ifdef XF86DRI + I830DRISetVBlankInterrupt (pScrn, FALSE); +#endif vgaHWRestore(pScrn, vgaReg, VGA_SR_FONTS); vgaHWLock(hwp); - return TRUE; -} + /* First, disable display planes */ + temp = INREG(DSPACNTR); + OUTREG(DSPACNTR, temp & ~DISPLAY_PLANE_ENABLE); + temp = INREG(DSPBCNTR); + OUTREG(DSPBCNTR, temp & ~DISPLAY_PLANE_ENABLE); -static void I830SetCloneVBERefresh(ScrnInfoPtr pScrn, int mode, VbeCRTCInfoBlock * block, int refresh) -{ - I830Ptr pI830 = I830PTR(pScrn); - DisplayModePtr p = NULL; - int RefreshRate; - int clock; - - /* Search for our mode and get a refresh to match */ - for (p = pScrn->monitor->Modes; p != NULL; p = p->next) { - if ((p->HDisplay != pI830->CloneHDisplay) || - (p->VDisplay != pI830->CloneVDisplay) || - (p->Flags & (V_INTERLACE | V_DBLSCAN | V_CLKDIV2))) - continue; - RefreshRate = ((double)(p->Clock * 1000) / - (double)(p->HTotal * p->VTotal)) * 100; - /* we could probably do better here that 2Hz boundaries */ - if (RefreshRate > (refresh - 200) && RefreshRate < (refresh + 200)) { - block->HorizontalTotal = p->HTotal; - block->HorizontalSyncStart = p->HSyncStart; - block->HorizontalSyncEnd = p->HSyncEnd; - block->VerticalTotal = p->VTotal; - block->VerticalSyncStart = p->VSyncStart; - block->VerticalSyncEnd = p->VSyncEnd; - block->Flags = ((p->Flags & V_NHSYNC) ? CRTC_NHSYNC : 0) | - ((p->Flags & V_NVSYNC) ? CRTC_NVSYNC : 0); - block->PixelClock = p->Clock * 1000; - /* XXX May not have this. */ - clock = VBEGetPixelClock(pI830->pVbe, mode, block->PixelClock); -#ifdef DEBUG - ErrorF("Setting clock %.2fMHz, closest is %.2fMHz\n", - (double)data->block->PixelClock / 1000000.0, - (double)clock / 1000000.0); -#endif - if (clock) - block->PixelClock = clock; - block->RefreshRate = RefreshRate; - return; - } - } -} - -static Bool -I830VESASetVBEMode(ScrnInfoPtr pScrn, int mode, VbeCRTCInfoBlock * block) -{ - I830Ptr pI830 = I830PTR(pScrn); - Bool ret = FALSE; - int Mon; - - DPRINTF(PFX, "Setting mode 0x%.8x\n", mode); - -#if 0 - /* Clear the framebuffer (could do this with VBIOS call) */ - if (I830IsPrimary(pScrn)) - memset(pI830->FbBase + pI830->FrontBuffer.Start, 0, - pScrn->virtualY * pI830->displayWidth * pI830->cpp); - else - memset(pI830->FbBase + pI830->FrontBuffer2.Start, 0, - pScrn->virtualY * pI830->displayWidth * pI830->cpp); -#endif - - if (pI830->Clone && - pI830->CloneHDisplay && pI830->CloneVDisplay && - !pI830->preinit && !pI830->closing) { - VbeCRTCInfoBlock newblock; - int newmode = mode; - - if (pI830->pipe == 1) - Mon = pI830->MonType1; - else - Mon = pI830->MonType2; - - SetBIOSPipe(pScrn, !pI830->pipe); - - /* Now recheck refresh operations we can use */ - pI830->useExtendedRefresh = FALSE; - pI830->vesa->useDefaultRefresh = FALSE; - - if (Mon != PIPE_CRT) { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "A non-CRT device is attached to Clone pipe %c.\n" - "\tNo refresh rate overrides will be attempted (0x%x).\n", - PIPE_NAME(!pI830->pipe), newmode); - pI830->vesa->useDefaultRefresh = TRUE; - } - /* - * Some desktop platforms might not have 0x5f05, so useExtendedRefresh - * would need to be set to FALSE for those cases. - */ - if (!pI830->vesa->useDefaultRefresh) - pI830->useExtendedRefresh = TRUE; - - newmode |= 1 << 11; - if (pI830->vesa->useDefaultRefresh) - newmode &= ~(1 << 11); - - if (!SetRefreshRate(pScrn, newmode, 60)) { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "BIOS call 0x5f05 not supported on Clone Head, " - "setting refresh with VBE 3 method.\n"); - pI830->useExtendedRefresh = FALSE; - } - - if (!pI830->vesa->useDefaultRefresh) { - I830SetCloneVBERefresh(pScrn, newmode, &newblock, pI830->CloneRefresh * 100); - - if (!VBESetVBEMode(pI830->pVbe, newmode, &newblock)) { - if (!VBESetVBEMode(pI830->pVbe, (newmode & ~(1 << 11)), NULL)) - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "Failed to set mode for Clone head.\n"); - } else { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Setting refresh on clone head with VBE 3 method.\n"); - pI830->useExtendedRefresh = FALSE; - } - } else { - if (!VBESetVBEMode(pI830->pVbe, (newmode & ~(1 << 11)), NULL)) - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "Failed to set mode for Clone head.\n"); - } - - if (pI830->useExtendedRefresh && !pI830->vesa->useDefaultRefresh) { - if (!SetRefreshRate(pScrn, newmode, pI830->CloneRefresh)) - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "Failed to set refresh rate to %dHz on Clone head.\n", - pI830->CloneRefresh); - else - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Set refresh rate to %dHz on Clone head.\n", - pI830->CloneRefresh); - } - SetPipeAccess(pScrn); - } - - if (pI830->pipe == 0) - Mon = pI830->MonType1; - else - Mon = pI830->MonType2; - - - /* Now recheck refresh operations we can use */ - pI830->useExtendedRefresh = FALSE; - pI830->vesa->useDefaultRefresh = FALSE; - - if (Mon != PIPE_CRT) { - xf86DrvMsg(pScrn->scrnIndex, X_PROBED, - "A non-CRT device is attached to pipe %c.\n" - "\tNo refresh rate overrides will be attempted.\n", - PIPE_NAME(pI830->pipe)); - pI830->vesa->useDefaultRefresh = TRUE; - } - - mode |= 1 << 11; - if (pI830->vesa->useDefaultRefresh) - mode &= ~(1 << 11); - /* - * Some desktop platforms might not have 0x5f05, so useExtendedRefresh - * would need to be set to FALSE for those cases. - */ - if (!pI830->vesa->useDefaultRefresh) - pI830->useExtendedRefresh = TRUE; - - if (!SetRefreshRate(pScrn, mode, 60)) { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "BIOS call 0x5f05 not supported, " - "setting refresh with VBE 3 method.\n"); - pI830->useExtendedRefresh = FALSE; - } - - if (!pI830->vesa->useDefaultRefresh && block) { - ret = VBESetVBEMode(pI830->pVbe, mode, block); - if (!ret) - ret = VBESetVBEMode(pI830->pVbe, (mode & ~(1 << 11)), NULL); - else { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Setting refresh with VBE 3 method.\n"); - pI830->useExtendedRefresh = FALSE; - } - } else { - ret = VBESetVBEMode(pI830->pVbe, (mode & ~(1 << 11)), NULL); - } - - /* Might as well bail now if we've failed */ - if (!ret) return FALSE; - - if (pI830->useExtendedRefresh && !pI830->vesa->useDefaultRefresh && block) { - if (!SetRefreshRate(pScrn, mode, block->RefreshRate / 100)) { - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "Failed to set refresh rate to %dHz.\n", - block->RefreshRate / 100); - pI830->useExtendedRefresh = FALSE; - } - } - - return ret; -} - -static Bool -I830VESASetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode) -{ - I830Ptr pI830 = I830PTR(pScrn); - vbeInfoPtr pVbe = pI830->pVbe; - I830ModePrivatePtr mp = (I830ModePrivatePtr) pMode->Private; - int mode, i; - CARD32 planeA, planeB, temp; - int refresh = 60; -#ifdef XF86DRI - Bool didLock = FALSE; -#endif - - DPRINTF(PFX, "I830VESASetMode\n"); - - /* Always Enable Linear Addressing */ - mode = mp->vbeData.mode | (1 << 15) | (1 << 14); - -#ifdef XF86DRI - didLock = I830DRILock(pScrn); -#endif - - if (pI830->Clone) { - pI830->CloneHDisplay = pMode->HDisplay; - pI830->CloneVDisplay = pMode->VDisplay; - } - -#ifndef MODESWITCH_RESET_STATE -#define MODESWITCH_RESET_STATE 0 -#endif -#if MODESWITCH_RESET_STATE - ResetState(pScrn, TRUE); -#endif - - SetPipeAccess(pScrn); - - if (!pI830->MergedFB) { - if (I830VESASetVBEMode(pScrn, mode, mp->vbeData.block) == FALSE) { - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Set VBE Mode failed!\n"); - return FALSE; - } - }else { - I830ModePrivatePtr s = (I830ModePrivatePtr)mp->merged.Second->Private; - I830ModePrivatePtr f = (I830ModePrivatePtr)mp->merged.First->Private; - int pipe = pI830->pipe; /* save current pipe */ - - SetBIOSPipe(pScrn, !pI830->pipe); - - pI830->pipe = !pI830->pipe; - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Setting mode on Pipe %s.\n", pI830->pipe ? "B" : "A"); - - if (I830VESASetVBEMode(pScrn, (s->vbeData.mode | 1<<15 | 1<<14), s->vbeData.block) == FALSE) { - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Set VBE Mode failed!\n"); - return FALSE; - } - - pI830->pipe = pipe; /* restore current pipe */ - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Setting mode on Pipe %s.\n", pI830->pipe ? "B" : "A"); - - SetPipeAccess(pScrn); - - if (I830VESASetVBEMode(pScrn, (f->vbeData.mode | 1<<15 | 1<<14), f->vbeData.block) == FALSE) { - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Set VBE Mode failed!\n"); - return FALSE; - } - } - -#if 0 - { /* I965G ENABLE TILING */ - planeA = INREG(DSPACNTR) | 1<<10; - OUTREG(DSPACNTR, planeA); - /* flush the change. */ - temp = INREG(DSPABASE); - OUTREG(DSPABASE, temp); - } -#else - { /* I965G DISABLE TILING */ - planeA = INREG(DSPACNTR) & ~1<<10; - OUTREG(DSPACNTR, planeA); - /* flush the change. */ - temp = INREG(DSPABASE); - OUTREG(DSPABASE, temp); - OUTREG(DSPASURF, INREG(DSPASURF)); - } -#endif - - /* - * The BIOS may not set a scanline pitch that would require more video - * memory than it's aware of. We check for this later, and set it - * explicitly if necessary. - */ - if (mp->vbeData.data->XResolution != pI830->displayWidth) { - if (pI830->Clone || pI830->MergedFB) { - SetBIOSPipe(pScrn, !pI830->pipe); - VBESetLogicalScanline(pVbe, pI830->displayWidth); - } - SetPipeAccess(pScrn); - VBESetLogicalScanline(pVbe, pI830->displayWidth); - } - - if (pScrn->bitsPerPixel >= 8 && pI830->vbeInfo->Capabilities[0] & 0x01) { - if (pI830->Clone || pI830->MergedFB) { - SetBIOSPipe(pScrn, !pI830->pipe); - VBESetGetDACPaletteFormat(pVbe, 8); - } - SetPipeAccess(pScrn); - VBESetGetDACPaletteFormat(pVbe, 8); - } - - /* XXX Fix plane A with pipe A, and plane B with pipe B. */ - planeA = INREG(DSPACNTR); - planeB = INREG(DSPBCNTR); - - pI830->planeEnabled[0] = ((planeA & DISPLAY_PLANE_ENABLE) != 0); - pI830->planeEnabled[1] = ((planeB & DISPLAY_PLANE_ENABLE) != 0); - - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Display plane A is %s and connected to %s.\n", - pI830->planeEnabled[0] ? "enabled" : "disabled", - planeA & DISPPLANE_SEL_PIPE_MASK ? "Pipe B" : "Pipe A"); - if (pI830->availablePipes == 2) - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Display plane B is %s and connected to %s.\n", - pI830->planeEnabled[1] ? "enabled" : "disabled", - planeB & DISPPLANE_SEL_PIPE_MASK ? "Pipe B" : "Pipe A"); - - if (pI830->operatingDevices & 0xff) { - pI830->planeEnabled[0] = 1; - } else { - pI830->planeEnabled[0] = 0; - } - - if (pI830->operatingDevices & 0xff00) { - pI830->planeEnabled[1] = 1; - } else { - pI830->planeEnabled[1] = 0; - } - - if (pI830->planeEnabled[0]) { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Enabling plane A.\n"); - planeA |= DISPLAY_PLANE_ENABLE; - planeA &= ~DISPPLANE_SEL_PIPE_MASK; - planeA |= DISPPLANE_SEL_PIPE_A; - OUTREG(DSPACNTR, planeA); - /* flush the change. */ - temp = INREG(DSPABASE); - OUTREG(DSPABASE, temp); - if (IS_I965G(pI830)) { - temp = INREG(DSPASURF); - OUTREG(DSPASURF, temp); - } - } - if (pI830->planeEnabled[1]) { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Enabling plane B.\n"); - planeB |= DISPLAY_PLANE_ENABLE; - planeB &= ~DISPPLANE_SEL_PIPE_MASK; - planeB |= DISPPLANE_SEL_PIPE_B; - OUTREG(DSPBCNTR, planeB); - /* flush the change. */ - temp = INREG(DSPBADDR); - OUTREG(DSPBADDR, temp); - if (IS_I965G(pI830)) { - temp = INREG(DSPBSURF); - OUTREG(DSPBSURF, temp); - } - } - - planeA = INREG(DSPACNTR); - planeB = INREG(DSPBCNTR); - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Display plane A is now %s and connected to %s.\n", - pI830->planeEnabled[0] ? "enabled" : "disabled", - planeA & DISPPLANE_SEL_PIPE_MASK ? "Pipe B" : "Pipe A"); - if (pI830->availablePipes == 2) - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Display plane B is now %s and connected to %s.\n", - pI830->planeEnabled[1] ? "enabled" : "disabled", - planeB & DISPPLANE_SEL_PIPE_MASK ? "Pipe B" : "Pipe A"); - - /* XXX Plane C is ignored for now (overlay). */ - - /* - * Print out the PIPEACONF and PIPEBCONF registers. - */ + /* Next, disable display pipes */ temp = INREG(PIPEACONF); - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "PIPEACONF is 0x%08lx\n", - (unsigned long) temp); - if (pI830->availablePipes == 2) { - temp = INREG(PIPEBCONF); - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "PIPEBCONF is 0x%08lx\n", - (unsigned long) temp); + OUTREG(PIPEACONF, temp & ~PIPEACONF_ENABLE); + temp = INREG(PIPEBCONF); + OUTREG(PIPEBCONF, temp & ~PIPEBCONF_ENABLE); + + /* Disable outputs if necessary */ + for (i = 0; i < pI830->num_outputs; i++) { + pI830->output[i].pre_set_mode(pScrn, &pI830->output[i], NULL); } - if (xf86IsEntityShared(pScrn->entityList[0])) { - /* Clean this up !! */ - if (I830IsPrimary(pScrn)) { - CARD32 stridereg = !pI830->pipe ? DSPASTRIDE : DSPBSTRIDE; - CARD32 basereg = !pI830->pipe ? DSPABASE : DSPBBASE; - CARD32 sizereg = !pI830->pipe ? DSPASIZE : DSPBSIZE; - CARD32 surfreg = !pI830->pipe ? DSPASURF : DSPBSURF; - I830Ptr pI8301 = I830PTR(pI830->entityPrivate->pScrn_1); + i830WaitForVblank(pScrn); - temp = INREG(stridereg); - if (temp / pI8301->cpp != (CARD32)(pI830->displayWidth)) { - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "Correcting plane %c stride (%d -> %d)\n", PIPE_NAME(!pI830->pipe), - (int)(temp / pI8301->cpp), pI830->displayWidth); - OUTREG(stridereg, pI830->displayWidth * pI8301->cpp); - } - OUTREG(sizereg, (pMode->HDisplay - 1) | ((pMode->VDisplay - 1) << 16)); - /* Trigger update */ - temp = INREG(basereg); - OUTREG(basereg, temp); - if (IS_I965G(pI830)) { - temp = INREG(surfreg); - OUTREG(surfreg, temp); - } - - if (pI830->entityPrivate && pI830->entityPrivate->pScrn_2) { - I830Ptr pI8302 = I830PTR(pI830->entityPrivate->pScrn_2); - stridereg = pI830->pipe ? DSPASTRIDE : DSPBSTRIDE; - basereg = pI830->pipe ? DSPABASE : DSPBBASE; - sizereg = pI830->pipe ? DSPASIZE : DSPBSIZE; - surfreg = pI830->pipe ? DSPASURF : DSPBSURF; - - temp = INREG(stridereg); - if (temp / pI8302->cpp != (CARD32)(pI8302->displayWidth)) { - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "Correcting plane %c stride (%d -> %d)\n", PIPE_NAME(pI830->pipe), - (int)(temp / pI8302->cpp), pI8302->displayWidth); - OUTREG(stridereg, pI8302->displayWidth * pI8302->cpp); - } - OUTREG(sizereg, (pI830->entityPrivate->pScrn_2->currentMode->HDisplay - 1) | ((pI830->entityPrivate->pScrn_2->currentMode->VDisplay - 1) << 16)); - /* Trigger update */ - temp = INREG(basereg); - OUTREG(basereg, temp); - if (IS_I965G(pI830)) { - temp = INREG(surfreg); - OUTREG(surfreg, temp); - } - } - } else { - CARD32 stridereg = pI830->pipe ? DSPASTRIDE : DSPBSTRIDE; - CARD32 basereg = pI830->pipe ? DSPABASE : DSPBBASE; - CARD32 sizereg = pI830->pipe ? DSPASIZE : DSPBSIZE; - CARD32 surfreg = pI830->pipe ? DSPASURF : DSPBSURF; - I830Ptr pI8301 = I830PTR(pI830->entityPrivate->pScrn_1); - I830Ptr pI8302 = I830PTR(pI830->entityPrivate->pScrn_2); - - temp = INREG(stridereg); - if (temp / pI8301->cpp != (CARD32)(pI8301->displayWidth)) { - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "Correcting plane %c stride (%d -> %d)\n", PIPE_NAME(pI830->pipe), - (int)(temp / pI8301->cpp), pI8301->displayWidth); - OUTREG(stridereg, pI8301->displayWidth * pI8301->cpp); - } - OUTREG(sizereg, (pI830->entityPrivate->pScrn_1->currentMode->HDisplay - 1) | ((pI830->entityPrivate->pScrn_1->currentMode->VDisplay - 1) << 16)); - /* Trigger update */ - temp = INREG(basereg); - OUTREG(basereg, temp); - if (IS_I965G(pI830)) { - temp = INREG(surfreg); - OUTREG(surfreg, temp); - } - - stridereg = !pI830->pipe ? DSPASTRIDE : DSPBSTRIDE; - basereg = !pI830->pipe ? DSPABASE : DSPBBASE; - sizereg = !pI830->pipe ? DSPASIZE : DSPBSIZE; - surfreg = !pI830->pipe ? DSPASURF : DSPBSURF; - - temp = INREG(stridereg); - if (temp / pI8302->cpp != ((CARD32)pI8302->displayWidth)) { - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "Correcting plane %c stride (%d -> %d)\n", PIPE_NAME(!pI830->pipe), - (int)(temp / pI8302->cpp), pI8302->displayWidth); - OUTREG(stridereg, pI8302->displayWidth * pI8302->cpp); - } - OUTREG(sizereg, (pMode->HDisplay - 1) | ((pMode->VDisplay - 1) << 16)); - /* Trigger update */ - temp = INREG(basereg); - OUTREG(basereg, temp); - if (IS_I965G(pI830)) { - temp = INREG(surfreg); - OUTREG(surfreg, temp); - } - } - } else { - for (i = 0; i < pI830->availablePipes; i++) { - CARD32 stridereg = i ? DSPBSTRIDE : DSPASTRIDE; - CARD32 basereg = i ? DSPBBASE : DSPABASE; - CARD32 sizereg = i ? DSPBSIZE : DSPASIZE; - CARD32 surfreg = i ? DSPBSURF : DSPASURF; - - if (!pI830->planeEnabled[i]) - continue; - - temp = INREG(stridereg); - if (temp / pI830->cpp != (CARD32)pI830->displayWidth) { - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "Correcting plane %c stride (%d -> %d)\n", PIPE_NAME(i), - (int)(temp / pI830->cpp), pI830->displayWidth); - OUTREG(stridereg, pI830->displayWidth * pI830->cpp); - } - - if (pI830->MergedFB) { - switch (pI830->SecondPosition) { - case PosRightOf: - case PosBelow: - OUTREG(DSPABASE, (CDMPTR.First->HDisplay - 1) | ((CDMPTR.First->VDisplay - 1) << 16)); - OUTREG(DSPBBASE, (CDMPTR.Second->HDisplay - 1) | ((CDMPTR.Second->VDisplay - 1) << 16)); - break; - case PosLeftOf: - case PosAbove: - OUTREG(DSPABASE, (CDMPTR.Second->HDisplay - 1) | ((CDMPTR.Second->VDisplay - 1) << 16)); - OUTREG(DSPBBASE, (CDMPTR.First->HDisplay - 1) | ((CDMPTR.First->VDisplay - 1) << 16)); - break; - } - } else - OUTREG(sizereg, (pMode->HDisplay - 1) | ((pMode->VDisplay - 1) << 16)); - /* Trigger update */ - temp = INREG(basereg); - OUTREG(basereg, temp); - if (IS_I965G(pI830)) { - temp = INREG(surfreg); - OUTREG(surfreg, temp); - } - } - } - -#if 0 - /* Print out some CRTC/display information. */ - temp = INREG(HTOTAL_A); - ErrorF("Horiz active: %d, Horiz total: %d\n", temp & 0x7ff, - (temp >> 16) & 0xfff); - temp = INREG(HBLANK_A); - ErrorF("Horiz blank start: %d, Horiz blank end: %d\n", temp & 0xfff, - (temp >> 16) & 0xfff); - temp = INREG(HSYNC_A); - ErrorF("Horiz sync start: %d, Horiz sync end: %d\n", temp & 0xfff, - (temp >> 16) & 0xfff); - temp = INREG(VTOTAL_A); - ErrorF("Vert active: %d, Vert total: %d\n", temp & 0x7ff, - (temp >> 16) & 0xfff); - temp = INREG(VBLANK_A); - ErrorF("Vert blank start: %d, Vert blank end: %d\n", temp & 0xfff, - (temp >> 16) & 0xfff); - temp = INREG(VSYNC_A); - ErrorF("Vert sync start: %d, Vert sync end: %d\n", temp & 0xfff, - (temp >> 16) & 0xfff); - temp = INREG(PIPEASRC); - ErrorF("Image size: %dx%d (%dx%d)\n", - (temp >> 16) & 0x7ff, temp & 0x7ff, - (((temp >> 16) & 0x7ff) + 1), ((temp & 0x7ff) + 1)); - ErrorF("Pixel multiply is %d\n", (planeA >> 20) & 0x3); - temp = INREG(DSPABASE); - ErrorF("Plane A start offset is %d\n", temp); - temp = INREG(DSPASTRIDE); - ErrorF("Plane A stride is %d bytes (%d pixels)\n", temp, temp / pI830->cpp); - temp = INREG(DSPAPOS); - ErrorF("Plane A position %d %d\n", temp & 0xffff, (temp & 0xffff0000) >> 16); - temp = INREG(DSPASIZE); - ErrorF("Plane A size %d %d\n", temp & 0xffff, (temp & 0xffff0000) >> 16); - - /* Print out some CRTC/display information. */ - temp = INREG(HTOTAL_B); - ErrorF("Horiz active: %d, Horiz total: %d\n", temp & 0x7ff, - (temp >> 16) & 0xfff); - temp = INREG(HBLANK_B); - ErrorF("Horiz blank start: %d, Horiz blank end: %d\n", temp & 0xfff, - (temp >> 16) & 0xfff); - temp = INREG(HSYNC_B); - ErrorF("Horiz sync start: %d, Horiz sync end: %d\n", temp & 0xfff, - (temp >> 16) & 0xfff); - temp = INREG(VTOTAL_B); - ErrorF("Vert active: %d, Vert total: %d\n", temp & 0x7ff, - (temp >> 16) & 0xfff); - temp = INREG(VBLANK_B); - ErrorF("Vert blank start: %d, Vert blank end: %d\n", temp & 0xfff, - (temp >> 16) & 0xfff); - temp = INREG(VSYNC_B); - ErrorF("Vert sync start: %d, Vert sync end: %d\n", temp & 0xfff, - (temp >> 16) & 0xfff); - temp = INREG(PIPEBSRC); - ErrorF("Image size: %dx%d (%dx%d)\n", - (temp >> 16) & 0x7ff, temp & 0x7ff, - (((temp >> 16) & 0x7ff) + 1), ((temp & 0x7ff) + 1)); - ErrorF("Pixel multiply is %d\n", (planeA >> 20) & 0x3); - temp = INREG(DSPBBASE); - ErrorF("Plane B start offset is %d\n", temp); - temp = INREG(DSPBSTRIDE); - ErrorF("Plane B stride is %d bytes (%d pixels)\n", temp, temp / pI830->cpp); - temp = INREG(DSPBPOS); - ErrorF("Plane B position %d %d\n", temp & 0xffff, (temp & 0xffff0000) >> 16); - temp = INREG(DSPBSIZE); - ErrorF("Plane B size %d %d\n", temp & 0xffff, (temp & 0xffff0000) >> 16); -#endif - - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Mode bandwidth is %d Mpixel/s\n", - pMode->HDisplay * pMode->VDisplay * refresh / 1000000); - if (0) - { - int maxBandwidth, bandwidthA, bandwidthB; - - if (GetModeSupport(pScrn, 0x80, 0x80, 0x80, 0x80, - &maxBandwidth, &bandwidthA, &bandwidthB)) { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "maxBandwidth is %d Mbyte/s, " - "pipe bandwidths are %d Mbyte/s, %d Mbyte/s\n", - maxBandwidth, bandwidthA, bandwidthB); - } - } - -#if 0 - { - int ret; - - ret = GetLFPCompMode(pScrn); - if (ret != -1) { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "LFP compensation mode: 0x%x\n", ret); - } - } -#endif - -#if MODESWITCH_RESET_STATE - ResetState(pScrn, TRUE); - SetHWOperatingState(pScrn); -#endif - -#if 0 + OUTREG(FPA0, pI830->saveFPA0); + OUTREG(FPA1, pI830->saveFPA1); + OUTREG(DPLL_A, pI830->saveDPLL_A); if (IS_I965G(pI830)) - I965PrintErrorState(pScrn); - else - I830PrintErrorState(pScrn); -#endif + OUTREG(DPLL_A_MD, pI830->saveDPLL_A_MD); + OUTREG(HTOTAL_A, pI830->saveHTOTAL_A); + OUTREG(HBLANK_A, pI830->saveHBLANK_A); + OUTREG(HSYNC_A, pI830->saveHSYNC_A); + OUTREG(VTOTAL_A, pI830->saveVTOTAL_A); + OUTREG(VBLANK_A, pI830->saveVBLANK_A); + OUTREG(VSYNC_A, pI830->saveVSYNC_A); + OUTREG(DSPASTRIDE, pI830->saveDSPASTRIDE); + OUTREG(DSPASIZE, pI830->saveDSPASIZE); + OUTREG(DSPAPOS, pI830->saveDSPAPOS); + OUTREG(DSPABASE, pI830->saveDSPABASE); + OUTREG(PIPEASRC, pI830->savePIPEASRC); + for(i = 0; i < 256; i++) { + OUTREG(PALETTE_A + (i << 2), pI830->savePaletteA[i]); + } -#ifdef XF86DRI - if (didLock) - I830DRIUnlock(pScrn); -#endif + if(pI830->num_pipes == 2) { + OUTREG(FPB0, pI830->saveFPB0); + OUTREG(FPB1, pI830->saveFPB1); + OUTREG(DPLL_B, pI830->saveDPLL_B); + if (IS_I965G(pI830)) + OUTREG(DPLL_B_MD, pI830->saveDPLL_B_MD); + OUTREG(HTOTAL_B, pI830->saveHTOTAL_B); + OUTREG(HBLANK_B, pI830->saveHBLANK_B); + OUTREG(HSYNC_B, pI830->saveHSYNC_B); + OUTREG(VTOTAL_B, pI830->saveVTOTAL_B); + OUTREG(VBLANK_B, pI830->saveVBLANK_B); + OUTREG(VSYNC_B, pI830->saveVSYNC_B); + OUTREG(DSPBSTRIDE, pI830->saveDSPBSTRIDE); + OUTREG(DSPBSIZE, pI830->saveDSPBSIZE); + OUTREG(DSPBPOS, pI830->saveDSPBPOS); + OUTREG(DSPBBASE, pI830->saveDSPBBASE); + OUTREG(PIPEBSRC, pI830->savePIPEBSRC); + for(i= 0; i < 256; i++) { + OUTREG(PALETTE_B + (i << 2), pI830->savePaletteB[i]); + } + } + + OUTREG(PFIT_CONTROL, pI830->savePFIT_CONTROL); + + for (i = 0; i < pI830->num_outputs; i++) { + pI830->output[i].restore(pScrn, &pI830->output[i]); + } + + if (IS_I965G(pI830)) { + OUTREG(DSPASURF, pI830->saveDSPASURF); + OUTREG(DSPBSURF, pI830->saveDSPBSURF); + } + + OUTREG(VCLK_DIVISOR_VGA0, pI830->saveVCLK_DIVISOR_VGA0); + OUTREG(VCLK_DIVISOR_VGA1, pI830->saveVCLK_DIVISOR_VGA1); + OUTREG(VCLK_POST_DIV, pI830->saveVCLK_POST_DIV); + + OUTREG(PIPEACONF, pI830->savePIPEACONF); + OUTREG(PIPEBCONF, pI830->savePIPEBCONF); + + OUTREG(VGACNTRL, pI830->saveVGACNTRL); + OUTREG(DSPACNTR, pI830->saveDSPACNTR); + OUTREG(DSPBCNTR, pI830->saveDSPBCNTR); + + for(i = 0; i < 7; i++) { + OUTREG(SWF0 + (i << 2), pI830->saveSWF[i]); + OUTREG(SWF00 + (i << 2), pI830->saveSWF[i+7]); + } + + OUTREG(SWF30, pI830->saveSWF[14]); + OUTREG(SWF31, pI830->saveSWF[15]); + OUTREG(SWF32, pI830->saveSWF[16]); + + i830CompareRegsToSnapshot(pScrn); - pScrn->vtSema = TRUE; return TRUE; } @@ -7016,26 +2756,8 @@ I830CreateScreenResources (ScreenPtr pScreen) if (!(*pScreen->CreateScreenResources)(pScreen)) return FALSE; - if (xf86LoaderCheckSymbol("I830RandRSetConfig") && pI830->rotation != RR_Rotate_0) { - Rotation (*I830RandRSetConfig)(ScreenPtr pScreen, Rotation rr, int rate, RRScreenSizePtr pSize) = NULL; - RRScreenSize p; - Rotation requestedRotation = pI830->rotation; - - pI830->rotation = RR_Rotate_0; - - /* Just setup enough for an initial rotate */ - p.width = pScreen->width; - p.height = pScreen->height; - p.mmWidth = pScreen->mmWidth; - p.mmHeight = pScreen->mmHeight; - - I830RandRSetConfig = LoaderSymbol("I830RandRSetConfig"); - if (I830RandRSetConfig) { - pI830->starting = TRUE; /* abuse this for dual head & rotation */ - (*I830RandRSetConfig) (pScreen, requestedRotation, 0, &p); - pI830->starting = FALSE; - } - } + if (!I830RandRCreateScreenResources (pScreen)) + return FALSE; return TRUE; } @@ -7046,7 +2768,6 @@ I830InitFBManager( BoxPtr FullBox ){ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; - I830Ptr pI830 = I830PTR(pScrn); RegionRec ScreenRegion; RegionRec FullRegion; BoxRec ScreenBox; @@ -7055,7 +2776,7 @@ I830InitFBManager( ScreenBox.x1 = 0; ScreenBox.y1 = 0; ScreenBox.x2 = pScrn->displayWidth; - if (!pI830->MergedFB && pScrn->virtualX > pScrn->virtualY) + if (pScrn->virtualX > pScrn->virtualY) ScreenBox.y2 = pScrn->virtualX; else ScreenBox.y2 = pScrn->virtualY; @@ -7195,7 +2916,7 @@ static int I830DrmMMUnlock(int fd, unsigned memType) #endif static Bool -I830BIOSScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) +I830ScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) { ScrnInfoPtr pScrn; vgaHWPtr hwp; @@ -7262,17 +2983,6 @@ I830BIOSScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) } #endif - if (xf86IsEntityShared(pScrn->entityList[0])) { - /* PreInit failed on the second head, so make sure we turn it off */ - if (I830IsPrimary(pScrn) && !pI830->entityPrivate->pScrn_2) { - if (pI830->pipe == 0) { - pI830->operatingDevices &= 0xFF; - } else { - pI830->operatingDevices &= 0xFF00; - } - } - } - pI830->starting = TRUE; /* Alloc our pointers for the primary head */ @@ -7311,37 +3021,6 @@ I830BIOSScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) pI830->used3D = pI8301->used3D; } - /* - * If we're changing the BIOS's view of the video memory size, do that - * first, then re-initialise the VBE information. - */ - if (I830IsPrimary(pScrn)) { - SetPipeAccess(pScrn); - if (pI830->pVbe) - vbeFree(pI830->pVbe); - pI830->pVbe = VBEInit(NULL, pI830->pEnt->index); - } else { - pI830->pVbe = pI8301->pVbe; - } - - if (I830IsPrimary(pScrn)) { - if (!TweakMemorySize(pScrn, pI830->newBIOSMemSize,FALSE)) - SetBIOSMemSize(pScrn, pI830->newBIOSMemSize); - } - - if (!pI830->pVbe) - return FALSE; - - if (I830IsPrimary(pScrn)) { - if (pI830->vbeInfo) - VBEFreeVBEInfo(pI830->vbeInfo); - pI830->vbeInfo = VBEGetVBEInfo(pI830->pVbe); - } else { - pI830->vbeInfo = pI8301->vbeInfo; - } - - SetPipeAccess(pScrn); - miClearVisualTypes(); if (!miSetVisualTypes(pScrn->depth, miGetDefaultVisualMask(pScrn->depth), @@ -7493,14 +3172,14 @@ I830BIOSScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) if (!vgaHWMapMem(pScrn)) return FALSE; - /* Clear SavedReg */ - memset(&pI830->SavedReg, 0, sizeof(pI830->SavedReg)); + DPRINTF(PFX, "assert( if(!I830EnterVT(scrnIndex, 0)) )\n"); - DPRINTF(PFX, "assert( if(!I830BIOSEnterVT(scrnIndex, 0)) )\n"); - - if (!I830BIOSEnterVT(scrnIndex, 0)) + if (!I830EnterVT(scrnIndex, 0)) return FALSE; + if (pScrn->virtualX > pScrn->displayWidth) + pScrn->displayWidth = pScrn->virtualX; + DPRINTF(PFX, "assert( if(!fbScreenInit(pScreen, ...) )\n"); if (!fbScreenInit(pScreen, pI830->FbBase + pScrn->fbOffset, pScrn->virtualX, pScrn->virtualY, @@ -7610,27 +3289,11 @@ I830BIOSScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) xf86DrvMsg(pScrn->scrnIndex, X_INFO, "direct rendering: Not available\n"); #endif - pScreen->SaveScreen = I830BIOSSaveScreen; + pScreen->SaveScreen = I830SaveScreen; pI830->CloseScreen = pScreen->CloseScreen; - pScreen->CloseScreen = I830BIOSCloseScreen; + pScreen->CloseScreen = I830CloseScreen; - if (pI830->MergedFB) { - pI830->PointerMoved = pScrn->PointerMoved; - pScrn->PointerMoved = I830MergedPointerMoved; - - if(pI830->IntelXinerama) { - I830noPanoramiXExtension = FALSE; - I830XineramaExtensionInit(pScrn); - if(!I830noPanoramiXExtension) { - if(pI830->HaveNonRect) { - /* Reset the viewport (now eventually non-recangular) */ - I830AdjustFrame(scrnIndex, pScrn->frameX0, pScrn->frameY0, 0); - } - } - } else { - pI830->MouseRestrictions = FALSE; - } - } else if (pI830->shadowReq.minorversion >= 1) { + if (pI830->shadowReq.minorversion >= 1) { /* Rotation */ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "RandR enabled, ignore the following RandR disabled message.\n"); xf86DisableRandR(); /* Disable built-in RandR extension */ @@ -7650,9 +3313,6 @@ I830BIOSScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) xf86DrvMsg(pScrn->scrnIndex, X_INFO, "libshadow is version %d.%d.%d, required 1.1.0 or greater for rotation.\n",pI830->shadowReq.majorversion,pI830->shadowReq.minorversion,pI830->shadowReq.patchlevel); } - /* Call this unconditionally, as it also sets some fields in the SAREA */ - I830UpdateXineramaScreenInfo(pScrn); - if (serverGeneration == 1) xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options); @@ -7746,20 +3406,14 @@ I830BIOSScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) return TRUE; } - static void -I830AdjustFrame(int scrnIndex, int x, int y, int flags) +i830AdjustFrame(int scrnIndex, int x, int y, int flags) { - ScrnInfoPtr pScrn; - I830Ptr pI830; - vbeInfoPtr pVbe; - unsigned long Start; + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + I830Ptr pI830 = I830PTR(pScrn); + int i; - pScrn = xf86Screens[scrnIndex]; - pI830 = I830PTR(pScrn); - pVbe = pI830->pVbe; - - DPRINTF(PFX, "I830AdjustFrame: y = %d (+ %d), x = %d (+ %d)\n", + DPRINTF(PFX, "i830AdjustFrame: y = %d (+ %d), x = %d (+ %d)\n", x, pI830->xoffset, y, pI830->yoffset); /* Sync the engine before adjust frame */ @@ -7768,105 +3422,21 @@ I830AdjustFrame(int scrnIndex, int x, int y, int flags) pI830->AccelInfoRec->NeedToSync = FALSE; } - if (pI830->MergedFB) { - I830AdjustFrameMerged(scrnIndex, x, y, flags); - - if (pI830->pipe == 0) { - OUTREG(DSPABASE, pI830->FrontBuffer.Start + ((pI830->FirstframeY0 * pScrn->displayWidth + pI830->FirstframeX0) * pI830->cpp)); - OUTREG(DSPBBASE, pI830->FrontBuffer.Start + ((pI830->pScrn_2->frameY0 * pScrn->displayWidth + pI830->pScrn_2->frameX0) * pI830->cpp)); - } else { - OUTREG(DSPBBASE, pI830->FrontBuffer.Start + ((pI830->FirstframeY0 * pScrn->displayWidth + pI830->FirstframeX0) * pI830->cpp)); - OUTREG(DSPABASE, pI830->FrontBuffer.Start + ((pI830->pScrn_2->frameY0 * pScrn->displayWidth + pI830->pScrn_2->frameX0) * pI830->cpp)); - } - - return; - } - - if (I830IsPrimary(pScrn)) - Start = pI830->FrontBuffer.Start; - else { - I830Ptr pI8301 = I830PTR(pI830->entityPrivate->pScrn_1); - Start = pI8301->FrontBuffer2.Start; - } - - /* Sigh... - * It seems that there are quite a few Video BIOS' that get this wrong. - * So, we'll bypass the VBE call and hit the hardware directly. - */ - - if (pI830->Clone) { - if (!pI830->pipe == 0) { - if (!IS_I965G(pI830)) { - OUTREG(DSPABASE, Start + ((y * pScrn->displayWidth + x) * pI830->cpp)); - } else { - OUTREG(DSPABASE, 0); - OUTREG(DSPASURF, Start + ((y * pScrn->displayWidth + x) * pI830->cpp)); - } - } else { - if (!IS_I965G(pI830)) { - OUTREG(DSPBBASE, Start + ((y * pScrn->displayWidth + x) * pI830->cpp)); - } else { - OUTREG(DSPBBASE, 0); - OUTREG(DSPBSURF, Start + ((y * pScrn->displayWidth + x) * pI830->cpp)); - } - } - } - - if (pI830->pipe == 0) { - if (!IS_I965G(pI830)) { - OUTREG(DSPABASE, Start + ((y * pScrn->displayWidth + x) * pI830->cpp)); - } else { - OUTREG(DSPABASE, 0); - OUTREG(DSPASURF, Start + ((y * pScrn->displayWidth + x) * pI830->cpp)); - } - } else { - if (!IS_I965G(pI830)) { - OUTREG(DSPBBASE, Start + ((y * pScrn->displayWidth + x) * pI830->cpp)); - } else { - OUTREG(DSPBBASE, 0); - OUTREG(DSPBSURF, Start + ((y * pScrn->displayWidth + x) * pI830->cpp)); - } - } + for (i = 0; i < pI830->num_pipes; i++) + if (pI830->pipes[i].enabled) + i830PipeSetBase(pScrn, i, x, y); } static void -I830BIOSFreeScreen(int scrnIndex, int flags) +I830FreeScreen(int scrnIndex, int flags) { - I830BIOSFreeRec(xf86Screens[scrnIndex]); + I830FreeRec(xf86Screens[scrnIndex]); if (xf86LoaderCheckSymbol("vgaHWFreeHWRec")) vgaHWFreeHWRec(xf86Screens[scrnIndex]); } -#ifndef SAVERESTORE_HWSTATE -#define SAVERESTORE_HWSTATE 0 -#endif - -#if SAVERESTORE_HWSTATE static void -SaveHWOperatingState(ScrnInfoPtr pScrn) -{ - I830Ptr pI830 = I830PTR(pScrn); - I830RegPtr save = &pI830->SavedReg; - - DPRINTF(PFX, "SaveHWOperatingState\n"); - - return; -} - -static void -RestoreHWOperatingState(ScrnInfoPtr pScrn) -{ - I830Ptr pI830 = I830PTR(pScrn); - I830RegPtr save = &pI830->SavedReg; - - DPRINTF(PFX, "RestoreHWOperatingState\n"); - - return; -} -#endif - -static void -I830BIOSLeaveVT(int scrnIndex, int flags) +I830LeaveVT(int scrnIndex, int flags) { ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; I830Ptr pI830 = I830PTR(pScrn); @@ -7879,12 +3449,14 @@ I830BIOSLeaveVT(int scrnIndex, int flags) TimerCancel(pI830->devicesTimer); pI830->devicesTimer = NULL; + i830SetHotkeyControl(pScrn, HOTKEY_BIOS_SWITCH); + #ifdef I830_XV /* Give the video overlay code a chance to shutdown. */ I830VideoSwitchModeBefore(pScrn, NULL); #endif - if (pI830->Clone || pI830->MergedFB) { + if (pI830->Clone) { /* Ensure we don't try and setup modes on a clone head */ pI830->CloneHDisplay = 0; pI830->CloneVDisplay = 0; @@ -7913,339 +3485,27 @@ I830BIOSLeaveVT(int scrnIndex, int flags) } #endif -#if SAVERESTORE_HWSTATE - if (!pI830->closing) - SaveHWOperatingState(pScrn); -#endif - if (pI830->CursorInfoRec && pI830->CursorInfoRec->HideCursor) pI830->CursorInfoRec->HideCursor(pScrn); ResetState(pScrn, TRUE); - if (I830IsPrimary(pScrn)) { - if (!SetDisplayDevices(pScrn, pI830->savedDevices)) { - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "Failed to switch back to original display devices (0x%x)\n", - pI830->savedDevices); - } else { - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "Successfully set original devices\n"); - } - } - RestoreHWState(pScrn); - RestoreBIOSMemSize(pScrn); if (I830IsPrimary(pScrn)) I830UnbindAGPMemory(pScrn); if (pI830->AccelInfoRec) pI830->AccelInfoRec->NeedToSync = FALSE; - - /* DO IT AGAIN! AS IT SEEMS THAT SOME LFPs FLICKER OTHERWISE */ - if (I830IsPrimary(pScrn)) { - if (!SetDisplayDevices(pScrn, pI830->savedDevices)) { - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "Failed to switch back to original display devices (0x%x) (2)\n", - pI830->savedDevices); - } else { - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "Successfully set original devices (2)\n"); - } - } } -static Bool -I830DetectMonitorChange(ScrnInfoPtr pScrn) -{ - I830Ptr pI830 = I830PTR(pScrn); - pointer pDDCModule = NULL; - DisplayModePtr p, pMon; - int memsize; - int DDCclock = 0, DDCclock2 = 0; - int displayWidth = pScrn->displayWidth; - int curHDisplay = pScrn->currentMode->HDisplay; - int curVDisplay = pScrn->currentMode->VDisplay; - xf86MonPtr monitor = NULL; - - DPRINTF(PFX, "Detect Monitor Change\n"); - - SetPipeAccess(pScrn); - - /* Re-read EDID */ - pDDCModule = xf86LoadSubModule(pScrn, "ddc"); - - if (pI830->MergedFB) { - pI830->pVbe->ddc = DDC_UNCHECKED; - SetBIOSPipe(pScrn, !pI830->pipe); - monitor = vbeDoEDID(pI830->pVbe, pDDCModule); - if ((pI830->pScrn_2->monitor->DDC = monitor) != NULL) { - xf86PrintEDID(monitor); - xf86SetDDCproperties(pScrn, monitor); - } - SetPipeAccess(pScrn); - } - - pI830->pVbe->ddc = DDC_UNCHECKED; - monitor = vbeDoEDID(pI830->pVbe, pDDCModule); - xf86UnloadSubModule(pDDCModule); - if ((pScrn->monitor->DDC = monitor) != NULL) { - xf86PrintEDID(monitor); - xf86SetDDCproperties(pScrn, monitor); - } - - DDCclock = I830UseDDC(pScrn); - - /* Check if DDC exists on the second head, if not don't abort. */ - if (pI830->MergedFB) - DDCclock2 = I830UseDDC(pI830->pScrn_2); - - /* Revalidate the modes */ - - /* - * Note: VBE modes (> 0x7f) won't work with Intel's extended BIOS - * functions. - */ - SetPipeAccess(pScrn); - - pScrn->modePool = I830GetModePool(pScrn, pI830->pVbe, pI830->vbeInfo); - - if (!pScrn->modePool) { - /* This is bad, which would cause the Xserver to exit, maybe - * we should default to a 640x480 @ 60Hz mode here ??? */ - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, - "No Video BIOS modes for chosen depth.\n"); - return FALSE; - } - - if (pI830->MergedFB) { - SetBIOSPipe(pScrn, !pI830->pipe); - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Retrieving mode pool for second head.\n"); - pI830->pScrn_2->modePool = I830GetModePool(pI830->pScrn_2, pI830->pVbe, pI830->vbeInfo); - - if (!pI830->pScrn_2->modePool) { - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, - "No Video BIOS modes for chosen depth.\n"); - PreInitCleanup(pScrn); - return FALSE; - } - SetPipeAccess(pScrn); - } - - VBESetModeNames(pScrn->modePool); - if (pI830->MergedFB) - VBESetModeNames(pI830->pScrn_2->modePool); - - if (pScrn->videoRam > (pI830->vbeInfo->TotalMemory * 64)) - memsize = pI830->vbeInfo->TotalMemory * 64; - else - memsize = pScrn->videoRam; - - VBEValidateModes(pScrn, pScrn->monitor->Modes, pScrn->display->modes, NULL, - NULL, 0, MAX_DISPLAY_PITCH, 1, - 0, MAX_DISPLAY_HEIGHT, - pScrn->display->virtualX, - pScrn->display->virtualY, - memsize, LOOKUP_BEST_REFRESH); - - if (pI830->MergedFB) { - VBEValidateModes(pI830->pScrn_2, pI830->pScrn_2->monitor->Modes, - pI830->pScrn_2->display->modes, NULL, - NULL, 0, MAX_DISPLAY_PITCH, 1, - 0, MAX_DISPLAY_HEIGHT, - pScrn->display->virtualX, - pScrn->display->virtualY, - memsize, LOOKUP_BEST_REFRESH); - } - - if (DDCclock > 0) { - p = pScrn->modes; - if (p == NULL) - return FALSE; - do { - int Clock = 100000000; /* incredible value */ - - if (p->status == MODE_OK) { - for (pMon = pScrn->monitor->Modes; pMon != NULL; pMon = pMon->next) { - if ((pMon->HDisplay != p->HDisplay) || - (pMon->VDisplay != p->VDisplay) || - (pMon->Flags & (V_INTERLACE | V_DBLSCAN | V_CLKDIV2))) - continue; - - /* Find lowest supported Clock for this resolution */ - if (Clock > pMon->Clock) - Clock = pMon->Clock; - } - - if (Clock != 100000000 && DDCclock < 2550 && Clock / 1000.0 > DDCclock) { - ErrorF("(%s,%s) mode clock %gMHz exceeds DDC maximum %dMHz\n", - p->name, pScrn->monitor->id, - Clock/1000.0, DDCclock); - p->status = MODE_BAD; - } - } - p = p->next; - } while (p != NULL && p != pScrn->modes); - } - - /* Only use this if we've got DDC available */ - if (pI830->MergedFB && DDCclock2 > 0) { - p = pI830->pScrn_2->modes; - if (p == NULL) - return FALSE; - do { - int Clock = 100000000; /* incredible value */ - - if (p->status == MODE_OK) { - for (pMon = pI830->pScrn_2->monitor->Modes; pMon != NULL; pMon = pMon->next) { - if ((pMon->HDisplay != p->HDisplay) || - (pMon->VDisplay != p->VDisplay) || - (pMon->Flags & (V_INTERLACE | V_DBLSCAN | V_CLKDIV2))) - continue; - - /* Find lowest supported Clock for this resolution */ - if (Clock > pMon->Clock) - Clock = pMon->Clock; - } - - if (Clock != 100000000 && DDCclock2 < 2550 && Clock / 1000.0 > DDCclock2) { - ErrorF("(%s,%s) mode clock %gMHz exceeds DDC maximum %dMHz\n", - p->name, pI830->pScrn_2->monitor->id, - Clock/1000.0, DDCclock2); - p->status = MODE_BAD; - } - } - p = p->next; - } while (p != NULL && p != pI830->pScrn_2->modes); - } - - xf86PruneDriverModes(pScrn); - - if (pI830->MergedFB) - xf86PruneDriverModes(pI830->pScrn_2); - - if (pI830->MergedFB) { - DisplayModePtr old_modes, cur_mode; - - old_modes = pScrn->modes; - cur_mode = pScrn->currentMode; - - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "MergedFB: Generating mode list\n"); - - pScrn->modes = I830GenerateModeList(pScrn, pI830->MetaModes, - old_modes, pI830->pScrn_2->modes, - pI830->SecondPosition); - - if(!pScrn->modes) { - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No modes. Disabling MergedFB.\n"); - pScrn->modes = old_modes; - pScrn->currentMode = cur_mode; - pI830->MergedFB = FALSE; - } - } - - if (!pI830->vesa->useDefaultRefresh) - I830SetModeParameters(pScrn, pI830->pVbe); - - /* Now check if the previously used mode is o.k. for the current monitor. - * This allows VT switching to continue happily when not disconnecting - * and reconnecting monitors */ - - pScrn->currentMode = pScrn->modes; - - if (pI830->MergedFB) { - /* If no virtual dimension was given by the user, - * calculate a sane one now. Adapts pScrn->virtualX, - * pScrn->virtualY and pScrn->displayWidth. - */ - I830RecalcDefaultVirtualSize(pScrn); - - pScrn->modes = pScrn->modes->next; /* We get the last from GenerateModeList(), skip to first */ - pScrn->currentMode = pScrn->modes; - pI830->currentMode = pScrn->currentMode; - } - - pScrn->displayWidth = displayWidth; /* restore old displayWidth */ - - p = pScrn->modes; - if (p == NULL) - return FALSE; - do { - if ((p->HDisplay == curHDisplay) && - (p->VDisplay == curVDisplay) && - (!(p->Flags & (V_INTERLACE | V_DBLSCAN | V_CLKDIV2)))) { - pScrn->currentMode = p; /* previous mode is o.k. */ - } - p = p->next; - } while (p != NULL && p != pScrn->modes); - - I830PrintModes(pScrn); - - /* Now readjust for panning if necessary */ - { - pScrn->frameX0 = (pScrn->frameX0 + pScrn->frameX1 + 1 - pScrn->currentMode->HDisplay) / 2; - - if (pScrn->frameX0 < 0) - pScrn->frameX0 = 0; - - pScrn->frameX1 = pScrn->frameX0 + pScrn->currentMode->HDisplay - 1; - if (pScrn->frameX1 >= pScrn->virtualX) { - pScrn->frameX0 = pScrn->virtualX - pScrn->currentMode->HDisplay; - pScrn->frameX1 = pScrn->virtualX - 1; - } - - pScrn->frameY0 = (pScrn->frameY0 + pScrn->frameY1 + 1 - pScrn->currentMode->VDisplay) / 2; - - if (pScrn->frameY0 < 0) - pScrn->frameY0 = 0; - - pScrn->frameY1 = pScrn->frameY0 + pScrn->currentMode->VDisplay - 1; - if (pScrn->frameY1 >= pScrn->virtualY) { - pScrn->frameY0 = pScrn->virtualY - pScrn->currentMode->VDisplay; - pScrn->frameY1 = pScrn->virtualY - 1; - } - } - - if (pI830->MergedFB) - I830AdjustFrameMerged(pScrn->scrnIndex, pScrn->frameX0, pScrn->frameY0, 0); - - return TRUE; -} - -Bool -I830CheckModeSupport(ScrnInfoPtr pScrn, int x, int y, int mode) -{ - I830Ptr pI830 = I830PTR(pScrn); - Bool ret = TRUE; - - if (pI830->Clone) { - if (pI830->pipeDisplaySize[0].x2 != 0) { - if (x > pI830->pipeDisplaySize[0].x2 || - y > pI830->pipeDisplaySize[0].y2) { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Bad Clone Mode removing\n"); - return FALSE; - } - } - if (pI830->pipeDisplaySize[1].x2 != 0) { - if (x > pI830->pipeDisplaySize[1].x2 || - y > pI830->pipeDisplaySize[1].y2) { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Bad Clone Mode removing\n"); - return FALSE; - } - } - } - - return ret; -} - /* * This gets called when gaining control of the VT, and from ScreenInit(). */ static Bool -I830BIOSEnterVT(int scrnIndex, int flags) +I830EnterVT(int scrnIndex, int flags) { ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; - I830Ptr pI830 = I830PTR(pScrn); + I830Ptr pI830 = I830PTR(pScrn); + int i; DPRINTF(PFX, "Enter VT\n"); @@ -8266,67 +3526,42 @@ I830BIOSEnterVT(int scrnIndex, int flags) pScrn->virtualY * pScrn->displayWidth * pI830->cpp); #endif - if (I830IsPrimary(pScrn)) { - /* - * This is needed for restoring from ACPI modes (especially S3) - * so that we warmboot the Video BIOS. Some platforms have problems, - * warm booting when we don't need to, so check that we can call - * the Video BIOS with our saved devices, and only when that fails, - * we'll warm boot it. - */ - /* Check Pipe conf registers or possibly HTOTAL/VTOTAL for 0x00000000)*/ - CARD32 temp; - Bool set = I830Set640x480(pScrn); - temp = pI830->pipe ? INREG(PIPEBCONF) : INREG(PIPEACONF); - if (!set || !(temp & 0x80000000)) { - xf86Int10InfoPtr pInt; - - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Detected resume, re-POSTing.\n"); - - pInt = xf86InitInt10(pI830->pEnt->index); - - /* Now perform our warm boot */ - if (pInt) { - pInt->num = 0xe6; - xf86ExecX86int10 (pInt); - xf86FreeInt10 (pInt); - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Re-POSTing via int10.\n"); - } else { - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "Re-POSTing via int10 failed, trying to continue.\n"); - } - } - - /* Finally, re-setup the display devices */ - if (!SetDisplayDevices(pScrn, pI830->operatingDevices)) { - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "Failed to switch to configured display devices\n"); - return FALSE; - } - } - - /* Setup for device monitoring status */ - pI830->monitorSwitch = pI830->toggleDevices = INREG(SWF0) & 0x0000FFFF; - if (I830IsPrimary(pScrn)) if (!I830BindAGPMemory(pScrn)) return FALSE; CheckInheritedState(pScrn); - if (I830IsPrimary(pScrn)) { - if (!TweakMemorySize(pScrn, pI830->newBIOSMemSize,FALSE)) - SetBIOSMemSize(pScrn, pI830->newBIOSMemSize); - } ResetState(pScrn, FALSE); SetHWOperatingState(pScrn); - if (!pI830->starting) - I830DetectMonitorChange(pScrn); - - if (!I830VESASetMode(pScrn, pScrn->currentMode)) + for (i = 0; i < pI830->num_pipes; i++) + { + I830PipePtr pipe = &pI830->pipes[i]; + /* Mark that we'll need to re-set the mode for sure */ + memset(&pipe->curMode, 0, sizeof(pipe->curMode)); + if (!pipe->desiredMode.CrtcHDisplay) + { + pipe->desiredMode = *i830PipeFindClosestMode (pScrn, i, + pScrn->currentMode); + } + if (!i830PipeSetMode (pScrn, &pipe->desiredMode, i, TRUE)) + return FALSE; + i830PipeSetBase(pScrn, i, pipe->x, pipe->y); + } + + i830DisableUnusedFunctions(pScrn); + + i830DescribeOutputConfiguration(pScrn); + +#ifdef XF86DRI + I830DRISetVBlankInterrupt (pScrn, TRUE); +#endif + +#if 0 + if (!i830SetMode(pScrn, pScrn->currentMode)) return FALSE; +#endif #ifdef I830_XV I830VideoSwitchModeAfter(pScrn, pScrn->currentMode); @@ -8337,10 +3572,6 @@ I830BIOSEnterVT(int scrnIndex, int flags) pScrn->AdjustFrame(scrnIndex, pScrn->frameX0, pScrn->frameY0, 0); -#if SAVERESTORE_HWSTATE - RestoreHWOperatingState(pScrn); -#endif - #ifdef XF86DRI if (pI830->directRenderingEnabled) { @@ -8376,6 +3607,13 @@ I830BIOSEnterVT(int scrnIndex, int flags) } #endif + /* Set the hotkey to just notify us. We can check its results periodically + * in the CheckDevicesTimer. Eventually we want the kernel to just hand us + * an input event when someone presses the button, but for now we just have + * to poll. + */ + i830SetHotkeyControl(pScrn, HOTKEY_DRIVER_NOTIFY); + /* Needed for rotation */ IntelEmitInvarientState(pScrn); @@ -8391,7 +3629,7 @@ I830BIOSEnterVT(int scrnIndex, int flags) } static Bool -I830BIOSSwitchMode(int scrnIndex, DisplayModePtr mode, int flags) +I830SwitchMode(int scrnIndex, DisplayModePtr mode, int flags) { ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; @@ -8399,7 +3637,7 @@ I830BIOSSwitchMode(int scrnIndex, DisplayModePtr mode, int flags) Bool ret = TRUE; PixmapPtr pspix = (*pScrn->pScreen->GetScreenPixmap) (pScrn->pScreen); - DPRINTF(PFX, "I830BIOSSwitchMode: mode == %p\n", mode); + DPRINTF(PFX, "I830SwitchMode: mode == %p\n", mode); #ifdef I830_XV /* Give the video overlay code a chance to see the new mode. */ @@ -8416,7 +3654,7 @@ I830BIOSSwitchMode(int scrnIndex, DisplayModePtr mode, int flags) * are rotating, we don't need to call the mode setup again. */ if (pI830->currentMode != mode) { - if (!I830VESASetMode(pScrn, mode)) + if (!i830SetMode(pScrn, mode)) ret = FALSE; } @@ -8438,7 +3676,7 @@ I830BIOSSwitchMode(int scrnIndex, DisplayModePtr mode, int flags) * video mode here, as we'll have already re-instated the original rotation. */ if (!ret) { - if (!I830VESASetMode(pScrn, pI830->currentMode)) { + if (!i830SetMode(pScrn, pI830->currentMode)) { xf86DrvMsg(scrnIndex, X_INFO, "Failed to restore previous mode (SwitchMode)\n"); } @@ -8456,49 +3694,46 @@ I830BIOSSwitchMode(int scrnIndex, DisplayModePtr mode, int flags) #endif } - /* Since RandR (indirectly) uses SwitchMode(), we need to - * update our Xinerama info here, too, in case of resizing - * Call this unconditionally, as it also sets some fields in the SAREA - */ - I830UpdateXineramaScreenInfo(pScrn); - return ret; } static Bool -I830BIOSSaveScreen(ScreenPtr pScreen, int mode) +I830SaveScreen(ScreenPtr pScreen, int mode) { ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; I830Ptr pI830 = I830PTR(pScrn); Bool on = xf86IsUnblank(mode); CARD32 temp, ctrl, base, surf; + int i; - DPRINTF(PFX, "I830BIOSSaveScreen: %d, on is %s\n", mode, BOOLTOSTRING(on)); + DPRINTF(PFX, "I830SaveScreen: %d, on is %s\n", mode, BOOLTOSTRING(on)); if (pScrn->vtSema) { - if (pI830->pipe == 0) { - ctrl = DSPACNTR; - base = DSPABASE; - surf = DSPASURF; - } else { - ctrl = DSPBCNTR; - base = DSPBADDR; - surf = DSPBSURF; - } - if (pI830->planeEnabled[pI830->pipe]) { - temp = INREG(ctrl); - if (on) - temp |= DISPLAY_PLANE_ENABLE; - else - temp &= ~DISPLAY_PLANE_ENABLE; - OUTREG(ctrl, temp); - /* Flush changes */ - temp = INREG(base); - OUTREG(base, temp); - if (IS_I965G(pI830)) { - temp = INREG(surf); - OUTREG(surf, temp); - } + for (i = 0; i < pI830->num_pipes; i++) { + if (i == 0) { + ctrl = DSPACNTR; + base = DSPABASE; + surf = DSPASURF; + } else { + ctrl = DSPBCNTR; + base = DSPBADDR; + surf = DSPBSURF; + } + if (pI830->pipes[i].enabled) { + temp = INREG(ctrl); + if (on) + temp |= DISPLAY_PLANE_ENABLE; + else + temp &= ~DISPLAY_PLANE_ENABLE; + OUTREG(ctrl, temp); + /* Flush changes */ + temp = INREG(base); + OUTREG(base, temp); + if (IS_I965G(pI830)) { + temp = INREG(surf); + OUTREG(surf, temp); + } + } } if (pI830->CursorInfoRec && !pI830->SWCursor && pI830->cursorOn) { @@ -8518,62 +3753,45 @@ I830DisplayPowerManagementSet(ScrnInfoPtr pScrn, int PowerManagementMode, int flags) { I830Ptr pI830 = I830PTR(pScrn); - vbeInfoPtr pVbe = pI830->pVbe; + int i; + CARD32 temp, ctrl, base; - if (pI830->Clone || pI830->MergedFB) { - SetBIOSPipe(pScrn, !pI830->pipe); - if (xf86LoaderCheckSymbol("VBEDPMSSet")) { - VBEDPMSSet(pVbe, PowerManagementMode); + for (i = 0; i < pI830->num_outputs; i++) { + pI830->output[i].dpms(pScrn, &pI830->output[i], PowerManagementMode); + } + + for (i = 0; i < pI830->num_pipes; i++) { + if (i == 0) { + ctrl = DSPACNTR; + base = DSPABASE; } else { - pVbe->pInt10->num = 0x10; - pVbe->pInt10->ax = 0x4f10; - pVbe->pInt10->bx = 0x01; - - switch (PowerManagementMode) { - case DPMSModeOn: - break; - case DPMSModeStandby: - pVbe->pInt10->bx |= 0x0100; - break; - case DPMSModeSuspend: - pVbe->pInt10->bx |= 0x0200; - break; - case DPMSModeOff: - pVbe->pInt10->bx |= 0x0400; - break; - } - xf86ExecX86int10_wrapper(pVbe->pInt10, pScrn); + ctrl = DSPBCNTR; + base = DSPBADDR; + } + if (pI830->pipes[i].enabled) { + temp = INREG(ctrl); + if (PowerManagementMode == DPMSModeOn) + temp |= DISPLAY_PLANE_ENABLE; + else + temp &= ~DISPLAY_PLANE_ENABLE; + OUTREG(ctrl, temp); + /* Flush changes */ + temp = INREG(base); + OUTREG(base, temp); } } - SetPipeAccess(pScrn); - - if (xf86LoaderCheckSymbol("VBEDPMSSet")) { - VBEDPMSSet(pVbe, PowerManagementMode); - } else { - pVbe->pInt10->num = 0x10; - pVbe->pInt10->ax = 0x4f10; - pVbe->pInt10->bx = 0x01; - - switch (PowerManagementMode) { - case DPMSModeOn: - break; - case DPMSModeStandby: - pVbe->pInt10->bx |= 0x0100; - break; - case DPMSModeSuspend: - pVbe->pInt10->bx |= 0x0200; - break; - case DPMSModeOff: - pVbe->pInt10->bx |= 0x0400; - break; - } - xf86ExecX86int10_wrapper(pVbe->pInt10, pScrn); + if (pI830->CursorInfoRec && !pI830->SWCursor && pI830->cursorOn) { + if (PowerManagementMode == DPMSModeOn) + pI830->CursorInfoRec->ShowCursor(pScrn); + else + pI830->CursorInfoRec->HideCursor(pScrn); + pI830->cursorOn = TRUE; } } static Bool -I830BIOSCloseScreen(int scrnIndex, ScreenPtr pScreen) +I830CloseScreen(int scrnIndex, ScreenPtr pScreen) { ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; I830Ptr pI830 = I830PTR(pScrn); @@ -8595,7 +3813,7 @@ I830BIOSCloseScreen(int scrnIndex, ScreenPtr pScreen) #endif if (pScrn->vtSema == TRUE) { - I830BIOSLeaveVT(scrnIndex, 0); + I830LeaveVT(scrnIndex, 0); } if (pI830->devicesTimer) @@ -8730,15 +3948,6 @@ I830PMEvent(int scrnIndex, pmEvent event, Bool undo) ErrorF("I830PMEvent: Capability change\n"); - /* ACPI Toggle */ - pI830->toggleDevices = GetNextDisplayDeviceList(pScrn, 1); - if (xf86IsEntityShared(pScrn->entityList[0])) { - I830Ptr pI8302 = I830PTR(pI830->entityPrivate->pScrn_2); - pI8302->toggleDevices = pI830->toggleDevices; - } - - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "ACPI Toggle to 0x%x\n",pI830->toggleDevices); - I830CheckDevicesTimer(NULL, 0, pScrn); SaveScreens(SCREEN_SAVER_FORCER, ScreenSaverReset); break; @@ -8748,338 +3957,87 @@ I830PMEvent(int scrnIndex, pmEvent event, Bool undo) return TRUE; } -static int CountBits(int a) +#if 0 +/** + * This function is used for testing of the screen detect functions from the + * periodic timer. + */ +static void +i830MonitorDetectDebugger(ScrnInfoPtr pScrn) { - int i; - int b = 0; + Bool found_crt; + I830Ptr pI830 = I830PTR(pScrn); + int start, finish, i; - for (i=0;i<8;i++) { - if (a & (1<vtSema) + return 1000; + + for (i = 0; i < pI830->num_outputs; i++) { + enum output_status ret; + char *result; + + start = GetTimeInMillis(); + ret = pI830->output[i].detect(pScrn, &pI830->output[i]); + finish = GetTimeInMillis(); + + if (ret == OUTPUT_STATUS_CONNECTED) + result = "connected"; + else if (ret == OUTPUT_STATUS_DISCONNECTED) + result = "disconnected"; + else + result = "unknown"; + + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Detected SDVO as %s in %dms\n", + result, finish - start); } - - return b; } +#endif static CARD32 I830CheckDevicesTimer(OsTimerPtr timer, CARD32 now, pointer arg) { ScrnInfoPtr pScrn = (ScrnInfoPtr) arg; I830Ptr pI830 = I830PTR(pScrn); - int cloned = 0; + CARD8 gr18; - if (pScrn->vtSema) { - /* Check for monitor lid being closed/opened and act accordingly */ - CARD32 adjust; - CARD32 temp = INREG(SWF0) & 0x0000FFFF; - int fixup = 0; - I830Ptr pI8301; - I830Ptr pI8302 = NULL; - - if (I830IsPrimary(pScrn)) - pI8301 = pI830; - else - pI8301 = I830PTR(pI830->entityPrivate->pScrn_1); - - if (xf86IsEntityShared(pScrn->entityList[0])) - pI8302 = I830PTR(pI830->entityPrivate->pScrn_2); - - /* this avoids several BIOS calls if possible */ - if (pI830->monitorSwitch != temp || pI830->monitorSwitch != pI830->toggleDevices) { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Hotkey switch to 0x%lx.\n", (unsigned long) temp); - - if (pI830->AccelInfoRec && pI830->AccelInfoRec->NeedToSync) { - (*pI830->AccelInfoRec->Sync)(pScrn); - pI830->AccelInfoRec->NeedToSync = FALSE; - if (xf86IsEntityShared(pScrn->entityList[0])) - pI8302->AccelInfoRec->NeedToSync = FALSE; - } - - GetAttachableDisplayDeviceList(pScrn); - - pI8301->lastDevice0 = pI8301->lastDevice1; - pI8301->lastDevice1 = pI8301->lastDevice2; - pI8301->lastDevice2 = pI8301->monitorSwitch; - - if (temp != pI8301->lastDevice1 && - temp != pI8301->lastDevice2) { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Detected three device configs.\n"); - } else - if (CountBits(temp & 0xff) > 1) { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Detected cloned pipe mode (A).\n"); - if (xf86IsEntityShared(pScrn->entityList[0]) || pI830->Clone) - temp = pI8301->MonType2 << 8 | pI8301->MonType1; - } else - if (CountBits((temp & 0xff00) >> 8) > 1) { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Detected cloned pipe mode (B).\n"); - if (xf86IsEntityShared(pScrn->entityList[0]) || pI830->Clone) - temp = pI8301->MonType2 << 8 | pI8301->MonType1; - } else - if (pI8301->lastDevice1 && pI8301->lastDevice2) { - if ( ((pI8301->lastDevice1 & 0xFF00) == 0) && - ((pI8301->lastDevice2 & 0x00FF) == 0) ) { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Detected last devices (1).\n"); - cloned = 1; - } else if ( ((pI8301->lastDevice2 & 0xFF00) == 0) && - ((pI8301->lastDevice1 & 0x00FF) == 0) ) { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Detected last devices (2).\n"); - cloned = 1; - } else - cloned = 0; - } - - if (cloned && - ((CountBits(pI8301->lastDevice1 & 0xff) > 1) || - ((CountBits((pI8301->lastDevice1 & 0xff00) >> 8) > 1))) ) { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Detected duplicate (1).\n"); - cloned = 0; - } else - if (cloned && - ((CountBits(pI8301->lastDevice2 & 0xff) > 1) || - ((CountBits((pI8301->lastDevice2 & 0xff00) >> 8) > 1))) ) { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Detected duplicate (2).\n"); - cloned = 0; - } - - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Requested display devices 0x%lx.\n", - (unsigned long) temp); - - - /* If the BIOS doesn't flip between CRT, LFP and CRT+LFP we fake - * it here as it seems some just flip between CRT and LFP. Ugh! - * - * So this pushes them onto Pipe B and clones the displays, which - * is what most BIOS' should be doing. - * - * Cloned pipe mode should only be done when running single head. - */ - if (xf86IsEntityShared(pScrn->entityList[0])) { - cloned = 0; - - /* Some BIOS' don't realize we may be in true dual head mode. - * And only display the primary output on both when switching. - * We detect this here and cycle back to both pipes. - */ - if ((pI830->lastDevice0 == temp) && - ((CountBits(pI8301->lastDevice2 & 0xff) > 1) || - ((CountBits((pI8301->lastDevice2 & 0xff00) >> 8) > 1))) ) { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Detected cloned pipe mode when dual head on previous switch. (0x%x -> 0x%x)\n", (int)temp, pI8301->MonType2 << 8 | pI8301->MonType1); - temp = pI8301->MonType2 << 8 | pI8301->MonType1; - } - - } - - if (cloned) { - if (pI830->Clone) - temp = pI8301->MonType2 << 8 | pI8301->MonType1; - else if (pI8301->lastDevice1 & 0xFF) - temp = pI8301->lastDevice1 << 8 | pI8301->lastDevice2; - else - temp = pI8301->lastDevice2 << 8 | pI8301->lastDevice1; - } - - /* Jump to our next mode if we detect we've been here before */ - if (temp == pI8301->lastDevice1 || temp == pI8301->lastDevice2) { - temp = GetToggleList(pScrn, 1); - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Detected duplicate devices. Toggling (0x%lx)\n", - (unsigned long) temp); - } - - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Detected display change operation (0x%x, 0x%x, 0x%lx).\n", - pI8301->lastDevice1, pI8301->lastDevice2, - (unsigned long) temp); - - /* So that if we close on the wrong config, we restore correctly */ - pI830->specifiedMonitor = TRUE; - - if (!xf86IsEntityShared(pScrn->entityList[0])) { - if ((temp & 0xFF00) && (temp & 0x00FF)) { - pI830->Clone = TRUE; - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Setting Clone mode\n"); - } else { - pI830->Clone = FALSE; - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Clearing Clone mode\n"); - } - } - - { - /* Turn Cursor off before switching */ - Bool on = pI830->cursorOn; - if (pI830->CursorInfoRec && pI830->CursorInfoRec->HideCursor) - pI830->CursorInfoRec->HideCursor(pScrn); - pI830->cursorOn = on; - } - - /* double check the display devices are what's configured and try - * not to do it twice because of dual heads with the code above */ - if (!SetDisplayDevices(pScrn, temp)) { - if ( cloned && - ((CountBits(temp & 0xff) > 1) || - (CountBits((temp & 0xff00) >> 8) > 1)) ) { - temp = pI8301->lastDevice2 | pI8301->lastDevice1; - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Cloning failed, " - "trying dual pipe clone mode (0x%lx)\n", - (unsigned long) temp); - if (!SetDisplayDevices(pScrn, temp)) - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Failed to switch " - "to configured display devices (0x%lx).\n", - (unsigned long) temp); - else { - pI830->Clone = TRUE; - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Setting Clone mode\n"); - } - } - } - - pI8301->monitorSwitch = temp; - pI8301->operatingDevices = temp; - pI8301->toggleDevices = temp; - - if (xf86IsEntityShared(pScrn->entityList[0])) { - pI8302->operatingDevices = pI8301->operatingDevices; - pI8302->monitorSwitch = pI8301->monitorSwitch; - pI8302->toggleDevices = pI8301->toggleDevices; - } - - fixup = 1; + if (!pScrn->vtSema) + return 1000; #if 0 - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "ACPI _DGS queried devices is 0x%x, but probed is 0x%x monitorSwitch=0x%x\n", - pI830->toggleDevices, INREG(SWF0), pI830->monitorSwitch); + i830MonitorDetectDebugger(pScrn); #endif - } else { - int offset = -1; - if (I830IsPrimary(pScrn)) - offset = pI8301->FrontBuffer.Start + ((pScrn->frameY0 * pI830->displayWidth + pScrn->frameX0) * pI830->cpp); - else { - offset = pI8301->FrontBuffer2.Start + ((pScrn->frameY0 * pI830->displayWidth + pScrn->frameX0) * pI830->cpp); - } - if (IS_I965G(pI830)) { - if (pI830->pipe == 0) - adjust = INREG(DSPASURF); - else - adjust = INREG(DSPBSURF); - } else { - if (pI830->pipe == 0) - adjust = INREG(DSPABASE); - else - adjust = INREG(DSPBBASE); - } + /* Check for a hotkey press report from the BIOS. */ + gr18 = pI830->readControl(pI830, GRX, 0x18); + if ((gr18 & (HOTKEY_TOGGLE | HOTKEY_SWITCH)) != 0) { + /* The user has pressed the hotkey requesting a toggle or switch. + * Re-probe our connected displays and turn on whatever we find. + * + * In the future, we want the hotkey to dump down to a user app which + * implements a sensible policy using RandR-1.2. For now, all we get + * is this. + */ + I830ValidateXF86ModeList(pScrn, FALSE); + xf86SwitchMode(pScrn->pScreen, pScrn->currentMode); - if (adjust != offset) { - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "Fixing display offsets.\n"); - - I830AdjustFrame(pScrn->pScreen->myNum, pScrn->frameX0, pScrn->frameY0, 0); - } - } - - if (fixup) { - ScreenPtr pCursorScreen; - int x = 0, y = 0; - - pCursorScreen = miPointerCurrentScreen(); - if (pScrn->pScreen == pCursorScreen) - miPointerPosition(&x, &y); - - /* Now, when we're single head, make sure we switch pipes */ - if (!(xf86IsEntityShared(pScrn->entityList[0]) || pI830->Clone) || cloned) { - if (temp & 0xFF00) - pI830->pipe = 1; - else - pI830->pipe = 0; - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Primary pipe is now %s.\n", pI830->pipe ? "B" : "A"); - } - - pI830->currentMode = NULL; - I830BIOSSwitchMode(pScrn->pScreen->myNum, pScrn->currentMode, 0); - I830AdjustFrame(pScrn->pScreen->myNum, pScrn->frameX0, pScrn->frameY0, 0); - - if (xf86IsEntityShared(pScrn->entityList[0])) { - ScrnInfoPtr pScrn2; - I830Ptr pI8302; - - if (I830IsPrimary(pScrn)) { - pScrn2 = pI830->entityPrivate->pScrn_2; - pI8302 = I830PTR(pI830->entityPrivate->pScrn_2); - } else { - pScrn2 = pI830->entityPrivate->pScrn_1; - pI8302 = I830PTR(pI830->entityPrivate->pScrn_1); - } - - if (pScrn2->pScreen == pCursorScreen) - miPointerPosition(&x, &y); - - pI8302->currentMode = NULL; - I830BIOSSwitchMode(pScrn2->pScreen->myNum, pScrn2->currentMode, 0); - I830AdjustFrame(pScrn2->pScreen->myNum, pScrn2->frameX0, pScrn2->frameY0, 0); - - (*pScrn2->EnableDisableFBAccess) (pScrn2->pScreen->myNum, FALSE); - (*pScrn2->EnableDisableFBAccess) (pScrn2->pScreen->myNum, TRUE); - - if (pScrn2->pScreen == pCursorScreen) { - int sigstate = xf86BlockSIGIO (); - miPointerWarpCursor(pScrn2->pScreen,x,y); - - /* xf86Info.currentScreen = pScrn->pScreen; */ - xf86UnblockSIGIO (sigstate); - if (pI8302->CursorInfoRec && !pI8302->SWCursor && pI8302->cursorOn) { - pI8302->CursorInfoRec->HideCursor(pScrn); - xf86SetCursor(pScrn2->pScreen, pI830->pCurs, x, y); - pI8302->CursorInfoRec->ShowCursor(pScrn); - pI8302->cursorOn = TRUE; - } - } - } - - (*pScrn->EnableDisableFBAccess) (pScrn->pScreen->myNum, FALSE); - (*pScrn->EnableDisableFBAccess) (pScrn->pScreen->myNum, TRUE); - - if (pScrn->pScreen == pCursorScreen) { - int sigstate = xf86BlockSIGIO (); - miPointerWarpCursor(pScrn->pScreen,x,y); - - /* xf86Info.currentScreen = pScrn->pScreen; */ - xf86UnblockSIGIO (sigstate); - if (pI830->CursorInfoRec && !pI830->SWCursor && pI830->cursorOn) { - pI830->CursorInfoRec->HideCursor(pScrn); - xf86SetCursor(pScrn->pScreen, pI830->pCurs, x, y); - pI830->CursorInfoRec->ShowCursor(pScrn); - pI830->cursorOn = TRUE; - } - } - } + /* Clear the BIOS's hotkey press flags */ + gr18 &= ~(HOTKEY_TOGGLE | HOTKEY_SWITCH); + pI830->writeControl(pI830, GRX, 0x18, gr18); } - return 1000; } void I830InitpScrn(ScrnInfoPtr pScrn) { - pScrn->PreInit = I830BIOSPreInit; - pScrn->ScreenInit = I830BIOSScreenInit; - pScrn->SwitchMode = I830BIOSSwitchMode; - pScrn->AdjustFrame = I830AdjustFrame; - pScrn->EnterVT = I830BIOSEnterVT; - pScrn->LeaveVT = I830BIOSLeaveVT; - pScrn->FreeScreen = I830BIOSFreeScreen; + pScrn->PreInit = I830PreInit; + pScrn->ScreenInit = I830ScreenInit; + pScrn->SwitchMode = I830SwitchMode; + pScrn->AdjustFrame = i830AdjustFrame; + pScrn->EnterVT = I830EnterVT; + pScrn->LeaveVT = I830LeaveVT; + pScrn->FreeScreen = I830FreeScreen; pScrn->ValidMode = I830ValidMode; pScrn->PMEvent = I830PMEvent; } diff --git a/src/i830_dvo.c b/src/i830_dvo.c new file mode 100644 index 00000000..31fb76ba --- /dev/null +++ b/src/i830_dvo.c @@ -0,0 +1,236 @@ +/************************************************************************** + +Copyright 2006 Dave Airlie + +All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +on the rights to use, copy, modify, merge, publish, distribute, sub +license, and/or sell copies of the Software, and to permit persons to whom +the Software is furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice (including the next +paragraph) shall be included in all copies or substantial portions of the +Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +THE COPYRIGHT HOLDERS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +USE OR OTHER DEALINGS IN THE SOFTWARE. + +****** +********************************************************************/ + +#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++; +} diff --git a/src/i830_gtf.c b/src/i830_gtf.c new file mode 100644 index 00000000..523e167a --- /dev/null +++ b/src/i830_gtf.c @@ -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 + * + * $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 + * to support extended BIOS modes for the Intel chipsets + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include "xf86.h" +#include "vbe.h" +#include "vbeModes.h" +#include "i830.h" +#include "i830_xf86Modes.h" + +#include + +#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); +} diff --git a/src/i830_i2c.c b/src/i830_i2c.c new file mode 100644 index 00000000..8b93c8e6 --- /dev/null +++ b/src/i830_i2c.c @@ -0,0 +1,324 @@ +/************************************************************************** + + Copyright 2006 Dave Airlie + +All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +on the rights to use, copy, modify, merge, publish, distribute, sub +license, and/or sell copies of the Software, and to permit persons to whom +the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice (including the next +paragraph) shall be included in all copies or substantial portions of the +Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +THE COPYRIGHT HOLDERS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +USE OR OTHER DEALINGS IN THE SOFTWARE. + +**************************************************************************/ + +#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 +#include "fb.h" +#include "miscstruct.h" +#include "xf86xv.h" +#include +#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; +} diff --git a/src/i830_lvds.c b/src/i830_lvds.c new file mode 100644 index 00000000..ea45420f --- /dev/null +++ b/src/i830_lvds.c @@ -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 + * + */ + +#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++; +} diff --git a/src/i830_memory.c b/src/i830_memory.c index 09ef5be8..52131775 100644 --- a/src/i830_memory.c +++ b/src/i830_memory.c @@ -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; diff --git a/src/i830_modes.c b/src/i830_modes.c index 7d145198..7fdd40ed 100644 --- a/src/i830_modes.c +++ b/src/i830_modes.c @@ -1,6 +1,9 @@ +/* -*- c-basic-offset: 4 -*- */ + #define DEBUG_VERB 2 /* * Copyright © 2002 David Dawes + * 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"), @@ -26,6 +29,7 @@ * the author(s). * * Authors: David Dawes + * Eric Anholt * * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/vbe/vbeModes.c,v 1.6 2002/11/02 01:38:25 dawes Exp $ */ @@ -40,14 +44,20 @@ #include #include - -#include "xf86.h" -#include "i830.h" - +#include #include +#include "xf86.h" +#include "X11/Xatom.h" +#include "i830.h" +#include "i830_display.h" +#include "i830_xf86Modes.h" +#include + #define rint(x) floor(x) +#define MAX(a,b) ((a) > (b) ? (a) : (b)) + #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 */ @@ -63,725 +73,32 @@ #define C_PRIME (((C - J) * K/256.0) + J) #define M_PRIME (K/256.0 * M) - -extern const int i830refreshes[]; - -static DisplayModePtr -I830GetGTF (int h_pixels, int v_lines, float freq, - int interlaced, int margins) +/* Established timings from EDID standard */ +static struct { - 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; - char modename[20]; - 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 */; - - snprintf(modename, sizeof(modename), "%dx%d", m->HDisplay,m->VDisplay); - m->name = xnfstrdup(modename); - - return (m); -} - -static DisplayModePtr -CheckMode(ScrnInfoPtr pScrn, vbeInfoPtr pVbe, VbeInfoBlock *vbe, int id, - int flags) -{ - CARD16 major, minor; - VbeModeInfoBlock *mode; - DisplayModePtr p = NULL, pMode = NULL; -#if 0 - VbeModeInfoData *data; -#else - I830ModePrivatePtr data; -#endif - Bool modeOK = FALSE; - ModeStatus status = MODE_OK; - - major = (unsigned)(vbe->VESAVersion >> 8); - minor = vbe->VESAVersion & 0xff; - - if ((mode = VBEGetModeInfo(pVbe, id)) == NULL) - return NULL; - - /* Does the mode match the depth/bpp? */ - /* Some BIOS's set BitsPerPixel to 15 instead of 16 for 15/16 */ - if (VBE_MODE_USABLE(mode, flags) && - ((pScrn->bitsPerPixel == 1 && !VBE_MODE_COLOR(mode)) || - (mode->BitsPerPixel > 8 && - (mode->RedMaskSize + mode->GreenMaskSize + - mode->BlueMaskSize) == pScrn->depth && - mode->BitsPerPixel == pScrn->bitsPerPixel) || - (mode->BitsPerPixel == 15 && pScrn->depth == 15) || - (mode->BitsPerPixel <= 8 && - mode->BitsPerPixel == pScrn->bitsPerPixel))) { - modeOK = TRUE; - xf86ErrorFVerb(DEBUG_VERB, "*"); - } - - if (mode->XResolution && mode->YResolution && - !I830CheckModeSupport(pScrn, mode->XResolution, mode->YResolution, id)) - modeOK = FALSE; - - - /* - * Check if there's a valid monitor mode that this one can be matched - * up with from the 'specified' modes list. - */ - if (modeOK) { - for (p = pScrn->monitor->Modes; p != NULL; p = p->next) { - if ((p->type != 0) || - (p->HDisplay != mode->XResolution) || - (p->VDisplay != mode->YResolution) || - (p->Flags & (V_INTERLACE | V_DBLSCAN | V_CLKDIV2))) - continue; - status = xf86CheckModeForMonitor(p, pScrn->monitor); - if (status == MODE_OK) { - modeOK = TRUE; - break; - } - } - if (p) { - pMode = xnfcalloc(sizeof(DisplayModeRec), 1); - memcpy((char*)pMode,(char*)p,sizeof(DisplayModeRec)); - pMode->name = xnfstrdup(p->name); - } - } - - /* - * Now, check if there's a valid monitor mode that this one can be matched - * up with from the default modes list. i.e. VESA modes in xf86DefModes.c - */ - if (modeOK && !pMode) { - int refresh = 0, calcrefresh = 0; - DisplayModePtr newMode = NULL; - - for (p = pScrn->monitor->Modes; p != NULL; p = p->next) { - calcrefresh = (int)(((double)(p->Clock * 1000) / - (double)(p->HTotal * p->VTotal)) * 100); - if ((p->type != M_T_DEFAULT) || - (p->HDisplay != mode->XResolution) || - (p->VDisplay != mode->YResolution) || - (p->Flags & (V_INTERLACE | V_DBLSCAN | V_CLKDIV2))) - continue; - status = xf86CheckModeForMonitor(p, pScrn->monitor); - if (status == MODE_OK) { - if (calcrefresh > refresh) { - refresh = calcrefresh; - newMode = p; - } - modeOK = TRUE; - } - } - if (newMode) { - pMode = xnfcalloc(sizeof(DisplayModeRec), 1); - memcpy((char*)pMode,(char*)newMode,sizeof(DisplayModeRec)); - pMode->name = xnfstrdup(newMode->name); - } - } - - /* - * Check if there's a valid monitor mode that this one can be matched - * up with. The actual matching is done later. - */ - if (modeOK && !pMode) { - float vrefresh = 0.0f; - int i; - - for (i=0;imonitor->nVrefresh;i++) { - - for (vrefresh = pScrn->monitor->vrefresh[i].hi; - vrefresh >= pScrn->monitor->vrefresh[i].lo; vrefresh -= 1.0f) { - - if (vrefresh != (float)0.0f) { - float best_vrefresh; - int int_vrefresh; - - /* Find the best refresh for the Intel chipsets */ - int_vrefresh = I830GetBestRefresh(pScrn, (int)vrefresh); - best_vrefresh = (float)i830refreshes[int_vrefresh]; - - /* Now, grab the best mode from the available refresh */ - pMode = I830GetGTF(mode->XResolution, mode->YResolution, - best_vrefresh, 0, 0); - - pMode->type = M_T_BUILTIN; - - status = xf86CheckModeForMonitor(pMode, pScrn->monitor); - if (status == MODE_OK) { - if (major >= 3) { - if (pMode->Clock * 1000 <= mode->MaxPixelClock) - modeOK = TRUE; - else - modeOK = FALSE; - } else - modeOK = TRUE; - } else - modeOK = FALSE; - pMode->status = status; - } else { - modeOK = FALSE; - } - if (modeOK) break; - } - if (modeOK) break; - } - } - - xf86ErrorFVerb(DEBUG_VERB, - "Mode: %x (%dx%d)\n", id, mode->XResolution, mode->YResolution); - xf86ErrorFVerb(DEBUG_VERB, - " ModeAttributes: 0x%x\n", mode->ModeAttributes); - xf86ErrorFVerb(DEBUG_VERB, - " WinAAttributes: 0x%x\n", mode->WinAAttributes); - xf86ErrorFVerb(DEBUG_VERB, - " WinBAttributes: 0x%x\n", mode->WinBAttributes); - xf86ErrorFVerb(DEBUG_VERB, - " WinGranularity: %d\n", mode->WinGranularity); - xf86ErrorFVerb(DEBUG_VERB, - " WinSize: %d\n", mode->WinSize); - xf86ErrorFVerb(DEBUG_VERB, - " WinASegment: 0x%x\n", mode->WinASegment); - xf86ErrorFVerb(DEBUG_VERB, - " WinBSegment: 0x%x\n", mode->WinBSegment); - xf86ErrorFVerb(DEBUG_VERB, - " WinFuncPtr: 0x%lx\n", (unsigned long)mode->WinFuncPtr); - xf86ErrorFVerb(DEBUG_VERB, - " BytesPerScanline: %d\n", mode->BytesPerScanline); - xf86ErrorFVerb(DEBUG_VERB, - " XResolution: %d\n", mode->XResolution); - xf86ErrorFVerb(DEBUG_VERB, - " YResolution: %d\n", mode->YResolution); - xf86ErrorFVerb(DEBUG_VERB, - " XCharSize: %d\n", mode->XCharSize); - xf86ErrorFVerb(DEBUG_VERB, - " YCharSize: %d\n", mode->YCharSize); - xf86ErrorFVerb(DEBUG_VERB, - " NumberOfPlanes: %d\n", mode->NumberOfPlanes); - xf86ErrorFVerb(DEBUG_VERB, - " BitsPerPixel: %d\n", mode->BitsPerPixel); - xf86ErrorFVerb(DEBUG_VERB, - " NumberOfBanks: %d\n", mode->NumberOfBanks); - xf86ErrorFVerb(DEBUG_VERB, - " MemoryModel: %d\n", mode->MemoryModel); - xf86ErrorFVerb(DEBUG_VERB, - " BankSize: %d\n", mode->BankSize); - xf86ErrorFVerb(DEBUG_VERB, - " NumberOfImages: %d\n", mode->NumberOfImages); - xf86ErrorFVerb(DEBUG_VERB, - " RedMaskSize: %d\n", mode->RedMaskSize); - xf86ErrorFVerb(DEBUG_VERB, - " RedFieldPosition: %d\n", mode->RedFieldPosition); - xf86ErrorFVerb(DEBUG_VERB, - " GreenMaskSize: %d\n", mode->GreenMaskSize); - xf86ErrorFVerb(DEBUG_VERB, - " GreenFieldPosition: %d\n", mode->GreenFieldPosition); - xf86ErrorFVerb(DEBUG_VERB, - " BlueMaskSize: %d\n", mode->BlueMaskSize); - xf86ErrorFVerb(DEBUG_VERB, - " BlueFieldPosition: %d\n", mode->BlueFieldPosition); - xf86ErrorFVerb(DEBUG_VERB, - " RsvdMaskSize: %d\n", mode->RsvdMaskSize); - xf86ErrorFVerb(DEBUG_VERB, - " RsvdFieldPosition: %d\n", mode->RsvdFieldPosition); - xf86ErrorFVerb(DEBUG_VERB, - " DirectColorModeInfo: %d\n", mode->DirectColorModeInfo); - if (major >= 2) { - xf86ErrorFVerb(DEBUG_VERB, - " PhysBasePtr: 0x%lx\n", - (unsigned long)mode->PhysBasePtr); - if (major >= 3) { - xf86ErrorFVerb(DEBUG_VERB, - " LinBytesPerScanLine: %d\n", mode->LinBytesPerScanLine); - xf86ErrorFVerb(DEBUG_VERB, - " BnkNumberOfImagePages: %d\n", mode->BnkNumberOfImagePages); - xf86ErrorFVerb(DEBUG_VERB, - " LinNumberOfImagePages: %d\n", mode->LinNumberOfImagePages); - xf86ErrorFVerb(DEBUG_VERB, - " LinRedMaskSize: %d\n", mode->LinRedMaskSize); - xf86ErrorFVerb(DEBUG_VERB, - " LinRedFieldPosition: %d\n", mode->LinRedFieldPosition); - xf86ErrorFVerb(DEBUG_VERB, - " LinGreenMaskSize: %d\n", mode->LinGreenMaskSize); - xf86ErrorFVerb(DEBUG_VERB, - " LinGreenFieldPosition: %d\n", mode->LinGreenFieldPosition); - xf86ErrorFVerb(DEBUG_VERB, - " LinBlueMaskSize: %d\n", mode->LinBlueMaskSize); - xf86ErrorFVerb(DEBUG_VERB, - " LinBlueFieldPosition: %d\n", mode->LinBlueFieldPosition); - xf86ErrorFVerb(DEBUG_VERB, - " LinRsvdMaskSize: %d\n", mode->LinRsvdMaskSize); - xf86ErrorFVerb(DEBUG_VERB, - " LinRsvdFieldPosition: %d\n", mode->LinRsvdFieldPosition); - xf86ErrorFVerb(DEBUG_VERB, - " MaxPixelClock: %ld\n", (unsigned long) - mode->MaxPixelClock); - } - } - - if (!modeOK) { - VBEFreeModeInfo(mode); - if (pMode) - xfree(pMode); - return NULL; - } - - pMode->status = MODE_OK; - pMode->type = M_T_BUILTIN; - - /* for adjust frame */ - pMode->HDisplay = mode->XResolution; - pMode->VDisplay = mode->YResolution; - -#if 0 - data = xnfcalloc(sizeof(VbeModeInfoData), 1); - data->mode = id; - data->data = mode; - pMode->PrivSize = sizeof(VbeModeInfoData); - pMode->Private = (INT32*)data; -#else - data = xnfcalloc(sizeof(I830ModePrivateRec), 1); - data->vbeData.mode = id; - data->vbeData.data = mode; - pMode->PrivSize = sizeof(I830ModePrivateRec); - pMode->Private = (INT32*)data; -#endif - pMode->next = NULL; - - return pMode; -} - -/* - * Check the available BIOS modes, and extract those that match the - * requirements into the modePool. Note: modePool is a NULL-terminated - * list. - */ - -DisplayModePtr -I830GetModePool(ScrnInfoPtr pScrn, vbeInfoPtr pVbe, VbeInfoBlock *vbe) -{ - DisplayModePtr pMode, p = NULL, modePool = NULL; - int i = 0; - - for (i = 0; i < 0x7F; i++) { - if ((pMode = CheckMode(pScrn, pVbe, vbe, i, V_MODETYPE_VGA)) != NULL) { - ModeStatus status = MODE_OK; - - /* Check the mode against a specified virtual size (if any) */ - if (pScrn->display->virtualX > 0 && - pMode->HDisplay > pScrn->display->virtualX) { - status = MODE_VIRTUAL_X; - } - if (pScrn->display->virtualY > 0 && - pMode->VDisplay > pScrn->display->virtualY) { - status = MODE_VIRTUAL_Y; - } - if (status != MODE_OK) { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Not using mode \"%dx%d\" (%s)\n", - pMode->HDisplay, pMode->VDisplay, - xf86ModeStatusToString(status)); - } else { - if (p == NULL) { - modePool = pMode; - } else { - p->next = pMode; - } - pMode->prev = NULL; - p = pMode; - } - } - } - return modePool; -} - -/* - * Go through the monitor modes and selecting the best set of - * parameters for each BIOS mode. Note: This is only supported in - * VBE version 3.0 or later. - */ -void -I830SetModeParameters(ScrnInfoPtr pScrn, vbeInfoPtr pVbe) -{ - I830Ptr pI830 = I830PTR(pScrn); - DisplayModePtr pMode = pScrn->modes; - DisplayModePtr ppMode = pScrn->modes; - I830ModePrivatePtr mp = NULL; - - do { - int clock; - - mp = (I830ModePrivatePtr) pMode->Private; - - if (pI830->MergedFB) { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "%s\n", pScrn->monitor->id); - ppMode = (DisplayModePtr) mp->merged.First; - mp = (I830ModePrivatePtr) mp->merged.First->Private; - } - mp->vbeData.block = xcalloc(sizeof(VbeCRTCInfoBlock), 1); - mp->vbeData.block->HorizontalTotal = ppMode->HTotal; - mp->vbeData.block->HorizontalSyncStart = ppMode->HSyncStart; - mp->vbeData.block->HorizontalSyncEnd = ppMode->HSyncEnd; - mp->vbeData.block->VerticalTotal = ppMode->VTotal; - mp->vbeData.block->VerticalSyncStart = ppMode->VSyncStart; - mp->vbeData.block->VerticalSyncEnd = ppMode->VSyncEnd; - mp->vbeData.block->Flags = ((ppMode->Flags & V_NHSYNC) ? CRTC_NHSYNC : 0) | - ((ppMode->Flags & V_NVSYNC) ? CRTC_NVSYNC : 0); - mp->vbeData.block->PixelClock = ppMode->Clock * 1000; - /* XXX May not have this. */ - clock = VBEGetPixelClock(pVbe, mp->vbeData.mode, mp->vbeData.block->PixelClock); - if (clock) - mp->vbeData.block->PixelClock = clock; -#ifdef DEBUG - ErrorF("Setting clock %.2fMHz, closest is %.2fMHz\n", - (double)mp->vbeData.block->PixelClock / 1000000.0, - (double)clock / 1000000.0); -#endif - mp->vbeData.mode |= (1 << 11); - if (ppMode->VRefresh != 0) { - mp->vbeData.block->RefreshRate = ppMode->VRefresh * 100; - } else { - mp->vbeData.block->RefreshRate = (int)(((double)(mp->vbeData.block->PixelClock)/ - (double)(ppMode->HTotal * ppMode->VTotal)) * 100); - } - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Attempting to use %2.2fHz refresh for mode \"%s\" (%x)\n", - (float)(((double)(mp->vbeData.block->PixelClock) / (double)(ppMode->HTotal * ppMode->VTotal))), ppMode->name, mp->vbeData.mode); -#ifdef DEBUG - ErrorF("Video Modeline: ID: 0x%x Name: %s %i %i %i %i - " - " %i %i %i %i %.2f MHz Refresh: %.2f Hz\n", - mp->vbeData.mode, ppMode->name, ppMode->HDisplay, ppMode->HSyncStart, - ppMode->HSyncEnd, ppMode->HTotal, ppMode->VDisplay, - ppMode->VSyncStart,ppMode->VSyncEnd,ppMode->VTotal, - (double)mp->vbeData.block->PixelClock/1000000.0, - (double)mp->vbeData.block->RefreshRate/100); -#endif - pMode = ppMode = pMode->next; - } while (pMode != pScrn->modes); - - if (pI830->MergedFB) { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "%s\n", pI830->pScrn_2->monitor->id); - pMode = pScrn->modes; - do { - int clock; - - mp = (I830ModePrivatePtr) pMode->Private; - ppMode = (DisplayModePtr) mp->merged.Second; - mp = (I830ModePrivatePtr) mp->merged.Second->Private; - - mp->vbeData.block = xcalloc(sizeof(VbeCRTCInfoBlock), 1); - mp->vbeData.block->HorizontalTotal = ppMode->HTotal; - mp->vbeData.block->HorizontalSyncStart = ppMode->HSyncStart; - mp->vbeData.block->HorizontalSyncEnd = ppMode->HSyncEnd; - mp->vbeData.block->VerticalTotal = ppMode->VTotal; - mp->vbeData.block->VerticalSyncStart = ppMode->VSyncStart; - mp->vbeData.block->VerticalSyncEnd = ppMode->VSyncEnd; - mp->vbeData.block->Flags = ((ppMode->Flags & V_NHSYNC) ? CRTC_NHSYNC : 0) | - ((ppMode->Flags & V_NVSYNC) ? CRTC_NVSYNC : 0); - mp->vbeData.block->PixelClock = ppMode->Clock * 1000; - /* XXX May not have this. */ - clock = VBEGetPixelClock(pVbe, mp->vbeData.mode, mp->vbeData.block->PixelClock); - if (clock) - mp->vbeData.block->PixelClock = clock; -#ifdef DEBUG - ErrorF("Setting clock %.2fMHz, closest is %.2fMHz\n", - (double)mp->vbeData.block->PixelClock / 1000000.0, - (double)clock / 1000000.0); -#endif - mp->vbeData.mode |= (1 << 11); - if (ppMode->VRefresh != 0) { - mp->vbeData.block->RefreshRate = ppMode->VRefresh * 100; - } else { - mp->vbeData.block->RefreshRate = (int)(((double)(mp->vbeData.block->PixelClock)/ - (double)(ppMode->HTotal * ppMode->VTotal)) * 100); - } - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Attempting to use %2.2fHz refresh for mode \"%s\" (%x)\n", - (float)(((double)(mp->vbeData.block->PixelClock) / (double)(ppMode->HTotal * ppMode->VTotal))), ppMode->name, mp->vbeData.mode); -#ifdef DEBUG - ErrorF("Video Modeline: ID: 0x%x Name: %s %i %i %i %i - " - " %i %i %i %i %.2f MHz Refresh: %.2f Hz\n", - mp->vbeData.mode, ppMode->name, ppMode->HDisplay, ppMode->HSyncStart, - ppMode->HSyncEnd, ppMode->HTotal, ppMode->VDisplay, - ppMode->VSyncStart,ppMode->VSyncEnd,ppMode->VTotal, - (double)mp->vbeData.block->PixelClock/1000000.0, - (double)mp->vbeData.block->RefreshRate/100); -#endif - pMode = ppMode = pMode->next; - } while (pMode != pScrn->modes); - } -} + int hsize; + int vsize; + int refresh; +} est_timings[] = { + {1280, 1024, 75}, + {1024, 768, 75}, + {1024, 768, 70}, + {1024, 768, 60}, + {1024, 768, 87}, + {832, 624, 75}, + {800, 600, 75}, + {800, 600, 72}, + {800, 600, 60}, + {800, 600, 56}, + {640, 480, 75}, + {640, 480, 72}, + {640, 480, 67}, + {640, 480, 60}, + {720, 400, 88}, + {720, 400, 70}, +}; + +#define DEBUG_REPROBE 1 void I830PrintModes(ScrnInfoPtr scrp) @@ -845,3 +162,539 @@ I830PrintModes(ScrnInfoPtr scrp) p = p->next; } while (p != NULL && p != scrp->modes); } + +/* This function will sort all modes according to their resolution. + * Highest resolution first. + */ +static void +I830xf86SortModes(DisplayModePtr new, DisplayModePtr *first, + DisplayModePtr *last) +{ + DisplayModePtr p; + + p = *last; + while (p) { + if (((new->HDisplay < p->HDisplay) && + (new->VDisplay < p->VDisplay)) || + ((new->HDisplay * new->VDisplay) < (p->HDisplay * p->VDisplay)) || + ((new->HDisplay == p->HDisplay) && + (new->VDisplay == p->VDisplay) && + (new->Clock < p->Clock))) { + + if (p->next) + p->next->prev = new; + new->prev = p; + new->next = p->next; + p->next = new; + if (!(new->next)) + *last = new; + break; + } + if (!p->prev) { + new->prev = NULL; + new->next = p; + p->prev = new; + *first = new; + break; + } + p = p->prev; + } + + if (!*first) { + *first = new; + new->prev = NULL; + new->next = NULL; + *last = new; + } +} + +/** + * Gets a new pointer to a VESA established mode. + * + * \param i index into the VESA established modes table. + */ +static DisplayModePtr +I830GetVESAEstablishedMode(ScrnInfoPtr pScrn, int i) +{ + DisplayModePtr pMode; + + for (pMode = I830xf86DefaultModes; pMode->name != NULL; pMode++) + { + if (pMode->HDisplay == est_timings[i].hsize && + pMode->VDisplay == est_timings[i].vsize && + fabs(i830xf86ModeVRefresh(pMode) - est_timings[i].refresh) < 1.0) + { + DisplayModePtr pNew = i830xf86DuplicateMode(pMode); + i830xf86SetModeDefaultName(pNew); + pNew->VRefresh = i830xf86ModeVRefresh(pMode); + return pNew; + } + } + return NULL; +} + +static DisplayModePtr +i830GetDDCModes(ScrnInfoPtr pScrn, xf86MonPtr ddc) +{ + DisplayModePtr last = NULL; + DisplayModePtr new = NULL; + DisplayModePtr first = NULL; + int count = 0; + int j, tmp; + + if (ddc == NULL) + return NULL; + + /* Go thru detailed timing table first */ + for (j = 0; j < 4; j++) { + if (ddc->det_mon[j].type == 0) { + struct detailed_timings *d_timings = + &ddc->det_mon[j].section.d_timings; + + if (d_timings->h_active == 0 || d_timings->v_active == 0) break; + + new = xnfcalloc(1, sizeof (DisplayModeRec)); + memset(new, 0, sizeof (DisplayModeRec)); + + new->HDisplay = d_timings->h_active; + new->VDisplay = d_timings->v_active; + + new->HTotal = new->HDisplay + d_timings->h_blanking; + new->HSyncStart = new->HDisplay + d_timings->h_sync_off; + new->HSyncEnd = new->HSyncStart + d_timings->h_sync_width; + new->VTotal = new->VDisplay + d_timings->v_blanking; + new->VSyncStart = new->VDisplay + d_timings->v_sync_off; + new->VSyncEnd = new->VSyncStart + d_timings->v_sync_width; + new->Clock = d_timings->clock / 1000; + new->Flags = (d_timings->interlaced ? V_INTERLACE : 0); + new->status = MODE_OK; + if (PREFERRED_TIMING_MODE(ddc->features.msc)) + new->type = M_T_PREFERRED; + else + new->type = M_T_DRIVER; + + i830xf86SetModeDefaultName(new); + + if (d_timings->sync == 3) { + switch (d_timings->misc) { + case 0: new->Flags |= V_NHSYNC | V_NVSYNC; break; + case 1: new->Flags |= V_PHSYNC | V_NVSYNC; break; + case 2: new->Flags |= V_NHSYNC | V_PVSYNC; break; + case 3: new->Flags |= V_PHSYNC | V_PVSYNC; break; + } + } + count++; + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Valid Mode from Detailed timing table: %s (ht %d hss %d hse %d vt %d vss %d vse %d)\n", + new->name, + new->HTotal, new->HSyncStart, new->HSyncEnd, + new->VTotal, new->VSyncStart, new->VSyncEnd); + + I830xf86SortModes(new, &first, &last); + } + } + + /* Search thru standard VESA modes from EDID */ + for (j = 0; j < 8; j++) { + if (ddc->timings2[j].hsize == 0 || ddc->timings2[j].vsize == 0) + continue; +#if 1 + new = i830GetGTF(ddc->timings2[j].hsize, ddc->timings2[j].vsize, + ddc->timings2[j].refresh, FALSE, FALSE); + new->status = MODE_OK; + new->type |= M_T_DEFAULT; + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Valid Mode from standard timing table: %s\n", + new->name); + + I830xf86SortModes(new, &first, &last); +#else + for (p = pScrn->monitor->Modes; p && p->next; p = p->next->next) { + + /* Ignore all double scan modes */ + if ((ddc->timings2[j].hsize == p->HDisplay) && + (ddc->timings2[j].vsize == p->VDisplay)) { + float refresh = + (float)p->Clock * 1000.0 / p->HTotal / p->VTotal; + float err = (float)ddc->timings2[j].refresh - refresh; + + if (err < 0) err = -err; + if (err < 1.0) { + /* Is this good enough? */ + new = xnfcalloc(1, sizeof (DisplayModeRec)); + memcpy(new, p, sizeof(DisplayModeRec)); + new->name = xnfalloc(strlen(p->name) + 1); + strcpy(new->name, p->name); + new->status = MODE_OK; + new->type = M_T_DEFAULT; + + count++; + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Valid Mode from standard timing table: %s\n", + new->name); + + I830xf86SortModes(new, &first, &last); + break; + } + } + } +#endif + } + + /* Search thru established modes from EDID */ + tmp = (ddc->timings1.t1 << 8) | ddc->timings1.t2; + for (j = 0; j < 16; j++) { + if (tmp & (1 << j)) { + new = I830GetVESAEstablishedMode(pScrn, j); + if (new == NULL) { + ErrorF("Couldn't get established mode %d\n", j); + continue; + } + new->status = MODE_OK; + new->type = M_T_DEFAULT; + + count++; + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Valid Mode from established " + "timing table: %s\n", new->name); + + I830xf86SortModes(new, &first, &last); + } + } + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Total of %d DDC mode(s) found.\n", count); + + return first; +} + +static DisplayModePtr +i830GetModeListTail(DisplayModePtr pModeList) +{ + DisplayModePtr last; + + if (pModeList == NULL) + return NULL; + + for (last = pModeList; last->next != NULL; last = last->next) + ; + + return last; +} + +/** + * This function removes a mode from a list of modes. It should probably be + * moved to xf86Mode.c. + * + * There are different types of mode lists: + * + * - singly linked linear lists, ending in NULL + * - doubly linked linear lists, starting and ending in NULL + * - doubly linked circular lists + * + */ + +static void +I830xf86DeleteModeFromList(DisplayModePtr *modeList, DisplayModePtr mode) +{ + /* Catch the easy/insane cases */ + if (modeList == NULL || *modeList == NULL || mode == NULL) + return; + + /* If the mode is at the start of the list, move the start of the list */ + if (*modeList == mode) + *modeList = mode->next; + + /* If mode is the only one on the list, set the list to NULL */ + if ((mode == mode->prev) && (mode == mode->next)) { + *modeList = NULL; + } else { + if ((mode->prev != NULL) && (mode->prev->next == mode)) + mode->prev->next = mode->next; + if ((mode->next != NULL) && (mode->next->prev == mode)) + mode->next->prev = mode->prev; + } +} + +void +i830_reprobe_output_modes(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + Bool properties_set = FALSE; + int i; + + /* Re-probe the list of modes for each output. */ + for (i = 0; i < pI830->num_outputs; i++) { + DisplayModePtr mode; + + while (pI830->output[i].probed_modes != NULL) { + xf86DeleteMode(&pI830->output[i].probed_modes, + pI830->output[i].probed_modes); + } + + pI830->output[i].probed_modes = + pI830->output[i].get_modes(pScrn, &pI830->output[i]); + + /* Set the DDC properties to whatever first output has DDC information. + */ + if (pI830->output[i].MonInfo != NULL && !properties_set) { + xf86SetDDCproperties(pScrn, pI830->output[i].MonInfo); + properties_set = TRUE; + } + + if (pI830->output[i].probed_modes != NULL) { + /* silently prune modes down to ones matching the user's + * configuration. + */ + i830xf86ValidateModesUserConfig(pScrn, + pI830->output[i].probed_modes); + i830xf86PruneInvalidModes(pScrn, &pI830->output[i].probed_modes, + FALSE); + } + +#ifdef DEBUG_REPROBE + if (pI830->output[i].probed_modes != NULL) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Printing probed modes for output %s\n", + i830_output_type_names[pI830->output[i].type]); + } else { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "No remaining probed modes for output %s\n", + i830_output_type_names[pI830->output[i].type]); + } +#endif + for (mode = pI830->output[i].probed_modes; mode != NULL; + mode = mode->next) + { + /* The code to choose the best mode per pipe later on will require + * VRefresh to be set. + */ + mode->VRefresh = i830xf86ModeVRefresh(mode); + I830xf86SetModeCrtc(mode, INTERLACE_HALVE_V); + +#ifdef DEBUG_REPROBE + PrintModeline(pScrn->scrnIndex, mode); +#endif + } + } +} + +/** + * Constructs pScrn->modes from the output mode lists. + * + * Currently it only takes one output's mode list and stuffs it into the + * XFree86 DDX mode list while trimming it for root window size. + * + * This should be obsoleted by RandR 1.2 hopefully. + */ +void +i830_set_xf86_modes_from_outputs(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + DisplayModePtr saved_mode, last; + int originalVirtualX, originalVirtualY; + int i; + + /* Remove the current mode from the modelist if we're re-validating, so we + * can find a new mode to map ourselves to afterwards. + */ + saved_mode = pI830->currentMode; + if (saved_mode != NULL) { + I830xf86DeleteModeFromList(&pScrn->modes, saved_mode); + } + + /* Clear any existing modes from pScrn->modes */ + while (pScrn->modes != NULL) + xf86DeleteMode(&pScrn->modes, pScrn->modes); + + /* Set pScrn->modes to the mode list for an arbitrary output. + * pScrn->modes should only be used for XF86VidMode now, which we don't + * care about enough to make some sort of unioned list. + */ + for (i = 0; i < pI830->num_outputs; i++) { + if (pI830->output[i].probed_modes != NULL) { + pScrn->modes = + i830xf86DuplicateModes(pScrn, pI830->output[i].probed_modes); + break; + } + } + + I830GetOriginalVirtualSize(pScrn, &originalVirtualX, &originalVirtualY); + + /* Disable modes in the XFree86 DDX list that are larger than the current + * virtual size. + */ + i830xf86ValidateModesSize(pScrn, pScrn->modes, + originalVirtualX, originalVirtualY, + pScrn->displayWidth); + + /* Strip out anything that we threw out for virtualX/Y. */ + i830xf86PruneInvalidModes(pScrn, &pScrn->modes, TRUE); + + if (pScrn->modes == NULL) { + FatalError("No modes left for XFree86 DDX\n"); + } + + /* For some reason, pScrn->modes is circular, unlike the other mode lists. + * How great is that? + */ + last = i830GetModeListTail(pScrn->modes); + last->next = pScrn->modes; + pScrn->modes->prev = last; + + /* Save a pointer to the previous current mode. We can't reset + * pScrn->currentmode, because we rely on xf86SwitchMode's shortcut not + * happening so we can hot-enable devices at SwitchMode. We'll notice this + * case at SwitchMode and free the saved mode. + */ + pI830->savedCurrentMode = saved_mode; +} + +/** + * Takes the output mode lists and decides the default root window size + * and framebuffer pitch. + */ +void +i830_set_default_screen_size(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + int maxX = -1, maxY = -1; + int i; + + /* Set up a virtual size that will cover any clone mode we'd want to + * set for the currently-connected outputs. + */ + for (i = 0; i < pI830->num_outputs; i++) { + DisplayModePtr mode; + + for (mode = pI830->output[i].probed_modes; mode != NULL; + mode = mode->next) + { + if (mode->HDisplay > maxX) + maxX = mode->HDisplay; + if (mode->VDisplay > maxY) + maxY = mode->VDisplay; + } + } + /* let the user specify a bigger virtual size if they like */ + if (pScrn->display->virtualX > maxX) + maxX = pScrn->display->virtualX; + if (pScrn->display->virtualY > maxY) + maxY = pScrn->display->virtualY; + pScrn->virtualX = maxX; + pScrn->virtualY = maxY; + pScrn->displayWidth = (maxX + 63) & ~63; +} + +/** + * Probes for video modes on attached otuputs, and assembles a list to insert + * into pScrn. + * + * \param first_time indicates that the memory layout has already been set up, + * so displayWidth, virtualX, and virtualY shouldn't be touched. + * + * A SetMode must follow this call in order for operatingDevices to match the + * hardware's state, in case we detect a new output device. + */ +int +I830ValidateXF86ModeList(ScrnInfoPtr pScrn, Bool first_time) +{ + i830_reprobe_output_modes(pScrn); + + if (first_time) { + i830_set_default_screen_size(pScrn); + } + + i830_set_xf86_modes_from_outputs(pScrn); + + return 1; /* XXX */ +} + +#ifdef RANDR_12_INTERFACE + +#define EDID_ATOM_NAME "EDID_DATA" + +static void +i830_ddc_set_edid_property(ScrnInfoPtr pScrn, I830OutputPtr output, + void *data, int data_len) +{ + Atom edid_atom = MakeAtom(EDID_ATOM_NAME, sizeof(EDID_ATOM_NAME), TRUE); + + /* This may get called before the RandR resources have been created */ + if (output->randr_output == NULL) + return; + + if (data_len != 0) { + RRChangeOutputProperty(output->randr_output, edid_atom, XA_INTEGER, 8, + PropModeReplace, data_len, data, FALSE); + } else { + RRDeleteOutputProperty(output->randr_output, edid_atom); + } +} +#endif + +/** + * Generic get_modes function using DDC, used by many outputs. + */ +DisplayModePtr +i830_ddc_get_modes(ScrnInfoPtr pScrn, I830OutputPtr output) +{ + xf86MonPtr ddc_mon; + DisplayModePtr ddc_modes, mode; + int i; + + ddc_mon = xf86DoEDID_DDC2(pScrn->scrnIndex, output->pDDCBus); + if (ddc_mon == NULL) { +#ifdef RANDR_12_INTERFACE + i830_ddc_set_edid_property(pScrn, output, NULL, 0); +#endif + return NULL; + } + + if (output->MonInfo != NULL) + xfree(output->MonInfo); + output->MonInfo = ddc_mon; + +#ifdef RANDR_12_INTERFACE + if (output->MonInfo->ver.version == 1) { + i830_ddc_set_edid_property(pScrn, output, ddc_mon->rawData, 128); + } else if (output->MonInfo->ver.version == 2) { + i830_ddc_set_edid_property(pScrn, output, ddc_mon->rawData, 256); + } else { + i830_ddc_set_edid_property(pScrn, output, NULL, 0); + } +#endif + + /* Debug info for now, at least */ + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "EDID for output %s\n", + i830_output_type_names[output->type]); + xf86PrintEDID(output->MonInfo); + + ddc_modes = i830GetDDCModes(pScrn, ddc_mon); + + /* Strip out any modes that can't be supported on this output. */ + for (mode = ddc_modes; mode != NULL; mode = mode->next) { + int status = output->mode_valid(pScrn, output, mode); + + if (status != MODE_OK) + mode->status = status; + } + i830xf86PruneInvalidModes(pScrn, &ddc_modes, TRUE); + + /* Pull out a phyiscal size from a detailed timing if available. */ + for (i = 0; i < 4; i++) { + if (ddc_mon->det_mon[i].type == DT && + ddc_mon->det_mon[i].section.d_timings.h_size != 0 && + ddc_mon->det_mon[i].section.d_timings.v_size != 0) + { + output->mm_width = ddc_mon->det_mon[i].section.d_timings.h_size; + output->mm_height = ddc_mon->det_mon[i].section.d_timings.v_size; + break; + } + } + + return ddc_modes; +} diff --git a/src/i830_randr.c b/src/i830_randr.c index 0311f2b6..d27125f4 100644 --- a/src/i830_randr.c +++ b/src/i830_randr.c @@ -23,6 +23,10 @@ * PERFORMANCE OF THIS SOFTWARE. */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include "xf86.h" #include "os.h" #include "mibank.h" @@ -33,8 +37,11 @@ #include "mipointer.h" #include "windowstr.h" #include +#include #include "i830.h" +#include "i830_xf86Modes.h" +#include "i830_display.h" typedef struct _i830RandRInfo { int virtualX; @@ -45,12 +52,21 @@ typedef struct _i830RandRInfo { int maxY; Rotation rotation; /* current mode */ Rotation supported_rotations; /* driver supported */ +#ifdef RANDR_12_INTERFACE + DisplayModePtr modes[MAX_DISPLAY_PIPES]; +#endif } XF86RandRInfoRec, *XF86RandRInfoPtr; - + +#ifdef RANDR_12_INTERFACE +static Bool I830RandRInit12 (ScreenPtr pScreen); +static Bool I830RandRCreateScreenResources12 (ScreenPtr pScreen); +#endif + static int i830RandRIndex; static int i830RandRGeneration; -#define XF86RANDRINFO(p) ((XF86RandRInfoPtr) (p)->devPrivates[i830RandRIndex].ptr) +#define XF86RANDRINFO(p) \ + ((XF86RandRInfoPtr)(p)->devPrivates[i830RandRIndex].ptr) static int I830RandRModeRefresh (DisplayModePtr mode) @@ -70,15 +86,18 @@ I830RandRGetInfo (ScreenPtr pScreen, Rotation *rotations) DisplayModePtr mode; int refresh0 = 60; int maxX = 0, maxY = 0; - + *rotations = randrp->supported_rotations; - if (randrp->virtualX == -1 || randrp->virtualY == -1) + if (randrp->virtualX == -1 || randrp->virtualY == -1) { randrp->virtualX = scrp->virtualX; randrp->virtualY = scrp->virtualY; } + /* Re-probe the outputs for new monitors or modes */ + I830ValidateXF86ModeList(scrp, FALSE); + for (mode = scrp->modes; ; mode = mode->next) { int refresh = I830RandRModeRefresh (mode); @@ -97,9 +116,13 @@ I830RandRGetInfo (ScreenPtr pScreen, Rotation *rotations) if (!pSize) return FALSE; RRRegisterRate (pScreen, pSize, refresh); - if (mode == scrp->currentMode && - mode->HDisplay == scrp->virtualX && mode->VDisplay == scrp->virtualY) + + if (I830ModesEqual(mode, scrp->currentMode) && + mode->HDisplay == scrp->virtualX && + mode->VDisplay == scrp->virtualY) + { RRSetCurrentConfig (pScreen, randrp->rotation, refresh, pSize); + } if (mode->next == scrp->modes) break; } @@ -109,11 +132,10 @@ I830RandRGetInfo (ScreenPtr pScreen, Rotation *rotations) randrp->maxX = maxX; randrp->maxY = maxY; } - + if (scrp->currentMode->HDisplay != randrp->virtualX || scrp->currentMode->VDisplay != randrp->virtualY) { - mode = scrp->modes; pSize = RRRegisterSize (pScreen, randrp->virtualX, randrp->virtualY, randrp->mmWidth, @@ -121,7 +143,7 @@ I830RandRGetInfo (ScreenPtr pScreen, Rotation *rotations) if (!pSize) return FALSE; RRRegisterRate (pScreen, pSize, refresh0); - if (scrp->virtualX == randrp->virtualX && + if (scrp->virtualX == randrp->virtualX && scrp->virtualY == randrp->virtualY) { RRSetCurrentConfig (pScreen, randrp->rotation, refresh0, pSize); @@ -148,7 +170,7 @@ I830RandRSetMode (ScreenPtr pScreen, DisplayModePtr currentMode = NULL; Bool ret = TRUE; PixmapPtr pspix = NULL; - + if (pRoot) (*scrp->EnableDisableFBAccess) (pScreen->myNum, FALSE); if (useVirtual) @@ -161,6 +183,7 @@ I830RandRSetMode (ScreenPtr pScreen, scrp->virtualX = mode->HDisplay; scrp->virtualY = mode->VDisplay; } + if(randrp->rotation & (RR_Rotate_90 | RR_Rotate_270)) { /* If the screen is rotated 90 or 270 degrees, swap the sizes. */ @@ -203,7 +226,7 @@ I830RandRSetMode (ScreenPtr pScreen, pspix = (*pScreen->GetScreenPixmap) (pScreen); if (pspix->devPrivate.ptr) scrp->pixmapPrivate = pspix->devPrivate; - + /* * Make sure the layout is correct */ @@ -235,7 +258,7 @@ I830RandRSetConfig (ScreenPtr pScreen, randrp->rotation = rotation; - if (randrp->virtualX == -1 || randrp->virtualY == -1) + if (randrp->virtualX == -1 || randrp->virtualY == -1) { randrp->virtualX = scrp->virtualX; randrp->virtualY = scrp->virtualY; @@ -251,7 +274,7 @@ I830RandRSetConfig (ScreenPtr pScreen, if (maxY < mode->VDisplay) maxY = mode->VDisplay; } - if (mode->HDisplay == pSize->width && + if (mode->HDisplay == pSize->width && mode->VDisplay == pSize->height && (rate == 0 || I830RandRModeRefresh (mode) == rate)) break; @@ -279,7 +302,8 @@ I830RandRSetConfig (ScreenPtr pScreen, randrp->maxY = maxY; } - if (!I830RandRSetMode (pScreen, mode, useVirtual, pSize->mmWidth, pSize->mmHeight)) { + if (!I830RandRSetMode (pScreen, mode, useVirtual, pSize->mmWidth, + pSize->mmHeight)) { randrp->rotation = oldRotation; return FALSE; } @@ -308,12 +332,46 @@ I830GetRotation(ScreenPtr pScreen) return randrp->rotation; } +Bool +I830RandRCreateScreenResources (ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + I830Ptr pI830 = I830PTR(pScrn); +#ifdef PANORAMIX + /* XXX disable RandR when using Xinerama */ + if (!noPanoramiXExtension) + return TRUE; +#endif +#if RANDR_12_INTERFACE + if (I830RandRCreateScreenResources12 (pScreen)) + return TRUE; +#endif + if (pI830->rotation != RR_Rotate_0) { + RRScreenSize p; + Rotation requestedRotation = pI830->rotation; + + pI830->rotation = RR_Rotate_0; + + /* Just setup enough for an initial rotate */ + p.width = pScreen->width; + p.height = pScreen->height; + p.mmWidth = pScreen->mmWidth; + p.mmHeight = pScreen->mmHeight; + + pI830->starting = TRUE; /* abuse this for dual head & rotation */ + I830RandRSetConfig (pScreen, requestedRotation, 0, &p); + pI830->starting = FALSE; + } + return TRUE; +} + + Bool I830RandRInit (ScreenPtr pScreen, int rotation) { rrScrPrivPtr rp; XF86RandRInfoPtr randrp; - + #ifdef PANORAMIX /* XXX disable RandR when using Xinerama */ if (!noPanoramiXExtension) @@ -324,11 +382,11 @@ I830RandRInit (ScreenPtr pScreen, int rotation) i830RandRIndex = AllocateScreenPrivateIndex(); i830RandRGeneration = serverGeneration; } - + randrp = xalloc (sizeof (XF86RandRInfoRec)); if (!randrp) return FALSE; - + if (!RRScreenInit(pScreen)) { xfree (randrp); @@ -342,7 +400,7 @@ I830RandRInit (ScreenPtr pScreen, int rotation) randrp->virtualY = -1; randrp->mmWidth = pScreen->mmWidth; randrp->mmHeight = pScreen->mmHeight; - + randrp->rotation = RR_Rotate_0; /* initial rotated mode */ randrp->supported_rotations = rotation; @@ -351,5 +409,872 @@ I830RandRInit (ScreenPtr pScreen, int rotation) pScreen->devPrivates[i830RandRIndex].ptr = randrp; +#if RANDR_12_INTERFACE + if (!I830RandRInit12 (pScreen)) + return FALSE; +#endif + return TRUE; +} + +void +I830GetOriginalVirtualSize(ScrnInfoPtr pScrn, int *x, int *y) +{ + ScreenPtr pScreen = screenInfo.screens[pScrn->scrnIndex]; + + if (i830RandRGeneration != serverGeneration || + XF86RANDRINFO(pScreen)->virtualX == -1) + { + *x = pScrn->virtualX; + *y = pScrn->virtualY; + } else { + XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); + + *x = randrp->virtualX; + *y = randrp->virtualY; + } +} + +#if RANDR_12_INTERFACE +static Bool +I830RandRScreenSetSize (ScreenPtr pScreen, + CARD16 width, + CARD16 height, + CARD32 mmWidth, + CARD32 mmHeight) +{ + XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); + ScrnInfoPtr pScrn = XF86SCRNINFO(pScreen); + WindowPtr pRoot = WindowTable[pScreen->myNum]; + Bool ret = TRUE; + + if (randrp->virtualX == -1 || randrp->virtualY == -1) + { + randrp->virtualX = pScrn->virtualX; + randrp->virtualY = pScrn->virtualY; + } + if (pRoot) + (*pScrn->EnableDisableFBAccess) (pScreen->myNum, FALSE); + pScrn->virtualX = width; + pScrn->virtualY = height; + + pScreen->width = pScrn->virtualX; + pScreen->height = pScrn->virtualY; + pScreen->mmWidth = mmWidth; + pScreen->mmHeight = mmHeight; + + xf86SetViewport (pScreen, pScreen->width, pScreen->height); + xf86SetViewport (pScreen, 0, 0); + if (pRoot) + (*pScrn->EnableDisableFBAccess) (pScreen->myNum, TRUE); + if (WindowTable[pScreen->myNum]) + RRScreenSizeNotify (pScreen); + return ret; +} + +static Bool +I830RandRCrtcNotify (RRCrtcPtr crtc) +{ + ScreenPtr pScreen = crtc->pScreen; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + I830Ptr pI830 = I830PTR(pScrn); + RRModePtr mode = NULL; + int x; + int y; + Rotation rotation; + int numOutputs; + RROutputPtr outputs[MAX_OUTPUTS]; + struct _I830OutputRec *output; + RROutputPtr rrout; + int pipe = (int) crtc->devPrivate; + I830PipePtr pI830Pipe = &pI830->pipes[pipe]; + int i, j; + DisplayModePtr pipeMode = &pI830Pipe->curMode; + + x = pI830Pipe->x; + y = pI830Pipe->y; + rotation = RR_Rotate_0; + numOutputs = 0; + mode = NULL; + for (i = 0; i < pI830->num_outputs; i++) + { + output = &pI830->output[i]; + if (output->enabled && output->pipe == pipe) + { + rrout = output->randr_output; + outputs[numOutputs++] = rrout; + /* + * We make copies of modes, so pointer equality + * isn't sufficient + */ + for (j = 0; j < rrout->numModes; j++) + { + DisplayModePtr outMode = rrout->modes[j]->devPrivate; + if (I830ModesEqual(pipeMode, outMode)) + { + mode = rrout->modes[j]; + break; + } + } + } + } + return RRCrtcNotify (crtc, mode, x, y, rotation, numOutputs, outputs); +} + +static Bool +I830RandRCrtcSet (ScreenPtr pScreen, + RRCrtcPtr crtc, + RRModePtr mode, + int x, + int y, + Rotation rotation, + int num_randr_outputs, + RROutputPtr *randr_outputs) +{ + XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + I830Ptr pI830 = I830PTR(pScrn); + int pipe = (int) (crtc->devPrivate); + I830PipePtr pI830Pipe = &pI830->pipes[pipe]; + DisplayModePtr display_mode = mode ? mode->devPrivate : NULL; + Bool changed = FALSE; + Bool disable = FALSE; + int o, ro; + struct { + int pipe; + int enabled; + } save_output[MAX_OUTPUTS]; + Bool save_enabled = pI830Pipe->enabled; + + if (display_mode != randrp->modes[pipe]) + { + changed = TRUE; + if (!display_mode) + disable = TRUE; + } + + for (o = 0; o < pI830->num_outputs; o++) + { + I830OutputPtr output = &pI830->output[o]; + RROutputPtr randr_output = NULL; + + save_output[o].enabled = output->enabled; + save_output[o].pipe = output->pipe; + for (ro = 0; ro < num_randr_outputs; ro++) + { + if (output->randr_output == randr_outputs[ro]) + { + randr_output = randr_outputs[ro]; + break; + } + } + if (randr_output) + { + if (output->pipe != pipe || !output->enabled) + { + output->pipe = pipe; + output->enabled = TRUE; + changed = TRUE; + } + } + else + { + /* Disable outputs which were on this pipe */ + if (output->enabled && output->pipe == pipe) + { + output->enabled = FALSE; + changed = TRUE; + disable = TRUE; + } + } + } + if (changed) + { + pI830Pipe->enabled = mode != NULL; + /* Sync the engine before adjust mode */ + if (pI830->AccelInfoRec && pI830->AccelInfoRec->NeedToSync) { + (*pI830->AccelInfoRec->Sync)(pScrn); + pI830->AccelInfoRec->NeedToSync = FALSE; + } + + if (display_mode) + { + if (!i830PipeSetMode (pScrn, display_mode, pipe, TRUE)) + { + pI830Pipe->enabled = save_enabled; + for (o = 0; o < pI830->num_outputs; o++) + { + I830OutputPtr output = &pI830->output[o]; + output->enabled = save_output[o].enabled; + output->pipe = save_output[o].pipe; + } + return FALSE; + } + pI830Pipe->desiredMode = *display_mode; + i830PipeSetBase(pScrn, pipe, x, y); + } + randrp->modes[pipe] = display_mode; + if (disable) + i830DisableUnusedFunctions (pScrn); + } + return I830RandRCrtcNotify (crtc); +} + +static Bool +I830RandRCrtcSetGamma (ScreenPtr pScreen, + RRCrtcPtr crtc) +{ + return FALSE; +} + +/** + * Given a list of xf86 modes and a RandR Output object, construct + * RandR modes and assign them to the output + */ +static Bool +I830xf86RROutputSetModes (RROutputPtr randr_output, DisplayModePtr modes) +{ + DisplayModePtr mode; + RRModePtr *rrmodes = NULL; + int nmode = 0; + int npreferred = 0; + Bool ret = TRUE; + int pref; + + for (mode = modes; mode; mode = mode->next) + nmode++; + + if (nmode) { + rrmodes = xalloc (nmode * sizeof (RRModePtr)); + + if (!rrmodes) + return FALSE; + nmode = 0; + + for (pref = 1; pref >= 0; pref--) { + for (mode = modes; mode; mode = mode->next) { + if ((pref != 0) == ((mode->type & M_T_PREFERRED) != 0)) { + xRRModeInfo modeInfo; + RRModePtr rrmode; + + modeInfo.nameLength = strlen (mode->name); + modeInfo.width = mode->HDisplay; + modeInfo.dotClock = mode->Clock * 1000; + modeInfo.hSyncStart = mode->HSyncStart; + modeInfo.hSyncEnd = mode->HSyncEnd; + modeInfo.hTotal = mode->HTotal; + modeInfo.hSkew = mode->HSkew; + + modeInfo.height = mode->VDisplay; + modeInfo.vSyncStart = mode->VSyncStart; + modeInfo.vSyncEnd = mode->VSyncEnd; + modeInfo.vTotal = mode->VTotal; + modeInfo.modeFlags = mode->Flags; + + rrmode = RRModeGet (&modeInfo, mode->name); + rrmode->devPrivate = mode; + if (rrmode) { + rrmodes[nmode++] = rrmode; + npreferred += pref; + } + } + } + } + } + + ret = RROutputSetModes (randr_output, rrmodes, nmode, npreferred); + xfree (rrmodes); + return ret; +} + +/* + * Mirror the current mode configuration to RandR + */ +static Bool +I830RandRSetInfo12 (ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + RROutputPtr clones[MAX_OUTPUTS]; + RRCrtcPtr crtcs[MAX_DISPLAY_PIPES]; + int ncrtc; + I830OutputPtr output; + int o, c, p; + int clone_types; + int crtc_types; + int subpixel; + RRCrtcPtr randr_crtc; + RROutputPtr randr_output; + int nclone; + + for (o = 0; o < pI830->num_outputs; o++) + { + output = &pI830->output[o]; + randr_output = output->randr_output; + /* + * Valid crtcs + */ + switch (output->type) { + case I830_OUTPUT_DVO: + case I830_OUTPUT_SDVO: + crtc_types = ((1 << 0)| + (1 << 1)); + clone_types = ((1 << I830_OUTPUT_ANALOG) | + (1 << I830_OUTPUT_DVO) | + (1 << I830_OUTPUT_SDVO)); + subpixel = SubPixelHorizontalRGB; + break; + case I830_OUTPUT_ANALOG: + crtc_types = ((1 << 0) | (1 << 1)); + clone_types = ((1 << I830_OUTPUT_ANALOG) | + (1 << I830_OUTPUT_DVO) | + (1 << I830_OUTPUT_SDVO)); + subpixel = SubPixelNone; + break; + case I830_OUTPUT_LVDS: + crtc_types = (1 << 1); + clone_types = (1 << I830_OUTPUT_LVDS); + subpixel = SubPixelHorizontalRGB; + break; + case I830_OUTPUT_TVOUT: + crtc_types = ((1 << 0) | + (1 << 1)); + clone_types = (1 << I830_OUTPUT_TVOUT); + subpixel = SubPixelNone; + break; + default: + crtc_types = 0; + clone_types = 0; + subpixel = SubPixelUnknown; + break; + } + ncrtc = 0; + for (p = 0; p < pI830->num_pipes; p++) + if (crtc_types & (1 << p)) + crtcs[ncrtc++] = pI830->pipes[p].randr_crtc; + + if (output->enabled) + randr_crtc = pI830->pipes[output->pipe].randr_crtc; + else + randr_crtc = NULL; + + if (!RROutputSetCrtcs (output->randr_output, crtcs, ncrtc)) + return FALSE; + + RROutputSetCrtc (output->randr_output, randr_crtc); + RROutputSetPhysicalSize(output->randr_output, + output->mm_width, + output->mm_height); + I830xf86RROutputSetModes (output->randr_output, output->probed_modes); + + switch (output->detect(pScrn, output)) { + case OUTPUT_STATUS_CONNECTED: + RROutputSetConnection (output->randr_output, RR_Connected); + break; + case OUTPUT_STATUS_DISCONNECTED: + RROutputSetConnection (output->randr_output, RR_Disconnected); + break; + case OUTPUT_STATUS_UNKNOWN: + RROutputSetConnection (output->randr_output, RR_UnknownConnection); + break; + } + + RROutputSetSubpixelOrder (output->randr_output, subpixel); + + /* + * Valid clones + */ + nclone = 0; + for (c = 0; c < pI830->num_outputs; c++) + { + if (o != c && ((1 << pI830->output[c].type) & clone_types)) + clones[nclone++] = pI830->output[c].randr_output; + } + if (!RROutputSetClones (output->randr_output, clones, nclone)) + return FALSE; + } + return TRUE; +} + +/* + * Query the hardware for the current state, then mirror + * that to RandR + */ +static Bool +I830RandRGetInfo12 (ScreenPtr pScreen, Rotation *rotations) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + + i830_reprobe_output_modes(pScrn); + return I830RandRSetInfo12 (pScrn); +} + +static Bool +I830RandRCreateObjects12 (ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + int p; + int o; + + if (!RRInit ()) + return FALSE; + + /* + * Create RandR resources, then probe them + */ + for (p = 0; p < pI830->num_pipes; p++) + { + I830PipePtr pipe = &pI830->pipes[p]; + RRCrtcPtr randr_crtc = RRCrtcCreate ((void *) p); + + if (!randr_crtc) + return FALSE; + RRCrtcGammaSetSize (randr_crtc, 256); + pipe->randr_crtc = randr_crtc; + } + + for (o = 0; o < pI830->num_outputs; o++) + { + I830OutputPtr output = &pI830->output[o]; + const char *name = i830_output_type_names[output->type]; + RROutputPtr randr_output = RROutputCreate (name, strlen (name), + (void *) o); + if (!randr_output) + return FALSE; + output->randr_output = randr_output; + } + return TRUE; +} + +static Bool +I830RandRCreateScreenResources12 (ScreenPtr pScreen) +{ + XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + I830Ptr pI830 = I830PTR(pScrn); + int p, o; + int width, height; + + /* + * Attach RandR objects to screen + */ + for (p = 0; p < pI830->num_pipes; p++) + if (!RRCrtcAttachScreen (pI830->pipes[p].randr_crtc, pScreen)) + return FALSE; + + for (o = 0; o < pI830->num_outputs; o++) + if (!RROutputAttachScreen (pI830->output[o].randr_output, pScreen)) + return FALSE; + + /* + * Compute width of screen + */ + width = 0; height = 0; + for (p = 0; p < pI830->num_pipes; p++) + { + I830PipePtr pipe = &pI830->pipes[p]; + int pipe_width = pipe->x + pipe->curMode.HDisplay; + int pipe_height = pipe->y + pipe->curMode.VDisplay; + if (pipe->enabled && pipe_width > width) + width = pipe_width; + if (pipe->enabled && pipe_height > height) + height = pipe_height; + } + + if (width && height) + { + int mmWidth, mmHeight; + + mmWidth = pScreen->mmWidth; + mmHeight = pScreen->mmHeight; + if (width != pScreen->width) + mmWidth = mmWidth * width / pScreen->width; + if (height != pScreen->height) + mmHeight = mmHeight * height / pScreen->height; + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Setting screen physical size to %d x %d\n", + mmWidth, mmHeight); + I830RandRScreenSetSize (pScreen, + width, + height, + mmWidth, + mmHeight); + } + + for (p = 0; p < pI830->num_pipes; p++) + I830RandRCrtcNotify (pI830->pipes[p].randr_crtc); + + if (randrp->virtualX == -1 || randrp->virtualY == -1) + { + randrp->virtualX = pScrn->virtualX; + randrp->virtualY = pScrn->virtualY; + } + + RRScreenSetSizeRange (pScreen, 320, 240, + randrp->virtualX, randrp->virtualY); + return TRUE; +} + +static void +I830RandRPointerMoved (int scrnIndex, int x, int y) +{ +} + +static Bool +I830RandRInit12 (ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + rrScrPrivPtr rp = rrGetScrPriv(pScreen); + + rp->rrGetInfo = I830RandRGetInfo12; + rp->rrScreenSetSize = I830RandRScreenSetSize; + rp->rrCrtcSet = I830RandRCrtcSet; + rp->rrCrtcSetGamma = I830RandRCrtcSetGamma; + rp->rrSetConfig = NULL; + pScrn->PointerMoved = I830RandRPointerMoved; + return TRUE; +} + +static RRModePtr +I830RRDefaultMode (RROutputPtr output) +{ + RRModePtr target_mode = NULL; + int target_diff = 0; + int mmHeight; + int num_modes; + int m; + + num_modes = output->numPreferred ? output->numPreferred : output->numModes; + mmHeight = output->mmHeight; + if (!mmHeight) + mmHeight = 203; /* 768 pixels at 96dpi */ + /* + * Pick a mode closest to 96dpi + */ + for (m = 0; m < num_modes; m++) + { + RRModePtr mode = output->modes[m]; + int dpi; + int diff; + + dpi = (mode->mode.height * 254) / (mmHeight * 10); + diff = dpi - 96; + diff = diff < 0 ? -diff : diff; + if (target_mode == NULL || diff < target_diff) + { + target_mode = mode; + target_diff = diff; + } + } + return target_mode; +} + +static RRModePtr +I830ClosestMode (RROutputPtr output, RRModePtr match) +{ + RRModePtr target_mode = NULL; + int target_diff = 0; + int m; + + /* + * Pick a mode closest to the specified mode + */ + for (m = 0; m < output->numModes; m++) + { + RRModePtr mode = output->modes[m]; + int dx, dy; + int diff; + + /* exact matches are preferred */ + if (mode == match) + return mode; + + dx = match->mode.width - mode->mode.width; + dy = match->mode.height - mode->mode.height; + diff = dx * dx + dy * dy; + if (target_mode == NULL || diff < target_diff) + { + target_mode = mode; + target_diff = diff; + } + } + return target_mode; +} + +static int +I830RRPickCrtcs (RROutputPtr *outputs, + RRCrtcPtr *best_crtcs, + RRModePtr *modes, + int num_outputs, + int n) +{ + int c, o, l; + RROutputPtr output; + RRCrtcPtr crtc; + RRCrtcPtr *crtcs; + RRCrtcPtr best_crtc; + int best_score; + int score; + int my_score; + + if (n == num_outputs) + return 0; + output = outputs[n]; + + /* + * Compute score with this output disabled + */ + best_crtcs[n] = NULL; + best_crtc = NULL; + best_score = I830RRPickCrtcs (outputs, best_crtcs, modes, num_outputs, n+1); + if (modes[n] == NULL) + return best_score; + + crtcs = xalloc (num_outputs * sizeof (RRCrtcPtr)); + if (!crtcs) + return best_score; + + my_score = 1; + /* Score outputs that are known to be connected higher */ + if (output->connection == RR_Connected) + my_score++; + /* Score outputs with preferred modes higher */ + if (output->numPreferred) + my_score++; + /* + * Select a crtc for this output and + * then attempt to configure the remaining + * outputs + */ + for (c = 0; c < output->numCrtcs; c++) + { + crtc = output->crtcs[c]; + /* + * Check to see if some other output is + * using this crtc + */ + for (o = 0; o < n; o++) + if (best_crtcs[o] == crtc) + break; + if (o < n) + { + /* + * If the two outputs desire the same mode, + * see if they can be cloned + */ + if (modes[o] == modes[n]) + { + for (l = 0; l < output->numClones; l++) + if (output->clones[l] == outputs[o]) + break; + if (l == output->numClones) + continue; /* nope, try next CRTC */ + } + else + continue; /* different modes, can't clone */ + } + crtcs[n] = crtc; + memcpy (crtcs, best_crtcs, n * sizeof (RRCrtcPtr)); + score = my_score + I830RRPickCrtcs (outputs, crtcs, modes, + num_outputs, n+1); + if (score >= best_score) + { + best_crtc = crtc; + best_score = score; + memcpy (best_crtcs, crtcs, num_outputs * sizeof (RRCrtcPtr)); + } + } + xfree (crtcs); + return best_score; +} + +static Bool +I830RRInitialConfiguration (RROutputPtr *outputs, + RRCrtcPtr *crtcs, + RRModePtr *modes, + int num_outputs) +{ + int o; + RRModePtr target_mode = NULL; + + for (o = 0; o < num_outputs; o++) + modes[o] = NULL; + + /* + * Let outputs with preferred modes drive screen size + */ + for (o = 0; o < num_outputs; o++) + { + RROutputPtr output = outputs[o]; + + if (output->connection != RR_Disconnected && output->numPreferred) + { + target_mode = I830RRDefaultMode (output); + if (target_mode) + { + modes[o] = target_mode; + break; + } + } + } + if (!target_mode) + { + for (o = 0; o < num_outputs; o++) + { + RROutputPtr output = outputs[o]; + if (output->connection != RR_Disconnected) + { + target_mode = I830RRDefaultMode (output); + if (target_mode) + { + modes[o] = target_mode; + break; + } + } + } + } + for (o = 0; o < num_outputs; o++) + { + RROutputPtr output = outputs[o]; + + if (output->connection != RR_Disconnected && !modes[o]) + modes[o] = I830ClosestMode (output, target_mode); + } + + if (!I830RRPickCrtcs (outputs, crtcs, modes, num_outputs, 0)) + return FALSE; + + return TRUE; +} + +/* + * Compute the virtual size necessary to place all of the available + * crtcs in a panorama configuration + */ + +static void +I830RRDefaultScreenLimits (RROutputPtr *outputs, int num_outputs, + RRCrtcPtr *crtcs, int num_crtc, + int *widthp, int *heightp) +{ + int width = 0, height = 0; + int o; + int c; + int m; + int s; + + for (c = 0; c < num_crtc; c++) + { + RRCrtcPtr crtc = crtcs[c]; + int crtc_width = 1600, crtc_height = 1200; + + for (o = 0; o < num_outputs; o++) + { + RROutputPtr output = outputs[o]; + + for (s = 0; s < output->numCrtcs; s++) + if (output->crtcs[s] == crtc) + break; + if (s == output->numCrtcs) + continue; + for (m = 0; m < output->numModes; m++) + { + RRModePtr mode = output->modes[m]; + if (mode->mode.width > crtc_width) + crtc_width = mode->mode.width; + if (mode->mode.height > crtc_width) + crtc_height = mode->mode.height; + } + } + width += crtc_width; + if (crtc_height > height) + height = crtc_height; + } + *widthp = width; + *heightp = height; +} + +#endif + +Bool +I830RandRPreInit (ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); +#if RANDR_12_INTERFACE + RROutputPtr outputs[MAX_OUTPUTS]; + RRCrtcPtr output_crtcs[MAX_OUTPUTS]; + RRModePtr output_modes[MAX_OUTPUTS]; + RRCrtcPtr crtcs[MAX_DISPLAY_PIPES]; + int width, height; + int o; + int c; +#endif + + if (pI830->num_outputs <= 0) + return FALSE; + + i830_reprobe_output_modes(pScrn); + +#if RANDR_12_INTERFACE + if (!I830RandRCreateObjects12 (pScrn)) + return FALSE; + + /* + * Configure output modes + */ + if (!I830RandRSetInfo12 (pScrn)) + return FALSE; + /* + * With RandR info set up, let RandR choose + * the initial configuration + */ + for (o = 0; o < pI830->num_outputs; o++) + outputs[o] = pI830->output[o].randr_output; + for (c = 0; c < pI830->num_pipes; c++) + crtcs[c] = pI830->pipes[c].randr_crtc; + + if (!I830RRInitialConfiguration (outputs, output_crtcs, output_modes, + pI830->num_outputs)) + return FALSE; + + I830RRDefaultScreenLimits (outputs, pI830->num_outputs, + crtcs, pI830->num_pipes, + &width, &height); + + if (width > pScrn->virtualX) + pScrn->virtualX = width; + if (height > pScrn->virtualY) + pScrn->virtualY = height; + + for (o = 0; o < pI830->num_outputs; o++) + { + RRModePtr randr_mode = output_modes[o]; + DisplayModePtr mode; + RRCrtcPtr randr_crtc = output_crtcs[o]; + int pipe; + Bool enabled; + + if (randr_mode) + mode = (DisplayModePtr) randr_mode->devPrivate; + else + mode = NULL; + if (randr_crtc) + { + pipe = (int) randr_crtc->devPrivate; + enabled = TRUE; + } + else + { + pipe = 0; + enabled = FALSE; + } + if (mode) + pI830->pipes[pipe].desiredMode = *mode; + pI830->output[o].pipe = pipe; + pI830->output[o].enabled = enabled; + } +#endif + i830_set_xf86_modes_from_outputs (pScrn); + + i830_set_default_screen_size(pScrn); + return TRUE; } diff --git a/src/i830_sdvo.c b/src/i830_sdvo.c new file mode 100644 index 00000000..8d1f296c --- /dev/null +++ b/src/i830_sdvo.c @@ -0,0 +1,1067 @@ +/************************************************************************** + + Copyright 2006 Dave Airlie + +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. + +**************************************************************************/ + +/** @file + * SDVO support for i915 and newer chipsets. + * + * The SDVO outputs send digital display data out over the PCIE bus to display + * cards implementing a defined interface. These cards may have DVI, TV, CRT, + * or other outputs on them. + * + * The system has two SDVO channels, which may be used for SDVO chips on the + * motherboard, or in the external cards. The two channels may also be used + * in a ganged mode to provide higher bandwidth to a single output. Currently, + * this code doesn't deal with either ganged mode or more than one SDVO output. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "xf86.h" +#include "xf86_OSproc.h" +#include "compiler.h" +#include "i830.h" +#include "i830_display.h" +#include "i810_reg.h" +#include "i830_sdvo_regs.h" + +/** SDVO driver private structure. */ +struct i830_sdvo_priv { + /** SDVO device on SDVO I2C bus. */ + I2CDevRec d; + + /** Register for the SDVO device: SDVOB or SDVOC */ + int output_device; + + /** Active outputs controlled by this SDVO output */ + struct i830_sdvo_output_flags active_outputs; + + /** + * Capabilities of the SDVO device returned by i830_sdvo_get_capabilities() + */ + struct i830_sdvo_caps caps; + + /** Pixel clock limitations reported by the SDVO device, in kHz */ + int pixel_clock_min, pixel_clock_max; + + /** State for save/restore */ + /** @{ */ + int save_sdvo_mult; + struct i830_sdvo_output_flags save_active_outputs; + struct i830_sdvo_dtd save_input_dtd_1, save_input_dtd_2; + struct i830_sdvo_dtd save_output_dtd; + CARD32 save_SDVOX; + /** @} */ +}; + +/** Read a single byte from the given address on the SDVO device. */ +static Bool i830_sdvo_read_byte(I830OutputPtr output, int addr, + unsigned char *ch) +{ + struct i830_sdvo_priv *dev_priv = output->dev_priv; + + if (!xf86I2CReadByte(&dev_priv->d, addr, ch)) { + xf86DrvMsg(output->pI2CBus->scrnIndex, X_ERROR, + "Unable to read from %s slave %d.\n", + output->pI2CBus->BusName, dev_priv->d.SlaveAddr); + return FALSE; + } + return TRUE; +} + +/** Write a single byte to the given address on the SDVO device. */ +static Bool i830_sdvo_write_byte(I830OutputPtr output, + int addr, unsigned char ch) +{ + struct i830_sdvo_priv *dev_priv = output->dev_priv; + + if (!xf86I2CWriteByte(&dev_priv->d, addr, ch)) { + xf86DrvMsg(output->pI2CBus->scrnIndex, X_ERROR, + "Unable to write to %s Slave %d.\n", + output->pI2CBus->BusName, dev_priv->d.SlaveAddr); + return FALSE; + } + return TRUE; +} + + +#define SDVO_CMD_NAME_ENTRY(cmd) {cmd, #cmd} +/** Mapping of command numbers to names, for debug output */ +const struct _sdvo_cmd_name { + CARD8 cmd; + char *name; +} sdvo_cmd_names[] = { + SDVO_CMD_NAME_ENTRY(SDVO_CMD_RESET), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_DEVICE_CAPS), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_FIRMWARE_REV), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_TRAINED_INPUTS), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_ACTIVE_OUTPUTS), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_ACTIVE_OUTPUTS), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_IN_OUT_MAP), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_IN_OUT_MAP), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_ATTACHED_DISPLAYS), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_HOT_PLUG_SUPPORT), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_ACTIVE_HOT_PLUG), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_ACTIVE_HOT_PLUG), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_INTERRUPT_EVENT_SOURCE), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TARGET_INPUT), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TARGET_OUTPUT), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_INPUT_TIMINGS_PART1), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_INPUT_TIMINGS_PART2), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_INPUT_TIMINGS_PART1), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_INPUT_TIMINGS_PART2), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_INPUT_TIMINGS_PART1), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_OUTPUT_TIMINGS_PART1), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_OUTPUT_TIMINGS_PART2), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_OUTPUT_TIMINGS_PART1), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_OUTPUT_TIMINGS_PART2), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_CREATE_PREFERRED_INPUT_TIMING), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART1), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART2), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_INPUT_PIXEL_CLOCK_RANGE), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_OUTPUT_PIXEL_CLOCK_RANGE), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SUPPORTED_CLOCK_RATE_MULTS), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_CLOCK_RATE_MULT), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_CLOCK_RATE_MULT), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SUPPORTED_TV_FORMATS), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_TV_FORMAT), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TV_FORMAT), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TV_RESOLUTION_SUPPORT), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_CONTROL_BUS_SWITCH), +}; + +/** + * Writes out the data given in args (up to 8 bytes), followed by the opcode. + */ +static void +i830_sdvo_write_cmd(I830OutputPtr output, CARD8 cmd, void *args, int args_len) +{ + int i; + + /* Write the SDVO command logging */ + xf86DrvMsg(output->pI2CBus->scrnIndex, X_INFO, "SDVO: W: %02X ", cmd); + for (i = 0; i < args_len; i++) + LogWrite(1, "%02X ", ((CARD8 *)args)[i]); + for (; i < 8; i++) + LogWrite(1, " "); + for (i = 0; i < sizeof(sdvo_cmd_names) / sizeof(sdvo_cmd_names[0]); i++) { + if (cmd == sdvo_cmd_names[i].cmd) { + LogWrite(1, "(%s)", sdvo_cmd_names[i].name); + break; + } + } + if (i == sizeof(sdvo_cmd_names) / sizeof(sdvo_cmd_names[0])) + LogWrite(1, "(%02X)", cmd); + LogWrite(1, "\n"); + + /* send the output regs */ + for (i = 0; i < args_len; i++) { + i830_sdvo_write_byte(output, SDVO_I2C_ARG_0 - i, ((CARD8 *)args)[i]); + } + /* blast the command reg */ + i830_sdvo_write_byte(output, SDVO_I2C_OPCODE, cmd); +} + +static const char *cmd_status_names[] = { + "Power on", + "Success", + "Not supported", + "Invalid arg", + "Pending", + "Target not specified", + "Scaling not supported" +}; + +/** + * Reads back response_len bytes from the SDVO device, and returns the status. + */ +static CARD8 +i830_sdvo_read_response(I830OutputPtr output, void *response, int response_len) +{ + int i; + CARD8 status; + + /* Read the command response */ + for (i = 0; i < response_len; i++) { + i830_sdvo_read_byte(output, SDVO_I2C_RETURN_0 + i, + &((CARD8 *)response)[i]); + } + + /* Read the return status */ + i830_sdvo_read_byte(output, SDVO_I2C_CMD_STATUS, &status); + + /* Write the SDVO command logging */ + xf86DrvMsg(output->pI2CBus->scrnIndex, X_INFO, + "SDVO: R: "); + for (i = 0; i < response_len; i++) + LogWrite(1, "%02X ", ((CARD8 *)response)[i]); + for (; i < 8; i++) + LogWrite(1, " "); + if (status <= SDVO_CMD_STATUS_SCALING_NOT_SUPP) + { + LogWrite(1, "(%s)", cmd_status_names[status]); + } else { + LogWrite(1, "(??? %d)", status); + } + LogWrite(1, "\n"); + + return status; +} + +int +i830_sdvo_get_pixel_multiplier(DisplayModePtr pMode) +{ + if (pMode->Clock >= 100000) + return 1; + else if (pMode->Clock >= 50000) + return 2; + else + return 4; +} + +/* Sets the control bus switch to either point at one of the DDC buses or the + * PROM. It resets from the DDC bus back to internal registers at the next I2C + * STOP. PROM access is terminated by accessing an internal register. + */ +static void +i830_sdvo_set_control_bus_switch(I830OutputPtr output, CARD8 target) +{ + i830_sdvo_write_cmd(output, SDVO_CMD_SET_CONTROL_BUS_SWITCH, &target, 1); +} + +static Bool +i830_sdvo_set_target_input(I830OutputPtr output, Bool target_0, Bool target_1) +{ + struct i830_sdvo_set_target_input_args targets = {0}; + CARD8 status; + + if (target_0 && target_1) + return SDVO_CMD_STATUS_NOTSUPP; + + if (target_1) + targets.target_1 = 1; + + i830_sdvo_write_cmd(output, SDVO_CMD_SET_TARGET_INPUT, &targets, + sizeof(targets)); + + status = i830_sdvo_read_response(output, NULL, 0); + + return (status == SDVO_CMD_STATUS_SUCCESS); +} + +/** + * Return whether each input is trained. + * + * This function is making an assumption about the layout of the response, + * which should be checked against the docs. + */ +static Bool +i830_sdvo_get_trained_inputs(I830OutputPtr output, Bool *input_1, Bool *input_2) +{ + struct i830_sdvo_get_trained_inputs_response response; + CARD8 status; + + i830_sdvo_write_cmd(output, SDVO_CMD_GET_TRAINED_INPUTS, NULL, 0); + + status = i830_sdvo_read_response(output, &response, sizeof(response)); + if (status != SDVO_CMD_STATUS_SUCCESS) + return FALSE; + + *input_1 = response.input0_trained; + *input_2 = response.input1_trained; + + return TRUE; +} + +static Bool +i830_sdvo_get_active_outputs(I830OutputPtr output, + struct i830_sdvo_output_flags *outputs) +{ + CARD8 status; + + i830_sdvo_write_cmd(output, SDVO_CMD_GET_ACTIVE_OUTPUTS, NULL, 0); + status = i830_sdvo_read_response(output, outputs, sizeof(*outputs)); + + return (status == SDVO_CMD_STATUS_SUCCESS); +} + +static Bool +i830_sdvo_set_active_outputs(I830OutputPtr output, + struct i830_sdvo_output_flags *outputs) +{ + CARD8 status; + + i830_sdvo_write_cmd(output, SDVO_CMD_SET_ACTIVE_OUTPUTS, outputs, + sizeof(*outputs)); + status = i830_sdvo_read_response(output, NULL, 0); + + return (status == SDVO_CMD_STATUS_SUCCESS); +} + +/** + * Returns the pixel clock range limits of the current target input in kHz. + */ +static Bool +i830_sdvo_get_input_pixel_clock_range(I830OutputPtr output, int *clock_min, + int *clock_max) +{ + struct i830_sdvo_pixel_clock_range clocks; + CARD8 status; + + i830_sdvo_write_cmd(output, SDVO_CMD_GET_INPUT_PIXEL_CLOCK_RANGE, NULL, 0); + + status = i830_sdvo_read_response(output, &clocks, sizeof(clocks)); + + if (status != SDVO_CMD_STATUS_SUCCESS) + return FALSE; + + /* Convert the values from units of 10 kHz to kHz. */ + *clock_min = clocks.min * 10; + *clock_max = clocks.max * 10; + + return TRUE; +} + +static Bool +i830_sdvo_set_target_output(I830OutputPtr output, + struct i830_sdvo_output_flags *outputs) +{ + CARD8 status; + + i830_sdvo_write_cmd(output, SDVO_CMD_SET_TARGET_OUTPUT, outputs, + sizeof(*outputs)); + + status = i830_sdvo_read_response(output, NULL, 0); + + return (status == SDVO_CMD_STATUS_SUCCESS); +} + +/** Fetches either input or output timings to *dtd, depending on cmd. */ +static Bool +i830_sdvo_get_timing(I830OutputPtr output, CARD8 cmd, struct i830_sdvo_dtd *dtd) +{ + CARD8 status; + + i830_sdvo_write_cmd(output, cmd, NULL, 0); + + status = i830_sdvo_read_response(output, &dtd->part1, sizeof(dtd->part1)); + if (status != SDVO_CMD_STATUS_SUCCESS) + return FALSE; + + i830_sdvo_write_cmd(output, cmd + 1, NULL, 0); + + status = i830_sdvo_read_response(output, &dtd->part2, sizeof(dtd->part2)); + if (status != SDVO_CMD_STATUS_SUCCESS) + return FALSE; + + return TRUE; +} + +static Bool +i830_sdvo_get_input_timing(I830OutputPtr output, struct i830_sdvo_dtd *dtd) +{ + return i830_sdvo_get_timing(output, SDVO_CMD_GET_INPUT_TIMINGS_PART1, dtd); +} + +static Bool +i830_sdvo_get_output_timing(I830OutputPtr output, struct i830_sdvo_dtd *dtd) +{ + return i830_sdvo_get_timing(output, SDVO_CMD_GET_OUTPUT_TIMINGS_PART1, dtd); +} + +/** Sets either input or output timings from *dtd, depending on cmd. */ +static Bool +i830_sdvo_set_timing(I830OutputPtr output, CARD8 cmd, struct i830_sdvo_dtd *dtd) +{ + CARD8 status; + + i830_sdvo_write_cmd(output, cmd, &dtd->part1, sizeof(dtd->part1)); + status = i830_sdvo_read_response(output, NULL, 0); + if (status != SDVO_CMD_STATUS_SUCCESS) + return FALSE; + + i830_sdvo_write_cmd(output, cmd + 1, &dtd->part2, sizeof(dtd->part2)); + status = i830_sdvo_read_response(output, NULL, 0); + if (status != SDVO_CMD_STATUS_SUCCESS) + return FALSE; + + return TRUE; +} + +static Bool +i830_sdvo_set_input_timing(I830OutputPtr output, struct i830_sdvo_dtd *dtd) +{ + return i830_sdvo_set_timing(output, SDVO_CMD_SET_INPUT_TIMINGS_PART1, dtd); +} + +static Bool +i830_sdvo_set_output_timing(I830OutputPtr output, struct i830_sdvo_dtd *dtd) +{ + return i830_sdvo_set_timing(output, SDVO_CMD_SET_OUTPUT_TIMINGS_PART1, dtd); +} + +#if 0 +static Bool +i830_sdvo_create_preferred_input_timing(I830OutputPtr output, CARD16 clock, + CARD16 width, CARD16 height) +{ + struct i830_sdvo_priv *dev_priv = output->dev_priv; + struct i830_sdvo_preferred_input_timing_args args; + + args.clock = clock; + args.width = width; + args.height = height; + i830_sdvo_write_cmd(output, SDVO_CMD_CREATE_PREFERRED_INPUT_TIMING, + &args, sizeof(args)); + status = i830_sdvo_read_response(output, NULL, 0); + if (status != SDVO_CMD_STATUS_SUCCESS) + return FALSE; + + return TRUE; +} + +static Bool +i830_sdvo_get_preferred_input_timing(I830OutputPtr output, + struct i830_sdvo_dtd *dtd) +{ + struct i830_sdvo_priv *dev_priv = output->dev_priv; + + i830_sdvo_write_cmd(output, SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART1, + NULL, 0); + + status = i830_sdvo_read_response(output, &dtd->part1, sizeof(dtd->part1)); + if (status != SDVO_CMD_STATUS_SUCCESS) + return FALSE; + + i830_sdvo_write_cmd(output, SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART2, + NULL, 0); + + status = i830_sdvo_read_response(output, &dtd->part2, sizeof(dtd->part2)); + if (status != SDVO_CMD_STATUS_SUCCESS) + return FALSE; + + return TRUE; +} +#endif + +/** Returns the SDVO_CLOCK_RATE_MULT_* for the current clock multiplier */ +static int +i830_sdvo_get_clock_rate_mult(I830OutputPtr output) +{ + struct i830_sdvo_priv *dev_priv = output->dev_priv; + CARD8 response; + CARD8 status; + + i830_sdvo_write_cmd(output, SDVO_CMD_GET_CLOCK_RATE_MULT, NULL, 0); + status = i830_sdvo_read_response(output, &response, 1); + + if (status != SDVO_CMD_STATUS_SUCCESS) { + xf86DrvMsg(dev_priv->d.pI2CBus->scrnIndex, X_ERROR, + "Couldn't get SDVO clock rate multiplier\n"); + return SDVO_CLOCK_RATE_MULT_1X; + } else { + xf86DrvMsg(dev_priv->d.pI2CBus->scrnIndex, X_INFO, + "Current clock rate multiplier: %d\n", response); + } + + return response; +} + +/** + * Sets the current clock multiplier. + * + * This has to match with the settings in the DPLL/SDVO reg when the output + * is actually turned on. + */ +static Bool +i830_sdvo_set_clock_rate_mult(I830OutputPtr output, CARD8 val) +{ + CARD8 status; + + i830_sdvo_write_cmd(output, SDVO_CMD_SET_CLOCK_RATE_MULT, &val, 1); + status = i830_sdvo_read_response(output, NULL, 0); + if (status != SDVO_CMD_STATUS_SUCCESS) + return FALSE; + + return TRUE; +} + +static void +i830_sdvo_pre_set_mode(ScrnInfoPtr pScrn, I830OutputPtr output, + DisplayModePtr mode) +{ + I830Ptr pI830 = I830PTR(pScrn); + struct i830_sdvo_priv *dev_priv = output->dev_priv; + CARD16 width; + CARD16 height; + CARD16 h_blank_len, h_sync_len, v_blank_len, v_sync_len; + CARD16 h_sync_offset, v_sync_offset; + struct i830_sdvo_dtd output_dtd; + struct i830_sdvo_output_flags no_outputs; + + memset(&no_outputs, 0, sizeof(no_outputs)); + + if (!mode) + return; + width = mode->CrtcHDisplay; + height = mode->CrtcVDisplay; + + /* do some mode translations */ + h_blank_len = mode->CrtcHBlankEnd - mode->CrtcHBlankStart; + h_sync_len = mode->CrtcHSyncEnd - mode->CrtcHSyncStart; + + v_blank_len = mode->CrtcVBlankEnd - mode->CrtcVBlankStart; + v_sync_len = mode->CrtcVSyncEnd - mode->CrtcVSyncStart; + + h_sync_offset = mode->CrtcHSyncStart - mode->CrtcHBlankStart; + v_sync_offset = mode->CrtcVSyncStart - mode->CrtcVBlankStart; + + output_dtd.part1.clock = mode->Clock / 10; + output_dtd.part1.h_active = width & 0xff; + output_dtd.part1.h_blank = h_blank_len & 0xff; + output_dtd.part1.h_high = (((width >> 8) & 0xf) << 4) | + ((h_blank_len >> 8) & 0xf); + output_dtd.part1.v_active = height & 0xff; + output_dtd.part1.v_blank = v_blank_len & 0xff; + output_dtd.part1.v_high = (((height >> 8) & 0xf) << 4) | + ((v_blank_len >> 8) & 0xf); + + output_dtd.part2.h_sync_off = h_sync_offset; + output_dtd.part2.h_sync_width = h_sync_len & 0xff; + output_dtd.part2.v_sync_off_width = (v_sync_offset & 0xf) << 4 | + (v_sync_len & 0xf); + output_dtd.part2.sync_off_width_high = ((h_sync_offset & 0x300) >> 2) | + ((h_sync_len & 0x300) >> 4) | ((v_sync_offset & 0x30) >> 2) | + ((v_sync_len & 0x30) >> 4); + + output_dtd.part2.dtd_flags = 0x18; + if (mode->Flags & V_PHSYNC) + output_dtd.part2.dtd_flags |= 0x2; + if (mode->Flags & V_PVSYNC) + output_dtd.part2.dtd_flags |= 0x4; + + output_dtd.part2.sdvo_flags = 0; + output_dtd.part2.v_sync_off_high = v_sync_offset & 0xc0; + output_dtd.part2.reserved = 0; + + /* Turn off the screens before adjusting timings */ + i830_sdvo_set_active_outputs(output, &no_outputs); + + /* Set the output timing to the screen */ + i830_sdvo_set_target_output(output, &dev_priv->active_outputs); + i830_sdvo_set_output_timing(output, &output_dtd); + + /* Set the input timing to the screen. Assume always input 0. */ + i830_sdvo_set_target_input(output, TRUE, FALSE); + + /* We would like to use i830_sdvo_create_preferred_input_timing() to + * provide the device with a timing it can support, if it supports that + * feature. However, presumably we would need to adjust the CRTC to output + * the preferred timing, and we don't support that currently. + */ +#if 0 + success = i830_sdvo_create_preferred_input_timing(output, clock, + width, height); + if (success) { + struct i830_sdvo_dtd *input_dtd; + + i830_sdvo_get_preferred_input_timing(output, &input_dtd); + i830_sdvo_set_input_timing(output, &input_dtd); + } +#else + i830_sdvo_set_input_timing(output, &output_dtd); +#endif + + switch (i830_sdvo_get_pixel_multiplier(mode)) { + case 1: + i830_sdvo_set_clock_rate_mult(output, SDVO_CLOCK_RATE_MULT_1X); + break; + case 2: + i830_sdvo_set_clock_rate_mult(output, SDVO_CLOCK_RATE_MULT_2X); + break; + case 4: + i830_sdvo_set_clock_rate_mult(output, SDVO_CLOCK_RATE_MULT_4X); + break; + } + + OUTREG(SDVOC, INREG(SDVOC) & ~SDVO_ENABLE); + OUTREG(SDVOB, INREG(SDVOB) & ~SDVO_ENABLE); +} + +static void +i830_sdvo_post_set_mode(ScrnInfoPtr pScrn, I830OutputPtr output, + DisplayModePtr mode) +{ + I830Ptr pI830 = I830PTR(pScrn); + struct i830_sdvo_priv *dev_priv = output->dev_priv; + Bool input1, input2; + CARD32 dpll, sdvob, sdvoc; + int dpll_reg = (output->pipe == 0) ? DPLL_A : DPLL_B; + int dpll_md_reg = (output->pipe == 0) ? DPLL_A_MD : DPLL_B_MD; + int sdvo_pixel_multiply; + int i; + CARD8 status; + + /* Set the SDVO control regs. */ + sdvob = INREG(SDVOB) & SDVOB_PRESERVE_MASK; + sdvoc = INREG(SDVOC) & SDVOC_PRESERVE_MASK; + sdvob |= SDVO_ENABLE | (9 << 19) | SDVO_BORDER_ENABLE; + sdvoc |= 9 << 19; + if (output->pipe == 1) + sdvob |= SDVO_PIPE_B_SELECT; + + dpll = INREG(dpll_reg); + + sdvo_pixel_multiply = i830_sdvo_get_pixel_multiplier(mode); + if (IS_I965G(pI830)) { + OUTREG(dpll_md_reg, (0 << DPLL_MD_UDI_DIVIDER_SHIFT) | + ((sdvo_pixel_multiply - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT)); + } else if (IS_I945G(pI830) || IS_I945GM(pI830)) { + dpll |= (sdvo_pixel_multiply - 1) << SDVO_MULTIPLIER_SHIFT_HIRES; + } else { + sdvob |= (sdvo_pixel_multiply - 1) << SDVO_PORT_MULTIPLY_SHIFT; + } + + OUTREG(dpll_reg, dpll | DPLL_DVO_HIGH_SPEED); + + OUTREG(SDVOB, sdvob); + OUTREG(SDVOC, sdvoc); + + for (i = 0; i < 2; i++) + i830WaitForVblank(pScrn); + + status = i830_sdvo_get_trained_inputs(output, &input1, &input2); + + /* Warn if the device reported failure to sync. */ + if (status == SDVO_CMD_STATUS_SUCCESS && !input1) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "First SDVO output reported failure to sync\n"); + } + + i830_sdvo_set_active_outputs(output, &dev_priv->active_outputs); + i830_sdvo_set_target_input(output, TRUE, FALSE); +} + +static void +i830_sdvo_dpms(ScrnInfoPtr pScrn, I830OutputPtr output, int mode) +{ + I830Ptr pI830 = I830PTR(pScrn); + struct i830_sdvo_priv *dev_priv = output->dev_priv; + + if (mode != DPMSModeOn) { + struct i830_sdvo_output_flags no_outputs; + + memset(&no_outputs, 0, sizeof(no_outputs)); + + i830_sdvo_set_active_outputs(output, &no_outputs); + OUTREG(SDVOB, INREG(SDVOB) & ~SDVO_ENABLE); + } else { + i830_sdvo_set_active_outputs(output, &dev_priv->active_outputs); + OUTREG(SDVOB, INREG(SDVOB) | SDVO_ENABLE); + } +} + +static void +i830_sdvo_save(ScrnInfoPtr pScrn, I830OutputPtr output) +{ + I830Ptr pI830 = I830PTR(pScrn); + struct i830_sdvo_priv *dev_priv = output->dev_priv; + + /* XXX: We should save the in/out mapping. */ + + dev_priv->save_sdvo_mult = i830_sdvo_get_clock_rate_mult(output); + i830_sdvo_get_active_outputs(output, &dev_priv->save_active_outputs); + + if (dev_priv->caps.sdvo_inputs_mask & 0x1) { + i830_sdvo_set_target_input(output, TRUE, FALSE); + i830_sdvo_get_input_timing(output, &dev_priv->save_input_dtd_1); + } + + if (dev_priv->caps.sdvo_inputs_mask & 0x2) { + i830_sdvo_set_target_input(output, FALSE, TRUE); + i830_sdvo_get_input_timing(output, &dev_priv->save_input_dtd_2); + } + + /* XXX: We should really iterate over the enabled outputs and save each + * one's state. + */ + i830_sdvo_set_target_output(output, &dev_priv->save_active_outputs); + i830_sdvo_get_output_timing(output, &dev_priv->save_output_dtd); + + dev_priv->save_SDVOX = INREG(dev_priv->output_device); +} + +static void +i830_sdvo_restore(ScrnInfoPtr pScrn, I830OutputPtr output) +{ + I830Ptr pI830 = I830PTR(pScrn); + struct i830_sdvo_priv *dev_priv = output->dev_priv; + + if (dev_priv->caps.sdvo_inputs_mask & 0x1) { + i830_sdvo_set_target_input(output, TRUE, FALSE); + i830_sdvo_set_input_timing(output, &dev_priv->save_input_dtd_1); + } + + if (dev_priv->caps.sdvo_inputs_mask & 0x2) { + i830_sdvo_set_target_input(output, FALSE, TRUE); + i830_sdvo_set_input_timing(output, &dev_priv->save_input_dtd_2); + } + + i830_sdvo_set_target_output(output, &dev_priv->save_active_outputs); + i830_sdvo_set_output_timing(output, &dev_priv->save_output_dtd); + + i830_sdvo_set_clock_rate_mult(output, dev_priv->save_sdvo_mult); + + OUTREG(dev_priv->output_device, dev_priv->save_SDVOX); + + i830_sdvo_set_active_outputs(output, &dev_priv->save_active_outputs); +} + +static int +i830_sdvo_mode_valid(ScrnInfoPtr pScrn, I830OutputPtr output, + DisplayModePtr pMode) +{ + struct i830_sdvo_priv *dev_priv = output->dev_priv; + + if (pMode->Flags & V_DBLSCAN) + return MODE_NO_DBLESCAN; + + if (dev_priv->pixel_clock_min > pMode->Clock) + return MODE_CLOCK_HIGH; + + if (dev_priv->pixel_clock_max < pMode->Clock) + return MODE_CLOCK_LOW; + + return MODE_OK; +} + +static Bool +i830_sdvo_get_capabilities(I830OutputPtr output, struct i830_sdvo_caps *caps) +{ + CARD8 status; + + i830_sdvo_write_cmd(output, SDVO_CMD_GET_DEVICE_CAPS, NULL, 0); + status = i830_sdvo_read_response(output, caps, sizeof(*caps)); + if (status != SDVO_CMD_STATUS_SUCCESS) + return FALSE; + + return TRUE; +} + +/** Forces the device over to the real I2C bus and uses its GetByte */ +static Bool +i830_sdvo_ddc_i2c_get_byte(I2CDevPtr d, I2CByte *data, Bool last) +{ + I830OutputPtr output = d->pI2CBus->DriverPrivate.ptr; + I2CBusPtr i2cbus = output->pI2CBus, savebus; + Bool ret; + + savebus = d->pI2CBus; + d->pI2CBus = i2cbus; + ret = i2cbus->I2CGetByte(d, data, last); + d->pI2CBus = savebus; + + return ret; +} + +/** Forces the device over to the real I2C bus and uses its PutByte */ +static Bool +i830_sdvo_ddc_i2c_put_byte(I2CDevPtr d, I2CByte c) +{ + I830OutputPtr output = d->pI2CBus->DriverPrivate.ptr; + I2CBusPtr i2cbus = output->pI2CBus, savebus; + Bool ret; + + savebus = d->pI2CBus; + d->pI2CBus = i2cbus; + ret = i2cbus->I2CPutByte(d, c); + d->pI2CBus = savebus; + + return ret; +} + +/** + * Sets the control bus over to DDC before sending the start on the real I2C + * bus. + * + * The control bus will flip back at the stop following the start executed + * here. + */ +static Bool +i830_sdvo_ddc_i2c_start(I2CBusPtr b, int timeout) +{ + I830OutputPtr output = b->DriverPrivate.ptr; + I2CBusPtr i2cbus = output->pI2CBus; + + i830_sdvo_set_control_bus_switch(output, SDVO_CONTROL_BUS_DDC2); + return i2cbus->I2CStart(i2cbus, timeout); +} + +/** Forces the device over to the real SDVO bus and sends a stop to it. */ +static void +i830_sdvo_ddc_i2c_stop(I2CDevPtr d) +{ + I830OutputPtr output = d->pI2CBus->DriverPrivate.ptr; + I2CBusPtr i2cbus = output->pI2CBus, savebus; + + savebus = d->pI2CBus; + d->pI2CBus = i2cbus; + i2cbus->I2CStop(d); + d->pI2CBus = savebus; +} + +/** + * Mirrors xf86i2c I2CAddress, using the bus's (wrapped) methods rather than + * the default methods. + * + * This ensures that our start commands always get wrapped with control bus + * switches. xf86i2c should probably be fixed to do this. + */ +static Bool +i830_sdvo_ddc_i2c_address(I2CDevPtr d, I2CSlaveAddr addr) +{ + if (d->pI2CBus->I2CStart(d->pI2CBus, d->StartTimeout)) { + if (d->pI2CBus->I2CPutByte(d, addr & 0xFF)) { + if ((addr & 0xF8) != 0xF0 && + (addr & 0xFE) != 0x00) + return TRUE; + + if (d->pI2CBus->I2CPutByte(d, (addr >> 8) & 0xFF)) + return TRUE; + } + + d->pI2CBus->I2CStop(d); + } + + return FALSE; +} + +static void +i830_sdvo_dump_cmd(I830OutputPtr output, int opcode) +{ + CARD8 response[8]; + + i830_sdvo_write_cmd(output, opcode, NULL, 0); + i830_sdvo_read_response(output, response, 8); +} + +static void +i830_sdvo_dump_device(I830OutputPtr output) +{ + struct i830_sdvo_priv *dev_priv = output->dev_priv; + + ErrorF("Dump %s\n", dev_priv->d.DevName); + i830_sdvo_dump_cmd(output, SDVO_CMD_GET_DEVICE_CAPS); + i830_sdvo_dump_cmd(output, SDVO_CMD_GET_FIRMWARE_REV); + i830_sdvo_dump_cmd(output, SDVO_CMD_GET_TRAINED_INPUTS); + i830_sdvo_dump_cmd(output, SDVO_CMD_GET_ACTIVE_OUTPUTS); + i830_sdvo_dump_cmd(output, SDVO_CMD_GET_IN_OUT_MAP); + i830_sdvo_dump_cmd(output, SDVO_CMD_GET_ATTACHED_DISPLAYS); + i830_sdvo_dump_cmd(output, SDVO_CMD_GET_HOT_PLUG_SUPPORT); + i830_sdvo_dump_cmd(output, SDVO_CMD_GET_ACTIVE_HOT_PLUG); + i830_sdvo_dump_cmd(output, SDVO_CMD_GET_INTERRUPT_EVENT_SOURCE); + i830_sdvo_dump_cmd(output, SDVO_CMD_GET_INPUT_TIMINGS_PART1); + i830_sdvo_dump_cmd(output, SDVO_CMD_GET_INPUT_TIMINGS_PART2); + i830_sdvo_dump_cmd(output, SDVO_CMD_GET_OUTPUT_TIMINGS_PART1); + i830_sdvo_dump_cmd(output, SDVO_CMD_GET_OUTPUT_TIMINGS_PART2); + i830_sdvo_dump_cmd(output, SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART1); + i830_sdvo_dump_cmd(output, SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART2); + i830_sdvo_dump_cmd(output, SDVO_CMD_GET_INPUT_PIXEL_CLOCK_RANGE); + i830_sdvo_dump_cmd(output, SDVO_CMD_GET_OUTPUT_PIXEL_CLOCK_RANGE); + i830_sdvo_dump_cmd(output, SDVO_CMD_GET_SUPPORTED_CLOCK_RATE_MULTS); + i830_sdvo_dump_cmd(output, SDVO_CMD_GET_CLOCK_RATE_MULT); + i830_sdvo_dump_cmd(output, SDVO_CMD_GET_SUPPORTED_TV_FORMATS); + i830_sdvo_dump_cmd(output, SDVO_CMD_GET_TV_FORMAT); +} + +void +i830_sdvo_dump(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + int i; + + for (i = 0; i < pI830->num_outputs; i++) { + if (pI830->output[i].type == I830_OUTPUT_SDVO) + i830_sdvo_dump_device(&pI830->output[i]); + } +} + +/** + * Asks the SDVO device if any displays are currently connected. + * + * This interface will need to be augmented, since we could potentially have + * multiple displays connected, and the caller will also probably want to know + * what type of display is connected. But this is enough for the moment. + * + * Takes 14ms on average on my i945G. + */ +static enum detect_status +i830_sdvo_detect(ScrnInfoPtr pScrn, I830OutputPtr output) +{ + CARD8 response[2]; + CARD8 status; + + i830_sdvo_write_cmd(output, SDVO_CMD_GET_ATTACHED_DISPLAYS, NULL, 0); + status = i830_sdvo_read_response(output, &response, 2); + + if (status != SDVO_CMD_STATUS_SUCCESS) + return OUTPUT_STATUS_UNKNOWN; + + if (response[0] != 0 || response[1] != 0) + return OUTPUT_STATUS_CONNECTED; + else + return OUTPUT_STATUS_DISCONNECTED; +} + +void +i830_sdvo_init(ScrnInfoPtr pScrn, int output_device) +{ + I830Ptr pI830 = I830PTR(pScrn); + I830OutputPtr output = &pI830->output[pI830->num_outputs]; + struct i830_sdvo_priv *dev_priv; + int i; + unsigned char ch[0x40]; + I2CBusPtr i2cbus = NULL, ddcbus; + + output->type = I830_OUTPUT_SDVO; + output->dpms = i830_sdvo_dpms; + output->save = i830_sdvo_save; + output->restore = i830_sdvo_restore; + output->mode_valid = i830_sdvo_mode_valid; + output->pre_set_mode = i830_sdvo_pre_set_mode; + output->post_set_mode = i830_sdvo_post_set_mode; + output->detect = i830_sdvo_detect; + output->get_modes = i830_ddc_get_modes; + + /* While it's the same bus, we just initialize a new copy to avoid trouble + * with tracking refcounting ourselves, since the XFree86 DDX bits don't. + */ + if (output_device == SDVOB) + I830I2CInit(pScrn, &i2cbus, GPIOE, "SDVOCTRL_E for SDVOB"); + else + I830I2CInit(pScrn, &i2cbus, GPIOE, "SDVOCTRL_E for SDVOC"); + + if (i2cbus == NULL) + return; + + /* Allocate the SDVO output private data */ + dev_priv = xcalloc(1, sizeof(struct i830_sdvo_priv)); + if (dev_priv == NULL) { + xf86DestroyI2CBusRec(i2cbus, TRUE, TRUE); + return; + } + + if (output_device == SDVOB) { + dev_priv->d.DevName = "SDVO Controller B"; + dev_priv->d.SlaveAddr = 0x70; + } else { + dev_priv->d.DevName = "SDVO Controller C"; + dev_priv->d.SlaveAddr = 0x72; + } + dev_priv->d.pI2CBus = i2cbus; + dev_priv->d.DriverPrivate.ptr = output; + dev_priv->output_device = output_device; + + if (!xf86I2CDevInit(&dev_priv->d)) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Failed to initialize SDVO I2C device %s\n", + output_device == SDVOB ? "SDVOB" : "SDVOC"); + xf86DestroyI2CBusRec(i2cbus, TRUE, TRUE); + xfree(dev_priv); + return; + } + + /* Set up our wrapper I2C bus for DDC. It acts just like the regular I2C + * bus, except that it does the control bus switch to DDC mode before every + * Start. While we only need to do it at Start after every Stop after a + * Start, extra attempts should be harmless. + */ + ddcbus = xf86CreateI2CBusRec(); + if (ddcbus == NULL) { + xf86DestroyI2CDevRec(&dev_priv->d, FALSE); + xf86DestroyI2CBusRec(i2cbus, TRUE, TRUE); + xfree(dev_priv); + return; + } + if (output_device == SDVOB) + ddcbus->BusName = "SDVOB DDC Bus"; + else + ddcbus->BusName = "SDVOC DDC Bus"; + ddcbus->scrnIndex = i2cbus->scrnIndex; + ddcbus->I2CGetByte = i830_sdvo_ddc_i2c_get_byte; + ddcbus->I2CPutByte = i830_sdvo_ddc_i2c_put_byte; + ddcbus->I2CStart = i830_sdvo_ddc_i2c_start; + ddcbus->I2CStop = i830_sdvo_ddc_i2c_stop; + ddcbus->I2CAddress = i830_sdvo_ddc_i2c_address; + ddcbus->DriverPrivate.ptr = &pI830->output[pI830->num_outputs]; + if (!xf86I2CBusInit(ddcbus)) { + xf86DestroyI2CDevRec(&dev_priv->d, FALSE); + xf86DestroyI2CBusRec(i2cbus, TRUE, TRUE); + xfree(dev_priv); + return; + } + + output->pI2CBus = i2cbus; + output->pDDCBus = ddcbus; + output->dev_priv = dev_priv; + + /* Read the regs to test if we can talk to the device */ + for (i = 0; i < 0x40; i++) { + if (!i830_sdvo_read_byte(output, i, &ch[i])) { + xf86DestroyI2CBusRec(output->pDDCBus, FALSE, FALSE); + xf86DestroyI2CDevRec(&dev_priv->d, FALSE); + xf86DestroyI2CBusRec(i2cbus, TRUE, TRUE); + xfree(dev_priv); + return; + } + } + + i830_sdvo_get_capabilities(output, &dev_priv->caps); + + i830_sdvo_get_input_pixel_clock_range(output, &dev_priv->pixel_clock_min, + &dev_priv->pixel_clock_max); + + memset(&dev_priv->active_outputs, 0, sizeof(dev_priv->active_outputs)); + dev_priv->active_outputs.tmds0 = 1; + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "SDVO device VID/DID: %02X:%02X.%02X, " + "clock range %.1fMHz - %.1fMHz, " + "input 1: %c, input 2: %c, " + "output 1: %c, output 2: %c\n", + dev_priv->caps.vendor_id, dev_priv->caps.device_id, + dev_priv->caps.device_rev_id, + dev_priv->pixel_clock_min / 1000.0, + dev_priv->pixel_clock_max / 1000.0, + (dev_priv->caps.sdvo_inputs_mask & 0x1) ? 'Y' : 'N', + (dev_priv->caps.sdvo_inputs_mask & 0x2) ? 'Y' : 'N', + dev_priv->caps.output_flags.tmds0 ? 'Y' : 'N', + dev_priv->caps.output_flags.tmds1 ? 'Y' : 'N'); + + pI830->num_outputs++; +} diff --git a/src/i830_sdvo.h b/src/i830_sdvo.h new file mode 100644 index 00000000..1368e43b --- /dev/null +++ b/src/i830_sdvo.h @@ -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 + * + */ + +void +i830_sdvo_init(ScrnInfoPtr pScrn, int output_device); + +int +i830_sdvo_get_pixel_multiplier(DisplayModePtr pMode); + +void +i830_sdvo_dump(ScrnInfoPtr pScrn); diff --git a/src/i830_sdvo_regs.h b/src/i830_sdvo_regs.h new file mode 100644 index 00000000..98aa7a6b --- /dev/null +++ b/src/i830_sdvo_regs.h @@ -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 + * + */ + +/** + * @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 + diff --git a/src/i830_tv.c b/src/i830_tv.c new file mode 100644 index 00000000..c597db53 --- /dev/null +++ b/src/i830_tv.c @@ -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 + * + */ + +/** @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++; +} diff --git a/src/i830_video.c b/src/i830_video.c index 054d26bb..d84c1c97 100644 --- a/src/i830_video.c +++ b/src/i830_video.c @@ -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; diff --git a/src/i830_video.h b/src/i830_video.h index 9e11641e..6a09a258 100644 --- a/src/i830_video.h +++ b/src/i830_video.h @@ -40,6 +40,7 @@ typedef struct { int brightness; int contrast; + int saturation; int pipe; int doubleBuffer; diff --git a/src/i830_xf86Modes.c b/src/i830_xf86Modes.c new file mode 100644 index 00000000..ca92e4d0 --- /dev/null +++ b/src/i830_xf86Modes.c @@ -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 +#include +#include + +#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 xx 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} +}; diff --git a/src/i830_xf86Modes.h b/src/i830_xf86Modes.h new file mode 100644 index 00000000..5a26c0e4 --- /dev/null +++ b/src/i830_xf86Modes.h @@ -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 + * + */ + +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[]; diff --git a/src/i915_video.c b/src/i915_video.c index 0833d508..78907efb 100644 --- a/src/i915_video.c +++ b/src/i915_video.c @@ -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; } diff --git a/src/sil164/Makefile.am b/src/sil164/Makefile.am new file mode 100644 index 00000000..bb84d036 --- /dev/null +++ b/src/sil164/Makefile.am @@ -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 diff --git a/src/sil164/sil164.c b/src/sil164/sil164.c new file mode 100644 index 00000000..0a68d691 --- /dev/null +++ b/src/sil164/sil164.c @@ -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, +}; diff --git a/src/sil164/sil164.h b/src/sil164/sil164.h new file mode 100644 index 00000000..9f823d6b --- /dev/null +++ b/src/sil164/sil164.h @@ -0,0 +1,31 @@ +/************************************************************************** + + Copyright 2006 Dave Airlie + +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 diff --git a/src/sil164/sil164_module.c b/src/sil164/sil164_module.c new file mode 100644 index 00000000..d3bda819 --- /dev/null +++ b/src/sil164/sil164_module.c @@ -0,0 +1,38 @@ +/* -*- c-basic-offset: 4 -*- */ + +#ifdef HAVE_XORG_CONFIG_H +#include +#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; +} diff --git a/src/sil164/sil164_reg.h b/src/sil164/sil164_reg.h new file mode 100644 index 00000000..ebfcb8c7 --- /dev/null +++ b/src/sil164/sil164_reg.h @@ -0,0 +1,74 @@ +/* -*- c-basic-offset: 4 -*- */ +/************************************************************************** + + Copyright 2006 Dave Airlie + +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 diff --git a/src/xvmc/.gitignore b/src/xvmc/.gitignore new file mode 100644 index 00000000..9730646f --- /dev/null +++ b/src/xvmc/.gitignore @@ -0,0 +1,6 @@ +.deps +.libs +Makefile +Makefile.in +*.la +*.lo diff --git a/src/xvmc/I810XvMC.c b/src/xvmc/I810XvMC.c index 89aa3ea4..03be2514 100644 --- a/src/xvmc/I810XvMC.c +++ b/src/xvmc/I810XvMC.c @@ -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);