uboot/drivers/pci/pcie_ecam_generic.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Generic PCIE host provided by e.g. QEMU
   4 *
   5 * Heavily based on drivers/pci/pcie_xilinx.c
   6 *
   7 * Copyright (C) 2016 Imagination Technologies
   8 */
   9
  10#include <common.h>
  11#include <dm.h>
  12#include <pci.h>
  13#include <asm/global_data.h>
  14
  15#include <asm/io.h>
  16
  17/**
  18 * struct generic_ecam_pcie - generic_ecam PCIe controller state
  19 * @cfg_base: The base address of memory mapped configuration space
  20 */
  21struct generic_ecam_pcie {
  22        void *cfg_base;
  23        pci_size_t size;
  24        int first_busno;
  25};
  26
  27/**
  28 * pci_generic_ecam_conf_address() - Calculate the address of a config access
  29 * @bus: Pointer to the PCI bus
  30 * @bdf: Identifies the PCIe device to access
  31 * @offset: The offset into the device's configuration space
  32 * @paddress: Pointer to the pointer to write the calculates address to
  33 *
  34 * Calculates the address that should be accessed to perform a PCIe
  35 * configuration space access for a given device identified by the PCIe
  36 * controller device @pcie and the bus, device & function numbers in @bdf. If
  37 * access to the device is not valid then the function will return an error
  38 * code. Otherwise the address to access will be written to the pointer pointed
  39 * to by @paddress.
  40 */
  41static int pci_generic_ecam_conf_address(const struct udevice *bus,
  42                                         pci_dev_t bdf, uint offset,
  43                                         void **paddress)
  44{
  45        struct generic_ecam_pcie *pcie = dev_get_priv(bus);
  46        void *addr;
  47
  48        addr = pcie->cfg_base;
  49        addr += (PCI_BUS(bdf) - pcie->first_busno) << 20;
  50        addr += PCI_DEV(bdf) << 15;
  51        addr += PCI_FUNC(bdf) << 12;
  52        addr += offset;
  53        *paddress = addr;
  54
  55        return 0;
  56}
  57
  58static bool pci_generic_ecam_addr_valid(const struct udevice *bus,
  59                                        pci_dev_t bdf)
  60{
  61        struct generic_ecam_pcie *pcie = dev_get_priv(bus);
  62        int num_buses = DIV_ROUND_UP(pcie->size, 1 << 16);
  63
  64        return (PCI_BUS(bdf) >= pcie->first_busno &&
  65                PCI_BUS(bdf) < pcie->first_busno + num_buses);
  66}
  67
  68/**
  69 * pci_generic_ecam_read_config() - Read from configuration space
  70 * @bus: Pointer to the PCI bus
  71 * @bdf: Identifies the PCIe device to access
  72 * @offset: The offset into the device's configuration space
  73 * @valuep: A pointer at which to store the read value
  74 * @size: Indicates the size of access to perform
  75 *
  76 * Read a value of size @size from offset @offset within the configuration
  77 * space of the device identified by the bus, device & function numbers in @bdf
  78 * on the PCI bus @bus.
  79 */
  80static int pci_generic_ecam_read_config(const struct udevice *bus,
  81                                        pci_dev_t bdf, uint offset,
  82                                        ulong *valuep, enum pci_size_t size)
  83{
  84        if (!pci_generic_ecam_addr_valid(bus, bdf)) {
  85                *valuep = pci_get_ff(size);
  86                return 0;
  87        }
  88
  89        return pci_generic_mmap_read_config(bus, pci_generic_ecam_conf_address,
  90                                            bdf, offset, valuep, size);
  91}
  92
  93/**
  94 * pci_generic_ecam_write_config() - Write to configuration space
  95 * @bus: Pointer to the PCI bus
  96 * @bdf: Identifies the PCIe device to access
  97 * @offset: The offset into the device's configuration space
  98 * @value: The value to write
  99 * @size: Indicates the size of access to perform
 100 *
 101 * Write the value @value of size @size from offset @offset within the
 102 * configuration space of the device identified by the bus, device & function
 103 * numbers in @bdf on the PCI bus @bus.
 104 */
 105static int pci_generic_ecam_write_config(struct udevice *bus, pci_dev_t bdf,
 106                                    uint offset, ulong value,
 107                                    enum pci_size_t size)
 108{
 109        if (!pci_generic_ecam_addr_valid(bus, bdf))
 110                return 0;
 111
 112        return pci_generic_mmap_write_config(bus, pci_generic_ecam_conf_address,
 113                                             bdf, offset, value, size);
 114}
 115
 116/**
 117 * pci_generic_ecam_of_to_plat() - Translate from DT to device state
 118 * @dev: A pointer to the device being operated on
 119 *
 120 * Translate relevant data from the device tree pertaining to device @dev into
 121 * state that the driver will later make use of. This state is stored in the
 122 * device's private data structure.
 123 *
 124 * Return: 0 on success, else -EINVAL
 125 */
 126static int pci_generic_ecam_of_to_plat(struct udevice *dev)
 127{
 128        struct generic_ecam_pcie *pcie = dev_get_priv(dev);
 129        struct fdt_resource reg_res;
 130        DECLARE_GLOBAL_DATA_PTR;
 131        int err;
 132
 133        err = fdt_get_resource(gd->fdt_blob, dev_of_offset(dev), "reg",
 134                               0, &reg_res);
 135        if (err < 0) {
 136                pr_err("\"reg\" resource not found\n");
 137                return err;
 138        }
 139
 140        pcie->size = fdt_resource_size(&reg_res);
 141        pcie->cfg_base = map_physmem(reg_res.start, pcie->size, MAP_NOCACHE);
 142
 143        return 0;
 144}
 145
 146static int pci_generic_ecam_probe(struct udevice *dev)
 147{
 148        struct generic_ecam_pcie *pcie = dev_get_priv(dev);
 149
 150        pcie->first_busno = dev_seq(dev);
 151
 152        return 0;
 153}
 154
 155static const struct dm_pci_ops pci_generic_ecam_ops = {
 156        .read_config    = pci_generic_ecam_read_config,
 157        .write_config   = pci_generic_ecam_write_config,
 158};
 159
 160static const struct udevice_id pci_generic_ecam_ids[] = {
 161        { .compatible = "pci-host-ecam-generic" },
 162        { }
 163};
 164
 165U_BOOT_DRIVER(pci_generic_ecam) = {
 166        .name                   = "pci_generic_ecam",
 167        .id                     = UCLASS_PCI,
 168        .of_match               = pci_generic_ecam_ids,
 169        .ops                    = &pci_generic_ecam_ops,
 170        .probe                  = pci_generic_ecam_probe,
 171        .of_to_plat     = pci_generic_ecam_of_to_plat,
 172        .priv_auto      = sizeof(struct generic_ecam_pcie),
 173};
 174