aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mn10300/unit-asb2305/pci-asb2305.c
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2008-02-08 07:19:31 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2008-02-08 12:22:30 -0500
commitb920de1b77b72ca9432ac3f97edb26541e65e5dd (patch)
tree40fa9be1470e929c47927dea7eddf184c0204229 /arch/mn10300/unit-asb2305/pci-asb2305.c
parentef3d534754f31fed9c3b976fee1ece1b3bc38282 (diff)
mn10300: add the MN10300/AM33 architecture to the kernel
Add architecture support for the MN10300/AM33 CPUs produced by MEI to the kernel. This patch also adds board support for the ASB2303 with the ASB2308 daughter board, and the ASB2305. The only processor supported is the MN103E010, which is an AM33v2 core plus on-chip devices. [akpm@linux-foundation.org: nuke cvs control strings] Signed-off-by: Masakazu Urade <urade.masakazu@jp.panasonic.com> Signed-off-by: Koichi Yasutake <yasutake.koichi@jp.panasonic.com> Signed-off-by: David Howells <dhowells@redhat.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'arch/mn10300/unit-asb2305/pci-asb2305.c')
-rw-r--r--arch/mn10300/unit-asb2305/pci-asb2305.c303
1 files changed, 303 insertions, 0 deletions
diff --git a/arch/mn10300/unit-asb2305/pci-asb2305.c b/arch/mn10300/unit-asb2305/pci-asb2305.c
new file mode 100644
index 000000000000..d100ca788468
--- /dev/null
+++ b/arch/mn10300/unit-asb2305/pci-asb2305.c
@@ -0,0 +1,303 @@
1/* ASB2305 PCI resource stuff
2 *
3 * Copyright (C) 2001 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 * - Derived from arch/i386/pci-i386.c
6 * - Copyright 1997--2000 Martin Mares <mj@suse.cz>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public Licence
10 * as published by the Free Software Foundation; either version
11 * 2 of the Licence, or (at your option) any later version.
12 */
13#include <linux/types.h>
14#include <linux/kernel.h>
15#include <linux/pci.h>
16#include <linux/init.h>
17#include <linux/ioport.h>
18#include <linux/errno.h>
19#include "pci-asb2305.h"
20
21/*
22 * We need to avoid collisions with `mirrored' VGA ports
23 * and other strange ISA hardware, so we always want the
24 * addresses to be allocated in the 0x000-0x0ff region
25 * modulo 0x400.
26 *
27 * Why? Because some silly external IO cards only decode
28 * the low 10 bits of the IO address. The 0x00-0xff region
29 * is reserved for motherboard devices that decode all 16
30 * bits, so it's ok to allocate at, say, 0x2800-0x28ff,
31 * but we want to try to avoid allocating at 0x2900-0x2bff
32 * which might have be mirrored at 0x0100-0x03ff..
33 */
34void pcibios_align_resource(void *data, struct resource *res,
35 resource_size_t size, resource_size_t align)
36{
37#if 0
38 struct pci_dev *dev = data;
39
40 printk(KERN_DEBUG
41 "### PCIBIOS_ALIGN_RESOURCE(%s,,{%08lx-%08lx,%08lx},%lx)\n",
42 pci_name(dev),
43 res->start,
44 res->end,
45 res->flags,
46 size
47 );
48#endif
49
50 if (res->flags & IORESOURCE_IO) {
51 unsigned long start = res->start;
52
53 if (start & 0x300) {
54 start = (start + 0x3ff) & ~0x3ff;
55 res->start = start;
56 }
57 }
58}
59
60
61/*
62 * Handle resources of PCI devices. If the world were perfect, we could
63 * just allocate all the resource regions and do nothing more. It isn't.
64 * On the other hand, we cannot just re-allocate all devices, as it would
65 * require us to know lots of host bridge internals. So we attempt to
66 * keep as much of the original configuration as possible, but tweak it
67 * when it's found to be wrong.
68 *
69 * Known BIOS problems we have to work around:
70 * - I/O or memory regions not configured
71 * - regions configured, but not enabled in the command register
72 * - bogus I/O addresses above 64K used
73 * - expansion ROMs left enabled (this may sound harmless, but given
74 * the fact the PCI specs explicitly allow address decoders to be
75 * shared between expansion ROMs and other resource regions, it's
76 * at least dangerous)
77 *
78 * Our solution:
79 * (1) Allocate resources for all buses behind PCI-to-PCI bridges.
80 * This gives us fixed barriers on where we can allocate.
81 * (2) Allocate resources for all enabled devices. If there is
82 * a collision, just mark the resource as unallocated. Also
83 * disable expansion ROMs during this step.
84 * (3) Try to allocate resources for disabled devices. If the
85 * resources were assigned correctly, everything goes well,
86 * if they weren't, they won't disturb allocation of other
87 * resources.
88 * (4) Assign new addresses to resources which were either
89 * not configured at all or misconfigured. If explicitly
90 * requested by the user, configure expansion ROM address
91 * as well.
92 */
93static void __init pcibios_allocate_bus_resources(struct list_head *bus_list)
94{
95 struct pci_bus *bus;
96 struct pci_dev *dev;
97 int idx;
98 struct resource *r, *pr;
99
100 /* Depth-First Search on bus tree */
101 list_for_each_entry(bus, bus_list, node) {
102 dev = bus->self;
103 if (dev) {
104 for (idx = PCI_BRIDGE_RESOURCES;
105 idx < PCI_NUM_RESOURCES;
106 idx++) {
107 r = &dev->resource[idx];
108 if (!r->flags)
109 continue;
110 pr = pci_find_parent_resource(dev, r);
111 if (!r->start ||
112 !pr ||
113 request_resource(pr, r) < 0) {
114 printk(KERN_ERR "PCI:"
115 " Cannot allocate resource"
116 " region %d of bridge %s\n",
117 idx, pci_name(dev));
118 /* Something is wrong with the region.
119 * Invalidate the resource to prevent
120 * child resource allocations in this
121 * range. */
122 r->flags = 0;
123 }
124 }
125 }
126 pcibios_allocate_bus_resources(&bus->children);
127 }
128}
129
130static void __init pcibios_allocate_resources(int pass)
131{
132 struct pci_dev *dev = NULL;
133 int idx, disabled;
134 u16 command;
135 struct resource *r, *pr;
136
137 for_each_pci_dev(dev) {
138 pci_read_config_word(dev, PCI_COMMAND, &command);
139 for (idx = 0; idx < 6; idx++) {
140 r = &dev->resource[idx];
141 if (r->parent) /* Already allocated */
142 continue;
143 if (!r->start) /* Address not assigned */
144 continue;
145 if (r->flags & IORESOURCE_IO)
146 disabled = !(command & PCI_COMMAND_IO);
147 else
148 disabled = !(command & PCI_COMMAND_MEMORY);
149 if (pass == disabled) {
150 DBG("PCI[%s]: Resource %08lx-%08lx"
151 " (f=%lx, d=%d, p=%d)\n",
152 pci_name(dev), r->start, r->end, r->flags,
153 disabled, pass);
154 pr = pci_find_parent_resource(dev, r);
155 if (!pr || request_resource(pr, r) < 0) {
156 printk(KERN_ERR "PCI:"
157 " Cannot allocate resource"
158 " region %d of device %s\n",
159 idx, pci_name(dev));
160 /* We'll assign a new address later */
161 r->end -= r->start;
162 r->start = 0;
163 }
164 }
165 }
166 if (!pass) {
167 r = &dev->resource[PCI_ROM_RESOURCE];
168 if (r->flags & IORESOURCE_ROM_ENABLE) {
169 /* Turn the ROM off, leave the resource region,
170 * but keep it unregistered. */
171 u32 reg;
172 DBG("PCI: Switching off ROM of %s\n",
173 pci_name(dev));
174 r->flags &= ~IORESOURCE_ROM_ENABLE;
175 pci_read_config_dword(
176 dev, dev->rom_base_reg, &reg);
177 pci_write_config_dword(
178 dev, dev->rom_base_reg,
179 reg & ~PCI_ROM_ADDRESS_ENABLE);
180 }
181 }
182 }
183}
184
185static int __init pcibios_assign_resources(void)
186{
187 struct pci_dev *dev = NULL;
188 struct resource *r, *pr;
189
190 if (!(pci_probe & PCI_ASSIGN_ROMS)) {
191 /* Try to use BIOS settings for ROMs, otherwise let
192 pci_assign_unassigned_resources() allocate the new
193 addresses. */
194 for_each_pci_dev(dev) {
195 r = &dev->resource[PCI_ROM_RESOURCE];
196 if (!r->flags || !r->start)
197 continue;
198 pr = pci_find_parent_resource(dev, r);
199 if (!pr || request_resource(pr, r) < 0) {
200 r->end -= r->start;
201 r->start = 0;
202 }
203 }
204 }
205
206 pci_assign_unassigned_resources();
207
208 return 0;
209}
210
211fs_initcall(pcibios_assign_resources);
212
213void __init pcibios_resource_survey(void)
214{
215 DBG("PCI: Allocating resources\n");
216 pcibios_allocate_bus_resources(&pci_root_buses);
217 pcibios_allocate_resources(0);
218 pcibios_allocate_resources(1);
219}
220
221int pcibios_enable_resources(struct pci_dev *dev, int mask)
222{
223 u16 cmd, old_cmd;
224 int idx;
225 struct resource *r;
226
227 pci_read_config_word(dev, PCI_COMMAND, &cmd);
228 old_cmd = cmd;
229
230 for (idx = 0; idx < 6; idx++) {
231 /* Only set up the requested stuff */
232 if (!(mask & (1 << idx)))
233 continue;
234
235 r = &dev->resource[idx];
236
237 if (!r->start && r->end) {
238 printk(KERN_ERR
239 "PCI: Device %s not available because of"
240 " resource collisions\n",
241 pci_name(dev));
242 return -EINVAL;
243 }
244
245 if (r->flags & IORESOURCE_IO)
246 cmd |= PCI_COMMAND_IO;
247 if (r->flags & IORESOURCE_MEM)
248 cmd |= PCI_COMMAND_MEMORY;
249 }
250
251 if (dev->resource[PCI_ROM_RESOURCE].start)
252 cmd |= PCI_COMMAND_MEMORY;
253
254 if (cmd != old_cmd)
255 pci_write_config_word(dev, PCI_COMMAND, cmd);
256
257 return 0;
258}
259
260/*
261 * If we set up a device for bus mastering, we need to check the latency
262 * timer as certain crappy BIOSes forget to set it properly.
263 */
264unsigned int pcibios_max_latency = 255;
265
266void pcibios_set_master(struct pci_dev *dev)
267{
268 u8 lat;
269
270 pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
271
272 if (lat < 16)
273 lat = (64 <= pcibios_max_latency) ? 64 : pcibios_max_latency;
274 else if (lat > pcibios_max_latency)
275 lat = pcibios_max_latency;
276 else
277 return;
278
279 pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat);
280}
281
282int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
283 enum pci_mmap_state mmap_state, int write_combine)
284{
285 unsigned long prot;
286
287 /* Leave vm_pgoff as-is, the PCI space address is the physical
288 * address on this platform.
289 */
290 vma->vm_flags |= VM_LOCKED | VM_IO;
291
292 prot = pgprot_val(vma->vm_page_prot);
293 prot &= ~_PAGE_CACHE;
294 vma->vm_page_prot = __pgprot(prot);
295
296 /* Write-combine setting is ignored */
297 if (io_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
298 vma->vm_end - vma->vm_start,
299 vma->vm_page_prot))
300 return -EAGAIN;
301
302 return 0;
303}