blob: ef102646ba9abbd4e650b79e8ded6e5137ff6bd6 [file] [log] [blame]
Saeed Bishara651c74c2008-06-22 22:45:06 +02001/*
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>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090013#include <linux/slab.h>
Andrew Lunn27e53cf2012-03-08 21:45:59 +010014#include <linux/clk.h>
Rob Herringcc22b4c2011-06-28 21:22:40 -050015#include <video/vga.h>
Nicolas Pitre6e5c11a2009-01-07 04:47:02 +010016#include <asm/irq.h>
Saeed Bishara651c74c2008-06-22 22:45:06 +020017#include <asm/mach/pci.h>
Lennert Buytenhek6f088f12008-08-09 13:44:58 +020018#include <plat/pcie.h>
Rabeeh Khourye8b2b7b2009-03-22 17:30:32 +020019#include <mach/bridge-regs.h>
Andrew Lunn45173d52011-12-07 21:48:06 +010020#include <plat/addr-map.h>
Saeed Bishara651c74c2008-06-22 22:45:06 +020021#include "common.h"
22
Andrew Lunn27e53cf2012-03-08 21:45:59 +010023static void kirkwood_enable_pcie_clk(const char *port)
24{
25 struct clk *clk;
26
27 clk = clk_get_sys("pcie", port);
28 if (IS_ERR(clk)) {
Andrew Lunn98adf932012-10-20 13:23:16 +020029 pr_err("PCIE clock %s missing\n", port);
Andrew Lunn27e53cf2012-03-08 21:45:59 +010030 return;
31 }
32 clk_prepare_enable(clk);
33 clk_put(clk);
34}
35
36/* This function is called very early in the boot when probing the
37 hardware to determine what we actually are, and what rate tclk is
38 ticking at. Hence calling kirkwood_enable_pcie_clk() is not
39 possible since the clk tree has not been created yet. */
Eric Cooper0e0cdd32011-02-02 17:16:10 -050040void kirkwood_enable_pcie(void)
41{
42 u32 curr = readl(CLOCK_GATING_CTRL);
43 if (!(curr & CGC_PEX0))
44 writel(curr | CGC_PEX0, CLOCK_GATING_CTRL);
45}
46
Andrew Lunn98d99862012-04-11 21:07:45 +020047void kirkwood_pcie_id(u32 *dev, u32 *rev)
Ronen Shitritb2b3dc22008-09-15 10:40:35 +030048{
Eric Cooper0e0cdd32011-02-02 17:16:10 -050049 kirkwood_enable_pcie();
Thomas Petazzoni060f3d12012-09-11 14:27:19 +020050 *dev = orion_pcie_dev_id(PCIE_VIRT_BASE);
51 *rev = orion_pcie_rev(PCIE_VIRT_BASE);
Ronen Shitritb2b3dc22008-09-15 10:40:35 +030052}
53
Saeed Bisharaffd58bd2010-06-08 14:21:34 +030054struct pcie_port {
55 u8 root_bus_nr;
56 void __iomem *base;
57 spinlock_t conf_lock;
58 int irq;
Rob Herring2bb08082012-07-09 22:43:33 -050059 struct resource res;
Saeed Bisharaffd58bd2010-06-08 14:21:34 +030060};
61
62static int pcie_port_map[2];
63static int num_pcie_ports;
64
Saeed Bisharaffd58bd2010-06-08 14:21:34 +030065static int pcie_valid_config(struct pcie_port *pp, int bus, int dev)
Saeed Bishara651c74c2008-06-22 22:45:06 +020066{
67 /*
68 * Don't go out when trying to access --
69 * 1. nonexisting device on local bus
70 * 2. where there's no device connected (no link)
71 */
Saeed Bisharaffd58bd2010-06-08 14:21:34 +030072 if (bus == pp->root_bus_nr && dev == 0)
Saeed Bishara651c74c2008-06-22 22:45:06 +020073 return 1;
74
Saeed Bisharaffd58bd2010-06-08 14:21:34 +030075 if (!orion_pcie_link_up(pp->base))
Saeed Bishara651c74c2008-06-22 22:45:06 +020076 return 0;
77
Saeed Bisharaffd58bd2010-06-08 14:21:34 +030078 if (bus == pp->root_bus_nr && dev != 1)
Saeed Bishara651c74c2008-06-22 22:45:06 +020079 return 0;
80
81 return 1;
82}
83
84
85/*
86 * PCIe config cycles are done by programming the PCIE_CONF_ADDR register
87 * and then reading the PCIE_CONF_DATA register. Need to make sure these
88 * transactions are atomic.
89 */
Saeed Bishara651c74c2008-06-22 22:45:06 +020090
91static int pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where,
92 int size, u32 *val)
93{
Russell King43ba9902012-03-10 13:31:34 +000094 struct pci_sys_data *sys = bus->sysdata;
95 struct pcie_port *pp = sys->private_data;
Saeed Bishara651c74c2008-06-22 22:45:06 +020096 unsigned long flags;
97 int ret;
98
Saeed Bisharaffd58bd2010-06-08 14:21:34 +030099 if (pcie_valid_config(pp, bus->number, PCI_SLOT(devfn)) == 0) {
Saeed Bishara651c74c2008-06-22 22:45:06 +0200100 *val = 0xffffffff;
101 return PCIBIOS_DEVICE_NOT_FOUND;
102 }
103
Saeed Bisharaffd58bd2010-06-08 14:21:34 +0300104 spin_lock_irqsave(&pp->conf_lock, flags);
105 ret = orion_pcie_rd_conf(pp->base, bus, devfn, where, size, val);
106 spin_unlock_irqrestore(&pp->conf_lock, flags);
Saeed Bishara651c74c2008-06-22 22:45:06 +0200107
108 return ret;
109}
110
111static int pcie_wr_conf(struct pci_bus *bus, u32 devfn,
112 int where, int size, u32 val)
113{
Russell King43ba9902012-03-10 13:31:34 +0000114 struct pci_sys_data *sys = bus->sysdata;
115 struct pcie_port *pp = sys->private_data;
Saeed Bishara651c74c2008-06-22 22:45:06 +0200116 unsigned long flags;
117 int ret;
118
Saeed Bisharaffd58bd2010-06-08 14:21:34 +0300119 if (pcie_valid_config(pp, bus->number, PCI_SLOT(devfn)) == 0)
Saeed Bishara651c74c2008-06-22 22:45:06 +0200120 return PCIBIOS_DEVICE_NOT_FOUND;
121
Saeed Bisharaffd58bd2010-06-08 14:21:34 +0300122 spin_lock_irqsave(&pp->conf_lock, flags);
123 ret = orion_pcie_wr_conf(pp->base, bus, devfn, where, size, val);
124 spin_unlock_irqrestore(&pp->conf_lock, flags);
Saeed Bishara651c74c2008-06-22 22:45:06 +0200125
126 return ret;
127}
128
129static struct pci_ops pcie_ops = {
130 .read = pcie_rd_conf,
131 .write = pcie_wr_conf,
132};
133
Nicolas Pitrea87182b2010-07-05 13:59:56 -0400134static void __init pcie0_ioresources_init(struct pcie_port *pp)
Saeed Bishara651c74c2008-06-22 22:45:06 +0200135{
Thomas Petazzoni060f3d12012-09-11 14:27:19 +0200136 pp->base = PCIE_VIRT_BASE;
Nicolas Pitrea87182b2010-07-05 13:59:56 -0400137 pp->irq = IRQ_KIRKWOOD_PCIE;
Saeed Bishara651c74c2008-06-22 22:45:06 +0200138
139 /*
Saeed Bishara651c74c2008-06-22 22:45:06 +0200140 * IORESOURCE_MEM
141 */
Rob Herring2bb08082012-07-09 22:43:33 -0500142 pp->res.name = "PCIe 0 MEM";
143 pp->res.start = KIRKWOOD_PCIE_MEM_PHYS_BASE;
144 pp->res.end = pp->res.start + KIRKWOOD_PCIE_MEM_SIZE - 1;
145 pp->res.flags = IORESOURCE_MEM;
Saeed Bisharaffd58bd2010-06-08 14:21:34 +0300146}
147
Nicolas Pitrea87182b2010-07-05 13:59:56 -0400148static void __init pcie1_ioresources_init(struct pcie_port *pp)
Saeed Bisharaffd58bd2010-06-08 14:21:34 +0300149{
Thomas Petazzoni060f3d12012-09-11 14:27:19 +0200150 pp->base = PCIE1_VIRT_BASE;
Nicolas Pitrea87182b2010-07-05 13:59:56 -0400151 pp->irq = IRQ_KIRKWOOD_PCIE1;
Saeed Bisharaffd58bd2010-06-08 14:21:34 +0300152
153 /*
Saeed Bisharaffd58bd2010-06-08 14:21:34 +0300154 * IORESOURCE_MEM
155 */
Rob Herring2bb08082012-07-09 22:43:33 -0500156 pp->res.name = "PCIe 1 MEM";
157 pp->res.start = KIRKWOOD_PCIE1_MEM_PHYS_BASE;
158 pp->res.end = pp->res.start + KIRKWOOD_PCIE1_MEM_SIZE - 1;
159 pp->res.flags = IORESOURCE_MEM;
Saeed Bisharaffd58bd2010-06-08 14:21:34 +0300160}
161
162static int __init kirkwood_pcie_setup(int nr, struct pci_sys_data *sys)
163{
Saeed Bisharaffd58bd2010-06-08 14:21:34 +0300164 struct pcie_port *pp;
165 int index;
166
167 if (nr >= num_pcie_ports)
168 return 0;
169
170 index = pcie_port_map[nr];
Andrew Lunn98adf932012-10-20 13:23:16 +0200171 pr_info("PCI: bus%d uses PCIe port %d\n", sys->busnr, index);
Saeed Bisharaffd58bd2010-06-08 14:21:34 +0300172
173 pp = kzalloc(sizeof(*pp), GFP_KERNEL);
174 if (!pp)
175 panic("PCIe: failed to allocate pcie_port data");
176 sys->private_data = pp;
177 pp->root_bus_nr = sys->busnr;
178 spin_lock_init(&pp->conf_lock);
179
180 switch (index) {
181 case 0:
Andrew Lunn27e53cf2012-03-08 21:45:59 +0100182 kirkwood_enable_pcie_clk("0");
Nicolas Pitrea87182b2010-07-05 13:59:56 -0400183 pcie0_ioresources_init(pp);
Rob Herring2bb08082012-07-09 22:43:33 -0500184 pci_ioremap_io(SZ_64K * sys->busnr, KIRKWOOD_PCIE_IO_PHYS_BASE);
Saeed Bisharaffd58bd2010-06-08 14:21:34 +0300185 break;
186 case 1:
Andrew Lunn27e53cf2012-03-08 21:45:59 +0100187 kirkwood_enable_pcie_clk("1");
Nicolas Pitrea87182b2010-07-05 13:59:56 -0400188 pcie1_ioresources_init(pp);
Andrew Lunn98adf932012-10-20 13:23:16 +0200189 pci_ioremap_io(SZ_64K * sys->busnr,
190 KIRKWOOD_PCIE1_IO_PHYS_BASE);
Saeed Bisharaffd58bd2010-06-08 14:21:34 +0300191 break;
192 default:
Nicolas Pitrea87182b2010-07-05 13:59:56 -0400193 panic("PCIe setup: invalid controller %d", index);
Saeed Bisharaffd58bd2010-06-08 14:21:34 +0300194 }
195
Rob Herring2bb08082012-07-09 22:43:33 -0500196 if (request_resource(&iomem_resource, &pp->res))
Nicolas Pitrea87182b2010-07-05 13:59:56 -0400197 panic("Request PCIe%d Memory resource failed\n", index);
198
Rob Herring2bb08082012-07-09 22:43:33 -0500199 pci_add_resource_offset(&sys->resources, &pp->res, sys->mem_offset);
Nicolas Pitrea87182b2010-07-05 13:59:56 -0400200
Saeed Bisharaffd58bd2010-06-08 14:21:34 +0300201 /*
202 * Generic PCIe unit setup.
203 */
204 orion_pcie_set_local_bus_nr(pp->base, sys->busnr);
205
Andrew Lunn63a93322011-12-07 21:48:07 +0100206 orion_pcie_setup(pp->base);
Rabeeh Khourye8b2b7b2009-03-22 17:30:32 +0200207
Saeed Bishara651c74c2008-06-22 22:45:06 +0200208 return 1;
209}
210
Jason Gunthorpe1dc831b2012-11-21 00:19:06 -0700211/*
212 * The root complex has a hardwired class of PCI_CLASS_MEMORY_OTHER, when it
213 * is operating as a root complex this needs to be switched to
214 * PCI_CLASS_BRIDGE_HOST or Linux will errantly try to process the BAR's on
215 * the device. Decoding setup is handled by the orion code.
216 */
Saeed Bishara651c74c2008-06-22 22:45:06 +0200217static void __devinit rc_pci_fixup(struct pci_dev *dev)
218{
Saeed Bishara651c74c2008-06-22 22:45:06 +0200219 if (dev->bus->parent == NULL && dev->devfn == 0) {
220 int i;
221
Jason Gunthorpe1dc831b2012-11-21 00:19:06 -0700222 dev->class &= 0xff;
223 dev->class |= PCI_CLASS_BRIDGE_HOST << 8;
Saeed Bishara651c74c2008-06-22 22:45:06 +0200224 for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
225 dev->resource[i].start = 0;
226 dev->resource[i].end = 0;
227 dev->resource[i].flags = 0;
228 }
229 }
230}
231DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL, PCI_ANY_ID, rc_pci_fixup);
232
Ralf Baechled5341942011-06-10 15:30:21 +0100233static int __init kirkwood_pcie_map_irq(const struct pci_dev *dev, u8 slot,
234 u8 pin)
Saeed Bishara651c74c2008-06-22 22:45:06 +0200235{
Russell King43ba9902012-03-10 13:31:34 +0000236 struct pci_sys_data *sys = dev->sysdata;
237 struct pcie_port *pp = sys->private_data;
Saeed Bisharaffd58bd2010-06-08 14:21:34 +0300238
239 return pp->irq;
Saeed Bishara651c74c2008-06-22 22:45:06 +0200240}
241
242static struct hw_pci kirkwood_pci __initdata = {
Saeed Bishara651c74c2008-06-22 22:45:06 +0200243 .setup = kirkwood_pcie_setup,
Saeed Bishara651c74c2008-06-22 22:45:06 +0200244 .map_irq = kirkwood_pcie_map_irq,
Jason Gunthorpe4a9329a2012-11-21 00:15:11 -0700245 .ops = &pcie_ops,
Saeed Bishara651c74c2008-06-22 22:45:06 +0200246};
247
Thomas Petazzoni060f3d12012-09-11 14:27:19 +0200248static void __init add_pcie_port(int index, void __iomem *base)
Saeed Bishara651c74c2008-06-22 22:45:06 +0200249{
Andrew Lunn98adf932012-10-20 13:23:16 +0200250 pr_info("Kirkwood PCIe port %d: ", index);
Saeed Bisharaffd58bd2010-06-08 14:21:34 +0300251
Thomas Petazzoni060f3d12012-09-11 14:27:19 +0200252 if (orion_pcie_link_up(base)) {
Andrew Lunn98adf932012-10-20 13:23:16 +0200253 pr_info("link up\n");
Saeed Bisharaffd58bd2010-06-08 14:21:34 +0300254 pcie_port_map[num_pcie_ports++] = index;
255 } else
Andrew Lunn98adf932012-10-20 13:23:16 +0200256 pr_info("link down, ignoring\n");
Saeed Bisharaffd58bd2010-06-08 14:21:34 +0300257}
258
259void __init kirkwood_pcie_init(unsigned int portmask)
260{
Rob Herringcc22b4c2011-06-28 21:22:40 -0500261 vga_base = KIRKWOOD_PCIE_MEM_PHYS_BASE;
262
Saeed Bisharaffd58bd2010-06-08 14:21:34 +0300263 if (portmask & KW_PCIE0)
264 add_pcie_port(0, PCIE_VIRT_BASE);
265
266 if (portmask & KW_PCIE1)
267 add_pcie_port(1, PCIE1_VIRT_BASE);
268
269 kirkwood_pci.nr_controllers = num_pcie_ports;
Saeed Bishara651c74c2008-06-22 22:45:06 +0200270 pci_common_init(&kirkwood_pci);
271}