Commit ca460f86521ed515d17dd1314f7b95183866f681

Authored by David Henningsson
Committed by Takashi Iwai
1 parent d604b39908

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>

Showing 1 changed file with 23 additions and 1 deletions Side-by-side Diff

sound/pci/hda/hda_intel.c
... ... @@ -769,6 +769,8 @@
769 769  
770 770 static void azx_init_cmd_io(struct azx *chip)
771 771 {
  772 + int timeout;
  773 +
772 774 spin_lock_irq(&chip->reg_lock);
773 775 /* CORB set up */
774 776 chip->corb.addr = chip->rb.addr;
775 777  
... ... @@ -780,8 +782,28 @@
780 782 azx_writeb(chip, CORBSIZE, 0x02);
781 783 /* set the corb write pointer to 0 */
782 784 azx_writew(chip, CORBWP, 0);
  785 +
783 786 /* reset the corb hw read pointer */
784 787 azx_writew(chip, CORBRP, ICH6_CORBRP_RST);
  788 + for (timeout = 1000; timeout > 0; timeout--) {
  789 + if ((azx_readw(chip, CORBRP) & ICH6_CORBRP_RST) == ICH6_CORBRP_RST)
  790 + break;
  791 + udelay(1);
  792 + }
  793 + if (timeout <= 0)
  794 + dev_err(chip->card->dev, "CORB reset timeout#1, CORBRP = %d\n",
  795 + azx_readw(chip, CORBRP));
  796 +
  797 + azx_writew(chip, CORBRP, 0);
  798 + for (timeout = 1000; timeout > 0; timeout--) {
  799 + if (azx_readw(chip, CORBRP) == 0)
  800 + break;
  801 + udelay(1);
  802 + }
  803 + if (timeout <= 0)
  804 + dev_err(chip->card->dev, "CORB reset timeout#2, CORBRP = %d\n",
  805 + azx_readw(chip, CORBRP));
  806 +
785 807 /* enable corb dma */
786 808 azx_writeb(chip, CORBCTL, ICH6_CORBCTL_RUN);
787 809  
... ... @@ -856,7 +878,7 @@
856 878  
857 879 chip->rirb.cmds[addr]++;
858 880 chip->corb.buf[wp] = cpu_to_le32(val);
859   - azx_writel(chip, CORBWP, wp);
  881 + azx_writew(chip, CORBWP, wp);
860 882  
861 883 spin_unlock_irq(&chip->reg_lock);
862 884