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
;
248 //#define CT4712_WR 1 /* Workaround for 4712 */
251 sbpci_init(void *sbh
)
253 uint chip
, chiprev
, chippkg
, coreidx
, host
, i
;
257 pci_config_regs
*cfg
;
263 uint8
class, subclass
, progif
;
265 uint32 sbips_int_mask
[] = { 0, SBIPS_INT1_MASK
, SBIPS_INT2_MASK
, SBIPS_INT3_MASK
, SBIPS_INT4_MASK
};
266 uint32 sbips_int_shift
[] = { 0, 0, SBIPS_INT2_SHIFT
, SBIPS_INT3_SHIFT
, SBIPS_INT4_SHIFT
};
269 chiprev
= sb_chiprev(sbh
);
270 chippkg
= sb_chippkg(sbh
);
271 coreidx
= sb_coreidx(sbh
);
273 if (!(pci
= (sbpciregs_t
*) sb_setcore(sbh
, SB_PCI
, 0)))
275 sb_core_reset(sbh
, 0);
278 if(nvram_match("boardtype", "bcm94710dev") || nvram_match("boardtype", "bcm94710ap")|| nvram_match("boardtype", "bcm94710r4")|| nvram_match("boardtype", "bcm94710r4")|| nvram_match("boardtype", "bcm95365r"))
283 boardflags
= (uint32
) getintvar(NULL
, "boardflags");
285 if ((chip
== BCM4310_DEVICE_ID
) && (chiprev
== 0))
289 * The 200-pin BCM4712 package does not bond out PCI. Even when
290 * PCI is bonded out, some boards may leave the pins
293 if (((chip
== BCM4712_DEVICE_ID
) && (chippkg
== BCM4712SMALL_PKG_ID
)) ||
294 (boardflags
& BFL_NOPCI
) || CT4712_WR
)
298 * If the PCI core should not be touched (disabled, not bonded
299 * out, or pins floating), do not even attempt to access core
300 * registers. Otherwise, try to determine if it is in host
306 host
= !BUSPROBE(val
, &pci
->control
);
309 /* Disable PCI interrupts in client mode */
310 sb
= (sbconfig_t
*)((ulong
) pci
+ SBCONFIGOFF
);
311 W_REG(&sb
->sbintvec
, 0);
313 /* Disable the PCI bridge in client mode */
315 printf("PCI: Disabled\n");
317 /* Reset the external PCI bus and enable the clock */
318 W_REG(&pci
->control
, 0x5); /* enable the tristate drivers */
319 W_REG(&pci
->control
, 0xd); /* enable the PCI clock */
320 OSL_DELAY(150); /* delay > 100 us */
321 W_REG(&pci
->control
, 0xf); /* deassert PCI reset */
322 W_REG(&pci
->arbcontrol
, PCI_INT_ARB
); /* use internal arbiter */
323 OSL_DELAY(1); /* delay 1 us */
325 /* Enable CardBusMode */
326 cardbus
= nvram_match("cardbus", "1");
328 printf("PCI: Enabling CardBus\n");
329 /* GPIO 1 resets the CardBus device on bcm94710ap */
330 sb_gpioout(sbh
, 1, 1);
331 sb_gpioouten(sbh
, 1, 1);
332 W_REG(&pci
->sprom
[0], R_REG(&pci
->sprom
[0]) | 0x400);
335 /* 64 MB I/O access window */
336 W_REG(&pci
->sbtopci0
, SBTOPCI_IO
);
337 /* 64 MB configuration access window */
338 W_REG(&pci
->sbtopci1
, SBTOPCI_CFG0
);
339 /* 1 GB memory access window */
340 W_REG(&pci
->sbtopci2
, SBTOPCI_MEM
| SB_PCI_DMA
);
342 /* Enable PCI bridge BAR0 prefetch and burst */
344 sbpci_write_config(sbh
, 1, 0, 0, PCI_CFG_CMD
, &val
, sizeof(val
));
346 /* Enable PCI interrupts */
347 W_REG(&pci
->intmask
, PCI_INTA
);
350 /* Scan the SB bus */
351 bzero(sb_config_regs
, sizeof(sb_config_regs
));
352 for (cfg
= sb_config_regs
; cfg
< &sb_config_regs
[SB_MAXCORES
]; cfg
++) {
353 cfg
->vendor
= 0xffff;
354 if (!(regs
= sb_setcoreidx(sbh
, cfg
- sb_config_regs
)))
356 sb
= (sbconfig_t
*)((ulong
) regs
+ SBCONFIGOFF
);
358 /* Read ID register and parse vendor and core */
359 val
= R_REG(&sb
->sbidhigh
);
360 vendor
= (val
& SBIDH_VC_MASK
) >> SBIDH_VC_SHIFT
;
361 core
= (val
& SBIDH_CC_MASK
) >> SBIDH_CC_SHIFT
;
364 /* Check if this core is banned */
365 for (i
= 0; i
< pci_banned
; i
++)
366 if (core
== pci_ban
[i
])
371 /* Known vendor translations */
374 vendor
= VENDOR_BROADCOM
;
378 /* Determine class based on known core codes */
381 class = PCI_CLASS_NET
;
382 subclass
= PCI_NET_ETHER
;
383 core
= BCM47XX_ILINE_ID
;
386 class = PCI_CLASS_NET
;
387 subclass
= PCI_NET_ETHER
;
388 core
= BCM4610_ILINE_ID
;
391 class = PCI_CLASS_NET
;
392 subclass
= PCI_NET_ETHER
;
393 core
= BCM47XX_ENET_ID
;
397 class = PCI_CLASS_MEMORY
;
398 subclass
= PCI_MEMORY_RAM
;
401 class = PCI_CLASS_BRIDGE
;
402 subclass
= PCI_BRIDGE_PCI
;
406 class = PCI_CLASS_CPU
;
407 subclass
= PCI_CPU_MIPS
;
410 class = PCI_CLASS_COMM
;
411 subclass
= PCI_COMM_MODEM
;
412 core
= BCM47XX_V90_ID
;
415 class = PCI_CLASS_SERIAL
;
416 subclass
= PCI_SERIAL_USB
;
417 progif
= 0x10; /* OHCI */
418 core
= BCM47XX_USB_ID
;
421 class = PCI_CLASS_SERIAL
;
422 subclass
= PCI_SERIAL_USB
;
423 progif
= 0x10; /* OHCI */
424 core
= BCM47XX_USBH_ID
;
427 class = PCI_CLASS_SERIAL
;
428 subclass
= PCI_SERIAL_USB
;
429 core
= BCM47XX_USBD_ID
;
432 class = PCI_CLASS_CRYPT
;
433 subclass
= PCI_CRYPT_NETWORK
;
434 core
= BCM47XX_IPSEC_ID
;
438 class = PCI_CLASS_MEMORY
;
439 subclass
= PCI_MEMORY_FLASH
;
442 class = PCI_CLASS_NET
;
443 subclass
= PCI_NET_OTHER
;
444 /* Let an nvram variable override this */
445 sprintf(varname
, "wl%did", wlidx
);
447 if ((core
= getintvar(NULL
, varname
)) == 0) {
448 if (chip
== BCM4712_DEVICE_ID
) {
449 if (chippkg
== BCM4712SMALL_PKG_ID
)
450 core
= BCM4306_D11G_ID
;
452 core
= BCM4306_D11DUAL_ID
;
455 core
= BCM4310_D11B_ID
;
461 class = subclass
= progif
= 0xff;
465 /* Supported translations */
466 cfg
->vendor
= htol16(vendor
);
467 cfg
->device
= htol16(core
);
468 cfg
->rev_id
= chiprev
;
469 cfg
->prog_if
= progif
;
470 cfg
->sub_class
= subclass
;
471 cfg
->base_class
= class;
472 cfg
->base
[0] = htol32(sb_base(R_REG(&sb
->sbadmatch0
)));
473 cfg
->base
[1] = htol32(sb_base(R_REG(&sb
->sbadmatch1
)));
474 cfg
->base
[2] = htol32(sb_base(R_REG(&sb
->sbadmatch2
)));
475 cfg
->base
[3] = htol32(sb_base(R_REG(&sb
->sbadmatch3
)));
478 if (class == PCI_CLASS_BRIDGE
&& subclass
== PCI_BRIDGE_PCI
)
479 cfg
->header_type
= PCI_HEADER_BRIDGE
;
481 cfg
->header_type
= PCI_HEADER_NORMAL
;
482 /* Save core interrupt flag */
483 cfg
->int_pin
= R_REG(&sb
->sbtpsflag
) & SBTPS_NUM0_MASK
;
484 /* Default to MIPS shared interrupt 0 */
486 /* MIPS sbipsflag maps core interrupt flags to interrupts 1 through 4 */
487 if ((regs
= sb_setcore(sbh
, SB_MIPS
, 0)) ||
488 (regs
= sb_setcore(sbh
, SB_MIPS33
, 0))) {
489 sb
= (sbconfig_t
*)((ulong
) regs
+ SBCONFIGOFF
);
490 val
= R_REG(&sb
->sbipsflag
);
491 for (cfg
->int_line
= 1; cfg
->int_line
<= 4; cfg
->int_line
++) {
492 if (((val
& sbips_int_mask
[cfg
->int_line
]) >> sbips_int_shift
[cfg
->int_line
]) == cfg
->int_pin
)
495 if (cfg
->int_line
> 4)
499 *((uint32
*) &cfg
->sprom_control
) = 0xffffffff;
502 sb_setcoreidx(sbh
, coreidx
);
507 sbpci_check(void *sbh
)
512 uint32 buf
[64], *ptr
, i
;
516 coreidx
= sb_coreidx(sbh
);
517 pci
= (sbpciregs_t
*) sb_setcore(sbh
, SB_PCI
, 0);
519 /* Clear the test array */
520 pa
= (ulong
) DMA_MAP(NULL
, buf
, sizeof(buf
), DMA_RX
, NULL
);
521 ptr
= (uint32
*) OSL_UNCACHED(&buf
[0]);
522 memset(ptr
, 0, sizeof(buf
));
524 /* Point PCI window 1 to memory */
525 sbtopci1
= R_REG(&pci
->sbtopci1
);
526 W_REG(&pci
->sbtopci1
, SBTOPCI_MEM
| (pa
& SBTOPCI1_MASK
));
528 /* Fill the test array via PCI window 1 */
529 ptr
= (uint32
*) REG_MAP(SB_PCI_CFG
+ (pa
& ~SBTOPCI1_MASK
), sizeof(buf
));
530 for (i
= 0; i
< ARRAYSIZE(buf
); i
++) {
531 for (j
= 0; j
< 2; j
++);
536 /* Restore PCI window 1 */
537 W_REG(&pci
->sbtopci1
, sbtopci1
);
539 /* Check the test array */
540 DMA_UNMAP(NULL
, pa
, sizeof(buf
), DMA_RX
, NULL
);
541 ptr
= (uint32
*) OSL_UNCACHED(&buf
[0]);
542 for (i
= 0; i
< ARRAYSIZE(buf
); i
++) {
547 /* Change the clock if the test fails */
548 if (i
< ARRAYSIZE(buf
)) {
552 printf("PCI: Test failed at %d MHz\n", (cur
+ 500000) / 1000000);
553 for (req
= 104000000; req
< 176000000; req
+= 4000000) {
554 printf("PCI: Resetting to %d MHz\n", (req
+ 500000) / 1000000);
555 /* This will only reset if the clocks are valid and have changed */
556 sb_mips_setclock(sbh
, req
, 0, 0);
558 /* Should not reach here */
562 sb_setcoreidx(sbh
, coreidx
);