armv7: USB port workaround for Allwinner V3s

classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

armv7: USB port workaround for Allwinner V3s

SASANO Takayoshi
Hello,

Allwinner V3s shares one USB port with MUSB OTG module and EHCI/OHCI.
The default route of USB-PHY is to OTG module so we have to add workaround
to sys/dev/fdt/ehci_fdt.c that the port connects to host controller.

(reference: sun4i_usb_phy0_reroute() at drivers/phy/allwinner/phy-sun4i-usb.c,
Linux-5.0-RC6 code)

Index: ehci_fdt.c
===================================================================
RCS file: /cvs/src/sys/dev/fdt/ehci_fdt.c,v
retrieving revision 1.4
diff -u -p -u -r1.4 ehci_fdt.c
--- ehci_fdt.c 6 Aug 2018 10:52:30 -0000 1.4
+++ ehci_fdt.c 20 Feb 2019 10:42:49 -0000
@@ -254,6 +254,57 @@ ehci_init_phys(struct ehci_fdt_softc *sc
 #define  SUNXI_AHB_INCR8 (1 << 10)
 #define  SUNXI_AHB_INCR16 (1 << 11)
 
+#define SUNXI_OTG_CTL 0x020
+#define  SUNXI_ROUTE_MUSB (1 << 0)
+
+/*
+ * Allwinner V3s shares one USB port with MUSB OTG module and OHCI/EHCI.
+ * Different from other Allwinner SoCs, V3s has no dedicated port connected
+ * to host controller. And default port routing is to MUSB OTG.
+ * So this workaround is needed.
+ */
+void
+sun4i_port_routing(struct ehci_fdt_softc *sc, uint32_t *cells)
+{
+ bus_space_tag_t iot;
+ bus_space_handle_t ioh;
+ int idx, len, node;
+ uint32_t *reg;
+ uint32_t val;
+
+ node = OF_getnodebyphandle(cells[0]);
+ if (node == 0)
+ return;
+
+ if (!OF_is_compatible(node, "allwinner,sun8i-v3s-usb-phy"))
+ return;
+
+ idx = OF_getindex(node, "phy_ctrl", "reg-names");
+ if (idx < 0)
+ return;
+
+ len = OF_getproplen(node, "reg");
+ if (len <= 0)
+ return;
+
+ reg = malloc(len, M_TEMP, M_WAITOK);
+ OF_getpropintarray(node, "reg", reg, len);
+
+ iot = sc->sc.iot;
+ if (bus_space_map(iot, reg[idx], reg[idx + 1], 0, &ioh)) {
+ free(reg, M_TEMP, len);
+ return;
+ }
+
+ /* assign USB port to OHCI/EHCI */
+ val = bus_space_read_4(iot, ioh, SUNXI_OTG_CTL);
+ val &= ~SUNXI_ROUTE_MUSB;
+ bus_space_write_4(iot, ioh, SUNXI_OTG_CTL, val);
+
+ bus_space_unmap(iot, ioh, reg[idx + 1]);
+ free(reg, M_TEMP, len);
+}
+
 void
 sun4i_phy_init(struct ehci_fdt_softc *sc, uint32_t *cells)
 {
@@ -278,6 +329,7 @@ sun4i_phy_init(struct ehci_fdt_softc *sc
  */
  if (OF_is_compatible(node, "allwinner,sun8i-h3-usb-phy") ||
     OF_is_compatible(node, "allwinner,sun8i-r40-usb-phy") ||
+    OF_is_compatible(node, "allwinner,sun8i-v3s-usb-phy") ||
     OF_is_compatible(node, "allwinner,sun50i-a64-usb-phy")) {
  val = bus_space_read_4(sc->sc.iot, sc->sc.ioh, 0x810);
  val &= ~(1 << 1);
@@ -306,6 +358,8 @@ sun4i_phy_init(struct ehci_fdt_softc *sc
  vbus_supply = OF_getpropint(node, name, 0);
  if (vbus_supply)
  regulator_enable(vbus_supply);
+
+ sun4i_port_routing(sc, cells);
 }
 
 void


--------
To support OHCI/EHCI on LicheePi Zero, we have to modify devicetree
like this diff. ehci (and maybe ohci) node needs phys and phy-names
property.

--- sun8i-v3s.dtsi.orig Thu Feb 14 21:59:49 2019
+++ sun8i-v3s.dtsi Wed Feb 20 12:59:19 2019
@@ -180,6 +180,29 @@
  #phy-cells = <1>;
  };
 
+ ehci0: usb@01c1a000 {
+ compatible = "allwinner,sun8i-v3s-ehci", "generic-ehci";
+ reg = <0x01c1a000 0x100>;
+ interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_EHCI0>, <&ccu CLK_BUS_OHCI0>;
+ resets = <&ccu RST_BUS_EHCI0>, <&ccu RST_BUS_OHCI0>;
+ phys = <&usbphy 0>;
+ phy-names = "usb";
+ status = "disabled";
+ };
+
+ ohci0: usb@01c1a400 {
+ compatible = "allwinner,sun8i-v3s-ohci", "generic-ohci";
+ reg = <0x01c1a400 0x100>;
+ interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_EHCI0>, <&ccu CLK_BUS_OHCI0>,
+ <&ccu CLK_USB_OHCI0>;
+ resets = <&ccu RST_BUS_EHCI0>, <&ccu RST_BUS_OHCI0>;
+ phys = <&usbphy 0>;
+ phy-names = "usb";
+ status = "disabled";
+ };
+
  ccu: clock@01c20000 {
  compatible = "allwinner,sun8i-v3s-ccu";
  reg = <0x01c20000 0x400>;
--- sun8i-v3s-licheepi-zero.dts.orig Thu Feb 14 21:59:49 2019
+++ sun8i-v3s-licheepi-zero.dts Thu Feb 14 22:46:31 2019
@@ -57,6 +57,10 @@
  };
 };
 
+&ehci0 {
+       status = "okay";
+};
+
 &mmc0 {
  pinctrl-0 = <&mmc0_pins_a>;
  pinctrl-names = "default";
@@ -64,6 +68,10 @@
  bus-width = <4>;
  vmmc-supply = <&reg_vcc3v3>;
  status = "okay";
+};
+
+&ohci0 {
+       status = "okay";
 };
 
 &uart0 {


Regards,
--
SASANO Takayoshi (JG1UAA) <[hidden email]>

Reply | Threaded
Open this post in threaded view
|

Re: armv7: USB port workaround for Allwinner V3s

Patrick Wildt-3
On Wed, Feb 20, 2019 at 10:03:26PM +0900, SASANO Takayoshi wrote:
> Hello,
>
> Allwinner V3s shares one USB port with MUSB OTG module and EHCI/OHCI.
> The default route of USB-PHY is to OTG module so we have to add workaround
> to sys/dev/fdt/ehci_fdt.c that the port connects to host controller.
>
> (reference: sun4i_usb_phy0_reroute() at drivers/phy/allwinner/phy-sun4i-usb.c,
> Linux-5.0-RC6 code)

> + len = OF_getproplen(node, "reg");
> + if (len <= 0)
> + return;
> +
> + reg = malloc(len, M_TEMP, M_WAITOK);
> + OF_getpropintarray(node, "reg", reg, len);
> +
> + iot = sc->sc.iot;
> + if (bus_space_map(iot, reg[idx], reg[idx + 1], 0, &ioh)) {
> + free(reg, M_TEMP, len);
> + return;
> + }

That's not right.  The reg property needs to be translated through
all necessary layers.  This only works if the phy is in the same
layer as the ehci.  Feels like a hack.

I have also done an attempt at fixing this not long ago, but I wasn't
quite ready yet as this enable VBUS all the time and if there is a hw
where someone tries to connect a host to the device... then there are
two VBUSes, heh.  But if (for now) that's fine, we could also just go
ahead with it.

diff --git a/sys/arch/arm64/conf/GENERIC b/sys/arch/arm64/conf/GENERIC
index b85e1099412..edb785662c6 100644
--- a/sys/arch/arm64/conf/GENERIC
+++ b/sys/arch/arm64/conf/GENERIC
@@ -177,6 +177,7 @@ sdmmc* at sximmc? # SD/MMC bus
 sxitemp* at fdt? # Temperature sensor
 sxitwi* at fdt? # I2C controller
 iic* at sxitwi? # I2C bus
+sxiuphy* at fdt? # USB Phy
 dwxe* at fdt?
 
 # PCI
diff --git a/sys/arch/arm64/conf/RAMDISK b/sys/arch/arm64/conf/RAMDISK
index 201a5f0fcb2..83ab6602c04 100644
--- a/sys/arch/arm64/conf/RAMDISK
+++ b/sys/arch/arm64/conf/RAMDISK
@@ -169,6 +169,7 @@ sximmc* at fdt? # SD/MMC card controller
 sdmmc* at sximmc? # SD/MMC bus
 sxitwi* at fdt? # I2C controller
 iic* at sxitwi? # I2C bus
+sxiuphy* at fdt? # USB Phy
 dwxe* at fdt?
 
 # PCI
diff --git a/sys/dev/fdt/files.fdt b/sys/dev/fdt/files.fdt
index f90efcdf446..5d6bf652d47 100644
--- a/sys/dev/fdt/files.fdt
+++ b/sys/dev/fdt/files.fdt
@@ -44,6 +44,10 @@ device sxitwi: i2cbus
 attach sxitwi at fdt
 file dev/fdt/sxitwi.c sxitwi
 
+device sxiuphy
+attach sxiuphy at fdt
+file dev/fdt/sxiuphy.c sxiuphy
+
 device axppmic
 attach axppmic at i2c
 attach axppmic at rsb with axppmic_rsb
diff --git a/sys/dev/fdt/sxiuphy.c b/sys/dev/fdt/sxiuphy.c
new file mode 100644
index 00000000000..40d22bb2df5
--- /dev/null
+++ b/sys/dev/fdt/sxiuphy.c
@@ -0,0 +1,110 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2019 Patrick Wildt <[hidden email]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+
+#include <machine/intr.h>
+#include <machine/bus.h>
+#include <machine/fdt.h>
+
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_misc.h>
+#include <dev/ofw/fdt.h>
+
+#define PHY_ISCR 0x00
+#define  PHY_ISCR_DPDM_CHANGE_DET (1 << 4)
+#define  PHY_ISCR_ID_CHANGE_DET (1 << 5)
+#define  PHY_ISCR_VBUS_CHANGE_DET (1 << 6)
+#define  PHY_ISCR_VBUS_LOW (2 << 12)
+#define  PHY_ISCR_VBUS_HIGH (3 << 12)
+#define  PHY_ISCR_VBUS_MASK (3 << 12)
+#define  PHY_ISCR_ID_LOW (2 << 14)
+#define  PHY_ISCR_ID_HIGH (3 << 14)
+#define  PHY_ISCR_ID_MASK (3 << 14)
+#define  PHY_ISCR_DPDM_PULLUP (1 << 16)
+#define  PHY_ISCR_ID_PULLUP (1 << 17)
+#define PHY_PHYCTL_A10 0x04
+#define PHY_PHYBIST 0x08
+#define PHY_PHYTUNE 0x0c
+#define PHY_PHYCTL_A33 0x10
+#define PHY_OTGCTL 0x20
+#define  PHY_OTGCTL_ROUTE_MUSB (1 << 0)
+
+#define PMU_UNK1 0x10
+
+struct sxiuphy_softc {
+ struct device sc_dev;
+ bus_space_tag_t sc_iot;
+ bus_space_handle_t sc_ioh;
+};
+
+int sxiuphy_match(struct device *, void *, void *);
+void sxiuphy_attach(struct device *, struct device *, void *);
+
+struct cfattach sxiuphy_ca = {
+ sizeof (struct sxiuphy_softc), sxiuphy_match, sxiuphy_attach
+};
+
+struct cfdriver sxiuphy_cd = {
+ NULL, "sxiuphy", DV_DULL
+};
+
+int
+sxiuphy_match(struct device *parent, void *match, void *aux)
+{
+ struct fdt_attach_args *faa = aux;
+
+ return (OF_is_compatible(faa->fa_node, "allwinner,sun8i-h3-usb-phy") ||
+    OF_is_compatible(faa->fa_node, "allwinner,sun8i-r40-usb-phy") ||
+    OF_is_compatible(faa->fa_node, "allwinner,sun8i-v3s-usb-phy") ||
+    OF_is_compatible(faa->fa_node, "allwinner,sun50i-a64-usb-phy") ||
+    OF_is_compatible(faa->fa_node, "allwinner,sun50i-h6-usb-phy"));
+}
+
+void
+sxiuphy_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct sxiuphy_softc *sc = (struct sxiuphy_softc *)self;
+ struct fdt_attach_args *faa = aux;
+ uint32_t reg;
+
+ if (faa->fa_nreg < 1) {
+ printf(": no registers\n");
+ return;
+ }
+
+ sc->sc_iot = faa->fa_iot;
+
+ if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
+    faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
+ printf(": can't map registers\n");
+ return;
+ }
+
+ printf("\n");
+
+ reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, PHY_OTGCTL);
+ reg &= ~(PHY_ISCR_DPDM_CHANGE_DET | PHY_ISCR_ID_CHANGE_DET |
+    PHY_ISCR_VBUS_CHANGE_DET);
+ reg |= (PHY_ISCR_DPDM_PULLUP | PHY_ISCR_ID_PULLUP);
+ reg &= ~(PHY_ISCR_VBUS_MASK | PHY_ISCR_ID_MASK);
+ reg |= (PHY_ISCR_VBUS_HIGH | PHY_ISCR_ID_LOW);
+ reg &= ~PHY_OTGCTL_ROUTE_MUSB;
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, PHY_OTGCTL, reg);
+}

Reply | Threaded
Open this post in threaded view
|

Re: armv7: USB port workaround for Allwinner V3s

SASANO Takayoshi
Hello,

> That's not right.  The reg property needs to be translated through
> all necessary layers.  This only works if the phy is in the same
> layer as the ehci.  Feels like a hack.

Is there any good documentation to understand OF_xxx() api calls?
I'm new to hack this area, I wrote that patch by reading OpenBSD's
sourcecode with many trial and error.

I think your sxiuphy is very good idea, and I am trying to
test this driver.

But there is a problem that current sxiuphy cannot access
USB PHY register of Allwinner V3s even if I add clock_enable() and
reset_deassert_all() after bus_space_map().

I checked behavior of USB PHY register, and I found that this module
requires one of {EHCI, OHCI, OTG} clock and its own clock.

So, sxiuphy requires to start *after* ehci/ohci (or musb-otg) driver
when running them on Allwinner V3s. How about on other Allwinner SoC?

If it is difficult to change order to boot sxiuphy driver,
we have to consider to add some code to ehci_fdt.c or something other.


Here is the log that I tested on U-boot.

----
U-Boot 2019.01 (Feb 20 2019 - 13:01:02 +0900) Allwinner Technology

CPU:   Allwinner V3s (SUN8I 1681)
Model: Lichee Pi Zero
DRAM:  64 MiB
MMC:   SUNXI SD/MMC: 0
Loading Environment from FAT... *** Warning - bad CRC, using default environment

In:    serial@01c28000
Out:   serial@01c28000
Err:   serial@01c28000
Net:   No ethernet found.
starting USB...
No controllers found
Hit any key to stop autoboot:  0
=> md 01c20060 1 *BUS_CLK_GATING_REG0: OHCI/EHCI/OTG clock off
01c20060: 00004140                               @A..
=> md 01c202c0 1 *BUS_SOFT_RST_REG0: OHCI/EHCI/OTG are reset
01c202c0: 00004140                               @A..
=> md 01c200cc 1 *USBPHY_CFG_REG: OHCI/PHY clock off, PHY reset
01c200cc: 00000000                               ....
=> md 01c19400 b *USBPHY register access failed
01c19400: 00000000 00000000 00000000 00000000    ................
01c19410: 00000000 00000000 00000000 00000000    ................
01c19420: 00000000 00000000 00000000             ............
=> mw 01c200cc 00000101 *USBPHY_CFG_REG: PHY clock on, reset deassert
=> md 01c19400 b *USBPHY register access failed
01c19400: 00000000 00000000 00000000 00000000    ................
01c19410: 00000000 00000000 00000000 00000000    ................
01c19420: 00000000 00000000 00000000             ............
=> mw 01c20060 01004140 *BUS_CLK_GATING_REG0: OTG clock on
=> md 01c19400 b *USBPHY register access success
01c19400: 40000000 00000000 00000000 00000000    ...@............
01c19410: 00000002 00000000 023438e4 00000000    .........84.....
01c19420: 00000001 00000000 00000000             ............
=> mw 01c20060 04004140 *BUS_CLK_GATING_REG0: EHCI clock on
=> md 01c19400 b *USBPHY register access success
01c19400: 40000000 00000000 00000000 00000000    ...@............
01c19410: 00000002 00000000 023438e4 00000000    .........84.....
01c19420: 00000001 00000000 00000000             ............
=> mw 01c20060 20004140 *BUS_CLK_GATING_REG0: OHCI clock on
=> md 01c19400 b *USBPHY register access success
01c19400: 40000000 00000000 00000000 00000000    ...@............
01c19410: 00000002 00000000 023438e4 00000000    .........84.....
01c19420: 00000001 00000000 00000000             ............
=> mw 01c20060 00004140 *BUS_CLK_GATING_REG0: OHCI/EHCI/OTG clock off
=> md 01c19400 b *USBPHY register access failed
01c19400: 00000000 00000000 00000000 00000000    ................
01c19410: 00000000 00000000 00000000 00000000    ................
01c19420: 00000000 00000000 00000000             ............
=>

Regards,
--
SASANO Takayoshi (JG1UAA) <[hidden email]>

Reply | Threaded
Open this post in threaded view
|

Re: armv7: USB port workaround for Allwinner V3s

Krystian Lewandowski-2
In reply to this post by Patrick Wildt-3
Patrick, thank you for the patch,
I tried it on:
1. pinebook (A64) - OK, the other USB port works as expected
2. pine A64+ - not quite OK, dmesg is constantly flooded with:
[...]
ohci0: 249 scheduling overruns
ohci0: 247 scheduling overruns
ohci0: 259 scheduling overruns
ohci0: 249 scheduling overruns
ohci0: 249 scheduling overruns
ohci0: 259 scheduling overruns
[...]

--
Krystian