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 <inki.dae@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
This commit is contained in:
Inki Dae 2012-10-19 17:37:35 +09:00
parent bcc5cd1c5f
commit 1055b39fac
4 changed files with 40 additions and 1 deletions

View File

@ -346,9 +346,23 @@ static int hdmi_subdrv_probe(struct drm_device *drm_dev,
ctx->hdmi_ctx->drm_dev = drm_dev; ctx->hdmi_ctx->drm_dev = drm_dev;
ctx->mixer_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; 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) static int __devinit exynos_drm_hdmi_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
@ -368,6 +382,7 @@ static int __devinit exynos_drm_hdmi_probe(struct platform_device *pdev)
subdrv->dev = dev; subdrv->dev = dev;
subdrv->manager = &hdmi_manager; subdrv->manager = &hdmi_manager;
subdrv->probe = hdmi_subdrv_probe; subdrv->probe = hdmi_subdrv_probe;
subdrv->remove = hdmi_subdrv_remove;
platform_set_drvdata(pdev, subdrv); platform_set_drvdata(pdev, subdrv);

View File

@ -62,6 +62,7 @@ struct exynos_hdmi_ops {
struct exynos_mixer_ops { struct exynos_mixer_ops {
/* manager */ /* manager */
int (*iommu_on)(void *ctx, bool enable);
int (*enable_vblank)(void *ctx, int pipe); int (*enable_vblank)(void *ctx, int pipe);
void (*disable_vblank)(void *ctx); void (*disable_vblank)(void *ctx);
void (*dpms)(void *ctx, int mode); void (*dpms)(void *ctx, int mode);

View File

@ -74,6 +74,7 @@ struct hdmi_context {
struct mutex hdmi_mutex; struct mutex hdmi_mutex;
void __iomem *regs; void __iomem *regs;
void *parent_ctx;
int external_irq; int external_irq;
int internal_irq; int internal_irq;
@ -84,7 +85,6 @@ struct hdmi_context {
int cur_conf; int cur_conf;
struct hdmi_resources res; struct hdmi_resources res;
void *parent_ctx;
int hpd_gpio; int hpd_gpio;

View File

@ -36,6 +36,7 @@
#include "exynos_drm_drv.h" #include "exynos_drm_drv.h"
#include "exynos_drm_hdmi.h" #include "exynos_drm_hdmi.h"
#include "exynos_drm_iommu.h"
#define get_mixer_context(dev) platform_get_drvdata(to_platform_device(dev)) #define get_mixer_context(dev) platform_get_drvdata(to_platform_device(dev))
@ -80,6 +81,7 @@ enum mixer_version_id {
struct mixer_context { struct mixer_context {
struct device *dev; struct device *dev;
struct drm_device *drm_dev;
int pipe; int pipe;
bool interlace; bool interlace;
bool powered; bool powered;
@ -90,6 +92,7 @@ struct mixer_context {
struct mixer_resources mixer_res; struct mixer_resources mixer_res;
struct hdmi_win_data win_data[MIXER_WIN_NR]; struct hdmi_win_data win_data[MIXER_WIN_NR];
enum mixer_version_id mxr_ver; enum mixer_version_id mxr_ver;
void *parent_ctx;
}; };
struct mixer_drv_data { struct mixer_drv_data {
@ -665,6 +668,24 @@ static void mixer_win_reset(struct mixer_context *ctx)
spin_unlock_irqrestore(&res->reg_slock, flags); 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) static void mixer_poweron(struct mixer_context *ctx)
{ {
struct mixer_resources *res = &ctx->mixer_res; 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 = { static struct exynos_mixer_ops mixer_ops = {
/* manager */ /* manager */
.iommu_on = mixer_iommu_on,
.enable_vblank = mixer_enable_vblank, .enable_vblank = mixer_enable_vblank,
.disable_vblank = mixer_disable_vblank, .disable_vblank = mixer_disable_vblank,
.dpms = mixer_dpms, .dpms = mixer_dpms,
@ -1140,6 +1162,7 @@ static int __devinit mixer_probe(struct platform_device *pdev)
} }
ctx->dev = &pdev->dev; ctx->dev = &pdev->dev;
ctx->parent_ctx = (void *)drm_hdmi_ctx;
drm_hdmi_ctx->ctx = (void *)ctx; drm_hdmi_ctx->ctx = (void *)ctx;
ctx->vp_enabled = drv->is_vp_enabled; ctx->vp_enabled = drv->is_vp_enabled;
ctx->mxr_ver = drv->version; ctx->mxr_ver = drv->version;