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