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:
		
				
					committed by
					
						 Martin Roth
						Martin Roth
					
				
			
			
				
	
			
			
			
						parent
						
							68130f506d
						
					
				
				
					commit
					50001b80f5
				
			| @@ -1666,6 +1666,67 @@ static void cpuSetAMDPCI(u8 node) | |||||||
| 		pci_write_config32(NODE_PCI(node, 3), 0x140, dword); | 		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"); | 	printk(BIOS_DEBUG, " done\n"); | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -75,6 +75,7 @@ | |||||||
| #define HTSLAVE_LINK01_OFFSET			4 | #define HTSLAVE_LINK01_OFFSET			4 | ||||||
| #define HTSLAVE_LINK_CONTROL_0_REG		4 | #define HTSLAVE_LINK_CONTROL_0_REG		4 | ||||||
| #define HTSLAVE_FREQ_REV_0_REG			0xC | #define HTSLAVE_FREQ_REV_0_REG			0xC | ||||||
|  | #define HTSLAVE_FEATURE_CAP_REG		0x10 | ||||||
|  |  | ||||||
| /* HT3 gen Capability */ | /* HT3 gen Capability */ | ||||||
| #define IS_HT_GEN3_CAPABILITY(reg) \ | #define IS_HT_GEN3_CAPABILITY(reg) \ | ||||||
| @@ -122,10 +123,12 @@ typedef struct | |||||||
| 	u8 SelWidthIn; | 	u8 SelWidthIn; | ||||||
| 	u8 SelWidthOut; | 	u8 SelWidthOut; | ||||||
| 	u8 SelFrequency; | 	u8 SelFrequency; | ||||||
|  | 	uint8_t enable_isochronous_mode; | ||||||
|  |  | ||||||
| 	/* This section is for keeping track of capabilities and possible configurations */ | 	/* This section is for keeping track of capabilities and possible configurations */ | ||||||
| 	BOOL RegangCap; | 	BOOL RegangCap; | ||||||
| 	uint32_t PrvFrequencyCap; | 	uint32_t PrvFrequencyCap; | ||||||
|  | 	uint32_t PrvFeatureCap; | ||||||
| 	u8 PrvWidthInCap; | 	u8 PrvWidthInCap; | ||||||
| 	u8 PrvWidthOutCap; | 	u8 PrvWidthOutCap; | ||||||
| 	uint32_t CompositeFrequencyCap; | 	uint32_t CompositeFrequencyCap; | ||||||
|   | |||||||
| @@ -1415,6 +1415,38 @@ static void regangLinks(sMainData *pDat) | |||||||
| #endif /* HT_BUILD_NC_ONLY */ | #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 |  * void | ||||||
|  * selectOptimalWidthAndFrequency(sMainData *pDat) |  * selectOptimalWidthAndFrequency(sMainData *pDat) | ||||||
| @@ -1535,7 +1567,6 @@ static void selectOptimalWidthAndFrequency(sMainData *pDat) | |||||||
| 			temp = cbPCBBAUpstreamWidth; | 			temp = cbPCBBAUpstreamWidth; | ||||||
| 		pDat->PortList[i].SelWidthIn = (u8)temp; | 		pDat->PortList[i].SelWidthIn = (u8)temp; | ||||||
| 		pDat->PortList[i+1].SelWidthOut = (u8)temp; | 		pDat->PortList[i+1].SelWidthOut = (u8)temp; | ||||||
|  |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -1697,6 +1728,8 @@ static void linkOptimization(sMainData *pDat) | |||||||
| { | { | ||||||
| 	pDat->nb->gatherLinkData(pDat, pDat->nb); | 	pDat->nb->gatherLinkData(pDat, pDat->nb); | ||||||
| 	regangLinks(pDat); | 	regangLinks(pDat); | ||||||
|  | 	if (is_fam15h()) | ||||||
|  | 		detectIoLinkIsochronousCapable(pDat); | ||||||
| 	selectOptimalWidthAndFrequency(pDat); | 	selectOptimalWidthAndFrequency(pDat); | ||||||
| 	hammerSublinkFixup(pDat); | 	hammerSublinkFixup(pDat); | ||||||
| 	pDat->nb->setLinkData(pDat, pDat->nb); | 	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*  LinkWidthIn  = modify to change the Link Witdh In | ||||||
| 	 *	@param[in,out] u8*  LinkWidthOut  = modify to change the Link Witdh Out | 	 *	@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* 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 Link, | ||||||
| 		u8 *LinkWidthIn, | 		u8 *LinkWidthIn, | ||||||
| 		u8 *LinkWidthOut, | 		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 */ | 				temp &= 0x7;	/* Mask off reserved values */ | ||||||
| 				pDat->PortList[i].PrvFrequencyCap |= (temp << 17); | 				pDat->PortList[i].PrvFrequencyCap |= (temp << 17); | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
|  | 			AmdPCIReadBits(linkBase + HTHOST_FEATURE_CAP_REG, 9, 0, &temp); | ||||||
|  | 			pDat->PortList[i].PrvFeatureCap = (u16)temp; | ||||||
| 		} | 		} | ||||||
| 		else | 		else | ||||||
| 		{ | 		{ | ||||||
| 			linkBase = pDat->PortList[i].Pointer; | 			linkBase = pDat->PortList[i].Pointer; | ||||||
| 			if (pDat->PortList[i].Link == 1) | 			if (pDat->PortList[i].Link == 1) | ||||||
| 			 linkBase += HTSLAVE_LINK01_OFFSET; | 				linkBase += HTSLAVE_LINK01_OFFSET; | ||||||
|  |  | ||||||
| 			AmdPCIReadBits(linkBase + HTSLAVE_LINK_CONTROL_0_REG, 22, 20, &temp); | 			AmdPCIReadBits(linkBase + HTSLAVE_LINK_CONTROL_0_REG, 22, 20, &temp); | ||||||
| 			pDat->PortList[i].PrvWidthOutCap = convertBitsToWidth((u8)temp, pDat->nb); | 			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); | 			AmdPCIReadBits(linkBase + HTSLAVE_FREQ_REV_0_REG, 31, 16, &temp); | ||||||
| 			pDat->PortList[i].PrvFrequencyCap = (u16)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) | 			if (pDat->HtBlock->AMD_CB_DeviceCapOverride) | ||||||
| 			{ | 			{ | ||||||
| 				linkBase &= 0xFFFFF000; | 				linkBase &= 0xFFFFF000; | ||||||
| @@ -1461,7 +1467,8 @@ static void gatherLinkData(sMainData *pDat, cNorthBridge *nb) | |||||||
| 					pDat->PortList[i].Link, | 					pDat->PortList[i].Link, | ||||||
| 					&(pDat->PortList[i].PrvWidthInCap), | 					&(pDat->PortList[i].PrvWidthInCap), | ||||||
| 					&(pDat->PortList[i].PrvWidthOutCap), | 					&(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()) | 			if (is_gt_rev_d()) | ||||||
| 				AmdPCIWriteBits(linkBase + HTHOST_FREQ_REV_REG_2, 0, 0, &temp2); | 				AmdPCIWriteBits(linkBase + HTHOST_FREQ_REV_REG_2, 0, 0, &temp2); | ||||||
| 			AmdPCIWriteBits(linkBase + HTHOST_FREQ_REV_REG, 11, 8, &temp); | 			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 */ | 			if (frequency_index > HT_FREQUENCY_1000M) /*  Gen1 = 200MHz -> 1000MHz, Gen3 = 1200MHz -> 3200MHz */ | ||||||
| 			{ | 			{ | ||||||
| 				/* Enable  for Gen3 frequencies */ | 				/* Enable  for Gen3 frequencies */ | ||||||
| @@ -1579,6 +1596,7 @@ static void setLinkData(sMainData *pDat, cNorthBridge *nb) | |||||||
| 						CPU_HTNB_FUNC_00, | 						CPU_HTNB_FUNC_00, | ||||||
| 						REG_HT_LINK_RETRY0_0X130 + 4*pDat->PortList[i].Link), | 						REG_HT_LINK_RETRY0_0X130 + 4*pDat->PortList[i].Link), | ||||||
| 						0, 0, &temp); | 						0, 0, &temp); | ||||||
|  |  | ||||||
| 			/* and Scrambling enable / disable */ | 			/* and Scrambling enable / disable */ | ||||||
| 			AmdPCIWriteBits(MAKE_SBDFO(makePCISegmentFromNode(pDat->PortList[i].NodeID), | 			AmdPCIWriteBits(MAKE_SBDFO(makePCISegmentFromNode(pDat->PortList[i].NodeID), | ||||||
| 					makePCIBusFromNode(pDat->PortList[i].NodeID), | 					makePCIBusFromNode(pDat->PortList[i].NodeID), | ||||||
| @@ -1617,6 +1635,14 @@ static void setLinkData(sMainData *pDat, cNorthBridge *nb) | |||||||
| 				bits = 0; | 				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 */ | 			/* Retry Enable */ | ||||||
| 			isFound = FALSE; | 			isFound = FALSE; | ||||||
| 			currentPtr = linkBase & (u32)0xFFFFF000; /* Set PCI Offset to 0 */ | 			currentPtr = linkBase & (u32)0xFFFFF000; /* Set PCI Offset to 0 */ | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user