Hi,

i got a branch i would like to have this for =]

this works for me as is, and already does more than the current code
in tree, which this diff removes from sys/dev/fdt/ehci_fdt.c.

i took a look at how netbsd does this, but went essentially with what
linux does for these bindings (excluding some otg-only stuff for now).

fwiw., i haven't tested the type>=H3 paths so far(no hw). any comments?

-Artturi


diff --git a/sys/arch/arm64/conf/GENERIC b/sys/arch/arm64/conf/GENERIC
index 57ad904ed22..175074a4651 100644
--- a/sys/arch/arm64/conf/GENERIC
+++ b/sys/arch/arm64/conf/GENERIC
@@ -199,6 +199,7 @@ sxirtc*             at fdt? early 1 # Real Time Clock
 sximmc*                at fdt?         # SD/MMC card controller
 sdmmc*         at sximmc?      # SD/MMC bus
 sxisyscon*     at fdt? early 1 # System controller
+sxiusbphy*     at fdt? early 1         # Allwinner USB PHY
 sxitemp*       at fdt?         # Temperature sensor
 sxitwi*                at fdt?         # I2C controller
 iic*           at sxitwi?      # I2C bus
diff --git a/sys/arch/arm64/conf/RAMDISK b/sys/arch/arm64/conf/RAMDISK
index 2a87cc9a88a..1542743469c 100644
--- a/sys/arch/arm64/conf/RAMDISK
+++ b/sys/arch/arm64/conf/RAMDISK
@@ -185,6 +185,7 @@ sxirtc*             at fdt? early 1 # Real Time Clock
 sximmc*                at fdt?         # SD/MMC card controller
 sdmmc*         at sximmc?      # SD/MMC bus
 sxisyscon*     at fdt? early 1 # System controller
+sxiusbphy*     at fdt? early 1         # Allwinner USB PHY
 sxitwi*                at fdt?         # I2C controller
 iic*           at sxitwi?      # I2C bus
 dwxe*          at fdt?
diff --git a/sys/arch/armv7/conf/GENERIC b/sys/arch/armv7/conf/GENERIC
index 1fe66198653..f02788df236 100644
--- a/sys/arch/armv7/conf/GENERIC
+++ b/sys/arch/armv7/conf/GENERIC
@@ -115,6 +115,7 @@ usb*                at ehci?        #flags 0x1
 ohci*          at fdt?
 usb*           at ohci?
 sxisyscon*     at fdt? early 1         # System controller
+sxiusbphy*     at fdt? early 1         # Allwinner USB PHY
 sxitemp*       at fdt?                 # Temperature sensor
 sxits*         at fdt?                 # Touchpad controller
 sxitwi*                at fdt?                 # Two-Wire Serial Interface
diff --git a/sys/arch/armv7/conf/RAMDISK b/sys/arch/armv7/conf/RAMDISK
index 05067ae11ea..022cbd2262c 100644
--- a/sys/arch/armv7/conf/RAMDISK
+++ b/sys/arch/armv7/conf/RAMDISK
@@ -106,6 +106,7 @@ usb*                at ehci?        #flags 0x1
 ohci*          at fdt?
 usb*           at ohci?
 sxisyscon*     at fdt? early 1         # System controller
+sxiusbphy*     at fdt? early 1         # Allwinner USB PHY
 sxitwi*                at fdt?                 # Two-Wire Serial Interface
 iic*           at sxitwi?              # I2C bus
 
diff --git a/sys/dev/fdt/ehci_fdt.c b/sys/dev/fdt/ehci_fdt.c
index 807fac3d441..6f12c684925 100644
--- a/sys/dev/fdt/ehci_fdt.c
+++ b/sys/dev/fdt/ehci_fdt.c
@@ -28,6 +28,7 @@
 
 #include <dev/ofw/openfirm.h>
 #include <dev/ofw/ofw_clock.h>
+#include <dev/ofw/ofw_misc.h>
 #include <dev/ofw/ofw_pinctrl.h>
 #include <dev/ofw/ofw_regulator.h>
 #include <dev/ofw/fdt.h>
@@ -109,6 +110,7 @@ ehci_fdt_attach(struct device *parent, struct device *self, 
void *aux)
        printf("\n");
 
        ehci_init_phys(sc);
+       phy_enable_idx(sc->sc_node, 0);
 
        strlcpy(sc->sc.sc_vendor, "Generic", sizeof(sc->sc.sc_vendor));
        r = ehci_init(&sc->sc);
@@ -161,20 +163,9 @@ struct ehci_phy {
        void (*init)(struct ehci_fdt_softc *, uint32_t *);
 };
 
-void sun4i_phy_init(struct ehci_fdt_softc *, uint32_t *);
 void sun9i_phy_init(struct ehci_fdt_softc *, uint32_t *);
 
 struct ehci_phy ehci_phys[] = {
-       { "allwinner,sun4i-a10-usb-phy", sun4i_phy_init },
-       { "allwinner,sun5i-a13-usb-phy", sun4i_phy_init },
-       { "allwinner,sun6i-a31-usb-phy", sun4i_phy_init },
-       { "allwinner,sun7i-a20-usb-phy", sun4i_phy_init },
-       { "allwinner,sun8i-a23-usb-phy", sun4i_phy_init },
-       { "allwinner,sun8i-a33-usb-phy", sun4i_phy_init },
-       { "allwinner,sun8i-h3-usb-phy", sun4i_phy_init },
-       { "allwinner,sun8i-r40-usb-phy", sun4i_phy_init },
-       { "allwinner,sun8i-v3s-usb-phy", sun4i_phy_init },
-       { "allwinner,sun50i-a64-usb-phy", sun4i_phy_init },
        { "allwinner,sun9i-a80-usb-phy", sun9i_phy_init },
 };
 
@@ -250,60 +241,6 @@ ehci_init_phys(struct ehci_fdt_softc *sc)
 #define  SUNXI_AHB_INCR8       (1 << 10)
 #define  SUNXI_AHB_INCR16      (1 << 11)
 
-void
-sun4i_phy_init(struct ehci_fdt_softc *sc, uint32_t *cells)
-{
-       uint32_t vbus_supply;
-       char name[32];
-       uint32_t val;
-       int node;
-
-       node = OF_getnodebyphandle(cells[0]);
-       if (node == -1)
-               return;
-
-       val = bus_space_read_4(sc->sc.iot, sc->sc.ioh, SUNXI_HCI_ICR);
-       val |= SUNXI_AHB_INCR8 | SUNXI_AHB_INCR4;
-       val |= SUNXI_AHB_INCRX_ALIGN;
-       val |= SUNXI_ULPI_BYPASS;
-       bus_space_write_4(sc->sc.iot, sc->sc.ioh, SUNXI_HCI_ICR, val);
-
-       /*
-        * We need to poke an undocumented register to make the PHY
-        * work on Allwinner A64/H3/H5/R40.
-        */
-       if (OF_is_compatible(node, "allwinner,sun8i-h3-usb-phy") ||
-           OF_is_compatible(node, "allwinner,sun8i-r40-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);
-               bus_space_write_4(sc->sc.iot, sc->sc.ioh, 0x810, val);
-       }
-
-       pinctrl_byname(node, "default");
-
-       /*
-        * On sun4i, sun5i and sun7i, there is a single clock.  The
-        * more recent SoCs have a separate clock for each PHY.
-        */
-       if (OF_is_compatible(node, "allwinner,sun4i-a10-usb-phy") ||
-           OF_is_compatible(node, "allwinner,sun5i-a13-usb-phy") ||
-           OF_is_compatible(node, "allwinner,sun7i-a20-usb-phy")) {
-               clock_enable(node, "usb_phy");
-       } else {
-               snprintf(name, sizeof(name), "usb%d_phy", cells[1]);
-               clock_enable(node, name);
-       }
-
-       snprintf(name, sizeof(name), "usb%d_reset", cells[1]);
-       reset_deassert(node, name);
-
-       snprintf(name, sizeof(name), "usb%d_vbus-supply", cells[1]);
-       vbus_supply = OF_getpropint(node, name, 0);
-       if (vbus_supply)
-               regulator_enable(vbus_supply);
-}
-
 void
 sun9i_phy_init(struct ehci_fdt_softc *sc, uint32_t *cells)
 {
diff --git a/sys/dev/fdt/files.fdt b/sys/dev/fdt/files.fdt
index 28390fee6dc..9e41d862e68 100644
--- a/sys/dev/fdt/files.fdt
+++ b/sys/dev/fdt/files.fdt
@@ -36,6 +36,10 @@ device       sxisyscon: fdt
 attach sxisyscon at fdt
 file   dev/fdt/sxisyscon.c             sxisyscon
 
+device sxiusbphy: fdt
+attach sxiusbphy at fdt
+file   dev/fdt/sxiusbphy.c             sxiusbphy
+
 device sxitemp
 attach sxitemp at fdt
 file   dev/fdt/sxitemp.c               sxitemp
diff --git a/sys/dev/fdt/sxiusbphy.c b/sys/dev/fdt/sxiusbphy.c
new file mode 100644
index 00000000000..23f94b9c7d9
--- /dev/null
+++ b/sys/dev/fdt/sxiusbphy.c
@@ -0,0 +1,424 @@
+/*     $OpenBSD: amlusbphy.c,v 1.1 2019/08/29 17:20:03 kettenis Exp $  */
+/*
+ * Copyright (c) 2019 Mark Kettenis <[email protected]>
+ *
+ * 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_clock.h>
+#include <dev/ofw/ofw_misc.h>
+#include <dev/ofw/ofw_regulator.h>
+#include <dev/ofw/fdt.h>
+
+/* Registers */
+#define        PHY_ISCR                        0x00
+#define         PHY_ISCR_DPDM_CHANGE_DETECT_EN         (1u << 0)
+#define         PHY_ISCR_ID_CHANGE_DETECT_EN           (1u << 1)
+#define         PHY_ISCR_VBUS_CHANGE_DETECT_EN         (1u << 2)
+#define         PHY_ISCR_IRQ_ENABLE                    (1u << 3)
+#define         PHY_ISCR_DPDM_CHANGE_DETECT            (1u << 4)       /* w1c 
*/
+#define         PHY_ISCR_ID_CHANGE_DETECT              (1u << 5)       /* w1c 
*/
+#define         PHY_ISCR_VBUS_CHANGE_DETECT            (1u << 6)       /* w1c 
*/
+#define         PHY_ISCR_HOSC_EN                       (1u << 7)
+/*efine         PHY_ISCR_VBUS_VALID_SRC_DISABLE        XXX unknown */
+/*efine         PHY_ISCR_VBUS_VALID_SRC_LOW            (2u << 10)*/
+/*efine         PHY_ISCR_VBUS_VALID_SRC_HIGH           (3u << 10)*/
+#define         PHY_ISCR_VBUS_VALID_SRC_MASK           (3u << 10)
+#define         PHY_ISCR_FORCE_VBUS_VALID_DIS          (0u << 12)
+#define         PHY_ISCR_FORCE_VBUS_VALID_LOW          (2u << 12)
+#define         PHY_ISCR_FORCE_VBUS_VALID_HIGH         (3u << 12)
+#define         PHY_ISCR_FORCE_VBUS_VALID_MASK         (3u << 12)
+#define         PHY_ISCR_FORCE_ID_DISABLE              (0u << 15)
+#define         PHY_ISCR_FORCE_ID_LOW                  (2u << 15)
+#define         PHY_ISCR_FORCE_ID_HIGH                 (3u << 15)
+#define         PHY_ISCR_FORCE_ID_MASK                 (3u << 15)
+#define         PHY_ISCR_DPDM_PULLUP_EN                (1u << 16)
+#define         PHY_ISCR_ID_PULLUP_EN                  (1u << 17)
+#define         PHY_ISCR_MERGED_ID_STATUS              (1u << 24)
+#define         PHY_ISCR_MERGED_VBUS_STATUS            (1u << 25)
+#define         PHY_ISCR_EXT_DP_STATUS                 (1u << 26)
+#define         PHY_ISCR_EXT_DM_STATUS                 (1u << 27)
+#define         PHY_ISCR_EXT_ID_STATUS                 (1u << 28)
+#define         PHY_ISCR_VBUS_VALID_FROM_VBUS          (1u << 29)
+#define         PHY_ISCR_VBUS_VALID_FROM_DATA          (1u << 30)
+
+#define        PHY_CTRL_A10                    0x04
+#define        PHY_CTRL_A33                    0x10
+#define         PHY_CTRL_USBCn(i)                      (1u << ((i) * 2))
+#define         PHY_CTRL_USBC_MASK                     0x7f
+#define         PHY_CTRL_DATA                          (1u << 7)
+#define         PHY_CTRL_DATA_SHIFT                    7
+#define         PHY_CTRL_ADDR                          0xff00
+#define         PHY_CTRL_ADDR_SHIFT                    8
+#define         PHY_CTRL_SET_PLL_BW                    0x03
+#define         PHY_CTRL_SET_PLL_BW_MASK                       0x3
+#define         PHY_CTRL_RES45_CAL_EN                  0x0c
+#define         PHY_CTRL_SET_TX_AMPLITUDE_TUNE         0x20
+#define         PHY_CTRL_SET_TX_AMPLITUDE_TUNE_MASK            0x3
+#define         PHY_CTRL_SET_TX_SLEWRATE_TUNE          0x22
+#define         PHY_CTRL_SET_TX_SLEWRATE_TUNE_MASK             0x7
+#define         PHY_CTRL_SET_VBUS_VALID_THRESHOLD      0x25
+#define         PHY_CTRL_SET_VBUS_VALID_THRESHOLD_MASK         0x3
+#define         PHY_CTRL_OTG_FUNC_ENABLE               0x28
+#define         PHY_CTRL_VBUS_DET_ENABLE               0x29
+#define         PHY_CTRL_SET_DISCON_DET_THRESHOLD      0x2a
+#define         PHY_CTRL_SET_DISCON_DET_THRESHOLD_MASK         0x3
+
+#define         PHY_CTRL_SIDDQ                 (1u << 3)
+#define         PHY_CTRL_VBUSVLDEXT            (1u << 5)
+
+#define        PHY_OTGCTRL                     0x20
+#define         PHY_OTGCTRL_ROUTE_MUSB         (1u << 0)
+
+#define        HCI_ICR                         0x00
+#define         ULPI_BYPASS                    (1u << 0)
+#define         A83T_HSIC                      (1u << 1)
+#define         AHB_INCRX_ALIGN                (1u << 8)
+#define         AHB_INCR4                      (1u << 9)
+#define         AHB_INCR8                      (1u << 10)
+#define         A83T_HSIC_CON_INT              (1u << 16)
+#define         A83T_HSIC_CON_DET              (1u << 17)
+#define         A83T_EHCI_HS_FORCE             (1u << 20)
+
+#define        HREAD4(sc, reg)                                                 
\
+       (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
+#define        HWRITE4(sc, reg, val)                                           
\
+       bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
+#define        HSET4(sc, reg, bits)                                            
\
+       HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits))
+#define        HCLR4(sc, reg, bits)                                            
\
+       HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits))
+#define        HCMS4(sc, reg, mask, bits)                                      
\
+       HWRITE4((sc), (reg), (HREAD4((sc), (reg)) & ~(mask)) | (bits))
+
+#define        MAXUSBPHY               4
+
+struct sxiusbphy_softc {
+       struct device           sc_dev;
+       bus_space_tag_t         sc_iot;
+       bus_space_handle_t      sc_ioh;                 /* phy ctrl */
+
+       bus_space_handle_t      sc_phy_ioh[MAXUSBPHY];  /* pmu */
+       bus_size_t              sc_phy_iosize[MAXUSBPHY];
+       uint32_t                sc_phy_vbus_supply[MAXUSBPHY];
+       int                     sc_phytyp;
+       bus_size_t              sc_phyreg;
+       int                     sc_nphys;
+
+#ifdef notyet
+       uint32_t                sc_usb0_id_det[4];
+       uint32_t                sc_usb0_vbus_det[4];
+#endif
+
+       struct phy_device       sc_pd;
+};
+
+int    sxiusbphy_match(struct device *, void *, void *);
+void   sxiusbphy_attach(struct device *, struct device *, void *);
+
+struct cfattach        sxiusbphy_ca = {
+       sizeof (struct sxiusbphy_softc), sxiusbphy_match, sxiusbphy_attach
+};
+
+struct cfdriver sxiusbphy_cd = {
+       NULL, "sxiusbphy", DV_DULL
+};
+
+int    sxiusbphy_enable(void *, uint32_t *);
+void   sxiusbphy_write(struct sxiusbphy_softc *, u_int, u_int, u_int, u_int);
+static inline int      sxiusbphy_nphys(int);
+static inline u_int    sxiusbphy_disc_det_treshold(int);
+
+enum {
+       SXIUSBPHY_T_A10 = 0,
+       SXIUSBPHY_T_A13,
+       SXIUSBPHY_T_A31,
+       SXIUSBPHY_T_A20,
+       SXIUSBPHY_T_A23,
+       SXIUSBPHY_T_A33,
+       SXIUSBPHY_T_A83,
+       SXIUSBPHY_T_H3,
+       SXIUSBPHY_T_R40,
+       SXIUSBPHY_T_V3S,
+       SXIUSBPHY_T_A64,
+       SXIUSBPHY_T_H6,
+       SXIUSBPHY_T_MAX,
+};
+const char *sxiusb_phys[] = {
+       [SXIUSBPHY_T_A10] = "allwinner,sun4i-a10-usb-phy",
+       [SXIUSBPHY_T_A13] = "allwinner,sun5i-a13-usb-phy",
+       [SXIUSBPHY_T_A31] = "allwinner,sun6i-a31-usb-phy",
+       [SXIUSBPHY_T_A20] = "allwinner,sun7i-a20-usb-phy",
+       [SXIUSBPHY_T_A23] = "allwinner,sun8i-a23-usb-phy",
+       [SXIUSBPHY_T_A33] = "allwinner,sun8i-a33-usb-phy",
+       [SXIUSBPHY_T_A83] = "allwinner,sun8i-a83t-usb-phy",
+       [SXIUSBPHY_T_H3] = "allwinner,sun8i-h3-usb-phy",
+       [SXIUSBPHY_T_R40] = "allwinner,sun8i-r40-usb-phy",
+       [SXIUSBPHY_T_V3S] = "allwinner,sun8i-v3s-usb-phy",
+       [SXIUSBPHY_T_A64] = "allwinner,sun50i-a64-usb-phy",
+       [SXIUSBPHY_T_H6] = "allwinner,sun50i-h6-usb-phy",
+};
+
+int
+sxiusbphy_match(struct device *parent, void *match, void *aux)
+{
+       struct fdt_attach_args *faa = aux;
+       int i = 0;
+
+       for (; i < nitems(sxiusb_phys); i++)
+               if (OF_is_compatible(faa->fa_node, sxiusb_phys[i]))
+                       return 1;
+       return 0;
+}
+
+void
+sxiusbphy_attach(struct device *parent, struct device *self, void *aux)
+{
+       struct sxiusbphy_softc *sc = (struct sxiusbphy_softc *)self;
+       struct fdt_attach_args *faa = aux;
+       struct fdt_reg dtr;
+       int node = faa->fa_node;
+       uint32_t node_phandle = OF_getpropint(node, "phandle", 0);
+       void *dtnode = node_phandle ? fdt_find_phandle(node_phandle) : NULL;
+       int i, ptyp, regidx;
+       char vsname[32];
+       char regname[32];
+
+       if (faa->fa_nreg < 1) {
+               printf(": no registers\n");
+               return;
+       }
+
+       if (!dtnode) {
+               printf(": can't get phandle\n");
+               return;
+       }
+
+       for (ptyp = 0; ptyp < nitems(sxiusb_phys); ptyp++)
+               if (OF_is_compatible(faa->fa_node, sxiusb_phys[ptyp]))
+                       break;
+       sc->sc_phytyp = ptyp;
+       sc->sc_phyreg = (ptyp < SXIUSBPHY_T_A33) ? PHY_CTRL_A10 : PHY_CTRL_A33;
+       sc->sc_nphys = sxiusbphy_nphys(ptyp);
+
+       sc->sc_iot = faa->fa_iot;
+       /**/
+       regidx = OF_getindex(node, "phy_ctrl", "reg-names");
+       if (regidx == -1) {
+               printf(": can't get phy_ctrl register index\n");
+               return;
+       } else if (fdt_get_reg(dtnode, regidx, &dtr)) {
+               printf(": can't get registers\n");
+               return;
+       }
+       if (bus_space_map(sc->sc_iot, dtr.addr, dtr.size, 0, &sc->sc_ioh)) {
+               printf(": can't map registers\n");
+               return;
+       }
+
+       for (i = 0; i < sc->sc_nphys; i++) {
+               /* H6 has two missing phys */
+               if (ptyp == SXIUSBPHY_T_H6 && ((1u << i) & 0x06))
+                       continue;
+
+               snprintf(vsname, sizeof(vsname), "usb%d_vbus-supply", i);
+               sc->sc_phy_vbus_supply[i] = OF_getpropint(node, vsname, 0);
+
+               if (i == 0 && ptyp < SXIUSBPHY_T_H3)
+                       continue;       /* otg phy0 && !dualroute */
+
+               snprintf(regname, sizeof(regname), "pmu%d", i);
+               regidx = OF_getindex(node, regname, "reg-names");
+               if (regidx == -1 || fdt_get_reg(dtnode, regidx, &dtr))
+                       continue;
+               if (bus_space_map(sc->sc_iot, dtr.addr, dtr.size, 0,
+                   &sc->sc_phy_ioh[i])) {
+                       printf(": can't map registers\n");
+                       return;
+               }
+               sc->sc_phy_iosize[i] = dtr.size;
+       }
+
+       printf("\n");
+
+#ifdef notyet
+/*
+ * usb0_id_det-gpios           =gpio phandle for reading the otg id pin value
+ * usb0_vbus_det-gpios         =gpio phandle for detecting the presence of 
usb0 vbus
+ * usb0_vbus_power-supply      =power-supply phandle for usb0 vbus presence 
detect
+ * usb*_vbus-supply            =regulator phandle for controller usb{0-3} vbus
+ */
+       OF_getpropintarray(node, "usb0_id_det-gpios",
+           sc->sc_usb0_id_det, sizeof(sc->sc_usb0_id_det));
+       gpio_controller_config_pin(sc->sc_usb0_id_det, GPIO_CONFIG_INPUT);
+
+       OF_getpropintarray(node, "usb0_vbus_det-gpios",
+           sc->sc_usb0_vbus_det, sizeof(sc->sc_usb0_vbus_det));
+       gpio_controller_config_pin(sc->sc_usb0_vbus_det, GPIO_CONFIG_INPUT);
+
+       /* XXX */
+       pinctrl_byname(faa->fa_node, "default");
+#endif
+
+       sc->sc_pd.pd_node = faa->fa_node;
+       sc->sc_pd.pd_cookie = sc;
+       sc->sc_pd.pd_enable = sxiusbphy_enable;
+       phy_register(&sc->sc_pd);
+}
+
+int
+sxiusbphy_nphys(int ptyp)
+{
+       if (ptyp == SXIUSBPHY_T_A13 ||
+           ptyp == SXIUSBPHY_T_A23 ||
+           ptyp == SXIUSBPHY_T_A33 ||
+           ptyp == SXIUSBPHY_T_A64)
+               return 2;
+       if (ptyp == SXIUSBPHY_T_H3 ||
+           ptyp == SXIUSBPHY_T_H6)
+               return 4;
+       return 3;
+}
+
+u_int
+sxiusbphy_disc_det_treshold(int ptyp)
+{
+       if (ptyp == SXIUSBPHY_T_A13 ||
+           ptyp == SXIUSBPHY_T_A20)
+               return 0x2;
+       if (ptyp == SXIUSBPHY_T_A83)
+               return 0x0;
+       return 0x3;
+}
+
+int
+sxiusbphy_enable(void *cookie, uint32_t *cells)
+{
+       struct sxiusbphy_softc *sc = cookie;
+       int idx = cells[0];
+       int node = sc->sc_pd.pd_node;
+       int ptyp = sc->sc_phytyp;
+       bus_space_tag_t iot = sc->sc_iot;
+       bus_space_handle_t ioh = sc->sc_phy_ioh[idx];
+       uint32_t bits = AHB_INCR8 | AHB_INCR4 | AHB_INCRX_ALIGN | ULPI_BYPASS;
+       uint32_t phy_supply;
+       char name[32];
+
+       /*
+        * On sun4i, sun5i and sun7i, there is a single clock.  The
+        * more recent SoCs have a separate clock for each PHY.
+        */
+       if (ptyp == SXIUSBPHY_T_A10 ||
+           ptyp == SXIUSBPHY_T_A13 ||
+           ptyp == SXIUSBPHY_T_A20)
+               clock_enable(node, "usb_phy");
+       else {
+               snprintf(name, sizeof(name), "usb%d_phy", idx);
+               clock_enable(node, name);
+
+               if (ptyp == SXIUSBPHY_T_A83 && idx == 2) {
+                       /* there's a second clock on sun8i-a83t */
+                       snprintf(name, sizeof(name), "usb%d_hsic_12M", idx);
+                       clock_enable(node, name);
+               }
+       }
+
+       snprintf(name, sizeof(name), "usb%d_reset", idx);
+       reset_deassert(node, name);
+
+       if (ptyp == SXIUSBPHY_T_A83 ||
+           ptyp == SXIUSBPHY_T_H6) {
+               if (idx == 0)
+                       HCMS4(sc, sc->sc_phyreg,
+                           PHY_CTRL_SIDDQ, PHY_CTRL_VBUSVLDEXT);
+       } else {
+               /*
+                * We need to poke an undocumented register to make the PHY
+                * work on Allwinner A64/H3/H5/R40.
+                */
+               if (ioh && ptyp >= SXIUSBPHY_T_H3)
+                       bus_space_write_4(iot, ioh, 0x10,
+                           bus_space_read_4(iot, ioh, 0x10) & ~(1u << 1));
+
+               if (idx == 0)
+                       sxiusbphy_write(sc, idx,
+                           PHY_CTRL_RES45_CAL_EN, 0x1, 1);
+
+               sxiusbphy_write(sc, idx,
+                   PHY_CTRL_SET_TX_AMPLITUDE_TUNE, 0x14, 5);
+
+               sxiusbphy_write(sc, idx, PHY_CTRL_SET_DISCON_DET_THRESHOLD,
+                   sxiusbphy_disc_det_treshold(ptyp), 2);
+       }
+
+       /* enable passby etc. */
+       if (ioh) {
+               if (ptyp == SXIUSBPHY_T_A83 && idx == 2)
+                       bits |= A83T_HSIC | A83T_HSIC_CON_INT |
+                           A83T_HSIC_CON_DET | A83T_EHCI_HS_FORCE;
+
+               bus_space_write_4(iot, ioh, HCI_ICR,
+                   bus_space_read_4(iot, ioh, HCI_ICR) | bits);
+       }
+
+       if (idx == 0) {
+#if 1
+               HSET4(sc, PHY_ISCR, PHY_ISCR_DPDM_PULLUP_EN);
+               HSET4(sc, PHY_ISCR, PHY_ISCR_ID_PULLUP_EN);
+#else
+               /* iirc. what netbsd does here */
+               HCMS4(sc, PHY_ISCR,
+                   PHY_ISCR_FORCE_ID_MASK | PHY_ISCR_FORCE_VBUS_VALID_MASK,
+                   PHY_ISCR_FORCE_ID_LOW | PHY_ISCR_FORCE_VBUS_VALID_HIGH |
+                   PHY_ISCR_DPDM_PULLUP_EN | PHY_ISCR_ID_PULLUP_EN);
+#endif
+               /* phy0 has "dualroute" to both *HCI and MUSB */
+               if (ptyp >= SXIUSBPHY_T_H3)     /* route away from MUSB */
+                       HCLR4(sc, PHY_OTGCTRL, PHY_OTGCTRL_ROUTE_MUSB);
+       }
+
+       /* XXX */
+       phy_supply = sc->sc_phy_vbus_supply[idx];
+       if (phy_supply)
+               regulator_enable(phy_supply);
+
+       return 0;
+}
+
+void
+sxiusbphy_write(struct sxiusbphy_softc *sc, u_int phy_index,
+    u_int bit_addr, u_int bits, u_int len)
+{
+       const uint32_t usbc_mask = PHY_CTRL_USBCn(phy_index);
+       bus_size_t reg = sc->sc_phyreg;
+
+       if (reg == PHY_CTRL_A33)
+               HWRITE4(sc, reg, 0);
+       for (; len-- > 0; bits >>= 1) {
+               HCMS4(sc, reg, PHY_CTRL_ADDR,
+                   (bit_addr++ << PHY_CTRL_ADDR_SHIFT));
+               HCMS4(sc, reg, PHY_CTRL_DATA,
+                   ((bits & 1) << PHY_CTRL_DATA_SHIFT));
+               HSET4(sc, reg, usbc_mask);
+               HCLR4(sc, reg, usbc_mask);
+       }
+}

Reply via email to