aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-ebsa110
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-ebsa110')
-rw-r--r--arch/arm/mach-ebsa110/Makefile12
-rw-r--r--arch/arm/mach-ebsa110/Makefile.boot4
-rw-r--r--arch/arm/mach-ebsa110/core.c245
-rw-r--r--arch/arm/mach-ebsa110/io.c378
-rw-r--r--arch/arm/mach-ebsa110/leds.c51
5 files changed, 690 insertions, 0 deletions
diff --git a/arch/arm/mach-ebsa110/Makefile b/arch/arm/mach-ebsa110/Makefile
new file mode 100644
index 000000000000..6520ac835802
--- /dev/null
+++ b/arch/arm/mach-ebsa110/Makefile
@@ -0,0 +1,12 @@
1#
2# Makefile for the linux kernel.
3#
4
5# Object file lists.
6
7obj-y := core.o io.o
8obj-m :=
9obj-n :=
10obj- :=
11
12obj-$(CONFIG_LEDS) += leds.o
diff --git a/arch/arm/mach-ebsa110/Makefile.boot b/arch/arm/mach-ebsa110/Makefile.boot
new file mode 100644
index 000000000000..232126044935
--- /dev/null
+++ b/arch/arm/mach-ebsa110/Makefile.boot
@@ -0,0 +1,4 @@
1 zreladdr-y := 0x00008000
2params_phys-y := 0x00000400
3initrd_phys-y := 0x00800000
4
diff --git a/arch/arm/mach-ebsa110/core.c b/arch/arm/mach-ebsa110/core.c
new file mode 100644
index 000000000000..ef362d44949d
--- /dev/null
+++ b/arch/arm/mach-ebsa110/core.c
@@ -0,0 +1,245 @@
1/*
2 * linux/arch/arm/mach-ebsa110/core.c
3 *
4 * Copyright (C) 1998-2001 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 * Extra MM routines for the EBSA-110 architecture
11 */
12#include <linux/kernel.h>
13#include <linux/mm.h>
14#include <linux/interrupt.h>
15#include <linux/serial_8250.h>
16#include <linux/init.h>
17
18#include <asm/hardware.h>
19#include <asm/irq.h>
20#include <asm/io.h>
21#include <asm/setup.h>
22#include <asm/mach-types.h>
23#include <asm/pgtable.h>
24#include <asm/page.h>
25#include <asm/system.h>
26
27#include <asm/mach/arch.h>
28#include <asm/mach/irq.h>
29#include <asm/mach/map.h>
30
31#include <asm/mach/time.h>
32
33#define IRQ_MASK 0xfe000000 /* read */
34#define IRQ_MSET 0xfe000000 /* write */
35#define IRQ_STAT 0xff000000 /* read */
36#define IRQ_MCLR 0xff000000 /* write */
37
38static void ebsa110_mask_irq(unsigned int irq)
39{
40 __raw_writeb(1 << irq, IRQ_MCLR);
41}
42
43static void ebsa110_unmask_irq(unsigned int irq)
44{
45 __raw_writeb(1 << irq, IRQ_MSET);
46}
47
48static struct irqchip ebsa110_irq_chip = {
49 .ack = ebsa110_mask_irq,
50 .mask = ebsa110_mask_irq,
51 .unmask = ebsa110_unmask_irq,
52};
53
54static void __init ebsa110_init_irq(void)
55{
56 unsigned long flags;
57 unsigned int irq;
58
59 local_irq_save(flags);
60 __raw_writeb(0xff, IRQ_MCLR);
61 __raw_writeb(0x55, IRQ_MSET);
62 __raw_writeb(0x00, IRQ_MSET);
63 if (__raw_readb(IRQ_MASK) != 0x55)
64 while (1);
65 __raw_writeb(0xff, IRQ_MCLR); /* clear all interrupt enables */
66 local_irq_restore(flags);
67
68 for (irq = 0; irq < NR_IRQS; irq++) {
69 set_irq_chip(irq, &ebsa110_irq_chip);
70 set_irq_handler(irq, do_level_IRQ);
71 set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
72 }
73}
74
75static struct map_desc ebsa110_io_desc[] __initdata = {
76 /*
77 * sparse external-decode ISAIO space
78 */
79 { IRQ_STAT, TRICK4_PHYS, PGDIR_SIZE, MT_DEVICE }, /* IRQ_STAT/IRQ_MCLR */
80 { IRQ_MASK, TRICK3_PHYS, PGDIR_SIZE, MT_DEVICE }, /* IRQ_MASK/IRQ_MSET */
81 { SOFT_BASE, TRICK1_PHYS, PGDIR_SIZE, MT_DEVICE }, /* SOFT_BASE */
82 { PIT_BASE, TRICK0_PHYS, PGDIR_SIZE, MT_DEVICE }, /* PIT_BASE */
83
84 /*
85 * self-decode ISAIO space
86 */
87 { ISAIO_BASE, ISAIO_PHYS, ISAIO_SIZE, MT_DEVICE },
88 { ISAMEM_BASE, ISAMEM_PHYS, ISAMEM_SIZE, MT_DEVICE }
89};
90
91static void __init ebsa110_map_io(void)
92{
93 iotable_init(ebsa110_io_desc, ARRAY_SIZE(ebsa110_io_desc));
94}
95
96
97#define PIT_CTRL (PIT_BASE + 0x0d)
98#define PIT_T2 (PIT_BASE + 0x09)
99#define PIT_T1 (PIT_BASE + 0x05)
100#define PIT_T0 (PIT_BASE + 0x01)
101
102/*
103 * This is the rate at which your MCLK signal toggles (in Hz)
104 * This was measured on a 10 digit frequency counter sampling
105 * over 1 second.
106 */
107#define MCLK 47894000
108
109/*
110 * This is the rate at which the PIT timers get clocked
111 */
112#define CLKBY7 (MCLK / 7)
113
114/*
115 * This is the counter value. We tick at 200Hz on this platform.
116 */
117#define COUNT ((CLKBY7 + (HZ / 2)) / HZ)
118
119/*
120 * Get the time offset from the system PIT. Note that if we have missed an
121 * interrupt, then the PIT counter will roll over (ie, be negative).
122 * This actually works out to be convenient.
123 */
124static unsigned long ebsa110_gettimeoffset(void)
125{
126 unsigned long offset, count;
127
128 __raw_writeb(0x40, PIT_CTRL);
129 count = __raw_readb(PIT_T1);
130 count |= __raw_readb(PIT_T1) << 8;
131
132 /*
133 * If count > COUNT, make the number negative.
134 */
135 if (count > COUNT)
136 count |= 0xffff0000;
137
138 offset = COUNT;
139 offset -= count;
140
141 /*
142 * `offset' is in units of timer counts. Convert
143 * offset to units of microseconds.
144 */
145 offset = offset * (1000000 / HZ) / COUNT;
146
147 return offset;
148}
149
150static irqreturn_t
151ebsa110_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
152{
153 u32 count;
154
155 write_seqlock(&xtime_lock);
156
157 /* latch and read timer 1 */
158 __raw_writeb(0x40, PIT_CTRL);
159 count = __raw_readb(PIT_T1);
160 count |= __raw_readb(PIT_T1) << 8;
161
162 count += COUNT;
163
164 __raw_writeb(count & 0xff, PIT_T1);
165 __raw_writeb(count >> 8, PIT_T1);
166
167 timer_tick(regs);
168
169 write_sequnlock(&xtime_lock);
170
171 return IRQ_HANDLED;
172}
173
174static struct irqaction ebsa110_timer_irq = {
175 .name = "EBSA110 Timer Tick",
176 .flags = SA_INTERRUPT,
177 .handler = ebsa110_timer_interrupt
178};
179
180/*
181 * Set up timer interrupt.
182 */
183static void __init ebsa110_timer_init(void)
184{
185 /*
186 * Timer 1, mode 2, LSB/MSB
187 */
188 __raw_writeb(0x70, PIT_CTRL);
189 __raw_writeb(COUNT & 0xff, PIT_T1);
190 __raw_writeb(COUNT >> 8, PIT_T1);
191
192 setup_irq(IRQ_EBSA110_TIMER0, &ebsa110_timer_irq);
193}
194
195static struct sys_timer ebsa110_timer = {
196 .init = ebsa110_timer_init,
197 .offset = ebsa110_gettimeoffset,
198};
199
200static struct plat_serial8250_port serial_platform_data[] = {
201 {
202 .iobase = 0x3f8,
203 .irq = 1,
204 .uartclk = 1843200,
205 .regshift = 0,
206 .iotype = UPIO_PORT,
207 .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
208 },
209 {
210 .iobase = 0x2f8,
211 .irq = 2,
212 .uartclk = 1843200,
213 .regshift = 0,
214 .iotype = UPIO_PORT,
215 .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
216 },
217 { },
218};
219
220static struct platform_device serial_device = {
221 .name = "serial8250",
222 .id = 0,
223 .dev = {
224 .platform_data = serial_platform_data,
225 },
226};
227
228static int __init ebsa110_init(void)
229{
230 return platform_device_register(&serial_device);
231}
232
233arch_initcall(ebsa110_init);
234
235MACHINE_START(EBSA110, "EBSA110")
236 MAINTAINER("Russell King")
237 BOOT_MEM(0x00000000, 0xe0000000, 0xe0000000)
238 BOOT_PARAMS(0x00000400)
239 DISABLE_PARPORT(0)
240 DISABLE_PARPORT(2)
241 SOFT_REBOOT
242 MAPIO(ebsa110_map_io)
243 INITIRQ(ebsa110_init_irq)
244 .timer = &ebsa110_timer,
245MACHINE_END
diff --git a/arch/arm/mach-ebsa110/io.c b/arch/arm/mach-ebsa110/io.c
new file mode 100644
index 000000000000..ef7eb5dc91bd
--- /dev/null
+++ b/arch/arm/mach-ebsa110/io.c
@@ -0,0 +1,378 @@
1/*
2 * linux/arch/arm/mach-ebsa110/isamem.c
3 *
4 * Copyright (C) 2001 Russell King
5 *
6 * Perform "ISA" memory and IO accesses. The EBSA110 has some "peculiarities"
7 * in the way it handles accesses to odd IO ports on 16-bit devices. These
8 * devices have their D0-D15 lines connected to the processors D0-D15 lines.
9 * Since they expect all byte IO operations to be performed on D0-D7, and the
10 * StrongARM expects to transfer the byte to these odd addresses on D8-D15,
11 * we must use a trick to get the required behaviour.
12 *
13 * The trick employed here is to use long word stores to odd address -1. The
14 * glue logic picks this up as a "trick" access, and asserts the LSB of the
15 * peripherals address bus, thereby accessing the odd IO port. Meanwhile, the
16 * StrongARM transfers its data on D0-D7 as expected.
17 *
18 * Things get more interesting on the pass-1 EBSA110 - the PCMCIA controller
19 * wiring was screwed in such a way that it had limited memory space access.
20 * Luckily, the work-around for this is not too horrible. See
21 * __isamem_convert_addr for the details.
22 */
23#include <linux/module.h>
24#include <linux/kernel.h>
25#include <linux/types.h>
26
27#include <asm/io.h>
28#include <asm/page.h>
29
30static void __iomem *__isamem_convert_addr(void __iomem *addr)
31{
32 u32 ret, a = (u32 __force) addr;
33
34 /*
35 * The PCMCIA controller is wired up as follows:
36 * +---------+---------+---------+---------+---------+---------+
37 * PCMCIA | 2 2 2 2 | 1 1 1 1 | 1 1 1 1 | 1 1 | | |
38 * | 3 2 1 0 | 9 8 7 6 | 5 4 3 2 | 1 0 9 8 | 7 6 5 4 | 3 2 1 0 |
39 * +---------+---------+---------+---------+---------+---------+
40 * CPU | 2 2 2 2 | 2 1 1 1 | 1 1 1 1 | 1 1 1 | | |
41 * | 4 3 2 1 | 0 9 9 8 | 7 6 5 4 | 3 2 0 9 | 8 7 6 5 | 4 3 2 x |
42 * +---------+---------+---------+---------+---------+---------+
43 *
44 * This means that we can access PCMCIA regions as follows:
45 * 0x*10000 -> 0x*1ffff
46 * 0x*70000 -> 0x*7ffff
47 * 0x*90000 -> 0x*9ffff
48 * 0x*f0000 -> 0x*fffff
49 */
50 ret = (a & 0xf803fe) << 1;
51 ret |= (a & 0x03fc00) << 2;
52
53 ret += 0xe8000000;
54
55 if ((a & 0x20000) == (a & 0x40000) >> 1)
56 return (void __iomem *)ret;
57
58 BUG();
59 return NULL;
60}
61
62/*
63 * read[bwl] and write[bwl]
64 */
65u8 __readb(void __iomem *addr)
66{
67 void __iomem *a = __isamem_convert_addr(addr);
68 u32 ret;
69
70 if ((unsigned long)addr & 1)
71 ret = __raw_readl(a);
72 else
73 ret = __raw_readb(a);
74 return ret;
75}
76
77u16 __readw(void __iomem *addr)
78{
79 void __iomem *a = __isamem_convert_addr(addr);
80
81 if ((unsigned long)addr & 1)
82 BUG();
83
84 return __raw_readw(a);
85}
86
87u32 __readl(void __iomem *addr)
88{
89 void __iomem *a = __isamem_convert_addr(addr);
90 u32 ret;
91
92 if ((unsigned long)addr & 3)
93 BUG();
94
95 ret = __raw_readw(a);
96 ret |= __raw_readw(a + 4) << 16;
97 return ret;
98}
99
100EXPORT_SYMBOL(__readb);
101EXPORT_SYMBOL(__readw);
102EXPORT_SYMBOL(__readl);
103
104void __writeb(u8 val, void __iomem *addr)
105{
106 void __iomem *a = __isamem_convert_addr(addr);
107
108 if ((unsigned long)addr & 1)
109 __raw_writel(val, a);
110 else
111 __raw_writeb(val, a);
112}
113
114void __writew(u16 val, void __iomem *addr)
115{
116 void __iomem *a = __isamem_convert_addr(addr);
117
118 if ((unsigned long)addr & 1)
119 BUG();
120
121 __raw_writew(val, a);
122}
123
124void __writel(u32 val, void __iomem *addr)
125{
126 void __iomem *a = __isamem_convert_addr(addr);
127
128 if ((unsigned long)addr & 3)
129 BUG();
130
131 __raw_writew(val, a);
132 __raw_writew(val >> 16, a + 4);
133}
134
135EXPORT_SYMBOL(__writeb);
136EXPORT_SYMBOL(__writew);
137EXPORT_SYMBOL(__writel);
138
139#define SUPERIO_PORT(p) \
140 (((p) >> 3) == (0x3f8 >> 3) || \
141 ((p) >> 3) == (0x2f8 >> 3) || \
142 ((p) >> 3) == (0x378 >> 3))
143
144/*
145 * We're addressing an 8 or 16-bit peripheral which tranfers
146 * odd addresses on the low ISA byte lane.
147 */
148u8 __inb8(unsigned int port)
149{
150 u32 ret;
151
152 /*
153 * The SuperIO registers use sane addressing techniques...
154 */
155 if (SUPERIO_PORT(port))
156 ret = __raw_readb((void __iomem *)ISAIO_BASE + (port << 2));
157 else {
158 void __iomem *a = (void __iomem *)ISAIO_BASE + ((port & ~1) << 1);
159
160 /*
161 * Shame nothing else does
162 */
163 if (port & 1)
164 ret = __raw_readl(a);
165 else
166 ret = __raw_readb(a);
167 }
168 return ret;
169}
170
171/*
172 * We're addressing a 16-bit peripheral which transfers odd
173 * addresses on the high ISA byte lane.
174 */
175u8 __inb16(unsigned int port)
176{
177 unsigned int offset;
178
179 /*
180 * The SuperIO registers use sane addressing techniques...
181 */
182 if (SUPERIO_PORT(port))
183 offset = port << 2;
184 else
185 offset = (port & ~1) << 1 | (port & 1);
186
187 return __raw_readb((void __iomem *)ISAIO_BASE + offset);
188}
189
190u16 __inw(unsigned int port)
191{
192 unsigned int offset;
193
194 /*
195 * The SuperIO registers use sane addressing techniques...
196 */
197 if (SUPERIO_PORT(port))
198 offset = port << 2;
199 else {
200 offset = port << 1;
201 BUG_ON(port & 1);
202 }
203 return __raw_readw((void __iomem *)ISAIO_BASE + offset);
204}
205
206/*
207 * Fake a 32-bit read with two 16-bit reads. Needed for 3c589.
208 */
209u32 __inl(unsigned int port)
210{
211 void __iomem *a;
212
213 if (SUPERIO_PORT(port) || port & 3)
214 BUG();
215
216 a = (void __iomem *)ISAIO_BASE + ((port & ~1) << 1);
217
218 return __raw_readw(a) | __raw_readw(a + 4) << 16;
219}
220
221EXPORT_SYMBOL(__inb8);
222EXPORT_SYMBOL(__inb16);
223EXPORT_SYMBOL(__inw);
224EXPORT_SYMBOL(__inl);
225
226void __outb8(u8 val, unsigned int port)
227{
228 /*
229 * The SuperIO registers use sane addressing techniques...
230 */
231 if (SUPERIO_PORT(port))
232 __raw_writeb(val, (void __iomem *)ISAIO_BASE + (port << 2));
233 else {
234 void __iomem *a = (void __iomem *)ISAIO_BASE + ((port & ~1) << 1);
235
236 /*
237 * Shame nothing else does
238 */
239 if (port & 1)
240 __raw_writel(val, a);
241 else
242 __raw_writeb(val, a);
243 }
244}
245
246void __outb16(u8 val, unsigned int port)
247{
248 unsigned int offset;
249
250 /*
251 * The SuperIO registers use sane addressing techniques...
252 */
253 if (SUPERIO_PORT(port))
254 offset = port << 2;
255 else
256 offset = (port & ~1) << 1 | (port & 1);
257
258 __raw_writeb(val, (void __iomem *)ISAIO_BASE + offset);
259}
260
261void __outw(u16 val, unsigned int port)
262{
263 unsigned int offset;
264
265 /*
266 * The SuperIO registers use sane addressing techniques...
267 */
268 if (SUPERIO_PORT(port))
269 offset = port << 2;
270 else {
271 offset = port << 1;
272 BUG_ON(port & 1);
273 }
274 __raw_writew(val, (void __iomem *)ISAIO_BASE + offset);
275}
276
277void __outl(u32 val, unsigned int port)
278{
279 BUG();
280}
281
282EXPORT_SYMBOL(__outb8);
283EXPORT_SYMBOL(__outb16);
284EXPORT_SYMBOL(__outw);
285EXPORT_SYMBOL(__outl);
286
287void outsb(unsigned int port, const void *from, int len)
288{
289 u32 off;
290
291 if (SUPERIO_PORT(port))
292 off = port << 2;
293 else {
294 off = (port & ~1) << 1;
295 if (port & 1)
296 BUG();
297 }
298
299 __raw_writesb((void __iomem *)ISAIO_BASE + off, from, len);
300}
301
302void insb(unsigned int port, void *from, int len)
303{
304 u32 off;
305
306 if (SUPERIO_PORT(port))
307 off = port << 2;
308 else {
309 off = (port & ~1) << 1;
310 if (port & 1)
311 BUG();
312 }
313
314 __raw_readsb((void __iomem *)ISAIO_BASE + off, from, len);
315}
316
317EXPORT_SYMBOL(outsb);
318EXPORT_SYMBOL(insb);
319
320void outsw(unsigned int port, const void *from, int len)
321{
322 u32 off;
323
324 if (SUPERIO_PORT(port))
325 off = port << 2;
326 else {
327 off = (port & ~1) << 1;
328 if (port & 1)
329 BUG();
330 }
331
332 __raw_writesw((void __iomem *)ISAIO_BASE + off, from, len);
333}
334
335void insw(unsigned int port, void *from, int len)
336{
337 u32 off;
338
339 if (SUPERIO_PORT(port))
340 off = port << 2;
341 else {
342 off = (port & ~1) << 1;
343 if (port & 1)
344 BUG();
345 }
346
347 __raw_readsw((void __iomem *)ISAIO_BASE + off, from, len);
348}
349
350EXPORT_SYMBOL(outsw);
351EXPORT_SYMBOL(insw);
352
353/*
354 * We implement these as 16-bit insw/outsw, mainly for
355 * 3c589 cards.
356 */
357void outsl(unsigned int port, const void *from, int len)
358{
359 u32 off = port << 1;
360
361 if (SUPERIO_PORT(port) || port & 3)
362 BUG();
363
364 __raw_writesw((void __iomem *)ISAIO_BASE + off, from, len << 1);
365}
366
367void insl(unsigned int port, void *from, int len)
368{
369 u32 off = port << 1;
370
371 if (SUPERIO_PORT(port) || port & 3)
372 BUG();
373
374 __raw_readsw((void __iomem *)ISAIO_BASE + off, from, len << 1);
375}
376
377EXPORT_SYMBOL(outsl);
378EXPORT_SYMBOL(insl);
diff --git a/arch/arm/mach-ebsa110/leds.c b/arch/arm/mach-ebsa110/leds.c
new file mode 100644
index 000000000000..3bc8c5e708e6
--- /dev/null
+++ b/arch/arm/mach-ebsa110/leds.c
@@ -0,0 +1,51 @@
1/*
2 * linux/arch/arm/mach-ebsa110/leds.c
3 *
4 * Copyright (C) 1998 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 * EBSA-110 LED control routines. We use the led as follows:
11 *
12 * - Red - toggles state every 50 timer interrupts
13 */
14#include <linux/module.h>
15#include <linux/spinlock.h>
16#include <linux/init.h>
17
18#include <asm/hardware.h>
19#include <asm/leds.h>
20#include <asm/system.h>
21#include <asm/mach-types.h>
22
23static spinlock_t leds_lock;
24
25static void ebsa110_leds_event(led_event_t ledevt)
26{
27 unsigned long flags;
28
29 spin_lock_irqsave(&leds_lock, flags);
30
31 switch(ledevt) {
32 case led_timer:
33 *(volatile unsigned char *)SOFT_BASE ^= 128;
34 break;
35
36 default:
37 break;
38 }
39
40 spin_unlock_irqrestore(&leds_lock, flags);
41}
42
43static int __init leds_init(void)
44{
45 if (machine_is_ebsa110())
46 leds_event = ebsa110_leds_event;
47
48 return 0;
49}
50
51__initcall(leds_init);