From 1055b39facd1bf8f84031a07385f84b46a20540f Mon Sep 17 00:00:00 2001 From: Inki Dae Date: Fri, 19 Oct 2012 17:37:35 +0900 Subject: [PATCH] drm/exynos: add iommu support for hdmi driver 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 Signed-off-by: Kyungmin Park --- drivers/gpu/drm/exynos/exynos_drm_hdmi.c | 15 +++++++++++++++ drivers/gpu/drm/exynos/exynos_drm_hdmi.h | 1 + drivers/gpu/drm/exynos/exynos_hdmi.c | 2 +- drivers/gpu/drm/exynos/exynos_mixer.c | 23 +++++++++++++++++++++++ 4 files changed, 40 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c index c3b9e2b45185..2d11e70b601a 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c @@ -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); diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.h b/drivers/gpu/drm/exynos/exynos_drm_hdmi.h index 2da5ffd3a059..54b522353e48 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.h +++ b/drivers/gpu/drm/exynos/exynos_drm_hdmi.h @@ -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); diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 2c115f8a62a3..c73f43874944 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -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; diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index 0d3ed282376c..50100cfddf4e 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -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; -- 2.20.1