diff options
author | Philipp Tomsich <philipp.tomsich@theobroma-systems.com> | 2017-02-01 18:41:56 +0100 |
---|---|---|
committer | Philipp Tomsich <philipp.tomsich@theobroma-systems.com> | 2017-03-09 01:40:17 +0100 |
commit | 8319f247b9304c23176c9cca1aa749bbedede7ce (patch) | |
tree | 41e2564056312ea917e7db79995bcdbdd4a24177 /drivers/usb | |
parent | 797481ca6d81260f8e4ead17f90b803c00121b10 (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.c | 15 | ||||
-rw-r--r-- | drivers/usb/host/ohci-sunxi.c | 8 | ||||
-rw-r--r-- | drivers/usb/musb-new/sunxi.c | 34 |
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 } |