diff mbox

[4/5] drm/i915: take power well refs when needed

Message ID 1381792069-27800-5-git-send-email-jbarnes@virtuousgeek.org (mailing list archive)
State New, archived
Headers show

Commit Message

Jesse Barnes Oct. 14, 2013, 11:07 p.m. UTC
When accessing the display regs for hw state readout or cross check, we
need to make sure the power well is enabled so we can read valid
register state.

Likewise, in an actual mode set, we need to take a ref on the
appropriate power well so that the mode set succeeds.  From then on, the
power well ref will be tracked by the CRTC enable/disable code.

Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
---
 drivers/gpu/drm/i915/i915_dma.c      |  2 ++
 drivers/gpu/drm/i915/intel_display.c | 30 ++++++++++++++++++++++++++++++
 2 files changed, 32 insertions(+)

Comments

Paulo Zanoni Oct. 15, 2013, 7:54 p.m. UTC | #1
2013/10/14 Jesse Barnes <jbarnes@virtuousgeek.org>:
> When accessing the display regs for hw state readout or cross check, we
> need to make sure the power well is enabled so we can read valid
> register state.

On the current code (HSW) we already check for the power wells in the
HW state readout code: if the power well is disabled, then transcoders
A/B/C are disabled. The current code takes care to not touch registers
on a disabled power well.

>
> Likewise, in an actual mode set, we need to take a ref on the
> appropriate power well so that the mode set succeeds.  From then on, the
> power well ref will be tracked by the CRTC enable/disable code.
>
> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
> ---
>  drivers/gpu/drm/i915/i915_dma.c      |  2 ++
>  drivers/gpu/drm/i915/intel_display.c | 30 ++++++++++++++++++++++++++++++
>  2 files changed, 32 insertions(+)
>
> diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
> index 313a8c9..91c3e6c 100644
> --- a/drivers/gpu/drm/i915/i915_dma.c
> +++ b/drivers/gpu/drm/i915/i915_dma.c
> @@ -1367,6 +1367,8 @@ static int i915_load_modeset_init(struct drm_device *dev)
>         i915_disable_vga_mem(dev);
>         intel_display_power_put(dev, POWER_DOMAIN_VGA);
>
> +       intel_display_power_put(dev, POWER_DOMAIN_PIPE(0));
> +

Why is this here? It certainly deserves a comment in the code.


>         /* Only enable hotplug handling once the fbdev is fully set up. */
>         dev_priv->enable_hotplug_processing = true;
>
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index 6e4729b..62ee110 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -3841,6 +3841,8 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc)
>         if (intel_crtc->active)
>                 return;
>
> +       intel_display_power_get(dev, POWER_DOMAIN_PIPE(pipe));
> +
>         intel_crtc->active = true;
>
>         for_each_encoder_on_crtc(dev, crtc, encoder)
> @@ -3975,6 +3977,9 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc)
>         intel_update_watermarks(crtc);
>
>         intel_update_fbc(dev);
> +
> +       if (IS_VALLEYVIEW(dev))
> +               intel_display_power_put(dev, POWER_DOMAIN_PIPE(pipe));

So now HSW uses global_resources while VLV uses crtc enable/disable. I
really think both platforms should try to do the same thing.

By the way, at least on Haswell, if we do an equivalent change we'll
have problems, because when you disable the power well at
crtc_disable, then everything you did at crtc_mode_set will be undone,
and it won't be redone at crtc_enable. When you reenable the power
well, the registers go back to their default values, not the values
that were previously there. Did you check if VLV behaves the same?

>  }
>
>  static void i9xx_crtc_off(struct drm_crtc *crtc)
> @@ -4134,6 +4139,11 @@ static void intel_connector_check_state(struct intel_connector *connector)
>   * consider. */
>  void intel_connector_dpms(struct drm_connector *connector, int mode)
>  {
> +       struct intel_crtc *intel_crtc = to_intel_crtc(connector->encoder->crtc);
> +       enum intel_display_power_domain domain;
> +
> +       domain = POWER_DOMAIN_PIPE(intel_crtc->pipe);
> +
>         /* All the simple cases only support two dpms states. */
>         if (mode != DRM_MODE_DPMS_ON)
>                 mode = DRM_MODE_DPMS_OFF;
> @@ -4141,6 +4151,7 @@ void intel_connector_dpms(struct drm_connector *connector, int mode)
>         if (mode == connector->dpms)
>                 return;
>
> +       intel_display_power_get(connector->dev, domain);
>         connector->dpms = mode;
>
>         /* Only need to change hw state when actually enabled */
> @@ -4148,6 +4159,7 @@ void intel_connector_dpms(struct drm_connector *connector, int mode)
>                 intel_encoder_dpms(to_intel_encoder(connector->encoder), mode);
>
>         intel_modeset_check_state(connector->dev);
> +       intel_display_power_put(connector->dev, domain);
>  }
>
>  /* Simple connector->get_hw_state implementation for encoders that support only
> @@ -9192,6 +9204,15 @@ static int __intel_set_mode(struct drm_crtc *crtc,
>         for_each_intel_crtc_masked(dev, disable_pipes, intel_crtc)
>                 intel_crtc_disable(&intel_crtc->base);
>
> +       /*
> +        * We take a ref here so the mode set will hit live hw.  Once
> +        * we call the CRTC enable, we can drop our ref since it'll get
> +        * tracked there from then on.
> +        */
> +       for_each_intel_crtc_masked(dev, prepare_pipes, intel_crtc)
> +               intel_display_power_get(dev,
> +                                       POWER_DOMAIN_PIPE(intel_crtc->pipe));
> +
>         for_each_intel_crtc_masked(dev, prepare_pipes, intel_crtc) {
>                 if (intel_crtc->base.enabled)
>                         dev_priv->display.crtc_disable(&intel_crtc->base);
> @@ -9247,6 +9268,10 @@ done:
>         }
>
>  out:
> +       for_each_intel_crtc_masked(dev, prepare_pipes, intel_crtc)
> +               intel_display_power_put(dev,
> +                                       POWER_DOMAIN_PIPE(intel_crtc->pipe));
> +
>         kfree(pipe_config);
>         kfree(saved_mode);
>         return ret;
> @@ -10692,6 +10717,11 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev)
>
>                 crtc->base.enabled = crtc->active;
>
> +               if (crtc->active)
> +                       intel_display_power_get(dev,
> +                                               POWER_DOMAIN_PIPE(crtc->pipe));
> +

What about the panel fitter power domains? Sometimes the panel fitter
is the thing that makes you require a power well, even though you're
on a pipe that doesn't need it.

And on Haswell you also have to take into account
TRANSCODER_EDP+PIPE_A versus TRANSCODER_A+PIPE_A, where the first
doesn't need the power well but the second needs it.

> +
>                 DRM_DEBUG_KMS("[CRTC:%d] hw state readout: %s\n",
>                               crtc->base.base.id,
>                               crtc->active ? "enabled" : "disabled");
> --
> 1.8.3.1
>
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx
Jesse Barnes Oct. 15, 2013, 8:40 p.m. UTC | #2
On Tue, 15 Oct 2013 16:54:00 -0300
Paulo Zanoni <przanoni@gmail.com> wrote:

> 2013/10/14 Jesse Barnes <jbarnes@virtuousgeek.org>:
> > When accessing the display regs for hw state readout or cross check, we
> > need to make sure the power well is enabled so we can read valid
> > register state.
> 
> On the current code (HSW) we already check for the power wells in the
> HW state readout code: if the power well is disabled, then transcoders
> A/B/C are disabled. The current code takes care to not touch registers
> on a disabled power well.

Yeah and we should probably preserve that behavior, for the readout
code at least.

> > +       intel_display_power_put(dev, POWER_DOMAIN_PIPE(0));
> > +
> 
> Why is this here? It certainly deserves a comment in the code.

It probably needs to be removed.  The refcounting for the initial load
is still screwy due to the unconditional enable later on.

> So now HSW uses global_resources while VLV uses crtc enable/disable. I
> really think both platforms should try to do the same thing.

Definitely agreed.

> By the way, at least on Haswell, if we do an equivalent change we'll
> have problems, because when you disable the power well at
> crtc_disable, then everything you did at crtc_mode_set will be undone,
> and it won't be redone at crtc_enable. When you reenable the power
> well, the registers go back to their default values, not the values
> that were previously there. Did you check if VLV behaves the same?

No that's taken into account here.  In __intel_set_mode we take a
private ref on the appropriate power well so that we'll preserve state
until we do the first crtc_enable.  From then on, the ref is tracked
there and we drop the private one in __intel_set_mode

> > +               if (crtc->active)
> > +                       intel_display_power_get(dev,
> > +                                               POWER_DOMAIN_PIPE(crtc->pipe));
> > +
> 
> What about the panel fitter power domains? Sometimes the panel fitter
> is the thing that makes you require a power well, even though you're
> on a pipe that doesn't need it.
> 
> And on Haswell you also have to take into account
> TRANSCODER_EDP+PIPE_A versus TRANSCODER_A+PIPE_A, where the first
> doesn't need the power well but the second needs it.

Yeah I'm still not sure how to handle this in generic code.  Maybe the
power well mapping function Imre added will be enough, but it
definitely gets tricky when we look at all the different platforms we
have to (and will have to) handle.

Thanks,
Paulo Zanoni Oct. 15, 2013, 8:47 p.m. UTC | #3
2013/10/15 Jesse Barnes <jbarnes@virtuousgeek.org>:
> On Tue, 15 Oct 2013 16:54:00 -0300
> Paulo Zanoni <przanoni@gmail.com> wrote:
>
>> 2013/10/14 Jesse Barnes <jbarnes@virtuousgeek.org>:
>> > When accessing the display regs for hw state readout or cross check, we
>> > need to make sure the power well is enabled so we can read valid
>> > register state.
>>
>> On the current code (HSW) we already check for the power wells in the
>> HW state readout code: if the power well is disabled, then transcoders
>> A/B/C are disabled. The current code takes care to not touch registers
>> on a disabled power well.
>
> Yeah and we should probably preserve that behavior, for the readout
> code at least.
>
>> > +       intel_display_power_put(dev, POWER_DOMAIN_PIPE(0));
>> > +
>>
>> Why is this here? It certainly deserves a comment in the code.
>
> It probably needs to be removed.  The refcounting for the initial load
> is still screwy due to the unconditional enable later on.
>
>> So now HSW uses global_resources while VLV uses crtc enable/disable. I
>> really think both platforms should try to do the same thing.
>
> Definitely agreed.
>
>> By the way, at least on Haswell, if we do an equivalent change we'll
>> have problems, because when you disable the power well at
>> crtc_disable, then everything you did at crtc_mode_set will be undone,
>> and it won't be redone at crtc_enable. When you reenable the power
>> well, the registers go back to their default values, not the values
>> that were previously there. Did you check if VLV behaves the same?
>
> No that's taken into account here.  In __intel_set_mode we take a
> private ref on the appropriate power well so that we'll preserve state
> until we do the first crtc_enable.  From then on, the ref is tracked
> there and we drop the private one in __intel_set_mode

Yeah, but then after all this is done, at some point we'll call
crtc_disable, then we'll put the last ref back and then the power well
will be disabled. Then the user moves the mouse and we call
crtc_enable, so we enable the power well, all its registers to back to
their reset state, then crtc_enable sets some of the registers, but
that won't really be enough since no one called crtc_mode_set again,
and all the state set by crtc_mode_set (not touched by crtc_enable) is
back to the default values. No? What am I missing?

>
>> > +               if (crtc->active)
>> > +                       intel_display_power_get(dev,
>> > +                                               POWER_DOMAIN_PIPE(crtc->pipe));
>> > +
>>
>> What about the panel fitter power domains? Sometimes the panel fitter
>> is the thing that makes you require a power well, even though you're
>> on a pipe that doesn't need it.
>>
>> And on Haswell you also have to take into account
>> TRANSCODER_EDP+PIPE_A versus TRANSCODER_A+PIPE_A, where the first
>> doesn't need the power well but the second needs it.
>
> Yeah I'm still not sure how to handle this in generic code.  Maybe the
> power well mapping function Imre added will be enough, but it
> definitely gets tricky when we look at all the different platforms we
> have to (and will have to) handle.
>
> Thanks,
> --
> Jesse Barnes, Intel Open Source Technology Center
Jesse Barnes Oct. 15, 2013, 8:57 p.m. UTC | #4
On Tue, 15 Oct 2013 17:47:20 -0300
Paulo Zanoni <przanoni@gmail.com> wrote:

> 2013/10/15 Jesse Barnes <jbarnes@virtuousgeek.org>:
> > On Tue, 15 Oct 2013 16:54:00 -0300
> > Paulo Zanoni <przanoni@gmail.com> wrote:
> >
> >> 2013/10/14 Jesse Barnes <jbarnes@virtuousgeek.org>:
> >> > When accessing the display regs for hw state readout or cross check, we
> >> > need to make sure the power well is enabled so we can read valid
> >> > register state.
> >>
> >> On the current code (HSW) we already check for the power wells in the
> >> HW state readout code: if the power well is disabled, then transcoders
> >> A/B/C are disabled. The current code takes care to not touch registers
> >> on a disabled power well.
> >
> > Yeah and we should probably preserve that behavior, for the readout
> > code at least.
> >
> >> > +       intel_display_power_put(dev, POWER_DOMAIN_PIPE(0));
> >> > +
> >>
> >> Why is this here? It certainly deserves a comment in the code.
> >
> > It probably needs to be removed.  The refcounting for the initial load
> > is still screwy due to the unconditional enable later on.
> >
> >> So now HSW uses global_resources while VLV uses crtc enable/disable. I
> >> really think both platforms should try to do the same thing.
> >
> > Definitely agreed.
> >
> >> By the way, at least on Haswell, if we do an equivalent change we'll
> >> have problems, because when you disable the power well at
> >> crtc_disable, then everything you did at crtc_mode_set will be undone,
> >> and it won't be redone at crtc_enable. When you reenable the power
> >> well, the registers go back to their default values, not the values
> >> that were previously there. Did you check if VLV behaves the same?
> >
> > No that's taken into account here.  In __intel_set_mode we take a
> > private ref on the appropriate power well so that we'll preserve state
> > until we do the first crtc_enable.  From then on, the ref is tracked
> > there and we drop the private one in __intel_set_mode
> 
> Yeah, but then after all this is done, at some point we'll call
> crtc_disable, then we'll put the last ref back and then the power well
> will be disabled. Then the user moves the mouse and we call
> crtc_enable, so we enable the power well, all its registers to back to
> their reset state, then crtc_enable sets some of the registers, but
> that won't really be enough since no one called crtc_mode_set again,
> and all the state set by crtc_mode_set (not touched by crtc_enable) is
> back to the default values. No? What am I missing?

That's where the save/restore state of the later patch comes in.  We
need that if we're going to support DPMS and runtime suspend w/o a mode
set.
Paulo Zanoni Oct. 15, 2013, 9:03 p.m. UTC | #5
2013/10/15 Jesse Barnes <jbarnes@virtuousgeek.org>:
> On Tue, 15 Oct 2013 17:47:20 -0300
> Paulo Zanoni <przanoni@gmail.com> wrote:
>
>> 2013/10/15 Jesse Barnes <jbarnes@virtuousgeek.org>:
>> > On Tue, 15 Oct 2013 16:54:00 -0300
>> > Paulo Zanoni <przanoni@gmail.com> wrote:
>> >
>> >> 2013/10/14 Jesse Barnes <jbarnes@virtuousgeek.org>:
>> >> > When accessing the display regs for hw state readout or cross check, we
>> >> > need to make sure the power well is enabled so we can read valid
>> >> > register state.
>> >>
>> >> On the current code (HSW) we already check for the power wells in the
>> >> HW state readout code: if the power well is disabled, then transcoders
>> >> A/B/C are disabled. The current code takes care to not touch registers
>> >> on a disabled power well.
>> >
>> > Yeah and we should probably preserve that behavior, for the readout
>> > code at least.
>> >
>> >> > +       intel_display_power_put(dev, POWER_DOMAIN_PIPE(0));
>> >> > +
>> >>
>> >> Why is this here? It certainly deserves a comment in the code.
>> >
>> > It probably needs to be removed.  The refcounting for the initial load
>> > is still screwy due to the unconditional enable later on.
>> >
>> >> So now HSW uses global_resources while VLV uses crtc enable/disable. I
>> >> really think both platforms should try to do the same thing.
>> >
>> > Definitely agreed.
>> >
>> >> By the way, at least on Haswell, if we do an equivalent change we'll
>> >> have problems, because when you disable the power well at
>> >> crtc_disable, then everything you did at crtc_mode_set will be undone,
>> >> and it won't be redone at crtc_enable. When you reenable the power
>> >> well, the registers go back to their default values, not the values
>> >> that were previously there. Did you check if VLV behaves the same?
>> >
>> > No that's taken into account here.  In __intel_set_mode we take a
>> > private ref on the appropriate power well so that we'll preserve state
>> > until we do the first crtc_enable.  From then on, the ref is tracked
>> > there and we drop the private one in __intel_set_mode
>>
>> Yeah, but then after all this is done, at some point we'll call
>> crtc_disable, then we'll put the last ref back and then the power well
>> will be disabled. Then the user moves the mouse and we call
>> crtc_enable, so we enable the power well, all its registers to back to
>> their reset state, then crtc_enable sets some of the registers, but
>> that won't really be enough since no one called crtc_mode_set again,
>> and all the state set by crtc_mode_set (not touched by crtc_enable) is
>> back to the default values. No? What am I missing?
>
> That's where the save/restore state of the later patch comes in.  We
> need that if we're going to support DPMS and runtime suspend w/o a mode
> set.

Oh... I wasn't even thinking about it since it's on a later patch. But
makes sense.

But instead of the save/restore thing, shouldn't we just move all the
code that touches registers from mode_set to crtc_enable? IMHO it's
the shiny solution here. And anything else that we may need to
save/restore should be moved to crtc enable/disable and be saved in
"struct intel_crtc" every time it is touched. I really think that
removing stuff from the save/restore code is the way to go. Also, with
my suggestion, crtc_enable will fully implement the "mode set
sequence" from BSpec, so people like the Audio guys will have an
easier time understanding our code :)

>
> --
> Jesse Barnes, Intel Open Source Technology Center
Imre Deak Oct. 16, 2013, 11:10 a.m. UTC | #6
On Tue, 2013-10-15 at 13:40 -0700, Jesse Barnes wrote:
> On Tue, 15 Oct 2013 16:54:00 -0300
> Paulo Zanoni <przanoni@gmail.com> wrote:
> [...]
> No that's taken into account here.  In __intel_set_mode we take a
> private ref on the appropriate power well so that we'll preserve state
> until we do the first crtc_enable.  From then on, the ref is tracked
> there and we drop the private one in __intel_set_mode
> 
> > > +               if (crtc->active)
> > > +                       intel_display_power_get(dev,
> > > +                                               POWER_DOMAIN_PIPE(crtc->pipe));
> > > +
> > 
> > What about the panel fitter power domains? Sometimes the panel fitter
> > is the thing that makes you require a power well, even though you're
> > on a pipe that doesn't need it.
> > 
> > And on Haswell you also have to take into account
> > TRANSCODER_EDP+PIPE_A versus TRANSCODER_A+PIPE_A, where the first
> > doesn't need the power well but the second needs it.
> 
> Yeah I'm still not sure how to handle this in generic code.  Maybe the
> power well mapping function Imre added will be enough, but it
> definitely gets tricky when we look at all the different platforms we
> have to (and will have to) handle.

Isn't the power domain abstraction a neat idea exactly for the above
case? Generic code just asks for the domain it needs and doesn't care
how it maps to power wells on the given platform. So for transcoder_edp
+pipe_a it'd end up asking for POWER_DOMAIN_PIPE_A and
POWER_DOMAIN_TRANSCODER_EDP, both of which is a nop on HSW, and for the
other case POWER_DOMAIN_PIPE_A and POWER_DOMAIN_TRANSCODER_A which would
enable the power well. You also have the POWER_DOMAIN_PIPE,
POWER_DOMAIN_TRANSCODER, POWER_DOMAIN_PIPE_PANEL_FITTER helpers already.

--Imre
Jesse Barnes Oct. 16, 2013, 3:08 p.m. UTC | #7
On Wed, 16 Oct 2013 14:10:13 +0300
Imre Deak <imre.deak@intel.com> wrote:

> On Tue, 2013-10-15 at 13:40 -0700, Jesse Barnes wrote:
> > On Tue, 15 Oct 2013 16:54:00 -0300
> > Paulo Zanoni <przanoni@gmail.com> wrote:
> > [...]
> > No that's taken into account here.  In __intel_set_mode we take a
> > private ref on the appropriate power well so that we'll preserve state
> > until we do the first crtc_enable.  From then on, the ref is tracked
> > there and we drop the private one in __intel_set_mode
> > 
> > > > +               if (crtc->active)
> > > > +                       intel_display_power_get(dev,
> > > > +                                               POWER_DOMAIN_PIPE(crtc->pipe));
> > > > +
> > > 
> > > What about the panel fitter power domains? Sometimes the panel fitter
> > > is the thing that makes you require a power well, even though you're
> > > on a pipe that doesn't need it.
> > > 
> > > And on Haswell you also have to take into account
> > > TRANSCODER_EDP+PIPE_A versus TRANSCODER_A+PIPE_A, where the first
> > > doesn't need the power well but the second needs it.
> > 
> > Yeah I'm still not sure how to handle this in generic code.  Maybe the
> > power well mapping function Imre added will be enough, but it
> > definitely gets tricky when we look at all the different platforms we
> > have to (and will have to) handle.
> 
> Isn't the power domain abstraction a neat idea exactly for the above
> case? Generic code just asks for the domain it needs and doesn't care
> how it maps to power wells on the given platform. So for transcoder_edp
> +pipe_a it'd end up asking for POWER_DOMAIN_PIPE_A and
> POWER_DOMAIN_TRANSCODER_EDP, both of which is a nop on HSW, and for the
> other case POWER_DOMAIN_PIPE_A and POWER_DOMAIN_TRANSCODER_A which would
> enable the power well. You also have the POWER_DOMAIN_PIPE,
> POWER_DOMAIN_TRANSCODER, POWER_DOMAIN_PIPE_PANEL_FITTER helpers already.

Yeah I think it can work.  I missed your function that takes a crtc
though as well, so we don't end up polluting the generic functions with
TRANSCODER references that don't exist on the Atom platforms for
example.  That's the main thing I'm worried about, since as we get more
and more wells I think it'll get easier to get it wrong in the generic
code, if we have to use all the required domains for all platforms
there.
Imre Deak Oct. 17, 2013, 1:01 p.m. UTC | #8
On Wed, 2013-10-16 at 08:08 -0700, Jesse Barnes wrote:
> On Wed, 16 Oct 2013 14:10:13 +0300
> Imre Deak <imre.deak@intel.com> wrote:
> 
> > On Tue, 2013-10-15 at 13:40 -0700, Jesse Barnes wrote:
> > > On Tue, 15 Oct 2013 16:54:00 -0300
> > > Paulo Zanoni <przanoni@gmail.com> wrote:
> > > [...]
> > > No that's taken into account here.  In __intel_set_mode we take a
> > > private ref on the appropriate power well so that we'll preserve state
> > > until we do the first crtc_enable.  From then on, the ref is tracked
> > > there and we drop the private one in __intel_set_mode
> > > 
> > > > > +               if (crtc->active)
> > > > > +                       intel_display_power_get(dev,
> > > > > +                                               POWER_DOMAIN_PIPE(crtc->pipe));
> > > > > +
> > > > 
> > > > What about the panel fitter power domains? Sometimes the panel fitter
> > > > is the thing that makes you require a power well, even though you're
> > > > on a pipe that doesn't need it.
> > > > 
> > > > And on Haswell you also have to take into account
> > > > TRANSCODER_EDP+PIPE_A versus TRANSCODER_A+PIPE_A, where the first
> > > > doesn't need the power well but the second needs it.
> > > 
> > > Yeah I'm still not sure how to handle this in generic code.  Maybe the
> > > power well mapping function Imre added will be enough, but it
> > > definitely gets tricky when we look at all the different platforms we
> > > have to (and will have to) handle.
> > 
> > Isn't the power domain abstraction a neat idea exactly for the above
> > case? Generic code just asks for the domain it needs and doesn't care
> > how it maps to power wells on the given platform. So for transcoder_edp
> > +pipe_a it'd end up asking for POWER_DOMAIN_PIPE_A and
> > POWER_DOMAIN_TRANSCODER_EDP, both of which is a nop on HSW, and for the
> > other case POWER_DOMAIN_PIPE_A and POWER_DOMAIN_TRANSCODER_A which would
> > enable the power well. You also have the POWER_DOMAIN_PIPE,
> > POWER_DOMAIN_TRANSCODER, POWER_DOMAIN_PIPE_PANEL_FITTER helpers already.
> 
> Yeah I think it can work.  I missed your function that takes a crtc
> though as well, so we don't end up polluting the generic functions with
> TRANSCODER references that don't exist on the Atom platforms for
> example.  That's the main thing I'm worried about, since as we get more
> and more wells I think it'll get easier to get it wrong in the generic
> code, if we have to use all the required domains for all platforms
> there.

Afaics, on VLV for example we'd ask for pipe A/B and transcoder A/B
power domains, which is still correct. It's true that there the
pipe-transcoder connection is fixed, and so we'll always ask for the
same pipe/transcoder power domain pair, but I think it's still ok
conceptually.

So atm the power domains as defined are platform independent, which is
great. If we can't avoid adding a platform specific ones in the future,
we could still handle those in platform specific code.

--Imre
diff mbox

Patch

diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index 313a8c9..91c3e6c 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -1367,6 +1367,8 @@  static int i915_load_modeset_init(struct drm_device *dev)
 	i915_disable_vga_mem(dev);
 	intel_display_power_put(dev, POWER_DOMAIN_VGA);
 
+	intel_display_power_put(dev, POWER_DOMAIN_PIPE(0));
+
 	/* Only enable hotplug handling once the fbdev is fully set up. */
 	dev_priv->enable_hotplug_processing = true;
 
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 6e4729b..62ee110 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -3841,6 +3841,8 @@  static void valleyview_crtc_enable(struct drm_crtc *crtc)
 	if (intel_crtc->active)
 		return;
 
+	intel_display_power_get(dev, POWER_DOMAIN_PIPE(pipe));
+
 	intel_crtc->active = true;
 
 	for_each_encoder_on_crtc(dev, crtc, encoder)
@@ -3975,6 +3977,9 @@  static void i9xx_crtc_disable(struct drm_crtc *crtc)
 	intel_update_watermarks(crtc);
 
 	intel_update_fbc(dev);
+
+	if (IS_VALLEYVIEW(dev))
+		intel_display_power_put(dev, POWER_DOMAIN_PIPE(pipe));
 }
 
 static void i9xx_crtc_off(struct drm_crtc *crtc)
@@ -4134,6 +4139,11 @@  static void intel_connector_check_state(struct intel_connector *connector)
  * consider. */
 void intel_connector_dpms(struct drm_connector *connector, int mode)
 {
+	struct intel_crtc *intel_crtc = to_intel_crtc(connector->encoder->crtc);
+	enum intel_display_power_domain domain;
+
+	domain = POWER_DOMAIN_PIPE(intel_crtc->pipe);
+
 	/* All the simple cases only support two dpms states. */
 	if (mode != DRM_MODE_DPMS_ON)
 		mode = DRM_MODE_DPMS_OFF;
@@ -4141,6 +4151,7 @@  void intel_connector_dpms(struct drm_connector *connector, int mode)
 	if (mode == connector->dpms)
 		return;
 
+	intel_display_power_get(connector->dev, domain);
 	connector->dpms = mode;
 
 	/* Only need to change hw state when actually enabled */
@@ -4148,6 +4159,7 @@  void intel_connector_dpms(struct drm_connector *connector, int mode)
 		intel_encoder_dpms(to_intel_encoder(connector->encoder), mode);
 
 	intel_modeset_check_state(connector->dev);
+	intel_display_power_put(connector->dev, domain);
 }
 
 /* Simple connector->get_hw_state implementation for encoders that support only
@@ -9192,6 +9204,15 @@  static int __intel_set_mode(struct drm_crtc *crtc,
 	for_each_intel_crtc_masked(dev, disable_pipes, intel_crtc)
 		intel_crtc_disable(&intel_crtc->base);
 
+	/*
+	 * We take a ref here so the mode set will hit live hw.  Once
+	 * we call the CRTC enable, we can drop our ref since it'll get
+	 * tracked there from then on.
+	 */
+	for_each_intel_crtc_masked(dev, prepare_pipes, intel_crtc)
+		intel_display_power_get(dev,
+					POWER_DOMAIN_PIPE(intel_crtc->pipe));
+
 	for_each_intel_crtc_masked(dev, prepare_pipes, intel_crtc) {
 		if (intel_crtc->base.enabled)
 			dev_priv->display.crtc_disable(&intel_crtc->base);
@@ -9247,6 +9268,10 @@  done:
 	}
 
 out:
+	for_each_intel_crtc_masked(dev, prepare_pipes, intel_crtc)
+		intel_display_power_put(dev,
+					POWER_DOMAIN_PIPE(intel_crtc->pipe));
+
 	kfree(pipe_config);
 	kfree(saved_mode);
 	return ret;
@@ -10692,6 +10717,11 @@  static void intel_modeset_readout_hw_state(struct drm_device *dev)
 
 		crtc->base.enabled = crtc->active;
 
+		if (crtc->active)
+			intel_display_power_get(dev,
+						POWER_DOMAIN_PIPE(crtc->pipe));
+
+
 		DRM_DEBUG_KMS("[CRTC:%d] hw state readout: %s\n",
 			      crtc->base.base.id,
 			      crtc->active ? "enabled" : "disabled");