blob: 9be6c32132541fadc88a81235df9927d5148b535 [file] [log] [blame]
Bellido Nicolas038c5b62005-06-20 18:51:05 +01001/*
2 * linux/arch/arm/mach-aaec2000/core.c
3 *
4 * Code common to all AAEC-2000 machines
5 *
6 * Copyright (c) 2005 Nicolas Bellido Y Ortega
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12#include <linux/config.h>
13#include <linux/module.h>
14#include <linux/kernel.h>
15#include <linux/init.h>
16#include <linux/list.h>
17#include <linux/errno.h>
18#include <linux/interrupt.h>
19#include <linux/timex.h>
20#include <linux/signal.h>
21
22#include <asm/hardware.h>
23#include <asm/irq.h>
24
25#include <asm/mach/irq.h>
26#include <asm/mach/time.h>
27#include <asm/mach/map.h>
28
29/*
30 * Common I/O mapping:
31 *
32 * Static virtual address mappings are as follow:
33 *
34 * 0xf8000000-0xf8001ffff: Devices connected to APB bus
35 * 0xf8002000-0xf8003ffff: Devices connected to AHB bus
36 *
37 * Below 0xe8000000 is reserved for vm allocation.
38 *
39 * The machine specific code must provide the extra mapping beside the
40 * default mapping provided here.
41 */
42static struct map_desc standard_io_desc[] __initdata = {
Deepak Saxenaf70cd652005-10-28 15:18:56 +010043 {
44 .virtual = VIO_APB_BASE,
45 .physical = __phys_to_pfn(PIO_APB_BASE),
46 .length = IO_APB_LENGTH,
47 .type = MT_DEVICE
48 }, {
49 .virtual = VIO_AHB_BASE,
50 .physical = __phys_to_pfn(PIO_AHB_BASE),
51 .length = IO_AHB_LENGTH,
52 .type = MT_DEVICE
53 }
Bellido Nicolas038c5b62005-06-20 18:51:05 +010054};
55
56void __init aaec2000_map_io(void)
57{
58 iotable_init(standard_io_desc, ARRAY_SIZE(standard_io_desc));
59}
60
61/*
62 * Interrupt handling routines
63 */
64static void aaec2000_int_ack(unsigned int irq)
65{
66 IRQ_INTSR = 1 << irq;
67}
68
69static void aaec2000_int_mask(unsigned int irq)
70{
71 IRQ_INTENC |= (1 << irq);
72}
73
74static void aaec2000_int_unmask(unsigned int irq)
75{
76 IRQ_INTENS |= (1 << irq);
77}
78
79static struct irqchip aaec2000_irq_chip = {
80 .ack = aaec2000_int_ack,
81 .mask = aaec2000_int_mask,
82 .unmask = aaec2000_int_unmask,
83};
84
85void __init aaec2000_init_irq(void)
86{
87 unsigned int i;
88
89 for (i = 0; i < NR_IRQS; i++) {
90 set_irq_handler(i, do_level_IRQ);
91 set_irq_chip(i, &aaec2000_irq_chip);
92 set_irq_flags(i, IRQF_VALID);
93 }
94
95 /* Disable all interrupts */
96 IRQ_INTENC = 0xffffffff;
97
98 /* Clear any pending interrupts */
99 IRQ_INTSR = IRQ_INTSR;
100}
101
102/*
103 * Time keeping
104 */
105/* IRQs are disabled before entering here from do_gettimeofday() */
106static unsigned long aaec2000_gettimeoffset(void)
107{
108 unsigned long ticks_to_match, elapsed, usec;
109
110 /* Get ticks before next timer match */
111 ticks_to_match = TIMER1_LOAD - TIMER1_VAL;
112
113 /* We need elapsed ticks since last match */
114 elapsed = LATCH - ticks_to_match;
115
116 /* Now, convert them to usec */
117 usec = (unsigned long)(elapsed * (tick_nsec / 1000))/LATCH;
118
119 return usec;
120}
121
122/* We enter here with IRQs enabled */
123static irqreturn_t
124aaec2000_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
125{
126 /* TODO: Check timer accuracy */
127 write_seqlock(&xtime_lock);
128
129 timer_tick(regs);
130 TIMER1_CLEAR = 1;
131
132 write_sequnlock(&xtime_lock);
133
134 return IRQ_HANDLED;
135}
136
137static struct irqaction aaec2000_timer_irq = {
138 .name = "AAEC-2000 Timer Tick",
Russell King09b8b5f2005-06-26 17:06:36 +0100139 .flags = SA_INTERRUPT | SA_TIMER,
140 .handler = aaec2000_timer_interrupt,
Bellido Nicolas038c5b62005-06-20 18:51:05 +0100141};
142
143static void __init aaec2000_timer_init(void)
144{
145 /* Disable timer 1 */
146 TIMER1_CTRL = 0;
147
148 /* We have somehow to generate a 100Hz clock.
149 * We then use the 508KHz timer in periodic mode.
150 */
151 TIMER1_LOAD = LATCH;
152 TIMER1_CLEAR = 1; /* Clear interrupt */
153
154 setup_irq(INT_TMR1_OFL, &aaec2000_timer_irq);
155
156 TIMER1_CTRL = TIMER_CTRL_ENABLE |
157 TIMER_CTRL_PERIODIC |
158 TIMER_CTRL_CLKSEL_508K;
159}
160
161struct sys_timer aaec2000_timer = {
162 .init = aaec2000_timer_init,
163 .offset = aaec2000_gettimeoffset,
164};
165