aboutsummaryrefslogtreecommitdiff
path: root/drivers/usb/host/ehci-ps3.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/host/ehci-ps3.c')
-rw-r--r--drivers/usb/host/ehci-ps3.c67
1 files changed, 42 insertions, 25 deletions
diff --git a/drivers/usb/host/ehci-ps3.c b/drivers/usb/host/ehci-ps3.c
index bbda58eb881..7934ff9b35e 100644
--- a/drivers/usb/host/ehci-ps3.c
+++ b/drivers/usb/host/ehci-ps3.c
@@ -21,33 +21,47 @@
#include <asm/firmware.h>
#include <asm/ps3.h>
-static int ps3_ehci_hc_reset(struct usb_hcd *hcd)
+static void ps3_ehci_setup_insnreg(struct ehci_hcd *ehci)
{
- int result;
- struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+ /* PS3 HC internal setup register offsets. */
- ehci->big_endian_mmio = 1;
+ enum ps3_ehci_hc_insnreg {
+ ps3_ehci_hc_insnreg01 = 0x084,
+ ps3_ehci_hc_insnreg02 = 0x088,
+ ps3_ehci_hc_insnreg03 = 0x08c,
+ };
- ehci->caps = hcd->regs;
- ehci->regs = hcd->regs + HC_LENGTH(ehci_readl(ehci,
- &ehci->caps->hc_capbase));
+ /* PS3 EHCI HC errata fix 316 - The PS3 EHCI HC will reset its
+ * internal INSNREGXX setup regs back to the chip default values
+ * on Host Controller Reset (CMD_RESET) or Light Host Controller
+ * Reset (CMD_LRESET). The work-around for this is for the HC
+ * driver to re-initialise these regs when ever the HC is reset.
+ */
- dbg_hcs_params(ehci, "reset");
- dbg_hcc_params(ehci, "reset");
+ /* Set burst transfer counts to 256 out, 32 in. */
- ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
+ writel_be(0x01000020, (void __iomem *)ehci->regs +
+ ps3_ehci_hc_insnreg01);
- result = ehci_halt(ehci);
+ /* Enable burst transfer counts. */
- if (result)
- return result;
+ writel_be(0x00000001, (void __iomem *)ehci->regs +
+ ps3_ehci_hc_insnreg03);
+}
- result = ehci_init(hcd);
+static int ps3_ehci_hc_reset(struct usb_hcd *hcd)
+{
+ int result;
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+ ehci->big_endian_mmio = 1;
+ ehci->caps = hcd->regs;
+
+ result = ehci_setup(hcd);
if (result)
return result;
- ehci_reset(ehci);
+ ps3_ehci_setup_insnreg(ehci);
return result;
}
@@ -57,7 +71,7 @@ static const struct hc_driver ps3_ehci_hc_driver = {
.product_desc = "PS3 EHCI Host Controller",
.hcd_priv_size = sizeof(struct ehci_hcd),
.irq = ehci_irq,
- .flags = HCD_MEMORY | HCD_USB2,
+ .flags = HCD_MEMORY | HCD_USB2 | HCD_BH,
.reset = ps3_ehci_hc_reset,
.start = ehci_run,
.stop = ehci_stop,
@@ -65,6 +79,7 @@ static const struct hc_driver ps3_ehci_hc_driver = {
.urb_enqueue = ehci_urb_enqueue,
.urb_dequeue = ehci_urb_dequeue,
.endpoint_disable = ehci_endpoint_disable,
+ .endpoint_reset = ehci_endpoint_reset,
.get_frame_number = ehci_get_frame,
.hub_status_data = ehci_hub_status_data,
.hub_control = ehci_hub_control,
@@ -73,6 +88,9 @@ static const struct hc_driver ps3_ehci_hc_driver = {
.bus_resume = ehci_bus_resume,
#endif
.relinquish_port = ehci_relinquish_port,
+ .port_handed_over = ehci_port_handed_over,
+
+ .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
};
static int ps3_ehci_probe(struct ps3_system_bus_device *dev)
@@ -80,7 +98,7 @@ static int ps3_ehci_probe(struct ps3_system_bus_device *dev)
int result;
struct usb_hcd *hcd;
unsigned int virq;
- static u64 dummy_mask = DMA_32BIT_MASK;
+ static u64 dummy_mask = DMA_BIT_MASK(32);
if (usb_disabled()) {
result = -ENODEV;
@@ -125,10 +143,9 @@ static int ps3_ehci_probe(struct ps3_system_bus_device *dev)
goto fail_irq;
}
- dev->core.power.power_state = PMSG_ON;
dev->core.dma_mask = &dummy_mask; /* FIXME: for improper usb code */
- hcd = usb_create_hcd(&ps3_ehci_hc_driver, &dev->core, dev->core.bus_id);
+ hcd = usb_create_hcd(&ps3_ehci_hc_driver, &dev->core, dev_name(&dev->core));
if (!hcd) {
dev_dbg(&dev->core, "%s:%d: usb_create_hcd failed\n", __func__,
@@ -162,9 +179,9 @@ static int ps3_ehci_probe(struct ps3_system_bus_device *dev)
dev_dbg(&dev->core, "%s:%d: virq %lu\n", __func__, __LINE__,
(unsigned long)virq);
- ps3_system_bus_set_driver_data(dev, hcd);
+ ps3_system_bus_set_drvdata(dev, hcd);
- result = usb_add_hcd(hcd, virq, IRQF_DISABLED);
+ result = usb_add_hcd(hcd, virq, 0);
if (result) {
dev_dbg(&dev->core, "%s:%d: usb_add_hcd failed (%d)\n",
@@ -172,6 +189,7 @@ static int ps3_ehci_probe(struct ps3_system_bus_device *dev)
goto fail_add_hcd;
}
+ device_wakeup_enable(hcd->self.controller);
return result;
fail_add_hcd:
@@ -195,8 +213,7 @@ fail_start:
static int ps3_ehci_remove(struct ps3_system_bus_device *dev)
{
unsigned int tmp;
- struct usb_hcd *hcd =
- (struct usb_hcd *)ps3_system_bus_get_driver_data(dev);
+ struct usb_hcd *hcd = ps3_system_bus_get_drvdata(dev);
BUG_ON(!hcd);
@@ -207,7 +224,7 @@ static int ps3_ehci_remove(struct ps3_system_bus_device *dev)
usb_remove_hcd(hcd);
- ps3_system_bus_set_driver_data(dev, NULL);
+ ps3_system_bus_set_drvdata(dev, NULL);
BUG_ON(!hcd->regs);
iounmap(hcd->regs);
@@ -224,7 +241,7 @@ static int ps3_ehci_remove(struct ps3_system_bus_device *dev)
return 0;
}
-static int ps3_ehci_driver_register(struct ps3_system_bus_driver *drv)
+static int __init ps3_ehci_driver_register(struct ps3_system_bus_driver *drv)
{
return firmware_has_feature(FW_FEATURE_PS3_LV1)
? ps3_system_bus_driver_register(drv)