Browse Source

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/anholt/drm-intel

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/anholt/drm-intel:
  drm/i915: Select CONFIG_SHMEM
  drm/i915: Fix CRT hotplug detect by checking really no channels attached
  agp/intel: new host bridge support
  drm/i915: Add more registers save/restore for Ironlake suspend
  drm/i915: Fix IRQ stall issue on Ironlake
  drm/i915: HDMI hardware workaround for Ironlake
  drm/i915: Fix and cleanup DPLL calculation for Ironlake
  drm/i915: Avoid potential sleep whilst holding spinlock
Linus Torvalds 15 năm trước cách đây
mục cha
commit
9709652703

+ 7 - 1
drivers/char/agp/intel-agp.c

@@ -62,6 +62,7 @@
 #define PCI_DEVICE_ID_INTEL_IGDNG_D_IG	    0x0042
 #define PCI_DEVICE_ID_INTEL_IGDNG_D_IG	    0x0042
 #define PCI_DEVICE_ID_INTEL_IGDNG_M_HB	    0x0044
 #define PCI_DEVICE_ID_INTEL_IGDNG_M_HB	    0x0044
 #define PCI_DEVICE_ID_INTEL_IGDNG_MA_HB	    0x0062
 #define PCI_DEVICE_ID_INTEL_IGDNG_MA_HB	    0x0062
+#define PCI_DEVICE_ID_INTEL_IGDNG_MC2_HB    0x006a
 #define PCI_DEVICE_ID_INTEL_IGDNG_M_IG	    0x0046
 #define PCI_DEVICE_ID_INTEL_IGDNG_M_IG	    0x0046
 
 
 /* cover 915 and 945 variants */
 /* cover 915 and 945 variants */
@@ -96,7 +97,8 @@
 		agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_B43_HB || \
 		agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_B43_HB || \
 		agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IGDNG_D_HB || \
 		agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IGDNG_D_HB || \
 		agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IGDNG_M_HB || \
 		agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IGDNG_M_HB || \
-		agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IGDNG_MA_HB)
+		agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IGDNG_MA_HB || \
+		agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IGDNG_MC2_HB)
 
 
 extern int agp_memory_reserved;
 extern int agp_memory_reserved;
 
 
@@ -1358,6 +1360,7 @@ static void intel_i965_get_gtt_range(int *gtt_offset, int *gtt_size)
 	case PCI_DEVICE_ID_INTEL_IGDNG_D_HB:
 	case PCI_DEVICE_ID_INTEL_IGDNG_D_HB:
 	case PCI_DEVICE_ID_INTEL_IGDNG_M_HB:
 	case PCI_DEVICE_ID_INTEL_IGDNG_M_HB:
 	case PCI_DEVICE_ID_INTEL_IGDNG_MA_HB:
 	case PCI_DEVICE_ID_INTEL_IGDNG_MA_HB:
+	case PCI_DEVICE_ID_INTEL_IGDNG_MC2_HB:
 		*gtt_offset = *gtt_size = MB(2);
 		*gtt_offset = *gtt_size = MB(2);
 		break;
 		break;
 	default:
 	default:
@@ -2359,6 +2362,8 @@ static const struct intel_driver_description {
 	    "IGDNG/M", NULL, &intel_i965_driver },
 	    "IGDNG/M", NULL, &intel_i965_driver },
 	{ PCI_DEVICE_ID_INTEL_IGDNG_MA_HB, PCI_DEVICE_ID_INTEL_IGDNG_M_IG, 0,
 	{ PCI_DEVICE_ID_INTEL_IGDNG_MA_HB, PCI_DEVICE_ID_INTEL_IGDNG_M_IG, 0,
 	    "IGDNG/MA", NULL, &intel_i965_driver },
 	    "IGDNG/MA", NULL, &intel_i965_driver },
+	{ PCI_DEVICE_ID_INTEL_IGDNG_MC2_HB, PCI_DEVICE_ID_INTEL_IGDNG_M_IG, 0,
+	    "IGDNG/MC2", NULL, &intel_i965_driver },
 	{ 0, 0, 0, NULL, NULL, NULL }
 	{ 0, 0, 0, NULL, NULL, NULL }
 };
 };
 
 
@@ -2560,6 +2565,7 @@ static struct pci_device_id agp_intel_pci_table[] = {
 	ID(PCI_DEVICE_ID_INTEL_IGDNG_D_HB),
 	ID(PCI_DEVICE_ID_INTEL_IGDNG_D_HB),
 	ID(PCI_DEVICE_ID_INTEL_IGDNG_M_HB),
 	ID(PCI_DEVICE_ID_INTEL_IGDNG_M_HB),
 	ID(PCI_DEVICE_ID_INTEL_IGDNG_MA_HB),
 	ID(PCI_DEVICE_ID_INTEL_IGDNG_MA_HB),
+	ID(PCI_DEVICE_ID_INTEL_IGDNG_MC2_HB),
 	{ }
 	{ }
 };
 };
 
 

+ 1 - 0
drivers/gpu/drm/Kconfig

@@ -92,6 +92,7 @@ config DRM_I830
 config DRM_I915
 config DRM_I915
 	tristate "i915 driver"
 	tristate "i915 driver"
 	depends on AGP_INTEL
 	depends on AGP_INTEL
+	select SHMEM
 	select DRM_KMS_HELPER
 	select DRM_KMS_HELPER
 	select FB_CFB_FILLRECT
 	select FB_CFB_FILLRECT
 	select FB_CFB_COPYAREA
 	select FB_CFB_COPYAREA

+ 2 - 2
drivers/gpu/drm/i915/i915_debugfs.c

@@ -267,10 +267,10 @@ static void i915_dump_pages(struct seq_file *m, struct page **pages, int page_co
 	uint32_t *mem;
 	uint32_t *mem;
 
 
 	for (page = 0; page < page_count; page++) {
 	for (page = 0; page < page_count; page++) {
-		mem = kmap(pages[page]);
+		mem = kmap_atomic(pages[page], KM_USER0);
 		for (i = 0; i < PAGE_SIZE; i += 4)
 		for (i = 0; i < PAGE_SIZE; i += 4)
 			seq_printf(m, "%08x :  %08x\n", i, mem[i / 4]);
 			seq_printf(m, "%08x :  %08x\n", i, mem[i / 4]);
-		kunmap(pages[page]);
+		kunmap_atomic(pages[page], KM_USER0);
 	}
 	}
 }
 }
 
 

+ 12 - 0
drivers/gpu/drm/i915/i915_drv.h

@@ -296,6 +296,7 @@ typedef struct drm_i915_private {
 	u32 saveVBLANK_A;
 	u32 saveVBLANK_A;
 	u32 saveVSYNC_A;
 	u32 saveVSYNC_A;
 	u32 saveBCLRPAT_A;
 	u32 saveBCLRPAT_A;
+	u32 saveTRANSACONF;
 	u32 saveTRANS_HTOTAL_A;
 	u32 saveTRANS_HTOTAL_A;
 	u32 saveTRANS_HBLANK_A;
 	u32 saveTRANS_HBLANK_A;
 	u32 saveTRANS_HSYNC_A;
 	u32 saveTRANS_HSYNC_A;
@@ -326,6 +327,7 @@ typedef struct drm_i915_private {
 	u32 saveVBLANK_B;
 	u32 saveVBLANK_B;
 	u32 saveVSYNC_B;
 	u32 saveVSYNC_B;
 	u32 saveBCLRPAT_B;
 	u32 saveBCLRPAT_B;
+	u32 saveTRANSBCONF;
 	u32 saveTRANS_HTOTAL_B;
 	u32 saveTRANS_HTOTAL_B;
 	u32 saveTRANS_HBLANK_B;
 	u32 saveTRANS_HBLANK_B;
 	u32 saveTRANS_HSYNC_B;
 	u32 saveTRANS_HSYNC_B;
@@ -414,6 +416,16 @@ typedef struct drm_i915_private {
 	u32 savePFB_WIN_SZ;
 	u32 savePFB_WIN_SZ;
 	u32 savePFA_WIN_POS;
 	u32 savePFA_WIN_POS;
 	u32 savePFB_WIN_POS;
 	u32 savePFB_WIN_POS;
+	u32 savePCH_DREF_CONTROL;
+	u32 saveDISP_ARB_CTL;
+	u32 savePIPEA_DATA_M1;
+	u32 savePIPEA_DATA_N1;
+	u32 savePIPEA_LINK_M1;
+	u32 savePIPEA_LINK_N1;
+	u32 savePIPEB_DATA_M1;
+	u32 savePIPEB_DATA_N1;
+	u32 savePIPEB_LINK_M1;
+	u32 savePIPEB_LINK_N1;
 
 
 	struct {
 	struct {
 		struct drm_mm gtt_space;
 		struct drm_mm gtt_space;

+ 9 - 1
drivers/gpu/drm/i915/i915_irq.c

@@ -254,10 +254,15 @@ irqreturn_t igdng_irq_handler(struct drm_device *dev)
 {
 {
 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 	int ret = IRQ_NONE;
 	int ret = IRQ_NONE;
-	u32 de_iir, gt_iir;
+	u32 de_iir, gt_iir, de_ier;
 	u32 new_de_iir, new_gt_iir;
 	u32 new_de_iir, new_gt_iir;
 	struct drm_i915_master_private *master_priv;
 	struct drm_i915_master_private *master_priv;
 
 
+	/* disable master interrupt before clearing iir  */
+	de_ier = I915_READ(DEIER);
+	I915_WRITE(DEIER, de_ier & ~DE_MASTER_IRQ_CONTROL);
+	(void)I915_READ(DEIER);
+
 	de_iir = I915_READ(DEIIR);
 	de_iir = I915_READ(DEIIR);
 	gt_iir = I915_READ(GTIIR);
 	gt_iir = I915_READ(GTIIR);
 
 
@@ -290,6 +295,9 @@ irqreturn_t igdng_irq_handler(struct drm_device *dev)
 		gt_iir = new_gt_iir;
 		gt_iir = new_gt_iir;
 	}
 	}
 
 
+	I915_WRITE(DEIER, de_ier);
+	(void)I915_READ(DEIER);
+
 	return ret;
 	return ret;
 }
 }
 
 

+ 35 - 1
drivers/gpu/drm/i915/i915_suspend.c

@@ -239,6 +239,11 @@ static void i915_save_modeset_reg(struct drm_device *dev)
 	if (drm_core_check_feature(dev, DRIVER_MODESET))
 	if (drm_core_check_feature(dev, DRIVER_MODESET))
 		return;
 		return;
 
 
+	if (IS_IGDNG(dev)) {
+		dev_priv->savePCH_DREF_CONTROL = I915_READ(PCH_DREF_CONTROL);
+		dev_priv->saveDISP_ARB_CTL = I915_READ(DISP_ARB_CTL);
+	}
+
 	/* Pipe & plane A info */
 	/* Pipe & plane A info */
 	dev_priv->savePIPEACONF = I915_READ(PIPEACONF);
 	dev_priv->savePIPEACONF = I915_READ(PIPEACONF);
 	dev_priv->savePIPEASRC = I915_READ(PIPEASRC);
 	dev_priv->savePIPEASRC = I915_READ(PIPEASRC);
@@ -263,6 +268,11 @@ static void i915_save_modeset_reg(struct drm_device *dev)
 		dev_priv->saveBCLRPAT_A = I915_READ(BCLRPAT_A);
 		dev_priv->saveBCLRPAT_A = I915_READ(BCLRPAT_A);
 
 
 	if (IS_IGDNG(dev)) {
 	if (IS_IGDNG(dev)) {
+		dev_priv->savePIPEA_DATA_M1 = I915_READ(PIPEA_DATA_M1);
+		dev_priv->savePIPEA_DATA_N1 = I915_READ(PIPEA_DATA_N1);
+		dev_priv->savePIPEA_LINK_M1 = I915_READ(PIPEA_LINK_M1);
+		dev_priv->savePIPEA_LINK_N1 = I915_READ(PIPEA_LINK_N1);
+
 		dev_priv->saveFDI_TXA_CTL = I915_READ(FDI_TXA_CTL);
 		dev_priv->saveFDI_TXA_CTL = I915_READ(FDI_TXA_CTL);
 		dev_priv->saveFDI_RXA_CTL = I915_READ(FDI_RXA_CTL);
 		dev_priv->saveFDI_RXA_CTL = I915_READ(FDI_RXA_CTL);
 
 
@@ -270,6 +280,7 @@ static void i915_save_modeset_reg(struct drm_device *dev)
 		dev_priv->savePFA_WIN_SZ = I915_READ(PFA_WIN_SZ);
 		dev_priv->savePFA_WIN_SZ = I915_READ(PFA_WIN_SZ);
 		dev_priv->savePFA_WIN_POS = I915_READ(PFA_WIN_POS);
 		dev_priv->savePFA_WIN_POS = I915_READ(PFA_WIN_POS);
 
 
+		dev_priv->saveTRANSACONF = I915_READ(TRANSACONF);
 		dev_priv->saveTRANS_HTOTAL_A = I915_READ(TRANS_HTOTAL_A);
 		dev_priv->saveTRANS_HTOTAL_A = I915_READ(TRANS_HTOTAL_A);
 		dev_priv->saveTRANS_HBLANK_A = I915_READ(TRANS_HBLANK_A);
 		dev_priv->saveTRANS_HBLANK_A = I915_READ(TRANS_HBLANK_A);
 		dev_priv->saveTRANS_HSYNC_A = I915_READ(TRANS_HSYNC_A);
 		dev_priv->saveTRANS_HSYNC_A = I915_READ(TRANS_HSYNC_A);
@@ -314,6 +325,11 @@ static void i915_save_modeset_reg(struct drm_device *dev)
 		dev_priv->saveBCLRPAT_B = I915_READ(BCLRPAT_B);
 		dev_priv->saveBCLRPAT_B = I915_READ(BCLRPAT_B);
 
 
 	if (IS_IGDNG(dev)) {
 	if (IS_IGDNG(dev)) {
+		dev_priv->savePIPEB_DATA_M1 = I915_READ(PIPEB_DATA_M1);
+		dev_priv->savePIPEB_DATA_N1 = I915_READ(PIPEB_DATA_N1);
+		dev_priv->savePIPEB_LINK_M1 = I915_READ(PIPEB_LINK_M1);
+		dev_priv->savePIPEB_LINK_N1 = I915_READ(PIPEB_LINK_N1);
+
 		dev_priv->saveFDI_TXB_CTL = I915_READ(FDI_TXB_CTL);
 		dev_priv->saveFDI_TXB_CTL = I915_READ(FDI_TXB_CTL);
 		dev_priv->saveFDI_RXB_CTL = I915_READ(FDI_RXB_CTL);
 		dev_priv->saveFDI_RXB_CTL = I915_READ(FDI_RXB_CTL);
 
 
@@ -321,6 +337,7 @@ static void i915_save_modeset_reg(struct drm_device *dev)
 		dev_priv->savePFB_WIN_SZ = I915_READ(PFB_WIN_SZ);
 		dev_priv->savePFB_WIN_SZ = I915_READ(PFB_WIN_SZ);
 		dev_priv->savePFB_WIN_POS = I915_READ(PFB_WIN_POS);
 		dev_priv->savePFB_WIN_POS = I915_READ(PFB_WIN_POS);
 
 
+		dev_priv->saveTRANSBCONF = I915_READ(TRANSBCONF);
 		dev_priv->saveTRANS_HTOTAL_B = I915_READ(TRANS_HTOTAL_B);
 		dev_priv->saveTRANS_HTOTAL_B = I915_READ(TRANS_HTOTAL_B);
 		dev_priv->saveTRANS_HBLANK_B = I915_READ(TRANS_HBLANK_B);
 		dev_priv->saveTRANS_HBLANK_B = I915_READ(TRANS_HBLANK_B);
 		dev_priv->saveTRANS_HSYNC_B = I915_READ(TRANS_HSYNC_B);
 		dev_priv->saveTRANS_HSYNC_B = I915_READ(TRANS_HSYNC_B);
@@ -368,6 +385,11 @@ static void i915_restore_modeset_reg(struct drm_device *dev)
 		fpb1_reg = FPB1;
 		fpb1_reg = FPB1;
 	}
 	}
 
 
+	if (IS_IGDNG(dev)) {
+		I915_WRITE(PCH_DREF_CONTROL, dev_priv->savePCH_DREF_CONTROL);
+		I915_WRITE(DISP_ARB_CTL, dev_priv->saveDISP_ARB_CTL);
+	}
+
 	/* Pipe & plane A info */
 	/* Pipe & plane A info */
 	/* Prime the clock */
 	/* Prime the clock */
 	if (dev_priv->saveDPLL_A & DPLL_VCO_ENABLE) {
 	if (dev_priv->saveDPLL_A & DPLL_VCO_ENABLE) {
@@ -395,6 +417,11 @@ static void i915_restore_modeset_reg(struct drm_device *dev)
 		I915_WRITE(BCLRPAT_A, dev_priv->saveBCLRPAT_A);
 		I915_WRITE(BCLRPAT_A, dev_priv->saveBCLRPAT_A);
 
 
 	if (IS_IGDNG(dev)) {
 	if (IS_IGDNG(dev)) {
+		I915_WRITE(PIPEA_DATA_M1, dev_priv->savePIPEA_DATA_M1);
+		I915_WRITE(PIPEA_DATA_N1, dev_priv->savePIPEA_DATA_N1);
+		I915_WRITE(PIPEA_LINK_M1, dev_priv->savePIPEA_LINK_M1);
+		I915_WRITE(PIPEA_LINK_N1, dev_priv->savePIPEA_LINK_N1);
+
 		I915_WRITE(FDI_RXA_CTL, dev_priv->saveFDI_RXA_CTL);
 		I915_WRITE(FDI_RXA_CTL, dev_priv->saveFDI_RXA_CTL);
 		I915_WRITE(FDI_TXA_CTL, dev_priv->saveFDI_TXA_CTL);
 		I915_WRITE(FDI_TXA_CTL, dev_priv->saveFDI_TXA_CTL);
 
 
@@ -402,6 +429,7 @@ static void i915_restore_modeset_reg(struct drm_device *dev)
 		I915_WRITE(PFA_WIN_SZ, dev_priv->savePFA_WIN_SZ);
 		I915_WRITE(PFA_WIN_SZ, dev_priv->savePFA_WIN_SZ);
 		I915_WRITE(PFA_WIN_POS, dev_priv->savePFA_WIN_POS);
 		I915_WRITE(PFA_WIN_POS, dev_priv->savePFA_WIN_POS);
 
 
+		I915_WRITE(TRANSACONF, dev_priv->saveTRANSACONF);
 		I915_WRITE(TRANS_HTOTAL_A, dev_priv->saveTRANS_HTOTAL_A);
 		I915_WRITE(TRANS_HTOTAL_A, dev_priv->saveTRANS_HTOTAL_A);
 		I915_WRITE(TRANS_HBLANK_A, dev_priv->saveTRANS_HBLANK_A);
 		I915_WRITE(TRANS_HBLANK_A, dev_priv->saveTRANS_HBLANK_A);
 		I915_WRITE(TRANS_HSYNC_A, dev_priv->saveTRANS_HSYNC_A);
 		I915_WRITE(TRANS_HSYNC_A, dev_priv->saveTRANS_HSYNC_A);
@@ -439,7 +467,7 @@ static void i915_restore_modeset_reg(struct drm_device *dev)
 	/* Actually enable it */
 	/* Actually enable it */
 	I915_WRITE(dpll_b_reg, dev_priv->saveDPLL_B);
 	I915_WRITE(dpll_b_reg, dev_priv->saveDPLL_B);
 	DRM_UDELAY(150);
 	DRM_UDELAY(150);
-	if (IS_I965G(dev))
+	if (IS_I965G(dev) && !IS_IGDNG(dev))
 		I915_WRITE(DPLL_B_MD, dev_priv->saveDPLL_B_MD);
 		I915_WRITE(DPLL_B_MD, dev_priv->saveDPLL_B_MD);
 	DRM_UDELAY(150);
 	DRM_UDELAY(150);
 
 
@@ -454,6 +482,11 @@ static void i915_restore_modeset_reg(struct drm_device *dev)
 		I915_WRITE(BCLRPAT_B, dev_priv->saveBCLRPAT_B);
 		I915_WRITE(BCLRPAT_B, dev_priv->saveBCLRPAT_B);
 
 
 	if (IS_IGDNG(dev)) {
 	if (IS_IGDNG(dev)) {
+		I915_WRITE(PIPEB_DATA_M1, dev_priv->savePIPEB_DATA_M1);
+		I915_WRITE(PIPEB_DATA_N1, dev_priv->savePIPEB_DATA_N1);
+		I915_WRITE(PIPEB_LINK_M1, dev_priv->savePIPEB_LINK_M1);
+		I915_WRITE(PIPEB_LINK_N1, dev_priv->savePIPEB_LINK_N1);
+
 		I915_WRITE(FDI_RXB_CTL, dev_priv->saveFDI_RXB_CTL);
 		I915_WRITE(FDI_RXB_CTL, dev_priv->saveFDI_RXB_CTL);
 		I915_WRITE(FDI_TXB_CTL, dev_priv->saveFDI_TXB_CTL);
 		I915_WRITE(FDI_TXB_CTL, dev_priv->saveFDI_TXB_CTL);
 
 
@@ -461,6 +494,7 @@ static void i915_restore_modeset_reg(struct drm_device *dev)
 		I915_WRITE(PFB_WIN_SZ, dev_priv->savePFB_WIN_SZ);
 		I915_WRITE(PFB_WIN_SZ, dev_priv->savePFB_WIN_SZ);
 		I915_WRITE(PFB_WIN_POS, dev_priv->savePFB_WIN_POS);
 		I915_WRITE(PFB_WIN_POS, dev_priv->savePFB_WIN_POS);
 
 
+		I915_WRITE(TRANSBCONF, dev_priv->saveTRANSBCONF);
 		I915_WRITE(TRANS_HTOTAL_B, dev_priv->saveTRANS_HTOTAL_B);
 		I915_WRITE(TRANS_HTOTAL_B, dev_priv->saveTRANS_HTOTAL_B);
 		I915_WRITE(TRANS_HBLANK_B, dev_priv->saveTRANS_HBLANK_B);
 		I915_WRITE(TRANS_HBLANK_B, dev_priv->saveTRANS_HBLANK_B);
 		I915_WRITE(TRANS_HSYNC_B, dev_priv->saveTRANS_HSYNC_B);
 		I915_WRITE(TRANS_HSYNC_B, dev_priv->saveTRANS_HSYNC_B);

+ 2 - 2
drivers/gpu/drm/i915/intel_crt.c

@@ -262,8 +262,8 @@ static bool intel_crt_detect_hotplug(struct drm_connector *connector)
 		} while (time_after(timeout, jiffies));
 		} while (time_after(timeout, jiffies));
 	}
 	}
 
 
-	if ((I915_READ(PORT_HOTPLUG_STAT) & CRT_HOTPLUG_MONITOR_MASK) ==
-	    CRT_HOTPLUG_MONITOR_COLOR)
+	if ((I915_READ(PORT_HOTPLUG_STAT) & CRT_HOTPLUG_MONITOR_MASK) !=
+	    CRT_HOTPLUG_MONITOR_NONE)
 		return true;
 		return true;
 
 
 	return false;
 	return false;

+ 6 - 9
drivers/gpu/drm/i915/intel_display.c

@@ -863,10 +863,8 @@ intel_igdng_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
 	struct drm_device *dev = crtc->dev;
 	struct drm_device *dev = crtc->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	intel_clock_t clock;
 	intel_clock_t clock;
-	int max_n;
-	bool found;
 	int err_most = 47;
 	int err_most = 47;
-	found = false;
+	int err_min = 10000;
 
 
 	/* eDP has only 2 clock choice, no n/m/p setting */
 	/* eDP has only 2 clock choice, no n/m/p setting */
 	if (HAS_eDP)
 	if (HAS_eDP)
@@ -890,10 +888,9 @@ intel_igdng_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
 	}
 	}
 
 
 	memset(best_clock, 0, sizeof(*best_clock));
 	memset(best_clock, 0, sizeof(*best_clock));
-	max_n = limit->n.max;
 	for (clock.p1 = limit->p1.max; clock.p1 >= limit->p1.min; clock.p1--) {
 	for (clock.p1 = limit->p1.max; clock.p1 >= limit->p1.min; clock.p1--) {
 		/* based on hardware requriment prefer smaller n to precision */
 		/* based on hardware requriment prefer smaller n to precision */
-		for (clock.n = limit->n.min; clock.n <= max_n; clock.n++) {
+		for (clock.n = limit->n.min; clock.n <= limit->n.max; clock.n++) {
 			/* based on hardware requirment prefere larger m1,m2 */
 			/* based on hardware requirment prefere larger m1,m2 */
 			for (clock.m1 = limit->m1.max;
 			for (clock.m1 = limit->m1.max;
 			     clock.m1 >= limit->m1.min; clock.m1--) {
 			     clock.m1 >= limit->m1.min; clock.m1--) {
@@ -907,18 +904,18 @@ intel_igdng_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
 					this_err = abs((10000 - (target*10000/clock.dot)));
 					this_err = abs((10000 - (target*10000/clock.dot)));
 					if (this_err < err_most) {
 					if (this_err < err_most) {
 						*best_clock = clock;
 						*best_clock = clock;
-						err_most = this_err;
-						max_n = clock.n;
-						found = true;
 						/* found on first matching */
 						/* found on first matching */
 						goto out;
 						goto out;
+					} else if (this_err < err_min) {
+						*best_clock = clock;
+						err_min = this_err;
 					}
 					}
 				}
 				}
 			}
 			}
 		}
 		}
 	}
 	}
 out:
 out:
-	return found;
+	return true;
 }
 }
 
 
 /* DisplayPort has only two frequencies, 162MHz and 270MHz */
 /* DisplayPort has only two frequencies, 162MHz and 270MHz */

+ 22 - 4
drivers/gpu/drm/i915/intel_hdmi.c

@@ -77,14 +77,32 @@ static void intel_hdmi_dpms(struct drm_encoder *encoder, int mode)
 	struct intel_hdmi_priv *hdmi_priv = intel_output->dev_priv;
 	struct intel_hdmi_priv *hdmi_priv = intel_output->dev_priv;
 	u32 temp;
 	u32 temp;
 
 
-	if (mode != DRM_MODE_DPMS_ON) {
-		temp = I915_READ(hdmi_priv->sdvox_reg);
+	temp = I915_READ(hdmi_priv->sdvox_reg);
+
+	/* HW workaround, need to toggle enable bit off and on for 12bpc, but
+	 * we do this anyway which shows more stable in testing.
+	 */
+	if (IS_IGDNG(dev)) {
 		I915_WRITE(hdmi_priv->sdvox_reg, temp & ~SDVO_ENABLE);
 		I915_WRITE(hdmi_priv->sdvox_reg, temp & ~SDVO_ENABLE);
+		POSTING_READ(hdmi_priv->sdvox_reg);
+	}
+
+	if (mode != DRM_MODE_DPMS_ON) {
+		temp &= ~SDVO_ENABLE;
 	} else {
 	} else {
-		temp = I915_READ(hdmi_priv->sdvox_reg);
-		I915_WRITE(hdmi_priv->sdvox_reg, temp | SDVO_ENABLE);
+		temp |= SDVO_ENABLE;
 	}
 	}
+
+	I915_WRITE(hdmi_priv->sdvox_reg, temp);
 	POSTING_READ(hdmi_priv->sdvox_reg);
 	POSTING_READ(hdmi_priv->sdvox_reg);
+
+	/* HW workaround, need to write this twice for issue that may result
+	 * in first write getting masked.
+	 */
+	if (IS_IGDNG(dev)) {
+		I915_WRITE(hdmi_priv->sdvox_reg, temp);
+		POSTING_READ(hdmi_priv->sdvox_reg);
+	}
 }
 }
 
 
 static void intel_hdmi_save(struct drm_connector *connector)
 static void intel_hdmi_save(struct drm_connector *connector)