1 /* $NetBSD: vrpciu.c,v 1.1 2001/06/13 07:32:48 enami Exp $ */ 2 3 /*- 4 * Copyright (c) 2001 Enami Tsugutomo. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/param.h> 30 #include <sys/systm.h> 31 #include <sys/device.h> 32 33 #define _HPCMIPS_BUS_DMA_PRIVATE /* XXX */ 34 #include <machine/bus.h> 35 36 #include <dev/pci/pcivar.h> 37 38 #include <hpcmips/vr/icureg.h> 39 #include <hpcmips/vr/vripvar.h> 40 #include <hpcmips/vr/vrpciureg.h> 41 #include <hpcmips/vr/vrc4173bcuvar.h> 42 43 #include "pci.h" 44 45 #ifdef DEBUG 46 #define DPRINTF(args) printf args 47 #else 48 #define DPRINTF(args) 49 #endif 50 51 struct vrpciu_softc { 52 struct device sc_dev; 53 54 vrip_chipset_tag_t sc_vc; 55 bus_space_tag_t sc_iot; 56 bus_space_handle_t sc_ioh; 57 void *sc_ih; 58 59 struct vrc4173bcu_softc *sc_bcu; /* vrc4173bcu */ 60 61 struct hpcmips_pci_chipset sc_pc; 62 }; 63 64 static void vrpciu_write(struct vrpciu_softc *, int, u_int32_t); 65 static u_int32_t 66 vrpciu_read(struct vrpciu_softc *, int); 67 #ifdef DEBUG 68 static void vrpciu_write_2(struct vrpciu_softc *, int, u_int16_t) 69 __attribute__((unused)); 70 static u_int16_t 71 vrpciu_read_2(struct vrpciu_softc *, int); 72 #endif 73 static int vrpciu_match(struct device *, struct cfdata *, void *); 74 static void vrpciu_attach(struct device *, struct device *, void *); 75 #if NPCI > 0 76 static int vrpciu_print(void *, const char *); 77 #endif 78 static int vrpciu_intr(void *); 79 static void vrpciu_attach_hook(struct device *, struct device *, 80 struct pcibus_attach_args *); 81 static int vrpciu_bus_maxdevs(pci_chipset_tag_t, int); 82 static pcitag_t vrpciu_make_tag(pci_chipset_tag_t, int, int, int); 83 static void vrpciu_decompose_tag(pci_chipset_tag_t, pcitag_t, int *, int *, 84 int *); 85 static pcireg_t vrpciu_conf_read(pci_chipset_tag_t, pcitag_t, int); 86 static void vrpciu_conf_write(pci_chipset_tag_t, pcitag_t, int, pcireg_t); 87 static void *vrpciu_intr_establish(pci_chipset_tag_t, pci_intr_handle_t, 88 int, int (*)(void *), void *); 89 static void vrpciu_intr_disestablish(pci_chipset_tag_t, void *); 90 static void *vrpciu_vrcintr_establish(pci_chipset_tag_t, int, 91 int (*)(void *), void *); 92 static void vrpciu_vrcintr_disestablish(pci_chipset_tag_t, void *); 93 94 struct cfattach vrpciu_ca = { 95 sizeof(struct vrpciu_softc), vrpciu_match, vrpciu_attach 96 }; 97 98 static void 99 vrpciu_write(struct vrpciu_softc *sc, int offset, u_int32_t val) 100 { 101 102 bus_space_write_4(sc->sc_iot, sc->sc_ioh, offset, val); 103 } 104 105 static u_int32_t 106 vrpciu_read(struct vrpciu_softc *sc, int offset) 107 { 108 109 return (bus_space_read_4(sc->sc_iot, sc->sc_ioh, offset)); 110 } 111 112 #ifdef DEBUG 113 static void 114 vrpciu_write_2(struct vrpciu_softc *sc, int offset, u_int16_t val) 115 { 116 117 bus_space_write_2(sc->sc_iot, sc->sc_ioh, offset, val); 118 } 119 120 static u_int16_t 121 vrpciu_read_2(struct vrpciu_softc *sc, int offset) 122 { 123 124 return (bus_space_read_2(sc->sc_iot, sc->sc_ioh, offset)); 125 } 126 #endif 127 128 static int 129 vrpciu_match(struct device *parent, struct cfdata *match, void *aux) 130 { 131 132 return (1); 133 } 134 135 static void 136 vrpciu_attach(struct device *parent, struct device *self, void *aux) 137 { 138 struct vrpciu_softc *sc = (struct vrpciu_softc *)self; 139 pci_chipset_tag_t pc = &sc->sc_pc; 140 struct vrip_attach_args *va = aux; 141 bus_space_tag_t iot; 142 u_int32_t reg; 143 #if NPCI > 0 144 struct pcibus_attach_args pba; 145 #endif 146 147 sc->sc_vc = va->va_vc; 148 sc->sc_iot = va->va_iot; 149 if (bus_space_map(sc->sc_iot, va->va_addr, va->va_size, 0, 150 &sc->sc_ioh)) { 151 printf(": couldn't map io space\n"); 152 return; 153 } 154 155 sc->sc_ih = vrip_intr_establish(va->va_vc, va->va_intr, IPL_TTY, 156 vrpciu_intr, sc); 157 if (sc->sc_ih == NULL) { 158 printf(": couldn't establish interrupt\n"); 159 return; 160 } 161 162 /* Enable level 2 interrupt */ 163 vrip_intr_setmask2(va->va_vc, sc->sc_ih, PCIINT_INT0, 1); 164 165 printf("\n"); 166 167 #ifdef DEBUG 168 #define DUMP_MAW(sc, name, reg) do { \ 169 printf("%s: %s =\t0x%08x\n", (sc)->sc_dev.dv_xname, \ 170 (name), (reg)); \ 171 printf("%s:\tIBA/MASK =\t0x%08x/0x%08x (0x%08x - 0x%08x)\n", \ 172 (sc)->sc_dev.dv_xname, \ 173 reg & VRPCIU_MAW_IBAMASK, VRPCIU_MAW_ADDRMASK(reg), \ 174 VRPCIU_MAW_ADDR(reg), \ 175 VRPCIU_MAW_ADDR(reg) + VRPCIU_MAW_SIZE(reg)); \ 176 printf("%s:\tWINEN =\t0x%08x\n", (sc)->sc_dev.dv_xname, \ 177 reg & VRPCIU_MAW_WINEN); \ 178 printf("%s:\tPCIADR =\t0x%08x\n", (sc)->sc_dev.dv_xname, \ 179 VRPCIU_MAW_PCIADDR(reg)); \ 180 } while (0) 181 #define DUMP_TAW(sc, name, reg) do { \ 182 printf("%s: %s =\t\t0x%08x\n", (sc)->sc_dev.dv_xname, \ 183 (name), (reg)); \ 184 printf("%s:\tMASK =\t0x%08x\n", (sc)->sc_dev.dv_xname, \ 185 VRPCIU_TAW_ADDRMASK(reg)); \ 186 printf("%s:\tWINEN =\t0x%08x\n", (sc)->sc_dev.dv_xname, \ 187 reg & VRPCIU_TAW_WINEN); \ 188 printf("%s:\tIBA =\t0x%08x\n", (sc)->sc_dev.dv_xname, \ 189 VRPCIU_TAW_IBA(reg)); \ 190 } while (0) 191 reg = vrpciu_read(sc, VRPCIU_MMAW1REG); 192 DUMP_MAW(sc, "MMAW1", reg); 193 reg = vrpciu_read(sc, VRPCIU_MMAW2REG); 194 DUMP_MAW(sc, "MMAW2", reg); 195 reg = vrpciu_read(sc, VRPCIU_TAW1REG); 196 DUMP_TAW(sc, "TAW1", reg); 197 reg = vrpciu_read(sc, VRPCIU_TAW2REG); 198 DUMP_TAW(sc, "TAW2", reg); 199 reg = vrpciu_read(sc, VRPCIU_MIOAWREG); 200 DUMP_MAW(sc, "MIOAW", reg); 201 printf("%s: BUSERRAD =\t0x%08x\n", sc->sc_dev.dv_xname, 202 vrpciu_read(sc, VRPCIU_BUSERRADREG)); 203 printf("%s: INTCNTSTA =\t0x%08x\n", sc->sc_dev.dv_xname, 204 vrpciu_read(sc, VRPCIU_INTCNTSTAREG)); 205 printf("%s: EXACC =\t0x%08x\n", sc->sc_dev.dv_xname, 206 vrpciu_read(sc, VRPCIU_EXACCREG)); 207 printf("%s: RECONT =\t0x%08x\n", sc->sc_dev.dv_xname, 208 vrpciu_read(sc, VRPCIU_RECONTREG)); 209 printf("%s: PCIEN =\t0x%08x\n", sc->sc_dev.dv_xname, 210 vrpciu_read(sc, VRPCIU_ENREG)); 211 printf("%s: CLOCKSEL =\t0x%08x\n", sc->sc_dev.dv_xname, 212 vrpciu_read(sc, VRPCIU_CLKSELREG)); 213 printf("%s: TRDYV =\t0x%08x\n", sc->sc_dev.dv_xname, 214 vrpciu_read(sc, VRPCIU_TRDYVREG)); 215 printf("%s: CLKRUN =\t0x%08x\n", sc->sc_dev.dv_xname, 216 vrpciu_read_2(sc, VRPCIU_CLKRUNREG)); 217 printf("%s: IDREG =\t0x%08x\n", sc->sc_dev.dv_xname, 218 vrpciu_read(sc, VRPCIU_CONF_BASE + PCI_ID_REG)); 219 reg = vrpciu_read(sc, VRPCIU_CONF_BASE + PCI_COMMAND_STATUS_REG); 220 printf("%s: CSR =\t\t0x%08x\n", sc->sc_dev.dv_xname, reg); 221 vrpciu_write(sc, VRPCIU_CONF_BASE + PCI_COMMAND_STATUS_REG, reg); 222 printf("%s: CSR =\t\t0x%08x\n", sc->sc_dev.dv_xname, 223 vrpciu_read(sc, VRPCIU_CONF_BASE + PCI_COMMAND_STATUS_REG)); 224 printf("%s: CLASS =\t0x%08x\n", sc->sc_dev.dv_xname, 225 vrpciu_read(sc, VRPCIU_CONF_BASE + PCI_CLASS_REG)); 226 printf("%s: BHLC =\t\t0x%08x\n", sc->sc_dev.dv_xname, 227 vrpciu_read(sc, VRPCIU_CONF_BASE + PCI_BHLC_REG)); 228 printf("%s: MAIL =\t\t0x%08x\n", sc->sc_dev.dv_xname, 229 vrpciu_read(sc, VRPCIU_CONF_BASE + VRPCIU_CONF_MAILREG)); 230 printf("%s: MBA1 =\t\t0x%08x\n", sc->sc_dev.dv_xname, 231 vrpciu_read(sc, VRPCIU_CONF_BASE + VRPCIU_CONF_MBA1REG)); 232 printf("%s: MBA2 =\t\t0x%08x\n", sc->sc_dev.dv_xname, 233 vrpciu_read(sc, VRPCIU_CONF_BASE + VRPCIU_CONF_MBA2REG)); 234 printf("%s: INTR =\t\t0x%08x\n", sc->sc_dev.dv_xname, 235 vrpciu_read(sc, VRPCIU_CONF_BASE + PCI_INTERRUPT_REG)); 236 #if 0 237 vrpciu_write(sc, VRPCIU_CONF_BASE + PCI_INTERRUPT_REG, 238 vrpciu_read(sc, VRPCIU_CONF_BASE + PCI_INTERRUPT_REG) | 0x01); 239 printf("%s: INTR =\t\t0x%08x\n", sc->sc_dev.dv_xname, 240 vrpciu_read(sc, VRPCIU_CONF_BASE + PCI_INTERRUPT_REG)); 241 #endif 242 #endif 243 244 pc->pc_dev = &sc->sc_dev; 245 pc->pc_attach_hook = vrpciu_attach_hook; 246 pc->pc_bus_maxdevs = vrpciu_bus_maxdevs; 247 pc->pc_bus_devorder = vrc4173bcu_pci_bus_devorder; 248 pc->pc_make_tag = vrpciu_make_tag; 249 pc->pc_decompose_tag = vrpciu_decompose_tag; 250 pc->pc_conf_read = vrpciu_conf_read; 251 pc->pc_conf_write = vrpciu_conf_write; 252 pc->pc_intr_map = vrc4173bcu_pci_intr_map; 253 pc->pc_intr_string = vrc4173bcu_pci_intr_string; 254 pc->pc_intr_evcnt = vrc4173bcu_pci_intr_evcnt; 255 pc->pc_intr_establish = vrpciu_intr_establish; 256 pc->pc_intr_disestablish = vrpciu_intr_disestablish; 257 pc->pc_vrcintr_establish = vrpciu_vrcintr_establish; 258 pc->pc_vrcintr_disestablish = vrpciu_vrcintr_disestablish; 259 260 #if 0 261 { 262 int i; 263 264 for (i = 0; i < 8; i++) 265 printf("%s: ID_REG(0, 0, %d) = 0x%08x\n", 266 sc->sc_dev.dv_xname, i, 267 pci_conf_read(pc, pci_make_tag(pc, 0, 0, i), 268 PCI_ID_REG)); 269 } 270 #endif 271 272 #if NPCI > 0 273 memset(&pba, 0, sizeof(pba)); 274 pba.pba_busname = "pci"; 275 276 /* For now, just inherit window mappings set by WinCE. XXX. */ 277 278 pba.pba_iot = iot = hpcmips_alloc_bus_space_tag(); 279 reg = vrpciu_read(sc, VRPCIU_MIOAWREG); 280 iot->t_base = VRPCIU_MAW_ADDR(reg); 281 iot->t_size = VRPCIU_MAW_SIZE(reg); 282 snprintf(iot->t_name, sizeof(iot->t_name), "%s/iot", 283 sc->sc_dev.dv_xname); 284 hpcmips_init_bus_space_extent(iot); 285 286 /* 287 * Just use system bus space tag. It works since WinCE maps 288 * PCI bus space at same offset. But this isn't right thing 289 * of course. XXX. 290 */ 291 pba.pba_memt = sc->sc_iot; 292 pba.pba_dmat = &hpcmips_default_bus_dma_tag; 293 pba.pba_bus = 0; 294 pba.pba_flags = PCI_FLAGS_IO_ENABLED | PCI_FLAGS_MEM_ENABLED | 295 PCI_FLAGS_MRL_OKAY; 296 pba.pba_pc = pc; 297 298 config_found(self, &pba, vrpciu_print); 299 #endif 300 } 301 302 #if NPCI > 0 303 static int 304 vrpciu_print(void *aux, const char *pnp) 305 { 306 struct pcibus_attach_args *pba = aux; 307 308 if (pnp != NULL) 309 printf("%s at %s", pba->pba_busname, pnp); 310 else 311 printf(" bus %d", pba->pba_bus); 312 313 return (UNCONF); 314 } 315 #endif 316 317 /* 318 * Handle PCI error interrupts. 319 */ 320 int 321 vrpciu_intr(void *arg) 322 { 323 struct vrpciu_softc *sc = (struct vrpciu_softc *)arg; 324 u_int32_t isr; 325 326 isr = vrpciu_read(sc, VRPCIU_INTCNTSTAREG); 327 printf("%s: vrpciu_intr 0x%08x\n", sc->sc_dev.dv_xname, isr); 328 return ((isr & 0x0f) ? 1 : 0); 329 } 330 331 void 332 vrpciu_attach_hook(struct device *parent, struct device *self, 333 struct pcibus_attach_args *pba) 334 { 335 336 return; 337 } 338 339 int 340 vrpciu_bus_maxdevs(pci_chipset_tag_t pc, int busno) 341 { 342 343 return (32); 344 } 345 346 pcitag_t 347 vrpciu_make_tag(pci_chipset_tag_t pc, int bus, int device, int function) 348 { 349 350 return ((bus << 16) | (device << 11) | (function << 8)); 351 } 352 353 void 354 vrpciu_decompose_tag(pci_chipset_tag_t pc, pcitag_t tag, int *bp, int *dp, 355 int *fp) 356 { 357 358 if (bp != NULL) 359 *bp = (tag >> 16) & 0xff; 360 if (dp != NULL) 361 *dp = (tag >> 11) & 0x1f; 362 if (fp != NULL) 363 *fp = (tag >> 8) & 0x07; 364 } 365 366 pcireg_t 367 vrpciu_conf_read(pci_chipset_tag_t pc, pcitag_t tag, int reg) 368 { 369 struct vrpciu_softc *sc = (struct vrpciu_softc *)pc->pc_dev; 370 u_int32_t val; 371 int bus, device, function; 372 373 pci_decompose_tag(pc, tag, &bus, &device, &function); 374 if (bus == 0) { 375 if (device > 21) 376 return ((pcitag_t)-1); 377 tag = (1 << (device + 11)) | (function << 8); /* Type 0 */ 378 } else 379 tag |= VRPCIU_CONF_TYPE1; 380 381 vrpciu_write(sc, VRPCIU_CONFAREG, tag | reg); 382 val = vrpciu_read(sc, VRPCIU_CONFDREG); 383 #if 0 384 printf("%s: conf_read: tag = 0x%08x, reg = 0x%x, val = 0x%08x\n", 385 sc->sc_dev.dv_xname, (u_int32_t)tag, reg, val); 386 #endif 387 return (val); 388 } 389 390 void 391 vrpciu_conf_write(pci_chipset_tag_t pc, pcitag_t tag, int reg, 392 pcireg_t data) 393 { 394 struct vrpciu_softc *sc = (struct vrpciu_softc *)pc->pc_dev; 395 int bus, device, function; 396 397 #if 0 398 printf("%s: conf_write: tag = 0x%08x, reg = 0x%x, val = 0x%08x\n", 399 sc->sc_dev.dv_xname, (u_int32_t)tag, reg, (u_int32_t)data); 400 #endif 401 vrpciu_decompose_tag(pc, tag, &bus, &device, &function); 402 if (bus == 0) { 403 if (device > 21) 404 return; 405 tag = (1 << (device + 11)) | (function << 8); /* Type 0 */ 406 } else 407 tag |= VRPCIU_CONF_TYPE1; 408 409 vrpciu_write(sc, VRPCIU_CONFAREG, tag | reg); 410 vrpciu_write(sc, VRPCIU_CONFDREG, data); 411 } 412 413 void * 414 vrpciu_intr_establish(pci_chipset_tag_t pc, pci_intr_handle_t ih, int level, 415 int (*func)(void *), void *arg) 416 { 417 struct vrpciu_softc *sc = (struct vrpciu_softc *)pc->pc_dev; 418 419 if (ih == -1) 420 return (NULL); 421 DPRINTF(("vrpciu_intr_establish: %p\n", sc)); 422 return (vrc4173bcu_intr_establish(sc->sc_bcu, ih, func, arg)); 423 } 424 425 void 426 vrpciu_intr_disestablish(pci_chipset_tag_t pc, void *cookie) 427 { 428 struct vrpciu_softc *sc = (struct vrpciu_softc *)pc->pc_dev; 429 430 DPRINTF(("vrpciu_intr_disestablish: %p\n", sc)); 431 vrc4173bcu_intr_disestablish(sc->sc_bcu, cookie); 432 } 433 434 void * 435 vrpciu_vrcintr_establish(pci_chipset_tag_t pc, int port, 436 int (*func)(void *), void *arg) 437 { 438 struct vrpciu_softc *sc = (struct vrpciu_softc *)pc->pc_dev; 439 struct vrip_softc *vsc = (struct vrip_softc *)sc->sc_vc; 440 void *ih; 441 442 sc->sc_bcu = arg; 443 ih = hpcio_intr_establish(vsc->sc_gpio_chips[VRIP_IOCHIP_VRGIU], 444 port, HPCIO_INTR_LEVEL | HPCIO_INTR_LOW | HPCIO_INTR_HOLD, 445 func, arg); 446 447 return (ih); 448 } 449 450 void 451 vrpciu_vrcintr_disestablish(pci_chipset_tag_t pc, void *ih) 452 { 453 struct vrpciu_softc *sc = (struct vrpciu_softc *)pc->pc_dev; 454 struct vrip_softc *vsc = (struct vrip_softc *)sc->sc_vc; 455 456 return (vrip_intr_disestablish(vsc->sc_gpio_chips[VRIP_IOCHIP_VRGIU], 457 ih)); 458 } 459