ALSA: hda - Reorganize controller quriks with bit flags
authorTakashi Iwai <tiwai@suse.de>
Wed, 25 May 2011 07:11:37 +0000 (09:11 +0200)
committerTakashi Iwai <tiwai@suse.de>
Thu, 26 May 2011 12:43:07 +0000 (14:43 +0200)
Introduce bit-flags indicating the necessary controller quirks, and
set them in pci driver_data field.  This simplifies the checks in the
driver code and avoids the pci-id lookup in different places.

Also, this patch adds the PCI ID entry for AMD Hudson.  AMD Hudson
requires a similar workaround like ATI SB while other generic ATI and
AMD controllers don't need but some ATI-HDMI quirks.  So, we need a
different entry for Hudson.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
sound/pci/hda/hda_intel.c

index 43a0367..3487056 100644 (file)
@@ -391,6 +391,7 @@ struct azx {
 
        /* chip type specific */
        int driver_type;
+       unsigned int driver_caps;
        int playback_streams;
        int playback_index_offset;
        int capture_streams;
@@ -464,6 +465,34 @@ enum {
        AZX_NUM_DRIVERS, /* keep this as last entry */
 };
 
+/* driver quirks (capabilities) */
+/* bits 0-7 are used for indicating driver type */
+#define AZX_DCAPS_NO_TCSEL     (1 << 8)        /* No Intel TCSEL bit */
+#define AZX_DCAPS_NO_MSI       (1 << 9)        /* No MSI support */
+#define AZX_DCAPS_ATI_SNOOP    (1 << 10)       /* ATI snoop enable */
+#define AZX_DCAPS_NVIDIA_SNOOP (1 << 11)       /* Nvidia snoop enable */
+#define AZX_DCAPS_SCH_SNOOP    (1 << 12)       /* SCH/PCH snoop enable */
+#define AZX_DCAPS_RIRB_DELAY   (1 << 13)       /* Long delay in read loop */
+#define AZX_DCAPS_RIRB_PRE_DELAY (1 << 14)     /* Put a delay before read */
+#define AZX_DCAPS_CTX_WORKAROUND (1 << 15)     /* X-Fi workaround */
+#define AZX_DCAPS_POSFIX_LPIB  (1 << 16)       /* Use LPIB as default */
+#define AZX_DCAPS_POSFIX_VIA   (1 << 17)       /* Use VIACOMBO as default */
+#define AZX_DCAPS_NO_64BIT     (1 << 18)       /* No 64bit address */
+#define AZX_DCAPS_SYNC_WRITE   (1 << 19)       /* sync each cmd write */
+
+/* quirks for ATI SB / AMD Hudson */
+#define AZX_DCAPS_PRESET_ATI_SB \
+       (AZX_DCAPS_ATI_SNOOP | AZX_DCAPS_NO_TCSEL | \
+        AZX_DCAPS_SYNC_WRITE | AZX_DCAPS_POSFIX_LPIB)
+
+/* quirks for ATI/AMD HDMI */
+#define AZX_DCAPS_PRESET_ATI_HDMI \
+       (AZX_DCAPS_NO_TCSEL | AZX_DCAPS_SYNC_WRITE | AZX_DCAPS_POSFIX_LPIB)
+
+/* quirks for Nvidia */
+#define AZX_DCAPS_PRESET_NVIDIA \
+       (AZX_DCAPS_NVIDIA_SNOOP | AZX_DCAPS_RIRB_DELAY | AZX_DCAPS_NO_MSI)
+
 static char *driver_short_names[] __devinitdata = {
        [AZX_DRIVER_ICH] = "HDA Intel",
        [AZX_DRIVER_PCH] = "HDA Intel PCH",
@@ -566,7 +595,7 @@ static void azx_init_cmd_io(struct azx *chip)
        /* reset the rirb hw write pointer */
        azx_writew(chip, RIRBWP, ICH6_RIRBWP_RST);
        /* set N=1, get RIRB response interrupt for new entry */
-       if (chip->driver_type == AZX_DRIVER_CTX)
+       if (chip->driver_caps & AZX_DCAPS_CTX_WORKAROUND)
                azx_writew(chip, RINTCNT, 0xc0);
        else
                azx_writew(chip, RINTCNT, 1);
@@ -1056,19 +1085,24 @@ static void azx_init_pci(struct azx *chip)
         * codecs.
         * The PCI register TCSEL is defined in the Intel manuals.
         */
-       if (chip->driver_type != AZX_DRIVER_ATI &&
-           chip->driver_type != AZX_DRIVER_ATIHDMI)
+       if (chip->driver_caps & AZX_DCAPS_NO_TCSEL) {
+               snd_printdd(SFX "Clearing TCSEL\n");
                update_pci_byte(chip->pci, ICH6_PCIREG_TCSEL, 0x07, 0);
+       }
 
-       switch (chip->driver_type) {
-       case AZX_DRIVER_ATI:
-               /* For ATI SB450 azalia HD audio, we need to enable snoop */
+       /* For ATI SB450/600/700/800/900 and AMD Hudson azalia HD audio,
+        * we need to enable snoop.
+        */
+       if (chip->driver_caps & AZX_DCAPS_ATI_SNOOP) {
+               snd_printdd(SFX "Enabling ATI snoop\n");
                update_pci_byte(chip->pci,
                                ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR, 
                                0x07, ATI_SB450_HDAUDIO_ENABLE_SNOOP);
-               break;
-       case AZX_DRIVER_NVIDIA:
-               /* For NVIDIA HDA, enable snoop */
+       }
+
+       /* For NVIDIA HDA, enable snoop */
+       if (chip->driver_caps & AZX_DCAPS_NVIDIA_SNOOP) {
+               snd_printdd(SFX "Enabling Nvidia snoop\n");
                update_pci_byte(chip->pci,
                                NVIDIA_HDA_TRANSREG_ADDR,
                                0x0f, NVIDIA_HDA_ENABLE_COHBITS);
@@ -1078,9 +1112,10 @@ static void azx_init_pci(struct azx *chip)
                update_pci_byte(chip->pci,
                                NVIDIA_HDA_OSTRM_COH,
                                0x01, NVIDIA_HDA_ENABLE_COHBIT);
-               break;
-       case AZX_DRIVER_SCH:
-       case AZX_DRIVER_PCH:
+       }
+
+       /* Enable SCH/PCH snoop if needed */
+       if (chip->driver_caps & AZX_DCAPS_SCH_SNOOP) {
                pci_read_config_word(chip->pci, INTEL_SCH_HDA_DEVC, &snoop);
                if (snoop & INTEL_SCH_HDA_DEVC_NOSNOOP) {
                        pci_write_config_word(chip->pci, INTEL_SCH_HDA_DEVC,
@@ -1091,14 +1126,6 @@ static void azx_init_pci(struct azx *chip)
                                (snoop & INTEL_SCH_HDA_DEVC_NOSNOOP)
                                ? "Failed" : "OK");
                }
-               break;
-       default:
-               /* AMD Hudson needs the similar snoop, as it seems... */
-               if (chip->pci->vendor == PCI_VENDOR_ID_AMD)
-                       update_pci_byte(chip->pci,
-                               ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR,
-                               0x07, ATI_SB450_HDAUDIO_ENABLE_SNOOP);
-               break;
         }
 }
 
@@ -1152,7 +1179,7 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id)
        status = azx_readb(chip, RIRBSTS);
        if (status & RIRB_INT_MASK) {
                if (status & RIRB_INT_RESPONSE) {
-                       if (chip->driver_type == AZX_DRIVER_CTX)
+                       if (chip->driver_caps & AZX_DCAPS_RIRB_PRE_DELAY)
                                udelay(80);
                        azx_update_rirb(chip);
                }
@@ -1421,8 +1448,10 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model)
        if (err < 0)
                return err;
 
-       if (chip->driver_type == AZX_DRIVER_NVIDIA)
+       if (chip->driver_caps & AZX_DCAPS_RIRB_DELAY) {
+               snd_printd(SFX "Enable delay in RIRB handling\n");
                chip->bus->needs_damn_long_delay = 1;
+       }
 
        codecs = 0;
        max_slots = azx_max_codecs[chip->driver_type];
@@ -1457,9 +1486,8 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model)
         * sequence like the pin-detection.  It seems that forcing the synced
         * access works around the stall.  Grrr...
         */
-       if (chip->pci->vendor == PCI_VENDOR_ID_AMD ||
-           chip->pci->vendor == PCI_VENDOR_ID_ATI) {
-               snd_printk(KERN_INFO SFX "Enable sync_write for AMD chipset\n");
+       if (chip->driver_caps & AZX_DCAPS_SYNC_WRITE) {
+               snd_printd(SFX "Enable sync_write for stable communication\n");
                chip->bus->sync_write = 1;
                chip->bus->allow_bus_reset = 1;
        }
@@ -1720,7 +1748,7 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream)
 
        stream_tag = azx_dev->stream_tag;
        /* CA-IBG chips need the playback stream starting from 1 */
-       if (chip->driver_type == AZX_DRIVER_CTX &&
+       if ((chip->driver_caps & AZX_DCAPS_CTX_WORKAROUND) &&
            stream_tag > chip->capture_streams)
                stream_tag -= chip->capture_streams;
        return snd_hda_codec_prepare(apcm->codec, hinfo, stream_tag,
@@ -2365,20 +2393,14 @@ static int __devinit check_position_fix(struct azx *chip, int fix)
        }
 
        /* Check VIA/ATI HD Audio Controller exist */
-       switch (chip->driver_type) {
-       case AZX_DRIVER_VIA:
-               /* Use link position directly, avoid any transfer problem. */
+       if (chip->driver_caps & AZX_DCAPS_POSFIX_VIA) {
+               snd_printd(SFX "Using VIACOMBO position fix\n");
                return POS_FIX_VIACOMBO;
-       case AZX_DRIVER_ATI:
-               /* ATI chipsets don't work well with position-buffer */
+       }
+       if (chip->driver_caps & AZX_DCAPS_POSFIX_LPIB) {
+               snd_printd(SFX "Using LPIB position fix\n");
                return POS_FIX_LPIB;
-       case AZX_DRIVER_GENERIC:
-               /* AMD chipsets also don't work with position-buffer */
-               if (chip->pci->vendor == PCI_VENDOR_ID_AMD)
-                       return POS_FIX_LPIB;
-               break;
        }
-
        return POS_FIX_AUTO;
 }
 
@@ -2460,8 +2482,8 @@ static void __devinit check_msi(struct azx *chip)
        }
 
        /* NVidia chipsets seem to cause troubles with MSI */
-       if (chip->driver_type == AZX_DRIVER_NVIDIA) {
-               printk(KERN_INFO "hda_intel: Disable MSI for Nvidia chipset\n");
+       if (chip->driver_caps & AZX_DCAPS_NO_MSI) {
+               printk(KERN_INFO "hda_intel: Disabling MSI\n");
                chip->msi = 0;
        }
 }
@@ -2471,7 +2493,7 @@ static void __devinit check_msi(struct azx *chip)
  * constructor
  */
 static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
-                               int dev, int driver_type,
+                               int dev, unsigned int driver_caps,
                                struct azx **rchip)
 {
        struct azx *chip;
@@ -2499,7 +2521,8 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
        chip->card = card;
        chip->pci = pci;
        chip->irq = -1;
-       chip->driver_type = driver_type;
+       chip->driver_caps = driver_caps;
+       chip->driver_type = driver_caps & 0xff;
        check_msi(chip);
        chip->dev_index = dev;
        INIT_WORK(&chip->irq_pending_work, azx_irq_pending_work);
@@ -2563,8 +2586,7 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
        snd_printdd(SFX "chipset global capabilities = 0x%x\n", gcap);
 
        /* disable SB600 64bit support for safety */
-       if ((chip->driver_type == AZX_DRIVER_ATI) ||
-           (chip->driver_type == AZX_DRIVER_ATIHDMI)) {
+       if (chip->pci->vendor == PCI_VENDOR_ID_ATI) {
                struct pci_dev *p_smbus;
                p_smbus = pci_get_device(PCI_VENDOR_ID_ATI,
                                         PCI_DEVICE_ID_ATI_SBX00_SMBUS,
@@ -2574,19 +2596,13 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
                                gcap &= ~ICH6_GCAP_64OK;
                        pci_dev_put(p_smbus);
                }
-       } else {
-               /* FIXME: not sure whether this is really needed, but
-                * Hudson isn't stable enough for allowing everything...
-                * let's check later again.
-                */
-               if (chip->pci->vendor == PCI_VENDOR_ID_AMD)
-                       gcap &= ~ICH6_GCAP_64OK;
        }
 
-       /* disable 64bit DMA address for Teradici */
-       /* it does not work with device 6549:1200 subsys e4a2:040b */
-       if (chip->driver_type == AZX_DRIVER_TERA)
+       /* disable 64bit DMA address on some devices */
+       if (chip->driver_caps & AZX_DCAPS_NO_64BIT) {
+               snd_printd(SFX "Disabling 64bit DMA\n");
                gcap &= ~ICH6_GCAP_64OK;
+       }
 
        /* allow 64bit DMA address if supported by H/W */
        if ((gcap & ICH6_GCAP_64OK) && !pci_set_dma_mask(pci, DMA_BIT_MASK(64)))
@@ -2788,38 +2804,62 @@ static void __devexit azx_remove(struct pci_dev *pci)
 /* PCI IDs */
 static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
        /* CPT */
-       { PCI_DEVICE(0x8086, 0x1c20), .driver_data = AZX_DRIVER_PCH },
+       { PCI_DEVICE(0x8086, 0x1c20),
+         .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP },
        /* PBG */
-       { PCI_DEVICE(0x8086, 0x1d20), .driver_data = AZX_DRIVER_PCH },
+       { PCI_DEVICE(0x8086, 0x1d20),
+         .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP },
        /* Panther Point */
-       { PCI_DEVICE(0x8086, 0x1e20), .driver_data = AZX_DRIVER_PCH },
+       { PCI_DEVICE(0x8086, 0x1e20),
+         .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP },
        /* SCH */
-       { PCI_DEVICE(0x8086, 0x811b), .driver_data = AZX_DRIVER_SCH },
+       { PCI_DEVICE(0x8086, 0x811b),
+         .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_SCH_SNOOP },
        /* Generic Intel */
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_ANY_ID),
          .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
          .class_mask = 0xffffff,
          .driver_data = AZX_DRIVER_ICH },
-       /* ATI SB 450/600 */
-       { PCI_DEVICE(0x1002, 0x437b), .driver_data = AZX_DRIVER_ATI },
-       { PCI_DEVICE(0x1002, 0x4383), .driver_data = AZX_DRIVER_ATI },
+       /* ATI SB 450/600/700/800/900 */
+       { PCI_DEVICE(0x1002, 0x437b),
+         .driver_data = AZX_DRIVER_ATI | AZX_DCAPS_PRESET_ATI_SB },
+       { PCI_DEVICE(0x1002, 0x4383),
+         .driver_data = AZX_DRIVER_ATI | AZX_DCAPS_PRESET_ATI_SB },
+       /* AMD Hudson */
+       { PCI_DEVICE(0x1022, 0x780d),
+         .driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_ATI_SB },
        /* ATI HDMI */
-       { PCI_DEVICE(0x1002, 0x793b), .driver_data = AZX_DRIVER_ATIHDMI },
-       { PCI_DEVICE(0x1002, 0x7919), .driver_data = AZX_DRIVER_ATIHDMI },
-       { PCI_DEVICE(0x1002, 0x960f), .driver_data = AZX_DRIVER_ATIHDMI },
-       { PCI_DEVICE(0x1002, 0x970f), .driver_data = AZX_DRIVER_ATIHDMI },
-       { PCI_DEVICE(0x1002, 0xaa00), .driver_data = AZX_DRIVER_ATIHDMI },
-       { PCI_DEVICE(0x1002, 0xaa08), .driver_data = AZX_DRIVER_ATIHDMI },
-       { PCI_DEVICE(0x1002, 0xaa10), .driver_data = AZX_DRIVER_ATIHDMI },
-       { PCI_DEVICE(0x1002, 0xaa18), .driver_data = AZX_DRIVER_ATIHDMI },
-       { PCI_DEVICE(0x1002, 0xaa20), .driver_data = AZX_DRIVER_ATIHDMI },
-       { PCI_DEVICE(0x1002, 0xaa28), .driver_data = AZX_DRIVER_ATIHDMI },
-       { PCI_DEVICE(0x1002, 0xaa30), .driver_data = AZX_DRIVER_ATIHDMI },
-       { PCI_DEVICE(0x1002, 0xaa38), .driver_data = AZX_DRIVER_ATIHDMI },
-       { PCI_DEVICE(0x1002, 0xaa40), .driver_data = AZX_DRIVER_ATIHDMI },
-       { PCI_DEVICE(0x1002, 0xaa48), .driver_data = AZX_DRIVER_ATIHDMI },
+       { PCI_DEVICE(0x1002, 0x793b),
+         .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
+       { PCI_DEVICE(0x1002, 0x7919),
+         .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
+       { PCI_DEVICE(0x1002, 0x960f),
+         .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
+       { PCI_DEVICE(0x1002, 0x970f),
+         .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
+       { PCI_DEVICE(0x1002, 0xaa00),
+         .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
+       { PCI_DEVICE(0x1002, 0xaa08),
+         .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
+       { PCI_DEVICE(0x1002, 0xaa10),
+         .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
+       { PCI_DEVICE(0x1002, 0xaa18),
+         .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
+       { PCI_DEVICE(0x1002, 0xaa20),
+         .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
+       { PCI_DEVICE(0x1002, 0xaa28),
+         .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
+       { PCI_DEVICE(0x1002, 0xaa30),
+         .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
+       { PCI_DEVICE(0x1002, 0xaa38),
+         .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
+       { PCI_DEVICE(0x1002, 0xaa40),
+         .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
+       { PCI_DEVICE(0x1002, 0xaa48),
+         .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
        /* VIA VT8251/VT8237A */
-       { PCI_DEVICE(0x1106, 0x3288), .driver_data = AZX_DRIVER_VIA },
+       { PCI_DEVICE(0x1106, 0x3288),
+         .driver_data = AZX_DRIVER_VIA | AZX_DCAPS_POSFIX_VIA },
        /* SIS966 */
        { PCI_DEVICE(0x1039, 0x7502), .driver_data = AZX_DRIVER_SIS },
        /* ULI M5461 */
@@ -2828,9 +2868,10 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
        { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID),
          .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
          .class_mask = 0xffffff,
-         .driver_data = AZX_DRIVER_NVIDIA },
+         .driver_data = AZX_DRIVER_NVIDIA | AZX_DCAPS_PRESET_NVIDIA },
        /* Teradici */
-       { PCI_DEVICE(0x6549, 0x1200), .driver_data = AZX_DRIVER_TERA },
+       { PCI_DEVICE(0x6549, 0x1200),
+         .driver_data = AZX_DRIVER_TERA | AZX_DCAPS_NO_64BIT },
        /* Creative X-Fi (CA0110-IBG) */
 #if !defined(CONFIG_SND_CTXFI) && !defined(CONFIG_SND_CTXFI_MODULE)
        /* the following entry conflicts with snd-ctxfi driver,
@@ -2840,10 +2881,13 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
        { PCI_DEVICE(PCI_VENDOR_ID_CREATIVE, PCI_ANY_ID),
          .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
          .class_mask = 0xffffff,
-         .driver_data = AZX_DRIVER_CTX },
+         .driver_data = AZX_DRIVER_CTX | AZX_DCAPS_CTX_WORKAROUND |
+         AZX_DCAPS_RIRB_PRE_DELAY },
 #else
        /* this entry seems still valid -- i.e. without emu20kx chip */
-       { PCI_DEVICE(0x1102, 0x0009), .driver_data = AZX_DRIVER_CTX },
+       { PCI_DEVICE(0x1102, 0x0009),
+         .driver_data = AZX_DRIVER_CTX | AZX_DCAPS_CTX_WORKAROUND |
+         AZX_DCAPS_RIRB_PRE_DELAY },
 #endif
        /* Vortex86MX */
        { PCI_DEVICE(0x17f3, 0x3010), .driver_data = AZX_DRIVER_GENERIC },
@@ -2853,11 +2897,11 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
        { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_ANY_ID),
          .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
          .class_mask = 0xffffff,
-         .driver_data = AZX_DRIVER_GENERIC },
+         .driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_ATI_HDMI },
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_ANY_ID),
          .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
          .class_mask = 0xffffff,
-         .driver_data = AZX_DRIVER_GENERIC },
+         .driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_ATI_HDMI },
        { 0, }
 };
 MODULE_DEVICE_TABLE(pci, azx_ids);