Merge remote branch 'anholt/drm-intel-next' of /home/airlied/kernel/drm-next into...
authorDave Airlie <airlied@redhat.com>
Tue, 20 Apr 2010 03:11:45 +0000 (13:11 +1000)
committerDave Airlie <airlied@redhat.com>
Tue, 20 Apr 2010 03:11:45 +0000 (13:11 +1000)
* 'anholt/drm-intel-next' of /home/airlied/kernel/drm-next: (48 commits)
  agp/intel-gtt: kill previous_size assignments
  agp/intel-gtt: kill intel_i830_tlbflush
  agp/intel: split out gmch/gtt probe, part 1
  agp/intel: kill mutli_gmch_chip
  agp/intel: uncoditionally reconfigure driver on resume
  agp/intel: split out the GTT support
  agp/intel: introduce intel-agp.h header file
  drm/i915: Don't touch PORT_HOTPLUG_EN in intel_dp_detect()
  drm/i915/pch: Use minimal number of FDI lanes (v2)
  drm/i915: Add the support of memory self-refresh on Ironlake
  drm/i915: Move Pineview CxSR and watermark code into update_wm hook.
  drm/i915: Only save/restore FBC on the platform that supports FBC
  drm/i915: Fix the incorrect argument for SDVO SET_TV_format command
  drm/i915: Add support of SDVO on Ibexpeak PCH
  drm/i915: Don't enable pipe/plane/VCO early (wait for DPMS on).
  drm/i915: do not read uninitialized ->dev_private
  Revert "drm/i915: Use a dmi quirk to skip a broken SDVO TV output."
  drm/i915: implement multifunction SDVO device support
  drm/i915: remove unused intel_pipe_get_connector()
  drm/i915: remove connector object in old output structure
  ...

28 files changed:
drivers/char/agp/agp.h
drivers/char/agp/efficeon-agp.c
drivers/char/agp/intel-agp.c
drivers/char/agp/intel-agp.h [new file with mode: 0644]
drivers/char/agp/intel-gtt.c [new file with mode: 0644]
drivers/gpu/drm/i915/dvo.h
drivers/gpu/drm/i915/dvo_ch7017.c
drivers/gpu/drm/i915/dvo_ch7xxx.c
drivers/gpu/drm/i915/dvo_ivch.c
drivers/gpu/drm/i915/dvo_sil164.c
drivers/gpu/drm/i915/dvo_tfp410.c
drivers/gpu/drm/i915/i915_dma.c
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_irq.c
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/i915_suspend.c
drivers/gpu/drm/i915/i915_trace.h
drivers/gpu/drm/i915/intel_crt.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_dp.c
drivers/gpu/drm/i915/intel_drv.h
drivers/gpu/drm/i915/intel_dvo.c
drivers/gpu/drm/i915/intel_hdmi.c
drivers/gpu/drm/i915/intel_lvds.c
drivers/gpu/drm/i915/intel_modes.c
drivers/gpu/drm/i915/intel_sdvo.c
drivers/gpu/drm/i915/intel_tv.c

index 870f12c..1204909 100644 (file)
@@ -178,86 +178,6 @@ struct agp_bridge_data {
 #define PGE_EMPTY(b, p)        (!(p) || (p) == (unsigned long) (b)->scratch_page)
 
 
-/* Intel registers */
-#define INTEL_APSIZE   0xb4
-#define INTEL_ATTBASE  0xb8
-#define INTEL_AGPCTRL  0xb0
-#define INTEL_NBXCFG   0x50
-#define INTEL_ERRSTS   0x91
-
-/* Intel i830 registers */
-#define I830_GMCH_CTRL                 0x52
-#define I830_GMCH_ENABLED              0x4
-#define I830_GMCH_MEM_MASK             0x1
-#define I830_GMCH_MEM_64M              0x1
-#define I830_GMCH_MEM_128M             0
-#define I830_GMCH_GMS_MASK             0x70
-#define I830_GMCH_GMS_DISABLED         0x00
-#define I830_GMCH_GMS_LOCAL            0x10
-#define I830_GMCH_GMS_STOLEN_512       0x20
-#define I830_GMCH_GMS_STOLEN_1024      0x30
-#define I830_GMCH_GMS_STOLEN_8192      0x40
-#define I830_RDRAM_CHANNEL_TYPE                0x03010
-#define I830_RDRAM_ND(x)               (((x) & 0x20) >> 5)
-#define I830_RDRAM_DDT(x)              (((x) & 0x18) >> 3)
-
-/* This one is for I830MP w. an external graphic card */
-#define INTEL_I830_ERRSTS      0x92
-
-/* Intel 855GM/852GM registers */
-#define I855_GMCH_GMS_MASK             0xF0
-#define I855_GMCH_GMS_STOLEN_0M                0x0
-#define I855_GMCH_GMS_STOLEN_1M                (0x1 << 4)
-#define I855_GMCH_GMS_STOLEN_4M                (0x2 << 4)
-#define I855_GMCH_GMS_STOLEN_8M                (0x3 << 4)
-#define I855_GMCH_GMS_STOLEN_16M       (0x4 << 4)
-#define I855_GMCH_GMS_STOLEN_32M       (0x5 << 4)
-#define I85X_CAPID                     0x44
-#define I85X_VARIANT_MASK              0x7
-#define I85X_VARIANT_SHIFT             5
-#define I855_GME                       0x0
-#define I855_GM                                0x4
-#define I852_GME                       0x2
-#define I852_GM                                0x5
-
-/* Intel i845 registers */
-#define INTEL_I845_AGPM                0x51
-#define INTEL_I845_ERRSTS      0xc8
-
-/* Intel i860 registers */
-#define INTEL_I860_MCHCFG      0x50
-#define INTEL_I860_ERRSTS      0xc8
-
-/* Intel i810 registers */
-#define I810_GMADDR            0x10
-#define I810_MMADDR            0x14
-#define I810_PTE_BASE          0x10000
-#define I810_PTE_MAIN_UNCACHED 0x00000000
-#define I810_PTE_LOCAL         0x00000002
-#define I810_PTE_VALID         0x00000001
-#define I830_PTE_SYSTEM_CACHED  0x00000006
-#define I810_SMRAM_MISCC       0x70
-#define I810_GFX_MEM_WIN_SIZE  0x00010000
-#define I810_GFX_MEM_WIN_32M   0x00010000
-#define I810_GMS               0x000000c0
-#define I810_GMS_DISABLE       0x00000000
-#define I810_PGETBL_CTL                0x2020
-#define I810_PGETBL_ENABLED    0x00000001
-#define I965_PGETBL_SIZE_MASK  0x0000000e
-#define I965_PGETBL_SIZE_512KB (0 << 1)
-#define I965_PGETBL_SIZE_256KB (1 << 1)
-#define I965_PGETBL_SIZE_128KB (2 << 1)
-#define I965_PGETBL_SIZE_1MB   (3 << 1)
-#define I965_PGETBL_SIZE_2MB   (4 << 1)
-#define I965_PGETBL_SIZE_1_5MB (5 << 1)
-#define G33_PGETBL_SIZE_MASK    (3 << 8)
-#define G33_PGETBL_SIZE_1M      (1 << 8)
-#define G33_PGETBL_SIZE_2M      (2 << 8)
-
-#define I810_DRAM_CTL          0x3000
-#define I810_DRAM_ROW_0                0x00000001
-#define I810_DRAM_ROW_0_SDRAM  0x00000001
-
 struct agp_device_ids {
        unsigned short device_id; /* first, to make table easier to read */
        enum chipset_type chipset;
index 793f39e..aa109cb 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/page-flags.h>
 #include <linux/mm.h>
 #include "agp.h"
+#include "intel-agp.h"
 
 /*
  * The real differences to the generic AGP code is
index aa4248e..07a9aad 100644 (file)
 #include <linux/agp_backend.h>
 #include <asm/smp.h>
 #include "agp.h"
+#include "intel-agp.h"
 
-int intel_agp_enabled;
-EXPORT_SYMBOL(intel_agp_enabled);
-
-/*
- * If we have Intel graphics, we're not going to have anything other than
- * an Intel IOMMU. So make the correct use of the PCI DMA API contingent
- * on the Intel IOMMU support (CONFIG_DMAR).
- * Only newer chipsets need to bother with this, of course.
- */
-#ifdef CONFIG_DMAR
-#define USE_PCI_DMA_API 1
-#endif
-
-#define PCI_DEVICE_ID_INTEL_E7221_HB   0x2588
-#define PCI_DEVICE_ID_INTEL_E7221_IG   0x258a
-#define PCI_DEVICE_ID_INTEL_82946GZ_HB      0x2970
-#define PCI_DEVICE_ID_INTEL_82946GZ_IG      0x2972
-#define PCI_DEVICE_ID_INTEL_82G35_HB     0x2980
-#define PCI_DEVICE_ID_INTEL_82G35_IG     0x2982
-#define PCI_DEVICE_ID_INTEL_82965Q_HB       0x2990
-#define PCI_DEVICE_ID_INTEL_82965Q_IG       0x2992
-#define PCI_DEVICE_ID_INTEL_82965G_HB       0x29A0
-#define PCI_DEVICE_ID_INTEL_82965G_IG       0x29A2
-#define PCI_DEVICE_ID_INTEL_82965GM_HB      0x2A00
-#define PCI_DEVICE_ID_INTEL_82965GM_IG      0x2A02
-#define PCI_DEVICE_ID_INTEL_82965GME_HB     0x2A10
-#define PCI_DEVICE_ID_INTEL_82965GME_IG     0x2A12
-#define PCI_DEVICE_ID_INTEL_82945GME_HB     0x27AC
-#define PCI_DEVICE_ID_INTEL_82945GME_IG     0x27AE
-#define PCI_DEVICE_ID_INTEL_PINEVIEW_M_HB        0xA010
-#define PCI_DEVICE_ID_INTEL_PINEVIEW_M_IG        0xA011
-#define PCI_DEVICE_ID_INTEL_PINEVIEW_HB         0xA000
-#define PCI_DEVICE_ID_INTEL_PINEVIEW_IG         0xA001
-#define PCI_DEVICE_ID_INTEL_G33_HB          0x29C0
-#define PCI_DEVICE_ID_INTEL_G33_IG          0x29C2
-#define PCI_DEVICE_ID_INTEL_Q35_HB          0x29B0
-#define PCI_DEVICE_ID_INTEL_Q35_IG          0x29B2
-#define PCI_DEVICE_ID_INTEL_Q33_HB          0x29D0
-#define PCI_DEVICE_ID_INTEL_Q33_IG          0x29D2
-#define PCI_DEVICE_ID_INTEL_B43_HB          0x2E40
-#define PCI_DEVICE_ID_INTEL_B43_IG          0x2E42
-#define PCI_DEVICE_ID_INTEL_GM45_HB         0x2A40
-#define PCI_DEVICE_ID_INTEL_GM45_IG         0x2A42
-#define PCI_DEVICE_ID_INTEL_EAGLELAKE_HB        0x2E00
-#define PCI_DEVICE_ID_INTEL_EAGLELAKE_IG        0x2E02
-#define PCI_DEVICE_ID_INTEL_Q45_HB          0x2E10
-#define PCI_DEVICE_ID_INTEL_Q45_IG          0x2E12
-#define PCI_DEVICE_ID_INTEL_G45_HB          0x2E20
-#define PCI_DEVICE_ID_INTEL_G45_IG          0x2E22
-#define PCI_DEVICE_ID_INTEL_G41_HB          0x2E30
-#define PCI_DEVICE_ID_INTEL_G41_IG          0x2E32
-#define PCI_DEVICE_ID_INTEL_IRONLAKE_D_HB          0x0040
-#define PCI_DEVICE_ID_INTEL_IRONLAKE_D_IG          0x0042
-#define PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB          0x0044
-#define PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB         0x0062
-#define PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB    0x006a
-#define PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG          0x0046
-#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB  0x0100
-#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_IG  0x0102
-#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB  0x0104
-#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_IG  0x0106
-
-/* cover 915 and 945 variants */
-#define IS_I915 (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_E7221_HB || \
-                agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915G_HB || \
-                agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB || \
-                agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945G_HB || \
-                agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GM_HB || \
-                agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GME_HB)
-
-#define IS_I965 (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82946GZ_HB || \
-                agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82G35_HB || \
-                agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965Q_HB || \
-                agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965G_HB || \
-                agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965GM_HB || \
-                agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965GME_HB)
-
-#define IS_G33 (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_G33_HB || \
-               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_Q35_HB || \
-               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_Q33_HB || \
-               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_PINEVIEW_M_HB || \
-               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_PINEVIEW_HB)
-
-#define IS_PINEVIEW (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_PINEVIEW_M_HB || \
-               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_PINEVIEW_HB)
-
-#define IS_SNB (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB || \
-               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB)
-
-#define IS_G4X (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_EAGLELAKE_HB || \
-               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_Q45_HB || \
-               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_G45_HB || \
-               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_GM45_HB || \
-               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_G41_HB || \
-               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_B43_HB || \
-               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IRONLAKE_D_HB || \
-               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB || \
-               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB || \
-               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB || \
-               IS_SNB)
-
-extern int agp_memory_reserved;
-
-
-/* Intel 815 register */
-#define INTEL_815_APCONT       0x51
-#define INTEL_815_ATTBASE_MASK ~0x1FFFFFFF
-
-/* Intel i820 registers */
-#define INTEL_I820_RDCR                0x51
-#define INTEL_I820_ERRSTS      0xc8
-
-/* Intel i840 registers */
-#define INTEL_I840_MCHCFG      0x50
-#define INTEL_I840_ERRSTS      0xc8
-
-/* Intel i850 registers */
-#define INTEL_I850_MCHCFG      0x50
-#define INTEL_I850_ERRSTS      0xc8
-
-/* intel 915G registers */
-#define I915_GMADDR    0x18
-#define I915_MMADDR    0x10
-#define I915_PTEADDR   0x1C
-#define I915_GMCH_GMS_STOLEN_48M       (0x6 << 4)
-#define I915_GMCH_GMS_STOLEN_64M       (0x7 << 4)
-#define G33_GMCH_GMS_STOLEN_128M       (0x8 << 4)
-#define G33_GMCH_GMS_STOLEN_256M       (0x9 << 4)
-#define INTEL_GMCH_GMS_STOLEN_96M      (0xa << 4)
-#define INTEL_GMCH_GMS_STOLEN_160M     (0xb << 4)
-#define INTEL_GMCH_GMS_STOLEN_224M     (0xc << 4)
-#define INTEL_GMCH_GMS_STOLEN_352M     (0xd << 4)
-
-#define I915_IFPADDR    0x60
-
-/* Intel 965G registers */
-#define I965_MSAC 0x62
-#define I965_IFPADDR    0x70
-
-/* Intel 7505 registers */
-#define INTEL_I7505_APSIZE     0x74
-#define INTEL_I7505_NCAPID     0x60
-#define INTEL_I7505_NISTAT     0x6c
-#define INTEL_I7505_ATTBASE    0x78
-#define INTEL_I7505_ERRSTS     0x42
-#define INTEL_I7505_AGPCTRL    0x70
-#define INTEL_I7505_MCHCFG     0x50
-
-#define SNB_GMCH_CTRL  0x50
-#define SNB_GMCH_GMS_STOLEN_MASK       0xF8
-#define SNB_GMCH_GMS_STOLEN_32M                (1 << 3)
-#define SNB_GMCH_GMS_STOLEN_64M                (2 << 3)
-#define SNB_GMCH_GMS_STOLEN_96M                (3 << 3)
-#define SNB_GMCH_GMS_STOLEN_128M       (4 << 3)
-#define SNB_GMCH_GMS_STOLEN_160M       (5 << 3)
-#define SNB_GMCH_GMS_STOLEN_192M       (6 << 3)
-#define SNB_GMCH_GMS_STOLEN_224M       (7 << 3)
-#define SNB_GMCH_GMS_STOLEN_256M       (8 << 3)
-#define SNB_GMCH_GMS_STOLEN_288M       (9 << 3)
-#define SNB_GMCH_GMS_STOLEN_320M       (0xa << 3)
-#define SNB_GMCH_GMS_STOLEN_352M       (0xb << 3)
-#define SNB_GMCH_GMS_STOLEN_384M       (0xc << 3)
-#define SNB_GMCH_GMS_STOLEN_416M       (0xd << 3)
-#define SNB_GMCH_GMS_STOLEN_448M       (0xe << 3)
-#define SNB_GMCH_GMS_STOLEN_480M       (0xf << 3)
-#define SNB_GMCH_GMS_STOLEN_512M       (0x10 << 3)
-#define SNB_GTT_SIZE_0M                        (0 << 8)
-#define SNB_GTT_SIZE_1M                        (1 << 8)
-#define SNB_GTT_SIZE_2M                        (2 << 8)
-#define SNB_GTT_SIZE_MASK              (3 << 8)
-
-static const struct aper_size_info_fixed intel_i810_sizes[] =
-{
-       {64, 16384, 4},
-       /* The 32M mode still requires a 64k gatt */
-       {32, 8192, 4}
-};
-
-#define AGP_DCACHE_MEMORY      1
-#define AGP_PHYS_MEMORY                2
-#define INTEL_AGP_CACHED_MEMORY 3
-
-static struct gatt_mask intel_i810_masks[] =
-{
-       {.mask = I810_PTE_VALID, .type = 0},
-       {.mask = (I810_PTE_VALID | I810_PTE_LOCAL), .type = AGP_DCACHE_MEMORY},
-       {.mask = I810_PTE_VALID, .type = 0},
-       {.mask = I810_PTE_VALID | I830_PTE_SYSTEM_CACHED,
-        .type = INTEL_AGP_CACHED_MEMORY}
-};
-
-static struct _intel_private {
-       struct pci_dev *pcidev; /* device one */
-       u8 __iomem *registers;
-       u32 __iomem *gtt;               /* I915G */
-       int num_dcache_entries;
-       /* gtt_entries is the number of gtt entries that are already mapped
-        * to stolen memory.  Stolen memory is larger than the memory mapped
-        * through gtt_entries, as it includes some reserved space for the BIOS
-        * popup and for the GTT.
-        */
-       int gtt_entries;                        /* i830+ */
-       int gtt_total_size;
-       union {
-               void __iomem *i9xx_flush_page;
-               void *i8xx_flush_page;
-       };
-       struct page *i8xx_page;
-       struct resource ifp_resource;
-       int resource_valid;
-} intel_private;
-
-#ifdef USE_PCI_DMA_API
-static int intel_agp_map_page(struct page *page, dma_addr_t *ret)
-{
-       *ret = pci_map_page(intel_private.pcidev, page, 0,
-                           PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
-       if (pci_dma_mapping_error(intel_private.pcidev, *ret))
-               return -EINVAL;
-       return 0;
-}
-
-static void intel_agp_unmap_page(struct page *page, dma_addr_t dma)
-{
-       pci_unmap_page(intel_private.pcidev, dma,
-                      PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
-}
-
-static void intel_agp_free_sglist(struct agp_memory *mem)
-{
-       struct sg_table st;
-
-       st.sgl = mem->sg_list;
-       st.orig_nents = st.nents = mem->page_count;
-
-       sg_free_table(&st);
-
-       mem->sg_list = NULL;
-       mem->num_sg = 0;
-}
-
-static int intel_agp_map_memory(struct agp_memory *mem)
-{
-       struct sg_table st;
-       struct scatterlist *sg;
-       int i;
-
-       DBG("try mapping %lu pages\n", (unsigned long)mem->page_count);
-
-       if (sg_alloc_table(&st, mem->page_count, GFP_KERNEL))
-               return -ENOMEM;
-
-       mem->sg_list = sg = st.sgl;
-
-       for (i = 0 ; i < mem->page_count; i++, sg = sg_next(sg))
-               sg_set_page(sg, mem->pages[i], PAGE_SIZE, 0);
-
-       mem->num_sg = pci_map_sg(intel_private.pcidev, mem->sg_list,
-                                mem->page_count, PCI_DMA_BIDIRECTIONAL);
-       if (unlikely(!mem->num_sg)) {
-               intel_agp_free_sglist(mem);
-               return -ENOMEM;
-       }
-       return 0;
-}
-
-static void intel_agp_unmap_memory(struct agp_memory *mem)
-{
-       DBG("try unmapping %lu pages\n", (unsigned long)mem->page_count);
-
-       pci_unmap_sg(intel_private.pcidev, mem->sg_list,
-                    mem->page_count, PCI_DMA_BIDIRECTIONAL);
-       intel_agp_free_sglist(mem);
-}
-
-static void intel_agp_insert_sg_entries(struct agp_memory *mem,
-                                       off_t pg_start, int mask_type)
-{
-       struct scatterlist *sg;
-       int i, j;
-
-       j = pg_start;
-
-       WARN_ON(!mem->num_sg);
-
-       if (mem->num_sg == mem->page_count) {
-               for_each_sg(mem->sg_list, sg, mem->page_count, i) {
-                       writel(agp_bridge->driver->mask_memory(agp_bridge,
-                                       sg_dma_address(sg), mask_type),
-                                       intel_private.gtt+j);
-                       j++;
-               }
-       } else {
-               /* sg may merge pages, but we have to separate
-                * per-page addr for GTT */
-               unsigned int len, m;
-
-               for_each_sg(mem->sg_list, sg, mem->num_sg, i) {
-                       len = sg_dma_len(sg) / PAGE_SIZE;
-                       for (m = 0; m < len; m++) {
-                               writel(agp_bridge->driver->mask_memory(agp_bridge,
-                                                                      sg_dma_address(sg) + m * PAGE_SIZE,
-                                                                      mask_type),
-                                      intel_private.gtt+j);
-                               j++;
-                       }
-               }
-       }
-       readl(intel_private.gtt+j-1);
-}
-
-#else
-
-static void intel_agp_insert_sg_entries(struct agp_memory *mem,
-                                       off_t pg_start, int mask_type)
-{
-       int i, j;
-       u32 cache_bits = 0;
-
-       if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB ||
-           agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB)
-       {
-               cache_bits = I830_PTE_SYSTEM_CACHED;
-       }
-
-       for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
-               writel(agp_bridge->driver->mask_memory(agp_bridge,
-                               page_to_phys(mem->pages[i]), mask_type),
-                      intel_private.gtt+j);
-       }
-
-       readl(intel_private.gtt+j-1);
-}
-
-#endif
-
-static int intel_i810_fetch_size(void)
-{
-       u32 smram_miscc;
-       struct aper_size_info_fixed *values;
-
-       pci_read_config_dword(agp_bridge->dev, I810_SMRAM_MISCC, &smram_miscc);
-       values = A_SIZE_FIX(agp_bridge->driver->aperture_sizes);
-
-       if ((smram_miscc & I810_GMS) == I810_GMS_DISABLE) {
-               dev_warn(&agp_bridge->dev->dev, "i810 is disabled\n");
-               return 0;
-       }
-       if ((smram_miscc & I810_GFX_MEM_WIN_SIZE) == I810_GFX_MEM_WIN_32M) {
-               agp_bridge->previous_size =
-                       agp_bridge->current_size = (void *) (values + 1);
-               agp_bridge->aperture_size_idx = 1;
-               return values[1].size;
-       } else {
-               agp_bridge->previous_size =
-                       agp_bridge->current_size = (void *) (values);
-               agp_bridge->aperture_size_idx = 0;
-               return values[0].size;
-       }
-
-       return 0;
-}
-
-static int intel_i810_configure(void)
-{
-       struct aper_size_info_fixed *current_size;
-       u32 temp;
-       int i;
-
-       current_size = A_SIZE_FIX(agp_bridge->current_size);
-
-       if (!intel_private.registers) {
-               pci_read_config_dword(intel_private.pcidev, I810_MMADDR, &temp);
-               temp &= 0xfff80000;
-
-               intel_private.registers = ioremap(temp, 128 * 4096);
-               if (!intel_private.registers) {
-                       dev_err(&intel_private.pcidev->dev,
-                               "can't remap memory\n");
-                       return -ENOMEM;
-               }
-       }
-
-       if ((readl(intel_private.registers+I810_DRAM_CTL)
-               & I810_DRAM_ROW_0) == I810_DRAM_ROW_0_SDRAM) {
-               /* This will need to be dynamically assigned */
-               dev_info(&intel_private.pcidev->dev,
-                        "detected 4MB dedicated video ram\n");
-               intel_private.num_dcache_entries = 1024;
-       }
-       pci_read_config_dword(intel_private.pcidev, I810_GMADDR, &temp);
-       agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
-       writel(agp_bridge->gatt_bus_addr | I810_PGETBL_ENABLED, intel_private.registers+I810_PGETBL_CTL);
-       readl(intel_private.registers+I810_PGETBL_CTL); /* PCI Posting. */
-
-       if (agp_bridge->driver->needs_scratch_page) {
-               for (i = 0; i < current_size->num_entries; i++) {
-                       writel(agp_bridge->scratch_page, intel_private.registers+I810_PTE_BASE+(i*4));
-               }
-               readl(intel_private.registers+I810_PTE_BASE+((i-1)*4)); /* PCI posting. */
-       }
-       global_cache_flush();
-       return 0;
-}
-
-static void intel_i810_cleanup(void)
-{
-       writel(0, intel_private.registers+I810_PGETBL_CTL);
-       readl(intel_private.registers); /* PCI Posting. */
-       iounmap(intel_private.registers);
-}
-
-static void intel_i810_tlbflush(struct agp_memory *mem)
-{
-       return;
-}
-
-static void intel_i810_agp_enable(struct agp_bridge_data *bridge, u32 mode)
-{
-       return;
-}
-
-/* Exists to support ARGB cursors */
-static struct page *i8xx_alloc_pages(void)
-{
-       struct page *page;
-
-       page = alloc_pages(GFP_KERNEL | GFP_DMA32, 2);
-       if (page == NULL)
-               return NULL;
-
-       if (set_pages_uc(page, 4) < 0) {
-               set_pages_wb(page, 4);
-               __free_pages(page, 2);
-               return NULL;
-       }
-       get_page(page);
-       atomic_inc(&agp_bridge->current_memory_agp);
-       return page;
-}
-
-static void i8xx_destroy_pages(struct page *page)
-{
-       if (page == NULL)
-               return;
-
-       set_pages_wb(page, 4);
-       put_page(page);
-       __free_pages(page, 2);
-       atomic_dec(&agp_bridge->current_memory_agp);
-}
-
-static int intel_i830_type_to_mask_type(struct agp_bridge_data *bridge,
-                                       int type)
-{
-       if (type < AGP_USER_TYPES)
-               return type;
-       else if (type == AGP_USER_CACHED_MEMORY)
-               return INTEL_AGP_CACHED_MEMORY;
-       else
-               return 0;
-}
-
-static int intel_i810_insert_entries(struct agp_memory *mem, off_t pg_start,
-                               int type)
-{
-       int i, j, num_entries;
-       void *temp;
-       int ret = -EINVAL;
-       int mask_type;
-
-       if (mem->page_count == 0)
-               goto out;
-
-       temp = agp_bridge->current_size;
-       num_entries = A_SIZE_FIX(temp)->num_entries;
-
-       if ((pg_start + mem->page_count) > num_entries)
-               goto out_err;
-
-
-       for (j = pg_start; j < (pg_start + mem->page_count); j++) {
-               if (!PGE_EMPTY(agp_bridge, readl(agp_bridge->gatt_table+j))) {
-                       ret = -EBUSY;
-                       goto out_err;
-               }
-       }
-
-       if (type != mem->type)
-               goto out_err;
-
-       mask_type = agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type);
-
-       switch (mask_type) {
-       case AGP_DCACHE_MEMORY:
-               if (!mem->is_flushed)
-                       global_cache_flush();
-               for (i = pg_start; i < (pg_start + mem->page_count); i++) {
-                       writel((i*4096)|I810_PTE_LOCAL|I810_PTE_VALID,
-                              intel_private.registers+I810_PTE_BASE+(i*4));
-               }
-               readl(intel_private.registers+I810_PTE_BASE+((i-1)*4));
-               break;
-       case AGP_PHYS_MEMORY:
-       case AGP_NORMAL_MEMORY:
-               if (!mem->is_flushed)
-                       global_cache_flush();
-               for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
-                       writel(agp_bridge->driver->mask_memory(agp_bridge,
-                                       page_to_phys(mem->pages[i]), mask_type),
-                              intel_private.registers+I810_PTE_BASE+(j*4));
-               }
-               readl(intel_private.registers+I810_PTE_BASE+((j-1)*4));
-               break;
-       default:
-               goto out_err;
-       }
-
-       agp_bridge->driver->tlb_flush(mem);
-out:
-       ret = 0;
-out_err:
-       mem->is_flushed = true;
-       return ret;
-}
-
-static int intel_i810_remove_entries(struct agp_memory *mem, off_t pg_start,
-                               int type)
-{
-       int i;
-
-       if (mem->page_count == 0)
-               return 0;
-
-       for (i = pg_start; i < (mem->page_count + pg_start); i++) {
-               writel(agp_bridge->scratch_page, intel_private.registers+I810_PTE_BASE+(i*4));
-       }
-       readl(intel_private.registers+I810_PTE_BASE+((i-1)*4));
-
-       agp_bridge->driver->tlb_flush(mem);
-       return 0;
-}
-
-/*
- * The i810/i830 requires a physical address to program its mouse
- * pointer into hardware.
- * However the Xserver still writes to it through the agp aperture.
- */
-static struct agp_memory *alloc_agpphysmem_i8xx(size_t pg_count, int type)
-{
-       struct agp_memory *new;
-       struct page *page;
-
-       switch (pg_count) {
-       case 1: page = agp_bridge->driver->agp_alloc_page(agp_bridge);
-               break;
-       case 4:
-               /* kludge to get 4 physical pages for ARGB cursor */
-               page = i8xx_alloc_pages();
-               break;
-       default:
-               return NULL;
-       }
-
-       if (page == NULL)
-               return NULL;
-
-       new = agp_create_memory(pg_count);
-       if (new == NULL)
-               return NULL;
-
-       new->pages[0] = page;
-       if (pg_count == 4) {
-               /* kludge to get 4 physical pages for ARGB cursor */
-               new->pages[1] = new->pages[0] + 1;
-               new->pages[2] = new->pages[1] + 1;
-               new->pages[3] = new->pages[2] + 1;
-       }
-       new->page_count = pg_count;
-       new->num_scratch_pages = pg_count;
-       new->type = AGP_PHYS_MEMORY;
-       new->physical = page_to_phys(new->pages[0]);
-       return new;
-}
-
-static struct agp_memory *intel_i810_alloc_by_type(size_t pg_count, int type)
-{
-       struct agp_memory *new;
-
-       if (type == AGP_DCACHE_MEMORY) {
-               if (pg_count != intel_private.num_dcache_entries)
-                       return NULL;
-
-               new = agp_create_memory(1);
-               if (new == NULL)
-                       return NULL;
-
-               new->type = AGP_DCACHE_MEMORY;
-               new->page_count = pg_count;
-               new->num_scratch_pages = 0;
-               agp_free_page_array(new);
-               return new;
-       }
-       if (type == AGP_PHYS_MEMORY)
-               return alloc_agpphysmem_i8xx(pg_count, type);
-       return NULL;
-}
-
-static void intel_i810_free_by_type(struct agp_memory *curr)
-{
-       agp_free_key(curr->key);
-       if (curr->type == AGP_PHYS_MEMORY) {
-               if (curr->page_count == 4)
-                       i8xx_destroy_pages(curr->pages[0]);
-               else {
-                       agp_bridge->driver->agp_destroy_page(curr->pages[0],
-                                                            AGP_PAGE_DESTROY_UNMAP);
-                       agp_bridge->driver->agp_destroy_page(curr->pages[0],
-                                                            AGP_PAGE_DESTROY_FREE);
-               }
-               agp_free_page_array(curr);
-       }
-       kfree(curr);
-}
-
-static unsigned long intel_i810_mask_memory(struct agp_bridge_data *bridge,
-                                           dma_addr_t addr, int type)
-{
-       /* Type checking must be done elsewhere */
-       return addr | bridge->driver->masks[type].mask;
-}
-
-static struct aper_size_info_fixed intel_i830_sizes[] =
-{
-       {128, 32768, 5},
-       /* The 64M mode still requires a 128k gatt */
-       {64, 16384, 5},
-       {256, 65536, 6},
-       {512, 131072, 7},
-};
-
-static void intel_i830_init_gtt_entries(void)
-{
-       u16 gmch_ctrl;
-       int gtt_entries = 0;
-       u8 rdct;
-       int local = 0;
-       static const int ddt[4] = { 0, 16, 32, 64 };
-       int size; /* reserved space (in kb) at the top of stolen memory */
-
-       pci_read_config_word(agp_bridge->dev, I830_GMCH_CTRL, &gmch_ctrl);
-
-       if (IS_I965) {
-               u32 pgetbl_ctl;
-               pgetbl_ctl = readl(intel_private.registers+I810_PGETBL_CTL);
-
-               /* The 965 has a field telling us the size of the GTT,
-                * which may be larger than what is necessary to map the
-                * aperture.
-                */
-               switch (pgetbl_ctl & I965_PGETBL_SIZE_MASK) {
-               case I965_PGETBL_SIZE_128KB:
-                       size = 128;
-                       break;
-               case I965_PGETBL_SIZE_256KB:
-                       size = 256;
-                       break;
-               case I965_PGETBL_SIZE_512KB:
-                       size = 512;
-                       break;
-               case I965_PGETBL_SIZE_1MB:
-                       size = 1024;
-                       break;
-               case I965_PGETBL_SIZE_2MB:
-                       size = 2048;
-                       break;
-               case I965_PGETBL_SIZE_1_5MB:
-                       size = 1024 + 512;
-                       break;
-               default:
-                       dev_info(&intel_private.pcidev->dev,
-                                "unknown page table size, assuming 512KB\n");
-                       size = 512;
-               }
-               size += 4; /* add in BIOS popup space */
-       } else if (IS_G33 && !IS_PINEVIEW) {
-       /* G33's GTT size defined in gmch_ctrl */
-               switch (gmch_ctrl & G33_PGETBL_SIZE_MASK) {
-               case G33_PGETBL_SIZE_1M:
-                       size = 1024;
-                       break;
-               case G33_PGETBL_SIZE_2M:
-                       size = 2048;
-                       break;
-               default:
-                       dev_info(&agp_bridge->dev->dev,
-                                "unknown page table size 0x%x, assuming 512KB\n",
-                               (gmch_ctrl & G33_PGETBL_SIZE_MASK));
-                       size = 512;
-               }
-               size += 4;
-       } else if (IS_G4X || IS_PINEVIEW) {
-               /* On 4 series hardware, GTT stolen is separate from graphics
-                * stolen, ignore it in stolen gtt entries counting.  However,
-                * 4KB of the stolen memory doesn't get mapped to the GTT.
-                */
-               size = 4;
-       } else {
-               /* On previous hardware, the GTT size was just what was
-                * required to map the aperture.
-                */
-               size = agp_bridge->driver->fetch_size() + 4;
-       }
-
-       if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82830_HB ||
-           agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82845G_HB) {
-               switch (gmch_ctrl & I830_GMCH_GMS_MASK) {
-               case I830_GMCH_GMS_STOLEN_512:
-                       gtt_entries = KB(512) - KB(size);
-                       break;
-               case I830_GMCH_GMS_STOLEN_1024:
-                       gtt_entries = MB(1) - KB(size);
-                       break;
-               case I830_GMCH_GMS_STOLEN_8192:
-                       gtt_entries = MB(8) - KB(size);
-                       break;
-               case I830_GMCH_GMS_LOCAL:
-                       rdct = readb(intel_private.registers+I830_RDRAM_CHANNEL_TYPE);
-                       gtt_entries = (I830_RDRAM_ND(rdct) + 1) *
-                                       MB(ddt[I830_RDRAM_DDT(rdct)]);
-                       local = 1;
-                       break;
-               default:
-                       gtt_entries = 0;
-                       break;
-               }
-       } else if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB ||
-                  agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB) {
-               /*
-                * SandyBridge has new memory control reg at 0x50.w
-                */
-               u16 snb_gmch_ctl;
-               pci_read_config_word(intel_private.pcidev, SNB_GMCH_CTRL, &snb_gmch_ctl);
-               switch (snb_gmch_ctl & SNB_GMCH_GMS_STOLEN_MASK) {
-               case SNB_GMCH_GMS_STOLEN_32M:
-                       gtt_entries = MB(32) - KB(size);
-                       break;
-               case SNB_GMCH_GMS_STOLEN_64M:
-                       gtt_entries = MB(64) - KB(size);
-                       break;
-               case SNB_GMCH_GMS_STOLEN_96M:
-                       gtt_entries = MB(96) - KB(size);
-                       break;
-               case SNB_GMCH_GMS_STOLEN_128M:
-                       gtt_entries = MB(128) - KB(size);
-                       break;
-               case SNB_GMCH_GMS_STOLEN_160M:
-                       gtt_entries = MB(160) - KB(size);
-                       break;
-               case SNB_GMCH_GMS_STOLEN_192M:
-                       gtt_entries = MB(192) - KB(size);
-                       break;
-               case SNB_GMCH_GMS_STOLEN_224M:
-                       gtt_entries = MB(224) - KB(size);
-                       break;
-               case SNB_GMCH_GMS_STOLEN_256M:
-                       gtt_entries = MB(256) - KB(size);
-                       break;
-               case SNB_GMCH_GMS_STOLEN_288M:
-                       gtt_entries = MB(288) - KB(size);
-                       break;
-               case SNB_GMCH_GMS_STOLEN_320M:
-                       gtt_entries = MB(320) - KB(size);
-                       break;
-               case SNB_GMCH_GMS_STOLEN_352M:
-                       gtt_entries = MB(352) - KB(size);
-                       break;
-               case SNB_GMCH_GMS_STOLEN_384M:
-                       gtt_entries = MB(384) - KB(size);
-                       break;
-               case SNB_GMCH_GMS_STOLEN_416M:
-                       gtt_entries = MB(416) - KB(size);
-                       break;
-               case SNB_GMCH_GMS_STOLEN_448M:
-                       gtt_entries = MB(448) - KB(size);
-                       break;
-               case SNB_GMCH_GMS_STOLEN_480M:
-                       gtt_entries = MB(480) - KB(size);
-                       break;
-               case SNB_GMCH_GMS_STOLEN_512M:
-                       gtt_entries = MB(512) - KB(size);
-                       break;
-               }
-       } else {
-               switch (gmch_ctrl & I855_GMCH_GMS_MASK) {
-               case I855_GMCH_GMS_STOLEN_1M:
-                       gtt_entries = MB(1) - KB(size);
-                       break;
-               case I855_GMCH_GMS_STOLEN_4M:
-                       gtt_entries = MB(4) - KB(size);
-                       break;
-               case I855_GMCH_GMS_STOLEN_8M:
-                       gtt_entries = MB(8) - KB(size);
-                       break;
-               case I855_GMCH_GMS_STOLEN_16M:
-                       gtt_entries = MB(16) - KB(size);
-                       break;
-               case I855_GMCH_GMS_STOLEN_32M:
-                       gtt_entries = MB(32) - KB(size);
-                       break;
-               case I915_GMCH_GMS_STOLEN_48M:
-                       /* Check it's really I915G */
-                       if (IS_I915 || IS_I965 || IS_G33 || IS_G4X)
-                               gtt_entries = MB(48) - KB(size);
-                       else
-                               gtt_entries = 0;
-                       break;
-               case I915_GMCH_GMS_STOLEN_64M:
-                       /* Check it's really I915G */
-                       if (IS_I915 || IS_I965 || IS_G33 || IS_G4X)
-                               gtt_entries = MB(64) - KB(size);
-                       else
-                               gtt_entries = 0;
-                       break;
-               case G33_GMCH_GMS_STOLEN_128M:
-                       if (IS_G33 || IS_I965 || IS_G4X)
-                               gtt_entries = MB(128) - KB(size);
-                       else
-                               gtt_entries = 0;
-                       break;
-               case G33_GMCH_GMS_STOLEN_256M:
-                       if (IS_G33 || IS_I965 || IS_G4X)
-                               gtt_entries = MB(256) - KB(size);
-                       else
-                               gtt_entries = 0;
-                       break;
-               case INTEL_GMCH_GMS_STOLEN_96M:
-                       if (IS_I965 || IS_G4X)
-                               gtt_entries = MB(96) - KB(size);
-                       else
-                               gtt_entries = 0;
-                       break;
-               case INTEL_GMCH_GMS_STOLEN_160M:
-                       if (IS_I965 || IS_G4X)
-                               gtt_entries = MB(160) - KB(size);
-                       else
-                               gtt_entries = 0;
-                       break;
-               case INTEL_GMCH_GMS_STOLEN_224M:
-                       if (IS_I965 || IS_G4X)
-                               gtt_entries = MB(224) - KB(size);
-                       else
-                               gtt_entries = 0;
-                       break;
-               case INTEL_GMCH_GMS_STOLEN_352M:
-                       if (IS_I965 || IS_G4X)
-                               gtt_entries = MB(352) - KB(size);
-                       else
-                               gtt_entries = 0;
-                       break;
-               default:
-                       gtt_entries = 0;
-                       break;
-               }
-       }
-       if (gtt_entries > 0) {
-               dev_info(&agp_bridge->dev->dev, "detected %dK %s memory\n",
-                      gtt_entries / KB(1), local ? "local" : "stolen");
-               gtt_entries /= KB(4);
-       } else {
-               dev_info(&agp_bridge->dev->dev,
-                      "no pre-allocated video memory detected\n");
-               gtt_entries = 0;
-       }
-
-       intel_private.gtt_entries = gtt_entries;
-}
-
-static void intel_i830_fini_flush(void)
-{
-       kunmap(intel_private.i8xx_page);
-       intel_private.i8xx_flush_page = NULL;
-       unmap_page_from_agp(intel_private.i8xx_page);
-
-       __free_page(intel_private.i8xx_page);
-       intel_private.i8xx_page = NULL;
-}
-
-static void intel_i830_setup_flush(void)
-{
-       /* return if we've already set the flush mechanism up */
-       if (intel_private.i8xx_page)
-               return;
-
-       intel_private.i8xx_page = alloc_page(GFP_KERNEL | __GFP_ZERO | GFP_DMA32);
-       if (!intel_private.i8xx_page)
-               return;
-
-       intel_private.i8xx_flush_page = kmap(intel_private.i8xx_page);
-       if (!intel_private.i8xx_flush_page)
-               intel_i830_fini_flush();
-}
-
-/* The chipset_flush interface needs to get data that has already been
- * flushed out of the CPU all the way out to main memory, because the GPU
- * doesn't snoop those buffers.
- *
- * The 8xx series doesn't have the same lovely interface for flushing the
- * chipset write buffers that the later chips do. According to the 865
- * specs, it's 64 octwords, or 1KB.  So, to get those previous things in
- * that buffer out, we just fill 1KB and clflush it out, on the assumption
- * that it'll push whatever was in there out.  It appears to work.
- */
-static void intel_i830_chipset_flush(struct agp_bridge_data *bridge)
-{
-       unsigned int *pg = intel_private.i8xx_flush_page;
-
-       memset(pg, 0, 1024);
-
-       if (cpu_has_clflush)
-               clflush_cache_range(pg, 1024);
-       else if (wbinvd_on_all_cpus() != 0)
-               printk(KERN_ERR "Timed out waiting for cache flush.\n");
-}
-
-/* The intel i830 automatically initializes the agp aperture during POST.
- * Use the memory already set aside for in the GTT.
- */
-static int intel_i830_create_gatt_table(struct agp_bridge_data *bridge)
-{
-       int page_order;
-       struct aper_size_info_fixed *size;
-       int num_entries;
-       u32 temp;
-
-       size = agp_bridge->current_size;
-       page_order = size->page_order;
-       num_entries = size->num_entries;
-       agp_bridge->gatt_table_real = NULL;
-
-       pci_read_config_dword(intel_private.pcidev, I810_MMADDR, &temp);
-       temp &= 0xfff80000;
-
-       intel_private.registers = ioremap(temp, 128 * 4096);
-       if (!intel_private.registers)
-               return -ENOMEM;
-
-       temp = readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000;
-       global_cache_flush();   /* FIXME: ?? */
-
-       /* we have to call this as early as possible after the MMIO base address is known */
-       intel_i830_init_gtt_entries();
-
-       agp_bridge->gatt_table = NULL;
-
-       agp_bridge->gatt_bus_addr = temp;
-
-       return 0;
-}
-
-/* Return the gatt table to a sane state. Use the top of stolen
- * memory for the GTT.
- */
-static int intel_i830_free_gatt_table(struct agp_bridge_data *bridge)
-{
-       return 0;
-}
-
-static int intel_i830_fetch_size(void)
-{
-       u16 gmch_ctrl;
-       struct aper_size_info_fixed *values;
-
-       values = A_SIZE_FIX(agp_bridge->driver->aperture_sizes);
-
-       if (agp_bridge->dev->device != PCI_DEVICE_ID_INTEL_82830_HB &&
-           agp_bridge->dev->device != PCI_DEVICE_ID_INTEL_82845G_HB) {
-               /* 855GM/852GM/865G has 128MB aperture size */
-               agp_bridge->previous_size = agp_bridge->current_size = (void *) values;
-               agp_bridge->aperture_size_idx = 0;
-               return values[0].size;
-       }
-
-       pci_read_config_word(agp_bridge->dev, I830_GMCH_CTRL, &gmch_ctrl);
-
-       if ((gmch_ctrl & I830_GMCH_MEM_MASK) == I830_GMCH_MEM_128M) {
-               agp_bridge->previous_size = agp_bridge->current_size = (void *) values;
-               agp_bridge->aperture_size_idx = 0;
-               return values[0].size;
-       } else {
-               agp_bridge->previous_size = agp_bridge->current_size = (void *) (values + 1);
-               agp_bridge->aperture_size_idx = 1;
-               return values[1].size;
-       }
-
-       return 0;
-}
-
-static int intel_i830_configure(void)
-{
-       struct aper_size_info_fixed *current_size;
-       u32 temp;
-       u16 gmch_ctrl;
-       int i;
-
-       current_size = A_SIZE_FIX(agp_bridge->current_size);
-
-       pci_read_config_dword(intel_private.pcidev, I810_GMADDR, &temp);
-       agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
-
-       pci_read_config_word(agp_bridge->dev, I830_GMCH_CTRL, &gmch_ctrl);
-       gmch_ctrl |= I830_GMCH_ENABLED;
-       pci_write_config_word(agp_bridge->dev, I830_GMCH_CTRL, gmch_ctrl);
-
-       writel(agp_bridge->gatt_bus_addr|I810_PGETBL_ENABLED, intel_private.registers+I810_PGETBL_CTL);
-       readl(intel_private.registers+I810_PGETBL_CTL); /* PCI Posting. */
-
-       if (agp_bridge->driver->needs_scratch_page) {
-               for (i = intel_private.gtt_entries; i < current_size->num_entries; i++) {
-                       writel(agp_bridge->scratch_page, intel_private.registers+I810_PTE_BASE+(i*4));
-               }
-               readl(intel_private.registers+I810_PTE_BASE+((i-1)*4)); /* PCI Posting. */
-       }
-
-       global_cache_flush();
-
-       intel_i830_setup_flush();
-       return 0;
-}
-
-static void intel_i830_cleanup(void)
-{
-       iounmap(intel_private.registers);
-}
-
-static int intel_i830_insert_entries(struct agp_memory *mem, off_t pg_start,
-                                    int type)
-{
-       int i, j, num_entries;
-       void *temp;
-       int ret = -EINVAL;
-       int mask_type;
-
-       if (mem->page_count == 0)
-               goto out;
-
-       temp = agp_bridge->current_size;
-       num_entries = A_SIZE_FIX(temp)->num_entries;
-
-       if (pg_start < intel_private.gtt_entries) {
-               dev_printk(KERN_DEBUG, &intel_private.pcidev->dev,
-                          "pg_start == 0x%.8lx, intel_private.gtt_entries == 0x%.8x\n",
-                          pg_start, intel_private.gtt_entries);
-
-               dev_info(&intel_private.pcidev->dev,
-                        "trying to insert into local/stolen memory\n");
-               goto out_err;
-       }
-
-       if ((pg_start + mem->page_count) > num_entries)
-               goto out_err;
-
-       /* The i830 can't check the GTT for entries since its read only,
-        * depend on the caller to make the correct offset decisions.
-        */
-
-       if (type != mem->type)
-               goto out_err;
-
-       mask_type = agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type);
-
-       if (mask_type != 0 && mask_type != AGP_PHYS_MEMORY &&
-           mask_type != INTEL_AGP_CACHED_MEMORY)
-               goto out_err;
-
-       if (!mem->is_flushed)
-               global_cache_flush();
-
-       for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
-               writel(agp_bridge->driver->mask_memory(agp_bridge,
-                               page_to_phys(mem->pages[i]), mask_type),
-                      intel_private.registers+I810_PTE_BASE+(j*4));
-       }
-       readl(intel_private.registers+I810_PTE_BASE+((j-1)*4));
-       agp_bridge->driver->tlb_flush(mem);
-
-out:
-       ret = 0;
-out_err:
-       mem->is_flushed = true;
-       return ret;
-}
-
-static int intel_i830_remove_entries(struct agp_memory *mem, off_t pg_start,
-                                    int type)
-{
-       int i;
-
-       if (mem->page_count == 0)
-               return 0;
-
-       if (pg_start < intel_private.gtt_entries) {
-               dev_info(&intel_private.pcidev->dev,
-                        "trying to disable local/stolen memory\n");
-               return -EINVAL;
-       }
-
-       for (i = pg_start; i < (mem->page_count + pg_start); i++) {
-               writel(agp_bridge->scratch_page, intel_private.registers+I810_PTE_BASE+(i*4));
-       }
-       readl(intel_private.registers+I810_PTE_BASE+((i-1)*4));
-
-       agp_bridge->driver->tlb_flush(mem);
-       return 0;
-}
-
-static struct agp_memory *intel_i830_alloc_by_type(size_t pg_count, int type)
-{
-       if (type == AGP_PHYS_MEMORY)
-               return alloc_agpphysmem_i8xx(pg_count, type);
-       /* always return NULL for other allocation types for now */
-       return NULL;
-}
-
-static int intel_alloc_chipset_flush_resource(void)
-{
-       int ret;
-       ret = pci_bus_alloc_resource(agp_bridge->dev->bus, &intel_private.ifp_resource, PAGE_SIZE,
-                                    PAGE_SIZE, PCIBIOS_MIN_MEM, 0,
-                                    pcibios_align_resource, agp_bridge->dev);
-
-       return ret;
-}
-
-static void intel_i915_setup_chipset_flush(void)
-{
-       int ret;
-       u32 temp;
-
-       pci_read_config_dword(agp_bridge->dev, I915_IFPADDR, &temp);
-       if (!(temp & 0x1)) {
-               intel_alloc_chipset_flush_resource();
-               intel_private.resource_valid = 1;
-               pci_write_config_dword(agp_bridge->dev, I915_IFPADDR, (intel_private.ifp_resource.start & 0xffffffff) | 0x1);
-       } else {
-               temp &= ~1;
-
-               intel_private.resource_valid = 1;
-               intel_private.ifp_resource.start = temp;
-               intel_private.ifp_resource.end = temp + PAGE_SIZE;
-               ret = request_resource(&iomem_resource, &intel_private.ifp_resource);
-               /* some BIOSes reserve this area in a pnp some don't */
-               if (ret)
-                       intel_private.resource_valid = 0;
-       }
-}
-
-static void intel_i965_g33_setup_chipset_flush(void)
-{
-       u32 temp_hi, temp_lo;
-       int ret;
-
-       pci_read_config_dword(agp_bridge->dev, I965_IFPADDR + 4, &temp_hi);
-       pci_read_config_dword(agp_bridge->dev, I965_IFPADDR, &temp_lo);
-
-       if (!(temp_lo & 0x1)) {
-
-               intel_alloc_chipset_flush_resource();
-
-               intel_private.resource_valid = 1;
-               pci_write_config_dword(agp_bridge->dev, I965_IFPADDR + 4,
-                       upper_32_bits(intel_private.ifp_resource.start));
-               pci_write_config_dword(agp_bridge->dev, I965_IFPADDR, (intel_private.ifp_resource.start & 0xffffffff) | 0x1);
-       } else {
-               u64 l64;
-
-               temp_lo &= ~0x1;
-               l64 = ((u64)temp_hi << 32) | temp_lo;
-
-               intel_private.resource_valid = 1;
-               intel_private.ifp_resource.start = l64;
-               intel_private.ifp_resource.end = l64 + PAGE_SIZE;
-               ret = request_resource(&iomem_resource, &intel_private.ifp_resource);
-               /* some BIOSes reserve this area in a pnp some don't */
-               if (ret)
-                       intel_private.resource_valid = 0;
-       }
-}
-
-static void intel_i9xx_setup_flush(void)
-{
-       /* return if already configured */
-       if (intel_private.ifp_resource.start)
-               return;
-
-       if (IS_SNB)
-               return;
-
-       /* setup a resource for this object */
-       intel_private.ifp_resource.name = "Intel Flush Page";
-       intel_private.ifp_resource.flags = IORESOURCE_MEM;
-
-       /* Setup chipset flush for 915 */
-       if (IS_I965 || IS_G33 || IS_G4X) {
-               intel_i965_g33_setup_chipset_flush();
-       } else {
-               intel_i915_setup_chipset_flush();
-       }
-
-       if (intel_private.ifp_resource.start) {
-               intel_private.i9xx_flush_page = ioremap_nocache(intel_private.ifp_resource.start, PAGE_SIZE);
-               if (!intel_private.i9xx_flush_page)
-                       dev_info(&intel_private.pcidev->dev, "can't ioremap flush page - no chipset flushing");
-       }
-}
-
-static int intel_i915_configure(void)
-{
-       struct aper_size_info_fixed *current_size;
-       u32 temp;
-       u16 gmch_ctrl;
-       int i;
-
-       current_size = A_SIZE_FIX(agp_bridge->current_size);
-
-       pci_read_config_dword(intel_private.pcidev, I915_GMADDR, &temp);
-
-       agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
-
-       pci_read_config_word(agp_bridge->dev, I830_GMCH_CTRL, &gmch_ctrl);
-       gmch_ctrl |= I830_GMCH_ENABLED;
-       pci_write_config_word(agp_bridge->dev, I830_GMCH_CTRL, gmch_ctrl);
-
-       writel(agp_bridge->gatt_bus_addr|I810_PGETBL_ENABLED, intel_private.registers+I810_PGETBL_CTL);
-       readl(intel_private.registers+I810_PGETBL_CTL); /* PCI Posting. */
-
-       if (agp_bridge->driver->needs_scratch_page) {
-               for (i = intel_private.gtt_entries; i < intel_private.gtt_total_size; i++) {
-                       writel(agp_bridge->scratch_page, intel_private.gtt+i);
-               }
-               readl(intel_private.gtt+i-1);   /* PCI Posting. */
-       }
-
-       global_cache_flush();
-
-       intel_i9xx_setup_flush();
-
-       return 0;
-}
-
-static void intel_i915_cleanup(void)
-{
-       if (intel_private.i9xx_flush_page)
-               iounmap(intel_private.i9xx_flush_page);
-       if (intel_private.resource_valid)
-               release_resource(&intel_private.ifp_resource);
-       intel_private.ifp_resource.start = 0;
-       intel_private.resource_valid = 0;
-       iounmap(intel_private.gtt);
-       iounmap(intel_private.registers);
-}
-
-static void intel_i915_chipset_flush(struct agp_bridge_data *bridge)
-{
-       if (intel_private.i9xx_flush_page)
-               writel(1, intel_private.i9xx_flush_page);
-}
-
-static int intel_i915_insert_entries(struct agp_memory *mem, off_t pg_start,
-                                    int type)
-{
-       int num_entries;
-       void *temp;
-       int ret = -EINVAL;
-       int mask_type;
-
-       if (mem->page_count == 0)
-               goto out;
-
-       temp = agp_bridge->current_size;
-       num_entries = A_SIZE_FIX(temp)->num_entries;
-
-       if (pg_start < intel_private.gtt_entries) {
-               dev_printk(KERN_DEBUG, &intel_private.pcidev->dev,
-                          "pg_start == 0x%.8lx, intel_private.gtt_entries == 0x%.8x\n",
-                          pg_start, intel_private.gtt_entries);
-
-               dev_info(&intel_private.pcidev->dev,
-                        "trying to insert into local/stolen memory\n");
-               goto out_err;
-       }
-
-       if ((pg_start + mem->page_count) > num_entries)
-               goto out_err;
-
-       /* The i915 can't check the GTT for entries since it's read only;
-        * depend on the caller to make the correct offset decisions.
-        */
-
-       if (type != mem->type)
-               goto out_err;
-
-       mask_type = agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type);
-
-       if (mask_type != 0 && mask_type != AGP_PHYS_MEMORY &&
-           mask_type != INTEL_AGP_CACHED_MEMORY)
-               goto out_err;
-
-       if (!mem->is_flushed)
-               global_cache_flush();
-
-       intel_agp_insert_sg_entries(mem, pg_start, mask_type);
-       agp_bridge->driver->tlb_flush(mem);
-
- out:
-       ret = 0;
- out_err:
-       mem->is_flushed = true;
-       return ret;
-}
-
-static int intel_i915_remove_entries(struct agp_memory *mem, off_t pg_start,
-                                    int type)
-{
-       int i;
-
-       if (mem->page_count == 0)
-               return 0;
-
-       if (pg_start < intel_private.gtt_entries) {
-               dev_info(&intel_private.pcidev->dev,
-                        "trying to disable local/stolen memory\n");
-               return -EINVAL;
-       }
-
-       for (i = pg_start; i < (mem->page_count + pg_start); i++)
-               writel(agp_bridge->scratch_page, intel_private.gtt+i);
-
-       readl(intel_private.gtt+i-1);
-
-       agp_bridge->driver->tlb_flush(mem);
-       return 0;
-}
-
-/* Return the aperture size by just checking the resource length.  The effect
- * described in the spec of the MSAC registers is just changing of the
- * resource size.
- */
-static int intel_i9xx_fetch_size(void)
-{
-       int num_sizes = ARRAY_SIZE(intel_i830_sizes);
-       int aper_size; /* size in megabytes */
-       int i;
-
-       aper_size = pci_resource_len(intel_private.pcidev, 2) / MB(1);
-
-       for (i = 0; i < num_sizes; i++) {
-               if (aper_size == intel_i830_sizes[i].size) {
-                       agp_bridge->current_size = intel_i830_sizes + i;
-                       agp_bridge->previous_size = agp_bridge->current_size;
-                       return aper_size;
-               }
-       }
-
-       return 0;
-}
-
-/* The intel i915 automatically initializes the agp aperture during POST.
- * Use the memory already set aside for in the GTT.
- */
-static int intel_i915_create_gatt_table(struct agp_bridge_data *bridge)
-{
-       int page_order;
-       struct aper_size_info_fixed *size;
-       int num_entries;
-       u32 temp, temp2;
-       int gtt_map_size = 256 * 1024;
-
-       size = agp_bridge->current_size;
-       page_order = size->page_order;
-       num_entries = size->num_entries;
-       agp_bridge->gatt_table_real = NULL;
-
-       pci_read_config_dword(intel_private.pcidev, I915_MMADDR, &temp);
-       pci_read_config_dword(intel_private.pcidev, I915_PTEADDR, &temp2);
-
-       if (IS_G33)
-           gtt_map_size = 1024 * 1024; /* 1M on G33 */
-       intel_private.gtt = ioremap(temp2, gtt_map_size);
-       if (!intel_private.gtt)
-               return -ENOMEM;
-
-       intel_private.gtt_total_size = gtt_map_size / 4;
-
-       temp &= 0xfff80000;
-
-       intel_private.registers = ioremap(temp, 128 * 4096);
-       if (!intel_private.registers) {
-               iounmap(intel_private.gtt);
-               return -ENOMEM;
-       }
-
-       temp = readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000;
-       global_cache_flush();   /* FIXME: ? */
-
-       /* we have to call this as early as possible after the MMIO base address is known */
-       intel_i830_init_gtt_entries();
-
-       agp_bridge->gatt_table = NULL;
-
-       agp_bridge->gatt_bus_addr = temp;
-
-       return 0;
-}
-
-/*
- * The i965 supports 36-bit physical addresses, but to keep
- * the format of the GTT the same, the bits that don't fit
- * in a 32-bit word are shifted down to bits 4..7.
- *
- * Gcc is smart enough to notice that "(addr >> 28) & 0xf0"
- * is always zero on 32-bit architectures, so no need to make
- * this conditional.
- */
-static unsigned long intel_i965_mask_memory(struct agp_bridge_data *bridge,
-                                           dma_addr_t addr, int type)
-{
-       /* Shift high bits down */
-       addr |= (addr >> 28) & 0xf0;
-
-       /* Type checking must be done elsewhere */
-       return addr | bridge->driver->masks[type].mask;
-}
-
-static void intel_i965_get_gtt_range(int *gtt_offset, int *gtt_size)
-{
-       u16 snb_gmch_ctl;
-
-       switch (agp_bridge->dev->device) {
-       case PCI_DEVICE_ID_INTEL_GM45_HB:
-       case PCI_DEVICE_ID_INTEL_EAGLELAKE_HB:
-       case PCI_DEVICE_ID_INTEL_Q45_HB:
-       case PCI_DEVICE_ID_INTEL_G45_HB:
-       case PCI_DEVICE_ID_INTEL_G41_HB:
-       case PCI_DEVICE_ID_INTEL_B43_HB:
-       case PCI_DEVICE_ID_INTEL_IRONLAKE_D_HB:
-       case PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB:
-       case PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB:
-       case PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB:
-               *gtt_offset = *gtt_size = MB(2);
-               break;
-       case PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB:
-       case PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB:
-               *gtt_offset = MB(2);
-
-               pci_read_config_word(intel_private.pcidev, SNB_GMCH_CTRL, &snb_gmch_ctl);
-               switch (snb_gmch_ctl & SNB_GTT_SIZE_MASK) {
-               default:
-               case SNB_GTT_SIZE_0M:
-                       printk(KERN_ERR "Bad GTT size mask: 0x%04x.\n", snb_gmch_ctl);
-                       *gtt_size = MB(0);
-                       break;
-               case SNB_GTT_SIZE_1M:
-                       *gtt_size = MB(1);
-                       break;
-               case SNB_GTT_SIZE_2M:
-                       *gtt_size = MB(2);
-                       break;
-               }
-               break;
-       default:
-               *gtt_offset = *gtt_size = KB(512);
-       }
-}
-
-/* The intel i965 automatically initializes the agp aperture during POST.
- * Use the memory already set aside for in the GTT.
- */
-static int intel_i965_create_gatt_table(struct agp_bridge_data *bridge)
-{
-       int page_order;
-       struct aper_size_info_fixed *size;
-       int num_entries;
-       u32 temp;
-       int gtt_offset, gtt_size;
-
-       size = agp_bridge->current_size;
-       page_order = size->page_order;
-       num_entries = size->num_entries;
-       agp_bridge->gatt_table_real = NULL;
-
-       pci_read_config_dword(intel_private.pcidev, I915_MMADDR, &temp);
-
-       temp &= 0xfff00000;
-
-       intel_i965_get_gtt_range(&gtt_offset, &gtt_size);
-
-       intel_private.gtt = ioremap((temp + gtt_offset) , gtt_size);
-
-       if (!intel_private.gtt)
-               return -ENOMEM;
-
-       intel_private.gtt_total_size = gtt_size / 4;
-
-       intel_private.registers = ioremap(temp, 128 * 4096);
-       if (!intel_private.registers) {
-               iounmap(intel_private.gtt);
-               return -ENOMEM;
-       }
-
-       temp = readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000;
-       global_cache_flush();   /* FIXME: ? */
-
-       /* we have to call this as early as possible after the MMIO base address is known */
-       intel_i830_init_gtt_entries();
-
-       agp_bridge->gatt_table = NULL;
-
-       agp_bridge->gatt_bus_addr = temp;
-
-       return 0;
-}
+#include "intel-gtt.c"
 
+int intel_agp_enabled;
+EXPORT_SYMBOL(intel_agp_enabled);
 
 static int intel_fetch_size(void)
 {
@@ -2003,33 +485,6 @@ static const struct agp_bridge_driver intel_generic_driver = {
        .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 };
 
-static const struct agp_bridge_driver intel_810_driver = {
-       .owner                  = THIS_MODULE,
-       .aperture_sizes         = intel_i810_sizes,
-       .size_type              = FIXED_APER_SIZE,
-       .num_aperture_sizes     = 2,
-       .needs_scratch_page     = true,
-       .configure              = intel_i810_configure,
-       .fetch_size             = intel_i810_fetch_size,
-       .cleanup                = intel_i810_cleanup,
-       .tlb_flush              = intel_i810_tlbflush,
-       .mask_memory            = intel_i810_mask_memory,
-       .masks                  = intel_i810_masks,
-       .agp_enable             = intel_i810_agp_enable,
-       .cache_flush            = global_cache_flush,
-       .create_gatt_table      = agp_generic_create_gatt_table,
-       .free_gatt_table        = agp_generic_free_gatt_table,
-       .insert_memory          = intel_i810_insert_entries,
-       .remove_memory          = intel_i810_remove_entries,
-       .alloc_by_type          = intel_i810_alloc_by_type,
-       .free_by_type           = intel_i810_free_by_type,
-       .agp_alloc_page         = agp_generic_alloc_page,
-       .agp_alloc_pages        = agp_generic_alloc_pages,
-       .agp_destroy_page       = agp_generic_destroy_page,
-       .agp_destroy_pages      = agp_generic_destroy_pages,
-       .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
-};
-
 static const struct agp_bridge_driver intel_815_driver = {
        .owner                  = THIS_MODULE,
        .aperture_sizes         = intel_815_sizes,
@@ -2056,34 +511,6 @@ static const struct agp_bridge_driver intel_815_driver = {
        .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 };
 
-static const struct agp_bridge_driver intel_830_driver = {
-       .owner                  = THIS_MODULE,
-       .aperture_sizes         = intel_i830_sizes,
-       .size_type              = FIXED_APER_SIZE,
-       .num_aperture_sizes     = 4,
-       .needs_scratch_page     = true,
-       .configure              = intel_i830_configure,
-       .fetch_size             = intel_i830_fetch_size,
-       .cleanup                = intel_i830_cleanup,
-       .tlb_flush              = intel_i810_tlbflush,
-       .mask_memory            = intel_i810_mask_memory,
-       .masks                  = intel_i810_masks,
-       .agp_enable             = intel_i810_agp_enable,
-       .cache_flush            = global_cache_flush,
-       .create_gatt_table      = intel_i830_create_gatt_table,
-       .free_gatt_table        = intel_i830_free_gatt_table,
-       .insert_memory          = intel_i830_insert_entries,
-       .remove_memory          = intel_i830_remove_entries,
-       .alloc_by_type          = intel_i830_alloc_by_type,
-       .free_by_type           = intel_i810_free_by_type,
-       .agp_alloc_page         = agp_generic_alloc_page,
-       .agp_alloc_pages        = agp_generic_alloc_pages,
-       .agp_destroy_page       = agp_generic_destroy_page,
-       .agp_destroy_pages      = agp_generic_destroy_pages,
-       .agp_type_to_mask_type  = intel_i830_type_to_mask_type,
-       .chipset_flush          = intel_i830_chipset_flush,
-};
-
 static const struct agp_bridge_driver intel_820_driver = {
        .owner                  = THIS_MODULE,
        .aperture_sizes         = intel_8xx_sizes,
@@ -2240,74 +667,6 @@ static const struct agp_bridge_driver intel_860_driver = {
        .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 };
 
-static const struct agp_bridge_driver intel_915_driver = {
-       .owner                  = THIS_MODULE,
-       .aperture_sizes         = intel_i830_sizes,
-       .size_type              = FIXED_APER_SIZE,
-       .num_aperture_sizes     = 4,
-       .needs_scratch_page     = true,
-       .configure              = intel_i915_configure,
-       .fetch_size             = intel_i9xx_fetch_size,
-       .cleanup                = intel_i915_cleanup,
-       .tlb_flush              = intel_i810_tlbflush,
-       .mask_memory            = intel_i810_mask_memory,
-       .masks                  = intel_i810_masks,
-       .agp_enable             = intel_i810_agp_enable,
-       .cache_flush            = global_cache_flush,
-       .create_gatt_table      = intel_i915_create_gatt_table,
-       .free_gatt_table        = intel_i830_free_gatt_table,
-       .insert_memory          = intel_i915_insert_entries,
-       .remove_memory          = intel_i915_remove_entries,
-       .alloc_by_type          = intel_i830_alloc_by_type,
-       .free_by_type           = intel_i810_free_by_type,
-       .agp_alloc_page         = agp_generic_alloc_page,
-       .agp_alloc_pages        = agp_generic_alloc_pages,
-       .agp_destroy_page       = agp_generic_destroy_page,
-       .agp_destroy_pages      = agp_generic_destroy_pages,
-       .agp_type_to_mask_type  = intel_i830_type_to_mask_type,
-       .chipset_flush          = intel_i915_chipset_flush,
-#ifdef USE_PCI_DMA_API
-       .agp_map_page           = intel_agp_map_page,
-       .agp_unmap_page         = intel_agp_unmap_page,
-       .agp_map_memory         = intel_agp_map_memory,
-       .agp_unmap_memory       = intel_agp_unmap_memory,
-#endif
-};
-
-static const struct agp_bridge_driver intel_i965_driver = {
-       .owner                  = THIS_MODULE,
-       .aperture_sizes         = intel_i830_sizes,
-       .size_type              = FIXED_APER_SIZE,
-       .num_aperture_sizes     = 4,
-       .needs_scratch_page     = true,
-       .configure              = intel_i915_configure,
-       .fetch_size             = intel_i9xx_fetch_size,
-       .cleanup                = intel_i915_cleanup,
-       .tlb_flush              = intel_i810_tlbflush,
-       .mask_memory            = intel_i965_mask_memory,
-       .masks                  = intel_i810_masks,
-       .agp_enable             = intel_i810_agp_enable,
-       .cache_flush            = global_cache_flush,
-       .create_gatt_table      = intel_i965_create_gatt_table,
-       .free_gatt_table        = intel_i830_free_gatt_table,
-       .insert_memory          = intel_i915_insert_entries,
-       .remove_memory          = intel_i915_remove_entries,
-       .alloc_by_type          = intel_i830_alloc_by_type,
-       .free_by_type           = intel_i810_free_by_type,
-       .agp_alloc_page         = agp_generic_alloc_page,
-       .agp_alloc_pages        = agp_generic_alloc_pages,
-       .agp_destroy_page       = agp_generic_destroy_page,
-       .agp_destroy_pages      = agp_generic_destroy_pages,
-       .agp_type_to_mask_type  = intel_i830_type_to_mask_type,
-       .chipset_flush          = intel_i915_chipset_flush,
-#ifdef USE_PCI_DMA_API
-       .agp_map_page           = intel_agp_map_page,
-       .agp_unmap_page         = intel_agp_unmap_page,
-       .agp_map_memory         = intel_agp_map_memory,
-       .agp_unmap_memory       = intel_agp_unmap_memory,
-#endif
-};
-
 static const struct agp_bridge_driver intel_7505_driver = {
        .owner                  = THIS_MODULE,
        .aperture_sizes         = intel_8xx_sizes,
@@ -2334,40 +693,6 @@ static const struct agp_bridge_driver intel_7505_driver = {
        .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 };
 
-static const struct agp_bridge_driver intel_g33_driver = {
-       .owner                  = THIS_MODULE,
-       .aperture_sizes         = intel_i830_sizes,
-       .size_type              = FIXED_APER_SIZE,
-       .num_aperture_sizes     = 4,
-       .needs_scratch_page     = true,
-       .configure              = intel_i915_configure,
-       .fetch_size             = intel_i9xx_fetch_size,
-       .cleanup                = intel_i915_cleanup,
-       .tlb_flush              = intel_i810_tlbflush,
-       .mask_memory            = intel_i965_mask_memory,
-       .masks                  = intel_i810_masks,
-       .agp_enable             = intel_i810_agp_enable,
-       .cache_flush            = global_cache_flush,
-       .create_gatt_table      = intel_i915_create_gatt_table,
-       .free_gatt_table        = intel_i830_free_gatt_table,
-       .insert_memory          = intel_i915_insert_entries,
-       .remove_memory          = intel_i915_remove_entries,
-       .alloc_by_type          = intel_i830_alloc_by_type,
-       .free_by_type           = intel_i810_free_by_type,
-       .agp_alloc_page         = agp_generic_alloc_page,
-       .agp_alloc_pages        = agp_generic_alloc_pages,
-       .agp_destroy_page       = agp_generic_destroy_page,
-       .agp_destroy_pages      = agp_generic_destroy_pages,
-       .agp_type_to_mask_type  = intel_i830_type_to_mask_type,
-       .chipset_flush          = intel_i915_chipset_flush,
-#ifdef USE_PCI_DMA_API
-       .agp_map_page           = intel_agp_map_page,
-       .agp_unmap_page         = intel_agp_unmap_page,
-       .agp_map_memory         = intel_agp_map_memory,
-       .agp_unmap_memory       = intel_agp_unmap_memory,
-#endif
-};
-
 static int find_gmch(u16 device)
 {
        struct pci_dev *gmch_device;
@@ -2392,103 +717,137 @@ static int find_gmch(u16 device)
 static const struct intel_driver_description {
        unsigned int chip_id;
        unsigned int gmch_chip_id;
-       unsigned int multi_gmch_chip; /* if we have more gfx chip type on this HB. */
        char *name;
        const struct agp_bridge_driver *driver;
        const struct agp_bridge_driver *gmch_driver;
 } intel_agp_chipsets[] = {
-       { PCI_DEVICE_ID_INTEL_82443LX_0, 0, 0, "440LX", &intel_generic_driver, NULL },
-       { PCI_DEVICE_ID_INTEL_82443BX_0, 0, 0, "440BX", &intel_generic_driver, NULL },
-       { PCI_DEVICE_ID_INTEL_82443GX_0, 0, 0, "440GX", &intel_generic_driver, NULL },
-       { PCI_DEVICE_ID_INTEL_82810_MC1, PCI_DEVICE_ID_INTEL_82810_IG1, 0, "i810",
+       { PCI_DEVICE_ID_INTEL_82443LX_0, 0, "440LX", &intel_generic_driver, NULL },
+       { PCI_DEVICE_ID_INTEL_82443BX_0, 0, "440BX", &intel_generic_driver, NULL },
+       { PCI_DEVICE_ID_INTEL_82443GX_0, 0, "440GX", &intel_generic_driver, NULL },
+       { PCI_DEVICE_ID_INTEL_82810_MC1, PCI_DEVICE_ID_INTEL_82810_IG1, "i810",
                NULL, &intel_810_driver },
-       { PCI_DEVICE_ID_INTEL_82810_MC3, PCI_DEVICE_ID_INTEL_82810_IG3, 0, "i810",
+       { PCI_DEVICE_ID_INTEL_82810_MC3, PCI_DEVICE_ID_INTEL_82810_IG3, "i810",
                NULL, &intel_810_driver },
-       { PCI_DEVICE_ID_INTEL_82810E_MC, PCI_DEVICE_ID_INTEL_82810E_IG, 0, "i810",
+       { PCI_DEVICE_ID_INTEL_82810E_MC, PCI_DEVICE_ID_INTEL_82810E_IG, "i810",
                NULL, &intel_810_driver },
-       { PCI_DEVICE_ID_INTEL_82815_MC, PCI_DEVICE_ID_INTEL_82815_CGC, 0, "i815",
+       { PCI_DEVICE_ID_INTEL_82815_MC, PCI_DEVICE_ID_INTEL_82815_CGC, "i815",
                &intel_815_driver, &intel_810_driver },
-       { PCI_DEVICE_ID_INTEL_82820_HB, 0, 0, "i820", &intel_820_driver, NULL },
-       { PCI_DEVICE_ID_INTEL_82820_UP_HB, 0, 0, "i820", &intel_820_driver, NULL },
-       { PCI_DEVICE_ID_INTEL_82830_HB, PCI_DEVICE_ID_INTEL_82830_CGC, 0, "830M",
+       { PCI_DEVICE_ID_INTEL_82820_HB, 0, "i820", &intel_820_driver, NULL },
+       { PCI_DEVICE_ID_INTEL_82820_UP_HB, 0, "i820", &intel_820_driver, NULL },
+       { PCI_DEVICE_ID_INTEL_82830_HB, PCI_DEVICE_ID_INTEL_82830_CGC, "830M",
                &intel_830mp_driver, &intel_830_driver },
-       { PCI_DEVICE_ID_INTEL_82840_HB, 0, 0, "i840", &intel_840_driver, NULL },
-       { PCI_DEVICE_ID_INTEL_82845_HB, 0, 0, "845G", &intel_845_driver, NULL },
-       { PCI_DEVICE_ID_INTEL_82845G_HB, PCI_DEVICE_ID_INTEL_82845G_IG, 0, "830M",
+       { PCI_DEVICE_ID_INTEL_82840_HB, 0, "i840", &intel_840_driver, NULL },
+       { PCI_DEVICE_ID_INTEL_82845_HB, 0, "845G", &intel_845_driver, NULL },
+       { PCI_DEVICE_ID_INTEL_82845G_HB, PCI_DEVICE_ID_INTEL_82845G_IG, "830M",
                &intel_845_driver, &intel_830_driver },
-       { PCI_DEVICE_ID_INTEL_82850_HB, 0, 0, "i850", &intel_850_driver, NULL },
-       { PCI_DEVICE_ID_INTEL_82854_HB, PCI_DEVICE_ID_INTEL_82854_IG, 0, "854",
+       { PCI_DEVICE_ID_INTEL_82850_HB, 0, "i850", &intel_850_driver, NULL },
+       { PCI_DEVICE_ID_INTEL_82854_HB, PCI_DEVICE_ID_INTEL_82854_IG, "854",
                &intel_845_driver, &intel_830_driver },
-       { PCI_DEVICE_ID_INTEL_82855PM_HB, 0, 0, "855PM", &intel_845_driver, NULL },
-       { PCI_DEVICE_ID_INTEL_82855GM_HB, PCI_DEVICE_ID_INTEL_82855GM_IG, 0, "855GM",
+       { PCI_DEVICE_ID_INTEL_82855PM_HB, 0, "855PM", &intel_845_driver, NULL },
+       { PCI_DEVICE_ID_INTEL_82855GM_HB, PCI_DEVICE_ID_INTEL_82855GM_IG, "855GM",
                &intel_845_driver, &intel_830_driver },
-       { PCI_DEVICE_ID_INTEL_82860_HB, 0, 0, "i860", &intel_860_driver, NULL },
-       { PCI_DEVICE_ID_INTEL_82865_HB, PCI_DEVICE_ID_INTEL_82865_IG, 0, "865",
+       { PCI_DEVICE_ID_INTEL_82860_HB, 0, "i860", &intel_860_driver, NULL },
+       { PCI_DEVICE_ID_INTEL_82865_HB, PCI_DEVICE_ID_INTEL_82865_IG, "865",
                &intel_845_driver, &intel_830_driver },
-       { PCI_DEVICE_ID_INTEL_82875_HB, 0, 0, "i875", &intel_845_driver, NULL },
-       { PCI_DEVICE_ID_INTEL_E7221_HB, PCI_DEVICE_ID_INTEL_E7221_IG, 0, "E7221 (i915)",
+       { PCI_DEVICE_ID_INTEL_82875_HB, 0, "i875", &intel_845_driver, NULL },
+       { PCI_DEVICE_ID_INTEL_E7221_HB, PCI_DEVICE_ID_INTEL_E7221_IG, "E7221 (i915)",
                NULL, &intel_915_driver },
-       { PCI_DEVICE_ID_INTEL_82915G_HB, PCI_DEVICE_ID_INTEL_82915G_IG, 0, "915G",
+       { PCI_DEVICE_ID_INTEL_82915G_HB, PCI_DEVICE_ID_INTEL_82915G_IG, "915G",
                NULL, &intel_915_driver },
-       { PCI_DEVICE_ID_INTEL_82915GM_HB, PCI_DEVICE_ID_INTEL_82915GM_IG, 0, "915GM",
+       { PCI_DEVICE_ID_INTEL_82915GM_HB, PCI_DEVICE_ID_INTEL_82915GM_IG, "915GM",
                NULL, &intel_915_driver },
-       { PCI_DEVICE_ID_INTEL_82945G_HB, PCI_DEVICE_ID_INTEL_82945G_IG, 0, "945G",
+       { PCI_DEVICE_ID_INTEL_82945G_HB, PCI_DEVICE_ID_INTEL_82945G_IG, "945G",
                NULL, &intel_915_driver },
-       { PCI_DEVICE_ID_INTEL_82945GM_HB, PCI_DEVICE_ID_INTEL_82945GM_IG, 0, "945GM",
+       { PCI_DEVICE_ID_INTEL_82945GM_HB, PCI_DEVICE_ID_INTEL_82945GM_IG, "945GM",
                NULL, &intel_915_driver },
-       { PCI_DEVICE_ID_INTEL_82945GME_HB, PCI_DEVICE_ID_INTEL_82945GME_IG, 0, "945GME",
+       { PCI_DEVICE_ID_INTEL_82945GME_HB, PCI_DEVICE_ID_INTEL_82945GME_IG, "945GME",
                NULL, &intel_915_driver },
-       { PCI_DEVICE_ID_INTEL_82946GZ_HB, PCI_DEVICE_ID_INTEL_82946GZ_IG, 0, "946GZ",
+       { PCI_DEVICE_ID_INTEL_82946GZ_HB, PCI_DEVICE_ID_INTEL_82946GZ_IG, "946GZ",
                NULL, &intel_i965_driver },
-       { PCI_DEVICE_ID_INTEL_82G35_HB, PCI_DEVICE_ID_INTEL_82G35_IG, 0, "G35",
+       { PCI_DEVICE_ID_INTEL_82G35_HB, PCI_DEVICE_ID_INTEL_82G35_IG, "G35",
                NULL, &intel_i965_driver },
-       { PCI_DEVICE_ID_INTEL_82965Q_HB, PCI_DEVICE_ID_INTEL_82965Q_IG, 0, "965Q",
+       { PCI_DEVICE_ID_INTEL_82965Q_HB, PCI_DEVICE_ID_INTEL_82965Q_IG, "965Q",
                NULL, &intel_i965_driver },
-       { PCI_DEVICE_ID_INTEL_82965G_HB, PCI_DEVICE_ID_INTEL_82965G_IG, 0, "965G",
+       { PCI_DEVICE_ID_INTEL_82965G_HB, PCI_DEVICE_ID_INTEL_82965G_IG, "965G",
                NULL, &intel_i965_driver },
-       { PCI_DEVICE_ID_INTEL_82965GM_HB, PCI_DEVICE_ID_INTEL_82965GM_IG, 0, "965GM",
+       { PCI_DEVICE_ID_INTEL_82965GM_HB, PCI_DEVICE_ID_INTEL_82965GM_IG, "965GM",
                NULL, &intel_i965_driver },
-       { PCI_DEVICE_ID_INTEL_82965GME_HB, PCI_DEVICE_ID_INTEL_82965GME_IG, 0, "965GME/GLE",
+       { PCI_DEVICE_ID_INTEL_82965GME_HB, PCI_DEVICE_ID_INTEL_82965GME_IG, "965GME/GLE",
                NULL, &intel_i965_driver },
-       { PCI_DEVICE_ID_INTEL_7505_0, 0, 0, "E7505", &intel_7505_driver, NULL },
-       { PCI_DEVICE_ID_INTEL_7205_0, 0, 0, "E7205", &intel_7505_driver, NULL },
-       { PCI_DEVICE_ID_INTEL_G33_HB, PCI_DEVICE_ID_INTEL_G33_IG, 0, "G33",
+       { PCI_DEVICE_ID_INTEL_7505_0, 0, "E7505", &intel_7505_driver, NULL },
+       { PCI_DEVICE_ID_INTEL_7205_0, 0, "E7205", &intel_7505_driver, NULL },
+       { PCI_DEVICE_ID_INTEL_G33_HB, PCI_DEVICE_ID_INTEL_G33_IG, "G33",
                NULL, &intel_g33_driver },
-       { PCI_DEVICE_ID_INTEL_Q35_HB, PCI_DEVICE_ID_INTEL_Q35_IG, 0, "Q35",
+       { PCI_DEVICE_ID_INTEL_Q35_HB, PCI_DEVICE_ID_INTEL_Q35_IG, "Q35",
                NULL, &intel_g33_driver },
-       { PCI_DEVICE_ID_INTEL_Q33_HB, PCI_DEVICE_ID_INTEL_Q33_IG, 0, "Q33",
+       { PCI_DEVICE_ID_INTEL_Q33_HB, PCI_DEVICE_ID_INTEL_Q33_IG, "Q33",
                NULL, &intel_g33_driver },
-       { PCI_DEVICE_ID_INTEL_PINEVIEW_M_HB, PCI_DEVICE_ID_INTEL_PINEVIEW_M_IG, 0, "GMA3150",
+       { PCI_DEVICE_ID_INTEL_PINEVIEW_M_HB, PCI_DEVICE_ID_INTEL_PINEVIEW_M_IG, "GMA3150",
                NULL, &intel_g33_driver },
-       { PCI_DEVICE_ID_INTEL_PINEVIEW_HB, PCI_DEVICE_ID_INTEL_PINEVIEW_IG, 0, "GMA3150",
+       { PCI_DEVICE_ID_INTEL_PINEVIEW_HB, PCI_DEVICE_ID_INTEL_PINEVIEW_IG, "GMA3150",
                NULL, &intel_g33_driver },
-       { PCI_DEVICE_ID_INTEL_GM45_HB, PCI_DEVICE_ID_INTEL_GM45_IG, 0,
+       { PCI_DEVICE_ID_INTEL_GM45_HB, PCI_DEVICE_ID_INTEL_GM45_IG,
            "GM45", NULL, &intel_i965_driver },
-       { PCI_DEVICE_ID_INTEL_EAGLELAKE_HB, PCI_DEVICE_ID_INTEL_EAGLELAKE_IG, 0,
+       { PCI_DEVICE_ID_INTEL_EAGLELAKE_HB, PCI_DEVICE_ID_INTEL_EAGLELAKE_IG,
            "Eaglelake", NULL, &intel_i965_driver },
-       { PCI_DEVICE_ID_INTEL_Q45_HB, PCI_DEVICE_ID_INTEL_Q45_IG, 0,
+       { PCI_DEVICE_ID_INTEL_Q45_HB, PCI_DEVICE_ID_INTEL_Q45_IG,
            "Q45/Q43", NULL, &intel_i965_driver },
-       { PCI_DEVICE_ID_INTEL_G45_HB, PCI_DEVICE_ID_INTEL_G45_IG, 0,
+       { PCI_DEVICE_ID_INTEL_G45_HB, PCI_DEVICE_ID_INTEL_G45_IG,
            "G45/G43", NULL, &intel_i965_driver },
-       { PCI_DEVICE_ID_INTEL_B43_HB, PCI_DEVICE_ID_INTEL_B43_IG, 0,
+       { PCI_DEVICE_ID_INTEL_B43_HB, PCI_DEVICE_ID_INTEL_B43_IG,
            "B43", NULL, &intel_i965_driver },
-       { PCI_DEVICE_ID_INTEL_G41_HB, PCI_DEVICE_ID_INTEL_G41_IG, 0,
+       { PCI_DEVICE_ID_INTEL_G41_HB, PCI_DEVICE_ID_INTEL_G41_IG,
            "G41", NULL, &intel_i965_driver },
-       { PCI_DEVICE_ID_INTEL_IRONLAKE_D_HB, PCI_DEVICE_ID_INTEL_IRONLAKE_D_IG, 0,
+       { PCI_DEVICE_ID_INTEL_IRONLAKE_D_HB, PCI_DEVICE_ID_INTEL_IRONLAKE_D_IG,
            "HD Graphics", NULL, &intel_i965_driver },
-       { PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB, PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG, 0,
+       { PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB, PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG,
            "HD Graphics", NULL, &intel_i965_driver },
-       { PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB, PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG, 0,
+       { PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB, PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG,
            "HD Graphics", NULL, &intel_i965_driver },
-       { PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB, PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG, 0,
+       { PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB, PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG,
            "HD Graphics", NULL, &intel_i965_driver },
-       { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_IG, 0,
+       { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_IG,
            "Sandybridge", NULL, &intel_i965_driver },
-       { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_IG, 0,
+       { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_IG,
            "Sandybridge", NULL, &intel_i965_driver },
-       { 0, 0, 0, NULL, NULL, NULL }
+       { 0, 0, NULL, NULL, NULL }
 };
 
+static int __devinit intel_gmch_probe(struct pci_dev *pdev,
+                                     struct agp_bridge_data *bridge)
+{
+       int i;
+       bridge->driver = NULL;
+
+       for (i = 0; intel_agp_chipsets[i].name != NULL; i++) {
+               if ((intel_agp_chipsets[i].gmch_chip_id != 0) &&
+                       find_gmch(intel_agp_chipsets[i].gmch_chip_id)) {
+                       bridge->driver =
+                               intel_agp_chipsets[i].gmch_driver;
+                       break;
+               }
+       }
+
+       if (!bridge->driver)
+               return 0;
+
+       bridge->dev_private_data = &intel_private;
+       bridge->dev = pdev;
+
+       dev_info(&pdev->dev, "Intel %s Chipset\n", intel_agp_chipsets[i].name);
+
+       if (bridge->driver->mask_memory == intel_i965_mask_memory) {
+               if (pci_set_dma_mask(intel_private.pcidev, DMA_BIT_MASK(36)))
+                       dev_err(&intel_private.pcidev->dev,
+                               "set gfx device dma mask 36bit failed!\n");
+               else
+                       pci_set_consistent_dma_mask(intel_private.pcidev,
+                                                   DMA_BIT_MASK(36));
+       }
+
+       return 1;
+}
+
 static int __devinit agp_intel_probe(struct pci_dev *pdev,
                                     const struct pci_device_id *ent)
 {
@@ -2503,22 +862,18 @@ static int __devinit agp_intel_probe(struct pci_dev *pdev,
        if (!bridge)
                return -ENOMEM;
 
+       bridge->capndx = cap_ptr;
+
+       if (intel_gmch_probe(pdev, bridge))
+               goto found_gmch;
+
        for (i = 0; intel_agp_chipsets[i].name != NULL; i++) {
                /* In case that multiple models of gfx chip may
                   stand on same host bridge type, this can be
                   sure we detect the right IGD. */
                if (pdev->device == intel_agp_chipsets[i].chip_id) {
-                       if ((intel_agp_chipsets[i].gmch_chip_id != 0) &&
-                               find_gmch(intel_agp_chipsets[i].gmch_chip_id)) {
-                               bridge->driver =
-                                       intel_agp_chipsets[i].gmch_driver;
-                               break;
-                       } else if (intel_agp_chipsets[i].multi_gmch_chip) {
-                               continue;
-                       } else {
-                               bridge->driver = intel_agp_chipsets[i].driver;
-                               break;
-                       }
+                       bridge->driver = intel_agp_chipsets[i].driver;
+                       break;
                }
        }
 
@@ -2530,18 +885,8 @@ static int __devinit agp_intel_probe(struct pci_dev *pdev,
                return -ENODEV;
        }
 
-       if (bridge->driver == NULL) {
-               /* bridge has no AGP and no IGD detected */
-               if (cap_ptr)
-                       dev_warn(&pdev->dev, "can't find bridge device (chip_id: %04x)\n",
-                                intel_agp_chipsets[i].gmch_chip_id);
-               agp_put_bridge(bridge);
-               return -ENODEV;
-       }
-
        bridge->dev = pdev;
-       bridge->capndx = cap_ptr;
-       bridge->dev_private_data = &intel_private;
+       bridge->dev_private_data = NULL;
 
        dev_info(&pdev->dev, "Intel %s Chipset\n", intel_agp_chipsets[i].name);
 
@@ -2577,15 +922,7 @@ static int __devinit agp_intel_probe(struct pci_dev *pdev,
                                &bridge->mode);
        }
 
-       if (bridge->driver->mask_memory == intel_i965_mask_memory) {
-               if (pci_set_dma_mask(intel_private.pcidev, DMA_BIT_MASK(36)))
-                       dev_err(&intel_private.pcidev->dev,
-                               "set gfx device dma mask 36bit failed!\n");
-               else
-                       pci_set_consistent_dma_mask(intel_private.pcidev,
-                                                   DMA_BIT_MASK(36));
-       }
-
+found_gmch:
        pci_set_drvdata(pdev, bridge);
        err = agp_add_bridge(bridge);
        if (!err)
@@ -2611,22 +948,7 @@ static int agp_intel_resume(struct pci_dev *pdev)
        struct agp_bridge_data *bridge = pci_get_drvdata(pdev);
        int ret_val;
 
-       if (bridge->driver == &intel_generic_driver)
-               intel_configure();
-       else if (bridge->driver == &intel_850_driver)
-               intel_850_configure();
-       else if (bridge->driver == &intel_845_driver)
-               intel_845_configure();
-       else if (bridge->driver == &intel_830mp_driver)
-               intel_830mp_configure();
-       else if (bridge->driver == &intel_915_driver)
-               intel_i915_configure();
-       else if (bridge->driver == &intel_830_driver)
-               intel_i830_configure();
-       else if (bridge->driver == &intel_810_driver)
-               intel_i810_configure();
-       else if (bridge->driver == &intel_i965_driver)
-               intel_i915_configure();
+       bridge->driver->configure();
 
        ret_val = agp_rebind_memory();
        if (ret_val != 0)
diff --git a/drivers/char/agp/intel-agp.h b/drivers/char/agp/intel-agp.h
new file mode 100644 (file)
index 0000000..2547465
--- /dev/null
@@ -0,0 +1,239 @@
+/*
+ * Common Intel AGPGART and GTT definitions.
+ */
+
+/* Intel registers */
+#define INTEL_APSIZE   0xb4
+#define INTEL_ATTBASE  0xb8
+#define INTEL_AGPCTRL  0xb0
+#define INTEL_NBXCFG   0x50
+#define INTEL_ERRSTS   0x91
+
+/* Intel i830 registers */
+#define I830_GMCH_CTRL                 0x52
+#define I830_GMCH_ENABLED              0x4
+#define I830_GMCH_MEM_MASK             0x1
+#define I830_GMCH_MEM_64M              0x1
+#define I830_GMCH_MEM_128M             0
+#define I830_GMCH_GMS_MASK             0x70
+#define I830_GMCH_GMS_DISABLED         0x00
+#define I830_GMCH_GMS_LOCAL            0x10
+#define I830_GMCH_GMS_STOLEN_512       0x20
+#define I830_GMCH_GMS_STOLEN_1024      0x30
+#define I830_GMCH_GMS_STOLEN_8192      0x40
+#define I830_RDRAM_CHANNEL_TYPE                0x03010
+#define I830_RDRAM_ND(x)               (((x) & 0x20) >> 5)
+#define I830_RDRAM_DDT(x)              (((x) & 0x18) >> 3)
+
+/* This one is for I830MP w. an external graphic card */
+#define INTEL_I830_ERRSTS      0x92
+
+/* Intel 855GM/852GM registers */
+#define I855_GMCH_GMS_MASK             0xF0
+#define I855_GMCH_GMS_STOLEN_0M                0x0
+#define I855_GMCH_GMS_STOLEN_1M                (0x1 << 4)
+#define I855_GMCH_GMS_STOLEN_4M                (0x2 << 4)
+#define I855_GMCH_GMS_STOLEN_8M                (0x3 << 4)
+#define I855_GMCH_GMS_STOLEN_16M       (0x4 << 4)
+#define I855_GMCH_GMS_STOLEN_32M       (0x5 << 4)
+#define I85X_CAPID                     0x44
+#define I85X_VARIANT_MASK              0x7
+#define I85X_VARIANT_SHIFT             5
+#define I855_GME                       0x0
+#define I855_GM                                0x4
+#define I852_GME                       0x2
+#define I852_GM                                0x5
+
+/* Intel i845 registers */
+#define INTEL_I845_AGPM                0x51
+#define INTEL_I845_ERRSTS      0xc8
+
+/* Intel i860 registers */
+#define INTEL_I860_MCHCFG      0x50
+#define INTEL_I860_ERRSTS      0xc8
+
+/* Intel i810 registers */
+#define I810_GMADDR            0x10
+#define I810_MMADDR            0x14
+#define I810_PTE_BASE          0x10000
+#define I810_PTE_MAIN_UNCACHED 0x00000000
+#define I810_PTE_LOCAL         0x00000002
+#define I810_PTE_VALID         0x00000001
+#define I830_PTE_SYSTEM_CACHED  0x00000006
+#define I810_SMRAM_MISCC       0x70
+#define I810_GFX_MEM_WIN_SIZE  0x00010000
+#define I810_GFX_MEM_WIN_32M   0x00010000
+#define I810_GMS               0x000000c0
+#define I810_GMS_DISABLE       0x00000000
+#define I810_PGETBL_CTL                0x2020
+#define I810_PGETBL_ENABLED    0x00000001
+#define I965_PGETBL_SIZE_MASK  0x0000000e
+#define I965_PGETBL_SIZE_512KB (0 << 1)
+#define I965_PGETBL_SIZE_256KB (1 << 1)
+#define I965_PGETBL_SIZE_128KB (2 << 1)
+#define I965_PGETBL_SIZE_1MB   (3 << 1)
+#define I965_PGETBL_SIZE_2MB   (4 << 1)
+#define I965_PGETBL_SIZE_1_5MB (5 << 1)
+#define G33_PGETBL_SIZE_MASK    (3 << 8)
+#define G33_PGETBL_SIZE_1M      (1 << 8)
+#define G33_PGETBL_SIZE_2M      (2 << 8)
+
+#define I810_DRAM_CTL          0x3000
+#define I810_DRAM_ROW_0                0x00000001
+#define I810_DRAM_ROW_0_SDRAM  0x00000001
+
+/* Intel 815 register */
+#define INTEL_815_APCONT       0x51
+#define INTEL_815_ATTBASE_MASK ~0x1FFFFFFF
+
+/* Intel i820 registers */
+#define INTEL_I820_RDCR                0x51
+#define INTEL_I820_ERRSTS      0xc8
+
+/* Intel i840 registers */
+#define INTEL_I840_MCHCFG      0x50
+#define INTEL_I840_ERRSTS      0xc8
+
+/* Intel i850 registers */
+#define INTEL_I850_MCHCFG      0x50
+#define INTEL_I850_ERRSTS      0xc8
+
+/* intel 915G registers */
+#define I915_GMADDR    0x18
+#define I915_MMADDR    0x10
+#define I915_PTEADDR   0x1C
+#define I915_GMCH_GMS_STOLEN_48M       (0x6 << 4)
+#define I915_GMCH_GMS_STOLEN_64M       (0x7 << 4)
+#define G33_GMCH_GMS_STOLEN_128M       (0x8 << 4)
+#define G33_GMCH_GMS_STOLEN_256M       (0x9 << 4)
+#define INTEL_GMCH_GMS_STOLEN_96M      (0xa << 4)
+#define INTEL_GMCH_GMS_STOLEN_160M     (0xb << 4)
+#define INTEL_GMCH_GMS_STOLEN_224M     (0xc << 4)
+#define INTEL_GMCH_GMS_STOLEN_352M     (0xd << 4)
+
+#define I915_IFPADDR    0x60
+
+/* Intel 965G registers */
+#define I965_MSAC 0x62
+#define I965_IFPADDR    0x70
+
+/* Intel 7505 registers */
+#define INTEL_I7505_APSIZE     0x74
+#define INTEL_I7505_NCAPID     0x60
+#define INTEL_I7505_NISTAT     0x6c
+#define INTEL_I7505_ATTBASE    0x78
+#define INTEL_I7505_ERRSTS     0x42
+#define INTEL_I7505_AGPCTRL    0x70
+#define INTEL_I7505_MCHCFG     0x50
+
+#define SNB_GMCH_CTRL  0x50
+#define SNB_GMCH_GMS_STOLEN_MASK       0xF8
+#define SNB_GMCH_GMS_STOLEN_32M                (1 << 3)
+#define SNB_GMCH_GMS_STOLEN_64M                (2 << 3)
+#define SNB_GMCH_GMS_STOLEN_96M                (3 << 3)
+#define SNB_GMCH_GMS_STOLEN_128M       (4 << 3)
+#define SNB_GMCH_GMS_STOLEN_160M       (5 << 3)
+#define SNB_GMCH_GMS_STOLEN_192M       (6 << 3)
+#define SNB_GMCH_GMS_STOLEN_224M       (7 << 3)
+#define SNB_GMCH_GMS_STOLEN_256M       (8 << 3)
+#define SNB_GMCH_GMS_STOLEN_288M       (9 << 3)
+#define SNB_GMCH_GMS_STOLEN_320M       (0xa << 3)
+#define SNB_GMCH_GMS_STOLEN_352M       (0xb << 3)
+#define SNB_GMCH_GMS_STOLEN_384M       (0xc << 3)
+#define SNB_GMCH_GMS_STOLEN_416M       (0xd << 3)
+#define SNB_GMCH_GMS_STOLEN_448M       (0xe << 3)
+#define SNB_GMCH_GMS_STOLEN_480M       (0xf << 3)
+#define SNB_GMCH_GMS_STOLEN_512M       (0x10 << 3)
+#define SNB_GTT_SIZE_0M                        (0 << 8)
+#define SNB_GTT_SIZE_1M                        (1 << 8)
+#define SNB_GTT_SIZE_2M                        (2 << 8)
+#define SNB_GTT_SIZE_MASK              (3 << 8)
+
+/* pci devices ids */
+#define PCI_DEVICE_ID_INTEL_E7221_HB   0x2588
+#define PCI_DEVICE_ID_INTEL_E7221_IG   0x258a
+#define PCI_DEVICE_ID_INTEL_82946GZ_HB      0x2970
+#define PCI_DEVICE_ID_INTEL_82946GZ_IG      0x2972
+#define PCI_DEVICE_ID_INTEL_82G35_HB     0x2980
+#define PCI_DEVICE_ID_INTEL_82G35_IG     0x2982
+#define PCI_DEVICE_ID_INTEL_82965Q_HB       0x2990
+#define PCI_DEVICE_ID_INTEL_82965Q_IG       0x2992
+#define PCI_DEVICE_ID_INTEL_82965G_HB       0x29A0
+#define PCI_DEVICE_ID_INTEL_82965G_IG       0x29A2
+#define PCI_DEVICE_ID_INTEL_82965GM_HB      0x2A00
+#define PCI_DEVICE_ID_INTEL_82965GM_IG      0x2A02
+#define PCI_DEVICE_ID_INTEL_82965GME_HB     0x2A10
+#define PCI_DEVICE_ID_INTEL_82965GME_IG     0x2A12
+#define PCI_DEVICE_ID_INTEL_82945GME_HB     0x27AC
+#define PCI_DEVICE_ID_INTEL_82945GME_IG     0x27AE
+#define PCI_DEVICE_ID_INTEL_PINEVIEW_M_HB        0xA010
+#define PCI_DEVICE_ID_INTEL_PINEVIEW_M_IG        0xA011
+#define PCI_DEVICE_ID_INTEL_PINEVIEW_HB         0xA000
+#define PCI_DEVICE_ID_INTEL_PINEVIEW_IG         0xA001
+#define PCI_DEVICE_ID_INTEL_G33_HB          0x29C0
+#define PCI_DEVICE_ID_INTEL_G33_IG          0x29C2
+#define PCI_DEVICE_ID_INTEL_Q35_HB          0x29B0
+#define PCI_DEVICE_ID_INTEL_Q35_IG          0x29B2
+#define PCI_DEVICE_ID_INTEL_Q33_HB          0x29D0
+#define PCI_DEVICE_ID_INTEL_Q33_IG          0x29D2
+#define PCI_DEVICE_ID_INTEL_B43_HB          0x2E40
+#define PCI_DEVICE_ID_INTEL_B43_IG          0x2E42
+#define PCI_DEVICE_ID_INTEL_GM45_HB         0x2A40
+#define PCI_DEVICE_ID_INTEL_GM45_IG         0x2A42
+#define PCI_DEVICE_ID_INTEL_EAGLELAKE_HB        0x2E00
+#define PCI_DEVICE_ID_INTEL_EAGLELAKE_IG        0x2E02
+#define PCI_DEVICE_ID_INTEL_Q45_HB          0x2E10
+#define PCI_DEVICE_ID_INTEL_Q45_IG          0x2E12
+#define PCI_DEVICE_ID_INTEL_G45_HB          0x2E20
+#define PCI_DEVICE_ID_INTEL_G45_IG          0x2E22
+#define PCI_DEVICE_ID_INTEL_G41_HB          0x2E30
+#define PCI_DEVICE_ID_INTEL_G41_IG          0x2E32
+#define PCI_DEVICE_ID_INTEL_IRONLAKE_D_HB          0x0040
+#define PCI_DEVICE_ID_INTEL_IRONLAKE_D_IG          0x0042
+#define PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB          0x0044
+#define PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB         0x0062
+#define PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB    0x006a
+#define PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG          0x0046
+#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB  0x0100
+#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_IG  0x0102
+#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB  0x0104
+#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_IG  0x0106
+
+/* cover 915 and 945 variants */
+#define IS_I915 (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_E7221_HB || \
+                agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915G_HB || \
+                agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB || \
+                agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945G_HB || \
+                agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GM_HB || \
+                agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GME_HB)
+
+#define IS_I965 (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82946GZ_HB || \
+                agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82G35_HB || \
+                agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965Q_HB || \
+                agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965G_HB || \
+                agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965GM_HB || \
+                agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965GME_HB)
+
+#define IS_G33 (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_G33_HB || \
+               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_Q35_HB || \
+               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_Q33_HB || \
+               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_PINEVIEW_M_HB || \
+               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_PINEVIEW_HB)
+
+#define IS_PINEVIEW (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_PINEVIEW_M_HB || \
+               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_PINEVIEW_HB)
+
+#define IS_SNB (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB || \
+               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB)
+
+#define IS_G4X (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_EAGLELAKE_HB || \
+               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_Q45_HB || \
+               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_G45_HB || \
+               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_GM45_HB || \
+               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_G41_HB || \
+               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_B43_HB || \
+               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IRONLAKE_D_HB || \
+               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB || \
+               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB || \
+               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB || \
+               IS_SNB)
diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c
new file mode 100644 (file)
index 0000000..e8ea682
--- /dev/null
@@ -0,0 +1,1516 @@
+/*
+ * Intel GTT (Graphics Translation Table) routines
+ *
+ * Caveat: This driver implements the linux agp interface, but this is far from
+ * a agp driver! GTT support ended up here for purely historical reasons: The
+ * old userspace intel graphics drivers needed an interface to map memory into
+ * the GTT. And the drm provides a default interface for graphic devices sitting
+ * on an agp port. So it made sense to fake the GTT support as an agp port to
+ * avoid having to create a new api.
+ *
+ * With gem this does not make much sense anymore, just needlessly complicates
+ * the code. But as long as the old graphics stack is still support, it's stuck
+ * here.
+ *
+ * /fairy-tale-mode off
+ */
+
+/*
+ * If we have Intel graphics, we're not going to have anything other than
+ * an Intel IOMMU. So make the correct use of the PCI DMA API contingent
+ * on the Intel IOMMU support (CONFIG_DMAR).
+ * Only newer chipsets need to bother with this, of course.
+ */
+#ifdef CONFIG_DMAR
+#define USE_PCI_DMA_API 1
+#endif
+
+static const struct aper_size_info_fixed intel_i810_sizes[] =
+{
+       {64, 16384, 4},
+       /* The 32M mode still requires a 64k gatt */
+       {32, 8192, 4}
+};
+
+#define AGP_DCACHE_MEMORY      1
+#define AGP_PHYS_MEMORY                2
+#define INTEL_AGP_CACHED_MEMORY 3
+
+static struct gatt_mask intel_i810_masks[] =
+{
+       {.mask = I810_PTE_VALID, .type = 0},
+       {.mask = (I810_PTE_VALID | I810_PTE_LOCAL), .type = AGP_DCACHE_MEMORY},
+       {.mask = I810_PTE_VALID, .type = 0},
+       {.mask = I810_PTE_VALID | I830_PTE_SYSTEM_CACHED,
+        .type = INTEL_AGP_CACHED_MEMORY}
+};
+
+static struct _intel_private {
+       struct pci_dev *pcidev; /* device one */
+       u8 __iomem *registers;
+       u32 __iomem *gtt;               /* I915G */
+       int num_dcache_entries;
+       /* gtt_entries is the number of gtt entries that are already mapped
+        * to stolen memory.  Stolen memory is larger than the memory mapped
+        * through gtt_entries, as it includes some reserved space for the BIOS
+        * popup and for the GTT.
+        */
+       int gtt_entries;                        /* i830+ */
+       int gtt_total_size;
+       union {
+               void __iomem *i9xx_flush_page;
+               void *i8xx_flush_page;
+       };
+       struct page *i8xx_page;
+       struct resource ifp_resource;
+       int resource_valid;
+} intel_private;
+
+#ifdef USE_PCI_DMA_API
+static int intel_agp_map_page(struct page *page, dma_addr_t *ret)
+{
+       *ret = pci_map_page(intel_private.pcidev, page, 0,
+                           PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
+       if (pci_dma_mapping_error(intel_private.pcidev, *ret))
+               return -EINVAL;
+       return 0;
+}
+
+static void intel_agp_unmap_page(struct page *page, dma_addr_t dma)
+{
+       pci_unmap_page(intel_private.pcidev, dma,
+                      PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
+}
+
+static void intel_agp_free_sglist(struct agp_memory *mem)
+{
+       struct sg_table st;
+
+       st.sgl = mem->sg_list;
+       st.orig_nents = st.nents = mem->page_count;
+
+       sg_free_table(&st);
+
+       mem->sg_list = NULL;
+       mem->num_sg = 0;
+}
+
+static int intel_agp_map_memory(struct agp_memory *mem)
+{
+       struct sg_table st;
+       struct scatterlist *sg;
+       int i;
+
+       DBG("try mapping %lu pages\n", (unsigned long)mem->page_count);
+
+       if (sg_alloc_table(&st, mem->page_count, GFP_KERNEL))
+               return -ENOMEM;
+
+       mem->sg_list = sg = st.sgl;
+
+       for (i = 0 ; i < mem->page_count; i++, sg = sg_next(sg))
+               sg_set_page(sg, mem->pages[i], PAGE_SIZE, 0);
+
+       mem->num_sg = pci_map_sg(intel_private.pcidev, mem->sg_list,
+                                mem->page_count, PCI_DMA_BIDIRECTIONAL);
+       if (unlikely(!mem->num_sg)) {
+               intel_agp_free_sglist(mem);
+               return -ENOMEM;
+       }
+       return 0;
+}
+
+static void intel_agp_unmap_memory(struct agp_memory *mem)
+{
+       DBG("try unmapping %lu pages\n", (unsigned long)mem->page_count);
+
+       pci_unmap_sg(intel_private.pcidev, mem->sg_list,
+                    mem->page_count, PCI_DMA_BIDIRECTIONAL);
+       intel_agp_free_sglist(mem);
+}
+
+static void intel_agp_insert_sg_entries(struct agp_memory *mem,
+                                       off_t pg_start, int mask_type)
+{
+       struct scatterlist *sg;
+       int i, j;
+
+       j = pg_start;
+
+       WARN_ON(!mem->num_sg);
+
+       if (mem->num_sg == mem->page_count) {
+               for_each_sg(mem->sg_list, sg, mem->page_count, i) {
+                       writel(agp_bridge->driver->mask_memory(agp_bridge,
+                                       sg_dma_address(sg), mask_type),
+                                       intel_private.gtt+j);
+                       j++;
+               }
+       } else {
+               /* sg may merge pages, but we have to separate
+                * per-page addr for GTT */
+               unsigned int len, m;
+
+               for_each_sg(mem->sg_list, sg, mem->num_sg, i) {
+                       len = sg_dma_len(sg) / PAGE_SIZE;
+                       for (m = 0; m < len; m++) {
+                               writel(agp_bridge->driver->mask_memory(agp_bridge,
+                                                                      sg_dma_address(sg) + m * PAGE_SIZE,
+                                                                      mask_type),
+                                      intel_private.gtt+j);
+                               j++;
+                       }
+               }
+       }
+       readl(intel_private.gtt+j-1);
+}
+
+#else
+
+static void intel_agp_insert_sg_entries(struct agp_memory *mem,
+                                       off_t pg_start, int mask_type)
+{
+       int i, j;
+       u32 cache_bits = 0;
+
+       if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB ||
+           agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB)
+       {
+               cache_bits = I830_PTE_SYSTEM_CACHED;
+       }
+
+       for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
+               writel(agp_bridge->driver->mask_memory(agp_bridge,
+                               page_to_phys(mem->pages[i]), mask_type),
+                      intel_private.gtt+j);
+       }
+
+       readl(intel_private.gtt+j-1);
+}
+
+#endif
+
+static int intel_i810_fetch_size(void)
+{
+       u32 smram_miscc;
+       struct aper_size_info_fixed *values;
+
+       pci_read_config_dword(agp_bridge->dev, I810_SMRAM_MISCC, &smram_miscc);
+       values = A_SIZE_FIX(agp_bridge->driver->aperture_sizes);
+
+       if ((smram_miscc & I810_GMS) == I810_GMS_DISABLE) {
+               dev_warn(&agp_bridge->dev->dev, "i810 is disabled\n");
+               return 0;
+       }
+       if ((smram_miscc & I810_GFX_MEM_WIN_SIZE) == I810_GFX_MEM_WIN_32M) {
+               agp_bridge->current_size = (void *) (values + 1);
+               agp_bridge->aperture_size_idx = 1;
+               return values[1].size;
+       } else {
+               agp_bridge->current_size = (void *) (values);
+               agp_bridge->aperture_size_idx = 0;
+               return values[0].size;
+       }
+
+       return 0;
+}
+
+static int intel_i810_configure(void)
+{
+       struct aper_size_info_fixed *current_size;
+       u32 temp;
+       int i;
+
+       current_size = A_SIZE_FIX(agp_bridge->current_size);
+
+       if (!intel_private.registers) {
+               pci_read_config_dword(intel_private.pcidev, I810_MMADDR, &temp);
+               temp &= 0xfff80000;
+
+               intel_private.registers = ioremap(temp, 128 * 4096);
+               if (!intel_private.registers) {
+                       dev_err(&intel_private.pcidev->dev,
+                               "can't remap memory\n");
+                       return -ENOMEM;
+               }
+       }
+
+       if ((readl(intel_private.registers+I810_DRAM_CTL)
+               & I810_DRAM_ROW_0) == I810_DRAM_ROW_0_SDRAM) {
+               /* This will need to be dynamically assigned */
+               dev_info(&intel_private.pcidev->dev,
+                        "detected 4MB dedicated video ram\n");
+               intel_private.num_dcache_entries = 1024;
+       }
+       pci_read_config_dword(intel_private.pcidev, I810_GMADDR, &temp);
+       agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
+       writel(agp_bridge->gatt_bus_addr | I810_PGETBL_ENABLED, intel_private.registers+I810_PGETBL_CTL);
+       readl(intel_private.registers+I810_PGETBL_CTL); /* PCI Posting. */
+
+       if (agp_bridge->driver->needs_scratch_page) {
+               for (i = 0; i < current_size->num_entries; i++) {
+                       writel(agp_bridge->scratch_page, intel_private.registers+I810_PTE_BASE+(i*4));
+               }
+               readl(intel_private.registers+I810_PTE_BASE+((i-1)*4)); /* PCI posting. */
+       }
+       global_cache_flush();
+       return 0;
+}
+
+static void intel_i810_cleanup(void)
+{
+       writel(0, intel_private.registers+I810_PGETBL_CTL);
+       readl(intel_private.registers); /* PCI Posting. */
+       iounmap(intel_private.registers);
+}
+
+static void intel_i810_agp_enable(struct agp_bridge_data *bridge, u32 mode)
+{
+       return;
+}
+
+/* Exists to support ARGB cursors */
+static struct page *i8xx_alloc_pages(void)
+{
+       struct page *page;
+
+       page = alloc_pages(GFP_KERNEL | GFP_DMA32, 2);
+       if (page == NULL)
+               return NULL;
+
+       if (set_pages_uc(page, 4) < 0) {
+               set_pages_wb(page, 4);
+               __free_pages(page, 2);
+               return NULL;
+       }
+       get_page(page);
+       atomic_inc(&agp_bridge->current_memory_agp);
+       return page;
+}
+
+static void i8xx_destroy_pages(struct page *page)
+{
+       if (page == NULL)
+               return;
+
+       set_pages_wb(page, 4);
+       put_page(page);
+       __free_pages(page, 2);
+       atomic_dec(&agp_bridge->current_memory_agp);
+}
+
+static int intel_i830_type_to_mask_type(struct agp_bridge_data *bridge,
+                                       int type)
+{
+       if (type < AGP_USER_TYPES)
+               return type;
+       else if (type == AGP_USER_CACHED_MEMORY)
+               return INTEL_AGP_CACHED_MEMORY;
+       else
+               return 0;
+}
+
+static int intel_i810_insert_entries(struct agp_memory *mem, off_t pg_start,
+                               int type)
+{
+       int i, j, num_entries;
+       void *temp;
+       int ret = -EINVAL;
+       int mask_type;
+
+       if (mem->page_count == 0)
+               goto out;
+
+       temp = agp_bridge->current_size;
+       num_entries = A_SIZE_FIX(temp)->num_entries;
+
+       if ((pg_start + mem->page_count) > num_entries)
+               goto out_err;
+
+
+       for (j = pg_start; j < (pg_start + mem->page_count); j++) {
+               if (!PGE_EMPTY(agp_bridge, readl(agp_bridge->gatt_table+j))) {
+                       ret = -EBUSY;
+                       goto out_err;
+               }
+       }
+
+       if (type != mem->type)
+               goto out_err;
+
+       mask_type = agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type);
+
+       switch (mask_type) {
+       case AGP_DCACHE_MEMORY:
+               if (!mem->is_flushed)
+                       global_cache_flush();
+               for (i = pg_start; i < (pg_start + mem->page_count); i++) {
+                       writel((i*4096)|I810_PTE_LOCAL|I810_PTE_VALID,
+                              intel_private.registers+I810_PTE_BASE+(i*4));
+               }
+               readl(intel_private.registers+I810_PTE_BASE+((i-1)*4));
+               break;
+       case AGP_PHYS_MEMORY:
+       case AGP_NORMAL_MEMORY:
+               if (!mem->is_flushed)
+                       global_cache_flush();
+               for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
+                       writel(agp_bridge->driver->mask_memory(agp_bridge,
+                                       page_to_phys(mem->pages[i]), mask_type),
+                              intel_private.registers+I810_PTE_BASE+(j*4));
+               }
+               readl(intel_private.registers+I810_PTE_BASE+((j-1)*4));
+               break;
+       default:
+               goto out_err;
+       }
+
+out:
+       ret = 0;
+out_err:
+       mem->is_flushed = true;
+       return ret;
+}
+
+static int intel_i810_remove_entries(struct agp_memory *mem, off_t pg_start,
+                               int type)
+{
+       int i;
+
+       if (mem->page_count == 0)
+               return 0;
+
+       for (i = pg_start; i < (mem->page_count + pg_start); i++) {
+               writel(agp_bridge->scratch_page, intel_private.registers+I810_PTE_BASE+(i*4));
+       }
+       readl(intel_private.registers+I810_PTE_BASE+((i-1)*4));
+
+       return 0;
+}
+
+/*
+ * The i810/i830 requires a physical address to program its mouse
+ * pointer into hardware.
+ * However the Xserver still writes to it through the agp aperture.
+ */
+static struct agp_memory *alloc_agpphysmem_i8xx(size_t pg_count, int type)
+{
+       struct agp_memory *new;
+       struct page *page;
+
+       switch (pg_count) {
+       case 1: page = agp_bridge->driver->agp_alloc_page(agp_bridge);
+               break;
+       case 4:
+               /* kludge to get 4 physical pages for ARGB cursor */
+               page = i8xx_alloc_pages();
+               break;
+       default:
+               return NULL;
+       }
+
+       if (page == NULL)
+               return NULL;
+
+       new = agp_create_memory(pg_count);
+       if (new == NULL)
+               return NULL;
+
+       new->pages[0] = page;
+       if (pg_count == 4) {
+               /* kludge to get 4 physical pages for ARGB cursor */
+               new->pages[1] = new->pages[0] + 1;
+               new->pages[2] = new->pages[1] + 1;
+               new->pages[3] = new->pages[2] + 1;
+       }
+       new->page_count = pg_count;
+       new->num_scratch_pages = pg_count;
+       new->type = AGP_PHYS_MEMORY;
+       new->physical = page_to_phys(new->pages[0]);
+       return new;
+}
+
+static struct agp_memory *intel_i810_alloc_by_type(size_t pg_count, int type)
+{
+       struct agp_memory *new;
+
+       if (type == AGP_DCACHE_MEMORY) {
+               if (pg_count != intel_private.num_dcache_entries)
+                       return NULL;
+
+               new = agp_create_memory(1);
+               if (new == NULL)
+                       return NULL;
+
+               new->type = AGP_DCACHE_MEMORY;
+               new->page_count = pg_count;
+               new->num_scratch_pages = 0;
+               agp_free_page_array(new);
+               return new;
+       }
+       if (type == AGP_PHYS_MEMORY)
+               return alloc_agpphysmem_i8xx(pg_count, type);
+       return NULL;
+}
+
+static void intel_i810_free_by_type(struct agp_memory *curr)
+{
+       agp_free_key(curr->key);
+       if (curr->type == AGP_PHYS_MEMORY) {
+               if (curr->page_count == 4)
+                       i8xx_destroy_pages(curr->pages[0]);
+               else {
+                       agp_bridge->driver->agp_destroy_page(curr->pages[0],
+                                                            AGP_PAGE_DESTROY_UNMAP);
+                       agp_bridge->driver->agp_destroy_page(curr->pages[0],
+                                                            AGP_PAGE_DESTROY_FREE);
+               }
+               agp_free_page_array(curr);
+       }
+       kfree(curr);
+}
+
+static unsigned long intel_i810_mask_memory(struct agp_bridge_data *bridge,
+                                           dma_addr_t addr, int type)
+{
+       /* Type checking must be done elsewhere */
+       return addr | bridge->driver->masks[type].mask;
+}
+
+static struct aper_size_info_fixed intel_i830_sizes[] =
+{
+       {128, 32768, 5},
+       /* The 64M mode still requires a 128k gatt */
+       {64, 16384, 5},
+       {256, 65536, 6},
+       {512, 131072, 7},
+};
+
+static void intel_i830_init_gtt_entries(void)
+{
+       u16 gmch_ctrl;
+       int gtt_entries = 0;
+       u8 rdct;
+       int local = 0;
+       static const int ddt[4] = { 0, 16, 32, 64 };
+       int size; /* reserved space (in kb) at the top of stolen memory */
+
+       pci_read_config_word(agp_bridge->dev, I830_GMCH_CTRL, &gmch_ctrl);
+
+       if (IS_I965) {
+               u32 pgetbl_ctl;
+               pgetbl_ctl = readl(intel_private.registers+I810_PGETBL_CTL);
+
+               /* The 965 has a field telling us the size of the GTT,
+                * which may be larger than what is necessary to map the
+                * aperture.
+                */
+               switch (pgetbl_ctl & I965_PGETBL_SIZE_MASK) {
+               case I965_PGETBL_SIZE_128KB:
+                       size = 128;
+                       break;
+               case I965_PGETBL_SIZE_256KB:
+                       size = 256;
+                       break;
+               case I965_PGETBL_SIZE_512KB:
+                       size = 512;
+                       break;
+               case I965_PGETBL_SIZE_1MB:
+                       size = 1024;
+                       break;
+               case I965_PGETBL_SIZE_2MB:
+                       size = 2048;
+                       break;
+               case I965_PGETBL_SIZE_1_5MB:
+                       size = 1024 + 512;
+                       break;
+               default:
+                       dev_info(&intel_private.pcidev->dev,
+                                "unknown page table size, assuming 512KB\n");
+                       size = 512;
+               }
+               size += 4; /* add in BIOS popup space */
+       } else if (IS_G33 && !IS_PINEVIEW) {
+       /* G33's GTT size defined in gmch_ctrl */
+               switch (gmch_ctrl & G33_PGETBL_SIZE_MASK) {
+               case G33_PGETBL_SIZE_1M:
+                       size = 1024;
+                       break;
+               case G33_PGETBL_SIZE_2M:
+                       size = 2048;
+                       break;
+               default:
+                       dev_info(&agp_bridge->dev->dev,
+                                "unknown page table size 0x%x, assuming 512KB\n",
+                               (gmch_ctrl & G33_PGETBL_SIZE_MASK));
+                       size = 512;
+               }
+               size += 4;
+       } else if (IS_G4X || IS_PINEVIEW) {
+               /* On 4 series hardware, GTT stolen is separate from graphics
+                * stolen, ignore it in stolen gtt entries counting.  However,
+                * 4KB of the stolen memory doesn't get mapped to the GTT.
+                */
+               size = 4;
+       } else {
+               /* On previous hardware, the GTT size was just what was
+                * required to map the aperture.
+                */
+               size = agp_bridge->driver->fetch_size() + 4;
+       }
+
+       if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82830_HB ||
+           agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82845G_HB) {
+               switch (gmch_ctrl & I830_GMCH_GMS_MASK) {
+               case I830_GMCH_GMS_STOLEN_512:
+                       gtt_entries = KB(512) - KB(size);
+                       break;
+               case I830_GMCH_GMS_STOLEN_1024:
+                       gtt_entries = MB(1) - KB(size);
+                       break;
+               case I830_GMCH_GMS_STOLEN_8192:
+                       gtt_entries = MB(8) - KB(size);
+                       break;
+               case I830_GMCH_GMS_LOCAL:
+                       rdct = readb(intel_private.registers+I830_RDRAM_CHANNEL_TYPE);
+                       gtt_entries = (I830_RDRAM_ND(rdct) + 1) *
+                                       MB(ddt[I830_RDRAM_DDT(rdct)]);
+                       local = 1;
+                       break;
+               default:
+                       gtt_entries = 0;
+                       break;
+               }
+       } else if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB ||
+                  agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB) {
+               /*
+                * SandyBridge has new memory control reg at 0x50.w
+                */
+               u16 snb_gmch_ctl;
+               pci_read_config_word(intel_private.pcidev, SNB_GMCH_CTRL, &snb_gmch_ctl);
+               switch (snb_gmch_ctl & SNB_GMCH_GMS_STOLEN_MASK) {
+               case SNB_GMCH_GMS_STOLEN_32M:
+                       gtt_entries = MB(32) - KB(size);
+                       break;
+               case SNB_GMCH_GMS_STOLEN_64M:
+                       gtt_entries = MB(64) - KB(size);
+                       break;
+               case SNB_GMCH_GMS_STOLEN_96M:
+                       gtt_entries = MB(96) - KB(size);
+                       break;
+               case SNB_GMCH_GMS_STOLEN_128M:
+                       gtt_entries = MB(128) - KB(size);
+                       break;
+               case SNB_GMCH_GMS_STOLEN_160M:
+                       gtt_entries = MB(160) - KB(size);
+                       break;
+               case SNB_GMCH_GMS_STOLEN_192M:
+                       gtt_entries = MB(192) - KB(size);
+                       break;
+               case SNB_GMCH_GMS_STOLEN_224M:
+                       gtt_entries = MB(224) - KB(size);
+                       break;
+               case SNB_GMCH_GMS_STOLEN_256M:
+                       gtt_entries = MB(256) - KB(size);
+                       break;
+               case SNB_GMCH_GMS_STOLEN_288M:
+                       gtt_entries = MB(288) - KB(size);
+                       break;
+               case SNB_GMCH_GMS_STOLEN_320M:
+                       gtt_entries = MB(320) - KB(size);
+                       break;
+               case SNB_GMCH_GMS_STOLEN_352M:
+                       gtt_entries = MB(352) - KB(size);
+                       break;
+               case SNB_GMCH_GMS_STOLEN_384M:
+                       gtt_entries = MB(384) - KB(size);
+                       break;
+               case SNB_GMCH_GMS_STOLEN_416M:
+                       gtt_entries = MB(416) - KB(size);
+                       break;
+               case SNB_GMCH_GMS_STOLEN_448M:
+                       gtt_entries = MB(448) - KB(size);
+                       break;
+               case SNB_GMCH_GMS_STOLEN_480M:
+                       gtt_entries = MB(480) - KB(size);
+                       break;
+               case SNB_GMCH_GMS_STOLEN_512M:
+                       gtt_entries = MB(512) - KB(size);
+                       break;
+               }
+       } else {
+               switch (gmch_ctrl & I855_GMCH_GMS_MASK) {
+               case I855_GMCH_GMS_STOLEN_1M:
+                       gtt_entries = MB(1) - KB(size);
+                       break;
+               case I855_GMCH_GMS_STOLEN_4M:
+                       gtt_entries = MB(4) - KB(size);
+                       break;
+               case I855_GMCH_GMS_STOLEN_8M:
+                       gtt_entries = MB(8) - KB(size);
+                       break;
+               case I855_GMCH_GMS_STOLEN_16M:
+                       gtt_entries = MB(16) - KB(size);
+                       break;
+               case I855_GMCH_GMS_STOLEN_32M:
+                       gtt_entries = MB(32) - KB(size);
+                       break;
+               case I915_GMCH_GMS_STOLEN_48M:
+                       /* Check it's really I915G */
+                       if (IS_I915 || IS_I965 || IS_G33 || IS_G4X)
+                               gtt_entries = MB(48) - KB(size);
+                       else
+                               gtt_entries = 0;
+                       break;
+               case I915_GMCH_GMS_STOLEN_64M:
+                       /* Check it's really I915G */
+                       if (IS_I915 || IS_I965 || IS_G33 || IS_G4X)
+                               gtt_entries = MB(64) - KB(size);
+                       else
+                               gtt_entries = 0;
+                       break;
+               case G33_GMCH_GMS_STOLEN_128M:
+                       if (IS_G33 || IS_I965 || IS_G4X)
+                               gtt_entries = MB(128) - KB(size);
+                       else
+                               gtt_entries = 0;
+                       break;
+               case G33_GMCH_GMS_STOLEN_256M:
+                       if (IS_G33 || IS_I965 || IS_G4X)
+                               gtt_entries = MB(256) - KB(size);
+                       else
+                               gtt_entries = 0;
+                       break;
+               case INTEL_GMCH_GMS_STOLEN_96M:
+                       if (IS_I965 || IS_G4X)
+                               gtt_entries = MB(96) - KB(size);
+                       else
+                               gtt_entries = 0;
+                       break;
+               case INTEL_GMCH_GMS_STOLEN_160M:
+                       if (IS_I965 || IS_G4X)
+                               gtt_entries = MB(160) - KB(size);
+                       else
+                               gtt_entries = 0;
+                       break;
+               case INTEL_GMCH_GMS_STOLEN_224M:
+                       if (IS_I965 || IS_G4X)
+                               gtt_entries = MB(224) - KB(size);
+                       else
+                               gtt_entries = 0;
+                       break;
+               case INTEL_GMCH_GMS_STOLEN_352M:
+                       if (IS_I965 || IS_G4X)
+                               gtt_entries = MB(352) - KB(size);
+                       else
+                               gtt_entries = 0;
+                       break;
+               default:
+                       gtt_entries = 0;
+                       break;
+               }
+       }
+       if (gtt_entries > 0) {
+               dev_info(&agp_bridge->dev->dev, "detected %dK %s memory\n",
+                      gtt_entries / KB(1), local ? "local" : "stolen");
+               gtt_entries /= KB(4);
+       } else {
+               dev_info(&agp_bridge->dev->dev,
+                      "no pre-allocated video memory detected\n");
+               gtt_entries = 0;
+       }
+
+       intel_private.gtt_entries = gtt_entries;
+}
+
+static void intel_i830_fini_flush(void)
+{
+       kunmap(intel_private.i8xx_page);
+       intel_private.i8xx_flush_page = NULL;
+       unmap_page_from_agp(intel_private.i8xx_page);
+
+       __free_page(intel_private.i8xx_page);
+       intel_private.i8xx_page = NULL;
+}
+
+static void intel_i830_setup_flush(void)
+{
+       /* return if we've already set the flush mechanism up */
+       if (intel_private.i8xx_page)
+               return;
+
+       intel_private.i8xx_page = alloc_page(GFP_KERNEL | __GFP_ZERO | GFP_DMA32);
+       if (!intel_private.i8xx_page)
+               return;
+
+       intel_private.i8xx_flush_page = kmap(intel_private.i8xx_page);
+       if (!intel_private.i8xx_flush_page)
+               intel_i830_fini_flush();
+}
+
+/* The chipset_flush interface needs to get data that has already been
+ * flushed out of the CPU all the way out to main memory, because the GPU
+ * doesn't snoop those buffers.
+ *
+ * The 8xx series doesn't have the same lovely interface for flushing the
+ * chipset write buffers that the later chips do. According to the 865
+ * specs, it's 64 octwords, or 1KB.  So, to get those previous things in
+ * that buffer out, we just fill 1KB and clflush it out, on the assumption
+ * that it'll push whatever was in there out.  It appears to work.
+ */
+static void intel_i830_chipset_flush(struct agp_bridge_data *bridge)
+{
+       unsigned int *pg = intel_private.i8xx_flush_page;
+
+       memset(pg, 0, 1024);
+
+       if (cpu_has_clflush)
+               clflush_cache_range(pg, 1024);
+       else if (wbinvd_on_all_cpus() != 0)
+               printk(KERN_ERR "Timed out waiting for cache flush.\n");
+}
+
+/* The intel i830 automatically initializes the agp aperture during POST.
+ * Use the memory already set aside for in the GTT.
+ */
+static int intel_i830_create_gatt_table(struct agp_bridge_data *bridge)
+{
+       int page_order;
+       struct aper_size_info_fixed *size;
+       int num_entries;
+       u32 temp;
+
+       size = agp_bridge->current_size;
+       page_order = size->page_order;
+       num_entries = size->num_entries;
+       agp_bridge->gatt_table_real = NULL;
+
+       pci_read_config_dword(intel_private.pcidev, I810_MMADDR, &temp);
+       temp &= 0xfff80000;
+
+       intel_private.registers = ioremap(temp, 128 * 4096);
+       if (!intel_private.registers)
+               return -ENOMEM;
+
+       temp = readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000;
+       global_cache_flush();   /* FIXME: ?? */
+
+       /* we have to call this as early as possible after the MMIO base address is known */
+       intel_i830_init_gtt_entries();
+
+       agp_bridge->gatt_table = NULL;
+
+       agp_bridge->gatt_bus_addr = temp;
+
+       return 0;
+}
+
+/* Return the gatt table to a sane state. Use the top of stolen
+ * memory for the GTT.
+ */
+static int intel_i830_free_gatt_table(struct agp_bridge_data *bridge)
+{
+       return 0;
+}
+
+static int intel_i830_fetch_size(void)
+{
+       u16 gmch_ctrl;
+       struct aper_size_info_fixed *values;
+
+       values = A_SIZE_FIX(agp_bridge->driver->aperture_sizes);
+
+       if (agp_bridge->dev->device != PCI_DEVICE_ID_INTEL_82830_HB &&
+           agp_bridge->dev->device != PCI_DEVICE_ID_INTEL_82845G_HB) {
+               /* 855GM/852GM/865G has 128MB aperture size */
+               agp_bridge->current_size = (void *) values;
+               agp_bridge->aperture_size_idx = 0;
+               return values[0].size;
+       }
+
+       pci_read_config_word(agp_bridge->dev, I830_GMCH_CTRL, &gmch_ctrl);
+
+       if ((gmch_ctrl & I830_GMCH_MEM_MASK) == I830_GMCH_MEM_128M) {
+               agp_bridge->current_size = (void *) values;
+               agp_bridge->aperture_size_idx = 0;
+               return values[0].size;
+       } else {
+               agp_bridge->current_size = (void *) (values + 1);
+               agp_bridge->aperture_size_idx = 1;
+               return values[1].size;
+       }
+
+       return 0;
+}
+
+static int intel_i830_configure(void)
+{
+       struct aper_size_info_fixed *current_size;
+       u32 temp;
+       u16 gmch_ctrl;
+       int i;
+
+       current_size = A_SIZE_FIX(agp_bridge->current_size);
+
+       pci_read_config_dword(intel_private.pcidev, I810_GMADDR, &temp);
+       agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
+
+       pci_read_config_word(agp_bridge->dev, I830_GMCH_CTRL, &gmch_ctrl);
+       gmch_ctrl |= I830_GMCH_ENABLED;
+       pci_write_config_word(agp_bridge->dev, I830_GMCH_CTRL, gmch_ctrl);
+
+       writel(agp_bridge->gatt_bus_addr|I810_PGETBL_ENABLED, intel_private.registers+I810_PGETBL_CTL);
+       readl(intel_private.registers+I810_PGETBL_CTL); /* PCI Posting. */
+
+       if (agp_bridge->driver->needs_scratch_page) {
+               for (i = intel_private.gtt_entries; i < current_size->num_entries; i++) {
+                       writel(agp_bridge->scratch_page, intel_private.registers+I810_PTE_BASE+(i*4));
+               }
+               readl(intel_private.registers+I810_PTE_BASE+((i-1)*4)); /* PCI Posting. */
+       }
+
+       global_cache_flush();
+
+       intel_i830_setup_flush();
+       return 0;
+}
+
+static void intel_i830_cleanup(void)
+{
+       iounmap(intel_private.registers);
+}
+
+static int intel_i830_insert_entries(struct agp_memory *mem, off_t pg_start,
+                                    int type)
+{
+       int i, j, num_entries;
+       void *temp;
+       int ret = -EINVAL;
+       int mask_type;
+
+       if (mem->page_count == 0)
+               goto out;
+
+       temp = agp_bridge->current_size;
+       num_entries = A_SIZE_FIX(temp)->num_entries;
+
+       if (pg_start < intel_private.gtt_entries) {
+               dev_printk(KERN_DEBUG, &intel_private.pcidev->dev,
+                          "pg_start == 0x%.8lx, intel_private.gtt_entries == 0x%.8x\n",
+                          pg_start, intel_private.gtt_entries);
+
+               dev_info(&intel_private.pcidev->dev,
+                        "trying to insert into local/stolen memory\n");
+               goto out_err;
+       }
+
+       if ((pg_start + mem->page_count) > num_entries)
+               goto out_err;
+
+       /* The i830 can't check the GTT for entries since its read only,
+        * depend on the caller to make the correct offset decisions.
+        */
+
+       if (type != mem->type)
+               goto out_err;
+
+       mask_type = agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type);
+
+       if (mask_type != 0 && mask_type != AGP_PHYS_MEMORY &&
+           mask_type != INTEL_AGP_CACHED_MEMORY)
+               goto out_err;
+
+       if (!mem->is_flushed)
+               global_cache_flush();
+
+       for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
+               writel(agp_bridge->driver->mask_memory(agp_bridge,
+                               page_to_phys(mem->pages[i]), mask_type),
+                      intel_private.registers+I810_PTE_BASE+(j*4));
+       }
+       readl(intel_private.registers+I810_PTE_BASE+((j-1)*4));
+
+out:
+       ret = 0;
+out_err:
+       mem->is_flushed = true;
+       return ret;
+}
+
+static int intel_i830_remove_entries(struct agp_memory *mem, off_t pg_start,
+                                    int type)
+{
+       int i;
+
+       if (mem->page_count == 0)
+               return 0;
+
+       if (pg_start < intel_private.gtt_entries) {
+               dev_info(&intel_private.pcidev->dev,
+                        "trying to disable local/stolen memory\n");
+               return -EINVAL;
+       }
+
+       for (i = pg_start; i < (mem->page_count + pg_start); i++) {
+               writel(agp_bridge->scratch_page, intel_private.registers+I810_PTE_BASE+(i*4));
+       }
+       readl(intel_private.registers+I810_PTE_BASE+((i-1)*4));
+
+       return 0;
+}
+
+static struct agp_memory *intel_i830_alloc_by_type(size_t pg_count, int type)
+{
+       if (type == AGP_PHYS_MEMORY)
+               return alloc_agpphysmem_i8xx(pg_count, type);
+       /* always return NULL for other allocation types for now */
+       return NULL;
+}
+
+static int intel_alloc_chipset_flush_resource(void)
+{
+       int ret;
+       ret = pci_bus_alloc_resource(agp_bridge->dev->bus, &intel_private.ifp_resource, PAGE_SIZE,
+                                    PAGE_SIZE, PCIBIOS_MIN_MEM, 0,
+                                    pcibios_align_resource, agp_bridge->dev);
+
+       return ret;
+}
+
+static void intel_i915_setup_chipset_flush(void)
+{
+       int ret;
+       u32 temp;
+
+       pci_read_config_dword(agp_bridge->dev, I915_IFPADDR, &temp);
+       if (!(temp & 0x1)) {
+               intel_alloc_chipset_flush_resource();
+               intel_private.resource_valid = 1;
+               pci_write_config_dword(agp_bridge->dev, I915_IFPADDR, (intel_private.ifp_resource.start & 0xffffffff) | 0x1);
+       } else {
+               temp &= ~1;
+
+               intel_private.resource_valid = 1;
+               intel_private.ifp_resource.start = temp;
+               intel_private.ifp_resource.end = temp + PAGE_SIZE;
+               ret = request_resource(&iomem_resource, &intel_private.ifp_resource);
+               /* some BIOSes reserve this area in a pnp some don't */
+               if (ret)
+                       intel_private.resource_valid = 0;
+       }
+}
+
+static void intel_i965_g33_setup_chipset_flush(void)
+{
+       u32 temp_hi, temp_lo;
+       int ret;
+
+       pci_read_config_dword(agp_bridge->dev, I965_IFPADDR + 4, &temp_hi);
+       pci_read_config_dword(agp_bridge->dev, I965_IFPADDR, &temp_lo);
+
+       if (!(temp_lo & 0x1)) {
+
+               intel_alloc_chipset_flush_resource();
+
+               intel_private.resource_valid = 1;
+               pci_write_config_dword(agp_bridge->dev, I965_IFPADDR + 4,
+                       upper_32_bits(intel_private.ifp_resource.start));
+               pci_write_config_dword(agp_bridge->dev, I965_IFPADDR, (intel_private.ifp_resource.start & 0xffffffff) | 0x1);
+       } else {
+               u64 l64;
+
+               temp_lo &= ~0x1;
+               l64 = ((u64)temp_hi << 32) | temp_lo;
+
+               intel_private.resource_valid = 1;
+               intel_private.ifp_resource.start = l64;
+               intel_private.ifp_resource.end = l64 + PAGE_SIZE;
+               ret = request_resource(&iomem_resource, &intel_private.ifp_resource);
+               /* some BIOSes reserve this area in a pnp some don't */
+               if (ret)
+                       intel_private.resource_valid = 0;
+       }
+}
+
+static void intel_i9xx_setup_flush(void)
+{
+       /* return if already configured */
+       if (intel_private.ifp_resource.start)
+               return;
+
+       if (IS_SNB)
+               return;
+
+       /* setup a resource for this object */
+       intel_private.ifp_resource.name = "Intel Flush Page";
+       intel_private.ifp_resource.flags = IORESOURCE_MEM;
+
+       /* Setup chipset flush for 915 */
+       if (IS_I965 || IS_G33 || IS_G4X) {
+               intel_i965_g33_setup_chipset_flush();
+       } else {
+               intel_i915_setup_chipset_flush();
+       }
+
+       if (intel_private.ifp_resource.start) {
+               intel_private.i9xx_flush_page = ioremap_nocache(intel_private.ifp_resource.start, PAGE_SIZE);
+               if (!intel_private.i9xx_flush_page)
+                       dev_info(&intel_private.pcidev->dev, "can't ioremap flush page - no chipset flushing");
+       }
+}
+
+static int intel_i915_configure(void)
+{
+       struct aper_size_info_fixed *current_size;
+       u32 temp;
+       u16 gmch_ctrl;
+       int i;
+
+       current_size = A_SIZE_FIX(agp_bridge->current_size);
+
+       pci_read_config_dword(intel_private.pcidev, I915_GMADDR, &temp);
+
+       agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
+
+       pci_read_config_word(agp_bridge->dev, I830_GMCH_CTRL, &gmch_ctrl);
+       gmch_ctrl |= I830_GMCH_ENABLED;
+       pci_write_config_word(agp_bridge->dev, I830_GMCH_CTRL, gmch_ctrl);
+
+       writel(agp_bridge->gatt_bus_addr|I810_PGETBL_ENABLED, intel_private.registers+I810_PGETBL_CTL);
+       readl(intel_private.registers+I810_PGETBL_CTL); /* PCI Posting. */
+
+       if (agp_bridge->driver->needs_scratch_page) {
+               for (i = intel_private.gtt_entries; i < intel_private.gtt_total_size; i++) {
+                       writel(agp_bridge->scratch_page, intel_private.gtt+i);
+               }
+               readl(intel_private.gtt+i-1);   /* PCI Posting. */
+       }
+
+       global_cache_flush();
+
+       intel_i9xx_setup_flush();
+
+       return 0;
+}
+
+static void intel_i915_cleanup(void)
+{
+       if (intel_private.i9xx_flush_page)
+               iounmap(intel_private.i9xx_flush_page);
+       if (intel_private.resource_valid)
+               release_resource(&intel_private.ifp_resource);
+       intel_private.ifp_resource.start = 0;
+       intel_private.resource_valid = 0;
+       iounmap(intel_private.gtt);
+       iounmap(intel_private.registers);
+}
+
+static void intel_i915_chipset_flush(struct agp_bridge_data *bridge)
+{
+       if (intel_private.i9xx_flush_page)
+               writel(1, intel_private.i9xx_flush_page);
+}
+
+static int intel_i915_insert_entries(struct agp_memory *mem, off_t pg_start,
+                                    int type)
+{
+       int num_entries;
+       void *temp;
+       int ret = -EINVAL;
+       int mask_type;
+
+       if (mem->page_count == 0)
+               goto out;
+
+       temp = agp_bridge->current_size;
+       num_entries = A_SIZE_FIX(temp)->num_entries;
+
+       if (pg_start < intel_private.gtt_entries) {
+               dev_printk(KERN_DEBUG, &intel_private.pcidev->dev,
+                          "pg_start == 0x%.8lx, intel_private.gtt_entries == 0x%.8x\n",
+                          pg_start, intel_private.gtt_entries);
+
+               dev_info(&intel_private.pcidev->dev,
+                        "trying to insert into local/stolen memory\n");
+               goto out_err;
+       }
+
+       if ((pg_start + mem->page_count) > num_entries)
+               goto out_err;
+
+       /* The i915 can't check the GTT for entries since it's read only;
+        * depend on the caller to make the correct offset decisions.
+        */
+
+       if (type != mem->type)
+               goto out_err;
+
+       mask_type = agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type);
+
+       if (mask_type != 0 && mask_type != AGP_PHYS_MEMORY &&
+           mask_type != INTEL_AGP_CACHED_MEMORY)
+               goto out_err;
+
+       if (!mem->is_flushed)
+               global_cache_flush();
+
+       intel_agp_insert_sg_entries(mem, pg_start, mask_type);
+
+ out:
+       ret = 0;
+ out_err:
+       mem->is_flushed = true;
+       return ret;
+}
+
+static int intel_i915_remove_entries(struct agp_memory *mem, off_t pg_start,
+                                    int type)
+{
+       int i;
+
+       if (mem->page_count == 0)
+               return 0;
+
+       if (pg_start < intel_private.gtt_entries) {
+               dev_info(&intel_private.pcidev->dev,
+                        "trying to disable local/stolen memory\n");
+               return -EINVAL;
+       }
+
+       for (i = pg_start; i < (mem->page_count + pg_start); i++)
+               writel(agp_bridge->scratch_page, intel_private.gtt+i);
+
+       readl(intel_private.gtt+i-1);
+
+       return 0;
+}
+
+/* Return the aperture size by just checking the resource length.  The effect
+ * described in the spec of the MSAC registers is just changing of the
+ * resource size.
+ */
+static int intel_i9xx_fetch_size(void)
+{
+       int num_sizes = ARRAY_SIZE(intel_i830_sizes);
+       int aper_size; /* size in megabytes */
+       int i;
+
+       aper_size = pci_resource_len(intel_private.pcidev, 2) / MB(1);
+
+       for (i = 0; i < num_sizes; i++) {
+               if (aper_size == intel_i830_sizes[i].size) {
+                       agp_bridge->current_size = intel_i830_sizes + i;
+                       return aper_size;
+               }
+       }
+
+       return 0;
+}
+
+/* The intel i915 automatically initializes the agp aperture during POST.
+ * Use the memory already set aside for in the GTT.
+ */
+static int intel_i915_create_gatt_table(struct agp_bridge_data *bridge)
+{
+       int page_order;
+       struct aper_size_info_fixed *size;
+       int num_entries;
+       u32 temp, temp2;
+       int gtt_map_size = 256 * 1024;
+
+       size = agp_bridge->current_size;
+       page_order = size->page_order;
+       num_entries = size->num_entries;
+       agp_bridge->gatt_table_real = NULL;
+
+       pci_read_config_dword(intel_private.pcidev, I915_MMADDR, &temp);
+       pci_read_config_dword(intel_private.pcidev, I915_PTEADDR, &temp2);
+
+       if (IS_G33)
+           gtt_map_size = 1024 * 1024; /* 1M on G33 */
+       intel_private.gtt = ioremap(temp2, gtt_map_size);
+       if (!intel_private.gtt)
+               return -ENOMEM;
+
+       intel_private.gtt_total_size = gtt_map_size / 4;
+
+       temp &= 0xfff80000;
+
+       intel_private.registers = ioremap(temp, 128 * 4096);
+       if (!intel_private.registers) {
+               iounmap(intel_private.gtt);
+               return -ENOMEM;
+       }
+
+       temp = readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000;
+       global_cache_flush();   /* FIXME: ? */
+
+       /* we have to call this as early as possible after the MMIO base address is known */
+       intel_i830_init_gtt_entries();
+
+       agp_bridge->gatt_table = NULL;
+
+       agp_bridge->gatt_bus_addr = temp;
+
+       return 0;
+}
+
+/*
+ * The i965 supports 36-bit physical addresses, but to keep
+ * the format of the GTT the same, the bits that don't fit
+ * in a 32-bit word are shifted down to bits 4..7.
+ *
+ * Gcc is smart enough to notice that "(addr >> 28) & 0xf0"
+ * is always zero on 32-bit architectures, so no need to make
+ * this conditional.
+ */
+static unsigned long intel_i965_mask_memory(struct agp_bridge_data *bridge,
+                                           dma_addr_t addr, int type)
+{
+       /* Shift high bits down */
+       addr |= (addr >> 28) & 0xf0;
+
+       /* Type checking must be done elsewhere */
+       return addr | bridge->driver->masks[type].mask;
+}
+
+static void intel_i965_get_gtt_range(int *gtt_offset, int *gtt_size)
+{
+       u16 snb_gmch_ctl;
+
+       switch (agp_bridge->dev->device) {
+       case PCI_DEVICE_ID_INTEL_GM45_HB:
+       case PCI_DEVICE_ID_INTEL_EAGLELAKE_HB:
+       case PCI_DEVICE_ID_INTEL_Q45_HB:
+       case PCI_DEVICE_ID_INTEL_G45_HB:
+       case PCI_DEVICE_ID_INTEL_G41_HB:
+       case PCI_DEVICE_ID_INTEL_B43_HB:
+       case PCI_DEVICE_ID_INTEL_IRONLAKE_D_HB:
+       case PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB:
+       case PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB:
+       case PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB:
+               *gtt_offset = *gtt_size = MB(2);
+               break;
+       case PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB:
+       case PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB:
+               *gtt_offset = MB(2);
+
+               pci_read_config_word(intel_private.pcidev, SNB_GMCH_CTRL, &snb_gmch_ctl);
+               switch (snb_gmch_ctl & SNB_GTT_SIZE_MASK) {
+               default:
+               case SNB_GTT_SIZE_0M:
+                       printk(KERN_ERR "Bad GTT size mask: 0x%04x.\n", snb_gmch_ctl);
+                       *gtt_size = MB(0);
+                       break;
+               case SNB_GTT_SIZE_1M:
+                       *gtt_size = MB(1);
+                       break;
+               case SNB_GTT_SIZE_2M:
+                       *gtt_size = MB(2);
+                       break;
+               }
+               break;
+       default:
+               *gtt_offset = *gtt_size = KB(512);
+       }
+}
+
+/* The intel i965 automatically initializes the agp aperture during POST.
+ * Use the memory already set aside for in the GTT.
+ */
+static int intel_i965_create_gatt_table(struct agp_bridge_data *bridge)
+{
+       int page_order;
+       struct aper_size_info_fixed *size;
+       int num_entries;
+       u32 temp;
+       int gtt_offset, gtt_size;
+
+       size = agp_bridge->current_size;
+       page_order = size->page_order;
+       num_entries = size->num_entries;
+       agp_bridge->gatt_table_real = NULL;
+
+       pci_read_config_dword(intel_private.pcidev, I915_MMADDR, &temp);
+
+       temp &= 0xfff00000;
+
+       intel_i965_get_gtt_range(&gtt_offset, &gtt_size);
+
+       intel_private.gtt = ioremap((temp + gtt_offset) , gtt_size);
+
+       if (!intel_private.gtt)
+               return -ENOMEM;
+
+       intel_private.gtt_total_size = gtt_size / 4;
+
+       intel_private.registers = ioremap(temp, 128 * 4096);
+       if (!intel_private.registers) {
+               iounmap(intel_private.gtt);
+               return -ENOMEM;
+       }
+
+       temp = readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000;
+       global_cache_flush();   /* FIXME: ? */
+
+       /* we have to call this as early as possible after the MMIO base address is known */
+       intel_i830_init_gtt_entries();
+
+       agp_bridge->gatt_table = NULL;
+
+       agp_bridge->gatt_bus_addr = temp;
+
+       return 0;
+}
+
+static const struct agp_bridge_driver intel_810_driver = {
+       .owner                  = THIS_MODULE,
+       .aperture_sizes         = intel_i810_sizes,
+       .size_type              = FIXED_APER_SIZE,
+       .num_aperture_sizes     = 2,
+       .needs_scratch_page     = true,
+       .configure              = intel_i810_configure,
+       .fetch_size             = intel_i810_fetch_size,
+       .cleanup                = intel_i810_cleanup,
+       .mask_memory            = intel_i810_mask_memory,
+       .masks                  = intel_i810_masks,
+       .agp_enable             = intel_i810_agp_enable,
+       .cache_flush            = global_cache_flush,
+       .create_gatt_table      = agp_generic_create_gatt_table,
+       .free_gatt_table        = agp_generic_free_gatt_table,
+       .insert_memory          = intel_i810_insert_entries,
+       .remove_memory          = intel_i810_remove_entries,
+       .alloc_by_type          = intel_i810_alloc_by_type,
+       .free_by_type           = intel_i810_free_by_type,
+       .agp_alloc_page         = agp_generic_alloc_page,
+       .agp_alloc_pages        = agp_generic_alloc_pages,
+       .agp_destroy_page       = agp_generic_destroy_page,
+       .agp_destroy_pages      = agp_generic_destroy_pages,
+       .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
+};
+
+static const struct agp_bridge_driver intel_830_driver = {
+       .owner                  = THIS_MODULE,
+       .aperture_sizes         = intel_i830_sizes,
+       .size_type              = FIXED_APER_SIZE,
+       .num_aperture_sizes     = 4,
+       .needs_scratch_page     = true,
+       .configure              = intel_i830_configure,
+       .fetch_size             = intel_i830_fetch_size,
+       .cleanup                = intel_i830_cleanup,
+       .mask_memory            = intel_i810_mask_memory,
+       .masks                  = intel_i810_masks,
+       .agp_enable             = intel_i810_agp_enable,
+       .cache_flush            = global_cache_flush,
+       .create_gatt_table      = intel_i830_create_gatt_table,
+       .free_gatt_table        = intel_i830_free_gatt_table,
+       .insert_memory          = intel_i830_insert_entries,
+       .remove_memory          = intel_i830_remove_entries,
+       .alloc_by_type          = intel_i830_alloc_by_type,
+       .free_by_type           = intel_i810_free_by_type,
+       .agp_alloc_page         = agp_generic_alloc_page,
+       .agp_alloc_pages        = agp_generic_alloc_pages,
+       .agp_destroy_page       = agp_generic_destroy_page,
+       .agp_destroy_pages      = agp_generic_destroy_pages,
+       .agp_type_to_mask_type  = intel_i830_type_to_mask_type,
+       .chipset_flush          = intel_i830_chipset_flush,
+};
+
+static const struct agp_bridge_driver intel_915_driver = {
+       .owner                  = THIS_MODULE,
+       .aperture_sizes         = intel_i830_sizes,
+       .size_type              = FIXED_APER_SIZE,
+       .num_aperture_sizes     = 4,
+       .needs_scratch_page     = true,
+       .configure              = intel_i915_configure,
+       .fetch_size             = intel_i9xx_fetch_size,
+       .cleanup                = intel_i915_cleanup,
+       .mask_memory            = intel_i810_mask_memory,
+       .masks                  = intel_i810_masks,
+       .agp_enable             = intel_i810_agp_enable,
+       .cache_flush            = global_cache_flush,
+       .create_gatt_table      = intel_i915_create_gatt_table,
+       .free_gatt_table        = intel_i830_free_gatt_table,
+       .insert_memory          = intel_i915_insert_entries,
+       .remove_memory          = intel_i915_remove_entries,
+       .alloc_by_type          = intel_i830_alloc_by_type,
+       .free_by_type           = intel_i810_free_by_type,
+       .agp_alloc_page         = agp_generic_alloc_page,
+       .agp_alloc_pages        = agp_generic_alloc_pages,
+       .agp_destroy_page       = agp_generic_destroy_page,
+       .agp_destroy_pages      = agp_generic_destroy_pages,
+       .agp_type_to_mask_type  = intel_i830_type_to_mask_type,
+       .chipset_flush          = intel_i915_chipset_flush,
+#ifdef USE_PCI_DMA_API
+       .agp_map_page           = intel_agp_map_page,
+       .agp_unmap_page         = intel_agp_unmap_page,
+       .agp_map_memory         = intel_agp_map_memory,
+       .agp_unmap_memory       = intel_agp_unmap_memory,
+#endif
+};
+
+static const struct agp_bridge_driver intel_i965_driver = {
+       .owner                  = THIS_MODULE,
+       .aperture_sizes         = intel_i830_sizes,
+       .size_type              = FIXED_APER_SIZE,
+       .num_aperture_sizes     = 4,
+       .needs_scratch_page     = true,
+       .configure              = intel_i915_configure,
+       .fetch_size             = intel_i9xx_fetch_size,
+       .cleanup                = intel_i915_cleanup,
+       .mask_memory            = intel_i965_mask_memory,
+       .masks                  = intel_i810_masks,
+       .agp_enable             = intel_i810_agp_enable,
+       .cache_flush            = global_cache_flush,
+       .create_gatt_table      = intel_i965_create_gatt_table,
+       .free_gatt_table        = intel_i830_free_gatt_table,
+       .insert_memory          = intel_i915_insert_entries,
+       .remove_memory          = intel_i915_remove_entries,
+       .alloc_by_type          = intel_i830_alloc_by_type,
+       .free_by_type           = intel_i810_free_by_type,
+       .agp_alloc_page         = agp_generic_alloc_page,
+       .agp_alloc_pages        = agp_generic_alloc_pages,
+       .agp_destroy_page       = agp_generic_destroy_page,
+       .agp_destroy_pages      = agp_generic_destroy_pages,
+       .agp_type_to_mask_type  = intel_i830_type_to_mask_type,
+       .chipset_flush          = intel_i915_chipset_flush,
+#ifdef USE_PCI_DMA_API
+       .agp_map_page           = intel_agp_map_page,
+       .agp_unmap_page         = intel_agp_unmap_page,
+       .agp_map_memory         = intel_agp_map_memory,
+       .agp_unmap_memory       = intel_agp_unmap_memory,
+#endif
+};
+
+static const struct agp_bridge_driver intel_g33_driver = {
+       .owner                  = THIS_MODULE,
+       .aperture_sizes         = intel_i830_sizes,
+       .size_type              = FIXED_APER_SIZE,
+       .num_aperture_sizes     = 4,
+       .needs_scratch_page     = true,
+       .configure              = intel_i915_configure,
+       .fetch_size             = intel_i9xx_fetch_size,
+       .cleanup                = intel_i915_cleanup,
+       .mask_memory            = intel_i965_mask_memory,
+       .masks                  = intel_i810_masks,
+       .agp_enable             = intel_i810_agp_enable,
+       .cache_flush            = global_cache_flush,
+       .create_gatt_table      = intel_i915_create_gatt_table,
+       .free_gatt_table        = intel_i830_free_gatt_table,
+       .insert_memory          = intel_i915_insert_entries,
+       .remove_memory          = intel_i915_remove_entries,
+       .alloc_by_type          = intel_i830_alloc_by_type,
+       .free_by_type           = intel_i810_free_by_type,
+       .agp_alloc_page         = agp_generic_alloc_page,
+       .agp_alloc_pages        = agp_generic_alloc_pages,
+       .agp_destroy_page       = agp_generic_destroy_page,
+       .agp_destroy_pages      = agp_generic_destroy_pages,
+       .agp_type_to_mask_type  = intel_i830_type_to_mask_type,
+       .chipset_flush          = intel_i915_chipset_flush,
+#ifdef USE_PCI_DMA_API
+       .agp_map_page           = intel_agp_map_page,
+       .agp_unmap_page         = intel_agp_unmap_page,
+       .agp_map_memory         = intel_agp_map_memory,
+       .agp_unmap_memory       = intel_agp_unmap_memory,
+#endif
+};
index 288fc50..0d6ff64 100644 (file)
@@ -69,16 +69,6 @@ struct intel_dvo_dev_ops {
         */
        void (*dpms)(struct intel_dvo_device *dvo, int mode);
 
-       /*
-        * Saves the output's state for restoration on VT switch.
-        */
-       void (*save)(struct intel_dvo_device *dvo);
-
-       /*
-        * Restore's the output's state at VT switch.
-        */
-       void (*restore)(struct intel_dvo_device *dvo);
-
        /*
         * Callback for testing a video mode for a given output.
         *
index 1184c14..14d5980 100644 (file)
 #define CH7017_BANG_LIMIT_CONTROL      0x7f
 
 struct ch7017_priv {
-       uint8_t save_hapi;
-       uint8_t save_vali;
-       uint8_t save_valo;
-       uint8_t save_ailo;
-       uint8_t save_lvds_pll_vco;
-       uint8_t save_feedback_div;
-       uint8_t save_lvds_control_2;
-       uint8_t save_outputs_enable;
-       uint8_t save_lvds_power_down;
-       uint8_t save_power_management;
+       uint8_t dummy;
 };
 
 static void ch7017_dump_regs(struct intel_dvo_device *dvo);
@@ -401,39 +392,6 @@ do {                                                       \
        DUMP(CH7017_LVDS_POWER_DOWN);
 }
 
-static void ch7017_save(struct intel_dvo_device *dvo)
-{
-       struct ch7017_priv *priv = dvo->dev_priv;
-
-       ch7017_read(dvo, CH7017_HORIZONTAL_ACTIVE_PIXEL_INPUT, &priv->save_hapi);
-       ch7017_read(dvo, CH7017_VERTICAL_ACTIVE_LINE_OUTPUT, &priv->save_valo);
-       ch7017_read(dvo, CH7017_ACTIVE_INPUT_LINE_OUTPUT, &priv->save_ailo);
-       ch7017_read(dvo, CH7017_LVDS_PLL_VCO_CONTROL, &priv->save_lvds_pll_vco);
-       ch7017_read(dvo, CH7017_LVDS_PLL_FEEDBACK_DIV, &priv->save_feedback_div);
-       ch7017_read(dvo, CH7017_LVDS_CONTROL_2, &priv->save_lvds_control_2);
-       ch7017_read(dvo, CH7017_OUTPUTS_ENABLE, &priv->save_outputs_enable);
-       ch7017_read(dvo, CH7017_LVDS_POWER_DOWN, &priv->save_lvds_power_down);
-       ch7017_read(dvo, CH7017_POWER_MANAGEMENT, &priv->save_power_management);
-}
-
-static void ch7017_restore(struct intel_dvo_device *dvo)
-{
-       struct ch7017_priv *priv = dvo->dev_priv;
-
-       /* Power down before changing mode */
-       ch7017_dpms(dvo, DRM_MODE_DPMS_OFF);
-
-       ch7017_write(dvo, CH7017_HORIZONTAL_ACTIVE_PIXEL_INPUT, priv->save_hapi);
-       ch7017_write(dvo, CH7017_VERTICAL_ACTIVE_LINE_OUTPUT, priv->save_valo);
-       ch7017_write(dvo, CH7017_ACTIVE_INPUT_LINE_OUTPUT, priv->save_ailo);
-       ch7017_write(dvo, CH7017_LVDS_PLL_VCO_CONTROL, priv->save_lvds_pll_vco);
-       ch7017_write(dvo, CH7017_LVDS_PLL_FEEDBACK_DIV, priv->save_feedback_div);
-       ch7017_write(dvo, CH7017_LVDS_CONTROL_2, priv->save_lvds_control_2);
-       ch7017_write(dvo, CH7017_OUTPUTS_ENABLE, priv->save_outputs_enable);
-       ch7017_write(dvo, CH7017_LVDS_POWER_DOWN, priv->save_lvds_power_down);
-       ch7017_write(dvo, CH7017_POWER_MANAGEMENT, priv->save_power_management);
-}
-
 static void ch7017_destroy(struct intel_dvo_device *dvo)
 {
        struct ch7017_priv *priv = dvo->dev_priv;
@@ -451,7 +409,5 @@ struct intel_dvo_dev_ops ch7017_ops = {
        .mode_set = ch7017_mode_set,
        .dpms = ch7017_dpms,
        .dump_regs = ch7017_dump_regs,
-       .save = ch7017_save,
-       .restore = ch7017_restore,
        .destroy = ch7017_destroy,
 };
index d56ff5c..6f1944b 100644 (file)
@@ -92,21 +92,10 @@ static struct ch7xxx_id_struct {
        { CH7301_VID, "CH7301" },
 };
 
-struct ch7xxx_reg_state {
-    uint8_t regs[CH7xxx_NUM_REGS];
-};
-
 struct ch7xxx_priv {
        bool quiet;
-
-       struct ch7xxx_reg_state save_reg;
-       struct ch7xxx_reg_state mode_reg;
-       uint8_t save_TCTL, save_TPCP, save_TPD, save_TPVT;
-       uint8_t save_TLPF, save_TCT, save_PM, save_IDF;
 };
 
-static void ch7xxx_save(struct intel_dvo_device *dvo);
-
 static char *ch7xxx_get_id(uint8_t vid)
 {
        int i;
@@ -312,42 +301,17 @@ static void ch7xxx_dpms(struct intel_dvo_device *dvo, int mode)
 
 static void ch7xxx_dump_regs(struct intel_dvo_device *dvo)
 {
-       struct ch7xxx_priv *ch7xxx = dvo->dev_priv;
        int i;
 
        for (i = 0; i < CH7xxx_NUM_REGS; i++) {
+               uint8_t val;
                if ((i % 8) == 0 )
                        DRM_LOG_KMS("\n %02X: ", i);
-               DRM_LOG_KMS("%02X ", ch7xxx->mode_reg.regs[i]);
+               ch7xxx_readb(dvo, i, &val);
+               DRM_LOG_KMS("%02X ", val);
        }
 }
 
-static void ch7xxx_save(struct intel_dvo_device *dvo)
-{
-       struct ch7xxx_priv *ch7xxx= dvo->dev_priv;
-
-       ch7xxx_readb(dvo, CH7xxx_TCTL, &ch7xxx->save_TCTL);
-       ch7xxx_readb(dvo, CH7xxx_TPCP, &ch7xxx->save_TPCP);
-       ch7xxx_readb(dvo, CH7xxx_TPD, &ch7xxx->save_TPD);
-       ch7xxx_readb(dvo, CH7xxx_TPVT, &ch7xxx->save_TPVT);
-       ch7xxx_readb(dvo, CH7xxx_TLPF, &ch7xxx->save_TLPF);
-       ch7xxx_readb(dvo, CH7xxx_PM, &ch7xxx->save_PM);
-       ch7xxx_readb(dvo, CH7xxx_IDF, &ch7xxx->save_IDF);
-}
-
-static void ch7xxx_restore(struct intel_dvo_device *dvo)
-{
-       struct ch7xxx_priv *ch7xxx = dvo->dev_priv;
-
-       ch7xxx_writeb(dvo, CH7xxx_TCTL, ch7xxx->save_TCTL);
-       ch7xxx_writeb(dvo, CH7xxx_TPCP, ch7xxx->save_TPCP);
-       ch7xxx_writeb(dvo, CH7xxx_TPD, ch7xxx->save_TPD);
-       ch7xxx_writeb(dvo, CH7xxx_TPVT, ch7xxx->save_TPVT);
-       ch7xxx_writeb(dvo, CH7xxx_TLPF, ch7xxx->save_TLPF);
-       ch7xxx_writeb(dvo, CH7xxx_IDF, ch7xxx->save_IDF);
-       ch7xxx_writeb(dvo, CH7xxx_PM, ch7xxx->save_PM);
-}
-
 static void ch7xxx_destroy(struct intel_dvo_device *dvo)
 {
        struct ch7xxx_priv *ch7xxx = dvo->dev_priv;
@@ -365,7 +329,5 @@ struct intel_dvo_dev_ops ch7xxx_ops = {
        .mode_set = ch7xxx_mode_set,
        .dpms = ch7xxx_dpms,
        .dump_regs = ch7xxx_dump_regs,
-       .save = ch7xxx_save,
-       .restore = ch7xxx_restore,
        .destroy = ch7xxx_destroy,
 };
index 24169e5..a2ec3f4 100644 (file)
@@ -153,9 +153,6 @@ struct ivch_priv {
        bool quiet;
 
        uint16_t width, height;
-
-       uint16_t save_VR01;
-       uint16_t save_VR40;
 };
 
 
@@ -405,22 +402,6 @@ static void ivch_dump_regs(struct intel_dvo_device *dvo)
        DRM_LOG_KMS("VR8F: 0x%04x\n", val);
 }
 
-static void ivch_save(struct intel_dvo_device *dvo)
-{
-       struct ivch_priv *priv = dvo->dev_priv;
-
-       ivch_read(dvo, VR01, &priv->save_VR01);
-       ivch_read(dvo, VR40, &priv->save_VR40);
-}
-
-static void ivch_restore(struct intel_dvo_device *dvo)
-{
-       struct ivch_priv *priv = dvo->dev_priv;
-
-       ivch_write(dvo, VR01, priv->save_VR01);
-       ivch_write(dvo, VR40, priv->save_VR40);
-}
-
 static void ivch_destroy(struct intel_dvo_device *dvo)
 {
        struct ivch_priv *priv = dvo->dev_priv;
@@ -434,8 +415,6 @@ static void ivch_destroy(struct intel_dvo_device *dvo)
 struct intel_dvo_dev_ops ivch_ops= {
        .init = ivch_init,
        .dpms = ivch_dpms,
-       .save = ivch_save,
-       .restore = ivch_restore,
        .mode_valid = ivch_mode_valid,
        .mode_set = ivch_mode_set,
        .detect = ivch_detect,
index 0001c13..9b8e676 100644 (file)
@@ -58,17 +58,9 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
 #define SIL164_REGC 0x0c
 
-struct sil164_save_rec {
-       uint8_t reg8;
-       uint8_t reg9;
-       uint8_t regc;
-};
-
 struct sil164_priv {
        //I2CDevRec d;
        bool quiet;
-       struct sil164_save_rec save_regs;
-       struct sil164_save_rec mode_regs;
 };
 
 #define SILPTR(d) ((SIL164Ptr)(d->DriverPrivate.ptr))
@@ -252,34 +244,6 @@ static void sil164_dump_regs(struct intel_dvo_device *dvo)
        DRM_LOG_KMS("SIL164_REGC: 0x%02x\n", val);
 }
 
-static void sil164_save(struct intel_dvo_device *dvo)
-{
-       struct sil164_priv *sil= dvo->dev_priv;
-
-       if (!sil164_readb(dvo, SIL164_REG8, &sil->save_regs.reg8))
-               return;
-
-       if (!sil164_readb(dvo, SIL164_REG9, &sil->save_regs.reg9))
-               return;
-
-       if (!sil164_readb(dvo, SIL164_REGC, &sil->save_regs.regc))
-               return;
-
-       return;
-}
-
-static void sil164_restore(struct intel_dvo_device *dvo)
-{
-       struct sil164_priv *sil = dvo->dev_priv;
-
-       /* Restore it powered down initially */
-       sil164_writeb(dvo, SIL164_REG8, sil->save_regs.reg8 & ~0x1);
-
-       sil164_writeb(dvo, SIL164_REG9, sil->save_regs.reg9);
-       sil164_writeb(dvo, SIL164_REGC, sil->save_regs.regc);
-       sil164_writeb(dvo, SIL164_REG8, sil->save_regs.reg8);
-}
-
 static void sil164_destroy(struct intel_dvo_device *dvo)
 {
        struct sil164_priv *sil = dvo->dev_priv;
@@ -297,7 +261,5 @@ struct intel_dvo_dev_ops sil164_ops = {
        .mode_set = sil164_mode_set,
        .dpms = sil164_dpms,
        .dump_regs = sil164_dump_regs,
-       .save = sil164_save,
-       .restore = sil164_restore,
        .destroy = sil164_destroy,
 };
index c7c391b..66c697b 100644 (file)
 #define TFP410_V_RES_LO                0x3C
 #define TFP410_V_RES_HI                0x3D
 
-struct tfp410_save_rec {
-       uint8_t ctl1;
-       uint8_t ctl2;
-};
-
 struct tfp410_priv {
        bool quiet;
-
-       struct tfp410_save_rec saved_reg;
-       struct tfp410_save_rec mode_reg;
 };
 
 static bool tfp410_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
@@ -293,28 +285,6 @@ static void tfp410_dump_regs(struct intel_dvo_device *dvo)
        DRM_LOG_KMS("TFP410_V_RES: 0x%02X%02X\n", val2, val);
 }
 
-static void tfp410_save(struct intel_dvo_device *dvo)
-{
-       struct tfp410_priv *tfp = dvo->dev_priv;
-
-       if (!tfp410_readb(dvo, TFP410_CTL_1, &tfp->saved_reg.ctl1))
-               return;
-
-       if (!tfp410_readb(dvo, TFP410_CTL_2, &tfp->saved_reg.ctl2))
-               return;
-}
-
-static void tfp410_restore(struct intel_dvo_device *dvo)
-{
-       struct tfp410_priv *tfp = dvo->dev_priv;
-
-       /* Restore it powered down initially */
-       tfp410_writeb(dvo, TFP410_CTL_1, tfp->saved_reg.ctl1 & ~0x1);
-
-       tfp410_writeb(dvo, TFP410_CTL_2, tfp->saved_reg.ctl2);
-       tfp410_writeb(dvo, TFP410_CTL_1, tfp->saved_reg.ctl1);
-}
-
 static void tfp410_destroy(struct intel_dvo_device *dvo)
 {
        struct tfp410_priv *tfp = dvo->dev_priv;
@@ -332,7 +302,5 @@ struct intel_dvo_dev_ops tfp410_ops = {
        .mode_set = tfp410_mode_set,
        .dpms = tfp410_dpms,
        .dump_regs = tfp410_dump_regs,
-       .save = tfp410_save,
-       .restore = tfp410_restore,
        .destroy = tfp410_destroy,
 };
index 2dc9393..f0538da 100644 (file)
@@ -1579,7 +1579,7 @@ static void i915_get_mem_freq(struct drm_device *dev)
  */
 int i915_driver_load(struct drm_device *dev, unsigned long flags)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv;
        resource_size_t base, size;
        int ret = 0, mmio_bar;
        uint32_t agp_size, prealloc_size, prealloc_start;
@@ -1711,6 +1711,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
        /* Start out suspended */
        dev_priv->mm.suspended = 1;
 
+       intel_detect_pch(dev);
+
        if (drm_core_check_feature(dev, DRIVER_MODESET)) {
                ret = i915_load_modeset_init(dev, prealloc_start,
                                             prealloc_size, agp_size);
index 0af3dcc..01e91ea 100644 (file)
@@ -187,6 +187,35 @@ const static struct pci_device_id pciidlist[] = {
 MODULE_DEVICE_TABLE(pci, pciidlist);
 #endif
 
+#define INTEL_PCH_DEVICE_ID_MASK       0xff00
+#define INTEL_PCH_CPT_DEVICE_ID_TYPE   0x1c00
+
+void intel_detect_pch (struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct pci_dev *pch;
+
+       /*
+        * The reason to probe ISA bridge instead of Dev31:Fun0 is to
+        * make graphics device passthrough work easy for VMM, that only
+        * need to expose ISA bridge to let driver know the real hardware
+        * underneath. This is a requirement from virtualization team.
+        */
+       pch = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, NULL);
+       if (pch) {
+               if (pch->vendor == PCI_VENDOR_ID_INTEL) {
+                       int id;
+                       id = pch->device & INTEL_PCH_DEVICE_ID_MASK;
+
+                       if (id == INTEL_PCH_CPT_DEVICE_ID_TYPE) {
+                               dev_priv->pch_type = PCH_CPT;
+                               DRM_DEBUG_KMS("Found CougarPoint PCH\n");
+                       }
+               }
+               pci_dev_put(pch);
+       }
+}
+
 static int i915_drm_freeze(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
index 6960849..790fef3 100644 (file)
@@ -221,6 +221,11 @@ enum no_fbc_reason {
        FBC_NOT_TILED, /* buffer not tiled */
 };
 
+enum intel_pch {
+       PCH_IBX,        /* Ibexpeak PCH */
+       PCH_CPT,        /* Cougarpoint PCH */
+};
+
 typedef struct drm_i915_private {
        struct drm_device *dev;
 
@@ -331,6 +336,9 @@ typedef struct drm_i915_private {
        /* Display functions */
        struct drm_i915_display_funcs display;
 
+       /* PCH chipset type */
+       enum intel_pch pch_type;
+
        /* Register state */
        bool modeset_on_lid;
        u8 saveLBB;
@@ -992,6 +1000,9 @@ extern int intel_modeset_vga_set_state(struct drm_device *dev, bool state);
 extern void i8xx_disable_fbc(struct drm_device *dev);
 extern void g4x_disable_fbc(struct drm_device *dev);
 
+extern void intel_detect_pch (struct drm_device *dev);
+extern int intel_trans_dp_port_sel (struct drm_crtc *crtc);
+
 /**
  * Lock test for when it's just for synchronization of ring access.
  *
@@ -1123,7 +1134,8 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
 #define SUPPORTS_INTEGRATED_DP(dev)    (IS_G4X(dev) || IS_IRONLAKE(dev))
 #define SUPPORTS_EDP(dev)              (IS_IRONLAKE_M(dev))
 #define SUPPORTS_TV(dev)               (IS_I9XX(dev) && IS_MOBILE(dev) && \
-                                       !IS_IRONLAKE(dev) && !IS_PINEVIEW(dev))
+                                       !IS_IRONLAKE(dev) && !IS_PINEVIEW(dev) && \
+                                       !IS_GEN6(dev))
 #define I915_HAS_HOTPLUG(dev)           (INTEL_INFO(dev)->has_hotplug)
 /* dsparb controlled by hw only */
 #define DSPARB_HWCONTROL(dev) (IS_G4X(dev) || IS_IRONLAKE(dev))
@@ -1136,6 +1148,9 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
 #define HAS_PCH_SPLIT(dev) (IS_IRONLAKE(dev) ||        \
                            IS_GEN6(dev))
 
+#define INTEL_PCH_TYPE(dev) (((struct drm_i915_private *)(dev)->dev_private)->pch_type)
+#define HAS_PCH_CPT(dev) (INTEL_PCH_TYPE(dev) == PCH_CPT)
+
 #define PRIMARY_RINGBUFFER_SIZE         (128*1024)
 
 #endif
index 6421481..4541e33 100644 (file)
@@ -169,9 +169,13 @@ void intel_enable_asle (struct drm_device *dev)
 
        if (HAS_PCH_SPLIT(dev))
                ironlake_enable_display_irq(dev_priv, DE_GSE);
-       else
+       else {
                i915_enable_pipestat(dev_priv, 1,
                                     I915_LEGACY_BLC_EVENT_ENABLE);
+               if (IS_I965G(dev))
+                       i915_enable_pipestat(dev_priv, 0,
+                                            I915_LEGACY_BLC_EVENT_ENABLE);
+       }
 }
 
 /**
@@ -256,11 +260,11 @@ static void i915_hotplug_work_func(struct work_struct *work)
                                                    hotplug_work);
        struct drm_device *dev = dev_priv->dev;
        struct drm_mode_config *mode_config = &dev->mode_config;
-       struct drm_connector *connector;
+       struct drm_encoder *encoder;
 
-       if (mode_config->num_connector) {
-               list_for_each_entry(connector, &mode_config->connector_list, head) {
-                       struct intel_encoder *intel_encoder = to_intel_encoder(connector);
+       if (mode_config->num_encoder) {
+               list_for_each_entry(encoder, &mode_config->encoder_list, head) {
+                       struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
        
                        if (intel_encoder->hot_plug)
                                (*intel_encoder->hot_plug) (intel_encoder);
@@ -946,7 +950,8 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
                        intel_finish_page_flip(dev, 1);
                }
 
-               if ((pipeb_stats & I915_LEGACY_BLC_EVENT_STATUS) ||
+               if ((pipea_stats & I915_LEGACY_BLC_EVENT_STATUS) ||
+                   (pipeb_stats & I915_LEGACY_BLC_EVENT_STATUS) ||
                    (iir & I915_ASLE_INTERRUPT))
                        opregion_asle_intr(dev);
 
index cbbf59f..527d30a 100644 (file)
 #define   DP_LINK_TRAIN_MASK           (3 << 28)
 #define   DP_LINK_TRAIN_SHIFT          28
 
+/* CPT Link training mode */
+#define   DP_LINK_TRAIN_PAT_1_CPT      (0 << 8)
+#define   DP_LINK_TRAIN_PAT_2_CPT      (1 << 8)
+#define   DP_LINK_TRAIN_PAT_IDLE_CPT   (2 << 8)
+#define   DP_LINK_TRAIN_OFF_CPT                (3 << 8)
+#define   DP_LINK_TRAIN_MASK_CPT       (7 << 8)
+#define   DP_LINK_TRAIN_SHIFT_CPT      8
+
 /* Signal voltages. These are mostly controlled by the other end */
 #define   DP_VOLTAGE_0_4               (0 << 25)
 #define   DP_VOLTAGE_0_6               (1 << 25)
 
 #define DSPFW1                 0x70034
 #define   DSPFW_SR_SHIFT       23
+#define   DSPFW_SR_MASK        (0x1ff<<23)
 #define   DSPFW_CURSORB_SHIFT  16
+#define   DSPFW_CURSORB_MASK   (0x3f<<16)
 #define   DSPFW_PLANEB_SHIFT   8
+#define   DSPFW_PLANEB_MASK    (0x7f<<8)
+#define   DSPFW_PLANEA_MASK    (0x7f)
 #define DSPFW2                 0x70038
 #define   DSPFW_CURSORA_MASK   0x00003f00
 #define   DSPFW_CURSORA_SHIFT  8
+#define   DSPFW_PLANEC_MASK    (0x7f)
 #define DSPFW3                 0x7003c
 #define   DSPFW_HPLL_SR_EN     (1<<31)
 #define   DSPFW_CURSOR_SR_SHIFT        24
 #define   PINEVIEW_SELF_REFRESH_EN     (1<<30)
+#define   DSPFW_CURSOR_SR_MASK         (0x3f<<24)
+#define   DSPFW_HPLL_CURSOR_SHIFT      16
+#define   DSPFW_HPLL_CURSOR_MASK       (0x3f<<16)
+#define   DSPFW_HPLL_SR_MASK           (0x1ff)
 
 /* FIFO watermark sizes etc */
 #define G4X_FIFO_LINE_SIZE     64
 #define PINEVIEW_CURSOR_DFT_WM 0
 #define PINEVIEW_CURSOR_GUARD_WM       5
 
+
+/* define the Watermark register on Ironlake */
+#define WM0_PIPEA_ILK          0x45100
+#define  WM0_PIPE_PLANE_MASK   (0x7f<<16)
+#define  WM0_PIPE_PLANE_SHIFT  16
+#define  WM0_PIPE_SPRITE_MASK  (0x3f<<8)
+#define  WM0_PIPE_SPRITE_SHIFT 8
+#define  WM0_PIPE_CURSOR_MASK  (0x1f)
+
+#define WM0_PIPEB_ILK          0x45104
+#define WM1_LP_ILK             0x45108
+#define  WM1_LP_SR_EN          (1<<31)
+#define  WM1_LP_LATENCY_SHIFT  24
+#define  WM1_LP_LATENCY_MASK   (0x7f<<24)
+#define  WM1_LP_SR_MASK                (0x1ff<<8)
+#define  WM1_LP_SR_SHIFT       8
+#define  WM1_LP_CURSOR_MASK    (0x3f)
+
+/* Memory latency timer register */
+#define MLTR_ILK               0x11222
+/* the unit of memory self-refresh latency time is 0.5us */
+#define  ILK_SRLT_MASK         0x3f
+
+/* define the fifo size on Ironlake */
+#define ILK_DISPLAY_FIFO       128
+#define ILK_DISPLAY_MAXWM      64
+#define ILK_DISPLAY_DFTWM      8
+
+#define ILK_DISPLAY_SR_FIFO    512
+#define ILK_DISPLAY_MAX_SRWM   0x1ff
+#define ILK_DISPLAY_DFT_SRWM   0x3f
+#define ILK_CURSOR_SR_FIFO     64
+#define ILK_CURSOR_MAX_SRWM    0x3f
+#define ILK_CURSOR_DFT_SRWM    8
+
+#define ILK_FIFO_LINE_SIZE     64
+
 /*
  * The two pipe frame counter registers are not synchronized, so
  * reading a stable value is somewhat tricky. The following code
 #define GTIIR   0x44018
 #define GTIER   0x4401c
 
+#define ILK_DISPLAY_CHICKEN2   0x42004
+#define  ILK_DPARB_GATE        (1<<22)
+#define  ILK_VSDPFD_FULL       (1<<21)
+#define ILK_DSPCLK_GATE                0x42020
+#define  ILK_DPARB_CLK_GATE    (1<<5)
+
 #define DISP_ARB_CTL   0x45000
 #define  DISP_TILE_SURFACE_SWIZZLING   (1<<13)
+#define  DISP_FBC_WM_DIS               (1<<15)
 
 /* PCH */
 
 #define SDE_PORTB_HOTPLUG       (1 << 8)
 #define SDE_SDVOB_HOTPLUG       (1 << 6)
 #define SDE_HOTPLUG_MASK       (0xf << 8)
+/* CPT */
+#define SDE_CRT_HOTPLUG_CPT    (1 << 19)
+#define SDE_PORTD_HOTPLUG_CPT  (1 << 23)
+#define SDE_PORTC_HOTPLUG_CPT  (1 << 22)
+#define SDE_PORTB_HOTPLUG_CPT  (1 << 21)
 
 #define SDEISR  0xc4000
 #define SDEIMR  0xc4004
 #define PCH_SSC4_PARMS          0xc6210
 #define PCH_SSC4_AUX_PARMS      0xc6214
 
+#define PCH_DPLL_SEL           0xc7000
+#define  TRANSA_DPLL_ENABLE    (1<<3)
+#define         TRANSA_DPLLB_SEL       (1<<0)
+#define         TRANSA_DPLLA_SEL       0
+#define  TRANSB_DPLL_ENABLE    (1<<7)
+#define         TRANSB_DPLLB_SEL       (1<<4)
+#define         TRANSB_DPLLA_SEL       (0)
+#define  TRANSC_DPLL_ENABLE    (1<<11)
+#define         TRANSC_DPLLB_SEL       (1<<8)
+#define         TRANSC_DPLLA_SEL       (0)
+
 /* transcoder */
 
 #define TRANS_HTOTAL_A          0xe0000
 #define  FDI_LINK_TRAIN_PRE_EMPHASIS_1_5X (1<<22)
 #define  FDI_LINK_TRAIN_PRE_EMPHASIS_2X   (2<<22)
 #define  FDI_LINK_TRAIN_PRE_EMPHASIS_3X   (3<<22)
+/* ILK always use 400mV 0dB for voltage swing and pre-emphasis level.
+   SNB has different settings. */
+/* SNB A-stepping */
+#define  FDI_LINK_TRAIN_400MV_0DB_SNB_A                (0x38<<22)
+#define  FDI_LINK_TRAIN_400MV_6DB_SNB_A                (0x02<<22)
+#define  FDI_LINK_TRAIN_600MV_3_5DB_SNB_A      (0x01<<22)
+#define  FDI_LINK_TRAIN_800MV_0DB_SNB_A                (0x0<<22)
+/* SNB B-stepping */
+#define  FDI_LINK_TRAIN_400MV_0DB_SNB_B                (0x0<<22)
+#define  FDI_LINK_TRAIN_400MV_6DB_SNB_B                (0x3a<<22)
+#define  FDI_LINK_TRAIN_600MV_3_5DB_SNB_B      (0x39<<22)
+#define  FDI_LINK_TRAIN_800MV_0DB_SNB_B                (0x38<<22)
+#define  FDI_LINK_TRAIN_VOL_EMP_MASK           (0x3f<<22)
 #define  FDI_DP_PORT_WIDTH_X1           (0<<19)
 #define  FDI_DP_PORT_WIDTH_X2           (1<<19)
 #define  FDI_DP_PORT_WIDTH_X3           (2<<19)
 #define  FDI_RX_ENHANCE_FRAME_ENABLE    (1<<6)
 #define  FDI_SEL_RAWCLK                 (0<<4)
 #define  FDI_SEL_PCDCLK                 (1<<4)
+/* CPT */
+#define  FDI_AUTO_TRAINING                     (1<<10)
+#define  FDI_LINK_TRAIN_PATTERN_1_CPT          (0<<8)
+#define  FDI_LINK_TRAIN_PATTERN_2_CPT          (1<<8)
+#define  FDI_LINK_TRAIN_PATTERN_IDLE_CPT       (2<<8)
+#define  FDI_LINK_TRAIN_NORMAL_CPT             (3<<8)
+#define  FDI_LINK_TRAIN_PATTERN_MASK_CPT       (3<<8)
 
 #define FDI_RXA_MISC            0xf0010
 #define FDI_RXB_MISC            0xf1010
 #define  HSYNC_ACTIVE_HIGH      (1 << 3)
 #define  PORT_DETECTED          (1 << 2)
 
+/* PCH SDVOB multiplex with HDMIB */
+#define PCH_SDVOB      HDMIB
+
 #define HDMIC   0xe1150
 #define HDMID   0xe1160
 
 #define PCH_DPD_AUX_CH_DATA4   0xe4320
 #define PCH_DPD_AUX_CH_DATA5   0xe4324
 
+/* CPT */
+#define  PORT_TRANS_A_SEL_CPT  0
+#define  PORT_TRANS_B_SEL_CPT  (1<<29)
+#define  PORT_TRANS_C_SEL_CPT  (2<<29)
+#define  PORT_TRANS_SEL_MASK   (3<<29)
+
+#define TRANS_DP_CTL_A         0xe0300
+#define TRANS_DP_CTL_B         0xe1300
+#define TRANS_DP_CTL_C         0xe2300
+#define  TRANS_DP_OUTPUT_ENABLE        (1<<31)
+#define  TRANS_DP_PORT_SEL_B   (0<<29)
+#define  TRANS_DP_PORT_SEL_C   (1<<29)
+#define  TRANS_DP_PORT_SEL_D   (2<<29)
+#define  TRANS_DP_PORT_SEL_MASK        (3<<29)
+#define  TRANS_DP_AUDIO_ONLY   (1<<26)
+#define  TRANS_DP_ENH_FRAMING  (1<<18)
+#define  TRANS_DP_8BPC         (0<<9)
+#define  TRANS_DP_10BPC                (1<<9)
+#define  TRANS_DP_6BPC         (2<<9)
+#define  TRANS_DP_12BPC                (3<<9)
+#define  TRANS_DP_VSYNC_ACTIVE_HIGH    (1<<4)
+#define  TRANS_DP_VSYNC_ACTIVE_LOW     0
+#define  TRANS_DP_HSYNC_ACTIVE_HIGH    (1<<3)
+#define  TRANS_DP_HSYNC_ACTIVE_LOW     0
+
+/* SNB eDP training params */
+/* SNB A-stepping */
+#define  EDP_LINK_TRAIN_400MV_0DB_SNB_A                (0x38<<22)
+#define  EDP_LINK_TRAIN_400MV_6DB_SNB_A                (0x02<<22)
+#define  EDP_LINK_TRAIN_600MV_3_5DB_SNB_A      (0x01<<22)
+#define  EDP_LINK_TRAIN_800MV_0DB_SNB_A                (0x0<<22)
+/* SNB B-stepping */
+#define  EDP_LINK_TRAIN_400MV_0DB_SNB_B                (0x0<<22)
+#define  EDP_LINK_TRAIN_400MV_6DB_SNB_B                (0x3a<<22)
+#define  EDP_LINK_TRAIN_600MV_3_5DB_SNB_B      (0x39<<22)
+#define  EDP_LINK_TRAIN_800MV_0DB_SNB_B                (0x38<<22)
+#define  EDP_LINK_TRAIN_VOL_EMP_MASK_SNB       (0x3f<<22)
+
 #endif /* _I915_REG_H_ */
index ac0d1a7..60a5800 100644 (file)
@@ -600,14 +600,16 @@ void i915_save_display(struct drm_device *dev)
        }
        /* FIXME: save TV & SDVO state */
 
-       /* FBC state */
-       if (IS_GM45(dev)) {
-               dev_priv->saveDPFC_CB_BASE = I915_READ(DPFC_CB_BASE);
-       } else {
-               dev_priv->saveFBC_CFB_BASE = I915_READ(FBC_CFB_BASE);
-               dev_priv->saveFBC_LL_BASE = I915_READ(FBC_LL_BASE);
-               dev_priv->saveFBC_CONTROL2 = I915_READ(FBC_CONTROL2);
-               dev_priv->saveFBC_CONTROL = I915_READ(FBC_CONTROL);
+       /* Only save FBC state on the platform that supports FBC */
+       if (I915_HAS_FBC(dev)) {
+               if (IS_GM45(dev)) {
+                       dev_priv->saveDPFC_CB_BASE = I915_READ(DPFC_CB_BASE);
+               } else {
+                       dev_priv->saveFBC_CFB_BASE = I915_READ(FBC_CFB_BASE);
+                       dev_priv->saveFBC_LL_BASE = I915_READ(FBC_LL_BASE);
+                       dev_priv->saveFBC_CONTROL2 = I915_READ(FBC_CONTROL2);
+                       dev_priv->saveFBC_CONTROL = I915_READ(FBC_CONTROL);
+               }
        }
 
        /* VGA state */
@@ -702,18 +704,19 @@ void i915_restore_display(struct drm_device *dev)
        }
        /* FIXME: restore TV & SDVO state */
 
-       /* FBC info */
-       if (IS_GM45(dev)) {
-               g4x_disable_fbc(dev);
-               I915_WRITE(DPFC_CB_BASE, dev_priv->saveDPFC_CB_BASE);
-       } else {
-               i8xx_disable_fbc(dev);
-               I915_WRITE(FBC_CFB_BASE, dev_priv->saveFBC_CFB_BASE);
-               I915_WRITE(FBC_LL_BASE, dev_priv->saveFBC_LL_BASE);
-               I915_WRITE(FBC_CONTROL2, dev_priv->saveFBC_CONTROL2);
-               I915_WRITE(FBC_CONTROL, dev_priv->saveFBC_CONTROL);
+       /* only restore FBC info on the platform that supports FBC*/
+       if (I915_HAS_FBC(dev)) {
+               if (IS_GM45(dev)) {
+                       g4x_disable_fbc(dev);
+                       I915_WRITE(DPFC_CB_BASE, dev_priv->saveDPFC_CB_BASE);
+               } else {
+                       i8xx_disable_fbc(dev);
+                       I915_WRITE(FBC_CFB_BASE, dev_priv->saveFBC_CFB_BASE);
+                       I915_WRITE(FBC_LL_BASE, dev_priv->saveFBC_LL_BASE);
+                       I915_WRITE(FBC_CONTROL2, dev_priv->saveFBC_CONTROL2);
+                       I915_WRITE(FBC_CONTROL, dev_priv->saveFBC_CONTROL);
+               }
        }
-
        /* VGA state */
        if (IS_IRONLAKE(dev))
                I915_WRITE(CPU_VGACNTRL, dev_priv->saveVGACNTRL);
index 01840d9..3038153 100644 (file)
@@ -115,7 +115,7 @@ TRACE_EVENT(i915_gem_object_get_fence,
                      __entry->obj, __entry->fence, __entry->tiling_mode)
 );
 
-TRACE_EVENT(i915_gem_object_unbind,
+DECLARE_EVENT_CLASS(i915_gem_object,
 
            TP_PROTO(struct drm_gem_object *obj),
 
@@ -132,21 +132,18 @@ TRACE_EVENT(i915_gem_object_unbind,
            TP_printk("obj=%p", __entry->obj)
 );
 
-TRACE_EVENT(i915_gem_object_destroy,
+DEFINE_EVENT(i915_gem_object, i915_gem_object_unbind,
 
            TP_PROTO(struct drm_gem_object *obj),
 
-           TP_ARGS(obj),
+           TP_ARGS(obj)
+);
 
-           TP_STRUCT__entry(
-                            __field(struct drm_gem_object *, obj)
-                            ),
+DEFINE_EVENT(i915_gem_object, i915_gem_object_destroy,
 
-           TP_fast_assign(
-                          __entry->obj = obj;
-                          ),
+           TP_PROTO(struct drm_gem_object *obj),
 
-           TP_printk("obj=%p", __entry->obj)
+           TP_ARGS(obj)
 );
 
 /* batch tracing */
@@ -197,8 +194,7 @@ TRACE_EVENT(i915_gem_request_flush,
                      __entry->flush_domains, __entry->invalidate_domains)
 );
 
-
-TRACE_EVENT(i915_gem_request_complete,
+DECLARE_EVENT_CLASS(i915_gem_request,
 
            TP_PROTO(struct drm_device *dev, u32 seqno),
 
@@ -217,64 +213,35 @@ TRACE_EVENT(i915_gem_request_complete,
            TP_printk("dev=%u, seqno=%u", __entry->dev, __entry->seqno)
 );
 
-TRACE_EVENT(i915_gem_request_retire,
+DEFINE_EVENT(i915_gem_request, i915_gem_request_complete,
 
            TP_PROTO(struct drm_device *dev, u32 seqno),
 
-           TP_ARGS(dev, seqno),
-
-           TP_STRUCT__entry(
-                            __field(u32, dev)
-                            __field(u32, seqno)
-                            ),
-
-           TP_fast_assign(
-                          __entry->dev = dev->primary->index;
-                          __entry->seqno = seqno;
-                          ),
-
-           TP_printk("dev=%u, seqno=%u", __entry->dev, __entry->seqno)
+           TP_ARGS(dev, seqno)
 );
 
-TRACE_EVENT(i915_gem_request_wait_begin,
+DEFINE_EVENT(i915_gem_request, i915_gem_request_retire,
 
            TP_PROTO(struct drm_device *dev, u32 seqno),
 
-           TP_ARGS(dev, seqno),
-
-           TP_STRUCT__entry(
-                            __field(u32, dev)
-                            __field(u32, seqno)
-                            ),
-
-           TP_fast_assign(
-                          __entry->dev = dev->primary->index;
-                          __entry->seqno = seqno;
-                          ),
-
-           TP_printk("dev=%u, seqno=%u", __entry->dev, __entry->seqno)
+           TP_ARGS(dev, seqno)
 );
 
-TRACE_EVENT(i915_gem_request_wait_end,
+DEFINE_EVENT(i915_gem_request, i915_gem_request_wait_begin,
 
            TP_PROTO(struct drm_device *dev, u32 seqno),
 
-           TP_ARGS(dev, seqno),
+           TP_ARGS(dev, seqno)
+);
 
-           TP_STRUCT__entry(
-                            __field(u32, dev)
-                            __field(u32, seqno)
-                            ),
+DEFINE_EVENT(i915_gem_request, i915_gem_request_wait_end,
 
-           TP_fast_assign(
-                          __entry->dev = dev->primary->index;
-                          __entry->seqno = seqno;
-                          ),
+           TP_PROTO(struct drm_device *dev, u32 seqno),
 
-           TP_printk("dev=%u, seqno=%u", __entry->dev, __entry->seqno)
+           TP_ARGS(dev, seqno)
 );
 
-TRACE_EVENT(i915_ring_wait_begin,
+DECLARE_EVENT_CLASS(i915_ring,
 
            TP_PROTO(struct drm_device *dev),
 
@@ -291,21 +258,18 @@ TRACE_EVENT(i915_ring_wait_begin,
            TP_printk("dev=%u", __entry->dev)
 );
 
-TRACE_EVENT(i915_ring_wait_end,
+DEFINE_EVENT(i915_ring, i915_ring_wait_begin,
 
            TP_PROTO(struct drm_device *dev),
 
-           TP_ARGS(dev),
+           TP_ARGS(dev)
+);
 
-           TP_STRUCT__entry(
-                            __field(u32, dev)
-                            ),
+DEFINE_EVENT(i915_ring, i915_ring_wait_end,
 
-           TP_fast_assign(
-                          __entry->dev = dev->primary->index;
-                          ),
+           TP_PROTO(struct drm_device *dev),
 
-           TP_printk("dev=%u", __entry->dev)
+           TP_ARGS(dev)
 );
 
 #endif /* _I915_TRACE_H_ */
index 759c2ef..26756cd 100644 (file)
@@ -136,11 +136,17 @@ static void intel_crt_mode_set(struct drm_encoder *encoder,
                adpa |= ADPA_VSYNC_ACTIVE_HIGH;
 
        if (intel_crtc->pipe == 0) {
-               adpa |= ADPA_PIPE_A_SELECT;
+               if (HAS_PCH_CPT(dev))
+                       adpa |= PORT_TRANS_A_SEL_CPT;
+               else
+                       adpa |= ADPA_PIPE_A_SELECT;
                if (!HAS_PCH_SPLIT(dev))
                        I915_WRITE(BCLRPAT_A, 0);
        } else {
-               adpa |= ADPA_PIPE_B_SELECT;
+               if (HAS_PCH_CPT(dev))
+                       adpa |= PORT_TRANS_B_SEL_CPT;
+               else
+                       adpa |= ADPA_PIPE_B_SELECT;
                if (!HAS_PCH_SPLIT(dev))
                        I915_WRITE(BCLRPAT_B, 0);
        }
@@ -152,15 +158,21 @@ static bool intel_ironlake_crt_detect_hotplug(struct drm_connector *connector)
 {
        struct drm_device *dev = connector->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 adpa;
+       u32 adpa, temp;
        bool ret;
 
-       adpa = I915_READ(PCH_ADPA);
+       temp = adpa = I915_READ(PCH_ADPA);
 
-       adpa &= ~ADPA_CRT_HOTPLUG_MASK;
-       /* disable HPD first */
-       I915_WRITE(PCH_ADPA, adpa);
-       (void)I915_READ(PCH_ADPA);
+       if (HAS_PCH_CPT(dev)) {
+               /* Disable DAC before force detect */
+               I915_WRITE(PCH_ADPA, adpa & ~ADPA_DAC_ENABLE);
+               (void)I915_READ(PCH_ADPA);
+       } else {
+               adpa &= ~ADPA_CRT_HOTPLUG_MASK;
+               /* disable HPD first */
+               I915_WRITE(PCH_ADPA, adpa);
+               (void)I915_READ(PCH_ADPA);
+       }
 
        adpa |= (ADPA_CRT_HOTPLUG_PERIOD_128 |
                        ADPA_CRT_HOTPLUG_WARMUP_10MS |
@@ -176,6 +188,11 @@ static bool intel_ironlake_crt_detect_hotplug(struct drm_connector *connector)
        while ((I915_READ(PCH_ADPA) & ADPA_CRT_HOTPLUG_FORCE_TRIGGER) != 0)
                ;
 
+       if (HAS_PCH_CPT(dev)) {
+               I915_WRITE(PCH_ADPA, temp);
+               (void)I915_READ(PCH_ADPA);
+       }
+
        /* Check the status to see if both blue and green are on now */
        adpa = I915_READ(PCH_ADPA);
        adpa &= ADPA_CRT_HOTPLUG_MONITOR_MASK;
@@ -245,9 +262,9 @@ static bool intel_crt_detect_hotplug(struct drm_connector *connector)
        return false;
 }
 
-static bool intel_crt_detect_ddc(struct drm_connector *connector)
+static bool intel_crt_detect_ddc(struct drm_encoder *encoder)
 {
-       struct intel_encoder *intel_encoder = to_intel_encoder(connector);
+       struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
 
        /* CRT should always be at 0, but check anyway */
        if (intel_encoder->type != INTEL_OUTPUT_ANALOG)
@@ -387,8 +404,8 @@ intel_crt_load_detect(struct drm_crtc *crtc, struct intel_encoder *intel_encoder
 static enum drm_connector_status intel_crt_detect(struct drm_connector *connector)
 {
        struct drm_device *dev = connector->dev;
-       struct intel_encoder *intel_encoder = to_intel_encoder(connector);
-       struct drm_encoder *encoder = &intel_encoder->enc;
+       struct drm_encoder *encoder = intel_attached_encoder(connector);
+       struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
        struct drm_crtc *crtc;
        int dpms_mode;
        enum drm_connector_status status;
@@ -400,18 +417,19 @@ static enum drm_connector_status intel_crt_detect(struct drm_connector *connecto
                        return connector_status_disconnected;
        }
 
-       if (intel_crt_detect_ddc(connector))
+       if (intel_crt_detect_ddc(encoder))
                return connector_status_connected;
 
        /* for pre-945g platforms use load detect */
        if (encoder->crtc && encoder->crtc->enabled) {
                status = intel_crt_load_detect(encoder->crtc, intel_encoder);
        } else {
-               crtc = intel_get_load_detect_pipe(intel_encoder,
+               crtc = intel_get_load_detect_pipe(intel_encoder, connector,
                                                  NULL, &dpms_mode);
                if (crtc) {
                        status = intel_crt_load_detect(crtc, intel_encoder);
-                       intel_release_load_detect_pipe(intel_encoder, dpms_mode);
+                       intel_release_load_detect_pipe(intel_encoder,
+                                                      connector, dpms_mode);
                } else
                        status = connector_status_unknown;
        }
@@ -421,9 +439,6 @@ static enum drm_connector_status intel_crt_detect(struct drm_connector *connecto
 
 static void intel_crt_destroy(struct drm_connector *connector)
 {
-       struct intel_encoder *intel_encoder = to_intel_encoder(connector);
-
-       intel_i2c_destroy(intel_encoder->ddc_bus);
        drm_sysfs_connector_remove(connector);
        drm_connector_cleanup(connector);
        kfree(connector);
@@ -432,29 +447,27 @@ static void intel_crt_destroy(struct drm_connector *connector)
 static int intel_crt_get_modes(struct drm_connector *connector)
 {
        int ret;
-       struct intel_encoder *intel_encoder = to_intel_encoder(connector);
-       struct i2c_adapter *ddcbus;
+       struct drm_encoder *encoder = intel_attached_encoder(connector);
+       struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
+       struct i2c_adapter *ddc_bus;
        struct drm_device *dev = connector->dev;
 
 
-       ret = intel_ddc_get_modes(intel_encoder);
+       ret = intel_ddc_get_modes(connector, intel_encoder->ddc_bus);
        if (ret || !IS_G4X(dev))
                goto end;
 
-       ddcbus = intel_encoder->ddc_bus;
        /* Try to probe digital port for output in DVI-I -> VGA mode. */
-       intel_encoder->ddc_bus =
-               intel_i2c_create(connector->dev, GPIOD, "CRTDDC_D");
+       ddc_bus = intel_i2c_create(connector->dev, GPIOD, "CRTDDC_D");
 
-       if (!intel_encoder->ddc_bus) {
-               intel_encoder->ddc_bus = ddcbus;
+       if (!ddc_bus) {
                dev_printk(KERN_ERR, &connector->dev->pdev->dev,
                           "DDC bus registration failed for CRTDDC_D.\n");
                goto end;
        }
        /* Try to get modes by GPIOD port */
-       ret = intel_ddc_get_modes(intel_encoder);
-       intel_i2c_destroy(ddcbus);
+       ret = intel_ddc_get_modes(connector, ddc_bus);
+       intel_i2c_destroy(ddc_bus);
 
 end:
        return ret;
@@ -491,12 +504,16 @@ static const struct drm_connector_funcs intel_crt_connector_funcs = {
 static const struct drm_connector_helper_funcs intel_crt_connector_helper_funcs = {
        .mode_valid = intel_crt_mode_valid,
        .get_modes = intel_crt_get_modes,
-       .best_encoder = intel_best_encoder,
+       .best_encoder = intel_attached_encoder,
 };
 
 static void intel_crt_enc_destroy(struct drm_encoder *encoder)
 {
+       struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
+
+       intel_i2c_destroy(intel_encoder->ddc_bus);
        drm_encoder_cleanup(encoder);
+       kfree(intel_encoder);
 }
 
 static const struct drm_encoder_funcs intel_crt_enc_funcs = {
@@ -507,6 +524,7 @@ void intel_crt_init(struct drm_device *dev)
 {
        struct drm_connector *connector;
        struct intel_encoder *intel_encoder;
+       struct intel_connector *intel_connector;
        struct drm_i915_private *dev_priv = dev->dev_private;
        u32 i2c_reg;
 
@@ -514,14 +532,20 @@ void intel_crt_init(struct drm_device *dev)
        if (!intel_encoder)
                return;
 
-       connector = &intel_encoder->base;
-       drm_connector_init(dev, &intel_encoder->base,
+       intel_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL);
+       if (!intel_connector) {
+               kfree(intel_encoder);
+               return;
+       }
+
+       connector = &intel_connector->base;
+       drm_connector_init(dev, &intel_connector->base,
                           &intel_crt_connector_funcs, DRM_MODE_CONNECTOR_VGA);
 
        drm_encoder_init(dev, &intel_encoder->enc, &intel_crt_enc_funcs,
                         DRM_MODE_ENCODER_DAC);
 
-       drm_mode_connector_attach_encoder(&intel_encoder->base,
+       drm_mode_connector_attach_encoder(&intel_connector->base,
                                          &intel_encoder->enc);
 
        /* Set up the DDC bus. */
index e7356fb..4bb60af 100644 (file)
@@ -742,12 +742,11 @@ bool intel_pipe_has_type (struct drm_crtc *crtc, int type)
 {
     struct drm_device *dev = crtc->dev;
     struct drm_mode_config *mode_config = &dev->mode_config;
-    struct drm_connector *l_entry;
+    struct drm_encoder *l_entry;
 
-    list_for_each_entry(l_entry, &mode_config->connector_list, head) {
-           if (l_entry->encoder &&
-               l_entry->encoder->crtc == crtc) {
-                   struct intel_encoder *intel_encoder = to_intel_encoder(l_entry);
+    list_for_each_entry(l_entry, &mode_config->encoder_list, head) {
+           if (l_entry && l_entry->crtc == crtc) {
+                   struct intel_encoder *intel_encoder = enc_to_intel_encoder(l_entry);
                    if (intel_encoder->type == type)
                            return true;
            }
@@ -755,23 +754,6 @@ bool intel_pipe_has_type (struct drm_crtc *crtc, int type)
     return false;
 }
 
-static struct drm_connector *
-intel_pipe_get_connector (struct drm_crtc *crtc)
-{
-    struct drm_device *dev = crtc->dev;
-    struct drm_mode_config *mode_config = &dev->mode_config;
-    struct drm_connector *l_entry, *ret = NULL;
-
-    list_for_each_entry(l_entry, &mode_config->connector_list, head) {
-           if (l_entry->encoder &&
-               l_entry->encoder->crtc == crtc) {
-                   ret = l_entry;
-                   break;
-           }
-    }
-    return ret;
-}
-
 #define INTELPllInvalid(s)   do { /* DRM_DEBUG(s); */ return false; } while (0)
 /**
  * Returns whether the given set of divisors are valid for a given refclk with
@@ -1510,6 +1492,219 @@ static void ironlake_set_pll_edp (struct drm_crtc *crtc, int clock)
        udelay(500);
 }
 
+/* The FDI link training functions for ILK/Ibexpeak. */
+static void ironlake_fdi_link_train(struct drm_crtc *crtc)
+{
+       struct drm_device *dev = crtc->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       int pipe = intel_crtc->pipe;
+       int fdi_tx_reg = (pipe == 0) ? FDI_TXA_CTL : FDI_TXB_CTL;
+       int fdi_rx_reg = (pipe == 0) ? FDI_RXA_CTL : FDI_RXB_CTL;
+       int fdi_rx_iir_reg = (pipe == 0) ? FDI_RXA_IIR : FDI_RXB_IIR;
+       int fdi_rx_imr_reg = (pipe == 0) ? FDI_RXA_IMR : FDI_RXB_IMR;
+       u32 temp, tries = 0;
+
+       /* enable CPU FDI TX and PCH FDI RX */
+       temp = I915_READ(fdi_tx_reg);
+       temp |= FDI_TX_ENABLE;
+       temp &= ~(7 << 19);
+       temp |= (intel_crtc->fdi_lanes - 1) << 19;
+       temp &= ~FDI_LINK_TRAIN_NONE;
+       temp |= FDI_LINK_TRAIN_PATTERN_1;
+       I915_WRITE(fdi_tx_reg, temp);
+       I915_READ(fdi_tx_reg);
+
+       temp = I915_READ(fdi_rx_reg);
+       temp &= ~FDI_LINK_TRAIN_NONE;
+       temp |= FDI_LINK_TRAIN_PATTERN_1;
+       I915_WRITE(fdi_rx_reg, temp | FDI_RX_ENABLE);
+       I915_READ(fdi_rx_reg);
+       udelay(150);
+
+       /* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit
+          for train result */
+       temp = I915_READ(fdi_rx_imr_reg);
+       temp &= ~FDI_RX_SYMBOL_LOCK;
+       temp &= ~FDI_RX_BIT_LOCK;
+       I915_WRITE(fdi_rx_imr_reg, temp);
+       I915_READ(fdi_rx_imr_reg);
+       udelay(150);
+
+       for (;;) {
+               temp = I915_READ(fdi_rx_iir_reg);
+               DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp);
+
+               if ((temp & FDI_RX_BIT_LOCK)) {
+                       DRM_DEBUG_KMS("FDI train 1 done.\n");
+                       I915_WRITE(fdi_rx_iir_reg,
+                                  temp | FDI_RX_BIT_LOCK);
+                       break;
+               }
+
+               tries++;
+
+               if (tries > 5) {
+                       DRM_DEBUG_KMS("FDI train 1 fail!\n");
+                       break;
+               }
+       }
+
+       /* Train 2 */
+       temp = I915_READ(fdi_tx_reg);
+       temp &= ~FDI_LINK_TRAIN_NONE;
+       temp |= FDI_LINK_TRAIN_PATTERN_2;
+       I915_WRITE(fdi_tx_reg, temp);
+
+       temp = I915_READ(fdi_rx_reg);
+       temp &= ~FDI_LINK_TRAIN_NONE;
+       temp |= FDI_LINK_TRAIN_PATTERN_2;
+       I915_WRITE(fdi_rx_reg, temp);
+       udelay(150);
+
+       tries = 0;
+
+       for (;;) {
+               temp = I915_READ(fdi_rx_iir_reg);
+               DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp);
+
+               if (temp & FDI_RX_SYMBOL_LOCK) {
+                       I915_WRITE(fdi_rx_iir_reg,
+                                  temp | FDI_RX_SYMBOL_LOCK);
+                       DRM_DEBUG_KMS("FDI train 2 done.\n");
+                       break;
+               }
+
+               tries++;
+
+               if (tries > 5) {
+                       DRM_DEBUG_KMS("FDI train 2 fail!\n");
+                       break;
+               }
+       }
+
+       DRM_DEBUG_KMS("FDI train done\n");
+}
+
+static int snb_b_fdi_train_param [] = {
+       FDI_LINK_TRAIN_400MV_0DB_SNB_B,
+       FDI_LINK_TRAIN_400MV_6DB_SNB_B,
+       FDI_LINK_TRAIN_600MV_3_5DB_SNB_B,
+       FDI_LINK_TRAIN_800MV_0DB_SNB_B,
+};
+
+/* The FDI link training functions for SNB/Cougarpoint. */
+static void gen6_fdi_link_train(struct drm_crtc *crtc)
+{
+       struct drm_device *dev = crtc->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       int pipe = intel_crtc->pipe;
+       int fdi_tx_reg = (pipe == 0) ? FDI_TXA_CTL : FDI_TXB_CTL;
+       int fdi_rx_reg = (pipe == 0) ? FDI_RXA_CTL : FDI_RXB_CTL;
+       int fdi_rx_iir_reg = (pipe == 0) ? FDI_RXA_IIR : FDI_RXB_IIR;
+       int fdi_rx_imr_reg = (pipe == 0) ? FDI_RXA_IMR : FDI_RXB_IMR;
+       u32 temp, i;
+
+       /* enable CPU FDI TX and PCH FDI RX */
+       temp = I915_READ(fdi_tx_reg);
+       temp |= FDI_TX_ENABLE;
+       temp &= ~(7 << 19);
+       temp |= (intel_crtc->fdi_lanes - 1) << 19;
+       temp &= ~FDI_LINK_TRAIN_NONE;
+       temp |= FDI_LINK_TRAIN_PATTERN_1;
+       temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
+       /* SNB-B */
+       temp |= FDI_LINK_TRAIN_400MV_0DB_SNB_B;
+       I915_WRITE(fdi_tx_reg, temp);
+       I915_READ(fdi_tx_reg);
+
+       temp = I915_READ(fdi_rx_reg);
+       if (HAS_PCH_CPT(dev)) {
+               temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
+               temp |= FDI_LINK_TRAIN_PATTERN_1_CPT;
+       } else {
+               temp &= ~FDI_LINK_TRAIN_NONE;
+               temp |= FDI_LINK_TRAIN_PATTERN_1;
+       }
+       I915_WRITE(fdi_rx_reg, temp | FDI_RX_ENABLE);
+       I915_READ(fdi_rx_reg);
+       udelay(150);
+
+       /* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit
+          for train result */
+       temp = I915_READ(fdi_rx_imr_reg);
+       temp &= ~FDI_RX_SYMBOL_LOCK;
+       temp &= ~FDI_RX_BIT_LOCK;
+       I915_WRITE(fdi_rx_imr_reg, temp);
+       I915_READ(fdi_rx_imr_reg);
+       udelay(150);
+
+       for (i = 0; i < 4; i++ ) {
+               temp = I915_READ(fdi_tx_reg);
+               temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
+               temp |= snb_b_fdi_train_param[i];
+               I915_WRITE(fdi_tx_reg, temp);
+               udelay(500);
+
+               temp = I915_READ(fdi_rx_iir_reg);
+               DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp);
+
+               if (temp & FDI_RX_BIT_LOCK) {
+                       I915_WRITE(fdi_rx_iir_reg,
+                                  temp | FDI_RX_BIT_LOCK);
+                       DRM_DEBUG_KMS("FDI train 1 done.\n");
+                       break;
+               }
+       }
+       if (i == 4)
+               DRM_DEBUG_KMS("FDI train 1 fail!\n");
+
+       /* Train 2 */
+       temp = I915_READ(fdi_tx_reg);
+       temp &= ~FDI_LINK_TRAIN_NONE;
+       temp |= FDI_LINK_TRAIN_PATTERN_2;
+       if (IS_GEN6(dev)) {
+               temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
+               /* SNB-B */
+               temp |= FDI_LINK_TRAIN_400MV_0DB_SNB_B;
+       }
+       I915_WRITE(fdi_tx_reg, temp);
+
+       temp = I915_READ(fdi_rx_reg);
+       if (HAS_PCH_CPT(dev)) {
+               temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
+               temp |= FDI_LINK_TRAIN_PATTERN_2_CPT;
+       } else {
+               temp &= ~FDI_LINK_TRAIN_NONE;
+               temp |= FDI_LINK_TRAIN_PATTERN_2;
+       }
+       I915_WRITE(fdi_rx_reg, temp);
+       udelay(150);
+
+       for (i = 0; i < 4; i++ ) {
+               temp = I915_READ(fdi_tx_reg);
+               temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
+               temp |= snb_b_fdi_train_param[i];
+               I915_WRITE(fdi_tx_reg, temp);
+               udelay(500);
+
+               temp = I915_READ(fdi_rx_iir_reg);
+               DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp);
+
+               if (temp & FDI_RX_SYMBOL_LOCK) {
+                       I915_WRITE(fdi_rx_iir_reg,
+                                  temp | FDI_RX_SYMBOL_LOCK);
+                       DRM_DEBUG_KMS("FDI train 2 done.\n");
+                       break;
+               }
+       }
+       if (i == 4)
+               DRM_DEBUG_KMS("FDI train 2 fail!\n");
+
+       DRM_DEBUG_KMS("FDI train done.\n");
+}
+
 static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode)
 {
        struct drm_device *dev = crtc->dev;
@@ -1523,8 +1718,6 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode)
        int dspbase_reg = (plane == 0) ? DSPAADDR : DSPBADDR;
        int fdi_tx_reg = (pipe == 0) ? FDI_TXA_CTL : FDI_TXB_CTL;
        int fdi_rx_reg = (pipe == 0) ? FDI_RXA_CTL : FDI_RXB_CTL;
-       int fdi_rx_iir_reg = (pipe == 0) ? FDI_RXA_IIR : FDI_RXB_IIR;
-       int fdi_rx_imr_reg = (pipe == 0) ? FDI_RXA_IMR : FDI_RXB_IMR;
        int transconf_reg = (pipe == 0) ? TRANSACONF : TRANSBCONF;
        int pf_ctl_reg = (pipe == 0) ? PFA_CTL_1 : PFB_CTL_1;
        int pf_win_size = (pipe == 0) ? PFA_WIN_SZ : PFB_WIN_SZ;
@@ -1541,8 +1734,9 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode)
        int trans_vtot_reg = (pipe == 0) ? TRANS_VTOTAL_A : TRANS_VTOTAL_B;
        int trans_vblank_reg = (pipe == 0) ? TRANS_VBLANK_A : TRANS_VBLANK_B;
        int trans_vsync_reg = (pipe == 0) ? TRANS_VSYNC_A : TRANS_VSYNC_B;
+       int trans_dpll_sel = (pipe == 0) ? 0 : 1;
        u32 temp;
-       int tries = 5, j, n;
+       int n;
        u32 pipe_bpc;
 
        temp = I915_READ(pipeconf_reg);
@@ -1569,12 +1763,6 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode)
                        /* enable eDP PLL */
                        ironlake_enable_pll_edp(crtc);
                } else {
-                       /* enable PCH DPLL */
-                       temp = I915_READ(pch_dpll_reg);
-                       if ((temp & DPLL_VCO_ENABLE) == 0) {
-                               I915_WRITE(pch_dpll_reg, temp | DPLL_VCO_ENABLE);
-                               I915_READ(pch_dpll_reg);
-                       }
 
                        /* enable PCH FDI RX PLL, wait warmup plus DMI latency */
                        temp = I915_READ(fdi_rx_reg);
@@ -1584,9 +1772,15 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode)
                         */
                        temp &= ~(0x7 << 16);
                        temp |= (pipe_bpc << 11);
-                       I915_WRITE(fdi_rx_reg, temp | FDI_RX_PLL_ENABLE |
-                                       FDI_SEL_PCDCLK |
-                                       FDI_DP_PORT_WIDTH_X4); /* default 4 lanes */
+                       temp &= ~(7 << 19);
+                       temp |= (intel_crtc->fdi_lanes - 1) << 19;
+                       I915_WRITE(fdi_rx_reg, temp | FDI_RX_PLL_ENABLE);
+                       I915_READ(fdi_rx_reg);
+                       udelay(200);
+
+                       /* Switch from Rawclk to PCDclk */
+                       temp = I915_READ(fdi_rx_reg);
+                       I915_WRITE(fdi_rx_reg, temp | FDI_SEL_PCDCLK);
                        I915_READ(fdi_rx_reg);
                        udelay(200);
 
@@ -1629,91 +1823,32 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode)
                }
 
                if (!HAS_eDP) {
-                       /* enable CPU FDI TX and PCH FDI RX */
-                       temp = I915_READ(fdi_tx_reg);
-                       temp |= FDI_TX_ENABLE;
-                       temp |= FDI_DP_PORT_WIDTH_X4; /* default */
-                       temp &= ~FDI_LINK_TRAIN_NONE;
-                       temp |= FDI_LINK_TRAIN_PATTERN_1;
-                       I915_WRITE(fdi_tx_reg, temp);
-                       I915_READ(fdi_tx_reg);
-
-                       temp = I915_READ(fdi_rx_reg);
-                       temp &= ~FDI_LINK_TRAIN_NONE;
-                       temp |= FDI_LINK_TRAIN_PATTERN_1;
-                       I915_WRITE(fdi_rx_reg, temp | FDI_RX_ENABLE);
-                       I915_READ(fdi_rx_reg);
-
-                       udelay(150);
-
-                       /* Train FDI. */
-                       /* umask FDI RX Interrupt symbol_lock and bit_lock bit
-                          for train result */
-                       temp = I915_READ(fdi_rx_imr_reg);
-                       temp &= ~FDI_RX_SYMBOL_LOCK;
-                       temp &= ~FDI_RX_BIT_LOCK;
-                       I915_WRITE(fdi_rx_imr_reg, temp);
-                       I915_READ(fdi_rx_imr_reg);
-                       udelay(150);
+                       /* For PCH output, training FDI link */
+                       if (IS_GEN6(dev))
+                               gen6_fdi_link_train(crtc);
+                       else
+                               ironlake_fdi_link_train(crtc);
 
-                       temp = I915_READ(fdi_rx_iir_reg);
-                       DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp);
-
-                       if ((temp & FDI_RX_BIT_LOCK) == 0) {
-                               for (j = 0; j < tries; j++) {
-                                       temp = I915_READ(fdi_rx_iir_reg);
-                                       DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n",
-                                                               temp);
-                                       if (temp & FDI_RX_BIT_LOCK)
-                                               break;
-                                       udelay(200);
-                               }
-                               if (j != tries)
-                                       I915_WRITE(fdi_rx_iir_reg,
-                                                       temp | FDI_RX_BIT_LOCK);
-                               else
-                                       DRM_DEBUG_KMS("train 1 fail\n");
-                       } else {
-                               I915_WRITE(fdi_rx_iir_reg,
-                                               temp | FDI_RX_BIT_LOCK);
-                               DRM_DEBUG_KMS("train 1 ok 2!\n");
+                       /* enable PCH DPLL */
+                       temp = I915_READ(pch_dpll_reg);
+                       if ((temp & DPLL_VCO_ENABLE) == 0) {
+                               I915_WRITE(pch_dpll_reg, temp | DPLL_VCO_ENABLE);
+                               I915_READ(pch_dpll_reg);
                        }
-                       temp = I915_READ(fdi_tx_reg);
-                       temp &= ~FDI_LINK_TRAIN_NONE;
-                       temp |= FDI_LINK_TRAIN_PATTERN_2;
-                       I915_WRITE(fdi_tx_reg, temp);
-
-                       temp = I915_READ(fdi_rx_reg);
-                       temp &= ~FDI_LINK_TRAIN_NONE;
-                       temp |= FDI_LINK_TRAIN_PATTERN_2;
-                       I915_WRITE(fdi_rx_reg, temp);
-
-                       udelay(150);
+                       udelay(200);
 
-                       temp = I915_READ(fdi_rx_iir_reg);
-                       DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp);
-
-                       if ((temp & FDI_RX_SYMBOL_LOCK) == 0) {
-                               for (j = 0; j < tries; j++) {
-                                       temp = I915_READ(fdi_rx_iir_reg);
-                                       DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n",
-                                                               temp);
-                                       if (temp & FDI_RX_SYMBOL_LOCK)
-                                               break;
-                                       udelay(200);
-                               }
-                               if (j != tries) {
-                                       I915_WRITE(fdi_rx_iir_reg,
-                                                       temp | FDI_RX_SYMBOL_LOCK);
-                                       DRM_DEBUG_KMS("train 2 ok 1!\n");
-                               } else
-                                       DRM_DEBUG_KMS("train 2 fail\n");
-                       } else {
-                               I915_WRITE(fdi_rx_iir_reg,
-                                               temp | FDI_RX_SYMBOL_LOCK);
-                               DRM_DEBUG_KMS("train 2 ok 2!\n");
+                       if (HAS_PCH_CPT(dev)) {
+                               /* Be sure PCH DPLL SEL is set */
+                               temp = I915_READ(PCH_DPLL_SEL);
+                               if (trans_dpll_sel == 0 &&
+                                               (temp & TRANSA_DPLL_ENABLE) == 0)
+                                       temp |= (TRANSA_DPLL_ENABLE | TRANSA_DPLLA_SEL);
+                               else if (trans_dpll_sel == 1 &&
+                                               (temp & TRANSB_DPLL_ENABLE) == 0)
+                                       temp |= (TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL);
+                               I915_WRITE(PCH_DPLL_SEL, temp);
+                               I915_READ(PCH_DPLL_SEL);
                        }
-                       DRM_DEBUG_KMS("train done\n");
 
                        /* set transcoder timing */
                        I915_WRITE(trans_htot_reg, I915_READ(cpu_htot_reg));
@@ -1724,6 +1859,60 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode)
                        I915_WRITE(trans_vblank_reg, I915_READ(cpu_vblank_reg));
                        I915_WRITE(trans_vsync_reg, I915_READ(cpu_vsync_reg));
 
+                       /* enable normal train */
+                       temp = I915_READ(fdi_tx_reg);
+                       temp &= ~FDI_LINK_TRAIN_NONE;
+                       I915_WRITE(fdi_tx_reg, temp | FDI_LINK_TRAIN_NONE |
+                                       FDI_TX_ENHANCE_FRAME_ENABLE);
+                       I915_READ(fdi_tx_reg);
+
+                       temp = I915_READ(fdi_rx_reg);
+                       if (HAS_PCH_CPT(dev)) {
+                               temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
+                               temp |= FDI_LINK_TRAIN_NORMAL_CPT;
+                       } else {
+                               temp &= ~FDI_LINK_TRAIN_NONE;
+                               temp |= FDI_LINK_TRAIN_NONE;
+                       }
+                       I915_WRITE(fdi_rx_reg, temp | FDI_RX_ENHANCE_FRAME_ENABLE);
+                       I915_READ(fdi_rx_reg);
+
+                       /* wait one idle pattern time */
+                       udelay(100);
+
+                       /* For PCH DP, enable TRANS_DP_CTL */
+                       if (HAS_PCH_CPT(dev) &&
+                           intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT)) {
+                               int trans_dp_ctl = (pipe == 0) ? TRANS_DP_CTL_A : TRANS_DP_CTL_B;
+                               int reg;
+
+                               reg = I915_READ(trans_dp_ctl);
+                               reg &= ~TRANS_DP_PORT_SEL_MASK;
+                               reg = TRANS_DP_OUTPUT_ENABLE |
+                                     TRANS_DP_ENH_FRAMING |
+                                     TRANS_DP_VSYNC_ACTIVE_HIGH |
+                                     TRANS_DP_HSYNC_ACTIVE_HIGH;
+
+                               switch (intel_trans_dp_port_sel(crtc)) {
+                               case PCH_DP_B:
+                                       reg |= TRANS_DP_PORT_SEL_B;
+                                       break;
+                               case PCH_DP_C:
+                                       reg |= TRANS_DP_PORT_SEL_C;
+                                       break;
+                               case PCH_DP_D:
+                                       reg |= TRANS_DP_PORT_SEL_D;
+                                       break;
+                               default:
+                                       DRM_DEBUG_KMS("Wrong PCH DP port return. Guess port B\n");
+                                       reg |= TRANS_DP_PORT_SEL_B;
+                                       break;
+                               }
+
+                               I915_WRITE(trans_dp_ctl, reg);
+                               POSTING_READ(trans_dp_ctl);
+                       }
+
                        /* enable PCH transcoder */
                        temp = I915_READ(transconf_reg);
                        /*
@@ -1738,23 +1927,6 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode)
                        while ((I915_READ(transconf_reg) & TRANS_STATE_ENABLE) == 0)
                                ;
 
-                       /* enable normal */
-
-                       temp = I915_READ(fdi_tx_reg);
-                       temp &= ~FDI_LINK_TRAIN_NONE;
-                       I915_WRITE(fdi_tx_reg, temp | FDI_LINK_TRAIN_NONE |
-                                       FDI_TX_ENHANCE_FRAME_ENABLE);
-                       I915_READ(fdi_tx_reg);
-
-                       temp = I915_READ(fdi_rx_reg);
-                       temp &= ~FDI_LINK_TRAIN_NONE;
-                       I915_WRITE(fdi_rx_reg, temp | FDI_LINK_TRAIN_NONE |
-                                       FDI_RX_ENHANCE_FRAME_ENABLE);
-                       I915_READ(fdi_rx_reg);
-
-                       /* wait one idle pattern time */
-                       udelay(100);
-
                }
 
                intel_crtc_load_lut(crtc);
@@ -1805,6 +1977,8 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode)
                        I915_READ(pf_ctl_reg);
                }
                I915_WRITE(pf_win_size, 0);
+               POSTING_READ(pf_win_size);
+
 
                /* disable CPU FDI tx and PCH FDI rx */
                temp = I915_READ(fdi_tx_reg);
@@ -1825,11 +1999,18 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode)
                temp &= ~FDI_LINK_TRAIN_NONE;
                temp |= FDI_LINK_TRAIN_PATTERN_1;
                I915_WRITE(fdi_tx_reg, temp);
+               POSTING_READ(fdi_tx_reg);
 
                temp = I915_READ(fdi_rx_reg);
-               temp &= ~FDI_LINK_TRAIN_NONE;
-               temp |= FDI_LINK_TRAIN_PATTERN_1;
+               if (HAS_PCH_CPT(dev)) {
+                       temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
+                       temp |= FDI_LINK_TRAIN_PATTERN_1_CPT;
+               } else {
+                       temp &= ~FDI_LINK_TRAIN_NONE;
+                       temp |= FDI_LINK_TRAIN_PATTERN_1;
+               }
                I915_WRITE(fdi_rx_reg, temp);
+               POSTING_READ(fdi_rx_reg);
 
                udelay(100);
 
@@ -1859,6 +2040,7 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode)
                                }
                        }
                }
+
                temp = I915_READ(transconf_reg);
                /* BPC in transcoder is consistent with that in pipeconf */
                temp &= ~PIPE_BPC_MASK;
@@ -1867,35 +2049,53 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode)
                I915_READ(transconf_reg);
                udelay(100);
 
+               if (HAS_PCH_CPT(dev)) {
+                       /* disable TRANS_DP_CTL */
+                       int trans_dp_ctl = (pipe == 0) ? TRANS_DP_CTL_A : TRANS_DP_CTL_B;
+                       int reg;
+
+                       reg = I915_READ(trans_dp_ctl);
+                       reg &= ~(TRANS_DP_OUTPUT_ENABLE | TRANS_DP_PORT_SEL_MASK);
+                       I915_WRITE(trans_dp_ctl, reg);
+                       POSTING_READ(trans_dp_ctl);
+
+                       /* disable DPLL_SEL */
+                       temp = I915_READ(PCH_DPLL_SEL);
+                       if (trans_dpll_sel == 0)
+                               temp &= ~(TRANSA_DPLL_ENABLE | TRANSA_DPLLB_SEL);
+                       else
+                               temp &= ~(TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL);
+                       I915_WRITE(PCH_DPLL_SEL, temp);
+                       I915_READ(PCH_DPLL_SEL);
+
+               }
+
                /* disable PCH DPLL */
                temp = I915_READ(pch_dpll_reg);
-               if ((temp & DPLL_VCO_ENABLE) != 0) {
-                       I915_WRITE(pch_dpll_reg, temp & ~DPLL_VCO_ENABLE);
-                       I915_READ(pch_dpll_reg);
-               }
+               I915_WRITE(pch_dpll_reg, temp & ~DPLL_VCO_ENABLE);
+               I915_READ(pch_dpll_reg);
 
                if (HAS_eDP) {
                        ironlake_disable_pll_edp(crtc);
                }
 
+               /* Switch from PCDclk to Rawclk */
                temp = I915_READ(fdi_rx_reg);
                temp &= ~FDI_SEL_PCDCLK;
                I915_WRITE(fdi_rx_reg, temp);
                I915_READ(fdi_rx_reg);
 
+               /* Disable CPU FDI TX PLL */
+               temp = I915_READ(fdi_tx_reg);
+               I915_WRITE(fdi_tx_reg, temp & ~FDI_TX_PLL_ENABLE);
+               I915_READ(fdi_tx_reg);
+               udelay(100);
+
                temp = I915_READ(fdi_rx_reg);
                temp &= ~FDI_RX_PLL_ENABLE;
                I915_WRITE(fdi_rx_reg, temp);
                I915_READ(fdi_rx_reg);
 
-               /* Disable CPU FDI TX PLL */
-               temp = I915_READ(fdi_tx_reg);
-               if ((temp & FDI_TX_PLL_ENABLE) != 0) {
-                       I915_WRITE(fdi_tx_reg, temp & ~FDI_TX_PLL_ENABLE);
-                       I915_READ(fdi_tx_reg);
-                       udelay(100);
-               }
-
                /* Wait for the clocks to turn off. */
                udelay(100);
                break;
@@ -2331,6 +2531,30 @@ static struct intel_watermark_params i830_wm_info = {
        I830_FIFO_LINE_SIZE
 };
 
+static struct intel_watermark_params ironlake_display_wm_info = {
+       ILK_DISPLAY_FIFO,
+       ILK_DISPLAY_MAXWM,
+       ILK_DISPLAY_DFTWM,
+       2,
+       ILK_FIFO_LINE_SIZE
+};
+
+static struct intel_watermark_params ironlake_display_srwm_info = {
+       ILK_DISPLAY_SR_FIFO,
+       ILK_DISPLAY_MAX_SRWM,
+       ILK_DISPLAY_DFT_SRWM,
+       2,
+       ILK_FIFO_LINE_SIZE
+};
+
+static struct intel_watermark_params ironlake_cursor_srwm_info = {
+       ILK_CURSOR_SR_FIFO,
+       ILK_CURSOR_MAX_SRWM,
+       ILK_CURSOR_DFT_SRWM,
+       2,
+       ILK_FIFO_LINE_SIZE
+};
+
 /**
  * intel_calculate_wm - calculate watermark level
  * @clock_in_khz: pixel clock
@@ -2449,66 +2673,6 @@ static void pineview_disable_cxsr(struct drm_device *dev)
        DRM_INFO("Big FIFO is disabled\n");
 }
 
-static void pineview_enable_cxsr(struct drm_device *dev, unsigned long clock,
-                                int pixel_size)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 reg;
-       unsigned long wm;
-       struct cxsr_latency *latency;
-
-       latency = intel_get_cxsr_latency(IS_PINEVIEW_G(dev), dev_priv->fsb_freq,
-               dev_priv->mem_freq);
-       if (!latency) {
-               DRM_DEBUG_KMS("Unknown FSB/MEM found, disable CxSR\n");
-               pineview_disable_cxsr(dev);
-               return;
-       }
-
-       /* Display SR */
-       wm = intel_calculate_wm(clock, &pineview_display_wm, pixel_size,
-                               latency->display_sr);
-       reg = I915_READ(DSPFW1);
-       reg &= 0x7fffff;
-       reg |= wm << 23;
-       I915_WRITE(DSPFW1, reg);
-       DRM_DEBUG_KMS("DSPFW1 register is %x\n", reg);
-
-       /* cursor SR */
-       wm = intel_calculate_wm(clock, &pineview_cursor_wm, pixel_size,
-                               latency->cursor_sr);
-       reg = I915_READ(DSPFW3);
-       reg &= ~(0x3f << 24);
-       reg |= (wm & 0x3f) << 24;
-       I915_WRITE(DSPFW3, reg);
-
-       /* Display HPLL off SR */
-       wm = intel_calculate_wm(clock, &pineview_display_hplloff_wm,
-               latency->display_hpll_disable, I915_FIFO_LINE_SIZE);
-       reg = I915_READ(DSPFW3);
-       reg &= 0xfffffe00;
-       reg |= wm & 0x1ff;
-       I915_WRITE(DSPFW3, reg);
-
-       /* cursor HPLL off SR */
-       wm = intel_calculate_wm(clock, &pineview_cursor_hplloff_wm, pixel_size,
-                               latency->cursor_hpll_disable);
-       reg = I915_READ(DSPFW3);
-       reg &= ~(0x3f << 16);
-       reg |= (wm & 0x3f) << 16;
-       I915_WRITE(DSPFW3, reg);
-       DRM_DEBUG_KMS("DSPFW3 register is %x\n", reg);
-
-       /* activate cxsr */
-       reg = I915_READ(DSPFW3);
-       reg |= PINEVIEW_SELF_REFRESH_EN;
-       I915_WRITE(DSPFW3, reg);
-
-       DRM_INFO("Big FIFO is enabled\n");
-
-       return;
-}
-
 /*
  * Latency for FIFO fetches is dependent on several factors:
  *   - memory configuration (speed, channels)
@@ -2593,6 +2757,71 @@ static int i830_get_fifo_size(struct drm_device *dev, int plane)
        return size;
 }
 
+static void pineview_update_wm(struct drm_device *dev,  int planea_clock,
+                         int planeb_clock, int sr_hdisplay, int pixel_size)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 reg;
+       unsigned long wm;
+       struct cxsr_latency *latency;
+       int sr_clock;
+
+       latency = intel_get_cxsr_latency(IS_PINEVIEW_G(dev), dev_priv->fsb_freq,
+                                        dev_priv->mem_freq);
+       if (!latency) {
+               DRM_DEBUG_KMS("Unknown FSB/MEM found, disable CxSR\n");
+               pineview_disable_cxsr(dev);
+               return;
+       }
+
+       if (!planea_clock || !planeb_clock) {
+               sr_clock = planea_clock ? planea_clock : planeb_clock;
+
+               /* Display SR */
+               wm = intel_calculate_wm(sr_clock, &pineview_display_wm,
+                                       pixel_size, latency->display_sr);
+               reg = I915_READ(DSPFW1);
+               reg &= ~DSPFW_SR_MASK;
+               reg |= wm << DSPFW_SR_SHIFT;
+               I915_WRITE(DSPFW1, reg);
+               DRM_DEBUG_KMS("DSPFW1 register is %x\n", reg);
+
+               /* cursor SR */
+               wm = intel_calculate_wm(sr_clock, &pineview_cursor_wm,
+                                       pixel_size, latency->cursor_sr);
+               reg = I915_READ(DSPFW3);
+               reg &= ~DSPFW_CURSOR_SR_MASK;
+               reg |= (wm & 0x3f) << DSPFW_CURSOR_SR_SHIFT;
+               I915_WRITE(DSPFW3, reg);
+
+               /* Display HPLL off SR */
+               wm = intel_calculate_wm(sr_clock, &pineview_display_hplloff_wm,
+                                       pixel_size, latency->display_hpll_disable);
+               reg = I915_READ(DSPFW3);
+               reg &= ~DSPFW_HPLL_SR_MASK;
+               reg |= wm & DSPFW_HPLL_SR_MASK;
+               I915_WRITE(DSPFW3, reg);
+
+               /* cursor HPLL off SR */
+               wm = intel_calculate_wm(sr_clock, &pineview_cursor_hplloff_wm,
+                                       pixel_size, latency->cursor_hpll_disable);
+               reg = I915_READ(DSPFW3);
+               reg &= ~DSPFW_HPLL_CURSOR_MASK;
+               reg |= (wm & 0x3f) << DSPFW_HPLL_CURSOR_SHIFT;
+               I915_WRITE(DSPFW3, reg);
+               DRM_DEBUG_KMS("DSPFW3 register is %x\n", reg);
+
+               /* activate cxsr */
+               reg = I915_READ(DSPFW3);
+               reg |= PINEVIEW_SELF_REFRESH_EN;
+               I915_WRITE(DSPFW3, reg);
+               DRM_DEBUG_KMS("Self-refresh is enabled\n");
+       } else {
+               pineview_disable_cxsr(dev);
+               DRM_DEBUG_KMS("Self-refresh is disabled\n");
+       }
+}
+
 static void g4x_update_wm(struct drm_device *dev,  int planea_clock,
                          int planeb_clock, int sr_hdisplay, int pixel_size)
 {
@@ -2813,6 +3042,108 @@ static void i830_update_wm(struct drm_device *dev, int planea_clock, int unused,
        I915_WRITE(FW_BLC, fwater_lo);
 }
 
+#define ILK_LP0_PLANE_LATENCY          700
+
+static void ironlake_update_wm(struct drm_device *dev,  int planea_clock,
+                      int planeb_clock, int sr_hdisplay, int pixel_size)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int planea_wm, planeb_wm, cursora_wm, cursorb_wm;
+       int sr_wm, cursor_wm;
+       unsigned long line_time_us;
+       int sr_clock, entries_required;
+       u32 reg_value;
+
+       /* Calculate and update the watermark for plane A */
+       if (planea_clock) {
+               entries_required = ((planea_clock / 1000) * pixel_size *
+                                    ILK_LP0_PLANE_LATENCY) / 1000;
+               entries_required = DIV_ROUND_UP(entries_required,
+                                  ironlake_display_wm_info.cacheline_size);
+               planea_wm = entries_required +
+                           ironlake_display_wm_info.guard_size;
+
+               if (planea_wm > (int)ironlake_display_wm_info.max_wm)
+                       planea_wm = ironlake_display_wm_info.max_wm;
+
+               cursora_wm = 16;
+               reg_value = I915_READ(WM0_PIPEA_ILK);
+               reg_value &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK);
+               reg_value |= (planea_wm << WM0_PIPE_PLANE_SHIFT) |
+                            (cursora_wm & WM0_PIPE_CURSOR_MASK);
+               I915_WRITE(WM0_PIPEA_ILK, reg_value);
+               DRM_DEBUG_KMS("FIFO watermarks For pipe A - plane %d, "
+                               "cursor: %d\n", planea_wm, cursora_wm);
+       }
+       /* Calculate and update the watermark for plane B */
+       if (planeb_clock) {
+               entries_required = ((planeb_clock / 1000) * pixel_size *
+                                    ILK_LP0_PLANE_LATENCY) / 1000;
+               entries_required = DIV_ROUND_UP(entries_required,
+                                  ironlake_display_wm_info.cacheline_size);
+               planeb_wm = entries_required +
+                           ironlake_display_wm_info.guard_size;
+
+               if (planeb_wm > (int)ironlake_display_wm_info.max_wm)
+                       planeb_wm = ironlake_display_wm_info.max_wm;
+
+               cursorb_wm = 16;
+               reg_value = I915_READ(WM0_PIPEB_ILK);
+               reg_value &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK);
+               reg_value |= (planeb_wm << WM0_PIPE_PLANE_SHIFT) |
+                            (cursorb_wm & WM0_PIPE_CURSOR_MASK);
+               I915_WRITE(WM0_PIPEB_ILK, reg_value);
+               DRM_DEBUG_KMS("FIFO watermarks For pipe B - plane %d, "
+                               "cursor: %d\n", planeb_wm, cursorb_wm);
+       }
+
+       /*
+        * Calculate and update the self-refresh watermark only when one
+        * display plane is used.
+        */
+       if (!planea_clock || !planeb_clock) {
+               int line_count;
+               /* Read the self-refresh latency. The unit is 0.5us */
+               int ilk_sr_latency = I915_READ(MLTR_ILK) & ILK_SRLT_MASK;
+
+               sr_clock = planea_clock ? planea_clock : planeb_clock;
+               line_time_us = ((sr_hdisplay * 1000) / sr_clock);
+
+               /* Use ns/us then divide to preserve precision */
+               line_count = ((ilk_sr_latency * 500) / line_time_us + 1000)
+                              / 1000;
+
+               /* calculate the self-refresh watermark for display plane */
+               entries_required = line_count * sr_hdisplay * pixel_size;
+               entries_required = DIV_ROUND_UP(entries_required,
+                                  ironlake_display_srwm_info.cacheline_size);
+               sr_wm = entries_required +
+                       ironlake_display_srwm_info.guard_size;
+
+               /* calculate the self-refresh watermark for display cursor */
+               entries_required = line_count * pixel_size * 64;
+               entries_required = DIV_ROUND_UP(entries_required,
+                                  ironlake_cursor_srwm_info.cacheline_size);
+               cursor_wm = entries_required +
+                           ironlake_cursor_srwm_info.guard_size;
+
+               /* configure watermark and enable self-refresh */
+               reg_value = I915_READ(WM1_LP_ILK);
+               reg_value &= ~(WM1_LP_LATENCY_MASK | WM1_LP_SR_MASK |
+                              WM1_LP_CURSOR_MASK);
+               reg_value |= WM1_LP_SR_EN |
+                            (ilk_sr_latency << WM1_LP_LATENCY_SHIFT) |
+                            (sr_wm << WM1_LP_SR_SHIFT) | cursor_wm;
+
+               I915_WRITE(WM1_LP_ILK, reg_value);
+               DRM_DEBUG_KMS("self-refresh watermark: display plane %d "
+                               "cursor %d\n", sr_wm, cursor_wm);
+
+       } else {
+               /* Turn off self refresh if both pipes are enabled */
+               I915_WRITE(WM1_LP_ILK, I915_READ(WM1_LP_ILK) & ~WM1_LP_SR_EN);
+       }
+}
 /**
  * intel_update_watermarks - update FIFO watermark values based on current modes
  *
@@ -2882,12 +3213,6 @@ static void intel_update_watermarks(struct drm_device *dev)
        if (enabled <= 0)
                return;
 
-       /* Single plane configs can enable self refresh */
-       if (enabled == 1 && IS_PINEVIEW(dev))
-               pineview_enable_cxsr(dev, sr_clock, pixel_size);
-       else if (IS_PINEVIEW(dev))
-               pineview_disable_cxsr(dev);
-
        dev_priv->display.update_wm(dev, planea_clock, planeb_clock,
                                    sr_hdisplay, pixel_size);
 }
@@ -2924,7 +3249,8 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
        bool is_crt = false, is_lvds = false, is_tv = false, is_dp = false;
        bool is_edp = false;
        struct drm_mode_config *mode_config = &dev->mode_config;
-       struct drm_connector *connector;
+       struct drm_encoder *encoder;
+       struct intel_encoder *intel_encoder = NULL;
        const intel_limit_t *limit;
        int ret;
        struct fdi_m_n m_n = {0};
@@ -2935,6 +3261,8 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
        int pch_fp_reg = (pipe == 0) ? PCH_FPA0 : PCH_FPB0;
        int pch_dpll_reg = (pipe == 0) ? PCH_DPLL_A : PCH_DPLL_B;
        int fdi_rx_reg = (pipe == 0) ? FDI_RXA_CTL : FDI_RXB_CTL;
+       int fdi_tx_reg = (pipe == 0) ? FDI_TXA_CTL : FDI_TXB_CTL;
+       int trans_dpll_sel = (pipe == 0) ? 0 : 1;
        int lvds_reg = LVDS;
        u32 temp;
        int sdvo_pixel_multiply;
@@ -2942,12 +3270,13 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
 
        drm_vblank_pre_modeset(dev, pipe);
 
-       list_for_each_entry(connector, &mode_config->connector_list, head) {
-               struct intel_encoder *intel_encoder = to_intel_encoder(connector);
+       list_for_each_entry(encoder, &mode_config->encoder_list, head) {
 
-               if (!connector->encoder || connector->encoder->crtc != crtc)
+               if (!encoder || encoder->crtc != crtc)
                        continue;
 
+               intel_encoder = enc_to_intel_encoder(encoder);
+
                switch (intel_encoder->type) {
                case INTEL_OUTPUT_LVDS:
                        is_lvds = true;
@@ -3043,14 +3372,12 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
 
        /* FDI link */
        if (HAS_PCH_SPLIT(dev)) {
-               int lane, link_bw, bpp;
+               int lane = 0, link_bw, bpp;
                /* eDP doesn't require FDI link, so just set DP M/N
                   according to current link config */
                if (is_edp) {
-                       struct drm_connector *edp;
                        target_clock = mode->clock;
-                       edp = intel_pipe_get_connector(crtc);
-                       intel_edp_link_config(to_intel_encoder(edp),
+                       intel_edp_link_config(intel_encoder,
                                        &lane, &link_bw);
                } else {
                        /* DP over FDI requires target mode clock
@@ -3059,7 +3386,6 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                                target_clock = mode->clock;
                        else
                                target_clock = adjusted_mode->clock;
-                       lane = 4;
                        link_bw = 270000;
                }
 
@@ -3111,6 +3437,18 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                        bpp = 24;
                }
 
+               if (!lane) {
+                       /* 
+                        * Account for spread spectrum to avoid
+                        * oversubscribing the link. Max center spread
+                        * is 2.5%; use 5% for safety's sake.
+                        */
+                       u32 bps = target_clock * bpp * 21 / 20;
+                       lane = bps / (link_bw * 8) + 1;
+               }
+
+               intel_crtc->fdi_lanes = lane;
+
                ironlake_compute_m_n(bpp, lane, target_clock, link_bw, &m_n);
        }
 
@@ -3265,11 +3603,6 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                        pipeconf &= ~PIPEACONF_DOUBLE_WIDE;
        }
 
-       dspcntr |= DISPLAY_PLANE_ENABLE;
-       pipeconf |= PIPEACONF_ENABLE;
-       dpll |= DPLL_VCO_ENABLE;
-
-
        /* Disable the panel fitter if it was on our pipe */
        if (!HAS_PCH_SPLIT(dev) && intel_panel_fitter_pipe(dev) == pipe)
                I915_WRITE(PFIT_CONTROL, 0);
@@ -3292,6 +3625,18 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                udelay(150);
        }
 
+       /* enable transcoder DPLL */
+       if (HAS_PCH_CPT(dev)) {
+               temp = I915_READ(PCH_DPLL_SEL);
+               if (trans_dpll_sel == 0)
+                       temp |= (TRANSA_DPLL_ENABLE | TRANSA_DPLLA_SEL);
+               else
+                       temp |= (TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL);
+               I915_WRITE(PCH_DPLL_SEL, temp);
+               I915_READ(PCH_DPLL_SEL);
+               udelay(150);
+       }
+
        /* The LVDS pin pair needs to be on before the DPLLs are enabled.
         * This is an exception to the general rule that mode_set doesn't turn
         * things on.
@@ -3303,7 +3648,18 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                        lvds_reg = PCH_LVDS;
 
                lvds = I915_READ(lvds_reg);
-               lvds |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP | LVDS_PIPEB_SELECT;
+               lvds |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP;
+               if (pipe == 1) {
+                       if (HAS_PCH_CPT(dev))
+                               lvds |= PORT_TRANS_B_SEL_CPT;
+                       else
+                               lvds |= LVDS_PIPEB_SELECT;
+               } else {
+                       if (HAS_PCH_CPT(dev))
+                               lvds &= ~PORT_TRANS_SEL_MASK;
+                       else
+                               lvds &= ~LVDS_PIPEB_SELECT;
+               }
                /* set the corresponsding LVDS_BORDER bit */
                lvds |= dev_priv->lvds_border_bits;
                /* Set the B0-B3 data pairs corresponding to whether we're going to
@@ -3337,6 +3693,20 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
        }
        if (is_dp)
                intel_dp_set_m_n(crtc, mode, adjusted_mode);
+       else if (HAS_PCH_SPLIT(dev)) {
+               /* For non-DP output, clear any trans DP clock recovery setting.*/
+               if (pipe == 0) {
+                       I915_WRITE(TRANSA_DATA_M1, 0);
+                       I915_WRITE(TRANSA_DATA_N1, 0);
+                       I915_WRITE(TRANSA_DP_LINK_M1, 0);
+                       I915_WRITE(TRANSA_DP_LINK_N1, 0);
+               } else {
+                       I915_WRITE(TRANSB_DATA_M1, 0);
+                       I915_WRITE(TRANSB_DATA_N1, 0);
+                       I915_WRITE(TRANSB_DP_LINK_M1, 0);
+                       I915_WRITE(TRANSB_DP_LINK_N1, 0);
+               }
+       }
 
        if (!is_edp) {
                I915_WRITE(fp_reg, fp);
@@ -3411,6 +3781,18 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                        /* enable FDI RX PLL too */
                        temp = I915_READ(fdi_rx_reg);
                        I915_WRITE(fdi_rx_reg, temp | FDI_RX_PLL_ENABLE);
+                       I915_READ(fdi_rx_reg);
+                       udelay(200);
+
+                       /* enable FDI TX PLL too */
+                       temp = I915_READ(fdi_tx_reg);
+                       I915_WRITE(fdi_tx_reg, temp | FDI_TX_PLL_ENABLE);
+                       I915_READ(fdi_tx_reg);
+
+                       /* enable FDI RX PCDCLK */
+                       temp = I915_READ(fdi_rx_reg);
+                       I915_WRITE(fdi_rx_reg, temp | FDI_SEL_PCDCLK);
+                       I915_READ(fdi_rx_reg);
                        udelay(200);
                }
        }
@@ -3671,6 +4053,7 @@ static struct drm_display_mode load_detect_mode = {
 };
 
 struct drm_crtc *intel_get_load_detect_pipe(struct intel_encoder *intel_encoder,
+                                           struct drm_connector *connector,
                                            struct drm_display_mode *mode,
                                            int *dpms_mode)
 {
@@ -3729,7 +4112,7 @@ struct drm_crtc *intel_get_load_detect_pipe(struct intel_encoder *intel_encoder,
        }
 
        encoder->crtc = crtc;
-       intel_encoder->base.encoder = encoder;
+       connector->encoder = encoder;
        intel_encoder->load_detect_temp = true;
 
        intel_crtc = to_intel_crtc(crtc);
@@ -3755,7 +4138,8 @@ struct drm_crtc *intel_get_load_detect_pipe(struct intel_encoder *intel_encoder,
        return crtc;
 }
 
-void intel_release_load_detect_pipe(struct intel_encoder *intel_encoder, int dpms_mode)
+void intel_release_load_detect_pipe(struct intel_encoder *intel_encoder,
+                                   struct drm_connector *connector, int dpms_mode)
 {
        struct drm_encoder *encoder = &intel_encoder->enc;
        struct drm_device *dev = encoder->dev;
@@ -3765,7 +4149,7 @@ void intel_release_load_detect_pipe(struct intel_encoder *intel_encoder, int dpm
 
        if (intel_encoder->load_detect_temp) {
                encoder->crtc = NULL;
-               intel_encoder->base.encoder = NULL;
+               connector->encoder = NULL;
                intel_encoder->load_detect_temp = false;
                crtc->enabled = drm_helper_crtc_in_use(crtc);
                drm_helper_disable_unused_functions(dev);
@@ -4392,14 +4776,14 @@ struct drm_crtc *intel_get_crtc_from_pipe(struct drm_device *dev, int pipe)
        return crtc;
 }
 
-static int intel_connector_clones(struct drm_device *dev, int type_mask)
+static int intel_encoder_clones(struct drm_device *dev, int type_mask)
 {
        int index_mask = 0;
-       struct drm_connector *connector;
+       struct drm_encoder *encoder;
        int entry = 0;
 
-        list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
-               struct intel_encoder *intel_encoder = to_intel_encoder(connector);
+        list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+               struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
                if (type_mask & intel_encoder->clone_mask)
                        index_mask |= (1 << entry);
                entry++;
@@ -4411,7 +4795,7 @@ static int intel_connector_clones(struct drm_device *dev, int type_mask)
 static void intel_setup_outputs(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct drm_connector *connector;
+       struct drm_encoder *encoder;
 
        intel_crt_init(dev);
 
@@ -4426,9 +4810,8 @@ static void intel_setup_outputs(struct drm_device *dev)
                        intel_dp_init(dev, DP_A);
 
                if (I915_READ(HDMIB) & PORT_DETECTED) {
-                       /* check SDVOB */
-                       /* found = intel_sdvo_init(dev, HDMIB); */
-                       found = 0;
+                       /* PCH SDVOB multiplex with HDMIB */
+                       found = intel_sdvo_init(dev, PCH_SDVOB);
                        if (!found)
                                intel_hdmi_init(dev, HDMIB);
                        if (!found && (I915_READ(PCH_DP_B) & DP_DETECTED))
@@ -4494,12 +4877,11 @@ static void intel_setup_outputs(struct drm_device *dev)
        if (SUPPORTS_TV(dev))
                intel_tv_init(dev);
 
-       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
-               struct intel_encoder *intel_encoder = to_intel_encoder(connector);
-               struct drm_encoder *encoder = &intel_encoder->enc;
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+               struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
 
                encoder->possible_crtcs = intel_encoder->crtc_mask;
-               encoder->possible_clones = intel_connector_clones(dev,
+               encoder->possible_clones = intel_encoder_clones(dev,
                                                intel_encoder->clone_mask);
        }
 }
@@ -4732,6 +5114,25 @@ void intel_init_clock_gating(struct drm_device *dev)
                }
 
                I915_WRITE(PCH_DSPCLK_GATE_D, dspclk_gate);
+
+               /*
+                * According to the spec the following bits should be set in
+                * order to enable memory self-refresh
+                * The bit 22/21 of 0x42004
+                * The bit 5 of 0x42020
+                * The bit 15 of 0x45000
+                */
+               if (IS_IRONLAKE(dev)) {
+                       I915_WRITE(ILK_DISPLAY_CHICKEN2,
+                                       (I915_READ(ILK_DISPLAY_CHICKEN2) |
+                                       ILK_DPARB_GATE | ILK_VSDPFD_FULL));
+                       I915_WRITE(ILK_DSPCLK_GATE,
+                                       (I915_READ(ILK_DSPCLK_GATE) |
+                                               ILK_DPARB_CLK_GATE));
+                       I915_WRITE(DISP_ARB_CTL,
+                                       (I915_READ(DISP_ARB_CTL) |
+                                               DISP_FBC_WM_DIS));
+               }
                return;
        } else if (IS_G4X(dev)) {
                uint32_t dspclk_gate;
@@ -4847,9 +5248,31 @@ static void intel_init_display(struct drm_device *dev)
                        i830_get_display_clock_speed;
 
        /* For FIFO watermark updates */
-       if (HAS_PCH_SPLIT(dev))
-               dev_priv->display.update_wm = NULL;
-       else if (IS_G4X(dev))
+       if (HAS_PCH_SPLIT(dev)) {
+               if (IS_IRONLAKE(dev)) {
+                       if (I915_READ(MLTR_ILK) & ILK_SRLT_MASK)
+                               dev_priv->display.update_wm = ironlake_update_wm;
+                       else {
+                               DRM_DEBUG_KMS("Failed to get proper latency. "
+                                             "Disable CxSR\n");
+                               dev_priv->display.update_wm = NULL;
+                       }
+               } else
+                       dev_priv->display.update_wm = NULL;
+       } else if (IS_PINEVIEW(dev)) {
+               if (!intel_get_cxsr_latency(IS_PINEVIEW_G(dev),
+                                           dev_priv->fsb_freq,
+                                           dev_priv->mem_freq)) {
+                       DRM_INFO("failed to find known CxSR latency "
+                                "(found fsb freq %d, mem freq %d), "
+                                "disabling CxSR\n",
+                                dev_priv->fsb_freq, dev_priv->mem_freq);
+                       /* Disable CxSR and never update its watermark again */
+                       pineview_disable_cxsr(dev);
+                       dev_priv->display.update_wm = NULL;
+               } else
+                       dev_priv->display.update_wm = pineview_update_wm;
+       } else if (IS_G4X(dev))
                dev_priv->display.update_wm = g4x_update_wm;
        else if (IS_I965G(dev))
                dev_priv->display.update_wm = i965_update_wm;
@@ -4922,13 +5345,6 @@ void intel_modeset_init(struct drm_device *dev)
                    (unsigned long)dev);
 
        intel_setup_overlay(dev);
-
-       if (IS_PINEVIEW(dev) && !intel_get_cxsr_latency(IS_PINEVIEW_G(dev),
-                                                       dev_priv->fsb_freq,
-                                                       dev_priv->mem_freq))
-               DRM_INFO("failed to find known CxSR latency "
-                        "(found fsb freq %d, mem freq %d), disabling CxSR\n",
-                        dev_priv->fsb_freq, dev_priv->mem_freq);
 }
 
 void intel_modeset_cleanup(struct drm_device *dev)
@@ -4973,14 +5389,29 @@ void intel_modeset_cleanup(struct drm_device *dev)
 }
 
 
-/* current intel driver doesn't take advantage of encoders
-   always give back the encoder for the connector
-*/
-struct drm_encoder *intel_best_encoder(struct drm_connector *connector)
+/*
+ * Return which encoder is currently attached for connector.
+ */
+struct drm_encoder *intel_attached_encoder (struct drm_connector *connector)
 {
-       struct intel_encoder *intel_encoder = to_intel_encoder(connector);
+       struct drm_mode_object *obj;
+       struct drm_encoder *encoder;
+       int i;
+
+       for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
+               if (connector->encoder_ids[i] == 0)
+                       break;
 
-       return &intel_encoder->enc;
+               obj = drm_mode_object_find(connector->dev,
+                                           connector->encoder_ids[i],
+                                           DRM_MODE_OBJECT_ENCODER);
+               if (!obj)
+                       continue;
+
+               encoder = obj_to_encoder(obj);
+               return encoder;
+       }
+       return NULL;
 }
 
 /*
index 77e40cf..f6299bb 100644 (file)
@@ -48,8 +48,6 @@ struct intel_dp_priv {
        uint32_t output_reg;
        uint32_t DP;
        uint8_t  link_configuration[DP_LINK_CONFIGURATION_SIZE];
-       uint32_t save_DP;
-       uint8_t  save_link_configuration[DP_LINK_CONFIGURATION_SIZE];
        bool has_audio;
        int dpms_mode;
        uint8_t link_bw;
@@ -141,7 +139,8 @@ static int
 intel_dp_mode_valid(struct drm_connector *connector,
                    struct drm_display_mode *mode)
 {
-       struct intel_encoder *intel_encoder = to_intel_encoder(connector);
+       struct drm_encoder *encoder = intel_attached_encoder(connector);
+       struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
        int max_link_clock = intel_dp_link_clock(intel_dp_max_link_bw(intel_encoder));
        int max_lanes = intel_dp_max_lane_count(intel_encoder);
 
@@ -215,7 +214,7 @@ intel_dp_aux_ch(struct intel_encoder *intel_encoder,
 {
        struct intel_dp_priv *dp_priv = intel_encoder->dev_priv;
        uint32_t output_reg = dp_priv->output_reg;
-       struct drm_device *dev = intel_encoder->base.dev;
+       struct drm_device *dev = intel_encoder->enc.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        uint32_t ch_ctl = output_reg + 0x10;
        uint32_t ch_data = ch_ctl + 4;
@@ -224,19 +223,27 @@ intel_dp_aux_ch(struct intel_encoder *intel_encoder,
        uint32_t ctl;
        uint32_t status;
        uint32_t aux_clock_divider;
-       int try;
+       int try, precharge;
 
        /* The clock divider is based off the hrawclk,
         * and would like to run at 2MHz. So, take the
         * hrawclk value and divide by 2 and use that
         */
-       if (IS_eDP(intel_encoder))
-               aux_clock_divider = 225; /* eDP input clock at 450Mhz */
-       else if (HAS_PCH_SPLIT(dev))
+       if (IS_eDP(intel_encoder)) {
+               if (IS_GEN6(dev))
+                       aux_clock_divider = 200; /* SNB eDP input clock at 400Mhz */
+               else
+                       aux_clock_divider = 225; /* eDP input clock at 450Mhz */
+       } else if (HAS_PCH_SPLIT(dev))
                aux_clock_divider = 62; /* IRL input clock fixed at 125Mhz */
        else
                aux_clock_divider = intel_hrawclk(dev) / 2;
 
+       if (IS_GEN6(dev))
+               precharge = 3;
+       else
+               precharge = 5;
+
        /* Must try at least 3 times according to DP spec */
        for (try = 0; try < 5; try++) {
                /* Load the send data into the aux channel data registers */
@@ -249,7 +256,7 @@ intel_dp_aux_ch(struct intel_encoder *intel_encoder,
                ctl = (DP_AUX_CH_CTL_SEND_BUSY |
                       DP_AUX_CH_CTL_TIME_OUT_400us |
                       (send_bytes << DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT) |
-                      (5 << DP_AUX_CH_CTL_PRECHARGE_2US_SHIFT) |
+                      (precharge << DP_AUX_CH_CTL_PRECHARGE_2US_SHIFT) |
                       (aux_clock_divider << DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT) |
                       DP_AUX_CH_CTL_DONE |
                       DP_AUX_CH_CTL_TIME_OUT_ERROR |
@@ -465,7 +472,8 @@ intel_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode,
 }
 
 static int
-intel_dp_i2c_init(struct intel_encoder *intel_encoder, const char *name)
+intel_dp_i2c_init(struct intel_encoder *intel_encoder,
+                 struct intel_connector *intel_connector, const char *name)
 {
        struct intel_dp_priv   *dp_priv = intel_encoder->dev_priv;
 
@@ -480,7 +488,7 @@ intel_dp_i2c_init(struct intel_encoder *intel_encoder, const char *name)
        strncpy (dp_priv->adapter.name, name, sizeof(dp_priv->adapter.name) - 1);
        dp_priv->adapter.name[sizeof(dp_priv->adapter.name) - 1] = '\0';
        dp_priv->adapter.algo_data = &dp_priv->algo;
-       dp_priv->adapter.dev.parent = &intel_encoder->base.kdev;
+       dp_priv->adapter.dev.parent = &intel_connector->base.kdev;
        
        return i2c_dp_aux_add_bus(&dp_priv->adapter);
 }
@@ -555,7 +563,7 @@ intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
 {
        struct drm_device *dev = crtc->dev;
        struct drm_mode_config *mode_config = &dev->mode_config;
-       struct drm_connector *connector;
+       struct drm_encoder *encoder;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        int lane_count = 4;
@@ -564,13 +572,16 @@ intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
        /*
         * Find the lane count in the intel_encoder private
         */
-       list_for_each_entry(connector, &mode_config->connector_list, head) {
-               struct intel_encoder *intel_encoder = to_intel_encoder(connector);
-               struct intel_dp_priv *dp_priv = intel_encoder->dev_priv;
+       list_for_each_entry(encoder, &mode_config->encoder_list, head) {
+               struct intel_encoder *intel_encoder;
+               struct intel_dp_priv *dp_priv;
 
-               if (!connector->encoder || connector->encoder->crtc != crtc)
+               if (!encoder || encoder->crtc != crtc)
                        continue;
 
+               intel_encoder = enc_to_intel_encoder(encoder);
+               dp_priv = intel_encoder->dev_priv;
+
                if (intel_encoder->type == INTEL_OUTPUT_DISPLAYPORT) {
                        lane_count = dp_priv->lane_count;
                        break;
@@ -626,16 +637,24 @@ static void
 intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
                  struct drm_display_mode *adjusted_mode)
 {
+       struct drm_device *dev = encoder->dev;
        struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
        struct intel_dp_priv *dp_priv = intel_encoder->dev_priv;
        struct drm_crtc *crtc = intel_encoder->enc.crtc;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 
-       dp_priv->DP = (DP_LINK_TRAIN_OFF |
-                       DP_VOLTAGE_0_4 |
-                       DP_PRE_EMPHASIS_0 |
-                       DP_SYNC_VS_HIGH |
-                       DP_SYNC_HS_HIGH);
+       dp_priv->DP = (DP_VOLTAGE_0_4 |
+                      DP_PRE_EMPHASIS_0);
+
+       if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
+               dp_priv->DP |= DP_SYNC_HS_HIGH;
+       if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
+               dp_priv->DP |= DP_SYNC_VS_HIGH;
+
+       if (HAS_PCH_CPT(dev) && !IS_eDP(intel_encoder))
+               dp_priv->DP |= DP_LINK_TRAIN_OFF_CPT;
+       else
+               dp_priv->DP |= DP_LINK_TRAIN_OFF;
 
        switch (dp_priv->lane_count) {
        case 1:
@@ -664,7 +683,8 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
                dp_priv->DP |= DP_ENHANCED_FRAMING;
        }
 
-       if (intel_crtc->pipe == 1)
+       /* CPT DP's pipe select is decided in TRANS_DP_CTL */
+       if (intel_crtc->pipe == 1 && !HAS_PCH_CPT(dev))
                dp_priv->DP |= DP_PIPEB_SELECT;
 
        if (IS_eDP(intel_encoder)) {
@@ -704,7 +724,7 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode)
 {
        struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
        struct intel_dp_priv *dp_priv = intel_encoder->dev_priv;
-       struct drm_device *dev = intel_encoder->base.dev;
+       struct drm_device *dev = encoder->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        uint32_t dp_reg = I915_READ(dp_priv->output_reg);
 
@@ -749,20 +769,6 @@ intel_dp_link_status(uint8_t link_status[DP_LINK_STATUS_SIZE],
        return link_status[r - DP_LANE0_1_STATUS];
 }
 
-static void
-intel_dp_save(struct drm_connector *connector)
-{
-       struct intel_encoder *intel_encoder = to_intel_encoder(connector);
-       struct drm_device *dev = intel_encoder->base.dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_dp_priv *dp_priv = intel_encoder->dev_priv;
-
-       dp_priv->save_DP = I915_READ(dp_priv->output_reg);
-       intel_dp_aux_native_read(intel_encoder, DP_LINK_BW_SET,
-                                dp_priv->save_link_configuration,
-                                sizeof (dp_priv->save_link_configuration));
-}
-
 static uint8_t
 intel_get_adjust_request_voltage(uint8_t link_status[DP_LINK_STATUS_SIZE],
                                 int lane)
@@ -892,6 +898,25 @@ intel_dp_signal_levels(uint8_t train_set, int lane_count)
        return signal_levels;
 }
 
+/* Gen6's DP voltage swing and pre-emphasis control */
+static uint32_t
+intel_gen6_edp_signal_levels(uint8_t train_set)
+{
+       switch (train_set & (DP_TRAIN_VOLTAGE_SWING_MASK|DP_TRAIN_PRE_EMPHASIS_MASK)) {
+       case DP_TRAIN_VOLTAGE_SWING_400 | DP_TRAIN_PRE_EMPHASIS_0:
+               return EDP_LINK_TRAIN_400MV_0DB_SNB_B;
+       case DP_TRAIN_VOLTAGE_SWING_400 | DP_TRAIN_PRE_EMPHASIS_6:
+               return EDP_LINK_TRAIN_400MV_6DB_SNB_B;
+       case DP_TRAIN_VOLTAGE_SWING_600 | DP_TRAIN_PRE_EMPHASIS_3_5:
+               return EDP_LINK_TRAIN_600MV_3_5DB_SNB_B;
+       case DP_TRAIN_VOLTAGE_SWING_800 | DP_TRAIN_PRE_EMPHASIS_0:
+               return EDP_LINK_TRAIN_800MV_0DB_SNB_B;
+       default:
+               DRM_DEBUG_KMS("Unsupported voltage swing/pre-emphasis level\n");
+               return EDP_LINK_TRAIN_400MV_0DB_SNB_B;
+       }
+}
+
 static uint8_t
 intel_get_lane_status(uint8_t link_status[DP_LINK_STATUS_SIZE],
                      int lane)
@@ -948,7 +973,7 @@ intel_dp_set_link_train(struct intel_encoder *intel_encoder,
                        uint8_t train_set[4],
                        bool first)
 {
-       struct drm_device *dev = intel_encoder->base.dev;
+       struct drm_device *dev = intel_encoder->enc.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_dp_priv *dp_priv = intel_encoder->dev_priv;
        int ret;
@@ -974,7 +999,7 @@ static void
 intel_dp_link_train(struct intel_encoder *intel_encoder, uint32_t DP,
                    uint8_t link_configuration[DP_LINK_CONFIGURATION_SIZE])
 {
-       struct drm_device *dev = intel_encoder->base.dev;
+       struct drm_device *dev = intel_encoder->enc.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_dp_priv *dp_priv = intel_encoder->dev_priv;
        uint8_t train_set[4];
@@ -985,23 +1010,38 @@ intel_dp_link_train(struct intel_encoder *intel_encoder, uint32_t DP,
        bool channel_eq = false;
        bool first = true;
        int tries;
+       u32 reg;
 
        /* Write the link configuration data */
-       intel_dp_aux_native_write(intel_encoder, 0x100,
+       intel_dp_aux_native_write(intel_encoder, DP_LINK_BW_SET,
                                  link_configuration, DP_LINK_CONFIGURATION_SIZE);
 
        DP |= DP_PORT_EN;
-       DP &= ~DP_LINK_TRAIN_MASK;
+       if (HAS_PCH_CPT(dev) && !IS_eDP(intel_encoder))
+               DP &= ~DP_LINK_TRAIN_MASK_CPT;
+       else
+               DP &= ~DP_LINK_TRAIN_MASK;
        memset(train_set, 0, 4);
        voltage = 0xff;
        tries = 0;
        clock_recovery = false;
        for (;;) {
                /* Use train_set[0] to set the voltage and pre emphasis values */
-               uint32_t    signal_levels = intel_dp_signal_levels(train_set[0], dp_priv->lane_count);
-               DP = (DP & ~(DP_VOLTAGE_MASK|DP_PRE_EMPHASIS_MASK)) | signal_levels;
+               uint32_t    signal_levels;
+               if (IS_GEN6(dev) && IS_eDP(intel_encoder)) {
+                       signal_levels = intel_gen6_edp_signal_levels(train_set[0]);
+                       DP = (DP & ~EDP_LINK_TRAIN_VOL_EMP_MASK_SNB) | signal_levels;
+               } else {
+                       signal_levels = intel_dp_signal_levels(train_set[0], dp_priv->lane_count);
+                       DP = (DP & ~(DP_VOLTAGE_MASK|DP_PRE_EMPHASIS_MASK)) | signal_levels;
+               }
 
-               if (!intel_dp_set_link_train(intel_encoder, DP | DP_LINK_TRAIN_PAT_1,
+               if (HAS_PCH_CPT(dev) && !IS_eDP(intel_encoder))
+                       reg = DP | DP_LINK_TRAIN_PAT_1_CPT;
+               else
+                       reg = DP | DP_LINK_TRAIN_PAT_1;
+
+               if (!intel_dp_set_link_train(intel_encoder, reg,
                                             DP_TRAINING_PATTERN_1, train_set, first))
                        break;
                first = false;
@@ -1041,11 +1081,23 @@ intel_dp_link_train(struct intel_encoder *intel_encoder, uint32_t DP,
        channel_eq = false;
        for (;;) {
                /* Use train_set[0] to set the voltage and pre emphasis values */
-               uint32_t    signal_levels = intel_dp_signal_levels(train_set[0], dp_priv->lane_count);
-               DP = (DP & ~(DP_VOLTAGE_MASK|DP_PRE_EMPHASIS_MASK)) | signal_levels;
+               uint32_t    signal_levels;
+
+               if (IS_GEN6(dev) && IS_eDP(intel_encoder)) {
+                       signal_levels = intel_gen6_edp_signal_levels(train_set[0]);
+                       DP = (DP & ~EDP_LINK_TRAIN_VOL_EMP_MASK_SNB) | signal_levels;
+               } else {
+                       signal_levels = intel_dp_signal_levels(train_set[0], dp_priv->lane_count);
+                       DP = (DP & ~(DP_VOLTAGE_MASK|DP_PRE_EMPHASIS_MASK)) | signal_levels;
+               }
+
+               if (HAS_PCH_CPT(dev) && !IS_eDP(intel_encoder))
+                       reg = DP | DP_LINK_TRAIN_PAT_2_CPT;
+               else
+                       reg = DP | DP_LINK_TRAIN_PAT_2;
 
                /* channel eq pattern */
-               if (!intel_dp_set_link_train(intel_encoder, DP | DP_LINK_TRAIN_PAT_2,
+               if (!intel_dp_set_link_train(intel_encoder, reg,
                                             DP_TRAINING_PATTERN_2, train_set,
                                             false))
                        break;
@@ -1068,7 +1120,12 @@ intel_dp_link_train(struct intel_encoder *intel_encoder, uint32_t DP,
                ++tries;
        }
 
-       I915_WRITE(dp_priv->output_reg, DP | DP_LINK_TRAIN_OFF);
+       if (HAS_PCH_CPT(dev) && !IS_eDP(intel_encoder))
+               reg = DP | DP_LINK_TRAIN_OFF_CPT;
+       else
+               reg = DP | DP_LINK_TRAIN_OFF;
+
+       I915_WRITE(dp_priv->output_reg, reg);
        POSTING_READ(dp_priv->output_reg);
        intel_dp_aux_native_write_1(intel_encoder,
                                    DP_TRAINING_PATTERN_SET, DP_TRAINING_PATTERN_DISABLE);
@@ -1077,7 +1134,7 @@ intel_dp_link_train(struct intel_encoder *intel_encoder, uint32_t DP,
 static void
 intel_dp_link_down(struct intel_encoder *intel_encoder, uint32_t DP)
 {
-       struct drm_device *dev = intel_encoder->base.dev;
+       struct drm_device *dev = intel_encoder->enc.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_dp_priv *dp_priv = intel_encoder->dev_priv;
 
@@ -1090,9 +1147,15 @@ intel_dp_link_down(struct intel_encoder *intel_encoder, uint32_t DP)
                udelay(100);
        }
 
-       DP &= ~DP_LINK_TRAIN_MASK;
-       I915_WRITE(dp_priv->output_reg, DP | DP_LINK_TRAIN_PAT_IDLE);
-       POSTING_READ(dp_priv->output_reg);
+       if (HAS_PCH_CPT(dev) && !IS_eDP(intel_encoder)) {
+               DP &= ~DP_LINK_TRAIN_MASK_CPT;
+               I915_WRITE(dp_priv->output_reg, DP | DP_LINK_TRAIN_PAT_IDLE_CPT);
+               POSTING_READ(dp_priv->output_reg);
+       } else {
+               DP &= ~DP_LINK_TRAIN_MASK;
+               I915_WRITE(dp_priv->output_reg, DP | DP_LINK_TRAIN_PAT_IDLE);
+               POSTING_READ(dp_priv->output_reg);
+       }
 
        udelay(17000);
 
@@ -1102,18 +1165,6 @@ intel_dp_link_down(struct intel_encoder *intel_encoder, uint32_t DP)
        POSTING_READ(dp_priv->output_reg);
 }
 
-static void
-intel_dp_restore(struct drm_connector *connector)
-{
-       struct intel_encoder *intel_encoder = to_intel_encoder(connector);
-       struct intel_dp_priv *dp_priv = intel_encoder->dev_priv;
-
-       if (dp_priv->save_DP & DP_PORT_EN)
-               intel_dp_link_train(intel_encoder, dp_priv->save_DP, dp_priv->save_link_configuration);
-       else
-               intel_dp_link_down(intel_encoder,  dp_priv->save_DP);
-}
-
 /*
  * According to DP spec
  * 5.1.2:
@@ -1144,7 +1195,8 @@ intel_dp_check_link_status(struct intel_encoder *intel_encoder)
 static enum drm_connector_status
 ironlake_dp_detect(struct drm_connector *connector)
 {
-       struct intel_encoder *intel_encoder = to_intel_encoder(connector);
+       struct drm_encoder *encoder = intel_attached_encoder(connector);
+       struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
        struct intel_dp_priv *dp_priv = intel_encoder->dev_priv;
        enum drm_connector_status status;
 
@@ -1168,8 +1220,9 @@ ironlake_dp_detect(struct drm_connector *connector)
 static enum drm_connector_status
 intel_dp_detect(struct drm_connector *connector)
 {
-       struct intel_encoder *intel_encoder = to_intel_encoder(connector);
-       struct drm_device *dev = intel_encoder->base.dev;
+       struct drm_encoder *encoder = intel_attached_encoder(connector);
+       struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
+       struct drm_device *dev = intel_encoder->enc.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_dp_priv *dp_priv = intel_encoder->dev_priv;
        uint32_t temp, bit;
@@ -1180,16 +1233,6 @@ intel_dp_detect(struct drm_connector *connector)
        if (HAS_PCH_SPLIT(dev))
                return ironlake_dp_detect(connector);
 
-       temp = I915_READ(PORT_HOTPLUG_EN);
-
-       I915_WRITE(PORT_HOTPLUG_EN,
-              temp |
-              DPB_HOTPLUG_INT_EN |
-              DPC_HOTPLUG_INT_EN |
-              DPD_HOTPLUG_INT_EN);
-
-       POSTING_READ(PORT_HOTPLUG_EN);
-
        switch (dp_priv->output_reg) {
        case DP_B:
                bit = DPB_HOTPLUG_INT_STATUS;
@@ -1222,15 +1265,16 @@ intel_dp_detect(struct drm_connector *connector)
 
 static int intel_dp_get_modes(struct drm_connector *connector)
 {
-       struct intel_encoder *intel_encoder = to_intel_encoder(connector);
-       struct drm_device *dev = intel_encoder->base.dev;
+       struct drm_encoder *encoder = intel_attached_encoder(connector);
+       struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
+       struct drm_device *dev = intel_encoder->enc.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        int ret;
 
        /* We should parse the EDID data and find out if it has an audio sink
         */
 
-       ret = intel_ddc_get_modes(intel_encoder);
+       ret = intel_ddc_get_modes(connector, intel_encoder->ddc_bus);
        if (ret)
                return ret;
 
@@ -1249,13 +1293,9 @@ static int intel_dp_get_modes(struct drm_connector *connector)
 static void
 intel_dp_destroy (struct drm_connector *connector)
 {
-       struct intel_encoder *intel_encoder = to_intel_encoder(connector);
-
-       if (intel_encoder->i2c_bus)
-               intel_i2c_destroy(intel_encoder->i2c_bus);
        drm_sysfs_connector_remove(connector);
        drm_connector_cleanup(connector);
-       kfree(intel_encoder);
+       kfree(connector);
 }
 
 static const struct drm_encoder_helper_funcs intel_dp_helper_funcs = {
@@ -1268,8 +1308,6 @@ static const struct drm_encoder_helper_funcs intel_dp_helper_funcs = {
 
 static const struct drm_connector_funcs intel_dp_connector_funcs = {
        .dpms = drm_helper_connector_dpms,
-       .save = intel_dp_save,
-       .restore = intel_dp_restore,
        .detect = intel_dp_detect,
        .fill_modes = drm_helper_probe_single_connector_modes,
        .destroy = intel_dp_destroy,
@@ -1278,12 +1316,17 @@ static const struct drm_connector_funcs intel_dp_connector_funcs = {
 static const struct drm_connector_helper_funcs intel_dp_connector_helper_funcs = {
        .get_modes = intel_dp_get_modes,
        .mode_valid = intel_dp_mode_valid,
-       .best_encoder = intel_best_encoder,
+       .best_encoder = intel_attached_encoder,
 };
 
 static void intel_dp_enc_destroy(struct drm_encoder *encoder)
 {
+       struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
+
+       if (intel_encoder->i2c_bus)
+               intel_i2c_destroy(intel_encoder->i2c_bus);
        drm_encoder_cleanup(encoder);
+       kfree(intel_encoder);
 }
 
 static const struct drm_encoder_funcs intel_dp_enc_funcs = {
@@ -1299,12 +1342,35 @@ intel_dp_hot_plug(struct intel_encoder *intel_encoder)
                intel_dp_check_link_status(intel_encoder);
 }
 
+/* Return which DP Port should be selected for Transcoder DP control */
+int
+intel_trans_dp_port_sel (struct drm_crtc *crtc)
+{
+       struct drm_device *dev = crtc->dev;
+       struct drm_mode_config *mode_config = &dev->mode_config;
+       struct drm_encoder *encoder;
+       struct intel_encoder *intel_encoder = NULL;
+
+       list_for_each_entry(encoder, &mode_config->encoder_list, head) {
+               if (!encoder || encoder->crtc != crtc)
+                       continue;
+
+               intel_encoder = enc_to_intel_encoder(encoder);
+               if (intel_encoder->type == INTEL_OUTPUT_DISPLAYPORT) {
+                       struct intel_dp_priv *dp_priv = intel_encoder->dev_priv;
+                       return dp_priv->output_reg;
+               }
+       }
+       return -1;
+}
+
 void
 intel_dp_init(struct drm_device *dev, int output_reg)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_connector *connector;
        struct intel_encoder *intel_encoder;
+       struct intel_connector *intel_connector;
        struct intel_dp_priv *dp_priv;
        const char *name = NULL;
 
@@ -1313,9 +1379,15 @@ intel_dp_init(struct drm_device *dev, int output_reg)
        if (!intel_encoder)
                return;
 
+       intel_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL);
+       if (!intel_connector) {
+               kfree(intel_encoder);
+               return;
+       }
+
        dp_priv = (struct intel_dp_priv *)(intel_encoder + 1);
 
-       connector = &intel_encoder->base;
+       connector = &intel_connector->base;
        drm_connector_init(dev, connector, &intel_dp_connector_funcs,
                           DRM_MODE_CONNECTOR_DisplayPort);
        drm_connector_helper_add(connector, &intel_dp_connector_helper_funcs);
@@ -1349,7 +1421,7 @@ intel_dp_init(struct drm_device *dev, int output_reg)
                         DRM_MODE_ENCODER_TMDS);
        drm_encoder_helper_add(&intel_encoder->enc, &intel_dp_helper_funcs);
 
-       drm_mode_connector_attach_encoder(&intel_encoder->base,
+       drm_mode_connector_attach_encoder(&intel_connector->base,
                                          &intel_encoder->enc);
        drm_sysfs_connector_add(connector);
 
@@ -1378,7 +1450,7 @@ intel_dp_init(struct drm_device *dev, int output_reg)
                        break;
        }
 
-       intel_dp_i2c_init(intel_encoder, name);
+       intel_dp_i2c_init(intel_encoder, intel_connector, name);
 
        intel_encoder->ddc_bus = &dp_priv->adapter;
        intel_encoder->hot_plug = intel_dp_hot_plug;
index e302537..1ee4717 100644 (file)
@@ -96,8 +96,6 @@ struct intel_framebuffer {
 
 
 struct intel_encoder {
-       struct drm_connector base;
-
        struct drm_encoder enc;
        int type;
        struct i2c_adapter *i2c_bus;
@@ -110,6 +108,11 @@ struct intel_encoder {
        int clone_mask;
 };
 
+struct intel_connector {
+       struct drm_connector base;
+       void *dev_priv;
+};
+
 struct intel_crtc;
 struct intel_overlay {
        struct drm_device *dev;
@@ -149,17 +152,18 @@ struct intel_crtc {
        bool lowfreq_avail;
        struct intel_overlay *overlay;
        struct intel_unpin_work *unpin_work;
+       int fdi_lanes;
 };
 
 #define to_intel_crtc(x) container_of(x, struct intel_crtc, base)
-#define to_intel_encoder(x) container_of(x, struct intel_encoder, base)
+#define to_intel_connector(x) container_of(x, struct intel_connector, base)
 #define enc_to_intel_encoder(x) container_of(x, struct intel_encoder, enc)
 #define to_intel_framebuffer(x) container_of(x, struct intel_framebuffer, base)
 
 struct i2c_adapter *intel_i2c_create(struct drm_device *dev, const u32 reg,
                                     const char *name);
 void intel_i2c_destroy(struct i2c_adapter *adapter);
-int intel_ddc_get_modes(struct intel_encoder *intel_encoder);
+int intel_ddc_get_modes(struct drm_connector *c, struct i2c_adapter *adapter);
 extern bool intel_ddc_probe(struct intel_encoder *intel_encoder);
 void intel_i2c_quirk_set(struct drm_device *dev, bool enable);
 void intel_i2c_reset_gmbus(struct drm_device *dev);
@@ -183,7 +187,7 @@ extern void intel_crtc_load_lut(struct drm_crtc *crtc);
 extern void intel_encoder_prepare (struct drm_encoder *encoder);
 extern void intel_encoder_commit (struct drm_encoder *encoder);
 
-extern struct drm_encoder *intel_best_encoder(struct drm_connector *connector);
+extern struct drm_encoder *intel_attached_encoder(struct drm_connector *connector);
 
 extern struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev,
                                                    struct drm_crtc *crtc);
@@ -192,9 +196,11 @@ int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data,
 extern void intel_wait_for_vblank(struct drm_device *dev);
 extern struct drm_crtc *intel_get_crtc_from_pipe(struct drm_device *dev, int pipe);
 extern struct drm_crtc *intel_get_load_detect_pipe(struct intel_encoder *intel_encoder,
+                                                  struct drm_connector *connector,
                                                   struct drm_display_mode *mode,
                                                   int *dpms_mode);
 extern void intel_release_load_detect_pipe(struct intel_encoder *intel_encoder,
+                                          struct drm_connector *connector,
                                           int dpms_mode);
 
 extern struct drm_connector* intel_sdvo_find(struct drm_device *dev, int sdvoB);
index ebf213c..227feca 100644 (file)
@@ -96,39 +96,11 @@ static void intel_dvo_dpms(struct drm_encoder *encoder, int mode)
        }
 }
 
-static void intel_dvo_save(struct drm_connector *connector)
-{
-       struct drm_i915_private *dev_priv = connector->dev->dev_private;
-       struct intel_encoder *intel_encoder = to_intel_encoder(connector);
-       struct intel_dvo_device *dvo = intel_encoder->dev_priv;
-
-       /* Each output should probably just save the registers it touches,
-        * but for now, use more overkill.
-        */
-       dev_priv->saveDVOA = I915_READ(DVOA);
-       dev_priv->saveDVOB = I915_READ(DVOB);
-       dev_priv->saveDVOC = I915_READ(DVOC);
-
-       dvo->dev_ops->save(dvo);
-}
-
-static void intel_dvo_restore(struct drm_connector *connector)
-{
-       struct drm_i915_private *dev_priv = connector->dev->dev_private;
-       struct intel_encoder *intel_encoder = to_intel_encoder(connector);
-       struct intel_dvo_device *dvo = intel_encoder->dev_priv;
-
-       dvo->dev_ops->restore(dvo);
-
-       I915_WRITE(DVOA, dev_priv->saveDVOA);
-       I915_WRITE(DVOB, dev_priv->saveDVOB);
-       I915_WRITE(DVOC, dev_priv->saveDVOC);
-}
-
 static int intel_dvo_mode_valid(struct drm_connector *connector,
                                struct drm_display_mode *mode)
 {
-       struct intel_encoder *intel_encoder = to_intel_encoder(connector);
+       struct drm_encoder *encoder = intel_attached_encoder(connector);
+       struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
        struct intel_dvo_device *dvo = intel_encoder->dev_priv;
 
        if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
@@ -241,7 +213,8 @@ static void intel_dvo_mode_set(struct drm_encoder *encoder,
  */
 static enum drm_connector_status intel_dvo_detect(struct drm_connector *connector)
 {
-       struct intel_encoder *intel_encoder = to_intel_encoder(connector);
+       struct drm_encoder *encoder = intel_attached_encoder(connector);
+       struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
        struct intel_dvo_device *dvo = intel_encoder->dev_priv;
 
        return dvo->dev_ops->detect(dvo);
@@ -249,7 +222,8 @@ static enum drm_connector_status intel_dvo_detect(struct drm_connector *connecto
 
 static int intel_dvo_get_modes(struct drm_connector *connector)
 {
-       struct intel_encoder *intel_encoder = to_intel_encoder(connector);
+       struct drm_encoder *encoder = intel_attached_encoder(connector);
+       struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
        struct intel_dvo_device *dvo = intel_encoder->dev_priv;
 
        /* We should probably have an i2c driver get_modes function for those
@@ -257,7 +231,7 @@ static int intel_dvo_get_modes(struct drm_connector *connector)
         * (TV-out, for example), but for now with just TMDS and LVDS,
         * that's not the case.
         */
-       intel_ddc_get_modes(intel_encoder);
+       intel_ddc_get_modes(connector, intel_encoder->ddc_bus);
        if (!list_empty(&connector->probed_modes))
                return 1;
 
@@ -275,38 +249,10 @@ static int intel_dvo_get_modes(struct drm_connector *connector)
 
 static void intel_dvo_destroy (struct drm_connector *connector)
 {
-       struct intel_encoder *intel_encoder = to_intel_encoder(connector);
-       struct intel_dvo_device *dvo = intel_encoder->dev_priv;
-
-       if (dvo) {
-               if (dvo->dev_ops->destroy)
-                       dvo->dev_ops->destroy(dvo);
-               if (dvo->panel_fixed_mode)
-                       kfree(dvo->panel_fixed_mode);
-               /* no need, in i830_dvoices[] now */
-               //kfree(dvo);
-       }
-       if (intel_encoder->i2c_bus)
-               intel_i2c_destroy(intel_encoder->i2c_bus);
-       if (intel_encoder->ddc_bus)
-               intel_i2c_destroy(intel_encoder->ddc_bus);
        drm_sysfs_connector_remove(connector);
        drm_connector_cleanup(connector);
-       kfree(intel_encoder);
-}
-
-#ifdef RANDR_GET_CRTC_INTERFACE
-static struct drm_crtc *intel_dvo_get_crtc(struct drm_connector *connector)
-{
-       struct drm_device *dev = connector->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_encoder *intel_encoder = to_intel_encoder(connector);
-       struct intel_dvo_device *dvo = intel_encoder->dev_priv;
-       int pipe = !!(I915_READ(dvo->dvo_reg) & SDVO_PIPE_B_SELECT);
-
-       return intel_pipe_to_crtc(pScrn, pipe);
+       kfree(connector);
 }
-#endif
 
 static const struct drm_encoder_helper_funcs intel_dvo_helper_funcs = {
        .dpms = intel_dvo_dpms,
@@ -318,8 +264,6 @@ static const struct drm_encoder_helper_funcs intel_dvo_helper_funcs = {
 
 static const struct drm_connector_funcs intel_dvo_connector_funcs = {
        .dpms = drm_helper_connector_dpms,
-       .save = intel_dvo_save,
-       .restore = intel_dvo_restore,
        .detect = intel_dvo_detect,
        .destroy = intel_dvo_destroy,
        .fill_modes = drm_helper_probe_single_connector_modes,
@@ -328,12 +272,26 @@ static const struct drm_connector_funcs intel_dvo_connector_funcs = {
 static const struct drm_connector_helper_funcs intel_dvo_connector_helper_funcs = {
        .mode_valid = intel_dvo_mode_valid,
        .get_modes = intel_dvo_get_modes,
-       .best_encoder = intel_best_encoder,
+       .best_encoder = intel_attached_encoder,
 };
 
 static void intel_dvo_enc_destroy(struct drm_encoder *encoder)
 {
+       struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
+       struct intel_dvo_device *dvo = intel_encoder->dev_priv;
+
+       if (dvo) {
+               if (dvo->dev_ops->destroy)
+                       dvo->dev_ops->destroy(dvo);
+               if (dvo->panel_fixed_mode)
+                       kfree(dvo->panel_fixed_mode);
+       }
+       if (intel_encoder->i2c_bus)
+               intel_i2c_destroy(intel_encoder->i2c_bus);
+       if (intel_encoder->ddc_bus)
+               intel_i2c_destroy(intel_encoder->ddc_bus);
        drm_encoder_cleanup(encoder);
+       kfree(intel_encoder);
 }
 
 static const struct drm_encoder_funcs intel_dvo_enc_funcs = {
@@ -352,7 +310,8 @@ intel_dvo_get_current_mode (struct drm_connector *connector)
 {
        struct drm_device *dev = connector->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_encoder *intel_encoder = to_intel_encoder(connector);
+       struct drm_encoder *encoder = intel_attached_encoder(connector);
+       struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
        struct intel_dvo_device *dvo = intel_encoder->dev_priv;
        uint32_t dvo_reg = dvo->dvo_reg;
        uint32_t dvo_val = I915_READ(dvo_reg);
@@ -384,6 +343,7 @@ intel_dvo_get_current_mode (struct drm_connector *connector)
 void intel_dvo_init(struct drm_device *dev)
 {
        struct intel_encoder *intel_encoder;
+       struct intel_connector *intel_connector;
        struct intel_dvo_device *dvo;
        struct i2c_adapter *i2cbus = NULL;
        int ret = 0;
@@ -393,6 +353,12 @@ void intel_dvo_init(struct drm_device *dev)
        if (!intel_encoder)
                return;
 
+       intel_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL);
+       if (!intel_connector) {
+               kfree(intel_encoder);
+               return;
+       }
+
        /* Set up the DDC bus */
        intel_encoder->ddc_bus = intel_i2c_create(dev, GPIOD, "DVODDC_D");
        if (!intel_encoder->ddc_bus)
@@ -400,7 +366,7 @@ void intel_dvo_init(struct drm_device *dev)
 
        /* Now, try to find a controller */
        for (i = 0; i < ARRAY_SIZE(intel_dvo_devices); i++) {
-               struct drm_connector *connector = &intel_encoder->base;
+               struct drm_connector *connector = &intel_connector->base;
                int gpio;
 
                dvo = &intel_dvo_devices[i];
@@ -471,7 +437,7 @@ void intel_dvo_init(struct drm_device *dev)
                drm_encoder_helper_add(&intel_encoder->enc,
                                       &intel_dvo_helper_funcs);
 
-               drm_mode_connector_attach_encoder(&intel_encoder->base,
+               drm_mode_connector_attach_encoder(&intel_connector->base,
                                                  &intel_encoder->enc);
                if (dvo->type == INTEL_DVO_CHIP_LVDS) {
                        /* For our LVDS chipsets, we should hopefully be able
@@ -496,4 +462,5 @@ void intel_dvo_init(struct drm_device *dev)
                intel_i2c_destroy(i2cbus);
 free_intel:
        kfree(intel_encoder);
+       kfree(intel_connector);
 }
index 48cade0..8a1c4ed 100644 (file)
@@ -39,7 +39,6 @@
 
 struct intel_hdmi_priv {
        u32 sdvox_reg;
-       u32 save_SDVOX;
        bool has_hdmi_sink;
 };
 
@@ -63,8 +62,12 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder,
        if (hdmi_priv->has_hdmi_sink)
                sdvox |= SDVO_AUDIO_ENABLE;
 
-       if (intel_crtc->pipe == 1)
-               sdvox |= SDVO_PIPE_B_SELECT;
+       if (intel_crtc->pipe == 1) {
+               if (HAS_PCH_CPT(dev))
+                       sdvox |= PORT_TRANS_B_SEL_CPT;
+               else
+                       sdvox |= SDVO_PIPE_B_SELECT;
+       }
 
        I915_WRITE(hdmi_priv->sdvox_reg, sdvox);
        POSTING_READ(hdmi_priv->sdvox_reg);
@@ -106,27 +109,6 @@ static void intel_hdmi_dpms(struct drm_encoder *encoder, int mode)
        }
 }
 
-static void intel_hdmi_save(struct drm_connector *connector)
-{
-       struct drm_device *dev = connector->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_encoder *intel_encoder = to_intel_encoder(connector);
-       struct intel_hdmi_priv *hdmi_priv = intel_encoder->dev_priv;
-
-       hdmi_priv->save_SDVOX = I915_READ(hdmi_priv->sdvox_reg);
-}
-
-static void intel_hdmi_restore(struct drm_connector *connector)
-{
-       struct drm_device *dev = connector->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_encoder *intel_encoder = to_intel_encoder(connector);
-       struct intel_hdmi_priv *hdmi_priv = intel_encoder->dev_priv;
-
-       I915_WRITE(hdmi_priv->sdvox_reg, hdmi_priv->save_SDVOX);
-       POSTING_READ(hdmi_priv->sdvox_reg);
-}
-
 static int intel_hdmi_mode_valid(struct drm_connector *connector,
                                 struct drm_display_mode *mode)
 {
@@ -151,13 +133,14 @@ static bool intel_hdmi_mode_fixup(struct drm_encoder *encoder,
 static enum drm_connector_status
 intel_hdmi_detect(struct drm_connector *connector)
 {
-       struct intel_encoder *intel_encoder = to_intel_encoder(connector);
+       struct drm_encoder *encoder = intel_attached_encoder(connector);
+       struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
        struct intel_hdmi_priv *hdmi_priv = intel_encoder->dev_priv;
        struct edid *edid = NULL;
        enum drm_connector_status status = connector_status_disconnected;
 
        hdmi_priv->has_hdmi_sink = false;
-       edid = drm_get_edid(&intel_encoder->base,
+       edid = drm_get_edid(connector,
                            intel_encoder->ddc_bus);
 
        if (edid) {
@@ -165,7 +148,7 @@ intel_hdmi_detect(struct drm_connector *connector)
                        status = connector_status_connected;
                        hdmi_priv->has_hdmi_sink = drm_detect_hdmi_monitor(edid);
                }
-               intel_encoder->base.display_info.raw_edid = NULL;
+               connector->display_info.raw_edid = NULL;
                kfree(edid);
        }
 
@@ -174,24 +157,21 @@ intel_hdmi_detect(struct drm_connector *connector)
 
 static int intel_hdmi_get_modes(struct drm_connector *connector)
 {
-       struct intel_encoder *intel_encoder = to_intel_encoder(connector);
+       struct drm_encoder *encoder = intel_attached_encoder(connector);
+       struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
 
        /* We should parse the EDID data and find out if it's an HDMI sink so
         * we can send audio to it.
         */
 
-       return intel_ddc_get_modes(intel_encoder);
+       return intel_ddc_get_modes(connector, intel_encoder->ddc_bus);
 }
 
 static void intel_hdmi_destroy(struct drm_connector *connector)
 {
-       struct intel_encoder *intel_encoder = to_intel_encoder(connector);
-
-       if (intel_encoder->i2c_bus)
-               intel_i2c_destroy(intel_encoder->i2c_bus);
        drm_sysfs_connector_remove(connector);
        drm_connector_cleanup(connector);
-       kfree(intel_encoder);
+       kfree(connector);
 }
 
 static const struct drm_encoder_helper_funcs intel_hdmi_helper_funcs = {
@@ -204,8 +184,6 @@ static const struct drm_encoder_helper_funcs intel_hdmi_helper_funcs = {
 
 static const struct drm_connector_funcs intel_hdmi_connector_funcs = {
        .dpms = drm_helper_connector_dpms,
-       .save = intel_hdmi_save,
-       .restore = intel_hdmi_restore,
        .detect = intel_hdmi_detect,
        .fill_modes = drm_helper_probe_single_connector_modes,
        .destroy = intel_hdmi_destroy,
@@ -214,12 +192,17 @@ static const struct drm_connector_funcs intel_hdmi_connector_funcs = {
 static const struct drm_connector_helper_funcs intel_hdmi_connector_helper_funcs = {
        .get_modes = intel_hdmi_get_modes,
        .mode_valid = intel_hdmi_mode_valid,
-       .best_encoder = intel_best_encoder,
+       .best_encoder = intel_attached_encoder,
 };
 
 static void intel_hdmi_enc_destroy(struct drm_encoder *encoder)
 {
+       struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
+
+       if (intel_encoder->i2c_bus)
+               intel_i2c_destroy(intel_encoder->i2c_bus);
        drm_encoder_cleanup(encoder);
+       kfree(intel_encoder);
 }
 
 static const struct drm_encoder_funcs intel_hdmi_enc_funcs = {
@@ -231,15 +214,23 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg)
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_connector *connector;
        struct intel_encoder *intel_encoder;
+       struct intel_connector *intel_connector;
        struct intel_hdmi_priv *hdmi_priv;
 
        intel_encoder = kcalloc(sizeof(struct intel_encoder) +
                               sizeof(struct intel_hdmi_priv), 1, GFP_KERNEL);
        if (!intel_encoder)
                return;
+
+       intel_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL);
+       if (!intel_connector) {
+               kfree(intel_encoder);
+               return;
+       }
+
        hdmi_priv = (struct intel_hdmi_priv *)(intel_encoder + 1);
 
-       connector = &intel_encoder->base;
+       connector = &intel_connector->base;
        drm_connector_init(dev, connector, &intel_hdmi_connector_funcs,
                           DRM_MODE_CONNECTOR_HDMIA);
        drm_connector_helper_add(connector, &intel_hdmi_connector_helper_funcs);
@@ -285,7 +276,7 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg)
                         DRM_MODE_ENCODER_TMDS);
        drm_encoder_helper_add(&intel_encoder->enc, &intel_hdmi_helper_funcs);
 
-       drm_mode_connector_attach_encoder(&intel_encoder->base,
+       drm_mode_connector_attach_encoder(&intel_connector->base,
                                          &intel_encoder->enc);
        drm_sysfs_connector_add(connector);
 
@@ -303,6 +294,7 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg)
 err_connector:
        drm_connector_cleanup(connector);
        kfree(intel_encoder);
+       kfree(intel_connector);
 
        return;
 }
index b66806a..6a1accd 100644 (file)
@@ -139,75 +139,6 @@ static void intel_lvds_dpms(struct drm_encoder *encoder, int mode)
        /* XXX: We never power down the LVDS pairs. */
 }
 
-static void intel_lvds_save(struct drm_connector *connector)
-{
-       struct drm_device *dev = connector->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 pp_on_reg, pp_off_reg, pp_ctl_reg, pp_div_reg;
-       u32 pwm_ctl_reg;
-
-       if (HAS_PCH_SPLIT(dev)) {
-               pp_on_reg = PCH_PP_ON_DELAYS;
-               pp_off_reg = PCH_PP_OFF_DELAYS;
-               pp_ctl_reg = PCH_PP_CONTROL;
-               pp_div_reg = PCH_PP_DIVISOR;
-               pwm_ctl_reg = BLC_PWM_CPU_CTL;
-       } else {
-               pp_on_reg = PP_ON_DELAYS;
-               pp_off_reg = PP_OFF_DELAYS;
-               pp_ctl_reg = PP_CONTROL;
-               pp_div_reg = PP_DIVISOR;
-               pwm_ctl_reg = BLC_PWM_CTL;
-       }
-
-       dev_priv->savePP_ON = I915_READ(pp_on_reg);
-       dev_priv->savePP_OFF = I915_READ(pp_off_reg);
-       dev_priv->savePP_CONTROL = I915_READ(pp_ctl_reg);
-       dev_priv->savePP_DIVISOR = I915_READ(pp_div_reg);
-       dev_priv->saveBLC_PWM_CTL = I915_READ(pwm_ctl_reg);
-       dev_priv->backlight_duty_cycle = (dev_priv->saveBLC_PWM_CTL &
-                                      BACKLIGHT_DUTY_CYCLE_MASK);
-
-       /*
-        * If the light is off at server startup, just make it full brightness
-        */
-       if (dev_priv->backlight_duty_cycle == 0)
-               dev_priv->backlight_duty_cycle =
-                       intel_lvds_get_max_backlight(dev);
-}
-
-static void intel_lvds_restore(struct drm_connector *connector)
-{
-       struct drm_device *dev = connector->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 pp_on_reg, pp_off_reg, pp_ctl_reg, pp_div_reg;
-       u32 pwm_ctl_reg;
-
-       if (HAS_PCH_SPLIT(dev)) {
-               pp_on_reg = PCH_PP_ON_DELAYS;
-               pp_off_reg = PCH_PP_OFF_DELAYS;
-               pp_ctl_reg = PCH_PP_CONTROL;
-               pp_div_reg = PCH_PP_DIVISOR;
-               pwm_ctl_reg = BLC_PWM_CPU_CTL;
-       } else {
-               pp_on_reg = PP_ON_DELAYS;
-               pp_off_reg = PP_OFF_DELAYS;
-               pp_ctl_reg = PP_CONTROL;
-               pp_div_reg = PP_DIVISOR;
-               pwm_ctl_reg = BLC_PWM_CTL;
-       }
-
-       I915_WRITE(pwm_ctl_reg, dev_priv->saveBLC_PWM_CTL);
-       I915_WRITE(pp_on_reg, dev_priv->savePP_ON);
-       I915_WRITE(pp_off_reg, dev_priv->savePP_OFF);
-       I915_WRITE(pp_div_reg, dev_priv->savePP_DIVISOR);
-       I915_WRITE(pp_ctl_reg, dev_priv->savePP_CONTROL);
-       if (dev_priv->savePP_CONTROL & POWER_TARGET_ON)
-               intel_lvds_set_power(dev, true);
-       else
-               intel_lvds_set_power(dev, false);
-}
-
 static int intel_lvds_mode_valid(struct drm_connector *connector,
                                 struct drm_display_mode *mode)
 {
@@ -635,12 +566,13 @@ static enum drm_connector_status intel_lvds_detect(struct drm_connector *connect
 static int intel_lvds_get_modes(struct drm_connector *connector)
 {
        struct drm_device *dev = connector->dev;
-       struct intel_encoder *intel_encoder = to_intel_encoder(connector);
+       struct drm_encoder *encoder = intel_attached_encoder(connector);
+       struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
        struct drm_i915_private *dev_priv = dev->dev_private;
        int ret = 0;
 
        if (dev_priv->lvds_edid_good) {
-               ret = intel_ddc_get_modes(intel_encoder);
+               ret = intel_ddc_get_modes(connector, intel_encoder->ddc_bus);
 
                if (ret)
                        return ret;
@@ -717,11 +649,8 @@ static int intel_lid_notify(struct notifier_block *nb, unsigned long val,
 static void intel_lvds_destroy(struct drm_connector *connector)
 {
        struct drm_device *dev = connector->dev;
-       struct intel_encoder *intel_encoder = to_intel_encoder(connector);
        struct drm_i915_private *dev_priv = dev->dev_private;
 
-       if (intel_encoder->ddc_bus)
-               intel_i2c_destroy(intel_encoder->ddc_bus);
        if (dev_priv->lid_notifier.notifier_call)
                acpi_lid_notifier_unregister(&dev_priv->lid_notifier);
        drm_sysfs_connector_remove(connector);
@@ -734,13 +663,14 @@ static int intel_lvds_set_property(struct drm_connector *connector,
                                   uint64_t value)
 {
        struct drm_device *dev = connector->dev;
-       struct intel_encoder *intel_encoder =
-                       to_intel_encoder(connector);
 
        if (property == dev->mode_config.scaling_mode_property &&
                                connector->encoder) {
                struct drm_crtc *crtc = connector->encoder->crtc;
+               struct drm_encoder *encoder = connector->encoder;
+               struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
                struct intel_lvds_priv *lvds_priv = intel_encoder->dev_priv;
+
                if (value == DRM_MODE_SCALE_NONE) {
                        DRM_DEBUG_KMS("no scaling not supported\n");
                        return 0;
@@ -774,13 +704,11 @@ static const struct drm_encoder_helper_funcs intel_lvds_helper_funcs = {
 static const struct drm_connector_helper_funcs intel_lvds_connector_helper_funcs = {
        .get_modes = intel_lvds_get_modes,
        .mode_valid = intel_lvds_mode_valid,
-       .best_encoder = intel_best_encoder,
+       .best_encoder = intel_attached_encoder,
 };
 
 static const struct drm_connector_funcs intel_lvds_connector_funcs = {
        .dpms = drm_helper_connector_dpms,
-       .save = intel_lvds_save,
-       .restore = intel_lvds_restore,
        .detect = intel_lvds_detect,
        .fill_modes = drm_helper_probe_single_connector_modes,
        .set_property = intel_lvds_set_property,
@@ -790,7 +718,12 @@ static const struct drm_connector_funcs intel_lvds_connector_funcs = {
 
 static void intel_lvds_enc_destroy(struct drm_encoder *encoder)
 {
+       struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
+
+       if (intel_encoder->ddc_bus)
+               intel_i2c_destroy(intel_encoder->ddc_bus);
        drm_encoder_cleanup(encoder);
+       kfree(intel_encoder);
 }
 
 static const struct drm_encoder_funcs intel_lvds_enc_funcs = {
@@ -979,6 +912,7 @@ void intel_lvds_init(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_encoder *intel_encoder;
+       struct intel_connector *intel_connector;
        struct drm_connector *connector;
        struct drm_encoder *encoder;
        struct drm_display_mode *scan; /* *modes, *bios_mode; */
@@ -1012,19 +946,27 @@ void intel_lvds_init(struct drm_device *dev)
                return;
        }
 
-       connector = &intel_encoder->base;
+       intel_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL);
+       if (!intel_connector) {
+               kfree(intel_encoder);
+               return;
+       }
+
+       connector = &intel_connector->base;
        encoder = &intel_encoder->enc;
-       drm_connector_init(dev, &intel_encoder->base, &intel_lvds_connector_funcs,
+       drm_connector_init(dev, &intel_connector->base, &intel_lvds_connector_funcs,
                           DRM_MODE_CONNECTOR_LVDS);
 
        drm_encoder_init(dev, &intel_encoder->enc, &intel_lvds_enc_funcs,
                         DRM_MODE_ENCODER_LVDS);
 
-       drm_mode_connector_attach_encoder(&intel_encoder->base, &intel_encoder->enc);
+       drm_mode_connector_attach_encoder(&intel_connector->base, &intel_encoder->enc);
        intel_encoder->type = INTEL_OUTPUT_LVDS;
 
        intel_encoder->clone_mask = (1 << INTEL_LVDS_CLONE_BIT);
        intel_encoder->crtc_mask = (1 << 1);
+       if (IS_I965G(dev))
+               intel_encoder->crtc_mask |= (1 << 0);
        drm_encoder_helper_add(encoder, &intel_lvds_helper_funcs);
        drm_connector_helper_add(connector, &intel_lvds_connector_helper_funcs);
        connector->display_info.subpixel_order = SubPixelHorizontalRGB;
@@ -1039,7 +981,7 @@ void intel_lvds_init(struct drm_device *dev)
         * the initial panel fitting mode will be FULL_SCREEN.
         */
 
-       drm_connector_attach_property(&intel_encoder->base,
+       drm_connector_attach_property(&intel_connector->base,
                                      dev->mode_config.scaling_mode_property,
                                      DRM_MODE_SCALE_FULLSCREEN);
        lvds_priv->fitting_mode = DRM_MODE_SCALE_FULLSCREEN;
@@ -1067,7 +1009,7 @@ void intel_lvds_init(struct drm_device *dev)
         */
        dev_priv->lvds_edid_good = true;
 
-       if (!intel_ddc_get_modes(intel_encoder))
+       if (!intel_ddc_get_modes(connector, intel_encoder->ddc_bus))
                dev_priv->lvds_edid_good = false;
 
        list_for_each_entry(scan, &connector->probed_modes, head) {
@@ -1151,4 +1093,5 @@ failed:
        drm_connector_cleanup(connector);
        drm_encoder_cleanup(encoder);
        kfree(intel_encoder);
+       kfree(intel_connector);
 }
index 8e5c83b..4b1fd3d 100644 (file)
@@ -54,9 +54,9 @@ bool intel_ddc_probe(struct intel_encoder *intel_encoder)
                }
        };
 
-       intel_i2c_quirk_set(intel_encoder->base.dev, true);
+       intel_i2c_quirk_set(intel_encoder->enc.dev, true);
        ret = i2c_transfer(intel_encoder->ddc_bus, msgs, 2);
-       intel_i2c_quirk_set(intel_encoder->base.dev, false);
+       intel_i2c_quirk_set(intel_encoder->enc.dev, false);
        if (ret == 2)
                return true;
 
@@ -66,22 +66,23 @@ bool intel_ddc_probe(struct intel_encoder *intel_encoder)
 /**
  * intel_ddc_get_modes - get modelist from monitor
  * @connector: DRM connector device to use
+ * @adapter: i2c adapter
  *
  * Fetch the EDID information from @connector using the DDC bus.
  */
-int intel_ddc_get_modes(struct intel_encoder *intel_encoder)
+int intel_ddc_get_modes(struct drm_connector *connector,
+                       struct i2c_adapter *adapter)
 {
        struct edid *edid;
        int ret = 0;
 
-       intel_i2c_quirk_set(intel_encoder->base.dev, true);
-       edid = drm_get_edid(&intel_encoder->base, intel_encoder->ddc_bus);
-       intel_i2c_quirk_set(intel_encoder->base.dev, false);
+       intel_i2c_quirk_set(connector->dev, true);
+       edid = drm_get_edid(connector, adapter);
+       intel_i2c_quirk_set(connector->dev, false);
        if (edid) {
-               drm_mode_connector_update_edid_property(&intel_encoder->base,
-                                                       edid);
-               ret = drm_add_edid_modes(&intel_encoder->base, edid);
-               intel_encoder->base.display_info.raw_edid = NULL;
+               drm_mode_connector_update_edid_property(connector, edid);
+               ret = drm_add_edid_modes(connector, edid);
+               connector->display_info.raw_edid = NULL;
                kfree(edid);
        }
 
index 87d9536..42ceb15 100644 (file)
 #include "i915_drm.h"
 #include "i915_drv.h"
 #include "intel_sdvo_regs.h"
-#include <linux/dmi.h>
+
+#define SDVO_TMDS_MASK (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_TMDS1)
+#define SDVO_RGB_MASK  (SDVO_OUTPUT_RGB0 | SDVO_OUTPUT_RGB1)
+#define SDVO_LVDS_MASK (SDVO_OUTPUT_LVDS0 | SDVO_OUTPUT_LVDS1)
+#define SDVO_TV_MASK   (SDVO_OUTPUT_CVBS0 | SDVO_OUTPUT_SVID0)
+
+#define SDVO_OUTPUT_MASK (SDVO_TMDS_MASK | SDVO_RGB_MASK | SDVO_LVDS_MASK |\
+                         SDVO_TV_MASK)
+
+#define IS_TV(c)       (c->output_flag & SDVO_TV_MASK)
+#define IS_LVDS(c)     (c->output_flag & SDVO_LVDS_MASK)
+
 
 static char *tv_format_names[] = {
        "NTSC_M"   , "NTSC_J"  , "NTSC_443",
@@ -86,12 +97,6 @@ struct intel_sdvo_priv {
        /* This is for current tv format name */
        char *tv_format_name;
 
-       /* This contains all current supported TV format */
-       char *tv_format_supported[TV_FORMAT_NUM];
-       int   format_supported_num;
-       struct drm_property *tv_format_property;
-       struct drm_property *tv_format_name_property[TV_FORMAT_NUM];
-
        /**
         * This is set if we treat the device as HDMI, instead of DVI.
         */
@@ -112,12 +117,6 @@ struct intel_sdvo_priv {
         */
        struct drm_display_mode *sdvo_lvds_fixed_mode;
 
-       /**
-        * Returned SDTV resolutions allowed for the current format, if the
-        * device reported it.
-        */
-       struct intel_sdvo_sdtv_resolution_reply sdtv_resolutions;
-
        /*
         * supported encoding mode, used to determine whether HDMI is
         * supported
@@ -130,11 +129,24 @@ struct intel_sdvo_priv {
        /* Mac mini hack -- use the same DDC as the analog connector */
        struct i2c_adapter *analog_ddc_bus;
 
-       int save_sdvo_mult;
-       u16 save_active_outputs;
-       struct intel_sdvo_dtd save_input_dtd_1, save_input_dtd_2;
-       struct intel_sdvo_dtd save_output_dtd[16];
-       u32 save_SDVOX;
+};
+
+struct intel_sdvo_connector {
+       /* Mark the type of connector */
+       uint16_t output_flag;
+
+       /* This contains all current supported TV format */
+       char *tv_format_supported[TV_FORMAT_NUM];
+       int   format_supported_num;
+       struct drm_property *tv_format_property;
+       struct drm_property *tv_format_name_property[TV_FORMAT_NUM];
+
+       /**
+        * Returned SDTV resolutions allowed for the current format, if the
+        * device reported it.
+        */
+       struct intel_sdvo_sdtv_resolution_reply sdtv_resolutions;
+
        /* add the property for the SDVO-TV */
        struct drm_property *left_property;
        struct drm_property *right_property;
@@ -162,7 +174,12 @@ struct intel_sdvo_priv {
 };
 
 static bool
-intel_sdvo_output_setup(struct intel_encoder *intel_encoder, uint16_t flags);
+intel_sdvo_output_setup(struct intel_encoder *intel_encoder,
+                       uint16_t flags);
+static void
+intel_sdvo_tv_create_property(struct drm_connector *connector, int type);
+static void
+intel_sdvo_create_enhance_property(struct drm_connector *connector);
 
 /**
  * Writes the SDVOB or SDVOC with the given value, but always writes both
@@ -171,12 +188,18 @@ intel_sdvo_output_setup(struct intel_encoder *intel_encoder, uint16_t flags);
  */
 static void intel_sdvo_write_sdvox(struct intel_encoder *intel_encoder, u32 val)
 {
-       struct drm_device *dev = intel_encoder->base.dev;
+       struct drm_device *dev = intel_encoder->enc.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_sdvo_priv   *sdvo_priv = intel_encoder->dev_priv;
        u32 bval = val, cval = val;
        int i;
 
+       if (sdvo_priv->sdvo_reg == PCH_SDVOB) {
+               I915_WRITE(sdvo_priv->sdvo_reg, val);
+               I915_READ(sdvo_priv->sdvo_reg);
+               return;
+       }
+
        if (sdvo_priv->sdvo_reg == SDVOB) {
                cval = I915_READ(SDVOC);
        } else {
@@ -353,7 +376,8 @@ static const struct _sdvo_cmd_name {
     SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_HBUF_DATA),
 };
 
-#define SDVO_NAME(dev_priv) ((dev_priv)->sdvo_reg == SDVOB ? "SDVOB" : "SDVOC")
+#define IS_SDVOB(reg)  (reg == SDVOB || reg == PCH_SDVOB)
+#define SDVO_NAME(dev_priv) (IS_SDVOB((dev_priv)->sdvo_reg) ? "SDVOB" : "SDVOC")
 #define SDVO_PRIV(encoder)   ((struct intel_sdvo_priv *) (encoder)->dev_priv)
 
 static void intel_sdvo_debug_write(struct intel_encoder *intel_encoder, u8 cmd,
@@ -563,17 +587,6 @@ static bool intel_sdvo_get_trained_inputs(struct intel_encoder *intel_encoder, b
        return true;
 }
 
-static bool intel_sdvo_get_active_outputs(struct intel_encoder *intel_encoder,
-                                         u16 *outputs)
-{
-       u8 status;
-
-       intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_GET_ACTIVE_OUTPUTS, NULL, 0);
-       status = intel_sdvo_read_response(intel_encoder, outputs, sizeof(*outputs));
-
-       return (status == SDVO_CMD_STATUS_SUCCESS);
-}
-
 static bool intel_sdvo_set_active_outputs(struct intel_encoder *intel_encoder,
                                          u16 outputs)
 {
@@ -646,40 +659,6 @@ static bool intel_sdvo_set_target_output(struct intel_encoder *intel_encoder,
        return (status == SDVO_CMD_STATUS_SUCCESS);
 }
 
-static bool intel_sdvo_get_timing(struct intel_encoder *intel_encoder, u8 cmd,
-                                 struct intel_sdvo_dtd *dtd)
-{
-       u8 status;
-
-       intel_sdvo_write_cmd(intel_encoder, cmd, NULL, 0);
-       status = intel_sdvo_read_response(intel_encoder, &dtd->part1,
-                                         sizeof(dtd->part1));
-       if (status != SDVO_CMD_STATUS_SUCCESS)
-               return false;
-
-       intel_sdvo_write_cmd(intel_encoder, cmd + 1, NULL, 0);
-       status = intel_sdvo_read_response(intel_encoder, &dtd->part2,
-                                         sizeof(dtd->part2));
-       if (status != SDVO_CMD_STATUS_SUCCESS)
-               return false;
-
-       return true;
-}
-
-static bool intel_sdvo_get_input_timing(struct intel_encoder *intel_encoder,
-                                        struct intel_sdvo_dtd *dtd)
-{
-       return intel_sdvo_get_timing(intel_encoder,
-                                    SDVO_CMD_GET_INPUT_TIMINGS_PART1, dtd);
-}
-
-static bool intel_sdvo_get_output_timing(struct intel_encoder *intel_encoder,
-                                        struct intel_sdvo_dtd *dtd)
-{
-       return intel_sdvo_get_timing(intel_encoder,
-                                    SDVO_CMD_GET_OUTPUT_TIMINGS_PART1, dtd);
-}
-
 static bool intel_sdvo_set_timing(struct intel_encoder *intel_encoder, u8 cmd,
                                  struct intel_sdvo_dtd *dtd)
 {
@@ -767,23 +746,6 @@ static bool intel_sdvo_get_preferred_input_timing(struct intel_encoder *intel_en
        return false;
 }
 
-static int intel_sdvo_get_clock_rate_mult(struct intel_encoder *intel_encoder)
-{
-       u8 response, status;
-
-       intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_GET_CLOCK_RATE_MULT, NULL, 0);
-       status = intel_sdvo_read_response(intel_encoder, &response, 1);
-
-       if (status != SDVO_CMD_STATUS_SUCCESS) {
-               DRM_DEBUG_KMS("Couldn't get SDVO clock rate multiplier\n");
-               return SDVO_CLOCK_RATE_MULT_1X;
-       } else {
-               DRM_DEBUG_KMS("Current clock rate multiplier: %d\n", response);
-       }
-
-       return response;
-}
-
 static bool intel_sdvo_set_clock_rate_mult(struct intel_encoder *intel_encoder, u8 val)
 {
        u8 status;
@@ -1071,7 +1033,7 @@ static void intel_sdvo_set_tv_format(struct intel_encoder *intel_encoder)
        memcpy(&format, &format_map, sizeof(format_map) > sizeof(format) ?
                        sizeof(format) : sizeof(format_map));
 
-       intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_SET_TV_FORMAT, &format_map,
+       intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_SET_TV_FORMAT, &format,
                             sizeof(format));
 
        status = intel_sdvo_read_response(intel_encoder, NULL, 0);
@@ -1101,7 +1063,7 @@ static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder,
                /* Set output timings */
                intel_sdvo_get_dtd_from_mode(&output_dtd, mode);
                intel_sdvo_set_target_output(intel_encoder,
-                                            dev_priv->controlled_output);
+                                            dev_priv->attached_output);
                intel_sdvo_set_output_timing(intel_encoder, &output_dtd);
 
                /* Set the input timing to the screen. Assume always input 0. */
@@ -1139,7 +1101,7 @@ static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder,
                                dev_priv->sdvo_lvds_fixed_mode);
 
                intel_sdvo_set_target_output(intel_encoder,
-                                            dev_priv->controlled_output);
+                                            dev_priv->attached_output);
                intel_sdvo_set_output_timing(intel_encoder, &output_dtd);
 
                /* Set the input timing to the screen. Assume always input 0. */
@@ -1204,7 +1166,7 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder,
         * channel on the motherboard.  In a two-input device, the first input
         * will be SDVOB and the second SDVOC.
         */
-       in_out.in0 = sdvo_priv->controlled_output;
+       in_out.in0 = sdvo_priv->attached_output;
        in_out.in1 = 0;
 
        intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_SET_IN_OUT_MAP,
@@ -1230,7 +1192,7 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder,
        if (!sdvo_priv->is_tv && !sdvo_priv->is_lvds) {
                /* Set the output timing to the screen */
                intel_sdvo_set_target_output(intel_encoder,
-                                            sdvo_priv->controlled_output);
+                                            sdvo_priv->attached_output);
                intel_sdvo_set_output_timing(intel_encoder, &input_dtd);
        }
 
@@ -1352,107 +1314,16 @@ static void intel_sdvo_dpms(struct drm_encoder *encoder, int mode)
 
                if (0)
                        intel_sdvo_set_encoder_power_state(intel_encoder, mode);
-               intel_sdvo_set_active_outputs(intel_encoder, sdvo_priv->controlled_output);
+               intel_sdvo_set_active_outputs(intel_encoder, sdvo_priv->attached_output);
        }
        return;
 }
 
-static void intel_sdvo_save(struct drm_connector *connector)
-{
-       struct drm_device *dev = connector->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_encoder *intel_encoder = to_intel_encoder(connector);
-       struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv;
-       int o;
-
-       sdvo_priv->save_sdvo_mult = intel_sdvo_get_clock_rate_mult(intel_encoder);
-       intel_sdvo_get_active_outputs(intel_encoder, &sdvo_priv->save_active_outputs);
-
-       if (sdvo_priv->caps.sdvo_inputs_mask & 0x1) {
-               intel_sdvo_set_target_input(intel_encoder, true, false);
-               intel_sdvo_get_input_timing(intel_encoder,
-                                           &sdvo_priv->save_input_dtd_1);
-       }
-
-       if (sdvo_priv->caps.sdvo_inputs_mask & 0x2) {
-               intel_sdvo_set_target_input(intel_encoder, false, true);
-               intel_sdvo_get_input_timing(intel_encoder,
-                                           &sdvo_priv->save_input_dtd_2);
-       }
-
-       for (o = SDVO_OUTPUT_FIRST; o <= SDVO_OUTPUT_LAST; o++)
-       {
-               u16  this_output = (1 << o);
-               if (sdvo_priv->caps.output_flags & this_output)
-               {
-                       intel_sdvo_set_target_output(intel_encoder, this_output);
-                       intel_sdvo_get_output_timing(intel_encoder,
-                                                    &sdvo_priv->save_output_dtd[o]);
-               }
-       }
-       if (sdvo_priv->is_tv) {
-               /* XXX: Save TV format/enhancements. */
-       }
-
-       sdvo_priv->save_SDVOX = I915_READ(sdvo_priv->sdvo_reg);
-}
-
-static void intel_sdvo_restore(struct drm_connector *connector)
-{
-       struct drm_device *dev = connector->dev;
-       struct intel_encoder *intel_encoder = to_intel_encoder(connector);
-       struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv;
-       int o;
-       int i;
-       bool input1, input2;
-       u8 status;
-
-       intel_sdvo_set_active_outputs(intel_encoder, 0);
-
-       for (o = SDVO_OUTPUT_FIRST; o <= SDVO_OUTPUT_LAST; o++)
-       {
-               u16  this_output = (1 << o);
-               if (sdvo_priv->caps.output_flags & this_output) {
-                       intel_sdvo_set_target_output(intel_encoder, this_output);
-                       intel_sdvo_set_output_timing(intel_encoder, &sdvo_priv->save_output_dtd[o]);
-               }
-       }
-
-       if (sdvo_priv->caps.sdvo_inputs_mask & 0x1) {
-               intel_sdvo_set_target_input(intel_encoder, true, false);
-               intel_sdvo_set_input_timing(intel_encoder, &sdvo_priv->save_input_dtd_1);
-       }
-
-       if (sdvo_priv->caps.sdvo_inputs_mask & 0x2) {
-               intel_sdvo_set_target_input(intel_encoder, false, true);
-               intel_sdvo_set_input_timing(intel_encoder, &sdvo_priv->save_input_dtd_2);
-       }
-
-       intel_sdvo_set_clock_rate_mult(intel_encoder, sdvo_priv->save_sdvo_mult);
-
-       if (sdvo_priv->is_tv) {
-               /* XXX: Restore TV format/enhancements. */
-       }
-
-       intel_sdvo_write_sdvox(intel_encoder, sdvo_priv->save_SDVOX);
-
-       if (sdvo_priv->save_SDVOX & SDVO_ENABLE)
-       {
-               for (i = 0; i < 2; i++)
-                       intel_wait_for_vblank(dev);
-               status = intel_sdvo_get_trained_inputs(intel_encoder, &input1, &input2);
-               if (status == SDVO_CMD_STATUS_SUCCESS && !input1)
-                       DRM_DEBUG_KMS("First %s output reported failure to "
-                                       "sync\n", SDVO_NAME(sdvo_priv));
-       }
-
-       intel_sdvo_set_active_outputs(intel_encoder, sdvo_priv->save_active_outputs);
-}
-
 static int intel_sdvo_mode_valid(struct drm_connector *connector,
                                 struct drm_display_mode *mode)
 {
-       struct intel_encoder *intel_encoder = to_intel_encoder(connector);
+       struct drm_encoder *encoder = intel_attached_encoder(connector);
+       struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
        struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv;
 
        if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
@@ -1490,6 +1361,8 @@ static bool intel_sdvo_get_capabilities(struct intel_encoder *intel_encoder, str
        return true;
 }
 
+/* No use! */
+#if 0
 struct drm_connector* intel_sdvo_find(struct drm_device *dev, int sdvoB)
 {
        struct drm_connector *connector = NULL;
@@ -1560,6 +1433,7 @@ void intel_sdvo_set_hotplug(struct drm_connector *connector, int on)
        intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_GET_ACTIVE_HOT_PLUG, NULL, 0);
        intel_sdvo_read_response(intel_encoder, &response, 2);
 }
+#endif
 
 static bool
 intel_sdvo_multifunc_encoder(struct intel_encoder *intel_encoder)
@@ -1598,12 +1472,17 @@ static struct drm_connector *
 intel_find_analog_connector(struct drm_device *dev)
 {
        struct drm_connector *connector;
+       struct drm_encoder *encoder;
        struct intel_encoder *intel_encoder;
 
-       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
-               intel_encoder = to_intel_encoder(connector);
-               if (intel_encoder->type == INTEL_OUTPUT_ANALOG)
-                       return connector;
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+               intel_encoder = enc_to_intel_encoder(encoder);
+               if (intel_encoder->type == INTEL_OUTPUT_ANALOG) {
+                       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+                               if (connector && encoder == intel_attached_encoder(connector))
+                                       return connector;
+                       }
+               }
        }
        return NULL;
 }
@@ -1627,12 +1506,13 @@ intel_analog_is_connected(struct drm_device *dev)
 enum drm_connector_status
 intel_sdvo_hdmi_sink_detect(struct drm_connector *connector, u16 response)
 {
-       struct intel_encoder *intel_encoder = to_intel_encoder(connector);
+       struct drm_encoder *encoder = intel_attached_encoder(connector);
+       struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
        struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv;
        enum drm_connector_status status = connector_status_connected;
        struct edid *edid = NULL;
 
-       edid = drm_get_edid(&intel_encoder->base,
+       edid = drm_get_edid(connector,
                            intel_encoder->ddc_bus);
 
        /* This is only applied to SDVO cards with multiple outputs */
@@ -1646,7 +1526,7 @@ intel_sdvo_hdmi_sink_detect(struct drm_connector *connector, u16 response)
                 */
                while(temp_ddc > 1) {
                        sdvo_priv->ddc_bus = temp_ddc;
-                       edid = drm_get_edid(&intel_encoder->base,
+                       edid = drm_get_edid(connector,
                                intel_encoder->ddc_bus);
                        if (edid) {
                                /*
@@ -1666,8 +1546,8 @@ intel_sdvo_hdmi_sink_detect(struct drm_connector *connector, u16 response)
         */
        if (edid == NULL &&
            sdvo_priv->analog_ddc_bus &&
-           !intel_analog_is_connected(intel_encoder->base.dev))
-               edid = drm_get_edid(&intel_encoder->base,
+           !intel_analog_is_connected(connector->dev))
+               edid = drm_get_edid(connector,
                                    sdvo_priv->analog_ddc_bus);
        if (edid != NULL) {
                /* Don't report the output as connected if it's a DVI-I
@@ -1682,7 +1562,7 @@ intel_sdvo_hdmi_sink_detect(struct drm_connector *connector, u16 response)
                }
 
                kfree(edid);
-               intel_encoder->base.display_info.raw_edid = NULL;
+               connector->display_info.raw_edid = NULL;
 
        } else if (response & (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_TMDS1))
                status = connector_status_disconnected;
@@ -1694,8 +1574,12 @@ static enum drm_connector_status intel_sdvo_detect(struct drm_connector *connect
 {
        uint16_t response;
        u8 status;
-       struct intel_encoder *intel_encoder = to_intel_encoder(connector);
+       struct drm_encoder *encoder = intel_attached_encoder(connector);
+       struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
+       struct intel_connector *intel_connector = to_intel_connector(connector);
        struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv;
+       struct intel_sdvo_connector *sdvo_connector = intel_connector->dev_priv;
+       enum drm_connector_status ret;
 
        intel_sdvo_write_cmd(intel_encoder,
                             SDVO_CMD_GET_ATTACHED_DISPLAYS, NULL, 0);
@@ -1713,24 +1597,41 @@ static enum drm_connector_status intel_sdvo_detect(struct drm_connector *connect
        if (response == 0)
                return connector_status_disconnected;
 
-       if (intel_sdvo_multifunc_encoder(intel_encoder) &&
-               sdvo_priv->attached_output != response) {
-               if (sdvo_priv->controlled_output != response &&
-                       intel_sdvo_output_setup(intel_encoder, response) != true)
-                       return connector_status_unknown;
-               sdvo_priv->attached_output = response;
+       sdvo_priv->attached_output = response;
+
+       if ((sdvo_connector->output_flag & response) == 0)
+               ret = connector_status_disconnected;
+       else if (response & (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_TMDS1))
+               ret = intel_sdvo_hdmi_sink_detect(connector, response);
+       else
+               ret = connector_status_connected;
+
+       /* May update encoder flag for like clock for SDVO TV, etc.*/
+       if (ret == connector_status_connected) {
+               sdvo_priv->is_tv = false;
+               sdvo_priv->is_lvds = false;
+               intel_encoder->needs_tv_clock = false;
+
+               if (response & SDVO_TV_MASK) {
+                       sdvo_priv->is_tv = true;
+                       intel_encoder->needs_tv_clock = true;
+               }
+               if (response & SDVO_LVDS_MASK)
+                       sdvo_priv->is_lvds = true;
        }
-       return intel_sdvo_hdmi_sink_detect(connector, response);
+
+       return ret;
 }
 
 static void intel_sdvo_get_ddc_modes(struct drm_connector *connector)
 {
-       struct intel_encoder *intel_encoder = to_intel_encoder(connector);
+       struct drm_encoder *encoder = intel_attached_encoder(connector);
+       struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
        struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv;
        int num_modes;
 
        /* set the bus switch and get the modes */
-       num_modes = intel_ddc_get_modes(intel_encoder);
+       num_modes = intel_ddc_get_modes(connector, intel_encoder->ddc_bus);
 
        /*
         * Mac mini hack.  On this device, the DVI-I connector shares one DDC
@@ -1740,17 +1641,10 @@ static void intel_sdvo_get_ddc_modes(struct drm_connector *connector)
         */
        if (num_modes == 0 &&
            sdvo_priv->analog_ddc_bus &&
-           !intel_analog_is_connected(intel_encoder->base.dev)) {
-               struct i2c_adapter *digital_ddc_bus;
-
+           !intel_analog_is_connected(connector->dev)) {
                /* Switch to the analog ddc bus and try that
                 */
-               digital_ddc_bus = intel_encoder->ddc_bus;
-               intel_encoder->ddc_bus = sdvo_priv->analog_ddc_bus;
-
-               (void) intel_ddc_get_modes(intel_encoder);
-
-               intel_encoder->ddc_bus = digital_ddc_bus;
+               (void) intel_ddc_get_modes(connector, sdvo_priv->analog_ddc_bus);
        }
 }
 
@@ -1821,8 +1715,9 @@ struct drm_display_mode sdvo_tv_modes[] = {
 
 static void intel_sdvo_get_tv_modes(struct drm_connector *connector)
 {
-       struct intel_encoder *output = to_intel_encoder(connector);
-       struct intel_sdvo_priv *sdvo_priv = output->dev_priv;
+       struct drm_encoder *encoder = intel_attached_encoder(connector);
+       struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
+       struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv;
        struct intel_sdvo_sdtv_resolution_request tv_res;
        uint32_t reply = 0, format_map = 0;
        int i;
@@ -1842,11 +1737,11 @@ static void intel_sdvo_get_tv_modes(struct drm_connector *connector)
               sizeof(format_map) ? sizeof(format_map) :
               sizeof(struct intel_sdvo_sdtv_resolution_request));
 
-       intel_sdvo_set_target_output(output, sdvo_priv->controlled_output);
+       intel_sdvo_set_target_output(intel_encoder, sdvo_priv->attached_output);
 
-       intel_sdvo_write_cmd(output, SDVO_CMD_GET_SDTV_RESOLUTION_SUPPORT,
+       intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_GET_SDTV_RESOLUTION_SUPPORT,
                             &tv_res, sizeof(tv_res));
-       status = intel_sdvo_read_response(output, &reply, 3);
+       status = intel_sdvo_read_response(intel_encoder, &reply, 3);
        if (status != SDVO_CMD_STATUS_SUCCESS)
                return;
 
@@ -1863,7 +1758,8 @@ static void intel_sdvo_get_tv_modes(struct drm_connector *connector)
 
 static void intel_sdvo_get_lvds_modes(struct drm_connector *connector)
 {
-       struct intel_encoder *intel_encoder = to_intel_encoder(connector);
+       struct drm_encoder *encoder = intel_attached_encoder(connector);
+       struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
        struct drm_i915_private *dev_priv = connector->dev->dev_private;
        struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv;
        struct drm_display_mode *newmode;
@@ -1873,7 +1769,7 @@ static void intel_sdvo_get_lvds_modes(struct drm_connector *connector)
         * Assume that the preferred modes are
         * arranged in priority order.
         */
-       intel_ddc_get_modes(intel_encoder);
+       intel_ddc_get_modes(connector, intel_encoder->ddc_bus);
        if (list_empty(&connector->probed_modes) == false)
                goto end;
 
@@ -1902,12 +1798,12 @@ end:
 
 static int intel_sdvo_get_modes(struct drm_connector *connector)
 {
-       struct intel_encoder *output = to_intel_encoder(connector);
-       struct intel_sdvo_priv *sdvo_priv = output->dev_priv;
+       struct intel_connector *intel_connector = to_intel_connector(connector);
+       struct intel_sdvo_connector *sdvo_connector = intel_connector->dev_priv;
 
-       if (sdvo_priv->is_tv)
+       if (IS_TV(sdvo_connector))
                intel_sdvo_get_tv_modes(connector);
-       else if (sdvo_priv->is_lvds == true)
+       else if (IS_LVDS(sdvo_connector))
                intel_sdvo_get_lvds_modes(connector);
        else
                intel_sdvo_get_ddc_modes(connector);
@@ -1920,11 +1816,11 @@ static int intel_sdvo_get_modes(struct drm_connector *connector)
 static
 void intel_sdvo_destroy_enhance_property(struct drm_connector *connector)
 {
-       struct intel_encoder *intel_encoder = to_intel_encoder(connector);
-       struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv;
+       struct intel_connector *intel_connector = to_intel_connector(connector);
+       struct intel_sdvo_connector *sdvo_priv = intel_connector->dev_priv;
        struct drm_device *dev = connector->dev;
 
-       if (sdvo_priv->is_tv) {
+       if (IS_TV(sdvo_priv)) {
                if (sdvo_priv->left_property)
                        drm_property_destroy(dev, sdvo_priv->left_property);
                if (sdvo_priv->right_property)
@@ -1937,8 +1833,6 @@ void intel_sdvo_destroy_enhance_property(struct drm_connector *connector)
                        drm_property_destroy(dev, sdvo_priv->hpos_property);
                if (sdvo_priv->vpos_property)
                        drm_property_destroy(dev, sdvo_priv->vpos_property);
-       }
-       if (sdvo_priv->is_tv) {
                if (sdvo_priv->saturation_property)
                        drm_property_destroy(dev,
                                        sdvo_priv->saturation_property);
@@ -1948,7 +1842,7 @@ void intel_sdvo_destroy_enhance_property(struct drm_connector *connector)
                if (sdvo_priv->hue_property)
                        drm_property_destroy(dev, sdvo_priv->hue_property);
        }
-       if (sdvo_priv->is_tv || sdvo_priv->is_lvds) {
+       if (IS_TV(sdvo_priv) || IS_LVDS(sdvo_priv)) {
                if (sdvo_priv->brightness_property)
                        drm_property_destroy(dev,
                                        sdvo_priv->brightness_property);
@@ -1958,31 +1852,17 @@ void intel_sdvo_destroy_enhance_property(struct drm_connector *connector)
 
 static void intel_sdvo_destroy(struct drm_connector *connector)
 {
-       struct intel_encoder *intel_encoder = to_intel_encoder(connector);
-       struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv;
+       struct intel_connector *intel_connector = to_intel_connector(connector);
+       struct intel_sdvo_connector *sdvo_connector = intel_connector->dev_priv;
 
-       if (intel_encoder->i2c_bus)
-               intel_i2c_destroy(intel_encoder->i2c_bus);
-       if (intel_encoder->ddc_bus)
-               intel_i2c_destroy(intel_encoder->ddc_bus);
-       if (sdvo_priv->analog_ddc_bus)
-               intel_i2c_destroy(sdvo_priv->analog_ddc_bus);
-
-       if (sdvo_priv->sdvo_lvds_fixed_mode != NULL)
-               drm_mode_destroy(connector->dev,
-                                sdvo_priv->sdvo_lvds_fixed_mode);
-
-       if (sdvo_priv->tv_format_property)
+       if (sdvo_connector->tv_format_property)
                drm_property_destroy(connector->dev,
-                                    sdvo_priv->tv_format_property);
-
-       if (sdvo_priv->is_tv || sdvo_priv->is_lvds)
-               intel_sdvo_destroy_enhance_property(connector);
+                                    sdvo_connector->tv_format_property);
 
+       intel_sdvo_destroy_enhance_property(connector);
        drm_sysfs_connector_remove(connector);
        drm_connector_cleanup(connector);
-
-       kfree(intel_encoder);
+       kfree(connector);
 }
 
 static int
@@ -1990,9 +1870,11 @@ intel_sdvo_set_property(struct drm_connector *connector,
                        struct drm_property *property,
                        uint64_t val)
 {
-       struct intel_encoder *intel_encoder = to_intel_encoder(connector);
+       struct drm_encoder *encoder = intel_attached_encoder(connector);
+       struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
        struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv;
-       struct drm_encoder *encoder = &intel_encoder->enc;
+       struct intel_connector *intel_connector = to_intel_connector(connector);
+       struct intel_sdvo_connector *sdvo_connector = intel_connector->dev_priv;
        struct drm_crtc *crtc = encoder->crtc;
        int ret = 0;
        bool changed = false;
@@ -2003,101 +1885,101 @@ intel_sdvo_set_property(struct drm_connector *connector,
        if (ret < 0)
                goto out;
 
-       if (property == sdvo_priv->tv_format_property) {
+       if (property == sdvo_connector->tv_format_property) {
                if (val >= TV_FORMAT_NUM) {
                        ret = -EINVAL;
                        goto out;
                }
                if (sdvo_priv->tv_format_name ==
-                   sdvo_priv->tv_format_supported[val])
+                   sdvo_connector->tv_format_supported[val])
                        goto out;
 
-               sdvo_priv->tv_format_name = sdvo_priv->tv_format_supported[val];
+               sdvo_priv->tv_format_name = sdvo_connector->tv_format_supported[val];
                changed = true;
        }
 
-       if (sdvo_priv->is_tv || sdvo_priv->is_lvds) {
+       if (IS_TV(sdvo_connector) || IS_LVDS(sdvo_connector)) {
                cmd = 0;
                temp_value = val;
-               if (sdvo_priv->left_property == property) {
+               if (sdvo_connector->left_property == property) {
                        drm_connector_property_set_value(connector,
-                               sdvo_priv->right_property, val);
-                       if (sdvo_priv->left_margin == temp_value)
+                               sdvo_connector->right_property, val);
+                       if (sdvo_connector->left_margin == temp_value)
                                goto out;
 
-                       sdvo_priv->left_margin = temp_value;
-                       sdvo_priv->right_margin = temp_value;
-                       temp_value = sdvo_priv->max_hscan -
-                                       sdvo_priv->left_margin;
+                       sdvo_connector->left_margin = temp_value;
+                       sdvo_connector->right_margin = temp_value;
+                       temp_value = sdvo_connector->max_hscan -
+                                       sdvo_connector->left_margin;
                        cmd = SDVO_CMD_SET_OVERSCAN_H;
-               } else if (sdvo_priv->right_property == property) {
+               } else if (sdvo_connector->right_property == property) {
                        drm_connector_property_set_value(connector,
-                               sdvo_priv->left_property, val);
-                       if (sdvo_priv->right_margin == temp_value)
+                               sdvo_connector->left_property, val);
+                       if (sdvo_connector->right_margin == temp_value)
                                goto out;
 
-                       sdvo_priv->left_margin = temp_value;
-                       sdvo_priv->right_margin = temp_value;
-                       temp_value = sdvo_priv->max_hscan -
-                               sdvo_priv->left_margin;
+                       sdvo_connector->left_margin = temp_value;
+                       sdvo_connector->right_margin = temp_value;
+                       temp_value = sdvo_connector->max_hscan -
+                               sdvo_connector->left_margin;
                        cmd = SDVO_CMD_SET_OVERSCAN_H;
-               } else if (sdvo_priv->top_property == property) {
+               } else if (sdvo_connector->top_property == property) {
                        drm_connector_property_set_value(connector,
-                               sdvo_priv->bottom_property, val);
-                       if (sdvo_priv->top_margin == temp_value)
+                               sdvo_connector->bottom_property, val);
+                       if (sdvo_connector->top_margin == temp_value)
                                goto out;
 
-                       sdvo_priv->top_margin = temp_value;
-                       sdvo_priv->bottom_margin = temp_value;
-                       temp_value = sdvo_priv->max_vscan -
-                                       sdvo_priv->top_margin;
+                       sdvo_connector->top_margin = temp_value;
+                       sdvo_connector->bottom_margin = temp_value;
+                       temp_value = sdvo_connector->max_vscan -
+                                       sdvo_connector->top_margin;
                        cmd = SDVO_CMD_SET_OVERSCAN_V;
-               } else if (sdvo_priv->bottom_property == property) {
+               } else if (sdvo_connector->bottom_property == property) {
                        drm_connector_property_set_value(connector,
-                               sdvo_priv->top_property, val);
-                       if (sdvo_priv->bottom_margin == temp_value)
+                               sdvo_connector->top_property, val);
+                       if (sdvo_connector->bottom_margin == temp_value)
                                goto out;
-                       sdvo_priv->top_margin = temp_value;
-                       sdvo_priv->bottom_margin = temp_value;
-                       temp_value = sdvo_priv->max_vscan -
-                                       sdvo_priv->top_margin;
+                       sdvo_connector->top_margin = temp_value;
+                       sdvo_connector->bottom_margin = temp_value;
+                       temp_value = sdvo_connector->max_vscan -
+                                       sdvo_connector->top_margin;
                        cmd = SDVO_CMD_SET_OVERSCAN_V;
-               } else if (sdvo_priv->hpos_property == property) {
-                       if (sdvo_priv->cur_hpos == temp_value)
+               } else if (sdvo_connector->hpos_property == property) {
+                       if (sdvo_connector->cur_hpos == temp_value)
                                goto out;
 
                        cmd = SDVO_CMD_SET_POSITION_H;
-                       sdvo_priv->cur_hpos = temp_value;
-               } else if (sdvo_priv->vpos_property == property) {
-                       if (sdvo_priv->cur_vpos == temp_value)
+                       sdvo_connector->cur_hpos = temp_value;
+               } else if (sdvo_connector->vpos_property == property) {
+                       if (sdvo_connector->cur_vpos == temp_value)
                                goto out;
 
                        cmd = SDVO_CMD_SET_POSITION_V;
-                       sdvo_priv->cur_vpos = temp_value;
-               } else if (sdvo_priv->saturation_property == property) {
-                       if (sdvo_priv->cur_saturation == temp_value)
+                       sdvo_connector->cur_vpos = temp_value;
+               } else if (sdvo_connector->saturation_property == property) {
+                       if (sdvo_connector->cur_saturation == temp_value)
                                goto out;
 
                        cmd = SDVO_CMD_SET_SATURATION;
-                       sdvo_priv->cur_saturation = temp_value;
-               } else if (sdvo_priv->contrast_property == property) {
-                       if (sdvo_priv->cur_contrast == temp_value)
+                       sdvo_connector->cur_saturation = temp_value;
+               } else if (sdvo_connector->contrast_property == property) {
+                       if (sdvo_connector->cur_contrast == temp_value)
                                goto out;
 
                        cmd = SDVO_CMD_SET_CONTRAST;
-                       sdvo_priv->cur_contrast = temp_value;
-               } else if (sdvo_priv->hue_property == property) {
-                       if (sdvo_priv->cur_hue == temp_value)
+                       sdvo_connector->cur_contrast = temp_value;
+               } else if (sdvo_connector->hue_property == property) {
+                       if (sdvo_connector->cur_hue == temp_value)
                                goto out;
 
                        cmd = SDVO_CMD_SET_HUE;
-                       sdvo_priv->cur_hue = temp_value;
-               } else if (sdvo_priv->brightness_property == property) {
-                       if (sdvo_priv->cur_brightness == temp_value)
+                       sdvo_connector->cur_hue = temp_value;
+               } else if (sdvo_connector->brightness_property == property) {
+                       if (sdvo_connector->cur_brightness == temp_value)
                                goto out;
 
                        cmd = SDVO_CMD_SET_BRIGHTNESS;
-                       sdvo_priv->cur_brightness = temp_value;
+                       sdvo_connector->cur_brightness = temp_value;
                }
                if (cmd) {
                        intel_sdvo_write_cmd(intel_encoder, cmd, &temp_value, 2);
@@ -2127,8 +2009,6 @@ static const struct drm_encoder_helper_funcs intel_sdvo_helper_funcs = {
 
 static const struct drm_connector_funcs intel_sdvo_connector_funcs = {
        .dpms = drm_helper_connector_dpms,
-       .save = intel_sdvo_save,
-       .restore = intel_sdvo_restore,
        .detect = intel_sdvo_detect,
        .fill_modes = drm_helper_probe_single_connector_modes,
        .set_property = intel_sdvo_set_property,
@@ -2138,12 +2018,27 @@ static const struct drm_connector_funcs intel_sdvo_connector_funcs = {
 static const struct drm_connector_helper_funcs intel_sdvo_connector_helper_funcs = {
        .get_modes = intel_sdvo_get_modes,
        .mode_valid = intel_sdvo_mode_valid,
-       .best_encoder = intel_best_encoder,
+       .best_encoder = intel_attached_encoder,
 };
 
 static void intel_sdvo_enc_destroy(struct drm_encoder *encoder)
 {
+       struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
+       struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv;
+
+       if (intel_encoder->i2c_bus)
+               intel_i2c_destroy(intel_encoder->i2c_bus);
+       if (intel_encoder->ddc_bus)
+               intel_i2c_destroy(intel_encoder->ddc_bus);
+       if (sdvo_priv->analog_ddc_bus)
+               intel_i2c_destroy(sdvo_priv->analog_ddc_bus);
+
+       if (sdvo_priv->sdvo_lvds_fixed_mode != NULL)
+               drm_mode_destroy(encoder->dev,
+                                sdvo_priv->sdvo_lvds_fixed_mode);
+
        drm_encoder_cleanup(encoder);
+       kfree(intel_encoder);
 }
 
 static const struct drm_encoder_funcs intel_sdvo_enc_funcs = {
@@ -2196,12 +2091,15 @@ intel_sdvo_select_ddc_bus(struct intel_sdvo_priv *dev_priv)
 }
 
 static bool
-intel_sdvo_get_digital_encoding_mode(struct intel_encoder *output)
+intel_sdvo_get_digital_encoding_mode(struct intel_encoder *output, int device)
 {
        struct intel_sdvo_priv *sdvo_priv = output->dev_priv;
        uint8_t status;
 
-       intel_sdvo_set_target_output(output, sdvo_priv->controlled_output);
+       if (device == 0)
+               intel_sdvo_set_target_output(output, SDVO_OUTPUT_TMDS0);
+       else
+               intel_sdvo_set_target_output(output, SDVO_OUTPUT_TMDS1);
 
        intel_sdvo_write_cmd(output, SDVO_CMD_GET_ENCODE, NULL, 0);
        status = intel_sdvo_read_response(output, &sdvo_priv->is_hdmi, 1);
@@ -2214,15 +2112,13 @@ static struct intel_encoder *
 intel_sdvo_chan_to_intel_encoder(struct intel_i2c_chan *chan)
 {
        struct drm_device *dev = chan->drm_dev;
-       struct drm_connector *connector;
+       struct drm_encoder *encoder;
        struct intel_encoder *intel_encoder = NULL;
 
-       list_for_each_entry(connector,
-                       &dev->mode_config.connector_list, head) {
-               if (to_intel_encoder(connector)->ddc_bus == &chan->adapter) {
-                       intel_encoder = to_intel_encoder(connector);
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+               intel_encoder = enc_to_intel_encoder(encoder);
+               if (intel_encoder->ddc_bus == &chan->adapter)
                        break;
-               }
        }
        return intel_encoder;
 }
@@ -2259,7 +2155,7 @@ intel_sdvo_get_slave_addr(struct drm_device *dev, int sdvo_reg)
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct sdvo_device_mapping *my_mapping, *other_mapping;
 
-       if (sdvo_reg == SDVOB) {
+       if (IS_SDVOB(sdvo_reg)) {
                my_mapping = &dev_priv->sdvo_mappings[0];
                other_mapping = &dev_priv->sdvo_mappings[1];
        } else {
@@ -2284,120 +2180,235 @@ intel_sdvo_get_slave_addr(struct drm_device *dev, int sdvo_reg)
        /* No SDVO device info is found for another DVO port,
         * so use mapping assumption we had before BIOS parsing.
         */
-       if (sdvo_reg == SDVOB)
+       if (IS_SDVOB(sdvo_reg))
                return 0x70;
        else
                return 0x72;
 }
 
-static int intel_sdvo_bad_tv_callback(const struct dmi_system_id *id)
+static bool
+intel_sdvo_connector_alloc (struct intel_connector **ret)
 {
-       DRM_DEBUG_KMS("Ignoring bad SDVO TV connector for %s\n", id->ident);
-       return 1;
+       struct intel_connector *intel_connector;
+       struct intel_sdvo_connector *sdvo_connector;
+
+       *ret = kzalloc(sizeof(*intel_connector) +
+                       sizeof(*sdvo_connector), GFP_KERNEL);
+       if (!*ret)
+               return false;
+
+       intel_connector = *ret;
+       sdvo_connector = (struct intel_sdvo_connector *)(intel_connector + 1);
+       intel_connector->dev_priv = sdvo_connector;
+
+       return true;
 }
 
-static struct dmi_system_id intel_sdvo_bad_tv[] = {
-       {
-               .callback = intel_sdvo_bad_tv_callback,
-               .ident = "IntelG45/ICH10R/DME1737",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "IBM CORPORATION"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "4800784"),
-               },
-       },
+static void
+intel_sdvo_connector_create (struct drm_encoder *encoder,
+                            struct drm_connector *connector)
+{
+       drm_connector_init(encoder->dev, connector, &intel_sdvo_connector_funcs,
+                          connector->connector_type);
 
-       { }     /* terminating entry */
-};
+       drm_connector_helper_add(connector, &intel_sdvo_connector_helper_funcs);
+
+       connector->interlace_allowed = 0;
+       connector->doublescan_allowed = 0;
+       connector->display_info.subpixel_order = SubPixelHorizontalRGB;
+
+       drm_mode_connector_attach_encoder(connector, encoder);
+       drm_sysfs_connector_add(connector);
+}
 
 static bool
-intel_sdvo_output_setup(struct intel_encoder *intel_encoder, uint16_t flags)
+intel_sdvo_dvi_init(struct intel_encoder *intel_encoder, int device)
 {
-       struct drm_connector *connector = &intel_encoder->base;
        struct drm_encoder *encoder = &intel_encoder->enc;
        struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv;
-       bool ret = true, registered = false;
+       struct drm_connector *connector;
+       struct intel_connector *intel_connector;
+       struct intel_sdvo_connector *sdvo_connector;
+
+       if (!intel_sdvo_connector_alloc(&intel_connector))
+               return false;
+
+       sdvo_connector = intel_connector->dev_priv;
+
+       if (device == 0) {
+               sdvo_priv->controlled_output |= SDVO_OUTPUT_TMDS0;
+               sdvo_connector->output_flag = SDVO_OUTPUT_TMDS0;
+       } else if (device == 1) {
+               sdvo_priv->controlled_output |= SDVO_OUTPUT_TMDS1;
+               sdvo_connector->output_flag = SDVO_OUTPUT_TMDS1;
+       }
+
+       connector = &intel_connector->base;
+       encoder->encoder_type = DRM_MODE_ENCODER_TMDS;
+       connector->connector_type = DRM_MODE_CONNECTOR_DVID;
+
+       if (intel_sdvo_get_supp_encode(intel_encoder, &sdvo_priv->encode)
+               && intel_sdvo_get_digital_encoding_mode(intel_encoder, device)
+               && sdvo_priv->is_hdmi) {
+               /* enable hdmi encoding mode if supported */
+               intel_sdvo_set_encode(intel_encoder, SDVO_ENCODE_HDMI);
+               intel_sdvo_set_colorimetry(intel_encoder,
+                                          SDVO_COLORIMETRY_RGB256);
+               connector->connector_type = DRM_MODE_CONNECTOR_HDMIA;
+       }
+       intel_encoder->clone_mask = (1 << INTEL_SDVO_NON_TV_CLONE_BIT) |
+                                   (1 << INTEL_ANALOG_CLONE_BIT);
+
+       intel_sdvo_connector_create(encoder, connector);
+
+       return true;
+}
+
+static bool
+intel_sdvo_tv_init(struct intel_encoder *intel_encoder, int type)
+{
+        struct drm_encoder *encoder = &intel_encoder->enc;
+        struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv;
+        struct drm_connector *connector;
+        struct intel_connector *intel_connector;
+        struct intel_sdvo_connector *sdvo_connector;
+
+        if (!intel_sdvo_connector_alloc(&intel_connector))
+                return false;
+
+        connector = &intel_connector->base;
+        encoder->encoder_type = DRM_MODE_ENCODER_TVDAC;
+        connector->connector_type = DRM_MODE_CONNECTOR_SVIDEO;
+        sdvo_connector = intel_connector->dev_priv;
+
+        sdvo_priv->controlled_output |= type;
+        sdvo_connector->output_flag = type;
+
+        sdvo_priv->is_tv = true;
+        intel_encoder->needs_tv_clock = true;
+        intel_encoder->clone_mask = 1 << INTEL_SDVO_TV_CLONE_BIT;
+
+        intel_sdvo_connector_create(encoder, connector);
+
+        intel_sdvo_tv_create_property(connector, type);
+
+        intel_sdvo_create_enhance_property(connector);
+
+        return true;
+}
+
+static bool
+intel_sdvo_analog_init(struct intel_encoder *intel_encoder, int device)
+{
+        struct drm_encoder *encoder = &intel_encoder->enc;
+        struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv;
+        struct drm_connector *connector;
+        struct intel_connector *intel_connector;
+        struct intel_sdvo_connector *sdvo_connector;
+
+        if (!intel_sdvo_connector_alloc(&intel_connector))
+                return false;
+
+        connector = &intel_connector->base;
+        encoder->encoder_type = DRM_MODE_ENCODER_DAC;
+        connector->connector_type = DRM_MODE_CONNECTOR_VGA;
+        sdvo_connector = intel_connector->dev_priv;
+
+        if (device == 0) {
+                sdvo_priv->controlled_output |= SDVO_OUTPUT_RGB0;
+                sdvo_connector->output_flag = SDVO_OUTPUT_RGB0;
+        } else if (device == 1) {
+                sdvo_priv->controlled_output |= SDVO_OUTPUT_RGB1;
+                sdvo_connector->output_flag = SDVO_OUTPUT_RGB1;
+        }
+
+        intel_encoder->clone_mask = (1 << INTEL_SDVO_NON_TV_CLONE_BIT) |
+                                    (1 << INTEL_ANALOG_CLONE_BIT);
+
+        intel_sdvo_connector_create(encoder, connector);
+        return true;
+}
+
+static bool
+intel_sdvo_lvds_init(struct intel_encoder *intel_encoder, int device)
+{
+        struct drm_encoder *encoder = &intel_encoder->enc;
+        struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv;
+        struct drm_connector *connector;
+        struct intel_connector *intel_connector;
+        struct intel_sdvo_connector *sdvo_connector;
+
+        if (!intel_sdvo_connector_alloc(&intel_connector))
+                return false;
+
+        connector = &intel_connector->base;
+        encoder->encoder_type = DRM_MODE_ENCODER_LVDS;
+        connector->connector_type = DRM_MODE_CONNECTOR_LVDS;
+        sdvo_connector = intel_connector->dev_priv;
+
+        sdvo_priv->is_lvds = true;
+
+        if (device == 0) {
+                sdvo_priv->controlled_output |= SDVO_OUTPUT_LVDS0;
+                sdvo_connector->output_flag = SDVO_OUTPUT_LVDS0;
+        } else if (device == 1) {
+                sdvo_priv->controlled_output |= SDVO_OUTPUT_LVDS1;
+                sdvo_connector->output_flag = SDVO_OUTPUT_LVDS1;
+        }
+
+        intel_encoder->clone_mask = (1 << INTEL_ANALOG_CLONE_BIT) |
+                                    (1 << INTEL_SDVO_LVDS_CLONE_BIT);
+
+        intel_sdvo_connector_create(encoder, connector);
+        intel_sdvo_create_enhance_property(connector);
+        return true;
+}
+
+static bool
+intel_sdvo_output_setup(struct intel_encoder *intel_encoder, uint16_t flags)
+{
+       struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv;
 
        sdvo_priv->is_tv = false;
        intel_encoder->needs_tv_clock = false;
        sdvo_priv->is_lvds = false;
 
-       if (device_is_registered(&connector->kdev)) {
-               drm_sysfs_connector_remove(connector);
-               registered = true;
-       }
+       /* SDVO requires XXX1 function may not exist unless it has XXX0 function.*/
 
-       if (flags &
-           (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_TMDS1)) {
-               if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_TMDS0)
-                       sdvo_priv->controlled_output = SDVO_OUTPUT_TMDS0;
-               else
-                       sdvo_priv->controlled_output = SDVO_OUTPUT_TMDS1;
-
-               encoder->encoder_type = DRM_MODE_ENCODER_TMDS;
-               connector->connector_type = DRM_MODE_CONNECTOR_DVID;
-
-               if (intel_sdvo_get_supp_encode(intel_encoder,
-                                              &sdvo_priv->encode) &&
-                   intel_sdvo_get_digital_encoding_mode(intel_encoder) &&
-                   sdvo_priv->is_hdmi) {
-                       /* enable hdmi encoding mode if supported */
-                       intel_sdvo_set_encode(intel_encoder, SDVO_ENCODE_HDMI);
-                       intel_sdvo_set_colorimetry(intel_encoder,
-                                                  SDVO_COLORIMETRY_RGB256);
-                       connector->connector_type = DRM_MODE_CONNECTOR_HDMIA;
-                       intel_encoder->clone_mask =
-                                       (1 << INTEL_SDVO_NON_TV_CLONE_BIT) |
-                                       (1 << INTEL_ANALOG_CLONE_BIT);
-               }
-       } else if ((flags & SDVO_OUTPUT_SVID0) &&
-                  !dmi_check_system(intel_sdvo_bad_tv)) {
-
-               sdvo_priv->controlled_output = SDVO_OUTPUT_SVID0;
-               encoder->encoder_type = DRM_MODE_ENCODER_TVDAC;
-               connector->connector_type = DRM_MODE_CONNECTOR_SVIDEO;
-               sdvo_priv->is_tv = true;
-               intel_encoder->needs_tv_clock = true;
-               intel_encoder->clone_mask = 1 << INTEL_SDVO_TV_CLONE_BIT;
-       } else if (flags & SDVO_OUTPUT_RGB0) {
-
-               sdvo_priv->controlled_output = SDVO_OUTPUT_RGB0;
-               encoder->encoder_type = DRM_MODE_ENCODER_DAC;
-               connector->connector_type = DRM_MODE_CONNECTOR_VGA;
-               intel_encoder->clone_mask = (1 << INTEL_SDVO_NON_TV_CLONE_BIT) |
-                                       (1 << INTEL_ANALOG_CLONE_BIT);
-       } else if (flags & SDVO_OUTPUT_RGB1) {
-
-               sdvo_priv->controlled_output = SDVO_OUTPUT_RGB1;
-               encoder->encoder_type = DRM_MODE_ENCODER_DAC;
-               connector->connector_type = DRM_MODE_CONNECTOR_VGA;
-               intel_encoder->clone_mask = (1 << INTEL_SDVO_NON_TV_CLONE_BIT) |
-                                       (1 << INTEL_ANALOG_CLONE_BIT);
-       } else if (flags & SDVO_OUTPUT_CVBS0) {
-
-               sdvo_priv->controlled_output = SDVO_OUTPUT_CVBS0;
-               encoder->encoder_type = DRM_MODE_ENCODER_TVDAC;
-               connector->connector_type = DRM_MODE_CONNECTOR_SVIDEO;
-               sdvo_priv->is_tv = true;
-               intel_encoder->needs_tv_clock = true;
-               intel_encoder->clone_mask = 1 << INTEL_SDVO_TV_CLONE_BIT;
-       } else if (flags & SDVO_OUTPUT_LVDS0) {
-
-               sdvo_priv->controlled_output = SDVO_OUTPUT_LVDS0;
-               encoder->encoder_type = DRM_MODE_ENCODER_LVDS;
-               connector->connector_type = DRM_MODE_CONNECTOR_LVDS;
-               sdvo_priv->is_lvds = true;
-               intel_encoder->clone_mask = (1 << INTEL_ANALOG_CLONE_BIT) |
-                                       (1 << INTEL_SDVO_LVDS_CLONE_BIT);
-       } else if (flags & SDVO_OUTPUT_LVDS1) {
-
-               sdvo_priv->controlled_output = SDVO_OUTPUT_LVDS1;
-               encoder->encoder_type = DRM_MODE_ENCODER_LVDS;
-               connector->connector_type = DRM_MODE_CONNECTOR_LVDS;
-               sdvo_priv->is_lvds = true;
-               intel_encoder->clone_mask = (1 << INTEL_ANALOG_CLONE_BIT) |
-                                       (1 << INTEL_SDVO_LVDS_CLONE_BIT);
-       } else {
+       if (flags & SDVO_OUTPUT_TMDS0)
+               if (!intel_sdvo_dvi_init(intel_encoder, 0))
+                       return false;
+
+       if ((flags & SDVO_TMDS_MASK) == SDVO_TMDS_MASK)
+               if (!intel_sdvo_dvi_init(intel_encoder, 1))
+                       return false;
+
+       /* TV has no XXX1 function block */
+       if (flags & SDVO_OUTPUT_SVID0)
+               if (!intel_sdvo_tv_init(intel_encoder, SDVO_OUTPUT_SVID0))
+                       return false;
+
+       if (flags & SDVO_OUTPUT_CVBS0)
+               if (!intel_sdvo_tv_init(intel_encoder, SDVO_OUTPUT_CVBS0))
+                       return false;
 
+       if (flags & SDVO_OUTPUT_RGB0)
+               if (!intel_sdvo_analog_init(intel_encoder, 0))
+                       return false;
+
+       if ((flags & SDVO_RGB_MASK) == SDVO_RGB_MASK)
+               if (!intel_sdvo_analog_init(intel_encoder, 1))
+                       return false;
+
+       if (flags & SDVO_OUTPUT_LVDS0)
+               if (!intel_sdvo_lvds_init(intel_encoder, 0))
+                       return false;
+
+       if ((flags & SDVO_LVDS_MASK) == SDVO_LVDS_MASK)
+               if (!intel_sdvo_lvds_init(intel_encoder, 1))
+                       return false;
+
+       if ((flags & SDVO_OUTPUT_MASK) == 0) {
                unsigned char bytes[2];
 
                sdvo_priv->controlled_output = 0;
@@ -2405,28 +2416,25 @@ intel_sdvo_output_setup(struct intel_encoder *intel_encoder, uint16_t flags)
                DRM_DEBUG_KMS("%s: Unknown SDVO output type (0x%02x%02x)\n",
                              SDVO_NAME(sdvo_priv),
                              bytes[0], bytes[1]);
-               ret = false;
+               return false;
        }
        intel_encoder->crtc_mask = (1 << 0) | (1 << 1);
 
-       if (ret && registered)
-               ret = drm_sysfs_connector_add(connector) == 0 ? true : false;
-
-
-       return ret;
-
+       return true;
 }
 
-static void intel_sdvo_tv_create_property(struct drm_connector *connector)
+static void intel_sdvo_tv_create_property(struct drm_connector *connector, int type)
 {
-      struct intel_encoder *intel_encoder = to_intel_encoder(connector);
+       struct drm_encoder *encoder = intel_attached_encoder(connector);
+       struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
        struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv;
+       struct intel_connector *intel_connector = to_intel_connector(connector);
+       struct intel_sdvo_connector *sdvo_connector = intel_connector->dev_priv;
        struct intel_sdvo_tv_format format;
        uint32_t format_map, i;
        uint8_t status;
 
-       intel_sdvo_set_target_output(intel_encoder,
-                                    sdvo_priv->controlled_output);
+       intel_sdvo_set_target_output(intel_encoder, type);
 
        intel_sdvo_write_cmd(intel_encoder,
                             SDVO_CMD_GET_SUPPORTED_TV_FORMATS, NULL, 0);
@@ -2441,35 +2449,37 @@ static void intel_sdvo_tv_create_property(struct drm_connector *connector)
        if (format_map == 0)
                return;
 
-       sdvo_priv->format_supported_num = 0;
+       sdvo_connector->format_supported_num = 0;
        for (i = 0 ; i < TV_FORMAT_NUM; i++)
                if (format_map & (1 << i)) {
-                       sdvo_priv->tv_format_supported
-                       [sdvo_priv->format_supported_num++] =
+                       sdvo_connector->tv_format_supported
+                       [sdvo_connector->format_supported_num++] =
                        tv_format_names[i];
                }
 
 
-       sdvo_priv->tv_format_property =
+       sdvo_connector->tv_format_property =
                        drm_property_create(
                                connector->dev, DRM_MODE_PROP_ENUM,
-                               "mode", sdvo_priv->format_supported_num);
+                               "mode", sdvo_connector->format_supported_num);
 
-       for (i = 0; i < sdvo_priv->format_supported_num; i++)
+       for (i = 0; i < sdvo_connector->format_supported_num; i++)
                drm_property_add_enum(
-                               sdvo_priv->tv_format_property, i,
-                               i, sdvo_priv->tv_format_supported[i]);
+                               sdvo_connector->tv_format_property, i,
+                               i, sdvo_connector->tv_format_supported[i]);
 
-       sdvo_priv->tv_format_name = sdvo_priv->tv_format_supported[0];
+       sdvo_priv->tv_format_name = sdvo_connector->tv_format_supported[0];
        drm_connector_attach_property(
-                       connector, sdvo_priv->tv_format_property, 0);
+                       connector, sdvo_connector->tv_format_property, 0);
 
 }
 
 static void intel_sdvo_create_enhance_property(struct drm_connector *connector)
 {
-       struct intel_encoder *intel_encoder = to_intel_encoder(connector);
-       struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv;
+       struct drm_encoder *encoder = intel_attached_encoder(connector);
+       struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
+       struct intel_connector *intel_connector = to_intel_connector(connector);
+       struct intel_sdvo_connector *sdvo_priv = intel_connector->dev_priv;
        struct intel_sdvo_enhancements_reply sdvo_data;
        struct drm_device *dev = connector->dev;
        uint8_t status;
@@ -2488,7 +2498,7 @@ static void intel_sdvo_create_enhance_property(struct drm_connector *connector)
                DRM_DEBUG_KMS("No enhancement is supported\n");
                return;
        }
-       if (sdvo_priv->is_tv) {
+       if (IS_TV(sdvo_priv)) {
                /* when horizontal overscan is supported, Add the left/right
                 * property
                 */
@@ -2636,8 +2646,6 @@ static void intel_sdvo_create_enhance_property(struct drm_connector *connector)
                                        "default %d, current %d\n",
                                        data_value[0], data_value[1], response);
                }
-       }
-       if (sdvo_priv->is_tv) {
                if (sdvo_data.saturation) {
                        intel_sdvo_write_cmd(intel_encoder,
                                SDVO_CMD_GET_MAX_SATURATION, NULL, 0);
@@ -2733,7 +2741,7 @@ static void intel_sdvo_create_enhance_property(struct drm_connector *connector)
                                        data_value[0], data_value[1], response);
                }
        }
-       if (sdvo_priv->is_tv || sdvo_priv->is_lvds) {
+       if (IS_TV(sdvo_priv) || IS_LVDS(sdvo_priv)) {
                if (sdvo_data.brightness) {
                        intel_sdvo_write_cmd(intel_encoder,
                                SDVO_CMD_GET_MAX_BRIGHTNESS, NULL, 0);
@@ -2773,12 +2781,11 @@ static void intel_sdvo_create_enhance_property(struct drm_connector *connector)
 bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct drm_connector *connector;
        struct intel_encoder *intel_encoder;
        struct intel_sdvo_priv *sdvo_priv;
-
        u8 ch[0x40];
        int i;
+       u32 i2c_reg, ddc_reg, analog_ddc_reg;
 
        intel_encoder = kcalloc(sizeof(struct intel_encoder)+sizeof(struct intel_sdvo_priv), 1, GFP_KERNEL);
        if (!intel_encoder) {
@@ -2791,11 +2798,21 @@ bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg)
        intel_encoder->dev_priv = sdvo_priv;
        intel_encoder->type = INTEL_OUTPUT_SDVO;
 
+       if (HAS_PCH_SPLIT(dev)) {
+               i2c_reg = PCH_GPIOE;
+               ddc_reg = PCH_GPIOE;
+               analog_ddc_reg = PCH_GPIOA;
+       } else {
+               i2c_reg = GPIOE;
+               ddc_reg = GPIOE;
+               analog_ddc_reg = GPIOA;
+       }
+
        /* setup the DDC bus. */
-       if (sdvo_reg == SDVOB)
-               intel_encoder->i2c_bus = intel_i2c_create(dev, GPIOE, "SDVOCTRL_E for SDVOB");
+       if (IS_SDVOB(sdvo_reg))
+               intel_encoder->i2c_bus = intel_i2c_create(dev, i2c_reg, "SDVOCTRL_E for SDVOB");
        else
-               intel_encoder->i2c_bus = intel_i2c_create(dev, GPIOE, "SDVOCTRL_E for SDVOC");
+               intel_encoder->i2c_bus = intel_i2c_create(dev, i2c_reg, "SDVOCTRL_E for SDVOC");
 
        if (!intel_encoder->i2c_bus)
                goto err_inteloutput;
@@ -2809,20 +2826,20 @@ bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg)
        for (i = 0; i < 0x40; i++) {
                if (!intel_sdvo_read_byte(intel_encoder, i, &ch[i])) {
                        DRM_DEBUG_KMS("No SDVO device found on SDVO%c\n",
-                                       sdvo_reg == SDVOB ? 'B' : 'C');
+                                     IS_SDVOB(sdvo_reg) ? 'B' : 'C');
                        goto err_i2c;
                }
        }
 
        /* setup the DDC bus. */
-       if (sdvo_reg == SDVOB) {
-               intel_encoder->ddc_bus = intel_i2c_create(dev, GPIOE, "SDVOB DDC BUS");
-               sdvo_priv->analog_ddc_bus = intel_i2c_create(dev, GPIOA,
+       if (IS_SDVOB(sdvo_reg)) {
+               intel_encoder->ddc_bus = intel_i2c_create(dev, ddc_reg, "SDVOB DDC BUS");
+               sdvo_priv->analog_ddc_bus = intel_i2c_create(dev, analog_ddc_reg,
                                                "SDVOB/VGA DDC BUS");
                dev_priv->hotplug_supported_mask |= SDVOB_HOTPLUG_INT_STATUS;
        } else {
-               intel_encoder->ddc_bus = intel_i2c_create(dev, GPIOE, "SDVOC DDC BUS");
-               sdvo_priv->analog_ddc_bus = intel_i2c_create(dev, GPIOA,
+               intel_encoder->ddc_bus = intel_i2c_create(dev, ddc_reg, "SDVOC DDC BUS");
+               sdvo_priv->analog_ddc_bus = intel_i2c_create(dev, analog_ddc_reg,
                                                "SDVOC/VGA DDC BUS");
                dev_priv->hotplug_supported_mask |= SDVOC_HOTPLUG_INT_STATUS;
        }
@@ -2833,40 +2850,20 @@ bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg)
        /* Wrap with our custom algo which switches to DDC mode */
        intel_encoder->ddc_bus->algo = &intel_sdvo_i2c_bit_algo;
 
+       /* encoder type will be decided later */
+       drm_encoder_init(dev, &intel_encoder->enc, &intel_sdvo_enc_funcs, 0);
+       drm_encoder_helper_add(&intel_encoder->enc, &intel_sdvo_helper_funcs);
+
        /* In default case sdvo lvds is false */
        intel_sdvo_get_capabilities(intel_encoder, &sdvo_priv->caps);
 
        if (intel_sdvo_output_setup(intel_encoder,
                                    sdvo_priv->caps.output_flags) != true) {
                DRM_DEBUG_KMS("SDVO output failed to setup on SDVO%c\n",
-                         sdvo_reg == SDVOB ? 'B' : 'C');
+                             IS_SDVOB(sdvo_reg) ? 'B' : 'C');
                goto err_i2c;
        }
 
-
-       connector = &intel_encoder->base;
-       drm_connector_init(dev, connector, &intel_sdvo_connector_funcs,
-                          connector->connector_type);
-
-       drm_connector_helper_add(connector, &intel_sdvo_connector_helper_funcs);
-       connector->interlace_allowed = 0;
-       connector->doublescan_allowed = 0;
-       connector->display_info.subpixel_order = SubPixelHorizontalRGB;
-
-       drm_encoder_init(dev, &intel_encoder->enc,
-                       &intel_sdvo_enc_funcs, intel_encoder->enc.encoder_type);
-
-       drm_encoder_helper_add(&intel_encoder->enc, &intel_sdvo_helper_funcs);
-
-       drm_mode_connector_attach_encoder(&intel_encoder->base, &intel_encoder->enc);
-       if (sdvo_priv->is_tv)
-               intel_sdvo_tv_create_property(connector);
-
-       if (sdvo_priv->is_tv || sdvo_priv->is_lvds)
-               intel_sdvo_create_enhance_property(connector);
-
-       drm_sysfs_connector_add(connector);
-
        intel_sdvo_select_ddc_bus(sdvo_priv);
 
        /* Set the input timing to the screen. Assume always input 0. */
index d7d39b2..081cb90 100644 (file)
@@ -916,143 +916,6 @@ intel_tv_dpms(struct drm_encoder *encoder, int mode)
        }
 }
 
-static void
-intel_tv_save(struct drm_connector *connector)
-{
-       struct drm_device *dev = connector->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_encoder *intel_encoder = to_intel_encoder(connector);
-       struct intel_tv_priv *tv_priv = intel_encoder->dev_priv;
-       int i;
-
-       tv_priv->save_TV_H_CTL_1 = I915_READ(TV_H_CTL_1);
-       tv_priv->save_TV_H_CTL_2 = I915_READ(TV_H_CTL_2);
-       tv_priv->save_TV_H_CTL_3 = I915_READ(TV_H_CTL_3);
-       tv_priv->save_TV_V_CTL_1 = I915_READ(TV_V_CTL_1);
-       tv_priv->save_TV_V_CTL_2 = I915_READ(TV_V_CTL_2);
-       tv_priv->save_TV_V_CTL_3 = I915_READ(TV_V_CTL_3);
-       tv_priv->save_TV_V_CTL_4 = I915_READ(TV_V_CTL_4);
-       tv_priv->save_TV_V_CTL_5 = I915_READ(TV_V_CTL_5);
-       tv_priv->save_TV_V_CTL_6 = I915_READ(TV_V_CTL_6);
-       tv_priv->save_TV_V_CTL_7 = I915_READ(TV_V_CTL_7);
-       tv_priv->save_TV_SC_CTL_1 = I915_READ(TV_SC_CTL_1);
-       tv_priv->save_TV_SC_CTL_2 = I915_READ(TV_SC_CTL_2);
-       tv_priv->save_TV_SC_CTL_3 = I915_READ(TV_SC_CTL_3);
-
-       tv_priv->save_TV_CSC_Y = I915_READ(TV_CSC_Y);
-       tv_priv->save_TV_CSC_Y2 = I915_READ(TV_CSC_Y2);
-       tv_priv->save_TV_CSC_U = I915_READ(TV_CSC_U);
-       tv_priv->save_TV_CSC_U2 = I915_READ(TV_CSC_U2);
-       tv_priv->save_TV_CSC_V = I915_READ(TV_CSC_V);
-       tv_priv->save_TV_CSC_V2 = I915_READ(TV_CSC_V2);
-       tv_priv->save_TV_CLR_KNOBS = I915_READ(TV_CLR_KNOBS);
-       tv_priv->save_TV_CLR_LEVEL = I915_READ(TV_CLR_LEVEL);
-       tv_priv->save_TV_WIN_POS = I915_READ(TV_WIN_POS);
-       tv_priv->save_TV_WIN_SIZE = I915_READ(TV_WIN_SIZE);
-       tv_priv->save_TV_FILTER_CTL_1 = I915_READ(TV_FILTER_CTL_1);
-       tv_priv->save_TV_FILTER_CTL_2 = I915_READ(TV_FILTER_CTL_2);
-       tv_priv->save_TV_FILTER_CTL_3 = I915_READ(TV_FILTER_CTL_3);
-
-       for (i = 0; i < 60; i++)
-               tv_priv->save_TV_H_LUMA[i] = I915_READ(TV_H_LUMA_0 + (i <<2));
-       for (i = 0; i < 60; i++)
-               tv_priv->save_TV_H_CHROMA[i] = I915_READ(TV_H_CHROMA_0 + (i <<2));
-       for (i = 0; i < 43; i++)
-               tv_priv->save_TV_V_LUMA[i] = I915_READ(TV_V_LUMA_0 + (i <<2));
-       for (i = 0; i < 43; i++)
-               tv_priv->save_TV_V_CHROMA[i] = I915_READ(TV_V_CHROMA_0 + (i <<2));
-
-       tv_priv->save_TV_DAC = I915_READ(TV_DAC);
-       tv_priv->save_TV_CTL = I915_READ(TV_CTL);
-}
-
-static void
-intel_tv_restore(struct drm_connector *connector)
-{
-       struct drm_device *dev = connector->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_encoder *intel_encoder = to_intel_encoder(connector);
-       struct intel_tv_priv *tv_priv = intel_encoder->dev_priv;
-       struct drm_crtc *crtc = connector->encoder->crtc;
-       struct intel_crtc *intel_crtc;
-       int i;
-
-       /* FIXME: No CRTC? */
-       if (!crtc)
-               return;
-
-       intel_crtc = to_intel_crtc(crtc);
-       I915_WRITE(TV_H_CTL_1, tv_priv->save_TV_H_CTL_1);
-       I915_WRITE(TV_H_CTL_2, tv_priv->save_TV_H_CTL_2);
-       I915_WRITE(TV_H_CTL_3, tv_priv->save_TV_H_CTL_3);
-       I915_WRITE(TV_V_CTL_1, tv_priv->save_TV_V_CTL_1);
-       I915_WRITE(TV_V_CTL_2, tv_priv->save_TV_V_CTL_2);
-       I915_WRITE(TV_V_CTL_3, tv_priv->save_TV_V_CTL_3);
-       I915_WRITE(TV_V_CTL_4, tv_priv->save_TV_V_CTL_4);
-       I915_WRITE(TV_V_CTL_5, tv_priv->save_TV_V_CTL_5);
-       I915_WRITE(TV_V_CTL_6, tv_priv->save_TV_V_CTL_6);
-       I915_WRITE(TV_V_CTL_7, tv_priv->save_TV_V_CTL_7);
-       I915_WRITE(TV_SC_CTL_1, tv_priv->save_TV_SC_CTL_1);
-       I915_WRITE(TV_SC_CTL_2, tv_priv->save_TV_SC_CTL_2);
-       I915_WRITE(TV_SC_CTL_3, tv_priv->save_TV_SC_CTL_3);
-
-       I915_WRITE(TV_CSC_Y, tv_priv->save_TV_CSC_Y);
-       I915_WRITE(TV_CSC_Y2, tv_priv->save_TV_CSC_Y2);
-       I915_WRITE(TV_CSC_U, tv_priv->save_TV_CSC_U);
-       I915_WRITE(TV_CSC_U2, tv_priv->save_TV_CSC_U2);
-       I915_WRITE(TV_CSC_V, tv_priv->save_TV_CSC_V);
-       I915_WRITE(TV_CSC_V2, tv_priv->save_TV_CSC_V2);
-       I915_WRITE(TV_CLR_KNOBS, tv_priv->save_TV_CLR_KNOBS);
-       I915_WRITE(TV_CLR_LEVEL, tv_priv->save_TV_CLR_LEVEL);
-
-       {
-               int pipeconf_reg = (intel_crtc->pipe == 0) ?
-                       PIPEACONF : PIPEBCONF;
-               int dspcntr_reg = (intel_crtc->plane == 0) ?
-                       DSPACNTR : DSPBCNTR;
-               int pipeconf = I915_READ(pipeconf_reg);
-               int dspcntr = I915_READ(dspcntr_reg);
-               int dspbase_reg = (intel_crtc->plane == 0) ?
-                       DSPAADDR : DSPBADDR;
-               /* Pipe must be off here */
-               I915_WRITE(dspcntr_reg, dspcntr & ~DISPLAY_PLANE_ENABLE);
-               /* Flush the plane changes */
-               I915_WRITE(dspbase_reg, I915_READ(dspbase_reg));
-
-               if (!IS_I9XX(dev)) {
-                       /* Wait for vblank for the disable to take effect */
-                       intel_wait_for_vblank(dev);
-               }
-
-               I915_WRITE(pipeconf_reg, pipeconf & ~PIPEACONF_ENABLE);
-               /* Wait for vblank for the disable to take effect. */
-               intel_wait_for_vblank(dev);
-
-               /* Filter ctl must be set before TV_WIN_SIZE */
-               I915_WRITE(TV_FILTER_CTL_1, tv_priv->save_TV_FILTER_CTL_1);
-               I915_WRITE(TV_FILTER_CTL_2, tv_priv->save_TV_FILTER_CTL_2);
-               I915_WRITE(TV_FILTER_CTL_3, tv_priv->save_TV_FILTER_CTL_3);
-               I915_WRITE(TV_WIN_POS, tv_priv->save_TV_WIN_POS);
-               I915_WRITE(TV_WIN_SIZE, tv_priv->save_TV_WIN_SIZE);
-               I915_WRITE(pipeconf_reg, pipeconf);
-               I915_WRITE(dspcntr_reg, dspcntr);
-               /* Flush the plane changes */
-               I915_WRITE(dspbase_reg, I915_READ(dspbase_reg));
-       }
-
-       for (i = 0; i < 60; i++)
-               I915_WRITE(TV_H_LUMA_0 + (i <<2), tv_priv->save_TV_H_LUMA[i]);
-       for (i = 0; i < 60; i++)
-               I915_WRITE(TV_H_CHROMA_0 + (i <<2), tv_priv->save_TV_H_CHROMA[i]);
-       for (i = 0; i < 43; i++)
-               I915_WRITE(TV_V_LUMA_0 + (i <<2), tv_priv->save_TV_V_LUMA[i]);
-       for (i = 0; i < 43; i++)
-               I915_WRITE(TV_V_CHROMA_0 + (i <<2), tv_priv->save_TV_V_CHROMA[i]);
-
-       I915_WRITE(TV_DAC, tv_priv->save_TV_DAC);
-       I915_WRITE(TV_CTL, tv_priv->save_TV_CTL);
-}
-
 static const struct tv_mode *
 intel_tv_mode_lookup (char *tv_format)
 {
@@ -1078,7 +941,8 @@ intel_tv_mode_find (struct intel_encoder *intel_encoder)
 static enum drm_mode_status
 intel_tv_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode)
 {
-       struct intel_encoder *intel_encoder = to_intel_encoder(connector);
+       struct drm_encoder *encoder = intel_attached_encoder(connector);
+       struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
        const struct tv_mode *tv_mode = intel_tv_mode_find(intel_encoder);
 
        /* Ensure TV refresh is close to desired refresh */
@@ -1399,6 +1263,15 @@ intel_tv_detect_type (struct drm_crtc *crtc, struct intel_encoder *intel_encoder
                   DAC_A_0_7_V |
                   DAC_B_0_7_V |
                   DAC_C_0_7_V);
+
+       /*
+        * The TV sense state should be cleared to zero on cantiga platform. Otherwise
+        * the TV is misdetected. This is hardware requirement.
+        */
+       if (IS_GM45(dev))
+               tv_dac &= ~(TVDAC_STATE_CHG_EN | TVDAC_A_SENSE_CTL |
+                           TVDAC_B_SENSE_CTL | TVDAC_C_SENSE_CTL);
+
        I915_WRITE(TV_CTL, tv_ctl);
        I915_WRITE(TV_DAC, tv_dac);
        intel_wait_for_vblank(dev);
@@ -1441,7 +1314,8 @@ intel_tv_detect_type (struct drm_crtc *crtc, struct intel_encoder *intel_encoder
  */
 static void intel_tv_find_better_format(struct drm_connector *connector)
 {
-       struct intel_encoder *intel_encoder = to_intel_encoder(connector);
+       struct drm_encoder *encoder = intel_attached_encoder(connector);
+       struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
        struct intel_tv_priv *tv_priv = intel_encoder->dev_priv;
        const struct tv_mode *tv_mode = intel_tv_mode_find(intel_encoder);
        int i;
@@ -1475,9 +1349,9 @@ intel_tv_detect(struct drm_connector *connector)
 {
        struct drm_crtc *crtc;
        struct drm_display_mode mode;
-       struct intel_encoder *intel_encoder = to_intel_encoder(connector);
+       struct drm_encoder *encoder = intel_attached_encoder(connector);
+       struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
        struct intel_tv_priv *tv_priv = intel_encoder->dev_priv;
-       struct drm_encoder *encoder = &intel_encoder->enc;
        int dpms_mode;
        int type = tv_priv->type;
 
@@ -1487,10 +1361,12 @@ intel_tv_detect(struct drm_connector *connector)
        if (encoder->crtc && encoder->crtc->enabled) {
                type = intel_tv_detect_type(encoder->crtc, intel_encoder);
        } else {
-               crtc = intel_get_load_detect_pipe(intel_encoder, &mode, &dpms_mode);
+               crtc = intel_get_load_detect_pipe(intel_encoder, connector,
+                                                 &mode, &dpms_mode);
                if (crtc) {
                        type = intel_tv_detect_type(crtc, intel_encoder);
-                       intel_release_load_detect_pipe(intel_encoder, dpms_mode);
+                       intel_release_load_detect_pipe(intel_encoder, connector,
+                                                      dpms_mode);
                } else
                        type = -1;
        }
@@ -1525,7 +1401,8 @@ static void
 intel_tv_chose_preferred_modes(struct drm_connector *connector,
                               struct drm_display_mode *mode_ptr)
 {
-       struct intel_encoder *intel_encoder = to_intel_encoder(connector);
+       struct drm_encoder *encoder = intel_attached_encoder(connector);
+       struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
        const struct tv_mode *tv_mode = intel_tv_mode_find(intel_encoder);
 
        if (tv_mode->nbr_end < 480 && mode_ptr->vdisplay == 480)
@@ -1550,7 +1427,8 @@ static int
 intel_tv_get_modes(struct drm_connector *connector)
 {
        struct drm_display_mode *mode_ptr;
-       struct intel_encoder *intel_encoder = to_intel_encoder(connector);
+       struct drm_encoder *encoder = intel_attached_encoder(connector);
+       struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
        const struct tv_mode *tv_mode = intel_tv_mode_find(intel_encoder);
        int j, count = 0;
        u64 tmp;
@@ -1604,11 +1482,9 @@ intel_tv_get_modes(struct drm_connector *connector)
 static void
 intel_tv_destroy (struct drm_connector *connector)
 {
-       struct intel_encoder *intel_encoder = to_intel_encoder(connector);
-
        drm_sysfs_connector_remove(connector);
        drm_connector_cleanup(connector);
-       kfree(intel_encoder);
+       kfree(connector);
 }
 
 
@@ -1617,9 +1493,9 @@ intel_tv_set_property(struct drm_connector *connector, struct drm_property *prop
                      uint64_t val)
 {
        struct drm_device *dev = connector->dev;
-       struct intel_encoder *intel_encoder = to_intel_encoder(connector);
+       struct drm_encoder *encoder = intel_attached_encoder(connector);
+       struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
        struct intel_tv_priv *tv_priv = intel_encoder->dev_priv;
-       struct drm_encoder *encoder = &intel_encoder->enc;
        struct drm_crtc *crtc = encoder->crtc;
        int ret = 0;
        bool changed = false;
@@ -1676,8 +1552,6 @@ static const struct drm_encoder_helper_funcs intel_tv_helper_funcs = {
 
 static const struct drm_connector_funcs intel_tv_connector_funcs = {
        .dpms = drm_helper_connector_dpms,
-       .save = intel_tv_save,
-       .restore = intel_tv_restore,
        .detect = intel_tv_detect,
        .destroy = intel_tv_destroy,
        .set_property = intel_tv_set_property,
@@ -1687,12 +1561,15 @@ static const struct drm_connector_funcs intel_tv_connector_funcs = {
 static const struct drm_connector_helper_funcs intel_tv_connector_helper_funcs = {
        .mode_valid = intel_tv_mode_valid,
        .get_modes = intel_tv_get_modes,
-       .best_encoder = intel_best_encoder,
+       .best_encoder = intel_attached_encoder,
 };
 
 static void intel_tv_enc_destroy(struct drm_encoder *encoder)
 {
+       struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
+
        drm_encoder_cleanup(encoder);
+       kfree(intel_encoder);
 }
 
 static const struct drm_encoder_funcs intel_tv_enc_funcs = {
@@ -1741,6 +1618,7 @@ intel_tv_init(struct drm_device *dev)
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_connector *connector;
        struct intel_encoder *intel_encoder;
+       struct intel_connector *intel_connector;
        struct intel_tv_priv *tv_priv;
        u32 tv_dac_on, tv_dac_off, save_tv_dac;
        char **tv_format_names;
@@ -1786,7 +1664,13 @@ intel_tv_init(struct drm_device *dev)
                return;
        }
 
-       connector = &intel_encoder->base;
+       intel_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL);
+       if (!intel_connector) {
+               kfree(intel_encoder);
+               return;
+       }
+
+       connector = &intel_connector->base;
 
        drm_connector_init(dev, connector, &intel_tv_connector_funcs,
                           DRM_MODE_CONNECTOR_SVIDEO);
@@ -1794,7 +1678,7 @@ intel_tv_init(struct drm_device *dev)
        drm_encoder_init(dev, &intel_encoder->enc, &intel_tv_enc_funcs,
                         DRM_MODE_ENCODER_TVDAC);
 
-       drm_mode_connector_attach_encoder(&intel_encoder->base, &intel_encoder->enc);
+       drm_mode_connector_attach_encoder(&intel_connector->base, &intel_encoder->enc);
        tv_priv = (struct intel_tv_priv *)(intel_encoder + 1);
        intel_encoder->type = INTEL_OUTPUT_TVOUT;
        intel_encoder->crtc_mask = (1 << 0) | (1 << 1);