summaryrefslogtreecommitdiffstats
path: root/target/linux/brcm47xx/patches-2.6.28/250-ohci-ssb-usb2.patch
blob: 065a16b3866f983d63c6a0226e1942bf52b990ce (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
---
 drivers/usb/host/ohci-ssb.c |   39 ++++++++++++++++++++++++++++++++++++---
 1 file changed, 36 insertions(+), 3 deletions(-)

--- linux-2.6.28.10.orig/drivers/usb/host/ohci-ssb.c
+++ linux-2.6.28.10/drivers/usb/host/ohci-ssb.c
@@ -106,10 +106,42 @@ static int ssb_ohci_attach(struct ssb_de
 	int err = -ENOMEM;
 	u32 tmp, flags = 0;
 
-	if (dev->id.coreid == SSB_DEV_USB11_HOSTDEV)
+	if (dev->id.coreid == SSB_DEV_USB11_HOSTDEV) {
+		/* Put the device into host-mode. */
 		flags |= SSB_OHCI_TMSLOW_HOSTMODE;
-
-	ssb_device_enable(dev, flags);
+		ssb_device_enable(dev, flags);
+	} else if (dev->id.coreid == SSB_DEV_USB20_HOST) {
+		/*
+		 * USB 2.0 special considerations:
+		 *
+		 * 1. Since the core supports both OHCI and EHCI functions, it must
+		 *    only be reset once.
+		 *
+		 * 2. In addition to the standard SSB reset sequence, the Host Control
+		 *    Register must be programmed to bring the USB core and various
+		 *    phy components out of reset.
+		 */
+		ssb_device_enable(dev, 0);
+		ssb_write32(dev, 0x200, 0x7ff);
+		udelay(1);
+		if (dev->id.revision == 1) { // bug in rev 1
+
+			/* Change Flush control reg */
+			tmp = ssb_read32(dev, 0x400);
+			tmp &= ~8;
+			ssb_write32(dev, 0x400, tmp);
+			tmp = ssb_read32(dev, 0x400);
+			printk("USB20H fcr: 0x%0x\n", tmp);
+
+			/* Change Shim control reg */
+			tmp = ssb_read32(dev, 0x304);
+			tmp &= ~0x100;
+			ssb_write32(dev, 0x304, tmp);
+			tmp = ssb_read32(dev, 0x304);
+			printk("USB20H shim: 0x%0x\n", tmp);
+		}
+	} else
+		ssb_device_enable(dev, 0);
 
 	hcd = usb_create_hcd(&ssb_ohci_hc_driver, dev->dev,
 			dev_name(dev->dev));
@@ -200,6 +232,7 @@ static int ssb_ohci_resume(struct ssb_de
 static const struct ssb_device_id ssb_ohci_table[] = {
 	SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOSTDEV, SSB_ANY_REV),
 	SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOST, SSB_ANY_REV),
+	SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB20_HOST, SSB_ANY_REV),
 	SSB_DEVTABLE_END
 };
 MODULE_DEVICE_TABLE(ssb, ssb_ohci_table);