|  | /* | 
|  | * 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/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"); | 
|  | } | 
|  | } | 
|  |  | 
|  | void machine_restart (char *__unused) | 
|  | { | 
|  | machine_halt (); | 
|  | } | 
|  |  | 
|  | void machine_power_off (void) | 
|  | { | 
|  | machine_halt (); | 
|  | } | 
|  |  | 
|  |  | 
|  | /* 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 (ARRAY_SIZE(irq_inits) - 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 = { | 
|  | .handler = make_reg_snap, | 
|  | .mask = CPU_MASK_NONE, | 
|  | .name = "reg_snap", | 
|  | .dev_id = ®_snap_dev_id, | 
|  | }; |