Merge tag 'drm-intel-next-2012-05-20' of git://people.freedesktop.org/~danvet/drm-intel into drm-core-next
Daniel wrote: The last pull I'd like to squeeze into 3.5, safe for the hsw stuff mostly bugfixes: - last few patches for basic hsw enabling (Eugeni, infoframe support by Paulo) - Fix up infoframe support, we've hopefully squashed all the cargo-culting in there (Paulo). Among all the issues, this finally fixes some of the infoframe regressions seen on g4x and snb systems. - Fixup sdvo infoframe support, this fixes a regression from 2.6.37. - Correctly enable semaphores on snb, we've enabled it already for 3.5, but the dmar check was slightly wrong. - gen6 irq fixlets from Chris. - disable gmbus on i830, the hw seems to be simply broken. - fix up the pch pll fallout (Chris & me). - for_each_ring macro from Chris - I've figured I'll merge this now to avoid backport pain. - complain when the rps state isn't what we expect (Chris). Note that this is shockingly easy to hit and hence pretty much will cause a regression report. But it only tells us that the gpu turbo state got out of whack, a problem we know off since a long time (it cause the gpu to get stuck a a fixed frequency, usually the lowest one). Chris is working on a fix, but we haven't yet found a magic formula that works perfectly (only patches that massively reduce the frequency of this happening). - MAINTAINERS patch, I'm now officially the guy to beat up." * tag 'drm-intel-next-2012-05-20' of git://people.freedesktop.org/~danvet/drm-intel: (57 commits) drm/i915: IBX has a fixed pch pll to pch pipe mapping drm/i915: implement hsw_write_infoframe drm/i915: small hdmi coding style cleanups drm/i915: fixup infoframe support for sdvo drm/i915: Enable the PCH PLL for all generations after link training drm/i915: Convert BUG_ON(!pll->active) and friends to a WARN drm/i915: don't clobber the pipe param in sanitize_modesetting drm/i915: disable gmbus on i830 drm/i915: Replace the feature tests for BLT/BSD with ring init checks drm/i915: Check whether the ring is initialised prior to dispatch drm/i915: Introduce for_each_ring() macro drm/i915: Assert that the transcoder is indeed off before modifying it drm/i915: hook Haswell devices in place drm/i915: prepare HDMI link for Haswell drm/i915: move HDMI structs to shared location drm/i915: add WR PLL programming table drm/i915: add support for DDI-controlled digital outputs drm/i915: detect digital outputs on Haswell drm/i915: program iCLKIP on Lynx Point drm/i915: program WM_LINETIME on Haswell ...
This commit is contained in:
Коммит
f15b4ca2cc
|
@ -2373,10 +2373,10 @@ F: drivers/gpu/drm/
|
|||
F: include/drm/
|
||||
|
||||
INTEL DRM DRIVERS (excluding Poulsbo, Moorestown and derivative chipsets)
|
||||
M: Keith Packard <keithp@keithp.com>
|
||||
M: Daniel Vetter <daniel.vetter@ffwll.ch>
|
||||
L: intel-gfx@lists.freedesktop.org (subscribers-only)
|
||||
L: dri-devel@lists.freedesktop.org
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/keithp/linux.git
|
||||
T: git git://people.freedesktop.org/~danvet/drm-intel
|
||||
S: Supported
|
||||
F: drivers/gpu/drm/i915
|
||||
F: include/drm/i915*
|
||||
|
|
|
@ -908,6 +908,10 @@ static struct pci_device_id agp_intel_pci_table[] = {
|
|||
ID(PCI_DEVICE_ID_INTEL_IVYBRIDGE_M_HB),
|
||||
ID(PCI_DEVICE_ID_INTEL_IVYBRIDGE_S_HB),
|
||||
ID(PCI_DEVICE_ID_INTEL_VALLEYVIEW_HB),
|
||||
ID(PCI_DEVICE_ID_INTEL_HASWELL_HB),
|
||||
ID(PCI_DEVICE_ID_INTEL_HASWELL_M_HB),
|
||||
ID(PCI_DEVICE_ID_INTEL_HASWELL_S_HB),
|
||||
ID(PCI_DEVICE_ID_INTEL_HASWELL_E_HB),
|
||||
{ }
|
||||
};
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o \
|
|||
intel_crt.o \
|
||||
intel_lvds.o \
|
||||
intel_bios.o \
|
||||
intel_ddi.o \
|
||||
intel_dp.o \
|
||||
intel_hdmi.o \
|
||||
intel_sdvo.o \
|
||||
|
|
|
@ -699,6 +699,7 @@ static int i915_error_state(struct seq_file *m, void *unused)
|
|||
struct drm_device *dev = error_priv->dev;
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
struct drm_i915_error_state *error = error_priv->error;
|
||||
struct intel_ring_buffer *ring;
|
||||
int i, j, page, offset, elt;
|
||||
|
||||
if (!error) {
|
||||
|
@ -706,7 +707,6 @@ static int i915_error_state(struct seq_file *m, void *unused)
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
seq_printf(m, "Time: %ld s %ld us\n", error->time.tv_sec,
|
||||
error->time.tv_usec);
|
||||
seq_printf(m, "PCI ID: 0x%04x\n", dev->pci_device);
|
||||
|
@ -722,11 +722,8 @@ static int i915_error_state(struct seq_file *m, void *unused)
|
|||
seq_printf(m, "DONE_REG: 0x%08x\n", error->done_reg);
|
||||
}
|
||||
|
||||
i915_ring_error_state(m, dev, error, RCS);
|
||||
if (HAS_BLT(dev))
|
||||
i915_ring_error_state(m, dev, error, BCS);
|
||||
if (HAS_BSD(dev))
|
||||
i915_ring_error_state(m, dev, error, VCS);
|
||||
for_each_ring(ring, dev_priv, i)
|
||||
i915_ring_error_state(m, dev, error, i);
|
||||
|
||||
if (error->active_bo)
|
||||
print_error_buffers(m, "Active",
|
||||
|
|
|
@ -980,10 +980,10 @@ static int i915_getparam(struct drm_device *dev, void *data,
|
|||
value = 1;
|
||||
break;
|
||||
case I915_PARAM_HAS_BSD:
|
||||
value = HAS_BSD(dev);
|
||||
value = intel_ring_initialized(&dev_priv->ring[VCS]);
|
||||
break;
|
||||
case I915_PARAM_HAS_BLT:
|
||||
value = HAS_BLT(dev);
|
||||
value = intel_ring_initialized(&dev_priv->ring[BCS]);
|
||||
break;
|
||||
case I915_PARAM_HAS_RELAXED_FENCING:
|
||||
value = 1;
|
||||
|
|
|
@ -345,6 +345,13 @@ static const struct pci_device_id pciidlist[] = { /* aka */
|
|||
INTEL_VGA_DEVICE(0x0162, &intel_ivybridge_d_info), /* GT2 desktop */
|
||||
INTEL_VGA_DEVICE(0x015a, &intel_ivybridge_d_info), /* GT1 server */
|
||||
INTEL_VGA_DEVICE(0x016a, &intel_ivybridge_d_info), /* GT2 server */
|
||||
INTEL_VGA_DEVICE(0x0402, &intel_haswell_d_info), /* GT1 desktop */
|
||||
INTEL_VGA_DEVICE(0x0412, &intel_haswell_d_info), /* GT2 desktop */
|
||||
INTEL_VGA_DEVICE(0x040a, &intel_haswell_d_info), /* GT1 server */
|
||||
INTEL_VGA_DEVICE(0x041a, &intel_haswell_d_info), /* GT2 server */
|
||||
INTEL_VGA_DEVICE(0x0406, &intel_haswell_m_info), /* GT1 mobile */
|
||||
INTEL_VGA_DEVICE(0x0416, &intel_haswell_m_info), /* GT2 mobile */
|
||||
INTEL_VGA_DEVICE(0x0c16, &intel_haswell_d_info), /* SDV */
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
|
@ -407,9 +414,11 @@ bool i915_semaphore_is_enabled(struct drm_device *dev)
|
|||
if (i915_semaphores >= 0)
|
||||
return i915_semaphores;
|
||||
|
||||
#ifdef CONFIG_INTEL_IOMMU
|
||||
/* Enable semaphores on SNB when IO remapping is off */
|
||||
if (INTEL_INFO(dev)->gen == 6)
|
||||
return !intel_iommu_enabled;
|
||||
if (INTEL_INFO(dev)->gen == 6 && intel_iommu_gfx_mapped)
|
||||
return false;
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -622,15 +631,16 @@ static int i915_drm_thaw(struct drm_device *dev)
|
|||
|
||||
/* KMS EnterVT equivalent */
|
||||
if (drm_core_check_feature(dev, DRIVER_MODESET)) {
|
||||
if (HAS_PCH_SPLIT(dev))
|
||||
ironlake_init_pch_refclk(dev);
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
dev_priv->mm.suspended = 0;
|
||||
|
||||
error = i915_gem_init_hw(dev);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
if (HAS_PCH_SPLIT(dev))
|
||||
ironlake_init_pch_refclk(dev);
|
||||
|
||||
intel_modeset_init_hw(dev);
|
||||
drm_mode_config_reset(dev);
|
||||
drm_irq_install(dev);
|
||||
|
||||
|
@ -638,9 +648,6 @@ static int i915_drm_thaw(struct drm_device *dev)
|
|||
mutex_lock(&dev->mode_config.mutex);
|
||||
drm_helper_resume_force_mode(dev);
|
||||
mutex_unlock(&dev->mode_config.mutex);
|
||||
|
||||
if (IS_IRONLAKE_M(dev))
|
||||
ironlake_enable_rc6(dev);
|
||||
}
|
||||
|
||||
intel_opregion_init(dev);
|
||||
|
@ -886,15 +893,15 @@ int i915_reset(struct drm_device *dev)
|
|||
*/
|
||||
if (drm_core_check_feature(dev, DRIVER_MODESET) ||
|
||||
!dev_priv->mm.suspended) {
|
||||
struct intel_ring_buffer *ring;
|
||||
int i;
|
||||
|
||||
dev_priv->mm.suspended = 0;
|
||||
|
||||
i915_gem_init_swizzling(dev);
|
||||
|
||||
dev_priv->ring[RCS].init(&dev_priv->ring[RCS]);
|
||||
if (HAS_BSD(dev))
|
||||
dev_priv->ring[VCS].init(&dev_priv->ring[VCS]);
|
||||
if (HAS_BLT(dev))
|
||||
dev_priv->ring[BCS].init(&dev_priv->ring[BCS]);
|
||||
for_each_ring(ring, dev_priv, i)
|
||||
ring->init(ring);
|
||||
|
||||
i915_gem_init_ppgtt(dev);
|
||||
|
||||
|
|
|
@ -243,6 +243,8 @@ struct drm_i915_display_funcs {
|
|||
void (*update_sprite_wm)(struct drm_device *dev, int pipe,
|
||||
uint32_t sprite_width, int pixel_size);
|
||||
void (*sanitize_pm)(struct drm_device *dev);
|
||||
void (*update_linetime_wm)(struct drm_device *dev, int pipe,
|
||||
struct drm_display_mode *mode);
|
||||
int (*crtc_mode_set)(struct drm_crtc *crtc,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode,
|
||||
|
@ -408,9 +410,7 @@ typedef struct drm_i915_private {
|
|||
#define DRM_I915_HANGCHECK_PERIOD 1500 /* in ms */
|
||||
struct timer_list hangcheck_timer;
|
||||
int hangcheck_count;
|
||||
uint32_t last_acthd;
|
||||
uint32_t last_acthd_bsd;
|
||||
uint32_t last_acthd_blt;
|
||||
uint32_t last_acthd[I915_NUM_RINGS];
|
||||
uint32_t last_instdone;
|
||||
uint32_t last_instdone1;
|
||||
|
||||
|
@ -818,6 +818,11 @@ typedef struct drm_i915_private {
|
|||
struct drm_property *force_audio_property;
|
||||
} drm_i915_private_t;
|
||||
|
||||
/* Iterate over initialised rings */
|
||||
#define for_each_ring(ring__, dev_priv__, i__) \
|
||||
for ((i__) = 0; (i__) < I915_NUM_RINGS; (i__)++) \
|
||||
if (((ring__) = &(dev_priv__)->ring[(i__)]), intel_ring_initialized((ring__)))
|
||||
|
||||
enum hdmi_force_audio {
|
||||
HDMI_AUDIO_OFF_DVI = -2, /* no aux data for HDMI-DVI converter */
|
||||
HDMI_AUDIO_OFF, /* force turn off HDMI audio */
|
||||
|
|
|
@ -1655,10 +1655,11 @@ void i915_gem_reset(struct drm_device *dev)
|
|||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct drm_i915_gem_object *obj;
|
||||
struct intel_ring_buffer *ring;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < I915_NUM_RINGS; i++)
|
||||
i915_gem_reset_ring_lists(dev_priv, &dev_priv->ring[i]);
|
||||
for_each_ring(ring, dev_priv, i)
|
||||
i915_gem_reset_ring_lists(dev_priv, ring);
|
||||
|
||||
/* Remove anything from the flushing lists. The GPU cache is likely
|
||||
* to be lost on reset along with the data, so simply move the
|
||||
|
@ -1763,10 +1764,11 @@ void
|
|||
i915_gem_retire_requests(struct drm_device *dev)
|
||||
{
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
struct intel_ring_buffer *ring;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < I915_NUM_RINGS; i++)
|
||||
i915_gem_retire_requests_ring(&dev_priv->ring[i]);
|
||||
for_each_ring(ring, dev_priv, i)
|
||||
i915_gem_retire_requests_ring(ring);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -1774,6 +1776,7 @@ i915_gem_retire_work_handler(struct work_struct *work)
|
|||
{
|
||||
drm_i915_private_t *dev_priv;
|
||||
struct drm_device *dev;
|
||||
struct intel_ring_buffer *ring;
|
||||
bool idle;
|
||||
int i;
|
||||
|
||||
|
@ -1793,9 +1796,7 @@ i915_gem_retire_work_handler(struct work_struct *work)
|
|||
* objects indefinitely.
|
||||
*/
|
||||
idle = true;
|
||||
for (i = 0; i < I915_NUM_RINGS; i++) {
|
||||
struct intel_ring_buffer *ring = &dev_priv->ring[i];
|
||||
|
||||
for_each_ring(ring, dev_priv, i) {
|
||||
if (!list_empty(&ring->gpu_write_list)) {
|
||||
struct drm_i915_gem_request *request;
|
||||
int ret;
|
||||
|
@ -2137,13 +2138,18 @@ static int i915_ring_idle(struct intel_ring_buffer *ring)
|
|||
int i915_gpu_idle(struct drm_device *dev)
|
||||
{
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
struct intel_ring_buffer *ring;
|
||||
int ret, i;
|
||||
|
||||
/* Flush everything onto the inactive list. */
|
||||
for (i = 0; i < I915_NUM_RINGS; i++) {
|
||||
ret = i915_ring_idle(&dev_priv->ring[i]);
|
||||
for_each_ring(ring, dev_priv, i) {
|
||||
ret = i915_ring_idle(ring);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Is the device fubar? */
|
||||
if (WARN_ON(!list_empty(&ring->gpu_write_list)))
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -3463,9 +3469,7 @@ void i915_gem_init_ppgtt(struct drm_device *dev)
|
|||
/* GFX_MODE is per-ring on gen7+ */
|
||||
}
|
||||
|
||||
for (i = 0; i < I915_NUM_RINGS; i++) {
|
||||
ring = &dev_priv->ring[i];
|
||||
|
||||
for_each_ring(ring, dev_priv, i) {
|
||||
if (INTEL_INFO(dev)->gen >= 7)
|
||||
I915_WRITE(RING_MODE_GEN7(ring),
|
||||
_MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE));
|
||||
|
@ -3581,10 +3585,11 @@ void
|
|||
i915_gem_cleanup_ringbuffer(struct drm_device *dev)
|
||||
{
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
struct intel_ring_buffer *ring;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < I915_NUM_RINGS; i++)
|
||||
intel_cleanup_ring_buffer(&dev_priv->ring[i]);
|
||||
for_each_ring(ring, dev_priv, i)
|
||||
intel_cleanup_ring_buffer(ring);
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -3592,7 +3597,7 @@ i915_gem_entervt_ioctl(struct drm_device *dev, void *data,
|
|||
struct drm_file *file_priv)
|
||||
{
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
int ret, i;
|
||||
int ret;
|
||||
|
||||
if (drm_core_check_feature(dev, DRIVER_MODESET))
|
||||
return 0;
|
||||
|
@ -3614,10 +3619,6 @@ i915_gem_entervt_ioctl(struct drm_device *dev, void *data,
|
|||
BUG_ON(!list_empty(&dev_priv->mm.active_list));
|
||||
BUG_ON(!list_empty(&dev_priv->mm.flushing_list));
|
||||
BUG_ON(!list_empty(&dev_priv->mm.inactive_list));
|
||||
for (i = 0; i < I915_NUM_RINGS; i++) {
|
||||
BUG_ON(!list_empty(&dev_priv->ring[i].active_list));
|
||||
BUG_ON(!list_empty(&dev_priv->ring[i].request_list));
|
||||
}
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
ret = drm_irq_install(dev);
|
||||
|
|
|
@ -168,7 +168,7 @@ i915_gem_evict_everything(struct drm_device *dev, bool purgeable_only)
|
|||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
struct drm_i915_gem_object *obj, *next;
|
||||
bool lists_empty;
|
||||
int ret,i;
|
||||
int ret;
|
||||
|
||||
lists_empty = (list_empty(&dev_priv->mm.inactive_list) &&
|
||||
list_empty(&dev_priv->mm.flushing_list) &&
|
||||
|
@ -178,17 +178,13 @@ i915_gem_evict_everything(struct drm_device *dev, bool purgeable_only)
|
|||
|
||||
trace_i915_gem_evict_everything(dev, purgeable_only);
|
||||
|
||||
ret = i915_gpu_idle(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* The gpu_idle will flush everything in the write domain to the
|
||||
* active list. Then we must move everything off the active list
|
||||
* with retire requests.
|
||||
*/
|
||||
for (i = 0; i < I915_NUM_RINGS; i++)
|
||||
if (WARN_ON(!list_empty(&dev_priv->ring[i].gpu_write_list)))
|
||||
return -EBUSY;
|
||||
ret = i915_gpu_idle(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
i915_gem_retire_requests(dev);
|
||||
|
||||
|
@ -203,5 +199,5 @@ i915_gem_evict_everything(struct drm_device *dev, bool purgeable_only)
|
|||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -967,11 +967,14 @@ i915_gem_execbuffer_move_to_active(struct list_head *objects,
|
|||
obj->pending_gpu_write = true;
|
||||
list_move_tail(&obj->gpu_write_list,
|
||||
&ring->gpu_write_list);
|
||||
intel_mark_busy(ring->dev, obj);
|
||||
if (obj->pin_count) /* check for potential scanout */
|
||||
intel_mark_busy(ring->dev, obj);
|
||||
}
|
||||
|
||||
trace_i915_gem_object_change_domain(obj, old_read, old_write);
|
||||
}
|
||||
|
||||
intel_mark_busy(ring->dev, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -1061,17 +1064,9 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
|
|||
ring = &dev_priv->ring[RCS];
|
||||
break;
|
||||
case I915_EXEC_BSD:
|
||||
if (!HAS_BSD(dev)) {
|
||||
DRM_DEBUG("execbuf with invalid ring (BSD)\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
ring = &dev_priv->ring[VCS];
|
||||
break;
|
||||
case I915_EXEC_BLT:
|
||||
if (!HAS_BLT(dev)) {
|
||||
DRM_DEBUG("execbuf with invalid ring (BLT)\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
ring = &dev_priv->ring[BCS];
|
||||
break;
|
||||
default:
|
||||
|
@ -1079,6 +1074,11 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
|
|||
(int)(args->flags & I915_EXEC_RING_MASK));
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!intel_ring_initialized(ring)) {
|
||||
DRM_DEBUG("execbuf with invalid ring: %d\n",
|
||||
(int)(args->flags & I915_EXEC_RING_MASK));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mode = args->flags & I915_EXEC_CONSTANTS_MASK;
|
||||
mask = I915_EXEC_CONSTANTS_MASK;
|
||||
|
|
|
@ -533,14 +533,11 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void pch_irq_handler(struct drm_device *dev)
|
||||
static void pch_irq_handler(struct drm_device *dev, u32 pch_iir)
|
||||
{
|
||||
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
|
||||
u32 pch_iir;
|
||||
int pipe;
|
||||
|
||||
pch_iir = I915_READ(SDEIIR);
|
||||
|
||||
if (pch_iir & SDE_AUDIO_POWER_MASK)
|
||||
DRM_DEBUG_DRIVER("PCH audio power change on port %d\n",
|
||||
(pch_iir & SDE_AUDIO_POWER_MASK) >>
|
||||
|
@ -580,72 +577,61 @@ static irqreturn_t ivybridge_irq_handler(DRM_IRQ_ARGS)
|
|||
{
|
||||
struct drm_device *dev = (struct drm_device *) arg;
|
||||
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
|
||||
int ret = IRQ_NONE;
|
||||
u32 de_iir, gt_iir, de_ier, pch_iir, pm_iir;
|
||||
u32 de_iir, gt_iir, de_ier, pm_iir;
|
||||
irqreturn_t ret = IRQ_NONE;
|
||||
int i;
|
||||
|
||||
atomic_inc(&dev_priv->irq_received);
|
||||
|
||||
/* disable master interrupt before clearing iir */
|
||||
de_ier = I915_READ(DEIER);
|
||||
I915_WRITE(DEIER, de_ier & ~DE_MASTER_IRQ_CONTROL);
|
||||
POSTING_READ(DEIER);
|
||||
|
||||
gt_iir = I915_READ(GTIIR);
|
||||
if (gt_iir) {
|
||||
snb_gt_irq_handler(dev, dev_priv, gt_iir);
|
||||
I915_WRITE(GTIIR, gt_iir);
|
||||
ret = IRQ_HANDLED;
|
||||
}
|
||||
|
||||
de_iir = I915_READ(DEIIR);
|
||||
gt_iir = I915_READ(GTIIR);
|
||||
pch_iir = I915_READ(SDEIIR);
|
||||
if (de_iir) {
|
||||
if (de_iir & DE_GSE_IVB)
|
||||
intel_opregion_gse_intr(dev);
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
if (de_iir & (DE_PLANEA_FLIP_DONE_IVB << (5 * i))) {
|
||||
intel_prepare_page_flip(dev, i);
|
||||
intel_finish_page_flip_plane(dev, i);
|
||||
}
|
||||
if (de_iir & (DE_PIPEA_VBLANK_IVB << (5 * i)))
|
||||
drm_handle_vblank(dev, i);
|
||||
}
|
||||
|
||||
/* check event from PCH */
|
||||
if (de_iir & DE_PCH_EVENT_IVB) {
|
||||
u32 pch_iir = I915_READ(SDEIIR);
|
||||
|
||||
if (pch_iir & SDE_HOTPLUG_MASK_CPT)
|
||||
queue_work(dev_priv->wq, &dev_priv->hotplug_work);
|
||||
pch_irq_handler(dev, pch_iir);
|
||||
|
||||
/* clear PCH hotplug event before clear CPU irq */
|
||||
I915_WRITE(SDEIIR, pch_iir);
|
||||
}
|
||||
|
||||
I915_WRITE(DEIIR, de_iir);
|
||||
ret = IRQ_HANDLED;
|
||||
}
|
||||
|
||||
pm_iir = I915_READ(GEN6_PMIIR);
|
||||
|
||||
if (de_iir == 0 && gt_iir == 0 && pch_iir == 0 && pm_iir == 0)
|
||||
goto done;
|
||||
|
||||
ret = IRQ_HANDLED;
|
||||
|
||||
snb_gt_irq_handler(dev, dev_priv, gt_iir);
|
||||
|
||||
if (de_iir & DE_GSE_IVB)
|
||||
intel_opregion_gse_intr(dev);
|
||||
|
||||
if (de_iir & DE_PLANEA_FLIP_DONE_IVB) {
|
||||
intel_prepare_page_flip(dev, 0);
|
||||
intel_finish_page_flip_plane(dev, 0);
|
||||
if (pm_iir) {
|
||||
if (pm_iir & GEN6_PM_DEFERRED_EVENTS)
|
||||
gen6_queue_rps_work(dev_priv, pm_iir);
|
||||
I915_WRITE(GEN6_PMIIR, pm_iir);
|
||||
ret = IRQ_HANDLED;
|
||||
}
|
||||
|
||||
if (de_iir & DE_PLANEB_FLIP_DONE_IVB) {
|
||||
intel_prepare_page_flip(dev, 1);
|
||||
intel_finish_page_flip_plane(dev, 1);
|
||||
}
|
||||
|
||||
if (de_iir & DE_PLANEC_FLIP_DONE_IVB) {
|
||||
intel_prepare_page_flip(dev, 2);
|
||||
intel_finish_page_flip_plane(dev, 2);
|
||||
}
|
||||
|
||||
if (de_iir & DE_PIPEA_VBLANK_IVB)
|
||||
drm_handle_vblank(dev, 0);
|
||||
|
||||
if (de_iir & DE_PIPEB_VBLANK_IVB)
|
||||
drm_handle_vblank(dev, 1);
|
||||
|
||||
if (de_iir & DE_PIPEC_VBLANK_IVB)
|
||||
drm_handle_vblank(dev, 2);
|
||||
|
||||
/* check event from PCH */
|
||||
if (de_iir & DE_PCH_EVENT_IVB) {
|
||||
if (pch_iir & SDE_HOTPLUG_MASK_CPT)
|
||||
queue_work(dev_priv->wq, &dev_priv->hotplug_work);
|
||||
pch_irq_handler(dev);
|
||||
}
|
||||
|
||||
if (pm_iir & GEN6_PM_DEFERRED_EVENTS)
|
||||
gen6_queue_rps_work(dev_priv, pm_iir);
|
||||
|
||||
/* should clear PCH hotplug event before clear CPU irq */
|
||||
I915_WRITE(SDEIIR, pch_iir);
|
||||
I915_WRITE(GTIIR, gt_iir);
|
||||
I915_WRITE(DEIIR, de_iir);
|
||||
I915_WRITE(GEN6_PMIIR, pm_iir);
|
||||
|
||||
done:
|
||||
I915_WRITE(DEIER, de_ier);
|
||||
POSTING_READ(DEIER);
|
||||
|
||||
|
@ -721,7 +707,7 @@ static irqreturn_t ironlake_irq_handler(DRM_IRQ_ARGS)
|
|||
if (de_iir & DE_PCH_EVENT) {
|
||||
if (pch_iir & hotplug_mask)
|
||||
queue_work(dev_priv->wq, &dev_priv->hotplug_work);
|
||||
pch_irq_handler(dev);
|
||||
pch_irq_handler(dev, pch_iir);
|
||||
}
|
||||
|
||||
if (de_iir & DE_PCU_EVENT) {
|
||||
|
@ -1036,15 +1022,11 @@ static void i915_gem_record_rings(struct drm_device *dev,
|
|||
struct drm_i915_error_state *error)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct intel_ring_buffer *ring;
|
||||
struct drm_i915_gem_request *request;
|
||||
int i, count;
|
||||
|
||||
for (i = 0; i < I915_NUM_RINGS; i++) {
|
||||
struct intel_ring_buffer *ring = &dev_priv->ring[i];
|
||||
|
||||
if (ring->obj == NULL)
|
||||
continue;
|
||||
|
||||
for_each_ring(ring, dev_priv, i) {
|
||||
i915_record_ring_state(dev, error, ring);
|
||||
|
||||
error->ring[i].batchbuffer =
|
||||
|
@ -1309,6 +1291,8 @@ static void i915_report_and_clear_eir(struct drm_device *dev)
|
|||
void i915_handle_error(struct drm_device *dev, bool wedged)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct intel_ring_buffer *ring;
|
||||
int i;
|
||||
|
||||
i915_capture_error_state(dev);
|
||||
i915_report_and_clear_eir(dev);
|
||||
|
@ -1320,11 +1304,8 @@ void i915_handle_error(struct drm_device *dev, bool wedged)
|
|||
/*
|
||||
* Wakeup waiting processes so they don't hang
|
||||
*/
|
||||
wake_up_all(&dev_priv->ring[RCS].irq_queue);
|
||||
if (HAS_BSD(dev))
|
||||
wake_up_all(&dev_priv->ring[VCS].irq_queue);
|
||||
if (HAS_BLT(dev))
|
||||
wake_up_all(&dev_priv->ring[BCS].irq_queue);
|
||||
for_each_ring(ring, dev_priv, i)
|
||||
wake_up_all(&ring->irq_queue);
|
||||
}
|
||||
|
||||
queue_work(dev_priv->wq, &dev_priv->error_work);
|
||||
|
@ -1529,11 +1510,6 @@ ring_last_seqno(struct intel_ring_buffer *ring)
|
|||
|
||||
static bool i915_hangcheck_ring_idle(struct intel_ring_buffer *ring, bool *err)
|
||||
{
|
||||
/* We don't check whether the ring even exists before calling this
|
||||
* function. Hence check whether it's initialized. */
|
||||
if (ring->obj == NULL)
|
||||
return true;
|
||||
|
||||
if (list_empty(&ring->request_list) ||
|
||||
i915_seqno_passed(ring->get_seqno(ring), ring_last_seqno(ring))) {
|
||||
/* Issue a wake-up to catch stuck h/w. */
|
||||
|
@ -1567,26 +1543,25 @@ static bool i915_hangcheck_hung(struct drm_device *dev)
|
|||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
|
||||
if (dev_priv->hangcheck_count++ > 1) {
|
||||
bool hung = true;
|
||||
|
||||
DRM_ERROR("Hangcheck timer elapsed... GPU hung\n");
|
||||
i915_handle_error(dev, true);
|
||||
|
||||
if (!IS_GEN2(dev)) {
|
||||
struct intel_ring_buffer *ring;
|
||||
int i;
|
||||
|
||||
/* Is the chip hanging on a WAIT_FOR_EVENT?
|
||||
* If so we can simply poke the RB_WAIT bit
|
||||
* and break the hang. This should work on
|
||||
* all but the second generation chipsets.
|
||||
*/
|
||||
if (kick_ring(&dev_priv->ring[RCS]))
|
||||
return false;
|
||||
|
||||
if (HAS_BSD(dev) && kick_ring(&dev_priv->ring[VCS]))
|
||||
return false;
|
||||
|
||||
if (HAS_BLT(dev) && kick_ring(&dev_priv->ring[BCS]))
|
||||
return false;
|
||||
for_each_ring(ring, dev_priv, i)
|
||||
hung &= !kick_ring(ring);
|
||||
}
|
||||
|
||||
return true;
|
||||
return hung;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -1602,16 +1577,23 @@ void i915_hangcheck_elapsed(unsigned long data)
|
|||
{
|
||||
struct drm_device *dev = (struct drm_device *)data;
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
uint32_t acthd, instdone, instdone1, acthd_bsd, acthd_blt;
|
||||
bool err = false;
|
||||
uint32_t acthd[I915_NUM_RINGS], instdone, instdone1;
|
||||
struct intel_ring_buffer *ring;
|
||||
bool err = false, idle;
|
||||
int i;
|
||||
|
||||
if (!i915_enable_hangcheck)
|
||||
return;
|
||||
|
||||
memset(acthd, 0, sizeof(acthd));
|
||||
idle = true;
|
||||
for_each_ring(ring, dev_priv, i) {
|
||||
idle &= i915_hangcheck_ring_idle(ring, &err);
|
||||
acthd[i] = intel_ring_get_active_head(ring);
|
||||
}
|
||||
|
||||
/* If all work is done then ACTHD clearly hasn't advanced. */
|
||||
if (i915_hangcheck_ring_idle(&dev_priv->ring[RCS], &err) &&
|
||||
i915_hangcheck_ring_idle(&dev_priv->ring[VCS], &err) &&
|
||||
i915_hangcheck_ring_idle(&dev_priv->ring[BCS], &err)) {
|
||||
if (idle) {
|
||||
if (err) {
|
||||
if (i915_hangcheck_hung(dev))
|
||||
return;
|
||||
|
@ -1630,15 +1612,8 @@ void i915_hangcheck_elapsed(unsigned long data)
|
|||
instdone = I915_READ(INSTDONE_I965);
|
||||
instdone1 = I915_READ(INSTDONE1);
|
||||
}
|
||||
acthd = intel_ring_get_active_head(&dev_priv->ring[RCS]);
|
||||
acthd_bsd = HAS_BSD(dev) ?
|
||||
intel_ring_get_active_head(&dev_priv->ring[VCS]) : 0;
|
||||
acthd_blt = HAS_BLT(dev) ?
|
||||
intel_ring_get_active_head(&dev_priv->ring[BCS]) : 0;
|
||||
|
||||
if (dev_priv->last_acthd == acthd &&
|
||||
dev_priv->last_acthd_bsd == acthd_bsd &&
|
||||
dev_priv->last_acthd_blt == acthd_blt &&
|
||||
if (memcmp(dev_priv->last_acthd, acthd, sizeof(acthd)) == 0 &&
|
||||
dev_priv->last_instdone == instdone &&
|
||||
dev_priv->last_instdone1 == instdone1) {
|
||||
if (i915_hangcheck_hung(dev))
|
||||
|
@ -1646,9 +1621,7 @@ void i915_hangcheck_elapsed(unsigned long data)
|
|||
} else {
|
||||
dev_priv->hangcheck_count = 0;
|
||||
|
||||
dev_priv->last_acthd = acthd;
|
||||
dev_priv->last_acthd_bsd = acthd_bsd;
|
||||
dev_priv->last_acthd_blt = acthd_blt;
|
||||
memcpy(dev_priv->last_acthd, acthd, sizeof(acthd));
|
||||
dev_priv->last_instdone = instdone;
|
||||
dev_priv->last_instdone1 = instdone1;
|
||||
}
|
||||
|
@ -2597,8 +2570,7 @@ void intel_irq_init(struct drm_device *dev)
|
|||
|
||||
dev->driver->get_vblank_counter = i915_get_vblank_counter;
|
||||
dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */
|
||||
if (IS_G4X(dev) || IS_GEN5(dev) || IS_GEN6(dev) || IS_IVYBRIDGE(dev) ||
|
||||
IS_VALLEYVIEW(dev)) {
|
||||
if (IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5) {
|
||||
dev->max_vblank_count = 0xffffffff; /* full 32 bit counter */
|
||||
dev->driver->get_vblank_counter = gm45_get_vblank_counter;
|
||||
}
|
||||
|
@ -2624,6 +2596,14 @@ void intel_irq_init(struct drm_device *dev)
|
|||
dev->driver->irq_uninstall = ironlake_irq_uninstall;
|
||||
dev->driver->enable_vblank = ivybridge_enable_vblank;
|
||||
dev->driver->disable_vblank = ivybridge_disable_vblank;
|
||||
} else if (IS_HASWELL(dev)) {
|
||||
/* Share interrupts handling with IVB */
|
||||
dev->driver->irq_handler = ivybridge_irq_handler;
|
||||
dev->driver->irq_preinstall = ironlake_irq_preinstall;
|
||||
dev->driver->irq_postinstall = ivybridge_irq_postinstall;
|
||||
dev->driver->irq_uninstall = ironlake_irq_uninstall;
|
||||
dev->driver->enable_vblank = ivybridge_enable_vblank;
|
||||
dev->driver->disable_vblank = ivybridge_disable_vblank;
|
||||
} else if (HAS_PCH_SPLIT(dev)) {
|
||||
dev->driver->irq_handler = ironlake_irq_handler;
|
||||
dev->driver->irq_preinstall = ironlake_irq_preinstall;
|
||||
|
|
|
@ -1697,9 +1697,12 @@
|
|||
/* Video Data Island Packet control */
|
||||
#define VIDEO_DIP_DATA 0x61178
|
||||
#define VIDEO_DIP_CTL 0x61170
|
||||
/* Pre HSW: */
|
||||
#define VIDEO_DIP_ENABLE (1 << 31)
|
||||
#define VIDEO_DIP_PORT_B (1 << 29)
|
||||
#define VIDEO_DIP_PORT_C (2 << 29)
|
||||
#define VIDEO_DIP_PORT_D (3 << 29)
|
||||
#define VIDEO_DIP_PORT_MASK (3 << 29)
|
||||
#define VIDEO_DIP_ENABLE_AVI (1 << 21)
|
||||
#define VIDEO_DIP_ENABLE_VENDOR (2 << 21)
|
||||
#define VIDEO_DIP_ENABLE_SPD (8 << 21)
|
||||
|
@ -1710,6 +1713,10 @@
|
|||
#define VIDEO_DIP_FREQ_ONCE (0 << 16)
|
||||
#define VIDEO_DIP_FREQ_VSYNC (1 << 16)
|
||||
#define VIDEO_DIP_FREQ_2VSYNC (2 << 16)
|
||||
#define VIDEO_DIP_FREQ_MASK (3 << 16)
|
||||
/* HSW and later: */
|
||||
#define VIDEO_DIP_ENABLE_AVI_HSW (1 << 12)
|
||||
#define VIDEO_DIP_ENABLE_SPD_HSW (1 << 0)
|
||||
|
||||
/* Panel power sequencing */
|
||||
#define PP_STATUS 0x61200
|
||||
|
@ -2476,7 +2483,8 @@
|
|||
|
||||
/* Pipe A */
|
||||
#define _PIPEADSL 0x70000
|
||||
#define DSL_LINEMASK 0x00000fff
|
||||
#define DSL_LINEMASK_GEN2 0x00000fff
|
||||
#define DSL_LINEMASK_GEN3 0x00001fff
|
||||
#define _PIPEACONF 0x70008
|
||||
#define PIPECONF_ENABLE (1<<31)
|
||||
#define PIPECONF_DISABLE 0
|
||||
|
@ -3520,6 +3528,42 @@
|
|||
#define VLV_TVIDEO_DIP_GCP(pipe) \
|
||||
_PIPE(pipe, VLV_VIDEO_DIP_GDCP_PAYLOAD_A, VLV_VIDEO_DIP_GDCP_PAYLOAD_B)
|
||||
|
||||
/* Haswell DIP controls */
|
||||
#define HSW_VIDEO_DIP_CTL_A 0x60200
|
||||
#define HSW_VIDEO_DIP_AVI_DATA_A 0x60220
|
||||
#define HSW_VIDEO_DIP_VS_DATA_A 0x60260
|
||||
#define HSW_VIDEO_DIP_SPD_DATA_A 0x602A0
|
||||
#define HSW_VIDEO_DIP_GMP_DATA_A 0x602E0
|
||||
#define HSW_VIDEO_DIP_VSC_DATA_A 0x60320
|
||||
#define HSW_VIDEO_DIP_AVI_ECC_A 0x60240
|
||||
#define HSW_VIDEO_DIP_VS_ECC_A 0x60280
|
||||
#define HSW_VIDEO_DIP_SPD_ECC_A 0x602C0
|
||||
#define HSW_VIDEO_DIP_GMP_ECC_A 0x60300
|
||||
#define HSW_VIDEO_DIP_VSC_ECC_A 0x60344
|
||||
#define HSW_VIDEO_DIP_GCP_A 0x60210
|
||||
|
||||
#define HSW_VIDEO_DIP_CTL_B 0x61200
|
||||
#define HSW_VIDEO_DIP_AVI_DATA_B 0x61220
|
||||
#define HSW_VIDEO_DIP_VS_DATA_B 0x61260
|
||||
#define HSW_VIDEO_DIP_SPD_DATA_B 0x612A0
|
||||
#define HSW_VIDEO_DIP_GMP_DATA_B 0x612E0
|
||||
#define HSW_VIDEO_DIP_VSC_DATA_B 0x61320
|
||||
#define HSW_VIDEO_DIP_BVI_ECC_B 0x61240
|
||||
#define HSW_VIDEO_DIP_VS_ECC_B 0x61280
|
||||
#define HSW_VIDEO_DIP_SPD_ECC_B 0x612C0
|
||||
#define HSW_VIDEO_DIP_GMP_ECC_B 0x61300
|
||||
#define HSW_VIDEO_DIP_VSC_ECC_B 0x61344
|
||||
#define HSW_VIDEO_DIP_GCP_B 0x61210
|
||||
|
||||
#define HSW_TVIDEO_DIP_CTL(pipe) \
|
||||
_PIPE(pipe, HSW_VIDEO_DIP_CTL_A, HSW_VIDEO_DIP_CTL_B)
|
||||
#define HSW_TVIDEO_DIP_AVI_DATA(pipe) \
|
||||
_PIPE(pipe, HSW_VIDEO_DIP_AVI_DATA_A, HSW_VIDEO_DIP_AVI_DATA_B)
|
||||
#define HSW_TVIDEO_DIP_SPD_DATA(pipe) \
|
||||
_PIPE(pipe, HSW_VIDEO_DIP_SPD_DATA_A, HSW_VIDEO_DIP_SPD_DATA_B)
|
||||
#define HSW_TVIDEO_DIP_GCP(pipe) \
|
||||
_PIPE(pipe, HSW_VIDEO_DIP_GCP_A, HSW_VIDEO_DIP_GCP_B)
|
||||
|
||||
#define _TRANS_HTOTAL_B 0xe1000
|
||||
#define _TRANS_HBLANK_B 0xe1004
|
||||
#define _TRANS_HSYNC_B 0xe1008
|
||||
|
|
|
@ -876,12 +876,6 @@ int i915_restore_state(struct drm_device *dev)
|
|||
I915_WRITE(IER, dev_priv->saveIER);
|
||||
I915_WRITE(IMR, dev_priv->saveIMR);
|
||||
}
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
if (drm_core_check_feature(dev, DRIVER_MODESET))
|
||||
intel_modeset_init_hw(dev);
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
|
||||
/* Cache mode state */
|
||||
I915_WRITE(CACHE_MODE_0, dev_priv->saveCACHE_MODE_0 | 0xffff0000);
|
||||
|
|
|
@ -615,7 +615,11 @@ void intel_crt_init(struct drm_device *dev)
|
|||
crt->base.clone_mask = (1 << INTEL_SDVO_NON_TV_CLONE_BIT |
|
||||
1 << INTEL_ANALOG_CLONE_BIT |
|
||||
1 << INTEL_SDVO_LVDS_CLONE_BIT);
|
||||
crt->base.crtc_mask = (1 << 0) | (1 << 1);
|
||||
if (IS_HASWELL(dev))
|
||||
crt->base.crtc_mask = (1 << 0);
|
||||
else
|
||||
crt->base.crtc_mask = (1 << 0) | (1 << 1);
|
||||
|
||||
if (IS_GEN2(dev))
|
||||
connector->interlace_allowed = 0;
|
||||
else
|
||||
|
|
|
@ -0,0 +1,755 @@
|
|||
/*
|
||||
* Copyright © 2012 Intel Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*
|
||||
* Authors:
|
||||
* Eugeni Dodonov <eugeni.dodonov@intel.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#include "i915_drv.h"
|
||||
#include "intel_drv.h"
|
||||
|
||||
/* HDMI/DVI modes ignore everything but the last 2 items. So we share
|
||||
* them for both DP and FDI transports, allowing those ports to
|
||||
* automatically adapt to HDMI connections as well
|
||||
*/
|
||||
static const u32 hsw_ddi_translations_dp[] = {
|
||||
0x00FFFFFF, 0x0006000E, /* DP parameters */
|
||||
0x00D75FFF, 0x0005000A,
|
||||
0x00C30FFF, 0x00040006,
|
||||
0x80AAAFFF, 0x000B0000,
|
||||
0x00FFFFFF, 0x0005000A,
|
||||
0x00D75FFF, 0x000C0004,
|
||||
0x80C30FFF, 0x000B0000,
|
||||
0x00FFFFFF, 0x00040006,
|
||||
0x80D75FFF, 0x000B0000,
|
||||
0x00FFFFFF, 0x00040006 /* HDMI parameters */
|
||||
};
|
||||
|
||||
static const u32 hsw_ddi_translations_fdi[] = {
|
||||
0x00FFFFFF, 0x0007000E, /* FDI parameters */
|
||||
0x00D75FFF, 0x000F000A,
|
||||
0x00C30FFF, 0x00060006,
|
||||
0x00AAAFFF, 0x001E0000,
|
||||
0x00FFFFFF, 0x000F000A,
|
||||
0x00D75FFF, 0x00160004,
|
||||
0x00C30FFF, 0x001E0000,
|
||||
0x00FFFFFF, 0x00060006,
|
||||
0x00D75FFF, 0x001E0000,
|
||||
0x00FFFFFF, 0x00040006 /* HDMI parameters */
|
||||
};
|
||||
|
||||
/* On Haswell, DDI port buffers must be programmed with correct values
|
||||
* in advance. The buffer values are different for FDI and DP modes,
|
||||
* but the HDMI/DVI fields are shared among those. So we program the DDI
|
||||
* in either FDI or DP modes only, as HDMI connections will work with both
|
||||
* of those
|
||||
*/
|
||||
void intel_prepare_ddi_buffers(struct drm_device *dev, enum port port, bool use_fdi_mode)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
u32 reg;
|
||||
int i;
|
||||
const u32 *ddi_translations = ((use_fdi_mode) ?
|
||||
hsw_ddi_translations_fdi :
|
||||
hsw_ddi_translations_dp);
|
||||
|
||||
DRM_DEBUG_DRIVER("Initializing DDI buffers for port %c in %s mode\n",
|
||||
port_name(port),
|
||||
use_fdi_mode ? "FDI" : "DP");
|
||||
|
||||
WARN((use_fdi_mode && (port != PORT_E)),
|
||||
"Programming port %c in FDI mode, this probably will not work.\n",
|
||||
port_name(port));
|
||||
|
||||
for (i=0, reg=DDI_BUF_TRANS(port); i < ARRAY_SIZE(hsw_ddi_translations_fdi); i++) {
|
||||
I915_WRITE(reg, ddi_translations[i]);
|
||||
reg += 4;
|
||||
}
|
||||
}
|
||||
|
||||
/* Program DDI buffers translations for DP. By default, program ports A-D in DP
|
||||
* mode and port E for FDI.
|
||||
*/
|
||||
void intel_prepare_ddi(struct drm_device *dev)
|
||||
{
|
||||
int port;
|
||||
|
||||
if (IS_HASWELL(dev)) {
|
||||
for (port = PORT_A; port < PORT_E; port++)
|
||||
intel_prepare_ddi_buffers(dev, port, false);
|
||||
|
||||
/* DDI E is the suggested one to work in FDI mode, so program is as such by
|
||||
* default. It will have to be re-programmed in case a digital DP output
|
||||
* will be detected on it
|
||||
*/
|
||||
intel_prepare_ddi_buffers(dev, PORT_E, true);
|
||||
}
|
||||
}
|
||||
|
||||
static const long hsw_ddi_buf_ctl_values[] = {
|
||||
DDI_BUF_EMP_400MV_0DB_HSW,
|
||||
DDI_BUF_EMP_400MV_3_5DB_HSW,
|
||||
DDI_BUF_EMP_400MV_6DB_HSW,
|
||||
DDI_BUF_EMP_400MV_9_5DB_HSW,
|
||||
DDI_BUF_EMP_600MV_0DB_HSW,
|
||||
DDI_BUF_EMP_600MV_3_5DB_HSW,
|
||||
DDI_BUF_EMP_600MV_6DB_HSW,
|
||||
DDI_BUF_EMP_800MV_0DB_HSW,
|
||||
DDI_BUF_EMP_800MV_3_5DB_HSW
|
||||
};
|
||||
|
||||
|
||||
/* Starting with Haswell, different DDI ports can work in FDI mode for
|
||||
* connection to the PCH-located connectors. For this, it is necessary to train
|
||||
* both the DDI port and PCH receiver for the desired DDI buffer settings.
|
||||
*
|
||||
* The recommended port to work in FDI mode is DDI E, which we use here. Also,
|
||||
* please note that when FDI mode is active on DDI E, it shares 2 lines with
|
||||
* DDI A (which is used for eDP)
|
||||
*/
|
||||
|
||||
void hsw_fdi_link_train(struct drm_crtc *crtc)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
||||
int pipe = intel_crtc->pipe;
|
||||
u32 reg, temp, i;
|
||||
|
||||
/* Configure CPU PLL, wait for warmup */
|
||||
I915_WRITE(SPLL_CTL,
|
||||
SPLL_PLL_ENABLE |
|
||||
SPLL_PLL_FREQ_1350MHz |
|
||||
SPLL_PLL_SCC);
|
||||
|
||||
/* Use SPLL to drive the output when in FDI mode */
|
||||
I915_WRITE(PORT_CLK_SEL(PORT_E),
|
||||
PORT_CLK_SEL_SPLL);
|
||||
I915_WRITE(PIPE_CLK_SEL(pipe),
|
||||
PIPE_CLK_SEL_PORT(PORT_E));
|
||||
|
||||
udelay(20);
|
||||
|
||||
/* Start the training iterating through available voltages and emphasis */
|
||||
for (i=0; i < ARRAY_SIZE(hsw_ddi_buf_ctl_values); i++) {
|
||||
/* Configure DP_TP_CTL with auto-training */
|
||||
I915_WRITE(DP_TP_CTL(PORT_E),
|
||||
DP_TP_CTL_FDI_AUTOTRAIN |
|
||||
DP_TP_CTL_ENHANCED_FRAME_ENABLE |
|
||||
DP_TP_CTL_LINK_TRAIN_PAT1 |
|
||||
DP_TP_CTL_ENABLE);
|
||||
|
||||
/* Configure and enable DDI_BUF_CTL for DDI E with next voltage */
|
||||
temp = I915_READ(DDI_BUF_CTL(PORT_E));
|
||||
temp = (temp & ~DDI_BUF_EMP_MASK);
|
||||
I915_WRITE(DDI_BUF_CTL(PORT_E),
|
||||
temp |
|
||||
DDI_BUF_CTL_ENABLE |
|
||||
DDI_PORT_WIDTH_X2 |
|
||||
hsw_ddi_buf_ctl_values[i]);
|
||||
|
||||
udelay(600);
|
||||
|
||||
/* Enable CPU FDI Receiver with auto-training */
|
||||
reg = FDI_RX_CTL(pipe);
|
||||
I915_WRITE(reg,
|
||||
I915_READ(reg) |
|
||||
FDI_LINK_TRAIN_AUTO |
|
||||
FDI_RX_ENABLE |
|
||||
FDI_LINK_TRAIN_PATTERN_1_CPT |
|
||||
FDI_RX_ENHANCE_FRAME_ENABLE |
|
||||
FDI_PORT_WIDTH_2X_LPT |
|
||||
FDI_RX_PLL_ENABLE);
|
||||
POSTING_READ(reg);
|
||||
udelay(100);
|
||||
|
||||
temp = I915_READ(DP_TP_STATUS(PORT_E));
|
||||
if (temp & DP_TP_STATUS_AUTOTRAIN_DONE) {
|
||||
DRM_DEBUG_DRIVER("BUF_CTL training done on %d step\n", i);
|
||||
|
||||
/* Enable normal pixel sending for FDI */
|
||||
I915_WRITE(DP_TP_CTL(PORT_E),
|
||||
DP_TP_CTL_FDI_AUTOTRAIN |
|
||||
DP_TP_CTL_LINK_TRAIN_NORMAL |
|
||||
DP_TP_CTL_ENHANCED_FRAME_ENABLE |
|
||||
DP_TP_CTL_ENABLE);
|
||||
|
||||
/* Enable PIPE_DDI_FUNC_CTL for the pipe to work in FDI mode */
|
||||
temp = I915_READ(DDI_FUNC_CTL(pipe));
|
||||
temp &= ~PIPE_DDI_PORT_MASK;
|
||||
temp |= PIPE_DDI_SELECT_PORT(PORT_E) |
|
||||
PIPE_DDI_MODE_SELECT_FDI |
|
||||
PIPE_DDI_FUNC_ENABLE |
|
||||
PIPE_DDI_PORT_WIDTH_X2;
|
||||
I915_WRITE(DDI_FUNC_CTL(pipe),
|
||||
temp);
|
||||
break;
|
||||
} else {
|
||||
DRM_ERROR("Error training BUF_CTL %d\n", i);
|
||||
|
||||
/* Disable DP_TP_CTL and FDI_RX_CTL) and retry */
|
||||
I915_WRITE(DP_TP_CTL(PORT_E),
|
||||
I915_READ(DP_TP_CTL(PORT_E)) &
|
||||
~DP_TP_CTL_ENABLE);
|
||||
I915_WRITE(FDI_RX_CTL(pipe),
|
||||
I915_READ(FDI_RX_CTL(pipe)) &
|
||||
~FDI_RX_PLL_ENABLE);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
DRM_DEBUG_KMS("FDI train done.\n");
|
||||
}
|
||||
|
||||
/* For DDI connections, it is possible to support different outputs over the
|
||||
* same DDI port, such as HDMI or DP or even VGA via FDI. So we don't know by
|
||||
* the time the output is detected what exactly is on the other end of it. This
|
||||
* function aims at providing support for this detection and proper output
|
||||
* configuration.
|
||||
*/
|
||||
void intel_ddi_init(struct drm_device *dev, enum port port)
|
||||
{
|
||||
/* For now, we don't do any proper output detection and assume that we
|
||||
* handle HDMI only */
|
||||
|
||||
switch(port){
|
||||
case PORT_A:
|
||||
/* We don't handle eDP and DP yet */
|
||||
DRM_DEBUG_DRIVER("Found digital output on DDI port A\n");
|
||||
break;
|
||||
/* Assume that the ports B, C and D are working in HDMI mode for now */
|
||||
case PORT_B:
|
||||
case PORT_C:
|
||||
case PORT_D:
|
||||
intel_hdmi_init(dev, DDI_BUF_CTL(port));
|
||||
break;
|
||||
default:
|
||||
DRM_DEBUG_DRIVER("No handlers defined for port %d, skipping DDI initialization\n",
|
||||
port);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* WRPLL clock dividers */
|
||||
struct wrpll_tmds_clock {
|
||||
u32 clock;
|
||||
u16 p; /* Post divider */
|
||||
u16 n2; /* Feedback divider */
|
||||
u16 r2; /* Reference divider */
|
||||
};
|
||||
|
||||
/* Table of matching values for WRPLL clocks programming for each frequency */
|
||||
static const struct wrpll_tmds_clock wrpll_tmds_clock_table[] = {
|
||||
{19750, 38, 25, 18},
|
||||
{20000, 48, 32, 18},
|
||||
{21000, 36, 21, 15},
|
||||
{21912, 42, 29, 17},
|
||||
{22000, 36, 22, 15},
|
||||
{23000, 36, 23, 15},
|
||||
{23500, 40, 40, 23},
|
||||
{23750, 26, 16, 14},
|
||||
{23750, 26, 16, 14},
|
||||
{24000, 36, 24, 15},
|
||||
{25000, 36, 25, 15},
|
||||
{25175, 26, 40, 33},
|
||||
{25200, 30, 21, 15},
|
||||
{26000, 36, 26, 15},
|
||||
{27000, 30, 21, 14},
|
||||
{27027, 18, 100, 111},
|
||||
{27500, 30, 29, 19},
|
||||
{28000, 34, 30, 17},
|
||||
{28320, 26, 30, 22},
|
||||
{28322, 32, 42, 25},
|
||||
{28750, 24, 23, 18},
|
||||
{29000, 30, 29, 18},
|
||||
{29750, 32, 30, 17},
|
||||
{30000, 30, 25, 15},
|
||||
{30750, 30, 41, 24},
|
||||
{31000, 30, 31, 18},
|
||||
{31500, 30, 28, 16},
|
||||
{32000, 30, 32, 18},
|
||||
{32500, 28, 32, 19},
|
||||
{33000, 24, 22, 15},
|
||||
{34000, 28, 30, 17},
|
||||
{35000, 26, 32, 19},
|
||||
{35500, 24, 30, 19},
|
||||
{36000, 26, 26, 15},
|
||||
{36750, 26, 46, 26},
|
||||
{37000, 24, 23, 14},
|
||||
{37762, 22, 40, 26},
|
||||
{37800, 20, 21, 15},
|
||||
{38000, 24, 27, 16},
|
||||
{38250, 24, 34, 20},
|
||||
{39000, 24, 26, 15},
|
||||
{40000, 24, 32, 18},
|
||||
{40500, 20, 21, 14},
|
||||
{40541, 22, 147, 89},
|
||||
{40750, 18, 19, 14},
|
||||
{41000, 16, 17, 14},
|
||||
{41500, 22, 44, 26},
|
||||
{41540, 22, 44, 26},
|
||||
{42000, 18, 21, 15},
|
||||
{42500, 22, 45, 26},
|
||||
{43000, 20, 43, 27},
|
||||
{43163, 20, 24, 15},
|
||||
{44000, 18, 22, 15},
|
||||
{44900, 20, 108, 65},
|
||||
{45000, 20, 25, 15},
|
||||
{45250, 20, 52, 31},
|
||||
{46000, 18, 23, 15},
|
||||
{46750, 20, 45, 26},
|
||||
{47000, 20, 40, 23},
|
||||
{48000, 18, 24, 15},
|
||||
{49000, 18, 49, 30},
|
||||
{49500, 16, 22, 15},
|
||||
{50000, 18, 25, 15},
|
||||
{50500, 18, 32, 19},
|
||||
{51000, 18, 34, 20},
|
||||
{52000, 18, 26, 15},
|
||||
{52406, 14, 34, 25},
|
||||
{53000, 16, 22, 14},
|
||||
{54000, 16, 24, 15},
|
||||
{54054, 16, 173, 108},
|
||||
{54500, 14, 24, 17},
|
||||
{55000, 12, 22, 18},
|
||||
{56000, 14, 45, 31},
|
||||
{56250, 16, 25, 15},
|
||||
{56750, 14, 25, 17},
|
||||
{57000, 16, 27, 16},
|
||||
{58000, 16, 43, 25},
|
||||
{58250, 16, 38, 22},
|
||||
{58750, 16, 40, 23},
|
||||
{59000, 14, 26, 17},
|
||||
{59341, 14, 40, 26},
|
||||
{59400, 16, 44, 25},
|
||||
{60000, 16, 32, 18},
|
||||
{60500, 12, 39, 29},
|
||||
{61000, 14, 49, 31},
|
||||
{62000, 14, 37, 23},
|
||||
{62250, 14, 42, 26},
|
||||
{63000, 12, 21, 15},
|
||||
{63500, 14, 28, 17},
|
||||
{64000, 12, 27, 19},
|
||||
{65000, 14, 32, 19},
|
||||
{65250, 12, 29, 20},
|
||||
{65500, 12, 32, 22},
|
||||
{66000, 12, 22, 15},
|
||||
{66667, 14, 38, 22},
|
||||
{66750, 10, 21, 17},
|
||||
{67000, 14, 33, 19},
|
||||
{67750, 14, 58, 33},
|
||||
{68000, 14, 30, 17},
|
||||
{68179, 14, 46, 26},
|
||||
{68250, 14, 46, 26},
|
||||
{69000, 12, 23, 15},
|
||||
{70000, 12, 28, 18},
|
||||
{71000, 12, 30, 19},
|
||||
{72000, 12, 24, 15},
|
||||
{73000, 10, 23, 17},
|
||||
{74000, 12, 23, 14},
|
||||
{74176, 8, 100, 91},
|
||||
{74250, 10, 22, 16},
|
||||
{74481, 12, 43, 26},
|
||||
{74500, 10, 29, 21},
|
||||
{75000, 12, 25, 15},
|
||||
{75250, 10, 39, 28},
|
||||
{76000, 12, 27, 16},
|
||||
{77000, 12, 53, 31},
|
||||
{78000, 12, 26, 15},
|
||||
{78750, 12, 28, 16},
|
||||
{79000, 10, 38, 26},
|
||||
{79500, 10, 28, 19},
|
||||
{80000, 12, 32, 18},
|
||||
{81000, 10, 21, 14},
|
||||
{81081, 6, 100, 111},
|
||||
{81624, 8, 29, 24},
|
||||
{82000, 8, 17, 14},
|
||||
{83000, 10, 40, 26},
|
||||
{83950, 10, 28, 18},
|
||||
{84000, 10, 28, 18},
|
||||
{84750, 6, 16, 17},
|
||||
{85000, 6, 17, 18},
|
||||
{85250, 10, 30, 19},
|
||||
{85750, 10, 27, 17},
|
||||
{86000, 10, 43, 27},
|
||||
{87000, 10, 29, 18},
|
||||
{88000, 10, 44, 27},
|
||||
{88500, 10, 41, 25},
|
||||
{89000, 10, 28, 17},
|
||||
{89012, 6, 90, 91},
|
||||
{89100, 10, 33, 20},
|
||||
{90000, 10, 25, 15},
|
||||
{91000, 10, 32, 19},
|
||||
{92000, 10, 46, 27},
|
||||
{93000, 10, 31, 18},
|
||||
{94000, 10, 40, 23},
|
||||
{94500, 10, 28, 16},
|
||||
{95000, 10, 44, 25},
|
||||
{95654, 10, 39, 22},
|
||||
{95750, 10, 39, 22},
|
||||
{96000, 10, 32, 18},
|
||||
{97000, 8, 23, 16},
|
||||
{97750, 8, 42, 29},
|
||||
{98000, 8, 45, 31},
|
||||
{99000, 8, 22, 15},
|
||||
{99750, 8, 34, 23},
|
||||
{100000, 6, 20, 18},
|
||||
{100500, 6, 19, 17},
|
||||
{101000, 6, 37, 33},
|
||||
{101250, 8, 21, 14},
|
||||
{102000, 6, 17, 15},
|
||||
{102250, 6, 25, 22},
|
||||
{103000, 8, 29, 19},
|
||||
{104000, 8, 37, 24},
|
||||
{105000, 8, 28, 18},
|
||||
{106000, 8, 22, 14},
|
||||
{107000, 8, 46, 29},
|
||||
{107214, 8, 27, 17},
|
||||
{108000, 8, 24, 15},
|
||||
{108108, 8, 173, 108},
|
||||
{109000, 6, 23, 19},
|
||||
{109000, 6, 23, 19},
|
||||
{110000, 6, 22, 18},
|
||||
{110013, 6, 22, 18},
|
||||
{110250, 8, 49, 30},
|
||||
{110500, 8, 36, 22},
|
||||
{111000, 8, 23, 14},
|
||||
{111264, 8, 150, 91},
|
||||
{111375, 8, 33, 20},
|
||||
{112000, 8, 63, 38},
|
||||
{112500, 8, 25, 15},
|
||||
{113100, 8, 57, 34},
|
||||
{113309, 8, 42, 25},
|
||||
{114000, 8, 27, 16},
|
||||
{115000, 6, 23, 18},
|
||||
{116000, 8, 43, 25},
|
||||
{117000, 8, 26, 15},
|
||||
{117500, 8, 40, 23},
|
||||
{118000, 6, 38, 29},
|
||||
{119000, 8, 30, 17},
|
||||
{119500, 8, 46, 26},
|
||||
{119651, 8, 39, 22},
|
||||
{120000, 8, 32, 18},
|
||||
{121000, 6, 39, 29},
|
||||
{121250, 6, 31, 23},
|
||||
{121750, 6, 23, 17},
|
||||
{122000, 6, 42, 31},
|
||||
{122614, 6, 30, 22},
|
||||
{123000, 6, 41, 30},
|
||||
{123379, 6, 37, 27},
|
||||
{124000, 6, 51, 37},
|
||||
{125000, 6, 25, 18},
|
||||
{125250, 4, 13, 14},
|
||||
{125750, 4, 27, 29},
|
||||
{126000, 6, 21, 15},
|
||||
{127000, 6, 24, 17},
|
||||
{127250, 6, 41, 29},
|
||||
{128000, 6, 27, 19},
|
||||
{129000, 6, 43, 30},
|
||||
{129859, 4, 25, 26},
|
||||
{130000, 6, 26, 18},
|
||||
{130250, 6, 42, 29},
|
||||
{131000, 6, 32, 22},
|
||||
{131500, 6, 38, 26},
|
||||
{131850, 6, 41, 28},
|
||||
{132000, 6, 22, 15},
|
||||
{132750, 6, 28, 19},
|
||||
{133000, 6, 34, 23},
|
||||
{133330, 6, 37, 25},
|
||||
{134000, 6, 61, 41},
|
||||
{135000, 6, 21, 14},
|
||||
{135250, 6, 167, 111},
|
||||
{136000, 6, 62, 41},
|
||||
{137000, 6, 35, 23},
|
||||
{138000, 6, 23, 15},
|
||||
{138500, 6, 40, 26},
|
||||
{138750, 6, 37, 24},
|
||||
{139000, 6, 34, 22},
|
||||
{139050, 6, 34, 22},
|
||||
{139054, 6, 34, 22},
|
||||
{140000, 6, 28, 18},
|
||||
{141000, 6, 36, 23},
|
||||
{141500, 6, 22, 14},
|
||||
{142000, 6, 30, 19},
|
||||
{143000, 6, 27, 17},
|
||||
{143472, 4, 17, 16},
|
||||
{144000, 6, 24, 15},
|
||||
{145000, 6, 29, 18},
|
||||
{146000, 6, 47, 29},
|
||||
{146250, 6, 26, 16},
|
||||
{147000, 6, 49, 30},
|
||||
{147891, 6, 23, 14},
|
||||
{148000, 6, 23, 14},
|
||||
{148250, 6, 28, 17},
|
||||
{148352, 4, 100, 91},
|
||||
{148500, 6, 33, 20},
|
||||
{149000, 6, 48, 29},
|
||||
{150000, 6, 25, 15},
|
||||
{151000, 4, 19, 17},
|
||||
{152000, 6, 27, 16},
|
||||
{152280, 6, 44, 26},
|
||||
{153000, 6, 34, 20},
|
||||
{154000, 6, 53, 31},
|
||||
{155000, 6, 31, 18},
|
||||
{155250, 6, 50, 29},
|
||||
{155750, 6, 45, 26},
|
||||
{156000, 6, 26, 15},
|
||||
{157000, 6, 61, 35},
|
||||
{157500, 6, 28, 16},
|
||||
{158000, 6, 65, 37},
|
||||
{158250, 6, 44, 25},
|
||||
{159000, 6, 53, 30},
|
||||
{159500, 6, 39, 22},
|
||||
{160000, 6, 32, 18},
|
||||
{161000, 4, 31, 26},
|
||||
{162000, 4, 18, 15},
|
||||
{162162, 4, 131, 109},
|
||||
{162500, 4, 53, 44},
|
||||
{163000, 4, 29, 24},
|
||||
{164000, 4, 17, 14},
|
||||
{165000, 4, 22, 18},
|
||||
{166000, 4, 32, 26},
|
||||
{167000, 4, 26, 21},
|
||||
{168000, 4, 46, 37},
|
||||
{169000, 4, 104, 83},
|
||||
{169128, 4, 64, 51},
|
||||
{169500, 4, 39, 31},
|
||||
{170000, 4, 34, 27},
|
||||
{171000, 4, 19, 15},
|
||||
{172000, 4, 51, 40},
|
||||
{172750, 4, 32, 25},
|
||||
{172800, 4, 32, 25},
|
||||
{173000, 4, 41, 32},
|
||||
{174000, 4, 49, 38},
|
||||
{174787, 4, 22, 17},
|
||||
{175000, 4, 35, 27},
|
||||
{176000, 4, 30, 23},
|
||||
{177000, 4, 38, 29},
|
||||
{178000, 4, 29, 22},
|
||||
{178500, 4, 37, 28},
|
||||
{179000, 4, 53, 40},
|
||||
{179500, 4, 73, 55},
|
||||
{180000, 4, 20, 15},
|
||||
{181000, 4, 55, 41},
|
||||
{182000, 4, 31, 23},
|
||||
{183000, 4, 42, 31},
|
||||
{184000, 4, 30, 22},
|
||||
{184750, 4, 26, 19},
|
||||
{185000, 4, 37, 27},
|
||||
{186000, 4, 51, 37},
|
||||
{187000, 4, 36, 26},
|
||||
{188000, 4, 32, 23},
|
||||
{189000, 4, 21, 15},
|
||||
{190000, 4, 38, 27},
|
||||
{190960, 4, 41, 29},
|
||||
{191000, 4, 41, 29},
|
||||
{192000, 4, 27, 19},
|
||||
{192250, 4, 37, 26},
|
||||
{193000, 4, 20, 14},
|
||||
{193250, 4, 53, 37},
|
||||
{194000, 4, 23, 16},
|
||||
{194208, 4, 23, 16},
|
||||
{195000, 4, 26, 18},
|
||||
{196000, 4, 45, 31},
|
||||
{197000, 4, 35, 24},
|
||||
{197750, 4, 41, 28},
|
||||
{198000, 4, 22, 15},
|
||||
{198500, 4, 25, 17},
|
||||
{199000, 4, 28, 19},
|
||||
{200000, 4, 37, 25},
|
||||
{201000, 4, 61, 41},
|
||||
{202000, 4, 112, 75},
|
||||
{202500, 4, 21, 14},
|
||||
{203000, 4, 146, 97},
|
||||
{204000, 4, 62, 41},
|
||||
{204750, 4, 44, 29},
|
||||
{205000, 4, 38, 25},
|
||||
{206000, 4, 29, 19},
|
||||
{207000, 4, 23, 15},
|
||||
{207500, 4, 40, 26},
|
||||
{208000, 4, 37, 24},
|
||||
{208900, 4, 48, 31},
|
||||
{209000, 4, 48, 31},
|
||||
{209250, 4, 31, 20},
|
||||
{210000, 4, 28, 18},
|
||||
{211000, 4, 25, 16},
|
||||
{212000, 4, 22, 14},
|
||||
{213000, 4, 30, 19},
|
||||
{213750, 4, 38, 24},
|
||||
{214000, 4, 46, 29},
|
||||
{214750, 4, 35, 22},
|
||||
{215000, 4, 43, 27},
|
||||
{216000, 4, 24, 15},
|
||||
{217000, 4, 37, 23},
|
||||
{218000, 4, 42, 26},
|
||||
{218250, 4, 42, 26},
|
||||
{218750, 4, 34, 21},
|
||||
{219000, 4, 47, 29},
|
||||
{219000, 4, 47, 29},
|
||||
{220000, 4, 44, 27},
|
||||
{220640, 4, 49, 30},
|
||||
{220750, 4, 36, 22},
|
||||
{221000, 4, 36, 22},
|
||||
{222000, 4, 23, 14},
|
||||
{222525, 4, 28, 17},
|
||||
{222750, 4, 33, 20},
|
||||
{227000, 4, 37, 22},
|
||||
{230250, 4, 29, 17},
|
||||
{233500, 4, 38, 22},
|
||||
{235000, 4, 40, 23},
|
||||
{238000, 4, 30, 17},
|
||||
{241500, 2, 17, 19},
|
||||
{245250, 2, 20, 22},
|
||||
{247750, 2, 22, 24},
|
||||
{253250, 2, 15, 16},
|
||||
{256250, 2, 18, 19},
|
||||
{262500, 2, 31, 32},
|
||||
{267250, 2, 66, 67},
|
||||
{268500, 2, 94, 95},
|
||||
{270000, 2, 14, 14},
|
||||
{272500, 2, 77, 76},
|
||||
{273750, 2, 57, 56},
|
||||
{280750, 2, 24, 23},
|
||||
{281250, 2, 23, 22},
|
||||
{286000, 2, 17, 16},
|
||||
{291750, 2, 26, 24},
|
||||
{296703, 2, 56, 51},
|
||||
{297000, 2, 22, 20},
|
||||
{298000, 2, 21, 19},
|
||||
};
|
||||
|
||||
void intel_ddi_mode_set(struct drm_encoder *encoder,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
{
|
||||
struct drm_device *dev = encoder->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct drm_crtc *crtc = encoder->crtc;
|
||||
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
||||
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
|
||||
int port = intel_hdmi->ddi_port;
|
||||
int pipe = intel_crtc->pipe;
|
||||
int p, n2, r2, valid=0;
|
||||
u32 temp, i;
|
||||
|
||||
/* On Haswell, we need to enable the clocks and prepare DDI function to
|
||||
* work in HDMI mode for this pipe.
|
||||
*/
|
||||
DRM_DEBUG_KMS("Preparing HDMI DDI mode for Haswell on port %c, pipe %c\n", port_name(port), pipe_name(pipe));
|
||||
|
||||
for (i=0; i < ARRAY_SIZE(wrpll_tmds_clock_table); i++) {
|
||||
if (crtc->mode.clock == wrpll_tmds_clock_table[i].clock) {
|
||||
p = wrpll_tmds_clock_table[i].p;
|
||||
n2 = wrpll_tmds_clock_table[i].n2;
|
||||
r2 = wrpll_tmds_clock_table[i].r2;
|
||||
|
||||
DRM_DEBUG_KMS("WR PLL clock: found settings for %dKHz refresh rate: p=%d, n2=%d, r2=%d\n",
|
||||
crtc->mode.clock,
|
||||
p, n2, r2);
|
||||
|
||||
valid = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!valid) {
|
||||
DRM_ERROR("Unable to find WR PLL clock settings for %dKHz refresh rate\n",
|
||||
crtc->mode.clock);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Enable LCPLL if disabled */
|
||||
temp = I915_READ(LCPLL_CTL);
|
||||
if (temp & LCPLL_PLL_DISABLE)
|
||||
I915_WRITE(LCPLL_CTL,
|
||||
temp & ~LCPLL_PLL_DISABLE);
|
||||
|
||||
/* Configure WR PLL 1, program the correct divider values for
|
||||
* the desired frequency and wait for warmup */
|
||||
I915_WRITE(WRPLL_CTL1,
|
||||
WRPLL_PLL_ENABLE |
|
||||
WRPLL_PLL_SELECT_LCPLL_2700 |
|
||||
WRPLL_DIVIDER_REFERENCE(r2) |
|
||||
WRPLL_DIVIDER_FEEDBACK(n2) |
|
||||
WRPLL_DIVIDER_POST(p));
|
||||
|
||||
udelay(20);
|
||||
|
||||
/* Use WRPLL1 clock to drive the output to the port, and tell the pipe to use
|
||||
* this port for connection.
|
||||
*/
|
||||
I915_WRITE(PORT_CLK_SEL(port),
|
||||
PORT_CLK_SEL_WRPLL1);
|
||||
I915_WRITE(PIPE_CLK_SEL(pipe),
|
||||
PIPE_CLK_SEL_PORT(port));
|
||||
|
||||
udelay(20);
|
||||
|
||||
if (intel_hdmi->has_audio) {
|
||||
/* Proper support for digital audio needs a new logic and a new set
|
||||
* of registers, so we leave it for future patch bombing.
|
||||
*/
|
||||
DRM_DEBUG_DRIVER("HDMI audio on pipe %c not yet supported on DDI\n",
|
||||
pipe_name(intel_crtc->pipe));
|
||||
}
|
||||
|
||||
/* Enable PIPE_DDI_FUNC_CTL for the pipe to work in HDMI mode */
|
||||
temp = I915_READ(DDI_FUNC_CTL(pipe));
|
||||
temp &= ~PIPE_DDI_PORT_MASK;
|
||||
temp &= ~PIPE_DDI_BPC_12;
|
||||
temp |= PIPE_DDI_SELECT_PORT(port) |
|
||||
PIPE_DDI_MODE_SELECT_HDMI |
|
||||
((intel_crtc->bpp > 24) ?
|
||||
PIPE_DDI_BPC_12 :
|
||||
PIPE_DDI_BPC_8) |
|
||||
PIPE_DDI_FUNC_ENABLE;
|
||||
|
||||
I915_WRITE(DDI_FUNC_CTL(pipe), temp);
|
||||
|
||||
intel_hdmi_set_avi_infoframe(encoder, adjusted_mode);
|
||||
intel_hdmi_set_spd_infoframe(encoder);
|
||||
}
|
||||
|
||||
void intel_ddi_dpms(struct drm_encoder *encoder, int mode)
|
||||
{
|
||||
struct drm_device *dev = encoder->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
|
||||
int port = intel_hdmi->ddi_port;
|
||||
u32 temp;
|
||||
|
||||
temp = I915_READ(DDI_BUF_CTL(port));
|
||||
|
||||
if (mode != DRM_MODE_DPMS_ON) {
|
||||
temp &= ~DDI_BUF_CTL_ENABLE;
|
||||
} else {
|
||||
temp |= DDI_BUF_CTL_ENABLE;
|
||||
}
|
||||
|
||||
/* Enable DDI_BUF_CTL. In HDMI/DVI mode, the port width,
|
||||
* and swing/emphasis values are ignored so nothing special needs
|
||||
* to be done besides enabling the port.
|
||||
*/
|
||||
I915_WRITE(DDI_BUF_CTL(port),
|
||||
temp);
|
||||
}
|
|
@ -784,6 +784,17 @@ intel_find_pll_g4x_dp(const intel_limit_t *limit, struct drm_crtc *crtc,
|
|||
return true;
|
||||
}
|
||||
|
||||
static void ironlake_wait_for_vblank(struct drm_device *dev, int pipe)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
u32 frame, frame_reg = PIPEFRAME(pipe);
|
||||
|
||||
frame = I915_READ(frame_reg);
|
||||
|
||||
if (wait_for(I915_READ_NOTRACE(frame_reg) != frame, 50))
|
||||
DRM_DEBUG_KMS("vblank wait timed out\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* intel_wait_for_vblank - wait for vblank on a given pipe
|
||||
* @dev: drm device
|
||||
|
@ -797,6 +808,11 @@ void intel_wait_for_vblank(struct drm_device *dev, int pipe)
|
|||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
int pipestat_reg = PIPESTAT(pipe);
|
||||
|
||||
if (INTEL_INFO(dev)->gen >= 5) {
|
||||
ironlake_wait_for_vblank(dev, pipe);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Clear existing vblank status. Note this will clear any other
|
||||
* sticky status fields as well.
|
||||
*
|
||||
|
@ -849,15 +865,20 @@ void intel_wait_for_pipe_off(struct drm_device *dev, int pipe)
|
|||
100))
|
||||
DRM_DEBUG_KMS("pipe_off wait timed out\n");
|
||||
} else {
|
||||
u32 last_line;
|
||||
u32 last_line, line_mask;
|
||||
int reg = PIPEDSL(pipe);
|
||||
unsigned long timeout = jiffies + msecs_to_jiffies(100);
|
||||
|
||||
if (IS_GEN2(dev))
|
||||
line_mask = DSL_LINEMASK_GEN2;
|
||||
else
|
||||
line_mask = DSL_LINEMASK_GEN3;
|
||||
|
||||
/* Wait for the display line to settle */
|
||||
do {
|
||||
last_line = I915_READ(reg) & DSL_LINEMASK;
|
||||
last_line = I915_READ(reg) & line_mask;
|
||||
mdelay(5);
|
||||
} while (((I915_READ(reg) & DSL_LINEMASK) != last_line) &&
|
||||
} while (((I915_READ(reg) & line_mask) != last_line) &&
|
||||
time_after(timeout, jiffies));
|
||||
if (time_after(jiffies, timeout))
|
||||
DRM_DEBUG_KMS("pipe_off wait timed out\n");
|
||||
|
@ -895,6 +916,11 @@ static void assert_pch_pll(struct drm_i915_private *dev_priv,
|
|||
u32 val;
|
||||
bool cur_state;
|
||||
|
||||
if (HAS_PCH_LPT(dev_priv->dev)) {
|
||||
DRM_DEBUG_DRIVER("LPT detected: skipping PCH PLL test\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!intel_crtc->pch_pll) {
|
||||
WARN(1, "asserting PCH PLL enabled with no PLL\n");
|
||||
return;
|
||||
|
@ -927,9 +953,16 @@ static void assert_fdi_tx(struct drm_i915_private *dev_priv,
|
|||
u32 val;
|
||||
bool cur_state;
|
||||
|
||||
reg = FDI_TX_CTL(pipe);
|
||||
val = I915_READ(reg);
|
||||
cur_state = !!(val & FDI_TX_ENABLE);
|
||||
if (IS_HASWELL(dev_priv->dev)) {
|
||||
/* On Haswell, DDI is used instead of FDI_TX_CTL */
|
||||
reg = DDI_FUNC_CTL(pipe);
|
||||
val = I915_READ(reg);
|
||||
cur_state = !!(val & PIPE_DDI_FUNC_ENABLE);
|
||||
} else {
|
||||
reg = FDI_TX_CTL(pipe);
|
||||
val = I915_READ(reg);
|
||||
cur_state = !!(val & FDI_TX_ENABLE);
|
||||
}
|
||||
WARN(cur_state != state,
|
||||
"FDI TX state assertion failure (expected %s, current %s)\n",
|
||||
state_string(state), state_string(cur_state));
|
||||
|
@ -944,9 +977,14 @@ static void assert_fdi_rx(struct drm_i915_private *dev_priv,
|
|||
u32 val;
|
||||
bool cur_state;
|
||||
|
||||
reg = FDI_RX_CTL(pipe);
|
||||
val = I915_READ(reg);
|
||||
cur_state = !!(val & FDI_RX_ENABLE);
|
||||
if (IS_HASWELL(dev_priv->dev) && pipe > 0) {
|
||||
DRM_ERROR("Attempting to enable FDI_RX on Haswell pipe > 0\n");
|
||||
return;
|
||||
} else {
|
||||
reg = FDI_RX_CTL(pipe);
|
||||
val = I915_READ(reg);
|
||||
cur_state = !!(val & FDI_RX_ENABLE);
|
||||
}
|
||||
WARN(cur_state != state,
|
||||
"FDI RX state assertion failure (expected %s, current %s)\n",
|
||||
state_string(state), state_string(cur_state));
|
||||
|
@ -964,6 +1002,10 @@ static void assert_fdi_tx_pll_enabled(struct drm_i915_private *dev_priv,
|
|||
if (dev_priv->info->gen == 5)
|
||||
return;
|
||||
|
||||
/* On Haswell, DDI ports are responsible for the FDI PLL setup */
|
||||
if (IS_HASWELL(dev_priv->dev))
|
||||
return;
|
||||
|
||||
reg = FDI_TX_CTL(pipe);
|
||||
val = I915_READ(reg);
|
||||
WARN(!(val & FDI_TX_PLL_ENABLE), "FDI TX PLL assertion failure, should be active but is disabled\n");
|
||||
|
@ -975,6 +1017,10 @@ static void assert_fdi_rx_pll_enabled(struct drm_i915_private *dev_priv,
|
|||
int reg;
|
||||
u32 val;
|
||||
|
||||
if (IS_HASWELL(dev_priv->dev) && pipe > 0) {
|
||||
DRM_ERROR("Attempting to enable FDI on Haswell with pipe > 0\n");
|
||||
return;
|
||||
}
|
||||
reg = FDI_RX_CTL(pipe);
|
||||
val = I915_READ(reg);
|
||||
WARN(!(val & FDI_RX_PLL_ENABLE), "FDI RX PLL assertion failure, should be active but is disabled\n");
|
||||
|
@ -1080,6 +1126,11 @@ static void assert_pch_refclk_enabled(struct drm_i915_private *dev_priv)
|
|||
u32 val;
|
||||
bool enabled;
|
||||
|
||||
if (HAS_PCH_LPT(dev_priv->dev)) {
|
||||
DRM_DEBUG_DRIVER("LPT does not has PCH refclk, skipping check\n");
|
||||
return;
|
||||
}
|
||||
|
||||
val = I915_READ(PCH_DREF_CONTROL);
|
||||
enabled = !!(val & (DREF_SSC_SOURCE_MASK | DREF_NONSPREAD_SOURCE_MASK |
|
||||
DREF_SUPERSPREAD_SOURCE_MASK));
|
||||
|
@ -1278,6 +1329,69 @@ static void intel_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe)
|
|||
POSTING_READ(reg);
|
||||
}
|
||||
|
||||
/* SBI access */
|
||||
static void
|
||||
intel_sbi_write(struct drm_i915_private *dev_priv, u16 reg, u32 value)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&dev_priv->dpio_lock, flags);
|
||||
if (wait_for((I915_READ(SBI_CTL_STAT) & SBI_READY) == 0,
|
||||
100)) {
|
||||
DRM_ERROR("timeout waiting for SBI to become ready\n");
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
I915_WRITE(SBI_ADDR,
|
||||
(reg << 16));
|
||||
I915_WRITE(SBI_DATA,
|
||||
value);
|
||||
I915_WRITE(SBI_CTL_STAT,
|
||||
SBI_BUSY |
|
||||
SBI_CTL_OP_CRWR);
|
||||
|
||||
if (wait_for((I915_READ(SBI_CTL_STAT) & (SBI_READY | SBI_RESPONSE_SUCCESS)) == 0,
|
||||
100)) {
|
||||
DRM_ERROR("timeout waiting for SBI to complete write transaction\n");
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
out_unlock:
|
||||
spin_unlock_irqrestore(&dev_priv->dpio_lock, flags);
|
||||
}
|
||||
|
||||
static u32
|
||||
intel_sbi_read(struct drm_i915_private *dev_priv, u16 reg)
|
||||
{
|
||||
unsigned long flags;
|
||||
u32 value;
|
||||
|
||||
spin_lock_irqsave(&dev_priv->dpio_lock, flags);
|
||||
if (wait_for((I915_READ(SBI_CTL_STAT) & SBI_READY) == 0,
|
||||
100)) {
|
||||
DRM_ERROR("timeout waiting for SBI to become ready\n");
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
I915_WRITE(SBI_ADDR,
|
||||
(reg << 16));
|
||||
I915_WRITE(SBI_CTL_STAT,
|
||||
SBI_BUSY |
|
||||
SBI_CTL_OP_CRRD);
|
||||
|
||||
if (wait_for((I915_READ(SBI_CTL_STAT) & (SBI_READY | SBI_RESPONSE_SUCCESS)) == 0,
|
||||
100)) {
|
||||
DRM_ERROR("timeout waiting for SBI to complete read transaction\n");
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
value = I915_READ(SBI_DATA);
|
||||
|
||||
out_unlock:
|
||||
spin_unlock_irqrestore(&dev_priv->dpio_lock, flags);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* intel_enable_pch_pll - enable PCH PLL
|
||||
* @dev_priv: i915 private structure
|
||||
|
@ -1289,14 +1403,18 @@ static void intel_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe)
|
|||
static void intel_enable_pch_pll(struct intel_crtc *intel_crtc)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = intel_crtc->base.dev->dev_private;
|
||||
struct intel_pch_pll *pll = intel_crtc->pch_pll;
|
||||
struct intel_pch_pll *pll;
|
||||
int reg;
|
||||
u32 val;
|
||||
|
||||
/* PCH only available on ILK+ */
|
||||
/* PCH PLLs only available on ILK, SNB and IVB */
|
||||
BUG_ON(dev_priv->info->gen < 5);
|
||||
BUG_ON(pll == NULL);
|
||||
BUG_ON(pll->refcount == 0);
|
||||
pll = intel_crtc->pch_pll;
|
||||
if (pll == NULL)
|
||||
return;
|
||||
|
||||
if (WARN_ON(pll->refcount == 0))
|
||||
return;
|
||||
|
||||
DRM_DEBUG_KMS("enable PCH PLL %x (active %d, on? %d)for crtc %d\n",
|
||||
pll->pll_reg, pll->active, pll->on,
|
||||
|
@ -1334,13 +1452,18 @@ static void intel_disable_pch_pll(struct intel_crtc *intel_crtc)
|
|||
if (pll == NULL)
|
||||
return;
|
||||
|
||||
BUG_ON(pll->refcount == 0);
|
||||
if (WARN_ON(pll->refcount == 0))
|
||||
return;
|
||||
|
||||
DRM_DEBUG_KMS("disable PCH PLL %x (active %d, on? %d) for crtc %d\n",
|
||||
pll->pll_reg, pll->active, pll->on,
|
||||
intel_crtc->base.base.id);
|
||||
|
||||
BUG_ON(pll->active == 0);
|
||||
if (WARN_ON(pll->active == 0)) {
|
||||
assert_pch_pll_disabled(dev_priv, intel_crtc);
|
||||
return;
|
||||
}
|
||||
|
||||
if (--pll->active) {
|
||||
assert_pch_pll_enabled(dev_priv, intel_crtc);
|
||||
return;
|
||||
|
@ -1378,6 +1501,10 @@ static void intel_enable_transcoder(struct drm_i915_private *dev_priv,
|
|||
assert_fdi_tx_enabled(dev_priv, pipe);
|
||||
assert_fdi_rx_enabled(dev_priv, pipe);
|
||||
|
||||
if (IS_HASWELL(dev_priv->dev) && pipe > 0) {
|
||||
DRM_ERROR("Attempting to enable transcoder on Haswell with pipe > 0\n");
|
||||
return;
|
||||
}
|
||||
reg = TRANSCONF(pipe);
|
||||
val = I915_READ(reg);
|
||||
pipeconf_val = I915_READ(PIPECONF(pipe));
|
||||
|
@ -1896,16 +2023,10 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
|
|||
return 0;
|
||||
}
|
||||
|
||||
switch (intel_crtc->plane) {
|
||||
case 0:
|
||||
case 1:
|
||||
break;
|
||||
case 2:
|
||||
if (IS_IVYBRIDGE(dev))
|
||||
break;
|
||||
/* fall through otherwise */
|
||||
default:
|
||||
DRM_ERROR("no plane for crtc\n");
|
||||
if(intel_crtc->plane > dev_priv->num_pipe) {
|
||||
DRM_ERROR("no plane for crtc: plane %d, num_pipes %d\n",
|
||||
intel_crtc->plane,
|
||||
dev_priv->num_pipe);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -2426,14 +2547,18 @@ static void ironlake_fdi_pll_enable(struct drm_crtc *crtc)
|
|||
POSTING_READ(reg);
|
||||
udelay(200);
|
||||
|
||||
/* Enable CPU FDI TX PLL, always on for Ironlake */
|
||||
reg = FDI_TX_CTL(pipe);
|
||||
temp = I915_READ(reg);
|
||||
if ((temp & FDI_TX_PLL_ENABLE) == 0) {
|
||||
I915_WRITE(reg, temp | FDI_TX_PLL_ENABLE);
|
||||
/* On Haswell, the PLL configuration for ports and pipes is handled
|
||||
* separately, as part of DDI setup */
|
||||
if (!IS_HASWELL(dev)) {
|
||||
/* Enable CPU FDI TX PLL, always on for Ironlake */
|
||||
reg = FDI_TX_CTL(pipe);
|
||||
temp = I915_READ(reg);
|
||||
if ((temp & FDI_TX_PLL_ENABLE) == 0) {
|
||||
I915_WRITE(reg, temp | FDI_TX_PLL_ENABLE);
|
||||
|
||||
POSTING_READ(reg);
|
||||
udelay(100);
|
||||
POSTING_READ(reg);
|
||||
udelay(100);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2532,6 +2657,22 @@ static bool intel_crtc_driving_pch(struct drm_crtc *crtc)
|
|||
if (encoder->base.crtc != crtc)
|
||||
continue;
|
||||
|
||||
/* On Haswell, LPT PCH handles the VGA connection via FDI, and Haswell
|
||||
* CPU handles all others */
|
||||
if (IS_HASWELL(dev)) {
|
||||
/* It is still unclear how this will work on PPT, so throw up a warning */
|
||||
WARN_ON(!HAS_PCH_LPT(dev));
|
||||
|
||||
if (encoder->type == DRM_MODE_ENCODER_DAC) {
|
||||
DRM_DEBUG_KMS("Haswell detected DAC encoder, assuming is PCH\n");
|
||||
return true;
|
||||
} else {
|
||||
DRM_DEBUG_KMS("Haswell detected encoder %d, assuming is CPU\n",
|
||||
encoder->type);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
switch (encoder->type) {
|
||||
case INTEL_OUTPUT_EDP:
|
||||
if (!intel_encoder_is_pch_edp(&encoder->base))
|
||||
|
@ -2543,6 +2684,97 @@ static bool intel_crtc_driving_pch(struct drm_crtc *crtc)
|
|||
return true;
|
||||
}
|
||||
|
||||
/* Program iCLKIP clock to the desired frequency */
|
||||
static void lpt_program_iclkip(struct drm_crtc *crtc)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
u32 divsel, phaseinc, auxdiv, phasedir = 0;
|
||||
u32 temp;
|
||||
|
||||
/* It is necessary to ungate the pixclk gate prior to programming
|
||||
* the divisors, and gate it back when it is done.
|
||||
*/
|
||||
I915_WRITE(PIXCLK_GATE, PIXCLK_GATE_GATE);
|
||||
|
||||
/* Disable SSCCTL */
|
||||
intel_sbi_write(dev_priv, SBI_SSCCTL6,
|
||||
intel_sbi_read(dev_priv, SBI_SSCCTL6) |
|
||||
SBI_SSCCTL_DISABLE);
|
||||
|
||||
/* 20MHz is a corner case which is out of range for the 7-bit divisor */
|
||||
if (crtc->mode.clock == 20000) {
|
||||
auxdiv = 1;
|
||||
divsel = 0x41;
|
||||
phaseinc = 0x20;
|
||||
} else {
|
||||
/* The iCLK virtual clock root frequency is in MHz,
|
||||
* but the crtc->mode.clock in in KHz. To get the divisors,
|
||||
* it is necessary to divide one by another, so we
|
||||
* convert the virtual clock precision to KHz here for higher
|
||||
* precision.
|
||||
*/
|
||||
u32 iclk_virtual_root_freq = 172800 * 1000;
|
||||
u32 iclk_pi_range = 64;
|
||||
u32 desired_divisor, msb_divisor_value, pi_value;
|
||||
|
||||
desired_divisor = (iclk_virtual_root_freq / crtc->mode.clock);
|
||||
msb_divisor_value = desired_divisor / iclk_pi_range;
|
||||
pi_value = desired_divisor % iclk_pi_range;
|
||||
|
||||
auxdiv = 0;
|
||||
divsel = msb_divisor_value - 2;
|
||||
phaseinc = pi_value;
|
||||
}
|
||||
|
||||
/* This should not happen with any sane values */
|
||||
WARN_ON(SBI_SSCDIVINTPHASE_DIVSEL(divsel) &
|
||||
~SBI_SSCDIVINTPHASE_DIVSEL_MASK);
|
||||
WARN_ON(SBI_SSCDIVINTPHASE_DIR(phasedir) &
|
||||
~SBI_SSCDIVINTPHASE_INCVAL_MASK);
|
||||
|
||||
DRM_DEBUG_KMS("iCLKIP clock: found settings for %dKHz refresh rate: auxdiv=%x, divsel=%x, phasedir=%x, phaseinc=%x\n",
|
||||
crtc->mode.clock,
|
||||
auxdiv,
|
||||
divsel,
|
||||
phasedir,
|
||||
phaseinc);
|
||||
|
||||
/* Program SSCDIVINTPHASE6 */
|
||||
temp = intel_sbi_read(dev_priv, SBI_SSCDIVINTPHASE6);
|
||||
temp &= ~SBI_SSCDIVINTPHASE_DIVSEL_MASK;
|
||||
temp |= SBI_SSCDIVINTPHASE_DIVSEL(divsel);
|
||||
temp &= ~SBI_SSCDIVINTPHASE_INCVAL_MASK;
|
||||
temp |= SBI_SSCDIVINTPHASE_INCVAL(phaseinc);
|
||||
temp |= SBI_SSCDIVINTPHASE_DIR(phasedir);
|
||||
temp |= SBI_SSCDIVINTPHASE_PROPAGATE;
|
||||
|
||||
intel_sbi_write(dev_priv,
|
||||
SBI_SSCDIVINTPHASE6,
|
||||
temp);
|
||||
|
||||
/* Program SSCAUXDIV */
|
||||
temp = intel_sbi_read(dev_priv, SBI_SSCAUXDIV6);
|
||||
temp &= ~SBI_SSCAUXDIV_FINALDIV2SEL(1);
|
||||
temp |= SBI_SSCAUXDIV_FINALDIV2SEL(auxdiv);
|
||||
intel_sbi_write(dev_priv,
|
||||
SBI_SSCAUXDIV6,
|
||||
temp);
|
||||
|
||||
|
||||
/* Enable modulator and associated divider */
|
||||
temp = intel_sbi_read(dev_priv, SBI_SSCCTL6);
|
||||
temp &= ~SBI_SSCCTL_DISABLE;
|
||||
intel_sbi_write(dev_priv,
|
||||
SBI_SSCCTL6,
|
||||
temp);
|
||||
|
||||
/* Wait for initialization time */
|
||||
udelay(24);
|
||||
|
||||
I915_WRITE(PIXCLK_GATE, PIXCLK_GATE_UNGATE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable PCH resources required for PCH ports:
|
||||
* - PCH PLLs
|
||||
|
@ -2559,12 +2791,17 @@ static void ironlake_pch_enable(struct drm_crtc *crtc)
|
|||
int pipe = intel_crtc->pipe;
|
||||
u32 reg, temp;
|
||||
|
||||
assert_transcoder_disabled(dev_priv, pipe);
|
||||
|
||||
/* For PCH output, training FDI link */
|
||||
dev_priv->display.fdi_link_train(crtc);
|
||||
|
||||
intel_enable_pch_pll(intel_crtc);
|
||||
|
||||
if (HAS_PCH_CPT(dev)) {
|
||||
if (HAS_PCH_LPT(dev)) {
|
||||
DRM_DEBUG_KMS("LPT detected: programming iCLKIP\n");
|
||||
lpt_program_iclkip(crtc);
|
||||
} else if (HAS_PCH_CPT(dev)) {
|
||||
u32 sel;
|
||||
|
||||
temp = I915_READ(PCH_DPLL_SEL);
|
||||
|
@ -2601,7 +2838,8 @@ static void ironlake_pch_enable(struct drm_crtc *crtc)
|
|||
I915_WRITE(TRANS_VSYNC(pipe), I915_READ(VSYNC(pipe)));
|
||||
I915_WRITE(TRANS_VSYNCSHIFT(pipe), I915_READ(VSYNCSHIFT(pipe)));
|
||||
|
||||
intel_fdi_normal_train(crtc);
|
||||
if (!IS_HASWELL(dev))
|
||||
intel_fdi_normal_train(crtc);
|
||||
|
||||
/* For PCH DP, enable TRANS_DP_CTL */
|
||||
if (HAS_PCH_CPT(dev) &&
|
||||
|
@ -2673,6 +2911,17 @@ static struct intel_pch_pll *intel_get_pch_pll(struct intel_crtc *intel_crtc, u3
|
|||
goto prepare;
|
||||
}
|
||||
|
||||
if (HAS_PCH_IBX(dev_priv->dev)) {
|
||||
/* Ironlake PCH has a fixed PLL->PCH pipe mapping. */
|
||||
i = intel_crtc->pipe;
|
||||
pll = &dev_priv->pch_plls[i];
|
||||
|
||||
DRM_DEBUG_KMS("CRTC:%d using pre-allocated PCH PLL %x\n",
|
||||
intel_crtc->base.base.id, pll->pll_reg);
|
||||
|
||||
goto found;
|
||||
}
|
||||
|
||||
for (i = 0; i < dev_priv->num_pch_pll; i++) {
|
||||
pll = &dev_priv->pch_plls[i];
|
||||
|
||||
|
@ -3120,8 +3369,7 @@ void intel_encoder_commit(struct drm_encoder *encoder)
|
|||
{
|
||||
struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;
|
||||
struct drm_device *dev = encoder->dev;
|
||||
struct intel_encoder *intel_encoder = to_intel_encoder(encoder);
|
||||
struct intel_crtc *intel_crtc = to_intel_crtc(intel_encoder->base.crtc);
|
||||
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
|
||||
|
||||
/* lvds has its own version of commit see intel_lvds_commit */
|
||||
encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON);
|
||||
|
@ -4312,8 +4560,12 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
|
|||
DRM_DEBUG_KMS("Mode for pipe %d:\n", pipe);
|
||||
drm_mode_debug_printmodeline(mode);
|
||||
|
||||
/* CPU eDP is the only output that doesn't need a PCH PLL of its own */
|
||||
if (!is_cpu_edp) {
|
||||
/* CPU eDP is the only output that doesn't need a PCH PLL of its own on
|
||||
* pre-Haswell/LPT generation */
|
||||
if (HAS_PCH_LPT(dev)) {
|
||||
DRM_DEBUG_KMS("LPT detected: no PLL for pipe %d necessary\n",
|
||||
pipe);
|
||||
} else if (!is_cpu_edp) {
|
||||
struct intel_pch_pll *pll;
|
||||
|
||||
pll = intel_get_pch_pll(intel_crtc, dpll, fp);
|
||||
|
@ -4473,6 +4725,8 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
|
|||
|
||||
intel_update_watermarks(dev);
|
||||
|
||||
intel_update_linetime_watermarks(dev, pipe, adjusted_mode);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -5538,6 +5792,9 @@ void intel_mark_busy(struct drm_device *dev, struct drm_i915_gem_object *obj)
|
|||
mod_timer(&dev_priv->idle_timer, jiffies +
|
||||
msecs_to_jiffies(GPU_IDLE_TIMEOUT));
|
||||
|
||||
if (obj == NULL)
|
||||
return;
|
||||
|
||||
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
|
||||
if (!crtc->fb)
|
||||
continue;
|
||||
|
@ -5987,6 +6244,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
|
|||
goto cleanup_pending;
|
||||
|
||||
intel_disable_fbc(dev);
|
||||
intel_mark_busy(dev, obj);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
trace_i915_flip_request(intel_crtc->plane, obj);
|
||||
|
@ -6015,10 +6273,11 @@ static void intel_sanitize_modesetting(struct drm_device *dev,
|
|||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
u32 reg, val;
|
||||
int i;
|
||||
|
||||
/* Clear any frame start delays used for debugging left by the BIOS */
|
||||
for_each_pipe(pipe) {
|
||||
reg = PIPECONF(pipe);
|
||||
for_each_pipe(i) {
|
||||
reg = PIPECONF(i);
|
||||
I915_WRITE(reg, I915_READ(reg) & ~PIPECONF_FRAME_START_DELAY_MASK);
|
||||
}
|
||||
|
||||
|
@ -6238,7 +6497,26 @@ static void intel_setup_outputs(struct drm_device *dev)
|
|||
|
||||
intel_crt_init(dev);
|
||||
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
if (IS_HASWELL(dev)) {
|
||||
int found;
|
||||
|
||||
/* Haswell uses DDI functions to detect digital outputs */
|
||||
found = I915_READ(DDI_BUF_CTL_A) & DDI_INIT_DISPLAY_DETECTED;
|
||||
/* DDI A only supports eDP */
|
||||
if (found)
|
||||
intel_ddi_init(dev, PORT_A);
|
||||
|
||||
/* DDI B, C and D detection is indicated by the SFUSE_STRAP
|
||||
* register */
|
||||
found = I915_READ(SFUSE_STRAP);
|
||||
|
||||
if (found & SFUSE_STRAP_DDIB_DETECTED)
|
||||
intel_ddi_init(dev, PORT_B);
|
||||
if (found & SFUSE_STRAP_DDIC_DETECTED)
|
||||
intel_ddi_init(dev, PORT_C);
|
||||
if (found & SFUSE_STRAP_DDID_DETECTED)
|
||||
intel_ddi_init(dev, PORT_D);
|
||||
} else if (HAS_PCH_SPLIT(dev)) {
|
||||
int found;
|
||||
|
||||
if (I915_READ(HDMIB) & PORT_DETECTED) {
|
||||
|
@ -6467,6 +6745,9 @@ static void intel_init_display(struct drm_device *dev)
|
|||
/* FIXME: detect B0+ stepping and use auto training */
|
||||
dev_priv->display.fdi_link_train = ivb_manual_fdi_link_train;
|
||||
dev_priv->display.write_eld = ironlake_write_eld;
|
||||
} else if (IS_HASWELL(dev)) {
|
||||
dev_priv->display.fdi_link_train = hsw_fdi_link_train;
|
||||
dev_priv->display.write_eld = ironlake_write_eld;
|
||||
} else
|
||||
dev_priv->display.update_wm = NULL;
|
||||
} else if (IS_VALLEYVIEW(dev)) {
|
||||
|
@ -6634,6 +6915,7 @@ void intel_modeset_init_hw(struct drm_device *dev)
|
|||
|
||||
if (IS_IRONLAKE_M(dev)) {
|
||||
ironlake_enable_drps(dev);
|
||||
ironlake_enable_rc6(dev);
|
||||
intel_init_emon(dev);
|
||||
}
|
||||
|
||||
|
@ -6665,6 +6947,8 @@ void intel_modeset_init(struct drm_device *dev)
|
|||
|
||||
intel_init_pm(dev);
|
||||
|
||||
intel_prepare_ddi(dev);
|
||||
|
||||
intel_init_display(dev);
|
||||
|
||||
if (IS_GEN2(dev)) {
|
||||
|
@ -6695,8 +6979,6 @@ void intel_modeset_init(struct drm_device *dev)
|
|||
i915_disable_vga(dev);
|
||||
intel_setup_outputs(dev);
|
||||
|
||||
intel_modeset_init_hw(dev);
|
||||
|
||||
INIT_WORK(&dev_priv->idle_work, intel_idle_update);
|
||||
setup_timer(&dev_priv->idle_timer, intel_gpu_idle_timer,
|
||||
(unsigned long)dev);
|
||||
|
@ -6704,8 +6986,7 @@ void intel_modeset_init(struct drm_device *dev)
|
|||
|
||||
void intel_modeset_gem_init(struct drm_device *dev)
|
||||
{
|
||||
if (IS_IRONLAKE_M(dev))
|
||||
ironlake_enable_rc6(dev);
|
||||
intel_modeset_init_hw(dev);
|
||||
|
||||
intel_setup_overlay(dev);
|
||||
}
|
||||
|
|
|
@ -280,16 +280,29 @@ struct dip_infoframe {
|
|||
uint16_t bottom_bar_start;
|
||||
uint16_t left_bar_end;
|
||||
uint16_t right_bar_start;
|
||||
} avi;
|
||||
} __attribute__ ((packed)) avi;
|
||||
struct {
|
||||
uint8_t vn[8];
|
||||
uint8_t pd[16];
|
||||
uint8_t sdi;
|
||||
} spd;
|
||||
} __attribute__ ((packed)) spd;
|
||||
uint8_t payload[27];
|
||||
} __attribute__ ((packed)) body;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct intel_hdmi {
|
||||
struct intel_encoder base;
|
||||
u32 sdvox_reg;
|
||||
int ddc_bus;
|
||||
int ddi_port;
|
||||
uint32_t color_range;
|
||||
bool has_hdmi_sink;
|
||||
bool has_audio;
|
||||
enum hdmi_force_audio force_audio;
|
||||
void (*write_infoframe)(struct drm_encoder *encoder,
|
||||
struct dip_infoframe *frame);
|
||||
};
|
||||
|
||||
static inline struct drm_crtc *
|
||||
intel_get_crtc_for_pipe(struct drm_device *dev, int pipe)
|
||||
{
|
||||
|
@ -329,7 +342,11 @@ extern void intel_attach_broadcast_rgb_property(struct drm_connector *connector)
|
|||
|
||||
extern void intel_crt_init(struct drm_device *dev);
|
||||
extern void intel_hdmi_init(struct drm_device *dev, int sdvox_reg);
|
||||
void intel_dip_infoframe_csum(struct dip_infoframe *avi_if);
|
||||
extern struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder);
|
||||
extern void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder,
|
||||
struct drm_display_mode *adjusted_mode);
|
||||
extern void intel_hdmi_set_spd_infoframe(struct drm_encoder *encoder);
|
||||
extern void intel_dip_infoframe_csum(struct dip_infoframe *avi_if);
|
||||
extern bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg,
|
||||
bool is_sdvob);
|
||||
extern void intel_dvo_init(struct drm_device *dev);
|
||||
|
@ -446,12 +463,17 @@ extern void intel_init_clock_gating(struct drm_device *dev);
|
|||
extern void intel_write_eld(struct drm_encoder *encoder,
|
||||
struct drm_display_mode *mode);
|
||||
extern void intel_cpt_verify_modeset(struct drm_device *dev, int pipe);
|
||||
extern void intel_prepare_ddi(struct drm_device *dev);
|
||||
extern void hsw_fdi_link_train(struct drm_crtc *crtc);
|
||||
extern void intel_ddi_init(struct drm_device *dev, enum port port);
|
||||
|
||||
/* For use by IVB LP watermark workaround in intel_sprite.c */
|
||||
extern void intel_update_watermarks(struct drm_device *dev);
|
||||
extern void intel_update_sprite_watermarks(struct drm_device *dev, int pipe,
|
||||
uint32_t sprite_width,
|
||||
int pixel_size);
|
||||
extern void intel_update_linetime_watermarks(struct drm_device *dev, int pipe,
|
||||
struct drm_display_mode *mode);
|
||||
|
||||
extern int intel_sprite_set_colorkey(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv);
|
||||
|
@ -475,4 +497,9 @@ extern void gen6_update_ring_freq(struct drm_i915_private *dev_priv);
|
|||
extern void gen6_disable_rps(struct drm_device *dev);
|
||||
extern void intel_init_emon(struct drm_device *dev);
|
||||
|
||||
extern void intel_ddi_dpms(struct drm_encoder *encoder, int mode);
|
||||
extern void intel_ddi_mode_set(struct drm_encoder *encoder,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode);
|
||||
|
||||
#endif /* __INTEL_DRV_H__ */
|
||||
|
|
|
@ -37,19 +37,7 @@
|
|||
#include "i915_drm.h"
|
||||
#include "i915_drv.h"
|
||||
|
||||
struct intel_hdmi {
|
||||
struct intel_encoder base;
|
||||
u32 sdvox_reg;
|
||||
int ddc_bus;
|
||||
uint32_t color_range;
|
||||
bool has_hdmi_sink;
|
||||
bool has_audio;
|
||||
enum hdmi_force_audio force_audio;
|
||||
void (*write_infoframe)(struct drm_encoder *encoder,
|
||||
struct dip_infoframe *frame);
|
||||
};
|
||||
|
||||
static struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder)
|
||||
struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder)
|
||||
{
|
||||
return container_of(encoder, struct intel_hdmi, base.base);
|
||||
}
|
||||
|
@ -75,107 +63,182 @@ void intel_dip_infoframe_csum(struct dip_infoframe *frame)
|
|||
frame->checksum = 0x100 - sum;
|
||||
}
|
||||
|
||||
static u32 intel_infoframe_index(struct dip_infoframe *frame)
|
||||
static u32 g4x_infoframe_index(struct dip_infoframe *frame)
|
||||
{
|
||||
u32 flags = 0;
|
||||
|
||||
switch (frame->type) {
|
||||
case DIP_TYPE_AVI:
|
||||
flags |= VIDEO_DIP_SELECT_AVI;
|
||||
break;
|
||||
return VIDEO_DIP_SELECT_AVI;
|
||||
case DIP_TYPE_SPD:
|
||||
flags |= VIDEO_DIP_SELECT_SPD;
|
||||
break;
|
||||
return VIDEO_DIP_SELECT_SPD;
|
||||
default:
|
||||
DRM_DEBUG_DRIVER("unknown info frame type %d\n", frame->type);
|
||||
break;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
static u32 intel_infoframe_flags(struct dip_infoframe *frame)
|
||||
static u32 g4x_infoframe_enable(struct dip_infoframe *frame)
|
||||
{
|
||||
u32 flags = 0;
|
||||
|
||||
switch (frame->type) {
|
||||
case DIP_TYPE_AVI:
|
||||
flags |= VIDEO_DIP_ENABLE_AVI | VIDEO_DIP_FREQ_VSYNC;
|
||||
break;
|
||||
return VIDEO_DIP_ENABLE_AVI;
|
||||
case DIP_TYPE_SPD:
|
||||
flags |= VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_FREQ_VSYNC;
|
||||
break;
|
||||
return VIDEO_DIP_ENABLE_SPD;
|
||||
default:
|
||||
DRM_DEBUG_DRIVER("unknown info frame type %d\n", frame->type);
|
||||
break;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
static void i9xx_write_infoframe(struct drm_encoder *encoder,
|
||||
struct dip_infoframe *frame)
|
||||
static u32 hsw_infoframe_enable(struct dip_infoframe *frame)
|
||||
{
|
||||
switch (frame->type) {
|
||||
case DIP_TYPE_AVI:
|
||||
return VIDEO_DIP_ENABLE_AVI_HSW;
|
||||
case DIP_TYPE_SPD:
|
||||
return VIDEO_DIP_ENABLE_SPD_HSW;
|
||||
default:
|
||||
DRM_DEBUG_DRIVER("unknown info frame type %d\n", frame->type);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static u32 hsw_infoframe_data_reg(struct dip_infoframe *frame, enum pipe pipe)
|
||||
{
|
||||
switch (frame->type) {
|
||||
case DIP_TYPE_AVI:
|
||||
return HSW_TVIDEO_DIP_AVI_DATA(pipe);
|
||||
case DIP_TYPE_SPD:
|
||||
return HSW_TVIDEO_DIP_SPD_DATA(pipe);
|
||||
default:
|
||||
DRM_DEBUG_DRIVER("unknown info frame type %d\n", frame->type);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void g4x_write_infoframe(struct drm_encoder *encoder,
|
||||
struct dip_infoframe *frame)
|
||||
{
|
||||
uint32_t *data = (uint32_t *)frame;
|
||||
struct drm_device *dev = encoder->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
|
||||
u32 port, flags, val = I915_READ(VIDEO_DIP_CTL);
|
||||
u32 val = I915_READ(VIDEO_DIP_CTL);
|
||||
unsigned i, len = DIP_HEADER_SIZE + frame->len;
|
||||
|
||||
|
||||
/* XXX first guess at handling video port, is this corrent? */
|
||||
val &= ~VIDEO_DIP_PORT_MASK;
|
||||
if (intel_hdmi->sdvox_reg == SDVOB)
|
||||
port = VIDEO_DIP_PORT_B;
|
||||
val |= VIDEO_DIP_PORT_B;
|
||||
else if (intel_hdmi->sdvox_reg == SDVOC)
|
||||
port = VIDEO_DIP_PORT_C;
|
||||
val |= VIDEO_DIP_PORT_C;
|
||||
else
|
||||
return;
|
||||
|
||||
flags = intel_infoframe_index(frame);
|
||||
val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
|
||||
val |= g4x_infoframe_index(frame);
|
||||
|
||||
val &= ~VIDEO_DIP_SELECT_MASK;
|
||||
val &= ~g4x_infoframe_enable(frame);
|
||||
val |= VIDEO_DIP_ENABLE;
|
||||
|
||||
I915_WRITE(VIDEO_DIP_CTL, VIDEO_DIP_ENABLE | val | port | flags);
|
||||
I915_WRITE(VIDEO_DIP_CTL, val);
|
||||
|
||||
for (i = 0; i < len; i += 4) {
|
||||
I915_WRITE(VIDEO_DIP_DATA, *data);
|
||||
data++;
|
||||
}
|
||||
|
||||
flags |= intel_infoframe_flags(frame);
|
||||
val |= g4x_infoframe_enable(frame);
|
||||
val &= ~VIDEO_DIP_FREQ_MASK;
|
||||
val |= VIDEO_DIP_FREQ_VSYNC;
|
||||
|
||||
I915_WRITE(VIDEO_DIP_CTL, VIDEO_DIP_ENABLE | val | port | flags);
|
||||
I915_WRITE(VIDEO_DIP_CTL, val);
|
||||
}
|
||||
|
||||
static void ironlake_write_infoframe(struct drm_encoder *encoder,
|
||||
struct dip_infoframe *frame)
|
||||
static void ibx_write_infoframe(struct drm_encoder *encoder,
|
||||
struct dip_infoframe *frame)
|
||||
{
|
||||
uint32_t *data = (uint32_t *)frame;
|
||||
struct drm_device *dev = encoder->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct drm_crtc *crtc = encoder->crtc;
|
||||
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
||||
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
|
||||
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
|
||||
int reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
|
||||
unsigned i, len = DIP_HEADER_SIZE + frame->len;
|
||||
u32 flags, val = I915_READ(reg);
|
||||
u32 val = I915_READ(reg);
|
||||
|
||||
val &= ~VIDEO_DIP_PORT_MASK;
|
||||
switch (intel_hdmi->sdvox_reg) {
|
||||
case HDMIB:
|
||||
val |= VIDEO_DIP_PORT_B;
|
||||
break;
|
||||
case HDMIC:
|
||||
val |= VIDEO_DIP_PORT_C;
|
||||
break;
|
||||
case HDMID:
|
||||
val |= VIDEO_DIP_PORT_D;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
intel_wait_for_vblank(dev, intel_crtc->pipe);
|
||||
|
||||
flags = intel_infoframe_index(frame);
|
||||
|
||||
val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
|
||||
val |= g4x_infoframe_index(frame);
|
||||
|
||||
I915_WRITE(reg, VIDEO_DIP_ENABLE | val | flags);
|
||||
val &= ~g4x_infoframe_enable(frame);
|
||||
val |= VIDEO_DIP_ENABLE;
|
||||
|
||||
I915_WRITE(reg, val);
|
||||
|
||||
for (i = 0; i < len; i += 4) {
|
||||
I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), *data);
|
||||
data++;
|
||||
}
|
||||
|
||||
flags |= intel_infoframe_flags(frame);
|
||||
val |= g4x_infoframe_enable(frame);
|
||||
val &= ~VIDEO_DIP_FREQ_MASK;
|
||||
val |= VIDEO_DIP_FREQ_VSYNC;
|
||||
|
||||
I915_WRITE(reg, VIDEO_DIP_ENABLE | val | flags);
|
||||
I915_WRITE(reg, val);
|
||||
}
|
||||
|
||||
static void cpt_write_infoframe(struct drm_encoder *encoder,
|
||||
struct dip_infoframe *frame)
|
||||
{
|
||||
uint32_t *data = (uint32_t *)frame;
|
||||
struct drm_device *dev = encoder->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
|
||||
int reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
|
||||
unsigned i, len = DIP_HEADER_SIZE + frame->len;
|
||||
u32 val = I915_READ(reg);
|
||||
|
||||
intel_wait_for_vblank(dev, intel_crtc->pipe);
|
||||
|
||||
val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
|
||||
val |= g4x_infoframe_index(frame);
|
||||
|
||||
/* The DIP control register spec says that we need to update the AVI
|
||||
* infoframe without clearing its enable bit */
|
||||
if (frame->type == DIP_TYPE_AVI)
|
||||
val |= VIDEO_DIP_ENABLE_AVI;
|
||||
else
|
||||
val &= ~g4x_infoframe_enable(frame);
|
||||
|
||||
val |= VIDEO_DIP_ENABLE;
|
||||
|
||||
I915_WRITE(reg, val);
|
||||
|
||||
for (i = 0; i < len; i += 4) {
|
||||
I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), *data);
|
||||
data++;
|
||||
}
|
||||
|
||||
val |= g4x_infoframe_enable(frame);
|
||||
val &= ~VIDEO_DIP_FREQ_MASK;
|
||||
val |= VIDEO_DIP_FREQ_VSYNC;
|
||||
|
||||
I915_WRITE(reg, val);
|
||||
}
|
||||
|
||||
static void vlv_write_infoframe(struct drm_encoder *encoder,
|
||||
|
@ -184,28 +247,60 @@ static void vlv_write_infoframe(struct drm_encoder *encoder,
|
|||
uint32_t *data = (uint32_t *)frame;
|
||||
struct drm_device *dev = encoder->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct drm_crtc *crtc = encoder->crtc;
|
||||
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
||||
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
|
||||
int reg = VLV_TVIDEO_DIP_CTL(intel_crtc->pipe);
|
||||
unsigned i, len = DIP_HEADER_SIZE + frame->len;
|
||||
u32 flags, val = I915_READ(reg);
|
||||
u32 val = I915_READ(reg);
|
||||
|
||||
intel_wait_for_vblank(dev, intel_crtc->pipe);
|
||||
|
||||
flags = intel_infoframe_index(frame);
|
||||
|
||||
val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
|
||||
val |= g4x_infoframe_index(frame);
|
||||
|
||||
I915_WRITE(reg, VIDEO_DIP_ENABLE | val | flags);
|
||||
val &= ~g4x_infoframe_enable(frame);
|
||||
val |= VIDEO_DIP_ENABLE;
|
||||
|
||||
I915_WRITE(reg, val);
|
||||
|
||||
for (i = 0; i < len; i += 4) {
|
||||
I915_WRITE(VLV_TVIDEO_DIP_DATA(intel_crtc->pipe), *data);
|
||||
data++;
|
||||
}
|
||||
|
||||
flags |= intel_infoframe_flags(frame);
|
||||
val |= g4x_infoframe_enable(frame);
|
||||
val &= ~VIDEO_DIP_FREQ_MASK;
|
||||
val |= VIDEO_DIP_FREQ_VSYNC;
|
||||
|
||||
I915_WRITE(reg, VIDEO_DIP_ENABLE | val | flags);
|
||||
I915_WRITE(reg, val);
|
||||
}
|
||||
|
||||
static void hsw_write_infoframe(struct drm_encoder *encoder,
|
||||
struct dip_infoframe *frame)
|
||||
{
|
||||
uint32_t *data = (uint32_t *)frame;
|
||||
struct drm_device *dev = encoder->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
|
||||
u32 ctl_reg = HSW_TVIDEO_DIP_CTL(intel_crtc->pipe);
|
||||
u32 data_reg = hsw_infoframe_data_reg(frame, intel_crtc->pipe);
|
||||
unsigned int i, len = DIP_HEADER_SIZE + frame->len;
|
||||
u32 val = I915_READ(ctl_reg);
|
||||
|
||||
if (data_reg == 0)
|
||||
return;
|
||||
|
||||
intel_wait_for_vblank(dev, intel_crtc->pipe);
|
||||
|
||||
val &= ~hsw_infoframe_enable(frame);
|
||||
I915_WRITE(ctl_reg, val);
|
||||
|
||||
for (i = 0; i < len; i += 4) {
|
||||
I915_WRITE(data_reg + i, *data);
|
||||
data++;
|
||||
}
|
||||
|
||||
val |= hsw_infoframe_enable(frame);
|
||||
I915_WRITE(ctl_reg, val);
|
||||
}
|
||||
|
||||
static void intel_set_infoframe(struct drm_encoder *encoder,
|
||||
|
@ -220,7 +315,7 @@ static void intel_set_infoframe(struct drm_encoder *encoder,
|
|||
intel_hdmi->write_infoframe(encoder, frame);
|
||||
}
|
||||
|
||||
static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder,
|
||||
void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
{
|
||||
struct dip_infoframe avi_if = {
|
||||
|
@ -235,7 +330,7 @@ static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder,
|
|||
intel_set_infoframe(encoder, &avi_if);
|
||||
}
|
||||
|
||||
static void intel_hdmi_set_spd_infoframe(struct drm_encoder *encoder)
|
||||
void intel_hdmi_set_spd_infoframe(struct drm_encoder *encoder)
|
||||
{
|
||||
struct dip_infoframe spd_if;
|
||||
|
||||
|
@ -256,8 +351,7 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder,
|
|||
{
|
||||
struct drm_device *dev = encoder->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct drm_crtc *crtc = encoder->crtc;
|
||||
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
||||
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
|
||||
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
|
||||
u32 sdvox;
|
||||
|
||||
|
@ -431,8 +525,8 @@ intel_hdmi_detect_audio(struct drm_connector *connector)
|
|||
|
||||
static int
|
||||
intel_hdmi_set_property(struct drm_connector *connector,
|
||||
struct drm_property *property,
|
||||
uint64_t val)
|
||||
struct drm_property *property,
|
||||
uint64_t val)
|
||||
{
|
||||
struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
|
||||
struct drm_i915_private *dev_priv = connector->dev->dev_private;
|
||||
|
@ -491,6 +585,14 @@ static void intel_hdmi_destroy(struct drm_connector *connector)
|
|||
kfree(connector);
|
||||
}
|
||||
|
||||
static const struct drm_encoder_helper_funcs intel_hdmi_helper_funcs_hsw = {
|
||||
.dpms = intel_ddi_dpms,
|
||||
.mode_fixup = intel_hdmi_mode_fixup,
|
||||
.prepare = intel_encoder_prepare,
|
||||
.mode_set = intel_ddi_mode_set,
|
||||
.commit = intel_encoder_commit,
|
||||
};
|
||||
|
||||
static const struct drm_encoder_helper_funcs intel_hdmi_helper_funcs = {
|
||||
.dpms = intel_hdmi_dpms,
|
||||
.mode_fixup = intel_hdmi_mode_fixup,
|
||||
|
@ -580,24 +682,60 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg)
|
|||
intel_encoder->clone_mask = (1 << INTEL_HDMIF_CLONE_BIT);
|
||||
intel_hdmi->ddc_bus = GMBUS_PORT_DPD;
|
||||
dev_priv->hotplug_supported_mask |= HDMID_HOTPLUG_INT_STATUS;
|
||||
} else if (sdvox_reg == DDI_BUF_CTL(PORT_B)) {
|
||||
DRM_DEBUG_DRIVER("LPT: detected output on DDI B\n");
|
||||
intel_encoder->clone_mask = (1 << INTEL_HDMIB_CLONE_BIT);
|
||||
intel_hdmi->ddc_bus = GMBUS_PORT_DPB;
|
||||
intel_hdmi->ddi_port = PORT_B;
|
||||
dev_priv->hotplug_supported_mask |= HDMIB_HOTPLUG_INT_STATUS;
|
||||
} else if (sdvox_reg == DDI_BUF_CTL(PORT_C)) {
|
||||
DRM_DEBUG_DRIVER("LPT: detected output on DDI C\n");
|
||||
intel_encoder->clone_mask = (1 << INTEL_HDMIC_CLONE_BIT);
|
||||
intel_hdmi->ddc_bus = GMBUS_PORT_DPC;
|
||||
intel_hdmi->ddi_port = PORT_C;
|
||||
dev_priv->hotplug_supported_mask |= HDMIC_HOTPLUG_INT_STATUS;
|
||||
} else if (sdvox_reg == DDI_BUF_CTL(PORT_D)) {
|
||||
DRM_DEBUG_DRIVER("LPT: detected output on DDI D\n");
|
||||
intel_encoder->clone_mask = (1 << INTEL_HDMID_CLONE_BIT);
|
||||
intel_hdmi->ddc_bus = GMBUS_PORT_DPD;
|
||||
intel_hdmi->ddi_port = PORT_D;
|
||||
dev_priv->hotplug_supported_mask |= HDMID_HOTPLUG_INT_STATUS;
|
||||
} else {
|
||||
/* If we got an unknown sdvox_reg, things are pretty much broken
|
||||
* in a way that we should let the kernel know about it */
|
||||
BUG();
|
||||
}
|
||||
|
||||
intel_hdmi->sdvox_reg = sdvox_reg;
|
||||
|
||||
if (!HAS_PCH_SPLIT(dev)) {
|
||||
intel_hdmi->write_infoframe = i9xx_write_infoframe;
|
||||
intel_hdmi->write_infoframe = g4x_write_infoframe;
|
||||
I915_WRITE(VIDEO_DIP_CTL, 0);
|
||||
} else if (IS_VALLEYVIEW(dev)) {
|
||||
intel_hdmi->write_infoframe = vlv_write_infoframe;
|
||||
for_each_pipe(i)
|
||||
I915_WRITE(VLV_TVIDEO_DIP_CTL(i), 0);
|
||||
} else {
|
||||
intel_hdmi->write_infoframe = ironlake_write_infoframe;
|
||||
} else if (IS_HASWELL(dev)) {
|
||||
/* FIXME: Haswell has a new set of DIP frame registers, but we are
|
||||
* just doing the minimal required for HDMI to work at this stage.
|
||||
*/
|
||||
intel_hdmi->write_infoframe = hsw_write_infoframe;
|
||||
for_each_pipe(i)
|
||||
I915_WRITE(HSW_TVIDEO_DIP_CTL(i), 0);
|
||||
} else if (HAS_PCH_IBX(dev)) {
|
||||
intel_hdmi->write_infoframe = ibx_write_infoframe;
|
||||
for_each_pipe(i)
|
||||
I915_WRITE(TVIDEO_DIP_CTL(i), 0);
|
||||
} else {
|
||||
intel_hdmi->write_infoframe = cpt_write_infoframe;
|
||||
for_each_pipe(i)
|
||||
I915_WRITE(TVIDEO_DIP_CTL(i), 0);
|
||||
}
|
||||
|
||||
drm_encoder_helper_add(&intel_encoder->base, &intel_hdmi_helper_funcs);
|
||||
if (IS_HASWELL(dev))
|
||||
drm_encoder_helper_add(&intel_encoder->base, &intel_hdmi_helper_funcs_hsw);
|
||||
else
|
||||
drm_encoder_helper_add(&intel_encoder->base, &intel_hdmi_helper_funcs);
|
||||
|
||||
intel_hdmi_add_properties(intel_hdmi, connector);
|
||||
|
||||
|
|
|
@ -490,6 +490,10 @@ int intel_setup_gmbus(struct drm_device *dev)
|
|||
/* By default use a conservative clock rate */
|
||||
bus->reg0 = port | GMBUS_RATE_100KHZ;
|
||||
|
||||
/* gmbus seems to be broken on i830 */
|
||||
if (IS_I830(dev))
|
||||
bus->force_bit = true;
|
||||
|
||||
intel_gpio_setup(bus, port);
|
||||
}
|
||||
|
||||
|
|
|
@ -1803,8 +1803,7 @@ static void sandybridge_update_wm(struct drm_device *dev)
|
|||
enabled |= 2;
|
||||
}
|
||||
|
||||
/* IVB has 3 pipes */
|
||||
if (IS_IVYBRIDGE(dev) &&
|
||||
if ((dev_priv->num_pipe == 3) &&
|
||||
g4x_compute_wm0(dev, 2,
|
||||
&sandybridge_display_wm_info, latency,
|
||||
&sandybridge_cursor_wm_info, latency,
|
||||
|
@ -1884,6 +1883,33 @@ static void sandybridge_update_wm(struct drm_device *dev)
|
|||
cursor_wm);
|
||||
}
|
||||
|
||||
static void
|
||||
haswell_update_linetime_wm(struct drm_device *dev, int pipe,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
u32 temp;
|
||||
|
||||
temp = I915_READ(PIPE_WM_LINETIME(pipe));
|
||||
temp &= ~PIPE_WM_LINETIME_MASK;
|
||||
|
||||
/* The WM are computed with base on how long it takes to fill a single
|
||||
* row at the given clock rate, multiplied by 8.
|
||||
* */
|
||||
temp |= PIPE_WM_LINETIME_TIME(
|
||||
((mode->crtc_hdisplay * 1000) / mode->clock) * 8);
|
||||
|
||||
/* IPS watermarks are only used by pipe A, and are ignored by
|
||||
* pipes B and C. They are calculated similarly to the common
|
||||
* linetime values, except that we are using CD clock frequency
|
||||
* in MHz instead of pixel rate for the division.
|
||||
*
|
||||
* This is a placeholder for the IPS watermark calculation code.
|
||||
*/
|
||||
|
||||
I915_WRITE(PIPE_WM_LINETIME(pipe), temp);
|
||||
}
|
||||
|
||||
static bool
|
||||
sandybridge_compute_sprite_wm(struct drm_device *dev, int plane,
|
||||
uint32_t sprite_width, int pixel_size,
|
||||
|
@ -2079,6 +2105,15 @@ void intel_update_watermarks(struct drm_device *dev)
|
|||
dev_priv->display.update_wm(dev);
|
||||
}
|
||||
|
||||
void intel_update_linetime_watermarks(struct drm_device *dev,
|
||||
int pipe, struct drm_display_mode *mode)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
||||
if (dev_priv->display.update_linetime_wm)
|
||||
dev_priv->display.update_linetime_wm(dev, pipe, mode);
|
||||
}
|
||||
|
||||
void intel_update_sprite_watermarks(struct drm_device *dev, int pipe,
|
||||
uint32_t sprite_width, int pixel_size)
|
||||
{
|
||||
|
@ -2291,6 +2326,7 @@ int intel_enable_rc6(const struct drm_device *dev)
|
|||
|
||||
void gen6_enable_rps(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
struct intel_ring_buffer *ring;
|
||||
u32 rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
|
||||
u32 gt_perf_status = I915_READ(GEN6_GT_PERF_STATUS);
|
||||
u32 pcu_mbox, rc6_mask = 0;
|
||||
|
@ -2325,8 +2361,8 @@ void gen6_enable_rps(struct drm_i915_private *dev_priv)
|
|||
I915_WRITE(GEN6_RC_EVALUATION_INTERVAL, 125000);
|
||||
I915_WRITE(GEN6_RC_IDLE_HYSTERSIS, 25);
|
||||
|
||||
for (i = 0; i < I915_NUM_RINGS; i++)
|
||||
I915_WRITE(RING_MAX_IDLE(dev_priv->ring[i].mmio_base), 10);
|
||||
for_each_ring(ring, dev_priv, i)
|
||||
I915_WRITE(RING_MAX_IDLE(ring->mmio_base), 10);
|
||||
|
||||
I915_WRITE(GEN6_RC_SLEEP, 0);
|
||||
I915_WRITE(GEN6_RC1e_THRESHOLD, 1000);
|
||||
|
@ -3560,6 +3596,37 @@ void intel_sanitize_pm(struct drm_device *dev)
|
|||
dev_priv->display.sanitize_pm(dev);
|
||||
}
|
||||
|
||||
/* Starting with Haswell, we have different power wells for
|
||||
* different parts of the GPU. This attempts to enable them all.
|
||||
*/
|
||||
void intel_init_power_wells(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
unsigned long power_wells[] = {
|
||||
HSW_PWR_WELL_CTL1,
|
||||
HSW_PWR_WELL_CTL2,
|
||||
HSW_PWR_WELL_CTL4
|
||||
};
|
||||
int i;
|
||||
|
||||
if (!IS_HASWELL(dev))
|
||||
return;
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(power_wells); i++) {
|
||||
int well = I915_READ(power_wells[i]);
|
||||
|
||||
if ((well & HSW_PWR_WELL_STATE) == 0) {
|
||||
I915_WRITE(power_wells[i], well & HSW_PWR_WELL_ENABLE);
|
||||
if (wait_for(I915_READ(power_wells[i] & HSW_PWR_WELL_STATE), 20))
|
||||
DRM_ERROR("Error enabling power well %lx\n", power_wells[i]);
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
}
|
||||
|
||||
/* Set up chip specific power management-related functions */
|
||||
void intel_init_pm(struct drm_device *dev)
|
||||
{
|
||||
|
@ -3655,6 +3722,18 @@ void intel_init_pm(struct drm_device *dev)
|
|||
}
|
||||
dev_priv->display.init_clock_gating = ivybridge_init_clock_gating;
|
||||
dev_priv->display.sanitize_pm = gen6_sanitize_pm;
|
||||
} else if (IS_HASWELL(dev)) {
|
||||
if (SNB_READ_WM0_LATENCY()) {
|
||||
dev_priv->display.update_wm = sandybridge_update_wm;
|
||||
dev_priv->display.update_sprite_wm = sandybridge_update_sprite_wm;
|
||||
dev_priv->display.update_linetime_wm = haswell_update_linetime_wm;
|
||||
} else {
|
||||
DRM_DEBUG_KMS("Failed to read display plane latency. "
|
||||
"Disable CxSR\n");
|
||||
dev_priv->display.update_wm = NULL;
|
||||
}
|
||||
dev_priv->display.init_clock_gating = ivybridge_init_clock_gating;
|
||||
dev_priv->display.sanitize_pm = gen6_sanitize_pm;
|
||||
} else
|
||||
dev_priv->display.update_wm = NULL;
|
||||
} else if (IS_VALLEYVIEW(dev)) {
|
||||
|
@ -3708,5 +3787,10 @@ void intel_init_pm(struct drm_device *dev)
|
|||
else
|
||||
dev_priv->display.get_fifo_size = i830_get_fifo_size;
|
||||
}
|
||||
|
||||
/* We attempt to init the necessary power wells early in the initialization
|
||||
* time, so the subsystems that expect power to be enabled can work.
|
||||
*/
|
||||
intel_init_power_wells(dev);
|
||||
}
|
||||
|
||||
|
|
|
@ -119,6 +119,12 @@ struct intel_ring_buffer {
|
|||
void *private;
|
||||
};
|
||||
|
||||
static inline bool
|
||||
intel_ring_initialized(struct intel_ring_buffer *ring)
|
||||
{
|
||||
return ring->obj != NULL;
|
||||
}
|
||||
|
||||
static inline unsigned
|
||||
intel_ring_flag(struct intel_ring_buffer *ring)
|
||||
{
|
||||
|
|
|
@ -887,17 +887,24 @@ static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo)
|
|||
};
|
||||
uint8_t tx_rate = SDVO_HBUF_TX_VSYNC;
|
||||
uint8_t set_buf_index[2] = { 1, 0 };
|
||||
uint64_t *data = (uint64_t *)&avi_if;
|
||||
uint8_t sdvo_data[4 + sizeof(avi_if.body.avi)];
|
||||
uint64_t *data = (uint64_t *)sdvo_data;
|
||||
unsigned i;
|
||||
|
||||
intel_dip_infoframe_csum(&avi_if);
|
||||
|
||||
/* sdvo spec says that the ecc is handled by the hw, and it looks like
|
||||
* we must not send the ecc field, either. */
|
||||
memcpy(sdvo_data, &avi_if, 3);
|
||||
sdvo_data[3] = avi_if.checksum;
|
||||
memcpy(&sdvo_data[4], &avi_if.body, sizeof(avi_if.body.avi));
|
||||
|
||||
if (!intel_sdvo_set_value(intel_sdvo,
|
||||
SDVO_CMD_SET_HBUF_INDEX,
|
||||
set_buf_index, 2))
|
||||
return false;
|
||||
|
||||
for (i = 0; i < sizeof(avi_if); i += 8) {
|
||||
for (i = 0; i < sizeof(sdvo_data); i += 8) {
|
||||
if (!intel_sdvo_set_value(intel_sdvo,
|
||||
SDVO_CMD_SET_HBUF_DATA,
|
||||
data, 8))
|
||||
|
|
Загрузка…
Ссылка в новой задаче