summaryrefslogtreecommitdiff
path: root/arch
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 /arch
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 'arch')
-rw-r--r--arch/arm/include/asm/arch-sunxi/clock_sun6i.h12
-rw-r--r--arch/arm/include/asm/arch-sunxi/cpu_sun4i.h6
-rw-r--r--arch/arm/include/asm/arch-sunxi/usb_phy.h2
-rw-r--r--arch/arm/mach-sunxi/usb_phy.c48
4 files changed, 48 insertions, 20 deletions
diff --git a/arch/arm/include/asm/arch-sunxi/clock_sun6i.h b/arch/arm/include/asm/arch-sunxi/clock_sun6i.h
index e397558fcc..cfc233460f 100644
--- a/arch/arm/include/asm/arch-sunxi/clock_sun6i.h
+++ b/arch/arm/include/asm/arch-sunxi/clock_sun6i.h
@@ -256,11 +256,21 @@ struct sunxi_ccm_reg {
#define AHB_GATE_OFFSET_USB_EHCI2 27
#define AHB_GATE_OFFSET_USB_EHCI1 26
#define AHB_GATE_OFFSET_USB_EHCI0 25
+#define AHB_GATE_OFFSET_USB0 24
+#elif defined(CONFIG_MACH_SUN50I)
+#define AHB_GATE_OFFSET_USB_OHCI0 29
+#define AHB_GATE_OFFSET_USBOTG_OHCI 28
+#define AHB_GATE_OFFSET_USB_EHCI0 25
+#define AHB_GATE_OFFSET_USBOTG_EHCI 24
+#define AHB_GATE_OFFSET_USBOTG 23
+/* The musb-new/sunxi.c glue uses AHB_GATE_OFFSET_USB0 for the MUSB OTG
+ block, so we define it to what it expects. */
+#define AHB_GATE_OFFSET_USB0 AHB_GATE_OFFSET_USBOTG
#else
#define AHB_GATE_OFFSET_USB_EHCI1 27
#define AHB_GATE_OFFSET_USB_EHCI0 26
-#endif
#define AHB_GATE_OFFSET_USB0 24
+#endif
#define AHB_GATE_OFFSET_MCTL 14
#define AHB_GATE_OFFSET_GMAC 17
#define AHB_GATE_OFFSET_NAND0 13
diff --git a/arch/arm/include/asm/arch-sunxi/cpu_sun4i.h b/arch/arm/include/asm/arch-sunxi/cpu_sun4i.h
index 1e2c29477d..e8719b0fde 100644
--- a/arch/arm/include/asm/arch-sunxi/cpu_sun4i.h
+++ b/arch/arm/include/asm/arch-sunxi/cpu_sun4i.h
@@ -66,13 +66,17 @@
#endif
#ifdef CONFIG_SUNXI_GEN_SUN6I
#if defined(CONFIG_MACH_SUN8I_H3) || defined(CONFIG_MACH_SUN50I)
-#define SUNXI_USBPHY_BASE 0x01c19000
+#define SUNXI_MUSB_BASE 0x01c19000
#define SUNXI_USB0_BASE 0x01c1a000
#define SUNXI_USB1_BASE 0x01c1b000
+#if defined(CONFIG_MACH_SUN8I_H3)
+#define SUNXI_USBPHY_BASE SUNXI_MUSB_BASE
#define SUNXI_USB2_BASE 0x01c1c000
#define SUNXI_USB3_BASE 0x01c1d000
+#endif
#else
#define SUNXI_USB0_BASE 0x01c19000
+#define SUNXI_MUSB_BASE SUNXI_USB0_BASE
#define SUNXI_USB1_BASE 0x01c1a000
#define SUNXI_USB2_BASE 0x01c1b000
#endif
diff --git a/arch/arm/include/asm/arch-sunxi/usb_phy.h b/arch/arm/include/asm/arch-sunxi/usb_phy.h
index cef6c985bc..e374daa7aa 100644
--- a/arch/arm/include/asm/arch-sunxi/usb_phy.h
+++ b/arch/arm/include/asm/arch-sunxi/usb_phy.h
@@ -19,6 +19,8 @@ void sunxi_usb_phy_power_off(int index);
int sunxi_usb_phy_vbus_detect(int index);
int sunxi_usb_phy_id_detect(int index);
void sunxi_usb_phy_enable_squelch_detect(int index, int enable);
+void sunxi_usb_phy_passby(int index, bool enable);
+void sunxi_usb_phy_clear_SIDDP(void *base);
/* Not really phy related, but we have to declare this somewhere ... */
#if defined(CONFIG_USB_MUSB_HOST) || defined(CONFIG_USB_MUSB_GADGET)
diff --git a/arch/arm/mach-sunxi/usb_phy.c b/arch/arm/mach-sunxi/usb_phy.c
index 278587b493..496eeb0aa2 100644
--- a/arch/arm/mach-sunxi/usb_phy.c
+++ b/arch/arm/mach-sunxi/usb_phy.c
@@ -19,7 +19,7 @@
#include <errno.h>
#define SUNXI_USB_PMU_IRQ_ENABLE 0x800
-#ifdef CONFIG_MACH_SUN8I_A33
+#if defined(CONFIG_MACH_SUN8I_A33) || defined(CONFIG_MACH_SUN50I)
#define SUNXI_USB_CSR 0x410
#else
#define SUNXI_USB_CSR 0x404
@@ -31,8 +31,10 @@
#define SUNXI_EHCI_AHB_INCRX_ALIGN_EN (1 << 8)
#define SUNXI_EHCI_ULPI_BYPASS_EN (1 << 0)
+#if defined(CONFIG_MACH_SUN8I_H3)
#define REG_PHY_UNK_H3 0x420
#define REG_PMU_UNK_H3 0x810
+#endif
/* A83T specific control bits for PHY0 */
#define SUNXI_PHY_CTL_VBUSVLDEXT BIT(5)
@@ -146,13 +148,21 @@ __maybe_unused static void usb_phy_write(struct sunxi_usb_phy *phy, int addr,
}
}
-#if defined(CONFIG_MACH_SUN8I_H3) || defined(CONFIG_MACH_SUN50I)
+#if defined(CONFIG_MACH_SUN8I_H3)
static void sunxi_usb_phy_config(struct sunxi_usb_phy *phy)
{
-#if defined CONFIG_MACH_SUN8I_H3
+ /* This function performs similar initialisation to what we do
+ * for the A64: routing PHY 0 to the OTG controller and what
+ * the 3.10 kernel calls 'clearing SIDDP'.
+ *
+ * Refer to musb-new/sunxi.c and ehci-sunxi.c for the call-sites
+ * (conditional on CONFIG_MACH_SUN50I) to determine suitability
+ * for the H3.
+ */
+
if (phy->id == 0)
clrbits_le32(SUNXI_USBPHY_BASE + REG_PHY_UNK_H3, 0x01);
-#endif
+
clrbits_le32(phy->base + REG_PMU_UNK_H3, 0x02);
}
#elif defined CONFIG_MACH_SUN8I_A83T
@@ -162,18 +172,14 @@ static void sunxi_usb_phy_config(struct sunxi_usb_phy *phy)
#else
static void sunxi_usb_phy_config(struct sunxi_usb_phy *phy)
{
- /* The following comments are machine
- * translated from Chinese, you have been warned!
- */
-
- /* Regulation 45 ohms */
+ /* adjust the 45 ohm resistor */
if (phy->id == 0)
usb_phy_write(phy, 0x0c, 0x01, 1);
- /* adjust PHY's magnitude and rate */
+ /* adjust PHY range and rate */
usb_phy_write(phy, 0x20, 0x14, 5);
- /* threshold adjustment disconnect */
+ /* adjust disconnect threshold */
#if defined CONFIG_MACH_SUN5I || defined CONFIG_MACH_SUN7I
usb_phy_write(phy, 0x2a, 2, 2);
#else
@@ -184,8 +190,20 @@ static void sunxi_usb_phy_config(struct sunxi_usb_phy *phy)
}
#endif
-static void sunxi_usb_phy_passby(struct sunxi_usb_phy *phy, int enable)
+#if defined(CONFIG_MACH_SUN50I)
+void sunxi_usb_phy_clear_SIDDP(void *base)
{
+ /* We pretend that this is always at the same offset (0x410),
+ * even though it is 0x410 for MUSB/OTG and OHCI, but 0x810
+ * for EHCI. The EHCI call site will have to adjust this...
+ */
+ clrbits_le32(base + SUNXI_USB_CSR, (1 << 1));
+}
+#endif
+
+void sunxi_usb_phy_passby(int index, bool enable)
+{
+ struct sunxi_usb_phy *phy = &sunxi_usb_phy[index];
unsigned long bits = 0;
void *addr;
@@ -233,9 +251,6 @@ void sunxi_usb_phy_init(int index)
sunxi_usb_phy_config(phy);
- if (phy->id != 0)
- sunxi_usb_phy_passby(phy, SUNXI_USB_PASSBY_EN);
-
#ifdef CONFIG_MACH_SUN8I_A83T
if (phy->id == 0) {
setbits_le32(SUNXI_USB0_BASE + SUNXI_USB_CSR,
@@ -255,9 +270,6 @@ void sunxi_usb_phy_exit(int index)
if (phy->init_count != 0)
return;
- if (phy->id != 0)
- sunxi_usb_phy_passby(phy, !SUNXI_USB_PASSBY_EN);
-
#ifdef CONFIG_MACH_SUN8I_A83T
if (phy->id == 0) {
setbits_le32(SUNXI_USB0_BASE + SUNXI_USB_CSR,