aboutsummaryrefslogtreecommitdiff
path: root/drivers/usb/host
diff options
context:
space:
mode:
authorDavid Woodhouse <David.Woodhouse@intel.com>2008-09-01 11:32:13 +0100
committerDavid Woodhouse <David.Woodhouse@intel.com>2008-09-01 11:32:13 +0100
commit9d7548d4ca3c52ecb58f098a32b0756cdf8f96ee (patch)
tree651f7058bbaa2d8b2855286380d614afcf505118 /drivers/usb/host
parent31db6e9ea1dbdcf66b8227b4f7035dee1b1dd8c0 (diff)
parentbef69ea0dcce574a425feb0a5aa4c63dd108b9a6 (diff)
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
Diffstat (limited to 'drivers/usb/host')
-rw-r--r--drivers/usb/host/ehci-orion.c2
-rw-r--r--drivers/usb/host/isp1760-hcd.c53
-rw-r--r--drivers/usb/host/isp1760-hcd.h5
-rw-r--r--drivers/usb/host/ohci-at91.c1
-rw-r--r--drivers/usb/host/ohci-au1xxx.c1
-rw-r--r--drivers/usb/host/ohci-ep93xx.c1
-rw-r--r--drivers/usb/host/ohci-hcd.c23
-rw-r--r--drivers/usb/host/ohci-hub.c64
-rw-r--r--drivers/usb/host/ohci-lh7a404.c1
-rw-r--r--drivers/usb/host/ohci-omap.c4
-rw-r--r--drivers/usb/host/ohci-pci.c133
-rw-r--r--drivers/usb/host/ohci-pnx4008.c1
-rw-r--r--drivers/usb/host/ohci-pnx8550.c1
-rw-r--r--drivers/usb/host/ohci-ppc-of.c1
-rw-r--r--drivers/usb/host/ohci-ppc-soc.c1
-rw-r--r--drivers/usb/host/ohci-ps3.c1
-rw-r--r--drivers/usb/host/ohci-pxa27x.c1
-rw-r--r--drivers/usb/host/ohci-q.c6
-rw-r--r--drivers/usb/host/ohci-s3c2410.c1
-rw-r--r--drivers/usb/host/ohci-sa1111.c1
-rw-r--r--drivers/usb/host/ohci-sh.c1
-rw-r--r--drivers/usb/host/ohci-sm501.c1
-rw-r--r--drivers/usb/host/ohci-ssb.c1
-rw-r--r--drivers/usb/host/ohci.h11
-rw-r--r--drivers/usb/host/r8a66597-hcd.c49
-rw-r--r--drivers/usb/host/u132-hcd.c11
26 files changed, 279 insertions, 97 deletions
diff --git a/drivers/usb/host/ehci-orion.c b/drivers/usb/host/ehci-orion.c
index 5fbdc14e63b..5416cf96900 100644
--- a/drivers/usb/host/ehci-orion.c
+++ b/drivers/usb/host/ehci-orion.c
@@ -12,7 +12,7 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/mbus.h>
-#include <asm/plat-orion/ehci-orion.h>
+#include <plat/ehci-orion.h>
#define rdl(off) __raw_readl(hcd->regs + (off))
#define wrl(off, val) __raw_writel((val), hcd->regs + (off))
diff --git a/drivers/usb/host/isp1760-hcd.c b/drivers/usb/host/isp1760-hcd.c
index c858f2adb92..8017f1cf78e 100644
--- a/drivers/usb/host/isp1760-hcd.c
+++ b/drivers/usb/host/isp1760-hcd.c
@@ -126,9 +126,8 @@ static void isp1760_writel(const unsigned int val, __u32 __iomem *regs)
* doesn't quite work because some people have to enforce 32-bit access
*/
static void priv_read_copy(struct isp1760_hcd *priv, u32 *src,
- __u32 __iomem *dst, u32 offset, u32 len)
+ __u32 __iomem *dst, u32 len)
{
- struct usb_hcd *hcd = priv_to_hcd(priv);
u32 val;
u8 *buff8;
@@ -136,11 +135,6 @@ static void priv_read_copy(struct isp1760_hcd *priv, u32 *src,
printk(KERN_ERR "ERROR: buffer: %p len: %d\n", src, len);
return;
}
- isp1760_writel(offset, hcd->regs + HC_MEMORY_REG);
- /* XXX
- * 90nsec delay, the spec says something how this could be avoided.
- */
- mdelay(1);
while (len >= 4) {
*src = __raw_readl(dst);
@@ -987,8 +981,20 @@ static void do_atl_int(struct usb_hcd *usb_hcd)
printk(KERN_ERR "qh is 0\n");
continue;
}
- priv_read_copy(priv, (u32 *)&ptd, usb_hcd->regs + atl_regs,
- atl_regs, sizeof(ptd));
+ isp1760_writel(atl_regs + ISP_BANK(0), usb_hcd->regs +
+ HC_MEMORY_REG);
+ isp1760_writel(payload + ISP_BANK(1), usb_hcd->regs +
+ HC_MEMORY_REG);
+ /*
+ * write bank1 address twice to ensure the 90ns delay (time
+ * between BANK0 write and the priv_read_copy() call is at
+ * least 3*t_WHWL + 2*t_w11 = 3*25ns + 2*17ns = 109ns)
+ */
+ isp1760_writel(payload + ISP_BANK(1), usb_hcd->regs +
+ HC_MEMORY_REG);
+
+ priv_read_copy(priv, (u32 *)&ptd, usb_hcd->regs + atl_regs +
+ ISP_BANK(0), sizeof(ptd));
dw1 = le32_to_cpu(ptd.dw1);
dw2 = le32_to_cpu(ptd.dw2);
@@ -1091,7 +1097,7 @@ static void do_atl_int(struct usb_hcd *usb_hcd)
case IN_PID:
priv_read_copy(priv,
priv->atl_ints[queue_entry].data_buffer,
- usb_hcd->regs + payload, payload,
+ usb_hcd->regs + payload + ISP_BANK(1),
length);
case OUT_PID:
@@ -1122,11 +1128,11 @@ static void do_atl_int(struct usb_hcd *usb_hcd)
} else if (usb_pipebulk(urb->pipe) && (length < qtd->length)) {
/* short BULK received */
- printk(KERN_ERR "short bulk, %d instead %zu\n", length,
- qtd->length);
if (urb->transfer_flags & URB_SHORT_NOT_OK) {
urb->status = -EREMOTEIO;
- printk(KERN_ERR "not okey\n");
+ isp1760_dbg(priv, "short bulk, %d instead %zu "
+ "with URB_SHORT_NOT_OK flag.\n",
+ length, qtd->length);
}
if (urb->status == -EINPROGRESS)
@@ -1206,8 +1212,20 @@ static void do_intl_int(struct usb_hcd *usb_hcd)
continue;
}
- priv_read_copy(priv, (u32 *)&ptd, usb_hcd->regs + int_regs,
- int_regs, sizeof(ptd));
+ isp1760_writel(int_regs + ISP_BANK(0), usb_hcd->regs +
+ HC_MEMORY_REG);
+ isp1760_writel(payload + ISP_BANK(1), usb_hcd->regs +
+ HC_MEMORY_REG);
+ /*
+ * write bank1 address twice to ensure the 90ns delay (time
+ * between BANK0 write and the priv_read_copy() call is at
+ * least 3*t_WHWL + 2*t_w11 = 3*25ns + 2*17ns = 92ns)
+ */
+ isp1760_writel(payload + ISP_BANK(1), usb_hcd->regs +
+ HC_MEMORY_REG);
+
+ priv_read_copy(priv, (u32 *)&ptd, usb_hcd->regs + int_regs +
+ ISP_BANK(0), sizeof(ptd));
dw1 = le32_to_cpu(ptd.dw1);
dw3 = le32_to_cpu(ptd.dw3);
check_int_err_status(le32_to_cpu(ptd.dw4));
@@ -1242,7 +1260,7 @@ static void do_intl_int(struct usb_hcd *usb_hcd)
case IN_PID:
priv_read_copy(priv,
priv->int_ints[queue_entry].data_buffer,
- usb_hcd->regs + payload , payload,
+ usb_hcd->regs + payload + ISP_BANK(1),
length);
case OUT_PID:
@@ -1615,8 +1633,7 @@ static int isp1760_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
return -EPIPE;
}
- isp1760_prepare_enqueue(priv, urb, &qtd_list, mem_flags, pe);
- return 0;
+ return isp1760_prepare_enqueue(priv, urb, &qtd_list, mem_flags, pe);
}
static int isp1760_urb_dequeue(struct usb_hcd *hcd, struct urb *urb,
diff --git a/drivers/usb/host/isp1760-hcd.h b/drivers/usb/host/isp1760-hcd.h
index 6473dd86993..4377277667d 100644
--- a/drivers/usb/host/isp1760-hcd.h
+++ b/drivers/usb/host/isp1760-hcd.h
@@ -54,6 +54,8 @@ void deinit_kmem_cache(void);
#define BUFFER_MAP 0x7
#define HC_MEMORY_REG 0x33c
+#define ISP_BANK(x) ((x) << 16)
+
#define HC_PORT1_CTRL 0x374
#define PORT1_POWER (3 << 3)
#define PORT1_INIT1 (1 << 7)
@@ -119,6 +121,9 @@ struct inter_packet_info {
typedef void (packet_enqueue)(struct usb_hcd *hcd, struct isp1760_qh *qh,
struct isp1760_qtd *qtd);
+#define isp1760_dbg(priv, fmt, args...) \
+ dev_dbg(priv_to_hcd(priv)->self.controller, fmt, ##args)
+
#define isp1760_info(priv, fmt, args...) \
dev_info(priv_to_hcd(priv)->self.controller, fmt, ##args)
diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
index 6db7a2889e6..4ed228a8994 100644
--- a/drivers/usb/host/ohci-at91.c
+++ b/drivers/usb/host/ohci-at91.c
@@ -260,7 +260,6 @@ static const struct hc_driver ohci_at91_hc_driver = {
*/
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
- .hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
diff --git a/drivers/usb/host/ohci-au1xxx.c b/drivers/usb/host/ohci-au1xxx.c
index c0948008fe3..2ac4e022a13 100644
--- a/drivers/usb/host/ohci-au1xxx.c
+++ b/drivers/usb/host/ohci-au1xxx.c
@@ -163,7 +163,6 @@ static const struct hc_driver ohci_au1xxx_hc_driver = {
*/
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
- .hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
diff --git a/drivers/usb/host/ohci-ep93xx.c b/drivers/usb/host/ohci-ep93xx.c
index cb0b506f825..fb3055f084b 100644
--- a/drivers/usb/host/ohci-ep93xx.c
+++ b/drivers/usb/host/ohci-ep93xx.c
@@ -134,7 +134,6 @@ static struct hc_driver ohci_ep93xx_hc_driver = {
.get_frame_number = ohci_get_frame,
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
- .hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index 26bc47941d0..89901962cbf 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -86,6 +86,21 @@ static void ohci_stop (struct usb_hcd *hcd);
static int ohci_restart (struct ohci_hcd *ohci);
#endif
+#ifdef CONFIG_PCI
+static void quirk_amd_pll(int state);
+static void amd_iso_dev_put(void);
+#else
+static inline void quirk_amd_pll(int state)
+{
+ return;
+}
+static inline void amd_iso_dev_put(void)
+{
+ return;
+}
+#endif
+
+
#include "ohci-hub.c"
#include "ohci-dbg.c"
#include "ohci-mem.c"
@@ -483,6 +498,9 @@ static int ohci_init (struct ohci_hcd *ohci)
int ret;
struct usb_hcd *hcd = ohci_to_hcd(ohci);
+ if (distrust_firmware)
+ ohci->flags |= OHCI_QUIRK_HUB_POWER;
+
disable (ohci);
ohci->regs = hcd->regs;
@@ -689,7 +707,8 @@ retry:
temp |= RH_A_NOCP;
temp &= ~(RH_A_POTPGT | RH_A_NPS);
ohci_writel (ohci, temp, &ohci->regs->roothub.a);
- } else if ((ohci->flags & OHCI_QUIRK_AMD756) || distrust_firmware) {
+ } else if ((ohci->flags & OHCI_QUIRK_AMD756) ||
+ (ohci->flags & OHCI_QUIRK_HUB_POWER)) {
/* hub power always on; required for AMD-756 and some
* Mac platforms. ganged overcurrent reporting, if any.
*/
@@ -882,6 +901,8 @@ static void ohci_stop (struct usb_hcd *hcd)
if (quirk_zfmicro(ohci))
del_timer(&ohci->unlink_watchdog);
+ if (quirk_amdiso(ohci))
+ amd_iso_dev_put();
remove_debug_files (ohci);
ohci_mem_cleanup (ohci);
diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c
index b56739221d1..7ea9a7b3115 100644
--- a/drivers/usb/host/ohci-hub.c
+++ b/drivers/usb/host/ohci-hub.c
@@ -36,18 +36,6 @@
/*-------------------------------------------------------------------------*/
-/* hcd->hub_irq_enable() */
-static void ohci_rhsc_enable (struct usb_hcd *hcd)
-{
- struct ohci_hcd *ohci = hcd_to_ohci (hcd);
-
- spin_lock_irq(&ohci->lock);
- if (!ohci->autostop)
- del_timer(&hcd->rh_timer); /* Prevent next poll */
- ohci_writel(ohci, OHCI_INTR_RHSC, &ohci->regs->intrenable);
- spin_unlock_irq(&ohci->lock);
-}
-
#define OHCI_SCHED_ENABLES \
(OHCI_CTRL_CLE|OHCI_CTRL_BLE|OHCI_CTRL_PLE|OHCI_CTRL_IE)
@@ -374,18 +362,28 @@ static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed,
int any_connected)
{
int poll_rh = 1;
+ int rhsc;
+ rhsc = ohci_readl(ohci, &ohci->regs->intrenable) & OHCI_INTR_RHSC;
switch (ohci->hc_control & OHCI_CTRL_HCFS) {
case OHCI_USB_OPER:
- /* keep on polling until we know a device is connected
- * and RHSC is enabled */
+ /* If no status changes are pending, enable status-change
+ * interrupts.
+ */
+ if (!rhsc && !changed) {
+ rhsc = OHCI_INTR_RHSC;
+ ohci_writel(ohci, rhsc, &ohci->regs->intrenable);
+ }
+
+ /* Keep on polling until we know a device is connected
+ * and RHSC is enabled, or until we autostop.
+ */
if (!ohci->autostop) {
if (any_connected ||
!device_may_wakeup(&ohci_to_hcd(ohci)
->self.root_hub->dev)) {
- if (ohci_readl(ohci, &ohci->regs->intrenable) &
- OHCI_INTR_RHSC)
+ if (rhsc)
poll_rh = 0;
} else {
ohci->autostop = 1;
@@ -398,12 +396,13 @@ static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed,
ohci->autostop = 0;
ohci->next_statechange = jiffies +
STATECHANGE_DELAY;
- } else if (time_after_eq(jiffies,
+ } else if (rhsc && time_after_eq(jiffies,
ohci->next_statechange)
&& !ohci->ed_rm_list
&& !(ohci->hc_control &
OHCI_SCHED_ENABLES)) {
ohci_rh_suspend(ohci, 1);
+ poll_rh = 0;
}
}
break;
@@ -417,6 +416,12 @@ static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed,
else
usb_hcd_resume_root_hub(ohci_to_hcd(ohci));
} else {
+ if (!rhsc && (ohci->autostop ||
+ ohci_to_hcd(ohci)->self.root_hub->
+ do_remote_wakeup))
+ ohci_writel(ohci, OHCI_INTR_RHSC,
+ &ohci->regs->intrenable);
+
/* everything is idle, no need for polling */
poll_rh = 0;
}
@@ -438,12 +443,16 @@ static inline int ohci_rh_resume(struct ohci_hcd *ohci)
static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed,
int any_connected)
{
- int poll_rh = 1;
-
- /* keep on polling until RHSC is enabled */
+ /* If RHSC is enabled, don't poll */
if (ohci_readl(ohci, &ohci->regs->intrenable) & OHCI_INTR_RHSC)
- poll_rh = 0;
- return poll_rh;
+ return 0;
+
+ /* If no status changes are pending, enable status-change interrupts */
+ if (!changed) {
+ ohci_writel(ohci, OHCI_INTR_RHSC, &ohci->regs->intrenable);
+ return 0;
+ }
+ return 1;
}
#endif /* CONFIG_PM */
@@ -483,6 +492,13 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
length++;
}
+ /* Some broken controllers never turn off RHCS in the interrupt
+ * status register. For their sake we won't re-enable RHSC
+ * interrupts if the flag is already set.
+ */
+ if (ohci_readl(ohci, &ohci->regs->intrstatus) & OHCI_INTR_RHSC)
+ changed = 1;
+
/* look at each port */
for (i = 0; i < ohci->num_ports; i++) {
u32 status = roothub_portstatus (ohci, i);
@@ -572,8 +588,6 @@ static int ohci_start_port_reset (struct usb_hcd *hcd, unsigned port)
return 0;
}
-static void start_hnp(struct ohci_hcd *ohci);
-
#else
#define ohci_start_port_reset NULL
@@ -760,7 +774,7 @@ static int ohci_hub_control (
#ifdef CONFIG_USB_OTG
if (hcd->self.otg_port == (wIndex + 1)
&& hcd->self.b_hnp_enable)
- start_hnp(ohci);
+ ohci->start_hnp(ohci);
else
#endif
ohci_writel (ohci, RH_PS_PSS,
diff --git a/drivers/usb/host/ohci-lh7a404.c b/drivers/usb/host/ohci-lh7a404.c
index 9e31d440d11..de42283149c 100644
--- a/drivers/usb/host/ohci-lh7a404.c
+++ b/drivers/usb/host/ohci-lh7a404.c
@@ -193,7 +193,6 @@ static const struct hc_driver ohci_lh7a404_hc_driver = {
*/
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
- .hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c
index 94dfca02f7e..1eb64d08b60 100644
--- a/drivers/usb/host/ohci-omap.c
+++ b/drivers/usb/host/ohci-omap.c
@@ -225,6 +225,7 @@ static int ohci_omap_init(struct usb_hcd *hcd)
dev_err(hcd->self.controller, "can't find transceiver\n");
return -ENODEV;
}
+ ohci->start_hnp = start_hnp;
}
#endif
@@ -260,7 +261,7 @@ static int ohci_omap_init(struct usb_hcd *hcd)
omap_cfg_reg(W4_USB_HIGHZ);
}
ohci_writel(ohci, rh, &ohci->regs->roothub.a);
- distrust_firmware = 0;
+ ohci->flags &= ~OHCI_QUIRK_HUB_POWER;
} else if (machine_is_nokia770()) {
/* We require a self-powered hub, which should have
* plenty of power. */
@@ -469,7 +470,6 @@ static const struct hc_driver ohci_omap_hc_driver = {
*/
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
- .hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c
index 4696cc912e1..a9c2ae36c7a 100644
--- a/drivers/usb/host/ohci-pci.c
+++ b/drivers/usb/host/ohci-pci.c
@@ -18,6 +18,28 @@
#error "This file is PCI bus glue. CONFIG_PCI must be defined."
#endif
+#include <linux/pci.h>
+#include <linux/io.h>
+
+
+/* constants used to work around PM-related transfer
+ * glitches in some AMD 700 series southbridges
+ */
+#define AB_REG_BAR 0xf0
+#define AB_INDX(addr) ((addr) + 0x00)
+#define AB_DATA(addr) ((addr) + 0x04)
+#define AX_INDXC 0X30
+#define AX_DATAC 0x34
+
+#define NB_PCIE_INDX_ADDR 0xe0
+#define NB_PCIE_INDX_DATA 0xe4
+#define PCIE_P_CNTL 0x10040
+#define BIF_NB 0x10002
+
+static struct pci_dev *amd_smbus_dev;
+static struct pci_dev *amd_hb_dev;
+static int amd_ohci_iso_count;
+
/*-------------------------------------------------------------------------*/
static int broken_suspend(struct usb_hcd *hcd)
@@ -143,6 +165,103 @@ static int ohci_quirk_nec(struct usb_hcd *hcd)
return 0;
}
+static int ohci_quirk_amd700(struct usb_hcd *hcd)
+{
+ struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+ u8 rev = 0;
+
+ if (!amd_smbus_dev)
+ amd_smbus_dev = pci_get_device(PCI_VENDOR_ID_ATI,
+ PCI_DEVICE_ID_ATI_SBX00_SMBUS, NULL);
+ if (!amd_smbus_dev)
+ return 0;
+
+ pci_read_config_byte(amd_smbus_dev, PCI_REVISION_ID, &rev);
+ if ((rev > 0x3b) || (rev < 0x30)) {
+ pci_dev_put(amd_smbus_dev);
+ amd_smbus_dev = NULL;
+ return 0;
+ }
+
+ amd_ohci_iso_count++;
+
+ if (!amd_hb_dev)
+ amd_hb_dev = pci_get_device(PCI_VENDOR_ID_AMD, 0x9600, NULL);
+
+ ohci->flags |= OHCI_QUIRK_AMD_ISO;
+ ohci_dbg(ohci, "enabled AMD ISO transfers quirk\n");
+
+ return 0;
+}
+
+/*
+ * The hardware normally enables the A-link power management feature, which
+ * lets the system lower the power consumption in idle states.
+ *
+ * Assume the system is configured to have USB 1.1 ISO transfers going
+ * to or from a USB device. Without this quirk, that stream may stutter
+ * or have breaks occasionally. For transfers going to speakers, this
+ * makes a very audible mess...
+ *
+ * That audio playback corruption is due to the audio stream getting
+ * interrupted occasionally when the link goes in lower power state
+ * This USB quirk prevents the link going into that lower power state
+ * during audio playback or other ISO operations.
+ */
+static void quirk_amd_pll(int on)
+{
+ u32 addr;
+ u32 val;
+ u32 bit = (on > 0) ? 1 : 0;
+
+ pci_read_config_dword(amd_smbus_dev, AB_REG_BAR, &addr);
+
+ /* BIT names/meanings are NDA-protected, sorry ... */
+
+ outl(AX_INDXC, AB_INDX(addr));
+ outl(0x40, AB_DATA(addr));
+ outl(AX_DATAC, AB_INDX(addr));
+ val = inl(AB_DATA(addr));
+ val &= ~((1 << 3) | (1 << 4) | (1 << 9));
+ val |= (bit << 3) | ((!bit) << 4) | ((!bit) << 9);
+ outl(val, AB_DATA(addr));
+
+ if (amd_hb_dev) {
+ addr = PCIE_P_CNTL;
+ pci_write_config_dword(amd_hb_dev, NB_PCIE_INDX_ADDR, addr);
+
+ pci_read_config_dword(amd_hb_dev, NB_PCIE_INDX_DATA, &val);
+ val &= ~(1 | (1 << 3) | (1 << 4) | (1 << 9) | (1 << 12));
+ val |= bit | (bit << 3) | (bit << 12);
+ val |= ((!bit) << 4) | ((!bit) << 9);
+ pci_write_config_dword(amd_hb_dev, NB_PCIE_INDX_DATA, val);
+
+ addr = BIF_NB;
+ pci_write_config_dword(amd_hb_dev, NB_PCIE_INDX_ADDR, addr);
+
+ pci_read_config_dword(amd_hb_dev, NB_PCIE_INDX_DATA, &val);
+ val &= ~(1 << 8);
+ val |= bit << 8;
+ pci_write_config_dword(amd_hb_dev, NB_PCIE_INDX_DATA, val);
+ }
+}
+
+static void amd_iso_dev_put(void)
+{
+ amd_ohci_iso_count--;
+ if (amd_ohci_iso_count == 0) {
+ if (amd_smbus_dev) {
+ pci_dev_put(amd_smbus_dev);
+ amd_smbus_dev = NULL;
+ }
+ if (amd_hb_dev) {
+ pci_dev_put(amd_hb_dev);
+ amd_hb_dev = NULL;
+ }
+ }
+
+}
+
/* List of quirks for OHCI */
static const struct pci_device_id ohci_pci_quirks[] = {
{
@@ -181,6 +300,19 @@ static const struct pci_device_id ohci_pci_quirks[] = {
PCI_DEVICE(PCI_VENDOR_ID_ITE, 0x8152),
.driver_data = (unsigned long) broken_suspend,
},
+ {
+ PCI_DEVICE(PCI_VENDOR_ID_ATI, 0x4397),
+ .driver_data = (unsigned long)ohci_quirk_amd700,
+ },
+ {
+ PCI_DEVICE(PCI_VENDOR_ID_ATI, 0x4398),
+ .driver_data = (unsigned long)ohci_quirk_amd700,
+ },
+ {
+ PCI_DEVICE(PCI_VENDOR_ID_ATI, 0x4399),
+ .driver_data = (unsigned long)ohci_quirk_amd700,
+ },
+
/* FIXME for some of the early AMD 760 southbridges, OHCI
* won't work at all. blacklist them.
*/
@@ -327,7 +459,6 @@ static const struct hc_driver ohci_pci_hc_driver = {
*/
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
- .hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
diff --git a/drivers/usb/host/ohci-pnx4008.c b/drivers/usb/host/ohci-pnx4008.c
index b02cd076197..658a2a978c3 100644
--- a/drivers/usb/host/ohci-pnx4008.c
+++ b/drivers/usb/host/ohci-pnx4008.c
@@ -277,7 +277,6 @@ static const struct hc_driver ohci_pnx4008_hc_driver = {
*/
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
- .hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
diff --git a/drivers/usb/host/ohci-pnx8550.c b/drivers/usb/host/ohci-pnx8550.c
index 605d59cba28..28467e288a9 100644
--- a/drivers/usb/host/ohci-pnx8550.c
+++ b/drivers/usb/host/ohci-pnx8550.c
@@ -201,7 +201,6 @@ static const struct hc_driver ohci_pnx8550_hc_driver = {
*/
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
- .hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
diff --git a/drivers/usb/host/ohci-ppc-of.c b/drivers/usb/host/ohci-ppc-of.c
index 91e6e101a4c..7ac53264ead 100644
--- a/drivers/usb/host/ohci-ppc-of.c
+++ b/drivers/usb/host/ohci-ppc-of.c
@@ -72,7 +72,6 @@ static const struct hc_driver ohci_ppc_of_hc_driver = {
*/
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
- .hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
diff --git a/drivers/usb/host/ohci-ppc-soc.c b/drivers/usb/host/ohci-ppc-soc.c
index 523c3012557..cd3398b675b 100644
--- a/drivers/usb/host/ohci-ppc-soc.c
+++ b/drivers/usb/host/ohci-ppc-soc.c
@@ -172,7 +172,6 @@ static const struct hc_driver ohci_ppc_soc_hc_driver = {
*/
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
- .hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
diff --git a/drivers/usb/host/ohci-ps3.c b/drivers/usb/host/ohci-ps3.c
index 55c95647f00..2089d8a46c4 100644
--- a/drivers/usb/host/ohci-ps3.c
+++ b/drivers/usb/host/ohci-ps3.c
@@ -68,7 +68,6 @@ static const struct hc_driver ps3_ohci_hc_driver = {
.get_frame_number = ohci_get_frame,
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
- .hub_irq_enable = ohci_rhsc_enable,
.start_port_reset = ohci_start_port_reset,
#if defined(CONFIG_PM)
.bus_suspend = ohci_bus_suspend,
diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c
index 8c9c4849db6..7f0f35c7818 100644
--- a/drivers/usb/host/ohci-pxa27x.c
+++ b/drivers/usb/host/ohci-pxa27x.c
@@ -298,7 +298,6 @@ static const struct hc_driver ohci_pxa27x_hc_driver = {
*/
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
- .hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c
index 6a9b4c55795..c2d80f80448 100644
--- a/drivers/usb/host/ohci-q.c
+++ b/drivers/usb/host/ohci-q.c
@@ -49,6 +49,9 @@ __acquires(ohci->lock)
switch (usb_pipetype (urb->pipe)) {
case PIPE_ISOCHRONOUS:
ohci_to_hcd(ohci)->self.bandwidth_isoc_reqs--;
+ if (ohci_to_hcd(ohci)->self.bandwidth_isoc_reqs == 0
+ && quirk_amdiso(ohci))
+ quirk_amd_pll(1);
break;
case PIPE_INTERRUPT:
ohci_to_hcd(ohci)->self.bandwidth_int_reqs--;
@@ -677,6 +680,9 @@ static void td_submit_urb (
data + urb->iso_frame_desc [cnt].offset,
urb->iso_frame_desc [cnt].length, urb, cnt);
}
+ if (ohci_to_hcd(ohci)->self.bandwidth_isoc_reqs == 0
+ && quirk_amdiso(ohci))
+ quirk_amd_pll(0);
periodic = ohci_to_hcd(ohci)->self.bandwidth_isoc_reqs++ == 0
&& ohci_to_hcd(ohci)->self.bandwidth_int_reqs == 0;
break;
diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c
index 9e3dc4069e8..f46af7a718d 100644
--- a/drivers/usb/host/ohci-s3c2410.c
+++ b/drivers/usb/host/ohci-s3c2410.c
@@ -466,7 +466,6 @@ static const struct hc_driver ohci_s3c2410_hc_driver = {
*/
.hub_status_data = ohci_s3c2410_hub_status_data,
.hub_control = ohci_s3c2410_hub_control,
- .hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
diff --git a/drivers/usb/host/ohci-sa1111.c b/drivers/usb/host/ohci-sa1111.c
index 4626b002e67..e4bbe8e188e 100644
--- a/drivers/usb/host/ohci-sa1111.c
+++ b/drivers/usb/host/ohci-sa1111.c
@@ -231,7 +231,6 @@ static const struct hc_driver ohci_sa1111_hc_driver = {
*/
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
- .hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
diff --git a/drivers/usb/host/ohci-sh.c b/drivers/usb/host/ohci-sh.c
index e7ee607278f..60f03cc7ec4 100644
--- a/drivers/usb/host/ohci-sh.c
+++ b/drivers/usb/host/ohci-sh.c
@@ -68,7 +68,6 @@ static const struct hc_driver ohci_sh_hc_driver = {
*/
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
- .hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
diff --git a/drivers/usb/host/ohci-sm501.c b/drivers/usb/host/ohci-sm501.c
index 21b164e4abe..cff23637cfc 100644
--- a/drivers/usb/host/ohci-sm501.c
+++ b/drivers/usb/host/ohci-sm501.c
@@ -75,7 +75,6 @@ static const struct hc_driver ohci_sm501_hc_driver = {
*/
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
- .hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
diff --git a/drivers/usb/host/ohci-ssb.c b/drivers/usb/host/ohci-ssb.c
index 3660c83d80a..23fd6a886bd 100644
--- a/drivers/usb/host/ohci-ssb.c
+++ b/drivers/usb/host/ohci-ssb.c
@@ -81,7 +81,6 @@ static const struct hc_driver ssb_ohci_hc_driver = {
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
- .hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h
index dc544ddc784..faf622eafce 100644
--- a/drivers/usb/host/ohci.h
+++ b/drivers/usb/host/ohci.h
@@ -371,6 +371,7 @@ struct ohci_hcd {
* other external transceivers should be software-transparent
*/
struct otg_transceiver *transceiver;
+ void (*start_hnp)(struct ohci_hcd *ohci);
/*
* memory management for queue data structures
@@ -399,6 +400,8 @@ struct ohci_hcd {
#define OHCI_QUIRK_ZFMICRO 0x20 /* Compaq ZFMicro chipset*/
#define OHCI_QUIRK_NEC 0x40 /* lost interrupts */
#define OHCI_QUIRK_FRAME_NO 0x80 /* no big endian frame_no shift */
+#define OHCI_QUIRK_HUB_POWER 0x100 /* distrust firmware power/oc setup */
+#define OHCI_QUIRK_AMD_ISO 0x200 /* ISO transfers*/
// there are also chip quirks/bugs in init logic
struct work_struct nec_work; /* Worker for NEC quirk */
@@ -426,6 +429,10 @@ static inline int quirk_zfmicro(struct ohci_hcd *ohci)
{
return ohci->flags & OHCI_QUIRK_ZFMICRO;
}
+static inline int quirk_amdiso(struct ohci_hcd *ohci)
+{
+ return ohci->flags & OHCI_QUIRK_AMD_ISO;
+}
#else
static inline int quirk_nec(struct ohci_hcd *ohci)
{
@@ -435,6 +442,10 @@ static inline int quirk_zfmicro(struct ohci_hcd *ohci)
{
return 0;
}
+static inline int quirk_amdiso(struct ohci_hcd *ohci)
+{
+ return 0;
+}
#endif
/* convert between an hcd pointer and the corresponding ohci_hcd */
diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c
index d5f02dddb12..ea7126f99ca 100644
--- a/drivers/usb/host/r8a66597-hcd.c
+++ b/drivers/usb/host/r8a66597-hcd.c
@@ -964,11 +964,34 @@ static void pipe_irq_disable(struct r8a66597 *r8a66597, u16 pipenum)
disable_irq_nrdy(r8a66597, pipenum);
}
+static void r8a66597_root_hub_start_polling(struct r8a66597 *r8a66597)
+{
+ mod_timer(&r8a66597->rh_timer,
+ jiffies + msecs_to_jiffies(R8A66597_RH_POLL_TIME));
+}
+
+static void start_root_hub_sampling(struct r8a66597 *r8a66597, int port,
+ int connect)
+{
+ struct r8a66597_root_hub *rh = &r8a66597->root_hub[port];
+
+ rh->old_syssts = r8a66597_read(r8a66597, get_syssts_reg(port)) & LNST;
+ rh->scount = R8A66597_MAX_SAMPLING;
+ if (connect)
+ rh->port |= 1 << USB_PORT_FEAT_CONNECTION;
+ else
+ rh->port &= ~(1 << USB_PORT_FEAT_CONNECTION);
+ rh->port |= 1 << USB_PORT_FEAT_C_CONNECTION;
+
+ r8a66597_root_hub_start_polling(r8a66597);
+}
+
/* this function must be called with interrupt disabled */
static void r8a66597_check_syssts(struct r8a66597 *r8a66597, int port,
u16 syssts)
{
if (syssts == SE0) {
+ r8a66597_write(r8a66597, ~ATTCH, get_intsts_reg(port));
r8a66597_bset(r8a66597, ATTCHE, get_intenb_reg(port));
return;
}
@@ -1002,13 +1025,10 @@ static void r8a66597_usb_disconnect(struct r8a66597 *r8a66597, int port)
{
struct r8a66597_device *dev = r8a66597->root_hub[port].dev;
- r8a66597->root_hub[port].port &= ~(1 << USB_PORT_FEAT_CONNECTION);
- r8a66597->root_hub[port].port |= (1 << USB_PORT_FEAT_C_CONNECTION);
-
disable_r8a66597_pipe_all(r8a66597, dev);
free_usb_address(r8a66597, dev);
- r8a66597_bset(r8a66597, ATTCHE, get_intenb_reg(port));
+ start_root_hub_sampling(r8a66597, port, 0);
}
/* this function must be called with interrupt disabled */
@@ -1551,23 +1571,6 @@ static void irq_pipe_nrdy(struct r8a66597 *r8a66597)
}
}
-static void r8a66597_root_hub_start_polling(struct r8a66597 *r8a66597)
-{
- mod_timer(&r8a66597->rh_timer,
- jiffies + msecs_to_jiffies(R8A66597_RH_POLL_TIME));
-}
-
-static void start_root_hub_sampling(struct r8a66597 *r8a66597, int port)
-{
- struct r8a66597_root_hub *rh = &r8a66597->root_hub[port];
-
- rh->old_syssts = r8a66597_read(r8a66597, get_syssts_reg(port)) & LNST;
- rh->scount = R8A66597_MAX_SAMPLING;
- r8a66597->root_hub[port].port |= (1 << USB_PORT_FEAT_CONNECTION)
- | (1 << USB_PORT_FEAT_C_CONNECTION);
- r8a66597_root_hub_start_polling(r8a66597);
-}
-
static irqreturn_t r8a66597_irq(struct usb_hcd *hcd)
{
struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd);
@@ -1594,7 +1597,7 @@ static irqreturn_t r8a66597_irq(struct usb_hcd *hcd)
r8a66597_bclr(r8a66597, ATTCHE, INTENB2);
/* start usb bus sampling */
- start_root_hub_sampling(r8a66597, 1);
+ start_root_hub_sampling(r8a66597, 1, 1);
}
if (mask2 & DTCH) {
r8a66597_write(r8a66597, ~DTCH, INTSTS2);
@@ -1609,7 +1612,7 @@ static irqreturn_t r8a66597_irq(struct usb_hcd *hcd)
r8a66597_bclr(r8a66597, ATTCHE, INTENB1);
/* start usb bus sampling */
- start_root_hub_sampling(r8a66597, 0);
+ start_root_hub_sampling(r8a66597, 0, 1);
}
if (mask1 & DTCH) {
r8a66597_write(r8a66597, ~DTCH, INTSTS1);
diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c
index 20ad3c48fcb..228f2b070f2 100644
--- a/drivers/usb/host/u132-hcd.c
+++ b/drivers/usb/host/u132-hcd.c
@@ -2934,16 +2934,6 @@ static int u132_start_port_reset(struct usb_hcd *hcd, unsigned port_num)
return 0;
}
-static void u132_hub_irq_enable(struct usb_hcd *hcd)
-{
- struct u132 *u132 = hcd_to_u132(hcd);
- if (u132->going > 1) {
- dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
- , u132->going);
- } else if (u132->going > 0)
- dev_err(&u132->platform_dev->dev, "device is being removed\n");
-}
-
#ifdef CONFIG_PM
static int u132_bus_suspend(struct usb_hcd *hcd)
@@ -2995,7 +2985,6 @@ static struct hc_driver u132_hc_driver = {
.bus_suspend = u132_bus_suspend,
.bus_resume = u132_bus_resume,
.start_port_reset = u132_start_port_reset,
- .hub_irq_enable = u132_hub_irq_enable,
};
/*