diff options
author | Rahul Sharma <rahul.sharma@samsung.com> | 2013-05-13 12:59:16 +0530 |
---|---|---|
committer | Tushar Behera <tushar.behera@linaro.org> | 2013-05-14 11:01:08 +0530 |
commit | 9afff744fadf3c1463bf49e86269c0580f469c02 (patch) | |
tree | d31f2e8539247ba46a0ab958252b312daa0fe4eb | |
parent | fa3822f93b42ab0dab8e00fe03ffbff6c5dfd153 (diff) |
s5p-tv: add support for dt based exynos5 mixer
Signed-off-by: Rahul Sharma <rahul.sharma@samsung.com>
-rw-r--r-- | drivers/media/platform/s5p-tv/mixer.h | 9 | ||||
-rw-r--r-- | drivers/media/platform/s5p-tv/mixer_drv.c | 178 | ||||
-rw-r--r-- | drivers/media/platform/s5p-tv/mixer_reg.c | 37 | ||||
-rw-r--r-- | drivers/media/platform/s5p-tv/regs-mixer.h | 19 |
4 files changed, 184 insertions, 59 deletions
diff --git a/drivers/media/platform/s5p-tv/mixer.h b/drivers/media/platform/s5p-tv/mixer.h index 7095e0a5fc6..f3912cb34af 100644 --- a/drivers/media/platform/s5p-tv/mixer.h +++ b/drivers/media/platform/s5p-tv/mixer.h @@ -232,6 +232,11 @@ enum mxr_devide_flags { MXR_EVENT_TOP = 1, }; +enum mixer_version_id { + MXR_VER_0_0_0_16, + MXR_VER_16_0_33_0, +}; + /** drivers instance */ struct mxr_device { /** master device */ @@ -267,6 +272,10 @@ struct mxr_device { int current_output; /** auxiliary resources used my mixer */ struct mxr_resources res; + /** is Video Processor is enabled */ + bool vp_enabled; + /** is Video Processor is enabled */ + enum mixer_version_id mxr_ver; }; /** transform device structure into mixer device */ diff --git a/drivers/media/platform/s5p-tv/mixer_drv.c b/drivers/media/platform/s5p-tv/mixer_drv.c index 202c50066c6..f6a1c76b72e 100644 --- a/drivers/media/platform/s5p-tv/mixer_drv.c +++ b/drivers/media/platform/s5p-tv/mixer_drv.c @@ -66,10 +66,12 @@ void mxr_streamer_get(struct mxr_device *mdev) struct mxr_resources *res = &mdev->res; int ret; - if (to_output(mdev)->cookie == 0) - clk_set_parent(res->sclk_mixer, res->sclk_dac); - else - clk_set_parent(res->sclk_mixer, res->sclk_hdmi); + if (mdev->vp_enabled) { + if (to_output(mdev)->cookie == 0) + clk_set_parent(res->sclk_mixer, res->sclk_dac); + else + clk_set_parent(res->sclk_mixer, res->sclk_hdmi); + } mxr_reg_s_output(mdev, to_output(mdev)->cookie); ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mbus_fmt); @@ -171,18 +173,20 @@ static int mxr_acquire_plat_resources(struct mxr_device *mdev, goto fail; } - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vp"); - if (res == NULL) { - mxr_err(mdev, "get memory resource failed.\n"); - ret = -ENXIO; - goto fail_mxr_regs; - } - - mdev->res.vp_regs = ioremap(res->start, resource_size(res)); - if (mdev->res.vp_regs == NULL) { - mxr_err(mdev, "register mapping failed.\n"); - ret = -ENXIO; - goto fail_mxr_regs; + if (mdev->vp_enabled) { + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vp"); + if (res == NULL) { + mxr_err(mdev, "get memory resource failed.\n"); + ret = -ENXIO; + goto fail_mxr_regs; + } + + mdev->res.vp_regs = ioremap(res->start, resource_size(res)); + if (mdev->res.vp_regs == NULL) { + mxr_err(mdev, "register mapping failed.\n"); + ret = -ENXIO; + goto fail_mxr_regs; + } } res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "irq"); @@ -202,7 +206,8 @@ static int mxr_acquire_plat_resources(struct mxr_device *mdev, return 0; fail_vp_regs: - iounmap(mdev->res.vp_regs); + if (mdev->vp_enabled) + iounmap(mdev->res.vp_regs); fail_mxr_regs: iounmap(mdev->res.mxr_regs); @@ -214,7 +219,8 @@ fail: static void mxr_release_plat_resources(struct mxr_device *mdev) { free_irq(mdev->res.irq, mdev); - iounmap(mdev->res.vp_regs); + if (mdev->vp_enabled) + iounmap(mdev->res.vp_regs); iounmap(mdev->res.mxr_regs); } @@ -222,14 +228,16 @@ static void mxr_release_clocks(struct mxr_device *mdev) { struct mxr_resources *res = &mdev->res; - if (!IS_ERR_OR_NULL(res->sclk_dac)) - clk_put(res->sclk_dac); if (!IS_ERR_OR_NULL(res->sclk_hdmi)) clk_put(res->sclk_hdmi); - if (!IS_ERR_OR_NULL(res->sclk_mixer)) - clk_put(res->sclk_mixer); - if (!IS_ERR_OR_NULL(res->vp)) - clk_put(res->vp); + if (mdev->vp_enabled) { + if (!IS_ERR_OR_NULL(res->sclk_dac)) + clk_put(res->sclk_dac); + if (!IS_ERR_OR_NULL(res->sclk_mixer)) + clk_put(res->sclk_mixer); + if (!IS_ERR_OR_NULL(res->vp)) + clk_put(res->vp); + } if (!IS_ERR_OR_NULL(res->mixer)) clk_put(res->mixer); } @@ -244,26 +252,28 @@ static int mxr_acquire_clocks(struct mxr_device *mdev) mxr_err(mdev, "failed to get clock 'mixer'\n"); goto fail; } - res->vp = clk_get(dev, "vp"); - if (IS_ERR(res->vp)) { - mxr_err(mdev, "failed to get clock 'vp'\n"); - goto fail; - } - res->sclk_mixer = clk_get(dev, "sclk_mixer"); - if (IS_ERR(res->sclk_mixer)) { - mxr_err(mdev, "failed to get clock 'sclk_mixer'\n"); - goto fail; + if (mdev->vp_enabled) { + res->vp = clk_get(dev, "vp"); + if (IS_ERR(res->vp)) { + mxr_err(mdev, "failed to get clock 'vp'\n"); + goto fail; + } + res->sclk_mixer = clk_get(dev, "sclk_mixer"); + if (IS_ERR(res->sclk_mixer)) { + mxr_err(mdev, "failed to get clock 'sclk_mixer'\n"); + goto fail; + } + res->sclk_dac = clk_get(dev, "sclk_dac"); + if (IS_ERR(res->sclk_dac)) { + mxr_err(mdev, "failed to get clock 'sclk_dac'\n"); + goto fail; + } } res->sclk_hdmi = clk_get(dev, "sclk_hdmi"); if (IS_ERR(res->sclk_hdmi)) { mxr_err(mdev, "failed to get clock 'sclk_hdmi'\n"); goto fail; } - res->sclk_dac = clk_get(dev, "sclk_dac"); - if (IS_ERR(res->sclk_dac)) { - mxr_err(mdev, "failed to get clock 'sclk_dac'\n"); - goto fail; - } return 0; fail: @@ -315,12 +325,18 @@ static int mxr_acquire_layers(struct mxr_device *mdev, { mdev->layer[0] = mxr_graph_layer_create(mdev, 0); mdev->layer[1] = mxr_graph_layer_create(mdev, 1); - mdev->layer[2] = mxr_vp_layer_create(mdev, 0); - if (!mdev->layer[0] || !mdev->layer[1] || !mdev->layer[2]) { + if (mdev->vp_enabled) + mdev->layer[2] = mxr_vp_layer_create(mdev, 0); + + if (!mdev->layer[0] || !mdev->layer[1]) { mxr_err(mdev, "failed to acquire layers\n"); goto fail; } + if (mdev->vp_enabled && !mdev->layer[2]) { + mxr_err(mdev, "failed to acquire vp layer\n"); + goto fail; + } return 0; @@ -340,8 +356,10 @@ static int mxr_runtime_resume(struct device *dev) mutex_lock(&mdev->mutex); /* turn clocks on */ clk_enable(res->mixer); - clk_enable(res->vp); - clk_enable(res->sclk_mixer); + if (mdev->vp_enabled) { + clk_enable(res->vp); + clk_enable(res->sclk_mixer); + } /* apply default configuration */ mxr_reg_reset(mdev); mxr_dbg(mdev, "resume - finished\n"); @@ -357,8 +375,10 @@ static int mxr_runtime_suspend(struct device *dev) mxr_dbg(mdev, "suspend - start\n"); mutex_lock(&mdev->mutex); /* turn clocks off */ - clk_disable(res->sclk_mixer); - clk_disable(res->vp); + if (mdev->vp_enabled) { + clk_disable(res->sclk_mixer); + clk_disable(res->vp); + } clk_disable(res->mixer); mutex_unlock(&mdev->mutex); mxr_dbg(mdev, "suspend - finished\n"); @@ -372,11 +392,59 @@ static const struct dev_pm_ops mxr_pm_ops = { /* --------- DRIVER INITIALIZATION ---------- */ +struct mixer_drv_data { + enum mixer_version_id version; + bool is_vp_enabled; +}; + +static struct mixer_drv_data exynos5_mxr_drv_data = { + .version = MXR_VER_16_0_33_0, + .is_vp_enabled = 0, +}; + +static struct mixer_drv_data exynos4_mxr_drv_data = { + .version = MXR_VER_0_0_0_16, + .is_vp_enabled = 1, +}; + +static struct platform_device_id mixer_driver_types[] = { + { + .name = "s5p-mixer", + .driver_data = (unsigned long)&exynos4_mxr_drv_data, + }, { + .name = "exynos5-mixer", + .driver_data = (unsigned long)&exynos5_mxr_drv_data, + }, { + /* end node */ + } +}; + +#ifdef CONFIG_OF + +static struct of_device_id mxr_dt_match[] = { + { + .compatible = "samsung,s5pv210-tvmixer", + .data = &exynos4_mxr_drv_data, + }, { + .compatible = "samsung,exynos4-mixer", + .data = &exynos4_mxr_drv_data, + }, { + .compatible = "samsung,exynos5-mixer", + .data = &exynos5_mxr_drv_data, + }, { + /* end node */ + } +}; + +MODULE_DEVICE_TABLE(of, mxr_dt_match); +#endif + static int mxr_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct mxr_platform_data *pdata = dev->platform_data; struct mxr_device *mdev; + struct mixer_drv_data *drv = NULL; int ret; /* mdev does not exist yet so no mxr_dbg is used */ @@ -389,8 +457,21 @@ static int mxr_probe(struct platform_device *pdev) goto fail; } + if (dev->of_node) { + const struct of_device_id *match; + match = of_match_node(of_match_ptr(mxr_dt_match), + pdev->dev.of_node); + + drv = (struct mixer_drv_data *)match->data; + } else { + drv = (struct mixer_drv_data *) + platform_get_device_id(pdev)->driver_data; + } + /* setup pointer to master device */ mdev->dev = dev; + mdev->vp_enabled = drv->is_vp_enabled; + mdev->mxr_ver = drv->version; mutex_init(&mdev->mutex); spin_lock_init(&mdev->reg_slock); @@ -448,17 +529,10 @@ static int mxr_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_OF -static const struct of_device_id mxr_dt_match[] = { - { .compatible = "samsung,s5pv210-tvmixer" }, - { }, -}; -MODULE_DEVICE_TABLE(of, mxr_dt_match); -#endif - static struct platform_driver mxr_driver __refdata = { .probe = mxr_probe, .remove = mxr_remove, + .id_table = mixer_driver_types, .driver = { .name = MXR_DRIVER_NAME, .owner = THIS_MODULE, diff --git a/drivers/media/platform/s5p-tv/mixer_reg.c b/drivers/media/platform/s5p-tv/mixer_reg.c index b713403024e..56d9b45c3ab 100644 --- a/drivers/media/platform/s5p-tv/mixer_reg.c +++ b/drivers/media/platform/s5p-tv/mixer_reg.c @@ -57,12 +57,25 @@ static inline void mxr_write_mask(struct mxr_device *mdev, u32 reg_id, writel(val, mdev->res.mxr_regs + reg_id); } +static void mxr_reg_layer_update(struct mxr_device *mdev) +{ + u32 val; + + val = mxr_read(mdev, MXR_CFG); + + /* allow one update per vsync only */ + if (!(val & MXR_CFG_LAYER_UPDATE_COUNT_MASK)) + mxr_write_mask(mdev, MXR_CFG, ~0, MXR_CFG_LAYER_UPDATE); +} + void mxr_vsync_set_update(struct mxr_device *mdev, int en) { /* block update on vsync */ mxr_write_mask(mdev, MXR_STATUS, en ? MXR_STATUS_SYNC_ENABLE : 0, MXR_STATUS_SYNC_ENABLE); - vp_write(mdev, VP_SHADOW_UPDATE, en ? VP_SHADOW_UPDATE_ENABLE : 0); + if (mdev->vp_enabled) + vp_write(mdev, VP_SHADOW_UPDATE, + en ? VP_SHADOW_UPDATE_ENABLE : 0); } static void __mxr_reg_vp_reset(struct mxr_device *mdev) @@ -103,8 +116,9 @@ void mxr_reg_reset(struct mxr_device *mdev) * layer1 - OSD */ val = MXR_LAYER_CFG_GRP0_VAL(1); - val |= MXR_LAYER_CFG_VP_VAL(2); val |= MXR_LAYER_CFG_GRP1_VAL(3); + if (mdev->vp_enabled) + val |= MXR_LAYER_CFG_VP_VAL(2); mxr_write(mdev, MXR_LAYER_CFG, val); /* use dark gray background color */ @@ -123,8 +137,10 @@ void mxr_reg_reset(struct mxr_device *mdev) mxr_write(mdev, MXR_GRAPHIC_CFG(1), val); /* configuration of Video Processor Registers */ - __mxr_reg_vp_reset(mdev); - mxr_reg_vp_default_filter(mdev); + if (mdev->vp_enabled) { + __mxr_reg_vp_reset(mdev); + mxr_reg_vp_default_filter(mdev); + } /* enable all interrupts */ mxr_write_mask(mdev, MXR_INT_EN, ~0, MXR_INT_EN_ALL); @@ -225,6 +241,9 @@ void mxr_reg_graph_buffer(struct mxr_device *mdev, int idx, dma_addr_t addr) mxr_write_mask(mdev, MXR_CFG, val, MXR_CFG_GRP1_ENABLE); mxr_write(mdev, MXR_GRAPHIC_BASE(idx), addr); + if (mdev->mxr_ver == MXR_VER_16_0_33_0) + mxr_reg_layer_update(mdev); + mxr_vsync_set_update(mdev, MXR_ENABLE); spin_unlock_irqrestore(&mdev->reg_slock, flags); } @@ -409,8 +428,11 @@ void mxr_reg_set_mbus_fmt(struct mxr_device *mdev, MXR_CFG_OUT_MASK); val = (fmt->field == V4L2_FIELD_INTERLACED) ? ~0 : 0; - vp_write_mask(mdev, VP_MODE, val, - VP_MODE_LINE_SKIP | VP_MODE_FIELD_ID_AUTO_TOGGLING); + + if (mdev->vp_enabled) { + vp_write_mask(mdev, VP_MODE, val, + VP_MODE_LINE_SKIP | VP_MODE_FIELD_ID_AUTO_TOGGLING); + } mxr_vsync_set_update(mdev, MXR_ENABLE); spin_unlock_irqrestore(&mdev->reg_slock, flags); @@ -548,6 +570,7 @@ do { \ void mxr_reg_dump(struct mxr_device *mdev) { mxr_reg_mxr_dump(mdev); - mxr_reg_vp_dump(mdev); + if (mdev->vp_enabled) + mxr_reg_vp_dump(mdev); } diff --git a/drivers/media/platform/s5p-tv/regs-mixer.h b/drivers/media/platform/s5p-tv/regs-mixer.h index 158abb43d0a..b64ec73149c 100644 --- a/drivers/media/platform/s5p-tv/regs-mixer.h +++ b/drivers/media/platform/s5p-tv/regs-mixer.h @@ -38,6 +38,11 @@ #define MXR_BG_COLOR0 0x0064 #define MXR_BG_COLOR1 0x0068 #define MXR_BG_COLOR2 0x006C +#define MXR_CM_COEFF_Y 0x0080 +#define MXR_CM_COEFF_CB 0x0084 +#define MXR_CM_COEFF_CR 0x0088 +#define MXR_GRAPHIC0_BASE_S 0x2024 +#define MXR_GRAPHIC1_BASE_S 0x2044 /* for parametrized access to layer registers */ #define MXR_GRAPHIC_CFG(i) (0x0020 + (i) * 0x20) @@ -46,6 +51,8 @@ #define MXR_GRAPHIC_SXY(i) (0x002C + (i) * 0x20) #define MXR_GRAPHIC_WH(i) (0x0030 + (i) * 0x20) #define MXR_GRAPHIC_DXY(i) (0x0034 + (i) * 0x20) +#define MXR_GRAPHIC_BLANK(i) (0x0038 + (i) * 0x20) +#define MXR_GRAPHIC_BASE_S(i) (0x2024 + (i) * 0x20) /* * Bit definition part @@ -59,12 +66,22 @@ (((val) << (low_bit)) & MXR_MASK(high_bit, low_bit)) /* bits for MXR_STATUS */ +#define MXR_STATUS_SOFT_RESET (1 << 8) #define MXR_STATUS_16_BURST (1 << 7) #define MXR_STATUS_BURST_MASK (1 << 7) +#define MXR_STATUS_BIG_ENDIAN (1 << 3) +#define MXR_STATUS_ENDIAN_MASK (1 << 3) #define MXR_STATUS_SYNC_ENABLE (1 << 2) #define MXR_STATUS_REG_RUN (1 << 0) /* bits for MXR_CFG */ +#define MXR_CFG_LAYER_UPDATE (1 << 31) +#define MXR_CFG_LAYER_UPDATE_COUNT_MASK (3 << 29) +#define MXR_CFG_RGB601_0_255 (0 << 9) +#define MXR_CFG_RGB601_16_235 (1 << 9) +#define MXR_CFG_RGB709_0_255 (2 << 9) +#define MXR_CFG_RGB709_16_235 (3 << 9) +#define MXR_CFG_RGB_FMT_MASK 0x600 #define MXR_CFG_OUT_YUV444 (0 << 8) #define MXR_CFG_OUT_RGB888 (1 << 8) #define MXR_CFG_OUT_MASK (1 << 8) @@ -87,6 +104,8 @@ /* bits for MXR_GRAPHICn_CFG */ #define MXR_GRP_CFG_COLOR_KEY_DISABLE (1 << 21) #define MXR_GRP_CFG_BLEND_PRE_MUL (1 << 20) +#define MXR_GRP_CFG_WIN_BLEND_EN (1 << 17) +#define MXR_GRP_CFG_PIXEL_BLEND_EN (1 << 16) #define MXR_GRP_CFG_FORMAT_VAL(x) MXR_MASK_VAL(x, 11, 8) #define MXR_GRP_CFG_FORMAT_MASK MXR_GRP_CFG_FORMAT_VAL(~0) #define MXR_GRP_CFG_ALPHA_VAL(x) MXR_MASK_VAL(x, 7, 0) |