301 lines
		
	
	
	
		
			7.2 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			301 lines
		
	
	
	
		
			7.2 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
| 
								 | 
							
								/*
							 | 
						|||
| 
								 | 
							
								 * arch/v850/kernel/rte_me2_cb.c -- Midas labs RTE-V850E/ME2-CB board
							 | 
						|||
| 
								 | 
							
								 *
							 | 
						|||
| 
								 | 
							
								 *  Copyright (C) 2001,02,03  NEC Electronics Corporation
							 | 
						|||
| 
								 | 
							
								 *  Copyright (C) 2001,02,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/init.h>
							 | 
						|||
| 
								 | 
							
								#include <linux/bootmem.h>
							 | 
						|||
| 
								 | 
							
								#include <linux/irq.h>
							 | 
						|||
| 
								 | 
							
								#include <linux/fs.h>
							 | 
						|||
| 
								 | 
							
								#include <linux/major.h>
							 | 
						|||
| 
								 | 
							
								#include <linux/sched.h>
							 | 
						|||
| 
								 | 
							
								#include <linux/delay.h>
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								#include <asm/atomic.h>
							 | 
						|||
| 
								 | 
							
								#include <asm/page.h>
							 | 
						|||
| 
								 | 
							
								#include <asm/me2.h>
							 | 
						|||
| 
								 | 
							
								#include <asm/rte_me2_cb.h>
							 | 
						|||
| 
								 | 
							
								#include <asm/machdep.h>
							 | 
						|||
| 
								 | 
							
								#include <asm/v850e_intc.h>
							 | 
						|||
| 
								 | 
							
								#include <asm/v850e_cache.h>
							 | 
						|||
| 
								 | 
							
								#include <asm/irq.h>
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								#include "mach.h"
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								extern unsigned long *_intv_start;
							 | 
						|||
| 
								 | 
							
								extern unsigned long *_intv_end;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								/* LED access routines.  */
							 | 
						|||
| 
								 | 
							
								extern unsigned read_leds (int pos, char *buf, int len);
							 | 
						|||
| 
								 | 
							
								extern unsigned write_leds (int pos, const char *buf, int len);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								/* SDRAM are almost contiguous (with a small hole in between;
							 | 
						|||
| 
								 | 
							
								   see mach_reserve_bootmem for details), so just use both as one big area.  */
							 | 
						|||
| 
								 | 
							
								#define RAM_START 	SDRAM_ADDR
							 | 
						|||
| 
								 | 
							
								#define RAM_END		(SDRAM_ADDR + SDRAM_SIZE)
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								void __init mach_get_physical_ram (unsigned long *ram_start,
							 | 
						|||
| 
								 | 
							
												   unsigned long *ram_len)
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
									*ram_start = RAM_START;
							 | 
						|||
| 
								 | 
							
									*ram_len = RAM_END - RAM_START;
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								void mach_gettimeofday (struct timespec *tv)
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
									tv->tv_sec = 0;
							 | 
						|||
| 
								 | 
							
									tv->tv_nsec = 0;
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								/* Called before configuring an on-chip UART.  */
							 | 
						|||
| 
								 | 
							
								void rte_me2_cb_uart_pre_configure (unsigned chan,
							 | 
						|||
| 
								 | 
							
												    unsigned cflags, unsigned baud)
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
									/* The RTE-V850E/ME2-CB connects some general-purpose I/O
							 | 
						|||
| 
								 | 
							
									   pins on the CPU to the RTS/CTS lines of UARTB channel 0's
							 | 
						|||
| 
								 | 
							
									   serial connection.
							 | 
						|||
| 
								 | 
							
									   I/O pins P21 and P22 are RTS and CTS respectively.  */
							 | 
						|||
| 
								 | 
							
									if (chan == 0) {
							 | 
						|||
| 
								 | 
							
										/* Put P21 & P22 in I/O port mode.  */
							 | 
						|||
| 
								 | 
							
										ME2_PORT2_PMC &= ~0x6;
							 | 
						|||
| 
								 | 
							
										/* Make P21 and output, and P22 an input.  */
							 | 
						|||
| 
								 | 
							
										ME2_PORT2_PM = (ME2_PORT2_PM & ~0xC) | 0x4;
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									me2_uart_pre_configure (chan, cflags, baud);
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								void __init mach_init_irqs (void)
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
									/* Initialize interrupts.  */
							 | 
						|||
| 
								 | 
							
									me2_init_irqs ();
							 | 
						|||
| 
								 | 
							
									rte_me2_cb_init_irqs ();
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								#ifdef CONFIG_ROM_KERNEL
							 | 
						|||
| 
								 | 
							
								/* Initialization for kernel in ROM.  */
							 | 
						|||
| 
								 | 
							
								static inline rom_kernel_init (void)
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
									/* If the kernel is in ROM, we have to copy any initialized data
							 | 
						|||
| 
								 | 
							
									   from ROM into RAM.  */
							 | 
						|||
| 
								 | 
							
									extern unsigned long _data_load_start, _sdata, _edata;
							 | 
						|||
| 
								 | 
							
									register unsigned long *src = &_data_load_start;
							 | 
						|||
| 
								 | 
							
									register unsigned long *dst = &_sdata, *end = &_edata;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									while (dst != end)
							 | 
						|||
| 
								 | 
							
										*dst++ = *src++;
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								#endif /* CONFIG_ROM_KERNEL */
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								static void install_interrupt_vectors (void)
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
									unsigned long *p1, *p2;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									ME2_IRAMM = 0x03; /* V850E/ME2 iRAM write mode */
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									/* vector copy to iRAM */
							 | 
						|||
| 
								 | 
							
									p1 = (unsigned long *)0; /* v85x vector start */
							 | 
						|||
| 
								 | 
							
									p2 = (unsigned long *)&_intv_start;
							 | 
						|||
| 
								 | 
							
									while (p2 < (unsigned long *)&_intv_end)
							 | 
						|||
| 
								 | 
							
										*p1++ = *p2++;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									ME2_IRAMM = 0x00; /* V850E/ME2 iRAM read mode */
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								/* CompactFlash */
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								static void cf_power_on (void)
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
									/* CF card detected? */
							 | 
						|||
| 
								 | 
							
									if (CB_CF_STS0 & 0x0030)
							 | 
						|||
| 
								 | 
							
										return;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									CB_CF_REG0 = 0x0002; /* reest on */
							 | 
						|||
| 
								 | 
							
									mdelay (10);
							 | 
						|||
| 
								 | 
							
									CB_CF_REG0 = 0x0003; /* power on */
							 | 
						|||
| 
								 | 
							
									mdelay (10);
							 | 
						|||
| 
								 | 
							
									CB_CF_REG0 = 0x0001; /* reset off */
							 | 
						|||
| 
								 | 
							
									mdelay (10);
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								static void cf_power_off (void)
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
									CB_CF_REG0 = 0x0003; /* power on */
							 | 
						|||
| 
								 | 
							
									mdelay (10);
							 | 
						|||
| 
								 | 
							
									CB_CF_REG0 = 0x0002; /* reest on */
							 | 
						|||
| 
								 | 
							
									mdelay (10);
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								void __init mach_early_init (void)
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
									install_interrupt_vectors ();
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									/* CS1 SDRAM instruction cache enable */
							 | 
						|||
| 
								 | 
							
									v850e_cache_enable (0x04, 0x03, 0);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									rte_cb_early_init ();
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									/* CompactFlash power on */
							 | 
						|||
| 
								 | 
							
									cf_power_on ();
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								#if defined (CONFIG_ROM_KERNEL)
							 | 
						|||
| 
								 | 
							
									rom_kernel_init ();
							 | 
						|||
| 
								 | 
							
								#endif
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								/* RTE-V850E/ME2-CB Programmable Interrupt Controller.  */
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								static struct cb_pic_irq_init cb_pic_irq_inits[] = {
							 | 
						|||
| 
								 | 
							
									{ "CB_EXTTM0",       IRQ_CB_EXTTM0,       1, 1, 6 },
							 | 
						|||
| 
								 | 
							
									{ "CB_EXTSIO",       IRQ_CB_EXTSIO,       1, 1, 6 },
							 | 
						|||
| 
								 | 
							
									{ "CB_TOVER",        IRQ_CB_TOVER,        1, 1, 6 },
							 | 
						|||
| 
								 | 
							
									{ "CB_GINT0",        IRQ_CB_GINT0,        1, 1, 6 },
							 | 
						|||
| 
								 | 
							
									{ "CB_USB",          IRQ_CB_USB,          1, 1, 6 },
							 | 
						|||
| 
								 | 
							
									{ "CB_LANC",         IRQ_CB_LANC,         1, 1, 6 },
							 | 
						|||
| 
								 | 
							
									{ "CB_USB_VBUS_ON",  IRQ_CB_USB_VBUS_ON,  1, 1, 6 },
							 | 
						|||
| 
								 | 
							
									{ "CB_USB_VBUS_OFF", IRQ_CB_USB_VBUS_OFF, 1, 1, 6 },
							 | 
						|||
| 
								 | 
							
									{ "CB_EXTTM1",       IRQ_CB_EXTTM1,       1, 1, 6 },
							 | 
						|||
| 
								 | 
							
									{ "CB_EXTTM2",       IRQ_CB_EXTTM2,       1, 1, 6 },
							 | 
						|||
| 
								 | 
							
									{ 0 }
							 | 
						|||
| 
								 | 
							
								};
							 | 
						|||
| 
								 | 
							
								#define NUM_CB_PIC_IRQ_INITS  \
							 | 
						|||
| 
								 | 
							
								   ((sizeof cb_pic_irq_inits / sizeof cb_pic_irq_inits[0]) - 1)
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								static struct hw_interrupt_type cb_pic_hw_itypes[NUM_CB_PIC_IRQ_INITS];
							 | 
						|||
| 
								 | 
							
								static unsigned char cb_pic_active_irqs = 0;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								void __init rte_me2_cb_init_irqs (void)
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
									cb_pic_init_irq_types (cb_pic_irq_inits, cb_pic_hw_itypes);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									/* Initalize on board PIC1 (not PIC0) enable */
							 | 
						|||
| 
								 | 
							
									CB_PIC_INT0M  = 0x0000;
							 | 
						|||
| 
								 | 
							
									CB_PIC_INT1M  = 0x0000;
							 | 
						|||
| 
								 | 
							
									CB_PIC_INTR   = 0x0000;
							 | 
						|||
| 
								 | 
							
									CB_PIC_INTEN |= CB_PIC_INT1EN;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									ME2_PORT2_PMC 	 |= 0x08;	/* INTP23/SCK1 mode */
							 | 
						|||
| 
								 | 
							
									ME2_PORT2_PFC 	 &= ~0x08;	/* INTP23 mode */
							 | 
						|||
| 
								 | 
							
									ME2_INTR(2) 	 &= ~0x08;	/* INTP23 falling-edge detect */
							 | 
						|||
| 
								 | 
							
									ME2_INTF(2) 	 &= ~0x08;	/*   " */
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									rte_cb_init_irqs ();	/* gbus &c */
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								/* Enable interrupt handling for interrupt IRQ.  */
							 | 
						|||
| 
								 | 
							
								void cb_pic_enable_irq (unsigned irq)
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
									CB_PIC_INT1M |= 1 << (irq - CB_PIC_BASE_IRQ);
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								void cb_pic_disable_irq (unsigned irq)
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
									CB_PIC_INT1M &= ~(1 << (irq - CB_PIC_BASE_IRQ));
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								void cb_pic_shutdown_irq (unsigned irq)
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
									cb_pic_disable_irq (irq);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									if (--cb_pic_active_irqs == 0)
							 | 
						|||
| 
								 | 
							
										free_irq (IRQ_CB_PIC, 0);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									CB_PIC_INT1M &= ~(1 << (irq - CB_PIC_BASE_IRQ));
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								static irqreturn_t cb_pic_handle_irq (int irq, void *dev_id,
							 | 
						|||
| 
								 | 
							
												      struct pt_regs *regs)
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
									irqreturn_t rval = IRQ_NONE;
							 | 
						|||
| 
								 | 
							
									unsigned status = CB_PIC_INTR;
							 | 
						|||
| 
								 | 
							
									unsigned enable = CB_PIC_INT1M;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									/* Only pay attention to enabled interrupts.  */
							 | 
						|||
| 
								 | 
							
									status &= enable;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									CB_PIC_INTEN &= ~CB_PIC_INT1EN;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									if (status) {
							 | 
						|||
| 
								 | 
							
										unsigned mask = 1;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										irq = CB_PIC_BASE_IRQ;
							 | 
						|||
| 
								 | 
							
										do {
							 | 
						|||
| 
								 | 
							
											/* There's an active interrupt, find out which one,
							 | 
						|||
| 
								 | 
							
											   and call its handler.  */
							 | 
						|||
| 
								 | 
							
											while (! (status & mask)) {
							 | 
						|||
| 
								 | 
							
												irq++;
							 | 
						|||
| 
								 | 
							
												mask <<= 1;
							 | 
						|||
| 
								 | 
							
											}
							 | 
						|||
| 
								 | 
							
											status &= ~mask;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
											CB_PIC_INTR = mask;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
											/* Recursively call handle_irq to handle it. */
							 | 
						|||
| 
								 | 
							
											handle_irq (irq, regs);
							 | 
						|||
| 
								 | 
							
											rval = IRQ_HANDLED;
							 | 
						|||
| 
								 | 
							
										} while (status);
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									CB_PIC_INTEN |= CB_PIC_INT1EN;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									return rval;
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								static void irq_nop (unsigned irq) { }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								static unsigned cb_pic_startup_irq (unsigned irq)
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
									int rval;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									if (cb_pic_active_irqs == 0) {
							 | 
						|||
| 
								 | 
							
										rval = request_irq (IRQ_CB_PIC, cb_pic_handle_irq,
							 | 
						|||
| 
								 | 
							
												    SA_INTERRUPT, "cb_pic_handler", 0);
							 | 
						|||
| 
								 | 
							
										if (rval != 0)
							 | 
						|||
| 
								 | 
							
											return rval;
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									cb_pic_active_irqs++;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									cb_pic_enable_irq (irq);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									return 0;
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								/* Initialize HW_IRQ_TYPES for INTC-controlled irqs described in array
							 | 
						|||
| 
								 | 
							
								   INITS (which is terminated by an entry with the name field == 0).  */
							 | 
						|||
| 
								 | 
							
								void __init cb_pic_init_irq_types (struct cb_pic_irq_init *inits,
							 | 
						|||
| 
								 | 
							
												   struct hw_interrupt_type *hw_irq_types)
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
									struct cb_pic_irq_init *init;
							 | 
						|||
| 
								 | 
							
									for (init = inits; init->name; init++) {
							 | 
						|||
| 
								 | 
							
										struct hw_interrupt_type *hwit = hw_irq_types++;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										hwit->typename = init->name;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										hwit->startup  = cb_pic_startup_irq;
							 | 
						|||
| 
								 | 
							
										hwit->shutdown = cb_pic_shutdown_irq;
							 | 
						|||
| 
								 | 
							
										hwit->enable   = cb_pic_enable_irq;
							 | 
						|||
| 
								 | 
							
										hwit->disable  = cb_pic_disable_irq;
							 | 
						|||
| 
								 | 
							
										hwit->ack      = irq_nop;
							 | 
						|||
| 
								 | 
							
										hwit->end      = irq_nop;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										/* Initialize kernel IRQ infrastructure for this interrupt.  */
							 | 
						|||
| 
								 | 
							
										init_irq_handlers(init->base, init->num, init->interval, hwit);
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								}
							 |