xref: /openbsd/sys/arch/armv7/marvell/mvxhci.c (revision 09467b48)
1 /* $OpenBSD: mvxhci.c,v 1.2 2018/05/08 13:41:52 mpi Exp $ */
2 /*
3  * Copyright (c) 2017 Patrick Wildt <patrick@blueri.se>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <sys/types.h>
19 #include <sys/systm.h>
20 #include <sys/device.h>
21 
22 #include <machine/bus.h>
23 #include <machine/fdt.h>
24 
25 #include <armv7/marvell/mvmbusvar.h>
26 
27 #include <dev/ofw/openfirm.h>
28 #include <dev/ofw/ofw_clock.h>
29 #include <dev/ofw/fdt.h>
30 
31 #include <dev/usb/usb.h>
32 #include <dev/usb/usbdi.h>
33 #include <dev/usb/usbdivar.h>
34 #include <dev/usb/usb_mem.h>
35 
36 #include <dev/usb/xhcireg.h>
37 #include <dev/usb/xhcivar.h>
38 
39 #define MVXHCI_READ(sc, reg) \
40 	bus_space_read_4((sc)->sc.iot, (sc)->mbus_ioh, (reg))
41 #define MVXHCI_WRITE(sc, reg, val) \
42 	bus_space_write_4((sc)->sc.iot, (sc)->mbus_ioh, (reg), (val))
43 
44 #define MVXHCI_NWINDOW			4
45 #define MVXHCI_CTRL(x)			(0x0 + ((x) << 3))
46 #define MVXHCI_BASE(x)			(0x4 + ((x) << 3))
47 
48 #define MVXHCI_TARGET(target)		(((target) & 0xf) << 4)
49 #define MVXHCI_ATTR(attr)		(((attr) & 0xff) << 8)
50 #define MVXHCI_BASEADDR(base)		((base) & 0xffff0000)
51 #define MVXHCI_SIZE(size)		(((size) - 1) & 0xffff0000)
52 #define MVXHCI_WINEN			(1 << 0)
53 
54 struct mvxhci_softc {
55 	struct xhci_softc	sc;
56 	int			sc_node;
57 	bus_space_handle_t	mbus_ioh;
58 	void			*sc_ih;
59 };
60 
61 void	mvxhci_wininit(struct mvxhci_softc *);
62 
63 int	mvxhci_match(struct device *, void *, void *);
64 void	mvxhci_attach(struct device *, struct device *, void *);
65 
66 struct cfattach mvxhci_ca = {
67 	sizeof (struct mvxhci_softc), mvxhci_match, mvxhci_attach
68 };
69 
70 struct cfdriver mvxhci_cd = {
71 	NULL, "mvxhci", DV_DULL
72 };
73 
74 void
75 mvxhci_wininit(struct mvxhci_softc *sc)
76 {
77 	int i;
78 
79 	if (mvmbus_dram_info == NULL)
80 		panic("%s: mbus dram information not set up", __func__);
81 
82 	for (i = 0; i < MVXHCI_NWINDOW; i++) {
83 		MVXHCI_WRITE(sc, MVXHCI_CTRL(i), 0);
84 		MVXHCI_WRITE(sc, MVXHCI_BASE(i), 0);
85 	}
86 
87 	for (i = 0; i < mvmbus_dram_info->numcs; i++) {
88 		struct mbus_dram_window *win = &mvmbus_dram_info->cs[i];
89 
90 		MVXHCI_WRITE(sc, MVXHCI_CTRL(i),
91 		    MVXHCI_WINEN |
92 		    MVXHCI_TARGET(mvmbus_dram_info->targetid) |
93 		    MVXHCI_ATTR(win->attr) |
94 		    MVXHCI_SIZE(win->size));
95 		MVXHCI_WRITE(sc, MVXHCI_BASE(i), MVXHCI_BASEADDR(win->base));
96 	}
97 }
98 
99 int
100 mvxhci_match(struct device *parent, void *match, void *aux)
101 {
102 	struct fdt_attach_args *faa = aux;
103 
104 	return OF_is_compatible(faa->fa_node, "marvell,armada-375-xhci") ||
105 	    OF_is_compatible(faa->fa_node, "marvell,armada-380-xhci");
106 }
107 
108 void
109 mvxhci_attach(struct device *parent, struct device *self, void *aux)
110 {
111 	struct mvxhci_softc *sc = (struct mvxhci_softc *)self;
112 	struct fdt_attach_args *faa = aux;
113 	int error;
114 
115 	if (faa->fa_nreg < 2) {
116 		printf(": no registers\n");
117 		return;
118 	}
119 
120 	sc->sc_node = faa->fa_node;
121 	sc->sc.iot = faa->fa_iot;
122 	sc->sc.sc_bus.dmatag = faa->fa_dmat;
123 	sc->sc.sc_size = faa->fa_reg[0].size;
124 
125 	if (bus_space_map(sc->sc.iot, faa->fa_reg[0].addr,
126 	    faa->fa_reg[0].size, 0, &sc->sc.ioh)) {
127 		printf(": can't map registers\n");
128 		return;
129 	}
130 
131 	clock_enable_all(faa->fa_node);
132 	reset_deassert_all(sc->sc_node);
133 
134 	if (bus_space_map(sc->sc.iot, faa->fa_reg[1].addr,
135 	    faa->fa_reg[1].size, 0, &sc->mbus_ioh)) {
136 		printf(": can't map registers\n");
137 		goto unmap;
138 	}
139 
140 	/* Set up MBUS windows. */
141 	mvxhci_wininit(sc);
142 
143 	bus_space_unmap(sc->sc.iot, sc->mbus_ioh, faa->fa_reg[1].size);
144 
145 	sc->sc_ih = arm_intr_establish_fdt(faa->fa_node, IPL_USB,
146 	    xhci_intr, &sc->sc, sc->sc.sc_bus.bdev.dv_xname);
147 	if (sc->sc_ih == NULL) {
148 		printf(": can't establish interrupt\n");
149 		goto unmap;
150 	}
151 
152 	strlcpy(sc->sc.sc_vendor, "Marvell", sizeof(sc->sc.sc_vendor));
153 	if ((error = xhci_init(&sc->sc)) != 0) {
154 		printf("%s: init failed, error=%d\n",
155 		    sc->sc.sc_bus.bdev.dv_xname, error);
156 		goto disestablish_ret;
157 	}
158 
159 	/* Attach usb device. */
160 	config_found(self, &sc->sc.sc_bus, usbctlprint);
161 
162 	/* Now that the stack is ready, config' the HC and enable interrupts. */
163 	xhci_config(&sc->sc);
164 
165 	return;
166 
167 disestablish_ret:
168 	arm_intr_disestablish_fdt(sc->sc_ih);
169 unmap:
170 	bus_space_unmap(sc->sc.iot, sc->sc.ioh, sc->sc.sc_size);
171 }
172