diff options
Diffstat (limited to 'drivers/media/video/samsung/tvout')
-rw-r--r-- | drivers/media/video/samsung/tvout/Kconfig | 10 | ||||
-rw-r--r-- | drivers/media/video/samsung/tvout/hw_if/hdcp.c | 20 | ||||
-rw-r--r-- | drivers/media/video/samsung/tvout/hw_if/hdmi.c | 56 | ||||
-rw-r--r-- | drivers/media/video/samsung/tvout/hw_if/hw_if.h | 26 | ||||
-rw-r--r-- | drivers/media/video/samsung/tvout/s5p_mixer_ctrl.c | 76 | ||||
-rw-r--r-- | drivers/media/video/samsung/tvout/s5p_tvif_ctrl.c | 89 | ||||
-rw-r--r-- | drivers/media/video/samsung/tvout/s5p_tvout.c | 38 | ||||
-rw-r--r-- | drivers/media/video/samsung/tvout/s5p_tvout_common_lib.h | 10 | ||||
-rw-r--r-- | drivers/media/video/samsung/tvout/s5p_tvout_ctrl.h | 4 | ||||
-rw-r--r-- | drivers/media/video/samsung/tvout/s5p_tvout_fb.c | 16 | ||||
-rw-r--r-- | drivers/media/video/samsung/tvout/s5p_tvout_hpd.c | 80 | ||||
-rw-r--r-- | drivers/media/video/samsung/tvout/s5p_tvout_v4l2.c | 115 | ||||
-rw-r--r-- | drivers/media/video/samsung/tvout/s5p_vp_ctrl.c | 20 |
13 files changed, 447 insertions, 113 deletions
diff --git a/drivers/media/video/samsung/tvout/Kconfig b/drivers/media/video/samsung/tvout/Kconfig index 176efeb..da7bda7 100644 --- a/drivers/media/video/samsung/tvout/Kconfig +++ b/drivers/media/video/samsung/tvout/Kconfig @@ -62,6 +62,16 @@ config HDMI_CONTROLLED_BY_EXT_IC For example, the H/W has HDMI level shifter then it should be turned on when HPD interrupt comes. +config HDMI_TX_STRENGTH + bool "Tuning TX amplitude" + depends on VIDEO_TVOUT && ARCH_EXYNOS4 + default n + ---help--- + Say y here if the H/W needs to be tuned for TX amplitude. + HDMI driver will take the values registered at board file + and apply them through HDMI phy i2c according to the requested + channel number. + config HDMI_SWITCH_HPD bool "HDMI HPD switch uevent driver support" depends on HDMI_HPD diff --git a/drivers/media/video/samsung/tvout/hw_if/hdcp.c b/drivers/media/video/samsung/tvout/hw_if/hdcp.c index 569de28..41caf19 100644 --- a/drivers/media/video/samsung/tvout/hw_if/hdcp.c +++ b/drivers/media/video/samsung/tvout/hw_if/hdcp.c @@ -379,7 +379,9 @@ static int s5p_hdcp_read_bcaps(void) if (s5p_ddc_read(HDCP_Bcaps, BCAPS_SIZE, &bcaps) < 0) goto bcaps_read_err; - if (s5p_hdmi_ctrl_status() == false || !s5p_hdmi_reg_get_hpd_status() || on_stop_process) + if (s5p_hdmi_ctrl_status() == false || + !s5p_hdmi_reg_get_hpd_status() || + on_stop_process) goto bcaps_read_err; writeb(bcaps, hdmi_base + S5P_HDMI_HDCP_BCAPS); @@ -532,7 +534,8 @@ static void s5p_hdcp_reset_auth(void) unsigned long spin_flags; if (s5p_hdmi_ctrl_status() == false || - !s5p_hdmi_reg_get_hpd_status() || on_stop_process) + !s5p_hdmi_reg_get_hpd_status() || + on_stop_process) return; spin_lock_irqsave(&hdcp_info.reset_lock, spin_flags); @@ -956,9 +959,12 @@ check_ri_err: static void s5p_hdcp_work(void *arg) { + s5p_tvout_mutex_lock(); if (!hdcp_info.hdcp_enable || s5p_hdmi_ctrl_status() == false || - !s5p_hdmi_reg_get_hpd_status() || on_stop_process) + !s5p_hdmi_reg_get_hpd_status() || on_stop_process) { + s5p_tvout_mutex_unlock(); return; + } if (hdcp_info.event & HDCP_EVENT_READ_BKSV_START) { if (s5p_hdcp_bksv() < 0) @@ -987,13 +993,16 @@ static void s5p_hdcp_work(void *arg) else hdcp_info.event &= ~HDCP_EVENT_CHECK_RI_START; } + s5p_tvout_mutex_unlock(); return; work_err: if (!hdcp_info.hdcp_enable || s5p_hdmi_ctrl_status() == false || !s5p_hdmi_reg_get_hpd_status() || on_stop_process) { + s5p_tvout_mutex_unlock(); return; } s5p_hdcp_reset_auth(); + s5p_tvout_mutex_unlock(); } irqreturn_t s5p_hdcp_irq_handler(int irq, void *dev_id) @@ -1121,3 +1130,8 @@ int s5p_hdcp_encrypt_stop(bool on) return 0; } + +void s5p_hdcp_flush_work(void) +{ + flush_workqueue(hdcp_wq); +} diff --git a/drivers/media/video/samsung/tvout/hw_if/hdmi.c b/drivers/media/video/samsung/tvout/hw_if/hdmi.c index dfb3152..67099af 100644 --- a/drivers/media/video/samsung/tvout/hw_if/hdmi.c +++ b/drivers/media/video/samsung/tvout/hw_if/hdmi.c @@ -871,10 +871,10 @@ static void s5p_hdmi_print_phy_config(void) printk(KERN_WARNING "read buffer :\n"); - for (i = 1; i < size; i++) { + for (i = 0; i < size; i++) { printk("0x%02x", read_buffer[i]); - if (i % 8) + if ((i+1) % 8) printk(" "); else printk("\n"); @@ -1146,6 +1146,58 @@ void s5p_hdmi_reg_sw_reset(void) s5p_hdmi_ctrl_clock(0); } +#ifdef CONFIG_HDMI_TX_STRENGTH +int s5p_hdmi_phy_set_tx_strength(u8 ch, u8 *value) +{ + u8 buff[2]; + + if (ch & TX_EMP_LVL) { /* REG10 BIT7:4 */ + buff[0] = HDMI_PHY_I2C_REG10; + buff[1] = (value[TX_EMP_LVL_VAL] & 0x0f) << 4; + if (s5p_hdmi_i2c_phy_write(PHY_I2C_ADDRESS, 2, buff) != 0) + goto err_exit; + } + + if (ch & TX_AMP_LVL) { /* REG10 BIT3:0, REG0F BIT7 */ + buff[0] = HDMI_PHY_I2C_REG10; + buff[1] = (value[TX_AMP_LVL_VAL] & 0x0e) >> 1; + if (s5p_hdmi_i2c_phy_write(PHY_I2C_ADDRESS, 2, buff) != 0) + goto err_exit; + buff[0] = HDMI_PHY_I2C_REG0F; + buff[1] = (value[TX_AMP_LVL_VAL] & 0x01) << 7; + if (s5p_hdmi_i2c_phy_write(PHY_I2C_ADDRESS, 2, buff) != 0) + goto err_exit; + } + + if (ch & TX_LVL_CH0) { /* REG04 BIT7:6 */ + buff[0] = HDMI_PHY_I2C_REG04; + buff[1] = (value[TX_LVL_CH0_VAL] & 0x3) << 6; + if (s5p_hdmi_i2c_phy_write(PHY_I2C_ADDRESS, 2, buff) != 0) + goto err_exit; + } + + if (ch & TX_LVL_CH1) { /* REG13 BIT1:0 */ + buff[0] = HDMI_PHY_I2C_REG13; + buff[1] = (value[TX_LVL_CH1_VAL] & 0x3); + if (s5p_hdmi_i2c_phy_write(PHY_I2C_ADDRESS, 2, buff) != 0) + goto err_exit; + } + + if (ch & TX_LVL_CH2) { /* REG17 BIT1:0 */ + buff[0] = HDMI_PHY_I2C_REG17; + buff[1] = (value[TX_LVL_CH2_VAL] & 0x3); + if (s5p_hdmi_i2c_phy_write(PHY_I2C_ADDRESS, 2, buff) != 0) + goto err_exit; + } + + return 0; + +err_exit: + pr_err("%s: failed to set tx strength\n", __func__); + return -1; +} +#endif + int s5p_hdmi_phy_power(bool on) { u32 size; diff --git a/drivers/media/video/samsung/tvout/hw_if/hw_if.h b/drivers/media/video/samsung/tvout/hw_if/hw_if.h index 11bda99..e437b0a 100644 --- a/drivers/media/video/samsung/tvout/hw_if/hw_if.h +++ b/drivers/media/video/samsung/tvout/hw_if/hw_if.h @@ -364,6 +364,27 @@ struct s5p_hdmi_v_format { u8 mhl_vsync; }; +#ifdef CONFIG_HDMI_TX_STRENGTH +#define HDMI_PHY_I2C_REG10 0x10 +#define HDMI_PHY_I2C_REG0F 0x0F +#define HDMI_PHY_I2C_REG04 0x04 +#define HDMI_PHY_I2C_REG13 0x13 +#define HDMI_PHY_I2C_REG17 0x17 + +#define TX_EMP_LVL 0x10 +#define TX_AMP_LVL 0x08 +#define TX_LVL_CH0 0x04 +#define TX_LVL_CH1 0x02 +#define TX_LVL_CH2 0x01 + +#define TX_EMP_LVL_VAL 0 +#define TX_AMP_LVL_VAL 1 +#define TX_LVL_CH0_VAL 2 +#define TX_LVL_CH1_VAL 3 +#define TX_LVL_CH2_VAL 4 + +extern int s5p_hdmi_phy_set_tx_strength(u8 ch, u8 *value); +#endif extern int s5p_hdmi_phy_power(bool on); extern s32 s5p_hdmi_phy_config( enum phy_freq freq, enum s5p_hdmi_color_depth cd); @@ -750,6 +771,7 @@ extern int s5p_hdcp_encrypt_stop(bool on); extern int __init s5p_hdcp_init(void); extern int s5p_hdcp_start(void); extern int s5p_hdcp_stop(void); +extern void s5p_hdcp_flush_work(void); /**************************************** * Definitions for sdo ctrl class @@ -1000,6 +1022,10 @@ struct s5p_tvif_ctrl_private_data { struct device *bus_dev; /* for BusFreq with Opp */ #endif struct device *dev; /* hpd device pointer */ +#ifdef CONFIG_HDMI_TX_STRENGTH + u8 tx_ch; + u8 *tx_val; +#endif }; #endif /* _SAMSUNG_TVOUT_HW_IF_H_ */ diff --git a/drivers/media/video/samsung/tvout/s5p_mixer_ctrl.c b/drivers/media/video/samsung/tvout/s5p_mixer_ctrl.c index a0169cb..5e78a3c 100644 --- a/drivers/media/video/samsung/tvout/s5p_mixer_ctrl.c +++ b/drivers/media/video/samsung/tvout/s5p_mixer_ctrl.c @@ -241,7 +241,7 @@ static void s5p_mixer_ctrl_clock(bool on) clk_enable(s5p_mixer_ctrl_private.clk[ACLK].ptr); - // Restore mixer_base address + /* Restore mixer_base address */ s5p_mixer_init(s5p_mixer_ctrl_private.reg_mem.base); } else { clk_disable(s5p_mixer_ctrl_private.clk[ACLK].ptr); @@ -252,7 +252,7 @@ static void s5p_mixer_ctrl_clock(bool on) clk_disable(s5p_mixer_ctrl_private.clk[MUX].ptr); - // Set mixer_base address to NULL + /* Set mixer_base address to NULL */ s5p_mixer_init(NULL); } } @@ -267,7 +267,7 @@ void s5p_mixer_ctrl_init_grp_layer(enum s5p_mixer_layer layer) { struct s5ptvfb_user_scaling scaling; -#ifdef CONFIG_HAS_EARLYSUSPEND +#ifdef CLOCK_GATING_ON_EARLY_SUSPEND if (suspend_status) { tvout_dbg("driver is suspend_status\n"); return; @@ -278,12 +278,16 @@ void s5p_mixer_ctrl_init_grp_layer(enum s5p_mixer_layer layer) s5p_mixer_set_priority(layer, s5p_mixer_ctrl_private.layer[layer].priority); s5p_mixer_set_pre_mul_mode(layer, - s5p_mixer_ctrl_private.layer[layer].pre_mul_mode); + s5p_mixer_ctrl_private.layer[layer]. + pre_mul_mode); s5p_mixer_set_chroma_key(layer, - s5p_mixer_ctrl_private.layer[layer].chroma_enable, - s5p_mixer_ctrl_private.layer[layer].chroma_key); + s5p_mixer_ctrl_private.layer[layer]. + chroma_enable, + s5p_mixer_ctrl_private.layer[layer]. + chroma_key); s5p_mixer_set_layer_blend(layer, - s5p_mixer_ctrl_private.layer[layer].layer_blend); + s5p_mixer_ctrl_private.layer[layer]. + layer_blend); s5p_mixer_set_alpha(layer, s5p_mixer_ctrl_private.layer[layer].alpha); s5p_mixer_set_grp_layer_dst_pos(layer, @@ -299,7 +303,8 @@ void s5p_mixer_ctrl_init_grp_layer(enum s5p_mixer_layer layer) } } -int s5p_mixer_ctrl_set_pixel_format(enum s5p_mixer_layer layer, u32 bpp, u32 trans_len) +int s5p_mixer_ctrl_set_pixel_format( + enum s5p_mixer_layer layer, u32 bpp, u32 trans_len) { enum s5p_mixer_color_fmt format; @@ -322,7 +327,7 @@ int s5p_mixer_ctrl_set_pixel_format(enum s5p_mixer_layer layer, u32 bpp, u32 tra s5p_mixer_ctrl_private.layer[layer].format = format; -#ifdef CONFIG_HAS_EARLYSUSPEND +#ifdef CLOCK_GATING_ON_EARLY_SUSPEND if (suspend_status) { tvout_dbg("driver is suspend_status\n"); return 0; @@ -351,7 +356,7 @@ int s5p_mixer_ctrl_enable_layer(enum s5p_mixer_layer layer) tvout_err("invalid layer\n"); return -1; } -#ifdef CONFIG_HAS_EARLYSUSPEND +#ifdef CLOCK_GATING_ON_EARLY_SUSPEND if (suspend_status) { tvout_dbg("driver is suspend_status\n"); return 0; @@ -384,7 +389,7 @@ int s5p_mixer_ctrl_disable_layer(enum s5p_mixer_layer layer) return -1; } -#ifdef CONFIG_HAS_EARLYSUSPEND +#ifdef CLOCK_GATING_ON_EARLY_SUSPEND if (suspend_status) { tvout_dbg("driver is suspend_status\n"); return 0; @@ -523,7 +528,7 @@ int s5p_mixer_ctrl_set_dst_win_pos(enum s5p_mixer_layer layer, s5p_mixer_ctrl_private.layer[layer].dst_x = (u32)dst_x; s5p_mixer_ctrl_private.layer[layer].dst_y = (u32)dst_y; -#ifdef CONFIG_HAS_EARLYSUSPEND +#ifdef CLOCK_GATING_ON_EARLY_SUSPEND if (suspend_status) { tvout_dbg("driver is suspend_status\n"); return 0; @@ -551,7 +556,7 @@ int s5p_mixer_ctrl_set_src_win_pos(enum s5p_mixer_layer layer, s5p_mixer_ctrl_private.layer[layer].width = w; s5p_mixer_ctrl_private.layer[layer].height = h; -#ifdef CONFIG_HAS_EARLYSUSPEND +#ifdef CLOCK_GATING_ON_EARLY_SUSPEND if (suspend_status) { tvout_dbg("driver is suspend_status\n"); return 0; @@ -559,7 +564,8 @@ int s5p_mixer_ctrl_set_src_win_pos(enum s5p_mixer_layer layer, #endif { if (s5p_mixer_ctrl_private.running) - s5p_mixer_set_grp_layer_src_pos(layer, src_x, src_y, w, w, h); + s5p_mixer_set_grp_layer_src_pos( + layer, src_x, src_y, w, w, h); } return 0; @@ -577,7 +583,7 @@ int s5p_mixer_ctrl_set_buffer_address(enum s5p_mixer_layer layer, s5p_mixer_ctrl_private.layer[layer].fb_addr = start_addr; -#ifdef CONFIG_HAS_EARLYSUSPEND +#ifdef CLOCK_GATING_ON_EARLY_SUSPEND if (suspend_status) { tvout_dbg("driver is suspend_status\n"); return 0; @@ -602,7 +608,7 @@ int s5p_mixer_ctrl_set_chroma_key(enum s5p_mixer_layer layer, s5p_mixer_ctrl_private.layer[layer].chroma_enable = enabled; s5p_mixer_ctrl_private.layer[layer].chroma_key = chroma.key; -#ifdef CONFIG_HAS_EARLYSUSPEND +#ifdef CLOCK_GATING_ON_EARLY_SUSPEND if (suspend_status) { tvout_dbg("driver is suspend_status\n"); return 0; @@ -709,7 +715,7 @@ int s5p_mixer_ctrl_set_alpha_blending(enum s5p_mixer_layer layer, case PIXEL_BLENDING: tvout_dbg("pixel blending\n"); s5p_mixer_ctrl_private.layer[layer].pixel_blend = true; -#ifdef CONFIG_HAS_EARLYSUSPEND +#ifdef CLOCK_GATING_ON_EARLY_SUSPEND if (suspend_status) { tvout_dbg("driver is suspend_status\n"); return 0; @@ -723,7 +729,7 @@ int s5p_mixer_ctrl_set_alpha_blending(enum s5p_mixer_layer layer, tvout_dbg("layer blending : alpha value = 0x%x\n", alpha); s5p_mixer_ctrl_private.layer[layer].layer_blend = true; s5p_mixer_ctrl_private.layer[layer].alpha = alpha; -#ifdef CONFIG_HAS_EARLYSUSPEND +#ifdef CLOCK_GATING_ON_EARLY_SUSPEND if (suspend_status) { tvout_dbg("driver is suspend_status\n"); return 0; @@ -739,7 +745,7 @@ int s5p_mixer_ctrl_set_alpha_blending(enum s5p_mixer_layer layer, tvout_dbg("alpha blending off\n"); s5p_mixer_ctrl_private.layer[layer].pixel_blend = false; s5p_mixer_ctrl_private.layer[layer].layer_blend = false; -#ifdef CONFIG_HAS_EARLYSUSPEND +#ifdef CLOCK_GATING_ON_EARLY_SUSPEND if (suspend_status) { tvout_dbg("driver is suspend_status\n"); return 0; @@ -780,7 +786,7 @@ int s5p_mixer_ctrl_scaling(enum s5p_mixer_layer layer, s5p_mixer_ctrl_private.layer[layer].ver = scaling.ver; s5p_mixer_ctrl_private.layer[layer].hor = scaling.hor; -#ifdef CONFIG_HAS_EARLYSUSPEND +#ifdef CLOCK_GATING_ON_EARLY_SUSPEND if (suspend_status) { tvout_dbg("driver is suspend_status\n"); return 0; @@ -796,7 +802,8 @@ int s5p_mixer_ctrl_mux_clk(struct clk *ptr) { if (clk_set_parent(s5p_mixer_ctrl_private.clk[MUX].ptr, ptr)) { tvout_err("unable to set parent %s of clock %s.\n", - ptr->name, s5p_mixer_ctrl_private.clk[MUX].ptr->name); + ptr->name, + s5p_mixer_ctrl_private.clk[MUX].ptr->name); return -1; } @@ -828,6 +835,12 @@ bool s5p_mixer_ctrl_get_vsync_interrupt() return s5p_mixer_ctrl_private.vsync_interrupt_enable; } +void s5p_mixer_ctrl_disable_vsync_interrupt() +{ + if (s5p_mixer_ctrl_private.running) + s5p_mixer_set_vsync_interrupt(false); +} + void s5p_mixer_ctrl_clear_pend_all(void) { if (s5p_mixer_ctrl_private.running) @@ -840,7 +853,7 @@ void s5p_mixer_ctrl_stop(void) tvout_dbg("running(%d)\n", s5p_mixer_ctrl_private.running); if (s5p_mixer_ctrl_private.running) { -#ifdef CONFIG_HAS_EARLYSUSPEND +#ifdef CLOCK_GATING_ON_EARLY_SUSPEND if (suspend_status) { tvout_dbg("driver is suspend_status\n"); } else @@ -848,11 +861,12 @@ void s5p_mixer_ctrl_stop(void) { s5p_mixer_set_vsync_interrupt(false); - for (i = 0; i < S5PTV_VP_BUFF_CNT -1; i++) + for (i = 0; i < S5PTV_VP_BUFF_CNT-1; i++) s5ptv_vp_buff.copy_buff_idxs[i] = i; s5ptv_vp_buff.curr_copy_idx = 0; - s5ptv_vp_buff.vp_access_buff_idx = S5PTV_VP_BUFF_CNT - 1; + s5ptv_vp_buff.vp_access_buff_idx = + S5PTV_VP_BUFF_CNT - 1; s5p_mixer_stop(); s5p_mixer_ctrl_clock(0); @@ -1006,10 +1020,24 @@ int s5p_mixer_ctrl_start( s5p_mixer_init_csc_coef_default(csc_for_coeff); s5p_mixer_init_display_mode(disp, out, csc); +#ifndef __CONFIG_HDMI_SUPPORT_FULL_RANGE__ if (!s5p_tvif_get_q_range() || out == TVOUT_HDMI_RGB) mixer_video_limiter = true; else mixer_video_limiter = false; +#else + /* full range */ + if ((out == TVOUT_HDMI_RGB && disp == TVOUT_480P_60_4_3) || + (out != TVOUT_HDMI_RGB && s5p_tvif_get_q_range())) { + mixer_video_limiter = false; + for (i = MIXER_BG_COLOR_0; i <= MIXER_BG_COLOR_2; i++) + s5p_mixer_ctrl_private.bg_color[i].color_y = 0; + } else { /* limited range */ + mixer_video_limiter = true; + for (i = MIXER_BG_COLOR_0; i <= MIXER_BG_COLOR_2; i++) + s5p_mixer_ctrl_private.bg_color[i].color_y = 16; + } +#endif s5p_mixer_set_video_limiter(s5p_mixer_ctrl_private.v_layer.y_min, s5p_mixer_ctrl_private.v_layer.y_max, diff --git a/drivers/media/video/samsung/tvout/s5p_tvif_ctrl.c b/drivers/media/video/samsung/tvout/s5p_tvif_ctrl.c index 93cb640..43e7a1f 100644 --- a/drivers/media/video/samsung/tvout/s5p_tvif_ctrl.c +++ b/drivers/media/video/samsung/tvout/s5p_tvif_ctrl.c @@ -49,6 +49,12 @@ #if defined(CONFIG_BUSFREQ_OPP) || defined(CONFIG_BUSFREQ_LOCK_WRAPPER) #include <mach/dev.h> #endif +#include <mach/regs-hdmi.h> + +#ifdef CONFIG_HDMI_TX_STRENGTH +#include <plat/tvout.h> +#endif + #include "s5p_tvout_common_lib.h" #include "hw_if/hw_if.h" @@ -1758,7 +1764,7 @@ static void s5p_sdo_ctrl_clock(bool on) #ifdef CONFIG_ARCH_EXYNOS4 s5p_tvout_pm_runtime_get(); #endif - // Restore sdo_base address + /* Restore sdo_base address */ s5p_sdo_init(s5p_sdo_ctrl_private.reg_mem.base); clk_enable(s5p_sdo_ctrl_private.clk[SDO_PCLK].ptr); @@ -1771,7 +1777,7 @@ static void s5p_sdo_ctrl_clock(bool on) clk_disable(s5p_sdo_ctrl_private.clk[SDO_MUX].ptr); - // Set sdo_base address to NULL + /* Set sdo_base address to NULL */ s5p_sdo_init(NULL); } @@ -2362,8 +2368,10 @@ static void s5p_hdmi_ctrl_internal_stop(void) #ifdef CONFIG_HDMI_HPD s5p_hpd_set_eint(); #endif - if (ctrl->hdcp_en) + if (ctrl->hdcp_en) { s5p_hdcp_stop(); + s5p_hdcp_flush_work(); + } s5p_hdmi_reg_enable(false); @@ -2376,10 +2384,16 @@ int s5p_hdmi_ctrl_phy_power(bool on) if (on) { /* on */ clk_enable(s5ptv_status.i2c_phy_clk); - // Restore i2c_hdmi_phy_base address + /* Restore i2c_hdmi_phy_base address */ s5p_hdmi_phy_init(s5p_hdmi_ctrl_private.reg_mem[HDMI_PHY].base); s5p_hdmi_phy_power(true); +#ifdef CONFIG_HDMI_TX_STRENGTH + if (s5p_tvif_ctrl_private.tx_val) + s5p_hdmi_phy_set_tx_strength( + s5p_tvif_ctrl_private.tx_ch, + s5p_tvif_ctrl_private.tx_val); +#endif } else { /* @@ -2398,7 +2412,7 @@ int s5p_hdmi_ctrl_phy_power(bool on) s5p_hdmi_phy_power(false); clk_disable(s5ptv_status.i2c_phy_clk); - // Set i2c_hdmi_phy_base to NULL + /* Set i2c_hdmi_phy_base to NULL */ s5p_hdmi_phy_init(NULL); } @@ -2419,7 +2433,7 @@ void s5p_hdmi_ctrl_clock(bool on) #endif clk_enable(clk[HDMI_PCLK].ptr); - // Restore hdmi_base address + /* Restore hdmi_base address */ s5p_hdmi_init(s5p_hdmi_ctrl_private.reg_mem[HDMI].base); } else { clk_disable(clk[HDMI_PCLK].ptr); @@ -2430,7 +2444,7 @@ void s5p_hdmi_ctrl_clock(bool on) clk_disable(clk[HDMI_MUX].ptr); - // Set hdmi_base to NULL + /* Set hdmi_base to NULL */ s5p_hdmi_init(NULL); } } @@ -2447,7 +2461,7 @@ void s5p_hdmi_ctrl_stop(void) tvout_dbg("running(%d)\n", ctrl->running); if (ctrl->running) { ctrl->running = false; -#ifdef CONFIG_HAS_EARLYSUSPEND +#ifdef CLOCK_GATING_ON_EARLY_SUSPEND if (suspend_status) { tvout_dbg("driver is suspend_status\n"); } else @@ -2681,7 +2695,7 @@ static int s5p_tvif_ctrl_internal_stop(void) case TVOUT_HDMI: case TVOUT_HDMI_RGB: s5p_hdmi_ctrl_stop(); -#ifdef CONFIG_HAS_EARLYSUSPEND +#ifdef CLOCK_GATING_ON_EARLY_SUSPEND if (suspend_status) { tvout_dbg("driver is suspend_status\n"); } else @@ -2705,6 +2719,10 @@ static void s5p_tvif_ctrl_internal_start( enum s5p_tvout_o_mode inf) { tvout_dbg("\n"); +#ifdef __CONFIG_HDMI_SUPPORT_FULL_RANGE__ + s5p_hdmi_output[inf].reg.pxl_limit = + S5P_HDMI_PX_LMT_CTRL_BYPASS; +#endif s5p_mixer_ctrl_set_int_enable(false); /* Clear All Interrupt Pending */ @@ -2724,6 +2742,47 @@ static void s5p_tvif_ctrl_internal_start( case TVOUT_HDMI: case TVOUT_HDMI_RGB: case TVOUT_DVI: +#ifdef __CONFIG_HDMI_SUPPORT_FULL_RANGE__ + switch (std) { + case TVOUT_480P_60_4_3: + if (inf == TVOUT_HDMI_RGB) /* full range */ + s5p_hdmi_output[inf].reg.pxl_limit = + S5P_HDMI_PX_LMT_CTRL_BYPASS; + else if (s5p_tvif_get_q_range()) /* full range */ + s5p_hdmi_output[inf].reg.pxl_limit = + S5P_HDMI_PX_LMT_CTRL_BYPASS; + else /* limited range */ + s5p_hdmi_output[inf].reg.pxl_limit = + S5P_HDMI_PX_LMT_CTRL_YPBPR; + break; + case TVOUT_480P_60_16_9: + case TVOUT_480P_59: + case TVOUT_576P_50_16_9: + case TVOUT_576P_50_4_3: + case TVOUT_720P_60: + case TVOUT_720P_50: + case TVOUT_720P_59: + case TVOUT_1080I_60: + case TVOUT_1080I_59: + case TVOUT_1080I_50: + case TVOUT_1080P_60: + case TVOUT_1080P_30: + case TVOUT_1080P_59: + case TVOUT_1080P_50: + if (inf == TVOUT_HDMI_RGB) /* limited range */ + s5p_hdmi_output[inf].reg.pxl_limit = + S5P_HDMI_PX_LMT_CTRL_RGB; + else if (s5p_tvif_get_q_range()) /* full range */ + s5p_hdmi_output[inf].reg.pxl_limit = + S5P_HDMI_PX_LMT_CTRL_BYPASS; + else /* limited range */ + s5p_hdmi_output[inf].reg.pxl_limit = + S5P_HDMI_PX_LMT_CTRL_YPBPR; + break; + default: + break; + } +#endif s5p_hdmi_ctrl_phy_power(1); if (s5p_mixer_ctrl_start(std, inf) < 0) @@ -2854,7 +2913,7 @@ int s5p_tvif_ctrl_start( goto cannot_change; } -#ifdef CONFIG_HAS_EARLYSUSPEND +#ifdef CLOCK_GATING_ON_EARLY_SUSPEND if (suspend_status) { tvout_dbg("driver is suspend_status\n"); } else @@ -2889,6 +2948,16 @@ void s5p_tvif_ctrl_stop(void) int s5p_tvif_ctrl_constructor(struct platform_device *pdev) { +#ifdef CONFIG_HDMI_TX_STRENGTH + struct s5p_platform_tvout *pdata = to_tvout_plat(&pdev->dev); + s5p_tvif_ctrl_private.tx_ch = 0x00; + s5p_tvif_ctrl_private.tx_val = NULL; + if ((pdata) && (pdata->tx_tune)) { + s5p_tvif_ctrl_private.tx_ch = pdata->tx_tune->tx_ch; + s5p_tvif_ctrl_private.tx_val = pdata->tx_tune->tx_val; + } +#endif + #ifdef CONFIG_ANALOG_TVENC if (s5p_sdo_ctrl_constructor(pdev)) goto err; diff --git a/drivers/media/video/samsung/tvout/s5p_tvout.c b/drivers/media/video/samsung/tvout/s5p_tvout.c index 7407670..5f00ebc 100644 --- a/drivers/media/video/samsung/tvout/s5p_tvout.c +++ b/drivers/media/video/samsung/tvout/s5p_tvout.c @@ -13,6 +13,7 @@ #include <linux/clk.h> #include <linux/io.h> #include <linux/mm.h> +#include <linux/delay.h> #if defined(CONFIG_S5P_SYSMMU_TV) #include <plat/sysmmu.h> @@ -25,6 +26,10 @@ #include <mach/media.h> #endif +#if defined(CONFIG_HDMI_TX_STRENGTH) && !defined(CONFIG_USER_ALLOC_TVOUT) +#include <plat/tvout.h> +#endif + #include "s5p_tvout_common_lib.h" #include "s5p_tvout_ctrl.h" #include "s5p_tvout_fb.h" @@ -291,6 +296,12 @@ static int __devinit s5p_tvout_probe(struct platform_device *pdev) struct device *hdmi_audio_dev; #endif +#if defined(CONFIG_HDMI_TX_STRENGTH) && !defined(CONFIG_USER_ALLOC_TVOUT) + struct s5p_platform_tvout *pdata; + u8 tx_ch; + u8 *tx_val; +#endif + #ifdef CONFIG_TVOUT_DEBUG struct class *sec_tvout; tvout_dbg_flag = 1 << DBG_FLAG_HPD; @@ -339,6 +350,15 @@ static int __devinit s5p_tvout_probe(struct platform_device *pdev) s5p_hdmi_phy_power(true); if (s5p_tvif_ctrl_start(TVOUT_720P_60, TVOUT_HDMI) < 0) goto err_tvif_start; +#ifdef CONFIG_HDMI_TX_STRENGTH + pdata = to_tvout_plat(&pdev->dev); + if (pdata && pdata->tx_tune) { + tx_ch = pdata->tx_tune->tx_ch; + tx_val = pdata->tx_tune->tx_val; + } + if (tx_ch && tx_val) + s5p_hdmi_phy_set_tx_strength(tx_ch, tx_val); +#endif #endif /* prepare memory */ @@ -495,14 +515,19 @@ static int s5p_tvout_remove(struct platform_device *pdev) static void s5p_tvout_early_suspend(struct early_suspend *h) { tvout_dbg("\n"); +#ifdef CLOCK_GATING_ON_EARLY_SUSPEND mutex_lock(&s5p_tvout_mutex); - s5p_mixer_ctrl_set_vsync_interrupt(false); + /* disable vsync interrupt during early suspend */ + s5p_mixer_ctrl_disable_vsync_interrupt(); s5p_vp_ctrl_suspend(); s5p_mixer_ctrl_suspend(); s5p_tvif_ctrl_suspend(); suspend_status = 1; tvout_dbg("suspend_status is true\n"); mutex_unlock(&s5p_tvout_mutex); +#else + suspend_status = 1; +#endif return; } @@ -511,6 +536,7 @@ static void s5p_tvout_late_resume(struct early_suspend *h) { tvout_dbg("\n"); +#ifdef CLOCK_GATING_ON_EARLY_SUSPEND mutex_lock(&s5p_tvout_mutex); #if defined(CONFIG_CPU_EXYNOS4212) || defined(CONFIG_CPU_EXYNOS4412) @@ -521,11 +547,17 @@ static void s5p_tvout_late_resume(struct early_suspend *h) #endif suspend_status = 0; tvout_dbg("suspend_status is false\n"); + s5p_tvif_ctrl_resume(); s5p_mixer_ctrl_resume(); s5p_vp_ctrl_resume(); - s5p_mixer_ctrl_set_vsync_interrupt(s5p_mixer_ctrl_get_vsync_interrupt()); + /* restore vsync interrupt setting */ + s5p_mixer_ctrl_set_vsync_interrupt( + s5p_mixer_ctrl_get_vsync_interrupt()); mutex_unlock(&s5p_tvout_mutex); +#else + suspend_status = 0; +#endif return; } @@ -562,8 +594,10 @@ static int s5p_tvout_suspend(struct device *dev) static int s5p_tvout_resume(struct device *dev) { tvout_dbg("\n"); +#if defined(CLOCK_GATING_ON_EARLY_SUSPEND) #if defined(CONFIG_CPU_EXYNOS4212) || defined(CONFIG_CPU_EXYNOS4412) flag_after_resume = true; +#endif #else queue_work_on(0, tvout_resume_wq, &tvout_resume_work); #endif diff --git a/drivers/media/video/samsung/tvout/s5p_tvout_common_lib.h b/drivers/media/video/samsung/tvout/s5p_tvout_common_lib.h index e43b9c7..467ab1d 100644 --- a/drivers/media/video/samsung/tvout/s5p_tvout_common_lib.h +++ b/drivers/media/video/samsung/tvout/s5p_tvout_common_lib.h @@ -45,6 +45,12 @@ do { \ #endif #endif +/* +#if defined(CONFIG_MACH_T0) || defined(CONFIG_MACH_M3) +#define __CONFIG_HDMI_SUPPORT_FULL_RANGE__ +#endif +*/ + #define S5PTV_FB_CNT 2 #define S5PTV_VP_BUFF_CNT 4 #define S5PTV_VP_BUFF_SIZE (4*1024*1024) @@ -53,6 +59,10 @@ do { \ #define HDMI_START_NUM 0x1000 +#ifdef CONFIG_CPU_EXYNOS4210 +#define CLOCK_GATING_ON_EARLY_SUSPEND +#endif + enum s5p_tvout_disp_mode { TVOUT_NTSC_M = 0, TVOUT_PAL_BDGHI, diff --git a/drivers/media/video/samsung/tvout/s5p_tvout_ctrl.h b/drivers/media/video/samsung/tvout/s5p_tvout_ctrl.h index 43043b4..b330a95 100644 --- a/drivers/media/video/samsung/tvout/s5p_tvout_ctrl.h +++ b/drivers/media/video/samsung/tvout/s5p_tvout_ctrl.h @@ -29,7 +29,8 @@ extern void s5p_mixer_ctrl_init_fb_addr_phy(enum s5p_mixer_layer layer, dma_addr_t fb_addr); extern void s5p_mixer_ctrl_init_grp_layer(enum s5p_mixer_layer layer); -extern int s5p_mixer_ctrl_set_pixel_format(enum s5p_mixer_layer layer, u32 bpp, u32 trans_len); +extern int s5p_mixer_ctrl_set_pixel_format( + enum s5p_mixer_layer layer, u32 bpp, u32 trans_len); extern int s5p_mixer_ctrl_enable_layer(enum s5p_mixer_layer layer); extern int s5p_mixer_ctrl_disable_layer(enum s5p_mixer_layer layer); extern int s5p_mixer_ctrl_set_priority(enum s5p_mixer_layer layer, u32 prio); @@ -52,6 +53,7 @@ extern int s5p_mixer_ctrl_mux_clk(struct clk *ptr); extern void s5p_mixer_ctrl_set_int_enable(bool en); extern void s5p_mixer_ctrl_set_vsync_interrupt(bool en); extern bool s5p_mixer_ctrl_get_vsync_interrupt(void); +extern void s5p_mixer_ctrl_disable_vsync_interrupt(void); extern void s5p_mixer_ctrl_clear_pend_all(void); extern void s5p_mixer_ctrl_stop(void); extern void s5p_mixer_ctrl_internal_start(void); diff --git a/drivers/media/video/samsung/tvout/s5p_tvout_fb.c b/drivers/media/video/samsung/tvout/s5p_tvout_fb.c index 5a2ce5a..c0a3508 100644 --- a/drivers/media/video/samsung/tvout/s5p_tvout_fb.c +++ b/drivers/media/video/samsung/tvout/s5p_tvout_fb.c @@ -303,7 +303,7 @@ static int s5p_tvout_fb_blank(int blank_mode, struct fb_info *fb) tvout_dbg("change blank mode\n"); -#ifdef CONFIG_HAS_EARLYSUSPEND +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(CLOCK_GATING_ON_EARLY_SUSPEND) s5p_tvout_mutex_lock(); #endif switch (fb->node) { @@ -336,12 +336,12 @@ static int s5p_tvout_fb_blank(int blank_mode, struct fb_info *fb) goto err_fb_blank; } -#ifdef CONFIG_HAS_EARLYSUSPEND +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(CLOCK_GATING_ON_EARLY_SUSPEND) s5p_tvout_mutex_unlock(); #endif return 1; err_fb_blank: -#ifdef CONFIG_HAS_EARLYSUSPEND +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(CLOCK_GATING_ON_EARLY_SUSPEND) s5p_tvout_mutex_unlock(); #endif return -1; @@ -356,7 +356,7 @@ static int s5p_tvout_fb_set_par(struct fb_info *fb) tvout_dbg("[fb%d] set_par\n", win->id); -#ifdef CONFIG_HAS_EARLYSUSPEND +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(CLOCK_GATING_ON_EARLY_SUSPEND) s5p_tvout_mutex_lock(); #endif if (!fb->fix.smem_start) { @@ -390,7 +390,7 @@ static int s5p_tvout_fb_set_par(struct fb_info *fb) s5p_mixer_ctrl_set_src_win_pos(layer, src_x, src_y, w, h); s5p_mixer_ctrl_set_alpha_blending(layer, win->alpha.mode, win->alpha.value); -#ifdef CONFIG_HAS_EARLYSUSPEND +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(CLOCK_GATING_ON_EARLY_SUSPEND) s5p_tvout_mutex_unlock(); #endif return 0; @@ -472,7 +472,7 @@ static int s5p_tvout_fb_ioctl(struct fb_info *fb, unsigned int cmd, } p; tvout_dbg("\n"); -#ifdef CONFIG_HAS_EARLYSUSPEND +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(CLOCK_GATING_ON_EARLY_SUSPEND) s5p_tvout_mutex_lock(); #endif switch (fb->node) { @@ -552,13 +552,13 @@ static int s5p_tvout_fb_ioctl(struct fb_info *fb, unsigned int cmd, s5p_mixer_ctrl_scaling(layer, p.user_scaling); break; } -#ifdef CONFIG_HAS_EARLYSUSPEND +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(CLOCK_GATING_ON_EARLY_SUSPEND) s5p_tvout_mutex_unlock(); #endif return 0; err_fb_ioctl: -#ifdef CONFIG_HAS_EARLYSUSPEND +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(CLOCK_GATING_ON_EARLY_SUSPEND) s5p_tvout_mutex_unlock(); #endif return -1; diff --git a/drivers/media/video/samsung/tvout/s5p_tvout_hpd.c b/drivers/media/video/samsung/tvout/s5p_tvout_hpd.c index 4f35a91..1c98453 100644 --- a/drivers/media/video/samsung/tvout/s5p_tvout_hpd.c +++ b/drivers/media/video/samsung/tvout/s5p_tvout_hpd.c @@ -67,6 +67,12 @@ struct hpd_struct { #endif }; +#ifdef CONFIG_HDMI_CONTROLLED_BY_EXT_IC +static work_func_t ext_ic_control_func(void) ; +static DECLARE_DELAYED_WORK(ext_ic_control_dwork, + (work_func_t)ext_ic_control_func); +#endif + static struct hpd_struct hpd_struct; static int last_hpd_state; @@ -81,6 +87,10 @@ static ssize_t s5p_hpd_read(struct file *file, char __user *buffer, static unsigned int s5p_hpd_poll(struct file *file, poll_table *wait); static long s5p_hpd_ioctl(struct file *file, unsigned int cmd, unsigned long arg); +#ifdef CONFIG_SAMSUNG_WORKAROUND_HPD_GLANCE +void mhl_hpd_handler(bool onoff); +bool (*is_mhl_power_state_on)(void); +#endif static const struct file_operations hpd_fops = { .owner = THIS_MODULE, @@ -139,6 +149,7 @@ static void s5p_hpd_kobject_uevent(void) if (hpd_state) { if (last_uevent_state == -1 || last_uevent_state == HPD_LO) { #ifdef CONFIG_HDMI_CONTROLLED_BY_EXT_IC + HPDPRINTK("ext_ic power ON\n"); hpd_struct.ext_ic_control(true); msleep(20); #endif @@ -154,9 +165,13 @@ static void s5p_hpd_kobject_uevent(void) KOBJ_CHANGE, envp); #endif HPDPRINTK("[HDMI] HPD event -connect!!!\n"); - on_start_process = true; + if (atomic_read(&hdmi_status) == HDMI_OFF) { + on_start_process = true; + } else { + on_start_process = false; + } HPDIFPRINTK("%s() on_start_process(%d)\n", - __func__, on_start_process); + __func__, on_start_process); } last_uevent_state = HPD_HI; } else { @@ -176,10 +191,14 @@ static void s5p_hpd_kobject_uevent(void) KOBJ_CHANGE, envp); #endif HPDPRINTK("[HDMI] HPD event -disconnet!!!\n"); - on_stop_process = true; -#ifdef CONFIG_HDMI_CONTROLLED_BY_EXT_IC - hpd_struct.ext_ic_control(false); -#endif + if (atomic_read(&hdmi_status) == HDMI_ON) { + on_stop_process = true; + } else { + on_stop_process = false; + } + HPDIFPRINTK("%s() on_stop_process(%d)\n", + __func__, on_stop_process); + } last_uevent_state = HPD_LO; } @@ -233,9 +252,16 @@ static unsigned int s5p_hpd_poll(struct file *file, poll_table * wait) void hdmi_send_audio_ch_num( int supported_ch_num, struct switch_dev *p_audio_ch_switch) { - printk(KERN_INFO "%s() hdmi_send_audio_ch_num :: " - "HDMI Audio supported ch = %d", - __func__, supported_ch_num); + if (last_uevent_state == HPD_LO) { + printk(KERN_INFO "[WARNING] %s() " + "HDMI Audio ch = %d but not send\n", + __func__, supported_ch_num); + return; + } else + printk(KERN_INFO "%s() " + "HDMI Audio ch = %d\n", + __func__, supported_ch_num); + p_audio_ch_switch->state = 0; switch_set_state(p_audio_ch_switch, (int)supported_ch_num); } @@ -366,7 +392,16 @@ static int s5p_hpd_irq_eint(int irq) atomic_set(&poll_state, 1); last_hpd_state = HPD_LO; +#ifdef CONFIG_SAMSUNG_WORKAROUND_HPD_GLANCE + if (is_mhl_power_state_on != NULL) + if (!is_mhl_power_state_on()) + mhl_hpd_handler(false); +#endif +#ifdef CONFIG_HDMI_CONTROLLED_BY_EXT_IC + schedule_delayed_work(&ext_ic_control_dwork , + msecs_to_jiffies(1000)); +#endif wake_up_interruptible(&hpd_struct.waitq); } schedule_work(&hpd_work); @@ -438,6 +473,15 @@ static int s5p_hpd_irq_hdmi(int irq) atomic_set(&poll_state, 1); last_hpd_state = HPD_LO; +#ifdef CONFIG_SAMSUNG_WORKAROUND_HPD_GLANCE + if (is_mhl_power_state_on != NULL) + if (!is_mhl_power_state_on()) + mhl_hpd_handler(false); +#endif +#ifdef CONFIG_HDMI_CONTROLLED_BY_EXT_IC + schedule_delayed_work(&ext_ic_control_dwork , + msecs_to_jiffies(1000)); +#endif wake_up_interruptible(&hpd_struct.waitq); } @@ -474,6 +518,20 @@ static irqreturn_t s5p_hpd_irq_handler(int irq, void *dev_id) return ret; } +#ifdef CONFIG_HDMI_CONTROLLED_BY_EXT_IC +static work_func_t ext_ic_control_func(void) +{ + if (!hpd_struct.read_gpio()) { + hpd_struct.ext_ic_control(false); + HPDPRINTK("HDMI_EXT_IC Power Off\n"); + } else { + HPDPRINTK("HDMI_EXT_IC Delay work do nothing\n"); + } + return 0; +} +#endif + + #ifdef CONFIG_SAMSUNG_WORKAROUND_HPD_GLANCE static irqreturn_t s5p_hpd_irq_default_handler(int irq, void *dev_id) { @@ -566,6 +624,9 @@ static int __devinit s5p_hpd_probe(struct platform_device *pdev) if (hpd_struct.read_gpio()) { atomic_set(&hpd_struct.state, HPD_HI); last_hpd_state = HPD_HI; +#ifdef CONFIG_HDMI_CONTROLLED_BY_EXT_IC + hpd_struct.ext_ic_control(true); +#endif } else { atomic_set(&hpd_struct.state, HPD_LO); last_hpd_state = HPD_LO; @@ -575,6 +636,7 @@ static int __devinit s5p_hpd_probe(struct platform_device *pdev) hpd_struct.hpd_switch.name = "hdmi"; switch_dev_register(&hpd_struct.hpd_switch); #endif + switch_set_state(&hpd_struct.hpd_switch, last_hpd_state); irq_set_irq_type(hpd_struct.irq_n, IRQ_TYPE_EDGE_BOTH); ret = request_irq(hpd_struct.irq_n, (irq_handler_t) s5p_hpd_irq_handler, diff --git a/drivers/media/video/samsung/tvout/s5p_tvout_v4l2.c b/drivers/media/video/samsung/tvout/s5p_tvout_v4l2.c index 68508e7..3fa6e55 100644 --- a/drivers/media/video/samsung/tvout/s5p_tvout_v4l2.c +++ b/drivers/media/video/samsung/tvout/s5p_tvout_v4l2.c @@ -369,7 +369,7 @@ static int s5p_tvout_tvif_s_std( int i; v4l2_std_id std_id = *norm; -#ifdef CONFIG_HAS_EARLYSUSPEND +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(CLOCK_GATING_ON_EARLY_SUSPEND) s5p_tvout_mutex_lock(); #endif for (i = 0; i < S5P_TVOUT_TVIF_NO_OF_STANDARD; i++) { @@ -379,7 +379,8 @@ static int s5p_tvout_tvif_s_std( if (i == S5P_TVOUT_TVIF_NO_OF_STANDARD) { tvout_err("There is no TV standard(0x%08Lx)\n", std_id); -#ifdef CONFIG_HAS_EARLYSUSPEND + +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(CLOCK_GATING_ON_EARLY_SUSPEND) s5p_tvout_mutex_unlock(); #endif return -EINVAL; @@ -390,7 +391,7 @@ static int s5p_tvout_tvif_s_std( tvout_dbg("standard id=0x%X, name=\"%s\"\n", (u32) std_id, s5p_tvout_tvif_standard[i].name); -#ifdef CONFIG_HAS_EARLYSUSPEND +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(CLOCK_GATING_ON_EARLY_SUSPEND) s5p_tvout_mutex_unlock(); #endif @@ -437,7 +438,7 @@ static int s5p_tvout_tvif_s_output( return -EINVAL; } -#ifdef CONFIG_HAS_EARLYSUSPEND +#if defined(CONFIG_HAS_EARLYSUSPEND) s5p_tvout_mutex_lock(); #endif on_start_process = true; @@ -582,12 +583,12 @@ static int s5p_tvout_tvif_s_output( s5p_tvif_ctrl_start(tv_std, tv_if); -#ifdef CONFIG_HAS_EARLYSUSPEND +#if defined(CONFIG_HAS_EARLYSUSPEND) s5p_tvout_mutex_unlock(); #endif return 0; error_on_tvif_s_output: -#ifdef CONFIG_HAS_EARLYSUSPEND +#if defined(CONFIG_HAS_EARLYSUSPEND) s5p_tvout_mutex_unlock(); #endif return -1; @@ -749,7 +750,7 @@ long s5p_tvout_tvif_ioctl( void *argp = (void *) arg; int i = 0; -#ifdef CONFIG_HAS_EARLYSUSPEND +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(CLOCK_GATING_ON_EARLY_SUSPEND) s5p_tvout_mutex_lock(); #endif @@ -916,13 +917,13 @@ long s5p_tvout_tvif_ioctl( break; } -#ifdef CONFIG_HAS_EARLYSUSPEND +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(CLOCK_GATING_ON_EARLY_SUSPEND) s5p_tvout_mutex_unlock(); #endif return video_ioctl2(file, cmd, arg); end_tvif_ioctl: -#ifdef CONFIG_HAS_EARLYSUSPEND +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(CLOCK_GATING_ON_EARLY_SUSPEND) s5p_tvout_mutex_unlock(); #endif return ret; @@ -1035,7 +1036,7 @@ static int s5p_tvout_vo_s_fmt_type_private( (u32) vparam.base_y, (u32) vparam.base_c, pix_fmt->field); -#ifdef CONFIG_HAS_EARLYSUSPEND +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(CLOCK_GATING_ON_EARLY_SUSPEND) s5p_tvout_mutex_lock(); #endif /* check progressive or not */ @@ -1133,52 +1134,72 @@ static int s5p_tvout_vo_s_fmt_type_private( pix_fmt->height, color, field); #else if (pix_fmt->priv) { - copy_buff_idx = s5ptv_vp_buff.copy_buff_idxs[s5ptv_vp_buff.curr_copy_idx]; - - if ((void *)s5ptv_vp_buff.vp_buffs[copy_buff_idx].vir_base == NULL) { - s5p_vp_ctrl_set_src_plane((u32) vparam.base_y, (u32) vparam.base_c, - pix_fmt->width, pix_fmt->height, color, field); + copy_buff_idx = + s5ptv_vp_buff. + copy_buff_idxs[s5ptv_vp_buff.curr_copy_idx]; + + if ((void *)s5ptv_vp_buff.vp_buffs[copy_buff_idx].vir_base + == NULL) { + s5p_vp_ctrl_set_src_plane( + (u32) vparam.base_y, (u32) vparam.base_c, + pix_fmt->width, pix_fmt->height, color, field); } else { - if (pix_fmt->pixelformat == V4L2_PIX_FMT_NV12T - || pix_fmt->pixelformat == V4L2_PIX_FMT_NV21T) { - y_size = ALIGN(ALIGN(pix_fmt->width, 128) * ALIGN(pix_fmt->height, 32), SZ_8K); - cbcr_size = ALIGN(ALIGN(pix_fmt->width, 128) * ALIGN(pix_fmt->height >> 1, 32), SZ_8K); + if (pix_fmt->pixelformat == + V4L2_PIX_FMT_NV12T + || pix_fmt->pixelformat == V4L2_PIX_FMT_NV21T) { + y_size = ALIGN(ALIGN(pix_fmt->width, 128) * + ALIGN(pix_fmt->height, 32), SZ_8K); + cbcr_size = ALIGN(ALIGN(pix_fmt->width, 128) * + ALIGN(pix_fmt->height >> 1, 32), SZ_8K); } else { y_size = pix_fmt->width * pix_fmt->height; - cbcr_size = pix_fmt->width * (pix_fmt->height >> 1); + cbcr_size = + pix_fmt->width * (pix_fmt->height >> 1); } - src_vir_y_addr = (unsigned int)phys_to_virt((unsigned long)vparam.base_y); - src_vir_cb_addr = (unsigned int)phys_to_virt((unsigned long)vparam.base_c); + src_vir_y_addr = (unsigned int)phys_to_virt( + (unsigned long)vparam.base_y); + src_vir_cb_addr = (unsigned int)phys_to_virt( + (unsigned long)vparam.base_c); - memcpy((void *)s5ptv_vp_buff.vp_buffs[copy_buff_idx].vir_base, - (void *)src_vir_y_addr, y_size); - memcpy((void *)s5ptv_vp_buff.vp_buffs[copy_buff_idx].vir_base + y_size, - (void *)src_vir_cb_addr, cbcr_size); + memcpy( + (void *) + s5ptv_vp_buff.vp_buffs[copy_buff_idx].vir_base, + (void *)src_vir_y_addr, y_size); + memcpy( + (void *)s5ptv_vp_buff.vp_buffs[copy_buff_idx]. + vir_base + y_size, + (void *)src_vir_cb_addr, cbcr_size); flush_all_cpu_caches(); outer_flush_all(); - s5p_vp_ctrl_set_src_plane((u32) s5ptv_vp_buff.vp_buffs[copy_buff_idx].phy_base, - (u32) s5ptv_vp_buff.vp_buffs[copy_buff_idx].phy_base + y_size, - pix_fmt->width, pix_fmt->height, color, field); + s5p_vp_ctrl_set_src_plane( + (u32) s5ptv_vp_buff. + vp_buffs[copy_buff_idx].phy_base, + (u32) s5ptv_vp_buff. + vp_buffs[copy_buff_idx].phy_base + + y_size, + pix_fmt->width, pix_fmt->height, color, field); s5ptv_vp_buff.curr_copy_idx++; - if (s5ptv_vp_buff.curr_copy_idx >= S5PTV_VP_BUFF_CNT - 1) + if (s5ptv_vp_buff.curr_copy_idx >= + S5PTV_VP_BUFF_CNT - 1) s5ptv_vp_buff.curr_copy_idx = 0; } } else { - s5p_vp_ctrl_set_src_plane((u32) vparam.base_y, (u32) vparam.base_c, - pix_fmt->width, pix_fmt->height, color, field); + s5p_vp_ctrl_set_src_plane( + (u32) vparam.base_y, (u32) vparam.base_c, + pix_fmt->width, pix_fmt->height, color, field); } #endif -#ifdef CONFIG_HAS_EARLYSUSPEND +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(CLOCK_GATING_ON_EARLY_SUSPEND) s5p_tvout_mutex_unlock(); #endif return 0; error_on_s_fmt_type_private: -#ifdef CONFIG_HAS_EARLYSUSPEND +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(CLOCK_GATING_ON_EARLY_SUSPEND) s5p_tvout_mutex_unlock(); #endif return -1; @@ -1201,7 +1222,7 @@ static int s5p_tvout_vo_s_fmt_vid_overlay( rect->left, rect->top, rect->width, rect->height, a->fmt.win.global_alpha); -#ifdef CONFIG_HAS_EARLYSUSPEND +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(CLOCK_GATING_ON_EARLY_SUSPEND) s5p_tvout_mutex_lock(); #endif s5p_tvout_v4l2_private.vo_dst_fmt = a->fmt.win; @@ -1211,7 +1232,7 @@ static int s5p_tvout_vo_s_fmt_vid_overlay( rect->left, rect->top, rect->width, rect->height); -#ifdef CONFIG_HAS_EARLYSUSPEND +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(CLOCK_GATING_ON_EARLY_SUSPEND) s5p_tvout_mutex_unlock(); #endif return 0; @@ -1237,7 +1258,7 @@ static int s5p_tvout_vo_s_crop( struct file *file, void *fh, struct v4l2_crop *a) { tvout_dbg("\n"); -#ifdef CONFIG_HAS_EARLYSUSPEND +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(CLOCK_GATING_ON_EARLY_SUSPEND) s5p_tvout_mutex_lock(); #endif switch (a->type) { @@ -1260,7 +1281,7 @@ static int s5p_tvout_vo_s_crop( tvout_err("Invalid buf type(0x%08x)\n", a->type); break; } -#ifdef CONFIG_HAS_EARLYSUSPEND +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(CLOCK_GATING_ON_EARLY_SUSPEND) s5p_tvout_mutex_unlock(); #endif return 0; @@ -1285,7 +1306,7 @@ static int s5p_tvout_vo_s_fbuf( (a->flags & V4L2_FBUF_FLAG_GLOBAL_ALPHA) ? 1 : 0, a->fmt.priv); -#ifdef CONFIG_HAS_EARLYSUSPEND +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(CLOCK_GATING_ON_EARLY_SUSPEND) s5p_tvout_mutex_lock(); #endif @@ -1294,7 +1315,7 @@ static int s5p_tvout_vo_s_fbuf( s5p_vp_ctrl_set_dest_win_priority(a->fmt.priv); -#ifdef CONFIG_HAS_EARLYSUSPEND +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(CLOCK_GATING_ON_EARLY_SUSPEND) s5p_tvout_mutex_unlock(); #endif return 0; @@ -1305,15 +1326,21 @@ static int s5p_tvout_vo_overlay( { tvout_dbg("%s\n", (i) ? "start" : "stop"); -#ifdef CONFIG_HAS_EARLYSUSPEND +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(CLOCK_GATING_ON_EARLY_SUSPEND) s5p_tvout_mutex_lock(); #endif - if (i) + if (i) { s5p_vp_ctrl_start(); - else + /* restore vsync interrupt setting */ + s5p_mixer_set_vsync_interrupt( + s5p_mixer_ctrl_get_vsync_interrupt()); + } else { + /* disable vsync interrupt when VP is disabled */ + s5p_mixer_ctrl_disable_vsync_interrupt(); s5p_vp_ctrl_stop(); + } -#ifdef CONFIG_HAS_EARLYSUSPEND +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(CLOCK_GATING_ON_EARLY_SUSPEND) s5p_tvout_mutex_unlock(); #endif return 0; diff --git a/drivers/media/video/samsung/tvout/s5p_vp_ctrl.c b/drivers/media/video/samsung/tvout/s5p_vp_ctrl.c index d074da3..148e3e9 100644 --- a/drivers/media/video/samsung/tvout/s5p_vp_ctrl.c +++ b/drivers/media/video/samsung/tvout/s5p_vp_ctrl.c @@ -279,7 +279,7 @@ static int s5p_vp_ctrl_set_reg(void) struct s5p_vp_ctrl_pp_param *pp_param = &s5p_vp_ctrl_private.pp_param; struct s5p_vp_ctrl_op_mode *op_mode = &s5p_vp_ctrl_private.op_mode; -#ifdef CONFIG_HAS_EARLYSUSPEND +#ifdef CLOCK_GATING_ON_EARLY_SUSPEND if (suspend_status) { tvout_dbg("driver is suspend_status\n"); } else @@ -362,7 +362,7 @@ static int s5p_vp_ctrl_set_reg(void) static void s5p_vp_ctrl_internal_stop(void) { -#ifdef CONFIG_HAS_EARLYSUSPEND +#ifdef CLOCK_GATING_ON_EARLY_SUSPEND if (suspend_status) { tvout_dbg("driver is suspend_status\n"); } else @@ -409,7 +409,7 @@ void s5p_vp_ctrl_set_src_plane( src_plane->w = width; src_plane->h = height; -#ifdef CONFIG_HAS_EARLYSUSPEND +#ifdef CLOCK_GATING_ON_EARLY_SUSPEND if (suspend_status) { tvout_dbg("driver is suspend_status\n"); return; @@ -434,7 +434,7 @@ void s5p_vp_ctrl_set_src_win(u32 left, u32 top, u32 width, u32 height) src_win->w = width; src_win->h = height; -#ifdef CONFIG_HAS_EARLYSUSPEND +#ifdef CLOCK_GATING_ON_EARLY_SUSPEND if (suspend_status) { tvout_dbg("driver is suspend_status\n"); return; @@ -466,7 +466,7 @@ void s5p_vp_ctrl_set_dest_win(u32 left, u32 top, u32 width, u32 height) dst_win->y = top; dst_win->w = width; dst_win->h = height; -#ifdef CONFIG_HAS_EARLYSUSPEND +#ifdef CLOCK_GATING_ON_EARLY_SUSPEND if (suspend_status) { tvout_dbg("driver is suspend_status\n"); return; @@ -493,7 +493,7 @@ void s5p_vp_ctrl_set_dest_win(u32 left, u32 top, u32 width, u32 height) void s5p_vp_ctrl_set_dest_win_alpha_val(u32 alpha) { s5p_vp_ctrl_private.mixer_param.alpha = alpha; -#ifdef CONFIG_HAS_EARLYSUSPEND +#ifdef CLOCK_GATING_ON_EARLY_SUSPEND if (suspend_status) { tvout_dbg("driver is suspend_status\n"); return; @@ -505,7 +505,7 @@ void s5p_vp_ctrl_set_dest_win_alpha_val(u32 alpha) void s5p_vp_ctrl_set_dest_win_blend(bool enable) { s5p_vp_ctrl_private.mixer_param.blend = enable; -#ifdef CONFIG_HAS_EARLYSUSPEND +#ifdef CLOCK_GATING_ON_EARLY_SUSPEND if (suspend_status) { tvout_dbg("driver is suspend_status\n"); return; @@ -518,7 +518,7 @@ void s5p_vp_ctrl_set_dest_win_blend(bool enable) void s5p_vp_ctrl_set_dest_win_priority(u32 prio) { s5p_vp_ctrl_private.mixer_param.prio = prio; -#ifdef CONFIG_HAS_EARLYSUSPEND +#ifdef CLOCK_GATING_ON_EARLY_SUSPEND if (suspend_status) { tvout_dbg("driver is suspend_status\n"); return; @@ -531,7 +531,7 @@ void s5p_vp_ctrl_stop(void) { if (s5p_vp_ctrl_private.running) { s5p_vp_ctrl_internal_stop(); -#ifdef CONFIG_HAS_EARLYSUSPEND +#ifdef CLOCK_GATING_ON_EARLY_SUSPEND if (suspend_status) { tvout_dbg("driver is suspend_status\n"); } else @@ -647,7 +647,7 @@ int s5p_vp_ctrl_start(void) if (s5p_vp_ctrl_private.running) s5p_vp_ctrl_internal_stop(); else { -#ifdef CONFIG_HAS_EARLYSUSPEND +#ifdef CLOCK_GATING_ON_EARLY_SUSPEND if (suspend_status) { tvout_dbg("driver is suspend_status\n"); } else |