Module Name: src Committed By: jmcneill Date: Tue Jul 3 16:09:04 UTC 2018
Modified Files: src/sys/arch/arm/samsung: exynos_ehci.c exynos_ohci.c exynos_usbphy.c files.exynos Added Files: src/sys/arch/arm/samsung: exynos_usbdrdphy.c Removed Files: src/sys/arch/arm/samsung: exynos_usb3.c Log Message: Add support for Samsung Exynos USB. To generate a diff of this commit: cvs rdiff -u -r1.3 -r1.4 src/sys/arch/arm/samsung/exynos_ehci.c cvs rdiff -u -r1.2 -r1.3 src/sys/arch/arm/samsung/exynos_ohci.c cvs rdiff -u -r1.1 -r0 src/sys/arch/arm/samsung/exynos_usb3.c cvs rdiff -u -r0 -r1.1 src/sys/arch/arm/samsung/exynos_usbdrdphy.c cvs rdiff -u -r1.1 -r1.2 src/sys/arch/arm/samsung/exynos_usbphy.c cvs rdiff -u -r1.27 -r1.28 src/sys/arch/arm/samsung/files.exynos Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/arch/arm/samsung/exynos_ehci.c diff -u src/sys/arch/arm/samsung/exynos_ehci.c:1.3 src/sys/arch/arm/samsung/exynos_ehci.c:1.4 --- src/sys/arch/arm/samsung/exynos_ehci.c:1.3 Mon Apr 9 16:21:09 2018 +++ src/sys/arch/arm/samsung/exynos_ehci.c Tue Jul 3 16:09:04 2018 @@ -1,12 +1,9 @@ -/* $NetBSD: exynos_ehci.c,v 1.3 2018/04/09 16:21:09 jakllsch Exp $ */ +/* $NetBSD: exynos_ehci.c,v 1.4 2018/07/03 16:09:04 jmcneill Exp $ */ /*- - * Copyright (c) 2014 The NetBSD Foundation, Inc. + * Copyright (c) 2015-2018 Jared McNeill <jmcne...@invisible.ca> * All rights reserved. * - * This code is derived from software contributed to The NetBSD Foundation - * by Reinoud Zandijk. - * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -16,107 +13,132 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. */ -#include "locators.h" -#include "ohci.h" -#include "ehci.h" - #include <sys/cdefs.h> - -__KERNEL_RCSID(1, "$NetBSD: exynos_ehci.c,v 1.3 2018/04/09 16:21:09 jakllsch Exp $"); +__KERNEL_RCSID(0, "$NetBSD: exynos_ehci.c,v 1.4 2018/07/03 16:09:04 jmcneill Exp $"); #include <sys/param.h> -#include <sys/systm.h> -#include <sys/kernel.h> -#include <sys/intr.h> #include <sys/bus.h> #include <sys/device.h> -#include <sys/proc.h> -#include <sys/queue.h> -#include <sys/kmem.h> -#include <sys/gpio.h> +#include <sys/intr.h> +#include <sys/systm.h> +#include <sys/kernel.h> #include <dev/usb/usb.h> #include <dev/usb/usbdi.h> #include <dev/usb/usbdivar.h> #include <dev/usb/usb_mem.h> - #include <dev/usb/ehcireg.h> #include <dev/usb/ehcivar.h> -#include <arm/samsung/exynos_reg.h> -#include <arm/samsung/exynos_var.h> - #include <dev/fdt/fdtvar.h> static int exynos_ehci_match(device_t, cfdata_t, void *); static void exynos_ehci_attach(device_t, device_t, void *); -CFATTACH_DECL_NEW(exynos_ehci, sizeof(struct ehci_softc), - exynos_ehci_match, exynos_ehci_attach, NULL, NULL); - +CFATTACH_DECL2_NEW(exynos_ehci, sizeof(struct ehci_softc), + exynos_ehci_match, exynos_ehci_attach, NULL, + ehci_activate, NULL, ehci_childdet); static int exynos_ehci_match(device_t parent, cfdata_t cf, void *aux) { - const char * const compatible[] = { "samsung,exynos5-ehci", - NULL }; + const char * const compatible[] = { + "samsung,exynos4210-ehci", + NULL + }; struct fdt_attach_args * const faa = aux; + return of_match_compatible(faa->faa_phandle, compatible); } - static void exynos_ehci_attach(device_t parent, device_t self, void *aux) { - struct ehci_softc *sc = device_private(self); + struct ehci_softc * const sc = device_private(self); struct fdt_attach_args * const faa = aux; + const int phandle = faa->faa_phandle; + struct fdtbus_phy *phy; + struct clk *clk; + char intrstr[128]; bus_addr_t addr; bus_size_t size; - int error; + int error, child; + void *ih; - if (fdtbus_get_reg(faa->faa_phandle, 0, &addr, &size) != 0) { + if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) { aprint_error(": couldn't get registers\n"); return; } + /* Enable clocks */ + clk = fdtbus_clock_get(phandle, "usbhost"); + if (clk == NULL || clk_enable(clk) != 0) { + aprint_error(": couldn't enable clock\n"); + return; + } + + /* Enable phys for each port */ + for (child = OF_child(phandle); child; child = OF_peer(child)) { + phy = fdtbus_phy_get_index(child, 0); + if (phy && fdtbus_phy_enable(phy, true) != 0) + aprint_error(": couldn't enable phy for %s\n", + fdtbus_get_string(child, "name")); + } + sc->sc_dev = self; - sc->iot = faa->faa_bst; - sc->sc_size = size; - sc->sc_bus.ub_dmatag = faa->faa_dmat; sc->sc_bus.ub_hcpriv = sc; + sc->sc_bus.ub_dmatag = faa->faa_dmat; sc->sc_bus.ub_revision = USBREV_2_0; - sc->sc_ncomp = 0; - - error = bus_space_map(sc->iot, addr, size, 0, &sc->ioh); - if (error) { - aprint_error(": couldn't map %#llx: %d", - (uint64_t)addr, error); + if (of_hasprop(phandle, "has-transaction-translator")) + sc->sc_flags |= EHCIF_ETTF; + else + sc->sc_ncomp = 1; + sc->sc_size = size; + sc->iot = faa->faa_bst; + if (bus_space_map(sc->iot, addr, size, 0, &sc->ioh) != 0) { + aprint_error(": couldn't map registers\n"); return; } + aprint_naive("\n"); + aprint_normal(": Exynos EHCI\n"); + + /* Disable interrupts */ + sc->sc_offs = EREAD1(sc, EHCI_CAPLENGTH); + EOWRITE4(sc, EHCI_USBINTR, 0); + + if (!fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr))) { + aprint_error_dev(self, "failed to decode interrupt\n"); + return; + } - aprint_naive(": EHCI USB controller\n"); - aprint_normal(": EHCI NOT IMPLEMENTED\n"); + ih = fdtbus_intr_establish(phandle, 0, IPL_USB, FDT_INTR_MPSAFE, + ehci_intr, sc); + if (ih == NULL) { + aprint_error_dev(self, "couldn't establish interrupt on %s\n", + intrstr); + return; + } + aprint_normal_dev(self, "interrupting on %s\n", intrstr); - /* attach */ error = ehci_init(sc); if (error) { aprint_error_dev(self, "init failed, error = %d\n", error); - /* disable : TBD */ return; } + sc->sc_child = config_found(self, &sc->sc_bus, usbctlprint); } Index: src/sys/arch/arm/samsung/exynos_ohci.c diff -u src/sys/arch/arm/samsung/exynos_ohci.c:1.2 src/sys/arch/arm/samsung/exynos_ohci.c:1.3 --- src/sys/arch/arm/samsung/exynos_ohci.c:1.2 Sat Apr 23 10:15:28 2016 +++ src/sys/arch/arm/samsung/exynos_ohci.c Tue Jul 3 16:09:04 2018 @@ -1,12 +1,9 @@ -/* $NetBSD: exynos_ohci.c,v 1.2 2016/04/23 10:15:28 skrll Exp $ */ +/* $NetBSD: exynos_ohci.c,v 1.3 2018/07/03 16:09:04 jmcneill Exp $ */ /*- - * Copyright (c) 2014 The NetBSD Foundation, Inc. + * Copyright (c) 2015-2018 Jared McNeill <jmcne...@invisible.ca> * All rights reserved. * - * This code is derived from software contributed to The NetBSD Foundation - * by Reinoud Zandijk. - * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -16,105 +13,128 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. */ -#include "locators.h" -#include "ohci.h" -#include "ehci.h" - #include <sys/cdefs.h> - -__KERNEL_RCSID(1, "$NetBSD: exynos_ohci.c,v 1.2 2016/04/23 10:15:28 skrll Exp $"); +__KERNEL_RCSID(0, "$NetBSD: exynos_ohci.c,v 1.3 2018/07/03 16:09:04 jmcneill Exp $"); #include <sys/param.h> -#include <sys/systm.h> -#include <sys/kernel.h> -#include <sys/intr.h> #include <sys/bus.h> #include <sys/device.h> -#include <sys/proc.h> -#include <sys/queue.h> -#include <sys/kmem.h> -#include <sys/gpio.h> +#include <sys/intr.h> +#include <sys/systm.h> +#include <sys/kernel.h> #include <dev/usb/usb.h> #include <dev/usb/usbdi.h> #include <dev/usb/usbdivar.h> #include <dev/usb/usb_mem.h> - #include <dev/usb/ohcireg.h> #include <dev/usb/ohcivar.h> -#include <arm/samsung/exynos_reg.h> -#include <arm/samsung/exynos_var.h> - #include <dev/fdt/fdtvar.h> static int exynos_ohci_match(device_t, cfdata_t, void *); static void exynos_ohci_attach(device_t, device_t, void *); -CFATTACH_DECL_NEW(exynos_ohci, sizeof(struct ohci_softc), - exynos_ohci_match, exynos_ohci_attach, NULL, NULL); - +CFATTACH_DECL2_NEW(exynos_ohci, sizeof(struct ohci_softc), + exynos_ohci_match, exynos_ohci_attach, NULL, + ohci_activate, NULL, ohci_childdet); static int exynos_ohci_match(device_t parent, cfdata_t cf, void *aux) { - const char * const compatible[] = { "samsung,exynos5-ohci", - NULL }; + const char * const compatible[] = { + "samsung,exynos4210-ohci", + NULL + }; struct fdt_attach_args * const faa = aux; + return of_match_compatible(faa->faa_phandle, compatible); } - static void exynos_ohci_attach(device_t parent, device_t self, void *aux) { - struct ohci_softc *sc = device_private(self); + struct ohci_softc * const sc = device_private(self); struct fdt_attach_args * const faa = aux; + const int phandle = faa->faa_phandle; + struct fdtbus_phy *phy; + struct clk *clk; + char intrstr[128]; bus_addr_t addr; bus_size_t size; - int error; + int error, child; + void *ih; - if (fdtbus_get_reg(faa->faa_phandle, 0, &addr, &size) != 0) { + if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) { aprint_error(": couldn't get registers\n"); return; } + /* Enable clocks */ + clk = fdtbus_clock_get(phandle, "usbhost"); + if (clk == NULL || clk_enable(clk) != 0) { + aprint_error(": couldn't enable clock\n"); + return; + } + + /* Enable phys for each port */ + for (child = OF_child(phandle); child; child = OF_peer(child)) { + phy = fdtbus_phy_get_index(child, 0); + if (phy && fdtbus_phy_enable(phy, true) != 0) + aprint_error(": couldn't enable phy for %s\n", + fdtbus_get_string(child, "name")); + } + sc->sc_dev = self; - sc->iot = faa->faa_bst; - sc->sc_size = size; - sc->sc_bus.ub_dmatag = faa->faa_dmat; sc->sc_bus.ub_hcpriv = sc; + sc->sc_bus.ub_dmatag = faa->faa_dmat; + sc->sc_flags = 0; + sc->sc_size = size; + sc->iot = faa->faa_bst; + if (bus_space_map(sc->iot, addr, size, 0, &sc->ioh) != 0) { + aprint_error(": couldn't map registers\n"); + return; + } - error = bus_space_map(sc->iot, addr, size, 0, &sc->ioh); - if (error) { - aprint_error(": couldn't map %#llx: %d", - (uint64_t)addr, error); + aprint_naive("\n"); + aprint_normal(": Exynos OHCI\n"); + + /* Disable interrupts */ + bus_space_write_4(sc->iot, sc->ioh, OHCI_INTERRUPT_DISABLE, + OHCI_ALL_INTRS); + + if (!fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr))) { + aprint_error_dev(self, "failed to decode interrupt\n"); return; } - aprint_naive(": OHCI USB controller\n"); - aprint_normal(": OHCI NOT IMPLEMENTED\n"); + ih = fdtbus_intr_establish(phandle, 0, IPL_USB, FDT_INTR_MPSAFE, + ohci_intr, sc); + if (ih == NULL) { + aprint_error_dev(self, "couldn't establish interrupt on %s\n", + intrstr); + return; + } + aprint_normal_dev(self, "interrupting on %s\n", intrstr); - /* attach */ error = ohci_init(sc); if (error) { aprint_error_dev(self, "init failed, error = %d\n", error); - /* disable : TBD */ return; } + sc->sc_child = config_found(self, &sc->sc_bus, usbctlprint); } - Index: src/sys/arch/arm/samsung/exynos_usbphy.c diff -u src/sys/arch/arm/samsung/exynos_usbphy.c:1.1 src/sys/arch/arm/samsung/exynos_usbphy.c:1.2 --- src/sys/arch/arm/samsung/exynos_usbphy.c:1.1 Sun Dec 27 02:54:12 2015 +++ src/sys/arch/arm/samsung/exynos_usbphy.c Tue Jul 3 16:09:04 2018 @@ -1,12 +1,9 @@ -/* $NetBSD: exynos_usbphy.c,v 1.1 2015/12/27 02:54:12 marty Exp $ */ +/* $NetBSD: exynos_usbphy.c,v 1.2 2018/07/03 16:09:04 jmcneill Exp $ */ /*- - * Copyright (c) 2014 The NetBSD Foundation, Inc. + * Copyright (c) 2018 Jared McNeill <jmcne...@invisible.ca> * All rights reserved. * - * This code is derived from software contributed to The NetBSD Foundation - * by Reinoud Zandijk. - * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -29,81 +26,268 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include "locators.h" -#include "ohci.h" -#include "ehci.h" - #include <sys/cdefs.h> -__KERNEL_RCSID(1, "$NetBSD: exynos_usbphy.c,v 1.1 2015/12/27 02:54:12 marty Exp $"); +__KERNEL_RCSID(0, "$NetBSD: exynos_usbphy.c,v 1.2 2018/07/03 16:09:04 jmcneill Exp $"); #include <sys/param.h> -#include <sys/systm.h> -#include <sys/kernel.h> -#include <sys/intr.h> #include <sys/bus.h> #include <sys/device.h> -#include <sys/proc.h> -#include <sys/queue.h> +#include <sys/intr.h> +#include <sys/systm.h> #include <sys/kmem.h> -#include <sys/gpio.h> -#include <dev/usb/usb.h> -#include <dev/usb/usbdi.h> -#include <dev/usb/usbdivar.h> -#include <dev/usb/usb_mem.h> +#include <dev/fdt/fdtvar.h> +#include <dev/fdt/syscon.h> #include <arm/samsung/exynos_reg.h> -#include <arm/samsung/exynos_var.h> +#include <arm/samsung/exynos5_reg.h> -#include <dev/fdt/fdtvar.h> +/* + * System Registers + */ +#define USB20PHY_CFG 0x230 +#define USB20PHY_CFG_HOST_LINK_EN __BIT(0) + +/* + * PMU Registers + */ +#define USBHOST_PHY_CTRL 0x708 +#define USBHOST_PHY_CTRL_EN __BIT(0) + +enum { + PHY_ID_DEVICE = 0, + PHY_ID_HOST, + PHY_ID_HSIC0, + PHY_ID_HSIC1, + NPHY_ID +}; + +static int exynos_usbphy_match(device_t, cfdata_t, void *); +static void exynos_usbphy_attach(device_t, device_t, void *); + +static const struct of_compat_data compat_data[] = { + { "samsung,exynos5250-usb2-phy", 0 }, + { NULL } +}; + +struct exynos_usbphy_softc; + +struct exynos_usbphy { + struct exynos_usbphy_softc *phy_sc; + u_int phy_index; +}; struct exynos_usbphy_softc { - device_t sc_dev; - bus_space_tag_t sc_bst; - bus_space_handle_t sc_bsh; + device_t sc_dev; + bus_space_tag_t sc_bst; + bus_space_handle_t sc_bsh; + int sc_phandle; + + struct syscon *sc_sysreg; + struct syscon *sc_pmureg; + + u_int sc_refcnt; + + struct exynos_usbphy *sc_phy; + u_int sc_nphy; + + struct fdtbus_gpio_pin *sc_gpio_id_det; + struct fdtbus_gpio_pin *sc_gpio_vbus_det; }; -static int exynos_usbphy_match(device_t, cfdata_t, void *); -static void exynos_usbphy_attach(device_t, device_t, void *); +#define PHY_READ(sc, reg) \ + bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg)) +#define PHY_WRITE(sc, reg, val) \ + bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val)) CFATTACH_DECL_NEW(exynos_usbphy, sizeof(struct exynos_usbphy_softc), - exynos_usbphy_match, exynos_usbphy_attach, NULL, NULL); + exynos_usbphy_match, exynos_usbphy_attach, NULL, NULL); + +static void * +exynos_usbphy_acquire(device_t dev, const void *data, size_t len) +{ + struct exynos_usbphy_softc * const sc = device_private(dev); + + if (len != 4) + return NULL; + + const u_int index = be32dec(data); + if (index >= sc->sc_nphy) + return NULL; + + return &sc->sc_phy[index]; +} + +static void +exynos_usbphy_release(device_t dev, void *priv) +{ +} + +static int +exynos_usbphy_enable(device_t dev, void *priv, bool enable) +{ + struct exynos_usbphy * const phy = priv; + struct exynos_usbphy_softc * const sc = phy->phy_sc; + bool do_common; + uint32_t val; + + if (enable) { + sc->sc_refcnt++; + } else { + KASSERT(sc->sc_refcnt > 0); + sc->sc_refcnt--; + } + do_common = sc->sc_refcnt == enable; + + if (do_common) { + syscon_lock(sc->sc_sysreg); + val = syscon_read_4(sc->sc_sysreg, USB20PHY_CFG); + if (enable) + val |= USB20PHY_CFG_HOST_LINK_EN; + else + val &= ~USB20PHY_CFG_HOST_LINK_EN; + syscon_write_4(sc->sc_sysreg, USB20PHY_CFG, val); + syscon_unlock(sc->sc_sysreg); + + syscon_lock(sc->sc_pmureg); + val = syscon_read_4(sc->sc_pmureg, USBHOST_PHY_CTRL); + if (enable) + val |= USBHOST_PHY_CTRL_EN; + else + val &= ~USBHOST_PHY_CTRL_EN; + syscon_write_4(sc->sc_pmureg, USBHOST_PHY_CTRL, val); + syscon_unlock(sc->sc_pmureg); + + if (enable) { + val = PHY_READ(sc, USB_PHY_HOST_CTRL0); + val &= ~HOST_CTRL0_COMMONON_N; + val &= ~HOST_CTRL0_PHY_SWRST; + val &= ~HOST_CTRL0_PHY_SWRST_ALL; + val &= ~HOST_CTRL0_SIDDQ; + val &= ~HOST_CTRL0_FORCESUSPEND; + val &= ~HOST_CTRL0_FORCESLEEP; + val &= ~HOST_CTRL0_FSEL_MASK; + val |= __SHIFTIN(FSEL_CLKSEL_24M, HOST_CTRL0_FSEL_MASK); + val |= HOST_CTRL0_LINK_SWRST; + val |= HOST_CTRL0_UTMI_SWRST; + PHY_WRITE(sc, USB_PHY_HOST_CTRL0, val); + + delay(10000); + + val &= ~HOST_CTRL0_LINK_SWRST; + val &= ~HOST_CTRL0_UTMI_SWRST; + PHY_WRITE(sc, USB_PHY_HOST_CTRL0, val); + + delay(10000); + } + } + + switch (phy->phy_index) { + case PHY_ID_HSIC0: + case PHY_ID_HSIC1: + if (enable) { + const bus_size_t reg = phy->phy_index == PHY_ID_HSIC0 ? + USB_PHY_HSIC_CTRL1 : USB_PHY_HSIC_CTRL2; + + val = HSIC_CTRL_PHY_SWRST; + val |= __SHIFTIN(HSIC_CTRL_REFCLKDIV_12, HSIC_CTRL_REFCLKDIV_MASK); + val |= __SHIFTIN(HSIC_CTRL_REFCLKSEL_DEFAULT, HSIC_CTRL_REFCLKSEL_MASK); + PHY_WRITE(sc, reg, val); + + delay(10000); + + val &= ~HSIC_CTRL_PHY_SWRST; + PHY_WRITE(sc, reg, val); + + delay(10000); + } + break; + } + + if (do_common) { + if (enable) { + val = PHY_READ(sc, USB_PHY_HOST_EHCICTRL); + val |= HOST_EHCICTRL_ENA_INCRXALIGN; + val |= HOST_EHCICTRL_ENA_INCR4; + val |= HOST_EHCICTRL_ENA_INCR8; + val |= HOST_EHCICTRL_ENA_INCR16; + PHY_WRITE(sc, USB_PHY_HOST_EHCICTRL, val); + } + } + + return 0; +} +const struct fdtbus_phy_controller_func exynos_usbphy_funcs = { + .acquire = exynos_usbphy_acquire, + .release = exynos_usbphy_release, + .enable = exynos_usbphy_enable, +}; static int exynos_usbphy_match(device_t parent, cfdata_t cf, void *aux) { - const char * const compatible[] = { "samsung,exynos5-usb2phy", - NULL }; struct fdt_attach_args * const faa = aux; - return of_match_compatible(faa->faa_phandle, compatible); -} + return of_match_compat_data(faa->faa_phandle, compat_data); +} static void exynos_usbphy_attach(device_t parent, device_t self, void *aux) { - struct exynos_usbphy_softc *sc = device_private(self); + struct exynos_usbphy_softc * const sc = device_private(self); struct fdt_attach_args * const faa = aux; + const int phandle = faa->faa_phandle; + struct clk *clk; bus_addr_t addr; bus_size_t size; - int error; + u_int n; - if (fdtbus_get_reg(faa->faa_phandle, 0, &addr, &size) != 0) { - aprint_error(": couldn't get registers\n"); + if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) { + aprint_error(": couldn't get phy registers\n"); return; } sc->sc_dev = self; + sc->sc_phandle = phandle; sc->sc_bst = faa->faa_bst; + if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) { + aprint_error(": couldn't map phy registers\n"); + return; + } + sc->sc_nphy = NPHY_ID; + sc->sc_phy = kmem_alloc(sizeof(*sc->sc_phy) * sc->sc_nphy, KM_SLEEP); + for (n = 0; n < sc->sc_nphy; n++) { + sc->sc_phy[n].phy_sc = sc; + sc->sc_phy[n].phy_index = n; + } - error = bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh); - if (error) { - aprint_error(": couldn't map %#llx: %d", - (uint64_t)addr, error); + sc->sc_sysreg = fdtbus_syscon_acquire(phandle, "samsung,sysreg-phandle"); + if (sc->sc_sysreg == NULL) { + aprint_error(": couldn't acquire sysreg syscon\n"); return; } + sc->sc_pmureg = fdtbus_syscon_acquire(phandle, "samsung,pmureg-phandle"); + if (sc->sc_pmureg == NULL) { + aprint_error(": couldn't acquire pmureg syscon\n"); + return; + } + + /* Enable clocks */ + clk = fdtbus_clock_get(phandle, "phy"); + if (clk == NULL || clk_enable(clk) != 0) { + aprint_error(": couldn't enable phy clock\n"); + return; + } + clk = fdtbus_clock_get(phandle, "ref"); + if (clk == NULL || clk_enable(clk) != 0) { + aprint_error(": couldn't enable ref clock\n"); + return; + } + + aprint_naive("\n"); + aprint_normal(": USB2 PHY\n"); - aprint_normal(": USB 2 PHY NOT IMPLEMENTED\n"); + fdtbus_register_phy_controller(self, phandle, &exynos_usbphy_funcs); } Index: src/sys/arch/arm/samsung/files.exynos diff -u src/sys/arch/arm/samsung/files.exynos:1.27 src/sys/arch/arm/samsung/files.exynos:1.28 --- src/sys/arch/arm/samsung/files.exynos:1.27 Mon Jul 2 12:53:51 2018 +++ src/sys/arch/arm/samsung/files.exynos Tue Jul 3 16:09:04 2018 @@ -1,4 +1,4 @@ -# $NetBSD: files.exynos,v 1.27 2018/07/02 12:53:51 jmcneill Exp $ +# $NetBSD: files.exynos,v 1.28 2018/07/03 16:09:04 jmcneill Exp $ # # Configuration info for Samsung Exynos SoC ARM Peripherals # @@ -79,25 +79,24 @@ attach exyopctl at fdt with exynos_pinc file arch/arm/samsung/exynos_pinctrl.c exynos_pinctrl needs-flag file arch/arm/samsung/exynos_gpio.c exynos_pinctrl needs-flag -# USB2 phy -device exyousbphy -attach exyousbphy at fdt with exynos_usbphy +# USB2 PHY +device exusbphy +attach exusbphy at fdt with exynos_usbphy file arch/arm/samsung/exynos_usbphy.c exynos_usbphy +# USB DRD PHY +device exusbdrdphy +attach exusbdrdphy at fdt with exynos_usbdrdphy +file arch/arm/samsung/exynos_usbdrdphy.c exynos_usbdrdphy + # USB2 Host Controller (OHCI) attach ohci at fdt with exynos_ohci file arch/arm/samsung/exynos_ohci.c exynos_ohci -#USB 2 Host Controller (EHCI) +# USB 2 Host Controller (EHCI) attach ehci at fdt with exynos_ehci file arch/arm/samsung/exynos_ehci.c exynos_ehci -# USB3 Host Controller (xHCI) -device exyousb : fdtbus -attach exyousb at fdt with exynos_usb -attach xhci at fdt -file arch/arm/samsung/exynos_usb3.c exynos_usb - # SD/MMC Host Controller attach dwcmmc at fdt with exynos_dwcmmc file arch/arm/samsung/exynos_dwcmmc.c exynos_dwcmmc Added files: Index: src/sys/arch/arm/samsung/exynos_usbdrdphy.c diff -u /dev/null src/sys/arch/arm/samsung/exynos_usbdrdphy.c:1.1 --- /dev/null Tue Jul 3 16:09:04 2018 +++ src/sys/arch/arm/samsung/exynos_usbdrdphy.c Tue Jul 3 16:09:04 2018 @@ -0,0 +1,288 @@ +/* $NetBSD: exynos_usbdrdphy.c,v 1.1 2018/07/03 16:09:04 jmcneill Exp $ */ + +/*- + * Copyright (c) 2018 Jared McNeill <jmcne...@invisible.ca> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> + +__KERNEL_RCSID(0, "$NetBSD: exynos_usbdrdphy.c,v 1.1 2018/07/03 16:09:04 jmcneill Exp $"); + +#include <sys/param.h> +#include <sys/bus.h> +#include <sys/device.h> +#include <sys/intr.h> +#include <sys/systm.h> +#include <sys/kmem.h> + +#include <dev/fdt/fdtvar.h> +#include <dev/fdt/syscon.h> + +/* + * PHY Registers + */ +#define PHY_LINK_SYSTEM 0x04 +#define PHY_LINK_SYSTEM_XHCI_VERCTL __BIT(27) +#define PHY_LINK_SYSTEM_FLADJ __BITS(6,1) +#define PHY_UTMI 0x08 +#define PHY_UTMI_OTGDISABLE __BIT(6) +#define PHY_CLK_RST 0x10 +#define PHY_CLK_RST_SSC_REFCLKSEL __BITS(30,23) +#define PHY_CLK_RST_SSC_EN __BIT(20) +#define PHY_CLK_RST_REF_SSP_EN __BIT(19) +#define PHY_CLK_RST_MPLL_MULT __BITS(17,11) +#define PHY_CLK_RST_MPLL_MULT_24M 0x68 +#define PHY_CLK_RST_FSEL __BITS(10,5) +#define PHY_CLK_RST_FSEL_24M 0x2a +#define PHY_CLK_RST_RETENABLEN __BIT(4) +#define PHY_CLK_RST_REFCLKSEL __BITS(3,2) +#define PHY_CLK_RST_REFCLKSEL_EXT 3 +#define PHY_CLK_RST_PORTRESET __BIT(1) +#define PHY_CLK_RST_COMMONONN __BIT(0) +#define PHY_REG0 0x14 +#define PHY_PARAM0 0x1c +#define PHY_PARAM0_REF_USE_PAD __BIT(31) +#define PHY_PARAM0_REF_LOSLEVEL __BITS(30,26) +#define PHY_PARAM1 0x20 +#define PHY_PARAM1_TXDEEMPH __BITS(4,0) +#define PHY_TEST 0x28 +#define PHY_TEST_POWERDOWN_SSP __BIT(3) +#define PHY_TEST_POWERDOWN_HSP __BIT(2) +#define PHY_BATCHG 0x30 +#define PHY_BATCHG_UTMI_CLKSEL __BIT(2) +#define PHY_RESUME 0x34 + +/* + * PMU Registers + */ +#define USBDRD_PHY_CTRL(n) (0x704 + (n) * 4) +#define USBDRD_PHY_CTRL_EN __BIT(0) + +static int exynos_usbdrdphy_match(device_t, cfdata_t, void *); +static void exynos_usbdrdphy_attach(device_t, device_t, void *); + +enum { + PHY_ID_UTMI_PLUS = 0, + PHY_ID_PIPE3, + NPHY_ID +}; + +static const struct of_compat_data compat_data[] = { + { "samsung,exynos5420-usbdrd-phy", 0 }, + { NULL } +}; + +struct exynos_usbdrdphy_softc; + +struct exynos_usbdrdphy { + struct exynos_usbdrdphy_softc *phy_sc; + u_int phy_index; +}; + +struct exynos_usbdrdphy_softc { + device_t sc_dev; + bus_space_tag_t sc_bst; + bus_space_handle_t sc_bsh; + int sc_phandle; + struct syscon *sc_pmureg; + + struct exynos_usbdrdphy *sc_phy; + u_int sc_nphy; + + struct fdtbus_gpio_pin *sc_gpio_id_det; + struct fdtbus_gpio_pin *sc_gpio_vbus_det; +}; + +#define PHY_READ(sc, reg) \ + bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg)) +#define PHY_WRITE(sc, reg, val) \ + bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val)) + +CFATTACH_DECL_NEW(exynos_usbdrdphy, sizeof(struct exynos_usbdrdphy_softc), + exynos_usbdrdphy_match, exynos_usbdrdphy_attach, NULL, NULL); + +static void * +exynos_usbdrdphy_acquire(device_t dev, const void *data, size_t len) +{ + struct exynos_usbdrdphy_softc * const sc = device_private(dev); + + if (len != 4) + return NULL; + + const u_int index = be32dec(data); + if (index >= sc->sc_nphy) + return NULL; + + return &sc->sc_phy[index]; +} + +static void +exynos_usbdrdphy_release(device_t dev, void *priv) +{ +} + +static int +exynos_usbdrdphy_enable(device_t dev, void *priv, bool enable) +{ + struct exynos_usbdrdphy * const phy = priv; + struct exynos_usbdrdphy_softc * const sc = phy->phy_sc; + uint32_t val; + + syscon_lock(sc->sc_pmureg); + val = syscon_read_4(sc->sc_pmureg, USBDRD_PHY_CTRL(phy->phy_index)); + if (enable) + val |= USBDRD_PHY_CTRL_EN; + else + val &= ~USBDRD_PHY_CTRL_EN; + syscon_write_4(sc->sc_pmureg, USBDRD_PHY_CTRL(phy->phy_index), val); + syscon_unlock(sc->sc_pmureg); + + return 0; +} + +const struct fdtbus_phy_controller_func exynos_usbdrdphy_funcs = { + .acquire = exynos_usbdrdphy_acquire, + .release = exynos_usbdrdphy_release, + .enable = exynos_usbdrdphy_enable, +}; + +static void +exynos_usbdrdphy_init(struct exynos_usbdrdphy_softc *sc) +{ + uint32_t val; + + PHY_WRITE(sc, PHY_REG0, 0); + + val = PHY_READ(sc, PHY_PARAM0); + val &= ~PHY_PARAM0_REF_USE_PAD; + val &= ~PHY_PARAM0_REF_LOSLEVEL; + val |= __SHIFTIN(9, PHY_PARAM0_REF_LOSLEVEL); + PHY_WRITE(sc, PHY_PARAM0, val); + + PHY_WRITE(sc, PHY_RESUME, 0); + + val = PHY_READ(sc, PHY_LINK_SYSTEM); + val |= PHY_LINK_SYSTEM_XHCI_VERCTL; + val &= ~PHY_LINK_SYSTEM_FLADJ; + val |= __SHIFTIN(0x20, PHY_LINK_SYSTEM_FLADJ); + PHY_WRITE(sc, PHY_LINK_SYSTEM, val); + + val = PHY_READ(sc, PHY_PARAM1); + val &= ~PHY_PARAM1_TXDEEMPH; + val |= __SHIFTIN(0x1c, PHY_PARAM1_TXDEEMPH); + PHY_WRITE(sc, PHY_PARAM1, val); + + val = PHY_READ(sc, PHY_BATCHG); + val |= PHY_BATCHG_UTMI_CLKSEL; + PHY_WRITE(sc, PHY_BATCHG, val); + + val = PHY_READ(sc, PHY_TEST); + val &= ~PHY_TEST_POWERDOWN_SSP; + val &= ~PHY_TEST_POWERDOWN_HSP; + PHY_WRITE(sc, PHY_TEST, val); + + PHY_WRITE(sc, PHY_UTMI, PHY_UTMI_OTGDISABLE); + + val = __SHIFTIN(PHY_CLK_RST_REFCLKSEL_EXT, PHY_CLK_RST_REFCLKSEL); + val |= __SHIFTIN(PHY_CLK_RST_FSEL_24M, PHY_CLK_RST_FSEL); + val |= __SHIFTIN(PHY_CLK_RST_MPLL_MULT_24M, PHY_CLK_RST_MPLL_MULT); + val |= __SHIFTIN(0x88, PHY_CLK_RST_SSC_REFCLKSEL); + val |= PHY_CLK_RST_PORTRESET; + val |= PHY_CLK_RST_RETENABLEN; + val |= PHY_CLK_RST_REF_SSP_EN; + val |= PHY_CLK_RST_SSC_EN; + val |= PHY_CLK_RST_COMMONONN; + PHY_WRITE(sc, PHY_CLK_RST, val); + + delay(50000); + + val &= ~PHY_CLK_RST_PORTRESET; + PHY_WRITE(sc, PHY_CLK_RST, val); +} + +static int +exynos_usbdrdphy_match(device_t parent, cfdata_t cf, void *aux) +{ + struct fdt_attach_args * const faa = aux; + + return of_match_compat_data(faa->faa_phandle, compat_data); +} + +static void +exynos_usbdrdphy_attach(device_t parent, device_t self, void *aux) +{ + struct exynos_usbdrdphy_softc * const sc = device_private(self); + struct fdt_attach_args * const faa = aux; + const int phandle = faa->faa_phandle; + struct clk *clk; + bus_addr_t addr; + bus_size_t size; + u_int n; + + if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) { + aprint_error(": couldn't get phy registers\n"); + return; + } + + sc->sc_dev = self; + sc->sc_phandle = phandle; + sc->sc_bst = faa->faa_bst; + if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) { + aprint_error(": couldn't map phy registers\n"); + return; + } + + sc->sc_nphy = NPHY_ID; + sc->sc_phy = kmem_alloc(sizeof(*sc->sc_phy) * sc->sc_nphy, KM_SLEEP); + for (n = 0; n < sc->sc_nphy; n++) { + sc->sc_phy[n].phy_sc = sc; + sc->sc_phy[n].phy_index = n; + } + + sc->sc_pmureg = fdtbus_syscon_acquire(phandle, "samsung,pmu-syscon"); + if (sc->sc_pmureg == NULL) { + aprint_error(": couldn't acquire pmureg syscon\n"); + return; + } + + /* Enable clocks */ + clk = fdtbus_clock_get(phandle, "phy"); + if (clk == NULL || clk_enable(clk) != 0) { + aprint_error(": couldn't enable phy clock\n"); + return; + } + clk = fdtbus_clock_get(phandle, "ref"); + if (clk == NULL || clk_enable(clk) != 0) { + aprint_error(": couldn't enable ref clock\n"); + return; + } + + aprint_naive("\n"); + aprint_normal(": USB DRD PHY\n"); + + exynos_usbdrdphy_init(sc); + + fdtbus_register_phy_controller(self, phandle, &exynos_usbdrdphy_funcs); +}