diff options
author | Ben Skeggs <bskeggs@redhat.com> | 2012-12-10 03:53:43 -0500 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2013-01-13 03:07:32 -0500 |
commit | 1a1841d300a1b6cac35b0761755364d6d3e10b2e (patch) | |
tree | dc791bacb66771e5d8fa5db60c8c44117a382ca2 /drivers/gpu | |
parent | 4459146deb9eeabb0adf10d829bd8019d16bb0f4 (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.c | 30 | ||||
-rw-r--r-- | 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 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 | ||
160 | static struct nouveau_encoder * | 182 | static 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 | ||