[PATCH 12/23] drm/exynos: Split manager/display/subdrv

Inki Dae inki.dae at samsung.com
Wed Oct 16 04:17:46 CEST 2013


2013/10/16 Sean Paul <seanpaul at chromium.org>:
> On Tue, Oct 15, 2013 at 12:09 AM, Inki Dae <inki.dae at samsung.com> wrote:
>> 2013/10/15 Inki Dae <inki.dae at samsung.com>:
>>>> diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
>>>> index c417c90..ba63c72 100644
>>>> --- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c
>>>> +++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
>>>> @@ -26,24 +26,23 @@
>>>>   * exynos specific encoder structure.
>>>>   *
>>>>   * @drm_encoder: encoder object.
>>>> - * @manager: specific encoder has its own manager to control a hardware
>>>> - *     appropriately and we can access a hardware drawing on this manager.
>>>> + * @display: the display structure that maps to this encoder
>>>>   */
>>>>  struct exynos_drm_encoder {
>>>>         struct drm_crtc                 *old_crtc;
>>>>         struct drm_encoder              drm_encoder;
>>>> -       struct exynos_drm_manager       *manager;
>>>> +       struct exynos_drm_display       *display;
>>>>  };
>>>>
>>>>  static void exynos_drm_encoder_dpms(struct drm_encoder *encoder, int mode)
>>>>  {
>>>> -       struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
>>>> -       struct exynos_drm_display_ops *display_ops = manager->display_ops;
>>>> +       struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
>>>> +       struct exynos_drm_display *display = exynos_encoder->display;
>>>>
>>>>         DRM_DEBUG_KMS("encoder dpms: %d\n", mode);
>>>>
>>>> -       if (display_ops && display_ops->dpms)
>>>> -               display_ops->dpms(manager->ctx, mode);
>>>> +       if (display->ops->dpms)
>>>> +               display->ops->dpms(display->ctx, mode);
>>>
>>> It's good to remove apply callback. However, it seems that this patch
>>> has a problem that dma channel of fimd isn't enabled after dpms goes
>>> from off to on. So can you implement win_enable callback of fimd, and
>>> add it to fimd_win_resume function? We should have implemented
>>> win_enable callback.
>>>
>>
>> Plz, ignore the above comments, and see the below comments.
>>
>>
>>>> diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
>>>> index 838c47d..f3dc808 100644
>>>> --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
>>>> +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
>>>> @@ -105,7 +105,6 @@ struct fimd_win_data {
>>>>  };
>>>>
>>>>  struct fimd_context {
>>>> -       struct exynos_drm_subdrv        subdrv;
>>>>         struct device                   *dev;
>>>>         struct drm_device               *drm_dev;
>>>>         int                             irq;
>>>> @@ -120,6 +119,7 @@ struct fimd_context {
>>>>         u32                             vidcon0;
>>>>         u32                             vidcon1;
>>>>         bool                            suspended;
>>>> +       int                             pipe;
>>>>         struct mutex                    lock;
>>>>         wait_queue_head_t               wait_vsync_queue;
>>>>         atomic_t                        wait_vsync_event;
>>>> @@ -169,12 +169,16 @@ static int fimd_check_mode(void *in_ctx, struct drm_display_mode *mode)
>>>>  }
>>>>
>>>>  static struct exynos_drm_display_ops fimd_display_ops = {
>>>> -       .type = EXYNOS_DISPLAY_TYPE_LCD,
>>>>         .is_connected = fimd_display_is_connected,
>>>>         .get_panel = fimd_get_panel,
>>>>         .check_mode = fimd_check_mode,
>>>>  };
>>>>
>>>> +static struct exynos_drm_display fimd_display = {
>>>> +       .type = EXYNOS_DISPLAY_TYPE_LCD,
>>>> +       .ops = &fimd_display_ops,
>>>> +};
>>>> +
>>>>  static void fimd_win_mode_set(void *in_ctx, struct exynos_drm_overlay *overlay)
>>>>  {
>>>>         struct fimd_context *ctx = in_ctx;
>>>> @@ -481,15 +485,46 @@ static void fimd_win_disable(void *in_ctx, int zpos)
>>>>         win_data->enabled = false;
>>>>  }
>>>>
>>>> -static int fimd_mgr_initialize(void *in_ctx, struct drm_device *drm_dev)
>>>> +static int fimd_mgr_initialize(void *in_ctx, struct drm_device *drm_dev,
>>>> +               int pipe)
>>>>  {
>>>>         struct fimd_context *ctx = in_ctx;
>>>>
>>>>         ctx->drm_dev = drm_dev;
>>>> +       ctx->pipe = pipe;
>>>> +
>>>> +       /*
>>>> +        * enable drm irq mode.
>>>> +        * - with irq_enabled = 1, we can use the vblank feature.
>>>> +        *
>>>> +        * P.S. note that we wouldn't use drm irq handler but
>>>> +        *      just specific driver own one instead because
>>>> +        *      drm framework supports only one irq handler.
>>>> +        */
>>>> +       ctx->drm_dev->irq_enabled = 1;
>>>> +
>>>> +       /*
>>>> +        * with vblank_disable_allowed = 1, vblank interrupt will be disabled
>>>> +        * by drm timer once a current process gives up ownership of
>>>> +        * vblank event.(after drm_vblank_put function is called)
>>>> +        */
>>>> +       drm_dev->vblank_disable_allowed = 1;
>>>> +
>>>> +       /* attach this sub driver to iommu mapping if supported. */
>>>> +       if (is_drm_iommu_supported(ctx->drm_dev))
>>>> +               drm_iommu_attach_device(ctx->drm_dev, ctx->dev);
>>>>
>>>>         return 0;
>>>>  }
>>>>
>>>> +static void fimd_mgr_remove(void *in_ctx)
>>>> +{
>>>> +       struct fimd_context *ctx = in_ctx;
>>>> +
>>>> +       if (is_drm_iommu_supported(ctx->drm_dev))
>>>> +               drm_iommu_detach_device(ctx->drm_dev, ctx->dev);
>>>> +}
>>>> +
>>>>  static void fimd_dpms(void *in_ctx, int mode)
>>>>  {
>>>>         struct fimd_context *ctx = in_ctx;
>>>> @@ -523,24 +558,6 @@ static void fimd_dpms(void *in_ctx, int mode)
>>>>         mutex_unlock(&ctx->lock);
>>>>  }
>>>>
>>>> -static void fimd_apply(void *in_ctx)
>>>> -{
>>>> -       struct fimd_context *ctx = in_ctx;
>>>> -       struct exynos_drm_manager *mgr = ctx->subdrv.manager;
>>>> -       struct exynos_drm_manager_ops *mgr_ops = mgr->ops;
>>>> -       struct fimd_win_data *win_data;
>>>> -       int i;
>>>> -
>>>> -       for (i = 0; i < WINDOWS_NR; i++) {
>>>> -               win_data = &ctx->win_data[i];
>>>> -               if (win_data->enabled && (mgr_ops && mgr_ops->win_commit))
>>>> -                       mgr_ops->win_commit(ctx, i);
>>>> -       }
>>>> -
>>>> -       if (mgr_ops && mgr_ops->commit)
>>>> -               mgr_ops->commit(ctx);
>>>> -}
>>>> -
>>>>  static void fimd_commit(void *in_ctx)
>>>>  {
>>>>         struct fimd_context *ctx = in_ctx;
>>>> @@ -597,6 +614,21 @@ static void fimd_commit(void *in_ctx)
>>>>         writel(val, ctx->regs + VIDCON0);
>>>>  }
>>>>
>>>> +static void fimd_apply(void *in_ctx)
>>>> +{
>>>> +       struct fimd_context *ctx = in_ctx;
>>>> +       struct fimd_win_data *win_data;
>>>> +       int i;
>>>> +
>>>> +       for (i = 0; i < WINDOWS_NR; i++) {
>>>> +               win_data = &ctx->win_data[i];
>>>> +               if (win_data->enabled)
>>>> +                       fimd_win_commit(ctx, i);
>>
>> Implement fimd_win_enable function and call it at here,
>>
>>                       if (win_data->enabled) {
>>                              fimd_win_commit(ctx,i);
>>                              fimd_win_enable(ctx, i);  <- here
>>                       }
>>
>> And, the below codes, for enable overlay dma channel, should be
>> removed from fimd_win_commit function,
>>
>>     /* wincon */
>>     val = readl(ctx->regs + WINCON(win));
>>     val |= WINCONx_ENWIN;
>>     writel(val, ctx->regs + WINCON(win));
>>
>
> I'm not sure I follow why you want this done here. It seems unrelated
> to this patch.
>

Yes, it's unrelated to this patch. I mean additional work.

>>
>> And, with [PATCH v2] drm/exynos: fimd: clean up pm suspend/resume, it
>> must work well.
>
>
> I've got a patch to remove all of the
> suspend/resume/pm_suspend/pm_resume stuff from all of the individual
> drivers and do everything through dpms. This will eliminate the error
> modes where the dpms state in the upper layers get out of sync with
> the actual state of the hardware. It's also more consistent with other
> drm drivers. I'll post it after this set.
>

It seems like more clear  if we _can_do_ so. However, can the dpms be
called when entering sleep? And I think this way - removing all pm
related stuff from device drivers - is not reasonable, and we'd need
more discussion about that with pm people. So add the related patch
set at top of your re-factoring patch set if you want to do so.

Thanks,
Inki Dae

> Sean
>
>>
>>>> +       }
>>>> +
>>>> +       fimd_commit(ctx);
>>>> +}
>>>> +
>>>>  static int fimd_enable_vblank(void *in_ctx)
>>>>  {
>>>>         struct fimd_context *ctx = in_ctx;
>>>> @@ -661,6 +693,7 @@ static void fimd_wait_for_vblank(void *in_ctx)
>>>>
>>>>  static struct exynos_drm_manager_ops fimd_manager_ops = {
>>>>         .initialize = fimd_mgr_initialize,
>>>> +       .remove = fimd_mgr_remove,
>>>>         .dpms = fimd_dpms,
>>>>         .apply = fimd_apply,
>>>>         .commit = fimd_commit,
>>>> @@ -673,16 +706,13 @@ static struct exynos_drm_manager_ops fimd_manager_ops = {
>>>>  };
>>>>
>>>>  static struct exynos_drm_manager fimd_manager = {
>>>> -       .pipe           = -1,
>>>> -       .ops            = &fimd_manager_ops,
>>>> -       .display_ops    = &fimd_display_ops,
>>>> +       .type = EXYNOS_DISPLAY_TYPE_LCD,
>>>> +       .ops = &fimd_manager_ops,
>>>>  };
>>>>
>>>>  static irqreturn_t fimd_irq_handler(int irq, void *dev_id)
>>>>  {
>>>>         struct fimd_context *ctx = (struct fimd_context *)dev_id;
>>>> -       struct exynos_drm_subdrv *subdrv = &ctx->subdrv;
>>>> -       struct exynos_drm_manager *manager = subdrv->manager;
>>>>         u32 val;
>>>>
>>>>         val = readl(ctx->regs + VIDINTCON1);
>>>> @@ -692,11 +722,11 @@ static irqreturn_t fimd_irq_handler(int irq, void *dev_id)
>>>>                 writel(VIDINTCON1_INT_FRAME, ctx->regs + VIDINTCON1);
>>>>
>>>>         /* check the crtc is detached already from encoder */
>>>> -       if (manager->pipe < 0 || !ctx->drm_dev)
>>>> +       if (ctx->pipe < 0 || !ctx->drm_dev)
>>>>                 goto out;
>>>>
>>>> -       drm_handle_vblank(ctx->drm_dev, manager->pipe);
>>>> -       exynos_drm_crtc_finish_pageflip(ctx->drm_dev, manager->pipe);
>>>> +       drm_handle_vblank(ctx->drm_dev, ctx->pipe);
>>>> +       exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe);
>>>>
>>>>         /* set wait vsync event to zero and wake up queue. */
>>>>         if (atomic_read(&ctx->wait_vsync_event)) {
>>>> @@ -707,39 +737,6 @@ out:
>>>>         return IRQ_HANDLED;
>>>>  }
>>>>
>>>> -static int fimd_subdrv_probe(struct drm_device *drm_dev, struct device *dev)
>>>> -{
>>>> -       /*
>>>> -        * enable drm irq mode.
>>>> -        * - with irq_enabled = 1, we can use the vblank feature.
>>>> -        *
>>>> -        * P.S. note that we wouldn't use drm irq handler but
>>>> -        *      just specific driver own one instead because
>>>> -        *      drm framework supports only one irq handler.
>>>> -        */
>>>> -       drm_dev->irq_enabled = 1;
>>>> -
>>>> -       /*
>>>> -        * with vblank_disable_allowed = 1, vblank interrupt will be disabled
>>>> -        * by drm timer once a current process gives up ownership of
>>>> -        * vblank event.(after drm_vblank_put function is called)
>>>> -        */
>>>> -       drm_dev->vblank_disable_allowed = 1;
>>>> -
>>>> -       /* attach this sub driver to iommu mapping if supported. */
>>>> -       if (is_drm_iommu_supported(drm_dev))
>>>> -               drm_iommu_attach_device(drm_dev, dev);
>>>> -
>>>> -       return 0;
>>>> -}
>>>> -
>>>> -static void fimd_subdrv_remove(struct drm_device *drm_dev, struct device *dev)
>>>> -{
>>>> -       /* detach this sub driver from iommu mapping if supported. */
>>>> -       if (is_drm_iommu_supported(drm_dev))
>>>> -               drm_iommu_detach_device(drm_dev, dev);
>>>> -}
>>>> -
>>>>  static int fimd_configure_clocks(struct fimd_context *ctx, struct device *dev)
>>>>  {
>>>>         struct videomode *vm = &ctx->panel.vm;
>>>> @@ -825,9 +822,8 @@ static int fimd_clock(struct fimd_context *ctx, bool enable)
>>>>         return 0;
>>>>  }
>>>>
>>>> -static void fimd_window_suspend(struct device *dev)
>>>> +static void fimd_window_suspend(struct fimd_context *ctx)
>>>>  {
>>>> -       struct fimd_context *ctx = get_fimd_context(dev);
>>>>         struct fimd_win_data *win_data;
>>>>         int i;
>>>>
>>>> @@ -839,9 +835,8 @@ static void fimd_window_suspend(struct device *dev)
>>>>         fimd_wait_for_vblank(ctx);
>>>>  }
>>>>
>>>> -static void fimd_window_resume(struct device *dev)
>>>> +static void fimd_window_resume(struct fimd_context *ctx)
>>>>  {
>>>> -       struct fimd_context *ctx = get_fimd_context(dev);
>>>>         struct fimd_win_data *win_data;
>>>>         int i;
>>>>
>>>> @@ -854,7 +849,6 @@ static void fimd_window_resume(struct device *dev)
>>>>
>>>>  static int fimd_activate(struct fimd_context *ctx, bool enable)
>>>>  {
>>>> -       struct device *dev = ctx->subdrv.dev;
>>>>         if (enable) {
>>>>                 int ret;
>>>>
>>>> @@ -866,11 +860,11 @@ static int fimd_activate(struct fimd_context *ctx, bool enable)
>>>>
>>>>                 /* if vblank was enabled status, enable it again. */
>>>>                 if (test_and_clear_bit(0, &ctx->irq_flags))
>>>> -                       fimd_enable_vblank(dev);
>>>> +                       fimd_enable_vblank(ctx);
>>>>
>>>> -               fimd_window_resume(dev);
>>>> +               fimd_window_resume(ctx);
>>>>         } else {
>>>> -               fimd_window_suspend(dev);
>>>> +               fimd_window_suspend(ctx);
>>>>
>>>>                 fimd_clock(ctx, false);
>>>>                 ctx->suspended = true;
>>>> @@ -907,7 +901,6 @@ static int fimd_probe(struct platform_device *pdev)
>>>>  {
>>>>         struct device *dev = &pdev->dev;
>>>>         struct fimd_context *ctx;
>>>> -       struct exynos_drm_subdrv *subdrv;
>>>>         struct resource *res;
>>>>         int win;
>>>>         int ret = -EINVAL;
>>>> @@ -952,15 +945,6 @@ static int fimd_probe(struct platform_device *pdev)
>>>>         DRM_INIT_WAITQUEUE(&ctx->wait_vsync_queue);
>>>>         atomic_set(&ctx->wait_vsync_event, 0);
>>>>
>>>> -       fimd_manager.ctx = ctx;
>>>> -
>>>> -       subdrv = &ctx->subdrv;
>>>> -
>>>> -       subdrv->dev = dev;
>>>> -       subdrv->manager = &fimd_manager;
>>>> -       subdrv->probe = fimd_subdrv_probe;
>>>> -       subdrv->remove = fimd_subdrv_remove;
>>>> -
>>>>         mutex_init(&ctx->lock);
>>>>
>>>>         platform_set_drvdata(pdev, ctx);
>>>> @@ -971,7 +955,11 @@ static int fimd_probe(struct platform_device *pdev)
>>>>         for (win = 0; win < WINDOWS_NR; win++)
>>>>                 fimd_clear_win(ctx, win);
>>>>
>>>> -       exynos_drm_subdrv_register(subdrv);
>>>> +       fimd_manager.ctx = ctx;
>>>> +       exynos_drm_manager_register(&fimd_manager);
>>>> +
>>>> +       fimd_display.ctx = ctx;
>>>> +       exynos_drm_display_register(&fimd_display);
>>>>
>>>>         return 0;
>>>>  }
>>>> @@ -981,7 +969,8 @@ static int fimd_remove(struct platform_device *pdev)
>>>>         struct device *dev = &pdev->dev;
>>>>         struct fimd_context *ctx = platform_get_drvdata(pdev);
>>>>
>>>> -       exynos_drm_subdrv_unregister(&ctx->subdrv);
>>>> +       exynos_drm_display_unregister(&fimd_display);
>>>> +       exynos_drm_manager_unregister(&fimd_manager);
>>>>
>>>>         if (ctx->suspended)
>>>>                 goto out;
> _______________________________________________
> 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