1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * PCI auto-configuration library 4 * 5 * Author: Matt Porter <mporter (at) 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 (at) 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, bool supports_64bit) 36 { 37 pci_addr_t addr; 38 39 if (!res) { 40 debug("No resource\n"); 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 if (upper_32_bits(addr) && !supports_64bit) { 52 debug("Cannot assign 64-bit address to 32-bit-only resource\n"); 53 goto error; 54 } 55 56 res->bus_lower = addr + size; 57 58 debug("address=0x%llx bus_lower=0x%llx\n", (unsigned long long)addr, 59 (unsigned long long)res->bus_lower); 60 61 *bar = addr; 62 return 0; 63 64 error: 65 *bar = (pci_addr_t)-1; 66 return -1; 67 } 68 69 static void pciauto_show_region(const char *name, struct pci_region *region) 70 { 71 pciauto_region_init(region); 72 debug("PCI Autoconfig: Bus %s region: [%llx-%llx],\n" 73 "\t\tPhysical Memory [%llx-%llxx]\n", name, 74 (unsigned long long)region->bus_start, 75 (unsigned long long)(region->bus_start + region->size - 1), 76 (unsigned long long)region->phys_start, 77 (unsigned long long)(region->phys_start + region->size - 1)); 78 } 79 80 void pciauto_config_init(struct pci_controller *hose) 81 { 82 int i; 83 84 hose->pci_io = NULL; 85 hose->pci_mem = NULL; 86 hose->pci_prefetch = NULL; 87 88 for (i = 0; i < hose->region_count; i++) { 89 switch (hose->regions[i].flags) { 90 case PCI_REGION_IO: 91 if (!hose->pci_io || 92 hose->pci_io->size < hose->regions[i].size) 93 hose->pci_io = hose->regions + i; 94 break; 95 case PCI_REGION_MEM: 96 if (!hose->pci_mem || 97 hose->pci_mem->size < hose->regions[i].size) 98 hose->pci_mem = hose->regions + i; 99 break; 100 case (PCI_REGION_MEM | PCI_REGION_PREFETCH): 101 if (!hose->pci_prefetch || 102 hose->pci_prefetch->size < hose->regions[i].size) 103 hose->pci_prefetch = hose->regions + i; 104 break; 105 } 106 } 107 108 109 if (hose->pci_mem) 110 pciauto_show_region("Memory", hose->pci_mem); 111 if (hose->pci_prefetch) 112 pciauto_show_region("Prefetchable Mem", hose->pci_prefetch); 113 if (hose->pci_io) 114 pciauto_show_region("I/O", hose->pci_io); 115 } 116