1 /* *********************************************************************
2 * Broadcom Common Firmware Environment (CFE)
4 * LDT Fabric Initialization File: ldtinit.c
6 *********************************************************************
8 * Copyright 2001,2002,2003
9 * Broadcom Corporation. All rights reserved.
11 * This software is furnished under license and may be used and
12 * copied only in accordance with the following terms and
13 * conditions. Subject to these conditions, you may download,
14 * copy, install, use, modify and distribute modified or unmodified
15 * copies of this software in source and/or binary form. No title
16 * or ownership is transferred hereby.
18 * 1) Any source code used, modified or distributed must reproduce
19 * and retain this copyright notice and list of conditions
20 * as they appear in the source file.
22 * 2) No right is granted to use any trade name, trademark, or
23 * logo of Broadcom Corporation. The "Broadcom Corporation"
24 * name may not be used to endorse or promote products derived
25 * from this software without the prior written permission of
26 * Broadcom Corporation.
28 * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
29 * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
30 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
31 * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
32 * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
33 * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
34 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
35 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
36 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
37 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
38 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
39 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
40 * THE POSSIBILITY OF SUCH DAMAGE.
41 ********************************************************************* */
44 * Broadcom Corporation. All rights reserved.
46 * This software is furnished under license and may be used and
47 * copied only in accordance with the following terms and
48 * conditions. Subject to these conditions, you may download,
49 * copy, install, use, modify and distribute modified or unmodified
50 * copies of this software in source and/or binary form. No title
51 * or ownership is transferred hereby.
53 * 1) Any source code used, modified or distributed must reproduce
54 * and retain this copyright notice and list of conditions as
55 * they appear in the source file.
57 * 2) No right is granted to use any trade name, trademark, or
58 * logo of Broadcom Corporation. Neither the "Broadcom
59 * Corporation" name nor any trademark or logo of Broadcom
60 * Corporation may be used to endorse or promote products
61 * derived from this software without the prior written
62 * permission of Broadcom Corporation.
64 * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
65 * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
66 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
67 * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
68 * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
69 * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
70 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
71 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
72 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
73 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
74 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
75 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
76 * THE POSSIBILITY OF SUCH DAMAGE.
80 * ldtinit.c: generic LDT fabric initialization and capability
84 #include "lib_types.h"
85 #include "lib_printf.h"
86 #include "cfe_timer.h"
92 /* Write-to-clear bit masks */
95 #define LDT_LINKCTRL_WC (LDT_LINKCTRL_CRCERROR_MASK)
97 #define LDT_LINKCTRL_WC (LDT_LINKCTRL_LINKFAIL | LDT_LINKCTRL_CRCERROR_MASK)
101 /* LDT capability lookup. */
104 pci_find_ldt_cap (pcitag_t tag
, int secondary
)
111 cpr
= pci_conf_read(tag
, PCI_CAPLISTPTR_REG
);
112 offset
= PCI_CAPLIST_PTR(cpr
) &~ 0x3;
115 while (offset
!= 0 && offset
!= prev
) {
117 pci_tagprintf(tag
, "read cap offset %04x\n", offset
);
119 cr
= pci_conf_read(tag
, offset
);
120 if (PCI_CAPLIST_CAP(cr
) == PCI_CAP_LDT
) {
121 type
= LDT_COMMAND_TYPE(cr
);
122 if (secondary
&& type
== LDT_COMMAND_TYPE_HOST
)
124 if (!secondary
&& type
== LDT_COMMAND_TYPE_SLAVE
)
128 offset
= PCI_CAPLIST_NEXT(cr
) &~ 0x3;
134 /* LDT utility functions, mostly for capabilities. */
137 ldt_get_link(pcitag_t tag
, int offset
, int index
)
139 return pci_conf_read(tag
, offset
+ LDT_LINK_OFF(index
));
143 ldt_set_link(pcitag_t tag
, int offset
, int index
, pcireg_t lr
)
145 pci_conf_write(tag
, offset
+ LDT_LINK_OFF(index
), lr
);
150 ldt_show_cap(pcitag_t tag
, int offset
, int secondary
)
152 printf(" Cmd %08x", pci_conf_read(tag
, offset
));
154 printf(" Lnk0 %08x", pci_conf_read(tag
, offset
));
157 printf(" Lnk1 %08x", pci_conf_read(tag
, offset
));
160 printf(" Freq0 %08x", pci_conf_read(tag
, offset
));
163 printf(" Freq1 %08x", pci_conf_read(tag
, offset
));
170 ldt_show_cap(pcitag_t tag
, int offset
, int secondary
)
176 /* LDT bus initialization and sizing. */
178 /* We expect the entire chain to be ready at approximately the same
179 time, but we add some delay here for possible node-to-node
182 Empirically, neither InitDone nor LinkFail is reported for an
183 unconnected link. Thus we do not expect the outgoing link of a
184 terminating tunnel node to become ready.
186 Also, CRC errors are observed to occur with InitDone, so link
187 errors do not necessarily force LinkFail.
191 ldt_wait_ready (pcitag_t tag
, int offset
, int index
)
198 count
= 0x10000; /* empirical */
202 lr
= ldt_get_link(tag
, offset
, index
);
203 if ((lr
& (LDT_LINKCTRL_LINKFAIL
| LDT_LINKCTRL_CRCERROR_MASK
)) != 0)
205 } while ((lr
& (LDT_LINKCTRL_INITDONE
| LDT_LINKCTRL_LINKFAIL
)) == 0);
211 ldt_end_chain (pcitag_t tag
, int offset
, int index
)
215 lr
= ldt_get_link(tag
, offset
, index
);
216 lr
|= LDT_LINKCTRL_EOC
;
217 ldt_set_link(tag
, offset
, index
, lr
);
218 lr
|= LDT_LINKCTRL_TXOFF
;
219 ldt_set_link(tag
, offset
, index
, lr
);
220 t
= ldt_get_link(tag
, offset
, index
); /* push */
225 ldt_freq_cap (pcitag_t tag
, int offset
, int index
)
230 cmd
= pci_conf_read(tag
, offset
+ LDT_COMMAND_CAP_OFF
);
231 if (LDT_COMMAND_TYPE(cmd
) == LDT_COMMAND_TYPE_HOST
) {
232 cr
= pci_conf_read(tag
, offset
+ LDT_FREQ_OFF
);
233 if (LDT_REVISION_ID(cr
) == LDT_REV_017
) {
234 /* REV 0.17 has restricted support for setting
235 frequencies. We assume that this is the host bridge in
236 pseudo-1.0x mode, in which case the desired maximum
237 frequency was left in the LDT_FREQ register and all
238 lower frequencies are supported. */
239 freq_cap
= (1 << (LDT_LINKFREQ(cr
) + 1)) - 1;
241 freq_cap
= LDT_LINKFREQ_CAP(cr
);
244 cr
= pci_conf_read(tag
, offset
+ LDT_FREQ0_OFF
);
245 if (LDT_REVISION_ID(cr
) == LDT_REV_017
) {
246 freq_cap
= (1 << LDT_FREQ_200
);
248 cr
= pci_conf_read(tag
, offset
+ LDT_FREQn_OFF(index
));
249 freq_cap
= LDT_LINKFREQ_CAP(cr
);
256 ldt_max_freq (uint16_t freq_cap
)
260 /* 200 MHz (encoded as 1 << 0) is required for all devices */
261 freq_cap
|= (1 << LDT_FREQ_200
);
265 while (freq_cap
!= 1) {
270 return (ldt_freq
>= LDT_FREQ_200
&& ldt_freq
<= LDT_FREQ_1000
) ?
271 ldt_freq
: LDT_FREQ_200
;
275 ldt_set_freq (pcitag_t tag
, int offset
, int index
, uint8_t freq
)
279 cmd
= pci_conf_read(tag
, offset
+ LDT_COMMAND_CAP_OFF
);
280 if (LDT_COMMAND_TYPE(cmd
) == LDT_COMMAND_TYPE_HOST
) {
281 cr
= pci_conf_read(tag
, offset
+ LDT_FREQ_OFF
);
282 cr
&=~ LDT_LINKFREQ_MASK
;
283 cr
|= (freq
<< LDT_LINKFREQ_SHIFT
);
284 pci_conf_write(tag
, offset
+ LDT_FREQ_OFF
, cr
);
286 cr
= pci_conf_read(tag
, offset
+ LDT_FREQn_OFF(index
));
287 cr
&=~ LDT_LINKFREQ_MASK
;
288 cr
|= (freq
<< LDT_LINKFREQ_SHIFT
);
289 pci_conf_write(tag
, offset
+ LDT_FREQn_OFF(index
), cr
);
292 pci_tagprintf(tag
, "set link %d freq = %02x\n", index
, freq
);
297 /* LDT fabric initialization. See LDT Spec, Section 13.3. */
299 ldt_fabric_init (pcitag_t br_tag
, int br_offset
,
300 int port
, int bus
, pci_flags_t flags
)
303 pcitag_t prev_tag
, tag
;
304 int offset
, prev_offset
;
307 pcireg_t cmd
, lr
, id
, t
;
311 prev_tag
= br_tag
; prev_offset
= br_offset
; prev_link
= 0;
312 /* Since there is no direct peer-to-peer traffic, there is no
313 point in configuring a downstream link with more capability
314 than the current one. */
315 prev_cap
= ldt_freq_cap(br_tag
, br_offset
, 0);
321 printf("Link sizing for bus %d, bridge freq cap %04x\n",
322 bus
, ldt_freq_cap(br_tag
, br_offset
, 0));
326 tag
= pci_make_tag(port
, bus
, 0, 0);
328 id
= pci_conf_read(tag
, PCI_ID_REG
);
330 pci_tagprintf(tag
, "ldt_fabric_init: id register %08x\n", id
);
332 if (PCI_VENDOR(id
) == 0xffff) {
333 /* The incoming link had InitDone set, but we got an NXA
334 trying to read the vendor id. Either the reverse link
335 is broken or we have found an LDT-Lite node. For now,
336 assume the latter. Since an LDT-Lite device cannot be
337 a tunnel, assume the chain terminates here. */
338 pci_tagprintf(tag
, "assumed LDT-LITE device (virtual unit %d)\n",
343 offset
= pci_find_ldt_cap(tag
, LDT_PRIMARY
);
345 pci_tagprintf(tag
, "ldt_fabric_init: offset %08x\n", offset
);
348 /* There is no primary interface; we must have found a host. */
349 offset
= pci_find_ldt_cap(tag
, LDT_SECONDARY
);
351 lr
= pci_conf_read(tag
, offset
+ LDT_COMMAND_CAP_OFF
);
352 lr
|= LDT_COMMAND_DOUBLE_ENDED
;
353 pci_conf_write(tag
, offset
+ LDT_COMMAND_CAP_OFF
, lr
);
359 /* Otherwise, we have the primary interface. */
361 /* Rewrite the old value to set master host bit. */
362 cmd
= pci_conf_read(tag
, offset
+ LDT_COMMAND_CAP_OFF
);
364 pci_tagprintf(tag
, "ldt_fabric_init: set master host\n");
366 pci_conf_write(tag
, offset
+ LDT_COMMAND_CAP_OFF
, cmd
);
367 cmd
= pci_conf_read(tag
, offset
+ LDT_COMMAND_CAP_OFF
); /* push */
369 id
= pci_conf_read(tag
, PCI_ID_REG
);
371 /* Update the unit id, gingerly. */
372 cmd
&= ~LDT_COMMAND_UNIT_ID_MASK
;
373 cmd
|= (next_free_id
<< LDT_COMMAND_UNIT_ID_SHIFT
);
375 pci_tagprintf(tag
, "ldt_fabric_init: set unit id %d\n", next_free_id
);
377 if (!pci_conf_write_acked(tag
, offset
+ LDT_COMMAND_CAP_OFF
, cmd
)) {
378 pci_tagprintf(tag
, "no ack of id update to %d\n", next_free_id
);
381 /* The unit id just changed. Update the tag */
382 tag
= pci_make_tag(port
, bus
, next_free_id
, 0);
384 pci_tagprintf(tag
, "ldt_fabric_init: check unit id\n");
386 t
= pci_conf_read(tag
, PCI_ID_REG
);
388 pci_tagprintf(tag
, "id mismatch: old %08x, new %08x\n", id
, t
);
391 next_free_id
+= LDT_COMMAND_UNIT_COUNT(cmd
);
393 link
= LDT_COMMAND_MASTER_HOST(cmd
); /* Upstream link index */
395 /* LDT Rev 0.17 does not support frequency updates. */
396 if ((flags
& PCI_FLG_LDT_REV_017
) == 0) {
397 /* Find common frequency for upstream link. */
398 uint16_t link_cap
, freq_cap_in
, freq_cap_out
;
401 freq_cap_out
= ldt_freq_cap(prev_tag
, prev_offset
, prev_link
);
402 freq_cap_in
= ldt_freq_cap(tag
, offset
, link
);
403 link_cap
= freq_cap_in
& freq_cap_out
;
404 ldt_freq
= ldt_max_freq(link_cap
& prev_cap
);
407 pci_tagprintf(tag
, "set freq %d\n", ldt_freq
);
409 /* Set up frequency registers, next warm reset installs. */
410 ldt_set_freq(prev_tag
, prev_offset
, prev_link
, ldt_freq
);
411 ldt_set_freq(tag
, offset
, link
, ldt_freq
);
413 prev_cap
&= link_cap
;
416 link
^= 1; /* Downstream */
417 linkerr
= ldt_wait_ready(tag
, offset
, link
);
418 lr
= ldt_get_link(tag
, offset
, link
);
419 ldt_set_link(tag
, offset
, link
, lr
| LDT_LINKCTRL_WC
);
422 pci_tagprintf(tag
, "node: up %d down %d:\n", link
^ 1, link
);
424 ldt_show_cap(tag
, offset
, LDT_PRIMARY
);
426 if (linkerr
|| next_free_id
> 0x1f) {
427 /* No downstream link or too many devices, set end of chain */
428 ldt_end_chain(tag
, offset
, link
);
432 prev_tag
= tag
; prev_offset
= offset
; prev_link
= link
;
440 ldt_fabric_reinit (int port
, int bus
)
446 pcireg_t cmd
, lr
, id
, t
;
452 printf("Link resizing for bus %d\n", bus
);
456 tag
= pci_make_tag(port
, bus
, 0, 0);
458 id
= pci_conf_read(tag
, PCI_ID_REG
);
459 if (PCI_VENDOR(id
) == 0xffff) {
460 /* Per the init pass, assume this indicates a link to an
461 LDT-Lite node, and the chain terminates here. */
465 offset
= pci_find_ldt_cap(tag
, LDT_PRIMARY
);
467 /* There is no primary interface; we must have found a host. */
468 offset
= pci_find_ldt_cap(tag
, LDT_SECONDARY
);
470 lr
= pci_conf_read(tag
, offset
+ LDT_COMMAND_CAP_OFF
);
471 lr
|= LDT_COMMAND_DOUBLE_ENDED
;
472 pci_conf_write(tag
, offset
+ LDT_COMMAND_CAP_OFF
, lr
);
477 /* Otherwise, we have the primary interface. */
479 /* Rewrite the old value to set master host bit. */
480 cmd
= pci_conf_read(tag
, offset
+ LDT_COMMAND_CAP_OFF
);
481 pci_conf_write(tag
, offset
+ LDT_COMMAND_CAP_OFF
, cmd
);
482 cmd
= pci_conf_read(tag
, offset
+ LDT_COMMAND_CAP_OFF
);
484 id
= pci_conf_read(tag
, PCI_ID_REG
);
486 /* (Re)update the unit id. See above. */
487 cmd
&= ~LDT_COMMAND_UNIT_ID_MASK
;
488 cmd
|= (next_free_id
<< LDT_COMMAND_UNIT_ID_SHIFT
);
489 if (!pci_conf_write_acked(tag
, offset
+ LDT_COMMAND_CAP_OFF
, cmd
)) {
490 pci_tagprintf(tag
, "no ack of id update to %d\n", next_free_id
);
493 /* The unit id just changed. Update the tag */
494 tag
= pci_make_tag(port
, bus
, next_free_id
, 0);
495 t
= pci_conf_read(tag
, PCI_ID_REG
); /* for good measure */
497 pci_tagprintf(tag
, "id mismatch: old %08x, new %08x\n", id
, t
);
500 next_free_id
+= LDT_COMMAND_UNIT_COUNT(cmd
);
502 link
= LDT_COMMAND_MASTER_HOST(cmd
); /* Upstream link index */
503 link
^= 1; /* Downstream */
505 linkerr
= ldt_wait_ready(tag
, offset
, link
);
507 lr
= ldt_get_link(tag
, offset
, link
);
508 ldt_set_link(tag
, offset
, link
, lr
| LDT_LINKCTRL_WC
);
510 pci_tagprintf(tag
, "node: up %d down %d:\n", link
^ 1, link
);
511 ldt_show_cap(tag
, offset
, LDT_PRIMARY
);
513 if (linkerr
|| next_free_id
> 0x1f) {
514 /* No downstream link or too many devices, set end of chain */
515 ldt_end_chain(tag
, offset
, link
);
519 return next_free_id
- 1;
523 /* LDT link reset (warm or cold as set by caller) */
526 ldt_link_reset (pcitag_t tag
, int delay
)
530 /* This code may be necessary for LDT buses behind bridges (none
531 of which yet exist) but seems to be a bad idea for the SB-1250
532 LDT bus in pass 1 parts. Note that if we do reset, we must
533 delay to give any attached devices a chance to (re)initialize
536 /* Attempt a Secondary Bus Reset. */
537 brctl
= pci_conf_read(tag
, PPB_BRCTL_INTERRUPT_REG
);
538 brctl
|= PPB_BRCTL_SECONDARY_RESET
;
539 pci_conf_write(tag
, PPB_BRCTL_INTERRUPT_REG
, brctl
);
541 brctl
= pci_conf_read(tag
, PPB_BRCTL_INTERRUPT_REG
);
542 if ((brctl
& PPB_BRCTL_SECONDARY_RESET
) != 0) {
544 /* Bit can be written, assume soft reset is implemented. */
545 brctl
&=~ PPB_BRCTL_SECONDARY_RESET
;
546 pci_conf_write(tag
, PPB_BRCTL_INTERRUPT_REG
, brctl
);
548 /* Add some delay (duration is a guess) */
549 for (i
= 0; i
< delay
; i
++)
550 (void)pci_conf_read(tag
, PPB_BRCTL_INTERRUPT_REG
);
551 /* Alternatively, wait for LinkFail or InitDone. */
556 /* LDT bridge and fabric initialization for a secondary chain */
559 ldt_chain_init (pcitag_t tag
, int port
, int bus
, pci_flags_t flags
)
568 /* To avoid a chip erratum, we must prevent Type 0 configuration
569 probes that get NXAs on a double hosted chain. */
572 offset
= pci_find_ldt_cap(tag
, LDT_SECONDARY
);
574 linkerr
= ldt_wait_ready(tag
, offset
, 0);
577 pci_tagprintf(tag
, "bridge secondary:\n");
578 ldt_show_cap(tag
, offset
, LDT_SECONDARY
);
581 pci_tagprintf(tag
, "secondary bad or never ready\n");
583 lr
= ldt_get_link(tag
, offset
, 0);
584 if ((lr
& LDT_LINKCTRL_INITDONE
) != 0)
585 double_ended
= ldt_fabric_init(tag
, offset
, port
, bus
, flags
);
587 ldt_end_chain(tag
, offset
, 0);
590 cr
= pci_conf_read(tag
, offset
+ LDT_COMMAND_CAP_OFF
);
592 cr
|= LDT_COMMAND_DOUBLE_ENDED
;
594 cr
&=~ LDT_COMMAND_DOUBLE_ENDED
;
595 pci_conf_write(tag
, offset
+ LDT_COMMAND_CAP_OFF
, cr
);
597 /* Rev 0.17 does not support dynamic link resizing. */
598 if ((flags
& PCI_FLG_LDT_REV_017
) == 0) {
599 /* Issue a warm reset to update link frequencies. */
600 cr
= pci_conf_read(tag
, offset
+ LDT_COMMAND_CAP_OFF
);
601 cr
|= LDT_COMMAND_WARM_RESET
;
602 pci_conf_write(tag
, offset
+ LDT_COMMAND_CAP_OFF
, cr
);
603 cr
= pci_conf_read(tag
, offset
+ LDT_COMMAND_CAP_OFF
);
604 ldt_link_reset(tag
, 100);
605 ldt_wait_ready(tag
, offset
, 0);
608 pci_tagprintf(tag
, "bridge secondary:\n");
609 ldt_show_cap(tag
, offset
, LDT_SECONDARY
);
611 /* After reset, let secondary devices reinitialize. */
614 ndev
= ldt_fabric_reinit(port
, bus
);
617 cr
= pci_conf_read(tag
, offset
+ LDT_COMMAND_CAP_OFF
);
618 cr
|= LDT_COMMAND_DOUBLE_ENDED
;
619 pci_conf_write(tag
, offset
+ LDT_COMMAND_CAP_OFF
, cr
);