ohci_sbus.c revision 1.8
1/* $NetBSD: ohci_sbus.c,v 1.8 2008/04/26 14:57:44 drochner Exp $ */ 2 3/*- 4 * Copyright (c) 2001 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by UCHIYAMA Yasushi. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39#include <sys/cdefs.h> 40__KERNEL_RCSID(0, "$NetBSD: ohci_sbus.c,v 1.8 2008/04/26 14:57:44 drochner Exp $"); 41 42#include <sys/param.h> 43 44/* bus_dma */ 45#include <sys/mbuf.h> 46#include <uvm/uvm_extern.h> 47 48#define _PLAYSTATION2_BUS_DMA_PRIVATE 49#include <machine/bus.h> 50#include <machine/autoconf.h> 51 52#include <dev/usb/usb.h> 53#include <dev/usb/usbdi.h> 54#include <dev/usb/usbdivar.h> 55#include <dev/usb/usb_mem.h> 56 57#include <dev/usb/ohcireg.h> 58#include <dev/usb/ohcivar.h> 59 60#include <playstation2/ee/sifvar.h> /* DMA staff */ 61#include <playstation2/ee/dmacvar.h> 62#include <playstation2/dev/sbusvar.h> 63 64#ifdef DEBUG 65#define STATIC 66#else 67#define STATIC static 68#endif 69 70#define SBUS_OHCI_REGBASE MIPS_PHYS_TO_KSEG1(0x1f801600) 71#define SBUS_OHCI_REGSIZE 0x1000 72 73STATIC int ohci_sbus_match(struct device *, struct cfdata *, void *); 74STATIC void ohci_sbus_attach(struct device *, struct device *, void *); 75 76STATIC void _ohci_sbus_map_sync(bus_dma_tag_t, bus_dmamap_t, bus_addr_t, 77 bus_size_t, int); 78STATIC int _ohci_sbus_mem_alloc(bus_dma_tag_t, bus_size_t, bus_size_t, 79 bus_size_t, bus_dma_segment_t *, int, int *, int); 80STATIC void _ohci_sbus_mem_free(bus_dma_tag_t, bus_dma_segment_t *, int); 81STATIC int _ohci_sbus_mem_map(bus_dma_tag_t, bus_dma_segment_t *, int, size_t, 82 void **, int); 83STATIC void _ohci_sbus_mem_unmap(bus_dma_tag_t, void *, size_t); 84 85struct playstation2_bus_dma_tag ohci_bus_dma_tag = { 86 _bus_dmamap_create, 87 _bus_dmamap_destroy, 88 _bus_dmamap_load, 89 _bus_dmamap_load_mbuf, 90 _bus_dmamap_load_uio, 91 _bus_dmamap_load_raw, 92 _bus_dmamap_unload, 93 _ohci_sbus_map_sync, 94 _ohci_sbus_mem_alloc, 95 _ohci_sbus_mem_free, 96 _ohci_sbus_mem_map, 97 _ohci_sbus_mem_unmap, 98 _bus_dmamem_mmap, 99}; 100 101struct ohci_dma_segment { 102 struct iopdma_segment ds_iopdma_seg; 103 104 LIST_ENTRY(ohci_dma_segment) ds_link; 105}; 106 107struct ohci_sbus_softc { 108 struct ohci_softc sc; 109 110 LIST_HEAD(, ohci_dma_segment) sc_dmaseg_head; 111}; 112 113CFATTACH_DECL_NEW(ohci_sbus, sizeof(struct ohci_sbus_softc), 114 ohci_sbus_match, ohci_sbus_attach, NULL, NULL); 115 116int 117ohci_sbus_match(struct device *parent, struct cfdata *cf, void *aux) 118{ 119 120 return (1); 121} 122 123void 124ohci_sbus_attach(struct device *parent, struct device *self, void *aux) 125{ 126 struct ohci_sbus_softc *sc = device_private(self); 127 usbd_status result; 128 129 printf("\n"); 130 131 sc->sc.sc_dev = self; 132 sc->sc.sc_bus.hci_private = sc; 133 134 sc->sc.iot = bus_space_create(0, "OHCI I/O space", SBUS_OHCI_REGBASE, 135 SBUS_OHCI_REGSIZE); 136 sc->sc.ioh = SBUS_OHCI_REGBASE; 137 138 ohci_bus_dma_tag._dmachip_cookie = sc; 139 sc->sc.sc_bus.dmatag = &ohci_bus_dma_tag; 140 141 /* Disable interrupts, so we don't can any spurious ones. */ 142 bus_space_write_4(sc->sc.iot, sc->sc.ioh, OHCI_INTERRUPT_DISABLE, 143 OHCI_ALL_INTRS); 144 145 sbus_intr_establish(SBUS_IRQ_USB, ohci_intr, sc); 146 147 /* IOP/EE DMA relay segment list */ 148 LIST_INIT(&sc->sc_dmaseg_head); 149 150 result = ohci_init(&sc->sc); 151 152 if (result != USBD_NORMAL_COMPLETION) { 153 printf(": init failed. error=%d\n", result); 154 return; 155 } 156 157 /* Attach usb device. */ 158 sc->sc.sc_child = config_found(self, &sc->sc.sc_bus, usbctlprint); 159} 160 161void 162_ohci_sbus_map_sync(bus_dma_tag_t t, bus_dmamap_t map, bus_addr_t offset, 163 bus_size_t len, int ops) 164{ 165 166 dmac_sync_buffer(); /* XXX over flush */ 167} 168 169int 170_ohci_sbus_mem_alloc(bus_dma_tag_t t, bus_size_t size, bus_size_t alignment, 171 bus_size_t boundary, bus_dma_segment_t *segs, int nsegs, int *rsegs, 172 int flags) 173{ 174 struct ohci_sbus_softc *sc = t->_dmachip_cookie; 175 struct ohci_dma_segment *ds; 176 struct iopdma_segment *iopdma_seg; 177 int error; 178 179 KDASSERT(sc); 180 ds = malloc(sizeof(struct ohci_dma_segment), M_DEVBUF, M_NOWAIT); 181 if (ds == NULL) 182 return (1); 183 /* 184 * Allocate DMA Area (IOP DMA Area <-> SIF DMA <-> EE DMA Area) 185 */ 186 iopdma_seg = &ds->ds_iopdma_seg; 187 error = iopdma_allocate_buffer(iopdma_seg, size); 188 189 if (error) { 190 free(ds, M_DEVBUF); 191 return (1); 192 } 193 194 segs[0].ds_len = iopdma_seg->size; 195 segs[0].ds_addr = iopdma_seg->iop_paddr; 196 segs[0]._ds_vaddr = iopdma_seg->ee_vaddr; 197 198 LIST_INSERT_HEAD(&sc->sc_dmaseg_head, ds, ds_link); 199 200 *rsegs = 1; 201 202 return (0); 203} 204 205void 206_ohci_sbus_mem_free(bus_dma_tag_t t, bus_dma_segment_t *segs, int nsegs) 207{ 208 struct ohci_sbus_softc *sc = t->_dmachip_cookie; 209 struct ohci_dma_segment *ds; 210 paddr_t addr = segs[0].ds_addr; 211 212 for (ds = LIST_FIRST(&sc->sc_dmaseg_head); ds != NULL; 213 ds = LIST_NEXT(ds, ds_link)) { 214 if (ds->ds_iopdma_seg.iop_paddr == addr) { 215 iopdma_free_buffer(&ds->ds_iopdma_seg); 216 217 LIST_REMOVE(ds, ds_link); 218 free(ds, M_DEVBUF); 219 return; 220 } 221 } 222 223 panic("_dmamem_free: can't find corresponding handle."); 224 /* NOTREACHED */ 225} 226 227int 228_ohci_sbus_mem_map(bus_dma_tag_t t, bus_dma_segment_t *segs, int nsegs, size_t size, 229 void **kvap, int flags) 230{ 231 struct ohci_sbus_softc *sc = t->_dmachip_cookie; 232 struct ohci_dma_segment *ds; 233 paddr_t addr = segs[0].ds_addr; 234 235 for (ds = LIST_FIRST(&sc->sc_dmaseg_head); ds != NULL; 236 ds = LIST_NEXT(ds, ds_link)) { 237 if (ds->ds_iopdma_seg.iop_paddr == addr) { 238 239 *kvap = (void *)ds->ds_iopdma_seg.ee_vaddr; 240 241 return (0); 242 } 243 } 244 245 return (1); 246} 247 248void 249_ohci_sbus_mem_unmap(bus_dma_tag_t t, void *kva, size_t size) 250{ 251 /* nothing to do */ 252} 253