From b62cdbddedc3e0c42f3b017a887e4ed7aaa6a4da Mon Sep 17 00:00:00 2001 From: Vasily Khoruzhick Date: Thu, 7 Jun 2018 19:23:38 -0700 Subject: [PATCH 1/5] sunxi: clock: Fix EHCI and OHCI clocks on A64 EHCI0 is bit 24, EHCI1 - 25, OHCI0 - 28, OHCI1 - 29 Fixes commit fef73766d9ad ("sunxi: clock: Fix OHCI clock gating for H3/H5") Signed-off-by: Vasily Khoruzhick --- arch/arm/include/asm/arch-sunxi/clock_sun6i.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/arm/include/asm/arch-sunxi/clock_sun6i.h b/arch/arm/include/asm/arch-sunxi/clock_sun6i.h index 8acf79f..8afeaf8 100644 --- a/arch/arm/include/asm/arch-sunxi/clock_sun6i.h +++ b/arch/arm/include/asm/arch-sunxi/clock_sun6i.h @@ -280,8 +280,10 @@ struct sunxi_ccm_reg { #define AHB_GATE_OFFSET_USB_EHCI1 26 #define AHB_GATE_OFFSET_USB_EHCI0 24 #elif defined(CONFIG_MACH_SUN50I) -#define AHB_GATE_OFFSET_USB_OHCI0 29 -#define AHB_GATE_OFFSET_USB_EHCI0 25 +#define AHB_GATE_OFFSET_USB_OHCI0 28 +#define AHB_GATE_OFFSET_USB_OHCI1 29 +#define AHB_GATE_OFFSET_USB_EHCI0 24 +#define AHB_GATE_OFFSET_USB_EHCI1 25 #else #define AHB_GATE_OFFSET_USB_OHCI1 30 #define AHB_GATE_OFFSET_USB_OHCI0 29 From 1ed9c11188853d0a69baf93a64f4bcfefa0c5a99 Mon Sep 17 00:00:00 2001 From: Vasily Khoruzhick Date: Thu, 7 Jun 2018 19:23:39 -0700 Subject: [PATCH 2/5] usb: sunxi: ehci: get rid of ifdefs We can use compatibles instead. Signed-off-by: Vasily Khoruzhick --- drivers/usb/host/ehci-sunxi.c | 83 ++++++++++++++++++++++++++++++++----------- 1 file changed, 63 insertions(+), 20 deletions(-) diff --git a/drivers/usb/host/ehci-sunxi.c b/drivers/usb/host/ehci-sunxi.c index 360efc9..35fbe03 100644 --- a/drivers/usb/host/ehci-sunxi.c +++ b/drivers/usb/host/ehci-sunxi.c @@ -22,11 +22,17 @@ #define AHB_CLK_DIST 1 #endif +struct ehci_sunxi_cfg { + bool has_reset; + u32 extra_ahb_gate_mask; +}; + struct ehci_sunxi_priv { struct ehci_ctrl ehci; struct sunxi_ccm_reg *ccm; int ahb_gate_mask; /* Mask of ahb_gate0 clk gate bits for this hcd */ struct phy phy; + const struct ehci_sunxi_cfg *cfg; }; static int ehci_usb_probe(struct udevice *dev) @@ -38,6 +44,7 @@ static int ehci_usb_probe(struct udevice *dev) int extra_ahb_gate_mask = 0; int phys, ret; + priv->cfg = (const struct ehci_sunxi_cfg *)dev_get_driver_data(dev); priv->ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; if (IS_ERR(priv->ccm)) return PTR_ERR(priv->ccm); @@ -72,18 +79,15 @@ no_phy: * clocks resp. phys. */ priv->ahb_gate_mask = 1 << AHB_GATE_OFFSET_USB_EHCI0; -#if defined(CONFIG_MACH_SUNXI_H3_H5) || defined(CONFIG_MACH_SUN50I) - extra_ahb_gate_mask = 1 << AHB_GATE_OFFSET_USB_OHCI0; -#endif + extra_ahb_gate_mask = priv->cfg->extra_ahb_gate_mask; priv->ahb_gate_mask <<= phys * AHB_CLK_DIST; extra_ahb_gate_mask <<= phys * AHB_CLK_DIST; setbits_le32(&priv->ccm->ahb_gate0, priv->ahb_gate_mask | extra_ahb_gate_mask); -#ifdef CONFIG_SUNXI_GEN_SUN6I - setbits_le32(&priv->ccm->ahb_reset0_cfg, - priv->ahb_gate_mask | extra_ahb_gate_mask); -#endif + if (priv->cfg->has_reset) + setbits_le32(&priv->ccm->ahb_reset0_cfg, + priv->ahb_gate_mask | extra_ahb_gate_mask); hcor = (struct ehci_hcor *)((uintptr_t)hccr + HC_LENGTH(ehci_readl(&hccr->cr_capbase))); @@ -108,25 +112,64 @@ static int ehci_usb_remove(struct udevice *dev) if (ret) return ret; -#ifdef CONFIG_SUNXI_GEN_SUN6I - clrbits_le32(&priv->ccm->ahb_reset0_cfg, priv->ahb_gate_mask); -#endif + if (priv->cfg->has_reset) + clrbits_le32(&priv->ccm->ahb_reset0_cfg, priv->ahb_gate_mask); clrbits_le32(&priv->ccm->ahb_gate0, priv->ahb_gate_mask); return 0; } +static const struct ehci_sunxi_cfg sun4i_a10_cfg = { + .has_reset = false, +}; + +static const struct ehci_sunxi_cfg sun6i_a31_cfg = { + .has_reset = true, +}; + +static const struct ehci_sunxi_cfg sun8i_h3_cfg = { + .has_reset = true, + .extra_ahb_gate_mask = 1 << AHB_GATE_OFFSET_USB_OHCI0, +}; + static const struct udevice_id ehci_usb_ids[] = { - { .compatible = "allwinner,sun4i-a10-ehci", }, - { .compatible = "allwinner,sun5i-a13-ehci", }, - { .compatible = "allwinner,sun6i-a31-ehci", }, - { .compatible = "allwinner,sun7i-a20-ehci", }, - { .compatible = "allwinner,sun8i-a23-ehci", }, - { .compatible = "allwinner,sun8i-a83t-ehci", }, - { .compatible = "allwinner,sun8i-h3-ehci", }, - { .compatible = "allwinner,sun9i-a80-ehci", }, - { .compatible = "allwinner,sun50i-a64-ehci", }, - { } + { + .compatible = "allwinner,sun4i-a10-ehci", + .data = (ulong)&sun4i_a10_cfg, + }, + { + .compatible = "allwinner,sun5i-a13-ehci", + .data = (ulong)&sun4i_a10_cfg, + }, + { + .compatible = "allwinner,sun6i-a31-ehci", + .data = (ulong)&sun6i_a31_cfg, + }, + { + .compatible = "allwinner,sun7i-a20-ehci", + .data = (ulong)&sun4i_a10_cfg, + }, + { + .compatible = "allwinner,sun8i-a23-ehci", + .data = (ulong)&sun6i_a31_cfg, + }, + { + .compatible = "allwinner,sun8i-a83t-ehci", + .data = (ulong)&sun6i_a31_cfg, + }, + { + .compatible = "allwinner,sun8i-h3-ehci", + .data = (ulong)&sun8i_h3_cfg, + }, + { + .compatible = "allwinner,sun9i-a80-ehci", + .data = (ulong)&sun6i_a31_cfg, + }, + { + .compatible = "allwinner,sun50i-a64-ehci", + .data = (ulong)&sun8i_h3_cfg, + }, + { /* sentinel */ } }; U_BOOT_DRIVER(ehci_sunxi) = { From 56830cee3a2ffca3e062cd5c73a071b51e2055ff Mon Sep 17 00:00:00 2001 From: Vasily Khoruzhick Date: Thu, 7 Jun 2018 19:23:40 -0700 Subject: [PATCH 3/5] usb: sunxi: ohci: get rid of ifdefs We can use compatibles instead. Signed-off-by: Vasily Khoruzhick --- drivers/usb/host/ohci-sunxi.c | 83 ++++++++++++++++++++++++++++++++----------- 1 file changed, 63 insertions(+), 20 deletions(-) diff --git a/drivers/usb/host/ohci-sunxi.c b/drivers/usb/host/ohci-sunxi.c index ce2b47a..19f99ad 100644 --- a/drivers/usb/host/ohci-sunxi.c +++ b/drivers/usb/host/ohci-sunxi.c @@ -22,12 +22,18 @@ #define AHB_CLK_DIST 1 #endif +struct ohci_sunxi_cfg { + bool has_reset; + u32 extra_ahb_gate_mask; +}; + struct ohci_sunxi_priv { struct sunxi_ccm_reg *ccm; ohci_t ohci; int ahb_gate_mask; /* Mask of ahb_gate0 clk gate bits for this hcd */ int usb_gate_mask; /* Mask of usb_clk_cfg clk gate bits for this hcd */ struct phy phy; + const struct ohci_sunxi_cfg *cfg; }; static int ohci_usb_probe(struct udevice *dev) @@ -38,6 +44,7 @@ static int ohci_usb_probe(struct udevice *dev) int extra_ahb_gate_mask = 0; int phys, ret; + priv->cfg = (const struct ohci_sunxi_cfg *)dev_get_driver_data(dev); priv->ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; if (IS_ERR(priv->ccm)) return PTR_ERR(priv->ccm); @@ -74,9 +81,7 @@ no_phy: * 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 + extra_ahb_gate_mask = priv->cfg->extra_ahb_gate_mask; priv->usb_gate_mask = CCM_USB_CTRL_OHCI0_CLK; priv->ahb_gate_mask <<= phys * AHB_CLK_DIST; extra_ahb_gate_mask <<= phys * AHB_CLK_DIST; @@ -85,10 +90,9 @@ no_phy: setbits_le32(&priv->ccm->ahb_gate0, priv->ahb_gate_mask | extra_ahb_gate_mask); setbits_le32(&priv->ccm->usb_clk_cfg, priv->usb_gate_mask); -#ifdef CONFIG_SUNXI_GEN_SUN6I - setbits_le32(&priv->ccm->ahb_reset0_cfg, - priv->ahb_gate_mask | extra_ahb_gate_mask); -#endif + if (priv->cfg->has_reset) + setbits_le32(&priv->ccm->ahb_reset0_cfg, + priv->ahb_gate_mask | extra_ahb_gate_mask); return ohci_register(dev, regs); } @@ -110,26 +114,65 @@ static int ohci_usb_remove(struct udevice *dev) if (ret) return ret; -#ifdef CONFIG_SUNXI_GEN_SUN6I - clrbits_le32(&priv->ccm->ahb_reset0_cfg, priv->ahb_gate_mask); -#endif + if (priv->cfg->has_reset) + clrbits_le32(&priv->ccm->ahb_reset0_cfg, priv->ahb_gate_mask); clrbits_le32(&priv->ccm->usb_clk_cfg, priv->usb_gate_mask); clrbits_le32(&priv->ccm->ahb_gate0, priv->ahb_gate_mask); return 0; } +static const struct ohci_sunxi_cfg sun4i_a10_cfg = { + .has_reset = false, +}; + +static const struct ohci_sunxi_cfg sun6i_a31_cfg = { + .has_reset = true, +}; + +static const struct ohci_sunxi_cfg sun8i_h3_cfg = { + .has_reset = true, + .extra_ahb_gate_mask = 1 << AHB_GATE_OFFSET_USB_EHCI0, +}; + static const struct udevice_id ohci_usb_ids[] = { - { .compatible = "allwinner,sun4i-a10-ohci", }, - { .compatible = "allwinner,sun5i-a13-ohci", }, - { .compatible = "allwinner,sun6i-a31-ohci", }, - { .compatible = "allwinner,sun7i-a20-ohci", }, - { .compatible = "allwinner,sun8i-a23-ohci", }, - { .compatible = "allwinner,sun8i-a83t-ohci", }, - { .compatible = "allwinner,sun8i-h3-ohci", }, - { .compatible = "allwinner,sun9i-a80-ohci", }, - { .compatible = "allwinner,sun50i-a64-ohci", }, - { } + { + .compatible = "allwinner,sun4i-a10-ohci", + .data = (ulong)&sun4i_a10_cfg, + }, + { + .compatible = "allwinner,sun5i-a13-ohci", + .data = (ulong)&sun4i_a10_cfg, + }, + { + .compatible = "allwinner,sun6i-a31-ohci", + .data = (ulong)&sun6i_a31_cfg, + }, + { + .compatible = "allwinner,sun7i-a20-ohci", + .data = (ulong)&sun4i_a10_cfg, + }, + { + .compatible = "allwinner,sun8i-a23-ohci", + .data = (ulong)&sun6i_a31_cfg, + }, + { + .compatible = "allwinner,sun8i-a83t-ohci", + .data = (ulong)&sun6i_a31_cfg, + }, + { + .compatible = "allwinner,sun8i-h3-ohci", + .data = (ulong)&sun8i_h3_cfg, + }, + { + .compatible = "allwinner,sun9i-a80-ohci", + .data = (ulong)&sun6i_a31_cfg, + }, + { + .compatible = "allwinner,sun50i-a64-ohci", + .data = (ulong)&sun6i_a31_cfg, + }, + { /* sentinel */ } }; U_BOOT_DRIVER(usb_ohci) = { From 11bb62768de4c1508202ce9dd572f17fc3d95779 Mon Sep 17 00:00:00 2001 From: Vasily Khoruzhick Date: Thu, 7 Jun 2018 19:23:41 -0700 Subject: [PATCH 4/5] usb: sunxi: sun50i: enable OHCI0 clock when OHCI1 is in use On A64 OHCI1 clock source is OHCI0 clock, so we need to enable OHCI0 clock when OHCI1 is in use. Fixes commit dd3228170ad7 ("usb: sunxi: Switch to use generic-phy") Signed-off-by: Vasily Khoruzhick --- drivers/usb/host/ohci-sunxi.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/usb/host/ohci-sunxi.c b/drivers/usb/host/ohci-sunxi.c index 19f99ad..2b99169 100644 --- a/drivers/usb/host/ohci-sunxi.c +++ b/drivers/usb/host/ohci-sunxi.c @@ -25,6 +25,7 @@ struct ohci_sunxi_cfg { bool has_reset; u32 extra_ahb_gate_mask; + u32 extra_usb_gate_mask; }; struct ohci_sunxi_priv { @@ -89,7 +90,8 @@ no_phy: setbits_le32(&priv->ccm->ahb_gate0, priv->ahb_gate_mask | extra_ahb_gate_mask); - setbits_le32(&priv->ccm->usb_clk_cfg, priv->usb_gate_mask); + setbits_le32(&priv->ccm->usb_clk_cfg, + priv->usb_gate_mask | priv->cfg->extra_usb_gate_mask); if (priv->cfg->has_reset) setbits_le32(&priv->ccm->ahb_reset0_cfg, priv->ahb_gate_mask | extra_ahb_gate_mask); @@ -135,6 +137,12 @@ static const struct ohci_sunxi_cfg sun8i_h3_cfg = { .extra_ahb_gate_mask = 1 << AHB_GATE_OFFSET_USB_EHCI0, }; +static const struct ohci_sunxi_cfg sun50i_a64_cfg = { + .has_reset = true, + .extra_ahb_gate_mask = 1 << AHB_GATE_OFFSET_USB_EHCI0, + .extra_usb_gate_mask = CCM_USB_CTRL_OHCI0_CLK, +}; + static const struct udevice_id ohci_usb_ids[] = { { .compatible = "allwinner,sun4i-a10-ohci", @@ -170,7 +178,7 @@ static const struct udevice_id ohci_usb_ids[] = { }, { .compatible = "allwinner,sun50i-a64-ohci", - .data = (ulong)&sun6i_a31_cfg, + .data = (ulong)&sun50i_a64_cfg, }, { /* sentinel */ } }; From b9f34757db5dcde9ccfa6ce35705b025bc4843fc Mon Sep 17 00:00:00 2001 From: Vasily Khoruzhick Date: Wed, 13 Jun 2018 23:19:34 -0700 Subject: [PATCH 5/5] usb: sunxi: access ahb_reset0_cfg in CCM using its offset struct sunxi_ccm_reg doesn't have ahb_reset0_cfg on sun4i and sun5i, thus compilation fails with: drivers/usb/host/ohci-sunxi.c:96:26: error: 'struct sunxi_ccm_reg' has no member named 'ahb_reset0_cfg' Access this reg using its offset to fix this issue. Fixes commit 1ed9c1118 ("usb: sunxi: ehci: get rid of ifdefs") and commit 56830cee3 ("usb: sunxi: ohci: get rid of ifdefs") Signed-off-by: Vasily Khoruzhick --- drivers/usb/host/ehci-sunxi.c | 21 ++++++++++++++++++--- drivers/usb/host/ohci-sunxi.c | 22 +++++++++++++++++++--- 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/drivers/usb/host/ehci-sunxi.c b/drivers/usb/host/ehci-sunxi.c index 35fbe03..97d06d5 100644 --- a/drivers/usb/host/ehci-sunxi.c +++ b/drivers/usb/host/ehci-sunxi.c @@ -22,14 +22,19 @@ #define AHB_CLK_DIST 1 #endif +#define SUN6I_AHB_RESET0_CFG_OFFSET 0x2c0 +#define SUN9I_AHB_RESET0_CFG_OFFSET 0x5a0 + struct ehci_sunxi_cfg { bool has_reset; u32 extra_ahb_gate_mask; + u32 reset0_cfg_offset; }; struct ehci_sunxi_priv { struct ehci_ctrl ehci; struct sunxi_ccm_reg *ccm; + u32 *reset0_cfg; int ahb_gate_mask; /* Mask of ahb_gate0 clk gate bits for this hcd */ struct phy phy; const struct ehci_sunxi_cfg *cfg; @@ -49,6 +54,9 @@ static int ehci_usb_probe(struct udevice *dev) if (IS_ERR(priv->ccm)) return PTR_ERR(priv->ccm); + priv->reset0_cfg = (void *)priv->ccm + + priv->cfg->reset0_cfg_offset; + phys = dev_count_phandle_with_args(dev, "phys", "#phy-cells"); if (phys < 0) { phys = 0; @@ -86,7 +94,7 @@ no_phy: setbits_le32(&priv->ccm->ahb_gate0, priv->ahb_gate_mask | extra_ahb_gate_mask); if (priv->cfg->has_reset) - setbits_le32(&priv->ccm->ahb_reset0_cfg, + setbits_le32(priv->reset0_cfg, priv->ahb_gate_mask | extra_ahb_gate_mask); hcor = (struct ehci_hcor *)((uintptr_t)hccr + @@ -113,7 +121,7 @@ static int ehci_usb_remove(struct udevice *dev) return ret; if (priv->cfg->has_reset) - clrbits_le32(&priv->ccm->ahb_reset0_cfg, priv->ahb_gate_mask); + clrbits_le32(priv->reset0_cfg, priv->ahb_gate_mask); clrbits_le32(&priv->ccm->ahb_gate0, priv->ahb_gate_mask); return 0; @@ -125,11 +133,18 @@ static const struct ehci_sunxi_cfg sun4i_a10_cfg = { static const struct ehci_sunxi_cfg sun6i_a31_cfg = { .has_reset = true, + .reset0_cfg_offset = SUN6I_AHB_RESET0_CFG_OFFSET, }; static const struct ehci_sunxi_cfg sun8i_h3_cfg = { .has_reset = true, .extra_ahb_gate_mask = 1 << AHB_GATE_OFFSET_USB_OHCI0, + .reset0_cfg_offset = SUN6I_AHB_RESET0_CFG_OFFSET, +}; + +static const struct ehci_sunxi_cfg sun9i_a80_cfg = { + .has_reset = true, + .reset0_cfg_offset = SUN9I_AHB_RESET0_CFG_OFFSET, }; static const struct udevice_id ehci_usb_ids[] = { @@ -163,7 +178,7 @@ static const struct udevice_id ehci_usb_ids[] = { }, { .compatible = "allwinner,sun9i-a80-ehci", - .data = (ulong)&sun6i_a31_cfg, + .data = (ulong)&sun9i_a80_cfg, }, { .compatible = "allwinner,sun50i-a64-ehci", diff --git a/drivers/usb/host/ohci-sunxi.c b/drivers/usb/host/ohci-sunxi.c index 2b99169..e13f6ec 100644 --- a/drivers/usb/host/ohci-sunxi.c +++ b/drivers/usb/host/ohci-sunxi.c @@ -22,14 +22,19 @@ #define AHB_CLK_DIST 1 #endif +#define SUN6I_AHB_RESET0_CFG_OFFSET 0x2c0 +#define SUN9I_AHB_RESET0_CFG_OFFSET 0x5a0 + struct ohci_sunxi_cfg { bool has_reset; u32 extra_ahb_gate_mask; u32 extra_usb_gate_mask; + u32 reset0_cfg_offset; }; struct ohci_sunxi_priv { struct sunxi_ccm_reg *ccm; + u32 *reset0_cfg; ohci_t ohci; int ahb_gate_mask; /* Mask of ahb_gate0 clk gate bits for this hcd */ int usb_gate_mask; /* Mask of usb_clk_cfg clk gate bits for this hcd */ @@ -50,6 +55,9 @@ static int ohci_usb_probe(struct udevice *dev) if (IS_ERR(priv->ccm)) return PTR_ERR(priv->ccm); + priv->reset0_cfg = (void *)priv->ccm + + priv->cfg->reset0_cfg_offset; + phys = dev_count_phandle_with_args(dev, "phys", "#phy-cells"); if (phys < 0) { phys = 0; @@ -93,7 +101,7 @@ no_phy: setbits_le32(&priv->ccm->usb_clk_cfg, priv->usb_gate_mask | priv->cfg->extra_usb_gate_mask); if (priv->cfg->has_reset) - setbits_le32(&priv->ccm->ahb_reset0_cfg, + setbits_le32(priv->reset0_cfg, priv->ahb_gate_mask | extra_ahb_gate_mask); return ohci_register(dev, regs); @@ -117,7 +125,7 @@ static int ohci_usb_remove(struct udevice *dev) return ret; if (priv->cfg->has_reset) - clrbits_le32(&priv->ccm->ahb_reset0_cfg, priv->ahb_gate_mask); + clrbits_le32(priv->reset0_cfg, priv->ahb_gate_mask); clrbits_le32(&priv->ccm->usb_clk_cfg, priv->usb_gate_mask); clrbits_le32(&priv->ccm->ahb_gate0, priv->ahb_gate_mask); @@ -130,17 +138,25 @@ static const struct ohci_sunxi_cfg sun4i_a10_cfg = { static const struct ohci_sunxi_cfg sun6i_a31_cfg = { .has_reset = true, + .reset0_cfg_offset = SUN6I_AHB_RESET0_CFG_OFFSET, }; static const struct ohci_sunxi_cfg sun8i_h3_cfg = { .has_reset = true, .extra_ahb_gate_mask = 1 << AHB_GATE_OFFSET_USB_EHCI0, + .reset0_cfg_offset = SUN6I_AHB_RESET0_CFG_OFFSET, +}; + +static const struct ohci_sunxi_cfg sun9i_a80_cfg = { + .has_reset = true, + .reset0_cfg_offset = SUN9I_AHB_RESET0_CFG_OFFSET, }; static const struct ohci_sunxi_cfg sun50i_a64_cfg = { .has_reset = true, .extra_ahb_gate_mask = 1 << AHB_GATE_OFFSET_USB_EHCI0, .extra_usb_gate_mask = CCM_USB_CTRL_OHCI0_CLK, + .reset0_cfg_offset = SUN6I_AHB_RESET0_CFG_OFFSET, }; static const struct udevice_id ohci_usb_ids[] = { @@ -174,7 +190,7 @@ static const struct udevice_id ohci_usb_ids[] = { }, { .compatible = "allwinner,sun9i-a80-ohci", - .data = (ulong)&sun6i_a31_cfg, + .data = (ulong)&sun9i_a80_cfg, }, { .compatible = "allwinner,sun50i-a64-ohci",