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 #include <linux/io.h>
18 
19 #include <mach/hardware.h>
20 #include <asm/irq.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 
ebsa110_mask_irq(struct irq_data * d)38 static void ebsa110_mask_irq(struct irq_data *d)
39 {
40 	__raw_writeb(1 << d->irq, IRQ_MCLR);
41 }
42 
ebsa110_unmask_irq(struct irq_data * d)43 static void ebsa110_unmask_irq(struct irq_data *d)
44 {
45 	__raw_writeb(1 << d->irq, IRQ_MSET);
46 }
47 
48 static struct irq_chip ebsa110_irq_chip = {
49 	.irq_ack	= ebsa110_mask_irq,
50 	.irq_mask	= ebsa110_mask_irq,
51 	.irq_unmask	= ebsa110_unmask_irq,
52 };
53 
ebsa110_init_irq(void)54 static 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 		irq_set_chip_and_handler(irq, &ebsa110_irq_chip,
70 					 handle_level_irq);
71 		set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
72 	}
73 }
74 
75 static struct map_desc ebsa110_io_desc[] __initdata = {
76 	/*
77 	 * sparse external-decode ISAIO space
78 	 */
79 	{	/* IRQ_STAT/IRQ_MCLR */
80 		.virtual	= IRQ_STAT,
81 		.pfn		= __phys_to_pfn(TRICK4_PHYS),
82 		.length		= PGDIR_SIZE,
83 		.type		= MT_DEVICE
84 	}, {	/* IRQ_MASK/IRQ_MSET */
85 		.virtual	= IRQ_MASK,
86 		.pfn		= __phys_to_pfn(TRICK3_PHYS),
87 		.length		= PGDIR_SIZE,
88 		.type		= MT_DEVICE
89 	}, {	/* SOFT_BASE */
90 		.virtual	= SOFT_BASE,
91 		.pfn		= __phys_to_pfn(TRICK1_PHYS),
92 		.length		= PGDIR_SIZE,
93 		.type		= MT_DEVICE
94 	}, {	/* PIT_BASE */
95 		.virtual	= PIT_BASE,
96 		.pfn		= __phys_to_pfn(TRICK0_PHYS),
97 		.length		= PGDIR_SIZE,
98 		.type		= MT_DEVICE
99 	},
100 
101 	/*
102 	 * self-decode ISAIO space
103 	 */
104 	{
105 		.virtual	= ISAIO_BASE,
106 		.pfn		= __phys_to_pfn(ISAIO_PHYS),
107 		.length		= ISAIO_SIZE,
108 		.type		= MT_DEVICE
109 	}, {
110 		.virtual	= ISAMEM_BASE,
111 		.pfn		= __phys_to_pfn(ISAMEM_PHYS),
112 		.length		= ISAMEM_SIZE,
113 		.type		= MT_DEVICE
114 	}
115 };
116 
ebsa110_map_io(void)117 static void __init ebsa110_map_io(void)
118 {
119 	iotable_init(ebsa110_io_desc, ARRAY_SIZE(ebsa110_io_desc));
120 }
121 
122 
123 #define PIT_CTRL		(PIT_BASE + 0x0d)
124 #define PIT_T2			(PIT_BASE + 0x09)
125 #define PIT_T1			(PIT_BASE + 0x05)
126 #define PIT_T0			(PIT_BASE + 0x01)
127 
128 /*
129  * This is the rate at which your MCLK signal toggles (in Hz)
130  * This was measured on a 10 digit frequency counter sampling
131  * over 1 second.
132  */
133 #define MCLK	47894000
134 
135 /*
136  * This is the rate at which the PIT timers get clocked
137  */
138 #define CLKBY7	(MCLK / 7)
139 
140 /*
141  * This is the counter value.  We tick at 200Hz on this platform.
142  */
143 #define COUNT	((CLKBY7 + (HZ / 2)) / HZ)
144 
145 /*
146  * Get the time offset from the system PIT.  Note that if we have missed an
147  * interrupt, then the PIT counter will roll over (ie, be negative).
148  * This actually works out to be convenient.
149  */
ebsa110_gettimeoffset(void)150 static unsigned long ebsa110_gettimeoffset(void)
151 {
152 	unsigned long offset, count;
153 
154 	__raw_writeb(0x40, PIT_CTRL);
155 	count = __raw_readb(PIT_T1);
156 	count |= __raw_readb(PIT_T1) << 8;
157 
158 	/*
159 	 * If count > COUNT, make the number negative.
160 	 */
161 	if (count > COUNT)
162 		count |= 0xffff0000;
163 
164 	offset = COUNT;
165 	offset -= count;
166 
167 	/*
168 	 * `offset' is in units of timer counts.  Convert
169 	 * offset to units of microseconds.
170 	 */
171 	offset = offset * (1000000 / HZ) / COUNT;
172 
173 	return offset;
174 }
175 
176 static irqreturn_t
ebsa110_timer_interrupt(int irq,void * dev_id)177 ebsa110_timer_interrupt(int irq, void *dev_id)
178 {
179 	u32 count;
180 
181 	/* latch and read timer 1 */
182 	__raw_writeb(0x40, PIT_CTRL);
183 	count = __raw_readb(PIT_T1);
184 	count |= __raw_readb(PIT_T1) << 8;
185 
186 	count += COUNT;
187 
188 	__raw_writeb(count & 0xff, PIT_T1);
189 	__raw_writeb(count >> 8, PIT_T1);
190 
191 	timer_tick();
192 
193 	return IRQ_HANDLED;
194 }
195 
196 static struct irqaction ebsa110_timer_irq = {
197 	.name		= "EBSA110 Timer Tick",
198 	.flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
199 	.handler	= ebsa110_timer_interrupt,
200 };
201 
202 /*
203  * Set up timer interrupt.
204  */
ebsa110_timer_init(void)205 static void __init ebsa110_timer_init(void)
206 {
207 	/*
208 	 * Timer 1, mode 2, LSB/MSB
209 	 */
210 	__raw_writeb(0x70, PIT_CTRL);
211 	__raw_writeb(COUNT & 0xff, PIT_T1);
212 	__raw_writeb(COUNT >> 8, PIT_T1);
213 
214 	setup_irq(IRQ_EBSA110_TIMER0, &ebsa110_timer_irq);
215 }
216 
217 static struct sys_timer ebsa110_timer = {
218 	.init		= ebsa110_timer_init,
219 	.offset		= ebsa110_gettimeoffset,
220 };
221 
222 static struct plat_serial8250_port serial_platform_data[] = {
223 	{
224 		.iobase		= 0x3f8,
225 		.irq		= 1,
226 		.uartclk	= 1843200,
227 		.regshift	= 0,
228 		.iotype		= UPIO_PORT,
229 		.flags		= UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
230 	},
231 	{
232 		.iobase		= 0x2f8,
233 		.irq		= 2,
234 		.uartclk	= 1843200,
235 		.regshift	= 0,
236 		.iotype		= UPIO_PORT,
237 		.flags		= UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
238 	},
239 	{ },
240 };
241 
242 static struct platform_device serial_device = {
243 	.name			= "serial8250",
244 	.id			= PLAT8250_DEV_PLATFORM,
245 	.dev			= {
246 		.platform_data	= serial_platform_data,
247 	},
248 };
249 
250 static struct resource am79c961_resources[] = {
251 	{
252 		.start		= 0x220,
253 		.end		= 0x238,
254 		.flags		= IORESOURCE_IO,
255 	}, {
256 		.start		= IRQ_EBSA110_ETHERNET,
257 		.end		= IRQ_EBSA110_ETHERNET,
258 		.flags		= IORESOURCE_IRQ,
259 	},
260 };
261 
262 static struct platform_device am79c961_device = {
263 	.name			= "am79c961",
264 	.id			= -1,
265 	.num_resources		= ARRAY_SIZE(am79c961_resources),
266 	.resource		= am79c961_resources,
267 };
268 
269 static struct platform_device *ebsa110_devices[] = {
270 	&serial_device,
271 	&am79c961_device,
272 };
273 
ebsa110_init(void)274 static int __init ebsa110_init(void)
275 {
276 	return platform_add_devices(ebsa110_devices, ARRAY_SIZE(ebsa110_devices));
277 }
278 
279 arch_initcall(ebsa110_init);
280 
ebsa110_restart(char mode,const char * cmd)281 static void ebsa110_restart(char mode, const char *cmd)
282 {
283 	soft_restart(0x80000000);
284 }
285 
286 MACHINE_START(EBSA110, "EBSA110")
287 	/* Maintainer: Russell King */
288 	.atag_offset	= 0x400,
289 	.reserve_lp0	= 1,
290 	.reserve_lp2	= 1,
291 	.restart_mode	= 's',
292 	.map_io		= ebsa110_map_io,
293 	.init_irq	= ebsa110_init_irq,
294 	.timer		= &ebsa110_timer,
295 	.restart	= ebsa110_restart,
296 MACHINE_END
297