Commit 1a1841d3 authored by Ben Skeggs's avatar Ben Skeggs

drm/nouveau: do not forcibly power on lvds panels

This fix was put in place to fix a bug where the eDP panel on certain
laptops fails to respond over the aux channel after suspend.

It appears that on some systems (Dell M6600, with LVDS panel) there's a
very bad interaction with the eDP init table that causes the SOR to get
very confused and not drive the panel correctly, leading to bleed.

A DPMS off/on cycle is enough to bring it back, but, this will avoid the
problem by not touching the panel GPIOs at times we're not meant to.
Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent 4459146d
...@@ -127,12 +127,26 @@ nouveau_connector_ddc_detect(struct drm_connector *connector, ...@@ -127,12 +127,26 @@ nouveau_connector_ddc_detect(struct drm_connector *connector,
struct nouveau_encoder **pnv_encoder) struct nouveau_encoder **pnv_encoder)
{ {
struct drm_device *dev = connector->dev; struct drm_device *dev = connector->dev;
struct nouveau_connector *nv_connector = nouveau_connector(connector);
struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_drm *drm = nouveau_drm(dev);
struct nouveau_gpio *gpio = nouveau_gpio(drm->device);
struct nouveau_i2c *i2c = nouveau_i2c(drm->device); struct nouveau_i2c *i2c = nouveau_i2c(drm->device);
int i; struct nouveau_i2c_port *port = NULL;
int i, panel = -ENODEV;
/* eDP panels need powering on by us (if the VBIOS doesn't default it
* to on) before doing any AUX channel transactions. LVDS panel power
* is handled by the SOR itself, and not required for LVDS DDC.
*/
if (nv_connector->type == DCB_CONNECTOR_eDP) {
panel = gpio->get(gpio, 0, DCB_GPIO_PANEL_POWER, 0xff);
if (panel == 0) {
gpio->set(gpio, 0, DCB_GPIO_PANEL_POWER, 0xff, 1);
msleep(300);
}
}
for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
struct nouveau_i2c_port *port = NULL;
struct nouveau_encoder *nv_encoder; struct nouveau_encoder *nv_encoder;
struct drm_mode_object *obj; struct drm_mode_object *obj;
int id; int id;
...@@ -150,11 +164,19 @@ nouveau_connector_ddc_detect(struct drm_connector *connector, ...@@ -150,11 +164,19 @@ nouveau_connector_ddc_detect(struct drm_connector *connector,
port = i2c->find(i2c, nv_encoder->dcb->i2c_index); port = i2c->find(i2c, nv_encoder->dcb->i2c_index);
if (port && nv_probe_i2c(port, 0x50)) { if (port && nv_probe_i2c(port, 0x50)) {
*pnv_encoder = nv_encoder; *pnv_encoder = nv_encoder;
return port; break;
} }
port = NULL;
} }
return NULL; /* eDP panel not detected, restore panel power GPIO to previous
* state to avoid confusing the SOR for other output types.
*/
if (!port && panel == 0)
gpio->set(gpio, 0, DCB_GPIO_PANEL_POWER, 0xff, panel);
return port;
} }
static struct nouveau_encoder * static struct nouveau_encoder *
......
...@@ -225,15 +225,6 @@ nouveau_display_init(struct drm_device *dev) ...@@ -225,15 +225,6 @@ nouveau_display_init(struct drm_device *dev)
if (ret) if (ret)
return ret; return ret;
/* power on internal panel if it's not already. the init tables of
* some vbios default this to off for some reason, causing the
* panel to not work after resume
*/
if (gpio && gpio->get(gpio, 0, DCB_GPIO_PANEL_POWER, 0xff) == 0) {
gpio->set(gpio, 0, DCB_GPIO_PANEL_POWER, 0xff, 1);
msleep(300);
}
/* enable polling for external displays */ /* enable polling for external displays */
drm_kms_helper_poll_enable(dev); drm_kms_helper_poll_enable(dev);
......
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