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 <aparmar@codeaurora.org>
This commit is contained in:
parent
7c8c5976a7
commit
dd648e410f
3 changed files with 49 additions and 0 deletions
|
@ -30,6 +30,7 @@ struct msm_hdmi_audio_codec_ops {
|
||||||
bool down_mix);
|
bool down_mix);
|
||||||
int (*get_audio_edid_blk) (struct platform_device *pdev,
|
int (*get_audio_edid_blk) (struct platform_device *pdev,
|
||||||
struct msm_hdmi_audio_edid_blk *blk);
|
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,
|
int msm_hdmi_register_audio_codec(struct platform_device *pdev,
|
||||||
|
|
|
@ -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)
|
static void hdmi_tx_wait_for_audio_engine(struct hdmi_tx_ctrl *hdmi_ctrl)
|
||||||
{
|
{
|
||||||
u32 status = 0;
|
u32 status = 0;
|
||||||
|
u32 wait_for_vote = 50;
|
||||||
struct dss_io_data *io = NULL;
|
struct dss_io_data *io = NULL;
|
||||||
|
|
||||||
if (!hdmi_ctrl) {
|
if (!hdmi_ctrl) {
|
||||||
|
@ -386,6 +387,18 @@ static void hdmi_tx_wait_for_audio_engine(struct hdmi_tx_ctrl *hdmi_ctrl)
|
||||||
return;
|
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,
|
if (readl_poll_timeout(io->base + HDMI_AUDIO_PKT_CTRL, status,
|
||||||
(status & BIT(0)) == 0, AUDIO_POLL_SLEEP_US,
|
(status & BIT(0)) == 0, AUDIO_POLL_SLEEP_US,
|
||||||
AUDIO_POLL_TIMEOUT_US))
|
AUDIO_POLL_TIMEOUT_US))
|
||||||
|
@ -2240,6 +2253,29 @@ int msm_hdmi_register_mhl(struct platform_device *pdev,
|
||||||
return 0;
|
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,
|
int msm_hdmi_register_audio_codec(struct platform_device *pdev,
|
||||||
struct msm_hdmi_audio_codec_ops *ops)
|
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->audio_info_setup = hdmi_tx_audio_info_setup;
|
||||||
ops->get_audio_edid_blk = hdmi_tx_get_audio_edid_blk;
|
ops->get_audio_edid_blk = hdmi_tx_get_audio_edid_blk;
|
||||||
|
ops->hdmi_cable_status = hdmi_tx_get_cable_status;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
} /* hdmi_tx_audio_register */
|
} /* hdmi_tx_audio_register */
|
||||||
|
@ -2565,6 +2602,7 @@ static void hdmi_tx_hpd_off(struct hdmi_tx_ctrl *hdmi_ctrl)
|
||||||
{
|
{
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
struct dss_io_data *io = NULL;
|
struct dss_io_data *io = NULL;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
if (!hdmi_ctrl) {
|
if (!hdmi_ctrl) {
|
||||||
DEV_ERR("%s: invalid input\n", __func__);
|
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",
|
DEV_INFO("%s: Failed to disable hpd power. Error=%d\n",
|
||||||
__func__, rc);
|
__func__, rc);
|
||||||
|
|
||||||
|
spin_lock_irqsave(&hdmi_ctrl->hpd_state_lock, flags);
|
||||||
hdmi_ctrl->hpd_state = false;
|
hdmi_ctrl->hpd_state = false;
|
||||||
|
spin_unlock_irqrestore(&hdmi_ctrl->hpd_state_lock, flags);
|
||||||
|
|
||||||
hdmi_ctrl->hpd_initialized = false;
|
hdmi_ctrl->hpd_initialized = false;
|
||||||
} /* hdmi_tx_hpd_off */
|
} /* 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 dss_io_data *io = NULL;
|
||||||
struct hdmi_tx_ctrl *hdmi_ctrl = (struct hdmi_tx_ctrl *)data;
|
struct hdmi_tx_ctrl *hdmi_ctrl = (struct hdmi_tx_ctrl *)data;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
if (!hdmi_ctrl) {
|
if (!hdmi_ctrl) {
|
||||||
DEV_WARN("%s: invalid input data, ISR ignored\n", __func__);
|
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)) {
|
if (DSS_REG_R(io, HDMI_HPD_INT_STATUS) & BIT(0)) {
|
||||||
|
spin_lock_irqsave(&hdmi_ctrl->hpd_state_lock, flags);
|
||||||
hdmi_ctrl->hpd_state =
|
hdmi_ctrl->hpd_state =
|
||||||
(DSS_REG_R(io, HDMI_HPD_INT_STATUS) & BIT(1)) >> 1;
|
(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
|
* 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);
|
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.sample_rate = AUDIO_SAMPLE_RATE_48KHZ;
|
||||||
hdmi_ctrl->audio_data.channel_num = MSM_HDMI_AUDIO_CHANNEL_2;
|
hdmi_ctrl->audio_data.channel_num = MSM_HDMI_AUDIO_CHANNEL_2;
|
||||||
|
|
||||||
|
|
|
@ -58,6 +58,7 @@ struct hdmi_tx_ctrl {
|
||||||
struct switch_dev sdev;
|
struct switch_dev sdev;
|
||||||
struct switch_dev audio_sdev;
|
struct switch_dev audio_sdev;
|
||||||
struct workqueue_struct *workq;
|
struct workqueue_struct *workq;
|
||||||
|
spinlock_t hpd_state_lock;
|
||||||
|
|
||||||
uint32_t video_resolution;
|
uint32_t video_resolution;
|
||||||
|
|
||||||
|
@ -68,6 +69,7 @@ struct hdmi_tx_ctrl {
|
||||||
u32 hpd_off_pending;
|
u32 hpd_off_pending;
|
||||||
u32 hpd_feature_on;
|
u32 hpd_feature_on;
|
||||||
u32 hpd_initialized;
|
u32 hpd_initialized;
|
||||||
|
u32 vote_hdmi_core_on;
|
||||||
u8 timing_gen_on;
|
u8 timing_gen_on;
|
||||||
u32 mhl_max_pclk;
|
u32 mhl_max_pclk;
|
||||||
u8 mhl_hpd_on;
|
u8 mhl_hpd_on;
|
||||||
|
|
Loading…
Add table
Reference in a new issue