Merge tag 'drm-intel-fixes-2013-09-19' of git://people.freedesktop.org/~danvet/drm-intel into drm-fixes
Some more dealock fixes around pageflips and gpu hangs, fixes for hsw hangs when doing modesets/dpms. And a few minor things to rectify issues with our modeset state tracking which the checker spotted. * tag 'drm-intel-fixes-2013-09-19' of git://people.freedesktop.org/~danvet/drm-intel: drm/i915: Don't enable the cursor on a disable pipe drm/i915: do not update cursor in crtc mode set drm/i915: kill set_need_resched drm/i915/dvo: set crtc timings again for panel fixed modes drm/i915/sdvo: Robustify the dtd<->drm_mode conversions drm/i915/sdvo: Fully translate sync flags in the dtd->mode conversion drm/i915: Use proper print format for debug prints drm/i915: fix wait_for_pending_flips vs gpu hang deadlock drm/i915: Track pfit enable state separately from size
This commit is contained in:
@@ -1390,14 +1390,11 @@ out:
|
|||||||
if (i915_terminally_wedged(&dev_priv->gpu_error))
|
if (i915_terminally_wedged(&dev_priv->gpu_error))
|
||||||
return VM_FAULT_SIGBUS;
|
return VM_FAULT_SIGBUS;
|
||||||
case -EAGAIN:
|
case -EAGAIN:
|
||||||
/* Give the error handler a chance to run and move the
|
/*
|
||||||
* objects off the GPU active list. Next time we service the
|
* EAGAIN means the gpu is hung and we'll wait for the error
|
||||||
* fault, we should be able to transition the page into the
|
* handler to reset everything when re-faulting in
|
||||||
* GTT without touching the GPU (and so avoid further
|
* i915_mutex_lock_interruptible.
|
||||||
* EIO/EGAIN). If the GPU is wedged, then there is no issue
|
|
||||||
* with coherency, just lost writes.
|
|
||||||
*/
|
*/
|
||||||
set_need_resched();
|
|
||||||
case 0:
|
case 0:
|
||||||
case -ERESTARTSYS:
|
case -ERESTARTSYS:
|
||||||
case -EINTR:
|
case -EINTR:
|
||||||
|
@@ -1469,6 +1469,34 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void i915_error_wake_up(struct drm_i915_private *dev_priv,
|
||||||
|
bool reset_completed)
|
||||||
|
{
|
||||||
|
struct intel_ring_buffer *ring;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Notify all waiters for GPU completion events that reset state has
|
||||||
|
* been changed, and that they need to restart their wait after
|
||||||
|
* checking for potential errors (and bail out to drop locks if there is
|
||||||
|
* a gpu reset pending so that i915_error_work_func can acquire them).
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Wake up __wait_seqno, potentially holding dev->struct_mutex. */
|
||||||
|
for_each_ring(ring, dev_priv, i)
|
||||||
|
wake_up_all(&ring->irq_queue);
|
||||||
|
|
||||||
|
/* Wake up intel_crtc_wait_for_pending_flips, holding crtc->mutex. */
|
||||||
|
wake_up_all(&dev_priv->pending_flip_queue);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Signal tasks blocked in i915_gem_wait_for_error that the pending
|
||||||
|
* reset state is cleared.
|
||||||
|
*/
|
||||||
|
if (reset_completed)
|
||||||
|
wake_up_all(&dev_priv->gpu_error.reset_queue);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* i915_error_work_func - do process context error handling work
|
* i915_error_work_func - do process context error handling work
|
||||||
* @work: work struct
|
* @work: work struct
|
||||||
@@ -1483,11 +1511,10 @@ static void i915_error_work_func(struct work_struct *work)
|
|||||||
drm_i915_private_t *dev_priv = container_of(error, drm_i915_private_t,
|
drm_i915_private_t *dev_priv = container_of(error, drm_i915_private_t,
|
||||||
gpu_error);
|
gpu_error);
|
||||||
struct drm_device *dev = dev_priv->dev;
|
struct drm_device *dev = dev_priv->dev;
|
||||||
struct intel_ring_buffer *ring;
|
|
||||||
char *error_event[] = { I915_ERROR_UEVENT "=1", NULL };
|
char *error_event[] = { I915_ERROR_UEVENT "=1", NULL };
|
||||||
char *reset_event[] = { I915_RESET_UEVENT "=1", NULL };
|
char *reset_event[] = { I915_RESET_UEVENT "=1", NULL };
|
||||||
char *reset_done_event[] = { I915_ERROR_UEVENT "=0", NULL };
|
char *reset_done_event[] = { I915_ERROR_UEVENT "=0", NULL };
|
||||||
int i, ret;
|
int ret;
|
||||||
|
|
||||||
kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, error_event);
|
kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, error_event);
|
||||||
|
|
||||||
@@ -1506,8 +1533,16 @@ static void i915_error_work_func(struct work_struct *work)
|
|||||||
kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE,
|
kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE,
|
||||||
reset_event);
|
reset_event);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* All state reset _must_ be completed before we update the
|
||||||
|
* reset counter, for otherwise waiters might miss the reset
|
||||||
|
* pending state and not properly drop locks, resulting in
|
||||||
|
* deadlocks with the reset work.
|
||||||
|
*/
|
||||||
ret = i915_reset(dev);
|
ret = i915_reset(dev);
|
||||||
|
|
||||||
|
intel_display_handle_reset(dev);
|
||||||
|
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
/*
|
/*
|
||||||
* After all the gem state is reset, increment the reset
|
* After all the gem state is reset, increment the reset
|
||||||
@@ -1528,12 +1563,11 @@ static void i915_error_work_func(struct work_struct *work)
|
|||||||
atomic_set(&error->reset_counter, I915_WEDGED);
|
atomic_set(&error->reset_counter, I915_WEDGED);
|
||||||
}
|
}
|
||||||
|
|
||||||
for_each_ring(ring, dev_priv, i)
|
/*
|
||||||
wake_up_all(&ring->irq_queue);
|
* Note: The wake_up also serves as a memory barrier so that
|
||||||
|
* waiters see the update value of the reset counter atomic_t.
|
||||||
intel_display_handle_reset(dev);
|
*/
|
||||||
|
i915_error_wake_up(dev_priv, true);
|
||||||
wake_up_all(&dev_priv->gpu_error.reset_queue);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1642,8 +1676,6 @@ static void i915_report_and_clear_eir(struct drm_device *dev)
|
|||||||
void i915_handle_error(struct drm_device *dev, bool wedged)
|
void i915_handle_error(struct drm_device *dev, bool wedged)
|
||||||
{
|
{
|
||||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||||
struct intel_ring_buffer *ring;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
i915_capture_error_state(dev);
|
i915_capture_error_state(dev);
|
||||||
i915_report_and_clear_eir(dev);
|
i915_report_and_clear_eir(dev);
|
||||||
@@ -1653,11 +1685,19 @@ void i915_handle_error(struct drm_device *dev, bool wedged)
|
|||||||
&dev_priv->gpu_error.reset_counter);
|
&dev_priv->gpu_error.reset_counter);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Wakeup waiting processes so that the reset work item
|
* Wakeup waiting processes so that the reset work function
|
||||||
* doesn't deadlock trying to grab various locks.
|
* i915_error_work_func doesn't deadlock trying to grab various
|
||||||
|
* locks. By bumping the reset counter first, the woken
|
||||||
|
* processes will see a reset in progress and back off,
|
||||||
|
* releasing their locks and then wait for the reset completion.
|
||||||
|
* We must do this for _all_ gpu waiters that might hold locks
|
||||||
|
* that the reset work needs to acquire.
|
||||||
|
*
|
||||||
|
* Note: The wake_up serves as the required memory barrier to
|
||||||
|
* ensure that the waiters see the updated value of the reset
|
||||||
|
* counter atomic_t.
|
||||||
*/
|
*/
|
||||||
for_each_ring(ring, dev_priv, i)
|
i915_error_wake_up(dev_priv, false);
|
||||||
wake_up_all(&ring->irq_queue);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@@ -778,7 +778,7 @@ void intel_ddi_enable_transcoder_func(struct drm_crtc *crtc)
|
|||||||
/* Can only use the always-on power well for eDP when
|
/* Can only use the always-on power well for eDP when
|
||||||
* not using the panel fitter, and when not using motion
|
* not using the panel fitter, and when not using motion
|
||||||
* blur mitigation (which we don't support). */
|
* blur mitigation (which we don't support). */
|
||||||
if (intel_crtc->config.pch_pfit.size)
|
if (intel_crtc->config.pch_pfit.enabled)
|
||||||
temp |= TRANS_DDI_EDP_INPUT_A_ONOFF;
|
temp |= TRANS_DDI_EDP_INPUT_A_ONOFF;
|
||||||
else
|
else
|
||||||
temp |= TRANS_DDI_EDP_INPUT_A_ON;
|
temp |= TRANS_DDI_EDP_INPUT_A_ON;
|
||||||
|
@@ -2249,7 +2249,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
|
|||||||
I915_WRITE(PIPESRC(intel_crtc->pipe),
|
I915_WRITE(PIPESRC(intel_crtc->pipe),
|
||||||
((crtc->mode.hdisplay - 1) << 16) |
|
((crtc->mode.hdisplay - 1) << 16) |
|
||||||
(crtc->mode.vdisplay - 1));
|
(crtc->mode.vdisplay - 1));
|
||||||
if (!intel_crtc->config.pch_pfit.size &&
|
if (!intel_crtc->config.pch_pfit.enabled &&
|
||||||
(intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) ||
|
(intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) ||
|
||||||
intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP))) {
|
intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP))) {
|
||||||
I915_WRITE(PF_CTL(intel_crtc->pipe), 0);
|
I915_WRITE(PF_CTL(intel_crtc->pipe), 0);
|
||||||
@@ -3203,7 +3203,7 @@ static void ironlake_pfit_enable(struct intel_crtc *crtc)
|
|||||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||||
int pipe = crtc->pipe;
|
int pipe = crtc->pipe;
|
||||||
|
|
||||||
if (crtc->config.pch_pfit.size) {
|
if (crtc->config.pch_pfit.enabled) {
|
||||||
/* Force use of hard-coded filter coefficients
|
/* Force use of hard-coded filter coefficients
|
||||||
* as some pre-programmed values are broken,
|
* as some pre-programmed values are broken,
|
||||||
* e.g. x201.
|
* e.g. x201.
|
||||||
@@ -3428,7 +3428,7 @@ static void ironlake_pfit_disable(struct intel_crtc *crtc)
|
|||||||
|
|
||||||
/* To avoid upsetting the power well on haswell only disable the pfit if
|
/* To avoid upsetting the power well on haswell only disable the pfit if
|
||||||
* it's in use. The hw state code will make sure we get this right. */
|
* it's in use. The hw state code will make sure we get this right. */
|
||||||
if (crtc->config.pch_pfit.size) {
|
if (crtc->config.pch_pfit.enabled) {
|
||||||
I915_WRITE(PF_CTL(pipe), 0);
|
I915_WRITE(PF_CTL(pipe), 0);
|
||||||
I915_WRITE(PF_WIN_POS(pipe), 0);
|
I915_WRITE(PF_WIN_POS(pipe), 0);
|
||||||
I915_WRITE(PF_WIN_SZ(pipe), 0);
|
I915_WRITE(PF_WIN_SZ(pipe), 0);
|
||||||
@@ -4877,9 +4877,6 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Ensure that the cursor is valid for the new mode before changing... */
|
|
||||||
intel_crtc_update_cursor(crtc, true);
|
|
||||||
|
|
||||||
if (is_lvds && dev_priv->lvds_downclock_avail) {
|
if (is_lvds && dev_priv->lvds_downclock_avail) {
|
||||||
/*
|
/*
|
||||||
* Ensure we match the reduced clock's P to the target clock.
|
* Ensure we match the reduced clock's P to the target clock.
|
||||||
@@ -5768,9 +5765,6 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
|
|||||||
intel_crtc->config.dpll.p2 = clock.p2;
|
intel_crtc->config.dpll.p2 = clock.p2;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Ensure that the cursor is valid for the new mode before changing... */
|
|
||||||
intel_crtc_update_cursor(crtc, true);
|
|
||||||
|
|
||||||
/* CPU eDP is the only output that doesn't need a PCH PLL of its own. */
|
/* CPU eDP is the only output that doesn't need a PCH PLL of its own. */
|
||||||
if (intel_crtc->config.has_pch_encoder) {
|
if (intel_crtc->config.has_pch_encoder) {
|
||||||
fp = i9xx_dpll_compute_fp(&intel_crtc->config.dpll);
|
fp = i9xx_dpll_compute_fp(&intel_crtc->config.dpll);
|
||||||
@@ -5859,6 +5853,7 @@ static void ironlake_get_pfit_config(struct intel_crtc *crtc,
|
|||||||
tmp = I915_READ(PF_CTL(crtc->pipe));
|
tmp = I915_READ(PF_CTL(crtc->pipe));
|
||||||
|
|
||||||
if (tmp & PF_ENABLE) {
|
if (tmp & PF_ENABLE) {
|
||||||
|
pipe_config->pch_pfit.enabled = true;
|
||||||
pipe_config->pch_pfit.pos = I915_READ(PF_WIN_POS(crtc->pipe));
|
pipe_config->pch_pfit.pos = I915_READ(PF_WIN_POS(crtc->pipe));
|
||||||
pipe_config->pch_pfit.size = I915_READ(PF_WIN_SZ(crtc->pipe));
|
pipe_config->pch_pfit.size = I915_READ(PF_WIN_SZ(crtc->pipe));
|
||||||
|
|
||||||
@@ -6236,7 +6231,7 @@ static void haswell_modeset_global_resources(struct drm_device *dev)
|
|||||||
if (!crtc->base.enabled)
|
if (!crtc->base.enabled)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (crtc->pipe != PIPE_A || crtc->config.pch_pfit.size ||
|
if (crtc->pipe != PIPE_A || crtc->config.pch_pfit.enabled ||
|
||||||
crtc->config.cpu_transcoder != TRANSCODER_EDP)
|
crtc->config.cpu_transcoder != TRANSCODER_EDP)
|
||||||
enable = true;
|
enable = true;
|
||||||
}
|
}
|
||||||
@@ -6259,9 +6254,6 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc,
|
|||||||
if (!intel_ddi_pll_mode_set(crtc))
|
if (!intel_ddi_pll_mode_set(crtc))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
/* Ensure that the cursor is valid for the new mode before changing... */
|
|
||||||
intel_crtc_update_cursor(crtc, true);
|
|
||||||
|
|
||||||
if (intel_crtc->config.has_dp_encoder)
|
if (intel_crtc->config.has_dp_encoder)
|
||||||
intel_dp_set_m_n(intel_crtc);
|
intel_dp_set_m_n(intel_crtc);
|
||||||
|
|
||||||
@@ -6494,15 +6486,15 @@ static void haswell_write_eld(struct drm_connector *connector,
|
|||||||
|
|
||||||
/* Set ELD valid state */
|
/* Set ELD valid state */
|
||||||
tmp = I915_READ(aud_cntrl_st2);
|
tmp = I915_READ(aud_cntrl_st2);
|
||||||
DRM_DEBUG_DRIVER("HDMI audio: pin eld vld status=0x%8x\n", tmp);
|
DRM_DEBUG_DRIVER("HDMI audio: pin eld vld status=0x%08x\n", tmp);
|
||||||
tmp |= (AUDIO_ELD_VALID_A << (pipe * 4));
|
tmp |= (AUDIO_ELD_VALID_A << (pipe * 4));
|
||||||
I915_WRITE(aud_cntrl_st2, tmp);
|
I915_WRITE(aud_cntrl_st2, tmp);
|
||||||
tmp = I915_READ(aud_cntrl_st2);
|
tmp = I915_READ(aud_cntrl_st2);
|
||||||
DRM_DEBUG_DRIVER("HDMI audio: eld vld status=0x%8x\n", tmp);
|
DRM_DEBUG_DRIVER("HDMI audio: eld vld status=0x%08x\n", tmp);
|
||||||
|
|
||||||
/* Enable HDMI mode */
|
/* Enable HDMI mode */
|
||||||
tmp = I915_READ(aud_config);
|
tmp = I915_READ(aud_config);
|
||||||
DRM_DEBUG_DRIVER("HDMI audio: audio conf: 0x%8x\n", tmp);
|
DRM_DEBUG_DRIVER("HDMI audio: audio conf: 0x%08x\n", tmp);
|
||||||
/* clear N_programing_enable and N_value_index */
|
/* clear N_programing_enable and N_value_index */
|
||||||
tmp &= ~(AUD_CONFIG_N_VALUE_INDEX | AUD_CONFIG_N_PROG_ENABLE);
|
tmp &= ~(AUD_CONFIG_N_VALUE_INDEX | AUD_CONFIG_N_PROG_ENABLE);
|
||||||
I915_WRITE(aud_config, tmp);
|
I915_WRITE(aud_config, tmp);
|
||||||
@@ -6937,7 +6929,8 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
|
|||||||
intel_crtc->cursor_width = width;
|
intel_crtc->cursor_width = width;
|
||||||
intel_crtc->cursor_height = height;
|
intel_crtc->cursor_height = height;
|
||||||
|
|
||||||
intel_crtc_update_cursor(crtc, intel_crtc->cursor_bo != NULL);
|
if (intel_crtc->active)
|
||||||
|
intel_crtc_update_cursor(crtc, intel_crtc->cursor_bo != NULL);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
fail_unpin:
|
fail_unpin:
|
||||||
@@ -6956,7 +6949,8 @@ static int intel_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
|
|||||||
intel_crtc->cursor_x = x;
|
intel_crtc->cursor_x = x;
|
||||||
intel_crtc->cursor_y = y;
|
intel_crtc->cursor_y = y;
|
||||||
|
|
||||||
intel_crtc_update_cursor(crtc, intel_crtc->cursor_bo != NULL);
|
if (intel_crtc->active)
|
||||||
|
intel_crtc_update_cursor(crtc, intel_crtc->cursor_bo != NULL);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -8205,9 +8199,10 @@ static void intel_dump_pipe_config(struct intel_crtc *crtc,
|
|||||||
pipe_config->gmch_pfit.control,
|
pipe_config->gmch_pfit.control,
|
||||||
pipe_config->gmch_pfit.pgm_ratios,
|
pipe_config->gmch_pfit.pgm_ratios,
|
||||||
pipe_config->gmch_pfit.lvds_border_bits);
|
pipe_config->gmch_pfit.lvds_border_bits);
|
||||||
DRM_DEBUG_KMS("pch pfit: pos: 0x%08x, size: 0x%08x\n",
|
DRM_DEBUG_KMS("pch pfit: pos: 0x%08x, size: 0x%08x, %s\n",
|
||||||
pipe_config->pch_pfit.pos,
|
pipe_config->pch_pfit.pos,
|
||||||
pipe_config->pch_pfit.size);
|
pipe_config->pch_pfit.size,
|
||||||
|
pipe_config->pch_pfit.enabled ? "enabled" : "disabled");
|
||||||
DRM_DEBUG_KMS("ips: %i\n", pipe_config->ips_enabled);
|
DRM_DEBUG_KMS("ips: %i\n", pipe_config->ips_enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -8603,8 +8598,11 @@ intel_pipe_config_compare(struct drm_device *dev,
|
|||||||
if (INTEL_INFO(dev)->gen < 4)
|
if (INTEL_INFO(dev)->gen < 4)
|
||||||
PIPE_CONF_CHECK_I(gmch_pfit.pgm_ratios);
|
PIPE_CONF_CHECK_I(gmch_pfit.pgm_ratios);
|
||||||
PIPE_CONF_CHECK_I(gmch_pfit.lvds_border_bits);
|
PIPE_CONF_CHECK_I(gmch_pfit.lvds_border_bits);
|
||||||
PIPE_CONF_CHECK_I(pch_pfit.pos);
|
PIPE_CONF_CHECK_I(pch_pfit.enabled);
|
||||||
PIPE_CONF_CHECK_I(pch_pfit.size);
|
if (current_config->pch_pfit.enabled) {
|
||||||
|
PIPE_CONF_CHECK_I(pch_pfit.pos);
|
||||||
|
PIPE_CONF_CHECK_I(pch_pfit.size);
|
||||||
|
}
|
||||||
|
|
||||||
PIPE_CONF_CHECK_I(ips_enabled);
|
PIPE_CONF_CHECK_I(ips_enabled);
|
||||||
|
|
||||||
|
@@ -280,6 +280,7 @@ struct intel_crtc_config {
|
|||||||
struct {
|
struct {
|
||||||
u32 pos;
|
u32 pos;
|
||||||
u32 size;
|
u32 size;
|
||||||
|
bool enabled;
|
||||||
} pch_pfit;
|
} pch_pfit;
|
||||||
|
|
||||||
/* FDI configuration, only valid if has_pch_encoder is set. */
|
/* FDI configuration, only valid if has_pch_encoder is set. */
|
||||||
|
@@ -263,6 +263,8 @@ static bool intel_dvo_compute_config(struct intel_encoder *encoder,
|
|||||||
C(vtotal);
|
C(vtotal);
|
||||||
C(clock);
|
C(clock);
|
||||||
#undef C
|
#undef C
|
||||||
|
|
||||||
|
drm_mode_set_crtcinfo(adjusted_mode, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (intel_dvo->dev.dev_ops->mode_fixup)
|
if (intel_dvo->dev.dev_ops->mode_fixup)
|
||||||
|
@@ -112,6 +112,7 @@ intel_pch_panel_fitting(struct intel_crtc *intel_crtc,
|
|||||||
done:
|
done:
|
||||||
pipe_config->pch_pfit.pos = (x << 16) | y;
|
pipe_config->pch_pfit.pos = (x << 16) | y;
|
||||||
pipe_config->pch_pfit.size = (width << 16) | height;
|
pipe_config->pch_pfit.size = (width << 16) | height;
|
||||||
|
pipe_config->pch_pfit.enabled = pipe_config->pch_pfit.size != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@@ -2096,16 +2096,16 @@ static uint32_t ilk_pipe_pixel_rate(struct drm_device *dev,
|
|||||||
struct drm_crtc *crtc)
|
struct drm_crtc *crtc)
|
||||||
{
|
{
|
||||||
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
||||||
uint32_t pixel_rate, pfit_size;
|
uint32_t pixel_rate;
|
||||||
|
|
||||||
pixel_rate = intel_crtc->config.adjusted_mode.clock;
|
pixel_rate = intel_crtc->config.adjusted_mode.clock;
|
||||||
|
|
||||||
/* We only use IF-ID interlacing. If we ever use PF-ID we'll need to
|
/* We only use IF-ID interlacing. If we ever use PF-ID we'll need to
|
||||||
* adjust the pixel_rate here. */
|
* adjust the pixel_rate here. */
|
||||||
|
|
||||||
pfit_size = intel_crtc->config.pch_pfit.size;
|
if (intel_crtc->config.pch_pfit.enabled) {
|
||||||
if (pfit_size) {
|
|
||||||
uint64_t pipe_w, pipe_h, pfit_w, pfit_h;
|
uint64_t pipe_w, pipe_h, pfit_w, pfit_h;
|
||||||
|
uint32_t pfit_size = intel_crtc->config.pch_pfit.size;
|
||||||
|
|
||||||
pipe_w = intel_crtc->config.requested_mode.hdisplay;
|
pipe_w = intel_crtc->config.requested_mode.hdisplay;
|
||||||
pipe_h = intel_crtc->config.requested_mode.vdisplay;
|
pipe_h = intel_crtc->config.requested_mode.vdisplay;
|
||||||
|
@@ -788,6 +788,8 @@ static void intel_sdvo_get_dtd_from_mode(struct intel_sdvo_dtd *dtd,
|
|||||||
uint16_t h_sync_offset, v_sync_offset;
|
uint16_t h_sync_offset, v_sync_offset;
|
||||||
int mode_clock;
|
int mode_clock;
|
||||||
|
|
||||||
|
memset(dtd, 0, sizeof(*dtd));
|
||||||
|
|
||||||
width = mode->hdisplay;
|
width = mode->hdisplay;
|
||||||
height = mode->vdisplay;
|
height = mode->vdisplay;
|
||||||
|
|
||||||
@@ -830,44 +832,51 @@ static void intel_sdvo_get_dtd_from_mode(struct intel_sdvo_dtd *dtd,
|
|||||||
if (mode->flags & DRM_MODE_FLAG_PVSYNC)
|
if (mode->flags & DRM_MODE_FLAG_PVSYNC)
|
||||||
dtd->part2.dtd_flags |= DTD_FLAG_VSYNC_POSITIVE;
|
dtd->part2.dtd_flags |= DTD_FLAG_VSYNC_POSITIVE;
|
||||||
|
|
||||||
dtd->part2.sdvo_flags = 0;
|
|
||||||
dtd->part2.v_sync_off_high = v_sync_offset & 0xc0;
|
dtd->part2.v_sync_off_high = v_sync_offset & 0xc0;
|
||||||
dtd->part2.reserved = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void intel_sdvo_get_mode_from_dtd(struct drm_display_mode * mode,
|
static void intel_sdvo_get_mode_from_dtd(struct drm_display_mode *pmode,
|
||||||
const struct intel_sdvo_dtd *dtd)
|
const struct intel_sdvo_dtd *dtd)
|
||||||
{
|
{
|
||||||
mode->hdisplay = dtd->part1.h_active;
|
struct drm_display_mode mode = {};
|
||||||
mode->hdisplay += ((dtd->part1.h_high >> 4) & 0x0f) << 8;
|
|
||||||
mode->hsync_start = mode->hdisplay + dtd->part2.h_sync_off;
|
|
||||||
mode->hsync_start += (dtd->part2.sync_off_width_high & 0xc0) << 2;
|
|
||||||
mode->hsync_end = mode->hsync_start + dtd->part2.h_sync_width;
|
|
||||||
mode->hsync_end += (dtd->part2.sync_off_width_high & 0x30) << 4;
|
|
||||||
mode->htotal = mode->hdisplay + dtd->part1.h_blank;
|
|
||||||
mode->htotal += (dtd->part1.h_high & 0xf) << 8;
|
|
||||||
|
|
||||||
mode->vdisplay = dtd->part1.v_active;
|
mode.hdisplay = dtd->part1.h_active;
|
||||||
mode->vdisplay += ((dtd->part1.v_high >> 4) & 0x0f) << 8;
|
mode.hdisplay += ((dtd->part1.h_high >> 4) & 0x0f) << 8;
|
||||||
mode->vsync_start = mode->vdisplay;
|
mode.hsync_start = mode.hdisplay + dtd->part2.h_sync_off;
|
||||||
mode->vsync_start += (dtd->part2.v_sync_off_width >> 4) & 0xf;
|
mode.hsync_start += (dtd->part2.sync_off_width_high & 0xc0) << 2;
|
||||||
mode->vsync_start += (dtd->part2.sync_off_width_high & 0x0c) << 2;
|
mode.hsync_end = mode.hsync_start + dtd->part2.h_sync_width;
|
||||||
mode->vsync_start += dtd->part2.v_sync_off_high & 0xc0;
|
mode.hsync_end += (dtd->part2.sync_off_width_high & 0x30) << 4;
|
||||||
mode->vsync_end = mode->vsync_start +
|
mode.htotal = mode.hdisplay + dtd->part1.h_blank;
|
||||||
|
mode.htotal += (dtd->part1.h_high & 0xf) << 8;
|
||||||
|
|
||||||
|
mode.vdisplay = dtd->part1.v_active;
|
||||||
|
mode.vdisplay += ((dtd->part1.v_high >> 4) & 0x0f) << 8;
|
||||||
|
mode.vsync_start = mode.vdisplay;
|
||||||
|
mode.vsync_start += (dtd->part2.v_sync_off_width >> 4) & 0xf;
|
||||||
|
mode.vsync_start += (dtd->part2.sync_off_width_high & 0x0c) << 2;
|
||||||
|
mode.vsync_start += dtd->part2.v_sync_off_high & 0xc0;
|
||||||
|
mode.vsync_end = mode.vsync_start +
|
||||||
(dtd->part2.v_sync_off_width & 0xf);
|
(dtd->part2.v_sync_off_width & 0xf);
|
||||||
mode->vsync_end += (dtd->part2.sync_off_width_high & 0x3) << 4;
|
mode.vsync_end += (dtd->part2.sync_off_width_high & 0x3) << 4;
|
||||||
mode->vtotal = mode->vdisplay + dtd->part1.v_blank;
|
mode.vtotal = mode.vdisplay + dtd->part1.v_blank;
|
||||||
mode->vtotal += (dtd->part1.v_high & 0xf) << 8;
|
mode.vtotal += (dtd->part1.v_high & 0xf) << 8;
|
||||||
|
|
||||||
mode->clock = dtd->part1.clock * 10;
|
mode.clock = dtd->part1.clock * 10;
|
||||||
|
|
||||||
mode->flags &= ~(DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC);
|
|
||||||
if (dtd->part2.dtd_flags & DTD_FLAG_INTERLACE)
|
if (dtd->part2.dtd_flags & DTD_FLAG_INTERLACE)
|
||||||
mode->flags |= DRM_MODE_FLAG_INTERLACE;
|
mode.flags |= DRM_MODE_FLAG_INTERLACE;
|
||||||
if (dtd->part2.dtd_flags & DTD_FLAG_HSYNC_POSITIVE)
|
if (dtd->part2.dtd_flags & DTD_FLAG_HSYNC_POSITIVE)
|
||||||
mode->flags |= DRM_MODE_FLAG_PHSYNC;
|
mode.flags |= DRM_MODE_FLAG_PHSYNC;
|
||||||
|
else
|
||||||
|
mode.flags |= DRM_MODE_FLAG_NHSYNC;
|
||||||
if (dtd->part2.dtd_flags & DTD_FLAG_VSYNC_POSITIVE)
|
if (dtd->part2.dtd_flags & DTD_FLAG_VSYNC_POSITIVE)
|
||||||
mode->flags |= DRM_MODE_FLAG_PVSYNC;
|
mode.flags |= DRM_MODE_FLAG_PVSYNC;
|
||||||
|
else
|
||||||
|
mode.flags |= DRM_MODE_FLAG_NVSYNC;
|
||||||
|
|
||||||
|
drm_mode_set_crtcinfo(&mode, 0);
|
||||||
|
|
||||||
|
drm_mode_copy(pmode, &mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool intel_sdvo_check_supp_encode(struct intel_sdvo *intel_sdvo)
|
static bool intel_sdvo_check_supp_encode(struct intel_sdvo *intel_sdvo)
|
||||||
|
Reference in New Issue
Block a user