Update of /cvsroot/linux-mips/linux/arch/mips/korva In directory usw-pr-cvs1:/tmp/cvs-serv27423/arch/mips/korva Added Files: Makefile dbg_io.c int_handler.S irq.c irq_cpu.c irq_korva.c prom.c reset.c setup.c Log Message: Support NEC Korva board (vr4120a based). --- NEW FILE: Makefile --- # # Makefile for common code of NEC Korva board # # Note! Dependencies are done automagically by 'make dep', which also # removes any old dependencies. DON'T put your own dependencies here # unless it's something special (ie not a .c file). # .S.s: $(CPP) $(CFLAGS) $< -o $*.s .S.o: $(CC) $(CFLAGS) -c $< -o $*.o O_TARGET:= korva.a obj-y := setup.o prom.o reset.o int_handler.o irq.o irq_cpu.o irq_korva.o obj-$(CONFIG_BLK_DEV_INITRD) += ramdisk.o obj-$(CONFIG_REMOTE_DEBUG) += dbg_io.o include $(TOPDIR)/Rules.make --- NEW FILE: dbg_io.c --- #include <linux/config.h> #if defined(CONFIG_REMOTE_DEBUG) /* --- CONFIG --- */ typedef unsigned char uint8; typedef unsigned int uint32; /* --- END OF CONFIG --- */ #define UART16550_BAUD_2400 2400 #define UART16550_BAUD_4800 4800 #define UART16550_BAUD_9600 9600 #define UART16550_BAUD_19200 19200 #define UART16550_BAUD_38400 38400 #define UART16550_BAUD_57600 57600 #define UART16550_BAUD_115200 115200 #define UART16550_PARITY_NONE 0 #define UART16550_PARITY_ODD 0x08 #define UART16550_PARITY_EVEN 0x18 #define UART16550_PARITY_MARK 0x28 #define UART16550_PARITY_SPACE 0x38 #define UART16550_DATA_5BIT 0x0 #define UART16550_DATA_6BIT 0x1 #define UART16550_DATA_7BIT 0x2 #define UART16550_DATA_8BIT 0x3 #define UART16550_STOP_1BIT 0x0 #define UART16550_STOP_2BIT 0x4 /* ----------------------------------------------------- */ /* === CONFIG === */ /* [jsun] we use the debug board serial port for kdb */ #define BASE 0xb0000080 #define MAX_BAUD 1152000 #define REG_OFFSET 4 static int remoteDebugInitialized = 0; #define BAUD_DEFAULT UART16550_BAUD_115200 /* === END OF CONFIG === */ /* register offset */ #define OFS_RCV_BUFFER 0 #define OFS_TRANS_HOLD 0 #define OFS_SEND_BUFFER 0 #define OFS_INTR_ENABLE (1*REG_OFFSET) #define OFS_INTR_ID (2*REG_OFFSET) #define OFS_DATA_FORMAT (3*REG_OFFSET) #define OFS_LINE_CONTROL (3*REG_OFFSET) #define OFS_MODEM_CONTROL (4*REG_OFFSET) #define OFS_RS232_OUTPUT (4*REG_OFFSET) #define OFS_LINE_STATUS (5*REG_OFFSET) #define OFS_MODEM_STATUS (6*REG_OFFSET) #define OFS_RS232_INPUT (6*REG_OFFSET) #define OFS_SCRATCH_PAD (7*REG_OFFSET) #define OFS_DIVISOR_LSB (0*REG_OFFSET) #define OFS_DIVISOR_MSB (1*REG_OFFSET) /* memory-mapped read/write of the port */ #define UART16550_READ(y) (*((volatile uint8*)(BASE + y))) #define UART16550_WRITE(y, z) ((*((volatile uint8*)(BASE + y))) = z) void debugInit(uint32 baud, uint8 data, uint8 parity, uint8 stop) { /* disable interrupts */ UART16550_WRITE(OFS_INTR_ENABLE, 0); /* set up buad rate */ { uint32 divisor; /* set DIAB bit */ UART16550_WRITE(OFS_LINE_CONTROL, 0x80); /* set divisor */ divisor = MAX_BAUD / baud; UART16550_WRITE(OFS_DIVISOR_LSB, divisor & 0xff); UART16550_WRITE(OFS_DIVISOR_MSB, (divisor & 0xff00) >> 8); /* clear DIAB bit */ UART16550_WRITE(OFS_LINE_CONTROL, 0x0); } /* set data format */ UART16550_WRITE(OFS_DATA_FORMAT, data | parity | stop); } uint8 getDebugChar(void) { if (!remoteDebugInitialized) { remoteDebugInitialized = 1; debugInit(BAUD_DEFAULT, UART16550_DATA_8BIT, UART16550_PARITY_NONE, UART16550_STOP_1BIT); } while ((UART16550_READ(OFS_LINE_STATUS) & 0x1) == 0); return UART16550_READ(OFS_RCV_BUFFER); } int putDebugChar(uint8 byte) { if (!remoteDebugInitialized) { remoteDebugInitialized = 1; debugInit(BAUD_DEFAULT, UART16550_DATA_8BIT, UART16550_PARITY_NONE, UART16550_STOP_1BIT); } while ((UART16550_READ(OFS_LINE_STATUS) & 0x20) == 0); UART16550_WRITE(OFS_SEND_BUFFER, byte); return 1; } #endif --- NEW FILE: int_handler.S --- /* * Copyright 2001 MontaVista Software Inc. * Author: js...@mv... or js...@ju... * * First-level&2nd-level interrupt dispatcher for ddb5477 * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. */ /* * The second level IRQ has 5 interrupt sources. So we simply lump * it together here with the first level. * * The IRQ levels are hardcoded. If you change them here, you better * change the init_IRQ() as well. * * CPU IRQs : * 0 - software intr 0 * 1 - software intr 1 * 2 - ATM Cell Processor * 3 - USB Controller * 4 - Ether Controller #1 * 5 - Ether Controller #2 * 6 - cascading to 2nd level (korva) interrupts * 7 - cpu timer * * Korva IRQs : * 8 - Timer ch0 * 9 - Timer ch1 * 10 - UART * 11 - External interrupt * 12 - Wakeup */ #include <linux/config.h> #include <asm/asm.h> #include <asm/mipsregs.h> #include <asm/addrspace.h> #include <asm/regdef.h> #include <asm/stackframe.h> #include <asm/korva.h> /* * first level interrupt dispatcher for ocelot board - * We check for the timer first, then check PCI ints A and D. * Then check for serial IRQ and fall through. */ .align 5 NESTED(korva_handle_irq, PT_SIZE, sp) SAVE_ALL CLI .set at .set noreorder mfc0 t0, CP0_CAUSE mfc0 t2, CP0_STATUS and t0, t2 andi t1, t0, STATUSF_IP7 /* cpu timer */ bnez t1, ll_cputimer_irq andi t1, t0, STATUSF_IP2 bnez t1, ll_cpu_ip2 andi t1, t0, STATUSF_IP3 bnez t1, ll_cpu_ip3 andi t1, t0, STATUSF_IP4 bnez t1, ll_cpu_ip4 andi t1, t0, STATUSF_IP5 bnez t1, ll_cpu_ip5 andi t1, t0, STATUSF_IP6 bnez t1, ll_cpu_ip6 andi t1, t0, STATUSF_IP0 /* software int 0 */ bnez t1, ll_cpu_ip0 andi t1, t0, STATUSF_IP1 /* software int 1 */ bnez t1, ll_cpu_ip1 nop .set reorder /* wrong alarm or masked ... */ j spurious_interrupt nop END(korva_handle_irq) .align 5 ll_cputimer_irq: li a0, 7 move a1, sp jal do_IRQ j ret_from_irq ll_cpu_ip0: li a0, 0 move a1, sp jal do_IRQ j ret_from_irq ll_cpu_ip1: li a0, 1 move a1, sp jal do_IRQ j ret_from_irq ll_cpu_ip2: li a0, 2 move a1, sp jal do_IRQ j ret_from_irq ll_cpu_ip3: li a0, 3 move a1, sp jal do_IRQ j ret_from_irq ll_cpu_ip4: li a0, 4 move a1, sp jal do_IRQ j ret_from_irq ll_cpu_ip5: li a0, 5 move a1, sp jal do_IRQ j ret_from_irq ll_cpu_ip6: /* it is korva 2nd level interrupts */ /* reading ISR will clear it */ la t0, KORVA_BASE_VIRT + KORVA_S_ISR lw s0, 0(t0) /* and with the mask - just to be safe */ la t0, KORVA_BASE_VIRT + KORVA_S_IMR lw t0, 0(t0) and s0, s0, t0 /* do we need to deliver all the pending ones? */ li a0, 8 li a1, 13 li t0, 1 loop: and t1, t0, s0 bnez t1, foundone sll t0, t0, 1 addiu a0, a0, 1 /* check if we reach the end */ beq a0, a1, error j loop foundone: move a1, sp jal do_IRQ j ret_from_irq error: j spurious_interrupt --- NEW FILE: irq.c --- /* * Copyright 2001 MontaVista Software Inc. * Author: Jun Sun, js...@mv... or js...@ju... * * init_IRQ for korva. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * */ #include <linux/init.h> #include <linux/kernel_stat.h> #include <linux/signal.h> #include <linux/sched.h> #include <linux/interrupt.h> #include <linux/malloc.h> #include <linux/random.h> #include <linux/pm.h> #include <asm/irq.h> #include <asm/mipsregs.h> #include <asm/gdb-stub.h> #include <asm/korva.h> extern asmlinkage void korva_handle_irq(void); extern void breakpoint(void); extern void mips_cpu_irq_init(u32 irq_base); extern void korva_irq_init(u32 irq_base); extern int setup_irq(unsigned int irq, struct irqaction *irqaction); static struct irqaction irq2 = { no_action, 0, 0, "cascade", NULL, NULL }; void __init init_IRQ(void) { set_except_vector(0, korva_handle_irq); mips_cpu_irq_init(0); korva_irq_init(8); /* hack - enable uart */ /* korva_out32(KORVA_S_IMR, 1 << 2); */ /* setup cascade interrupt 6 */ setup_irq(6, &irq2); #ifdef CONFIG_REMOTE_DEBUG printk("Setting debug traps - please connect the remote debugger.\n"); set_debug_traps(); // you may move this line to whereever you want breakpoint(); #endif } --- NEW FILE: irq_cpu.c --- /* * Copyright 2001 MontaVista Software Inc. * Author: Jun Sun, js...@mv... or js...@ju... * * This file define the irq handler for MIPS CPU interrupts. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. */ /* * Almost all MIPS CPUs define 8 interrupt sources. They are typically * level triggered (i.e., cannot be cleared from CPU; must be cleared from * device). The first two are software interrupts. The last one is * usually cpu timer interrupt if coutner register is present. * * This file exports one global function: * mips_cpu_irq_init(u32 irq_base); */ #include <linux/irq.h> #include <linux/types.h> #include <linux/kernel.h> #include <asm/mipsregs.h> /* [jsun] sooner or later we should move this debug stuff to MIPS common */ #include <asm/ddb5xxx/debug.h> static int mips_cpu_irq_base=-1; static void mips_cpu_irq_enable(unsigned int irq) { MIPS_ASSERT(mips_cpu_irq_base != -1); MIPS_ASSERT(irq >= mips_cpu_irq_base); MIPS_ASSERT(irq < mips_cpu_irq_base+8); clear_cp0_cause( 1 << (irq - mips_cpu_irq_base + 8)); set_cp0_status(1 << (irq - mips_cpu_irq_base + 8)); } static void mips_cpu_irq_disable(unsigned int irq) { MIPS_ASSERT(mips_cpu_irq_base != -1); MIPS_ASSERT(irq >= mips_cpu_irq_base); MIPS_ASSERT(irq < mips_cpu_irq_base+8); clear_cp0_status(1 << (irq - mips_cpu_irq_base + 8)); } static unsigned int mips_cpu_irq_startup(unsigned int irq) { mips_cpu_irq_enable(irq); return 0; } #define mips_cpu_irq_shutdown mips_cpu_irq_disable static void mips_cpu_irq_ack(unsigned int irq) { MIPS_ASSERT(mips_cpu_irq_base != -1); MIPS_ASSERT(irq >= mips_cpu_irq_base); MIPS_ASSERT(irq < mips_cpu_irq_base+8); /* although we attemp to clear the IP bit in cause reigster, I think * usually it is cleared by device (irq source) */ clear_cp0_cause( 1 << (irq - mips_cpu_irq_base + 8)); /* disable this interrupt - so that we safe proceed to the handler */ mips_cpu_irq_disable(irq); } static void mips_cpu_irq_end(unsigned int irq) { MIPS_ASSERT(mips_cpu_irq_base != -1); MIPS_ASSERT(irq >= mips_cpu_irq_base); MIPS_ASSERT(irq < mips_cpu_irq_base+8); mips_cpu_irq_enable(irq); } static hw_irq_controller mips_cpu_irq_controller = { "CPU_irq", mips_cpu_irq_startup, mips_cpu_irq_shutdown, mips_cpu_irq_enable, mips_cpu_irq_disable, mips_cpu_irq_ack, mips_cpu_irq_end, NULL /* no affinity stuff for UP */ }; void mips_cpu_irq_init(u32 irq_base) { extern irq_desc_t irq_desc[]; u32 i; for (i= irq_base; i< irq_base+8; i++) { irq_desc[i].status = IRQ_DISABLED; irq_desc[i].action = NULL; irq_desc[i].depth = 1; irq_desc[i].handler = &mips_cpu_irq_controller; } mips_cpu_irq_base = irq_base; } --- NEW FILE: irq_korva.c --- /* * Copyright 2001 MontaVista Software Inc. * Author: Jun Sun, js...@mv... or js...@ju... * * This file define the irq handler for MIPS CPU interrupts. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * */ /* * This file exports one global function: * korva_irq_init(u32 irq_base); */ #include <linux/irq.h> #include <linux/types.h> #include <linux/kernel.h> #include <asm/korva.h> #include <asm/mipsregs.h> /* [jsun] sooner or later we should move this debug stuff to MIPS common */ #include <asm/ddb5xxx/debug.h> #define NUM_KORVA_IRQS 5 static int korva_irq_base=-1; static void korva_irq_enable(unsigned int irq) { MIPS_ASSERT(korva_irq_base != -1); MIPS_ASSERT(irq >= korva_irq_base); MIPS_ASSERT(irq < korva_irq_base+NUM_KORVA_IRQS); irq -= korva_irq_base; korva_out32(KORVA_S_IMR, korva_in32(KORVA_S_IMR) | (1 << irq) ); } static void korva_irq_disable(unsigned int irq) { MIPS_ASSERT(korva_irq_base != -1); MIPS_ASSERT(irq >= korva_irq_base); MIPS_ASSERT(irq < korva_irq_base+NUM_KORVA_IRQS); irq -= korva_irq_base; korva_out32(KORVA_S_IMR, korva_in32(KORVA_S_IMR) & ~(1 << irq) ); } static unsigned int korva_irq_startup(unsigned int irq) { korva_irq_enable(irq); return 0; } #define korva_irq_shutdown korva_irq_disable /* the intr status register is already cleared when we read it */ #define korva_irq_ack korva_irq_disable #define korva_irq_end korva_irq_enable static hw_irq_controller korva_irq_controller = { "KORVA_irq", korva_irq_startup, korva_irq_shutdown, korva_irq_enable, korva_irq_disable, korva_irq_ack, korva_irq_end, NULL /* no affinity stuff for UP */ }; void korva_irq_init(u32 irq_base) { extern irq_desc_t irq_desc[]; u32 i; for (i= irq_base; i< irq_base+NUM_KORVA_IRQS; i++) { irq_desc[i].status = IRQ_DISABLED; irq_desc[i].action = NULL; irq_desc[i].depth = 1; irq_desc[i].handler = &korva_irq_controller; } korva_irq_base = irq_base; } --- NEW FILE: prom.c --- /*********************************************************************** * Copyright 2001 MontaVista Software Inc. * Author: Jun Sun, js...@mv... or js...@ju... * * arch/mips/korva/prom.c * prom setup file for korva * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. *********************************************************************** */ #include <linux/init.h> #include <linux/config.h> #include <linux/kernel.h> #include <linux/string.h> #include <linux/mm.h> #include <linux/bootmem.h> #include <asm/bootinfo.h> #include <asm/addrspace.h> #include <asm/korva.h> char arcs_cmdline[COMMAND_LINE_SIZE]; void __init prom_init(void) { u32 sdtsr; u32 ramsize; strcpy(arcs_cmdline, "console=ttyS0,115200"); strcat(arcs_cmdline, " ip=bootp"); mips_machgroup = MACH_GROUP_NEC_VR41XX; mips_machtype = MACH_NEC_KORVA; /* bit 8:9 determines the RAM size */ sdtsr = korva_in32(KORVA_SDTSR); ramsize = 2 << (1 + ((sdtsr >> 8) & 3)); printk("Korva board with %d MB system RAM\n", ramsize); add_memory_region(0, ramsize << 20 , BOOT_MEM_RAM); } void __init prom_free_prom_memory(void) { } void __init prom_fixup_mem_map(unsigned long start, unsigned long end) { } --- NEW FILE: reset.c --- /* * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * Copyright (C) 1997, 2001 Ralf Baechle * Copyright 2001 MontaVista Software Inc. * Author: js...@mv... or js...@ju... */ #include <linux/sched.h> #include <linux/mm.h> #include <asm/io.h> #include <asm/pgtable.h> #include <asm/processor.h> #include <asm/reboot.h> #include <asm/system.h> void nec_korva_restart(char *command) { set_cp0_status(ST0_BEV | ST0_ERL); change_cp0_config(CONF_CM_CMASK, CONF_CM_UNCACHED); flush_cache_all(); write_32bit_cp0_register(CP0_WIRED, 0); __asm__ __volatile__("jr\t%0"::"r"(0xbfc00000)); } void nec_korva_halt(void) { printk(KERN_NOTICE "\n** You can safely turn off the power\n"); while (1); } void nec_korva_power_off(void) { nec_korva_halt(); } --- NEW FILE: setup.c --- /*********************************************************************** * Copyright 2001 MontaVista Software Inc. * Author: Jun Sun, js...@mv... or js...@ju... * * arch/mips/korva/setup.c * The setup file for korva. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. *********************************************************************** */ #include <linux/config.h> #include <linux/init.h> #include <linux/delay.h> #include <linux/irq.h> #include <linux/interrupt.h> #include <linux/serial.h> #include <linux/types.h> #include <linux/string.h> /* for memset */ #include <asm/reboot.h> #include <asm/io.h> #include <asm/time.h> #include <asm/korva.h> #include <asm/ddb5xxx/debug.h> // #define USE_CPU_TIMER 1 /* are we using cpu counter as timer */ extern void nec_korva_restart(char* c); extern void nec_korva_halt(void); extern void nec_korva_power_off(void); static void __init init_serial_ports(void) { struct serial_struct s; /* clear memory */ memset(&s, 0, sizeof(s)); s.line = 0; /* we set the first one */ s.baud_base = 1152000; // s.irq = 6; s.irq = 10; s.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST; s.iomem_base = (u8*)(KORVA_BASE_VIRT + KORVA_UARTDLL); s.iomem_reg_shift = 2; s.io_type = SERIAL_IO_MEM; MIPS_VERIFY(early_serial_setup(&s), == 0); } static void __init nec_korva_time_init(void) { /* 100 (CPU clock) MHz divided by 8 */ mips_counter_frequency = 100000000 / 8; } extern int setup_irq(unsigned int irq, struct irqaction *irqaction); static void __init nec_korva_timer_setup(struct irqaction *irq) { #if defined(USE_CPU_TIMER) unsigned int count; setup_irq(7, irq); /* to generate the first CPU timer interrupt */ count = read_32bit_cp0_register(CP0_COUNT); write_32bit_cp0_register(CP0_COMPARE, count + 1000); #else setup_irq(8,irq); korva_out32(KORVA_TM0CSR, 100000000 / HZ); /* CPU clock / HZ */ korva_out32(KORVA_TMMR, 0x1); /* start the timer 0 */ #endif } #if defined(CONFIG_BLK_DEV_INITRD) extern unsigned long __rd_start, __rd_end, initrd_start, initrd_end; #endif #if defined(CONFIG_NEC_CANDY) /* need to come up with a better way. FIXME */ static u_char ETHER_MAC_ADDR[][6] = { {0x00, 0x00, 0x4c, 0x80, 0x92, 0xa1}, {0x00, 0x00, 0x4c, 0x80, 0x92, 0xa2} }; extern int nec_candy_setup_boot_param(uint irq, ulong base_addr, ulong pmd_addr, u_char *mac_addr); #endif void __init nec_korva_setup(void) { MIPS_DEBUG(printk("nec_korva_setup() starts.\n")); #if defined(CONFIG_BLK_DEV_INITRD) ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0); initrd_start = (unsigned long)&__rd_start; initrd_end = (unsigned long)&__rd_end; #endif board_time_init = nec_korva_time_init; board_timer_setup = nec_korva_timer_setup; _machine_restart = nec_korva_restart; _machine_halt = nec_korva_halt; _machine_power_off = nec_korva_power_off; init_serial_ports(); #if defined(CONFIG_NEC_CANDY) /* setup ether driver */ nec_candy_setup_boot_param(4, 0xb0002000, 0x14, ETHER_MAC_ADDR[0]); nec_candy_setup_boot_param(5, 0xb0003000, 0x16, ETHER_MAC_ADDR[1]); #endif /* ---------------- board hardware setup ---------------- */ /* reset all peripherials, except uart */ // korva_out32(KORVA_S_WRCR, 0x1f); korva_out32(KORVA_S_WRCR, 0x0f); /* enable IBUS arbitration for peripherals */ korva_set_bits(KORVA_S_GMR, 0x2); } |