Sergei Antonov
2014-May-04 18:48 UTC
[Nouveau] [PATCH] drm/nouveau/dp: restore DP suspend/resume functionality
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(). 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
Ben Skeggs
2014-May-04 23:43 UTC
[Nouveau] [PATCH] drm/nouveau/dp: restore DP suspend/resume functionality
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
Sergei Antonov
2014-May-05 10:34 UTC
[Nouveau] [PATCH] drm/nouveau/dp: restore DP suspend/resume functionality
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
Apparently Analagous Threads
- [PATCH] drm/nouveau/dp: restore DP suspend/resume functionality
- [PATCH] drm/nouveau/dp: restore DP suspend/resume functionality
- drm/nve0/disp: Fix HDMI InfoFrame initialisation.
- [Bug 76483] New: [NV50, bisected, RFC patch] xset dpms force {on, off} does not work over DP
- VGA resume & thaw (wake up from S3 & S4) broken - kernel(nouveau) exclusively