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

Inki Dae inki.dae at samsung.com
Mon Oct 14 17:24:20 CEST 2013


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

>  }
>
>  static bool
> @@ -52,15 +51,17 @@ exynos_drm_encoder_mode_fixup(struct drm_encoder *encoder,
>                                struct drm_display_mode *adjusted_mode)
>  {
>         struct drm_device *dev = encoder->dev;
> +       struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
> +       struct exynos_drm_display *display = exynos_encoder->display;
>         struct drm_connector *connector;
> -       struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
> -       struct exynos_drm_manager_ops *manager_ops = manager->ops;
>
>         list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
> -               if (connector->encoder == encoder)
> -                       if (manager_ops && manager_ops->mode_fixup)
> -                               manager_ops->mode_fixup(manager->ctx, connector,
> -                                                       mode, adjusted_mode);
> +               if (connector->encoder != encoder)
> +                       continue;
> +
> +               if (display->ops->mode_fixup)
> +                       display->ops->mode_fixup(display->ctx, connector, mode,
> +                                       adjusted_mode);
>         }
>
>         return true;
> @@ -102,8 +103,7 @@ static void exynos_drm_encoder_mode_set(struct drm_encoder *encoder,
>  {
>         struct drm_device *dev = encoder->dev;
>         struct drm_connector *connector;
> -       struct exynos_drm_manager *manager;
> -       struct exynos_drm_manager_ops *manager_ops;
> +       struct exynos_drm_display *display;
>
>         list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
>                 if (connector->encoder == encoder) {
> @@ -123,11 +123,10 @@ static void exynos_drm_encoder_mode_set(struct drm_encoder *encoder,
>                                                 encoder->crtc);
>                         }
>
> -                       manager = exynos_drm_get_manager(encoder);
> -                       manager_ops = manager->ops;
> +                       display = exynos_encoder->display;
>
> -                       if (manager_ops && manager_ops->mode_set)
> -                               manager_ops->mode_set(manager->ctx,
> +                       if (display->ops->mode_set)
> +                               display->ops->mode_set(display->ctx,
>                                                         adjusted_mode);
>
>                         exynos_encoder->old_crtc = encoder->crtc;
> @@ -143,39 +142,15 @@ static void exynos_drm_encoder_prepare(struct drm_encoder *encoder)
>  static void exynos_drm_encoder_commit(struct drm_encoder *encoder)
>  {
>         struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
> -       struct exynos_drm_manager *manager = exynos_encoder->manager;
> -       struct exynos_drm_manager_ops *manager_ops = manager->ops;
> -
> -       if (manager_ops && manager_ops->commit)
> -               manager_ops->commit(manager->ctx);
> -}
> +       struct exynos_drm_display *display = exynos_encoder->display;
>
> -void exynos_drm_encoder_complete_scanout(struct drm_framebuffer *fb)
> -{
> -       struct exynos_drm_encoder *exynos_encoder;
> -       struct exynos_drm_manager_ops *ops;
> -       struct drm_device *dev = fb->dev;
> -       struct drm_encoder *encoder;
> +       if (display->ops->dpms)
> +               display->ops->dpms(display->ctx, DRM_MODE_DPMS_ON);
>
> -       /*
> -        * make sure that overlay data are updated to real hardware
> -        * for all encoders.
> -        */
> -       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
> -               exynos_encoder = to_exynos_encoder(encoder);
> -               ops = exynos_encoder->manager->ops;
> -
> -               /*
> -                * wait for vblank interrupt
> -                * - this makes sure that overlay data are updated to
> -                *      real hardware.
> -                */
> -               if (ops->wait_for_vblank)
> -                       ops->wait_for_vblank(exynos_encoder->manager->dev);
> -       }
> +       if (display->ops->commit)
> +               display->ops->commit(display->ctx);
>  }
>
> -
>  static void exynos_drm_encoder_disable(struct drm_encoder *encoder)
>  {
>         struct drm_plane *plane;
> @@ -201,10 +176,7 @@ static struct drm_encoder_helper_funcs exynos_encoder_helper_funcs = {
>
>  static void exynos_drm_encoder_destroy(struct drm_encoder *encoder)
>  {
> -       struct exynos_drm_encoder *exynos_encoder =
> -               to_exynos_encoder(encoder);
> -
> -       exynos_encoder->manager->pipe = -1;
> +       struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
>
>         drm_encoder_cleanup(encoder);
>         kfree(exynos_encoder);
> @@ -219,13 +191,12 @@ static unsigned int exynos_drm_encoder_clones(struct drm_encoder *encoder)
>         struct drm_encoder *clone;
>         struct drm_device *dev = encoder->dev;
>         struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
> -       struct exynos_drm_display_ops *display_ops =
> -                               exynos_encoder->manager->display_ops;
> +       struct exynos_drm_display *display = exynos_encoder->display;
>         unsigned int clone_mask = 0;
>         int cnt = 0;
>
>         list_for_each_entry(clone, &dev->mode_config.encoder_list, head) {
> -               switch (display_ops->type) {
> +               switch (display->type) {
>                 case EXYNOS_DISPLAY_TYPE_LCD:
>                 case EXYNOS_DISPLAY_TYPE_HDMI:
>                 case EXYNOS_DISPLAY_TYPE_VIDI:
> @@ -249,24 +220,20 @@ void exynos_drm_encoder_setup(struct drm_device *dev)
>
>  struct drm_encoder *
>  exynos_drm_encoder_create(struct drm_device *dev,
> -                          struct exynos_drm_manager *manager,
> +                          struct exynos_drm_display *display,
>                            unsigned long possible_crtcs)
>  {
>         struct drm_encoder *encoder;
>         struct exynos_drm_encoder *exynos_encoder;
> -       int ret;
>
> -       if (!manager || !possible_crtcs)
> -               return NULL;
> -
> -       if (!manager->dev)
> +       if (!possible_crtcs)
>                 return NULL;
>
>         exynos_encoder = kzalloc(sizeof(*exynos_encoder), GFP_KERNEL);
>         if (!exynos_encoder)
>                 return NULL;
>
> -       exynos_encoder->manager = manager;
> +       exynos_encoder->display = display;
>         encoder = &exynos_encoder->drm_encoder;
>         encoder->possible_crtcs = possible_crtcs;
>
> @@ -277,174 +244,12 @@ exynos_drm_encoder_create(struct drm_device *dev,
>
>         drm_encoder_helper_add(encoder, &exynos_encoder_helper_funcs);
>
> -       if (manager->ops && manager->ops->initialize) {
> -               ret = manager->ops->initialize(manager->ctx, dev);
> -               if (ret) {
> -                       DRM_ERROR("Manager initialize failed %d\n", ret);
> -                       goto error;
> -               }
> -       }
> -
> -       if (manager->display_ops && manager->display_ops->initialize) {
> -               ret = manager->display_ops->initialize(manager->ctx, dev);
> -               if (ret) {
> -                       DRM_ERROR("Display initialize failed %d\n", ret);
> -                       goto error;
> -               }
> -       }
> -
>         DRM_DEBUG_KMS("encoder has been created\n");
>
>         return encoder;
> -
> -error:
> -       exynos_drm_encoder_destroy(&exynos_encoder->drm_encoder);
> -       return NULL;
>  }
>
> -struct exynos_drm_manager *exynos_drm_get_manager(struct drm_encoder *encoder)
> +struct exynos_drm_display *exynos_drm_get_display(struct drm_encoder *encoder)
>  {
> -       return to_exynos_encoder(encoder)->manager;
> -}
> -
> -void exynos_drm_fn_encoder(struct drm_crtc *crtc, void *data,
> -                           void (*fn)(struct drm_encoder *, void *))
> -{
> -       struct drm_device *dev = crtc->dev;
> -       struct drm_encoder *encoder;
> -       struct exynos_drm_private *private = dev->dev_private;
> -       struct exynos_drm_manager *manager;
> -
> -       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
> -               /*
> -                * if crtc is detached from encoder, check pipe,
> -                * otherwise check crtc attached to encoder
> -                */
> -               if (!encoder->crtc) {
> -                       manager = to_exynos_encoder(encoder)->manager;
> -                       if (manager->pipe < 0 ||
> -                                       private->crtc[manager->pipe] != crtc)
> -                               continue;
> -               } else {
> -                       if (encoder->crtc != crtc)
> -                               continue;
> -               }
> -
> -               fn(encoder, data);
> -       }
> -}
> -
> -void exynos_drm_enable_vblank(struct drm_encoder *encoder, void *data)
> -{
> -       struct exynos_drm_manager *manager =
> -               to_exynos_encoder(encoder)->manager;
> -       struct exynos_drm_manager_ops *manager_ops = manager->ops;
> -       int crtc = *(int *)data;
> -
> -       if (manager->pipe != crtc)
> -               return;
> -
> -       if (manager_ops->enable_vblank)
> -               manager_ops->enable_vblank(manager->ctx);
> -}
> -
> -void exynos_drm_disable_vblank(struct drm_encoder *encoder, void *data)
> -{
> -       struct exynos_drm_manager *manager =
> -               to_exynos_encoder(encoder)->manager;
> -       struct exynos_drm_manager_ops *manager_ops = manager->ops;
> -       int crtc = *(int *)data;
> -
> -       if (manager->pipe != crtc)
> -               return;
> -
> -       if (manager_ops->disable_vblank)
> -               manager_ops->disable_vblank(manager->ctx);
> -}
> -
> -void exynos_drm_encoder_crtc_dpms(struct drm_encoder *encoder, void *data)
> -{
> -       struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
> -       struct exynos_drm_manager *manager = exynos_encoder->manager;
> -       struct exynos_drm_manager_ops *manager_ops = manager->ops;
> -       int mode = *(int *)data;
> -
> -       if (manager_ops && manager_ops->dpms)
> -               manager_ops->dpms(manager->ctx, mode);
> -
> -       /*
> -        * if this condition is ok then it means that the crtc is already
> -        * detached from encoder and last function for detaching is properly
> -        * done, so clear pipe from manager to prevent repeated call.
> -        */
> -       if (mode > DRM_MODE_DPMS_ON) {
> -               if (!encoder->crtc)
> -                       manager->pipe = -1;
> -       }
> -}
> -
> -void exynos_drm_encoder_crtc_pipe(struct drm_encoder *encoder, void *data)
> -{
> -       struct exynos_drm_manager *manager =
> -               to_exynos_encoder(encoder)->manager;
> -       int pipe = *(int *)data;
> -
> -       /*
> -        * when crtc is detached from encoder, this pipe is used
> -        * to select manager operation
> -        */
> -       manager->pipe = pipe;
> -}
> -
> -void exynos_drm_encoder_plane_mode_set(struct drm_encoder *encoder, void *data)
> -{
> -       struct exynos_drm_manager *manager =
> -               to_exynos_encoder(encoder)->manager;
> -       struct exynos_drm_manager_ops *manager_ops = manager->ops;
> -       struct exynos_drm_overlay *overlay = data;
> -
> -       if (manager_ops && manager_ops->win_mode_set)
> -               manager_ops->win_mode_set(manager->ctx, overlay);
> -}
> -
> -void exynos_drm_encoder_plane_commit(struct drm_encoder *encoder, void *data)
> -{
> -       struct exynos_drm_manager *manager =
> -               to_exynos_encoder(encoder)->manager;
> -       struct exynos_drm_manager_ops *manager_ops = manager->ops;
> -       int zpos = DEFAULT_ZPOS;
> -
> -       if (data)
> -               zpos = *(int *)data;
> -
> -       if (manager_ops && manager_ops->win_commit)
> -               manager_ops->win_commit(manager->ctx, zpos);
> -}
> -
> -void exynos_drm_encoder_plane_enable(struct drm_encoder *encoder, void *data)
> -{
> -       struct exynos_drm_manager *manager =
> -               to_exynos_encoder(encoder)->manager;
> -       struct exynos_drm_manager_ops *manager_ops = manager->ops;
> -       int zpos = DEFAULT_ZPOS;
> -
> -       if (data)
> -               zpos = *(int *)data;
> -
> -       if (manager_ops && manager_ops->win_enable)
> -               manager_ops->win_enable(manager->ctx, zpos);
> -}
> -
> -void exynos_drm_encoder_plane_disable(struct drm_encoder *encoder, void *data)
> -{
> -       struct exynos_drm_manager *manager =
> -               to_exynos_encoder(encoder)->manager;
> -       struct exynos_drm_manager_ops *manager_ops = manager->ops;
> -       int zpos = DEFAULT_ZPOS;
> -
> -       if (data)
> -               zpos = *(int *)data;
> -
> -       if (manager_ops && manager_ops->win_disable)
> -               manager_ops->win_disable(manager->ctx, zpos);
> +       return to_exynos_encoder(encoder)->display;
>  }
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.h b/drivers/gpu/drm/exynos/exynos_drm_encoder.h
> index 0f3e5e2..b7a1620 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_encoder.h
> +++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.h
> @@ -18,20 +18,8 @@ struct exynos_drm_manager;
>
>  void exynos_drm_encoder_setup(struct drm_device *dev);
>  struct drm_encoder *exynos_drm_encoder_create(struct drm_device *dev,
> -                                              struct exynos_drm_manager *mgr,
> -                                              unsigned long possible_crtcs);
> -struct exynos_drm_manager *
> -exynos_drm_get_manager(struct drm_encoder *encoder);
> -void exynos_drm_fn_encoder(struct drm_crtc *crtc, void *data,
> -                           void (*fn)(struct drm_encoder *, void *));
> -void exynos_drm_enable_vblank(struct drm_encoder *encoder, void *data);
> -void exynos_drm_disable_vblank(struct drm_encoder *encoder, void *data);
> -void exynos_drm_encoder_crtc_dpms(struct drm_encoder *encoder, void *data);
> -void exynos_drm_encoder_crtc_pipe(struct drm_encoder *encoder, void *data);
> -void exynos_drm_encoder_plane_mode_set(struct drm_encoder *encoder, void *data);
> -void exynos_drm_encoder_plane_commit(struct drm_encoder *encoder, void *data);
> -void exynos_drm_encoder_plane_enable(struct drm_encoder *encoder, void *data);
> -void exynos_drm_encoder_plane_disable(struct drm_encoder *encoder, void *data);
> -void exynos_drm_encoder_complete_scanout(struct drm_framebuffer *fb);
> +                       struct exynos_drm_display *mgr,
> +                       unsigned long possible_crtcs);
> +struct exynos_drm_display *exynos_drm_get_display(struct drm_encoder *encoder);
>
>  #endif
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.c b/drivers/gpu/drm/exynos/exynos_drm_fb.c
> index ea39e0e..c7c08d0 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_fb.c
> +++ b/drivers/gpu/drm/exynos/exynos_drm_fb.c
> @@ -22,7 +22,7 @@
>  #include "exynos_drm_fb.h"
>  #include "exynos_drm_gem.h"
>  #include "exynos_drm_iommu.h"
> -#include "exynos_drm_encoder.h"
> +#include "exynos_drm_crtc.h"
>
>  #define to_exynos_fb(x)        container_of(x, struct exynos_drm_fb, fb)
>
> @@ -71,7 +71,7 @@ static void exynos_drm_fb_destroy(struct drm_framebuffer *fb)
>         unsigned int i;
>
>         /* make sure that overlay data are updated before relesing fb. */
> -       exynos_drm_encoder_complete_scanout(fb);
> +       exynos_drm_crtc_complete_scanout(fb);
>
>         drm_framebuffer_cleanup(fb);
>
> 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);
> +       }
> +
> +       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;
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
> index 8173e44..8fc9d6d 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
> +++ b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
> @@ -24,14 +24,11 @@
>  #include "exynos_drm_hdmi.h"
>
>  #define to_context(dev)                platform_get_drvdata(to_platform_device(dev))
> -#define to_subdrv(dev)         to_context(dev)
> -#define get_ctx_from_subdrv(subdrv)    container_of(subdrv,\
> -                                       struct drm_hdmi_context, subdrv);
>
>  /* platform device pointer for common drm hdmi device. */
>  static struct platform_device *exynos_drm_hdmi_pdev;
>
> -/* Common hdmi subdrv needs to access the hdmi and mixer though context.
> +/* Common hdmi needs to access the hdmi and mixer though context.
>  * These should be initialied by the repective drivers */
>  static struct exynos_drm_hdmi_context *hdmi_ctx;
>  static struct exynos_drm_hdmi_context *mixer_ctx;
> @@ -41,7 +38,6 @@ static struct exynos_hdmi_ops *hdmi_ops;
>  static struct exynos_mixer_ops *mixer_ops;
>
>  struct drm_hdmi_context {
> -       struct exynos_drm_subdrv        subdrv;
>         struct exynos_drm_hdmi_context  *hdmi_ctx;
>         struct exynos_drm_hdmi_context  *mixer_ctx;
>
> @@ -101,6 +97,12 @@ static int drm_hdmi_display_initialize(void *in_ctx, struct drm_device *drm_dev)
>  {
>         struct drm_hdmi_context *ctx = in_ctx;
>
> +       if (!hdmi_ctx) {
> +               DRM_ERROR("hdmi context not initialized.\n");
> +               return -EINVAL;
> +       }
> +       ctx->hdmi_ctx = hdmi_ctx;
> +
>         if (hdmi_ops && hdmi_ops->initialize)
>                 return hdmi_ops->initialize(ctx->hdmi_ctx->ctx, drm_dev);
>
> @@ -118,6 +120,17 @@ static bool drm_hdmi_is_connected(void *in_ctx)
>         return false;
>  }
>
> +static void drm_hdmi_get_max_resol(void *in_ctx, unsigned int *width,
> +                               unsigned int *height)
> +{
> +       struct drm_hdmi_context *ctx = in_ctx;
> +
> +       DRM_DEBUG_KMS("%s\n", __FILE__);
> +
> +       if (hdmi_ops && hdmi_ops->get_max_resol)
> +               hdmi_ops->get_max_resol(ctx->hdmi_ctx->ctx, width, height);
> +}
> +
>  static struct edid *drm_hdmi_get_edid(void *in_ctx,
>                         struct drm_connector *connector)
>  {
> @@ -129,6 +142,16 @@ static struct edid *drm_hdmi_get_edid(void *in_ctx,
>         return NULL;
>  }
>
> +static void drm_hdmi_mode_set(void *in_ctx, struct drm_display_mode *mode)
> +{
> +       struct drm_hdmi_context *ctx = in_ctx;
> +
> +       DRM_DEBUG_KMS("%s\n", __FILE__);
> +
> +       if (hdmi_ops && hdmi_ops->mode_set)
> +               hdmi_ops->mode_set(ctx->hdmi_ctx->ctx, mode);
> +}
> +
>  static int drm_hdmi_check_mode(void *in_ctx, struct drm_display_mode *mode)
>  {
>         struct drm_hdmi_context *ctx = in_ctx;
> @@ -151,52 +174,6 @@ static int drm_hdmi_check_mode(void *in_ctx, struct drm_display_mode *mode)
>         return 0;
>  }
>
> -static void drm_hdmi_display_dpms(void *in_ctx, int mode)
> -{
> -       struct drm_hdmi_context *ctx = in_ctx;
> -
> -       if (hdmi_ops && hdmi_ops->dpms)
> -               hdmi_ops->dpms(ctx->hdmi_ctx->ctx, mode);
> -}
> -
> -static struct exynos_drm_display_ops drm_hdmi_display_ops = {
> -       .type = EXYNOS_DISPLAY_TYPE_HDMI,
> -       .initialize = drm_hdmi_display_initialize,
> -       .is_connected = drm_hdmi_is_connected,
> -       .get_edid = drm_hdmi_get_edid,
> -       .check_mode = drm_hdmi_check_mode,
> -       .dpms = drm_hdmi_display_dpms,
> -};
> -
> -static int drm_hdmi_enable_vblank(void *in_ctx)
> -{
> -       struct drm_hdmi_context *ctx = in_ctx;
> -       struct exynos_drm_subdrv *subdrv = &ctx->subdrv;
> -       struct exynos_drm_manager *manager = subdrv->manager;
> -
> -       if (mixer_ops && mixer_ops->enable_vblank)
> -               return mixer_ops->enable_vblank(ctx->mixer_ctx->ctx,
> -                                               manager->pipe);
> -
> -       return 0;
> -}
> -
> -static void drm_hdmi_disable_vblank(void *in_ctx)
> -{
> -       struct drm_hdmi_context *ctx = in_ctx;
> -
> -       if (mixer_ops && mixer_ops->disable_vblank)
> -               return mixer_ops->disable_vblank(ctx->mixer_ctx->ctx);
> -}
> -
> -static void drm_hdmi_wait_for_vblank(void *in_ctx)
> -{
> -       struct drm_hdmi_context *ctx = in_ctx;
> -
> -       if (mixer_ops && mixer_ops->wait_for_vblank)
> -               mixer_ops->wait_for_vblank(ctx->mixer_ctx->ctx);
> -}
> -
>  static void drm_hdmi_mode_fixup(void *in_ctx, struct drm_connector *connector,
>                                 const struct drm_display_mode *mode,
>                                 struct drm_display_mode *adjusted_mode)
> @@ -241,21 +218,57 @@ static void drm_hdmi_mode_fixup(void *in_ctx, struct drm_connector *connector,
>         }
>  }
>
> -static void drm_hdmi_mode_set(void *in_ctx, void *mode)
> +static void drm_hdmi_display_dpms(void *in_ctx, int mode)
>  {
>         struct drm_hdmi_context *ctx = in_ctx;
>
> -       if (hdmi_ops && hdmi_ops->mode_set)
> -               hdmi_ops->mode_set(ctx->hdmi_ctx->ctx, mode);
> +       if (hdmi_ops && hdmi_ops->dpms)
> +               hdmi_ops->dpms(ctx->hdmi_ctx->ctx, mode);
>  }
>
> -static void drm_hdmi_get_max_resol(void *in_ctx, unsigned int *width,
> -                               unsigned int *height)
> +static struct exynos_drm_display_ops drm_hdmi_display_ops = {
> +       .initialize = drm_hdmi_display_initialize,
> +       .is_connected = drm_hdmi_is_connected,
> +       .get_max_resol = drm_hdmi_get_max_resol,
> +       .get_edid = drm_hdmi_get_edid,
> +       .mode_fixup = drm_hdmi_mode_fixup,
> +       .mode_set = drm_hdmi_mode_set,
> +       .check_mode = drm_hdmi_check_mode,
> +       .dpms = drm_hdmi_display_dpms,
> +};
> +
> +static struct exynos_drm_display hdmi_display = {
> +       .type = EXYNOS_DISPLAY_TYPE_HDMI,
> +       .ops = &drm_hdmi_display_ops,
> +};
> +
> +static int drm_hdmi_enable_vblank(void *in_ctx)
>  {
>         struct drm_hdmi_context *ctx = in_ctx;
>
> -       if (hdmi_ops && hdmi_ops->get_max_resol)
> -               hdmi_ops->get_max_resol(ctx->hdmi_ctx->ctx, width, height);
> +       if (mixer_ops && mixer_ops->enable_vblank)
> +               return mixer_ops->enable_vblank(ctx->mixer_ctx->ctx,
> +                                               ctx->mixer_ctx->pipe);
> +
> +       return 0;
> +}
> +
> +static void drm_hdmi_disable_vblank(void *in_ctx)
> +{
> +       struct drm_hdmi_context *ctx = in_ctx;
> +
> +       DRM_DEBUG_KMS("%s\n", __FILE__);
> +
> +       if (mixer_ops && mixer_ops->disable_vblank)
> +               return mixer_ops->disable_vblank(ctx->mixer_ctx->ctx);
> +}
> +
> +static void drm_hdmi_wait_for_vblank(void *in_ctx)
> +{
> +       struct drm_hdmi_context *ctx = in_ctx;
> +
> +       if (mixer_ops && mixer_ops->wait_for_vblank)
> +               mixer_ops->wait_for_vblank(ctx->mixer_ctx->ctx);
>  }
>
>  static void drm_hdmi_commit(void *in_ctx)
> @@ -266,11 +279,19 @@ static void drm_hdmi_commit(void *in_ctx)
>                 hdmi_ops->commit(ctx->hdmi_ctx->ctx);
>  }
>
> -static int drm_hdmi_mgr_initialize(void *in_ctx, struct drm_device *drm_dev)
> +static int drm_hdmi_mgr_initialize(void *in_ctx, struct drm_device *drm_dev,
> +               int pipe)
>  {
>         struct drm_hdmi_context *ctx = in_ctx;
>         int ret = 0;
>
> +       if (!mixer_ctx) {
> +               DRM_ERROR("mixer context not initialized.\n");
> +               return -EFAULT;
> +       }
> +       ctx->mixer_ctx = mixer_ctx;
> +       ctx->mixer_ctx->pipe = pipe;
> +
>         if (mixer_ops && mixer_ops->initialize)
>                 ret = mixer_ops->initialize(ctx->mixer_ctx->ctx, drm_dev);
>
> @@ -280,6 +301,14 @@ static int drm_hdmi_mgr_initialize(void *in_ctx, struct drm_device *drm_dev)
>         return ret;
>  }
>
> +static void drm_hdmi_mgr_remove(void *in_ctx)
> +{
> +       struct drm_hdmi_context *ctx = in_ctx;
> +
> +       if (mixer_ops->iommu_on)
> +               mixer_ops->iommu_on(ctx->mixer_ctx->ctx, false);
> +}
> +
>  static void drm_hdmi_dpms(void *in_ctx, int mode)
>  {
>         struct drm_hdmi_context *ctx = in_ctx;
> @@ -350,14 +379,12 @@ static void drm_mixer_win_disable(void *in_ctx, int zpos)
>
>  static struct exynos_drm_manager_ops drm_hdmi_manager_ops = {
>         .initialize = drm_hdmi_mgr_initialize,
> +       .remove = drm_hdmi_mgr_remove,
>         .dpms = drm_hdmi_dpms,
>         .apply = drm_hdmi_apply,
>         .enable_vblank = drm_hdmi_enable_vblank,
>         .disable_vblank = drm_hdmi_disable_vblank,
>         .wait_for_vblank = drm_hdmi_wait_for_vblank,
> -       .mode_fixup = drm_hdmi_mode_fixup,
> -       .mode_set = drm_hdmi_mode_set,
> -       .get_max_resol = drm_hdmi_get_max_resol,
>         .commit = drm_hdmi_commit,
>         .win_mode_set = drm_mixer_win_mode_set,
>         .win_commit = drm_mixer_win_commit,
> @@ -365,82 +392,33 @@ static struct exynos_drm_manager_ops drm_hdmi_manager_ops = {
>  };
>
>  static struct exynos_drm_manager hdmi_manager = {
> -       .pipe           = -1,
> -       .ops            = &drm_hdmi_manager_ops,
> -       .display_ops    = &drm_hdmi_display_ops,
> +       .type = EXYNOS_DISPLAY_TYPE_HDMI,
> +       .ops = &drm_hdmi_manager_ops,
>  };
>
> -static int hdmi_subdrv_probe(struct drm_device *drm_dev,
> -               struct device *dev)
> -{
> -       struct exynos_drm_subdrv *subdrv = to_subdrv(dev);
> -       struct drm_hdmi_context *ctx;
> -
> -       if (!hdmi_ctx) {
> -               DRM_ERROR("hdmi context not initialized.\n");
> -               return -EFAULT;
> -       }
> -
> -       if (!mixer_ctx) {
> -               DRM_ERROR("mixer context not initialized.\n");
> -               return -EFAULT;
> -       }
> -
> -       ctx = get_ctx_from_subdrv(subdrv);
> -
> -       if (!ctx) {
> -               DRM_ERROR("no drm hdmi context.\n");
> -               return -EFAULT;
> -       }
> -
> -       ctx->hdmi_ctx = hdmi_ctx;
> -       ctx->mixer_ctx = mixer_ctx;
> -
> -       return 0;
> -}
> -
> -static void hdmi_subdrv_remove(struct drm_device *drm_dev, struct device *dev)
> -{
> -       struct drm_hdmi_context *ctx;
> -       struct exynos_drm_subdrv *subdrv = to_subdrv(dev);
> -
> -       ctx = get_ctx_from_subdrv(subdrv);
> -
> -       if (mixer_ops->iommu_on)
> -               mixer_ops->iommu_on(ctx->mixer_ctx->ctx, false);
> -}
> -
>  static int exynos_drm_hdmi_probe(struct platform_device *pdev)
>  {
> -       struct device *dev = &pdev->dev;
> -       struct exynos_drm_subdrv *subdrv;
>         struct drm_hdmi_context *ctx;
>
> -       ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
> +       ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
>         if (!ctx)
>                 return -ENOMEM;
>
>         hdmi_manager.ctx = ctx;
> +       exynos_drm_manager_register(&hdmi_manager);
>
> -       subdrv = &ctx->subdrv;
> -
> -       subdrv->dev = dev;
> -       subdrv->manager = &hdmi_manager;
> -       subdrv->probe = hdmi_subdrv_probe;
> -       subdrv->remove = hdmi_subdrv_remove;
> +       hdmi_display.ctx = ctx;
> +       exynos_drm_display_register(&hdmi_display);
>
> -       platform_set_drvdata(pdev, subdrv);
> -
> -       exynos_drm_subdrv_register(subdrv);
> +       platform_set_drvdata(pdev, ctx);
>
>         return 0;
>  }
>
>  static int exynos_drm_hdmi_remove(struct platform_device *pdev)
>  {
> -       struct drm_hdmi_context *ctx = platform_get_drvdata(pdev);
> -
> -       exynos_drm_subdrv_unregister(&ctx->subdrv);
> +       exynos_drm_display_unregister(&hdmi_display);
> +       exynos_drm_manager_unregister(&hdmi_manager);
>
>         return 0;
>  }
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.h b/drivers/gpu/drm/exynos/exynos_drm_hdmi.h
> index 923239b..37059ea 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.h
> +++ b/drivers/gpu/drm/exynos/exynos_drm_hdmi.h
> @@ -19,10 +19,12 @@
>   * exynos hdmi common context structure.
>   *
>   * @drm_dev: pointer to drm_device.
> + * @pipe: pipe for mixer
>   * @ctx: pointer to the context of specific device driver.
>   *     this context should be hdmi_context or mixer_context.
>   */
>  struct exynos_drm_hdmi_context {
> +       int                     pipe;
>         void                    *ctx;
>  };
>
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c
> index cff3aed..e0db2b3 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_plane.c
> +++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c
> @@ -13,7 +13,7 @@
>
>  #include <drm/exynos_drm.h>
>  #include "exynos_drm_drv.h"
> -#include "exynos_drm_encoder.h"
> +#include "exynos_drm_crtc.h"
>  #include "exynos_drm_fb.h"
>  #include "exynos_drm_gem.h"
>  #include "exynos_drm_plane.h"
> @@ -139,7 +139,7 @@ int exynos_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc,
>                         overlay->crtc_x, overlay->crtc_y,
>                         overlay->crtc_width, overlay->crtc_height);
>
> -       exynos_drm_fn_encoder(crtc, overlay, exynos_drm_encoder_plane_mode_set);
> +       exynos_drm_crtc_plane_mode_set(crtc, overlay);
>
>         return 0;
>  }
> @@ -149,8 +149,7 @@ void exynos_plane_commit(struct drm_plane *plane)
>         struct exynos_plane *exynos_plane = to_exynos_plane(plane);
>         struct exynos_drm_overlay *overlay = &exynos_plane->overlay;
>
> -       exynos_drm_fn_encoder(plane->crtc, &overlay->zpos,
> -                       exynos_drm_encoder_plane_commit);
> +       exynos_drm_crtc_plane_commit(plane->crtc, overlay->zpos);
>  }
>
>  void exynos_plane_dpms(struct drm_plane *plane, int mode)
> @@ -162,17 +161,13 @@ void exynos_plane_dpms(struct drm_plane *plane, int mode)
>                 if (exynos_plane->enabled)
>                         return;
>
> -               exynos_drm_fn_encoder(plane->crtc, &overlay->zpos,
> -                               exynos_drm_encoder_plane_enable);
> -
> +               exynos_drm_crtc_plane_enable(plane->crtc, overlay->zpos);
>                 exynos_plane->enabled = true;
>         } else {
>                 if (!exynos_plane->enabled)
>                         return;
>
> -               exynos_drm_fn_encoder(plane->crtc, &overlay->zpos,
> -                               exynos_drm_encoder_plane_disable);
> -
> +               exynos_drm_crtc_plane_disable(plane->crtc, overlay->zpos);
>                 exynos_plane->enabled = false;
>         }
>  }
> --
> 1.8.4
>
> _______________________________________________
> 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