summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Matthew <jmatthew@cvs.openbsd.org>2016-03-18 05:38:11 +0000
committerJonathan Matthew <jmatthew@cvs.openbsd.org>2016-03-18 05:38:11 +0000
commit4fe9bb8c281e32f8554addaa7d4098a336134125 (patch)
tree1defe2d317755004c8fb8341dcb9eb0852ba5827
parentbd7f7bd5eb8a950a652060c499cad643741dcac7 (diff)
add octuctl, a driver for the Octeon II usb controller interface, and
attachments for ehci and ohci. ok uebayasi@ jasper@ visa@ mpi@
-rw-r--r--sys/arch/octeon/conf/GENERIC7
-rw-r--r--sys/arch/octeon/conf/RAMDISK9
-rw-r--r--sys/arch/octeon/conf/files.octeon10
-rw-r--r--sys/arch/octeon/dev/octehci.c118
-rw-r--r--sys/arch/octeon/dev/octeon_iobus.c4
-rw-r--r--sys/arch/octeon/dev/octohci.c142
-rw-r--r--sys/arch/octeon/dev/octuctl.c250
-rw-r--r--sys/arch/octeon/dev/octuctlreg.h77
-rw-r--r--sys/arch/octeon/dev/octuctlvar.h32
9 files changed, 645 insertions, 4 deletions
diff --git a/sys/arch/octeon/conf/GENERIC b/sys/arch/octeon/conf/GENERIC
index 60fa5eac3af..9f6ebf64ba6 100644
--- a/sys/arch/octeon/conf/GENERIC
+++ b/sys/arch/octeon/conf/GENERIC
@@ -1,4 +1,4 @@
-# $OpenBSD: GENERIC,v 1.24 2016/01/14 17:20:34 visa Exp $
+# $OpenBSD: GENERIC,v 1.25 2016/03/18 05:38:10 jmatthew Exp $
#
# For further information on compiling OpenBSD kernels, see the config(8)
# man page.
@@ -64,9 +64,14 @@ wd* at pciide? flags 0x0000
# USB Controllers
dwctwo0 at iobus? irq 56
+octuctl0 at iobus? irq 56
+ehci0 at octuctl?
+ohci0 at octuctl?
# USB bus support
usb* at dwctwo?
+usb* at ehci?
+usb* at ohci?
# USB devices
uhub* at usb? # USB Hubs
diff --git a/sys/arch/octeon/conf/RAMDISK b/sys/arch/octeon/conf/RAMDISK
index cf0a04bf819..a2182722914 100644
--- a/sys/arch/octeon/conf/RAMDISK
+++ b/sys/arch/octeon/conf/RAMDISK
@@ -1,4 +1,4 @@
-# $OpenBSD: RAMDISK,v 1.23 2016/01/14 17:20:34 visa Exp $
+# $OpenBSD: RAMDISK,v 1.24 2016/03/18 05:38:10 jmatthew Exp $
machine octeon mips64
maxusers 4
@@ -55,7 +55,14 @@ pciide* at pci? flags 0x0000
wd* at pciide? flags 0x0000
dwctwo0 at iobus0 irq 56
+octuctl0 at iobus0 irq 56
+ehci0 at octuctl?
+ohci0 at octuctl?
+
usb* at dwctwo?
+usb* at ehci?
+usb* at ohci?
+
uhub* at usb?
uhub* at uhub?
umass* at uhub?
diff --git a/sys/arch/octeon/conf/files.octeon b/sys/arch/octeon/conf/files.octeon
index 4db0107193d..08a67b2fc00 100644
--- a/sys/arch/octeon/conf/files.octeon
+++ b/sys/arch/octeon/conf/files.octeon
@@ -1,4 +1,4 @@
-# $OpenBSD: files.octeon,v 1.28 2016/01/14 17:20:34 visa Exp $
+# $OpenBSD: files.octeon,v 1.29 2016/03/18 05:38:10 jmatthew Exp $
# Standard stanzas config(8) can't run without
maxpartitions 16
@@ -71,6 +71,14 @@ file arch/octeon/dev/cn30xxsmi.c iobus
attach dwctwo at iobus with octdwctwo
file arch/octeon/dev/octdwctwo.c octdwctwo needs-flag
+device octuctl {}
+attach octuctl at iobus
+file arch/octeon/dev/octuctl.c octuctl needs-flag
+attach ehci at octuctl with octehci
+file arch/octeon/dev/octehci.c octehci
+attach ohci at octuctl with octohci
+file arch/octeon/dev/octohci.c octohci
+
# On-board CF
device octcf: disk
attach octcf at iobus
diff --git a/sys/arch/octeon/dev/octehci.c b/sys/arch/octeon/dev/octehci.c
new file mode 100644
index 00000000000..c6cacac6946
--- /dev/null
+++ b/sys/arch/octeon/dev/octehci.c
@@ -0,0 +1,118 @@
+/* $OpenBSD: octehci.c,v 1.1 2016/03/18 05:38:10 jmatthew Exp $ */
+
+/*
+ * Copyright (c) 2015 Jonathan Matthew <jmatthew@openbsd.org>
+ *
+ * Permission to use, copy, modify, and/or 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/octeonreg.h>
+#include <machine/octeonvar.h>
+
+#include <octeon/dev/octuctlreg.h>
+#include <octeon/dev/octuctlvar.h>
+
+#include <dev/usb/usb.h>
+#include <dev/usb/usbdi.h>
+#include <dev/usb/usbdivar.h>
+
+#include <sys/rwlock.h>
+#include <dev/usb/ehcireg.h>
+#include <dev/usb/ehcivar.h>
+
+struct octehci_softc {
+ struct ehci_softc sc_ehci;
+
+ void *sc_ih;
+};
+
+int octehci_match(struct device *, void *, void *);
+void octehci_attach(struct device *, struct device *, void *);
+
+const struct cfattach octehci_ca = {
+ sizeof(struct octehci_softc), octehci_match, octehci_attach,
+};
+
+struct cfdriver octehci_cd = {
+ NULL, "ehci", DV_DULL
+};
+
+int
+octehci_match(struct device *parent, void *match, void *aux)
+{
+ struct octuctl_attach_args *aa = aux;
+
+ if (strcmp(aa->aa_name, "ehci") != 0)
+ return (0);
+
+ return (1);
+}
+
+void
+octehci_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct octehci_softc *sc = (struct octehci_softc *)self;
+ struct octuctl_attach_args *aa = aux;
+ uint64_t port_ctl;
+ int rc;
+ int s;
+
+ sc->sc_ehci.iot = aa->aa_bust;
+ sc->sc_ehci.sc_bus.pipe_size = sizeof(struct usbd_pipe);
+ sc->sc_ehci.sc_bus.dmatag = aa->aa_dmat;
+
+ rc = bus_space_map(sc->sc_ehci.iot, UCTL_EHCI_BASE, UCTL_EHCI_SIZE,
+ 0, &sc->sc_ehci.ioh);
+ KASSERT(rc == 0);
+
+ port_ctl = bus_space_read_8(aa->aa_octuctl_bust, aa->aa_ioh,
+ UCTL_EHCI_CTL);
+ port_ctl &= ~UCTL_EHCI_CTL_L2C_ADDR_MSB_MASK;
+ port_ctl |= (1 << UCTL_EHCI_CTL_L2C_DESC_EMOD_SHIFT);
+ port_ctl |= (1 << UCTL_EHCI_CTL_L2C_BUFF_EMOD_SHIFT);
+ port_ctl |= UCTL_EHCI_CTL_EHCI_64B_ADDR_EN;
+ bus_space_write_8(aa->aa_octuctl_bust, aa->aa_ioh, UCTL_EHCI_CTL,
+ port_ctl);
+
+ s = splhardusb();
+ sc->sc_ehci.sc_offs = EREAD1(&sc->sc_ehci, EHCI_CAPLENGTH);
+ EOWRITE2(&sc->sc_ehci, EHCI_USBINTR, 0);
+
+ sc->sc_ehci.sc_id_vendor = 0;
+ strlcpy(sc->sc_ehci.sc_vendor, "Octeon", sizeof(sc->sc_ehci.sc_vendor));
+
+ sc->sc_ih = octeon_intr_establish(CIU_INT_USB, IPL_USB, ehci_intr,
+ (void *)&sc->sc_ehci, sc->sc_ehci.sc_bus.bdev.dv_xname);
+ KASSERT(sc->sc_ih != NULL);
+
+ rc = ehci_init(&sc->sc_ehci);
+ if (rc != USBD_NORMAL_COMPLETION) {
+ printf(": init failed, error=%d\n", rc);
+ octeon_intr_disestablish(sc->sc_ih);
+ bus_space_unmap(sc->sc_ehci.iot, sc->sc_ehci.ioh,
+ UCTL_EHCI_SIZE);
+ splx(s);
+ return;
+ }
+
+ printf("\n");
+ if (rc == 0)
+ config_found(self, &sc->sc_ehci.sc_bus, usbctlprint);
+ splx(s);
+}
diff --git a/sys/arch/octeon/dev/octeon_iobus.c b/sys/arch/octeon/dev/octeon_iobus.c
index 6dde070207b..7c3193fbb8d 100644
--- a/sys/arch/octeon/dev/octeon_iobus.c
+++ b/sys/arch/octeon/dev/octeon_iobus.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: octeon_iobus.c,v 1.14 2015/07/20 19:44:32 pirofti Exp $ */
+/* $OpenBSD: octeon_iobus.c,v 1.15 2016/03/18 05:38:10 jmatthew Exp $ */
/*
* Copyright (c) 2000-2004 Opsycon AB (www.opsycon.se)
@@ -48,6 +48,7 @@
#include <octeon/dev/iobusvar.h>
#include <octeon/dev/cn30xxgmxreg.h>
#include <octeon/dev/octhcireg.h> /* USBN_BASE */
+#include <octeon/dev/octuctlreg.h>
int iobusmatch(struct device *, void *, void *);
void iobusattach(struct device *, struct device *, void *);
@@ -150,6 +151,7 @@ static const struct octeon_iobus_addrs iobus_addrs[] = {
{ "octrng", OCTEON_RNG_BASE },
{ "dwctwo", USBN_BASE },
{ "amdcf", OCTEON_AMDCF_BASE},
+ { "octuctl", UCTL_BASE },
};
/* There can only be one. */
diff --git a/sys/arch/octeon/dev/octohci.c b/sys/arch/octeon/dev/octohci.c
new file mode 100644
index 00000000000..e23489b7153
--- /dev/null
+++ b/sys/arch/octeon/dev/octohci.c
@@ -0,0 +1,142 @@
+/* $OpenBSD: octohci.c,v 1.1 2016/03/18 05:38:10 jmatthew Exp $ */
+
+/*
+ * Copyright (c) 2015 Jonathan Matthew <jmatthew@openbsd.org>
+ *
+ * Permission to use, copy, modify, and/or 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/octeonreg.h>
+#include <machine/octeonvar.h>
+
+#include <octeon/dev/octuctlreg.h>
+#include <octeon/dev/octuctlvar.h>
+
+#include <dev/usb/usb.h>
+#include <dev/usb/usbdi.h>
+#include <dev/usb/usbdivar.h>
+
+#include <dev/usb/ohcireg.h>
+#include <dev/usb/ohcivar.h>
+
+struct octohci_softc {
+ struct ohci_softc sc_ohci;
+
+ void *sc_ih;
+};
+
+int octohci_match(struct device *, void *, void *);
+void octohci_attach(struct device *, struct device *, void *);
+void octohci_attach_deferred(struct device *);
+
+const struct cfattach octohci_ca = {
+ sizeof(struct octohci_softc), octohci_match, octohci_attach,
+};
+
+struct cfdriver octohci_cd = {
+ NULL, "ohci", DV_DULL
+};
+
+int
+octohci_match(struct device *parent, void *match, void *aux)
+{
+ struct octuctl_attach_args *aa = aux;
+
+ if (strcmp(aa->aa_name, "ohci") != 0)
+ return (0);
+
+ return (1);
+}
+
+void
+octohci_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct octohci_softc *sc = (struct octohci_softc *)self;
+ struct octuctl_attach_args *aa = aux;
+ char *devname;
+ uint64_t port_ctl;
+ int rc;
+ int s;
+
+ sc->sc_ohci.iot = aa->aa_bust;
+ sc->sc_ohci.sc_bus.pipe_size = sizeof(struct usbd_pipe);
+ sc->sc_ohci.sc_bus.dmatag = aa->aa_dmat;
+
+ rc = bus_space_map(sc->sc_ohci.iot, UCTL_OHCI_BASE, UCTL_OHCI_SIZE,
+ 0, &sc->sc_ohci.ioh);
+ KASSERT(rc == 0);
+
+ port_ctl = bus_space_read_8(aa->aa_octuctl_bust, aa->aa_ioh,
+ UCTL_OHCI_CTL);
+ port_ctl &= ~UCTL_OHCI_CTL_L2C_ADDR_MSB_MASK;
+ port_ctl |= (1 << UCTL_OHCI_CTL_L2C_DESC_EMOD_SHIFT);
+ port_ctl |= (1 << UCTL_OHCI_CTL_L2C_BUFF_EMOD_SHIFT);
+ bus_space_write_8(aa->aa_octuctl_bust, aa->aa_ioh, UCTL_OHCI_CTL,
+ port_ctl);
+
+ s = splusb();
+
+ sc->sc_ohci.sc_id_vendor = 0;
+ strlcpy(sc->sc_ohci.sc_vendor, "Octeon", sizeof(sc->sc_ohci.sc_vendor));
+
+ sc->sc_ih = octeon_intr_establish(CIU_INT_USB, IPL_USB, ohci_intr,
+ (void *)&sc->sc_ohci, devname);
+ KASSERT(sc->sc_ih != NULL);
+
+ if ((ohci_checkrev(&sc->sc_ohci) != USBD_NORMAL_COMPLETION) ||
+ (ohci_handover(&sc->sc_ohci) != USBD_NORMAL_COMPLETION))
+ goto failed;
+
+ /* ignore interrupts for now */
+ sc->sc_ohci.sc_bus.dying = 1;
+ config_defer(self, octohci_attach_deferred);
+
+ splx(s);
+ return;
+
+failed:
+ octeon_intr_disestablish(sc->sc_ih);
+ bus_space_unmap(sc->sc_ohci.iot, sc->sc_ohci.ioh, UCTL_OHCI_SIZE);
+ splx(s);
+ return;
+}
+
+void
+octohci_attach_deferred(struct device *self)
+{
+ struct octohci_softc *sc = (struct octohci_softc *)self;
+ usbd_status r;
+ int s;
+
+ s = splusb();
+ sc->sc_ohci.sc_bus.dying = 0;
+
+ r = ohci_init(&sc->sc_ohci);
+ splx(s);
+
+ if (r != USBD_NORMAL_COMPLETION) {
+ printf("%s: init failed, error=%d\n",
+ sc->sc_ohci.sc_bus.bdev.dv_xname, r);
+ octeon_intr_disestablish(sc->sc_ih);
+ bus_space_unmap(sc->sc_ohci.iot, sc->sc_ohci.ioh,
+ UCTL_OHCI_SIZE);
+ } else {
+ config_found(self, &sc->sc_ohci.sc_bus, usbctlprint);
+ }
+}
diff --git a/sys/arch/octeon/dev/octuctl.c b/sys/arch/octeon/dev/octuctl.c
new file mode 100644
index 00000000000..d2791409bf1
--- /dev/null
+++ b/sys/arch/octeon/dev/octuctl.c
@@ -0,0 +1,250 @@
+/* $OpenBSD: octuctl.c,v 1.1 2016/03/18 05:38:10 jmatthew Exp $ */
+
+/*
+ * Copyright (c) 2015 Jonathan Matthew <jmatthew@openbsd.org>
+ *
+ * Permission to use, copy, modify, and/or 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/octeonreg.h>
+#include <machine/octeonvar.h>
+#include <machine/octeon_model.h>
+
+#include <octeon/dev/iobusvar.h>
+#include <octeon/dev/octuctlreg.h>
+#include <octeon/dev/octuctlvar.h>
+
+struct octuctl_softc {
+ struct device sc_dev;
+ bus_space_tag_t sc_iot;
+ bus_space_handle_t sc_ioh;
+};
+
+int octuctl_match(struct device *, void *, void *);
+void octuctl_attach(struct device *, struct device *, void *);
+
+const struct cfattach octuctl_ca = {
+ sizeof(struct octuctl_softc), octuctl_match, octuctl_attach,
+};
+
+struct cfdriver octuctl_cd = {
+ NULL, "octuctl", DV_DULL
+};
+
+uint8_t octuctl_read_1(bus_space_tag_t, bus_space_handle_t, bus_size_t);
+uint16_t octuctl_read_2(bus_space_tag_t, bus_space_handle_t, bus_size_t);
+uint32_t octuctl_read_4(bus_space_tag_t, bus_space_handle_t, bus_size_t);
+void octuctl_write_1(bus_space_tag_t, bus_space_handle_t, bus_size_t, uint8_t);
+void octuctl_write_2(bus_space_tag_t, bus_space_handle_t, bus_size_t, uint16_t);
+void octuctl_write_4(bus_space_tag_t, bus_space_handle_t, bus_size_t, uint32_t);
+
+bus_space_t octuctl_tag = {
+ .bus_base = PHYS_TO_XKPHYS(0, CCA_NC),
+ .bus_private = NULL,
+ ._space_read_1 = octuctl_read_1,
+ ._space_write_1 = octuctl_write_1,
+ ._space_read_2 = octuctl_read_2,
+ ._space_write_2 = octuctl_write_2,
+ ._space_read_4 = octuctl_read_4,
+ ._space_write_4 = octuctl_write_4,
+ ._space_map = iobus_space_map,
+ ._space_unmap = iobus_space_unmap,
+ ._space_subregion = generic_space_region,
+ ._space_vaddr = generic_space_vaddr
+};
+
+uint8_t
+octuctl_read_1(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o)
+{
+ return *(volatile uint8_t *)(h + (o^3));
+}
+
+uint16_t
+octuctl_read_2(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o)
+{
+ return *(volatile uint16_t *)(h + (o^2));
+}
+
+uint32_t
+octuctl_read_4(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o)
+{
+ return *(volatile uint32_t *)(h + o);
+}
+
+void
+octuctl_write_1(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o, uint8_t v)
+{
+ *(volatile uint8_t *)(h + (o^3)) = v;
+}
+
+void
+octuctl_write_2(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o, uint16_t v)
+{
+ *(volatile uint16_t *)(h + (o^2)) = v;
+}
+
+void
+octuctl_write_4(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o, uint32_t v)
+{
+ *(volatile uint32_t *)(h + o) = v;
+}
+
+int
+octuctl_match(struct device *parent, void *match, void *aux)
+{
+ int id;
+
+ id = octeon_get_chipid();
+ switch (octeon_model_family(id)) {
+ case OCTEON_MODEL_FAMILY_CN61XX:
+ return (1);
+ default:
+ return (0);
+ }
+}
+
+int
+octuctlprint(void *aux, const char *parentname)
+{
+ return (QUIET);
+}
+
+void
+octuctl_clock_setup(struct octuctl_softc *sc, uint64_t ctl)
+{
+ int div;
+ int lastdiv;
+ int validdiv[] = { 1, 2, 3, 4, 6, 8, 12, INT_MAX };
+ int i;
+
+ div = octeon_ioclock_speed() / UCTL_CLK_TARGET_FREQ;
+
+ /* start usb controller reset */
+ ctl |= UCTL_CLK_RST_CTL_P_POR;
+ ctl &= ~(UCTL_CLK_RST_CTL_HRST |
+ UCTL_CLK_RST_CTL_P_PRST |
+ UCTL_CLK_RST_CTL_O_CLKDIV_EN |
+ UCTL_CLK_RST_CTL_H_CLKDIV_EN |
+ UCTL_CLK_RST_CTL_H_CLKDIV_RST |
+ UCTL_CLK_RST_CTL_O_CLKDIV_RST);
+ bus_space_write_8(sc->sc_iot, sc->sc_ioh, UCTL_CLK_RST_CTL, ctl);
+
+ /* set up for 12mhz crystal */
+ ctl &= ~((3 << UCTL_CLK_RST_CTL_P_REFCLK_DIV_SHIFT) |
+ (3 << UCTL_CLK_RST_CTL_P_REFCLK_SEL_SHIFT));
+ bus_space_write_8(sc->sc_iot, sc->sc_ioh, UCTL_CLK_RST_CTL, ctl);
+
+ /* set clock divider */
+ lastdiv = 1;
+ for (i = 0; i < nitems(validdiv); i++) {
+ if (div < validdiv[i]) {
+ div = lastdiv;
+ break;
+ }
+ lastdiv = validdiv[i];
+ }
+
+ ctl &= ~(0xf << UCTL_CLK_RST_CTL_H_DIV_SHIFT);
+ ctl |= (div << UCTL_CLK_RST_CTL_H_DIV_SHIFT);
+ bus_space_write_8(sc->sc_iot, sc->sc_ioh, UCTL_CLK_RST_CTL, ctl);
+
+ /* turn hclk on */
+ ctl = bus_space_read_8(sc->sc_iot, sc->sc_ioh,
+ UCTL_CLK_RST_CTL);
+ ctl |= UCTL_CLK_RST_CTL_H_CLKDIV_EN;
+ bus_space_write_8(sc->sc_iot, sc->sc_ioh, UCTL_CLK_RST_CTL, ctl);
+ ctl |= UCTL_CLK_RST_CTL_H_CLKDIV_RST;
+ bus_space_write_8(sc->sc_iot, sc->sc_ioh, UCTL_CLK_RST_CTL, ctl);
+
+ delay(1);
+
+ /* power-on-reset finished */
+ ctl &= ~UCTL_CLK_RST_CTL_P_POR;
+ bus_space_write_8(sc->sc_iot, sc->sc_ioh, UCTL_CLK_RST_CTL, ctl);
+
+ delay(1000);
+
+ /* set up ohci clocks */
+ ctl |= UCTL_CLK_RST_CTL_O_CLKDIV_RST;
+ bus_space_write_8(sc->sc_iot, sc->sc_ioh, UCTL_CLK_RST_CTL, ctl);
+ ctl |= UCTL_CLK_RST_CTL_O_CLKDIV_EN;
+ bus_space_write_8(sc->sc_iot, sc->sc_ioh, UCTL_CLK_RST_CTL, ctl);
+
+ delay(1);
+
+ /* phy reset */
+ ctl |= UCTL_CLK_RST_CTL_P_PRST;
+ bus_space_write_8(sc->sc_iot, sc->sc_ioh, UCTL_CLK_RST_CTL, ctl);
+
+ delay(1);
+
+ /* clear host reset */
+ ctl |= UCTL_CLK_RST_CTL_HRST;
+ bus_space_write_8(sc->sc_iot, sc->sc_ioh, UCTL_CLK_RST_CTL, ctl);
+}
+
+void
+octuctl_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct octuctl_softc *sc = (struct octuctl_softc *)self;
+ struct iobus_attach_args *aa = aux;
+ struct octuctl_attach_args uaa;
+ uint64_t port_ctl;
+ uint64_t ctl;
+ uint64_t preg;
+ uint64_t txvref;
+ int rc;
+ int port;
+
+ sc->sc_iot = aa->aa_bust;
+ rc = bus_space_map(sc->sc_iot, UCTL_BASE, UCTL_SIZE,
+ 0, &sc->sc_ioh);
+ KASSERT(rc == 0);
+
+ /* do clock setup if not already done */
+ bus_space_write_8(sc->sc_iot, sc->sc_ioh, UCTL_IF_ENA,
+ UCTL_IF_ENA_EN);
+ ctl = bus_space_read_8(sc->sc_iot, sc->sc_ioh, UCTL_CLK_RST_CTL);
+ if ((ctl & UCTL_CLK_RST_CTL_HRST) == 0)
+ octuctl_clock_setup(sc, ctl);
+
+ /* port phy settings */
+ for (port = 0; port < 2; port++) {
+ preg = UCTL_UPHY_PORTX_STATUS + (port * 8);
+ port_ctl = bus_space_read_8(sc->sc_iot, sc->sc_ioh, preg);
+ txvref = 0xf;
+ port_ctl |= (UCTL_UPHY_PORTX_STATUS_TXPREEMPHTUNE |
+ UCTL_UPHY_PORTX_STATUS_TXRISETUNE |
+ (txvref << UCTL_UPHY_PORTX_STATUS_TXVREF_SHIFT));
+ bus_space_write_8(sc->sc_iot, sc->sc_ioh, preg, port_ctl);
+ }
+
+ printf("\n");
+
+ uaa.aa_octuctl_bust = aa->aa_bust;
+ uaa.aa_bust = &octuctl_tag;
+ uaa.aa_dmat = aa->aa_dmat;
+ uaa.aa_ioh = sc->sc_ioh;
+
+ uaa.aa_name = "ehci";
+ config_found(self, &uaa, octuctlprint);
+
+ uaa.aa_name = "ohci";
+ config_found(self, &uaa, octuctlprint);
+}
diff --git a/sys/arch/octeon/dev/octuctlreg.h b/sys/arch/octeon/dev/octuctlreg.h
new file mode 100644
index 00000000000..5ead56add38
--- /dev/null
+++ b/sys/arch/octeon/dev/octuctlreg.h
@@ -0,0 +1,77 @@
+/* $OpenBSD: octuctlreg.h,v 1.1 2016/03/18 05:38:10 jmatthew Exp $ */
+
+/*
+ * Copyright (c) 2015 Jonathan Matthew <jmatthew@openbsd.org>
+ *
+ * Permission to use, copy, modify, and/or 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.
+ */
+
+#ifndef _OCTUCTLREG_H_
+#define _OCTUCTLREG_H_
+
+/*
+ * UCTL - octeon II usb controller interface
+ */
+#define UCTL_BASE 0x000118006f000000ull
+#define UCTL_SIZE 0x100
+
+#define UCTL_EHCI_BASE 0x00016f0000000000ull
+#define UCTL_EHCI_SIZE 0x100
+#define UCTL_OHCI_BASE 0x00016f0000000400ull
+#define UCTL_OHCI_SIZE 0x100
+
+#define UCTL_CLK_TARGET_FREQ 130000000ull
+
+#define UCTL_CLK_RST_CTL 0x00
+#define UCTL_CLK_RST_CTL_HRST (1 << 0)
+#define UCTL_CLK_RST_CTL_P_PRST (1 << 1)
+#define UCTL_CLK_RST_CTL_P_POR (1 << 2)
+#define UCTL_CLK_RST_CTL_P_COM_ON (1 << 3)
+#define UCTL_CLK_RST_CTL_P_REFCLK_DIV_SHIFT 5
+#define UCTL_CLK_RST_CTL_P_REFCLK_SEL_SHIFT 7
+#define UCTL_CLK_RST_CTL_H_DIV_SHIFT 9
+#define UCTL_CLK_RST_CTL_O_CLKDIV_EN (1 << 13)
+#define UCTL_CLK_RST_CTL_H_CLKDIV_EN (1 << 14)
+#define UCTL_CLK_RST_CTL_H_CLKDIV_RST (1 << 15)
+#define UCTL_CLK_RST_CTL_H_CLKDIV_BYP (1 << 16)
+#define UCTL_CLK_RST_CTL_O_CLKDIV_RST (1 << 17)
+#define UCTL_CLK_RST_CTL_APP_START_CLK (1 << 18)
+#define UCTL_CLK_RST_CTL_OHCI_SUSP_LGCY (1 << 19)
+#define UCTL_CLK_RST_CTL_OHCI_SM (1 << 20)
+#define UCTL_CLK_RST_CTL_OHCI_CLKCKTRST (1 << 21)
+#define UCTL_CLK_RST_CTL_EHCI_SM (1 << 22)
+
+#define UCTL_UPHY_STATUS 0x08
+
+#define UCTL_UPHY_PORTX_STATUS 0x10
+#define UCTL_UPHY_PORTX_STATUS_TXVREF_SHIFT 28
+#define UCTL_UPHY_PORTX_STATUS_TXRISETUNE (1 << 27)
+#define UCTL_UPHY_PORTX_STATUS_TXPREEMPHTUNE (1 << 26)
+
+#define UCTL_IF_ENA 0x30
+#define UCTL_IF_ENA_EN (1 << 0)
+
+#define UCTL_EHCI_CTL 0x80
+#define UCTL_EHCI_CTL_L2C_ADDR_MSB_MASK 0xff
+#define UCTL_EHCI_CTL_L2C_ADDR_MSB_SHIFT 0
+#define UCTL_EHCI_CTL_EHCI_64B_ADDR_EN (1 << 8)
+#define UCTL_EHCI_CTL_L2C_DESC_EMOD_SHIFT 10
+#define UCTL_EHCI_CTL_L2C_BUFF_EMOD_SHIFT 12
+
+#define UCTL_OHCI_CTL 0x88
+#define UCTL_OHCI_CTL_L2C_ADDR_MSB_MASK 0xff
+#define UCTL_OHCI_CTL_L2C_ADDR_MSB_SHIFT 0
+#define UCTL_OHCI_CTL_L2C_DESC_EMOD_SHIFT 10
+#define UCTL_OHCI_CTL_L2C_BUFF_EMOD_SHIFT 12
+
+#endif /* _OCTUCTLREG_H_ */
diff --git a/sys/arch/octeon/dev/octuctlvar.h b/sys/arch/octeon/dev/octuctlvar.h
new file mode 100644
index 00000000000..56a8d189a26
--- /dev/null
+++ b/sys/arch/octeon/dev/octuctlvar.h
@@ -0,0 +1,32 @@
+/* $OpenBSD: octuctlvar.h,v 1.1 2016/03/18 05:38:10 jmatthew Exp $ */
+
+/*
+ * Copyright (c) 2015 Jonathan Matthew <jmatthew@openbsd.org>
+ *
+ * Permission to use, copy, modify, and/or 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.
+ */
+
+#ifndef _OCTUCTLVAR_H_
+#define _OCTUCTLVAR_H_
+
+#include <machine/bus.h>
+
+struct octuctl_attach_args {
+ char *aa_name;
+ bus_space_tag_t aa_octuctl_bust;
+ bus_space_tag_t aa_bust;
+ bus_dma_tag_t aa_dmat;
+ bus_space_handle_t aa_ioh;
+};
+
+#endif /* _OCTUCTLVAR_H_ */