[PATCH v2] drm/exynos: add iommu support for hdmi driver

2012-12-04 Thread Inki Dae
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 = <>;
};

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 deletions(-)

diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c 
b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
index c3b9e2b..2d11e70 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 = >dev;
@@ -368,6 +382,7 @@ static int __devinit exynos_drm_hdmi_probe(struct 
platform_device *pdev)
subdrv->dev = dev;
subdrv->manager = _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 2da5ffd..54b5223 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 2c115f8..c73f438 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 mutexhdmi_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 0d3ed28..50100cf 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;
boolinterlace;
boolpowered;
@@ -90,6 +92,7 @@ struct mixer_context {
struct mixer_resources  mixer_res;
struct hdmi_win_datawin_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(>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 = >mixer_res;

[PATCH v2] drm/exynos: add iommu support for hdmi driver

2012-12-03 Thread Inki Dae
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@samsung.com
Signed-off-by: Kyungmin Park kyungmin.p...@samsung.com
---
 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 deletions(-)

diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c 
b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
index c3b9e2b..2d11e70 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 2da5ffd..54b5223 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 2c115f8..c73f438 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 mutexhdmi_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 0d3ed28..50100cf 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;
boolinterlace;
boolpowered;
@@ -90,6 +92,7 @@ struct mixer_context {
struct mixer_resources  mixer_res;
struct hdmi_win_datawin_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)
 {