linux/arch/v850/kernel/rte_me2_cb.c
<<
>>
Prefs
   1/*
   2 * arch/v850/kernel/rte_me2_cb.c -- Midas labs RTE-V850E/ME2-CB board
   3 *
   4 *  Copyright (C) 2001,02,03  NEC Electronics Corporation
   5 *  Copyright (C) 2001,02,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/init.h>
  16#include <linux/bootmem.h>
  17#include <linux/irq.h>
  18#include <linux/fs.h>
  19#include <linux/major.h>
  20#include <linux/sched.h>
  21#include <linux/delay.h>
  22
  23#include <asm/atomic.h>
  24#include <asm/page.h>
  25#include <asm/me2.h>
  26#include <asm/rte_me2_cb.h>
  27#include <asm/machdep.h>
  28#include <asm/v850e_intc.h>
  29#include <asm/v850e_cache.h>
  30#include <asm/irq.h>
  31
  32#include "mach.h"
  33
  34extern unsigned long *_intv_start;
  35extern unsigned long *_intv_end;
  36
  37/* LED access routines.  */
  38extern unsigned read_leds (int pos, char *buf, int len);
  39extern unsigned write_leds (int pos, const char *buf, int len);
  40
  41
  42/* SDRAM are almost contiguous (with a small hole in between;
  43   see mach_reserve_bootmem for details), so just use both as one big area.  */
  44#define RAM_START       SDRAM_ADDR
  45#define RAM_END         (SDRAM_ADDR + SDRAM_SIZE)
  46
  47
  48void __init mach_get_physical_ram (unsigned long *ram_start,
  49                                   unsigned long *ram_len)
  50{
  51        *ram_start = RAM_START;
  52        *ram_len = RAM_END - RAM_START;
  53}
  54
  55void mach_gettimeofday (struct timespec *tv)
  56{
  57        tv->tv_sec = 0;
  58        tv->tv_nsec = 0;
  59}
  60
  61/* Called before configuring an on-chip UART.  */
  62void rte_me2_cb_uart_pre_configure (unsigned chan,
  63                                    unsigned cflags, unsigned baud)
  64{
  65        /* The RTE-V850E/ME2-CB connects some general-purpose I/O
  66           pins on the CPU to the RTS/CTS lines of UARTB channel 0's
  67           serial connection.
  68           I/O pins P21 and P22 are RTS and CTS respectively.  */
  69        if (chan == 0) {
  70                /* Put P21 & P22 in I/O port mode.  */
  71                ME2_PORT2_PMC &= ~0x6;
  72                /* Make P21 and output, and P22 an input.  */
  73                ME2_PORT2_PM = (ME2_PORT2_PM & ~0xC) | 0x4;
  74        }
  75
  76        me2_uart_pre_configure (chan, cflags, baud);
  77}
  78
  79void __init mach_init_irqs (void)
  80{
  81        /* Initialize interrupts.  */
  82        me2_init_irqs ();
  83        rte_me2_cb_init_irqs ();
  84}
  85
  86#ifdef CONFIG_ROM_KERNEL
  87/* Initialization for kernel in ROM.  */
  88static inline rom_kernel_init (void)
  89{
  90        /* If the kernel is in ROM, we have to copy any initialized data
  91           from ROM into RAM.  */
  92        extern unsigned long _data_load_start, _sdata, _edata;
  93        register unsigned long *src = &_data_load_start;
  94        register unsigned long *dst = &_sdata, *end = &_edata;
  95
  96        while (dst != end)
  97                *dst++ = *src++;
  98}
  99#endif /* CONFIG_ROM_KERNEL */
 100
 101static void install_interrupt_vectors (void)
 102{
 103        unsigned long *p1, *p2;
 104
 105        ME2_IRAMM = 0x03; /* V850E/ME2 iRAM write mode */
 106
 107        /* vector copy to iRAM */
 108        p1 = (unsigned long *)0; /* v85x vector start */
 109        p2 = (unsigned long *)&_intv_start;
 110        while (p2 < (unsigned long *)&_intv_end)
 111                *p1++ = *p2++;
 112
 113        ME2_IRAMM = 0x00; /* V850E/ME2 iRAM read mode */
 114}
 115
 116/* CompactFlash */
 117
 118static void cf_power_on (void)
 119{
 120        /* CF card detected? */
 121        if (CB_CF_STS0 & 0x0030)
 122                return;
 123
 124        CB_CF_REG0 = 0x0002; /* reest on */
 125        mdelay (10);
 126        CB_CF_REG0 = 0x0003; /* power on */
 127        mdelay (10);
 128        CB_CF_REG0 = 0x0001; /* reset off */
 129        mdelay (10);
 130}
 131
 132static void cf_power_off (void)
 133{
 134        CB_CF_REG0 = 0x0003; /* power on */
 135        mdelay (10);
 136        CB_CF_REG0 = 0x0002; /* reest on */
 137        mdelay (10);
 138}
 139
 140void __init mach_early_init (void)
 141{
 142        install_interrupt_vectors ();
 143
 144        /* CS1 SDRAM instruction cache enable */
 145        v850e_cache_enable (0x04, 0x03, 0);
 146
 147        rte_cb_early_init ();
 148
 149        /* CompactFlash power on */
 150        cf_power_on ();
 151
 152#if defined (CONFIG_ROM_KERNEL)
 153        rom_kernel_init ();
 154#endif
 155}
 156
 157
 158/* RTE-V850E/ME2-CB Programmable Interrupt Controller.  */
 159
 160static struct cb_pic_irq_init cb_pic_irq_inits[] = {
 161        { "CB_EXTTM0",       IRQ_CB_EXTTM0,       1, 1, 6 },
 162        { "CB_EXTSIO",       IRQ_CB_EXTSIO,       1, 1, 6 },
 163        { "CB_TOVER",        IRQ_CB_TOVER,        1, 1, 6 },
 164        { "CB_GINT0",        IRQ_CB_GINT0,        1, 1, 6 },
 165        { "CB_USB",          IRQ_CB_USB,          1, 1, 6 },
 166        { "CB_LANC",         IRQ_CB_LANC,         1, 1, 6 },
 167        { "CB_USB_VBUS_ON",  IRQ_CB_USB_VBUS_ON,  1, 1, 6 },
 168        { "CB_USB_VBUS_OFF", IRQ_CB_USB_VBUS_OFF, 1, 1, 6 },
 169        { "CB_EXTTM1",       IRQ_CB_EXTTM1,       1, 1, 6 },
 170        { "CB_EXTTM2",       IRQ_CB_EXTTM2,       1, 1, 6 },
 171        { 0 }
 172};
 173#define NUM_CB_PIC_IRQ_INITS (ARRAY_SIZE(cb_pic_irq_inits) - 1)
 174
 175static struct hw_interrupt_type cb_pic_hw_itypes[NUM_CB_PIC_IRQ_INITS];
 176static unsigned char cb_pic_active_irqs = 0;
 177
 178void __init rte_me2_cb_init_irqs (void)
 179{
 180        cb_pic_init_irq_types (cb_pic_irq_inits, cb_pic_hw_itypes);
 181
 182        /* Initalize on board PIC1 (not PIC0) enable */
 183        CB_PIC_INT0M  = 0x0000;
 184        CB_PIC_INT1M  = 0x0000;
 185        CB_PIC_INTR   = 0x0000;
 186        CB_PIC_INTEN |= CB_PIC_INT1EN;
 187
 188        ME2_PORT2_PMC    |= 0x08;       /* INTP23/SCK1 mode */
 189        ME2_PORT2_PFC    &= ~0x08;      /* INTP23 mode */
 190        ME2_INTR(2)      &= ~0x08;      /* INTP23 falling-edge detect */
 191        ME2_INTF(2)      &= ~0x08;      /*   " */
 192
 193        rte_cb_init_irqs ();    /* gbus &c */
 194}
 195
 196
 197/* Enable interrupt handling for interrupt IRQ.  */
 198void cb_pic_enable_irq (unsigned irq)
 199{
 200        CB_PIC_INT1M |= 1 << (irq - CB_PIC_BASE_IRQ);
 201}
 202
 203void cb_pic_disable_irq (unsigned irq)
 204{
 205        CB_PIC_INT1M &= ~(1 << (irq - CB_PIC_BASE_IRQ));
 206}
 207
 208void cb_pic_shutdown_irq (unsigned irq)
 209{
 210        cb_pic_disable_irq (irq);
 211
 212        if (--cb_pic_active_irqs == 0)
 213                free_irq (IRQ_CB_PIC, 0);
 214
 215        CB_PIC_INT1M &= ~(1 << (irq - CB_PIC_BASE_IRQ));
 216}
 217
 218static irqreturn_t cb_pic_handle_irq (int irq, void *dev_id,
 219                                      struct pt_regs *regs)
 220{
 221        irqreturn_t rval = IRQ_NONE;
 222        unsigned status = CB_PIC_INTR;
 223        unsigned enable = CB_PIC_INT1M;
 224
 225        /* Only pay attention to enabled interrupts.  */
 226        status &= enable;
 227
 228        CB_PIC_INTEN &= ~CB_PIC_INT1EN;
 229
 230        if (status) {
 231                unsigned mask = 1;
 232
 233                irq = CB_PIC_BASE_IRQ;
 234                do {
 235                        /* There's an active interrupt, find out which one,
 236                           and call its handler.  */
 237                        while (! (status & mask)) {
 238                                irq++;
 239                                mask <<= 1;
 240                        }
 241                        status &= ~mask;
 242
 243                        CB_PIC_INTR = mask;
 244
 245                        /* Recursively call handle_irq to handle it. */
 246                        handle_irq (irq, regs);
 247                        rval = IRQ_HANDLED;
 248                } while (status);
 249        }
 250
 251        CB_PIC_INTEN |= CB_PIC_INT1EN;
 252
 253        return rval;
 254}
 255
 256
 257static void irq_nop (unsigned irq) { }
 258
 259static unsigned cb_pic_startup_irq (unsigned irq)
 260{
 261        int rval;
 262
 263        if (cb_pic_active_irqs == 0) {
 264                rval = request_irq (IRQ_CB_PIC, cb_pic_handle_irq,
 265                                    IRQF_DISABLED, "cb_pic_handler", 0);
 266                if (rval != 0)
 267                        return rval;
 268        }
 269
 270        cb_pic_active_irqs++;
 271
 272        cb_pic_enable_irq (irq);
 273
 274        return 0;
 275}
 276
 277/* Initialize HW_IRQ_TYPES for INTC-controlled irqs described in array
 278   INITS (which is terminated by an entry with the name field == 0).  */
 279void __init cb_pic_init_irq_types (struct cb_pic_irq_init *inits,
 280                                   struct hw_interrupt_type *hw_irq_types)
 281{
 282        struct cb_pic_irq_init *init;
 283        for (init = inits; init->name; init++) {
 284                struct hw_interrupt_type *hwit = hw_irq_types++;
 285
 286                hwit->typename = init->name;
 287
 288                hwit->startup  = cb_pic_startup_irq;
 289                hwit->shutdown = cb_pic_shutdown_irq;
 290                hwit->enable   = cb_pic_enable_irq;
 291                hwit->disable  = cb_pic_disable_irq;
 292                hwit->ack      = irq_nop;
 293                hwit->end      = irq_nop;
 294
 295                /* Initialize kernel IRQ infrastructure for this interrupt.  */
 296                init_irq_handlers(init->base, init->num, init->interval, hwit);
 297        }
 298}
 299