2 * arch/arm/mach-kirkwood/pcie.c
4 * PCIe functions for Marvell Kirkwood SoCs
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.
11 #include <linux/kernel.h>
12 #include <linux/pci.h>
13 #include <linux/slab.h>
14 #include <linux/mbus.h>
16 #include <asm/mach/pci.h>
17 #include <plat/pcie.h>
18 #include <mach/bridge-regs.h>
21 void __init
kirkwood_pcie_id(u32
*dev
, u32
*rev
)
23 *dev
= orion_pcie_dev_id((void __iomem
*)PCIE_VIRT_BASE
);
24 *rev
= orion_pcie_rev((void __iomem
*)PCIE_VIRT_BASE
);
32 struct resource res
[2];
35 static int pcie_port_map
[2];
36 static int num_pcie_ports
;
38 static inline struct pcie_port
*bus_to_port(struct pci_bus
*bus
)
40 struct pci_sys_data
*sys
= bus
->sysdata
;
41 return sys
->private_data
;
44 static int pcie_valid_config(struct pcie_port
*pp
, int bus
, int dev
)
47 * Don't go out when trying to access --
48 * 1. nonexisting device on local bus
49 * 2. where there's no device connected (no link)
51 if (bus
== pp
->root_bus_nr
&& dev
== 0)
54 if (!orion_pcie_link_up(pp
->base
))
57 if (bus
== pp
->root_bus_nr
&& dev
!= 1)
65 * PCIe config cycles are done by programming the PCIE_CONF_ADDR register
66 * and then reading the PCIE_CONF_DATA register. Need to make sure these
67 * transactions are atomic.
70 static int pcie_rd_conf(struct pci_bus
*bus
, u32 devfn
, int where
,
73 struct pcie_port
*pp
= bus_to_port(bus
);
77 if (pcie_valid_config(pp
, bus
->number
, PCI_SLOT(devfn
)) == 0) {
79 return PCIBIOS_DEVICE_NOT_FOUND
;
82 spin_lock_irqsave(&pp
->conf_lock
, flags
);
83 ret
= orion_pcie_rd_conf(pp
->base
, bus
, devfn
, where
, size
, val
);
84 spin_unlock_irqrestore(&pp
->conf_lock
, flags
);
89 static int pcie_wr_conf(struct pci_bus
*bus
, u32 devfn
,
90 int where
, int size
, u32 val
)
92 struct pcie_port
*pp
= bus_to_port(bus
);
96 if (pcie_valid_config(pp
, bus
->number
, PCI_SLOT(devfn
)) == 0)
97 return PCIBIOS_DEVICE_NOT_FOUND
;
99 spin_lock_irqsave(&pp
->conf_lock
, flags
);
100 ret
= orion_pcie_wr_conf(pp
->base
, bus
, devfn
, where
, size
, val
);
101 spin_unlock_irqrestore(&pp
->conf_lock
, flags
);
106 static struct pci_ops pcie_ops
= {
107 .read
= pcie_rd_conf
,
108 .write
= pcie_wr_conf
,
111 static void __init
pcie0_ioresources_init(struct pcie_port
*pp
)
113 pp
->base
= (void __iomem
*)PCIE_VIRT_BASE
;
114 pp
->irq
= IRQ_KIRKWOOD_PCIE
;
119 pp
->res
[0].name
= "PCIe 0 I/O Space";
120 pp
->res
[0].start
= KIRKWOOD_PCIE_IO_BUS_BASE
;
121 pp
->res
[0].end
= pp
->res
[0].start
+ KIRKWOOD_PCIE_IO_SIZE
- 1;
122 pp
->res
[0].flags
= IORESOURCE_IO
;
127 pp
->res
[1].name
= "PCIe 0 MEM";
128 pp
->res
[1].start
= KIRKWOOD_PCIE_MEM_PHYS_BASE
;
129 pp
->res
[1].end
= pp
->res
[1].start
+ KIRKWOOD_PCIE_MEM_SIZE
- 1;
130 pp
->res
[1].flags
= IORESOURCE_MEM
;
133 static void __init
pcie1_ioresources_init(struct pcie_port
*pp
)
135 pp
->base
= (void __iomem
*)PCIE1_VIRT_BASE
;
136 pp
->irq
= IRQ_KIRKWOOD_PCIE1
;
141 pp
->res
[0].name
= "PCIe 1 I/O Space";
142 pp
->res
[0].start
= KIRKWOOD_PCIE1_IO_BUS_BASE
;
143 pp
->res
[0].end
= pp
->res
[0].start
+ KIRKWOOD_PCIE1_IO_SIZE
- 1;
144 pp
->res
[0].flags
= IORESOURCE_IO
;
149 pp
->res
[1].name
= "PCIe 1 MEM";
150 pp
->res
[1].start
= KIRKWOOD_PCIE1_MEM_PHYS_BASE
;
151 pp
->res
[1].end
= pp
->res
[1].start
+ KIRKWOOD_PCIE1_MEM_SIZE
- 1;
152 pp
->res
[1].flags
= IORESOURCE_MEM
;
155 static int __init
kirkwood_pcie_setup(int nr
, struct pci_sys_data
*sys
)
157 extern unsigned int kirkwood_clk_ctrl
;
158 struct pcie_port
*pp
;
161 if (nr
>= num_pcie_ports
)
164 index
= pcie_port_map
[nr
];
165 printk(KERN_INFO
"PCI: bus%d uses PCIe port %d\n", sys
->busnr
, index
);
167 pp
= kzalloc(sizeof(*pp
), GFP_KERNEL
);
169 panic("PCIe: failed to allocate pcie_port data");
170 sys
->private_data
= pp
;
171 pp
->root_bus_nr
= sys
->busnr
;
172 spin_lock_init(&pp
->conf_lock
);
176 kirkwood_clk_ctrl
|= CGC_PEX0
;
177 pcie0_ioresources_init(pp
);
180 kirkwood_clk_ctrl
|= CGC_PEX1
;
181 pcie1_ioresources_init(pp
);
184 panic("PCIe setup: invalid controller %d", index
);
187 if (request_resource(&ioport_resource
, &pp
->res
[0]))
188 panic("Request PCIe%d IO resource failed\n", index
);
189 if (request_resource(&iomem_resource
, &pp
->res
[1]))
190 panic("Request PCIe%d Memory resource failed\n", index
);
192 sys
->resource
[0] = &pp
->res
[0];
193 sys
->resource
[1] = &pp
->res
[1];
194 sys
->resource
[2] = NULL
;
198 * Generic PCIe unit setup.
200 orion_pcie_set_local_bus_nr(pp
->base
, sys
->busnr
);
202 orion_pcie_setup(pp
->base
, &kirkwood_mbus_dram_info
);
207 static void __devinit
rc_pci_fixup(struct pci_dev
*dev
)
210 * Prevent enumeration of root complex.
212 if (dev
->bus
->parent
== NULL
&& dev
->devfn
== 0) {
215 for (i
= 0; i
< DEVICE_COUNT_RESOURCE
; i
++) {
216 dev
->resource
[i
].start
= 0;
217 dev
->resource
[i
].end
= 0;
218 dev
->resource
[i
].flags
= 0;
222 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL
, PCI_ANY_ID
, rc_pci_fixup
);
224 static struct pci_bus __init
*
225 kirkwood_pcie_scan_bus(int nr
, struct pci_sys_data
*sys
)
229 if (nr
< num_pcie_ports
) {
230 bus
= pci_scan_bus(sys
->busnr
, &pcie_ops
, sys
);
239 static int __init
kirkwood_pcie_map_irq(struct pci_dev
*dev
, u8 slot
, u8 pin
)
241 struct pcie_port
*pp
= bus_to_port(dev
->bus
);
246 static struct hw_pci kirkwood_pci __initdata
= {
247 .swizzle
= pci_std_swizzle
,
248 .setup
= kirkwood_pcie_setup
,
249 .scan
= kirkwood_pcie_scan_bus
,
250 .map_irq
= kirkwood_pcie_map_irq
,
253 static void __init
add_pcie_port(int index
, unsigned long base
)
255 printk(KERN_INFO
"Kirkwood PCIe port %d: ", index
);
257 if (orion_pcie_link_up((void __iomem
*)base
)) {
258 printk(KERN_INFO
"link up\n");
259 pcie_port_map
[num_pcie_ports
++] = index
;
261 printk(KERN_INFO
"link down, ignoring\n");
264 void __init
kirkwood_pcie_init(unsigned int portmask
)
266 if (portmask
& KW_PCIE0
)
267 add_pcie_port(0, PCIE_VIRT_BASE
);
269 if (portmask
& KW_PCIE1
)
270 add_pcie_port(1, PCIE1_VIRT_BASE
);
272 kirkwood_pci
.nr_controllers
= num_pcie_ports
;
273 pci_common_init(&kirkwood_pci
);