Commit 8e1f80c0 authored by Dave Airlie's avatar Dave Airlie

Merge tag 'drm-intel-fixes-2013-09-19' of...

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
parents c21eb21c f2f5f771
...@@ -1390,14 +1390,11 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) ...@@ -1390,14 +1390,11 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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 { ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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.hdisplay = dtd->part1.h_active;
mode->hsync_start += (dtd->part2.sync_off_width_high & 0xc0) << 2; mode.hdisplay += ((dtd->part1.h_high >> 4) & 0x0f) << 8;
mode->hsync_end = mode->hsync_start + dtd->part2.h_sync_width; mode.hsync_start = mode.hdisplay + dtd->part2.h_sync_off;
mode->hsync_end += (dtd->part2.sync_off_width_high & 0x30) << 4; mode.hsync_start += (dtd->part2.sync_off_width_high & 0xc0) << 2;
mode->htotal = mode->hdisplay + dtd->part1.h_blank; mode.hsync_end = mode.hsync_start + dtd->part2.h_sync_width;
mode->htotal += (dtd->part1.h_high & 0xf) << 8; mode.hsync_end += (dtd->part2.sync_off_width_high & 0x30) << 4;
mode.htotal = mode.hdisplay + dtd->part1.h_blank;
mode->vdisplay = dtd->part1.v_active; mode.htotal += (dtd->part1.h_high & 0xf) << 8;
mode->vdisplay += ((dtd->part1.v_high >> 4) & 0x0f) << 8;
mode->vsync_start = mode->vdisplay; mode.vdisplay = dtd->part1.v_active;
mode->vsync_start += (dtd->part2.v_sync_off_width >> 4) & 0xf; mode.vdisplay += ((dtd->part1.v_high >> 4) & 0x0f) << 8;
mode->vsync_start += (dtd->part2.sync_off_width_high & 0x0c) << 2; mode.vsync_start = mode.vdisplay;
mode->vsync_start += dtd->part2.v_sync_off_high & 0xc0; mode.vsync_start += (dtd->part2.v_sync_off_width >> 4) & 0xf;
mode->vsync_end = mode->vsync_start + 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)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment