[U-Boot] [PATCH v1 2/2] sunxi (sun50i): improved USB support for sun50i (A64)
Philipp Tomsich
philipp.tomsich at theobroma-systems.com
Fri Feb 17 17:41:17 UTC 2017
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 at theobroma-systems.com>
---
arch/arm/include/asm/arch-sunxi/clock_sun6i.h | 12 ++++++-
arch/arm/include/asm/arch-sunxi/cpu_sun4i.h | 6 +++-
arch/arm/include/asm/arch-sunxi/usb_phy.h | 2 ++
arch/arm/mach-sunxi/usb_phy.c | 48 +++++++++++++++++----------
drivers/usb/host/ehci-sunxi.c | 15 +++++++++
drivers/usb/host/ohci-sunxi.c | 8 +++++
drivers/usb/musb-new/sunxi.c | 34 ++++++++++++++-----
7 files changed, 97 insertions(+), 28 deletions(-)
diff --git a/arch/arm/include/asm/arch-sunxi/clock_sun6i.h b/arch/arm/include/asm/arch-sunxi/clock_sun6i.h
index e397558..cfc2334 100644
--- a/arch/arm/include/asm/arch-sunxi/clock_sun6i.h
+++ b/arch/arm/include/asm/arch-sunxi/clock_sun6i.h
@@ -14,417 +14,427 @@
struct sunxi_ccm_reg {
u32 pll1_cfg; /* 0x00 pll1 control */
u32 reserved0;
u32 pll2_cfg; /* 0x08 pll2 control */
u32 reserved1;
u32 pll3_cfg; /* 0x10 pll3 control */
u32 reserved2;
u32 pll4_cfg; /* 0x18 pll4 control */
u32 reserved3;
u32 pll5_cfg; /* 0x20 pll5 control */
u32 reserved4;
u32 pll6_cfg; /* 0x28 pll6 control */
u32 reserved5;
u32 pll7_cfg; /* 0x30 pll7 control */
u32 reserved6;
u32 pll8_cfg; /* 0x38 pll8 control */
u32 reserved7;
u32 mipi_pll_cfg; /* 0x40 MIPI pll control */
u32 pll9_cfg; /* 0x44 pll9 control */
u32 pll10_cfg; /* 0x48 pll10 control */
u32 pll11_cfg; /* 0x4c pll11 (ddr1) control (A33 only) */
u32 cpu_axi_cfg; /* 0x50 CPU/AXI divide ratio */
u32 ahb1_apb1_div; /* 0x54 AHB1/APB1 divide ratio */
u32 apb2_div; /* 0x58 APB2 divide ratio */
u32 axi_gate; /* 0x5c axi module clock gating */
u32 ahb_gate0; /* 0x60 ahb module clock gating 0 */
u32 ahb_gate1; /* 0x64 ahb module clock gating 1 */
u32 apb1_gate; /* 0x68 apb1 module clock gating */
u32 apb2_gate; /* 0x6c apb2 module clock gating */
u32 bus_gate4; /* 0x70 gate 4 module clock gating */
u8 res3[0xc];
u32 nand0_clk_cfg; /* 0x80 nand0 clock control */
u32 nand1_clk_cfg; /* 0x84 nand1 clock control */
u32 sd0_clk_cfg; /* 0x88 sd0 clock control */
u32 sd1_clk_cfg; /* 0x8c sd1 clock control */
u32 sd2_clk_cfg; /* 0x90 sd2 clock control */
u32 sd3_clk_cfg; /* 0x94 sd3 clock control */
u32 ts_clk_cfg; /* 0x98 transport stream clock control */
u32 ss_clk_cfg; /* 0x9c security system clock control */
u32 spi0_clk_cfg; /* 0xa0 spi0 clock control */
u32 spi1_clk_cfg; /* 0xa4 spi1 clock control */
u32 spi2_clk_cfg; /* 0xa8 spi2 clock control */
u32 spi3_clk_cfg; /* 0xac spi3 clock control */
u32 i2s0_clk_cfg; /* 0xb0 I2S0 clock control*/
u32 i2s1_clk_cfg; /* 0xb4 I2S1 clock control */
u32 reserved10[2];
u32 spdif_clk_cfg; /* 0xc0 SPDIF clock control */
u32 reserved11[2];
u32 usb_clk_cfg; /* 0xcc USB clock control */
u32 gmac_clk_cfg; /* 0xd0 GMAC clock control */
u32 reserved12[7];
u32 mdfs_clk_cfg; /* 0xf0 MDFS clock control */
u32 dram_clk_cfg; /* 0xf4 DRAM configuration clock control */
u32 dram_pll_cfg; /* 0xf8 PLL_DDR cfg register, A33 only */
u32 mbus_reset; /* 0xfc MBUS reset control, A33 only */
u32 dram_clk_gate; /* 0x100 DRAM module gating */
u32 be0_clk_cfg; /* 0x104 BE0 module clock */
u32 be1_clk_cfg; /* 0x108 BE1 module clock */
u32 fe0_clk_cfg; /* 0x10c FE0 module clock */
u32 fe1_clk_cfg; /* 0x110 FE1 module clock */
u32 mp_clk_cfg; /* 0x114 MP module clock */
u32 lcd0_ch0_clk_cfg; /* 0x118 LCD0 CH0 module clock */
u32 lcd1_ch0_clk_cfg; /* 0x11c LCD1 CH0 module clock */
u32 reserved14[3];
u32 lcd0_ch1_clk_cfg; /* 0x12c LCD0 CH1 module clock */
u32 lcd1_ch1_clk_cfg; /* 0x130 LCD1 CH1 module clock */
u32 csi0_clk_cfg; /* 0x134 CSI0 module clock */
u32 csi1_clk_cfg; /* 0x138 CSI1 module clock */
u32 ve_clk_cfg; /* 0x13c VE module clock */
u32 adda_clk_cfg; /* 0x140 ADDA module clock */
u32 avs_clk_cfg; /* 0x144 AVS module clock */
u32 dmic_clk_cfg; /* 0x148 Digital Mic module clock*/
u32 reserved15;
u32 hdmi_clk_cfg; /* 0x150 HDMI module clock */
u32 ps_clk_cfg; /* 0x154 PS module clock */
u32 mtc_clk_cfg; /* 0x158 MTC module clock */
u32 mbus0_clk_cfg; /* 0x15c MBUS0 module clock */
u32 mbus1_clk_cfg; /* 0x160 MBUS1 module clock */
u32 reserved16;
u32 mipi_dsi_clk_cfg; /* 0x168 MIPI DSI clock control */
u32 mipi_csi_clk_cfg; /* 0x16c MIPI CSI clock control */
u32 reserved17[4];
u32 iep_drc0_clk_cfg; /* 0x180 IEP DRC0 module clock */
u32 iep_drc1_clk_cfg; /* 0x184 IEP DRC1 module clock */
u32 iep_deu0_clk_cfg; /* 0x188 IEP DEU0 module clock */
u32 iep_deu1_clk_cfg; /* 0x18c IEP DEU1 module clock */
u32 reserved18[4];
u32 gpu_core_clk_cfg; /* 0x1a0 GPU core clock config */
u32 gpu_mem_clk_cfg; /* 0x1a4 GPU memory clock config */
u32 gpu_hyd_clk_cfg; /* 0x1a0 GPU HYD clock config */
u32 reserved19[21];
u32 pll_lock; /* 0x200 PLL Lock Time */
u32 pll1_lock; /* 0x204 PLL1 Lock Time */
u32 reserved20[6];
u32 pll1_bias_cfg; /* 0x220 PLL1 Bias config */
u32 pll2_bias_cfg; /* 0x224 PLL2 Bias config */
u32 pll3_bias_cfg; /* 0x228 PLL3 Bias config */
u32 pll4_bias_cfg; /* 0x22c PLL4 Bias config */
u32 pll5_bias_cfg; /* 0x230 PLL5 Bias config */
u32 pll6_bias_cfg; /* 0x234 PLL6 Bias config */
u32 pll7_bias_cfg; /* 0x238 PLL7 Bias config */
u32 pll8_bias_cfg; /* 0x23c PLL8 Bias config */
u32 mipi_bias_cfg; /* 0x240 MIPI Bias config */
u32 pll9_bias_cfg; /* 0x244 PLL9 Bias config */
u32 pll10_bias_cfg; /* 0x248 PLL10 Bias config */
u32 reserved21[5];
u32 pll5_tuning_cfg; /* 0x260 PLL5 Tuning config */
u32 reserved21_5[7];
u32 pll1_pattern_cfg; /* 0x280 PLL1 Pattern config */
u32 pll2_pattern_cfg; /* 0x284 PLL2 Pattern config */
u32 pll3_pattern_cfg; /* 0x288 PLL3 Pattern config */
u32 pll4_pattern_cfg; /* 0x28c PLL4 Pattern config */
u32 pll5_pattern_cfg; /* 0x290 PLL5 Pattern config */
u32 pll6_pattern_cfg; /* 0x294 PLL6 Pattern config */
u32 pll7_pattern_cfg; /* 0x298 PLL7 Pattern config */
u32 pll8_pattern_cfg; /* 0x29c PLL8 Pattern config */
u32 mipi_pattern_cfg; /* 0x2a0 MIPI Pattern config */
u32 pll9_pattern_cfg; /* 0x2a4 PLL9 Pattern config */
u32 pll10_pattern_cfg; /* 0x2a8 PLL10 Pattern config */
u32 pll11_pattern_cfg0; /* 0x2ac PLL11 Pattern config0, A33 only */
u32 pll11_pattern_cfg1; /* 0x2b0 PLL11 Pattern config0, A33 only */
u32 reserved22[3];
u32 ahb_reset0_cfg; /* 0x2c0 AHB1 Reset 0 config */
u32 ahb_reset1_cfg; /* 0x2c4 AHB1 Reset 1 config */
u32 ahb_reset2_cfg; /* 0x2c8 AHB1 Reset 2 config */
u32 reserved23;
u32 apb1_reset_cfg; /* 0x2d0 APB1 Reset config */
u32 reserved24;
u32 apb2_reset_cfg; /* 0x2d8 APB2 Reset config */
u32 reserved25[5];
u32 ccu_sec_switch; /* 0x2f0 CCU Security Switch, H3 only */
};
/* apb2 bit field */
#define APB2_CLK_SRC_LOSC (0x0 << 24)
#define APB2_CLK_SRC_OSC24M (0x1 << 24)
#define APB2_CLK_SRC_PLL6 (0x2 << 24)
#define APB2_CLK_SRC_MASK (0x3 << 24)
#define APB2_CLK_RATE_N_1 (0x0 << 16)
#define APB2_CLK_RATE_N_2 (0x1 << 16)
#define APB2_CLK_RATE_N_4 (0x2 << 16)
#define APB2_CLK_RATE_N_8 (0x3 << 16)
#define APB2_CLK_RATE_N_MASK (3 << 16)
#define APB2_CLK_RATE_M(m) (((m)-1) << 0)
#define APB2_CLK_RATE_M_MASK (0x1f << 0)
/* apb2 gate field */
#define APB2_GATE_UART_SHIFT (16)
#define APB2_GATE_UART_MASK (0xff << APB2_GATE_UART_SHIFT)
#define APB2_GATE_TWI_SHIFT (0)
#define APB2_GATE_TWI_MASK (0xf << APB2_GATE_TWI_SHIFT)
/* cpu_axi_cfg bits */
#define AXI_DIV_SHIFT 0
#define ATB_DIV_SHIFT 8
#define CPU_CLK_SRC_SHIFT 16
#define AXI_DIV_1 0
#define AXI_DIV_2 1
#define AXI_DIV_3 2
#define AXI_DIV_4 3
#define ATB_DIV_1 0
#define ATB_DIV_2 1
#define ATB_DIV_4 2
#define CPU_CLK_SRC_OSC24M 1
#define CPU_CLK_SRC_PLL1 2
#define CCM_PLLx_CTRL_LOCK (0x1 << 28)
#define CCM_PLL1_CTRL_M(n) ((((n) - 1) & 0x3) << 0)
#define CCM_PLL1_CTRL_K(n) ((((n) - 1) & 0x3) << 4)
#define CCM_PLL1_CTRL_N(n) ((((n) - 1) & 0x1f) << 8)
#define CCM_PLL1_CTRL_P(n) (((n) & 0x3) << 16)
#define CCM_PLL1_CTRL_EN (0x1 << 31)
#define CCM_PLL3_CTRL_M_SHIFT 0
#define CCM_PLL3_CTRL_M_MASK (0xf << CCM_PLL3_CTRL_M_SHIFT)
#define CCM_PLL3_CTRL_M(n) ((((n) - 1) & 0xf) << 0)
#define CCM_PLL3_CTRL_N_SHIFT 8
#define CCM_PLL3_CTRL_N_MASK (0x7f << CCM_PLL3_CTRL_N_SHIFT)
#define CCM_PLL3_CTRL_N(n) ((((n) - 1) & 0x7f) << 8)
#define CCM_PLL3_CTRL_INTEGER_MODE (0x1 << 24)
#define CCM_PLL3_CTRL_EN (0x1 << 31)
#define CCM_PLL5_CTRL_M(n) ((((n) - 1) & 0x3) << 0)
#define CCM_PLL5_CTRL_K(n) ((((n) - 1) & 0x3) << 4)
#define CCM_PLL5_CTRL_N(n) ((((n) - 1) & 0x1f) << 8)
#define CCM_PLL5_CTRL_UPD (0x1 << 20)
#define CCM_PLL5_CTRL_SIGMA_DELTA_EN (0x1 << 24)
#define CCM_PLL5_CTRL_EN (0x1 << 31)
#define CCM_PLL6_CTRL_N_SHIFT 8
#define CCM_PLL6_CTRL_N_MASK (0x1f << CCM_PLL6_CTRL_N_SHIFT)
#define CCM_PLL6_CTRL_K_SHIFT 4
#define CCM_PLL6_CTRL_K_MASK (0x3 << CCM_PLL6_CTRL_K_SHIFT)
#define CCM_PLL6_CTRL_LOCK (1 << 28)
#define CCM_MIPI_PLL_CTRL_M_SHIFT 0
#define CCM_MIPI_PLL_CTRL_M_MASK (0xf << CCM_MIPI_PLL_CTRL_M_SHIFT)
#define CCM_MIPI_PLL_CTRL_M(n) ((((n) - 1) & 0xf) << 0)
#define CCM_MIPI_PLL_CTRL_K_SHIFT 4
#define CCM_MIPI_PLL_CTRL_K_MASK (0x3 << CCM_MIPI_PLL_CTRL_K_SHIFT)
#define CCM_MIPI_PLL_CTRL_K(n) ((((n) - 1) & 0x3) << 4)
#define CCM_MIPI_PLL_CTRL_N_SHIFT 8
#define CCM_MIPI_PLL_CTRL_N_MASK (0xf << CCM_MIPI_PLL_CTRL_N_SHIFT)
#define CCM_MIPI_PLL_CTRL_N(n) ((((n) - 1) & 0xf) << 8)
#define CCM_MIPI_PLL_CTRL_LDO_EN (0x3 << 22)
#define CCM_MIPI_PLL_CTRL_EN (0x1 << 31)
#define CCM_PLL6_CTRL_M(n) ((((n) - 1) & 0x3) << 0)
#define CCM_PLL6_CTRL_K(n) ((((n) - 1) & 0x3) << 4)
#define CCM_PLL6_CTRL_N(n) ((((n) - 1) & 0x1f) << 8)
#define CCM_PLL6_CTRL_24M_OUT_EN (0x1 << 18)
#define CCM_PLL6_CTRL_EN (0x1 << 31)
#define CCM_PLL11_CTRL_N(n) ((((n) - 1) & 0x3f) << 8)
#define CCM_PLL11_CTRL_SIGMA_DELTA_EN (0x1 << 24)
#define CCM_PLL11_CTRL_UPD (0x1 << 30)
#define CCM_PLL11_CTRL_EN (0x1 << 31)
#define CCM_PLL5_TUN_LOCK_TIME(x) (((x) & 0x7) << 24)
#define CCM_PLL5_TUN_LOCK_TIME_MASK CCM_PLL5_TUN_LOCK_TIME(0x7)
#define CCM_PLL5_TUN_INIT_FREQ(x) (((x) & 0x7f) << 16)
#define CCM_PLL5_TUN_INIT_FREQ_MASK CCM_PLL5_TUN_INIT_FREQ(0x7f)
#if defined(CONFIG_MACH_SUN50I)
/* AHB1=100MHz failsafe setup from the FEL mode, usable with PMIC defaults */
#define AHB1_ABP1_DIV_DEFAULT 0x00003190 /* AHB1=PLL6/6,APB1=AHB1/2 */
#else
#define AHB1_ABP1_DIV_DEFAULT 0x00003180 /* AHB1=PLL6/3,APB1=AHB1/2 */
#endif
#define AXI_GATE_OFFSET_DRAM 0
/* ahb_gate0 offsets */
#define AHB_GATE_OFFSET_USB_OHCI1 30
#define AHB_GATE_OFFSET_USB_OHCI0 29
#ifdef CONFIG_MACH_SUN8I_H3
/*
* These are EHCI1 - EHCI3 in the datasheet (EHCI0 is for the OTG) we call
* them 0 - 2 like they were called on older SoCs.
*/
#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
#define AHB_GATE_OFFSET_NAND1 12
#define AHB_GATE_OFFSET_MMC3 11
#define AHB_GATE_OFFSET_MMC2 10
#define AHB_GATE_OFFSET_MMC1 9
#define AHB_GATE_OFFSET_MMC0 8
#define AHB_GATE_OFFSET_MMC(n) (AHB_GATE_OFFSET_MMC0 + (n))
#define AHB_GATE_OFFSET_DMA 6
#define AHB_GATE_OFFSET_SS 5
/* ahb_gate1 offsets */
#define AHB_GATE_OFFSET_DRC0 25
#define AHB_GATE_OFFSET_DE_FE0 14
#define AHB_GATE_OFFSET_DE_BE0 12
#define AHB_GATE_OFFSET_HDMI 11
#define AHB_GATE_OFFSET_LCD1 5
#define AHB_GATE_OFFSET_LCD0 4
#define CCM_MMC_CTRL_M(x) ((x) - 1)
#define CCM_MMC_CTRL_OCLK_DLY(x) ((x) << 8)
#define CCM_MMC_CTRL_N(x) ((x) << 16)
#define CCM_MMC_CTRL_SCLK_DLY(x) ((x) << 20)
#define CCM_MMC_CTRL_OSCM24 (0x0 << 24)
#define CCM_MMC_CTRL_PLL6 (0x1 << 24)
#define CCM_MMC_CTRL_ENABLE (0x1 << 31)
#define CCM_USB_CTRL_PHY0_RST (0x1 << 0)
#define CCM_USB_CTRL_PHY1_RST (0x1 << 1)
#define CCM_USB_CTRL_PHY2_RST (0x1 << 2)
#define CCM_USB_CTRL_PHY3_RST (0x1 << 3)
/* There is no global phy clk gate on sun6i, define as 0 */
#define CCM_USB_CTRL_PHYGATE 0
#define CCM_USB_CTRL_PHY0_CLK (0x1 << 8)
#define CCM_USB_CTRL_PHY1_CLK (0x1 << 9)
#define CCM_USB_CTRL_PHY2_CLK (0x1 << 10)
#define CCM_USB_CTRL_PHY3_CLK (0x1 << 11)
#ifdef CONFIG_MACH_SUN8I_H3
/*
* These are OHCI1 - OHCI3 in the datasheet (OHCI0 is for the OTG) we call
* them 0 - 2 like they were called on older SoCs.
*/
#define CCM_USB_CTRL_OHCI0_CLK (0x1 << 17)
#define CCM_USB_CTRL_OHCI1_CLK (0x1 << 18)
#define CCM_USB_CTRL_OHCI2_CLK (0x1 << 19)
#else
#define CCM_USB_CTRL_OHCI0_CLK (0x1 << 16)
#define CCM_USB_CTRL_OHCI1_CLK (0x1 << 17)
#endif
#define CCM_GMAC_CTRL_TX_CLK_SRC_MII 0x0
#define CCM_GMAC_CTRL_TX_CLK_SRC_EXT_RGMII 0x1
#define CCM_GMAC_CTRL_TX_CLK_SRC_INT_RGMII 0x2
#define CCM_GMAC_CTRL_GPIT_MII (0x0 << 2)
#define CCM_GMAC_CTRL_GPIT_RGMII (0x1 << 2)
#define CCM_GMAC_CTRL_RX_CLK_DELAY(x) ((x) << 5)
#define CCM_GMAC_CTRL_TX_CLK_DELAY(x) ((x) << 10)
#define MDFS_CLK_DEFAULT 0x81000002 /* PLL6 / 3 */
#define CCM_DRAMCLK_CFG_DIV(x) ((x - 1) << 0)
#define CCM_DRAMCLK_CFG_DIV_MASK (0xf << 0)
#define CCM_DRAMCLK_CFG_DIV0(x) ((x - 1) << 8)
#define CCM_DRAMCLK_CFG_DIV0_MASK (0xf << 8)
#define CCM_DRAMCLK_CFG_SRC_PLL5 (0x0 << 20)
#define CCM_DRAMCLK_CFG_SRC_PLL6x2 (0x1 << 20)
#define CCM_DRAMCLK_CFG_SRC_PLL11 (0x1 << 20) /* A64 only */
#define CCM_DRAMCLK_CFG_SRC_MASK (0x3 << 20)
#define CCM_DRAMCLK_CFG_UPD (0x1 << 16)
#define CCM_DRAMCLK_CFG_RST (0x1 << 31)
#define CCM_DRAMPLL_CFG_SRC_PLL5 (0x0 << 16) /* Select PLL5 (DDR0) */
#define CCM_DRAMPLL_CFG_SRC_PLL11 (0x1 << 16) /* Select PLL11 (DDR1) */
#define CCM_DRAMPLL_CFG_SRC_MASK (0x1 << 16)
#define CCM_MBUS_RESET_RESET (0x1 << 31)
#define CCM_DRAM_GATE_OFFSET_DE_FE0 24
#define CCM_DRAM_GATE_OFFSET_DE_FE1 25
#define CCM_DRAM_GATE_OFFSET_DE_BE0 26
#define CCM_DRAM_GATE_OFFSET_DE_BE1 27
#define CCM_LCD_CH0_CTRL_PLL3 (0 << 24)
#define CCM_LCD_CH0_CTRL_PLL7 (1 << 24)
#define CCM_LCD_CH0_CTRL_PLL3_2X (2 << 24)
#define CCM_LCD_CH0_CTRL_PLL7_2X (3 << 24)
#define CCM_LCD_CH0_CTRL_MIPI_PLL (4 << 24)
/* No reset bit in ch0_clk_cfg (reset is controlled through ahb_reset1) */
#define CCM_LCD_CH0_CTRL_RST 0
#define CCM_LCD_CH0_CTRL_GATE (0x1 << 31)
#define CCM_LCD_CH1_CTRL_M(n) ((((n) - 1) & 0xf) << 0)
#define CCM_LCD_CH1_CTRL_HALF_SCLK1 0 /* no seperate sclk1 & 2 on sun6i */
#define CCM_LCD_CH1_CTRL_PLL3 (0 << 24)
#define CCM_LCD_CH1_CTRL_PLL7 (1 << 24)
#define CCM_LCD_CH1_CTRL_PLL3_2X (2 << 24)
#define CCM_LCD_CH1_CTRL_PLL7_2X (3 << 24)
#define CCM_LCD_CH1_CTRL_GATE (0x1 << 31)
#define CCM_HDMI_CTRL_M(n) ((((n) - 1) & 0xf) << 0)
#define CCM_HDMI_CTRL_PLL_MASK (3 << 24)
#define CCM_HDMI_CTRL_PLL3 (0 << 24)
#define CCM_HDMI_CTRL_PLL7 (1 << 24)
#define CCM_HDMI_CTRL_PLL3_2X (2 << 24)
#define CCM_HDMI_CTRL_PLL7_2X (3 << 24)
#define CCM_HDMI_CTRL_DDC_GATE (0x1 << 30)
#define CCM_HDMI_CTRL_GATE (0x1 << 31)
#if defined(CONFIG_MACH_SUN50I)
#define MBUS_CLK_DEFAULT 0x81000002 /* PLL6x2 / 3 */
#elif defined(CONFIG_MACH_SUN8I)
#define MBUS_CLK_DEFAULT 0x81000003 /* PLL6 / 4 */
#else
#define MBUS_CLK_DEFAULT 0x81000001 /* PLL6 / 2 */
#endif
#define MBUS_CLK_GATE (0x1 << 31)
#define CCM_PLL5_PATTERN 0xd1303333
#define CCM_PLL11_PATTERN 0xf5860000
/* ahb_reset0 offsets */
#define AHB_RESET_OFFSET_GMAC 17
#define AHB_RESET_OFFSET_MCTL 14
#define AHB_RESET_OFFSET_MMC3 11
#define AHB_RESET_OFFSET_MMC2 10
#define AHB_RESET_OFFSET_MMC1 9
#define AHB_RESET_OFFSET_MMC0 8
#define AHB_RESET_OFFSET_MMC(n) (AHB_RESET_OFFSET_MMC0 + (n))
#define AHB_RESET_OFFSET_SS 5
/* ahb_reset1 offsets */
#define AHB_RESET_OFFSET_SAT 26
#define AHB_RESET_OFFSET_DRC0 25
#define AHB_RESET_OFFSET_DE_FE0 14
#define AHB_RESET_OFFSET_DE_BE0 12
#define AHB_RESET_OFFSET_HDMI 11
#define AHB_RESET_OFFSET_LCD1 5
#define AHB_RESET_OFFSET_LCD0 4
/* ahb_reset2 offsets */
#define AHB_RESET_OFFSET_EPHY 2
#define AHB_RESET_OFFSET_LVDS 0
/* apb2 reset */
#define APB2_RESET_UART_SHIFT (16)
#define APB2_RESET_UART_MASK (0xff << APB2_RESET_UART_SHIFT)
#define APB2_RESET_TWI_SHIFT (0)
#define APB2_RESET_TWI_MASK (0xf << APB2_RESET_TWI_SHIFT)
/* CCM bits common to all Display Engine (and IEP) clock ctrl regs */
#define CCM_DE_CTRL_M(n) ((((n) - 1) & 0xf) << 0)
#define CCM_DE_CTRL_PLL_MASK (0xf << 24)
#define CCM_DE_CTRL_PLL3 (0 << 24)
#define CCM_DE_CTRL_PLL7 (1 << 24)
#define CCM_DE_CTRL_PLL6_2X (2 << 24)
#define CCM_DE_CTRL_PLL8 (3 << 24)
#define CCM_DE_CTRL_PLL9 (4 << 24)
#define CCM_DE_CTRL_PLL10 (5 << 24)
#define CCM_DE_CTRL_GATE (1 << 31)
/* CCU security switch, H3 only */
#define CCM_SEC_SWITCH_MBUS_NONSEC (1 << 2)
#define CCM_SEC_SWITCH_BUS_NONSEC (1 << 1)
#define CCM_SEC_SWITCH_PLL_NONSEC (1 << 0)
#ifndef __ASSEMBLY__
diff --git a/arch/arm/include/asm/arch-sunxi/cpu_sun4i.h b/arch/arm/include/asm/arch-sunxi/cpu_sun4i.h
index 1e2c294..e8719b0 100644
--- a/arch/arm/include/asm/arch-sunxi/cpu_sun4i.h
+++ b/arch/arm/include/asm/arch-sunxi/cpu_sun4i.h
@@ -1,110 +1,114 @@
/*
* (C) Copyright 2007-2011
* Allwinner Technology Co., Ltd. <www.allwinnertech.com>
* Tom Cubie <tangliang at allwinnertech.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#ifndef _SUNXI_CPU_SUN4I_H
#define _SUNXI_CPU_SUN4I_H
#define SUNXI_SRAM_A1_BASE 0x00000000
#define SUNXI_SRAM_A1_SIZE (16 * 1024) /* 16 kiB */
#define SUNXI_SRAM_A2_BASE 0x00004000 /* 16 kiB */
#define SUNXI_SRAM_A3_BASE 0x00008000 /* 13 kiB */
#define SUNXI_SRAM_A4_BASE 0x0000b400 /* 3 kiB */
#define SUNXI_SRAM_D_BASE 0x00010000 /* 4 kiB */
#define SUNXI_SRAM_B_BASE 0x00020000 /* 64 kiB (secure) */
#ifdef CONFIG_MACH_SUN8I_A83T
#define SUNXI_CPUCFG_BASE 0x01700000
#endif
#define SUNXI_SRAMC_BASE 0x01c00000
#define SUNXI_DRAMC_BASE 0x01c01000
#define SUNXI_DMA_BASE 0x01c02000
#define SUNXI_NFC_BASE 0x01c03000
#define SUNXI_TS_BASE 0x01c04000
#ifdef CONFIG_MACH_SUN6I
#define SUNXI_SPI0_BASE 0x01c68000
#define SUNXI_SPI1_BASE 0x01c69000
#else
#define SUNXI_SPI0_BASE 0x01c05000
#define SUNXI_SPI1_BASE 0x01c06000
#endif
#define SUNXI_MS_BASE 0x01c07000
#define SUNXI_TVD_BASE 0x01c08000
#define SUNXI_CSI0_BASE 0x01c09000
#define SUNXI_TVE0_BASE 0x01c0a000
#define SUNXI_EMAC_BASE 0x01c0b000
#define SUNXI_LCD0_BASE 0x01c0C000
#define SUNXI_LCD1_BASE 0x01c0d000
#define SUNXI_VE_BASE 0x01c0e000
#define SUNXI_MMC0_BASE 0x01c0f000
#define SUNXI_MMC1_BASE 0x01c10000
#define SUNXI_MMC2_BASE 0x01c11000
#define SUNXI_MMC3_BASE 0x01c12000
#ifdef CONFIG_SUNXI_GEN_SUN4I
#define SUNXI_USB0_BASE 0x01c13000
#define SUNXI_USB1_BASE 0x01c14000
#endif
#define SUNXI_SS_BASE 0x01c15000
#define SUNXI_HDMI_BASE 0x01c16000
#ifdef CONFIG_MACH_SUN6I
#define SUNXI_SPI2_BASE 0x01c6a000
#else
#define SUNXI_SPI2_BASE 0x01c17000
#endif
#define SUNXI_SATA_BASE 0x01c18000
#ifdef CONFIG_SUNXI_GEN_SUN4I
#define SUNXI_PATA_BASE 0x01c19000
#define SUNXI_ACE_BASE 0x01c1a000
#define SUNXI_TVE1_BASE 0x01c1b000
#define SUNXI_USB2_BASE 0x01c1c000
#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
#endif
#define SUNXI_CSI1_BASE 0x01c1d000
#define SUNXI_TZASC_BASE 0x01c1e000
#ifdef CONFIG_MACH_SUN6I
#define SUNXI_SPI3_BASE 0x01c6b000
#else
#define SUNXI_SPI3_BASE 0x01c1f000
#endif
#define SUNXI_CCM_BASE 0x01c20000
#define SUNXI_INTC_BASE 0x01c20400
#define SUNXI_PIO_BASE 0x01c20800
#define SUNXI_TIMER_BASE 0x01c20c00
#ifndef CONFIG_SUNXI_GEN_SUN6I
#define SUNXI_PWM_BASE 0x01c20e00
#endif
#define SUNXI_SPDIF_BASE 0x01c21000
#ifdef CONFIG_SUNXI_GEN_SUN6I
#define SUNXI_PWM_BASE 0x01c21400
#else
#define SUNXI_AC97_BASE 0x01c21400
#endif
#define SUNXI_IR0_BASE 0x01c21800
#define SUNXI_IR1_BASE 0x01c21c00
#define SUNXI_IIS_BASE 0x01c22400
#define SUNXI_LRADC_BASE 0x01c22800
#define SUNXI_AD_DA_BASE 0x01c22c00
#define SUNXI_KEYPAD_BASE 0x01c23000
#define SUNXI_TZPC_BASE 0x01c23400
#if defined(CONFIG_MACH_SUN8I_A83T) || defined(CONFIG_MACH_SUN8I_H3) || \
diff --git a/arch/arm/include/asm/arch-sunxi/usb_phy.h b/arch/arm/include/asm/arch-sunxi/usb_phy.h
index cef6c98..e374daa 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 278587b..496eeb0 100644
--- a/arch/arm/mach-sunxi/usb_phy.c
+++ b/arch/arm/mach-sunxi/usb_phy.c
@@ -1,46 +1,48 @@
/*
* Sunxi usb-phy code
*
* Copyright (C) 2015 Hans de Goede <hdegoede at redhat.com>
* Copyright (C) 2014 Roman Byshko <rbyshko at gmail.com>
*
* Based on code from
* Allwinner Technology Co., Ltd. <www.allwinnertech.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <asm/arch/clock.h>
#include <asm/arch/cpu.h>
#include <asm/arch/usb_phy.h>
#include <asm/gpio.h>
#include <asm/io.h>
#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
#endif
#define SUNXI_USB_PASSBY_EN 1
#define SUNXI_EHCI_AHB_ICHR8_EN (1 << 10)
#define SUNXI_EHCI_AHB_INCR4_BURST_EN (1 << 9)
#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)
#define SUNXI_PHY_CTL_SIDDQ BIT(3)
/* A83T HSIC specific bits */
#define SUNXI_EHCI_HS_FORCE BIT(20)
#define SUNXI_EHCI_CONNECT_DET BIT(17)
#define SUNXI_EHCI_CONNECT_INT BIT(16)
#define SUNXI_EHCI_HSIC BIT(1)
@@ -117,42 +119,50 @@ static int get_id_detect_gpio(int index)
__maybe_unused static void usb_phy_write(struct sunxi_usb_phy *phy, int addr,
int data, int len)
{
int j = 0, usbc_bit = 0;
void *dest = (void *)SUNXI_USB0_BASE + SUNXI_USB_CSR;
#ifdef CONFIG_MACH_SUN8I_A33
/* CSR needs to be explicitly initialized to 0 on A33 */
writel(0, dest);
#endif
usbc_bit = 1 << (phy->id * 2);
for (j = 0; j < len; j++) {
/* set the bit address to be written */
clrbits_le32(dest, 0xff << 8);
setbits_le32(dest, (addr + j) << 8);
clrbits_le32(dest, usbc_bit);
/* set data bit */
if (data & 0x1)
setbits_le32(dest, 1 << 7);
else
clrbits_le32(dest, 1 << 7);
setbits_le32(dest, usbc_bit);
clrbits_le32(dest, usbc_bit);
data >>= 1;
}
}
-#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,52 +172,60 @@ 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
usb_phy_write(phy, 0x2a, 3, 2);
#endif
return;
}
#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;
addr = (void *)phy->base + SUNXI_USB_PMU_IRQ_ENABLE;
bits = SUNXI_EHCI_AHB_ICHR8_EN |
SUNXI_EHCI_AHB_INCR4_BURST_EN |
SUNXI_EHCI_AHB_INCRX_ALIGN_EN |
SUNXI_EHCI_ULPI_BYPASS_EN;
#ifdef CONFIG_MACH_SUN8I_A83T
if (phy->id == 2)
bits |= SUNXI_EHCI_HS_FORCE |
SUNXI_EHCI_CONNECT_INT |
SUNXI_EHCI_HSIC;
#endif
if (enable)
setbits_le32(addr, bits);
else
clrbits_le32(addr, bits);
return;
}
@@ -223,48 +241,42 @@ void sunxi_usb_phy_enable_squelch_detect(int index, int enable)
void sunxi_usb_phy_init(int index)
{
struct sunxi_usb_phy *phy = &sunxi_usb_phy[index];
struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
phy->init_count++;
if (phy->init_count != 1)
return;
setbits_le32(&ccm->usb_clk_cfg, phy->usb_rst_mask);
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,
SUNXI_PHY_CTL_VBUSVLDEXT);
clrbits_le32(SUNXI_USB0_BASE + SUNXI_USB_CSR,
SUNXI_PHY_CTL_SIDDQ);
}
#endif
}
void sunxi_usb_phy_exit(int index)
{
struct sunxi_usb_phy *phy = &sunxi_usb_phy[index];
struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
phy->init_count--;
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,
SUNXI_PHY_CTL_SIDDQ);
}
#endif
clrbits_le32(&ccm->usb_clk_cfg, phy->usb_rst_mask);
}
diff --git a/drivers/usb/host/ehci-sunxi.c b/drivers/usb/host/ehci-sunxi.c
index 5bb97ff..af5ae38 100644
--- a/drivers/usb/host/ehci-sunxi.c
+++ b/drivers/usb/host/ehci-sunxi.c
@@ -34,58 +34,73 @@ struct ehci_sunxi_priv {
static int ehci_usb_probe(struct udevice *dev)
{
struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
struct usb_platdata *plat = dev_get_platdata(dev);
struct ehci_sunxi_priv *priv = dev_get_priv(dev);
struct ehci_hccr *hccr = (struct ehci_hccr *)dev_get_addr(dev);
struct ehci_hcor *hcor;
int extra_ahb_gate_mask = 0;
/*
* This should go away once we've moved to the driver model for
* clocks resp. phys.
*/
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;
priv->ahb_gate_mask <<= priv->phy_index * AHB_CLK_DIST;
extra_ahb_gate_mask <<= priv->phy_index * AHB_CLK_DIST;
priv->phy_index++; /* Non otg phys start at 1 */
setbits_le32(&ccm->ahb_gate0,
priv->ahb_gate_mask | extra_ahb_gate_mask);
#ifdef CONFIG_SUNXI_GEN_SUN6I
setbits_le32(&ccm->ahb_reset0_cfg,
priv->ahb_gate_mask | extra_ahb_gate_mask);
#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 +
HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
return ehci_register(dev, hccr, hcor, NULL, 0, plat->init_type);
}
static int ehci_usb_remove(struct udevice *dev)
{
struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
struct ehci_sunxi_priv *priv = dev_get_priv(dev);
int ret;
ret = ehci_deregister(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
clrbits_le32(&ccm->ahb_reset0_cfg, priv->ahb_gate_mask);
#endif
clrbits_le32(&ccm->ahb_gate0, priv->ahb_gate_mask);
return 0;
}
diff --git a/drivers/usb/host/ohci-sunxi.c b/drivers/usb/host/ohci-sunxi.c
index 0c45eec..047c3a9 100644
--- a/drivers/usb/host/ohci-sunxi.c
+++ b/drivers/usb/host/ohci-sunxi.c
@@ -35,60 +35,68 @@ struct ohci_sunxi_priv {
static int ohci_usb_probe(struct udevice *dev)
{
struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
struct usb_bus_priv *bus_priv = dev_get_uclass_priv(dev);
struct ohci_sunxi_priv *priv = dev_get_priv(dev);
struct ohci_regs *regs = (struct ohci_regs *)dev_get_addr(dev);
int extra_ahb_gate_mask = 0;
bus_priv->companion = true;
/*
* This should go away once we've moved to the driver model for
* clocks resp. phys.
*/
priv->ahb_gate_mask = 1 << AHB_GATE_OFFSET_USB_OHCI0;
#ifdef CONFIG_MACH_SUN8I_H3
extra_ahb_gate_mask = 1 << AHB_GATE_OFFSET_USB_EHCI0;
#endif
priv->usb_gate_mask = CCM_USB_CTRL_OHCI0_CLK;
priv->phy_index = ((uintptr_t)regs - (SUNXI_USB1_BASE + 0x400)) / BASE_DIST;
priv->ahb_gate_mask <<= priv->phy_index * AHB_CLK_DIST;
extra_ahb_gate_mask <<= priv->phy_index * AHB_CLK_DIST;
priv->usb_gate_mask <<= priv->phy_index;
priv->phy_index++; /* Non otg phys start at 1 */
setbits_le32(&ccm->ahb_gate0,
priv->ahb_gate_mask | extra_ahb_gate_mask);
setbits_le32(&ccm->usb_clk_cfg, priv->usb_gate_mask);
#ifdef CONFIG_SUNXI_GEN_SUN6I
setbits_le32(&ccm->ahb_reset0_cfg,
priv->ahb_gate_mask | extra_ahb_gate_mask);
#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);
}
static int ohci_usb_remove(struct udevice *dev)
{
struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
struct ohci_sunxi_priv *priv = dev_get_priv(dev);
int ret;
ret = ohci_deregister(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
clrbits_le32(&ccm->ahb_reset0_cfg, priv->ahb_gate_mask);
#endif
clrbits_le32(&ccm->usb_clk_cfg, priv->usb_gate_mask);
clrbits_le32(&ccm->ahb_gate0, priv->ahb_gate_mask);
return 0;
}
diff --git a/drivers/usb/musb-new/sunxi.c b/drivers/usb/musb-new/sunxi.c
index 469377f..0dab99d 100644
--- a/drivers/usb/musb-new/sunxi.c
+++ b/drivers/usb/musb-new/sunxi.c
@@ -1,77 +1,81 @@
/*
* Allwinner SUNXI "glue layer"
*
* Copyright © 2015 Hans de Goede <hdegoede at redhat.com>
* Copyright © 2013 Jussi Kivilinna <jussi.kivilinna at iki.fi>
*
* Based on the sw_usb "Allwinner OTG Dual Role Controller" code.
* Copyright 2007-2012 (C) Allwinner Technology Co., Ltd.
* javen <javen at allwinnertech.com>
*
* Based on the DA8xx "glue layer" code.
* Copyright (c) 2008-2009 MontaVista Software, Inc. <source at mvista.com>
* Copyright (C) 2005-2006 by Texas Instruments
*
* This file is part of the Inventra Controller Driver for Linux.
*
* SPDX-License-Identifier: GPL-2.0
*/
#include <common.h>
#include <asm/arch/cpu.h>
#include <asm/arch/clock.h>
#include <asm/arch/gpio.h>
#include <asm/arch/usb_phy.h>
#include <asm-generic/gpio.h>
#include <dm/lists.h>
#include <dm/root.h>
#include <linux/usb/musb.h>
#include "linux-compat.h"
#include "musb_core.h"
#include "musb_uboot.h"
/******************************************************************************
******************************************************************************
* From the Allwinner driver
******************************************************************************
******************************************************************************/
/******************************************************************************
* From include/sunxi_usb_bsp.h
******************************************************************************/
/* reg offsets */
#define USBC_REG_o_ISCR 0x0400
#define USBC_REG_o_PHYCTL 0x0404
#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 */
#define USBC_BP_ISCR_VBUS_VALID_FROM_DATA 30
#define USBC_BP_ISCR_VBUS_VALID_FROM_VBUS 29
#define USBC_BP_ISCR_EXT_ID_STATUS 28
#define USBC_BP_ISCR_EXT_DM_STATUS 27
#define USBC_BP_ISCR_EXT_DP_STATUS 26
#define USBC_BP_ISCR_MERGED_VBUS_STATUS 25
#define USBC_BP_ISCR_MERGED_ID_STATUS 24
#define USBC_BP_ISCR_ID_PULLUP_EN 17
#define USBC_BP_ISCR_DPDM_PULLUP_EN 16
#define USBC_BP_ISCR_FORCE_ID 14
#define USBC_BP_ISCR_FORCE_VBUS_VALID 12
#define USBC_BP_ISCR_VBUS_VALID_SRC 10
#define USBC_BP_ISCR_HOSC_EN 7
#define USBC_BP_ISCR_VBUS_CHANGE_DETECT 6
#define USBC_BP_ISCR_ID_CHANGE_DETECT 5
#define USBC_BP_ISCR_DPDM_CHANGE_DETECT 4
#define USBC_BP_ISCR_IRQ_ENABLE 3
#define USBC_BP_ISCR_VBUS_CHANGE_DETECT_EN 2
#define USBC_BP_ISCR_ID_CHANGE_DETECT_EN 1
#define USBC_BP_ISCR_DPDM_CHANGE_DETECT_EN 0
/******************************************************************************
* From usbc/usbc.c
******************************************************************************/
@@ -152,16 +156,21 @@ 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
******************************************************************************/
@@ -256,30 +265,35 @@ static void sunxi_musb_disable(struct musb *musb)
static int sunxi_musb_init(struct musb *musb)
{
struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
pr_debug("%s():\n", __func__);
musb->isr = sunxi_musb_interrupt;
setbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_USB0);
#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);
USBC_EnableIdPullUp(musb->mregs);
if (is_host_enabled(musb)) {
/* Host mode */
USBC_ForceIdToLow(musb->mregs);
} else {
/* Peripheral mode */
USBC_ForceIdToHigh(musb->mregs);
}
USBC_ForceVbusValidToHigh(musb->mregs);
return 0;
}
@@ -313,41 +327,45 @@ static int musb_usb_remove(struct udevice *dev);
static int musb_usb_probe(struct udevice *dev)
{
struct musb_host_data *host = dev_get_priv(dev);
struct usb_bus_priv *priv = dev_get_uclass_priv(dev);
int ret;
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;
ret = musb_lowlevel_init(host);
if (ret == 0)
printf("MUSB OTG\n");
else
musb_usb_remove(dev);
return ret;
}
static int musb_usb_remove(struct udevice *dev)
{
struct musb_host_data *host = dev_get_priv(dev);
struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
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
clrbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_USB0);
free(host->host);
host->host = NULL;
return 0;
}
@@ -365,16 +383,16 @@ U_BOOT_DRIVER(usb_musb) = {
void sunxi_musb_board_init(void)
{
#ifdef CONFIG_USB_MUSB_HOST
struct udevice *dev;
/*
* Bind the driver directly for now as musb linux kernel support is
* still pending upstream so our dts files do not have the necessary
* nodes yet. TODO: Remove this as soon as the dts nodes are in place
* and bind by compatible instead.
*/
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
}
--
1.9.1
More information about the U-Boot
mailing list