diff options
Diffstat (limited to 'arch/arm/mach-footbridge')
23 files changed, 2666 insertions, 0 deletions
diff --git a/arch/arm/mach-footbridge/Kconfig b/arch/arm/mach-footbridge/Kconfig new file mode 100644 index 000000000000..1090c680b6dd --- /dev/null +++ b/arch/arm/mach-footbridge/Kconfig | |||
@@ -0,0 +1,80 @@ | |||
1 | if ARCH_FOOTBRIDGE | ||
2 | |||
3 | menu "Footbridge Implementations" | ||
4 | |||
5 | config ARCH_CATS | ||
6 | bool "CATS" | ||
7 | select FOOTBRIDGE_HOST | ||
8 | help | ||
9 | Say Y here if you intend to run this kernel on the CATS. | ||
10 | |||
11 | Saying N will reduce the size of the Footbridge kernel. | ||
12 | |||
13 | config ARCH_PERSONAL_SERVER | ||
14 | bool "Compaq Personal Server" | ||
15 | select FOOTBRIDGE_HOST | ||
16 | ---help--- | ||
17 | Say Y here if you intend to run this kernel on the Compaq | ||
18 | Personal Server. | ||
19 | |||
20 | Saying N will reduce the size of the Footbridge kernel. | ||
21 | |||
22 | The Compaq Personal Server is not available for purchase. | ||
23 | There are no product plans beyond the current research | ||
24 | prototypes at this time. Information is available at: | ||
25 | |||
26 | <http://www.crl.hpl.hp.com/projects/personalserver/> | ||
27 | |||
28 | If you have any questions or comments about the Compaq Personal | ||
29 | Server, send e-mail to <skiff@crl.dec.com>. | ||
30 | |||
31 | config ARCH_EBSA285_ADDIN | ||
32 | bool "EBSA285 (addin mode)" | ||
33 | select ARCH_EBSA285 | ||
34 | select FOOTBRIDGE_ADDIN | ||
35 | help | ||
36 | Say Y here if you intend to run this kernel on the EBSA285 card | ||
37 | in addin mode. | ||
38 | |||
39 | Saying N will reduce the size of the Footbridge kernel. | ||
40 | |||
41 | config ARCH_EBSA285_HOST | ||
42 | bool "EBSA285 (host mode)" | ||
43 | select ARCH_EBSA285 | ||
44 | select FOOTBRIDGE_HOST | ||
45 | help | ||
46 | Say Y here if you intend to run this kernel on the EBSA285 card | ||
47 | in host ("central function") mode. | ||
48 | |||
49 | Saying N will reduce the size of the Footbridge kernel. | ||
50 | |||
51 | config ARCH_NETWINDER | ||
52 | bool "NetWinder" | ||
53 | select FOOTBRIDGE_HOST | ||
54 | help | ||
55 | Say Y here if you intend to run this kernel on the Rebel.COM | ||
56 | NetWinder. Information about this machine can be found at: | ||
57 | |||
58 | <http://www.netwinder.org/> | ||
59 | |||
60 | Saying N will reduce the size of the Footbridge kernel. | ||
61 | |||
62 | endmenu | ||
63 | |||
64 | # Footbridge support | ||
65 | config FOOTBRIDGE | ||
66 | bool | ||
67 | |||
68 | # Footbridge in host mode | ||
69 | config FOOTBRIDGE_HOST | ||
70 | bool | ||
71 | |||
72 | # Footbridge in addin mode | ||
73 | config FOOTBRIDGE_ADDIN | ||
74 | bool | ||
75 | |||
76 | # EBSA285 board in either host or addin mode | ||
77 | config ARCH_EBSA285 | ||
78 | bool | ||
79 | |||
80 | endif | ||
diff --git a/arch/arm/mach-footbridge/Makefile b/arch/arm/mach-footbridge/Makefile new file mode 100644 index 000000000000..0694ad6b6476 --- /dev/null +++ b/arch/arm/mach-footbridge/Makefile | |||
@@ -0,0 +1,30 @@ | |||
1 | # | ||
2 | # Makefile for the linux kernel. | ||
3 | # | ||
4 | |||
5 | # Object file lists. | ||
6 | |||
7 | obj-y := common.o dc21285.o dma.o isa-irq.o time.o | ||
8 | obj-m := | ||
9 | obj-n := | ||
10 | obj- := | ||
11 | |||
12 | pci-$(CONFIG_ARCH_CATS) += cats-pci.o | ||
13 | pci-$(CONFIG_ARCH_EBSA285_HOST) += ebsa285-pci.o | ||
14 | pci-$(CONFIG_ARCH_NETWINDER) += netwinder-pci.o | ||
15 | pci-$(CONFIG_ARCH_PERSONAL_SERVER) += personal-pci.o | ||
16 | |||
17 | leds-$(CONFIG_ARCH_CO285) += ebsa285-leds.o | ||
18 | leds-$(CONFIG_ARCH_EBSA285) += ebsa285-leds.o | ||
19 | leds-$(CONFIG_ARCH_NETWINDER) += netwinder-leds.o | ||
20 | |||
21 | obj-$(CONFIG_ARCH_CATS) += cats-hw.o isa-timer.o | ||
22 | obj-$(CONFIG_ARCH_CO285) += co285.o dc21285-timer.o | ||
23 | obj-$(CONFIG_ARCH_EBSA285) += ebsa285.o dc21285-timer.o | ||
24 | obj-$(CONFIG_ARCH_NETWINDER) += netwinder-hw.o isa-timer.o | ||
25 | obj-$(CONFIG_ARCH_PERSONAL_SERVER) += personal.o dc21285-timer.o | ||
26 | |||
27 | obj-$(CONFIG_PCI) +=$(pci-y) | ||
28 | obj-$(CONFIG_LEDS) +=$(leds-y) | ||
29 | |||
30 | obj-$(CONFIG_ISA) += isa.o | ||
diff --git a/arch/arm/mach-footbridge/Makefile.boot b/arch/arm/mach-footbridge/Makefile.boot new file mode 100644 index 000000000000..c7e75acfe6c9 --- /dev/null +++ b/arch/arm/mach-footbridge/Makefile.boot | |||
@@ -0,0 +1,4 @@ | |||
1 | zreladdr-y := 0x00008000 | ||
2 | params_phys-y := 0x00000100 | ||
3 | initrd_phys-y := 0x00800000 | ||
4 | |||
diff --git a/arch/arm/mach-footbridge/cats-hw.c b/arch/arm/mach-footbridge/cats-hw.c new file mode 100644 index 000000000000..d1ced86c379c --- /dev/null +++ b/arch/arm/mach-footbridge/cats-hw.c | |||
@@ -0,0 +1,95 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-footbridge/cats-hw.c | ||
3 | * | ||
4 | * CATS machine fixup | ||
5 | * | ||
6 | * Copyright (C) 1998, 1999 Russell King, Phil Blundell | ||
7 | */ | ||
8 | #include <linux/ioport.h> | ||
9 | #include <linux/kernel.h> | ||
10 | #include <linux/init.h> | ||
11 | #include <linux/tty.h> | ||
12 | |||
13 | #include <asm/hardware/dec21285.h> | ||
14 | #include <asm/io.h> | ||
15 | #include <asm/mach-types.h> | ||
16 | #include <asm/setup.h> | ||
17 | |||
18 | #include <asm/mach/arch.h> | ||
19 | |||
20 | #include "common.h" | ||
21 | |||
22 | #define CFG_PORT 0x370 | ||
23 | #define INDEX_PORT (CFG_PORT) | ||
24 | #define DATA_PORT (CFG_PORT + 1) | ||
25 | |||
26 | static int __init cats_hw_init(void) | ||
27 | { | ||
28 | if (machine_is_cats()) { | ||
29 | /* Set Aladdin to CONFIGURE mode */ | ||
30 | outb(0x51, CFG_PORT); | ||
31 | outb(0x23, CFG_PORT); | ||
32 | |||
33 | /* Select logical device 3 */ | ||
34 | outb(0x07, INDEX_PORT); | ||
35 | outb(0x03, DATA_PORT); | ||
36 | |||
37 | /* Set parallel port to DMA channel 3, ECP+EPP1.9, | ||
38 | enable EPP timeout */ | ||
39 | outb(0x74, INDEX_PORT); | ||
40 | outb(0x03, DATA_PORT); | ||
41 | |||
42 | outb(0xf0, INDEX_PORT); | ||
43 | outb(0x0f, DATA_PORT); | ||
44 | |||
45 | outb(0xf1, INDEX_PORT); | ||
46 | outb(0x07, DATA_PORT); | ||
47 | |||
48 | /* Select logical device 4 */ | ||
49 | outb(0x07, INDEX_PORT); | ||
50 | outb(0x04, DATA_PORT); | ||
51 | |||
52 | /* UART1 high speed mode */ | ||
53 | outb(0xf0, INDEX_PORT); | ||
54 | outb(0x02, DATA_PORT); | ||
55 | |||
56 | /* Select logical device 5 */ | ||
57 | outb(0x07, INDEX_PORT); | ||
58 | outb(0x05, DATA_PORT); | ||
59 | |||
60 | /* UART2 high speed mode */ | ||
61 | outb(0xf0, INDEX_PORT); | ||
62 | outb(0x02, DATA_PORT); | ||
63 | |||
64 | /* Set Aladdin to RUN mode */ | ||
65 | outb(0xbb, CFG_PORT); | ||
66 | } | ||
67 | |||
68 | return 0; | ||
69 | } | ||
70 | |||
71 | __initcall(cats_hw_init); | ||
72 | |||
73 | /* | ||
74 | * CATS uses soft-reboot by default, since | ||
75 | * hard reboots fail on early boards. | ||
76 | */ | ||
77 | static void __init | ||
78 | fixup_cats(struct machine_desc *desc, struct tag *tags, | ||
79 | char **cmdline, struct meminfo *mi) | ||
80 | { | ||
81 | ORIG_VIDEO_LINES = 25; | ||
82 | ORIG_VIDEO_POINTS = 16; | ||
83 | ORIG_Y = 24; | ||
84 | } | ||
85 | |||
86 | MACHINE_START(CATS, "Chalice-CATS") | ||
87 | MAINTAINER("Philip Blundell") | ||
88 | BOOT_MEM(0x00000000, DC21285_ARMCSR_BASE, 0xfe000000) | ||
89 | BOOT_PARAMS(0x00000100) | ||
90 | SOFT_REBOOT | ||
91 | FIXUP(fixup_cats) | ||
92 | MAPIO(footbridge_map_io) | ||
93 | INITIRQ(footbridge_init_irq) | ||
94 | .timer = &isa_timer, | ||
95 | MACHINE_END | ||
diff --git a/arch/arm/mach-footbridge/cats-pci.c b/arch/arm/mach-footbridge/cats-pci.c new file mode 100644 index 000000000000..4f984fde7375 --- /dev/null +++ b/arch/arm/mach-footbridge/cats-pci.c | |||
@@ -0,0 +1,55 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-footbridge/cats-pci.c | ||
3 | * | ||
4 | * PCI bios-type initialisation for PCI machines | ||
5 | * | ||
6 | * Bits taken from various places. | ||
7 | */ | ||
8 | #include <linux/kernel.h> | ||
9 | #include <linux/pci.h> | ||
10 | #include <linux/init.h> | ||
11 | |||
12 | #include <asm/irq.h> | ||
13 | #include <asm/mach/pci.h> | ||
14 | #include <asm/mach-types.h> | ||
15 | |||
16 | /* cats host-specific stuff */ | ||
17 | static int irqmap_cats[] __initdata = { IRQ_PCI, IRQ_IN0, IRQ_IN1, IRQ_IN3 }; | ||
18 | |||
19 | static int __init cats_map_irq(struct pci_dev *dev, u8 slot, u8 pin) | ||
20 | { | ||
21 | if (dev->irq >= 128) | ||
22 | return dev->irq & 0x1f; | ||
23 | |||
24 | if (dev->irq >= 1 && dev->irq <= 4) | ||
25 | return irqmap_cats[dev->irq - 1]; | ||
26 | |||
27 | if (dev->irq != 0) | ||
28 | printk("PCI: device %02x:%02x has unknown irq line %x\n", | ||
29 | dev->bus->number, dev->devfn, dev->irq); | ||
30 | |||
31 | return -1; | ||
32 | } | ||
33 | |||
34 | /* | ||
35 | * why not the standard PCI swizzle? does this prevent 4-port tulip | ||
36 | * cards being used (ie, pci-pci bridge based cards)? | ||
37 | */ | ||
38 | static struct hw_pci cats_pci __initdata = { | ||
39 | .swizzle = NULL, | ||
40 | .map_irq = cats_map_irq, | ||
41 | .nr_controllers = 1, | ||
42 | .setup = dc21285_setup, | ||
43 | .scan = dc21285_scan_bus, | ||
44 | .preinit = dc21285_preinit, | ||
45 | .postinit = dc21285_postinit, | ||
46 | }; | ||
47 | |||
48 | static int cats_pci_init(void) | ||
49 | { | ||
50 | if (machine_is_cats()) | ||
51 | pci_common_init(&cats_pci); | ||
52 | return 0; | ||
53 | } | ||
54 | |||
55 | subsys_initcall(cats_pci_init); | ||
diff --git a/arch/arm/mach-footbridge/co285.c b/arch/arm/mach-footbridge/co285.c new file mode 100644 index 000000000000..e1541914fdcd --- /dev/null +++ b/arch/arm/mach-footbridge/co285.c | |||
@@ -0,0 +1,38 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-footbridge/co285.c | ||
3 | * | ||
4 | * CO285 machine fixup | ||
5 | */ | ||
6 | #include <linux/init.h> | ||
7 | |||
8 | #include <asm/hardware/dec21285.h> | ||
9 | #include <asm/mach-types.h> | ||
10 | |||
11 | #include <asm/mach/arch.h> | ||
12 | |||
13 | #include "common.h" | ||
14 | |||
15 | static void __init | ||
16 | fixup_coebsa285(struct machine_desc *desc, struct tag *tags, | ||
17 | char **cmdline, struct meminfo *mi) | ||
18 | { | ||
19 | extern unsigned long boot_memory_end; | ||
20 | extern char boot_command_line[]; | ||
21 | |||
22 | mi->nr_banks = 1; | ||
23 | mi->bank[0].start = PHYS_OFFSET; | ||
24 | mi->bank[0].size = boot_memory_end; | ||
25 | mi->bank[0].node = 0; | ||
26 | |||
27 | *cmdline = boot_command_line; | ||
28 | } | ||
29 | |||
30 | MACHINE_START(CO285, "co-EBSA285") | ||
31 | MAINTAINER("Mark van Doesburg") | ||
32 | BOOT_MEM(0x00000000, DC21285_ARMCSR_BASE, 0x7cf00000) | ||
33 | FIXUP(fixup_coebsa285) | ||
34 | MAPIO(footbridge_map_io) | ||
35 | INITIRQ(footbridge_init_irq) | ||
36 | .timer = &footbridge_timer, | ||
37 | MACHINE_END | ||
38 | |||
diff --git a/arch/arm/mach-footbridge/common.c b/arch/arm/mach-footbridge/common.c new file mode 100644 index 000000000000..eb8238c1ef06 --- /dev/null +++ b/arch/arm/mach-footbridge/common.c | |||
@@ -0,0 +1,205 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-footbridge/common.c | ||
3 | * | ||
4 | * Copyright (C) 1998-2000 Russell King, Dave Gilbert. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | #include <linux/config.h> | ||
11 | #include <linux/module.h> | ||
12 | #include <linux/types.h> | ||
13 | #include <linux/mm.h> | ||
14 | #include <linux/ioport.h> | ||
15 | #include <linux/list.h> | ||
16 | #include <linux/init.h> | ||
17 | |||
18 | #include <asm/pgtable.h> | ||
19 | #include <asm/page.h> | ||
20 | #include <asm/irq.h> | ||
21 | #include <asm/io.h> | ||
22 | #include <asm/mach-types.h> | ||
23 | #include <asm/setup.h> | ||
24 | #include <asm/hardware/dec21285.h> | ||
25 | |||
26 | #include <asm/mach/irq.h> | ||
27 | #include <asm/mach/map.h> | ||
28 | |||
29 | #include "common.h" | ||
30 | |||
31 | extern void __init isa_init_irq(unsigned int irq); | ||
32 | |||
33 | unsigned int mem_fclk_21285 = 50000000; | ||
34 | |||
35 | EXPORT_SYMBOL(mem_fclk_21285); | ||
36 | |||
37 | static int __init parse_tag_memclk(const struct tag *tag) | ||
38 | { | ||
39 | mem_fclk_21285 = tag->u.memclk.fmemclk; | ||
40 | return 0; | ||
41 | } | ||
42 | |||
43 | __tagtable(ATAG_MEMCLK, parse_tag_memclk); | ||
44 | |||
45 | /* | ||
46 | * Footbridge IRQ translation table | ||
47 | * Converts from our IRQ numbers into FootBridge masks | ||
48 | */ | ||
49 | static const int fb_irq_mask[] = { | ||
50 | IRQ_MASK_UART_RX, /* 0 */ | ||
51 | IRQ_MASK_UART_TX, /* 1 */ | ||
52 | IRQ_MASK_TIMER1, /* 2 */ | ||
53 | IRQ_MASK_TIMER2, /* 3 */ | ||
54 | IRQ_MASK_TIMER3, /* 4 */ | ||
55 | IRQ_MASK_IN0, /* 5 */ | ||
56 | IRQ_MASK_IN1, /* 6 */ | ||
57 | IRQ_MASK_IN2, /* 7 */ | ||
58 | IRQ_MASK_IN3, /* 8 */ | ||
59 | IRQ_MASK_DOORBELLHOST, /* 9 */ | ||
60 | IRQ_MASK_DMA1, /* 10 */ | ||
61 | IRQ_MASK_DMA2, /* 11 */ | ||
62 | IRQ_MASK_PCI, /* 12 */ | ||
63 | IRQ_MASK_SDRAMPARITY, /* 13 */ | ||
64 | IRQ_MASK_I2OINPOST, /* 14 */ | ||
65 | IRQ_MASK_PCI_ABORT, /* 15 */ | ||
66 | IRQ_MASK_PCI_SERR, /* 16 */ | ||
67 | IRQ_MASK_DISCARD_TIMER, /* 17 */ | ||
68 | IRQ_MASK_PCI_DPERR, /* 18 */ | ||
69 | IRQ_MASK_PCI_PERR, /* 19 */ | ||
70 | }; | ||
71 | |||
72 | static void fb_mask_irq(unsigned int irq) | ||
73 | { | ||
74 | *CSR_IRQ_DISABLE = fb_irq_mask[_DC21285_INR(irq)]; | ||
75 | } | ||
76 | |||
77 | static void fb_unmask_irq(unsigned int irq) | ||
78 | { | ||
79 | *CSR_IRQ_ENABLE = fb_irq_mask[_DC21285_INR(irq)]; | ||
80 | } | ||
81 | |||
82 | static struct irqchip fb_chip = { | ||
83 | .ack = fb_mask_irq, | ||
84 | .mask = fb_mask_irq, | ||
85 | .unmask = fb_unmask_irq, | ||
86 | }; | ||
87 | |||
88 | static void __init __fb_init_irq(void) | ||
89 | { | ||
90 | unsigned int irq; | ||
91 | |||
92 | /* | ||
93 | * setup DC21285 IRQs | ||
94 | */ | ||
95 | *CSR_IRQ_DISABLE = -1; | ||
96 | *CSR_FIQ_DISABLE = -1; | ||
97 | |||
98 | for (irq = _DC21285_IRQ(0); irq < _DC21285_IRQ(20); irq++) { | ||
99 | set_irq_chip(irq, &fb_chip); | ||
100 | set_irq_handler(irq, do_level_IRQ); | ||
101 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); | ||
102 | } | ||
103 | } | ||
104 | |||
105 | void __init footbridge_init_irq(void) | ||
106 | { | ||
107 | __fb_init_irq(); | ||
108 | |||
109 | if (!footbridge_cfn_mode()) | ||
110 | return; | ||
111 | |||
112 | if (machine_is_ebsa285()) | ||
113 | /* The following is dependent on which slot | ||
114 | * you plug the Southbridge card into. We | ||
115 | * currently assume that you plug it into | ||
116 | * the right-hand most slot. | ||
117 | */ | ||
118 | isa_init_irq(IRQ_PCI); | ||
119 | |||
120 | if (machine_is_cats()) | ||
121 | isa_init_irq(IRQ_IN2); | ||
122 | |||
123 | if (machine_is_netwinder()) | ||
124 | isa_init_irq(IRQ_IN3); | ||
125 | } | ||
126 | |||
127 | /* | ||
128 | * Common mapping for all systems. Note that the outbound write flush is | ||
129 | * commented out since there is a "No Fix" problem with it. Not mapping | ||
130 | * it means that we have extra bullet protection on our feet. | ||
131 | */ | ||
132 | static struct map_desc fb_common_io_desc[] __initdata = { | ||
133 | { ARMCSR_BASE, DC21285_ARMCSR_BASE, ARMCSR_SIZE, MT_DEVICE }, | ||
134 | { XBUS_BASE, 0x40000000, XBUS_SIZE, MT_DEVICE } | ||
135 | }; | ||
136 | |||
137 | /* | ||
138 | * The mapping when the footbridge is in host mode. We don't map any of | ||
139 | * this when we are in add-in mode. | ||
140 | */ | ||
141 | static struct map_desc ebsa285_host_io_desc[] __initdata = { | ||
142 | #if defined(CONFIG_ARCH_FOOTBRIDGE) && defined(CONFIG_FOOTBRIDGE_HOST) | ||
143 | { PCIMEM_BASE, DC21285_PCI_MEM, PCIMEM_SIZE, MT_DEVICE }, | ||
144 | { PCICFG0_BASE, DC21285_PCI_TYPE_0_CONFIG, PCICFG0_SIZE, MT_DEVICE }, | ||
145 | { PCICFG1_BASE, DC21285_PCI_TYPE_1_CONFIG, PCICFG1_SIZE, MT_DEVICE }, | ||
146 | { PCIIACK_BASE, DC21285_PCI_IACK, PCIIACK_SIZE, MT_DEVICE }, | ||
147 | { PCIO_BASE, DC21285_PCI_IO, PCIO_SIZE, MT_DEVICE } | ||
148 | #endif | ||
149 | }; | ||
150 | |||
151 | /* | ||
152 | * The CO-ebsa285 mapping. | ||
153 | */ | ||
154 | static struct map_desc co285_io_desc[] __initdata = { | ||
155 | #ifdef CONFIG_ARCH_CO285 | ||
156 | { PCIO_BASE, DC21285_PCI_IO, PCIO_SIZE, MT_DEVICE }, | ||
157 | { PCIMEM_BASE, DC21285_PCI_MEM, PCIMEM_SIZE, MT_DEVICE } | ||
158 | #endif | ||
159 | }; | ||
160 | |||
161 | void __init footbridge_map_io(void) | ||
162 | { | ||
163 | /* | ||
164 | * Set up the common mapping first; we need this to | ||
165 | * determine whether we're in host mode or not. | ||
166 | */ | ||
167 | iotable_init(fb_common_io_desc, ARRAY_SIZE(fb_common_io_desc)); | ||
168 | |||
169 | /* | ||
170 | * Now, work out what we've got to map in addition on this | ||
171 | * platform. | ||
172 | */ | ||
173 | if (machine_is_co285()) | ||
174 | iotable_init(co285_io_desc, ARRAY_SIZE(co285_io_desc)); | ||
175 | if (footbridge_cfn_mode()) | ||
176 | iotable_init(ebsa285_host_io_desc, ARRAY_SIZE(ebsa285_host_io_desc)); | ||
177 | } | ||
178 | |||
179 | #ifdef CONFIG_FOOTBRIDGE_ADDIN | ||
180 | |||
181 | /* | ||
182 | * These two functions convert virtual addresses to PCI addresses and PCI | ||
183 | * addresses to virtual addresses. Note that it is only legal to use these | ||
184 | * on memory obtained via get_zeroed_page or kmalloc. | ||
185 | */ | ||
186 | unsigned long __virt_to_bus(unsigned long res) | ||
187 | { | ||
188 | WARN_ON(res < PAGE_OFFSET || res >= (unsigned long)high_memory); | ||
189 | |||
190 | return (res - PAGE_OFFSET) + (*CSR_PCISDRAMBASE & 0xfffffff0); | ||
191 | } | ||
192 | EXPORT_SYMBOL(__virt_to_bus); | ||
193 | |||
194 | unsigned long __bus_to_virt(unsigned long res) | ||
195 | { | ||
196 | res -= (*CSR_PCISDRAMBASE & 0xfffffff0); | ||
197 | res += PAGE_OFFSET; | ||
198 | |||
199 | WARN_ON(res < PAGE_OFFSET || res >= (unsigned long)high_memory); | ||
200 | |||
201 | return res; | ||
202 | } | ||
203 | EXPORT_SYMBOL(__bus_to_virt); | ||
204 | |||
205 | #endif | ||
diff --git a/arch/arm/mach-footbridge/common.h b/arch/arm/mach-footbridge/common.h new file mode 100644 index 000000000000..580e31bbc711 --- /dev/null +++ b/arch/arm/mach-footbridge/common.h | |||
@@ -0,0 +1,9 @@ | |||
1 | |||
2 | extern struct sys_timer footbridge_timer; | ||
3 | extern struct sys_timer isa_timer; | ||
4 | |||
5 | extern void isa_rtc_init(void); | ||
6 | |||
7 | extern void footbridge_map_io(void); | ||
8 | extern void footbridge_init_irq(void); | ||
9 | |||
diff --git a/arch/arm/mach-footbridge/dc21285-timer.c b/arch/arm/mach-footbridge/dc21285-timer.c new file mode 100644 index 000000000000..580e1d4bce08 --- /dev/null +++ b/arch/arm/mach-footbridge/dc21285-timer.c | |||
@@ -0,0 +1,68 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-footbridge/dc21285-timer.c | ||
3 | * | ||
4 | * Copyright (C) 1998 Russell King. | ||
5 | * Copyright (C) 1998 Phil Blundell | ||
6 | */ | ||
7 | #include <linux/init.h> | ||
8 | #include <linux/interrupt.h> | ||
9 | |||
10 | #include <asm/irq.h> | ||
11 | |||
12 | #include <asm/hardware/dec21285.h> | ||
13 | #include <asm/mach/time.h> | ||
14 | |||
15 | #include "common.h" | ||
16 | |||
17 | /* | ||
18 | * Footbridge timer 1 support. | ||
19 | */ | ||
20 | static unsigned long timer1_latch; | ||
21 | |||
22 | static unsigned long timer1_gettimeoffset (void) | ||
23 | { | ||
24 | unsigned long value = timer1_latch - *CSR_TIMER1_VALUE; | ||
25 | |||
26 | return ((tick_nsec / 1000) * value) / timer1_latch; | ||
27 | } | ||
28 | |||
29 | static irqreturn_t | ||
30 | timer1_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
31 | { | ||
32 | write_seqlock(&xtime_lock); | ||
33 | |||
34 | *CSR_TIMER1_CLR = 0; | ||
35 | |||
36 | timer_tick(regs); | ||
37 | |||
38 | write_sequnlock(&xtime_lock); | ||
39 | |||
40 | return IRQ_HANDLED; | ||
41 | } | ||
42 | |||
43 | static struct irqaction footbridge_timer_irq = { | ||
44 | .name = "Timer1 timer tick", | ||
45 | .handler = timer1_interrupt, | ||
46 | .flags = SA_INTERRUPT, | ||
47 | }; | ||
48 | |||
49 | /* | ||
50 | * Set up timer interrupt. | ||
51 | */ | ||
52 | static void __init footbridge_timer_init(void) | ||
53 | { | ||
54 | isa_rtc_init(); | ||
55 | |||
56 | timer1_latch = (mem_fclk_21285 + 8 * HZ) / (16 * HZ); | ||
57 | |||
58 | *CSR_TIMER1_CLR = 0; | ||
59 | *CSR_TIMER1_LOAD = timer1_latch; | ||
60 | *CSR_TIMER1_CNTL = TIMER_CNTL_ENABLE | TIMER_CNTL_AUTORELOAD | TIMER_CNTL_DIV16; | ||
61 | |||
62 | setup_irq(IRQ_TIMER1, &footbridge_timer_irq); | ||
63 | } | ||
64 | |||
65 | struct sys_timer footbridge_timer = { | ||
66 | .init = footbridge_timer_init, | ||
67 | .offset = timer1_gettimeoffset, | ||
68 | }; | ||
diff --git a/arch/arm/mach-footbridge/dc21285.c b/arch/arm/mach-footbridge/dc21285.c new file mode 100644 index 000000000000..e79884eea1f7 --- /dev/null +++ b/arch/arm/mach-footbridge/dc21285.c | |||
@@ -0,0 +1,384 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/kernel/dec21285.c: PCI functions for DC21285 | ||
3 | * | ||
4 | * Copyright (C) 1998-2001 Russell King | ||
5 | * Copyright (C) 1998-2000 Phil Blundell | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/pci.h> | ||
13 | #include <linux/ptrace.h> | ||
14 | #include <linux/interrupt.h> | ||
15 | #include <linux/mm.h> | ||
16 | #include <linux/slab.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <linux/ioport.h> | ||
19 | |||
20 | #include <asm/io.h> | ||
21 | #include <asm/irq.h> | ||
22 | #include <asm/system.h> | ||
23 | #include <asm/mach/pci.h> | ||
24 | #include <asm/hardware/dec21285.h> | ||
25 | |||
26 | #define MAX_SLOTS 21 | ||
27 | |||
28 | #define PCICMD_ABORT ((PCI_STATUS_REC_MASTER_ABORT| \ | ||
29 | PCI_STATUS_REC_TARGET_ABORT)<<16) | ||
30 | |||
31 | #define PCICMD_ERROR_BITS ((PCI_STATUS_DETECTED_PARITY | \ | ||
32 | PCI_STATUS_REC_MASTER_ABORT | \ | ||
33 | PCI_STATUS_REC_TARGET_ABORT | \ | ||
34 | PCI_STATUS_PARITY) << 16) | ||
35 | |||
36 | extern int setup_arm_irq(int, struct irqaction *); | ||
37 | extern void pcibios_report_status(u_int status_mask, int warn); | ||
38 | extern void register_isa_ports(unsigned int, unsigned int, unsigned int); | ||
39 | |||
40 | static unsigned long | ||
41 | dc21285_base_address(struct pci_bus *bus, unsigned int devfn) | ||
42 | { | ||
43 | unsigned long addr = 0; | ||
44 | |||
45 | if (bus->number == 0) { | ||
46 | if (PCI_SLOT(devfn) == 0) | ||
47 | /* | ||
48 | * For devfn 0, point at the 21285 | ||
49 | */ | ||
50 | addr = ARMCSR_BASE; | ||
51 | else { | ||
52 | devfn -= 1 << 3; | ||
53 | |||
54 | if (devfn < PCI_DEVFN(MAX_SLOTS, 0)) | ||
55 | addr = PCICFG0_BASE | 0xc00000 | (devfn << 8); | ||
56 | } | ||
57 | } else | ||
58 | addr = PCICFG1_BASE | (bus->number << 16) | (devfn << 8); | ||
59 | |||
60 | return addr; | ||
61 | } | ||
62 | |||
63 | static int | ||
64 | dc21285_read_config(struct pci_bus *bus, unsigned int devfn, int where, | ||
65 | int size, u32 *value) | ||
66 | { | ||
67 | unsigned long addr = dc21285_base_address(bus, devfn); | ||
68 | u32 v = 0xffffffff; | ||
69 | |||
70 | if (addr) | ||
71 | switch (size) { | ||
72 | case 1: | ||
73 | asm("ldr%?b %0, [%1, %2]" | ||
74 | : "=r" (v) : "r" (addr), "r" (where)); | ||
75 | break; | ||
76 | case 2: | ||
77 | asm("ldr%?h %0, [%1, %2]" | ||
78 | : "=r" (v) : "r" (addr), "r" (where)); | ||
79 | break; | ||
80 | case 4: | ||
81 | asm("ldr%? %0, [%1, %2]" | ||
82 | : "=r" (v) : "r" (addr), "r" (where)); | ||
83 | break; | ||
84 | } | ||
85 | |||
86 | *value = v; | ||
87 | |||
88 | v = *CSR_PCICMD; | ||
89 | if (v & PCICMD_ABORT) { | ||
90 | *CSR_PCICMD = v & (0xffff|PCICMD_ABORT); | ||
91 | return -1; | ||
92 | } | ||
93 | |||
94 | return PCIBIOS_SUCCESSFUL; | ||
95 | } | ||
96 | |||
97 | static int | ||
98 | dc21285_write_config(struct pci_bus *bus, unsigned int devfn, int where, | ||
99 | int size, u32 value) | ||
100 | { | ||
101 | unsigned long addr = dc21285_base_address(bus, devfn); | ||
102 | u32 v; | ||
103 | |||
104 | if (addr) | ||
105 | switch (size) { | ||
106 | case 1: | ||
107 | asm("str%?b %0, [%1, %2]" | ||
108 | : : "r" (value), "r" (addr), "r" (where)); | ||
109 | break; | ||
110 | case 2: | ||
111 | asm("str%?h %0, [%1, %2]" | ||
112 | : : "r" (value), "r" (addr), "r" (where)); | ||
113 | break; | ||
114 | case 4: | ||
115 | asm("str%? %0, [%1, %2]" | ||
116 | : : "r" (value), "r" (addr), "r" (where)); | ||
117 | break; | ||
118 | } | ||
119 | |||
120 | v = *CSR_PCICMD; | ||
121 | if (v & PCICMD_ABORT) { | ||
122 | *CSR_PCICMD = v & (0xffff|PCICMD_ABORT); | ||
123 | return -1; | ||
124 | } | ||
125 | |||
126 | return PCIBIOS_SUCCESSFUL; | ||
127 | } | ||
128 | |||
129 | static struct pci_ops dc21285_ops = { | ||
130 | .read = dc21285_read_config, | ||
131 | .write = dc21285_write_config, | ||
132 | }; | ||
133 | |||
134 | static struct timer_list serr_timer; | ||
135 | static struct timer_list perr_timer; | ||
136 | |||
137 | static void dc21285_enable_error(unsigned long __data) | ||
138 | { | ||
139 | switch (__data) { | ||
140 | case IRQ_PCI_SERR: | ||
141 | del_timer(&serr_timer); | ||
142 | break; | ||
143 | |||
144 | case IRQ_PCI_PERR: | ||
145 | del_timer(&perr_timer); | ||
146 | break; | ||
147 | } | ||
148 | |||
149 | enable_irq(__data); | ||
150 | } | ||
151 | |||
152 | /* | ||
153 | * Warn on PCI errors. | ||
154 | */ | ||
155 | static irqreturn_t dc21285_abort_irq(int irq, void *dev_id, struct pt_regs *regs) | ||
156 | { | ||
157 | unsigned int cmd; | ||
158 | unsigned int status; | ||
159 | |||
160 | cmd = *CSR_PCICMD; | ||
161 | status = cmd >> 16; | ||
162 | cmd = cmd & 0xffff; | ||
163 | |||
164 | if (status & PCI_STATUS_REC_MASTER_ABORT) { | ||
165 | printk(KERN_DEBUG "PCI: master abort, pc=0x%08lx\n", | ||
166 | instruction_pointer(regs)); | ||
167 | cmd |= PCI_STATUS_REC_MASTER_ABORT << 16; | ||
168 | } | ||
169 | |||
170 | if (status & PCI_STATUS_REC_TARGET_ABORT) { | ||
171 | printk(KERN_DEBUG "PCI: target abort: "); | ||
172 | pcibios_report_status(PCI_STATUS_REC_MASTER_ABORT | | ||
173 | PCI_STATUS_SIG_TARGET_ABORT | | ||
174 | PCI_STATUS_REC_TARGET_ABORT, 1); | ||
175 | printk("\n"); | ||
176 | |||
177 | cmd |= PCI_STATUS_REC_TARGET_ABORT << 16; | ||
178 | } | ||
179 | |||
180 | *CSR_PCICMD = cmd; | ||
181 | |||
182 | return IRQ_HANDLED; | ||
183 | } | ||
184 | |||
185 | static irqreturn_t dc21285_serr_irq(int irq, void *dev_id, struct pt_regs *regs) | ||
186 | { | ||
187 | struct timer_list *timer = dev_id; | ||
188 | unsigned int cntl; | ||
189 | |||
190 | printk(KERN_DEBUG "PCI: system error received: "); | ||
191 | pcibios_report_status(PCI_STATUS_SIG_SYSTEM_ERROR, 1); | ||
192 | printk("\n"); | ||
193 | |||
194 | cntl = *CSR_SA110_CNTL & 0xffffdf07; | ||
195 | *CSR_SA110_CNTL = cntl | SA110_CNTL_RXSERR; | ||
196 | |||
197 | /* | ||
198 | * back off this interrupt | ||
199 | */ | ||
200 | disable_irq(irq); | ||
201 | timer->expires = jiffies + HZ; | ||
202 | add_timer(timer); | ||
203 | |||
204 | return IRQ_HANDLED; | ||
205 | } | ||
206 | |||
207 | static irqreturn_t dc21285_discard_irq(int irq, void *dev_id, struct pt_regs *regs) | ||
208 | { | ||
209 | printk(KERN_DEBUG "PCI: discard timer expired\n"); | ||
210 | *CSR_SA110_CNTL &= 0xffffde07; | ||
211 | |||
212 | return IRQ_HANDLED; | ||
213 | } | ||
214 | |||
215 | static irqreturn_t dc21285_dparity_irq(int irq, void *dev_id, struct pt_regs *regs) | ||
216 | { | ||
217 | unsigned int cmd; | ||
218 | |||
219 | printk(KERN_DEBUG "PCI: data parity error detected: "); | ||
220 | pcibios_report_status(PCI_STATUS_PARITY | PCI_STATUS_DETECTED_PARITY, 1); | ||
221 | printk("\n"); | ||
222 | |||
223 | cmd = *CSR_PCICMD & 0xffff; | ||
224 | *CSR_PCICMD = cmd | 1 << 24; | ||
225 | |||
226 | return IRQ_HANDLED; | ||
227 | } | ||
228 | |||
229 | static irqreturn_t dc21285_parity_irq(int irq, void *dev_id, struct pt_regs *regs) | ||
230 | { | ||
231 | struct timer_list *timer = dev_id; | ||
232 | unsigned int cmd; | ||
233 | |||
234 | printk(KERN_DEBUG "PCI: parity error detected: "); | ||
235 | pcibios_report_status(PCI_STATUS_PARITY | PCI_STATUS_DETECTED_PARITY, 1); | ||
236 | printk("\n"); | ||
237 | |||
238 | cmd = *CSR_PCICMD & 0xffff; | ||
239 | *CSR_PCICMD = cmd | 1 << 31; | ||
240 | |||
241 | /* | ||
242 | * back off this interrupt | ||
243 | */ | ||
244 | disable_irq(irq); | ||
245 | timer->expires = jiffies + HZ; | ||
246 | add_timer(timer); | ||
247 | |||
248 | return IRQ_HANDLED; | ||
249 | } | ||
250 | |||
251 | int __init dc21285_setup(int nr, struct pci_sys_data *sys) | ||
252 | { | ||
253 | struct resource *res; | ||
254 | |||
255 | if (nr || !footbridge_cfn_mode()) | ||
256 | return 0; | ||
257 | |||
258 | res = kmalloc(sizeof(struct resource) * 2, GFP_KERNEL); | ||
259 | if (!res) { | ||
260 | printk("out of memory for root bus resources"); | ||
261 | return 0; | ||
262 | } | ||
263 | |||
264 | memset(res, 0, sizeof(struct resource) * 2); | ||
265 | |||
266 | res[0].flags = IORESOURCE_MEM; | ||
267 | res[0].name = "Footbridge non-prefetch"; | ||
268 | res[1].flags = IORESOURCE_MEM | IORESOURCE_PREFETCH; | ||
269 | res[1].name = "Footbridge prefetch"; | ||
270 | |||
271 | allocate_resource(&iomem_resource, &res[1], 0x20000000, | ||
272 | 0xa0000000, 0xffffffff, 0x20000000, NULL, NULL); | ||
273 | allocate_resource(&iomem_resource, &res[0], 0x40000000, | ||
274 | 0x80000000, 0xffffffff, 0x40000000, NULL, NULL); | ||
275 | |||
276 | sys->resource[0] = &ioport_resource; | ||
277 | sys->resource[1] = &res[0]; | ||
278 | sys->resource[2] = &res[1]; | ||
279 | sys->mem_offset = DC21285_PCI_MEM; | ||
280 | |||
281 | return 1; | ||
282 | } | ||
283 | |||
284 | struct pci_bus * __init dc21285_scan_bus(int nr, struct pci_sys_data *sys) | ||
285 | { | ||
286 | return pci_scan_bus(0, &dc21285_ops, sys); | ||
287 | } | ||
288 | |||
289 | void __init dc21285_preinit(void) | ||
290 | { | ||
291 | unsigned int mem_size, mem_mask; | ||
292 | int cfn_mode; | ||
293 | |||
294 | mem_size = (unsigned int)high_memory - PAGE_OFFSET; | ||
295 | for (mem_mask = 0x00100000; mem_mask < 0x10000000; mem_mask <<= 1) | ||
296 | if (mem_mask >= mem_size) | ||
297 | break; | ||
298 | |||
299 | /* | ||
300 | * These registers need to be set up whether we're the | ||
301 | * central function or not. | ||
302 | */ | ||
303 | *CSR_SDRAMBASEMASK = (mem_mask - 1) & 0x0ffc0000; | ||
304 | *CSR_SDRAMBASEOFFSET = 0; | ||
305 | *CSR_ROMBASEMASK = 0x80000000; | ||
306 | *CSR_CSRBASEMASK = 0; | ||
307 | *CSR_CSRBASEOFFSET = 0; | ||
308 | *CSR_PCIADDR_EXTN = 0; | ||
309 | |||
310 | cfn_mode = __footbridge_cfn_mode(); | ||
311 | |||
312 | printk(KERN_INFO "PCI: DC21285 footbridge, revision %02lX, in " | ||
313 | "%s mode\n", *CSR_CLASSREV & 0xff, cfn_mode ? | ||
314 | "central function" : "addin"); | ||
315 | |||
316 | if (footbridge_cfn_mode()) { | ||
317 | /* | ||
318 | * Clear any existing errors - we aren't | ||
319 | * interested in historical data... | ||
320 | */ | ||
321 | *CSR_SA110_CNTL = (*CSR_SA110_CNTL & 0xffffde07) | | ||
322 | SA110_CNTL_RXSERR; | ||
323 | *CSR_PCICMD = (*CSR_PCICMD & 0xffff) | PCICMD_ERROR_BITS; | ||
324 | } | ||
325 | |||
326 | init_timer(&serr_timer); | ||
327 | init_timer(&perr_timer); | ||
328 | |||
329 | serr_timer.data = IRQ_PCI_SERR; | ||
330 | serr_timer.function = dc21285_enable_error; | ||
331 | perr_timer.data = IRQ_PCI_PERR; | ||
332 | perr_timer.function = dc21285_enable_error; | ||
333 | |||
334 | /* | ||
335 | * We don't care if these fail. | ||
336 | */ | ||
337 | request_irq(IRQ_PCI_SERR, dc21285_serr_irq, SA_INTERRUPT, | ||
338 | "PCI system error", &serr_timer); | ||
339 | request_irq(IRQ_PCI_PERR, dc21285_parity_irq, SA_INTERRUPT, | ||
340 | "PCI parity error", &perr_timer); | ||
341 | request_irq(IRQ_PCI_ABORT, dc21285_abort_irq, SA_INTERRUPT, | ||
342 | "PCI abort", NULL); | ||
343 | request_irq(IRQ_DISCARD_TIMER, dc21285_discard_irq, SA_INTERRUPT, | ||
344 | "Discard timer", NULL); | ||
345 | request_irq(IRQ_PCI_DPERR, dc21285_dparity_irq, SA_INTERRUPT, | ||
346 | "PCI data parity", NULL); | ||
347 | |||
348 | if (cfn_mode) { | ||
349 | static struct resource csrio; | ||
350 | |||
351 | csrio.flags = IORESOURCE_IO; | ||
352 | csrio.name = "Footbridge"; | ||
353 | |||
354 | allocate_resource(&ioport_resource, &csrio, 128, | ||
355 | 0xff00, 0xffff, 128, NULL, NULL); | ||
356 | |||
357 | /* | ||
358 | * Map our SDRAM at a known address in PCI space, just in case | ||
359 | * the firmware had other ideas. Using a nonzero base is | ||
360 | * necessary, since some VGA cards forcefully use PCI addresses | ||
361 | * in the range 0x000a0000 to 0x000c0000. (eg, S3 cards). | ||
362 | */ | ||
363 | *CSR_PCICSRBASE = 0xf4000000; | ||
364 | *CSR_PCICSRIOBASE = csrio.start; | ||
365 | *CSR_PCISDRAMBASE = __virt_to_bus(PAGE_OFFSET); | ||
366 | *CSR_PCIROMBASE = 0; | ||
367 | *CSR_PCICMD = PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | | ||
368 | PCI_COMMAND_INVALIDATE | PCICMD_ERROR_BITS; | ||
369 | } else if (footbridge_cfn_mode() != 0) { | ||
370 | /* | ||
371 | * If we are not compiled to accept "add-in" mode, then | ||
372 | * we are using a constant virt_to_bus translation which | ||
373 | * can not hope to cater for the way the host BIOS has | ||
374 | * set up the machine. | ||
375 | */ | ||
376 | panic("PCI: this kernel is compiled for central " | ||
377 | "function mode only"); | ||
378 | } | ||
379 | } | ||
380 | |||
381 | void __init dc21285_postinit(void) | ||
382 | { | ||
383 | register_isa_ports(DC21285_PCI_MEM, DC21285_PCI_IO, 0); | ||
384 | } | ||
diff --git a/arch/arm/mach-footbridge/dma.c b/arch/arm/mach-footbridge/dma.c new file mode 100644 index 000000000000..a6b1396b0951 --- /dev/null +++ b/arch/arm/mach-footbridge/dma.c | |||
@@ -0,0 +1,54 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/kernel/dma-ebsa285.c | ||
3 | * | ||
4 | * Copyright (C) 1998 Phil Blundell | ||
5 | * | ||
6 | * DMA functions specific to EBSA-285/CATS architectures | ||
7 | * | ||
8 | * Changelog: | ||
9 | * 09-Nov-1998 RMK Split out ISA DMA functions to dma-isa.c | ||
10 | * 17-Mar-1999 RMK Allow any EBSA285-like architecture to have | ||
11 | * ISA DMA controllers. | ||
12 | */ | ||
13 | #include <linux/config.h> | ||
14 | #include <linux/init.h> | ||
15 | |||
16 | #include <asm/dma.h> | ||
17 | #include <asm/io.h> | ||
18 | |||
19 | #include <asm/mach/dma.h> | ||
20 | #include <asm/hardware/dec21285.h> | ||
21 | |||
22 | #if 0 | ||
23 | static int fb_dma_request(dmach_t channel, dma_t *dma) | ||
24 | { | ||
25 | return -EINVAL; | ||
26 | } | ||
27 | |||
28 | static void fb_dma_enable(dmach_t channel, dma_t *dma) | ||
29 | { | ||
30 | } | ||
31 | |||
32 | static void fb_dma_disable(dmach_t channel, dma_t *dma) | ||
33 | { | ||
34 | } | ||
35 | |||
36 | static struct dma_ops fb_dma_ops = { | ||
37 | .type = "fb", | ||
38 | .request = fb_dma_request, | ||
39 | .enable = fb_dma_enable, | ||
40 | .disable = fb_dma_disable, | ||
41 | }; | ||
42 | #endif | ||
43 | |||
44 | void __init arch_dma_init(dma_t *dma) | ||
45 | { | ||
46 | #if 0 | ||
47 | dma[_DC21285_DMA(0)].d_ops = &fb_dma_ops; | ||
48 | dma[_DC21285_DMA(1)].d_ops = &fb_dma_ops; | ||
49 | #endif | ||
50 | #ifdef CONFIG_ISA_DMA | ||
51 | if (footbridge_cfn_mode()) | ||
52 | isa_init_dma(dma + _ISA_DMA(0)); | ||
53 | #endif | ||
54 | } | ||
diff --git a/arch/arm/mach-footbridge/ebsa285-leds.c b/arch/arm/mach-footbridge/ebsa285-leds.c new file mode 100644 index 000000000000..2c7c3630401b --- /dev/null +++ b/arch/arm/mach-footbridge/ebsa285-leds.c | |||
@@ -0,0 +1,140 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-footbridge/ebsa285-leds.c | ||
3 | * | ||
4 | * Copyright (C) 1998-1999 Russell King | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * EBSA-285 control routines. | ||
10 | * | ||
11 | * The EBSA-285 uses the leds as follows: | ||
12 | * - Green - toggles state every 50 timer interrupts | ||
13 | * - Amber - On if system is not idle | ||
14 | * - Red - currently unused | ||
15 | * | ||
16 | * Changelog: | ||
17 | * 02-05-1999 RMK Various cleanups | ||
18 | */ | ||
19 | #include <linux/config.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/kernel.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <linux/spinlock.h> | ||
24 | |||
25 | #include <asm/hardware.h> | ||
26 | #include <asm/leds.h> | ||
27 | #include <asm/mach-types.h> | ||
28 | #include <asm/system.h> | ||
29 | |||
30 | #define LED_STATE_ENABLED 1 | ||
31 | #define LED_STATE_CLAIMED 2 | ||
32 | static char led_state; | ||
33 | static char hw_led_state; | ||
34 | |||
35 | static DEFINE_SPINLOCK(leds_lock); | ||
36 | |||
37 | static void ebsa285_leds_event(led_event_t evt) | ||
38 | { | ||
39 | unsigned long flags; | ||
40 | |||
41 | spin_lock_irqsave(&leds_lock, flags); | ||
42 | |||
43 | switch (evt) { | ||
44 | case led_start: | ||
45 | hw_led_state = XBUS_LED_RED | XBUS_LED_GREEN; | ||
46 | #ifndef CONFIG_LEDS_CPU | ||
47 | hw_led_state |= XBUS_LED_AMBER; | ||
48 | #endif | ||
49 | led_state |= LED_STATE_ENABLED; | ||
50 | break; | ||
51 | |||
52 | case led_stop: | ||
53 | led_state &= ~LED_STATE_ENABLED; | ||
54 | break; | ||
55 | |||
56 | case led_claim: | ||
57 | led_state |= LED_STATE_CLAIMED; | ||
58 | hw_led_state = XBUS_LED_RED | XBUS_LED_GREEN | XBUS_LED_AMBER; | ||
59 | break; | ||
60 | |||
61 | case led_release: | ||
62 | led_state &= ~LED_STATE_CLAIMED; | ||
63 | hw_led_state = XBUS_LED_RED | XBUS_LED_GREEN | XBUS_LED_AMBER; | ||
64 | break; | ||
65 | |||
66 | #ifdef CONFIG_LEDS_TIMER | ||
67 | case led_timer: | ||
68 | if (!(led_state & LED_STATE_CLAIMED)) | ||
69 | hw_led_state ^= XBUS_LED_GREEN; | ||
70 | break; | ||
71 | #endif | ||
72 | |||
73 | #ifdef CONFIG_LEDS_CPU | ||
74 | case led_idle_start: | ||
75 | if (!(led_state & LED_STATE_CLAIMED)) | ||
76 | hw_led_state |= XBUS_LED_AMBER; | ||
77 | break; | ||
78 | |||
79 | case led_idle_end: | ||
80 | if (!(led_state & LED_STATE_CLAIMED)) | ||
81 | hw_led_state &= ~XBUS_LED_AMBER; | ||
82 | break; | ||
83 | #endif | ||
84 | |||
85 | case led_halted: | ||
86 | if (!(led_state & LED_STATE_CLAIMED)) | ||
87 | hw_led_state &= ~XBUS_LED_RED; | ||
88 | break; | ||
89 | |||
90 | case led_green_on: | ||
91 | if (led_state & LED_STATE_CLAIMED) | ||
92 | hw_led_state &= ~XBUS_LED_GREEN; | ||
93 | break; | ||
94 | |||
95 | case led_green_off: | ||
96 | if (led_state & LED_STATE_CLAIMED) | ||
97 | hw_led_state |= XBUS_LED_GREEN; | ||
98 | break; | ||
99 | |||
100 | case led_amber_on: | ||
101 | if (led_state & LED_STATE_CLAIMED) | ||
102 | hw_led_state &= ~XBUS_LED_AMBER; | ||
103 | break; | ||
104 | |||
105 | case led_amber_off: | ||
106 | if (led_state & LED_STATE_CLAIMED) | ||
107 | hw_led_state |= XBUS_LED_AMBER; | ||
108 | break; | ||
109 | |||
110 | case led_red_on: | ||
111 | if (led_state & LED_STATE_CLAIMED) | ||
112 | hw_led_state &= ~XBUS_LED_RED; | ||
113 | break; | ||
114 | |||
115 | case led_red_off: | ||
116 | if (led_state & LED_STATE_CLAIMED) | ||
117 | hw_led_state |= XBUS_LED_RED; | ||
118 | break; | ||
119 | |||
120 | default: | ||
121 | break; | ||
122 | } | ||
123 | |||
124 | if (led_state & LED_STATE_ENABLED) | ||
125 | *XBUS_LEDS = hw_led_state; | ||
126 | |||
127 | spin_unlock_irqrestore(&leds_lock, flags); | ||
128 | } | ||
129 | |||
130 | static int __init leds_init(void) | ||
131 | { | ||
132 | if (machine_is_ebsa285() || machine_is_co285()) | ||
133 | leds_event = ebsa285_leds_event; | ||
134 | |||
135 | leds_event(led_start); | ||
136 | |||
137 | return 0; | ||
138 | } | ||
139 | |||
140 | __initcall(leds_init); | ||
diff --git a/arch/arm/mach-footbridge/ebsa285-pci.c b/arch/arm/mach-footbridge/ebsa285-pci.c new file mode 100644 index 000000000000..720c0bac1702 --- /dev/null +++ b/arch/arm/mach-footbridge/ebsa285-pci.c | |||
@@ -0,0 +1,48 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-footbridge/ebsa285-pci.c | ||
3 | * | ||
4 | * PCI bios-type initialisation for PCI machines | ||
5 | * | ||
6 | * Bits taken from various places. | ||
7 | */ | ||
8 | #include <linux/kernel.h> | ||
9 | #include <linux/pci.h> | ||
10 | #include <linux/init.h> | ||
11 | |||
12 | #include <asm/irq.h> | ||
13 | #include <asm/mach/pci.h> | ||
14 | #include <asm/mach-types.h> | ||
15 | |||
16 | static int irqmap_ebsa285[] __initdata = { IRQ_IN3, IRQ_IN1, IRQ_IN0, IRQ_PCI }; | ||
17 | |||
18 | static int __init ebsa285_map_irq(struct pci_dev *dev, u8 slot, u8 pin) | ||
19 | { | ||
20 | if (dev->vendor == PCI_VENDOR_ID_CONTAQ && | ||
21 | dev->device == PCI_DEVICE_ID_CONTAQ_82C693) | ||
22 | switch (PCI_FUNC(dev->devfn)) { | ||
23 | case 1: return 14; | ||
24 | case 2: return 15; | ||
25 | case 3: return 12; | ||
26 | } | ||
27 | |||
28 | return irqmap_ebsa285[(slot + pin) & 3]; | ||
29 | } | ||
30 | |||
31 | static struct hw_pci ebsa285_pci __initdata = { | ||
32 | .swizzle = pci_std_swizzle, | ||
33 | .map_irq = ebsa285_map_irq, | ||
34 | .nr_controllers = 1, | ||
35 | .setup = dc21285_setup, | ||
36 | .scan = dc21285_scan_bus, | ||
37 | .preinit = dc21285_preinit, | ||
38 | .postinit = dc21285_postinit, | ||
39 | }; | ||
40 | |||
41 | static int __init ebsa285_init_pci(void) | ||
42 | { | ||
43 | if (machine_is_ebsa285()) | ||
44 | pci_common_init(&ebsa285_pci); | ||
45 | return 0; | ||
46 | } | ||
47 | |||
48 | subsys_initcall(ebsa285_init_pci); | ||
diff --git a/arch/arm/mach-footbridge/ebsa285.c b/arch/arm/mach-footbridge/ebsa285.c new file mode 100644 index 000000000000..d0931f5a63c8 --- /dev/null +++ b/arch/arm/mach-footbridge/ebsa285.c | |||
@@ -0,0 +1,24 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-footbridge/ebsa285.c | ||
3 | * | ||
4 | * EBSA285 machine fixup | ||
5 | */ | ||
6 | #include <linux/init.h> | ||
7 | |||
8 | #include <asm/hardware/dec21285.h> | ||
9 | #include <asm/mach-types.h> | ||
10 | |||
11 | #include <asm/mach/arch.h> | ||
12 | |||
13 | #include "common.h" | ||
14 | |||
15 | MACHINE_START(EBSA285, "EBSA285") | ||
16 | MAINTAINER("Russell King") | ||
17 | BOOT_MEM(0x00000000, DC21285_ARMCSR_BASE, 0xfe000000) | ||
18 | BOOT_PARAMS(0x00000100) | ||
19 | VIDEO(0x000a0000, 0x000bffff) | ||
20 | MAPIO(footbridge_map_io) | ||
21 | INITIRQ(footbridge_init_irq) | ||
22 | .timer = &footbridge_timer, | ||
23 | MACHINE_END | ||
24 | |||
diff --git a/arch/arm/mach-footbridge/isa-irq.c b/arch/arm/mach-footbridge/isa-irq.c new file mode 100644 index 000000000000..b21016070ea3 --- /dev/null +++ b/arch/arm/mach-footbridge/isa-irq.c | |||
@@ -0,0 +1,168 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-footbridge/irq.c | ||
3 | * | ||
4 | * Copyright (C) 1996-2000 Russell King | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * Changelog: | ||
11 | * 22-Aug-1998 RMK Restructured IRQ routines | ||
12 | * 03-Sep-1998 PJB Merged CATS support | ||
13 | * 20-Jan-1998 RMK Started merge of EBSA286, CATS and NetWinder | ||
14 | * 26-Jan-1999 PJB Don't use IACK on CATS | ||
15 | * 16-Mar-1999 RMK Added autodetect of ISA PICs | ||
16 | */ | ||
17 | #include <linux/ioport.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/list.h> | ||
20 | #include <linux/init.h> | ||
21 | |||
22 | #include <asm/mach/irq.h> | ||
23 | |||
24 | #include <asm/hardware.h> | ||
25 | #include <asm/hardware/dec21285.h> | ||
26 | #include <asm/irq.h> | ||
27 | #include <asm/io.h> | ||
28 | #include <asm/mach-types.h> | ||
29 | |||
30 | static void isa_mask_pic_lo_irq(unsigned int irq) | ||
31 | { | ||
32 | unsigned int mask = 1 << (irq & 7); | ||
33 | |||
34 | outb(inb(PIC_MASK_LO) | mask, PIC_MASK_LO); | ||
35 | } | ||
36 | |||
37 | static void isa_ack_pic_lo_irq(unsigned int irq) | ||
38 | { | ||
39 | unsigned int mask = 1 << (irq & 7); | ||
40 | |||
41 | outb(inb(PIC_MASK_LO) | mask, PIC_MASK_LO); | ||
42 | outb(0x20, PIC_LO); | ||
43 | } | ||
44 | |||
45 | static void isa_unmask_pic_lo_irq(unsigned int irq) | ||
46 | { | ||
47 | unsigned int mask = 1 << (irq & 7); | ||
48 | |||
49 | outb(inb(PIC_MASK_LO) & ~mask, PIC_MASK_LO); | ||
50 | } | ||
51 | |||
52 | static struct irqchip isa_lo_chip = { | ||
53 | .ack = isa_ack_pic_lo_irq, | ||
54 | .mask = isa_mask_pic_lo_irq, | ||
55 | .unmask = isa_unmask_pic_lo_irq, | ||
56 | }; | ||
57 | |||
58 | static void isa_mask_pic_hi_irq(unsigned int irq) | ||
59 | { | ||
60 | unsigned int mask = 1 << (irq & 7); | ||
61 | |||
62 | outb(inb(PIC_MASK_HI) | mask, PIC_MASK_HI); | ||
63 | } | ||
64 | |||
65 | static void isa_ack_pic_hi_irq(unsigned int irq) | ||
66 | { | ||
67 | unsigned int mask = 1 << (irq & 7); | ||
68 | |||
69 | outb(inb(PIC_MASK_HI) | mask, PIC_MASK_HI); | ||
70 | outb(0x62, PIC_LO); | ||
71 | outb(0x20, PIC_HI); | ||
72 | } | ||
73 | |||
74 | static void isa_unmask_pic_hi_irq(unsigned int irq) | ||
75 | { | ||
76 | unsigned int mask = 1 << (irq & 7); | ||
77 | |||
78 | outb(inb(PIC_MASK_HI) & ~mask, PIC_MASK_HI); | ||
79 | } | ||
80 | |||
81 | static struct irqchip isa_hi_chip = { | ||
82 | .ack = isa_ack_pic_hi_irq, | ||
83 | .mask = isa_mask_pic_hi_irq, | ||
84 | .unmask = isa_unmask_pic_hi_irq, | ||
85 | }; | ||
86 | |||
87 | static void | ||
88 | isa_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) | ||
89 | { | ||
90 | unsigned int isa_irq = *(unsigned char *)PCIIACK_BASE; | ||
91 | |||
92 | if (isa_irq < _ISA_IRQ(0) || isa_irq >= _ISA_IRQ(16)) { | ||
93 | do_bad_IRQ(isa_irq, desc, regs); | ||
94 | return; | ||
95 | } | ||
96 | |||
97 | desc = irq_desc + isa_irq; | ||
98 | desc->handle(isa_irq, desc, regs); | ||
99 | } | ||
100 | |||
101 | static struct irqaction irq_cascade = { .handler = no_action, .name = "cascade", }; | ||
102 | static struct resource pic1_resource = { "pic1", 0x20, 0x3f }; | ||
103 | static struct resource pic2_resource = { "pic2", 0xa0, 0xbf }; | ||
104 | |||
105 | void __init isa_init_irq(unsigned int host_irq) | ||
106 | { | ||
107 | unsigned int irq; | ||
108 | |||
109 | /* | ||
110 | * Setup, and then probe for an ISA PIC | ||
111 | * If the PIC is not there, then we | ||
112 | * ignore the PIC. | ||
113 | */ | ||
114 | outb(0x11, PIC_LO); | ||
115 | outb(_ISA_IRQ(0), PIC_MASK_LO); /* IRQ number */ | ||
116 | outb(0x04, PIC_MASK_LO); /* Slave on Ch2 */ | ||
117 | outb(0x01, PIC_MASK_LO); /* x86 */ | ||
118 | outb(0xf5, PIC_MASK_LO); /* pattern: 11110101 */ | ||
119 | |||
120 | outb(0x11, PIC_HI); | ||
121 | outb(_ISA_IRQ(8), PIC_MASK_HI); /* IRQ number */ | ||
122 | outb(0x02, PIC_MASK_HI); /* Slave on Ch1 */ | ||
123 | outb(0x01, PIC_MASK_HI); /* x86 */ | ||
124 | outb(0xfa, PIC_MASK_HI); /* pattern: 11111010 */ | ||
125 | |||
126 | outb(0x0b, PIC_LO); | ||
127 | outb(0x0b, PIC_HI); | ||
128 | |||
129 | if (inb(PIC_MASK_LO) == 0xf5 && inb(PIC_MASK_HI) == 0xfa) { | ||
130 | outb(0xff, PIC_MASK_LO);/* mask all IRQs */ | ||
131 | outb(0xff, PIC_MASK_HI);/* mask all IRQs */ | ||
132 | } else { | ||
133 | printk(KERN_INFO "IRQ: ISA PIC not found\n"); | ||
134 | host_irq = (unsigned int)-1; | ||
135 | } | ||
136 | |||
137 | if (host_irq != (unsigned int)-1) { | ||
138 | for (irq = _ISA_IRQ(0); irq < _ISA_IRQ(8); irq++) { | ||
139 | set_irq_chip(irq, &isa_lo_chip); | ||
140 | set_irq_handler(irq, do_level_IRQ); | ||
141 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); | ||
142 | } | ||
143 | |||
144 | for (irq = _ISA_IRQ(8); irq < _ISA_IRQ(16); irq++) { | ||
145 | set_irq_chip(irq, &isa_hi_chip); | ||
146 | set_irq_handler(irq, do_level_IRQ); | ||
147 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); | ||
148 | } | ||
149 | |||
150 | request_resource(&ioport_resource, &pic1_resource); | ||
151 | request_resource(&ioport_resource, &pic2_resource); | ||
152 | setup_irq(IRQ_ISA_CASCADE, &irq_cascade); | ||
153 | |||
154 | set_irq_chained_handler(host_irq, isa_irq_handler); | ||
155 | |||
156 | /* | ||
157 | * On the NetWinder, don't automatically | ||
158 | * enable ISA IRQ11 when it is requested. | ||
159 | * There appears to be a missing pull-up | ||
160 | * resistor on this line. | ||
161 | */ | ||
162 | if (machine_is_netwinder()) | ||
163 | set_irq_flags(_ISA_IRQ(11), IRQF_VALID | | ||
164 | IRQF_PROBE | IRQF_NOAUTOEN); | ||
165 | } | ||
166 | } | ||
167 | |||
168 | |||
diff --git a/arch/arm/mach-footbridge/isa-timer.c b/arch/arm/mach-footbridge/isa-timer.c new file mode 100644 index 000000000000..a4fefa0bb5a1 --- /dev/null +++ b/arch/arm/mach-footbridge/isa-timer.c | |||
@@ -0,0 +1,94 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-footbridge/isa-timer.c | ||
3 | * | ||
4 | * Copyright (C) 1998 Russell King. | ||
5 | * Copyright (C) 1998 Phil Blundell | ||
6 | */ | ||
7 | #include <linux/init.h> | ||
8 | #include <linux/interrupt.h> | ||
9 | |||
10 | #include <asm/io.h> | ||
11 | #include <asm/irq.h> | ||
12 | |||
13 | #include <asm/mach/time.h> | ||
14 | |||
15 | #include "common.h" | ||
16 | |||
17 | /* | ||
18 | * ISA timer tick support | ||
19 | */ | ||
20 | #define mSEC_10_from_14 ((14318180 + 100) / 200) | ||
21 | |||
22 | static unsigned long isa_gettimeoffset(void) | ||
23 | { | ||
24 | int count; | ||
25 | |||
26 | static int count_p = (mSEC_10_from_14/6); /* for the first call after boot */ | ||
27 | static unsigned long jiffies_p = 0; | ||
28 | |||
29 | /* | ||
30 | * cache volatile jiffies temporarily; we have IRQs turned off. | ||
31 | */ | ||
32 | unsigned long jiffies_t; | ||
33 | |||
34 | /* timer count may underflow right here */ | ||
35 | outb_p(0x00, 0x43); /* latch the count ASAP */ | ||
36 | |||
37 | count = inb_p(0x40); /* read the latched count */ | ||
38 | |||
39 | /* | ||
40 | * We do this guaranteed double memory access instead of a _p | ||
41 | * postfix in the previous port access. Wheee, hackady hack | ||
42 | */ | ||
43 | jiffies_t = jiffies; | ||
44 | |||
45 | count |= inb_p(0x40) << 8; | ||
46 | |||
47 | /* Detect timer underflows. If we haven't had a timer tick since | ||
48 | the last time we were called, and time is apparently going | ||
49 | backwards, the counter must have wrapped during this routine. */ | ||
50 | if ((jiffies_t == jiffies_p) && (count > count_p)) | ||
51 | count -= (mSEC_10_from_14/6); | ||
52 | else | ||
53 | jiffies_p = jiffies_t; | ||
54 | |||
55 | count_p = count; | ||
56 | |||
57 | count = (((mSEC_10_from_14/6)-1) - count) * (tick_nsec / 1000); | ||
58 | count = (count + (mSEC_10_from_14/6)/2) / (mSEC_10_from_14/6); | ||
59 | |||
60 | return count; | ||
61 | } | ||
62 | |||
63 | static irqreturn_t | ||
64 | isa_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
65 | { | ||
66 | write_seqlock(&xtime_lock); | ||
67 | timer_tick(regs); | ||
68 | write_sequnlock(&xtime_lock); | ||
69 | return IRQ_HANDLED; | ||
70 | } | ||
71 | |||
72 | static struct irqaction isa_timer_irq = { | ||
73 | .name = "ISA timer tick", | ||
74 | .handler = isa_timer_interrupt, | ||
75 | .flags = SA_INTERRUPT, | ||
76 | }; | ||
77 | |||
78 | static void __init isa_timer_init(void) | ||
79 | { | ||
80 | isa_rtc_init(); | ||
81 | |||
82 | /* enable PIT timer */ | ||
83 | /* set for periodic (4) and LSB/MSB write (0x30) */ | ||
84 | outb(0x34, 0x43); | ||
85 | outb((mSEC_10_from_14/6) & 0xFF, 0x40); | ||
86 | outb((mSEC_10_from_14/6) >> 8, 0x40); | ||
87 | |||
88 | setup_irq(IRQ_ISA_TIMER, &isa_timer_irq); | ||
89 | } | ||
90 | |||
91 | struct sys_timer isa_timer = { | ||
92 | .init = isa_timer_init, | ||
93 | .offset = isa_gettimeoffset, | ||
94 | }; | ||
diff --git a/arch/arm/mach-footbridge/isa.c b/arch/arm/mach-footbridge/isa.c new file mode 100644 index 000000000000..aa3a1fef563e --- /dev/null +++ b/arch/arm/mach-footbridge/isa.c | |||
@@ -0,0 +1,48 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-footbridge/isa.c | ||
3 | * | ||
4 | * Copyright (C) 2004 Russell King. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | #include <linux/init.h> | ||
11 | #include <linux/serial_8250.h> | ||
12 | |||
13 | #include <asm/irq.h> | ||
14 | |||
15 | static struct plat_serial8250_port serial_platform_data[] = { | ||
16 | { | ||
17 | .iobase = 0x3f8, | ||
18 | .irq = IRQ_ISA_UART, | ||
19 | .uartclk = 1843200, | ||
20 | .regshift = 0, | ||
21 | .iotype = UPIO_PORT, | ||
22 | .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, | ||
23 | }, | ||
24 | { | ||
25 | .iobase = 0x2f8, | ||
26 | .irq = IRQ_ISA_UART2, | ||
27 | .uartclk = 1843200, | ||
28 | .regshift = 0, | ||
29 | .iotype = UPIO_PORT, | ||
30 | .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, | ||
31 | }, | ||
32 | { }, | ||
33 | }; | ||
34 | |||
35 | static struct platform_device serial_device = { | ||
36 | .name = "serial8250", | ||
37 | .id = 0, | ||
38 | .dev = { | ||
39 | .platform_data = serial_platform_data, | ||
40 | }, | ||
41 | }; | ||
42 | |||
43 | static int __init footbridge_isa_init(void) | ||
44 | { | ||
45 | return platform_device_register(&serial_device); | ||
46 | } | ||
47 | |||
48 | arch_initcall(footbridge_isa_init); | ||
diff --git a/arch/arm/mach-footbridge/netwinder-hw.c b/arch/arm/mach-footbridge/netwinder-hw.c new file mode 100644 index 000000000000..1e1dfd79f4fe --- /dev/null +++ b/arch/arm/mach-footbridge/netwinder-hw.c | |||
@@ -0,0 +1,660 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-footbridge/netwinder-hw.c | ||
3 | * | ||
4 | * Netwinder machine fixup | ||
5 | * | ||
6 | * Copyright (C) 1998, 1999 Russell King, Phil Blundell | ||
7 | */ | ||
8 | #include <linux/config.h> | ||
9 | #include <linux/module.h> | ||
10 | #include <linux/ioport.h> | ||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/delay.h> | ||
13 | #include <linux/init.h> | ||
14 | |||
15 | #include <asm/hardware/dec21285.h> | ||
16 | #include <asm/io.h> | ||
17 | #include <asm/leds.h> | ||
18 | #include <asm/mach-types.h> | ||
19 | #include <asm/setup.h> | ||
20 | |||
21 | #include <asm/mach/arch.h> | ||
22 | |||
23 | #include "common.h" | ||
24 | |||
25 | #define IRDA_IO_BASE 0x180 | ||
26 | #define GP1_IO_BASE 0x338 | ||
27 | #define GP2_IO_BASE 0x33a | ||
28 | |||
29 | |||
30 | #ifdef CONFIG_LEDS | ||
31 | #define DEFAULT_LEDS 0 | ||
32 | #else | ||
33 | #define DEFAULT_LEDS GPIO_GREEN_LED | ||
34 | #endif | ||
35 | |||
36 | /* | ||
37 | * Winbond WB83977F accessibility stuff | ||
38 | */ | ||
39 | static inline void wb977_open(void) | ||
40 | { | ||
41 | outb(0x87, 0x370); | ||
42 | outb(0x87, 0x370); | ||
43 | } | ||
44 | |||
45 | static inline void wb977_close(void) | ||
46 | { | ||
47 | outb(0xaa, 0x370); | ||
48 | } | ||
49 | |||
50 | static inline void wb977_wb(int reg, int val) | ||
51 | { | ||
52 | outb(reg, 0x370); | ||
53 | outb(val, 0x371); | ||
54 | } | ||
55 | |||
56 | static inline void wb977_ww(int reg, int val) | ||
57 | { | ||
58 | outb(reg, 0x370); | ||
59 | outb(val >> 8, 0x371); | ||
60 | outb(reg + 1, 0x370); | ||
61 | outb(val & 255, 0x371); | ||
62 | } | ||
63 | |||
64 | #define wb977_device_select(dev) wb977_wb(0x07, dev) | ||
65 | #define wb977_device_disable() wb977_wb(0x30, 0x00) | ||
66 | #define wb977_device_enable() wb977_wb(0x30, 0x01) | ||
67 | |||
68 | /* | ||
69 | * This is a lock for accessing ports GP1_IO_BASE and GP2_IO_BASE | ||
70 | */ | ||
71 | DEFINE_SPINLOCK(gpio_lock); | ||
72 | |||
73 | static unsigned int current_gpio_op; | ||
74 | static unsigned int current_gpio_io; | ||
75 | static unsigned int current_cpld; | ||
76 | |||
77 | void gpio_modify_op(int mask, int set) | ||
78 | { | ||
79 | unsigned int new_gpio, changed; | ||
80 | |||
81 | new_gpio = (current_gpio_op & ~mask) | set; | ||
82 | changed = new_gpio ^ current_gpio_op; | ||
83 | current_gpio_op = new_gpio; | ||
84 | |||
85 | if (changed & 0xff) | ||
86 | outb(new_gpio, GP1_IO_BASE); | ||
87 | if (changed & 0xff00) | ||
88 | outb(new_gpio >> 8, GP2_IO_BASE); | ||
89 | } | ||
90 | |||
91 | static inline void __gpio_modify_io(int mask, int in) | ||
92 | { | ||
93 | unsigned int new_gpio, changed; | ||
94 | int port; | ||
95 | |||
96 | new_gpio = (current_gpio_io & ~mask) | in; | ||
97 | changed = new_gpio ^ current_gpio_io; | ||
98 | current_gpio_io = new_gpio; | ||
99 | |||
100 | changed >>= 1; | ||
101 | new_gpio >>= 1; | ||
102 | |||
103 | wb977_device_select(7); | ||
104 | |||
105 | for (port = 0xe1; changed && port < 0xe8; changed >>= 1) { | ||
106 | wb977_wb(port, new_gpio & 1); | ||
107 | |||
108 | port += 1; | ||
109 | new_gpio >>= 1; | ||
110 | } | ||
111 | |||
112 | wb977_device_select(8); | ||
113 | |||
114 | for (port = 0xe8; changed && port < 0xec; changed >>= 1) { | ||
115 | wb977_wb(port, new_gpio & 1); | ||
116 | |||
117 | port += 1; | ||
118 | new_gpio >>= 1; | ||
119 | } | ||
120 | } | ||
121 | |||
122 | void gpio_modify_io(int mask, int in) | ||
123 | { | ||
124 | /* Open up the SuperIO chip */ | ||
125 | wb977_open(); | ||
126 | |||
127 | __gpio_modify_io(mask, in); | ||
128 | |||
129 | /* Close up the EFER gate */ | ||
130 | wb977_close(); | ||
131 | } | ||
132 | |||
133 | int gpio_read(void) | ||
134 | { | ||
135 | return inb(GP1_IO_BASE) | inb(GP2_IO_BASE) << 8; | ||
136 | } | ||
137 | |||
138 | /* | ||
139 | * Initialise the Winbond W83977F global registers | ||
140 | */ | ||
141 | static inline void wb977_init_global(void) | ||
142 | { | ||
143 | /* | ||
144 | * Enable R/W config registers | ||
145 | */ | ||
146 | wb977_wb(0x26, 0x40); | ||
147 | |||
148 | /* | ||
149 | * Power down FDC (not used) | ||
150 | */ | ||
151 | wb977_wb(0x22, 0xfe); | ||
152 | |||
153 | /* | ||
154 | * GP12, GP11, CIRRX, IRRXH, GP10 | ||
155 | */ | ||
156 | wb977_wb(0x2a, 0xc1); | ||
157 | |||
158 | /* | ||
159 | * GP23, GP22, GP21, GP20, GP13 | ||
160 | */ | ||
161 | wb977_wb(0x2b, 0x6b); | ||
162 | |||
163 | /* | ||
164 | * GP17, GP16, GP15, GP14 | ||
165 | */ | ||
166 | wb977_wb(0x2c, 0x55); | ||
167 | } | ||
168 | |||
169 | /* | ||
170 | * Initialise the Winbond W83977F printer port | ||
171 | */ | ||
172 | static inline void wb977_init_printer(void) | ||
173 | { | ||
174 | wb977_device_select(1); | ||
175 | |||
176 | /* | ||
177 | * mode 1 == EPP | ||
178 | */ | ||
179 | wb977_wb(0xf0, 0x01); | ||
180 | } | ||
181 | |||
182 | /* | ||
183 | * Initialise the Winbond W83977F keyboard controller | ||
184 | */ | ||
185 | static inline void wb977_init_keyboard(void) | ||
186 | { | ||
187 | wb977_device_select(5); | ||
188 | |||
189 | /* | ||
190 | * Keyboard controller address | ||
191 | */ | ||
192 | wb977_ww(0x60, 0x0060); | ||
193 | wb977_ww(0x62, 0x0064); | ||
194 | |||
195 | /* | ||
196 | * Keyboard IRQ 1, active high, edge trigger | ||
197 | */ | ||
198 | wb977_wb(0x70, 1); | ||
199 | wb977_wb(0x71, 0x02); | ||
200 | |||
201 | /* | ||
202 | * Mouse IRQ 5, active high, edge trigger | ||
203 | */ | ||
204 | wb977_wb(0x72, 5); | ||
205 | wb977_wb(0x73, 0x02); | ||
206 | |||
207 | /* | ||
208 | * KBC 8MHz | ||
209 | */ | ||
210 | wb977_wb(0xf0, 0x40); | ||
211 | |||
212 | /* | ||
213 | * Enable device | ||
214 | */ | ||
215 | wb977_device_enable(); | ||
216 | } | ||
217 | |||
218 | /* | ||
219 | * Initialise the Winbond W83977F Infra-Red device | ||
220 | */ | ||
221 | static inline void wb977_init_irda(void) | ||
222 | { | ||
223 | wb977_device_select(6); | ||
224 | |||
225 | /* | ||
226 | * IR base address | ||
227 | */ | ||
228 | wb977_ww(0x60, IRDA_IO_BASE); | ||
229 | |||
230 | /* | ||
231 | * IRDA IRQ 6, active high, edge trigger | ||
232 | */ | ||
233 | wb977_wb(0x70, 6); | ||
234 | wb977_wb(0x71, 0x02); | ||
235 | |||
236 | /* | ||
237 | * RX DMA - ISA DMA 0 | ||
238 | */ | ||
239 | wb977_wb(0x74, 0x00); | ||
240 | |||
241 | /* | ||
242 | * TX DMA - Disable Tx DMA | ||
243 | */ | ||
244 | wb977_wb(0x75, 0x04); | ||
245 | |||
246 | /* | ||
247 | * Append CRC, Enable bank selection | ||
248 | */ | ||
249 | wb977_wb(0xf0, 0x03); | ||
250 | |||
251 | /* | ||
252 | * Enable device | ||
253 | */ | ||
254 | wb977_device_enable(); | ||
255 | } | ||
256 | |||
257 | /* | ||
258 | * Initialise Winbond W83977F general purpose IO | ||
259 | */ | ||
260 | static inline void wb977_init_gpio(void) | ||
261 | { | ||
262 | unsigned long flags; | ||
263 | |||
264 | /* | ||
265 | * Set up initial I/O definitions | ||
266 | */ | ||
267 | current_gpio_io = -1; | ||
268 | __gpio_modify_io(-1, GPIO_DONE | GPIO_WDTIMER); | ||
269 | |||
270 | wb977_device_select(7); | ||
271 | |||
272 | /* | ||
273 | * Group1 base address | ||
274 | */ | ||
275 | wb977_ww(0x60, GP1_IO_BASE); | ||
276 | wb977_ww(0x62, 0); | ||
277 | wb977_ww(0x64, 0); | ||
278 | |||
279 | /* | ||
280 | * GP10 (Orage button) IRQ 10, active high, edge trigger | ||
281 | */ | ||
282 | wb977_wb(0x70, 10); | ||
283 | wb977_wb(0x71, 0x02); | ||
284 | |||
285 | /* | ||
286 | * GP10: Debounce filter enabled, IRQ, input | ||
287 | */ | ||
288 | wb977_wb(0xe0, 0x19); | ||
289 | |||
290 | /* | ||
291 | * Enable Group1 | ||
292 | */ | ||
293 | wb977_device_enable(); | ||
294 | |||
295 | wb977_device_select(8); | ||
296 | |||
297 | /* | ||
298 | * Group2 base address | ||
299 | */ | ||
300 | wb977_ww(0x60, GP2_IO_BASE); | ||
301 | |||
302 | /* | ||
303 | * Clear watchdog timer regs | ||
304 | * - timer disable | ||
305 | */ | ||
306 | wb977_wb(0xf2, 0x00); | ||
307 | |||
308 | /* | ||
309 | * - disable LED, no mouse nor keyboard IRQ | ||
310 | */ | ||
311 | wb977_wb(0xf3, 0x00); | ||
312 | |||
313 | /* | ||
314 | * - timer counting, disable power LED, disable timeouot | ||
315 | */ | ||
316 | wb977_wb(0xf4, 0x00); | ||
317 | |||
318 | /* | ||
319 | * Enable group2 | ||
320 | */ | ||
321 | wb977_device_enable(); | ||
322 | |||
323 | /* | ||
324 | * Set Group1/Group2 outputs | ||
325 | */ | ||
326 | spin_lock_irqsave(&gpio_lock, flags); | ||
327 | gpio_modify_op(-1, GPIO_RED_LED | GPIO_FAN); | ||
328 | spin_unlock_irqrestore(&gpio_lock, flags); | ||
329 | } | ||
330 | |||
331 | /* | ||
332 | * Initialise the Winbond W83977F chip. | ||
333 | */ | ||
334 | static void __init wb977_init(void) | ||
335 | { | ||
336 | request_region(0x370, 2, "W83977AF configuration"); | ||
337 | |||
338 | /* | ||
339 | * Open up the SuperIO chip | ||
340 | */ | ||
341 | wb977_open(); | ||
342 | |||
343 | /* | ||
344 | * Initialise the global registers | ||
345 | */ | ||
346 | wb977_init_global(); | ||
347 | |||
348 | /* | ||
349 | * Initialise the various devices in | ||
350 | * the multi-IO chip. | ||
351 | */ | ||
352 | wb977_init_printer(); | ||
353 | wb977_init_keyboard(); | ||
354 | wb977_init_irda(); | ||
355 | wb977_init_gpio(); | ||
356 | |||
357 | /* | ||
358 | * Close up the EFER gate | ||
359 | */ | ||
360 | wb977_close(); | ||
361 | } | ||
362 | |||
363 | void cpld_modify(int mask, int set) | ||
364 | { | ||
365 | int msk; | ||
366 | |||
367 | current_cpld = (current_cpld & ~mask) | set; | ||
368 | |||
369 | gpio_modify_io(GPIO_DATA | GPIO_IOCLK | GPIO_IOLOAD, 0); | ||
370 | gpio_modify_op(GPIO_IOLOAD, 0); | ||
371 | |||
372 | for (msk = 8; msk; msk >>= 1) { | ||
373 | int bit = current_cpld & msk; | ||
374 | |||
375 | gpio_modify_op(GPIO_DATA | GPIO_IOCLK, bit ? GPIO_DATA : 0); | ||
376 | gpio_modify_op(GPIO_IOCLK, GPIO_IOCLK); | ||
377 | } | ||
378 | |||
379 | gpio_modify_op(GPIO_IOCLK|GPIO_DATA, 0); | ||
380 | gpio_modify_op(GPIO_IOLOAD|GPIO_DSCLK, GPIO_IOLOAD|GPIO_DSCLK); | ||
381 | gpio_modify_op(GPIO_IOLOAD, 0); | ||
382 | } | ||
383 | |||
384 | static void __init cpld_init(void) | ||
385 | { | ||
386 | unsigned long flags; | ||
387 | |||
388 | spin_lock_irqsave(&gpio_lock, flags); | ||
389 | cpld_modify(-1, CPLD_UNMUTE | CPLD_7111_DISABLE); | ||
390 | spin_unlock_irqrestore(&gpio_lock, flags); | ||
391 | } | ||
392 | |||
393 | static unsigned char rwa_unlock[] __initdata = | ||
394 | { 0x00, 0x00, 0x6a, 0xb5, 0xda, 0xed, 0xf6, 0xfb, 0x7d, 0xbe, 0xdf, 0x6f, 0x37, 0x1b, | ||
395 | 0x0d, 0x86, 0xc3, 0x61, 0xb0, 0x58, 0x2c, 0x16, 0x8b, 0x45, 0xa2, 0xd1, 0xe8, 0x74, | ||
396 | 0x3a, 0x9d, 0xce, 0xe7, 0x73, 0x39 }; | ||
397 | |||
398 | #ifndef DEBUG | ||
399 | #define dprintk(x...) | ||
400 | #else | ||
401 | #define dprintk(x...) printk(x) | ||
402 | #endif | ||
403 | |||
404 | #define WRITE_RWA(r,v) do { outb((r), 0x279); udelay(10); outb((v), 0xa79); } while (0) | ||
405 | |||
406 | static inline void rwa010_unlock(void) | ||
407 | { | ||
408 | int i; | ||
409 | |||
410 | WRITE_RWA(2, 2); | ||
411 | mdelay(10); | ||
412 | |||
413 | for (i = 0; i < sizeof(rwa_unlock); i++) { | ||
414 | outb(rwa_unlock[i], 0x279); | ||
415 | udelay(10); | ||
416 | } | ||
417 | } | ||
418 | |||
419 | static inline void rwa010_read_ident(void) | ||
420 | { | ||
421 | unsigned char si[9]; | ||
422 | int i, j; | ||
423 | |||
424 | WRITE_RWA(3, 0); | ||
425 | WRITE_RWA(0, 128); | ||
426 | |||
427 | outb(1, 0x279); | ||
428 | |||
429 | mdelay(1); | ||
430 | |||
431 | dprintk("Identifier: "); | ||
432 | for (i = 0; i < 9; i++) { | ||
433 | si[i] = 0; | ||
434 | for (j = 0; j < 8; j++) { | ||
435 | int bit; | ||
436 | udelay(250); | ||
437 | inb(0x203); | ||
438 | udelay(250); | ||
439 | bit = inb(0x203); | ||
440 | dprintk("%02X ", bit); | ||
441 | bit = (bit == 0xaa) ? 1 : 0; | ||
442 | si[i] |= bit << j; | ||
443 | } | ||
444 | dprintk("(%02X) ", si[i]); | ||
445 | } | ||
446 | dprintk("\n"); | ||
447 | } | ||
448 | |||
449 | static inline void rwa010_global_init(void) | ||
450 | { | ||
451 | WRITE_RWA(6, 2); // Assign a card no = 2 | ||
452 | |||
453 | dprintk("Card no = %d\n", inb(0x203)); | ||
454 | |||
455 | /* disable the modem section of the chip */ | ||
456 | WRITE_RWA(7, 3); | ||
457 | WRITE_RWA(0x30, 0); | ||
458 | |||
459 | /* disable the cdrom section of the chip */ | ||
460 | WRITE_RWA(7, 4); | ||
461 | WRITE_RWA(0x30, 0); | ||
462 | |||
463 | /* disable the MPU-401 section of the chip */ | ||
464 | WRITE_RWA(7, 2); | ||
465 | WRITE_RWA(0x30, 0); | ||
466 | } | ||
467 | |||
468 | static inline void rwa010_game_port_init(void) | ||
469 | { | ||
470 | int i; | ||
471 | |||
472 | WRITE_RWA(7, 5); | ||
473 | |||
474 | dprintk("Slider base: "); | ||
475 | WRITE_RWA(0x61, 1); | ||
476 | i = inb(0x203); | ||
477 | |||
478 | WRITE_RWA(0x60, 2); | ||
479 | dprintk("%02X%02X (201)\n", inb(0x203), i); | ||
480 | |||
481 | WRITE_RWA(0x30, 1); | ||
482 | } | ||
483 | |||
484 | static inline void rwa010_waveartist_init(int base, int irq, int dma) | ||
485 | { | ||
486 | int i; | ||
487 | |||
488 | WRITE_RWA(7, 0); | ||
489 | |||
490 | dprintk("WaveArtist base: "); | ||
491 | WRITE_RWA(0x61, base & 255); | ||
492 | i = inb(0x203); | ||
493 | |||
494 | WRITE_RWA(0x60, base >> 8); | ||
495 | dprintk("%02X%02X (%X),", inb(0x203), i, base); | ||
496 | |||
497 | WRITE_RWA(0x70, irq); | ||
498 | dprintk(" irq: %d (%d),", inb(0x203), irq); | ||
499 | |||
500 | WRITE_RWA(0x74, dma); | ||
501 | dprintk(" dma: %d (%d)\n", inb(0x203), dma); | ||
502 | |||
503 | WRITE_RWA(0x30, 1); | ||
504 | } | ||
505 | |||
506 | static inline void rwa010_soundblaster_init(int sb_base, int al_base, int irq, int dma) | ||
507 | { | ||
508 | int i; | ||
509 | |||
510 | WRITE_RWA(7, 1); | ||
511 | |||
512 | dprintk("SoundBlaster base: "); | ||
513 | WRITE_RWA(0x61, sb_base & 255); | ||
514 | i = inb(0x203); | ||
515 | |||
516 | WRITE_RWA(0x60, sb_base >> 8); | ||
517 | dprintk("%02X%02X (%X),", inb(0x203), i, sb_base); | ||
518 | |||
519 | dprintk(" irq: "); | ||
520 | WRITE_RWA(0x70, irq); | ||
521 | dprintk("%d (%d),", inb(0x203), irq); | ||
522 | |||
523 | dprintk(" 8-bit DMA: "); | ||
524 | WRITE_RWA(0x74, dma); | ||
525 | dprintk("%d (%d)\n", inb(0x203), dma); | ||
526 | |||
527 | dprintk("AdLib base: "); | ||
528 | WRITE_RWA(0x63, al_base & 255); | ||
529 | i = inb(0x203); | ||
530 | |||
531 | WRITE_RWA(0x62, al_base >> 8); | ||
532 | dprintk("%02X%02X (%X)\n", inb(0x203), i, al_base); | ||
533 | |||
534 | WRITE_RWA(0x30, 1); | ||
535 | } | ||
536 | |||
537 | static void rwa010_soundblaster_reset(void) | ||
538 | { | ||
539 | int i; | ||
540 | |||
541 | outb(1, 0x226); | ||
542 | udelay(3); | ||
543 | outb(0, 0x226); | ||
544 | |||
545 | for (i = 0; i < 5; i++) { | ||
546 | if (inb(0x22e) & 0x80) | ||
547 | break; | ||
548 | mdelay(1); | ||
549 | } | ||
550 | if (i == 5) | ||
551 | printk("SoundBlaster: DSP reset failed\n"); | ||
552 | |||
553 | dprintk("SoundBlaster DSP reset: %02X (AA)\n", inb(0x22a)); | ||
554 | |||
555 | for (i = 0; i < 5; i++) { | ||
556 | if ((inb(0x22c) & 0x80) == 0) | ||
557 | break; | ||
558 | mdelay(1); | ||
559 | } | ||
560 | |||
561 | if (i == 5) | ||
562 | printk("SoundBlaster: DSP not ready\n"); | ||
563 | else { | ||
564 | outb(0xe1, 0x22c); | ||
565 | |||
566 | dprintk("SoundBlaster DSP id: "); | ||
567 | i = inb(0x22a); | ||
568 | udelay(1); | ||
569 | i |= inb(0x22a) << 8; | ||
570 | dprintk("%04X\n", i); | ||
571 | |||
572 | for (i = 0; i < 5; i++) { | ||
573 | if ((inb(0x22c) & 0x80) == 0) | ||
574 | break; | ||
575 | mdelay(1); | ||
576 | } | ||
577 | |||
578 | if (i == 5) | ||
579 | printk("SoundBlaster: could not turn speaker off\n"); | ||
580 | |||
581 | outb(0xd3, 0x22c); | ||
582 | } | ||
583 | |||
584 | /* turn on OPL3 */ | ||
585 | outb(5, 0x38a); | ||
586 | outb(1, 0x38b); | ||
587 | } | ||
588 | |||
589 | static void __init rwa010_init(void) | ||
590 | { | ||
591 | rwa010_unlock(); | ||
592 | rwa010_read_ident(); | ||
593 | rwa010_global_init(); | ||
594 | rwa010_game_port_init(); | ||
595 | rwa010_waveartist_init(0x250, 3, 7); | ||
596 | rwa010_soundblaster_init(0x220, 0x388, 3, 1); | ||
597 | rwa010_soundblaster_reset(); | ||
598 | } | ||
599 | |||
600 | EXPORT_SYMBOL(gpio_lock); | ||
601 | EXPORT_SYMBOL(gpio_modify_op); | ||
602 | EXPORT_SYMBOL(gpio_modify_io); | ||
603 | EXPORT_SYMBOL(cpld_modify); | ||
604 | |||
605 | /* | ||
606 | * Initialise any other hardware after we've got the PCI bus | ||
607 | * initialised. We may need the PCI bus to talk to this other | ||
608 | * hardware. | ||
609 | */ | ||
610 | static int __init nw_hw_init(void) | ||
611 | { | ||
612 | if (machine_is_netwinder()) { | ||
613 | unsigned long flags; | ||
614 | |||
615 | wb977_init(); | ||
616 | cpld_init(); | ||
617 | rwa010_init(); | ||
618 | |||
619 | spin_lock_irqsave(&gpio_lock, flags); | ||
620 | gpio_modify_op(GPIO_RED_LED|GPIO_GREEN_LED, DEFAULT_LEDS); | ||
621 | spin_unlock_irqrestore(&gpio_lock, flags); | ||
622 | } | ||
623 | return 0; | ||
624 | } | ||
625 | |||
626 | __initcall(nw_hw_init); | ||
627 | |||
628 | /* | ||
629 | * Older NeTTroms either do not provide a parameters | ||
630 | * page, or they don't supply correct information in | ||
631 | * the parameter page. | ||
632 | */ | ||
633 | static void __init | ||
634 | fixup_netwinder(struct machine_desc *desc, struct tag *tags, | ||
635 | char **cmdline, struct meminfo *mi) | ||
636 | { | ||
637 | #ifdef CONFIG_ISAPNP | ||
638 | extern int isapnp_disable; | ||
639 | |||
640 | /* | ||
641 | * We must not use the kernels ISAPnP code | ||
642 | * on the NetWinder - it will reset the settings | ||
643 | * for the WaveArtist chip and render it inoperable. | ||
644 | */ | ||
645 | isapnp_disable = 1; | ||
646 | #endif | ||
647 | } | ||
648 | |||
649 | MACHINE_START(NETWINDER, "Rebel-NetWinder") | ||
650 | MAINTAINER("Russell King/Rebel.com") | ||
651 | BOOT_MEM(0x00000000, DC21285_ARMCSR_BASE, 0xfe000000) | ||
652 | BOOT_PARAMS(0x00000100) | ||
653 | VIDEO(0x000a0000, 0x000bffff) | ||
654 | DISABLE_PARPORT(0) | ||
655 | DISABLE_PARPORT(2) | ||
656 | FIXUP(fixup_netwinder) | ||
657 | MAPIO(footbridge_map_io) | ||
658 | INITIRQ(footbridge_init_irq) | ||
659 | .timer = &isa_timer, | ||
660 | MACHINE_END | ||
diff --git a/arch/arm/mach-footbridge/netwinder-leds.c b/arch/arm/mach-footbridge/netwinder-leds.c new file mode 100644 index 000000000000..7451fc07b85a --- /dev/null +++ b/arch/arm/mach-footbridge/netwinder-leds.c | |||
@@ -0,0 +1,141 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-footbridge/netwinder-leds.c | ||
3 | * | ||
4 | * Copyright (C) 1998-1999 Russell King | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * NetWinder LED control routines. | ||
11 | * | ||
12 | * The Netwinder uses the leds as follows: | ||
13 | * - Green - toggles state every 50 timer interrupts | ||
14 | * - Red - On if the system is not idle | ||
15 | * | ||
16 | * Changelog: | ||
17 | * 02-05-1999 RMK Various cleanups | ||
18 | */ | ||
19 | #include <linux/config.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/kernel.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <linux/spinlock.h> | ||
24 | |||
25 | #include <asm/hardware.h> | ||
26 | #include <asm/leds.h> | ||
27 | #include <asm/mach-types.h> | ||
28 | #include <asm/system.h> | ||
29 | |||
30 | #define LED_STATE_ENABLED 1 | ||
31 | #define LED_STATE_CLAIMED 2 | ||
32 | static char led_state; | ||
33 | static char hw_led_state; | ||
34 | |||
35 | static DEFINE_SPINLOCK(leds_lock); | ||
36 | extern spinlock_t gpio_lock; | ||
37 | |||
38 | static void netwinder_leds_event(led_event_t evt) | ||
39 | { | ||
40 | unsigned long flags; | ||
41 | |||
42 | spin_lock_irqsave(&leds_lock, flags); | ||
43 | |||
44 | switch (evt) { | ||
45 | case led_start: | ||
46 | led_state |= LED_STATE_ENABLED; | ||
47 | hw_led_state = GPIO_GREEN_LED; | ||
48 | break; | ||
49 | |||
50 | case led_stop: | ||
51 | led_state &= ~LED_STATE_ENABLED; | ||
52 | break; | ||
53 | |||
54 | case led_claim: | ||
55 | led_state |= LED_STATE_CLAIMED; | ||
56 | hw_led_state = 0; | ||
57 | break; | ||
58 | |||
59 | case led_release: | ||
60 | led_state &= ~LED_STATE_CLAIMED; | ||
61 | hw_led_state = 0; | ||
62 | break; | ||
63 | |||
64 | #ifdef CONFIG_LEDS_TIMER | ||
65 | case led_timer: | ||
66 | if (!(led_state & LED_STATE_CLAIMED)) | ||
67 | hw_led_state ^= GPIO_GREEN_LED; | ||
68 | break; | ||
69 | #endif | ||
70 | |||
71 | #ifdef CONFIG_LEDS_CPU | ||
72 | case led_idle_start: | ||
73 | if (!(led_state & LED_STATE_CLAIMED)) | ||
74 | hw_led_state &= ~GPIO_RED_LED; | ||
75 | break; | ||
76 | |||
77 | case led_idle_end: | ||
78 | if (!(led_state & LED_STATE_CLAIMED)) | ||
79 | hw_led_state |= GPIO_RED_LED; | ||
80 | break; | ||
81 | #endif | ||
82 | |||
83 | case led_halted: | ||
84 | if (!(led_state & LED_STATE_CLAIMED)) | ||
85 | hw_led_state |= GPIO_RED_LED; | ||
86 | break; | ||
87 | |||
88 | case led_green_on: | ||
89 | if (led_state & LED_STATE_CLAIMED) | ||
90 | hw_led_state |= GPIO_GREEN_LED; | ||
91 | break; | ||
92 | |||
93 | case led_green_off: | ||
94 | if (led_state & LED_STATE_CLAIMED) | ||
95 | hw_led_state &= ~GPIO_GREEN_LED; | ||
96 | break; | ||
97 | |||
98 | case led_amber_on: | ||
99 | if (led_state & LED_STATE_CLAIMED) | ||
100 | hw_led_state |= GPIO_GREEN_LED | GPIO_RED_LED; | ||
101 | break; | ||
102 | |||
103 | case led_amber_off: | ||
104 | if (led_state & LED_STATE_CLAIMED) | ||
105 | hw_led_state &= ~(GPIO_GREEN_LED | GPIO_RED_LED); | ||
106 | break; | ||
107 | |||
108 | case led_red_on: | ||
109 | if (led_state & LED_STATE_CLAIMED) | ||
110 | hw_led_state |= GPIO_RED_LED; | ||
111 | break; | ||
112 | |||
113 | case led_red_off: | ||
114 | if (led_state & LED_STATE_CLAIMED) | ||
115 | hw_led_state &= ~GPIO_RED_LED; | ||
116 | break; | ||
117 | |||
118 | default: | ||
119 | break; | ||
120 | } | ||
121 | |||
122 | spin_unlock_irqrestore(&leds_lock, flags); | ||
123 | |||
124 | if (led_state & LED_STATE_ENABLED) { | ||
125 | spin_lock_irqsave(&gpio_lock, flags); | ||
126 | gpio_modify_op(GPIO_RED_LED | GPIO_GREEN_LED, hw_led_state); | ||
127 | spin_unlock_irqrestore(&gpio_lock, flags); | ||
128 | } | ||
129 | } | ||
130 | |||
131 | static int __init leds_init(void) | ||
132 | { | ||
133 | if (machine_is_netwinder()) | ||
134 | leds_event = netwinder_leds_event; | ||
135 | |||
136 | leds_event(led_start); | ||
137 | |||
138 | return 0; | ||
139 | } | ||
140 | |||
141 | __initcall(leds_init); | ||
diff --git a/arch/arm/mach-footbridge/netwinder-pci.c b/arch/arm/mach-footbridge/netwinder-pci.c new file mode 100644 index 000000000000..e263d6d54a0f --- /dev/null +++ b/arch/arm/mach-footbridge/netwinder-pci.c | |||
@@ -0,0 +1,62 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-footbridge/netwinder-pci.c | ||
3 | * | ||
4 | * PCI bios-type initialisation for PCI machines | ||
5 | * | ||
6 | * Bits taken from various places. | ||
7 | */ | ||
8 | #include <linux/kernel.h> | ||
9 | #include <linux/pci.h> | ||
10 | #include <linux/init.h> | ||
11 | |||
12 | #include <asm/irq.h> | ||
13 | #include <asm/mach/pci.h> | ||
14 | #include <asm/mach-types.h> | ||
15 | |||
16 | /* | ||
17 | * We now use the slot ID instead of the device identifiers to select | ||
18 | * which interrupt is routed where. | ||
19 | */ | ||
20 | static int __init netwinder_map_irq(struct pci_dev *dev, u8 slot, u8 pin) | ||
21 | { | ||
22 | switch (slot) { | ||
23 | case 0: /* host bridge */ | ||
24 | return 0; | ||
25 | |||
26 | case 9: /* CyberPro */ | ||
27 | return IRQ_NETWINDER_VGA; | ||
28 | |||
29 | case 10: /* DC21143 */ | ||
30 | return IRQ_NETWINDER_ETHER100; | ||
31 | |||
32 | case 12: /* Winbond 553 */ | ||
33 | return IRQ_ISA_HARDDISK1; | ||
34 | |||
35 | case 13: /* Winbond 89C940F */ | ||
36 | return IRQ_NETWINDER_ETHER10; | ||
37 | |||
38 | default: | ||
39 | printk(KERN_ERR "PCI: unknown device in slot %s\n", | ||
40 | pci_name(dev)); | ||
41 | return 0; | ||
42 | } | ||
43 | } | ||
44 | |||
45 | static struct hw_pci netwinder_pci __initdata = { | ||
46 | .swizzle = pci_std_swizzle, | ||
47 | .map_irq = netwinder_map_irq, | ||
48 | .nr_controllers = 1, | ||
49 | .setup = dc21285_setup, | ||
50 | .scan = dc21285_scan_bus, | ||
51 | .preinit = dc21285_preinit, | ||
52 | .postinit = dc21285_postinit, | ||
53 | }; | ||
54 | |||
55 | static int __init netwinder_pci_init(void) | ||
56 | { | ||
57 | if (machine_is_netwinder()) | ||
58 | pci_common_init(&netwinder_pci); | ||
59 | return 0; | ||
60 | } | ||
61 | |||
62 | subsys_initcall(netwinder_pci_init); | ||
diff --git a/arch/arm/mach-footbridge/personal-pci.c b/arch/arm/mach-footbridge/personal-pci.c new file mode 100644 index 000000000000..d5fca95afdad --- /dev/null +++ b/arch/arm/mach-footbridge/personal-pci.c | |||
@@ -0,0 +1,56 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-footbridge/personal-pci.c | ||
3 | * | ||
4 | * PCI bios-type initialisation for PCI machines | ||
5 | * | ||
6 | * Bits taken from various places. | ||
7 | */ | ||
8 | #include <linux/kernel.h> | ||
9 | #include <linux/pci.h> | ||
10 | #include <linux/init.h> | ||
11 | |||
12 | #include <asm/irq.h> | ||
13 | #include <asm/mach/pci.h> | ||
14 | #include <asm/mach-types.h> | ||
15 | |||
16 | static int irqmap_personal_server[] __initdata = { | ||
17 | IRQ_IN0, IRQ_IN1, IRQ_IN2, IRQ_IN3, 0, 0, 0, | ||
18 | IRQ_DOORBELLHOST, IRQ_DMA1, IRQ_DMA2, IRQ_PCI | ||
19 | }; | ||
20 | |||
21 | static int __init personal_server_map_irq(struct pci_dev *dev, u8 slot, u8 pin) | ||
22 | { | ||
23 | unsigned char line; | ||
24 | |||
25 | pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &line); | ||
26 | |||
27 | if (line > 0x40 && line <= 0x5f) { | ||
28 | /* line corresponds to the bit controlling this interrupt | ||
29 | * in the footbridge. Ignore the first 8 interrupt bits, | ||
30 | * look up the rest in the map. IN0 is bit number 8 | ||
31 | */ | ||
32 | return irqmap_personal_server[(line & 0x1f) - 8]; | ||
33 | } else if (line == 0) { | ||
34 | /* no interrupt */ | ||
35 | return 0; | ||
36 | } else | ||
37 | return irqmap_personal_server[(line - 1) & 3]; | ||
38 | } | ||
39 | |||
40 | static struct hw_pci personal_server_pci __initdata = { | ||
41 | .map_irq = personal_server_map_irq, | ||
42 | .nr_controllers = 1, | ||
43 | .setup = dc21285_setup, | ||
44 | .scan = dc21285_scan_bus, | ||
45 | .preinit = dc21285_preinit, | ||
46 | .postinit = dc21285_postinit, | ||
47 | }; | ||
48 | |||
49 | static int __init personal_pci_init(void) | ||
50 | { | ||
51 | if (machine_is_personal_server()) | ||
52 | pci_common_init(&personal_server_pci); | ||
53 | return 0; | ||
54 | } | ||
55 | |||
56 | subsys_initcall(personal_pci_init); | ||
diff --git a/arch/arm/mach-footbridge/personal.c b/arch/arm/mach-footbridge/personal.c new file mode 100644 index 000000000000..415086d7bbee --- /dev/null +++ b/arch/arm/mach-footbridge/personal.c | |||
@@ -0,0 +1,23 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-footbridge/personal.c | ||
3 | * | ||
4 | * Personal server (Skiff) machine fixup | ||
5 | */ | ||
6 | #include <linux/init.h> | ||
7 | |||
8 | #include <asm/hardware/dec21285.h> | ||
9 | #include <asm/mach-types.h> | ||
10 | |||
11 | #include <asm/mach/arch.h> | ||
12 | |||
13 | #include "common.h" | ||
14 | |||
15 | MACHINE_START(PERSONAL_SERVER, "Compaq-PersonalServer") | ||
16 | MAINTAINER("Jamey Hicks / George France") | ||
17 | BOOT_MEM(0x00000000, DC21285_ARMCSR_BASE, 0xfe000000) | ||
18 | BOOT_PARAMS(0x00000100) | ||
19 | MAPIO(footbridge_map_io) | ||
20 | INITIRQ(footbridge_init_irq) | ||
21 | .timer = &footbridge_timer, | ||
22 | MACHINE_END | ||
23 | |||
diff --git a/arch/arm/mach-footbridge/time.c b/arch/arm/mach-footbridge/time.c new file mode 100644 index 000000000000..2c64a0b0502e --- /dev/null +++ b/arch/arm/mach-footbridge/time.c | |||
@@ -0,0 +1,180 @@ | |||
1 | /* | ||
2 | * linux/include/asm-arm/arch-ebsa285/time.h | ||
3 | * | ||
4 | * Copyright (C) 1998 Russell King. | ||
5 | * Copyright (C) 1998 Phil Blundell | ||
6 | * | ||
7 | * CATS has a real-time clock, though the evaluation board doesn't. | ||
8 | * | ||
9 | * Changelog: | ||
10 | * 21-Mar-1998 RMK Created | ||
11 | * 27-Aug-1998 PJB CATS support | ||
12 | * 28-Dec-1998 APH Made leds optional | ||
13 | * 20-Jan-1999 RMK Started merge of EBSA285, CATS and NetWinder | ||
14 | * 16-Mar-1999 RMK More support for EBSA285-like machines with RTCs in | ||
15 | */ | ||
16 | |||
17 | #define RTC_PORT(x) (rtc_base+(x)) | ||
18 | #define RTC_ALWAYS_BCD 0 | ||
19 | |||
20 | #include <linux/timex.h> | ||
21 | #include <linux/init.h> | ||
22 | #include <linux/sched.h> | ||
23 | #include <linux/mc146818rtc.h> | ||
24 | #include <linux/bcd.h> | ||
25 | |||
26 | #include <asm/hardware.h> | ||
27 | #include <asm/io.h> | ||
28 | |||
29 | #include <asm/mach/time.h> | ||
30 | #include "common.h" | ||
31 | |||
32 | static int rtc_base; | ||
33 | |||
34 | static unsigned long __init get_isa_cmos_time(void) | ||
35 | { | ||
36 | unsigned int year, mon, day, hour, min, sec; | ||
37 | int i; | ||
38 | |||
39 | // check to see if the RTC makes sense..... | ||
40 | if ((CMOS_READ(RTC_VALID) & RTC_VRT) == 0) | ||
41 | return mktime(1970, 1, 1, 0, 0, 0); | ||
42 | |||
43 | /* The Linux interpretation of the CMOS clock register contents: | ||
44 | * When the Update-In-Progress (UIP) flag goes from 1 to 0, the | ||
45 | * RTC registers show the second which has precisely just started. | ||
46 | * Let's hope other operating systems interpret the RTC the same way. | ||
47 | */ | ||
48 | /* read RTC exactly on falling edge of update flag */ | ||
49 | for (i = 0 ; i < 1000000 ; i++) /* may take up to 1 second... */ | ||
50 | if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP) | ||
51 | break; | ||
52 | |||
53 | for (i = 0 ; i < 1000000 ; i++) /* must try at least 2.228 ms */ | ||
54 | if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)) | ||
55 | break; | ||
56 | |||
57 | do { /* Isn't this overkill ? UIP above should guarantee consistency */ | ||
58 | sec = CMOS_READ(RTC_SECONDS); | ||
59 | min = CMOS_READ(RTC_MINUTES); | ||
60 | hour = CMOS_READ(RTC_HOURS); | ||
61 | day = CMOS_READ(RTC_DAY_OF_MONTH); | ||
62 | mon = CMOS_READ(RTC_MONTH); | ||
63 | year = CMOS_READ(RTC_YEAR); | ||
64 | } while (sec != CMOS_READ(RTC_SECONDS)); | ||
65 | |||
66 | if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { | ||
67 | BCD_TO_BIN(sec); | ||
68 | BCD_TO_BIN(min); | ||
69 | BCD_TO_BIN(hour); | ||
70 | BCD_TO_BIN(day); | ||
71 | BCD_TO_BIN(mon); | ||
72 | BCD_TO_BIN(year); | ||
73 | } | ||
74 | if ((year += 1900) < 1970) | ||
75 | year += 100; | ||
76 | return mktime(year, mon, day, hour, min, sec); | ||
77 | } | ||
78 | |||
79 | static int set_isa_cmos_time(void) | ||
80 | { | ||
81 | int retval = 0; | ||
82 | int real_seconds, real_minutes, cmos_minutes; | ||
83 | unsigned char save_control, save_freq_select; | ||
84 | unsigned long nowtime = xtime.tv_sec; | ||
85 | |||
86 | save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */ | ||
87 | CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); | ||
88 | |||
89 | save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */ | ||
90 | CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); | ||
91 | |||
92 | cmos_minutes = CMOS_READ(RTC_MINUTES); | ||
93 | if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) | ||
94 | BCD_TO_BIN(cmos_minutes); | ||
95 | |||
96 | /* | ||
97 | * since we're only adjusting minutes and seconds, | ||
98 | * don't interfere with hour overflow. This avoids | ||
99 | * messing with unknown time zones but requires your | ||
100 | * RTC not to be off by more than 15 minutes | ||
101 | */ | ||
102 | real_seconds = nowtime % 60; | ||
103 | real_minutes = nowtime / 60; | ||
104 | if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1) | ||
105 | real_minutes += 30; /* correct for half hour time zone */ | ||
106 | real_minutes %= 60; | ||
107 | |||
108 | if (abs(real_minutes - cmos_minutes) < 30) { | ||
109 | if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { | ||
110 | BIN_TO_BCD(real_seconds); | ||
111 | BIN_TO_BCD(real_minutes); | ||
112 | } | ||
113 | CMOS_WRITE(real_seconds,RTC_SECONDS); | ||
114 | CMOS_WRITE(real_minutes,RTC_MINUTES); | ||
115 | } else | ||
116 | retval = -1; | ||
117 | |||
118 | /* The following flags have to be released exactly in this order, | ||
119 | * otherwise the DS12887 (popular MC146818A clone with integrated | ||
120 | * battery and quartz) will not reset the oscillator and will not | ||
121 | * update precisely 500 ms later. You won't find this mentioned in | ||
122 | * the Dallas Semiconductor data sheets, but who believes data | ||
123 | * sheets anyway ... -- Markus Kuhn | ||
124 | */ | ||
125 | CMOS_WRITE(save_control, RTC_CONTROL); | ||
126 | CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); | ||
127 | |||
128 | return retval; | ||
129 | } | ||
130 | |||
131 | void __init isa_rtc_init(void) | ||
132 | { | ||
133 | if (machine_is_co285() || | ||
134 | machine_is_personal_server()) | ||
135 | /* | ||
136 | * Add-in 21285s shouldn't access the RTC | ||
137 | */ | ||
138 | rtc_base = 0; | ||
139 | else | ||
140 | rtc_base = 0x70; | ||
141 | |||
142 | if (rtc_base) { | ||
143 | int reg_d, reg_b; | ||
144 | |||
145 | /* | ||
146 | * Probe for the RTC. | ||
147 | */ | ||
148 | reg_d = CMOS_READ(RTC_REG_D); | ||
149 | |||
150 | /* | ||
151 | * make sure the divider is set | ||
152 | */ | ||
153 | CMOS_WRITE(RTC_REF_CLCK_32KHZ, RTC_REG_A); | ||
154 | |||
155 | /* | ||
156 | * Set control reg B | ||
157 | * (24 hour mode, update enabled) | ||
158 | */ | ||
159 | reg_b = CMOS_READ(RTC_REG_B) & 0x7f; | ||
160 | reg_b |= 2; | ||
161 | CMOS_WRITE(reg_b, RTC_REG_B); | ||
162 | |||
163 | if ((CMOS_READ(RTC_REG_A) & 0x7f) == RTC_REF_CLCK_32KHZ && | ||
164 | CMOS_READ(RTC_REG_B) == reg_b) { | ||
165 | struct timespec tv; | ||
166 | |||
167 | /* | ||
168 | * We have a RTC. Check the battery | ||
169 | */ | ||
170 | if ((reg_d & 0x80) == 0) | ||
171 | printk(KERN_WARNING "RTC: *** warning: CMOS battery bad\n"); | ||
172 | |||
173 | tv.tv_nsec = 0; | ||
174 | tv.tv_sec = get_isa_cmos_time(); | ||
175 | do_settimeofday(&tv); | ||
176 | set_rtc = set_isa_cmos_time; | ||
177 | } else | ||
178 | rtc_base = 0; | ||
179 | } | ||
180 | } | ||