summaryrefslogtreecommitdiff
path: root/driver/xf86-video-intel/src/intel_driver.c
diff options
context:
space:
mode:
Diffstat (limited to 'driver/xf86-video-intel/src/intel_driver.c')
-rw-r--r--driver/xf86-video-intel/src/intel_driver.c2875
1 files changed, 2875 insertions, 0 deletions
diff --git a/driver/xf86-video-intel/src/intel_driver.c b/driver/xf86-video-intel/src/intel_driver.c
new file mode 100644
index 000000000..5d9980ebf
--- /dev/null
+++ b/driver/xf86-video-intel/src/intel_driver.c
@@ -0,0 +1,2875 @@
+/**************************************************************************
+
+Copyright 2001 VA Linux Systems Inc., Fremont, California.
+Copyright © 2002 by David Dawes
+
+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.
+
+**************************************************************************/
+
+/*
+ * Authors: Jeff Hartmann <jhartmann@valinux.com>
+ * Abraham van der Merwe <abraham@2d3d.co.za>
+ * David Dawes <dawes@xfree86.org>
+ * Alan Hourihane <alanh@tungstengraphics.com>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifndef PRINT_MODE_INFO
+#define PRINT_MODE_INFO 0
+#endif
+
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <poll.h>
+
+#include "xf86.h"
+#include "xf86_OSproc.h"
+#include "xf86Priv.h"
+#include "xf86cmap.h"
+#include "compiler.h"
+#include "mibstore.h"
+#include "vgaHW.h"
+#include "mipointer.h"
+#include "micmap.h"
+#include "shadowfb.h"
+#include <X11/extensions/randr.h>
+#include "fb.h"
+#include "miscstruct.h"
+#include "dixstruct.h"
+#include "xf86xv.h"
+#include <X11/extensions/Xv.h>
+#include "shadow.h"
+#include "intel.h"
+#include "i830_reg.h"
+#include "i830_display.h"
+#include "i830_bios.h"
+#include "intel_video.h"
+
+#ifdef INTEL_XVMC
+#define _INTEL_XVMC_SERVER_
+#include "intel_hwmc.h"
+#endif
+
+#include "legacy/legacy.h"
+
+#include <sys/ioctl.h>
+#include "i915_drm.h"
+#include <xf86drmMode.h>
+
+#define BIT(x) (1 << (x))
+#define MAX(a,b) ((a) > (b) ? (a) : (b))
+#define NB_OF(x) (sizeof (x) / sizeof (*x))
+
+/* *INDENT-OFF* */
+/*
+ * Note: "ColorKey" is provided for compatibility with the i810 driver.
+ * However, the correct option name is "VideoKey". "ColorKey" usually
+ * refers to the tranparency key for 8+24 overlays, not for video overlays.
+ */
+
+typedef enum {
+ OPTION_DRI,
+ OPTION_VIDEO_KEY,
+ OPTION_COLOR_KEY,
+ OPTION_MODEDEBUG,
+ OPTION_FALLBACKDEBUG,
+ OPTION_LVDS24BITMODE,
+ OPTION_FBC,
+ OPTION_TILING_FB,
+ OPTION_TILING_2D,
+ OPTION_SHADOW,
+ OPTION_SWAPBUFFERS_WAIT,
+ OPTION_LVDSFIXEDMODE,
+ OPTION_FORCEENABLEPIPEA,
+#ifdef INTEL_XVMC
+ OPTION_XVMC,
+#endif
+ OPTION_PREFER_OVERLAY,
+ OPTION_DEBUG_FLUSH_BATCHES,
+ OPTION_DEBUG_FLUSH_CACHES,
+ OPTION_DEBUG_WAIT,
+} I830Opts;
+
+static OptionInfoRec I830Options[] = {
+ {OPTION_DRI, "DRI", OPTV_BOOLEAN, {0}, TRUE},
+ {OPTION_COLOR_KEY, "ColorKey", OPTV_INTEGER, {0}, FALSE},
+ {OPTION_VIDEO_KEY, "VideoKey", OPTV_INTEGER, {0}, FALSE},
+ {OPTION_MODEDEBUG, "ModeDebug", OPTV_BOOLEAN, {0}, FALSE},
+ {OPTION_FALLBACKDEBUG, "FallbackDebug", OPTV_BOOLEAN, {0}, FALSE},
+ {OPTION_LVDS24BITMODE, "LVDS24Bit", OPTV_BOOLEAN, {0}, FALSE},
+ {OPTION_FBC, "FramebufferCompression", OPTV_BOOLEAN, {0}, TRUE},
+ {OPTION_TILING_2D, "Tiling", OPTV_BOOLEAN, {0}, TRUE},
+ {OPTION_TILING_FB, "LinearFramebuffer", OPTV_BOOLEAN, {0}, FALSE},
+ {OPTION_SHADOW, "Shadow", OPTV_BOOLEAN, {0}, FALSE},
+ {OPTION_SWAPBUFFERS_WAIT, "SwapbuffersWait", OPTV_BOOLEAN, {0}, TRUE},
+ {OPTION_LVDSFIXEDMODE, "LVDSFixedMode", OPTV_BOOLEAN, {0}, FALSE},
+ {OPTION_FORCEENABLEPIPEA, "ForceEnablePipeA", OPTV_BOOLEAN, {0}, FALSE},
+#ifdef INTEL_XVMC
+ {OPTION_XVMC, "XvMC", OPTV_BOOLEAN, {0}, TRUE},
+#endif
+ {OPTION_PREFER_OVERLAY, "XvPreferOverlay", OPTV_BOOLEAN, {0}, FALSE},
+ {OPTION_DEBUG_FLUSH_BATCHES, "DebugFlushBatches", OPTV_BOOLEAN, {0}, FALSE},
+ {OPTION_DEBUG_FLUSH_CACHES, "DebugFlushCaches", OPTV_BOOLEAN, {0}, FALSE},
+ {OPTION_DEBUG_WAIT, "DebugWait", OPTV_BOOLEAN, {0}, FALSE},
+ {-1, NULL, OPTV_NONE, {0}, FALSE}
+};
+/* *INDENT-ON* */
+
+static void i830AdjustFrame(int scrnIndex, int x, int y, int flags);
+static Bool I830CloseScreen(int scrnIndex, ScreenPtr screen);
+static Bool I830EnterVT(int scrnIndex, int flags);
+static Bool SaveHWState(ScrnInfoPtr scrn);
+static Bool RestoreHWState(ScrnInfoPtr scrn);
+
+/* temporary */
+extern void xf86SetCursor(ScreenPtr screen, CursorPtr pCurs, int x, int y);
+
+#ifdef I830DEBUG
+void
+I830DPRINTF(const char *filename, int line, const char *function,
+ const char *fmt, ...)
+{
+ va_list ap;
+
+ ErrorF("\n##############################################\n"
+ "*** In function %s, on line %d, in file %s ***\n",
+ function, line, filename);
+ va_start(ap, fmt);
+ VErrorF(fmt, ap);
+ va_end(ap);
+ ErrorF("##############################################\n\n");
+}
+#endif /* #ifdef I830DEBUG */
+
+/* Export I830 options to i830 driver where necessary */
+const OptionInfoRec *intel_uxa_available_options(int chipid, int busid)
+{
+ return I830Options;
+}
+
+static Bool I830GetRec(ScrnInfoPtr scrn)
+{
+ intel_screen_private *intel;
+
+ if (scrn->driverPrivate)
+ return TRUE;
+ intel = scrn->driverPrivate = xnfcalloc(sizeof(intel_screen_private), 1);
+ return TRUE;
+}
+
+static void I830FreeRec(ScrnInfoPtr scrn)
+{
+ if (!scrn)
+ return;
+ if (!scrn->driverPrivate)
+ return;
+
+ free(scrn->driverPrivate);
+ scrn->driverPrivate = NULL;
+}
+
+static int
+I830DetectMemory(ScrnInfoPtr scrn)
+{
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+ uint16_t gmch_ctrl;
+ int memsize = 0, gtt_size;
+ int range;
+ struct pci_device *bridge = intel_host_bridge ();
+ pci_device_cfg_read_u16(bridge, & gmch_ctrl, I830_GMCH_CTRL);
+
+ if (IS_I965G(intel)) {
+ /* The 965 may have a GTT that is actually larger than is necessary
+ * to cover the aperture, so check the hardware's reporting of the
+ * GTT size.
+ */
+ switch (INREG(PGETBL_CTL) & PGETBL_SIZE_MASK) {
+ case PGETBL_SIZE_512KB:
+ gtt_size = 512;
+ break;
+ case PGETBL_SIZE_256KB:
+ gtt_size = 256;
+ break;
+ case PGETBL_SIZE_128KB:
+ gtt_size = 128;
+ break;
+ case PGETBL_SIZE_1MB:
+ gtt_size = 1024;
+ break;
+ case PGETBL_SIZE_2MB:
+ gtt_size = 2048;
+ break;
+ case PGETBL_SIZE_1_5MB:
+ gtt_size = 1024 + 512;
+ break;
+ default:
+ FatalError("Unknown GTT size value: %08x\n", (int)INREG(PGETBL_CTL));
+ }
+ } else if (IS_G33CLASS(intel)) {
+ /* G33's GTT size is detect in GMCH_CTRL */
+ switch (gmch_ctrl & G33_PGETBL_SIZE_MASK) {
+ case G33_PGETBL_SIZE_1M:
+ gtt_size = 1024;
+ break;
+ case G33_PGETBL_SIZE_2M:
+ gtt_size = 2048;
+ break;
+ default:
+ FatalError("Unknown GTT size value: %08x\n",
+ (int)(gmch_ctrl & G33_PGETBL_SIZE_MASK));
+ }
+ } else {
+ /* Older chipsets only had GTT appropriately sized for the aperture. */
+ gtt_size = intel->FbMapSize / (1024*1024);
+ }
+
+ xf86DrvMsg(scrn->scrnIndex, X_INFO, "detected %d kB GTT.\n", gtt_size);
+
+ /* The stolen memory has the GTT at the top, and the 4KB popup below that.
+ * Everything else can be freely used by the graphics driver.
+ */
+ range = gtt_size + 4;
+
+ /* new 4 series hardware has seperate GTT stolen with GFX stolen */
+ if (IS_G4X(intel) || IS_IGD(intel) || IS_IGDNG(intel))
+ range = 4;
+
+ if (IS_I85X(intel) || IS_I865G(intel) || IS_I9XX(intel)) {
+ switch (gmch_ctrl & I855_GMCH_GMS_MASK) {
+ case I855_GMCH_GMS_STOLEN_1M:
+ memsize = MB(1) - KB(range);
+ break;
+ case I855_GMCH_GMS_STOLEN_4M:
+ memsize = MB(4) - KB(range);
+ break;
+ case I855_GMCH_GMS_STOLEN_8M:
+ memsize = MB(8) - KB(range);
+ break;
+ case I855_GMCH_GMS_STOLEN_16M:
+ memsize = MB(16) - KB(range);
+ break;
+ case I855_GMCH_GMS_STOLEN_32M:
+ memsize = MB(32) - KB(range);
+ break;
+ case I915G_GMCH_GMS_STOLEN_48M:
+ if (IS_I9XX(intel))
+ memsize = MB(48) - KB(range);
+ break;
+ case I915G_GMCH_GMS_STOLEN_64M:
+ if (IS_I9XX(intel))
+ memsize = MB(64) - KB(range);
+ break;
+ case G33_GMCH_GMS_STOLEN_128M:
+ if (IS_I9XX(intel))
+ memsize = MB(128) - KB(range);
+ break;
+ case G33_GMCH_GMS_STOLEN_256M:
+ if (IS_I9XX(intel))
+ memsize = MB(256) - KB(range);
+ break;
+ case INTEL_GMCH_GMS_STOLEN_96M:
+ if (IS_I9XX(intel))
+ memsize = MB(96) - KB(range);
+ break;
+ case INTEL_GMCH_GMS_STOLEN_160M:
+ if (IS_I9XX(intel))
+ memsize = MB(160) - KB(range);
+ break;
+ case INTEL_GMCH_GMS_STOLEN_224M:
+ if (IS_I9XX(intel))
+ memsize = MB(224) - KB(range);
+ break;
+ case INTEL_GMCH_GMS_STOLEN_352M:
+ if (IS_I9XX(intel))
+ memsize = MB(352) - KB(range);
+ break;
+ }
+ } else {
+ switch (gmch_ctrl & I830_GMCH_GMS_MASK) {
+ case I830_GMCH_GMS_STOLEN_512:
+ memsize = KB(512) - KB(range);
+ break;
+ case I830_GMCH_GMS_STOLEN_1024:
+ memsize = MB(1) - KB(range);
+ break;
+ case I830_GMCH_GMS_STOLEN_8192:
+ memsize = MB(8) - KB(range);
+ break;
+ case I830_GMCH_GMS_LOCAL:
+ memsize = 0;
+ xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+ "Local memory found, but won't be used.\n");
+ break;
+ }
+ }
+
+#if 0
+ /* And 64KB page aligned */
+ memsize &= ~0xFFFF;
+#endif
+
+ if (memsize > 0) {
+ xf86DrvMsg(scrn->scrnIndex, X_INFO,
+ "detected %d kB stolen memory.\n", memsize / 1024);
+ } else {
+ xf86DrvMsg(scrn->scrnIndex, X_INFO, "no video memory detected.\n");
+ }
+
+ return memsize;
+}
+
+static Bool
+I830MapMMIO(ScrnInfoPtr scrn)
+{
+ int err;
+ struct pci_device *device;
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+
+ device = intel->PciInfo;
+ err = pci_device_map_range (device,
+ intel->MMIOAddr,
+ intel->MMIOSize,
+ PCI_DEV_MAP_FLAG_WRITABLE,
+ (void **) &intel->MMIOBase);
+ if (err)
+ {
+ xf86DrvMsg (scrn->scrnIndex, X_ERROR,
+ "Unable to map mmio range. %s (%d)\n",
+ strerror (err), err);
+ return FALSE;
+ }
+
+ /* Set up the GTT mapping for the various places it has been moved over
+ * time.
+ */
+ if (IS_I9XX(intel)) {
+ uint32_t gttaddr;
+
+ if (IS_I965G(intel))
+ {
+ if (IS_G4X(intel) || IS_IGDNG(intel)) {
+ gttaddr = intel->MMIOAddr + MB(2);
+ intel->GTTMapSize = MB(2);
+ } else {
+ gttaddr = intel->MMIOAddr + KB(512);
+ intel->GTTMapSize = KB(512);
+ }
+ }
+ else
+ {
+ gttaddr = I810_MEMBASE(intel->PciInfo, 3) & 0xFFFFFF00;
+ intel->GTTMapSize = intel->FbMapSize / 1024;
+ }
+ err = pci_device_map_range (device,
+ gttaddr, intel->GTTMapSize,
+ PCI_DEV_MAP_FLAG_WRITABLE,
+ (void **) &intel->GTTBase);
+ if (err)
+ {
+ xf86DrvMsg (scrn->scrnIndex, X_ERROR,
+ "Unable to map GTT range. %s (%d)\n",
+ strerror (err), err);
+ return FALSE;
+ }
+ } else {
+ /* The GTT aperture on i830 is write-only. We could probably map the
+ * actual physical pages that back it, but leave it alone for now.
+ */
+ intel->GTTBase = NULL;
+ intel->GTTMapSize = 0;
+ }
+
+ return TRUE;
+}
+
+static Bool
+I830MapMem(ScrnInfoPtr scrn)
+{
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+ long i;
+ struct pci_device *const device = intel->PciInfo;
+ int err;
+
+ for (i = 2; i < intel->FbMapSize; i <<= 1) ;
+ intel->FbMapSize = i;
+
+ err = pci_device_map_range (device, intel->LinearAddr, intel->FbMapSize,
+ PCI_DEV_MAP_FLAG_WRITABLE | PCI_DEV_MAP_FLAG_WRITE_COMBINE,
+ (void **) &intel->FbBase);
+ if (err)
+ return FALSE;
+
+ return TRUE;
+}
+
+static void
+I830UnmapMMIO(ScrnInfoPtr scrn)
+{
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+
+ pci_device_unmap_range (intel->PciInfo, intel->MMIOBase, intel->MMIOSize);
+ intel->MMIOBase = NULL;
+
+ if (IS_I9XX(intel)) {
+ pci_device_unmap_range (intel->PciInfo, intel->GTTBase, intel->GTTMapSize);
+ intel->GTTBase = NULL;
+ }
+}
+
+static Bool
+I830UnmapMem(ScrnInfoPtr scrn)
+{
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+
+ pci_device_unmap_range (intel->PciInfo, intel->FbBase, intel->FbMapSize);
+ intel->FbBase = NULL;
+ I830UnmapMMIO(scrn);
+ return TRUE;
+}
+
+static void
+I830LoadPalette(ScrnInfoPtr scrn, int numColors, int *indices,
+ LOCO * colors, VisualPtr pVisual)
+{
+ xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
+ int i, j, index;
+ int p;
+ uint16_t lut_r[256], lut_g[256], lut_b[256];
+
+ DPRINTF(PFX, "I830LoadPalette: numColors: %d\n", numColors);
+
+ for (p = 0; p < xf86_config->num_crtc; p++) {
+ xf86CrtcPtr crtc = xf86_config->crtc[p];
+ I830CrtcPrivatePtr intel_crtc = crtc->driver_private;
+
+ /* Initialize to the old lookup table values. */
+ for (i = 0; i < 256; i++) {
+ lut_r[i] = intel_crtc->lut_r[i] << 8;
+ lut_g[i] = intel_crtc->lut_g[i] << 8;
+ lut_b[i] = intel_crtc->lut_b[i] << 8;
+ }
+
+ switch (scrn->depth) {
+ case 15:
+ for (i = 0; i < numColors; i++) {
+ index = indices[i];
+ for (j = 0; j < 8; j++) {
+ lut_r[index * 8 + j] =
+ colors[index].red << 8;
+ lut_g[index * 8 + j] =
+ colors[index].green << 8;
+ lut_b[index * 8 + j] =
+ colors[index].blue << 8;
+ }
+ }
+ break;
+ case 16:
+ for (i = 0; i < numColors; i++) {
+ index = indices[i];
+
+ if (index <= 31) {
+ for (j = 0; j < 8; j++) {
+ lut_r[index * 8 + j] =
+ colors[index].red << 8;
+ lut_b[index * 8 + j] =
+ colors[index].blue << 8;
+ }
+ }
+
+ for (j = 0; j < 4; j++) {
+ lut_g[index * 4 + j] =
+ colors[index].green << 8;
+ }
+ }
+ break;
+ default:
+ for (i = 0; i < numColors; i++) {
+ index = indices[i];
+ lut_r[index] = colors[index].red << 8;
+ lut_g[index] = colors[index].green << 8;
+ lut_b[index] = colors[index].blue << 8;
+ }
+ break;
+ }
+
+ /* Make the change through RandR */
+#ifdef RANDR_12_INTERFACE
+ RRCrtcGammaSet(crtc->randr_crtc, lut_r, lut_g, lut_b);
+#else
+ crtc->funcs->gamma_set(crtc, lut_r, lut_g, lut_b, 256);
+#endif
+ }
+}
+
+/**
+ * Adjust the screen pixmap for the current location of the front buffer.
+ * This is done at EnterVT when buffers are bound as long as the resources
+ * have already been created, but the first EnterVT happens before
+ * CreateScreenResources.
+ */
+static Bool i830CreateScreenResources(ScreenPtr screen)
+{
+ ScrnInfoPtr scrn = xf86Screens[screen->myNum];
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+
+ screen->CreateScreenResources = intel->CreateScreenResources;
+ if (!(*screen->CreateScreenResources) (screen))
+ return FALSE;
+
+ return intel_uxa_create_screen_resources(screen);
+}
+
+static int i830_output_clones (ScrnInfoPtr scrn, int type_mask)
+{
+ xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR (scrn);
+ int o;
+ int index_mask = 0;
+
+ for (o = 0; o < config->num_output; o++) {
+ xf86OutputPtr output = config->output[o];
+ I830OutputPrivatePtr intel_output = output->driver_private;
+ if (type_mask & (1 << intel_output->type))
+ index_mask |= (1 << o);
+ }
+ return index_mask;
+}
+
+/**
+ * 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 scrn)
+{
+ xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR (scrn);
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+ int o, c;
+ Bool lvds_detected = FALSE;
+
+ /* everyone has at least a single analog output */
+ i830_crt_init(scrn);
+
+ /* Set up integrated LVDS */
+ if (IS_MOBILE(intel) && !IS_I830(intel))
+ i830_lvds_init(scrn);
+
+ if (IS_IGDNG(intel)) {
+ int found;
+
+ if (INREG(HDMIB) & PORT_DETECTED) {
+ /* check SDVOB */
+ /* found = intel_sdvo_init(dev, HDMIB); */
+ found = 0;
+ if (!found)
+ i830_hdmi_init(scrn, HDMIB);
+ }
+
+ if (INREG(HDMIC) & PORT_DETECTED)
+ i830_hdmi_init(scrn, HDMIC);
+
+ if (INREG(HDMID) & PORT_DETECTED)
+ i830_hdmi_init(scrn, HDMID);
+
+ /* Disable DP by force */
+ OUTREG(PCH_DP_B, INREG(PCH_DP_B) & ~PORT_ENABLE);
+ OUTREG(PCH_DP_C, INREG(PCH_DP_C) & ~PORT_ENABLE);
+ OUTREG(PCH_DP_D, INREG(PCH_DP_D) & ~PORT_ENABLE);
+
+ } else if (IS_I9XX(intel)) {
+ Bool found = FALSE;
+ if ((INREG(SDVOB) & SDVO_DETECTED)) {
+ found = i830_sdvo_init(scrn, SDVOB);
+
+ if (!found && SUPPORTS_INTEGRATED_HDMI(intel))
+ i830_hdmi_init(scrn, SDVOB);
+ }
+
+ if ((INREG(SDVOB) & SDVO_DETECTED))
+ found = i830_sdvo_init(scrn, SDVOC);
+
+ if ((INREG(SDVOC) & SDVO_DETECTED) &&
+ !found && SUPPORTS_INTEGRATED_HDMI(intel))
+ i830_hdmi_init(scrn, SDVOC);
+
+ } else {
+ i830_dvo_init(scrn);
+ }
+ if (IS_I9XX(intel) && IS_MOBILE(intel) && !IS_IGDNG(intel))
+ i830_tv_init(scrn);
+
+ for (o = 0; o < config->num_output; o++) {
+ xf86OutputPtr output = config->output[o];
+ I830OutputPrivatePtr intel_output = output->driver_private;
+ int crtc_mask;
+
+ if (intel_output->type == I830_OUTPUT_LVDS)
+ lvds_detected = TRUE;
+
+ crtc_mask = 0;
+ for (c = 0; c < config->num_crtc; c++) {
+ xf86CrtcPtr crtc = config->crtc[c];
+ I830CrtcPrivatePtr intel_crtc = crtc->driver_private;
+
+ if (intel_output->pipe_mask & (1 << intel_crtc->pipe))
+ crtc_mask |= (1 << c);
+ }
+ output->possible_crtcs = crtc_mask;
+ output->possible_clones =
+ i830_output_clones(scrn, intel_output->clone_mask);
+ }
+}
+
+static void i830_init_clock_gating(ScrnInfoPtr scrn)
+{
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+
+ /* Disable clock gating reported to work incorrectly according to the specs.
+ */
+ if (IS_G4X(intel)) {
+ uint32_t dspclk_gate;
+ OUTREG(RENCLK_GATE_D1, 0);
+ OUTREG(RENCLK_GATE_D2, VF_UNIT_CLOCK_GATE_DISABLE |
+ GS_UNIT_CLOCK_GATE_DISABLE | CL_UNIT_CLOCK_GATE_DISABLE);
+ OUTREG(RAMCLK_GATE_D, 0);
+ dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE |
+ OVRUNIT_CLOCK_GATE_DISABLE | OVCUNIT_CLOCK_GATE_DISABLE;
+ if (IS_GM45(intel))
+ dspclk_gate |= DSSUNIT_CLOCK_GATE_DISABLE;
+ OUTREG(DSPCLK_GATE_D, dspclk_gate);
+ } else if (IS_I965GM(intel)) {
+ OUTREG(RENCLK_GATE_D1, I965_RCC_CLOCK_GATE_DISABLE);
+ OUTREG(RENCLK_GATE_D2, 0);
+ OUTREG(DSPCLK_GATE_D, 0);
+ OUTREG(RAMCLK_GATE_D, 0);
+ OUTREG16(DEUC, 0);
+ } else if (IS_I965G(intel)) {
+ OUTREG(RENCLK_GATE_D1, I965_RCZ_CLOCK_GATE_DISABLE |
+ I965_RCC_CLOCK_GATE_DISABLE | I965_RCPB_CLOCK_GATE_DISABLE |
+ I965_ISC_CLOCK_GATE_DISABLE | I965_FBC_CLOCK_GATE_DISABLE);
+ OUTREG(RENCLK_GATE_D2, 0);
+ } else if (IS_I855(intel) || IS_I865G(intel)) {
+ OUTREG(RENCLK_GATE_D1, SV_CLOCK_GATE_DISABLE);
+ } else if (IS_I830(intel)) {
+ OUTREG(DSPCLK_GATE_D, OVRUNIT_CLOCK_GATE_DISABLE);
+ }
+}
+
+static void i830_init_bios_control(ScrnInfoPtr scrn)
+{
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+
+ /* Set "extended desktop" */
+ OUTREG(SWF0, INREG(SWF0) | (1 << 21));
+
+ /* Set "driver loaded", "OS unknown", "APM 1.2" */
+ OUTREG(SWF4, (INREG(SWF4) & ~((3 << 19) | (7 << 16))) |
+ (1 << 23) | (2 << 16));
+}
+
+static int
+I830LVDSPresent(ScrnInfoPtr scrn)
+{
+ xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR (scrn);
+ int o, lvds_detected = FALSE;
+
+ for (o = 0; o < config->num_output; o++) {
+ xf86OutputPtr output = config->output[o];
+ I830OutputPrivatePtr intel_output = output->driver_private;
+
+ if (intel_output->type == I830_OUTPUT_LVDS)
+ lvds_detected = TRUE;
+ }
+
+ return lvds_detected;
+}
+
+/**
+ * Setup the CRTCs
+ */
+
+static void
+I830PreInitDDC(ScrnInfoPtr scrn)
+{
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+
+ if (!xf86LoadSubModule(scrn, "ddc")) {
+ intel->ddc2 = FALSE;
+ } else {
+ intel->ddc2 = TRUE;
+ }
+
+ /* DDC can use I2C bus */
+ /* Load I2C if we have the code to use it */
+ if (intel->ddc2) {
+ if (xf86LoadSubModule(scrn, "i2c")) {
+ intel->ddc2 = TRUE;
+ } else {
+ intel->ddc2 = FALSE;
+ }
+ }
+}
+
+static void PreInitCleanup(ScrnInfoPtr scrn)
+{
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+
+ if (intel->MMIOBase)
+ I830UnmapMMIO(scrn);
+ I830FreeRec(scrn);
+}
+
+static Bool i830_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height)
+{
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+ int old_width, old_height, old_pitch;
+ drm_intel_bo *old_front;
+ unsigned long pitch;
+ uint32_t tiling;
+
+ if (scrn->virtualX == width && scrn->virtualY == height)
+ return TRUE;
+
+ old_width = scrn->virtualX;
+ old_height = scrn->virtualY;
+ old_pitch = scrn->displayWidth;
+ old_front = intel->front_buffer;
+
+ intel->front_buffer = intel_allocate_framebuffer(scrn,
+ width, height,
+ intel->cpp,
+ &pitch,
+ &tiling);
+ if (!intel->front_buffer)
+ goto fail;
+
+ intel->front_pitch = pitch;
+ intel->front_tiling = tiling;
+
+ scrn->virtualX = width;
+ scrn->virtualY = height;
+
+ intel_sync(scrn);
+ i830WaitForVblank(scrn);
+
+ xf86DrvMsg(scrn->scrnIndex, X_INFO,
+ "New front buffer at 0x%lx\n",
+ intel->front_buffer->offset);
+ i830_set_new_crtc_bo(scrn);
+ intel_sync(scrn);
+ i830WaitForVblank(scrn);
+
+ intel_uxa_create_screen_resources(scrn->pScreen);
+
+ if (old_front) {
+ /* if we own the vt, don't forget to unpin */
+ if (scrn->vtSema)
+ (void)dri_bo_unpin(old_front);
+ drm_intel_bo_unreference(old_front);
+ }
+
+ return TRUE;
+
+fail:
+ intel->front_buffer = old_front;
+ scrn->virtualX = old_width;
+ scrn->virtualY = old_height;
+ scrn->displayWidth = old_pitch;
+
+ return FALSE;
+}
+
+static const xf86CrtcConfigFuncsRec i830_xf86crtc_config_funcs = {
+ i830_xf86crtc_resize
+};
+
+#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 scrn, int mode)
+{
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+ uint8_t gr18;
+
+ /* Don't mess with kernel settings... */
+ if (intel->use_drm_mode)
+ return;
+
+ gr18 = intel->readControl(intel, GRX, 0x18);
+ if (mode == HOTKEY_BIOS_SWITCH)
+ gr18 &= ~HOTKEY_VBIOS_SWITCH_BLOCK;
+ else
+ gr18 |= HOTKEY_VBIOS_SWITCH_BLOCK;
+ intel->writeControl(intel, GRX, 0x18, gr18);
+}
+
+/*
+ * DRM mode setting Linux only at this point... later on we could
+ * add a wrapper here.
+ */
+static Bool intel_kernel_mode_enabled(ScrnInfoPtr scrn)
+{
+ struct pci_device *dev;
+ char id[20];
+ int ret;
+
+ dev = xf86GetPciInfoForEntity(xf86GetEntityInfo(scrn->entityList[0])->index);
+ snprintf(id, sizeof(id),
+ "pci:%04x:%02x:%02x.%d",
+ dev->domain, dev->bus, dev->dev, dev->func);
+
+ ret = drmCheckModesettingSupported(id);
+ if (ret) {
+ if (xf86LoadKernelModule("i915"))
+ ret = drmCheckModesettingSupported(id);
+ }
+ /* Be nice to the user and load fbcon too */
+ if (!ret)
+ (void)xf86LoadKernelModule("fbcon");
+
+ return ret == 0;
+}
+
+static Bool intel_check_chipset_option(ScrnInfoPtr scrn)
+{
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+ MessageType from = X_PROBED;
+ int fb_bar, mmio_bar;
+
+ if (!intel->use_drm_mode)
+ I830SetPIOAccess(intel);
+
+ intel_detect_chipset(scrn,
+ intel->PciInfo,
+ &intel->chipset);
+
+ /* Set the Chipset and ChipRev, allowing config file entries to override. */
+ if (intel->pEnt->device->chipset && *intel->pEnt->device->chipset) {
+ scrn->chipset = intel->pEnt->device->chipset;
+ from = X_CONFIG;
+ } else if (intel->pEnt->device->chipID >= 0) {
+ scrn->chipset = (char *)xf86TokenToString(intel_chipsets,
+ intel->pEnt->device->chipID);
+ from = X_CONFIG;
+ xf86DrvMsg(scrn->scrnIndex, X_CONFIG,
+ "ChipID override: 0x%04X\n",
+ intel->pEnt->device->chipID);
+ DEVICE_ID(intel->PciInfo) = intel->pEnt->device->chipID;
+ } else {
+ from = X_PROBED;
+ scrn->chipset = (char *)xf86TokenToString(intel_chipsets,
+ DEVICE_ID(intel->PciInfo));
+ }
+
+ if (intel->pEnt->device->chipRev >= 0) {
+ xf86DrvMsg(scrn->scrnIndex, X_CONFIG, "ChipRev override: %d\n",
+ intel->pEnt->device->chipRev);
+ }
+
+ xf86DrvMsg(scrn->scrnIndex, from, "Chipset: \"%s\"\n",
+ (scrn->chipset != NULL) ? scrn->chipset : "Unknown i8xx");
+ /* Check if the HW cursor needs physical address. */
+ if (IS_MOBILE(intel) || IS_I9XX(intel))
+ intel->CursorNeedsPhysical = TRUE;
+ else
+ intel->CursorNeedsPhysical = FALSE;
+
+ if (IS_I965G(intel) || IS_G33CLASS(intel))
+ intel->CursorNeedsPhysical = FALSE;
+
+ /* Skip the rest if the kernel is taking care of things */
+ if (intel->use_drm_mode)
+ return TRUE;
+
+ /* Now that we know the chipset, figure out the resource base addrs */
+ if (IS_I9XX(intel)) {
+ fb_bar = 2;
+ mmio_bar = 0;
+ } else {
+ fb_bar = 0;
+ mmio_bar = 1;
+ }
+
+ if (intel->pEnt->device->MemBase != 0) {
+ intel->LinearAddr = intel->pEnt->device->MemBase;
+ from = X_CONFIG;
+ } else {
+ intel->LinearAddr = I810_MEMBASE (intel->PciInfo, fb_bar);
+ if (intel->LinearAddr == 0) {
+ xf86DrvMsg(scrn->scrnIndex, X_ERROR,
+ "No valid FB address in PCI config space\n");
+ PreInitCleanup(scrn);
+ return FALSE;
+ }
+ }
+
+ xf86DrvMsg(scrn->scrnIndex, from, "Linear framebuffer at 0x%lX\n",
+ (unsigned long)intel->LinearAddr);
+
+ if (intel->pEnt->device->IOBase != 0) {
+ intel->MMIOAddr = intel->pEnt->device->IOBase;
+ from = X_CONFIG;
+ intel->MMIOSize = I810_REG_SIZE;
+ } else {
+ intel->MMIOAddr = I810_MEMBASE (intel->PciInfo, mmio_bar);
+ if (intel->MMIOAddr == 0) {
+ xf86DrvMsg(scrn->scrnIndex, X_ERROR,
+ "No valid MMIO address in PCI config space\n");
+ PreInitCleanup(scrn);
+ return FALSE;
+ }
+ intel->MMIOSize = intel->PciInfo->regions[mmio_bar].size;
+ }
+
+ xf86DrvMsg(scrn->scrnIndex, from,
+ "IO registers at addr 0x%lX size %u\n",
+ (unsigned long)intel->MMIOAddr, intel->MMIOSize);
+
+ /* Now figure out mapsize on 8xx chips */
+ if (IS_I830(intel) || IS_845G(intel)) {
+ uint16_t gmch_ctrl;
+ struct pci_device *bridge;
+
+ bridge = intel_host_bridge ();
+ pci_device_cfg_read_u16 (bridge, &gmch_ctrl, I830_GMCH_CTRL);
+ if ((gmch_ctrl & I830_GMCH_MEM_MASK) == I830_GMCH_MEM_128M) {
+ intel->FbMapSize = 0x8000000;
+ } else {
+ /* 64MB - has this been tested ?? */
+ intel->FbMapSize = 0x4000000;
+ }
+ } else {
+ if (IS_I9XX(intel)) {
+ intel->FbMapSize = intel->PciInfo->regions[fb_bar].size;
+ } else {
+ /* 128MB aperture for later i8xx series. */
+ intel->FbMapSize = 0x8000000;
+ }
+ }
+
+ return TRUE;
+}
+
+static Bool I830LoadSyms(ScrnInfoPtr scrn)
+{
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+
+ if (intel->use_drm_mode)
+ return TRUE;
+
+ /* The vgahw module should be loaded here when needed */
+ if (!xf86LoadSubModule(scrn, "vgahw"))
+ return FALSE;
+
+ if (!xf86LoadSubModule(scrn, "ramdac"))
+ return FALSE;
+
+ return TRUE;
+}
+
+static Bool I830GetEarlyOptions(ScrnInfoPtr scrn)
+{
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+
+ /* Process the options */
+ xf86CollectOptions(scrn, NULL);
+ if (!(intel->Options = malloc(sizeof(I830Options))))
+ return FALSE;
+ memcpy(intel->Options, I830Options, sizeof(I830Options));
+ xf86ProcessOptions(scrn->scrnIndex, scrn->options, intel->Options);
+
+ intel->fallback_debug = xf86ReturnOptValBool(intel->Options,
+ OPTION_FALLBACKDEBUG,
+ FALSE);
+
+ if (xf86ReturnOptValBool(intel->Options, OPTION_MODEDEBUG, FALSE)) {
+ intel->debug_modes = TRUE;
+ } else {
+ intel->debug_modes = FALSE;
+ }
+
+ if (xf86ReturnOptValBool(intel->Options, OPTION_LVDS24BITMODE, FALSE)) {
+ intel->lvds_24_bit_mode = TRUE;
+ } else {
+ intel->lvds_24_bit_mode = FALSE;
+ }
+
+ if (xf86ReturnOptValBool(intel->Options, OPTION_LVDSFIXEDMODE, TRUE)) {
+ intel->skip_panel_detect = FALSE;
+ } else {
+ intel->skip_panel_detect = TRUE;
+ }
+
+ if (xf86ReturnOptValBool(intel->Options,
+ OPTION_FORCEENABLEPIPEA, FALSE))
+ intel->quirk_flag |= QUIRK_PIPEA_FORCE;
+ intel->debug_flush = 0;
+
+ if (xf86ReturnOptValBool(intel->Options,
+ OPTION_DEBUG_FLUSH_BATCHES,
+ FALSE))
+ intel->debug_flush |= DEBUG_FLUSH_BATCHES;
+
+ if (xf86ReturnOptValBool(intel->Options,
+ OPTION_DEBUG_FLUSH_CACHES,
+ FALSE))
+ intel->debug_flush |= DEBUG_FLUSH_CACHES;
+
+ if (xf86ReturnOptValBool(intel->Options,
+ OPTION_DEBUG_WAIT,
+ FALSE))
+ intel->debug_flush |= DEBUG_FLUSH_WAIT;
+
+ return TRUE;
+}
+
+static void
+I830PreInitCrtcConfig(ScrnInfoPtr scrn)
+{
+ xf86CrtcConfigPtr xf86_config;
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+ int max_width, max_height;
+
+ /* check quirks */
+ i830_fixup_devices(scrn);
+
+ /* Allocate an xf86CrtcConfig */
+ xf86CrtcConfigInit (scrn, &i830_xf86crtc_config_funcs);
+ xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
+
+ /* See i830_exa.c comments for why we limit the framebuffer size like
+ * this.
+ */
+ if (IS_I965G(intel)) {
+ max_height = max_width = min(16384 / intel->cpp, 8192);
+ } else {
+ max_width = 2048;
+ max_height = 2048;
+ }
+ xf86CrtcSetSizeRange (scrn, 320, 200, max_width, max_height);
+}
+
+static void intel_check_dri_option(ScrnInfoPtr scrn)
+{
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+ intel->directRenderingType = DRI_NONE;
+ if (!xf86ReturnOptValBool(intel->Options, OPTION_DRI, TRUE))
+ intel->directRenderingType = DRI_DISABLED;
+
+ if (scrn->depth != 16 && scrn->depth != 24 && scrn->depth != 30) {
+ xf86DrvMsg(scrn->scrnIndex, X_CONFIG,
+ "DRI is disabled because it "
+ "runs only at depths 16, 24, and 30.\n");
+ intel->directRenderingType = DRI_DISABLED;
+ }
+}
+
+#ifdef notyet
+static void
+drm_vblank_handler(int fd, unsigned int frame, unsigned int tv_sec,
+ unsigned int tv_usec, void *event_data)
+{
+ I830DRI2FrameEventHandler(frame, tv_sec, tv_usec, event_data);
+}
+
+static void
+drm_wakeup_handler(pointer data, int err, pointer p)
+{
+ intel_screen_private *intel = data;
+ fd_set *read_mask = p;
+
+ if (err >= 0 && FD_ISSET(intel->drmSubFD, read_mask))
+ drmHandleEvent(intel->drmSubFD, &intel->event_context);
+}
+#endif
+
+static Bool i830_user_modesetting_init(ScrnInfoPtr scrn)
+{
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+ int i, num_pipe;
+
+ I830MapMMIO(scrn);
+
+ if (DEVICE_ID(intel->PciInfo) == PCI_CHIP_E7221_G)
+ num_pipe = 1;
+ else
+ if (IS_MOBILE(intel) || IS_I9XX(intel))
+ num_pipe = 2;
+ else
+ num_pipe = 1;
+ xf86DrvMsg(scrn->scrnIndex, X_INFO, "%d display pipe%s available.\n",
+ num_pipe, num_pipe > 1 ? "s" : "");
+
+ I830PreInitDDC(scrn);
+ for (i = 0; i < num_pipe; i++) {
+ i830_crtc_init(scrn, i);
+ }
+ I830SetupOutputs(scrn);
+
+ SaveHWState(scrn);
+
+ if (!xf86InitialConfiguration (scrn, TRUE)) {
+ xf86DrvMsg(scrn->scrnIndex, X_ERROR, "No valid modes.\n");
+ RestoreHWState(scrn);
+ PreInitCleanup(scrn);
+ return FALSE;
+ }
+ RestoreHWState(scrn);
+
+ intel->stolen_size = I830DetectMemory(scrn);
+#ifdef notyet
+ intel->event_context.version = DRM_EVENT_CONTEXT_VERSION;
+ intel->event_context.vblank_handler = drm_vblank_handler;
+#endif
+
+
+ return TRUE;
+}
+
+static Bool intel_open_drm_master(ScrnInfoPtr scrn)
+{
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+ struct pci_device *dev = intel->PciInfo;
+ drmSetVersion sv;
+ struct drm_i915_getparam gp;
+ int err, has_gem;
+ char busid[20];
+
+ snprintf(busid, sizeof(busid), "pci:%04x:%02x:%02x.%d",
+ dev->domain, dev->bus, dev->dev, dev->func);
+
+ intel->drmSubFD = drmOpen("i915", busid);
+ if (intel->drmSubFD == -1) {
+ xf86DrvMsg(scrn->scrnIndex, X_ERROR,
+ "[drm] Failed to open DRM device for %s: %s\n",
+ busid, strerror(errno));
+ return FALSE;
+ }
+
+ /* Check that what we opened was a master or a master-capable FD,
+ * by setting the version of the interface we'll use to talk to it.
+ * (see DRIOpenDRMMaster() in DRI1)
+ */
+ sv.drm_di_major = 1;
+ sv.drm_di_minor = 1;
+ sv.drm_dd_major = -1;
+ sv.drm_dd_minor = -1;
+ err = drmSetInterfaceVersion(intel->drmSubFD, &sv);
+ if (err != 0) {
+ xf86DrvMsg(scrn->scrnIndex, X_ERROR,
+ "[drm] failed to set drm interface version.\n");
+ drmClose(intel->drmSubFD);
+ intel->drmSubFD = -1;
+ return FALSE;
+ }
+
+ has_gem = FALSE;
+ gp.param = I915_PARAM_HAS_GEM;
+ gp.value = &has_gem;
+ (void)drmCommandWriteRead(intel->drmSubFD, DRM_I915_GETPARAM,
+ &gp, sizeof(gp));
+ if (!has_gem) {
+ xf86DrvMsg(scrn->scrnIndex, X_ERROR,
+ "[drm] Failed to detect GEM. Kernel 2.6.28 required.\n");
+ drmClose(intel->drmSubFD);
+ intel->drmSubFD = -1;
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void intel_close_drm_master(ScrnInfoPtr scrn)
+{
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+ if (intel && intel->drmSubFD > 0) {
+ drmClose(intel->drmSubFD);
+ intel->drmSubFD = -1;
+ }
+}
+
+void intel_init_bufmgr(ScrnInfoPtr scrn)
+{
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+ int batch_size;
+
+ if (intel->bufmgr)
+ return;
+
+ batch_size = 4096 * 4;
+
+ /* The 865 has issues with larger-than-page-sized batch buffers. */
+ if (IS_I865G(intel))
+ batch_size = 4096;
+
+ intel->bufmgr = drm_intel_bufmgr_gem_init(intel->drmSubFD, batch_size);
+ drm_intel_bufmgr_gem_enable_reuse(intel->bufmgr);
+ drm_intel_bufmgr_gem_enable_fenced_relocs(intel->bufmgr);
+
+ list_init(&intel->batch_pixmaps);
+ list_init(&intel->flush_pixmaps);
+ list_init(&intel->in_flight);
+}
+
+static Bool I830DrmModeInit(ScrnInfoPtr scrn)
+{
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+
+ if (drmmode_pre_init(scrn, intel->drmSubFD, intel->cpp) == FALSE) {
+ xf86DrvMsg(scrn->scrnIndex, X_ERROR,
+ "Kernel modesetting setup failed\n");
+ PreInitCleanup(scrn);
+ return FALSE;
+ }
+
+ intel_init_bufmgr(scrn);
+
+ return TRUE;
+}
+
+static void I830XvInit(ScrnInfoPtr scrn)
+{
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+ MessageType from = X_PROBED;
+
+ intel->XvPreferOverlay =
+ xf86ReturnOptValBool(intel->Options, OPTION_PREFER_OVERLAY, FALSE);
+
+ if (xf86GetOptValInteger(intel->Options, OPTION_VIDEO_KEY,
+ &(intel->colorKey))) {
+ from = X_CONFIG;
+ } else if (xf86GetOptValInteger(intel->Options, OPTION_COLOR_KEY,
+ &(intel->colorKey))) {
+ from = X_CONFIG;
+ } else {
+ intel->colorKey =
+ (1 << scrn->offset.red) | (1 << scrn->offset.green) |
+ (((scrn->mask.blue >> scrn->offset.blue) - 1) <<
+ scrn->offset.blue);
+ from = X_DEFAULT;
+ }
+ xf86DrvMsg(scrn->scrnIndex, from, "video overlay key set to 0x%x\n",
+ intel->colorKey);
+}
+
+static Bool has_kernel_flush(struct intel_screen_private *intel)
+{
+ drm_i915_getparam_t gp;
+ int value;
+
+ /* The BLT ring was introduced at the same time as the
+ * automatic flush for the busy-ioctl.
+ */
+
+ gp.value = &value;
+ gp.param = I915_PARAM_HAS_BLT;
+ if (drmIoctl(intel->drmSubFD, DRM_IOCTL_I915_GETPARAM, &gp))
+ return FALSE;
+
+ return value;
+}
+
+static Bool can_accelerate_blt(struct intel_screen_private *intel)
+{
+ if (0 && (IS_I830(intel) || IS_845G(intel))) {
+ /* These pair of i8xx chipsets have a crippling erratum
+ * that prevents the use of a PTE entry by the BLT
+ * engine immediately following updating that
+ * entry in the GATT.
+ *
+ * As the BLT is fundamental to our 2D acceleration,
+ * and the workaround is lost in the midst of time,
+ * fallback.
+ *
+ * XXX disabled for release as causes regressions in GL.
+ */
+ return FALSE;
+ }
+
+ if (INTEL_INFO(intel)->gen >= 60) {
+ drm_i915_getparam_t gp;
+ int value;
+
+ /* On Sandybridge we need the BLT in order to do anything since
+ * it so frequently used in the acceleration code paths.
+ */
+ gp.value = &value;
+ gp.param = I915_PARAM_HAS_BLT;
+ if (drmIoctl(intel->drmSubFD, DRM_IOCTL_I915_GETPARAM, &gp))
+ return FALSE;
+ }
+
+ if (INTEL_INFO(intel)->gen == 60) {
+ struct pci_device *const device = intel->PciInfo;
+
+ /* Sandybridge rev07 locks up easily, even with the
+ * BLT ring workaround in place.
+ * Thus use shadowfb by default.
+ */
+ if (device->revision < 8)
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ * This is called before ScreenInit to do any require probing of screen
+ * configuration.
+ *
+ * This code generally covers probing, module loading, option handling
+ * card mapping, and RandR setup.
+ *
+ * Since xf86InitialConfiguration ends up requiring that we set video modes
+ * in order to detect configuration, we end up having to do a lot of driver
+ * setup (talking to the DRM, mapping the device, etc.) in this function.
+ * As a result, we want to set up that server initialization once rather
+ * that doing it per generation.
+ */
+static Bool I830PreInit(ScrnInfoPtr scrn, int flags)
+{
+ vgaHWPtr hwp;
+ intel_screen_private *intel;
+ rgb defaultWeight = { 0, 0, 0 };
+ EntityInfoPtr pEnt;
+ int flags24;
+ Gamma zeros = { 0.0, 0.0, 0.0 };
+ int drm_mode_setting;
+
+ if (scrn->numEntities != 1)
+ return FALSE;
+
+ drm_mode_setting = intel_kernel_mode_enabled(scrn);
+
+ pEnt = xf86GetEntityInfo(scrn->entityList[0]);
+
+ if (flags & PROBE_DETECT)
+ return TRUE;
+
+ /* Allocate driverPrivate */
+ if (!I830GetRec(scrn))
+ return FALSE;
+
+ intel = intel_get_screen_private(scrn);
+ intel->SaveGeneration = -1;
+ intel->pEnt = pEnt;
+ intel->scrn = scrn;
+ intel->use_drm_mode = drm_mode_setting;
+
+ if (!I830LoadSyms(scrn))
+ return FALSE;
+
+ if (!drm_mode_setting) {
+ /* Allocate a vgaHWRec */
+ if (!vgaHWGetHWRec(scrn))
+ return FALSE;
+ hwp = VGAHWPTR(scrn);
+ }
+
+ scrn->displayWidth = 640; /* default it */
+
+ if (intel->pEnt->location.type != BUS_PCI)
+ return FALSE;
+
+ intel->PciInfo = xf86GetPciInfoForEntity(intel->pEnt->index);
+
+ if (!intel_open_drm_master(scrn))
+ xf86DrvMsg(scrn->scrnIndex, X_ERROR,
+ "Failed to become DRM master.\n");
+
+ scrn->monitor = scrn->confScreen->monitor;
+ scrn->progClock = TRUE;
+ scrn->rgbBits = 8;
+
+ flags24 = Support32bppFb | PreferConvert24to32 | SupportConvert24to32;
+
+ if (!xf86SetDepthBpp(scrn, 0, 0, 0, flags24))
+ return FALSE;
+
+ switch (scrn->depth) {
+ case 8:
+ case 15:
+ case 16:
+ case 24:
+ case 30:
+ break;
+ default:
+ xf86DrvMsg(scrn->scrnIndex, X_ERROR,
+ "Given depth (%d) is not supported by I830 driver\n",
+ scrn->depth);
+ return FALSE;
+ }
+ xf86PrintDepthBpp(scrn);
+
+ if (!xf86SetWeight(scrn, defaultWeight, defaultWeight))
+ return FALSE;
+ if (!xf86SetDefaultVisual(scrn, -1))
+ return FALSE;
+
+ if (!intel->use_drm_mode)
+ hwp = VGAHWPTR(scrn);
+
+ intel->cpp = scrn->bitsPerPixel / 8;
+
+ if (!I830GetEarlyOptions(scrn))
+ return FALSE;
+
+ if (!intel_check_chipset_option(scrn))
+ return FALSE;
+
+ intel_check_dri_option(scrn);
+
+ if (intel->use_drm_mode) {
+ if (!I830DrmModeInit(scrn))
+ return FALSE;
+ } else {
+ if (i830_bios_init(scrn))
+ xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+ "VBIOS initialization failed.\n");
+ I830PreInitCrtcConfig(scrn);
+ if (!i830_user_modesetting_init(scrn))
+ return FALSE;
+ }
+
+ I830XvInit(scrn);
+
+ if (!xf86SetGamma(scrn, zeros)) {
+ PreInitCleanup(scrn);
+ return FALSE;
+ }
+
+ if (scrn->modes == NULL) {
+ xf86DrvMsg(scrn->scrnIndex, X_ERROR, "No modes.\n");
+ PreInitCleanup(scrn);
+ return FALSE;
+ }
+ scrn->currentMode = scrn->modes;
+
+ /* Set display resolution */
+ xf86SetDpi(scrn, 0, 0);
+
+ /* Load the required sub modules */
+ if (!xf86LoadSubModule(scrn, "fb")) {
+ PreInitCleanup(scrn);
+ return FALSE;
+ }
+
+ if (!intel->use_drm_mode) {
+ /* console hack, stolen from G80 */
+ if (IS_IGDNG(intel)) {
+ if (xf86LoadSubModule(scrn, "int10")) {
+ intel->int10 = xf86InitInt10(pEnt->index);
+ if (intel->int10) {
+ intel->int10->num = 0x10;
+ intel->int10->ax = 0x4f03;
+ intel->int10->bx =
+ intel->int10->cx =
+ intel->int10->dx = 0;
+ xf86ExecX86int10(intel->int10);
+ intel->int10Mode = intel->int10->bx & 0x3fff;
+ xf86DrvMsg(scrn->scrnIndex, X_PROBED,
+ "Console VGA mode is 0x%x\n", intel->int10Mode);
+ } else {
+ xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+ "Failed int10 setup, VT switch won't work\n");
+ }
+ } else {
+ xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+ "Failed to load int10module, ironlake vt switch broken");
+ }
+ }
+
+ I830UnmapMMIO(scrn);
+
+ /* We won't be using the VGA access after the probe. */
+ I830SetMMIOAccess(intel);
+ }
+
+ /* Load the dri2 module if requested. */
+ if (xf86ReturnOptValBool(intel->Options, OPTION_DRI, FALSE) &&
+ intel->directRenderingType != DRI_DISABLED) {
+ xf86LoadSubModule(scrn, "dri2");
+ }
+
+ return TRUE;
+}
+
+enum pipe {
+ PIPE_A = 0,
+ PIPE_B,
+};
+
+static Bool i830_pipe_enabled(intel_screen_private *intel, enum pipe pipe)
+{
+ uint32_t dpll_reg;
+
+ if (IS_IGDNG(intel)) {
+ dpll_reg = (pipe == PIPE_A) ? PCH_DPLL_A : PCH_DPLL_B;
+ } else {
+ dpll_reg = (pipe == PIPE_A) ? DPLL_A : DPLL_B;
+ }
+
+ return (INREG(dpll_reg) & DPLL_VCO_ENABLE);
+}
+
+static void i830_save_palette(intel_screen_private *intel, enum pipe pipe)
+{
+ uint32_t reg = (pipe == PIPE_A ? PALETTE_A : PALETTE_B);
+ uint32_t *array;
+ int i;
+
+ if (!i830_pipe_enabled(intel, pipe))
+ return;
+
+ if (IS_IGDNG(intel))
+ reg = (pipe == PIPE_A) ? LGC_PALETTE_A : LGC_PALETTE_B;
+
+ if (pipe == PIPE_A)
+ array = intel->savePaletteA;
+ else
+ array = intel->savePaletteB;
+
+ for (i = 0; i < 256; i++)
+ array[i] = INREG(reg + (i << 2));
+}
+
+static void i830_restore_palette(intel_screen_private *intel, enum pipe pipe)
+{
+ uint32_t reg = (pipe == PIPE_A ? PALETTE_A : PALETTE_B);
+ uint32_t *array;
+ int i;
+
+ if (!i830_pipe_enabled(intel, pipe))
+ return;
+
+ if (IS_IGDNG(intel))
+ reg = (pipe == PIPE_A) ? LGC_PALETTE_A : LGC_PALETTE_B;
+
+ if (pipe == PIPE_A)
+ array = intel->savePaletteA;
+ else
+ array = intel->savePaletteB;
+
+ for (i = 0; i < 256; i++)
+ OUTREG(reg + (i << 2), array[i]);
+}
+
+static Bool SaveHWState(ScrnInfoPtr scrn)
+{
+ xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+ vgaHWPtr hwp = VGAHWPTR(scrn);
+ vgaRegPtr vgaReg = &hwp->SavedReg;
+ int i;
+
+ if (IS_IGDNG(intel))
+ return TRUE;
+
+ /* Save video mode information for native mode-setting. */
+ if (!DSPARB_HWCONTROL(intel))
+ intel->saveDSPARB = INREG(DSPARB);
+
+ intel->saveDSPACNTR = INREG(DSPACNTR);
+ intel->savePIPEACONF = INREG(PIPEACONF);
+ intel->savePIPEASRC = INREG(PIPEASRC);
+ intel->saveFPA0 = INREG(FPA0);
+ intel->saveFPA1 = INREG(FPA1);
+ intel->saveDPLL_A = INREG(DPLL_A);
+ if (IS_I965G(intel))
+ intel->saveDPLL_A_MD = INREG(DPLL_A_MD);
+ intel->saveHTOTAL_A = INREG(HTOTAL_A);
+ intel->saveHBLANK_A = INREG(HBLANK_A);
+ intel->saveHSYNC_A = INREG(HSYNC_A);
+ intel->saveVTOTAL_A = INREG(VTOTAL_A);
+ intel->saveVBLANK_A = INREG(VBLANK_A);
+ intel->saveVSYNC_A = INREG(VSYNC_A);
+ intel->saveBCLRPAT_A = INREG(BCLRPAT_A);
+ intel->saveDSPASTRIDE = INREG(DSPASTRIDE);
+ intel->saveDSPASIZE = INREG(DSPASIZE);
+ intel->saveDSPAPOS = INREG(DSPAPOS);
+ intel->saveDSPABASE = INREG(DSPABASE);
+
+ i830_save_palette(intel, PIPE_A);
+
+ if(xf86_config->num_crtc == 2) {
+ intel->savePIPEBCONF = INREG(PIPEBCONF);
+ intel->savePIPEBSRC = INREG(PIPEBSRC);
+ intel->saveDSPBCNTR = INREG(DSPBCNTR);
+ intel->saveFPB0 = INREG(FPB0);
+ intel->saveFPB1 = INREG(FPB1);
+ intel->saveDPLL_B = INREG(DPLL_B);
+ if (IS_I965G(intel))
+ intel->saveDPLL_B_MD = INREG(DPLL_B_MD);
+ intel->saveHTOTAL_B = INREG(HTOTAL_B);
+ intel->saveHBLANK_B = INREG(HBLANK_B);
+ intel->saveHSYNC_B = INREG(HSYNC_B);
+ intel->saveVTOTAL_B = INREG(VTOTAL_B);
+ intel->saveVBLANK_B = INREG(VBLANK_B);
+ intel->saveVSYNC_B = INREG(VSYNC_B);
+ intel->saveBCLRPAT_B = INREG(BCLRPAT_B);
+ intel->saveDSPBSTRIDE = INREG(DSPBSTRIDE);
+ intel->saveDSPBSIZE = INREG(DSPBSIZE);
+ intel->saveDSPBPOS = INREG(DSPBPOS);
+ intel->saveDSPBBASE = INREG(DSPBBASE);
+
+ i830_save_palette(intel, PIPE_B);
+ }
+
+ if (IS_I965G(intel)) {
+ intel->saveDSPASURF = INREG(DSPASURF);
+ intel->saveDSPBSURF = INREG(DSPBSURF);
+ intel->saveDSPATILEOFF = INREG(DSPATILEOFF);
+ intel->saveDSPBTILEOFF = INREG(DSPBTILEOFF);
+ }
+
+ intel->saveVCLK_DIVISOR_VGA0 = INREG(VCLK_DIVISOR_VGA0);
+ intel->saveVCLK_DIVISOR_VGA1 = INREG(VCLK_DIVISOR_VGA1);
+ intel->saveVCLK_POST_DIV = INREG(VCLK_POST_DIV);
+ intel->saveVGACNTRL = INREG(VGACNTRL);
+
+ intel->saveCURSOR_A_CONTROL = INREG(CURSOR_A_CONTROL);
+ intel->saveCURSOR_A_POSITION = INREG(CURSOR_A_POSITION);
+ intel->saveCURSOR_A_BASE = INREG(CURSOR_A_BASE);
+ intel->saveCURSOR_B_CONTROL = INREG(CURSOR_B_CONTROL);
+ intel->saveCURSOR_B_POSITION = INREG(CURSOR_B_POSITION);
+ intel->saveCURSOR_B_BASE = INREG(CURSOR_B_BASE);
+
+ for(i = 0; i < 7; i++) {
+ intel->saveSWF[i] = INREG(SWF0 + (i << 2));
+ intel->saveSWF[i+7] = INREG(SWF00 + (i << 2));
+ }
+ intel->saveSWF[14] = INREG(SWF30);
+ intel->saveSWF[15] = INREG(SWF31);
+ intel->saveSWF[16] = INREG(SWF32);
+
+ intel->saveDSPCLK_GATE_D = INREG(DSPCLK_GATE_D);
+ intel->saveRENCLK_GATE_D1 = INREG(RENCLK_GATE_D1);
+
+ if (IS_I965G(intel)) {
+ intel->saveRENCLK_GATE_D2 = INREG(RENCLK_GATE_D2);
+ intel->saveRAMCLK_GATE_D = INREG(RAMCLK_GATE_D);
+ }
+
+ if (IS_I965GM(intel) || IS_GM45(intel))
+ intel->savePWRCTXA = INREG(PWRCTXA);
+
+ if (IS_MOBILE(intel) && !IS_I830(intel))
+ intel->saveLVDS = INREG(LVDS);
+ intel->savePFIT_CONTROL = INREG(PFIT_CONTROL);
+
+ for (i = 0; i < xf86_config->num_output; i++) {
+ xf86OutputPtr output = xf86_config->output[i];
+ if (output->funcs->save)
+ (*output->funcs->save) (output);
+ }
+
+ vgaHWUnlock(hwp);
+ vgaHWSave(scrn, vgaReg, VGA_SR_FONTS);
+
+ return TRUE;
+}
+
+/* Wait for the PLL to settle down after programming */
+static void i830_dpll_settle(void)
+{
+ usleep(10000); /* 10 ms *should* be plenty */
+}
+
+static Bool RestoreHWState(ScrnInfoPtr scrn)
+{
+ xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+ vgaHWPtr hwp = VGAHWPTR(scrn);
+ vgaRegPtr vgaReg = &hwp->SavedReg;
+ int i;
+
+ if (IS_IGDNG(intel))
+ return TRUE;
+
+ DPRINTF(PFX, "RestoreHWState\n");
+
+ /* Disable outputs */
+ for (i = 0; i < xf86_config->num_output; i++) {
+ xf86OutputPtr output = xf86_config->output[i];
+ output->funcs->dpms(output, DPMSModeOff);
+ }
+ i830WaitForVblank(scrn);
+
+ /* Disable pipes */
+ for (i = 0; i < xf86_config->num_crtc; i++) {
+ xf86CrtcPtr crtc = xf86_config->crtc[i];
+ i830_crtc_disable(crtc, TRUE);
+ }
+ i830WaitForVblank(scrn);
+
+ if (IS_MOBILE(intel) && !IS_I830(intel))
+ OUTREG(LVDS, intel->saveLVDS);
+
+ if (!IS_I830(intel) && !IS_845G(intel))
+ OUTREG(PFIT_CONTROL, intel->savePFIT_CONTROL);
+
+ if (!DSPARB_HWCONTROL(intel))
+ OUTREG(DSPARB, intel->saveDSPARB);
+
+ OUTREG(DSPCLK_GATE_D, intel->saveDSPCLK_GATE_D);
+ OUTREG(RENCLK_GATE_D1, intel->saveRENCLK_GATE_D1);
+
+ if (IS_I965G(intel)) {
+ OUTREG(RENCLK_GATE_D2, intel->saveRENCLK_GATE_D2);
+ OUTREG(RAMCLK_GATE_D, intel->saveRAMCLK_GATE_D);
+ }
+
+ if (IS_I965GM(intel) || IS_GM45(intel))
+ OUTREG(PWRCTXA, intel->savePWRCTXA);
+
+ /*
+ * Pipe regs
+ * To restore the saved state, we first need to program the PLL regs,
+ * followed by the pipe configuration and finally the display plane
+ * configuration. The VGA registers can program one, both or neither
+ * of the PLL regs, depending on their VGA_MOD_DIS bit value.
+ */
+
+ /*
+ * Since either or both pipes may use the VGA clocks, make sure the
+ * regs are valid.
+ */
+ OUTREG(VCLK_DIVISOR_VGA0, intel->saveVCLK_DIVISOR_VGA0);
+ OUTREG(VCLK_DIVISOR_VGA1, intel->saveVCLK_DIVISOR_VGA1);
+ OUTREG(VCLK_POST_DIV, intel->saveVCLK_POST_DIV);
+
+ /* If the pipe A PLL is active, we can restore the pipe & plane config */
+ if (intel->saveDPLL_A & DPLL_VCO_ENABLE) {
+ OUTREG(FPA0, intel->saveFPA0);
+ OUTREG(DPLL_A, intel->saveDPLL_A & ~DPLL_VCO_ENABLE);
+ POSTING_READ(DPLL_A);
+ usleep(150);
+ }
+ OUTREG(FPA0, intel->saveFPA0);
+ OUTREG(FPA1, intel->saveFPA1);
+ OUTREG(DPLL_A, intel->saveDPLL_A);
+ POSTING_READ(DPLL_A);
+ i830_dpll_settle();
+ if (IS_I965G(intel))
+ OUTREG(DPLL_A_MD, intel->saveDPLL_A_MD);
+ else
+ OUTREG(DPLL_A, intel->saveDPLL_A);
+ POSTING_READ(DPLL_A);
+ i830_dpll_settle();
+
+ /* Restore mode config */
+ OUTREG(HTOTAL_A, intel->saveHTOTAL_A);
+ OUTREG(HBLANK_A, intel->saveHBLANK_A);
+ OUTREG(HSYNC_A, intel->saveHSYNC_A);
+ OUTREG(VTOTAL_A, intel->saveVTOTAL_A);
+ OUTREG(VBLANK_A, intel->saveVBLANK_A);
+ OUTREG(VSYNC_A, intel->saveVSYNC_A);
+ OUTREG(BCLRPAT_A, intel->saveBCLRPAT_A);
+
+ OUTREG(DSPASTRIDE, intel->saveDSPASTRIDE);
+ OUTREG(DSPASIZE, intel->saveDSPASIZE);
+ OUTREG(DSPAPOS, intel->saveDSPAPOS);
+ OUTREG(PIPEASRC, intel->savePIPEASRC);
+ OUTREG(DSPABASE, intel->saveDSPABASE);
+ if (IS_I965G(intel)) {
+ OUTREG(DSPASURF, intel->saveDSPASURF);
+ OUTREG(DSPATILEOFF, intel->saveDSPATILEOFF);
+ }
+
+ OUTREG(PIPEACONF, intel->savePIPEACONF);
+ POSTING_READ(PIPEACONF);
+ i830WaitForVblank(scrn);
+
+ /*
+ * Program Pipe A's plane
+ * The corresponding display plane may be disabled, and should only be
+ * enabled if pipe A is actually on (otherwise we have a bug in the initial
+ * state).
+ */
+ if ((intel->saveDSPACNTR & DISPPLANE_SEL_PIPE_MASK) ==
+ DISPPLANE_SEL_PIPE_A) {
+ OUTREG(DSPACNTR, intel->saveDSPACNTR);
+ OUTREG(DSPABASE, INREG(DSPABASE));
+ POSTING_READ(DSPABASE);
+ i830WaitForVblank(scrn);
+ }
+ if ((intel->saveDSPBCNTR & DISPPLANE_SEL_PIPE_MASK) ==
+ DISPPLANE_SEL_PIPE_A) {
+ OUTREG(DSPBCNTR, intel->saveDSPBCNTR);
+ OUTREG(DSPBBASE, INREG(DSPBBASE));
+ POSTING_READ(DSPBBASE);
+ i830WaitForVblank(scrn);
+ }
+
+ /* See note about pipe programming above */
+ if(xf86_config->num_crtc == 2) {
+ /* If the pipe B PLL is active, we can restore the pipe
+ * & plane config
+ */
+ if (intel->saveDPLL_B & DPLL_VCO_ENABLE) {
+ OUTREG(FPB0, intel->saveFPB0);
+ OUTREG(DPLL_B, intel->saveDPLL_B & ~DPLL_VCO_ENABLE);
+ POSTING_READ(DPLL_B);
+ usleep(150);
+ }
+ OUTREG(FPB0, intel->saveFPB0);
+ OUTREG(FPB1, intel->saveFPB1);
+ OUTREG(DPLL_B, intel->saveDPLL_B);
+ POSTING_READ(DPLL_B);
+ i830_dpll_settle();
+ if (IS_I965G(intel))
+ OUTREG(DPLL_B_MD, intel->saveDPLL_B_MD);
+ else
+ OUTREG(DPLL_B, intel->saveDPLL_B);
+ POSTING_READ(DPLL_B);
+ i830_dpll_settle();
+
+ /* Restore mode config */
+ OUTREG(HTOTAL_B, intel->saveHTOTAL_B);
+ OUTREG(HBLANK_B, intel->saveHBLANK_B);
+ OUTREG(HSYNC_B, intel->saveHSYNC_B);
+ OUTREG(VTOTAL_B, intel->saveVTOTAL_B);
+ OUTREG(VBLANK_B, intel->saveVBLANK_B);
+ OUTREG(VSYNC_B, intel->saveVSYNC_B);
+ OUTREG(BCLRPAT_B, intel->saveBCLRPAT_B);
+ OUTREG(DSPBSTRIDE, intel->saveDSPBSTRIDE);
+ OUTREG(DSPBSIZE, intel->saveDSPBSIZE);
+ OUTREG(DSPBPOS, intel->saveDSPBPOS);
+ OUTREG(PIPEBSRC, intel->savePIPEBSRC);
+ OUTREG(DSPBBASE, intel->saveDSPBBASE);
+ if (IS_I965G(intel)) {
+ OUTREG(DSPBSURF, intel->saveDSPBSURF);
+ OUTREG(DSPBTILEOFF, intel->saveDSPBTILEOFF);
+ }
+
+ OUTREG(PIPEBCONF, intel->savePIPEBCONF);
+ POSTING_READ(PIPEBCONF);
+ i830WaitForVblank(scrn);
+
+ /*
+ * Program Pipe B's plane
+ * Note that pipe B may be disabled, and in that case, the plane
+ * should also be disabled or we must have had a bad initial state.
+ */
+ if ((intel->saveDSPACNTR & DISPPLANE_SEL_PIPE_MASK) ==
+ DISPPLANE_SEL_PIPE_B) {
+ OUTREG(DSPACNTR, intel->saveDSPACNTR);
+ OUTREG(DSPABASE, INREG(DSPABASE));
+ i830WaitForVblank(scrn);
+ }
+ if ((intel->saveDSPBCNTR & DISPPLANE_SEL_PIPE_MASK) ==
+ DISPPLANE_SEL_PIPE_B) {
+ OUTREG(DSPBCNTR, intel->saveDSPBCNTR);
+ OUTREG(DSPBBASE, INREG(DSPBBASE));
+ i830WaitForVblank(scrn);
+ }
+ }
+
+ OUTREG(VGACNTRL, intel->saveVGACNTRL);
+
+ /*
+ * Restore cursors
+ * Even though the X cursor is hidden before we restore the hw state,
+ * we probably only disabled one cursor plane. If we're going from
+ * e.g. plane b to plane a here in RestoreHWState, we need to restore
+ * both cursor plane settings.
+ */
+ OUTREG(CURSOR_A_POSITION, intel->saveCURSOR_A_POSITION);
+ OUTREG(CURSOR_A_BASE, intel->saveCURSOR_A_BASE);
+ OUTREG(CURSOR_A_CONTROL, intel->saveCURSOR_A_CONTROL);
+ OUTREG(CURSOR_B_POSITION, intel->saveCURSOR_B_POSITION);
+ OUTREG(CURSOR_B_BASE, intel->saveCURSOR_B_BASE);
+ OUTREG(CURSOR_B_CONTROL, intel->saveCURSOR_B_CONTROL);
+
+ /* Restore outputs */
+ for (i = 0; i < xf86_config->num_output; i++) {
+ xf86OutputPtr output = xf86_config->output[i];
+ if (output->funcs->restore)
+ output->funcs->restore(output);
+ }
+
+ i830_restore_palette(intel, PIPE_A);
+ i830_restore_palette(intel, PIPE_B);
+
+ for(i = 0; i < 7; i++) {
+ OUTREG(SWF0 + (i << 2), intel->saveSWF[i]);
+ OUTREG(SWF00 + (i << 2), intel->saveSWF[i+7]);
+ }
+
+ OUTREG(SWF30, intel->saveSWF[14]);
+ OUTREG(SWF31, intel->saveSWF[15]);
+ OUTREG(SWF32, intel->saveSWF[16]);
+
+ vgaHWRestore(scrn, vgaReg, VGA_SR_FONTS);
+ vgaHWLock(hwp);
+
+ return TRUE;
+}
+
+/**
+ * Intialiazes the hardware for the 3D pipeline use in the 2D driver.
+ *
+ * Some state caching is performed to avoid redundant state emits. This
+ * function is also responsible for marking the state as clobbered for DRI
+ * clients.
+ */
+void IntelEmitInvarientState(ScrnInfoPtr scrn)
+{
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+
+ /* If we've emitted our state since the last clobber by another client,
+ * skip it.
+ */
+ if (intel->last_3d != LAST_3D_OTHER)
+ return;
+
+ if (IS_GEN2(intel))
+ I830EmitInvarientState(scrn);
+ else if IS_GEN3(intel)
+ I915EmitInvarientState(scrn);
+}
+
+static void
+I830BlockHandler(int i, pointer blockData, pointer pTimeout, pointer pReadmask)
+{
+ ScreenPtr screen = screenInfo.screens[i];
+ ScrnInfoPtr scrn = xf86Screens[i];
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+
+ screen->BlockHandler = intel->BlockHandler;
+
+ (*screen->BlockHandler) (i, blockData, pTimeout, pReadmask);
+
+ intel->BlockHandler = screen->BlockHandler;
+ screen->BlockHandler = I830BlockHandler;
+
+ intel_uxa_block_handler(intel);
+ intel_video_block_handler(scrn);
+}
+
+static void intel_fixup_mtrrs(ScrnInfoPtr scrn)
+{
+#ifdef HAS_MTRR_SUPPORT
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+ int fd;
+ struct mtrr_gentry gentry;
+ struct mtrr_sentry sentry;
+
+ if ((fd = open("/proc/mtrr", O_RDONLY, 0)) != -1) {
+ for (gentry.regnum = 0;
+ ioctl(fd, MTRRIOC_GET_ENTRY, &gentry) == 0;
+ ++gentry.regnum) {
+
+ if (gentry.size < 1) {
+ /* DISABLED */
+ continue;
+ }
+
+ /* Check the MTRR range is one we like and if not - remove it.
+ * The Xserver common layer will then setup the right range
+ * for us.
+ */
+ if (gentry.base == intel->LinearAddr &&
+ gentry.size < intel->FbMapSize) {
+
+ xf86DrvMsg(scrn->scrnIndex, X_INFO,
+ "Removing bad MTRR range (base 0x%lx, size 0x%x)\n",
+ gentry.base, gentry.size);
+
+ sentry.base = gentry.base;
+ sentry.size = gentry.size;
+ sentry.type = gentry.type;
+
+ if (ioctl(fd, MTRRIOC_DEL_ENTRY, &sentry) == -1) {
+ xf86DrvMsg(scrn->scrnIndex, X_ERROR,
+ "Failed to remove bad MTRR range\n");
+ }
+ }
+ }
+ close(fd);
+ }
+#endif
+}
+
+/*
+ * Try to allocate memory for rendering
+ */
+static Bool i830_memory_init(ScrnInfoPtr scrn)
+{
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+
+ /* Set up our video memory allocator for the chosen videoRam */
+ if (!i830_allocator_init(scrn, scrn->videoRam * KB(1))) {
+ xf86DrvMsg(scrn->scrnIndex, X_ERROR,
+ "Couldn't initialize video memory allocator\n");
+ PreInitCleanup(scrn);
+ return FALSE;
+ }
+
+ xf86DrvMsg(scrn->scrnIndex,
+ intel->pEnt->device->videoRam ? X_CONFIG : X_DEFAULT,
+ "VideoRam: %d KB\n", scrn->videoRam);
+
+ if (!i830_allocate_2d_memory(scrn))
+ return FALSE;
+
+ if (IS_I965GM(intel) || IS_GM45(intel))
+ if (!i830_allocate_pwrctx(scrn))
+ return FALSE;
+ return TRUE;
+}
+
+Bool intel_crtc_on(xf86CrtcPtr crtc)
+{
+ ScrnInfoPtr scrn = crtc->scrn;
+ xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+
+ if (intel->use_drm_mode) {
+ int i, active_outputs = 0;
+
+ if (!crtc->enabled)
+ return FALSE;
+
+ /* Kernel manages CRTC status based out output config */
+ for (i = 0; i < xf86_config->num_output; i++) {
+ xf86OutputPtr output = xf86_config->output[i];
+ if (output->crtc == crtc &&
+ drmmode_output_dpms_status(output) == DPMSModeOn)
+ active_outputs++;
+ }
+
+ if (active_outputs)
+ return TRUE;
+ return FALSE;
+ } else {
+ I830CrtcPrivatePtr intel_crtc = crtc->driver_private;
+
+ if (!crtc->enabled)
+ return FALSE;
+
+ if (intel_crtc->dpms_mode == DPMSModeOn)
+ return TRUE;
+ return FALSE;
+ }
+}
+
+int intel_crtc_to_pipe(xf86CrtcPtr crtc)
+{
+ ScrnInfoPtr scrn = crtc->scrn;
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+ int pipe;
+
+ if (intel->use_drm_mode) {
+ pipe = drmmode_get_pipe_from_crtc_id(intel->bufmgr, crtc);
+ } else {
+ I830CrtcPrivatePtr intel_crtc = crtc->driver_private;
+ pipe = intel_crtc->pipe;
+ }
+
+ return pipe;
+}
+
+static void
+I830AdjustMemory(ScreenPtr screen)
+{
+ ScrnInfoPtr scrn;
+ intel_screen_private *intel;
+ unsigned long sys_mem;
+ MessageType from;
+
+ scrn = xf86Screens[screen->myNum];
+ intel = intel_get_screen_private(scrn);
+
+ /* Limit videoRam to how much we might be able to allocate from AGP */
+ sys_mem = I830CheckAvailableMemory(scrn);
+ if (sys_mem == -1) {
+ xf86DrvMsg(scrn->scrnIndex, X_ERROR,
+ "/dev/agpgart is either not available, or no memory "
+ "is available\nfor allocation. Please enable agpgart\n.");
+ scrn->videoRam = intel->stolen_size / KB(1);
+ }
+ if (sys_mem + (intel->stolen_size / 1024) < scrn->videoRam) {
+ scrn->videoRam = sys_mem + (intel->stolen_size / 1024);
+ from = X_PROBED;
+ if (sys_mem + (intel->stolen_size / 1024) <
+ intel->pEnt->device->videoRam) {
+ xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+ "VideoRAM reduced to %d kByte "
+ "(limited to available sysmem)\n", scrn->videoRam);
+ }
+ }
+
+ /* Limit video RAM to the actual aperture size */
+ if (scrn->videoRam > intel->FbMapSize / 1024) {
+ scrn->videoRam = intel->FbMapSize / 1024;
+ if (intel->FbMapSize / 1024 < intel->pEnt->device->videoRam) {
+ xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+ "VideoRam reduced to %d kByte (limited to aperture "
+ "size)\n", scrn->videoRam);
+ }
+ }
+
+ /* Make sure it's on a page boundary */
+ if (scrn->videoRam & 3) {
+ xf86DrvMsg(scrn->scrnIndex, X_WARNING, "VideoRam reduced to "
+ "%d KB (page aligned - was %d KB)\n", scrn->videoRam & ~3,
+ scrn->videoRam);
+ scrn->videoRam &= ~3;
+ }
+
+ if (!IS_I965G(intel) && scrn->displayWidth > 2048) {
+ xf86DrvMsg(scrn->scrnIndex, X_ERROR,
+ "Cannot support DRI with frame buffer width > 2048.\n");
+ intel->directRenderingType = DRI_DISABLED;
+ }
+}
+
+static void
+i830_disable_render_standby(ScrnInfoPtr scrn)
+{
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+ uint32_t render_standby;
+
+ /* Render Standby might cause hang issue, try always disable it.*/
+ if (IS_I965GM(intel) || IS_GM45(intel)) {
+ render_standby = INREG(MCHBAR_RENDER_STANDBY);
+ if (render_standby & RENDER_STANDBY_ENABLE) {
+ xf86DrvMsg(scrn->scrnIndex, X_INFO, "Disable render standby.\n");
+ OUTREG(MCHBAR_RENDER_STANDBY,
+ (render_standby & (~RENDER_STANDBY_ENABLE)));
+ }
+ }
+}
+
+static void
+intel_flush_callback(CallbackListPtr *list,
+ pointer user_data, pointer call_data)
+{
+ ScrnInfoPtr scrn = user_data;
+ if (scrn->vtSema)
+ intel_batch_submit(scrn);
+}
+
+static Bool
+I830ScreenInit(int scrnIndex, ScreenPtr screen, int argc, char **argv)
+{
+ ScrnInfoPtr scrn = xf86Screens[screen->myNum];
+ vgaHWPtr hwp = NULL;
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+ VisualPtr visual;
+ MessageType from;
+
+ if (!intel->use_drm_mode)
+ hwp = VGAHWPTR(scrn);
+
+ /*
+ * The "VideoRam" config file parameter specifies the maximum amount of
+ * memory that will be used/allocated. When not present, we allow the
+ * driver to allocate as much memory as it wishes to satisfy its
+ * allocations, but if agpgart support isn't available, it gets limited
+ * to the amount of pre-allocated ("stolen") memory.
+ *
+ * Note that in using this value for allocator initialization, we're
+ * limiting aperture allocation to the VideoRam option, rather than limiting
+ * actual memory allocation, so alignment and things will cause less than
+ * VideoRam to be actually used.
+ */
+ if (intel->pEnt->device->videoRam == 0) {
+ from = X_DEFAULT;
+ scrn->videoRam = intel->FbMapSize / KB(1);
+ } else {
+#if 0
+ from = X_CONFIG;
+ scrn->videoRam = intel->pEnt->device->videoRam;
+#else
+ /* Disable VideoRam configuration, at least for now. Previously,
+ * VideoRam was necessary to avoid overly low limits on allocated
+ * memory, so users created larger, yet still small, fixed allocation
+ * limits in their config files. Now, the driver wants to allocate more,
+ * and the old intention of the VideoRam lines that had been entered is
+ * obsolete.
+ */
+ from = X_DEFAULT;
+ scrn->videoRam = intel->FbMapSize / KB(1);
+
+ if (scrn->videoRam != intel->pEnt->device->videoRam) {
+ xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+ "VideoRam configuration found, which is no longer "
+ "recommended.\n");
+ xf86DrvMsg(scrn->scrnIndex, X_INFO,
+ "Continuing with default %dkB VideoRam instead of %d "
+ "kB.\n",
+ scrn->videoRam,
+ intel->pEnt->device->videoRam);
+ }
+#endif
+ }
+
+ if (intel->use_drm_mode) {
+ struct pci_device *const device = intel->PciInfo;
+ int fb_bar = IS_GEN2(intel) ? 0 : 2;
+
+ scrn->videoRam = device->regions[fb_bar].size / 1024;
+ } else {
+ I830AdjustMemory(screen);
+ }
+
+#ifdef DRI2
+ if (intel->directRenderingType == DRI_NONE
+ && I830DRI2ScreenInit(screen))
+ intel->directRenderingType = DRI_DRI2;
+#endif
+
+ intel->force_fallback = FALSE;
+ intel->can_blt = can_accelerate_blt(intel);
+#if 0 /* XXX oga */
+ intel->has_kernel_flush = has_kernel_flush(intel);
+#endif
+ intel->has_kernel_flush = TRUE;
+ intel->use_shadow = !intel->can_blt;
+
+ /* Enable tiling by default */
+ intel->tiling = INTEL_TILING_ALL;
+
+ /* Allow user override if they set a value */
+ if (!xf86ReturnOptValBool(intel->Options, OPTION_TILING_2D, TRUE))
+ intel->tiling &= ~INTEL_TILING_2D;
+ if (xf86ReturnOptValBool(intel->Options, OPTION_TILING_FB, FALSE))
+ intel->tiling &= ~INTEL_TILING_FB;
+
+ if (xf86IsOptionSet(intel->Options, OPTION_SHADOW)) {
+ if (xf86ReturnOptValBool(intel->Options, OPTION_SHADOW, FALSE))
+ intel->use_shadow = TRUE;
+ }
+
+ if (intel->use_shadow) {
+ xf86DrvMsg(scrn->scrnIndex, X_CONFIG,
+ "Shadow buffer enabled,"
+ " 2D GPU acceleration disabled.\n");
+ }
+
+ /* SwapBuffers delays to avoid tearing */
+ intel->swapbuffers_wait = TRUE;
+
+ /* Allow user override if they set a value */
+ if (xf86IsOptionSet(intel->Options, OPTION_SWAPBUFFERS_WAIT)) {
+ if (xf86ReturnOptValBool
+ (intel->Options, OPTION_SWAPBUFFERS_WAIT, FALSE))
+ intel->swapbuffers_wait = TRUE;
+ else
+ intel->swapbuffers_wait = FALSE;
+ }
+
+ xf86DrvMsg(scrn->scrnIndex, X_CONFIG, "Framebuffer %s\n",
+ intel->tiling & INTEL_TILING_FB ? "tiled" : "linear");
+ xf86DrvMsg(scrn->scrnIndex, X_CONFIG, "Pixmaps %s\n",
+ intel->tiling & INTEL_TILING_2D ? "tiled" : "linear");
+ xf86DrvMsg(scrn->scrnIndex, X_CONFIG, "3D buffers %s\n",
+ intel->tiling & INTEL_TILING_3D ? "tiled" : "linear");
+ xf86DrvMsg(scrn->scrnIndex, X_CONFIG, "SwapBuffers wait %sabled\n",
+ intel->swapbuffers_wait ? "en" : "dis");
+
+ intel->last_3d = LAST_3D_OTHER;
+ intel->overlayOn = FALSE;
+
+ /*
+ * Set this so that the overlay allocation is factored in when
+ * appropriate.
+ */
+ intel->XvEnabled = TRUE;
+
+ /* Need MMIO mapped to do GTT lookups during memory allocation. */
+ if (!intel->use_drm_mode)
+ I830MapMMIO(scrn);
+
+ /* Need FB mapped to access non-GEM objects like
+ * a UMS frame buffer, or the fake bufmgr.
+ */
+ if (!intel->use_drm_mode) {
+ if (!I830MapMem(scrn))
+ return FALSE;
+ scrn->memPhysBase = (unsigned long)intel->FbBase;
+ }
+
+ if (!i830_memory_init(scrn)) {
+ xf86DrvMsg(scrn->scrnIndex, X_ERROR,
+ "Couldn't allocate video memory\n");
+ return FALSE;
+ }
+
+ intel_fixup_mtrrs(scrn);
+
+ intel_batch_init(scrn);
+
+ if (INTEL_INFO(intel)->gen >= 40)
+ gen4_render_state_init(scrn);
+
+ miClearVisualTypes();
+ if (!miSetVisualTypes(scrn->depth,
+ miGetDefaultVisualMask(scrn->depth),
+ scrn->rgbBits, scrn->defaultVisual))
+ return FALSE;
+ if (!miSetPixmapDepths())
+ return FALSE;
+
+ if (!intel->use_drm_mode) {
+ vgaHWSetMmioFuncs(hwp, intel->MMIOBase, 0);
+ vgaHWGetIOBase(hwp);
+ DPRINTF(PFX, "assert( if(!vgaHWMapMem(scrn)) )\n");
+ if (!vgaHWMapMem(scrn))
+ return FALSE;
+ }
+
+ DPRINTF(PFX, "assert( if(!I830EnterVT(scrnIndex, 0)) )\n");
+
+ DPRINTF(PFX, "assert( if(!fbScreenInit(screen, ...) )\n");
+ if (!fbScreenInit(screen, NULL,
+ scrn->virtualX, scrn->virtualY,
+ scrn->xDpi, scrn->yDpi,
+ scrn->displayWidth, scrn->bitsPerPixel))
+ return FALSE;
+
+ if (scrn->bitsPerPixel > 8) {
+ /* Fixup RGB ordering */
+ visual = screen->visuals + screen->numVisuals;
+ while (--visual >= screen->visuals) {
+ if ((visual->class | DynamicClass) == DirectColor) {
+ visual->offsetRed = scrn->offset.red;
+ visual->offsetGreen = scrn->offset.green;
+ visual->offsetBlue = scrn->offset.blue;
+ visual->redMask = scrn->mask.red;
+ visual->greenMask = scrn->mask.green;
+ visual->blueMask = scrn->mask.blue;
+ }
+ }
+ }
+
+ fbPictureInit(screen, NULL, 0);
+
+ xf86SetBlackWhitePixels(screen);
+
+ if (!intel_uxa_init(screen)) {
+ xf86DrvMsg(scrn->scrnIndex, X_ERROR,
+ "Hardware acceleration initialization failed\n");
+ return FALSE;
+ }
+
+ miInitializeBackingStore(screen);
+ xf86SetBackingStore(screen);
+ xf86SetSilkenMouse(screen);
+ miDCInitialize(screen, xf86GetPointerScreenFuncs());
+
+ xf86DrvMsg(scrn->scrnIndex, X_INFO, "Initializing HW Cursor\n");
+ if (!I830CursorInit(screen))
+ xf86DrvMsg(scrn->scrnIndex, X_ERROR,
+ "Hardware cursor initialization failed\n");
+
+ /* Must force it before EnterVT, so we are in control of VT and
+ * later memory should be bound when allocating, e.g rotate_mem */
+ scrn->vtSema = TRUE;
+
+ if (!I830EnterVT(scrnIndex, 0))
+ return FALSE;
+
+ intel->BlockHandler = screen->BlockHandler;
+ screen->BlockHandler = I830BlockHandler;
+
+ if (!AddCallback(&FlushCallback, intel_flush_callback, scrn))
+ return FALSE;
+
+ screen->SaveScreen = xf86SaveScreen;
+ intel->CloseScreen = screen->CloseScreen;
+ screen->CloseScreen = I830CloseScreen;
+ intel->CreateScreenResources = screen->CreateScreenResources;
+ screen->CreateScreenResources = i830CreateScreenResources;
+
+ if (!xf86CrtcScreenInit(screen))
+ return FALSE;
+
+ DPRINTF(PFX, "assert( if(!miCreateDefColormap(screen)) )\n");
+ if (!miCreateDefColormap(screen))
+ return FALSE;
+
+ DPRINTF(PFX, "assert( if(!xf86HandleColormaps(screen, ...)) )\n");
+ if (!xf86HandleColormaps(screen, 256, 8, I830LoadPalette, NULL,
+ CMAP_RELOAD_ON_MODE_SWITCH |
+ CMAP_PALETTED_TRUECOLOR)) {
+ return FALSE;
+ }
+
+ xf86DPMSInit(screen, xf86DPMSSet, 0);
+
+#ifdef INTEL_XVMC
+ if (INTEL_INFO(intel)->gen >= 40)
+ intel->XvMCEnabled = TRUE;
+ from = ((intel->directRenderingType == DRI_DRI2) &&
+ xf86GetOptValBool(intel->Options, OPTION_XVMC,
+ &intel->XvMCEnabled) ? X_CONFIG : X_DEFAULT);
+ xf86DrvMsg(scrn->scrnIndex, from, "Intel XvMC decoder %sabled\n",
+ intel->XvMCEnabled ? "en" : "dis");
+#endif
+ /* Init video */
+ if (intel->XvEnabled)
+ I830InitVideo(screen);
+
+#if defined(DRI2)
+ switch (intel->directRenderingType) {
+ case DRI_DRI2:
+ intel->directRenderingOpen = TRUE;
+ xf86DrvMsg(scrn->scrnIndex, X_INFO,
+ "direct rendering: DRI2 Enabled\n");
+ break;
+ case DRI_DISABLED:
+ xf86DrvMsg(scrn->scrnIndex, X_INFO,
+ "direct rendering: Disabled\n");
+ break;
+ case DRI_NONE:
+ xf86DrvMsg(scrn->scrnIndex, X_INFO,
+ "direct rendering: Failed\n");
+ break;
+ }
+#else
+ xf86DrvMsg(scrn->scrnIndex, X_INFO,
+ "direct rendering: Not available\n");
+#endif
+
+ if (serverGeneration == 1)
+ xf86ShowUnusedOptions(scrn->scrnIndex, scrn->options);
+
+#ifdef notyet
+ if (!intel->use_drm_mode {
+ AddGeneralSocket(intel->drmSubFD);
+ RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA,
+ drm_wakeup_handler, intel);
+ }
+#endif
+
+ intel->starting = FALSE;
+ intel->suspended = FALSE;
+
+ return TRUE;
+}
+
+static void i830AdjustFrame(int scrnIndex, int x, int y, int flags)
+{
+ ScrnInfoPtr scrn = xf86Screens[scrnIndex];
+ xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+ xf86OutputPtr output = config->output[config->compat_output];
+ xf86CrtcPtr crtc = output->crtc;
+
+ DPRINTF(PFX, "i830AdjustFrame: y = %d (+ %d), x = %d (+ %d)\n",
+ x, crtc->desiredX, y, crtc->desiredY);
+
+ if (intel->use_drm_mode)
+ return;
+
+ if (crtc && crtc->enabled)
+ {
+ /* Sync the engine before adjust frame */
+ intel_sync(scrn);
+ i830PipeSetBase(crtc, crtc->desiredX + x, crtc->desiredY + y);
+ crtc->x = output->initial_x + x;
+ crtc->y = output->initial_y + y;
+ }
+}
+
+static void I830FreeScreen(int scrnIndex, int flags)
+{
+ ScrnInfoPtr scrn = xf86Screens[scrnIndex];
+
+ intel_close_drm_master(scrn);
+
+ I830FreeRec(xf86Screens[scrnIndex]);
+ if (xf86LoaderCheckSymbol("vgaHWFreeHWRec"))
+ vgaHWFreeHWRec(xf86Screens[scrnIndex]);
+}
+
+static void I830LeaveVT(int scrnIndex, int flags)
+{
+ ScrnInfoPtr scrn = xf86Screens[scrnIndex];
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+ int ret;
+
+ DPRINTF(PFX, "Leave VT\n");
+
+ i830SetHotkeyControl(scrn, HOTKEY_BIOS_SWITCH);
+
+ xf86RotateFreeShadow(scrn);
+
+ xf86_hide_cursors(scrn);
+
+ if (!intel->use_drm_mode) {
+ RestoreHWState(scrn);
+
+ /* console restore hack */
+ if (IS_IGDNG(intel) && intel->int10 && intel->int10Mode) {
+ xf86Int10InfoPtr int10 = intel->int10;
+
+ /* Use int10 to restore the console mode */
+ int10->num = 0x10;
+ int10->ax = 0x4f02;
+ int10->bx = intel->int10Mode | 0x8000;
+ int10->cx = int10->dx = 0;
+ xf86ExecX86int10(int10);
+ }
+
+ }
+
+ i830_unbind_all_memory(scrn);
+
+ if (!intel->use_drm_mode) {
+ int ret;
+
+ /* Tell the kernel to evict all buffer objects and block GTT
+ * usage while we're no longer in control of the chip.
+ */
+ ret = drmCommandNone(intel->drmSubFD, DRM_I915_GEM_LEAVEVT);
+ if (ret != 0)
+ FatalError("DRM_I915_LEAVEVT failed: %s\n",
+ strerror(ret));
+ }
+
+ ret = drmDropMaster(intel->drmSubFD);
+ if (ret)
+ xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+ "drmDropMaster failed: %s\n", strerror(errno));
+}
+
+/*
+ * This gets called when gaining control of the VT, and from ScreenInit().
+ */
+static Bool I830EnterVT(int scrnIndex, int flags)
+{
+ ScrnInfoPtr scrn = xf86Screens[scrnIndex];
+ xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+ int i, ret;
+
+ DPRINTF(PFX, "Enter VT\n");
+
+ ret = drmSetMaster(intel->drmSubFD);
+ if (ret) {
+ if (errno == EINVAL) {
+ xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+ "drmSetMaster failed: 2.6.29 or newer kernel required for "
+ "multi-server DRI\n");
+ } else {
+ xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+ "drmSetMaster failed: %s\n",
+ strerror(errno));
+ }
+ }
+
+ /*
+ * Only save state once per server generation since that's what most
+ * drivers do. Could change this to save state at each VT enter.
+ */
+ if (intel->SaveGeneration != serverGeneration) {
+ intel->SaveGeneration = serverGeneration;
+ if (!intel->use_drm_mode)
+ SaveHWState(scrn);
+ }
+
+ /* Get the hardware into a known state if needed */
+ if (!intel->use_drm_mode) {
+ /* Disable outputs */
+ for (i = 0; i < xf86_config->num_output; i++) {
+ xf86OutputPtr output = xf86_config->output[i];
+ output->funcs->dpms(output, DPMSModeOff);
+ }
+ i830WaitForVblank(scrn);
+
+ /* Disable pipes */
+ for (i = 0; i < xf86_config->num_crtc; i++) {
+ xf86CrtcPtr crtc = xf86_config->crtc[i];
+ if (IS_IGDNG(intel))
+ ironlake_crtc_disable(crtc);
+ else
+ i830_crtc_disable(crtc, TRUE);
+ }
+ i830WaitForVblank(scrn);
+ }
+
+ if (!intel->use_drm_mode) {
+ int ret;
+
+ i830_disable_render_standby(scrn);
+
+ /* Tell the kernel that we're back in control and ready for GTT
+ * usage.
+ */
+ ret = drmCommandNone(intel->drmSubFD, DRM_I915_GEM_ENTERVT);
+ if (ret != 0)
+ FatalError("DRM_I915_ENTERVT failed: %s\n",
+ strerror(ret));
+ }
+
+ if (!i830_bind_all_memory(scrn))
+ return FALSE;
+
+ i830_describe_allocations(scrn, 1, "");
+
+ if (!intel->use_drm_mode) {
+ I830InitHWCursor(scrn);
+
+ /* Tell the BIOS that we're in control of mode setting now. */
+ i830_init_bios_control(scrn);
+
+ i830_init_clock_gating(scrn);
+
+ if (intel->power_context)
+ OUTREG(PWRCTXA, intel->power_context->offset |
+ PWRCTX_EN);
+ /* Clear the framebuffer XXX drm_bo_map */
+ memset(intel->FbBase + intel->front_buffer->offset, 0,
+ scrn->virtualY * scrn->displayWidth * intel->cpp);
+ }
+
+ if (!xf86SetDesiredModes(scrn))
+ return FALSE;
+
+ if (!intel->use_drm_mode) {
+ i830DescribeOutputConfiguration(scrn);
+ }
+
+ /* Set the hotkey to just notify us. We could check its results
+ * periodically and attempt to do something, but it seems like we
+ * basically never get results when we should, and this should all
+ * be better handled through ACPI putting the key events out through
+ * evdev and your desktop environment picking it up.
+ */
+ i830SetHotkeyControl(scrn, HOTKEY_DRIVER_NOTIFY);
+
+ return TRUE;
+}
+
+static Bool I830SwitchMode(int scrnIndex, DisplayModePtr mode, int flags)
+{
+ ScrnInfoPtr scrn = xf86Screens[scrnIndex];
+
+ return xf86SetSingleMode(scrn, mode, RR_Rotate_0);
+}
+
+static Bool I830CloseScreen(int scrnIndex, ScreenPtr screen)
+{
+ ScrnInfoPtr scrn = xf86Screens[scrnIndex];
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+
+ if (scrn->vtSema == TRUE) {
+ I830LeaveVT(scrnIndex, 0);
+ }
+
+ DeleteCallback(&FlushCallback, intel_flush_callback, scrn);
+
+ if (!intel->use_drm_mode) {
+ DPRINTF(PFX, "\nUnmapping memory\n");
+ I830UnmapMem(scrn);
+ vgaHWUnmapMem(scrn);
+ }
+
+ if (intel->uxa_driver) {
+ uxa_driver_fini(screen);
+ free(intel->uxa_driver);
+ intel->uxa_driver = NULL;
+ }
+ if (intel->front_buffer) {
+ if (!intel->use_shadow)
+ intel_set_pixmap_bo(screen->GetScreenPixmap(screen),
+ NULL);
+ if (intel->use_drm_mode)
+ drmmode_closefb(scrn);
+ /* already unpinned by leavevt */
+ drm_intel_bo_unreference(intel->front_buffer);
+ intel->front_buffer = NULL;
+ }
+
+ if (intel->shadow_buffer) {
+ free(intel->shadow_buffer);
+ intel->shadow_buffer = NULL;
+ }
+
+ if (intel->shadow_damage) {
+ DamageUnregister(&screen->GetScreenPixmap(screen)->drawable,
+ intel->shadow_damage);
+ DamageDestroy(intel->shadow_damage);
+ intel->shadow_damage = NULL;
+ }
+
+ intel_batch_teardown(scrn);
+
+ if (INTEL_INFO(intel)->gen >= 40)
+ gen4_render_state_cleanup(scrn);
+
+ xf86_cursors_fini(screen);
+
+ i830_allocator_fini(scrn);
+
+ i965_free_video(scrn);
+ free(intel->offscreenImages);
+ intel->offscreenImages = NULL;
+
+ screen->CloseScreen = intel->CloseScreen;
+ (*screen->CloseScreen) (scrnIndex, screen);
+
+ if (intel->directRenderingOpen
+ && intel->directRenderingType == DRI_DRI2) {
+ intel->directRenderingOpen = FALSE;
+ I830DRI2CloseScreen(screen);
+ }
+
+ xf86GARTCloseScreen(scrnIndex);
+
+ scrn->vtSema = FALSE;
+ return TRUE;
+}
+
+static ModeStatus
+I830ValidMode(int scrnIndex, DisplayModePtr mode, Bool verbose, int flags)
+{
+ if (mode->Flags & V_INTERLACE) {
+ if (verbose) {
+ xf86DrvMsg(scrnIndex, X_PROBED,
+ "Removing interlaced mode \"%s\"\n",
+ mode->name);
+ }
+ return MODE_BAD;
+ }
+ return MODE_OK;
+}
+
+#ifndef SUSPEND_SLEEP
+#define SUSPEND_SLEEP 0
+#endif
+#ifndef RESUME_SLEEP
+#define RESUME_SLEEP 0
+#endif
+
+/*
+ * This function is only required if we need to do anything differently from
+ * DoApmEvent() in common/xf86PM.c, including if we want to see events other
+ * than suspend/resume.
+ */
+static Bool I830PMEvent(int scrnIndex, pmEvent event, Bool undo)
+{
+ ScrnInfoPtr scrn = xf86Screens[scrnIndex];
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+
+ DPRINTF(PFX, "Enter VT, event %d, undo: %s\n", event,
+ BOOLTOSTRING(undo));
+
+ switch (event) {
+ case XF86_APM_SYS_SUSPEND:
+ case XF86_APM_CRITICAL_SUSPEND: /*do we want to delay a critical suspend? */
+ case XF86_APM_USER_SUSPEND:
+ case XF86_APM_SYS_STANDBY:
+ case XF86_APM_USER_STANDBY:
+ if (!undo && !intel->suspended) {
+ scrn->LeaveVT(scrnIndex, 0);
+ intel->suspended = TRUE;
+ sleep(SUSPEND_SLEEP);
+ } else if (undo && intel->suspended) {
+ sleep(RESUME_SLEEP);
+ scrn->EnterVT(scrnIndex, 0);
+ intel->suspended = FALSE;
+ }
+ break;
+ case XF86_APM_STANDBY_RESUME:
+ case XF86_APM_NORMAL_RESUME:
+ case XF86_APM_CRITICAL_RESUME:
+ if (intel->suspended) {
+ sleep(RESUME_SLEEP);
+ scrn->EnterVT(scrnIndex, 0);
+ intel->suspended = FALSE;
+ /*
+ * Turn the screen saver off when resuming. This seems to be
+ * needed to stop xscreensaver kicking in (when used).
+ *
+ * XXX DoApmEvent() should probably call this just like
+ * xf86VTSwitch() does. Maybe do it here only in 4.2
+ * compatibility mode.
+ */
+ SaveScreens(SCREEN_SAVER_FORCER, ScreenSaverReset);
+ }
+ break;
+ /* This is currently used for ACPI */
+ case XF86_APM_CAPABILITY_CHANGED:
+ ErrorF("I830PMEvent: Capability change\n");
+
+ SaveScreens(SCREEN_SAVER_FORCER, ScreenSaverReset);
+ if (intel->quirk_flag & QUIRK_RESET_MODES)
+ xf86SetDesiredModes(scrn);
+
+ break;
+ default:
+ ErrorF("I830PMEvent: received APM event %d\n", event);
+ }
+ return TRUE;
+}
+
+xf86CrtcPtr intel_pipe_to_crtc(ScrnInfoPtr scrn, int pipe)
+{
+ xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
+ int c;
+
+ for (c = 0; c < config->num_crtc; c++) {
+ xf86CrtcPtr crtc = config->crtc[c];
+ I830CrtcPrivatePtr intel_crtc = crtc->driver_private;
+
+ if (intel_crtc->pipe == pipe)
+ return crtc;
+ }
+
+ return NULL;
+}
+
+void intel_init_scrn(ScrnInfoPtr scrn)
+{
+ scrn->PreInit = I830PreInit;
+ scrn->ScreenInit = I830ScreenInit;
+ scrn->SwitchMode = I830SwitchMode;
+ scrn->AdjustFrame = i830AdjustFrame;
+ scrn->EnterVT = I830EnterVT;
+ scrn->LeaveVT = I830LeaveVT;
+ scrn->FreeScreen = I830FreeScreen;
+ scrn->ValidMode = I830ValidMode;
+ scrn->PMEvent = I830PMEvent;
+}