2 * Low-Level PCI and SB support for BCM47xx
4 * Copyright 2004, Broadcom Corporation
7 * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
8 * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
9 * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
10 * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
21 #include <bcmendian.h>
27 /* Can free sbpci_init() memory after boot */
32 /* Emulated configuration space */
33 static pci_config_regs sb_config_regs
[SB_MAXCORES
];
36 static uint16 pci_ban
[32] = { 0 };
37 static uint pci_banned
= 0;
40 static bool cardbus
= FALSE
;
42 /* Disable PCI host core */
43 static bool pci_disabled
= FALSE
;
46 * Functions for accessing external PCI configuration space
49 /* Assume one-hot slot wiring */
50 #define PCI_SLOT_MAX 16
53 config_cmd(void *sbh
, uint bus
, uint dev
, uint func
, uint off
)
59 /* CardBusMode supports only one device */
60 if (cardbus
&& dev
> 1)
63 coreidx
= sb_coreidx(sbh
);
64 regs
= (sbpciregs_t
*) sb_setcore(sbh
, SB_PCI
, 0);
66 /* Type 0 transaction */
68 /* Skip unwired slots */
69 if (dev
< PCI_SLOT_MAX
) {
70 /* Slide the PCI window to the appropriate slot */
71 W_REG(®s
->sbtopci1
, SBTOPCI_CFG0
| ((1 << (dev
+ 16)) & SBTOPCI1_MASK
));
72 addr
= SB_PCI_CFG
| ((1 << (dev
+ 16)) & ~SBTOPCI1_MASK
) |
73 (func
<< 8) | (off
& ~3);
77 /* Type 1 transaction */
79 W_REG(®s
->sbtopci1
, SBTOPCI_CFG1
);
80 addr
= SB_PCI_CFG
| (bus
<< 16) | (dev
<< 11) | (func
<< 8) | (off
& ~3);
83 sb_setcoreidx(sbh
, coreidx
);
89 extpci_read_config(void *sbh
, uint bus
, uint dev
, uint func
, uint off
, void *buf
, int len
)
91 uint32 addr
, *reg
= NULL
, val
;
95 !(addr
= config_cmd(sbh
, bus
, dev
, func
, off
)) ||
96 !(reg
= (uint32
*) REG_MAP(addr
, len
)) ||
100 val
>>= 8 * (off
& 3);
102 *((uint32
*) buf
) = val
;
104 *((uint16
*) buf
) = (uint16
) val
;
106 *((uint8
*) buf
) = (uint8
) val
;
117 extpci_write_config(void *sbh
, uint bus
, uint dev
, uint func
, uint off
, void *buf
, int len
)
119 uint32 addr
, *reg
= NULL
, val
;
123 !(addr
= config_cmd(sbh
, bus
, dev
, func
, off
)) ||
124 !(reg
= (uint32
*) REG_MAP(addr
, len
)) ||
129 val
= *((uint32
*) buf
);
131 val
&= ~(0xffff << (8 * (off
& 3)));
132 val
|= *((uint16
*) buf
) << (8 * (off
& 3));
133 } else if (len
== 1) {
134 val
&= ~(0xff << (8 * (off
& 3)));
135 val
|= *((uint8
*) buf
) << (8 * (off
& 3));
149 * Functions for accessing translated SB configuration space
153 sb_read_config(void *sbh
, uint bus
, uint dev
, uint func
, uint off
, void *buf
, int len
)
155 pci_config_regs
*cfg
;
157 if (dev
>= SB_MAXCORES
|| (off
+ len
) > sizeof(pci_config_regs
))
159 cfg
= &sb_config_regs
[dev
];
161 ASSERT(ISALIGNED(off
, len
));
162 ASSERT(ISALIGNED(buf
, len
));
165 *((uint32
*) buf
) = ltoh32(*((uint32
*)((ulong
) cfg
+ off
)));
167 *((uint16
*) buf
) = ltoh16(*((uint16
*)((ulong
) cfg
+ off
)));
169 *((uint8
*) buf
) = *((uint8
*)((ulong
) cfg
+ off
));
177 sb_write_config(void *sbh
, uint bus
, uint dev
, uint func
, uint off
, void *buf
, int len
)
182 pci_config_regs
*cfg
;
184 if (dev
>= SB_MAXCORES
|| (off
+ len
) > sizeof(pci_config_regs
))
186 cfg
= &sb_config_regs
[dev
];
188 ASSERT(ISALIGNED(off
, len
));
189 ASSERT(ISALIGNED(buf
, len
));
191 /* Emulate BAR sizing */
192 if (off
>= OFFSETOF(pci_config_regs
, base
[0]) && off
<= OFFSETOF(pci_config_regs
, base
[3]) &&
193 len
== 4 && *((uint32
*) buf
) == ~0) {
194 coreidx
= sb_coreidx(sbh
);
195 if ((regs
= sb_setcoreidx(sbh
, dev
))) {
196 sb
= (sbconfig_t
*)((ulong
) regs
+ SBCONFIGOFF
);
197 /* Highest numbered address match register */
198 n
= (R_REG(&sb
->sbidlow
) & SBIDL_AR_MASK
) >> SBIDL_AR_SHIFT
;
199 if (off
== OFFSETOF(pci_config_regs
, base
[0]))
200 cfg
->base
[0] = ~(sb_size(R_REG(&sb
->sbadmatch0
)) - 1);
201 else if (off
== OFFSETOF(pci_config_regs
, base
[1]) && n
>= 1)
202 cfg
->base
[1] = ~(sb_size(R_REG(&sb
->sbadmatch1
)) - 1);
203 else if (off
== OFFSETOF(pci_config_regs
, base
[2]) && n
>= 2)
204 cfg
->base
[2] = ~(sb_size(R_REG(&sb
->sbadmatch2
)) - 1);
205 else if (off
== OFFSETOF(pci_config_regs
, base
[3]) && n
>= 3)
206 cfg
->base
[3] = ~(sb_size(R_REG(&sb
->sbadmatch3
)) - 1);
208 sb_setcoreidx(sbh
, coreidx
);
213 *((uint32
*)((ulong
) cfg
+ off
)) = htol32(*((uint32
*) buf
));
215 *((uint16
*)((ulong
) cfg
+ off
)) = htol16(*((uint16
*) buf
));
217 *((uint8
*)((ulong
) cfg
+ off
)) = *((uint8
*) buf
);
225 sbpci_read_config(void *sbh
, uint bus
, uint dev
, uint func
, uint off
, void *buf
, int len
)
228 return sb_read_config(sbh
, bus
, dev
, func
, off
, buf
, len
);
230 return extpci_read_config(sbh
, bus
, dev
, func
, off
, buf
, len
);
234 sbpci_write_config(void *sbh
, uint bus
, uint dev
, uint func
, uint off
, void *buf
, int len
)
237 return sb_write_config(sbh
, bus
, dev
, func
, off
, buf
, len
);
239 return extpci_write_config(sbh
, bus
, dev
, func
, off
, buf
, len
);
243 sbpci_ban(uint16 core
)
245 if (pci_banned
< ARRAYSIZE(pci_ban
))
246 pci_ban
[pci_banned
++] = core
;
250 sbpci_init(void *sbh
)
252 uint chip
, chiprev
, chippkg
, coreidx
, host
, i
;
256 pci_config_regs
*cfg
;
261 uint8
class, subclass
, progif
;
263 uint32 sbips_int_mask
[] = { 0, SBIPS_INT1_MASK
, SBIPS_INT2_MASK
, SBIPS_INT3_MASK
, SBIPS_INT4_MASK
};
264 uint32 sbips_int_shift
[] = { 0, 0, SBIPS_INT2_SHIFT
, SBIPS_INT3_SHIFT
, SBIPS_INT4_SHIFT
};
267 chiprev
= sb_chiprev(sbh
);
268 chippkg
= sb_chippkg(sbh
);
269 coreidx
= sb_coreidx(sbh
);
271 if (!(pci
= (sbpciregs_t
*) sb_setcore(sbh
, SB_PCI
, 0)))
273 sb_core_reset(sbh
, 0);
275 boardflags
= (uint32
) getintvar(NULL
, "boardflags");
277 if ((chip
== BCM4310_DEVICE_ID
) && (chiprev
== 0))
281 * The 200-pin BCM4712 package does not bond out PCI. Even when
282 * PCI is bonded out, some boards may leave the pins
285 if (((chip
== BCM4712_DEVICE_ID
) &&
286 ((chippkg
== BCM4712SMALL_PKG_ID
) ||
287 (chippkg
== BCM4712MID_PKG_ID
))) ||
288 (boardflags
& BFL_NOPCI
))
292 * If the PCI core should not be touched (disabled, not bonded
293 * out, or pins floating), do not even attempt to access core
294 * registers. Otherwise, try to determine if it is in host
300 host
= !BUSPROBE(val
, &pci
->control
);
303 /* Disable PCI interrupts in client mode */
304 sb
= (sbconfig_t
*)((ulong
) pci
+ SBCONFIGOFF
);
305 W_REG(&sb
->sbintvec
, 0);
307 /* Disable the PCI bridge in client mode */
309 printf("PCI: Disabled\n");
311 /* Reset the external PCI bus and enable the clock */
312 W_REG(&pci
->control
, 0x5); /* enable the tristate drivers */
313 W_REG(&pci
->control
, 0xd); /* enable the PCI clock */
314 OSL_DELAY(150); /* delay > 100 us */
315 W_REG(&pci
->control
, 0xf); /* deassert PCI reset */
316 W_REG(&pci
->arbcontrol
, PCI_INT_ARB
); /* use internal arbiter */
317 OSL_DELAY(1); /* delay 1 us */
319 /* Enable CardBusMode */
320 cardbus
= nvram_match("cardbus", "1");
322 printf("PCI: Enabling CardBus\n");
323 /* GPIO 1 resets the CardBus device on bcm94710ap */
324 sb_gpioout(sbh
, 1, 1);
325 sb_gpioouten(sbh
, 1, 1);
326 W_REG(&pci
->sprom
[0], R_REG(&pci
->sprom
[0]) | 0x400);
329 /* 64 MB I/O access window */
330 W_REG(&pci
->sbtopci0
, SBTOPCI_IO
);
331 /* 64 MB configuration access window */
332 W_REG(&pci
->sbtopci1
, SBTOPCI_CFG0
);
333 /* 1 GB memory access window */
334 W_REG(&pci
->sbtopci2
, SBTOPCI_MEM
| SB_PCI_DMA
);
336 /* Enable PCI bridge BAR0 prefetch and burst */
338 sbpci_write_config(sbh
, 1, 0, 0, PCI_CFG_CMD
, &val
, sizeof(val
));
340 /* Enable PCI interrupts */
341 W_REG(&pci
->intmask
, PCI_INTA
);
344 /* Scan the SB bus */
345 bzero(sb_config_regs
, sizeof(sb_config_regs
));
346 for (cfg
= sb_config_regs
; cfg
< &sb_config_regs
[SB_MAXCORES
]; cfg
++) {
347 cfg
->vendor
= 0xffff;
348 if (!(regs
= sb_setcoreidx(sbh
, cfg
- sb_config_regs
)))
350 sb
= (sbconfig_t
*)((ulong
) regs
+ SBCONFIGOFF
);
352 /* Read ID register and parse vendor and core */
353 val
= R_REG(&sb
->sbidhigh
);
354 vendor
= (val
& SBIDH_VC_MASK
) >> SBIDH_VC_SHIFT
;
355 core
= (val
& SBIDH_CC_MASK
) >> SBIDH_CC_SHIFT
;
358 /* Check if this core is banned */
359 for (i
= 0; i
< pci_banned
; i
++)
360 if (core
== pci_ban
[i
])
365 /* Known vendor translations */
368 vendor
= VENDOR_BROADCOM
;
372 /* Determine class based on known core codes */
375 class = PCI_CLASS_NET
;
376 subclass
= PCI_NET_ETHER
;
377 core
= BCM47XX_ILINE_ID
;
380 class = PCI_CLASS_NET
;
381 subclass
= PCI_NET_ETHER
;
382 core
= BCM4610_ILINE_ID
;
385 class = PCI_CLASS_NET
;
386 subclass
= PCI_NET_ETHER
;
387 core
= BCM47XX_ENET_ID
;
391 class = PCI_CLASS_MEMORY
;
392 subclass
= PCI_MEMORY_RAM
;
395 class = PCI_CLASS_BRIDGE
;
396 subclass
= PCI_BRIDGE_PCI
;
400 class = PCI_CLASS_CPU
;
401 subclass
= PCI_CPU_MIPS
;
404 class = PCI_CLASS_COMM
;
405 subclass
= PCI_COMM_MODEM
;
406 core
= BCM47XX_V90_ID
;
409 class = PCI_CLASS_SERIAL
;
410 subclass
= PCI_SERIAL_USB
;
411 progif
= 0x10; /* OHCI */
412 core
= BCM47XX_USB_ID
;
415 class = PCI_CLASS_SERIAL
;
416 subclass
= PCI_SERIAL_USB
;
417 progif
= 0x10; /* OHCI */
418 core
= BCM47XX_USBH_ID
;
421 class = PCI_CLASS_SERIAL
;
422 subclass
= PCI_SERIAL_USB
;
423 core
= BCM47XX_USBD_ID
;
426 class = PCI_CLASS_CRYPT
;
427 subclass
= PCI_CRYPT_NETWORK
;
428 core
= BCM47XX_IPSEC_ID
;
432 class = PCI_CLASS_MEMORY
;
433 subclass
= PCI_MEMORY_FLASH
;
436 class = PCI_CLASS_NET
;
437 subclass
= PCI_NET_OTHER
;
438 /* Let an nvram variable override this */
439 sprintf(varname
, "wl%did", wlidx
);
441 if ((core
= getintvar(NULL
, varname
)) == 0) {
442 if (chip
== BCM4712_DEVICE_ID
) {
443 if (chippkg
== BCM4712SMALL_PKG_ID
)
444 core
= BCM4306_D11G_ID
;
446 core
= BCM4306_D11DUAL_ID
;
449 core
= BCM4310_D11B_ID
;
455 class = subclass
= progif
= 0xff;
459 /* Supported translations */
460 cfg
->vendor
= htol16(vendor
);
461 cfg
->device
= htol16(core
);
462 cfg
->rev_id
= chiprev
;
463 cfg
->prog_if
= progif
;
464 cfg
->sub_class
= subclass
;
465 cfg
->base_class
= class;
466 cfg
->base
[0] = htol32(sb_base(R_REG(&sb
->sbadmatch0
)));
467 cfg
->base
[1] = htol32(sb_base(R_REG(&sb
->sbadmatch1
)));
468 cfg
->base
[2] = htol32(sb_base(R_REG(&sb
->sbadmatch2
)));
469 cfg
->base
[3] = htol32(sb_base(R_REG(&sb
->sbadmatch3
)));
472 if (class == PCI_CLASS_BRIDGE
&& subclass
== PCI_BRIDGE_PCI
)
473 cfg
->header_type
= PCI_HEADER_BRIDGE
;
475 cfg
->header_type
= PCI_HEADER_NORMAL
;
476 /* Save core interrupt flag */
477 cfg
->int_pin
= R_REG(&sb
->sbtpsflag
) & SBTPS_NUM0_MASK
;
478 /* Default to MIPS shared interrupt 0 */
480 /* MIPS sbipsflag maps core interrupt flags to interrupts 1 through 4 */
481 if ((regs
= sb_setcore(sbh
, SB_MIPS
, 0)) ||
482 (regs
= sb_setcore(sbh
, SB_MIPS33
, 0))) {
483 sb
= (sbconfig_t
*)((ulong
) regs
+ SBCONFIGOFF
);
484 val
= R_REG(&sb
->sbipsflag
);
485 for (cfg
->int_line
= 1; cfg
->int_line
<= 4; cfg
->int_line
++) {
486 if (((val
& sbips_int_mask
[cfg
->int_line
]) >> sbips_int_shift
[cfg
->int_line
]) == cfg
->int_pin
)
489 if (cfg
->int_line
> 4)
493 *((uint32
*) &cfg
->sprom_control
) = 0xffffffff;
496 sb_setcoreidx(sbh
, coreidx
);
501 sbpci_check(void *sbh
)
506 uint32 buf
[64], *ptr
, i
;
510 coreidx
= sb_coreidx(sbh
);
511 pci
= (sbpciregs_t
*) sb_setcore(sbh
, SB_PCI
, 0);
513 /* Clear the test array */
514 pa
= (ulong
) DMA_MAP(NULL
, buf
, sizeof(buf
), DMA_RX
, NULL
);
515 ptr
= (uint32
*) OSL_UNCACHED(&buf
[0]);
516 memset(ptr
, 0, sizeof(buf
));
518 /* Point PCI window 1 to memory */
519 sbtopci1
= R_REG(&pci
->sbtopci1
);
520 W_REG(&pci
->sbtopci1
, SBTOPCI_MEM
| (pa
& SBTOPCI1_MASK
));
522 /* Fill the test array via PCI window 1 */
523 ptr
= (uint32
*) REG_MAP(SB_PCI_CFG
+ (pa
& ~SBTOPCI1_MASK
), sizeof(buf
));
524 for (i
= 0; i
< ARRAYSIZE(buf
); i
++) {
525 for (j
= 0; j
< 2; j
++);
530 /* Restore PCI window 1 */
531 W_REG(&pci
->sbtopci1
, sbtopci1
);
533 /* Check the test array */
534 DMA_UNMAP(NULL
, pa
, sizeof(buf
), DMA_RX
, NULL
);
535 ptr
= (uint32
*) OSL_UNCACHED(&buf
[0]);
536 for (i
= 0; i
< ARRAYSIZE(buf
); i
++) {
541 /* Change the clock if the test fails */
542 if (i
< ARRAYSIZE(buf
)) {
546 printf("PCI: Test failed at %d MHz\n", (cur
+ 500000) / 1000000);
547 for (req
= 104000000; req
< 176000000; req
+= 4000000) {
548 printf("PCI: Resetting to %d MHz\n", (req
+ 500000) / 1000000);
549 /* This will only reset if the clocks are valid and have changed */
550 sb_mips_setclock(sbh
, req
, 0, 0);
552 /* Should not reach here */
556 sb_setcoreidx(sbh
, coreidx
);