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/clk.h>
15 #include <video/vga.h>
17 #include <asm/mach/pci.h>
18 #include <plat/pcie.h>
19 #include <mach/bridge-regs.h>
22 static void kirkwood_enable_pcie_clk(const char *port
)
26 clk
= clk_get_sys("pcie", port
);
28 pr_err("PCIE clock %s missing\n", port
);
31 clk_prepare_enable(clk
);
35 /* This function is called very early in the boot when probing the
36 hardware to determine what we actually are, and what rate tclk is
37 ticking at. Hence calling kirkwood_enable_pcie_clk() is not
38 possible since the clk tree has not been created yet. */
39 void kirkwood_enable_pcie(void)
41 u32 curr
= readl(CLOCK_GATING_CTRL
);
42 if (!(curr
& CGC_PEX0
))
43 writel(curr
| CGC_PEX0
, CLOCK_GATING_CTRL
);
46 void kirkwood_pcie_id(u32
*dev
, u32
*rev
)
48 kirkwood_enable_pcie();
49 *dev
= orion_pcie_dev_id(PCIE_VIRT_BASE
);
50 *rev
= orion_pcie_rev(PCIE_VIRT_BASE
);
61 static int pcie_port_map
[2];
62 static int num_pcie_ports
;
64 static int pcie_valid_config(struct pcie_port
*pp
, int bus
, int dev
)
67 * Don't go out when trying to access --
68 * 1. nonexisting device on local bus
69 * 2. where there's no device connected (no link)
71 if (bus
== pp
->root_bus_nr
&& dev
== 0)
74 if (!orion_pcie_link_up(pp
->base
))
77 if (bus
== pp
->root_bus_nr
&& dev
!= 1)
85 * PCIe config cycles are done by programming the PCIE_CONF_ADDR register
86 * and then reading the PCIE_CONF_DATA register. Need to make sure these
87 * transactions are atomic.
90 static int pcie_rd_conf(struct pci_bus
*bus
, u32 devfn
, int where
,
93 struct pci_sys_data
*sys
= bus
->sysdata
;
94 struct pcie_port
*pp
= sys
->private_data
;
98 if (pcie_valid_config(pp
, bus
->number
, PCI_SLOT(devfn
)) == 0) {
100 return PCIBIOS_DEVICE_NOT_FOUND
;
103 spin_lock_irqsave(&pp
->conf_lock
, flags
);
104 ret
= orion_pcie_rd_conf(pp
->base
, bus
, devfn
, where
, size
, val
);
105 spin_unlock_irqrestore(&pp
->conf_lock
, flags
);
110 static int pcie_wr_conf(struct pci_bus
*bus
, u32 devfn
,
111 int where
, int size
, u32 val
)
113 struct pci_sys_data
*sys
= bus
->sysdata
;
114 struct pcie_port
*pp
= sys
->private_data
;
118 if (pcie_valid_config(pp
, bus
->number
, PCI_SLOT(devfn
)) == 0)
119 return PCIBIOS_DEVICE_NOT_FOUND
;
121 spin_lock_irqsave(&pp
->conf_lock
, flags
);
122 ret
= orion_pcie_wr_conf(pp
->base
, bus
, devfn
, where
, size
, val
);
123 spin_unlock_irqrestore(&pp
->conf_lock
, flags
);
128 static struct pci_ops pcie_ops
= {
129 .read
= pcie_rd_conf
,
130 .write
= pcie_wr_conf
,
133 static void __init
pcie0_ioresources_init(struct pcie_port
*pp
)
135 pp
->base
= PCIE_VIRT_BASE
;
136 pp
->irq
= IRQ_KIRKWOOD_PCIE
;
141 pp
->res
.name
= "PCIe 0 MEM";
142 pp
->res
.start
= KIRKWOOD_PCIE_MEM_PHYS_BASE
;
143 pp
->res
.end
= pp
->res
.start
+ KIRKWOOD_PCIE_MEM_SIZE
- 1;
144 pp
->res
.flags
= IORESOURCE_MEM
;
147 static void __init
pcie1_ioresources_init(struct pcie_port
*pp
)
149 pp
->base
= PCIE1_VIRT_BASE
;
150 pp
->irq
= IRQ_KIRKWOOD_PCIE1
;
155 pp
->res
.name
= "PCIe 1 MEM";
156 pp
->res
.start
= KIRKWOOD_PCIE1_MEM_PHYS_BASE
;
157 pp
->res
.end
= pp
->res
.start
+ KIRKWOOD_PCIE1_MEM_SIZE
- 1;
158 pp
->res
.flags
= IORESOURCE_MEM
;
161 static int __init
kirkwood_pcie_setup(int nr
, struct pci_sys_data
*sys
)
163 struct pcie_port
*pp
;
166 if (nr
>= num_pcie_ports
)
169 index
= pcie_port_map
[nr
];
170 pr_info("PCI: bus%d uses PCIe port %d\n", sys
->busnr
, index
);
172 pp
= kzalloc(sizeof(*pp
), GFP_KERNEL
);
174 panic("PCIe: failed to allocate pcie_port data");
175 sys
->private_data
= pp
;
176 pp
->root_bus_nr
= sys
->busnr
;
177 spin_lock_init(&pp
->conf_lock
);
181 kirkwood_enable_pcie_clk("0");
182 pcie0_ioresources_init(pp
);
183 pci_ioremap_io(SZ_64K
* sys
->busnr
, KIRKWOOD_PCIE_IO_PHYS_BASE
);
186 kirkwood_enable_pcie_clk("1");
187 pcie1_ioresources_init(pp
);
188 pci_ioremap_io(SZ_64K
* sys
->busnr
,
189 KIRKWOOD_PCIE1_IO_PHYS_BASE
);
192 panic("PCIe setup: invalid controller %d", index
);
195 if (request_resource(&iomem_resource
, &pp
->res
))
196 panic("Request PCIe%d Memory resource failed\n", index
);
198 pci_add_resource_offset(&sys
->resources
, &pp
->res
, sys
->mem_offset
);
201 * Generic PCIe unit setup.
203 orion_pcie_set_local_bus_nr(pp
->base
, sys
->busnr
);
205 orion_pcie_setup(pp
->base
);
211 * The root complex has a hardwired class of PCI_CLASS_MEMORY_OTHER, when it
212 * is operating as a root complex this needs to be switched to
213 * PCI_CLASS_BRIDGE_HOST or Linux will errantly try to process the BAR's on
214 * the device. Decoding setup is handled by the orion code.
216 static void rc_pci_fixup(struct pci_dev
*dev
)
218 if (dev
->bus
->parent
== NULL
&& dev
->devfn
== 0) {
222 dev
->class |= PCI_CLASS_BRIDGE_HOST
<< 8;
223 for (i
= 0; i
< DEVICE_COUNT_RESOURCE
; i
++) {
224 dev
->resource
[i
].start
= 0;
225 dev
->resource
[i
].end
= 0;
226 dev
->resource
[i
].flags
= 0;
230 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL
, PCI_ANY_ID
, rc_pci_fixup
);
232 static int __init
kirkwood_pcie_map_irq(const struct pci_dev
*dev
, u8 slot
,
235 struct pci_sys_data
*sys
= dev
->sysdata
;
236 struct pcie_port
*pp
= sys
->private_data
;
241 static struct hw_pci kirkwood_pci __initdata
= {
242 .setup
= kirkwood_pcie_setup
,
243 .map_irq
= kirkwood_pcie_map_irq
,
247 static void __init
add_pcie_port(int index
, void __iomem
*base
)
249 pcie_port_map
[num_pcie_ports
++] = index
;
250 pr_info("Kirkwood PCIe port %d: link %s\n", index
,
251 orion_pcie_link_up(base
) ? "up" : "down");
254 void __init
kirkwood_pcie_init(unsigned int portmask
)
256 vga_base
= KIRKWOOD_PCIE_MEM_PHYS_BASE
;
258 if (portmask
& KW_PCIE0
)
259 add_pcie_port(0, PCIE_VIRT_BASE
);
261 if (portmask
& KW_PCIE1
)
262 add_pcie_port(1, PCIE1_VIRT_BASE
);
264 kirkwood_pci
.nr_controllers
= num_pcie_ports
;
265 pci_common_init(&kirkwood_pci
);