From 50001b80f54c3d1cdd926102c68d33e549541205 Mon Sep 17 00:00:00 2001 From: Timothy Pearson Date: Tue, 11 Aug 2015 17:47:48 -0500 Subject: 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 Reviewed-on: http://review.coreboot.org/12042 Tested-by: build bot (Jenkins) Reviewed-by: Martin Roth --- 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 ++++++++++++++++++++++++++++-- 4 files changed, 68 insertions(+), 4 deletions(-) (limited to 'src/northbridge/amd') 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 */ -- cgit v1.2.3