aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mn10300/unit-asb2305
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
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')
-rw-r--r--arch/mn10300/unit-asb2305/Makefile8
-rw-r--r--arch/mn10300/unit-asb2305/leds.c124
-rw-r--r--arch/mn10300/unit-asb2305/pci-asb2305.c303
-rw-r--r--arch/mn10300/unit-asb2305/pci-asb2305.h82
-rw-r--r--arch/mn10300/unit-asb2305/pci-iomap.c31
-rw-r--r--arch/mn10300/unit-asb2305/pci-irq.c51
-rw-r--r--arch/mn10300/unit-asb2305/pci.c545
-rw-r--r--arch/mn10300/unit-asb2305/unit-init.c61
8 files changed, 1205 insertions, 0 deletions
diff --git a/arch/mn10300/unit-asb2305/Makefile b/arch/mn10300/unit-asb2305/Makefile
new file mode 100644
index 000000000000..0551022225b3
--- /dev/null
+++ b/arch/mn10300/unit-asb2305/Makefile
@@ -0,0 +1,8 @@
1###############################################################################
2#
3# Makefile for the ASB2305 board
4#
5###############################################################################
6obj-y := unit-init.o leds.o
7
8obj-$(CONFIG_PCI) += pci.o pci-asb2305.o pci-irq.o pci-iomap.o
diff --git a/arch/mn10300/unit-asb2305/leds.c b/arch/mn10300/unit-asb2305/leds.c
new file mode 100644
index 000000000000..e99dcc9cee1a
--- /dev/null
+++ b/arch/mn10300/unit-asb2305/leds.c
@@ -0,0 +1,124 @@
1/* ASB2305 Peripheral 7-segment LEDs x4 support
2 *
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 */
11#include <linux/kernel.h>
12#include <linux/param.h>
13#include <linux/init.h>
14#include <asm/io.h>
15#include <asm/processor.h>
16#include <asm/cpu/intctl-regs.h>
17#include <asm/cpu/rtc-regs.h>
18#include <asm/unit/leds.h>
19
20static const u8 asb2305_led_hex_tbl[16] = {
21 0x80, 0xf2, 0x48, 0x60, 0x32, 0x24, 0x04, 0xf0,
22 0x00, 0x20, 0x10, 0x06, 0x8c, 0x42, 0x0c, 0x1c
23};
24
25static const u32 asb2305_led_chase_tbl[6] = {
26 ~0x02020202, /* top - segA */
27 ~0x04040404, /* right top - segB */
28 ~0x08080808, /* right bottom - segC */
29 ~0x10101010, /* bottom - segD */
30 ~0x20202020, /* left bottom - segE */
31 ~0x40404040, /* left top - segF */
32};
33
34static unsigned asb2305_led_chase;
35
36void peripheral_leds7x4_display_dec(unsigned int val, unsigned int points)
37{
38 u32 leds;
39
40 leds = asb2305_led_hex_tbl[(val/1000) % 10];
41 leds <<= 8;
42 leds |= asb2305_led_hex_tbl[(val/100) % 10];
43 leds <<= 8;
44 leds |= asb2305_led_hex_tbl[(val/10) % 10];
45 leds <<= 8;
46 leds |= asb2305_led_hex_tbl[val % 10];
47 leds |= points^0x01010101;
48
49 ASB2305_7SEGLEDS = leds;
50}
51
52void peripheral_leds7x4_display_hex(unsigned int val, unsigned int points)
53{
54 u32 leds;
55
56 leds = asb2305_led_hex_tbl[(val/1000) % 10];
57 leds <<= 8;
58 leds |= asb2305_led_hex_tbl[(val/100) % 10];
59 leds <<= 8;
60 leds |= asb2305_led_hex_tbl[(val/10) % 10];
61 leds <<= 8;
62 leds |= asb2305_led_hex_tbl[val % 10];
63 leds |= points^0x01010101;
64
65 ASB2305_7SEGLEDS = leds;
66}
67
68void peripheral_leds_display_exception(enum exception_code code)
69{
70 u32 leds;
71
72 leds = asb2305_led_hex_tbl[(code/0x100) % 0x10];
73 leds <<= 8;
74 leds |= asb2305_led_hex_tbl[(code/0x10) % 0x10];
75 leds <<= 8;
76 leds |= asb2305_led_hex_tbl[code % 0x10];
77 leds |= 0x6d010101;
78
79 ASB2305_7SEGLEDS = leds;
80}
81
82void peripheral_leds7x4_display_minssecs(unsigned int time, unsigned int points)
83{
84 u32 leds;
85
86 leds = asb2305_led_hex_tbl[(time/600) % 6];
87 leds <<= 8;
88 leds |= asb2305_led_hex_tbl[(time/60) % 10];
89 leds <<= 8;
90 leds |= asb2305_led_hex_tbl[(time/10) % 6];
91 leds <<= 8;
92 leds |= asb2305_led_hex_tbl[time % 10];
93 leds |= points^0x01010101;
94
95 ASB2305_7SEGLEDS = leds;
96}
97
98void peripheral_leds7x4_display_rtc(void)
99{
100 unsigned int clock;
101 u8 mins, secs;
102
103 mins = RTMCR;
104 secs = RTSCR;
105
106 clock = ((mins & 0xf0) >> 4);
107 clock *= 10;
108 clock += (mins & 0x0f);
109 clock *= 6;
110
111 clock += ((secs & 0xf0) >> 4);
112 clock *= 10;
113 clock += (secs & 0x0f);
114
115 peripheral_leds7x4_display_minssecs(clock, 0);
116}
117
118void peripheral_leds_led_chase(void)
119{
120 ASB2305_7SEGLEDS = asb2305_led_chase_tbl[asb2305_led_chase];
121 asb2305_led_chase++;
122 if (asb2305_led_chase >= 6)
123 asb2305_led_chase = 0;
124}
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}
diff --git a/arch/mn10300/unit-asb2305/pci-asb2305.h b/arch/mn10300/unit-asb2305/pci-asb2305.h
new file mode 100644
index 000000000000..84634fa3bce6
--- /dev/null
+++ b/arch/mn10300/unit-asb2305/pci-asb2305.h
@@ -0,0 +1,82 @@
1/* ASB2305 Arch-specific PCI declarations
2 *
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 * Derived from: arch/i386/kernel/pci-i386.h: (c) 1999 Martin Mares <mj@ucw.cz>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public Licence
9 * as published by the Free Software Foundation; either version
10 * 2 of the Licence, or (at your option) any later version.
11 */
12#ifndef _PCI_ASB2305_H
13#define _PCI_ASB2305_H
14
15#undef DEBUG
16
17#ifdef DEBUG
18#define DBG(x...) printk(x)
19#else
20#define DBG(x...)
21#endif
22
23#define PCI_PROBE_BIOS 1
24#define PCI_PROBE_CONF1 2
25#define PCI_PROBE_CONF2 4
26#define PCI_NO_SORT 0x100
27#define PCI_BIOS_SORT 0x200
28#define PCI_NO_CHECKS 0x400
29#define PCI_ASSIGN_ROMS 0x1000
30#define PCI_BIOS_IRQ_SCAN 0x2000
31
32extern unsigned int pci_probe;
33
34/* pci-asb2305.c */
35
36extern unsigned int pcibios_max_latency;
37
38extern void pcibios_resource_survey(void);
39extern int pcibios_enable_resources(struct pci_dev *dev, int mask);
40
41/* pci.c */
42
43extern int pcibios_last_bus;
44extern struct pci_bus *pci_root_bus;
45extern struct pci_ops *pci_root_ops;
46
47extern struct irq_routing_table *pcibios_get_irq_routing_table(void);
48extern int pcibios_set_irq_routing(struct pci_dev *dev, int pin, int irq);
49
50/* pci-irq.c */
51
52struct irq_info {
53 u8 bus, devfn; /* Bus, device and function */
54 struct {
55 u8 link; /* IRQ line ID, chipset dependent,
56 * 0=not routed */
57 u16 bitmap; /* Available IRQs */
58 } __attribute__((packed)) irq[4];
59 u8 slot; /* Slot number, 0=onboard */
60 u8 rfu;
61} __attribute__((packed));
62
63struct irq_routing_table {
64 u32 signature; /* PIRQ_SIGNATURE should be here */
65 u16 version; /* PIRQ_VERSION */
66 u16 size; /* Table size in bytes */
67 u8 rtr_bus, rtr_devfn; /* Where the interrupt router lies */
68 u16 exclusive_irqs; /* IRQs devoted exclusively to PCI usage */
69 u16 rtr_vendor, rtr_device; /* Vendor and device ID of interrupt router */
70 u32 miniport_data; /* Crap */
71 u8 rfu[11];
72 u8 checksum; /* Modulo 256 checksum must give zero */
73 struct irq_info slots[0];
74} __attribute__((packed));
75
76extern unsigned int pcibios_irq_mask;
77
78extern void pcibios_irq_init(void);
79extern void pcibios_fixup_irqs(void);
80extern void pcibios_enable_irq(struct pci_dev *dev);
81
82#endif /* PCI_ASB2305_H */
diff --git a/arch/mn10300/unit-asb2305/pci-iomap.c b/arch/mn10300/unit-asb2305/pci-iomap.c
new file mode 100644
index 000000000000..dbceae4307da
--- /dev/null
+++ b/arch/mn10300/unit-asb2305/pci-iomap.c
@@ -0,0 +1,31 @@
1/* ASB2305 PCI I/O mapping handler
2 *
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 */
11#include <linux/pci.h>
12#include <linux/module.h>
13
14/*
15 * Create a virtual mapping cookie for a PCI BAR (memory or IO)
16 */
17void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen)
18{
19 unsigned long start = pci_resource_start(dev, bar);
20 unsigned long len = pci_resource_len(dev, bar);
21 unsigned long flags = pci_resource_flags(dev, bar);
22
23 if (!len || !start)
24 return NULL;
25
26 if ((flags & IORESOURCE_IO) || (flags & IORESOURCE_MEM))
27 return (void __iomem *) start;
28
29 return NULL;
30}
31EXPORT_SYMBOL(pci_iomap);
diff --git a/arch/mn10300/unit-asb2305/pci-irq.c b/arch/mn10300/unit-asb2305/pci-irq.c
new file mode 100644
index 000000000000..58cfb44f0acf
--- /dev/null
+++ b/arch/mn10300/unit-asb2305/pci-irq.c
@@ -0,0 +1,51 @@
1/* PCI IRQ routing on the MN103E010 based ASB2305
2 *
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 *
11 * This is simple: All PCI interrupts route through the CPU's XIRQ1 pin [IRQ 35]
12 */
13#include <linux/types.h>
14#include <linux/kernel.h>
15#include <linux/pci.h>
16#include <linux/init.h>
17#include <linux/slab.h>
18#include <linux/interrupt.h>
19#include <linux/irq.h>
20#include <asm/io.h>
21#include <asm/smp.h>
22#include "pci-asb2305.h"
23
24void __init pcibios_irq_init(void)
25{
26}
27
28void __init pcibios_fixup_irqs(void)
29{
30 struct pci_dev *dev = NULL;
31 u8 line, pin;
32
33 while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
34 pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
35 if (pin) {
36 dev->irq = XIRQ1;
37 pci_write_config_byte(dev, PCI_INTERRUPT_LINE,
38 dev->irq);
39 }
40 pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &line);
41 }
42}
43
44void __init pcibios_penalize_isa_irq(int irq)
45{
46}
47
48void pcibios_enable_irq(struct pci_dev *dev)
49{
50 pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
51}
diff --git a/arch/mn10300/unit-asb2305/pci.c b/arch/mn10300/unit-asb2305/pci.c
new file mode 100644
index 000000000000..1a86425fec42
--- /dev/null
+++ b/arch/mn10300/unit-asb2305/pci.c
@@ -0,0 +1,545 @@
1/* ASB2305 PCI support
2 *
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 * Derived from arch/i386/kernel/pci-pc.c
6 * (c) 1999--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/sched.h>
16#include <linux/pci.h>
17#include <linux/init.h>
18#include <linux/ioport.h>
19#include <linux/delay.h>
20#include <asm/io.h>
21#include "pci-asb2305.h"
22
23unsigned int pci_probe = 1;
24
25int pcibios_last_bus = -1;
26struct pci_bus *pci_root_bus;
27struct pci_ops *pci_root_ops;
28
29/*
30 * Functions for accessing PCI configuration space
31 */
32
33#define CONFIG_CMD(bus, devfn, where) \
34 (0x80000000 | (bus->number << 16) | (devfn << 8) | (where & ~3))
35
36#define MEM_PAGING_REG (*(volatile __u32 *) 0xBFFFFFF4)
37#define CONFIG_ADDRESS (*(volatile __u32 *) 0xBFFFFFF8)
38#define CONFIG_DATAL(X) (*(volatile __u32 *) 0xBFFFFFFC)
39#define CONFIG_DATAW(X) (*(volatile __u16 *) (0xBFFFFFFC + ((X) & 2)))
40#define CONFIG_DATAB(X) (*(volatile __u8 *) (0xBFFFFFFC + ((X) & 3)))
41
42#define BRIDGEREGB(X) (*(volatile __u8 *) (0xBE040000 + (X)))
43#define BRIDGEREGW(X) (*(volatile __u16 *) (0xBE040000 + (X)))
44#define BRIDGEREGL(X) (*(volatile __u32 *) (0xBE040000 + (X)))
45
46static inline int __query(const struct pci_bus *bus, unsigned int devfn)
47{
48#if 0
49 return bus->number == 0 && (devfn == PCI_DEVFN(0, 0));
50 return bus->number == 1;
51 return bus->number == 0 &&
52 (devfn == PCI_DEVFN(2, 0) || devfn == PCI_DEVFN(3, 0));
53#endif
54 return 1;
55}
56
57/*
58 * translate Linuxcentric addresses to PCI bus addresses
59 */
60void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
61 struct resource *res)
62{
63 if (res->flags & IORESOURCE_IO) {
64 region->start = (res->start & 0x00ffffff);
65 region->end = (res->end & 0x00ffffff);
66 }
67
68 if (res->flags & IORESOURCE_MEM) {
69 region->start = (res->start & 0x03ffffff) | MEM_PAGING_REG;
70 region->end = (res->end & 0x03ffffff) | MEM_PAGING_REG;
71 }
72
73#if 0
74 printk(KERN_DEBUG "RES->BUS: %lx-%lx => %lx-%lx\n",
75 res->start, res->end, region->start, region->end);
76#endif
77}
78EXPORT_SYMBOL(pcibios_resource_to_bus);
79
80/*
81 * translate PCI bus addresses to Linuxcentric addresses
82 */
83void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
84 struct pci_bus_region *region)
85{
86 if (res->flags & IORESOURCE_IO) {
87 res->start = (region->start & 0x00ffffff) | 0xbe000000;
88 res->end = (region->end & 0x00ffffff) | 0xbe000000;
89 }
90
91 if (res->flags & IORESOURCE_MEM) {
92 res->start = (region->start & 0x03ffffff) | 0xb8000000;
93 res->end = (region->end & 0x03ffffff) | 0xb8000000;
94 }
95
96#if 0
97 printk(KERN_INFO "BUS->RES: %lx-%lx => %lx-%lx\n",
98 region->start, region->end, res->start, res->end);
99#endif
100}
101EXPORT_SYMBOL(pcibios_bus_to_resource);
102
103/*
104 *
105 */
106static int pci_ampci_read_config_byte(struct pci_bus *bus, unsigned int devfn,
107 int where, u32 *_value)
108{
109 u32 rawval, value;
110
111 if (bus->number == 0 && devfn == PCI_DEVFN(0, 0)) {
112 value = BRIDGEREGB(where);
113 __pcbdebug("=> %02hx", &BRIDGEREGL(where), value);
114 } else {
115 CONFIG_ADDRESS = CONFIG_CMD(bus, devfn, where);
116 rawval = CONFIG_ADDRESS;
117 value = CONFIG_DATAB(where);
118 if (__query(bus, devfn))
119 __pcidebug("=> %02hx", bus, devfn, where, value);
120 }
121
122 *_value = value;
123 return PCIBIOS_SUCCESSFUL;
124}
125
126static int pci_ampci_read_config_word(struct pci_bus *bus, unsigned int devfn,
127 int where, u32 *_value)
128{
129 u32 rawval, value;
130
131 if (bus->number == 0 && devfn == PCI_DEVFN(0, 0)) {
132 value = BRIDGEREGW(where);
133 __pcbdebug("=> %04hx", &BRIDGEREGL(where), value);
134 } else {
135 CONFIG_ADDRESS = CONFIG_CMD(bus, devfn, where);
136 rawval = CONFIG_ADDRESS;
137 value = CONFIG_DATAW(where);
138 if (__query(bus, devfn))
139 __pcidebug("=> %04hx", bus, devfn, where, value);
140 }
141
142 *_value = value;
143 return PCIBIOS_SUCCESSFUL;
144}
145
146static int pci_ampci_read_config_dword(struct pci_bus *bus, unsigned int devfn,
147 int where, u32 *_value)
148{
149 u32 rawval, value;
150
151 if (bus->number == 0 && devfn == PCI_DEVFN(0, 0)) {
152 value = BRIDGEREGL(where);
153 __pcbdebug("=> %08x", &BRIDGEREGL(where), value);
154 } else {
155 CONFIG_ADDRESS = CONFIG_CMD(bus, devfn, where);
156 rawval = CONFIG_ADDRESS;
157 value = CONFIG_DATAL(where);
158 if (__query(bus, devfn))
159 __pcidebug("=> %08x", bus, devfn, where, value);
160 }
161
162 *_value = value;
163 return PCIBIOS_SUCCESSFUL;
164}
165
166static int pci_ampci_write_config_byte(struct pci_bus *bus, unsigned int devfn,
167 int where, u8 value)
168{
169 u32 rawval;
170
171 if (bus->number == 0 && devfn == PCI_DEVFN(0, 0)) {
172 __pcbdebug("<= %02x", &BRIDGEREGB(where), value);
173 BRIDGEREGB(where) = value;
174 } else {
175 if (bus->number == 0 &&
176 (devfn == PCI_DEVFN(2, 0) && devfn == PCI_DEVFN(3, 0))
177 )
178 __pcidebug("<= %02x", bus, devfn, where, value);
179 CONFIG_ADDRESS = CONFIG_CMD(bus, devfn, where);
180 rawval = CONFIG_ADDRESS;
181 CONFIG_DATAB(where) = value;
182 }
183 return PCIBIOS_SUCCESSFUL;
184}
185
186static int pci_ampci_write_config_word(struct pci_bus *bus, unsigned int devfn,
187 int where, u16 value)
188{
189 u32 rawval;
190
191 if (bus->number == 0 && devfn == PCI_DEVFN(0, 0)) {
192 __pcbdebug("<= %04hx", &BRIDGEREGW(where), value);
193 BRIDGEREGW(where) = value;
194 } else {
195 if (__query(bus, devfn))
196 __pcidebug("<= %04hx", bus, devfn, where, value);
197 CONFIG_ADDRESS = CONFIG_CMD(bus, devfn, where);
198 rawval = CONFIG_ADDRESS;
199 CONFIG_DATAW(where) = value;
200 }
201 return PCIBIOS_SUCCESSFUL;
202}
203
204static int pci_ampci_write_config_dword(struct pci_bus *bus, unsigned int devfn,
205 int where, u32 value)
206{
207 u32 rawval;
208
209 if (bus->number == 0 && devfn == PCI_DEVFN(0, 0)) {
210 __pcbdebug("<= %08x", &BRIDGEREGL(where), value);
211 BRIDGEREGL(where) = value;
212 } else {
213 if (__query(bus, devfn))
214 __pcidebug("<= %08x", bus, devfn, where, value);
215 CONFIG_ADDRESS = CONFIG_CMD(bus, devfn, where);
216 rawval = CONFIG_ADDRESS;
217 CONFIG_DATAL(where) = value;
218 }
219 return PCIBIOS_SUCCESSFUL;
220}
221
222static int pci_ampci_read_config(struct pci_bus *bus, unsigned int devfn,
223 int where, int size, u32 *val)
224{
225 switch (size) {
226 case 1:
227 return pci_ampci_read_config_byte(bus, devfn, where, val);
228 case 2:
229 return pci_ampci_read_config_word(bus, devfn, where, val);
230 case 4:
231 return pci_ampci_read_config_dword(bus, devfn, where, val);
232 default:
233 BUG();
234 return -EOPNOTSUPP;
235 }
236}
237
238static int pci_ampci_write_config(struct pci_bus *bus, unsigned int devfn,
239 int where, int size, u32 val)
240{
241 switch (size) {
242 case 1:
243 return pci_ampci_write_config_byte(bus, devfn, where, val);
244 case 2:
245 return pci_ampci_write_config_word(bus, devfn, where, val);
246 case 4:
247 return pci_ampci_write_config_dword(bus, devfn, where, val);
248 default:
249 BUG();
250 return -EOPNOTSUPP;
251 }
252}
253
254static struct pci_ops pci_direct_ampci = {
255 pci_ampci_read_config,
256 pci_ampci_write_config,
257};
258
259/*
260 * Before we decide to use direct hardware access mechanisms, we try to do some
261 * trivial checks to ensure it at least _seems_ to be working -- we just test
262 * whether bus 00 contains a host bridge (this is similar to checking
263 * techniques used in XFree86, but ours should be more reliable since we
264 * attempt to make use of direct access hints provided by the PCI BIOS).
265 *
266 * This should be close to trivial, but it isn't, because there are buggy
267 * chipsets (yes, you guessed it, by Intel and Compaq) that have no class ID.
268 */
269static int __init pci_sanity_check(struct pci_ops *o)
270{
271 struct pci_bus bus; /* Fake bus and device */
272 u32 x;
273
274 bus.number = 0;
275
276 if ((!o->read(&bus, 0, PCI_CLASS_DEVICE, 2, &x) &&
277 (x == PCI_CLASS_BRIDGE_HOST || x == PCI_CLASS_DISPLAY_VGA)) ||
278 (!o->read(&bus, 0, PCI_VENDOR_ID, 2, &x) &&
279 (x == PCI_VENDOR_ID_INTEL || x == PCI_VENDOR_ID_COMPAQ)))
280 return 1;
281
282 printk(KERN_ERROR "PCI: Sanity check failed\n");
283 return 0;
284}
285
286static int __init pci_check_direct(void)
287{
288 unsigned long flags;
289
290 local_irq_save(flags);
291
292 /*
293 * Check if access works.
294 */
295 if (pci_sanity_check(&pci_direct_ampci)) {
296 local_irq_restore(flags);
297 printk(KERN_INFO "PCI: Using configuration ampci\n");
298 request_mem_region(0xBE040000, 256, "AMPCI bridge");
299 request_mem_region(0xBFFFFFF4, 12, "PCI ampci");
300 return 0;
301 }
302
303 local_irq_restore(flags);
304 return -ENODEV;
305}
306
307static int __devinit is_valid_resource(struct pci_dev *dev, int idx)
308{
309 unsigned int i, type_mask = IORESOURCE_IO | IORESOURCE_MEM;
310 struct resource *devr = &dev->resource[idx];
311
312 if (dev->bus) {
313 for (i = 0; i < PCI_BUS_NUM_RESOURCES; i++) {
314 struct resource *busr = dev->bus->resource[i];
315
316 if (!busr || (busr->flags ^ devr->flags) & type_mask)
317 continue;
318
319 if (devr->start &&
320 devr->start >= busr->start &&
321 devr->end <= busr->end)
322 return 1;
323 }
324 }
325
326 return 0;
327}
328
329static void __devinit pcibios_fixup_device_resources(struct pci_dev *dev)
330{
331 struct pci_bus_region region;
332 int i;
333 int limit;
334
335 if (dev->bus->number != 0)
336 return;
337
338 limit = (dev->hdr_type == PCI_HEADER_TYPE_NORMAL) ?
339 PCI_BRIDGE_RESOURCES : PCI_NUM_RESOURCES;
340
341 for (i = 0; i < limit; i++) {
342 if (!dev->resource[i].flags)
343 continue;
344
345 region.start = dev->resource[i].start;
346 region.end = dev->resource[i].end;
347 pcibios_bus_to_resource(dev, &dev->resource[i], &region);
348 if (is_valid_resource(dev, i))
349 pci_claim_resource(dev, i);
350 }
351}
352
353/*
354 * Called after each bus is probed, but before its children
355 * are examined.
356 */
357void __devinit pcibios_fixup_bus(struct pci_bus *bus)
358{
359 struct pci_dev *dev;
360
361 if (bus->self) {
362 pci_read_bridge_bases(bus);
363 pcibios_fixup_device_resources(bus->self);
364 }
365
366 list_for_each_entry(dev, &bus->devices, bus_list)
367 pcibios_fixup_device_resources(dev);
368}
369
370/*
371 * Initialization. Try all known PCI access methods. Note that we support
372 * using both PCI BIOS and direct access: in such cases, we use I/O ports
373 * to access config space, but we still keep BIOS order of cards to be
374 * compatible with 2.0.X. This should go away some day.
375 */
376static int __init pcibios_init(void)
377{
378 ioport_resource.start = 0xA0000000;
379 ioport_resource.end = 0xDFFFFFFF;
380 iomem_resource.start = 0xA0000000;
381 iomem_resource.end = 0xDFFFFFFF;
382
383 if (!pci_probe)
384 return 0;
385
386 if (pci_check_direct() < 0) {
387 printk(KERN_WARNING "PCI: No PCI bus detected\n");
388 return 0;
389 }
390
391 printk(KERN_INFO "PCI: Probing PCI hardware [mempage %08x]\n",
392 MEM_PAGING_REG);
393
394 {
395#if 0
396 static struct pci_bus am33_root_bus = {
397 .children = LIST_HEAD_INIT(am33_root_bus.children),
398 .devices = LIST_HEAD_INIT(am33_root_bus.devices),
399 .number = 0,
400 .secondary = 0,
401 .resource = { &ioport_resource, &iomem_resource },
402 };
403
404 am33_root_bus.ops = pci_root_ops;
405 list_add_tail(&am33_root_bus.node, &pci_root_buses);
406
407 am33_root_bus.subordinate = pci_do_scan_bus(0);
408
409 pci_root_bus = &am33_root_bus;
410#else
411 pci_root_bus = pci_scan_bus(0, &pci_direct_ampci, NULL);
412#endif
413 }
414
415 pcibios_irq_init();
416 pcibios_fixup_irqs();
417#if 0
418 pcibios_resource_survey();
419#endif
420 return 0;
421}
422
423arch_initcall(pcibios_init);
424
425char *__init pcibios_setup(char *str)
426{
427 if (!strcmp(str, "off")) {
428 pci_probe = 0;
429 return NULL;
430
431 } else if (!strncmp(str, "lastbus=", 8)) {
432 pcibios_last_bus = simple_strtol(str+8, NULL, 0);
433 return NULL;
434 }
435
436 return str;
437}
438
439int pcibios_enable_device(struct pci_dev *dev, int mask)
440{
441 int err;
442
443 err = pcibios_enable_resources(dev, mask);
444 if (err == 0)
445 pcibios_enable_irq(dev);
446 return err;
447}
448
449/*
450 * disable the ethernet chipset
451 */
452static void __init unit_disable_pcnet(struct pci_bus *bus, struct pci_ops *o)
453{
454 u32 x;
455
456 bus->number = 0;
457
458 o->read (bus, PCI_DEVFN(2, 0), PCI_COMMAND, 2, &x);
459 x |= PCI_COMMAND_MASTER |
460 PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
461 PCI_COMMAND_SERR | PCI_COMMAND_PARITY;
462 o->write(bus, PCI_DEVFN(2, 0), PCI_COMMAND, 2, x);
463 o->read (bus, PCI_DEVFN(2, 0), PCI_COMMAND, 2, &x);
464 o->write(bus, PCI_DEVFN(2, 0), PCI_BASE_ADDRESS_0, 4, 0x00030001);
465 o->read (bus, PCI_DEVFN(2, 0), PCI_BASE_ADDRESS_0, 4, &x);
466
467#define RDP (*(volatile u32 *) 0xBE030010)
468#define RAP (*(volatile u32 *) 0xBE030014)
469#define __set_RAP(X) do { RAP = (X); x = RAP; } while (0)
470#define __set_RDP(X) do { RDP = (X); x = RDP; } while (0)
471#define __get_RDP() ({ RDP & 0xffff; })
472
473 __set_RAP(0);
474 __set_RDP(0x0004); /* CSR0 = STOP */
475
476 __set_RAP(88); /* check CSR88 indicates an Am79C973 */
477 BUG_ON(__get_RDP() != 0x5003);
478
479 for (x = 0; x < 100; x++)
480 asm volatile("nop");
481
482 __set_RDP(0x0004); /* CSR0 = STOP */
483}
484
485/*
486 * initialise the unit hardware
487 */
488asmlinkage void __init unit_pci_init(void)
489{
490 struct pci_bus bus; /* Fake bus and device */
491 struct pci_ops *o = &pci_direct_ampci;
492 u32 x;
493
494 set_intr_level(XIRQ1, GxICR_LEVEL_3);
495
496 memset(&bus, 0, sizeof(bus));
497
498 MEM_PAGING_REG = 0xE8000000;
499
500 /* we need to set up the bridge _now_ or we won't be able to access the
501 * PCI config registers
502 */
503 BRIDGEREGW(PCI_COMMAND) |=
504 PCI_COMMAND_SERR | PCI_COMMAND_PARITY |
505 PCI_COMMAND_MEMORY | PCI_COMMAND_IO | PCI_COMMAND_MASTER;
506 BRIDGEREGW(PCI_STATUS) = 0xF800;
507 BRIDGEREGB(PCI_LATENCY_TIMER) = 0x10;
508 BRIDGEREGL(PCI_BASE_ADDRESS_0) = 0x80000000;
509 BRIDGEREGB(PCI_INTERRUPT_LINE) = 1;
510 BRIDGEREGL(0x48) = 0x98000000; /* AMPCI base addr */
511 BRIDGEREGB(0x41) = 0x00; /* secondary bus
512 * number */
513 BRIDGEREGB(0x42) = 0x01; /* subordinate bus
514 * number */
515 BRIDGEREGB(0x44) = 0x01;
516 BRIDGEREGL(0x50) = 0x00000001;
517 BRIDGEREGL(0x58) = 0x00001002;
518 BRIDGEREGL(0x5C) = 0x00000011;
519
520 /* we also need to set up the PCI-PCI bridge */
521 bus.number = 0;
522
523 /* IO: 0x00000000-0x00020000 */
524 o->read (&bus, PCI_DEVFN(3, 0), PCI_COMMAND, 2, &x);
525 x |= PCI_COMMAND_MASTER |
526 PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
527 PCI_COMMAND_SERR | PCI_COMMAND_PARITY;
528 o->write(&bus, PCI_DEVFN(3, 0), PCI_COMMAND, 2, x);
529
530 o->read (&bus, PCI_DEVFN(3, 0), PCI_IO_BASE, 1, &x);
531 o->read (&bus, PCI_DEVFN(3, 0), PCI_IO_BASE_UPPER16, 4, &x);
532 o->read (&bus, PCI_DEVFN(3, 0), PCI_MEMORY_BASE, 4, &x);
533 o->read (&bus, PCI_DEVFN(3, 0), PCI_PREF_MEMORY_BASE, 4, &x);
534
535 o->write(&bus, PCI_DEVFN(3, 0), PCI_IO_BASE, 1, 0x01);
536 o->read (&bus, PCI_DEVFN(3, 0), PCI_IO_BASE, 1, &x);
537 o->write(&bus, PCI_DEVFN(3, 0), PCI_IO_BASE_UPPER16, 4, 0x00020000);
538 o->read (&bus, PCI_DEVFN(3, 0), PCI_IO_BASE_UPPER16, 4, &x);
539 o->write(&bus, PCI_DEVFN(3, 0), PCI_MEMORY_BASE, 4, 0xEBB0EA00);
540 o->read (&bus, PCI_DEVFN(3, 0), PCI_MEMORY_BASE, 4, &x);
541 o->write(&bus, PCI_DEVFN(3, 0), PCI_PREF_MEMORY_BASE, 4, 0xE9F0E800);
542 o->read (&bus, PCI_DEVFN(3, 0), PCI_PREF_MEMORY_BASE, 4, &x);
543
544 unit_disable_pcnet(&bus, o);
545}
diff --git a/arch/mn10300/unit-asb2305/unit-init.c b/arch/mn10300/unit-asb2305/unit-init.c
new file mode 100644
index 000000000000..6a352414a358
--- /dev/null
+++ b/arch/mn10300/unit-asb2305/unit-init.c
@@ -0,0 +1,61 @@
1/* ASB2305 Initialisation
2 *
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 */
11#include <linux/kernel.h>
12#include <linux/param.h>
13#include <linux/init.h>
14#include <linux/pci.h>
15#include <asm/io.h>
16#include <asm/setup.h>
17#include <asm/processor.h>
18#include <asm/cpu/intctl-regs.h>
19#include <asm/cpu/rtc-regs.h>
20#include <asm/cpu/serial-regs.h>
21#include <asm/unit/serial.h>
22
23/*
24 * initialise some of the unit hardware before gdbstub is set up
25 */
26asmlinkage void __init unit_init(void)
27{
28#ifndef CONFIG_GDBSTUB_ON_TTYSx
29 /* set the 16550 interrupt line to level 3 if not being used for GDB */
30 set_intr_level(XIRQ0, GxICR_LEVEL_3);
31#endif
32}
33
34/*
35 * initialise the rest of the unit hardware after gdbstub is ready
36 */
37void __init unit_setup(void)
38{
39#ifdef CONFIG_PCI
40 unit_pci_init();
41#endif
42}
43
44/*
45 * initialise the external interrupts used by a unit of this type
46 */
47void __init unit_init_IRQ(void)
48{
49 unsigned int extnum;
50
51 for (extnum = 0; extnum < NR_XIRQS; extnum++) {
52 switch (GET_XIRQ_TRIGGER(extnum)) {
53 case XIRQ_TRIGGER_HILEVEL:
54 case XIRQ_TRIGGER_LOWLEVEL:
55 set_irq_handler(XIRQ2IRQ(extnum), handle_level_irq);
56 break;
57 default:
58 break;
59 }
60 }
61}