summaryrefslogtreecommitdiff
path: root/sound/pci/hda/hda_intel.c
diff options
context:
space:
mode:
authorDavid Henningsson <david.henningsson@canonical.com>2014-02-28 06:56:58 (GMT)
committerTakashi Iwai <tiwai@suse.de>2014-02-28 13:03:30 (GMT)
commitca460f86521ed515d17dd1314f7b95183866f681 (patch)
treeb2a48c6e5b97602edbb59f9b717801c9cd89a26a /sound/pci/hda/hda_intel.c
parentd604b3990884062873e3bef09ef5e89857c409c3 (diff)
downloadlinux-ca460f86521ed515d17dd1314f7b95183866f681.tar.xz
ALSA: hda - Fix CORB reset to follow specification
According to the HDA spec, we must write 1 to bit 15 on a CORBRP reset, read back 1, then write 0, then read back 0. This must be done while the DMA is not running. We accidentaly ended up writing back the 0 by using a writel instead of a writew to CORBWP. This caused occasional controller failure on Bay Trail hardware. [replaced error messages with dev_err() by tiwai] Signed-off-by: David Henningsson <david.henningsson@canonical.com> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/hda/hda_intel.c')
-rw-r--r--sound/pci/hda/hda_intel.c24
1 files changed, 23 insertions, 1 deletions
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index 6eb0941..e8a9e87 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -769,6 +769,8 @@ static int azx_alloc_cmd_io(struct azx *chip)
static void azx_init_cmd_io(struct azx *chip)
{
+ int timeout;
+
spin_lock_irq(&chip->reg_lock);
/* CORB set up */
chip->corb.addr = chip->rb.addr;
@@ -780,8 +782,28 @@ static void azx_init_cmd_io(struct azx *chip)
azx_writeb(chip, CORBSIZE, 0x02);
/* set the corb write pointer to 0 */
azx_writew(chip, CORBWP, 0);
+
/* reset the corb hw read pointer */
azx_writew(chip, CORBRP, ICH6_CORBRP_RST);
+ for (timeout = 1000; timeout > 0; timeout--) {
+ if ((azx_readw(chip, CORBRP) & ICH6_CORBRP_RST) == ICH6_CORBRP_RST)
+ break;
+ udelay(1);
+ }
+ if (timeout <= 0)
+ dev_err(chip->card->dev, "CORB reset timeout#1, CORBRP = %d\n",
+ azx_readw(chip, CORBRP));
+
+ azx_writew(chip, CORBRP, 0);
+ for (timeout = 1000; timeout > 0; timeout--) {
+ if (azx_readw(chip, CORBRP) == 0)
+ break;
+ udelay(1);
+ }
+ if (timeout <= 0)
+ dev_err(chip->card->dev, "CORB reset timeout#2, CORBRP = %d\n",
+ azx_readw(chip, CORBRP));
+
/* enable corb dma */
azx_writeb(chip, CORBCTL, ICH6_CORBCTL_RUN);
@@ -856,7 +878,7 @@ static int azx_corb_send_cmd(struct hda_bus *bus, u32 val)
chip->rirb.cmds[addr]++;
chip->corb.buf[wp] = cpu_to_le32(val);
- azx_writel(chip, CORBWP, wp);
+ azx_writew(chip, CORBWP, wp);
spin_unlock_irq(&chip->reg_lock);