diff options
author | Andiry Xu <andiry.xu@amd.com> | 2011-01-25 05:41:21 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2011-02-04 14:42:52 -0500 |
commit | b7d5b439b7a40dd0a0202fe1c118615a3fcc3b25 (patch) | |
tree | 8a9be25f550e4a9921733d5b0dae9c8fcdc274f6 /drivers/usb/host/ehci-sched.c | |
parent | a51ea8cc9cfcfd719240455ff8f217b4f165d1d0 (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/usb/host/ehci-sched.c')
-rw-r--r-- | drivers/usb/host/ehci-sched.c | 73 |
1 files changed, 8 insertions, 65 deletions
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 | |||
1602 | static 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 */ |
1651 | static int | 1594 | static int |
1652 | itd_link_urb ( | 1595 | itd_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)) { |