Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/shaggy...
[linux-2.6] / arch / v850 / kernel / as85ep1.c
1 /*
2  * arch/v850/kernel/as85ep1.c -- AS85EP1 V850E evaluation chip/board
3  *
4  *  Copyright (C) 2002,03  NEC Electronics Corporation
5  *  Copyright (C) 2002,03  Miles Bader <miles@gnu.org>
6  *
7  * This file is subject to the terms and conditions of the GNU General
8  * Public License.  See the file COPYING in the main directory of this
9  * archive for more details.
10  *
11  * Written by Miles Bader <miles@gnu.org>
12  */
13
14 #include <linux/kernel.h>
15 #include <linux/module.h>
16 #include <linux/init.h>
17 #include <linux/bootmem.h>
18 #include <linux/major.h>
19 #include <linux/irq.h>
20
21 #include <asm/machdep.h>
22 #include <asm/atomic.h>
23 #include <asm/page.h>
24 #include <asm/v850e_timer_d.h>
25 #include <asm/v850e_uart.h>
26
27 #include "mach.h"
28
29
30 /* SRAM and SDRAM are vaguely contiguous (with a big hole in between; see
31    mach_reserve_bootmem for details); use both as one big area.  */
32 #define RAM_START       SRAM_ADDR
33 #define RAM_END         (SDRAM_ADDR + SDRAM_SIZE)
34
35 /* The bits of this port are connected to an 8-LED bar-graph.  */
36 #define LEDS_PORT       4
37
38
39 static void as85ep1_led_tick (void);
40
41 extern char _intv_copy_src_start, _intv_copy_src_end;
42 extern char _intv_copy_dst_start;
43
44
45 void __init mach_early_init (void)
46 {
47 #ifndef CONFIG_ROM_KERNEL
48         const u32 *src;
49         register u32 *dst asm ("ep");
50 #endif
51
52         AS85EP1_CSC(0) = 0x0403;
53         AS85EP1_BCT(0) = 0xB8B8;
54         AS85EP1_DWC(0) = 0x0104;
55         AS85EP1_BCC    = 0x0012;
56         AS85EP1_ASC    = 0;
57         AS85EP1_LBS    = 0x00A9;
58
59         AS85EP1_PORT_PMC(6)  = 0xFF; /* valid A0,A1,A20-A25 */
60         AS85EP1_PORT_PMC(7)  = 0x0E; /* valid CS1-CS3       */
61         AS85EP1_PORT_PMC(9)  = 0xFF; /* valid D16-D23       */
62         AS85EP1_PORT_PMC(10) = 0xFF; /* valid D24-D31       */
63
64         AS85EP1_RFS(1) = 0x800c;
65         AS85EP1_RFS(3) = 0x800c;
66         AS85EP1_SCR(1) = 0x20A9;
67         AS85EP1_SCR(3) = 0x20A9;
68
69 #ifndef CONFIG_ROM_KERNEL
70         /* The early chip we have is buggy, and writing the interrupt
71            vectors into low RAM may screw up, so for non-ROM kernels, we
72            only rely on the reset vector being downloaded, and copy the
73            rest of the interrupt vectors into place here.  The specific bug
74            is that writing address N, where (N & 0x10) == 0x10, will _also_
75            write to address (N - 0x10).  We avoid this (effectively) by
76            writing in 16-byte chunks backwards from the end.  */
77
78         AS85EP1_IRAMM = 0x3;    /* "write-mode" for the internal instruction memory */
79
80         src = (u32 *)(((u32)&_intv_copy_src_end - 1) & ~0xF);
81         dst = (u32 *)&_intv_copy_dst_start
82                 + (src - (u32 *)&_intv_copy_src_start);
83         do {
84                 u32 t0 = src[0], t1 = src[1], t2 = src[2], t3 = src[3];
85                 dst[0] = t0; dst[1] = t1; dst[2] = t2; dst[3] = t3;
86                 dst -= 4;
87                 src -= 4;
88         } while (src > (u32 *)&_intv_copy_src_start);
89
90         AS85EP1_IRAMM = 0x0;    /* "read-mode" for the internal instruction memory */
91 #endif /* !CONFIG_ROM_KERNEL */
92
93         v850e_intc_disable_irqs ();
94 }
95
96 void __init mach_setup (char **cmdline)
97 {
98         AS85EP1_PORT_PMC (LEDS_PORT) = 0; /* Make the LEDs port an I/O port. */
99         AS85EP1_PORT_PM (LEDS_PORT) = 0; /* Make all the bits output pins.  */
100         mach_tick = as85ep1_led_tick;
101 }
102
103 void __init mach_get_physical_ram (unsigned long *ram_start,
104                                    unsigned long *ram_len)
105 {
106         *ram_start = RAM_START;
107         *ram_len = RAM_END - RAM_START;
108 }
109
110 /* Convenience macros.  */
111 #define SRAM_END        (SRAM_ADDR + SRAM_SIZE)
112 #define SDRAM_END       (SDRAM_ADDR + SDRAM_SIZE)
113
114 void __init mach_reserve_bootmem ()
115 {
116         if (SDRAM_ADDR < RAM_END && SDRAM_ADDR > RAM_START)
117                 /* We can't use the space between SRAM and SDRAM, so
118                    prevent the kernel from trying.  */
119                 reserve_bootmem (SRAM_END, SDRAM_ADDR - SRAM_END);
120 }
121
122 void mach_gettimeofday (struct timespec *tv)
123 {
124         tv->tv_sec = 0;
125         tv->tv_nsec = 0;
126 }
127
128 void __init mach_sched_init (struct irqaction *timer_action)
129 {
130         /* Start hardware timer.  */
131         v850e_timer_d_configure (0, HZ);
132         /* Install timer interrupt handler.  */
133         setup_irq (IRQ_INTCMD(0), timer_action);
134 }
135
136 static struct v850e_intc_irq_init irq_inits[] = {
137         { "IRQ", 0,             NUM_MACH_IRQS,  1, 7 },
138         { "CCC", IRQ_INTCCC(0), IRQ_INTCCC_NUM, 1, 5 },
139         { "CMD", IRQ_INTCMD(0), IRQ_INTCMD_NUM, 1, 5 },
140         { "SRE", IRQ_INTSRE(0), IRQ_INTSRE_NUM, 3, 3 },
141         { "SR",  IRQ_INTSR(0),  IRQ_INTSR_NUM,  3, 4 },
142         { "ST",  IRQ_INTST(0),  IRQ_INTST_NUM,  3, 5 },
143         { 0 }
144 };
145 #define NUM_IRQ_INITS (ARRAY_SIZE(irq_inits) - 1)
146
147 static struct hw_interrupt_type hw_itypes[NUM_IRQ_INITS];
148
149 void __init mach_init_irqs (void)
150 {
151         v850e_intc_init_irq_types (irq_inits, hw_itypes);
152 }
153
154 void machine_restart (char *__unused)
155 {
156 #ifdef CONFIG_RESET_GUARD
157         disable_reset_guard ();
158 #endif
159         asm ("jmp r0"); /* Jump to the reset vector.  */
160 }
161
162 void machine_halt (void)
163 {
164 #ifdef CONFIG_RESET_GUARD
165         disable_reset_guard ();
166 #endif
167         local_irq_disable ();   /* Ignore all interrupts.  */
168         AS85EP1_PORT_IO (LEDS_PORT) = 0xAA;     /* Note that we halted.  */
169         for (;;)
170                 asm ("halt; nop; nop; nop; nop; nop");
171 }
172
173 void machine_power_off (void)
174 {
175         machine_halt ();
176 }
177
178 /* Called before configuring an on-chip UART.  */
179 void as85ep1_uart_pre_configure (unsigned chan, unsigned cflags, unsigned baud)
180 {
181         /* Make the shared uart/port pins be uart pins.  */
182         AS85EP1_PORT_PMC(3) |= (0x5 << chan);
183
184         /* The AS85EP1 connects some general-purpose I/O pins on the CPU to
185            the RTS/CTS lines of UART 1's serial connection.  I/O pins P53
186            and P54 are RTS and CTS respectively.  */
187         if (chan == 1) {
188                 /* Put P53 & P54 in I/O port mode.  */
189                 AS85EP1_PORT_PMC(5) &= ~0x18;
190                 /* Make P53 an output, and P54 an input.  */
191                 AS85EP1_PORT_PM(5) |=  0x10;
192         }
193 }
194
195 /* Minimum and maximum bounds for the moving upper LED boundary in the
196    clock tick display.  */
197 #define MIN_MAX_POS 0
198 #define MAX_MAX_POS 7
199
200 /* There are MAX_MAX_POS^2 - MIN_MAX_POS^2 cycles in the animation, so if
201    we pick 6 and 0 as above, we get 49 cycles, which is when divided into
202    the standard 100 value for HZ, gives us an almost 1s total time.  */
203 #define TICKS_PER_FRAME \
204         (HZ / (MAX_MAX_POS * MAX_MAX_POS - MIN_MAX_POS * MIN_MAX_POS))
205
206 static void as85ep1_led_tick ()
207 {
208         static unsigned counter = 0;
209         
210         if (++counter == TICKS_PER_FRAME) {
211                 static int pos = 0, max_pos = MAX_MAX_POS, dir = 1;
212
213                 if (dir > 0 && pos == max_pos) {
214                         dir = -1;
215                         if (max_pos == MIN_MAX_POS)
216                                 max_pos = MAX_MAX_POS;
217                         else
218                                 max_pos--;
219                 } else {
220                         if (dir < 0 && pos == 0)
221                                 dir = 1;
222
223                         if (pos + dir <= max_pos) {
224                                 /* Each bit of port 0 has a LED. */
225                                 set_bit (pos, &AS85EP1_PORT_IO(LEDS_PORT));
226                                 pos += dir;
227                                 clear_bit (pos, &AS85EP1_PORT_IO(LEDS_PORT));
228                         }
229                 }
230
231                 counter = 0;
232         }
233 }