1 /* $NetBSD: i80321.c,v 1.13 2003/06/15 23:08:57 fvdl Exp $ */ 2 3 /* 4 * Copyright (c) 2002 Wasabi Systems, Inc. 5 * All rights reserved. 6 * 7 * Written by Jason R. Thorpe for Wasabi Systems, Inc. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed for the NetBSD Project by 20 * Wasabi Systems, Inc. 21 * 4. The name of Wasabi Systems, Inc. may not be used to endorse 22 * or promote products derived from this software without specific prior 23 * written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 * POSSIBILITY OF SUCH DAMAGE. 36 */ 37 38 /* 39 * Autoconfiguration support for the Intel i80321 I/O Processor. 40 */ 41 42 #include <sys/param.h> 43 #include <sys/systm.h> 44 #include <sys/device.h> 45 46 #define _ARM32_BUS_DMA_PRIVATE 47 #include <machine/bus.h> 48 49 #include <arm/xscale/i80321reg.h> 50 #include <arm/xscale/i80321var.h> 51 52 /* 53 * Statically-allocated bus_space stucture used to access the 54 * i80321's own registers. 55 */ 56 struct bus_space i80321_bs_tag; 57 58 /* 59 * There can be only one i80321, so we keep a global pointer to 60 * the softc, so board-specific code can use features of the 61 * i80321 without having to have a handle on the softc itself. 62 */ 63 struct i80321_softc *i80321_softc; 64 65 static int i80321_iopxs_print(void *, const char *); 66 static int i80321_pcibus_print(void *, const char *); 67 68 /* Built-in devices. */ 69 static const struct iopxs_device { 70 const char *id_name; 71 bus_addr_t id_offset; 72 bus_size_t id_size; 73 } iopxs_devices[] = { 74 { "iopaau", VERDE_AAU_BASE, VERDE_AAU_SIZE }, 75 { "iopdma", VERDE_DMA_BASE0, VERDE_DMA_CHSIZE }, 76 { "iopdma", VERDE_DMA_BASE1, VERDE_DMA_CHSIZE }, 77 { "iopssp", VERDE_SSP_BASE, VERDE_SSP_SIZE }, 78 { "iopmu", VERDE_MU_BASE, VERDE_MU_SIZE }, 79 { "iopwdog", 0, 0 }, 80 { NULL, 0, 0 } 81 }; 82 83 static void i80321_pci_dma_init(struct i80321_softc *); 84 85 /* 86 * i80321_attach: 87 * 88 * Board-independent attach routine for the i80321. 89 */ 90 void 91 i80321_attach(struct i80321_softc *sc) 92 { 93 struct pcibus_attach_args pba; 94 const struct iopxs_device *id; 95 struct iopxs_attach_args ia; 96 pcireg_t preg; 97 98 i80321_softc = sc; 99 100 /* 101 * Slice off some useful subregion handles. 102 */ 103 104 if (bus_space_subregion(sc->sc_st, sc->sc_sh, VERDE_ATU_BASE, 105 VERDE_ATU_SIZE, &sc->sc_atu_sh)) 106 panic("%s: unable to subregion ATU registers", 107 sc->sc_dev.dv_xname); 108 109 /* We expect the Memory Controller to be already sliced off. */ 110 111 /* 112 * Program the Inbound windows. 113 */ 114 bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_IALR0, 115 (0xffffffff - (sc->sc_iwin[0].iwin_size - 1)) & 0xffffffc0); 116 bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_IATVR0, 117 sc->sc_iwin[0].iwin_xlate); 118 if (sc->sc_is_host) { 119 bus_space_write_4(sc->sc_st, sc->sc_atu_sh, 120 PCI_MAPREG_START, sc->sc_iwin[0].iwin_base_lo); 121 bus_space_write_4(sc->sc_st, sc->sc_atu_sh, 122 PCI_MAPREG_START + 0x04, sc->sc_iwin[0].iwin_base_hi); 123 } else { 124 sc->sc_iwin[0].iwin_base_lo = bus_space_read_4(sc->sc_st, 125 sc->sc_atu_sh, PCI_MAPREG_START); 126 sc->sc_iwin[0].iwin_base_hi = bus_space_read_4(sc->sc_st, 127 sc->sc_atu_sh, PCI_MAPREG_START + 0x04); 128 sc->sc_iwin[0].iwin_base_lo = 129 PCI_MAPREG_MEM_ADDR(sc->sc_iwin[0].iwin_base_lo); 130 } 131 132 bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_IALR1, 133 (0xffffffff - (sc->sc_iwin[1].iwin_size - 1)) & 0xffffffc0); 134 /* no xlate for window 1 */ 135 if (sc->sc_is_host) { 136 bus_space_write_4(sc->sc_st, sc->sc_atu_sh, 137 PCI_MAPREG_START + 0x08, sc->sc_iwin[1].iwin_base_lo); 138 bus_space_write_4(sc->sc_st, sc->sc_atu_sh, 139 PCI_MAPREG_START + 0x0c, sc->sc_iwin[1].iwin_base_hi); 140 } else { 141 sc->sc_iwin[1].iwin_base_lo = bus_space_read_4(sc->sc_st, 142 sc->sc_atu_sh, PCI_MAPREG_START + 0x08); 143 sc->sc_iwin[1].iwin_base_hi = bus_space_read_4(sc->sc_st, 144 sc->sc_atu_sh, PCI_MAPREG_START + 0x0c); 145 sc->sc_iwin[1].iwin_base_lo = 146 PCI_MAPREG_MEM_ADDR(sc->sc_iwin[1].iwin_base_lo); 147 } 148 149 bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_IALR2, 150 (0xffffffff - (sc->sc_iwin[2].iwin_size - 1)) & 0xffffffc0); 151 bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_IATVR2, 152 sc->sc_iwin[2].iwin_xlate); 153 if (sc->sc_is_host) { 154 bus_space_write_4(sc->sc_st, sc->sc_atu_sh, 155 PCI_MAPREG_START + 0x10, sc->sc_iwin[2].iwin_base_lo); 156 bus_space_write_4(sc->sc_st, sc->sc_atu_sh, 157 PCI_MAPREG_START + 0x14, sc->sc_iwin[2].iwin_base_hi); 158 } else { 159 sc->sc_iwin[2].iwin_base_lo = bus_space_read_4(sc->sc_st, 160 sc->sc_atu_sh, PCI_MAPREG_START + 0x10); 161 sc->sc_iwin[2].iwin_base_hi = bus_space_read_4(sc->sc_st, 162 sc->sc_atu_sh, PCI_MAPREG_START + 0x14); 163 sc->sc_iwin[2].iwin_base_lo = 164 PCI_MAPREG_MEM_ADDR(sc->sc_iwin[2].iwin_base_lo); 165 } 166 167 bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_IALR3, 168 (0xffffffff - (sc->sc_iwin[3].iwin_size - 1)) & 0xffffffc0); 169 bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_IATVR3, 170 sc->sc_iwin[3].iwin_xlate); 171 if (sc->sc_is_host) { 172 bus_space_write_4(sc->sc_st, sc->sc_atu_sh, 173 ATU_IABAR3, sc->sc_iwin[3].iwin_base_lo); 174 bus_space_write_4(sc->sc_st, sc->sc_atu_sh, 175 ATU_IAUBAR3, sc->sc_iwin[3].iwin_base_hi); 176 } else { 177 sc->sc_iwin[3].iwin_base_lo = bus_space_read_4(sc->sc_st, 178 sc->sc_atu_sh, ATU_IABAR3); 179 sc->sc_iwin[3].iwin_base_hi = bus_space_read_4(sc->sc_st, 180 sc->sc_atu_sh, ATU_IAUBAR3); 181 sc->sc_iwin[3].iwin_base_lo = 182 PCI_MAPREG_MEM_ADDR(sc->sc_iwin[3].iwin_base_lo); 183 } 184 185 /* 186 * Mask (disable) the ATU interrupt sources. 187 * XXX May want to revisit this if we encounter 188 * XXX an application that wants it. 189 */ 190 bus_space_write_4(sc->sc_st, sc->sc_atu_sh, 191 ATU_ATUIMR, 192 ATUIMR_IMW1BU|ATUIMR_ISCEM|ATUIMR_RSCEM|ATUIMR_PST| 193 ATUIMR_DPE|ATUIMR_P_SERR_ASRT|ATUIMR_PMA|ATUIMR_PTAM| 194 ATUIMR_PTAT|ATUIMR_PMPE); 195 196 /* 197 * Program the outbound windows. 198 */ 199 bus_space_write_4(sc->sc_st, sc->sc_atu_sh, 200 ATU_OIOWTVR, sc->sc_ioout_xlate); 201 202 if (!sc->sc_is_host) { 203 sc->sc_owin[0].owin_xlate_lo = sc->sc_iwin[1].iwin_base_lo; 204 sc->sc_owin[0].owin_xlate_hi = sc->sc_iwin[1].iwin_base_hi; 205 } 206 bus_space_write_4(sc->sc_st, sc->sc_atu_sh, 207 ATU_OMWTVR0, sc->sc_owin[0].owin_xlate_lo); 208 bus_space_write_4(sc->sc_st, sc->sc_atu_sh, 209 ATU_OUMWTVR0, sc->sc_owin[0].owin_xlate_hi); 210 211 bus_space_write_4(sc->sc_st, sc->sc_atu_sh, 212 ATU_OMWTVR1, sc->sc_owin[1].owin_xlate_lo); 213 bus_space_write_4(sc->sc_st, sc->sc_atu_sh, 214 ATU_OUMWTVR1, sc->sc_owin[1].owin_xlate_hi); 215 216 /* 217 * Set up the ATU configuration register. All we do 218 * right now is enable Outbound Windows. 219 */ 220 bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_ATUCR, 221 ATUCR_OUT_EN); 222 223 /* 224 * Enable bus mastering, memory access, SERR, and parity 225 * checking on the ATU. 226 */ 227 if (sc->sc_is_host) { 228 preg = bus_space_read_4(sc->sc_st, sc->sc_atu_sh, 229 PCI_COMMAND_STATUS_REG); 230 preg |= PCI_COMMAND_MEM_ENABLE | PCI_COMMAND_MASTER_ENABLE | 231 PCI_COMMAND_PARITY_ENABLE | PCI_COMMAND_SERR_ENABLE; 232 bus_space_write_4(sc->sc_st, sc->sc_atu_sh, 233 PCI_COMMAND_STATUS_REG, preg); 234 } 235 236 /* Initialize the bus space tags. */ 237 i80321_io_bs_init(&sc->sc_pci_iot, sc); 238 i80321_mem_bs_init(&sc->sc_pci_memt, sc); 239 240 /* Initialize the PCI chipset tag. */ 241 i80321_pci_init(&sc->sc_pci_chipset, sc); 242 243 /* Initialize the DMA tags. */ 244 i80321_pci_dma_init(sc); 245 i80321_local_dma_init(sc); 246 247 /* 248 * Attach all the IOP built-ins. 249 */ 250 for (id = iopxs_devices; id->id_name != NULL; id++) { 251 ia.ia_name = id->id_name; 252 ia.ia_st = sc->sc_st; 253 ia.ia_sh = sc->sc_sh; 254 ia.ia_dmat = &sc->sc_local_dmat; 255 ia.ia_offset = id->id_offset; 256 ia.ia_size = id->id_size; 257 258 (void) config_found(&sc->sc_dev, &ia, i80321_iopxs_print); 259 } 260 261 /* 262 * Attach the PCI bus. 263 */ 264 preg = bus_space_read_4(sc->sc_st, sc->sc_atu_sh, ATU_PCIXSR); 265 preg = PCIXSR_BUSNO(preg); 266 if (preg == 0xff) 267 preg = 0; 268 pba.pba_busname = "pci"; 269 pba.pba_iot = &sc->sc_pci_iot; 270 pba.pba_memt = &sc->sc_pci_memt; 271 pba.pba_dmat = &sc->sc_pci_dmat; 272 pba.pba_dmat64 = NULL; 273 pba.pba_pc = &sc->sc_pci_chipset; 274 pba.pba_bus = preg; 275 pba.pba_bridgetag = NULL; 276 pba.pba_intrswiz = 0; /* XXX what if busno != 0? */ 277 pba.pba_intrtag = 0; 278 pba.pba_flags = PCI_FLAGS_IO_ENABLED | PCI_FLAGS_MEM_ENABLED | 279 PCI_FLAGS_MRL_OKAY | PCI_FLAGS_MRM_OKAY | PCI_FLAGS_MWI_OKAY; 280 (void) config_found(&sc->sc_dev, &pba, i80321_pcibus_print); 281 } 282 283 /* 284 * i80321_iopxs_print: 285 * 286 * Autoconfiguration cfprint routine when attaching 287 * to the "iopxs" device. 288 */ 289 static int 290 i80321_iopxs_print(void *aux, const char *pnp) 291 { 292 293 return (QUIET); 294 } 295 296 /* 297 * i80321_pcibus_print: 298 * 299 * Autoconfiguration cfprint routine when attaching 300 * to the "pcibus" attribute. 301 */ 302 static int 303 i80321_pcibus_print(void *aux, const char *pnp) 304 { 305 struct pcibus_attach_args *pba = aux; 306 307 if (pnp) 308 aprint_normal("%s at %s", pba->pba_busname, pnp); 309 310 aprint_normal(" bus %d", pba->pba_bus); 311 312 return (UNCONF); 313 } 314 315 /* 316 * i80321_pci_dma_init: 317 * 318 * Initialize the PCI DMA tag. 319 */ 320 static void 321 i80321_pci_dma_init(struct i80321_softc *sc) 322 { 323 bus_dma_tag_t dmat = &sc->sc_pci_dmat; 324 struct arm32_dma_range *dr = &sc->sc_pci_dma_range; 325 326 dr->dr_sysbase = sc->sc_iwin[2].iwin_xlate; 327 dr->dr_busbase = PCI_MAPREG_MEM_ADDR(sc->sc_iwin[2].iwin_base_lo); 328 dr->dr_len = sc->sc_iwin[2].iwin_size; 329 330 dmat->_ranges = dr; 331 dmat->_nranges = 1; 332 333 dmat->_dmamap_create = _bus_dmamap_create; 334 dmat->_dmamap_destroy = _bus_dmamap_destroy; 335 dmat->_dmamap_load = _bus_dmamap_load; 336 dmat->_dmamap_load_mbuf = _bus_dmamap_load_mbuf; 337 dmat->_dmamap_load_uio = _bus_dmamap_load_uio; 338 dmat->_dmamap_load_raw = _bus_dmamap_load_raw; 339 dmat->_dmamap_unload = _bus_dmamap_unload; 340 dmat->_dmamap_sync_pre = _bus_dmamap_sync; 341 dmat->_dmamap_sync_post = NULL; 342 343 dmat->_dmamem_alloc = _bus_dmamem_alloc; 344 dmat->_dmamem_free = _bus_dmamem_free; 345 dmat->_dmamem_map = _bus_dmamem_map; 346 dmat->_dmamem_unmap = _bus_dmamem_unmap; 347 dmat->_dmamem_mmap = _bus_dmamem_mmap; 348 } 349 350 /* 351 * i80321_local_dma_init: 352 * 353 * Initialize the local DMA tag. 354 */ 355 void 356 i80321_local_dma_init(struct i80321_softc *sc) 357 { 358 bus_dma_tag_t dmat = &sc->sc_local_dmat; 359 360 dmat->_ranges = NULL; 361 dmat->_nranges = 0; 362 363 dmat->_dmamap_create = _bus_dmamap_create; 364 dmat->_dmamap_destroy = _bus_dmamap_destroy; 365 dmat->_dmamap_load = _bus_dmamap_load; 366 dmat->_dmamap_load_mbuf = _bus_dmamap_load_mbuf; 367 dmat->_dmamap_load_uio = _bus_dmamap_load_uio; 368 dmat->_dmamap_load_raw = _bus_dmamap_load_raw; 369 dmat->_dmamap_unload = _bus_dmamap_unload; 370 dmat->_dmamap_sync_pre = _bus_dmamap_sync; 371 dmat->_dmamap_sync_post = NULL; 372 373 dmat->_dmamem_alloc = _bus_dmamem_alloc; 374 dmat->_dmamem_free = _bus_dmamem_free; 375 dmat->_dmamem_map = _bus_dmamem_map; 376 dmat->_dmamem_unmap = _bus_dmamem_unmap; 377 dmat->_dmamem_mmap = _bus_dmamem_mmap; 378 } 379