diff --git a/arch/arm/mach-msm/include/mach/audio_dma_msm8k.h b/arch/arm/mach-msm/include/mach/audio_dma_msm8k.h index 5c9bfb5b84c..1970d0b8d8f 100644 --- a/arch/arm/mach-msm/include/mach/audio_dma_msm8k.h +++ b/arch/arm/mach-msm/include/mach/audio_dma_msm8k.h @@ -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 diff --git a/arch/arm/mach-msm/include/mach/msm_hdmi_audio.h b/arch/arm/mach-msm/include/mach/msm_hdmi_audio.h index 97dad677d65..3965a75c036 100644 --- a/arch/arm/mach-msm/include/mach/msm_hdmi_audio.h +++ b/arch/arm/mach-msm/include/mach/msm_hdmi_audio.h @@ -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*/ diff --git a/arch/arm/mach-msm/qdsp6v2/lpa_if_hdmi.c b/arch/arm/mach-msm/qdsp6v2/lpa_if_hdmi.c index 11d5d055869..16258ebb3a6 100644 --- a/arch/arm/mach-msm/qdsp6v2/lpa_if_hdmi.c +++ b/arch/arm/mach-msm/qdsp6v2/lpa_if_hdmi.c @@ -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; } diff --git a/arch/arm/mach-msm/qdsp6v2/snddev_hdmi.c b/arch/arm/mach-msm/qdsp6v2/snddev_hdmi.c index 4eeb654d4cb..9b8346d3508 100644 --- a/arch/arm/mach-msm/qdsp6v2/snddev_hdmi.c +++ b/arch/arm/mach-msm/qdsp6v2/snddev_hdmi.c @@ -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; diff --git a/drivers/video/msm/hdmi_msm.c b/drivers/video/msm/hdmi_msm.c index 9805b6cae8a..4b34969357d 100644 --- a/drivers/video/msm/hdmi_msm.c +++ b/drivers/video/msm/hdmi_msm.c @@ -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)); diff --git a/include/sound/dai.h b/include/sound/dai.h index 27ff9806c09..4d3fb960a87 100644 --- a/include/sound/dai.h +++ b/include/sound/dai.h @@ -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 diff --git a/sound/soc/msm/lpass-dma.c b/sound/soc/msm/lpass-dma.c index 84b6f1fc54d..66c183615ce 100644 --- a/sound/soc/msm/lpass-dma.c +++ b/sound/soc/msm/lpass-dma.c @@ -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); }