diff --git a/src/add-ons/kernel/drivers/audio/hda/hda_controller.cpp b/src/add-ons/kernel/drivers/audio/hda/hda_controller.cpp index 533e91e8b2..6d75b06e1e 100644 --- a/src/add-ons/kernel/drivers/audio/hda/hda_controller.cpp +++ b/src/add-ons/kernel/drivers/audio/hda/hda_controller.cpp @@ -35,6 +35,33 @@ #define PAGE_ALIGN(size) (((size) + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1)) +#define PCI_VENDOR_AMD 0x1002 +#define PCI_VENDOR_INTEL 0x8086 +#define PCI_VENDOR_NVIDIA 0x10de +#define PCI_ALL_DEVICES 0xffffffff +#define HDA_QUIRK_SNOOP 0x0001 + + +static const struct { + uint32 vendor_id, device_id; + uint32 quirks; +} kControllerQuirks[] = { + { PCI_VENDOR_INTEL, 0x1c20, HDA_QUIRK_SNOOP }, + { PCI_VENDOR_INTEL, 0x1d20, HDA_QUIRK_SNOOP }, + { PCI_VENDOR_INTEL, 0x1e20, HDA_QUIRK_SNOOP }, + { PCI_VENDOR_INTEL, 0x8c20, HDA_QUIRK_SNOOP }, + { PCI_VENDOR_INTEL, 0x9c20, HDA_QUIRK_SNOOP }, + { PCI_VENDOR_INTEL, 0x9c21, HDA_QUIRK_SNOOP }, + { PCI_VENDOR_INTEL, 0x0c0c, HDA_QUIRK_SNOOP }, + { PCI_VENDOR_INTEL, 0x811b, HDA_QUIRK_SNOOP }, + { PCI_VENDOR_INTEL, 0x080a, HDA_QUIRK_SNOOP }, + // Enable snooping for ATI and Nvidia, right now for all their hda-devices, + // but only based on guessing. + { PCI_VENDOR_AMD, PCI_ALL_DEVICES, HDA_QUIRK_SNOOP }, + { PCI_VENDOR_NVIDIA, PCI_ALL_DEVICES, HDA_QUIRK_SNOOP }, +}; + + static const struct { uint32 multi_rate; uint32 hw_rate; @@ -59,6 +86,20 @@ static const struct { static pci_x86_module_info* sPCIx86Module; +static uint32 +get_controller_quirks(pci_info& info) +{ + for (size_t i = 0; + i < sizeof(kControllerQuirks) / sizeof(kControllerQuirks[0]); i++) { + if (info.vendor_id == kControllerQuirks[i].vendor_id + && (kControllerQuirks[i].device_id == PCI_ALL_DEVICES + || kControllerQuirks[i].device_id == info.device_id)) + return kControllerQuirks[i].quirks; + } + return 0; +} + + static inline void update_pci_register(hda_controller* controller, uint8 reg, uint32 mask, uint32 value, uint8 size) @@ -800,8 +841,11 @@ hda_verb_read(hda_codec* codec, uint32 nid, uint32 vid, uint32* response) status_t hda_hw_init(hda_controller* controller) { - uint16 capabilities, stateStatus, cmd; + uint16 capabilities; + uint16 stateStatus; + uint16 cmd; status_t status; + uint32 quirks; // Map MMIO registers controller->regs_area = map_physical_memory("hda_hw_regs", @@ -861,27 +905,26 @@ hda_hw_init(hda_controller* controller) // TCSEL is reset to TC0 (clear 0-2 bits) update_pci_register(controller, PCI_HDA_TCSEL, PCI_HDA_TCSEL_MASK, 0, 1); - // Enable snooping for ATI and Nvidia, right now for all their hda-devices, - // but only based on guessing. - switch (controller->pci_info.vendor_id) { - case NVIDIA_VENDORID: - update_pci_register(controller, NVIDIA_HDA_TRANSREG, - NVIDIA_HDA_TRANSREG_MASK, NVIDIA_HDA_ENABLE_COHBITS, 1); - update_pci_register(controller, NVIDIA_HDA_ISTRM_COH, - ~NVIDIA_HDA_ENABLE_COHBIT, NVIDIA_HDA_ENABLE_COHBIT, 1); - update_pci_register(controller, NVIDIA_HDA_OSTRM_COH, - ~NVIDIA_HDA_ENABLE_COHBIT, NVIDIA_HDA_ENABLE_COHBIT, 1); - break; - case ATI_VENDORID: - update_pci_register(controller, ATI_HDA_MISC_CNTR2, - ATI_HDA_MISC_CNTR2_MASK, ATI_HDA_ENABLE_SNOOP, 1); - break; - case INTEL_VENDORID: - if (controller->pci_info.device_id == INTEL_SCH_DEVICEID) { + quirks = get_controller_quirks(controller->pci_info); + if ((quirks & HDA_QUIRK_SNOOP) != 0) { + switch (controller->pci_info.vendor_id) { + case PCI_VENDOR_NVIDIA: + update_pci_register(controller, NVIDIA_HDA_TRANSREG, + NVIDIA_HDA_TRANSREG_MASK, NVIDIA_HDA_ENABLE_COHBITS, 1); + update_pci_register(controller, NVIDIA_HDA_ISTRM_COH, + ~NVIDIA_HDA_ENABLE_COHBIT, NVIDIA_HDA_ENABLE_COHBIT, 1); + update_pci_register(controller, NVIDIA_HDA_OSTRM_COH, + ~NVIDIA_HDA_ENABLE_COHBIT, NVIDIA_HDA_ENABLE_COHBIT, 1); + break; + case PCI_VENDOR_AMD: + update_pci_register(controller, ATI_HDA_MISC_CNTR2, + ATI_HDA_MISC_CNTR2_MASK, ATI_HDA_ENABLE_SNOOP, 1); + break; + case PCI_VENDOR_INTEL: update_pci_register(controller, INTEL_SCH_HDA_DEVC, ~INTEL_SCH_HDA_DEVC_SNOOP, 0, 2); - } - break; + break; + } } capabilities = controller->Read16(HDAC_GLOBAL_CAP); diff --git a/src/add-ons/kernel/drivers/audio/hda/hda_controller_defs.h b/src/add-ons/kernel/drivers/audio/hda/hda_controller_defs.h index 1fbca3f87b..154ab38feb 100644 --- a/src/add-ons/kernel/drivers/audio/hda/hda_controller_defs.h +++ b/src/add-ons/kernel/drivers/audio/hda/hda_controller_defs.h @@ -1,5 +1,5 @@ /* - * Copyright 2007-2008, Haiku, Inc. All Rights Reserved. + * Copyright 2007-2012, Haiku, Inc. All Rights Reserved. * Distributed under the terms of the MIT License. * * Authors: @@ -135,24 +135,18 @@ #define PCI_HDA_TCSEL 0x44 #define PCI_HDA_TCSEL_MASK 0xf8 -#define ATI_HDA_MISC_CNTR2 0x42 +#define ATI_HDA_MISC_CNTR2 0x42 #define ATI_HDA_MISC_CNTR2_MASK 0xf8 #define ATI_HDA_ENABLE_SNOOP 0x02 #define NVIDIA_HDA_OSTRM_COH 0x4c #define NVIDIA_HDA_ISTRM_COH 0x4d #define NVIDIA_HDA_ENABLE_COHBIT 0x01 -#define NVIDIA_HDA_TRANSREG 0x4e +#define NVIDIA_HDA_TRANSREG 0x4e #define NVIDIA_HDA_TRANSREG_MASK 0xf0 #define NVIDIA_HDA_ENABLE_COHBITS 0x0f -#define INTEL_SCH_HDA_DEVC 0x78 +#define INTEL_SCH_HDA_DEVC 0x78 #define INTEL_SCH_HDA_DEVC_SNOOP 0x800 -#define ATI_VENDORID 0x1002 -#define INTEL_VENDORID 0x8086 -#define INTEL_SCH_DEVICEID 0x811b -#define NVIDIA_VENDORID 0x10de - - typedef uint32 corb_t; typedef struct {