msm: 8660: audio: HDMI: Fix the HDMI DMA stop issue
LPA_IF dma channel is disabled without checking the per count value. Because of this dma channel is not functional after few iterations of continuous playback. Fix this issue by checking the dma per count value to stop before disabling the LPA_IF dma channel. Change-Id: Ie9e9a9337ca2c4b76cebd99cd3eb98137be85b89 Signed-off-by: Deepa Madiregama <dmadireg@codeaurora.org>
This commit is contained in:
committed by
Linux Build Service Account
parent
fc464f0f66
commit
6a3a01ae8e
@@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
|
||||
/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
@@ -202,6 +202,11 @@
|
||||
#define LPAIF_DMA_SET_BUFF_CNT(x) DMA_CTRL_ADDR(x, 0x20)
|
||||
#define LPAIF_DMA_SET_PER_CNT(x) DMA_CTRL_ADDR(x, 0x24)
|
||||
|
||||
#define LPAIF_DMA_PER_CNT_PER_CNT_MASK 0x000FFFFF
|
||||
#define LPAIF_DMA_PER_CNT_PER_CNT_SHIFT 0
|
||||
#define LPAIF_DMA_PER_CNT_FIFO_WORDCNT_MASK 0x00F00000
|
||||
#define LPAIF_DMA_PER_CNT_FIFO_WORDCNT_SHIFT 20
|
||||
|
||||
/* channel assignments */
|
||||
|
||||
#define DMA_CH_0 0
|
||||
|
||||
@@ -14,5 +14,6 @@
|
||||
#define __MSM_HDMI_AUDIO_H
|
||||
|
||||
int hdmi_audio_enable(bool on , u32 fifo_water_mark);
|
||||
int hdmi_audio_packet_enable(bool on);
|
||||
|
||||
#endif /* __MSM_HDMI_AUDIO_H*/
|
||||
|
||||
@@ -74,8 +74,6 @@ static irqreturn_t lpa_if_irq(int intrsrc, void *data)
|
||||
pending = (intrsrc
|
||||
& (UNDER_CH(dma_ch) | PER_CH(dma_ch) | ERR_CH(dma_ch)));
|
||||
|
||||
pr_debug("pending = 0x%08x\n", pending);
|
||||
|
||||
if (pending & UNDER_CH(dma_ch))
|
||||
pr_err("under run\n");
|
||||
if (pending & ERR_CH(dma_ch))
|
||||
@@ -104,10 +102,9 @@ int lpa_if_start(struct lpa_if *lpa_if)
|
||||
|
||||
dai_start_hdmi(lpa_if->dma_ch);
|
||||
|
||||
mb();
|
||||
|
||||
hdmi_audio_enable(1, HDMI_AUDIO_FIFO_WATER_MARK);
|
||||
mb();
|
||||
|
||||
hdmi_audio_packet_enable(1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -121,7 +118,7 @@ int lpa_if_config(struct lpa_if *lpa_if)
|
||||
dma_params.period_size = lpa_if->dma_period_sz;
|
||||
dma_params.channels = 2;
|
||||
|
||||
lpa_if->dma_ch = 0;
|
||||
lpa_if->dma_ch = 4;
|
||||
dai_set_params(lpa_if->dma_ch, &dma_params);
|
||||
|
||||
register_dma_irq_handler(lpa_if->dma_ch, lpa_if_irq, (void *)lpa_if);
|
||||
@@ -232,6 +229,7 @@ static int lpa_if_open(struct inode *inode, struct file *file)
|
||||
lpa_if_ptr->dma_buf = 0;
|
||||
|
||||
core_req_bus_bandwith(AUDIO_IF_BUS_ID, 100000, 0);
|
||||
mb();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -244,9 +242,6 @@ static ssize_t lpa_if_write(struct file *file, const char __user *buf,
|
||||
const char __user *start = buf;
|
||||
int xfer, rc;
|
||||
|
||||
pr_debug("count %u cpu_buf %d dma_buf %d\n",
|
||||
(unsigned int)count, lpa_if->cpu_buf, lpa_if->dma_buf);
|
||||
|
||||
mutex_lock(&lpa_if->lock);
|
||||
|
||||
if (dma_buf_index < 2) {
|
||||
@@ -259,6 +254,7 @@ static ssize_t lpa_if_write(struct file *file, const char __user *buf,
|
||||
goto end;
|
||||
|
||||
}
|
||||
mb();
|
||||
pr_debug("prefill: count %u audio_buf[%u].size %u\n",
|
||||
count, dma_buf_index, ab->size);
|
||||
|
||||
@@ -315,15 +311,20 @@ end:
|
||||
static int lpa_if_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct lpa_if *lpa_if = file->private_data;
|
||||
hdmi_audio_enable(0, HDMI_AUDIO_FIFO_WATER_MARK);
|
||||
|
||||
smp_mb();
|
||||
hdmi_audio_packet_enable(0);
|
||||
|
||||
wait_for_dma_cnt_stop(lpa_if->dma_ch);
|
||||
|
||||
hdmi_audio_enable(0, HDMI_AUDIO_FIFO_WATER_MARK);
|
||||
|
||||
if (lpa_if->config) {
|
||||
unregister_dma_irq_handler(lpa_if->dma_ch);
|
||||
dai_stop_hdmi(lpa_if->dma_ch);
|
||||
lpa_if->config = 0;
|
||||
}
|
||||
core_req_bus_bandwith(AUDIO_IF_BUS_ID, 0, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -102,7 +102,7 @@ static int snddev_hdmi_close(struct msm_snddev_info *dev_info)
|
||||
snddev_hdmi_active = 0;
|
||||
|
||||
if (snddev_hdmi_data->on_apps) {
|
||||
pr_debug("%s open done\n", dev_info->name);
|
||||
pr_debug("%s Closed\n", dev_info->name);
|
||||
|
||||
mutex_unlock(&snddev_hdmi_lock);
|
||||
return 0;
|
||||
|
||||
@@ -3088,10 +3088,36 @@ int hdmi_audio_enable(bool on , u32 fifo_water_mark)
|
||||
|
||||
HDMI_OUTP(HDMI_AUDIO_CFG, hdmi_audio_config);
|
||||
|
||||
mb();
|
||||
pr_info("%s :HDMI_AUDIO_CFG 0x%08x\n", __func__,
|
||||
HDMI_INP(HDMI_AUDIO_CFG));
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(hdmi_audio_enable);
|
||||
|
||||
#define HDMI_AUDIO_PKT_CTRL 0x0020
|
||||
#define HDMI_AUDIO_SAMPLE_SEND_ENABLE 1
|
||||
|
||||
int hdmi_audio_packet_enable(bool on)
|
||||
{
|
||||
u32 hdmi_audio_pkt_ctrl;
|
||||
hdmi_audio_pkt_ctrl = HDMI_INP(HDMI_AUDIO_PKT_CTRL);
|
||||
|
||||
if (on)
|
||||
hdmi_audio_pkt_ctrl |= HDMI_AUDIO_SAMPLE_SEND_ENABLE;
|
||||
else
|
||||
hdmi_audio_pkt_ctrl &= ~(HDMI_AUDIO_SAMPLE_SEND_ENABLE);
|
||||
|
||||
HDMI_OUTP(HDMI_AUDIO_PKT_CTRL, hdmi_audio_pkt_ctrl);
|
||||
|
||||
mb();
|
||||
pr_info("%s : HDMI_AUDIO_PKT_CTRL 0x%08x\n", __func__,
|
||||
HDMI_INP(HDMI_AUDIO_PKT_CTRL));
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(hdmi_audio_packet_enable);
|
||||
|
||||
static void hdmi_msm_audio_info_setup(boolean enabled, int num_of_channels,
|
||||
int level_shift, boolean down_mix)
|
||||
{
|
||||
@@ -3294,7 +3320,8 @@ static void hdmi_msm_audio_setup(void)
|
||||
external_common_state->video_resolution,
|
||||
MSM_HDMI_SAMPLE_RATE_48KHZ, channels);
|
||||
hdmi_msm_audio_info_setup(TRUE, channels, 0, FALSE);
|
||||
hdmi_msm_audio_ctrl_setup(TRUE, 1);
|
||||
|
||||
hdmi_msm_audio_ctrl_setup(FALSE, 1);
|
||||
|
||||
/* Turn on Audio FIFO and SAM DROP ISR */
|
||||
HDMI_OUTP(0x02CC, HDMI_INP(0x02CC) | BIT(1) | BIT(3));
|
||||
|
||||
@@ -43,6 +43,7 @@ void register_dma_irq_handler(int dma_ch,
|
||||
void unregister_dma_irq_handler(int dma_ch);
|
||||
void dai_set_master_mode(uint32_t dma_ch, int mode);
|
||||
int dai_start_hdmi(uint32_t dma_ch);
|
||||
int wait_for_dma_cnt_stop(uint32_t dma_ch);
|
||||
void dai_stop_hdmi(uint32_t dma_ch);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -93,6 +93,7 @@ static irqreturn_t dai_irq_handler(int irq, void *data)
|
||||
spin_lock_irqsave(&dai_lock, flag);
|
||||
intrsrc = readl(dai_info.base + LPAIF_IRQ_STAT(0));
|
||||
writel(intrsrc, dai_info.base + LPAIF_IRQ_CLEAR(0));
|
||||
mb();
|
||||
while (intrsrc) {
|
||||
dma_ch = dai_find_dma_channel(intrsrc);
|
||||
|
||||
@@ -149,6 +150,7 @@ static void dai_config_dma(uint32_t dma_ch)
|
||||
dai_info.base + LPAIF_DMA_BUFF_LEN(dma_ch));
|
||||
writel(((dai[dma_ch]->period_len >> 2) - 1),
|
||||
dai_info.base + LPAIF_DMA_PER_LEN(dma_ch));
|
||||
mb();
|
||||
}
|
||||
|
||||
static void dai_enable_codec(uint32_t dma_ch, int codec)
|
||||
@@ -237,6 +239,7 @@ int dai_set_params(uint32_t dma_ch, struct dai_dma_params *params)
|
||||
dai[dma_ch]->channels = params->channels;
|
||||
dai[dma_ch]->buffer_len = params->buffer_size;
|
||||
dai[dma_ch]->period_len = params->period_size;
|
||||
mb();
|
||||
dai_config_dma(dma_ch);
|
||||
return dma_ch;
|
||||
}
|
||||
@@ -278,6 +281,7 @@ int dai_start_hdmi(uint32_t dma_ch)
|
||||
val = readl(dai_info.base + LPAIF_IRQ_EN(0));
|
||||
val = val | (7 << (dma_ch * 3));
|
||||
writel(val, dai_info.base + LPAIF_IRQ_EN(0));
|
||||
mb();
|
||||
|
||||
|
||||
val = (HDMI_BURST_INCR4 | HDMI_WPSCNT | HDMI_AUDIO_INTF |
|
||||
@@ -287,10 +291,58 @@ int dai_start_hdmi(uint32_t dma_ch)
|
||||
}
|
||||
spin_unlock_irqrestore(&dai_lock, flag);
|
||||
|
||||
mb();
|
||||
dai_print_state(dma_ch);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wait_for_dma_cnt_stop(uint32_t dma_ch)
|
||||
{
|
||||
uint32_t dma_per_cnt_reg_val, dma_per_cnt, prev_dma_per_cnt;
|
||||
uint32_t i;
|
||||
|
||||
pr_info("%s dma_ch %u\n", __func__, dma_ch);
|
||||
|
||||
dma_per_cnt_reg_val = readl_relaxed(dai_info.base +
|
||||
LPAIF_DMA_PER_CNT(dma_ch));
|
||||
|
||||
dma_per_cnt =
|
||||
((LPAIF_DMA_PER_CNT_PER_CNT_MASK & dma_per_cnt_reg_val) >>
|
||||
LPAIF_DMA_PER_CNT_PER_CNT_SHIFT) -
|
||||
((LPAIF_DMA_PER_CNT_FIFO_WORDCNT_MASK & dma_per_cnt_reg_val) >>
|
||||
LPAIF_DMA_PER_CNT_FIFO_WORDCNT_SHIFT);
|
||||
|
||||
prev_dma_per_cnt = dma_per_cnt;
|
||||
|
||||
i = 1;
|
||||
pr_info("%s: i = %u dma_per_cnt_reg_val 0x%08x , dma_per_cnt %u\n",
|
||||
__func__, i, dma_per_cnt_reg_val, dma_per_cnt);
|
||||
|
||||
while (i <= 50) {
|
||||
msleep(50);
|
||||
|
||||
dma_per_cnt_reg_val = readl_relaxed(dai_info.base +
|
||||
LPAIF_DMA_PER_CNT(dma_ch));
|
||||
|
||||
dma_per_cnt =
|
||||
((LPAIF_DMA_PER_CNT_PER_CNT_MASK & dma_per_cnt_reg_val) >>
|
||||
LPAIF_DMA_PER_CNT_PER_CNT_SHIFT) -
|
||||
((LPAIF_DMA_PER_CNT_FIFO_WORDCNT_MASK & dma_per_cnt_reg_val) >>
|
||||
LPAIF_DMA_PER_CNT_FIFO_WORDCNT_SHIFT);
|
||||
|
||||
i++;
|
||||
|
||||
pr_info("%s: i = %u dma_per_cnt_reg_val 0x%08x , dma_per_cnt %u\n",
|
||||
__func__, i, dma_per_cnt_reg_val, dma_per_cnt);
|
||||
|
||||
if (prev_dma_per_cnt == dma_per_cnt)
|
||||
break;
|
||||
|
||||
prev_dma_per_cnt = dma_per_cnt;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dai_stop_hdmi(uint32_t dma_ch)
|
||||
{
|
||||
unsigned long flag = 0x0;
|
||||
@@ -307,14 +359,18 @@ void dai_stop_hdmi(uint32_t dma_ch)
|
||||
intrVal = 0x0;
|
||||
writel(intrVal, dai_info.base + LPAIF_DMA_CTL(dma_ch));
|
||||
|
||||
mb();
|
||||
|
||||
intrVal = readl(dai_info.base + LPAIF_IRQ_EN(0));
|
||||
|
||||
int_mask = ((int_mask) << (dma_ch * 3));
|
||||
int_mask = ~int_mask;
|
||||
|
||||
intrVal = intrVal && int_mask;
|
||||
intrVal = intrVal & int_mask;
|
||||
writel(intrVal, dai_info.base + LPAIF_IRQ_EN(0));
|
||||
|
||||
mb();
|
||||
|
||||
spin_unlock_irqrestore(&dai_lock, flag);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user