aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/bcma-hcd.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/host/bcma-hcd.c')
-rw-r--r--drivers/usb/host/bcma-hcd.c169
1 files changed, 118 insertions, 51 deletions
diff --git a/drivers/usb/host/bcma-hcd.c b/drivers/usb/host/bcma-hcd.c
index 172ef17911aa..5f425c89faf1 100644
--- a/drivers/usb/host/bcma-hcd.c
+++ b/drivers/usb/host/bcma-hcd.c
@@ -27,6 +27,7 @@
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
+#include <linux/of_platform.h>
#include <linux/usb/ehci_pdriver.h>
#include <linux/usb/ohci_pdriver.h>
@@ -34,6 +35,9 @@ MODULE_AUTHOR("Hauke Mehrtens");
MODULE_DESCRIPTION("Common USB driver for BCMA Bus");
MODULE_LICENSE("GPL");
+/* See BCMA_CLKCTLST_EXTRESREQ and BCMA_CLKCTLST_EXTRESST */
+#define USB_BCMA_CLKCTLST_USB_CLK_REQ 0x00000100
+
struct bcma_hcd_device {
struct bcma_device *core;
struct platform_device *ehci_dev;
@@ -165,44 +169,80 @@ static void bcma_hcd_init_chip_mips(struct bcma_device *dev)
}
}
-static void bcma_hcd_init_chip_arm_phy(struct bcma_device *dev)
+/**
+ * bcma_hcd_usb20_old_arm_init - Initialize old USB 2.0 controller on ARM
+ *
+ * Old USB 2.0 core is identified as BCMA_CORE_USB20_HOST and was introduced
+ * long before Northstar devices. It seems some cheaper chipsets like BCM53573
+ * still use it.
+ * Initialization of this old core differs between MIPS and ARM.
+ */
+static int bcma_hcd_usb20_old_arm_init(struct bcma_hcd_device *usb_dev)
{
- struct bcma_device *arm_core;
- void __iomem *dmu;
-
- arm_core = bcma_find_core(dev->bus, BCMA_CORE_ARMCA9);
- if (!arm_core) {
- dev_err(&dev->dev, "can not find ARM Cortex A9 ihost core\n");
- return;
+ struct bcma_device *core = usb_dev->core;
+ struct device *dev = &core->dev;
+ struct bcma_device *pmu_core;
+
+ usleep_range(10000, 20000);
+ if (core->id.rev < 5)
+ return 0;
+
+ pmu_core = bcma_find_core(core->bus, BCMA_CORE_PMU);
+ if (!pmu_core) {
+ dev_err(dev, "Could not find PMU core\n");
+ return -ENOENT;
}
- dmu = ioremap_nocache(arm_core->addr_s[0], 0x1000);
- if (!dmu) {
- dev_err(&dev->dev, "can not map ARM Cortex A9 ihost core\n");
- return;
- }
-
- /* Unlock DMU PLL settings */
- iowrite32(0x0000ea68, dmu + 0x180);
-
- /* Write USB 2.0 PLL control setting */
- iowrite32(0x00dd10c3, dmu + 0x164);
+ /* Take USB core out of reset */
+ bcma_awrite32(core, BCMA_IOCTL, BCMA_IOCTL_CLK | BCMA_IOCTL_FGC);
+ usleep_range(100, 200);
+ bcma_awrite32(core, BCMA_RESET_CTL, BCMA_RESET_CTL_RESET);
+ usleep_range(100, 200);
+ bcma_awrite32(core, BCMA_RESET_CTL, 0);
+ usleep_range(100, 200);
+ bcma_awrite32(core, BCMA_IOCTL, BCMA_IOCTL_CLK);
+ usleep_range(100, 200);
+
+ /* Enable Misc PLL */
+ bcma_write32(core, BCMA_CLKCTLST, BCMA_CLKCTLST_FORCEHT |
+ BCMA_CLKCTLST_HQCLKREQ |
+ USB_BCMA_CLKCTLST_USB_CLK_REQ);
+ usleep_range(100, 200);
+
+ bcma_write32(core, 0x510, 0xc7f85000);
+ bcma_write32(core, 0x510, 0xc7f85003);
+ usleep_range(300, 600);
+
+ /* Program USB PHY PLL parameters */
+ bcma_write32(pmu_core, BCMA_CC_PMU_PLLCTL_ADDR, 0x6);
+ bcma_write32(pmu_core, BCMA_CC_PMU_PLLCTL_DATA, 0x005360c1);
+ usleep_range(100, 200);
+ bcma_write32(pmu_core, BCMA_CC_PMU_PLLCTL_ADDR, 0x7);
+ bcma_write32(pmu_core, BCMA_CC_PMU_PLLCTL_DATA, 0x0);
+ usleep_range(100, 200);
+ bcma_set32(pmu_core, BCMA_CC_PMU_CTL, BCMA_CC_PMU_CTL_PLL_UPD);
+ usleep_range(100, 200);
+
+ bcma_write32(core, 0x510, 0x7f8d007);
+ udelay(1000);
+
+ /* Take controller out of reset */
+ bcma_write32(core, 0x200, 0x4ff);
+ usleep_range(25, 50);
+ bcma_write32(core, 0x200, 0x6ff);
+ usleep_range(25, 50);
+ bcma_write32(core, 0x200, 0x7ff);
+ usleep_range(25, 50);
+
+ of_platform_default_populate(dev->of_node, NULL, dev);
- /* Lock DMU PLL settings */
- iowrite32(0x00000000, dmu + 0x180);
-
- iounmap(dmu);
+ return 0;
}
-static void bcma_hcd_init_chip_arm_hc(struct bcma_device *dev)
+static void bcma_hcd_usb20_ns_init_hc(struct bcma_device *dev)
{
u32 val;
- /*
- * Delay after PHY initialized to ensure HC is ready to be configured
- */
- usleep_range(1000, 2000);
-
/* Set packet buffer OUT threshold */
val = bcma_read32(dev, 0x94);
val &= 0xffff;
@@ -213,20 +253,33 @@ static void bcma_hcd_init_chip_arm_hc(struct bcma_device *dev)
val = bcma_read32(dev, 0x9c);
val |= 1;
bcma_write32(dev, 0x9c, val);
+
+ /*
+ * Broadcom initializes PHY and then waits to ensure HC is ready to be
+ * configured. In our case the order is reversed. We just initialized
+ * controller and we let HCD initialize PHY, so let's wait (sleep) now.
+ */
+ usleep_range(1000, 2000);
}
-static void bcma_hcd_init_chip_arm(struct bcma_device *dev)
+/**
+ * bcma_hcd_usb20_ns_init - Initialize Northstar USB 2.0 controller
+ */
+static int bcma_hcd_usb20_ns_init(struct bcma_hcd_device *bcma_hcd)
{
- bcma_core_enable(dev, 0);
+ struct bcma_device *core = bcma_hcd->core;
+ struct bcma_chipinfo *ci = &core->bus->chipinfo;
+ struct device *dev = &core->dev;
- if (dev->bus->chipinfo.id == BCMA_CHIP_ID_BCM4707 ||
- dev->bus->chipinfo.id == BCMA_CHIP_ID_BCM53018) {
- if (dev->bus->chipinfo.pkg == BCMA_PKG_ID_BCM4707 ||
- dev->bus->chipinfo.pkg == BCMA_PKG_ID_BCM4708)
- bcma_hcd_init_chip_arm_phy(dev);
+ bcma_core_enable(core, 0);
- bcma_hcd_init_chip_arm_hc(dev);
- }
+ if (ci->id == BCMA_CHIP_ID_BCM4707 ||
+ ci->id == BCMA_CHIP_ID_BCM53018)
+ bcma_hcd_usb20_ns_init_hc(core);
+
+ of_platform_default_populate(dev->of_node, NULL, dev);
+
+ return 0;
}
static void bcma_hci_platform_power_gpio(struct bcma_device *dev, bool val)
@@ -299,16 +352,7 @@ static int bcma_hcd_usb20_init(struct bcma_hcd_device *usb_dev)
if (dma_set_mask_and_coherent(dev->dma_dev, DMA_BIT_MASK(32)))
return -EOPNOTSUPP;
- switch (dev->id.id) {
- case BCMA_CORE_NS_USB20:
- bcma_hcd_init_chip_arm(dev);
- break;
- case BCMA_CORE_USB20_HOST:
- bcma_hcd_init_chip_mips(dev);
- break;
- default:
- return -ENODEV;
- }
+ bcma_hcd_init_chip_mips(dev);
/* In AI chips EHCI is addrspace 0, OHCI is 1 */
ohci_addr = dev->addr_s[0];
@@ -338,6 +382,18 @@ err_unregister_ohci_dev:
return err;
}
+static int bcma_hcd_usb30_init(struct bcma_hcd_device *bcma_hcd)
+{
+ struct bcma_device *core = bcma_hcd->core;
+ struct device *dev = &core->dev;
+
+ bcma_core_enable(core, 0);
+
+ of_platform_default_populate(dev->of_node, NULL, dev);
+
+ return 0;
+}
+
static int bcma_hcd_probe(struct bcma_device *core)
{
int err;
@@ -357,14 +413,24 @@ static int bcma_hcd_probe(struct bcma_device *core)
switch (core->id.id) {
case BCMA_CORE_USB20_HOST:
+ if (IS_ENABLED(CONFIG_ARM))
+ err = bcma_hcd_usb20_old_arm_init(usb_dev);
+ else if (IS_ENABLED(CONFIG_MIPS))
+ err = bcma_hcd_usb20_init(usb_dev);
+ else
+ err = -ENOTSUPP;
+ break;
case BCMA_CORE_NS_USB20:
- err = bcma_hcd_usb20_init(usb_dev);
- if (err)
- return err;
+ err = bcma_hcd_usb20_ns_init(usb_dev);
+ break;
+ case BCMA_CORE_NS_USB30:
+ err = bcma_hcd_usb30_init(usb_dev);
break;
default:
return -ENODEV;
}
+ if (err)
+ return err;
bcma_set_drvdata(core, usb_dev);
return 0;
@@ -416,6 +482,7 @@ static int bcma_hcd_resume(struct bcma_device *dev)
static const struct bcma_device_id bcma_hcd_table[] = {
BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_USB20_HOST, BCMA_ANY_REV, BCMA_ANY_CLASS),
BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_NS_USB20, BCMA_ANY_REV, BCMA_ANY_CLASS),
+ BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_NS_USB30, BCMA_ANY_REV, BCMA_ANY_CLASS),
{},
};
MODULE_DEVICE_TABLE(bcma, bcma_hcd_table);