xref: /OK3568_Linux_fs/kernel/arch/arm/mach-dove/pcie.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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