Commit d0aaa283 authored by Dave Airlie's avatar Dave Airlie

Merge tag 'drm-intel-fixes-2013-07-03' of...

Merge tag 'drm-intel-fixes-2013-07-03' of git://people.freedesktop.org/~danvet/drm-intel into drm-next

Pile of fixes for 3.11. A bit large in patch count, but that's simply due
to two fixes being split up into really small parts. Also I've included a
few more vlv patches than I'd have included for other platforms. But since
vlv is officially supported for the first time only in 3.11 that shouldn't
result in unbearable risks.

Highlights:
- ghost eDP fixes for hsw from Paulo
- fix PCH detection in virtualized enviroments (Rui Guo)
- duct-tape dma sg construction when swiotlb is in use (Konrad), dupe with
  a patch in your drm-fixes branch
- fix sdvo hotplug on i965g
- tune down a bunch of dmesg ERRORs which can be hit under normal
  conditions
- detect invalid pitches for tiled scanout buffers (Chris)
- a pile of vlv fixes from Ville: rps improvements, fixes for the dpll
  LPF, fixup the sprite mmio offsets
- fix context size on hsw (Ben)
- locking fixes for the hotplug code, specifically the storm handling
- fix get_config on CPT (Xiong Zhang)
- Fix the domain tracking when an unlocked seqno wait was interrupt
  (Chris), this seems to explain tons of little corruption bugs in the
  ddx. Chris also added a nice igt to exercise this.
- work around stack-corrupting vnsprintf in our error state dumper

* tag 'drm-intel-fixes-2013-07-03' of git://people.freedesktop.org/~danvet/drm-intel: (39 commits)
  drm/i915: Don't try to tear down the stolen drm_mm if it's not there
  drm/i915: Break up the large vsnprintf() in print_error_buffers()
  drm/i915: Refactor the wait_rendering completion into a common routine
  drm/i915: Only clear write-domains after a successful wait-seqno
  drm/i915: correct intel_dp_get_config() function for DevCPT
  drm/i915: fix hpd interrupt register locking
  drm/i915: fold the no-irq check into intel_hpd_irq_handler
  drm/i915: fold the queue_work into intel_hpd_irq_handler
  drm/i915: fold the hpd_irq_setup call into intel_hpd_irq_handler
  drm/i915: s/hotplug_irq_storm_detect/intel_hpd_irq_handler/
  drm/i915: close tiny race in the ilk pcu even interrupt setup
  drm/i915: fix locking around ironlake_enable|disable_display_irq
  drm/i915: Fix context sizes on HSW
  drm/i915: Fix VLV sprite register offsets
  Revert "drm/i915: Don't use the HDMI port color range bit on Valleyview"
  drm/i915: s/LFP/LPF in DPIO PLL register names
  drm/i915: Fix VLV PLL LPF coefficients for DAC
  drm/i915: Jump to at least RPe on VLV when increasing the GPU frequency
  drm/i915: Don't increase the GPU frequency from the delayed VLV rps timer
  drm/i915: GEN6_RP_INTERRUPT_LIMITS doesn't seem to exist on VLV
  ...
parents 1586ba72 446f8d81
...@@ -647,41 +647,44 @@ static const char *purgeable_flag(int purgeable) ...@@ -647,41 +647,44 @@ static const char *purgeable_flag(int purgeable)
return purgeable ? " purgeable" : ""; return purgeable ? " purgeable" : "";
} }
static void i915_error_vprintf(struct drm_i915_error_state_buf *e, static bool __i915_error_ok(struct drm_i915_error_state_buf *e)
const char *f, va_list args)
{ {
unsigned len;
if (!e->err && WARN(e->bytes > (e->size - 1), "overflow")) { if (!e->err && WARN(e->bytes > (e->size - 1), "overflow")) {
e->err = -ENOSPC; e->err = -ENOSPC;
return; return false;
} }
if (e->bytes == e->size - 1 || e->err) if (e->bytes == e->size - 1 || e->err)
return; return false;
/* Seek the first printf which is hits start position */ return true;
if (e->pos < e->start) { }
len = vsnprintf(NULL, 0, f, args);
if (e->pos + len <= e->start) {
e->pos += len;
return;
}
/* First vsnprintf needs to fit in full for memmove*/ static bool __i915_error_seek(struct drm_i915_error_state_buf *e,
if (len >= e->size) { unsigned len)
e->err = -EIO; {
return; if (e->pos + len <= e->start) {
} e->pos += len;
return false;
} }
len = vsnprintf(e->buf + e->bytes, e->size - e->bytes, f, args); /* First vsnprintf needs to fit in its entirety for memmove */
if (len >= e->size - e->bytes) if (len >= e->size) {
len = e->size - e->bytes - 1; e->err = -EIO;
return false;
}
return true;
}
static void __i915_error_advance(struct drm_i915_error_state_buf *e,
unsigned len)
{
/* If this is first printf in this window, adjust it so that /* If this is first printf in this window, adjust it so that
* start position matches start of the buffer * start position matches start of the buffer
*/ */
if (e->pos < e->start) { if (e->pos < e->start) {
const size_t off = e->start - e->pos; const size_t off = e->start - e->pos;
...@@ -701,6 +704,51 @@ static void i915_error_vprintf(struct drm_i915_error_state_buf *e, ...@@ -701,6 +704,51 @@ static void i915_error_vprintf(struct drm_i915_error_state_buf *e,
e->pos += len; e->pos += len;
} }
static void i915_error_vprintf(struct drm_i915_error_state_buf *e,
const char *f, va_list args)
{
unsigned len;
if (!__i915_error_ok(e))
return;
/* Seek the first printf which is hits start position */
if (e->pos < e->start) {
len = vsnprintf(NULL, 0, f, args);
if (!__i915_error_seek(e, len))
return;
}
len = vsnprintf(e->buf + e->bytes, e->size - e->bytes, f, args);
if (len >= e->size - e->bytes)
len = e->size - e->bytes - 1;
__i915_error_advance(e, len);
}
static void i915_error_puts(struct drm_i915_error_state_buf *e,
const char *str)
{
unsigned len;
if (!__i915_error_ok(e))
return;
len = strlen(str);
/* Seek the first printf which is hits start position */
if (e->pos < e->start) {
if (!__i915_error_seek(e, len))
return;
}
if (len >= e->size - e->bytes)
len = e->size - e->bytes - 1;
memcpy(e->buf + e->bytes, str, len);
__i915_error_advance(e, len);
}
void i915_error_printf(struct drm_i915_error_state_buf *e, const char *f, ...) void i915_error_printf(struct drm_i915_error_state_buf *e, const char *f, ...)
{ {
va_list args; va_list args;
...@@ -711,6 +759,7 @@ void i915_error_printf(struct drm_i915_error_state_buf *e, const char *f, ...) ...@@ -711,6 +759,7 @@ void i915_error_printf(struct drm_i915_error_state_buf *e, const char *f, ...)
} }
#define err_printf(e, ...) i915_error_printf(e, __VA_ARGS__) #define err_printf(e, ...) i915_error_printf(e, __VA_ARGS__)
#define err_puts(e, s) i915_error_puts(e, s)
static void print_error_buffers(struct drm_i915_error_state_buf *m, static void print_error_buffers(struct drm_i915_error_state_buf *m,
const char *name, const char *name,
...@@ -720,26 +769,26 @@ static void print_error_buffers(struct drm_i915_error_state_buf *m, ...@@ -720,26 +769,26 @@ static void print_error_buffers(struct drm_i915_error_state_buf *m,
err_printf(m, "%s [%d]:\n", name, count); err_printf(m, "%s [%d]:\n", name, count);
while (count--) { while (count--) {
err_printf(m, " %08x %8u %02x %02x %x %x%s%s%s%s%s%s%s", err_printf(m, " %08x %8u %02x %02x %x %x",
err->gtt_offset, err->gtt_offset,
err->size, err->size,
err->read_domains, err->read_domains,
err->write_domain, err->write_domain,
err->rseqno, err->wseqno, err->rseqno, err->wseqno);
pin_flag(err->pinned), err_puts(m, pin_flag(err->pinned));
tiling_flag(err->tiling), err_puts(m, tiling_flag(err->tiling));
dirty_flag(err->dirty), err_puts(m, dirty_flag(err->dirty));
purgeable_flag(err->purgeable), err_puts(m, purgeable_flag(err->purgeable));
err->ring != -1 ? " " : "", err_puts(m, err->ring != -1 ? " " : "");
ring_str(err->ring), err_puts(m, ring_str(err->ring));
cache_level_str(err->cache_level)); err_puts(m, cache_level_str(err->cache_level));
if (err->name) if (err->name)
err_printf(m, " (name: %d)", err->name); err_printf(m, " (name: %d)", err->name);
if (err->fence_reg != I915_FENCE_REG_NONE) if (err->fence_reg != I915_FENCE_REG_NONE)
err_printf(m, " (fence: %d)", err->fence_reg); err_printf(m, " (fence: %d)", err->fence_reg);
err_printf(m, "\n"); err_puts(m, "\n");
err++; err++;
} }
} }
...@@ -1483,7 +1532,7 @@ static int i915_ips_status(struct seq_file *m, void *unused) ...@@ -1483,7 +1532,7 @@ static int i915_ips_status(struct seq_file *m, void *unused)
struct drm_device *dev = node->minor->dev; struct drm_device *dev = node->minor->dev;
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
if (!IS_ULT(dev)) { if (!HAS_IPS(dev)) {
seq_puts(m, "not supported\n"); seq_puts(m, "not supported\n");
return 0; return 0;
} }
...@@ -1862,10 +1911,10 @@ static int i915_dpio_info(struct seq_file *m, void *data) ...@@ -1862,10 +1911,10 @@ static int i915_dpio_info(struct seq_file *m, void *data)
seq_printf(m, "DPIO_CORE_CLK_B: 0x%08x\n", seq_printf(m, "DPIO_CORE_CLK_B: 0x%08x\n",
vlv_dpio_read(dev_priv, _DPIO_CORE_CLK_B)); vlv_dpio_read(dev_priv, _DPIO_CORE_CLK_B));
seq_printf(m, "DPIO_LFP_COEFF_A: 0x%08x\n", seq_printf(m, "DPIO_LPF_COEFF_A: 0x%08x\n",
vlv_dpio_read(dev_priv, _DPIO_LFP_COEFF_A)); vlv_dpio_read(dev_priv, _DPIO_LPF_COEFF_A));
seq_printf(m, "DPIO_LFP_COEFF_B: 0x%08x\n", seq_printf(m, "DPIO_LPF_COEFF_B: 0x%08x\n",
vlv_dpio_read(dev_priv, _DPIO_LFP_COEFF_B)); vlv_dpio_read(dev_priv, _DPIO_LPF_COEFF_B));
seq_printf(m, "DPIO_FASTCLK_DISABLE: 0x%08x\n", seq_printf(m, "DPIO_FASTCLK_DISABLE: 0x%08x\n",
vlv_dpio_read(dev_priv, DPIO_FASTCLK_DISABLE)); vlv_dpio_read(dev_priv, DPIO_FASTCLK_DISABLE));
......
...@@ -465,9 +465,15 @@ void intel_detect_pch(struct drm_device *dev) ...@@ -465,9 +465,15 @@ void intel_detect_pch(struct drm_device *dev)
* make graphics device passthrough work easy for VMM, that only * make graphics device passthrough work easy for VMM, that only
* need to expose ISA bridge to let driver know the real hardware * need to expose ISA bridge to let driver know the real hardware
* underneath. This is a requirement from virtualization team. * underneath. This is a requirement from virtualization team.
*
* In some virtualized environments (e.g. XEN), there is irrelevant
* ISA bridge in the system. To work reliably, we should scan trhough
* all the ISA bridge devices and check for the first match, instead
* of only checking the first one.
*/ */
pch = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, NULL); pch = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, NULL);
if (pch) { while (pch) {
struct pci_dev *curr = pch;
if (pch->vendor == PCI_VENDOR_ID_INTEL) { if (pch->vendor == PCI_VENDOR_ID_INTEL) {
unsigned short id; unsigned short id;
id = pch->device & INTEL_PCH_DEVICE_ID_MASK; id = pch->device & INTEL_PCH_DEVICE_ID_MASK;
...@@ -496,10 +502,18 @@ void intel_detect_pch(struct drm_device *dev) ...@@ -496,10 +502,18 @@ void intel_detect_pch(struct drm_device *dev)
DRM_DEBUG_KMS("Found LynxPoint LP PCH\n"); DRM_DEBUG_KMS("Found LynxPoint LP PCH\n");
WARN_ON(!IS_HASWELL(dev)); WARN_ON(!IS_HASWELL(dev));
WARN_ON(!IS_ULT(dev)); WARN_ON(!IS_ULT(dev));
} else {
goto check_next;
} }
pci_dev_put(pch);
break;
} }
pci_dev_put(pch); check_next:
pch = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, curr);
pci_dev_put(curr);
} }
if (!pch)
DRM_DEBUG_KMS("No PCH found?\n");
} }
bool i915_semaphore_is_enabled(struct drm_device *dev) bool i915_semaphore_is_enabled(struct drm_device *dev)
......
...@@ -1474,6 +1474,8 @@ struct drm_i915_file_private { ...@@ -1474,6 +1474,8 @@ struct drm_i915_file_private {
#define HAS_PIPE_CXSR(dev) (INTEL_INFO(dev)->has_pipe_cxsr) #define HAS_PIPE_CXSR(dev) (INTEL_INFO(dev)->has_pipe_cxsr)
#define I915_HAS_FBC(dev) (INTEL_INFO(dev)->has_fbc) #define I915_HAS_FBC(dev) (INTEL_INFO(dev)->has_fbc)
#define HAS_IPS(dev) (IS_ULT(dev))
#define HAS_PIPE_CONTROL(dev) (INTEL_INFO(dev)->gen >= 5) #define HAS_PIPE_CONTROL(dev) (INTEL_INFO(dev)->gen >= 5)
#define HAS_DDI(dev) (INTEL_INFO(dev)->has_ddi) #define HAS_DDI(dev) (INTEL_INFO(dev)->has_ddi)
......
...@@ -1087,6 +1087,25 @@ i915_wait_seqno(struct intel_ring_buffer *ring, uint32_t seqno) ...@@ -1087,6 +1087,25 @@ i915_wait_seqno(struct intel_ring_buffer *ring, uint32_t seqno)
interruptible, NULL); interruptible, NULL);
} }
static int
i915_gem_object_wait_rendering__tail(struct drm_i915_gem_object *obj,
struct intel_ring_buffer *ring)
{
i915_gem_retire_requests_ring(ring);
/* Manually manage the write flush as we may have not yet
* retired the buffer.
*
* Note that the last_write_seqno is always the earlier of
* the two (read/write) seqno, so if we haved successfully waited,
* we know we have passed the last write.
*/
obj->last_write_seqno = 0;
obj->base.write_domain &= ~I915_GEM_GPU_DOMAINS;
return 0;
}
/** /**
* Ensures that all rendering to the object has completed and the object is * Ensures that all rendering to the object has completed and the object is
* safe to unbind from the GTT or access from the CPU. * safe to unbind from the GTT or access from the CPU.
...@@ -1107,18 +1126,7 @@ i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj, ...@@ -1107,18 +1126,7 @@ i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj,
if (ret) if (ret)
return ret; return ret;
i915_gem_retire_requests_ring(ring); return i915_gem_object_wait_rendering__tail(obj, ring);
/* Manually manage the write flush as we may have not yet
* retired the buffer.
*/
if (obj->last_write_seqno &&
i915_seqno_passed(seqno, obj->last_write_seqno)) {
obj->last_write_seqno = 0;
obj->base.write_domain &= ~I915_GEM_GPU_DOMAINS;
}
return 0;
} }
/* A nonblocking variant of the above wait. This is a highly dangerous routine /* A nonblocking variant of the above wait. This is a highly dangerous routine
...@@ -1154,19 +1162,10 @@ i915_gem_object_wait_rendering__nonblocking(struct drm_i915_gem_object *obj, ...@@ -1154,19 +1162,10 @@ i915_gem_object_wait_rendering__nonblocking(struct drm_i915_gem_object *obj,
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
ret = __wait_seqno(ring, seqno, reset_counter, true, NULL); ret = __wait_seqno(ring, seqno, reset_counter, true, NULL);
mutex_lock(&dev->struct_mutex); mutex_lock(&dev->struct_mutex);
if (ret)
return ret;
i915_gem_retire_requests_ring(ring); return i915_gem_object_wait_rendering__tail(obj, ring);
/* Manually manage the write flush as we may have not yet
* retired the buffer.
*/
if (obj->last_write_seqno &&
i915_seqno_passed(seqno, obj->last_write_seqno)) {
obj->last_write_seqno = 0;
obj->base.write_domain &= ~I915_GEM_GPU_DOMAINS;
}
return ret;
} }
/** /**
...@@ -1802,7 +1801,14 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj) ...@@ -1802,7 +1801,14 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj)
gfp |= __GFP_NORETRY | __GFP_NOWARN | __GFP_NO_KSWAPD; gfp |= __GFP_NORETRY | __GFP_NOWARN | __GFP_NO_KSWAPD;
gfp &= ~(__GFP_IO | __GFP_WAIT); gfp &= ~(__GFP_IO | __GFP_WAIT);
} }
#ifdef CONFIG_SWIOTLB
if (swiotlb_nr_tbl()) {
st->nents++;
sg_set_page(sg, page, PAGE_SIZE, 0);
sg = sg_next(sg);
continue;
}
#endif
if (!i || page_to_pfn(page) != last_pfn + 1) { if (!i || page_to_pfn(page) != last_pfn + 1) {
if (i) if (i)
sg = sg_next(sg); sg = sg_next(sg);
...@@ -1813,8 +1819,10 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj) ...@@ -1813,8 +1819,10 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj)
} }
last_pfn = page_to_pfn(page); last_pfn = page_to_pfn(page);
} }
#ifdef CONFIG_SWIOTLB
sg_mark_end(sg); if (!swiotlb_nr_tbl())
#endif
sg_mark_end(sg);
obj->pages = st; obj->pages = st;
if (i915_gem_object_needs_bit17_swizzle(obj)) if (i915_gem_object_needs_bit17_swizzle(obj))
...@@ -3103,7 +3111,7 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj, ...@@ -3103,7 +3111,7 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj,
* before evicting everything in a vain attempt to find space. * before evicting everything in a vain attempt to find space.
*/ */
if (obj->base.size > gtt_max) { if (obj->base.size > gtt_max) {
DRM_ERROR("Attempting to bind an object larger than the aperture: object=%zd > %s aperture=%ld\n", DRM_ERROR("Attempting to bind an object larger than the aperture: object=%zd > %s aperture=%zu\n",
obj->base.size, obj->base.size,
map_and_fenceable ? "mappable" : "total", map_and_fenceable ? "mappable" : "total",
gtt_max); gtt_max);
......
...@@ -113,7 +113,7 @@ static int get_context_size(struct drm_device *dev) ...@@ -113,7 +113,7 @@ static int get_context_size(struct drm_device *dev)
case 7: case 7:
reg = I915_READ(GEN7_CXT_SIZE); reg = I915_READ(GEN7_CXT_SIZE);
if (IS_HASWELL(dev)) if (IS_HASWELL(dev))
ret = HSW_CXT_TOTAL_SIZE(reg) * 64; ret = HSW_CXT_TOTAL_SIZE;
else else
ret = GEN7_CXT_TOTAL_SIZE(reg) * 64; ret = GEN7_CXT_TOTAL_SIZE(reg) * 64;
break; break;
......
...@@ -147,7 +147,7 @@ int i915_gem_stolen_setup_compression(struct drm_device *dev, int size) ...@@ -147,7 +147,7 @@ int i915_gem_stolen_setup_compression(struct drm_device *dev, int size)
{ {
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
if (dev_priv->mm.stolen_base == 0) if (!drm_mm_initialized(&dev_priv->mm.stolen))
return -ENODEV; return -ENODEV;
if (size < dev_priv->cfb_size) if (size < dev_priv->cfb_size)
...@@ -179,6 +179,9 @@ void i915_gem_cleanup_stolen(struct drm_device *dev) ...@@ -179,6 +179,9 @@ void i915_gem_cleanup_stolen(struct drm_device *dev)
{ {
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
if (!drm_mm_initialized(&dev_priv->mm.stolen))
return;
i915_gem_stolen_cleanup_compression(dev); i915_gem_stolen_cleanup_compression(dev);
drm_mm_takedown(&dev_priv->mm.stolen); drm_mm_takedown(&dev_priv->mm.stolen);
} }
...@@ -300,7 +303,7 @@ i915_gem_object_create_stolen(struct drm_device *dev, u32 size) ...@@ -300,7 +303,7 @@ i915_gem_object_create_stolen(struct drm_device *dev, u32 size)
struct drm_i915_gem_object *obj; struct drm_i915_gem_object *obj;
struct drm_mm_node *stolen; struct drm_mm_node *stolen;
if (dev_priv->mm.stolen_base == 0) if (!drm_mm_initialized(&dev_priv->mm.stolen))
return NULL; return NULL;
DRM_DEBUG_KMS("creating stolen object: size=%x\n", size); DRM_DEBUG_KMS("creating stolen object: size=%x\n", size);
...@@ -331,7 +334,7 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_device *dev, ...@@ -331,7 +334,7 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_device *dev,
struct drm_i915_gem_object *obj; struct drm_i915_gem_object *obj;
struct drm_mm_node *stolen; struct drm_mm_node *stolen;
if (dev_priv->mm.stolen_base == 0) if (!drm_mm_initialized(&dev_priv->mm.stolen))
return NULL; return NULL;
DRM_DEBUG_KMS("creating preallocated stolen object: stolen_offset=%x, gtt_offset=%x, size=%x\n", DRM_DEBUG_KMS("creating preallocated stolen object: stolen_offset=%x, gtt_offset=%x, size=%x\n",
......
...@@ -70,15 +70,6 @@ static const u32 hpd_status_gen4[] = { ...@@ -70,15 +70,6 @@ static const u32 hpd_status_gen4[] = {
[HPD_PORT_D] = PORTD_HOTPLUG_INT_STATUS [HPD_PORT_D] = PORTD_HOTPLUG_INT_STATUS
}; };
static const u32 hpd_status_i965[] = {
[HPD_CRT] = CRT_HOTPLUG_INT_STATUS,
[HPD_SDVO_B] = SDVOB_HOTPLUG_INT_STATUS_I965,
[HPD_SDVO_C] = SDVOC_HOTPLUG_INT_STATUS_I965,
[HPD_PORT_B] = PORTB_HOTPLUG_INT_STATUS,
[HPD_PORT_C] = PORTC_HOTPLUG_INT_STATUS,
[HPD_PORT_D] = PORTD_HOTPLUG_INT_STATUS
};
static const u32 hpd_status_i915[] = { /* i915 and valleyview are the same */ static const u32 hpd_status_i915[] = { /* i915 and valleyview are the same */
[HPD_CRT] = CRT_HOTPLUG_INT_STATUS, [HPD_CRT] = CRT_HOTPLUG_INT_STATUS,
[HPD_SDVO_B] = SDVOB_HOTPLUG_INT_STATUS_I915, [HPD_SDVO_B] = SDVOB_HOTPLUG_INT_STATUS_I915,
...@@ -88,13 +79,12 @@ static const u32 hpd_status_i915[] = { /* i915 and valleyview are the same */ ...@@ -88,13 +79,12 @@ static const u32 hpd_status_i915[] = { /* i915 and valleyview are the same */
[HPD_PORT_D] = PORTD_HOTPLUG_INT_STATUS [HPD_PORT_D] = PORTD_HOTPLUG_INT_STATUS
}; };
static void ibx_hpd_irq_setup(struct drm_device *dev);
static void i915_hpd_irq_setup(struct drm_device *dev);
/* For display hotplug interrupt */ /* For display hotplug interrupt */
static void static void
ironlake_enable_display_irq(drm_i915_private_t *dev_priv, u32 mask) ironlake_enable_display_irq(drm_i915_private_t *dev_priv, u32 mask)
{ {
assert_spin_locked(&dev_priv->irq_lock);
if ((dev_priv->irq_mask & mask) != 0) { if ((dev_priv->irq_mask & mask) != 0) {
dev_priv->irq_mask &= ~mask; dev_priv->irq_mask &= ~mask;
I915_WRITE(DEIMR, dev_priv->irq_mask); I915_WRITE(DEIMR, dev_priv->irq_mask);
...@@ -105,6 +95,8 @@ ironlake_enable_display_irq(drm_i915_private_t *dev_priv, u32 mask) ...@@ -105,6 +95,8 @@ ironlake_enable_display_irq(drm_i915_private_t *dev_priv, u32 mask)
static void static void
ironlake_disable_display_irq(drm_i915_private_t *dev_priv, u32 mask) ironlake_disable_display_irq(drm_i915_private_t *dev_priv, u32 mask)
{ {
assert_spin_locked(&dev_priv->irq_lock);
if ((dev_priv->irq_mask & mask) != mask) { if ((dev_priv->irq_mask & mask) != mask) {
dev_priv->irq_mask |= mask; dev_priv->irq_mask |= mask;
I915_WRITE(DEIMR, dev_priv->irq_mask); I915_WRITE(DEIMR, dev_priv->irq_mask);
...@@ -118,6 +110,8 @@ static bool ivb_can_enable_err_int(struct drm_device *dev) ...@@ -118,6 +110,8 @@ static bool ivb_can_enable_err_int(struct drm_device *dev)
struct intel_crtc *crtc; struct intel_crtc *crtc;
enum pipe pipe; enum pipe pipe;
assert_spin_locked(&dev_priv->irq_lock);
for_each_pipe(pipe) { for_each_pipe(pipe) {
crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]); crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
...@@ -708,16 +702,24 @@ static void gen6_pm_rps_work(struct work_struct *work) ...@@ -708,16 +702,24 @@ static void gen6_pm_rps_work(struct work_struct *work)
mutex_lock(&dev_priv->rps.hw_lock); mutex_lock(&dev_priv->rps.hw_lock);
if (pm_iir & GEN6_PM_RP_UP_THRESHOLD) if (pm_iir & GEN6_PM_RP_UP_THRESHOLD) {
new_delay = dev_priv->rps.cur_delay + 1; new_delay = dev_priv->rps.cur_delay + 1;
else
/*
* For better performance, jump directly
* to RPe if we're below it.
*/
if (IS_VALLEYVIEW(dev_priv->dev) &&
dev_priv->rps.cur_delay < dev_priv->rps.rpe_delay)
new_delay = dev_priv->rps.rpe_delay;
} else
new_delay = dev_priv->rps.cur_delay - 1; new_delay = dev_priv->rps.cur_delay - 1;
/* sysfs frequency interfaces may have snuck in while servicing the /* sysfs frequency interfaces may have snuck in while servicing the
* interrupt * interrupt
*/ */
if (!(new_delay > dev_priv->rps.max_delay || if (new_delay >= dev_priv->rps.min_delay &&
new_delay < dev_priv->rps.min_delay)) { new_delay <= dev_priv->rps.max_delay) {
if (IS_VALLEYVIEW(dev_priv->dev)) if (IS_VALLEYVIEW(dev_priv->dev))
valleyview_set_rps(dev_priv->dev, new_delay); valleyview_set_rps(dev_priv->dev, new_delay);
else else
...@@ -870,17 +872,18 @@ static void gen6_queue_rps_work(struct drm_i915_private *dev_priv, ...@@ -870,17 +872,18 @@ static void gen6_queue_rps_work(struct drm_i915_private *dev_priv,
#define HPD_STORM_DETECT_PERIOD 1000 #define HPD_STORM_DETECT_PERIOD 1000
#define HPD_STORM_THRESHOLD 5 #define HPD_STORM_THRESHOLD 5
static inline bool hotplug_irq_storm_detect(struct drm_device *dev, static inline void intel_hpd_irq_handler(struct drm_device *dev,
u32 hotplug_trigger, u32 hotplug_trigger,
const u32 *hpd) const u32 *hpd)
{ {
drm_i915_private_t *dev_priv = dev->dev_private; drm_i915_private_t *dev_priv = dev->dev_private;
unsigned long irqflags;
int i; int i;
bool ret = false; bool storm_detected = false;
spin_lock_irqsave(&dev_priv->irq_lock, irqflags); if (!hotplug_trigger)
return;
spin_lock(&dev_priv->irq_lock);
for (i = 1; i < HPD_NUM_PINS; i++) { for (i = 1; i < HPD_NUM_PINS; i++) {
if (!(hpd[i] & hotplug_trigger) || if (!(hpd[i] & hotplug_trigger) ||
...@@ -897,15 +900,18 @@ static inline bool hotplug_irq_storm_detect(struct drm_device *dev, ...@@ -897,15 +900,18 @@ static inline bool hotplug_irq_storm_detect(struct drm_device *dev,
dev_priv->hpd_stats[i].hpd_mark = HPD_MARK_DISABLED; dev_priv->hpd_stats[i].hpd_mark = HPD_MARK_DISABLED;
dev_priv->hpd_event_bits &= ~(1 << i); dev_priv->hpd_event_bits &= ~(1 << i);
DRM_DEBUG_KMS("HPD interrupt storm detected on PIN %d\n", i); DRM_DEBUG_KMS("HPD interrupt storm detected on PIN %d\n", i);
ret = true; storm_detected = true;
} else { } else {
dev_priv->hpd_stats[i].hpd_cnt++; dev_priv->hpd_stats[i].hpd_cnt++;
} }
} }
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); if (storm_detected)
dev_priv->display.hpd_irq_setup(dev);
spin_unlock(&dev_priv->irq_lock);
return ret; queue_work(dev_priv->wq,
&dev_priv->hotplug_work);
} }
static void gmbus_irq_handler(struct drm_device *dev) static void gmbus_irq_handler(struct drm_device *dev)
...@@ -1012,12 +1018,9 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg) ...@@ -1012,12 +1018,9 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)
DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n", DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
hotplug_status); hotplug_status);
if (hotplug_trigger) {
if (hotplug_irq_storm_detect(dev, hotplug_trigger, hpd_status_i915)) intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915);
i915_hpd_irq_setup(dev);
queue_work(dev_priv->wq,
&dev_priv->hotplug_work);
}
I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status); I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
I915_READ(PORT_HOTPLUG_STAT); I915_READ(PORT_HOTPLUG_STAT);
} }
...@@ -1043,11 +1046,8 @@ static void ibx_irq_handler(struct drm_device *dev, u32 pch_iir) ...@@ -1043,11 +1046,8 @@ static void ibx_irq_handler(struct drm_device *dev, u32 pch_iir)
int pipe; int pipe;
u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK; u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK;
if (hotplug_trigger) { intel_hpd_irq_handler(dev, hotplug_trigger, hpd_ibx);
if (hotplug_irq_storm_detect(dev, hotplug_trigger, hpd_ibx))
ibx_hpd_irq_setup(dev);
queue_work(dev_priv->wq, &dev_priv->hotplug_work);
}
if (pch_iir & SDE_AUDIO_POWER_MASK) { if (pch_iir & SDE_AUDIO_POWER_MASK) {
int port = ffs((pch_iir & SDE_AUDIO_POWER_MASK) >> int port = ffs((pch_iir & SDE_AUDIO_POWER_MASK) >>
SDE_AUDIO_POWER_SHIFT); SDE_AUDIO_POWER_SHIFT);
...@@ -1148,11 +1148,8 @@ static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir) ...@@ -1148,11 +1148,8 @@ static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir)
int pipe; int pipe;
u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK_CPT; u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK_CPT;
if (hotplug_trigger) { intel_hpd_irq_handler(dev, hotplug_trigger, hpd_cpt);
if (hotplug_irq_storm_detect(dev, hotplug_trigger, hpd_cpt))
ibx_hpd_irq_setup(dev);
queue_work(dev_priv->wq, &dev_priv->hotplug_work);
}
if (pch_iir & SDE_AUDIO_POWER_MASK_CPT) { if (pch_iir & SDE_AUDIO_POWER_MASK_CPT) {
int port = ffs((pch_iir & SDE_AUDIO_POWER_MASK_CPT) >> int port = ffs((pch_iir & SDE_AUDIO_POWER_MASK_CPT) >>
SDE_AUDIO_POWER_SHIFT_CPT); SDE_AUDIO_POWER_SHIFT_CPT);
...@@ -1218,8 +1215,11 @@ static irqreturn_t ivybridge_irq_handler(int irq, void *arg) ...@@ -1218,8 +1215,11 @@ static irqreturn_t ivybridge_irq_handler(int irq, void *arg)
/* On Haswell, also mask ERR_INT because we don't want to risk /* On Haswell, also mask ERR_INT because we don't want to risk
* generating "unclaimed register" interrupts from inside the interrupt * generating "unclaimed register" interrupts from inside the interrupt
* handler. */ * handler. */
if (IS_HASWELL(dev)) if (IS_HASWELL(dev)) {
spin_lock(&dev_priv->irq_lock);
ironlake_disable_display_irq(dev_priv, DE_ERR_INT_IVB); ironlake_disable_display_irq(dev_priv, DE_ERR_INT_IVB);
spin_unlock(&dev_priv->irq_lock);
}
gt_iir = I915_READ(GTIIR); gt_iir = I915_READ(GTIIR);
if (gt_iir) { if (gt_iir) {
...@@ -1272,8 +1272,12 @@ static irqreturn_t ivybridge_irq_handler(int irq, void *arg) ...@@ -1272,8 +1272,12 @@ static irqreturn_t ivybridge_irq_handler(int irq, void *arg)
ret = IRQ_HANDLED; ret = IRQ_HANDLED;
} }
if (IS_HASWELL(dev) && ivb_can_enable_err_int(dev)) if (IS_HASWELL(dev)) {
ironlake_enable_display_irq(dev_priv, DE_ERR_INT_IVB); spin_lock(&dev_priv->irq_lock);
if (ivb_can_enable_err_int(dev))
ironlake_enable_display_irq(dev_priv, DE_ERR_INT_IVB);
spin_unlock(&dev_priv->irq_lock);
}
I915_WRITE(DEIER, de_ier); I915_WRITE(DEIER, de_ier);
POSTING_READ(DEIER); POSTING_READ(DEIER);
...@@ -2698,6 +2702,8 @@ static void ibx_irq_postinstall(struct drm_device *dev) ...@@ -2698,6 +2702,8 @@ static void ibx_irq_postinstall(struct drm_device *dev)
static int ironlake_irq_postinstall(struct drm_device *dev) static int ironlake_irq_postinstall(struct drm_device *dev)
{ {
unsigned long irqflags;
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;
/* enable kind of interrupts always enabled */ /* enable kind of interrupts always enabled */
u32 display_mask = DE_MASTER_IRQ_CONTROL | DE_GSE | DE_PCH_EVENT | u32 display_mask = DE_MASTER_IRQ_CONTROL | DE_GSE | DE_PCH_EVENT |
...@@ -2711,7 +2717,8 @@ static int ironlake_irq_postinstall(struct drm_device *dev) ...@@ -2711,7 +2717,8 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
/* should always can generate irq */ /* should always can generate irq */
I915_WRITE(DEIIR, I915_READ(DEIIR)); I915_WRITE(DEIIR, I915_READ(DEIIR));
I915_WRITE(DEIMR, dev_priv->irq_mask); I915_WRITE(DEIMR, dev_priv->irq_mask);
I915_WRITE(DEIER, display_mask | DE_PIPEA_VBLANK | DE_PIPEB_VBLANK); I915_WRITE(DEIER, display_mask |
DE_PIPEA_VBLANK | DE_PIPEB_VBLANK | DE_PCU_EVENT);
POSTING_READ(DEIER); POSTING_READ(DEIER);
dev_priv->gt_irq_mask = ~0; dev_priv->gt_irq_mask = ~0;
...@@ -2733,10 +2740,14 @@ static int ironlake_irq_postinstall(struct drm_device *dev) ...@@ -2733,10 +2740,14 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
ibx_irq_postinstall(dev); ibx_irq_postinstall(dev);
if (IS_IRONLAKE_M(dev)) { if (IS_IRONLAKE_M(dev)) {
/* Clear & enable PCU event interrupts */ /* Enable PCU event interrupts
I915_WRITE(DEIIR, DE_PCU_EVENT); *
I915_WRITE(DEIER, I915_READ(DEIER) | DE_PCU_EVENT); * spinlocking not required here for correctness since interrupt
* setup is guaranteed to run in single-threaded context. But we
* need it to make the assert_spin_locked happy. */
spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
ironlake_enable_display_irq(dev_priv, DE_PCU_EVENT); ironlake_enable_display_irq(dev_priv, DE_PCU_EVENT);
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
} }
return 0; return 0;
...@@ -3212,12 +3223,9 @@ static irqreturn_t i915_irq_handler(int irq, void *arg) ...@@ -3212,12 +3223,9 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n", DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
hotplug_status); hotplug_status);
if (hotplug_trigger) {
if (hotplug_irq_storm_detect(dev, hotplug_trigger, hpd_status_i915)) intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915);
i915_hpd_irq_setup(dev);
queue_work(dev_priv->wq,
&dev_priv->hotplug_work);
}
I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status); I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
POSTING_READ(PORT_HOTPLUG_STAT); POSTING_READ(PORT_HOTPLUG_STAT);
} }
...@@ -3369,6 +3377,8 @@ static void i915_hpd_irq_setup(struct drm_device *dev) ...@@ -3369,6 +3377,8 @@ static void i915_hpd_irq_setup(struct drm_device *dev)
struct intel_encoder *intel_encoder; struct intel_encoder *intel_encoder;
u32 hotplug_en; u32 hotplug_en;
assert_spin_locked(&dev_priv->irq_lock);
if (I915_HAS_HOTPLUG(dev)) { if (I915_HAS_HOTPLUG(dev)) {
hotplug_en = I915_READ(PORT_HOTPLUG_EN); hotplug_en = I915_READ(PORT_HOTPLUG_EN);
hotplug_en &= ~HOTPLUG_INT_EN_MASK; hotplug_en &= ~HOTPLUG_INT_EN_MASK;
...@@ -3449,17 +3459,14 @@ static irqreturn_t i965_irq_handler(int irq, void *arg) ...@@ -3449,17 +3459,14 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT); u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT);
u32 hotplug_trigger = hotplug_status & (IS_G4X(dev) ? u32 hotplug_trigger = hotplug_status & (IS_G4X(dev) ?
HOTPLUG_INT_STATUS_G4X : HOTPLUG_INT_STATUS_G4X :
HOTPLUG_INT_STATUS_I965); HOTPLUG_INT_STATUS_I915);
DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n", DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
hotplug_status); hotplug_status);
if (hotplug_trigger) {
if (hotplug_irq_storm_detect(dev, hotplug_trigger, intel_hpd_irq_handler(dev, hotplug_trigger,
IS_G4X(dev) ? hpd_status_gen4 : hpd_status_i965)) IS_G4X(dev) ? hpd_status_gen4 : hpd_status_i915);
i915_hpd_irq_setup(dev);
queue_work(dev_priv->wq,
&dev_priv->hotplug_work);
}
I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status); I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
I915_READ(PORT_HOTPLUG_STAT); I915_READ(PORT_HOTPLUG_STAT);
} }
...@@ -3655,6 +3662,7 @@ void intel_hpd_init(struct drm_device *dev) ...@@ -3655,6 +3662,7 @@ void intel_hpd_init(struct drm_device *dev)
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_mode_config *mode_config = &dev->mode_config; struct drm_mode_config *mode_config = &dev->mode_config;
struct drm_connector *connector; struct drm_connector *connector;
unsigned long irqflags;
int i; int i;
for (i = 1; i < HPD_NUM_PINS; i++) { for (i = 1; i < HPD_NUM_PINS; i++) {
...@@ -3667,6 +3675,11 @@ void intel_hpd_init(struct drm_device *dev) ...@@ -3667,6 +3675,11 @@ void intel_hpd_init(struct drm_device *dev)
if (!connector->polled && I915_HAS_HOTPLUG(dev) && intel_connector->encoder->hpd_pin > HPD_NONE) if (!connector->polled && I915_HAS_HOTPLUG(dev) && intel_connector->encoder->hpd_pin > HPD_NONE)
connector->polled = DRM_CONNECTOR_POLL_HPD; connector->polled = DRM_CONNECTOR_POLL_HPD;
} }
/* Interrupt setup is already guaranteed to be single-threaded, this is
* just to make the assert_spin_locked checks happy. */
spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
if (dev_priv->display.hpd_irq_setup) if (dev_priv->display.hpd_irq_setup)
dev_priv->display.hpd_irq_setup(dev); dev_priv->display.hpd_irq_setup(dev);
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
} }
...@@ -448,9 +448,9 @@ ...@@ -448,9 +448,9 @@
#define _DPIO_PLL_CML_B 0x806c #define _DPIO_PLL_CML_B 0x806c
#define DPIO_PLL_CML(pipe) _PIPE(pipe, _DPIO_PLL_CML_A, _DPIO_PLL_CML_B) #define DPIO_PLL_CML(pipe) _PIPE(pipe, _DPIO_PLL_CML_A, _DPIO_PLL_CML_B)
#define _DPIO_LFP_COEFF_A 0x8048 #define _DPIO_LPF_COEFF_A 0x8048
#define _DPIO_LFP_COEFF_B 0x8068 #define _DPIO_LPF_COEFF_B 0x8068
#define DPIO_LFP_COEFF(pipe) _PIPE(pipe, _DPIO_LFP_COEFF_A, _DPIO_LFP_COEFF_B) #define DPIO_LPF_COEFF(pipe) _PIPE(pipe, _DPIO_LPF_COEFF_A, _DPIO_LPF_COEFF_B)
#define DPIO_CALIBRATION 0x80ac #define DPIO_CALIBRATION 0x80ac
...@@ -1718,14 +1718,13 @@ ...@@ -1718,14 +1718,13 @@
GEN7_CXT_EXTENDED_SIZE(ctx_reg) + \ GEN7_CXT_EXTENDED_SIZE(ctx_reg) + \
GEN7_CXT_GT1_SIZE(ctx_reg) + \ GEN7_CXT_GT1_SIZE(ctx_reg) + \
GEN7_CXT_VFSTATE_SIZE(ctx_reg)) GEN7_CXT_VFSTATE_SIZE(ctx_reg))
#define HSW_CXT_POWER_SIZE(ctx_reg) ((ctx_reg >> 26) & 0x3f) /* Haswell does have the CXT_SIZE register however it does not appear to be
#define HSW_CXT_RING_SIZE(ctx_reg) ((ctx_reg >> 23) & 0x7) * valid. Now, docs explain in dwords what is in the context object. The full
#define HSW_CXT_RENDER_SIZE(ctx_reg) ((ctx_reg >> 15) & 0xff) * size is 70720 bytes, however, the power context and execlist context will
#define HSW_CXT_TOTAL_SIZE(ctx_reg) (HSW_CXT_POWER_SIZE(ctx_reg) + \ * never be saved (power context is stored elsewhere, and execlists don't work
HSW_CXT_RING_SIZE(ctx_reg) + \ * on HSW) - so the final size is 66944 bytes, which rounds to 17 pages.
HSW_CXT_RENDER_SIZE(ctx_reg) + \ */
GEN7_CXT_VFSTATE_SIZE(ctx_reg)) #define HSW_CXT_TOTAL_SIZE (17 * PAGE_SIZE)
/* /*
* Overlay regs * Overlay regs
...@@ -1874,6 +1873,12 @@ ...@@ -1874,6 +1873,12 @@
/* SDVO is different across gen3/4 */ /* SDVO is different across gen3/4 */
#define SDVOC_HOTPLUG_INT_STATUS_G4X (1 << 3) #define SDVOC_HOTPLUG_INT_STATUS_G4X (1 << 3)
#define SDVOB_HOTPLUG_INT_STATUS_G4X (1 << 2) #define SDVOB_HOTPLUG_INT_STATUS_G4X (1 << 2)
/*
* Bspec seems to be seriously misleaded about the SDVO hpd bits on i965g/gm,
* since reality corrobates that they're the same as on gen3. But keep these
* bits here (and the comment!) to help any other lost wanderers back onto the
* right tracks.
*/
#define SDVOC_HOTPLUG_INT_STATUS_I965 (3 << 4) #define SDVOC_HOTPLUG_INT_STATUS_I965 (3 << 4)
#define SDVOB_HOTPLUG_INT_STATUS_I965 (3 << 2) #define SDVOB_HOTPLUG_INT_STATUS_I965 (3 << 2)
#define SDVOC_HOTPLUG_INT_STATUS_I915 (1 << 7) #define SDVOC_HOTPLUG_INT_STATUS_I915 (1 << 7)
...@@ -1885,13 +1890,6 @@ ...@@ -1885,13 +1890,6 @@
PORTC_HOTPLUG_INT_STATUS | \ PORTC_HOTPLUG_INT_STATUS | \
PORTD_HOTPLUG_INT_STATUS) PORTD_HOTPLUG_INT_STATUS)
#define HOTPLUG_INT_STATUS_I965 (CRT_HOTPLUG_INT_STATUS | \
SDVOB_HOTPLUG_INT_STATUS_I965 | \
SDVOC_HOTPLUG_INT_STATUS_I965 | \
PORTB_HOTPLUG_INT_STATUS | \
PORTC_HOTPLUG_INT_STATUS | \
PORTD_HOTPLUG_INT_STATUS)
#define HOTPLUG_INT_STATUS_I915 (CRT_HOTPLUG_INT_STATUS | \ #define HOTPLUG_INT_STATUS_I915 (CRT_HOTPLUG_INT_STATUS | \
SDVOB_HOTPLUG_INT_STATUS_I915 | \ SDVOB_HOTPLUG_INT_STATUS_I915 | \
SDVOC_HOTPLUG_INT_STATUS_I915 | \ SDVOC_HOTPLUG_INT_STATUS_I915 | \
...@@ -3488,7 +3486,7 @@ ...@@ -3488,7 +3486,7 @@
#define SPRGAMC(pipe) _PIPE(pipe, _SPRA_GAMC, _SPRB_GAMC) #define SPRGAMC(pipe) _PIPE(pipe, _SPRA_GAMC, _SPRB_GAMC)
#define SPRSURFLIVE(pipe) _PIPE(pipe, _SPRA_SURFLIVE, _SPRB_SURFLIVE) #define SPRSURFLIVE(pipe) _PIPE(pipe, _SPRA_SURFLIVE, _SPRB_SURFLIVE)
#define _SPACNTR 0x72180 #define _SPACNTR (VLV_DISPLAY_BASE + 0x72180)
#define SP_ENABLE (1<<31) #define SP_ENABLE (1<<31)
#define SP_GEAMMA_ENABLE (1<<30) #define SP_GEAMMA_ENABLE (1<<30)
#define SP_PIXFORMAT_MASK (0xf<<26) #define SP_PIXFORMAT_MASK (0xf<<26)
...@@ -3507,30 +3505,30 @@ ...@@ -3507,30 +3505,30 @@
#define SP_YUV_ORDER_YVYU (2<<16) #define SP_YUV_ORDER_YVYU (2<<16)
#define SP_YUV_ORDER_VYUY (3<<16) #define SP_YUV_ORDER_VYUY (3<<16)
#define SP_TILED (1<<10) #define SP_TILED (1<<10)
#define _SPALINOFF 0x72184 #define _SPALINOFF (VLV_DISPLAY_BASE + 0x72184)
#define _SPASTRIDE 0x72188 #define _SPASTRIDE (VLV_DISPLAY_BASE + 0x72188)
#define _SPAPOS 0x7218c #define _SPAPOS (VLV_DISPLAY_BASE + 0x7218c)
#define _SPASIZE 0x72190 #define _SPASIZE (VLV_DISPLAY_BASE + 0x72190)
#define _SPAKEYMINVAL 0x72194 #define _SPAKEYMINVAL (VLV_DISPLAY_BASE + 0x72194)
#define _SPAKEYMSK 0x72198 #define _SPAKEYMSK (VLV_DISPLAY_BASE + 0x72198)
#define _SPASURF 0x7219c #define _SPASURF (VLV_DISPLAY_BASE + 0x7219c)
#define _SPAKEYMAXVAL 0x721a0 #define _SPAKEYMAXVAL (VLV_DISPLAY_BASE + 0x721a0)
#define _SPATILEOFF 0x721a4 #define _SPATILEOFF (VLV_DISPLAY_BASE + 0x721a4)
#define _SPACONSTALPHA 0x721a8 #define _SPACONSTALPHA (VLV_DISPLAY_BASE + 0x721a8)
#define _SPAGAMC 0x721f4 #define _SPAGAMC (VLV_DISPLAY_BASE + 0x721f4)
#define _SPBCNTR 0x72280 #define _SPBCNTR (VLV_DISPLAY_BASE + 0x72280)
#define _SPBLINOFF 0x72284 #define _SPBLINOFF (VLV_DISPLAY_BASE + 0x72284)
#define _SPBSTRIDE 0x72288 #define _SPBSTRIDE (VLV_DISPLAY_BASE + 0x72288)
#define _SPBPOS 0x7228c #define _SPBPOS (VLV_DISPLAY_BASE + 0x7228c)
#define _SPBSIZE 0x72290 #define _SPBSIZE (VLV_DISPLAY_BASE + 0x72290)
#define _SPBKEYMINVAL 0x72294 #define _SPBKEYMINVAL (VLV_DISPLAY_BASE + 0x72294)
#define _SPBKEYMSK 0x72298 #define _SPBKEYMSK (VLV_DISPLAY_BASE + 0x72298)
#define _SPBSURF 0x7229c #define _SPBSURF (VLV_DISPLAY_BASE + 0x7229c)
#define _SPBKEYMAXVAL 0x722a0 #define _SPBKEYMAXVAL (VLV_DISPLAY_BASE + 0x722a0)
#define _SPBTILEOFF 0x722a4 #define _SPBTILEOFF (VLV_DISPLAY_BASE + 0x722a4)
#define _SPBCONSTALPHA 0x722a8 #define _SPBCONSTALPHA (VLV_DISPLAY_BASE + 0x722a8)
#define _SPBGAMC 0x722f4 #define _SPBGAMC (VLV_DISPLAY_BASE + 0x722f4)
#define SPCNTR(pipe, plane) _PIPE(pipe * 2 + plane, _SPACNTR, _SPBCNTR) #define SPCNTR(pipe, plane) _PIPE(pipe * 2 + plane, _SPACNTR, _SPBCNTR)
#define SPLINOFF(pipe, plane) _PIPE(pipe * 2 + plane, _SPALINOFF, _SPBLINOFF) #define SPLINOFF(pipe, plane) _PIPE(pipe * 2 + plane, _SPALINOFF, _SPBLINOFF)
......
...@@ -1356,7 +1356,12 @@ void intel_ddi_init(struct drm_device *dev, enum port port) ...@@ -1356,7 +1356,12 @@ void intel_ddi_init(struct drm_device *dev, enum port port)
intel_encoder->cloneable = false; intel_encoder->cloneable = false;
intel_encoder->hot_plug = intel_ddi_hot_plug; intel_encoder->hot_plug = intel_ddi_hot_plug;
intel_dp_init_connector(intel_dig_port, dp_connector); if (!intel_dp_init_connector(intel_dig_port, dp_connector)) {
drm_encoder_cleanup(encoder);
kfree(intel_dig_port);
kfree(dp_connector);
return;
}
if (intel_encoder->type != INTEL_OUTPUT_EDP) { if (intel_encoder->type != INTEL_OUTPUT_EDP) {
hdmi_connector = kzalloc(sizeof(struct intel_connector), hdmi_connector = kzalloc(sizeof(struct intel_connector),
......
...@@ -3250,7 +3250,7 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) ...@@ -3250,7 +3250,7 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
/* IPS only exists on ULT machines and is tied to pipe A. */ /* IPS only exists on ULT machines and is tied to pipe A. */
static bool hsw_crtc_supports_ips(struct intel_crtc *crtc) static bool hsw_crtc_supports_ips(struct intel_crtc *crtc)
{ {
return IS_ULT(crtc->base.dev) && crtc->pipe == PIPE_A; return HAS_IPS(crtc->base.dev) && crtc->pipe == PIPE_A;
} }
static void hsw_enable_ips(struct intel_crtc *crtc) static void hsw_enable_ips(struct intel_crtc *crtc)
...@@ -4069,7 +4069,7 @@ static int intel_crtc_compute_config(struct intel_crtc *crtc, ...@@ -4069,7 +4069,7 @@ static int intel_crtc_compute_config(struct intel_crtc *crtc,
pipe_config->pipe_bpp = 8*3; pipe_config->pipe_bpp = 8*3;
} }
if (IS_HASWELL(dev)) if (HAS_IPS(dev))
hsw_compute_ips_config(crtc, pipe_config); hsw_compute_ips_config(crtc, pipe_config);
/* XXX: PCH clock sharing is done in ->mode_set, so make sure the old /* XXX: PCH clock sharing is done in ->mode_set, so make sure the old
...@@ -4404,11 +4404,12 @@ static void vlv_update_pll(struct intel_crtc *crtc) ...@@ -4404,11 +4404,12 @@ static void vlv_update_pll(struct intel_crtc *crtc)
/* Set HBR and RBR LPF coefficients */ /* Set HBR and RBR LPF coefficients */
if (crtc->config.port_clock == 162000 || if (crtc->config.port_clock == 162000 ||
intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_ANALOG) ||
intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_HDMI)) intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_HDMI))
vlv_dpio_write(dev_priv, DPIO_LFP_COEFF(pipe), vlv_dpio_write(dev_priv, DPIO_LPF_COEFF(pipe),
0x005f0021); 0x005f0021);
else else
vlv_dpio_write(dev_priv, DPIO_LFP_COEFF(pipe), vlv_dpio_write(dev_priv, DPIO_LPF_COEFF(pipe),
0x00d0000f); 0x00d0000f);
if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_EDP) || if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_EDP) ||
...@@ -8753,8 +8754,8 @@ static int intel_crtc_set_config(struct drm_mode_set *set) ...@@ -8753,8 +8754,8 @@ static int intel_crtc_set_config(struct drm_mode_set *set)
} }
if (ret) { if (ret) {
DRM_ERROR("failed to set mode on [CRTC:%d], err = %d\n", DRM_DEBUG_KMS("failed to set mode on [CRTC:%d], err = %d\n",
set->crtc->base.id, ret); set->crtc->base.id, ret);
fail: fail:
intel_set_config_restore_state(dev, config); intel_set_config_restore_state(dev, config);
...@@ -9121,6 +9122,7 @@ int intel_framebuffer_init(struct drm_device *dev, ...@@ -9121,6 +9122,7 @@ int intel_framebuffer_init(struct drm_device *dev,
struct drm_mode_fb_cmd2 *mode_cmd, struct drm_mode_fb_cmd2 *mode_cmd,
struct drm_i915_gem_object *obj) struct drm_i915_gem_object *obj)
{ {
int pitch_limit;
int ret; int ret;
if (obj->tiling_mode == I915_TILING_Y) { if (obj->tiling_mode == I915_TILING_Y) {
...@@ -9134,10 +9136,26 @@ int intel_framebuffer_init(struct drm_device *dev, ...@@ -9134,10 +9136,26 @@ int intel_framebuffer_init(struct drm_device *dev,
return -EINVAL; return -EINVAL;
} }
/* FIXME <= Gen4 stride limits are bit unclear */ if (INTEL_INFO(dev)->gen >= 5 && !IS_VALLEYVIEW(dev)) {
if (mode_cmd->pitches[0] > 32768) { pitch_limit = 32*1024;
DRM_DEBUG("pitch (%d) must be at less than 32768\n", } else if (INTEL_INFO(dev)->gen >= 4) {
mode_cmd->pitches[0]); if (obj->tiling_mode)
pitch_limit = 16*1024;
else
pitch_limit = 32*1024;
} else if (INTEL_INFO(dev)->gen >= 3) {
if (obj->tiling_mode)
pitch_limit = 8*1024;
else
pitch_limit = 16*1024;
} else
/* XXX DSPC is limited to 4k tiled */
pitch_limit = 8*1024;
if (mode_cmd->pitches[0] > pitch_limit) {
DRM_DEBUG("%s pitch (%d) must be at less than %d\n",
obj->tiling_mode ? "tiled" : "linear",
mode_cmd->pitches[0], pitch_limit);
return -EINVAL; return -EINVAL;
} }
......
...@@ -1324,20 +1324,35 @@ static void intel_dp_get_config(struct intel_encoder *encoder, ...@@ -1324,20 +1324,35 @@ static void intel_dp_get_config(struct intel_encoder *encoder,
struct intel_crtc_config *pipe_config) struct intel_crtc_config *pipe_config)
{ {
struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base); struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
u32 tmp, flags = 0; u32 tmp, flags = 0;
struct drm_device *dev = encoder->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
enum port port = dp_to_dig_port(intel_dp)->port;
struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
tmp = I915_READ(intel_dp->output_reg); if ((port == PORT_A) || !HAS_PCH_CPT(dev)) {
tmp = I915_READ(intel_dp->output_reg);
if (tmp & DP_SYNC_HS_HIGH)
flags |= DRM_MODE_FLAG_PHSYNC;
else
flags |= DRM_MODE_FLAG_NHSYNC;
if (tmp & DP_SYNC_HS_HIGH) if (tmp & DP_SYNC_VS_HIGH)
flags |= DRM_MODE_FLAG_PHSYNC; flags |= DRM_MODE_FLAG_PVSYNC;
else else
flags |= DRM_MODE_FLAG_NHSYNC; flags |= DRM_MODE_FLAG_NVSYNC;
} else {
tmp = I915_READ(TRANS_DP_CTL(crtc->pipe));
if (tmp & TRANS_DP_HSYNC_ACTIVE_HIGH)
flags |= DRM_MODE_FLAG_PHSYNC;
else
flags |= DRM_MODE_FLAG_NHSYNC;
if (tmp & DP_SYNC_VS_HIGH) if (tmp & TRANS_DP_VSYNC_ACTIVE_HIGH)
flags |= DRM_MODE_FLAG_PVSYNC; flags |= DRM_MODE_FLAG_PVSYNC;
else else
flags |= DRM_MODE_FLAG_NVSYNC; flags |= DRM_MODE_FLAG_NVSYNC;
}
pipe_config->adjusted_mode.flags |= flags; pipe_config->adjusted_mode.flags |= flags;
} }
...@@ -2681,15 +2696,16 @@ intel_dp_set_property(struct drm_connector *connector, ...@@ -2681,15 +2696,16 @@ intel_dp_set_property(struct drm_connector *connector,
} }
static void static void
intel_dp_destroy(struct drm_connector *connector) intel_dp_connector_destroy(struct drm_connector *connector)
{ {
struct intel_dp *intel_dp = intel_attached_dp(connector);
struct intel_connector *intel_connector = to_intel_connector(connector); struct intel_connector *intel_connector = to_intel_connector(connector);
if (!IS_ERR_OR_NULL(intel_connector->edid)) if (!IS_ERR_OR_NULL(intel_connector->edid))
kfree(intel_connector->edid); kfree(intel_connector->edid);
if (is_edp(intel_dp)) /* Can't call is_edp() since the encoder may have been destroyed
* already. */
if (connector->connector_type == DRM_MODE_CONNECTOR_eDP)
intel_panel_fini(&intel_connector->panel); intel_panel_fini(&intel_connector->panel);
drm_sysfs_connector_remove(connector); drm_sysfs_connector_remove(connector);
...@@ -2723,7 +2739,7 @@ static const struct drm_connector_funcs intel_dp_connector_funcs = { ...@@ -2723,7 +2739,7 @@ static const struct drm_connector_funcs intel_dp_connector_funcs = {
.detect = intel_dp_detect, .detect = intel_dp_detect,
.fill_modes = drm_helper_probe_single_connector_modes, .fill_modes = drm_helper_probe_single_connector_modes,
.set_property = intel_dp_set_property, .set_property = intel_dp_set_property,
.destroy = intel_dp_destroy, .destroy = intel_dp_connector_destroy,
}; };
static const struct drm_connector_helper_funcs intel_dp_connector_helper_funcs = { static const struct drm_connector_helper_funcs intel_dp_connector_helper_funcs = {
...@@ -2954,7 +2970,85 @@ intel_dp_init_panel_power_sequencer_registers(struct drm_device *dev, ...@@ -2954,7 +2970,85 @@ intel_dp_init_panel_power_sequencer_registers(struct drm_device *dev,
I915_READ(pp_div_reg)); I915_READ(pp_div_reg));
} }
void static bool intel_edp_init_connector(struct intel_dp *intel_dp,
struct intel_connector *intel_connector)
{
struct drm_connector *connector = &intel_connector->base;
struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
struct drm_device *dev = intel_dig_port->base.base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_display_mode *fixed_mode = NULL;
struct edp_power_seq power_seq = { 0 };
bool has_dpcd;
struct drm_display_mode *scan;
struct edid *edid;
if (!is_edp(intel_dp))
return true;
intel_dp_init_panel_power_sequencer(dev, intel_dp, &power_seq);
/* Cache DPCD and EDID for edp. */
ironlake_edp_panel_vdd_on(intel_dp);
has_dpcd = intel_dp_get_dpcd(intel_dp);
ironlake_edp_panel_vdd_off(intel_dp, false);
if (has_dpcd) {
if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11)
dev_priv->no_aux_handshake =
intel_dp->dpcd[DP_MAX_DOWNSPREAD] &
DP_NO_AUX_HANDSHAKE_LINK_TRAINING;
} else {
/* if this fails, presume the device is a ghost */
DRM_INFO("failed to retrieve link info, disabling eDP\n");
return false;
}
/* We now know it's not a ghost, init power sequence regs. */
intel_dp_init_panel_power_sequencer_registers(dev, intel_dp,
&power_seq);
ironlake_edp_panel_vdd_on(intel_dp);
edid = drm_get_edid(connector, &intel_dp->adapter);
if (edid) {
if (drm_add_edid_modes(connector, edid)) {
drm_mode_connector_update_edid_property(connector,
edid);
drm_edid_to_eld(connector, edid);
} else {
kfree(edid);
edid = ERR_PTR(-EINVAL);
}
} else {
edid = ERR_PTR(-ENOENT);
}
intel_connector->edid = edid;
/* prefer fixed mode from EDID if available */
list_for_each_entry(scan, &connector->probed_modes, head) {
if ((scan->type & DRM_MODE_TYPE_PREFERRED)) {
fixed_mode = drm_mode_duplicate(dev, scan);
break;
}
}
/* fallback to VBT if available for eDP */
if (!fixed_mode && dev_priv->vbt.lfp_lvds_vbt_mode) {
fixed_mode = drm_mode_duplicate(dev,
dev_priv->vbt.lfp_lvds_vbt_mode);
if (fixed_mode)
fixed_mode->type |= DRM_MODE_TYPE_PREFERRED;
}
ironlake_edp_panel_vdd_off(intel_dp, false);
intel_panel_init(&intel_connector->panel, fixed_mode);
intel_panel_setup_backlight(connector);
return true;
}
bool
intel_dp_init_connector(struct intel_digital_port *intel_dig_port, intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
struct intel_connector *intel_connector) struct intel_connector *intel_connector)
{ {
...@@ -2963,11 +3057,9 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port, ...@@ -2963,11 +3057,9 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
struct intel_encoder *intel_encoder = &intel_dig_port->base; struct intel_encoder *intel_encoder = &intel_dig_port->base;
struct drm_device *dev = intel_encoder->base.dev; struct drm_device *dev = intel_encoder->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_display_mode *fixed_mode = NULL;
struct edp_power_seq power_seq = { 0 };
enum port port = intel_dig_port->port; enum port port = intel_dig_port->port;
const char *name = NULL; const char *name = NULL;
int type; int type, error;
/* Preserve the current hw state. */ /* Preserve the current hw state. */
intel_dp->DP = I915_READ(intel_dp->output_reg); intel_dp->DP = I915_READ(intel_dp->output_reg);
...@@ -3065,74 +3157,21 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port, ...@@ -3065,74 +3157,21 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
BUG(); BUG();
} }
if (is_edp(intel_dp)) error = intel_dp_i2c_init(intel_dp, intel_connector, name);
intel_dp_init_panel_power_sequencer(dev, intel_dp, &power_seq); WARN(error, "intel_dp_i2c_init failed with error %d for port %c\n",
error, port_name(port));
intel_dp_i2c_init(intel_dp, intel_connector, name);
/* Cache DPCD and EDID for edp. */
if (is_edp(intel_dp)) {
bool ret;
struct drm_display_mode *scan;
struct edid *edid;
ironlake_edp_panel_vdd_on(intel_dp);
ret = intel_dp_get_dpcd(intel_dp);
ironlake_edp_panel_vdd_off(intel_dp, false);
if (ret) {
if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11)
dev_priv->no_aux_handshake =
intel_dp->dpcd[DP_MAX_DOWNSPREAD] &
DP_NO_AUX_HANDSHAKE_LINK_TRAINING;
} else {
/* if this fails, presume the device is a ghost */
DRM_INFO("failed to retrieve link info, disabling eDP\n");
intel_dp_encoder_destroy(&intel_encoder->base);
intel_dp_destroy(connector);
return;
}
/* We now know it's not a ghost, init power sequence regs. */
intel_dp_init_panel_power_sequencer_registers(dev, intel_dp,
&power_seq);
ironlake_edp_panel_vdd_on(intel_dp); if (!intel_edp_init_connector(intel_dp, intel_connector)) {
edid = drm_get_edid(connector, &intel_dp->adapter); i2c_del_adapter(&intel_dp->adapter);
if (edid) { if (is_edp(intel_dp)) {
if (drm_add_edid_modes(connector, edid)) { cancel_delayed_work_sync(&intel_dp->panel_vdd_work);
drm_mode_connector_update_edid_property(connector, edid); mutex_lock(&dev->mode_config.mutex);
drm_edid_to_eld(connector, edid); ironlake_panel_vdd_off_sync(intel_dp);
} else { mutex_unlock(&dev->mode_config.mutex);
kfree(edid);
edid = ERR_PTR(-EINVAL);
}
} else {
edid = ERR_PTR(-ENOENT);
} }
intel_connector->edid = edid; drm_sysfs_connector_remove(connector);
drm_connector_cleanup(connector);
/* prefer fixed mode from EDID if available */ return false;
list_for_each_entry(scan, &connector->probed_modes, head) {
if ((scan->type & DRM_MODE_TYPE_PREFERRED)) {
fixed_mode = drm_mode_duplicate(dev, scan);
break;
}
}
/* fallback to VBT if available for eDP */
if (!fixed_mode && dev_priv->vbt.lfp_lvds_vbt_mode) {
fixed_mode = drm_mode_duplicate(dev, dev_priv->vbt.lfp_lvds_vbt_mode);
if (fixed_mode)
fixed_mode->type |= DRM_MODE_TYPE_PREFERRED;
}
ironlake_edp_panel_vdd_off(intel_dp, false);
}
if (is_edp(intel_dp)) {
intel_panel_init(&intel_connector->panel, fixed_mode);
intel_panel_setup_backlight(connector);
} }
intel_dp_add_properties(intel_dp, connector); intel_dp_add_properties(intel_dp, connector);
...@@ -3145,6 +3184,8 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port, ...@@ -3145,6 +3184,8 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
u32 temp = I915_READ(PEG_BAND_GAP_DATA); u32 temp = I915_READ(PEG_BAND_GAP_DATA);
I915_WRITE(PEG_BAND_GAP_DATA, (temp & ~0xf) | 0xd); I915_WRITE(PEG_BAND_GAP_DATA, (temp & ~0xf) | 0xd);
} }
return true;
} }
void void
...@@ -3190,5 +3231,9 @@ intel_dp_init(struct drm_device *dev, int output_reg, enum port port) ...@@ -3190,5 +3231,9 @@ intel_dp_init(struct drm_device *dev, int output_reg, enum port port)
intel_encoder->cloneable = false; intel_encoder->cloneable = false;
intel_encoder->hot_plug = intel_dp_hot_plug; intel_encoder->hot_plug = intel_dp_hot_plug;
intel_dp_init_connector(intel_dig_port, intel_connector); if (!intel_dp_init_connector(intel_dig_port, intel_connector)) {
drm_encoder_cleanup(encoder);
kfree(intel_dig_port);
kfree(intel_connector);
}
} }
...@@ -141,7 +141,8 @@ struct intel_encoder { ...@@ -141,7 +141,8 @@ struct intel_encoder {
bool (*get_hw_state)(struct intel_encoder *, enum pipe *pipe); bool (*get_hw_state)(struct intel_encoder *, enum pipe *pipe);
/* Reconstructs the equivalent mode flags for the current hardware /* Reconstructs the equivalent mode flags for the current hardware
* state. This must be called _after_ display->get_pipe_config has * state. This must be called _after_ display->get_pipe_config has
* pre-filled the pipe config. */ * pre-filled the pipe config. Note that intel_encoder->base.crtc must
* be set correctly before calling this function. */
void (*get_config)(struct intel_encoder *, void (*get_config)(struct intel_encoder *,
struct intel_crtc_config *pipe_config); struct intel_crtc_config *pipe_config);
int crtc_mask; int crtc_mask;
...@@ -586,7 +587,7 @@ extern void intel_lvds_init(struct drm_device *dev); ...@@ -586,7 +587,7 @@ extern void intel_lvds_init(struct drm_device *dev);
extern bool intel_is_dual_link_lvds(struct drm_device *dev); extern bool intel_is_dual_link_lvds(struct drm_device *dev);
extern void intel_dp_init(struct drm_device *dev, int output_reg, extern void intel_dp_init(struct drm_device *dev, int output_reg,
enum port port); enum port port);
extern void intel_dp_init_connector(struct intel_digital_port *intel_dig_port, extern bool intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
struct intel_connector *intel_connector); struct intel_connector *intel_connector);
extern void intel_dp_init_link_config(struct intel_dp *intel_dp); extern void intel_dp_init_link_config(struct intel_dp *intel_dp);
extern void intel_dp_start_link_train(struct intel_dp *intel_dp); extern void intel_dp_start_link_train(struct intel_dp *intel_dp);
......
...@@ -602,7 +602,7 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder, ...@@ -602,7 +602,7 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder,
u32 hdmi_val; u32 hdmi_val;
hdmi_val = SDVO_ENCODING_HDMI; hdmi_val = SDVO_ENCODING_HDMI;
if (!HAS_PCH_SPLIT(dev) && !IS_VALLEYVIEW(dev)) if (!HAS_PCH_SPLIT(dev))
hdmi_val |= intel_hdmi->color_range; hdmi_val |= intel_hdmi->color_range;
if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
hdmi_val |= SDVO_VSYNC_ACTIVE_HIGH; hdmi_val |= SDVO_VSYNC_ACTIVE_HIGH;
......
...@@ -311,8 +311,8 @@ static void intel_didl_outputs(struct drm_device *dev) ...@@ -311,8 +311,8 @@ static void intel_didl_outputs(struct drm_device *dev)
list_for_each_entry(acpi_cdev, &acpi_video_bus->children, node) { list_for_each_entry(acpi_cdev, &acpi_video_bus->children, node) {
if (i >= 8) { if (i >= 8) {
dev_printk(KERN_ERR, &dev->pdev->dev, dev_dbg(&dev->pdev->dev,
"More than 8 outputs detected via ACPI\n"); "More than 8 outputs detected via ACPI\n");
return; return;
} }
status = status =
...@@ -338,8 +338,8 @@ static void intel_didl_outputs(struct drm_device *dev) ...@@ -338,8 +338,8 @@ static void intel_didl_outputs(struct drm_device *dev)
list_for_each_entry(connector, &dev->mode_config.connector_list, head) { list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
int output_type = ACPI_OTHER_OUTPUT; int output_type = ACPI_OTHER_OUTPUT;
if (i >= 8) { if (i >= 8) {
dev_printk(KERN_ERR, &dev->pdev->dev, dev_dbg(&dev->pdev->dev,
"More than 8 outputs in connector list\n"); "More than 8 outputs in connector list\n");
return; return;
} }
switch (connector->connector_type) { switch (connector->connector_type) {
......
...@@ -3069,26 +3069,17 @@ void gen6_set_rps(struct drm_device *dev, u8 val) ...@@ -3069,26 +3069,17 @@ void gen6_set_rps(struct drm_device *dev, u8 val)
trace_intel_gpu_freq_change(val * 50); trace_intel_gpu_freq_change(val * 50);
} }
void valleyview_set_rps(struct drm_device *dev, u8 val) /*
* Wait until the previous freq change has completed,
* or the timeout elapsed, and then update our notion
* of the current GPU frequency.
*/
static void vlv_update_rps_cur_delay(struct drm_i915_private *dev_priv)
{ {
struct drm_i915_private *dev_priv = dev->dev_private;
unsigned long timeout = jiffies + msecs_to_jiffies(10); unsigned long timeout = jiffies + msecs_to_jiffies(10);
u32 limits = gen6_rps_limits(dev_priv, &val);
u32 pval; u32 pval;
WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock)); WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock));
WARN_ON(val > dev_priv->rps.max_delay);
WARN_ON(val < dev_priv->rps.min_delay);
DRM_DEBUG_DRIVER("gpu freq request from %d to %d\n",
vlv_gpu_freq(dev_priv->mem_freq,
dev_priv->rps.cur_delay),
vlv_gpu_freq(dev_priv->mem_freq, val));
if (val == dev_priv->rps.cur_delay)
return;
vlv_punit_write(dev_priv, PUNIT_REG_GPU_FREQ_REQ, val);
do { do {
pval = vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS); pval = vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS);
...@@ -3099,17 +3090,41 @@ void valleyview_set_rps(struct drm_device *dev, u8 val) ...@@ -3099,17 +3090,41 @@ void valleyview_set_rps(struct drm_device *dev, u8 val)
udelay(10); udelay(10);
} while (pval & 1); } while (pval & 1);
pval = vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS); pval >>= 8;
if ((pval >> 8) != val)
DRM_DEBUG_DRIVER("punit overrode freq: %d requested, but got %d\n",
val, pval >> 8);
/* Make sure we continue to get interrupts if (pval != dev_priv->rps.cur_delay)
* until we hit the minimum or maximum frequencies. DRM_DEBUG_DRIVER("Punit overrode GPU freq: %d MHz (%u) requested, but got %d Mhz (%u)\n",
*/ vlv_gpu_freq(dev_priv->mem_freq, dev_priv->rps.cur_delay),
I915_WRITE(GEN6_RP_INTERRUPT_LIMITS, limits); dev_priv->rps.cur_delay,
vlv_gpu_freq(dev_priv->mem_freq, pval), pval);
dev_priv->rps.cur_delay = pval;
}
void valleyview_set_rps(struct drm_device *dev, u8 val)
{
struct drm_i915_private *dev_priv = dev->dev_private;
gen6_rps_limits(dev_priv, &val);
dev_priv->rps.cur_delay = pval >> 8; WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock));
WARN_ON(val > dev_priv->rps.max_delay);
WARN_ON(val < dev_priv->rps.min_delay);
vlv_update_rps_cur_delay(dev_priv);
DRM_DEBUG_DRIVER("GPU freq request from %d MHz (%u) to %d MHz (%u)\n",
vlv_gpu_freq(dev_priv->mem_freq,
dev_priv->rps.cur_delay),
dev_priv->rps.cur_delay,
vlv_gpu_freq(dev_priv->mem_freq, val), val);
if (val == dev_priv->rps.cur_delay)
return;
vlv_punit_write(dev_priv, PUNIT_REG_GPU_FREQ_REQ, val);
dev_priv->rps.cur_delay = val;
trace_intel_gpu_freq_change(vlv_gpu_freq(dev_priv->mem_freq, val)); trace_intel_gpu_freq_change(vlv_gpu_freq(dev_priv->mem_freq, val));
} }
...@@ -3446,7 +3461,8 @@ static void vlv_rps_timer_work(struct work_struct *work) ...@@ -3446,7 +3461,8 @@ static void vlv_rps_timer_work(struct work_struct *work)
* min freq available. * min freq available.
*/ */
mutex_lock(&dev_priv->rps.hw_lock); mutex_lock(&dev_priv->rps.hw_lock);
valleyview_set_rps(dev_priv->dev, dev_priv->rps.rpe_delay); if (dev_priv->rps.cur_delay > dev_priv->rps.rpe_delay)
valleyview_set_rps(dev_priv->dev, dev_priv->rps.rpe_delay);
mutex_unlock(&dev_priv->rps.hw_lock); mutex_unlock(&dev_priv->rps.hw_lock);
} }
...@@ -3496,7 +3512,7 @@ static void valleyview_enable_rps(struct drm_device *dev) ...@@ -3496,7 +3512,7 @@ static void valleyview_enable_rps(struct drm_device *dev)
{ {
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_ring_buffer *ring; struct intel_ring_buffer *ring;
u32 gtfifodbg, val, rpe; u32 gtfifodbg, val;
int i; int i;
WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock)); WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock));
...@@ -3557,31 +3573,39 @@ static void valleyview_enable_rps(struct drm_device *dev) ...@@ -3557,31 +3573,39 @@ static void valleyview_enable_rps(struct drm_device *dev)
DRM_DEBUG_DRIVER("GPLL enabled? %s\n", val & 0x10 ? "yes" : "no"); DRM_DEBUG_DRIVER("GPLL enabled? %s\n", val & 0x10 ? "yes" : "no");
DRM_DEBUG_DRIVER("GPU status: 0x%08x\n", val); DRM_DEBUG_DRIVER("GPU status: 0x%08x\n", val);
DRM_DEBUG_DRIVER("current GPU freq: %d\n",
vlv_gpu_freq(dev_priv->mem_freq, (val >> 8) & 0xff));
dev_priv->rps.cur_delay = (val >> 8) & 0xff; dev_priv->rps.cur_delay = (val >> 8) & 0xff;
DRM_DEBUG_DRIVER("current GPU freq: %d MHz (%u)\n",
vlv_gpu_freq(dev_priv->mem_freq,
dev_priv->rps.cur_delay),
dev_priv->rps.cur_delay);
dev_priv->rps.max_delay = valleyview_rps_max_freq(dev_priv); dev_priv->rps.max_delay = valleyview_rps_max_freq(dev_priv);
dev_priv->rps.hw_max = dev_priv->rps.max_delay; dev_priv->rps.hw_max = dev_priv->rps.max_delay;
DRM_DEBUG_DRIVER("max GPU freq: %d\n", vlv_gpu_freq(dev_priv->mem_freq, DRM_DEBUG_DRIVER("max GPU freq: %d MHz (%u)\n",
dev_priv->rps.max_delay)); vlv_gpu_freq(dev_priv->mem_freq,
dev_priv->rps.max_delay),
dev_priv->rps.max_delay);
rpe = valleyview_rps_rpe_freq(dev_priv); dev_priv->rps.rpe_delay = valleyview_rps_rpe_freq(dev_priv);
DRM_DEBUG_DRIVER("RPe GPU freq: %d\n", DRM_DEBUG_DRIVER("RPe GPU freq: %d MHz (%u)\n",
vlv_gpu_freq(dev_priv->mem_freq, rpe)); vlv_gpu_freq(dev_priv->mem_freq,
dev_priv->rps.rpe_delay = rpe; dev_priv->rps.rpe_delay),
dev_priv->rps.rpe_delay);
val = valleyview_rps_min_freq(dev_priv); dev_priv->rps.min_delay = valleyview_rps_min_freq(dev_priv);
DRM_DEBUG_DRIVER("min GPU freq: %d\n", vlv_gpu_freq(dev_priv->mem_freq, DRM_DEBUG_DRIVER("min GPU freq: %d MHz (%u)\n",
val)); vlv_gpu_freq(dev_priv->mem_freq,
dev_priv->rps.min_delay = val; dev_priv->rps.min_delay),
dev_priv->rps.min_delay);
DRM_DEBUG_DRIVER("setting GPU freq to %d\n", DRM_DEBUG_DRIVER("setting GPU freq to %d MHz (%u)\n",
vlv_gpu_freq(dev_priv->mem_freq, rpe)); vlv_gpu_freq(dev_priv->mem_freq,
dev_priv->rps.rpe_delay),
dev_priv->rps.rpe_delay);
INIT_DELAYED_WORK(&dev_priv->rps.vlv_work, vlv_rps_timer_work); INIT_DELAYED_WORK(&dev_priv->rps.vlv_work, vlv_rps_timer_work);
valleyview_set_rps(dev_priv->dev, rpe); valleyview_set_rps(dev_priv->dev, dev_priv->rps.rpe_delay);
/* requires MSI enabled */ /* requires MSI enabled */
I915_WRITE(GEN6_PMIER, GEN6_PM_RPS_EVENTS); I915_WRITE(GEN6_PMIER, GEN6_PM_RPS_EVENTS);
...@@ -4834,10 +4858,6 @@ static void valleyview_init_clock_gating(struct drm_device *dev) ...@@ -4834,10 +4858,6 @@ static void valleyview_init_clock_gating(struct drm_device *dev)
I915_WRITE(GEN7_ROW_CHICKEN2, I915_WRITE(GEN7_ROW_CHICKEN2,
_MASKED_BIT_ENABLE(DOP_CLOCK_GATING_DISABLE)); _MASKED_BIT_ENABLE(DOP_CLOCK_GATING_DISABLE));
/* WaForceL3Serialization:vlv */
I915_WRITE(GEN7_L3SQCREG4, I915_READ(GEN7_L3SQCREG4) &
~L3SQ_URB_READ_CAM_MATCH_DISABLE);
/* This is required by WaCatErrorRejectionIssue:vlv */ /* This is required by WaCatErrorRejectionIssue:vlv */
I915_WRITE(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG, I915_WRITE(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG,
I915_READ(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG) | I915_READ(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG) |
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment