mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-23 04:34:11 +08:00
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: Ben Skeggs <bskeggs@redhat.com>
This commit is contained in:
parent
df4cf1b72d
commit
ec7fc4a1a7
@ -38,13 +38,15 @@ struct nouveau_encoder {
|
||||
struct dcb_entry *dcb;
|
||||
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;
|
||||
int last_dpms;
|
||||
|
||||
struct nv04_output_reg restore;
|
||||
|
||||
void (*disconnect)(struct nouveau_encoder *encoder);
|
||||
|
||||
union {
|
||||
struct {
|
||||
int mc_unknown;
|
||||
|
@ -440,40 +440,9 @@ nv50_crtc_prepare(struct drm_crtc *crtc)
|
||||
{
|
||||
struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
|
||||
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);
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
|
@ -37,13 +37,17 @@
|
||||
#include "nv50_display.h"
|
||||
|
||||
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 nouveau_channel *evo = dev_priv->evo;
|
||||
int ret;
|
||||
|
||||
if (!nv_encoder->crtc)
|
||||
return;
|
||||
|
||||
NV_DEBUG_KMS(dev, "Disconnecting DAC %d\n", nv_encoder->or);
|
||||
|
||||
ret = RING_SPACE(evo, 2);
|
||||
@ -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);
|
||||
OUT_RING(evo, 0);
|
||||
|
||||
nv_encoder->crtc = NULL;
|
||||
}
|
||||
|
||||
static enum drm_connector_status
|
||||
@ -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);
|
||||
OUT_RING(evo, mode_ctl);
|
||||
OUT_RING(evo, mode_ctl2);
|
||||
|
||||
nv_encoder->crtc = encoder->crtc;
|
||||
}
|
||||
|
||||
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,
|
||||
.commit = nv50_dac_commit,
|
||||
.mode_set = nv50_dac_mode_set,
|
||||
.detect = nv50_dac_detect
|
||||
.detect = nv50_dac_detect,
|
||||
.disable = nv50_dac_disconnect
|
||||
};
|
||||
|
||||
static void
|
||||
@ -288,8 +297,6 @@ nv50_dac_create(struct drm_connector *connector, struct dcb_entry *entry)
|
||||
nv_encoder->dcb = entry;
|
||||
nv_encoder->or = ffs(entry->or) - 1;
|
||||
|
||||
nv_encoder->disconnect = nv50_dac_disconnect;
|
||||
|
||||
drm_encoder_init(connector->dev, encoder, &nv50_dac_encoder_funcs,
|
||||
DRM_MODE_ENCODER_DAC);
|
||||
drm_encoder_helper_add(encoder, &nv50_dac_helper_funcs);
|
||||
|
@ -37,13 +37,17 @@
|
||||
#include "nv50_display.h"
|
||||
|
||||
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 nouveau_channel *evo = dev_priv->evo;
|
||||
int ret;
|
||||
|
||||
if (!nv_encoder->crtc)
|
||||
return;
|
||||
|
||||
NV_DEBUG_KMS(dev, "Disconnecting SOR %d\n", nv_encoder->or);
|
||||
|
||||
ret = RING_SPACE(evo, 2);
|
||||
@ -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);
|
||||
OUT_RING(evo, 0);
|
||||
|
||||
nv_encoder->crtc = NULL;
|
||||
nv_encoder->last_dpms = DRM_MODE_DPMS_OFF;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -94,14 +101,16 @@ nv50_sor_dpms(struct drm_encoder *encoder, int mode)
|
||||
uint32_t val;
|
||||
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;
|
||||
list_for_each_entry(enc, &dev->mode_config.encoder_list, head) {
|
||||
struct nouveau_encoder *nvenc = nouveau_encoder(enc);
|
||||
|
||||
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)
|
||||
continue;
|
||||
|
||||
@ -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);
|
||||
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 = {
|
||||
@ -249,7 +266,9 @@ static const struct drm_encoder_helper_funcs nv50_sor_helper_funcs = {
|
||||
.prepare = nv50_sor_prepare,
|
||||
.commit = nv50_sor_commit,
|
||||
.mode_set = nv50_sor_mode_set,
|
||||
.detect = NULL
|
||||
.get_crtc = nv50_sor_crtc_get,
|
||||
.detect = NULL,
|
||||
.disable = nv50_sor_disconnect
|
||||
};
|
||||
|
||||
static void
|
||||
@ -300,8 +319,7 @@ nv50_sor_create(struct drm_connector *connector, struct dcb_entry *entry)
|
||||
|
||||
nv_encoder->dcb = entry;
|
||||
nv_encoder->or = ffs(entry->or) - 1;
|
||||
|
||||
nv_encoder->disconnect = nv50_sor_disconnect;
|
||||
nv_encoder->last_dpms = DRM_MODE_DPMS_OFF;
|
||||
|
||||
drm_encoder_init(dev, encoder, &nv50_sor_encoder_funcs, type);
|
||||
drm_encoder_helper_add(encoder, &nv50_sor_helper_funcs);
|
||||
|
Loading…
Reference in New Issue
Block a user