summaryrefslogtreecommitdiff
path: root/drivers/usb
diff options
context:
space:
mode:
authorPhilipp Tomsich <philipp.tomsich@theobroma-systems.com>2017-02-01 18:41:56 +0100
committerPhilipp Tomsich <philipp.tomsich@theobroma-systems.com>2017-03-09 01:40:17 +0100
commit8319f247b9304c23176c9cca1aa749bbedede7ce (patch)
tree41e2564056312ea917e7db79995bcdbdd4a24177 /drivers/usb
parent797481ca6d81260f8e4ead17f90b803c00121b10 (diff)
sunxi (sun50i): improved USB support for sun50i (A64)
These changes add support for MUSB (OTG) and HCI1 on sun50i (A64) and try to improve documentation: * adds support for the shared PHY (MUSB and OTG-EHCI/OTG-OHCI) on sun50i (A64) in musb-new/sunxi.c to automatically change the PHY routing when opening/closing MUSB * sets up the usb_phy_passby only from the HCI ([eo]hci_sunxi.c) init and does not match on the PHY id (id #0 is either used by MUSB or by OTG-EHCI/OHCI) in the common PHY initialisation * adds support for clearing the 'SIDDP' bit in the PHYCTL register (and left a comment for the H3, which apparently does the same from sunxi_usb_phy_config in a 'magic' write) * introduced a SUNXI_MUSB_BASE define for the MUSB driver to find the controller (it's usually USB0_BASE, but not on the A64 where USB0_BASE is the OTG-EHCI/OHCI address space) ... this should eventually disappear entirely, as the sunxi musb support moves to support the device model * added initialisation calls to clearing the 'SIDDP' bit in the PHYCTL register and for the usb_phy_passby to ehci-sunxi.c and ohci-sunxi.c (note that these are idempotent, so we don't need to worry that we call this multiple times) * updated the comments in 'sunxi_usb_phy_config' based on the English comments in Allwinner's 3.10 kernel release * add additional defines for the clock gating and module reset bits for the somewhat different controller configuration in the A64, partially motivated by the fact that the musb-new/sunxi.c glue expects AHB_GATE_OFFSET_USB0 to be the bit number for MUSB. Note (for testers) that turning on the complete USB hub cascade connected to EHCI1 on the A64-uQ7 requires two GPIOs, so you will need to either have the (separate) change for having multiple GPIOs in your tree or issue the command 'gpio set pe4' to turn on the second (cascaded) hub. X-AffectedPlatforms: A64-uQ7 Signed-off-by: Philipp Tomsich <philipp.tomsich@theobroma-systems.com>
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/host/ehci-sunxi.c15
-rw-r--r--drivers/usb/host/ohci-sunxi.c8
-rw-r--r--drivers/usb/musb-new/sunxi.c34
3 files changed, 49 insertions, 8 deletions
diff --git a/drivers/usb/host/ehci-sunxi.c b/drivers/usb/host/ehci-sunxi.c
index 5bb97ff45b..af5ae38de3 100644
--- a/drivers/usb/host/ehci-sunxi.c
+++ b/drivers/usb/host/ehci-sunxi.c
@@ -46,6 +46,13 @@ static int ehci_usb_probe(struct udevice *dev)
*/
priv->ahb_gate_mask = 1 << AHB_GATE_OFFSET_USB_EHCI0;
#if defined(CONFIG_MACH_SUN8I_H3) || defined(CONFIG_MACH_SUN50I)
+ /* On the A64-uQ7 (Lynx) we could do without opening OHCI for
+ * HCI1, as the on-module hubs will do the transaction
+ * translation.
+ *
+ * Until this is converted to the driver model (and can
+ * finally go away), it won't do any harm to have this here...
+ */
extra_ahb_gate_mask = 1 << AHB_GATE_OFFSET_USB_OHCI0;
#endif
priv->phy_index = ((uintptr_t)hccr - SUNXI_USB1_BASE) / BASE_DIST;
@@ -61,6 +68,13 @@ static int ehci_usb_probe(struct udevice *dev)
#endif
sunxi_usb_phy_init(priv->phy_index);
+#if defined(CONFIG_MACH_SUN50I)
+ /* For the HCI blocks, the PHYCTL register is at 0x810, so
+ it's an extra 0x400 for the EHCI block. This should go
+ away once the PHYs use the driver model. */
+ sunxi_usb_phy_clear_SIDDP((void *)hccr + 0x400);
+#endif
+ sunxi_usb_phy_passby(priv->phy_index, true);
sunxi_usb_phy_power_on(priv->phy_index);
hcor = (struct ehci_hcor *)((uintptr_t)hccr +
@@ -79,6 +93,7 @@ static int ehci_usb_remove(struct udevice *dev)
if (ret)
return ret;
+ sunxi_usb_phy_passby(priv->phy_index, false);
sunxi_usb_phy_exit(priv->phy_index);
#ifdef CONFIG_SUNXI_GEN_SUN6I
diff --git a/drivers/usb/host/ohci-sunxi.c b/drivers/usb/host/ohci-sunxi.c
index 0c45eec04a..047c3a969e 100644
--- a/drivers/usb/host/ohci-sunxi.c
+++ b/drivers/usb/host/ohci-sunxi.c
@@ -66,6 +66,13 @@ static int ohci_usb_probe(struct udevice *dev)
#endif
sunxi_usb_phy_init(priv->phy_index);
+#if defined(CONFIG_MACH_SUN50I)
+ /* For the HCI blocks, the PHYCTL register is at 0x810, so it's
+ an extra 0x400 for the EHCI block. This should go away once
+ the PHYs use the driver model. */
+ sunxi_usb_phy_clear_SIDDP(regs);
+#endif
+ sunxi_usb_phy_passby(priv->phy_index, true);
sunxi_usb_phy_power_on(priv->phy_index);
return ohci_register(dev, regs);
@@ -81,6 +88,7 @@ static int ohci_usb_remove(struct udevice *dev)
if (ret)
return ret;
+ sunxi_usb_phy_passby(priv->phy_index, false);
sunxi_usb_phy_exit(priv->phy_index);
#ifdef CONFIG_SUNXI_GEN_SUN6I
diff --git a/drivers/usb/musb-new/sunxi.c b/drivers/usb/musb-new/sunxi.c
index 469377fe4e..0dab99d24f 100644
--- a/drivers/usb/musb-new/sunxi.c
+++ b/drivers/usb/musb-new/sunxi.c
@@ -45,6 +45,10 @@
#define USBC_REG_o_PHYBIST 0x0408
#define USBC_REG_o_PHYTUNE 0x040c
+#if defined(CONFIG_MACH_SUN50I)
+#define SUNXI_OTG_PHY_CFG 0x0420
+#endif
+
#define USBC_REG_o_VEND0 0x0043
/* Interface Status and Control */
@@ -152,14 +156,19 @@ static void USBC_ForceVbusValidToHigh(__iomem void *base)
static void USBC_ConfigFIFO_Base(void)
{
- u32 reg_value;
-
/* config usb fifo, 8kb mode */
- reg_value = readl(SUNXI_SRAMC_BASE + 0x04);
- reg_value &= ~(0x03 << 0);
- reg_value |= (1 << 0);
- writel(reg_value, SUNXI_SRAMC_BASE + 0x04);
+ clrsetbits_le32(SUNXI_SRAMC_BASE + 0x04, 0x3, 0x1);
+}
+
+#if defined(CONFIG_MACH_SUN50I)
+static void USBC_SelectPhyToDevice(__iomem void *base, bool routePHYtoOTG)
+{
+ /* The OTG and HCI0 controllers share a single PHY in the A64.
+ * Select either 'to OTG' (1) or 'to HCI' (0).
+ */
+ clrsetbits_le32(base + SUNXI_OTG_PHY_CFG, 1, routePHYtoOTG ? 1 : 0);
}
+#endif
/******************************************************************************
* Needed for the DFU polling magic
@@ -265,7 +274,12 @@ static int sunxi_musb_init(struct musb *musb)
#ifdef CONFIG_SUNXI_GEN_SUN6I
setbits_le32(&ccm->ahb_reset0_cfg, 1 << AHB_GATE_OFFSET_USB0);
#endif
+
sunxi_usb_phy_init(0);
+#if defined(CONFIG_MACH_SUN50I)
+ sunxi_usb_phy_clear_SIDDP(musb->mregs);
+ USBC_SelectPhyToDevice(musb->mregs, true);
+#endif
USBC_ConfigFIFO_Base();
USBC_EnableDpDmPullUp(musb->mregs);
@@ -319,7 +333,7 @@ static int musb_usb_probe(struct udevice *dev)
priv->desc_before_addr = true;
host->host = musb_init_controller(&musb_plat, NULL,
- (void *)SUNXI_USB0_BASE);
+ (void *)SUNXI_MUSB_BASE);
if (!host->host)
return -EIO;
@@ -340,6 +354,10 @@ static int musb_usb_remove(struct udevice *dev)
musb_stop(host->host);
sunxi_usb_phy_exit(0);
+#if defined(CONFIG_MACH_SUN50I)
+ USBC_SelectPhyToDevice(musb->mregs, false);
+#endif
+
#ifdef CONFIG_SUNXI_GEN_SUN6I
clrbits_le32(&ccm->ahb_reset0_cfg, 1 << AHB_GATE_OFFSET_USB0);
#endif
@@ -375,6 +393,6 @@ void sunxi_musb_board_init(void)
*/
device_bind_driver(dm_root(), "sunxi-musb", "sunxi-musb", &dev);
#else
- musb_register(&musb_plat, NULL, (void *)SUNXI_USB0_BASE);
+ musb_register(&musb_plat, NULL, (void *)SUNXI_MUSB_BASE);
#endif
}