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