#include "exynos_drm_drv.h"
#include "exynos_drm_hdmi.h"
+#include <plat/map-base.h>
+#ifdef CONFIG_EXYNOS_IOMMU
+#include <mach/sysmmu.h>
+#include <linux/of_platform.h>
+#endif
+
#define MIXER_WIN_NR 3
#define MIXER_DEFAULT_WIN 0
void __iomem *mixer_regs;
void __iomem *vp_regs;
spinlock_t reg_slock;
+ wait_queue_head_t event_queue;
struct clk *mixer;
struct clk *vp;
struct clk *sclk_mixer;
struct clk *sclk_hdmi;
struct clk *sclk_dac;
+ unsigned int is_soc_exynos5;
};
struct mixer_context {
struct mixer_resources mixer_res;
struct hdmi_win_data win_data[MIXER_WIN_NR];
+ unsigned long event_flags;
+};
+
+/* event flags used */
+enum mixer_status_flags {
+ MXR_EVENT_VSYNC = 1,
};
static const u8 filter_y_horiz_tap8[] = {
70, 59, 48, 37, 27, 19, 11, 5,
};
+static void mixer_win_reset(struct mixer_context *ctx);
+
static inline u32 vp_reg_read(struct mixer_resources *res, u32 reg_id)
{
return readl(res->vp_regs + reg_id);
mixer_reg_writemask(res, MXR_STATUS, enable ?
MXR_STATUS_SYNC_ENABLE : 0, MXR_STATUS_SYNC_ENABLE);
- vp_reg_write(res, VP_SHADOW_UPDATE, enable ?
- VP_SHADOW_UPDATE_ENABLE : 0);
+ if (!(res->is_soc_exynos5))
+ vp_reg_write(res, VP_SHADOW_UPDATE, enable ?
+ VP_SHADOW_UPDATE_ENABLE : 0);
}
static void mixer_cfg_scan(struct mixer_context *ctx, unsigned int height)
mixer_regs_dump(ctx);
}
+static int mixer_wait_for_vsync(struct mixer_context *ctx)
+{
+ int ret;
+
+ ctx->event_flags |= MXR_EVENT_VSYNC;
+
+ ret = wait_event_timeout(ctx->mixer_res.event_queue,
+ ((ctx->event_flags & MXR_EVENT_VSYNC) == 0), msecs_to_jiffies(1000));
+ if (ret > 0)
+ return 0;
+
+ return -ETIME;
+}
+
static void vp_video_buffer(struct mixer_context *ctx, int win)
{
struct mixer_resources *res = &ctx->mixer_res;
mixer_cfg_scan(ctx, mode_height);
mixer_cfg_rgb_fmt(ctx, mode_height);
mixer_cfg_layer(ctx, win, true);
+ mixer_cfg_layer(ctx, MIXER_DEFAULT_WIN, true);
mixer_run(ctx);
mixer_vsync_set_update(ctx, true);
DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
- mixer_ctx->pipe = pipe;
-
/* enable vsync interrupt */
mixer_reg_writemask(res, MXR_INT_EN, MXR_INT_EN_VSYNC,
MXR_INT_EN_VSYNC);
win_data->fb_x = overlay->fb_x;
win_data->fb_y = overlay->fb_y;
- win_data->fb_width = overlay->fb_width;
+ win_data->fb_width = overlay->fb_pitch / (overlay->bpp >> 3);
win_data->fb_height = overlay->fb_height;
win_data->mode_width = overlay->mode_width;
static void mixer_win_commit(void *ctx, int zpos)
{
struct mixer_context *mixer_ctx = ctx;
+ struct mixer_resources *res = &mixer_ctx->mixer_res;
int win = zpos;
DRM_DEBUG_KMS("[%d] %s, win: %d\n", __LINE__, __func__, win);
return;
}
- if (win > 1)
- vp_video_buffer(mixer_ctx, win);
+ if (!(res->is_soc_exynos5)) {
+ if (win > 1)
+ vp_video_buffer(mixer_ctx, win);
+ else
+ mixer_graph_buffer(mixer_ctx, win);
+ }
else
mixer_graph_buffer(mixer_ctx, win);
}
return;
}
+ mixer_wait_for_vsync(mixer_ctx);
+
spin_lock_irqsave(&res->reg_slock, flags);
mixer_vsync_set_update(mixer_ctx, false);
mixer_cfg_layer(mixer_ctx, win, false);
mixer_vsync_set_update(mixer_ctx, true);
+
spin_unlock_irqrestore(&res->reg_slock, flags);
+
+ if (win == MIXER_DEFAULT_WIN) {
+ mixer_win_reset(ctx);
+ mixer_enable_vblank(ctx, 0);
+ }
}
static struct exynos_mixer_ops mixer_ops = {
/* handling VSYNC */
if (val & MXR_INT_STATUS_VSYNC) {
+
+ if (ctx->event_flags & MXR_EVENT_VSYNC) {
+ DRM_DEBUG_KMS("ctx->event_flags & MXR_EVENT_VSYNC");
+
+
+ mixer_reg_write(res, MXR_GRAPHIC_WH(1), 0);
+ mixer_reg_write(res, MXR_GRAPHIC_SPAN(1), 0);
+ mixer_reg_write(res, MXR_GRAPHIC_SXY(1), 0);
+ mixer_reg_write(res, MXR_GRAPHIC_DXY(1), 0);
+
+ ctx->event_flags &= ~MXR_EVENT_VSYNC;
+ wake_up(&ctx->mixer_res.event_queue);
+
+ goto out;
+ }
+
/* interlace scan need to check shadow register */
if (ctx->interlace) {
val_base = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(0));
drm_handle_vblank(drm_hdmi_ctx->drm_dev, ctx->pipe);
mixer_finish_pageflip(drm_hdmi_ctx->drm_dev, ctx->pipe);
+
+ /* layer update mandatory for exynos5 soc,and not present
+ * in exynos4 */
+ if (res->is_soc_exynos5)
+ mixer_reg_writemask(res, MXR_CFG, ~0, MXR_CFG_LAYER_UPDATE);
}
out:
u32 val; /* value stored to register */
spin_lock_irqsave(&res->reg_slock, flags);
+ mixer_reg_writemask(res, MXR_STATUS, ~0, MXR_STATUS_SOFT_RESET);
mixer_vsync_set_update(ctx, false);
mixer_reg_writemask(res, MXR_CFG, MXR_CFG_DST_HDMI, MXR_CFG_DST_MASK);
val |= MXR_GRP_CFG_PIXEL_BLEND_EN;
mixer_reg_write(res, MXR_GRAPHIC_CFG(1), val);
- /* configuration of Video Processor Registers */
- vp_win_reset(ctx);
- vp_default_filter(res);
+ if (!(res->is_soc_exynos5)) {
+ /* configuration of Video Processor for Exynos4 soc */
+ vp_win_reset(ctx);
+ vp_default_filter(res);
+ }
/* disable all layers */
mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP0_ENABLE);
mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP1_ENABLE);
mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_VP_ENABLE);
+ mixer_reg_writemask(res, MXR_INT_EN, ~0, MXR_INT_EN_ALL);
+
mixer_vsync_set_update(ctx, true);
spin_unlock_irqrestore(&res->reg_slock, flags);
}
DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
clk_enable(res->mixer);
- clk_enable(res->vp);
- clk_enable(res->sclk_mixer);
+ if (!(res->is_soc_exynos5)) {
+ clk_enable(res->vp);
+ clk_enable(res->sclk_mixer);
+ }
mixer_win_reset(ctx);
}
DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
clk_disable(res->mixer);
- clk_disable(res->vp);
- clk_disable(res->sclk_mixer);
+ if (!(res->is_soc_exynos5)) {
+ clk_disable(res->vp);
+ clk_disable(res->sclk_mixer);
+ }
}
static int mixer_runtime_resume(struct device *dev)
.runtime_resume = mixer_runtime_resume,
};
-static int __devinit mixer_resources_init(struct exynos_drm_hdmi_context *ctx,
- struct platform_device *pdev)
+#ifdef CONFIG_EXYNOS_IOMMU
+static int iommu_init(struct platform_device *pdev)
+{
+ struct platform_device *pds;
+
+ pds = find_sysmmu_dt(pdev, "sysmmu");
+ if (pds == NULL) {
+ printk(KERN_ERR "No sysmmu found :\n");
+ return -EINVAL;
+ }
+
+ platform_set_sysmmu(&pds->dev, &pdev->dev);
+ exynos_drm_common_mapping = s5p_create_iommu_mapping(&pdev->dev,
+ 0x20000000, SZ_128M, 4, exynos_drm_common_mapping);
+ if(exynos_drm_common_mapping == NULL) {
+ printk(KERN_ERR"Failed to create iommu mapping for Mixer\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+#endif
+
+static int __devinit mixer_resources_init_exynos(
+ struct exynos_drm_hdmi_context *ctx,
+ struct platform_device *pdev,
+ int is_exynos5)
{
struct mixer_context *mixer_ctx = ctx->ctx;
struct device *dev = &pdev->dev;
struct resource *res;
int ret;
+ DRM_DEBUG_KMS("Mixer resources init\n");
+
+ mixer_res->is_soc_exynos5 = is_exynos5;
mixer_res->dev = dev;
spin_lock_init(&mixer_res->reg_slock);
+ if(is_exynos5)
+ init_waitqueue_head(&mixer_res->event_queue);
+
mixer_res->mixer = clk_get(dev, "mixer");
if (IS_ERR_OR_NULL(mixer_res->mixer)) {
dev_err(dev, "failed to get clock 'mixer'\n");
ret = -ENODEV;
goto fail;
}
- mixer_res->vp = clk_get(dev, "vp");
- if (IS_ERR_OR_NULL(mixer_res->vp)) {
- dev_err(dev, "failed to get clock 'vp'\n");
- ret = -ENODEV;
- goto fail;
- }
- mixer_res->sclk_mixer = clk_get(dev, "sclk_mixer");
- if (IS_ERR_OR_NULL(mixer_res->sclk_mixer)) {
- dev_err(dev, "failed to get clock 'sclk_mixer'\n");
- ret = -ENODEV;
- goto fail;
+ if(!is_exynos5) {
+ mixer_res->vp = clk_get(dev, "vp");
+ if (IS_ERR_OR_NULL(mixer_res->vp)) {
+ dev_err(dev, "failed to get clock 'vp'\n");
+ ret = -ENODEV;
+ goto fail;
+ }
+ mixer_res->sclk_mixer = clk_get(dev, "sclk_mixer");
+ if (IS_ERR_OR_NULL(mixer_res->sclk_mixer)) {
+ dev_err(dev, "failed to get clock 'sclk_mixer'\n");
+ ret = -ENODEV;
+ goto fail;
+ }
}
mixer_res->sclk_hdmi = clk_get(dev, "sclk_hdmi");
if (IS_ERR_OR_NULL(mixer_res->sclk_hdmi)) {
ret = -ENODEV;
goto fail;
}
- mixer_res->sclk_dac = clk_get(dev, "sclk_dac");
- if (IS_ERR_OR_NULL(mixer_res->sclk_dac)) {
- dev_err(dev, "failed to get clock 'sclk_dac'\n");
- ret = -ENODEV;
- goto fail;
+ if(!is_exynos5) {
+ mixer_res->sclk_dac = clk_get(dev, "sclk_dac");
+ if (IS_ERR_OR_NULL(mixer_res->sclk_dac)) {
+ dev_err(dev, "failed to get clock 'sclk_dac'\n");
+ ret = -ENODEV;
+ goto fail;
+ }
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mxr");
}
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mxr");
+ else
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
if (res == NULL) {
dev_err(dev, "get memory resource failed.\n");
ret = -ENXIO;
goto fail;
}
- clk_set_parent(mixer_res->sclk_mixer, mixer_res->sclk_hdmi);
+ if(!is_exynos5)
+ clk_set_parent(mixer_res->sclk_mixer, mixer_res->sclk_hdmi);
mixer_res->mixer_regs = ioremap(res->start, resource_size(res));
if (mixer_res->mixer_regs == NULL) {
goto fail;
}
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vp");
- if (res == NULL) {
- dev_err(dev, "get memory resource failed.\n");
- ret = -ENXIO;
- goto fail_mixer_regs;
- }
+ if(!is_exynos5) {
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vp");
+ if (res == NULL) {
+ dev_err(dev, "get memory resource failed.\n");
+ ret = -ENXIO;
+ goto fail_vp_regs;
+ }
- mixer_res->vp_regs = ioremap(res->start, resource_size(res));
- if (mixer_res->vp_regs == NULL) {
- dev_err(dev, "register mapping failed.\n");
- ret = -ENXIO;
- goto fail_mixer_regs;
- }
+ mixer_res->vp_regs = ioremap(res->start, resource_size(res));
+ if (mixer_res->vp_regs == NULL) {
+ dev_err(dev, "register mapping failed.\n");
+ ret = -ENXIO;
+ goto fail_vp_regs;
+ }
- res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "irq");
- if (res == NULL) {
- dev_err(dev, "get interrupt resource failed.\n");
- ret = -ENXIO;
- goto fail_vp_regs;
+ res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "irq");
+ if (res == NULL) {
+ dev_err(dev, "get interrupt resource failed.\n");
+ ret = -ENXIO;
+ goto fail_vp_regs;
+ }
+ }else {
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (res == NULL) {
+ dev_err(dev, "get interrupt resource failed.\n");
+ ret = -ENXIO;
+ goto fail_mixer_regs;
+ }
}
ret = request_irq(res->start, mixer_irq_handler, 0, "drm_mixer", ctx);
if (ret) {
dev_err(dev, "request interrupt failed.\n");
- goto fail_vp_regs;
+ goto fail_mixer_regs;
}
mixer_res->irq = res->start;
+#ifdef CONFIG_EXYNOS_IOMMU
+ ret = iommu_init(pdev);
+ if(ret) {
+ dev_err(dev, "iommu init failed.\n");
+ goto fail_mixer_regs;
+ }
+#endif
return 0;
fail_vp_regs:
{
struct device *dev = &pdev->dev;
struct exynos_drm_hdmi_context *drm_hdmi_ctx;
+ struct exynos_drm_hdmi_pdata *pdata;
struct mixer_context *ctx;
int ret;
platform_set_drvdata(pdev, drm_hdmi_ctx);
+ /* Get from Platform soc deatils */
+ pdata = pdev->dev.platform_data;
+
/* acquire resources: regs, irqs, clocks */
- ret = mixer_resources_init(drm_hdmi_ctx, pdev);
+ ret = mixer_resources_init_exynos(drm_hdmi_ctx, pdev,pdata->is_soc_exynos5);
if (ret)
goto fail;
+ /* attach mixer driver to common hdmi. */
+ exynos_mixer_drv_attach(drm_hdmi_ctx);
+
/* register specific callback point to common hdmi. */
exynos_mixer_ops_register(&mixer_ops);