diff options
Diffstat (limited to 'arch/v850/kernel/fpga85e2c.c')
-rw-r--r-- | arch/v850/kernel/fpga85e2c.c | 171 |
1 files changed, 171 insertions, 0 deletions
diff --git a/arch/v850/kernel/fpga85e2c.c b/arch/v850/kernel/fpga85e2c.c new file mode 100644 index 00000000000..4bac5149b3c --- /dev/null +++ b/arch/v850/kernel/fpga85e2c.c @@ -0,0 +1,171 @@ +/* + * arch/v850/kernel/fpga85e2c.h -- Machine-dependent defs for + * FPGA implementation of V850E2/NA85E2C + * + * Copyright (C) 2002,03 NEC Electronics Corporation + * Copyright (C) 2002,03 Miles Bader <miles@gnu.org> + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader <miles@gnu.org> + */ + +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/mm.h> +#include <linux/swap.h> +#include <linux/bootmem.h> +#include <linux/irq.h> +#include <linux/bitops.h> + +#include <asm/atomic.h> +#include <asm/page.h> +#include <asm/machdep.h> + +#include "mach.h" + +extern void memcons_setup (void); + + +#define REG_DUMP_ADDR 0x220000 + + +extern struct irqaction reg_snap_action; /* fwd decl */ + + +void __init mach_early_init (void) +{ + int i; + const u32 *src; + register u32 *dst asm ("ep"); + extern u32 _intv_end, _intv_load_start; + + /* Set bus sizes: CS0 32-bit, CS1 16-bit, CS7 8-bit, + everything else 32-bit. */ + V850E2_BSC = 0x2AA6; + for (i = 2; i <= 6; i++) + CSDEV(i) = 0; /* 32 bit */ + + /* Ensure that the simulator halts on a panic, instead of going + into an infinite loop inside the panic function. */ + panic_timeout = -1; + + /* Move the interrupt vectors into their real location. Note that + any relocations there are relative to the real location, so we + don't have to fix anything up. We use a loop instead of calling + memcpy to keep this a leaf function (to avoid a function + prologue being generated). */ + dst = 0x10; /* &_intv_start + 0x10. */ + src = &_intv_load_start; + do { + u32 t0 = src[0], t1 = src[1], t2 = src[2], t3 = src[3]; + u32 t4 = src[4], t5 = src[5], t6 = src[6], t7 = src[7]; + dst[0] = t0; dst[1] = t1; dst[2] = t2; dst[3] = t3; + dst[4] = t4; dst[5] = t5; dst[6] = t6; dst[7] = t7; + dst += 8; + src += 8; + } while (dst < &_intv_end); +} + +void __init mach_setup (char **cmdline) +{ + memcons_setup (); + + /* Setup up NMI0 to copy the registers to a known memory location. + The FGPA board has a button that produces NMI0 when pressed, so + this allows us to push the button, and then look at memory to see + what's in the registers (there's no other way to easily do so). + We have to use `setup_irq' instead of `request_irq' because it's + still too early to do memory allocation. */ + setup_irq (IRQ_NMI (0), ®_snap_action); +} + +void mach_get_physical_ram (unsigned long *ram_start, unsigned long *ram_len) +{ + *ram_start = ERAM_ADDR; + *ram_len = ERAM_SIZE; +} + +void __init mach_sched_init (struct irqaction *timer_action) +{ + /* Setup up the timer interrupt. The FPGA peripheral control + registers _only_ work with single-bit writes (set1/clr1)! */ + __clear_bit (RPU_GTMC_CE_BIT, &RPU_GTMC); + __clear_bit (RPU_GTMC_CLK_BIT, &RPU_GTMC); + __set_bit (RPU_GTMC_CE_BIT, &RPU_GTMC); + + /* We use the first RPU interrupt, which occurs every 8.192ms. */ + setup_irq (IRQ_RPU (0), timer_action); +} + + +void mach_gettimeofday (struct timespec *tv) +{ + tv->tv_sec = 0; + tv->tv_nsec = 0; +} + +void machine_halt (void) __attribute__ ((noreturn)); +void machine_halt (void) +{ + for (;;) { + DWC(0) = 0x7777; + DWC(1) = 0x7777; + ASC = 0xffff; + FLGREG(0) = 1; /* Halt immediately. */ + asm ("di; halt; nop; nop; nop; nop; nop"); + } +} + +EXPORT_SYMBOL(machine_halt); + +void machine_restart (char *__unused) +{ + machine_halt (); +} + +EXPORT_SYMBOL(machine_restart); + +void machine_power_off (void) +{ + machine_halt (); +} + +EXPORT_SYMBOL(machine_power_off); + + +/* Interrupts */ + +struct v850e_intc_irq_init irq_inits[] = { + { "IRQ", 0, NUM_MACH_IRQS, 1, 7 }, + { "RPU", IRQ_RPU(0), IRQ_RPU_NUM, 1, 6 }, + { 0 } +}; +#define NUM_IRQ_INITS ((sizeof irq_inits / sizeof irq_inits[0]) - 1) + +struct hw_interrupt_type hw_itypes[NUM_IRQ_INITS]; + +/* Initialize interrupts. */ +void __init mach_init_irqs (void) +{ + v850e_intc_init_irq_types (irq_inits, hw_itypes); +} + + +/* An interrupt handler that copies the registers to a known memory location, + for debugging purposes. */ + +static void make_reg_snap (int irq, void *dummy, struct pt_regs *regs) +{ + (*(unsigned *)REG_DUMP_ADDR)++; + (*(struct pt_regs *)(REG_DUMP_ADDR + sizeof (unsigned))) = *regs; +} + +static int reg_snap_dev_id; +static struct irqaction reg_snap_action = { + make_reg_snap, 0, CPU_MASK_NONE, "reg_snap", ®_snap_dev_id, 0 +}; |