Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
leon_pci.c
Go to the documentation of this file.
1 /*
2  * leon_pci.c: LEON Host PCI support
3  *
4  * Copyright (C) 2011 Aeroflex Gaisler AB, Daniel Hellstrom
5  *
6  * Code is partially derived from pcic.c
7  */
8 
9 #include <linux/of_device.h>
10 #include <linux/kernel.h>
11 #include <linux/pci.h>
12 #include <linux/export.h>
13 #include <asm/leon.h>
14 #include <asm/leon_pci.h>
15 
16 /* The LEON architecture does not rely on a BIOS or bootloader to setup
17  * PCI for us. The Linux generic routines are used to setup resources,
18  * reset values of configuration-space register settings are preserved.
19  *
20  * PCI Memory and Prefetchable Memory is direct-mapped. However I/O Space is
21  * accessed through a Window which is translated to low 64KB in PCI space, the
22  * first 4KB is not used so 60KB is available.
23  */
24 void leon_pci_init(struct platform_device *ofdev, struct leon_pci_info *info)
25 {
27  struct pci_bus *root_bus;
28 
30  info->io_space.start - 0x1000);
32 
33  root_bus = pci_scan_root_bus(&ofdev->dev, 0, info->ops, info,
34  &resources);
35  if (root_bus) {
36  /* Setup IRQs of all devices using custom routines */
38 
39  /* Assign devices with resources */
41  } else {
43  }
44 }
45 
47 {
48  struct pci_dev *dev;
49  int i, has_io, has_mem;
50  u16 cmd;
51 
52  list_for_each_entry(dev, &pbus->devices, bus_list) {
53  /*
54  * We can not rely on that the bootloader has enabled I/O
55  * or memory access to PCI devices. Instead we enable it here
56  * if the device has BARs of respective type.
57  */
58  has_io = has_mem = 0;
59  for (i = 0; i < PCI_ROM_RESOURCE; i++) {
60  unsigned long f = dev->resource[i].flags;
61  if (f & IORESOURCE_IO)
62  has_io = 1;
63  else if (f & IORESOURCE_MEM)
64  has_mem = 1;
65  }
66  /* ROM BARs are mapped into 32-bit memory space */
67  if (dev->resource[PCI_ROM_RESOURCE].end != 0) {
68  dev->resource[PCI_ROM_RESOURCE].flags |=
70  has_mem = 1;
71  }
72  pci_bus_read_config_word(pbus, dev->devfn, PCI_COMMAND, &cmd);
73  if (has_io && !(cmd & PCI_COMMAND_IO)) {
74 #ifdef CONFIG_PCI_DEBUG
75  printk(KERN_INFO "LEONPCI: Enabling I/O for dev %s\n",
76  pci_name(dev));
77 #endif
78  cmd |= PCI_COMMAND_IO;
79  pci_bus_write_config_word(pbus, dev->devfn, PCI_COMMAND,
80  cmd);
81  }
82  if (has_mem && !(cmd & PCI_COMMAND_MEMORY)) {
83 #ifdef CONFIG_PCI_DEBUG
84  printk(KERN_INFO "LEONPCI: Enabling MEMORY for dev"
85  "%s\n", pci_name(dev));
86 #endif
87  cmd |= PCI_COMMAND_MEMORY;
88  pci_bus_write_config_word(pbus, dev->devfn, PCI_COMMAND,
89  cmd);
90  }
91  }
92 }
93 
96 {
97  return res->start;
98 }
99 
101 {
102  return pci_enable_resources(dev, mask);
103 }
104 
105 /* in/out routines taken from pcic.c
106  *
107  * This probably belongs here rather than ioport.c because
108  * we do not want this crud linked into SBus kernels.
109  * Also, think for a moment about likes of floppy.c that
110  * include architecture specific parts. They may want to redefine ins/outs.
111  *
112  * We do not use horrible macros here because we want to
113  * advance pointer by sizeof(size).
114  */
115 void outsb(unsigned long addr, const void *src, unsigned long count)
116 {
117  while (count) {
118  count -= 1;
119  outb(*(const char *)src, addr);
120  src += 1;
121  /* addr += 1; */
122  }
123 }
125 
126 void outsw(unsigned long addr, const void *src, unsigned long count)
127 {
128  while (count) {
129  count -= 2;
130  outw(*(const short *)src, addr);
131  src += 2;
132  /* addr += 2; */
133  }
134 }
136 
137 void outsl(unsigned long addr, const void *src, unsigned long count)
138 {
139  while (count) {
140  count -= 4;
141  outl(*(const long *)src, addr);
142  src += 4;
143  /* addr += 4; */
144  }
145 }
147 
148 void insb(unsigned long addr, void *dst, unsigned long count)
149 {
150  while (count) {
151  count -= 1;
152  *(unsigned char *)dst = inb(addr);
153  dst += 1;
154  /* addr += 1; */
155  }
156 }
158 
159 void insw(unsigned long addr, void *dst, unsigned long count)
160 {
161  while (count) {
162  count -= 2;
163  *(unsigned short *)dst = inw(addr);
164  dst += 2;
165  /* addr += 2; */
166  }
167 }
169 
170 void insl(unsigned long addr, void *dst, unsigned long count)
171 {
172  while (count) {
173  count -= 4;
174  /*
175  * XXX I am sure we are in for an unaligned trap here.
176  */
177  *(unsigned long *)dst = inl(addr);
178  dst += 4;
179  /* addr += 4; */
180  }
181 }