[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