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