dm: pci: Add a function to read a PCI BAR
At present PCI address transaction is not supported so drivers must manually read the correct BAR after reading the device tree info. The ns16550 has a suitable implementation, so move this code into the core DM support. Note that there is no live-tree equivalent at present. Signed-off-by: Simon Glass <sjg@chromium.org> Reviewed-by: Bin Meng <bmeng.cn@gmail.com> Tested-by: Bin Meng <bmeng.cn@gmail.com> [bmeng: correct the unclear comments in test.dts] Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
This commit is contained in:
		
							parent
							
								
									6a73cf3d8f
								
							
						
					
					
						commit
						33c215af4b
					
				| 
						 | 
					@ -456,12 +456,15 @@
 | 
				
			||||||
		};
 | 
							};
 | 
				
			||||||
		pci@1,0 {
 | 
							pci@1,0 {
 | 
				
			||||||
			compatible = "pci-generic";
 | 
								compatible = "pci-generic";
 | 
				
			||||||
			reg = <0x0800 0 0 0 0>;
 | 
								/* reg 0 is at 0x14, using FDT_PCI_SPACE_MEM32 */
 | 
				
			||||||
 | 
								reg = <0x02000814 0 0 0 0
 | 
				
			||||||
 | 
								       0x01000810 0 0 0 0>;
 | 
				
			||||||
			sandbox,emul = <&swap_case_emul0_1>;
 | 
								sandbox,emul = <&swap_case_emul0_1>;
 | 
				
			||||||
		};
 | 
							};
 | 
				
			||||||
		pci@1f,0 {
 | 
							pci@1f,0 {
 | 
				
			||||||
			compatible = "pci-generic";
 | 
								compatible = "pci-generic";
 | 
				
			||||||
			reg = <0xf800 0 0 0 0>;
 | 
								/* reg 0 is at 0x10, using FDT_PCI_SPACE_IO */
 | 
				
			||||||
 | 
								reg = <0x0100f810 0 0 0 0>;
 | 
				
			||||||
			sandbox,emul = <&swap_case_emul0_1f>;
 | 
								sandbox,emul = <&swap_case_emul0_1f>;
 | 
				
			||||||
		};
 | 
							};
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -190,3 +190,36 @@ void *devfdt_map_physmem(struct udevice *dev, unsigned long size)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return map_physmem(addr, size, MAP_NOCACHE);
 | 
						return map_physmem(addr, size, MAP_NOCACHE);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fdt_addr_t devfdt_get_addr_pci(struct udevice *dev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						ulong addr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						addr = devfdt_get_addr(dev);
 | 
				
			||||||
 | 
						if (CONFIG_IS_ENABLED(PCI) && IS_ENABLED(CONFIG_DM_PCI) &&
 | 
				
			||||||
 | 
						    addr == FDT_ADDR_T_NONE) {
 | 
				
			||||||
 | 
							struct fdt_pci_addr pci_addr;
 | 
				
			||||||
 | 
							u32 bar;
 | 
				
			||||||
 | 
							int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ret = fdtdec_get_pci_addr(gd->fdt_blob,
 | 
				
			||||||
 | 
										  dev_of_offset(dev),
 | 
				
			||||||
 | 
										  FDT_PCI_SPACE_MEM32, "reg",
 | 
				
			||||||
 | 
										  &pci_addr);
 | 
				
			||||||
 | 
							if (ret) {
 | 
				
			||||||
 | 
								/* try if there is any i/o-mapped register */
 | 
				
			||||||
 | 
								ret = fdtdec_get_pci_addr(gd->fdt_blob,
 | 
				
			||||||
 | 
											  dev_of_offset(dev),
 | 
				
			||||||
 | 
											  FDT_PCI_SPACE_IO, "reg",
 | 
				
			||||||
 | 
											  &pci_addr);
 | 
				
			||||||
 | 
								if (ret)
 | 
				
			||||||
 | 
									return FDT_ADDR_T_NONE;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							ret = fdtdec_get_pci_bar32(dev, &pci_addr, &bar);
 | 
				
			||||||
 | 
							if (ret)
 | 
				
			||||||
 | 
								return FDT_ADDR_T_NONE;
 | 
				
			||||||
 | 
							addr = bar;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return addr;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -307,3 +307,14 @@ int dev_read_alias_highest_id(const char *stem)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return fdtdec_get_alias_highest_id(gd->fdt_blob, stem);
 | 
						return fdtdec_get_alias_highest_id(gd->fdt_blob, stem);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fdt_addr_t dev_read_addr_pci(struct udevice *dev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						ulong addr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						addr = dev_read_addr(dev);
 | 
				
			||||||
 | 
						if (addr == FDT_ADDR_T_NONE && !of_live_active())
 | 
				
			||||||
 | 
							addr = devfdt_get_addr_pci(dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return addr;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -440,36 +440,7 @@ int ns16550_serial_ofdata_to_platdata(struct udevice *dev)
 | 
				
			||||||
	int err;
 | 
						int err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* try Processor Local Bus device first */
 | 
						/* try Processor Local Bus device first */
 | 
				
			||||||
	addr = dev_read_addr(dev);
 | 
						addr = dev_read_addr_pci(dev);
 | 
				
			||||||
#if CONFIG_IS_ENABLED(PCI) && defined(CONFIG_DM_PCI)
 | 
					 | 
				
			||||||
	if (addr == FDT_ADDR_T_NONE) {
 | 
					 | 
				
			||||||
		/* then try pci device */
 | 
					 | 
				
			||||||
		struct fdt_pci_addr pci_addr;
 | 
					 | 
				
			||||||
		u32 bar;
 | 
					 | 
				
			||||||
		int ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		/* we prefer to use a memory-mapped register */
 | 
					 | 
				
			||||||
		ret = fdtdec_get_pci_addr(gd->fdt_blob, dev_of_offset(dev),
 | 
					 | 
				
			||||||
					  FDT_PCI_SPACE_MEM32, "reg",
 | 
					 | 
				
			||||||
					  &pci_addr);
 | 
					 | 
				
			||||||
		if (ret) {
 | 
					 | 
				
			||||||
			/* try if there is any i/o-mapped register */
 | 
					 | 
				
			||||||
			ret = fdtdec_get_pci_addr(gd->fdt_blob,
 | 
					 | 
				
			||||||
						  dev_of_offset(dev),
 | 
					 | 
				
			||||||
						  FDT_PCI_SPACE_IO,
 | 
					 | 
				
			||||||
						  "reg", &pci_addr);
 | 
					 | 
				
			||||||
			if (ret)
 | 
					 | 
				
			||||||
				return ret;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		ret = fdtdec_get_pci_bar32(dev, &pci_addr, &bar);
 | 
					 | 
				
			||||||
		if (ret)
 | 
					 | 
				
			||||||
			return ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		addr = bar;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (addr == FDT_ADDR_T_NONE)
 | 
						if (addr == FDT_ADDR_T_NONE)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -138,4 +138,12 @@ fdt_addr_t devfdt_get_addr_name(struct udevice *dev, const char *name);
 | 
				
			||||||
fdt_addr_t devfdt_get_addr_size_name(struct udevice *dev, const char *name,
 | 
					fdt_addr_t devfdt_get_addr_size_name(struct udevice *dev, const char *name,
 | 
				
			||||||
				     fdt_size_t *size);
 | 
									     fdt_size_t *size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * devfdt_get_addr_pci() - Read an address and handle PCI address translation
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @dev: Device to read from
 | 
				
			||||||
 | 
					 * @return address or FDT_ADDR_T_NONE if not found
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					fdt_addr_t devfdt_get_addr_pci(struct udevice *dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -248,6 +248,26 @@ fdt_addr_t dev_read_addr(struct udevice *dev);
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
void *dev_read_addr_ptr(struct udevice *dev);
 | 
					void *dev_read_addr_ptr(struct udevice *dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * dev_read_addr_pci() - Read an address and handle PCI address translation
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * At present U-Boot does not have address translation logic for PCI in the
 | 
				
			||||||
 | 
					 * livetree implementation (of_addr.c). This special function supports this for
 | 
				
			||||||
 | 
					 * the flat tree implementation.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This function should be removed (and code should use dev_read() instead)
 | 
				
			||||||
 | 
					 * once:
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 1. PCI address translation is added; and either
 | 
				
			||||||
 | 
					 * 2. everything uses livetree where PCI translation is used (which is feasible
 | 
				
			||||||
 | 
					 *    in SPL and U-Boot proper) or PCI address translation is added to
 | 
				
			||||||
 | 
					 *    fdtdec_get_addr() and friends.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @dev: Device to read from
 | 
				
			||||||
 | 
					 * @return address or FDT_ADDR_T_NONE if not found
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					fdt_addr_t dev_read_addr_pci(struct udevice *dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * dev_remap_addr() - Get the reg property of a device as a
 | 
					 * dev_remap_addr() - Get the reg property of a device as a
 | 
				
			||||||
 *                         memory-mapped I/O pointer
 | 
					 *                         memory-mapped I/O pointer
 | 
				
			||||||
| 
						 | 
					@ -691,6 +711,11 @@ static inline void *dev_read_addr_ptr(struct udevice *dev)
 | 
				
			||||||
	return devfdt_get_addr_ptr(dev);
 | 
						return devfdt_get_addr_ptr(dev);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline fdt_addr_t dev_read_addr_pci(struct udevice *dev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return devfdt_get_addr_pci(dev);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline void *dev_remap_addr(struct udevice *dev)
 | 
					static inline void *dev_remap_addr(struct udevice *dev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return devfdt_remap_addr(dev);
 | 
						return devfdt_remap_addr(dev);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -294,3 +294,48 @@ static int dm_test_pci_ea(struct unit_test_state *uts)
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
DM_TEST(dm_test_pci_ea, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
 | 
					DM_TEST(dm_test_pci_ea, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Test the dev_read_addr_pci() function */
 | 
				
			||||||
 | 
					static int dm_test_pci_addr_flat(struct unit_test_state *uts)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct udevice *swap1f, *swap1;
 | 
				
			||||||
 | 
						ulong io_addr, mem_addr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ut_assertok(dm_pci_bus_find_bdf(PCI_BDF(0, 0x1f, 0), &swap1f));
 | 
				
			||||||
 | 
						io_addr = dm_pci_read_bar32(swap1f, 0);
 | 
				
			||||||
 | 
						ut_asserteq(io_addr, dev_read_addr_pci(swap1f));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * This device has both I/O and MEM spaces but the MEM space appears
 | 
				
			||||||
 | 
						 * first
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						ut_assertok(dm_pci_bus_find_bdf(PCI_BDF(0, 0x1, 0), &swap1));
 | 
				
			||||||
 | 
						mem_addr = dm_pci_read_bar32(swap1, 1);
 | 
				
			||||||
 | 
						ut_asserteq(mem_addr, dev_read_addr_pci(swap1));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					DM_TEST(dm_test_pci_addr_flat, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT |
 | 
				
			||||||
 | 
							DM_TESTF_FLAT_TREE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Test the dev_read_addr_pci() function with livetree. That function is
 | 
				
			||||||
 | 
					 * not currently fully implemented, in that it fails to return the BAR address.
 | 
				
			||||||
 | 
					 * Once that is implemented this test can be removed and dm_test_pci_addr_flat()
 | 
				
			||||||
 | 
					 * can be used for both flattree and livetree by removing the DM_TESTF_FLAT_TREE
 | 
				
			||||||
 | 
					 * flag above.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static int dm_test_pci_addr_live(struct unit_test_state *uts)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct udevice *swap1f, *swap1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ut_assertok(dm_pci_bus_find_bdf(PCI_BDF(0, 0x1f, 0), &swap1f));
 | 
				
			||||||
 | 
						ut_asserteq(FDT_ADDR_T_NONE, dev_read_addr_pci(swap1f));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ut_assertok(dm_pci_bus_find_bdf(PCI_BDF(0, 0x1, 0), &swap1));
 | 
				
			||||||
 | 
						ut_asserteq(FDT_ADDR_T_NONE, dev_read_addr_pci(swap1));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					DM_TEST(dm_test_pci_addr_live, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT |
 | 
				
			||||||
 | 
							DM_TESTF_LIVE_TREE);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue