A bit surprised that code does more than I imagined by reading your
description :) but it looks very good to me!

A few comments:

- `struct octuctl_softc' is not using `sc_ehci' and `sc_ohci'?
- Some magic numbers in `octuctl_clock_setup' could be #define'ed

I've just bought EdgeRouter Pro.  Hopefully I'll test this soon.

OK uebayasi@

On Thu, Mar 17, 2016 at 11:51:19AM +1000, Jonathan Matthew wrote:
> I've had this sitting around for a while and I figure it's time to get it in
> the tree.  Octeon II sensibly got rid of the DWC USB controller and put in 
> ehci
> and ohci compliant controllers instead, so all we need to do here is set up a
> few registers in the usb controller interface and attach the standard drivers.
> The diff below adds octuctl, a driver for the usb controller interface, and 
> octehci and octohci, which are attachments for ehci and ohci.
> 
> I've tested this on a Lanner MR326b, where it allows me to boot off a usb
> stick, and on an Edgerouter Lite, where it makes no difference at all.
> 
> ok?
> 
> Index: conf/GENERIC
> ===================================================================
> RCS file: /cvs/src/sys/arch/octeon/conf/GENERIC,v
> retrieving revision 1.24
> diff -u -p -u -p -r1.24 GENERIC
> --- conf/GENERIC      14 Jan 2016 17:20:34 -0000      1.24
> +++ conf/GENERIC      17 Mar 2016 01:43:51 -0000
> @@ -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
> Index: conf/RAMDISK
> ===================================================================
> RCS file: /cvs/src/sys/arch/octeon/conf/RAMDISK,v
> retrieving revision 1.23
> diff -u -p -u -p -r1.23 RAMDISK
> --- conf/RAMDISK      14 Jan 2016 17:20:34 -0000      1.23
> +++ conf/RAMDISK      17 Mar 2016 01:43:51 -0000
> @@ -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?
> Index: conf/files.octeon
> ===================================================================
> RCS file: /cvs/src/sys/arch/octeon/conf/files.octeon,v
> retrieving revision 1.28
> diff -u -p -u -p -r1.28 files.octeon
> --- conf/files.octeon 14 Jan 2016 17:20:34 -0000      1.28
> +++ conf/files.octeon 17 Mar 2016 01:43:51 -0000
> @@ -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
> Index: dev/octehci.c
> ===================================================================
> RCS file: dev/octehci.c
> diff -N dev/octehci.c
> --- /dev/null 1 Jan 1970 00:00:00 -0000
> +++ dev/octehci.c     17 Mar 2016 01:43:52 -0000
> @@ -0,0 +1,118 @@
> +/*   $OpenBSD$ */
> +
> +/*
> + * Copyright (c) 2015 Jonathan Matthew  <[email protected]>
> + *
> + * 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;
> +     }
> +
> +     splx(s);
> +     printf("\n");
> +     if (rc == 0)
> +             config_found(self, &sc->sc_ehci.sc_bus, usbctlprint);
> +}
> Index: dev/octeon_iobus.c
> ===================================================================
> RCS file: /cvs/src/sys/arch/octeon/dev/octeon_iobus.c,v
> retrieving revision 1.14
> diff -u -p -u -p -r1.14 octeon_iobus.c
> --- dev/octeon_iobus.c        20 Jul 2015 19:44:32 -0000      1.14
> +++ dev/octeon_iobus.c        17 Mar 2016 01:43:52 -0000
> @@ -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 i
>       { "octrng",     OCTEON_RNG_BASE },
>       { "dwctwo",     USBN_BASE       },
>       { "amdcf",      OCTEON_AMDCF_BASE},
> +     { "octuctl",    UCTL_BASE       },
>  };
>  
>  /* There can only be one. */
> Index: dev/octohci.c
> ===================================================================
> RCS file: dev/octohci.c
> diff -N dev/octohci.c
> --- /dev/null 1 Jan 1970 00:00:00 -0000
> +++ dev/octohci.c     17 Mar 2016 01:43:52 -0000
> @@ -0,0 +1,142 @@
> +/*   $OpenBSD$ */
> +
> +/*
> + * Copyright (c) 2015 Jonathan Matthew  <[email protected]>
> + *
> + * 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);
> +     }
> +}
> Index: dev/octuctl.c
> ===================================================================
> RCS file: dev/octuctl.c
> diff -N dev/octuctl.c
> --- /dev/null 1 Jan 1970 00:00:00 -0000
> +++ dev/octuctl.c     17 Mar 2016 01:43:52 -0000
> @@ -0,0 +1,266 @@
> +/*   $OpenBSD$ */
> +
> +/*
> + * Copyright (c) 2015 Jonathan Matthew  <[email protected]>
> + *
> + * 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 <sys/rwlock.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>
> +
> +#include <dev/usb/usb.h>
> +#include <dev/usb/usbdi.h>
> +#include <dev/usb/usbdivar.h>
> +
> +#include <dev/usb/ehcireg.h>
> +#include <dev/usb/ehcivar.h>
> +#include <dev/usb/ohcireg.h>
> +#include <dev/usb/ohcivar.h>
> +
> +struct octuctl_softc {
> +     bus_space_tag_t         sc_iot;
> +     bus_space_handle_t      sc_ioh;
> +
> +     void *                  sc_ehci_ih;
> +     void *                  sc_ohci_ih;
> +     struct ehci_softc       sc_ehci;
> +     struct ohci_softc       sc_ohci;
> +};
> +
> +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 ioclockdelay;
> +     int div;
> +     int lastdiv;
> +     int validdiv[] = { 1, 2, 3, 4, 6, 8, 12, INT_MAX };
> +     int i;
> +
> +     ioclockdelay = 64000000ull / octeon_ioclock_speed();
> +     div = octeon_ioclock_speed() / 130000000ull;
> +
> +     /* 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(ioclockdelay);
> +
> +     /* 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(ioclockdelay);
> +
> +     /* 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);
> +}
> Index: dev/octuctlreg.h
> ===================================================================
> RCS file: dev/octuctlreg.h
> diff -N dev/octuctlreg.h
> --- /dev/null 1 Jan 1970 00:00:00 -0000
> +++ dev/octuctlreg.h  17 Mar 2016 01:43:52 -0000
> @@ -0,0 +1,88 @@
> +/*   $OpenBSD$ */
> +
> +/*
> + * Copyright (c) 2015 Jonathan Matthew  <[email protected]>
> + *
> + * 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 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.
> + *
> + */
> +
> +
> +#ifndef _OCTUCTLREG_H_
> +#define _OCTUCTLREG_H_
> +
> +#include <sys/stdint.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_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_ */
> Index: dev/octuctlvar.h
> ===================================================================
> RCS file: dev/octuctlvar.h
> diff -N dev/octuctlvar.h
> --- /dev/null 1 Jan 1970 00:00:00 -0000
> +++ dev/octuctlvar.h  17 Mar 2016 01:43:52 -0000
> @@ -0,0 +1,42 @@
> +/*   $OpenBSD$ */
> +
> +/*
> + * Copyright (c) 2015 Jonathan Matthew  <[email protected]>
> + *
> + * 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 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.
> + *
> + */
> +
> +#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_ */
> 

Reply via email to