mirror of
				https://xff.cz/git/u-boot/
				synced 2025-10-31 10:26:10 +01:00 
			
		
		
		
	dm: pcie: designware: add correct ATU handling
Currently, ATU (address translation unit) implementation doesn't support translate addresses > 32 bits. This patch allows to configure ATU correctly for different memory accesses (memory, configuration and IO). The same approach is used in Linux Kernel. Signed-off-by: Igal Liberman <igall@marvell.com> Signed-off-by: Stefan Roese <sr@denx.de>
This commit is contained in:
		
				
					committed by
					
						 Stefan Roese
						Stefan Roese
					
				
			
			
				
	
			
			
			
						parent
						
							81cf7c8d45
						
					
				
				
					commit
					b8478fcd04
				
			| @@ -111,6 +111,10 @@ struct pcie_dw_mvebu { | |||||||
| 	void *cfg_base; | 	void *cfg_base; | ||||||
| 	fdt_size_t cfg_size; | 	fdt_size_t cfg_size; | ||||||
| 	int first_busno; | 	int first_busno; | ||||||
|  |  | ||||||
|  | 	/* IO and MEM PCI regions */ | ||||||
|  | 	struct pci_region io; | ||||||
|  | 	struct pci_region mem; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| static int pcie_dw_get_link_speed(const void *regs_base) | static int pcie_dw_get_link_speed(const void *regs_base) | ||||||
| @@ -125,6 +129,34 @@ static int pcie_dw_get_link_width(const void *regs_base) | |||||||
| 		PCIE_LINK_STATUS_WIDTH_MASK) >> PCIE_LINK_STATUS_WIDTH_OFF; | 		PCIE_LINK_STATUS_WIDTH_MASK) >> PCIE_LINK_STATUS_WIDTH_OFF; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * pcie_dw_prog_outbound_atu() - Configure ATU for outbound accesses | ||||||
|  |  * | ||||||
|  |  * @pcie: Pointer to the PCI controller state | ||||||
|  |  * @index: ATU region index | ||||||
|  |  * @type: ATU accsess type | ||||||
|  |  * @cpu_addr: the physical address for the translation entry | ||||||
|  |  * @pci_addr: the pcie bus address for the translation entry | ||||||
|  |  * @size: the size of the translation entry | ||||||
|  |  */ | ||||||
|  | static void pcie_dw_prog_outbound_atu(struct pcie_dw_mvebu *pcie, int index, | ||||||
|  | 				      int type, u64 cpu_addr, u64 pci_addr, | ||||||
|  | 				      u32 size) | ||||||
|  | { | ||||||
|  | 	writel(PCIE_ATU_REGION_OUTBOUND | index, | ||||||
|  | 	       pcie->ctrl_base + PCIE_ATU_VIEWPORT); | ||||||
|  | 	writel(lower_32_bits(cpu_addr), pcie->ctrl_base + PCIE_ATU_LOWER_BASE); | ||||||
|  | 	writel(upper_32_bits(cpu_addr), pcie->ctrl_base + PCIE_ATU_UPPER_BASE); | ||||||
|  | 	writel(lower_32_bits(cpu_addr + size - 1), | ||||||
|  | 	       pcie->ctrl_base + PCIE_ATU_LIMIT); | ||||||
|  | 	writel(lower_32_bits(pci_addr), | ||||||
|  | 	       pcie->ctrl_base + PCIE_ATU_LOWER_TARGET); | ||||||
|  | 	writel(upper_32_bits(pci_addr), | ||||||
|  | 	       pcie->ctrl_base + PCIE_ATU_UPPER_TARGET); | ||||||
|  | 	writel(type, pcie->ctrl_base + PCIE_ATU_CR1); | ||||||
|  | 	writel(PCIE_ATU_ENABLE, pcie->ctrl_base + PCIE_ATU_CR2); | ||||||
|  | } | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * set_cfg_address() - Configure the PCIe controller config space access |  * set_cfg_address() - Configure the PCIe controller config space access | ||||||
|  * |  * | ||||||
| @@ -143,27 +175,29 @@ static uintptr_t set_cfg_address(struct pcie_dw_mvebu *pcie, | |||||||
| 				 pci_dev_t d, uint where) | 				 pci_dev_t d, uint where) | ||||||
| { | { | ||||||
| 	uintptr_t va_address; | 	uintptr_t va_address; | ||||||
|  | 	u32 atu_type; | ||||||
|  |  | ||||||
| 	/* | 	/* | ||||||
| 	 * Region #0 is used for Outbound CFG space access. | 	 * Region #0 is used for Outbound CFG space access. | ||||||
| 	 * Direction = Outbound | 	 * Direction = Outbound | ||||||
| 	 * Region Index = 0 | 	 * Region Index = 0 | ||||||
| 	 */ | 	 */ | ||||||
| 	writel(0, pcie->ctrl_base + PCIE_ATU_VIEWPORT); |  | ||||||
|  |  | ||||||
| 	if (PCI_BUS(d) == (pcie->first_busno + 1)) | 	if (PCI_BUS(d) == (pcie->first_busno + 1)) | ||||||
| 		/* For local bus, change TLP Type field to 4. */ | 		/* For local bus, change TLP Type field to 4. */ | ||||||
| 		writel(PCIE_ATU_TYPE_CFG0, pcie->ctrl_base + PCIE_ATU_CR1); | 		atu_type = PCIE_ATU_TYPE_CFG0; | ||||||
| 	else | 	else | ||||||
| 		/* Otherwise, change TLP Type field to 5. */ | 		/* Otherwise, change TLP Type field to 5. */ | ||||||
| 		writel(PCIE_ATU_TYPE_CFG1, pcie->ctrl_base + PCIE_ATU_CR1); | 		atu_type = PCIE_ATU_TYPE_CFG1; | ||||||
|  |  | ||||||
| 	if (PCI_BUS(d) == pcie->first_busno) { | 	if (PCI_BUS(d) == pcie->first_busno) { | ||||||
| 		/* Accessing root port configuration space. */ | 		/* Accessing root port configuration space. */ | ||||||
| 		va_address = (uintptr_t)pcie->ctrl_base; | 		va_address = (uintptr_t)pcie->ctrl_base; | ||||||
| 	} else { | 	} else { | ||||||
| 		d = PCI_MASK_BUS(d) | (PCI_BUS(d) - pcie->first_busno); | 		d = PCI_MASK_BUS(d) | (PCI_BUS(d) - pcie->first_busno); | ||||||
| 		writel(d << 8, pcie->ctrl_base + PCIE_ATU_LOWER_TARGET); | 		pcie_dw_prog_outbound_atu(pcie, PCIE_ATU_REGION_INDEX0, | ||||||
|  | 					  atu_type, (u64)pcie->cfg_base, | ||||||
|  | 					  d << 8, pcie->cfg_size); | ||||||
| 		va_address = (uintptr_t)pcie->cfg_base; | 		va_address = (uintptr_t)pcie->cfg_base; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -231,6 +265,10 @@ static int pcie_dw_mvebu_read_config(struct udevice *bus, pci_dev_t bdf, | |||||||
| 	debug("(addr,val)=(0x%04x, 0x%08lx)\n", offset, value); | 	debug("(addr,val)=(0x%04x, 0x%08lx)\n", offset, value); | ||||||
| 	*valuep = pci_conv_32_to_size(value, offset, size); | 	*valuep = pci_conv_32_to_size(value, offset, size); | ||||||
|  |  | ||||||
|  | 	pcie_dw_prog_outbound_atu(pcie, PCIE_ATU_REGION_INDEX0, | ||||||
|  | 				  PCIE_ATU_TYPE_IO, pcie->io.phys_start, | ||||||
|  | 				  pcie->io.bus_start, pcie->io.size); | ||||||
|  |  | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -272,6 +310,10 @@ static int pcie_dw_mvebu_write_config(struct udevice *bus, pci_dev_t bdf, | |||||||
| 	value = pci_conv_size_to_32(old, value, offset, size); | 	value = pci_conv_size_to_32(old, value, offset, size); | ||||||
| 	writel(value, va_address); | 	writel(value, va_address); | ||||||
|  |  | ||||||
|  | 	pcie_dw_prog_outbound_atu(pcie, PCIE_ATU_REGION_INDEX0, | ||||||
|  | 				  PCIE_ATU_TYPE_IO, pcie->io.phys_start, | ||||||
|  | 				  pcie->io.bus_start, pcie->io.size); | ||||||
|  |  | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -387,34 +429,6 @@ static int pcie_dw_mvebu_pcie_link_up(const void *regs_base, u32 cap_speed) | |||||||
| 	return 1; | 	return 1; | ||||||
| } | } | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * pcie_dw_regions_setup() - iATU region setup |  | ||||||
|  * |  | ||||||
|  * @pcie: Pointer to the PCI controller state |  | ||||||
|  * |  | ||||||
|  * Configure the iATU regions in the PCIe controller for outbound access. |  | ||||||
|  */ |  | ||||||
| static void pcie_dw_regions_setup(struct pcie_dw_mvebu *pcie) |  | ||||||
| { |  | ||||||
| 	/* |  | ||||||
| 	 * Region #0 is used for Outbound CFG space access. |  | ||||||
| 	 * Direction = Outbound |  | ||||||
| 	 * Region Index = 0 |  | ||||||
| 	 */ |  | ||||||
| 	writel(0, pcie->ctrl_base + PCIE_ATU_VIEWPORT); |  | ||||||
|  |  | ||||||
| 	writel((u32)(uintptr_t)pcie->cfg_base, pcie->ctrl_base |  | ||||||
| 	       + PCIE_ATU_LOWER_BASE); |  | ||||||
| 	writel(0, pcie->ctrl_base + PCIE_ATU_UPPER_BASE); |  | ||||||
| 	writel((u32)(uintptr_t)pcie->cfg_base + pcie->cfg_size, |  | ||||||
| 	       pcie->ctrl_base + PCIE_ATU_LIMIT); |  | ||||||
|  |  | ||||||
| 	writel(0, pcie->ctrl_base + PCIE_ATU_LOWER_TARGET); |  | ||||||
| 	writel(0, pcie->ctrl_base + PCIE_ATU_UPPER_TARGET); |  | ||||||
| 	writel(PCIE_ATU_TYPE_CFG0, pcie->ctrl_base + PCIE_ATU_CR1); |  | ||||||
| 	writel(PCIE_ATU_ENABLE, pcie->ctrl_base + PCIE_ATU_CR2); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * pcie_dw_set_host_bars() - Configure the host BARs |  * pcie_dw_set_host_bars() - Configure the host BARs | ||||||
|  * |  * | ||||||
| @@ -495,7 +509,18 @@ static int pcie_dw_mvebu_probe(struct udevice *dev) | |||||||
| 		       hose->first_busno); | 		       hose->first_busno); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	pcie_dw_regions_setup(pcie); | 	/* Store the IO and MEM windows settings for future use by the ATU */ | ||||||
|  | 	pcie->io.phys_start = hose->regions[0].phys_start; /* IO base */ | ||||||
|  | 	pcie->io.bus_start  = hose->regions[0].bus_start;  /* IO_bus_addr */ | ||||||
|  | 	pcie->io.size	    = hose->regions[0].size;	   /* IO size */ | ||||||
|  |  | ||||||
|  | 	pcie->mem.phys_start = hose->regions[1].phys_start; /* MEM base */ | ||||||
|  | 	pcie->mem.bus_start  = hose->regions[1].bus_start;  /* MEM_bus_addr */ | ||||||
|  | 	pcie->mem.size	     = hose->regions[1].size;	    /* MEM size */ | ||||||
|  |  | ||||||
|  | 	pcie_dw_prog_outbound_atu(pcie, PCIE_ATU_REGION_INDEX1, | ||||||
|  | 				  PCIE_ATU_TYPE_MEM, pcie->mem.phys_start, | ||||||
|  | 				  pcie->mem.bus_start, pcie->mem.size); | ||||||
|  |  | ||||||
| 	/* Set the CLASS_REV of RC CFG header to PCI_CLASS_BRIDGE_PCI */ | 	/* Set the CLASS_REV of RC CFG header to PCI_CLASS_BRIDGE_PCI */ | ||||||
| 	clrsetbits_le32(pcie->ctrl_base + PCI_CLASS_REVISION, | 	clrsetbits_le32(pcie->ctrl_base + PCI_CLASS_REVISION, | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user