2 * This file is part of the coreboot project.
4 * Copyright (C) 2007 Advanced Micro Devices, Inc.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 /*----------------------------------------------------------------------------
24 *----------------------------------------------------------------------------
28 #define FILECODE 0xF002
35 /*----------------------------------------------------------------------------
36 * DEFINITIONS AND MACROS
38 *----------------------------------------------------------------------------
41 /* CPU Northbridge Functions */
42 #define CPU_HTNB_FUNC_00 0
43 #define CPU_HTNB_FUNC_04 4
44 #define CPU_ADDR_FUNC_01 1
45 #define CPU_NB_FUNC_03 3
47 /* Function 0 registers */
48 #define REG_ROUTE0_0X40 0x40
49 #define REG_ROUTE1_0X44 0x44
50 #define REG_NODE_ID_0X60 0x60
51 #define REG_UNIT_ID_0X64 0x64
52 #define REG_LINK_TRANS_CONTROL_0X68 0x68
53 #define REG_LINK_INIT_CONTROL_0X6C 0x6C
54 #define REG_HT_CAP_BASE_0X80 0x80
55 #define REG_HT_LINK_RETRY0_0X130 0x130
56 #define REG_HT_TRAFFIC_DIST_0X164 0x164
57 #define REG_HT_LINK_EXT_CONTROL0_0X170 0x170
59 #define HT_CONTROL_CLEAR_CRC (~(3 << 8))
61 /* Function 1 registers */
62 #define REG_ADDR_CONFIG_MAP0_1XE0 0xE0
63 #define CPU_ADDR_NUM_CONFIG_MAPS 4
65 /* Function 3 registers */
66 #define REG_NB_SRI_XBAR_BUF_3X70 0x70
67 #define REG_NB_MCT_XBAR_BUF_3X78 0x78
68 #define REG_NB_FIFOPTR_3XDC 0xDC
69 #define REG_NB_CAPABILITY_3XE8 0xE8
70 #define REG_NB_CPUID_3XFC 0xFC
71 #define REG_NB_LINK_XCS_TOKEN0_3X148 0x148
72 #define REG_NB_DOWNCORE_3X190 0x190
74 /* Function 4 registers */
77 /*----------------------------------------------------------------------------
78 * TYPEDEFS AND STRUCTURES
80 *----------------------------------------------------------------------------
82 /*----------------------------------------------------------------------------
83 * PROTOTYPES OF LOCAL FUNCTIONS
85 *----------------------------------------------------------------------------
88 /***************************************************************************
89 *** FAMILY/NORTHBRIDGE SPECIFIC FUNCTIONS ***
90 ***************************************************************************/
92 /**----------------------------------------------------------------------------------------
95 * makeLinkBase(u8 currentNode, u8 currentLink)
98 * Private to northbridge implementation. Return the HT Host capability base
99 * PCI config address for a link.
102 * @param[in] u8 node = the node this link is on
103 * @param[in] u8 link = the link
104 * @param[out] SBDFO result = the pci config address
106 * ---------------------------------------------------------------------------------------
108 static SBDFO makeLinkBase(u8 node, u8 link)
112 /* With rev F can not be called with a 4th link or with the sublinks */
114 linkBase = MAKE_SBDFO(makePCISegmentFromNode(node),
115 makePCIBusFromNode(node),
116 makePCIDeviceFromNode(node),
118 REG_HT_CAP_BASE_0X80 + link*HT_HOST_CAP_SIZE);
120 linkBase = MAKE_SBDFO(makePCISegmentFromNode(node),
121 makePCIBusFromNode(node),
122 makePCIDeviceFromNode(node),
124 REG_HT_CAP_BASE_0X80 + (link-4)*HT_HOST_CAP_SIZE);
128 /**----------------------------------------------------------------------------------------
131 * setHtControlRegisterBits(SBDFO reg, u8 hiBit, u8 loBit, u32 *pValue)
134 * Private to northbridge implementation. Provide a common routine for accessing the
135 * HT Link Control registers (84, a4, c4, e4), to enforce not clearing the
136 * HT CRC error bits. Replaces direct use of AmdPCIWriteBits().
137 * NOTE: This routine is called for IO Devices as well as CPUs!
140 * @param[in] SBDFO reg = the PCI config address the control register
141 * @param[in] u8 hiBit = the high bit number
142 * @param[in] u8 loBit = the low bit number
143 * @param[in] u8 pValue = the value to write to that bit range. Bit 0 => loBit.
145 * ---------------------------------------------------------------------------------------
147 static void setHtControlRegisterBits(SBDFO reg, u8 hiBit, u8 loBit, u32 *pValue)
151 ASSERT((hiBit < 32) && (loBit < 32) && (hiBit >= loBit) && ((reg & 0x3) == 0));
152 ASSERT((hiBit < 8) || (loBit > 9));
154 /* A 1<<32 == 1<<0 due to x86 SHL instruction, so skip if that is the case */
155 if ((hiBit-loBit) != 31)
156 mask = (((u32)1 << (hiBit-loBit+1))-1);
158 mask = (u32)0xFFFFFFFF;
160 AmdPCIRead(reg, &temp);
161 temp &= ~(mask << loBit);
162 temp |= (*pValue & mask) << loBit;
163 temp &= (u32)HT_CONTROL_CLEAR_CRC;
164 AmdPCIWrite(reg, &temp);
167 /**----------------------------------------------------------------------------------------
170 * writeRoutingTable(u8 node, u8 target, u8 Link, cNorthBridge *nb)
173 * This routine will modify the routing tables on the
174 * SourceNode to cause it to route both request and response traffic to the
175 * targetNode through the specified Link.
177 * NOTE: This routine is to be used for early discovery and initialization. The
178 * final routing tables must be loaded some other way because this
179 * routine does not address the issue of probes, or independent request
183 * @param[in] u8 node = the node that will have it's routing tables modified.
184 * @param[in] u8 target = For routing to node target
185 * @param[in] u8 Link = Link from node to target
186 * @param[in] cNorthBridge *nb = this northbridge
188 * ---------------------------------------------------------------------------------------
191 static void writeRoutingTable(u8 node, u8 target, u8 link, cNorthBridge *nb)
193 #ifndef HT_BUILD_NC_ONLY
194 u32 temp = (nb->selfRouteResponseMask | nb->selfRouteRequestMask) << (link + 1);
195 ASSERT((node < nb->maxNodes) && (target < nb->maxNodes) && (link < nb->maxLinks));
196 AmdPCIWrite(MAKE_SBDFO(makePCISegmentFromNode(node),
197 makePCIBusFromNode(node),
198 makePCIDeviceFromNode(node),
200 REG_ROUTE0_0X40 + target*4),
207 /**----------------------------------------------------------------------------------------
210 * writeNodeID(u8 node, u8 nodeID, cNorthBridge *nb)
213 * Modifies the NodeID register on the target node
216 * @param[in] u8 node = the node that will have its NodeID altered.
217 * @param[in] u8 nodeID = the new value for NodeID
218 * @param[in] cNorthBridge *nb = this northbridge
220 * ---------------------------------------------------------------------------------------
223 static void writeNodeID(u8 node, u8 nodeID, cNorthBridge *nb)
226 ASSERT((node < nb->maxNodes) && (nodeID < nb->maxNodes));
227 AmdPCIWriteBits(MAKE_SBDFO(makePCISegmentFromNode(node),
228 makePCIBusFromNode(node),
229 makePCIDeviceFromNode(node),
235 /**----------------------------------------------------------------------------------------
238 * readDefLnk(u8 node, cNorthBridge *nb)
241 * Read the DefLnk (the source link of the current packet)
245 * @param[in] u8 node = the node that will have its NodeID altered.
246 * @param[in] cNorthBridge *nb = this northbridge
247 * @param[out] u8 result = The HyperTransport link where the request to
248 * read the default link came from. Since this
249 * code is running on the BSP, this should be the link
250 * pointing back towards the BSP.
252 * ---------------------------------------------------------------------------------------
255 static u8 readDefLnk(u8 node, cNorthBridge *nb)
261 licr = MAKE_SBDFO(makePCISegmentFromNode(node),
262 makePCIBusFromNode(node),
263 makePCIDeviceFromNode(node),
265 REG_LINK_INIT_CONTROL_0X6C);
267 ASSERT((node < nb->maxNodes));
268 AmdPCIReadBits(licr, 3, 2, &deflink);
269 AmdPCIReadBits(licr, 8, 8, &temp); /* on rev F, this bit is reserved == 0 */
270 deflink |= temp << 2;
274 /**----------------------------------------------------------------------------------------
277 * enableRoutingTables(u8 node, cNorthBridge *nb)
280 * Turns routing tables on for a given node
283 * @param[in] u8 node = the node that will have it's routing tables enabled
284 * @param[in] cNorthBridge *nb = this northbridge
286 * ---------------------------------------------------------------------------------------
289 static void enableRoutingTables(u8 node, cNorthBridge *nb)
292 ASSERT((node < nb->maxNodes));
293 AmdPCIWriteBits(MAKE_SBDFO(makePCISegmentFromNode(node),
294 makePCIBusFromNode(node),
295 makePCIDeviceFromNode(node),
297 REG_LINK_INIT_CONTROL_0X6C),
302 /**----------------------------------------------------------------------------------------
305 * verifyLinkIsCoherent(u8 node, u8 Link, cNorthBridge *nbk)
308 * Verify that the link is coherent, connected, and ready
311 * @param[in] u8 node = the node that will be examined
312 * @param[in] u8 link = the link on that Node to examine
313 * @param[in] cNorthBridge *nb = this northbridge
314 * @param[out] u8 result = true - The link has the following status
315 * linkCon=1, Link is connected
316 * InitComplete=1, Link initialization is complete
317 * NC=0, Link is coherent
318 * UniP-cLDT=0, Link is not Uniprocessor cLDT
319 * LinkConPend=0 Link connection is not pending
320 * false- The link has some other status
322 * ---------------------------------------------------------------------------------------
325 static BOOL verifyLinkIsCoherent(u8 node, u8 link, cNorthBridge *nb)
327 #ifndef HT_BUILD_NC_ONLY
332 ASSERT((node < nb->maxNodes) && (link < nb->maxLinks));
334 linkBase = makeLinkBase(node, link);
336 /* FN0_98/A4/C4 = LDT Type Register */
337 AmdPCIRead(linkBase + HTHOST_LINK_TYPE_REG, &linkType);
339 /* Verify LinkCon=1, InitComplete=1, NC=0, UniP-cLDT=0, LinkConPend=0 */
340 return (linkType & HTHOST_TYPE_MASK) == HTHOST_TYPE_COHERENT;
343 #endif /* HT_BUILD_NC_ONLY */
346 /**----------------------------------------------------------------------------------------
349 * readTrueLinkFailStatus(u8 node, u8 link, sMainData *pDat, cNorthBridge *nb)
352 * Return the LinkFailed status AFTER an attempt is made to clear the bit.
353 * Also, call event notify if a Hardware Fault caused a synch flood on a previous boot.
355 * The table below summarizes correct responses of this routine.
356 * Family before after unconnected Notify? return
365 * @param[in] u8 node = the node that will be examined
366 * @param[in] u8 link = the link on that node to examine
367 * @param[in] u8 sMainData = access to call back routine
368 * @param[in] cNorthBridge *nb = this northbridge
369 * @param[out] u8 result = true - the link is not connected or has hard error
370 * false- if the link is connected
372 * ---------------------------------------------------------------------------------------
374 static BOOL readTrueLinkFailStatus(u8 node, u8 link, sMainData *pDat, cNorthBridge *nb)
376 u32 before, after, unconnected, crc;
379 ASSERT((node < nb->maxNodes) && (link < nb->maxLinks));
381 linkBase = makeLinkBase(node, link);
383 /* Save the CRC status before doing anything else.
384 * Read, Clear, the Re-read the error bits in the Link Control Register
385 * FN0_84/A4/C4[4] = LinkFail bit
386 * and the connection status, TransOff and EndOfChain
388 AmdPCIReadBits(linkBase + HTHOST_LINK_CONTROL_REG, 9, 8, &crc);
389 AmdPCIReadBits(linkBase + HTHOST_LINK_CONTROL_REG, 4, 4, &before);
390 setHtControlRegisterBits(linkBase + HTHOST_LINK_CONTROL_REG, 4, 4, &before);
391 AmdPCIReadBits(linkBase + HTHOST_LINK_CONTROL_REG, 4, 4, &after);
392 AmdPCIReadBits(linkBase + HTHOST_LINK_CONTROL_REG, 7, 6, &unconnected);
400 /* A synch flood occurred due to HT CRC */
401 if (pDat->HtBlock->AMD_CB_EventNotify)
403 /* Pass the node and link on which the generic synch flood event occurred. */
405 evt.eSize = sizeof(sHtEventHWHtCrc);
408 evt.laneMask = (uint8)crc;
410 pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_HW_FAULT,
417 /* Some synch flood occurred */
418 if (pDat->HtBlock->AMD_CB_EventNotify)
420 /* Pass the node and link on which the generic synch flood event occurred. */
421 sHtEventHWSynchFlood evt;
422 evt.eSize = sizeof(sHtEventHWSynchFlood);
426 pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_HW_FAULT,
427 HT_EVENT_HW_SYNCHFLOOD,
433 return ((after != 0) || unconnected);
437 /**----------------------------------------------------------------------------------------
440 * readToken(u8 node, cNorthBridge *nb)
443 * Read the token stored in the scratchpad register
444 * NOTE: The location used to store the token is arbitrary. The only
445 * requirement is that the location warm resets to zero, and that
446 * using it will have no ill-effects during HyperTransport initialization.
449 * @param[in] u8 node = the node that will be examined
450 * @param[in] cNorthBridge *nb = this northbridge
451 * @param[out] u8 result = the Token read from the node
453 * ---------------------------------------------------------------------------------------
455 static u8 readToken(u8 node, cNorthBridge *nb)
459 ASSERT((node < nb->maxNodes));
460 /* Use CpuCnt as a scratch register */
461 /* Limiting use to 4 bits makes code GH to rev F compatible. */
462 AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(node),
463 makePCIBusFromNode(node),
464 makePCIDeviceFromNode(node),
473 /**----------------------------------------------------------------------------------------
476 * writeToken(u8 node, u8 Value, cNorthBridge *nb)
479 * Write the token stored in the scratchpad register
480 * NOTE: The location used to store the token is arbitrary. The only
481 * requirement is that the location warm resets to zero, and that
482 * using it will have no ill-effects during HyperTransport initialization.
483 * Limiting use to 4 bits makes code GH to rev F compatible.
486 * @param[in] u8 node = the node that will be examined
487 * @param[in] cNorthBridge *nb = this northbridge
489 * ---------------------------------------------------------------------------------------
491 static void writeToken(u8 node, u8 value, cNorthBridge *nb)
494 ASSERT((node < nb->maxNodes));
495 /* Use CpuCnt as a scratch register */
496 /* Limiting use to 4 bits makes code GH to rev F compatible. */
497 AmdPCIWriteBits(MAKE_SBDFO(makePCISegmentFromNode(node),
498 makePCIBusFromNode(node),
499 makePCIDeviceFromNode(node),
505 /**----------------------------------------------------------------------------------------
508 * fam0FGetNumCoresOnNode(u8 node, cNorthBridge *nb)
511 * Return the number of cores (1 based count) on node.
514 * @param[in] u8 node = the node that will be examined
515 * @param[in] cNorthBridge *nb = this northbridge
516 * @param[out] u8 result = the number of cores
518 * ---------------------------------------------------------------------------------------
520 static u8 fam0FGetNumCoresOnNode(u8 node, cNorthBridge *nb)
524 ASSERT((node < nb->maxNodes));
526 AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(node),
527 makePCIBusFromNode(node),
528 makePCIDeviceFromNode(node),
530 REG_NB_CAPABILITY_3XE8),
537 /**----------------------------------------------------------------------------------------
540 * fam10GetNumCoresOnNode(u8 node, cNorthBridge *nb)
543 * Return the number of cores (1 based count) on node.
546 * @param[in] u8 node = the node that will be examined
547 * @param[in] cNorthBridge *nb = this northbridge
548 * @param[out] u8 result = the number of cores
550 * ---------------------------------------------------------------------------------------
552 static u8 fam10GetNumCoresOnNode(u8 node, cNorthBridge *nb)
554 u32 temp, leveling, cores;
557 ASSERT((node < nb->maxNodes));
558 /* Read CmpCap [2][1:0] */
559 AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(node),
560 makePCIBusFromNode(node),
561 makePCIDeviceFromNode(node),
563 REG_NB_CAPABILITY_3XE8),
566 /* bits[15,13,12] specify the cores */
567 /* Support Downcoring */
568 temp = ((temp & 8) >> 1) + (temp & 3);
570 AmdPCIReadBits (MAKE_SBDFO(makePCISegmentFromNode(node),
571 makePCIBusFromNode(node),
572 makePCIDeviceFromNode(node),
574 REG_NB_DOWNCORE_3X190),
576 for (i=0; i<cores; i++)
578 if (leveling & ((u32) 1 << i))
586 /**----------------------------------------------------------------------------------------
589 * setTotalNodesAndCores(u8 node, u8 totalNodes, u8 totalCores, cNorthBridge *nb)
592 * Write the total number of cores and nodes to the node
595 * @param[in] u8 node = the node that will be examined
596 * @param[in] u8 totalNodes = the total number of nodes
597 * @param[in] u8 totalCores = the total number of cores
598 * @param[in] cNorthBridge *nb = this northbridge
600 * ---------------------------------------------------------------------------------------
602 static void setTotalNodesAndCores(u8 node, u8 totalNodes, u8 totalCores, cNorthBridge *nb)
607 ASSERT((node < nb->maxNodes) && (totalNodes <= nb->maxNodes));
608 nodeIDReg = MAKE_SBDFO(makePCISegmentFromNode(node),
609 makePCIBusFromNode(node),
610 makePCIDeviceFromNode(node),
615 /* Rely on max number of nodes:cores for rev F and GH to make
616 * this code work, even though we write reserved bit 20 on rev F it will be
619 AmdPCIWriteBits(nodeIDReg, 20, 16, &temp);
621 AmdPCIWriteBits(nodeIDReg, 6, 4, &temp);
624 /**----------------------------------------------------------------------------------------
627 * limitNodes(u8 node, cNorthBridge *nb)
630 * Limit coherent config accesses to cpus as indicated by nodecnt.
633 * @param[in] u8 node = the node that will be examined
634 * @param[in] cNorthBridge *nb = this northbridge
636 * ---------------------------------------------------------------------------------------
638 static void limitNodes(u8 node, cNorthBridge *nb)
641 ASSERT((node < nb->maxNodes));
642 AmdPCIWriteBits(MAKE_SBDFO(makePCISegmentFromNode(node),
643 makePCIBusFromNode(node),
644 makePCIDeviceFromNode(node),
646 REG_LINK_TRANS_CONTROL_0X68),
650 /**----------------------------------------------------------------------------------------
653 * writeFullRoutingTable(u8 node, u8 target, u8 reqLink, u8 rspLink, u32 BClinks, cNorthBridge *nb)
656 * Write the routing table entry for node to target, using the request link, response
657 * link, and broadcast links provided.
660 * @param[in] u8 node = the node that will be examined
661 * @param[in] u8 target = the target node for these routes
662 * @param[in] u8 reqLink = the link for requests to target
663 * @param[in] u8 rspLink = the link for responses to target
664 * @param[in] u32 bClinks = the broadcast links
665 * @param[in] cNorthBridge *nb = this northbridge
667 * ---------------------------------------------------------------------------------------
669 static void writeFullRoutingTable(u8 node, u8 target, u8 reqLink, u8 rspLink, u32 bClinks, cNorthBridge *nb)
671 #ifndef HT_BUILD_NC_ONLY
674 ASSERT((node < nb->maxNodes) && (target < nb->maxNodes));
675 if (reqLink == ROUTETOSELF)
676 value |= nb->selfRouteRequestMask;
678 value |= nb->selfRouteRequestMask << (reqLink+1);
680 if (rspLink == ROUTETOSELF)
681 value |= nb->selfRouteResponseMask;
683 value |= nb->selfRouteResponseMask << (rspLink+1);
685 /* Allow us to accept a Broadcast ourselves, then set broadcasts for routes */
686 value |= (u32)1 << nb->broadcastSelfBit;
687 value |= (u32)bClinks << (nb->broadcastSelfBit + 1);
689 AmdPCIWrite(MAKE_SBDFO(makePCISegmentFromNode(node),
690 makePCIBusFromNode(node),
691 makePCIDeviceFromNode(node),
693 REG_ROUTE0_0X40 + target*4), &value);
696 #endif /* HT_BUILD_NC_ONLY */
699 /**----------------------------------------------------------------------------------------
702 * makeKey(u8 currentNode)
705 * Private routine to northbridge code.
706 * Determine whether a node is compatible with the discovered configuration so
707 * far. Currently, that means the family, extended family of the new node are the
711 * @param[in] u8 node = the node
712 * @param[out] u32 result = the key value
714 * ---------------------------------------------------------------------------------------
716 static u32 makeKey(u8 node)
719 AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(node),
720 makePCIBusFromNode(node),
721 makePCIDeviceFromNode(node),
725 AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(node),
726 makePCIBusFromNode(node),
727 makePCIDeviceFromNode(node),
731 return ((u32)(baseFam << 8) | extFam);
735 /**----------------------------------------------------------------------------------------
738 * isCompatible(u8 currentNode, cNorthBridge *nb)
741 * Determine whether a node is compatible with the discovered configuration so
742 * far. Currently, that means the family, extended family of the new node are the
746 * @param[in] u8 node = the node
747 * @param[in] cNorthBridge *nb = this northbridge
748 * @param[out] BOOL result = true: the new is compatible, false: it is not
750 * ---------------------------------------------------------------------------------------
752 static BOOL isCompatible(u8 node, cNorthBridge *nb)
754 return (makeKey(node) == nb->compatibleKey);
757 /**----------------------------------------------------------------------------------------
760 * fam0fIsCapable(u8 node, sMainData *pDat, cNorthBridge *nb)
763 * Get node capability and update the minimum supported system capability.
764 * Return whether the current configuration exceeds the capability.
767 * @param[in] u8 node = the node
768 * @param[in,out] sMainData *pDat = sysMpCap (updated) and NodesDiscovered
769 * @param[in] cNorthBridge *nb = this northbridge
770 * @param[out] BOOL result = true: system is capable of current config.
771 * false: system is not capable of current config.
773 * ---------------------------------------------------------------------------------------
775 static BOOL fam0fIsCapable(u8 node, sMainData *pDat, cNorthBridge *nb)
777 #ifndef HT_BUILD_NC_ONLY
781 ASSERT(node < nb->maxNodes);
783 AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(node),
784 makePCIBusFromNode(node),
785 makePCIDeviceFromNode(node),
787 REG_NB_CAPABILITY_3XE8),
800 if (pDat->sysMpCap > maxNodes)
802 pDat->sysMpCap = maxNodes;
804 /* Note since sysMpCap is one based and NodesDiscovered is zero based, equal is false */
805 return (pDat->sysMpCap > pDat->NodesDiscovered);
811 /**----------------------------------------------------------------------------------------
814 * fam10IsCapable(u8 node, sMainData *pDat, cNorthBridge *nb)
817 * Get node capability and update the minimum supported system capability.
818 * Return whether the current configuration exceeds the capability.
821 * @param[in] u8 node = the node
822 * @param[in,out] sMainData *pDat = sysMpCap (updated) and NodesDiscovered
823 * @param[in] cNorthBridge *nb = this northbridge
824 * @param[out] BOOL result = true: system is capable of current config.
825 * false: system is not capable of current config.
827 * ---------------------------------------------------------------------------------------
829 static BOOL fam10IsCapable(u8 node, sMainData *pDat, cNorthBridge *nb)
831 #ifndef HT_BUILD_NC_ONLY
835 ASSERT(node < nb->maxNodes);
837 AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(node),
838 makePCIBusFromNode(node),
839 makePCIDeviceFromNode(node),
841 REG_NB_CAPABILITY_3XE8),
846 maxNodes = (1 << (~temp & 0x3)); /* That is, 1, 2, 4, or 8 */
853 if (pDat->sysMpCap > maxNodes)
855 pDat->sysMpCap = maxNodes;
857 /* Note since sysMpCap is one based and NodesDiscovered is zero based, equal is false */
858 return (pDat->sysMpCap > pDat->NodesDiscovered);
864 /**----------------------------------------------------------------------------------------
867 * fam0fStopLink(u8 currentNode, u8 currentLink, cNorthBridge *nb)
870 * Disable a cHT link on node by setting F0x[E4, C4, A4, 84][TransOff, EndOfChain]=1
873 * @param[in] u8 node = the node this link is on
874 * @param[in] u8 link = the link to stop
875 * @param[in] cNorthBridge *nb = this northbridge
877 * ---------------------------------------------------------------------------------------
879 static void fam0fStopLink(u8 node, u8 link, cNorthBridge *nb)
881 #ifndef HT_BUILD_NC_ONLY
885 ASSERT((node < nb->maxNodes) && (link < nb->maxLinks));
887 linkBase = makeLinkBase(node, link);
889 /* Set TransOff, EndOfChain */
891 setHtControlRegisterBits(linkBase + HTHOST_LINK_CONTROL_REG, 7, 6, &temp);
895 /**----------------------------------------------------------------------------------------
906 * ---------------------------------------------------------------------------------------
908 static void commonVoid(void)
912 /**----------------------------------------------------------------------------------------
915 * commonReturnFalse()
921 * @param[out] BOOL result = false
922 * ---------------------------------------------------------------------------------------
924 static BOOL commonReturnFalse(void)
929 /***************************************************************************
930 *** Non-coherent init code ***
931 *** Northbridge access routines ***
932 ***************************************************************************/
934 /**----------------------------------------------------------------------------------------
937 * readSbLink(cNorthBridge *nb)
940 * Return the link to the Southbridge
943 * @param[in] cNorthBridge *nb = this northbridge
944 * @param[out] u8 results = the link to the southbridge
946 * ---------------------------------------------------------------------------------------
948 static u8 readSbLink(cNorthBridge *nb)
951 AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(0),
952 makePCIBusFromNode(0),
953 makePCIDeviceFromNode(0),
960 /**----------------------------------------------------------------------------------------
963 * verifyLinkIsNonCoherent(u8 node, u8 link, cNorthBridge *nb)
966 * Verify that the link is non-coherent, connected, and ready
969 * @param[in] u8 node = the node that will be examined
970 * @param[in] u8 link = the Link on that node to examine
971 * @param[in] cNorthBridge *nb = this northbridge
972 * @param[out] u8 results = true - The link has the following status
973 * LinkCon=1, Link is connected
974 * InitComplete=1,Link initilization is complete
975 * NC=1, Link is coherent
976 * UniP-cLDT=0, Link is not Uniprocessor cLDT
977 * LinkConPend=0 Link connection is not pending
978 * false- The link has some other status
980 * ---------------------------------------------------------------------------------------
982 static BOOL verifyLinkIsNonCoherent(u8 node, u8 link, cNorthBridge *nb)
987 ASSERT((node < nb->maxNodes) && (link < nb->maxLinks));
989 linkBase = makeLinkBase(node, link);
991 /* FN0_98/A4/C4 = LDT Type Register */
992 AmdPCIRead(linkBase + HTHOST_LINK_TYPE_REG, &linkType);
994 /* Verify linkCon=1, InitComplete=1, NC=0, UniP-cLDT=0, LinkConPend=0 */
995 return (linkType & HTHOST_TYPE_MASK) == HTHOST_TYPE_NONCOHERENT;
998 /**----------------------------------------------------------------------------------------
1001 * ht3SetCFGAddrMap(u8 cfgMapIndex, u8 secBus, u8 subBus, u8 targetNode, u8 targetLink, sMainData *pDat, cNorthBridge *nb)
1004 * Configure and enable config access to a non-coherent chain for the given bus range.
1007 * @param[in] u8 cfgRouteIndex = the map entry to set
1008 * @param[in] u8 secBus = The secondary bus number to use
1009 * @param[in] u8 subBus = The subordinate bus number to use
1010 * @param[in] u8 targetNode = The node that shall be the recipient of the traffic
1011 * @param[in] u8 targetLink = The link that shall be the recipient of the traffic
1012 * @param[in] sMainData* pDat = our global state
1013 * @param[in] cNorthBridge *nb = this northbridge
1015 * ---------------------------------------------------------------------------------------
1017 static void ht3SetCFGAddrMap(u8 cfgMapIndex, u8 secBus, u8 subBus, u8 targetNode, u8 targetLink, sMainData *pDat, cNorthBridge *nb)
1023 linkBase = makeLinkBase(targetNode, targetLink);
1025 ASSERT(secBus <= subBus);
1027 AmdPCIWriteBits(linkBase + HTHOST_ISOC_REG, 15, 8, &temp);
1029 /* For target link, note that rev F uses bits 9:8 and only with GH is bit 10
1030 * set to indicate a sublink. For node, we are currently not supporting Extended
1033 temp = ((u32)subBus << 24) + ((u32)secBus << 16) + ((u32)targetLink << 8)
1034 + ((u32)targetNode << 4) + (u32)3;
1035 for (curNode = 0; curNode < pDat->NodesDiscovered+1; curNode++)
1036 AmdPCIWrite(MAKE_SBDFO(makePCISegmentFromNode(curNode),
1037 makePCIBusFromNode(curNode),
1038 makePCIDeviceFromNode(curNode),
1040 REG_ADDR_CONFIG_MAP0_1XE0 + 4*cfgMapIndex),
1044 /**----------------------------------------------------------------------------------------
1047 * ht1SetCFGAddrMap(u8 cfgMapIndex, u8 secBus, u8 subBus, u8 targetNode, u8 targetLink, sMainData *pDat, cNorthBridge *nb)
1050 * Configure and enable config access to a non-coherent chain for the given bus range.
1053 * @param[in] u8 cfgMapIndex = the map entry to set
1054 * @param[in] u8 secBus = The secondary bus number to use
1055 * @param[in] u8 subBus = The subordinate bus number to use
1056 * @param[in] u8 targetNode = The node that shall be the recipient of the traffic
1057 * @param[in] u8 targetLink = The link that shall be the recipient of the traffic
1058 * @param[in] sMainData* pDat = our global state
1059 * @param[in] cNorthBridge *nb = this northbridge
1061 * ---------------------------------------------------------------------------------------
1063 static void ht1SetCFGAddrMap(u8 cfgMapIndex, u8 secBus, u8 subBus, u8 targetNode, u8 targetLink, sMainData *pDat, cNorthBridge *nb)
1069 linkBase = makeLinkBase(targetNode, targetLink);
1071 ASSERT(secBus <= subBus);
1073 AmdPCIWriteBits(linkBase + HTHOST_ISOC_REG, 15, 8, &temp);
1076 AmdPCIWriteBits(linkBase + HTHOST_ISOC_REG, 23, 16, &temp);
1078 /* For target link, note that rev F uses bits 9:8 and only with GH is bit 10
1079 * set to indicate a sublink. For node, we are currently not supporting Extended
1082 temp = ((u32)subBus << 24) + ((u32)secBus << 16) + ((u32)targetLink << 8)
1083 + ((u32)targetNode << 4) + (u32)3;
1084 for (curNode = 0; curNode < pDat->NodesDiscovered+1; curNode++)
1085 AmdPCIWrite(MAKE_SBDFO(makePCISegmentFromNode(curNode),
1086 makePCIBusFromNode(curNode),
1087 makePCIDeviceFromNode(curNode),
1089 REG_ADDR_CONFIG_MAP0_1XE0 + 4*cfgMapIndex),
1093 /***************************************************************************
1094 *** Link Optimization ***
1095 ***************************************************************************/
1097 /**----------------------------------------------------------------------------------------
1100 * convertBitsToWidth(u8 value, cNorthBridge *nb)
1103 * Given the bits set in the register field, return the width it represents
1106 * @param[in] u8 value = The bits for the register
1107 * @param[in] cNorthBridge *nb = this northbridge
1108 * @param[out] u8 results = The width
1110 * ---------------------------------------------------------------------------------------
1112 static u8 convertBitsToWidth(u8 value, cNorthBridge *nb)
1119 default: STOP_HERE; /* This is an error internal condition */
1121 return 0; // shut up GCC.
1124 /**----------------------------------------------------------------------------------------
1127 * convertWidthToBits(u8 value, cNorthBridge *nb)
1130 * Translate a desired width setting to the bits to set in the register field
1133 * @param[in] u8 value = The width
1134 * @param[in] cNorthBridge *nb = this northbridge
1135 * @param[out] u8 results = The bits for the register
1137 * ---------------------------------------------------------------------------------------
1139 static u8 convertWidthToBits(u8 value, cNorthBridge *nb)
1146 default: STOP_HERE; /* This is an internal error condition */
1148 return 0; // shut up GCC
1151 /**----------------------------------------------------------------------------------------
1154 * ht1NorthBridgeFreqMask(u8 NodeID, cNorthBridge *nb)
1157 * Return a mask that eliminates HT frequencies that cannot be used due to a slow
1158 * northbridge frequency.
1161 * @param[in] u8 node = Result could (later) be for a specific node
1162 * @param[in] cNorthBridge *nb = this northbridge
1163 * @param[out] u16 results = Frequency mask
1165 * ---------------------------------------------------------------------------------------
1167 static u16 ht1NorthBridgeFreqMask(u8 node, cNorthBridge *nb)
1169 /* only up to HT1 speeds */
1170 return (HT_FREQUENCY_LIMIT_HT1_ONLY);
1173 /**----------------------------------------------------------------------------------------
1176 * fam10NorthBridgeFreqMask(u8 NodeID, cNorthBridge *nb)
1179 * Return a mask that eliminates HT frequencies that cannot be used due to a slow
1180 * northbridge frequency.
1183 * @param[in] u8 node = Result could (later) be for a specific node
1184 * @param[in] cNorthBridge *nb = this northbridge
1185 * @param[out] u16 results = Frequency mask
1187 * ---------------------------------------------------------------------------------------
1189 static u16 fam10NorthBridgeFreqMask(u8 node, cNorthBridge *nb)
1194 nbCOF = getMinNbCOF();
1196 * nbCOF is minimum northbridge speed in hundreds of MHz.
1197 * HT can not go faster than the minimum speed of the northbridge.
1199 if ((nbCOF >= 6) && (nbCOF <= 26))
1201 /* Convert frequency to bit and all less significant bits,
1202 * by setting next power of 2 and subtracting 1.
1204 supported = ((u16)1 << ((nbCOF >> 1) + 2)) - 1;
1206 else if (nbCOF > 26)
1208 supported = HT_FREQUENCY_LIMIT_2600M;
1210 /* unlikely cases, but include as a defensive measure, also avoid trick above */
1211 else if (nbCOF == 4)
1213 supported = HT_FREQUENCY_LIMIT_400M;
1215 else if (nbCOF == 2)
1217 supported = HT_FREQUENCY_LIMIT_200M;
1222 supported = HT_FREQUENCY_LIMIT_200M;
1225 return (fixEarlySampleFreqCapability(supported));
1228 /**----------------------------------------------------------------------------------------
1231 * gatherLinkData(sMainData *pDat, cNorthBridge *nb)
1234 * For all discovered links, populate the port list with the frequency and width
1238 * @param[in,out] sMainData* pDat = our global state, port list
1239 * @param[in] cNorthBridge *nb = this northbridge
1241 * ---------------------------------------------------------------------------------------
1243 static void gatherLinkData(sMainData *pDat, cNorthBridge *nb)
1249 for (i = 0; i < pDat->TotalLinks*2; i++)
1251 if (pDat->PortList[i].Type == PORTLIST_TYPE_CPU)
1253 linkBase = makeLinkBase(pDat->PortList[i].NodeID, pDat->PortList[i].Link);
1255 pDat->PortList[i].Pointer = linkBase;
1257 AmdPCIReadBits(linkBase + HTHOST_LINK_CONTROL_REG, 22, 20, &temp);
1258 pDat->PortList[i].PrvWidthOutCap = convertBitsToWidth((u8)temp, pDat->nb);
1260 AmdPCIReadBits(linkBase + HTHOST_LINK_CONTROL_REG, 18, 16, &temp);
1261 pDat->PortList[i].PrvWidthInCap = convertBitsToWidth((u8)temp, pDat->nb);
1263 AmdPCIReadBits(linkBase + HTHOST_FREQ_REV_REG, 31, 16, &temp);
1264 pDat->PortList[i].PrvFrequencyCap = (u16)temp & 0x7FFF
1265 & nb->northBridgeFreqMask(pDat->PortList[i].NodeID, pDat->nb); /* Mask off bit 15, reserved value */
1269 linkBase = pDat->PortList[i].Pointer;
1270 if (pDat->PortList[i].Link == 1)
1271 linkBase += HTSLAVE_LINK01_OFFSET;
1273 AmdPCIReadBits(linkBase + HTSLAVE_LINK_CONTROL_0_REG, 22, 20, &temp);
1274 pDat->PortList[i].PrvWidthOutCap = convertBitsToWidth((u8)temp, pDat->nb);
1276 AmdPCIReadBits(linkBase + HTSLAVE_LINK_CONTROL_0_REG, 18, 16, &temp);
1277 pDat->PortList[i].PrvWidthInCap = convertBitsToWidth((u8)temp, pDat->nb);
1279 AmdPCIReadBits(linkBase + HTSLAVE_FREQ_REV_0_REG, 31, 16, &temp);
1280 pDat->PortList[i].PrvFrequencyCap = (u16)temp;
1282 if (pDat->HtBlock->AMD_CB_DeviceCapOverride)
1284 linkBase &= 0xFFFFF000;
1285 AmdPCIRead(linkBase, &temp);
1287 pDat->HtBlock->AMD_CB_DeviceCapOverride(
1288 pDat->PortList[i].NodeID,
1289 pDat->PortList[i].HostLink,
1290 pDat->PortList[i].HostDepth,
1291 (u8)SBDFO_SEG(pDat->PortList[i].Pointer),
1292 (u8)SBDFO_BUS(pDat->PortList[i].Pointer),
1293 (u8)SBDFO_DEV(pDat->PortList[i].Pointer),
1295 pDat->PortList[i].Link,
1296 &(pDat->PortList[i].PrvWidthInCap),
1297 &(pDat->PortList[i].PrvWidthOutCap),
1298 &(pDat->PortList[i].PrvFrequencyCap));
1304 /**----------------------------------------------------------------------------------------
1307 * setLinkData(sMainData *pDat, cNorthBridge *nb)
1310 * Change the hardware state for all links according to the now optimized data in the
1311 * port list data structure.
1314 * @param[in] sMainData* pDat = our global state, port list
1315 * @param[in] cNorthBridge *nb = this northbridge
1317 * ---------------------------------------------------------------------------------------
1319 static void setLinkData(sMainData *pDat, cNorthBridge *nb)
1323 u32 temp, widthin, widthout, bits;
1325 for (i = 0; i < pDat->TotalLinks*2; i++)
1328 ASSERT(pDat->PortList[i&0xFE].SelWidthOut == pDat->PortList[(i&0xFE)+1].SelWidthIn);
1329 ASSERT(pDat->PortList[i&0xFE].SelWidthIn == pDat->PortList[(i&0xFE)+1].SelWidthOut);
1330 ASSERT(pDat->PortList[i&0xFE].SelFrequency == pDat->PortList[(i&0xFE)+1].SelFrequency);
1332 if (pDat->PortList[i].SelRegang)
1334 ASSERT(pDat->PortList[i].Type == PORTLIST_TYPE_CPU);
1335 ASSERT(pDat->PortList[i].Link < 4);
1337 AmdPCIWriteBits(MAKE_SBDFO(makePCISegmentFromNode(pDat->PortList[i].NodeID),
1338 makePCIBusFromNode(pDat->PortList[i].NodeID),
1339 makePCIDeviceFromNode(pDat->PortList[i].NodeID),
1341 REG_HT_LINK_EXT_CONTROL0_0X170 + 4*pDat->PortList[i].Link),
1345 if (pDat->PortList[i].Type == PORTLIST_TYPE_CPU)
1347 if (pDat->HtBlock->AMD_CB_OverrideCpuPort)
1348 pDat->HtBlock->AMD_CB_OverrideCpuPort(pDat->PortList[i].NodeID,
1349 pDat->PortList[i].Link,
1350 &(pDat->PortList[i].SelWidthIn),
1351 &(pDat->PortList[i].SelWidthOut),
1352 &(pDat->PortList[i].SelFrequency));
1356 if (pDat->HtBlock->AMD_CB_OverrideDevicePort)
1357 pDat->HtBlock->AMD_CB_OverrideDevicePort(pDat->PortList[i].NodeID,
1358 pDat->PortList[i].HostLink,
1359 pDat->PortList[i].HostDepth,
1360 pDat->PortList[i].Link,
1361 &(pDat->PortList[i].SelWidthIn),
1362 &(pDat->PortList[i].SelWidthOut),
1363 &(pDat->PortList[i].SelFrequency));
1366 linkBase = pDat->PortList[i].Pointer;
1367 if ((pDat->PortList[i].Type == PORTLIST_TYPE_IO) && (pDat->PortList[i].Link == 1))
1368 linkBase += HTSLAVE_LINK01_OFFSET;
1370 /* Some IO devices don't work properly when setting widths, so write them in a single operation,
1371 * rather than individually.
1373 widthout = convertWidthToBits(pDat->PortList[i].SelWidthOut, pDat->nb);
1374 ASSERT(widthout == 1 || widthout == 0 || widthout == 5 || widthout == 4);
1375 widthin = convertWidthToBits(pDat->PortList[i].SelWidthIn, pDat->nb);
1376 ASSERT(widthin == 1 || widthin == 0 || widthin == 5 || widthin == 4);
1378 temp = (widthin & 7) | ((widthout & 7) << 4);
1379 setHtControlRegisterBits(linkBase + HTHOST_LINK_CONTROL_REG, 31, 24, &temp);
1381 temp = pDat->PortList[i].SelFrequency;
1382 if (pDat->PortList[i].Type == PORTLIST_TYPE_CPU)
1384 ASSERT((temp >= HT_FREQUENCY_600M && temp <= HT_FREQUENCY_2600M)
1385 || (temp == HT_FREQUENCY_200M) || (temp == HT_FREQUENCY_400M));
1386 AmdPCIWriteBits(linkBase + HTHOST_FREQ_REV_REG, 11, 8, &temp);
1387 if (temp > HT_FREQUENCY_1000M) /* Gen1 = 200Mhz -> 1000MHz, Gen3 = 1200MHz -> 2600MHz */
1389 /* Enable for Gen3 frequencies */
1394 /* Disable for Gen1 frequencies */
1397 /* HT3 retry mode enable / disable */
1398 AmdPCIWriteBits(MAKE_SBDFO(makePCISegmentFromNode(pDat->PortList[i].NodeID),
1399 makePCIBusFromNode(pDat->PortList[i].NodeID),
1400 makePCIDeviceFromNode(pDat->PortList[i].NodeID),
1402 REG_HT_LINK_RETRY0_0X130 + 4*pDat->PortList[i].Link),
1404 /* and Scrambling enable / disable */
1405 AmdPCIWriteBits(MAKE_SBDFO(makePCISegmentFromNode(pDat->PortList[i].NodeID),
1406 makePCIBusFromNode(pDat->PortList[i].NodeID),
1407 makePCIDeviceFromNode(pDat->PortList[i].NodeID),
1409 REG_HT_LINK_EXT_CONTROL0_0X170 + 4*pDat->PortList[i].Link),
1417 ASSERT(temp <= HT_FREQUENCY_2600M);
1418 /* Write the frequency setting */
1419 AmdPCIWriteBits(linkBase + HTSLAVE_FREQ_REV_0_REG, 11, 8, &temp);
1421 /* Handle additional HT3 frequency requirements, if needed,
1422 * or clear them if switching down to ht1 on a warm reset.
1423 * Gen1 = 200Mhz -> 1000MHz, Gen3 = 1200MHz -> 2600MHz
1425 * Even though we assert if debugging, we need to check that the capability was found
1426 * always, since this is an unknown hardware device, also we are taking
1427 * unqualified frequency from the call backs
1428 * (could be trying to do ht3 on an ht1 IO device).
1431 if (temp > HT_FREQUENCY_1000M)
1433 /* Enabling features if gen 3 */
1438 /* Disabling features if gen 1 */
1444 currentPtr = linkBase & (u32)0xFFFFF000; /* Set PCI Offset to 0 */
1447 AmdPCIFindNextCap(¤tPtr);
1448 if (currentPtr != ILLEGAL_SBDFO)
1450 AmdPCIRead(currentPtr, &temp);
1451 /* HyperTransport Retry Capability? */
1452 if (IS_HT_RETRY_CAPABILITY(temp))
1454 ASSERT(pDat->PortList[i].Link < 2);
1455 AmdPCIWriteBits(currentPtr + HTRETRY_CONTROL_REG,
1456 pDat->PortList[i].Link*16,
1457 pDat->PortList[i].Link*16,
1461 /* Some other capability, keep looking */
1465 /* If we are turning it off, that may mean the device was only ht1 capable,
1466 * so don't complain that we can't do it.
1470 if (pDat->HtBlock->AMD_CB_EventNotify)
1472 sHtEventOptRequiredCap evt;
1473 evt.eSize = sizeof(sHtEventOptRequiredCap);
1474 evt.node = pDat->PortList[i].NodeID;
1475 evt.link = pDat->PortList[i].HostLink;
1476 evt.depth = pDat->PortList[i].HostDepth;
1478 pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_WARNING,
1479 HT_EVENT_OPT_REQUIRED_CAP_RETRY,
1488 /* Scrambling enable */
1490 currentPtr = linkBase & (u32)0xFFFFF000; /* Set PCI Offset to 0 */
1493 AmdPCIFindNextCap(¤tPtr);
1494 if (currentPtr != ILLEGAL_SBDFO)
1496 AmdPCIRead(currentPtr, &temp);
1497 /* HyperTransport Gen3 Capability? */
1498 if (IS_HT_GEN3_CAPABILITY(temp))
1500 ASSERT(pDat->PortList[i].Link < 2);
1501 AmdPCIWriteBits((currentPtr +
1502 HTGEN3_LINK_TRAINING_0_REG +
1503 pDat->PortList[i].Link*HTGEN3_LINK01_OFFSET),
1507 /* Some other capability, keep looking */
1511 /* If we are turning it off, that may mean the device was only ht1 capable,
1512 * so don't complain that we can't do it.
1516 if (pDat->HtBlock->AMD_CB_EventNotify)
1518 sHtEventOptRequiredCap evt;
1519 evt.eSize = sizeof(sHtEventOptRequiredCap);
1520 evt.node = pDat->PortList[i].NodeID;
1521 evt.link = pDat->PortList[i].HostLink;
1522 evt.depth = pDat->PortList[i].HostDepth;
1524 pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_WARNING,
1525 HT_EVENT_OPT_REQUIRED_CAP_GEN3,
1537 /**----------------------------------------------------------------------------------------
1540 * fam0fWriteHTLinkCmdBufferAlloc(u8 node, u8 link, u8 req, u8 preq, u8 rsp, u8 prb)
1543 * Set the command buffer allocations in the buffer count register for the node and link.
1544 * The command buffer settings in the low 16 bits are the same on both
1545 * family 10h and family 0fh northbridges.
1548 * @param[in] u8 node = The node to set allocations on
1549 * @param[in] u8 link = the link to set allocations on
1550 * @param[in] u8 req = non-posted Request Command Buffers
1551 * @param[in] u8 preq = Posted Request Command Buffers
1552 * @param[in] u8 rsp = Response Command Buffers
1553 * @param[in] u8 prb = Probe Command Buffers
1555 * ---------------------------------------------------------------------------------------
1557 #ifndef HT_BUILD_NC_ONLY
1559 static void fam0fWriteHTLinkCmdBufferAlloc(u8 node, u8 link, u8 req, u8 preq, u8 rsp, u8 prb)
1564 currentPtr = makeLinkBase(node, link);
1565 currentPtr += HTHOST_BUFFER_COUNT_REG;
1567 /* non-posted Request Command Buffers */
1569 AmdPCIWriteBits(currentPtr, 3, 0, &temp);
1570 /* Posted Request Command Buffers */
1572 AmdPCIWriteBits(currentPtr, 7, 4, &temp);
1573 /* Response Command Buffers */
1575 AmdPCIWriteBits(currentPtr, 11, 8, &temp);
1576 /* Probe Command Buffers */
1578 AmdPCIWriteBits(currentPtr, 15, 12, &temp);
1580 #endif /* HT_BUILD_NC_ONLY */
1582 /**----------------------------------------------------------------------------------------
1585 * fam0fWriteHTLinkDatBufferAlloc(u8 node, u8 link, u8 reqD, u8 preqD, u8 rspD)
1588 * Set the data buffer allocations in the buffer count register for the node and link.
1589 * The command buffer settings in the high 16 bits are not the same on both
1590 * family 10h and family 0fh northbridges.
1593 * @param[in] u8 node = The node to set allocations on
1594 * @param[in] u8 link = the link to set allocations on
1595 * @param[in] u8 reqD = non-posted Request Data Buffers
1596 * @param[in] u8 preqD = Posted Request Data Buffers
1597 * @param[in] u8 rspD = Response Data Buffers
1599 * ---------------------------------------------------------------------------------------
1601 #ifndef HT_BUILD_NC_ONLY
1603 static void fam0fWriteHTLinkDatBufferAlloc(u8 node, u8 link, u8 reqD, u8 preqD, u8 rspD)
1608 currentPtr = makeLinkBase(node, link);
1609 currentPtr += HTHOST_BUFFER_COUNT_REG;
1611 /* Request Data Buffers */
1613 AmdPCIWriteBits(currentPtr, 18, 16, &temp);
1614 /* Posted Request Data Buffers */
1616 AmdPCIWriteBits(currentPtr, 22, 20, &temp);
1617 /* Response Data Buffers */
1619 AmdPCIWriteBits(currentPtr, 26, 24, &temp);
1621 #endif /* HT_BUILD_NC_ONLY */
1623 /**----------------------------------------------------------------------------------------
1626 * ht3WriteTrafficDistribution(u32 links01, u32 links10, cNorthBridge *nb)
1629 * Set the traffic distribution register for the links provided.
1632 * @param[in] u32 links01 = coherent links from node 0 to 1
1633 * @param[in] u32 links10 = coherent links from node 1 to 0
1634 * @param[in] cNorthBridge* nb = this northbridge
1636 * ---------------------------------------------------------------------------------------
1638 static void ht3WriteTrafficDistribution(u32 links01, u32 links10, cNorthBridge *nb)
1640 #ifndef HT_BUILD_NC_ONLY
1645 AmdPCIWriteBits(MAKE_SBDFO(makePCISegmentFromNode(0),
1646 makePCIBusFromNode(0),
1647 makePCIDeviceFromNode(0),
1649 REG_HT_TRAFFIC_DIST_0X164),
1651 /* DstNode = 1, cHTPrbDistEn=1, cHTRspDistEn=1, cHTReqDistEn=1 */
1653 AmdPCIWriteBits(MAKE_SBDFO(makePCISegmentFromNode(0),
1654 makePCIBusFromNode(0),
1655 makePCIDeviceFromNode(0),
1657 REG_HT_TRAFFIC_DIST_0X164),
1662 AmdPCIWriteBits(MAKE_SBDFO(makePCISegmentFromNode(1),
1663 makePCIBusFromNode(1),
1664 makePCIDeviceFromNode(1),
1666 REG_HT_TRAFFIC_DIST_0X164),
1668 /* DstNode = 0, cHTPrbDistEn=1, cHTRspDistEn=1, cHTReqDistEn=1 */
1670 AmdPCIWriteBits(MAKE_SBDFO(makePCISegmentFromNode(1),
1671 makePCIBusFromNode(1),
1672 makePCIDeviceFromNode(1),
1674 REG_HT_TRAFFIC_DIST_0X164),
1676 #endif /* HT_BUILD_NC_ONLY */
1679 /**----------------------------------------------------------------------------------------
1682 * ht1WriteTrafficDistribution(u32 links01, u32 links10, cNorthBridge *nb)
1685 * Traffic distribution is more complex in this case as the routing table must be
1686 * adjusted to use one link for requests and the other for responses. Also,
1687 * perform the buffer tunings on the links required for this config.
1690 * @param[in] u32 links01 = coherent links from node 0 to 1
1691 * @param[in] u32 links01 = coherent links from node 1 to 0
1692 * @param[in] cNorthBridge* nb = this northbridge
1694 * ---------------------------------------------------------------------------------------
1696 static void ht1WriteTrafficDistribution(u32 links01, u32 links10, cNorthBridge *nb)
1698 #ifndef HT_BUILD_NC_ONLY
1699 u32 route01, route10;
1700 u8 req0, req1, rsp0, rsp1, nclink;
1703 * Get the current request route for 0->1 and 1->0. This will indicate which of the links
1704 * in links01 are connected to which links in links10. Since we have to route to distribute
1705 * traffic, we need to know that. The link used by htinit will become the request, probe link.
1706 * the other link will be used for responses.
1709 /* Get the routes, and hang on to them, we will write them back updated. */
1710 AmdPCIRead(MAKE_SBDFO(makePCISegmentFromNode(0),
1711 makePCIBusFromNode(0),
1712 makePCIDeviceFromNode(0),
1716 AmdPCIRead(MAKE_SBDFO(makePCISegmentFromNode(1),
1717 makePCIBusFromNode(1),
1718 makePCIDeviceFromNode(1),
1723 /* Convert the request routes to a link number. Note "0xE" is ht1 nb specific.
1724 * Find the response link numbers.
1726 ASSERT((route01 & 0xE) && (route10 & 0xE)); /* no route! error! */
1727 req0 = (u8)AmdBitScanReverse((route01 & 0xE)) - 1;
1728 req1 = (u8)AmdBitScanReverse((route10 & 0xE)) - 1;
1729 /* Now, find the other link for the responses */
1730 rsp0 = (u8)AmdBitScanReverse((links01 & ~((u32)1 << req0)));
1731 rsp1 = (u8)AmdBitScanReverse((links10 & ~((u32)1 << req1)));
1733 /* ht1 nb restriction, must have exactly two links */
1734 ASSERT(((((links01 & ~((u32)1 << req0)) & ~((u32)1 << rsp0))) == 0)
1735 && ((((links10 & ~((u32)1 << req1)) & ~((u32)1 << rsp1))) == 0));
1737 route01 = (route01 & ~0x0E00) | ((u32)0x0100<<(rsp0 + 1));
1738 route10 = (route10 & ~0x0E00) | ((u32)0x0100<<(rsp1 + 1));
1740 AmdPCIWrite(MAKE_SBDFO(makePCISegmentFromNode(0),
1741 makePCIBusFromNode(0),
1742 makePCIDeviceFromNode(0),
1747 AmdPCIWrite(MAKE_SBDFO(makePCISegmentFromNode(1),
1748 makePCIBusFromNode(1),
1749 makePCIDeviceFromNode(1),
1754 /* While we otherwise do buffer tunings elsewhere, for the dual cHT DP case with
1755 * ht1 northbridges like family 0Fh, do the tunings here where we have all the
1756 * link and route info at hand and don't need to recalculate it.
1759 /* Node 0, Request / Probe Link (note family F only has links < 4) */
1760 fam0fWriteHTLinkCmdBufferAlloc(0, req0, 6, 3, 1, 6);
1761 fam0fWriteHTLinkDatBufferAlloc(0, req0, 4, 3, 1);
1762 /* Node 0, Response Link (note family F only has links < 4) */
1763 fam0fWriteHTLinkCmdBufferAlloc(0, rsp0, 1, 0, 15, 0);
1764 fam0fWriteHTLinkDatBufferAlloc(0, rsp0, 1, 1, 6);
1765 /* Node 1, Request / Probe Link (note family F only has links < 4) */
1766 fam0fWriteHTLinkCmdBufferAlloc(1, req1, 6, 3, 1, 6);
1767 fam0fWriteHTLinkDatBufferAlloc(1, req1, 4, 3, 1);
1768 /* Node 1, Response Link (note family F only has links < 4) */
1769 fam0fWriteHTLinkCmdBufferAlloc(1, rsp1, 1, 0, 15, 0);
1770 fam0fWriteHTLinkDatBufferAlloc(1, rsp1, 1, 1, 6);
1772 /* Node 0, is the third link non-coherent? */
1773 nclink = (u8)AmdBitScanReverse(((u8)0x07 & ~((u32)1 << req0) & ~((u32)1 << rsp0)));
1774 if (nb->verifyLinkIsNonCoherent(0, nclink, nb))
1776 fam0fWriteHTLinkCmdBufferAlloc(0, nclink, 6, 5, 2, 0);
1779 /* Node 1, is the third link non-coherent? */
1780 nclink = (u8)AmdBitScanReverse(((u8)0x07 & ~((u32)1 << req1) & ~((u32)1 << rsp1)));
1781 if (nb->verifyLinkIsNonCoherent(1, nclink, nb))
1783 fam0fWriteHTLinkCmdBufferAlloc(1, nclink, 6, 5, 2, 0);
1785 #endif /* HT_BUILD_NC_ONLY */
1788 /**----------------------------------------------------------------------------------------
1791 * fam0fBufferOptimizations(u8 node, sMainData *pDat, cNorthBridge *nb)
1794 * Buffer tunings are inherently northbridge specific. Check for specific configs
1795 * which require adjustments and apply any standard workarounds to this node.
1798 * @param[in] u8 node = the node to
1799 * @param[in] sMainData *pDat = coherent links from node 0 to 1
1800 * @param[in] cNorthBridge* nb = this northbridge
1802 * ---------------------------------------------------------------------------------------
1804 static void fam0fBufferOptimizations(u8 node, sMainData *pDat, cNorthBridge *nb)
1806 #ifndef HT_BUILD_NC_ONLY
1811 ASSERT(node < nb->maxNodes);
1813 /* Fix the FIFO pointer register before changing speeds */
1814 currentPtr = MAKE_SBDFO(makePCISegmentFromNode(node),
1815 makePCIBusFromNode(node),
1816 makePCIDeviceFromNode(node),
1818 REG_NB_FIFOPTR_3XDC);
1819 for (i=0; i < nb->maxLinks; i++)
1822 if (nb->verifyLinkIsCoherent(node, i, nb))
1826 AmdPCIWriteBits(currentPtr, 8*i + 5, 8*i, &temp);
1830 if (nb->verifyLinkIsNonCoherent(node, i, nb))
1834 AmdPCIWriteBits(currentPtr, 8*i + 5, 8*i, &temp);
1840 * Either apply the BKDG tunings or, if applicable, apply the more restrictive errata 153
1842 * If 8 nodes, Check this node for 'inner' or 'outer'.
1843 * Tune each link based on coherent or non-coherent
1845 if (pDat->NodesDiscovered >= 6)
1851 /* This is for family 0Fh, so assuming dual core max then 7 or 8 nodes are required
1852 * to be in the situation of 14 or more cores. We checked nodes above, cross check
1853 * that the number of cores is 14 or more. We want both 14 cores with at least 7 or 8 nodes
1854 * not one condition alone, to apply the errata 153 workaround. Otherwise, 7 or 8 rev F
1855 * nodes use the BKDG tuning.
1860 AmdPCIReadBits (MAKE_SBDFO(makePCISegmentFromNode(0),
1861 makePCIBusFromNode(0),
1862 makePCIDeviceFromNode(0),
1869 /* Check whether we need to do errata 153 tuning or BKDG tuning.
1870 * Errata 153 applies to JH-1, JH-2 and older. It is fixed in JH-3
1871 * (and, one assumes, from there on).
1873 for (i=0; i < (pDat->NodesDiscovered +1); i++)
1875 AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(i),
1876 makePCIBusFromNode(i),
1877 makePCIDeviceFromNode(i),
1881 if (((u8)temp & ~0x40) < 0x13)
1889 for (i=0; i < CPU_ADDR_NUM_CONFIG_MAPS; i++)
1892 /* Check for outer node by scanning the config maps on node 0 for one
1893 * which is assigned to this node.
1895 currentPtr = MAKE_SBDFO(makePCISegmentFromNode(0),
1896 makePCIBusFromNode(0),
1897 makePCIDeviceFromNode(0),
1899 REG_ADDR_CONFIG_MAP0_1XE0 + (4 * i));
1900 AmdPCIReadBits (currentPtr, 1, 0, &temp);
1901 /* Make sure this config map is valid, if it is it will be enabled for read/write */
1904 /* It's valid, get the node (that node is an outer node) */
1905 AmdPCIReadBits (currentPtr, 6, 4, &temp);
1906 /* Is the node we're working on now? */
1907 if (node == (u8)temp)
1909 /* This is an outer node. Tune it appropriately. */
1910 for (j=0; j < nb->maxLinks; j++)
1914 if (nb->verifyLinkIsCoherent(node, j, nb))
1916 fam0fWriteHTLinkCmdBufferAlloc(node, j, 1, 1, 6, 4);
1920 if (nb->verifyLinkIsNonCoherent(node, j, nb))
1922 fam0fWriteHTLinkCmdBufferAlloc(node, j, 5, 4, 1, 0);
1928 if (nb->verifyLinkIsCoherent(node, j, nb))
1930 fam0fWriteHTLinkCmdBufferAlloc(node, j, 1, 1, 8, 5);
1935 * SRI to XBAR Buffer Counts are correct for outer node at power on defaults.
1941 /* We fill config maps in ascending order, so if we didn't use this one, we're done. */
1948 /* Tuning for inner node coherent links */
1949 for (j=0; j < nb->maxLinks; j++)
1951 if (nb->verifyLinkIsCoherent(node, j, nb))
1953 fam0fWriteHTLinkCmdBufferAlloc(node, j, 2, 1, 5, 4);
1957 /* SRI to XBAR Buffer Count for inner nodes, zero DReq and DPReq */
1959 AmdPCIWriteBits (MAKE_SBDFO(makePCISegmentFromNode(node),
1960 makePCIBusFromNode(node),
1961 makePCIDeviceFromNode(node),
1963 REG_NB_SRI_XBAR_BUF_3X70),
1969 * Tune MCT to XBAR Buffer Count the same an all nodes, 2 Probes, 5 Response
1974 AmdPCIWriteBits (MAKE_SBDFO(makePCISegmentFromNode(node),
1975 makePCIBusFromNode(node),
1976 makePCIDeviceFromNode(node),
1978 REG_NB_MCT_XBAR_BUF_3X78),
1982 #endif /* HT_BUILD_NC_ONLY */
1985 /**----------------------------------------------------------------------------------------
1988 * fam10BufferOptimizations(u8 node, sMainData *pDat, cNorthBridge *nb)
1991 * Buffer tunings are inherently northbridge specific. Check for specific configs
1992 * which require adjustments and apply any standard workarounds to this node.
1995 * @param[in] u8 node = the node to tune
1996 * @param[in] sMainData *pDat = global state
1997 * @param[in] cNorthBridge* nb = this northbridge
1999 * ---------------------------------------------------------------------------------------
2001 static void fam10BufferOptimizations(u8 node, sMainData *pDat, cNorthBridge *nb)
2007 ASSERT(node < nb->maxNodes);
2010 * Link to XCS Token Count Tuning
2012 * For each active link that we reganged (so this unfortunately can't go into the PCI reg
2013 * table), we have to switch the Link to XCS Token Counts to the ganged state.
2014 * We do this here for the non-uma case, which is to write the values that would have
2015 * been power on defaults if the link was ganged at cold reset.
2017 for (i = 0; i < pDat->TotalLinks*2; i++)
2019 if ((pDat->PortList[i].NodeID == node) && (pDat->PortList[i].Type == PORTLIST_TYPE_CPU))
2021 /* If the link is greater than 4, this is a sublink 1, so it is not reganged. */
2022 if (pDat->PortList[i].Link < 4)
2024 currentPtr = MAKE_SBDFO(makePCISegmentFromNode(node),
2025 makePCIBusFromNode(node),
2026 makePCIDeviceFromNode(node),
2028 REG_NB_LINK_XCS_TOKEN0_3X148 + 4*pDat->PortList[i].Link);
2029 if (pDat->PortList[i].SelRegang)
2031 /* Handle all the regang Token count adjustments */
2033 /* Sublink 0: [Probe0tok] = 2 [Rsp0tok] = 2 [PReq0tok] = 2 [Req0tok] = 2 */
2035 AmdPCIWriteBits(currentPtr, 7, 0, &temp);
2036 /* Sublink 1: [Probe1tok] = 0 [Rsp1tok] = 0 [PReq1tok] = 0 [Req1tok] = 0 */
2038 AmdPCIWriteBits(currentPtr, 23, 16, &temp);
2041 AmdPCIWriteBits(currentPtr, 15, 14, &temp);
2045 /* Read the regang bit in hardware */
2046 AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(pDat->PortList[i].NodeID),
2047 makePCIBusFromNode(pDat->PortList[i].NodeID),
2048 makePCIDeviceFromNode(pDat->PortList[i].NodeID),
2050 REG_HT_LINK_EXT_CONTROL0_0X170 + 4*pDat->PortList[i].Link),
2054 /* handle a minor adjustment for stapped ganged links. If SelRegang is false we
2055 * didn't do the regang, so if the bit is on then it's hardware strapped.
2060 AmdPCIWriteBits(currentPtr, 15, 14, &temp);
2069 * North Bridge 'constructor'.
2073 /**----------------------------------------------------------------------------------------
2076 * newNorthBridge(u8 node, cNorthBridge *nb)
2079 * Construct a new northbridge. This routine encapsulates knowledge of how to tell
2080 * significant differences between families of supported northbridges and what routines
2081 * can be used in common and which are unique. A fully populated northbridge interface
2082 * is provided by nb.
2085 * @param[in] node u8 = create a northbridge interface for this node.
2086 * @param[out] cNorthBridge* nb = the caller's northbridge structure to initialize.
2088 * ---------------------------------------------------------------------------------------
2090 void newNorthBridge(u8 node, cNorthBridge *nb)
2093 u32 extFam, baseFam, model;
2095 cNorthBridge fam10 =
2097 #ifdef HT_BUILD_NC_ONLY
2105 #endif /* HT_BUILD_NC_ONLY*/
2109 enableRoutingTables,
2110 verifyLinkIsCoherent,
2111 readTrueLinkFailStatus,
2114 fam10GetNumCoresOnNode,
2115 setTotalNodesAndCores,
2117 writeFullRoutingTable,
2120 (void (*)(u8, u8, cNorthBridge*))commonVoid,
2121 (BOOL (*)(u8, u8, sMainData*, cNorthBridge*))commonReturnFalse,
2123 verifyLinkIsNonCoherent,
2127 fam10NorthBridgeFreqMask,
2130 ht3WriteTrafficDistribution,
2131 fam10BufferOptimizations,
2138 cNorthBridge fam0f =
2140 #ifdef HT_BUILD_NC_ONLY
2148 #endif /* HT_BUILD_NC_ONLY*/
2152 enableRoutingTables,
2153 verifyLinkIsCoherent,
2154 readTrueLinkFailStatus,
2157 fam0FGetNumCoresOnNode,
2158 setTotalNodesAndCores,
2160 writeFullRoutingTable,
2164 (BOOL (*)(u8, u8, sMainData*, cNorthBridge*))commonReturnFalse,
2166 verifyLinkIsNonCoherent,
2170 ht1NorthBridgeFreqMask,
2173 ht1WriteTrafficDistribution,
2174 fam0fBufferOptimizations,
2181 /* Start with enough of the key to identify the northbridge interface */
2182 AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(node),
2183 makePCIBusFromNode(node),
2184 makePCIDeviceFromNode(node),
2188 AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(node),
2189 makePCIBusFromNode(node),
2190 makePCIDeviceFromNode(node),
2194 AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(node),
2195 makePCIBusFromNode(node),
2196 makePCIDeviceFromNode(node),
2200 match = (u32)((baseFam << 8) | extFam);
2202 /* Test each in turn looking for a match. Init the struct if found */
2203 if (match == fam10.compatibleKey)
2205 Amdmemcpy((void *)nb, (const void *)&fam10, (u32) sizeof(cNorthBridge));
2209 if (match == fam0f.compatibleKey)
2211 Amdmemcpy((void *)nb, (const void *)&fam0f, (u32) sizeof(cNorthBridge));
2219 /* Update the initial limited key to the real one, which may include other matching info */
2220 nb->compatibleKey = makeKey(node);