summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/i915
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/i915')
-rw-r--r--drivers/gpu/drm/i915/i915_drv.c2
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h7
-rw-r--r--drivers/gpu/drm/i915/i915_gem.c55
-rw-r--r--drivers/gpu/drm/i915/i915_gem_tiling.c15
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c10
-rw-r--r--drivers/gpu/drm/i915/i915_reg.h22
-rw-r--r--drivers/gpu/drm/i915/i915_suspend.c2
-rw-r--r--drivers/gpu/drm/i915/intel_bios.c3
-rw-r--r--drivers/gpu/drm/i915/intel_crt.c13
-rw-r--r--drivers/gpu/drm/i915/intel_display.c173
-rw-r--r--drivers/gpu/drm/i915/intel_fb.c8
-rw-r--r--drivers/gpu/drm/i915/intel_lvds.c11
-rw-r--r--drivers/gpu/drm/i915/intel_sdvo.c96
-rw-r--r--drivers/gpu/drm/i915/intel_tv.c11
14 files changed, 312 insertions, 116 deletions
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index fc4b68aa2d05..c078d995aa91 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -94,8 +94,6 @@ static int i915_resume(struct drm_device *dev)
struct drm_i915_private *dev_priv = dev->dev_private;
int ret = 0;
- pci_set_power_state(dev->pdev, PCI_D0);
- pci_restore_state(dev->pdev);
if (pci_enable_device(dev->pdev))
return -1;
pci_set_master(dev->pdev);
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 5b4f87e55621..d3f365d8b6ef 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -264,6 +264,7 @@ typedef struct drm_i915_private {
u32 saveDSPASURF;
u32 saveDSPATILEOFF;
u32 savePFIT_PGM_RATIOS;
+ u32 saveBLC_HIST_CTL;
u32 saveBLC_PWM_CTL;
u32 saveBLC_PWM_CTL2;
u32 saveFPB0;
@@ -837,6 +838,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
#define IS_I85X(dev) ((dev)->pci_device == 0x3582)
#define IS_I855(dev) ((dev)->pci_device == 0x3582)
#define IS_I865G(dev) ((dev)->pci_device == 0x2572)
+#define IS_I8XX(dev) (IS_I830(dev) || IS_845G(dev) || IS_I85X(dev) || IS_I865G(dev))
#define IS_I915G(dev) ((dev)->pci_device == 0x2582 || (dev)->pci_device == 0x258a)
#define IS_I915GM(dev) ((dev)->pci_device == 0x2592)
@@ -854,6 +856,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
(dev)->pci_device == 0x2E12 || \
(dev)->pci_device == 0x2E22 || \
(dev)->pci_device == 0x2E32 || \
+ (dev)->pci_device == 0x2E42 || \
(dev)->pci_device == 0x0042 || \
(dev)->pci_device == 0x0046)
@@ -866,6 +869,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
(dev)->pci_device == 0x2E12 || \
(dev)->pci_device == 0x2E22 || \
(dev)->pci_device == 0x2E32 || \
+ (dev)->pci_device == 0x2E42 || \
IS_GM45(dev))
#define IS_IGDG(dev) ((dev)->pci_device == 0xa001)
@@ -896,9 +900,12 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
*/
#define HAS_128_BYTE_Y_TILING(dev) (IS_I9XX(dev) && !(IS_I915G(dev) || \
IS_I915GM(dev)))
+#define SUPPORTS_DIGITAL_OUTPUTS(dev) (IS_I9XX(dev) && !IS_IGD(dev))
#define SUPPORTS_INTEGRATED_HDMI(dev) (IS_G4X(dev) || IS_IGDNG(dev))
#define SUPPORTS_INTEGRATED_DP(dev) (IS_G4X(dev) || IS_IGDNG(dev))
#define SUPPORTS_EDP(dev) (IS_IGDNG_M(dev))
+#define SUPPORTS_TV(dev) (IS_I9XX(dev) && IS_MOBILE(dev) && \
+ !IS_IGDNG(dev) && !IS_IGD(dev))
#define I915_HAS_HOTPLUG(dev) (IS_I945G(dev) || IS_I945GM(dev) || IS_I965G(dev))
/* dsparb controlled by hw only */
#define DSPARB_HWCONTROL(dev) (IS_G4X(dev) || IS_IGDNG(dev))
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 80e5ba490dc2..2b7aeeed3990 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -1151,27 +1151,21 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
mutex_lock(&dev->struct_mutex);
if (!obj_priv->gtt_space) {
ret = i915_gem_object_bind_to_gtt(obj, obj_priv->gtt_alignment);
- if (ret) {
- mutex_unlock(&dev->struct_mutex);
- return VM_FAULT_SIGBUS;
- }
-
- ret = i915_gem_object_set_to_gtt_domain(obj, write);
- if (ret) {
- mutex_unlock(&dev->struct_mutex);
- return VM_FAULT_SIGBUS;
- }
+ if (ret)
+ goto unlock;
list_add_tail(&obj_priv->list, &dev_priv->mm.inactive_list);
+
+ ret = i915_gem_object_set_to_gtt_domain(obj, write);
+ if (ret)
+ goto unlock;
}
/* Need a new fence register? */
if (obj_priv->tiling_mode != I915_TILING_NONE) {
ret = i915_gem_object_get_fence_reg(obj);
- if (ret) {
- mutex_unlock(&dev->struct_mutex);
- return VM_FAULT_SIGBUS;
- }
+ if (ret)
+ goto unlock;
}
pfn = ((dev->agp->base + obj_priv->gtt_offset) >> PAGE_SHIFT) +
@@ -1179,18 +1173,18 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
/* Finally, remap it using the new GTT offset */
ret = vm_insert_pfn(vma, (unsigned long)vmf->virtual_address, pfn);
-
+unlock:
mutex_unlock(&dev->struct_mutex);
switch (ret) {
+ case 0:
+ case -ERESTARTSYS:
+ return VM_FAULT_NOPAGE;
case -ENOMEM:
case -EAGAIN:
return VM_FAULT_OOM;
- case -EFAULT:
- case -EINVAL:
- return VM_FAULT_SIGBUS;
default:
- return VM_FAULT_NOPAGE;
+ return VM_FAULT_SIGBUS;
}
}
@@ -2506,16 +2500,6 @@ i915_gem_clflush_object(struct drm_gem_object *obj)
if (obj_priv->pages == NULL)
return;
- /* XXX: The 865 in particular appears to be weird in how it handles
- * cache flushing. We haven't figured it out, but the
- * clflush+agp_chipset_flush doesn't appear to successfully get the
- * data visible to the PGU, while wbinvd + agp_chipset_flush does.
- */
- if (IS_I865G(obj->dev)) {
- wbinvd();
- return;
- }
-
drm_clflush_pages(obj_priv->pages, obj->size / PAGE_SIZE);
}
@@ -3007,6 +2991,16 @@ i915_gem_object_pin_and_relocate(struct drm_gem_object *obj,
return -EINVAL;
}
+ if (reloc->delta >= target_obj->size) {
+ DRM_ERROR("Relocation beyond target object bounds: "
+ "obj %p target %d delta %d size %d.\n",
+ obj, reloc->target_handle,
+ (int) reloc->delta, (int) target_obj->size);
+ drm_gem_object_unreference(target_obj);
+ i915_gem_object_unpin(obj);
+ return -EINVAL;
+ }
+
if (reloc->write_domain & I915_GEM_DOMAIN_CPU ||
reloc->read_domains & I915_GEM_DOMAIN_CPU) {
DRM_ERROR("reloc with read/write CPU domains: "
@@ -3837,7 +3831,8 @@ void i915_gem_free_object(struct drm_gem_object *obj)
i915_gem_object_unbind(obj);
- i915_gem_free_mmap_offset(obj);
+ if (obj_priv->mmap_offset)
+ i915_gem_free_mmap_offset(obj);
kfree(obj_priv->page_cpu_valid);
kfree(obj_priv->bit_17);
diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c
index a2d527b22ec4..e774a4a1a503 100644
--- a/drivers/gpu/drm/i915/i915_gem_tiling.c
+++ b/drivers/gpu/drm/i915/i915_gem_tiling.c
@@ -234,7 +234,13 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev)
uint32_t swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN;
bool need_disable;
- if (!IS_I9XX(dev)) {
+ if (IS_IGDNG(dev)) {
+ /* On IGDNG whatever DRAM config, GPU always do
+ * same swizzling setup.
+ */
+ swizzle_x = I915_BIT_6_SWIZZLE_9_10;
+ swizzle_y = I915_BIT_6_SWIZZLE_9;
+ } else if (!IS_I9XX(dev)) {
/* As far as we know, the 865 doesn't have these bit 6
* swizzling issues.
*/
@@ -317,13 +323,6 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev)
}
}
- /* FIXME: check with memory config on IGDNG */
- if (IS_IGDNG(dev)) {
- DRM_ERROR("disable tiling on IGDNG...\n");
- swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN;
- swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN;
- }
-
dev_priv->mm.bit_6_swizzle_x = swizzle_x;
dev_priv->mm.bit_6_swizzle_y = swizzle_y;
}
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 7ebc84c2881e..9431a727a985 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -253,10 +253,15 @@ irqreturn_t igdng_irq_handler(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
int ret = IRQ_NONE;
- u32 de_iir, gt_iir;
+ u32 de_iir, gt_iir, de_ier;
u32 new_de_iir, new_gt_iir;
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);
gt_iir = I915_READ(GTIIR);
@@ -287,6 +292,9 @@ irqreturn_t igdng_irq_handler(struct drm_device *dev)
gt_iir = new_gt_iir;
}
+ I915_WRITE(DEIER, de_ier);
+ (void)I915_READ(DEIER);
+
return ret;
}
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 2955083aa471..9917749afb32 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -915,6 +915,8 @@
#define BACKLIGHT_DUTY_CYCLE_SHIFT (0)
#define BACKLIGHT_DUTY_CYCLE_MASK (0xffff)
+#define BLC_HIST_CTL 0x61260
+
/* TV port control */
#define TV_CTL 0x68000
/** Enables the TV encoder */
@@ -1616,6 +1618,11 @@
#define PIPE_START_VBLANK_INTERRUPT_STATUS (1UL<<2) /* 965 or later */
#define PIPE_VBLANK_INTERRUPT_STATUS (1UL<<1)
#define PIPE_OVERLAY_UPDATED_STATUS (1UL<<0)
+#define PIPE_BPC_MASK (7 << 5) /* Ironlake */
+#define PIPE_8BPC (0 << 5)
+#define PIPE_10BPC (1 << 5)
+#define PIPE_6BPC (2 << 5)
+#define PIPE_12BPC (3 << 5)
#define DSPARB 0x70030
#define DSPARB_CSTART_MASK (0x7f << 7)
@@ -1733,6 +1740,7 @@
#define DISPPLANE_NO_LINE_DOUBLE 0
#define DISPPLANE_STEREO_POLARITY_FIRST 0
#define DISPPLANE_STEREO_POLARITY_SECOND (1<<18)
+#define DISPPLANE_TRICKLE_FEED_DISABLE (1<<14) /* IGDNG */
#define DISPPLANE_TILED (1<<10)
#define DSPAADDR 0x70184
#define DSPASTRIDE 0x70188
@@ -1865,8 +1873,15 @@
#define PFA_CTL_1 0x68080
#define PFB_CTL_1 0x68880
#define PF_ENABLE (1<<31)
+#define PF_FILTER_MASK (3<<23)
+#define PF_FILTER_PROGRAMMED (0<<23)
+#define PF_FILTER_MED_3x3 (1<<23)
+#define PF_FILTER_EDGE_ENHANCE (2<<23)
+#define PF_FILTER_EDGE_SOFTEN (3<<23)
#define PFA_WIN_SZ 0x68074
#define PFB_WIN_SZ 0x68874
+#define PFA_WIN_POS 0x68070
+#define PFB_WIN_POS 0x68870
/* legacy palette */
#define LGC_PALETTE_A 0x4a000
@@ -1913,6 +1928,9 @@
#define GTIIR 0x44018
#define GTIER 0x4401c
+#define DISP_ARB_CTL 0x45000
+#define DISP_TILE_SURFACE_SWIZZLING (1<<13)
+
/* PCH */
/* south display engine interrupt */
@@ -1979,11 +1997,11 @@
#define DREF_CPU_SOURCE_OUTPUT_MASK (3<<13)
#define DREF_SSC_SOURCE_DISABLE (0<<11)
#define DREF_SSC_SOURCE_ENABLE (2<<11)
-#define DREF_SSC_SOURCE_MASK (2<<11)
+#define DREF_SSC_SOURCE_MASK (3<<11)
#define DREF_NONSPREAD_SOURCE_DISABLE (0<<9)
#define DREF_NONSPREAD_CK505_ENABLE (1<<9)
#define DREF_NONSPREAD_SOURCE_ENABLE (2<<9)
-#define DREF_NONSPREAD_SOURCE_MASK (2<<9)
+#define DREF_NONSPREAD_SOURCE_MASK (3<<9)
#define DREF_SUPERSPREAD_SOURCE_DISABLE (0<<7)
#define DREF_SUPERSPREAD_SOURCE_ENABLE (2<<7)
#define DREF_SSC4_DOWNSPREAD (0<<6)
diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c
index 1d04e1904ac6..2e4aca658b8b 100644
--- a/drivers/gpu/drm/i915/i915_suspend.c
+++ b/drivers/gpu/drm/i915/i915_suspend.c
@@ -416,6 +416,7 @@ int i915_save_state(struct drm_device *dev)
dev_priv->savePP_CONTROL = I915_READ(PP_CONTROL);
dev_priv->savePFIT_PGM_RATIOS = I915_READ(PFIT_PGM_RATIOS);
dev_priv->saveBLC_PWM_CTL = I915_READ(BLC_PWM_CTL);
+ dev_priv->saveBLC_HIST_CTL = I915_READ(BLC_HIST_CTL);
if (IS_I965G(dev))
dev_priv->saveBLC_PWM_CTL2 = I915_READ(BLC_PWM_CTL2);
if (IS_MOBILE(dev) && !IS_I830(dev))
@@ -560,6 +561,7 @@ int i915_restore_state(struct drm_device *dev)
I915_WRITE(PFIT_PGM_RATIOS, dev_priv->savePFIT_PGM_RATIOS);
I915_WRITE(BLC_PWM_CTL, dev_priv->saveBLC_PWM_CTL);
+ I915_WRITE(BLC_HIST_CTL, dev_priv->saveBLC_HIST_CTL);
I915_WRITE(PP_ON_DELAYS, dev_priv->savePP_ON_DELAYS);
I915_WRITE(PP_OFF_DELAYS, dev_priv->savePP_OFF_DELAYS);
I915_WRITE(PP_DIVISOR, dev_priv->savePP_DIVISOR);
diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c
index f806fcc54e09..698a0edf0ea9 100644
--- a/drivers/gpu/drm/i915/intel_bios.c
+++ b/drivers/gpu/drm/i915/intel_bios.c
@@ -217,6 +217,9 @@ parse_general_features(struct drm_i915_private *dev_priv,
if (IS_I85X(dev_priv->dev))
dev_priv->lvds_ssc_freq =
general->ssc_freq ? 66 : 48;
+ else if (IS_IGDNG(dev_priv->dev))
+ dev_priv->lvds_ssc_freq =
+ general->ssc_freq ? 100 : 120;
else
dev_priv->lvds_ssc_freq =
general->ssc_freq ? 100 : 96;
diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c
index 590f81c8f594..046027fa9731 100644
--- a/drivers/gpu/drm/i915/intel_crt.c
+++ b/drivers/gpu/drm/i915/intel_crt.c
@@ -151,13 +151,10 @@ static bool intel_igdng_crt_detect_hotplug(struct drm_connector *connector)
{
struct drm_device *dev = connector->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- u32 adpa, temp;
+ u32 adpa;
bool ret;
- temp = adpa = I915_READ(PCH_ADPA);
-
- adpa &= ~ADPA_DAC_ENABLE;
- I915_WRITE(PCH_ADPA, adpa);
+ adpa = I915_READ(PCH_ADPA);
adpa &= ~ADPA_CRT_HOTPLUG_MASK;
@@ -184,8 +181,6 @@ static bool intel_igdng_crt_detect_hotplug(struct drm_connector *connector)
else
ret = false;
- /* restore origin register */
- I915_WRITE(PCH_ADPA, temp);
return ret;
}
@@ -239,8 +234,8 @@ static bool intel_crt_detect_hotplug(struct drm_connector *connector)
} 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 false;
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 748ed50c55ca..3ac3b7c49869 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -818,7 +818,7 @@ intel_igdng_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
refclk, best_clock);
if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
- if ((I915_READ(LVDS) & LVDS_CLKB_POWER_MASK) ==
+ if ((I915_READ(PCH_LVDS) & LVDS_CLKB_POWER_MASK) ==
LVDS_CLKB_POWER_UP)
clock.p2 = limit->p2.p2_fast;
else
@@ -1008,6 +1008,10 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
dspcntr &= ~DISPPLANE_TILED;
}
+ if (IS_IGDNG(dev))
+ /* must disable */
+ dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE;
+
I915_WRITE(dspcntr_reg, dspcntr);
Start = obj_priv->gtt_offset;
@@ -1154,6 +1158,7 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode)
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;
+ int pf_win_pos = (pipe == 0) ? PFA_WIN_POS : PFB_WIN_POS;
int cpu_htot_reg = (pipe == 0) ? HTOTAL_A : HTOTAL_B;
int cpu_hblank_reg = (pipe == 0) ? HBLANK_A : HBLANK_B;
int cpu_hsync_reg = (pipe == 0) ? HSYNC_A : HSYNC_B;
@@ -1177,6 +1182,15 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode)
case DRM_MODE_DPMS_STANDBY:
case DRM_MODE_DPMS_SUSPEND:
DRM_DEBUG("crtc %d dpms on\n", pipe);
+
+ if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
+ temp = I915_READ(PCH_LVDS);
+ if ((temp & LVDS_PORT_EN) == 0) {
+ I915_WRITE(PCH_LVDS, temp | LVDS_PORT_EN);
+ POSTING_READ(PCH_LVDS);
+ }
+ }
+
if (HAS_eDP) {
/* enable eDP PLL */
igdng_enable_pll_edp(crtc);
@@ -1205,6 +1219,19 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode)
}
}
+ /* Enable panel fitting for LVDS */
+ if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
+ temp = I915_READ(pf_ctl_reg);
+ I915_WRITE(pf_ctl_reg, temp | PF_ENABLE | PF_FILTER_MED_3x3);
+
+ /* currently full aspect */
+ I915_WRITE(pf_win_pos, 0);
+
+ I915_WRITE(pf_win_size,
+ (dev_priv->panel_fixed_mode->hdisplay << 16) |
+ (dev_priv->panel_fixed_mode->vdisplay));
+ }
+
/* Enable CPU pipe */
temp = I915_READ(pipeconf_reg);
if ((temp & PIPEACONF_ENABLE) == 0) {
@@ -1348,8 +1375,6 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode)
case DRM_MODE_DPMS_OFF:
DRM_DEBUG("crtc %d dpms off\n", pipe);
- i915_disable_vga(dev);
-
/* Disable display plane */
temp = I915_READ(dspcntr_reg);
if ((temp & DISPLAY_PLANE_ENABLE) != 0) {
@@ -1359,6 +1384,8 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode)
I915_READ(dspbase_reg);
}
+ i915_disable_vga(dev);
+
/* disable cpu pipe, disable after all planes disabled */
temp = I915_READ(pipeconf_reg);
if ((temp & PIPEACONF_ENABLE) != 0) {
@@ -1379,9 +1406,15 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode)
} else
DRM_DEBUG("crtc %d is disabled\n", pipe);
- if (HAS_eDP) {
- igdng_disable_pll_edp(crtc);
+ udelay(100);
+
+ /* Disable PF */
+ temp = I915_READ(pf_ctl_reg);
+ if ((temp & PF_ENABLE) != 0) {
+ I915_WRITE(pf_ctl_reg, temp & ~PF_ENABLE);
+ I915_READ(pf_ctl_reg);
}
+ I915_WRITE(pf_win_size, 0);
/* disable CPU FDI tx and PCH FDI rx */
temp = I915_READ(fdi_tx_reg);
@@ -1407,6 +1440,13 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode)
udelay(100);
+ if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
+ temp = I915_READ(PCH_LVDS);
+ I915_WRITE(PCH_LVDS, temp & ~LVDS_PORT_EN);
+ I915_READ(PCH_LVDS);
+ udelay(100);
+ }
+
/* disable PCH transcoder */
temp = I915_READ(transconf_reg);
if ((temp & TRANS_ENABLE) != 0) {
@@ -1426,6 +1466,8 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode)
}
}
+ udelay(100);
+
/* disable PCH DPLL */
temp = I915_READ(pch_dpll_reg);
if ((temp & DPLL_VCO_ENABLE) != 0) {
@@ -1433,14 +1475,20 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode)
I915_READ(pch_dpll_reg);
}
- temp = I915_READ(fdi_rx_reg);
- if ((temp & FDI_RX_PLL_ENABLE) != 0) {
- temp &= ~FDI_SEL_PCDCLK;
- temp &= ~FDI_RX_PLL_ENABLE;
- I915_WRITE(fdi_rx_reg, temp);
- I915_READ(fdi_rx_reg);
+ if (HAS_eDP) {
+ igdng_disable_pll_edp(crtc);
}
+ temp = I915_READ(fdi_rx_reg);
+ temp &= ~FDI_SEL_PCDCLK;
+ I915_WRITE(fdi_rx_reg, temp);
+ I915_READ(fdi_rx_reg);
+
+ 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) {
@@ -1449,16 +1497,8 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode)
udelay(100);
}
- /* Disable PF */
- temp = I915_READ(pf_ctl_reg);
- if ((temp & PF_ENABLE) != 0) {
- I915_WRITE(pf_ctl_reg, temp & ~PF_ENABLE);
- I915_READ(pf_ctl_reg);
- }
- I915_WRITE(pf_win_size, 0);
-
/* Wait for the clocks to turn off. */
- udelay(150);
+ udelay(100);
break;
}
}
@@ -1522,6 +1562,7 @@ static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode)
intel_update_watermarks(dev);
/* Give the overlay scaler a chance to disable if it's on this pipe */
//intel_crtc_dpms_video(crtc, FALSE); TODO
+ drm_vblank_off(dev, pipe);
/* Disable the VGA plane that we never use */
i915_disable_vga(dev);
@@ -1746,7 +1787,7 @@ fdi_reduce_ratio(u32 *num, u32 *den)
#define LINK_N 0x80000
static void
-igdng_compute_m_n(int bytes_per_pixel, int nlanes,
+igdng_compute_m_n(int bits_per_pixel, int nlanes,
int pixel_clock, int link_clock,
struct fdi_m_n *m_n)
{
@@ -1756,7 +1797,8 @@ igdng_compute_m_n(int bytes_per_pixel, int nlanes,
temp = (u64) DATA_N * pixel_clock;
temp = div_u64(temp, link_clock);
- m_n->gmch_m = div_u64(temp * bytes_per_pixel, nlanes);
+ m_n->gmch_m = div_u64(temp * bits_per_pixel, nlanes);
+ m_n->gmch_m >>= 3; /* convert to bytes_per_pixel */
m_n->gmch_n = DATA_N;
fdi_reduce_ratio(&m_n->gmch_m, &m_n->gmch_n);
@@ -1858,7 +1900,14 @@ static unsigned long intel_calculate_wm(unsigned long clock_in_khz,
{
long entries_required, wm_size;
- entries_required = (clock_in_khz * pixel_size * latency_ns) / 1000000;
+ /*
+ * Note: we need to make sure we don't overflow for various clock &
+ * latency values.
+ * clocks go from a few thousand to several hundred thousand.
+ * latency is usually a few thousand
+ */
+ entries_required = ((clock_in_khz / 1000) * pixel_size * latency_ns) /
+ 1000;
entries_required /= wm->cacheline_size;
DRM_DEBUG("FIFO entries required for mode: %d\n", entries_required);
@@ -2371,7 +2420,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
/* FDI link */
if (IS_IGDNG(dev)) {
- int lane, link_bw;
+ int lane, link_bw, bpp;
/* eDP doesn't require FDI link, so just set DP M/N
according to current link config */
if (is_edp) {
@@ -2390,10 +2439,72 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
lane = 4;
link_bw = 270000;
}
- igdng_compute_m_n(3, lane, target_clock,
+
+ /* determine panel color depth */
+ temp = I915_READ(pipeconf_reg);
+
+ switch (temp & PIPE_BPC_MASK) {
+ case PIPE_8BPC:
+ bpp = 24;
+ break;
+ case PIPE_10BPC:
+ bpp = 30;
+ break;
+ case PIPE_6BPC:
+ bpp = 18;
+ break;
+ case PIPE_12BPC:
+ bpp = 36;
+ break;
+ default:
+ DRM_ERROR("unknown pipe bpc value\n");
+ bpp = 24;
+ }
+
+ igdng_compute_m_n(bpp, lane, target_clock,
link_bw, &m_n);
}
+ /* Ironlake: try to setup display ref clock before DPLL
+ * enabling. This is only under driver's control after
+ * PCH B stepping, previous chipset stepping should be
+ * ignoring this setting.
+ */
+ if (IS_IGDNG(dev)) {
+ temp = I915_READ(PCH_DREF_CONTROL);
+ /* Always enable nonspread source */
+ temp &= ~DREF_NONSPREAD_SOURCE_MASK;
+ temp |= DREF_NONSPREAD_SOURCE_ENABLE;
+ I915_WRITE(PCH_DREF_CONTROL, temp);
+ POSTING_READ(PCH_DREF_CONTROL);
+
+ temp &= ~DREF_SSC_SOURCE_MASK;
+ temp |= DREF_SSC_SOURCE_ENABLE;
+ I915_WRITE(PCH_DREF_CONTROL, temp);
+ POSTING_READ(PCH_DREF_CONTROL);
+
+ udelay(200);
+
+ if (is_edp) {
+ if (dev_priv->lvds_use_ssc) {
+ temp |= DREF_SSC1_ENABLE;
+ I915_WRITE(PCH_DREF_CONTROL, temp);
+ POSTING_READ(PCH_DREF_CONTROL);
+
+ udelay(200);
+
+ temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
+ temp |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD;
+ I915_WRITE(PCH_DREF_CONTROL, temp);
+ POSTING_READ(PCH_DREF_CONTROL);
+ } else {
+ temp |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD;
+ I915_WRITE(PCH_DREF_CONTROL, temp);
+ POSTING_READ(PCH_DREF_CONTROL);
+ }
+ }
+ }
+
if (IS_IGD(dev))
fp = (1 << clock.n) << 16 | clock.m1 << 8 | clock.m2;
else
@@ -2616,6 +2727,12 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
intel_wait_for_vblank(dev);
+ if (IS_IGDNG(dev)) {
+ /* enable address swizzle for tiling buffer */
+ temp = I915_READ(DISP_ARB_CTL);
+ I915_WRITE(DISP_ARB_CTL, temp | DISP_TILE_SURFACE_SWIZZLING);
+ }
+
I915_WRITE(dspcntr_reg, dspcntr);
/* Flush the plane changes */
@@ -3231,7 +3348,7 @@ static void intel_setup_outputs(struct drm_device *dev)
if (I915_READ(PCH_DP_D) & DP_DETECTED)
intel_dp_init(dev, PCH_DP_D);
- } else if (IS_I9XX(dev)) {
+ } else if (SUPPORTS_DIGITAL_OUTPUTS(dev)) {
bool found = false;
if (I915_READ(SDVOB) & SDVO_DETECTED) {
@@ -3258,10 +3375,10 @@ static void intel_setup_outputs(struct drm_device *dev)
if (SUPPORTS_INTEGRATED_DP(dev) && (I915_READ(DP_D) & DP_DETECTED))
intel_dp_init(dev, DP_D);
- } else
+ } else if (IS_I8XX(dev))
intel_dvo_init(dev);
- if (IS_I9XX(dev) && IS_MOBILE(dev) && !IS_IGDNG(dev))
+ if (SUPPORTS_TV(dev))
intel_tv_init(dev);
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c
index 1d30802e773e..75a9b83fd7d3 100644
--- a/drivers/gpu/drm/i915/intel_fb.c
+++ b/drivers/gpu/drm/i915/intel_fb.c
@@ -114,7 +114,7 @@ static int intelfb_check_var(struct fb_var_screeninfo *var,
struct drm_framebuffer *fb = &intel_fb->base;
int depth;
- if (var->pixclock == -1 || !var->pixclock)
+ if (var->pixclock != 0)
return -EINVAL;
/* Need to resize the fb object !!! */
@@ -205,7 +205,7 @@ static int intelfb_set_par(struct fb_info *info)
DRM_DEBUG("%d %d\n", var->xres, var->pixclock);
- if (var->pixclock != -1) {
+ if (var->pixclock != 0) {
DRM_ERROR("PIXEL CLOCK SET\n");
return -EINVAL;
@@ -692,7 +692,7 @@ static int intelfb_multi_fb_probe_crtc(struct drm_device *dev, struct drm_crtc *
par->crtc_count = 1;
if (new_fb) {
- info->var.pixclock = -1;
+ info->var.pixclock = 0;
if (register_framebuffer(info) < 0)
return -EINVAL;
} else
@@ -846,7 +846,7 @@ static int intelfb_single_fb_probe(struct drm_device *dev)
par->crtc_count = crtc_count;
if (new_fb) {
- info->var.pixclock = -1;
+ info->var.pixclock = 0;
if (register_framebuffer(info) < 0)
return -EINVAL;
} else
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c
index 8df02ef89261..b7d091ba8c5c 100644
--- a/drivers/gpu/drm/i915/intel_lvds.c
+++ b/drivers/gpu/drm/i915/intel_lvds.c
@@ -305,6 +305,10 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
goto out;
}
+ /* full screen scale for now */
+ if (IS_IGDNG(dev))
+ goto out;
+
/* 965+ wants fuzzy fitting */
if (IS_I965G(dev))
pfit_control |= (intel_crtc->pipe << PFIT_PIPE_SHIFT) |
@@ -332,8 +336,10 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
* to register description and PRM.
* Change the value here to see the borders for debugging
*/
- I915_WRITE(BCLRPAT_A, 0);
- I915_WRITE(BCLRPAT_B, 0);
+ if (!IS_IGDNG(dev)) {
+ I915_WRITE(BCLRPAT_A, 0);
+ I915_WRITE(BCLRPAT_B, 0);
+ }
switch (lvds_priv->fitting_mode) {
case DRM_MODE_SCALE_NO_SCALE:
@@ -582,7 +588,6 @@ static void intel_lvds_mode_set(struct drm_encoder *encoder,
* settings.
*/
- /* No panel fitting yet, fixme */
if (IS_IGDNG(dev))
return;
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
index d3b74ba62b4a..66dc1a54cbf6 100644
--- a/drivers/gpu/drm/i915/intel_sdvo.c
+++ b/drivers/gpu/drm/i915/intel_sdvo.c
@@ -114,6 +114,9 @@ struct intel_sdvo_priv {
/* DDC bus used by this SDVO output */
uint8_t ddc_bus;
+ /* 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;
@@ -1478,6 +1481,36 @@ intel_sdvo_multifunc_encoder(struct intel_output *intel_output)
return (caps > 1);
}
+static struct drm_connector *
+intel_find_analog_connector(struct drm_device *dev)
+{
+ struct drm_connector *connector;
+ struct intel_output *intel_output;
+
+ list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+ intel_output = to_intel_output(connector);
+ if (intel_output->type == INTEL_OUTPUT_ANALOG)
+ return connector;
+ }
+ return NULL;
+}
+
+static int
+intel_analog_is_connected(struct drm_device *dev)
+{
+ struct drm_connector *analog_connector;
+ analog_connector = intel_find_analog_connector(dev);
+
+ if (!analog_connector)
+ return false;
+
+ if (analog_connector->funcs->detect(analog_connector) ==
+ connector_status_disconnected)
+ return false;
+
+ return true;
+}
+
enum drm_connector_status
intel_sdvo_hdmi_sink_detect(struct drm_connector *connector, u16 response)
{
@@ -1488,6 +1521,15 @@ intel_sdvo_hdmi_sink_detect(struct drm_connector *connector, u16 response)
edid = drm_get_edid(&intel_output->base,
intel_output->ddc_bus);
+
+ /* when there is no edid and no monitor is connected with VGA
+ * port, try to use the CRT ddc to read the EDID for DVI-connector
+ */
+ if (edid == NULL &&
+ sdvo_priv->analog_ddc_bus &&
+ !intel_analog_is_connected(intel_output->base.dev))
+ edid = drm_get_edid(&intel_output->base,
+ sdvo_priv->analog_ddc_bus);
if (edid != NULL) {
/* Don't report the output as connected if it's a DVI-I
* connector with a non-digital EDID coming out.
@@ -1540,31 +1582,32 @@ static enum drm_connector_status intel_sdvo_detect(struct drm_connector *connect
static void intel_sdvo_get_ddc_modes(struct drm_connector *connector)
{
struct intel_output *intel_output = to_intel_output(connector);
+ struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+ int num_modes;
/* set the bus switch and get the modes */
- intel_ddc_get_modes(intel_output);
+ num_modes = intel_ddc_get_modes(intel_output);
-#if 0
- struct drm_device *dev = encoder->dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- /* Mac mini hack. On this device, I get DDC through the analog, which
- * load-detects as disconnected. I fail to DDC through the SDVO DDC,
- * but it does load-detect as connected. So, just steal the DDC bits
- * from analog when we fail at finding it the right way.
+ /*
+ * Mac mini hack. On this device, the DVI-I connector shares one DDC
+ * link between analog and digital outputs. So, if the regular SDVO
+ * DDC fails, check to see if the analog output is disconnected, in
+ * which case we'll look there for the digital DDC data.
*/
- crt = xf86_config->output[0];
- intel_output = crt->driver_private;
- if (intel_output->type == I830_OUTPUT_ANALOG &&
- crt->funcs->detect(crt) == XF86OutputStatusDisconnected) {
- I830I2CInit(pScrn, &intel_output->pDDCBus, GPIOA, "CRTDDC_A");
- edid_mon = xf86OutputGetEDID(crt, intel_output->pDDCBus);
- xf86DestroyI2CBusRec(intel_output->pDDCBus, true, true);
- }
- if (edid_mon) {
- xf86OutputSetEDID(output, edid_mon);
- modes = xf86OutputGetEDIDModes(output);
+ if (num_modes == 0 &&
+ sdvo_priv->analog_ddc_bus &&
+ !intel_analog_is_connected(intel_output->base.dev)) {
+ struct i2c_adapter *digital_ddc_bus;
+
+ /* Switch to the analog ddc bus and try that
+ */
+ digital_ddc_bus = intel_output->ddc_bus;
+ intel_output->ddc_bus = sdvo_priv->analog_ddc_bus;
+
+ (void) intel_ddc_get_modes(intel_output);
+
+ intel_output->ddc_bus = digital_ddc_bus;
}
-#endif
}
/**
@@ -1748,6 +1791,8 @@ static void intel_sdvo_destroy(struct drm_connector *connector)
intel_i2c_destroy(intel_output->i2c_bus);
if (intel_output->ddc_bus)
intel_i2c_destroy(intel_output->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,
@@ -2074,10 +2119,15 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device)
}
/* setup the DDC bus. */
- if (output_device == SDVOB)
+ if (output_device == SDVOB) {
intel_output->ddc_bus = intel_i2c_create(dev, GPIOE, "SDVOB DDC BUS");
- else
+ sdvo_priv->analog_ddc_bus = intel_i2c_create(dev, GPIOA,
+ "SDVOB/VGA DDC BUS");
+ } else {
intel_output->ddc_bus = intel_i2c_create(dev, GPIOE, "SDVOC DDC BUS");
+ sdvo_priv->analog_ddc_bus = intel_i2c_create(dev, GPIOA,
+ "SDVOC/VGA DDC BUS");
+ }
if (intel_output->ddc_bus == NULL)
goto err_i2c;
@@ -2143,6 +2193,8 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device)
return true;
err_i2c:
+ if (sdvo_priv->analog_ddc_bus != NULL)
+ intel_i2c_destroy(sdvo_priv->analog_ddc_bus);
if (intel_output->ddc_bus != NULL)
intel_i2c_destroy(intel_output->ddc_bus);
if (intel_output->i2c_bus != NULL)
diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
index 5b1c9e9fdba0..05f6fe40f2e3 100644
--- a/drivers/gpu/drm/i915/intel_tv.c
+++ b/drivers/gpu/drm/i915/intel_tv.c
@@ -1212,20 +1212,17 @@ intel_tv_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
tv_ctl |= TV_TRILEVEL_SYNC;
if (tv_mode->pal_burst)
tv_ctl |= TV_PAL_BURST;
+
scctl1 = 0;
- /* dda1 implies valid video levels */
- if (tv_mode->dda1_inc) {
+ if (tv_mode->dda1_inc)
scctl1 |= TV_SC_DDA1_EN;
- }
-
if (tv_mode->dda2_inc)
scctl1 |= TV_SC_DDA2_EN;
-
if (tv_mode->dda3_inc)
scctl1 |= TV_SC_DDA3_EN;
-
scctl1 |= tv_mode->sc_reset;
- scctl1 |= video_levels->burst << TV_BURST_LEVEL_SHIFT;
+ if (video_levels)
+ scctl1 |= video_levels->burst << TV_BURST_LEVEL_SHIFT;
scctl1 |= tv_mode->dda1_inc << TV_SCDDA1_INC_SHIFT;
scctl2 = tv_mode->dda2_size << TV_SCDDA2_SIZE_SHIFT |