drm/exynos: add iommu support for hdmi driver
authorInki Dae <inki.dae@samsung.com>
Fri, 19 Oct 2012 08:37:35 +0000 (17:37 +0900)
committerInki Dae <inki.dae@samsung.com>
Tue, 4 Dec 2012 05:45:53 +0000 (14:45 +0900)
Changelog v2:
move iommu support feature to mixer side.
And below is Prathyush's comment.

According to the new IOMMU framework for exynos sysmmus,
the owner of the sysmmu-tv is mixer (which is the actual
device that does DMA) and not hdmi.
The mmu-master in sysmmu-tv node is set as below in exynos5250.dtsi
sysmmu-tv {
-
mmu-master = <&mixer>;
};

Changelog v1:
The iommu will be enabled when hdmi sub driver is probed and
will be disabled when removed.

Signed-off-by: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@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 c3b9e2b..2d11e70 100644 (file)
@@ -346,9 +346,23 @@ static int hdmi_subdrv_probe(struct drm_device *drm_dev,
        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;
 }
 
+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 __devinit exynos_drm_hdmi_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
@@ -368,6 +382,7 @@ static int __devinit exynos_drm_hdmi_probe(struct platform_device *pdev)
        subdrv->dev = dev;
        subdrv->manager = &hdmi_manager;
        subdrv->probe = hdmi_subdrv_probe;
+       subdrv->remove = hdmi_subdrv_remove;
 
        platform_set_drvdata(pdev, subdrv);
 
index 2da5ffd..54b5223 100644 (file)
@@ -62,6 +62,7 @@ struct exynos_hdmi_ops {
 
 struct exynos_mixer_ops {
        /* manager */
+       int (*iommu_on)(void *ctx, bool enable);
        int (*enable_vblank)(void *ctx, int pipe);
        void (*disable_vblank)(void *ctx);
        void (*dpms)(void *ctx, int mode);
index 2c115f8..c73f438 100644 (file)
@@ -74,6 +74,7 @@ struct hdmi_context {
        struct mutex                    hdmi_mutex;
 
        void __iomem                    *regs;
+       void                            *parent_ctx;
        int                             external_irq;
        int                             internal_irq;
 
@@ -84,7 +85,6 @@ struct hdmi_context {
        int cur_conf;
 
        struct hdmi_resources           res;
-       void                            *parent_ctx;
 
        int                             hpd_gpio;
 
index 0d3ed28..50100cf 100644 (file)
@@ -36,6 +36,7 @@
 
 #include "exynos_drm_drv.h"
 #include "exynos_drm_hdmi.h"
+#include "exynos_drm_iommu.h"
 
 #define get_mixer_context(dev) platform_get_drvdata(to_platform_device(dev))
 
@@ -80,6 +81,7 @@ enum mixer_version_id {
 
 struct mixer_context {
        struct device           *dev;
+       struct drm_device       *drm_dev;
        int                     pipe;
        bool                    interlace;
        bool                    powered;
@@ -90,6 +92,7 @@ struct mixer_context {
        struct mixer_resources  mixer_res;
        struct hdmi_win_data    win_data[MIXER_WIN_NR];
        enum mixer_version_id   mxr_ver;
+       void                    *parent_ctx;
 };
 
 struct mixer_drv_data {
@@ -665,6 +668,24 @@ static void mixer_win_reset(struct mixer_context *ctx)
        spin_unlock_irqrestore(&res->reg_slock, flags);
 }
 
+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 (enable)
+                       return drm_iommu_attach_device(drm_dev, mdata->dev);
+
+               drm_iommu_detach_device(drm_dev, mdata->dev);
+       }
+       return 0;
+}
+
 static void mixer_poweron(struct mixer_context *ctx)
 {
        struct mixer_resources *res = &ctx->mixer_res;
@@ -866,6 +887,7 @@ static void mixer_win_disable(void *ctx, int win)
 
 static struct exynos_mixer_ops mixer_ops = {
        /* manager */
+       .iommu_on               = mixer_iommu_on,
        .enable_vblank          = mixer_enable_vblank,
        .disable_vblank         = mixer_disable_vblank,
        .dpms                   = mixer_dpms,
@@ -1140,6 +1162,7 @@ static int __devinit mixer_probe(struct platform_device *pdev)
        }
 
        ctx->dev = &pdev->dev;
+       ctx->parent_ctx = (void *)drm_hdmi_ctx;
        drm_hdmi_ctx->ctx = (void *)ctx;
        ctx->vp_enabled = drv->is_vp_enabled;
        ctx->mxr_ver = drv->version;