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