1 /* $NetBSD: i80321.c,v 1.16 2004/08/30 15:05:16 drochner 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/cdefs.h> 43 __KERNEL_RCSID(0, "$NetBSD: i80321.c,v 1.16 2004/08/30 15:05:16 drochner Exp $"); 44 45 #include <sys/param.h> 46 #include <sys/systm.h> 47 #include <sys/device.h> 48 49 #define _ARM32_BUS_DMA_PRIVATE 50 #include <machine/bus.h> 51 52 #include <arm/xscale/i80321reg.h> 53 #include <arm/xscale/i80321var.h> 54 55 /* 56 * Statically-allocated bus_space stucture used to access the 57 * i80321's own registers. 58 */ 59 struct bus_space i80321_bs_tag; 60 61 /* 62 * There can be only one i80321, so we keep a global pointer to 63 * the softc, so board-specific code can use features of the 64 * i80321 without having to have a handle on the softc itself. 65 */ 66 struct i80321_softc *i80321_softc; 67 68 static int i80321_iopxs_print(void *, const char *); 69 70 /* Built-in devices. */ 71 static const struct iopxs_device { 72 const char *id_name; 73 bus_addr_t id_offset; 74 bus_size_t id_size; 75 } iopxs_devices[] = { 76 { "iopaau", VERDE_AAU_BASE, VERDE_AAU_SIZE }, 77 /* { "iopdma", VERDE_DMA_BASE0, VERDE_DMA_CHSIZE }, */ 78 /* { "iopdma", VERDE_DMA_BASE1, VERDE_DMA_CHSIZE }, */ 79 { "iopiic", VERDE_I2C_BASE0, VERDE_I2C_CHSIZE }, 80 { "iopiic", VERDE_I2C_BASE1, VERDE_I2C_CHSIZE }, 81 /* { "iopssp", VERDE_SSP_BASE, VERDE_SSP_SIZE }, */ 82 { "iopmu", VERDE_MU_BASE, VERDE_MU_SIZE }, 83 { "iopwdog", 0, 0 }, 84 { NULL, 0, 0 } 85 }; 86 87 static void i80321_pci_dma_init(struct i80321_softc *); 88 89 /* 90 * i80321_attach: 91 * 92 * Board-independent attach routine for the i80321. 93 */ 94 void 95 i80321_attach(struct i80321_softc *sc) 96 { 97 struct pcibus_attach_args pba; 98 const struct iopxs_device *id; 99 struct iopxs_attach_args ia; 100 pcireg_t preg; 101 102 i80321_softc = sc; 103 104 /* 105 * Slice off some useful subregion handles. 106 */ 107 108 if (bus_space_subregion(sc->sc_st, sc->sc_sh, VERDE_ATU_BASE, 109 VERDE_ATU_SIZE, &sc->sc_atu_sh)) 110 panic("%s: unable to subregion ATU registers", 111 sc->sc_dev.dv_xname); 112 113 /* We expect the Memory Controller to be already sliced off. */ 114 115 /* 116 * Program the Inbound windows. 117 */ 118 bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_IALR0, 119 (0xffffffff - (sc->sc_iwin[0].iwin_size - 1)) & 0xffffffc0); 120 bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_IATVR0, 121 sc->sc_iwin[0].iwin_xlate); 122 if (sc->sc_is_host) { 123 bus_space_write_4(sc->sc_st, sc->sc_atu_sh, 124 PCI_MAPREG_START, sc->sc_iwin[0].iwin_base_lo); 125 bus_space_write_4(sc->sc_st, sc->sc_atu_sh, 126 PCI_MAPREG_START + 0x04, sc->sc_iwin[0].iwin_base_hi); 127 } else { 128 sc->sc_iwin[0].iwin_base_lo = bus_space_read_4(sc->sc_st, 129 sc->sc_atu_sh, PCI_MAPREG_START); 130 sc->sc_iwin[0].iwin_base_hi = bus_space_read_4(sc->sc_st, 131 sc->sc_atu_sh, PCI_MAPREG_START + 0x04); 132 sc->sc_iwin[0].iwin_base_lo = 133 PCI_MAPREG_MEM_ADDR(sc->sc_iwin[0].iwin_base_lo); 134 } 135 136 bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_IALR1, 137 (0xffffffff - (sc->sc_iwin[1].iwin_size - 1)) & 0xffffffc0); 138 /* no xlate for window 1 */ 139 if (sc->sc_is_host) { 140 bus_space_write_4(sc->sc_st, sc->sc_atu_sh, 141 PCI_MAPREG_START + 0x08, sc->sc_iwin[1].iwin_base_lo); 142 bus_space_write_4(sc->sc_st, sc->sc_atu_sh, 143 PCI_MAPREG_START + 0x0c, sc->sc_iwin[1].iwin_base_hi); 144 } else { 145 sc->sc_iwin[1].iwin_base_lo = bus_space_read_4(sc->sc_st, 146 sc->sc_atu_sh, PCI_MAPREG_START + 0x08); 147 sc->sc_iwin[1].iwin_base_hi = bus_space_read_4(sc->sc_st, 148 sc->sc_atu_sh, PCI_MAPREG_START + 0x0c); 149 sc->sc_iwin[1].iwin_base_lo = 150 PCI_MAPREG_MEM_ADDR(sc->sc_iwin[1].iwin_base_lo); 151 } 152 153 bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_IALR2, 154 (0xffffffff - (sc->sc_iwin[2].iwin_size - 1)) & 0xffffffc0); 155 bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_IATVR2, 156 sc->sc_iwin[2].iwin_xlate); 157 if (sc->sc_is_host) { 158 bus_space_write_4(sc->sc_st, sc->sc_atu_sh, 159 PCI_MAPREG_START + 0x10, sc->sc_iwin[2].iwin_base_lo); 160 bus_space_write_4(sc->sc_st, sc->sc_atu_sh, 161 PCI_MAPREG_START + 0x14, sc->sc_iwin[2].iwin_base_hi); 162 } else { 163 sc->sc_iwin[2].iwin_base_lo = bus_space_read_4(sc->sc_st, 164 sc->sc_atu_sh, PCI_MAPREG_START + 0x10); 165 sc->sc_iwin[2].iwin_base_hi = bus_space_read_4(sc->sc_st, 166 sc->sc_atu_sh, PCI_MAPREG_START + 0x14); 167 sc->sc_iwin[2].iwin_base_lo = 168 PCI_MAPREG_MEM_ADDR(sc->sc_iwin[2].iwin_base_lo); 169 } 170 171 bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_IALR3, 172 (0xffffffff - (sc->sc_iwin[3].iwin_size - 1)) & 0xffffffc0); 173 bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_IATVR3, 174 sc->sc_iwin[3].iwin_xlate); 175 if (sc->sc_is_host) { 176 bus_space_write_4(sc->sc_st, sc->sc_atu_sh, 177 ATU_IABAR3, sc->sc_iwin[3].iwin_base_lo); 178 bus_space_write_4(sc->sc_st, sc->sc_atu_sh, 179 ATU_IAUBAR3, sc->sc_iwin[3].iwin_base_hi); 180 } else { 181 sc->sc_iwin[3].iwin_base_lo = bus_space_read_4(sc->sc_st, 182 sc->sc_atu_sh, ATU_IABAR3); 183 sc->sc_iwin[3].iwin_base_hi = bus_space_read_4(sc->sc_st, 184 sc->sc_atu_sh, ATU_IAUBAR3); 185 sc->sc_iwin[3].iwin_base_lo = 186 PCI_MAPREG_MEM_ADDR(sc->sc_iwin[3].iwin_base_lo); 187 } 188 189 /* 190 * Mask (disable) the ATU interrupt sources. 191 * XXX May want to revisit this if we encounter 192 * XXX an application that wants it. 193 */ 194 bus_space_write_4(sc->sc_st, sc->sc_atu_sh, 195 ATU_ATUIMR, 196 ATUIMR_IMW1BU|ATUIMR_ISCEM|ATUIMR_RSCEM|ATUIMR_PST| 197 ATUIMR_DPE|ATUIMR_P_SERR_ASRT|ATUIMR_PMA|ATUIMR_PTAM| 198 ATUIMR_PTAT|ATUIMR_PMPE); 199 200 /* 201 * Program the outbound windows. 202 */ 203 bus_space_write_4(sc->sc_st, sc->sc_atu_sh, 204 ATU_OIOWTVR, sc->sc_ioout_xlate); 205 206 if (!sc->sc_is_host) { 207 sc->sc_owin[0].owin_xlate_lo = sc->sc_iwin[1].iwin_base_lo; 208 sc->sc_owin[0].owin_xlate_hi = sc->sc_iwin[1].iwin_base_hi; 209 } 210 bus_space_write_4(sc->sc_st, sc->sc_atu_sh, 211 ATU_OMWTVR0, sc->sc_owin[0].owin_xlate_lo); 212 bus_space_write_4(sc->sc_st, sc->sc_atu_sh, 213 ATU_OUMWTVR0, sc->sc_owin[0].owin_xlate_hi); 214 215 bus_space_write_4(sc->sc_st, sc->sc_atu_sh, 216 ATU_OMWTVR1, sc->sc_owin[1].owin_xlate_lo); 217 bus_space_write_4(sc->sc_st, sc->sc_atu_sh, 218 ATU_OUMWTVR1, sc->sc_owin[1].owin_xlate_hi); 219 220 /* 221 * Set up the ATU configuration register. All we do 222 * right now is enable Outbound Windows. 223 */ 224 bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_ATUCR, 225 ATUCR_OUT_EN); 226 227 /* 228 * Enable bus mastering, memory access, SERR, and parity 229 * checking on the ATU. 230 */ 231 if (sc->sc_is_host) { 232 preg = bus_space_read_4(sc->sc_st, sc->sc_atu_sh, 233 PCI_COMMAND_STATUS_REG); 234 preg |= PCI_COMMAND_MEM_ENABLE | PCI_COMMAND_MASTER_ENABLE | 235 PCI_COMMAND_PARITY_ENABLE | PCI_COMMAND_SERR_ENABLE; 236 bus_space_write_4(sc->sc_st, sc->sc_atu_sh, 237 PCI_COMMAND_STATUS_REG, preg); 238 } 239 240 /* Initialize the bus space tags. */ 241 i80321_io_bs_init(&sc->sc_pci_iot, sc); 242 i80321_mem_bs_init(&sc->sc_pci_memt, sc); 243 244 /* Initialize the PCI chipset tag. */ 245 i80321_pci_init(&sc->sc_pci_chipset, sc); 246 247 /* Initialize the DMA tags. */ 248 i80321_pci_dma_init(sc); 249 i80321_local_dma_init(sc); 250 251 /* 252 * Attach all the IOP built-ins. 253 */ 254 for (id = iopxs_devices; id->id_name != NULL; id++) { 255 ia.ia_name = id->id_name; 256 ia.ia_st = sc->sc_st; 257 ia.ia_sh = sc->sc_sh; 258 ia.ia_dmat = &sc->sc_local_dmat; 259 ia.ia_offset = id->id_offset; 260 ia.ia_size = id->id_size; 261 262 (void) config_found_ia(&sc->sc_dev, "iopxs", &ia, 263 i80321_iopxs_print); 264 } 265 266 /* 267 * Attach the PCI bus. 268 */ 269 preg = bus_space_read_4(sc->sc_st, sc->sc_atu_sh, ATU_PCIXSR); 270 preg = PCIXSR_BUSNO(preg); 271 if (preg == 0xff) 272 preg = 0; 273 pba.pba_iot = &sc->sc_pci_iot; 274 pba.pba_memt = &sc->sc_pci_memt; 275 pba.pba_dmat = &sc->sc_pci_dmat; 276 pba.pba_dmat64 = NULL; 277 pba.pba_pc = &sc->sc_pci_chipset; 278 pba.pba_bus = preg; 279 pba.pba_bridgetag = NULL; 280 pba.pba_intrswiz = 0; /* XXX what if busno != 0? */ 281 pba.pba_intrtag = 0; 282 pba.pba_flags = PCI_FLAGS_IO_ENABLED | PCI_FLAGS_MEM_ENABLED | 283 PCI_FLAGS_MRL_OKAY | PCI_FLAGS_MRM_OKAY | PCI_FLAGS_MWI_OKAY; 284 (void) config_found_ia(&sc->sc_dev, "pcibus", &pba, pcibusprint); 285 } 286 287 /* 288 * i80321_iopxs_print: 289 * 290 * Autoconfiguration cfprint routine when attaching 291 * to the "iopxs" device. 292 */ 293 static int 294 i80321_iopxs_print(void *aux, const char *pnp) 295 { 296 297 return (QUIET); 298 } 299 300 /* 301 * i80321_pci_dma_init: 302 * 303 * Initialize the PCI DMA tag. 304 */ 305 static void 306 i80321_pci_dma_init(struct i80321_softc *sc) 307 { 308 bus_dma_tag_t dmat = &sc->sc_pci_dmat; 309 struct arm32_dma_range *dr = &sc->sc_pci_dma_range; 310 311 dr->dr_sysbase = sc->sc_iwin[2].iwin_xlate; 312 dr->dr_busbase = PCI_MAPREG_MEM_ADDR(sc->sc_iwin[2].iwin_base_lo); 313 dr->dr_len = sc->sc_iwin[2].iwin_size; 314 315 dmat->_ranges = dr; 316 dmat->_nranges = 1; 317 318 dmat->_dmamap_create = _bus_dmamap_create; 319 dmat->_dmamap_destroy = _bus_dmamap_destroy; 320 dmat->_dmamap_load = _bus_dmamap_load; 321 dmat->_dmamap_load_mbuf = _bus_dmamap_load_mbuf; 322 dmat->_dmamap_load_uio = _bus_dmamap_load_uio; 323 dmat->_dmamap_load_raw = _bus_dmamap_load_raw; 324 dmat->_dmamap_unload = _bus_dmamap_unload; 325 dmat->_dmamap_sync_pre = _bus_dmamap_sync; 326 dmat->_dmamap_sync_post = NULL; 327 328 dmat->_dmamem_alloc = _bus_dmamem_alloc; 329 dmat->_dmamem_free = _bus_dmamem_free; 330 dmat->_dmamem_map = _bus_dmamem_map; 331 dmat->_dmamem_unmap = _bus_dmamem_unmap; 332 dmat->_dmamem_mmap = _bus_dmamem_mmap; 333 } 334 335 /* 336 * i80321_local_dma_init: 337 * 338 * Initialize the local DMA tag. 339 */ 340 void 341 i80321_local_dma_init(struct i80321_softc *sc) 342 { 343 bus_dma_tag_t dmat = &sc->sc_local_dmat; 344 345 dmat->_ranges = NULL; 346 dmat->_nranges = 0; 347 348 dmat->_dmamap_create = _bus_dmamap_create; 349 dmat->_dmamap_destroy = _bus_dmamap_destroy; 350 dmat->_dmamap_load = _bus_dmamap_load; 351 dmat->_dmamap_load_mbuf = _bus_dmamap_load_mbuf; 352 dmat->_dmamap_load_uio = _bus_dmamap_load_uio; 353 dmat->_dmamap_load_raw = _bus_dmamap_load_raw; 354 dmat->_dmamap_unload = _bus_dmamap_unload; 355 dmat->_dmamap_sync_pre = _bus_dmamap_sync; 356 dmat->_dmamap_sync_post = NULL; 357 358 dmat->_dmamem_alloc = _bus_dmamem_alloc; 359 dmat->_dmamem_free = _bus_dmamem_free; 360 dmat->_dmamem_map = _bus_dmamem_map; 361 dmat->_dmamem_unmap = _bus_dmamem_unmap; 362 dmat->_dmamem_mmap = _bus_dmamem_mmap; 363 } 364