1aab6724cSSimon Glass /* 2aab6724cSSimon Glass * Copyright (c) 2014 Google, Inc 3aab6724cSSimon Glass * 4aab6724cSSimon Glass * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com> 5aab6724cSSimon Glass * Andreas Heppel <aheppel@sysgo.de> 6aab6724cSSimon Glass * 7aab6724cSSimon Glass * (C) Copyright 2002, 2003 8aab6724cSSimon Glass * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 9aab6724cSSimon Glass * 10aab6724cSSimon Glass * SPDX-License-Identifier: GPL-2.0+ 11aab6724cSSimon Glass */ 12aab6724cSSimon Glass 13aab6724cSSimon Glass #include <common.h> 14aec241dfSSimon Glass #include <dm.h> 15aab6724cSSimon Glass #include <errno.h> 16aab6724cSSimon Glass #include <pci.h> 17aab6724cSSimon Glass #include <asm/io.h> 18aab6724cSSimon Glass 19aab6724cSSimon Glass const char *pci_class_str(u8 class) 20aab6724cSSimon Glass { 21aab6724cSSimon Glass switch (class) { 22aab6724cSSimon Glass case PCI_CLASS_NOT_DEFINED: 23aab6724cSSimon Glass return "Build before PCI Rev2.0"; 24aab6724cSSimon Glass break; 25aab6724cSSimon Glass case PCI_BASE_CLASS_STORAGE: 26aab6724cSSimon Glass return "Mass storage controller"; 27aab6724cSSimon Glass break; 28aab6724cSSimon Glass case PCI_BASE_CLASS_NETWORK: 29aab6724cSSimon Glass return "Network controller"; 30aab6724cSSimon Glass break; 31aab6724cSSimon Glass case PCI_BASE_CLASS_DISPLAY: 32aab6724cSSimon Glass return "Display controller"; 33aab6724cSSimon Glass break; 34aab6724cSSimon Glass case PCI_BASE_CLASS_MULTIMEDIA: 35aab6724cSSimon Glass return "Multimedia device"; 36aab6724cSSimon Glass break; 37aab6724cSSimon Glass case PCI_BASE_CLASS_MEMORY: 38aab6724cSSimon Glass return "Memory controller"; 39aab6724cSSimon Glass break; 40aab6724cSSimon Glass case PCI_BASE_CLASS_BRIDGE: 41aab6724cSSimon Glass return "Bridge device"; 42aab6724cSSimon Glass break; 43aab6724cSSimon Glass case PCI_BASE_CLASS_COMMUNICATION: 44aab6724cSSimon Glass return "Simple comm. controller"; 45aab6724cSSimon Glass break; 46aab6724cSSimon Glass case PCI_BASE_CLASS_SYSTEM: 47aab6724cSSimon Glass return "Base system peripheral"; 48aab6724cSSimon Glass break; 49aab6724cSSimon Glass case PCI_BASE_CLASS_INPUT: 50aab6724cSSimon Glass return "Input device"; 51aab6724cSSimon Glass break; 52aab6724cSSimon Glass case PCI_BASE_CLASS_DOCKING: 53aab6724cSSimon Glass return "Docking station"; 54aab6724cSSimon Glass break; 55aab6724cSSimon Glass case PCI_BASE_CLASS_PROCESSOR: 56aab6724cSSimon Glass return "Processor"; 57aab6724cSSimon Glass break; 58aab6724cSSimon Glass case PCI_BASE_CLASS_SERIAL: 59aab6724cSSimon Glass return "Serial bus controller"; 60aab6724cSSimon Glass break; 61aab6724cSSimon Glass case PCI_BASE_CLASS_INTELLIGENT: 62aab6724cSSimon Glass return "Intelligent controller"; 63aab6724cSSimon Glass break; 64aab6724cSSimon Glass case PCI_BASE_CLASS_SATELLITE: 65aab6724cSSimon Glass return "Satellite controller"; 66aab6724cSSimon Glass break; 67aab6724cSSimon Glass case PCI_BASE_CLASS_CRYPT: 68aab6724cSSimon Glass return "Cryptographic device"; 69aab6724cSSimon Glass break; 70aab6724cSSimon Glass case PCI_BASE_CLASS_SIGNAL_PROCESSING: 71aab6724cSSimon Glass return "DSP"; 72aab6724cSSimon Glass break; 73aab6724cSSimon Glass case PCI_CLASS_OTHERS: 74aab6724cSSimon Glass return "Does not fit any class"; 75aab6724cSSimon Glass break; 76aab6724cSSimon Glass default: 77aab6724cSSimon Glass return "???"; 78aab6724cSSimon Glass break; 79aab6724cSSimon Glass }; 80aab6724cSSimon Glass } 81aab6724cSSimon Glass 82aab6724cSSimon Glass __weak int pci_skip_dev(struct pci_controller *hose, pci_dev_t dev) 83aab6724cSSimon Glass { 84aab6724cSSimon Glass /* 85aab6724cSSimon Glass * Check if pci device should be skipped in configuration 86aab6724cSSimon Glass */ 87aab6724cSSimon Glass if (dev == PCI_BDF(hose->first_busno, 0, 0)) { 88aab6724cSSimon Glass #if defined(CONFIG_PCI_CONFIG_HOST_BRIDGE) /* don't skip host bridge */ 89aab6724cSSimon Glass /* 90aab6724cSSimon Glass * Only skip configuration if "pciconfighost" is not set 91aab6724cSSimon Glass */ 92aab6724cSSimon Glass if (getenv("pciconfighost") == NULL) 93aab6724cSSimon Glass return 1; 94aab6724cSSimon Glass #else 95aab6724cSSimon Glass return 1; 96aab6724cSSimon Glass #endif 97aab6724cSSimon Glass } 98aab6724cSSimon Glass 99aab6724cSSimon Glass return 0; 100aab6724cSSimon Glass } 101aab6724cSSimon Glass 1027e78b9efSSimon Glass #if !defined(CONFIG_DM_PCI) || defined(CONFIG_DM_PCI_COMPAT) 103aab6724cSSimon Glass /* Get a virtual address associated with a BAR region */ 104aab6724cSSimon Glass void *pci_map_bar(pci_dev_t pdev, int bar, int flags) 105aab6724cSSimon Glass { 106aab6724cSSimon Glass pci_addr_t pci_bus_addr; 107aab6724cSSimon Glass u32 bar_response; 108aab6724cSSimon Glass 109aab6724cSSimon Glass /* read BAR address */ 110aab6724cSSimon Glass pci_read_config_dword(pdev, bar, &bar_response); 111aab6724cSSimon Glass pci_bus_addr = (pci_addr_t)(bar_response & ~0xf); 112aab6724cSSimon Glass 113aab6724cSSimon Glass /* 114aab6724cSSimon Glass * Pass "0" as the length argument to pci_bus_to_virt. The arg 115aab6724cSSimon Glass * isn't actualy used on any platform because u-boot assumes a static 116aab6724cSSimon Glass * linear mapping. In the future, this could read the BAR size 117aab6724cSSimon Glass * and pass that as the size if needed. 118aab6724cSSimon Glass */ 119aab6724cSSimon Glass return pci_bus_to_virt(pdev, pci_bus_addr, flags, 0, MAP_NOCACHE); 120aab6724cSSimon Glass } 121aab6724cSSimon Glass 122aab6724cSSimon Glass void pci_write_bar32(struct pci_controller *hose, pci_dev_t dev, int barnum, 123aab6724cSSimon Glass u32 addr_and_ctrl) 124aab6724cSSimon Glass { 125aab6724cSSimon Glass int bar; 126aab6724cSSimon Glass 127aab6724cSSimon Glass bar = PCI_BASE_ADDRESS_0 + barnum * 4; 128aab6724cSSimon Glass pci_hose_write_config_dword(hose, dev, bar, addr_and_ctrl); 129aab6724cSSimon Glass } 130aab6724cSSimon Glass 131aab6724cSSimon Glass u32 pci_read_bar32(struct pci_controller *hose, pci_dev_t dev, int barnum) 132aab6724cSSimon Glass { 133aab6724cSSimon Glass u32 addr; 134aab6724cSSimon Glass int bar; 135aab6724cSSimon Glass 136aab6724cSSimon Glass bar = PCI_BASE_ADDRESS_0 + barnum * 4; 137aab6724cSSimon Glass pci_hose_read_config_dword(hose, dev, bar, &addr); 138aab6724cSSimon Glass if (addr & PCI_BASE_ADDRESS_SPACE_IO) 139aab6724cSSimon Glass return addr & PCI_BASE_ADDRESS_IO_MASK; 140aab6724cSSimon Glass else 141aab6724cSSimon Glass return addr & PCI_BASE_ADDRESS_MEM_MASK; 142aab6724cSSimon Glass } 143aab6724cSSimon Glass 144aab6724cSSimon Glass int __pci_hose_bus_to_phys(struct pci_controller *hose, 145aab6724cSSimon Glass pci_addr_t bus_addr, 146aab6724cSSimon Glass unsigned long flags, 147aab6724cSSimon Glass unsigned long skip_mask, 148aab6724cSSimon Glass phys_addr_t *pa) 149aab6724cSSimon Glass { 150aab6724cSSimon Glass struct pci_region *res; 151aab6724cSSimon Glass int i; 152aab6724cSSimon Glass 153aab6724cSSimon Glass for (i = 0; i < hose->region_count; i++) { 154aab6724cSSimon Glass res = &hose->regions[i]; 155aab6724cSSimon Glass 156aab6724cSSimon Glass if (((res->flags ^ flags) & PCI_REGION_TYPE) != 0) 157aab6724cSSimon Glass continue; 158aab6724cSSimon Glass 159aab6724cSSimon Glass if (res->flags & skip_mask) 160aab6724cSSimon Glass continue; 161aab6724cSSimon Glass 162aab6724cSSimon Glass if (bus_addr >= res->bus_start && 163aab6724cSSimon Glass (bus_addr - res->bus_start) < res->size) { 164aab6724cSSimon Glass *pa = (bus_addr - res->bus_start + res->phys_start); 165aab6724cSSimon Glass return 0; 166aab6724cSSimon Glass } 167aab6724cSSimon Glass } 168aab6724cSSimon Glass 169aab6724cSSimon Glass return 1; 170aab6724cSSimon Glass } 171aab6724cSSimon Glass 172aab6724cSSimon Glass phys_addr_t pci_hose_bus_to_phys(struct pci_controller *hose, 173aab6724cSSimon Glass pci_addr_t bus_addr, 174aab6724cSSimon Glass unsigned long flags) 175aab6724cSSimon Glass { 176aab6724cSSimon Glass phys_addr_t phys_addr = 0; 177aab6724cSSimon Glass int ret; 178aab6724cSSimon Glass 179aab6724cSSimon Glass if (!hose) { 180aab6724cSSimon Glass puts("pci_hose_bus_to_phys: invalid hose\n"); 181aab6724cSSimon Glass return phys_addr; 182aab6724cSSimon Glass } 183aab6724cSSimon Glass 184aab6724cSSimon Glass /* 185aab6724cSSimon Glass * if PCI_REGION_MEM is set we do a two pass search with preference 186aab6724cSSimon Glass * on matches that don't have PCI_REGION_SYS_MEMORY set 187aab6724cSSimon Glass */ 18835262850SCheng Gu if ((flags & PCI_REGION_TYPE) == PCI_REGION_MEM) { 189aab6724cSSimon Glass ret = __pci_hose_bus_to_phys(hose, bus_addr, 190aab6724cSSimon Glass flags, PCI_REGION_SYS_MEMORY, &phys_addr); 191aab6724cSSimon Glass if (!ret) 192aab6724cSSimon Glass return phys_addr; 193aab6724cSSimon Glass } 194aab6724cSSimon Glass 195aab6724cSSimon Glass ret = __pci_hose_bus_to_phys(hose, bus_addr, flags, 0, &phys_addr); 196aab6724cSSimon Glass 197aab6724cSSimon Glass if (ret) 198aab6724cSSimon Glass puts("pci_hose_bus_to_phys: invalid physical address\n"); 199aab6724cSSimon Glass 200aab6724cSSimon Glass return phys_addr; 201238fe16cSBin Meng } 202238fe16cSBin Meng 203238fe16cSBin Meng int __pci_hose_phys_to_bus(struct pci_controller *hose, 204238fe16cSBin Meng phys_addr_t phys_addr, 205238fe16cSBin Meng unsigned long flags, 206238fe16cSBin Meng unsigned long skip_mask, 207238fe16cSBin Meng pci_addr_t *ba) 208238fe16cSBin Meng { 209238fe16cSBin Meng struct pci_region *res; 210238fe16cSBin Meng pci_addr_t bus_addr; 211238fe16cSBin Meng int i; 212238fe16cSBin Meng 213238fe16cSBin Meng for (i = 0; i < hose->region_count; i++) { 214238fe16cSBin Meng res = &hose->regions[i]; 215238fe16cSBin Meng 216238fe16cSBin Meng if (((res->flags ^ flags) & PCI_REGION_TYPE) != 0) 217238fe16cSBin Meng continue; 218238fe16cSBin Meng 219238fe16cSBin Meng if (res->flags & skip_mask) 220238fe16cSBin Meng continue; 221238fe16cSBin Meng 222238fe16cSBin Meng bus_addr = phys_addr - res->phys_start + res->bus_start; 223238fe16cSBin Meng 224238fe16cSBin Meng if (bus_addr >= res->bus_start && 225b4bd6554SMarcel Ziswiler (bus_addr - res->bus_start) < res->size) { 226238fe16cSBin Meng *ba = bus_addr; 227238fe16cSBin Meng return 0; 228238fe16cSBin Meng } 229238fe16cSBin Meng } 230238fe16cSBin Meng 231238fe16cSBin Meng return 1; 232238fe16cSBin Meng } 233238fe16cSBin Meng 234*fcf45692SMinghuan Lian /* 235*fcf45692SMinghuan Lian * pci_hose_phys_to_bus(): Convert physical address to bus address 236*fcf45692SMinghuan Lian * @hose: PCI hose of the root PCI controller 237*fcf45692SMinghuan Lian * @phys_addr: physical address to convert 238*fcf45692SMinghuan Lian * @flags: flags of pci regions 239*fcf45692SMinghuan Lian * @return bus address if OK, 0 on error 240*fcf45692SMinghuan Lian */ 241238fe16cSBin Meng pci_addr_t pci_hose_phys_to_bus(struct pci_controller *hose, 242238fe16cSBin Meng phys_addr_t phys_addr, 243238fe16cSBin Meng unsigned long flags) 244238fe16cSBin Meng { 245238fe16cSBin Meng pci_addr_t bus_addr = 0; 246238fe16cSBin Meng int ret; 247238fe16cSBin Meng 248238fe16cSBin Meng if (!hose) { 249238fe16cSBin Meng puts("pci_hose_phys_to_bus: invalid hose\n"); 250238fe16cSBin Meng return bus_addr; 251238fe16cSBin Meng } 252238fe16cSBin Meng 253238fe16cSBin Meng /* 254238fe16cSBin Meng * if PCI_REGION_MEM is set we do a two pass search with preference 255238fe16cSBin Meng * on matches that don't have PCI_REGION_SYS_MEMORY set 256238fe16cSBin Meng */ 25735262850SCheng Gu if ((flags & PCI_REGION_TYPE) == PCI_REGION_MEM) { 258238fe16cSBin Meng ret = __pci_hose_phys_to_bus(hose, phys_addr, 259238fe16cSBin Meng flags, PCI_REGION_SYS_MEMORY, &bus_addr); 260238fe16cSBin Meng if (!ret) 261238fe16cSBin Meng return bus_addr; 262238fe16cSBin Meng } 263238fe16cSBin Meng 264238fe16cSBin Meng ret = __pci_hose_phys_to_bus(hose, phys_addr, flags, 0, &bus_addr); 265238fe16cSBin Meng 266238fe16cSBin Meng if (ret) 267238fe16cSBin Meng puts("pci_hose_phys_to_bus: invalid physical address\n"); 268238fe16cSBin Meng 269238fe16cSBin Meng return bus_addr; 270aab6724cSSimon Glass } 271aab6724cSSimon Glass 272aab6724cSSimon Glass pci_dev_t pci_find_device(unsigned int vendor, unsigned int device, int index) 273aab6724cSSimon Glass { 274aab6724cSSimon Glass struct pci_device_id ids[2] = { {}, {0, 0} }; 275aab6724cSSimon Glass 276aab6724cSSimon Glass ids[0].vendor = vendor; 277aab6724cSSimon Glass ids[0].device = device; 278aab6724cSSimon Glass 279aab6724cSSimon Glass return pci_find_devices(ids, index); 280aab6724cSSimon Glass } 281aab6724cSSimon Glass 282aab6724cSSimon Glass pci_dev_t pci_hose_find_devices(struct pci_controller *hose, int busnum, 283aab6724cSSimon Glass struct pci_device_id *ids, int *indexp) 284aab6724cSSimon Glass { 285aab6724cSSimon Glass int found_multi = 0; 286aab6724cSSimon Glass u16 vendor, device; 287aab6724cSSimon Glass u8 header_type; 288aab6724cSSimon Glass pci_dev_t bdf; 289aab6724cSSimon Glass int i; 290aab6724cSSimon Glass 291aab6724cSSimon Glass for (bdf = PCI_BDF(busnum, 0, 0); 292aab6724cSSimon Glass bdf < PCI_BDF(busnum + 1, 0, 0); 293aab6724cSSimon Glass bdf += PCI_BDF(0, 0, 1)) { 294aab6724cSSimon Glass if (pci_skip_dev(hose, bdf)) 295aab6724cSSimon Glass continue; 296aab6724cSSimon Glass 297aab6724cSSimon Glass if (!PCI_FUNC(bdf)) { 298aab6724cSSimon Glass pci_read_config_byte(bdf, PCI_HEADER_TYPE, 299aab6724cSSimon Glass &header_type); 300aab6724cSSimon Glass found_multi = header_type & 0x80; 301aab6724cSSimon Glass } else { 302aab6724cSSimon Glass if (!found_multi) 303aab6724cSSimon Glass continue; 304aab6724cSSimon Glass } 305aab6724cSSimon Glass 306aab6724cSSimon Glass pci_read_config_word(bdf, PCI_VENDOR_ID, &vendor); 307aab6724cSSimon Glass pci_read_config_word(bdf, PCI_DEVICE_ID, &device); 308aab6724cSSimon Glass 309aab6724cSSimon Glass for (i = 0; ids[i].vendor != 0; i++) { 310aab6724cSSimon Glass if (vendor == ids[i].vendor && 311aab6724cSSimon Glass device == ids[i].device) { 312aab6724cSSimon Glass if ((*indexp) <= 0) 313aab6724cSSimon Glass return bdf; 314aab6724cSSimon Glass 315aab6724cSSimon Glass (*indexp)--; 316aab6724cSSimon Glass } 317aab6724cSSimon Glass } 318aab6724cSSimon Glass } 319aab6724cSSimon Glass 320aab6724cSSimon Glass return -1; 321aab6724cSSimon Glass } 322170366c1SSimon Glass 323170366c1SSimon Glass pci_dev_t pci_find_class(uint find_class, int index) 324170366c1SSimon Glass { 325170366c1SSimon Glass int bus; 326170366c1SSimon Glass int devnum; 327170366c1SSimon Glass pci_dev_t bdf; 328170366c1SSimon Glass uint32_t class; 329170366c1SSimon Glass 330170366c1SSimon Glass for (bus = 0; bus <= pci_last_busno(); bus++) { 331170366c1SSimon Glass for (devnum = 0; devnum < PCI_MAX_PCI_DEVICES - 1; devnum++) { 332170366c1SSimon Glass pci_read_config_dword(PCI_BDF(bus, devnum, 0), 333170366c1SSimon Glass PCI_CLASS_REVISION, &class); 334170366c1SSimon Glass if (class >> 16 == 0xffff) 335170366c1SSimon Glass continue; 336170366c1SSimon Glass 337170366c1SSimon Glass for (bdf = PCI_BDF(bus, devnum, 0); 338170366c1SSimon Glass bdf <= PCI_BDF(bus, devnum, 339170366c1SSimon Glass PCI_MAX_PCI_FUNCTIONS - 1); 340170366c1SSimon Glass bdf += PCI_BDF(0, 0, 1)) { 341170366c1SSimon Glass pci_read_config_dword(bdf, PCI_CLASS_REVISION, 342170366c1SSimon Glass &class); 343170366c1SSimon Glass class >>= 8; 344170366c1SSimon Glass 345170366c1SSimon Glass if (class != find_class) 346170366c1SSimon Glass continue; 347170366c1SSimon Glass /* 348170366c1SSimon Glass * Decrement the index. We want to return the 349170366c1SSimon Glass * correct device, so index is 0 for the first 350170366c1SSimon Glass * matching device, 1 for the second, etc. 351170366c1SSimon Glass */ 352170366c1SSimon Glass if (index) { 353170366c1SSimon Glass index--; 354170366c1SSimon Glass continue; 355170366c1SSimon Glass } 356170366c1SSimon Glass /* Return index'th controller. */ 357170366c1SSimon Glass return bdf; 358170366c1SSimon Glass } 359170366c1SSimon Glass } 360170366c1SSimon Glass } 361170366c1SSimon Glass 362170366c1SSimon Glass return -ENODEV; 363170366c1SSimon Glass } 3640fe9cb0fSSimon Glass #endif /* !CONFIG_DM_PCI || CONFIG_DM_PCI_COMPAT */ 365