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