[PATCH 8/8] drm/exynos: fimd: add complete_scanout function

Sean Paul seanpaul at chromium.org
Thu Jan 3 09:51:48 PST 2013


On Thu, Jan 3, 2013 at 7:56 AM, Prathyush K <prathyush at chromium.org> wrote:
>
>
>
> On Wed, Jan 2, 2013 at 10:24 PM, Sean Paul <seanpaul at chromium.org> wrote:
>>
>> On Wed, Dec 26, 2012 at 6:27 AM, Prathyush K <prathyush.k at samsung.com>
>> wrote:
>> > The wait_for_vblank interface is modified to the complete_scanout
>> > function in fimd. This patch adds the fimd_complete_scanout function
>> >
>> > Inside fimd_complete_scanout, we read the shadow register for each
>> > window and compare it with the dma address of the framebuffer. If
>> > the dma_address is in the shadow register, then the function waits
>> > for the next vblank and returns.
>> >
>> > Signed-off-by: Prathyush K <prathyush.k at samsung.com>
>> > ---
>> >  drivers/gpu/drm/exynos/exynos_drm_fimd.c | 32
>> > +++++++++++++++++++++++++++++++-
>> >  include/video/samsung_fimd.h             |  1 +
>> >  2 files changed, 32 insertions(+), 1 deletion(-)
>> >
>> > diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
>> > b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
>> > index 3aeedf5..190ffde9 100644
>> > --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
>> > +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
>> > @@ -46,6 +46,7 @@
>> >  #define VIDOSD_D(win)          (VIDOSD_BASE + 0x0C + (win) * 16)
>> >
>> >  #define VIDWx_BUF_START(win, buf)      (VIDW_BUF_START(buf) + (win) *
>> > 8)
>> > +#define VIDWx_BUF_START_S(win, buf)    (VIDW_BUF_START_S(buf) + (win) *
>> > 8)
>> >  #define VIDWx_BUF_END(win, buf)                (VIDW_BUF_END(buf) +
>> > (win) * 8)
>> >  #define VIDWx_BUF_SIZE(win, buf)       (VIDW_BUF_SIZE(buf) + (win) * 4)
>> >
>> > @@ -363,13 +364,42 @@ static void fimd_wait_for_vblank(struct device
>> > *dev)
>> >                 fimd_disable_vblank(dev);
>> >  }
>> >
>> > +static void fimd_complete_scanout(struct device *dev, dma_addr_t
>> > dma_addr,
>> > +                                       unsigned long size)
>> > +{
>> > +       struct fimd_context *ctx = get_fimd_context(dev);
>> > +       int win;
>> > +       bool in_use = false;
>> > +
>> > +       if (ctx->suspended)
>> > +               return;
>> > +
>>
>> Is this really possible? If it is, I think there's potential for
>> trouble. It seems possible that an fb is current, but we're suspended.
>> If we exit early here, the fb will be freed and we'll be sad when we
>> come out of suspend.
>>
> Hi Sean,
>
> Before suspend, we disable all the windows (and wait for vsync) and keep
> track of which windows need to be resumed.
>
> If a fb is being removed during suspend, and if that fb was previously set
> to fimd, we modify the resume flag
> so that the window will not be resumed during fimd_resume.
>
>
>>
>> > +       for (win = 0; win < WINDOWS_NR; win++) {
>> > +               dma_addr_t dma_addr_in_use;
>> > +
>> > +               if (!ctx->win_data[win].enabled)
>> > +                       continue;
>> > +
>> > +               dma_addr_in_use = readl(ctx->regs +
>> > VIDWx_BUF_START_S(win, 0));
>> > +               if (dma_addr_in_use >= dma_addr &&
>> > +                       dma_addr_in_use < (dma_addr + size)) {
>> > +                               in_use = true;
>> > +                               break;
>> > +               }
>>
>> I think this has the opposite problem as your mixer patch. You're
>> checking if the framebuffer is in the shadow register, but I don't
>> think this code will wait if the fb is currently being scanned out. I
>> hope I'm just missing something :)
>>
> Right, I do not check for the base register here. This is because I also
> consider the disable_crtc
> function.
>
> Consider the following two cases:
>
> 1>
> fb1 set to fimd and fimd is reading from fb1 (so both base register and
> shadow register have fb1's dma addr)
> call remove fb1
>
> since crtc->fb == fb1, the "exynos_drm_crtc_disable" gets called. This will
> disable the window and also turn off fimd with DPMS_OFF.
>
> fimd dpms off will ensure that the window actually gets disabled by waiting
> for vblank.
>
> Now before removing fb1, we call complete_scanout. Since fimd is already
> suspended, this will just return. No issue.
>

I see the code path you're talking about. I think I was confused by
the "suspended" name, it also covers the disabled/off case.


> 2>
> fb1 set to fimd, fimd reading from fb1.
> fb2 set to fimd
> call remove fb1
> (now base register has fb2, shadow register has fb1)
>
> since crtc->fb == fb2, crtc_disable wont be called.
>
> In complete scanout, we check only shadow register (which has fb1).
> So we wait for vsync, so that next dma starts from fb2 and then we go ahead
> and remove fb1.
>

Ok, I think I've straightened out my mental model of how this works.
Thanks for the explanation


> I tried to apply the same logic for mixer:
> In mixer, it is slightly more complex, since we have layer updates.
>
> Consider the following cases for mixer:
>
> 1> fb1 set to mixer (base register has fb1) - also fb1 gets queued with a
> layer update.
> mixer is reading from fb1 (shadow register has fb1).
> remove fb1
>
> crtc->fb == fb1, so win_disable gets called followed by crtc off. This will
> wait for vsync.
>
> complete_scanout will just return. remove fb1. no issue.
>
>
> 2> mixer reading from fb1
> fb2 set to mixer (layer update)
> remove fb1
>
> In this case, base has fb2, shadow has fb1.
>
> crtc->fb == fb2, so no win_disable.
>
> complete scanout will wait for vsync and ensure dma is from fb2. remove fb1.
> no issue.
>
> 3> mixer reading from fb1. shadow reg has fb1
> fb2 set to mixer (layer update - base reg has fb2)
> fb3 set to mixer (since layer update is pending, win_commit returns)
> remove fb2
>
> crtc->fb == fb3, so no win_disable
>
> complete scanout: base == fb2 so win_disable and then wait for vsync. remove
> fb1. no issue
>

I think I see where you're going with this. I think you have a bug in
your other patch which I'll reply to separately.

>
> Hope this answers your question. If there is any additional scenario which I
> missed, do let me know :)
>

In general, this seems like it's a pretty complex solution to
something that should be more simple, but maybe I'm just being dense
:)

Sean


> With the above approach, there is no crash in either fimd or hdmi after
> quite a few attempts at multiple scenarios.
> I am working on a patch set v2 which I'll post tomorrow with a couple of
> additional fixes.
>
> Regards,
> Prathyush
>
>
>
>
>>
>> Sean
>>
>>
>>
>> > +       }
>> > +
>> > +       if (in_use)
>> > +               fimd_wait_for_vblank(dev);
>> > +       return;
>> > +}
>> > +
>> >  static struct exynos_drm_manager_ops fimd_manager_ops = {
>> >         .dpms = fimd_dpms,
>> >         .apply = fimd_apply,
>> >         .commit = fimd_commit,
>> >         .enable_vblank = fimd_enable_vblank,
>> >         .disable_vblank = fimd_disable_vblank,
>> > -       .wait_for_vblank = fimd_wait_for_vblank,
>> > +       .complete_scanout = fimd_complete_scanout,
>> >  };
>> >
>> >  static void fimd_win_mode_set(struct device *dev,
>> > diff --git a/include/video/samsung_fimd.h b/include/video/samsung_fimd.h
>> > index 7ae6c07..382eaec 100644
>> > --- a/include/video/samsung_fimd.h
>> > +++ b/include/video/samsung_fimd.h
>> > @@ -274,6 +274,7 @@
>> >
>> >  /* Video buffer addresses */
>> >  #define VIDW_BUF_START(_buff)                  (0xA0 + ((_buff) * 8))
>> > +#define VIDW_BUF_START_S(_buff)                        (0x40A0 +
>> > ((_buff) * 8))
>> >  #define VIDW_BUF_START1(_buff)                 (0xA4 + ((_buff) * 8))
>> >  #define VIDW_BUF_END(_buff)                    (0xD0 + ((_buff) * 8))
>> >  #define VIDW_BUF_END1(_buff)                   (0xD4 + ((_buff) * 8))
>> > --
>> > 1.8.0
>> >
>> > _______________________________________________
>> > dri-devel mailing list
>> > dri-devel at lists.freedesktop.org
>> > http://lists.freedesktop.org/mailman/listinfo/dri-devel
>> _______________________________________________
>> dri-devel mailing list
>> dri-devel at lists.freedesktop.org
>> http://lists.freedesktop.org/mailman/listinfo/dri-devel
>
>


More information about the dri-devel mailing list