aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/samsung/tvout/hw_if/mixer.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/samsung/tvout/hw_if/mixer.c')
-rw-r--r--drivers/media/video/samsung/tvout/hw_if/mixer.c874
1 files changed, 874 insertions, 0 deletions
diff --git a/drivers/media/video/samsung/tvout/hw_if/mixer.c b/drivers/media/video/samsung/tvout/hw_if/mixer.c
new file mode 100644
index 0000000..b2753f2
--- /dev/null
+++ b/drivers/media/video/samsung/tvout/hw_if/mixer.c
@@ -0,0 +1,874 @@
+/* linux/drivers/media/video/samsung/tvout/hw_if/mixer.c
+ *
+ * Copyright (c) 2009 Samsung Electronics
+ * http://www.samsung.com/
+ *
+ * Mixer raw ftn file for Samsung TVOUT driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/io.h>
+#include <linux/sched.h>
+
+#include <mach/regs-mixer.h>
+
+#include "../s5p_tvout_common_lib.h"
+#include "../s5p_tvout_ctrl.h"
+#include "hw_if.h"
+
+#undef tvout_dbg
+
+#ifdef CONFIG_MIXER_DEBUG
+#define tvout_dbg(fmt, ...) \
+ printk(KERN_INFO "\t[MIXER] %s(): " fmt, \
+ __func__, ##__VA_ARGS__)
+#else
+#define tvout_dbg(fmt, ...)
+#endif
+
+void __iomem *mixer_base;
+spinlock_t lock_mixer;
+
+
+extern int s5p_vp_ctrl_get_src_addr(u32* top_y_addr, u32* top_c_addr);
+int s5p_mixer_set_show(enum s5p_mixer_layer layer, bool show)
+{
+ u32 mxr_config;
+
+ tvout_dbg("%d, %d\n", layer, show);
+
+ switch (layer) {
+ case MIXER_VIDEO_LAYER:
+ mxr_config = (show) ?
+ (readl(mixer_base + S5P_MXR_CFG) |
+ S5P_MXR_CFG_VIDEO_ENABLE) :
+ (readl(mixer_base + S5P_MXR_CFG) &
+ ~S5P_MXR_CFG_VIDEO_ENABLE);
+ break;
+
+ case MIXER_GPR0_LAYER:
+ mxr_config = (show) ?
+ (readl(mixer_base + S5P_MXR_CFG) |
+ S5P_MXR_CFG_GRAPHIC0_ENABLE) :
+ (readl(mixer_base + S5P_MXR_CFG) &
+ ~S5P_MXR_CFG_GRAPHIC0_ENABLE);
+ break;
+
+ case MIXER_GPR1_LAYER:
+ mxr_config = (show) ?
+ (readl(mixer_base + S5P_MXR_CFG) |
+ S5P_MXR_CFG_GRAPHIC1_ENABLE) :
+ (readl(mixer_base + S5P_MXR_CFG) &
+ ~S5P_MXR_CFG_GRAPHIC1_ENABLE);
+ break;
+
+ default:
+ tvout_err("invalid layer parameter = %d\n", layer);
+ return -1;
+ }
+
+ writel(mxr_config, mixer_base + S5P_MXR_CFG);
+
+ return 0;
+}
+
+int s5p_mixer_set_priority(enum s5p_mixer_layer layer, u32 priority)
+{
+ u32 layer_cfg;
+
+ tvout_dbg("%d, %d\n", layer, priority);
+
+ switch (layer) {
+ case MIXER_VIDEO_LAYER:
+ layer_cfg = S5P_MXR_LAYER_CFG_VID_PRIORITY_CLR(
+ readl(mixer_base + S5P_MXR_LAYER_CFG)) |
+ S5P_MXR_LAYER_CFG_VID_PRIORITY(priority);
+ break;
+
+ case MIXER_GPR0_LAYER:
+ layer_cfg = S5P_MXR_LAYER_CFG_GRP0_PRIORITY_CLR(
+ readl(mixer_base + S5P_MXR_LAYER_CFG)) |
+ S5P_MXR_LAYER_CFG_GRP0_PRIORITY(priority);
+ break;
+
+ case MIXER_GPR1_LAYER:
+ layer_cfg = S5P_MXR_LAYER_CFG_GRP1_PRIORITY_CLR(
+ readl(mixer_base + S5P_MXR_LAYER_CFG)) |
+ S5P_MXR_LAYER_CFG_GRP1_PRIORITY(priority);
+ break;
+
+ default:
+ tvout_err("invalid layer parameter = %d\n", layer);
+ return -1;
+ }
+
+ writel(layer_cfg, mixer_base + S5P_MXR_LAYER_CFG);
+
+ return 0;
+}
+
+void s5p_mixer_set_pre_mul_mode(enum s5p_mixer_layer layer, bool enable)
+{
+ u32 reg;
+
+ switch (layer) {
+ case MIXER_GPR0_LAYER:
+ reg = readl(mixer_base + S5P_MXR_GRAPHIC0_CFG);
+
+ if (enable)
+ reg |= S5P_MXR_PRE_MUL_MODE;
+ else
+ reg &= ~S5P_MXR_PRE_MUL_MODE;
+
+ writel(reg, mixer_base + S5P_MXR_GRAPHIC0_CFG);
+ break;
+ case MIXER_GPR1_LAYER:
+ reg = readl(mixer_base + S5P_MXR_GRAPHIC1_CFG);
+
+ if (enable)
+ reg |= S5P_MXR_PRE_MUL_MODE;
+ else
+ reg &= ~S5P_MXR_PRE_MUL_MODE;
+
+ writel(reg, mixer_base + S5P_MXR_GRAPHIC1_CFG);
+ break;
+ case MIXER_VIDEO_LAYER:
+ break;
+ }
+}
+
+int s5p_mixer_set_pixel_blend(enum s5p_mixer_layer layer, bool enable)
+{
+ u32 temp_reg;
+
+ tvout_dbg("%d, %d\n", layer, enable);
+
+ switch (layer) {
+ case MIXER_GPR0_LAYER:
+ temp_reg = readl(mixer_base + S5P_MXR_GRAPHIC0_CFG)
+ & (~S5P_MXR_PIXEL_BLEND_ENABLE) ;
+
+ if (enable)
+ temp_reg |= S5P_MXR_PIXEL_BLEND_ENABLE;
+ else
+ temp_reg |= S5P_MXR_PIXEL_BLEND_DISABLE;
+
+ writel(temp_reg, mixer_base + S5P_MXR_GRAPHIC0_CFG);
+ break;
+
+ case MIXER_GPR1_LAYER:
+ temp_reg = readl(mixer_base + S5P_MXR_GRAPHIC1_CFG)
+ & (~S5P_MXR_PIXEL_BLEND_ENABLE) ;
+
+ if (enable)
+ temp_reg |= S5P_MXR_PIXEL_BLEND_ENABLE;
+ else
+ temp_reg |= S5P_MXR_PIXEL_BLEND_DISABLE;
+
+ writel(temp_reg, mixer_base + S5P_MXR_GRAPHIC1_CFG);
+ break;
+
+ default:
+ tvout_err("invalid layer parameter = %d\n", layer);
+
+ return -1;
+ }
+
+ return 0;
+}
+
+int s5p_mixer_set_layer_blend(enum s5p_mixer_layer layer, bool enable)
+{
+ u32 temp_reg;
+
+ tvout_dbg("%d, %d\n", layer, enable);
+
+ switch (layer) {
+ case MIXER_VIDEO_LAYER:
+ temp_reg = readl(mixer_base + S5P_MXR_VIDEO_CFG)
+ & (~S5P_MXR_VIDEO_CFG_BLEND_EN) ;
+
+ if (enable)
+ temp_reg |= S5P_MXR_VIDEO_CFG_BLEND_EN;
+ else
+ temp_reg |= S5P_MXR_VIDEO_CFG_BLEND_DIS;
+
+ writel(temp_reg, mixer_base + S5P_MXR_VIDEO_CFG);
+ break;
+
+ case MIXER_GPR0_LAYER:
+ temp_reg = readl(mixer_base + S5P_MXR_GRAPHIC0_CFG)
+ & (~S5P_MXR_WIN_BLEND_ENABLE) ;
+
+ if (enable)
+ temp_reg |= S5P_MXR_WIN_BLEND_ENABLE;
+ else
+ temp_reg |= S5P_MXR_WIN_BLEND_DISABLE;
+
+ writel(temp_reg, mixer_base + S5P_MXR_GRAPHIC0_CFG);
+ break;
+
+ case MIXER_GPR1_LAYER:
+ temp_reg = readl(mixer_base + S5P_MXR_GRAPHIC1_CFG)
+ & (~S5P_MXR_WIN_BLEND_ENABLE) ;
+
+ if (enable)
+ temp_reg |= S5P_MXR_WIN_BLEND_ENABLE;
+ else
+ temp_reg |= S5P_MXR_WIN_BLEND_DISABLE;
+
+ writel(temp_reg, mixer_base + S5P_MXR_GRAPHIC1_CFG);
+ break;
+
+ default:
+ tvout_err("invalid layer parameter = %d\n", layer);
+
+ return -1;
+ }
+
+ return 0;
+}
+
+int s5p_mixer_set_alpha(enum s5p_mixer_layer layer, u32 alpha)
+{
+ u32 temp_reg;
+
+ tvout_dbg("%d, %d\n", layer, alpha);
+
+ switch (layer) {
+ case MIXER_VIDEO_LAYER:
+ temp_reg = readl(mixer_base + S5P_MXR_VIDEO_CFG)
+ & (~S5P_MXR_VIDEO_CFG_ALPHA_MASK) ;
+ temp_reg |= S5P_MXR_VIDEO_CFG_ALPHA_VALUE(alpha);
+ writel(temp_reg, mixer_base + S5P_MXR_VIDEO_CFG);
+ break;
+
+ case MIXER_GPR0_LAYER:
+ temp_reg = readl(mixer_base + S5P_MXR_GRAPHIC0_CFG)
+ & (~S5P_MXR_VIDEO_CFG_ALPHA_MASK) ;
+ temp_reg |= S5P_MXR_GRP_ALPHA_VALUE(alpha);
+ writel(temp_reg, mixer_base + S5P_MXR_GRAPHIC0_CFG);
+ break;
+
+ case MIXER_GPR1_LAYER:
+ temp_reg = readl(mixer_base + S5P_MXR_GRAPHIC1_CFG)
+ & (~S5P_MXR_VIDEO_CFG_ALPHA_MASK) ;
+ temp_reg |= S5P_MXR_GRP_ALPHA_VALUE(alpha);
+ writel(temp_reg, mixer_base + S5P_MXR_GRAPHIC1_CFG);
+ break;
+
+ default:
+ tvout_err("invalid layer parameter = %d\n", layer);
+ return -1;
+ }
+
+ return 0;
+}
+
+int s5p_mixer_set_grp_base_address(enum s5p_mixer_layer layer, u32 base_addr)
+{
+ tvout_dbg("%d, 0x%x\n", layer, base_addr);
+
+ if (S5P_MXR_GRP_ADDR_ILLEGAL(base_addr)) {
+ tvout_err("address is not word align = %d\n", base_addr);
+ return -1;
+ }
+
+ switch (layer) {
+ case MIXER_GPR0_LAYER:
+ writel(S5P_MXR_GPR_BASE(base_addr),
+ mixer_base + S5P_MXR_GRAPHIC0_BASE);
+ break;
+
+ case MIXER_GPR1_LAYER:
+ writel(S5P_MXR_GPR_BASE(base_addr),
+ mixer_base + S5P_MXR_GRAPHIC1_BASE);
+ break;
+
+ default:
+ tvout_err("invalid layer parameter = %d\n", layer);
+ return -1;
+ }
+
+ return 0;
+}
+
+int s5p_mixer_set_grp_layer_dst_pos(enum s5p_mixer_layer layer,
+ u32 dst_offs_x, u32 dst_offs_y)
+{
+ tvout_dbg("%d, %d, %d\n", layer, dst_offs_x, dst_offs_y);
+
+ switch (layer) {
+ case MIXER_GPR0_LAYER:
+ writel(S5P_MXR_GRP_DESTX(dst_offs_x) |
+ S5P_MXR_GRP_DESTY(dst_offs_y),
+ mixer_base + S5P_MXR_GRAPHIC0_DXY);
+ break;
+
+ case MIXER_GPR1_LAYER:
+ writel(S5P_MXR_GRP_DESTX(dst_offs_x) |
+ S5P_MXR_GRP_DESTY(dst_offs_y),
+ mixer_base + S5P_MXR_GRAPHIC1_DXY);
+ break;
+
+ default:
+ tvout_err("invalid layer parameter = %d\n", layer);
+ return -1;
+ }
+
+ return 0;
+}
+
+int s5p_mixer_set_grp_layer_src_pos(enum s5p_mixer_layer layer, u32 src_offs_x,
+ u32 src_offs_y, u32 span, u32 width, u32 height)
+{
+ tvout_dbg("%d, %d, %d, %d, %d, %d\n", layer, span, width, height,
+ src_offs_x, src_offs_y);
+
+ switch (layer) {
+ case MIXER_GPR0_LAYER:
+ writel(S5P_MXR_GRP_SPAN(span),
+ mixer_base + S5P_MXR_GRAPHIC0_SPAN);
+ writel(S5P_MXR_GRP_WIDTH(width) | S5P_MXR_GRP_HEIGHT(height),
+ mixer_base + S5P_MXR_GRAPHIC0_WH);
+ writel(S5P_MXR_GRP_STARTX(src_offs_x) |
+ S5P_MXR_GRP_STARTY(src_offs_y),
+ mixer_base + S5P_MXR_GRAPHIC0_SXY);
+ break;
+
+ case MIXER_GPR1_LAYER:
+ writel(S5P_MXR_GRP_SPAN(span),
+ mixer_base + S5P_MXR_GRAPHIC1_SPAN);
+ writel(S5P_MXR_GRP_WIDTH(width) | S5P_MXR_GRP_HEIGHT(height),
+ mixer_base + S5P_MXR_GRAPHIC1_WH);
+ writel(S5P_MXR_GRP_STARTX(src_offs_x) |
+ S5P_MXR_GRP_STARTY(src_offs_y),
+ mixer_base + S5P_MXR_GRAPHIC1_SXY);
+ break;
+
+ default:
+ tvout_err(" invalid layer parameter = %d\n", layer);
+ return -1;
+ }
+
+ return 0;
+}
+
+void s5p_mixer_set_bg_color(enum s5p_mixer_bg_color_num colornum,
+ u32 color_y, u32 color_cb, u32 color_cr)
+{
+ u32 reg_value;
+
+ reg_value = S5P_MXR_BG_COLOR_Y(color_y) |
+ S5P_MXR_BG_COLOR_CB(color_cb) |
+ S5P_MXR_BG_COLOR_CR(color_cr);
+
+ switch (colornum) {
+ case MIXER_BG_COLOR_0:
+ writel(reg_value, mixer_base + S5P_MXR_BG_COLOR0);
+ break;
+
+ case MIXER_BG_COLOR_1:
+ writel(reg_value, mixer_base + S5P_MXR_BG_COLOR1);
+ break;
+
+ case MIXER_BG_COLOR_2:
+ writel(reg_value, mixer_base + S5P_MXR_BG_COLOR2);
+ break;
+ }
+}
+void s5p_mixer_set_video_limiter(u32 y_min, u32 y_max,
+ u32 c_min, u32 c_max, bool enable)
+{
+ u32 reg_value;
+
+ reg_value = readl(mixer_base + S5P_MXR_VIDEO_CFG)
+ & (~S5P_MXR_VIDEO_CFG_LIMITER_EN) ;
+
+ if (enable)
+ reg_value |= S5P_MXR_VIDEO_CFG_LIMITER_EN;
+ else
+ reg_value |= S5P_MXR_VIDEO_CFG_LIMITER_DIS;
+
+ writel(reg_value, mixer_base + S5P_MXR_VIDEO_CFG);
+
+ reg_value = S5P_MXR_VIDEO_LIMITER_PARA_Y_UPPER(y_max) |
+ S5P_MXR_VIDEO_LIMITER_PARA_Y_LOWER(y_min) |
+ S5P_MXR_VIDEO_LIMITER_PARA_C_UPPER(c_max) |
+ S5P_MXR_VIDEO_LIMITER_PARA_C_LOWER(c_min);
+
+ writel(reg_value, mixer_base + S5P_MXR_VIDEO_LIMITER_PARA_CFG);
+
+}
+
+void s5p_mixer_init_status_reg(enum s5p_mixer_burst_mode burst,
+ enum s5p_tvout_endian endian)
+{
+ u32 temp_reg = 0;
+
+ temp_reg = S5P_MXR_STATUS_SYNC_ENABLE | S5P_MXR_STATUS_OPERATING;
+
+ switch (burst) {
+ case MIXER_BURST_8:
+ temp_reg |= S5P_MXR_STATUS_8_BURST;
+ break;
+ case MIXER_BURST_16:
+ temp_reg |= S5P_MXR_STATUS_16_BURST;
+ break;
+ }
+
+ switch (endian) {
+ case TVOUT_BIG_ENDIAN:
+ temp_reg |= S5P_MXR_STATUS_BIG_ENDIAN;
+ break;
+ case TVOUT_LITTLE_ENDIAN:
+ temp_reg |= S5P_MXR_STATUS_LITTLE_ENDIAN;
+ break;
+ }
+
+ writel(temp_reg, mixer_base + S5P_MXR_STATUS);
+}
+
+int s5p_mixer_init_display_mode(enum s5p_tvout_disp_mode mode,
+ enum s5p_tvout_o_mode output_mode,
+ enum s5p_mixer_rgb rgb_type)
+{
+ u32 temp_reg = readl(mixer_base + S5P_MXR_CFG);
+
+ tvout_dbg("%d, %d\n", mode, output_mode);
+
+ switch (mode) {
+ case TVOUT_NTSC_M:
+ case TVOUT_NTSC_443:
+ temp_reg &= ~S5P_MXR_CFG_HD;
+ temp_reg &= ~S5P_MXR_CFG_PAL;
+ temp_reg &= S5P_MXR_CFG_INTERLACE;
+ break;
+
+ case TVOUT_PAL_BDGHI:
+ case TVOUT_PAL_M:
+ case TVOUT_PAL_N:
+ case TVOUT_PAL_NC:
+ case TVOUT_PAL_60:
+ temp_reg &= ~S5P_MXR_CFG_HD;
+ temp_reg |= S5P_MXR_CFG_PAL;
+ temp_reg &= S5P_MXR_CFG_INTERLACE;
+ break;
+
+ case TVOUT_480P_60_16_9:
+ case TVOUT_480P_60_4_3:
+ case TVOUT_480P_59:
+ temp_reg &= ~S5P_MXR_CFG_HD;
+ temp_reg &= ~S5P_MXR_CFG_PAL;
+ temp_reg |= S5P_MXR_CFG_PROGRASSIVE;
+ break;
+
+ case TVOUT_576P_50_16_9:
+ case TVOUT_576P_50_4_3:
+ temp_reg &= ~S5P_MXR_CFG_HD;
+ temp_reg |= S5P_MXR_CFG_PAL;
+ temp_reg |= S5P_MXR_CFG_PROGRASSIVE;
+ break;
+
+ case TVOUT_720P_50:
+ case TVOUT_720P_59:
+ case TVOUT_720P_60:
+ temp_reg |= S5P_MXR_CFG_HD;
+ temp_reg &= ~S5P_MXR_CFG_HD_1080I;
+ temp_reg |= S5P_MXR_CFG_PROGRASSIVE;
+ break;
+
+#ifdef CONFIG_HDMI_14A_3D
+ case TVOUT_720P_60_SBS_HALF:
+ case TVOUT_720P_59_SBS_HALF:
+ case TVOUT_720P_50_TB:
+ temp_reg |= S5P_MXR_CFG_HD;
+ temp_reg &= ~S5P_MXR_CFG_HD_1080I;
+ temp_reg |= S5P_MXR_CFG_PROGRASSIVE;
+ break;
+#endif
+
+ case TVOUT_1080I_50:
+ case TVOUT_1080I_59:
+ case TVOUT_1080I_60:
+ temp_reg |= S5P_MXR_CFG_HD;
+ temp_reg |= S5P_MXR_CFG_HD_1080I;
+ temp_reg &= S5P_MXR_CFG_INTERLACE;
+ break;
+
+ case TVOUT_1080P_50:
+ case TVOUT_1080P_59:
+ case TVOUT_1080P_60:
+ case TVOUT_1080P_30:
+ temp_reg |= S5P_MXR_CFG_HD;
+ temp_reg |= S5P_MXR_CFG_HD_1080P;
+ temp_reg |= S5P_MXR_CFG_PROGRASSIVE;
+ break;
+
+#ifdef CONFIG_HDMI_14A_3D
+ case TVOUT_1080P_24_TB:
+ case TVOUT_1080P_23_TB:
+ temp_reg |= S5P_MXR_CFG_HD;
+ temp_reg |= S5P_MXR_CFG_HD_1080P;
+ temp_reg |= S5P_MXR_CFG_PROGRASSIVE;
+ break;
+#endif
+ default:
+ tvout_err("invalid mode parameter = %d\n", mode);
+ return -1;
+ }
+
+ switch (output_mode) {
+ case TVOUT_COMPOSITE:
+ temp_reg &= S5P_MXR_CFG_TV_OUT;
+ temp_reg &= ~(0x1<<8);
+ temp_reg |= MIXER_YUV444<<8;
+ break;
+
+ case TVOUT_HDMI_RGB:
+ case TVOUT_DVI:
+ temp_reg |= S5P_MXR_CFG_HDMI_OUT;
+ temp_reg &= ~(0x1<<8);
+ temp_reg |= MIXER_RGB888<<8;
+ break;
+
+ case TVOUT_HDMI:
+ temp_reg |= S5P_MXR_CFG_HDMI_OUT;
+ temp_reg &= ~(0x1<<8);
+ temp_reg |= MIXER_YUV444<<8;
+ break;
+
+ default:
+ tvout_err("invalid mode parameter = %d\n", mode);
+ return -1;
+ }
+
+ if (0 <= rgb_type && rgb_type <= 3)
+ temp_reg |= rgb_type<<9;
+ else
+ printk(KERN_INFO "Wrong rgb type!!\n");
+
+ tvout_dbg(KERN_INFO "Color range RGB Type : %x\n", rgb_type);
+ writel(temp_reg, mixer_base + S5P_MXR_CFG);
+
+ return 0;
+}
+
+void s5p_mixer_scaling(enum s5p_mixer_layer layer,
+ struct s5ptvfb_user_scaling scaling)
+{
+ u32 reg, ver_val = 0, hor_val = 0;
+
+ switch (scaling.ver) {
+ case VERTICAL_X1:
+ ver_val = 0;
+ break;
+ case VERTICAL_X2:
+ ver_val = 1;
+ break;
+ }
+
+ switch (scaling.hor) {
+ case HORIZONTAL_X1:
+ hor_val = 0;
+ break;
+ case HORIZONTAL_X2:
+ hor_val = 1;
+ break;
+ }
+
+ switch (layer) {
+ case MIXER_GPR0_LAYER:
+ reg = readl(mixer_base + S5P_MXR_GRAPHIC0_WH);
+ reg |= S5P_MXR_GRP_V_SCALE(ver_val);
+ reg |= S5P_MXR_GRP_H_SCALE(hor_val);
+ writel(reg, mixer_base + S5P_MXR_GRAPHIC0_WH);
+ break;
+ case MIXER_GPR1_LAYER:
+ reg = readl(mixer_base + S5P_MXR_GRAPHIC1_WH);
+ reg |= S5P_MXR_GRP_V_SCALE(ver_val);
+ reg |= S5P_MXR_GRP_H_SCALE(hor_val);
+ writel(reg, mixer_base + S5P_MXR_GRAPHIC1_WH);
+ break;
+ case MIXER_VIDEO_LAYER:
+ break;
+ }
+}
+
+void s5p_mixer_set_color_format(enum s5p_mixer_layer layer,
+ enum s5p_mixer_color_fmt format)
+{
+ u32 reg;
+
+ switch (layer) {
+ case MIXER_GPR0_LAYER:
+ reg = readl(mixer_base + S5P_MXR_GRAPHIC0_CFG);
+ reg &= ~(S5P_MXR_EG_COLOR_FORMAT(0xf));
+ reg |= S5P_MXR_EG_COLOR_FORMAT(format);
+ writel(reg, mixer_base + S5P_MXR_GRAPHIC0_CFG);
+ break;
+ case MIXER_GPR1_LAYER:
+ reg = readl(mixer_base + S5P_MXR_GRAPHIC1_CFG);
+ reg &= ~(S5P_MXR_EG_COLOR_FORMAT(0xf));
+ reg |= S5P_MXR_EG_COLOR_FORMAT(format);
+ writel(reg, mixer_base + S5P_MXR_GRAPHIC1_CFG);
+ break;
+ case MIXER_VIDEO_LAYER:
+ break;
+ }
+}
+
+void s5p_mixer_set_chroma_key(enum s5p_mixer_layer layer, bool enabled, u32 key)
+{
+ u32 reg;
+
+ switch (layer) {
+ case MIXER_GPR0_LAYER:
+ reg = readl(mixer_base + S5P_MXR_GRAPHIC0_CFG);
+
+ if (enabled)
+ reg &= ~S5P_MXR_BLANK_CHANGE_NEW_PIXEL;
+ else
+ reg |= S5P_MXR_BLANK_CHANGE_NEW_PIXEL;
+
+ writel(reg, mixer_base + S5P_MXR_GRAPHIC0_CFG);
+ writel(S5P_MXR_GPR_BLANK_COLOR(key),
+ mixer_base + S5P_MXR_GRAPHIC0_BLANK);
+ break;
+ case MIXER_GPR1_LAYER:
+ reg = readl(mixer_base + S5P_MXR_GRAPHIC1_CFG);
+
+ if (enabled)
+ reg &= ~S5P_MXR_BLANK_CHANGE_NEW_PIXEL;
+ else
+ reg |= S5P_MXR_BLANK_CHANGE_NEW_PIXEL;
+
+ writel(reg, mixer_base + S5P_MXR_GRAPHIC1_CFG);
+ writel(S5P_MXR_GPR_BLANK_COLOR(key),
+ mixer_base + S5P_MXR_GRAPHIC1_BLANK);
+ break;
+ case MIXER_VIDEO_LAYER:
+ break;
+ }
+}
+
+void s5p_mixer_init_bg_dither_enable(bool cr_dither_enable,
+ bool cb_dither_enable,
+ bool y_dither_enable)
+{
+ u32 temp_reg = 0;
+
+ tvout_dbg("%d, %d, %d\n", cr_dither_enable, cb_dither_enable,
+ y_dither_enable);
+
+ temp_reg = (cr_dither_enable) ?
+ (temp_reg | S5P_MXR_BG_CR_DIHER_EN) :
+ (temp_reg & ~S5P_MXR_BG_CR_DIHER_EN);
+ temp_reg = (cb_dither_enable) ?
+ (temp_reg | S5P_MXR_BG_CB_DIHER_EN) :
+ (temp_reg & ~S5P_MXR_BG_CB_DIHER_EN);
+ temp_reg = (y_dither_enable) ?
+ (temp_reg | S5P_MXR_BG_Y_DIHER_EN) :
+ (temp_reg & ~S5P_MXR_BG_Y_DIHER_EN);
+
+ writel(temp_reg, mixer_base + S5P_MXR_BG_CFG);
+
+}
+
+void s5p_mixer_init_csc_coef_default(enum s5p_mixer_rgb csc_type)
+{
+ tvout_dbg("%d\n", csc_type);
+
+ switch (csc_type) {
+ case MIXER_RGB601_16_235:
+ writel((0 << 30) | (153 << 20) | (300 << 10) | (58 << 0),
+ mixer_base + S5P_MXR_CM_COEFF_Y);
+ writel((936 << 20) | (851 << 10) | (262 << 0),
+ mixer_base + S5P_MXR_CM_COEFF_CB);
+ writel((262 << 20) | (805 << 10) | (982 << 0),
+ mixer_base + S5P_MXR_CM_COEFF_CR);
+ break;
+
+ case MIXER_RGB601_0_255:
+ writel((1 << 30) | (132 << 20) | (258 << 10) | (50 << 0),
+ mixer_base + S5P_MXR_CM_COEFF_Y);
+ writel((949 << 20) | (876 << 10) | (225 << 0),
+ mixer_base + S5P_MXR_CM_COEFF_CB);
+ writel((225 << 20) | (836 << 10) | (988 << 0),
+ mixer_base + S5P_MXR_CM_COEFF_CR);
+ break;
+
+ case MIXER_RGB709_16_235:
+ writel((0 << 30) | (109 << 20) | (366 << 10) | (36 << 0),
+ mixer_base + S5P_MXR_CM_COEFF_Y);
+ writel((964 << 20) | (822 << 10) | (216 << 0),
+ mixer_base + S5P_MXR_CM_COEFF_CB);
+ writel((262 << 20) | (787 << 10) | (1000 << 0),
+ mixer_base + S5P_MXR_CM_COEFF_CR);
+ break;
+
+ case MIXER_RGB709_0_255:
+ writel((1 << 30) | (94 << 20) | (314 << 10) | (32 << 0),
+ mixer_base + S5P_MXR_CM_COEFF_Y);
+ writel((972 << 20) | (851 << 10) | (225 << 0),
+ mixer_base + S5P_MXR_CM_COEFF_CB);
+ writel((225 << 20) | (820 << 10) | (1004 << 0),
+ mixer_base + S5P_MXR_CM_COEFF_CR);
+ break;
+
+ default:
+ tvout_err("invalid csc_type parameter = %d\n", csc_type);
+ break;
+ }
+}
+
+void s5p_mixer_start(void)
+{
+ writel((readl(mixer_base + S5P_MXR_STATUS) | S5P_MXR_STATUS_RUN),
+ mixer_base + S5P_MXR_STATUS);
+}
+
+void s5p_mixer_stop(void)
+{
+ u32 reg = readl(mixer_base + S5P_MXR_STATUS);
+
+ reg &= ~S5P_MXR_STATUS_RUN;
+
+ writel(reg, mixer_base + S5P_MXR_STATUS);
+
+ do {
+ reg = readl(mixer_base + S5P_MXR_STATUS);
+ } while (!(reg & S5P_MXR_STATUS_IDLE_MODE));
+}
+
+void s5p_mixer_set_underflow_int_enable(enum s5p_mixer_layer layer, bool en)
+{
+ u32 enable_mask = 0;
+
+ switch (layer) {
+ case MIXER_VIDEO_LAYER:
+ enable_mask = S5P_MXR_INT_EN_VP_ENABLE;
+ break;
+
+ case MIXER_GPR0_LAYER:
+ enable_mask = S5P_MXR_INT_EN_GRP0_ENABLE;
+ break;
+
+ case MIXER_GPR1_LAYER:
+ enable_mask = S5P_MXR_INT_EN_GRP1_ENABLE;
+ break;
+ }
+
+ if (en) {
+ writel((readl(mixer_base + S5P_MXR_INT_EN) | enable_mask),
+ mixer_base + S5P_MXR_INT_EN);
+ } else {
+ writel((readl(mixer_base + S5P_MXR_INT_EN) & ~enable_mask),
+ mixer_base + S5P_MXR_INT_EN);
+ }
+}
+
+void s5p_mixer_set_vsync_interrupt(bool en)
+{
+ if (en) {
+ writel(S5P_MXR_INT_STATUS_VSYNC_CLEARED, mixer_base +
+ S5P_MXR_INT_STATUS);
+ writel((readl(mixer_base + S5P_MXR_INT_EN) |
+ S5P_MXR_INT_EN_VSYNC_ENABLE),
+ mixer_base + S5P_MXR_INT_EN);
+ } else {
+ writel((readl(mixer_base + S5P_MXR_INT_EN) &
+ ~S5P_MXR_INT_EN_VSYNC_ENABLE),
+ mixer_base + S5P_MXR_INT_EN);
+ }
+
+ tvout_dbg("%s mixer VSYNC interrupt.\n", en? "Enable": "Disable");
+}
+
+void s5p_mixer_clear_pend_all(void)
+{
+ writel(S5P_MXR_INT_STATUS_INT_FIRED | S5P_MXR_INT_STATUS_VP_FIRED |
+ S5P_MXR_INT_STATUS_GRP0_FIRED | S5P_MXR_INT_STATUS_GRP1_FIRED,
+ mixer_base + S5P_MXR_INT_STATUS);
+}
+
+irqreturn_t s5p_mixer_irq(int irq, void *dev_id)
+{
+ bool v_i_f;
+ bool g0_i_f;
+ bool g1_i_f;
+ bool mxr_i_f;
+ u32 temp_reg = 0;
+ unsigned long spin_flags;
+ u32 top_y_addr, top_c_addr;
+ int i = 0;
+ unsigned int pre_vp_buff_idx;
+
+ spin_lock_irqsave(&lock_mixer, spin_flags);
+
+ v_i_f = (readl(mixer_base + S5P_MXR_INT_STATUS)
+ & S5P_MXR_INT_STATUS_VP_FIRED) ? true : false;
+ g0_i_f = (readl(mixer_base + S5P_MXR_INT_STATUS)
+ & S5P_MXR_INT_STATUS_GRP0_FIRED) ? true : false;
+ g1_i_f = (readl(mixer_base + S5P_MXR_INT_STATUS)
+ & S5P_MXR_INT_STATUS_GRP1_FIRED) ? true : false;
+ mxr_i_f = (readl(mixer_base + S5P_MXR_INT_STATUS)
+ & S5P_MXR_INT_STATUS_INT_FIRED) ? true : false;
+
+ if (mxr_i_f) {
+ temp_reg |= S5P_MXR_INT_STATUS_INT_FIRED;
+
+ if (v_i_f) {
+ temp_reg |= S5P_MXR_INT_STATUS_VP_FIRED;
+ tvout_dbg("VP fifo under run!!\n");
+ }
+
+ if (g0_i_f) {
+ temp_reg |= S5P_MXR_INT_STATUS_GRP0_FIRED;
+ tvout_dbg("GRP0 fifo under run!!\n");
+ }
+
+ if (g1_i_f) {
+ temp_reg |= S5P_MXR_INT_STATUS_GRP1_FIRED;
+ tvout_dbg("GRP1 fifo under run!!\n");
+ }
+
+ if (!v_i_f && !g0_i_f && !g1_i_f) {
+ writel(S5P_MXR_INT_STATUS_VSYNC_CLEARED,
+ mixer_base + S5P_MXR_INT_STATUS);
+ s5p_vp_ctrl_get_src_addr(&top_y_addr, &top_c_addr);
+
+ pre_vp_buff_idx = s5ptv_vp_buff.vp_access_buff_idx;
+ for (i = 0; i < S5PTV_VP_BUFF_CNT; i++) {
+ if (top_y_addr == s5ptv_vp_buff.vp_buffs[i].phy_base) {
+ s5ptv_vp_buff.vp_access_buff_idx = i;
+ break;
+ }
+ }
+
+ for (i = 0; i < S5PTV_VP_BUFF_CNT - 1; i++) {
+ if (s5ptv_vp_buff.copy_buff_idxs[i]
+ == s5ptv_vp_buff.vp_access_buff_idx) {
+ s5ptv_vp_buff.copy_buff_idxs[i] = pre_vp_buff_idx;
+ break;
+ }
+ }
+ wake_up(&s5ptv_wq);
+ } else {
+ writel(temp_reg, mixer_base + S5P_MXR_INT_STATUS);
+ }
+ }
+ spin_unlock_irqrestore(&lock_mixer, spin_flags);
+
+ return IRQ_HANDLED;
+}
+
+void s5p_mixer_init(void __iomem *addr)
+{
+ mixer_base = addr;
+
+ spin_lock_init(&lock_mixer);
+}