root/arch/microblaze/pci/indirect_pci.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. indirect_read_config
  2. indirect_write_config
  3. setup_indirect_pci

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * Support for indirect PCI bridges.
   4  *
   5  * Copyright (C) 1998 Gabriel Paubert.
   6  */
   7 
   8 #include <linux/kernel.h>
   9 #include <linux/pci.h>
  10 #include <linux/delay.h>
  11 #include <linux/string.h>
  12 #include <linux/init.h>
  13 
  14 #include <linux/io.h>
  15 #include <asm/pci-bridge.h>
  16 
  17 static int
  18 indirect_read_config(struct pci_bus *bus, unsigned int devfn, int offset,
  19                      int len, u32 *val)
  20 {
  21         struct pci_controller *hose = pci_bus_to_host(bus);
  22         volatile void __iomem *cfg_data;
  23         u8 cfg_type = 0;
  24         u32 bus_no, reg;
  25 
  26         if (hose->indirect_type & INDIRECT_TYPE_NO_PCIE_LINK) {
  27                 if (bus->number != hose->first_busno)
  28                         return PCIBIOS_DEVICE_NOT_FOUND;
  29                 if (devfn != 0)
  30                         return PCIBIOS_DEVICE_NOT_FOUND;
  31         }
  32 
  33         if (hose->indirect_type & INDIRECT_TYPE_SET_CFG_TYPE)
  34                 if (bus->number != hose->first_busno)
  35                         cfg_type = 1;
  36 
  37         bus_no = (bus->number == hose->first_busno) ?
  38                         hose->self_busno : bus->number;
  39 
  40         if (hose->indirect_type & INDIRECT_TYPE_EXT_REG)
  41                 reg = ((offset & 0xf00) << 16) | (offset & 0xfc);
  42         else
  43                 reg = offset & 0xfc; /* Only 3 bits for function */
  44 
  45         if (hose->indirect_type & INDIRECT_TYPE_BIG_ENDIAN)
  46                 out_be32(hose->cfg_addr, (0x80000000 | (bus_no << 16) |
  47                          (devfn << 8) | reg | cfg_type));
  48         else
  49                 out_le32(hose->cfg_addr, (0x80000000 | (bus_no << 16) |
  50                          (devfn << 8) | reg | cfg_type));
  51 
  52         /*
  53          * Note: the caller has already checked that offset is
  54          * suitably aligned and that len is 1, 2 or 4.
  55          */
  56         cfg_data = hose->cfg_data + (offset & 3); /* Only 3 bits for function */
  57         switch (len) {
  58         case 1:
  59                 *val = in_8(cfg_data);
  60                 break;
  61         case 2:
  62                 *val = in_le16(cfg_data);
  63                 break;
  64         default:
  65                 *val = in_le32(cfg_data);
  66                 break;
  67         }
  68         return PCIBIOS_SUCCESSFUL;
  69 }
  70 
  71 static int
  72 indirect_write_config(struct pci_bus *bus, unsigned int devfn, int offset,
  73                       int len, u32 val)
  74 {
  75         struct pci_controller *hose = pci_bus_to_host(bus);
  76         volatile void __iomem *cfg_data;
  77         u8 cfg_type = 0;
  78         u32 bus_no, reg;
  79 
  80         if (hose->indirect_type & INDIRECT_TYPE_NO_PCIE_LINK) {
  81                 if (bus->number != hose->first_busno)
  82                         return PCIBIOS_DEVICE_NOT_FOUND;
  83                 if (devfn != 0)
  84                         return PCIBIOS_DEVICE_NOT_FOUND;
  85         }
  86 
  87         if (hose->indirect_type & INDIRECT_TYPE_SET_CFG_TYPE)
  88                 if (bus->number != hose->first_busno)
  89                         cfg_type = 1;
  90 
  91         bus_no = (bus->number == hose->first_busno) ?
  92                         hose->self_busno : bus->number;
  93 
  94         if (hose->indirect_type & INDIRECT_TYPE_EXT_REG)
  95                 reg = ((offset & 0xf00) << 16) | (offset & 0xfc);
  96         else
  97                 reg = offset & 0xfc;
  98 
  99         if (hose->indirect_type & INDIRECT_TYPE_BIG_ENDIAN)
 100                 out_be32(hose->cfg_addr, (0x80000000 | (bus_no << 16) |
 101                          (devfn << 8) | reg | cfg_type));
 102         else
 103                 out_le32(hose->cfg_addr, (0x80000000 | (bus_no << 16) |
 104                          (devfn << 8) | reg | cfg_type));
 105 
 106         /* suppress setting of PCI_PRIMARY_BUS */
 107         if (hose->indirect_type & INDIRECT_TYPE_SURPRESS_PRIMARY_BUS)
 108                 if ((offset == PCI_PRIMARY_BUS) &&
 109                         (bus->number == hose->first_busno))
 110                         val &= 0xffffff00;
 111 
 112         /* Workaround for PCI_28 Errata in 440EPx/GRx */
 113         if ((hose->indirect_type & INDIRECT_TYPE_BROKEN_MRM) &&
 114                         offset == PCI_CACHE_LINE_SIZE) {
 115                 val = 0;
 116         }
 117 
 118         /*
 119          * Note: the caller has already checked that offset is
 120          * suitably aligned and that len is 1, 2 or 4.
 121          */
 122         cfg_data = hose->cfg_data + (offset & 3);
 123         switch (len) {
 124         case 1:
 125                 out_8(cfg_data, val);
 126                 break;
 127         case 2:
 128                 out_le16(cfg_data, val);
 129                 break;
 130         default:
 131                 out_le32(cfg_data, val);
 132                 break;
 133         }
 134 
 135         return PCIBIOS_SUCCESSFUL;
 136 }
 137 
 138 static struct pci_ops indirect_pci_ops = {
 139         .read = indirect_read_config,
 140         .write = indirect_write_config,
 141 };
 142 
 143 void __init
 144 setup_indirect_pci(struct pci_controller *hose,
 145                    resource_size_t cfg_addr,
 146                    resource_size_t cfg_data, u32 flags)
 147 {
 148         resource_size_t base = cfg_addr & PAGE_MASK;
 149         void __iomem *mbase;
 150 
 151         mbase = ioremap(base, PAGE_SIZE);
 152         hose->cfg_addr = mbase + (cfg_addr & ~PAGE_MASK);
 153         if ((cfg_data & PAGE_MASK) != base)
 154                 mbase = ioremap(cfg_data & PAGE_MASK, PAGE_SIZE);
 155         hose->cfg_data = mbase + (cfg_data & ~PAGE_MASK);
 156         hose->ops = &indirect_pci_ops;
 157         hose->indirect_type = flags;
 158 }

/* [<][>][^][v][top][bottom][index][help] */