Commit f6d52b21 authored by Ben Skeggs's avatar Ben Skeggs

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
...@@ -409,26 +409,11 @@ static struct nouveau_encoder * ...@@ -409,26 +409,11 @@ static struct nouveau_encoder *
nouveau_connector_ddc_detect(struct drm_connector *connector) nouveau_connector_ddc_detect(struct drm_connector *connector)
{ {
struct drm_device *dev = connector->dev; 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 nouveau_encoder *nv_encoder = NULL, *found = NULL;
struct drm_encoder *encoder; struct drm_encoder *encoder;
int i, ret, panel = -ENODEV; int i, ret;
bool switcheroo_ddc = false; 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) { drm_connector_for_each_possible_encoder(connector, encoder, i) {
nv_encoder = nouveau_encoder(encoder); nv_encoder = nouveau_encoder(encoder);
...@@ -462,12 +447,6 @@ nouveau_connector_ddc_detect(struct drm_connector *connector) ...@@ -462,12 +447,6 @@ nouveau_connector_ddc_detect(struct drm_connector *connector)
break; 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; return found;
} }
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include <subdev/bios.h> #include <subdev/bios.h>
#include <subdev/bios/init.h> #include <subdev/bios/init.h>
#include <subdev/gpio.h>
#include <subdev/i2c.h> #include <subdev/i2c.h>
#include <nvif/event.h> #include <nvif/event.h>
...@@ -491,7 +492,7 @@ nvkm_dp_acquire(struct nvkm_outp *outp) ...@@ -491,7 +492,7 @@ nvkm_dp_acquire(struct nvkm_outp *outp)
return ret; return ret;
} }
static void static bool
nvkm_dp_enable(struct nvkm_dp *dp, bool enable) nvkm_dp_enable(struct nvkm_dp *dp, bool enable)
{ {
struct nvkm_i2c_aux *aux = dp->aux; struct nvkm_i2c_aux *aux = dp->aux;
...@@ -505,7 +506,7 @@ nvkm_dp_enable(struct nvkm_dp *dp, bool enable) ...@@ -505,7 +506,7 @@ nvkm_dp_enable(struct nvkm_dp *dp, bool enable)
if (!nvkm_rdaux(aux, DPCD_RC00_DPCD_REV, dp->dpcd, if (!nvkm_rdaux(aux, DPCD_RC00_DPCD_REV, dp->dpcd,
sizeof(dp->dpcd))) sizeof(dp->dpcd)))
return; return true;
} }
if (dp->present) { if (dp->present) {
...@@ -515,6 +516,7 @@ nvkm_dp_enable(struct nvkm_dp *dp, bool enable) ...@@ -515,6 +516,7 @@ nvkm_dp_enable(struct nvkm_dp *dp, bool enable)
} }
atomic_set(&dp->lt.done, 0); atomic_set(&dp->lt.done, 0);
return false;
} }
static int static int
...@@ -555,9 +557,38 @@ nvkm_dp_fini(struct nvkm_outp *outp) ...@@ -555,9 +557,38 @@ nvkm_dp_fini(struct nvkm_outp *outp)
static void static void
nvkm_dp_init(struct nvkm_outp *outp) nvkm_dp_init(struct nvkm_outp *outp)
{ {
struct nvkm_gpio *gpio = outp->disp->engine.subdev.device->gpio;
struct nvkm_dp *dp = nvkm_dp(outp); struct nvkm_dp *dp = nvkm_dp(outp);
nvkm_notify_put(&dp->outp.conn->hpd); 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_dp_enable(dp, true);
}
nvkm_notify_get(&dp->hpd); nvkm_notify_get(&dp->hpd);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment