From 22b4f0cd1d4d98f50213e9a37ead654e80b54b9d Mon Sep 17 00:00:00 2001 From: Huang Rui Date: Mon, 16 Sep 2013 23:47:27 +0800 Subject: [PATCH] usb: pci-quirks: refactor AMD quirk to abstract AMD chipset types This patch abstracts out a AMD chipset type which includes southbridge generation and its revision. When os excutes usb_amd_find_chipset_info routine to initialize AMD chipset type, driver will know which kind of chipset is used. This update has below benifits: - Driver is able to confirm which southbridge generations and their revision are used, with chipset detection once. - To describe chipset generations with enumeration types brings better readability. - It's flexible to filter AMD platforms to implement new quirks in future. Signed-off-by: Huang Rui Cc: Andiry Xu Acked-by: Alan Stern Acked-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/pci-quirks.c | 104 ++++++++++++++++++++++++++++++++---------- 1 file changed, 80 insertions(+), 24 deletions(-) diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index 2c76ef1..d1e68d8 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c @@ -79,11 +79,30 @@ #define USB_INTEL_USB3_PSSEN 0xD8 #define USB_INTEL_USB3PRM 0xDC +/* + * amd_chipset_gen values represent AMD different chipset generations + */ +enum amd_chipset_gen { + NOT_AMD_CHIPSET = 0, + AMD_CHIPSET_SB600, + AMD_CHIPSET_SB700, + AMD_CHIPSET_SB800, + AMD_CHIPSET_HUDSON2, + AMD_CHIPSET_BOLTON, + AMD_CHIPSET_YANGTZE, + AMD_CHIPSET_UNKNOWN, +}; + +struct amd_chipset_type { + enum amd_chipset_gen gen; + u8 rev; +}; + static struct amd_chipset_info { struct pci_dev *nb_dev; struct pci_dev *smbus_dev; int nb_type; - int sb_type; + struct amd_chipset_type sb_type; int isoc_reqs; int probe_count; int probe_result; @@ -91,6 +110,51 @@ static struct amd_chipset_info { static DEFINE_SPINLOCK(amd_lock); +/* + * amd_chipset_sb_type_init - initialize amd chipset southbridge type + * + * AMD FCH/SB generation and revision is identified by SMBus controller + * vendor, device and revision IDs. + * + * Returns: 1 if it is an AMD chipset, 0 otherwise. + */ +int amd_chipset_sb_type_init(struct amd_chipset_info *pinfo) +{ + u8 rev = 0; + pinfo->sb_type.gen = AMD_CHIPSET_UNKNOWN; + + pinfo->smbus_dev = pci_get_device(PCI_VENDOR_ID_ATI, + PCI_DEVICE_ID_ATI_SBX00_SMBUS, NULL); + if (pinfo->smbus_dev) { + rev = pinfo->smbus_dev->revision; + if (rev >= 0x10 && rev <= 0x1f) + pinfo->sb_type.gen = AMD_CHIPSET_SB600; + else if (rev >= 0x30 && rev <= 0x3f) + pinfo->sb_type.gen = AMD_CHIPSET_SB700; + else if (rev >= 0x40 && rev <= 0x4f) + pinfo->sb_type.gen = AMD_CHIPSET_SB800; + } else { + pinfo->smbus_dev = pci_get_device(PCI_VENDOR_ID_AMD, + PCI_DEVICE_ID_AMD_HUDSON2_SMBUS, NULL); + + if (!pinfo->smbus_dev) { + pinfo->sb_type.gen = NOT_AMD_CHIPSET; + return 0; + } + + rev = pinfo->smbus_dev->revision; + if (rev >= 0x11 && rev <= 0x14) + pinfo->sb_type.gen = AMD_CHIPSET_HUDSON2; + else if (rev >= 0x15 && rev <= 0x18) + pinfo->sb_type.gen = AMD_CHIPSET_BOLTON; + else if (rev >= 0x39 && rev <= 0x3a) + pinfo->sb_type.gen = AMD_CHIPSET_YANGTZE; + } + + pinfo->sb_type.rev = rev; + return 1; +} + void sb800_prefetch(struct device *dev, int on) { u16 misc; @@ -106,7 +170,6 @@ EXPORT_SYMBOL_GPL(sb800_prefetch); int usb_amd_find_chipset_info(void) { - u8 rev = 0; unsigned long flags; struct amd_chipset_info info; int ret; @@ -122,27 +185,17 @@ int usb_amd_find_chipset_info(void) memset(&info, 0, sizeof(info)); spin_unlock_irqrestore(&amd_lock, flags); - info.smbus_dev = pci_get_device(PCI_VENDOR_ID_ATI, 0x4385, NULL); - if (info.smbus_dev) { - rev = info.smbus_dev->revision; - if (rev >= 0x40) - info.sb_type = 1; - else if (rev >= 0x30 && rev <= 0x3b) - info.sb_type = 3; - } else { - info.smbus_dev = pci_get_device(PCI_VENDOR_ID_AMD, - 0x780b, NULL); - if (!info.smbus_dev) { - ret = 0; - goto commit; - } - - rev = info.smbus_dev->revision; - if (rev >= 0x11 && rev <= 0x18) - info.sb_type = 2; + if (!amd_chipset_sb_type_init(&info)) { + ret = 0; + goto commit; } - if (info.sb_type == 0) { + /* Below chipset generations needn't enable AMD PLL quirk */ + if (info.sb_type.gen == AMD_CHIPSET_UNKNOWN || + info.sb_type.gen == AMD_CHIPSET_SB600 || + info.sb_type.gen == AMD_CHIPSET_YANGTZE || + (info.sb_type.gen == AMD_CHIPSET_SB700 && + info.sb_type.rev > 0x3b)) { if (info.smbus_dev) { pci_dev_put(info.smbus_dev); info.smbus_dev = NULL; @@ -229,7 +282,9 @@ static void usb_amd_quirk_pll(int disable) } } - if (amd_chipset.sb_type == 1 || amd_chipset.sb_type == 2) { + if (amd_chipset.sb_type.gen == AMD_CHIPSET_SB800 || + amd_chipset.sb_type.gen == AMD_CHIPSET_HUDSON2 || + amd_chipset.sb_type.gen == AMD_CHIPSET_BOLTON) { outb_p(AB_REG_BAR_LOW, 0xcd6); addr_low = inb_p(0xcd7); outb_p(AB_REG_BAR_HIGH, 0xcd6); @@ -240,7 +295,8 @@ static void usb_amd_quirk_pll(int disable) outl_p(0x40, AB_DATA(addr)); outl_p(0x34, AB_INDX(addr)); val = inl_p(AB_DATA(addr)); - } else if (amd_chipset.sb_type == 3) { + } else if (amd_chipset.sb_type.gen == AMD_CHIPSET_SB700 && + amd_chipset.sb_type.rev <= 0x3b) { pci_read_config_dword(amd_chipset.smbus_dev, AB_REG_BAR_SB700, &addr); outl(AX_INDXC, AB_INDX(addr)); @@ -353,7 +409,7 @@ void usb_amd_dev_put(void) amd_chipset.nb_dev = NULL; amd_chipset.smbus_dev = NULL; amd_chipset.nb_type = 0; - amd_chipset.sb_type = 0; + memset(&amd_chipset.sb_type, 0, sizeof(amd_chipset.sb_type)); amd_chipset.isoc_reqs = 0; amd_chipset.probe_result = 0; -- 2.7.4