summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/nouveau/nv50_display.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/nouveau/nv50_display.c')
-rw-r--r--drivers/gpu/drm/nouveau/nv50_display.c38
1 files changed, 27 insertions, 11 deletions
diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c
index 6dee4071bb3f..f7b4326a4641 100644
--- a/drivers/gpu/drm/nouveau/nv50_display.c
+++ b/drivers/gpu/drm/nouveau/nv50_display.c
@@ -3658,15 +3658,24 @@ nv50_sor_create(struct drm_connector *connector, struct dcb_output *dcbe)
drm_mode_connector_attach_encoder(connector, encoder);
if (dcbe->type == DCB_OUTPUT_DP) {
+ struct nv50_disp *disp = nv50_disp(encoder->dev);
struct nvkm_i2c_aux *aux =
nvkm_i2c_aux_find(i2c, dcbe->i2c_index);
if (aux) {
- nv_encoder->i2c = &nv_connector->aux.ddc;
+ if (disp->disp->oclass < GF110_DISP) {
+ /* HW has no support for address-only
+ * transactions, so we're required to
+ * use custom I2C-over-AUX code.
+ */
+ nv_encoder->i2c = &aux->i2c;
+ } else {
+ nv_encoder->i2c = &nv_connector->aux.ddc;
+ }
nv_encoder->aux = aux;
}
/*TODO: Use DP Info Table to check for support. */
- if (nv50_disp(encoder->dev)->disp->oclass >= GF110_DISP) {
+ if (disp->disp->oclass >= GF110_DISP) {
ret = nv50_mstm_new(nv_encoder, &nv_connector->aux, 16,
nv_connector->base.base.id,
&nv_encoder->dp.mstm);
@@ -3888,7 +3897,7 @@ static void
nv50_disp_atomic_commit_tail(struct drm_atomic_state *state)
{
struct drm_device *dev = state->dev;
- struct drm_crtc_state *new_crtc_state;
+ struct drm_crtc_state *new_crtc_state, *old_crtc_state;
struct drm_crtc *crtc;
struct drm_plane_state *new_plane_state;
struct drm_plane *plane;
@@ -3909,12 +3918,14 @@ nv50_disp_atomic_commit_tail(struct drm_atomic_state *state)
mutex_lock(&disp->mutex);
/* Disable head(s). */
- for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
+ for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
struct nv50_head_atom *asyh = nv50_head_atom(new_crtc_state);
struct nv50_head *head = nv50_head(crtc);
NV_ATOMIC(drm, "%s: clr %04x (set %04x)\n", crtc->name,
asyh->clr.mask, asyh->set.mask);
+ if (old_crtc_state->active && !new_crtc_state->active)
+ drm_crtc_vblank_off(crtc);
if (asyh->clr.mask) {
nv50_head_flush_clr(head, asyh, atom->flush_disable);
@@ -3989,7 +4000,7 @@ nv50_disp_atomic_commit_tail(struct drm_atomic_state *state)
}
/* Update head(s). */
- for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
+ for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
struct nv50_head_atom *asyh = nv50_head_atom(new_crtc_state);
struct nv50_head *head = nv50_head(crtc);
@@ -4000,11 +4011,13 @@ nv50_disp_atomic_commit_tail(struct drm_atomic_state *state)
nv50_head_flush_set(head, asyh);
interlock_core = 1;
}
- }
- for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
- if (new_crtc_state->event)
- drm_crtc_vblank_get(crtc);
+ if (new_crtc_state->active) {
+ if (!old_crtc_state->active)
+ drm_crtc_vblank_on(crtc);
+ if (new_crtc_state->event)
+ drm_crtc_vblank_get(crtc);
+ }
}
/* Update plane(s). */
@@ -4051,12 +4064,15 @@ nv50_disp_atomic_commit_tail(struct drm_atomic_state *state)
if (new_crtc_state->event) {
unsigned long flags;
/* Get correct count/ts if racing with vblank irq */
- drm_crtc_accurate_vblank_count(crtc);
+ if (new_crtc_state->active)
+ drm_crtc_accurate_vblank_count(crtc);
spin_lock_irqsave(&crtc->dev->event_lock, flags);
drm_crtc_send_vblank_event(crtc, new_crtc_state->event);
spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
+
new_crtc_state->event = NULL;
- drm_crtc_vblank_put(crtc);
+ if (new_crtc_state->active)
+ drm_crtc_vblank_put(crtc);
}
}
OpenPOWER on IntegriCloud