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