Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/arch Add USB3 support.



details:   https://anonhg.NetBSD.org/src/rev/ae022122fe0c
branches:  trunk
changeset: 936045:ae022122fe0c
user:      jmcneill <jmcneill%NetBSD.org@localhost>
date:      Thu Jul 16 21:34:52 2020 +0000

description:
Add USB3 support.

diffstat:

 sys/arch/evbmips/conf/OCTEON              |    6 +-
 sys/arch/mips/cavium/dev/octeon_xhci.c    |  391 ++++++++++++++++++++++++++++++
 sys/arch/mips/cavium/dev/octeon_xhcireg.h |   89 ++++++
 sys/arch/mips/conf/files.octeon           |    5 +-
 4 files changed, 488 insertions(+), 3 deletions(-)

diffs (truncated from 535 to 300 lines):

diff -r 5837943a024e -r ae022122fe0c sys/arch/evbmips/conf/OCTEON
--- a/sys/arch/evbmips/conf/OCTEON      Thu Jul 16 21:33:50 2020 +0000
+++ b/sys/arch/evbmips/conf/OCTEON      Thu Jul 16 21:34:52 2020 +0000
@@ -1,11 +1,11 @@
-#      $NetBSD: OCTEON,v 1.4 2020/07/16 18:39:18 jmcneill Exp $
+#      $NetBSD: OCTEON,v 1.5 2020/07/16 21:34:52 jmcneill Exp $
 
 include        "arch/mips/conf/std.octeon"
 include        "arch/evbmips/conf/files.octeon"
 
 #options       INCLUDE_CONFIG_FILE     # embed config file in kernel binary
 
-#ident                 "ERLITE-$Revision: 1.4 $"
+#ident                 "ERLITE-$Revision: 1.5 $"
 
 maxusers       32
 
@@ -135,8 +135,10 @@
 octrnm*                at iobus?               # Random Number Memory (and generator)
 
 dwctwo*                at iobus?
+xhci*          at fdt?
 
 usb*           at dwctwo?
+usb*           at xhci?
 
 uhub*          at usb?
 
diff -r 5837943a024e -r ae022122fe0c sys/arch/mips/cavium/dev/octeon_xhci.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/arch/mips/cavium/dev/octeon_xhci.c    Thu Jul 16 21:34:52 2020 +0000
@@ -0,0 +1,391 @@
+/*     $NetBSD: octeon_xhci.c,v 1.1 2020/07/16 21:34:52 jmcneill Exp $ */
+/*     $OpenBSD: octxhci.c,v 1.4 2019/09/29 04:32:23 visa Exp $        */
+
+/*
+ * Copyright (c) 2017 Visa Hankala
+ * Copyright (c) 2020 Jared McNeill <jmcneill%invisible.ca@localhost>
+ *
+ * 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.
+ */
+
+/*
+ * Driver for OCTEON USB3 controller bridge.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/malloc.h>
+
+#include <mips/cavium/octeonvar.h>
+
+#include <mips/cavium/dev/octeon_xhcireg.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/xhcireg.h>
+#include <dev/usb/xhcivar.h>
+
+#include <dev/fdt/fdtvar.h>
+
+#define XCTL_RD_8(sc, reg) \
+       bus_space_read_8((sc)->sc_iot, (sc)->sc_ioh, (reg))
+#define XCTL_WR_8(sc, reg, val) \
+       bus_space_write_8((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
+
+struct octxhci_softc {
+       struct xhci_softc       sc_xhci;
+       bus_space_tag_t         sc_iot;
+       bus_space_handle_t      sc_ioh;
+       struct fdtbus_gpio_pin  *sc_power_gpio;
+       int                     sc_unit;
+};
+
+static int     octxhci_match(device_t, cfdata_t, void *);
+static void    octxhci_attach(device_t, device_t, void *);
+
+static int     octxhci_dwc3_init(struct xhci_softc *);
+static void    octxhci_uctl_init(struct octxhci_softc *, uint64_t, uint64_t);
+
+static void    octxhci_bus_io_init(bus_space_tag_t, void *);
+
+static struct mips_bus_space octxhci_bus_tag;
+
+CFATTACH_DECL_NEW(octxhci, sizeof(struct octxhci_softc),
+    octxhci_match, octxhci_attach, NULL, NULL);
+
+static const char * compatible[] = {
+       "cavium,octeon-7130-usb-uctl",
+       NULL
+};
+
+int
+octxhci_match(device_t parent, cfdata_t cf, void *aux)
+{
+       struct fdt_attach_args * const faa = aux;
+
+       return of_match_compatible(faa->faa_phandle, compatible);
+}
+
+void
+octxhci_attach(device_t parent, device_t self, void *aux)
+{
+       struct octxhci_softc *osc = device_private(self);
+       struct xhci_softc *sc = &osc->sc_xhci;
+       struct fdt_attach_args * const faa = aux;
+       const int phandle = faa->faa_phandle;
+       const char *clock_type_hs;
+       const char *clock_type_ss;
+       u_int clock_freq, clock_sel;
+       char intrstr[128];
+       int child, error;
+       bus_addr_t addr;
+       bus_size_t size;
+       void *ih;
+
+       osc->sc_iot = faa->faa_bst;
+
+       if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
+               aprint_error(": couldn't get bridge registers\n");
+               return;
+       }
+       if (bus_space_map(osc->sc_iot, addr, size, 0, &osc->sc_ioh) != 0) {
+               aprint_error(": couldn't map bridge registers\n");
+               return;
+       }
+       osc->sc_power_gpio = fdtbus_gpio_acquire(phandle, "power",
+           GPIO_PIN_OUTPUT);
+       osc->sc_unit = (addr >> 24) & 0x1;
+
+       octxhci_bus_io_init(&octxhci_bus_tag, NULL);
+
+       sc->sc_dev = self;
+       sc->sc_bus.ub_hcpriv = sc;
+       sc->sc_bus.ub_dmatag = faa->faa_dmat;
+       sc->sc_iot = &octxhci_bus_tag;
+
+       child = of_find_bycompat(phandle, "synopsys,dwc3");
+       if (child == -1) {
+               aprint_error(": couldn't find dwc3 child node\n");
+               return;
+       }
+       if (fdtbus_get_reg(child, 0, &addr, &size) != 0) {
+               aprint_error(": couldn't get xhci registers\n");
+               return;
+       }
+       if (bus_space_map(sc->sc_iot, addr, size, 0, &sc->sc_ioh) != 0) {
+               aprint_error(": couldn't map xhci registers\n");
+               return;
+       }
+
+       if (of_getprop_uint32(phandle, "refclk-frequency", &clock_freq) != 0) {
+               aprint_error(": couldn't get refclk-frequency property\n");
+               return;
+       }
+       clock_type_hs = fdtbus_get_string(phandle, "refclk-type-hs");
+       if (clock_type_hs == NULL) {
+               aprint_error(": couldn't get refclk-type-hs property\n");
+               return;
+       }
+       clock_type_ss = fdtbus_get_string(phandle, "refclk-type-ss");
+       if (clock_type_ss == NULL) {
+               aprint_error(": couldn't get refclk-type-ss property\n");
+               return;
+       }
+
+       clock_sel = 0;
+       if (strcmp(clock_type_ss, "dlmc_ref_clk1") == 0)
+               clock_sel |= 1;
+       if (strcmp(clock_type_hs, "pll_ref_clk") == 0)
+               clock_sel |= 2;
+
+       if (0)
+       octxhci_uctl_init(osc, clock_freq, clock_sel);
+
+       if (octxhci_dwc3_init(sc) != 0) {
+               /* Error message has been printed already. */
+               return;
+       }
+
+       if (!fdtbus_intr_str(child, 0, intrstr, sizeof(intrstr))) {
+               aprint_error_dev(self, "failed to decode interrupt\n");
+               return;
+       }
+
+       ih = fdtbus_intr_establish(child, 0, IPL_USB, FDT_INTR_MPSAFE,
+           xhci_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);
+
+       sc->sc_bus.ub_revision = USBREV_3_0;
+       error = xhci_init(sc);
+       if (error != 0) {
+               aprint_error_dev(self, "init failed, error = %d\n", error);
+               return;
+       }
+
+       sc->sc_child = config_found(self, &sc->sc_bus, usbctlprint);
+       sc->sc_child2 = config_found(self, &sc->sc_bus2, usbctlprint);
+}
+
+void
+octxhci_uctl_init(struct octxhci_softc *sc, uint64_t clock_freq,
+    uint64_t clock_sel)
+{
+       static const uint32_t clock_divs[] = { 1, 2, 4, 6, 8, 16, 24, 32 };
+       uint64_t i, val;
+       uint64_t ioclock = octeon_ioclock_speed();
+       uint64_t mpll_mult;
+       uint64_t refclk_fsel;
+#if notyet
+       int output_sel;
+#endif
+
+       /*
+        * Put the bridge controller, USB core, PHY, and clock divider
+        * into reset.
+        */
+       val = XCTL_RD_8(sc, XCTL_CTL);
+       val |= XCTL_CTL_UCTL_RST;
+       val |= XCTL_CTL_UAHC_RST;
+       val |= XCTL_CTL_UPHY_RST;
+       XCTL_WR_8(sc, XCTL_CTL, val);
+       val = XCTL_RD_8(sc, XCTL_CTL);
+       val |= XCTL_CTL_CLKDIV_RST;
+       XCTL_WR_8(sc, XCTL_CTL, val);
+
+       /* Select IO clock divisor. */
+       for (i = 0; i < __arraycount(clock_divs); i++) {
+               if (ioclock / clock_divs[i] < 300000000)
+                       break;
+       }
+
+       /* Update the divisor and enable the clock. */
+       val = XCTL_RD_8(sc, XCTL_CTL);
+       val &= ~XCTL_CTL_CLKDIV_SEL;
+       val |= (i << XCTL_CTL_CLKDIV_SEL_SHIFT) & XCTL_CTL_CLKDIV_SEL;
+       val |= XCTL_CTL_CLK_EN;
+       XCTL_WR_8(sc, XCTL_CTL, val);
+
+       /* Take the clock divider out of reset. */
+       val = XCTL_RD_8(sc, XCTL_CTL);
+       val &= ~XCTL_CTL_CLKDIV_RST;
+       XCTL_WR_8(sc, XCTL_CTL, val);
+
+       /* Select the reference clock. */
+       switch (clock_freq) {
+       case 50000000:
+               refclk_fsel = 0x07;
+               mpll_mult = 0x32;
+               break;
+       case 125000000:
+               refclk_fsel = 0x07;
+               mpll_mult = 0x28;
+               break;
+       case 100000000:
+       default:
+               if (clock_sel < 2)
+                       refclk_fsel = 0x27;
+               else
+                       refclk_fsel = 0x07;
+               mpll_mult = 0x19;
+               break;
+       }
+
+       /* Set the clock and power up PHYs. */
+       val = XCTL_RD_8(sc, XCTL_CTL);
+       val &= ~XCTL_CTL_REFCLK_SEL;
+       val |= clock_sel << XCTL_CTL_REFCLK_SEL_SHIFT;
+       val &= ~XCTL_CTL_REFCLK_DIV2;
+       val &= ~XCTL_CTL_REFCLK_FSEL;
+       val |= refclk_fsel << XCTL_CTL_REFCLK_FSEL_SHIFT;
+       val &= ~XCTL_CTL_MPLL_MULT;
+       val |= mpll_mult << XCTL_CTL_MPLL_MULT_SHIFT;
+       val |= XCTL_CTL_SSC_EN;
+       val |= XCTL_CTL_REFCLK_SSP_EN;
+       val |= XCTL_CTL_SSPOWER_EN;
+       val |= XCTL_CTL_HSPOWER_EN;
+       XCTL_WR_8(sc, XCTL_CTL, val);
+
+       delay(100);
+
+       /* Take the bridge out of reset. */



Home | Main Index | Thread Index | Old Index