diff options
Diffstat (limited to 'arch/x86/cpu')
-rw-r--r-- | arch/x86/cpu/Makefile | 50 | ||||
-rw-r--r-- | arch/x86/cpu/config.mk | 32 | ||||
-rw-r--r-- | arch/x86/cpu/cpu.c | 157 | ||||
-rw-r--r-- | arch/x86/cpu/interrupts.c | 674 | ||||
-rw-r--r-- | arch/x86/cpu/resetvec.S | 38 | ||||
-rw-r--r-- | arch/x86/cpu/sc520/Makefile | 58 | ||||
-rw-r--r-- | arch/x86/cpu/sc520/sc520.c | 67 | ||||
-rw-r--r-- | arch/x86/cpu/sc520/sc520_car.S | 93 | ||||
-rw-r--r-- | arch/x86/cpu/sc520/sc520_pci.c | 140 | ||||
-rw-r--r-- | arch/x86/cpu/sc520/sc520_reset.c | 40 | ||||
-rw-r--r-- | arch/x86/cpu/sc520/sc520_sdram.c | 532 | ||||
-rw-r--r-- | arch/x86/cpu/sc520/sc520_ssi.c | 92 | ||||
-rw-r--r-- | arch/x86/cpu/sc520/sc520_timer.c | 90 | ||||
-rw-r--r-- | arch/x86/cpu/start.S | 132 | ||||
-rw-r--r-- | arch/x86/cpu/start16.S | 113 | ||||
-rw-r--r-- | arch/x86/cpu/u-boot.lds | 97 |
16 files changed, 2405 insertions, 0 deletions
diff --git a/arch/x86/cpu/Makefile b/arch/x86/cpu/Makefile new file mode 100644 index 0000000000..ddde83c91d --- /dev/null +++ b/arch/x86/cpu/Makefile @@ -0,0 +1,50 @@ +# +# (C) Copyright 2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# (C) Copyright 2002 +# Daniel Engström, Omicron Ceti AB, daniel@omicron.se. +# +# 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).o + +START = start.o start16.o resetvec.o +COBJS = interrupts.o cpu.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) + $(call cmd_link_o_target, $(OBJS)) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/arch/x86/cpu/config.mk b/arch/x86/cpu/config.mk new file mode 100644 index 0000000000..d1b528a437 --- /dev/null +++ b/arch/x86/cpu/config.mk @@ -0,0 +1,32 @@ +# +# (C) Copyright 2002 +# Daniel Engström, Omicron Ceti AB, daniel@omicron.se. +# +# 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 ?= i386-linux- + +PLATFORM_CPPFLAGS += -DCONFIG_X86 -D__I386__ -march=i386 -Werror + +# DO NOT MODIFY THE FOLLOWING UNLESS YOU REALLY KNOW WHAT YOU ARE DOING! +LDPPFLAGS += -DRESET_SEG_START=0xffff0000 +LDPPFLAGS += -DRESET_SEG_SIZE=0x10000 +LDPPFLAGS += -DRESET_VEC_LOC=0xfff0 +LDPPFLAGS += -DSTART_16=0xf800 diff --git a/arch/x86/cpu/cpu.c b/arch/x86/cpu/cpu.c new file mode 100644 index 0000000000..0c5d7c3d53 --- /dev/null +++ b/arch/x86/cpu/cpu.c @@ -0,0 +1,157 @@ +/* + * (C) Copyright 2008-2011 + * Graeme Russ, <graeme.russ@gmail.com> + * + * (C) Copyright 2002 + * Daniel Engström, Omicron Ceti AB, <daniel@omicron.se> + * + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Marius Groeger <mgroeger@sysgo.de> + * + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Alex Zuepke <azu@sysgo.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 <common.h> +#include <command.h> +#include <asm/processor.h> +#include <asm/processor-flags.h> +#include <asm/interrupt.h> + +/* + * Constructor for a conventional segment GDT (or LDT) entry + * This is a macro so it can be used in initialisers + */ +#define GDT_ENTRY(flags, base, limit) \ + ((((base) & 0xff000000ULL) << (56-24)) | \ + (((flags) & 0x0000f0ffULL) << 40) | \ + (((limit) & 0x000f0000ULL) << (48-16)) | \ + (((base) & 0x00ffffffULL) << 16) | \ + (((limit) & 0x0000ffffULL))) + +struct gdt_ptr { + u16 len; + u32 ptr; +} __attribute__((packed)); + +static void reload_gdt(void) +{ + /* + * There are machines which are known to not boot with the GDT + * being 8-byte unaligned. Intel recommends 16 byte alignment + */ + static const u64 boot_gdt[] __attribute__((aligned(16))) = { + /* CS: code, read/execute, 4 GB, base 0 */ + [GDT_ENTRY_32BIT_CS] = GDT_ENTRY(0xc09b, 0, 0xfffff), + /* DS: data, read/write, 4 GB, base 0 */ + [GDT_ENTRY_32BIT_DS] = GDT_ENTRY(0xc093, 0, 0xfffff), + /* 16-bit CS: code, read/execute, 64 kB, base 0 */ + [GDT_ENTRY_16BIT_CS] = GDT_ENTRY(0x109b, 0, 0x0ffff), + /* 16-bit DS: data, read/write, 64 kB, base 0 */ + [GDT_ENTRY_16BIT_DS] = GDT_ENTRY(0x1093, 0, 0x0ffff), + }; + static struct gdt_ptr gdt; + + gdt.len = sizeof(boot_gdt)-1; + gdt.ptr = (u32)&boot_gdt; + + asm volatile("lgdtl %0\n" \ + "movl $((2+1)*8), %%ecx\n" \ + "movl %%ecx, %%ds\n" \ + "movl %%ecx, %%es\n" \ + "movl %%ecx, %%fs\n" \ + "movl %%ecx, %%gs\n" \ + "movl %%ecx, %%ss" \ + : : "m" (gdt) : "ecx"); +} + +int x86_cpu_init_f(void) +{ + const u32 em_rst = ~X86_CR0_EM; + const u32 mp_ne_set = X86_CR0_MP | X86_CR0_NE; + + /* initialize FPU, reset EM, set MP and NE */ + asm ("fninit\n" \ + "movl %%cr0, %%eax\n" \ + "andl %0, %%eax\n" \ + "orl %1, %%eax\n" \ + "movl %%eax, %%cr0\n" \ + : : "i" (em_rst), "i" (mp_ne_set) : "eax"); + + return 0; +} +int cpu_init_f(void) __attribute__((weak, alias("x86_cpu_init_f"))); + +int x86_cpu_init_r(void) +{ + const u32 nw_cd_rst = ~(X86_CR0_NW | X86_CR0_CD); + + /* turn on the cache and disable write through */ + asm("movl %%cr0, %%eax\n" + "andl %0, %%eax\n" + "movl %%eax, %%cr0\n" + "wbinvd\n" : : "i" (nw_cd_rst) : "eax"); + + reload_gdt(); + + /* Initialize core interrupt and exception functionality of CPU */ + cpu_init_interrupts (); + return 0; +} +int cpu_init_r(void) __attribute__((weak, alias("x86_cpu_init_r"))); + +int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + printf ("resetting ...\n"); + + /* wait 50 ms */ + udelay(50000); + disable_interrupts(); + reset_cpu(0); + + /*NOTREACHED*/ + return 0; +} + +void flush_cache (unsigned long dummy1, unsigned long dummy2) +{ + asm("wbinvd\n"); +} + +void __attribute__ ((regparm(0))) generate_gpf(void); + +/* segment 0x70 is an arbitrary segment which does not exist */ +asm(".globl generate_gpf\n" + ".hidden generate_gpf\n" + ".type generate_gpf, @function\n" + "generate_gpf:\n" + "ljmp $0x70, $0x47114711\n"); + +void __reset_cpu(ulong addr) +{ + printf("Resetting using x86 Triple Fault\n"); + set_vector(13, generate_gpf); /* general protection fault handler */ + set_vector(8, generate_gpf); /* double fault handler */ + generate_gpf(); /* start the show */ +} +void reset_cpu(ulong addr) __attribute__((weak, alias("__reset_cpu"))); diff --git a/arch/x86/cpu/interrupts.c b/arch/x86/cpu/interrupts.c new file mode 100644 index 0000000000..62bcadc486 --- /dev/null +++ b/arch/x86/cpu/interrupts.c @@ -0,0 +1,674 @@ +/* + * (C) Copyright 2008-2011 + * Graeme Russ, <graeme.russ@gmail.com> + * + * (C) Copyright 2002 + * Daniel Engström, Omicron Ceti AB, <daniel@omicron.se> + * + * Portions of this file are derived from the Linux kernel source + * Copyright (C) 1991, 1992 Linus Torvalds + * + * 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/interrupt.h> +#include <asm/io.h> +#include <asm/processor-flags.h> + +#define DECLARE_INTERRUPT(x) \ + ".globl irq_"#x"\n" \ + ".hidden irq_"#x"\n" \ + ".type irq_"#x", @function\n" \ + "irq_"#x":\n" \ + "pushl $"#x"\n" \ + "jmp irq_common_entry\n" + +/* + * Volatile isn't enough to prevent the compiler from reordering the + * read/write functions for the control registers and messing everything up. + * A memory clobber would solve the problem, but would prevent reordering of + * all loads stores around it, which can hurt performance. Solution is to + * use a variable and mimic reads and writes to it to enforce serialisation + */ +static unsigned long __force_order; + +static inline unsigned long read_cr0(void) +{ + unsigned long val; + asm volatile("mov %%cr0,%0\n\t" : "=r" (val), "=m" (__force_order)); + return val; +} + +static inline unsigned long read_cr2(void) +{ + unsigned long val; + asm volatile("mov %%cr2,%0\n\t" : "=r" (val), "=m" (__force_order)); + return val; +} + +static inline unsigned long read_cr3(void) +{ + unsigned long val; + asm volatile("mov %%cr3,%0\n\t" : "=r" (val), "=m" (__force_order)); + return val; +} + +static inline unsigned long read_cr4(void) +{ + unsigned long val; + asm volatile("mov %%cr4,%0\n\t" : "=r" (val), "=m" (__force_order)); + return val; +} + +static inline unsigned long get_debugreg(int regno) +{ + unsigned long val = 0; /* Damn you, gcc! */ + + switch (regno) { + case 0: + asm("mov %%db0, %0" :"=r" (val)); + break; + case 1: + asm("mov %%db1, %0" :"=r" (val)); + break; + case 2: + asm("mov %%db2, %0" :"=r" (val)); + break; + case 3: + asm("mov %%db3, %0" :"=r" (val)); + break; + case 6: + asm("mov %%db6, %0" :"=r" (val)); + break; + case 7: + asm("mov %%db7, %0" :"=r" (val)); + break; + default: + val = 0; + } + return val; +} + +void dump_regs(struct irq_regs *regs) +{ + unsigned long cr0 = 0L, cr2 = 0L, cr3 = 0L, cr4 = 0L; + unsigned long d0, d1, d2, d3, d6, d7; + unsigned long sp; + + printf("EIP: %04x:[<%08lx>] EFLAGS: %08lx\n", + (u16)regs->xcs, regs->eip, regs->eflags); + + printf("EAX: %08lx EBX: %08lx ECX: %08lx EDX: %08lx\n", + regs->eax, regs->ebx, regs->ecx, regs->edx); + printf("ESI: %08lx EDI: %08lx EBP: %08lx ESP: %08lx\n", + regs->esi, regs->edi, regs->ebp, regs->esp); + printf(" DS: %04x ES: %04x FS: %04x GS: %04x SS: %04x\n", + (u16)regs->xds, (u16)regs->xes, (u16)regs->xfs, (u16)regs->xgs, (u16)regs->xss); + + cr0 = read_cr0(); + cr2 = read_cr2(); + cr3 = read_cr3(); + cr4 = read_cr4(); + + printf("CR0: %08lx CR2: %08lx CR3: %08lx CR4: %08lx\n", + cr0, cr2, cr3, cr4); + + d0 = get_debugreg(0); + d1 = get_debugreg(1); + d2 = get_debugreg(2); + d3 = get_debugreg(3); + + printf("DR0: %08lx DR1: %08lx DR2: %08lx DR3: %08lx\n", + d0, d1, d2, d3); + + d6 = get_debugreg(6); + d7 = get_debugreg(7); + printf("DR6: %08lx DR7: %08lx\n", + d6, d7); + + printf("Stack:\n"); + sp = regs->esp; + + sp += 64; + + while (sp > (regs->esp - 16)) { + if (sp == regs->esp) + printf("--->"); + else + printf(" "); + printf("0x%8.8lx : 0x%8.8lx\n", sp, (ulong)readl(sp)); + sp -= 4; + } +} + +struct idt_entry { + u16 base_low; + u16 selector; + u8 res; + u8 access; + u16 base_high; +} __attribute__ ((packed)); + +struct desc_ptr { + unsigned short size; + unsigned long address; + unsigned short segment; +} __attribute__((packed)); + +struct idt_entry idt[256]; + +struct desc_ptr idt_ptr; + +static inline void load_idt(const struct desc_ptr *dtr) +{ + asm volatile("cs lidt %0"::"m" (*dtr)); +} + +void set_vector(u8 intnum, void *routine) +{ + idt[intnum].base_high = (u16)((u32)(routine) >> 16); + idt[intnum].base_low = (u16)((u32)(routine) & 0xffff); +} + +void irq_0(void); +void irq_1(void); + +int cpu_init_interrupts(void) +{ + int i; + + int irq_entry_size = irq_1 - irq_0; + void *irq_entry = (void *)irq_0; + + /* Just in case... */ + disable_interrupts(); + + /* Setup the IDT */ + for (i=0;i<256;i++) { + idt[i].access = 0x8e; + idt[i].res = 0; + idt[i].selector = 0x10; + set_vector(i, irq_entry); + irq_entry += irq_entry_size; + } + + idt_ptr.size = 256 * 8; + idt_ptr.address = (unsigned long) idt; + idt_ptr.segment = 0x18; + + load_idt(&idt_ptr); + + /* It is now safe to enable interrupts */ + enable_interrupts(); + + return 0; +} + +void __do_irq(int irq) +{ + printf("Unhandled IRQ : %d\n", irq); +} +void do_irq(int irq) __attribute__((weak, alias("__do_irq"))); + +void enable_interrupts(void) +{ + asm("sti\n"); +} + +int disable_interrupts(void) +{ + long flags; + + asm volatile ("pushfl ; popl %0 ; cli\n" : "=g" (flags) : ); + + return flags & X86_EFLAGS_IF; /* IE flags is bit 9 */ +} + +/* IRQ Low-Level Service Routine */ +void irq_llsr(struct irq_regs *regs) +{ + /* + * For detailed description of each exception, refer to: + * Intel® 64 and IA-32 Architectures Software Developer's Manual + * Volume 1: Basic Architecture + * Order Number: 253665-029US, November 2008 + * Table 6-1. Exceptions and Interrupts + */ + switch (regs->irq_id) { + case 0x00: + printf("Divide Error (Division by zero)\n"); + dump_regs(regs); + while(1); + break; + case 0x01: + printf("Debug Interrupt (Single step)\n"); + dump_regs(regs); + break; + case 0x02: + printf("NMI Interrupt\n"); + dump_regs(regs); + break; + case 0x03: + printf("Breakpoint\n"); + dump_regs(regs); + break; + case 0x04: + printf("Overflow\n"); + dump_regs(regs); + while(1); + break; + case 0x05: + printf("BOUND Range Exceeded\n"); + dump_regs(regs); + while(1); + break; + case 0x06: + printf("Invalid Opcode (UnDefined Opcode)\n"); + dump_regs(regs); + while(1); + break; + case 0x07: + printf("Device Not Available (No Math Coprocessor)\n"); + dump_regs(regs); + while(1); + break; + case 0x08: + printf("Double fault\n"); + dump_regs(regs); + while(1); + break; + case 0x09: + printf("Co-processor segment overrun\n"); + dump_regs(regs); + while(1); + break; + case 0x0a: + printf("Invalid TSS\n"); + dump_regs(regs); + break; + case 0x0b: + printf("Segment Not Present\n"); + dump_regs(regs); + while(1); + break; + case 0x0c: + printf("Stack Segment Fault\n"); + dump_regs(regs); + while(1); + break; + case 0x0d: + printf("General Protection\n"); + dump_regs(regs); + break; + case 0x0e: + printf("Page fault\n"); + dump_regs(regs); + while(1); + break; + case 0x0f: + printf("Floating-Point Error (Math Fault)\n"); + dump_regs(regs); + break; + case 0x10: + printf("Alignment check\n"); + dump_regs(regs); + break; + case 0x11: + printf("Machine Check\n"); + dump_regs(regs); + break; + case 0x12: + printf("SIMD Floating-Point Exception\n"); + dump_regs(regs); + break; + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + case 0x18: + case 0x19: + case 0x1a: + case 0x1b: + case 0x1c: + case 0x1d: + case 0x1e: + case 0x1f: + printf("Reserved Exception\n"); + dump_regs(regs); + break; + + default: + /* Hardware or User IRQ */ + do_irq(regs->irq_id); + } +} + +/* + * OK - This looks really horrible, but it serves a purpose - It helps create + * fully relocatable code. + * - The call to irq_llsr will be a relative jump + * - The IRQ entries will be guaranteed to be in order + * Interrupt entries are now very small (a push and a jump) but they are + * now slower (all registers pushed on stack which provides complete + * crash dumps in the low level handlers + * + * Interrupt Entry Point: + * - Interrupt has caused eflags, CS and EIP to be pushed + * - Interrupt Vector Handler has pushed orig_eax + * - pt_regs.esp needs to be adjusted by 40 bytes: + * 12 bytes pushed by CPU (EFLAGSF, CS, EIP) + * 4 bytes pushed by vector handler (irq_id) + * 24 bytes pushed before SP (SS, GS, FS, ES, DS, EAX) + * NOTE: Only longs are pushed on/popped off the stack! + */ +asm(".globl irq_common_entry\n" \ + ".hidden irq_common_entry\n" \ + ".type irq_common_entry, @function\n" \ + "irq_common_entry:\n" \ + "cld\n" \ + "pushl %ss\n" \ + "pushl %gs\n" \ + "pushl %fs\n" \ + "pushl %es\n" \ + "pushl %ds\n" \ + "pushl %eax\n" \ + "movl %esp, %eax\n" \ + "addl $40, %eax\n" \ + "pushl %eax\n" \ + "pushl %ebp\n" \ + "pushl %edi\n" \ + "pushl %esi\n" \ + "pushl %edx\n" \ + "pushl %ecx\n" \ + "pushl %ebx\n" \ + "mov %esp, %eax\n" \ + "call irq_llsr\n" \ + "popl %ebx\n" \ + "popl %ecx\n" \ + "popl %edx\n" \ + "popl %esi\n" \ + "popl %edi\n" \ + "popl %ebp\n" \ + "popl %eax\n" \ + "popl %eax\n" \ + "popl %ds\n" \ + "popl %es\n" \ + "popl %fs\n" \ + "popl %gs\n" \ + "popl %ss\n" \ + "add $4, %esp\n" \ + "iret\n" \ + DECLARE_INTERRUPT(0) \ + DECLARE_INTERRUPT(1) \ + DECLARE_INTERRUPT(2) \ + DECLARE_INTERRUPT(3) \ + DECLARE_INTERRUPT(4) \ + DECLARE_INTERRUPT(5) \ + DECLARE_INTERRUPT(6) \ + DECLARE_INTERRUPT(7) \ + DECLARE_INTERRUPT(8) \ + DECLARE_INTERRUPT(9) \ + DECLARE_INTERRUPT(10) \ + DECLARE_INTERRUPT(11) \ + DECLARE_INTERRUPT(12) \ + DECLARE_INTERRUPT(13) \ + DECLARE_INTERRUPT(14) \ + DECLARE_INTERRUPT(15) \ + DECLARE_INTERRUPT(16) \ + DECLARE_INTERRUPT(17) \ + DECLARE_INTERRUPT(18) \ + DECLARE_INTERRUPT(19) \ + DECLARE_INTERRUPT(20) \ + DECLARE_INTERRUPT(21) \ + DECLARE_INTERRUPT(22) \ + DECLARE_INTERRUPT(23) \ + DECLARE_INTERRUPT(24) \ + DECLARE_INTERRUPT(25) \ + DECLARE_INTERRUPT(26) \ + DECLARE_INTERRUPT(27) \ + DECLARE_INTERRUPT(28) \ + DECLARE_INTERRUPT(29) \ + DECLARE_INTERRUPT(30) \ + DECLARE_INTERRUPT(31) \ + DECLARE_INTERRUPT(32) \ + DECLARE_INTERRUPT(33) \ + DECLARE_INTERRUPT(34) \ + DECLARE_INTERRUPT(35) \ + DECLARE_INTERRUPT(36) \ + DECLARE_INTERRUPT(37) \ + DECLARE_INTERRUPT(38) \ + DECLARE_INTERRUPT(39) \ + DECLARE_INTERRUPT(40) \ + DECLARE_INTERRUPT(41) \ + DECLARE_INTERRUPT(42) \ + DECLARE_INTERRUPT(43) \ + DECLARE_INTERRUPT(44) \ + DECLARE_INTERRUPT(45) \ + DECLARE_INTERRUPT(46) \ + DECLARE_INTERRUPT(47) \ + DECLARE_INTERRUPT(48) \ + DECLARE_INTERRUPT(49) \ + DECLARE_INTERRUPT(50) \ + DECLARE_INTERRUPT(51) \ + DECLARE_INTERRUPT(52) \ + DECLARE_INTERRUPT(53) \ + DECLARE_INTERRUPT(54) \ + DECLARE_INTERRUPT(55) \ + DECLARE_INTERRUPT(56) \ + DECLARE_INTERRUPT(57) \ + DECLARE_INTERRUPT(58) \ + DECLARE_INTERRUPT(59) \ + DECLARE_INTERRUPT(60) \ + DECLARE_INTERRUPT(61) \ + DECLARE_INTERRUPT(62) \ + DECLARE_INTERRUPT(63) \ + DECLARE_INTERRUPT(64) \ + DECLARE_INTERRUPT(65) \ + DECLARE_INTERRUPT(66) \ + DECLARE_INTERRUPT(67) \ + DECLARE_INTERRUPT(68) \ + DECLARE_INTERRUPT(69) \ + DECLARE_INTERRUPT(70) \ + DECLARE_INTERRUPT(71) \ + DECLARE_INTERRUPT(72) \ + DECLARE_INTERRUPT(73) \ + DECLARE_INTERRUPT(74) \ + DECLARE_INTERRUPT(75) \ + DECLARE_INTERRUPT(76) \ + DECLARE_INTERRUPT(77) \ + DECLARE_INTERRUPT(78) \ + DECLARE_INTERRUPT(79) \ + DECLARE_INTERRUPT(80) \ + DECLARE_INTERRUPT(81) \ + DECLARE_INTERRUPT(82) \ + DECLARE_INTERRUPT(83) \ + DECLARE_INTERRUPT(84) \ + DECLARE_INTERRUPT(85) \ + DECLARE_INTERRUPT(86) \ + DECLARE_INTERRUPT(87) \ + DECLARE_INTERRUPT(88) \ + DECLARE_INTERRUPT(89) \ + DECLARE_INTERRUPT(90) \ + DECLARE_INTERRUPT(91) \ + DECLARE_INTERRUPT(92) \ + DECLARE_INTERRUPT(93) \ + DECLARE_INTERRUPT(94) \ + DECLARE_INTERRUPT(95) \ + DECLARE_INTERRUPT(97) \ + DECLARE_INTERRUPT(96) \ + DECLARE_INTERRUPT(98) \ + DECLARE_INTERRUPT(99) \ + DECLARE_INTERRUPT(100) \ + DECLARE_INTERRUPT(101) \ + DECLARE_INTERRUPT(102) \ + DECLARE_INTERRUPT(103) \ + DECLARE_INTERRUPT(104) \ + DECLARE_INTERRUPT(105) \ + DECLARE_INTERRUPT(106) \ + DECLARE_INTERRUPT(107) \ + DECLARE_INTERRUPT(108) \ + DECLARE_INTERRUPT(109) \ + DECLARE_INTERRUPT(110) \ + DECLARE_INTERRUPT(111) \ + DECLARE_INTERRUPT(112) \ + DECLARE_INTERRUPT(113) \ + DECLARE_INTERRUPT(114) \ + DECLARE_INTERRUPT(115) \ + DECLARE_INTERRUPT(116) \ + DECLARE_INTERRUPT(117) \ + DECLARE_INTERRUPT(118) \ + DECLARE_INTERRUPT(119) \ + DECLARE_INTERRUPT(120) \ + DECLARE_INTERRUPT(121) \ + DECLARE_INTERRUPT(122) \ + DECLARE_INTERRUPT(123) \ + DECLARE_INTERRUPT(124) \ + DECLARE_INTERRUPT(125) \ + DECLARE_INTERRUPT(126) \ + DECLARE_INTERRUPT(127) \ + DECLARE_INTERRUPT(128) \ + DECLARE_INTERRUPT(129) \ + DECLARE_INTERRUPT(130) \ + DECLARE_INTERRUPT(131) \ + DECLARE_INTERRUPT(132) \ + DECLARE_INTERRUPT(133) \ + DECLARE_INTERRUPT(134) \ + DECLARE_INTERRUPT(135) \ + DECLARE_INTERRUPT(136) \ + DECLARE_INTERRUPT(137) \ + DECLARE_INTERRUPT(138) \ + DECLARE_INTERRUPT(139) \ + DECLARE_INTERRUPT(140) \ + DECLARE_INTERRUPT(141) \ + DECLARE_INTERRUPT(142) \ + DECLARE_INTERRUPT(143) \ + DECLARE_INTERRUPT(144) \ + DECLARE_INTERRUPT(145) \ + DECLARE_INTERRUPT(146) \ + DECLARE_INTERRUPT(147) \ + DECLARE_INTERRUPT(148) \ + DECLARE_INTERRUPT(149) \ + DECLARE_INTERRUPT(150) \ + DECLARE_INTERRUPT(151) \ + DECLARE_INTERRUPT(152) \ + DECLARE_INTERRUPT(153) \ + DECLARE_INTERRUPT(154) \ + DECLARE_INTERRUPT(155) \ + DECLARE_INTERRUPT(156) \ + DECLARE_INTERRUPT(157) \ + DECLARE_INTERRUPT(158) \ + DECLARE_INTERRUPT(159) \ + DECLARE_INTERRUPT(160) \ + DECLARE_INTERRUPT(161) \ + DECLARE_INTERRUPT(162) \ + DECLARE_INTERRUPT(163) \ + DECLARE_INTERRUPT(164) \ + DECLARE_INTERRUPT(165) \ + DECLARE_INTERRUPT(166) \ + DECLARE_INTERRUPT(167) \ + DECLARE_INTERRUPT(168) \ + DECLARE_INTERRUPT(169) \ + DECLARE_INTERRUPT(170) \ + DECLARE_INTERRUPT(171) \ + DECLARE_INTERRUPT(172) \ + DECLARE_INTERRUPT(173) \ + DECLARE_INTERRUPT(174) \ + DECLARE_INTERRUPT(175) \ + DECLARE_INTERRUPT(176) \ + DECLARE_INTERRUPT(177) \ + DECLARE_INTERRUPT(178) \ + DECLARE_INTERRUPT(179) \ + DECLARE_INTERRUPT(180) \ + DECLARE_INTERRUPT(181) \ + DECLARE_INTERRUPT(182) \ + DECLARE_INTERRUPT(183) \ + DECLARE_INTERRUPT(184) \ + DECLARE_INTERRUPT(185) \ + DECLARE_INTERRUPT(186) \ + DECLARE_INTERRUPT(187) \ + DECLARE_INTERRUPT(188) \ + DECLARE_INTERRUPT(189) \ + DECLARE_INTERRUPT(190) \ + DECLARE_INTERRUPT(191) \ + DECLARE_INTERRUPT(192) \ + DECLARE_INTERRUPT(193) \ + DECLARE_INTERRUPT(194) \ + DECLARE_INTERRUPT(195) \ + DECLARE_INTERRUPT(196) \ + DECLARE_INTERRUPT(197) \ + DECLARE_INTERRUPT(198) \ + DECLARE_INTERRUPT(199) \ + DECLARE_INTERRUPT(200) \ + DECLARE_INTERRUPT(201) \ + DECLARE_INTERRUPT(202) \ + DECLARE_INTERRUPT(203) \ + DECLARE_INTERRUPT(204) \ + DECLARE_INTERRUPT(205) \ + DECLARE_INTERRUPT(206) \ + DECLARE_INTERRUPT(207) \ + DECLARE_INTERRUPT(208) \ + DECLARE_INTERRUPT(209) \ + DECLARE_INTERRUPT(210) \ + DECLARE_INTERRUPT(211) \ + DECLARE_INTERRUPT(212) \ + DECLARE_INTERRUPT(213) \ + DECLARE_INTERRUPT(214) \ + DECLARE_INTERRUPT(215) \ + DECLARE_INTERRUPT(216) \ + DECLARE_INTERRUPT(217) \ + DECLARE_INTERRUPT(218) \ + DECLARE_INTERRUPT(219) \ + DECLARE_INTERRUPT(220) \ + DECLARE_INTERRUPT(221) \ + DECLARE_INTERRUPT(222) \ + DECLARE_INTERRUPT(223) \ + DECLARE_INTERRUPT(224) \ + DECLARE_INTERRUPT(225) \ + DECLARE_INTERRUPT(226) \ + DECLARE_INTERRUPT(227) \ + DECLARE_INTERRUPT(228) \ + DECLARE_INTERRUPT(229) \ + DECLARE_INTERRUPT(230) \ + DECLARE_INTERRUPT(231) \ + DECLARE_INTERRUPT(232) \ + DECLARE_INTERRUPT(233) \ + DECLARE_INTERRUPT(234) \ + DECLARE_INTERRUPT(235) \ + DECLARE_INTERRUPT(236) \ + DECLARE_INTERRUPT(237) \ + DECLARE_INTERRUPT(238) \ + DECLARE_INTERRUPT(239) \ + DECLARE_INTERRUPT(240) \ + DECLARE_INTERRUPT(241) \ + DECLARE_INTERRUPT(242) \ + DECLARE_INTERRUPT(243) \ + DECLARE_INTERRUPT(244) \ + DECLARE_INTERRUPT(245) \ + DECLARE_INTERRUPT(246) \ + DECLARE_INTERRUPT(247) \ + DECLARE_INTERRUPT(248) \ + DECLARE_INTERRUPT(249) \ + DECLARE_INTERRUPT(250) \ + DECLARE_INTERRUPT(251) \ + DECLARE_INTERRUPT(252) \ + DECLARE_INTERRUPT(253) \ + DECLARE_INTERRUPT(254) \ + DECLARE_INTERRUPT(255)); diff --git a/arch/x86/cpu/resetvec.S b/arch/x86/cpu/resetvec.S new file mode 100644 index 0000000000..c690d2516e --- /dev/null +++ b/arch/x86/cpu/resetvec.S @@ -0,0 +1,38 @@ +/* + * U-boot - x86 Startup Code + * + * (C) Copyright 2002 + * Daniel Engström, Omicron Ceti AB, <daniel@omicron.se> + * + * 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 + */ + +/* Reset vector, jumps to start16.S */ + +.extern start16 + +.section .resetvec, "ax" +.code16 +reset_vector: + cli + cld + jmp start16 + + .org 0xf + nop diff --git a/arch/x86/cpu/sc520/Makefile b/arch/x86/cpu/sc520/Makefile new file mode 100644 index 0000000000..694b61ee42 --- /dev/null +++ b/arch/x86/cpu/sc520/Makefile @@ -0,0 +1,58 @@ +# +# (C) Copyright 2008 +# Graeme Russ, graeme.russ@gmail.com. +# +# (C) Copyright 2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# (C) Copyright 2002 +# Daniel Engström, Omicron Ceti AB, daniel@omicron.se. +# +# 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$(SOC).o + +COBJS-$(CONFIG_SYS_SC520) += sc520.o +COBJS-$(CONFIG_PCI) += sc520_pci.o +COBJS-$(CONFIG_SYS_SC520_RESET) += sc520_reset.o +COBJS-$(CONFIG_SYS_SC520) += sc520_sdram.o +COBJS-$(CONFIG_SYS_SC520_SSI) += sc520_ssi.o +COBJS-$(CONFIG_SYS_SC520_TIMER) += sc520_timer.o + +SOBJS-$(CONFIG_SYS_SC520) += sc520_car.o + +SRCS := $(SOBJS-y:.o=.S) $(COBJS-y:.o=.c) +OBJS := $(addprefix $(obj),$(SOBJS-y) $(COBJS-y)) + +all: $(obj).depend $(LIB) + +$(LIB): $(OBJS) + $(call cmd_link_o_target, $(OBJS)) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +#########################################################################
\ No newline at end of file diff --git a/arch/x86/cpu/sc520/sc520.c b/arch/x86/cpu/sc520/sc520.c new file mode 100644 index 0000000000..8c410a2337 --- /dev/null +++ b/arch/x86/cpu/sc520/sc520.c @@ -0,0 +1,67 @@ +/* + * (C) Copyright 2008-2011 + * Graeme Russ, <graeme.russ@gmail.com> + * + * (C) Copyright 2002 + * Daniel Engström, Omicron Ceti AB, <daniel@omicron.se> + * + * 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/io.h> +#include <asm/processor-flags.h> +#include <asm/ic/sc520.h> + +DECLARE_GLOBAL_DATA_PTR; + +sc520_mmcr_t *sc520_mmcr = (sc520_mmcr_t *)SC520_MMCR_BASE; + +int cpu_init_f(void) +{ + if (CONFIG_SYS_SC520_HIGH_SPEED) { + /* set it to 133 MHz and write back */ + writeb(0x02, &sc520_mmcr->cpuctl); + gd->cpu_clk = 133000000; + } else { + /* set it to 100 MHz and write back */ + writeb(0x01, &sc520_mmcr->cpuctl); + gd->cpu_clk = 100000000; + } + + /* wait at least one millisecond */ + asm("movl $0x2000, %%ecx\n" + "0: pushl %%ecx\n" + "popl %%ecx\n" + "loop 0b\n": : : "ecx"); + + return x86_cpu_init_f(); +} + +int cpu_init_r(void) +{ + /* Disable the PAR used for CAR */ + writel(0x0000000, &sc520_mmcr->par[2]); + + /* turn on the SDRAM write buffer */ + writeb(0x11, &sc520_mmcr->dbctl); + + return x86_cpu_init_r(); +} + diff --git a/arch/x86/cpu/sc520/sc520_car.S b/arch/x86/cpu/sc520/sc520_car.S new file mode 100644 index 0000000000..a33f94f491 --- /dev/null +++ b/arch/x86/cpu/sc520/sc520_car.S @@ -0,0 +1,93 @@ +/* + * (C) Copyright 2010-2011 + * Graeme Russ, <graeme.russ@gmail.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/processor-flags.h> +#include <asm/ic/sc520.h> + +.section .text + +.globl car_init +car_init: + /* + * How to enable Cache-As-RAM for the AMD Elan SC520: + * 1. Turn off the CPU Cache (may not be strictly required) + * 2. Set code execution PAR (usually the BOOTCS region) to be + * non-cachable + * 3. Create a Cachable PAR Region for an area of memory which is + * a) NOT where the code is being executed + * b) NOT SDRAM (Controller not initialised yet) + * c) WILL response to read requests + * The easiest way to do this is to create a second BOOTCS + * PAR mappnig with an address != the PAR in step 2 + * 4. Issue a wbinvd to invalidate the CPU cache + * 5. Turn on the CPU Cache + * 6. Read 16kB from the cached PAR region setup in step 3 + * 7. Turn off the CPU Cache (but DO NOT issue a wbinvd) + * + * The following code uses PAR2 as the cached PAR (PAR0 and PAR1 + * are avoided as these are the only two PARs which can be used + * as PCI BUS Memory regions which the board might require) + * + * The configuration of PAR2 must be set in the board configuration + * file as CONFIG_SYS_SC520_CAR_PAR + */ + + /* Configure Cache-As-RAM PAR */ + movl $CONFIG_SYS_SC520_CAR_PAR, %eax + movl $SC520_PAR2, %edi + movl %eax, (%edi) + + /* Trash the cache then turn it on */ + wbinvd + movl %cr0, %eax + andl $~(X86_CR0_NW | X86_CR0_CD), %eax + movl %eax, %cr0 + + /* + * The cache is now enabled and empty. Map a region of memory to + * it by reading that region. + */ + movl $CONFIG_SYS_CAR_ADDR, %esi + movl $CONFIG_SYS_CAR_SIZE, %ecx + shrl $2, %ecx /* we are reading longs */ + cld + rep lodsl + + /* Turn off the cache, but don't trash it */ + movl %cr0, %eax + orl $(X86_CR0_NW | X86_CR0_CD), %eax + movl %eax, %cr0 + + /* Clear the CAR region */ + xorl %eax, %eax + movl $CONFIG_SYS_CAR_ADDR, %edi + movl $CONFIG_SYS_CAR_SIZE, %ecx + shrl $2, %ecx /* we are writing longs */ + rep stosl + + /* + * Done - We should now have CONFIG_SYS_CAR_SIZE bytes of + * Cache-As-RAM + */ + jmp car_init_ret diff --git a/arch/x86/cpu/sc520/sc520_pci.c b/arch/x86/cpu/sc520/sc520_pci.c new file mode 100644 index 0000000000..8cd7ffecdb --- /dev/null +++ b/arch/x86/cpu/sc520/sc520_pci.c @@ -0,0 +1,140 @@ +/* + * (C) Copyright 2008-2011 + * Graeme Russ, <graeme.russ@gmail.com> + * + * (C) Copyright 2002 + * Daniel Engström, Omicron Ceti AB, <daniel@omicron.se> + * + * 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 <pci.h> +#include <asm/io.h> +#include <asm/pci.h> +#include <asm/ic/pci.h> +#include <asm/ic/sc520.h> + +static struct { + u8 priority; + u16 level_reg; + u8 level_bit; +} sc520_irq[] = { + { SC520_IRQ0, 0, 0x01 }, + { SC520_IRQ1, 0, 0x02 }, + { SC520_IRQ2, 1, 0x02 }, + { SC520_IRQ3, 0, 0x08 }, + { SC520_IRQ4, 0, 0x10 }, + { SC520_IRQ5, 0, 0x20 }, + { SC520_IRQ6, 0, 0x40 }, + { SC520_IRQ7, 0, 0x80 }, + + { SC520_IRQ8, 1, 0x01 }, + { SC520_IRQ9, 1, 0x02 }, + { SC520_IRQ10, 1, 0x04 }, + { SC520_IRQ11, 1, 0x08 }, + { SC520_IRQ12, 1, 0x10 }, + { SC520_IRQ13, 1, 0x20 }, + { SC520_IRQ14, 1, 0x40 }, + { SC520_IRQ15, 1, 0x80 } +}; + +/* The interrupt used for PCI INTA-INTD */ +int sc520_pci_ints[15] = { + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1 +}; + +/* utility function to configure a pci interrupt */ +int pci_sc520_set_irq(int pci_pin, int irq) +{ + int i; + u8 tmpb; + u16 tmpw; + + debug("set_irq(): map INT%c to IRQ%d\n", pci_pin + 'A', irq); + + if (irq < 0 || irq > 15) { + return -1; /* illegal irq */ + } + + if (pci_pin < 0 || pci_pin > 15) { + return -1; /* illegal pci int pin */ + } + + /* first disable any non-pci interrupt source that use + * this level */ + + /* PCI interrupt mapping (A through D)*/ + for (i=0; i<=3 ;i++) { + if (readb(&sc520_mmcr->pci_int_map[i]) == sc520_irq[irq].priority) + writeb(SC520_IRQ_DISABLED, &sc520_mmcr->pci_int_map[i]); + } + + /* GP IRQ interrupt mapping */ + for (i=0; i<=10 ;i++) { + if (readb(&sc520_mmcr->gp_int_map[i]) == sc520_irq[irq].priority) + writeb(SC520_IRQ_DISABLED, &sc520_mmcr->gp_int_map[i]); + } + + /* Set the trigger to level */ + tmpb = readb(&sc520_mmcr->pic_mode[sc520_irq[irq].level_reg]); + tmpb |= sc520_irq[irq].level_bit; + writeb(tmpb, &sc520_mmcr->pic_mode[sc520_irq[irq].level_reg]); + + + if (pci_pin < 4) { + /* PCI INTA-INTD */ + /* route the interrupt */ + writeb(sc520_irq[irq].priority, &sc520_mmcr->pci_int_map[pci_pin]); + } else { + /* GPIRQ0-GPIRQ10 used for additional PCI INTS */ + writeb(sc520_irq[irq].priority, &sc520_mmcr->gp_int_map[pci_pin - 4]); + + /* also set the polarity in this case */ + tmpw = readw(&sc520_mmcr->intpinpol); + tmpw |= (1 << (pci_pin-4)); + writew(tmpw, &sc520_mmcr->intpinpol); + } + + /* register the pin */ + sc520_pci_ints[pci_pin] = irq; + + + return 0; /* OK */ +} + +void pci_sc520_init(struct pci_controller *hose) +{ + hose->first_busno = 0; + hose->last_busno = 0xff; + hose->region_count = pci_set_regions(hose); + + pci_setup_type1(hose, + SC520_REG_ADDR, + SC520_REG_DATA); + + pci_register_hose(hose); + + hose->last_busno = pci_hose_scan(hose); + + /* enable target memory acceses on host brige */ + pci_write_config_word(0, PCI_COMMAND, + PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); +} diff --git a/arch/x86/cpu/sc520/sc520_reset.c b/arch/x86/cpu/sc520/sc520_reset.c new file mode 100644 index 0000000000..79ef976838 --- /dev/null +++ b/arch/x86/cpu/sc520/sc520_reset.c @@ -0,0 +1,40 @@ +/* + * (C) Copyright 2011 + * Graeme Russ, <graeme.russ@gmail.com> + * + * (C) Copyright 2002 + * Daniel Engström, Omicron Ceti AB, <daniel@omicron.se> + * + * 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/io.h> +#include <asm/ic/sc520.h> + +DECLARE_GLOBAL_DATA_PTR; + +void reset_cpu(ulong addr) +{ + printf("Resetting using SC520 MMCR\n"); + /* Write a '1' to the SYS_RST of the RESCFG MMCR */ + writeb(0x01, &sc520_mmcr->rescfg); + + /* NOTREACHED */ +} diff --git a/arch/x86/cpu/sc520/sc520_sdram.c b/arch/x86/cpu/sc520/sc520_sdram.c new file mode 100644 index 0000000000..f3623f53f2 --- /dev/null +++ b/arch/x86/cpu/sc520/sc520_sdram.c @@ -0,0 +1,532 @@ +/* + * (C) Copyright 2010,2011 + * Graeme Russ, <graeme.russ@gmail.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/io.h> +#include <asm/processor-flags.h> +#include <asm/ic/sc520.h> + +DECLARE_GLOBAL_DATA_PTR; + +struct sc520_sdram_info { + u8 banks; + u8 columns; + u8 rows; + u8 size; +}; + +static void sc520_sizemem(void); +static void sc520_set_dram_timing(void); +static void sc520_set_dram_refresh_rate(void); +static void sc520_enable_dram_refresh(void); +static void sc520_enable_sdram(void); +#if CONFIG_SYS_SDRAM_ECC_ENABLE +static void sc520_enable_ecc(void) +#endif + +int dram_init_f(void) +{ + sc520_sizemem(); + sc520_set_dram_timing(); + sc520_set_dram_refresh_rate(); + sc520_enable_dram_refresh(); + sc520_enable_sdram(); +#if CONFIG_SYS_SDRAM_ECC_ENABLE + sc520_enable_ecc(); +#endif + + return 0; +} + +static inline void sc520_dummy_write(void) +{ + writew(0x0000, CACHELINESZ); +} +static inline void sc520_issue_sdram_op_mode_select(u8 command) +{ + writeb(command, &sc520_mmcr->drcctl); + sc520_dummy_write(); +} + +static inline int check_long(u32 test_long) +{ + u8 i; + u8 tmp_byte = (u8)(test_long & 0x000000ff); + + for (i = 1; i < 4; i++) { + if ((u8)((test_long >> (i * 8)) & 0x000000ff) != tmp_byte) + return -1; + } + + return 0; +} + +static inline int write_and_test(u32 data, u32 address) +{ + writel(data, address); + if (readl(address) == data) + return 0; /* Good */ + else + return -1; /* Bad */ +} + +static void sc520_enable_sdram(void) +{ + u32 par_config; + + /* Enable Writes, Caching and Code Execution to SDRAM */ + par_config = readl(&sc520_mmcr->par[3]); + par_config &= ~(SC520_PAR_EXEC_DIS | + SC520_PAR_CACHE_DIS | + SC520_PAR_WRITE_DIS); + writel(par_config, &sc520_mmcr->par[3]); + + par_config = readl(&sc520_mmcr->par[4]); + par_config &= ~(SC520_PAR_EXEC_DIS | + SC520_PAR_CACHE_DIS | + SC520_PAR_WRITE_DIS); + writel(par_config, &sc520_mmcr->par[4]); +} + +static void sc520_set_dram_timing(void) +{ + u8 drctmctl = 0x00; + +#if defined CONFIG_SYS_SDRAM_DRCTMCTL + /* just have your hardware designer _GIVE_ you what you need here! */ + drctmctl = CONFIG_SYS_SDRAM_DRCTMCTL; +#else + switch (CONFIG_SYS_SDRAM_RAS_CAS_DELAY) { + case 2: + break; + case 3: + drctmctl |= 0x01; + break; + case 4: + default: + drctmctl |= 0x02; + break; + } + + switch (CONFIG_SYS_SDRAM_PRECHARGE_DELAY) { + case 2: + break; + case 3: + drctmctl |= 0x04; + break; + case 4: + default: + drctmctl |= 0x08; + break; + + case 6: + drctmctl |= 0x0c; + break; + } + + switch (CONFIG_SYS_SDRAM_CAS_LATENCY) { + case 2: + break; + case 3: + default: + drctmctl |= 0x10; + break; + } +#endif + writeb(drctmctl, &sc520_mmcr->drctmctl); + + /* Issue load mode register command */ + sc520_issue_sdram_op_mode_select(0x03); +} + +static void sc520_set_dram_refresh_rate(void) +{ + u8 drctl; + + drctl = readb(&sc520_mmcr->drcctl); + drctl &= 0xcf; + + switch (CONFIG_SYS_SDRAM_REFRESH_RATE) { + case 78: + break; + case 156: + default: + drctl |= 0x10; + break; + case 312: + drctl |= 0x20; + break; + case 624: + drctl |= 0x30; + break; + } + + writeb(drctl, &sc520_mmcr->drcctl); +} + +static void sc520_enable_dram_refresh(void) +{ + u8 drctl; + + drctl = readb(&sc520_mmcr->drcctl); + drctl &= 0x30; /* keep refresh rate */ + drctl |= 0x08; /* enable refresh, normal mode */ + + writeb(drctl, &sc520_mmcr->drcctl); +} + +static void sc520_get_bank_info(int bank, struct sc520_sdram_info *bank_info) +{ + u32 col_data; + u32 row_data; + + u32 drcbendadr; + u16 drccfg; + + u8 banks = 0x00; + u8 columns = 0x00; + u8 rows = 0x00; + + bank_info->banks = 0x00; + bank_info->columns = 0x00; + bank_info->rows = 0x00; + bank_info->size = 0x00; + + if ((bank < 0) || (bank > 3)) { + printf("Bad Bank ID\n"); + return; + } + + /* Save configuration */ + drcbendadr = readl(&sc520_mmcr->drcbendadr); + drccfg = readw(&sc520_mmcr->drccfg); + + /* Setup SDRAM Bank to largest possible size */ + writew(0x000b << (bank * 4), &sc520_mmcr->drccfg); + + /* Set ending address for this bank */ + writel(0x000000ff << (bank * 8), &sc520_mmcr->drcbendadr); + + /* write col 11 wrap adr */ + if (write_and_test(COL11_DATA, COL11_ADR) != 0) + goto restore_and_exit; + + /* write col 10 wrap adr */ + if (write_and_test(COL10_DATA, COL10_ADR) != 0) + goto restore_and_exit; + + /* write col 9 wrap adr */ + if (write_and_test(COL09_DATA, COL09_ADR) != 0) + goto restore_and_exit; + + /* write col 8 wrap adr */ + if (write_and_test(COL08_DATA, COL08_ADR) != 0) + goto restore_and_exit; + + col_data = readl(COL11_ADR); + + /* All four bytes in the read long must be the same */ + if (check_long(col_data) < 0) + goto restore_and_exit; + + if ((col_data >= COL08_DATA) && (col_data <= COL11_DATA)) + columns = (u8)(col_data & 0x000000ff); + else + goto restore_and_exit; + + /* write row 14 wrap adr */ + if (write_and_test(ROW14_DATA, ROW14_ADR) != 0) + goto restore_and_exit; + + /* write row 13 wrap adr */ + if (write_and_test(ROW13_DATA, ROW13_ADR) != 0) + goto restore_and_exit; + + /* write row 12 wrap adr */ + if (write_and_test(ROW12_DATA, ROW12_ADR) != 0) + goto restore_and_exit; + + /* write row 11 wrap adr */ + if (write_and_test(ROW11_DATA, ROW11_ADR) != 0) + goto restore_and_exit; + + if (write_and_test(ROW10_DATA, ROW10_ADR) != 0) + goto restore_and_exit; + + /* + * read data @ row 12 wrap adr to determine number of banks, + * and read data @ row 14 wrap adr to determine number of rows. + * if data @ row 12 wrap adr is not AA, 11 or 12 we have bad RAM. + * if data @ row 12 wrap == AA, we only have 2 banks, NOT 4 + * if data @ row 12 wrap == 11 or 12, we have 4 banks, + */ + row_data = readl(ROW12_ADR); + + /* All four bytes in the read long must be the same */ + if (check_long(row_data) != 0) + goto restore_and_exit; + + switch (row_data) { + case ROW10_DATA: + banks = 2; + break; + + case ROW11_DATA: + case ROW12_DATA: + banks = 4; + break; + + default: + goto restore_and_exit; + } + + row_data = readl(ROW14_ADR); + + /* All four bytes in the read long must be the same */ + if (check_long(row_data) != 0) + goto restore_and_exit; + + switch (row_data) { + case ROW11_DATA: + case ROW12_DATA: + case ROW13_DATA: + case ROW14_DATA: + rows = (u8)(row_data & 0x000000ff); + break; + + default: + goto restore_and_exit; + } + + bank_info->banks = banks; + bank_info->columns = columns; + bank_info->rows = rows; + + if ((bank_info->banks != 0) && + (bank_info->columns != 0) && + (bank_info->rows != 0)) { + bank_info->size = bank_info->rows; + bank_info->size >>= (11 - bank_info->columns); + bank_info->size++; + } + +restore_and_exit: + /* Restore configuration */ + writel(drcbendadr, &sc520_mmcr->drcbendadr); + writew(drccfg, &sc520_mmcr->drccfg); +} + +static void sc520_setup_sizemem(void) +{ + u8 i; + + /* Disable write buffer */ + writeb(0x00, &sc520_mmcr->dbctl); + + /* Disable ECC */ + writeb(0x00, &sc520_mmcr->eccctl); + + /* Set slowest SDRAM timing */ + writeb(0x1e, &sc520_mmcr->drctmctl); + + /* Issue a NOP to all SDRAM banks */ + sc520_issue_sdram_op_mode_select(0x01); + + /* Delay for 100 microseconds */ + udelay(100); + + /* Issue 'All Banks Precharge' command */ + sc520_issue_sdram_op_mode_select(0x02); + + /* Issue 2 'Auto Refresh Enable' command */ + sc520_issue_sdram_op_mode_select(0x04); + sc520_dummy_write(); + + /* Issue 'Load Mode Register' command */ + sc520_issue_sdram_op_mode_select(0x03); + + /* Issue 8 more 'Auto Refresh Enable' commands */ + sc520_issue_sdram_op_mode_select(0x04); + for (i = 0; i < 7; i++) + sc520_dummy_write(); + + /* Set control register to 'Normal Mode' */ + writeb(0x00, &sc520_mmcr->drcctl); +} + +static void sc520_sizemem(void) +{ + struct sc520_sdram_info sdram_info[4]; + u8 bank_config = 0x00; + u8 end_addr = 0x00; + u16 drccfg = 0x0000; + u32 drcbendadr = 0x00000000; + u8 i; + + /* Use PARs to disable caching of maximum allowable 256MB SDRAM */ + writel(SC520_SDRAM1_PAR | SC520_PAR_CACHE_DIS, &sc520_mmcr->par[3]); + writel(SC520_SDRAM2_PAR | SC520_PAR_CACHE_DIS, &sc520_mmcr->par[4]); + + sc520_setup_sizemem(); + + gd->ram_size = 0; + + /* Size each SDRAM bank */ + for (i = 0; i <= 3; i++) { + sc520_get_bank_info(i, &sdram_info[i]); + + if (sdram_info[i].banks != 0) { + /* Update Configuration register */ + bank_config = sdram_info[i].columns - 8; + + if (sdram_info[i].banks == 4) + bank_config |= 0x08; + + drccfg |= bank_config << (i * 4); + + /* Update End Address register */ + end_addr += sdram_info[i].size; + drcbendadr |= (end_addr | 0x80) << (i * 8); + + gd->ram_size += sdram_info[i].size << 22; + } + + /* Issue 'All Banks Precharge' command */ + sc520_issue_sdram_op_mode_select(0x02); + + /* Set control register to 'Normal Mode' */ + writeb(0x00, &sc520_mmcr->drcctl); + } + + writel(drcbendadr, &sc520_mmcr->drcbendadr); + writew(drccfg, &sc520_mmcr->drccfg); + + /* Clear PARs preventing caching of SDRAM */ + writel(0x00000000, &sc520_mmcr->par[3]); + writel(0x00000000, &sc520_mmcr->par[4]); +} + +#if CONFIG_SYS_SDRAM_ECC_ENABLE +static void sc520_enable_ecc(void) + + /* A nominal memory test: just a byte at each address line */ + movl %eax, %ecx + shrl $0x1, %ecx + movl $0x1, %edi +memtest0: + movb $0xa5, (%edi) + cmpb $0xa5, (%edi) + jne out + shrl $0x1, %ecx + andl %ecx, %ecx + jz set_ecc + shll $0x1, %edi + jmp memtest0 + +set_ecc: + /* clear all ram with a memset */ + movl %eax, %ecx + xorl %esi, %esi + xorl %edi, %edi + xorl %eax, %eax + shrl $0x2, %ecx + cld + rep stosl + + /* enable read, write buffers */ + movb $0x11, %al + movl $DBCTL, %edi + movb %al, (%edi) + + /* enable NMI mapping for ECC */ + movl $ECCINT, %edi + movb $0x10, %al + movb %al, (%edi) + + /* Turn on ECC */ + movl $ECCCTL, %edi + movb $0x05, %al + movb %al,(%edi) + +out: + jmp init_ecc_ret +} +#endif + +int dram_init(void) +{ + ulong dram_ctrl; + ulong dram_present = 0x00000000; + + /* + * We read-back the configuration of the dram + * controller that the assembly code wrote + */ + dram_ctrl = readl(&sc520_mmcr->drcbendadr); + + gd->bd->bi_dram[0].start = 0; + if (dram_ctrl & 0x80) { + /* bank 0 enabled */ + gd->bd->bi_dram[1].start = (dram_ctrl & 0x7f) << 22; + dram_present = gd->bd->bi_dram[1].start; + gd->bd->bi_dram[0].size = gd->bd->bi_dram[1].start; + } else { + gd->bd->bi_dram[0].size = 0; + gd->bd->bi_dram[1].start = gd->bd->bi_dram[0].start; + } + + if (dram_ctrl & 0x8000) { + /* bank 1 enabled */ + gd->bd->bi_dram[2].start = (dram_ctrl & 0x7f00) << 14; + dram_present = gd->bd->bi_dram[2].start; + gd->bd->bi_dram[1].size = gd->bd->bi_dram[2].start - + gd->bd->bi_dram[1].start; + } else { + gd->bd->bi_dram[1].size = 0; + gd->bd->bi_dram[2].start = gd->bd->bi_dram[1].start; + } + + if (dram_ctrl & 0x800000) { + /* bank 2 enabled */ + gd->bd->bi_dram[3].start = (dram_ctrl & 0x7f0000) << 6; + dram_present = gd->bd->bi_dram[3].start; + gd->bd->bi_dram[2].size = gd->bd->bi_dram[3].start - + gd->bd->bi_dram[2].start; + } else { + gd->bd->bi_dram[2].size = 0; + gd->bd->bi_dram[3].start = gd->bd->bi_dram[2].start; + } + + if (dram_ctrl & 0x80000000) { + /* bank 3 enabled */ + dram_present = (dram_ctrl & 0x7f000000) >> 2; + gd->bd->bi_dram[3].size = dram_present - + gd->bd->bi_dram[3].start; + } else { + gd->bd->bi_dram[3].size = 0; + } + + gd->ram_size = dram_present; + + return 0; +} diff --git a/arch/x86/cpu/sc520/sc520_ssi.c b/arch/x86/cpu/sc520/sc520_ssi.c new file mode 100644 index 0000000000..ac58d25970 --- /dev/null +++ b/arch/x86/cpu/sc520/sc520_ssi.c @@ -0,0 +1,92 @@ +/* + * (C) Copyright 2002 + * Daniel Engström, Omicron Ceti AB, <daniel@omicron.se> + * + * 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/io.h> +#include <asm/ic/ssi.h> +#include <asm/ic/sc520.h> + +int ssi_set_interface(int freq, int lsb_first, int inv_clock, int inv_phase) +{ + u8 temp=0; + + if (freq >= 8192) { + temp |= CTL_CLK_SEL_4; + } else if (freq >= 4096) { + temp |= CTL_CLK_SEL_8; + } else if (freq >= 2048) { + temp |= CTL_CLK_SEL_16; + } else if (freq >= 1024) { + temp |= CTL_CLK_SEL_32; + } else if (freq >= 512) { + temp |= CTL_CLK_SEL_64; + } else if (freq >= 256) { + temp |= CTL_CLK_SEL_128; + } else if (freq >= 128) { + temp |= CTL_CLK_SEL_256; + } else { + temp |= CTL_CLK_SEL_512; + } + + if (!lsb_first) { + temp |= MSBF_ENB; + } + + if (inv_clock) { + temp |= CLK_INV_ENB; + } + + if (inv_phase) { + temp |= PHS_INV_ENB; + } + + writeb(temp, &sc520_mmcr->ssictl); + + return 0; +} + +u8 ssi_txrx_byte(u8 data) +{ + writeb(data, &sc520_mmcr->ssixmit); + while (readb(&sc520_mmcr->ssista) & SSISTA_BSY); + writeb(SSICMD_CMD_SEL_XMITRCV, &sc520_mmcr->ssicmd); + while (readb(&sc520_mmcr->ssista) & SSISTA_BSY); + + return readb(&sc520_mmcr->ssircv); +} + +void ssi_tx_byte(u8 data) +{ + writeb(data, &sc520_mmcr->ssixmit); + while (readb(&sc520_mmcr->ssista) & SSISTA_BSY); + writeb(SSICMD_CMD_SEL_XMIT, &sc520_mmcr->ssicmd); +} + +u8 ssi_rx_byte(void) +{ + while (readb(&sc520_mmcr->ssista) & SSISTA_BSY); + writeb(SSICMD_CMD_SEL_RCV, &sc520_mmcr->ssicmd); + while (readb(&sc520_mmcr->ssista) & SSISTA_BSY); + + return readb(&sc520_mmcr->ssircv); +} diff --git a/arch/x86/cpu/sc520/sc520_timer.c b/arch/x86/cpu/sc520/sc520_timer.c new file mode 100644 index 0000000000..1bcfe67c94 --- /dev/null +++ b/arch/x86/cpu/sc520/sc520_timer.c @@ -0,0 +1,90 @@ +/* + * (C) Copyright 2008-2011 + * Graeme Russ, <graeme.russ@gmail.com> + * + * (C) Copyright 2002 + * Daniel Engström, Omicron Ceti AB, <daniel@omicron.se> + * + * 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/io.h> +#include <asm/interrupt.h> +#include <asm/ic/sc520.h> + +void sc520_timer_isr(void) +{ + /* Ack the GP Timer Interrupt */ + writeb(0x02, &sc520_mmcr->gptmrsta); +} + +int timer_init(void) +{ + /* Register the SC520 specific timer interrupt handler */ + register_timer_isr (sc520_timer_isr); + + /* Install interrupt handler for GP Timer 1 */ + irq_install_handler (0, timer_isr, NULL); + + /* Map GP Timer 1 to Master PIC IR0 */ + writeb(0x01, &sc520_mmcr->gp_tmr_int_map[1]); + + /* Disable GP Timers 1 & 2 - Allow configuration writes */ + writew(0x4000, &sc520_mmcr->gptmr1ctl); + writew(0x4000, &sc520_mmcr->gptmr2ctl); + + /* Reset GP Timers 1 & 2 */ + writew(0x0000, &sc520_mmcr->gptmr1cnt); + writew(0x0000, &sc520_mmcr->gptmr2cnt); + + /* Setup GP Timer 2 as a 100kHz (10us) prescaler */ + writew(83, &sc520_mmcr->gptmr2maxcmpa); + writew(0xc001, &sc520_mmcr->gptmr2ctl); + + /* Setup GP Timer 1 as a 1000 Hz (1ms) interrupt generator */ + writew(100, &sc520_mmcr->gptmr1maxcmpa); + writew(0xe009, &sc520_mmcr->gptmr1ctl); + + unmask_irq (0); + + /* Clear the GP Timer 1 status register to get the show rolling*/ + writeb(0x02, &sc520_mmcr->gptmrsta); + + return 0; +} + +/* Allow boards to override udelay implementation */ +void __udelay(unsigned long usec) + __attribute__((weak, alias("sc520_udelay"))); + +void sc520_udelay(unsigned long usec) +{ + int m = 0; + long u; + long temp; + + temp = readw(&sc520_mmcr->swtmrmilli); + temp = readw(&sc520_mmcr->swtmrmicro); + + do { + m += readw(&sc520_mmcr->swtmrmilli); + u = readw(&sc520_mmcr->swtmrmicro) + (m * 1000); + } while (u < usec); +} diff --git a/arch/x86/cpu/start.S b/arch/x86/cpu/start.S new file mode 100644 index 0000000000..7ccc076fec --- /dev/null +++ b/arch/x86/cpu/start.S @@ -0,0 +1,132 @@ +/* + * U-boot - x86 Startup Code + * + * (C) Copyright 2008-2011 + * Graeme Russ, <graeme.russ@gmail.com> + * + * (C) Copyright 2002 + * Daniel Engström, Omicron Ceti AB, <daniel@omicron.se> + * + * 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 <version.h> +#include <asm/global_data.h> +#include <asm/processor-flags.h> + +.section .text +.code32 +.globl _start +.type _start, @function +.globl _x86boot_start +_x86boot_start: + /* + * This is the fail safe 32-bit bootstrap entry point. The + * following code is not executed from a cold-reset (actually, a + * lot of it is, but from real-mode after cold reset. It is + * repeated here to put the board into a state as close to cold + * reset as necessary) + */ + cli + cld + + /* Turn of cache (this might require a 486-class CPU) */ + movl %cr0, %eax + orl $(X86_CR0_NW | X86_CR0_CD), %eax + movl %eax, %cr0 + wbinvd + + /* Tell 32-bit code it is being entered from an in-RAM copy */ + movw $GD_FLG_WARM_BOOT, %bx +_start: + /* This is the 32-bit cold-reset entry point */ + + /* Load the segement registes to match the gdt loaded in start16.S */ + movl $0x18, %eax + movw %ax, %fs + movw %ax, %ds + movw %ax, %gs + movw %ax, %es + movw %ax, %ss + + /* Clear the interupt vectors */ + lidt blank_idt_ptr + + /* Early platform init (setup gpio, etc ) */ + jmp early_board_init +.globl early_board_init_ret +early_board_init_ret: + + /* Initialise Cache-As-RAM */ + jmp car_init +.globl car_init_ret +car_init_ret: + /* + * We now have CONFIG_SYS_CAR_SIZE bytes of Cache-As-RAM (or SRAM, + * or fully initialised SDRAM - we really don't care which) + * starting at CONFIG_SYS_CAR_ADDR to be used as a temporary stack + */ + movl $CONFIG_SYS_INIT_SP_ADDR, %esp + + /* Set parameter to board_init_f() to boot flags */ + xorl %eax, %eax + movw %bx, %ax + + /* Enter, U-boot! */ + call board_init_f + + /* indicate (lack of) progress */ + movw $0x85, %ax + jmp die + +.globl relocate_code +.type relocate_code, @function +relocate_code: + /* + * SDRAM has been initialised, U-Boot code has been copied into + * RAM, BSS has been cleared and relocation adjustments have been + * made. It is now time to jump into the in-RAM copy of U-Boot + * + * %eax = Address of top of stack + * %edx = Address of Global Data + * %ecx = Base address of in-RAM copy of U-Boot + */ + + /* Setup stack in RAM */ + movl %eax, %esp + + /* Setup call address of in-RAM copy of board_init_r() */ + movl $board_init_r, %ebp + addl (GD_RELOC_OFF * 4)(%edx), %ebp + + /* Setup parameters to board_init_r() */ + movl %edx, %eax + movl %ecx, %edx + + /* Jump to in-RAM copy of board_init_r() */ + call *%ebp + +die: hlt + jmp die + hlt + +blank_idt_ptr: + .word 0 /* limit */ + .long 0 /* base */ diff --git a/arch/x86/cpu/start16.S b/arch/x86/cpu/start16.S new file mode 100644 index 0000000000..f1b9d0a0c9 --- /dev/null +++ b/arch/x86/cpu/start16.S @@ -0,0 +1,113 @@ +/* + * U-boot - x86 Startup Code + * + * (C) Copyright 2008-2011 + * Graeme Russ, <graeme.russ@gmail.com> + * + * (C) Copyright 2002,2003 + * Daniel Engström, Omicron Ceti AB, <daniel@omicron.se> + * + * 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/global_data.h> +#include <asm/processor-flags.h> + +#define BOOT_SEG 0xffff0000 /* linear segment of boot code */ +#define a32 .byte 0x67; +#define o32 .byte 0x66; + +.section .start16, "ax" +.code16 +.globl start16 +start16: + /* Set the Cold Boot / Hard Reset flag */ + movl $GD_FLG_COLD_BOOT, %ebx + + /* + * First we let the BSP do some early initialization + * this code have to map the flash to its final position + */ + jmp board_init16 +.globl board_init16_ret +board_init16_ret: + + /* Turn of cache (this might require a 486-class CPU) */ + movl %cr0, %eax + orl $(X86_CR0_NW & X86_CR0_CD), %eax + movl %eax, %cr0 + wbinvd + + /* load the temporary Global Descriptor Table */ +o32 cs lidt idt_ptr +o32 cs lgdt gdt_ptr + + /* Now, we enter protected mode */ + movl %cr0, %eax + orl $X86_CR0_PE, %eax + movl %eax, %cr0 + + /* Flush the prefetch queue */ + jmp ff +ff: + /* Finally jump to the 32bit initialization code */ + movw $code32start, %ax + movw %ax, %bp +o32 cs ljmp *(%bp) + + /* 48-bit far pointer */ +code32start: + .long _start /* offset */ + .word 0x10 /* segment */ + +idt_ptr: + .word 0 /* limit */ + .long 0 /* base */ + +/* + * The following Global Descriptor Table is just enough to get us into + * 'Flat Protected Mode' - It will be discarded as soon as the final + * GDT is setup in a safe location in RAM + */ +gdt_ptr: + .word 0x20 /* limit (32 bytes = 4 GDT entries) */ + .long BOOT_SEG + gdt /* base */ + + /* The GDT table ... + * + * Selector Type + * 0x00 NULL + * 0x08 Unused + * 0x10 32bit code + * 0x18 32bit data/stack + */ + +gdt: + .word 0, 0, 0, 0 /* NULL */ + .word 0, 0, 0, 0 /* unused */ + + .word 0xFFFF /* 4Gb - (0x100000*0x1000 = 4Gb) */ + .word 0 /* base address = 0 */ + .word 0x9B00 /* code read/exec */ + .word 0x00CF /* granularity = 4096, 386 (+5th nibble of limit) */ + + .word 0xFFFF /* 4Gb - (0x100000*0x1000 = 4Gb) */ + .word 0x0 /* base address = 0 */ + .word 0x9300 /* data read/write */ + .word 0x00CF /* granularity = 4096, 386 (+5th nibble of limit) */ diff --git a/arch/x86/cpu/u-boot.lds b/arch/x86/cpu/u-boot.lds new file mode 100644 index 0000000000..55974228b5 --- /dev/null +++ b/arch/x86/cpu/u-boot.lds @@ -0,0 +1,97 @@ +/* + * (C) Copyright 2002 + * Daniel Engström, Omicron Ceti AB, daniel@omicron.se. + * + * 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> +OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") +OUTPUT_ARCH(i386) +ENTRY(_start) + +SECTIONS +{ + . = CONFIG_SYS_TEXT_BASE; /* Location of bootcode in flash */ + __text_start = .; + .text : { *(.text*); } + + . = ALIGN(4); + __u_boot_cmd_start = .; + .u_boot_cmd : { *(.u_boot_cmd) } + . = ALIGN(4); + __u_boot_cmd_end = .; + + . = ALIGN(4); + .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) } + + . = ALIGN(4); + .data : { *(.data*) } + + . = ALIGN(4); + .dynsym : { *(.dynsym*) } + + . = ALIGN(4); + .hash : { *(.hash*) } + + . = ALIGN(4); + .got : { *(.got*) } + + . = ALIGN(4); + __data_end = .; + + . = ALIGN(4); + __bss_start = ABSOLUTE(.); + .bss (NOLOAD) : { *(.bss) } + . = ALIGN(4); + __bss_end = ABSOLUTE(.); + + . = ALIGN(4); + __rel_dyn_start = .; + .rel.dyn : { *(.rel.dyn) } + __rel_dyn_end = .; + + /DISCARD/ : { *(.dynstr*) } + /DISCARD/ : { *(.dynamic*) } + /DISCARD/ : { *(.plt*) } + /DISCARD/ : { *(.interp*) } + /DISCARD/ : { *(.gnu*) } + + /* 16bit realmode trampoline code */ + .realmode REALMODE_BASE : AT ( LOADADDR(.rel.dyn) + SIZEOF(.rel.dyn) ) { KEEP(*(.realmode)) } + + __realmode_start = LOADADDR(.realmode); + __realmode_size = SIZEOF(.realmode); + + /* 16bit BIOS emulation code (just enough to boot Linux) */ + .bios 0 : AT ( LOADADDR(.realmode) + SIZEOF(.realmode) ) { KEEP(*(.bios)) } + + __bios_start = LOADADDR(.bios); + __bios_size = SIZEOF(.bios); + + /* + * The following expressions place the 16-bit Real-Mode code and + * Reset Vector at the end of the Flash ROM + */ + . = START_16; + .start16 : AT (CONFIG_SYS_TEXT_BASE + (CONFIG_SYS_MONITOR_LEN - RESET_SEG_SIZE + START_16)) { KEEP(*(.start16)); } + + . = RESET_VEC_LOC; + .resetvec : AT (CONFIG_SYS_TEXT_BASE + (CONFIG_SYS_MONITOR_LEN - RESET_SEG_SIZE + RESET_VEC_LOC)) { KEEP(*(.resetvec)); } +} |