From dd648e410f30f4c82dc13e26838a834ec39f3331 Mon Sep 17 00:00:00 2001 From: Ajay Singh Parmar Date: Wed, 9 Oct 2013 11:49:53 -0700 Subject: [PATCH] msm: mdss: hdmi: HDMI cable connection status and vote Add HDMI cable connection status functionality to be used by audio driver before starting the audio session and vote for hdmi tx core to remain power on until the audio has completed its processing. Change-Id: I35d1bafff472da19e04aa44f4ac91b1c3c0349e1 Signed-off-by: Ajay Singh Parmar --- .../include/mach/msm_hdmi_audio_codec.h | 1 + drivers/video/fbdev/msm/mdss_hdmi_tx.c | 46 +++++++++++++++++++ drivers/video/fbdev/msm/mdss_hdmi_tx.h | 2 + 3 files changed, 49 insertions(+) diff --git a/arch/arm/mach-msm/include/mach/msm_hdmi_audio_codec.h b/arch/arm/mach-msm/include/mach/msm_hdmi_audio_codec.h index ff3da1151047..397304408723 100644 --- a/arch/arm/mach-msm/include/mach/msm_hdmi_audio_codec.h +++ b/arch/arm/mach-msm/include/mach/msm_hdmi_audio_codec.h @@ -30,6 +30,7 @@ struct msm_hdmi_audio_codec_ops { bool down_mix); int (*get_audio_edid_blk) (struct platform_device *pdev, struct msm_hdmi_audio_edid_blk *blk); + int (*hdmi_cable_status) (struct platform_device *pdev, u32 vote); }; int msm_hdmi_register_audio_codec(struct platform_device *pdev, diff --git a/drivers/video/fbdev/msm/mdss_hdmi_tx.c b/drivers/video/fbdev/msm/mdss_hdmi_tx.c index b4a2c2f55081..d4b75d0d0f2d 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_tx.c +++ b/drivers/video/fbdev/msm/mdss_hdmi_tx.c @@ -373,6 +373,7 @@ static inline u32 hdmi_tx_is_dvi_mode(struct hdmi_tx_ctrl *hdmi_ctrl) static void hdmi_tx_wait_for_audio_engine(struct hdmi_tx_ctrl *hdmi_ctrl) { u32 status = 0; + u32 wait_for_vote = 50; struct dss_io_data *io = NULL; if (!hdmi_ctrl) { @@ -386,6 +387,18 @@ static void hdmi_tx_wait_for_audio_engine(struct hdmi_tx_ctrl *hdmi_ctrl) return; } + /* + * wait for 5 sec max for audio engine to acknowledge if hdmi tx core + * can be safely turned off. Sleep for a reasonable time to make sure + * vote_hdmi_core_on variable is updated properly by audio. + */ + while (hdmi_ctrl->vote_hdmi_core_on && --wait_for_vote) + msleep(100); + + + if (!wait_for_vote) + DEV_ERR("%s: HDMI core still voted for power on\n", __func__); + if (readl_poll_timeout(io->base + HDMI_AUDIO_PKT_CTRL, status, (status & BIT(0)) == 0, AUDIO_POLL_SLEEP_US, AUDIO_POLL_TIMEOUT_US)) @@ -2240,6 +2253,29 @@ int msm_hdmi_register_mhl(struct platform_device *pdev, return 0; } +static int hdmi_tx_get_cable_status(struct platform_device *pdev, u32 vote) +{ + struct hdmi_tx_ctrl *hdmi_ctrl = platform_get_drvdata(pdev); + unsigned long flags; + u32 hpd; + + if (!hdmi_ctrl) { + DEV_ERR("%s: invalid input\n", __func__); + return -ENODEV; + } + + spin_lock_irqsave(&hdmi_ctrl->hpd_state_lock, flags); + hpd = hdmi_ctrl->hpd_state; + spin_unlock_irqrestore(&hdmi_ctrl->hpd_state_lock, flags); + + hdmi_ctrl->vote_hdmi_core_on = false; + + if (vote && hpd) + hdmi_ctrl->vote_hdmi_core_on = true; + + return hpd; +} + int msm_hdmi_register_audio_codec(struct platform_device *pdev, struct msm_hdmi_audio_codec_ops *ops) { @@ -2252,6 +2288,7 @@ int msm_hdmi_register_audio_codec(struct platform_device *pdev, ops->audio_info_setup = hdmi_tx_audio_info_setup; ops->get_audio_edid_blk = hdmi_tx_get_audio_edid_blk; + ops->hdmi_cable_status = hdmi_tx_get_cable_status; return 0; } /* hdmi_tx_audio_register */ @@ -2565,6 +2602,7 @@ static void hdmi_tx_hpd_off(struct hdmi_tx_ctrl *hdmi_ctrl) { int rc = 0; struct dss_io_data *io = NULL; + unsigned long flags; if (!hdmi_ctrl) { DEV_ERR("%s: invalid input\n", __func__); @@ -2604,7 +2642,10 @@ static void hdmi_tx_hpd_off(struct hdmi_tx_ctrl *hdmi_ctrl) DEV_INFO("%s: Failed to disable hpd power. Error=%d\n", __func__, rc); + spin_lock_irqsave(&hdmi_ctrl->hpd_state_lock, flags); hdmi_ctrl->hpd_state = false; + spin_unlock_irqrestore(&hdmi_ctrl->hpd_state_lock, flags); + hdmi_ctrl->hpd_initialized = false; } /* hdmi_tx_hpd_off */ @@ -2730,6 +2771,7 @@ static irqreturn_t hdmi_tx_isr(int irq, void *data) { struct dss_io_data *io = NULL; struct hdmi_tx_ctrl *hdmi_ctrl = (struct hdmi_tx_ctrl *)data; + unsigned long flags; if (!hdmi_ctrl) { DEV_WARN("%s: invalid input data, ISR ignored\n", __func__); @@ -2744,8 +2786,10 @@ static irqreturn_t hdmi_tx_isr(int irq, void *data) } if (DSS_REG_R(io, HDMI_HPD_INT_STATUS) & BIT(0)) { + spin_lock_irqsave(&hdmi_ctrl->hpd_state_lock, flags); hdmi_ctrl->hpd_state = (DSS_REG_R(io, HDMI_HPD_INT_STATUS) & BIT(1)) >> 1; + spin_unlock_irqrestore(&hdmi_ctrl->hpd_state_lock, flags); /* * Ack the current hpd interrupt and stop listening to @@ -2844,6 +2888,8 @@ static int hdmi_tx_dev_init(struct hdmi_tx_ctrl *hdmi_ctrl) INIT_WORK(&hdmi_ctrl->power_off_work, hdmi_tx_power_off_work); + spin_lock_init(&hdmi_ctrl->hpd_state_lock); + hdmi_ctrl->audio_data.sample_rate = AUDIO_SAMPLE_RATE_48KHZ; hdmi_ctrl->audio_data.channel_num = MSM_HDMI_AUDIO_CHANNEL_2; diff --git a/drivers/video/fbdev/msm/mdss_hdmi_tx.h b/drivers/video/fbdev/msm/mdss_hdmi_tx.h index c4d03269edf2..66071e94fce1 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_tx.h +++ b/drivers/video/fbdev/msm/mdss_hdmi_tx.h @@ -58,6 +58,7 @@ struct hdmi_tx_ctrl { struct switch_dev sdev; struct switch_dev audio_sdev; struct workqueue_struct *workq; + spinlock_t hpd_state_lock; uint32_t video_resolution; @@ -68,6 +69,7 @@ struct hdmi_tx_ctrl { u32 hpd_off_pending; u32 hpd_feature_on; u32 hpd_initialized; + u32 vote_hdmi_core_on; u8 timing_gen_on; u32 mhl_max_pclk; u8 mhl_hpd_on;