pci_machdep.c revision 1.13
1/* $NetBSD: pci_machdep.c,v 1.13 2018/11/03 17:26:41 jmcneill Exp $ */ 2/* 3 * Copyright (c) 2008 KIYOHARA Takashi 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 19 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 23 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 24 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 * POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28#include <sys/cdefs.h> 29__KERNEL_RCSID(0, "$NetBSD: pci_machdep.c,v 1.13 2018/11/03 17:26:41 jmcneill Exp $"); 30 31#include "opt_mvsoc.h" 32#include "gtpci.h" 33#include "mvpex.h" 34#include "pci.h" 35 36#include <sys/param.h> 37#include <sys/device.h> 38#include <sys/extent.h> 39 40#include <dev/pci/pcivar.h> 41#include <dev/pci/pciconf.h> 42 43#include <arm/marvell/mvsocreg.h> 44#include <arm/marvell/mvsocvar.h> 45#include <arm/marvell/mvsocgppvar.h> 46#if NGTPCI > 0 47#include <dev/marvell/gtpcireg.h> 48#include <dev/marvell/gtpcivar.h> 49#endif 50#if NMVPEX > 0 51#include <dev/marvell/mvpexreg.h> 52#include <dev/marvell/mvpexvar.h> 53#endif 54 55#include <machine/pci_machdep.h> 56 57#if defined(ORION) 58#include <arm/marvell/orionreg.h> 59#endif 60#if defined(KIRKWOOD) 61#include <arm/marvell/kirkwoodreg.h> 62#endif 63#include <dev/marvell/marvellreg.h> 64 65 66#if NGTPCI > 0 67#if NGTPCI_MBUS > 0 68static pcireg_t gtpci_mbus_conf_read(void *, pcitag_t, int); 69static void gtpci_mbus_conf_write(void *, pcitag_t, int, pcireg_t); 70#endif 71static int gtpci_gpp_intr_map(const struct pci_attach_args *, 72 pci_intr_handle_t *); 73static const char *gtpci_gpp_intr_string(void *, pci_intr_handle_t, 74 char *, size_t); 75static const struct evcnt *gtpci_gpp_intr_evcnt(void *, pci_intr_handle_t); 76static void *gtpci_gpp_intr_establish(void *, pci_intr_handle_t, int, int (*)(void *), void *); 77static void gtpci_gpp_intr_disestablish(void *, void *); 78 79struct arm32_pci_chipset arm32_gtpci_chipset = { 80 NULL, /* conf_v */ 81 gtpci_attach_hook, 82 gtpci_bus_maxdevs, 83 gtpci_make_tag, 84 gtpci_decompose_tag, 85 NULL, /* get_segment */ 86#if NGTPCI_MBUS > 0 87 gtpci_mbus_conf_read, /* XXXX: always this functions */ 88 gtpci_mbus_conf_write, 89#else 90 gtpci_conf_read, 91 gtpci_conf_write, 92#endif 93 NULL, /* intr_v */ 94 gtpci_gpp_intr_map, 95 gtpci_gpp_intr_string, 96 gtpci_gpp_intr_evcnt, 97 NULL, /* intr_setattr */ 98 gtpci_gpp_intr_establish, 99 gtpci_gpp_intr_disestablish, 100#ifdef __HAVE_PCI_CONF_HOOK 101 gtpci_conf_hook, 102#endif 103 gtpci_conf_interrupt, 104}; 105#endif 106 107#if NMVPEX > 0 108#if NMVPEX_MBUS > 0 109static pcireg_t mvpex_mbus_conf_read(void *, pcitag_t, int); 110#endif 111 112struct arm32_pci_chipset arm32_mvpex0_chipset = { 113 NULL, /* conf_v */ 114 mvpex_attach_hook, 115 mvpex_bus_maxdevs, 116 mvpex_make_tag, 117 mvpex_decompose_tag, 118 NULL, /* get_segment */ 119#if NMVPEX_MBUS > 0 120 mvpex_mbus_conf_read, /* XXXX: always this functions */ 121#else 122 mvpex_conf_read, 123#endif 124 mvpex_conf_write, 125 NULL, /* intr_v */ 126 mvpex_intr_map, 127 mvpex_intr_string, 128 mvpex_intr_evcnt, 129 NULL, /* intr_setattr */ 130 mvpex_intr_establish, 131 mvpex_intr_disestablish, 132#ifdef __HAVE_PCI_CONF_HOOK 133 mvpex_conf_hook, 134#endif 135 mvpex_conf_interrupt, 136}; 137struct arm32_pci_chipset arm32_mvpex1_chipset = { 138 NULL, /* conf_v */ 139 mvpex_attach_hook, 140 mvpex_bus_maxdevs, 141 mvpex_make_tag, 142 mvpex_decompose_tag, 143 NULL, /* get_segment */ 144#if NMVPEX_MBUS > 0 145 mvpex_mbus_conf_read, /* XXXX: always this functions */ 146#else 147 mvpex_conf_read, 148#endif 149 mvpex_conf_write, 150 NULL, /* intr_v */ 151 mvpex_intr_map, 152 mvpex_intr_string, 153 mvpex_intr_evcnt, 154 NULL, /* intr_setattr */ 155 mvpex_intr_establish, 156 mvpex_intr_disestablish, 157#ifdef __HAVE_PCI_CONF_HOOK 158 mvpex_conf_hook, 159#endif 160 mvpex_conf_interrupt, 161}; 162struct arm32_pci_chipset arm32_mvpex2_chipset = { 163 NULL, /* conf_v */ 164 mvpex_attach_hook, 165 mvpex_bus_maxdevs, 166 mvpex_make_tag, 167 mvpex_decompose_tag, 168 NULL, /* get_segment */ 169#if NMVPEX_MBUS > 0 170 mvpex_mbus_conf_read, /* XXXX: always this functions */ 171#else 172 mvpex_conf_read, 173#endif 174 mvpex_conf_write, 175 NULL, /* intr_v */ 176 mvpex_intr_map, 177 mvpex_intr_string, 178 mvpex_intr_evcnt, 179 NULL, /* intr_setattr */ 180 mvpex_intr_establish, 181 mvpex_intr_disestablish, 182#ifdef __HAVE_PCI_CONF_HOOK 183 mvpex_conf_hook, 184#endif 185 mvpex_conf_interrupt, 186}; 187struct arm32_pci_chipset arm32_mvpex3_chipset = { 188 NULL, /* conf_v */ 189 mvpex_attach_hook, 190 mvpex_bus_maxdevs, 191 mvpex_make_tag, 192 mvpex_decompose_tag, 193 NULL, /* get_segment */ 194#if NMVPEX_MBUS > 0 195 mvpex_mbus_conf_read, /* XXXX: always this functions */ 196#else 197 mvpex_conf_read, 198#endif 199 mvpex_conf_write, 200 NULL, /* intr_v */ 201 mvpex_intr_map, 202 mvpex_intr_string, 203 mvpex_intr_evcnt, 204 NULL, /* intr_setattr */ 205 mvpex_intr_establish, 206 mvpex_intr_disestablish, 207#ifdef __HAVE_PCI_CONF_HOOK 208 mvpex_conf_hook, 209#endif 210 mvpex_conf_interrupt, 211}; 212struct arm32_pci_chipset arm32_mvpex4_chipset = { 213 NULL, /* conf_v */ 214 mvpex_attach_hook, 215 mvpex_bus_maxdevs, 216 mvpex_make_tag, 217 mvpex_decompose_tag, 218 NULL, /* get_segment */ 219#if NMVPEX_MBUS > 0 220 mvpex_mbus_conf_read, /* XXXX: always this functions */ 221#else 222 mvpex_conf_read, 223#endif 224 mvpex_conf_write, 225 NULL, /* intr_v */ 226 mvpex_intr_map, 227 mvpex_intr_string, 228 mvpex_intr_evcnt, 229 NULL, /* intr_setattr */ 230 mvpex_intr_establish, 231 mvpex_intr_disestablish, 232#ifdef __HAVE_PCI_CONF_HOOK 233 mvpex_conf_hook, 234#endif 235 mvpex_conf_interrupt, 236}; 237struct arm32_pci_chipset arm32_mvpex5_chipset = { 238 NULL, /* conf_v */ 239 mvpex_attach_hook, 240 mvpex_bus_maxdevs, 241 mvpex_make_tag, 242 mvpex_decompose_tag, 243 NULL, /* get_segment */ 244#if NMVPEX_MBUS > 0 245 mvpex_mbus_conf_read, /* XXXX: always this functions */ 246#else 247 mvpex_conf_read, 248#endif 249 mvpex_conf_write, 250 NULL, /* intr_v */ 251 mvpex_intr_map, 252 mvpex_intr_string, 253 mvpex_intr_evcnt, 254 NULL, /* intr_setattr */ 255 mvpex_intr_establish, 256 mvpex_intr_disestablish, 257#ifdef __HAVE_PCI_CONF_HOOK 258 mvpex_conf_hook, 259#endif 260 mvpex_conf_interrupt, 261}; 262struct arm32_pci_chipset arm32_mvpex6_chipset = { 263 NULL, /* conf_v */ 264 mvpex_attach_hook, 265 mvpex_bus_maxdevs, 266 mvpex_make_tag, 267 mvpex_decompose_tag, 268 NULL, /* get_segment */ 269#if NMVPEX_MBUS > 0 270 mvpex_mbus_conf_read, /* XXXX: always this functions */ 271#else 272 mvpex_conf_read, 273#endif 274 mvpex_conf_write, 275 NULL, /* intr_v */ 276 mvpex_intr_map, 277 mvpex_intr_string, 278 mvpex_intr_evcnt, 279 NULL, /* intr_setattr */ 280 mvpex_intr_establish, 281 mvpex_intr_disestablish, 282#ifdef __HAVE_PCI_CONF_HOOK 283 mvpex_conf_hook, 284#endif 285 mvpex_conf_interrupt, 286}; 287#endif /* NMVPEX > 0 */ 288 289#if NGTPCI > 0 290/* ARGSUSED */ 291void 292gtpci_conf_interrupt(void *v, int bus, int dev, int pin, int swiz, int *iline) 293{ 294 295 /* nothing */ 296} 297 298#if NGTPCI_MBUS > 0 299#define GTPCI_MBUS_CA 0x0c78 /* Configuration Address */ 300#define GTPCI_MBUS_CD 0x0c7c /* Configuration Data */ 301 302static pcireg_t 303gtpci_mbus_conf_read(void *v, pcitag_t tag, int reg) 304{ 305 struct gtpci_softc *sc = v; 306 const pcireg_t addr = tag | reg; 307 308 if ((unsigned int)reg >= PCI_CONF_SIZE) 309 return -1; 310 311 bus_space_write_4(sc->sc_iot, sc->sc_ioh, GTPCI_MBUS_CA, 312 addr | GTPCI_CA_CONFIGEN); 313 if ((addr | GTPCI_CA_CONFIGEN) != 314 bus_space_read_4(sc->sc_iot, sc->sc_ioh, GTPCI_MBUS_CA)) 315 return -1; 316 317 return bus_space_read_4(sc->sc_iot, sc->sc_ioh, GTPCI_MBUS_CD); 318} 319 320static void 321gtpci_mbus_conf_write(void *v, pcitag_t tag, int reg, pcireg_t data) 322{ 323 struct gtpci_softc *sc = v; 324 pcireg_t addr = tag | (reg & 0xfc); 325 326 if ((unsigned int)reg >= PCI_CONF_SIZE) 327 return; 328 329 bus_space_write_4(sc->sc_iot, sc->sc_ioh, GTPCI_MBUS_CA, 330 addr | GTPCI_CA_CONFIGEN); 331 if ((addr | GTPCI_CA_CONFIGEN) != 332 bus_space_read_4(sc->sc_iot, sc->sc_ioh, GTPCI_MBUS_CA)) 333 return; 334 335 bus_space_write_4(sc->sc_iot, sc->sc_ioh, GTPCI_MBUS_CD, data); 336} 337#endif /* NGTPCI_MBUS */ 338 339/* 340 * We assume to use GPP interrupt as PCI interrupts. 341 * pci_intr_map() shall returns number of GPP between 0 and 31. However 342 * returns 0xff, because we do not know the connected pin number for GPP 343 * of your board. 344 * pci_intr_string() shall returns string "gpp <num>". 345 * pci_intr_establish() established interrupt in the pin of all GPP. 346 * Moreover, the return value will be disregarded. For instance, the 347 * setting for interrupt is not done. 348 */ 349 350/* ARGSUSED */ 351static int 352gtpci_gpp_intr_map(const struct pci_attach_args *pa, pci_intr_handle_t *ihp) 353{ 354 355 *ihp = pa->pa_intrpin; 356 return 0; 357} 358 359/* ARGSUSED */ 360static const char * 361gtpci_gpp_intr_string(void *v, pci_intr_handle_t pin, char *buf, size_t len) 362{ 363 struct gtpci_softc *sc = v; 364 prop_array_t int2gpp; 365 prop_object_t gpp; 366 367 int2gpp = prop_dictionary_get(device_properties(sc->sc_dev), "int2gpp"); 368 gpp = prop_array_get(int2gpp, pin); 369 snprintf(buf, len, "gpp %d", (int)prop_number_integer_value(gpp)); 370 371 return buf; 372} 373 374/* ARGSUSED */ 375static const struct evcnt * 376gtpci_gpp_intr_evcnt(void *v, pci_intr_handle_t pin) 377{ 378 379 return NULL; 380} 381 382static void * 383gtpci_gpp_intr_establish(void *v, pci_intr_handle_t int_pin, int ipl, 384 int (*intrhand)(void *), void *intrarg) 385{ 386 struct gtpci_softc *sc = v; 387 prop_array_t int2gpp; 388 prop_object_t gpp; 389 int gpp_pin; 390 391 int2gpp = prop_dictionary_get(device_properties(sc->sc_dev), "int2gpp"); 392 gpp = prop_array_get(int2gpp, int_pin); 393 gpp_pin = prop_number_integer_value(gpp); 394 return mvsocgpp_intr_establish(gpp_pin, ipl, IST_LEVEL_LOW, intrhand, 395 intrarg); 396} 397 398static void 399gtpci_gpp_intr_disestablish(void *v, void *ih) 400{ 401 402 mvsocgpp_intr_disestablish(ih); 403} 404#endif 405 406#if NMVPEX_MBUS > 0 407/* ARGSUSED */ 408void 409mvpex_conf_interrupt(void *v, int bus, int dev, int ipin, int swiz, int *ilinep) 410{ 411 412 /* nothing */ 413} 414 415static pcireg_t 416mvpex_mbus_conf_read(void *v, pcitag_t tag, int reg) 417{ 418 struct mvpex_softc *sc = v; 419 pcireg_t addr, data, pci_cs; 420 uint32_t stat; 421 int bus, dev, func, pexbus, pexdev; 422 423 if ((unsigned int)reg >= PCI_CONF_SIZE) 424 return -1; 425 426 mvpex_decompose_tag(v, tag, &bus, &dev, &func); 427 428 stat = bus_space_read_4(sc->sc_iot, sc->sc_ioh, MVPEX_STAT); 429 pexbus = MVPEX_STAT_PEXBUSNUM(stat); 430 pexdev = MVPEX_STAT_PEXDEVNUM(stat); 431 if (bus != pexbus || dev != pexdev) 432 if (stat & MVPEX_STAT_DLDOWN) 433 return -1; 434 435 if (bus == pexbus) { 436 if (pexdev == 0) { 437 if (dev != 1 && dev != pexdev) 438 return -1; 439 } else { 440 if (dev != 0 && dev != pexdev) 441 return -1; 442 } 443 if (func != 0) 444 return -1; 445 } 446 447 addr = ((reg & 0xf00) << 24) | tag | (reg & 0xfc); 448 449#if defined(ORION) 450 /* 451 * Guideline (GL# PCI Express-1) Erroneous Read Data on Configuration 452 * This guideline is relevant for all devices except of the following 453 * devices: 454 * 88F5281-BO and above, and 88F5181L-A0 and above 455 */ 456 if ((bus != pexbus || dev != pexdev) && 457 !(sc->sc_model == MARVELL_ORION_2_88F5281 && sc->sc_rev == 1) && 458 !(sc->sc_model == MARVELL_ORION_1_88F5181 && sc->sc_rev == 8)) { 459 460 /* PCI-Express configuration read work-around */ 461 /* 462 * We will use one of the Punit (AHBToMbus) windows to 463 * access the xbar and read the data from there 464 * 465 * Need to configure the 2 free Punit (AHB to MBus bridge) 466 * address decoding windows: 467 * Configure the flash Window to handle Configuration space 468 * requests for PEX0/1: 469 * 470 * Configuration transactions from the CPU should write/read 471 * the data to/from address of the form: 472 * addr[31:28]: 0x5 (for PEX0) or 0x6 (for PEX1) 473 * addr[27:24]: extended register number 474 * addr[23:16]: bus number 475 * addr[15:11]: device number 476 * addr[10: 8]: function number 477 * addr[ 7: 0]: register number 478 */ 479 480 struct mvsoc_softc *soc = 481 device_private(device_parent(sc->sc_dev));; 482 bus_space_handle_t pcicfg_ioh; 483 uint32_t remapl, remaph, wc, pcicfg_addr, pcicfg_size; 484 int window, target, attr, base, size, s; 485 const int pex_pcicfg_tag = 486 (sc->sc_model == MARVELL_ORION_1_88F1181) ? 487 ORION_TAG_FLASH_CS : ORION_TAG_PEX0_MEM; 488 489 window = mvsoc_target(pex_pcicfg_tag, 490 &target, &attr, &base, &size); 491 if (window >= nwindow) { 492 aprint_error_dev(sc->sc_dev, 493 "can't read pcicfg space\n"); 494 return -1; 495 } 496 497 s = splhigh(); 498 499 remapl = remaph = 0; 500 if (window == 0 || window == 1) { 501 remapl = read_mlmbreg(MVSOC_MLMB_WRLR(window)); 502 remaph = read_mlmbreg(MVSOC_MLMB_WRHR(window)); 503 } 504 505 wc = 506 MVSOC_MLMB_WCR_WINEN | 507 MVSOC_MLMB_WCR_ATTR(ORION_ATTR_PEX_CFG) | 508 MVSOC_MLMB_WCR_TARGET((soc->sc_addr + sc->sc_offset) >> 16); 509 if (sc->sc_model == MARVELL_ORION_1_88F1181) { 510 pcicfg_addr = base; 511 pcicfg_size = size; 512 } else if (sc->sc_model == MARVELL_ORION_1_88F5182) { 513#define PEX_PCICFG_RW_WA_BASE 0x50000000 514#define PEX_PCICFG_RW_WA_5182_BASE 0xf0000000 515#define PEX_PCICFG_RW_WA_SIZE (16 * 1024 * 1024) 516 pcicfg_addr = PEX_PCICFG_RW_WA_5182_BASE; 517 pcicfg_size = PEX_PCICFG_RW_WA_SIZE; 518 } else { 519 pcicfg_addr = PEX_PCICFG_RW_WA_BASE; 520 pcicfg_size = PEX_PCICFG_RW_WA_SIZE; 521 } 522 write_mlmbreg(MVSOC_MLMB_WCR(window), 523 wc | MVSOC_MLMB_WCR_SIZE(pcicfg_size)); 524 write_mlmbreg(MVSOC_MLMB_WBR(window), pcicfg_addr); 525 526 if (window == 0 || window == 1) { 527 write_mlmbreg(MVSOC_MLMB_WRLR(window), pcicfg_addr); 528 write_mlmbreg(MVSOC_MLMB_WRHR(window), 0); 529 } 530 531 if (bus_space_map(sc->sc_iot, pcicfg_addr, pcicfg_size, 0, 532 &pcicfg_ioh) == 0) { 533 data = bus_space_read_4(sc->sc_iot, pcicfg_ioh, addr); 534 bus_space_unmap(sc->sc_iot, pcicfg_ioh, pcicfg_size); 535 } else 536 data = -1; 537 538 write_mlmbreg(MVSOC_MLMB_WCR(window), 539 MVSOC_MLMB_WCR_WINEN | 540 MVSOC_MLMB_WCR_ATTR(attr) | 541 MVSOC_MLMB_WCR_TARGET(target) | 542 MVSOC_MLMB_WCR_SIZE(size)); 543 write_mlmbreg(MVSOC_MLMB_WBR(window), base); 544 if (window == 0 || window == 1) { 545 write_mlmbreg(MVSOC_MLMB_WRLR(window), remapl); 546 write_mlmbreg(MVSOC_MLMB_WRHR(window), remaph); 547 } 548 549 splx(s); 550#else 551 if (0) { 552#endif 553 } else { 554 bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVPEX_CA, 555 addr | MVPEX_CA_CONFIGEN); 556 if ((addr | MVPEX_CA_CONFIGEN) != 557 bus_space_read_4(sc->sc_iot, sc->sc_ioh, MVPEX_CA)) 558 return -1; 559 560 pci_cs = bus_space_read_4(sc->sc_iot, sc->sc_ioh, 561 PCI_COMMAND_STATUS_REG); 562 bus_space_write_4(sc->sc_iot, sc->sc_ioh, 563 PCI_COMMAND_STATUS_REG, pci_cs | PCI_STATUS_MASTER_ABORT); 564 565 data = bus_space_read_4(sc->sc_iot, sc->sc_ioh, MVPEX_CD); 566 } 567 568 return data; 569} 570#endif 571