From c6a6d7b4fc613a18511d8aeb0040a350d61920e7 Mon Sep 17 00:00:00 2001 From: Timothy Pearson Date: Tue, 11 Aug 2015 17:47:48 -0500 Subject: [PATCH 111/143] northbridge/amd/amdht: Add isochronous setup support for coherent fabric Change-Id: Idd7c9b94a65f856b0059e1d45f8719d9475771b6 Signed-off-by: Timothy Pearson --- src/cpu/amd/family_10h-family_15h/init_cpus.c | 61 +++++++++++++++++++++++++ src/northbridge/amd/amdht/h3ffeat.h | 3 ++ src/northbridge/amd/amdht/h3finit.c | 35 +++++++++++++- src/northbridge/amd/amdht/h3finit.h | 4 +- src/northbridge/amd/amdht/h3ncmn.c | 30 +++++++++++- 5 files changed, 129 insertions(+), 4 deletions(-) diff --git a/src/cpu/amd/family_10h-family_15h/init_cpus.c b/src/cpu/amd/family_10h-family_15h/init_cpus.c index 7dffcc0..da6424f 100644 --- a/src/cpu/amd/family_10h-family_15h/init_cpus.c +++ b/src/cpu/amd/family_10h-family_15h/init_cpus.c @@ -1697,6 +1697,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"); } diff --git a/src/northbridge/amd/amdht/h3ffeat.h b/src/northbridge/amd/amdht/h3ffeat.h index 5dc9916..c523b12 100644 --- a/src/northbridge/amd/amdht/h3ffeat.h +++ b/src/northbridge/amd/amdht/h3ffeat.h @@ -79,6 +79,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) \ @@ -126,10 +127,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; diff --git a/src/northbridge/amd/amdht/h3finit.c b/src/northbridge/amd/amdht/h3finit.c index 14f348f..6b53d34 100644 --- a/src/northbridge/amd/amdht/h3finit.c +++ b/src/northbridge/amd/amdht/h3finit.c @@ -1419,6 +1419,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) @@ -1539,7 +1571,6 @@ static void selectOptimalWidthAndFrequency(sMainData *pDat) temp = cbPCBBAUpstreamWidth; pDat->PortList[i].SelWidthIn = (u8)temp; pDat->PortList[i+1].SelWidthOut = (u8)temp; - } } @@ -1701,6 +1732,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); diff --git a/src/northbridge/amd/amdht/h3finit.h b/src/northbridge/amd/amdht/h3finit.h index 462f3e3..eef8fe7 100644 --- a/src/northbridge/amd/amdht/h3finit.h +++ b/src/northbridge/amd/amdht/h3finit.h @@ -231,6 +231,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 * * --------------------------------------------------------------------------------------- */ @@ -245,7 +246,8 @@ typedef struct { u8 Link, u8 *LinkWidthIn, u8 *LinkWidthOut, - u32 *FreqCap + u32 *FreqCap, + u32 *FeatureCap ); /**---------------------------------------------------------------------------------------- diff --git a/src/northbridge/amd/amdht/h3ncmn.c b/src/northbridge/amd/amdht/h3ncmn.c index e377ff2..369ce3e 100644 --- a/src/northbridge/amd/amdht/h3ncmn.c +++ b/src/northbridge/amd/amdht/h3ncmn.c @@ -1433,12 +1433,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); @@ -1449,6 +1452,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; @@ -1465,7 +1471,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)); } } } @@ -1566,6 +1573,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 */ @@ -1583,6 +1600,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), @@ -1621,6 +1639,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 */ -- 1.7.9.5