uboot/drivers/pci/pci_auto_common.c
<<
>>
Prefs
   1/*
   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
  65static void pciauto_show_region(const char *name, struct pci_region *region)
  66{
  67        pciauto_region_init(region);
  68        debug("PCI Autoconfig: Bus %s region: [%llx-%llx],\n"
  69              "\t\tPhysical Memory [%llx-%llxx]\n", name,
  70              (unsigned long long)region->bus_start,
  71              (unsigned long long)(region->bus_start + region->size - 1),
  72              (unsigned long long)region->phys_start,
  73              (unsigned long long)(region->phys_start + region->size - 1));
  74}
  75
  76void pciauto_config_init(struct pci_controller *hose)
  77{
  78        int i;
  79
  80        hose->pci_io = NULL;
  81        hose->pci_mem = NULL;
  82        hose->pci_prefetch = NULL;
  83
  84        for (i = 0; i < hose->region_count; i++) {
  85                switch (hose->regions[i].flags) {
  86                case PCI_REGION_IO:
  87                        if (!hose->pci_io ||
  88                            hose->pci_io->size < hose->regions[i].size)
  89                                hose->pci_io = hose->regions + i;
  90                        break;
  91                case PCI_REGION_MEM:
  92                        if (!hose->pci_mem ||
  93                            hose->pci_mem->size < hose->regions[i].size)
  94                                hose->pci_mem = hose->regions + i;
  95                        break;
  96                case (PCI_REGION_MEM | PCI_REGION_PREFETCH):
  97                        if (!hose->pci_prefetch ||
  98                            hose->pci_prefetch->size < hose->regions[i].size)
  99                                hose->pci_prefetch = hose->regions + i;
 100                        break;
 101                }
 102        }
 103
 104
 105        if (hose->pci_mem)
 106                pciauto_show_region("Memory", hose->pci_mem);
 107        if (hose->pci_prefetch)
 108                pciauto_show_region("Prefetchable Mem", hose->pci_prefetch);
 109        if (hose->pci_io)
 110                pciauto_show_region("I/O", hose->pci_io);
 111}
 112