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
  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   %#018llx  %#018llx  %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(dev_seq(bus), short_listing);
 338
 339        for (device_find_first_child(bus, &dev);
 340             dev;
 341             device_find_next_child(&dev)) {
 342                struct pci_child_plat *pplat;
 343
 344                pplat = dev_get_parent_plat(dev);
 345                if (short_listing) {
 346                        printf("%02x.%02x.%02x   ", dev_seq(bus),
 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",
 351                               dev_seq(bus),
 352                               PCI_DEV(pplat->devfn), PCI_FUNC(pplat->devfn));
 353                        pci_header_show(dev);
 354                }
 355        }
 356}
 357
 358#else
 359
 360/**
 361 * pci_header_show_brief() - Show the short-form PCI device header
 362 *
 363 * Reads and prints the header of the specified PCI device in short form.
 364 *
 365 * @dev: Bus+Device+Function number
 366 */
 367void pci_header_show_brief(pci_dev_t dev)
 368{
 369        u16 vendor, device;
 370        u8 class, subclass;
 371
 372        pci_read_config_word(dev, PCI_VENDOR_ID, &vendor);
 373        pci_read_config_word(dev, PCI_DEVICE_ID, &device);
 374        pci_read_config_byte(dev, PCI_CLASS_CODE, &class);
 375        pci_read_config_byte(dev, PCI_CLASS_SUB_CODE, &subclass);
 376
 377        printf("0x%.4x     0x%.4x     %-23s 0x%.2x\n",
 378               vendor, device,
 379               pci_class_str(class), subclass);
 380}
 381
 382/**
 383 * pciinfo() - Show a list of devices on the PCI bus
 384 *
 385 * Show information about devices on PCI bus. Depending on @short_pci_listing
 386 * the output will be more or less exhaustive.
 387 *
 388 * @bus_num: The number of the bus to be scanned
 389 * @short_pci_listing: true to use short form, showing only a brief header
 390 * for each device
 391 */
 392void pciinfo(int bus_num, int short_pci_listing)
 393{
 394        struct pci_controller *hose = pci_bus_to_hose(bus_num);
 395        int device;
 396        int function;
 397        unsigned char header_type;
 398        unsigned short vendor_id;
 399        pci_dev_t dev;
 400        int ret;
 401
 402        if (!hose)
 403                return;
 404
 405        pciinfo_header(bus_num, short_pci_listing);
 406
 407        for (device = 0; device < PCI_MAX_PCI_DEVICES; device++) {
 408                header_type = 0;
 409                vendor_id = 0;
 410                for (function = 0; function < PCI_MAX_PCI_FUNCTIONS;
 411                     function++) {
 412                        /*
 413                         * If this is not a multi-function device, we skip
 414                         * the rest.
 415                         */
 416                        if (function && !(header_type & 0x80))
 417                                break;
 418
 419                        dev = PCI_BDF(bus_num, device, function);
 420
 421                        if (pci_skip_dev(hose, dev))
 422                                continue;
 423
 424                        ret = pci_read_config_word(dev, PCI_VENDOR_ID,
 425                                                   &vendor_id);
 426                        if (ret)
 427                                goto error;
 428                        if ((vendor_id == 0xFFFF) || (vendor_id == 0x0000))
 429                                continue;
 430
 431                        if (!function) {
 432                                pci_read_config_byte(dev, PCI_HEADER_TYPE,
 433                                                     &header_type);
 434                        }
 435
 436                        if (short_pci_listing) {
 437                                printf("%02x.%02x.%02x   ", bus_num, device,
 438                                       function);
 439                                pci_header_show_brief(dev);
 440                        } else {
 441                                printf("\nFound PCI device %02x.%02x.%02x:\n",
 442                                       bus_num, device, function);
 443                                pci_header_show(dev);
 444                        }
 445                }
 446        }
 447
 448        return;
 449error:
 450        printf("Cannot read bus configuration: %d\n", ret);
 451}
 452#endif
 453
 454/**
 455 * get_pci_dev() - Convert the "bus.device.function" identifier into a number
 456 *
 457 * @name: Device string in the form "bus.device.function" where each is in hex
 458 * @return encoded pci_dev_t or -1 if the string was invalid
 459 */
 460static pci_dev_t get_pci_dev(char *name)
 461{
 462        char cnum[12];
 463        int len, i, iold, n;
 464        int bdfs[3] = {0,0,0};
 465
 466        len = strlen(name);
 467        if (len > 8)
 468                return -1;
 469        for (i = 0, iold = 0, n = 0; i < len; i++) {
 470                if (name[i] == '.') {
 471                        memcpy(cnum, &name[iold], i - iold);
 472                        cnum[i - iold] = '\0';
 473                        bdfs[n++] = simple_strtoul(cnum, NULL, 16);
 474                        iold = i + 1;
 475                }
 476        }
 477        strcpy(cnum, &name[iold]);
 478        if (n == 0)
 479                n = 1;
 480        bdfs[n] = simple_strtoul(cnum, NULL, 16);
 481
 482        return PCI_BDF(bdfs[0], bdfs[1], bdfs[2]);
 483}
 484
 485#ifdef CONFIG_DM_PCI
 486static int pci_cfg_display(struct udevice *dev, ulong addr,
 487                           enum pci_size_t size, ulong length)
 488#else
 489static int pci_cfg_display(pci_dev_t bdf, ulong addr, enum pci_size_t size,
 490                           ulong length)
 491#endif
 492{
 493#define DISP_LINE_LEN   16
 494        ulong i, nbytes, linebytes;
 495        int byte_size;
 496        int rc = 0;
 497
 498        byte_size = pci_byte_size(size);
 499        if (length == 0)
 500                length = 0x40 / byte_size; /* Standard PCI config space */
 501
 502        /* Print the lines.
 503         * once, and all accesses are with the specified bus width.
 504         */
 505        nbytes = length * byte_size;
 506        do {
 507                printf("%08lx:", addr);
 508                linebytes = (nbytes > DISP_LINE_LEN) ? DISP_LINE_LEN : nbytes;
 509                for (i = 0; i < linebytes; i += byte_size) {
 510                        unsigned long val;
 511
 512#ifdef CONFIG_DM_PCI
 513                        dm_pci_read_config(dev, addr, &val, size);
 514#else
 515                        val = pci_read_config(bdf, addr, size);
 516#endif
 517                        printf(" %0*lx", pci_field_width(size), val);
 518                        addr += byte_size;
 519                }
 520                printf("\n");
 521                nbytes -= linebytes;
 522                if (ctrlc()) {
 523                        rc = 1;
 524                        break;
 525                }
 526        } while (nbytes > 0);
 527
 528        return (rc);
 529}
 530
 531#ifndef CONFIG_DM_PCI
 532static int pci_cfg_write (pci_dev_t bdf, ulong addr, ulong size, ulong value)
 533{
 534        if (size == 4) {
 535                pci_write_config_dword(bdf, addr, value);
 536        }
 537        else if (size == 2) {
 538                ushort val = value & 0xffff;
 539                pci_write_config_word(bdf, addr, val);
 540        }
 541        else {
 542                u_char val = value & 0xff;
 543                pci_write_config_byte(bdf, addr, val);
 544        }
 545        return 0;
 546}
 547#endif
 548
 549#ifdef CONFIG_DM_PCI
 550static int pci_cfg_modify(struct udevice *dev, ulong addr, ulong size,
 551                          ulong value, int incrflag)
 552#else
 553static int pci_cfg_modify(pci_dev_t bdf, ulong addr, ulong size, ulong value,
 554                          int incrflag)
 555#endif
 556{
 557        ulong   i;
 558        int     nbytes;
 559        ulong val;
 560
 561        /* Print the address, followed by value.  Then accept input for
 562         * the next value.  A non-converted value exits.
 563         */
 564        do {
 565                printf("%08lx:", addr);
 566#ifdef CONFIG_DM_PCI
 567                dm_pci_read_config(dev, addr, &val, size);
 568#else
 569                val = pci_read_config(bdf, addr, size);
 570#endif
 571                printf(" %0*lx", pci_field_width(size), val);
 572
 573                nbytes = cli_readline(" ? ");
 574                if (nbytes == 0 || (nbytes == 1 && console_buffer[0] == '-')) {
 575                        /* <CR> pressed as only input, don't modify current
 576                         * location and move to next. "-" pressed will go back.
 577                         */
 578                        if (incrflag)
 579                                addr += nbytes ? -size : size;
 580                        nbytes = 1;
 581                        /* good enough to not time out */
 582                        bootretry_reset_cmd_timeout();
 583                }
 584#ifdef CONFIG_BOOT_RETRY_TIME
 585                else if (nbytes == -2) {
 586                        break;  /* timed out, exit the command  */
 587                }
 588#endif
 589                else {
 590                        char *endp;
 591                        i = simple_strtoul(console_buffer, &endp, 16);
 592                        nbytes = endp - console_buffer;
 593                        if (nbytes) {
 594                                /* good enough to not time out
 595                                 */
 596                                bootretry_reset_cmd_timeout();
 597#ifdef CONFIG_DM_PCI
 598                                dm_pci_write_config(dev, addr, i, size);
 599#else
 600                                pci_cfg_write(bdf, addr, size, i);
 601#endif
 602                                if (incrflag)
 603                                        addr += size;
 604                        }
 605                }
 606        } while (nbytes);
 607
 608        return 0;
 609}
 610
 611#ifdef CONFIG_DM_PCI
 612static const struct pci_flag_info {
 613        uint flag;
 614        const char *name;
 615} pci_flag_info[] = {
 616        { PCI_REGION_IO, "io" },
 617        { PCI_REGION_PREFETCH, "prefetch" },
 618        { PCI_REGION_SYS_MEMORY, "sysmem" },
 619        { PCI_REGION_RO, "readonly" },
 620        { PCI_REGION_IO, "io" },
 621};
 622
 623static void pci_show_regions(struct udevice *bus)
 624{
 625        struct pci_controller *hose = dev_get_uclass_priv(bus);
 626        const struct pci_region *reg;
 627        int i, j;
 628
 629        if (!hose) {
 630                printf("Bus '%s' is not a PCI controller\n", bus->name);
 631                return;
 632        }
 633
 634        printf("#   %-18s %-18s %-18s  %s\n", "Bus start", "Phys start", "Size",
 635               "Flags");
 636        for (i = 0, reg = hose->regions; i < hose->region_count; i++, reg++) {
 637                printf("%d   %#018llx %#018llx %#018llx  ", i,
 638                       (unsigned long long)reg->bus_start,
 639                       (unsigned long long)reg->phys_start,
 640                       (unsigned long long)reg->size);
 641                if (!(reg->flags & PCI_REGION_TYPE))
 642                        printf("mem ");
 643                for (j = 0; j < ARRAY_SIZE(pci_flag_info); j++) {
 644                        if (reg->flags & pci_flag_info[j].flag)
 645                                printf("%s ", pci_flag_info[j].name);
 646                }
 647                printf("\n");
 648        }
 649}
 650#endif
 651
 652/* PCI Configuration Space access commands
 653 *
 654 * Syntax:
 655 *      pci display[.b, .w, .l] bus.device.function} [addr] [len]
 656 *      pci next[.b, .w, .l] bus.device.function [addr]
 657 *      pci modify[.b, .w, .l] bus.device.function [addr]
 658 *      pci write[.b, .w, .l] bus.device.function addr value
 659 */
 660static int do_pci(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
 661{
 662        ulong addr = 0, value = 0, cmd_size = 0;
 663        enum pci_size_t size = PCI_SIZE_32;
 664#ifdef CONFIG_DM_PCI
 665        struct udevice *dev, *bus;
 666#else
 667        pci_dev_t dev;
 668#endif
 669        int busnum = 0;
 670        pci_dev_t bdf = 0;
 671        char cmd = 's';
 672        int ret = 0;
 673
 674        if (argc > 1)
 675                cmd = argv[1][0];
 676
 677        switch (cmd) {
 678        case 'd':               /* display */
 679        case 'n':               /* next */
 680        case 'm':               /* modify */
 681        case 'w':               /* write */
 682                /* Check for a size specification. */
 683                cmd_size = cmd_get_data_size(argv[1], 4);
 684                size = (cmd_size == 4) ? PCI_SIZE_32 : cmd_size - 1;
 685                if (argc > 3)
 686                        addr = simple_strtoul(argv[3], NULL, 16);
 687                if (argc > 4)
 688                        value = simple_strtoul(argv[4], NULL, 16);
 689        case 'h':               /* header */
 690#ifdef CONFIG_DM_PCI
 691        case 'b':               /* bars */
 692#endif
 693                if (argc < 3)
 694                        goto usage;
 695                if ((bdf = get_pci_dev(argv[2])) == -1)
 696                        return 1;
 697                break;
 698#if defined(CONFIG_DM_PCI)
 699        case 'e':
 700                pci_init();
 701                return 0;
 702#endif
 703        case 'r': /* no break */
 704        default:                /* scan bus */
 705                value = 1; /* short listing */
 706                if (argc > 1) {
 707                        if (cmd != 'r' && argv[argc-1][0] == 'l') {
 708                                value = 0;
 709                                argc--;
 710                        }
 711                        if (argc > 1)
 712                                busnum = simple_strtoul(argv[1], NULL, 16);
 713                }
 714#ifdef CONFIG_DM_PCI
 715                ret = uclass_get_device_by_seq(UCLASS_PCI, busnum, &bus);
 716                if (ret) {
 717                        printf("No such bus\n");
 718                        return CMD_RET_FAILURE;
 719                }
 720                if (cmd == 'r')
 721                        pci_show_regions(bus);
 722                else
 723                        pciinfo(bus, value);
 724#else
 725                pciinfo(busnum, value);
 726#endif
 727                return 0;
 728        }
 729
 730#ifdef CONFIG_DM_PCI
 731        ret = dm_pci_bus_find_bdf(bdf, &dev);
 732        if (ret) {
 733                printf("No such device\n");
 734                return CMD_RET_FAILURE;
 735        }
 736#else
 737        dev = bdf;
 738#endif
 739
 740        switch (argv[1][0]) {
 741        case 'h':               /* header */
 742                pci_header_show(dev);
 743                break;
 744        case 'd':               /* display */
 745                return pci_cfg_display(dev, addr, size, value);
 746        case 'n':               /* next */
 747                if (argc < 4)
 748                        goto usage;
 749                ret = pci_cfg_modify(dev, addr, size, value, 0);
 750                break;
 751        case 'm':               /* modify */
 752                if (argc < 4)
 753                        goto usage;
 754                ret = pci_cfg_modify(dev, addr, size, value, 1);
 755                break;
 756        case 'w':               /* write */
 757                if (argc < 5)
 758                        goto usage;
 759#ifdef CONFIG_DM_PCI
 760                ret = dm_pci_write_config(dev, addr, value, size);
 761#else
 762                ret = pci_cfg_write(dev, addr, size, value);
 763#endif
 764                break;
 765#ifdef CONFIG_DM_PCI
 766
 767        case 'b':               /* bars */
 768                return pci_bar_show(dev);
 769#endif
 770        default:
 771                ret = CMD_RET_USAGE;
 772                break;
 773        }
 774
 775        return ret;
 776 usage:
 777        return CMD_RET_USAGE;
 778}
 779
 780/***************************************************/
 781
 782#ifdef CONFIG_SYS_LONGHELP
 783static char pci_help_text[] =
 784        "[bus] [long]\n"
 785        "    - short or long list of PCI devices on bus 'bus'\n"
 786#if defined(CONFIG_DM_PCI)
 787        "pci enum\n"
 788        "    - Enumerate PCI buses\n"
 789#endif
 790        "pci header b.d.f\n"
 791        "    - show header of PCI device 'bus.device.function'\n"
 792#ifdef CONFIG_DM_PCI
 793        "pci bar b.d.f\n"
 794        "    - show BARs base and size for device b.d.f'\n"
 795        "pci regions\n"
 796        "    - show PCI regions\n"
 797#endif
 798        "pci display[.b, .w, .l] b.d.f [address] [# of objects]\n"
 799        "    - display PCI configuration space (CFG)\n"
 800        "pci next[.b, .w, .l] b.d.f address\n"
 801        "    - modify, read and keep CFG address\n"
 802        "pci modify[.b, .w, .l] b.d.f address\n"
 803        "    -  modify, auto increment CFG address\n"
 804        "pci write[.b, .w, .l] b.d.f address value\n"
 805        "    - write to CFG address";
 806#endif
 807
 808U_BOOT_CMD(
 809        pci,    5,      1,      do_pci,
 810        "list and access PCI Configuration Space", pci_help_text
 811);
 812