drm/exynos: hdmi: Implement initialize op for hdmi
authorSean Paul <seanpaul@chromium.org>
Thu, 24 Apr 2014 11:44:39 +0000 (20:44 +0900)
committerMarek Szyprowski <m.szyprowski@samsung.com>
Thu, 15 May 2014 05:28:43 +0000 (07:28 +0200)
This patch implements the initialize callback in the hdmi and mixer
manager. This allows us to get rid of drm_dev in the drm_hdmi level and
track it in the mixer and hdmi drivers. This is one of the things
holding back the complete removal of the drm_hdmi layer.

Signed-off-by: Sean Paul <seanpaul@chromium.org>
Signed-off-by: Inki Dae <inki.dae@samsung.com>
drivers/gpu/drm/exynos/exynos_drm_hdmi.c
drivers/gpu/drm/exynos/exynos_drm_hdmi.h
drivers/gpu/drm/exynos/exynos_hdmi.c
drivers/gpu/drm/exynos/exynos_mixer.c

index 084a4a2..ef19945 100644 (file)
@@ -97,6 +97,18 @@ void exynos_mixer_ops_register(struct exynos_mixer_ops *ops)
                mixer_ops = ops;
 }
 
+static int drm_hdmi_display_initialize(struct device *dev,
+               struct drm_device *drm_dev)
+{
+       struct drm_hdmi_context *ctx = to_context(dev);
+
+       if (hdmi_ops && hdmi_ops->initialize)
+               return hdmi_ops->initialize(ctx->hdmi_ctx->ctx, drm_dev);
+
+       return 0;
+}
+
+
 static bool drm_hdmi_is_connected(struct device *dev)
 {
        struct drm_hdmi_context *ctx = to_context(dev);
@@ -153,6 +165,7 @@ static int drm_hdmi_power_on(struct device *dev, int 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,
@@ -257,6 +270,21 @@ static void drm_hdmi_commit(struct device *subdrv_dev)
                hdmi_ops->commit(ctx->hdmi_ctx->ctx);
 }
 
+static int drm_hdmi_mgr_initialize(struct device *subdrv_dev,
+               struct drm_device *drm_dev)
+{
+       struct drm_hdmi_context *ctx = to_context(subdrv_dev);
+       int ret = 0;
+
+       if (mixer_ops && mixer_ops->initialize)
+               ret = mixer_ops->initialize(ctx->mixer_ctx->ctx, drm_dev);
+
+       if (mixer_ops->iommu_on)
+               mixer_ops->iommu_on(ctx->mixer_ctx->ctx, true);
+
+       return ret;
+}
+
 static void drm_hdmi_dpms(struct device *subdrv_dev, int mode)
 {
        struct drm_hdmi_context *ctx = to_context(subdrv_dev);
@@ -326,6 +354,7 @@ static void drm_mixer_win_disable(struct device *subdrv_dev, int zpos)
 }
 
 static struct exynos_drm_manager_ops drm_hdmi_manager_ops = {
+       .initialize = drm_hdmi_mgr_initialize,
        .dpms = drm_hdmi_dpms,
        .apply = drm_hdmi_apply,
        .enable_vblank = drm_hdmi_enable_vblank,
@@ -372,12 +401,6 @@ static int hdmi_subdrv_probe(struct drm_device *drm_dev,
        ctx->hdmi_ctx = hdmi_ctx;
        ctx->mixer_ctx = mixer_ctx;
 
-       ctx->hdmi_ctx->drm_dev = drm_dev;
-       ctx->mixer_ctx->drm_dev = drm_dev;
-
-       if (mixer_ops->iommu_on)
-               mixer_ops->iommu_on(ctx->mixer_ctx->ctx, true);
-
        return 0;
 }
 
index 724cab1..cf7b1da 100644 (file)
  *     this context should be hdmi_context or mixer_context.
  */
 struct exynos_drm_hdmi_context {
-       struct drm_device       *drm_dev;
        void                    *ctx;
 };
 
 struct exynos_hdmi_ops {
        /* display */
+       int (*initialize)(void *ctx, struct drm_device *drm_dev);
        bool (*is_connected)(void *ctx);
        struct edid *(*get_edid)(void *ctx,
                        struct drm_connector *connector);
@@ -45,6 +45,7 @@ struct exynos_hdmi_ops {
 
 struct exynos_mixer_ops {
        /* manager */
+       int (*initialize)(void *ctx, struct drm_device *drm_dev);
        int (*iommu_on)(void *ctx, bool enable);
        int (*enable_vblank)(void *ctx, int pipe);
        void (*disable_vblank)(void *ctx);
index 2f041c1..079dac5 100644 (file)
@@ -788,6 +788,15 @@ static void hdmi_reg_infoframe(struct hdmi_context *hdata,
        }
 }
 
+static int hdmi_initialize(void *ctx, struct drm_device *drm_dev)
+{
+       struct hdmi_context *hdata = ctx;
+
+       hdata->drm_dev = drm_dev;
+
+       return 0;
+}
+
 static bool hdmi_is_connected(void *ctx)
 {
        struct hdmi_context *hdata = ctx;
@@ -1793,6 +1802,7 @@ static void hdmi_dpms(void *ctx, int mode)
 
 static struct exynos_hdmi_ops hdmi_ops = {
        /* display */
+       .initialize     = hdmi_initialize,
        .is_connected   = hdmi_is_connected,
        .get_edid       = hdmi_get_edid,
        .check_mode     = hdmi_check_mode,
@@ -1813,8 +1823,8 @@ static irqreturn_t hdmi_irq_thread(int irq, void *arg)
        hdata->hpd = gpio_get_value(hdata->hpd_gpio);
        mutex_unlock(&hdata->hdmi_mutex);
 
-       if (ctx->drm_dev)
-               drm_helper_hpd_irq_event(ctx->drm_dev);
+       if (hdata->drm_dev)
+               drm_helper_hpd_irq_event(hdata->drm_dev);
 
        return IRQ_HANDLED;
 }
@@ -2115,8 +2125,8 @@ static int hdmi_suspend(struct device *dev)
        disable_irq(hdata->irq);
 
        hdata->hpd = false;
-       if (ctx->drm_dev)
-               drm_helper_hpd_irq_event(ctx->drm_dev);
+       if (hdata->drm_dev)
+               drm_helper_hpd_irq_event(hdata->drm_dev);
 
        if (pm_runtime_suspended(dev)) {
                DRM_DEBUG_KMS("%s : Already suspended\n", __func__);
index e769faf..54ac5fd 100644 (file)
@@ -81,6 +81,7 @@ enum mixer_version_id {
 };
 
 struct mixer_context {
+       struct platform_device *pdev;
        struct device           *dev;
        struct drm_device       *drm_dev;
        int                     pipe;
@@ -673,20 +674,183 @@ static void mixer_win_reset(struct mixer_context *ctx)
        spin_unlock_irqrestore(&res->reg_slock, flags);
 }
 
+static irqreturn_t mixer_irq_handler(int irq, void *arg)
+{
+       struct mixer_context *ctx = arg;
+       struct mixer_resources *res = &ctx->mixer_res;
+       u32 val, base, shadow;
+
+       spin_lock(&res->reg_slock);
+
+       /* read interrupt status for handling and clearing flags for VSYNC */
+       val = mixer_reg_read(res, MXR_INT_STATUS);
+
+       /* handling VSYNC */
+       if (val & MXR_INT_STATUS_VSYNC) {
+               /* interlace scan need to check shadow register */
+               if (ctx->interlace) {
+                       base = mixer_reg_read(res, MXR_GRAPHIC_BASE(0));
+                       shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(0));
+                       if (base != shadow)
+                               goto out;
+
+                       base = mixer_reg_read(res, MXR_GRAPHIC_BASE(1));
+                       shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(1));
+                       if (base != shadow)
+                               goto out;
+               }
+
+               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)) {
+                       atomic_set(&ctx->wait_vsync_event, 0);
+                       wake_up(&ctx->wait_vsync_queue);
+               }
+       }
+
+out:
+       /* clear interrupts */
+       if (~val & MXR_INT_EN_VSYNC) {
+               /* vsync interrupt use different bit for read and clear */
+               val &= ~MXR_INT_EN_VSYNC;
+               val |= MXR_INT_CLEAR_VSYNC;
+       }
+       mixer_reg_write(res, MXR_INT_STATUS, val);
+
+       spin_unlock(&res->reg_slock);
+
+       return IRQ_HANDLED;
+}
+
+static int mixer_resources_init(struct mixer_context *mixer_ctx)
+{
+       struct device *dev = &mixer_ctx->pdev->dev;
+       struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
+       struct resource *res;
+       int ret;
+
+       spin_lock_init(&mixer_res->reg_slock);
+
+       mixer_res->mixer = devm_clk_get(dev, "mixer");
+       if (IS_ERR(mixer_res->mixer)) {
+               dev_err(dev, "failed to get clock 'mixer'\n");
+               return -ENODEV;
+       }
+
+       mixer_res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
+       if (IS_ERR(mixer_res->sclk_hdmi)) {
+               dev_err(dev, "failed to get clock 'sclk_hdmi'\n");
+               return -ENODEV;
+       }
+       res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_MEM, 0);
+       if (res == NULL) {
+               dev_err(dev, "get memory resource failed.\n");
+               return -ENXIO;
+       }
+
+       mixer_res->mixer_regs = devm_ioremap(dev, res->start,
+                                                       resource_size(res));
+       if (mixer_res->mixer_regs == NULL) {
+               dev_err(dev, "register mapping failed.\n");
+               return -ENXIO;
+       }
+
+       res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_IRQ, 0);
+       if (res == NULL) {
+               dev_err(dev, "get interrupt resource failed.\n");
+               return -ENXIO;
+       }
+
+       ret = devm_request_irq(dev, res->start, mixer_irq_handler,
+                                               0, "drm_mixer", mixer_ctx);
+       if (ret) {
+               dev_err(dev, "request interrupt failed.\n");
+               return ret;
+       }
+       mixer_res->irq = res->start;
+
+       return 0;
+}
+
+static int vp_resources_init(struct mixer_context *mixer_ctx)
+{
+       struct device *dev = &mixer_ctx->pdev->dev;
+       struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
+       struct resource *res;
+
+       mixer_res->vp = devm_clk_get(dev, "vp");
+       if (IS_ERR(mixer_res->vp)) {
+               dev_err(dev, "failed to get clock 'vp'\n");
+               return -ENODEV;
+       }
+       mixer_res->sclk_mixer = devm_clk_get(dev, "sclk_mixer");
+       if (IS_ERR(mixer_res->sclk_mixer)) {
+               dev_err(dev, "failed to get clock 'sclk_mixer'\n");
+               return -ENODEV;
+       }
+       mixer_res->sclk_dac = devm_clk_get(dev, "sclk_dac");
+       if (IS_ERR(mixer_res->sclk_dac)) {
+               dev_err(dev, "failed to get clock 'sclk_dac'\n");
+               return -ENODEV;
+       }
+
+       if (mixer_res->sclk_hdmi)
+               clk_set_parent(mixer_res->sclk_mixer, mixer_res->sclk_hdmi);
+
+       res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_MEM, 1);
+       if (res == NULL) {
+               dev_err(dev, "get memory resource failed.\n");
+               return -ENXIO;
+       }
+
+       mixer_res->vp_regs = devm_ioremap(dev, res->start,
+                                                       resource_size(res));
+       if (mixer_res->vp_regs == NULL) {
+               dev_err(dev, "register mapping failed.\n");
+               return -ENXIO;
+       }
+
+       return 0;
+}
+
+static int mixer_initialize(void *ctx, struct drm_device *drm_dev)
+{
+       int ret;
+       struct mixer_context *mixer_ctx = ctx;
+
+       mixer_ctx->drm_dev = drm_dev;
+
+       /* acquire resources: regs, irqs, clocks */
+       ret = mixer_resources_init(mixer_ctx);
+       if (ret) {
+               DRM_ERROR("mixer_resources_init failed ret=%d\n", ret);
+               return ret;
+       }
+
+       if (mixer_ctx->vp_enabled) {
+               /* acquire vp resources: regs, irqs, clocks */
+               ret = vp_resources_init(mixer_ctx);
+               if (ret) {
+                       DRM_ERROR("vp_resources_init failed ret=%d\n", ret);
+                       return ret;
+               }
+       }
+
+       return ret;
+}
+
 static int mixer_iommu_on(void *ctx, bool enable)
 {
-       struct exynos_drm_hdmi_context *drm_hdmi_ctx;
        struct mixer_context *mdata = ctx;
-       struct drm_device *drm_dev;
 
-       drm_hdmi_ctx = mdata->parent_ctx;
-       drm_dev = drm_hdmi_ctx->drm_dev;
-
-       if (is_drm_iommu_supported(drm_dev)) {
+       if (is_drm_iommu_supported(mdata->drm_dev)) {
                if (enable)
-                       return drm_iommu_attach_device(drm_dev, mdata->dev);
+                       return drm_iommu_attach_device(mdata->drm_dev,
+                                       mdata->dev);
 
-               drm_iommu_detach_device(drm_dev, mdata->dev);
+               drm_iommu_detach_device(mdata->drm_dev, mdata->dev);
        }
        return 0;
 }
@@ -953,6 +1117,7 @@ static void mixer_dpms(void *ctx, int mode)
 
 static struct exynos_mixer_ops mixer_ops = {
        /* manager */
+       .initialize             = mixer_initialize,
        .iommu_on               = mixer_iommu_on,
        .enable_vblank          = mixer_enable_vblank,
        .disable_vblank         = mixer_disable_vblank,
@@ -966,153 +1131,6 @@ static struct exynos_mixer_ops mixer_ops = {
        .check_mode             = mixer_check_mode,
 };
 
-static irqreturn_t mixer_irq_handler(int irq, void *arg)
-{
-       struct exynos_drm_hdmi_context *drm_hdmi_ctx = arg;
-       struct mixer_context *ctx = drm_hdmi_ctx->ctx;
-       struct mixer_resources *res = &ctx->mixer_res;
-       u32 val, base, shadow;
-
-       spin_lock(&res->reg_slock);
-
-       /* read interrupt status for handling and clearing flags for VSYNC */
-       val = mixer_reg_read(res, MXR_INT_STATUS);
-
-       /* handling VSYNC */
-       if (val & MXR_INT_STATUS_VSYNC) {
-               /* interlace scan need to check shadow register */
-               if (ctx->interlace) {
-                       base = mixer_reg_read(res, MXR_GRAPHIC_BASE(0));
-                       shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(0));
-                       if (base != shadow)
-                               goto out;
-
-                       base = mixer_reg_read(res, MXR_GRAPHIC_BASE(1));
-                       shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(1));
-                       if (base != shadow)
-                               goto out;
-               }
-
-               drm_handle_vblank(drm_hdmi_ctx->drm_dev, ctx->pipe);
-               exynos_drm_crtc_finish_pageflip(drm_hdmi_ctx->drm_dev,
-                               ctx->pipe);
-
-               /* set wait vsync event to zero and wake up queue. */
-               if (atomic_read(&ctx->wait_vsync_event)) {
-                       atomic_set(&ctx->wait_vsync_event, 0);
-                       DRM_WAKEUP(&ctx->wait_vsync_queue);
-               }
-       }
-
-out:
-       /* clear interrupts */
-       if (~val & MXR_INT_EN_VSYNC) {
-               /* vsync interrupt use different bit for read and clear */
-               val &= ~MXR_INT_EN_VSYNC;
-               val |= MXR_INT_CLEAR_VSYNC;
-       }
-       mixer_reg_write(res, MXR_INT_STATUS, val);
-
-       spin_unlock(&res->reg_slock);
-
-       return IRQ_HANDLED;
-}
-
-static int mixer_resources_init(struct exynos_drm_hdmi_context *ctx,
-                               struct platform_device *pdev)
-{
-       struct mixer_context *mixer_ctx = ctx->ctx;
-       struct device *dev = &pdev->dev;
-       struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
-       struct resource *res;
-       int ret;
-
-       spin_lock_init(&mixer_res->reg_slock);
-
-       mixer_res->mixer = devm_clk_get(dev, "mixer");
-       if (IS_ERR(mixer_res->mixer)) {
-               dev_err(dev, "failed to get clock 'mixer'\n");
-               return -ENODEV;
-       }
-
-       mixer_res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
-       if (IS_ERR(mixer_res->sclk_hdmi)) {
-               dev_err(dev, "failed to get clock 'sclk_hdmi'\n");
-               return -ENODEV;
-       }
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (res == NULL) {
-               dev_err(dev, "get memory resource failed.\n");
-               return -ENXIO;
-       }
-
-       mixer_res->mixer_regs = devm_ioremap(dev, res->start,
-                                                       resource_size(res));
-       if (mixer_res->mixer_regs == NULL) {
-               dev_err(dev, "register mapping failed.\n");
-               return -ENXIO;
-       }
-
-       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-       if (res == NULL) {
-               dev_err(dev, "get interrupt resource failed.\n");
-               return -ENXIO;
-       }
-
-       ret = devm_request_irq(dev, res->start, mixer_irq_handler,
-                                                       0, "drm_mixer", ctx);
-       if (ret) {
-               dev_err(dev, "request interrupt failed.\n");
-               return ret;
-       }
-       mixer_res->irq = res->start;
-
-       return 0;
-}
-
-static int vp_resources_init(struct exynos_drm_hdmi_context *ctx,
-                            struct platform_device *pdev)
-{
-       struct mixer_context *mixer_ctx = ctx->ctx;
-       struct device *dev = &pdev->dev;
-       struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
-       struct resource *res;
-
-       mixer_res->vp = devm_clk_get(dev, "vp");
-       if (IS_ERR(mixer_res->vp)) {
-               dev_err(dev, "failed to get clock 'vp'\n");
-               return -ENODEV;
-       }
-       mixer_res->sclk_mixer = devm_clk_get(dev, "sclk_mixer");
-       if (IS_ERR(mixer_res->sclk_mixer)) {
-               dev_err(dev, "failed to get clock 'sclk_mixer'\n");
-               return -ENODEV;
-       }
-       mixer_res->sclk_dac = devm_clk_get(dev, "sclk_dac");
-       if (IS_ERR(mixer_res->sclk_dac)) {
-               dev_err(dev, "failed to get clock 'sclk_dac'\n");
-               return -ENODEV;
-       }
-
-       if (mixer_res->sclk_hdmi)
-               clk_set_parent(mixer_res->sclk_mixer, mixer_res->sclk_hdmi);
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-       if (res == NULL) {
-               dev_err(dev, "get memory resource failed.\n");
-               return -ENXIO;
-       }
-
-       mixer_res->vp_regs = devm_ioremap(dev, res->start,
-                                                       resource_size(res));
-       if (mixer_res->vp_regs == NULL) {
-               dev_err(dev, "register mapping failed.\n");
-               return -ENXIO;
-       }
-
-       return 0;
-}
-
 static struct mixer_drv_data exynos5_mxr_drv_data = {
        .version = MXR_VER_16_0_33_0,
        .is_vp_enabled = 0,
@@ -1153,7 +1171,6 @@ static int mixer_probe(struct platform_device *pdev)
        struct exynos_drm_hdmi_context *drm_hdmi_ctx;
        struct mixer_context *ctx;
        struct mixer_drv_data *drv;
-       int ret;
 
        dev_info(dev, "probe start\n");
 
@@ -1177,6 +1194,7 @@ static int mixer_probe(struct platform_device *pdev)
                        platform_get_device_id(pdev)->driver_data;
        }
 
+       ctx->pdev = pdev;
        ctx->dev = dev;
        ctx->parent_ctx = (void *)drm_hdmi_ctx;
        drm_hdmi_ctx->ctx = (void *)ctx;
@@ -1187,22 +1205,6 @@ static int mixer_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, drm_hdmi_ctx);
 
-       /* acquire resources: regs, irqs, clocks */
-       ret = mixer_resources_init(drm_hdmi_ctx, pdev);
-       if (ret) {
-               DRM_ERROR("mixer_resources_init failed\n");
-               goto fail;
-       }
-
-       if (ctx->vp_enabled) {
-               /* acquire vp resources: regs, irqs, clocks */
-               ret = vp_resources_init(drm_hdmi_ctx, pdev);
-               if (ret) {
-                       DRM_ERROR("vp_resources_init failed\n");
-                       goto fail;
-               }
-       }
-
        /* attach mixer driver to common hdmi. */
        exynos_mixer_drv_attach(drm_hdmi_ctx);
 
@@ -1212,11 +1214,6 @@ static int mixer_probe(struct platform_device *pdev)
        pm_runtime_enable(dev);
 
        return 0;
-
-
-fail:
-       dev_info(dev, "probe failed\n");
-       return ret;
 }
 
 static int mixer_remove(struct platform_device *pdev)