[Nouveau] [PATCH] drm/nouveau/dp: restore DP suspend/resume functionality

Ben Skeggs skeggsb at gmail.com
Sun May 4 16:43:25 PDT 2014


On Mon, May 5, 2014 at 4:48 AM, Sergei Antonov <saproj at gmail.com> wrote:
> The following commit from about a year ago removed nouveau_dp_dpms() which
> did steps required to suspend and resume a monitor connected via DisplayPort.
>
>     commit 0a0afd282fd715dd63d64b243299a64da14f8e8d
>     Author: Ben Skeggs <bskeggs at redhat.com>
>     Date:   Mon Feb 18 23:17:53 2013 -0500
>     drm/nv50-/disp: move DP link training to core and train from supervisor
>
> My computer with NVIDIA GeForce GT 640M did not blank the screen after a period
> of inactivity, the screen was always on. When in framebuffer console mode
> the system switched to blank mode internally but continued to show picture
> on the screen which produced ugly artifacts as new lines were output.
>
> This patch resurrects some of the removed code to restore the lost
> functionality. Some of the resurrected code was removed by the aforementioned
> commit, some by a later cleanup done by 9a7046d55f319b2dde5d2536cc2adb01ebdbe09e
>
> The code was updated to make it compatible with the current state of the driver.
> Here is how it now works. If the connection is DCB_OUTPUT_DP, call
> nouveau_dp_dpms() which does DP_SET_POWER and, if we are resuming, initiates
> DP link training by sending NV94_DISP_SOR_DP_TRAIN to have nv50_sor_mthd()
> call nouveau_dp_train().
Thank you.  This, as you've seen, would appear to solve the issue.
There's a little more to the power-down to be done however (such as
shutting down the lanes at the SOR, which, yes, we never did before
either), and potential races between the supervisor running link
training and a dpms on.

I'm about to (as in, this week) start some work which will address
this and some other DP issues as they've become more urgent here too.

Thanks again,
Ben.

>
> Cc: Ben Skeggs <bskeggs at redhat.com>
> Cc: Dave Airlie <airlied at redhat.com>
> Signed-off-by: Sergei Antonov <saproj at gmail.com>
> ---
>  drivers/gpu/drm/nouveau/core/engine/disp/nv94.c    |  1 +
>  drivers/gpu/drm/nouveau/core/engine/disp/nva3.c    |  1 +
>  drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c    |  1 +
>  drivers/gpu/drm/nouveau/core/engine/disp/sornv50.c | 12 +++++++++++
>  drivers/gpu/drm/nouveau/core/include/core/class.h  |  1 +
>  drivers/gpu/drm/nouveau/nouveau_dp.c               | 24 ++++++++++++++++++++++
>  drivers/gpu/drm/nouveau/nv50_display.c             |  7 +++++--
>  7 files changed, 45 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv94.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv94.c
> index 6844061..1f24b10 100644
> --- a/drivers/gpu/drm/nouveau/core/engine/disp/nv94.c
> +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv94.c
> @@ -77,6 +77,7 @@ nv94_disp_base_omthds[] = {
>         { SOR_MTHD(NV50_DISP_SOR_PWR)         , nv50_sor_mthd },
>         { SOR_MTHD(NV84_DISP_SOR_HDMI_PWR)    , nv50_sor_mthd },
>         { SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd },
> +       { SOR_MTHD(NV94_DISP_SOR_DP_TRAIN)    , nv50_sor_mthd },
>         { DAC_MTHD(NV50_DISP_DAC_PWR)         , nv50_dac_mthd },
>         { DAC_MTHD(NV50_DISP_DAC_LOAD)        , nv50_dac_mthd },
>         { PIOR_MTHD(NV50_DISP_PIOR_PWR)       , nv50_pior_mthd },
> diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nva3.c b/drivers/gpu/drm/nouveau/core/engine/disp/nva3.c
> index 46cb2ce..59054ff6 100644
> --- a/drivers/gpu/drm/nouveau/core/engine/disp/nva3.c
> +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nva3.c
> @@ -50,6 +50,7 @@ nva3_disp_base_omthds[] = {
>         { SOR_MTHD(NVA3_DISP_SOR_HDA_ELD)     , nv50_sor_mthd },
>         { SOR_MTHD(NV84_DISP_SOR_HDMI_PWR)    , nv50_sor_mthd },
>         { SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd },
> +       { SOR_MTHD(NV94_DISP_SOR_DP_TRAIN)    , nv50_sor_mthd },
>         { DAC_MTHD(NV50_DISP_DAC_PWR)         , nv50_dac_mthd },
>         { DAC_MTHD(NV50_DISP_DAC_LOAD)        , nv50_dac_mthd },
>         { PIOR_MTHD(NV50_DISP_PIOR_PWR)       , nv50_pior_mthd },
> diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c b/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c
> index 7762665..8790c4c 100644
> --- a/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c
> +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c
> @@ -887,6 +887,7 @@ nvd0_disp_base_omthds[] = {
>         { SOR_MTHD(NVA3_DISP_SOR_HDA_ELD)     , nv50_sor_mthd },
>         { SOR_MTHD(NV84_DISP_SOR_HDMI_PWR)    , nv50_sor_mthd },
>         { SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd },
> +       { SOR_MTHD(NV94_DISP_SOR_DP_TRAIN)    , nv50_sor_mthd },
>         { DAC_MTHD(NV50_DISP_DAC_PWR)         , nv50_dac_mthd },
>         { DAC_MTHD(NV50_DISP_DAC_LOAD)        , nv50_dac_mthd },
>         { PIOR_MTHD(NV50_DISP_PIOR_PWR)       , nv50_pior_mthd },
> diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/sornv50.c b/drivers/gpu/drm/nouveau/core/engine/disp/sornv50.c
> index 526b752..5238e65 100644
> --- a/drivers/gpu/drm/nouveau/core/engine/disp/sornv50.c
> +++ b/drivers/gpu/drm/nouveau/core/engine/disp/sornv50.c
> @@ -47,8 +47,14 @@ int
>  nv50_sor_mthd(struct nouveau_object *object, u32 mthd, void *args, u32 size)
>  {
>         struct nv50_disp_priv *priv = (void *)object->engine;
> +       struct nouveau_bios *bios = nouveau_bios(priv);
> +       const u16 type = (mthd & NV50_DISP_SOR_MTHD_TYPE) >> 12;
>         const u8  head = (mthd & NV50_DISP_SOR_MTHD_HEAD) >> 3;
> +       const u8  link = (mthd & NV50_DISP_SOR_MTHD_LINK) >> 2;
>         const u8    or = (mthd & NV50_DISP_SOR_MTHD_OR);
> +       const u16 mask = (0x0100 << head) | (0x0040 << link) | (0x0001 << or);
> +       struct dcb_output outp;
> +       u8  ver, hdr;
>         u32 data;
>         int ret = -EINVAL;
>
> @@ -56,6 +62,8 @@ nv50_sor_mthd(struct nouveau_object *object, u32 mthd, void *args, u32 size)
>                 return -EINVAL;
>         data = *(u32 *)args;
>
> +       if (type && !dcb_outp_match(bios, type, mask, &ver, &hdr, &outp))
> +               return -ENODEV;
>
>         switch (mthd & ~0x3f) {
>         case NV50_DISP_SOR_PWR:
> @@ -71,6 +79,10 @@ nv50_sor_mthd(struct nouveau_object *object, u32 mthd, void *args, u32 size)
>                 priv->sor.lvdsconf = data & NV50_DISP_SOR_LVDS_SCRIPT_ID;
>                 ret = 0;
>                 break;
> +       case NV94_DISP_SOR_DP_TRAIN:
> +               ret = nouveau_dp_train(&priv->base, priv->sor.dp, &outp,
> +                                      head, data);
> +               break;
>         default:
>                 BUG_ON(1);
>         }
> diff --git a/drivers/gpu/drm/nouveau/core/include/core/class.h b/drivers/gpu/drm/nouveau/core/include/core/class.h
> index 9c0cd73..a32f515 100644
> --- a/drivers/gpu/drm/nouveau/core/include/core/class.h
> +++ b/drivers/gpu/drm/nouveau/core/include/core/class.h
> @@ -295,6 +295,7 @@ struct nv04_display_scanoutpos {
>  #define NV84_DISP_SOR_HDMI_PWR_REKEY                                 0x0000007f
>  #define NV50_DISP_SOR_LVDS_SCRIPT                                    0x00013000
>  #define NV50_DISP_SOR_LVDS_SCRIPT_ID                                 0x0000ffff
> +#define NV94_DISP_SOR_DP_TRAIN                                       0x00016000
>
>  #define NV50_DISP_DAC_MTHD                                           0x00020000
>  #define NV50_DISP_DAC_MTHD_TYPE                                      0x0000f000
> diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c
> index 36fd225..ee1bc27 100644
> --- a/drivers/gpu/drm/nouveau/nouveau_dp.c
> +++ b/drivers/gpu/drm/nouveau/nouveau_dp.c
> @@ -35,6 +35,30 @@
>  #include <subdev/gpio.h>
>  #include <subdev/i2c.h>
>
> +void
> +nouveau_dp_dpms(struct drm_encoder *encoder, int mode, u32 datarate,
> +               struct nouveau_object *core)
> +{
> +       struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
> +       struct nouveau_i2c_port *auxch;
> +       int or = nv_encoder->or;
> +       u8 status;
> +
> +       auxch = nv_encoder->i2c;
> +       if (!auxch)
> +               return;
> +
> +       if (mode == DRM_MODE_DPMS_ON)
> +               status = DP_SET_POWER_D0;
> +       else
> +               status = DP_SET_POWER_D3;
> +
> +       nv_wraux(auxch, DP_SET_POWER, &status, 1);
> +
> +       if (mode == DRM_MODE_DPMS_ON)
> +               nv_call(core, NV94_DISP_SOR_DP_TRAIN + or, datarate);
> +}
> +
>  static void
>  nouveau_dp_probe_oui(struct drm_device *dev, struct nouveau_i2c_port *auxch,
>                      u8 *dpcd)
> diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c
> index 58af547..98fd94d 100644
> --- a/drivers/gpu/drm/nouveau/nv50_display.c
> +++ b/drivers/gpu/drm/nouveau/nv50_display.c
> @@ -1720,7 +1720,7 @@ nv50_sor_dpms(struct drm_encoder *encoder, int mode)
>  {
>         struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
>         struct drm_device *dev = encoder->dev;
> -       struct nv50_disp *disp = nv50_disp(dev);
> +       struct nouveau_object *core = nv50_disp(dev)->core;
>         struct drm_encoder *partner;
>         int or = nv_encoder->or;
>
> @@ -1740,7 +1740,10 @@ nv50_sor_dpms(struct drm_encoder *encoder, int mode)
>                 }
>         }
>
> -       nv_call(disp->core, NV50_DISP_SOR_PWR + or, (mode == DRM_MODE_DPMS_ON));
> +       nv_call(core, NV50_DISP_SOR_PWR + or, mode == DRM_MODE_DPMS_ON);
> +
> +       if (nv_encoder->dcb->type == DCB_OUTPUT_DP)
> +               nouveau_dp_dpms(encoder, mode, nv_encoder->dp.datarate, core);
>  }
>
>  static bool
> --
> 1.9.0
>
> _______________________________________________
> Nouveau mailing list
> Nouveau at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/nouveau


More information about the Nouveau mailing list