pci.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762
  1. /*
  2. * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
  3. * Andreas Heppel <aheppel@sysgo.de>
  4. *
  5. * (C) Copyright 2002
  6. * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
  7. * Wolfgang Grandegger, DENX Software Engineering, wg@denx.de.
  8. *
  9. * SPDX-License-Identifier: GPL-2.0+
  10. */
  11. /*
  12. * PCI routines
  13. */
  14. #include <common.h>
  15. #include <bootretry.h>
  16. #include <cli.h>
  17. #include <command.h>
  18. #include <console.h>
  19. #include <dm.h>
  20. #include <asm/processor.h>
  21. #include <asm/io.h>
  22. #include <pci.h>
  23. struct pci_reg_info {
  24. const char *name;
  25. enum pci_size_t size;
  26. u8 offset;
  27. };
  28. static int pci_byte_size(enum pci_size_t size)
  29. {
  30. switch (size) {
  31. case PCI_SIZE_8:
  32. return 1;
  33. case PCI_SIZE_16:
  34. return 2;
  35. case PCI_SIZE_32:
  36. default:
  37. return 4;
  38. }
  39. }
  40. static int pci_field_width(enum pci_size_t size)
  41. {
  42. return pci_byte_size(size) * 2;
  43. }
  44. #ifdef CONFIG_DM_PCI
  45. static void pci_show_regs(struct udevice *dev, struct pci_reg_info *regs)
  46. {
  47. for (; regs->name; regs++) {
  48. unsigned long val;
  49. dm_pci_read_config(dev, regs->offset, &val, regs->size);
  50. printf(" %s =%*s%#.*lx\n", regs->name,
  51. (int)(28 - strlen(regs->name)), "",
  52. pci_field_width(regs->size), val);
  53. }
  54. }
  55. #else
  56. static unsigned long pci_read_config(pci_dev_t dev, int offset,
  57. enum pci_size_t size)
  58. {
  59. u32 val32;
  60. u16 val16;
  61. u8 val8;
  62. switch (size) {
  63. case PCI_SIZE_8:
  64. pci_read_config_byte(dev, offset, &val8);
  65. return val8;
  66. case PCI_SIZE_16:
  67. pci_read_config_word(dev, offset, &val16);
  68. return val16;
  69. case PCI_SIZE_32:
  70. default:
  71. pci_read_config_dword(dev, offset, &val32);
  72. return val32;
  73. }
  74. }
  75. static void pci_show_regs(pci_dev_t dev, struct pci_reg_info *regs)
  76. {
  77. for (; regs->name; regs++) {
  78. printf(" %s =%*s%#.*lx\n", regs->name,
  79. (int)(28 - strlen(regs->name)), "",
  80. pci_field_width(regs->size),
  81. pci_read_config(dev, regs->offset, regs->size));
  82. }
  83. }
  84. #endif
  85. #ifdef CONFIG_DM_PCI
  86. int pci_bar_show(struct udevice *dev)
  87. {
  88. u8 header_type;
  89. int bar_cnt, bar_id, mem_type;
  90. bool is_64, is_io;
  91. u32 base_low, base_high;
  92. u32 size_low, size_high;
  93. u64 base, size;
  94. u32 reg_addr;
  95. int prefetchable;
  96. dm_pci_read_config8(dev, PCI_HEADER_TYPE, &header_type);
  97. if (header_type == PCI_HEADER_TYPE_CARDBUS) {
  98. printf("CardBus doesn't support BARs\n");
  99. return -ENOSYS;
  100. }
  101. bar_cnt = (header_type == PCI_HEADER_TYPE_NORMAL) ? 6 : 2;
  102. printf("ID Base Size Width Type\n");
  103. printf("----------------------------------------------------------\n");
  104. bar_id = 0;
  105. reg_addr = PCI_BASE_ADDRESS_0;
  106. while (bar_cnt) {
  107. dm_pci_read_config32(dev, reg_addr, &base_low);
  108. dm_pci_write_config32(dev, reg_addr, 0xffffffff);
  109. dm_pci_read_config32(dev, reg_addr, &size_low);
  110. dm_pci_write_config32(dev, reg_addr, base_low);
  111. reg_addr += 4;
  112. base = base_low & ~0xf;
  113. size = size_low & ~0xf;
  114. base_high = 0x0;
  115. size_high = 0xffffffff;
  116. is_64 = 0;
  117. prefetchable = base_low & PCI_BASE_ADDRESS_MEM_PREFETCH;
  118. is_io = base_low & PCI_BASE_ADDRESS_SPACE_IO;
  119. mem_type = base_low & PCI_BASE_ADDRESS_MEM_TYPE_MASK;
  120. if (mem_type == PCI_BASE_ADDRESS_MEM_TYPE_64) {
  121. dm_pci_read_config32(dev, reg_addr, &base_high);
  122. dm_pci_write_config32(dev, reg_addr, 0xffffffff);
  123. dm_pci_read_config32(dev, reg_addr, &size_high);
  124. dm_pci_write_config32(dev, reg_addr, base_high);
  125. bar_cnt--;
  126. reg_addr += 4;
  127. is_64 = 1;
  128. }
  129. base = base | ((u64)base_high << 32);
  130. size = size | ((u64)size_high << 32);
  131. if ((!is_64 && size_low) || (is_64 && size)) {
  132. size = ~size + 1;
  133. printf(" %d %#016llx %#016llx %d %s %s\n",
  134. bar_id, base, size, is_64 ? 64 : 32,
  135. is_io ? "I/O" : "MEM",
  136. prefetchable ? "Prefetchable" : "");
  137. }
  138. bar_id++;
  139. bar_cnt--;
  140. }
  141. return 0;
  142. }
  143. #endif
  144. static struct pci_reg_info regs_start[] = {
  145. { "vendor ID", PCI_SIZE_16, PCI_VENDOR_ID },
  146. { "device ID", PCI_SIZE_16, PCI_DEVICE_ID },
  147. { "command register ID", PCI_SIZE_16, PCI_COMMAND },
  148. { "status register", PCI_SIZE_16, PCI_STATUS },
  149. { "revision ID", PCI_SIZE_8, PCI_REVISION_ID },
  150. {},
  151. };
  152. static struct pci_reg_info regs_rest[] = {
  153. { "sub class code", PCI_SIZE_8, PCI_CLASS_SUB_CODE },
  154. { "programming interface", PCI_SIZE_8, PCI_CLASS_PROG },
  155. { "cache line", PCI_SIZE_8, PCI_CACHE_LINE_SIZE },
  156. { "latency time", PCI_SIZE_8, PCI_LATENCY_TIMER },
  157. { "header type", PCI_SIZE_8, PCI_HEADER_TYPE },
  158. { "BIST", PCI_SIZE_8, PCI_BIST },
  159. { "base address 0", PCI_SIZE_32, PCI_BASE_ADDRESS_0 },
  160. {},
  161. };
  162. static struct pci_reg_info regs_normal[] = {
  163. { "base address 1", PCI_SIZE_32, PCI_BASE_ADDRESS_1 },
  164. { "base address 2", PCI_SIZE_32, PCI_BASE_ADDRESS_2 },
  165. { "base address 3", PCI_SIZE_32, PCI_BASE_ADDRESS_3 },
  166. { "base address 4", PCI_SIZE_32, PCI_BASE_ADDRESS_4 },
  167. { "base address 5", PCI_SIZE_32, PCI_BASE_ADDRESS_5 },
  168. { "cardBus CIS pointer", PCI_SIZE_32, PCI_CARDBUS_CIS },
  169. { "sub system vendor ID", PCI_SIZE_16, PCI_SUBSYSTEM_VENDOR_ID },
  170. { "sub system ID", PCI_SIZE_16, PCI_SUBSYSTEM_ID },
  171. { "expansion ROM base address", PCI_SIZE_32, PCI_ROM_ADDRESS },
  172. { "interrupt line", PCI_SIZE_8, PCI_INTERRUPT_LINE },
  173. { "interrupt pin", PCI_SIZE_8, PCI_INTERRUPT_PIN },
  174. { "min Grant", PCI_SIZE_8, PCI_MIN_GNT },
  175. { "max Latency", PCI_SIZE_8, PCI_MAX_LAT },
  176. {},
  177. };
  178. static struct pci_reg_info regs_bridge[] = {
  179. { "base address 1", PCI_SIZE_32, PCI_BASE_ADDRESS_1 },
  180. { "primary bus number", PCI_SIZE_8, PCI_PRIMARY_BUS },
  181. { "secondary bus number", PCI_SIZE_8, PCI_SECONDARY_BUS },
  182. { "subordinate bus number", PCI_SIZE_8, PCI_SUBORDINATE_BUS },
  183. { "secondary latency timer", PCI_SIZE_8, PCI_SEC_LATENCY_TIMER },
  184. { "IO base", PCI_SIZE_8, PCI_IO_BASE },
  185. { "IO limit", PCI_SIZE_8, PCI_IO_LIMIT },
  186. { "secondary status", PCI_SIZE_16, PCI_SEC_STATUS },
  187. { "memory base", PCI_SIZE_16, PCI_MEMORY_BASE },
  188. { "memory limit", PCI_SIZE_16, PCI_MEMORY_LIMIT },
  189. { "prefetch memory base", PCI_SIZE_16, PCI_PREF_MEMORY_BASE },
  190. { "prefetch memory limit", PCI_SIZE_16, PCI_PREF_MEMORY_LIMIT },
  191. { "prefetch memory base upper", PCI_SIZE_32, PCI_PREF_BASE_UPPER32 },
  192. { "prefetch memory limit upper", PCI_SIZE_32, PCI_PREF_LIMIT_UPPER32 },
  193. { "IO base upper 16 bits", PCI_SIZE_16, PCI_IO_BASE_UPPER16 },
  194. { "IO limit upper 16 bits", PCI_SIZE_16, PCI_IO_LIMIT_UPPER16 },
  195. { "expansion ROM base address", PCI_SIZE_32, PCI_ROM_ADDRESS1 },
  196. { "interrupt line", PCI_SIZE_8, PCI_INTERRUPT_LINE },
  197. { "interrupt pin", PCI_SIZE_8, PCI_INTERRUPT_PIN },
  198. { "bridge control", PCI_SIZE_16, PCI_BRIDGE_CONTROL },
  199. {},
  200. };
  201. static struct pci_reg_info regs_cardbus[] = {
  202. { "capabilities", PCI_SIZE_8, PCI_CB_CAPABILITY_LIST },
  203. { "secondary status", PCI_SIZE_16, PCI_CB_SEC_STATUS },
  204. { "primary bus number", PCI_SIZE_8, PCI_CB_PRIMARY_BUS },
  205. { "CardBus number", PCI_SIZE_8, PCI_CB_CARD_BUS },
  206. { "subordinate bus number", PCI_SIZE_8, PCI_CB_SUBORDINATE_BUS },
  207. { "CardBus latency timer", PCI_SIZE_8, PCI_CB_LATENCY_TIMER },
  208. { "CardBus memory base 0", PCI_SIZE_32, PCI_CB_MEMORY_BASE_0 },
  209. { "CardBus memory limit 0", PCI_SIZE_32, PCI_CB_MEMORY_LIMIT_0 },
  210. { "CardBus memory base 1", PCI_SIZE_32, PCI_CB_MEMORY_BASE_1 },
  211. { "CardBus memory limit 1", PCI_SIZE_32, PCI_CB_MEMORY_LIMIT_1 },
  212. { "CardBus IO base 0", PCI_SIZE_16, PCI_CB_IO_BASE_0 },
  213. { "CardBus IO base high 0", PCI_SIZE_16, PCI_CB_IO_BASE_0_HI },
  214. { "CardBus IO limit 0", PCI_SIZE_16, PCI_CB_IO_LIMIT_0 },
  215. { "CardBus IO limit high 0", PCI_SIZE_16, PCI_CB_IO_LIMIT_0_HI },
  216. { "CardBus IO base 1", PCI_SIZE_16, PCI_CB_IO_BASE_1 },
  217. { "CardBus IO base high 1", PCI_SIZE_16, PCI_CB_IO_BASE_1_HI },
  218. { "CardBus IO limit 1", PCI_SIZE_16, PCI_CB_IO_LIMIT_1 },
  219. { "CardBus IO limit high 1", PCI_SIZE_16, PCI_CB_IO_LIMIT_1_HI },
  220. { "interrupt line", PCI_SIZE_8, PCI_INTERRUPT_LINE },
  221. { "interrupt pin", PCI_SIZE_8, PCI_INTERRUPT_PIN },
  222. { "bridge control", PCI_SIZE_16, PCI_CB_BRIDGE_CONTROL },
  223. { "subvendor ID", PCI_SIZE_16, PCI_CB_SUBSYSTEM_VENDOR_ID },
  224. { "subdevice ID", PCI_SIZE_16, PCI_CB_SUBSYSTEM_ID },
  225. { "PC Card 16bit base address", PCI_SIZE_32, PCI_CB_LEGACY_MODE_BASE },
  226. {},
  227. };
  228. /**
  229. * pci_header_show() - Show the header of the specified PCI device.
  230. *
  231. * @dev: Bus+Device+Function number
  232. */
  233. #ifdef CONFIG_DM_PCI
  234. void pci_header_show(struct udevice *dev)
  235. #else
  236. void pci_header_show(pci_dev_t dev)
  237. #endif
  238. {
  239. #ifdef CONFIG_DM_PCI
  240. unsigned long class, header_type;
  241. dm_pci_read_config(dev, PCI_CLASS_CODE, &class, PCI_SIZE_8);
  242. dm_pci_read_config(dev, PCI_HEADER_TYPE, &header_type, PCI_SIZE_8);
  243. #else
  244. u8 class, header_type;
  245. pci_read_config_byte(dev, PCI_CLASS_CODE, &class);
  246. pci_read_config_byte(dev, PCI_HEADER_TYPE, &header_type);
  247. #endif
  248. pci_show_regs(dev, regs_start);
  249. printf(" class code = 0x%.2x (%s)\n", (int)class,
  250. pci_class_str(class));
  251. pci_show_regs(dev, regs_rest);
  252. switch (header_type & 0x03) {
  253. case PCI_HEADER_TYPE_NORMAL: /* "normal" PCI device */
  254. pci_show_regs(dev, regs_normal);
  255. break;
  256. case PCI_HEADER_TYPE_BRIDGE: /* PCI-to-PCI bridge */
  257. pci_show_regs(dev, regs_bridge);
  258. break;
  259. case PCI_HEADER_TYPE_CARDBUS: /* PCI-to-CardBus bridge */
  260. pci_show_regs(dev, regs_cardbus);
  261. break;
  262. default:
  263. printf("unknown header\n");
  264. break;
  265. }
  266. }
  267. void pciinfo_header(int busnum, bool short_listing)
  268. {
  269. printf("Scanning PCI devices on bus %d\n", busnum);
  270. if (short_listing) {
  271. printf("BusDevFun VendorId DeviceId Device Class Sub-Class\n");
  272. printf("_____________________________________________________________\n");
  273. }
  274. }
  275. #ifdef CONFIG_DM_PCI
  276. /**
  277. * pci_header_show_brief() - Show the short-form PCI device header
  278. *
  279. * Reads and prints the header of the specified PCI device in short form.
  280. *
  281. * @dev: PCI device to show
  282. */
  283. static void pci_header_show_brief(struct udevice *dev)
  284. {
  285. ulong vendor, device;
  286. ulong class, subclass;
  287. dm_pci_read_config(dev, PCI_VENDOR_ID, &vendor, PCI_SIZE_16);
  288. dm_pci_read_config(dev, PCI_DEVICE_ID, &device, PCI_SIZE_16);
  289. dm_pci_read_config(dev, PCI_CLASS_CODE, &class, PCI_SIZE_8);
  290. dm_pci_read_config(dev, PCI_CLASS_SUB_CODE, &subclass, PCI_SIZE_8);
  291. printf("0x%.4lx 0x%.4lx %-23s 0x%.2lx\n",
  292. vendor, device,
  293. pci_class_str(class), subclass);
  294. }
  295. static void pciinfo(struct udevice *bus, bool short_listing)
  296. {
  297. struct udevice *dev;
  298. pciinfo_header(bus->seq, short_listing);
  299. for (device_find_first_child(bus, &dev);
  300. dev;
  301. device_find_next_child(&dev)) {
  302. struct pci_child_platdata *pplat;
  303. pplat = dev_get_parent_platdata(dev);
  304. if (short_listing) {
  305. printf("%02x.%02x.%02x ", bus->seq,
  306. PCI_DEV(pplat->devfn), PCI_FUNC(pplat->devfn));
  307. pci_header_show_brief(dev);
  308. } else {
  309. printf("\nFound PCI device %02x.%02x.%02x:\n", bus->seq,
  310. PCI_DEV(pplat->devfn), PCI_FUNC(pplat->devfn));
  311. pci_header_show(dev);
  312. }
  313. }
  314. }
  315. #else
  316. /**
  317. * pci_header_show_brief() - Show the short-form PCI device header
  318. *
  319. * Reads and prints the header of the specified PCI device in short form.
  320. *
  321. * @dev: Bus+Device+Function number
  322. */
  323. void pci_header_show_brief(pci_dev_t dev)
  324. {
  325. u16 vendor, device;
  326. u8 class, subclass;
  327. pci_read_config_word(dev, PCI_VENDOR_ID, &vendor);
  328. pci_read_config_word(dev, PCI_DEVICE_ID, &device);
  329. pci_read_config_byte(dev, PCI_CLASS_CODE, &class);
  330. pci_read_config_byte(dev, PCI_CLASS_SUB_CODE, &subclass);
  331. printf("0x%.4x 0x%.4x %-23s 0x%.2x\n",
  332. vendor, device,
  333. pci_class_str(class), subclass);
  334. }
  335. /**
  336. * pciinfo() - Show a list of devices on the PCI bus
  337. *
  338. * Show information about devices on PCI bus. Depending on @short_pci_listing
  339. * the output will be more or less exhaustive.
  340. *
  341. * @bus_num: The number of the bus to be scanned
  342. * @short_pci_listing: true to use short form, showing only a brief header
  343. * for each device
  344. */
  345. void pciinfo(int bus_num, int short_pci_listing)
  346. {
  347. struct pci_controller *hose = pci_bus_to_hose(bus_num);
  348. int device;
  349. int function;
  350. unsigned char header_type;
  351. unsigned short vendor_id;
  352. pci_dev_t dev;
  353. int ret;
  354. if (!hose)
  355. return;
  356. pciinfo_header(bus_num, short_pci_listing);
  357. for (device = 0; device < PCI_MAX_PCI_DEVICES; device++) {
  358. header_type = 0;
  359. vendor_id = 0;
  360. for (function = 0; function < PCI_MAX_PCI_FUNCTIONS;
  361. function++) {
  362. /*
  363. * If this is not a multi-function device, we skip
  364. * the rest.
  365. */
  366. if (function && !(header_type & 0x80))
  367. break;
  368. dev = PCI_BDF(bus_num, device, function);
  369. if (pci_skip_dev(hose, dev))
  370. continue;
  371. ret = pci_read_config_word(dev, PCI_VENDOR_ID,
  372. &vendor_id);
  373. if (ret)
  374. goto error;
  375. if ((vendor_id == 0xFFFF) || (vendor_id == 0x0000))
  376. continue;
  377. if (!function) {
  378. pci_read_config_byte(dev, PCI_HEADER_TYPE,
  379. &header_type);
  380. }
  381. if (short_pci_listing) {
  382. printf("%02x.%02x.%02x ", bus_num, device,
  383. function);
  384. pci_header_show_brief(dev);
  385. } else {
  386. printf("\nFound PCI device %02x.%02x.%02x:\n",
  387. bus_num, device, function);
  388. pci_header_show(dev);
  389. }
  390. }
  391. }
  392. return;
  393. error:
  394. printf("Cannot read bus configuration: %d\n", ret);
  395. }
  396. #endif
  397. /**
  398. * get_pci_dev() - Convert the "bus.device.function" identifier into a number
  399. *
  400. * @name: Device string in the form "bus.device.function" where each is in hex
  401. * @return encoded pci_dev_t or -1 if the string was invalid
  402. */
  403. static pci_dev_t get_pci_dev(char *name)
  404. {
  405. char cnum[12];
  406. int len, i, iold, n;
  407. int bdfs[3] = {0,0,0};
  408. len = strlen(name);
  409. if (len > 8)
  410. return -1;
  411. for (i = 0, iold = 0, n = 0; i < len; i++) {
  412. if (name[i] == '.') {
  413. memcpy(cnum, &name[iold], i - iold);
  414. cnum[i - iold] = '\0';
  415. bdfs[n++] = simple_strtoul(cnum, NULL, 16);
  416. iold = i + 1;
  417. }
  418. }
  419. strcpy(cnum, &name[iold]);
  420. if (n == 0)
  421. n = 1;
  422. bdfs[n] = simple_strtoul(cnum, NULL, 16);
  423. return PCI_BDF(bdfs[0], bdfs[1], bdfs[2]);
  424. }
  425. #ifdef CONFIG_DM_PCI
  426. static int pci_cfg_display(struct udevice *dev, ulong addr,
  427. enum pci_size_t size, ulong length)
  428. #else
  429. static int pci_cfg_display(pci_dev_t bdf, ulong addr, enum pci_size_t size,
  430. ulong length)
  431. #endif
  432. {
  433. #define DISP_LINE_LEN 16
  434. ulong i, nbytes, linebytes;
  435. int byte_size;
  436. int rc = 0;
  437. byte_size = pci_byte_size(size);
  438. if (length == 0)
  439. length = 0x40 / byte_size; /* Standard PCI config space */
  440. /* Print the lines.
  441. * once, and all accesses are with the specified bus width.
  442. */
  443. nbytes = length * byte_size;
  444. do {
  445. printf("%08lx:", addr);
  446. linebytes = (nbytes > DISP_LINE_LEN) ? DISP_LINE_LEN : nbytes;
  447. for (i = 0; i < linebytes; i += byte_size) {
  448. unsigned long val;
  449. #ifdef CONFIG_DM_PCI
  450. dm_pci_read_config(dev, addr, &val, size);
  451. #else
  452. val = pci_read_config(bdf, addr, size);
  453. #endif
  454. printf(" %0*lx", pci_field_width(size), val);
  455. addr += byte_size;
  456. }
  457. printf("\n");
  458. nbytes -= linebytes;
  459. if (ctrlc()) {
  460. rc = 1;
  461. break;
  462. }
  463. } while (nbytes > 0);
  464. return (rc);
  465. }
  466. #ifndef CONFIG_DM_PCI
  467. static int pci_cfg_write (pci_dev_t bdf, ulong addr, ulong size, ulong value)
  468. {
  469. if (size == 4) {
  470. pci_write_config_dword(bdf, addr, value);
  471. }
  472. else if (size == 2) {
  473. ushort val = value & 0xffff;
  474. pci_write_config_word(bdf, addr, val);
  475. }
  476. else {
  477. u_char val = value & 0xff;
  478. pci_write_config_byte(bdf, addr, val);
  479. }
  480. return 0;
  481. }
  482. #endif
  483. #ifdef CONFIG_DM_PCI
  484. static int pci_cfg_modify(struct udevice *dev, ulong addr, ulong size,
  485. ulong value, int incrflag)
  486. #else
  487. static int pci_cfg_modify(pci_dev_t bdf, ulong addr, ulong size, ulong value,
  488. int incrflag)
  489. #endif
  490. {
  491. ulong i;
  492. int nbytes;
  493. ulong val;
  494. /* Print the address, followed by value. Then accept input for
  495. * the next value. A non-converted value exits.
  496. */
  497. do {
  498. printf("%08lx:", addr);
  499. #ifdef CONFIG_DM_PCI
  500. dm_pci_read_config(dev, addr, &val, size);
  501. #else
  502. val = pci_read_config(bdf, addr, size);
  503. #endif
  504. printf(" %0*lx", pci_field_width(size), val);
  505. nbytes = cli_readline(" ? ");
  506. if (nbytes == 0 || (nbytes == 1 && console_buffer[0] == '-')) {
  507. /* <CR> pressed as only input, don't modify current
  508. * location and move to next. "-" pressed will go back.
  509. */
  510. if (incrflag)
  511. addr += nbytes ? -size : size;
  512. nbytes = 1;
  513. /* good enough to not time out */
  514. bootretry_reset_cmd_timeout();
  515. }
  516. #ifdef CONFIG_BOOT_RETRY_TIME
  517. else if (nbytes == -2) {
  518. break; /* timed out, exit the command */
  519. }
  520. #endif
  521. else {
  522. char *endp;
  523. i = simple_strtoul(console_buffer, &endp, 16);
  524. nbytes = endp - console_buffer;
  525. if (nbytes) {
  526. /* good enough to not time out
  527. */
  528. bootretry_reset_cmd_timeout();
  529. #ifdef CONFIG_DM_PCI
  530. dm_pci_write_config(dev, addr, i, size);
  531. #else
  532. pci_cfg_write(bdf, addr, size, i);
  533. #endif
  534. if (incrflag)
  535. addr += size;
  536. }
  537. }
  538. } while (nbytes);
  539. return 0;
  540. }
  541. /* PCI Configuration Space access commands
  542. *
  543. * Syntax:
  544. * pci display[.b, .w, .l] bus.device.function} [addr] [len]
  545. * pci next[.b, .w, .l] bus.device.function [addr]
  546. * pci modify[.b, .w, .l] bus.device.function [addr]
  547. * pci write[.b, .w, .l] bus.device.function addr value
  548. */
  549. static int do_pci(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
  550. {
  551. ulong addr = 0, value = 0, cmd_size = 0;
  552. enum pci_size_t size = PCI_SIZE_32;
  553. #ifdef CONFIG_DM_PCI
  554. struct udevice *dev, *bus;
  555. #else
  556. pci_dev_t dev;
  557. #endif
  558. int busnum = 0;
  559. pci_dev_t bdf = 0;
  560. char cmd = 's';
  561. int ret = 0;
  562. if (argc > 1)
  563. cmd = argv[1][0];
  564. switch (cmd) {
  565. case 'd': /* display */
  566. case 'n': /* next */
  567. case 'm': /* modify */
  568. case 'w': /* write */
  569. /* Check for a size specification. */
  570. cmd_size = cmd_get_data_size(argv[1], 4);
  571. size = (cmd_size == 4) ? PCI_SIZE_32 : cmd_size - 1;
  572. if (argc > 3)
  573. addr = simple_strtoul(argv[3], NULL, 16);
  574. if (argc > 4)
  575. value = simple_strtoul(argv[4], NULL, 16);
  576. case 'h': /* header */
  577. #ifdef CONFIG_DM_PCI
  578. case 'b': /* bars */
  579. #endif
  580. if (argc < 3)
  581. goto usage;
  582. if ((bdf = get_pci_dev(argv[2])) == -1)
  583. return 1;
  584. break;
  585. #if defined(CONFIG_CMD_PCI_ENUM) || defined(CONFIG_DM_PCI)
  586. case 'e':
  587. pci_init();
  588. return 0;
  589. #endif
  590. default: /* scan bus */
  591. value = 1; /* short listing */
  592. if (argc > 1) {
  593. if (argv[argc-1][0] == 'l') {
  594. value = 0;
  595. argc--;
  596. }
  597. if (argc > 1)
  598. busnum = simple_strtoul(argv[1], NULL, 16);
  599. }
  600. #ifdef CONFIG_DM_PCI
  601. ret = uclass_get_device_by_seq(UCLASS_PCI, busnum, &bus);
  602. if (ret) {
  603. printf("No such bus\n");
  604. return CMD_RET_FAILURE;
  605. }
  606. pciinfo(bus, value);
  607. #else
  608. pciinfo(busnum, value);
  609. #endif
  610. return 0;
  611. }
  612. #ifdef CONFIG_DM_PCI
  613. ret = dm_pci_bus_find_bdf(bdf, &dev);
  614. if (ret) {
  615. printf("No such device\n");
  616. return CMD_RET_FAILURE;
  617. }
  618. #else
  619. dev = bdf;
  620. #endif
  621. switch (argv[1][0]) {
  622. case 'h': /* header */
  623. pci_header_show(dev);
  624. break;
  625. case 'd': /* display */
  626. return pci_cfg_display(dev, addr, size, value);
  627. case 'n': /* next */
  628. if (argc < 4)
  629. goto usage;
  630. ret = pci_cfg_modify(dev, addr, size, value, 0);
  631. break;
  632. case 'm': /* modify */
  633. if (argc < 4)
  634. goto usage;
  635. ret = pci_cfg_modify(dev, addr, size, value, 1);
  636. break;
  637. case 'w': /* write */
  638. if (argc < 5)
  639. goto usage;
  640. #ifdef CONFIG_DM_PCI
  641. ret = dm_pci_write_config(dev, addr, value, size);
  642. #else
  643. ret = pci_cfg_write(dev, addr, size, value);
  644. #endif
  645. break;
  646. #ifdef CONFIG_DM_PCI
  647. case 'b': /* bars */
  648. return pci_bar_show(dev);
  649. #endif
  650. default:
  651. ret = CMD_RET_USAGE;
  652. break;
  653. }
  654. return ret;
  655. usage:
  656. return CMD_RET_USAGE;
  657. }
  658. /***************************************************/
  659. #ifdef CONFIG_SYS_LONGHELP
  660. static char pci_help_text[] =
  661. "[bus] [long]\n"
  662. " - short or long list of PCI devices on bus 'bus'\n"
  663. #if defined(CONFIG_CMD_PCI_ENUM) || defined(CONFIG_DM_PCI)
  664. "pci enum\n"
  665. " - Enumerate PCI buses\n"
  666. #endif
  667. "pci header b.d.f\n"
  668. " - show header of PCI device 'bus.device.function'\n"
  669. #ifdef CONFIG_DM_PCI
  670. "pci bar b.d.f\n"
  671. " - show BARs base and size for device b.d.f'\n"
  672. #endif
  673. "pci display[.b, .w, .l] b.d.f [address] [# of objects]\n"
  674. " - display PCI configuration space (CFG)\n"
  675. "pci next[.b, .w, .l] b.d.f address\n"
  676. " - modify, read and keep CFG address\n"
  677. "pci modify[.b, .w, .l] b.d.f address\n"
  678. " - modify, auto increment CFG address\n"
  679. "pci write[.b, .w, .l] b.d.f address value\n"
  680. " - write to CFG address";
  681. #endif
  682. U_BOOT_CMD(
  683. pci, 5, 1, do_pci,
  684. "list and access PCI Configuration Space", pci_help_text
  685. );