1*71696a07Sdlg /* $OpenBSD: octohci.c,v 1.4 2019/01/07 03:41:06 dlg Exp $ */
2494889e9Sjmatthew
3494889e9Sjmatthew /*
4494889e9Sjmatthew * Copyright (c) 2015 Jonathan Matthew <jmatthew@openbsd.org>
5494889e9Sjmatthew *
6494889e9Sjmatthew * Permission to use, copy, modify, and/or distribute this software for any
7494889e9Sjmatthew * purpose with or without fee is hereby granted, provided that the above
8494889e9Sjmatthew * copyright notice and this permission notice appear in all copies.
9494889e9Sjmatthew *
10494889e9Sjmatthew * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11494889e9Sjmatthew * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12494889e9Sjmatthew * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13494889e9Sjmatthew * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14494889e9Sjmatthew * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15494889e9Sjmatthew * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16494889e9Sjmatthew * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17494889e9Sjmatthew */
18494889e9Sjmatthew
19494889e9Sjmatthew #include <sys/param.h>
20494889e9Sjmatthew #include <sys/systm.h>
21494889e9Sjmatthew #include <sys/device.h>
22494889e9Sjmatthew
23494889e9Sjmatthew #include <machine/intr.h>
24494889e9Sjmatthew #include <machine/bus.h>
25494889e9Sjmatthew #include <machine/octeonreg.h>
26494889e9Sjmatthew #include <machine/octeonvar.h>
27494889e9Sjmatthew
28494889e9Sjmatthew #include <octeon/dev/octuctlreg.h>
29494889e9Sjmatthew #include <octeon/dev/octuctlvar.h>
30494889e9Sjmatthew
31494889e9Sjmatthew #include <dev/usb/usb.h>
32494889e9Sjmatthew #include <dev/usb/usbdi.h>
33494889e9Sjmatthew #include <dev/usb/usbdivar.h>
34494889e9Sjmatthew
35494889e9Sjmatthew #include <dev/usb/ohcireg.h>
36494889e9Sjmatthew #include <dev/usb/ohcivar.h>
37494889e9Sjmatthew
38494889e9Sjmatthew struct octohci_softc {
39494889e9Sjmatthew struct ohci_softc sc_ohci;
40494889e9Sjmatthew
41494889e9Sjmatthew void *sc_ih;
42fe5dbe47Sjmatthew uint64_t sc_reg_size;
43494889e9Sjmatthew };
44494889e9Sjmatthew
45494889e9Sjmatthew int octohci_match(struct device *, void *, void *);
46494889e9Sjmatthew void octohci_attach(struct device *, struct device *, void *);
47494889e9Sjmatthew void octohci_attach_deferred(struct device *);
48494889e9Sjmatthew
49494889e9Sjmatthew const struct cfattach octohci_ca = {
50494889e9Sjmatthew sizeof(struct octohci_softc), octohci_match, octohci_attach,
51494889e9Sjmatthew };
52494889e9Sjmatthew
53494889e9Sjmatthew struct cfdriver octohci_cd = {
54494889e9Sjmatthew NULL, "ohci", DV_DULL
55494889e9Sjmatthew };
56494889e9Sjmatthew
57494889e9Sjmatthew int
octohci_match(struct device * parent,void * match,void * aux)58494889e9Sjmatthew octohci_match(struct device *parent, void *match, void *aux)
59494889e9Sjmatthew {
60494889e9Sjmatthew struct octuctl_attach_args *aa = aux;
61fe5dbe47Sjmatthew return (OF_is_compatible(aa->aa_node, "cavium,octeon-6335-ohci"));
62494889e9Sjmatthew }
63494889e9Sjmatthew
64494889e9Sjmatthew void
octohci_attach(struct device * parent,struct device * self,void * aux)65494889e9Sjmatthew octohci_attach(struct device *parent, struct device *self, void *aux)
66494889e9Sjmatthew {
67494889e9Sjmatthew struct octohci_softc *sc = (struct octohci_softc *)self;
68494889e9Sjmatthew struct octuctl_attach_args *aa = aux;
69494889e9Sjmatthew uint64_t port_ctl;
70494889e9Sjmatthew int rc;
71494889e9Sjmatthew int s;
72494889e9Sjmatthew
73494889e9Sjmatthew sc->sc_ohci.iot = aa->aa_bust;
74494889e9Sjmatthew sc->sc_ohci.sc_bus.pipe_size = sizeof(struct usbd_pipe);
75494889e9Sjmatthew sc->sc_ohci.sc_bus.dmatag = aa->aa_dmat;
76494889e9Sjmatthew
77fe5dbe47Sjmatthew rc = bus_space_map(sc->sc_ohci.iot, aa->aa_reg.addr, aa->aa_reg.size,
78494889e9Sjmatthew 0, &sc->sc_ohci.ioh);
79494889e9Sjmatthew KASSERT(rc == 0);
80fe5dbe47Sjmatthew sc->sc_reg_size = aa->aa_reg.size;
81494889e9Sjmatthew
82494889e9Sjmatthew port_ctl = bus_space_read_8(aa->aa_octuctl_bust, aa->aa_ioh,
83494889e9Sjmatthew UCTL_OHCI_CTL);
84494889e9Sjmatthew port_ctl &= ~UCTL_OHCI_CTL_L2C_ADDR_MSB_MASK;
85494889e9Sjmatthew port_ctl |= (1 << UCTL_OHCI_CTL_L2C_DESC_EMOD_SHIFT);
86494889e9Sjmatthew port_ctl |= (1 << UCTL_OHCI_CTL_L2C_BUFF_EMOD_SHIFT);
87494889e9Sjmatthew bus_space_write_8(aa->aa_octuctl_bust, aa->aa_ioh, UCTL_OHCI_CTL,
88494889e9Sjmatthew port_ctl);
89494889e9Sjmatthew
90494889e9Sjmatthew s = splusb();
91494889e9Sjmatthew
92494889e9Sjmatthew sc->sc_ohci.sc_id_vendor = 0;
93494889e9Sjmatthew strlcpy(sc->sc_ohci.sc_vendor, "Octeon", sizeof(sc->sc_ohci.sc_vendor));
94494889e9Sjmatthew
95494889e9Sjmatthew sc->sc_ih = octeon_intr_establish(CIU_INT_USB, IPL_USB, ohci_intr,
961e13e073Svisa (void *)&sc->sc_ohci, sc->sc_ohci.sc_bus.bdev.dv_xname);
97494889e9Sjmatthew KASSERT(sc->sc_ih != NULL);
98494889e9Sjmatthew
99*71696a07Sdlg printf(", ");
100*71696a07Sdlg
101494889e9Sjmatthew if ((ohci_checkrev(&sc->sc_ohci) != USBD_NORMAL_COMPLETION) ||
102494889e9Sjmatthew (ohci_handover(&sc->sc_ohci) != USBD_NORMAL_COMPLETION))
103494889e9Sjmatthew goto failed;
104494889e9Sjmatthew
105494889e9Sjmatthew /* ignore interrupts for now */
106494889e9Sjmatthew sc->sc_ohci.sc_bus.dying = 1;
107494889e9Sjmatthew config_defer(self, octohci_attach_deferred);
108494889e9Sjmatthew
109494889e9Sjmatthew splx(s);
110494889e9Sjmatthew return;
111494889e9Sjmatthew
112494889e9Sjmatthew failed:
113494889e9Sjmatthew octeon_intr_disestablish(sc->sc_ih);
114fe5dbe47Sjmatthew bus_space_unmap(sc->sc_ohci.iot, sc->sc_ohci.ioh, sc->sc_reg_size);
115494889e9Sjmatthew splx(s);
116494889e9Sjmatthew return;
117494889e9Sjmatthew }
118494889e9Sjmatthew
119494889e9Sjmatthew void
octohci_attach_deferred(struct device * self)120494889e9Sjmatthew octohci_attach_deferred(struct device *self)
121494889e9Sjmatthew {
122494889e9Sjmatthew struct octohci_softc *sc = (struct octohci_softc *)self;
123494889e9Sjmatthew usbd_status r;
124494889e9Sjmatthew int s;
125494889e9Sjmatthew
126494889e9Sjmatthew s = splusb();
127494889e9Sjmatthew sc->sc_ohci.sc_bus.dying = 0;
128494889e9Sjmatthew
129494889e9Sjmatthew r = ohci_init(&sc->sc_ohci);
130494889e9Sjmatthew splx(s);
131494889e9Sjmatthew
132494889e9Sjmatthew if (r != USBD_NORMAL_COMPLETION) {
133494889e9Sjmatthew printf("%s: init failed, error=%d\n",
134494889e9Sjmatthew sc->sc_ohci.sc_bus.bdev.dv_xname, r);
135494889e9Sjmatthew octeon_intr_disestablish(sc->sc_ih);
136494889e9Sjmatthew bus_space_unmap(sc->sc_ohci.iot, sc->sc_ohci.ioh,
137fe5dbe47Sjmatthew sc->sc_reg_size);
138494889e9Sjmatthew } else {
139494889e9Sjmatthew config_found(self, &sc->sc_ohci.sc_bus, usbctlprint);
140494889e9Sjmatthew }
141494889e9Sjmatthew }
142