1bfa9a2ebSMichael Ellerman /*
2bfa9a2ebSMichael Ellerman * PCI / PCI-X / PCI-Express support for 4xx parts
3bfa9a2ebSMichael Ellerman *
4bfa9a2ebSMichael Ellerman * Copyright 2007 Ben. Herrenschmidt <benh@kernel.crashing.org>, IBM Corp.
5bfa9a2ebSMichael Ellerman *
6bfa9a2ebSMichael Ellerman * Most PCI Express code is coming from Stefan Roese implementation for
7bfa9a2ebSMichael Ellerman * arch/ppc in the Denx tree, slightly reworked by me.
8bfa9a2ebSMichael Ellerman *
9bfa9a2ebSMichael Ellerman * Copyright 2007 DENX Software Engineering, Stefan Roese <sr@denx.de>
10bfa9a2ebSMichael Ellerman *
11bfa9a2ebSMichael Ellerman * Some of that comes itself from a previous implementation for 440SPE only
12bfa9a2ebSMichael Ellerman * by Roland Dreier:
13bfa9a2ebSMichael Ellerman *
14bfa9a2ebSMichael Ellerman * Copyright (c) 2005 Cisco Systems. All rights reserved.
15bfa9a2ebSMichael Ellerman * Roland Dreier <rolandd@cisco.com>
16bfa9a2ebSMichael Ellerman *
17bfa9a2ebSMichael Ellerman */
18bfa9a2ebSMichael Ellerman
19bfa9a2ebSMichael Ellerman #undef DEBUG
20bfa9a2ebSMichael Ellerman
21bfa9a2ebSMichael Ellerman #include <linux/kernel.h>
22bfa9a2ebSMichael Ellerman #include <linux/pci.h>
23bfa9a2ebSMichael Ellerman #include <linux/init.h>
24bfa9a2ebSMichael Ellerman #include <linux/of.h>
25e6f6390aSChristophe Leroy #include <linux/of_address.h>
26bfa9a2ebSMichael Ellerman #include <linux/delay.h>
27bfa9a2ebSMichael Ellerman #include <linux/slab.h>
28bfa9a2ebSMichael Ellerman
29bfa9a2ebSMichael Ellerman #include <asm/io.h>
30bfa9a2ebSMichael Ellerman #include <asm/pci-bridge.h>
31bfa9a2ebSMichael Ellerman #include <asm/machdep.h>
32bfa9a2ebSMichael Ellerman #include <asm/dcr.h>
33bfa9a2ebSMichael Ellerman #include <asm/dcr-regs.h>
34bfa9a2ebSMichael Ellerman #include <mm/mmu_decl.h>
35bfa9a2ebSMichael Ellerman
36bfa9a2ebSMichael Ellerman #include "pci.h"
37bfa9a2ebSMichael Ellerman
38bfa9a2ebSMichael Ellerman static int dma_offset_set;
39bfa9a2ebSMichael Ellerman
40bfa9a2ebSMichael Ellerman #define U64_TO_U32_LOW(val) ((u32)((val) & 0x00000000ffffffffULL))
41bfa9a2ebSMichael Ellerman #define U64_TO_U32_HIGH(val) ((u32)((val) >> 32))
42bfa9a2ebSMichael Ellerman
43bfa9a2ebSMichael Ellerman #define RES_TO_U32_LOW(val) \
44bfa9a2ebSMichael Ellerman ((sizeof(resource_size_t) > sizeof(u32)) ? U64_TO_U32_LOW(val) : (val))
45bfa9a2ebSMichael Ellerman #define RES_TO_U32_HIGH(val) \
46bfa9a2ebSMichael Ellerman ((sizeof(resource_size_t) > sizeof(u32)) ? U64_TO_U32_HIGH(val) : (0))
47bfa9a2ebSMichael Ellerman
ppc440spe_revA(void)48bfa9a2ebSMichael Ellerman static inline int ppc440spe_revA(void)
49bfa9a2ebSMichael Ellerman {
50bfa9a2ebSMichael Ellerman /* Catch both 440SPe variants, with and without RAID6 support */
51bfa9a2ebSMichael Ellerman if ((mfspr(SPRN_PVR) & 0xffefffff) == 0x53421890)
52bfa9a2ebSMichael Ellerman return 1;
53bfa9a2ebSMichael Ellerman else
54bfa9a2ebSMichael Ellerman return 0;
55bfa9a2ebSMichael Ellerman }
56bfa9a2ebSMichael Ellerman
fixup_ppc4xx_pci_bridge(struct pci_dev * dev)57bfa9a2ebSMichael Ellerman static void fixup_ppc4xx_pci_bridge(struct pci_dev *dev)
58bfa9a2ebSMichael Ellerman {
59bfa9a2ebSMichael Ellerman struct pci_controller *hose;
60*09cc9006SMika Westerberg struct resource *r;
61bfa9a2ebSMichael Ellerman
62bfa9a2ebSMichael Ellerman if (dev->devfn != 0 || dev->bus->self != NULL)
63bfa9a2ebSMichael Ellerman return;
64bfa9a2ebSMichael Ellerman
65bfa9a2ebSMichael Ellerman hose = pci_bus_to_host(dev->bus);
66bfa9a2ebSMichael Ellerman if (hose == NULL)
67bfa9a2ebSMichael Ellerman return;
68bfa9a2ebSMichael Ellerman
69bfa9a2ebSMichael Ellerman if (!of_device_is_compatible(hose->dn, "ibm,plb-pciex") &&
70bfa9a2ebSMichael Ellerman !of_device_is_compatible(hose->dn, "ibm,plb-pcix") &&
71bfa9a2ebSMichael Ellerman !of_device_is_compatible(hose->dn, "ibm,plb-pci"))
72bfa9a2ebSMichael Ellerman return;
73bfa9a2ebSMichael Ellerman
74bfa9a2ebSMichael Ellerman if (of_device_is_compatible(hose->dn, "ibm,plb440epx-pci") ||
75bfa9a2ebSMichael Ellerman of_device_is_compatible(hose->dn, "ibm,plb440grx-pci")) {
76bfa9a2ebSMichael Ellerman hose->indirect_type |= PPC_INDIRECT_TYPE_BROKEN_MRM;
77bfa9a2ebSMichael Ellerman }
78bfa9a2ebSMichael Ellerman
79bfa9a2ebSMichael Ellerman /* Hide the PCI host BARs from the kernel as their content doesn't
80bfa9a2ebSMichael Ellerman * fit well in the resource management
81bfa9a2ebSMichael Ellerman */
82*09cc9006SMika Westerberg pci_dev_for_each_resource(dev, r) {
83*09cc9006SMika Westerberg r->start = r->end = 0;
84*09cc9006SMika Westerberg r->flags = 0;
85bfa9a2ebSMichael Ellerman }
86bfa9a2ebSMichael Ellerman
87bfa9a2ebSMichael Ellerman printk(KERN_INFO "PCI: Hiding 4xx host bridge resources %s\n",
88bfa9a2ebSMichael Ellerman pci_name(dev));
89bfa9a2ebSMichael Ellerman }
90bfa9a2ebSMichael Ellerman DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, fixup_ppc4xx_pci_bridge);
91bfa9a2ebSMichael Ellerman
ppc4xx_parse_dma_ranges(struct pci_controller * hose,void __iomem * reg,struct resource * res)92bfa9a2ebSMichael Ellerman static int __init ppc4xx_parse_dma_ranges(struct pci_controller *hose,
93bfa9a2ebSMichael Ellerman void __iomem *reg,
94bfa9a2ebSMichael Ellerman struct resource *res)
95bfa9a2ebSMichael Ellerman {
96bfa9a2ebSMichael Ellerman u64 size;
97bfa9a2ebSMichael Ellerman const u32 *ranges;
98bfa9a2ebSMichael Ellerman int rlen;
99bfa9a2ebSMichael Ellerman int pna = of_n_addr_cells(hose->dn);
100bfa9a2ebSMichael Ellerman int np = pna + 5;
101bfa9a2ebSMichael Ellerman
102bfa9a2ebSMichael Ellerman /* Default */
103bfa9a2ebSMichael Ellerman res->start = 0;
104bfa9a2ebSMichael Ellerman size = 0x80000000;
105bfa9a2ebSMichael Ellerman res->end = size - 1;
106bfa9a2ebSMichael Ellerman res->flags = IORESOURCE_MEM | IORESOURCE_PREFETCH;
107bfa9a2ebSMichael Ellerman
108bfa9a2ebSMichael Ellerman /* Get dma-ranges property */
109bfa9a2ebSMichael Ellerman ranges = of_get_property(hose->dn, "dma-ranges", &rlen);
110bfa9a2ebSMichael Ellerman if (ranges == NULL)
111bfa9a2ebSMichael Ellerman goto out;
112bfa9a2ebSMichael Ellerman
113bfa9a2ebSMichael Ellerman /* Walk it */
114bfa9a2ebSMichael Ellerman while ((rlen -= np * 4) >= 0) {
115bfa9a2ebSMichael Ellerman u32 pci_space = ranges[0];
116bfa9a2ebSMichael Ellerman u64 pci_addr = of_read_number(ranges + 1, 2);
117bfa9a2ebSMichael Ellerman u64 cpu_addr = of_translate_dma_address(hose->dn, ranges + 3);
118bfa9a2ebSMichael Ellerman size = of_read_number(ranges + pna + 3, 2);
119bfa9a2ebSMichael Ellerman ranges += np;
120bfa9a2ebSMichael Ellerman if (cpu_addr == OF_BAD_ADDR || size == 0)
121bfa9a2ebSMichael Ellerman continue;
122bfa9a2ebSMichael Ellerman
123bfa9a2ebSMichael Ellerman /* We only care about memory */
124bfa9a2ebSMichael Ellerman if ((pci_space & 0x03000000) != 0x02000000)
125bfa9a2ebSMichael Ellerman continue;
126bfa9a2ebSMichael Ellerman
127bfa9a2ebSMichael Ellerman /* We currently only support memory at 0, and pci_addr
128bfa9a2ebSMichael Ellerman * within 32 bits space
129bfa9a2ebSMichael Ellerman */
130bfa9a2ebSMichael Ellerman if (cpu_addr != 0 || pci_addr > 0xffffffff) {
131b7c670d6SRob Herring printk(KERN_WARNING "%pOF: Ignored unsupported dma range"
132bfa9a2ebSMichael Ellerman " 0x%016llx...0x%016llx -> 0x%016llx\n",
133b7c670d6SRob Herring hose->dn,
134bfa9a2ebSMichael Ellerman pci_addr, pci_addr + size - 1, cpu_addr);
135bfa9a2ebSMichael Ellerman continue;
136bfa9a2ebSMichael Ellerman }
137bfa9a2ebSMichael Ellerman
138bfa9a2ebSMichael Ellerman /* Check if not prefetchable */
139bfa9a2ebSMichael Ellerman if (!(pci_space & 0x40000000))
140bfa9a2ebSMichael Ellerman res->flags &= ~IORESOURCE_PREFETCH;
141bfa9a2ebSMichael Ellerman
142bfa9a2ebSMichael Ellerman
143bfa9a2ebSMichael Ellerman /* Use that */
144bfa9a2ebSMichael Ellerman res->start = pci_addr;
145bfa9a2ebSMichael Ellerman /* Beware of 32 bits resources */
146bfa9a2ebSMichael Ellerman if (sizeof(resource_size_t) == sizeof(u32) &&
147bfa9a2ebSMichael Ellerman (pci_addr + size) > 0x100000000ull)
148bfa9a2ebSMichael Ellerman res->end = 0xffffffff;
149bfa9a2ebSMichael Ellerman else
150bfa9a2ebSMichael Ellerman res->end = res->start + size - 1;
151bfa9a2ebSMichael Ellerman break;
152bfa9a2ebSMichael Ellerman }
153bfa9a2ebSMichael Ellerman
154bfa9a2ebSMichael Ellerman /* We only support one global DMA offset */
155bfa9a2ebSMichael Ellerman if (dma_offset_set && pci_dram_offset != res->start) {
156b7c670d6SRob Herring printk(KERN_ERR "%pOF: dma-ranges(s) mismatch\n", hose->dn);
157bfa9a2ebSMichael Ellerman return -ENXIO;
158bfa9a2ebSMichael Ellerman }
159bfa9a2ebSMichael Ellerman
160bfa9a2ebSMichael Ellerman /* Check that we can fit all of memory as we don't support
161bfa9a2ebSMichael Ellerman * DMA bounce buffers
162bfa9a2ebSMichael Ellerman */
163bfa9a2ebSMichael Ellerman if (size < total_memory) {
164b7c670d6SRob Herring printk(KERN_ERR "%pOF: dma-ranges too small "
165bfa9a2ebSMichael Ellerman "(size=%llx total_memory=%llx)\n",
166b7c670d6SRob Herring hose->dn, size, (u64)total_memory);
167bfa9a2ebSMichael Ellerman return -ENXIO;
168bfa9a2ebSMichael Ellerman }
169bfa9a2ebSMichael Ellerman
170bfa9a2ebSMichael Ellerman /* Check we are a power of 2 size and that base is a multiple of size*/
171bfa9a2ebSMichael Ellerman if ((size & (size - 1)) != 0 ||
172bfa9a2ebSMichael Ellerman (res->start & (size - 1)) != 0) {
173b7c670d6SRob Herring printk(KERN_ERR "%pOF: dma-ranges unaligned\n", hose->dn);
174bfa9a2ebSMichael Ellerman return -ENXIO;
175bfa9a2ebSMichael Ellerman }
176bfa9a2ebSMichael Ellerman
177bfa9a2ebSMichael Ellerman /* Check that we are fully contained within 32 bits space if we are not
178bfa9a2ebSMichael Ellerman * running on a 460sx or 476fpe which have 64 bit bus addresses.
179bfa9a2ebSMichael Ellerman */
180bfa9a2ebSMichael Ellerman if (res->end > 0xffffffff &&
181bfa9a2ebSMichael Ellerman !(of_device_is_compatible(hose->dn, "ibm,plb-pciex-460sx")
182bfa9a2ebSMichael Ellerman || of_device_is_compatible(hose->dn, "ibm,plb-pciex-476fpe"))) {
183b7c670d6SRob Herring printk(KERN_ERR "%pOF: dma-ranges outside of 32 bits space\n",
184b7c670d6SRob Herring hose->dn);
185bfa9a2ebSMichael Ellerman return -ENXIO;
186bfa9a2ebSMichael Ellerman }
187bfa9a2ebSMichael Ellerman out:
188bfa9a2ebSMichael Ellerman dma_offset_set = 1;
189bfa9a2ebSMichael Ellerman pci_dram_offset = res->start;
190bfa9a2ebSMichael Ellerman hose->dma_window_base_cur = res->start;
191bfa9a2ebSMichael Ellerman hose->dma_window_size = resource_size(res);
192bfa9a2ebSMichael Ellerman
193bfa9a2ebSMichael Ellerman printk(KERN_INFO "4xx PCI DMA offset set to 0x%08lx\n",
194bfa9a2ebSMichael Ellerman pci_dram_offset);
195bfa9a2ebSMichael Ellerman printk(KERN_INFO "4xx PCI DMA window base to 0x%016llx\n",
196bfa9a2ebSMichael Ellerman (unsigned long long)hose->dma_window_base_cur);
197bfa9a2ebSMichael Ellerman printk(KERN_INFO "DMA window size 0x%016llx\n",
198bfa9a2ebSMichael Ellerman (unsigned long long)hose->dma_window_size);
199bfa9a2ebSMichael Ellerman return 0;
200bfa9a2ebSMichael Ellerman }
201bfa9a2ebSMichael Ellerman
202bfa9a2ebSMichael Ellerman /*
203bfa9a2ebSMichael Ellerman * 4xx PCI 2.x part
204bfa9a2ebSMichael Ellerman */
205bfa9a2ebSMichael Ellerman
ppc4xx_setup_one_pci_PMM(struct pci_controller * hose,void __iomem * reg,u64 plb_addr,u64 pci_addr,u64 size,unsigned int flags,int index)206bfa9a2ebSMichael Ellerman static int __init ppc4xx_setup_one_pci_PMM(struct pci_controller *hose,
207bfa9a2ebSMichael Ellerman void __iomem *reg,
208bfa9a2ebSMichael Ellerman u64 plb_addr,
209bfa9a2ebSMichael Ellerman u64 pci_addr,
210bfa9a2ebSMichael Ellerman u64 size,
211bfa9a2ebSMichael Ellerman unsigned int flags,
212bfa9a2ebSMichael Ellerman int index)
213bfa9a2ebSMichael Ellerman {
214bfa9a2ebSMichael Ellerman u32 ma, pcila, pciha;
215bfa9a2ebSMichael Ellerman
216bfa9a2ebSMichael Ellerman /* Hack warning ! The "old" PCI 2.x cell only let us configure the low
217bfa9a2ebSMichael Ellerman * 32-bit of incoming PLB addresses. The top 4 bits of the 36-bit
218bfa9a2ebSMichael Ellerman * address are actually hard wired to a value that appears to depend
219bfa9a2ebSMichael Ellerman * on the specific SoC. For example, it's 0 on 440EP and 1 on 440EPx.
220bfa9a2ebSMichael Ellerman *
221bfa9a2ebSMichael Ellerman * The trick here is we just crop those top bits and ignore them when
222bfa9a2ebSMichael Ellerman * programming the chip. That means the device-tree has to be right
223bfa9a2ebSMichael Ellerman * for the specific part used (we don't print a warning if it's wrong
224bfa9a2ebSMichael Ellerman * but on the other hand, you'll crash quickly enough), but at least
225bfa9a2ebSMichael Ellerman * this code should work whatever the hard coded value is
226bfa9a2ebSMichael Ellerman */
227bfa9a2ebSMichael Ellerman plb_addr &= 0xffffffffull;
228bfa9a2ebSMichael Ellerman
229bfa9a2ebSMichael Ellerman /* Note: Due to the above hack, the test below doesn't actually test
230bfa9a2ebSMichael Ellerman * if you address is above 4G, but it tests that address and
231bfa9a2ebSMichael Ellerman * (address + size) are both contained in the same 4G
232bfa9a2ebSMichael Ellerman */
233bfa9a2ebSMichael Ellerman if ((plb_addr + size) > 0xffffffffull || !is_power_of_2(size) ||
234bfa9a2ebSMichael Ellerman size < 0x1000 || (plb_addr & (size - 1)) != 0) {
235b7c670d6SRob Herring printk(KERN_WARNING "%pOF: Resource out of range\n", hose->dn);
236bfa9a2ebSMichael Ellerman return -1;
237bfa9a2ebSMichael Ellerman }
238bfa9a2ebSMichael Ellerman ma = (0xffffffffu << ilog2(size)) | 1;
239bfa9a2ebSMichael Ellerman if (flags & IORESOURCE_PREFETCH)
240bfa9a2ebSMichael Ellerman ma |= 2;
241bfa9a2ebSMichael Ellerman
242bfa9a2ebSMichael Ellerman pciha = RES_TO_U32_HIGH(pci_addr);
243bfa9a2ebSMichael Ellerman pcila = RES_TO_U32_LOW(pci_addr);
244bfa9a2ebSMichael Ellerman
245bfa9a2ebSMichael Ellerman writel(plb_addr, reg + PCIL0_PMM0LA + (0x10 * index));
246bfa9a2ebSMichael Ellerman writel(pcila, reg + PCIL0_PMM0PCILA + (0x10 * index));
247bfa9a2ebSMichael Ellerman writel(pciha, reg + PCIL0_PMM0PCIHA + (0x10 * index));
248bfa9a2ebSMichael Ellerman writel(ma, reg + PCIL0_PMM0MA + (0x10 * index));
249bfa9a2ebSMichael Ellerman
250bfa9a2ebSMichael Ellerman return 0;
251bfa9a2ebSMichael Ellerman }
252bfa9a2ebSMichael Ellerman
ppc4xx_configure_pci_PMMs(struct pci_controller * hose,void __iomem * reg)253bfa9a2ebSMichael Ellerman static void __init ppc4xx_configure_pci_PMMs(struct pci_controller *hose,
254bfa9a2ebSMichael Ellerman void __iomem *reg)
255bfa9a2ebSMichael Ellerman {
256bfa9a2ebSMichael Ellerman int i, j, found_isa_hole = 0;
257bfa9a2ebSMichael Ellerman
258bfa9a2ebSMichael Ellerman /* Setup outbound memory windows */
259bfa9a2ebSMichael Ellerman for (i = j = 0; i < 3; i++) {
260bfa9a2ebSMichael Ellerman struct resource *res = &hose->mem_resources[i];
261bfa9a2ebSMichael Ellerman resource_size_t offset = hose->mem_offset[i];
262bfa9a2ebSMichael Ellerman
263bfa9a2ebSMichael Ellerman /* we only care about memory windows */
264bfa9a2ebSMichael Ellerman if (!(res->flags & IORESOURCE_MEM))
265bfa9a2ebSMichael Ellerman continue;
266bfa9a2ebSMichael Ellerman if (j > 2) {
267b7c670d6SRob Herring printk(KERN_WARNING "%pOF: Too many ranges\n", hose->dn);
268bfa9a2ebSMichael Ellerman break;
269bfa9a2ebSMichael Ellerman }
270bfa9a2ebSMichael Ellerman
271bfa9a2ebSMichael Ellerman /* Configure the resource */
272bfa9a2ebSMichael Ellerman if (ppc4xx_setup_one_pci_PMM(hose, reg,
273bfa9a2ebSMichael Ellerman res->start,
274bfa9a2ebSMichael Ellerman res->start - offset,
275bfa9a2ebSMichael Ellerman resource_size(res),
276bfa9a2ebSMichael Ellerman res->flags,
277bfa9a2ebSMichael Ellerman j) == 0) {
278bfa9a2ebSMichael Ellerman j++;
279bfa9a2ebSMichael Ellerman
280bfa9a2ebSMichael Ellerman /* If the resource PCI address is 0 then we have our
281bfa9a2ebSMichael Ellerman * ISA memory hole
282bfa9a2ebSMichael Ellerman */
283bfa9a2ebSMichael Ellerman if (res->start == offset)
284bfa9a2ebSMichael Ellerman found_isa_hole = 1;
285bfa9a2ebSMichael Ellerman }
286bfa9a2ebSMichael Ellerman }
287bfa9a2ebSMichael Ellerman
288bfa9a2ebSMichael Ellerman /* Handle ISA memory hole if not already covered */
289bfa9a2ebSMichael Ellerman if (j <= 2 && !found_isa_hole && hose->isa_mem_size)
290bfa9a2ebSMichael Ellerman if (ppc4xx_setup_one_pci_PMM(hose, reg, hose->isa_mem_phys, 0,
291bfa9a2ebSMichael Ellerman hose->isa_mem_size, 0, j) == 0)
292b7c670d6SRob Herring printk(KERN_INFO "%pOF: Legacy ISA memory support enabled\n",
293b7c670d6SRob Herring hose->dn);
294bfa9a2ebSMichael Ellerman }
295bfa9a2ebSMichael Ellerman
ppc4xx_configure_pci_PTMs(struct pci_controller * hose,void __iomem * reg,const struct resource * res)296bfa9a2ebSMichael Ellerman static void __init ppc4xx_configure_pci_PTMs(struct pci_controller *hose,
297bfa9a2ebSMichael Ellerman void __iomem *reg,
298bfa9a2ebSMichael Ellerman const struct resource *res)
299bfa9a2ebSMichael Ellerman {
300bfa9a2ebSMichael Ellerman resource_size_t size = resource_size(res);
301bfa9a2ebSMichael Ellerman u32 sa;
302bfa9a2ebSMichael Ellerman
303bfa9a2ebSMichael Ellerman /* Calculate window size */
304bfa9a2ebSMichael Ellerman sa = (0xffffffffu << ilog2(size)) | 1;
305bfa9a2ebSMichael Ellerman sa |= 0x1;
306bfa9a2ebSMichael Ellerman
307bfa9a2ebSMichael Ellerman /* RAM is always at 0 local for now */
308bfa9a2ebSMichael Ellerman writel(0, reg + PCIL0_PTM1LA);
309bfa9a2ebSMichael Ellerman writel(sa, reg + PCIL0_PTM1MS);
310bfa9a2ebSMichael Ellerman
311bfa9a2ebSMichael Ellerman /* Map on PCI side */
312bfa9a2ebSMichael Ellerman early_write_config_dword(hose, hose->first_busno, 0,
313bfa9a2ebSMichael Ellerman PCI_BASE_ADDRESS_1, res->start);
314bfa9a2ebSMichael Ellerman early_write_config_dword(hose, hose->first_busno, 0,
315bfa9a2ebSMichael Ellerman PCI_BASE_ADDRESS_2, 0x00000000);
316bfa9a2ebSMichael Ellerman early_write_config_word(hose, hose->first_busno, 0,
317bfa9a2ebSMichael Ellerman PCI_COMMAND, 0x0006);
318bfa9a2ebSMichael Ellerman }
319bfa9a2ebSMichael Ellerman
ppc4xx_probe_pci_bridge(struct device_node * np)320bfa9a2ebSMichael Ellerman static void __init ppc4xx_probe_pci_bridge(struct device_node *np)
321bfa9a2ebSMichael Ellerman {
322bfa9a2ebSMichael Ellerman /* NYI */
323bfa9a2ebSMichael Ellerman struct resource rsrc_cfg;
324bfa9a2ebSMichael Ellerman struct resource rsrc_reg;
325bfa9a2ebSMichael Ellerman struct resource dma_window;
326bfa9a2ebSMichael Ellerman struct pci_controller *hose = NULL;
327bfa9a2ebSMichael Ellerman void __iomem *reg = NULL;
328bfa9a2ebSMichael Ellerman const int *bus_range;
329bfa9a2ebSMichael Ellerman int primary = 0;
330bfa9a2ebSMichael Ellerman
331bfa9a2ebSMichael Ellerman /* Check if device is enabled */
332bfa9a2ebSMichael Ellerman if (!of_device_is_available(np)) {
333b7c670d6SRob Herring printk(KERN_INFO "%pOF: Port disabled via device-tree\n", np);
334bfa9a2ebSMichael Ellerman return;
335bfa9a2ebSMichael Ellerman }
336bfa9a2ebSMichael Ellerman
337bfa9a2ebSMichael Ellerman /* Fetch config space registers address */
338bfa9a2ebSMichael Ellerman if (of_address_to_resource(np, 0, &rsrc_cfg)) {
339b7c670d6SRob Herring printk(KERN_ERR "%pOF: Can't get PCI config register base !",
340b7c670d6SRob Herring np);
341bfa9a2ebSMichael Ellerman return;
342bfa9a2ebSMichael Ellerman }
343bfa9a2ebSMichael Ellerman /* Fetch host bridge internal registers address */
344bfa9a2ebSMichael Ellerman if (of_address_to_resource(np, 3, &rsrc_reg)) {
345b7c670d6SRob Herring printk(KERN_ERR "%pOF: Can't get PCI internal register base !",
346b7c670d6SRob Herring np);
347bfa9a2ebSMichael Ellerman return;
348bfa9a2ebSMichael Ellerman }
349bfa9a2ebSMichael Ellerman
350bfa9a2ebSMichael Ellerman /* Check if primary bridge */
3514d57e351SRob Herring if (of_property_read_bool(np, "primary"))
352bfa9a2ebSMichael Ellerman primary = 1;
353bfa9a2ebSMichael Ellerman
354bfa9a2ebSMichael Ellerman /* Get bus range if any */
355bfa9a2ebSMichael Ellerman bus_range = of_get_property(np, "bus-range", NULL);
356bfa9a2ebSMichael Ellerman
357bfa9a2ebSMichael Ellerman /* Map registers */
358bfa9a2ebSMichael Ellerman reg = ioremap(rsrc_reg.start, resource_size(&rsrc_reg));
359bfa9a2ebSMichael Ellerman if (reg == NULL) {
360b7c670d6SRob Herring printk(KERN_ERR "%pOF: Can't map registers !", np);
361bfa9a2ebSMichael Ellerman goto fail;
362bfa9a2ebSMichael Ellerman }
363bfa9a2ebSMichael Ellerman
364bfa9a2ebSMichael Ellerman /* Allocate the host controller data structure */
365bfa9a2ebSMichael Ellerman hose = pcibios_alloc_controller(np);
366bfa9a2ebSMichael Ellerman if (!hose)
367bfa9a2ebSMichael Ellerman goto fail;
368bfa9a2ebSMichael Ellerman
369bfa9a2ebSMichael Ellerman hose->first_busno = bus_range ? bus_range[0] : 0x0;
370bfa9a2ebSMichael Ellerman hose->last_busno = bus_range ? bus_range[1] : 0xff;
371bfa9a2ebSMichael Ellerman
372bfa9a2ebSMichael Ellerman /* Setup config space */
373bfa9a2ebSMichael Ellerman setup_indirect_pci(hose, rsrc_cfg.start, rsrc_cfg.start + 0x4, 0);
374bfa9a2ebSMichael Ellerman
375bfa9a2ebSMichael Ellerman /* Disable all windows */
376bfa9a2ebSMichael Ellerman writel(0, reg + PCIL0_PMM0MA);
377bfa9a2ebSMichael Ellerman writel(0, reg + PCIL0_PMM1MA);
378bfa9a2ebSMichael Ellerman writel(0, reg + PCIL0_PMM2MA);
379bfa9a2ebSMichael Ellerman writel(0, reg + PCIL0_PTM1MS);
380bfa9a2ebSMichael Ellerman writel(0, reg + PCIL0_PTM2MS);
381bfa9a2ebSMichael Ellerman
382bfa9a2ebSMichael Ellerman /* Parse outbound mapping resources */
383bfa9a2ebSMichael Ellerman pci_process_bridge_OF_ranges(hose, np, primary);
384bfa9a2ebSMichael Ellerman
385bfa9a2ebSMichael Ellerman /* Parse inbound mapping resources */
386bfa9a2ebSMichael Ellerman if (ppc4xx_parse_dma_ranges(hose, reg, &dma_window) != 0)
387bfa9a2ebSMichael Ellerman goto fail;
388bfa9a2ebSMichael Ellerman
389bfa9a2ebSMichael Ellerman /* Configure outbound ranges POMs */
390bfa9a2ebSMichael Ellerman ppc4xx_configure_pci_PMMs(hose, reg);
391bfa9a2ebSMichael Ellerman
392bfa9a2ebSMichael Ellerman /* Configure inbound ranges PIMs */
393bfa9a2ebSMichael Ellerman ppc4xx_configure_pci_PTMs(hose, reg, &dma_window);
394bfa9a2ebSMichael Ellerman
395bfa9a2ebSMichael Ellerman /* We don't need the registers anymore */
396bfa9a2ebSMichael Ellerman iounmap(reg);
397bfa9a2ebSMichael Ellerman return;
398bfa9a2ebSMichael Ellerman
399bfa9a2ebSMichael Ellerman fail:
400bfa9a2ebSMichael Ellerman if (hose)
401bfa9a2ebSMichael Ellerman pcibios_free_controller(hose);
402bfa9a2ebSMichael Ellerman if (reg)
403bfa9a2ebSMichael Ellerman iounmap(reg);
404bfa9a2ebSMichael Ellerman }
405bfa9a2ebSMichael Ellerman
406bfa9a2ebSMichael Ellerman /*
407bfa9a2ebSMichael Ellerman * 4xx PCI-X part
408bfa9a2ebSMichael Ellerman */
409bfa9a2ebSMichael Ellerman
ppc4xx_setup_one_pcix_POM(struct pci_controller * hose,void __iomem * reg,u64 plb_addr,u64 pci_addr,u64 size,unsigned int flags,int index)410bfa9a2ebSMichael Ellerman static int __init ppc4xx_setup_one_pcix_POM(struct pci_controller *hose,
411bfa9a2ebSMichael Ellerman void __iomem *reg,
412bfa9a2ebSMichael Ellerman u64 plb_addr,
413bfa9a2ebSMichael Ellerman u64 pci_addr,
414bfa9a2ebSMichael Ellerman u64 size,
415bfa9a2ebSMichael Ellerman unsigned int flags,
416bfa9a2ebSMichael Ellerman int index)
417bfa9a2ebSMichael Ellerman {
418bfa9a2ebSMichael Ellerman u32 lah, lal, pciah, pcial, sa;
419bfa9a2ebSMichael Ellerman
420bfa9a2ebSMichael Ellerman if (!is_power_of_2(size) || size < 0x1000 ||
421bfa9a2ebSMichael Ellerman (plb_addr & (size - 1)) != 0) {
422b7c670d6SRob Herring printk(KERN_WARNING "%pOF: Resource out of range\n",
423b7c670d6SRob Herring hose->dn);
424bfa9a2ebSMichael Ellerman return -1;
425bfa9a2ebSMichael Ellerman }
426bfa9a2ebSMichael Ellerman
427bfa9a2ebSMichael Ellerman /* Calculate register values */
428bfa9a2ebSMichael Ellerman lah = RES_TO_U32_HIGH(plb_addr);
429bfa9a2ebSMichael Ellerman lal = RES_TO_U32_LOW(plb_addr);
430bfa9a2ebSMichael Ellerman pciah = RES_TO_U32_HIGH(pci_addr);
431bfa9a2ebSMichael Ellerman pcial = RES_TO_U32_LOW(pci_addr);
432bfa9a2ebSMichael Ellerman sa = (0xffffffffu << ilog2(size)) | 0x1;
433bfa9a2ebSMichael Ellerman
434bfa9a2ebSMichael Ellerman /* Program register values */
435bfa9a2ebSMichael Ellerman if (index == 0) {
436bfa9a2ebSMichael Ellerman writel(lah, reg + PCIX0_POM0LAH);
437bfa9a2ebSMichael Ellerman writel(lal, reg + PCIX0_POM0LAL);
438bfa9a2ebSMichael Ellerman writel(pciah, reg + PCIX0_POM0PCIAH);
439bfa9a2ebSMichael Ellerman writel(pcial, reg + PCIX0_POM0PCIAL);
440bfa9a2ebSMichael Ellerman writel(sa, reg + PCIX0_POM0SA);
441bfa9a2ebSMichael Ellerman } else {
442bfa9a2ebSMichael Ellerman writel(lah, reg + PCIX0_POM1LAH);
443bfa9a2ebSMichael Ellerman writel(lal, reg + PCIX0_POM1LAL);
444bfa9a2ebSMichael Ellerman writel(pciah, reg + PCIX0_POM1PCIAH);
445bfa9a2ebSMichael Ellerman writel(pcial, reg + PCIX0_POM1PCIAL);
446bfa9a2ebSMichael Ellerman writel(sa, reg + PCIX0_POM1SA);
447bfa9a2ebSMichael Ellerman }
448bfa9a2ebSMichael Ellerman
449bfa9a2ebSMichael Ellerman return 0;
450bfa9a2ebSMichael Ellerman }
451bfa9a2ebSMichael Ellerman
ppc4xx_configure_pcix_POMs(struct pci_controller * hose,void __iomem * reg)452bfa9a2ebSMichael Ellerman static void __init ppc4xx_configure_pcix_POMs(struct pci_controller *hose,
453bfa9a2ebSMichael Ellerman void __iomem *reg)
454bfa9a2ebSMichael Ellerman {
455bfa9a2ebSMichael Ellerman int i, j, found_isa_hole = 0;
456bfa9a2ebSMichael Ellerman
457bfa9a2ebSMichael Ellerman /* Setup outbound memory windows */
458bfa9a2ebSMichael Ellerman for (i = j = 0; i < 3; i++) {
459bfa9a2ebSMichael Ellerman struct resource *res = &hose->mem_resources[i];
460bfa9a2ebSMichael Ellerman resource_size_t offset = hose->mem_offset[i];
461bfa9a2ebSMichael Ellerman
462bfa9a2ebSMichael Ellerman /* we only care about memory windows */
463bfa9a2ebSMichael Ellerman if (!(res->flags & IORESOURCE_MEM))
464bfa9a2ebSMichael Ellerman continue;
465bfa9a2ebSMichael Ellerman if (j > 1) {
466b7c670d6SRob Herring printk(KERN_WARNING "%pOF: Too many ranges\n", hose->dn);
467bfa9a2ebSMichael Ellerman break;
468bfa9a2ebSMichael Ellerman }
469bfa9a2ebSMichael Ellerman
470bfa9a2ebSMichael Ellerman /* Configure the resource */
471bfa9a2ebSMichael Ellerman if (ppc4xx_setup_one_pcix_POM(hose, reg,
472bfa9a2ebSMichael Ellerman res->start,
473bfa9a2ebSMichael Ellerman res->start - offset,
474bfa9a2ebSMichael Ellerman resource_size(res),
475bfa9a2ebSMichael Ellerman res->flags,
476bfa9a2ebSMichael Ellerman j) == 0) {
477bfa9a2ebSMichael Ellerman j++;
478bfa9a2ebSMichael Ellerman
479bfa9a2ebSMichael Ellerman /* If the resource PCI address is 0 then we have our
480bfa9a2ebSMichael Ellerman * ISA memory hole
481bfa9a2ebSMichael Ellerman */
482bfa9a2ebSMichael Ellerman if (res->start == offset)
483bfa9a2ebSMichael Ellerman found_isa_hole = 1;
484bfa9a2ebSMichael Ellerman }
485bfa9a2ebSMichael Ellerman }
486bfa9a2ebSMichael Ellerman
487bfa9a2ebSMichael Ellerman /* Handle ISA memory hole if not already covered */
488bfa9a2ebSMichael Ellerman if (j <= 1 && !found_isa_hole && hose->isa_mem_size)
489bfa9a2ebSMichael Ellerman if (ppc4xx_setup_one_pcix_POM(hose, reg, hose->isa_mem_phys, 0,
490bfa9a2ebSMichael Ellerman hose->isa_mem_size, 0, j) == 0)
491b7c670d6SRob Herring printk(KERN_INFO "%pOF: Legacy ISA memory support enabled\n",
492b7c670d6SRob Herring hose->dn);
493bfa9a2ebSMichael Ellerman }
494bfa9a2ebSMichael Ellerman
ppc4xx_configure_pcix_PIMs(struct pci_controller * hose,void __iomem * reg,const struct resource * res,int big_pim,int enable_msi_hole)495bfa9a2ebSMichael Ellerman static void __init ppc4xx_configure_pcix_PIMs(struct pci_controller *hose,
496bfa9a2ebSMichael Ellerman void __iomem *reg,
497bfa9a2ebSMichael Ellerman const struct resource *res,
498bfa9a2ebSMichael Ellerman int big_pim,
499bfa9a2ebSMichael Ellerman int enable_msi_hole)
500bfa9a2ebSMichael Ellerman {
501bfa9a2ebSMichael Ellerman resource_size_t size = resource_size(res);
502bfa9a2ebSMichael Ellerman u32 sa;
503bfa9a2ebSMichael Ellerman
504bfa9a2ebSMichael Ellerman /* RAM is always at 0 */
505bfa9a2ebSMichael Ellerman writel(0x00000000, reg + PCIX0_PIM0LAH);
506bfa9a2ebSMichael Ellerman writel(0x00000000, reg + PCIX0_PIM0LAL);
507bfa9a2ebSMichael Ellerman
508bfa9a2ebSMichael Ellerman /* Calculate window size */
509bfa9a2ebSMichael Ellerman sa = (0xffffffffu << ilog2(size)) | 1;
510bfa9a2ebSMichael Ellerman sa |= 0x1;
511bfa9a2ebSMichael Ellerman if (res->flags & IORESOURCE_PREFETCH)
512bfa9a2ebSMichael Ellerman sa |= 0x2;
513bfa9a2ebSMichael Ellerman if (enable_msi_hole)
514bfa9a2ebSMichael Ellerman sa |= 0x4;
515bfa9a2ebSMichael Ellerman writel(sa, reg + PCIX0_PIM0SA);
516bfa9a2ebSMichael Ellerman if (big_pim)
517bfa9a2ebSMichael Ellerman writel(0xffffffff, reg + PCIX0_PIM0SAH);
518bfa9a2ebSMichael Ellerman
519bfa9a2ebSMichael Ellerman /* Map on PCI side */
520bfa9a2ebSMichael Ellerman writel(0x00000000, reg + PCIX0_BAR0H);
521bfa9a2ebSMichael Ellerman writel(res->start, reg + PCIX0_BAR0L);
522bfa9a2ebSMichael Ellerman writew(0x0006, reg + PCIX0_COMMAND);
523bfa9a2ebSMichael Ellerman }
524bfa9a2ebSMichael Ellerman
ppc4xx_probe_pcix_bridge(struct device_node * np)525bfa9a2ebSMichael Ellerman static void __init ppc4xx_probe_pcix_bridge(struct device_node *np)
526bfa9a2ebSMichael Ellerman {
527bfa9a2ebSMichael Ellerman struct resource rsrc_cfg;
528bfa9a2ebSMichael Ellerman struct resource rsrc_reg;
529bfa9a2ebSMichael Ellerman struct resource dma_window;
530bfa9a2ebSMichael Ellerman struct pci_controller *hose = NULL;
531bfa9a2ebSMichael Ellerman void __iomem *reg = NULL;
532bfa9a2ebSMichael Ellerman const int *bus_range;
5334d57e351SRob Herring int big_pim, msi, primary;
534bfa9a2ebSMichael Ellerman
535bfa9a2ebSMichael Ellerman /* Fetch config space registers address */
536bfa9a2ebSMichael Ellerman if (of_address_to_resource(np, 0, &rsrc_cfg)) {
537b7c670d6SRob Herring printk(KERN_ERR "%pOF: Can't get PCI-X config register base !",
538b7c670d6SRob Herring np);
539bfa9a2ebSMichael Ellerman return;
540bfa9a2ebSMichael Ellerman }
541bfa9a2ebSMichael Ellerman /* Fetch host bridge internal registers address */
542bfa9a2ebSMichael Ellerman if (of_address_to_resource(np, 3, &rsrc_reg)) {
543b7c670d6SRob Herring printk(KERN_ERR "%pOF: Can't get PCI-X internal register base !",
544b7c670d6SRob Herring np);
545bfa9a2ebSMichael Ellerman return;
546bfa9a2ebSMichael Ellerman }
547bfa9a2ebSMichael Ellerman
548bfa9a2ebSMichael Ellerman /* Check if it supports large PIMs (440GX) */
5494d57e351SRob Herring big_pim = of_property_read_bool(np, "large-inbound-windows");
550bfa9a2ebSMichael Ellerman
551bfa9a2ebSMichael Ellerman /* Check if we should enable MSIs inbound hole */
5524d57e351SRob Herring msi = of_property_read_bool(np, "enable-msi-hole");
553bfa9a2ebSMichael Ellerman
554bfa9a2ebSMichael Ellerman /* Check if primary bridge */
5554d57e351SRob Herring primary = of_property_read_bool(np, "primary");
556bfa9a2ebSMichael Ellerman
557bfa9a2ebSMichael Ellerman /* Get bus range if any */
558bfa9a2ebSMichael Ellerman bus_range = of_get_property(np, "bus-range", NULL);
559bfa9a2ebSMichael Ellerman
560bfa9a2ebSMichael Ellerman /* Map registers */
561bfa9a2ebSMichael Ellerman reg = ioremap(rsrc_reg.start, resource_size(&rsrc_reg));
562bfa9a2ebSMichael Ellerman if (reg == NULL) {
563b7c670d6SRob Herring printk(KERN_ERR "%pOF: Can't map registers !", np);
564bfa9a2ebSMichael Ellerman goto fail;
565bfa9a2ebSMichael Ellerman }
566bfa9a2ebSMichael Ellerman
567bfa9a2ebSMichael Ellerman /* Allocate the host controller data structure */
568bfa9a2ebSMichael Ellerman hose = pcibios_alloc_controller(np);
569bfa9a2ebSMichael Ellerman if (!hose)
570bfa9a2ebSMichael Ellerman goto fail;
571bfa9a2ebSMichael Ellerman
572bfa9a2ebSMichael Ellerman hose->first_busno = bus_range ? bus_range[0] : 0x0;
573bfa9a2ebSMichael Ellerman hose->last_busno = bus_range ? bus_range[1] : 0xff;
574bfa9a2ebSMichael Ellerman
575bfa9a2ebSMichael Ellerman /* Setup config space */
576bfa9a2ebSMichael Ellerman setup_indirect_pci(hose, rsrc_cfg.start, rsrc_cfg.start + 0x4,
577bfa9a2ebSMichael Ellerman PPC_INDIRECT_TYPE_SET_CFG_TYPE);
578bfa9a2ebSMichael Ellerman
579bfa9a2ebSMichael Ellerman /* Disable all windows */
580bfa9a2ebSMichael Ellerman writel(0, reg + PCIX0_POM0SA);
581bfa9a2ebSMichael Ellerman writel(0, reg + PCIX0_POM1SA);
582bfa9a2ebSMichael Ellerman writel(0, reg + PCIX0_POM2SA);
583bfa9a2ebSMichael Ellerman writel(0, reg + PCIX0_PIM0SA);
584bfa9a2ebSMichael Ellerman writel(0, reg + PCIX0_PIM1SA);
585bfa9a2ebSMichael Ellerman writel(0, reg + PCIX0_PIM2SA);
586bfa9a2ebSMichael Ellerman if (big_pim) {
587bfa9a2ebSMichael Ellerman writel(0, reg + PCIX0_PIM0SAH);
588bfa9a2ebSMichael Ellerman writel(0, reg + PCIX0_PIM2SAH);
589bfa9a2ebSMichael Ellerman }
590bfa9a2ebSMichael Ellerman
591bfa9a2ebSMichael Ellerman /* Parse outbound mapping resources */
592bfa9a2ebSMichael Ellerman pci_process_bridge_OF_ranges(hose, np, primary);
593bfa9a2ebSMichael Ellerman
594bfa9a2ebSMichael Ellerman /* Parse inbound mapping resources */
595bfa9a2ebSMichael Ellerman if (ppc4xx_parse_dma_ranges(hose, reg, &dma_window) != 0)
596bfa9a2ebSMichael Ellerman goto fail;
597bfa9a2ebSMichael Ellerman
598bfa9a2ebSMichael Ellerman /* Configure outbound ranges POMs */
599bfa9a2ebSMichael Ellerman ppc4xx_configure_pcix_POMs(hose, reg);
600bfa9a2ebSMichael Ellerman
601bfa9a2ebSMichael Ellerman /* Configure inbound ranges PIMs */
602bfa9a2ebSMichael Ellerman ppc4xx_configure_pcix_PIMs(hose, reg, &dma_window, big_pim, msi);
603bfa9a2ebSMichael Ellerman
604bfa9a2ebSMichael Ellerman /* We don't need the registers anymore */
605bfa9a2ebSMichael Ellerman iounmap(reg);
606bfa9a2ebSMichael Ellerman return;
607bfa9a2ebSMichael Ellerman
608bfa9a2ebSMichael Ellerman fail:
609bfa9a2ebSMichael Ellerman if (hose)
610bfa9a2ebSMichael Ellerman pcibios_free_controller(hose);
611bfa9a2ebSMichael Ellerman if (reg)
612bfa9a2ebSMichael Ellerman iounmap(reg);
613bfa9a2ebSMichael Ellerman }
614bfa9a2ebSMichael Ellerman
615bfa9a2ebSMichael Ellerman #ifdef CONFIG_PPC4xx_PCI_EXPRESS
616bfa9a2ebSMichael Ellerman
617bfa9a2ebSMichael Ellerman /*
618bfa9a2ebSMichael Ellerman * 4xx PCI-Express part
619bfa9a2ebSMichael Ellerman *
620bfa9a2ebSMichael Ellerman * We support 3 parts currently based on the compatible property:
621bfa9a2ebSMichael Ellerman *
622bfa9a2ebSMichael Ellerman * ibm,plb-pciex-440spe
623bfa9a2ebSMichael Ellerman * ibm,plb-pciex-405ex
624bfa9a2ebSMichael Ellerman * ibm,plb-pciex-460ex
625bfa9a2ebSMichael Ellerman *
626bfa9a2ebSMichael Ellerman * Anything else will be rejected for now as they are all subtly
627bfa9a2ebSMichael Ellerman * different unfortunately.
628bfa9a2ebSMichael Ellerman *
629bfa9a2ebSMichael Ellerman */
630bfa9a2ebSMichael Ellerman
631bfa9a2ebSMichael Ellerman #define MAX_PCIE_BUS_MAPPED 0x40
632bfa9a2ebSMichael Ellerman
633bfa9a2ebSMichael Ellerman struct ppc4xx_pciex_port
634bfa9a2ebSMichael Ellerman {
635bfa9a2ebSMichael Ellerman struct pci_controller *hose;
636bfa9a2ebSMichael Ellerman struct device_node *node;
637bfa9a2ebSMichael Ellerman unsigned int index;
638bfa9a2ebSMichael Ellerman int endpoint;
639bfa9a2ebSMichael Ellerman int link;
640bfa9a2ebSMichael Ellerman int has_ibpre;
641bfa9a2ebSMichael Ellerman unsigned int sdr_base;
642bfa9a2ebSMichael Ellerman dcr_host_t dcrs;
643bfa9a2ebSMichael Ellerman struct resource cfg_space;
644bfa9a2ebSMichael Ellerman struct resource utl_regs;
645bfa9a2ebSMichael Ellerman void __iomem *utl_base;
646bfa9a2ebSMichael Ellerman };
647bfa9a2ebSMichael Ellerman
648bfa9a2ebSMichael Ellerman static struct ppc4xx_pciex_port *ppc4xx_pciex_ports;
649bfa9a2ebSMichael Ellerman static unsigned int ppc4xx_pciex_port_count;
650bfa9a2ebSMichael Ellerman
651bfa9a2ebSMichael Ellerman struct ppc4xx_pciex_hwops
652bfa9a2ebSMichael Ellerman {
653bfa9a2ebSMichael Ellerman bool want_sdr;
654bfa9a2ebSMichael Ellerman int (*core_init)(struct device_node *np);
655bfa9a2ebSMichael Ellerman int (*port_init_hw)(struct ppc4xx_pciex_port *port);
656bfa9a2ebSMichael Ellerman int (*setup_utl)(struct ppc4xx_pciex_port *port);
657bfa9a2ebSMichael Ellerman void (*check_link)(struct ppc4xx_pciex_port *port);
658bfa9a2ebSMichael Ellerman };
659bfa9a2ebSMichael Ellerman
660bfa9a2ebSMichael Ellerman static struct ppc4xx_pciex_hwops *ppc4xx_pciex_hwops;
661bfa9a2ebSMichael Ellerman
ppc4xx_pciex_wait_on_sdr(struct ppc4xx_pciex_port * port,unsigned int sdr_offset,unsigned int mask,unsigned int value,int timeout_ms)662bfa9a2ebSMichael Ellerman static int __init ppc4xx_pciex_wait_on_sdr(struct ppc4xx_pciex_port *port,
663bfa9a2ebSMichael Ellerman unsigned int sdr_offset,
664bfa9a2ebSMichael Ellerman unsigned int mask,
665bfa9a2ebSMichael Ellerman unsigned int value,
666bfa9a2ebSMichael Ellerman int timeout_ms)
667bfa9a2ebSMichael Ellerman {
668bfa9a2ebSMichael Ellerman u32 val;
669bfa9a2ebSMichael Ellerman
670bfa9a2ebSMichael Ellerman while(timeout_ms--) {
671bfa9a2ebSMichael Ellerman val = mfdcri(SDR0, port->sdr_base + sdr_offset);
672bfa9a2ebSMichael Ellerman if ((val & mask) == value) {
673bfa9a2ebSMichael Ellerman pr_debug("PCIE%d: Wait on SDR %x success with tm %d (%08x)\n",
674bfa9a2ebSMichael Ellerman port->index, sdr_offset, timeout_ms, val);
675bfa9a2ebSMichael Ellerman return 0;
676bfa9a2ebSMichael Ellerman }
677bfa9a2ebSMichael Ellerman msleep(1);
678bfa9a2ebSMichael Ellerman }
679bfa9a2ebSMichael Ellerman return -1;
680bfa9a2ebSMichael Ellerman }
681bfa9a2ebSMichael Ellerman
ppc4xx_pciex_port_reset_sdr(struct ppc4xx_pciex_port * port)682bfa9a2ebSMichael Ellerman static int __init ppc4xx_pciex_port_reset_sdr(struct ppc4xx_pciex_port *port)
683bfa9a2ebSMichael Ellerman {
684bfa9a2ebSMichael Ellerman /* Wait for reset to complete */
685bfa9a2ebSMichael Ellerman if (ppc4xx_pciex_wait_on_sdr(port, PESDRn_RCSSTS, 1 << 20, 0, 10)) {
686bfa9a2ebSMichael Ellerman printk(KERN_WARNING "PCIE%d: PGRST failed\n",
687bfa9a2ebSMichael Ellerman port->index);
688bfa9a2ebSMichael Ellerman return -1;
689bfa9a2ebSMichael Ellerman }
690bfa9a2ebSMichael Ellerman return 0;
691bfa9a2ebSMichael Ellerman }
692bfa9a2ebSMichael Ellerman
693bfa9a2ebSMichael Ellerman
ppc4xx_pciex_check_link_sdr(struct ppc4xx_pciex_port * port)694bfa9a2ebSMichael Ellerman static void __init ppc4xx_pciex_check_link_sdr(struct ppc4xx_pciex_port *port)
695bfa9a2ebSMichael Ellerman {
696bfa9a2ebSMichael Ellerman printk(KERN_INFO "PCIE%d: Checking link...\n", port->index);
697bfa9a2ebSMichael Ellerman
698bfa9a2ebSMichael Ellerman /* Check for card presence detect if supported, if not, just wait for
699bfa9a2ebSMichael Ellerman * link unconditionally.
700bfa9a2ebSMichael Ellerman *
701bfa9a2ebSMichael Ellerman * note that we don't fail if there is no link, we just filter out
702bfa9a2ebSMichael Ellerman * config space accesses. That way, it will be easier to implement
703bfa9a2ebSMichael Ellerman * hotplug later on.
704bfa9a2ebSMichael Ellerman */
705bfa9a2ebSMichael Ellerman if (!port->has_ibpre ||
706bfa9a2ebSMichael Ellerman !ppc4xx_pciex_wait_on_sdr(port, PESDRn_LOOP,
707bfa9a2ebSMichael Ellerman 1 << 28, 1 << 28, 100)) {
708bfa9a2ebSMichael Ellerman printk(KERN_INFO
709bfa9a2ebSMichael Ellerman "PCIE%d: Device detected, waiting for link...\n",
710bfa9a2ebSMichael Ellerman port->index);
711bfa9a2ebSMichael Ellerman if (ppc4xx_pciex_wait_on_sdr(port, PESDRn_LOOP,
712bfa9a2ebSMichael Ellerman 0x1000, 0x1000, 2000))
713bfa9a2ebSMichael Ellerman printk(KERN_WARNING
714bfa9a2ebSMichael Ellerman "PCIE%d: Link up failed\n", port->index);
715bfa9a2ebSMichael Ellerman else {
716bfa9a2ebSMichael Ellerman printk(KERN_INFO
717bfa9a2ebSMichael Ellerman "PCIE%d: link is up !\n", port->index);
718bfa9a2ebSMichael Ellerman port->link = 1;
719bfa9a2ebSMichael Ellerman }
720bfa9a2ebSMichael Ellerman } else
721bfa9a2ebSMichael Ellerman printk(KERN_INFO "PCIE%d: No device detected.\n", port->index);
722bfa9a2ebSMichael Ellerman }
723bfa9a2ebSMichael Ellerman
724bfa9a2ebSMichael Ellerman #ifdef CONFIG_44x
725bfa9a2ebSMichael Ellerman
726bfa9a2ebSMichael Ellerman /* Check various reset bits of the 440SPe PCIe core */
ppc440spe_pciex_check_reset(struct device_node * np)727bfa9a2ebSMichael Ellerman static int __init ppc440spe_pciex_check_reset(struct device_node *np)
728bfa9a2ebSMichael Ellerman {
729bfa9a2ebSMichael Ellerman u32 valPE0, valPE1, valPE2;
730bfa9a2ebSMichael Ellerman int err = 0;
731bfa9a2ebSMichael Ellerman
732bfa9a2ebSMichael Ellerman /* SDR0_PEGPLLLCT1 reset */
733bfa9a2ebSMichael Ellerman if (!(mfdcri(SDR0, PESDR0_PLLLCT1) & 0x01000000)) {
734bfa9a2ebSMichael Ellerman /*
735bfa9a2ebSMichael Ellerman * the PCIe core was probably already initialised
736bfa9a2ebSMichael Ellerman * by firmware - let's re-reset RCSSET regs
737bfa9a2ebSMichael Ellerman *
738bfa9a2ebSMichael Ellerman * -- Shouldn't we also re-reset the whole thing ? -- BenH
739bfa9a2ebSMichael Ellerman */
740bfa9a2ebSMichael Ellerman pr_debug("PCIE: SDR0_PLLLCT1 already reset.\n");
741bfa9a2ebSMichael Ellerman mtdcri(SDR0, PESDR0_440SPE_RCSSET, 0x01010000);
742bfa9a2ebSMichael Ellerman mtdcri(SDR0, PESDR1_440SPE_RCSSET, 0x01010000);
743bfa9a2ebSMichael Ellerman mtdcri(SDR0, PESDR2_440SPE_RCSSET, 0x01010000);
744bfa9a2ebSMichael Ellerman }
745bfa9a2ebSMichael Ellerman
746bfa9a2ebSMichael Ellerman valPE0 = mfdcri(SDR0, PESDR0_440SPE_RCSSET);
747bfa9a2ebSMichael Ellerman valPE1 = mfdcri(SDR0, PESDR1_440SPE_RCSSET);
748bfa9a2ebSMichael Ellerman valPE2 = mfdcri(SDR0, PESDR2_440SPE_RCSSET);
749bfa9a2ebSMichael Ellerman
750bfa9a2ebSMichael Ellerman /* SDR0_PExRCSSET rstgu */
751bfa9a2ebSMichael Ellerman if (!(valPE0 & 0x01000000) ||
752bfa9a2ebSMichael Ellerman !(valPE1 & 0x01000000) ||
753bfa9a2ebSMichael Ellerman !(valPE2 & 0x01000000)) {
754bfa9a2ebSMichael Ellerman printk(KERN_INFO "PCIE: SDR0_PExRCSSET rstgu error\n");
755bfa9a2ebSMichael Ellerman err = -1;
756bfa9a2ebSMichael Ellerman }
757bfa9a2ebSMichael Ellerman
758bfa9a2ebSMichael Ellerman /* SDR0_PExRCSSET rstdl */
759bfa9a2ebSMichael Ellerman if (!(valPE0 & 0x00010000) ||
760bfa9a2ebSMichael Ellerman !(valPE1 & 0x00010000) ||
761bfa9a2ebSMichael Ellerman !(valPE2 & 0x00010000)) {
762bfa9a2ebSMichael Ellerman printk(KERN_INFO "PCIE: SDR0_PExRCSSET rstdl error\n");
763bfa9a2ebSMichael Ellerman err = -1;
764bfa9a2ebSMichael Ellerman }
765bfa9a2ebSMichael Ellerman
766bfa9a2ebSMichael Ellerman /* SDR0_PExRCSSET rstpyn */
767bfa9a2ebSMichael Ellerman if ((valPE0 & 0x00001000) ||
768bfa9a2ebSMichael Ellerman (valPE1 & 0x00001000) ||
769bfa9a2ebSMichael Ellerman (valPE2 & 0x00001000)) {
770bfa9a2ebSMichael Ellerman printk(KERN_INFO "PCIE: SDR0_PExRCSSET rstpyn error\n");
771bfa9a2ebSMichael Ellerman err = -1;
772bfa9a2ebSMichael Ellerman }
773bfa9a2ebSMichael Ellerman
774bfa9a2ebSMichael Ellerman /* SDR0_PExRCSSET hldplb */
775bfa9a2ebSMichael Ellerman if ((valPE0 & 0x10000000) ||
776bfa9a2ebSMichael Ellerman (valPE1 & 0x10000000) ||
777bfa9a2ebSMichael Ellerman (valPE2 & 0x10000000)) {
778bfa9a2ebSMichael Ellerman printk(KERN_INFO "PCIE: SDR0_PExRCSSET hldplb error\n");
779bfa9a2ebSMichael Ellerman err = -1;
780bfa9a2ebSMichael Ellerman }
781bfa9a2ebSMichael Ellerman
782bfa9a2ebSMichael Ellerman /* SDR0_PExRCSSET rdy */
783bfa9a2ebSMichael Ellerman if ((valPE0 & 0x00100000) ||
784bfa9a2ebSMichael Ellerman (valPE1 & 0x00100000) ||
785bfa9a2ebSMichael Ellerman (valPE2 & 0x00100000)) {
786bfa9a2ebSMichael Ellerman printk(KERN_INFO "PCIE: SDR0_PExRCSSET rdy error\n");
787bfa9a2ebSMichael Ellerman err = -1;
788bfa9a2ebSMichael Ellerman }
789bfa9a2ebSMichael Ellerman
790bfa9a2ebSMichael Ellerman /* SDR0_PExRCSSET shutdown */
791bfa9a2ebSMichael Ellerman if ((valPE0 & 0x00000100) ||
792bfa9a2ebSMichael Ellerman (valPE1 & 0x00000100) ||
793bfa9a2ebSMichael Ellerman (valPE2 & 0x00000100)) {
794bfa9a2ebSMichael Ellerman printk(KERN_INFO "PCIE: SDR0_PExRCSSET shutdown error\n");
795bfa9a2ebSMichael Ellerman err = -1;
796bfa9a2ebSMichael Ellerman }
797bfa9a2ebSMichael Ellerman
798bfa9a2ebSMichael Ellerman return err;
799bfa9a2ebSMichael Ellerman }
800bfa9a2ebSMichael Ellerman
801bfa9a2ebSMichael Ellerman /* Global PCIe core initializations for 440SPe core */
ppc440spe_pciex_core_init(struct device_node * np)802bfa9a2ebSMichael Ellerman static int __init ppc440spe_pciex_core_init(struct device_node *np)
803bfa9a2ebSMichael Ellerman {
804bfa9a2ebSMichael Ellerman int time_out = 20;
805bfa9a2ebSMichael Ellerman
806bfa9a2ebSMichael Ellerman /* Set PLL clock receiver to LVPECL */
807bfa9a2ebSMichael Ellerman dcri_clrset(SDR0, PESDR0_PLLLCT1, 0, 1 << 28);
808bfa9a2ebSMichael Ellerman
809bfa9a2ebSMichael Ellerman /* Shouldn't we do all the calibration stuff etc... here ? */
810bfa9a2ebSMichael Ellerman if (ppc440spe_pciex_check_reset(np))
811bfa9a2ebSMichael Ellerman return -ENXIO;
812bfa9a2ebSMichael Ellerman
813bfa9a2ebSMichael Ellerman if (!(mfdcri(SDR0, PESDR0_PLLLCT2) & 0x10000)) {
814bfa9a2ebSMichael Ellerman printk(KERN_INFO "PCIE: PESDR_PLLCT2 resistance calibration "
815bfa9a2ebSMichael Ellerman "failed (0x%08x)\n",
816bfa9a2ebSMichael Ellerman mfdcri(SDR0, PESDR0_PLLLCT2));
817bfa9a2ebSMichael Ellerman return -1;
818bfa9a2ebSMichael Ellerman }
819bfa9a2ebSMichael Ellerman
820bfa9a2ebSMichael Ellerman /* De-assert reset of PCIe PLL, wait for lock */
821bfa9a2ebSMichael Ellerman dcri_clrset(SDR0, PESDR0_PLLLCT1, 1 << 24, 0);
822bfa9a2ebSMichael Ellerman udelay(3);
823bfa9a2ebSMichael Ellerman
824bfa9a2ebSMichael Ellerman while (time_out) {
825bfa9a2ebSMichael Ellerman if (!(mfdcri(SDR0, PESDR0_PLLLCT3) & 0x10000000)) {
826bfa9a2ebSMichael Ellerman time_out--;
827bfa9a2ebSMichael Ellerman udelay(1);
828bfa9a2ebSMichael Ellerman } else
829bfa9a2ebSMichael Ellerman break;
830bfa9a2ebSMichael Ellerman }
831bfa9a2ebSMichael Ellerman if (!time_out) {
832bfa9a2ebSMichael Ellerman printk(KERN_INFO "PCIE: VCO output not locked\n");
833bfa9a2ebSMichael Ellerman return -1;
834bfa9a2ebSMichael Ellerman }
835bfa9a2ebSMichael Ellerman
836bfa9a2ebSMichael Ellerman pr_debug("PCIE initialization OK\n");
837bfa9a2ebSMichael Ellerman
838bfa9a2ebSMichael Ellerman return 3;
839bfa9a2ebSMichael Ellerman }
840bfa9a2ebSMichael Ellerman
ppc440spe_pciex_init_port_hw(struct ppc4xx_pciex_port * port)841bfa9a2ebSMichael Ellerman static int __init ppc440spe_pciex_init_port_hw(struct ppc4xx_pciex_port *port)
842bfa9a2ebSMichael Ellerman {
843bfa9a2ebSMichael Ellerman u32 val = 1 << 24;
844bfa9a2ebSMichael Ellerman
845bfa9a2ebSMichael Ellerman if (port->endpoint)
846bfa9a2ebSMichael Ellerman val = PTYPE_LEGACY_ENDPOINT << 20;
847bfa9a2ebSMichael Ellerman else
848bfa9a2ebSMichael Ellerman val = PTYPE_ROOT_PORT << 20;
849bfa9a2ebSMichael Ellerman
850bfa9a2ebSMichael Ellerman if (port->index == 0)
851bfa9a2ebSMichael Ellerman val |= LNKW_X8 << 12;
852bfa9a2ebSMichael Ellerman else
853bfa9a2ebSMichael Ellerman val |= LNKW_X4 << 12;
854bfa9a2ebSMichael Ellerman
855bfa9a2ebSMichael Ellerman mtdcri(SDR0, port->sdr_base + PESDRn_DLPSET, val);
856bfa9a2ebSMichael Ellerman mtdcri(SDR0, port->sdr_base + PESDRn_UTLSET1, 0x20222222);
857bfa9a2ebSMichael Ellerman if (ppc440spe_revA())
858bfa9a2ebSMichael Ellerman mtdcri(SDR0, port->sdr_base + PESDRn_UTLSET2, 0x11000000);
859bfa9a2ebSMichael Ellerman mtdcri(SDR0, port->sdr_base + PESDRn_440SPE_HSSL0SET1, 0x35000000);
860bfa9a2ebSMichael Ellerman mtdcri(SDR0, port->sdr_base + PESDRn_440SPE_HSSL1SET1, 0x35000000);
861bfa9a2ebSMichael Ellerman mtdcri(SDR0, port->sdr_base + PESDRn_440SPE_HSSL2SET1, 0x35000000);
862bfa9a2ebSMichael Ellerman mtdcri(SDR0, port->sdr_base + PESDRn_440SPE_HSSL3SET1, 0x35000000);
863bfa9a2ebSMichael Ellerman if (port->index == 0) {
864bfa9a2ebSMichael Ellerman mtdcri(SDR0, port->sdr_base + PESDRn_440SPE_HSSL4SET1,
865bfa9a2ebSMichael Ellerman 0x35000000);
866bfa9a2ebSMichael Ellerman mtdcri(SDR0, port->sdr_base + PESDRn_440SPE_HSSL5SET1,
867bfa9a2ebSMichael Ellerman 0x35000000);
868bfa9a2ebSMichael Ellerman mtdcri(SDR0, port->sdr_base + PESDRn_440SPE_HSSL6SET1,
869bfa9a2ebSMichael Ellerman 0x35000000);
870bfa9a2ebSMichael Ellerman mtdcri(SDR0, port->sdr_base + PESDRn_440SPE_HSSL7SET1,
871bfa9a2ebSMichael Ellerman 0x35000000);
872bfa9a2ebSMichael Ellerman }
873bfa9a2ebSMichael Ellerman dcri_clrset(SDR0, port->sdr_base + PESDRn_RCSSET,
874bfa9a2ebSMichael Ellerman (1 << 24) | (1 << 16), 1 << 12);
875bfa9a2ebSMichael Ellerman
876bfa9a2ebSMichael Ellerman return ppc4xx_pciex_port_reset_sdr(port);
877bfa9a2ebSMichael Ellerman }
878bfa9a2ebSMichael Ellerman
ppc440speA_pciex_init_port_hw(struct ppc4xx_pciex_port * port)879bfa9a2ebSMichael Ellerman static int __init ppc440speA_pciex_init_port_hw(struct ppc4xx_pciex_port *port)
880bfa9a2ebSMichael Ellerman {
881bfa9a2ebSMichael Ellerman return ppc440spe_pciex_init_port_hw(port);
882bfa9a2ebSMichael Ellerman }
883bfa9a2ebSMichael Ellerman
ppc440speB_pciex_init_port_hw(struct ppc4xx_pciex_port * port)884bfa9a2ebSMichael Ellerman static int __init ppc440speB_pciex_init_port_hw(struct ppc4xx_pciex_port *port)
885bfa9a2ebSMichael Ellerman {
886bfa9a2ebSMichael Ellerman int rc = ppc440spe_pciex_init_port_hw(port);
887bfa9a2ebSMichael Ellerman
888bfa9a2ebSMichael Ellerman port->has_ibpre = 1;
889bfa9a2ebSMichael Ellerman
890bfa9a2ebSMichael Ellerman return rc;
891bfa9a2ebSMichael Ellerman }
892bfa9a2ebSMichael Ellerman
ppc440speA_pciex_init_utl(struct ppc4xx_pciex_port * port)893bfa9a2ebSMichael Ellerman static int ppc440speA_pciex_init_utl(struct ppc4xx_pciex_port *port)
894bfa9a2ebSMichael Ellerman {
895bfa9a2ebSMichael Ellerman /* XXX Check what that value means... I hate magic */
896bfa9a2ebSMichael Ellerman dcr_write(port->dcrs, DCRO_PEGPL_SPECIAL, 0x68782800);
897bfa9a2ebSMichael Ellerman
898bfa9a2ebSMichael Ellerman /*
899bfa9a2ebSMichael Ellerman * Set buffer allocations and then assert VRB and TXE.
900bfa9a2ebSMichael Ellerman */
901bfa9a2ebSMichael Ellerman out_be32(port->utl_base + PEUTL_OUTTR, 0x08000000);
902bfa9a2ebSMichael Ellerman out_be32(port->utl_base + PEUTL_INTR, 0x02000000);
903bfa9a2ebSMichael Ellerman out_be32(port->utl_base + PEUTL_OPDBSZ, 0x10000000);
904bfa9a2ebSMichael Ellerman out_be32(port->utl_base + PEUTL_PBBSZ, 0x53000000);
905bfa9a2ebSMichael Ellerman out_be32(port->utl_base + PEUTL_IPHBSZ, 0x08000000);
906bfa9a2ebSMichael Ellerman out_be32(port->utl_base + PEUTL_IPDBSZ, 0x10000000);
907bfa9a2ebSMichael Ellerman out_be32(port->utl_base + PEUTL_RCIRQEN, 0x00f00000);
908bfa9a2ebSMichael Ellerman out_be32(port->utl_base + PEUTL_PCTL, 0x80800066);
909bfa9a2ebSMichael Ellerman
910bfa9a2ebSMichael Ellerman return 0;
911bfa9a2ebSMichael Ellerman }
912bfa9a2ebSMichael Ellerman
ppc440speB_pciex_init_utl(struct ppc4xx_pciex_port * port)913bfa9a2ebSMichael Ellerman static int ppc440speB_pciex_init_utl(struct ppc4xx_pciex_port *port)
914bfa9a2ebSMichael Ellerman {
915bfa9a2ebSMichael Ellerman /* Report CRS to the operating system */
916bfa9a2ebSMichael Ellerman out_be32(port->utl_base + PEUTL_PBCTL, 0x08000000);
917bfa9a2ebSMichael Ellerman
918bfa9a2ebSMichael Ellerman return 0;
919bfa9a2ebSMichael Ellerman }
920bfa9a2ebSMichael Ellerman
921bfa9a2ebSMichael Ellerman static struct ppc4xx_pciex_hwops ppc440speA_pcie_hwops __initdata =
922bfa9a2ebSMichael Ellerman {
923bfa9a2ebSMichael Ellerman .want_sdr = true,
924bfa9a2ebSMichael Ellerman .core_init = ppc440spe_pciex_core_init,
925bfa9a2ebSMichael Ellerman .port_init_hw = ppc440speA_pciex_init_port_hw,
926bfa9a2ebSMichael Ellerman .setup_utl = ppc440speA_pciex_init_utl,
927bfa9a2ebSMichael Ellerman .check_link = ppc4xx_pciex_check_link_sdr,
928bfa9a2ebSMichael Ellerman };
929bfa9a2ebSMichael Ellerman
930bfa9a2ebSMichael Ellerman static struct ppc4xx_pciex_hwops ppc440speB_pcie_hwops __initdata =
931bfa9a2ebSMichael Ellerman {
932bfa9a2ebSMichael Ellerman .want_sdr = true,
933bfa9a2ebSMichael Ellerman .core_init = ppc440spe_pciex_core_init,
934bfa9a2ebSMichael Ellerman .port_init_hw = ppc440speB_pciex_init_port_hw,
935bfa9a2ebSMichael Ellerman .setup_utl = ppc440speB_pciex_init_utl,
936bfa9a2ebSMichael Ellerman .check_link = ppc4xx_pciex_check_link_sdr,
937bfa9a2ebSMichael Ellerman };
938bfa9a2ebSMichael Ellerman
ppc460ex_pciex_core_init(struct device_node * np)939bfa9a2ebSMichael Ellerman static int __init ppc460ex_pciex_core_init(struct device_node *np)
940bfa9a2ebSMichael Ellerman {
941bfa9a2ebSMichael Ellerman /* Nothing to do, return 2 ports */
942bfa9a2ebSMichael Ellerman return 2;
943bfa9a2ebSMichael Ellerman }
944bfa9a2ebSMichael Ellerman
ppc460ex_pciex_init_port_hw(struct ppc4xx_pciex_port * port)945bfa9a2ebSMichael Ellerman static int __init ppc460ex_pciex_init_port_hw(struct ppc4xx_pciex_port *port)
946bfa9a2ebSMichael Ellerman {
947bfa9a2ebSMichael Ellerman u32 val;
948bfa9a2ebSMichael Ellerman u32 utlset1;
949bfa9a2ebSMichael Ellerman
950bfa9a2ebSMichael Ellerman if (port->endpoint)
951bfa9a2ebSMichael Ellerman val = PTYPE_LEGACY_ENDPOINT << 20;
952bfa9a2ebSMichael Ellerman else
953bfa9a2ebSMichael Ellerman val = PTYPE_ROOT_PORT << 20;
954bfa9a2ebSMichael Ellerman
955bfa9a2ebSMichael Ellerman if (port->index == 0) {
956bfa9a2ebSMichael Ellerman val |= LNKW_X1 << 12;
957bfa9a2ebSMichael Ellerman utlset1 = 0x20000000;
958bfa9a2ebSMichael Ellerman } else {
959bfa9a2ebSMichael Ellerman val |= LNKW_X4 << 12;
960bfa9a2ebSMichael Ellerman utlset1 = 0x20101101;
961bfa9a2ebSMichael Ellerman }
962bfa9a2ebSMichael Ellerman
963bfa9a2ebSMichael Ellerman mtdcri(SDR0, port->sdr_base + PESDRn_DLPSET, val);
964bfa9a2ebSMichael Ellerman mtdcri(SDR0, port->sdr_base + PESDRn_UTLSET1, utlset1);
965bfa9a2ebSMichael Ellerman mtdcri(SDR0, port->sdr_base + PESDRn_UTLSET2, 0x01210000);
966bfa9a2ebSMichael Ellerman
967bfa9a2ebSMichael Ellerman switch (port->index) {
968bfa9a2ebSMichael Ellerman case 0:
969bfa9a2ebSMichael Ellerman mtdcri(SDR0, PESDR0_460EX_L0CDRCTL, 0x00003230);
970bfa9a2ebSMichael Ellerman mtdcri(SDR0, PESDR0_460EX_L0DRV, 0x00000130);
971bfa9a2ebSMichael Ellerman mtdcri(SDR0, PESDR0_460EX_L0CLK, 0x00000006);
972bfa9a2ebSMichael Ellerman
973bfa9a2ebSMichael Ellerman mtdcri(SDR0, PESDR0_460EX_PHY_CTL_RST,0x10000000);
974bfa9a2ebSMichael Ellerman break;
975bfa9a2ebSMichael Ellerman
976bfa9a2ebSMichael Ellerman case 1:
977bfa9a2ebSMichael Ellerman mtdcri(SDR0, PESDR1_460EX_L0CDRCTL, 0x00003230);
978bfa9a2ebSMichael Ellerman mtdcri(SDR0, PESDR1_460EX_L1CDRCTL, 0x00003230);
979bfa9a2ebSMichael Ellerman mtdcri(SDR0, PESDR1_460EX_L2CDRCTL, 0x00003230);
980bfa9a2ebSMichael Ellerman mtdcri(SDR0, PESDR1_460EX_L3CDRCTL, 0x00003230);
981bfa9a2ebSMichael Ellerman mtdcri(SDR0, PESDR1_460EX_L0DRV, 0x00000130);
982bfa9a2ebSMichael Ellerman mtdcri(SDR0, PESDR1_460EX_L1DRV, 0x00000130);
983bfa9a2ebSMichael Ellerman mtdcri(SDR0, PESDR1_460EX_L2DRV, 0x00000130);
984bfa9a2ebSMichael Ellerman mtdcri(SDR0, PESDR1_460EX_L3DRV, 0x00000130);
985bfa9a2ebSMichael Ellerman mtdcri(SDR0, PESDR1_460EX_L0CLK, 0x00000006);
986bfa9a2ebSMichael Ellerman mtdcri(SDR0, PESDR1_460EX_L1CLK, 0x00000006);
987bfa9a2ebSMichael Ellerman mtdcri(SDR0, PESDR1_460EX_L2CLK, 0x00000006);
988bfa9a2ebSMichael Ellerman mtdcri(SDR0, PESDR1_460EX_L3CLK, 0x00000006);
989bfa9a2ebSMichael Ellerman
990bfa9a2ebSMichael Ellerman mtdcri(SDR0, PESDR1_460EX_PHY_CTL_RST,0x10000000);
991bfa9a2ebSMichael Ellerman break;
992bfa9a2ebSMichael Ellerman }
993bfa9a2ebSMichael Ellerman
994bfa9a2ebSMichael Ellerman mtdcri(SDR0, port->sdr_base + PESDRn_RCSSET,
995bfa9a2ebSMichael Ellerman mfdcri(SDR0, port->sdr_base + PESDRn_RCSSET) |
996bfa9a2ebSMichael Ellerman (PESDRx_RCSSET_RSTGU | PESDRx_RCSSET_RSTPYN));
997bfa9a2ebSMichael Ellerman
998bfa9a2ebSMichael Ellerman /* Poll for PHY reset */
999bfa9a2ebSMichael Ellerman /* XXX FIXME add timeout */
1000bfa9a2ebSMichael Ellerman switch (port->index) {
1001bfa9a2ebSMichael Ellerman case 0:
1002bfa9a2ebSMichael Ellerman while (!(mfdcri(SDR0, PESDR0_460EX_RSTSTA) & 0x1))
1003bfa9a2ebSMichael Ellerman udelay(10);
1004bfa9a2ebSMichael Ellerman break;
1005bfa9a2ebSMichael Ellerman case 1:
1006bfa9a2ebSMichael Ellerman while (!(mfdcri(SDR0, PESDR1_460EX_RSTSTA) & 0x1))
1007bfa9a2ebSMichael Ellerman udelay(10);
1008bfa9a2ebSMichael Ellerman break;
1009bfa9a2ebSMichael Ellerman }
1010bfa9a2ebSMichael Ellerman
1011bfa9a2ebSMichael Ellerman mtdcri(SDR0, port->sdr_base + PESDRn_RCSSET,
1012bfa9a2ebSMichael Ellerman (mfdcri(SDR0, port->sdr_base + PESDRn_RCSSET) &
1013bfa9a2ebSMichael Ellerman ~(PESDRx_RCSSET_RSTGU | PESDRx_RCSSET_RSTDL)) |
1014bfa9a2ebSMichael Ellerman PESDRx_RCSSET_RSTPYN);
1015bfa9a2ebSMichael Ellerman
1016bfa9a2ebSMichael Ellerman port->has_ibpre = 1;
1017bfa9a2ebSMichael Ellerman
1018bfa9a2ebSMichael Ellerman return ppc4xx_pciex_port_reset_sdr(port);
1019bfa9a2ebSMichael Ellerman }
1020bfa9a2ebSMichael Ellerman
ppc460ex_pciex_init_utl(struct ppc4xx_pciex_port * port)1021bfa9a2ebSMichael Ellerman static int ppc460ex_pciex_init_utl(struct ppc4xx_pciex_port *port)
1022bfa9a2ebSMichael Ellerman {
1023bfa9a2ebSMichael Ellerman dcr_write(port->dcrs, DCRO_PEGPL_SPECIAL, 0x0);
1024bfa9a2ebSMichael Ellerman
1025bfa9a2ebSMichael Ellerman /*
1026bfa9a2ebSMichael Ellerman * Set buffer allocations and then assert VRB and TXE.
1027bfa9a2ebSMichael Ellerman */
1028bfa9a2ebSMichael Ellerman out_be32(port->utl_base + PEUTL_PBCTL, 0x0800000c);
1029bfa9a2ebSMichael Ellerman out_be32(port->utl_base + PEUTL_OUTTR, 0x08000000);
1030bfa9a2ebSMichael Ellerman out_be32(port->utl_base + PEUTL_INTR, 0x02000000);
1031bfa9a2ebSMichael Ellerman out_be32(port->utl_base + PEUTL_OPDBSZ, 0x04000000);
1032bfa9a2ebSMichael Ellerman out_be32(port->utl_base + PEUTL_PBBSZ, 0x00000000);
1033bfa9a2ebSMichael Ellerman out_be32(port->utl_base + PEUTL_IPHBSZ, 0x02000000);
1034bfa9a2ebSMichael Ellerman out_be32(port->utl_base + PEUTL_IPDBSZ, 0x04000000);
1035bfa9a2ebSMichael Ellerman out_be32(port->utl_base + PEUTL_RCIRQEN,0x00f00000);
1036bfa9a2ebSMichael Ellerman out_be32(port->utl_base + PEUTL_PCTL, 0x80800066);
1037bfa9a2ebSMichael Ellerman
1038bfa9a2ebSMichael Ellerman return 0;
1039bfa9a2ebSMichael Ellerman }
1040bfa9a2ebSMichael Ellerman
1041bfa9a2ebSMichael Ellerman static struct ppc4xx_pciex_hwops ppc460ex_pcie_hwops __initdata =
1042bfa9a2ebSMichael Ellerman {
1043bfa9a2ebSMichael Ellerman .want_sdr = true,
1044bfa9a2ebSMichael Ellerman .core_init = ppc460ex_pciex_core_init,
1045bfa9a2ebSMichael Ellerman .port_init_hw = ppc460ex_pciex_init_port_hw,
1046bfa9a2ebSMichael Ellerman .setup_utl = ppc460ex_pciex_init_utl,
1047bfa9a2ebSMichael Ellerman .check_link = ppc4xx_pciex_check_link_sdr,
1048bfa9a2ebSMichael Ellerman };
1049bfa9a2ebSMichael Ellerman
apm821xx_pciex_core_init(struct device_node * np)1050bfa9a2ebSMichael Ellerman static int __init apm821xx_pciex_core_init(struct device_node *np)
1051bfa9a2ebSMichael Ellerman {
1052bfa9a2ebSMichael Ellerman /* Return the number of pcie port */
1053bfa9a2ebSMichael Ellerman return 1;
1054bfa9a2ebSMichael Ellerman }
1055bfa9a2ebSMichael Ellerman
apm821xx_pciex_init_port_hw(struct ppc4xx_pciex_port * port)1056bfa9a2ebSMichael Ellerman static int __init apm821xx_pciex_init_port_hw(struct ppc4xx_pciex_port *port)
1057bfa9a2ebSMichael Ellerman {
1058bfa9a2ebSMichael Ellerman u32 val;
1059bfa9a2ebSMichael Ellerman
1060bfa9a2ebSMichael Ellerman /*
1061bfa9a2ebSMichael Ellerman * Do a software reset on PCIe ports.
1062bfa9a2ebSMichael Ellerman * This code is to fix the issue that pci drivers doesn't re-assign
1063bfa9a2ebSMichael Ellerman * bus number for PCIE devices after Uboot
1064bfa9a2ebSMichael Ellerman * scanned and configured all the buses (eg. PCIE NIC IntelPro/1000
1065bfa9a2ebSMichael Ellerman * PT quad port, SAS LSI 1064E)
1066bfa9a2ebSMichael Ellerman */
1067bfa9a2ebSMichael Ellerman
1068bfa9a2ebSMichael Ellerman mtdcri(SDR0, PESDR0_460EX_PHY_CTL_RST, 0x0);
1069bfa9a2ebSMichael Ellerman mdelay(10);
1070bfa9a2ebSMichael Ellerman
1071bfa9a2ebSMichael Ellerman if (port->endpoint)
1072bfa9a2ebSMichael Ellerman val = PTYPE_LEGACY_ENDPOINT << 20;
1073bfa9a2ebSMichael Ellerman else
1074bfa9a2ebSMichael Ellerman val = PTYPE_ROOT_PORT << 20;
1075bfa9a2ebSMichael Ellerman
1076bfa9a2ebSMichael Ellerman val |= LNKW_X1 << 12;
1077bfa9a2ebSMichael Ellerman
1078bfa9a2ebSMichael Ellerman mtdcri(SDR0, port->sdr_base + PESDRn_DLPSET, val);
1079bfa9a2ebSMichael Ellerman mtdcri(SDR0, port->sdr_base + PESDRn_UTLSET1, 0x00000000);
1080bfa9a2ebSMichael Ellerman mtdcri(SDR0, port->sdr_base + PESDRn_UTLSET2, 0x01010000);
1081bfa9a2ebSMichael Ellerman
1082bfa9a2ebSMichael Ellerman mtdcri(SDR0, PESDR0_460EX_L0CDRCTL, 0x00003230);
1083bfa9a2ebSMichael Ellerman mtdcri(SDR0, PESDR0_460EX_L0DRV, 0x00000130);
1084bfa9a2ebSMichael Ellerman mtdcri(SDR0, PESDR0_460EX_L0CLK, 0x00000006);
1085bfa9a2ebSMichael Ellerman
1086bfa9a2ebSMichael Ellerman mtdcri(SDR0, PESDR0_460EX_PHY_CTL_RST, 0x10000000);
1087bfa9a2ebSMichael Ellerman mdelay(50);
1088bfa9a2ebSMichael Ellerman mtdcri(SDR0, PESDR0_460EX_PHY_CTL_RST, 0x30000000);
1089bfa9a2ebSMichael Ellerman
1090bfa9a2ebSMichael Ellerman mtdcri(SDR0, port->sdr_base + PESDRn_RCSSET,
1091bfa9a2ebSMichael Ellerman mfdcri(SDR0, port->sdr_base + PESDRn_RCSSET) |
1092bfa9a2ebSMichael Ellerman (PESDRx_RCSSET_RSTGU | PESDRx_RCSSET_RSTPYN));
1093bfa9a2ebSMichael Ellerman
1094bfa9a2ebSMichael Ellerman /* Poll for PHY reset */
1095bfa9a2ebSMichael Ellerman val = PESDR0_460EX_RSTSTA - port->sdr_base;
1096bfa9a2ebSMichael Ellerman if (ppc4xx_pciex_wait_on_sdr(port, val, 0x1, 1, 100)) {
1097bfa9a2ebSMichael Ellerman printk(KERN_WARNING "%s: PCIE: Can't reset PHY\n", __func__);
1098bfa9a2ebSMichael Ellerman return -EBUSY;
1099bfa9a2ebSMichael Ellerman } else {
1100bfa9a2ebSMichael Ellerman mtdcri(SDR0, port->sdr_base + PESDRn_RCSSET,
1101bfa9a2ebSMichael Ellerman (mfdcri(SDR0, port->sdr_base + PESDRn_RCSSET) &
1102bfa9a2ebSMichael Ellerman ~(PESDRx_RCSSET_RSTGU | PESDRx_RCSSET_RSTDL)) |
1103bfa9a2ebSMichael Ellerman PESDRx_RCSSET_RSTPYN);
1104bfa9a2ebSMichael Ellerman
1105bfa9a2ebSMichael Ellerman port->has_ibpre = 1;
1106bfa9a2ebSMichael Ellerman return 0;
1107bfa9a2ebSMichael Ellerman }
1108bfa9a2ebSMichael Ellerman }
1109bfa9a2ebSMichael Ellerman
1110bfa9a2ebSMichael Ellerman static struct ppc4xx_pciex_hwops apm821xx_pcie_hwops __initdata = {
1111bfa9a2ebSMichael Ellerman .want_sdr = true,
1112bfa9a2ebSMichael Ellerman .core_init = apm821xx_pciex_core_init,
1113bfa9a2ebSMichael Ellerman .port_init_hw = apm821xx_pciex_init_port_hw,
1114bfa9a2ebSMichael Ellerman .setup_utl = ppc460ex_pciex_init_utl,
1115bfa9a2ebSMichael Ellerman .check_link = ppc4xx_pciex_check_link_sdr,
1116bfa9a2ebSMichael Ellerman };
1117bfa9a2ebSMichael Ellerman
ppc460sx_pciex_core_init(struct device_node * np)1118bfa9a2ebSMichael Ellerman static int __init ppc460sx_pciex_core_init(struct device_node *np)
1119bfa9a2ebSMichael Ellerman {
1120bfa9a2ebSMichael Ellerman /* HSS drive amplitude */
1121bfa9a2ebSMichael Ellerman mtdcri(SDR0, PESDR0_460SX_HSSL0DAMP, 0xB9843211);
1122bfa9a2ebSMichael Ellerman mtdcri(SDR0, PESDR0_460SX_HSSL1DAMP, 0xB9843211);
1123bfa9a2ebSMichael Ellerman mtdcri(SDR0, PESDR0_460SX_HSSL2DAMP, 0xB9843211);
1124bfa9a2ebSMichael Ellerman mtdcri(SDR0, PESDR0_460SX_HSSL3DAMP, 0xB9843211);
1125bfa9a2ebSMichael Ellerman mtdcri(SDR0, PESDR0_460SX_HSSL4DAMP, 0xB9843211);
1126bfa9a2ebSMichael Ellerman mtdcri(SDR0, PESDR0_460SX_HSSL5DAMP, 0xB9843211);
1127bfa9a2ebSMichael Ellerman mtdcri(SDR0, PESDR0_460SX_HSSL6DAMP, 0xB9843211);
1128bfa9a2ebSMichael Ellerman mtdcri(SDR0, PESDR0_460SX_HSSL7DAMP, 0xB9843211);
1129bfa9a2ebSMichael Ellerman
1130bfa9a2ebSMichael Ellerman mtdcri(SDR0, PESDR1_460SX_HSSL0DAMP, 0xB9843211);
1131bfa9a2ebSMichael Ellerman mtdcri(SDR0, PESDR1_460SX_HSSL1DAMP, 0xB9843211);
1132bfa9a2ebSMichael Ellerman mtdcri(SDR0, PESDR1_460SX_HSSL2DAMP, 0xB9843211);
1133bfa9a2ebSMichael Ellerman mtdcri(SDR0, PESDR1_460SX_HSSL3DAMP, 0xB9843211);
1134bfa9a2ebSMichael Ellerman
1135bfa9a2ebSMichael Ellerman mtdcri(SDR0, PESDR2_460SX_HSSL0DAMP, 0xB9843211);
1136bfa9a2ebSMichael Ellerman mtdcri(SDR0, PESDR2_460SX_HSSL1DAMP, 0xB9843211);
1137bfa9a2ebSMichael Ellerman mtdcri(SDR0, PESDR2_460SX_HSSL2DAMP, 0xB9843211);
1138bfa9a2ebSMichael Ellerman mtdcri(SDR0, PESDR2_460SX_HSSL3DAMP, 0xB9843211);
1139bfa9a2ebSMichael Ellerman
1140bfa9a2ebSMichael Ellerman /* HSS TX pre-emphasis */
1141bfa9a2ebSMichael Ellerman mtdcri(SDR0, PESDR0_460SX_HSSL0COEFA, 0xDCB98987);
1142bfa9a2ebSMichael Ellerman mtdcri(SDR0, PESDR0_460SX_HSSL1COEFA, 0xDCB98987);
1143bfa9a2ebSMichael Ellerman mtdcri(SDR0, PESDR0_460SX_HSSL2COEFA, 0xDCB98987);
1144bfa9a2ebSMichael Ellerman mtdcri(SDR0, PESDR0_460SX_HSSL3COEFA, 0xDCB98987);
1145bfa9a2ebSMichael Ellerman mtdcri(SDR0, PESDR0_460SX_HSSL4COEFA, 0xDCB98987);
1146bfa9a2ebSMichael Ellerman mtdcri(SDR0, PESDR0_460SX_HSSL5COEFA, 0xDCB98987);
1147bfa9a2ebSMichael Ellerman mtdcri(SDR0, PESDR0_460SX_HSSL6COEFA, 0xDCB98987);
1148bfa9a2ebSMichael Ellerman mtdcri(SDR0, PESDR0_460SX_HSSL7COEFA, 0xDCB98987);
1149bfa9a2ebSMichael Ellerman
1150bfa9a2ebSMichael Ellerman mtdcri(SDR0, PESDR1_460SX_HSSL0COEFA, 0xDCB98987);
1151bfa9a2ebSMichael Ellerman mtdcri(SDR0, PESDR1_460SX_HSSL1COEFA, 0xDCB98987);
1152bfa9a2ebSMichael Ellerman mtdcri(SDR0, PESDR1_460SX_HSSL2COEFA, 0xDCB98987);
1153bfa9a2ebSMichael Ellerman mtdcri(SDR0, PESDR1_460SX_HSSL3COEFA, 0xDCB98987);
1154bfa9a2ebSMichael Ellerman
1155bfa9a2ebSMichael Ellerman mtdcri(SDR0, PESDR2_460SX_HSSL0COEFA, 0xDCB98987);
1156bfa9a2ebSMichael Ellerman mtdcri(SDR0, PESDR2_460SX_HSSL1COEFA, 0xDCB98987);
1157bfa9a2ebSMichael Ellerman mtdcri(SDR0, PESDR2_460SX_HSSL2COEFA, 0xDCB98987);
1158bfa9a2ebSMichael Ellerman mtdcri(SDR0, PESDR2_460SX_HSSL3COEFA, 0xDCB98987);
1159bfa9a2ebSMichael Ellerman
1160bfa9a2ebSMichael Ellerman /* HSS TX calibration control */
1161bfa9a2ebSMichael Ellerman mtdcri(SDR0, PESDR0_460SX_HSSL1CALDRV, 0x22222222);
1162bfa9a2ebSMichael Ellerman mtdcri(SDR0, PESDR1_460SX_HSSL1CALDRV, 0x22220000);
1163bfa9a2ebSMichael Ellerman mtdcri(SDR0, PESDR2_460SX_HSSL1CALDRV, 0x22220000);
1164bfa9a2ebSMichael Ellerman
1165bfa9a2ebSMichael Ellerman /* HSS TX slew control */
1166bfa9a2ebSMichael Ellerman mtdcri(SDR0, PESDR0_460SX_HSSSLEW, 0xFFFFFFFF);
1167bfa9a2ebSMichael Ellerman mtdcri(SDR0, PESDR1_460SX_HSSSLEW, 0xFFFF0000);
1168bfa9a2ebSMichael Ellerman mtdcri(SDR0, PESDR2_460SX_HSSSLEW, 0xFFFF0000);
1169bfa9a2ebSMichael Ellerman
1170bfa9a2ebSMichael Ellerman /* Set HSS PRBS enabled */
1171bfa9a2ebSMichael Ellerman mtdcri(SDR0, PESDR0_460SX_HSSCTLSET, 0x00001130);
1172bfa9a2ebSMichael Ellerman mtdcri(SDR0, PESDR2_460SX_HSSCTLSET, 0x00001130);
1173bfa9a2ebSMichael Ellerman
1174bfa9a2ebSMichael Ellerman udelay(100);
1175bfa9a2ebSMichael Ellerman
1176bfa9a2ebSMichael Ellerman /* De-assert PLLRESET */
1177bfa9a2ebSMichael Ellerman dcri_clrset(SDR0, PESDR0_PLLLCT2, 0x00000100, 0);
1178bfa9a2ebSMichael Ellerman
1179bfa9a2ebSMichael Ellerman /* Reset DL, UTL, GPL before configuration */
1180bfa9a2ebSMichael Ellerman mtdcri(SDR0, PESDR0_460SX_RCSSET,
1181bfa9a2ebSMichael Ellerman PESDRx_RCSSET_RSTDL | PESDRx_RCSSET_RSTGU);
1182bfa9a2ebSMichael Ellerman mtdcri(SDR0, PESDR1_460SX_RCSSET,
1183bfa9a2ebSMichael Ellerman PESDRx_RCSSET_RSTDL | PESDRx_RCSSET_RSTGU);
1184bfa9a2ebSMichael Ellerman mtdcri(SDR0, PESDR2_460SX_RCSSET,
1185bfa9a2ebSMichael Ellerman PESDRx_RCSSET_RSTDL | PESDRx_RCSSET_RSTGU);
1186bfa9a2ebSMichael Ellerman
1187bfa9a2ebSMichael Ellerman udelay(100);
1188bfa9a2ebSMichael Ellerman
1189bfa9a2ebSMichael Ellerman /*
1190bfa9a2ebSMichael Ellerman * If bifurcation is not enabled, u-boot would have disabled the
1191bfa9a2ebSMichael Ellerman * third PCIe port
1192bfa9a2ebSMichael Ellerman */
1193bfa9a2ebSMichael Ellerman if (((mfdcri(SDR0, PESDR1_460SX_HSSCTLSET) & 0x00000001) ==
1194bfa9a2ebSMichael Ellerman 0x00000001)) {
1195bfa9a2ebSMichael Ellerman printk(KERN_INFO "PCI: PCIE bifurcation setup successfully.\n");
1196bfa9a2ebSMichael Ellerman printk(KERN_INFO "PCI: Total 3 PCIE ports are present\n");
1197bfa9a2ebSMichael Ellerman return 3;
1198bfa9a2ebSMichael Ellerman }
1199bfa9a2ebSMichael Ellerman
1200bfa9a2ebSMichael Ellerman printk(KERN_INFO "PCI: Total 2 PCIE ports are present\n");
1201bfa9a2ebSMichael Ellerman return 2;
1202bfa9a2ebSMichael Ellerman }
1203bfa9a2ebSMichael Ellerman
ppc460sx_pciex_init_port_hw(struct ppc4xx_pciex_port * port)1204bfa9a2ebSMichael Ellerman static int __init ppc460sx_pciex_init_port_hw(struct ppc4xx_pciex_port *port)
1205bfa9a2ebSMichael Ellerman {
1206bfa9a2ebSMichael Ellerman
1207bfa9a2ebSMichael Ellerman if (port->endpoint)
1208bfa9a2ebSMichael Ellerman dcri_clrset(SDR0, port->sdr_base + PESDRn_UTLSET2,
1209bfa9a2ebSMichael Ellerman 0x01000000, 0);
1210bfa9a2ebSMichael Ellerman else
1211bfa9a2ebSMichael Ellerman dcri_clrset(SDR0, port->sdr_base + PESDRn_UTLSET2,
1212bfa9a2ebSMichael Ellerman 0, 0x01000000);
1213bfa9a2ebSMichael Ellerman
1214bfa9a2ebSMichael Ellerman dcri_clrset(SDR0, port->sdr_base + PESDRn_RCSSET,
1215bfa9a2ebSMichael Ellerman (PESDRx_RCSSET_RSTGU | PESDRx_RCSSET_RSTDL),
1216bfa9a2ebSMichael Ellerman PESDRx_RCSSET_RSTPYN);
1217bfa9a2ebSMichael Ellerman
1218bfa9a2ebSMichael Ellerman port->has_ibpre = 1;
1219bfa9a2ebSMichael Ellerman
1220bfa9a2ebSMichael Ellerman return ppc4xx_pciex_port_reset_sdr(port);
1221bfa9a2ebSMichael Ellerman }
1222bfa9a2ebSMichael Ellerman
ppc460sx_pciex_init_utl(struct ppc4xx_pciex_port * port)1223bfa9a2ebSMichael Ellerman static int ppc460sx_pciex_init_utl(struct ppc4xx_pciex_port *port)
1224bfa9a2ebSMichael Ellerman {
1225bfa9a2ebSMichael Ellerman /* Max 128 Bytes */
1226bfa9a2ebSMichael Ellerman out_be32 (port->utl_base + PEUTL_PBBSZ, 0x00000000);
1227bfa9a2ebSMichael Ellerman /* Assert VRB and TXE - per datasheet turn off addr validation */
1228bfa9a2ebSMichael Ellerman out_be32(port->utl_base + PEUTL_PCTL, 0x80800000);
1229bfa9a2ebSMichael Ellerman return 0;
1230bfa9a2ebSMichael Ellerman }
1231bfa9a2ebSMichael Ellerman
ppc460sx_pciex_check_link(struct ppc4xx_pciex_port * port)1232bfa9a2ebSMichael Ellerman static void __init ppc460sx_pciex_check_link(struct ppc4xx_pciex_port *port)
1233bfa9a2ebSMichael Ellerman {
1234bfa9a2ebSMichael Ellerman void __iomem *mbase;
1235bfa9a2ebSMichael Ellerman int attempt = 50;
1236bfa9a2ebSMichael Ellerman
1237bfa9a2ebSMichael Ellerman port->link = 0;
1238bfa9a2ebSMichael Ellerman
1239bfa9a2ebSMichael Ellerman mbase = ioremap(port->cfg_space.start + 0x10000000, 0x1000);
1240bfa9a2ebSMichael Ellerman if (mbase == NULL) {
1241b7c670d6SRob Herring printk(KERN_ERR "%pOF: Can't map internal config space !",
1242b7c670d6SRob Herring port->node);
1243bcec081eShuhai return;
1244bfa9a2ebSMichael Ellerman }
1245bfa9a2ebSMichael Ellerman
1246bfa9a2ebSMichael Ellerman while (attempt && (0 == (in_le32(mbase + PECFG_460SX_DLLSTA)
1247bfa9a2ebSMichael Ellerman & PECFG_460SX_DLLSTA_LINKUP))) {
1248bfa9a2ebSMichael Ellerman attempt--;
1249bfa9a2ebSMichael Ellerman mdelay(10);
1250bfa9a2ebSMichael Ellerman }
1251bfa9a2ebSMichael Ellerman if (attempt)
1252bfa9a2ebSMichael Ellerman port->link = 1;
1253bfa9a2ebSMichael Ellerman iounmap(mbase);
1254bfa9a2ebSMichael Ellerman }
1255bfa9a2ebSMichael Ellerman
1256bfa9a2ebSMichael Ellerman static struct ppc4xx_pciex_hwops ppc460sx_pcie_hwops __initdata = {
1257bfa9a2ebSMichael Ellerman .want_sdr = true,
1258bfa9a2ebSMichael Ellerman .core_init = ppc460sx_pciex_core_init,
1259bfa9a2ebSMichael Ellerman .port_init_hw = ppc460sx_pciex_init_port_hw,
1260bfa9a2ebSMichael Ellerman .setup_utl = ppc460sx_pciex_init_utl,
1261bfa9a2ebSMichael Ellerman .check_link = ppc460sx_pciex_check_link,
1262bfa9a2ebSMichael Ellerman };
1263bfa9a2ebSMichael Ellerman
1264bfa9a2ebSMichael Ellerman #endif /* CONFIG_44x */
1265bfa9a2ebSMichael Ellerman
1266bfa9a2ebSMichael Ellerman #ifdef CONFIG_40x
1267bfa9a2ebSMichael Ellerman
ppc405ex_pciex_core_init(struct device_node * np)1268bfa9a2ebSMichael Ellerman static int __init ppc405ex_pciex_core_init(struct device_node *np)
1269bfa9a2ebSMichael Ellerman {
1270bfa9a2ebSMichael Ellerman /* Nothing to do, return 2 ports */
1271bfa9a2ebSMichael Ellerman return 2;
1272bfa9a2ebSMichael Ellerman }
1273bfa9a2ebSMichael Ellerman
ppc405ex_pcie_phy_reset(struct ppc4xx_pciex_port * port)12741e3d992dSNick Child static void __init ppc405ex_pcie_phy_reset(struct ppc4xx_pciex_port *port)
1275bfa9a2ebSMichael Ellerman {
1276bfa9a2ebSMichael Ellerman /* Assert the PE0_PHY reset */
1277bfa9a2ebSMichael Ellerman mtdcri(SDR0, port->sdr_base + PESDRn_RCSSET, 0x01010000);
1278bfa9a2ebSMichael Ellerman msleep(1);
1279bfa9a2ebSMichael Ellerman
1280bfa9a2ebSMichael Ellerman /* deassert the PE0_hotreset */
1281bfa9a2ebSMichael Ellerman if (port->endpoint)
1282bfa9a2ebSMichael Ellerman mtdcri(SDR0, port->sdr_base + PESDRn_RCSSET, 0x01111000);
1283bfa9a2ebSMichael Ellerman else
1284bfa9a2ebSMichael Ellerman mtdcri(SDR0, port->sdr_base + PESDRn_RCSSET, 0x01101000);
1285bfa9a2ebSMichael Ellerman
1286bfa9a2ebSMichael Ellerman /* poll for phy !reset */
1287bfa9a2ebSMichael Ellerman /* XXX FIXME add timeout */
1288bfa9a2ebSMichael Ellerman while (!(mfdcri(SDR0, port->sdr_base + PESDRn_405EX_PHYSTA) & 0x00001000))
1289bfa9a2ebSMichael Ellerman ;
1290bfa9a2ebSMichael Ellerman
1291bfa9a2ebSMichael Ellerman /* deassert the PE0_gpl_utl_reset */
1292bfa9a2ebSMichael Ellerman mtdcri(SDR0, port->sdr_base + PESDRn_RCSSET, 0x00101000);
1293bfa9a2ebSMichael Ellerman }
1294bfa9a2ebSMichael Ellerman
ppc405ex_pciex_init_port_hw(struct ppc4xx_pciex_port * port)1295bfa9a2ebSMichael Ellerman static int __init ppc405ex_pciex_init_port_hw(struct ppc4xx_pciex_port *port)
1296bfa9a2ebSMichael Ellerman {
1297bfa9a2ebSMichael Ellerman u32 val;
1298bfa9a2ebSMichael Ellerman
1299bfa9a2ebSMichael Ellerman if (port->endpoint)
1300bfa9a2ebSMichael Ellerman val = PTYPE_LEGACY_ENDPOINT;
1301bfa9a2ebSMichael Ellerman else
1302bfa9a2ebSMichael Ellerman val = PTYPE_ROOT_PORT;
1303bfa9a2ebSMichael Ellerman
1304bfa9a2ebSMichael Ellerman mtdcri(SDR0, port->sdr_base + PESDRn_DLPSET,
1305bfa9a2ebSMichael Ellerman 1 << 24 | val << 20 | LNKW_X1 << 12);
1306bfa9a2ebSMichael Ellerman
1307bfa9a2ebSMichael Ellerman mtdcri(SDR0, port->sdr_base + PESDRn_UTLSET1, 0x00000000);
1308bfa9a2ebSMichael Ellerman mtdcri(SDR0, port->sdr_base + PESDRn_UTLSET2, 0x01010000);
1309bfa9a2ebSMichael Ellerman mtdcri(SDR0, port->sdr_base + PESDRn_405EX_PHYSET1, 0x720F0000);
1310bfa9a2ebSMichael Ellerman mtdcri(SDR0, port->sdr_base + PESDRn_405EX_PHYSET2, 0x70600003);
1311bfa9a2ebSMichael Ellerman
1312bfa9a2ebSMichael Ellerman /*
1313bfa9a2ebSMichael Ellerman * Only reset the PHY when no link is currently established.
1314bfa9a2ebSMichael Ellerman * This is for the Atheros PCIe board which has problems to establish
1315bfa9a2ebSMichael Ellerman * the link (again) after this PHY reset. All other currently tested
1316bfa9a2ebSMichael Ellerman * PCIe boards don't show this problem.
1317bfa9a2ebSMichael Ellerman * This has to be re-tested and fixed in a later release!
1318bfa9a2ebSMichael Ellerman */
1319bfa9a2ebSMichael Ellerman val = mfdcri(SDR0, port->sdr_base + PESDRn_LOOP);
1320bfa9a2ebSMichael Ellerman if (!(val & 0x00001000))
1321bfa9a2ebSMichael Ellerman ppc405ex_pcie_phy_reset(port);
1322bfa9a2ebSMichael Ellerman
1323bfa9a2ebSMichael Ellerman dcr_write(port->dcrs, DCRO_PEGPL_CFG, 0x10000000); /* guarded on */
1324bfa9a2ebSMichael Ellerman
1325bfa9a2ebSMichael Ellerman port->has_ibpre = 1;
1326bfa9a2ebSMichael Ellerman
1327bfa9a2ebSMichael Ellerman return ppc4xx_pciex_port_reset_sdr(port);
1328bfa9a2ebSMichael Ellerman }
1329bfa9a2ebSMichael Ellerman
ppc405ex_pciex_init_utl(struct ppc4xx_pciex_port * port)1330bfa9a2ebSMichael Ellerman static int ppc405ex_pciex_init_utl(struct ppc4xx_pciex_port *port)
1331bfa9a2ebSMichael Ellerman {
1332bfa9a2ebSMichael Ellerman dcr_write(port->dcrs, DCRO_PEGPL_SPECIAL, 0x0);
1333bfa9a2ebSMichael Ellerman
1334bfa9a2ebSMichael Ellerman /*
1335bfa9a2ebSMichael Ellerman * Set buffer allocations and then assert VRB and TXE.
1336bfa9a2ebSMichael Ellerman */
1337bfa9a2ebSMichael Ellerman out_be32(port->utl_base + PEUTL_OUTTR, 0x02000000);
1338bfa9a2ebSMichael Ellerman out_be32(port->utl_base + PEUTL_INTR, 0x02000000);
1339bfa9a2ebSMichael Ellerman out_be32(port->utl_base + PEUTL_OPDBSZ, 0x04000000);
1340bfa9a2ebSMichael Ellerman out_be32(port->utl_base + PEUTL_PBBSZ, 0x21000000);
1341bfa9a2ebSMichael Ellerman out_be32(port->utl_base + PEUTL_IPHBSZ, 0x02000000);
1342bfa9a2ebSMichael Ellerman out_be32(port->utl_base + PEUTL_IPDBSZ, 0x04000000);
1343bfa9a2ebSMichael Ellerman out_be32(port->utl_base + PEUTL_RCIRQEN, 0x00f00000);
1344bfa9a2ebSMichael Ellerman out_be32(port->utl_base + PEUTL_PCTL, 0x80800066);
1345bfa9a2ebSMichael Ellerman
1346bfa9a2ebSMichael Ellerman out_be32(port->utl_base + PEUTL_PBCTL, 0x08000000);
1347bfa9a2ebSMichael Ellerman
1348bfa9a2ebSMichael Ellerman return 0;
1349bfa9a2ebSMichael Ellerman }
1350bfa9a2ebSMichael Ellerman
1351bfa9a2ebSMichael Ellerman static struct ppc4xx_pciex_hwops ppc405ex_pcie_hwops __initdata =
1352bfa9a2ebSMichael Ellerman {
1353bfa9a2ebSMichael Ellerman .want_sdr = true,
1354bfa9a2ebSMichael Ellerman .core_init = ppc405ex_pciex_core_init,
1355bfa9a2ebSMichael Ellerman .port_init_hw = ppc405ex_pciex_init_port_hw,
1356bfa9a2ebSMichael Ellerman .setup_utl = ppc405ex_pciex_init_utl,
1357bfa9a2ebSMichael Ellerman .check_link = ppc4xx_pciex_check_link_sdr,
1358bfa9a2ebSMichael Ellerman };
1359bfa9a2ebSMichael Ellerman
1360bfa9a2ebSMichael Ellerman #endif /* CONFIG_40x */
1361bfa9a2ebSMichael Ellerman
1362bfa9a2ebSMichael Ellerman #ifdef CONFIG_476FPE
ppc_476fpe_pciex_core_init(struct device_node * np)1363bfa9a2ebSMichael Ellerman static int __init ppc_476fpe_pciex_core_init(struct device_node *np)
1364bfa9a2ebSMichael Ellerman {
1365bfa9a2ebSMichael Ellerman return 4;
1366bfa9a2ebSMichael Ellerman }
1367bfa9a2ebSMichael Ellerman
ppc_476fpe_pciex_check_link(struct ppc4xx_pciex_port * port)1368bfa9a2ebSMichael Ellerman static void __init ppc_476fpe_pciex_check_link(struct ppc4xx_pciex_port *port)
1369bfa9a2ebSMichael Ellerman {
1370bfa9a2ebSMichael Ellerman u32 timeout_ms = 20;
1371bfa9a2ebSMichael Ellerman u32 val = 0, mask = (PECFG_TLDLP_LNKUP|PECFG_TLDLP_PRESENT);
1372bfa9a2ebSMichael Ellerman void __iomem *mbase = ioremap(port->cfg_space.start + 0x10000000,
1373bfa9a2ebSMichael Ellerman 0x1000);
1374bfa9a2ebSMichael Ellerman
1375bfa9a2ebSMichael Ellerman printk(KERN_INFO "PCIE%d: Checking link...\n", port->index);
1376bfa9a2ebSMichael Ellerman
1377bfa9a2ebSMichael Ellerman if (mbase == NULL) {
1378bfa9a2ebSMichael Ellerman printk(KERN_WARNING "PCIE%d: failed to get cfg space\n",
1379bfa9a2ebSMichael Ellerman port->index);
1380bfa9a2ebSMichael Ellerman return;
1381bfa9a2ebSMichael Ellerman }
1382bfa9a2ebSMichael Ellerman
1383bfa9a2ebSMichael Ellerman while (timeout_ms--) {
1384bfa9a2ebSMichael Ellerman val = in_le32(mbase + PECFG_TLDLP);
1385bfa9a2ebSMichael Ellerman
1386bfa9a2ebSMichael Ellerman if ((val & mask) == mask)
1387bfa9a2ebSMichael Ellerman break;
1388bfa9a2ebSMichael Ellerman msleep(10);
1389bfa9a2ebSMichael Ellerman }
1390bfa9a2ebSMichael Ellerman
1391bfa9a2ebSMichael Ellerman if (val & PECFG_TLDLP_PRESENT) {
1392bfa9a2ebSMichael Ellerman printk(KERN_INFO "PCIE%d: link is up !\n", port->index);
1393bfa9a2ebSMichael Ellerman port->link = 1;
1394bfa9a2ebSMichael Ellerman } else
1395bfa9a2ebSMichael Ellerman printk(KERN_WARNING "PCIE%d: Link up failed\n", port->index);
1396bfa9a2ebSMichael Ellerman
1397bfa9a2ebSMichael Ellerman iounmap(mbase);
1398bfa9a2ebSMichael Ellerman }
1399bfa9a2ebSMichael Ellerman
1400bfa9a2ebSMichael Ellerman static struct ppc4xx_pciex_hwops ppc_476fpe_pcie_hwops __initdata =
1401bfa9a2ebSMichael Ellerman {
1402bfa9a2ebSMichael Ellerman .core_init = ppc_476fpe_pciex_core_init,
1403bfa9a2ebSMichael Ellerman .check_link = ppc_476fpe_pciex_check_link,
1404bfa9a2ebSMichael Ellerman };
1405bfa9a2ebSMichael Ellerman #endif /* CONFIG_476FPE */
1406bfa9a2ebSMichael Ellerman
1407bfa9a2ebSMichael Ellerman /* Check that the core has been initied and if not, do it */
ppc4xx_pciex_check_core_init(struct device_node * np)1408bfa9a2ebSMichael Ellerman static int __init ppc4xx_pciex_check_core_init(struct device_node *np)
1409bfa9a2ebSMichael Ellerman {
1410bfa9a2ebSMichael Ellerman static int core_init;
1411bfa9a2ebSMichael Ellerman int count = -ENODEV;
1412bfa9a2ebSMichael Ellerman
1413bfa9a2ebSMichael Ellerman if (core_init++)
1414bfa9a2ebSMichael Ellerman return 0;
1415bfa9a2ebSMichael Ellerman
1416bfa9a2ebSMichael Ellerman #ifdef CONFIG_44x
1417bfa9a2ebSMichael Ellerman if (of_device_is_compatible(np, "ibm,plb-pciex-440spe")) {
1418bfa9a2ebSMichael Ellerman if (ppc440spe_revA())
1419bfa9a2ebSMichael Ellerman ppc4xx_pciex_hwops = &ppc440speA_pcie_hwops;
1420bfa9a2ebSMichael Ellerman else
1421bfa9a2ebSMichael Ellerman ppc4xx_pciex_hwops = &ppc440speB_pcie_hwops;
1422bfa9a2ebSMichael Ellerman }
1423bfa9a2ebSMichael Ellerman if (of_device_is_compatible(np, "ibm,plb-pciex-460ex"))
1424bfa9a2ebSMichael Ellerman ppc4xx_pciex_hwops = &ppc460ex_pcie_hwops;
1425bfa9a2ebSMichael Ellerman if (of_device_is_compatible(np, "ibm,plb-pciex-460sx"))
1426bfa9a2ebSMichael Ellerman ppc4xx_pciex_hwops = &ppc460sx_pcie_hwops;
1427bfa9a2ebSMichael Ellerman if (of_device_is_compatible(np, "ibm,plb-pciex-apm821xx"))
1428bfa9a2ebSMichael Ellerman ppc4xx_pciex_hwops = &apm821xx_pcie_hwops;
1429bfa9a2ebSMichael Ellerman #endif /* CONFIG_44x */
1430bfa9a2ebSMichael Ellerman #ifdef CONFIG_40x
1431bfa9a2ebSMichael Ellerman if (of_device_is_compatible(np, "ibm,plb-pciex-405ex"))
1432bfa9a2ebSMichael Ellerman ppc4xx_pciex_hwops = &ppc405ex_pcie_hwops;
1433bfa9a2ebSMichael Ellerman #endif
1434bfa9a2ebSMichael Ellerman #ifdef CONFIG_476FPE
1435bfa9a2ebSMichael Ellerman if (of_device_is_compatible(np, "ibm,plb-pciex-476fpe")
1436bfa9a2ebSMichael Ellerman || of_device_is_compatible(np, "ibm,plb-pciex-476gtr"))
1437bfa9a2ebSMichael Ellerman ppc4xx_pciex_hwops = &ppc_476fpe_pcie_hwops;
1438bfa9a2ebSMichael Ellerman #endif
1439bfa9a2ebSMichael Ellerman if (ppc4xx_pciex_hwops == NULL) {
1440b7c670d6SRob Herring printk(KERN_WARNING "PCIE: unknown host type %pOF\n", np);
1441bfa9a2ebSMichael Ellerman return -ENODEV;
1442bfa9a2ebSMichael Ellerman }
1443bfa9a2ebSMichael Ellerman
1444bfa9a2ebSMichael Ellerman count = ppc4xx_pciex_hwops->core_init(np);
1445bfa9a2ebSMichael Ellerman if (count > 0) {
1446bfa9a2ebSMichael Ellerman ppc4xx_pciex_ports =
14476396bb22SKees Cook kcalloc(count, sizeof(struct ppc4xx_pciex_port),
1448bfa9a2ebSMichael Ellerman GFP_KERNEL);
1449bfa9a2ebSMichael Ellerman if (ppc4xx_pciex_ports) {
1450bfa9a2ebSMichael Ellerman ppc4xx_pciex_port_count = count;
1451bfa9a2ebSMichael Ellerman return 0;
1452bfa9a2ebSMichael Ellerman }
1453bfa9a2ebSMichael Ellerman printk(KERN_WARNING "PCIE: failed to allocate ports array\n");
1454bfa9a2ebSMichael Ellerman return -ENOMEM;
1455bfa9a2ebSMichael Ellerman }
1456bfa9a2ebSMichael Ellerman return -ENODEV;
1457bfa9a2ebSMichael Ellerman }
1458bfa9a2ebSMichael Ellerman
ppc4xx_pciex_port_init_mapping(struct ppc4xx_pciex_port * port)1459bfa9a2ebSMichael Ellerman static void __init ppc4xx_pciex_port_init_mapping(struct ppc4xx_pciex_port *port)
1460bfa9a2ebSMichael Ellerman {
1461bfa9a2ebSMichael Ellerman /* We map PCI Express configuration based on the reg property */
1462bfa9a2ebSMichael Ellerman dcr_write(port->dcrs, DCRO_PEGPL_CFGBAH,
1463bfa9a2ebSMichael Ellerman RES_TO_U32_HIGH(port->cfg_space.start));
1464bfa9a2ebSMichael Ellerman dcr_write(port->dcrs, DCRO_PEGPL_CFGBAL,
1465bfa9a2ebSMichael Ellerman RES_TO_U32_LOW(port->cfg_space.start));
1466bfa9a2ebSMichael Ellerman
1467bfa9a2ebSMichael Ellerman /* XXX FIXME: Use size from reg property. For now, map 512M */
1468bfa9a2ebSMichael Ellerman dcr_write(port->dcrs, DCRO_PEGPL_CFGMSK, 0xe0000001);
1469bfa9a2ebSMichael Ellerman
1470bfa9a2ebSMichael Ellerman /* We map UTL registers based on the reg property */
1471bfa9a2ebSMichael Ellerman dcr_write(port->dcrs, DCRO_PEGPL_REGBAH,
1472bfa9a2ebSMichael Ellerman RES_TO_U32_HIGH(port->utl_regs.start));
1473bfa9a2ebSMichael Ellerman dcr_write(port->dcrs, DCRO_PEGPL_REGBAL,
1474bfa9a2ebSMichael Ellerman RES_TO_U32_LOW(port->utl_regs.start));
1475bfa9a2ebSMichael Ellerman
1476bfa9a2ebSMichael Ellerman /* XXX FIXME: Use size from reg property */
1477bfa9a2ebSMichael Ellerman dcr_write(port->dcrs, DCRO_PEGPL_REGMSK, 0x00007001);
1478bfa9a2ebSMichael Ellerman
1479bfa9a2ebSMichael Ellerman /* Disable all other outbound windows */
1480bfa9a2ebSMichael Ellerman dcr_write(port->dcrs, DCRO_PEGPL_OMR1MSKL, 0);
1481bfa9a2ebSMichael Ellerman dcr_write(port->dcrs, DCRO_PEGPL_OMR2MSKL, 0);
1482bfa9a2ebSMichael Ellerman dcr_write(port->dcrs, DCRO_PEGPL_OMR3MSKL, 0);
1483bfa9a2ebSMichael Ellerman dcr_write(port->dcrs, DCRO_PEGPL_MSGMSK, 0);
1484bfa9a2ebSMichael Ellerman }
1485bfa9a2ebSMichael Ellerman
ppc4xx_pciex_port_init(struct ppc4xx_pciex_port * port)1486bfa9a2ebSMichael Ellerman static int __init ppc4xx_pciex_port_init(struct ppc4xx_pciex_port *port)
1487bfa9a2ebSMichael Ellerman {
1488bfa9a2ebSMichael Ellerman int rc = 0;
1489bfa9a2ebSMichael Ellerman
1490bfa9a2ebSMichael Ellerman /* Init HW */
1491bfa9a2ebSMichael Ellerman if (ppc4xx_pciex_hwops->port_init_hw)
1492bfa9a2ebSMichael Ellerman rc = ppc4xx_pciex_hwops->port_init_hw(port);
1493bfa9a2ebSMichael Ellerman if (rc != 0)
1494bfa9a2ebSMichael Ellerman return rc;
1495bfa9a2ebSMichael Ellerman
1496bfa9a2ebSMichael Ellerman /*
1497bfa9a2ebSMichael Ellerman * Initialize mapping: disable all regions and configure
1498bfa9a2ebSMichael Ellerman * CFG and REG regions based on resources in the device tree
1499bfa9a2ebSMichael Ellerman */
1500bfa9a2ebSMichael Ellerman ppc4xx_pciex_port_init_mapping(port);
1501bfa9a2ebSMichael Ellerman
1502bfa9a2ebSMichael Ellerman if (ppc4xx_pciex_hwops->check_link)
1503bfa9a2ebSMichael Ellerman ppc4xx_pciex_hwops->check_link(port);
1504bfa9a2ebSMichael Ellerman
1505bfa9a2ebSMichael Ellerman /*
1506bfa9a2ebSMichael Ellerman * Map UTL
1507bfa9a2ebSMichael Ellerman */
1508bfa9a2ebSMichael Ellerman port->utl_base = ioremap(port->utl_regs.start, 0x100);
1509bfa9a2ebSMichael Ellerman BUG_ON(port->utl_base == NULL);
1510bfa9a2ebSMichael Ellerman
1511bfa9a2ebSMichael Ellerman /*
1512bfa9a2ebSMichael Ellerman * Setup UTL registers --BenH.
1513bfa9a2ebSMichael Ellerman */
1514bfa9a2ebSMichael Ellerman if (ppc4xx_pciex_hwops->setup_utl)
1515bfa9a2ebSMichael Ellerman ppc4xx_pciex_hwops->setup_utl(port);
1516bfa9a2ebSMichael Ellerman
1517bfa9a2ebSMichael Ellerman /*
1518bfa9a2ebSMichael Ellerman * Check for VC0 active or PLL Locked and assert RDY.
1519bfa9a2ebSMichael Ellerman */
1520bfa9a2ebSMichael Ellerman if (port->sdr_base) {
1521bfa9a2ebSMichael Ellerman if (of_device_is_compatible(port->node,
1522bfa9a2ebSMichael Ellerman "ibm,plb-pciex-460sx")){
1523bfa9a2ebSMichael Ellerman if (port->link && ppc4xx_pciex_wait_on_sdr(port,
1524bfa9a2ebSMichael Ellerman PESDRn_RCSSTS,
1525bfa9a2ebSMichael Ellerman 1 << 12, 1 << 12, 5000)) {
1526bfa9a2ebSMichael Ellerman printk(KERN_INFO "PCIE%d: PLL not locked\n",
1527bfa9a2ebSMichael Ellerman port->index);
1528bfa9a2ebSMichael Ellerman port->link = 0;
1529bfa9a2ebSMichael Ellerman }
1530bfa9a2ebSMichael Ellerman } else if (port->link &&
1531bfa9a2ebSMichael Ellerman ppc4xx_pciex_wait_on_sdr(port, PESDRn_RCSSTS,
1532bfa9a2ebSMichael Ellerman 1 << 16, 1 << 16, 5000)) {
1533bfa9a2ebSMichael Ellerman printk(KERN_INFO "PCIE%d: VC0 not active\n",
1534bfa9a2ebSMichael Ellerman port->index);
1535bfa9a2ebSMichael Ellerman port->link = 0;
1536bfa9a2ebSMichael Ellerman }
1537bfa9a2ebSMichael Ellerman
1538bfa9a2ebSMichael Ellerman dcri_clrset(SDR0, port->sdr_base + PESDRn_RCSSET, 0, 1 << 20);
1539bfa9a2ebSMichael Ellerman }
1540bfa9a2ebSMichael Ellerman
1541bfa9a2ebSMichael Ellerman msleep(100);
1542bfa9a2ebSMichael Ellerman
1543bfa9a2ebSMichael Ellerman return 0;
1544bfa9a2ebSMichael Ellerman }
1545bfa9a2ebSMichael Ellerman
ppc4xx_pciex_validate_bdf(struct ppc4xx_pciex_port * port,struct pci_bus * bus,unsigned int devfn)1546bfa9a2ebSMichael Ellerman static int ppc4xx_pciex_validate_bdf(struct ppc4xx_pciex_port *port,
1547bfa9a2ebSMichael Ellerman struct pci_bus *bus,
1548bfa9a2ebSMichael Ellerman unsigned int devfn)
1549bfa9a2ebSMichael Ellerman {
1550bfa9a2ebSMichael Ellerman static int message;
1551bfa9a2ebSMichael Ellerman
1552bfa9a2ebSMichael Ellerman /* Endpoint can not generate upstream(remote) config cycles */
1553bfa9a2ebSMichael Ellerman if (port->endpoint && bus->number != port->hose->first_busno)
1554bfa9a2ebSMichael Ellerman return PCIBIOS_DEVICE_NOT_FOUND;
1555bfa9a2ebSMichael Ellerman
1556bfa9a2ebSMichael Ellerman /* Check we are within the mapped range */
1557bfa9a2ebSMichael Ellerman if (bus->number > port->hose->last_busno) {
1558bfa9a2ebSMichael Ellerman if (!message) {
1559bfa9a2ebSMichael Ellerman printk(KERN_WARNING "Warning! Probing bus %u"
1560bfa9a2ebSMichael Ellerman " out of range !\n", bus->number);
1561bfa9a2ebSMichael Ellerman message++;
1562bfa9a2ebSMichael Ellerman }
1563bfa9a2ebSMichael Ellerman return PCIBIOS_DEVICE_NOT_FOUND;
1564bfa9a2ebSMichael Ellerman }
1565bfa9a2ebSMichael Ellerman
1566bfa9a2ebSMichael Ellerman /* The root complex has only one device / function */
1567bfa9a2ebSMichael Ellerman if (bus->number == port->hose->first_busno && devfn != 0)
1568bfa9a2ebSMichael Ellerman return PCIBIOS_DEVICE_NOT_FOUND;
1569bfa9a2ebSMichael Ellerman
1570bfa9a2ebSMichael Ellerman /* The other side of the RC has only one device as well */
1571bfa9a2ebSMichael Ellerman if (bus->number == (port->hose->first_busno + 1) &&
1572bfa9a2ebSMichael Ellerman PCI_SLOT(devfn) != 0)
1573bfa9a2ebSMichael Ellerman return PCIBIOS_DEVICE_NOT_FOUND;
1574bfa9a2ebSMichael Ellerman
1575bfa9a2ebSMichael Ellerman /* Check if we have a link */
1576bfa9a2ebSMichael Ellerman if ((bus->number != port->hose->first_busno) && !port->link)
1577bfa9a2ebSMichael Ellerman return PCIBIOS_DEVICE_NOT_FOUND;
1578bfa9a2ebSMichael Ellerman
1579bfa9a2ebSMichael Ellerman return 0;
1580bfa9a2ebSMichael Ellerman }
1581bfa9a2ebSMichael Ellerman
ppc4xx_pciex_get_config_base(struct ppc4xx_pciex_port * port,struct pci_bus * bus,unsigned int devfn)1582bfa9a2ebSMichael Ellerman static void __iomem *ppc4xx_pciex_get_config_base(struct ppc4xx_pciex_port *port,
1583bfa9a2ebSMichael Ellerman struct pci_bus *bus,
1584bfa9a2ebSMichael Ellerman unsigned int devfn)
1585bfa9a2ebSMichael Ellerman {
1586bfa9a2ebSMichael Ellerman int relbus;
1587bfa9a2ebSMichael Ellerman
1588bfa9a2ebSMichael Ellerman /* Remove the casts when we finally remove the stupid volatile
1589bfa9a2ebSMichael Ellerman * in struct pci_controller
1590bfa9a2ebSMichael Ellerman */
1591bfa9a2ebSMichael Ellerman if (bus->number == port->hose->first_busno)
1592bfa9a2ebSMichael Ellerman return (void __iomem *)port->hose->cfg_addr;
1593bfa9a2ebSMichael Ellerman
1594bfa9a2ebSMichael Ellerman relbus = bus->number - (port->hose->first_busno + 1);
1595bfa9a2ebSMichael Ellerman return (void __iomem *)port->hose->cfg_data +
1596bfa9a2ebSMichael Ellerman ((relbus << 20) | (devfn << 12));
1597bfa9a2ebSMichael Ellerman }
1598bfa9a2ebSMichael Ellerman
ppc4xx_pciex_read_config(struct pci_bus * bus,unsigned int devfn,int offset,int len,u32 * val)1599bfa9a2ebSMichael Ellerman static int ppc4xx_pciex_read_config(struct pci_bus *bus, unsigned int devfn,
1600bfa9a2ebSMichael Ellerman int offset, int len, u32 *val)
1601bfa9a2ebSMichael Ellerman {
1602bfa9a2ebSMichael Ellerman struct pci_controller *hose = pci_bus_to_host(bus);
1603bfa9a2ebSMichael Ellerman struct ppc4xx_pciex_port *port =
1604bfa9a2ebSMichael Ellerman &ppc4xx_pciex_ports[hose->indirect_type];
1605bfa9a2ebSMichael Ellerman void __iomem *addr;
1606bfa9a2ebSMichael Ellerman u32 gpl_cfg;
1607bfa9a2ebSMichael Ellerman
1608bfa9a2ebSMichael Ellerman BUG_ON(hose != port->hose);
1609bfa9a2ebSMichael Ellerman
1610bfa9a2ebSMichael Ellerman if (ppc4xx_pciex_validate_bdf(port, bus, devfn) != 0)
1611bfa9a2ebSMichael Ellerman return PCIBIOS_DEVICE_NOT_FOUND;
1612bfa9a2ebSMichael Ellerman
1613bfa9a2ebSMichael Ellerman addr = ppc4xx_pciex_get_config_base(port, bus, devfn);
1614bfa9a2ebSMichael Ellerman
1615bfa9a2ebSMichael Ellerman /*
1616bfa9a2ebSMichael Ellerman * Reading from configuration space of non-existing device can
1617bfa9a2ebSMichael Ellerman * generate transaction errors. For the read duration we suppress
1618bfa9a2ebSMichael Ellerman * assertion of machine check exceptions to avoid those.
1619bfa9a2ebSMichael Ellerman */
1620bfa9a2ebSMichael Ellerman gpl_cfg = dcr_read(port->dcrs, DCRO_PEGPL_CFG);
1621bfa9a2ebSMichael Ellerman dcr_write(port->dcrs, DCRO_PEGPL_CFG, gpl_cfg | GPL_DMER_MASK_DISA);
1622bfa9a2ebSMichael Ellerman
1623bfa9a2ebSMichael Ellerman /* Make sure no CRS is recorded */
1624bfa9a2ebSMichael Ellerman out_be32(port->utl_base + PEUTL_RCSTA, 0x00040000);
1625bfa9a2ebSMichael Ellerman
1626bfa9a2ebSMichael Ellerman switch (len) {
1627bfa9a2ebSMichael Ellerman case 1:
1628bfa9a2ebSMichael Ellerman *val = in_8((u8 *)(addr + offset));
1629bfa9a2ebSMichael Ellerman break;
1630bfa9a2ebSMichael Ellerman case 2:
1631bfa9a2ebSMichael Ellerman *val = in_le16((u16 *)(addr + offset));
1632bfa9a2ebSMichael Ellerman break;
1633bfa9a2ebSMichael Ellerman default:
1634bfa9a2ebSMichael Ellerman *val = in_le32((u32 *)(addr + offset));
1635bfa9a2ebSMichael Ellerman break;
1636bfa9a2ebSMichael Ellerman }
1637bfa9a2ebSMichael Ellerman
1638bfa9a2ebSMichael Ellerman pr_debug("pcie-config-read: bus=%3d [%3d..%3d] devfn=0x%04x"
1639bfa9a2ebSMichael Ellerman " offset=0x%04x len=%d, addr=0x%p val=0x%08x\n",
1640bfa9a2ebSMichael Ellerman bus->number, hose->first_busno, hose->last_busno,
1641bfa9a2ebSMichael Ellerman devfn, offset, len, addr + offset, *val);
1642bfa9a2ebSMichael Ellerman
1643bfa9a2ebSMichael Ellerman /* Check for CRS (440SPe rev B does that for us but heh ..) */
1644bfa9a2ebSMichael Ellerman if (in_be32(port->utl_base + PEUTL_RCSTA) & 0x00040000) {
1645bfa9a2ebSMichael Ellerman pr_debug("Got CRS !\n");
1646bfa9a2ebSMichael Ellerman if (len != 4 || offset != 0)
1647bfa9a2ebSMichael Ellerman return PCIBIOS_DEVICE_NOT_FOUND;
1648bfa9a2ebSMichael Ellerman *val = 0xffff0001;
1649bfa9a2ebSMichael Ellerman }
1650bfa9a2ebSMichael Ellerman
1651bfa9a2ebSMichael Ellerman dcr_write(port->dcrs, DCRO_PEGPL_CFG, gpl_cfg);
1652bfa9a2ebSMichael Ellerman
1653bfa9a2ebSMichael Ellerman return PCIBIOS_SUCCESSFUL;
1654bfa9a2ebSMichael Ellerman }
1655bfa9a2ebSMichael Ellerman
ppc4xx_pciex_write_config(struct pci_bus * bus,unsigned int devfn,int offset,int len,u32 val)1656bfa9a2ebSMichael Ellerman static int ppc4xx_pciex_write_config(struct pci_bus *bus, unsigned int devfn,
1657bfa9a2ebSMichael Ellerman int offset, int len, u32 val)
1658bfa9a2ebSMichael Ellerman {
1659bfa9a2ebSMichael Ellerman struct pci_controller *hose = pci_bus_to_host(bus);
1660bfa9a2ebSMichael Ellerman struct ppc4xx_pciex_port *port =
1661bfa9a2ebSMichael Ellerman &ppc4xx_pciex_ports[hose->indirect_type];
1662bfa9a2ebSMichael Ellerman void __iomem *addr;
1663bfa9a2ebSMichael Ellerman u32 gpl_cfg;
1664bfa9a2ebSMichael Ellerman
1665bfa9a2ebSMichael Ellerman if (ppc4xx_pciex_validate_bdf(port, bus, devfn) != 0)
1666bfa9a2ebSMichael Ellerman return PCIBIOS_DEVICE_NOT_FOUND;
1667bfa9a2ebSMichael Ellerman
1668bfa9a2ebSMichael Ellerman addr = ppc4xx_pciex_get_config_base(port, bus, devfn);
1669bfa9a2ebSMichael Ellerman
1670bfa9a2ebSMichael Ellerman /*
1671bfa9a2ebSMichael Ellerman * Reading from configuration space of non-existing device can
1672bfa9a2ebSMichael Ellerman * generate transaction errors. For the read duration we suppress
1673bfa9a2ebSMichael Ellerman * assertion of machine check exceptions to avoid those.
1674bfa9a2ebSMichael Ellerman */
1675bfa9a2ebSMichael Ellerman gpl_cfg = dcr_read(port->dcrs, DCRO_PEGPL_CFG);
1676bfa9a2ebSMichael Ellerman dcr_write(port->dcrs, DCRO_PEGPL_CFG, gpl_cfg | GPL_DMER_MASK_DISA);
1677bfa9a2ebSMichael Ellerman
1678bfa9a2ebSMichael Ellerman pr_debug("pcie-config-write: bus=%3d [%3d..%3d] devfn=0x%04x"
1679bfa9a2ebSMichael Ellerman " offset=0x%04x len=%d, addr=0x%p val=0x%08x\n",
1680bfa9a2ebSMichael Ellerman bus->number, hose->first_busno, hose->last_busno,
1681bfa9a2ebSMichael Ellerman devfn, offset, len, addr + offset, val);
1682bfa9a2ebSMichael Ellerman
1683bfa9a2ebSMichael Ellerman switch (len) {
1684bfa9a2ebSMichael Ellerman case 1:
1685bfa9a2ebSMichael Ellerman out_8((u8 *)(addr + offset), val);
1686bfa9a2ebSMichael Ellerman break;
1687bfa9a2ebSMichael Ellerman case 2:
1688bfa9a2ebSMichael Ellerman out_le16((u16 *)(addr + offset), val);
1689bfa9a2ebSMichael Ellerman break;
1690bfa9a2ebSMichael Ellerman default:
1691bfa9a2ebSMichael Ellerman out_le32((u32 *)(addr + offset), val);
1692bfa9a2ebSMichael Ellerman break;
1693bfa9a2ebSMichael Ellerman }
1694bfa9a2ebSMichael Ellerman
1695bfa9a2ebSMichael Ellerman dcr_write(port->dcrs, DCRO_PEGPL_CFG, gpl_cfg);
1696bfa9a2ebSMichael Ellerman
1697bfa9a2ebSMichael Ellerman return PCIBIOS_SUCCESSFUL;
1698bfa9a2ebSMichael Ellerman }
1699bfa9a2ebSMichael Ellerman
1700bfa9a2ebSMichael Ellerman static struct pci_ops ppc4xx_pciex_pci_ops =
1701bfa9a2ebSMichael Ellerman {
1702bfa9a2ebSMichael Ellerman .read = ppc4xx_pciex_read_config,
1703bfa9a2ebSMichael Ellerman .write = ppc4xx_pciex_write_config,
1704bfa9a2ebSMichael Ellerman };
1705bfa9a2ebSMichael Ellerman
ppc4xx_setup_one_pciex_POM(struct ppc4xx_pciex_port * port,struct pci_controller * hose,void __iomem * mbase,u64 plb_addr,u64 pci_addr,u64 size,unsigned int flags,int index)1706bfa9a2ebSMichael Ellerman static int __init ppc4xx_setup_one_pciex_POM(struct ppc4xx_pciex_port *port,
1707bfa9a2ebSMichael Ellerman struct pci_controller *hose,
1708bfa9a2ebSMichael Ellerman void __iomem *mbase,
1709bfa9a2ebSMichael Ellerman u64 plb_addr,
1710bfa9a2ebSMichael Ellerman u64 pci_addr,
1711bfa9a2ebSMichael Ellerman u64 size,
1712bfa9a2ebSMichael Ellerman unsigned int flags,
1713bfa9a2ebSMichael Ellerman int index)
1714bfa9a2ebSMichael Ellerman {
1715bfa9a2ebSMichael Ellerman u32 lah, lal, pciah, pcial, sa;
1716bfa9a2ebSMichael Ellerman
1717bfa9a2ebSMichael Ellerman if (!is_power_of_2(size) ||
1718bfa9a2ebSMichael Ellerman (index < 2 && size < 0x100000) ||
1719bfa9a2ebSMichael Ellerman (index == 2 && size < 0x100) ||
1720bfa9a2ebSMichael Ellerman (plb_addr & (size - 1)) != 0) {
1721b7c670d6SRob Herring printk(KERN_WARNING "%pOF: Resource out of range\n", hose->dn);
1722bfa9a2ebSMichael Ellerman return -1;
1723bfa9a2ebSMichael Ellerman }
1724bfa9a2ebSMichael Ellerman
1725bfa9a2ebSMichael Ellerman /* Calculate register values */
1726bfa9a2ebSMichael Ellerman lah = RES_TO_U32_HIGH(plb_addr);
1727bfa9a2ebSMichael Ellerman lal = RES_TO_U32_LOW(plb_addr);
1728bfa9a2ebSMichael Ellerman pciah = RES_TO_U32_HIGH(pci_addr);
1729bfa9a2ebSMichael Ellerman pcial = RES_TO_U32_LOW(pci_addr);
1730bfa9a2ebSMichael Ellerman sa = (0xffffffffu << ilog2(size)) | 0x1;
1731bfa9a2ebSMichael Ellerman
1732bfa9a2ebSMichael Ellerman /* Program register values */
1733bfa9a2ebSMichael Ellerman switch (index) {
1734bfa9a2ebSMichael Ellerman case 0:
1735bfa9a2ebSMichael Ellerman out_le32(mbase + PECFG_POM0LAH, pciah);
1736bfa9a2ebSMichael Ellerman out_le32(mbase + PECFG_POM0LAL, pcial);
1737bfa9a2ebSMichael Ellerman dcr_write(port->dcrs, DCRO_PEGPL_OMR1BAH, lah);
1738bfa9a2ebSMichael Ellerman dcr_write(port->dcrs, DCRO_PEGPL_OMR1BAL, lal);
1739bfa9a2ebSMichael Ellerman dcr_write(port->dcrs, DCRO_PEGPL_OMR1MSKH, 0x7fffffff);
1740bfa9a2ebSMichael Ellerman /*Enabled and single region */
1741bfa9a2ebSMichael Ellerman if (of_device_is_compatible(port->node, "ibm,plb-pciex-460sx"))
1742bfa9a2ebSMichael Ellerman dcr_write(port->dcrs, DCRO_PEGPL_OMR1MSKL,
1743bfa9a2ebSMichael Ellerman sa | DCRO_PEGPL_460SX_OMR1MSKL_UOT
1744bfa9a2ebSMichael Ellerman | DCRO_PEGPL_OMRxMSKL_VAL);
1745bfa9a2ebSMichael Ellerman else if (of_device_is_compatible(
1746bfa9a2ebSMichael Ellerman port->node, "ibm,plb-pciex-476fpe") ||
1747bfa9a2ebSMichael Ellerman of_device_is_compatible(
1748bfa9a2ebSMichael Ellerman port->node, "ibm,plb-pciex-476gtr"))
1749bfa9a2ebSMichael Ellerman dcr_write(port->dcrs, DCRO_PEGPL_OMR1MSKL,
1750bfa9a2ebSMichael Ellerman sa | DCRO_PEGPL_476FPE_OMR1MSKL_UOT
1751bfa9a2ebSMichael Ellerman | DCRO_PEGPL_OMRxMSKL_VAL);
1752bfa9a2ebSMichael Ellerman else
1753bfa9a2ebSMichael Ellerman dcr_write(port->dcrs, DCRO_PEGPL_OMR1MSKL,
1754bfa9a2ebSMichael Ellerman sa | DCRO_PEGPL_OMR1MSKL_UOT
1755bfa9a2ebSMichael Ellerman | DCRO_PEGPL_OMRxMSKL_VAL);
1756bfa9a2ebSMichael Ellerman break;
1757bfa9a2ebSMichael Ellerman case 1:
1758bfa9a2ebSMichael Ellerman out_le32(mbase + PECFG_POM1LAH, pciah);
1759bfa9a2ebSMichael Ellerman out_le32(mbase + PECFG_POM1LAL, pcial);
1760bfa9a2ebSMichael Ellerman dcr_write(port->dcrs, DCRO_PEGPL_OMR2BAH, lah);
1761bfa9a2ebSMichael Ellerman dcr_write(port->dcrs, DCRO_PEGPL_OMR2BAL, lal);
1762bfa9a2ebSMichael Ellerman dcr_write(port->dcrs, DCRO_PEGPL_OMR2MSKH, 0x7fffffff);
1763bfa9a2ebSMichael Ellerman dcr_write(port->dcrs, DCRO_PEGPL_OMR2MSKL,
1764bfa9a2ebSMichael Ellerman sa | DCRO_PEGPL_OMRxMSKL_VAL);
1765bfa9a2ebSMichael Ellerman break;
1766bfa9a2ebSMichael Ellerman case 2:
1767bfa9a2ebSMichael Ellerman out_le32(mbase + PECFG_POM2LAH, pciah);
1768bfa9a2ebSMichael Ellerman out_le32(mbase + PECFG_POM2LAL, pcial);
1769bfa9a2ebSMichael Ellerman dcr_write(port->dcrs, DCRO_PEGPL_OMR3BAH, lah);
1770bfa9a2ebSMichael Ellerman dcr_write(port->dcrs, DCRO_PEGPL_OMR3BAL, lal);
1771bfa9a2ebSMichael Ellerman dcr_write(port->dcrs, DCRO_PEGPL_OMR3MSKH, 0x7fffffff);
1772bfa9a2ebSMichael Ellerman /* Note that 3 here means enabled | IO space !!! */
1773bfa9a2ebSMichael Ellerman dcr_write(port->dcrs, DCRO_PEGPL_OMR3MSKL,
1774bfa9a2ebSMichael Ellerman sa | DCRO_PEGPL_OMR3MSKL_IO
1775bfa9a2ebSMichael Ellerman | DCRO_PEGPL_OMRxMSKL_VAL);
1776bfa9a2ebSMichael Ellerman break;
1777bfa9a2ebSMichael Ellerman }
1778bfa9a2ebSMichael Ellerman
1779bfa9a2ebSMichael Ellerman return 0;
1780bfa9a2ebSMichael Ellerman }
1781bfa9a2ebSMichael Ellerman
ppc4xx_configure_pciex_POMs(struct ppc4xx_pciex_port * port,struct pci_controller * hose,void __iomem * mbase)1782bfa9a2ebSMichael Ellerman static void __init ppc4xx_configure_pciex_POMs(struct ppc4xx_pciex_port *port,
1783bfa9a2ebSMichael Ellerman struct pci_controller *hose,
1784bfa9a2ebSMichael Ellerman void __iomem *mbase)
1785bfa9a2ebSMichael Ellerman {
1786bfa9a2ebSMichael Ellerman int i, j, found_isa_hole = 0;
1787bfa9a2ebSMichael Ellerman
1788bfa9a2ebSMichael Ellerman /* Setup outbound memory windows */
1789bfa9a2ebSMichael Ellerman for (i = j = 0; i < 3; i++) {
1790bfa9a2ebSMichael Ellerman struct resource *res = &hose->mem_resources[i];
1791bfa9a2ebSMichael Ellerman resource_size_t offset = hose->mem_offset[i];
1792bfa9a2ebSMichael Ellerman
1793bfa9a2ebSMichael Ellerman /* we only care about memory windows */
1794bfa9a2ebSMichael Ellerman if (!(res->flags & IORESOURCE_MEM))
1795bfa9a2ebSMichael Ellerman continue;
1796bfa9a2ebSMichael Ellerman if (j > 1) {
1797b7c670d6SRob Herring printk(KERN_WARNING "%pOF: Too many ranges\n",
1798b7c670d6SRob Herring port->node);
1799bfa9a2ebSMichael Ellerman break;
1800bfa9a2ebSMichael Ellerman }
1801bfa9a2ebSMichael Ellerman
1802bfa9a2ebSMichael Ellerman /* Configure the resource */
1803bfa9a2ebSMichael Ellerman if (ppc4xx_setup_one_pciex_POM(port, hose, mbase,
1804bfa9a2ebSMichael Ellerman res->start,
1805bfa9a2ebSMichael Ellerman res->start - offset,
1806bfa9a2ebSMichael Ellerman resource_size(res),
1807bfa9a2ebSMichael Ellerman res->flags,
1808bfa9a2ebSMichael Ellerman j) == 0) {
1809bfa9a2ebSMichael Ellerman j++;
1810bfa9a2ebSMichael Ellerman
1811bfa9a2ebSMichael Ellerman /* If the resource PCI address is 0 then we have our
1812bfa9a2ebSMichael Ellerman * ISA memory hole
1813bfa9a2ebSMichael Ellerman */
1814bfa9a2ebSMichael Ellerman if (res->start == offset)
1815bfa9a2ebSMichael Ellerman found_isa_hole = 1;
1816bfa9a2ebSMichael Ellerman }
1817bfa9a2ebSMichael Ellerman }
1818bfa9a2ebSMichael Ellerman
1819bfa9a2ebSMichael Ellerman /* Handle ISA memory hole if not already covered */
1820bfa9a2ebSMichael Ellerman if (j <= 1 && !found_isa_hole && hose->isa_mem_size)
1821bfa9a2ebSMichael Ellerman if (ppc4xx_setup_one_pciex_POM(port, hose, mbase,
1822bfa9a2ebSMichael Ellerman hose->isa_mem_phys, 0,
1823bfa9a2ebSMichael Ellerman hose->isa_mem_size, 0, j) == 0)
1824b7c670d6SRob Herring printk(KERN_INFO "%pOF: Legacy ISA memory support enabled\n",
1825b7c670d6SRob Herring hose->dn);
1826bfa9a2ebSMichael Ellerman
1827bfa9a2ebSMichael Ellerman /* Configure IO, always 64K starting at 0. We hard wire it to 64K !
1828bfa9a2ebSMichael Ellerman * Note also that it -has- to be region index 2 on this HW
1829bfa9a2ebSMichael Ellerman */
1830bfa9a2ebSMichael Ellerman if (hose->io_resource.flags & IORESOURCE_IO)
1831bfa9a2ebSMichael Ellerman ppc4xx_setup_one_pciex_POM(port, hose, mbase,
1832bfa9a2ebSMichael Ellerman hose->io_base_phys, 0,
1833bfa9a2ebSMichael Ellerman 0x10000, IORESOURCE_IO, 2);
1834bfa9a2ebSMichael Ellerman }
1835bfa9a2ebSMichael Ellerman
ppc4xx_configure_pciex_PIMs(struct ppc4xx_pciex_port * port,struct pci_controller * hose,void __iomem * mbase,struct resource * res)1836bfa9a2ebSMichael Ellerman static void __init ppc4xx_configure_pciex_PIMs(struct ppc4xx_pciex_port *port,
1837bfa9a2ebSMichael Ellerman struct pci_controller *hose,
1838bfa9a2ebSMichael Ellerman void __iomem *mbase,
1839bfa9a2ebSMichael Ellerman struct resource *res)
1840bfa9a2ebSMichael Ellerman {
1841bfa9a2ebSMichael Ellerman resource_size_t size = resource_size(res);
1842bfa9a2ebSMichael Ellerman u64 sa;
1843bfa9a2ebSMichael Ellerman
1844bfa9a2ebSMichael Ellerman if (port->endpoint) {
1845bfa9a2ebSMichael Ellerman resource_size_t ep_addr = 0;
1846bfa9a2ebSMichael Ellerman resource_size_t ep_size = 32 << 20;
1847bfa9a2ebSMichael Ellerman
1848bfa9a2ebSMichael Ellerman /* Currently we map a fixed 64MByte window to PLB address
1849bfa9a2ebSMichael Ellerman * 0 (SDRAM). This should probably be configurable via a dts
1850bfa9a2ebSMichael Ellerman * property.
1851bfa9a2ebSMichael Ellerman */
1852bfa9a2ebSMichael Ellerman
1853bfa9a2ebSMichael Ellerman /* Calculate window size */
1854bfa9a2ebSMichael Ellerman sa = (0xffffffffffffffffull << ilog2(ep_size));
1855bfa9a2ebSMichael Ellerman
1856bfa9a2ebSMichael Ellerman /* Setup BAR0 */
1857bfa9a2ebSMichael Ellerman out_le32(mbase + PECFG_BAR0HMPA, RES_TO_U32_HIGH(sa));
1858bfa9a2ebSMichael Ellerman out_le32(mbase + PECFG_BAR0LMPA, RES_TO_U32_LOW(sa) |
1859bfa9a2ebSMichael Ellerman PCI_BASE_ADDRESS_MEM_TYPE_64);
1860bfa9a2ebSMichael Ellerman
1861bfa9a2ebSMichael Ellerman /* Disable BAR1 & BAR2 */
1862bfa9a2ebSMichael Ellerman out_le32(mbase + PECFG_BAR1MPA, 0);
1863bfa9a2ebSMichael Ellerman out_le32(mbase + PECFG_BAR2HMPA, 0);
1864bfa9a2ebSMichael Ellerman out_le32(mbase + PECFG_BAR2LMPA, 0);
1865bfa9a2ebSMichael Ellerman
1866bfa9a2ebSMichael Ellerman out_le32(mbase + PECFG_PIM01SAH, RES_TO_U32_HIGH(sa));
1867bfa9a2ebSMichael Ellerman out_le32(mbase + PECFG_PIM01SAL, RES_TO_U32_LOW(sa));
1868bfa9a2ebSMichael Ellerman
1869bfa9a2ebSMichael Ellerman out_le32(mbase + PCI_BASE_ADDRESS_0, RES_TO_U32_LOW(ep_addr));
1870bfa9a2ebSMichael Ellerman out_le32(mbase + PCI_BASE_ADDRESS_1, RES_TO_U32_HIGH(ep_addr));
1871bfa9a2ebSMichael Ellerman } else {
1872bfa9a2ebSMichael Ellerman /* Calculate window size */
1873bfa9a2ebSMichael Ellerman sa = (0xffffffffffffffffull << ilog2(size));
1874bfa9a2ebSMichael Ellerman if (res->flags & IORESOURCE_PREFETCH)
1875bfa9a2ebSMichael Ellerman sa |= PCI_BASE_ADDRESS_MEM_PREFETCH;
1876bfa9a2ebSMichael Ellerman
1877bfa9a2ebSMichael Ellerman if (of_device_is_compatible(port->node, "ibm,plb-pciex-460sx") ||
1878bfa9a2ebSMichael Ellerman of_device_is_compatible(
1879bfa9a2ebSMichael Ellerman port->node, "ibm,plb-pciex-476fpe") ||
1880bfa9a2ebSMichael Ellerman of_device_is_compatible(
1881bfa9a2ebSMichael Ellerman port->node, "ibm,plb-pciex-476gtr"))
1882bfa9a2ebSMichael Ellerman sa |= PCI_BASE_ADDRESS_MEM_TYPE_64;
1883bfa9a2ebSMichael Ellerman
1884bfa9a2ebSMichael Ellerman out_le32(mbase + PECFG_BAR0HMPA, RES_TO_U32_HIGH(sa));
1885bfa9a2ebSMichael Ellerman out_le32(mbase + PECFG_BAR0LMPA, RES_TO_U32_LOW(sa));
1886bfa9a2ebSMichael Ellerman
1887bfa9a2ebSMichael Ellerman /* The setup of the split looks weird to me ... let's see
1888bfa9a2ebSMichael Ellerman * if it works
1889bfa9a2ebSMichael Ellerman */
1890bfa9a2ebSMichael Ellerman out_le32(mbase + PECFG_PIM0LAL, 0x00000000);
1891bfa9a2ebSMichael Ellerman out_le32(mbase + PECFG_PIM0LAH, 0x00000000);
1892bfa9a2ebSMichael Ellerman out_le32(mbase + PECFG_PIM1LAL, 0x00000000);
1893bfa9a2ebSMichael Ellerman out_le32(mbase + PECFG_PIM1LAH, 0x00000000);
1894bfa9a2ebSMichael Ellerman out_le32(mbase + PECFG_PIM01SAH, 0xffff0000);
1895bfa9a2ebSMichael Ellerman out_le32(mbase + PECFG_PIM01SAL, 0x00000000);
1896bfa9a2ebSMichael Ellerman
1897bfa9a2ebSMichael Ellerman out_le32(mbase + PCI_BASE_ADDRESS_0, RES_TO_U32_LOW(res->start));
1898bfa9a2ebSMichael Ellerman out_le32(mbase + PCI_BASE_ADDRESS_1, RES_TO_U32_HIGH(res->start));
1899bfa9a2ebSMichael Ellerman }
1900bfa9a2ebSMichael Ellerman
1901bfa9a2ebSMichael Ellerman /* Enable inbound mapping */
1902bfa9a2ebSMichael Ellerman out_le32(mbase + PECFG_PIMEN, 0x1);
1903bfa9a2ebSMichael Ellerman
1904bfa9a2ebSMichael Ellerman /* Enable I/O, Mem, and Busmaster cycles */
1905bfa9a2ebSMichael Ellerman out_le16(mbase + PCI_COMMAND,
1906bfa9a2ebSMichael Ellerman in_le16(mbase + PCI_COMMAND) |
1907bfa9a2ebSMichael Ellerman PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
1908bfa9a2ebSMichael Ellerman }
1909bfa9a2ebSMichael Ellerman
ppc4xx_pciex_port_setup_hose(struct ppc4xx_pciex_port * port)1910bfa9a2ebSMichael Ellerman static void __init ppc4xx_pciex_port_setup_hose(struct ppc4xx_pciex_port *port)
1911bfa9a2ebSMichael Ellerman {
1912bfa9a2ebSMichael Ellerman struct resource dma_window;
1913bfa9a2ebSMichael Ellerman struct pci_controller *hose = NULL;
1914bfa9a2ebSMichael Ellerman const int *bus_range;
19154d57e351SRob Herring int primary, busses;
1916bfa9a2ebSMichael Ellerman void __iomem *mbase = NULL, *cfg_data = NULL;
1917bfa9a2ebSMichael Ellerman const u32 *pval;
1918bfa9a2ebSMichael Ellerman u32 val;
1919bfa9a2ebSMichael Ellerman
1920bfa9a2ebSMichael Ellerman /* Check if primary bridge */
19214d57e351SRob Herring primary = of_property_read_bool(port->node, "primary");
1922bfa9a2ebSMichael Ellerman
1923bfa9a2ebSMichael Ellerman /* Get bus range if any */
1924bfa9a2ebSMichael Ellerman bus_range = of_get_property(port->node, "bus-range", NULL);
1925bfa9a2ebSMichael Ellerman
1926bfa9a2ebSMichael Ellerman /* Allocate the host controller data structure */
1927bfa9a2ebSMichael Ellerman hose = pcibios_alloc_controller(port->node);
1928bfa9a2ebSMichael Ellerman if (!hose)
1929bfa9a2ebSMichael Ellerman goto fail;
1930bfa9a2ebSMichael Ellerman
1931bfa9a2ebSMichael Ellerman /* We stick the port number in "indirect_type" so the config space
1932bfa9a2ebSMichael Ellerman * ops can retrieve the port data structure easily
1933bfa9a2ebSMichael Ellerman */
1934bfa9a2ebSMichael Ellerman hose->indirect_type = port->index;
1935bfa9a2ebSMichael Ellerman
1936bfa9a2ebSMichael Ellerman /* Get bus range */
1937bfa9a2ebSMichael Ellerman hose->first_busno = bus_range ? bus_range[0] : 0x0;
1938bfa9a2ebSMichael Ellerman hose->last_busno = bus_range ? bus_range[1] : 0xff;
1939bfa9a2ebSMichael Ellerman
1940bfa9a2ebSMichael Ellerman /* Because of how big mapping the config space is (1M per bus), we
1941bfa9a2ebSMichael Ellerman * limit how many busses we support. In the long run, we could replace
1942bfa9a2ebSMichael Ellerman * that with something akin to kmap_atomic instead. We set aside 1 bus
1943bfa9a2ebSMichael Ellerman * for the host itself too.
1944bfa9a2ebSMichael Ellerman */
1945bfa9a2ebSMichael Ellerman busses = hose->last_busno - hose->first_busno; /* This is off by 1 */
1946bfa9a2ebSMichael Ellerman if (busses > MAX_PCIE_BUS_MAPPED) {
1947bfa9a2ebSMichael Ellerman busses = MAX_PCIE_BUS_MAPPED;
1948bfa9a2ebSMichael Ellerman hose->last_busno = hose->first_busno + busses;
1949bfa9a2ebSMichael Ellerman }
1950bfa9a2ebSMichael Ellerman
1951bfa9a2ebSMichael Ellerman if (!port->endpoint) {
1952bfa9a2ebSMichael Ellerman /* Only map the external config space in cfg_data for
1953bfa9a2ebSMichael Ellerman * PCIe root-complexes. External space is 1M per bus
1954bfa9a2ebSMichael Ellerman */
1955bfa9a2ebSMichael Ellerman cfg_data = ioremap(port->cfg_space.start +
1956bfa9a2ebSMichael Ellerman (hose->first_busno + 1) * 0x100000,
1957bfa9a2ebSMichael Ellerman busses * 0x100000);
1958bfa9a2ebSMichael Ellerman if (cfg_data == NULL) {
1959b7c670d6SRob Herring printk(KERN_ERR "%pOF: Can't map external config space !",
1960b7c670d6SRob Herring port->node);
1961bfa9a2ebSMichael Ellerman goto fail;
1962bfa9a2ebSMichael Ellerman }
1963bfa9a2ebSMichael Ellerman hose->cfg_data = cfg_data;
1964bfa9a2ebSMichael Ellerman }
1965bfa9a2ebSMichael Ellerman
1966bfa9a2ebSMichael Ellerman /* Always map the host config space in cfg_addr.
1967bfa9a2ebSMichael Ellerman * Internal space is 4K
1968bfa9a2ebSMichael Ellerman */
1969bfa9a2ebSMichael Ellerman mbase = ioremap(port->cfg_space.start + 0x10000000, 0x1000);
1970bfa9a2ebSMichael Ellerman if (mbase == NULL) {
1971b7c670d6SRob Herring printk(KERN_ERR "%pOF: Can't map internal config space !",
1972b7c670d6SRob Herring port->node);
1973bfa9a2ebSMichael Ellerman goto fail;
1974bfa9a2ebSMichael Ellerman }
1975bfa9a2ebSMichael Ellerman hose->cfg_addr = mbase;
1976bfa9a2ebSMichael Ellerman
1977b7c670d6SRob Herring pr_debug("PCIE %pOF, bus %d..%d\n", port->node,
1978bfa9a2ebSMichael Ellerman hose->first_busno, hose->last_busno);
1979bfa9a2ebSMichael Ellerman pr_debug(" config space mapped at: root @0x%p, other @0x%p\n",
1980bfa9a2ebSMichael Ellerman hose->cfg_addr, hose->cfg_data);
1981bfa9a2ebSMichael Ellerman
1982bfa9a2ebSMichael Ellerman /* Setup config space */
1983bfa9a2ebSMichael Ellerman hose->ops = &ppc4xx_pciex_pci_ops;
1984bfa9a2ebSMichael Ellerman port->hose = hose;
1985bfa9a2ebSMichael Ellerman mbase = (void __iomem *)hose->cfg_addr;
1986bfa9a2ebSMichael Ellerman
1987bfa9a2ebSMichael Ellerman if (!port->endpoint) {
1988bfa9a2ebSMichael Ellerman /*
1989bfa9a2ebSMichael Ellerman * Set bus numbers on our root port
1990bfa9a2ebSMichael Ellerman */
1991bfa9a2ebSMichael Ellerman out_8(mbase + PCI_PRIMARY_BUS, hose->first_busno);
1992bfa9a2ebSMichael Ellerman out_8(mbase + PCI_SECONDARY_BUS, hose->first_busno + 1);
1993bfa9a2ebSMichael Ellerman out_8(mbase + PCI_SUBORDINATE_BUS, hose->last_busno);
1994bfa9a2ebSMichael Ellerman }
1995bfa9a2ebSMichael Ellerman
1996bfa9a2ebSMichael Ellerman /*
1997bfa9a2ebSMichael Ellerman * OMRs are already reset, also disable PIMs
1998bfa9a2ebSMichael Ellerman */
1999bfa9a2ebSMichael Ellerman out_le32(mbase + PECFG_PIMEN, 0);
2000bfa9a2ebSMichael Ellerman
2001bfa9a2ebSMichael Ellerman /* Parse outbound mapping resources */
2002bfa9a2ebSMichael Ellerman pci_process_bridge_OF_ranges(hose, port->node, primary);
2003bfa9a2ebSMichael Ellerman
2004bfa9a2ebSMichael Ellerman /* Parse inbound mapping resources */
2005bfa9a2ebSMichael Ellerman if (ppc4xx_parse_dma_ranges(hose, mbase, &dma_window) != 0)
2006bfa9a2ebSMichael Ellerman goto fail;
2007bfa9a2ebSMichael Ellerman
2008bfa9a2ebSMichael Ellerman /* Configure outbound ranges POMs */
2009bfa9a2ebSMichael Ellerman ppc4xx_configure_pciex_POMs(port, hose, mbase);
2010bfa9a2ebSMichael Ellerman
2011bfa9a2ebSMichael Ellerman /* Configure inbound ranges PIMs */
2012bfa9a2ebSMichael Ellerman ppc4xx_configure_pciex_PIMs(port, hose, mbase, &dma_window);
2013bfa9a2ebSMichael Ellerman
2014bfa9a2ebSMichael Ellerman /* The root complex doesn't show up if we don't set some vendor
2015bfa9a2ebSMichael Ellerman * and device IDs into it. The defaults below are the same bogus
2016bfa9a2ebSMichael Ellerman * one that the initial code in arch/ppc had. This can be
2017bfa9a2ebSMichael Ellerman * overwritten by setting the "vendor-id/device-id" properties
2018bfa9a2ebSMichael Ellerman * in the pciex node.
2019bfa9a2ebSMichael Ellerman */
2020bfa9a2ebSMichael Ellerman
2021bfa9a2ebSMichael Ellerman /* Get the (optional) vendor-/device-id from the device-tree */
2022bfa9a2ebSMichael Ellerman pval = of_get_property(port->node, "vendor-id", NULL);
2023bfa9a2ebSMichael Ellerman if (pval) {
2024bfa9a2ebSMichael Ellerman val = *pval;
2025bfa9a2ebSMichael Ellerman } else {
2026bfa9a2ebSMichael Ellerman if (!port->endpoint)
2027bfa9a2ebSMichael Ellerman val = 0xaaa0 + port->index;
2028bfa9a2ebSMichael Ellerman else
2029bfa9a2ebSMichael Ellerman val = 0xeee0 + port->index;
2030bfa9a2ebSMichael Ellerman }
2031bfa9a2ebSMichael Ellerman out_le16(mbase + 0x200, val);
2032bfa9a2ebSMichael Ellerman
2033bfa9a2ebSMichael Ellerman pval = of_get_property(port->node, "device-id", NULL);
2034bfa9a2ebSMichael Ellerman if (pval) {
2035bfa9a2ebSMichael Ellerman val = *pval;
2036bfa9a2ebSMichael Ellerman } else {
2037bfa9a2ebSMichael Ellerman if (!port->endpoint)
2038bfa9a2ebSMichael Ellerman val = 0xbed0 + port->index;
2039bfa9a2ebSMichael Ellerman else
2040bfa9a2ebSMichael Ellerman val = 0xfed0 + port->index;
2041bfa9a2ebSMichael Ellerman }
2042bfa9a2ebSMichael Ellerman out_le16(mbase + 0x202, val);
2043bfa9a2ebSMichael Ellerman
2044bfa9a2ebSMichael Ellerman /* Enable Bus master, memory, and io space */
2045bfa9a2ebSMichael Ellerman if (of_device_is_compatible(port->node, "ibm,plb-pciex-460sx"))
2046bfa9a2ebSMichael Ellerman out_le16(mbase + 0x204, 0x7);
2047bfa9a2ebSMichael Ellerman
2048bfa9a2ebSMichael Ellerman if (!port->endpoint) {
2049bfa9a2ebSMichael Ellerman /* Set Class Code to PCI-PCI bridge and Revision Id to 1 */
2050bfa9a2ebSMichael Ellerman out_le32(mbase + 0x208, 0x06040001);
2051bfa9a2ebSMichael Ellerman
2052bfa9a2ebSMichael Ellerman printk(KERN_INFO "PCIE%d: successfully set as root-complex\n",
2053bfa9a2ebSMichael Ellerman port->index);
2054bfa9a2ebSMichael Ellerman } else {
2055bfa9a2ebSMichael Ellerman /* Set Class Code to Processor/PPC */
2056bfa9a2ebSMichael Ellerman out_le32(mbase + 0x208, 0x0b200001);
2057bfa9a2ebSMichael Ellerman
2058bfa9a2ebSMichael Ellerman printk(KERN_INFO "PCIE%d: successfully set as endpoint\n",
2059bfa9a2ebSMichael Ellerman port->index);
2060bfa9a2ebSMichael Ellerman }
2061bfa9a2ebSMichael Ellerman
2062bfa9a2ebSMichael Ellerman return;
2063bfa9a2ebSMichael Ellerman fail:
2064bfa9a2ebSMichael Ellerman if (hose)
2065bfa9a2ebSMichael Ellerman pcibios_free_controller(hose);
2066bfa9a2ebSMichael Ellerman if (cfg_data)
2067bfa9a2ebSMichael Ellerman iounmap(cfg_data);
2068bfa9a2ebSMichael Ellerman if (mbase)
2069bfa9a2ebSMichael Ellerman iounmap(mbase);
2070bfa9a2ebSMichael Ellerman }
2071bfa9a2ebSMichael Ellerman
ppc4xx_probe_pciex_bridge(struct device_node * np)2072bfa9a2ebSMichael Ellerman static void __init ppc4xx_probe_pciex_bridge(struct device_node *np)
2073bfa9a2ebSMichael Ellerman {
2074bfa9a2ebSMichael Ellerman struct ppc4xx_pciex_port *port;
2075bfa9a2ebSMichael Ellerman const u32 *pval;
2076bfa9a2ebSMichael Ellerman int portno;
2077bfa9a2ebSMichael Ellerman unsigned int dcrs;
2078bfa9a2ebSMichael Ellerman
2079bfa9a2ebSMichael Ellerman /* First, proceed to core initialization as we assume there's
2080bfa9a2ebSMichael Ellerman * only one PCIe core in the system
2081bfa9a2ebSMichael Ellerman */
2082bfa9a2ebSMichael Ellerman if (ppc4xx_pciex_check_core_init(np))
2083bfa9a2ebSMichael Ellerman return;
2084bfa9a2ebSMichael Ellerman
2085bfa9a2ebSMichael Ellerman /* Get the port number from the device-tree */
2086bfa9a2ebSMichael Ellerman pval = of_get_property(np, "port", NULL);
2087bfa9a2ebSMichael Ellerman if (pval == NULL) {
2088b7c670d6SRob Herring printk(KERN_ERR "PCIE: Can't find port number for %pOF\n", np);
2089bfa9a2ebSMichael Ellerman return;
2090bfa9a2ebSMichael Ellerman }
2091bfa9a2ebSMichael Ellerman portno = *pval;
2092bfa9a2ebSMichael Ellerman if (portno >= ppc4xx_pciex_port_count) {
2093b7c670d6SRob Herring printk(KERN_ERR "PCIE: port number out of range for %pOF\n",
2094b7c670d6SRob Herring np);
2095bfa9a2ebSMichael Ellerman return;
2096bfa9a2ebSMichael Ellerman }
2097bfa9a2ebSMichael Ellerman port = &ppc4xx_pciex_ports[portno];
2098bfa9a2ebSMichael Ellerman port->index = portno;
2099bfa9a2ebSMichael Ellerman
2100bfa9a2ebSMichael Ellerman /*
2101bfa9a2ebSMichael Ellerman * Check if device is enabled
2102bfa9a2ebSMichael Ellerman */
2103bfa9a2ebSMichael Ellerman if (!of_device_is_available(np)) {
2104bfa9a2ebSMichael Ellerman printk(KERN_INFO "PCIE%d: Port disabled via device-tree\n", port->index);
2105bfa9a2ebSMichael Ellerman return;
2106bfa9a2ebSMichael Ellerman }
2107bfa9a2ebSMichael Ellerman
2108bfa9a2ebSMichael Ellerman port->node = of_node_get(np);
2109bfa9a2ebSMichael Ellerman if (ppc4xx_pciex_hwops->want_sdr) {
2110bfa9a2ebSMichael Ellerman pval = of_get_property(np, "sdr-base", NULL);
2111bfa9a2ebSMichael Ellerman if (pval == NULL) {
2112b7c670d6SRob Herring printk(KERN_ERR "PCIE: missing sdr-base for %pOF\n",
2113b7c670d6SRob Herring np);
2114bfa9a2ebSMichael Ellerman return;
2115bfa9a2ebSMichael Ellerman }
2116bfa9a2ebSMichael Ellerman port->sdr_base = *pval;
2117bfa9a2ebSMichael Ellerman }
2118bfa9a2ebSMichael Ellerman
2119bfa9a2ebSMichael Ellerman /* Check if device_type property is set to "pci" or "pci-endpoint".
2120bfa9a2ebSMichael Ellerman * Resulting from this setup this PCIe port will be configured
2121bfa9a2ebSMichael Ellerman * as root-complex or as endpoint.
2122bfa9a2ebSMichael Ellerman */
2123e5480bdcSRob Herring if (of_node_is_type(port->node, "pci-endpoint")) {
2124bfa9a2ebSMichael Ellerman port->endpoint = 1;
2125e5480bdcSRob Herring } else if (of_node_is_type(port->node, "pci")) {
2126bfa9a2ebSMichael Ellerman port->endpoint = 0;
2127bfa9a2ebSMichael Ellerman } else {
2128b7c670d6SRob Herring printk(KERN_ERR "PCIE: missing or incorrect device_type for %pOF\n",
2129b7c670d6SRob Herring np);
2130bfa9a2ebSMichael Ellerman return;
2131bfa9a2ebSMichael Ellerman }
2132bfa9a2ebSMichael Ellerman
2133bfa9a2ebSMichael Ellerman /* Fetch config space registers address */
2134bfa9a2ebSMichael Ellerman if (of_address_to_resource(np, 0, &port->cfg_space)) {
2135b7c670d6SRob Herring printk(KERN_ERR "%pOF: Can't get PCI-E config space !", np);
2136bfa9a2ebSMichael Ellerman return;
2137bfa9a2ebSMichael Ellerman }
2138bfa9a2ebSMichael Ellerman /* Fetch host bridge internal registers address */
2139bfa9a2ebSMichael Ellerman if (of_address_to_resource(np, 1, &port->utl_regs)) {
2140b7c670d6SRob Herring printk(KERN_ERR "%pOF: Can't get UTL register base !", np);
2141bfa9a2ebSMichael Ellerman return;
2142bfa9a2ebSMichael Ellerman }
2143bfa9a2ebSMichael Ellerman
2144bfa9a2ebSMichael Ellerman /* Map DCRs */
2145bfa9a2ebSMichael Ellerman dcrs = dcr_resource_start(np, 0);
2146bfa9a2ebSMichael Ellerman if (dcrs == 0) {
2147b7c670d6SRob Herring printk(KERN_ERR "%pOF: Can't get DCR register base !", np);
2148bfa9a2ebSMichael Ellerman return;
2149bfa9a2ebSMichael Ellerman }
2150bfa9a2ebSMichael Ellerman port->dcrs = dcr_map(np, dcrs, dcr_resource_len(np, 0));
2151bfa9a2ebSMichael Ellerman
2152bfa9a2ebSMichael Ellerman /* Initialize the port specific registers */
2153bfa9a2ebSMichael Ellerman if (ppc4xx_pciex_port_init(port)) {
2154bfa9a2ebSMichael Ellerman printk(KERN_WARNING "PCIE%d: Port init failed\n", port->index);
2155bfa9a2ebSMichael Ellerman return;
2156bfa9a2ebSMichael Ellerman }
2157bfa9a2ebSMichael Ellerman
2158bfa9a2ebSMichael Ellerman /* Setup the linux hose data structure */
2159bfa9a2ebSMichael Ellerman ppc4xx_pciex_port_setup_hose(port);
2160bfa9a2ebSMichael Ellerman }
2161bfa9a2ebSMichael Ellerman
2162bfa9a2ebSMichael Ellerman #endif /* CONFIG_PPC4xx_PCI_EXPRESS */
2163bfa9a2ebSMichael Ellerman
ppc4xx_pci_find_bridges(void)2164bfa9a2ebSMichael Ellerman static int __init ppc4xx_pci_find_bridges(void)
2165bfa9a2ebSMichael Ellerman {
2166bfa9a2ebSMichael Ellerman struct device_node *np;
2167bfa9a2ebSMichael Ellerman
2168bfa9a2ebSMichael Ellerman pci_add_flags(PCI_ENABLE_PROC_DOMAINS | PCI_COMPAT_DOMAIN_0);
2169bfa9a2ebSMichael Ellerman
2170bfa9a2ebSMichael Ellerman #ifdef CONFIG_PPC4xx_PCI_EXPRESS
2171bfa9a2ebSMichael Ellerman for_each_compatible_node(np, NULL, "ibm,plb-pciex")
2172bfa9a2ebSMichael Ellerman ppc4xx_probe_pciex_bridge(np);
2173bfa9a2ebSMichael Ellerman #endif
2174bfa9a2ebSMichael Ellerman for_each_compatible_node(np, NULL, "ibm,plb-pcix")
2175bfa9a2ebSMichael Ellerman ppc4xx_probe_pcix_bridge(np);
2176bfa9a2ebSMichael Ellerman for_each_compatible_node(np, NULL, "ibm,plb-pci")
2177bfa9a2ebSMichael Ellerman ppc4xx_probe_pci_bridge(np);
2178bfa9a2ebSMichael Ellerman
2179bfa9a2ebSMichael Ellerman return 0;
2180bfa9a2ebSMichael Ellerman }
2181bfa9a2ebSMichael Ellerman arch_initcall(ppc4xx_pci_find_bridges);
2182bfa9a2ebSMichael Ellerman
2183