1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * arch/arm/mach-dove/pcie.c
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * PCIe functions for Marvell Dove 88AP510 SoC
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun * This file is licensed under the terms of the GNU General Public
7*4882a593Smuzhiyun * License version 2. This program is licensed "as is" without any
8*4882a593Smuzhiyun * warranty of any kind, whether express or implied.
9*4882a593Smuzhiyun */
10*4882a593Smuzhiyun
11*4882a593Smuzhiyun #include <linux/kernel.h>
12*4882a593Smuzhiyun #include <linux/pci.h>
13*4882a593Smuzhiyun #include <linux/clk.h>
14*4882a593Smuzhiyun #include <video/vga.h>
15*4882a593Smuzhiyun #include <asm/mach/pci.h>
16*4882a593Smuzhiyun #include <asm/mach/arch.h>
17*4882a593Smuzhiyun #include <asm/setup.h>
18*4882a593Smuzhiyun #include <asm/delay.h>
19*4882a593Smuzhiyun #include <plat/pcie.h>
20*4882a593Smuzhiyun #include <plat/addr-map.h>
21*4882a593Smuzhiyun #include "irqs.h"
22*4882a593Smuzhiyun #include "bridge-regs.h"
23*4882a593Smuzhiyun #include "common.h"
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun struct pcie_port {
26*4882a593Smuzhiyun u8 index;
27*4882a593Smuzhiyun u8 root_bus_nr;
28*4882a593Smuzhiyun void __iomem *base;
29*4882a593Smuzhiyun spinlock_t conf_lock;
30*4882a593Smuzhiyun char mem_space_name[16];
31*4882a593Smuzhiyun struct resource res;
32*4882a593Smuzhiyun };
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun static struct pcie_port pcie_port[2];
35*4882a593Smuzhiyun static int num_pcie_ports;
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun
dove_pcie_setup(int nr,struct pci_sys_data * sys)38*4882a593Smuzhiyun static int __init dove_pcie_setup(int nr, struct pci_sys_data *sys)
39*4882a593Smuzhiyun {
40*4882a593Smuzhiyun struct pcie_port *pp;
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun if (nr >= num_pcie_ports)
43*4882a593Smuzhiyun return 0;
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun pp = &pcie_port[nr];
46*4882a593Smuzhiyun sys->private_data = pp;
47*4882a593Smuzhiyun pp->root_bus_nr = sys->busnr;
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun /*
50*4882a593Smuzhiyun * Generic PCIe unit setup.
51*4882a593Smuzhiyun */
52*4882a593Smuzhiyun orion_pcie_set_local_bus_nr(pp->base, sys->busnr);
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun orion_pcie_setup(pp->base);
55*4882a593Smuzhiyun
56*4882a593Smuzhiyun if (pp->index == 0)
57*4882a593Smuzhiyun pci_ioremap_io(sys->busnr * SZ_64K, DOVE_PCIE0_IO_PHYS_BASE);
58*4882a593Smuzhiyun else
59*4882a593Smuzhiyun pci_ioremap_io(sys->busnr * SZ_64K, DOVE_PCIE1_IO_PHYS_BASE);
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun /*
62*4882a593Smuzhiyun * IORESOURCE_MEM
63*4882a593Smuzhiyun */
64*4882a593Smuzhiyun snprintf(pp->mem_space_name, sizeof(pp->mem_space_name),
65*4882a593Smuzhiyun "PCIe %d MEM", pp->index);
66*4882a593Smuzhiyun pp->mem_space_name[sizeof(pp->mem_space_name) - 1] = 0;
67*4882a593Smuzhiyun pp->res.name = pp->mem_space_name;
68*4882a593Smuzhiyun if (pp->index == 0) {
69*4882a593Smuzhiyun pp->res.start = DOVE_PCIE0_MEM_PHYS_BASE;
70*4882a593Smuzhiyun pp->res.end = pp->res.start + DOVE_PCIE0_MEM_SIZE - 1;
71*4882a593Smuzhiyun } else {
72*4882a593Smuzhiyun pp->res.start = DOVE_PCIE1_MEM_PHYS_BASE;
73*4882a593Smuzhiyun pp->res.end = pp->res.start + DOVE_PCIE1_MEM_SIZE - 1;
74*4882a593Smuzhiyun }
75*4882a593Smuzhiyun pp->res.flags = IORESOURCE_MEM;
76*4882a593Smuzhiyun if (request_resource(&iomem_resource, &pp->res))
77*4882a593Smuzhiyun panic("Request PCIe Memory resource failed\n");
78*4882a593Smuzhiyun pci_add_resource_offset(&sys->resources, &pp->res, sys->mem_offset);
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun return 1;
81*4882a593Smuzhiyun }
82*4882a593Smuzhiyun
pcie_valid_config(struct pcie_port * pp,int bus,int dev)83*4882a593Smuzhiyun static int pcie_valid_config(struct pcie_port *pp, int bus, int dev)
84*4882a593Smuzhiyun {
85*4882a593Smuzhiyun /*
86*4882a593Smuzhiyun * Don't go out when trying to access nonexisting devices
87*4882a593Smuzhiyun * on the local bus.
88*4882a593Smuzhiyun */
89*4882a593Smuzhiyun if (bus == pp->root_bus_nr && dev > 1)
90*4882a593Smuzhiyun return 0;
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun return 1;
93*4882a593Smuzhiyun }
94*4882a593Smuzhiyun
pcie_rd_conf(struct pci_bus * bus,u32 devfn,int where,int size,u32 * val)95*4882a593Smuzhiyun static int pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where,
96*4882a593Smuzhiyun int size, u32 *val)
97*4882a593Smuzhiyun {
98*4882a593Smuzhiyun struct pci_sys_data *sys = bus->sysdata;
99*4882a593Smuzhiyun struct pcie_port *pp = sys->private_data;
100*4882a593Smuzhiyun unsigned long flags;
101*4882a593Smuzhiyun int ret;
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun if (pcie_valid_config(pp, bus->number, PCI_SLOT(devfn)) == 0) {
104*4882a593Smuzhiyun *val = 0xffffffff;
105*4882a593Smuzhiyun return PCIBIOS_DEVICE_NOT_FOUND;
106*4882a593Smuzhiyun }
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun spin_lock_irqsave(&pp->conf_lock, flags);
109*4882a593Smuzhiyun ret = orion_pcie_rd_conf(pp->base, bus, devfn, where, size, val);
110*4882a593Smuzhiyun spin_unlock_irqrestore(&pp->conf_lock, flags);
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun return ret;
113*4882a593Smuzhiyun }
114*4882a593Smuzhiyun
pcie_wr_conf(struct pci_bus * bus,u32 devfn,int where,int size,u32 val)115*4882a593Smuzhiyun static int pcie_wr_conf(struct pci_bus *bus, u32 devfn,
116*4882a593Smuzhiyun int where, int size, u32 val)
117*4882a593Smuzhiyun {
118*4882a593Smuzhiyun struct pci_sys_data *sys = bus->sysdata;
119*4882a593Smuzhiyun struct pcie_port *pp = sys->private_data;
120*4882a593Smuzhiyun unsigned long flags;
121*4882a593Smuzhiyun int ret;
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun if (pcie_valid_config(pp, bus->number, PCI_SLOT(devfn)) == 0)
124*4882a593Smuzhiyun return PCIBIOS_DEVICE_NOT_FOUND;
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun spin_lock_irqsave(&pp->conf_lock, flags);
127*4882a593Smuzhiyun ret = orion_pcie_wr_conf(pp->base, bus, devfn, where, size, val);
128*4882a593Smuzhiyun spin_unlock_irqrestore(&pp->conf_lock, flags);
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun return ret;
131*4882a593Smuzhiyun }
132*4882a593Smuzhiyun
133*4882a593Smuzhiyun static struct pci_ops pcie_ops = {
134*4882a593Smuzhiyun .read = pcie_rd_conf,
135*4882a593Smuzhiyun .write = pcie_wr_conf,
136*4882a593Smuzhiyun };
137*4882a593Smuzhiyun
rc_pci_fixup(struct pci_dev * dev)138*4882a593Smuzhiyun static void rc_pci_fixup(struct pci_dev *dev)
139*4882a593Smuzhiyun {
140*4882a593Smuzhiyun /*
141*4882a593Smuzhiyun * Prevent enumeration of root complex.
142*4882a593Smuzhiyun */
143*4882a593Smuzhiyun if (dev->bus->parent == NULL && dev->devfn == 0) {
144*4882a593Smuzhiyun int i;
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
147*4882a593Smuzhiyun dev->resource[i].start = 0;
148*4882a593Smuzhiyun dev->resource[i].end = 0;
149*4882a593Smuzhiyun dev->resource[i].flags = 0;
150*4882a593Smuzhiyun }
151*4882a593Smuzhiyun }
152*4882a593Smuzhiyun }
153*4882a593Smuzhiyun DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL, PCI_ANY_ID, rc_pci_fixup);
154*4882a593Smuzhiyun
155*4882a593Smuzhiyun static int __init
dove_pcie_scan_bus(int nr,struct pci_host_bridge * bridge)156*4882a593Smuzhiyun dove_pcie_scan_bus(int nr, struct pci_host_bridge *bridge)
157*4882a593Smuzhiyun {
158*4882a593Smuzhiyun struct pci_sys_data *sys = pci_host_bridge_priv(bridge);
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun if (nr >= num_pcie_ports) {
161*4882a593Smuzhiyun BUG();
162*4882a593Smuzhiyun return -EINVAL;
163*4882a593Smuzhiyun }
164*4882a593Smuzhiyun
165*4882a593Smuzhiyun list_splice_init(&sys->resources, &bridge->windows);
166*4882a593Smuzhiyun bridge->dev.parent = NULL;
167*4882a593Smuzhiyun bridge->sysdata = sys;
168*4882a593Smuzhiyun bridge->busnr = sys->busnr;
169*4882a593Smuzhiyun bridge->ops = &pcie_ops;
170*4882a593Smuzhiyun
171*4882a593Smuzhiyun return pci_scan_root_bus_bridge(bridge);
172*4882a593Smuzhiyun }
173*4882a593Smuzhiyun
dove_pcie_map_irq(const struct pci_dev * dev,u8 slot,u8 pin)174*4882a593Smuzhiyun static int __init dove_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
175*4882a593Smuzhiyun {
176*4882a593Smuzhiyun struct pci_sys_data *sys = dev->sysdata;
177*4882a593Smuzhiyun struct pcie_port *pp = sys->private_data;
178*4882a593Smuzhiyun
179*4882a593Smuzhiyun return pp->index ? IRQ_DOVE_PCIE1 : IRQ_DOVE_PCIE0;
180*4882a593Smuzhiyun }
181*4882a593Smuzhiyun
182*4882a593Smuzhiyun static struct hw_pci dove_pci __initdata = {
183*4882a593Smuzhiyun .nr_controllers = 2,
184*4882a593Smuzhiyun .setup = dove_pcie_setup,
185*4882a593Smuzhiyun .scan = dove_pcie_scan_bus,
186*4882a593Smuzhiyun .map_irq = dove_pcie_map_irq,
187*4882a593Smuzhiyun };
188*4882a593Smuzhiyun
add_pcie_port(int index,void __iomem * base)189*4882a593Smuzhiyun static void __init add_pcie_port(int index, void __iomem *base)
190*4882a593Smuzhiyun {
191*4882a593Smuzhiyun printk(KERN_INFO "Dove PCIe port %d: ", index);
192*4882a593Smuzhiyun
193*4882a593Smuzhiyun if (orion_pcie_link_up(base)) {
194*4882a593Smuzhiyun struct pcie_port *pp = &pcie_port[num_pcie_ports++];
195*4882a593Smuzhiyun struct clk *clk = clk_get_sys("pcie", (index ? "1" : "0"));
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun if (!IS_ERR(clk))
198*4882a593Smuzhiyun clk_prepare_enable(clk);
199*4882a593Smuzhiyun
200*4882a593Smuzhiyun printk(KERN_INFO "link up\n");
201*4882a593Smuzhiyun
202*4882a593Smuzhiyun pp->index = index;
203*4882a593Smuzhiyun pp->root_bus_nr = -1;
204*4882a593Smuzhiyun pp->base = base;
205*4882a593Smuzhiyun spin_lock_init(&pp->conf_lock);
206*4882a593Smuzhiyun memset(&pp->res, 0, sizeof(pp->res));
207*4882a593Smuzhiyun } else {
208*4882a593Smuzhiyun printk(KERN_INFO "link down, ignoring\n");
209*4882a593Smuzhiyun }
210*4882a593Smuzhiyun }
211*4882a593Smuzhiyun
dove_pcie_init(int init_port0,int init_port1)212*4882a593Smuzhiyun void __init dove_pcie_init(int init_port0, int init_port1)
213*4882a593Smuzhiyun {
214*4882a593Smuzhiyun vga_base = DOVE_PCIE0_MEM_PHYS_BASE;
215*4882a593Smuzhiyun
216*4882a593Smuzhiyun if (init_port0)
217*4882a593Smuzhiyun add_pcie_port(0, DOVE_PCIE0_VIRT_BASE);
218*4882a593Smuzhiyun
219*4882a593Smuzhiyun if (init_port1)
220*4882a593Smuzhiyun add_pcie_port(1, DOVE_PCIE1_VIRT_BASE);
221*4882a593Smuzhiyun
222*4882a593Smuzhiyun pci_common_init(&dove_pci);
223*4882a593Smuzhiyun }
224