diff options
author | florian <florian@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2007-03-19 17:34:37 +0000 |
---|---|---|
committer | florian <florian@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2007-03-19 17:34:37 +0000 |
commit | 14f5c350584f1b0f282cfe7724965fb44494b3eb (patch) | |
tree | b35da0cddc71a9b1cf8639b770a4994c7c8024ae /target/linux/adm5120-2.6/files/arch/mips/adm5120 | |
parent | 83cf826ce2d25cf77fdd8fc905611d0ea5de45ef (diff) |
Preliminary ADM5120 support, marked as broken
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@6614 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'target/linux/adm5120-2.6/files/arch/mips/adm5120')
6 files changed, 697 insertions, 0 deletions
diff --git a/target/linux/adm5120-2.6/files/arch/mips/adm5120/Makefile b/target/linux/adm5120-2.6/files/arch/mips/adm5120/Makefile new file mode 100644 index 000000000..63024e36d --- /dev/null +++ b/target/linux/adm5120-2.6/files/arch/mips/adm5120/Makefile @@ -0,0 +1,7 @@ +# +# Makefile for the ADMtek ADM5120 SoC specific parts of the kernel +# + +obj-y := setup.o prom.o irq.o memory.o mipsIRQ.o + +EXTRA_AFLAGS := $(CFLAGS) diff --git a/target/linux/adm5120-2.6/files/arch/mips/adm5120/irq.c b/target/linux/adm5120-2.6/files/arch/mips/adm5120/irq.c new file mode 100644 index 000000000..46f3bb05e --- /dev/null +++ b/target/linux/adm5120-2.6/files/arch/mips/adm5120/irq.c @@ -0,0 +1,156 @@ +/* + * Copyright (C) ADMtek Incorporated. + * Creator : daniell@admtek.com.tw + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 2000, 2001 MIPS Technologies, Inc. + * Copyright (C) 2001 Ralf Baechle + * Copyright (C) 2005 Jeroen Vreeken (pe1rxq@amsat.org) + */ + +#include <linux/autoconf.h> +#include <linux/init.h> +#include <linux/kernel_stat.h> +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/interrupt.h> +#include <linux/slab.h> +#include <linux/random.h> +#include <linux/pm.h> + +#include <asm/irq.h> +#include <asm/time.h> +#include <asm/mipsregs.h> +#include <asm/gdb-stub.h> +#include <asm/irq_cpu.h> + +#define MIPS_CPU_TIMER_IRQ 7 + +extern int setup_irq(unsigned int irq, struct irqaction *irqaction); +extern irq_desc_t irq_desc[]; +extern asmlinkage void mipsIRQ(void); + +int mips_int_lock(void); +void mips_int_unlock(int); + +unsigned int mips_counter_frequency; + +#define ADM5120_INTC_REG(reg) (*(volatile u32 *)(KSEG1ADDR(0x12200000+(reg)))) +#define ADM5120_INTC_STATUS ADM5120_INTC_REG(0x00) +#define ADM5120_INTC_ENABLE ADM5120_INTC_REG(0x08) +#define ADM5120_INTC_DISABLE ADM5120_INTC_REG(0x0c) +#define ADM5120_IRQ_MAX 9 +#define ADM5120_IRQ_MASK 0x3ff + +void adm5120_hw0_irqdispatch(struct pt_regs *regs) +{ + unsigned long intsrc; + int i; + + intsrc = ADM5120_INTC_STATUS & ADM5120_IRQ_MASK; + + for (i = 0; intsrc; intsrc >>= 1, i++) + if (intsrc & 0x1) + do_IRQ(i); + else + spurious_interrupt(); +} + +void mips_timer_interrupt(struct pt_regs *regs) +{ + write_c0_compare(read_c0_count()+ mips_counter_frequency/HZ); + ll_timer_interrupt(MIPS_CPU_TIMER_IRQ); +} + +/* Main interrupt dispatcher */ +asmlinkage void plat_irq_dispatch(struct pt_regs *regs) +{ + unsigned int cp0_cause = read_c0_cause() & read_c0_status(); + + if (cp0_cause & CAUSEF_IP7) { + mips_timer_interrupt( regs); + } else if (cp0_cause & CAUSEF_IP2) { + adm5120_hw0_irqdispatch( regs); + } +} + +void enable_adm5120_irq(unsigned int irq) +{ + int s; + + /* Disable all interrupts (FIQ/IRQ) */ + s = mips_int_lock(); + + if ((irq < 0) || (irq > ADM5120_IRQ_MAX)) + goto err_exit; + + ADM5120_INTC_ENABLE = (1<<irq); + +err_exit: + + /* Restore the interrupts states */ + mips_int_unlock(s); +} + + +void disable_adm5120_irq(unsigned int irq) +{ + int s; + + /* Disable all interrupts (FIQ/IRQ) */ + s = mips_int_lock(); + + if ((irq < 0) || (irq > ADM5120_IRQ_MAX)) + goto err_exit; + + ADM5120_INTC_DISABLE = (1<<irq); + +err_exit: + /* Restore the interrupts states */ + mips_int_unlock(s); +} + +unsigned int startup_adm5120_irq(unsigned int irq) +{ + enable_adm5120_irq(irq); + return 0; +} + +void shutdown_adm5120_irq(unsigned int irq) +{ + disable_adm5120_irq(irq); +} + +static inline void ack_adm5120_irq(unsigned int irq_nr) +{ + ADM5120_INTC_DISABLE = (1 << irq_nr); +} + + +static void end_adm5120_irq(unsigned int irq_nr) +{ + ADM5120_INTC_ENABLE = (1 << irq_nr); +} + +static hw_irq_controller adm5120_irq_type = { + .typename = "MIPS", + .startup = startup_adm5120_irq, + .shutdown = shutdown_adm5120_irq, + .enable = enable_adm5120_irq, + .disable = disable_adm5120_irq, + .ack = ack_adm5120_irq, + .end = end_adm5120_irq, + .set_affinity = NULL, +}; + + +void __init arch_init_irq(void) +{ + int i; + + for (i = 0; i <= ADM5120_IRQ_MAX; i++) { + irq_desc[i].status = IRQ_DISABLED; + irq_desc[i].action = 0; + irq_desc[i].depth = 1; + irq_desc[i].chip = &adm5120_irq_type; + } +} diff --git a/target/linux/adm5120-2.6/files/arch/mips/adm5120/memory.c b/target/linux/adm5120-2.6/files/arch/mips/adm5120/memory.c new file mode 100644 index 000000000..a8ffb0c8f --- /dev/null +++ b/target/linux/adm5120-2.6/files/arch/mips/adm5120/memory.c @@ -0,0 +1,154 @@ +/***************************************************************************** + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. + * Copyright (C) 2003 ADMtek Incorporated. + * daniell@admtek.com.tw + * Copyright (C) 2005 Jeroen Vreeken (pe1rxq@amsat.org) + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + * + *****************************************************************************/ + +#include <linux/autoconf.h> +#include <linux/init.h> +#include <linux/mm.h> +#include <linux/bootmem.h> +#include <linux/pfn.h> +#include <linux/string.h> + +#include <asm/bootinfo.h> +#include <asm/page.h> +#include <asm/sections.h> + +#include <asm-mips/mips-boards/prom.h> + +extern char *prom_getenv(char *envname); + +#define PFN_ALIGN(x) (((unsigned long)(x) + (PAGE_SIZE - 1)) & PAGE_MASK) + +#define ADM5120_MEMCTRL 0x1200001c +#define ADM5120_MEMCTRL_SDRAM_MASK 0x7 + +static const unsigned long adm_sdramsize[] __initdata = { + 0x0, /* Reserved */ + 0x0400000, /* 4Mb */ + 0x0800000, /* 8Mb */ + 0x1000000, /* 16Mb */ + 0x4000000, /* 64Mb */ + 0x8000000, /* 128Mb */ +}; + +/* determined physical memory size, not overridden by command line args */ +unsigned long physical_memsize = 0L; + +struct prom_pmemblock mdesc[PROM_MAX_PMEMBLOCKS]; + +struct prom_pmemblock * __init prom_getmdesc(void) +{ + char *memsize_str; + unsigned int memsize; + char cmdline[CL_SIZE], *ptr; + + memsize_str = prom_getenv("memsize"); + + if (!memsize_str) + { + prom_printf("memsize not set in boot prom, set to default (8Mb)\n"); + physical_memsize = 0x00800000; + } + else +#ifdef DEBUG + prom_printf("prom_memsize = %s\n", memsize_str); +#endif + physical_memsize = simple_strtol(memsize_str, NULL, 0); + + /* Check the command line for a memsize directive that overrides + * the physical/default amount */ + strcpy(cmdline, arcs_cmdline); + ptr = strstr(cmdline, "memsize="); + if (ptr && (ptr != cmdline) && (*(ptr - 1) != ' ')) + ptr = strstr(ptr, " memsize="); + + if (ptr) + memsize = memparse(ptr + 8, &ptr); + else + memsize = physical_memsize; + + memset(mdesc, 0, sizeof(mdesc)); + + mdesc[0].type = BOOT_MEM_RAM; + mdesc[0].base = CPHYSADDR(PFN_ALIGN(&_end)); + mdesc[0].size = memsize - mdesc[0].base; + + return &mdesc[0]; +} + +void __init prom_meminit(void) +{ + struct prom_pmemblock *p; + + p = prom_getmdesc(); + + while (p->size) + { + long type; + unsigned long base, size; + base = p->base; + type = p->type, + size = p->size; + add_memory_region(base, size, type); + p++; + } +} + +#if 0 +void __init prom_meminit(void) +{ + unsigned long base = CPHYSADDR(PFN_ALIGN(&_end)); + unsigned long size; + + u32 memctrl = *(u32*)KSEG1ADDR(ADM5120_MEMCTRL); + size = adm_sdramsize[memctrl & ADM5120_MEMCTRL_SDRAM_MASK]; + add_memory_region(base, size-base, BOOT_MEM_RAM); +} +#endif + +unsigned long __init prom_free_prom_memory(void) +{ + unsigned long freed = 0; + unsigned long addr; + int i; + + for (i = 0; i < boot_mem_map.nr_map; i++) { + if (boot_mem_map.map[i].type != BOOT_MEM_ROM_DATA) + continue; + + addr = PAGE_ALIGN(boot_mem_map.map[i].addr); + while (addr < boot_mem_map.map[i].addr + + boot_mem_map.map[i].size) { + ClearPageReserved(virt_to_page(__va(addr))); + init_page_count(virt_to_page(__va(addr))); + free_page((unsigned long)__va(addr)); + addr += PAGE_SIZE; + freed += PAGE_SIZE; + } + } + printk("Freeing prom memory: %ldkb freed\n", freed >> 10); + + return freed; +} diff --git a/target/linux/adm5120-2.6/files/arch/mips/adm5120/mipsIRQ.S b/target/linux/adm5120-2.6/files/arch/mips/adm5120/mipsIRQ.S new file mode 100644 index 000000000..f118fb402 --- /dev/null +++ b/target/linux/adm5120-2.6/files/arch/mips/adm5120/mipsIRQ.S @@ -0,0 +1,135 @@ +/* + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 1999, 2000 MIPS Technologies, Inc. All rights reserved. + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + * + * Interrupt exception dispatch code. + * + */ +#include <linux/autoconf.h> + +#include <asm/asm.h> +#include <asm/mipsregs.h> +#include <asm/regdef.h> +#include <asm/stackframe.h> + +#define STATUS_IE 0x00000001 + +/* A lot of complication here is taken away because: + * + * 1) We handle one interrupt and return, sitting in a loop and moving across + * all the pending IRQ bits in the cause register is _NOT_ the answer, the + * common case is one pending IRQ so optimize in that direction. + * + * 2) We need not check against bits in the status register IRQ mask, that + * would make this routine slow as hell. + * + * 3) Linux only thinks in terms of all IRQs on or all IRQs off, nothing in + * between like BSD spl() brain-damage. + * + * Furthermore, the IRQs on the MIPS board look basically (barring software + * IRQs which we don't use at all and all external interrupt sources are + * combined together on hardware interrupt 0 (MIPS IRQ 2)) like: + * + * MIPS IRQ Source + * -------- ------ + * 0 Software (ignored) + * 1 Software (ignored) + * 2 Combined hardware interrupt (hw0) + * 3 Hardware (ignored) + * 4 Hardware (ignored) + * 5 Hardware (ignored) + * 6 Hardware (ignored) + * 7 R4k timer (what we use) + * + * Note: On the SEAD board thing are a little bit different. + * Here IRQ 2 (hw0) is wired to the UART0 and IRQ 3 (hw1) is wired + * wired to UART1. + * + * We handle the IRQ according to _our_ priority which is: + * + * Highest ---- R4k Timer + * Lowest ---- Combined hardware interrupt + * + * then we just return, if multiple IRQs are pending then we will just take + * another exception, big deal. + */ + + .text + .set noreorder + .set noat + .align 5 + +NESTED(mipsIRQ, PT_SIZE, sp) + SAVE_ALL + CLI + .set at + + mfc0 s0, CP0_CAUSE + mfc0 s1, CP0_STATUS + and s0, s0, s1 + + /* First we check for r4k counter/timer IRQ. */ + andi a0, s0, CAUSEF_IP7 + beq a0, zero, 1f + nop + + move a0, sp + jal mips_timer_interrupt + nop + + j ret_from_irq + nop + +1: + andi a0, s0, CAUSEF_IP2 + beq a0, zero, 1f + nop + + move a0, sp + jal adm5120_hw0_irqdispatch + nop +1: + j ret_from_irq + nop + +END(mipsIRQ) + + +LEAF(mips_int_lock) + .set noreorder + mfc0 v0, CP0_STATUS + li v1, ~STATUS_IE + and v1, v1, v0 + mtc0 v1, CP0_STATUS + j ra + and v0, v0, STATUS_IE + .set reorder +END(mips_int_lock) + + +LEAF(mips_int_unlock) + mfc0 v0, CP0_STATUS + and a0, a0, STATUS_IE + or v0, v0, a0 + mtc0 v0, CP0_STATUS + j ra + nop +END(mips_int_unlock) + diff --git a/target/linux/adm5120-2.6/files/arch/mips/adm5120/prom.c b/target/linux/adm5120-2.6/files/arch/mips/adm5120/prom.c new file mode 100644 index 000000000..ba8051ea8 --- /dev/null +++ b/target/linux/adm5120-2.6/files/arch/mips/adm5120/prom.c @@ -0,0 +1,113 @@ +/***************************************************************************** + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. + * Copyright (C) 2003 ADMtek Incorporated. + * daniell@admtek.com.tw + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + *****************************************************************************/ + +#include <linux/init.h> +#include <linux/autoconf.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> + +void setup_prom_printf(int); +void prom_printf(char *, ...); +void prom_meminit(void); + +#define ADM5120_ENVC 1 + +char *adm5120_envp[2*ADM5120_ENVC] = {"memsize","0x001000000"}; + +#define READCSR(r) *(volatile unsigned long *)(0xB2600000+(r)) +#define WRITECSR(r,v) *(volatile unsigned long *)(0xB2600000+(r)) = v + +#define UART_DR_REG 0x00 +#define UART_FR_REG 0x18 +#define UART_TX_FIFO_FULL 0x20 + +int putPromChar(char c) +{ + WRITECSR(UART_DR_REG, c); + while ( (READCSR(UART_FR_REG) & UART_TX_FIFO_FULL) ); + return 0; +} + +/* + * Ugly prom_printf used for debugging + */ + +void prom_printf(char *fmt, ...) +{ + va_list args; + int l; + char *p, *buf_end; + char buf[1024]; + + va_start(args, fmt); + l = vsprintf(buf, fmt, args); /* hopefully i < sizeof(buf) */ + va_end(args); + + buf_end = buf + l; + + for (p = buf; p < buf_end; p++) { + /* Crude cr/nl handling is better than none */ + if (*p == '\n') + putPromChar('\r'); + putPromChar(*p); + } +} + +char *prom_getenv(char *envname) +{ + int i, index=0; + + i = strlen(envname); + + printk(KERN_INFO "GETENV: envname is %s\n", envname); + + while(index < (2*ADM5120_ENVC)) { + if(strncmp(envname, adm5120_envp[index], i) == 0) { + printk(KERN_INFO "GETENV: returning %s\n", adm5120_envp[index+1]); + return(adm5120_envp[index+1]); + } + index += 2; + } + + printk(KERN_INFO "GETENV: not found.\n"); + return(NULL); +} + +/* + * initialize the prom module. + */ +void __init prom_init(void) +{ + /* you should these macros defined in include/asm/bootinfo.h */ + mips_machgroup = MACH_GROUP_ADM_GW; + mips_machtype = MACH_ADM_GW_5120; + + /* init command line, register a default kernel command line */ + strcpy(&(arcs_cmdline[0]), "console=ttyS0,115200 rootfstype=jffs2 init=/etc/preinit"); + + /* init memory map */ + prom_meminit(); +} diff --git a/target/linux/adm5120-2.6/files/arch/mips/adm5120/setup.c b/target/linux/adm5120-2.6/files/arch/mips/adm5120/setup.c new file mode 100644 index 000000000..23e668411 --- /dev/null +++ b/target/linux/adm5120-2.6/files/arch/mips/adm5120/setup.c @@ -0,0 +1,132 @@ +/* + * Copyright (C) ADMtek Incorporated. + * Creator : daniell@admtek.com.tw + * Copyright 1999, 2000 MIPS Technologies, Inc. + * Copyright Jeroen Vreeken (pe1rxq@amsat.org), 2005 + */ + +#include <linux/autoconf.h> +#include <linux/init.h> +#include <linux/device.h> +#include <linux/platform_device.h> + +#include <asm/reboot.h> +#include <asm/io.h> +#include <asm/time.h> + +#define ADM5120_SOFTRESET 0x12000004 +#define STATUS_IE 0x00000001 +#define ALLINTS (IE_IRQ0 | IE_IRQ5 | STATUS_IE) + +#define ADM5120_CODEREG 0x12000000 +#define ADM5120_CPU_CLK_MASK 0x00300000 +#define ADM5120_CPU_CLK_175 0x00000000 +#define ADM5120_CPU_CLK_200 0x00100000 +#define ADM5120_CPU_CLK_225 0x00200000 +#define ADM5120_CPU_CLK_250 0x00300000 + +void mips_time_init(void); + +extern unsigned int mips_counter_frequency; + +void adm5120_restart(char *command) +{ + *(u32*)KSEG1ADDR(ADM5120_SOFTRESET)=1; +} + + +void adm5120_halt(void) +{ + printk(KERN_NOTICE "\n** You can safely turn off the power\n"); + while (1); +} + + +void adm5120_power_off(void) +{ + adm5120_halt(); +} + +void __init mips_time_init(void) +{ + u32 clock; + + clock = *(u32*)KSEG1ADDR(ADM5120_CODEREG); + + switch (clock & ADM5120_CPU_CLK_MASK) { + case ADM5120_CPU_CLK_175: + mips_counter_frequency = 87500000; + printk("CPU clock: 175MHz\n"); + break; + case ADM5120_CPU_CLK_200: + mips_counter_frequency = 100000000; + printk("CPU clock: 200MHz\n"); + break; + case ADM5120_CPU_CLK_225: + mips_counter_frequency = 112500000; + printk("CPU clock: 225MHz\n"); + break; + case ADM5120_CPU_CLK_250: + mips_counter_frequency = 125000000; + printk("CPU clock: 250MHz\n"); + break; + } +} + +void __init plat_timer_setup(struct irqaction *irq) +{ + /* to generate the first timer interrupt */ + write_c0_compare(read_c0_count()+ mips_counter_frequency/HZ); + clear_c0_status(ST0_BEV); + set_c0_status(ALLINTS); +} + +void __init plat_mem_setup(void) +{ + printk(KERN_INFO "ADM5120 board setup\n"); + + board_time_init = mips_time_init; + //board_timer_setup = mips_timer_setup; + + _machine_restart = adm5120_restart; + _machine_halt = adm5120_halt; + pm_power_off = adm5120_power_off; + + set_io_port_base(KSEG1); +} + +const char *get_system_type(void) +{ + return "ADM5120 Board"; +} + +static struct resource adm5120_hcd_resources[] = { + [0] = { + .start = 0x11200000, + .end = 0x11200084, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = 0x3, + .end = 0x3, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device adm5120hcd_device = { + .name = "adm5120-hcd", + .id = -1, + .num_resources = ARRAY_SIZE(adm5120_hcd_resources), + .resource = adm5120_hcd_resources, +}; + +static struct platform_device *devices[] __initdata = { + &adm5120hcd_device, +}; + +static int __init adm5120_init(void) +{ + return platform_add_devices(devices, ARRAY_SIZE(devices)); +} + +subsys_initcall(adm5120_init); |