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