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

Sergei Antonov saproj at gmail.com
Mon May 5 03:34:06 PDT 2014


On 5 May 2014 01:43, Ben Skeggs <skeggsb at gmail.com> wrote:
> 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 curious about these races. The old code in nouveau_dp.c contained this:
- /* some sinks toggle hotplug in response to some of the actions
- * we take during link training (DP_SET_POWER is one), we need
- * to ignore them for the moment to avoid races.
- */
I wonder how DP_SET_POWER is taken during link training.

> 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