diff options
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_encoder.h | 6 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nv50_crtc.c | 31 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nv50_dac.c | 17 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nv50_sor.c | 32 |
4 files changed, 41 insertions, 45 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_encoder.h b/drivers/gpu/drm/nouveau/nouveau_encoder.h index e4442e28b568..a1a0d48ae70c 100644 --- a/drivers/gpu/drm/nouveau/nouveau_encoder.h +++ b/drivers/gpu/drm/nouveau/nouveau_encoder.h | |||
@@ -38,13 +38,15 @@ struct nouveau_encoder { | |||
38 | struct dcb_entry *dcb; | 38 | struct dcb_entry *dcb; |
39 | int or; | 39 | int or; |
40 | 40 | ||
41 | /* different to drm_encoder.crtc, this reflects what's | ||
42 | * actually programmed on the hw, not the proposed crtc */ | ||
43 | struct drm_crtc *crtc; | ||
44 | |||
41 | struct drm_display_mode mode; | 45 | struct drm_display_mode mode; |
42 | int last_dpms; | 46 | int last_dpms; |
43 | 47 | ||
44 | struct nv04_output_reg restore; | 48 | struct nv04_output_reg restore; |
45 | 49 | ||
46 | void (*disconnect)(struct nouveau_encoder *encoder); | ||
47 | |||
48 | union { | 50 | union { |
49 | struct { | 51 | struct { |
50 | int mc_unknown; | 52 | int mc_unknown; |
diff --git a/drivers/gpu/drm/nouveau/nv50_crtc.c b/drivers/gpu/drm/nouveau/nv50_crtc.c index b4e4a3b05eae..fb3ed5d80aa6 100644 --- a/drivers/gpu/drm/nouveau/nv50_crtc.c +++ b/drivers/gpu/drm/nouveau/nv50_crtc.c | |||
@@ -440,40 +440,9 @@ nv50_crtc_prepare(struct drm_crtc *crtc) | |||
440 | { | 440 | { |
441 | struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); | 441 | struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); |
442 | struct drm_device *dev = crtc->dev; | 442 | struct drm_device *dev = crtc->dev; |
443 | struct drm_encoder *encoder; | ||
444 | uint32_t dac = 0, sor = 0; | ||
445 | 443 | ||
446 | NV_DEBUG_KMS(dev, "index %d\n", nv_crtc->index); | 444 | NV_DEBUG_KMS(dev, "index %d\n", nv_crtc->index); |
447 | 445 | ||
448 | /* Disconnect all unused encoders. */ | ||
449 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { | ||
450 | struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); | ||
451 | |||
452 | if (!drm_helper_encoder_in_use(encoder)) | ||
453 | continue; | ||
454 | |||
455 | if (nv_encoder->dcb->type == OUTPUT_ANALOG || | ||
456 | nv_encoder->dcb->type == OUTPUT_TV) | ||
457 | dac |= (1 << nv_encoder->or); | ||
458 | else | ||
459 | sor |= (1 << nv_encoder->or); | ||
460 | } | ||
461 | |||
462 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { | ||
463 | struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); | ||
464 | |||
465 | if (nv_encoder->dcb->type == OUTPUT_ANALOG || | ||
466 | nv_encoder->dcb->type == OUTPUT_TV) { | ||
467 | if (dac & (1 << nv_encoder->or)) | ||
468 | continue; | ||
469 | } else { | ||
470 | if (sor & (1 << nv_encoder->or)) | ||
471 | continue; | ||
472 | } | ||
473 | |||
474 | nv_encoder->disconnect(nv_encoder); | ||
475 | } | ||
476 | |||
477 | nv50_crtc_blank(nv_crtc, true); | 446 | nv50_crtc_blank(nv_crtc, true); |
478 | } | 447 | } |
479 | 448 | ||
diff --git a/drivers/gpu/drm/nouveau/nv50_dac.c b/drivers/gpu/drm/nouveau/nv50_dac.c index e114f818751d..f5fd35a657c3 100644 --- a/drivers/gpu/drm/nouveau/nv50_dac.c +++ b/drivers/gpu/drm/nouveau/nv50_dac.c | |||
@@ -37,13 +37,17 @@ | |||
37 | #include "nv50_display.h" | 37 | #include "nv50_display.h" |
38 | 38 | ||
39 | static void | 39 | static void |
40 | nv50_dac_disconnect(struct nouveau_encoder *nv_encoder) | 40 | nv50_dac_disconnect(struct drm_encoder *encoder) |
41 | { | 41 | { |
42 | struct drm_device *dev = to_drm_encoder(nv_encoder)->dev; | 42 | struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); |
43 | struct drm_device *dev = encoder->dev; | ||
43 | struct drm_nouveau_private *dev_priv = dev->dev_private; | 44 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
44 | struct nouveau_channel *evo = dev_priv->evo; | 45 | struct nouveau_channel *evo = dev_priv->evo; |
45 | int ret; | 46 | int ret; |
46 | 47 | ||
48 | if (!nv_encoder->crtc) | ||
49 | return; | ||
50 | |||
47 | NV_DEBUG_KMS(dev, "Disconnecting DAC %d\n", nv_encoder->or); | 51 | NV_DEBUG_KMS(dev, "Disconnecting DAC %d\n", nv_encoder->or); |
48 | 52 | ||
49 | ret = RING_SPACE(evo, 2); | 53 | ret = RING_SPACE(evo, 2); |
@@ -53,6 +57,8 @@ nv50_dac_disconnect(struct nouveau_encoder *nv_encoder) | |||
53 | } | 57 | } |
54 | BEGIN_RING(evo, 0, NV50_EVO_DAC(nv_encoder->or, MODE_CTRL), 1); | 58 | BEGIN_RING(evo, 0, NV50_EVO_DAC(nv_encoder->or, MODE_CTRL), 1); |
55 | OUT_RING(evo, 0); | 59 | OUT_RING(evo, 0); |
60 | |||
61 | nv_encoder->crtc = NULL; | ||
56 | } | 62 | } |
57 | 63 | ||
58 | static enum drm_connector_status | 64 | static enum drm_connector_status |
@@ -243,6 +249,8 @@ nv50_dac_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, | |||
243 | BEGIN_RING(evo, 0, NV50_EVO_DAC(nv_encoder->or, MODE_CTRL), 2); | 249 | BEGIN_RING(evo, 0, NV50_EVO_DAC(nv_encoder->or, MODE_CTRL), 2); |
244 | OUT_RING(evo, mode_ctl); | 250 | OUT_RING(evo, mode_ctl); |
245 | OUT_RING(evo, mode_ctl2); | 251 | OUT_RING(evo, mode_ctl2); |
252 | |||
253 | nv_encoder->crtc = encoder->crtc; | ||
246 | } | 254 | } |
247 | 255 | ||
248 | static const struct drm_encoder_helper_funcs nv50_dac_helper_funcs = { | 256 | static const struct drm_encoder_helper_funcs nv50_dac_helper_funcs = { |
@@ -253,7 +261,8 @@ static const struct drm_encoder_helper_funcs nv50_dac_helper_funcs = { | |||
253 | .prepare = nv50_dac_prepare, | 261 | .prepare = nv50_dac_prepare, |
254 | .commit = nv50_dac_commit, | 262 | .commit = nv50_dac_commit, |
255 | .mode_set = nv50_dac_mode_set, | 263 | .mode_set = nv50_dac_mode_set, |
256 | .detect = nv50_dac_detect | 264 | .detect = nv50_dac_detect, |
265 | .disable = nv50_dac_disconnect | ||
257 | }; | 266 | }; |
258 | 267 | ||
259 | static void | 268 | static void |
@@ -288,8 +297,6 @@ nv50_dac_create(struct drm_connector *connector, struct dcb_entry *entry) | |||
288 | nv_encoder->dcb = entry; | 297 | nv_encoder->dcb = entry; |
289 | nv_encoder->or = ffs(entry->or) - 1; | 298 | nv_encoder->or = ffs(entry->or) - 1; |
290 | 299 | ||
291 | nv_encoder->disconnect = nv50_dac_disconnect; | ||
292 | |||
293 | drm_encoder_init(connector->dev, encoder, &nv50_dac_encoder_funcs, | 300 | drm_encoder_init(connector->dev, encoder, &nv50_dac_encoder_funcs, |
294 | DRM_MODE_ENCODER_DAC); | 301 | DRM_MODE_ENCODER_DAC); |
295 | drm_encoder_helper_add(encoder, &nv50_dac_helper_funcs); | 302 | drm_encoder_helper_add(encoder, &nv50_dac_helper_funcs); |
diff --git a/drivers/gpu/drm/nouveau/nv50_sor.c b/drivers/gpu/drm/nouveau/nv50_sor.c index 4832bba7c43a..b259d63202eb 100644 --- a/drivers/gpu/drm/nouveau/nv50_sor.c +++ b/drivers/gpu/drm/nouveau/nv50_sor.c | |||
@@ -37,13 +37,17 @@ | |||
37 | #include "nv50_display.h" | 37 | #include "nv50_display.h" |
38 | 38 | ||
39 | static void | 39 | static void |
40 | nv50_sor_disconnect(struct nouveau_encoder *nv_encoder) | 40 | nv50_sor_disconnect(struct drm_encoder *encoder) |
41 | { | 41 | { |
42 | struct drm_device *dev = to_drm_encoder(nv_encoder)->dev; | 42 | struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); |
43 | struct drm_device *dev = encoder->dev; | ||
43 | struct drm_nouveau_private *dev_priv = dev->dev_private; | 44 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
44 | struct nouveau_channel *evo = dev_priv->evo; | 45 | struct nouveau_channel *evo = dev_priv->evo; |
45 | int ret; | 46 | int ret; |
46 | 47 | ||
48 | if (!nv_encoder->crtc) | ||
49 | return; | ||
50 | |||
47 | NV_DEBUG_KMS(dev, "Disconnecting SOR %d\n", nv_encoder->or); | 51 | NV_DEBUG_KMS(dev, "Disconnecting SOR %d\n", nv_encoder->or); |
48 | 52 | ||
49 | ret = RING_SPACE(evo, 2); | 53 | ret = RING_SPACE(evo, 2); |
@@ -53,6 +57,9 @@ nv50_sor_disconnect(struct nouveau_encoder *nv_encoder) | |||
53 | } | 57 | } |
54 | BEGIN_RING(evo, 0, NV50_EVO_SOR(nv_encoder->or, MODE_CTRL), 1); | 58 | BEGIN_RING(evo, 0, NV50_EVO_SOR(nv_encoder->or, MODE_CTRL), 1); |
55 | OUT_RING(evo, 0); | 59 | OUT_RING(evo, 0); |
60 | |||
61 | nv_encoder->crtc = NULL; | ||
62 | nv_encoder->last_dpms = DRM_MODE_DPMS_OFF; | ||
56 | } | 63 | } |
57 | 64 | ||
58 | static void | 65 | static void |
@@ -94,14 +101,16 @@ nv50_sor_dpms(struct drm_encoder *encoder, int mode) | |||
94 | uint32_t val; | 101 | uint32_t val; |
95 | int or = nv_encoder->or; | 102 | int or = nv_encoder->or; |
96 | 103 | ||
97 | NV_DEBUG_KMS(dev, "or %d mode %d\n", or, mode); | 104 | NV_DEBUG_KMS(dev, "or %d type %d mode %d\n", or, nv_encoder->dcb->type, mode); |
98 | 105 | ||
99 | nv_encoder->last_dpms = mode; | 106 | nv_encoder->last_dpms = mode; |
100 | list_for_each_entry(enc, &dev->mode_config.encoder_list, head) { | 107 | list_for_each_entry(enc, &dev->mode_config.encoder_list, head) { |
101 | struct nouveau_encoder *nvenc = nouveau_encoder(enc); | 108 | struct nouveau_encoder *nvenc = nouveau_encoder(enc); |
102 | 109 | ||
103 | if (nvenc == nv_encoder || | 110 | if (nvenc == nv_encoder || |
104 | nvenc->disconnect != nv50_sor_disconnect || | 111 | (nvenc->dcb->type != OUTPUT_TMDS && |
112 | nvenc->dcb->type != OUTPUT_LVDS && | ||
113 | nvenc->dcb->type != OUTPUT_DP) || | ||
105 | nvenc->dcb->or != nv_encoder->dcb->or) | 114 | nvenc->dcb->or != nv_encoder->dcb->or) |
106 | continue; | 115 | continue; |
107 | 116 | ||
@@ -239,6 +248,14 @@ nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, | |||
239 | } | 248 | } |
240 | BEGIN_RING(evo, 0, NV50_EVO_SOR(nv_encoder->or, MODE_CTRL), 1); | 249 | BEGIN_RING(evo, 0, NV50_EVO_SOR(nv_encoder->or, MODE_CTRL), 1); |
241 | OUT_RING(evo, mode_ctl); | 250 | OUT_RING(evo, mode_ctl); |
251 | |||
252 | nv_encoder->crtc = encoder->crtc; | ||
253 | } | ||
254 | |||
255 | static struct drm_crtc * | ||
256 | nv50_sor_crtc_get(struct drm_encoder *encoder) | ||
257 | { | ||
258 | return nouveau_encoder(encoder)->crtc; | ||
242 | } | 259 | } |
243 | 260 | ||
244 | static const struct drm_encoder_helper_funcs nv50_sor_helper_funcs = { | 261 | static const struct drm_encoder_helper_funcs nv50_sor_helper_funcs = { |
@@ -249,7 +266,9 @@ static const struct drm_encoder_helper_funcs nv50_sor_helper_funcs = { | |||
249 | .prepare = nv50_sor_prepare, | 266 | .prepare = nv50_sor_prepare, |
250 | .commit = nv50_sor_commit, | 267 | .commit = nv50_sor_commit, |
251 | .mode_set = nv50_sor_mode_set, | 268 | .mode_set = nv50_sor_mode_set, |
252 | .detect = NULL | 269 | .get_crtc = nv50_sor_crtc_get, |
270 | .detect = NULL, | ||
271 | .disable = nv50_sor_disconnect | ||
253 | }; | 272 | }; |
254 | 273 | ||
255 | static void | 274 | static void |
@@ -300,8 +319,7 @@ nv50_sor_create(struct drm_connector *connector, struct dcb_entry *entry) | |||
300 | 319 | ||
301 | nv_encoder->dcb = entry; | 320 | nv_encoder->dcb = entry; |
302 | nv_encoder->or = ffs(entry->or) - 1; | 321 | nv_encoder->or = ffs(entry->or) - 1; |
303 | 322 | nv_encoder->last_dpms = DRM_MODE_DPMS_OFF; | |
304 | nv_encoder->disconnect = nv50_sor_disconnect; | ||
305 | 323 | ||
306 | drm_encoder_init(dev, encoder, &nv50_sor_encoder_funcs, type); | 324 | drm_encoder_init(dev, encoder, &nv50_sor_encoder_funcs, type); |
307 | drm_encoder_helper_add(encoder, &nv50_sor_helper_funcs); | 325 | drm_encoder_helper_add(encoder, &nv50_sor_helper_funcs); |