uboot/drivers/pci/pci_common.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (c) 2014 Google, Inc
   4 *
   5 * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
   6 * Andreas Heppel <aheppel@sysgo.de>
   7 *
   8 * (C) Copyright 2002, 2003
   9 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
  10 */
  11
  12#include <common.h>
  13#include <dm.h>
  14#include <env.h>
  15#include <errno.h>
  16#include <pci.h>
  17#include <asm/io.h>
  18
  19const char *pci_class_str(u8 class)
  20{
  21        switch (class) {
  22        case PCI_CLASS_NOT_DEFINED:
  23                return "Build before PCI Rev2.0";
  24                break;
  25        case PCI_BASE_CLASS_STORAGE:
  26                return "Mass storage controller";
  27                break;
  28        case PCI_BASE_CLASS_NETWORK:
  29                return "Network controller";
  30                break;
  31        case PCI_BASE_CLASS_DISPLAY:
  32                return "Display controller";
  33                break;
  34        case PCI_BASE_CLASS_MULTIMEDIA:
  35                return "Multimedia device";
  36                break;
  37        case PCI_BASE_CLASS_MEMORY:
  38                return "Memory controller";
  39                break;
  40        case PCI_BASE_CLASS_BRIDGE:
  41                return "Bridge device";
  42                break;
  43        case PCI_BASE_CLASS_COMMUNICATION:
  44                return "Simple comm. controller";
  45                break;
  46        case PCI_BASE_CLASS_SYSTEM:
  47                return "Base system peripheral";
  48                break;
  49        case PCI_BASE_CLASS_INPUT:
  50                return "Input device";
  51                break;
  52        case PCI_BASE_CLASS_DOCKING:
  53                return "Docking station";
  54                break;
  55        case PCI_BASE_CLASS_PROCESSOR:
  56                return "Processor";
  57                break;
  58        case PCI_BASE_CLASS_SERIAL:
  59                return "Serial bus controller";
  60                break;
  61        case PCI_BASE_CLASS_INTELLIGENT:
  62                return "Intelligent controller";
  63                break;
  64        case PCI_BASE_CLASS_SATELLITE:
  65                return "Satellite controller";
  66                break;
  67        case PCI_BASE_CLASS_CRYPT:
  68                return "Cryptographic device";
  69                break;
  70        case PCI_BASE_CLASS_SIGNAL_PROCESSING:
  71                return "DSP";
  72                break;
  73        case PCI_CLASS_OTHERS:
  74                return "Does not fit any class";
  75                break;
  76        default:
  77        return  "???";
  78                break;
  79        };
  80}
  81
  82__weak int pci_skip_dev(struct pci_controller *hose, pci_dev_t dev)
  83{
  84        /*
  85         * Check if pci device should be skipped in configuration
  86         */
  87        if (dev == PCI_BDF(hose->first_busno, 0, 0)) {
  88#if defined(CONFIG_PCI_CONFIG_HOST_BRIDGE) /* don't skip host bridge */
  89                /*
  90                 * Only skip configuration if "pciconfighost" is not set
  91                 */
  92                if (env_get("pciconfighost") == NULL)
  93                        return 1;
  94#else
  95                return 1;
  96#endif
  97        }
  98
  99        return 0;
 100}
 101
 102#if defined(CONFIG_DM_PCI_COMPAT)
 103/* Get a virtual address associated with a BAR region */
 104void *pci_map_bar(pci_dev_t pdev, int bar, int flags)
 105{
 106        pci_addr_t pci_bus_addr;
 107        u32 bar_response;
 108
 109        /* read BAR address */
 110        pci_read_config_dword(pdev, bar, &bar_response);
 111        pci_bus_addr = (pci_addr_t)(bar_response & ~0xf);
 112
 113        /*
 114         * Pass "0" as the length argument to pci_bus_to_virt.  The arg
 115         * isn't actualy used on any platform because u-boot assumes a static
 116         * linear mapping.  In the future, this could read the BAR size
 117         * and pass that as the size if needed.
 118         */
 119        return pci_bus_to_virt(pdev, pci_bus_addr, flags, 0, MAP_NOCACHE);
 120}
 121
 122void pci_write_bar32(struct pci_controller *hose, pci_dev_t dev, int barnum,
 123                     u32 addr_and_ctrl)
 124{
 125        int bar;
 126
 127        bar = PCI_BASE_ADDRESS_0 + barnum * 4;
 128        pci_hose_write_config_dword(hose, dev, bar, addr_and_ctrl);
 129}
 130
 131u32 pci_read_bar32(struct pci_controller *hose, pci_dev_t dev, int barnum)
 132{
 133        u32 addr;
 134        int bar;
 135
 136        bar = PCI_BASE_ADDRESS_0 + barnum * 4;
 137        pci_hose_read_config_dword(hose, dev, bar, &addr);
 138        if (addr & PCI_BASE_ADDRESS_SPACE_IO)
 139                return addr & PCI_BASE_ADDRESS_IO_MASK;
 140        else
 141                return addr & PCI_BASE_ADDRESS_MEM_MASK;
 142}
 143
 144int __pci_hose_bus_to_phys(struct pci_controller *hose,
 145                           pci_addr_t bus_addr,
 146                           unsigned long flags,
 147                           unsigned long skip_mask,
 148                           phys_addr_t *pa)
 149{
 150        struct pci_region *res;
 151        int i;
 152
 153        for (i = 0; i < hose->region_count; i++) {
 154                res = &hose->regions[i];
 155
 156                if (((res->flags ^ flags) & PCI_REGION_TYPE) != 0)
 157                        continue;
 158
 159                if (res->flags & skip_mask)
 160                        continue;
 161
 162                if (bus_addr >= res->bus_start &&
 163                    (bus_addr - res->bus_start) < res->size) {
 164                        *pa = (bus_addr - res->bus_start + res->phys_start);
 165                        return 0;
 166                }
 167        }
 168
 169        return 1;
 170}
 171
 172phys_addr_t pci_hose_bus_to_phys(struct pci_controller *hose,
 173                                 pci_addr_t bus_addr,
 174                                 unsigned long flags)
 175{
 176        phys_addr_t phys_addr = 0;
 177        int ret;
 178
 179        if (!hose) {
 180                puts("pci_hose_bus_to_phys: invalid hose\n");
 181                return phys_addr;
 182        }
 183
 184        /*
 185         * if PCI_REGION_MEM is set we do a two pass search with preference
 186         * on matches that don't have PCI_REGION_SYS_MEMORY set
 187         */
 188        if ((flags & PCI_REGION_TYPE) == PCI_REGION_MEM) {
 189                ret = __pci_hose_bus_to_phys(hose, bus_addr,
 190                                flags, PCI_REGION_SYS_MEMORY, &phys_addr);
 191                if (!ret)
 192                        return phys_addr;
 193        }
 194
 195        ret = __pci_hose_bus_to_phys(hose, bus_addr, flags, 0, &phys_addr);
 196
 197        if (ret)
 198                puts("pci_hose_bus_to_phys: invalid physical address\n");
 199
 200        return phys_addr;
 201}
 202
 203int __pci_hose_phys_to_bus(struct pci_controller *hose,
 204                           phys_addr_t phys_addr,
 205                           unsigned long flags,
 206                           unsigned long skip_mask,
 207                           pci_addr_t *ba)
 208{
 209        struct pci_region *res;
 210        pci_addr_t bus_addr;
 211        int i;
 212
 213        for (i = 0; i < hose->region_count; i++) {
 214                res = &hose->regions[i];
 215
 216                if (((res->flags ^ flags) & PCI_REGION_TYPE) != 0)
 217                        continue;
 218
 219                if (res->flags & skip_mask)
 220                        continue;
 221
 222                bus_addr = phys_addr - res->phys_start + res->bus_start;
 223
 224                if (bus_addr >= res->bus_start &&
 225                    (bus_addr - res->bus_start) < res->size) {
 226                        *ba = bus_addr;
 227                        return 0;
 228                }
 229        }
 230
 231        return 1;
 232}
 233
 234/*
 235 * pci_hose_phys_to_bus(): Convert physical address to bus address
 236 * @hose:       PCI hose of the root PCI controller
 237 * @phys_addr:  physical address to convert
 238 * @flags:      flags of pci regions
 239 * Return: bus address if OK, 0 on error
 240 */
 241pci_addr_t pci_hose_phys_to_bus(struct pci_controller *hose,
 242                                phys_addr_t phys_addr,
 243                                unsigned long flags)
 244{
 245        pci_addr_t bus_addr = 0;
 246        int ret;
 247
 248        if (!hose) {
 249                puts("pci_hose_phys_to_bus: invalid hose\n");
 250                return bus_addr;
 251        }
 252
 253        /*
 254         * if PCI_REGION_MEM is set we do a two pass search with preference
 255         * on matches that don't have PCI_REGION_SYS_MEMORY set
 256         */
 257        if ((flags & PCI_REGION_TYPE) == PCI_REGION_MEM) {
 258                ret = __pci_hose_phys_to_bus(hose, phys_addr,
 259                                flags, PCI_REGION_SYS_MEMORY, &bus_addr);
 260                if (!ret)
 261                        return bus_addr;
 262        }
 263
 264        ret = __pci_hose_phys_to_bus(hose, phys_addr, flags, 0, &bus_addr);
 265
 266        if (ret)
 267                puts("pci_hose_phys_to_bus: invalid physical address\n");
 268
 269        return bus_addr;
 270}
 271
 272pci_dev_t pci_find_device(unsigned int vendor, unsigned int device, int index)
 273{
 274        struct pci_device_id ids[2] = { {}, {0, 0} };
 275
 276        ids[0].vendor = vendor;
 277        ids[0].device = device;
 278
 279        return pci_find_devices(ids, index);
 280}
 281
 282pci_dev_t pci_hose_find_devices(struct pci_controller *hose, int busnum,
 283                                struct pci_device_id *ids, int *indexp)
 284{
 285        int found_multi = 0;
 286        u16 vendor, device;
 287        u8 header_type;
 288        pci_dev_t bdf;
 289        int i;
 290
 291        for (bdf = PCI_BDF(busnum, 0, 0);
 292             bdf < PCI_BDF(busnum + 1, 0, 0);
 293             bdf += PCI_BDF(0, 0, 1)) {
 294                if (pci_skip_dev(hose, bdf))
 295                        continue;
 296
 297                if (!PCI_FUNC(bdf)) {
 298                        pci_read_config_byte(bdf, PCI_HEADER_TYPE,
 299                                             &header_type);
 300                        found_multi = header_type & 0x80;
 301                } else {
 302                        if (!found_multi)
 303                                continue;
 304                }
 305
 306                pci_read_config_word(bdf, PCI_VENDOR_ID, &vendor);
 307                pci_read_config_word(bdf, PCI_DEVICE_ID, &device);
 308
 309                for (i = 0; ids[i].vendor != 0; i++) {
 310                        if (vendor == ids[i].vendor &&
 311                            device == ids[i].device) {
 312                                if ((*indexp) <= 0)
 313                                        return bdf;
 314
 315                                (*indexp)--;
 316                        }
 317                }
 318        }
 319
 320        return -1;
 321}
 322
 323pci_dev_t pci_find_class(uint find_class, int index)
 324{
 325        int bus;
 326        int devnum;
 327        pci_dev_t bdf;
 328        uint32_t class;
 329
 330        for (bus = 0; bus <= pci_last_busno(); bus++) {
 331                for (devnum = 0; devnum < PCI_MAX_PCI_DEVICES - 1; devnum++) {
 332                        pci_read_config_dword(PCI_BDF(bus, devnum, 0),
 333                                              PCI_CLASS_REVISION, &class);
 334                        if (class >> 16 == 0xffff)
 335                                continue;
 336
 337                        for (bdf = PCI_BDF(bus, devnum, 0);
 338                                        bdf <= PCI_BDF(bus, devnum,
 339                                                PCI_MAX_PCI_FUNCTIONS - 1);
 340                                        bdf += PCI_BDF(0, 0, 1)) {
 341                                pci_read_config_dword(bdf, PCI_CLASS_REVISION,
 342                                                      &class);
 343                                class >>= 8;
 344
 345                                if (class != find_class)
 346                                        continue;
 347                                /*
 348                                 * Decrement the index. We want to return the
 349                                 * correct device, so index is 0 for the first
 350                                 * matching device, 1 for the second, etc.
 351                                 */
 352                                if (index) {
 353                                        index--;
 354                                        continue;
 355                                }
 356                                /* Return index'th controller. */
 357                                return bdf;
 358                        }
 359                }
 360        }
 361
 362        return -ENODEV;
 363}
 364#endif /* CONFIG_DM_PCI_COMPAT */
 365