Merge tag 'hwmon-for-linus-v4.9' of git://git.kernel.org/pub/scm/linux/kernel/git...
[cascardo/linux.git] / drivers / usb / host / bcma-hcd.c
index 172ef17..5f425c8 100644 (file)
@@ -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);