diff options
Diffstat (limited to 'arch/sparc')
55 files changed, 10286 insertions, 0 deletions
diff --git a/arch/sparc/config.mk b/arch/sparc/config.mk new file mode 100644 index 0000000..4de6515 --- /dev/null +++ b/arch/sparc/config.mk @@ -0,0 +1,28 @@ +# +# (C) Copyright 2007 +# Daniel Hellstrom, Gaisler Research, daniel@gaisler.com +# +# See file CREDITS for list of people who contributed to this +# project. +# +# 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 program is distributed in the hope that 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 +# + +CROSS_COMPILE ?= sparc-elf- + +STANDALONE_LOAD_ADDR = 0x00000000 -L $(gcclibdir) -T sparc.lds + +PLATFORM_CPPFLAGS += -DCONFIG_SPARC -D__sparc__ diff --git a/arch/sparc/cpu/leon2/Makefile b/arch/sparc/cpu/leon2/Makefile new file mode 100644 index 0000000..7cc4420 --- /dev/null +++ b/arch/sparc/cpu/leon2/Makefile @@ -0,0 +1,54 @@ +# +# (C) Copyright 2003-2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# See file CREDITS for list of people who contributed to this +# project. +# +# 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 program is distributed in the hope that 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 $(TOPDIR)/config.mk + +LIB = $(obj)lib$(CPU).a + +START = start.o +SOBJS = +COBJS = cpu_init.o serial.o cpu.o interrupts.o prom.o + +SRCS := $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c) +OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS)) +START := $(addprefix $(obj),$(START)) + +all: $(obj).depend $(START) $(LIB) + +$(LIB): $(OBJS) + $(AR) $(ARFLAGS) $@ $(OBJS) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +$(START): $(START:.o=.S) + $(CC) -D__ASSEMBLY__ $(DBGFLAGS) $(OPTFLAGS) -D__KERNEL__ -DTEXT_BASE=$(TEXT_BASE) \ + -I$(TOPDIR)/include -fno-builtin -ffreestanding -nostdinc -isystem $(gccincdir) -pipe \ + $(PLATFORM_CPPFLAGS) -Wall -Wstrict-prototypes \ + -I$(TOPDIR)/board -c -o $(START) $(START:.o=.S) + +sinclude $(obj).depend + +######################################################################### diff --git a/arch/sparc/cpu/leon2/config.mk b/arch/sparc/cpu/leon2/config.mk new file mode 100644 index 0000000..30b224a --- /dev/null +++ b/arch/sparc/cpu/leon2/config.mk @@ -0,0 +1,26 @@ +# +# (C) Copyright 2003 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# See file CREDITS for list of people who contributed to this +# project. +# +# 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 program is distributed in the hope that 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 +# + +PLATFORM_RELFLAGS += -fPIC + +PLATFORM_CPPFLAGS += -DCONFIG_LEON diff --git a/arch/sparc/cpu/leon2/cpu.c b/arch/sparc/cpu/leon2/cpu.c new file mode 100644 index 0000000..d6e23b1 --- /dev/null +++ b/arch/sparc/cpu/leon2/cpu.c @@ -0,0 +1,66 @@ +/* CPU specific code for the LEON2 CPU + * + * (C) Copyright 2007 + * Daniel Hellstrom, Gaisler Research, daniel@gaisler.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 program is distributed in the hope that 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 <common.h> +#include <watchdog.h> +#include <command.h> +#include <netdev.h> + +DECLARE_GLOBAL_DATA_PTR; + +extern void _reset_reloc(void); + +int checkcpu(void) +{ + /* check LEON version here */ + printf("CPU: LEON2\n"); + return 0; +} + +/* ------------------------------------------------------------------------- */ + +void cpu_reset(void) +{ + /* Interrupts off */ + disable_interrupts(); + + /* jump to restart in flash */ + _reset_reloc(); +} + +int do_reset(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) +{ + cpu_reset(); + + return 1; +} + +/* ------------------------------------------------------------------------- */ + +#ifdef CONFIG_GRETH +int cpu_eth_init(bd_t *bis) +{ + return greth_initialize(bis); +} +#endif diff --git a/arch/sparc/cpu/leon2/cpu_init.c b/arch/sparc/cpu/leon2/cpu_init.c new file mode 100644 index 0000000..a24f778 --- /dev/null +++ b/arch/sparc/cpu/leon2/cpu_init.c @@ -0,0 +1,142 @@ +/* Initializes CPU and basic hardware such as memory + * controllers, IRQ controller and system timer 0. + * + * (C) Copyright 2007 + * Daniel Hellstrom, Gaisler Research, daniel@gaisler.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 program is distributed in the hope that 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 <common.h> +#include <asm/asi.h> +#include <asm/leon.h> + +#include <config.h> + +DECLARE_GLOBAL_DATA_PTR; + +/* reset CPU (jump to 0, without reset) */ +void start(void); + +struct { + gd_t gd_area; + bd_t bd; +} global_data; + +/* + * Breath some life into the CPU... + * + * Set up the memory map, + * initialize a bunch of registers. + * + * Run from FLASH/PROM: + * - until memory controller is set up, only registers avaiable + * - no global variables available for writing + * - constants avaiable + */ + +void cpu_init_f(void) +{ + LEON2_regs *leon2 = (LEON2_regs *) LEON2_PREGS; + + /* initialize the IRQMP */ + leon2->Interrupt_Force = 0; + leon2->Interrupt_Pending = 0; + leon2->Interrupt_Clear = 0xfffe; /* clear all old pending interrupts */ + leon2->Interrupt_Mask = 0xfffe0000; /* mask all IRQs */ + + /* cache */ + + /* I/O port setup */ +#ifdef LEON2_IO_PORT_DIR + leon2->PIO_Direction = LEON2_IO_PORT_DIR; +#endif +#ifdef LEON2_IO_PORT_DATA + leon2->PIO_Data = LEON2_IO_PORT_DATA; +#endif +#ifdef LEON2_IO_PORT_INT + leon2->PIO_Interrupt = LEON2_IO_PORT_INT; +#else + leon2->PIO_Interrupt = 0; +#endif +} + +void cpu_init_f2(void) +{ + +} + +/* + * initialize higher level parts of CPU like time base and timers + */ +int cpu_init_r(void) +{ + LEON2_regs *leon2 = (LEON2_regs *) LEON2_PREGS; + + /* initialize prescaler common to all timers to 1MHz */ + leon2->Scaler_Counter = leon2->Scaler_Reload = + (((CONFIG_SYS_CLK_FREQ / 1000) + 500) / 1000) - 1; + + return (0); +} + +/* Uses Timer 0 to get accurate + * pauses. Max 2 raised to 32 ticks + * + */ +void cpu_wait_ticks(unsigned long ticks) +{ + unsigned long start = get_timer(0); + while (get_timer(start) < ticks) ; +} + +/* initiate and setup timer0 interrupt to 1MHz + * Return irq number for timer int or a negative number for + * dealing with self + */ +int timer_interrupt_init_cpu(void) +{ + LEON2_regs *leon2 = (LEON2_regs *) LEON2_PREGS; + + /* 1ms ticks */ + leon2->Timer_Counter_1 = 0; + leon2->Timer_Reload_1 = 999; /* (((1000000 / 100) - 1)) */ + leon2->Timer_Control_1 = + (LEON2_TIMER_CTRL_EN | LEON2_TIMER_CTRL_RS | LEON2_TIMER_CTRL_LD); + + return LEON2_TIMER1_IRQNO; +} + +/* + * This function is intended for SHORT delays only. + */ +unsigned long cpu_usec2ticks(unsigned long usec) +{ + /* timer set to 1kHz ==> 1 clk tick = 1 msec */ + if (usec < 1000) + return 1; + return (usec / 1000); +} + +unsigned long cpu_ticks2usec(unsigned long ticks) +{ + /* 1tick = 1usec */ + return ticks * 1000; +} diff --git a/arch/sparc/cpu/leon2/interrupts.c b/arch/sparc/cpu/leon2/interrupts.c new file mode 100644 index 0000000..9b0da96 --- /dev/null +++ b/arch/sparc/cpu/leon2/interrupts.c @@ -0,0 +1,217 @@ +/* + * (C) Copyright 2007 + * Daniel Hellstrom, Gaisler Research, daniel@gaisler.com + * + * (C) Copyright 2006 + * Detlev Zundel, DENX Software Engineering, dzu@denx.de + * + * (C) Copyright -2003 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * (C) Copyright 2001 + * Josh Huber <huber@mclx.com>, Mission Critical Linux, Inc. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 program is distributed in the hope that 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 <asm/stack.h> +#include <common.h> +#include <asm/io.h> +#include <asm/processor.h> +#include <command.h> +#include <asm/irq.h> + +#include <asm/leon.h> + +/* 15 normal irqs and a non maskable interrupt */ +#define NR_IRQS 15 + +struct irq_action { + interrupt_handler_t *handler; + void *arg; + unsigned int count; +}; + +static struct irq_action irq_handlers[NR_IRQS] = { {0}, }; +static int spurious_irq_cnt = 0; +static int spurious_irq = 0; + +static inline unsigned int leon2_get_irqmask(unsigned int irq) +{ + if ((irq < 0) || (irq >= NR_IRQS)) { + return 0; + } else { + return (1 << irq); + } +} + +static void leon2_ic_disable(unsigned int irq) +{ + unsigned int mask, pil; + LEON2_regs *leon2 = (LEON2_regs *) LEON2_PREGS; + + pil = intLock(); + + /* get mask of interrupt */ + mask = leon2_get_irqmask(irq); + + /* set int level */ + leon2->Interrupt_Mask = + SPARC_NOCACHE_READ(&leon2->Interrupt_Mask) & (~mask); + + intUnlock(pil); +} + +static void leon2_ic_enable(unsigned int irq) +{ + unsigned int mask, pil; + LEON2_regs *leon2 = (LEON2_regs *) LEON2_PREGS; + + pil = intLock(); + + /* get mask of interrupt */ + mask = leon2_get_irqmask(irq); + + /* set int level */ + leon2->Interrupt_Mask = + SPARC_NOCACHE_READ(&leon2->Interrupt_Mask) | mask; + + intUnlock(pil); +} + +void handler_irq(int irq, struct pt_regs *regs) +{ + if (irq_handlers[irq].handler) { + if (((unsigned int)irq_handlers[irq].handler > CONFIG_SYS_RAM_END) || + ((unsigned int)irq_handlers[irq].handler < CONFIG_SYS_RAM_BASE) + ) { + printf("handler_irq: bad handler: %x, irq number %d\n", + (unsigned int)irq_handlers[irq].handler, irq); + return; + } + irq_handlers[irq].handler(irq_handlers[irq].arg); + irq_handlers[irq].count++; + } else { + spurious_irq_cnt++; + spurious_irq = irq; + } +} + +void leon2_force_int(int irq) +{ + LEON2_regs *leon2 = (LEON2_regs *) LEON2_PREGS; + + if ((irq >= NR_IRQS) || (irq < 0)) + return; + printf("Forcing interrupt %d\n", irq); + + leon2->Interrupt_Force = + SPARC_NOCACHE_READ(&leon2->Interrupt_Force) | (1 << irq); +} + +/****************************************************************************/ + +int interrupt_init_cpu(void) +{ + return (0); +} + +/****************************************************************************/ + +/* Handle Timer 0 IRQ */ +void timer_interrupt_cpu(void *arg) +{ + LEON2_regs *leon2 = (LEON2_regs *) LEON2_PREGS; + + leon2->Timer_Control_1 = + (LEON2_TIMER_CTRL_EN | LEON2_TIMER_CTRL_RS | LEON2_TIMER_CTRL_LD); + + /* nothing to do here */ + return; +} + +/****************************************************************************/ + +/* + * Install and free a interrupt handler. + */ + +void irq_install_handler(int irq, interrupt_handler_t * handler, void *arg) +{ + if (irq < 0 || irq >= NR_IRQS) { + printf("irq_install_handler: bad irq number %d\n", irq); + return; + } + + if (irq_handlers[irq].handler != NULL) + printf("irq_install_handler: 0x%08lx replacing 0x%08lx\n", + (ulong) handler, (ulong) irq_handlers[irq].handler); + + if (((unsigned int)handler > CONFIG_SYS_RAM_END) || + ((unsigned int)handler < CONFIG_SYS_RAM_BASE) + ) { + printf("irq_install_handler: bad handler: %x, irq number %d\n", + (unsigned int)handler, irq); + return; + } + irq_handlers[irq].handler = handler; + irq_handlers[irq].arg = arg; + + /* enable irq on LEON2 hardware */ + leon2_ic_enable(irq); + +} + +void irq_free_handler(int irq) +{ + if (irq < 0 || irq >= NR_IRQS) { + printf("irq_free_handler: bad irq number %d\n", irq); + return; + } + + /* disable irq on LEON2 hardware */ + leon2_ic_disable(irq); + + irq_handlers[irq].handler = NULL; + irq_handlers[irq].arg = NULL; +} + +/****************************************************************************/ + +#if defined(CONFIG_CMD_IRQ) +void do_irqinfo(cmd_tbl_t * cmdtp, bd_t * bd, int flag, int argc, char *argv[]) +{ + int irq; + unsigned int pil = get_pil(); + printf("PIL level: %u\n\r", pil); + printf("Spurious IRQ: %u, last unknown IRQ: %d\n", + spurious_irq_cnt, spurious_irq); + + puts("\nInterrupt-Information:\n" "Nr Routine Arg Count\n"); + + for (irq = 0; irq < NR_IRQS; irq++) { + if (irq_handlers[irq].handler != NULL) { + printf("%02d %08lx %08lx %ld\n", irq, + (unsigned int)irq_handlers[irq].handler, + (unsigned int)irq_handlers[irq].arg, + irq_handlers[irq].count); + } + } +} +#endif diff --git a/arch/sparc/cpu/leon2/prom.c b/arch/sparc/cpu/leon2/prom.c new file mode 100644 index 0000000..1a6c7f7 --- /dev/null +++ b/arch/sparc/cpu/leon2/prom.c @@ -0,0 +1,1047 @@ +/* prom.c - emulates a sparc v0 PROM for the linux kernel. + * + * Copyright (C) 2003 Konrad Eisele <eiselekd@web.de> + * Copyright (C) 2004 Stefan Holst <mail@s-holst.de> + * Copyright (C) 2007 Daniel Hellstrom <daniel@gaisler.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 program is distributed in the hope that 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 <common.h> +#include <asm/prom.h> +#include <asm/machines.h> +#include <asm/srmmu.h> +#include <asm/processor.h> +#include <asm/irq.h> +#include <asm/leon.h> + +#include <config.h> +/* +#define PRINT_ROM_VEC +*/ +extern struct linux_romvec *kernel_arg_promvec; + +#define PROM_PGT __attribute__ ((__section__ (".prom.pgt"))) +#define PROM_TEXT __attribute__ ((__section__ (".prom.text"))) +#define PROM_DATA __attribute__ ((__section__ (".prom.data"))) + +/* for __va */ +extern int __prom_start; +#define PAGE_OFFSET 0xf0000000 +#define phys_base CONFIG_SYS_SDRAM_BASE +#define PROM_OFFS 8192 +#define PROM_SIZE_MASK (PROM_OFFS-1) +#define __va(x) ( \ + (void *)( ((unsigned long)(x))-PROM_OFFS+ \ + (CONFIG_SYS_PROM_OFFSET-phys_base)+PAGE_OFFSET-TEXT_BASE ) \ + ) +#define __phy(x) ((void *)(((unsigned long)(x))-PROM_OFFS+CONFIG_SYS_PROM_OFFSET-TEXT_BASE)) + +struct property { + char *name; + char *value; + int length; +}; + +struct node { + int level; + struct property *properties; +}; + +static void leon_reboot(char *bcommand); +static void leon_halt(void); +static int leon_nbputchar(int c); +static int leon_nbgetchar(void); + +static int no_nextnode(int node); +static int no_child(int node); +static int no_proplen(int node, char *name); +static int no_getprop(int node, char *name, char *value); +static int no_setprop(int node, char *name, char *value, int len); +static char *no_nextprop(int node, char *name); + +static struct property PROM_TEXT *find_property(int node, char *name); +static int PROM_TEXT leon_strcmp(const char *s1, const char *s2); +static void *PROM_TEXT leon_memcpy(void *dest, const void *src, size_t n); +static void PROM_TEXT leon_reboot_physical(char *bcommand); + +void __inline__ leon_flush_cache_all(void) +{ + __asm__ __volatile__(" flush "); + __asm__ __volatile__("sta %%g0, [%%g0] %0\n\t"::"i"(ASI_DFLUSH):"memory"); +} + +void __inline__ leon_flush_tlb_all(void) +{ + leon_flush_cache_all(); + __asm__ __volatile__("sta %%g0, [%0] %1\n\t"::"r"(0x400), + "i"(ASI_MMUFLUSH):"memory"); +} + +typedef struct { + unsigned int ctx_table[256]; + unsigned int pgd_table[256]; +} sparc_srmmu_setup; + +sparc_srmmu_setup srmmu_tables PROM_PGT = { + {0}, + {0x1e, + 0x10001e, + 0x20001e, + 0x30001e, + 0x40001e, + 0x50001e, + 0x60001e, + 0x70001e, + 0x80001e, + 0x90001e, + 0xa0001e, + 0xb0001e, + 0xc0001e, + 0xd0001e, + 0xe0001e, + 0xf0001e, + 0x100001e, + 0x110001e, + 0x120001e, + 0x130001e, + 0x140001e, + 0x150001e, + 0x160001e, + 0x170001e, + 0x180001e, + 0x190001e, + 0x1a0001e, + 0x1b0001e, + 0x1c0001e, + 0x1d0001e, + 0x1e0001e, + 0x1f0001e, + 0x200001e, + 0x210001e, + 0x220001e, + 0x230001e, + 0x240001e, + 0x250001e, + 0x260001e, + 0x270001e, + 0x280001e, + 0x290001e, + 0x2a0001e, + 0x2b0001e, + 0x2c0001e, + 0x2d0001e, + 0x2e0001e, + 0x2f0001e, + 0x300001e, + 0x310001e, + 0x320001e, + 0x330001e, + 0x340001e, + 0x350001e, + 0x360001e, + 0x370001e, + 0x380001e, + 0x390001e, + 0x3a0001e, + 0x3b0001e, + 0x3c0001e, + 0x3d0001e, + 0x3e0001e, + 0x3f0001e, + 0x400001e, + 0x410001e, + 0x420001e, + 0x430001e, + 0x440001e, + 0x450001e, + 0x460001e, + 0x470001e, + 0x480001e, + 0x490001e, + 0x4a0001e, + 0x4b0001e, + 0x4c0001e, + 0x4d0001e, + 0x4e0001e, + 0x4f0001e, + 0x500001e, + 0x510001e, + 0x520001e, + 0x530001e, + 0x540001e, + 0x550001e, + 0x560001e, + 0x570001e, + 0x580001e, + 0x590001e, + 0x5a0001e, + 0x5b0001e, + 0x5c0001e, + 0x5d0001e, + 0x5e0001e, + 0x5f0001e, + 0x600001e, + 0x610001e, + 0x620001e, + 0x630001e, + 0x640001e, + 0x650001e, + 0x660001e, + 0x670001e, + 0x680001e, + 0x690001e, + 0x6a0001e, + 0x6b0001e, + 0x6c0001e, + 0x6d0001e, + 0x6e0001e, + 0x6f0001e, + 0x700001e, + 0x710001e, + 0x720001e, + 0x730001e, + 0x740001e, + 0x750001e, + 0x760001e, + 0x770001e, + 0x780001e, + 0x790001e, + 0x7a0001e, + 0x7b0001e, + 0x7c0001e, + 0x7d0001e, + 0x7e0001e, + 0x7f0001e, + 0x800001e, + 0x810001e, + 0x820001e, + 0x830001e, + 0x840001e, + 0x850001e, + 0x860001e, + 0x870001e, + 0x880001e, + 0x890001e, + 0x8a0001e, + 0x8b0001e, + 0x8c0001e, + 0x8d0001e, + 0x8e0001e, + 0x8f0001e, + 0x900001e, + 0x910001e, + 0x920001e, + 0x930001e, + 0x940001e, + 0x950001e, + 0x960001e, + 0x970001e, + 0x980001e, + 0x990001e, + 0x9a0001e, + 0x9b0001e, + 0x9c0001e, + 0x9d0001e, + 0x9e0001e, + 0x9f0001e, + 0xa00001e, + 0xa10001e, + 0xa20001e, + 0xa30001e, + 0xa40001e, + 0xa50001e, + 0xa60001e, + 0xa70001e, + 0xa80001e, + 0xa90001e, + 0xaa0001e, + 0xab0001e, + 0xac0001e, + 0xad0001e, + 0xae0001e, + 0xaf0001e, + 0xb00001e, + 0xb10001e, + 0xb20001e, + 0xb30001e, + 0xb40001e, + 0xb50001e, + 0xb60001e, + 0xb70001e, + 0xb80001e, + 0xb90001e, + 0xba0001e, + 0xbb0001e, + 0xbc0001e, + 0xbd0001e, + 0xbe0001e, + 0xbf0001e, + 0xc00001e, + 0xc10001e, + 0xc20001e, + 0xc30001e, + 0xc40001e, + 0xc50001e, + 0xc60001e, + 0xc70001e, + 0xc80001e, + 0xc90001e, + 0xca0001e, + 0xcb0001e, + 0xcc0001e, + 0xcd0001e, + 0xce0001e, + 0xcf0001e, + 0xd00001e, + 0xd10001e, + 0xd20001e, + 0xd30001e, + 0xd40001e, + 0xd50001e, + 0xd60001e, + 0xd70001e, + 0xd80001e, + 0xd90001e, + 0xda0001e, + 0xdb0001e, + 0xdc0001e, + 0xdd0001e, + 0xde0001e, + 0xdf0001e, + 0xe00001e, + 0xe10001e, + 0xe20001e, + 0xe30001e, + 0xe40001e, + 0xe50001e, + 0xe60001e, + 0xe70001e, + 0xe80001e, + 0xe90001e, + 0xea0001e, + 0xeb0001e, + 0xec0001e, + 0xed0001e, + 0xee0001e, + 0xef0001e, + 0x400001e /* default */ + } +}; + +/* a self contained prom info structure */ +struct leon_reloc_func { + struct property *(*find_property) (int node, char *name); + int (*strcmp) (char *s1, char *s2); + void *(*memcpy) (void *dest, const void *src, size_t n); + void (*reboot_physical) (char *cmd); +}; + +struct leon_prom_info { + int freq_khz; + int leon_nctx; + int mids[32]; + int baudrates[2]; + struct leon_reloc_func reloc_funcs; + struct property root_properties[4]; + struct property cpu_properties[7]; +#undef CPUENTRY +#define CPUENTRY(idx) struct property cpu_properties##idx[4] + CPUENTRY(1); + CPUENTRY(2); + CPUENTRY(3); + CPUENTRY(4); + CPUENTRY(5); + CPUENTRY(6); + CPUENTRY(7); + CPUENTRY(8); + CPUENTRY(9); + CPUENTRY(10); + CPUENTRY(11); + CPUENTRY(12); + CPUENTRY(13); + CPUENTRY(14); + CPUENTRY(15); + CPUENTRY(16); + CPUENTRY(17); + CPUENTRY(18); + CPUENTRY(19); + CPUENTRY(20); + CPUENTRY(21); + CPUENTRY(22); + CPUENTRY(23); + CPUENTRY(24); + CPUENTRY(25); + CPUENTRY(26); + CPUENTRY(27); + CPUENTRY(28); + CPUENTRY(29); + CPUENTRY(30); + CPUENTRY(31); + struct idprom idprom; + struct linux_nodeops nodeops; + struct linux_mlist_v0 *totphys_p; + struct linux_mlist_v0 totphys; + struct linux_mlist_v0 *avail_p; + struct linux_mlist_v0 avail; + struct linux_mlist_v0 *prommap_p; + void (*synchook) (void); + struct linux_arguments_v0 *bootargs_p; + struct linux_arguments_v0 bootargs; + struct linux_romvec romvec; + struct node nodes[35]; + char s_device_type[12]; + char s_cpu[4]; + char s_mid[4]; + char s_idprom[7]; + char s_compatability[14]; + char s_leon2[6]; + char s_mmu_nctx[9]; + char s_frequency[16]; + char s_uart1_baud[11]; + char s_uart2_baud[11]; + char arg[256]; +}; + +/* static prom info */ +static struct leon_prom_info PROM_DATA spi = { + CONFIG_SYS_CLK_FREQ / 1000, + 256, + { +#undef CPUENTRY +#define CPUENTRY(idx) idx + CPUENTRY(0), + CPUENTRY(1), + CPUENTRY(2), + CPUENTRY(3), + CPUENTRY(4), + CPUENTRY(5), + CPUENTRY(6), + CPUENTRY(7), + CPUENTRY(8), + CPUENTRY(9), + CPUENTRY(10), + CPUENTRY(11), + CPUENTRY(12), + CPUENTRY(13), + CPUENTRY(14), + CPUENTRY(15), + CPUENTRY(16), + CPUENTRY(17), + CPUENTRY(18), + CPUENTRY(19), + CPUENTRY(20), + CPUENTRY(21), + CPUENTRY(22), + CPUENTRY(23), + CPUENTRY(24), + CPUENTRY(25), + CPUENTRY(26), + CPUENTRY(27), + CPUENTRY(28), + CPUENTRY(29), + CPUENTRY(30), + 31}, + {38400, 38400}, + { + __va(find_property), + __va(leon_strcmp), + __va(leon_memcpy), + __phy(leon_reboot_physical), + }, + { + {__va(spi.s_device_type), __va(spi.s_idprom), 4}, + {__va(spi.s_idprom), (char *)__va(&spi.idprom), sizeof(struct idprom)}, + {__va(spi.s_compatability), __va(spi.s_leon2), 5}, + {NULL, NULL, -1} + }, + { + {__va(spi.s_device_type), __va(spi.s_cpu), 4}, + {__va(spi.s_mid), __va(&spi.mids[0]), 4}, + {__va(spi.s_mmu_nctx), (char *)__va(&spi.leon_nctx), 4}, + {__va(spi.s_frequency), (char *)__va(&spi.freq_khz), 4}, + {__va(spi.s_uart1_baud), (char *)__va(&spi.baudrates[0]), 4}, + {__va(spi.s_uart2_baud), (char *)__va(&spi.baudrates[1]), 4}, + {NULL, NULL, -1} + }, +#undef CPUENTRY +#define CPUENTRY(idx) \ + { /* cpu_properties */ \ + {__va(spi.s_device_type), __va(spi.s_cpu), 4}, \ + {__va(spi.s_mid), __va(&spi.mids[idx]), 4}, \ + {__va(spi.s_frequency), (char *)__va(&spi.freq_khz), 4}, \ + {NULL, NULL, -1} \ + } + CPUENTRY(1), + CPUENTRY(2), + CPUENTRY(3), + CPUENTRY(4), + CPUENTRY(5), + CPUENTRY(6), + CPUENTRY(7), + CPUENTRY(8), + CPUENTRY(9), + CPUENTRY(10), + CPUENTRY(11), + CPUENTRY(12), + CPUENTRY(13), + CPUENTRY(14), + CPUENTRY(15), + CPUENTRY(16), + CPUENTRY(17), + CPUENTRY(18), + CPUENTRY(19), + CPUENTRY(20), + CPUENTRY(21), + CPUENTRY(22), + CPUENTRY(23), + CPUENTRY(24), + CPUENTRY(25), + CPUENTRY(26), + CPUENTRY(27), + CPUENTRY(28), + CPUENTRY(29), + CPUENTRY(30), + CPUENTRY(31), + { + 0x01, /* format */ + M_LEON2 | M_LEON2_SOC, /* machine type */ + {0, 0, 0, 0, 0, 0}, /* eth */ + 0, /* date */ + 0, /* sernum */ + 0, /* checksum */ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} /* reserved */ + }, + { + __va(no_nextnode), + __va(no_child), + __va(no_proplen), + __va(no_getprop), + __va(no_setprop), + __va(no_nextprop) + }, + __va(&spi.totphys), + { + NULL, + (char *)CONFIG_SYS_SDRAM_BASE, + 0, + }, + __va(&spi.avail), + { + NULL, + (char *)CONFIG_SYS_SDRAM_BASE, + 0, + }, + NULL, /* prommap_p */ + NULL, + __va(&spi.bootargs), + { + {NULL, __va(spi.arg), NULL /*... */ }, + /*... */ + }, + { + 0, + 0, /* sun4c v0 prom */ + 0, 0, + {__va(&spi.totphys_p), __va(&spi.prommap_p), __va(&spi.avail_p)}, + __va(&spi.nodeops), + NULL, {NULL /* ... */ }, + NULL, NULL, + NULL, NULL, /* pv_getchar, pv_putchar */ + __va(leon_nbgetchar), __va(leon_nbputchar), + NULL, + __va(leon_reboot), + NULL, + NULL, + NULL, + __va(leon_halt), + __va(&spi.synchook), + {NULL}, + __va(&spi.bootargs_p) + /*... */ + }, + { + {0, __va(spi.root_properties + 3) /* NULL, NULL, -1 */ }, + {0, __va(spi.root_properties)}, + /* cpu 0, must be spi.nodes[2] see leon_prom_init() */ + {1, __va(spi.cpu_properties)}, + +#undef CPUENTRY +#define CPUENTRY(idx) \ + {1, __va(spi.cpu_properties##idx) } /* cpu <idx> */ + CPUENTRY(1), + CPUENTRY(2), + CPUENTRY(3), + CPUENTRY(4), + CPUENTRY(5), + CPUENTRY(6), + CPUENTRY(7), + CPUENTRY(8), + CPUENTRY(9), + CPUENTRY(10), + CPUENTRY(11), + CPUENTRY(12), + CPUENTRY(13), + CPUENTRY(14), + CPUENTRY(15), + CPUENTRY(16), + CPUENTRY(17), + CPUENTRY(18), + CPUENTRY(19), + CPUENTRY(20), + CPUENTRY(21), + CPUENTRY(22), + CPUENTRY(23), + CPUENTRY(24), + CPUENTRY(25), + CPUENTRY(26), + CPUENTRY(27), + CPUENTRY(28), + CPUENTRY(29), + CPUENTRY(30), + CPUENTRY(31), + {-1, __va(spi.root_properties + 3) /* NULL, NULL, -1 */ } + }, + "device_type", + "cpu", + "mid", + "idprom", + "compatability", + "leon2", + "mmu-nctx", + "clock-frequency", + "uart1_baud", + "uart2_baud", + CONFIG_DEFAULT_KERNEL_COMMAND_LINE +}; + +/* from arch/sparc/kernel/setup.c */ +#define RAMDISK_LOAD_FLAG 0x4000 +extern unsigned short root_flags; +extern unsigned short root_dev; +extern unsigned short ram_flags; +extern unsigned int sparc_ramdisk_image; +extern unsigned int sparc_ramdisk_size; +extern int root_mountflags; + +extern char initrd_end, initrd_start; + +/* Reboot the CPU = jump to beginning of flash again. + * + * Make sure that all function are inlined here. + */ +static void PROM_TEXT leon_reboot(char *bcommand) +{ + register char *arg = bcommand; + void __attribute__ ((noreturn)) (*reboot_physical) (char *cmd); + + /* get physical address */ + struct leon_prom_info *pspi = + (void *)(CONFIG_SYS_PROM_OFFSET + sizeof(srmmu_tables)); + + unsigned int *srmmu_ctx_table; + + /* Turn of Interrupts */ + set_pil(0xf); + + /* Set kernel's context, context zero */ + srmmu_set_context(0); + + /* Get physical address of the MMU shutdown routine */ + reboot_physical = (void *) + SPARC_BYPASS_READ(&pspi->reloc_funcs.reboot_physical); + + /* Now that we know the physical address of the function + * we can make the MMU allow jumping to it. + */ + srmmu_ctx_table = (unsigned int *)srmmu_get_ctable_ptr(); + + srmmu_ctx_table = (unsigned int *)SPARC_BYPASS_READ(srmmu_ctx_table); + + /* get physical address of kernel's context table (assume ptd) */ + srmmu_ctx_table = (unsigned int *) + (((unsigned int)srmmu_ctx_table & 0xfffffffc) << 4); + + /* enable access to physical address of MMU shutdown function */ + SPARC_BYPASS_WRITE(&srmmu_ctx_table + [((unsigned int)reboot_physical) >> 24], + (((unsigned int)reboot_physical & 0xff000000) >> 4) | + 0x1e); + + /* flush TLB cache */ + leon_flush_tlb_all(); + + /* flash instruction & data cache */ + sparc_icache_flush_all(); + sparc_dcache_flush_all(); + + /* jump to physical address function + * so that when the MMU is disabled + * we can continue to execute + */ + reboot_physical(arg); +} + +static void PROM_TEXT leon_reboot_physical(char *bcommand) +{ + void __attribute__ ((noreturn)) (*reset) (void); + + /* Turn off MMU */ + srmmu_set_mmureg(0); + + /* Hardcoded start address */ + reset = CONFIG_SYS_MONITOR_BASE; + + /* flush data cache */ + sparc_dcache_flush_all(); + + /* flush instruction cache */ + sparc_icache_flush_all(); + + /* Jump to start in Flash */ + reset(); +} + +static void PROM_TEXT leon_halt(void) +{ + while (1) ; +} + +/* get single char, don't care for blocking*/ +static int PROM_TEXT leon_nbgetchar(void) +{ + return -1; +} + +/* put single char, don't care for blocking*/ +static int PROM_TEXT leon_nbputchar(int c) +{ + LEON2_regs *leon2 = (LEON2_regs *) LEON2_PREGS; + + /***** put char in buffer... *********** + * Make sure all functions are inline! * + ***************************************/ + + /* Wait for last character to go. */ + while (!(SPARC_BYPASS_READ(&leon2->UART_Status_1) + & LEON2_UART_STAT_THE)) ; + + /* Send data */ + SPARC_BYPASS_WRITE(&leon2->UART_Channel_1, c); + + /* Wait for data to be sent */ + while (!(SPARC_BYPASS_READ(&leon2->UART_Status_1) + & LEON2_UART_STAT_TSE)) ; + + return 0; +} + +/* node ops */ + +/*#define nodes ((struct node *)__va(&pspi->nodes))*/ +#define nodes ((struct node *)(pspi->nodes)) + +static int PROM_TEXT no_nextnode(int node) +{ + /* get physical address */ + struct leon_prom_info *pspi = + (void *)(CONFIG_SYS_PROM_OFFSET + sizeof(srmmu_tables)); + + /* convert into virtual address */ + pspi = (struct leon_prom_info *) + (((unsigned int)pspi & 0x0fffffff) | PAGE_OFFSET); + + if (nodes[node].level == nodes[node + 1].level) + return node + 1; + return -1; +} + +static int PROM_TEXT no_child(int node) +{ + /* get physical address */ + struct leon_prom_info *pspi = (struct leon_prom_info *) + (CONFIG_SYS_PROM_OFFSET + sizeof(srmmu_tables)); + + /* convert into virtual address */ + pspi = (struct leon_prom_info *) + (((unsigned int)pspi & 0x0fffffff) | PAGE_OFFSET); + + if (nodes[node].level == nodes[node + 1].level - 1) + return node + 1; + return -1; +} + +static struct property PROM_TEXT *find_property(int node, char *name) +{ + /* get physical address */ + struct leon_prom_info *pspi = (struct leon_prom_info *) + (CONFIG_SYS_PROM_OFFSET + sizeof(srmmu_tables)); + + /* convert into virtual address */ + pspi = (struct leon_prom_info *) + (((unsigned int)pspi & 0x0fffffff) | PAGE_OFFSET); + + struct property *prop = &nodes[node].properties[0]; + while (prop && prop->name) { + if (pspi->reloc_funcs.strcmp(prop->name, name) == 0) + return prop; + prop++; + } + return NULL; +} + +static int PROM_TEXT no_proplen(int node, char *name) +{ + /* get physical address */ + struct leon_prom_info *pspi = (struct leon_prom_info *) + (CONFIG_SYS_PROM_OFFSET + sizeof(srmmu_tables)); + + /* convert into virtual address */ + pspi = (struct leon_prom_info *) + (((unsigned int)pspi & 0x0fffffff) | PAGE_OFFSET); + + struct property *prop = pspi->reloc_funcs.find_property(node, name); + if (prop) + return prop->length; + return -1; +} + +static int PROM_TEXT no_getprop(int node, char *name, char *value) +{ + /* get physical address */ + struct leon_prom_info *pspi = (struct leon_prom_info *) + (CONFIG_SYS_PROM_OFFSET + sizeof(srmmu_tables)); + + /* convert into virtual address */ + pspi = (struct leon_prom_info *) + (((unsigned int)pspi & 0x0fffffff) | PAGE_OFFSET); + + struct property *prop = pspi->reloc_funcs.find_property(node, name); + if (prop) { + pspi->reloc_funcs.memcpy(value, prop->value, prop->length); + return 1; + } + return -1; +} + +static int PROM_TEXT no_setprop(int node, char *name, char *value, int len) +{ + return -1; +} + +static char PROM_TEXT *no_nextprop(int node, char *name) +{ + /* get physical address */ + struct leon_prom_info *pspi = (struct leon_prom_info *) + (CONFIG_SYS_PROM_OFFSET + sizeof(srmmu_tables)); + struct property *prop; + + /* convert into virtual address */ + pspi = (struct leon_prom_info *) + (((unsigned int)pspi & 0x0fffffff) | PAGE_OFFSET); + + if (!name || !name[0]) + return nodes[node].properties[0].name; + + prop = pspi->reloc_funcs.find_property(node, name); + if (prop) + return prop[1].name; + return NULL; +} + +static int PROM_TEXT leon_strcmp(const char *s1, const char *s2) +{ + register char result; + + while (1) { + result = *s1 - *s2; + if (result || !*s1) + break; + s2++; + s1++; + } + + return result; +} + +static void *PROM_TEXT leon_memcpy(void *dest, const void *src, size_t n) +{ + char *dst = (char *)dest, *source = (char *)src; + + while (n--) { + *dst = *source; + dst++; + source++; + } + return dest; +} + +#define GETREGSP(sp) __asm__ __volatile__("mov %%sp, %0" : "=r" (sp)) + +void leon_prom_init(struct leon_prom_info *pspi) +{ + unsigned long i; + unsigned char cksum, *ptr; + char *addr_str, *end; + unsigned long sp; + GETREGSP(sp); + + pspi->freq_khz = CONFIG_SYS_CLK_FREQ / 1000; + + /* Set Available main memory size */ + pspi->totphys.num_bytes = CONFIG_SYS_PROM_OFFSET - CONFIG_SYS_SDRAM_BASE; + pspi->avail.num_bytes = pspi->totphys.num_bytes; + +#undef nodes + pspi->nodes[3].level = -1; + pspi->nodes[3].properties = __va(spi.root_properties + 3); + + /* Set Ethernet MAC address from environment */ + if ((addr_str = getenv("ethaddr")) != NULL) { + for (i = 0; i < 6; i++) { + pspi->idprom.id_ethaddr[i] = addr_str ? + simple_strtoul(addr_str, &end, 16) : 0; + if (addr_str) { + addr_str = (*end) ? end + 1 : end; + } + } + } else { + /* HW Address not found in environment, + * Set default HW address + */ + pspi->idprom.id_ethaddr[0] = 0; + pspi->idprom.id_ethaddr[1] = 0; + pspi->idprom.id_ethaddr[2] = 0; + pspi->idprom.id_ethaddr[3] = 0; + pspi->idprom.id_ethaddr[4] = 0; + pspi->idprom.id_ethaddr[5] = 0; + } + + ptr = (unsigned char *)&pspi->idprom; + for (i = cksum = 0; i <= 0x0E; i++) + cksum ^= *ptr++; + pspi->idprom.id_cksum = cksum; +} + +static inline void set_cache(unsigned long regval) +{ + asm volatile ("sta %0, [%%g0] %1\n\t":: "r" (regval), "i"(2):"memory"); +} + +extern unsigned short bss_start, bss_end; + +/* mark as section .img.main.text, to be referenced in linker script */ +int prom_init(void) +{ + struct leon_prom_info *pspi = (void *) + ((((unsigned int)&spi) & PROM_SIZE_MASK) + CONFIG_SYS_PROM_OFFSET); + + /* disable mmu */ + srmmu_set_mmureg(0x00000000); + __asm__ __volatile__("flush\n\t"); + + /* init prom info struct */ + leon_prom_init(pspi); + + kernel_arg_promvec = &pspi->romvec; +#ifdef PRINT_ROM_VEC + printf("Kernel rom vec: 0x%lx\n", (unsigned int)(&pspi->romvec)); +#endif + return 0; +} + +/* Copy current kernel boot argument to ROMvec */ +void prepare_bootargs(char *bootargs) +{ + struct leon_prom_info *pspi; + char *src, *dst; + int left; + + /* if no bootargs set, skip copying ==> default bootline */ + if (bootargs && (*bootargs != '\0')) { + pspi = (void *)((((unsigned int)&spi) & PROM_SIZE_MASK) + + CONFIG_SYS_PROM_OFFSET); + src = bootargs; + dst = &pspi->arg[0]; + left = 255; /* max len */ + while (*src && left > 0) { + *dst++ = *src++; + left--; + } + /* terminate kernel command line string */ + *dst = 0; + } +} + +void srmmu_init_cpu(unsigned int entry) +{ + sparc_srmmu_setup *psrmmu_tables = (void *) + ((((unsigned int)&srmmu_tables) & PROM_SIZE_MASK) + + CONFIG_SYS_PROM_OFFSET); + + /* Make context 0 (kernel's context) point + * to our prepared memory mapping + */ +#define PTD 1 + psrmmu_tables->ctx_table[0] = + ((unsigned int)&psrmmu_tables->pgd_table[0x00]) >> 4 | PTD; + + /* Set virtual kernel address 0xf0000000 + * to SRAM/SDRAM address. + * Make it READ/WRITE/EXEC to SuperUser + */ +#define PTE 2 +#define ACC_SU_ALL 0x1c + psrmmu_tables->pgd_table[0xf0] = + (CONFIG_SYS_SDRAM_BASE >> 4) | ACC_SU_ALL | PTE; + psrmmu_tables->pgd_table[0xf1] = + ((CONFIG_SYS_SDRAM_BASE + 0x1000000) >> 4) | ACC_SU_ALL | PTE; + psrmmu_tables->pgd_table[0xf2] = + ((CONFIG_SYS_SDRAM_BASE + 0x2000000) >> 4) | ACC_SU_ALL | PTE; + psrmmu_tables->pgd_table[0xf3] = + ((CONFIG_SYS_SDRAM_BASE + 0x3000000) >> 4) | ACC_SU_ALL | PTE; + psrmmu_tables->pgd_table[0xf4] = + ((CONFIG_SYS_SDRAM_BASE + 0x4000000) >> 4) | ACC_SU_ALL | PTE; + psrmmu_tables->pgd_table[0xf5] = + ((CONFIG_SYS_SDRAM_BASE + 0x5000000) >> 4) | ACC_SU_ALL | PTE; + psrmmu_tables->pgd_table[0xf6] = + ((CONFIG_SYS_SDRAM_BASE + 0x6000000) >> 4) | ACC_SU_ALL | PTE; + psrmmu_tables->pgd_table[0xf7] = + ((CONFIG_SYS_SDRAM_BASE + 0x7000000) >> 4) | ACC_SU_ALL | PTE; + + /* convert rom vec pointer to virtual address */ + kernel_arg_promvec = (struct linux_romvec *) + (((unsigned int)kernel_arg_promvec & 0x0fffffff) | 0xf0000000); + + /* Set Context pointer to point to context table + * 256 contexts supported. + */ + srmmu_set_ctable_ptr((unsigned int)&psrmmu_tables->ctx_table[0]); + + /* Set kernel's context, context zero */ + srmmu_set_context(0); + + /* Invalidate all Cache */ + __asm__ __volatile__("flush\n\t"); + + srmmu_set_mmureg(0x00000001); + leon_flush_tlb_all(); + leon_flush_cache_all(); +} diff --git a/arch/sparc/cpu/leon2/serial.c b/arch/sparc/cpu/leon2/serial.c new file mode 100644 index 0000000..4f41b8e --- /dev/null +++ b/arch/sparc/cpu/leon2/serial.c @@ -0,0 +1,165 @@ +/* GRLIB APBUART Serial controller driver + * + * (C) Copyright 2008 + * Daniel Hellstrom, Gaisler Research, daniel@gaisler.com. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 program is distributed in the hope that 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 <common.h> +#include <asm/processor.h> +#include <asm/leon.h> + +DECLARE_GLOBAL_DATA_PTR; + +/* Force cache miss each time a serial controller reg is read */ +#define CACHE_BYPASS 1 + +#ifdef CACHE_BYPASS +#define READ_BYTE(var) SPARC_NOCACHE_READ_BYTE((unsigned int)&(var)) +#define READ_HWORD(var) SPARC_NOCACHE_READ_HWORD((unsigned int)&(var)) +#define READ_WORD(var) SPARC_NOCACHE_READ((unsigned int)&(var)) +#define READ_DWORD(var) SPARC_NOCACHE_READ_DWORD((unsigned int)&(var)) +#endif + +int serial_init(void) +{ + LEON2_regs *leon2 = (LEON2_regs *) LEON2_PREGS; + LEON2_Uart_regs *regs; + unsigned int tmp; + + /* Init LEON2 UART + * + * Set scaler / baud rate + * + * Receiver & transmitter enable + */ +#if LEON2_CONSOLE_SELECT == LEON_CONSOLE_UART1 + regs = (LEON2_Uart_regs *) & leon2->UART_Channel_1; +#else + regs = (LEON2_Uart_regs *) & leon2->UART_Channel_2; +#endif + + regs->UART_Scaler = CONFIG_SYS_LEON2_UART1_SCALER; + + /* Let bit 11 be unchanged (debug bit for GRMON) */ + tmp = READ_WORD(regs->UART_Control); + + regs->UART_Control = ((tmp & LEON2_UART_CTRL_DBG) | + (LEON2_UART1_LOOPBACK_ENABLE << 7) | + (LEON2_UART1_FLOWCTRL_ENABLE << 6) | + (LEON2_UART1_PARITY_ENABLE << 5) | + (LEON2_UART1_ODDPAR_ENABLE << 4) | + LEON2_UART_CTRL_RE | LEON2_UART_CTRL_TE); + + return 0; +} + +void serial_putc(const char c) +{ + if (c == '\n') + serial_putc_raw('\r'); + + serial_putc_raw(c); +} + +void serial_putc_raw(const char c) +{ + LEON2_regs *leon2 = (LEON2_regs *) LEON2_PREGS; + LEON2_Uart_regs *regs; + +#if LEON2_CONSOLE_SELECT == LEON_CONSOLE_UART1 + regs = (LEON2_Uart_regs *) & leon2->UART_Channel_1; +#else + regs = (LEON2_Uart_regs *) & leon2->UART_Channel_2; +#endif + + /* Wait for last character to go. */ + while (!(READ_WORD(regs->UART_Status) & LEON2_UART_STAT_THE)) ; + + /* Send data */ + regs->UART_Channel = c; + +#ifdef LEON_DEBUG + /* Wait for data to be sent */ + while (!(READ_WORD(regs->UART_Status) & LEON2_UART_STAT_TSE)) ; +#endif +} + +void serial_puts(const char *s) +{ + while (*s) { + serial_putc(*s++); + } +} + +int serial_getc(void) +{ + LEON2_regs *leon2 = (LEON2_regs *) LEON2_PREGS; + LEON2_Uart_regs *regs; + +#if LEON2_CONSOLE_SELECT == LEON_CONSOLE_UART1 + regs = (LEON2_Uart_regs *) & leon2->UART_Channel_1; +#else + regs = (LEON2_Uart_regs *) & leon2->UART_Channel_2; +#endif + + /* Wait for a character to arrive. */ + while (!(READ_WORD(regs->UART_Status) & LEON2_UART_STAT_DR)) ; + + /* read data */ + return READ_WORD(regs->UART_Channel); +} + +int serial_tstc(void) +{ + LEON2_regs *leon2 = (LEON2_regs *) LEON2_PREGS; + LEON2_Uart_regs *regs; + +#if LEON2_CONSOLE_SELECT == LEON_CONSOLE_UART1 + regs = (LEON2_Uart_regs *) & leon2->UART_Channel_1; +#else + regs = (LEON2_Uart_regs *) & leon2->UART_Channel_2; +#endif + + return (READ_WORD(regs->UART_Status) & LEON2_UART_STAT_DR); +} + +/* set baud rate for uart */ +void serial_setbrg(void) +{ + /* update baud rate settings, read it from gd->baudrate */ + unsigned int scaler; + LEON2_regs *leon2 = (LEON2_regs *) LEON2_PREGS; + LEON2_Uart_regs *regs; + +#if LEON2_CONSOLE_SELECT == LEON_CONSOLE_UART1 + regs = (LEON2_Uart_regs *) & leon2->UART_Channel_1; +#else + regs = (LEON2_Uart_regs *) & leon2->UART_Channel_2; +#endif + + if (gd->baudrate > 0) { + scaler = + (((CONFIG_SYS_CLK_FREQ * 10) / (gd->baudrate * 8)) - + 5) / 10; + regs->UART_Scaler = scaler; + } +} diff --git a/arch/sparc/cpu/leon2/start.S b/arch/sparc/cpu/leon2/start.S new file mode 100644 index 0000000..b1f1eb5 --- /dev/null +++ b/arch/sparc/cpu/leon2/start.S @@ -0,0 +1,662 @@ +/* This is where the SPARC/LEON3 starts + * Copyright (C) 2007, + * Daniel Hellstrom, daniel@gaisler.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 program is distributed in the hope that 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 <config.h> +#include <asm/asmmacro.h> +#include <asm/winmacro.h> +#include <asm/psr.h> +#include <asm/stack.h> +#include <asm/leon.h> +#include <timestamp.h> +#include <version.h> + +/* Entry for traps which jump to a programmer-specified trap handler. */ +#define TRAPR(H) \ + wr %g0, 0xfe0, %psr; \ + mov %g0, %tbr; \ + ba (H); \ + mov %g0, %wim; + +#define TRAP(H) \ + mov %psr, %l0; \ + ba (H); \ + nop; nop; + +#define TRAPI(ilevel) \ + mov ilevel, %l7; \ + mov %psr, %l0; \ + b _irq_entry; \ + mov %wim, %l3 + +/* Unexcpected trap will halt the processor by forcing it to error state */ +#undef BAD_TRAP +#define BAD_TRAP ta 0; nop; nop; nop; + +/* Software trap. Treat as BAD_TRAP for the time being... */ +#define SOFT_TRAP TRAP(_hwerr) + +#define PSR_INIT 0x1FC0 /* Disable traps, set s and ps */ +#define WIM_INIT 2 + +/* All traps low-level code here must end with this macro. */ +#define RESTORE_ALL b ret_trap_entry; clr %l6; + +#define WRITE_PAUSE nop;nop;nop + +WINDOWSIZE = (16 * 4) +ARGPUSHSIZE = (6 * 4) +ARGPUSH = (WINDOWSIZE + 4) +MINFRAME = (WINDOWSIZE + ARGPUSHSIZE + 4) + +/* Number of register windows */ +#ifndef CONFIG_SYS_SPARC_NWINDOWS +#error Must define number of SPARC register windows, default is 8 +#endif + +#define STACK_ALIGN 8 +#define SA(X) (((X)+(STACK_ALIGN-1)) & ~(STACK_ALIGN-1)) + + .section ".start", "ax" + .globl _start, start, _trap_table + .globl _irq_entry, nmi_trap + .globl _reset_reloc + +/* at address 0 + * Hardware traps + */ +start: +_start: +_trap_table: + TRAPR(_hardreset); ! 00 reset trap + BAD_TRAP; ! 01 instruction_access_exception + BAD_TRAP; ! 02 illegal_instruction + BAD_TRAP; ! 03 priveleged_instruction + BAD_TRAP; ! 04 fp_disabled + TRAP(_window_overflow); ! 05 window_overflow + TRAP(_window_underflow); ! 06 window_underflow + BAD_TRAP; ! 07 Memory Address Not Aligned + BAD_TRAP; ! 08 Floating Point Exception + BAD_TRAP; ! 09 Data Miss Exception + BAD_TRAP; ! 0a Tagged Instruction Ovrflw + BAD_TRAP; ! 0b Watchpoint Detected + BAD_TRAP; ! 0c + BAD_TRAP; ! 0d + BAD_TRAP; ! 0e + BAD_TRAP; ! 0f + BAD_TRAP; ! 10 + TRAPI(1); ! 11 IRQ level 1 + TRAPI(2); ! 12 IRQ level 2 + TRAPI(3); ! 13 IRQ level 3 + TRAPI(4); ! 14 IRQ level 4 + TRAPI(5); ! 15 IRQ level 5 + TRAPI(6); ! 16 IRQ level 6 + TRAPI(7); ! 17 IRQ level 7 + TRAPI(8); ! 18 IRQ level 8 + TRAPI(9); ! 19 IRQ level 9 + TRAPI(10); ! 1a IRQ level 10 + TRAPI(11); ! 1b IRQ level 11 + TRAPI(12); ! 1c IRQ level 12 + TRAPI(13); ! 1d IRQ level 13 + TRAPI(14); ! 1e IRQ level 14 + TRAP(_nmi_trap); ! 1f IRQ level 15 / + ! NMI (non maskable interrupt) + BAD_TRAP; ! 20 r_register_access_error + BAD_TRAP; ! 21 instruction access error + BAD_TRAP; ! 22 + BAD_TRAP; ! 23 + BAD_TRAP; ! 24 co-processor disabled + BAD_TRAP; ! 25 uniplemented FLUSH + BAD_TRAP; ! 26 + BAD_TRAP; ! 27 + BAD_TRAP; ! 28 co-processor exception + BAD_TRAP; ! 29 data access error + BAD_TRAP; ! 2a division by zero + BAD_TRAP; ! 2b data store error + BAD_TRAP; ! 2c data access MMU miss + BAD_TRAP; ! 2d + BAD_TRAP; ! 2e + BAD_TRAP; ! 2f + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 30-33 + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 34-37 + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 38-3b + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 3c-3f + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 40-43 + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 44-47 + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 48-4b + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 4c-4f + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 50-53 + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 54-57 + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 58-5b + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 5c-5f + + /* implementaion dependent */ + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 60-63 + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 64-67 + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 68-6b + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 6c-6f + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 70-73 + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 74-77 + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 78-7b + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 7c-7f + + /* Software traps, not handled */ + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! 80-83 + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! 84-87 + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! 88-8b + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! 8c-8f + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! 90-93 + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! 94-97 + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! 98-9b + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! 9c-9f + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! a0-a3 + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! a4-a7 + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! a8-ab + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! ac-af + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! b0-b3 + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! b4-b7 + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! b8-bb + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! bc-bf + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! c0-c3 + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! c4-c7 + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! c8-cb + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! cc-cf + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! d0-d3 + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! d4-d7 + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! d8-db + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! dc-df + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! e0-e3 + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! e4-e7 + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! e8-eb + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! ec-ef + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! f0-f3 + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! f4-f7 + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! f8-fb + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! fc-ff +/* + * Version string + */ + + .data + .globl version_string +version_string: + .ascii U_BOOT_VERSION + .ascii " (", U_BOOT_DATE, " - ", U_BOOT_TIME, ")" + .ascii CONFIG_IDENT_STRING, "\0" + + .section ".text" + .align 4 + +_hardreset: +1000: + flush + nop + nop + nop + + /* Init Cache */ + set (LEON2_PREGS+LEON_REG_CACHECTRL_OFFSET), %g1 + set 0x0081000f, %g2 + st %g2, [%g1] + + mov %g0, %y + clr %g1 + clr %g2 + clr %g3 + clr %g4 + clr %g5 + clr %g6 + clr %g7 + + mov %asr17, %g3 + and %g3, 0x1f, %g3 +clear_window: + mov %g0, %l0 + mov %g0, %l1 + mov %g0, %l2 + mov %g0, %l3 + mov %g0, %l4 + mov %g0, %l5 + mov %g0, %l6 + mov %g0, %l7 + mov %g0, %o0 + mov %g0, %o1 + mov %g0, %o2 + mov %g0, %o3 + mov %g0, %o4 + mov %g0, %o5 + mov %g0, %o6 + mov %g0, %o7 + subcc %g3, 1, %g3 + bge clear_window + save + +leon2_init: + /* LEON2 Register Base in g1 */ + set LEON2_PREGS, %g1 + +leon2_init_cache: + /* Set Cache control register */ + set 0x1000f, %g2 + st %g2, [%g1 + 0x14] + +leon2_init_clear: + + /* Clear LEON2 registers */ + st %g0, [%g1 + LEON2_ECTRL] + st %g0, [%g1 + LEON2_IMASK] + st %g0, [%g1 + LEON2_IPEND] + st %g0, [%g1 + LEON2_IFORCE] + st %g0, [%g1 + LEON2_ICLEAR] + st %g0, [%g1 + LEON2_IOREG] + st %g0, [%g1 + LEON2_IODIR] + st %g0, [%g1 + LEON2_IOICONF] + st %g0, [%g1 + LEON2_UCTRL0] + st %g0, [%g1 + LEON2_UCTRL1] + +leon2_init_ioport: + /* I/O port initialization */ + set 0xaa00, %g2 + st %g2, [%g1 + LEON2_IOREG] + +leon2_init_mctrl: + + /* memory config register 1 */ + set CONFIG_SYS_GRLIB_MEMCFG1, %g2 + ld [%g1], %g3 ! + and %g3, 0x300, %g3 + or %g2, %g3, %g2 + st %g2, [%g1 + LEON2_MCFG1] + set CONFIG_SYS_GRLIB_MEMCFG2, %g2 ! Load memory config register 2 +#if !( defined(TSIM) || !defined(BZIMAGE)) + st %g2, [%g1 + LEON2_MCFG2] ! only for prom version, else done by "dumon -i" +#endif + set CONFIG_SYS_GRLIB_MEMCFG3, %g2 ! Init FT register + st %g2, [%g1 + LEON2_ECTRL] + ld [%g1 + LEON2_ECTRL], %g2 + srl %g2, 30, %g2 + andcc %g2, 3, %g6 + bne,a leon2_init_wim + mov %g0, %asr16 ! clear err_reg + +leon2_init_wim: + set WIM_INIT, %g3 + mov %g3, %wim + +leon2_init_psr: + set 0x1000, %g3 + mov %psr, %g2 + wr %g2, %g3, %psr + nop + nop + nop + +leon2_init_stackp: + set CONFIG_SYS_INIT_SP_OFFSET, %fp + andn %fp, 0x0f, %fp + sub %fp, 64, %sp + +cpu_init_unreloc: + call cpu_init_f + nop + +/* un relocated start address of monitor */ +#define TEXT_START _text + +/* un relocated end address of monitor */ +#define DATA_END __init_end + +reloc: + set TEXT_START,%g2 + set DATA_END,%g3 + set CONFIG_SYS_RELOC_MONITOR_BASE,%g4 +reloc_loop: + ldd [%g2],%l0 + ldd [%g2+8],%l2 + std %l0,[%g4] + std %l2,[%g4+8] + inc 16,%g2 + subcc %g3,%g2,%g0 + bne reloc_loop + inc 16,%g4 + + clr %l0 + clr %l1 + clr %l2 + clr %l3 + clr %g2 + +/* register g4 contain address to start + * This means that BSS must be directly after data and code segments + * + * g3 is length of bss = (__bss_end-__bss_start) + * + */ + +clr_bss: +/* clear bss area (the relocated) */ + set __bss_start,%g2 + set __bss_end,%g3 + sub %g3,%g2,%g3 + add %g3,%g4,%g3 + clr %g1 /* std %g0 uses g0 and g1 */ +/* clearing 16byte a time ==> linker script need to align to 16 byte offset */ +clr_bss_16: + std %g0,[%g4] + std %g0,[%g4+8] + inc 16,%g4 + cmp %g3,%g4 + bne clr_bss_16 + nop + +/* add offsets to GOT table */ +fixup_got: + set __got_start,%g4 + set __got_end,%g3 +/* + * new got offset = (old GOT-PTR (read with ld) - + * CONFIG_SYS_RELOC_MONITOR_BASE(from define) ) + + * Destination Address (from define) + */ + set CONFIG_SYS_RELOC_MONITOR_BASE,%g2 + set TEXT_START, %g1 + add %g4,%g2,%g4 + sub %g4,%g1,%g4 + add %g3,%g2,%g3 + sub %g3,%g1,%g3 + sub %g2,%g1,%g2 ! prepare register with (new base address) - + ! (old base address) +got_loop: + ld [%g4],%l0 ! load old GOT-PTR + add %l0,%g2,%l0 ! increase with (new base address) - + ! (old base) + st %l0,[%g4] + inc 4,%g4 + cmp %g3,%g4 + bne got_loop + nop + +prom_relocate: + set __prom_start, %g2 + set __prom_end, %g3 + set CONFIG_SYS_PROM_OFFSET, %g4 + +prom_relocate_loop: + ldd [%g2],%l0 + ldd [%g2+8],%l2 + std %l0,[%g4] + std %l2,[%g4+8] + inc 16,%g2 + subcc %g3,%g2,%g0 + bne prom_relocate_loop + inc 16,%g4 + +/* Trap table has been moved, lets tell CPU about + * the new trap table address + */ + + set CONFIG_SYS_RELOC_MONITOR_BASE, %g2 + wr %g0, %g2, %tbr + +/* call relocate*/ + nop +/* Call relocated init functions */ +jump: + set cpu_init_f2,%o1 + set CONFIG_SYS_RELOC_MONITOR_BASE,%o2 + add %o1,%o2,%o1 + sub %o1,%g1,%o1 + call %o1 + clr %o0 + + set board_init_f,%o1 + set CONFIG_SYS_RELOC_MONITOR_BASE,%o2 + add %o1,%o2,%o1 + sub %o1,%g1,%o1 + call %o1 + clr %o0 + +dead: ta 0 ! if call returns... + nop + +/* Interrupt handler caller, + * reg L7: interrupt number + * reg L0: psr after interrupt + * reg L1: PC + * reg L2: next PC + * reg L3: wim + */ +_irq_entry: + SAVE_ALL + + or %l0, PSR_PIL, %g2 + wr %g2, 0x0, %psr + WRITE_PAUSE + wr %g2, PSR_ET, %psr + WRITE_PAUSE + mov %l7, %o0 ! irq level + set handler_irq, %o1 + set (CONFIG_SYS_RELOC_MONITOR_BASE-TEXT_BASE), %o2 + add %o1, %o2, %o1 + call %o1 + add %sp, SF_REGS_SZ, %o1 ! pt_regs ptr + or %l0, PSR_PIL, %g2 ! restore PIL after handler_irq + wr %g2, PSR_ET, %psr ! keep ET up + WRITE_PAUSE + + RESTORE_ALL + +!Window overflow trap handler. + .global _window_overflow + +_window_overflow: + + mov %wim, %l3 ! Calculate next WIM + mov %g1, %l7 + srl %l3, 1, %g1 + sll %l3, (CONFIG_SYS_SPARC_NWINDOWS-1) , %l4 + or %l4, %g1, %g1 + + save ! Get into window to be saved. + mov %g1, %wim + nop; + nop; + nop + st %l0, [%sp + 0]; + st %l1, [%sp + 4]; + st %l2, [%sp + 8]; + st %l3, [%sp + 12]; + st %l4, [%sp + 16]; + st %l5, [%sp + 20]; + st %l6, [%sp + 24]; + st %l7, [%sp + 28]; + st %i0, [%sp + 32]; + st %i1, [%sp + 36]; + st %i2, [%sp + 40]; + st %i3, [%sp + 44]; + st %i4, [%sp + 48]; + st %i5, [%sp + 52]; + st %i6, [%sp + 56]; + st %i7, [%sp + 60]; + restore ! Go back to trap window. + mov %l7, %g1 + jmp %l1 ! Re-execute save. + rett %l2 + +/* Window underflow trap handler. */ + + .global _window_underflow + +_window_underflow: + + mov %wim, %l3 ! Calculate next WIM + sll %l3, 1, %l4 + srl %l3, (CONFIG_SYS_SPARC_NWINDOWS-1), %l5 + or %l5, %l4, %l5 + mov %l5, %wim + nop; nop; nop + restore ! Two restores to get into the + restore ! window to restore + ld [%sp + 0], %l0; ! Restore window from the stack + ld [%sp + 4], %l1; + ld [%sp + 8], %l2; + ld [%sp + 12], %l3; + ld [%sp + 16], %l4; + ld [%sp + 20], %l5; + ld [%sp + 24], %l6; + ld [%sp + 28], %l7; + ld [%sp + 32], %i0; + ld [%sp + 36], %i1; + ld [%sp + 40], %i2; + ld [%sp + 44], %i3; + ld [%sp + 48], %i4; + ld [%sp + 52], %i5; + ld [%sp + 56], %i6; + ld [%sp + 60], %i7; + save ! Get back to the trap window. + save + jmp %l1 ! Re-execute restore. + rett %l2 + + retl + +_nmi_trap: + nop + jmp %l1 + rett %l2 + +_hwerr: + ta 0 + nop + nop + b _hwerr ! loop infinite + nop + +/* Registers to not touch at all. */ +#define t_psr l0 /* Set by caller */ +#define t_pc l1 /* Set by caller */ +#define t_npc l2 /* Set by caller */ +#define t_wim l3 /* Set by caller */ +#define t_twinmask l4 /* Set at beginning of this entry routine. */ +#define t_kstack l5 /* Set right before pt_regs frame is built */ +#define t_retpc l6 /* If you change this, change winmacro.h header file */ +#define t_systable l7 /* Never touch this, could be the syscall table ptr. */ +#define curptr g6 /* Set after pt_regs frame is built */ + +trap_setup: +/* build a pt_regs trap frame. */ + sub %fp, (SF_REGS_SZ + PT_REGS_SZ), %t_kstack + PT_STORE_ALL(t_kstack, t_psr, t_pc, t_npc, g2) + + /* See if we are in the trap window. */ + mov 1, %t_twinmask + sll %t_twinmask, %t_psr, %t_twinmask ! t_twinmask = (1 << psr) + andcc %t_twinmask, %t_wim, %g0 + beq 1f ! in trap window, clean up + nop + + /*------------------------------------------------- + * Spill , adjust %wim and go. + */ + srl %t_wim, 0x1, %g2 ! begin computation of new %wim + + set (CONFIG_SYS_SPARC_NWINDOWS-1), %g3 !NWINDOWS-1 + + sll %t_wim, %g3, %t_wim ! NWINDOWS-1 + or %t_wim, %g2, %g2 + and %g2, 0xff, %g2 + + save %g0, %g0, %g0 ! get in window to be saved + + /* Set new %wim value */ + wr %g2, 0x0, %wim + + /* Save the kernel window onto the corresponding stack. */ + RW_STORE(sp) + + restore %g0, %g0, %g0 + /*-------------------------------------------------*/ + +1: + /* Trap from kernel with a window available. + * Just do it... + */ + jmpl %t_retpc + 0x8, %g0 ! return to caller + mov %t_kstack, %sp ! jump onto new stack + +#define twin_tmp1 l4 +#define glob_tmp g4 +#define curptr g6 +ret_trap_entry: + wr %t_psr, 0x0, %psr ! enable nesting again, clear ET + + /* Will the rett land us in the invalid window? */ + mov 2, %g1 + sll %g1, %t_psr, %g1 + + set CONFIG_SYS_SPARC_NWINDOWS, %g2 !NWINDOWS + + srl %g1, %g2, %g2 + or %g1, %g2, %g1 + rd %wim, %g2 + andcc %g2, %g1, %g0 + be 1f ! Nope, just return from the trap + sll %g2, 0x1, %g1 + + /* We have to grab a window before returning. */ + set (CONFIG_SYS_SPARC_NWINDOWS-1), %g3 !NWINDOWS-1 + + srl %g2, %g3, %g2 + or %g1, %g2, %g1 + and %g1, 0xff, %g1 + + wr %g1, 0x0, %wim + + /* Grrr, make sure we load from the right %sp... */ + PT_LOAD_ALL(sp, t_psr, t_pc, t_npc, g1) + + restore %g0, %g0, %g0 + RW_LOAD(sp) + b 2f + save %g0, %g0, %g0 + + /* Reload the entire frame in case this is from a + * kernel system call or whatever... + */ +1: + PT_LOAD_ALL(sp, t_psr, t_pc, t_npc, g1) +2: + wr %t_psr, 0x0, %psr + nop; + nop; + nop + + jmp %t_pc + rett %t_npc + +/* This is called from relocated C-code. + * It resets the system by jumping to _start + */ +_reset_reloc: + set start, %l0 + call %l0 + nop diff --git a/arch/sparc/cpu/leon3/Makefile b/arch/sparc/cpu/leon3/Makefile new file mode 100644 index 0000000..182543d --- /dev/null +++ b/arch/sparc/cpu/leon3/Makefile @@ -0,0 +1,54 @@ +# +# (C) Copyright 2003-2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# See file CREDITS for list of people who contributed to this +# project. +# +# 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 program is distributed in the hope that 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 $(TOPDIR)/config.mk + +LIB = $(obj)lib$(CPU).a + +START = start.o +SOBJS = +COBJS = cpu_init.o serial.o cpu.o ambapp.o interrupts.o prom.o usb_uhci.o + +SRCS := $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c) +OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS)) +START := $(addprefix $(obj),$(START)) + +all: $(obj).depend $(START) $(LIB) + +$(LIB): $(OBJS) + $(AR) $(ARFLAGS) $@ $(OBJS) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +$(START): $(START:.o=.S) + $(CC) -D__ASSEMBLY__ $(DBGFLAGS) $(OPTFLAGS) -D__KERNEL__ -DTEXT_BASE=$(TEXT_BASE) \ + -I$(TOPDIR)/include -fno-builtin -ffreestanding -nostdinc -isystem $(gccincdir) -pipe \ + $(PLATFORM_CPPFLAGS) -Wall -Wstrict-prototypes \ + -I$(TOPDIR)/board -c -o $(START) $(START:.o=.S) + +sinclude $(obj).depend + +######################################################################### diff --git a/arch/sparc/cpu/leon3/ambapp.c b/arch/sparc/cpu/leon3/ambapp.c new file mode 100644 index 0000000..efd41ae --- /dev/null +++ b/arch/sparc/cpu/leon3/ambapp.c @@ -0,0 +1,359 @@ +/* Gaisler AMBA Plug&Play bus scanning. Functions + * ending on _nomem is inteded to be used only during + * initialization, only registers are used (no ram). + * + * (C) Copyright 2007 + * Daniel Hellstrom, Gaisler Research, daniel@gaisler.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 program is distributed in the hope that 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 <common.h> +#include <command.h> +#include <ambapp.h> + +#if defined(CONFIG_CMD_AMBAPP) +extern void ambapp_print_apb(apbctrl_pp_dev * apb, + ambapp_ahbdev * apbmst, int index); +extern void ambapp_print_ahb(ahbctrl_pp_dev * ahb, int index); +extern int ambapp_apb_print; +extern int ambapp_ahb_print; +#endif + +static int ambapp_apb_scan(unsigned int vendor, /* Plug&Play Vendor ID */ + unsigned int driver, /* Plug&Play Device ID */ + ambapp_apbdev * dev, /* Result(s) is placed here */ + int index, /* Index of device to start copying Plug&Play + * info into dev + */ + int max_cnt /* Maximal count that dev can hold, if dev + * is NULL function will stop scanning after + * max_cnt devices are found. + */ + ) +{ + int i, cnt = 0; + unsigned int apbmst_base; + ambapp_ahbdev apbmst; + apbctrl_pp_dev *apb; + + if (max_cnt == 0) + return 0; + + /* Get AMBA APB Master */ + if (ambapp_ahbslv_first(VENDOR_GAISLER, GAISLER_APBMST, &apbmst) != 1) { + return 0; + } + + /* Get APB CTRL Plug&Play info area */ + apbmst_base = apbmst.address[0] & LEON3_IO_AREA; + apb = (apbctrl_pp_dev *) (apbmst_base | LEON3_CONF_AREA); + + for (i = 0; i < LEON3_APB_SLAVES; i++) { +#if defined(CONFIG_CMD_AMBAPP) + if (ambapp_apb_print && amba_vendor(apb->conf) + && amba_device(apb->conf)) { + ambapp_print_apb(apb, &apbmst, i); + } +#endif + if ((amba_vendor(apb->conf) == vendor) && + (amba_device(apb->conf) == driver) && ((index < 0) + || (index-- == 0))) { + /* Convert Plug&Play info into a more readable format */ + cnt++; + if (dev) { + dev->irq = amba_irq(apb->conf); + dev->ver = amba_ver(apb->conf); + dev->address = + (apbmst_base | + (((apb-> + bar & 0xfff00000) >> 12))) & (((apb-> + bar & + 0x0000fff0) + << 4) | + 0xfff00000); + dev++; + } + /* found max devices? */ + if (cnt >= max_cnt) + return cnt; + } + /* Get next Plug&Play entry */ + apb++; + } + return cnt; +} + +unsigned int ambapp_apb_next_nomem(register unsigned int vendor, /* Plug&Play Vendor ID */ + register unsigned int driver, /* Plug&Play Device ID */ + register int index) +{ + register int i; + register ahbctrl_pp_dev *apbmst; + register apbctrl_pp_dev *apb; + register unsigned int apbmst_base; + + /* APBMST is a AHB Slave */ + apbmst = ambapp_ahb_next_nomem(VENDOR_GAISLER, GAISLER_APBMST, 1, 0); + if (!apbmst) + return 0; + + apbmst_base = amba_membar_start(apbmst->bars[0]); + if (amba_membar_type(apbmst->bars[0]) == AMBA_TYPE_AHBIO) + apbmst_base = AMBA_TYPE_AHBIO_ADDR(apbmst_base); + apbmst_base &= LEON3_IO_AREA; + + /* Find the vendor/driver device on the first APB bus */ + apb = (apbctrl_pp_dev *) (apbmst_base | LEON3_CONF_AREA); + + for (i = 0; i < LEON3_APB_SLAVES; i++) { + if ((amba_vendor(apb->conf) == vendor) && + (amba_device(apb->conf) == driver) && ((index < 0) + || (index-- == 0))) { + /* Convert Plug&Play info info a more readable format */ + return (apbmst_base | (((apb->bar & 0xfff00000) >> 12))) + & (((apb->bar & 0x0000fff0) << 4) | 0xfff00000); + } + /* Get next Plug&Play entry */ + apb++; + } + return 0; +} + +/****************************** APB SLAVES ******************************/ + +int ambapp_apb_count(unsigned int vendor, unsigned int driver) +{ + return ambapp_apb_scan(vendor, driver, NULL, 0, LEON3_APB_SLAVES); +} + +int ambapp_apb_first(unsigned int vendor, + unsigned int driver, ambapp_apbdev * dev) +{ + return ambapp_apb_scan(vendor, driver, dev, 0, 1); +} + +int ambapp_apb_next(unsigned int vendor, + unsigned int driver, ambapp_apbdev * dev, int index) +{ + return ambapp_apb_scan(vendor, driver, dev, index, 1); +} + +int ambapp_apbs_first(unsigned int vendor, + unsigned int driver, ambapp_apbdev * dev, int max_cnt) +{ + return ambapp_apb_scan(vendor, driver, dev, 0, max_cnt); +} + +enum { + AHB_SCAN_MASTER = 0, + AHB_SCAN_SLAVE = 1 +}; + +/* Scan AMBA Plug&Play bus for AMBA AHB Masters or AHB Slaves + * for a certain matching Vendor and Device ID. + * + * Return number of devices found. + * + * Compact edition... + */ +static int ambapp_ahb_scan(unsigned int vendor, /* Plug&Play Vendor ID */ + unsigned int driver, /* Plug&Play Device ID */ + ambapp_ahbdev * dev, /* Result(s) is placed here */ + int index, /* Index of device to start copying Plug&Play + * info into dev + */ + int max_cnt, /* Maximal count that dev can hold, if dev + * is NULL function will stop scanning after + * max_cnt devices are found. + */ + int type /* Selectes what type of devices to scan. + * 0=AHB Masters + * 1=AHB Slaves + */ + ) +{ + int i, j, cnt = 0, max_pp_devs; + unsigned int addr; + ahbctrl_info *info = (ahbctrl_info *) (LEON3_IO_AREA | LEON3_CONF_AREA); + ahbctrl_pp_dev *ahb; + + if (max_cnt == 0) + return 0; + + if (type == 0) { + max_pp_devs = LEON3_AHB_MASTERS; + ahb = info->masters; + } else { + max_pp_devs = LEON3_AHB_SLAVES; + ahb = info->slaves; + } + + for (i = 0; i < max_pp_devs; i++) { +#if defined(CONFIG_CMD_AMBAPP) + if (ambapp_ahb_print && amba_vendor(ahb->conf) && + amba_device(ahb->conf)) { + ambapp_print_ahb(ahb, i); + } +#endif + if ((amba_vendor(ahb->conf) == vendor) && + (amba_device(ahb->conf) == driver) && + ((index < 0) || (index-- == 0))) { + /* Convert Plug&Play info info a more readable format */ + cnt++; + if (dev) { + dev->irq = amba_irq(ahb->conf); + dev->ver = amba_ver(ahb->conf); + dev->userdef[0] = ahb->userdef[0]; + dev->userdef[1] = ahb->userdef[1]; + dev->userdef[2] = ahb->userdef[2]; + for (j = 0; j < 4; j++) { + addr = amba_membar_start(ahb->bars[j]); + if (amba_membar_type(ahb->bars[j]) == + AMBA_TYPE_AHBIO) + addr = + AMBA_TYPE_AHBIO_ADDR(addr); + dev->address[j] = addr; + } + dev++; + } + /* found max devices? */ + if (cnt >= max_cnt) + return cnt; + } + /* Get next Plug&Play entry */ + ahb++; + } + return cnt; +} + +unsigned int ambapp_ahb_get_info(ahbctrl_pp_dev * ahb, int info) +{ + register unsigned int ret; + + if (!ahb) + return 0; + + switch (info) { + default: + info = 0; + case 0: + case 1: + case 2: + case 3: + /* Get Address from PnP Info */ + ret = amba_membar_start(ahb->bars[info]); + if (amba_membar_type(ahb->bars[info]) == AMBA_TYPE_AHBIO) + ret = AMBA_TYPE_AHBIO_ADDR(ret); + return ret; + } + return 0; + +} + +ahbctrl_pp_dev *ambapp_ahb_next_nomem(register unsigned int vendor, /* Plug&Play Vendor ID */ + register unsigned int driver, /* Plug&Play Device ID */ + register unsigned int opts, /* 1=slave, 0=master */ + register int index) +{ + register ahbctrl_pp_dev *ahb; + register ahbctrl_info *info = + (ahbctrl_info *) (LEON3_IO_AREA | LEON3_CONF_AREA); + register int i; + register int max_pp_devs; + + if (opts == 0) { + max_pp_devs = LEON3_AHB_MASTERS; + ahb = info->masters; + } else { + max_pp_devs = LEON3_AHB_SLAVES; + ahb = info->slaves; + } + + for (i = 0; i < max_pp_devs; i++) { + if ((amba_vendor(ahb->conf) == vendor) && + (amba_device(ahb->conf) == driver) && + ((index < 0) || (index-- == 0))) { + /* Convert Plug&Play info info a more readable format */ + return ahb; + } + /* Get next Plug&Play entry */ + ahb++; + } + return 0; +} + +/****************************** AHB MASTERS ******************************/ +int ambapp_ahbmst_count(unsigned int vendor, unsigned int driver) +{ + /* Get number of devices of this vendor&device ID */ + return ambapp_ahb_scan(vendor, driver, NULL, 0, LEON3_AHB_MASTERS, + AHB_SCAN_MASTER); +} + +int ambapp_ahbmst_first(unsigned int vendor, unsigned int driver, + ambapp_ahbdev * dev) +{ + /* find first device of this */ + return ambapp_ahb_scan(vendor, driver, dev, 0, 1, AHB_SCAN_MASTER); +} + +int ambapp_ahbmst_next(unsigned int vendor, + unsigned int driver, ambapp_ahbdev * dev, int index) +{ + /* find first device of this */ + return ambapp_ahb_scan(vendor, driver, dev, index, 1, AHB_SCAN_MASTER); +} + +int ambapp_ahbmsts_first(unsigned int vendor, + unsigned int driver, ambapp_ahbdev * dev, int max_cnt) +{ + /* find first device of this */ + return ambapp_ahb_scan(vendor, driver, dev, 0, max_cnt, + AHB_SCAN_MASTER); +} + +/****************************** AHB SLAVES ******************************/ +int ambapp_ahbslv_count(unsigned int vendor, unsigned int driver) +{ + /* Get number of devices of this vendor&device ID */ + return ambapp_ahb_scan(vendor, driver, NULL, 0, LEON3_AHB_SLAVES, + AHB_SCAN_SLAVE); +} + +int ambapp_ahbslv_first(unsigned int vendor, unsigned int driver, + ambapp_ahbdev * dev) +{ + /* find first device of this */ + return ambapp_ahb_scan(vendor, driver, dev, 0, 1, AHB_SCAN_SLAVE); +} + +int ambapp_ahbslv_next(unsigned int vendor, + unsigned int driver, ambapp_ahbdev * dev, int index) +{ + /* find first device of this */ + return ambapp_ahb_scan(vendor, driver, dev, index, 1, AHB_SCAN_SLAVE); +} + +int ambapp_ahbslvs_first(unsigned int vendor, + unsigned int driver, ambapp_ahbdev * dev, int max_cnt) +{ + /* find first device of this */ + return ambapp_ahb_scan(vendor, driver, dev, 0, max_cnt, AHB_SCAN_SLAVE); +} diff --git a/arch/sparc/cpu/leon3/config.mk b/arch/sparc/cpu/leon3/config.mk new file mode 100644 index 0000000..30b224a --- /dev/null +++ b/arch/sparc/cpu/leon3/config.mk @@ -0,0 +1,26 @@ +# +# (C) Copyright 2003 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# See file CREDITS for list of people who contributed to this +# project. +# +# 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 program is distributed in the hope that 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 +# + +PLATFORM_RELFLAGS += -fPIC + +PLATFORM_CPPFLAGS += -DCONFIG_LEON diff --git a/arch/sparc/cpu/leon3/cpu.c b/arch/sparc/cpu/leon3/cpu.c new file mode 100644 index 0000000..976f311 --- /dev/null +++ b/arch/sparc/cpu/leon3/cpu.c @@ -0,0 +1,75 @@ +/* CPU specific code for the LEON3 CPU + * + * (C) Copyright 2007 + * Daniel Hellstrom, Gaisler Research, daniel@gaisler.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 program is distributed in the hope that 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 <common.h> +#include <watchdog.h> +#include <command.h> +#include <netdev.h> + +#include <asm/io.h> +#include <asm/processor.h> + +DECLARE_GLOBAL_DATA_PTR; + +extern void _reset_reloc(void); + +int checkcpu(void) +{ + /* check LEON version here */ + printf("CPU: LEON3\n"); + return 0; +} + +/* ------------------------------------------------------------------------- */ + +void cpu_reset(void) +{ + /* Interrupts off */ + disable_interrupts(); + + /* jump to restart in flash */ + _reset_reloc(); +} + +int do_reset(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) +{ + cpu_reset(); + + return 1; + +} + +u64 flash_read64(void *addr) +{ + return __raw_readq(addr); +} + +/* ------------------------------------------------------------------------- */ + +#ifdef CONFIG_GRETH +int cpu_eth_init(bd_t *bis) +{ + return greth_initialize(bis); +} +#endif diff --git a/arch/sparc/cpu/leon3/cpu_init.c b/arch/sparc/cpu/leon3/cpu_init.c new file mode 100644 index 0000000..be22ec2 --- /dev/null +++ b/arch/sparc/cpu/leon3/cpu_init.c @@ -0,0 +1,254 @@ +/* Initializes CPU and basic hardware such as memory + * controllers, IRQ controller and system timer 0. + * + * (C) Copyright 2007 + * Daniel Hellstrom, Gaisler Research, daniel@gaisler.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 program is distributed in the hope that 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 <common.h> +#include <asm/asi.h> +#include <asm/leon.h> +#include <ambapp.h> + +#include <config.h> + +DECLARE_GLOBAL_DATA_PTR; + +/* reset CPU (jump to 0, without reset) */ +void start(void); + +/* find & initialize the memory controller */ +int init_memory_ctrl(void); + +ambapp_dev_irqmp *irqmp = NULL; +ambapp_dev_mctrl memctrl; +ambapp_dev_gptimer *gptimer = NULL; +unsigned int gptimer_irq = 0; +int leon3_snooping_avail = 0; + +struct { + gd_t gd_area; + bd_t bd; +} global_data; + +/* + * Breath some life into the CPU... + * + * Set up the memory map, + * initialize a bunch of registers. + * + * Run from FLASH/PROM: + * - until memory controller is set up, only registers avaiable + * - no global variables available for writing + * - constants avaiable + */ + +void cpu_init_f(void) +{ + /* these varaiable must not be initialized */ + ambapp_dev_irqmp *irqmp; + ambapp_apbdev apbdev; + register unsigned int apbmst; + + /* find AMBA APB Master */ + apbmst = (unsigned int) + ambapp_ahb_next_nomem(VENDOR_GAISLER, GAISLER_APBMST, 1, 0); + if (!apbmst) { + /* + * no AHB/APB bridge, something is wrong + * ==> jump to start (or hang) + */ + while (1) ; + } + /* Init memory controller */ + if (init_memory_ctrl()) { + while (1) ; + } + + /**************************************************** + * From here we can use the main memory and the stack. + */ + + /* Find AMBA APB IRQMP Controller */ + if (ambapp_apb_first(VENDOR_GAISLER, GAISLER_IRQMP, &apbdev) != 1) { + /* no IRQ controller, something is wrong + * ==> jump to start (or hang) + */ + while (1) ; + } + irqmp = (ambapp_dev_irqmp *) apbdev.address; + + /* initialize the IRQMP */ + irqmp->ilevel = 0xf; /* all IRQ off */ + irqmp->iforce = 0; + irqmp->ipend = 0; + irqmp->iclear = 0xfffe; /* clear all old pending interrupts */ + irqmp->cpu_mask[0] = 0; /* mask all IRQs on CPU 0 */ + irqmp->cpu_force[0] = 0; /* no force IRQ on CPU 0 */ + + /* cache */ +} + +void cpu_init_f2(void) +{ + +} + +/* + * initialize higher level parts of CPU like time base and timers + */ +int cpu_init_r(void) +{ + ambapp_apbdev apbdev; + + /* + * Find AMBA APB IRQMP Controller, + * When we come so far we know there is a IRQMP available + */ + ambapp_apb_first(VENDOR_GAISLER, GAISLER_IRQMP, &apbdev); + irqmp = (ambapp_dev_irqmp *) apbdev.address; + + /* timer */ + if (ambapp_apb_first(VENDOR_GAISLER, GAISLER_GPTIMER, &apbdev) != 1) { + printf("cpu_init_r: gptimer not found!\n"); + return 1; + } + gptimer = (ambapp_dev_gptimer *) apbdev.address; + gptimer_irq = apbdev.irq; + + /* initialize prescaler common to all timers to 1MHz */ + gptimer->scalar = gptimer->scalar_reload = + (((CONFIG_SYS_CLK_FREQ / 1000) + 500) / 1000) - 1; + + return (0); +} + +/* find & setup memory controller */ +int init_memory_ctrl() +{ + register ambapp_dev_mctrl *mctrl; + register ambapp_dev_sdctrl *sdctrl; + register ambapp_dev_ddrspa *ddrspa; + register ambapp_dev_ddr2spa *ddr2spa; + register ahbctrl_pp_dev *ahb; + register unsigned int base; + register int not_found_mctrl = -1; + + /* find ESA Memory controller */ + base = ambapp_apb_next_nomem(VENDOR_ESA, ESA_MCTRL, 0); + if (base) { + mctrl = (ambapp_dev_mctrl *) base; + + /* config MCTRL memory controller */ + mctrl->mcfg1 = CONFIG_SYS_GRLIB_MEMCFG1 | (mctrl->mcfg1 & 0x300); + mctrl->mcfg2 = CONFIG_SYS_GRLIB_MEMCFG2; + mctrl->mcfg3 = CONFIG_SYS_GRLIB_MEMCFG3; + not_found_mctrl = 0; + } + + /* find Gaisler Fault Tolerant Memory controller */ + base = ambapp_apb_next_nomem(VENDOR_GAISLER, GAISLER_FTMCTRL, 0); + if (base) { + mctrl = (ambapp_dev_mctrl *) base; + + /* config MCTRL memory controller */ + mctrl->mcfg1 = CONFIG_SYS_GRLIB_FT_MEMCFG1 | (mctrl->mcfg1 & 0x300); + mctrl->mcfg2 = CONFIG_SYS_GRLIB_FT_MEMCFG2; + mctrl->mcfg3 = CONFIG_SYS_GRLIB_FT_MEMCFG3; + not_found_mctrl = 0; + } + + /* find SDRAM controller */ + base = ambapp_apb_next_nomem(VENDOR_GAISLER, GAISLER_SDCTRL, 0); + if (base) { + sdctrl = (ambapp_dev_sdctrl *) base; + + /* config memory controller */ + sdctrl->sdcfg = CONFIG_SYS_GRLIB_SDRAM; + not_found_mctrl = 0; + } + + ahb = ambapp_ahb_next_nomem(VENDOR_GAISLER, GAISLER_DDR2SPA, 1, 0); + if (ahb) { + ddr2spa = (ambapp_dev_ddr2spa *) ambapp_ahb_get_info(ahb, 1); + + /* Config DDR2 memory controller */ + ddr2spa->cfg1 = CONFIG_SYS_GRLIB_DDR2_CFG1; + ddr2spa->cfg3 = CONFIG_SYS_GRLIB_DDR2_CFG3; + not_found_mctrl = 0; + } + + ahb = ambapp_ahb_next_nomem(VENDOR_GAISLER, GAISLER_DDRSPA, 1, 0); + if (ahb) { + ddrspa = (ambapp_dev_ddrspa *) ambapp_ahb_get_info(ahb, 1); + + /* Config DDR memory controller */ + ddrspa->ctrl = CONFIG_SYS_GRLIB_DDR_CFG; + not_found_mctrl = 0; + } + + /* failed to find any memory controller */ + return not_found_mctrl; +} + +/* Uses Timer 0 to get accurate + * pauses. Max 2 raised to 32 ticks + * + */ +void cpu_wait_ticks(unsigned long ticks) +{ + unsigned long start = get_timer(0); + while (get_timer(start) < ticks) ; +} + +/* initiate and setup timer0 interrupt to 1MHz + * Return irq number for timer int or a negative number for + * dealing with self + */ +int timer_interrupt_init_cpu(void) +{ + /* 1ms ticks */ + gptimer->e[0].val = 0; + gptimer->e[0].rld = 999; /* (((1000000 / 100) - 1)) */ + gptimer->e[0].ctrl = + (LEON3_GPTIMER_EN | + LEON3_GPTIMER_RL | LEON3_GPTIMER_LD | LEON3_GPTIMER_IRQEN); + + return gptimer_irq; +} + +/* + * This function is intended for SHORT delays only. + */ +unsigned long cpu_usec2ticks(unsigned long usec) +{ + /* timer set to 1kHz ==> 1 clk tick = 1 msec */ + if (usec < 1000) + return 1; + return (usec / 1000); +} + +unsigned long cpu_ticks2usec(unsigned long ticks) +{ + /* 1tick = 1usec */ + return ticks * 1000; +} diff --git a/arch/sparc/cpu/leon3/interrupts.c b/arch/sparc/cpu/leon3/interrupts.c new file mode 100644 index 0000000..ac6aca5 --- /dev/null +++ b/arch/sparc/cpu/leon3/interrupts.c @@ -0,0 +1,219 @@ +/* + * (C) Copyright 2007 + * Daniel Hellstrom, Gaisler Research, daniel@gaisler.com + * + * (C) Copyright 2006 + * Detlev Zundel, DENX Software Engineering, dzu@denx.de + * + * (C) Copyright -2003 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * (C) Copyright 2001 + * Josh Huber <huber@mclx.com>, Mission Critical Linux, Inc. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 program is distributed in the hope that 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 <asm/stack.h> +#include <common.h> +#include <asm/io.h> +#include <asm/processor.h> +#include <command.h> +#include <asm/irq.h> + +#include <asm/leon.h> +#include <ambapp.h> + +/* 15 normal irqs and a non maskable interrupt */ +#define NR_IRQS 15 + +struct irq_action { + interrupt_handler_t *handler; + void *arg; + unsigned int count; +}; + +extern ambapp_dev_irqmp *irqmp; +extern ambapp_dev_gptimer *gptimer; + +static struct irq_action irq_handlers[NR_IRQS] = { {0}, }; +static int spurious_irq_cnt = 0; +static int spurious_irq = 0; + +static inline unsigned int irqmp_get_irqmask(unsigned int irq) +{ + if ((irq < 0) || (irq >= NR_IRQS)) { + return 0; + } else { + return (1 << irq); + } + +} + +static void leon3_ic_disable(unsigned int irq) +{ + unsigned int mask, pil; + if (!irqmp) + return; + + pil = intLock(); + + /* get mask of interrupt */ + mask = irqmp_get_irqmask(irq); + + /* set int level */ + irqmp->cpu_mask[0] = SPARC_NOCACHE_READ(&irqmp->cpu_mask[0]) & (~mask); + + intUnlock(pil); +} + +static void leon3_ic_enable(unsigned int irq) +{ + unsigned int mask, pil; + if (!irqmp) + return; + + pil = intLock(); + + /* get mask of interrupt */ + mask = irqmp_get_irqmask(irq); + + /* set int level */ + irqmp->cpu_mask[0] = SPARC_NOCACHE_READ(&irqmp->cpu_mask[0]) | mask; + + intUnlock(pil); + +} + +void handler_irq(int irq, struct pt_regs *regs) +{ + if (irq_handlers[irq].handler) { + if (((unsigned int)irq_handlers[irq].handler > CONFIG_SYS_RAM_END) || + ((unsigned int)irq_handlers[irq].handler < CONFIG_SYS_RAM_BASE) + ) { + printf("handler_irq: bad handler: %x, irq number %d\n", + (unsigned int)irq_handlers[irq].handler, irq); + return; + } + irq_handlers[irq].handler(irq_handlers[irq].arg); + irq_handlers[irq].count++; + } else { + spurious_irq_cnt++; + spurious_irq = irq; + } +} + +void leon3_force_int(int irq) +{ + if (!irqmp || (irq >= NR_IRQS) || (irq < 0)) + return; + printf("Forcing interrupt %d\n", irq); + + irqmp->iforce = SPARC_NOCACHE_READ(&irqmp->iforce) | (1 << irq); +} + +/****************************************************************************/ + +int interrupt_init_cpu(void) +{ + + return (0); +} + +/****************************************************************************/ + +/* Handle Timer 0 IRQ */ +void timer_interrupt_cpu(void *arg) +{ + gptimer->e[0].ctrl = (LEON3_GPTIMER_EN | + LEON3_GPTIMER_RL | + LEON3_GPTIMER_LD | LEON3_GPTIMER_IRQEN); + /* nothing to do here */ + return; +} + +/****************************************************************************/ + +/* + * Install and free a interrupt handler. + */ + +void irq_install_handler(int irq, interrupt_handler_t * handler, void *arg) +{ + if (irq < 0 || irq >= NR_IRQS) { + printf("irq_install_handler: bad irq number %d\n", irq); + return; + } + + if (irq_handlers[irq].handler != NULL) + printf("irq_install_handler: 0x%08lx replacing 0x%08lx\n", + (ulong) handler, (ulong) irq_handlers[irq].handler); + + if (((unsigned int)handler > CONFIG_SYS_RAM_END) || + ((unsigned int)handler < CONFIG_SYS_RAM_BASE) + ) { + printf("irq_install_handler: bad handler: %x, irq number %d\n", + (unsigned int)handler, irq); + return; + } + irq_handlers[irq].handler = handler; + irq_handlers[irq].arg = arg; + + /* enable irq on IRQMP hardware */ + leon3_ic_enable(irq); + +} + +void irq_free_handler(int irq) +{ + if (irq < 0 || irq >= NR_IRQS) { + printf("irq_free_handler: bad irq number %d\n", irq); + return; + } + + /* disable irq on IRQMP hardware */ + leon3_ic_disable(irq); + + irq_handlers[irq].handler = NULL; + irq_handlers[irq].arg = NULL; +} + +/****************************************************************************/ + +#if defined(CONFIG_CMD_IRQ) +void do_irqinfo(cmd_tbl_t * cmdtp, bd_t * bd, int flag, int argc, char *argv[]) +{ + int irq; + unsigned int pil = get_pil(); + printf("PIL level: %u\n\r", pil); + printf("Spurious IRQ: %u, last unknown IRQ: %d\n", + spurious_irq_cnt, spurious_irq); + + puts("\nInterrupt-Information:\n" "Nr Routine Arg Count\n"); + + for (irq = 0; irq < NR_IRQS; irq++) { + if (irq_handlers[irq].handler != NULL) { + printf("%02d %08lx %08lx %ld\n", irq, + (unsigned int)irq_handlers[irq].handler, + (unsigned int)irq_handlers[irq].arg, + irq_handlers[irq].count); + } + } +} +#endif diff --git a/arch/sparc/cpu/leon3/prom.c b/arch/sparc/cpu/leon3/prom.c new file mode 100644 index 0000000..18d2fb2 --- /dev/null +++ b/arch/sparc/cpu/leon3/prom.c @@ -0,0 +1,1078 @@ +/* prom.c - emulates a sparc v0 PROM for the linux kernel. + * + * Copyright (C) 2003 Konrad Eisele <eiselekd@web.de> + * Copyright (C) 2004 Stefan Holst <mail@s-holst.de> + * Copyright (C) 2007 Daniel Hellstrom <daniel@gaisler.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 program is distributed in the hope that 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 <common.h> +#include <asm/prom.h> +#include <asm/machines.h> +#include <asm/srmmu.h> +#include <asm/processor.h> +#include <asm/irq.h> +#include <asm/leon.h> +#include <ambapp.h> + +#include <config.h> +/* +#define PRINT_ROM_VEC +*/ +extern struct linux_romvec *kernel_arg_promvec; +extern ambapp_dev_apbuart *leon3_apbuart; + +#define PROM_PGT __attribute__ ((__section__ (".prom.pgt"))) +#define PROM_TEXT __attribute__ ((__section__ (".prom.text"))) +#define PROM_DATA __attribute__ ((__section__ (".prom.data"))) + +ambapp_dev_gptimer *gptimer; + +/* for __va */ +extern int __prom_start; +#define PAGE_OFFSET 0xf0000000 +#define phys_base CONFIG_SYS_SDRAM_BASE +#define PROM_OFFS 8192 +#define PROM_SIZE_MASK (PROM_OFFS-1) +#define __va(x) ( \ + (void *)( ((unsigned long)(x))-PROM_OFFS+ \ + (CONFIG_SYS_PROM_OFFSET-phys_base)+PAGE_OFFSET-TEXT_BASE ) \ + ) +#define __phy(x) ((void *)(((unsigned long)(x))-PROM_OFFS+CONFIG_SYS_PROM_OFFSET-TEXT_BASE)) + +struct property { + char *name; + char *value; + int length; +}; + +struct node { + int level; + struct property *properties; +}; + +static void leon_reboot(char *bcommand); +static void leon_halt(void); +static int leon_nbputchar(int c); +static int leon_nbgetchar(void); + +static int no_nextnode(int node); +static int no_child(int node); +static int no_proplen(int node, char *name); +static int no_getprop(int node, char *name, char *value); +static int no_setprop(int node, char *name, char *value, int len); +static char *no_nextprop(int node, char *name); + +static struct property PROM_TEXT *find_property(int node, char *name); +static int PROM_TEXT leon_strcmp(const char *s1, const char *s2); +static void *PROM_TEXT leon_memcpy(void *dest, const void *src, size_t n); +static void PROM_TEXT leon_reboot_physical(char *bcommand); + +void __inline__ leon_flush_cache_all(void) +{ + __asm__ __volatile__(" flush "); + __asm__ __volatile__("sta %%g0, [%%g0] %0\n\t"::"i"(ASI_DFLUSH):"memory"); +} + +void __inline__ leon_flush_tlb_all(void) +{ + leon_flush_cache_all(); + __asm__ __volatile__("sta %%g0, [%0] %1\n\t"::"r"(0x400), + "i"(ASI_MMUFLUSH):"memory"); +} + +typedef struct { + unsigned int ctx_table[256]; + unsigned int pgd_table[256]; +} sparc_srmmu_setup; + +sparc_srmmu_setup srmmu_tables PROM_PGT = { + {0}, + {0x1e, + 0x10001e, + 0x20001e, + 0x30001e, + 0x40001e, + 0x50001e, + 0x60001e, + 0x70001e, + 0x80001e, + 0x90001e, + 0xa0001e, + 0xb0001e, + 0xc0001e, + 0xd0001e, + 0xe0001e, + 0xf0001e, + 0x100001e, + 0x110001e, + 0x120001e, + 0x130001e, + 0x140001e, + 0x150001e, + 0x160001e, + 0x170001e, + 0x180001e, + 0x190001e, + 0x1a0001e, + 0x1b0001e, + 0x1c0001e, + 0x1d0001e, + 0x1e0001e, + 0x1f0001e, + 0x200001e, + 0x210001e, + 0x220001e, + 0x230001e, + 0x240001e, + 0x250001e, + 0x260001e, + 0x270001e, + 0x280001e, + 0x290001e, + 0x2a0001e, + 0x2b0001e, + 0x2c0001e, + 0x2d0001e, + 0x2e0001e, + 0x2f0001e, + 0x300001e, + 0x310001e, + 0x320001e, + 0x330001e, + 0x340001e, + 0x350001e, + 0x360001e, + 0x370001e, + 0x380001e, + 0x390001e, + 0x3a0001e, + 0x3b0001e, + 0x3c0001e, + 0x3d0001e, + 0x3e0001e, + 0x3f0001e, + 0x400001e, + 0x410001e, + 0x420001e, + 0x430001e, + 0x440001e, + 0x450001e, + 0x460001e, + 0x470001e, + 0x480001e, + 0x490001e, + 0x4a0001e, + 0x4b0001e, + 0x4c0001e, + 0x4d0001e, + 0x4e0001e, + 0x4f0001e, + 0x500001e, + 0x510001e, + 0x520001e, + 0x530001e, + 0x540001e, + 0x550001e, + 0x560001e, + 0x570001e, + 0x580001e, + 0x590001e, + 0x5a0001e, + 0x5b0001e, + 0x5c0001e, + 0x5d0001e, + 0x5e0001e, + 0x5f0001e, + 0x600001e, + 0x610001e, + 0x620001e, + 0x630001e, + 0x640001e, + 0x650001e, + 0x660001e, + 0x670001e, + 0x680001e, + 0x690001e, + 0x6a0001e, + 0x6b0001e, + 0x6c0001e, + 0x6d0001e, + 0x6e0001e, + 0x6f0001e, + 0x700001e, + 0x710001e, + 0x720001e, + 0x730001e, + 0x740001e, + 0x750001e, + 0x760001e, + 0x770001e, + 0x780001e, + 0x790001e, + 0x7a0001e, + 0x7b0001e, + 0x7c0001e, + 0x7d0001e, + 0x7e0001e, + 0x7f0001e, + 0x800001e, + 0x810001e, + 0x820001e, + 0x830001e, + 0x840001e, + 0x850001e, + 0x860001e, + 0x870001e, + 0x880001e, + 0x890001e, + 0x8a0001e, + 0x8b0001e, + 0x8c0001e, + 0x8d0001e, + 0x8e0001e, + 0x8f0001e, + 0x900001e, + 0x910001e, + 0x920001e, + 0x930001e, + 0x940001e, + 0x950001e, + 0x960001e, + 0x970001e, + 0x980001e, + 0x990001e, + 0x9a0001e, + 0x9b0001e, + 0x9c0001e, + 0x9d0001e, + 0x9e0001e, + 0x9f0001e, + 0xa00001e, + 0xa10001e, + 0xa20001e, + 0xa30001e, + 0xa40001e, + 0xa50001e, + 0xa60001e, + 0xa70001e, + 0xa80001e, + 0xa90001e, + 0xaa0001e, + 0xab0001e, + 0xac0001e, + 0xad0001e, + 0xae0001e, + 0xaf0001e, + 0xb00001e, + 0xb10001e, + 0xb20001e, + 0xb30001e, + 0xb40001e, + 0xb50001e, + 0xb60001e, + 0xb70001e, + 0xb80001e, + 0xb90001e, + 0xba0001e, + 0xbb0001e, + 0xbc0001e, + 0xbd0001e, + 0xbe0001e, + 0xbf0001e, + 0xc00001e, + 0xc10001e, + 0xc20001e, + 0xc30001e, + 0xc40001e, + 0xc50001e, + 0xc60001e, + 0xc70001e, + 0xc80001e, + 0xc90001e, + 0xca0001e, + 0xcb0001e, + 0xcc0001e, + 0xcd0001e, + 0xce0001e, + 0xcf0001e, + 0xd00001e, + 0xd10001e, + 0xd20001e, + 0xd30001e, + 0xd40001e, + 0xd50001e, + 0xd60001e, + 0xd70001e, + 0xd80001e, + 0xd90001e, + 0xda0001e, + 0xdb0001e, + 0xdc0001e, + 0xdd0001e, + 0xde0001e, + 0xdf0001e, + 0xe00001e, + 0xe10001e, + 0xe20001e, + 0xe30001e, + 0xe40001e, + 0xe50001e, + 0xe60001e, + 0xe70001e, + 0xe80001e, + 0xe90001e, + 0xea0001e, + 0xeb0001e, + 0xec0001e, + 0xed0001e, + 0xee0001e, + 0xef0001e, + 0x400001e /* default */ + } +}; + +/* a self contained prom info structure */ +struct leon_reloc_func { + struct property *(*find_property) (int node, char *name); + int (*strcmp) (char *s1, char *s2); + void *(*memcpy) (void *dest, const void *src, size_t n); + void (*reboot_physical) (char *cmd); + ambapp_dev_apbuart *leon3_apbuart; +}; + +struct leon_prom_info { + int freq_khz; + int leon_nctx; + int mids[32]; + int baudrates[2]; + struct leon_reloc_func reloc_funcs; + struct property root_properties[4]; + struct property cpu_properties[7]; +#undef CPUENTRY +#define CPUENTRY(idx) struct property cpu_properties##idx[4] + CPUENTRY(1); + CPUENTRY(2); + CPUENTRY(3); + CPUENTRY(4); + CPUENTRY(5); + CPUENTRY(6); + CPUENTRY(7); + CPUENTRY(8); + CPUENTRY(9); + CPUENTRY(10); + CPUENTRY(11); + CPUENTRY(12); + CPUENTRY(13); + CPUENTRY(14); + CPUENTRY(15); + CPUENTRY(16); + CPUENTRY(17); + CPUENTRY(18); + CPUENTRY(19); + CPUENTRY(20); + CPUENTRY(21); + CPUENTRY(22); + CPUENTRY(23); + CPUENTRY(24); + CPUENTRY(25); + CPUENTRY(26); + CPUENTRY(27); + CPUENTRY(28); + CPUENTRY(29); + CPUENTRY(30); + CPUENTRY(31); + struct idprom idprom; + struct linux_nodeops nodeops; + struct linux_mlist_v0 *totphys_p; + struct linux_mlist_v0 totphys; + struct linux_mlist_v0 *avail_p; + struct linux_mlist_v0 avail; + struct linux_mlist_v0 *prommap_p; + void (*synchook) (void); + struct linux_arguments_v0 *bootargs_p; + struct linux_arguments_v0 bootargs; + struct linux_romvec romvec; + struct node nodes[35]; + char s_device_type[12]; + char s_cpu[4]; + char s_mid[4]; + char s_idprom[7]; + char s_compatability[14]; + char s_leon2[6]; + char s_mmu_nctx[9]; + char s_frequency[16]; + char s_uart1_baud[11]; + char s_uart2_baud[11]; + char arg[256]; +}; + +/* static prom info */ +static struct leon_prom_info PROM_DATA spi = { + CONFIG_SYS_CLK_FREQ / 1000, + 256, + { +#undef CPUENTRY +#define CPUENTRY(idx) idx + CPUENTRY(0), + CPUENTRY(1), + CPUENTRY(2), + CPUENTRY(3), + CPUENTRY(4), + CPUENTRY(5), + CPUENTRY(6), + CPUENTRY(7), + CPUENTRY(8), + CPUENTRY(9), + CPUENTRY(10), + CPUENTRY(11), + CPUENTRY(12), + CPUENTRY(13), + CPUENTRY(14), + CPUENTRY(15), + CPUENTRY(16), + CPUENTRY(17), + CPUENTRY(18), + CPUENTRY(19), + CPUENTRY(20), + CPUENTRY(21), + CPUENTRY(22), + CPUENTRY(23), + CPUENTRY(24), + CPUENTRY(25), + CPUENTRY(26), + CPUENTRY(27), + CPUENTRY(28), + CPUENTRY(29), + CPUENTRY(30), + 31}, + {38400, 38400}, + { + __va(find_property), + __va(leon_strcmp), + __va(leon_memcpy), + __phy(leon_reboot_physical), + }, + { + {__va(spi.s_device_type), __va(spi.s_idprom), 4}, + {__va(spi.s_idprom), (char *)__va(&spi.idprom), sizeof(struct idprom)}, + {__va(spi.s_compatability), __va(spi.s_leon2), 5}, + {NULL, NULL, -1} + }, + { + {__va(spi.s_device_type), __va(spi.s_cpu), 4}, + {__va(spi.s_mid), __va(&spi.mids[0]), 4}, + {__va(spi.s_mmu_nctx), (char *)__va(&spi.leon_nctx), 4}, + {__va(spi.s_frequency), (char *)__va(&spi.freq_khz), 4}, + {__va(spi.s_uart1_baud), (char *)__va(&spi.baudrates[0]), 4}, + {__va(spi.s_uart2_baud), (char *)__va(&spi.baudrates[1]), 4}, + {NULL, NULL, -1} + }, +#undef CPUENTRY +#define CPUENTRY(idx) \ + { /* cpu_properties */ \ + {__va(spi.s_device_type), __va(spi.s_cpu), 4}, \ + {__va(spi.s_mid), __va(&spi.mids[idx]), 4}, \ + {__va(spi.s_frequency), (char *)__va(&spi.freq_khz), 4}, \ + {NULL, NULL, -1} \ + } + CPUENTRY(1), + CPUENTRY(2), + CPUENTRY(3), + CPUENTRY(4), + CPUENTRY(5), + CPUENTRY(6), + CPUENTRY(7), + CPUENTRY(8), + CPUENTRY(9), + CPUENTRY(10), + CPUENTRY(11), + CPUENTRY(12), + CPUENTRY(13), + CPUENTRY(14), + CPUENTRY(15), + CPUENTRY(16), + CPUENTRY(17), + CPUENTRY(18), + CPUENTRY(19), + CPUENTRY(20), + CPUENTRY(21), + CPUENTRY(22), + CPUENTRY(23), + CPUENTRY(24), + CPUENTRY(25), + CPUENTRY(26), + CPUENTRY(27), + CPUENTRY(28), + CPUENTRY(29), + CPUENTRY(30), + CPUENTRY(31), + { + 0x01, /* format */ + M_LEON2 | M_LEON2_SOC, /* machine type */ + {0, 0, 0, 0, 0, 0}, /* eth */ + 0, /* date */ + 0, /* sernum */ + 0, /* checksum */ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} /* reserved */ + }, + { + __va(no_nextnode), + __va(no_child), + __va(no_proplen), + __va(no_getprop), + __va(no_setprop), + __va(no_nextprop) + }, + __va(&spi.totphys), + { + NULL, + (char *)CONFIG_SYS_SDRAM_BASE, + 0, + }, + __va(&spi.avail), + { + NULL, + (char *)CONFIG_SYS_SDRAM_BASE, + 0, + }, + NULL, /* prommap_p */ + NULL, + __va(&spi.bootargs), + { + {NULL, __va(spi.arg), NULL /*... */ }, + /*... */ + }, + { + 0, + 0, /* sun4c v0 prom */ + 0, 0, + {__va(&spi.totphys_p), __va(&spi.prommap_p), __va(&spi.avail_p)}, + __va(&spi.nodeops), + NULL, {NULL /* ... */ }, + NULL, NULL, + NULL, NULL, /* pv_getchar, pv_putchar */ + __va(leon_nbgetchar), __va(leon_nbputchar), + NULL, + __va(leon_reboot), + NULL, + NULL, + NULL, + __va(leon_halt), + __va(&spi.synchook), + {NULL}, + __va(&spi.bootargs_p) + /*... */ + }, + { + {0, __va(spi.root_properties + 3) /* NULL, NULL, -1 */ }, + {0, __va(spi.root_properties)}, + /* cpu 0, must be spi.nodes[2] see leon_prom_init() */ + {1, __va(spi.cpu_properties)}, + +#undef CPUENTRY +#define CPUENTRY(idx) \ + {1, __va(spi.cpu_properties##idx) } /* cpu <idx> */ + CPUENTRY(1), + CPUENTRY(2), + CPUENTRY(3), + CPUENTRY(4), + CPUENTRY(5), + CPUENTRY(6), + CPUENTRY(7), + CPUENTRY(8), + CPUENTRY(9), + CPUENTRY(10), + CPUENTRY(11), + CPUENTRY(12), + CPUENTRY(13), + CPUENTRY(14), + CPUENTRY(15), + CPUENTRY(16), + CPUENTRY(17), + CPUENTRY(18), + CPUENTRY(19), + CPUENTRY(20), + CPUENTRY(21), + CPUENTRY(22), + CPUENTRY(23), + CPUENTRY(24), + CPUENTRY(25), + CPUENTRY(26), + CPUENTRY(27), + CPUENTRY(28), + CPUENTRY(29), + CPUENTRY(30), + CPUENTRY(31), + {-1, __va(spi.root_properties + 3) /* NULL, NULL, -1 */ } + }, + "device_type", + "cpu", + "mid", + "idprom", + "compatability", + "leon2", + "mmu-nctx", + "clock-frequency", + "uart1_baud", + "uart2_baud", + CONFIG_DEFAULT_KERNEL_COMMAND_LINE +}; + +/* from arch/sparc/kernel/setup.c */ +#define RAMDISK_LOAD_FLAG 0x4000 +extern unsigned short root_flags; +extern unsigned short root_dev; +extern unsigned short ram_flags; +extern unsigned int sparc_ramdisk_image; +extern unsigned int sparc_ramdisk_size; +extern int root_mountflags; + +extern char initrd_end, initrd_start; + +/* Reboot the CPU = jump to beginning of flash again. + * + * Make sure that all function are inlined here. + */ +static void PROM_TEXT leon_reboot(char *bcommand) +{ + register char *arg = bcommand; + void __attribute__ ((noreturn)) (*reboot_physical) (char *cmd); + + /* get physical address */ + struct leon_prom_info *pspi = + (void *)(CONFIG_SYS_PROM_OFFSET + sizeof(srmmu_tables)); + + unsigned int *srmmu_ctx_table; + + /* Turn of Interrupts */ + set_pil(0xf); + + /* Set kernel's context, context zero */ + srmmu_set_context(0); + + /* Get physical address of the MMU shutdown routine */ + reboot_physical = (void *) + SPARC_BYPASS_READ(&pspi->reloc_funcs.reboot_physical); + + /* Now that we know the physical address of the function + * we can make the MMU allow jumping to it. + */ + srmmu_ctx_table = (unsigned int *)srmmu_get_ctable_ptr(); + + srmmu_ctx_table = (unsigned int *)SPARC_BYPASS_READ(srmmu_ctx_table); + + /* get physical address of kernel's context table (assume ptd) */ + srmmu_ctx_table = (unsigned int *) + (((unsigned int)srmmu_ctx_table & 0xfffffffc) << 4); + + /* enable access to physical address of MMU shutdown function */ + SPARC_BYPASS_WRITE(&srmmu_ctx_table + [((unsigned int)reboot_physical) >> 24], + (((unsigned int)reboot_physical & 0xff000000) >> 4) | + 0x1e); + + /* flush TLB cache */ + leon_flush_tlb_all(); + + /* flash instruction & data cache */ + sparc_icache_flush_all(); + sparc_dcache_flush_all(); + + /* jump to physical address function + * so that when the MMU is disabled + * we can continue to execute + */ + reboot_physical(arg); +} + +static void PROM_TEXT leon_reboot_physical(char *bcommand) +{ + void __attribute__ ((noreturn)) (*reset) (void); + + /* Turn off MMU */ + srmmu_set_mmureg(0); + + /* Hardcoded start address */ + reset = CONFIG_SYS_MONITOR_BASE; + + /* flush data cache */ + sparc_dcache_flush_all(); + + /* flush instruction cache */ + sparc_icache_flush_all(); + + /* Jump to start in Flash */ + reset(); +} + +static void PROM_TEXT leon_halt(void) +{ + while (1) ; +} + +/* get single char, don't care for blocking*/ +static int PROM_TEXT leon_nbgetchar(void) +{ + return -1; +} + +/* put single char, don't care for blocking*/ +static int PROM_TEXT leon_nbputchar(int c) +{ + ambapp_dev_apbuart *uart; + + /* get physical address */ + struct leon_prom_info *pspi = + (void *)(CONFIG_SYS_PROM_OFFSET + sizeof(srmmu_tables)); + + uart = (ambapp_dev_apbuart *) + SPARC_BYPASS_READ(&pspi->reloc_funcs.leon3_apbuart); + + /* no UART? */ + if (!uart) + return 0; + + /***** put char in buffer... *********** + * Make sure all functions are inline! * + ***************************************/ + + /* Wait for last character to go. */ + while (!(SPARC_BYPASS_READ(&uart->status) + & LEON_REG_UART_STATUS_THE)) ; + + /* Send data */ + SPARC_BYPASS_WRITE(&uart->data, c); + + /* Wait for data to be sent */ + while (!(SPARC_BYPASS_READ(&uart->status) + & LEON_REG_UART_STATUS_TSE)) ; + + return 0; +} + +/* node ops */ + +/*#define nodes ((struct node *)__va(&pspi->nodes))*/ +#define nodes ((struct node *)(pspi->nodes)) + +static int PROM_TEXT no_nextnode(int node) +{ + /* get physical address */ + struct leon_prom_info *pspi = + (void *)(CONFIG_SYS_PROM_OFFSET + sizeof(srmmu_tables)); + + /* convert into virtual address */ + pspi = (struct leon_prom_info *) + (((unsigned int)pspi & 0x0fffffff) | PAGE_OFFSET); + + if (nodes[node].level == nodes[node + 1].level) + return node + 1; + return -1; +} + +static int PROM_TEXT no_child(int node) +{ + /* get physical address */ + struct leon_prom_info *pspi = (struct leon_prom_info *) + (CONFIG_SYS_PROM_OFFSET + sizeof(srmmu_tables)); + + /* convert into virtual address */ + pspi = (struct leon_prom_info *) + (((unsigned int)pspi & 0x0fffffff) | PAGE_OFFSET); + + if (nodes[node].level == nodes[node + 1].level - 1) + return node + 1; + return -1; +} + +static struct property PROM_TEXT *find_property(int node, char *name) +{ + /* get physical address */ + struct leon_prom_info *pspi = (struct leon_prom_info *) + (CONFIG_SYS_PROM_OFFSET + sizeof(srmmu_tables)); + + /* convert into virtual address */ + pspi = (struct leon_prom_info *) + (((unsigned int)pspi & 0x0fffffff) | PAGE_OFFSET); + + struct property *prop = &nodes[node].properties[0]; + while (prop && prop->name) { + if (pspi->reloc_funcs.strcmp(prop->name, name) == 0) + return prop; + prop++; + } + return NULL; +} + +static int PROM_TEXT no_proplen(int node, char *name) +{ + /* get physical address */ + struct leon_prom_info *pspi = (struct leon_prom_info *) + (CONFIG_SYS_PROM_OFFSET + sizeof(srmmu_tables)); + + /* convert into virtual address */ + pspi = (struct leon_prom_info *) + (((unsigned int)pspi & 0x0fffffff) | PAGE_OFFSET); + + struct property *prop = pspi->reloc_funcs.find_property(node, name); + if (prop) + return prop->length; + return -1; +} + +static int PROM_TEXT no_getprop(int node, char *name, char *value) +{ + /* get physical address */ + struct leon_prom_info *pspi = (struct leon_prom_info *) + (CONFIG_SYS_PROM_OFFSET + sizeof(srmmu_tables)); + + /* convert into virtual address */ + pspi = (struct leon_prom_info *) + (((unsigned int)pspi & 0x0fffffff) | PAGE_OFFSET); + + struct property *prop = pspi->reloc_funcs.find_property(node, name); + if (prop) { + pspi->reloc_funcs.memcpy(value, prop->value, prop->length); + return 1; + } + return -1; +} + +static int PROM_TEXT no_setprop(int node, char *name, char *value, int len) +{ + return -1; +} + +static char PROM_TEXT *no_nextprop(int node, char *name) +{ + /* get physical address */ + struct leon_prom_info *pspi = (struct leon_prom_info *) + (CONFIG_SYS_PROM_OFFSET + sizeof(srmmu_tables)); + struct property *prop; + + /* convert into virtual address */ + pspi = (struct leon_prom_info *) + (((unsigned int)pspi & 0x0fffffff) | PAGE_OFFSET); + + if (!name || !name[0]) + return nodes[node].properties[0].name; + + prop = pspi->reloc_funcs.find_property(node, name); + if (prop) + return prop[1].name; + return NULL; +} + +static int PROM_TEXT leon_strcmp(const char *s1, const char *s2) +{ + register char result; + + while (1) { + result = *s1 - *s2; + if (result || !*s1) + break; + s2++; + s1++; + } + + return result; +} + +static void *PROM_TEXT leon_memcpy(void *dest, const void *src, size_t n) +{ + char *dst = (char *)dest, *source = (char *)src; + + while (n--) { + *dst = *source; + dst++; + source++; + } + return dest; +} + +#define GETREGSP(sp) __asm__ __volatile__("mov %%sp, %0" : "=r" (sp)) + +void leon_prom_init(struct leon_prom_info *pspi) +{ + unsigned long i; + unsigned char cksum, *ptr; + char *addr_str, *end; + unsigned long sp; + GETREGSP(sp); + + pspi->freq_khz = CONFIG_SYS_CLK_FREQ / 1000; + + /* Set Available main memory size */ + pspi->totphys.num_bytes = CONFIG_SYS_PROM_OFFSET - CONFIG_SYS_SDRAM_BASE; + pspi->avail.num_bytes = pspi->totphys.num_bytes; + + /* Set the pointer to the Console UART in romvec */ + pspi->reloc_funcs.leon3_apbuart = leon3_apbuart; + + { + int j = 1; +#ifdef CONFIG_SMP + ambapp_dev_irqmp *b; + b = (ambapp_dev_irqmp *) leon3_getapbbase(VENDOR_GAISLER, + GAISLER_IRQMP); + if (b) { + j = 1 + ((LEON3_BYPASS_LOAD_PA(&(b->mpstatus)) + >> LEON3_IRQMPSTATUS_CPUNR) & 0xf); + } +#endif +#undef nodes + pspi->nodes[2 + j].level = -1; + pspi->nodes[2 + j].properties = __va(spi.root_properties + 3); + } + + /* Set Ethernet MAC address from environment */ + if ((addr_str = getenv("ethaddr")) != NULL) { + for (i = 0; i < 6; i++) { + pspi->idprom.id_ethaddr[i] = addr_str ? + simple_strtoul(addr_str, &end, 16) : 0; + if (addr_str) { + addr_str = (*end) ? end + 1 : end; + } + } + } else { + /* HW Address not found in environment, + * Set default HW address + */ + pspi->idprom.id_ethaddr[0] = 0; + pspi->idprom.id_ethaddr[1] = 0; + pspi->idprom.id_ethaddr[2] = 0; + pspi->idprom.id_ethaddr[3] = 0; + pspi->idprom.id_ethaddr[4] = 0; + pspi->idprom.id_ethaddr[5] = 0; + } + + ptr = (unsigned char *)&pspi->idprom; + for (i = cksum = 0; i <= 0x0E; i++) + cksum ^= *ptr++; + pspi->idprom.id_cksum = cksum; +} + +static inline void set_cache(unsigned long regval) +{ + asm volatile ("sta %0, [%%g0] %1\n\t":: "r" (regval), "i"(2):"memory"); +} + +extern unsigned short bss_start, bss_end; + +/* mark as section .img.main.text, to be referenced in linker script */ +int prom_init(void) +{ + struct leon_prom_info *pspi = (void *) + ((((unsigned int)&spi) & PROM_SIZE_MASK) + CONFIG_SYS_PROM_OFFSET); + + /* disable mmu */ + srmmu_set_mmureg(0x00000000); + __asm__ __volatile__("flush\n\t"); + + /* init prom info struct */ + leon_prom_init(pspi); + + kernel_arg_promvec = &pspi->romvec; +#ifdef PRINT_ROM_VEC + printf("Kernel rom vec: 0x%lx\n", (unsigned int)(&pspi->romvec)); +#endif + return 0; +} + +/* Copy current kernel boot argument to ROMvec */ +void prepare_bootargs(char *bootargs) +{ + struct leon_prom_info *pspi; + char *src, *dst; + int left; + + /* if no bootargs set, skip copying ==> default bootline */ + if (bootargs && (*bootargs != '\0')) { + pspi = (void *)((((unsigned int)&spi) & PROM_SIZE_MASK) + + CONFIG_SYS_PROM_OFFSET); + src = bootargs; + dst = &pspi->arg[0]; + left = 255; /* max len */ + while (*src && left > 0) { + *dst++ = *src++; + left--; + } + /* terminate kernel command line string */ + *dst = 0; + } +} + +void srmmu_init_cpu(unsigned int entry) +{ + sparc_srmmu_setup *psrmmu_tables = (void *) + ((((unsigned int)&srmmu_tables) & PROM_SIZE_MASK) + + CONFIG_SYS_PROM_OFFSET); + + /* Make context 0 (kernel's context) point + * to our prepared memory mapping + */ +#define PTD 1 + psrmmu_tables->ctx_table[0] = + ((unsigned int)&psrmmu_tables->pgd_table[0x00]) >> 4 | PTD; + + /* Set virtual kernel address 0xf0000000 + * to SRAM/SDRAM address. + * Make it READ/WRITE/EXEC to SuperUser + */ +#define PTE 2 +#define ACC_SU_ALL 0x1c + psrmmu_tables->pgd_table[0xf0] = + (CONFIG_SYS_SDRAM_BASE >> 4) | ACC_SU_ALL | PTE; + psrmmu_tables->pgd_table[0xf1] = + ((CONFIG_SYS_SDRAM_BASE + 0x1000000) >> 4) | ACC_SU_ALL | PTE; + psrmmu_tables->pgd_table[0xf2] = + ((CONFIG_SYS_SDRAM_BASE + 0x2000000) >> 4) | ACC_SU_ALL | PTE; + psrmmu_tables->pgd_table[0xf3] = + ((CONFIG_SYS_SDRAM_BASE + 0x3000000) >> 4) | ACC_SU_ALL | PTE; + psrmmu_tables->pgd_table[0xf4] = + ((CONFIG_SYS_SDRAM_BASE + 0x4000000) >> 4) | ACC_SU_ALL | PTE; + psrmmu_tables->pgd_table[0xf5] = + ((CONFIG_SYS_SDRAM_BASE + 0x5000000) >> 4) | ACC_SU_ALL | PTE; + psrmmu_tables->pgd_table[0xf6] = + ((CONFIG_SYS_SDRAM_BASE + 0x6000000) >> 4) | ACC_SU_ALL | PTE; + psrmmu_tables->pgd_table[0xf7] = + ((CONFIG_SYS_SDRAM_BASE + 0x7000000) >> 4) | ACC_SU_ALL | PTE; + + /* convert rom vec pointer to virtual address */ + kernel_arg_promvec = (struct linux_romvec *) + (((unsigned int)kernel_arg_promvec & 0x0fffffff) | 0xf0000000); + + /* Set Context pointer to point to context table + * 256 contexts supported. + */ + srmmu_set_ctable_ptr((unsigned int)&psrmmu_tables->ctx_table[0]); + + /* Set kernel's context, context zero */ + srmmu_set_context(0); + + /* Invalidate all Cache */ + __asm__ __volatile__("flush\n\t"); + + srmmu_set_mmureg(0x00000001); + leon_flush_tlb_all(); + leon_flush_cache_all(); +} diff --git a/arch/sparc/cpu/leon3/serial.c b/arch/sparc/cpu/leon3/serial.c new file mode 100644 index 0000000..4b2fcb8 --- /dev/null +++ b/arch/sparc/cpu/leon3/serial.c @@ -0,0 +1,139 @@ +/* GRLIB APBUART Serial controller driver + * + * (C) Copyright 2007 + * Daniel Hellstrom, Gaisler Research, daniel@gaisler.com. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 program is distributed in the hope that 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 <common.h> +#include <asm/processor.h> +#include <asm/leon.h> +#include <ambapp.h> + +DECLARE_GLOBAL_DATA_PTR; + +/* Force cache miss each time a serial controller reg is read */ +#define CACHE_BYPASS 1 + +#ifdef CACHE_BYPASS +#define READ_BYTE(var) SPARC_NOCACHE_READ_BYTE((unsigned int)&(var)) +#define READ_HWORD(var) SPARC_NOCACHE_READ_HWORD((unsigned int)&(var)) +#define READ_WORD(var) SPARC_NOCACHE_READ((unsigned int)&(var)) +#define READ_DWORD(var) SPARC_NOCACHE_READ_DWORD((unsigned int)&(var)) +#endif + +ambapp_dev_apbuart *leon3_apbuart = NULL; + +int serial_init(void) +{ + ambapp_apbdev apbdev; + unsigned int tmp; + + /* find UART */ + if (ambapp_apb_first(VENDOR_GAISLER, GAISLER_APBUART, &apbdev) == 1) { + + leon3_apbuart = (ambapp_dev_apbuart *) apbdev.address; + + /* found apbuart, let's init... + * + * Set scaler / baud rate + * + * Receiver & transmitter enable + */ + leon3_apbuart->scaler = CONFIG_SYS_GRLIB_APBUART_SCALER; + + /* Let bit 11 be unchanged (debug bit for GRMON) */ + tmp = READ_WORD(leon3_apbuart->ctrl); + + leon3_apbuart->ctrl = ((tmp & LEON_REG_UART_CTRL_DBG) | + LEON_REG_UART_CTRL_RE | + LEON_REG_UART_CTRL_TE); + + return 0; + } + return -1; /* didn't find hardware */ +} + +void serial_putc(const char c) +{ + if (c == '\n') + serial_putc_raw('\r'); + + serial_putc_raw(c); +} + +void serial_putc_raw(const char c) +{ + if (!leon3_apbuart) + return; + + /* Wait for last character to go. */ + while (!(READ_WORD(leon3_apbuart->status) & LEON_REG_UART_STATUS_THE)) ; + + /* Send data */ + leon3_apbuart->data = c; + +#ifdef LEON_DEBUG + /* Wait for data to be sent */ + while (!(READ_WORD(leon3_apbuart->status) & LEON_REG_UART_STATUS_TSE)) ; +#endif +} + +void serial_puts(const char *s) +{ + while (*s) { + serial_putc(*s++); + } +} + +int serial_getc(void) +{ + if (!leon3_apbuart) + return 0; + + /* Wait for a character to arrive. */ + while (!(READ_WORD(leon3_apbuart->status) & LEON_REG_UART_STATUS_DR)) ; + + /* read data */ + return READ_WORD(leon3_apbuart->data); +} + +int serial_tstc(void) +{ + if (leon3_apbuart) + return (READ_WORD(leon3_apbuart->status) & + LEON_REG_UART_STATUS_DR); + return 0; +} + +/* set baud rate for uart */ +void serial_setbrg(void) +{ + /* update baud rate settings, read it from gd->baudrate */ + unsigned int scaler; + if (leon3_apbuart && (gd->baudrate > 0)) { + scaler = + (((CONFIG_SYS_CLK_FREQ * 10) / (gd->baudrate * 8)) - + 5) / 10; + leon3_apbuart->scaler = scaler; + } + return; +} diff --git a/arch/sparc/cpu/leon3/start.S b/arch/sparc/cpu/leon3/start.S new file mode 100644 index 0000000..bd634bd --- /dev/null +++ b/arch/sparc/cpu/leon3/start.S @@ -0,0 +1,617 @@ +/* This is where the SPARC/LEON3 starts + * Copyright (C) 2007, + * Daniel Hellstrom, daniel@gaisler.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 program is distributed in the hope that 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 <config.h> +#include <asm/asmmacro.h> +#include <asm/winmacro.h> +#include <asm/psr.h> +#include <asm/stack.h> +#include <asm/leon.h> +#include <timestamp.h> +#include <version.h> + +/* Entry for traps which jump to a programmer-specified trap handler. */ +#define TRAPR(H) \ + wr %g0, 0xfe0, %psr; \ + mov %g0, %tbr; \ + ba (H); \ + mov %g0, %wim; + +#define TRAP(H) \ + mov %psr, %l0; \ + ba (H); \ + nop; nop; + +#define TRAPI(ilevel) \ + mov ilevel, %l7; \ + mov %psr, %l0; \ + b _irq_entry; \ + mov %wim, %l3 + +/* Unexcpected trap will halt the processor by forcing it to error state */ +#undef BAD_TRAP +#define BAD_TRAP ta 0; nop; nop; nop; + +/* Software trap. Treat as BAD_TRAP for the time being... */ +#define SOFT_TRAP TRAP(_hwerr) + +#define PSR_INIT 0x1FC0 /* Disable traps, set s and ps */ +#define WIM_INIT 2 + +/* All traps low-level code here must end with this macro. */ +#define RESTORE_ALL b ret_trap_entry; clr %l6; + +#define WRITE_PAUSE nop;nop;nop + +WINDOWSIZE = (16 * 4) +ARGPUSHSIZE = (6 * 4) +ARGPUSH = (WINDOWSIZE + 4) +MINFRAME = (WINDOWSIZE + ARGPUSHSIZE + 4) + +/* Number of register windows */ +#ifndef CONFIG_SYS_SPARC_NWINDOWS +#error Must define number of SPARC register windows, default is 8 +#endif + +#define STACK_ALIGN 8 +#define SA(X) (((X)+(STACK_ALIGN-1)) & ~(STACK_ALIGN-1)) + + .section ".start", "ax" + .globl _start, start, _trap_table + .globl _irq_entry, nmi_trap + .globl _reset_reloc + +/* at address 0 + * Hardware traps + */ +start: +_start: +_trap_table: + TRAPR(_hardreset); ! 00 reset trap + BAD_TRAP; ! 01 instruction_access_exception + BAD_TRAP; ! 02 illegal_instruction + BAD_TRAP; ! 03 priveleged_instruction + BAD_TRAP; ! 04 fp_disabled + TRAP(_window_overflow); ! 05 window_overflow + TRAP(_window_underflow); ! 06 window_underflow + BAD_TRAP; ! 07 Memory Address Not Aligned + BAD_TRAP; ! 08 Floating Point Exception + BAD_TRAP; ! 09 Data Miss Exception + BAD_TRAP; ! 0a Tagged Instruction Ovrflw + BAD_TRAP; ! 0b Watchpoint Detected + BAD_TRAP; ! 0c + BAD_TRAP; ! 0d + BAD_TRAP; ! 0e + BAD_TRAP; ! 0f + BAD_TRAP; ! 10 + TRAPI(1); ! 11 IRQ level 1 + TRAPI(2); ! 12 IRQ level 2 + TRAPI(3); ! 13 IRQ level 3 + TRAPI(4); ! 14 IRQ level 4 + TRAPI(5); ! 15 IRQ level 5 + TRAPI(6); ! 16 IRQ level 6 + TRAPI(7); ! 17 IRQ level 7 + TRAPI(8); ! 18 IRQ level 8 + TRAPI(9); ! 19 IRQ level 9 + TRAPI(10); ! 1a IRQ level 10 + TRAPI(11); ! 1b IRQ level 11 + TRAPI(12); ! 1c IRQ level 12 + TRAPI(13); ! 1d IRQ level 13 + TRAPI(14); ! 1e IRQ level 14 + TRAP(_nmi_trap); ! 1f IRQ level 15 / + ! NMI (non maskable interrupt) + BAD_TRAP; ! 20 r_register_access_error + BAD_TRAP; ! 21 instruction access error + BAD_TRAP; ! 22 + BAD_TRAP; ! 23 + BAD_TRAP; ! 24 co-processor disabled + BAD_TRAP; ! 25 uniplemented FLUSH + BAD_TRAP; ! 26 + BAD_TRAP; ! 27 + BAD_TRAP; ! 28 co-processor exception + BAD_TRAP; ! 29 data access error + BAD_TRAP; ! 2a division by zero + BAD_TRAP; ! 2b data store error + BAD_TRAP; ! 2c data access MMU miss + BAD_TRAP; ! 2d + BAD_TRAP; ! 2e + BAD_TRAP; ! 2f + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 30-33 + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 34-37 + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 38-3b + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 3c-3f + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 40-43 + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 44-47 + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 48-4b + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 4c-4f + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 50-53 + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 54-57 + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 58-5b + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 5c-5f + + /* implementaion dependent */ + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 60-63 + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 64-67 + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 68-6b + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 6c-6f + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 70-73 + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 74-77 + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 78-7b + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 7c-7f + + /* Software traps, not handled */ + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! 80-83 + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! 84-87 + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! 88-8b + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! 8c-8f + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! 90-93 + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! 94-97 + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! 98-9b + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! 9c-9f + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! a0-a3 + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! a4-a7 + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! a8-ab + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! ac-af + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! b0-b3 + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! b4-b7 + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! b8-bb + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! bc-bf + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! c0-c3 + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! c4-c7 + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! c8-cb + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! cc-cf + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! d0-d3 + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! d4-d7 + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! d8-db + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! dc-df + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! e0-e3 + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! e4-e7 + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! e8-eb + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! ec-ef + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! f0-f3 + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! f4-f7 + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! f8-fb + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! fc-ff +/* + * Version string + */ + + .data + .extern leon3_snooping_avail + .globl version_string +version_string: + .ascii U_BOOT_VERSION + .ascii " (", U_BOOT_DATE, " - ", U_BOOT_TIME, ")" + .ascii CONFIG_IDENT_STRING, "\0" + + .section ".text" + .align 4 + +_hardreset: +1000: + flush + + /* Enable I/D-Cache and Snooping */ + set 0x0081000f, %g2 + sta %g2, [%g0] 2 + + mov %g0, %y + clr %g1 + clr %g2 + clr %g3 + clr %g4 + clr %g5 + clr %g6 + clr %g7 + + mov %asr17, %g3 + and %g3, 0x1f, %g3 +clear_window: + mov %g0, %l0 + mov %g0, %l1 + mov %g0, %l2 + mov %g0, %l3 + mov %g0, %l4 + mov %g0, %l5 + mov %g0, %l6 + mov %g0, %l7 + mov %g0, %o0 + mov %g0, %o1 + mov %g0, %o2 + mov %g0, %o3 + mov %g0, %o4 + mov %g0, %o5 + mov %g0, %o6 + mov %g0, %o7 + subcc %g3, 1, %g3 + bge clear_window + save + +wininit: + set WIM_INIT, %g3 + mov %g3, %wim + +stackp: + set CONFIG_SYS_INIT_SP_OFFSET, %fp + andn %fp, 0x0f, %fp + sub %fp, 64, %sp + +cpu_init_unreloc: + call cpu_init_f + nop + +/* un relocated start address of monitor */ +#define TEXT_START _text + +/* un relocated end address of monitor */ +#define DATA_END __init_end + +reloc: + set TEXT_START,%g2 + set DATA_END,%g3 + set CONFIG_SYS_RELOC_MONITOR_BASE,%g4 +reloc_loop: + ldd [%g2],%l0 + ldd [%g2+8],%l2 + std %l0,[%g4] + std %l2,[%g4+8] + inc 16,%g2 + subcc %g3,%g2,%g0 + bne reloc_loop + inc 16,%g4 + + clr %l0 + clr %l1 + clr %l2 + clr %l3 + clr %g2 + +/* register g4 contain address to start + * This means that BSS must be directly after data and code segments + * + * g3 is length of bss = (__bss_end-__bss_start) + * + */ + +clr_bss: +/* clear bss area (the relocated) */ + set __bss_start,%g2 + set __bss_end,%g3 + sub %g3,%g2,%g3 + add %g3,%g4,%g3 + clr %g1 /* std %g0 uses g0 and g1 */ +/* clearing 16byte a time ==> linker script need to align to 16 byte offset */ +clr_bss_16: + std %g0,[%g4] + std %g0,[%g4+8] + inc 16,%g4 + cmp %g3,%g4 + bne clr_bss_16 + nop + +/* add offsets to GOT table */ +fixup_got: + set __got_start,%g4 + set __got_end,%g3 +/* + * new got offset = (old GOT-PTR (read with ld) - + * CONFIG_SYS_RELOC_MONITOR_BASE(from define) ) + + * Destination Address (from define) + */ + set CONFIG_SYS_RELOC_MONITOR_BASE,%g2 + set TEXT_START, %g1 + add %g4,%g2,%g4 + sub %g4,%g1,%g4 + add %g3,%g2,%g3 + sub %g3,%g1,%g3 + sub %g2,%g1,%g2 ! prepare register with (new base address) - + ! (old base address) +got_loop: + ld [%g4],%l0 ! load old GOT-PTR + add %l0,%g2,%l0 ! increase with (new base address) - + ! (old base) + st %l0,[%g4] + inc 4,%g4 + cmp %g3,%g4 + bne got_loop + nop + +prom_relocate: + set __prom_start, %g2 + set __prom_end, %g3 + set CONFIG_SYS_PROM_OFFSET, %g4 + +prom_relocate_loop: + ldd [%g2],%l0 + ldd [%g2+8],%l2 + std %l0,[%g4] + std %l2,[%g4+8] + inc 16,%g2 + subcc %g3,%g2,%g0 + bne prom_relocate_loop + inc 16,%g4 + +/* Trap table has been moved, lets tell CPU about + * the new trap table address + */ + + set CONFIG_SYS_RELOC_MONITOR_BASE, %g2 + wr %g0, %g2, %tbr + nop + nop + nop + +/* If CACHE snooping is available in hardware the + * variable leon3_snooping_avail will be set to + * 0x800000 else 0. + */ +snoop_detect: + sethi %hi(0x00800000), %o0 + lda [%g0] 2, %o1 + and %o0, %o1, %o0 + sethi %hi(leon3_snooping_avail+CONFIG_SYS_RELOC_MONITOR_BASE-TEXT_BASE), %o1 + st %o0, [%lo(leon3_snooping_avail+CONFIG_SYS_RELOC_MONITOR_BASE-TEXT_BASE)+%o1] + +/* call relocate*/ + nop +/* Call relocated init functions */ +jump: + set cpu_init_f2,%o1 + set CONFIG_SYS_RELOC_MONITOR_BASE,%o2 + add %o1,%o2,%o1 + sub %o1,%g1,%o1 + call %o1 + clr %o0 + + set board_init_f,%o1 + set CONFIG_SYS_RELOC_MONITOR_BASE,%o2 + add %o1,%o2,%o1 + sub %o1,%g1,%o1 + call %o1 + clr %o0 + +dead: ta 0 ! if call returns... + nop + +/* Interrupt handler caller, + * reg L7: interrupt number + * reg L0: psr after interrupt + * reg L1: PC + * reg L2: next PC + * reg L3: wim + */ +_irq_entry: + SAVE_ALL + + or %l0, PSR_PIL, %g2 + wr %g2, 0x0, %psr + WRITE_PAUSE + wr %g2, PSR_ET, %psr + WRITE_PAUSE + mov %l7, %o0 ! irq level + set handler_irq, %o1 + set (CONFIG_SYS_RELOC_MONITOR_BASE-TEXT_BASE), %o2 + add %o1, %o2, %o1 + call %o1 + add %sp, SF_REGS_SZ, %o1 ! pt_regs ptr + or %l0, PSR_PIL, %g2 ! restore PIL after handler_irq + wr %g2, PSR_ET, %psr ! keep ET up + WRITE_PAUSE + + RESTORE_ALL + +!Window overflow trap handler. + .global _window_overflow + +_window_overflow: + + mov %wim, %l3 ! Calculate next WIM + mov %g1, %l7 + srl %l3, 1, %g1 + sll %l3, (CONFIG_SYS_SPARC_NWINDOWS-1) , %l4 + or %l4, %g1, %g1 + + save ! Get into window to be saved. + mov %g1, %wim + nop; + nop; + nop + st %l0, [%sp + 0]; + st %l1, [%sp + 4]; + st %l2, [%sp + 8]; + st %l3, [%sp + 12]; + st %l4, [%sp + 16]; + st %l5, [%sp + 20]; + st %l6, [%sp + 24]; + st %l7, [%sp + 28]; + st %i0, [%sp + 32]; + st %i1, [%sp + 36]; + st %i2, [%sp + 40]; + st %i3, [%sp + 44]; + st %i4, [%sp + 48]; + st %i5, [%sp + 52]; + st %i6, [%sp + 56]; + st %i7, [%sp + 60]; + restore ! Go back to trap window. + mov %l7, %g1 + jmp %l1 ! Re-execute save. + rett %l2 + +/* Window underflow trap handler. */ + + .global _window_underflow + +_window_underflow: + + mov %wim, %l3 ! Calculate next WIM + sll %l3, 1, %l4 + srl %l3, (CONFIG_SYS_SPARC_NWINDOWS-1), %l5 + or %l5, %l4, %l5 + mov %l5, %wim + nop; nop; nop + restore ! Two restores to get into the + restore ! window to restore + ld [%sp + 0], %l0; ! Restore window from the stack + ld [%sp + 4], %l1; + ld [%sp + 8], %l2; + ld [%sp + 12], %l3; + ld [%sp + 16], %l4; + ld [%sp + 20], %l5; + ld [%sp + 24], %l6; + ld [%sp + 28], %l7; + ld [%sp + 32], %i0; + ld [%sp + 36], %i1; + ld [%sp + 40], %i2; + ld [%sp + 44], %i3; + ld [%sp + 48], %i4; + ld [%sp + 52], %i5; + ld [%sp + 56], %i6; + ld [%sp + 60], %i7; + save ! Get back to the trap window. + save + jmp %l1 ! Re-execute restore. + rett %l2 + + retl + +_nmi_trap: + nop + jmp %l1 + rett %l2 + +_hwerr: + ta 0 + nop + nop + b _hwerr ! loop infinite + nop + +/* Registers to not touch at all. */ +#define t_psr l0 /* Set by caller */ +#define t_pc l1 /* Set by caller */ +#define t_npc l2 /* Set by caller */ +#define t_wim l3 /* Set by caller */ +#define t_twinmask l4 /* Set at beginning of this entry routine. */ +#define t_kstack l5 /* Set right before pt_regs frame is built */ +#define t_retpc l6 /* If you change this, change winmacro.h header file */ +#define t_systable l7 /* Never touch this, could be the syscall table ptr. */ +#define curptr g6 /* Set after pt_regs frame is built */ + +trap_setup: +/* build a pt_regs trap frame. */ + sub %fp, (SF_REGS_SZ + PT_REGS_SZ), %t_kstack + PT_STORE_ALL(t_kstack, t_psr, t_pc, t_npc, g2) + + /* See if we are in the trap window. */ + mov 1, %t_twinmask + sll %t_twinmask, %t_psr, %t_twinmask ! t_twinmask = (1 << psr) + andcc %t_twinmask, %t_wim, %g0 + beq 1f ! in trap window, clean up + nop + + /*------------------------------------------------- + * Spill , adjust %wim and go. + */ + srl %t_wim, 0x1, %g2 ! begin computation of new %wim + + set (CONFIG_SYS_SPARC_NWINDOWS-1), %g3 !NWINDOWS-1 + + sll %t_wim, %g3, %t_wim ! NWINDOWS-1 + or %t_wim, %g2, %g2 + and %g2, 0xff, %g2 + + save %g0, %g0, %g0 ! get in window to be saved + + /* Set new %wim value */ + wr %g2, 0x0, %wim + + /* Save the kernel window onto the corresponding stack. */ + RW_STORE(sp) + + restore %g0, %g0, %g0 + /*-------------------------------------------------*/ + +1: + /* Trap from kernel with a window available. + * Just do it... + */ + jmpl %t_retpc + 0x8, %g0 ! return to caller + mov %t_kstack, %sp ! jump onto new stack + +#define twin_tmp1 l4 +#define glob_tmp g4 +#define curptr g6 +ret_trap_entry: + wr %t_psr, 0x0, %psr ! enable nesting again, clear ET + + /* Will the rett land us in the invalid window? */ + mov 2, %g1 + sll %g1, %t_psr, %g1 + + set CONFIG_SYS_SPARC_NWINDOWS, %g2 !NWINDOWS + + srl %g1, %g2, %g2 + or %g1, %g2, %g1 + rd %wim, %g2 + andcc %g2, %g1, %g0 + be 1f ! Nope, just return from the trap + sll %g2, 0x1, %g1 + + /* We have to grab a window before returning. */ + set (CONFIG_SYS_SPARC_NWINDOWS-1), %g3 !NWINDOWS-1 + + srl %g2, %g3, %g2 + or %g1, %g2, %g1 + and %g1, 0xff, %g1 + + wr %g1, 0x0, %wim + + /* Grrr, make sure we load from the right %sp... */ + PT_LOAD_ALL(sp, t_psr, t_pc, t_npc, g1) + + restore %g0, %g0, %g0 + RW_LOAD(sp) + b 2f + save %g0, %g0, %g0 + + /* Reload the entire frame in case this is from a + * kernel system call or whatever... + */ +1: + PT_LOAD_ALL(sp, t_psr, t_pc, t_npc, g1) +2: + wr %t_psr, 0x0, %psr + nop; + nop; + nop + + jmp %t_pc + rett %t_npc + +/* This is called from relocated C-code. + * It resets the system by jumping to _start + */ +_reset_reloc: + set start, %l0 + call %l0 + nop diff --git a/arch/sparc/cpu/leon3/usb_uhci.c b/arch/sparc/cpu/leon3/usb_uhci.c new file mode 100644 index 0000000..8f99e1d --- /dev/null +++ b/arch/sparc/cpu/leon3/usb_uhci.c @@ -0,0 +1,1313 @@ +/* + * Part of this code has been derived from linux: + * Universal Host Controller Interface driver for USB (take II). + * + * (c) 1999-2001 Georg Acher, acher@in.tum.de (executive slave) (base guitar) + * Deti Fliegl, deti@fliegl.de (executive slave) (lead voice) + * Thomas Sailer, sailer@ife.ee.ethz.ch (chief consultant) (cheer leader) + * Roman Weissgaerber, weissg@vienna.at (virt root hub) (studio porter) + * (c) 2000 Yggdrasil Computing, Inc. (port of new PCI interface support + * from usb-ohci.c by Adam Richter, adam@yggdrasil.com). + * (C) 2000 David Brownell, david-b@pacbell.net (usb-ohci.c) + * + * HW-initalization based on material of + * + * (C) Copyright 1999 Linus Torvalds + * (C) Copyright 1999 Johannes Erdfelt + * (C) Copyright 1999 Randy Dunlap + * (C) Copyright 1999 Gregory P. Smith + * + * + * Adapted for U-Boot: + * (C) Copyright 2001 Denis Peter, MPL AG Switzerland + * (C) Copyright 2008, Daniel Hellström, daniel@gaisler.com + * Added AMBA Plug&Play detection of GRUSB, modified interrupt handler. + * Added cache flushes where needed. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 program is distributed in the hope that 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 + * + * + */ + +/********************************************************************** + * How it works: + * ------------- + * The framelist / Transfer descriptor / Queue Heads are similar like + * in the linux usb_uhci.c. + * + * During initialization, the following skeleton is allocated in init_skel: + * + * framespecific | common chain + * + * framelist[] + * [ 0 ]-----> TD ---------\ + * [ 1 ]-----> TD ----------> TD ------> QH -------> QH -------> QH ---> NULL + * ... TD ---------/ + * [1023]-----> TD --------/ + * + * ^^ ^^ ^^ ^^ ^^ + * 7 TDs for 1 TD for Start of Start of End Chain + * INT (2-128ms) 1ms-INT CTRL Chain BULK Chain + * + * + * Since this is a bootloader, the isochronous transfer descriptor have been removed. + * + * Interrupt Transfers. + * -------------------- + * For Interupt transfers USB_MAX_TEMP_INT_TD Transfer descriptor are available. They + * will be inserted after the appropriate (depending the interval setting) skeleton TD. + * If an interrupt has been detected the dev->irqhandler is called. The status and number + * of transfered bytes is stored in dev->irq_status resp. dev->irq_act_len. If the + * dev->irqhandler returns 0, the interrupt TD is removed and disabled. If an 1 is returned, + * the interrupt TD will be reactivated. + * + * Control Transfers + * ----------------- + * Control Transfers are issued by filling the tmp_td with the appropriate data and connect + * them to the qh_cntrl queue header. Before other control/bulk transfers can be issued, + * the programm has to wait for completion. This does not allows asynchronous data transfer. + * + * Bulk Transfers + * -------------- + * Bulk Transfers are issued by filling the tmp_td with the appropriate data and connect + * them to the qh_bulk queue header. Before other control/bulk transfers can be issued, + * the programm has to wait for completion. This does not allows asynchronous data transfer. + * + * + */ + +#include <common.h> +#include <ambapp.h> +#include <asm/leon.h> +#include <asm/leon3.h> +#include <asm/processor.h> + +#ifdef CONFIG_USB_UHCI + +#include <usb.h> +#include "usb_uhci.h" + +#define USB_MAX_TEMP_TD 128 /* number of temporary TDs for bulk and control transfers */ +#define USB_MAX_TEMP_INT_TD 32 /* number of temporary TDs for Interrupt transfers */ + +extern int leon3_snooping_avail; +/* +#define out16r(address,data) (*(unsigned short *)(address) = \ + (unsigned short)( \ + (((unsigned short)(data)&0xff)<<8) | \ + (((unsigned short)(data)&0xff00)>>8) \ + )) + */ +#define out16r(address,data) _out16r((unsigned int)(address), (unsigned short)(data)) +void _out16r(unsigned int address, unsigned short data) +{ + unsigned short val = (unsigned short)((((unsigned short)(data) & 0xff) + << 8) | (((unsigned short)(data) + & 0xff00) >> 8)); +#ifdef UHCI_DEBUG_REGS + printf("out16r(0x%lx,0x%04x = 0x%04x)\n", address, val, data); +#endif + *(unsigned short *)(address) = val; +} + +#define out32r(address,data) _out32r((unsigned int)(address), (unsigned int)(data)) +void _out32r(unsigned int address, unsigned int data) +{ + unsigned int val = (unsigned int)((((unsigned int)(data) & 0x000000ff) + << 24) | (((unsigned int)(data) & + 0x0000ff00) << 8) | + (((unsigned int)(data) & 0x00ff0000) + >> 8) | (((unsigned int)(data) & + 0xff000000) >> 24)); +#ifdef UHCI_DEBUG_REGS + printf("out32r(0x%lx,0x%lx = 0x%lx)\n", address, val, data); +#endif + *(unsigned int *)address = val; +} + +#define in16r(address) _in16r((unsigned int)(address)) +unsigned short _in16r(unsigned int address) +{ + unsigned short val = sparc_load_reg_cachemiss_word(address); + val = ((val << 8) & 0xff00) | ((val >> 8) & 0xff); +#ifdef UHCI_DEBUG_REGS + printf("in16r(0x%lx): 0x%04x\n", address, val); +#endif + return val; +} + +#define in32r(address) _in32r((unsigned int)(address)) +unsigned int _in32r(unsigned int address) +{ + unsigned int val = sparc_load_reg_cachemiss(address); + val = + ((val << 24) & 0xff000000) | ((val << 8) & 0xff0000) | ((val >> 8) & + 0xff00) | + ((val >> 24) & 0xff); +#ifdef UHCI_DEBUG_REGS + printf("in32r(0x%lx): 0x%08x\n", address, val); +#endif + return val; +} + +#define READ32(address) sparc_load_reg_cachemiss((unsigned int)(address)) + +/*#define USB_UHCI_DEBUG*/ +#undef USB_UHCI_DEBUG + +void usb_show_td(int max); +#ifdef USB_UHCI_DEBUG +void grusb_show_regs(void); +#define USB_UHCI_PRINTF(fmt,args...) printf (fmt ,##args) +#else +#define USB_UHCI_PRINTF(fmt,args...) +#endif + +static int grusb_irq = -1; /* irq vector, if -1 uhci is stopped / reseted */ +unsigned int usb_base_addr; /* base address */ + +static uhci_td_t td_int[8] __attribute__ ((aligned(16))); /* Interrupt Transfer descriptors */ +static uhci_qh_t qh_cntrl __attribute__ ((aligned(16))); /* control Queue Head */ +static uhci_qh_t qh_bulk __attribute__ ((aligned(16))); /* bulk Queue Head */ +static uhci_qh_t qh_end __attribute__ ((aligned(16))); /* end Queue Head */ +static uhci_td_t td_last __attribute__ ((aligned(16))); /* last TD (linked with end chain) */ + +/* temporary tds */ +static uhci_td_t tmp_td[USB_MAX_TEMP_TD] __attribute__ ((aligned(16))); /* temporary bulk/control td's */ +static uhci_td_t tmp_int_td[USB_MAX_TEMP_INT_TD] __attribute__ ((aligned(16))); /* temporary interrupt td's */ + +static unsigned long framelist[1024] __attribute__ ((aligned(0x1000))); /* frame list */ + +static struct virt_root_hub rh; /* struct for root hub */ + +/********************************************************************** + * some forward decleration + */ +int uhci_submit_rh_msg(struct usb_device *dev, unsigned long pipe, + void *buffer, int transfer_len, + struct devrequest *setup); + +/* fill a td with the approproiate data. Link, status, info and buffer + * are used by the USB controller itselfes, dev is used to identify the + * "connected" device + */ +void usb_fill_td(uhci_td_t * td, unsigned long link, unsigned long status, + unsigned long info, unsigned long buffer, unsigned long dev) +{ + td->link = swap_32(link); + td->status = swap_32(status); + if ((info & UHCI_PID) == 0) + info |= USB_PID_OUT; + td->info = swap_32(info); + td->buffer = swap_32(buffer); + td->dev_ptr = dev; +} + +/* fill a qh with the approproiate data. Head and element are used by the USB controller + * itselfes. As soon as a valid dev_ptr is filled, a td chain is connected to the qh. + * Please note, that after completion of the td chain, the entry element is removed / + * marked invalid by the USB controller. + */ +void usb_fill_qh(uhci_qh_t * qh, unsigned long head, unsigned long element) +{ + qh->head = swap_32(head); + qh->element = swap_32(element); + qh->dev_ptr = 0L; +} + +/* get the status of a td->status + */ +unsigned long usb_uhci_td_stat(unsigned long status) +{ + unsigned long result = 0; + result |= (status & TD_CTRL_NAK) ? USB_ST_NAK_REC : 0; + result |= (status & TD_CTRL_STALLED) ? USB_ST_STALLED : 0; + result |= (status & TD_CTRL_DBUFERR) ? USB_ST_BUF_ERR : 0; + result |= (status & TD_CTRL_BABBLE) ? USB_ST_BABBLE_DET : 0; + result |= (status & TD_CTRL_CRCTIMEO) ? USB_ST_CRC_ERR : 0; + result |= (status & TD_CTRL_BITSTUFF) ? USB_ST_BIT_ERR : 0; + result |= (status & TD_CTRL_ACTIVE) ? USB_ST_NOT_PROC : 0; + return result; +} + +/* get the status and the transfered len of a td chain. + * called from the completion handler + */ +int usb_get_td_status(uhci_td_t * td, struct usb_device *dev) +{ + unsigned long temp, info; + unsigned long stat; + uhci_td_t *mytd = td; + + if (dev->devnum == rh.devnum) + return 0; + dev->act_len = 0; + stat = 0; + do { + temp = swap_32((unsigned long)READ32(&mytd->status)); + stat = usb_uhci_td_stat(temp); + info = swap_32((unsigned long)READ32(&mytd->info)); + if (((info & 0xff) != USB_PID_SETUP) && (((info >> 21) & 0x7ff) != 0x7ff) && (temp & 0x7FF) != 0x7ff) { /* if not setup and not null data pack */ + dev->act_len += (temp & 0x7FF) + 1; /* the transfered len is act_len + 1 */ + } + if (stat) { /* status no ok */ + dev->status = stat; + return -1; + } + temp = swap_32((unsigned long)READ32(&mytd->link)); + mytd = (uhci_td_t *) (temp & 0xfffffff0); + } while ((temp & 0x1) == 0); /* process all TDs */ + dev->status = stat; + return 0; /* Ok */ +} + +/*------------------------------------------------------------------- + * LOW LEVEL STUFF + * assembles QHs und TDs for control, bulk and iso + *-------------------------------------------------------------------*/ +int dummy(void) +{ + USB_UHCI_PRINTF("DUMMY\n"); + return 0; +} + +/* Submits a control message. That is a Setup, Data and Status transfer. + * Routine does not wait for completion. + */ +int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer, + int transfer_len, struct devrequest *setup) +{ + unsigned long destination, status; + int maxsze = usb_maxpacket(dev, pipe); + unsigned long dataptr; + int len; + int pktsze; + int i = 0; + + if (!maxsze) { + USB_UHCI_PRINTF + ("uhci_submit_control_urb: pipesize for pipe %lx is zero\n", + pipe); + return -1; + } + if (((pipe >> 8) & 0x7f) == rh.devnum) { + /* this is the root hub -> redirect it */ + return uhci_submit_rh_msg(dev, pipe, buffer, transfer_len, + setup); + } + USB_UHCI_PRINTF("uhci_submit_control start len %x, maxsize %x\n", + transfer_len, maxsze); + /* The "pipe" thing contains the destination in bits 8--18 */ + destination = (pipe & PIPE_DEVEP_MASK) | USB_PID_SETUP; /* Setup stage */ + /* 3 errors */ + status = (pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | (3 << 27); + /* (urb->transfer_flags & USB_DISABLE_SPD ? 0 : TD_CTRL_SPD); */ + /* Build the TD for the control request, try forever, 8 bytes of data */ + usb_fill_td(&tmp_td[i], UHCI_PTR_TERM, status, destination | (7 << 21), + (unsigned long)setup, (unsigned long)dev); +#ifdef DEBUG_EXTRA + { + char *sp = (char *)setup; + printf("SETUP to pipe %lx: %x %x %x %x %x %x %x %x\n", pipe, + sp[0], sp[1], sp[2], sp[3], sp[4], sp[5], sp[6], sp[7]); + } +#endif + dataptr = (unsigned long)buffer; + len = transfer_len; + + /* If direction is "send", change the frame from SETUP (0x2D) + to OUT (0xE1). Else change it from SETUP to IN (0x69). */ + destination = + (pipe & PIPE_DEVEP_MASK) | ((pipe & USB_DIR_IN) == + 0 ? USB_PID_OUT : USB_PID_IN); + while (len > 0) { + /* data stage */ + pktsze = len; + i++; + if (pktsze > maxsze) + pktsze = maxsze; + destination ^= 1 << TD_TOKEN_TOGGLE; /* toggle DATA0/1 */ + usb_fill_td(&tmp_td[i], UHCI_PTR_TERM, status, destination | ((pktsze - 1) << 21), dataptr, (unsigned long)dev); /* Status, pktsze bytes of data */ + tmp_td[i - 1].link = swap_32((unsigned long)&tmp_td[i]); + + dataptr += pktsze; + len -= pktsze; + } + + /* Build the final TD for control status */ + /* It's only IN if the pipe is out AND we aren't expecting data */ + + destination &= ~UHCI_PID; + if (((pipe & USB_DIR_IN) == 0) || (transfer_len == 0)) + destination |= USB_PID_IN; + else + destination |= USB_PID_OUT; + destination |= 1 << TD_TOKEN_TOGGLE; /* End in Data1 */ + i++; + status &= ~TD_CTRL_SPD; + /* no limit on errors on final packet , 0 bytes of data */ + usb_fill_td(&tmp_td[i], UHCI_PTR_TERM, status | TD_CTRL_IOC, + destination | (UHCI_NULL_DATA_SIZE << 21), 0, + (unsigned long)dev); + tmp_td[i - 1].link = swap_32((unsigned long)&tmp_td[i]); /* queue status td */ + /* usb_show_td(i+1); */ + USB_UHCI_PRINTF("uhci_submit_control end (%d tmp_tds used)\n", i); + /* first mark the control QH element terminated */ + qh_cntrl.element = 0xffffffffL; + /* set qh active */ + qh_cntrl.dev_ptr = (unsigned long)dev; + /* fill in tmp_td_chain */ + dummy(); + qh_cntrl.element = swap_32((unsigned long)&tmp_td[0]); + return 0; +} + +/*------------------------------------------------------------------- + * Prepare TDs for bulk transfers. + */ +int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer, + int transfer_len) +{ + unsigned long destination, status, info; + unsigned long dataptr; + int maxsze = usb_maxpacket(dev, pipe); + int len; + int i = 0; + + if (transfer_len < 0) { + printf("Negative transfer length in submit_bulk\n"); + return -1; + } + if (!maxsze) + return -1; + /* The "pipe" thing contains the destination in bits 8--18. */ + destination = (pipe & PIPE_DEVEP_MASK) | usb_packetid(pipe); + /* 3 errors */ + status = (pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | (3 << 27); + /* ((urb->transfer_flags & USB_DISABLE_SPD) ? 0 : TD_CTRL_SPD) | (3 << 27); */ + /* Build the TDs for the bulk request */ + len = transfer_len; + dataptr = (unsigned long)buffer; + do { + int pktsze = len; + if (pktsze > maxsze) + pktsze = maxsze; + /* pktsze bytes of data */ + info = + destination | (((pktsze - 1) & UHCI_NULL_DATA_SIZE) << 21) | + (usb_gettoggle + (dev, usb_pipeendpoint(pipe), + usb_pipeout(pipe)) << TD_TOKEN_TOGGLE); + + if ((len - pktsze) == 0) + status |= TD_CTRL_IOC; /* last one generates INT */ + + usb_fill_td(&tmp_td[i], UHCI_PTR_TERM, status, info, dataptr, (unsigned long)dev); /* Status, pktsze bytes of data */ + if (i > 0) + tmp_td[i - 1].link = swap_32((unsigned long)&tmp_td[i]); + i++; + dataptr += pktsze; + len -= pktsze; + usb_dotoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)); + } while (len > 0); + /* first mark the bulk QH element terminated */ + qh_bulk.element = 0xffffffffL; + /* set qh active */ + qh_bulk.dev_ptr = (unsigned long)dev; + /* fill in tmp_td_chain */ + qh_bulk.element = swap_32((unsigned long)&tmp_td[0]); + return 0; +} + +/* search a free interrupt td + */ +uhci_td_t *uhci_alloc_int_td(void) +{ + int i; + for (i = 0; i < USB_MAX_TEMP_INT_TD; i++) { + if (tmp_int_td[i].dev_ptr == 0) /* no device assigned -> free TD */ + return &tmp_int_td[i]; + } + return NULL; +} + +/*------------------------------------------------------------------- + * submits USB interrupt (ie. polling ;-) + */ +int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer, + int transfer_len, int interval) +{ + int nint, n; + unsigned long status, destination; + unsigned long info, tmp; + uhci_td_t *mytd; + if (interval < 0 || interval >= 256) + return -1; + + if (interval == 0) + nint = 0; + else { + for (nint = 0, n = 1; nint <= 8; nint++, n += n) { /* round interval down to 2^n */ + if (interval < n) { + interval = n / 2; + break; + } + } + nint--; + } + + USB_UHCI_PRINTF("Rounded interval to %i, chain %i\n", interval, nint); + mytd = uhci_alloc_int_td(); + if (mytd == NULL) { + printf("No free INT TDs found\n"); + return -1; + } + status = (pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | TD_CTRL_IOC | (3 << 27); +/* (urb->transfer_flags & USB_DISABLE_SPD ? 0 : TD_CTRL_SPD) | (3 << 27); +*/ + + destination = + (pipe & PIPE_DEVEP_MASK) | usb_packetid(pipe) | + (((transfer_len - 1) & 0x7ff) << 21); + + info = + destination | + (usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)) << + TD_TOKEN_TOGGLE); + tmp = swap_32(td_int[nint].link); + usb_fill_td(mytd, tmp, status, info, (unsigned long)buffer, + (unsigned long)dev); + /* Link it */ + tmp = swap_32((unsigned long)mytd); + td_int[nint].link = tmp; + + usb_dotoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)); + + return 0; +} + +/********************************************************************** + * Low Level functions + */ + +void reset_hc(void) +{ + + /* Global reset for 100ms */ + out16r(usb_base_addr + USBPORTSC1, 0x0204); + out16r(usb_base_addr + USBPORTSC2, 0x0204); + out16r(usb_base_addr + USBCMD, USBCMD_GRESET | USBCMD_RS); + /* Turn off all interrupts */ + out16r(usb_base_addr + USBINTR, 0); + wait_ms(50); + out16r(usb_base_addr + USBCMD, 0); + wait_ms(10); +} + +void start_hc(void) +{ + int timeout = 1000; + + while (in16r(usb_base_addr + USBCMD) & USBCMD_HCRESET) { + if (!--timeout) { + printf("USBCMD_HCRESET timed out!\n"); + break; + } + } + /* Turn on all interrupts */ + out16r(usb_base_addr + USBINTR, + USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP); + /* Start at frame 0 */ + out16r(usb_base_addr + USBFRNUM, 0); + /* set Framebuffer base address */ + out32r(usb_base_addr + USBFLBASEADD, (unsigned long)&framelist); + /* Run and mark it configured with a 64-byte max packet */ + out16r(usb_base_addr + USBCMD, USBCMD_RS | USBCMD_CF | USBCMD_MAXP); +} + +/* Initialize the skeleton + */ +void usb_init_skel(void) +{ + unsigned long temp; + int n; + + for (n = 0; n < USB_MAX_TEMP_INT_TD; n++) + tmp_int_td[n].dev_ptr = 0L; /* no devices connected */ + /* last td */ + usb_fill_td(&td_last, UHCI_PTR_TERM, TD_CTRL_IOC, USB_PID_OUT, 0, 0L); + /* usb_fill_td(&td_last,UHCI_PTR_TERM,0,0,0); */ + /* End Queue Header */ + usb_fill_qh(&qh_end, UHCI_PTR_TERM, (unsigned long)&td_last); + /* Bulk Queue Header */ + temp = (unsigned long)&qh_end; + usb_fill_qh(&qh_bulk, temp | UHCI_PTR_QH, UHCI_PTR_TERM); + /* Control Queue Header */ + temp = (unsigned long)&qh_bulk; + usb_fill_qh(&qh_cntrl, temp | UHCI_PTR_QH, UHCI_PTR_TERM); + /* 1ms Interrupt td */ + temp = (unsigned long)&qh_cntrl; + usb_fill_td(&td_int[0], temp | UHCI_PTR_QH, 0, USB_PID_OUT, 0, 0L); + temp = (unsigned long)&td_int[0]; + for (n = 1; n < 8; n++) + usb_fill_td(&td_int[n], temp, 0, USB_PID_OUT, 0, 0L); + for (n = 0; n < 1024; n++) { + /* link all framelist pointers to one of the interrupts */ + int m, o; + if ((n & 127) == 127) + framelist[n] = swap_32((unsigned long)&td_int[0]); + else + for (o = 1, m = 2; m <= 128; o++, m += m) + if ((n & (m - 1)) == ((m - 1) / 2)) + framelist[n] = + swap_32((unsigned long)&td_int[o]); + + } +} + +/* check the common skeleton for completed transfers, and update the status + * of the "connected" device. Called from the IRQ routine. + */ +void usb_check_skel(void) +{ + struct usb_device *dev; + /* start with the control qh */ + if (qh_cntrl.dev_ptr != 0) { /* it's a device assigned check if this caused IRQ */ + dev = (struct usb_device *)qh_cntrl.dev_ptr; + /* Flush cache now that hardware updated DATA and TDs/QHs */ + if (!leon3_snooping_avail) + sparc_dcache_flush_all(); + usb_get_td_status(&tmp_td[0], dev); /* update status */ + if (!(dev->status & USB_ST_NOT_PROC)) { /* is not active anymore, disconnect devices */ + qh_cntrl.dev_ptr = 0; + } + } + /* now process the bulk */ + if (qh_bulk.dev_ptr != 0) { /* it's a device assigned check if this caused IRQ */ + dev = (struct usb_device *)qh_bulk.dev_ptr; + /* Flush cache now that hardware updated DATA and TDs/QHs */ + if (!leon3_snooping_avail) + sparc_dcache_flush_all(); + usb_get_td_status(&tmp_td[0], dev); /* update status */ + if (!(dev->status & USB_ST_NOT_PROC)) { /* is not active anymore, disconnect devices */ + qh_bulk.dev_ptr = 0; + } + } +} + +/* check the interrupt chain, ubdate the status of the appropriate device, + * call the appropriate irqhandler and reactivate the TD if the irqhandler + * returns with 1 + */ +void usb_check_int_chain(void) +{ + int i, res; + unsigned long link, status; + struct usb_device *dev; + uhci_td_t *td, *prevtd; + + for (i = 0; i < 8; i++) { + prevtd = &td_int[i]; /* the first previous td is the skeleton td */ + link = swap_32(READ32(&td_int[i].link)) & 0xfffffff0; /* next in chain */ + td = (uhci_td_t *) link; /* assign it */ + /* all interrupt TDs are finally linked to the td_int[0]. + * so we process all until we find the td_int[0]. + * if int0 chain points to a QH, we're also done + */ + while (((i > 0) && (link != (unsigned long)&td_int[0])) || + ((i == 0) + && !(swap_32(READ32(&td->link)) & UHCI_PTR_QH))) { + /* check if a device is assigned with this td */ + status = swap_32(READ32(&td->status)); + if ((td->dev_ptr != 0L) && !(status & TD_CTRL_ACTIVE)) { + /* td is not active and a device is assigned -> call irqhandler */ + dev = (struct usb_device *)td->dev_ptr; + dev->irq_act_len = ((status & 0x7FF) == 0x7FF) ? 0 : (status & 0x7FF) + 1; /* transfered length */ + dev->irq_status = usb_uhci_td_stat(status); /* get status */ + res = dev->irq_handle(dev); /* call irqhandler */ + if (res == 1) { + /* reactivate */ + status |= TD_CTRL_ACTIVE; + td->status = swap_32(status); + prevtd = td; /* previous td = this td */ + } else { + prevtd->link = READ32(&td->link); /* link previous td directly to the nex td -> unlinked */ + /* remove device pointer */ + td->dev_ptr = 0L; + } + } /* if we call the irq handler */ + link = swap_32(READ32(&td->link)) & 0xfffffff0; /* next in chain */ + td = (uhci_td_t *) link; /* assign it */ + } /* process all td in this int chain */ + } /* next interrupt chain */ +} + +/* usb interrupt service routine. + */ +void handle_usb_interrupt(void) +{ + unsigned short status; + static int error = 0; + + /* + * Read the interrupt status, and write it back to clear the + * interrupt cause + */ + + status = in16r(usb_base_addr + USBSTS); + + if (!status) /* shared interrupt, not mine */ + return; + if (status != 1) { + /* remove host controller halted state */ + if ((status & (USBSTS_HCPE | USBSTS_HCH)) == + (USBSTS_HCPE | USBSTS_HCH)) { + /* Stop due to bug in driver, or hardware */ + out16r(usb_base_addr + USBSTS, status); + out16r(usb_base_addr + USBCMD, + USBCMD_HCRESET | USBCMD_GRESET); + printf + ("GRUSB: HW detected error(s) in USB Descriptors (STS: 0x%x)\n", + status); + usb_show_td(8); + return; + } else if ((status & 0x20) + && ((in16r(usb_base_addr + USBCMD) & USBCMD_RS) == + 0)) { + if (error < 10) { + out16r(usb_base_addr + USBCMD, + USBCMD_RS | in16r(usb_base_addr + + USBCMD)); + error++; + } + } else + error = 0; + } + usb_check_int_chain(); /* call interrupt handlers for int tds */ + usb_check_skel(); /* call completion handler for common transfer routines */ + out16r(usb_base_addr + USBSTS, status); +} + +/* init uhci + */ +int usb_lowlevel_init(void) +{ + unsigned char temp; + ambapp_ahbdev ahbdev; + + /* Find GRUSB core using AMBA Plug&Play information */ + if (ambapp_ahbslv_first(VENDOR_GAISLER, GAISLER_UHCI, &ahbdev) != 1) { + printf("USB UHCI: Failed to find GRUSB controller\n"); + return -1; + } + usb_base_addr = ahbdev.address[0]; + grusb_irq = ahbdev.irq; + /* + usb_base_addr = 0xfffa0000; + grusb_irq = 10; + */ +#ifdef USB_UHCI_DEBUG + grusb_show_regs(); +#endif + memset(td_int, 0, sizeof(td_int)); + memset(tmp_td, 0, sizeof(tmp_td)); + memset(tmp_int_td, 0, sizeof(tmp_int_td)); + memset(&qh_cntrl, 0, sizeof(qh_cntrl)); + memset(&qh_end, 0, sizeof(qh_end)); + memset(&td_last, 0, sizeof(td_last)); + + irq_free_handler(grusb_irq); + USB_UHCI_PRINTF("GRUSB: at 0x%lx irq %d\n", usb_base_addr, grusb_irq); + rh.devnum = 0; + usb_init_skel(); + reset_hc(); + start_hc(); + irq_install_handler(grusb_irq, + (interrupt_handler_t *) handle_usb_interrupt, NULL); + return 0; +} + +/* stop uhci + */ +int usb_lowlevel_stop(void) +{ + if (grusb_irq == -1) + return 1; + irq_free_handler(grusb_irq); + reset_hc(); + grusb_irq = -1; + return 0; +} + +/******************************************************************************************* + * Virtual Root Hub + * Since the uhci does not have a real HUB, we simulate one ;-) + */ +#undef USB_RH_DEBUG + +#ifdef USB_RH_DEBUG +#define USB_RH_PRINTF(fmt,args...) printf (fmt ,##args) +static void usb_display_wValue(unsigned short wValue, unsigned short wIndex); +static void usb_display_Req(unsigned short req); +#else +#define USB_RH_PRINTF(fmt,args...) +static void usb_display_wValue(unsigned short wValue, unsigned short wIndex) +{ +} +static void usb_display_Req(unsigned short req) +{ +} +#endif + +static unsigned char root_hub_dev_des[] = { + 0x12, /* __u8 bLength; */ + 0x01, /* __u8 bDescriptorType; Device */ + 0x00, /* __u16 bcdUSB; v1.0 */ + 0x01, + 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */ + 0x00, /* __u8 bDeviceSubClass; */ + 0x00, /* __u8 bDeviceProtocol; */ + 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */ + 0x00, /* __u16 idVendor; */ + 0x00, + 0x00, /* __u16 idProduct; */ + 0x00, + 0x00, /* __u16 bcdDevice; */ + 0x00, + 0x01, /* __u8 iManufacturer; */ + 0x00, /* __u8 iProduct; */ + 0x00, /* __u8 iSerialNumber; */ + 0x01 /* __u8 bNumConfigurations; */ +}; + +/* Configuration descriptor */ +static unsigned char root_hub_config_des[] = { + 0x09, /* __u8 bLength; */ + 0x02, /* __u8 bDescriptorType; Configuration */ + 0x19, /* __u16 wTotalLength; */ + 0x00, + 0x01, /* __u8 bNumInterfaces; */ + 0x01, /* __u8 bConfigurationValue; */ + 0x00, /* __u8 iConfiguration; */ + 0x40, /* __u8 bmAttributes; + Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup, 4..0: resvd */ + 0x00, /* __u8 MaxPower; */ + + /* interface */ + 0x09, /* __u8 if_bLength; */ + 0x04, /* __u8 if_bDescriptorType; Interface */ + 0x00, /* __u8 if_bInterfaceNumber; */ + 0x00, /* __u8 if_bAlternateSetting; */ + 0x01, /* __u8 if_bNumEndpoints; */ + 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */ + 0x00, /* __u8 if_bInterfaceSubClass; */ + 0x00, /* __u8 if_bInterfaceProtocol; */ + 0x00, /* __u8 if_iInterface; */ + + /* endpoint */ + 0x07, /* __u8 ep_bLength; */ + 0x05, /* __u8 ep_bDescriptorType; Endpoint */ + 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */ + 0x03, /* __u8 ep_bmAttributes; Interrupt */ + 0x08, /* __u16 ep_wMaxPacketSize; 8 Bytes */ + 0x00, + 0xff /* __u8 ep_bInterval; 255 ms */ +}; + +static unsigned char root_hub_hub_des[] = { + 0x09, /* __u8 bLength; */ + 0x29, /* __u8 bDescriptorType; Hub-descriptor */ + 0x02, /* __u8 bNbrPorts; */ + 0x00, /* __u16 wHubCharacteristics; */ + 0x00, + 0x01, /* __u8 bPwrOn2pwrGood; 2ms */ + 0x00, /* __u8 bHubContrCurrent; 0 mA */ + 0x00, /* __u8 DeviceRemovable; *** 7 Ports max *** */ + 0xff /* __u8 PortPwrCtrlMask; *** 7 ports max *** */ +}; + +static unsigned char root_hub_str_index0[] = { + 0x04, /* __u8 bLength; */ + 0x03, /* __u8 bDescriptorType; String-descriptor */ + 0x09, /* __u8 lang ID */ + 0x04, /* __u8 lang ID */ +}; + +static unsigned char root_hub_str_index1[] = { + 28, /* __u8 bLength; */ + 0x03, /* __u8 bDescriptorType; String-descriptor */ + 'U', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + 'H', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + 'C', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + 'I', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + ' ', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + 'R', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + 'o', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + 'o', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + 't', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + ' ', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + 'H', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + 'u', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + 'b', /* __u8 Unicode */ + 0, /* __u8 Unicode */ +}; + +/* + * Root Hub Control Pipe (interrupt Pipes are not supported) + */ + +int uhci_submit_rh_msg(struct usb_device *dev, unsigned long pipe, void *buffer, + int transfer_len, struct devrequest *cmd) +{ + void *data = buffer; + int leni = transfer_len; + int len = 0; + int status = 0; + int stat = 0; + int i; + + unsigned short cstatus; + + unsigned short bmRType_bReq; + unsigned short wValue; + unsigned short wIndex; + unsigned short wLength; + + if (usb_pipeint(pipe)) { + printf("Root-Hub submit IRQ: NOT implemented\n"); + return 0; + } + bmRType_bReq = cmd->requesttype | cmd->request << 8; + wValue = swap_16(cmd->value); + wIndex = swap_16(cmd->index); + wLength = swap_16(cmd->length); + usb_display_Req(bmRType_bReq); + for (i = 0; i < 8; i++) + rh.c_p_r[i] = 0; + USB_RH_PRINTF("Root-Hub: adr: %2x cmd(%1x): %02x%02x %04x %04x %04x\n", + dev->devnum, 8, cmd->requesttype, cmd->request, wValue, + wIndex, wLength); + + switch (bmRType_bReq) { + /* Request Destination: + without flags: Device, + RH_INTERFACE: interface, + RH_ENDPOINT: endpoint, + RH_CLASS means HUB here, + RH_OTHER | RH_CLASS almost ever means HUB_PORT here + */ + + case RH_GET_STATUS: + *(unsigned short *)data = swap_16(1); + len = 2; + break; + case RH_GET_STATUS | RH_INTERFACE: + *(unsigned short *)data = swap_16(0); + len = 2; + break; + case RH_GET_STATUS | RH_ENDPOINT: + *(unsigned short *)data = swap_16(0); + len = 2; + break; + case RH_GET_STATUS | RH_CLASS: + *(unsigned long *)data = swap_32(0); + len = 4; + break; /* hub power ** */ + case RH_GET_STATUS | RH_OTHER | RH_CLASS: + + status = in16r(usb_base_addr + USBPORTSC1 + 2 * (wIndex - 1)); + cstatus = ((status & USBPORTSC_CSC) >> (1 - 0)) | + ((status & USBPORTSC_PEC) >> (3 - 1)) | + (rh.c_p_r[wIndex - 1] << (0 + 4)); + status = (status & USBPORTSC_CCS) | ((status & USBPORTSC_PE) >> (2 - 1)) | ((status & USBPORTSC_SUSP) >> (12 - 2)) | ((status & USBPORTSC_PR) >> (9 - 4)) | (1 << 8) | /* power on ** */ + ((status & USBPORTSC_LSDA) << (-8 + 9)); + + *(unsigned short *)data = swap_16(status); + *(unsigned short *)(data + 2) = swap_16(cstatus); + len = 4; + break; + case RH_CLEAR_FEATURE | RH_ENDPOINT: + switch (wValue) { + case (RH_ENDPOINT_STALL): + len = 0; + break; + } + break; + + case RH_CLEAR_FEATURE | RH_CLASS: + switch (wValue) { + case (RH_C_HUB_OVER_CURRENT): + len = 0; /* hub power over current ** */ + break; + } + break; + + case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS: + usb_display_wValue(wValue, wIndex); + switch (wValue) { + case (RH_PORT_ENABLE): + status = + in16r(usb_base_addr + USBPORTSC1 + + 2 * (wIndex - 1)); + status = (status & 0xfff5) & ~USBPORTSC_PE; + out16r(usb_base_addr + USBPORTSC1 + 2 * (wIndex - 1), + status); + len = 0; + break; + case (RH_PORT_SUSPEND): + status = + in16r(usb_base_addr + USBPORTSC1 + + 2 * (wIndex - 1)); + status = (status & 0xfff5) & ~USBPORTSC_SUSP; + out16r(usb_base_addr + USBPORTSC1 + 2 * (wIndex - 1), + status); + len = 0; + break; + case (RH_PORT_POWER): + len = 0; /* port power ** */ + break; + case (RH_C_PORT_CONNECTION): + status = + in16r(usb_base_addr + USBPORTSC1 + + 2 * (wIndex - 1)); + status = (status & 0xfff5) | USBPORTSC_CSC; + out16r(usb_base_addr + USBPORTSC1 + 2 * (wIndex - 1), + status); + len = 0; + break; + case (RH_C_PORT_ENABLE): + status = + in16r(usb_base_addr + USBPORTSC1 + + 2 * (wIndex - 1)); + status = (status & 0xfff5) | USBPORTSC_PEC; + out16r(usb_base_addr + USBPORTSC1 + 2 * (wIndex - 1), + status); + len = 0; + break; + case (RH_C_PORT_SUSPEND): +/*** WR_RH_PORTSTAT(RH_PS_PSSC); */ + len = 0; + break; + case (RH_C_PORT_OVER_CURRENT): + len = 0; + break; + case (RH_C_PORT_RESET): + rh.c_p_r[wIndex - 1] = 0; + len = 0; + break; + } + break; + case RH_SET_FEATURE | RH_OTHER | RH_CLASS: + usb_display_wValue(wValue, wIndex); + switch (wValue) { + case (RH_PORT_SUSPEND): + status = + in16r(usb_base_addr + USBPORTSC1 + + 2 * (wIndex - 1)); + status = (status & 0xfff5) | USBPORTSC_SUSP; + out16r(usb_base_addr + USBPORTSC1 + 2 * (wIndex - 1), + status); + len = 0; + break; + case (RH_PORT_RESET): + status = + in16r(usb_base_addr + USBPORTSC1 + + 2 * (wIndex - 1)); + status = (status & 0xfff5) | USBPORTSC_PR; + out16r(usb_base_addr + USBPORTSC1 + 2 * (wIndex - 1), + status); + wait_ms(10); + status = (status & 0xfff5) & ~USBPORTSC_PR; + out16r(usb_base_addr + USBPORTSC1 + 2 * (wIndex - 1), + status); + udelay(10); + status = (status & 0xfff5) | USBPORTSC_PE; + out16r(usb_base_addr + USBPORTSC1 + 2 * (wIndex - 1), + status); + wait_ms(10); + status = (status & 0xfff5) | 0xa; + out16r(usb_base_addr + USBPORTSC1 + 2 * (wIndex - 1), + status); + len = 0; + break; + case (RH_PORT_POWER): + len = 0; /* port power ** */ + break; + case (RH_PORT_ENABLE): + status = + in16r(usb_base_addr + USBPORTSC1 + + 2 * (wIndex - 1)); + status = (status & 0xfff5) | USBPORTSC_PE; + out16r(usb_base_addr + USBPORTSC1 + 2 * (wIndex - 1), + status); + len = 0; + break; + } + break; + + case RH_SET_ADDRESS: + rh.devnum = wValue; + len = 0; + break; + case RH_GET_DESCRIPTOR: + switch ((wValue & 0xff00) >> 8) { + case (0x01): /* device descriptor */ + i = sizeof(root_hub_config_des); + status = i > wLength ? wLength : i; + len = leni > status ? status : leni; + memcpy(data, root_hub_dev_des, len); + break; + case (0x02): /* configuration descriptor */ + i = sizeof(root_hub_config_des); + status = i > wLength ? wLength : i; + len = leni > status ? status : leni; + memcpy(data, root_hub_config_des, len); + break; + case (0x03): /*string descriptors */ + if (wValue == 0x0300) { + i = sizeof(root_hub_str_index0); + status = i > wLength ? wLength : i; + len = leni > status ? status : leni; + memcpy(data, root_hub_str_index0, len); + break; + } + if (wValue == 0x0301) { + i = sizeof(root_hub_str_index1); + status = i > wLength ? wLength : i; + len = leni > status ? status : leni; + memcpy(data, root_hub_str_index1, len); + break; + } + stat = USB_ST_STALLED; + } + break; + + case RH_GET_DESCRIPTOR | RH_CLASS: + root_hub_hub_des[2] = 2; + i = sizeof(root_hub_hub_des); + status = i > wLength ? wLength : i; + len = leni > status ? status : leni; + memcpy(data, root_hub_hub_des, len); + break; + case RH_GET_CONFIGURATION: + *(unsigned char *)data = 0x01; + len = 1; + break; + case RH_SET_CONFIGURATION: + len = 0; + break; + default: + stat = USB_ST_STALLED; + } + USB_RH_PRINTF("Root-Hub stat %lx port1: %x port2: %x\n\n", stat, + in16r(usb_base_addr + USBPORTSC1), + in16r(usb_base_addr + USBPORTSC2)); + dev->act_len = len; + dev->status = stat; + return stat; + +} + +/******************************************************************************** + * Some Debug Routines + */ + +#ifdef USB_RH_DEBUG + +static void usb_display_Req(unsigned short req) +{ + USB_RH_PRINTF("- Root-Hub Request: "); + switch (req) { + case RH_GET_STATUS: + USB_RH_PRINTF("Get Status "); + break; + case RH_GET_STATUS | RH_INTERFACE: + USB_RH_PRINTF("Get Status Interface "); + break; + case RH_GET_STATUS | RH_ENDPOINT: + USB_RH_PRINTF("Get Status Endpoint "); + break; + case RH_GET_STATUS | RH_CLASS: + USB_RH_PRINTF("Get Status Class"); + break; /* hub power ** */ + case RH_GET_STATUS | RH_OTHER | RH_CLASS: + USB_RH_PRINTF("Get Status Class Others"); + break; + case RH_CLEAR_FEATURE | RH_ENDPOINT: + USB_RH_PRINTF("Clear Feature Endpoint "); + break; + case RH_CLEAR_FEATURE | RH_CLASS: + USB_RH_PRINTF("Clear Feature Class "); + break; + case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS: + USB_RH_PRINTF("Clear Feature Other Class "); + break; + case RH_SET_FEATURE | RH_OTHER | RH_CLASS: + USB_RH_PRINTF("Set Feature Other Class "); + break; + case RH_SET_ADDRESS: + USB_RH_PRINTF("Set Address "); + break; + case RH_GET_DESCRIPTOR: + USB_RH_PRINTF("Get Descriptor "); + break; + case RH_GET_DESCRIPTOR | RH_CLASS: + USB_RH_PRINTF("Get Descriptor Class "); + break; + case RH_GET_CONFIGURATION: + USB_RH_PRINTF("Get Configuration "); + break; + case RH_SET_CONFIGURATION: + USB_RH_PRINTF("Get Configuration "); + break; + default: + USB_RH_PRINTF("****UNKNOWN**** 0x%04X ", req); + } + USB_RH_PRINTF("\n"); + +} + +static void usb_display_wValue(unsigned short wValue, unsigned short wIndex) +{ + switch (wValue) { + case (RH_PORT_ENABLE): + USB_RH_PRINTF("Root-Hub: Enable Port %d\n", wIndex); + break; + case (RH_PORT_SUSPEND): + USB_RH_PRINTF("Root-Hub: Suspend Port %d\n", wIndex); + break; + case (RH_PORT_POWER): + USB_RH_PRINTF("Root-Hub: Port Power %d\n", wIndex); + break; + case (RH_C_PORT_CONNECTION): + USB_RH_PRINTF("Root-Hub: C Port Connection Port %d\n", wIndex); + break; + case (RH_C_PORT_ENABLE): + USB_RH_PRINTF("Root-Hub: C Port Enable Port %d\n", wIndex); + break; + case (RH_C_PORT_SUSPEND): + USB_RH_PRINTF("Root-Hub: C Port Suspend Port %d\n", wIndex); + break; + case (RH_C_PORT_OVER_CURRENT): + USB_RH_PRINTF("Root-Hub: C Port Over Current Port %d\n", + wIndex); + break; + case (RH_C_PORT_RESET): + USB_RH_PRINTF("Root-Hub: C Port reset Port %d\n", wIndex); + break; + default: + USB_RH_PRINTF("Root-Hub: unknown %x %x\n", wValue, wIndex); + break; + } +} + +#endif + +/*#ifdef USB_UHCI_DEBUG*/ + +static int usb_display_td(uhci_td_t * td) +{ + unsigned long tmp; + int valid; + + printf("TD at %p:\n", td); + + tmp = swap_32(READ32(&td->link)); + printf("Link points to 0x%08lX, %s first, %s, %s\n", tmp & 0xfffffff0, + ((tmp & 0x4) == 0x4) ? "Depth" : "Breath", + ((tmp & 0x2) == 0x2) ? "QH" : "TD", + ((tmp & 0x1) == 0x1) ? "invalid" : "valid"); + valid = ((tmp & 0x1) == 0x0); + tmp = swap_32(READ32(&td->status)); + printf + (" %s %ld Errors %s %s %s \n %s %s %s %s %s %s\n Len 0x%lX\n", + (((tmp >> 29) & 0x1) == 0x1) ? "SPD Enable" : "SPD Disable", + ((tmp >> 28) & 0x3), + (((tmp >> 26) & 0x1) == 0x1) ? "Low Speed" : "Full Speed", + (((tmp >> 25) & 0x1) == 0x1) ? "ISO " : "", + (((tmp >> 24) & 0x1) == 0x1) ? "IOC " : "", + (((tmp >> 23) & 0x1) == 0x1) ? "Active " : "Inactive ", + (((tmp >> 22) & 0x1) == 0x1) ? "Stalled" : "", + (((tmp >> 21) & 0x1) == 0x1) ? "Data Buffer Error" : "", + (((tmp >> 20) & 0x1) == 0x1) ? "Babble" : "", + (((tmp >> 19) & 0x1) == 0x1) ? "NAK" : "", + (((tmp >> 18) & 0x1) == 0x1) ? "Bitstuff Error" : "", + (tmp & 0x7ff)); + tmp = swap_32(READ32(&td->info)); + printf(" MaxLen 0x%lX\n", ((tmp >> 21) & 0x7FF)); + printf(" %sEndpoint 0x%lX Dev Addr 0x%lX PID 0x%lX\n", + ((tmp >> 19) & 0x1) == 0x1 ? "TOGGLE " : "", ((tmp >> 15) & 0xF), + ((tmp >> 8) & 0x7F), tmp & 0xFF); + tmp = swap_32(READ32(&td->buffer)); + printf(" Buffer 0x%08lX\n", tmp); + printf(" DEV %08lX\n", td->dev_ptr); + return valid; +} + +void usb_show_td(int max) +{ + int i; + if (max > 0) { + for (i = 0; i < max; i++) { + usb_display_td(&tmp_td[i]); + } + } else { + i = 0; + do { + printf("tmp_td[%d]\n", i); + } while (usb_display_td(&tmp_td[i++])); + } +} + +void grusb_show_regs(void) +{ + unsigned int tmp; + + tmp = in16r(usb_base_addr + USBCMD); + printf(" USBCMD: 0x%04x\n", tmp); + tmp = in16r(usb_base_addr + USBSTS); + printf(" USBSTS: 0x%04x\n", tmp); + tmp = in16r(usb_base_addr + USBINTR); + printf(" USBINTR: 0x%04x\n", tmp); + tmp = in16r(usb_base_addr + USBFRNUM); + printf(" FRNUM: 0x%04x\n", tmp); + tmp = in32r(usb_base_addr + USBFLBASEADD); + printf(" FLBASEADD: 0x%08x\n", tmp); + tmp = in16r(usb_base_addr + USBSOF); + printf(" SOFMOD: 0x%04x\n", tmp); + tmp = in16r(usb_base_addr + USBPORTSC1); + printf(" PORTSC1: 0x%04x\n", tmp); +} + +/*#endif*/ +#endif /* CONFIG_USB_UHCI */ + +/* EOF */ diff --git a/arch/sparc/cpu/leon3/usb_uhci.h b/arch/sparc/cpu/leon3/usb_uhci.h new file mode 100644 index 0000000..bf572a6 --- /dev/null +++ b/arch/sparc/cpu/leon3/usb_uhci.h @@ -0,0 +1,184 @@ +/* + * (C) Copyright 2001 + * Denis Peter, MPL AG Switzerland + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 program is distributed in the hope that 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 + * + * Note: Part of this code has been derived from linux + * + */ +#ifndef _USB_UHCI_H_ +#define _USB_UHCI_H_ + +/* Command register */ +#define USBCMD 0 +#define USBCMD_RS 0x0001 /* Run/Stop */ +#define USBCMD_HCRESET 0x0002 /* Host reset */ +#define USBCMD_GRESET 0x0004 /* Global reset */ +#define USBCMD_EGSM 0x0008 /* Global Suspend Mode */ +#define USBCMD_FGR 0x0010 /* Force Global Resume */ +#define USBCMD_SWDBG 0x0020 /* SW Debug mode */ +#define USBCMD_CF 0x0040 /* Config Flag (sw only) */ +#define USBCMD_MAXP 0x0080 /* Max Packet (0 = 32, 1 = 64) */ + +/* Status register */ +#define USBSTS 2 +#define USBSTS_USBINT 0x0001 /* Interrupt due to IOC */ +#define USBSTS_ERROR 0x0002 /* Interrupt due to error */ +#define USBSTS_RD 0x0004 /* Resume Detect */ +#define USBSTS_HSE 0x0008 /* Host System Error - basically PCI problems */ +#define USBSTS_HCPE 0x0010 /* Host Controller Process Error - the scripts were buggy */ +#define USBSTS_HCH 0x0020 /* HC Halted */ + +/* Interrupt enable register */ +#define USBINTR 4 +#define USBINTR_TIMEOUT 0x0001 /* Timeout/CRC error enable */ +#define USBINTR_RESUME 0x0002 /* Resume interrupt enable */ +#define USBINTR_IOC 0x0004 /* Interrupt On Complete enable */ +#define USBINTR_SP 0x0008 /* Short packet interrupt enable */ + +#define USBFRNUM 6 +#define USBFLBASEADD 8 +#define USBSOF 12 + +/* USB port status and control registers */ +#define USBPORTSC1 16 +#define USBPORTSC2 18 +#define USBPORTSC_CCS 0x0001 /* Current Connect Status ("device present") */ +#define USBPORTSC_CSC 0x0002 /* Connect Status Change */ +#define USBPORTSC_PE 0x0004 /* Port Enable */ +#define USBPORTSC_PEC 0x0008 /* Port Enable Change */ +#define USBPORTSC_LS 0x0030 /* Line Status */ +#define USBPORTSC_RD 0x0040 /* Resume Detect */ +#define USBPORTSC_LSDA 0x0100 /* Low Speed Device Attached */ +#define USBPORTSC_PR 0x0200 /* Port Reset */ +#define USBPORTSC_SUSP 0x1000 /* Suspend */ + +/* Legacy support register */ +#define USBLEGSUP 0xc0 +#define USBLEGSUP_DEFAULT 0x2000 /* only PIRQ enable set */ + +#define UHCI_NULL_DATA_SIZE 0x7ff /* for UHCI controller TD */ +#define UHCI_PID 0xff /* PID MASK */ + +#define UHCI_PTR_BITS 0x000F +#define UHCI_PTR_TERM 0x0001 +#define UHCI_PTR_QH 0x0002 +#define UHCI_PTR_DEPTH 0x0004 + +/* for TD <status>: */ +#define TD_CTRL_SPD (1 << 29) /* Short Packet Detect */ +#define TD_CTRL_C_ERR_MASK (3 << 27) /* Error Counter bits */ +#define TD_CTRL_LS (1 << 26) /* Low Speed Device */ +#define TD_CTRL_IOS (1 << 25) /* Isochronous Select */ +#define TD_CTRL_IOC (1 << 24) /* Interrupt on Complete */ +#define TD_CTRL_ACTIVE (1 << 23) /* TD Active */ +#define TD_CTRL_STALLED (1 << 22) /* TD Stalled */ +#define TD_CTRL_DBUFERR (1 << 21) /* Data Buffer Error */ +#define TD_CTRL_BABBLE (1 << 20) /* Babble Detected */ +#define TD_CTRL_NAK (1 << 19) /* NAK Received */ +#define TD_CTRL_CRCTIMEO (1 << 18) /* CRC/Time Out Error */ +#define TD_CTRL_BITSTUFF (1 << 17) /* Bit Stuff Error */ +#define TD_CTRL_ACTLEN_MASK 0x7ff /* actual length, encoded as n - 1 */ + +#define TD_CTRL_ANY_ERROR (TD_CTRL_STALLED | TD_CTRL_DBUFERR | \ + TD_CTRL_BABBLE | TD_CTRL_CRCTIME | TD_CTRL_BITSTUFF) + +#define TD_TOKEN_TOGGLE 19 + +/* ------------------------------------------------------------------------------------ + Virtual Root HUB + ------------------------------------------------------------------------------------ */ +/* destination of request */ +#define RH_INTERFACE 0x01 +#define RH_ENDPOINT 0x02 +#define RH_OTHER 0x03 + +#define RH_CLASS 0x20 +#define RH_VENDOR 0x40 + +/* Requests: bRequest << 8 | bmRequestType */ +#define RH_GET_STATUS 0x0080 +#define RH_CLEAR_FEATURE 0x0100 +#define RH_SET_FEATURE 0x0300 +#define RH_SET_ADDRESS 0x0500 +#define RH_GET_DESCRIPTOR 0x0680 +#define RH_SET_DESCRIPTOR 0x0700 +#define RH_GET_CONFIGURATION 0x0880 +#define RH_SET_CONFIGURATION 0x0900 +#define RH_GET_STATE 0x0280 +#define RH_GET_INTERFACE 0x0A80 +#define RH_SET_INTERFACE 0x0B00 +#define RH_SYNC_FRAME 0x0C80 +/* Our Vendor Specific Request */ +#define RH_SET_EP 0x2000 + +/* Hub port features */ +#define RH_PORT_CONNECTION 0x00 +#define RH_PORT_ENABLE 0x01 +#define RH_PORT_SUSPEND 0x02 +#define RH_PORT_OVER_CURRENT 0x03 +#define RH_PORT_RESET 0x04 +#define RH_PORT_POWER 0x08 +#define RH_PORT_LOW_SPEED 0x09 +#define RH_C_PORT_CONNECTION 0x10 +#define RH_C_PORT_ENABLE 0x11 +#define RH_C_PORT_SUSPEND 0x12 +#define RH_C_PORT_OVER_CURRENT 0x13 +#define RH_C_PORT_RESET 0x14 + +/* Hub features */ +#define RH_C_HUB_LOCAL_POWER 0x00 +#define RH_C_HUB_OVER_CURRENT 0x01 + +#define RH_DEVICE_REMOTE_WAKEUP 0x00 +#define RH_ENDPOINT_STALL 0x01 + +/* Our Vendor Specific feature */ +#define RH_REMOVE_EP 0x00 + +#define RH_ACK 0x01 +#define RH_REQ_ERR -1 +#define RH_NACK 0x00 + +/* Transfer descriptor structure */ +typedef struct { + unsigned long link; /* next td/qh (LE) */ + unsigned long status; /* status of the td */ + unsigned long info; /* Max Lenght / Endpoint / device address and PID */ + unsigned long buffer; /* pointer to data buffer (LE) */ + unsigned long dev_ptr; /* pointer to the assigned device (BE) */ + unsigned long res[3]; /* reserved (TDs must be 8Byte aligned) */ +} uhci_td_t, *puhci_td_t; + +/* Queue Header structure */ +typedef struct { + unsigned long head; /* Next QH (LE) */ + unsigned long element; /* Queue element pointer (LE) */ + unsigned long res[5]; /* reserved */ + unsigned long dev_ptr; /* if 0 no tds have been assigned to this qh */ +} uhci_qh_t, *puhci_qh_t; + +struct virt_root_hub { + int devnum; /* Address of Root Hub endpoint */ + int numports; /* number of ports */ + int c_p_r[8]; /* C_PORT_RESET */ +}; + +#endif /* _USB_UHCI_H_ */ diff --git a/arch/sparc/include/asm/arch-leon2/asi.h b/arch/sparc/include/asm/arch-leon2/asi.h new file mode 100644 index 0000000..38fdd5c --- /dev/null +++ b/arch/sparc/include/asm/arch-leon2/asi.h @@ -0,0 +1,36 @@ +/* asi.h: Address Space Identifier values for the LEON2 sparc. + * + * Copyright (C) 2008 Daniel Hellstrom (daniel@gaisler.com) + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 program is distributed in the hope that 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 + * + */ + +#ifndef _LEON2_ASI_H +#define _LEON2_ASI_H + +#define ASI_CACHEMISS 0x01 /* Force D-Cache miss on load (lda) */ +#define ASI_M_FLUSH_PROBE 0x03 /* MMU Flush/Probe */ +#define ASI_IFLUSH 0x05 /* Flush I-Cache */ +#define ASI_DFLUSH 0x06 /* Flush D-Cache */ +#define ASI_BYPASS 0x1c /* Bypass MMU (Physical address) */ +#define ASI_MMUFLUSH 0x18 /* FLUSH TLB */ +#define ASI_M_MMUREGS 0x19 /* READ/Write MMU Registers */ + +#endif /* _LEON2_ASI_H */ diff --git a/arch/sparc/include/asm/arch-leon3/asi.h b/arch/sparc/include/asm/arch-leon3/asi.h new file mode 100644 index 0000000..700b3ca --- /dev/null +++ b/arch/sparc/include/asm/arch-leon3/asi.h @@ -0,0 +1,36 @@ +/* asi.h: Address Space Identifier values for the LEON3 sparc. + * + * Copyright (C) 2008 Daniel Hellstrom (daniel@gaisler.com) + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 program is distributed in the hope that 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 + * + */ + +#ifndef _LEON3_ASI_H +#define _LEON3_ASI_H + +#define ASI_CACHEMISS 0x01 /* Force D-Cache miss on load (lda) */ +#define ASI_M_FLUSH_PROBE 0x03 /* MMU Flush/Probe */ +#define ASI_IFLUSH 0x10 /* Flush I-Cache */ +#define ASI_DFLUSH 0x11 /* Flush D-Cache */ +#define ASI_BYPASS 0x1c /* Bypass MMU (Physical address) */ +#define ASI_MMUFLUSH 0x18 /* FLUSH TLB */ +#define ASI_M_MMUREGS 0x19 /* READ/Write MMU Registers */ + +#endif /* _LEON3_ASI_H */ diff --git a/arch/sparc/include/asm/asi.h b/arch/sparc/include/asm/asi.h new file mode 100644 index 0000000..bf6d70f --- /dev/null +++ b/arch/sparc/include/asm/asi.h @@ -0,0 +1,32 @@ +/* Address Space Identifier (ASI) values for sparc processors. + * + * (C) Copyright 2008 + * Daniel Hellstrom, Gaisler Research, daniel@gaisler.com. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 program is distributed in the hope that 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 + * + */ + +#ifndef _SPARC_ASI_H +#define _SPARC_ASI_H + +/* ASI numbers are processor implementation specific */ +#include <asm/arch/asi.h> + +#endif /* _SPARC_ASI_H */ diff --git a/arch/sparc/include/asm/asmmacro.h b/arch/sparc/include/asm/asmmacro.h new file mode 100644 index 0000000..aeb87ee --- /dev/null +++ b/arch/sparc/include/asm/asmmacro.h @@ -0,0 +1,45 @@ +/* Assembler macros for SPARC + * + * (C) Copyright 2007, taken from linux asm-sparc/asmmacro.h + * Daniel Hellstrom, Gaisler Research, daniel@gaisler.com. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 program is distributed in the hope that 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 + * + */ + +#ifndef __SPARC_ASMMACRO_H__ +#define __SPARC_ASMMACRO_H__ + +#include <config.h> + +/* All trap entry points _must_ begin with this macro or else you + * lose. It makes sure the kernel has a proper window so that + * c-code can be called. + */ +#define SAVE_ALL_HEAD \ + sethi %hi(trap_setup+(CONFIG_SYS_RELOC_MONITOR_BASE-TEXT_BASE)), %l4; \ + jmpl %l4 + %lo(trap_setup+(CONFIG_SYS_RELOC_MONITOR_BASE-TEXT_BASE)), %l6; +#define SAVE_ALL \ + SAVE_ALL_HEAD \ + nop; + +/* All traps low-level code here must end with this macro. */ +#define RESTORE_ALL b ret_trap_entry; clr %l6; + +#endif diff --git a/arch/sparc/include/asm/atomic.h b/arch/sparc/include/asm/atomic.h new file mode 100644 index 0000000..636498d --- /dev/null +++ b/arch/sparc/include/asm/atomic.h @@ -0,0 +1,29 @@ +/* SPARC atomic operations + * + * (C) Copyright 2008 + * Daniel Hellstrom, Gaisler Research, daniel@gaisler.com. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 program is distributed in the hope that 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 + * + */ + +#ifndef _ASM_SPARC_ATOMIC_H_ +#define _ASM_SPARC_ATOMIC_H_ + +#endif /* _ASM_SPARC_ATOMIC_H_ */ diff --git a/arch/sparc/include/asm/bitops.h b/arch/sparc/include/asm/bitops.h new file mode 100644 index 0000000..ceb39f2 --- /dev/null +++ b/arch/sparc/include/asm/bitops.h @@ -0,0 +1,29 @@ +/* Bit string operations on the SPARC + * + * (C) Copyright 2007, taken from asm-ppc/bitops.h + * Daniel Hellstrom, Gaisler Research, daniel@gaisler.com. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 program is distributed in the hope that 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 + * + */ + +#ifndef _SPARC_BITOPS_H +#define _SPARC_BITOPS_H + +#endif /* _SPARC_BITOPS_H */ diff --git a/arch/sparc/include/asm/byteorder.h b/arch/sparc/include/asm/byteorder.h new file mode 100644 index 0000000..b9fc656 --- /dev/null +++ b/arch/sparc/include/asm/byteorder.h @@ -0,0 +1,37 @@ +/* + * (C) Copyright 2002 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * (C) Copyright 2008 + * Daniel Hellstrom, Gaisler Research, daniel@gaisler.com. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 program is distributed in the hope that 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 + * + */ + +#ifndef _SPARC_BYTEORDER_H +#define _SPARC_BYTEORDER_H + +#include <asm/types.h> + +#if defined(__GNUC__) && !defined(__STRICT_ANSI__) +#define __BYTEORDER_HAS_U64__ +#endif +#include <linux/byteorder/big_endian.h> +#endif /* _SPARC_BYTEORDER_H */ diff --git a/arch/sparc/include/asm/cache.h b/arch/sparc/include/asm/cache.h new file mode 100644 index 0000000..03e8d94 --- /dev/null +++ b/arch/sparc/include/asm/cache.h @@ -0,0 +1,31 @@ +/* + * (C) Copyright 2008, + * Daniel Hellstrom, Gaisler Research, daniel@gaisler.com. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 program is distributed in the hope that 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 + * + */ + +#ifndef __SPARC_CACHE_H__ +#define __SPARC_CACHE_H__ + +#include <linux/config.h> +#include <asm/processor.h> + +#endif diff --git a/arch/sparc/include/asm/config.h b/arch/sparc/include/asm/config.h new file mode 100644 index 0000000..36438be --- /dev/null +++ b/arch/sparc/include/asm/config.h @@ -0,0 +1,26 @@ +/* + * Copyright 2009 Freescale Semiconductor, Inc. + * + * 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 program is distributed in the hope that 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 + * + */ + +#ifndef _ASM_CONFIG_H_ +#define _ASM_CONFIG_H_ + +#define CONFIG_LMB + +#endif diff --git a/arch/sparc/include/asm/errno.h b/arch/sparc/include/asm/errno.h new file mode 100644 index 0000000..4c82b50 --- /dev/null +++ b/arch/sparc/include/asm/errno.h @@ -0,0 +1 @@ +#include <asm-generic/errno.h> diff --git a/arch/sparc/include/asm/global_data.h b/arch/sparc/include/asm/global_data.h new file mode 100644 index 0000000..dea2857 --- /dev/null +++ b/arch/sparc/include/asm/global_data.h @@ -0,0 +1,89 @@ +/* + * (C) Copyright 2002 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * (C) Copyright 2007 + * Daniel Hellstrom, Gaisler Research, daniel@gaisler.com. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 program is distributed in the hope that 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 + */ + +#ifndef __ASM_GBL_DATA_H +#define __ASM_GBL_DATA_H + +#include "asm/types.h" + +/* + * The following data structure is placed in some memory wich is + * available very early after boot (like DPRAM on MPC8xx/MPC82xx, or + * some locked parts of the data cache) to allow for a minimum set of + * global variables during system initialization (until we have set + * up the memory controller so that we can use RAM). + * + * Keep it *SMALL* and remember to set CONFIG_SYS_GBL_DATA_SIZE > sizeof(gd_t) + */ + +typedef struct global_data { + bd_t *bd; + unsigned long flags; + unsigned long baudrate; + unsigned long cpu_clk; /* CPU clock in Hz! */ + unsigned long bus_clk; + + phys_size_t ram_size; /* RAM size */ + unsigned long reloc_off; /* Relocation Offset */ + unsigned long reset_status; /* reset status register at boot */ + unsigned long env_addr; /* Address of Environment struct */ + unsigned long env_valid; /* Checksum of Environment valid? */ + unsigned long have_console; /* serial_init() was called */ + +#if defined(CONFIG_LCD) || defined(CONFIG_VIDEO) + unsigned long fb_base; /* Base address of framebuffer memory */ +#endif +#if defined(CONFIG_POST) || defined(CONFIG_LOGBUFFER) + unsigned long post_log_word; /* Record POST activities */ + unsigned long post_init_f_time; /* When post_init_f started */ +#endif +#ifdef CONFIG_BOARD_TYPES + unsigned long board_type; +#endif +#ifdef CONFIG_MODEM_SUPPORT + unsigned long do_mdm_init; + unsigned long be_quiet; +#endif +#ifdef CONFIG_LWMON + unsigned long kbd_status; +#endif + void **jt; /* jump table */ +} gd_t; + +/* + * Global Data Flags + */ +#define GD_FLG_RELOC 0x00001 /* Code was relocated to RAM */ +#define GD_FLG_DEVINIT 0x00002 /* Devices have been initialized */ +#define GD_FLG_SILENT 0x00004 /* Silent mode */ +#define GD_FLG_POSTFAIL 0x00008 /* Critical POST test failed */ +#define GD_FLG_POSTSTOP 0x00010 /* POST seqeunce aborted */ +#define GD_FLG_LOGINIT 0x00020 /* Log Buffer has been initialized */ +#define GD_FLG_DISABLE_CONSOLE 0x00040 /* Disable console (in & out) */ + +#define DECLARE_GLOBAL_DATA_PTR register volatile gd_t *gd asm ("%g7") + +#endif /* __ASM_GBL_DATA_H */ diff --git a/arch/sparc/include/asm/io.h b/arch/sparc/include/asm/io.h new file mode 100644 index 0000000..0c5d86c --- /dev/null +++ b/arch/sparc/include/asm/io.h @@ -0,0 +1,98 @@ +/* SPARC I/O definitions + * + * (C) Copyright 2007 + * Daniel Hellstrom, Gaisler Research, daniel@gaisler.com. + * + * 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 program is distributed in the hope that 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 + * + */ + +#ifndef _SPARC_IO_H +#define _SPARC_IO_H + +/* Nothing to sync, total store ordering (TSO)... */ +#define sync() + +/* Forces a cache miss on read/load. + * On some architectures we need to bypass the cache when reading + * I/O registers so that we are not reading the same status word + * over and over again resulting in a hang (until an IRQ if lucky) + * + */ +#ifndef CONFIG_SYS_HAS_NO_CACHE +#define READ_BYTE(var) SPARC_NOCACHE_READ_BYTE((unsigned int)(var)) +#define READ_HWORD(var) SPARC_NOCACHE_READ_HWORD((unsigned int)(var)) +#define READ_WORD(var) SPARC_NOCACHE_READ((unsigned int)(var)) +#define READ_DWORD(var) SPARC_NOCACHE_READ_DWORD((unsigned int)(var)) +#else +#define READ_BYTE(var) (var) +#define READ_HWORD(var) (var) +#define READ_WORD(var) (var) +#define READ_DWORD(var) (var) +#endif + +/* + * Generic virtual read/write. + */ +#define __arch_getb(a) (READ_BYTE(a)) +#define __arch_getw(a) (READ_HWORD(a)) +#define __arch_getl(a) (READ_WORD(a)) +#define __arch_getq(a) (READ_DWORD(a)) + +#define __arch_putb(v,a) (*(volatile unsigned char *)(a) = (v)) +#define __arch_putw(v,a) (*(volatile unsigned short *)(a) = (v)) +#define __arch_putl(v,a) (*(volatile unsigned int *)(a) = (v)) + +#define __raw_writeb(v,a) __arch_putb(v,a) +#define __raw_writew(v,a) __arch_putw(v,a) +#define __raw_writel(v,a) __arch_putl(v,a) + +#define __raw_readb(a) __arch_getb(a) +#define __raw_readw(a) __arch_getw(a) +#define __raw_readl(a) __arch_getl(a) +#define __raw_readq(a) __arch_getq(a) + +/* + * Given a physical address and a length, return a virtual address + * that can be used to access the memory range with the caching + * properties specified by "flags". + */ + +#define MAP_NOCACHE (0) +#define MAP_WRCOMBINE (0) +#define MAP_WRBACK (0) +#define MAP_WRTHROUGH (0) + +static inline void *map_physmem(phys_addr_t paddr, unsigned long len, + unsigned long flags) +{ + return (void *)paddr; +} + +/* + * Take down a mapping set up by map_physmem(). + */ +static inline void unmap_physmem(void *vaddr, unsigned long flags) +{ + +} + +static inline phys_addr_t virt_to_phys(void * vaddr) +{ + return (phys_addr_t)(vaddr); +} + +#endif diff --git a/arch/sparc/include/asm/irq.h b/arch/sparc/include/asm/irq.h new file mode 100644 index 0000000..c5538c0 --- /dev/null +++ b/arch/sparc/include/asm/irq.h @@ -0,0 +1,49 @@ +/* IRQ functions + * + * (C) Copyright 2007 + * Daniel Hellstrom, Gaisler Research, daniel@gaisler.com. + * + * 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 program is distributed in the hope that 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 + * + */ + +#ifndef __SPARC_IRQ_H__ +#define __SPARC_IRQ_H__ + +#include <asm/psr.h> + +/* Set SPARC Processor Interrupt Level */ +extern inline void set_pil(unsigned int level) +{ + unsigned int psr = get_psr(); + + put_psr((psr & ~PSR_PIL) | ((level & 0xf) << PSR_PIL_OFS)); +} + +/* Get SPARC Processor Interrupt Level */ +extern inline unsigned int get_pil(void) +{ + unsigned int psr = get_psr(); + return (psr & PSR_PIL) >> PSR_PIL_OFS; +} + +/* Disables interrupts and return current PIL value */ +extern int intLock(void); + +/* Sets the PIL to oldLevel */ +extern void intUnlock(int oldLevel); + +#endif diff --git a/arch/sparc/include/asm/leon.h b/arch/sparc/include/asm/leon.h new file mode 100644 index 0000000..f7175ee --- /dev/null +++ b/arch/sparc/include/asm/leon.h @@ -0,0 +1,42 @@ +/* LEON Header File select + * + * (C) Copyright 2007 + * Daniel Hellstrom, Gaisler Research, daniel@gaisler.com. + * + * 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 program is distributed in the hope that 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 + * + */ + +#ifndef __ASM_LEON_H__ +#define __ASM_LEON_H__ + +#if defined(CONFIG_LEON3) + +#include <asm/leon3.h> + +#elif defined(CONFIG_LEON2) + +#include <asm/leon2.h> + +#else + +#error Unknown LEON processor + +#endif + +/* Common stuff */ + +#endif diff --git a/arch/sparc/include/asm/leon2.h b/arch/sparc/include/asm/leon2.h new file mode 100644 index 0000000..fa55cad --- /dev/null +++ b/arch/sparc/include/asm/leon2.h @@ -0,0 +1,236 @@ +/* LEON2 header file. LEON2 is a SOC processor. + * + * (C) Copyright 2008 + * Daniel Hellstrom, Gaisler Research, daniel@gaisler.com. + * + * 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 program is distributed in the hope that 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 + * + */ + +#ifndef __LEON2_H__ +#define __LEON2_H__ + +#ifdef CONFIG_LEON2 + +/* LEON 2 I/O register definitions */ +#define LEON2_PREGS 0x80000000 +#define LEON2_MCFG1 0x00 +#define LEON2_MCFG2 0x04 +#define LEON2_ECTRL 0x08 +#define LEON2_FADDR 0x0C +#define LEON2_MSTAT 0x10 +#define LEON2_CCTRL 0x14 +#define LEON2_PWDOWN 0x18 +#define LEON2_WPROT1 0x1C +#define LEON2_WPROT2 0x20 +#define LEON2_LCONF 0x24 +#define LEON2_TCNT0 0x40 +#define LEON2_TRLD0 0x44 +#define LEON2_TCTRL0 0x48 +#define LEON2_TCNT1 0x50 +#define LEON2_TRLD1 0x54 +#define LEON2_TCTRL1 0x58 +#define LEON2_SCNT 0x60 +#define LEON2_SRLD 0x64 +#define LEON2_UART0 0x70 +#define LEON2_UDATA0 0x70 +#define LEON2_USTAT0 0x74 +#define LEON2_UCTRL0 0x78 +#define LEON2_USCAL0 0x7C +#define LEON2_UART1 0x80 +#define LEON2_UDATA1 0x80 +#define LEON2_USTAT1 0x84 +#define LEON2_UCTRL1 0x88 +#define LEON2_USCAL1 0x8C +#define LEON2_IMASK 0x90 +#define LEON2_IPEND 0x94 +#define LEON2_IFORCE 0x98 +#define LEON2_ICLEAR 0x9C +#define LEON2_IOREG 0xA0 +#define LEON2_IODIR 0xA4 +#define LEON2_IOICONF 0xA8 +#define LEON2_IPEND2 0xB0 +#define LEON2_IMASK2 0xB4 +#define LEON2_ISTAT2 0xB8 +#define LEON2_ICLEAR2 0xBC + +#ifndef __ASSEMBLER__ +/* + * Structure for LEON memory mapped registers. + * + * Source: Section 6.1 - On-chip registers + * + * NOTE: There is only one of these structures per CPU, its base address + * is 0x80000000, and the variable LEON_REG is placed there by the + * linkcmds file. + */ +typedef struct { + volatile unsigned int Memory_Config_1; + volatile unsigned int Memory_Config_2; + volatile unsigned int Edac_Control; + volatile unsigned int Failed_Address; + volatile unsigned int Memory_Status; + volatile unsigned int Cache_Control; + volatile unsigned int Power_Down; + volatile unsigned int Write_Protection_1; + volatile unsigned int Write_Protection_2; + volatile unsigned int Leon_Configuration; + volatile unsigned int dummy2; + volatile unsigned int dummy3; + volatile unsigned int dummy4; + volatile unsigned int dummy5; + volatile unsigned int dummy6; + volatile unsigned int dummy7; + volatile unsigned int Timer_Counter_1; + volatile unsigned int Timer_Reload_1; + volatile unsigned int Timer_Control_1; + volatile unsigned int Watchdog; + volatile unsigned int Timer_Counter_2; + volatile unsigned int Timer_Reload_2; + volatile unsigned int Timer_Control_2; + volatile unsigned int dummy8; + volatile unsigned int Scaler_Counter; + volatile unsigned int Scaler_Reload; + volatile unsigned int dummy9; + volatile unsigned int dummy10; + volatile unsigned int UART_Channel_1; + volatile unsigned int UART_Status_1; + volatile unsigned int UART_Control_1; + volatile unsigned int UART_Scaler_1; + volatile unsigned int UART_Channel_2; + volatile unsigned int UART_Status_2; + volatile unsigned int UART_Control_2; + volatile unsigned int UART_Scaler_2; + volatile unsigned int Interrupt_Mask; + volatile unsigned int Interrupt_Pending; + volatile unsigned int Interrupt_Force; + volatile unsigned int Interrupt_Clear; + volatile unsigned int PIO_Data; + volatile unsigned int PIO_Direction; + volatile unsigned int PIO_Interrupt; +} LEON2_regs; + +typedef struct { + volatile unsigned int UART_Channel; + volatile unsigned int UART_Status; + volatile unsigned int UART_Control; + volatile unsigned int UART_Scaler; +} LEON2_Uart_regs; + +#endif + +/* + * The following constants are intended to be used ONLY in assembly + * language files. + * + * NOTE: The intended style of usage is to load the address of LEON REGS + * into a register and then use these as displacements from + * that register. + */ +#define LEON_REG_MEMCFG1_OFFSET 0x00 +#define LEON_REG_MEMCFG2_OFFSET 0x04 +#define LEON_REG_EDACCTRL_OFFSET 0x08 +#define LEON_REG_FAILADDR_OFFSET 0x0C +#define LEON_REG_MEMSTATUS_OFFSET 0x10 +#define LEON_REG_CACHECTRL_OFFSET 0x14 +#define LEON_REG_POWERDOWN_OFFSET 0x18 +#define LEON_REG_WRITEPROT1_OFFSET 0x1C +#define LEON_REG_WRITEPROT2_OFFSET 0x20 +#define LEON_REG_LEONCONF_OFFSET 0x24 +#define LEON_REG_UNIMPLEMENTED_2_OFFSET 0x28 +#define LEON_REG_UNIMPLEMENTED_3_OFFSET 0x2C +#define LEON_REG_UNIMPLEMENTED_4_OFFSET 0x30 +#define LEON_REG_UNIMPLEMENTED_5_OFFSET 0x34 +#define LEON_REG_UNIMPLEMENTED_6_OFFSET 0x38 +#define LEON_REG_UNIMPLEMENTED_7_OFFSET 0x3C +#define LEON_REG_TIMERCNT1_OFFSET 0x40 +#define LEON_REG_TIMERLOAD1_OFFSET 0x44 +#define LEON_REG_TIMERCTRL1_OFFSET 0x48 +#define LEON_REG_WDOG_OFFSET 0x4C +#define LEON_REG_TIMERCNT2_OFFSET 0x50 +#define LEON_REG_TIMERLOAD2_OFFSET 0x54 +#define LEON_REG_TIMERCTRL2_OFFSET 0x58 +#define LEON_REG_UNIMPLEMENTED_8_OFFSET 0x5C +#define LEON_REG_SCALERCNT_OFFSET 0x60 +#define LEON_REG_SCALER_LOAD_OFFSET 0x64 +#define LEON_REG_UNIMPLEMENTED_9_OFFSET 0x68 +#define LEON_REG_UNIMPLEMENTED_10_OFFSET 0x6C +#define LEON_REG_UARTDATA1_OFFSET 0x70 +#define LEON_REG_UARTSTATUS1_OFFSET 0x74 +#define LEON_REG_UARTCTRL1_OFFSET 0x78 +#define LEON_REG_UARTSCALER1_OFFSET 0x7C +#define LEON_REG_UARTDATA2_OFFSET 0x80 +#define LEON_REG_UARTSTATUS2_OFFSET 0x84 +#define LEON_REG_UARTCTRL2_OFFSET 0x88 +#define LEON_REG_UARTSCALER2_OFFSET 0x8C +#define LEON_REG_IRQMASK_OFFSET 0x90 +#define LEON_REG_IRQPEND_OFFSET 0x94 +#define LEON_REG_IRQFORCE_OFFSET 0x98 +#define LEON_REG_IRQCLEAR_OFFSET 0x9C +#define LEON_REG_PIODATA_OFFSET 0xA0 +#define LEON_REG_PIODIR_OFFSET 0xA4 +#define LEON_REG_PIOIRQ_OFFSET 0xA8 +#define LEON_REG_SIM_RAM_SIZE_OFFSET 0xF4 +#define LEON_REG_SIM_ROM_SIZE_OFFSET 0xF8 + +/* + * Interrupt Sources + * + * The interrupt source numbers directly map to the trap type and to + * the bits used in the Interrupt Clear, Interrupt Force, Interrupt Mask, + * and the Interrupt Pending Registers. + */ +#define LEON_INTERRUPT_CORRECTABLE_MEMORY_ERROR 1 +#define LEON_INTERRUPT_UART_1_RX_TX 2 +#define LEON_INTERRUPT_UART_0_RX_TX 3 +#define LEON_INTERRUPT_EXTERNAL_0 4 +#define LEON_INTERRUPT_EXTERNAL_1 5 +#define LEON_INTERRUPT_EXTERNAL_2 6 +#define LEON_INTERRUPT_EXTERNAL_3 7 +#define LEON_INTERRUPT_TIMER1 8 +#define LEON_INTERRUPT_TIMER2 9 +#define LEON_INTERRUPT_EMPTY1 10 +#define LEON_INTERRUPT_EMPTY2 11 +#define LEON_INTERRUPT_OPEN_ETH 12 +#define LEON_INTERRUPT_EMPTY4 13 +#define LEON_INTERRUPT_EMPTY5 14 +#define LEON_INTERRUPT_EMPTY6 15 + +/* Timer Bits */ +#define LEON2_TIMER_CTRL_EN 0x1 /* Timer enable */ +#define LEON2_TIMER_CTRL_RS 0x2 /* Timer reStart */ +#define LEON2_TIMER_CTRL_LD 0x4 /* Timer reLoad */ +#define LEON2_TIMER1_IRQNO 8 /* Timer 1 IRQ number */ +#define LEON2_TIMER2_IRQNO 9 /* Timer 2 IRQ number */ +#define LEON2_TIMER1_IE (1<<LEON2_TIMER1_IRQNO) /* Timer 1 interrupt enable */ +#define LEON2_TIMER2_IE (1<<LEON2_TIMER2_IRQNO) /* Timer 2 interrupt enable */ + +/* UART bits */ +#define LEON2_UART_CTRL_RE 1 /* UART Receiver enable */ +#define LEON2_UART_CTRL_TE 2 /* UART Transmitter enable */ +#define LEON2_UART_CTRL_RI 4 /* UART Receiver Interrupt enable */ +#define LEON2_UART_CTRL_TI 8 /* UART Transmitter Interrupt enable */ +#define LEON2_UART_CTRL_DBG (1<<11) /* Debug Bit used by GRMON */ + +#define LEON2_UART_STAT_DR 1 /* UART Data Ready */ +#define LEON2_UART_STAT_TSE 2 /* UART Transmit Shift Reg empty */ +#define LEON2_UART_STAT_THE 4 /* UART Transmit Hold Reg empty */ + +#else +#error Include LEON2 header file only if LEON2 processor +#endif + +#endif diff --git a/arch/sparc/include/asm/leon3.h b/arch/sparc/include/asm/leon3.h new file mode 100644 index 0000000..b90d35b --- /dev/null +++ b/arch/sparc/include/asm/leon3.h @@ -0,0 +1,36 @@ +/* LEON3 header file. LEON3 is a free GPL SOC processor available + * at www.gaisler.com. + * + * (C) Copyright 2007 + * Daniel Hellstrom, Gaisler Research, daniel@gaisler.com. + * + * 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 program is distributed in the hope that 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 + * + */ + +#ifndef __LEON3_H__ +#define __LEON3_H__ + +#ifndef CONFIG_LEON3 +#error Include LEON3 header file only if LEON3 processor +#endif + +/* Not much to define, most is Plug and Play and GRLIB dependent + * not LEON3 dependent. See <ambapp.h> for GRLIB timers, interrupt + * ctrl, memory controllers etc. + */ + +#endif diff --git a/arch/sparc/include/asm/machines.h b/arch/sparc/include/asm/machines.h new file mode 100644 index 0000000..1e26195 --- /dev/null +++ b/arch/sparc/include/asm/machines.h @@ -0,0 +1,92 @@ +/* machines.h: Defines for taking apart the machine type value in the + * idprom and determining the kind of machine we are on. + * + * Taken from the SPARC port of Linux. + * + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 2007 Daniel Hellstrom (daniel@gaisler.com) + * + * 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 program is distributed in the hope that 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 + * + */ + +#ifndef __SPARC_MACHINES_H__ +#define __SPARC_MACHINES_H__ + +struct Sun_Machine_Models { + char *name; + unsigned char id_machtype; +}; + +/* Current number of machines we know about that has an IDPROM + * machtype entry including one entry for the 0x80 OBP machines. + */ +#define NUM_SUN_MACHINES 16 + +extern struct Sun_Machine_Models Sun_Machines[NUM_SUN_MACHINES]; + +/* The machine type in the idprom area looks like this: + * + * --------------- + * | ARCH | MACH | + * --------------- + * 7 4 3 0 + * + * The ARCH field determines the architecture line (sun4, sun4c, etc). + * The MACH field determines the machine make within that architecture. + */ + +#define SM_ARCH_MASK 0xf0 +#define SM_SUN4 0x20 +#define M_LEON2 0x30 +#define SM_SUN4C 0x50 +#define SM_SUN4M 0x70 +#define SM_SUN4M_OBP 0x80 + +#define SM_TYP_MASK 0x0f +/* Sun4 machines */ +#define SM_4_260 0x01 /* Sun 4/200 series */ +#define SM_4_110 0x02 /* Sun 4/100 series */ +#define SM_4_330 0x03 /* Sun 4/300 series */ +#define SM_4_470 0x04 /* Sun 4/400 series */ + +/* Leon machines */ +#define M_LEON2_SOC 0x01 /* Leon2 SoC */ + +/* Sun4c machines Full Name - PROM NAME */ +#define SM_4C_SS1 0x01 /* Sun4c SparcStation 1 - Sun 4/60 */ +#define SM_4C_IPC 0x02 /* Sun4c SparcStation IPC - Sun 4/40 */ +#define SM_4C_SS1PLUS 0x03 /* Sun4c SparcStation 1+ - Sun 4/65 */ +#define SM_4C_SLC 0x04 /* Sun4c SparcStation SLC - Sun 4/20 */ +#define SM_4C_SS2 0x05 /* Sun4c SparcStation 2 - Sun 4/75 */ +#define SM_4C_ELC 0x06 /* Sun4c SparcStation ELC - Sun 4/25 */ +#define SM_4C_IPX 0x07 /* Sun4c SparcStation IPX - Sun 4/50 */ + +/* Sun4m machines, these predate the OpenBoot. These values only mean + * something if the value in the ARCH field is SM_SUN4M, if it is + * SM_SUN4M_OBP then you have the following situation: + * 1) You either have a sun4d, a sun4e, or a recently made sun4m. + * 2) You have to consult OpenBoot to determine which machine this is. + */ +#define SM_4M_SS60 0x01 /* Sun4m SparcSystem 600 */ +#define SM_4M_SS50 0x02 /* Sun4m SparcStation 10 */ +#define SM_4M_SS40 0x03 /* Sun4m SparcStation 5 */ + +/* Sun4d machines -- N/A */ +/* Sun4e machines -- N/A */ +/* Sun4u machines -- N/A */ + +#endif /* !(_SPARC_MACHINES_H) */ diff --git a/arch/sparc/include/asm/page.h b/arch/sparc/include/asm/page.h new file mode 100644 index 0000000..484953a --- /dev/null +++ b/arch/sparc/include/asm/page.h @@ -0,0 +1,43 @@ +/* page.h: Various defines and such for MMU operations on the Sparc for + * the Linux kernel. + * + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 2007 Daniel Hellstrom (daniel@gaisler.com) + * + * 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 program is distributed in the hope that 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 + * + */ + +#ifndef _SPARC_PAGE_H +#define _SPARC_PAGE_H + +#include <linux/config.h> +#ifdef CONFIG_SUN4 +#define PAGE_SHIFT 13 +#else +#define PAGE_SHIFT 12 +#endif + +#ifndef __ASSEMBLY__ +/* I have my suspicions... -DaveM */ +#define PAGE_SIZE (1UL << PAGE_SHIFT) +#else +#define PAGE_SIZE (1 << PAGE_SHIFT) +#endif + +#define PAGE_MASK (~(PAGE_SIZE-1)) + +#endif /* _SPARC_PAGE_H */ diff --git a/arch/sparc/include/asm/posix_types.h b/arch/sparc/include/asm/posix_types.h new file mode 100644 index 0000000..8d98b2a --- /dev/null +++ b/arch/sparc/include/asm/posix_types.h @@ -0,0 +1,139 @@ +/* + * (C) Copyright 2000 - 2002 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * (C) Copyright 2007, taken from asm-ppc/posix_types.h + * Daniel Hellstrom, Gaisler Research, daniel@gaisler.com. + * + * 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 program is distributed in the hope that 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 + * + */ + +#ifndef __SPARC_POSIX_TYPES_H__ +#define __SPARC_POSIX_TYPES_H__ + +/* + * This file is generally used by user-level software, so you need to + * be a little careful about namespace pollution etc. Also, we cannot + * assume GCC is being used. + */ + +typedef unsigned int __kernel_dev_t; +typedef unsigned int __kernel_ino_t; +typedef unsigned int __kernel_mode_t; +typedef unsigned short __kernel_nlink_t; +typedef long __kernel_off_t; +typedef int __kernel_pid_t; +typedef unsigned int __kernel_uid_t; +typedef unsigned int __kernel_gid_t; +typedef unsigned int __kernel_size_t; +typedef int __kernel_ssize_t; +typedef long __kernel_ptrdiff_t; +typedef long __kernel_time_t; +typedef long __kernel_suseconds_t; +typedef long __kernel_clock_t; +typedef int __kernel_daddr_t; +typedef char *__kernel_caddr_t; +typedef short __kernel_ipc_pid_t; +typedef unsigned short __kernel_uid16_t; +typedef unsigned short __kernel_gid16_t; +typedef unsigned int __kernel_uid32_t; +typedef unsigned int __kernel_gid32_t; + +typedef unsigned int __kernel_old_uid_t; +typedef unsigned int __kernel_old_gid_t; + +#ifdef __GNUC__ +typedef long long __kernel_loff_t; +#endif + +typedef struct { + int val[2]; +} __kernel_fsid_t; + +#ifndef __GNUC__ + +#define __FD_SET(d, set) ((set)->fds_bits[__FDELT(d)] |= __FDMASK(d)) +#define __FD_CLR(d, set) ((set)->fds_bits[__FDELT(d)] &= ~__FDMASK(d)) +#define __FD_ISSET(d, set) ((set)->fds_bits[__FDELT(d)] & __FDMASK(d)) +#define __FD_ZERO(set) \ + ((void) memset ((__ptr_t) (set), 0, sizeof (__kernel_fd_set))) + +#else /* __GNUC__ */ + +#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) \ + || (__GLIBC__ == 2 && __GLIBC_MINOR__ == 0) +/* With GNU C, use inline functions instead so args are evaluated only once: */ + +#undef __FD_SET +static __inline__ void __FD_SET(unsigned long fd, __kernel_fd_set * fdsetp) +{ + unsigned long _tmp = fd / __NFDBITS; + unsigned long _rem = fd % __NFDBITS; + fdsetp->fds_bits[_tmp] |= (1UL << _rem); +} + +#undef __FD_CLR +static __inline__ void __FD_CLR(unsigned long fd, __kernel_fd_set * fdsetp) +{ + unsigned long _tmp = fd / __NFDBITS; + unsigned long _rem = fd % __NFDBITS; + fdsetp->fds_bits[_tmp] &= ~(1UL << _rem); +} + +#undef __FD_ISSET +static __inline__ int __FD_ISSET(unsigned long fd, __kernel_fd_set * p) +{ + unsigned long _tmp = fd / __NFDBITS; + unsigned long _rem = fd % __NFDBITS; + return (p->fds_bits[_tmp] & (1UL << _rem)) != 0; +} + +/* + * This will unroll the loop for the normal constant case (8 ints, + * for a 256-bit fd_set) + */ +#undef __FD_ZERO +static __inline__ void __FD_ZERO(__kernel_fd_set * p) +{ + unsigned int *tmp = (unsigned int *)p->fds_bits; + int i; + + if (__builtin_constant_p(__FDSET_LONGS)) { + switch (__FDSET_LONGS) { + case 8: + tmp[0] = 0; + tmp[1] = 0; + tmp[2] = 0; + tmp[3] = 0; + tmp[4] = 0; + tmp[5] = 0; + tmp[6] = 0; + tmp[7] = 0; + return; + } + } + i = __FDSET_LONGS; + while (i) { + i--; + *tmp = 0; + tmp++; + } +} + +#endif /* defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) */ +#endif /* __GNUC__ */ +#endif /* _SPARC_POSIX_TYPES_H */ diff --git a/arch/sparc/include/asm/processor.h b/arch/sparc/include/asm/processor.h new file mode 100644 index 0000000..d518389 --- /dev/null +++ b/arch/sparc/include/asm/processor.h @@ -0,0 +1,116 @@ +/* SPARC Processor specifics + * taken from the SPARC port of Linux (ptrace.h). + * + * (C) Copyright 2007 + * Daniel Hellstrom, Gaisler Research, daniel@gaisler.com. + * + * 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 program is distributed in the hope that 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 + * + */ + +#ifndef __ASM_SPARC_PROCESSOR_H +#define __ASM_SPARC_PROCESSOR_H + +#include <asm/arch/asi.h> + +#ifdef CONFIG_LEON + +/* All LEON processors supported */ +#include <asm/leon.h> + +#else +/* other processors */ +#error Unknown SPARC Processor +#endif + +#ifndef __ASSEMBLY__ + +/* flush data cache */ +static __inline__ void sparc_dcache_flush_all(void) +{ + __asm__ __volatile__("sta %%g0, [%%g0] %0\n\t"::"i"(ASI_DFLUSH):"memory"); +} + +/* flush instruction cache */ +static __inline__ void sparc_icache_flush_all(void) +{ + __asm__ __volatile__("sta %%g0, [%%g0] %0\n\t"::"i"(ASI_IFLUSH):"memory"); +} + +/* do a cache miss load */ +static __inline__ unsigned long long sparc_load_reg_cachemiss_qword(unsigned + long paddr) +{ + unsigned long long retval; + __asm__ __volatile__("ldda [%1] %2, %0\n\t": + "=r"(retval):"r"(paddr), "i"(ASI_CACHEMISS)); + return retval; +} + +static __inline__ unsigned long sparc_load_reg_cachemiss(unsigned long paddr) +{ + unsigned long retval; + __asm__ __volatile__("lda [%1] %2, %0\n\t": + "=r"(retval):"r"(paddr), "i"(ASI_CACHEMISS)); + return retval; +} + +static __inline__ unsigned short sparc_load_reg_cachemiss_word(unsigned long + paddr) +{ + unsigned short retval; + __asm__ __volatile__("lduha [%1] %2, %0\n\t": + "=r"(retval):"r"(paddr), "i"(ASI_CACHEMISS)); + return retval; +} + +static __inline__ unsigned char sparc_load_reg_cachemiss_byte(unsigned long + paddr) +{ + unsigned char retval; + __asm__ __volatile__("lduba [%1] %2, %0\n\t": + "=r"(retval):"r"(paddr), "i"(ASI_CACHEMISS)); + return retval; +} + +/* do a physical address bypass write, i.e. for 0x80000000 */ +static __inline__ void sparc_store_reg_bypass(unsigned long paddr, + unsigned long value) +{ + __asm__ __volatile__("sta %0, [%1] %2\n\t"::"r"(value), "r"(paddr), + "i"(ASI_BYPASS):"memory"); +} + +static __inline__ unsigned long sparc_load_reg_bypass(unsigned long paddr) +{ + unsigned long retval; + __asm__ __volatile__("lda [%1] %2, %0\n\t": + "=r"(retval):"r"(paddr), "i"(ASI_BYPASS)); + return retval; +} + +/* Macros for bypassing cache when reading */ +#define SPARC_NOCACHE_READ_DWORD(address) sparc_load_reg_cachemiss_qword((unsigned int)(address)) +#define SPARC_NOCACHE_READ(address) sparc_load_reg_cachemiss((unsigned int)(address)) +#define SPARC_NOCACHE_READ_HWORD(address) sparc_load_reg_cachemiss_word((unsigned int)(address)) +#define SPARC_NOCACHE_READ_BYTE(address) sparc_load_reg_cachemiss_byte((unsigned int)(address)) + +#define SPARC_BYPASS_READ(address) sparc_load_reg_bypass((unsigned int)(address)) +#define SPARC_BYPASS_WRITE(address,value) sparc_store_reg_bypass((unsigned int)(address),(unsigned int)(value)) + +#endif + +#endif /* __ASM_SPARC_PROCESSOR_H */ diff --git a/arch/sparc/include/asm/prom.h b/arch/sparc/include/asm/prom.h new file mode 100644 index 0000000..d55cc86 --- /dev/null +++ b/arch/sparc/include/asm/prom.h @@ -0,0 +1,297 @@ +/* OpenProm defines mainly taken from linux kernel header files + * + * openprom.h: Prom structures and defines for access to the OPENBOOT + * prom routines and data areas. + * + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 2007 Daniel Hellstrom (daniel@gaisler.com) + * + * 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 program is distributed in the hope that 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 + * + */ + +#ifndef __SPARC_OPENPROM_H__ +#define __SPARC_OPENPROM_H__ + +/* Empirical constants... */ +#define LINUX_OPPROM_MAGIC 0x10010407 + +#ifndef __ASSEMBLY__ +/* V0 prom device operations. */ +struct linux_dev_v0_funcs { + int (*v0_devopen) (char *device_str); + int (*v0_devclose) (int dev_desc); + int (*v0_rdblkdev) (int dev_desc, int num_blks, int blk_st, char *buf); + int (*v0_wrblkdev) (int dev_desc, int num_blks, int blk_st, char *buf); + int (*v0_wrnetdev) (int dev_desc, int num_bytes, char *buf); + int (*v0_rdnetdev) (int dev_desc, int num_bytes, char *buf); + int (*v0_rdchardev) (int dev_desc, int num_bytes, int dummy, char *buf); + int (*v0_wrchardev) (int dev_desc, int num_bytes, int dummy, char *buf); + int (*v0_seekdev) (int dev_desc, long logical_offst, int from); +}; + +/* V2 and later prom device operations. */ +struct linux_dev_v2_funcs { + int (*v2_inst2pkg) (int d); /* Convert ihandle to phandle */ + char *(*v2_dumb_mem_alloc) (char *va, unsigned sz); + void (*v2_dumb_mem_free) (char *va, unsigned sz); + + /* To map devices into virtual I/O space. */ + char *(*v2_dumb_mmap) (char *virta, int which_io, unsigned paddr, + unsigned sz); + void (*v2_dumb_munmap) (char *virta, unsigned size); + + int (*v2_dev_open) (char *devpath); + void (*v2_dev_close) (int d); + int (*v2_dev_read) (int d, char *buf, int nbytes); + int (*v2_dev_write) (int d, char *buf, int nbytes); + int (*v2_dev_seek) (int d, int hi, int lo); + + /* Never issued (multistage load support) */ + void (*v2_wheee2) (void); + void (*v2_wheee3) (void); +}; + +struct linux_mlist_v0 { + struct linux_mlist_v0 *theres_more; + char *start_adr; + unsigned num_bytes; +}; + +struct linux_mem_v0 { + struct linux_mlist_v0 **v0_totphys; + struct linux_mlist_v0 **v0_prommap; + struct linux_mlist_v0 **v0_available; /* What we can use */ +}; + +/* Arguments sent to the kernel from the boot prompt. */ +struct linux_arguments_v0 { + char *argv[8]; + char args[100]; + char boot_dev[2]; + int boot_dev_ctrl; + int boot_dev_unit; + int dev_partition; + char *kernel_file_name; + void *aieee1; /* XXX */ +}; + +/* V2 and up boot things. */ +struct linux_bootargs_v2 { + char **bootpath; + char **bootargs; + int *fd_stdin; + int *fd_stdout; +}; + +/* The top level PROM vector. */ +struct linux_romvec { + /* Version numbers. */ + unsigned int pv_magic_cookie; + unsigned int pv_romvers; + unsigned int pv_plugin_revision; + unsigned int pv_printrev; + + /* Version 0 memory descriptors. */ + struct linux_mem_v0 pv_v0mem; + + /* Node operations. */ + struct linux_nodeops *pv_nodeops; + + char **pv_bootstr; + struct linux_dev_v0_funcs pv_v0devops; + + char *pv_stdin; + char *pv_stdout; +#define PROMDEV_KBD 0 /* input from keyboard */ +#define PROMDEV_SCREEN 0 /* output to screen */ +#define PROMDEV_TTYA 1 /* in/out to ttya */ +#define PROMDEV_TTYB 2 /* in/out to ttyb */ + + /* Blocking getchar/putchar. NOT REENTRANT! (grr) */ + int (*pv_getchar) (void); + void (*pv_putchar) (int ch); + + /* Non-blocking variants. */ + int (*pv_nbgetchar) (void); + int (*pv_nbputchar) (int ch); + + void (*pv_putstr) (char *str, int len); + + /* Miscellany. */ + void (*pv_reboot) (char *bootstr); + void (*pv_printf) (__const__ char *fmt, ...); + void (*pv_abort) (void); + __volatile__ int *pv_ticks; + void (*pv_halt) (void); + void (**pv_synchook) (void); + + /* Evaluate a forth string, not different proto for V0 and V2->up. */ + union { + void (*v0_eval) (int len, char *str); + void (*v2_eval) (char *str); + } pv_fortheval; + + struct linux_arguments_v0 **pv_v0bootargs; + + /* Get ether address. */ + unsigned int (*pv_enaddr) (int d, char *enaddr); + + struct linux_bootargs_v2 pv_v2bootargs; + struct linux_dev_v2_funcs pv_v2devops; + + int filler[15]; + + /* This one is sun4c/sun4 only. */ + void (*pv_setctxt) (int ctxt, char *va, int pmeg); + + /* Prom version 3 Multiprocessor routines. This stuff is crazy. + * No joke. Calling these when there is only one cpu probably + * crashes the machine, have to test this. :-) + */ + + /* v3_cpustart() will start the cpu 'whichcpu' in mmu-context + * 'thiscontext' executing at address 'prog_counter' + */ + int (*v3_cpustart) (unsigned int whichcpu, int ctxtbl_ptr, + int thiscontext, char *prog_counter); + + /* v3_cpustop() will cause cpu 'whichcpu' to stop executing + * until a resume cpu call is made. + */ + int (*v3_cpustop) (unsigned int whichcpu); + + /* v3_cpuidle() will idle cpu 'whichcpu' until a stop or + * resume cpu call is made. + */ + int (*v3_cpuidle) (unsigned int whichcpu); + + /* v3_cpuresume() will resume processor 'whichcpu' executing + * starting with whatever 'pc' and 'npc' were left at the + * last 'idle' or 'stop' call. + */ + int (*v3_cpuresume) (unsigned int whichcpu); +}; + +/* Routines for traversing the prom device tree. */ +struct linux_nodeops { + int (*no_nextnode) (int node); + int (*no_child) (int node); + int (*no_proplen) (int node, char *name); + int (*no_getprop) (int node, char *name, char *val); + int (*no_setprop) (int node, char *name, char *val, int len); + char *(*no_nextprop) (int node, char *name); +}; + +/* More fun PROM structures for device probing. */ +#define PROMREG_MAX 16 +#define PROMVADDR_MAX 16 +#define PROMINTR_MAX 15 + +struct linux_prom_registers { + unsigned int which_io; /* is this in OBIO space? */ + unsigned int phys_addr; /* The physical address of this register */ + unsigned int reg_size; /* How many bytes does this register take up? */ +}; + +struct linux_prom_irqs { + int pri; /* IRQ priority */ + int vector; /* This is foobar, what does it do? */ +}; + +/* Element of the "ranges" vector */ +struct linux_prom_ranges { + unsigned int ot_child_space; + unsigned int ot_child_base; /* Bus feels this */ + unsigned int ot_parent_space; + unsigned int ot_parent_base; /* CPU looks from here */ + unsigned int or_size; +}; + +/* Ranges and reg properties are a bit different for PCI. */ +struct linux_prom_pci_registers { + /* + * We don't know what information this field contain. + * We guess, PCI device function is in bits 15:8 + * So, ... + */ + unsigned int which_io; /* Let it be which_io */ + + unsigned int phys_hi; + unsigned int phys_lo; + + unsigned int size_hi; + unsigned int size_lo; +}; + +struct linux_prom_pci_ranges { + unsigned int child_phys_hi; /* Only certain bits are encoded here. */ + unsigned int child_phys_mid; + unsigned int child_phys_lo; + + unsigned int parent_phys_hi; + unsigned int parent_phys_lo; + + unsigned int size_hi; + unsigned int size_lo; +}; + +struct linux_prom_pci_assigned_addresses { + unsigned int which_io; + + unsigned int phys_hi; + unsigned int phys_lo; + + unsigned int size_hi; + unsigned int size_lo; +}; + +struct linux_prom_ebus_ranges { + unsigned int child_phys_hi; + unsigned int child_phys_lo; + + unsigned int parent_phys_hi; + unsigned int parent_phys_mid; + unsigned int parent_phys_lo; + + unsigned int size; +}; + +/* Offset into the EEPROM where the id PROM is located on the 4c */ +#define IDPROM_OFFSET 0x7d8 + +/* On sun4m; physical. */ +/* MicroSPARC(-II) does not decode 31rd bit, but it works. */ +#define IDPROM_OFFSET_M 0xfd8 + +struct idprom { + unsigned char id_format; /* Format identifier (always 0x01) */ + unsigned char id_machtype; /* Machine type */ + unsigned char id_ethaddr[6]; /* Hardware ethernet address */ + long id_date; /* Date of manufacture */ + unsigned int id_sernum:24; /* Unique serial number */ + unsigned char id_cksum; /* Checksum - xor of the data bytes */ + unsigned char reserved[16]; +}; + +extern struct idprom *idprom; +extern void idprom_init(void); + +#define IDPROM_SIZE (sizeof(struct idprom)) + +#endif /* !(__ASSEMBLY__) */ + +#endif diff --git a/arch/sparc/include/asm/psr.h b/arch/sparc/include/asm/psr.h new file mode 100644 index 0000000..fc77947 --- /dev/null +++ b/arch/sparc/include/asm/psr.h @@ -0,0 +1,97 @@ +/* psr.h: This file holds the macros for masking off various parts of + * the processor status register on the Sparc. This is valid + * for Version 8. On the V9 this is renamed to the PSTATE + * register and its members are accessed as fields like + * PSTATE.PRIV for the current CPU privilege level. + * + * taken from the SPARC port of Linux, + * + * Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 2007 Daniel Hellstrom (daniel@gaisler.com) + * + * 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 program is distributed in the hope that 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 + * + */ + +#ifndef __SPARC_PSR_H__ +#define __SPARC_PSR_H__ + +/* The Sparc PSR fields are laid out as the following: + * + * ------------------------------------------------------------------------ + * | impl | vers | icc | resv | EC | EF | PIL | S | PS | ET | CWP | + * | 31-28 | 27-24 | 23-20 | 19-14 | 13 | 12 | 11-8 | 7 | 6 | 5 | 4-0 | + * ------------------------------------------------------------------------ + */ +#define PSR_CWP 0x0000001f /* current window pointer */ +#define PSR_ET 0x00000020 /* enable traps field */ +#define PSR_PS 0x00000040 /* previous privilege level */ +#define PSR_S 0x00000080 /* current privilege level */ +#define PSR_PIL 0x00000f00 /* processor interrupt level */ +#define PSR_EF 0x00001000 /* enable floating point */ +#define PSR_EC 0x00002000 /* enable co-processor */ +#define PSR_LE 0x00008000 /* SuperSparcII little-endian */ +#define PSR_ICC 0x00f00000 /* integer condition codes */ +#define PSR_C 0x00100000 /* carry bit */ +#define PSR_V 0x00200000 /* overflow bit */ +#define PSR_Z 0x00400000 /* zero bit */ +#define PSR_N 0x00800000 /* negative bit */ +#define PSR_VERS 0x0f000000 /* cpu-version field */ +#define PSR_IMPL 0xf0000000 /* cpu-implementation field */ + +#define PSR_PIL_OFS 8 + +#ifndef __ASSEMBLY__ +/* Get the %psr register. */ +extern __inline__ unsigned int get_psr(void) +{ + unsigned int psr; + __asm__ __volatile__("rd %%psr, %0\n\t" + "nop\n\t" "nop\n\t" "nop\n\t":"=r"(psr) + : /* no inputs */ + :"memory"); + + return psr; +} + +extern __inline__ void put_psr(unsigned int new_psr) +{ + __asm__ __volatile__("wr %0, 0x0, %%psr\n\t" "nop\n\t" "nop\n\t" "nop\n\t": /* no outputs */ + :"r"(new_psr) + :"memory", "cc"); +} + +/* Get the %fsr register. Be careful, make sure the floating point + * enable bit is set in the %psr when you execute this or you will + * incur a trap. + */ + +extern unsigned int fsr_storage; + +extern __inline__ unsigned int get_fsr(void) +{ + unsigned int fsr = 0; + + __asm__ __volatile__("st %%fsr, %1\n\t" + "ld %1, %0\n\t":"=r"(fsr) + :"m"(fsr_storage)); + + return fsr; +} + +#endif /* !(__ASSEMBLY__) */ + +#endif /* !(__SPARC_PSR_H__) */ diff --git a/arch/sparc/include/asm/ptrace.h b/arch/sparc/include/asm/ptrace.h new file mode 100644 index 0000000..12a9c56 --- /dev/null +++ b/arch/sparc/include/asm/ptrace.h @@ -0,0 +1,181 @@ +/* Contain the Stack frame layout on interrupt. pt_regs. + * taken from the SPARC port of Linux (ptrace.h). + * + * (C) Copyright 2007 + * Daniel Hellstrom, Gaisler Research, daniel@gaisler.com. + * + * 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 program is distributed in the hope that 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 + * + */ + +#ifndef __SPARC_PTRACE_H__ +#define __SPARC_PTRACE_H__ + +#include <asm/psr.h> + +/* This struct defines the way the registers are stored on the + * stack during a system call and basically all traps. + */ + +#ifndef __ASSEMBLY__ + +struct pt_regs { + unsigned long psr; + unsigned long pc; + unsigned long npc; + unsigned long y; + unsigned long u_regs[16]; /* globals and ins */ +}; + +#define UREG_G0 0 +#define UREG_G1 1 +#define UREG_G2 2 +#define UREG_G3 3 +#define UREG_G4 4 +#define UREG_G5 5 +#define UREG_G6 6 +#define UREG_G7 7 +#define UREG_I0 8 +#define UREG_I1 9 +#define UREG_I2 10 +#define UREG_I3 11 +#define UREG_I4 12 +#define UREG_I5 13 +#define UREG_I6 14 +#define UREG_I7 15 +#define UREG_WIM UREG_G0 +#define UREG_FADDR UREG_G0 +#define UREG_FP UREG_I6 +#define UREG_RETPC UREG_I7 + +/* A register window */ +struct reg_window { + unsigned long locals[8]; + unsigned long ins[8]; +}; + +/* A Sparc stack frame */ +struct sparc_stackf { + unsigned long locals[8]; + unsigned long ins[6]; + struct sparc_stackf *fp; + unsigned long callers_pc; + char *structptr; + unsigned long xargs[6]; + unsigned long xxargs[1]; +}; + +#define TRACEREG_SZ sizeof(struct pt_regs) +#define STACKFRAME_SZ sizeof(struct sparc_stackf) + +#else /* __ASSEMBLY__ */ +/* For assembly code. */ +#define TRACEREG_SZ 0x50 +#define STACKFRAME_SZ 0x60 +#endif + +/* + * The asm_offsets.h is a generated file, so we cannot include it. + * It may be OK for glibc headers, but it's utterly pointless for C code. + * The assembly code using those offsets has to include it explicitly. + */ +/* #include <asm/asm_offsets.h> */ + +/* These are for pt_regs. */ +#define PT_PSR 0x0 +#define PT_PC 0x4 +#define PT_NPC 0x8 +#define PT_Y 0xc +#define PT_G0 0x10 +#define PT_WIM PT_G0 +#define PT_G1 0x14 +#define PT_G2 0x18 +#define PT_G3 0x1c +#define PT_G4 0x20 +#define PT_G5 0x24 +#define PT_G6 0x28 +#define PT_G7 0x2c +#define PT_I0 0x30 +#define PT_I1 0x34 +#define PT_I2 0x38 +#define PT_I3 0x3c +#define PT_I4 0x40 +#define PT_I5 0x44 +#define PT_I6 0x48 +#define PT_FP PT_I6 +#define PT_I7 0x4c + +/* Reg_window offsets */ +#define RW_L0 0x00 +#define RW_L1 0x04 +#define RW_L2 0x08 +#define RW_L3 0x0c +#define RW_L4 0x10 +#define RW_L5 0x14 +#define RW_L6 0x18 +#define RW_L7 0x1c +#define RW_I0 0x20 +#define RW_I1 0x24 +#define RW_I2 0x28 +#define RW_I3 0x2c +#define RW_I4 0x30 +#define RW_I5 0x34 +#define RW_I6 0x38 +#define RW_I7 0x3c + +/* Stack_frame offsets */ +#define SF_L0 0x00 +#define SF_L1 0x04 +#define SF_L2 0x08 +#define SF_L3 0x0c +#define SF_L4 0x10 +#define SF_L5 0x14 +#define SF_L6 0x18 +#define SF_L7 0x1c +#define SF_I0 0x20 +#define SF_I1 0x24 +#define SF_I2 0x28 +#define SF_I3 0x2c +#define SF_I4 0x30 +#define SF_I5 0x34 +#define SF_FP 0x38 +#define SF_PC 0x3c +#define SF_RETP 0x40 +#define SF_XARG0 0x44 +#define SF_XARG1 0x48 +#define SF_XARG2 0x4c +#define SF_XARG3 0x50 +#define SF_XARG4 0x54 +#define SF_XARG5 0x58 +#define SF_XXARG 0x5c + +/* Stuff for the ptrace system call */ +#define PTRACE_SUNATTACH 10 +#define PTRACE_SUNDETACH 11 +#define PTRACE_GETREGS 12 +#define PTRACE_SETREGS 13 +#define PTRACE_GETFPREGS 14 +#define PTRACE_SETFPREGS 15 +#define PTRACE_READDATA 16 +#define PTRACE_WRITEDATA 17 +#define PTRACE_READTEXT 18 +#define PTRACE_WRITETEXT 19 +#define PTRACE_GETFPAREGS 20 +#define PTRACE_SETFPAREGS 21 + +#define PTRACE_GETUCODE 29 /* stupid bsd-ism */ + +#endif /* !(_SPARC_PTRACE_H) */ diff --git a/arch/sparc/include/asm/srmmu.h b/arch/sparc/include/asm/srmmu.h new file mode 100644 index 0000000..5214d96 --- /dev/null +++ b/arch/sparc/include/asm/srmmu.h @@ -0,0 +1,301 @@ +/* SRMMU page table defines and code, + * taken from the SPARC port of Linux + * + * Copyright (C) 2007 Daniel Hellstrom (daniel@gaisler.com) + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + * + * 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 program is distributed in the hope that 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 + * + */ + +#ifndef __SPARC_SRMMU_H__ +#define __SPARC_SRMMU_H__ + +#include <asm/asi.h> +#include <asm/page.h> + +/* Number of contexts is implementation-dependent; 64k is the most we support */ +#define SRMMU_MAX_CONTEXTS 65536 + +/* PMD_SHIFT determines the size of the area a second-level page table entry can map */ +#define SRMMU_REAL_PMD_SHIFT 18 +#define SRMMU_REAL_PMD_SIZE (1UL << SRMMU_REAL_PMD_SHIFT) +#define SRMMU_REAL_PMD_MASK (~(SRMMU_REAL_PMD_SIZE-1)) +#define SRMMU_REAL_PMD_ALIGN(__addr) (((__addr)+SRMMU_REAL_PMD_SIZE-1)&SRMMU_REAL_PMD_MASK) + +/* PGDIR_SHIFT determines what a third-level page table entry can map */ +#define SRMMU_PGDIR_SHIFT 24 +#define SRMMU_PGDIR_SIZE (1UL << SRMMU_PGDIR_SHIFT) +#define SRMMU_PGDIR_MASK (~(SRMMU_PGDIR_SIZE-1)) +#define SRMMU_PGDIR_ALIGN(addr) (((addr)+SRMMU_PGDIR_SIZE-1)&SRMMU_PGDIR_MASK) + +#define SRMMU_REAL_PTRS_PER_PTE 64 +#define SRMMU_REAL_PTRS_PER_PMD 64 +#define SRMMU_PTRS_PER_PGD 256 + +#define SRMMU_REAL_PTE_TABLE_SIZE (SRMMU_REAL_PTRS_PER_PTE*4) +#define SRMMU_PMD_TABLE_SIZE (SRMMU_REAL_PTRS_PER_PMD*4) +#define SRMMU_PGD_TABLE_SIZE (SRMMU_PTRS_PER_PGD*4) + +/* + * To support pagetables in highmem, Linux introduces APIs which + * return struct page* and generally manipulate page tables when + * they are not mapped into kernel space. Our hardware page tables + * are smaller than pages. We lump hardware tabes into big, page sized + * software tables. + * + * PMD_SHIFT determines the size of the area a second-level page table entry + * can map, and our pmd_t is 16 times larger than normal. The values which + * were once defined here are now generic for 4c and srmmu, so they're + * found in pgtable.h. + */ +#define SRMMU_PTRS_PER_PMD 4 + +/* Definition of the values in the ET field of PTD's and PTE's */ +#define SRMMU_ET_MASK 0x3 +#define SRMMU_ET_INVALID 0x0 +#define SRMMU_ET_PTD 0x1 +#define SRMMU_ET_PTE 0x2 +#define SRMMU_ET_REPTE 0x3 /* AIEEE, SuperSparc II reverse endian page! */ + +/* Physical page extraction from PTP's and PTE's. */ +#define SRMMU_CTX_PMASK 0xfffffff0 +#define SRMMU_PTD_PMASK 0xfffffff0 +#define SRMMU_PTE_PMASK 0xffffff00 + +/* The pte non-page bits. Some notes: + * 1) cache, dirty, valid, and ref are frobbable + * for both supervisor and user pages. + * 2) exec and write will only give the desired effect + * on user pages + * 3) use priv and priv_readonly for changing the + * characteristics of supervisor ptes + */ +#define SRMMU_CACHE 0x80 +#define SRMMU_DIRTY 0x40 +#define SRMMU_REF 0x20 +#define SRMMU_NOREAD 0x10 +#define SRMMU_EXEC 0x08 +#define SRMMU_WRITE 0x04 +#define SRMMU_VALID 0x02 /* SRMMU_ET_PTE */ +#define SRMMU_PRIV 0x1c +#define SRMMU_PRIV_RDONLY 0x18 + +#define SRMMU_FILE 0x40 /* Implemented in software */ + +#define SRMMU_PTE_FILE_SHIFT 8 /* == 32-PTE_FILE_MAX_BITS */ + +#define SRMMU_CHG_MASK (0xffffff00 | SRMMU_REF | SRMMU_DIRTY) + +/* SRMMU swap entry encoding + * + * We use 5 bits for the type and 19 for the offset. This gives us + * 32 swapfiles of 4GB each. Encoding looks like: + * + * oooooooooooooooooootttttRRRRRRRR + * fedcba9876543210fedcba9876543210 + * + * The bottom 8 bits are reserved for protection and status bits, especially + * FILE and PRESENT. + */ +#define SRMMU_SWP_TYPE_MASK 0x1f +#define SRMMU_SWP_TYPE_SHIFT SRMMU_PTE_FILE_SHIFT +#define SRMMU_SWP_OFF_MASK 0x7ffff +#define SRMMU_SWP_OFF_SHIFT (SRMMU_PTE_FILE_SHIFT + 5) + +/* Some day I will implement true fine grained access bits for + * user pages because the SRMMU gives us the capabilities to + * enforce all the protection levels that vma's can have. + * XXX But for now... + */ +#define SRMMU_PAGE_NONE __pgprot(SRMMU_CACHE | \ + SRMMU_PRIV | SRMMU_REF) +#define SRMMU_PAGE_SHARED __pgprot(SRMMU_VALID | SRMMU_CACHE | \ + SRMMU_EXEC | SRMMU_WRITE | SRMMU_REF) +#define SRMMU_PAGE_COPY __pgprot(SRMMU_VALID | SRMMU_CACHE | \ + SRMMU_EXEC | SRMMU_REF) +#define SRMMU_PAGE_RDONLY __pgprot(SRMMU_VALID | SRMMU_CACHE | \ + SRMMU_EXEC | SRMMU_REF) +#define SRMMU_PAGE_KERNEL __pgprot(SRMMU_VALID | SRMMU_CACHE | SRMMU_PRIV | \ + SRMMU_DIRTY | SRMMU_REF) + +/* SRMMU Register addresses in ASI 0x4. These are valid for all + * current SRMMU implementations that exist. + */ +#define SRMMU_CTRL_REG 0x00000000 +#define SRMMU_CTXTBL_PTR 0x00000100 +#define SRMMU_CTX_REG 0x00000200 +#define SRMMU_FAULT_STATUS 0x00000300 +#define SRMMU_FAULT_ADDR 0x00000400 + +#define WINDOW_FLUSH(tmp1, tmp2) \ + mov 0, tmp1; \ +98: ld [%g6 + TI_UWINMASK], tmp2; \ + orcc %g0, tmp2, %g0; \ + add tmp1, 1, tmp1; \ + bne 98b; \ + save %sp, -64, %sp; \ +99: subcc tmp1, 1, tmp1; \ + bne 99b; \ + restore %g0, %g0, %g0; + +#ifndef __ASSEMBLY__ + +/* This makes sense. Honest it does - Anton */ +/* XXX Yes but it's ugly as sin. FIXME. -KMW */ +extern void *srmmu_nocache_pool; +#define __nocache_pa(VADDR) (((unsigned long)VADDR) - SRMMU_NOCACHE_VADDR + __pa((unsigned long)srmmu_nocache_pool)) +#define __nocache_va(PADDR) (__va((unsigned long)PADDR) - (unsigned long)srmmu_nocache_pool + SRMMU_NOCACHE_VADDR) +#define __nocache_fix(VADDR) __va(__nocache_pa(VADDR)) + +/* Accessing the MMU control register. */ +extern __inline__ unsigned int srmmu_get_mmureg(void) +{ + unsigned int retval; + __asm__ __volatile__("lda [%%g0] %1, %0\n\t": + "=r"(retval):"i"(ASI_M_MMUREGS)); + return retval; +} + +extern __inline__ void srmmu_set_mmureg(unsigned long regval) +{ + __asm__ __volatile__("sta %0, [%%g0] %1\n\t"::"r"(regval), + "i"(ASI_M_MMUREGS):"memory"); + +} + +extern __inline__ void srmmu_set_ctable_ptr(unsigned long paddr) +{ + paddr = ((paddr >> 4) & SRMMU_CTX_PMASK); + __asm__ __volatile__("sta %0, [%1] %2\n\t"::"r"(paddr), + "r"(SRMMU_CTXTBL_PTR), + "i"(ASI_M_MMUREGS):"memory"); +} + +extern __inline__ unsigned long srmmu_get_ctable_ptr(void) +{ + unsigned int retval; + + __asm__ __volatile__("lda [%1] %2, %0\n\t": + "=r"(retval): + "r"(SRMMU_CTXTBL_PTR), "i"(ASI_M_MMUREGS)); + return (retval & SRMMU_CTX_PMASK) << 4; +} + +extern __inline__ void srmmu_set_context(int context) +{ + __asm__ __volatile__("sta %0, [%1] %2\n\t"::"r"(context), + "r"(SRMMU_CTX_REG), "i"(ASI_M_MMUREGS):"memory"); +} + +extern __inline__ int srmmu_get_context(void) +{ + register int retval; + __asm__ __volatile__("lda [%1] %2, %0\n\t": + "=r"(retval): + "r"(SRMMU_CTX_REG), "i"(ASI_M_MMUREGS)); + return retval; +} + +extern __inline__ unsigned int srmmu_get_fstatus(void) +{ + unsigned int retval; + + __asm__ __volatile__("lda [%1] %2, %0\n\t": + "=r"(retval): + "r"(SRMMU_FAULT_STATUS), "i"(ASI_M_MMUREGS)); + return retval; +} + +extern __inline__ unsigned int srmmu_get_faddr(void) +{ + unsigned int retval; + + __asm__ __volatile__("lda [%1] %2, %0\n\t": + "=r"(retval): + "r"(SRMMU_FAULT_ADDR), "i"(ASI_M_MMUREGS)); + return retval; +} + +/* This is guaranteed on all SRMMU's. */ +extern __inline__ void srmmu_flush_whole_tlb(void) +{ + __asm__ __volatile__("sta %%g0, [%0] %1\n\t"::"r"(0x400), /* Flush entire TLB!! */ + "i"(ASI_M_FLUSH_PROBE):"memory"); + +} + +/* These flush types are not available on all chips... */ +extern __inline__ void srmmu_flush_tlb_ctx(void) +{ + __asm__ __volatile__("sta %%g0, [%0] %1\n\t"::"r"(0x300), /* Flush TLB ctx.. */ + "i"(ASI_M_FLUSH_PROBE):"memory"); + +} + +extern __inline__ void srmmu_flush_tlb_region(unsigned long addr) +{ + addr &= SRMMU_PGDIR_MASK; + __asm__ __volatile__("sta %%g0, [%0] %1\n\t"::"r"(addr | 0x200), /* Flush TLB region.. */ + "i"(ASI_M_FLUSH_PROBE):"memory"); + +} + +extern __inline__ void srmmu_flush_tlb_segment(unsigned long addr) +{ + addr &= SRMMU_REAL_PMD_MASK; + __asm__ __volatile__("sta %%g0, [%0] %1\n\t"::"r"(addr | 0x100), /* Flush TLB segment.. */ + "i"(ASI_M_FLUSH_PROBE):"memory"); + +} + +extern __inline__ void srmmu_flush_tlb_page(unsigned long page) +{ + page &= PAGE_MASK; + __asm__ __volatile__("sta %%g0, [%0] %1\n\t"::"r"(page), /* Flush TLB page.. */ + "i"(ASI_M_FLUSH_PROBE):"memory"); + +} + +extern __inline__ unsigned long srmmu_hwprobe(unsigned long vaddr) +{ + unsigned long retval; + + vaddr &= PAGE_MASK; + __asm__ __volatile__("lda [%1] %2, %0\n\t": + "=r"(retval): + "r"(vaddr | 0x400), "i"(ASI_M_FLUSH_PROBE)); + + return retval; +} + +extern __inline__ int srmmu_get_pte(unsigned long addr) +{ + register unsigned long entry; + + __asm__ __volatile__("\n\tlda [%1] %2,%0\n\t": + "=r"(entry): + "r"((addr & 0xfffff000) | 0x400), + "i"(ASI_M_FLUSH_PROBE)); + return entry; +} + +extern unsigned long (*srmmu_read_physical) (unsigned long paddr); +extern void (*srmmu_write_physical) (unsigned long paddr, unsigned long word); + +#endif /* !(__ASSEMBLY__) */ + +#endif /* !(__SPARC_SRMMU_H__) */ diff --git a/arch/sparc/include/asm/stack.h b/arch/sparc/include/asm/stack.h new file mode 100644 index 0000000..b40a9f3 --- /dev/null +++ b/arch/sparc/include/asm/stack.h @@ -0,0 +1,162 @@ +/* SPARC stack layout Macros and structures, + * mainly taken from BCC (the Bare C compiler for + * SPARC LEON2/3) sources. + * + * (C) Copyright 2007 + * Daniel Hellstrom, Gaisler Research, daniel@gaisler.com. + * + * 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 program is distributed in the hope that 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 + * + */ + +#ifndef __SPARC_STACK_H__ +#define __SPARC_STACK_H__ + +#include <asm/ptrace.h> + +#ifndef __ASSEMBLER__ + +#ifdef __cplusplus +extern "C" { +#endif + +#define PT_REGS_SZ sizeof(struct pt_regs) + +/* A Sparc stack frame */ + struct sparc_stackframe_regs { + unsigned long sf_locals[8]; + unsigned long sf_ins[6]; + struct sparc_stackframe_regs *sf_fp; + unsigned long sf_callers_pc; + char *sf_structptr; + unsigned long sf_xargs[6]; + unsigned long sf_xxargs[1]; + }; +#define SF_REGS_SZ sizeof(struct sparc_stackframe_regs) + +/* A register window */ + struct sparc_regwindow_regs { + unsigned long locals[8]; + unsigned long ins[8]; + }; +#define RW_REGS_SZ sizeof(struct sparc_regwindow_regs) + +/* A fpu window */ + struct sparc_fpuwindow_regs { + unsigned long locals[32]; + unsigned long fsr; + unsigned long lastctx; + }; +#define FW_REGS_SZ sizeof(struct sparc_fpuwindow_regs) + +#ifdef __cplusplus +} +#endif +#else +#define PT_REGS_SZ 0x50 /* 20*4 */ +#define SF_REGS_SZ 0x60 /* 24*4 */ +#define RW_REGS_SZ 0x20 /* 16*4 */ +#define FW_REGS_SZ 0x88 /* 34*4 */ +#endif /* !ASM */ + +/* These are for pt_regs. */ +#define PT_PSR 0x0 +#define PT_PC 0x4 +#define PT_NPC 0x8 +#define PT_Y 0xc +#define PT_G0 0x10 +#define PT_WIM PT_G0 +#define PT_G1 0x14 +#define PT_G2 0x18 +#define PT_G3 0x1c +#define PT_G4 0x20 +#define PT_G5 0x24 +#define PT_G6 0x28 +#define PT_G7 0x2c +#define PT_I0 0x30 +#define PT_I1 0x34 +#define PT_I2 0x38 +#define PT_I3 0x3c +#define PT_I4 0x40 +#define PT_I5 0x44 +#define PT_I6 0x48 +#define PT_FP PT_I6 +#define PT_I7 0x4c + +/* Stack_frame offsets */ +#define SF_L0 0x00 +#define SF_L1 0x04 +#define SF_L2 0x08 +#define SF_L3 0x0c +#define SF_L4 0x10 +#define SF_L5 0x14 +#define SF_L6 0x18 +#define SF_L7 0x1c +#define SF_I0 0x20 +#define SF_I1 0x24 +#define SF_I2 0x28 +#define SF_I3 0x2c +#define SF_I4 0x30 +#define SF_I5 0x34 +#define SF_FP 0x38 +#define SF_PC 0x3c +#define SF_RETP 0x40 +#define SF_XARG0 0x44 +#define SF_XARG1 0x48 +#define SF_XARG2 0x4c +#define SF_XARG3 0x50 +#define SF_XARG4 0x54 +#define SF_XARG5 0x58 +#define SF_XXARG 0x5c + +/* Reg_window offsets */ +#define RW_L0 0x00 +#define RW_L1 0x04 +#define RW_L2 0x08 +#define RW_L3 0x0c +#define RW_L4 0x10 +#define RW_L5 0x14 +#define RW_L6 0x18 +#define RW_L7 0x1c +#define RW_I0 0x20 +#define RW_I1 0x24 +#define RW_I2 0x28 +#define RW_I3 0x2c +#define RW_I4 0x30 +#define RW_I5 0x34 +#define RW_I6 0x38 +#define RW_I7 0x3c + +/* Fpu_window offsets */ +#define FW_F0 0x00 +#define FW_F2 0x08 +#define FW_F4 0x10 +#define FW_F6 0x18 +#define FW_F8 0x20 +#define FW_F10 0x28 +#define FW_F12 0x30 +#define FW_F14 0x38 +#define FW_F16 0x40 +#define FW_F18 0x48 +#define FW_F20 0x50 +#define FW_F22 0x58 +#define FW_F24 0x60 +#define FW_F26 0x68 +#define FW_F28 0x70 +#define FW_F30 0x78 +#define FW_FSR 0x80 + +#endif diff --git a/arch/sparc/include/asm/string.h b/arch/sparc/include/asm/string.h new file mode 100644 index 0000000..c6bbc20 --- /dev/null +++ b/arch/sparc/include/asm/string.h @@ -0,0 +1,55 @@ +/* + * (C) Copyright 2000 - 2002 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * (C) Copyright 2007 + * Daniel Hellstrom, Gaisler Research, daniel@gaisler.com. + * + * 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 program is distributed in the hope that 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 + * + */ + +#ifndef _SPARC_STRING_H_ +#define _SPARC_STRING_H_ + +/* +#define __HAVE_ARCH_STRCPY +#define __HAVE_ARCH_STRNCPY +#define __HAVE_ARCH_STRLEN +#define __HAVE_ARCH_STRCMP +#define __HAVE_ARCH_STRCAT +#define __HAVE_ARCH_MEMSET +#define __HAVE_ARCH_BCOPY +#define __HAVE_ARCH_MEMCPY +#define __HAVE_ARCH_MEMMOVE +#define __HAVE_ARCH_MEMCMP +#define __HAVE_ARCH_MEMCHR +*/ + +extern int strcasecmp(const char *, const char *); +extern int strncasecmp(const char *, const char *, int); +extern char *strcpy(char *, const char *); +extern char *strncpy(char *, const char *, __kernel_size_t); +extern __kernel_size_t strlen(const char *); +extern int strcmp(const char *, const char *); +extern char *strcat(char *, const char *); +extern void *memset(void *, int, __kernel_size_t); +extern void *memcpy(void *, const void *, __kernel_size_t); +extern void *memmove(void *, const void *, __kernel_size_t); +extern int memcmp(const void *, const void *, __kernel_size_t); +extern void *memchr(const void *, int, __kernel_size_t); + +#endif diff --git a/arch/sparc/include/asm/types.h b/arch/sparc/include/asm/types.h new file mode 100644 index 0000000..0a8a26c --- /dev/null +++ b/arch/sparc/include/asm/types.h @@ -0,0 +1,74 @@ +/* + * (C) Copyright 2000 - 2002 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * 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 program is distributed in the hope that 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 + * + */ + +#ifndef _SPARC_TYPES_H +#define _SPARC_TYPES_H + +#ifndef __ASSEMBLY__ + +typedef unsigned short umode_t; + +typedef __signed__ char __s8; +typedef unsigned char __u8; + +typedef __signed__ short __s16; +typedef unsigned short __u16; + +typedef __signed__ int __s32; +typedef unsigned int __u32; + +#if defined(__GNUC__) && !defined(__STRICT_ANSI__) +typedef __signed__ long long __s64; +typedef unsigned long long __u64; +#endif + +typedef struct { + __u32 u[4]; +} __attribute__((aligned(16))) vector128; + +#ifdef __KERNEL__ +/* + * These aren't exported outside the kernel to avoid name space clashes + */ +typedef signed char s8; +typedef unsigned char u8; + +typedef signed short s16; +typedef unsigned short u16; + +typedef signed int s32; +typedef unsigned int u32; + +typedef signed long long s64; +typedef unsigned long long u64; + +#define BITS_PER_LONG 32 + +/* DMA addresses are 32-bits wide */ +typedef u32 dma_addr_t; + +typedef unsigned long phys_addr_t; +typedef unsigned long phys_size_t; + +#endif /* __KERNEL__ */ +#endif /* __ASSEMBLY__ */ + +#endif diff --git a/arch/sparc/include/asm/u-boot.h b/arch/sparc/include/asm/u-boot.h new file mode 100644 index 0000000..209873f --- /dev/null +++ b/arch/sparc/include/asm/u-boot.h @@ -0,0 +1,62 @@ +/* + * (C) Copyright 2000 - 2002 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * (C) Copyright 2007, From asm-ppc/u-boot.h + * Daniel Hellstrom, Gaisler Research, daniel@gaisler.com. + * + * 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 program is distributed in the hope that 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 + * + ******************************************************************** + * NOTE: This header file defines an interface to U-Boot. Including + * this (unmodified) header file in another file is considered normal + * use of U-Boot, and does *not* fall under the heading of "derived + * work". + ******************************************************************** + */ + +#ifndef __U_BOOT_H__ +#define __U_BOOT_H__ + +/* + * Currently, this Board information is not passed to + * Linux kernel from U-Boot, but may be passed to other + * Operating systems. This is because U-boot emulates + * a SUN PROM loader (from Linux point of view). + * + * include/asm-sparc/u-boot.h + */ + +#ifndef __ASSEMBLY__ + +typedef struct bd_info { + unsigned long bi_memstart; /* start of DRAM memory */ + phys_size_t bi_memsize; /* size of DRAM memory in bytes */ + unsigned long bi_flashstart; /* start of FLASH memory */ + unsigned long bi_flashsize; /* size of FLASH memory */ + unsigned long bi_flashoffset; /* reserved area for startup monitor */ + unsigned long bi_sramstart; /* start of SRAM memory */ + unsigned long bi_sramsize; /* size of SRAM memory */ + unsigned long bi_bootflags; /* boot / reboot flag (for LynxOS) */ + unsigned long bi_ip_addr; /* IP Address */ + unsigned short bi_ethspeed; /* Ethernet speed in Mbps */ + unsigned long bi_intfreq; /* Internal Freq, in MHz */ + unsigned long bi_busfreq; /* Bus Freq, in MHz */ + unsigned long bi_baudrate; /* Console Baudrate */ +} bd_t; + +#endif /* __ASSEMBLY__ */ +#endif /* __U_BOOT_H__ */ diff --git a/arch/sparc/include/asm/winmacro.h b/arch/sparc/include/asm/winmacro.h new file mode 100644 index 0000000..66fc639 --- /dev/null +++ b/arch/sparc/include/asm/winmacro.h @@ -0,0 +1,151 @@ +/* + * Added to U-boot, + * Daniel Hellstrom, Gaisler Research, daniel@gaisler.com + * Copyright (C) 2007 + * + * LEON2/3 LIBIO low-level routines + * Written by Jiri Gaisler. + * Copyright (C) 2004 Gaisler Research AB + + * 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 program is distributed in the hope that 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 + +*/ + +#ifndef __SPARC_WINMACRO_H__ +#define __SPARC_WINMACRO_H__ + +#include <asm/asmmacro.h> +#include <asm/stack.h> + +/* Store the register window onto the 8-byte aligned area starting + * at %reg. It might be %sp, it might not, we don't care. + */ +#define RW_STORE(reg) \ + std %l0, [%reg + RW_L0]; \ + std %l2, [%reg + RW_L2]; \ + std %l4, [%reg + RW_L4]; \ + std %l6, [%reg + RW_L6]; \ + std %i0, [%reg + RW_I0]; \ + std %i2, [%reg + RW_I2]; \ + std %i4, [%reg + RW_I4]; \ + std %i6, [%reg + RW_I6]; + +/* Load a register window from the area beginning at %reg. */ +#define RW_LOAD(reg) \ + ldd [%reg + RW_L0], %l0; \ + ldd [%reg + RW_L2], %l2; \ + ldd [%reg + RW_L4], %l4; \ + ldd [%reg + RW_L6], %l6; \ + ldd [%reg + RW_I0], %i0; \ + ldd [%reg + RW_I2], %i2; \ + ldd [%reg + RW_I4], %i4; \ + ldd [%reg + RW_I6], %i6; + +/* Loading and storing struct pt_reg trap frames. */ +#define PT_LOAD_INS(base_reg) \ + ldd [%base_reg + SF_REGS_SZ + PT_I0], %i0; \ + ldd [%base_reg + SF_REGS_SZ + PT_I2], %i2; \ + ldd [%base_reg + SF_REGS_SZ + PT_I4], %i4; \ + ldd [%base_reg + SF_REGS_SZ + PT_I6], %i6; + +#define PT_LOAD_GLOBALS(base_reg) \ + ld [%base_reg + SF_REGS_SZ + PT_G1], %g1; \ + ldd [%base_reg + SF_REGS_SZ + PT_G2], %g2; \ + ldd [%base_reg + SF_REGS_SZ + PT_G4], %g4; \ + ldd [%base_reg + SF_REGS_SZ + PT_G6], %g6; + +#define PT_LOAD_YREG(base_reg, scratch) \ + ld [%base_reg + SF_REGS_SZ + PT_Y], %scratch; \ + wr %scratch, 0x0, %y; + +#define PT_LOAD_PRIV(base_reg, pt_psr, pt_pc, pt_npc) \ + ld [%base_reg + SF_REGS_SZ + PT_PSR], %pt_psr; \ + ld [%base_reg + SF_REGS_SZ + PT_PC], %pt_pc; \ + ld [%base_reg + SF_REGS_SZ + PT_NPC], %pt_npc; + +#define PT_LOAD_ALL(base_reg, pt_psr, pt_pc, pt_npc, scratch) \ + PT_LOAD_YREG(base_reg, scratch) \ + PT_LOAD_INS(base_reg) \ + PT_LOAD_GLOBALS(base_reg) \ + PT_LOAD_PRIV(base_reg, pt_psr, pt_pc, pt_npc) + +#define PT_STORE_INS(base_reg) \ + std %i0, [%base_reg + SF_REGS_SZ + PT_I0]; \ + std %i2, [%base_reg + SF_REGS_SZ + PT_I2]; \ + std %i4, [%base_reg + SF_REGS_SZ + PT_I4]; \ + std %i6, [%base_reg + SF_REGS_SZ + PT_I6]; + +#define PT_STORE_GLOBALS(base_reg) \ + st %g1, [%base_reg + SF_REGS_SZ + PT_G1]; \ + std %g2, [%base_reg + SF_REGS_SZ + PT_G2]; \ + std %g4, [%base_reg + SF_REGS_SZ + PT_G4]; \ + std %g6, [%base_reg + SF_REGS_SZ + PT_G6]; + +#define PT_STORE_YREG(base_reg, scratch) \ + rd %y, %scratch; \ + st %scratch, [%base_reg + SF_REGS_SZ + PT_Y]; + +#define PT_STORE_PRIV(base_reg, pt_psr, pt_pc, pt_npc) \ + st %pt_psr, [%base_reg + SF_REGS_SZ + PT_PSR]; \ + st %pt_pc, [%base_reg + SF_REGS_SZ + PT_PC]; \ + st %pt_npc, [%base_reg + SF_REGS_SZ + PT_NPC]; + +#define PT_STORE_ALL(base_reg, reg_psr, reg_pc, reg_npc, g_scratch) \ + PT_STORE_PRIV(base_reg, reg_psr, reg_pc, reg_npc) \ + PT_STORE_GLOBALS(base_reg) \ + PT_STORE_YREG(base_reg, g_scratch) \ + PT_STORE_INS(base_reg) + +/* Store the fpu register window*/ +#define FW_STORE(reg) \ + std %f0, [reg + FW_F0]; \ + std %f2, [reg + FW_F2]; \ + std %f4, [reg + FW_F4]; \ + std %f6, [reg + FW_F6]; \ + std %f8, [reg + FW_F8]; \ + std %f10, [reg + FW_F10]; \ + std %f12, [reg + FW_F12]; \ + std %f14, [reg + FW_F14]; \ + std %f16, [reg + FW_F16]; \ + std %f18, [reg + FW_F18]; \ + std %f20, [reg + FW_F20]; \ + std %f22, [reg + FW_F22]; \ + std %f24, [reg + FW_F24]; \ + std %f26, [reg + FW_F26]; \ + std %f28, [reg + FW_F28]; \ + std %f30, [reg + FW_F30]; \ + st %fsr, [reg + FW_FSR]; + +/* Load a fpu register window from the area beginning at reg. */ +#define FW_LOAD(reg) \ + ldd [reg + FW_F0], %f0; \ + ldd [reg + FW_F2], %f2; \ + ldd [reg + FW_F4], %f4; \ + ldd [reg + FW_F6], %f6; \ + ldd [reg + FW_F8], %f8; \ + ldd [reg + FW_F10], %f10; \ + ldd [reg + FW_F12], %f12; \ + ldd [reg + FW_F14], %f14; \ + ldd [reg + FW_F16], %f16; \ + ldd [reg + FW_F18], %f18; \ + ldd [reg + FW_F20], %f20; \ + ldd [reg + FW_F22], %f22; \ + ldd [reg + FW_F24], %f24; \ + ldd [reg + FW_F26], %f26; \ + ldd [reg + FW_F28], %f28; \ + ldd [reg + FW_F30], %f30; \ + ld [reg + FW_FSR], %fsr; + +#endif diff --git a/arch/sparc/lib/Makefile b/arch/sparc/lib/Makefile new file mode 100644 index 0000000..040ca10 --- /dev/null +++ b/arch/sparc/lib/Makefile @@ -0,0 +1,45 @@ +# +# (C) Copyright 2000-2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# See file CREDITS for list of people who contributed to this +# project. +# +# 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 program is distributed in the hope that 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 $(TOPDIR)/config.mk + +LIB = $(obj)lib$(ARCH).a + +SOBJS = + +COBJS = board.o cache.o interrupts.o time.o bootm.o + +SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c) +OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS)) + +$(LIB): $(obj).depend $(OBJS) + $(AR) $(ARFLAGS) $@ $(OBJS) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/arch/sparc/lib/board.c b/arch/sparc/lib/board.c new file mode 100644 index 0000000..11eea60 --- /dev/null +++ b/arch/sparc/lib/board.c @@ -0,0 +1,472 @@ +/* SPARC Board initialization + * + * (C) Copyright 2000-2006 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * (C) Copyright 2007 + * Daniel Hellstrom, Gaisler Research, daniel@gaisler.com. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 program is distributed in the hope that 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 <common.h> +#include <command.h> +#include <malloc.h> +#include <stdio_dev.h> +#include <config.h> +#if defined(CONFIG_CMD_IDE) +#include <ide.h> +#endif +#ifdef CONFIG_STATUS_LED +#include <status_led.h> +#endif +#include <net.h> +#include <serial.h> +#include <version.h> +#if defined(CONFIG_POST) +#include <post.h> +#endif +#ifdef CONFIG_PS2KBD +#include <keyboard.h> +#endif +#ifdef CONFIG_CMD_AMBAPP +#include <ambapp.h> +#endif + +#ifdef CONFIG_BITBANGMII +#include <miiphy.h> +#endif + +DECLARE_GLOBAL_DATA_PTR; + +/* Debug options +#define DEBUG_INIT_SEQUENCE +#define DEBUG_MEM_LAYOUT +#define DEBUG_COMMANDS +*/ + +extern void timer_interrupt_init(void); +extern void malloc_bin_reloc(void); +extern int do_ambapp_print(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]); +extern int prom_init(void); + +#if defined(CONFIG__CMD_DOC) +void doc_init(void); +#endif + +#if !defined(CONFIG_SYS_NO_FLASH) +static char *failed = "*** failed ***\n"; +#endif + +#include <environment.h> + +ulong monitor_flash_len; + +/************************************************************************ + * Init Utilities * + ************************************************************************ + * Some of this code should be moved into the core functions, + * but let's get it working (again) first... + */ + +static int init_baudrate(void) +{ + char tmp[64]; /* long enough for environment variables */ + int i = getenv_r("baudrate", tmp, sizeof(tmp)); + + gd->baudrate = (i > 0) + ? (int)simple_strtoul(tmp, NULL, 10) + : CONFIG_BAUDRATE; + return (0); +} + +/***********************************************************************/ + +/* + * All attempts to come up with a "common" initialization sequence + * that works for all boards and architectures failed: some of the + * requirements are just _too_ different. To get rid of the resulting + * mess of board dependend #ifdef'ed code we now make the whole + * initialization sequence configurable to the user. + * + * The requirements for any new initalization function is simple: it + * receives a pointer to the "global data" structure as it's only + * argument, and returns an integer return code, where 0 means + * "continue" and != 0 means "fatal error, hang the system". + */ +typedef int (init_fnc_t) (void); + +#define WATCHDOG_RESET(x) + +/************************************************************************ + * Initialization sequence * + ************************************************************************ + */ + +init_fnc_t *init_sequence[] = { + +#if defined(CONFIG_BOARD_EARLY_INIT_F) + board_early_init_f, +#endif + serial_init, + + init_timebase, + +#if defined(CONFIG_CMD_AMBAPP) + ambapp_init_reloc, +#endif + + env_init, + + init_baudrate, + + console_init_f, + display_options, + + checkcpu, + checkboard, +#if defined(CONFIG_MISC_INIT_F) + misc_init_f, +#endif + +#ifdef CONFIG_POST + post_init_f, +#endif + + NULL, /* Terminate this list, + * beware: this list will be relocated + * which means that NULL will become + * NULL+RELOC_OFFSET. We simply make + * NULL be -RELOC_OFFSET instead. + */ +}; + +/************************************************************************ + * + * This is the SPARC board initialization routine, running from RAM. + * + ************************************************************************ + */ +#ifdef DEBUG_INIT_SEQUENCE +char *str_init_seq = "INIT_SEQ 00\n"; +char *str_init_seq_done = "\n\rInit sequence done...\r\n\r\n"; +#endif + +void board_init_f(ulong bootflag) +{ + cmd_tbl_t *cmdtp; + bd_t *bd; + unsigned char *s; + init_fnc_t **init_fnc_ptr; + int j; + int i; + char *e; + +#ifndef CONFIG_SYS_NO_FLASH + ulong flash_size; +#endif + + gd = (gd_t *) (CONFIG_SYS_GBL_DATA_OFFSET); + + /* Clear initial global data */ + memset((void *)gd, 0, sizeof(gd_t)); + + gd->bd = (bd_t *) (gd + 1); /* At end of global data */ + gd->baudrate = CONFIG_BAUDRATE; + gd->cpu_clk = CONFIG_SYS_CLK_FREQ; + + bd = gd->bd; + bd->bi_memstart = CONFIG_SYS_RAM_BASE; + bd->bi_memsize = CONFIG_SYS_RAM_SIZE; + bd->bi_flashstart = CONFIG_SYS_FLASH_BASE; +#if defined(CONFIG_SYS_SRAM_BASE) && defined(CONFIG_SYS_SRAM_SIZE) + bd->bi_sramstart = CONFIG_SYS_SRAM_BASE; + bd->bi_sramsize = CONFIG_SYS_SRAM_SIZE; +#endif + bd->bi_baudrate = CONFIG_BAUDRATE; + bd->bi_bootflags = bootflag; /* boot / reboot flag (for LynxOS) */ + + gd->flags |= GD_FLG_RELOC; /* tell others: relocation done */ + gd->reloc_off = CONFIG_SYS_RELOC_MONITOR_BASE - CONFIG_SYS_MONITOR_BASE; + + for (init_fnc_ptr = init_sequence, j = 0; *init_fnc_ptr; + ++init_fnc_ptr, j++) { +#ifdef DEBUG_INIT_SEQUENCE + if (j > 9) + str_init_seq[9] = '0' + (j / 10); + str_init_seq[10] = '0' + (j - (j / 10) * 10); + serial_puts(str_init_seq); +#endif + if ((*init_fnc_ptr + gd->reloc_off) () != 0) { + hang(); + } + } +#ifdef DEBUG_INIT_SEQUENCE + serial_puts(str_init_seq_done); +#endif + + /* + * Now that we have DRAM mapped and working, we can + * relocate the code and continue running from DRAM. + * + * Reserve memory at end of RAM for (top down in that order): + * - kernel log buffer + * - protected RAM + * - LCD framebuffer + * - monitor code + * - board info struct + */ +#ifdef DEBUG_MEM_LAYOUT + printf("CONFIG_SYS_MONITOR_BASE: 0x%lx\n", CONFIG_SYS_MONITOR_BASE); + printf("CONFIG_ENV_ADDR: 0x%lx\n", CONFIG_ENV_ADDR); + printf("CONFIG_SYS_RELOC_MONITOR_BASE: 0x%lx (%d)\n", CONFIG_SYS_RELOC_MONITOR_BASE, + CONFIG_SYS_MONITOR_LEN); + printf("CONFIG_SYS_MALLOC_BASE: 0x%lx (%d)\n", CONFIG_SYS_MALLOC_BASE, + CONFIG_SYS_MALLOC_LEN); + printf("CONFIG_SYS_INIT_SP_OFFSET: 0x%lx (%d)\n", CONFIG_SYS_INIT_SP_OFFSET, + CONFIG_SYS_STACK_SIZE); + printf("CONFIG_SYS_PROM_OFFSET: 0x%lx (%d)\n", CONFIG_SYS_PROM_OFFSET, + CONFIG_SYS_PROM_SIZE); + printf("CONFIG_SYS_GBL_DATA_OFFSET: 0x%lx (%d)\n", CONFIG_SYS_GBL_DATA_OFFSET, + CONFIG_SYS_GBL_DATA_SIZE); +#endif + +#ifdef CONFIG_POST + post_bootmode_init(); + post_run(NULL, POST_ROM | post_bootmode_get(0)); +#endif + + /* + * We have to relocate the command table manually + */ + for (cmdtp = &__u_boot_cmd_start; cmdtp != &__u_boot_cmd_end; cmdtp++) { + ulong addr; + addr = (ulong) (cmdtp->cmd) + gd->reloc_off; +#if DEBUG_COMMANDS + printf("Command \"%s\": 0x%08lx => 0x%08lx\n", + cmdtp->name, (ulong) (cmdtp->cmd), addr); +#endif + cmdtp->cmd = + (int (*)(struct cmd_tbl_s *, int, int, char *[]))addr; + + addr = (ulong) (cmdtp->name) + gd->reloc_off; + cmdtp->name = (char *)addr; + + if (cmdtp->usage) { + addr = (ulong) (cmdtp->usage) + gd->reloc_off; + cmdtp->usage = (char *)addr; + } +#ifdef CONFIG_SYS_LONGHELP + if (cmdtp->help) { + addr = (ulong) (cmdtp->help) + gd->reloc_off; + cmdtp->help = (char *)addr; + } +#endif + } + +#if defined(CONFIG_CMD_AMBAPP) && defined(CONFIG_SYS_AMBAPP_PRINT_ON_STARTUP) + puts("AMBA:\n"); + do_ambapp_print(NULL, 0, 0, NULL); +#endif + + /* initialize higher level parts of CPU like time base and timers */ + cpu_init_r(); + + /* start timer */ + timer_interrupt_init(); + + /* + * Enable Interrupts before any calls to udelay, + * the flash driver may use udelay resulting in + * a hang if not timer0 IRQ is enabled. + */ + interrupt_init(); + + /* The Malloc area is immediately below the monitor copy in RAM */ + mem_malloc_init(CONFIG_SYS_MALLOC_BASE, + CONFIG_SYS_MALLOC_END - CONFIG_SYS_MALLOC_BASE); + malloc_bin_reloc(); + +#if !defined(CONFIG_SYS_NO_FLASH) + puts("FLASH: "); + + if ((flash_size = flash_init()) > 0) { +# ifdef CONFIG_SYS_FLASH_CHECKSUM + print_size(flash_size, ""); + /* + * Compute and print flash CRC if flashchecksum is set to 'y' + * + * NOTE: Maybe we should add some WATCHDOG_RESET()? XXX + */ + s = getenv("flashchecksum"); + if (s && (*s == 'y')) { + printf(" CRC: %08lX", + crc32(0, (const unsigned char *)CONFIG_SYS_FLASH_BASE, + flash_size) + ); + } + putc('\n'); +# else /* !CONFIG_SYS_FLASH_CHECKSUM */ + print_size(flash_size, "\n"); +# endif /* CONFIG_SYS_FLASH_CHECKSUM */ + } else { + puts(failed); + hang(); + } + + bd->bi_flashstart = CONFIG_SYS_FLASH_BASE; /* update start of FLASH memory */ + bd->bi_flashsize = flash_size; /* size of FLASH memory (final value) */ +#if CONFIG_SYS_MONITOR_BASE == CONFIG_SYS_FLASH_BASE + bd->bi_flashoffset = monitor_flash_len; /* reserved area for startup monitor */ +#else + bd->bi_flashoffset = 0; +#endif +#else /* CONFIG_SYS_NO_FLASH */ + bd->bi_flashsize = 0; + bd->bi_flashstart = 0; + bd->bi_flashoffset = 0; +#endif /* !CONFIG_SYS_NO_FLASH */ + +#ifdef CONFIG_SPI +# if !defined(CONFIG_ENV_IS_IN_EEPROM) + spi_init_f(); +# endif + spi_init_r(); +#endif + + /* relocate environment function pointers etc. */ + env_relocate(); + +#if defined(CONFIG_BOARD_LATE_INIT) + board_late_init(); +#endif + +#ifdef CONFIG_ID_EEPROM + mac_read_from_eeprom(); +#endif + + /* IP Address */ + bd->bi_ip_addr = getenv_IPaddr("ipaddr"); +#if defined(CONFIG_PCI) + /* + * Do pci configuration + */ + pci_init(); +#endif + + /* Initialize stdio devices */ + stdio_init(); + + /* Initialize the jump table for applications */ + jumptable_init(); + + /* Initialize the console (after the relocation and devices init) */ + console_init_r(); + +#ifdef CONFIG_SERIAL_SOFTWARE_FIFO + serial_buffered_init(); +#endif + +#ifdef CONFIG_STATUS_LED + status_led_set(STATUS_LED_BOOT, STATUS_LED_BLINKING); +#endif + + udelay(20); + + set_timer(0); + + /* Initialize from environment */ + if ((s = getenv("loadaddr")) != NULL) { + load_addr = simple_strtoul(s, NULL, 16); + } +#if defined(CONFIG_CMD_NET) + if ((s = getenv("bootfile")) != NULL) { + copy_filename(BootFile, s, sizeof(BootFile)); + } +#endif /* CONFIG_CMD_NET */ + + WATCHDOG_RESET(); + +#if defined(CONFIG_CMD_DOC) + WATCHDOG_RESET(); + puts("DOC: "); + doc_init(); +#endif + +#ifdef CONFIG_BITBANGMII + bb_miiphy_init(); +#endif +#if defined(CONFIG_CMD_NET) +#if defined(CONFIG_NET_MULTI) + WATCHDOG_RESET(); + puts("Net: "); +#endif + eth_initialize(bd); +#endif + +#if defined(CONFIG_CMD_NET) && defined(CONFIG_RESET_PHY_R) + WATCHDOG_RESET(); + debug("Reset Ethernet PHY\n"); + reset_phy(); +#endif + +#ifdef CONFIG_POST + post_run(NULL, POST_RAM | post_bootmode_get(0)); +#endif + +#if defined(CONFIG_CMD_IDE) + WATCHDOG_RESET(); + puts("IDE: "); + ide_init(); +#endif /* CONFIG_CMD_IDE */ + +#ifdef CONFIG_LAST_STAGE_INIT + WATCHDOG_RESET(); + /* + * Some parts can be only initialized if all others (like + * Interrupts) are up and running (i.e. the PC-style ISA + * keyboard). + */ + last_stage_init(); +#endif + +#ifdef CONFIG_PS2KBD + puts("PS/2: "); + kbd_init(); +#endif + prom_init(); + + /* main_loop */ + for (;;) { + WATCHDOG_RESET(); + main_loop(); + } + +} + +void hang(void) +{ + puts("### ERROR ### Please RESET the board ###\n"); +#ifdef CONFIG_SHOW_BOOT_PROGRESS + show_boot_progress(-30); +#endif + for (;;) ; +} + +/************************************************************************/ diff --git a/arch/sparc/lib/bootm.c b/arch/sparc/lib/bootm.c new file mode 100644 index 0000000..c62cf57 --- /dev/null +++ b/arch/sparc/lib/bootm.c @@ -0,0 +1,189 @@ +/* SPARC code for booting linux 2.6 + * + * (C) Copyright 2007 + * Daniel Hellstrom, Gaisler Research, daniel@gaisler.com. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 program is distributed in the hope that 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 <common.h> +#include <command.h> +#include <asm/byteorder.h> +#include <asm/prom.h> +#include <asm/cache.h> +#include <image.h> + +#define PRINT_KERNEL_HEADER + +extern image_header_t header; +extern void srmmu_init_cpu(unsigned int entry); +extern void prepare_bootargs(char *bootargs); + +#ifdef CONFIG_USB_UHCI +extern int usb_lowlevel_stop(void); +#endif + +/* sparc kernel argument (the ROM vector) */ +struct linux_romvec *kernel_arg_promvec; + +/* page szie is 4k */ +#define PAGE_SIZE 0x1000 +#define RAMDISK_IMAGE_START_MASK 0x07FF +#define RAMDISK_PROMPT_FLAG 0x8000 +#define RAMDISK_LOAD_FLAG 0x4000 +struct __attribute__ ((packed)) { + char traptable[PAGE_SIZE]; + char swapper_pg_dir[PAGE_SIZE]; + char pg0[PAGE_SIZE]; + char pg1[PAGE_SIZE]; + char pg2[PAGE_SIZE]; + char pg3[PAGE_SIZE]; + char empty_bad_page[PAGE_SIZE]; + char empty_bad_page_table[PAGE_SIZE]; + char empty_zero_page[PAGE_SIZE]; + unsigned char hdr[4]; /* ascii "HdrS" */ + /* 00.02.06.0b is for Linux kernel 2.6.11 */ + unsigned char linuxver_mega_major; + unsigned char linuxver_major; + unsigned char linuxver_minor; + unsigned char linuxver_revision; + /* header version 0x0203 */ + unsigned short hdr_ver; + union __attribute__ ((packed)) { + struct __attribute__ ((packed)) { + unsigned short root_flags; + unsigned short root_dev; + unsigned short ram_flags; + unsigned int sparc_ramdisk_image; + unsigned int sparc_ramdisk_size; + unsigned int reboot_command; + unsigned int resv[3]; + unsigned int end; + } ver_0203; + } hdr_input; +} *linux_hdr; + +/* temporary initrd image holder */ +image_header_t ihdr; + +void arch_lmb_reserve(struct lmb *lmb) +{ + /* Reserve the space used by PROM and stack. This is done + * to avoid that the RAM image is copied over stack or + * PROM. + */ + lmb_reserve(lmb, CONFIG_SYS_RELOC_MONITOR_BASE, CONFIG_SYS_RAM_END); +} + +/* boot the linux kernel */ +int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t * images) +{ + char *bootargs; + ulong initrd_start, initrd_end; + ulong rd_len; + unsigned int data, len, checksum; + unsigned int initrd_addr, kernend; + void (*kernel) (struct linux_romvec *, void *); + struct lmb *lmb = &images->lmb; + int ret; + + if ((flag != 0) && (flag != BOOTM_STATE_OS_GO)) + return 1; + + /* Get virtual address of kernel start */ + linux_hdr = (void *)images->os.load; + + /* */ + kernel = (void (*)(struct linux_romvec *, void *))images->ep; + + /* check for a SPARC kernel */ + if ((linux_hdr->hdr[0] != 'H') || + (linux_hdr->hdr[1] != 'd') || + (linux_hdr->hdr[2] != 'r') || (linux_hdr->hdr[3] != 'S')) { + puts("Error reading header of SPARC Linux kernel, aborting\n"); + goto error; + } +#ifdef PRINT_KERNEL_HEADER + printf("## Found SPARC Linux kernel %d.%d.%d ...\n", + linux_hdr->linuxver_major, + linux_hdr->linuxver_minor, linux_hdr->linuxver_revision); +#endif + +#ifdef CONFIG_USB_UHCI + usb_lowlevel_stop(); +#endif + + /* set basic boot params in kernel header now that it has been + * extracted and is writeable. + */ + + /* Calc length of RAM disk, if zero no ramdisk available */ + rd_len = images->rd_end - images->rd_start; + + if (rd_len) { + ret = boot_ramdisk_high(lmb, images->rd_start, rd_len, + &initrd_start, &initrd_end); + if (ret) { + puts("### Failed to relocate RAM disk\n"); + goto error; + } + + /* Update SPARC kernel header so that Linux knows + * what is going on and where to find RAM disk. + * + * Set INITRD Image address relative to RAM Start + */ + linux_hdr->hdr_input.ver_0203.sparc_ramdisk_image = + initrd_start - CONFIG_SYS_RAM_BASE; + linux_hdr->hdr_input.ver_0203.sparc_ramdisk_size = rd_len; + /* Clear READ ONLY flag if set to non-zero */ + linux_hdr->hdr_input.ver_0203.root_flags = 1; + /* Set root device to: Root_RAM0 */ + linux_hdr->hdr_input.ver_0203.root_dev = 0x100; + linux_hdr->hdr_input.ver_0203.ram_flags = 0; + } else { + /* NOT using RAMDISK image, overwriting kernel defaults */ + linux_hdr->hdr_input.ver_0203.sparc_ramdisk_image = 0; + linux_hdr->hdr_input.ver_0203.sparc_ramdisk_size = 0; + /* Leave to kernel defaults + linux_hdr->hdr_input.ver_0203.root_flags = 1; + linux_hdr->hdr_input.ver_0203.root_dev = 0; + linux_hdr->hdr_input.ver_0203.ram_flags = 0; + */ + } + + /* Copy bootargs from bootargs variable to kernel readable area */ + bootargs = getenv("bootargs"); + prepare_bootargs(bootargs); + + /* turn on mmu & setup context table & page table for process 0 (kernel) */ + srmmu_init_cpu((unsigned int)kernel); + + /* Enter SPARC Linux kernel + * From now on the only code in u-boot that will be + * executed is the PROM code. + */ + kernel(kernel_arg_promvec, (void *)images->ep); + + /* It will never come to this... */ + while (1) ; + + error: + return 1; +} diff --git a/arch/sparc/lib/cache.c b/arch/sparc/lib/cache.c new file mode 100644 index 0000000..59d9bbe --- /dev/null +++ b/arch/sparc/lib/cache.c @@ -0,0 +1,33 @@ +/* Sparc cache library + * + * (C) Copyright 2007 + * Daniel Hellstrom, Gaisler Research, daniel@gaisler.com. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 program is distributed in the hope that 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 <common.h> +#include <asm/processor.h> + +void flush_cache(ulong start_addr, ulong size) +{ + /* Flush All Cache */ + sparc_dcache_flush_all(); + sparc_icache_flush_all(); +} diff --git a/arch/sparc/lib/interrupts.c b/arch/sparc/lib/interrupts.c new file mode 100644 index 0000000..4c73b82 --- /dev/null +++ b/arch/sparc/lib/interrupts.c @@ -0,0 +1,122 @@ +/* + * (C) Copyright 2000-2002 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * (C) Copyright 2003 + * Gleb Natapov <gnatapov@mrv.com> + * + * (C) Copyright 2007 + * Daniel Hellstrom, Gaisler Research, daniel@gaisler.com. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 program is distributed in the hope that 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 <common.h> +#include <asm/processor.h> +#include <asm/irq.h> + +/* Implemented by SPARC CPUs */ +extern int interrupt_init_cpu(void); +extern void timer_interrupt_cpu(void *arg); +extern int timer_interrupt_init_cpu(void); + +int intLock(void) +{ + unsigned int pil; + + pil = get_pil(); + + /* set PIL to 15 ==> no pending interrupts will interrupt CPU */ + set_pil(15); + + return pil; +} + +void intUnlock(int oldLevel) +{ + set_pil(oldLevel); +} + +void enable_interrupts(void) +{ + set_pil(0); /* enable all interrupts */ +} + +int disable_interrupts(void) +{ + return intLock(); +} + +int interrupt_init(void) +{ + int ret; + + /* call cpu specific function from $(CPU)/interrupts.c */ + ret = interrupt_init_cpu(); + + /* enable global interrupts */ + enable_interrupts(); + + return ret; +} + +/* timer interrupt/overflow counter */ +static volatile ulong timestamp = 0; + +/* regs can not be used here! regs is actually the pointer given in + * irq_install_handler + */ +void timer_interrupt(struct pt_regs *regs) +{ + /* call cpu specific function from $(CPU)/interrupts.c */ + timer_interrupt_cpu((void *)regs); + + timestamp++; +} + +void reset_timer(void) +{ + timestamp = 0; +} + +ulong get_timer(ulong base) +{ + return (timestamp - base); +} + +void set_timer(ulong t) +{ + timestamp = t; +} + +void timer_interrupt_init(void) +{ + int irq; + + reset_timer(); + + irq = timer_interrupt_init_cpu(); + + if (irq < 0) { + /* cpu specific code handled the interrupt registration it self */ + return; + } + /* register interrupt handler for timer */ + irq_install_handler(irq, (void (*)(void *))timer_interrupt, NULL); +} diff --git a/arch/sparc/lib/time.c b/arch/sparc/lib/time.c new file mode 100644 index 0000000..82b2a3a --- /dev/null +++ b/arch/sparc/lib/time.c @@ -0,0 +1,78 @@ +/* + * (C) Copyright 2000, 2001 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * (C) Copyright 2007 + * Daniel Hellstrom, Gaisler Research, daniel@gaisler.com. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 program is distributed in the hope that 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 <common.h> + +/* Implemented by SPARC CPUs */ +extern void cpu_wait_ticks(unsigned long ticks); +extern unsigned long cpu_usec2ticks(unsigned long usec); +extern unsigned long cpu_ticks2usec(unsigned long ticks); + +/* ------------------------------------------------------------------------- */ + +void wait_ticks(unsigned long ticks) +{ + cpu_wait_ticks(ticks); +} + +/* + * This function is intended for SHORT delays only. + */ +unsigned long usec2ticks(unsigned long usec) +{ + return cpu_usec2ticks(usec); +} + +/* ------------------------------------------------------------------------- */ + +/* + * We implement the delay by converting the delay (the number of + * microseconds to wait) into a number of time base ticks; then we + * watch the time base until it has incremented by that amount. + */ +void __udelay(unsigned long usec) +{ + ulong ticks = usec2ticks(usec); + + wait_ticks(ticks); +} + +/* ------------------------------------------------------------------------- */ + +unsigned long ticks2usec(unsigned long ticks) +{ + return cpu_ticks2usec(ticks); +} + +/* ------------------------------------------------------------------------- */ + +int init_timebase(void) +{ + + return (0); +} + +/* ------------------------------------------------------------------------- */ |