diff options
author | Timothy Pearson <tpearson@raptorengineeringinc.com> | 2015-08-11 17:47:48 -0500 |
---|---|---|
committer | Martin Roth <martinroth@google.com> | 2015-11-24 19:28:00 +0100 |
commit | 50001b80f54c3d1cdd926102c68d33e549541205 (patch) | |
tree | 6c789e9040e25f31ed5336a95f59da69ca0ec484 | |
parent | 68130f506df5c77107ece8d71aa45b598be77b45 (diff) | |
download | coreboot-50001b80f54c3d1cdd926102c68d33e549541205.tar.xz |
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>
-rw-r--r-- | src/cpu/amd/family_10h-family_15h/init_cpus.c | 61 | ||||
-rw-r--r-- | src/northbridge/amd/amdht/h3ffeat.h | 3 | ||||
-rw-r--r-- | src/northbridge/amd/amdht/h3finit.c | 35 | ||||
-rw-r--r-- | src/northbridge/amd/amdht/h3finit.h | 4 | ||||
-rw-r--r-- | 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 da458883d3..635f35787e 100644 --- a/src/cpu/amd/family_10h-family_15h/init_cpus.c +++ b/src/cpu/amd/family_10h-family_15h/init_cpus.c @@ -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"); } diff --git a/src/northbridge/amd/amdht/h3ffeat.h b/src/northbridge/amd/amdht/h3ffeat.h index 628b86e660..bcd4c10cd2 100644 --- a/src/northbridge/amd/amdht/h3ffeat.h +++ b/src/northbridge/amd/amdht/h3ffeat.h @@ -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; diff --git a/src/northbridge/amd/amdht/h3finit.c b/src/northbridge/amd/amdht/h3finit.c index e4ce76803a..6a45f10306 100644 --- a/src/northbridge/amd/amdht/h3finit.c +++ b/src/northbridge/amd/amdht/h3finit.c @@ -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); diff --git a/src/northbridge/amd/amdht/h3finit.h b/src/northbridge/amd/amdht/h3finit.h index 1bd8616ef2..ab2dace20c 100644 --- a/src/northbridge/amd/amdht/h3finit.h +++ b/src/northbridge/amd/amdht/h3finit.h @@ -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 ); /**---------------------------------------------------------------------------------------- diff --git a/src/northbridge/amd/amdht/h3ncmn.c b/src/northbridge/amd/amdht/h3ncmn.c index c97d59293f..7937c6ea1a 100644 --- a/src/northbridge/amd/amdht/h3ncmn.c +++ b/src/northbridge/amd/amdht/h3ncmn.c @@ -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 */ |