aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh
diff options
context:
space:
mode:
authorPaul Mundt <lethal@linux-sh.org>2009-04-20 02:43:36 -0400
committerPaul Mundt <lethal@linux-sh.org>2009-04-20 02:43:36 -0400
commit4c5107e44514a9bde74d0af77982705d602d9e39 (patch)
tree7915b112e6f81cfc90787e5fb9097032bd4212a8 /arch/sh
parent9ade1217c9ba39ad2f004a898ddfbb815fd5fe74 (diff)
sh: pci: Split out new-style PCI core.
This splits off a 'pci-new.c' which is aimed at gradually replacing the pci-auto backend and the arch/sh/drivers/pci/pci.c core respectively. Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch/sh')
-rw-r--r--arch/sh/drivers/pci/Kconfig10
-rw-r--r--arch/sh/drivers/pci/Makefile4
-rw-r--r--arch/sh/drivers/pci/pci-new.c248
3 files changed, 258 insertions, 4 deletions
diff --git a/arch/sh/drivers/pci/Kconfig b/arch/sh/drivers/pci/Kconfig
index 7e816ededed7..efe8cf965a9b 100644
--- a/arch/sh/drivers/pci/Kconfig
+++ b/arch/sh/drivers/pci/Kconfig
@@ -18,10 +18,17 @@ config SH_PCIDMA_NONCOHERENT
18 bridge integrated with your SH CPU, refer carefully to the chip specs 18 bridge integrated with your SH CPU, refer carefully to the chip specs
19 to see if you can say 'N' here. Otherwise, leave it as 'Y'. 19 to see if you can say 'N' here. Otherwise, leave it as 'Y'.
20 20
21# Temporary config option for transitioning off of PCI_AUTO
22config PCI_NEW
23 bool
24 depends on PCI
25 default y if CPU_SUBTYPE_SH7763 || CPU_SUBTYPE_SH7780 || \
26 CPU_SUBTYPE_SH7785
27
21# This is also board-specific 28# This is also board-specific
22config PCI_AUTO 29config PCI_AUTO
23 bool 30 bool
24 depends on PCI 31 depends on PCI && !PCI_NEW
25 default y 32 default y
26 33
27config PCI_AUTO_UPDATE_RESOURCES 34config PCI_AUTO_UPDATE_RESOURCES
@@ -34,4 +41,3 @@ config PCI_AUTO_UPDATE_RESOURCES
34 for some reason, you have a board that simply refuses to work 41 for some reason, you have a board that simply refuses to work
35 with its resources updated beyond what they are when the device 42 with its resources updated beyond what they are when the device
36 is powered up, set this to N. Everyone else will want this as Y. 43 is powered up, set this to N. Everyone else will want this as Y.
37
diff --git a/arch/sh/drivers/pci/Makefile b/arch/sh/drivers/pci/Makefile
index 5003971476ec..362a1eec73a4 100644
--- a/arch/sh/drivers/pci/Makefile
+++ b/arch/sh/drivers/pci/Makefile
@@ -2,8 +2,8 @@
2# Makefile for the PCI specific kernel interface routines under Linux. 2# Makefile for the PCI specific kernel interface routines under Linux.
3# 3#
4 4
5obj-y += pci.o 5obj-$(CONFIG_PCI_AUTO) := pci.o pci-auto.o
6obj-$(CONFIG_PCI_AUTO) += pci-auto.o 6obj-$(CONFIG_PCI_NEW) := pci-new.o
7 7
8obj-$(CONFIG_CPU_SUBTYPE_SH7751) += pci-sh7751.o ops-sh4.o 8obj-$(CONFIG_CPU_SUBTYPE_SH7751) += pci-sh7751.o ops-sh4.o
9obj-$(CONFIG_CPU_SUBTYPE_SH7751R) += pci-sh7751.o ops-sh4.o 9obj-$(CONFIG_CPU_SUBTYPE_SH7751R) += pci-sh7751.o ops-sh4.o
diff --git a/arch/sh/drivers/pci/pci-new.c b/arch/sh/drivers/pci/pci-new.c
new file mode 100644
index 000000000000..097eb8811120
--- /dev/null
+++ b/arch/sh/drivers/pci/pci-new.c
@@ -0,0 +1,248 @@
1/*
2 * New-style PCI core.
3 *
4 * Copyright (c) 2002 M. R. Brown
5 * Copyright (c) 2004 - 2009 Paul Mundt
6 *
7 * This file is subject to the terms and conditions of the GNU General Public
8 * License. See the file "COPYING" in the main directory of this archive
9 * for more details.
10 */
11#include <linux/kernel.h>
12#include <linux/pci.h>
13#include <linux/init.h>
14#include <linux/dma-debug.h>
15#include <linux/io.h>
16
17static int __init pcibios_init(void)
18{
19 struct pci_channel *p;
20 struct pci_bus *bus;
21 int busno;
22
23 /* init channels */
24 busno = 0;
25 for (p = board_pci_channels; p->init; p++) {
26 if (p->init(p) == 0)
27 p->enabled = 1;
28 else
29 pr_err("Unable to init pci channel %d\n", busno);
30 busno++;
31 }
32
33 /* scan the buses */
34 busno = 0;
35 for (p = board_pci_channels; p->init; p++) {
36 if (p->enabled) {
37 bus = pci_scan_bus(busno, p->pci_ops, p);
38 busno = bus->subordinate + 1;
39
40 pci_bus_size_bridges(bus);
41 pci_bus_assign_resources(bus);
42 pci_enable_bridges(bus);
43 }
44 }
45
46 pci_fixup_irqs(pci_common_swizzle, pcibios_map_platform_irq);
47
48 dma_debug_add_bus(&pci_bus_type);
49
50 return 0;
51}
52subsys_initcall(pcibios_init);
53
54static void pcibios_fixup_device_resources(struct pci_dev *dev,
55 struct pci_bus *bus)
56{
57 /* Update device resources. */
58 struct pci_channel *chan = bus->sysdata;
59 unsigned long offset = 0;
60 int i;
61
62 for (i = 0; i < PCI_NUM_RESOURCES; i++) {
63 if (!dev->resource[i].start)
64 continue;
65 if (dev->resource[i].flags & IORESOURCE_PCI_FIXED)
66 continue;
67 if (dev->resource[i].flags & IORESOURCE_IO)
68 offset = chan->io_base;
69 else if (dev->resource[i].flags & IORESOURCE_MEM)
70 offset = 0;
71
72 dev->resource[i].start += offset;
73 dev->resource[i].end += offset;
74 }
75}
76
77
78/*
79 * Called after each bus is probed, but before its children
80 * are examined.
81 */
82void __devinit __weak pcibios_fixup_bus(struct pci_bus *bus)
83{
84 struct pci_dev *dev = bus->self;
85 struct list_head *ln;
86 struct pci_channel *chan = bus->sysdata;
87
88 if (!dev) {
89 bus->resource[0] = chan->io_resource;
90 bus->resource[1] = chan->mem_resource;
91 }
92
93 for (ln = bus->devices.next; ln != &bus->devices; ln = ln->next) {
94 dev = pci_dev_b(ln);
95
96 if ((dev->class >> 8) != PCI_CLASS_BRIDGE_PCI)
97 pcibios_fixup_device_resources(dev, bus);
98 }
99}
100
101void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
102 struct resource *res)
103{
104 struct pci_channel *chan = dev->sysdata;
105 unsigned long offset = 0;
106
107 if (res->flags & IORESOURCE_IO)
108 offset = chan->io_base;
109 else if (res->flags & IORESOURCE_MEM)
110 offset = 0;
111
112 region->start = res->start - offset;
113 region->end = res->end - offset;
114}
115
116void __devinit
117pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
118 struct pci_bus_region *region)
119{
120 struct pci_channel *chan = dev->sysdata;
121 unsigned long offset = 0;
122
123 if (res->flags & IORESOURCE_IO)
124 offset = chan->io_base;
125 else if (res->flags & IORESOURCE_MEM)
126 offset = 0;
127
128 res->start = region->start + offset;
129 res->end = region->end + offset;
130}
131
132void pcibios_align_resource(void *data, struct resource *res,
133 resource_size_t size, resource_size_t align)
134 __attribute__ ((weak));
135
136/*
137 * We need to avoid collisions with `mirrored' VGA ports
138 * and other strange ISA hardware, so we always want the
139 * addresses to be allocated in the 0x000-0x0ff region
140 * modulo 0x400.
141 */
142void pcibios_align_resource(void *data, struct resource *res,
143 resource_size_t size, resource_size_t align)
144{
145 if (res->flags & IORESOURCE_IO) {
146 resource_size_t start = res->start;
147
148 if (start & 0x300) {
149 start = (start + 0x3ff) & ~0x3ff;
150 res->start = start;
151 }
152 }
153}
154
155int pcibios_enable_device(struct pci_dev *dev, int mask)
156{
157 u16 cmd, old_cmd;
158 int idx;
159 struct resource *r;
160
161 pci_read_config_word(dev, PCI_COMMAND, &cmd);
162 old_cmd = cmd;
163 for(idx=0; idx<6; idx++) {
164 if (!(mask & (1 << idx)))
165 continue;
166 r = &dev->resource[idx];
167 if (!r->start && r->end) {
168 printk(KERN_ERR "PCI: Device %s not available because "
169 "of resource collisions\n", pci_name(dev));
170 return -EINVAL;
171 }
172 if (r->flags & IORESOURCE_IO)
173 cmd |= PCI_COMMAND_IO;
174 if (r->flags & IORESOURCE_MEM)
175 cmd |= PCI_COMMAND_MEMORY;
176 }
177 if (dev->resource[PCI_ROM_RESOURCE].start)
178 cmd |= PCI_COMMAND_MEMORY;
179 if (cmd != old_cmd) {
180 printk(KERN_INFO "PCI: Enabling device %s (%04x -> %04x)\n",
181 pci_name(dev), old_cmd, cmd);
182 pci_write_config_word(dev, PCI_COMMAND, cmd);
183 }
184 return 0;
185}
186
187/*
188 * If we set up a device for bus mastering, we need to check and set
189 * the latency timer as it may not be properly set.
190 */
191static unsigned int pcibios_max_latency = 255;
192
193void pcibios_set_master(struct pci_dev *dev)
194{
195 u8 lat;
196 pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
197 if (lat < 16)
198 lat = (64 <= pcibios_max_latency) ? 64 : pcibios_max_latency;
199 else if (lat > pcibios_max_latency)
200 lat = pcibios_max_latency;
201 else
202 return;
203 printk(KERN_INFO "PCI: Setting latency timer of device %s to %d\n",
204 pci_name(dev), lat);
205 pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat);
206}
207
208void __init pcibios_update_irq(struct pci_dev *dev, int irq)
209{
210 pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
211}
212
213void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen)
214{
215 resource_size_t start = pci_resource_start(dev, bar);
216 resource_size_t len = pci_resource_len(dev, bar);
217 unsigned long flags = pci_resource_flags(dev, bar);
218
219 if (unlikely(!len || !start))
220 return NULL;
221 if (maxlen && len > maxlen)
222 len = maxlen;
223
224 /*
225 * Presently the IORESOURCE_MEM case is a bit special, most
226 * SH7751 style PCI controllers have PCI memory at a fixed
227 * location in the address space where no remapping is desired.
228 * With the IORESOURCE_MEM case more care has to be taken
229 * to inhibit page table mapping for legacy cores, but this is
230 * punted off to __ioremap().
231 * -- PFM.
232 */
233 if (flags & IORESOURCE_IO)
234 return ioport_map(start, len);
235 if (flags & IORESOURCE_MEM)
236 return ioremap(start, len);
237
238 return NULL;
239}
240EXPORT_SYMBOL(pci_iomap);
241
242void pci_iounmap(struct pci_dev *dev, void __iomem *addr)
243{
244 iounmap(addr);
245}
246EXPORT_SYMBOL(pci_iounmap);
247
248EXPORT_SYMBOL(board_pci_channels);