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

Commit f6d52b21 authored by Ben Skeggs's avatar Ben Skeggs
Browse files

drm/nouveau/disp: move eDP panel power handling



We need to do this earlier to prevent aux channel timeouts in resume
paths on certain systems.

Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent 60655770
Loading
Loading
Loading
Loading
+1 −22
Original line number Diff line number Diff line
@@ -409,26 +409,11 @@ static struct nouveau_encoder *
nouveau_connector_ddc_detect(struct drm_connector *connector)
{
	struct drm_device *dev = connector->dev;
	struct nouveau_connector *nv_connector = nouveau_connector(connector);
	struct nouveau_drm *drm = nouveau_drm(dev);
	struct nvkm_gpio *gpio = nvxx_gpio(&drm->client.device);
	struct nouveau_encoder *nv_encoder = NULL, *found = NULL;
	struct drm_encoder *encoder;
	int i, ret, panel = -ENODEV;
	int i, ret;
	bool switcheroo_ddc = false;

	/* 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 = nvkm_gpio_get(gpio, 0, DCB_GPIO_PANEL_POWER, 0xff);
		if (panel == 0) {
			nvkm_gpio_set(gpio, 0, DCB_GPIO_PANEL_POWER, 0xff, 1);
			msleep(300);
		}
	}

	drm_connector_for_each_possible_encoder(connector, encoder, i) {
		nv_encoder = nouveau_encoder(encoder);

@@ -462,12 +447,6 @@ nouveau_connector_ddc_detect(struct drm_connector *connector)
			break;
	}

	/* eDP panel not detected, restore panel power GPIO to previous
	 * state to avoid confusing the SOR for other output types.
	 */
	if (!found && panel == 0)
		nvkm_gpio_set(gpio, 0, DCB_GPIO_PANEL_POWER, 0xff, panel);

	return found;
}

+34 −3
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@

#include <subdev/bios.h>
#include <subdev/bios/init.h>
#include <subdev/gpio.h>
#include <subdev/i2c.h>

#include <nvif/event.h>
@@ -491,7 +492,7 @@ nvkm_dp_acquire(struct nvkm_outp *outp)
	return ret;
}

static void
static bool
nvkm_dp_enable(struct nvkm_dp *dp, bool enable)
{
	struct nvkm_i2c_aux *aux = dp->aux;
@@ -505,7 +506,7 @@ nvkm_dp_enable(struct nvkm_dp *dp, bool enable)

		if (!nvkm_rdaux(aux, DPCD_RC00_DPCD_REV, dp->dpcd,
				sizeof(dp->dpcd)))
			return;
			return true;
	}

	if (dp->present) {
@@ -515,6 +516,7 @@ nvkm_dp_enable(struct nvkm_dp *dp, bool enable)
	}

	atomic_set(&dp->lt.done, 0);
	return false;
}

static int
@@ -555,9 +557,38 @@ nvkm_dp_fini(struct nvkm_outp *outp)
static void
nvkm_dp_init(struct nvkm_outp *outp)
{
	struct nvkm_gpio *gpio = outp->disp->engine.subdev.device->gpio;
	struct nvkm_dp *dp = nvkm_dp(outp);

	nvkm_notify_put(&dp->outp.conn->hpd);

	/* 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 (dp->outp.conn->info.type == DCB_CONNECTOR_eDP) {
		int power = nvkm_gpio_get(gpio, 0, DCB_GPIO_PANEL_POWER, 0xff);
		if (power == 0)
			nvkm_gpio_set(gpio, 0, DCB_GPIO_PANEL_POWER, 0xff, 1);

		/* We delay here unconditionally, even if already powered,
		 * because some laptop panels having a significant resume
		 * delay before the panel begins responding.
		 *
		 * This is likely a bit of a hack, but no better idea for
		 * handling this at the moment.
		 */
		msleep(300);

		/* If the eDP panel can't be detected, we need to restore
		 * the panel power GPIO to avoid breaking another output.
		 */
		if (!nvkm_dp_enable(dp, true) && power == 0)
			nvkm_gpio_set(gpio, 0, DCB_GPIO_PANEL_POWER, 0xff, 0);
	} else {
		nvkm_dp_enable(dp, true);
	}

	nvkm_notify_get(&dp->hpd);
}