Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+26 −4
Original line number Diff line number Diff line
@@ -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 *
+0 −9
Original line number Diff line number Diff line
@@ -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);