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