aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2012-12-10 03:53:43 -0500
committerBen Skeggs <bskeggs@redhat.com>2013-01-13 03:07:32 -0500
commit1a1841d300a1b6cac35b0761755364d6d3e10b2e (patch)
treedc791bacb66771e5d8fa5db60c8c44117a382ca2 /drivers/gpu
parent4459146deb9eeabb0adf10d829bd8019d16bb0f4 (diff)
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 <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_connector.c30
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_display.c9
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 ac340ba3201..e620ba8271b 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,
127 struct nouveau_encoder **pnv_encoder) 127 struct nouveau_encoder **pnv_encoder)
128{ 128{
129 struct drm_device *dev = connector->dev; 129 struct drm_device *dev = connector->dev;
130 struct nouveau_connector *nv_connector = nouveau_connector(connector);
130 struct nouveau_drm *drm = nouveau_drm(dev); 131 struct nouveau_drm *drm = nouveau_drm(dev);
132 struct nouveau_gpio *gpio = nouveau_gpio(drm->device);
131 struct nouveau_i2c *i2c = nouveau_i2c(drm->device); 133 struct nouveau_i2c *i2c = nouveau_i2c(drm->device);
132 int i; 134 struct nouveau_i2c_port *port = NULL;
135 int i, panel = -ENODEV;
136
137 /* eDP panels need powering on by us (if the VBIOS doesn't default it
138 * to on) before doing any AUX channel transactions. LVDS panel power
139 * is handled by the SOR itself, and not required for LVDS DDC.
140 */
141 if (nv_connector->type == DCB_CONNECTOR_eDP) {
142 panel = gpio->get(gpio, 0, DCB_GPIO_PANEL_POWER, 0xff);
143 if (panel == 0) {
144 gpio->set(gpio, 0, DCB_GPIO_PANEL_POWER, 0xff, 1);
145 msleep(300);
146 }
147 }
133 148
134 for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { 149 for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
135 struct nouveau_i2c_port *port = NULL;
136 struct nouveau_encoder *nv_encoder; 150 struct nouveau_encoder *nv_encoder;
137 struct drm_mode_object *obj; 151 struct drm_mode_object *obj;
138 int id; 152 int id;
@@ -150,11 +164,19 @@ nouveau_connector_ddc_detect(struct drm_connector *connector,
150 port = i2c->find(i2c, nv_encoder->dcb->i2c_index); 164 port = i2c->find(i2c, nv_encoder->dcb->i2c_index);
151 if (port && nv_probe_i2c(port, 0x50)) { 165 if (port && nv_probe_i2c(port, 0x50)) {
152 *pnv_encoder = nv_encoder; 166 *pnv_encoder = nv_encoder;
153 return port; 167 break;
154 } 168 }
169
170 port = NULL;
155 } 171 }
156 172
157 return NULL; 173 /* eDP panel not detected, restore panel power GPIO to previous
174 * state to avoid confusing the SOR for other output types.
175 */
176 if (!port && panel == 0)
177 gpio->set(gpio, 0, DCB_GPIO_PANEL_POWER, 0xff, panel);
178
179 return port;
158} 180}
159 181
160static struct nouveau_encoder * 182static struct nouveau_encoder *
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c
index e4188f24fc7..508b00a2ce0 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)
225 if (ret) 225 if (ret)
226 return ret; 226 return ret;
227 227
228 /* power on internal panel if it's not already. the init tables of
229 * some vbios default this to off for some reason, causing the
230 * panel to not work after resume
231 */
232 if (gpio && gpio->get(gpio, 0, DCB_GPIO_PANEL_POWER, 0xff) == 0) {
233 gpio->set(gpio, 0, DCB_GPIO_PANEL_POWER, 0xff, 1);
234 msleep(300);
235 }
236
237 /* enable polling for external displays */ 228 /* enable polling for external displays */
238 drm_kms_helper_poll_enable(dev); 229 drm_kms_helper_poll_enable(dev);
239 230