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

Ben Skeggs skeggsb at gmail.com
Tue May 6 22:35:38 PDT 2014


On Mon, May 5, 2014 at 8:34 PM, Sergei Antonov <saproj at gmail.com> wrote:
> 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.
VBIOS scripts call it.

>
>> 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