From 1a1841d300a1b6cac35b0761755364d6d3e10b2e Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 10 Dec 2012 18:53:43 +1000 Subject: [PATCH] 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: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_connector.c | 30 +++++++++++++++++++++++++---- drivers/gpu/drm/nouveau/nouveau_display.c | 9 --------- 2 files changed, 26 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index ac340ba..e620ba8 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -127,12 +127,26 @@ nouveau_connector_ddc_detect(struct drm_connector *connector, struct nouveau_encoder **pnv_encoder) { struct drm_device *dev = connector->dev; + struct nouveau_connector *nv_connector = nouveau_connector(connector); struct nouveau_drm *drm = nouveau_drm(dev); + struct nouveau_gpio *gpio = nouveau_gpio(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++) { - struct nouveau_i2c_port *port = NULL; struct nouveau_encoder *nv_encoder; struct drm_mode_object *obj; int id; @@ -150,11 +164,19 @@ nouveau_connector_ddc_detect(struct drm_connector *connector, port = i2c->find(i2c, nv_encoder->dcb->i2c_index); if (port && nv_probe_i2c(port, 0x50)) { *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 * diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index e4188f2..508b00a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -225,15 +225,6 @@ nouveau_display_init(struct drm_device *dev) if (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 */ drm_kms_helper_poll_enable(dev); -- 2.7.4