diff options
Diffstat (limited to 'arch/i386/cpu')
-rw-r--r-- | arch/i386/cpu/Makefile | 2 | ||||
-rw-r--r-- | arch/i386/cpu/interrupts.c | 214 | ||||
-rw-r--r-- | arch/i386/cpu/sc520/sc520.c | 33 | ||||
-rw-r--r-- | arch/i386/cpu/sc520/sc520_asm.S | 214 | ||||
-rw-r--r-- | arch/i386/cpu/sc520/sc520_pci.c | 63 | ||||
-rw-r--r-- | arch/i386/cpu/sc520/sc520_ssi.c | 27 | ||||
-rw-r--r-- | arch/i386/cpu/sc520/sc520_timer.c | 35 | ||||
-rw-r--r-- | arch/i386/cpu/serial.c | 506 | ||||
-rw-r--r-- | arch/i386/cpu/start.S | 137 | ||||
-rw-r--r-- | arch/i386/cpu/start16.S | 29 |
10 files changed, 530 insertions, 730 deletions
diff --git a/arch/i386/cpu/Makefile b/arch/i386/cpu/Makefile index c658c6e4591..bb0a48f8643 100644 --- a/arch/i386/cpu/Makefile +++ b/arch/i386/cpu/Makefile @@ -29,7 +29,7 @@ include $(TOPDIR)/config.mk LIB = $(obj)lib$(CPU).a START = start.o start16.o resetvec.o -COBJS = serial.o interrupts.o cpu.o +COBJS = interrupts.o cpu.o SRCS := $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c) OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS)) diff --git a/arch/i386/cpu/interrupts.c b/arch/i386/cpu/interrupts.c index 4b574371930..51023f3a86f 100644 --- a/arch/i386/cpu/interrupts.c +++ b/arch/i386/cpu/interrupts.c @@ -5,6 +5,9 @@ * (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. * @@ -32,12 +35,112 @@ ".hidden irq_"#x"\n" \ ".type irq_"#x", @function\n" \ "irq_"#x":\n" \ - "pushl %ebp\n" \ - "movl %esp,%ebp\n" \ - "pusha\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 serialization + */ +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 pt_regs *regs) +{ + unsigned long cr0 = 0L, cr2 = 0L, cr3 = 0L, cr4 = 0L; + unsigned long d0, d1, d2, d3, d6, d7; + + 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); +} + struct idt_entry { u16 base_low; u16 selector; @@ -122,7 +225,7 @@ int disable_interrupts(void) } /* IRQ Low-Level Service Routine */ -__isr__ irq_llsr(int ip, int seg, int irq) +__isr__ irq_llsr(struct pt_regs *regs) { /* * For detailed description of each exception, refer to: @@ -131,73 +234,92 @@ __isr__ irq_llsr(int ip, int seg, int irq) * Order Number: 253665-029US, November 2008 * Table 6-1. Exceptions and Interrupts */ - switch (irq) { + switch (regs->orig_eax) { case 0x00: - printf("Divide Error (Division by zero) at %04x:%08x\n", seg, ip); + printf("Divide Error (Division by zero)\n"); + dump_regs(regs); while(1); break; case 0x01: - printf("Debug Interrupt (Single step) at %04x:%08x\n", seg, ip); + printf("Debug Interrupt (Single step)\n"); + dump_regs(regs); break; case 0x02: - printf("NMI Interrupt at %04x:%08x\n", seg, ip); + printf("NMI Interrupt\n"); + dump_regs(regs); break; case 0x03: - printf("Breakpoint at %04x:%08x\n", seg, ip); + printf("Breakpoint\n"); + dump_regs(regs); break; case 0x04: - printf("Overflow at %04x:%08x\n", seg, ip); + printf("Overflow\n"); + dump_regs(regs); while(1); break; case 0x05: - printf("BOUND Range Exceeded at %04x:%08x\n", seg, ip); + printf("BOUND Range Exceeded\n"); + dump_regs(regs); while(1); break; case 0x06: - printf("Invalid Opcode (UnDefined Opcode) at %04x:%08x\n", seg, ip); + printf("Invalid Opcode (UnDefined Opcode)\n"); + dump_regs(regs); while(1); break; case 0x07: - printf("Device Not Available (No Math Coprocessor) at %04x:%08x\n", seg, ip); + printf("Device Not Available (No Math Coprocessor)\n"); + dump_regs(regs); while(1); break; case 0x08: - printf("Double fault at %04x:%08x\n", seg, ip); + printf("Double fault\n"); + dump_regs(regs); while(1); break; case 0x09: - printf("Co-processor segment overrun at %04x:%08x\n", seg, ip); + printf("Co-processor segment overrun\n"); + dump_regs(regs); while(1); break; case 0x0a: - printf("Invalid TSS at %04x:%08x\n", seg, ip); + printf("Invalid TSS\n"); + dump_regs(regs); break; case 0x0b: - printf("Segment Not Present at %04x:%08x\n", seg, ip); + printf("Segment Not Present\n"); + dump_regs(regs); while(1); break; case 0x0c: - printf("Stack Segment Fault at %04x:%08x\n", seg, ip); + printf("Stack Segment Fault\n"); + dump_regs(regs); while(1); break; case 0x0d: - printf("General Protection at %04x:%08x\n", seg, ip); + printf("General Protection\n"); + dump_regs(regs); break; case 0x0e: - printf("Page fault at %04x:%08x\n", seg, ip); + printf("Page fault\n"); + dump_regs(regs); while(1); break; case 0x0f: - printf("Floating-Point Error (Math Fault) at %04x:%08x\n", seg, ip); + printf("Floating-Point Error (Math Fault)\n"); + dump_regs(regs); break; case 0x10: - printf("Alignment check at %04x:%08x\n", seg, ip); + printf("Alignment check\n"); + dump_regs(regs); break; case 0x11: - printf("Machine Check at %04x:%08x\n", seg, ip); + printf("Machine Check\n"); + dump_regs(regs); break; case 0x12: - printf("SIMD Floating-Point Exception at %04x:%08x\n", seg, ip); + printf("SIMD Floating-Point Exception\n"); + dump_regs(regs); break; case 0x13: case 0x14: @@ -212,12 +334,13 @@ __isr__ irq_llsr(int ip, int seg, int irq) case 0x1d: case 0x1e: case 0x1f: - printf("Reserved Exception %d at %04x:%08x\n", irq, seg, ip); + printf("Reserved Exception\n"); + dump_regs(regs); break; default: /* Hardware or User IRQ */ - do_irq(irq); + do_irq(regs->orig_eax); } } @@ -226,22 +349,45 @@ __isr__ irq_llsr(int ip, int seg, int irq) * fully relocatable code. * - The call to irq_llsr will be a relative jump * - The IRQ entries will be guaranteed to be in order - * It's a bit annoying that we need to waste 3 bytes per interrupt entry - * (total of 768 code bytes), but we MUST create a Stack Frame and this is - * the easiest way I could do it. Maybe it can be made better later. + * 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 */ asm(".globl irq_common_entry\n" \ ".hidden irq_common_entry\n" \ ".type irq_common_entry, @function\n" \ "irq_common_entry:\n" \ - "pushl $0\n" \ - "pushl $0\n" \ + "cld\n" \ + "pushl %gs\n" \ + "pushl %fs\n" \ + "pushl %es\n" \ + "pushl %ds\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" \ + "pushl %ebp\n" \ + "movl %esp,%ebp\n" \ + "pushl %eax\n" \ "call irq_llsr\n" \ "popl %eax\n" \ - "popl %eax\n" \ - "popl %eax\n" \ - "popa\n" \ "leave\n"\ + "popl %ebx\n" \ + "popl %ecx\n" \ + "popl %edx\n" \ + "popl %esi\n" \ + "popl %edi\n" \ + "popl %ebp\n" \ + "popl %eax\n" \ + "popl %ds\n" \ + "popl %es\n" \ + "popl %fs\n" \ + "popl %gs\n" \ + "add $4, %esp\n" \ "iret\n" \ DECLARE_INTERRUPT(0) \ DECLARE_INTERRUPT(1) \ diff --git a/arch/i386/cpu/sc520/sc520.c b/arch/i386/cpu/sc520/sc520.c index 4b566a75ccd..519bfd8b0c2 100644 --- a/arch/i386/cpu/sc520/sc520.c +++ b/arch/i386/cpu/sc520/sc520.c @@ -44,24 +44,24 @@ void init_sc520(void) /* Set the UARTxCTL register at it's slower, * baud clock giving us a 1.8432 MHz reference */ - sc520_mmcr->uart1ctl = 0x07; - sc520_mmcr->uart2ctl = 0x07; + writeb(0x07, &sc520_mmcr->uart1ctl); + writeb(0x07, &sc520_mmcr->uart2ctl); /* first set the timer pin mapping */ - sc520_mmcr->clksel = 0x72; /* no clock frequency selected, use 1.1892MHz */ + writeb(0x72, &sc520_mmcr->clksel); /* no clock frequency selected, use 1.1892MHz */ /* enable PCI bus arbitrer */ - sc520_mmcr->sysarbctl = 0x02; /* enable concurrent mode */ + writeb(0x02, &sc520_mmcr->sysarbctl); /* enable concurrent mode */ - sc520_mmcr->sysarbmenb = 0x1f; /* enable external grants */ - sc520_mmcr->hbctl = 0x04; /* enable posted-writes */ + writeb(0x1f, &sc520_mmcr->sysarbmenb); /* enable external grants */ + writeb(0x04, &sc520_mmcr->hbctl); /* enable posted-writes */ if (CONFIG_SYS_SC520_HIGH_SPEED) { - sc520_mmcr->cpuctl = 0x02; /* set it to 133 MHz and write back */ + writeb(0x02, &sc520_mmcr->cpuctl); /* set it to 133 MHz and write back */ gd->cpu_clk = 133000000; printf("## CPU Speed set to 133MHz\n"); } else { - sc520_mmcr->cpuctl = 0x01; /* set it to 100 MHz and write back */ + writeb(0x01, &sc520_mmcr->cpuctl); /* set it to 100 MHz and write back */ printf("## CPU Speed set to 100MHz\n"); gd->cpu_clk = 100000000; } @@ -74,7 +74,7 @@ void init_sc520(void) "loop 0b\n": : : "ecx"); /* turn on the SDRAM write buffer */ - sc520_mmcr->dbctl = 0x11; + writeb(0x11, &sc520_mmcr->dbctl); /* turn on the cache and disable write through */ asm("movl %%cr0, %%eax\n" @@ -88,6 +88,7 @@ unsigned long init_sc520_dram(void) u32 dram_present=0; u32 dram_ctrl; + #ifdef CONFIG_SYS_SDRAM_DRCTMCTL /* these memory control registers are set up in the assember part, * in sc520_asm.S, during 'mem_init'. If we muck with them here, @@ -97,7 +98,8 @@ unsigned long init_sc520_dram(void) * simply dictates it. */ #else - int val; + u8 tmp; + u8 val; int cas_precharge_delay = CONFIG_SYS_SDRAM_PRECHARGE_DELAY; int refresh_rate = CONFIG_SYS_SDRAM_REFRESH_RATE; @@ -116,9 +118,10 @@ unsigned long init_sc520_dram(void) val = 3; /* 62.4us */ } - sc520_mmcr->drcctl = (sc520_mmcr->drcctl & 0xcf) | (val<<4); + tmp = (readb(&sc520_mmcr->drcctl) & 0xcf) | (val<<4); + writeb(tmp, &sc520_mmcr->drcctl); - val = sc520_mmcr->drctmctl & 0xf0; + val = readb(&sc520_mmcr->drctmctl) & 0xf0; if (cas_precharge_delay==3) { val |= 0x04; /* 3T */ @@ -133,12 +136,12 @@ unsigned long init_sc520_dram(void) } else { val |= 1; } - sc520_mmcr->drctmctl = val; + writeb(val, &c520_mmcr->drctmctl); #endif /* We read-back the configuration of the dram * controller that the assembly code wrote */ - dram_ctrl = sc520_mmcr->drcbendadr; + dram_ctrl = readl(&sc520_mmcr->drcbendadr); bd->bi_dram[0].start = 0; if (dram_ctrl & 0x80) { @@ -191,7 +194,7 @@ void reset_cpu(ulong addr) { printf("Resetting using SC520 MMCR\n"); /* Write a '1' to the SYS_RST of the RESCFG MMCR */ - sc520_mmcr->rescfg = 0x01; + writeb(0x01, &sc520_mmcr->rescfg); /* NOTREACHED */ } diff --git a/arch/i386/cpu/sc520/sc520_asm.S b/arch/i386/cpu/sc520/sc520_asm.S index 2042d9bfcf8..fff56c00b4f 100644 --- a/arch/i386/cpu/sc520/sc520_asm.S +++ b/arch/i386/cpu/sc520/sc520_asm.S @@ -25,48 +25,85 @@ * copyright is included below */ -/* - * ============================================================================= - * - * Copyright 1999 Advanced Micro Devices, Inc. - * - * This software is the property of Advanced Micro Devices, Inc (AMD) which - * specifically grants the user the right to modify, use and distribute this - * software provided this COPYRIGHT NOTICE is not removed or altered. All - * other rights are reserved by AMD. - * - * THE MATERIALS ARE PROVIDED "AS IS" WITHOUT ANY EXPRESS OR IMPLIED WARRANTY - * OF ANY KIND INCLUDING WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT OF - * THIRD-PARTY INTELLECTUAL PROPERTY, OR FITNESS FOR ANY PARTICULAR PURPOSE. - * IN NO EVENT SHALL AMD OR ITS SUPPLIERS BE LIABLE FOR ANY DAMAGES WHATSOEVER - * (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF PROFITS, BUSINESS - * INTERRUPTION, LOSS OF INFORMAITON) ARISING OUT OF THE USE OF OR INABILITY - * TO USE THE MATERIALS, EVEN IF AMD HAS BEEN ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGES. BECAUSE SOME JURSIDICTIONS PROHIBIT THE EXCLUSION OR - * LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES, THE ABOVE - * LIMITATION MAY NOT APPLY TO YOU. - * - * AMD does not assume any responsibility for any errors that may appear in - * the Materials nor any responsibility to support or update the Materials. - * AMD retains the right to make changes to its test specifications at any - * time, without notice. - * - * So that all may benefit from your experience, please report any problems - * or suggestions about this software back to AMD. Please include your name, - * company, telephone number, AMD product requiring support and question or - * problem encountered. - * - * Advanced Micro Devices, Inc. Worldwide support and contact - * Embedded Processor Division information available at: - * Systems Engineering epd.support@amd.com - * 5204 E. Ben White Blvd. -or- - * Austin, TX 78741 http://www.amd.com/html/support/techsup.html - * ============================================================================ +/* TITLE SIZER - Aspen DRAM Sizing Routine. + * ============================================================================= + * + * Copyright 1999 Advanced Micro Devices, Inc. + * You may redistribute this program and/or modify this program 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 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. + * + * THE MATERIALS ARE PROVIDED "AS IS" WITHOUT ANY EXPRESS OR IMPLIED WARRANTY + * OF ANY KIND INCLUDING WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT OF + * THIRD-PARTY INTELLECTUAL PROPERTY, OR FITNESS FOR ANY PARTICULAR PURPOSE. + * IN NO EVENT SHALL AMD OR ITS SUPPLIERS BE LIABLE FOR ANY DAMAGES WHATSOEVER + * (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF PROFITS, BUSINESS + * INTERRUPTION, LOSS OF INFORMATION) ARISING OUT OF THE USE OF OR INABILITY + * TO USE THE MATERIALS, EVEN IF AMD HAS BEEN ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGES. BECAUSE SOME JURSIDICTIONS PROHIBIT THE EXCLUSION OR + * LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES, THE ABOVE + * LIMITATION MAY NOT APPLY TO YOU. + * + * AMD does not assume any responsibility for any errors that may appear in + * the Materials nor any responsibility to support or update the Materials. + * AMD retains the right to make changes to its test specifications at any + * time, without notice. + * ============================================================================== */ - -/******************************************************************************* - * AUTHOR : Buddy Fey - Original. +/* + ****************************************************************************** + * + * FILE : sizer.asm - SDRAM DIMM Sizing Algorithm + * + * + * + * FUNCTIONS : sizemem() - jumped to, not called. To be executed after + * reset to determine the size of the SDRAM DIMMs. Initializes + * the memory subsystem. + * + * + * AUTHOR : Buddy Fey - Original. + * + * + * DESCRIPTION : Performs sizing on SDRAM DIMMs on ASPEN processor. + * NOTE: This is a small memory model version + * + * + * INPUTS : BP contains return address offset + * CACHE is assumed to be disabled. + * The FS segment limit has already been set to big real mode + * (full 32-bit addressing capability) + * + * + * OUTPUTS : None + * + * + * REG USE : ax,bx,cx,dx,di,si,bp, fs + * + * + * REVISION : See PVCS info below + * + * + * TEST PLAN CROSS REFERENCE: + * + * + * $Workfile: $ + * $Revision: 1.2 $ + * $Date: 1999/09/22 12:49:33 $ + * $Author: chipf $ + * $Log: sizer.asm $ + * Revision 1.2 1999/09/22 12:49:33 chipf + * Add legal header + * ******************************************************************************* */ @@ -463,7 +500,7 @@ emptybank: /* just have your hardware desinger _GIVE_ you what you need here! */ movl $DRCTMCTL, %edi movb $CONFIG_SYS_SDRAM_DRCTMCTL,%al - movb (%edi), %al + movb %al, (%edi) #else #if defined(CONFIG_SYS_SDRAM_CAS_LATENCY_2T) || defined(CONFIG_SYS_SDRAM_CAS_LATENCY_3T) /* set the CAS latency now since it is hard to do @@ -498,48 +535,21 @@ bad_ram: dram_done: - /* readback DRCBENDADR and return the number - * of available ram bytes in %eax */ - - movl $DRCBENDADR, %edi /* DRAM ending address register */ - - movl (%edi), %eax - movl %eax, %ecx - andl $0x80000000, %ecx - jz bank2 - andl $0x7f000000, %eax - shrl $2, %eax - movl %eax, %ebx - -bank2: movl (%edi), %eax - movl %eax, %ecx - andl $0x00800000, %ecx - jz bank1 - andl $0x007f0000, %eax - shll $6, %eax - movl %eax, %ebx - -bank1: movl (%edi), %eax - movl %eax, %ecx - andl $0x00008000, %ecx - jz bank0 - andl $0x00007f00, %eax - shll $14, %eax - movl %eax, %ebx - -bank0: movl (%edi), %eax - movl %eax, %ecx - andl $0x00000080, %ecx - jz done - andl $0x0000007f, %eax - shll $22, %eax - movl %eax, %ebx +#if CONFIG_SYS_SDRAM_ECC_ENABLE + /* + * We are in the middle of an existing 'call' - Need to store the + * existing return address before making another 'call' + */ + movl %ebp, %ebx + /* Get the memory size */ + movl $init_ecc, %ebp + jmpl get_mem_size -done: - movl %ebx, %eax +init_ecc: + /* Restore the orignal return address */ + movl %ebx, %ebp -#if CONFIG_SYS_SDRAM_ECC_ENABLE /* A nominal memory test: just a byte at each address line */ movl %eax, %ecx shrl $0x1, %ecx @@ -576,6 +586,50 @@ set_ecc: mov $0x05, %al movb %al, (%edi) #endif + out: + jmp *%ebp + +/* + * Read and decode the sc520 DRCBENDADR MMCR and return the number of + * available ram bytes in %eax + */ +.globl get_mem_size +get_mem_size: + movl $DRCBENDADR, %edi /* DRAM ending address register */ + +bank0: movl (%edi), %eax + movl %eax, %ecx + andl $0x00000080, %ecx + jz bank1 + andl $0x0000007f, %eax + shll $22, %eax + movl %eax, %ebx + +bank1: movl (%edi), %eax + movl %eax, %ecx + andl $0x00008000, %ecx + jz bank2 + andl $0x00007f00, %eax + shll $14, %eax + movl %eax, %ebx + +bank2: movl (%edi), %eax + movl %eax, %ecx + andl $0x00800000, %ecx + jz bank3 + andl $0x007f0000, %eax + shll $6, %eax + movl %eax, %ebx + +bank3: movl (%edi), %eax + movl %eax, %ecx + andl $0x80000000, %ecx + jz done + andl $0x7f000000, %eax + shrl $2, %eax + movl %eax, %ebx + +done: movl %ebx, %eax jmp *%ebp diff --git a/arch/i386/cpu/sc520/sc520_pci.c b/arch/i386/cpu/sc520/sc520_pci.c index f446c6d5927..b91773435e9 100644 --- a/arch/i386/cpu/sc520/sc520_pci.c +++ b/arch/i386/cpu/sc520/sc520_pci.c @@ -25,7 +25,9 @@ #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 { @@ -63,6 +65,8 @@ int sc520_pci_ints[15] = { int pci_sc520_set_irq(int pci_pin, int irq) { int i; + u8 tmpb; + u16 tmpw; # if 1 printf("set_irq(): map INT%c to IRQ%d\n", pci_pin + 'A', irq); @@ -80,31 +84,34 @@ int pci_sc520_set_irq(int pci_pin, int irq) /* PCI interrupt mapping (A through D)*/ for (i=0; i<=3 ;i++) { - if (sc520_mmcr->pci_int_map[i] == sc520_irq[irq].priority) - sc520_mmcr->pci_int_map[i] = SC520_IRQ_DISABLED; + 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 (sc520_mmcr->gp_int_map[i] == sc520_irq[irq].priority) - sc520_mmcr->gp_int_map[i] = SC520_IRQ_DISABLED; + 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 */ - sc520_mmcr->pic_mode[sc520_irq[irq].level_reg] = - sc520_mmcr->pic_mode[sc520_irq[irq].level_reg] | sc520_irq[irq].level_bit; + 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 */ - sc520_mmcr->pci_int_map[pci_pin] = sc520_irq[irq].priority; + writeb(sc520_irq[irq].priority, &sc520_mmcr->pci_int_map[pci_pin]); } else { /* GPIRQ0-GPIRQ10 used for additional PCI INTS */ - sc520_mmcr->gp_int_map[pci_pin - 4] = sc520_irq[irq].priority; + writeb(sc520_irq[irq].priority, &sc520_mmcr->gp_int_map[pci_pin - 4]); /* also set the polarity in this case */ - sc520_mmcr->intpinpol = sc520_mmcr->intpinpol | (1 << (pci_pin-4)); + tmpw = readw(&sc520_mmcr->intpinpol); + tmpw |= (1 << (pci_pin-4)); + writew(tmpw, &sc520_mmcr->intpinpol); } /* register the pin */ @@ -118,43 +125,7 @@ void pci_sc520_init(struct pci_controller *hose) { hose->first_busno = 0; hose->last_busno = 0xff; - - /* System memory space */ - pci_set_region(hose->regions + 0, - SC520_PCI_MEMORY_BUS, - SC520_PCI_MEMORY_PHYS, - SC520_PCI_MEMORY_SIZE, - PCI_REGION_MEM | PCI_REGION_SYS_MEMORY); - - /* PCI memory space */ - pci_set_region(hose->regions + 1, - SC520_PCI_MEM_BUS, - SC520_PCI_MEM_PHYS, - SC520_PCI_MEM_SIZE, - PCI_REGION_MEM); - - /* ISA/PCI memory space */ - pci_set_region(hose->regions + 2, - SC520_ISA_MEM_BUS, - SC520_ISA_MEM_PHYS, - SC520_ISA_MEM_SIZE, - PCI_REGION_MEM); - - /* PCI I/O space */ - pci_set_region(hose->regions + 3, - SC520_PCI_IO_BUS, - SC520_PCI_IO_PHYS, - SC520_PCI_IO_SIZE, - PCI_REGION_IO); - - /* ISA/PCI I/O space */ - pci_set_region(hose->regions + 4, - SC520_ISA_IO_BUS, - SC520_ISA_IO_PHYS, - SC520_ISA_IO_SIZE, - PCI_REGION_IO); - - hose->region_count = 5; + hose->region_count = pci_set_regions(hose); pci_setup_type1(hose, SC520_REG_ADDR, diff --git a/arch/i386/cpu/sc520/sc520_ssi.c b/arch/i386/cpu/sc520/sc520_ssi.c index 8dbe17aa60e..6e5e3463033 100644 --- a/arch/i386/cpu/sc520/sc520_ssi.c +++ b/arch/i386/cpu/sc520/sc520_ssi.c @@ -24,6 +24,7 @@ /* stuff specific for the sc520, but independent of implementation */ #include <common.h> +#include <asm/io.h> #include <asm/ic/ssi.h> #include <asm/ic/sc520.h> @@ -61,34 +62,34 @@ int ssi_set_interface(int freq, int lsb_first, int inv_clock, int inv_phase) temp |= PHS_INV_ENB; } - sc520_mmcr->ssictl = temp; + writeb(temp, &sc520_mmcr->ssictl); return 0; } u8 ssi_txrx_byte(u8 data) { - sc520_mmcr->ssixmit = data; - while (sc520_mmcr->ssista & SSISTA_BSY); - sc520_mmcr->ssicmd = SSICMD_CMD_SEL_XMITRCV; - while (sc520_mmcr->ssista & SSISTA_BSY); + 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 sc520_mmcr->ssircv; + return readb(&sc520_mmcr->ssircv); } void ssi_tx_byte(u8 data) { - sc520_mmcr->ssixmit = data; - while (sc520_mmcr->ssista & SSISTA_BSY); - sc520_mmcr->ssicmd = SSICMD_CMD_SEL_XMIT; + 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 (sc520_mmcr->ssista & SSISTA_BSY); - sc520_mmcr->ssicmd = SSICMD_CMD_SEL_RCV; - while (sc520_mmcr->ssista & SSISTA_BSY); + while (readb(&sc520_mmcr->ssista) & SSISTA_BSY); + writeb(SSICMD_CMD_SEL_RCV, &sc520_mmcr->ssicmd); + while (readb(&sc520_mmcr->ssista) & SSISTA_BSY); - return sc520_mmcr->ssircv; + return readb(&sc520_mmcr->ssircv); } diff --git a/arch/i386/cpu/sc520/sc520_timer.c b/arch/i386/cpu/sc520/sc520_timer.c index 93b5b555c30..d5617e91f6e 100644 --- a/arch/i386/cpu/sc520/sc520_timer.c +++ b/arch/i386/cpu/sc520/sc520_timer.c @@ -24,13 +24,14 @@ /* stuff specific for the sc520, but independent of implementation */ #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 */ - sc520_mmcr->gptmrsta = 0x02; + writeb(0x02, &sc520_mmcr->gptmrsta); } int timer_init(void) @@ -42,43 +43,47 @@ int timer_init(void) irq_install_handler (0, timer_isr, NULL); /* Map GP Timer 1 to Master PIC IR0 */ - sc520_mmcr->gp_tmr_int_map[1] = 0x01; + writeb(0x01, &sc520_mmcr->gp_tmr_int_map[1]); /* Disable GP Timers 1 & 2 - Allow configuration writes */ - sc520_mmcr->gptmr1ctl = 0x4000; - sc520_mmcr->gptmr2ctl = 0x4000; + writew(0x4000, &sc520_mmcr->gptmr1ctl); + writew(0x4000, &sc520_mmcr->gptmr2ctl); /* Reset GP Timers 1 & 2 */ - sc520_mmcr->gptmr1cnt = 0x0000; - sc520_mmcr->gptmr2cnt = 0x0000; + writew(0x0000, &sc520_mmcr->gptmr1cnt); + writew(0x0000, &sc520_mmcr->gptmr2cnt); /* Setup GP Timer 2 as a 100kHz (10us) prescaler */ - sc520_mmcr->gptmr2maxcmpa = 83; - sc520_mmcr->gptmr2ctl = 0xc001; + writew(83, &sc520_mmcr->gptmr2maxcmpa); + writew(0xc001, &sc520_mmcr->gptmr2ctl); /* Setup GP Timer 1 as a 1000 Hz (1ms) interrupt generator */ - sc520_mmcr->gptmr1maxcmpa = 100; - sc520_mmcr->gptmr1ctl = 0xe009; + 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*/ - sc520_mmcr->gptmrsta = 0x02; + 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 = sc520_mmcr->swtmrmilli; - temp = sc520_mmcr->swtmrmicro; + temp = readw(&sc520_mmcr->swtmrmilli); + temp = readw(&sc520_mmcr->swtmrmicro); do { - m += sc520_mmcr->swtmrmilli; - u = sc520_mmcr->swtmrmicro + (m * 1000); + m += readw(&sc520_mmcr->swtmrmilli); + u = readw(&sc520_mmcr->swtmrmicro) + (m * 1000); } while (u < usec); } diff --git a/arch/i386/cpu/serial.c b/arch/i386/cpu/serial.c deleted file mode 100644 index e7025a3cdc0..00000000000 --- a/arch/i386/cpu/serial.c +++ /dev/null @@ -1,506 +0,0 @@ -/* - * (C) Copyright 2002 - * Daniel Engström, Omicron Ceti AB, daniel@omicron.se - * - * (C) Copyright 2000 - * 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 - */ -/*------------------------------------------------------------------------------+ */ - -/* - * This source code is dual-licensed. You may use it under the terms of the - * GNU General Public License version 2, or under the license below. - * - * This source code has been made available to you by IBM on an AS-IS - * basis. Anyone receiving this source is licensed under IBM - * copyrights to use it in any way he or she deems fit, including - * copying it, modifying it, compiling it, and redistributing it either - * with or without modifications. No license under IBM patents or - * patent applications is to be implied by the copyright license. - * - * Any user of this software should understand that IBM cannot provide - * technical support for this software and will not be responsible for - * any consequences resulting from the use of this software. - * - * Any person who transfers this source code or any derivative work - * must include the IBM copyright notice, this paragraph, and the - * preceding two paragraphs in the transferred software. - * - * COPYRIGHT I B M CORPORATION 1995 - * LICENSED MATERIAL - PROGRAM PROPERTY OF I B M - */ -/*------------------------------------------------------------------------------- */ - -#include <common.h> -#include <watchdog.h> -#include <asm/io.h> -#include <asm/ibmpc.h> - -#ifdef CONFIG_SERIAL_SOFTWARE_FIFO -#include <malloc.h> -#endif - -DECLARE_GLOBAL_DATA_PTR; - -#define UART_RBR 0x00 -#define UART_THR 0x00 -#define UART_IER 0x01 -#define UART_IIR 0x02 -#define UART_FCR 0x02 -#define UART_LCR 0x03 -#define UART_MCR 0x04 -#define UART_LSR 0x05 -#define UART_MSR 0x06 -#define UART_SCR 0x07 -#define UART_DLL 0x00 -#define UART_DLM 0x01 - -/*-----------------------------------------------------------------------------+ - | Line Status Register. - +-----------------------------------------------------------------------------*/ -#define asyncLSRDataReady1 0x01 -#define asyncLSROverrunError1 0x02 -#define asyncLSRParityError1 0x04 -#define asyncLSRFramingError1 0x08 -#define asyncLSRBreakInterrupt1 0x10 -#define asyncLSRTxHoldEmpty1 0x20 -#define asyncLSRTxShiftEmpty1 0x40 -#define asyncLSRRxFifoError1 0x80 - - -#ifdef CONFIG_SERIAL_SOFTWARE_FIFO -/*-----------------------------------------------------------------------------+ - | Fifo - +-----------------------------------------------------------------------------*/ -typedef struct { - char *rx_buffer; - ulong rx_put; - ulong rx_get; - int cts; -} serial_buffer_t; - -volatile serial_buffer_t buf_info; -static int serial_buffer_active=0; -#endif - - -static int serial_div(int baudrate) -{ - - switch (baudrate) { - case 1200: - return 96; - case 9600: - return 12; - case 19200: - return 6; - case 38400: - return 3; - case 57600: - return 2; - case 115200: - return 1; - } - - return 12; -} - - -/* - * Minimal serial functions needed to use one of the SMC ports - * as serial console interface. - */ - -int serial_init(void) -{ - volatile char val; - int bdiv = serial_div(gd->baudrate); - - outb(0x80, UART0_BASE + UART_LCR); /* set DLAB bit */ - outb(bdiv, UART0_BASE + UART_DLL); /* set baudrate divisor */ - outb(bdiv >> 8, UART0_BASE + UART_DLM);/* set baudrate divisor */ - outb(0x03, UART0_BASE + UART_LCR); /* clear DLAB; set 8 bits, no parity */ - outb(0x01, UART0_BASE + UART_FCR); /* enable FIFO */ - outb(0x0b, UART0_BASE + UART_MCR); /* Set DTR and RTS active */ - val = inb(UART0_BASE + UART_LSR); /* clear line status */ - val = inb(UART0_BASE + UART_RBR); /* read receive buffer */ - outb(0x00, UART0_BASE + UART_SCR); /* set scratchpad */ - outb(0x00, UART0_BASE + UART_IER); /* set interrupt enable reg */ - - return 0; -} - - -void serial_setbrg(void) -{ - unsigned short bdiv; - - bdiv = serial_div(gd->baudrate); - - outb(0x80, UART0_BASE + UART_LCR); /* set DLAB bit */ - outb(bdiv&0xff, UART0_BASE + UART_DLL); /* set baudrate divisor */ - outb(bdiv >> 8, UART0_BASE + UART_DLM);/* set baudrate divisor */ - outb(0x03, UART0_BASE + UART_LCR); /* clear DLAB; set 8 bits, no parity */ -} - - -void serial_putc(const char c) -{ - int i; - - if (c == '\n') - serial_putc ('\r'); - - /* check THRE bit, wait for transmiter available */ - for (i = 1; i < 3500; i++) { - if ((inb (UART0_BASE + UART_LSR) & 0x20) == 0x20) { - break; - } - udelay(100); - } - outb(c, UART0_BASE + UART_THR); /* put character out */ -} - - -void serial_puts(const char *s) -{ - while (*s) { - serial_putc(*s++); - } -} - - -int serial_getc(void) -{ - unsigned char status = 0; - -#ifdef CONFIG_SERIAL_SOFTWARE_FIFO - if (serial_buffer_active) { - return serial_buffered_getc(); - } -#endif - - while (1) { -#if defined(CONFIG_HW_WATCHDOG) - WATCHDOG_RESET(); /* Reset HW Watchdog, if needed */ -#endif /* CONFIG_HW_WATCHDOG */ - status = inb(UART0_BASE + UART_LSR); - if ((status & asyncLSRDataReady1) != 0x0) { - break; - } - if ((status & ( asyncLSRFramingError1 | - asyncLSROverrunError1 | - asyncLSRParityError1 | - asyncLSRBreakInterrupt1 )) != 0) { - outb(asyncLSRFramingError1 | - asyncLSROverrunError1 | - asyncLSRParityError1 | - asyncLSRBreakInterrupt1, UART0_BASE + UART_LSR); - } - } - return (0x000000ff & (int) inb (UART0_BASE)); -} - - -int serial_tstc(void) -{ - unsigned char status; - -#ifdef CONFIG_SERIAL_SOFTWARE_FIFO - if (serial_buffer_active) { - return serial_buffered_tstc(); - } -#endif - - status = inb(UART0_BASE + UART_LSR); - if ((status & asyncLSRDataReady1) != 0x0) { - return (1); - } - if ((status & ( asyncLSRFramingError1 | - asyncLSROverrunError1 | - asyncLSRParityError1 | - asyncLSRBreakInterrupt1 )) != 0) { - outb(asyncLSRFramingError1 | - asyncLSROverrunError1 | - asyncLSRParityError1 | - asyncLSRBreakInterrupt1, UART0_BASE + UART_LSR); - } - return 0; -} - - -#ifdef CONFIG_SERIAL_SOFTWARE_FIFO - -void serial_isr(void *arg) -{ - int space; - int c; - int rx_put = buf_info.rx_put; - - if (buf_info.rx_get <= rx_put) { - space = CONFIG_SERIAL_SOFTWARE_FIFO - (rx_put - buf_info.rx_get); - } else { - space = buf_info.rx_get - rx_put; - } - - while (inb(UART0_BASE + UART_LSR) & 1) { - c = inb(UART0_BASE); - if (space) { - buf_info.rx_buffer[rx_put++] = c; - space--; - - if (rx_put == buf_info.rx_get) { - buf_info.rx_get++; - if (rx_put == CONFIG_SERIAL_SOFTWARE_FIFO) { - buf_info.rx_get = 0; - } - } - - if (rx_put == CONFIG_SERIAL_SOFTWARE_FIFO) { - rx_put = 0; - if (0 == buf_info.rx_get) { - buf_info.rx_get = 1; - } - - } - - } - if (space < CONFIG_SERIAL_SOFTWARE_FIFO / 4) { - /* Stop flow by setting RTS inactive */ - outb(inb(UART0_BASE + UART_MCR) & (0xFF ^ 0x02), - UART0_BASE + UART_MCR); - } - } - buf_info.rx_put = rx_put; -} - -void serial_buffered_init(void) -{ - serial_puts ("Switching to interrupt driven serial input mode.\n"); - buf_info.rx_buffer = malloc (CONFIG_SERIAL_SOFTWARE_FIFO); - buf_info.rx_put = 0; - buf_info.rx_get = 0; - - if (inb (UART0_BASE + UART_MSR) & 0x10) { - serial_puts ("Check CTS signal present on serial port: OK.\n"); - buf_info.cts = 1; - } else { - serial_puts ("WARNING: CTS signal not present on serial port.\n"); - buf_info.cts = 0; - } - - irq_install_handler ( VECNUM_U0 /*UART0 */ /*int vec */ , - serial_isr /*interrupt_handler_t *handler */ , - (void *) &buf_info /*void *arg */ ); - - /* Enable "RX Data Available" Interrupt on UART */ - /* outb(inb(UART0_BASE + UART_IER) |0x01, UART0_BASE + UART_IER); */ - outb(0x01, UART0_BASE + UART_IER); - - /* Set DTR and RTS active, enable interrupts */ - outb(inb (UART0_BASE + UART_MCR) | 0x0b, UART0_BASE + UART_MCR); - - /* Setup UART FIFO: RX trigger level: 1 byte, Enable FIFO */ - outb( /*(1 << 6) |*/ 1, UART0_BASE + UART_FCR); - - serial_buffer_active = 1; -} - -void serial_buffered_putc (const char c) -{ - int i; - /* Wait for CTS */ -#if defined(CONFIG_HW_WATCHDOG) - while (!(inb (UART0_BASE + UART_MSR) & 0x10)) - WATCHDOG_RESET (); -#else - if (buf_info.cts) { - for (i=0;i<1000;i++) { - if ((inb (UART0_BASE + UART_MSR) & 0x10)) { - break; - } - } - if (i!=1000) { - buf_info.cts = 0; - } - } else { - if ((inb (UART0_BASE + UART_MSR) & 0x10)) { - buf_info.cts = 1; - } - } - -#endif - serial_putc (c); -} - -void serial_buffered_puts(const char *s) -{ - serial_puts (s); -} - -int serial_buffered_getc(void) -{ - int space; - int c; - int rx_get = buf_info.rx_get; - int rx_put; - -#if defined(CONFIG_HW_WATCHDOG) - while (rx_get == buf_info.rx_put) - WATCHDOG_RESET (); -#else - while (rx_get == buf_info.rx_put); -#endif - c = buf_info.rx_buffer[rx_get++]; - if (rx_get == CONFIG_SERIAL_SOFTWARE_FIFO) { - rx_get = 0; - } - buf_info.rx_get = rx_get; - - rx_put = buf_info.rx_put; - if (rx_get <= rx_put) { - space = CONFIG_SERIAL_SOFTWARE_FIFO - (rx_put - rx_get); - } else { - space = rx_get - rx_put; - } - if (space > CONFIG_SERIAL_SOFTWARE_FIFO / 2) { - /* Start flow by setting RTS active */ - outb(inb (UART0_BASE + UART_MCR) | 0x02, UART0_BASE + UART_MCR); - } - - return c; -} - -int serial_buffered_tstc(void) -{ - return (buf_info.rx_get != buf_info.rx_put) ? 1 : 0; -} - -#endif /* CONFIG_SERIAL_SOFTWARE_FIFO */ - - -#if defined(CONFIG_CMD_KGDB) -/* - AS HARNOIS : according to CONFIG_KGDB_SER_INDEX kgdb uses serial port - number 0 or number 1 - - if CONFIG_KGDB_SER_INDEX = 1 => serial port number 0 : - configuration has been already done - - if CONFIG_KGDB_SER_INDEX = 2 => serial port number 1 : - configure port 1 for serial I/O with rate = CONFIG_KGDB_BAUDRATE -*/ -#if (CONFIG_KGDB_SER_INDEX & 2) -void kgdb_serial_init(void) -{ - volatile char val; - bdiv = serial_div (CONFIG_KGDB_BAUDRATE); - - /* - * Init onboard 16550 UART - */ - outb(0x80, UART1_BASE + UART_LCR); /* set DLAB bit */ - outb((bdiv & 0xff), UART1_BASE + UART_DLL); /* set divisor for 9600 baud */ - outb((bdiv >> 8 ), UART1_BASE + UART_DLM); /* set divisor for 9600 baud */ - outb(0x03, UART1_BASE + UART_LCR); /* line control 8 bits no parity */ - outb(0x00, UART1_BASE + UART_FCR); /* disable FIFO */ - outb(0x00, UART1_BASE + UART_MCR); /* no modem control DTR RTS */ - val = inb(UART1_BASE + UART_LSR); /* clear line status */ - val = inb(UART1_BASE + UART_RBR); /* read receive buffer */ - outb(0x00, UART1_BASE + UART_SCR); /* set scratchpad */ - outb(0x00, UART1_BASE + UART_IER); /* set interrupt enable reg */ -} - - -void putDebugChar(const char c) -{ - if (c == '\n') - serial_putc ('\r'); - - outb(c, UART1_BASE + UART_THR); /* put character out */ - - /* check THRE bit, wait for transfer done */ - while ((inb(UART1_BASE + UART_LSR) & 0x20) != 0x20); -} - - -void putDebugStr(const char *s) -{ - while (*s) { - serial_putc(*s++); - } -} - - -int getDebugChar(void) -{ - unsigned char status = 0; - - while (1) { - status = inb(UART1_BASE + UART_LSR); - if ((status & asyncLSRDataReady1) != 0x0) { - break; - } - if ((status & ( asyncLSRFramingError1 | - asyncLSROverrunError1 | - asyncLSRParityError1 | - asyncLSRBreakInterrupt1 )) != 0) { - outb(asyncLSRFramingError1 | - asyncLSROverrunError1 | - asyncLSRParityError1 | - asyncLSRBreakInterrupt1, UART1_BASE + UART_LSR); - } - } - return (0x000000ff & (int) inb(UART1_BASE)); -} - - -void kgdb_interruptible(int yes) -{ - return; -} - -#else /* ! (CONFIG_KGDB_SER_INDEX & 2) */ - -void kgdb_serial_init(void) -{ - serial_printf ("[on serial] "); -} - -void putDebugChar(int c) -{ - serial_putc (c); -} - -void putDebugStr(const char *str) -{ - serial_puts (str); -} - -int getDebugChar(void) -{ - return serial_getc (); -} - -void kgdb_interruptible(int yes) -{ - return; -} -#endif /* (CONFIG_KGDB_SER_INDEX & 2) */ -#endif diff --git a/arch/i386/cpu/start.S b/arch/i386/cpu/start.S index 25d32e658e6..7def8def8b1 100644 --- a/arch/i386/cpu/start.S +++ b/arch/i386/cpu/start.S @@ -33,7 +33,27 @@ .type _start, @function .globl _i386boot_start _i386boot_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 $0x60000000,%eax + movl %eax, %cr0 + wbinvd + + /* Tell 32-bit code it is being entered from an in-RAM copy */ + movw $0x0000, %bx _start: + /* This is the 32-bit cold-reset entry point */ + movl $0x18,%eax /* Load our segement registes, the * gdt have already been loaded by start16.S */ movw %ax,%fs @@ -42,6 +62,18 @@ _start: movw %ax,%es movw %ax,%ss + /* Clear the interupt vectors */ + lidt blank_idt_ptr + + /* + * Skip low-level board and memory initialization if not starting + * from cold-reset. This allows us to do a fail safe boot-strap + * into a new build of U-Boot from a known-good boot flash + */ + movw $0x0001, %ax + cmpw %ax, %bx + jne mem_init_ret + /* We call a few functions in the board support package * since we have no stack yet we'll have to use %ebp * to store the return address */ @@ -63,6 +95,58 @@ early_board_init_ret: jmp mem_init mem_init_ret: + /* fetch memory size (into %eax) */ + mov $get_mem_size_ret, %ebp + jmp get_mem_size +get_mem_size_ret: + + /* + * We are now in 'Flat Protected Mode' and we know how much memory + * the board has. The (temporary) Global Descriptor Table is not + * in a 'Safe' place (it is either in Flash which can be erased or + * reprogrammed or in a fail-safe boot-strap image which could be + * over-written). + * + * Move the final gdt to a safe place (top of RAM) and load it. + * This is not a trivial excercise - the lgdt instruction does not + * have a register operand (memory only) and we may well be + * running from Flash, so self modifying code will not work here. + * To overcome this, we copy a stub into upper memory along with + * the GDT. + */ + + /* Reduce upper memory limit by (Stub + GDT Pointer + GDT) */ + subl $(end_gdt_setup - start_gdt_setup), %eax + + /* Copy the GDT and Stub */ + movl $start_gdt_setup, %esi + movl %eax, %edi + movl $(end_gdt_setup - start_gdt_setup), %ecx + shrl $2, %ecx + cld + rep movsl + + /* write the lgdt 'parameter' */ + subl $(jmp_instr - start_gdt_setup - 4), %ebp + addl %eax, %ebp + movl $(gdt_ptr - start_gdt_setup), %ebx + addl %eax, %ebx + movl %ebx, (%ebp) + + /* write the gdt address into the pointer */ + movl $(gdt_addr - start_gdt_setup), %ebp + addl %eax, %ebp + movl $(gdt - start_gdt_setup), %ebx + addl %eax, %ebx + movl %ebx, (%ebp) + + /* Save the return address */ + movl $load_gdt_ret, %ebp + + /* Load the new (safe) Global Descriptor Table */ + jmp *%eax + +load_gdt_ret: /* Check we have enough memory for stack */ movl $CONFIG_SYS_STACK_SIZE, %ecx cmpl %ecx, %eax @@ -133,3 +217,56 @@ stack_ok: die: hlt jmp die hlt + +blank_idt_ptr: + .word 0 /* limit */ + .long 0 /* base */ + +.align 4 +start_gdt_setup: + lgdt gdt_ptr +jmp_instr: + jmp *%ebp + +.align 4 +gdt_ptr: + .word 0x30 /* limit (48 bytes = 6 GDT entries) */ +gdt_addr: + .long gdt /* base */ + + /* The GDT table ... + * + * Selector Type + * 0x00 NULL + * 0x08 Unused + * 0x10 32bit code + * 0x18 32bit data/stack + * 0x20 16bit code + * 0x28 16bit data/stack + */ + +.align 4 +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) */ + + .word 0xFFFF /* 64kb */ + .word 0 /* base address = 0 */ + .word 0x9b00 /* data read/write */ + .word 0x0010 /* granularity = 1 (+5th nibble of limit) */ + + .word 0xFFFF /* 64kb */ + .word 0 /* base address = 0 */ + .word 0x9300 /* data read/write */ + .word 0x0010 /* granularity = 1 (+5th nibble of limit) */ +end_gdt_setup: diff --git a/arch/i386/cpu/start16.S b/arch/i386/cpu/start16.S index 1ebb6bc8b63..3e8b2cc5c4f 100644 --- a/arch/i386/cpu/start16.S +++ b/arch/i386/cpu/start16.S @@ -44,11 +44,9 @@ board_init16_ret: movl %eax, %cr0 wbinvd - /* load the descriptor tables */ -o32 cs lidt idt_ptr + /* load the temporary Global Descriptor Table */ o32 cs lgdt gdt_ptr - /* Now, we enter protected mode */ movl %cr0, %eax orl $1,%eax @@ -57,6 +55,8 @@ o32 cs lgdt gdt_ptr /* Flush the prefetch queue */ jmp ff ff: + /* Tell 32-bit code it is being entered from hard-reset */ + movw $0x0001, %bx /* Finally jump to the 32bit initialization code */ movw $code32start, %ax @@ -68,12 +68,13 @@ 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 0x30 /* limit (48 bytes = 6 GDT entries) */ + .word 0x20 /* limit (32 bytes = 4 GDT entries) */ .long BOOT_SEG + gdt /* base */ /* The GDT table ... @@ -83,8 +84,6 @@ gdt_ptr: * 0x08 Unused * 0x10 32bit code * 0x18 32bit data/stack - * 0x20 16bit code - * 0x28 16bit data/stack */ gdt: @@ -100,13 +99,3 @@ gdt: .word 0x0 /* base address = 0 */ .word 0x9300 /* data read/write */ .word 0x00CF /* granularity = 4096, 386 (+5th nibble of limit) */ - - .word 0xFFFF /* 64kb */ - .word 0 /* base address = 0 */ - .word 0x9b00 /* data read/write */ - .word 0x0010 /* granularity = 1 (+5th nibble of limit) */ - - .word 0xFFFF /* 64kb */ - .word 0 /* base address = 0 */ - .word 0x9300 /* data read/write */ - .word 0x0010 /* granularity = 1 (+5th nibble of limit) */ |