mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-23 12:43:55 +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;
|
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)
|
|||||||
{
|
{
|
||||||
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 @@
|
|||||||
#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)
|
|||||||
}
|
}
|
||||||
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,
|
|||||||
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 = {
|
|||||||
.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)
|
|||||||
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 @@
|
|||||||
#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)
|
|||||||
}
|
}
|
||||||
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)
|
|||||||
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,
|
|||||||
}
|
}
|
||||||
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 = {
|
|||||||
.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)
|
|||||||
|
|
||||||
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);
|
||||||
|
Loading…
Reference in New Issue
Block a user