xref: /openbmc/u-boot/cmd/pci.c (revision e8f80a5a)
1*83d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
22e192b24SSimon Glass /*
32e192b24SSimon Glass  * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
42e192b24SSimon Glass  * Andreas Heppel <aheppel@sysgo.de>
52e192b24SSimon Glass  *
62e192b24SSimon Glass  * (C) Copyright 2002
72e192b24SSimon Glass  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
82e192b24SSimon Glass  * Wolfgang Grandegger, DENX Software Engineering, wg@denx.de.
92e192b24SSimon Glass  */
102e192b24SSimon Glass 
112e192b24SSimon Glass /*
122e192b24SSimon Glass  * PCI routines
132e192b24SSimon Glass  */
142e192b24SSimon Glass 
152e192b24SSimon Glass #include <common.h>
162e192b24SSimon Glass #include <bootretry.h>
172e192b24SSimon Glass #include <cli.h>
182e192b24SSimon Glass #include <command.h>
192e192b24SSimon Glass #include <console.h>
202e192b24SSimon Glass #include <dm.h>
212e192b24SSimon Glass #include <asm/processor.h>
222e192b24SSimon Glass #include <asm/io.h>
232e192b24SSimon Glass #include <pci.h>
242e192b24SSimon Glass 
252e192b24SSimon Glass struct pci_reg_info {
262e192b24SSimon Glass 	const char *name;
272e192b24SSimon Glass 	enum pci_size_t size;
282e192b24SSimon Glass 	u8 offset;
292e192b24SSimon Glass };
302e192b24SSimon Glass 
pci_byte_size(enum pci_size_t size)312e192b24SSimon Glass static int pci_byte_size(enum pci_size_t size)
322e192b24SSimon Glass {
332e192b24SSimon Glass 	switch (size) {
342e192b24SSimon Glass 	case PCI_SIZE_8:
352e192b24SSimon Glass 		return 1;
362e192b24SSimon Glass 	case PCI_SIZE_16:
372e192b24SSimon Glass 		return 2;
382e192b24SSimon Glass 	case PCI_SIZE_32:
392e192b24SSimon Glass 	default:
402e192b24SSimon Glass 		return 4;
412e192b24SSimon Glass 	}
422e192b24SSimon Glass }
432e192b24SSimon Glass 
pci_field_width(enum pci_size_t size)442e192b24SSimon Glass static int pci_field_width(enum pci_size_t size)
452e192b24SSimon Glass {
462e192b24SSimon Glass 	return pci_byte_size(size) * 2;
472e192b24SSimon Glass }
482e192b24SSimon Glass 
492e192b24SSimon Glass #ifdef CONFIG_DM_PCI
pci_show_regs(struct udevice * dev,struct pci_reg_info * regs)502e192b24SSimon Glass static void pci_show_regs(struct udevice *dev, struct pci_reg_info *regs)
512e192b24SSimon Glass {
522e192b24SSimon Glass 	for (; regs->name; regs++) {
532e192b24SSimon Glass 		unsigned long val;
542e192b24SSimon Glass 
552e192b24SSimon Glass 		dm_pci_read_config(dev, regs->offset, &val, regs->size);
562e192b24SSimon Glass 		printf("  %s =%*s%#.*lx\n", regs->name,
572e192b24SSimon Glass 		       (int)(28 - strlen(regs->name)), "",
582e192b24SSimon Glass 		       pci_field_width(regs->size), val);
592e192b24SSimon Glass 	}
602e192b24SSimon Glass }
612e192b24SSimon Glass #else
pci_read_config(pci_dev_t dev,int offset,enum pci_size_t size)622e192b24SSimon Glass static unsigned long pci_read_config(pci_dev_t dev, int offset,
632e192b24SSimon Glass 				     enum pci_size_t size)
642e192b24SSimon Glass {
652e192b24SSimon Glass 	u32 val32;
662e192b24SSimon Glass 	u16 val16;
672e192b24SSimon Glass 	u8 val8;
682e192b24SSimon Glass 
692e192b24SSimon Glass 	switch (size) {
702e192b24SSimon Glass 	case PCI_SIZE_8:
712e192b24SSimon Glass 		pci_read_config_byte(dev, offset, &val8);
722e192b24SSimon Glass 		return val8;
732e192b24SSimon Glass 	case PCI_SIZE_16:
742e192b24SSimon Glass 		pci_read_config_word(dev, offset, &val16);
752e192b24SSimon Glass 		return val16;
762e192b24SSimon Glass 	case PCI_SIZE_32:
772e192b24SSimon Glass 	default:
782e192b24SSimon Glass 		pci_read_config_dword(dev, offset, &val32);
792e192b24SSimon Glass 		return val32;
802e192b24SSimon Glass 	}
812e192b24SSimon Glass }
822e192b24SSimon Glass 
pci_show_regs(pci_dev_t dev,struct pci_reg_info * regs)832e192b24SSimon Glass static void pci_show_regs(pci_dev_t dev, struct pci_reg_info *regs)
842e192b24SSimon Glass {
852e192b24SSimon Glass 	for (; regs->name; regs++) {
862e192b24SSimon Glass 		printf("  %s =%*s%#.*lx\n", regs->name,
872e192b24SSimon Glass 		       (int)(28 - strlen(regs->name)), "",
882e192b24SSimon Glass 		       pci_field_width(regs->size),
892e192b24SSimon Glass 		       pci_read_config(dev, regs->offset, regs->size));
902e192b24SSimon Glass 	}
912e192b24SSimon Glass }
922e192b24SSimon Glass #endif
932e192b24SSimon Glass 
94e5f96a87SYehuda Yitschak #ifdef CONFIG_DM_PCI
pci_bar_show(struct udevice * dev)95e5f96a87SYehuda Yitschak int pci_bar_show(struct udevice *dev)
96e5f96a87SYehuda Yitschak {
97e5f96a87SYehuda Yitschak 	u8 header_type;
98e5f96a87SYehuda Yitschak 	int bar_cnt, bar_id, mem_type;
99e5f96a87SYehuda Yitschak 	bool is_64, is_io;
100e5f96a87SYehuda Yitschak 	u32 base_low, base_high;
101e5f96a87SYehuda Yitschak 	u32 size_low, size_high;
102e5f96a87SYehuda Yitschak 	u64 base, size;
103e5f96a87SYehuda Yitschak 	u32 reg_addr;
104e5f96a87SYehuda Yitschak 	int prefetchable;
105e5f96a87SYehuda Yitschak 
106e5f96a87SYehuda Yitschak 	dm_pci_read_config8(dev, PCI_HEADER_TYPE, &header_type);
107e5f96a87SYehuda Yitschak 
108e5f96a87SYehuda Yitschak 	if (header_type == PCI_HEADER_TYPE_CARDBUS) {
109e5f96a87SYehuda Yitschak 		printf("CardBus doesn't support BARs\n");
110e5f96a87SYehuda Yitschak 		return -ENOSYS;
111e5f96a87SYehuda Yitschak 	}
112e5f96a87SYehuda Yitschak 
113e5f96a87SYehuda Yitschak 	bar_cnt = (header_type == PCI_HEADER_TYPE_NORMAL) ? 6 : 2;
114e5f96a87SYehuda Yitschak 
115e5f96a87SYehuda Yitschak 	printf("ID   Base                Size                Width  Type\n");
116e5f96a87SYehuda Yitschak 	printf("----------------------------------------------------------\n");
117e5f96a87SYehuda Yitschak 
118e5f96a87SYehuda Yitschak 	bar_id = 0;
119e5f96a87SYehuda Yitschak 	reg_addr = PCI_BASE_ADDRESS_0;
120e5f96a87SYehuda Yitschak 	while (bar_cnt) {
121e5f96a87SYehuda Yitschak 		dm_pci_read_config32(dev, reg_addr, &base_low);
122e5f96a87SYehuda Yitschak 		dm_pci_write_config32(dev, reg_addr, 0xffffffff);
123e5f96a87SYehuda Yitschak 		dm_pci_read_config32(dev, reg_addr, &size_low);
124e5f96a87SYehuda Yitschak 		dm_pci_write_config32(dev, reg_addr, base_low);
125e5f96a87SYehuda Yitschak 		reg_addr += 4;
126e5f96a87SYehuda Yitschak 
127e5f96a87SYehuda Yitschak 		base = base_low & ~0xf;
128e5f96a87SYehuda Yitschak 		size = size_low & ~0xf;
129e5f96a87SYehuda Yitschak 		base_high = 0x0;
130e5f96a87SYehuda Yitschak 		size_high = 0xffffffff;
131e5f96a87SYehuda Yitschak 		is_64 = 0;
132e5f96a87SYehuda Yitschak 		prefetchable = base_low & PCI_BASE_ADDRESS_MEM_PREFETCH;
133e5f96a87SYehuda Yitschak 		is_io = base_low & PCI_BASE_ADDRESS_SPACE_IO;
134e5f96a87SYehuda Yitschak 		mem_type = base_low & PCI_BASE_ADDRESS_MEM_TYPE_MASK;
135e5f96a87SYehuda Yitschak 
136e5f96a87SYehuda Yitschak 		if (mem_type == PCI_BASE_ADDRESS_MEM_TYPE_64) {
137e5f96a87SYehuda Yitschak 			dm_pci_read_config32(dev, reg_addr, &base_high);
138e5f96a87SYehuda Yitschak 			dm_pci_write_config32(dev, reg_addr, 0xffffffff);
139e5f96a87SYehuda Yitschak 			dm_pci_read_config32(dev, reg_addr, &size_high);
140e5f96a87SYehuda Yitschak 			dm_pci_write_config32(dev, reg_addr, base_high);
141e5f96a87SYehuda Yitschak 			bar_cnt--;
142e5f96a87SYehuda Yitschak 			reg_addr += 4;
143e5f96a87SYehuda Yitschak 			is_64 = 1;
144e5f96a87SYehuda Yitschak 		}
145e5f96a87SYehuda Yitschak 
146e5f96a87SYehuda Yitschak 		base = base | ((u64)base_high << 32);
147e5f96a87SYehuda Yitschak 		size = size | ((u64)size_high << 32);
148e5f96a87SYehuda Yitschak 
149e5f96a87SYehuda Yitschak 		if ((!is_64 && size_low) || (is_64 && size)) {
150e5f96a87SYehuda Yitschak 			size = ~size + 1;
151e5f96a87SYehuda Yitschak 			printf(" %d   %#016llx  %#016llx  %d     %s   %s\n",
15284d7f916SSimon Glass 			       bar_id, (unsigned long long)base,
15384d7f916SSimon Glass 			       (unsigned long long)size, is_64 ? 64 : 32,
154e5f96a87SYehuda Yitschak 			       is_io ? "I/O" : "MEM",
155e5f96a87SYehuda Yitschak 			       prefetchable ? "Prefetchable" : "");
156e5f96a87SYehuda Yitschak 		}
157e5f96a87SYehuda Yitschak 
158e5f96a87SYehuda Yitschak 		bar_id++;
159e5f96a87SYehuda Yitschak 		bar_cnt--;
160e5f96a87SYehuda Yitschak 	}
161e5f96a87SYehuda Yitschak 
162e5f96a87SYehuda Yitschak 	return 0;
163e5f96a87SYehuda Yitschak }
164e5f96a87SYehuda Yitschak #endif
165e5f96a87SYehuda Yitschak 
1662e192b24SSimon Glass static struct pci_reg_info regs_start[] = {
1672e192b24SSimon Glass 	{ "vendor ID", PCI_SIZE_16, PCI_VENDOR_ID },
1682e192b24SSimon Glass 	{ "device ID", PCI_SIZE_16, PCI_DEVICE_ID },
1692e192b24SSimon Glass 	{ "command register ID", PCI_SIZE_16, PCI_COMMAND },
1702e192b24SSimon Glass 	{ "status register", PCI_SIZE_16, PCI_STATUS },
1712e192b24SSimon Glass 	{ "revision ID", PCI_SIZE_8, PCI_REVISION_ID },
1722e192b24SSimon Glass 	{},
1732e192b24SSimon Glass };
1742e192b24SSimon Glass 
1752e192b24SSimon Glass static struct pci_reg_info regs_rest[] = {
1762e192b24SSimon Glass 	{ "sub class code", PCI_SIZE_8, PCI_CLASS_SUB_CODE },
1772e192b24SSimon Glass 	{ "programming interface", PCI_SIZE_8, PCI_CLASS_PROG },
1782e192b24SSimon Glass 	{ "cache line", PCI_SIZE_8, PCI_CACHE_LINE_SIZE },
1792e192b24SSimon Glass 	{ "latency time", PCI_SIZE_8, PCI_LATENCY_TIMER },
1802e192b24SSimon Glass 	{ "header type", PCI_SIZE_8, PCI_HEADER_TYPE },
1812e192b24SSimon Glass 	{ "BIST", PCI_SIZE_8, PCI_BIST },
1822e192b24SSimon Glass 	{ "base address 0", PCI_SIZE_32, PCI_BASE_ADDRESS_0 },
1832e192b24SSimon Glass 	{},
1842e192b24SSimon Glass };
1852e192b24SSimon Glass 
1862e192b24SSimon Glass static struct pci_reg_info regs_normal[] = {
1872e192b24SSimon Glass 	{ "base address 1", PCI_SIZE_32, PCI_BASE_ADDRESS_1 },
1882e192b24SSimon Glass 	{ "base address 2", PCI_SIZE_32, PCI_BASE_ADDRESS_2 },
1892e192b24SSimon Glass 	{ "base address 3", PCI_SIZE_32, PCI_BASE_ADDRESS_3 },
1902e192b24SSimon Glass 	{ "base address 4", PCI_SIZE_32, PCI_BASE_ADDRESS_4 },
1912e192b24SSimon Glass 	{ "base address 5", PCI_SIZE_32, PCI_BASE_ADDRESS_5 },
1922e192b24SSimon Glass 	{ "cardBus CIS pointer", PCI_SIZE_32, PCI_CARDBUS_CIS },
1932e192b24SSimon Glass 	{ "sub system vendor ID", PCI_SIZE_16, PCI_SUBSYSTEM_VENDOR_ID },
1942e192b24SSimon Glass 	{ "sub system ID", PCI_SIZE_16, PCI_SUBSYSTEM_ID },
1952e192b24SSimon Glass 	{ "expansion ROM base address", PCI_SIZE_32, PCI_ROM_ADDRESS },
1962e192b24SSimon Glass 	{ "interrupt line", PCI_SIZE_8, PCI_INTERRUPT_LINE },
1972e192b24SSimon Glass 	{ "interrupt pin", PCI_SIZE_8, PCI_INTERRUPT_PIN },
1982e192b24SSimon Glass 	{ "min Grant", PCI_SIZE_8, PCI_MIN_GNT },
1992e192b24SSimon Glass 	{ "max Latency", PCI_SIZE_8, PCI_MAX_LAT },
2002e192b24SSimon Glass 	{},
2012e192b24SSimon Glass };
2022e192b24SSimon Glass 
2032e192b24SSimon Glass static struct pci_reg_info regs_bridge[] = {
2042e192b24SSimon Glass 	{ "base address 1", PCI_SIZE_32, PCI_BASE_ADDRESS_1 },
2052e192b24SSimon Glass 	{ "primary bus number", PCI_SIZE_8, PCI_PRIMARY_BUS },
2062e192b24SSimon Glass 	{ "secondary bus number", PCI_SIZE_8, PCI_SECONDARY_BUS },
2072e192b24SSimon Glass 	{ "subordinate bus number", PCI_SIZE_8, PCI_SUBORDINATE_BUS },
2082e192b24SSimon Glass 	{ "secondary latency timer", PCI_SIZE_8, PCI_SEC_LATENCY_TIMER },
2092e192b24SSimon Glass 	{ "IO base", PCI_SIZE_8, PCI_IO_BASE },
2102e192b24SSimon Glass 	{ "IO limit", PCI_SIZE_8, PCI_IO_LIMIT },
2112e192b24SSimon Glass 	{ "secondary status", PCI_SIZE_16, PCI_SEC_STATUS },
2122e192b24SSimon Glass 	{ "memory base", PCI_SIZE_16, PCI_MEMORY_BASE },
2132e192b24SSimon Glass 	{ "memory limit", PCI_SIZE_16, PCI_MEMORY_LIMIT },
2142e192b24SSimon Glass 	{ "prefetch memory base", PCI_SIZE_16, PCI_PREF_MEMORY_BASE },
2152e192b24SSimon Glass 	{ "prefetch memory limit", PCI_SIZE_16, PCI_PREF_MEMORY_LIMIT },
2162e192b24SSimon Glass 	{ "prefetch memory base upper", PCI_SIZE_32, PCI_PREF_BASE_UPPER32 },
2172e192b24SSimon Glass 	{ "prefetch memory limit upper", PCI_SIZE_32, PCI_PREF_LIMIT_UPPER32 },
2182e192b24SSimon Glass 	{ "IO base upper 16 bits", PCI_SIZE_16, PCI_IO_BASE_UPPER16 },
2192e192b24SSimon Glass 	{ "IO limit upper 16 bits", PCI_SIZE_16, PCI_IO_LIMIT_UPPER16 },
2202e192b24SSimon Glass 	{ "expansion ROM base address", PCI_SIZE_32, PCI_ROM_ADDRESS1 },
2212e192b24SSimon Glass 	{ "interrupt line", PCI_SIZE_8, PCI_INTERRUPT_LINE },
2222e192b24SSimon Glass 	{ "interrupt pin", PCI_SIZE_8, PCI_INTERRUPT_PIN },
2232e192b24SSimon Glass 	{ "bridge control", PCI_SIZE_16, PCI_BRIDGE_CONTROL },
2242e192b24SSimon Glass 	{},
2252e192b24SSimon Glass };
2262e192b24SSimon Glass 
2272e192b24SSimon Glass static struct pci_reg_info regs_cardbus[] = {
2282e192b24SSimon Glass 	{ "capabilities", PCI_SIZE_8, PCI_CB_CAPABILITY_LIST },
2292e192b24SSimon Glass 	{ "secondary status", PCI_SIZE_16, PCI_CB_SEC_STATUS },
2302e192b24SSimon Glass 	{ "primary bus number", PCI_SIZE_8, PCI_CB_PRIMARY_BUS },
2312e192b24SSimon Glass 	{ "CardBus number", PCI_SIZE_8, PCI_CB_CARD_BUS },
2322e192b24SSimon Glass 	{ "subordinate bus number", PCI_SIZE_8, PCI_CB_SUBORDINATE_BUS },
2332e192b24SSimon Glass 	{ "CardBus latency timer", PCI_SIZE_8, PCI_CB_LATENCY_TIMER },
2342e192b24SSimon Glass 	{ "CardBus memory base 0", PCI_SIZE_32, PCI_CB_MEMORY_BASE_0 },
2352e192b24SSimon Glass 	{ "CardBus memory limit 0", PCI_SIZE_32, PCI_CB_MEMORY_LIMIT_0 },
2362e192b24SSimon Glass 	{ "CardBus memory base 1", PCI_SIZE_32, PCI_CB_MEMORY_BASE_1 },
2372e192b24SSimon Glass 	{ "CardBus memory limit 1", PCI_SIZE_32, PCI_CB_MEMORY_LIMIT_1 },
2382e192b24SSimon Glass 	{ "CardBus IO base 0", PCI_SIZE_16, PCI_CB_IO_BASE_0 },
2392e192b24SSimon Glass 	{ "CardBus IO base high 0", PCI_SIZE_16, PCI_CB_IO_BASE_0_HI },
2402e192b24SSimon Glass 	{ "CardBus IO limit 0", PCI_SIZE_16, PCI_CB_IO_LIMIT_0 },
2412e192b24SSimon Glass 	{ "CardBus IO limit high 0", PCI_SIZE_16, PCI_CB_IO_LIMIT_0_HI },
2422e192b24SSimon Glass 	{ "CardBus IO base 1", PCI_SIZE_16, PCI_CB_IO_BASE_1 },
2432e192b24SSimon Glass 	{ "CardBus IO base high 1", PCI_SIZE_16, PCI_CB_IO_BASE_1_HI },
2442e192b24SSimon Glass 	{ "CardBus IO limit 1", PCI_SIZE_16, PCI_CB_IO_LIMIT_1 },
2452e192b24SSimon Glass 	{ "CardBus IO limit high 1", PCI_SIZE_16, PCI_CB_IO_LIMIT_1_HI },
2462e192b24SSimon Glass 	{ "interrupt line", PCI_SIZE_8, PCI_INTERRUPT_LINE },
2472e192b24SSimon Glass 	{ "interrupt pin", PCI_SIZE_8, PCI_INTERRUPT_PIN },
2482e192b24SSimon Glass 	{ "bridge control", PCI_SIZE_16, PCI_CB_BRIDGE_CONTROL },
2492e192b24SSimon Glass 	{ "subvendor ID", PCI_SIZE_16, PCI_CB_SUBSYSTEM_VENDOR_ID },
2502e192b24SSimon Glass 	{ "subdevice ID", PCI_SIZE_16, PCI_CB_SUBSYSTEM_ID },
2512e192b24SSimon Glass 	{ "PC Card 16bit base address", PCI_SIZE_32, PCI_CB_LEGACY_MODE_BASE },
2522e192b24SSimon Glass 	{},
2532e192b24SSimon Glass };
2542e192b24SSimon Glass 
2552e192b24SSimon Glass /**
2562e192b24SSimon Glass  * pci_header_show() - Show the header of the specified PCI device.
2572e192b24SSimon Glass  *
2582e192b24SSimon Glass  * @dev: Bus+Device+Function number
2592e192b24SSimon Glass  */
2602e192b24SSimon Glass #ifdef CONFIG_DM_PCI
pci_header_show(struct udevice * dev)2612e192b24SSimon Glass void pci_header_show(struct udevice *dev)
2622e192b24SSimon Glass #else
2632e192b24SSimon Glass void pci_header_show(pci_dev_t dev)
2642e192b24SSimon Glass #endif
2652e192b24SSimon Glass {
2662e192b24SSimon Glass #ifdef CONFIG_DM_PCI
2672e192b24SSimon Glass 	unsigned long class, header_type;
2682e192b24SSimon Glass 
2692e192b24SSimon Glass 	dm_pci_read_config(dev, PCI_CLASS_CODE, &class, PCI_SIZE_8);
2702e192b24SSimon Glass 	dm_pci_read_config(dev, PCI_HEADER_TYPE, &header_type, PCI_SIZE_8);
2712e192b24SSimon Glass #else
2722e192b24SSimon Glass 	u8 class, header_type;
2732e192b24SSimon Glass 
2742e192b24SSimon Glass 	pci_read_config_byte(dev, PCI_CLASS_CODE, &class);
2752e192b24SSimon Glass 	pci_read_config_byte(dev, PCI_HEADER_TYPE, &header_type);
2762e192b24SSimon Glass #endif
2772e192b24SSimon Glass 	pci_show_regs(dev, regs_start);
2782e192b24SSimon Glass 	printf("  class code =                  0x%.2x (%s)\n", (int)class,
2792e192b24SSimon Glass 	       pci_class_str(class));
2802e192b24SSimon Glass 	pci_show_regs(dev, regs_rest);
2812e192b24SSimon Glass 
2822e192b24SSimon Glass 	switch (header_type & 0x03) {
2832e192b24SSimon Glass 	case PCI_HEADER_TYPE_NORMAL:	/* "normal" PCI device */
2842e192b24SSimon Glass 		pci_show_regs(dev, regs_normal);
2852e192b24SSimon Glass 		break;
2862e192b24SSimon Glass 	case PCI_HEADER_TYPE_BRIDGE:	/* PCI-to-PCI bridge */
2872e192b24SSimon Glass 		pci_show_regs(dev, regs_bridge);
2882e192b24SSimon Glass 		break;
2892e192b24SSimon Glass 	case PCI_HEADER_TYPE_CARDBUS:	/* PCI-to-CardBus bridge */
2902e192b24SSimon Glass 		pci_show_regs(dev, regs_cardbus);
2912e192b24SSimon Glass 		break;
2922e192b24SSimon Glass 
2932e192b24SSimon Glass 	default:
2942e192b24SSimon Glass 		printf("unknown header\n");
2952e192b24SSimon Glass 		break;
2962e192b24SSimon Glass     }
2972e192b24SSimon Glass }
2982e192b24SSimon Glass 
pciinfo_header(int busnum,bool short_listing)2992e192b24SSimon Glass void pciinfo_header(int busnum, bool short_listing)
3002e192b24SSimon Glass {
3012e192b24SSimon Glass 	printf("Scanning PCI devices on bus %d\n", busnum);
3022e192b24SSimon Glass 
3032e192b24SSimon Glass 	if (short_listing) {
3042e192b24SSimon Glass 		printf("BusDevFun  VendorId   DeviceId   Device Class       Sub-Class\n");
3052e192b24SSimon Glass 		printf("_____________________________________________________________\n");
3062e192b24SSimon Glass 	}
3072e192b24SSimon Glass }
3082e192b24SSimon Glass 
3092e192b24SSimon Glass #ifdef CONFIG_DM_PCI
3102e192b24SSimon Glass /**
3112e192b24SSimon Glass  * pci_header_show_brief() - Show the short-form PCI device header
3122e192b24SSimon Glass  *
3132e192b24SSimon Glass  * Reads and prints the header of the specified PCI device in short form.
3142e192b24SSimon Glass  *
3152e192b24SSimon Glass  * @dev: PCI device to show
3162e192b24SSimon Glass  */
pci_header_show_brief(struct udevice * dev)3172e192b24SSimon Glass static void pci_header_show_brief(struct udevice *dev)
3182e192b24SSimon Glass {
3192e192b24SSimon Glass 	ulong vendor, device;
3202e192b24SSimon Glass 	ulong class, subclass;
3212e192b24SSimon Glass 
3222e192b24SSimon Glass 	dm_pci_read_config(dev, PCI_VENDOR_ID, &vendor, PCI_SIZE_16);
3232e192b24SSimon Glass 	dm_pci_read_config(dev, PCI_DEVICE_ID, &device, PCI_SIZE_16);
3242e192b24SSimon Glass 	dm_pci_read_config(dev, PCI_CLASS_CODE, &class, PCI_SIZE_8);
3252e192b24SSimon Glass 	dm_pci_read_config(dev, PCI_CLASS_SUB_CODE, &subclass, PCI_SIZE_8);
3262e192b24SSimon Glass 
3272e192b24SSimon Glass 	printf("0x%.4lx     0x%.4lx     %-23s 0x%.2lx\n",
3282e192b24SSimon Glass 	       vendor, device,
3292e192b24SSimon Glass 	       pci_class_str(class), subclass);
3302e192b24SSimon Glass }
3312e192b24SSimon Glass 
pciinfo(struct udevice * bus,bool short_listing)3322e192b24SSimon Glass static void pciinfo(struct udevice *bus, bool short_listing)
3332e192b24SSimon Glass {
3342e192b24SSimon Glass 	struct udevice *dev;
3352e192b24SSimon Glass 
3362e192b24SSimon Glass 	pciinfo_header(bus->seq, short_listing);
3372e192b24SSimon Glass 
3382e192b24SSimon Glass 	for (device_find_first_child(bus, &dev);
3392e192b24SSimon Glass 	     dev;
3402e192b24SSimon Glass 	     device_find_next_child(&dev)) {
3412e192b24SSimon Glass 		struct pci_child_platdata *pplat;
3422e192b24SSimon Glass 
3432e192b24SSimon Glass 		pplat = dev_get_parent_platdata(dev);
3442e192b24SSimon Glass 		if (short_listing) {
3452e192b24SSimon Glass 			printf("%02x.%02x.%02x   ", bus->seq,
3462e192b24SSimon Glass 			       PCI_DEV(pplat->devfn), PCI_FUNC(pplat->devfn));
3472e192b24SSimon Glass 			pci_header_show_brief(dev);
3482e192b24SSimon Glass 		} else {
3492e192b24SSimon Glass 			printf("\nFound PCI device %02x.%02x.%02x:\n", bus->seq,
3502e192b24SSimon Glass 			       PCI_DEV(pplat->devfn), PCI_FUNC(pplat->devfn));
3512e192b24SSimon Glass 			pci_header_show(dev);
3522e192b24SSimon Glass 		}
3532e192b24SSimon Glass 	}
3542e192b24SSimon Glass }
3552e192b24SSimon Glass 
3562e192b24SSimon Glass #else
3572e192b24SSimon Glass 
3582e192b24SSimon Glass /**
3592e192b24SSimon Glass  * pci_header_show_brief() - Show the short-form PCI device header
3602e192b24SSimon Glass  *
3612e192b24SSimon Glass  * Reads and prints the header of the specified PCI device in short form.
3622e192b24SSimon Glass  *
3632e192b24SSimon Glass  * @dev: Bus+Device+Function number
3642e192b24SSimon Glass  */
pci_header_show_brief(pci_dev_t dev)3652e192b24SSimon Glass void pci_header_show_brief(pci_dev_t dev)
3662e192b24SSimon Glass {
3672e192b24SSimon Glass 	u16 vendor, device;
3682e192b24SSimon Glass 	u8 class, subclass;
3692e192b24SSimon Glass 
3702e192b24SSimon Glass 	pci_read_config_word(dev, PCI_VENDOR_ID, &vendor);
3712e192b24SSimon Glass 	pci_read_config_word(dev, PCI_DEVICE_ID, &device);
3722e192b24SSimon Glass 	pci_read_config_byte(dev, PCI_CLASS_CODE, &class);
3732e192b24SSimon Glass 	pci_read_config_byte(dev, PCI_CLASS_SUB_CODE, &subclass);
3742e192b24SSimon Glass 
3752e192b24SSimon Glass 	printf("0x%.4x     0x%.4x     %-23s 0x%.2x\n",
3762e192b24SSimon Glass 	       vendor, device,
3772e192b24SSimon Glass 	       pci_class_str(class), subclass);
3782e192b24SSimon Glass }
3792e192b24SSimon Glass 
3802e192b24SSimon Glass /**
3812e192b24SSimon Glass  * pciinfo() - Show a list of devices on the PCI bus
3822e192b24SSimon Glass  *
3832e192b24SSimon Glass  * Show information about devices on PCI bus. Depending on @short_pci_listing
3842e192b24SSimon Glass  * the output will be more or less exhaustive.
3852e192b24SSimon Glass  *
3862e192b24SSimon Glass  * @bus_num: The number of the bus to be scanned
3872e192b24SSimon Glass  * @short_pci_listing: true to use short form, showing only a brief header
3882e192b24SSimon Glass  * for each device
3892e192b24SSimon Glass  */
pciinfo(int bus_num,int short_pci_listing)3902e192b24SSimon Glass void pciinfo(int bus_num, int short_pci_listing)
3912e192b24SSimon Glass {
3922e192b24SSimon Glass 	struct pci_controller *hose = pci_bus_to_hose(bus_num);
3932e192b24SSimon Glass 	int device;
3942e192b24SSimon Glass 	int function;
3952e192b24SSimon Glass 	unsigned char header_type;
3962e192b24SSimon Glass 	unsigned short vendor_id;
3972e192b24SSimon Glass 	pci_dev_t dev;
3982e192b24SSimon Glass 	int ret;
3992e192b24SSimon Glass 
4002e192b24SSimon Glass 	if (!hose)
4012e192b24SSimon Glass 		return;
4022e192b24SSimon Glass 
4032e192b24SSimon Glass 	pciinfo_header(bus_num, short_pci_listing);
4042e192b24SSimon Glass 
4052e192b24SSimon Glass 	for (device = 0; device < PCI_MAX_PCI_DEVICES; device++) {
4062e192b24SSimon Glass 		header_type = 0;
4072e192b24SSimon Glass 		vendor_id = 0;
4082e192b24SSimon Glass 		for (function = 0; function < PCI_MAX_PCI_FUNCTIONS;
4092e192b24SSimon Glass 		     function++) {
4102e192b24SSimon Glass 			/*
4112e192b24SSimon Glass 			 * If this is not a multi-function device, we skip
4122e192b24SSimon Glass 			 * the rest.
4132e192b24SSimon Glass 			 */
4142e192b24SSimon Glass 			if (function && !(header_type & 0x80))
4152e192b24SSimon Glass 				break;
4162e192b24SSimon Glass 
4172e192b24SSimon Glass 			dev = PCI_BDF(bus_num, device, function);
4182e192b24SSimon Glass 
4192e192b24SSimon Glass 			if (pci_skip_dev(hose, dev))
4202e192b24SSimon Glass 				continue;
4212e192b24SSimon Glass 
4222e192b24SSimon Glass 			ret = pci_read_config_word(dev, PCI_VENDOR_ID,
4232e192b24SSimon Glass 						   &vendor_id);
4242e192b24SSimon Glass 			if (ret)
4252e192b24SSimon Glass 				goto error;
4262e192b24SSimon Glass 			if ((vendor_id == 0xFFFF) || (vendor_id == 0x0000))
4272e192b24SSimon Glass 				continue;
4282e192b24SSimon Glass 
4292e192b24SSimon Glass 			if (!function) {
4302e192b24SSimon Glass 				pci_read_config_byte(dev, PCI_HEADER_TYPE,
4312e192b24SSimon Glass 						     &header_type);
4322e192b24SSimon Glass 			}
4332e192b24SSimon Glass 
4342e192b24SSimon Glass 			if (short_pci_listing) {
4352e192b24SSimon Glass 				printf("%02x.%02x.%02x   ", bus_num, device,
4362e192b24SSimon Glass 				       function);
4372e192b24SSimon Glass 				pci_header_show_brief(dev);
4382e192b24SSimon Glass 			} else {
4392e192b24SSimon Glass 				printf("\nFound PCI device %02x.%02x.%02x:\n",
4402e192b24SSimon Glass 				       bus_num, device, function);
4412e192b24SSimon Glass 				pci_header_show(dev);
4422e192b24SSimon Glass 			}
4432e192b24SSimon Glass 		}
4442e192b24SSimon Glass 	}
4452e192b24SSimon Glass 
4462e192b24SSimon Glass 	return;
4472e192b24SSimon Glass error:
4482e192b24SSimon Glass 	printf("Cannot read bus configuration: %d\n", ret);
4492e192b24SSimon Glass }
4502e192b24SSimon Glass #endif
4512e192b24SSimon Glass 
4522e192b24SSimon Glass /**
4532e192b24SSimon Glass  * get_pci_dev() - Convert the "bus.device.function" identifier into a number
4542e192b24SSimon Glass  *
4552e192b24SSimon Glass  * @name: Device string in the form "bus.device.function" where each is in hex
4562e192b24SSimon Glass  * @return encoded pci_dev_t or -1 if the string was invalid
4572e192b24SSimon Glass  */
get_pci_dev(char * name)4582e192b24SSimon Glass static pci_dev_t get_pci_dev(char *name)
4592e192b24SSimon Glass {
4602e192b24SSimon Glass 	char cnum[12];
4612e192b24SSimon Glass 	int len, i, iold, n;
4622e192b24SSimon Glass 	int bdfs[3] = {0,0,0};
4632e192b24SSimon Glass 
4642e192b24SSimon Glass 	len = strlen(name);
4652e192b24SSimon Glass 	if (len > 8)
4662e192b24SSimon Glass 		return -1;
4672e192b24SSimon Glass 	for (i = 0, iold = 0, n = 0; i < len; i++) {
4682e192b24SSimon Glass 		if (name[i] == '.') {
4692e192b24SSimon Glass 			memcpy(cnum, &name[iold], i - iold);
4702e192b24SSimon Glass 			cnum[i - iold] = '\0';
4712e192b24SSimon Glass 			bdfs[n++] = simple_strtoul(cnum, NULL, 16);
4722e192b24SSimon Glass 			iold = i + 1;
4732e192b24SSimon Glass 		}
4742e192b24SSimon Glass 	}
4752e192b24SSimon Glass 	strcpy(cnum, &name[iold]);
4762e192b24SSimon Glass 	if (n == 0)
4772e192b24SSimon Glass 		n = 1;
4782e192b24SSimon Glass 	bdfs[n] = simple_strtoul(cnum, NULL, 16);
4792e192b24SSimon Glass 
4802e192b24SSimon Glass 	return PCI_BDF(bdfs[0], bdfs[1], bdfs[2]);
4812e192b24SSimon Glass }
4822e192b24SSimon Glass 
4832e192b24SSimon Glass #ifdef CONFIG_DM_PCI
pci_cfg_display(struct udevice * dev,ulong addr,enum pci_size_t size,ulong length)4842e192b24SSimon Glass static int pci_cfg_display(struct udevice *dev, ulong addr,
4852e192b24SSimon Glass 			   enum pci_size_t size, ulong length)
4862e192b24SSimon Glass #else
4872e192b24SSimon Glass static int pci_cfg_display(pci_dev_t bdf, ulong addr, enum pci_size_t size,
4882e192b24SSimon Glass 			   ulong length)
4892e192b24SSimon Glass #endif
4902e192b24SSimon Glass {
4912e192b24SSimon Glass #define DISP_LINE_LEN	16
4922e192b24SSimon Glass 	ulong i, nbytes, linebytes;
4932e192b24SSimon Glass 	int byte_size;
4942e192b24SSimon Glass 	int rc = 0;
4952e192b24SSimon Glass 
4962e192b24SSimon Glass 	byte_size = pci_byte_size(size);
4972e192b24SSimon Glass 	if (length == 0)
4982e192b24SSimon Glass 		length = 0x40 / byte_size; /* Standard PCI config space */
4992e192b24SSimon Glass 
5002e192b24SSimon Glass 	/* Print the lines.
5012e192b24SSimon Glass 	 * once, and all accesses are with the specified bus width.
5022e192b24SSimon Glass 	 */
5032e192b24SSimon Glass 	nbytes = length * byte_size;
5042e192b24SSimon Glass 	do {
5052e192b24SSimon Glass 		printf("%08lx:", addr);
5062e192b24SSimon Glass 		linebytes = (nbytes > DISP_LINE_LEN) ? DISP_LINE_LEN : nbytes;
5072e192b24SSimon Glass 		for (i = 0; i < linebytes; i += byte_size) {
5082e192b24SSimon Glass 			unsigned long val;
5092e192b24SSimon Glass 
5102e192b24SSimon Glass #ifdef CONFIG_DM_PCI
5112e192b24SSimon Glass 			dm_pci_read_config(dev, addr, &val, size);
5122e192b24SSimon Glass #else
5132e192b24SSimon Glass 			val = pci_read_config(bdf, addr, size);
5142e192b24SSimon Glass #endif
5152e192b24SSimon Glass 			printf(" %0*lx", pci_field_width(size), val);
5162e192b24SSimon Glass 			addr += byte_size;
5172e192b24SSimon Glass 		}
5182e192b24SSimon Glass 		printf("\n");
5192e192b24SSimon Glass 		nbytes -= linebytes;
5202e192b24SSimon Glass 		if (ctrlc()) {
5212e192b24SSimon Glass 			rc = 1;
5222e192b24SSimon Glass 			break;
5232e192b24SSimon Glass 		}
5242e192b24SSimon Glass 	} while (nbytes > 0);
5252e192b24SSimon Glass 
5262e192b24SSimon Glass 	return (rc);
5272e192b24SSimon Glass }
5282e192b24SSimon Glass 
5292e192b24SSimon Glass #ifndef CONFIG_DM_PCI
pci_cfg_write(pci_dev_t bdf,ulong addr,ulong size,ulong value)5302e192b24SSimon Glass static int pci_cfg_write (pci_dev_t bdf, ulong addr, ulong size, ulong value)
5312e192b24SSimon Glass {
5322e192b24SSimon Glass 	if (size == 4) {
5332e192b24SSimon Glass 		pci_write_config_dword(bdf, addr, value);
5342e192b24SSimon Glass 	}
5352e192b24SSimon Glass 	else if (size == 2) {
5362e192b24SSimon Glass 		ushort val = value & 0xffff;
5372e192b24SSimon Glass 		pci_write_config_word(bdf, addr, val);
5382e192b24SSimon Glass 	}
5392e192b24SSimon Glass 	else {
5402e192b24SSimon Glass 		u_char val = value & 0xff;
5412e192b24SSimon Glass 		pci_write_config_byte(bdf, addr, val);
5422e192b24SSimon Glass 	}
5432e192b24SSimon Glass 	return 0;
5442e192b24SSimon Glass }
5452e192b24SSimon Glass #endif
5462e192b24SSimon Glass 
5472e192b24SSimon Glass #ifdef CONFIG_DM_PCI
pci_cfg_modify(struct udevice * dev,ulong addr,ulong size,ulong value,int incrflag)5482e192b24SSimon Glass static int pci_cfg_modify(struct udevice *dev, ulong addr, ulong size,
5492e192b24SSimon Glass 			  ulong value, int incrflag)
5502e192b24SSimon Glass #else
5512e192b24SSimon Glass static int pci_cfg_modify(pci_dev_t bdf, ulong addr, ulong size, ulong value,
5522e192b24SSimon Glass 			  int incrflag)
5532e192b24SSimon Glass #endif
5542e192b24SSimon Glass {
5552e192b24SSimon Glass 	ulong	i;
5562e192b24SSimon Glass 	int	nbytes;
5572e192b24SSimon Glass 	ulong val;
5582e192b24SSimon Glass 
5592e192b24SSimon Glass 	/* Print the address, followed by value.  Then accept input for
5602e192b24SSimon Glass 	 * the next value.  A non-converted value exits.
5612e192b24SSimon Glass 	 */
5622e192b24SSimon Glass 	do {
5632e192b24SSimon Glass 		printf("%08lx:", addr);
5642e192b24SSimon Glass #ifdef CONFIG_DM_PCI
5652e192b24SSimon Glass 		dm_pci_read_config(dev, addr, &val, size);
5662e192b24SSimon Glass #else
5672e192b24SSimon Glass 		val = pci_read_config(bdf, addr, size);
5682e192b24SSimon Glass #endif
5692e192b24SSimon Glass 		printf(" %0*lx", pci_field_width(size), val);
5702e192b24SSimon Glass 
5712e192b24SSimon Glass 		nbytes = cli_readline(" ? ");
5722e192b24SSimon Glass 		if (nbytes == 0 || (nbytes == 1 && console_buffer[0] == '-')) {
5732e192b24SSimon Glass 			/* <CR> pressed as only input, don't modify current
5742e192b24SSimon Glass 			 * location and move to next. "-" pressed will go back.
5752e192b24SSimon Glass 			 */
5762e192b24SSimon Glass 			if (incrflag)
5772e192b24SSimon Glass 				addr += nbytes ? -size : size;
5782e192b24SSimon Glass 			nbytes = 1;
5792e192b24SSimon Glass 			/* good enough to not time out */
5802e192b24SSimon Glass 			bootretry_reset_cmd_timeout();
5812e192b24SSimon Glass 		}
5822e192b24SSimon Glass #ifdef CONFIG_BOOT_RETRY_TIME
5832e192b24SSimon Glass 		else if (nbytes == -2) {
5842e192b24SSimon Glass 			break;	/* timed out, exit the command	*/
5852e192b24SSimon Glass 		}
5862e192b24SSimon Glass #endif
5872e192b24SSimon Glass 		else {
5882e192b24SSimon Glass 			char *endp;
5892e192b24SSimon Glass 			i = simple_strtoul(console_buffer, &endp, 16);
5902e192b24SSimon Glass 			nbytes = endp - console_buffer;
5912e192b24SSimon Glass 			if (nbytes) {
5922e192b24SSimon Glass 				/* good enough to not time out
5932e192b24SSimon Glass 				 */
5942e192b24SSimon Glass 				bootretry_reset_cmd_timeout();
5952e192b24SSimon Glass #ifdef CONFIG_DM_PCI
5962e192b24SSimon Glass 				dm_pci_write_config(dev, addr, i, size);
5972e192b24SSimon Glass #else
5982e192b24SSimon Glass 				pci_cfg_write(bdf, addr, size, i);
5992e192b24SSimon Glass #endif
6002e192b24SSimon Glass 				if (incrflag)
6012e192b24SSimon Glass 					addr += size;
6022e192b24SSimon Glass 			}
6032e192b24SSimon Glass 		}
6042e192b24SSimon Glass 	} while (nbytes);
6052e192b24SSimon Glass 
6062e192b24SSimon Glass 	return 0;
6072e192b24SSimon Glass }
6082e192b24SSimon Glass 
609b997a73eSSimon Glass #ifdef CONFIG_DM_PCI
610b997a73eSSimon Glass static const struct pci_flag_info {
611b997a73eSSimon Glass 	uint flag;
612b997a73eSSimon Glass 	const char *name;
613b997a73eSSimon Glass } pci_flag_info[] = {
614b997a73eSSimon Glass 	{ PCI_REGION_IO, "io" },
615b997a73eSSimon Glass 	{ PCI_REGION_PREFETCH, "prefetch" },
616b997a73eSSimon Glass 	{ PCI_REGION_SYS_MEMORY, "sysmem" },
617b997a73eSSimon Glass 	{ PCI_REGION_RO, "readonly" },
618b997a73eSSimon Glass 	{ PCI_REGION_IO, "io" },
619b997a73eSSimon Glass };
620b997a73eSSimon Glass 
pci_show_regions(struct udevice * bus)621b997a73eSSimon Glass static void pci_show_regions(struct udevice *bus)
622b997a73eSSimon Glass {
623b997a73eSSimon Glass 	struct pci_controller *hose = dev_get_uclass_priv(bus);
624b997a73eSSimon Glass 	const struct pci_region *reg;
625b997a73eSSimon Glass 	int i, j;
626b997a73eSSimon Glass 
627b997a73eSSimon Glass 	if (!hose) {
628b997a73eSSimon Glass 		printf("Bus '%s' is not a PCI controller\n", bus->name);
629b997a73eSSimon Glass 		return;
630b997a73eSSimon Glass 	}
631b997a73eSSimon Glass 
632b997a73eSSimon Glass 	printf("#   %-16s %-16s %-16s  %s\n", "Bus start", "Phys start", "Size",
633b997a73eSSimon Glass 	       "Flags");
634b997a73eSSimon Glass 	for (i = 0, reg = hose->regions; i < hose->region_count; i++, reg++) {
635b997a73eSSimon Glass 		printf("%d   %#016llx %#016llx %#016llx  ", i,
636b997a73eSSimon Glass 		       (unsigned long long)reg->bus_start,
637b997a73eSSimon Glass 		       (unsigned long long)reg->phys_start,
638b997a73eSSimon Glass 		       (unsigned long long)reg->size);
639b997a73eSSimon Glass 		if (!(reg->flags & PCI_REGION_TYPE))
640b997a73eSSimon Glass 			printf("mem ");
641b997a73eSSimon Glass 		for (j = 0; j < ARRAY_SIZE(pci_flag_info); j++) {
642b997a73eSSimon Glass 			if (reg->flags & pci_flag_info[j].flag)
643b997a73eSSimon Glass 				printf("%s ", pci_flag_info[j].name);
644b997a73eSSimon Glass 		}
645b997a73eSSimon Glass 		printf("\n");
646b997a73eSSimon Glass 	}
647b997a73eSSimon Glass }
648b997a73eSSimon Glass #endif
649b997a73eSSimon Glass 
6502e192b24SSimon Glass /* PCI Configuration Space access commands
6512e192b24SSimon Glass  *
6522e192b24SSimon Glass  * Syntax:
6532e192b24SSimon Glass  *	pci display[.b, .w, .l] bus.device.function} [addr] [len]
6542e192b24SSimon Glass  *	pci next[.b, .w, .l] bus.device.function [addr]
6552e192b24SSimon Glass  *      pci modify[.b, .w, .l] bus.device.function [addr]
6562e192b24SSimon Glass  *      pci write[.b, .w, .l] bus.device.function addr value
6572e192b24SSimon Glass  */
do_pci(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])6582e192b24SSimon Glass static int do_pci(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
6592e192b24SSimon Glass {
6602e192b24SSimon Glass 	ulong addr = 0, value = 0, cmd_size = 0;
6612e192b24SSimon Glass 	enum pci_size_t size = PCI_SIZE_32;
6622e192b24SSimon Glass #ifdef CONFIG_DM_PCI
6632e192b24SSimon Glass 	struct udevice *dev, *bus;
6642e192b24SSimon Glass #else
6652e192b24SSimon Glass 	pci_dev_t dev;
6662e192b24SSimon Glass #endif
6672e192b24SSimon Glass 	int busnum = 0;
6682e192b24SSimon Glass 	pci_dev_t bdf = 0;
6692e192b24SSimon Glass 	char cmd = 's';
6702e192b24SSimon Glass 	int ret = 0;
6712e192b24SSimon Glass 
6722e192b24SSimon Glass 	if (argc > 1)
6732e192b24SSimon Glass 		cmd = argv[1][0];
6742e192b24SSimon Glass 
6752e192b24SSimon Glass 	switch (cmd) {
6762e192b24SSimon Glass 	case 'd':		/* display */
6772e192b24SSimon Glass 	case 'n':		/* next */
6782e192b24SSimon Glass 	case 'm':		/* modify */
6792e192b24SSimon Glass 	case 'w':		/* write */
6802e192b24SSimon Glass 		/* Check for a size specification. */
6812e192b24SSimon Glass 		cmd_size = cmd_get_data_size(argv[1], 4);
6822e192b24SSimon Glass 		size = (cmd_size == 4) ? PCI_SIZE_32 : cmd_size - 1;
6832e192b24SSimon Glass 		if (argc > 3)
6842e192b24SSimon Glass 			addr = simple_strtoul(argv[3], NULL, 16);
6852e192b24SSimon Glass 		if (argc > 4)
6862e192b24SSimon Glass 			value = simple_strtoul(argv[4], NULL, 16);
6872e192b24SSimon Glass 	case 'h':		/* header */
688e5f96a87SYehuda Yitschak #ifdef CONFIG_DM_PCI
689e5f96a87SYehuda Yitschak 	case 'b':		/* bars */
690e5f96a87SYehuda Yitschak #endif
6912e192b24SSimon Glass 		if (argc < 3)
6922e192b24SSimon Glass 			goto usage;
6932e192b24SSimon Glass 		if ((bdf = get_pci_dev(argv[2])) == -1)
6942e192b24SSimon Glass 			return 1;
6952e192b24SSimon Glass 		break;
69618642424SSimon Glass #if defined(CONFIG_DM_PCI)
6972e192b24SSimon Glass 	case 'e':
698e578b92cSStephen Warren 		pci_init();
699e578b92cSStephen Warren 		return 0;
7002e192b24SSimon Glass #endif
701b997a73eSSimon Glass 	case 'r': /* no break */
7022e192b24SSimon Glass 	default:		/* scan bus */
7032e192b24SSimon Glass 		value = 1; /* short listing */
7042e192b24SSimon Glass 		if (argc > 1) {
705b997a73eSSimon Glass 			if (cmd != 'r' && argv[argc-1][0] == 'l') {
7062e192b24SSimon Glass 				value = 0;
7072e192b24SSimon Glass 				argc--;
7082e192b24SSimon Glass 			}
7092e192b24SSimon Glass 			if (argc > 1)
7102e192b24SSimon Glass 				busnum = simple_strtoul(argv[1], NULL, 16);
7112e192b24SSimon Glass 		}
7122e192b24SSimon Glass #ifdef CONFIG_DM_PCI
7132e192b24SSimon Glass 		ret = uclass_get_device_by_seq(UCLASS_PCI, busnum, &bus);
7142e192b24SSimon Glass 		if (ret) {
7152e192b24SSimon Glass 			printf("No such bus\n");
7162e192b24SSimon Glass 			return CMD_RET_FAILURE;
7172e192b24SSimon Glass 		}
718b997a73eSSimon Glass 		if (cmd == 'r')
719b997a73eSSimon Glass 			pci_show_regions(bus);
720b997a73eSSimon Glass 		else
7212e192b24SSimon Glass 			pciinfo(bus, value);
7222e192b24SSimon Glass #else
7232e192b24SSimon Glass 		pciinfo(busnum, value);
7242e192b24SSimon Glass #endif
7252e192b24SSimon Glass 		return 0;
7262e192b24SSimon Glass 	}
7272e192b24SSimon Glass 
7282e192b24SSimon Glass #ifdef CONFIG_DM_PCI
7292e192b24SSimon Glass 	ret = dm_pci_bus_find_bdf(bdf, &dev);
7302e192b24SSimon Glass 	if (ret) {
7312e192b24SSimon Glass 		printf("No such device\n");
7322e192b24SSimon Glass 		return CMD_RET_FAILURE;
7332e192b24SSimon Glass 	}
7342e192b24SSimon Glass #else
7352e192b24SSimon Glass 	dev = bdf;
7362e192b24SSimon Glass #endif
7372e192b24SSimon Glass 
7382e192b24SSimon Glass 	switch (argv[1][0]) {
7392e192b24SSimon Glass 	case 'h':		/* header */
7402e192b24SSimon Glass 		pci_header_show(dev);
7412e192b24SSimon Glass 		break;
7422e192b24SSimon Glass 	case 'd':		/* display */
7432e192b24SSimon Glass 		return pci_cfg_display(dev, addr, size, value);
7442e192b24SSimon Glass 	case 'n':		/* next */
7452e192b24SSimon Glass 		if (argc < 4)
7462e192b24SSimon Glass 			goto usage;
7472e192b24SSimon Glass 		ret = pci_cfg_modify(dev, addr, size, value, 0);
7482e192b24SSimon Glass 		break;
7492e192b24SSimon Glass 	case 'm':		/* modify */
7502e192b24SSimon Glass 		if (argc < 4)
7512e192b24SSimon Glass 			goto usage;
7522e192b24SSimon Glass 		ret = pci_cfg_modify(dev, addr, size, value, 1);
7532e192b24SSimon Glass 		break;
7542e192b24SSimon Glass 	case 'w':		/* write */
7552e192b24SSimon Glass 		if (argc < 5)
7562e192b24SSimon Glass 			goto usage;
7572e192b24SSimon Glass #ifdef CONFIG_DM_PCI
7582e192b24SSimon Glass 		ret = dm_pci_write_config(dev, addr, value, size);
7592e192b24SSimon Glass #else
7602e192b24SSimon Glass 		ret = pci_cfg_write(dev, addr, size, value);
7612e192b24SSimon Glass #endif
7622e192b24SSimon Glass 		break;
763e5f96a87SYehuda Yitschak #ifdef CONFIG_DM_PCI
764e5f96a87SYehuda Yitschak 
765e5f96a87SYehuda Yitschak 	case 'b':		/* bars */
766e5f96a87SYehuda Yitschak 		return pci_bar_show(dev);
767e5f96a87SYehuda Yitschak #endif
7682e192b24SSimon Glass 	default:
7692e192b24SSimon Glass 		ret = CMD_RET_USAGE;
7702e192b24SSimon Glass 		break;
7712e192b24SSimon Glass 	}
7722e192b24SSimon Glass 
7732e192b24SSimon Glass 	return ret;
7742e192b24SSimon Glass  usage:
7752e192b24SSimon Glass 	return CMD_RET_USAGE;
7762e192b24SSimon Glass }
7772e192b24SSimon Glass 
7782e192b24SSimon Glass /***************************************************/
7792e192b24SSimon Glass 
7802e192b24SSimon Glass #ifdef CONFIG_SYS_LONGHELP
7812e192b24SSimon Glass static char pci_help_text[] =
7822e192b24SSimon Glass 	"[bus] [long]\n"
7832e192b24SSimon Glass 	"    - short or long list of PCI devices on bus 'bus'\n"
78418642424SSimon Glass #if defined(CONFIG_DM_PCI)
7852e192b24SSimon Glass 	"pci enum\n"
786e578b92cSStephen Warren 	"    - Enumerate PCI buses\n"
7872e192b24SSimon Glass #endif
7882e192b24SSimon Glass 	"pci header b.d.f\n"
7892e192b24SSimon Glass 	"    - show header of PCI device 'bus.device.function'\n"
790e5f96a87SYehuda Yitschak #ifdef CONFIG_DM_PCI
791e5f96a87SYehuda Yitschak 	"pci bar b.d.f\n"
792e5f96a87SYehuda Yitschak 	"    - show BARs base and size for device b.d.f'\n"
793b997a73eSSimon Glass 	"pci regions\n"
794b997a73eSSimon Glass 	"    - show PCI regions\n"
795e5f96a87SYehuda Yitschak #endif
7962e192b24SSimon Glass 	"pci display[.b, .w, .l] b.d.f [address] [# of objects]\n"
7972e192b24SSimon Glass 	"    - display PCI configuration space (CFG)\n"
7982e192b24SSimon Glass 	"pci next[.b, .w, .l] b.d.f address\n"
7992e192b24SSimon Glass 	"    - modify, read and keep CFG address\n"
8002e192b24SSimon Glass 	"pci modify[.b, .w, .l] b.d.f address\n"
8012e192b24SSimon Glass 	"    -  modify, auto increment CFG address\n"
8022e192b24SSimon Glass 	"pci write[.b, .w, .l] b.d.f address value\n"
8032e192b24SSimon Glass 	"    - write to CFG address";
8042e192b24SSimon Glass #endif
8052e192b24SSimon Glass 
8062e192b24SSimon Glass U_BOOT_CMD(
8072e192b24SSimon Glass 	pci,	5,	1,	do_pci,
8082e192b24SSimon Glass 	"list and access PCI Configuration Space", pci_help_text
8092e192b24SSimon Glass );
810