Commit ec7fc4a1 authored by Ben Skeggs's avatar Ben Skeggs

drm/nv50: supply encoder disable() hook for SOR outputs

Allows us to remove a driver hack that used to be necessary to disable
encoders in certain situations before setting up a mode.  The DRM has
better knowledge of when this is needed than the driver does.

This fixes a number of display switching issues.
Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent df4cf1b7
...@@ -38,13 +38,15 @@ struct nouveau_encoder { ...@@ -38,13 +38,15 @@ struct nouveau_encoder {
struct dcb_entry *dcb; struct dcb_entry *dcb;
int or; int or;
/* different to drm_encoder.crtc, this reflects what's
* actually programmed on the hw, not the proposed crtc */
struct drm_crtc *crtc;
struct drm_display_mode mode; struct drm_display_mode mode;
int last_dpms; int last_dpms;
struct nv04_output_reg restore; struct nv04_output_reg restore;
void (*disconnect)(struct nouveau_encoder *encoder);
union { union {
struct { struct {
int mc_unknown; int mc_unknown;
......
...@@ -440,40 +440,9 @@ nv50_crtc_prepare(struct drm_crtc *crtc) ...@@ -440,40 +440,9 @@ nv50_crtc_prepare(struct drm_crtc *crtc)
{ {
struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
struct drm_device *dev = crtc->dev; struct drm_device *dev = crtc->dev;
struct drm_encoder *encoder;
uint32_t dac = 0, sor = 0;
NV_DEBUG_KMS(dev, "index %d\n", nv_crtc->index); NV_DEBUG_KMS(dev, "index %d\n", nv_crtc->index);
/* Disconnect all unused encoders. */
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
if (!drm_helper_encoder_in_use(encoder))
continue;
if (nv_encoder->dcb->type == OUTPUT_ANALOG ||
nv_encoder->dcb->type == OUTPUT_TV)
dac |= (1 << nv_encoder->or);
else
sor |= (1 << nv_encoder->or);
}
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
if (nv_encoder->dcb->type == OUTPUT_ANALOG ||
nv_encoder->dcb->type == OUTPUT_TV) {
if (dac & (1 << nv_encoder->or))
continue;
} else {
if (sor & (1 << nv_encoder->or))
continue;
}
nv_encoder->disconnect(nv_encoder);
}
nv50_crtc_blank(nv_crtc, true); nv50_crtc_blank(nv_crtc, true);
} }
......
...@@ -37,13 +37,17 @@ ...@@ -37,13 +37,17 @@
#include "nv50_display.h" #include "nv50_display.h"
static void static void
nv50_dac_disconnect(struct nouveau_encoder *nv_encoder) nv50_dac_disconnect(struct drm_encoder *encoder)
{ {
struct drm_device *dev = to_drm_encoder(nv_encoder)->dev; struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
struct drm_device *dev = encoder->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_channel *evo = dev_priv->evo; struct nouveau_channel *evo = dev_priv->evo;
int ret; int ret;
if (!nv_encoder->crtc)
return;
NV_DEBUG_KMS(dev, "Disconnecting DAC %d\n", nv_encoder->or); NV_DEBUG_KMS(dev, "Disconnecting DAC %d\n", nv_encoder->or);
ret = RING_SPACE(evo, 2); ret = RING_SPACE(evo, 2);
...@@ -53,6 +57,8 @@ nv50_dac_disconnect(struct nouveau_encoder *nv_encoder) ...@@ -53,6 +57,8 @@ nv50_dac_disconnect(struct nouveau_encoder *nv_encoder)
} }
BEGIN_RING(evo, 0, NV50_EVO_DAC(nv_encoder->or, MODE_CTRL), 1); BEGIN_RING(evo, 0, NV50_EVO_DAC(nv_encoder->or, MODE_CTRL), 1);
OUT_RING(evo, 0); OUT_RING(evo, 0);
nv_encoder->crtc = NULL;
} }
static enum drm_connector_status static enum drm_connector_status
...@@ -243,6 +249,8 @@ nv50_dac_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, ...@@ -243,6 +249,8 @@ nv50_dac_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
BEGIN_RING(evo, 0, NV50_EVO_DAC(nv_encoder->or, MODE_CTRL), 2); BEGIN_RING(evo, 0, NV50_EVO_DAC(nv_encoder->or, MODE_CTRL), 2);
OUT_RING(evo, mode_ctl); OUT_RING(evo, mode_ctl);
OUT_RING(evo, mode_ctl2); OUT_RING(evo, mode_ctl2);
nv_encoder->crtc = encoder->crtc;
} }
static const struct drm_encoder_helper_funcs nv50_dac_helper_funcs = { 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,7 +261,8 @@ static const struct drm_encoder_helper_funcs nv50_dac_helper_funcs = {
.prepare = nv50_dac_prepare, .prepare = nv50_dac_prepare,
.commit = nv50_dac_commit, .commit = nv50_dac_commit,
.mode_set = nv50_dac_mode_set, .mode_set = nv50_dac_mode_set,
.detect = nv50_dac_detect .detect = nv50_dac_detect,
.disable = nv50_dac_disconnect
}; };
static void static void
...@@ -288,8 +297,6 @@ nv50_dac_create(struct drm_connector *connector, struct dcb_entry *entry) ...@@ -288,8 +297,6 @@ nv50_dac_create(struct drm_connector *connector, struct dcb_entry *entry)
nv_encoder->dcb = entry; nv_encoder->dcb = entry;
nv_encoder->or = ffs(entry->or) - 1; nv_encoder->or = ffs(entry->or) - 1;
nv_encoder->disconnect = nv50_dac_disconnect;
drm_encoder_init(connector->dev, encoder, &nv50_dac_encoder_funcs, drm_encoder_init(connector->dev, encoder, &nv50_dac_encoder_funcs,
DRM_MODE_ENCODER_DAC); DRM_MODE_ENCODER_DAC);
drm_encoder_helper_add(encoder, &nv50_dac_helper_funcs); drm_encoder_helper_add(encoder, &nv50_dac_helper_funcs);
......
...@@ -37,13 +37,17 @@ ...@@ -37,13 +37,17 @@
#include "nv50_display.h" #include "nv50_display.h"
static void static void
nv50_sor_disconnect(struct nouveau_encoder *nv_encoder) nv50_sor_disconnect(struct drm_encoder *encoder)
{ {
struct drm_device *dev = to_drm_encoder(nv_encoder)->dev; struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
struct drm_device *dev = encoder->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_channel *evo = dev_priv->evo; struct nouveau_channel *evo = dev_priv->evo;
int ret; int ret;
if (!nv_encoder->crtc)
return;
NV_DEBUG_KMS(dev, "Disconnecting SOR %d\n", nv_encoder->or); NV_DEBUG_KMS(dev, "Disconnecting SOR %d\n", nv_encoder->or);
ret = RING_SPACE(evo, 2); ret = RING_SPACE(evo, 2);
...@@ -53,6 +57,9 @@ nv50_sor_disconnect(struct nouveau_encoder *nv_encoder) ...@@ -53,6 +57,9 @@ nv50_sor_disconnect(struct nouveau_encoder *nv_encoder)
} }
BEGIN_RING(evo, 0, NV50_EVO_SOR(nv_encoder->or, MODE_CTRL), 1); BEGIN_RING(evo, 0, NV50_EVO_SOR(nv_encoder->or, MODE_CTRL), 1);
OUT_RING(evo, 0); OUT_RING(evo, 0);
nv_encoder->crtc = NULL;
nv_encoder->last_dpms = DRM_MODE_DPMS_OFF;
} }
static void static void
...@@ -94,14 +101,16 @@ nv50_sor_dpms(struct drm_encoder *encoder, int mode) ...@@ -94,14 +101,16 @@ nv50_sor_dpms(struct drm_encoder *encoder, int mode)
uint32_t val; uint32_t val;
int or = nv_encoder->or; int or = nv_encoder->or;
NV_DEBUG_KMS(dev, "or %d mode %d\n", or, mode); NV_DEBUG_KMS(dev, "or %d type %d mode %d\n", or, nv_encoder->dcb->type, mode);
nv_encoder->last_dpms = mode; nv_encoder->last_dpms = mode;
list_for_each_entry(enc, &dev->mode_config.encoder_list, head) { list_for_each_entry(enc, &dev->mode_config.encoder_list, head) {
struct nouveau_encoder *nvenc = nouveau_encoder(enc); struct nouveau_encoder *nvenc = nouveau_encoder(enc);
if (nvenc == nv_encoder || if (nvenc == nv_encoder ||
nvenc->disconnect != nv50_sor_disconnect || (nvenc->dcb->type != OUTPUT_TMDS &&
nvenc->dcb->type != OUTPUT_LVDS &&
nvenc->dcb->type != OUTPUT_DP) ||
nvenc->dcb->or != nv_encoder->dcb->or) nvenc->dcb->or != nv_encoder->dcb->or)
continue; continue;
...@@ -239,6 +248,14 @@ nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, ...@@ -239,6 +248,14 @@ nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
} }
BEGIN_RING(evo, 0, NV50_EVO_SOR(nv_encoder->or, MODE_CTRL), 1); BEGIN_RING(evo, 0, NV50_EVO_SOR(nv_encoder->or, MODE_CTRL), 1);
OUT_RING(evo, mode_ctl); OUT_RING(evo, mode_ctl);
nv_encoder->crtc = encoder->crtc;
}
static struct drm_crtc *
nv50_sor_crtc_get(struct drm_encoder *encoder)
{
return nouveau_encoder(encoder)->crtc;
} }
static const struct drm_encoder_helper_funcs nv50_sor_helper_funcs = { 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,7 +266,9 @@ static const struct drm_encoder_helper_funcs nv50_sor_helper_funcs = {
.prepare = nv50_sor_prepare, .prepare = nv50_sor_prepare,
.commit = nv50_sor_commit, .commit = nv50_sor_commit,
.mode_set = nv50_sor_mode_set, .mode_set = nv50_sor_mode_set,
.detect = NULL .get_crtc = nv50_sor_crtc_get,
.detect = NULL,
.disable = nv50_sor_disconnect
}; };
static void static void
...@@ -300,8 +319,7 @@ nv50_sor_create(struct drm_connector *connector, struct dcb_entry *entry) ...@@ -300,8 +319,7 @@ nv50_sor_create(struct drm_connector *connector, struct dcb_entry *entry)
nv_encoder->dcb = entry; nv_encoder->dcb = entry;
nv_encoder->or = ffs(entry->or) - 1; nv_encoder->or = ffs(entry->or) - 1;
nv_encoder->last_dpms = DRM_MODE_DPMS_OFF;
nv_encoder->disconnect = nv50_sor_disconnect;
drm_encoder_init(dev, encoder, &nv50_sor_encoder_funcs, type); drm_encoder_init(dev, encoder, &nv50_sor_encoder_funcs, type);
drm_encoder_helper_add(encoder, &nv50_sor_helper_funcs); drm_encoder_helper_add(encoder, &nv50_sor_helper_funcs);
......
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