1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * PCI auto-configuration library 4 * 5 * Author: Matt Porter <mporter@mvista.com> 6 * 7 * Copyright 2000 MontaVista Software Inc. 8 * 9 * Modifications for driver model: 10 * Copyright 2015 Google, Inc 11 * Written by Simon Glass <sjg@chromium.org> 12 */ 13 14 #include <common.h> 15 #include <dm.h> 16 #include <errno.h> 17 #include <pci.h> 18 19 void pciauto_region_init(struct pci_region *res) 20 { 21 /* 22 * Avoid allocating PCI resources from address 0 -- this is illegal 23 * according to PCI 2.1 and moreover, this is known to cause Linux IDE 24 * drivers to fail. Use a reasonable starting value of 0x1000 instead. 25 */ 26 res->bus_lower = res->bus_start ? res->bus_start : 0x1000; 27 } 28 29 void pciauto_region_align(struct pci_region *res, pci_size_t size) 30 { 31 res->bus_lower = ((res->bus_lower - 1) | (size - 1)) + 1; 32 } 33 34 int pciauto_region_allocate(struct pci_region *res, pci_size_t size, 35 pci_addr_t *bar) 36 { 37 pci_addr_t addr; 38 39 if (!res) { 40 debug("No resource"); 41 goto error; 42 } 43 44 addr = ((res->bus_lower - 1) | (size - 1)) + 1; 45 46 if (addr - res->bus_start + size > res->size) { 47 debug("No room in resource"); 48 goto error; 49 } 50 51 res->bus_lower = addr + size; 52 53 debug("address=0x%llx bus_lower=0x%llx", (unsigned long long)addr, 54 (unsigned long long)res->bus_lower); 55 56 *bar = addr; 57 return 0; 58 59 error: 60 *bar = (pci_addr_t)-1; 61 return -1; 62 } 63 64 static void pciauto_show_region(const char *name, struct pci_region *region) 65 { 66 pciauto_region_init(region); 67 debug("PCI Autoconfig: Bus %s region: [%llx-%llx],\n" 68 "\t\tPhysical Memory [%llx-%llxx]\n", name, 69 (unsigned long long)region->bus_start, 70 (unsigned long long)(region->bus_start + region->size - 1), 71 (unsigned long long)region->phys_start, 72 (unsigned long long)(region->phys_start + region->size - 1)); 73 } 74 75 void pciauto_config_init(struct pci_controller *hose) 76 { 77 int i; 78 79 hose->pci_io = NULL; 80 hose->pci_mem = NULL; 81 hose->pci_prefetch = NULL; 82 83 for (i = 0; i < hose->region_count; i++) { 84 switch (hose->regions[i].flags) { 85 case PCI_REGION_IO: 86 if (!hose->pci_io || 87 hose->pci_io->size < hose->regions[i].size) 88 hose->pci_io = hose->regions + i; 89 break; 90 case PCI_REGION_MEM: 91 if (!hose->pci_mem || 92 hose->pci_mem->size < hose->regions[i].size) 93 hose->pci_mem = hose->regions + i; 94 break; 95 case (PCI_REGION_MEM | PCI_REGION_PREFETCH): 96 if (!hose->pci_prefetch || 97 hose->pci_prefetch->size < hose->regions[i].size) 98 hose->pci_prefetch = hose->regions + i; 99 break; 100 } 101 } 102 103 104 if (hose->pci_mem) 105 pciauto_show_region("Memory", hose->pci_mem); 106 if (hose->pci_prefetch) 107 pciauto_show_region("Prefetchable Mem", hose->pci_prefetch); 108 if (hose->pci_io) 109 pciauto_show_region("I/O", hose->pci_io); 110 } 111