northbridge/amd/amdht: Add isochronous setup support
The coherent fabric on all Family 10h/15h devices supports isochronous mode, which is required for IOMMU operation. Add initial support for isochronous operation. Change-Id: Idd7c9b94a65f856b0059e1d45f8719d9475771b6 Signed-off-by: Timothy Pearson <tpearson@raptorengineeringinc.com> Reviewed-on: http://review.coreboot.org/12042 Tested-by: build bot (Jenkins) Reviewed-by: Martin Roth <martinroth@google.com>
This commit is contained in:
parent
68130f506d
commit
50001b80f5
|
@ -1666,6 +1666,67 @@ static void cpuSetAMDPCI(u8 node)
|
|||
pci_write_config32(NODE_PCI(node, 3), 0x140, dword);
|
||||
}
|
||||
|
||||
uint8_t link;
|
||||
uint8_t isochronous;
|
||||
uint8_t isochronous_link_present;
|
||||
|
||||
/* Set up isochronous buffers if needed */
|
||||
isochronous_link_present = 0;
|
||||
if (revision & AMD_FAM15_ALL) {
|
||||
for (link = 0; link < 4; link++) {
|
||||
if (AMD_CpuFindCapability(node, link, &offset)) {
|
||||
isochronous = (pci_read_config32(NODE_PCI(node, 0), (link * 0x20) + 0x84) >> 12) & 0x1;
|
||||
|
||||
if (isochronous)
|
||||
isochronous_link_present = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t free_tok;
|
||||
uint8_t up_rsp_cbc;
|
||||
uint8_t isoc_preq_cbc;
|
||||
uint8_t isoc_preq_tok;
|
||||
uint8_t xbar_to_sri_free_list_cbc;
|
||||
if (isochronous_link_present) {
|
||||
/* Adjust buffer counts */
|
||||
dword = pci_read_config32(NODE_PCI(node, 3), 0x70);
|
||||
isoc_preq_cbc = (dword >> 24) & 0x7;
|
||||
up_rsp_cbc = (dword >> 16) & 0x7;
|
||||
up_rsp_cbc--;
|
||||
isoc_preq_cbc++;
|
||||
dword &= ~(0x7 << 24); /* IsocPreqCBC = isoc_preq_cbc */
|
||||
dword |= ((isoc_preq_cbc & 0x7) << 24);
|
||||
dword &= ~(0x7 << 16); /* UpRspCBC = up_rsp_cbc */
|
||||
dword |= ((up_rsp_cbc & 0x7) << 16);
|
||||
pci_write_config32(NODE_PCI(node, 3), 0x70, dword);
|
||||
|
||||
dword = pci_read_config32(NODE_PCI(node, 3), 0x74);
|
||||
isoc_preq_cbc = (dword >> 24) & 0x7;
|
||||
isoc_preq_cbc++;
|
||||
dword &= ~(0x7 << 24); /* IsocPreqCBC = isoc_preq_cbc */
|
||||
dword |= (isoc_preq_cbc & 0x7) << 24;
|
||||
pci_write_config32(NODE_PCI(node, 3), 0x74, dword);
|
||||
|
||||
dword = pci_read_config32(NODE_PCI(node, 3), 0x7c);
|
||||
xbar_to_sri_free_list_cbc = dword & 0x1f;
|
||||
xbar_to_sri_free_list_cbc--;
|
||||
dword &= ~0x1f; /* Xbar2SriFreeListCBC = xbar_to_sri_free_list_cbc */
|
||||
dword |= xbar_to_sri_free_list_cbc & 0x1f;
|
||||
pci_write_config32(NODE_PCI(node, 3), 0x7c, dword);
|
||||
|
||||
dword = pci_read_config32(NODE_PCI(node, 3), 0x140);
|
||||
free_tok = (dword >> 20) & 0xf;
|
||||
isoc_preq_tok = (dword >> 14) & 0x3;
|
||||
free_tok--;
|
||||
isoc_preq_tok++;
|
||||
dword &= ~(0xf << 20); /* FreeTok = free_tok */
|
||||
dword |= ((free_tok & 0xf) << 20);
|
||||
dword &= ~(0x3 << 14); /* IsocPreqTok = isoc_preq_tok */
|
||||
dword |= ((isoc_preq_tok & 0x3) << 14);
|
||||
pci_write_config32(NODE_PCI(node, 3), 0x140, dword);
|
||||
}
|
||||
|
||||
printk(BIOS_DEBUG, " done\n");
|
||||
}
|
||||
|
||||
|
|
|
@ -75,6 +75,7 @@
|
|||
#define HTSLAVE_LINK01_OFFSET 4
|
||||
#define HTSLAVE_LINK_CONTROL_0_REG 4
|
||||
#define HTSLAVE_FREQ_REV_0_REG 0xC
|
||||
#define HTSLAVE_FEATURE_CAP_REG 0x10
|
||||
|
||||
/* HT3 gen Capability */
|
||||
#define IS_HT_GEN3_CAPABILITY(reg) \
|
||||
|
@ -122,10 +123,12 @@ typedef struct
|
|||
u8 SelWidthIn;
|
||||
u8 SelWidthOut;
|
||||
u8 SelFrequency;
|
||||
uint8_t enable_isochronous_mode;
|
||||
|
||||
/* This section is for keeping track of capabilities and possible configurations */
|
||||
BOOL RegangCap;
|
||||
uint32_t PrvFrequencyCap;
|
||||
uint32_t PrvFeatureCap;
|
||||
u8 PrvWidthInCap;
|
||||
u8 PrvWidthOutCap;
|
||||
uint32_t CompositeFrequencyCap;
|
||||
|
|
|
@ -1415,6 +1415,38 @@ static void regangLinks(sMainData *pDat)
|
|||
#endif /* HT_BUILD_NC_ONLY */
|
||||
}
|
||||
|
||||
static void detectIoLinkIsochronousCapable(sMainData *pDat)
|
||||
{
|
||||
uint8_t i;
|
||||
unsigned char iommu;
|
||||
uint8_t isochronous_capable = 0;
|
||||
|
||||
iommu = 1;
|
||||
get_option(&iommu, "iommu");
|
||||
|
||||
for (i = 0; i < pDat->TotalLinks*2; i += 2) {
|
||||
if ((pDat->PortList[i].Type == PORTLIST_TYPE_CPU) && (pDat->PortList[i+1].Type == PORTLIST_TYPE_IO)) {
|
||||
if ((pDat->PortList[i].PrvFeatureCap & 0x1) && (pDat->PortList[i+1].PrvFeatureCap & 0x1)) {
|
||||
pDat->PortList[i].enable_isochronous_mode = 1;
|
||||
pDat->PortList[i+1].enable_isochronous_mode = 1;
|
||||
isochronous_capable = 1;
|
||||
} else {
|
||||
pDat->PortList[i].enable_isochronous_mode = 0;
|
||||
pDat->PortList[i+1].enable_isochronous_mode = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isochronous_capable && iommu) {
|
||||
printk(BIOS_DEBUG, "Forcing HT links to isochronous mode due to enabled IOMMU\n");
|
||||
/* Isochronous mode must be set on all links if the IOMMU is enabled */
|
||||
for (i = 0; i < pDat->TotalLinks*2; i += 2) {
|
||||
pDat->PortList[i].enable_isochronous_mode = 1;
|
||||
pDat->PortList[i+1].enable_isochronous_mode = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------------------
|
||||
* void
|
||||
* selectOptimalWidthAndFrequency(sMainData *pDat)
|
||||
|
@ -1535,7 +1567,6 @@ static void selectOptimalWidthAndFrequency(sMainData *pDat)
|
|||
temp = cbPCBBAUpstreamWidth;
|
||||
pDat->PortList[i].SelWidthIn = (u8)temp;
|
||||
pDat->PortList[i+1].SelWidthOut = (u8)temp;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1697,6 +1728,8 @@ static void linkOptimization(sMainData *pDat)
|
|||
{
|
||||
pDat->nb->gatherLinkData(pDat, pDat->nb);
|
||||
regangLinks(pDat);
|
||||
if (is_fam15h())
|
||||
detectIoLinkIsochronousCapable(pDat);
|
||||
selectOptimalWidthAndFrequency(pDat);
|
||||
hammerSublinkFixup(pDat);
|
||||
pDat->nb->setLinkData(pDat, pDat->nb);
|
||||
|
|
|
@ -227,6 +227,7 @@ typedef struct {
|
|||
* @param[in,out] u8* LinkWidthIn = modify to change the Link Witdh In
|
||||
* @param[in,out] u8* LinkWidthOut = modify to change the Link Witdh Out
|
||||
* @param[in,out] u32* FreqCap = modify to change the link's frequency capability
|
||||
* @param[in,out] u32* FeatureCap = modify to change the link's feature capability
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -241,7 +242,8 @@ typedef struct {
|
|||
u8 Link,
|
||||
u8 *LinkWidthIn,
|
||||
u8 *LinkWidthOut,
|
||||
u32 *FreqCap
|
||||
u32 *FreqCap,
|
||||
u32 *FeatureCap
|
||||
);
|
||||
|
||||
/**----------------------------------------------------------------------------------------
|
||||
|
|
|
@ -1429,12 +1429,15 @@ static void gatherLinkData(sMainData *pDat, cNorthBridge *nb)
|
|||
temp &= 0x7; /* Mask off reserved values */
|
||||
pDat->PortList[i].PrvFrequencyCap |= (temp << 17);
|
||||
}
|
||||
|
||||
AmdPCIReadBits(linkBase + HTHOST_FEATURE_CAP_REG, 9, 0, &temp);
|
||||
pDat->PortList[i].PrvFeatureCap = (u16)temp;
|
||||
}
|
||||
else
|
||||
{
|
||||
linkBase = pDat->PortList[i].Pointer;
|
||||
if (pDat->PortList[i].Link == 1)
|
||||
linkBase += HTSLAVE_LINK01_OFFSET;
|
||||
linkBase += HTSLAVE_LINK01_OFFSET;
|
||||
|
||||
AmdPCIReadBits(linkBase + HTSLAVE_LINK_CONTROL_0_REG, 22, 20, &temp);
|
||||
pDat->PortList[i].PrvWidthOutCap = convertBitsToWidth((u8)temp, pDat->nb);
|
||||
|
@ -1445,6 +1448,9 @@ static void gatherLinkData(sMainData *pDat, cNorthBridge *nb)
|
|||
AmdPCIReadBits(linkBase + HTSLAVE_FREQ_REV_0_REG, 31, 16, &temp);
|
||||
pDat->PortList[i].PrvFrequencyCap = (u16)temp;
|
||||
|
||||
AmdPCIReadBits(linkBase + HTSLAVE_FEATURE_CAP_REG, 7, 0, &temp);
|
||||
pDat->PortList[i].PrvFeatureCap = (u16)temp;
|
||||
|
||||
if (pDat->HtBlock->AMD_CB_DeviceCapOverride)
|
||||
{
|
||||
linkBase &= 0xFFFFF000;
|
||||
|
@ -1461,7 +1467,8 @@ static void gatherLinkData(sMainData *pDat, cNorthBridge *nb)
|
|||
pDat->PortList[i].Link,
|
||||
&(pDat->PortList[i].PrvWidthInCap),
|
||||
&(pDat->PortList[i].PrvWidthOutCap),
|
||||
&(pDat->PortList[i].PrvFrequencyCap));
|
||||
&(pDat->PortList[i].PrvFrequencyCap),
|
||||
&(pDat->PortList[i].PrvFeatureCap));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1562,6 +1569,16 @@ static void setLinkData(sMainData *pDat, cNorthBridge *nb)
|
|||
if (is_gt_rev_d())
|
||||
AmdPCIWriteBits(linkBase + HTHOST_FREQ_REV_REG_2, 0, 0, &temp2);
|
||||
AmdPCIWriteBits(linkBase + HTHOST_FREQ_REV_REG, 11, 8, &temp);
|
||||
|
||||
/* Enable isochronous flow control mode if supported by chipset */
|
||||
if (is_fam15h()) {
|
||||
if (pDat->PortList[i].enable_isochronous_mode)
|
||||
temp = 1;
|
||||
else
|
||||
temp = 0;
|
||||
setHtControlRegisterBits(linkBase + HTHOST_LINK_CONTROL_REG, 12, 12, &temp);
|
||||
}
|
||||
|
||||
if (frequency_index > HT_FREQUENCY_1000M) /* Gen1 = 200MHz -> 1000MHz, Gen3 = 1200MHz -> 3200MHz */
|
||||
{
|
||||
/* Enable for Gen3 frequencies */
|
||||
|
@ -1579,6 +1596,7 @@ static void setLinkData(sMainData *pDat, cNorthBridge *nb)
|
|||
CPU_HTNB_FUNC_00,
|
||||
REG_HT_LINK_RETRY0_0X130 + 4*pDat->PortList[i].Link),
|
||||
0, 0, &temp);
|
||||
|
||||
/* and Scrambling enable / disable */
|
||||
AmdPCIWriteBits(MAKE_SBDFO(makePCISegmentFromNode(pDat->PortList[i].NodeID),
|
||||
makePCIBusFromNode(pDat->PortList[i].NodeID),
|
||||
|
@ -1617,6 +1635,14 @@ static void setLinkData(sMainData *pDat, cNorthBridge *nb)
|
|||
bits = 0;
|
||||
}
|
||||
|
||||
/* Enable isochronous flow control mode if supported by chipset */
|
||||
if (is_fam15h()) {
|
||||
if (pDat->PortList[i].enable_isochronous_mode)
|
||||
temp = 1;
|
||||
else
|
||||
temp = 0;
|
||||
}
|
||||
|
||||
/* Retry Enable */
|
||||
isFound = FALSE;
|
||||
currentPtr = linkBase & (u32)0xFFFFF000; /* Set PCI Offset to 0 */
|
||||
|
|
Loading…
Reference in New Issue