~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/arm/mach-kirkwood/pcie.c

Version: ~ [ linux-5.13-rc2 ] ~ [ linux-5.12.4 ] ~ [ linux-5.11.21 ] ~ [ linux-5.10.37 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.119 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.190 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.232 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.268 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.268 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.18.140 ] ~ [ linux-3.16.85 ] ~ [ linux-3.14.79 ] ~ [ linux-3.12.74 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * arch/arm/mach-kirkwood/pcie.c
  3  *
  4  * PCIe functions for Marvell Kirkwood SoCs
  5  *
  6  * This file is licensed under the terms of the GNU General Public
  7  * License version 2.  This program is licensed "as is" without any
  8  * warranty of any kind, whether express or implied.
  9  */
 10 
 11 #include <linux/kernel.h>
 12 #include <linux/pci.h>
 13 #include <linux/slab.h>
 14 #include <linux/clk.h>
 15 #include <linux/mbus.h>
 16 #include <video/vga.h>
 17 #include <asm/irq.h>
 18 #include <asm/mach/pci.h>
 19 #include <plat/pcie.h>
 20 #include <mach/bridge-regs.h>
 21 #include "common.h"
 22 
 23 /* These can go away once Kirkwood uses the mvebu-mbus DT binding */
 24 #define KIRKWOOD_MBUS_PCIE0_MEM_TARGET    0x4
 25 #define KIRKWOOD_MBUS_PCIE0_MEM_ATTR      0xe8
 26 #define KIRKWOOD_MBUS_PCIE0_IO_TARGET     0x4
 27 #define KIRKWOOD_MBUS_PCIE0_IO_ATTR       0xe0
 28 #define KIRKWOOD_MBUS_PCIE1_MEM_TARGET    0x4
 29 #define KIRKWOOD_MBUS_PCIE1_MEM_ATTR      0xd8
 30 #define KIRKWOOD_MBUS_PCIE1_IO_TARGET     0x4
 31 #define KIRKWOOD_MBUS_PCIE1_IO_ATTR       0xd0
 32 
 33 static void kirkwood_enable_pcie_clk(const char *port)
 34 {
 35         struct clk *clk;
 36 
 37         clk = clk_get_sys("pcie", port);
 38         if (IS_ERR(clk)) {
 39                 pr_err("PCIE clock %s missing\n", port);
 40                 return;
 41         }
 42         clk_prepare_enable(clk);
 43         clk_put(clk);
 44 }
 45 
 46 /* This function is called very early in the boot when probing the
 47    hardware to determine what we actually are, and what rate tclk is
 48    ticking at. Hence calling kirkwood_enable_pcie_clk() is not
 49    possible since the clk tree has not been created yet. */
 50 void kirkwood_enable_pcie(void)
 51 {
 52         u32 curr = readl(CLOCK_GATING_CTRL);
 53         if (!(curr & CGC_PEX0))
 54                 writel(curr | CGC_PEX0, CLOCK_GATING_CTRL);
 55 }
 56 
 57 void kirkwood_pcie_id(u32 *dev, u32 *rev)
 58 {
 59         kirkwood_enable_pcie();
 60         *dev = orion_pcie_dev_id(PCIE_VIRT_BASE);
 61         *rev = orion_pcie_rev(PCIE_VIRT_BASE);
 62 }
 63 
 64 struct pcie_port {
 65         u8                      root_bus_nr;
 66         void __iomem            *base;
 67         spinlock_t              conf_lock;
 68         int                     irq;
 69         struct resource         res;
 70 };
 71 
 72 static int pcie_port_map[2];
 73 static int num_pcie_ports;
 74 
 75 static int pcie_valid_config(struct pcie_port *pp, int bus, int dev)
 76 {
 77         /*
 78          * Don't go out when trying to access --
 79          * 1. nonexisting device on local bus
 80          * 2. where there's no device connected (no link)
 81          */
 82         if (bus == pp->root_bus_nr && dev == 0)
 83                 return 1;
 84 
 85         if (!orion_pcie_link_up(pp->base))
 86                 return 0;
 87 
 88         if (bus == pp->root_bus_nr && dev != 1)
 89                 return 0;
 90 
 91         return 1;
 92 }
 93 
 94 
 95 /*
 96  * PCIe config cycles are done by programming the PCIE_CONF_ADDR register
 97  * and then reading the PCIE_CONF_DATA register. Need to make sure these
 98  * transactions are atomic.
 99  */
100 
101 static int pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where,
102                         int size, u32 *val)
103 {
104         struct pci_sys_data *sys = bus->sysdata;
105         struct pcie_port *pp = sys->private_data;
106         unsigned long flags;
107         int ret;
108 
109         if (pcie_valid_config(pp, bus->number, PCI_SLOT(devfn)) == 0) {
110                 *val = 0xffffffff;
111                 return PCIBIOS_DEVICE_NOT_FOUND;
112         }
113 
114         spin_lock_irqsave(&pp->conf_lock, flags);
115         ret = orion_pcie_rd_conf(pp->base, bus, devfn, where, size, val);
116         spin_unlock_irqrestore(&pp->conf_lock, flags);
117 
118         return ret;
119 }
120 
121 static int pcie_wr_conf(struct pci_bus *bus, u32 devfn,
122                         int where, int size, u32 val)
123 {
124         struct pci_sys_data *sys = bus->sysdata;
125         struct pcie_port *pp = sys->private_data;
126         unsigned long flags;
127         int ret;
128 
129         if (pcie_valid_config(pp, bus->number, PCI_SLOT(devfn)) == 0)
130                 return PCIBIOS_DEVICE_NOT_FOUND;
131 
132         spin_lock_irqsave(&pp->conf_lock, flags);
133         ret = orion_pcie_wr_conf(pp->base, bus, devfn, where, size, val);
134         spin_unlock_irqrestore(&pp->conf_lock, flags);
135 
136         return ret;
137 }
138 
139 static struct pci_ops pcie_ops = {
140         .read = pcie_rd_conf,
141         .write = pcie_wr_conf,
142 };
143 
144 static void __init pcie0_ioresources_init(struct pcie_port *pp)
145 {
146         pp->base = PCIE_VIRT_BASE;
147         pp->irq = IRQ_KIRKWOOD_PCIE;
148 
149         /*
150          * IORESOURCE_MEM
151          */
152         pp->res.name = "PCIe 0 MEM";
153         pp->res.start = KIRKWOOD_PCIE_MEM_PHYS_BASE;
154         pp->res.end = pp->res.start + KIRKWOOD_PCIE_MEM_SIZE - 1;
155         pp->res.flags = IORESOURCE_MEM;
156 }
157 
158 static void __init pcie1_ioresources_init(struct pcie_port *pp)
159 {
160         pp->base = PCIE1_VIRT_BASE;
161         pp->irq = IRQ_KIRKWOOD_PCIE1;
162 
163         /*
164          * IORESOURCE_MEM
165          */
166         pp->res.name = "PCIe 1 MEM";
167         pp->res.start = KIRKWOOD_PCIE1_MEM_PHYS_BASE;
168         pp->res.end = pp->res.start + KIRKWOOD_PCIE1_MEM_SIZE - 1;
169         pp->res.flags = IORESOURCE_MEM;
170 }
171 
172 static int __init kirkwood_pcie_setup(int nr, struct pci_sys_data *sys)
173 {
174         struct pcie_port *pp;
175         int index;
176 
177         if (nr >= num_pcie_ports)
178                 return 0;
179 
180         index = pcie_port_map[nr];
181         pr_info("PCI: bus%d uses PCIe port %d\n", sys->busnr, index);
182 
183         pp = kzalloc(sizeof(*pp), GFP_KERNEL);
184         if (!pp)
185                 panic("PCIe: failed to allocate pcie_port data");
186         sys->private_data = pp;
187         pp->root_bus_nr = sys->busnr;
188         spin_lock_init(&pp->conf_lock);
189 
190         switch (index) {
191         case 0:
192                 kirkwood_enable_pcie_clk("");
193                 pcie0_ioresources_init(pp);
194                 pci_ioremap_io(SZ_64K * sys->busnr, KIRKWOOD_PCIE_IO_PHYS_BASE);
195                 break;
196         case 1:
197                 kirkwood_enable_pcie_clk("1");
198                 pcie1_ioresources_init(pp);
199                 pci_ioremap_io(SZ_64K * sys->busnr,
200                                KIRKWOOD_PCIE1_IO_PHYS_BASE);
201                 break;
202         default:
203                 panic("PCIe setup: invalid controller %d", index);
204         }
205 
206         if (request_resource(&iomem_resource, &pp->res))
207                 panic("Request PCIe%d Memory resource failed\n", index);
208 
209         pci_add_resource_offset(&sys->resources, &pp->res, sys->mem_offset);
210 
211         /*
212          * Generic PCIe unit setup.
213          */
214         orion_pcie_set_local_bus_nr(pp->base, sys->busnr);
215 
216         orion_pcie_setup(pp->base);
217 
218         return 1;
219 }
220 
221 /*
222  * The root complex has a hardwired class of PCI_CLASS_MEMORY_OTHER, when it
223  * is operating as a root complex this needs to be switched to
224  * PCI_CLASS_BRIDGE_HOST or Linux will errantly try to process the BAR's on
225  * the device. Decoding setup is handled by the orion code.
226  */
227 static void rc_pci_fixup(struct pci_dev *dev)
228 {
229         if (dev->bus->parent == NULL && dev->devfn == 0) {
230                 int i;
231 
232                 dev->class &= 0xff;
233                 dev->class |= PCI_CLASS_BRIDGE_HOST << 8;
234                 for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
235                         dev->resource[i].start = 0;
236                         dev->resource[i].end   = 0;
237                         dev->resource[i].flags = 0;
238                 }
239         }
240 }
241 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL, PCI_ANY_ID, rc_pci_fixup);
242 
243 static int __init kirkwood_pcie_map_irq(const struct pci_dev *dev, u8 slot,
244         u8 pin)
245 {
246         struct pci_sys_data *sys = dev->sysdata;
247         struct pcie_port *pp = sys->private_data;
248 
249         return pp->irq;
250 }
251 
252 static struct hw_pci kirkwood_pci __initdata = {
253         .setup          = kirkwood_pcie_setup,
254         .map_irq        = kirkwood_pcie_map_irq,
255         .ops            = &pcie_ops,
256 };
257 
258 static void __init add_pcie_port(int index, void __iomem *base)
259 {
260         pcie_port_map[num_pcie_ports++] = index;
261         pr_info("Kirkwood PCIe port %d: link %s\n", index,
262                 orion_pcie_link_up(base) ? "up" : "down");
263 }
264 
265 void __init kirkwood_pcie_init(unsigned int portmask)
266 {
267         mvebu_mbus_add_window_remap_by_id(KIRKWOOD_MBUS_PCIE0_IO_TARGET,
268                                           KIRKWOOD_MBUS_PCIE0_IO_ATTR,
269                                           KIRKWOOD_PCIE_IO_PHYS_BASE,
270                                           KIRKWOOD_PCIE_IO_SIZE,
271                                           KIRKWOOD_PCIE_IO_BUS_BASE);
272         mvebu_mbus_add_window_by_id(KIRKWOOD_MBUS_PCIE0_MEM_TARGET,
273                                     KIRKWOOD_MBUS_PCIE0_MEM_ATTR,
274                                     KIRKWOOD_PCIE_MEM_PHYS_BASE,
275                                     KIRKWOOD_PCIE_MEM_SIZE);
276         mvebu_mbus_add_window_remap_by_id(KIRKWOOD_MBUS_PCIE1_IO_TARGET,
277                                           KIRKWOOD_MBUS_PCIE1_IO_ATTR,
278                                           KIRKWOOD_PCIE1_IO_PHYS_BASE,
279                                           KIRKWOOD_PCIE1_IO_SIZE,
280                                           KIRKWOOD_PCIE1_IO_BUS_BASE);
281         mvebu_mbus_add_window_by_id(KIRKWOOD_MBUS_PCIE1_MEM_TARGET,
282                                     KIRKWOOD_MBUS_PCIE1_MEM_ATTR,
283                                     KIRKWOOD_PCIE1_MEM_PHYS_BASE,
284                                     KIRKWOOD_PCIE1_MEM_SIZE);
285 
286         vga_base = KIRKWOOD_PCIE_MEM_PHYS_BASE;
287 
288         if (portmask & KW_PCIE0)
289                 add_pcie_port(0, PCIE_VIRT_BASE);
290 
291         if (portmask & KW_PCIE1)
292                 add_pcie_port(1, PCIE1_VIRT_BASE);
293 
294         kirkwood_pci.nr_controllers = num_pcie_ports;
295         pci_common_init(&kirkwood_pci);
296 }
297 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp