Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pci.c
Go to the documentation of this file.
1 /*
2  * linux/arch/arm/mach-versatile/pci.c
3  *
4  * (C) Copyright Koninklijke Philips Electronics NV 2004. All rights reserved.
5  * You can redistribute and/or modify this software under the terms of version 2
6  * of the GNU General Public License as published by the Free Software Foundation.
7  * THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED
8  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. See the GNU
9  * General Public License for more details.
10  * Koninklijke Philips Electronics nor its subsidiaries is obligated to provide any support for this software.
11  *
12  * ARM Versatile PCI driver.
13  *
14  * 14/04/2005 Initial version, [email protected]
15  *
16  */
17 #include <linux/kernel.h>
18 #include <linux/pci.h>
19 #include <linux/ioport.h>
20 #include <linux/interrupt.h>
21 #include <linux/spinlock.h>
22 #include <linux/init.h>
23 #include <linux/io.h>
24 
25 #include <mach/hardware.h>
26 #include <asm/irq.h>
27 #include <asm/mach/pci.h>
28 
29 /*
30  * these spaces are mapped using the following base registers:
31  *
32  * Usage Local Bus Memory Base/Map registers used
33  *
34  * Mem 50000000 - 5FFFFFFF LB_BASE0/LB_MAP0, non prefetch
35  * Mem 60000000 - 6FFFFFFF LB_BASE1/LB_MAP1, prefetch
36  * IO 44000000 - 4FFFFFFF LB_BASE2/LB_MAP2, IO
37  * Cfg 42000000 - 42FFFFFF PCI config
38  *
39  */
40 #define __IO_ADDRESS(n) ((void __iomem *)(unsigned long)IO_ADDRESS(n))
41 #define SYS_PCICTL __IO_ADDRESS(VERSATILE_SYS_PCICTL)
42 #define PCI_IMAP0 __IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x0)
43 #define PCI_IMAP1 __IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x4)
44 #define PCI_IMAP2 __IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x8)
45 #define PCI_SMAP0 __IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x10)
46 #define PCI_SMAP1 __IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x14)
47 #define PCI_SMAP2 __IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x18)
48 #define PCI_SELFID __IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0xc)
49 
50 #define DEVICE_ID_OFFSET 0x00
51 #define CSR_OFFSET 0x04
52 #define CLASS_ID_OFFSET 0x08
53 
54 #define VP_PCI_DEVICE_ID 0x030010ee
55 #define VP_PCI_CLASS_ID 0x0b400000
56 
57 static unsigned long pci_slot_ignore = 0;
58 
59 static int __init versatile_pci_slot_ignore(char *str)
60 {
61  int retval;
62  int slot;
63 
64  while ((retval = get_option(&str,&slot))) {
65  if ((slot < 0) || (slot > 31)) {
66  printk("Illegal slot value: %d\n",slot);
67  } else {
68  pci_slot_ignore |= (1 << slot);
69  }
70  }
71  return 1;
72 }
73 
74 __setup("pci_slot_ignore=", versatile_pci_slot_ignore);
75 
76 
77 static void __iomem *__pci_addr(struct pci_bus *bus,
78  unsigned int devfn, int offset)
79 {
80  unsigned int busnr = bus->number;
81 
82  /*
83  * Trap out illegal values
84  */
85  if (offset > 255)
86  BUG();
87  if (busnr > 255)
88  BUG();
89  if (devfn > 255)
90  BUG();
91 
92  return VERSATILE_PCI_CFG_VIRT_BASE + ((busnr << 16) |
93  (PCI_SLOT(devfn) << 11) | (PCI_FUNC(devfn) << 8) | offset);
94 }
95 
96 static int versatile_read_config(struct pci_bus *bus, unsigned int devfn, int where,
97  int size, u32 *val)
98 {
99  void __iomem *addr = __pci_addr(bus, devfn, where & ~3);
100  u32 v;
101  int slot = PCI_SLOT(devfn);
102 
103  if (pci_slot_ignore & (1 << slot)) {
104  /* Ignore this slot */
105  switch (size) {
106  case 1:
107  v = 0xff;
108  break;
109  case 2:
110  v = 0xffff;
111  break;
112  default:
113  v = 0xffffffff;
114  }
115  } else {
116  switch (size) {
117  case 1:
118  v = __raw_readl(addr);
119  if (where & 2) v >>= 16;
120  if (where & 1) v >>= 8;
121  v &= 0xff;
122  break;
123 
124  case 2:
125  v = __raw_readl(addr);
126  if (where & 2) v >>= 16;
127  v &= 0xffff;
128  break;
129 
130  default:
131  v = __raw_readl(addr);
132  break;
133  }
134  }
135 
136  *val = v;
137  return PCIBIOS_SUCCESSFUL;
138 }
139 
140 static int versatile_write_config(struct pci_bus *bus, unsigned int devfn, int where,
141  int size, u32 val)
142 {
143  void __iomem *addr = __pci_addr(bus, devfn, where);
144  int slot = PCI_SLOT(devfn);
145 
146  if (pci_slot_ignore & (1 << slot)) {
147  return PCIBIOS_SUCCESSFUL;
148  }
149 
150  switch (size) {
151  case 1:
152  __raw_writeb((u8)val, addr);
153  break;
154 
155  case 2:
156  __raw_writew((u16)val, addr);
157  break;
158 
159  case 4:
160  __raw_writel(val, addr);
161  break;
162  }
163 
164  return PCIBIOS_SUCCESSFUL;
165 }
166 
167 static struct pci_ops pci_versatile_ops = {
168  .read = versatile_read_config,
169  .write = versatile_write_config,
170 };
171 
172 static struct resource io_mem = {
173  .name = "PCI I/O space",
174  .start = VERSATILE_PCI_MEM_BASE0,
176  .flags = IORESOURCE_MEM,
177 };
178 
179 static struct resource non_mem = {
180  .name = "PCI non-prefetchable",
181  .start = VERSATILE_PCI_MEM_BASE1,
183  .flags = IORESOURCE_MEM,
184 };
185 
186 static struct resource pre_mem = {
187  .name = "PCI prefetchable",
188  .start = VERSATILE_PCI_MEM_BASE2,
191 };
192 
193 static int __init pci_versatile_setup_resources(struct pci_sys_data *sys)
194 {
195  int ret = 0;
196 
197  ret = request_resource(&iomem_resource, &io_mem);
198  if (ret) {
199  printk(KERN_ERR "PCI: unable to allocate I/O "
200  "memory region (%d)\n", ret);
201  goto out;
202  }
203  ret = request_resource(&iomem_resource, &non_mem);
204  if (ret) {
205  printk(KERN_ERR "PCI: unable to allocate non-prefetchable "
206  "memory region (%d)\n", ret);
207  goto release_io_mem;
208  }
209  ret = request_resource(&iomem_resource, &pre_mem);
210  if (ret) {
211  printk(KERN_ERR "PCI: unable to allocate prefetchable "
212  "memory region (%d)\n", ret);
213  goto release_non_mem;
214  }
215 
216  /*
217  * the mem resource for this bus
218  * the prefetch mem resource for this bus
219  */
220  pci_add_resource_offset(&sys->resources, &non_mem, sys->mem_offset);
221  pci_add_resource_offset(&sys->resources, &pre_mem, sys->mem_offset);
222 
223  goto out;
224 
225  release_non_mem:
226  release_resource(&non_mem);
227  release_io_mem:
228  release_resource(&io_mem);
229  out:
230  return ret;
231 }
232 
234 {
235  int ret = 0;
236  int i;
237  int myslot = -1;
238  unsigned long val;
239  void __iomem *local_pci_cfg_base;
240 
241  val = __raw_readl(SYS_PCICTL);
242  if (!(val & 1)) {
243  printk("Not plugged into PCI backplane!\n");
244  ret = -EIO;
245  goto out;
246  }
247 
248  ret = pci_ioremap_io(0, VERSATILE_PCI_MEM_BASE0);
249  if (ret)
250  goto out;
251 
252  if (nr == 0) {
253  ret = pci_versatile_setup_resources(sys);
254  if (ret < 0) {
255  printk("pci_versatile_setup: resources... oops?\n");
256  goto out;
257  }
258  } else {
259  printk("pci_versatile_setup: resources... nr == 0??\n");
260  goto out;
261  }
262 
263  /*
264  * We need to discover the PCI core first to configure itself
265  * before the main PCI probing is performed
266  */
267  for (i=0; i<32; i++)
270  myslot = i;
271  break;
272  }
273 
274  if (myslot == -1) {
275  printk("Cannot find PCI core!\n");
276  ret = -EIO;
277  goto out;
278  }
279 
280  printk("PCI core found (slot %d)\n",myslot);
281 
282  __raw_writel(myslot, PCI_SELFID);
283  local_pci_cfg_base = VERSATILE_PCI_CFG_VIRT_BASE + (myslot << 11);
284 
285  val = __raw_readl(local_pci_cfg_base + CSR_OFFSET);
287  __raw_writel(val, local_pci_cfg_base + CSR_OFFSET);
288 
289  /*
290  * Configure the PCI inbound memory windows to be 1:1 mapped to SDRAM
291  */
292  __raw_writel(PHYS_OFFSET, local_pci_cfg_base + PCI_BASE_ADDRESS_0);
293  __raw_writel(PHYS_OFFSET, local_pci_cfg_base + PCI_BASE_ADDRESS_1);
294  __raw_writel(PHYS_OFFSET, local_pci_cfg_base + PCI_BASE_ADDRESS_2);
295 
296  /*
297  * Do not to map Versatile FPGA PCI device into memory space
298  */
299  pci_slot_ignore |= (1 << myslot);
300  ret = 1;
301 
302  out:
303  return ret;
304 }
305 
306 
308 {
309  pcibios_min_mem = 0x50000000;
310 
314 
318 
320 }
321 
322 /*
323  * map the specified device/slot/pin to an IRQ. Different backplanes may need to modify this.
324  */
325 static int __init versatile_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
326 {
327  int irq;
328 
329  /* slot, pin, irq
330  * 24 1 27
331  * 25 1 28
332  * 26 1 29
333  * 27 1 30
334  */
335  irq = 27 + ((slot - 24 + pin - 1) & 3);
336 
337  return irq;
338 }
339 
340 static struct hw_pci versatile_pci __initdata = {
341  .map_irq = versatile_map_irq,
342  .nr_controllers = 1,
343  .ops = &pci_versatile_ops,
344  .setup = pci_versatile_setup,
345  .preinit = pci_versatile_preinit,
346 };
347 
348 static int __init versatile_pci_init(void)
349 {
350  pci_common_init(&versatile_pci);
351  return 0;
352 }
353 
354 subsys_initcall(versatile_pci_init);