aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorAndiry Xu <andiry.xu@amd.com>2011-01-25 05:41:21 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2011-02-04 14:42:52 -0500
commitb7d5b439b7a40dd0a0202fe1c118615a3fcc3b25 (patch)
tree8a9be25f550e4a9921733d5b0dae9c8fcdc274f6 /drivers
parenta51ea8cc9cfcfd719240455ff8f217b4f165d1d0 (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> Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/usb/host/ehci-hcd.c10
-rw-r--r--drivers/usb/host/ehci-pci.c38
-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.c260
-rw-r--r--drivers/usb/host/pci-quirks.h19
10 files changed, 311 insertions, 222 deletions
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 6fee3cd58efe..30515d362c4b 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 76179c39c0e3..1ec8060e8cc4 100644
--- a/drivers/usb/host/ehci-pci.c
+++ b/drivers/usb/host/ehci-pci.c
@@ -44,35 +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_SB800(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 return 0;
55
56 pci_read_config_byte(amd_smbus_dev, PCI_REVISION_ID, &rev);
57 if (rev < 0x40) {
58 pci_dev_put(amd_smbus_dev);
59 amd_smbus_dev = NULL;
60 return 0;
61 }
62
63 if (!amd_nb_dev)
64 amd_nb_dev = pci_get_device(PCI_VENDOR_ID_AMD, 0x1510, NULL);
65 if (!amd_nb_dev)
66 ehci_err(ehci, "QUIRK: unable to get AMD NB device\n");
67
68 ehci_info(ehci, "QUIRK: Enable AMD SB800 L1 fix\n");
69
70 pci_dev_put(amd_smbus_dev);
71 amd_smbus_dev = NULL;
72
73 return 1;
74}
75
76/* called during probe() after chip reset completes */ 47/* called during probe() after chip reset completes */
77static int ehci_pci_setup(struct usb_hcd *hcd) 48static int ehci_pci_setup(struct usb_hcd *hcd)
78{ 49{
@@ -131,9 +102,6 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
131 /* cache this readonly data; minimize chip reads */ 102 /* cache this readonly data; minimize chip reads */
132 ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); 103 ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
133 104
134 if (ehci_quirk_amd_SB800(ehci))
135 ehci->amd_l1_fix = 1;
136
137 retval = ehci_halt(ehci); 105 retval = ehci_halt(ehci);
138 if (retval) 106 if (retval)
139 return retval; 107 return retval;
@@ -184,6 +152,9 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
184 } 152 }
185 break; 153 break;
186 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;
187 /* AMD8111 EHCI doesn't work, according to AMD errata */ 158 /* AMD8111 EHCI doesn't work, according to AMD errata */
188 if (pdev->device == 0x7463) { 159 if (pdev->device == 0x7463) {
189 ehci_info(ehci, "ignoring AMD8111 (errata)\n"); 160 ehci_info(ehci, "ignoring AMD8111 (errata)\n");
@@ -229,6 +200,9 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
229 } 200 }
230 break; 201 break;
231 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;
232 /* 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,
233 * which causes usb devices lose response in some cases. 207 * which causes usb devices lose response in some cases.
234 */ 208 */
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index aa46f57f9ec8..b3bd1c6dc61f 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -1590,63 +1590,6 @@ itd_link (struct ehci_hcd *ehci, unsigned frame, struct ehci_itd *itd)
1590 *hw_p = cpu_to_hc32(ehci, itd->itd_dma | Q_TYPE_ITD); 1590 *hw_p = cpu_to_hc32(ehci, itd->itd_dma | Q_TYPE_ITD);
1591} 1591}
1592 1592
1593#define AB_REG_BAR_LOW 0xe0
1594#define AB_REG_BAR_HIGH 0xe1
1595#define AB_INDX(addr) ((addr) + 0x00)
1596#define AB_DATA(addr) ((addr) + 0x04)
1597#define NB_PCIE_INDX_ADDR 0xe0
1598#define NB_PCIE_INDX_DATA 0xe4
1599#define NB_PIF0_PWRDOWN_0 0x01100012
1600#define NB_PIF0_PWRDOWN_1 0x01100013
1601
1602static void ehci_quirk_amd_L1(struct ehci_hcd *ehci, int disable)
1603{
1604 u32 addr, addr_low, addr_high, val;
1605
1606 outb_p(AB_REG_BAR_LOW, 0xcd6);
1607 addr_low = inb_p(0xcd7);
1608 outb_p(AB_REG_BAR_HIGH, 0xcd6);
1609 addr_high = inb_p(0xcd7);
1610 addr = addr_high << 8 | addr_low;
1611 outl_p(0x30, AB_INDX(addr));
1612 outl_p(0x40, AB_DATA(addr));
1613 outl_p(0x34, AB_INDX(addr));
1614 val = inl_p(AB_DATA(addr));
1615
1616 if (disable) {
1617 val &= ~0x8;
1618 val |= (1 << 4) | (1 << 9);
1619 } else {
1620 val |= 0x8;
1621 val &= ~((1 << 4) | (1 << 9));
1622 }
1623 outl_p(val, AB_DATA(addr));
1624
1625 if (amd_nb_dev) {
1626 addr = NB_PIF0_PWRDOWN_0;
1627 pci_write_config_dword(amd_nb_dev, NB_PCIE_INDX_ADDR, addr);
1628 pci_read_config_dword(amd_nb_dev, NB_PCIE_INDX_DATA, &val);
1629 if (disable)
1630 val &= ~(0x3f << 7);
1631 else
1632 val |= 0x3f << 7;
1633
1634 pci_write_config_dword(amd_nb_dev, NB_PCIE_INDX_DATA, val);
1635
1636 addr = NB_PIF0_PWRDOWN_1;
1637 pci_write_config_dword(amd_nb_dev, NB_PCIE_INDX_ADDR, addr);
1638 pci_read_config_dword(amd_nb_dev, NB_PCIE_INDX_DATA, &val);
1639 if (disable)
1640 val &= ~(0x3f << 7);
1641 else
1642 val |= 0x3f << 7;
1643
1644 pci_write_config_dword(amd_nb_dev, NB_PCIE_INDX_DATA, val);
1645 }
1646
1647 return;
1648}
1649
1650/* fit urb's itds into the selected schedule slot; activate as needed */ 1593/* fit urb's itds into the selected schedule slot; activate as needed */
1651static int 1594static int
1652itd_link_urb ( 1595itd_link_urb (
@@ -1675,8 +1618,8 @@ itd_link_urb (
1675 } 1618 }
1676 1619
1677 if (ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs == 0) { 1620 if (ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs == 0) {
1678 if (ehci->amd_l1_fix == 1) 1621 if (ehci->amd_pll_fix == 1)
1679 ehci_quirk_amd_L1(ehci, 1); 1622 usb_amd_quirk_pll_disable();
1680 } 1623 }
1681 1624
1682 ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs++; 1625 ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs++;
@@ -1804,8 +1747,8 @@ itd_complete (
1804 ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs--; 1747 ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs--;
1805 1748
1806 if (ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs == 0) { 1749 if (ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs == 0) {
1807 if (ehci->amd_l1_fix == 1) 1750 if (ehci->amd_pll_fix == 1)
1808 ehci_quirk_amd_L1(ehci, 0); 1751 usb_amd_quirk_pll_enable();
1809 } 1752 }
1810 1753
1811 if (unlikely(list_is_singular(&stream->td_list))) { 1754 if (unlikely(list_is_singular(&stream->td_list))) {
@@ -2095,8 +2038,8 @@ sitd_link_urb (
2095 } 2038 }
2096 2039
2097 if (ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs == 0) { 2040 if (ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs == 0) {
2098 if (ehci->amd_l1_fix == 1) 2041 if (ehci->amd_pll_fix == 1)
2099 ehci_quirk_amd_L1(ehci, 1); 2042 usb_amd_quirk_pll_disable();
2100 } 2043 }
2101 2044
2102 ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs++; 2045 ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs++;
@@ -2200,8 +2143,8 @@ sitd_complete (
2200 ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs--; 2143 ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs--;
2201 2144
2202 if (ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs == 0) { 2145 if (ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs == 0) {
2203 if (ehci->amd_l1_fix == 1) 2146 if (ehci->amd_pll_fix == 1)
2204 ehci_quirk_amd_L1(ehci, 0); 2147 usb_amd_quirk_pll_enable();
2205 } 2148 }
2206 2149
2207 if (list_is_singular(&stream->td_list)) { 2150 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..344b25a790e1 100644
--- a/drivers/usb/host/pci-quirks.c
+++ b/drivers/usb/host/pci-quirks.c
@@ -52,6 +52,266 @@
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 pci_read_config_byte(amd_chipset.smbus_dev,
100 PCI_REVISION_ID, &rev);
101 if (rev >= 0x40)
102 amd_chipset.sb_type = 1;
103 else if (rev >= 0x30 && rev <= 0x3b)
104 amd_chipset.sb_type = 3;
105 } else {
106 amd_chipset.smbus_dev = pci_get_device(PCI_VENDOR_ID_AMD,
107 0x780b, NULL);
108 if (!amd_chipset.smbus_dev) {
109 spin_unlock_irqrestore(&amd_lock, flags);
110 return 0;
111 }
112 pci_read_config_byte(amd_chipset.smbus_dev,
113 PCI_REVISION_ID, &rev);
114 if (rev >= 0x11 && rev <= 0x18)
115 amd_chipset.sb_type = 2;
116 }
117
118 if (amd_chipset.sb_type == 0) {
119 if (amd_chipset.smbus_dev) {
120 pci_dev_put(amd_chipset.smbus_dev);
121 amd_chipset.smbus_dev = NULL;
122 }
123 spin_unlock_irqrestore(&amd_lock, flags);
124 return 0;
125 }
126
127 amd_chipset.nb_dev = pci_get_device(PCI_VENDOR_ID_AMD, 0x9601, NULL);
128 if (amd_chipset.nb_dev) {
129 amd_chipset.nb_type = 1;
130 } else {
131 amd_chipset.nb_dev = pci_get_device(PCI_VENDOR_ID_AMD,
132 0x1510, NULL);
133 if (amd_chipset.nb_dev) {
134 amd_chipset.nb_type = 2;
135 } else {
136 amd_chipset.nb_dev = pci_get_device(PCI_VENDOR_ID_AMD,
137 0x9600, NULL);
138 if (amd_chipset.nb_dev)
139 amd_chipset.nb_type = 3;
140 }
141 }
142
143 amd_chipset.probe_result = 1;
144 printk(KERN_DEBUG "QUIRK: Enable AMD PLL fix\n");
145
146 spin_unlock_irqrestore(&amd_lock, flags);
147 return amd_chipset.probe_result;
148}
149EXPORT_SYMBOL_GPL(usb_amd_find_chipset_info);
150
151/*
152 * The hardware normally enables the A-link power management feature, which
153 * lets the system lower the power consumption in idle states.
154 *
155 * This USB quirk prevents the link going into that lower power state
156 * during isochronous transfers.
157 *
158 * Without this quirk, isochronous stream on OHCI/EHCI/xHCI controllers of
159 * some AMD platforms may stutter or have breaks occasionally.
160 */
161static void usb_amd_quirk_pll(int disable)
162{
163 u32 addr, addr_low, addr_high, val;
164 u32 bit = disable ? 0 : 1;
165 unsigned long flags;
166
167 spin_lock_irqsave(&amd_lock, flags);
168
169 if (disable) {
170 amd_chipset.isoc_reqs++;
171 if (amd_chipset.isoc_reqs > 1) {
172 spin_unlock_irqrestore(&amd_lock, flags);
173 return;
174 }
175 } else {
176 amd_chipset.isoc_reqs--;
177 if (amd_chipset.isoc_reqs > 0) {
178 spin_unlock_irqrestore(&amd_lock, flags);
179 return;
180 }
181 }
182
183 if (amd_chipset.sb_type == 1 || amd_chipset.sb_type == 2) {
184 outb_p(AB_REG_BAR_LOW, 0xcd6);
185 addr_low = inb_p(0xcd7);
186 outb_p(AB_REG_BAR_HIGH, 0xcd6);
187 addr_high = inb_p(0xcd7);
188 addr = addr_high << 8 | addr_low;
189
190 outl_p(0x30, AB_INDX(addr));
191 outl_p(0x40, AB_DATA(addr));
192 outl_p(0x34, AB_INDX(addr));
193 val = inl_p(AB_DATA(addr));
194 } else if (amd_chipset.sb_type == 3) {
195 pci_read_config_dword(amd_chipset.smbus_dev,
196 AB_REG_BAR_SB700, &addr);
197 outl(AX_INDXC, AB_INDX(addr));
198 outl(0x40, AB_DATA(addr));
199 outl(AX_DATAC, AB_INDX(addr));
200 val = inl(AB_DATA(addr));
201 } else {
202 spin_unlock_irqrestore(&amd_lock, flags);
203 return;
204 }
205
206 if (disable) {
207 val &= ~0x08;
208 val |= (1 << 4) | (1 << 9);
209 } else {
210 val |= 0x08;
211 val &= ~((1 << 4) | (1 << 9));
212 }
213 outl_p(val, AB_DATA(addr));
214
215 if (!amd_chipset.nb_dev) {
216 spin_unlock_irqrestore(&amd_lock, flags);
217 return;
218 }
219
220 if (amd_chipset.nb_type == 1 || amd_chipset.nb_type == 3) {
221 addr = PCIE_P_CNTL;
222 pci_write_config_dword(amd_chipset.nb_dev,
223 NB_PCIE_INDX_ADDR, addr);
224 pci_read_config_dword(amd_chipset.nb_dev,
225 NB_PCIE_INDX_DATA, &val);
226
227 val &= ~(1 | (1 << 3) | (1 << 4) | (1 << 9) | (1 << 12));
228 val |= bit | (bit << 3) | (bit << 12);
229 val |= ((!bit) << 4) | ((!bit) << 9);
230 pci_write_config_dword(amd_chipset.nb_dev,
231 NB_PCIE_INDX_DATA, val);
232
233 addr = BIF_NB;
234 pci_write_config_dword(amd_chipset.nb_dev,
235 NB_PCIE_INDX_ADDR, addr);
236 pci_read_config_dword(amd_chipset.nb_dev,
237 NB_PCIE_INDX_DATA, &val);
238 val &= ~(1 << 8);
239 val |= bit << 8;
240
241 pci_write_config_dword(amd_chipset.nb_dev,
242 NB_PCIE_INDX_DATA, val);
243 } else if (amd_chipset.nb_type == 2) {
244 addr = NB_PIF0_PWRDOWN_0;
245 pci_write_config_dword(amd_chipset.nb_dev,
246 NB_PCIE_INDX_ADDR, addr);
247 pci_read_config_dword(amd_chipset.nb_dev,
248 NB_PCIE_INDX_DATA, &val);
249 if (disable)
250 val &= ~(0x3f << 7);
251 else
252 val |= 0x3f << 7;
253
254 pci_write_config_dword(amd_chipset.nb_dev,
255 NB_PCIE_INDX_DATA, val);
256
257 addr = NB_PIF0_PWRDOWN_1;
258 pci_write_config_dword(amd_chipset.nb_dev,
259 NB_PCIE_INDX_ADDR, addr);
260 pci_read_config_dword(amd_chipset.nb_dev,
261 NB_PCIE_INDX_DATA, &val);
262 if (disable)
263 val &= ~(0x3f << 7);
264 else
265 val |= 0x3f << 7;
266
267 pci_write_config_dword(amd_chipset.nb_dev,
268 NB_PCIE_INDX_DATA, val);
269 }
270
271 spin_unlock_irqrestore(&amd_lock, flags);
272 return;
273}
274
275void usb_amd_quirk_pll_disable(void)
276{
277 usb_amd_quirk_pll(1);
278}
279EXPORT_SYMBOL_GPL(usb_amd_quirk_pll_disable);
280
281void usb_amd_quirk_pll_enable(void)
282{
283 usb_amd_quirk_pll(0);
284}
285EXPORT_SYMBOL_GPL(usb_amd_quirk_pll_enable);
286
287void usb_amd_dev_put(void)
288{
289 unsigned long flags;
290
291 spin_lock_irqsave(&amd_lock, flags);
292
293 amd_chipset.probe_count--;
294 if (amd_chipset.probe_count > 0) {
295 spin_unlock_irqrestore(&amd_lock, flags);
296 return;
297 }
298
299 if (amd_chipset.nb_dev) {
300 pci_dev_put(amd_chipset.nb_dev);
301 amd_chipset.nb_dev = NULL;
302 }
303 if (amd_chipset.smbus_dev) {
304 pci_dev_put(amd_chipset.smbus_dev);
305 amd_chipset.smbus_dev = NULL;
306 }
307 amd_chipset.nb_type = 0;
308 amd_chipset.sb_type = 0;
309 amd_chipset.isoc_reqs = 0;
310 amd_chipset.probe_result = 0;
311
312 spin_unlock_irqrestore(&amd_lock, flags);
313}
314EXPORT_SYMBOL_GPL(usb_amd_dev_put);
55 315
56/* 316/*
57 * Make sure the controller is completely inactive, unable to 317 * 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..4d2118cf1ff8 100644
--- a/drivers/usb/host/pci-quirks.h
+++ b/drivers/usb/host/pci-quirks.h
@@ -1,7 +1,26 @@
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)
13{
14 return;
15}
16static inline void usb_amd_quirk_pll_enable(void)
17{
18 return;
19}
20static inline void usb_amd_dev_put(void)
21{
22 return;
23}
24#endif /* CONFIG_PCI */
6 25
7#endif /* __LINUX_USB_PCI_QUIRKS_H */ 26#endif /* __LINUX_USB_PCI_QUIRKS_H */