aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host
diff options
context:
space:
mode:
authorAndiry Xu <andiry.xu@amd.com>2011-03-01 01:57:05 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2011-03-01 16:01:45 -0500
commitad93562bdeecdded7d02eaaaf1aa5705ab57b1b7 (patch)
tree92bd220ce673a8260fb4cb4799024529af664208 /drivers/usb/host
parent53689ac1b677532be666a779e24b0ac9bd266354 (diff)
USB host: Move AMD PLL quirk to pci-quirks.c
This patch moves the AMD PLL quirk code in OHCI/EHCI driver to pci-quirks.c, and exports the functions to be used by xHCI driver later. AMD PLL quirk disable the optional PM feature inside specific SB700/SB800/Hudson-2/3 platforms under the following conditions: 1. If an isochronous device is connected to OHCI/EHCI/xHCI port and is active; 2. Optional PM feature that powers down the internal Bus PLL when the link is in low power state is enabled. Without AMD PLL quirk, USB isochronous stream may stutter or have breaks occasionally, which greatly impair the performance of audio/video streams. Currently AMD PLL quirk is implemented in OHCI and EHCI driver, and will be added to xHCI driver too. They are doing similar things actually, so move the quirk code to pci-quirks.c, which has several advantages: 1. Remove duplicate defines and functions in OHCI/EHCI (and xHCI) driver and make them cleaner; 2. AMD chipset information will be probed only once and then stored. Currently they're probed during every OHCI/EHCI initialization, move the detect code to pci-quirks.c saves the repeat detect cost; 3. Build up synchronization among OHCI/EHCI/xHCI driver. In current code, every host controller enable/disable PLL only according to its own status, and may enable PLL while there is still isoc transfer on other HCs. Move the quirk to pci-quirks.c prevents this issue. Signed-off-by: Andiry Xu <andiry.xu@amd.com> Cc: David Brownell <dbrownell@users.sourceforge.net> Cc: Alex He <alex.he@amd.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/host')
-rw-r--r--drivers/usb/host/ehci-hcd.c10
-rw-r--r--drivers/usb/host/ehci-pci.c45
-rw-r--r--drivers/usb/host/ehci-sched.c73
-rw-r--r--drivers/usb/host/ehci.h2
-rw-r--r--drivers/usb/host/ohci-hcd.c13
-rw-r--r--drivers/usb/host/ohci-pci.c110
-rw-r--r--drivers/usb/host/ohci-q.c4
-rw-r--r--drivers/usb/host/ohci.h4
-rw-r--r--drivers/usb/host/pci-quirks.c258
-rw-r--r--drivers/usb/host/pci-quirks.h10
10 files changed, 300 insertions, 229 deletions
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index f69305d3a9b8..e6277536f392 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -114,13 +114,11 @@ MODULE_PARM_DESC(hird, "host initiated resume duration, +1 for each 75us\n");
114 114
115#define INTR_MASK (STS_IAA | STS_FATAL | STS_PCD | STS_ERR | STS_INT) 115#define INTR_MASK (STS_IAA | STS_FATAL | STS_PCD | STS_ERR | STS_INT)
116 116
117/* for ASPM quirk of ISOC on AMD SB800 */
118static struct pci_dev *amd_nb_dev;
119
120/*-------------------------------------------------------------------------*/ 117/*-------------------------------------------------------------------------*/
121 118
122#include "ehci.h" 119#include "ehci.h"
123#include "ehci-dbg.c" 120#include "ehci-dbg.c"
121#include "pci-quirks.h"
124 122
125/*-------------------------------------------------------------------------*/ 123/*-------------------------------------------------------------------------*/
126 124
@@ -532,10 +530,8 @@ static void ehci_stop (struct usb_hcd *hcd)
532 spin_unlock_irq (&ehci->lock); 530 spin_unlock_irq (&ehci->lock);
533 ehci_mem_cleanup (ehci); 531 ehci_mem_cleanup (ehci);
534 532
535 if (amd_nb_dev) { 533 if (ehci->amd_pll_fix == 1)
536 pci_dev_put(amd_nb_dev); 534 usb_amd_dev_put();
537 amd_nb_dev = NULL;
538 }
539 535
540#ifdef EHCI_STATS 536#ifdef EHCI_STATS
541 ehci_dbg (ehci, "irq normal %ld err %ld reclaim %ld (lost %ld)\n", 537 ehci_dbg (ehci, "irq normal %ld err %ld reclaim %ld (lost %ld)\n",
diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c
index 07bb982e59f6..d5eaea7caf89 100644
--- a/drivers/usb/host/ehci-pci.c
+++ b/drivers/usb/host/ehci-pci.c
@@ -44,42 +44,6 @@ static int ehci_pci_reinit(struct ehci_hcd *ehci, struct pci_dev *pdev)
44 return 0; 44 return 0;
45} 45}
46 46
47static int ehci_quirk_amd_hudson(struct ehci_hcd *ehci)
48{
49 struct pci_dev *amd_smbus_dev;
50 u8 rev = 0;
51
52 amd_smbus_dev = pci_get_device(PCI_VENDOR_ID_ATI, 0x4385, NULL);
53 if (amd_smbus_dev) {
54 pci_read_config_byte(amd_smbus_dev, PCI_REVISION_ID, &rev);
55 if (rev < 0x40) {
56 pci_dev_put(amd_smbus_dev);
57 amd_smbus_dev = NULL;
58 return 0;
59 }
60 } else {
61 amd_smbus_dev = pci_get_device(PCI_VENDOR_ID_AMD, 0x780b, NULL);
62 if (!amd_smbus_dev)
63 return 0;
64 pci_read_config_byte(amd_smbus_dev, PCI_REVISION_ID, &rev);
65 if (rev < 0x11 || rev > 0x18) {
66 pci_dev_put(amd_smbus_dev);
67 amd_smbus_dev = NULL;
68 return 0;
69 }
70 }
71
72 if (!amd_nb_dev)
73 amd_nb_dev = pci_get_device(PCI_VENDOR_ID_AMD, 0x1510, NULL);
74
75 ehci_info(ehci, "QUIRK: Enable exception for AMD Hudson ASPM\n");
76
77 pci_dev_put(amd_smbus_dev);
78 amd_smbus_dev = NULL;
79
80 return 1;
81}
82
83/* called during probe() after chip reset completes */ 47/* called during probe() after chip reset completes */
84static int ehci_pci_setup(struct usb_hcd *hcd) 48static int ehci_pci_setup(struct usb_hcd *hcd)
85{ 49{
@@ -138,9 +102,6 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
138 /* cache this readonly data; minimize chip reads */ 102 /* cache this readonly data; minimize chip reads */
139 ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); 103 ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
140 104
141 if (ehci_quirk_amd_hudson(ehci))
142 ehci->amd_l1_fix = 1;
143
144 retval = ehci_halt(ehci); 105 retval = ehci_halt(ehci);
145 if (retval) 106 if (retval)
146 return retval; 107 return retval;
@@ -191,6 +152,9 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
191 } 152 }
192 break; 153 break;
193 case PCI_VENDOR_ID_AMD: 154 case PCI_VENDOR_ID_AMD:
155 /* AMD PLL quirk */
156 if (usb_amd_find_chipset_info())
157 ehci->amd_pll_fix = 1;
194 /* AMD8111 EHCI doesn't work, according to AMD errata */ 158 /* AMD8111 EHCI doesn't work, according to AMD errata */
195 if (pdev->device == 0x7463) { 159 if (pdev->device == 0x7463) {
196 ehci_info(ehci, "ignoring AMD8111 (errata)\n"); 160 ehci_info(ehci, "ignoring AMD8111 (errata)\n");
@@ -236,6 +200,9 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
236 } 200 }
237 break; 201 break;
238 case PCI_VENDOR_ID_ATI: 202 case PCI_VENDOR_ID_ATI:
203 /* AMD PLL quirk */
204 if (usb_amd_find_chipset_info())
205 ehci->amd_pll_fix = 1;
239 /* SB600 and old version of SB700 have a bug in EHCI controller, 206 /* SB600 and old version of SB700 have a bug in EHCI controller,
240 * which causes usb devices lose response in some cases. 207 * which causes usb devices lose response in some cases.
241 */ 208 */
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index 30fbdbe1cf1e..1543c838b3d1 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -1587,63 +1587,6 @@ itd_link (struct ehci_hcd *ehci, unsigned frame, struct ehci_itd *itd)
1587 *hw_p = cpu_to_hc32(ehci, itd->itd_dma | Q_TYPE_ITD); 1587 *hw_p = cpu_to_hc32(ehci, itd->itd_dma | Q_TYPE_ITD);
1588} 1588}
1589 1589
1590#define AB_REG_BAR_LOW 0xe0
1591#define AB_REG_BAR_HIGH 0xe1
1592#define AB_INDX(addr) ((addr) + 0x00)
1593#define AB_DATA(addr) ((addr) + 0x04)
1594#define NB_PCIE_INDX_ADDR 0xe0
1595#define NB_PCIE_INDX_DATA 0xe4
1596#define NB_PIF0_PWRDOWN_0 0x01100012
1597#define NB_PIF0_PWRDOWN_1 0x01100013
1598
1599static void ehci_quirk_amd_L1(struct ehci_hcd *ehci, int disable)
1600{
1601 u32 addr, addr_low, addr_high, val;
1602
1603 outb_p(AB_REG_BAR_LOW, 0xcd6);
1604 addr_low = inb_p(0xcd7);
1605 outb_p(AB_REG_BAR_HIGH, 0xcd6);
1606 addr_high = inb_p(0xcd7);
1607 addr = addr_high << 8 | addr_low;
1608 outl_p(0x30, AB_INDX(addr));
1609 outl_p(0x40, AB_DATA(addr));
1610 outl_p(0x34, AB_INDX(addr));
1611 val = inl_p(AB_DATA(addr));
1612
1613 if (disable) {
1614 val &= ~0x8;
1615 val |= (1 << 4) | (1 << 9);
1616 } else {
1617 val |= 0x8;
1618 val &= ~((1 << 4) | (1 << 9));
1619 }
1620 outl_p(val, AB_DATA(addr));
1621
1622 if (amd_nb_dev) {
1623 addr = NB_PIF0_PWRDOWN_0;
1624 pci_write_config_dword(amd_nb_dev, NB_PCIE_INDX_ADDR, addr);
1625 pci_read_config_dword(amd_nb_dev, NB_PCIE_INDX_DATA, &val);
1626 if (disable)
1627 val &= ~(0x3f << 7);
1628 else
1629 val |= 0x3f << 7;
1630
1631 pci_write_config_dword(amd_nb_dev, NB_PCIE_INDX_DATA, val);
1632
1633 addr = NB_PIF0_PWRDOWN_1;
1634 pci_write_config_dword(amd_nb_dev, NB_PCIE_INDX_ADDR, addr);
1635 pci_read_config_dword(amd_nb_dev, NB_PCIE_INDX_DATA, &val);
1636 if (disable)
1637 val &= ~(0x3f << 7);
1638 else
1639 val |= 0x3f << 7;
1640
1641 pci_write_config_dword(amd_nb_dev, NB_PCIE_INDX_DATA, val);
1642 }
1643
1644 return;
1645}
1646
1647/* fit urb's itds into the selected schedule slot; activate as needed */ 1590/* fit urb's itds into the selected schedule slot; activate as needed */
1648static int 1591static int
1649itd_link_urb ( 1592itd_link_urb (
@@ -1672,8 +1615,8 @@ itd_link_urb (
1672 } 1615 }
1673 1616
1674 if (ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs == 0) { 1617 if (ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs == 0) {
1675 if (ehci->amd_l1_fix == 1) 1618 if (ehci->amd_pll_fix == 1)
1676 ehci_quirk_amd_L1(ehci, 1); 1619 usb_amd_quirk_pll_disable();
1677 } 1620 }
1678 1621
1679 ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs++; 1622 ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs++;
@@ -1801,8 +1744,8 @@ itd_complete (
1801 ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs--; 1744 ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs--;
1802 1745
1803 if (ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs == 0) { 1746 if (ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs == 0) {
1804 if (ehci->amd_l1_fix == 1) 1747 if (ehci->amd_pll_fix == 1)
1805 ehci_quirk_amd_L1(ehci, 0); 1748 usb_amd_quirk_pll_enable();
1806 } 1749 }
1807 1750
1808 if (unlikely(list_is_singular(&stream->td_list))) { 1751 if (unlikely(list_is_singular(&stream->td_list))) {
@@ -2092,8 +2035,8 @@ sitd_link_urb (
2092 } 2035 }
2093 2036
2094 if (ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs == 0) { 2037 if (ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs == 0) {
2095 if (ehci->amd_l1_fix == 1) 2038 if (ehci->amd_pll_fix == 1)
2096 ehci_quirk_amd_L1(ehci, 1); 2039 usb_amd_quirk_pll_disable();
2097 } 2040 }
2098 2041
2099 ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs++; 2042 ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs++;
@@ -2197,8 +2140,8 @@ sitd_complete (
2197 ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs--; 2140 ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs--;
2198 2141
2199 if (ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs == 0) { 2142 if (ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs == 0) {
2200 if (ehci->amd_l1_fix == 1) 2143 if (ehci->amd_pll_fix == 1)
2201 ehci_quirk_amd_L1(ehci, 0); 2144 usb_amd_quirk_pll_enable();
2202 } 2145 }
2203 2146
2204 if (list_is_singular(&stream->td_list)) { 2147 if (list_is_singular(&stream->td_list)) {
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 799ac16a54b4..f86d3fa20214 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -131,7 +131,7 @@ struct ehci_hcd { /* one per controller */
131 unsigned has_amcc_usb23:1; 131 unsigned has_amcc_usb23:1;
132 unsigned need_io_watchdog:1; 132 unsigned need_io_watchdog:1;
133 unsigned broken_periodic:1; 133 unsigned broken_periodic:1;
134 unsigned amd_l1_fix:1; 134 unsigned amd_pll_fix:1;
135 unsigned fs_i_thresh:1; /* Intel iso scheduling */ 135 unsigned fs_i_thresh:1; /* Intel iso scheduling */
136 unsigned use_dummy_qh:1; /* AMD Frame List table quirk*/ 136 unsigned use_dummy_qh:1; /* AMD Frame List table quirk*/
137 137
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index 759a12ff8048..7b791bf1e7b4 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -75,6 +75,7 @@ static const char hcd_name [] = "ohci_hcd";
75#define STATECHANGE_DELAY msecs_to_jiffies(300) 75#define STATECHANGE_DELAY msecs_to_jiffies(300)
76 76
77#include "ohci.h" 77#include "ohci.h"
78#include "pci-quirks.h"
78 79
79static void ohci_dump (struct ohci_hcd *ohci, int verbose); 80static void ohci_dump (struct ohci_hcd *ohci, int verbose);
80static int ohci_init (struct ohci_hcd *ohci); 81static int ohci_init (struct ohci_hcd *ohci);
@@ -85,18 +86,8 @@ static int ohci_restart (struct ohci_hcd *ohci);
85#endif 86#endif
86 87
87#ifdef CONFIG_PCI 88#ifdef CONFIG_PCI
88static void quirk_amd_pll(int state);
89static void amd_iso_dev_put(void);
90static void sb800_prefetch(struct ohci_hcd *ohci, int on); 89static void sb800_prefetch(struct ohci_hcd *ohci, int on);
91#else 90#else
92static inline void quirk_amd_pll(int state)
93{
94 return;
95}
96static inline void amd_iso_dev_put(void)
97{
98 return;
99}
100static inline void sb800_prefetch(struct ohci_hcd *ohci, int on) 91static inline void sb800_prefetch(struct ohci_hcd *ohci, int on)
101{ 92{
102 return; 93 return;
@@ -912,7 +903,7 @@ static void ohci_stop (struct usb_hcd *hcd)
912 if (quirk_zfmicro(ohci)) 903 if (quirk_zfmicro(ohci))
913 del_timer(&ohci->unlink_watchdog); 904 del_timer(&ohci->unlink_watchdog);
914 if (quirk_amdiso(ohci)) 905 if (quirk_amdiso(ohci))
915 amd_iso_dev_put(); 906 usb_amd_dev_put();
916 907
917 remove_debug_files (ohci); 908 remove_debug_files (ohci);
918 ohci_mem_cleanup (ohci); 909 ohci_mem_cleanup (ohci);
diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c
index 36ee9a666e93..9816a2870d00 100644
--- a/drivers/usb/host/ohci-pci.c
+++ b/drivers/usb/host/ohci-pci.c
@@ -22,24 +22,6 @@
22#include <linux/io.h> 22#include <linux/io.h>
23 23
24 24
25/* constants used to work around PM-related transfer
26 * glitches in some AMD 700 series southbridges
27 */
28#define AB_REG_BAR 0xf0
29#define AB_INDX(addr) ((addr) + 0x00)
30#define AB_DATA(addr) ((addr) + 0x04)
31#define AX_INDXC 0X30
32#define AX_DATAC 0x34
33
34#define NB_PCIE_INDX_ADDR 0xe0
35#define NB_PCIE_INDX_DATA 0xe4
36#define PCIE_P_CNTL 0x10040
37#define BIF_NB 0x10002
38
39static struct pci_dev *amd_smbus_dev;
40static struct pci_dev *amd_hb_dev;
41static int amd_ohci_iso_count;
42
43/*-------------------------------------------------------------------------*/ 25/*-------------------------------------------------------------------------*/
44 26
45static int broken_suspend(struct usb_hcd *hcd) 27static int broken_suspend(struct usb_hcd *hcd)
@@ -168,11 +150,14 @@ static int ohci_quirk_nec(struct usb_hcd *hcd)
168static int ohci_quirk_amd700(struct usb_hcd *hcd) 150static int ohci_quirk_amd700(struct usb_hcd *hcd)
169{ 151{
170 struct ohci_hcd *ohci = hcd_to_ohci(hcd); 152 struct ohci_hcd *ohci = hcd_to_ohci(hcd);
153 struct pci_dev *amd_smbus_dev;
171 u8 rev = 0; 154 u8 rev = 0;
172 155
173 if (!amd_smbus_dev) 156 if (usb_amd_find_chipset_info())
174 amd_smbus_dev = pci_get_device(PCI_VENDOR_ID_ATI, 157 ohci->flags |= OHCI_QUIRK_AMD_PLL;
175 PCI_DEVICE_ID_ATI_SBX00_SMBUS, NULL); 158
159 amd_smbus_dev = pci_get_device(PCI_VENDOR_ID_ATI,
160 PCI_DEVICE_ID_ATI_SBX00_SMBUS, NULL);
176 if (!amd_smbus_dev) 161 if (!amd_smbus_dev)
177 return 0; 162 return 0;
178 163
@@ -184,19 +169,8 @@ static int ohci_quirk_amd700(struct usb_hcd *hcd)
184 ohci_dbg(ohci, "enabled AMD prefetch quirk\n"); 169 ohci_dbg(ohci, "enabled AMD prefetch quirk\n");
185 } 170 }
186 171
187 if ((rev > 0x3b) || (rev < 0x30)) { 172 pci_dev_put(amd_smbus_dev);
188 pci_dev_put(amd_smbus_dev); 173 amd_smbus_dev = NULL;
189 amd_smbus_dev = NULL;
190 return 0;
191 }
192
193 amd_ohci_iso_count++;
194
195 if (!amd_hb_dev)
196 amd_hb_dev = pci_get_device(PCI_VENDOR_ID_AMD, 0x9600, NULL);
197
198 ohci->flags |= OHCI_QUIRK_AMD_ISO;
199 ohci_dbg(ohci, "enabled AMD ISO transfers quirk\n");
200 174
201 return 0; 175 return 0;
202} 176}
@@ -215,74 +189,6 @@ static int ohci_quirk_nvidia_shutdown(struct usb_hcd *hcd)
215 return 0; 189 return 0;
216} 190}
217 191
218/*
219 * The hardware normally enables the A-link power management feature, which
220 * lets the system lower the power consumption in idle states.
221 *
222 * Assume the system is configured to have USB 1.1 ISO transfers going
223 * to or from a USB device. Without this quirk, that stream may stutter
224 * or have breaks occasionally. For transfers going to speakers, this
225 * makes a very audible mess...
226 *
227 * That audio playback corruption is due to the audio stream getting
228 * interrupted occasionally when the link goes in lower power state
229 * This USB quirk prevents the link going into that lower power state
230 * during audio playback or other ISO operations.
231 */
232static void quirk_amd_pll(int on)
233{
234 u32 addr;
235 u32 val;
236 u32 bit = (on > 0) ? 1 : 0;
237
238 pci_read_config_dword(amd_smbus_dev, AB_REG_BAR, &addr);
239
240 /* BIT names/meanings are NDA-protected, sorry ... */
241
242 outl(AX_INDXC, AB_INDX(addr));
243 outl(0x40, AB_DATA(addr));
244 outl(AX_DATAC, AB_INDX(addr));
245 val = inl(AB_DATA(addr));
246 val &= ~((1 << 3) | (1 << 4) | (1 << 9));
247 val |= (bit << 3) | ((!bit) << 4) | ((!bit) << 9);
248 outl(val, AB_DATA(addr));
249
250 if (amd_hb_dev) {
251 addr = PCIE_P_CNTL;
252 pci_write_config_dword(amd_hb_dev, NB_PCIE_INDX_ADDR, addr);
253
254 pci_read_config_dword(amd_hb_dev, NB_PCIE_INDX_DATA, &val);
255 val &= ~(1 | (1 << 3) | (1 << 4) | (1 << 9) | (1 << 12));
256 val |= bit | (bit << 3) | (bit << 12);
257 val |= ((!bit) << 4) | ((!bit) << 9);
258 pci_write_config_dword(amd_hb_dev, NB_PCIE_INDX_DATA, val);
259
260 addr = BIF_NB;
261 pci_write_config_dword(amd_hb_dev, NB_PCIE_INDX_ADDR, addr);
262
263 pci_read_config_dword(amd_hb_dev, NB_PCIE_INDX_DATA, &val);
264 val &= ~(1 << 8);
265 val |= bit << 8;
266 pci_write_config_dword(amd_hb_dev, NB_PCIE_INDX_DATA, val);
267 }
268}
269
270static void amd_iso_dev_put(void)
271{
272 amd_ohci_iso_count--;
273 if (amd_ohci_iso_count == 0) {
274 if (amd_smbus_dev) {
275 pci_dev_put(amd_smbus_dev);
276 amd_smbus_dev = NULL;
277 }
278 if (amd_hb_dev) {
279 pci_dev_put(amd_hb_dev);
280 amd_hb_dev = NULL;
281 }
282 }
283
284}
285
286static void sb800_prefetch(struct ohci_hcd *ohci, int on) 192static void sb800_prefetch(struct ohci_hcd *ohci, int on)
287{ 193{
288 struct pci_dev *pdev; 194 struct pci_dev *pdev;
diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c
index 83094d067e0f..dd24fc115e48 100644
--- a/drivers/usb/host/ohci-q.c
+++ b/drivers/usb/host/ohci-q.c
@@ -52,7 +52,7 @@ __acquires(ohci->lock)
52 ohci_to_hcd(ohci)->self.bandwidth_isoc_reqs--; 52 ohci_to_hcd(ohci)->self.bandwidth_isoc_reqs--;
53 if (ohci_to_hcd(ohci)->self.bandwidth_isoc_reqs == 0) { 53 if (ohci_to_hcd(ohci)->self.bandwidth_isoc_reqs == 0) {
54 if (quirk_amdiso(ohci)) 54 if (quirk_amdiso(ohci))
55 quirk_amd_pll(1); 55 usb_amd_quirk_pll_enable();
56 if (quirk_amdprefetch(ohci)) 56 if (quirk_amdprefetch(ohci))
57 sb800_prefetch(ohci, 0); 57 sb800_prefetch(ohci, 0);
58 } 58 }
@@ -686,7 +686,7 @@ static void td_submit_urb (
686 } 686 }
687 if (ohci_to_hcd(ohci)->self.bandwidth_isoc_reqs == 0) { 687 if (ohci_to_hcd(ohci)->self.bandwidth_isoc_reqs == 0) {
688 if (quirk_amdiso(ohci)) 688 if (quirk_amdiso(ohci))
689 quirk_amd_pll(0); 689 usb_amd_quirk_pll_disable();
690 if (quirk_amdprefetch(ohci)) 690 if (quirk_amdprefetch(ohci))
691 sb800_prefetch(ohci, 1); 691 sb800_prefetch(ohci, 1);
692 } 692 }
diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h
index 51facb985c84..bad11a72c202 100644
--- a/drivers/usb/host/ohci.h
+++ b/drivers/usb/host/ohci.h
@@ -401,7 +401,7 @@ struct ohci_hcd {
401#define OHCI_QUIRK_NEC 0x40 /* lost interrupts */ 401#define OHCI_QUIRK_NEC 0x40 /* lost interrupts */
402#define OHCI_QUIRK_FRAME_NO 0x80 /* no big endian frame_no shift */ 402#define OHCI_QUIRK_FRAME_NO 0x80 /* no big endian frame_no shift */
403#define OHCI_QUIRK_HUB_POWER 0x100 /* distrust firmware power/oc setup */ 403#define OHCI_QUIRK_HUB_POWER 0x100 /* distrust firmware power/oc setup */
404#define OHCI_QUIRK_AMD_ISO 0x200 /* ISO transfers*/ 404#define OHCI_QUIRK_AMD_PLL 0x200 /* AMD PLL quirk*/
405#define OHCI_QUIRK_AMD_PREFETCH 0x400 /* pre-fetch for ISO transfer */ 405#define OHCI_QUIRK_AMD_PREFETCH 0x400 /* pre-fetch for ISO transfer */
406#define OHCI_QUIRK_SHUTDOWN 0x800 /* nVidia power bug */ 406#define OHCI_QUIRK_SHUTDOWN 0x800 /* nVidia power bug */
407 // there are also chip quirks/bugs in init logic 407 // there are also chip quirks/bugs in init logic
@@ -433,7 +433,7 @@ static inline int quirk_zfmicro(struct ohci_hcd *ohci)
433} 433}
434static inline int quirk_amdiso(struct ohci_hcd *ohci) 434static inline int quirk_amdiso(struct ohci_hcd *ohci)
435{ 435{
436 return ohci->flags & OHCI_QUIRK_AMD_ISO; 436 return ohci->flags & OHCI_QUIRK_AMD_PLL;
437} 437}
438static inline int quirk_amdprefetch(struct ohci_hcd *ohci) 438static inline int quirk_amdprefetch(struct ohci_hcd *ohci)
439{ 439{
diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c
index 4c502c890ebd..1d586d4f7b56 100644
--- a/drivers/usb/host/pci-quirks.c
+++ b/drivers/usb/host/pci-quirks.c
@@ -52,6 +52,264 @@
52#define EHCI_USBLEGCTLSTS 4 /* legacy control/status */ 52#define EHCI_USBLEGCTLSTS 4 /* legacy control/status */
53#define EHCI_USBLEGCTLSTS_SOOE (1 << 13) /* SMI on ownership change */ 53#define EHCI_USBLEGCTLSTS_SOOE (1 << 13) /* SMI on ownership change */
54 54
55/* AMD quirk use */
56#define AB_REG_BAR_LOW 0xe0
57#define AB_REG_BAR_HIGH 0xe1
58#define AB_REG_BAR_SB700 0xf0
59#define AB_INDX(addr) ((addr) + 0x00)
60#define AB_DATA(addr) ((addr) + 0x04)
61#define AX_INDXC 0x30
62#define AX_DATAC 0x34
63
64#define NB_PCIE_INDX_ADDR 0xe0
65#define NB_PCIE_INDX_DATA 0xe4
66#define PCIE_P_CNTL 0x10040
67#define BIF_NB 0x10002
68#define NB_PIF0_PWRDOWN_0 0x01100012
69#define NB_PIF0_PWRDOWN_1 0x01100013
70
71static struct amd_chipset_info {
72 struct pci_dev *nb_dev;
73 struct pci_dev *smbus_dev;
74 int nb_type;
75 int sb_type;
76 int isoc_reqs;
77 int probe_count;
78 int probe_result;
79} amd_chipset;
80
81static DEFINE_SPINLOCK(amd_lock);
82
83int usb_amd_find_chipset_info(void)
84{
85 u8 rev = 0;
86 unsigned long flags;
87
88 spin_lock_irqsave(&amd_lock, flags);
89
90 amd_chipset.probe_count++;
91 /* probe only once */
92 if (amd_chipset.probe_count > 1) {
93 spin_unlock_irqrestore(&amd_lock, flags);
94 return amd_chipset.probe_result;
95 }
96
97 amd_chipset.smbus_dev = pci_get_device(PCI_VENDOR_ID_ATI, 0x4385, NULL);
98 if (amd_chipset.smbus_dev) {
99 rev = amd_chipset.smbus_dev->revision;
100 if (rev >= 0x40)
101 amd_chipset.sb_type = 1;
102 else if (rev >= 0x30 && rev <= 0x3b)
103 amd_chipset.sb_type = 3;
104 } else {
105 amd_chipset.smbus_dev = pci_get_device(PCI_VENDOR_ID_AMD,
106 0x780b, NULL);
107 if (!amd_chipset.smbus_dev) {
108 spin_unlock_irqrestore(&amd_lock, flags);
109 return 0;
110 }
111 rev = amd_chipset.smbus_dev->revision;
112 if (rev >= 0x11 && rev <= 0x18)
113 amd_chipset.sb_type = 2;
114 }
115
116 if (amd_chipset.sb_type == 0) {
117 if (amd_chipset.smbus_dev) {
118 pci_dev_put(amd_chipset.smbus_dev);
119 amd_chipset.smbus_dev = NULL;
120 }
121 spin_unlock_irqrestore(&amd_lock, flags);
122 return 0;
123 }
124
125 amd_chipset.nb_dev = pci_get_device(PCI_VENDOR_ID_AMD, 0x9601, NULL);
126 if (amd_chipset.nb_dev) {
127 amd_chipset.nb_type = 1;
128 } else {
129 amd_chipset.nb_dev = pci_get_device(PCI_VENDOR_ID_AMD,
130 0x1510, NULL);
131 if (amd_chipset.nb_dev) {
132 amd_chipset.nb_type = 2;
133 } else {
134 amd_chipset.nb_dev = pci_get_device(PCI_VENDOR_ID_AMD,
135 0x9600, NULL);
136 if (amd_chipset.nb_dev)
137 amd_chipset.nb_type = 3;
138 }
139 }
140
141 amd_chipset.probe_result = 1;
142 printk(KERN_DEBUG "QUIRK: Enable AMD PLL fix\n");
143
144 spin_unlock_irqrestore(&amd_lock, flags);
145 return amd_chipset.probe_result;
146}
147EXPORT_SYMBOL_GPL(usb_amd_find_chipset_info);
148
149/*
150 * The hardware normally enables the A-link power management feature, which
151 * lets the system lower the power consumption in idle states.
152 *
153 * This USB quirk prevents the link going into that lower power state
154 * during isochronous transfers.
155 *
156 * Without this quirk, isochronous stream on OHCI/EHCI/xHCI controllers of
157 * some AMD platforms may stutter or have breaks occasionally.
158 */
159static void usb_amd_quirk_pll(int disable)
160{
161 u32 addr, addr_low, addr_high, val;
162 u32 bit = disable ? 0 : 1;
163 unsigned long flags;
164
165 spin_lock_irqsave(&amd_lock, flags);
166
167 if (disable) {
168 amd_chipset.isoc_reqs++;
169 if (amd_chipset.isoc_reqs > 1) {
170 spin_unlock_irqrestore(&amd_lock, flags);
171 return;
172 }
173 } else {
174 amd_chipset.isoc_reqs--;
175 if (amd_chipset.isoc_reqs > 0) {
176 spin_unlock_irqrestore(&amd_lock, flags);
177 return;
178 }
179 }
180
181 if (amd_chipset.sb_type == 1 || amd_chipset.sb_type == 2) {
182 outb_p(AB_REG_BAR_LOW, 0xcd6);
183 addr_low = inb_p(0xcd7);
184 outb_p(AB_REG_BAR_HIGH, 0xcd6);
185 addr_high = inb_p(0xcd7);
186 addr = addr_high << 8 | addr_low;
187
188 outl_p(0x30, AB_INDX(addr));
189 outl_p(0x40, AB_DATA(addr));
190 outl_p(0x34, AB_INDX(addr));
191 val = inl_p(AB_DATA(addr));
192 } else if (amd_chipset.sb_type == 3) {
193 pci_read_config_dword(amd_chipset.smbus_dev,
194 AB_REG_BAR_SB700, &addr);
195 outl(AX_INDXC, AB_INDX(addr));
196 outl(0x40, AB_DATA(addr));
197 outl(AX_DATAC, AB_INDX(addr));
198 val = inl(AB_DATA(addr));
199 } else {
200 spin_unlock_irqrestore(&amd_lock, flags);
201 return;
202 }
203
204 if (disable) {
205 val &= ~0x08;
206 val |= (1 << 4) | (1 << 9);
207 } else {
208 val |= 0x08;
209 val &= ~((1 << 4) | (1 << 9));
210 }
211 outl_p(val, AB_DATA(addr));
212
213 if (!amd_chipset.nb_dev) {
214 spin_unlock_irqrestore(&amd_lock, flags);
215 return;
216 }
217
218 if (amd_chipset.nb_type == 1 || amd_chipset.nb_type == 3) {
219 addr = PCIE_P_CNTL;
220 pci_write_config_dword(amd_chipset.nb_dev,
221 NB_PCIE_INDX_ADDR, addr);
222 pci_read_config_dword(amd_chipset.nb_dev,
223 NB_PCIE_INDX_DATA, &val);
224
225 val &= ~(1 | (1 << 3) | (1 << 4) | (1 << 9) | (1 << 12));
226 val |= bit | (bit << 3) | (bit << 12);
227 val |= ((!bit) << 4) | ((!bit) << 9);
228 pci_write_config_dword(amd_chipset.nb_dev,
229 NB_PCIE_INDX_DATA, val);
230
231 addr = BIF_NB;
232 pci_write_config_dword(amd_chipset.nb_dev,
233 NB_PCIE_INDX_ADDR, addr);
234 pci_read_config_dword(amd_chipset.nb_dev,
235 NB_PCIE_INDX_DATA, &val);
236 val &= ~(1 << 8);
237 val |= bit << 8;
238
239 pci_write_config_dword(amd_chipset.nb_dev,
240 NB_PCIE_INDX_DATA, val);
241 } else if (amd_chipset.nb_type == 2) {
242 addr = NB_PIF0_PWRDOWN_0;
243 pci_write_config_dword(amd_chipset.nb_dev,
244 NB_PCIE_INDX_ADDR, addr);
245 pci_read_config_dword(amd_chipset.nb_dev,
246 NB_PCIE_INDX_DATA, &val);
247 if (disable)
248 val &= ~(0x3f << 7);
249 else
250 val |= 0x3f << 7;
251
252 pci_write_config_dword(amd_chipset.nb_dev,
253 NB_PCIE_INDX_DATA, val);
254
255 addr = NB_PIF0_PWRDOWN_1;
256 pci_write_config_dword(amd_chipset.nb_dev,
257 NB_PCIE_INDX_ADDR, addr);
258 pci_read_config_dword(amd_chipset.nb_dev,
259 NB_PCIE_INDX_DATA, &val);
260 if (disable)
261 val &= ~(0x3f << 7);
262 else
263 val |= 0x3f << 7;
264
265 pci_write_config_dword(amd_chipset.nb_dev,
266 NB_PCIE_INDX_DATA, val);
267 }
268
269 spin_unlock_irqrestore(&amd_lock, flags);
270 return;
271}
272
273void usb_amd_quirk_pll_disable(void)
274{
275 usb_amd_quirk_pll(1);
276}
277EXPORT_SYMBOL_GPL(usb_amd_quirk_pll_disable);
278
279void usb_amd_quirk_pll_enable(void)
280{
281 usb_amd_quirk_pll(0);
282}
283EXPORT_SYMBOL_GPL(usb_amd_quirk_pll_enable);
284
285void usb_amd_dev_put(void)
286{
287 unsigned long flags;
288
289 spin_lock_irqsave(&amd_lock, flags);
290
291 amd_chipset.probe_count--;
292 if (amd_chipset.probe_count > 0) {
293 spin_unlock_irqrestore(&amd_lock, flags);
294 return;
295 }
296
297 if (amd_chipset.nb_dev) {
298 pci_dev_put(amd_chipset.nb_dev);
299 amd_chipset.nb_dev = NULL;
300 }
301 if (amd_chipset.smbus_dev) {
302 pci_dev_put(amd_chipset.smbus_dev);
303 amd_chipset.smbus_dev = NULL;
304 }
305 amd_chipset.nb_type = 0;
306 amd_chipset.sb_type = 0;
307 amd_chipset.isoc_reqs = 0;
308 amd_chipset.probe_result = 0;
309
310 spin_unlock_irqrestore(&amd_lock, flags);
311}
312EXPORT_SYMBOL_GPL(usb_amd_dev_put);
55 313
56/* 314/*
57 * Make sure the controller is completely inactive, unable to 315 * Make sure the controller is completely inactive, unable to
diff --git a/drivers/usb/host/pci-quirks.h b/drivers/usb/host/pci-quirks.h
index 1564edfff6fe..6ae9f78e9938 100644
--- a/drivers/usb/host/pci-quirks.h
+++ b/drivers/usb/host/pci-quirks.h
@@ -1,7 +1,17 @@
1#ifndef __LINUX_USB_PCI_QUIRKS_H 1#ifndef __LINUX_USB_PCI_QUIRKS_H
2#define __LINUX_USB_PCI_QUIRKS_H 2#define __LINUX_USB_PCI_QUIRKS_H
3 3
4#ifdef CONFIG_PCI
4void uhci_reset_hc(struct pci_dev *pdev, unsigned long base); 5void uhci_reset_hc(struct pci_dev *pdev, unsigned long base);
5int uhci_check_and_reset_hc(struct pci_dev *pdev, unsigned long base); 6int uhci_check_and_reset_hc(struct pci_dev *pdev, unsigned long base);
7int usb_amd_find_chipset_info(void);
8void usb_amd_dev_put(void);
9void usb_amd_quirk_pll_disable(void);
10void usb_amd_quirk_pll_enable(void);
11#else
12static inline void usb_amd_quirk_pll_disable(void) {}
13static inline void usb_amd_quirk_pll_enable(void) {}
14static inline void usb_amd_dev_put(void) {}
15#endif /* CONFIG_PCI */
6 16
7#endif /* __LINUX_USB_PCI_QUIRKS_H */ 17#endif /* __LINUX_USB_PCI_QUIRKS_H */