ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / arch / v850 / kernel / fpga85e2c.c
1 /*
2  * arch/v850/kernel/fpga85e2c.h -- Machine-dependent defs for
3  *      FPGA implementation of V850E2/NA85E2C
4  *
5  *  Copyright (C) 2002,03  NEC Electronics Corporation
6  *  Copyright (C) 2002,03  Miles Bader <miles@gnu.org>
7  *
8  * This file is subject to the terms and conditions of the GNU General
9  * Public License.  See the file COPYING in the main directory of this
10  * archive for more details.
11  *
12  * Written by Miles Bader <miles@gnu.org>
13  */
14
15 #include <linux/config.h>
16 #include <linux/kernel.h>
17 #include <linux/module.h>
18 #include <linux/init.h>
19 #include <linux/mm.h>
20 #include <linux/swap.h>
21 #include <linux/bootmem.h>
22 #include <linux/irq.h>
23
24 #include <asm/atomic.h>
25 #include <asm/page.h>
26 #include <asm/machdep.h>
27 #include <asm/bitops.h>
28
29 #include "mach.h"
30
31 extern void memcons_setup (void);
32
33
34 #define REG_DUMP_ADDR           0x220000
35
36
37 extern struct irqaction reg_snap_action; /* fwd decl */
38
39
40 void __init mach_early_init (void)
41 {
42         int i;
43         const u32 *src;
44         register u32 *dst asm ("ep");
45         extern int panic_timeout;
46         extern u32 _intv_end, _intv_load_start;
47
48         /* Set bus sizes: CS0 32-bit, CS1 16-bit, CS7 8-bit,
49            everything else 32-bit.  */
50         V850E2_BSC = 0x2AA6;
51         for (i = 2; i <= 6; i++)
52                 CSDEV(i) = 0;   /* 32 bit */
53
54         /* Ensure that the simulator halts on a panic, instead of going
55            into an infinite loop inside the panic function.  */
56         panic_timeout = -1;
57
58         /* Move the interrupt vectors into their real location.  Note that
59            any relocations there are relative to the real location, so we
60            don't have to fix anything up.  We use a loop instead of calling
61            memcpy to keep this a leaf function (to avoid a function
62            prologue being generated).  */
63         dst = 0x10;             /* &_intv_start + 0x10.  */
64         src = &_intv_load_start;
65         do {
66                 u32 t0 = src[0], t1 = src[1], t2 = src[2], t3 = src[3];
67                 u32 t4 = src[4], t5 = src[5], t6 = src[6], t7 = src[7];
68                 dst[0] = t0; dst[1] = t1; dst[2] = t2; dst[3] = t3;
69                 dst[4] = t4; dst[5] = t5; dst[6] = t6; dst[7] = t7;
70                 dst += 8;
71                 src += 8;
72         } while (dst < &_intv_end);
73 }
74
75 void __init mach_setup (char **cmdline)
76 {
77         memcons_setup ();
78
79         /* Setup up NMI0 to copy the registers to a known memory location.
80            The FGPA board has a button that produces NMI0 when pressed, so
81            this allows us to push the button, and then look at memory to see
82            what's in the registers (there's no other way to easily do so).
83            We have to use `setup_irq' instead of `request_irq' because it's
84            still too early to do memory allocation.  */
85         setup_irq (IRQ_NMI (0), &reg_snap_action);
86 }
87
88 void mach_get_physical_ram (unsigned long *ram_start, unsigned long *ram_len)
89 {
90         *ram_start = ERAM_ADDR;
91         *ram_len = ERAM_SIZE;
92 }
93
94 void __init mach_sched_init (struct irqaction *timer_action)
95 {
96         /* Setup up the timer interrupt.  The FPGA peripheral control
97            registers _only_ work with single-bit writes (set1/clr1)!  */
98         __clear_bit (RPU_GTMC_CE_BIT, &RPU_GTMC);
99         __clear_bit (RPU_GTMC_CLK_BIT, &RPU_GTMC);
100         __set_bit (RPU_GTMC_CE_BIT, &RPU_GTMC);
101
102         /* We use the first RPU interrupt, which occurs every 8.192ms.  */
103         setup_irq (IRQ_RPU (0), timer_action);
104 }
105
106 \f
107 void mach_gettimeofday (struct timespec *tv)
108 {
109         tv->tv_sec = 0;
110         tv->tv_nsec = 0;
111 }
112
113 void machine_halt (void) __attribute__ ((noreturn));
114 void machine_halt (void)
115 {
116         for (;;) {
117                 DWC(0) = 0x7777;
118                 DWC(1) = 0x7777;
119                 ASC = 0xffff;
120                 FLGREG(0) = 1;  /* Halt immediately.  */
121                 asm ("di; halt; nop; nop; nop; nop; nop");
122         }
123 }
124
125 EXPORT_SYMBOL(machine_halt);
126
127 void machine_restart (char *__unused)
128 {
129         machine_halt ();
130 }
131
132 EXPORT_SYMBOL(machine_restart);
133
134 void machine_power_off (void)
135 {
136         machine_halt ();
137 }
138
139 EXPORT_SYMBOL(machine_power_off);
140
141 \f
142 /* Interrupts */
143
144 struct v850e_intc_irq_init irq_inits[] = {
145         { "IRQ", 0,             NUM_MACH_IRQS,  1, 7 },
146         { "RPU", IRQ_RPU(0),    IRQ_RPU_NUM,    1, 6 },
147         { 0 }
148 };
149 #define NUM_IRQ_INITS ((sizeof irq_inits / sizeof irq_inits[0]) - 1)
150
151 struct hw_interrupt_type hw_itypes[NUM_IRQ_INITS];
152
153 /* Initialize interrupts.  */
154 void __init mach_init_irqs (void)
155 {
156         v850e_intc_init_irq_types (irq_inits, hw_itypes);
157 }
158
159 \f
160 /* An interrupt handler that copies the registers to a known memory location,
161    for debugging purposes.  */
162
163 static void make_reg_snap (int irq, void *dummy, struct pt_regs *regs)
164 {
165         (*(unsigned *)REG_DUMP_ADDR)++;
166         (*(struct pt_regs *)(REG_DUMP_ADDR + sizeof (unsigned))) = *regs;
167 }
168
169 static int reg_snap_dev_id;
170 static struct irqaction reg_snap_action = {
171         make_reg_snap, 0, 0, "reg_snap", &reg_snap_dev_id, 0
172 };