diff options
author | Peter Tyser <ptyser@xes-inc.com> | 2010-04-12 22:28:17 -0500 |
---|---|---|
committer | Wolfgang Denk <wd@denx.de> | 2010-04-13 09:13:26 +0200 |
commit | e9a882803eb59f482ca4aa6ffd6fa21e4c53d618 (patch) | |
tree | 4ababcaa28c6ba75dff4a1fc362a1fe01fb232dc /arch/i386 | |
parent | 6260fb0458d94c83aa5b180745b1946c0c94d364 (diff) |
i386: Move cpu/i386/* to arch/i386/cpu/*
Signed-off-by: Peter Tyser <ptyser@xes-inc.com>
Diffstat (limited to 'arch/i386')
-rw-r--r-- | arch/i386/cpu/Makefile | 50 | ||||
-rw-r--r-- | arch/i386/cpu/config.mk | 26 | ||||
-rw-r--r-- | arch/i386/cpu/cpu.c | 92 | ||||
-rw-r--r-- | arch/i386/cpu/interrupts.c | 501 | ||||
-rw-r--r-- | arch/i386/cpu/resetvec.S | 37 | ||||
-rw-r--r-- | arch/i386/cpu/sc520/Makefile | 56 | ||||
-rw-r--r-- | arch/i386/cpu/sc520/sc520.c | 198 | ||||
-rw-r--r-- | arch/i386/cpu/sc520/sc520_asm.S | 581 | ||||
-rw-r--r-- | arch/i386/cpu/sc520/sc520_pci.c | 171 | ||||
-rw-r--r-- | arch/i386/cpu/sc520/sc520_ssi.c | 94 | ||||
-rw-r--r-- | arch/i386/cpu/sc520/sc520_timer.c | 84 | ||||
-rw-r--r-- | arch/i386/cpu/serial.c | 506 | ||||
-rw-r--r-- | arch/i386/cpu/start.S | 135 | ||||
-rw-r--r-- | arch/i386/cpu/start16.S | 112 | ||||
-rw-r--r-- | arch/i386/include/asm/interrupt.h | 2 | ||||
-rw-r--r-- | arch/i386/include/asm/u-boot-i386.h | 2 |
16 files changed, 2645 insertions, 2 deletions
diff --git a/arch/i386/cpu/Makefile b/arch/i386/cpu/Makefile new file mode 100644 index 00000000000..c658c6e4591 --- /dev/null +++ b/arch/i386/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).a + +START = start.o start16.o resetvec.o +COBJS = serial.o 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) + $(AR) $(ARFLAGS) $@ $(OBJS) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/arch/i386/cpu/config.mk b/arch/i386/cpu/config.mk new file mode 100644 index 00000000000..16a160d2f36 --- /dev/null +++ b/arch/i386/cpu/config.mk @@ -0,0 +1,26 @@ +# +# (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 +# + +PLATFORM_RELFLAGS += + +PLATFORM_CPPFLAGS += -march=i386 -Werror diff --git a/arch/i386/cpu/cpu.c b/arch/i386/cpu/cpu.c new file mode 100644 index 00000000000..3010519e746 --- /dev/null +++ b/arch/i386/cpu/cpu.c @@ -0,0 +1,92 @@ +/* + * (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 + */ + +/* + * CPU specific code + */ + +#include <common.h> +#include <command.h> +#include <asm/interrupt.h> + +int cpu_init_f(void) +{ + /* initialize FPU, reset EM, set MP and NE */ + asm ("fninit\n" \ + "movl %cr0, %eax\n" \ + "andl $~0x4, %eax\n" \ + "orl $0x22, %eax\n" \ + "movl %eax, %cr0\n" ); + + return 0; +} + +int cpu_init_r(void) +{ + /* Initialize core interrupt and exception functionality of CPU */ + cpu_init_interrupts (); + return 0; +} + +int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + printf ("resetting ...\n"); + udelay(50000); /* wait 50 ms */ + disable_interrupts(); + reset_cpu(0); + + /*NOTREACHED*/ + return 0; +} + +void flush_cache (unsigned long dummy1, unsigned long dummy2) +{ + asm("wbinvd\n"); + return; +} + +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 i386 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/i386/cpu/interrupts.c b/arch/i386/cpu/interrupts.c new file mode 100644 index 00000000000..4b574371930 --- /dev/null +++ b/arch/i386/cpu/interrupts.c @@ -0,0 +1,501 @@ +/* + * (C) Copyright 2008 + * 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/interrupt.h> + +#define DECLARE_INTERRUPT(x) \ + ".globl irq_"#x"\n" \ + ".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" + +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&0x200); /* IE flags is bit 9 */ +} + +/* IRQ Low-Level Service Routine */ +__isr__ irq_llsr(int ip, int seg, int irq) +{ + /* + * 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 (irq) { + case 0x00: + printf("Divide Error (Division by zero) at %04x:%08x\n", seg, ip); + while(1); + break; + case 0x01: + printf("Debug Interrupt (Single step) at %04x:%08x\n", seg, ip); + break; + case 0x02: + printf("NMI Interrupt at %04x:%08x\n", seg, ip); + break; + case 0x03: + printf("Breakpoint at %04x:%08x\n", seg, ip); + break; + case 0x04: + printf("Overflow at %04x:%08x\n", seg, ip); + while(1); + break; + case 0x05: + printf("BOUND Range Exceeded at %04x:%08x\n", seg, ip); + while(1); + break; + case 0x06: + printf("Invalid Opcode (UnDefined Opcode) at %04x:%08x\n", seg, ip); + while(1); + break; + case 0x07: + printf("Device Not Available (No Math Coprocessor) at %04x:%08x\n", seg, ip); + while(1); + break; + case 0x08: + printf("Double fault at %04x:%08x\n", seg, ip); + while(1); + break; + case 0x09: + printf("Co-processor segment overrun at %04x:%08x\n", seg, ip); + while(1); + break; + case 0x0a: + printf("Invalid TSS at %04x:%08x\n", seg, ip); + break; + case 0x0b: + printf("Segment Not Present at %04x:%08x\n", seg, ip); + while(1); + break; + case 0x0c: + printf("Stack Segment Fault at %04x:%08x\n", seg, ip); + while(1); + break; + case 0x0d: + printf("General Protection at %04x:%08x\n", seg, ip); + break; + case 0x0e: + printf("Page fault at %04x:%08x\n", seg, ip); + while(1); + break; + case 0x0f: + printf("Floating-Point Error (Math Fault) at %04x:%08x\n", seg, ip); + break; + case 0x10: + printf("Alignment check at %04x:%08x\n", seg, ip); + break; + case 0x11: + printf("Machine Check at %04x:%08x\n", seg, ip); + break; + case 0x12: + printf("SIMD Floating-Point Exception at %04x:%08x\n", seg, ip); + 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 %d at %04x:%08x\n", irq, seg, ip); + break; + + default: + /* Hardware or User IRQ */ + do_irq(irq); + } +} + +/* + * 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 + * 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. + */ +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" \ + "call irq_llsr\n" \ + "popl %eax\n" \ + "popl %eax\n" \ + "popl %eax\n" \ + "popa\n" \ + "leave\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/i386/cpu/resetvec.S b/arch/i386/cpu/resetvec.S new file mode 100644 index 00000000000..d9222dd2fc6 --- /dev/null +++ b/arch/i386/cpu/resetvec.S @@ -0,0 +1,37 @@ +/* + * U-boot - i386 Startup Code + * + * Copyright (c) 2002 Omicron Ceti AB, Daniel Engström <denaiel@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/i386/cpu/sc520/Makefile b/arch/i386/cpu/sc520/Makefile new file mode 100644 index 00000000000..87835b2c20d --- /dev/null +++ b/arch/i386/cpu/sc520/Makefile @@ -0,0 +1,56 @@ +# +# (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).a + +COBJS-$(CONFIG_SYS_SC520) += sc520.o +COBJS-$(CONFIG_SYS_SC520_SSI) += sc520_ssi.o +COBJS-$(CONFIG_SYS_SC520_TIMER) += sc520_timer.o +COBJS-$(CONFIG_PCI) += sc520_pci.o + +SOBJS-$(CONFIG_SYS_SC520) += sc520_asm.o + +SRCS := $(SOBJS-y:.o=.S) $(COBJS-y:.o=.c) +OBJS := $(addprefix $(obj),$(SOBJS-y) $(COBJS-y)) + +all: $(obj).depend $(LIB) + +$(LIB): $(OBJS) + $(AR) $(ARFLAGS) $@ $(OBJS) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +#########################################################################
\ No newline at end of file diff --git a/arch/i386/cpu/sc520/sc520.c b/arch/i386/cpu/sc520/sc520.c new file mode 100644 index 00000000000..4b566a75ccd --- /dev/null +++ b/arch/i386/cpu/sc520/sc520.c @@ -0,0 +1,198 @@ +/* + * (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 + */ + +/* stuff specific for the sc520, + * but idependent of implementation */ + +#include <common.h> +#include <asm/io.h> +#include <asm/ic/sc520.h> + +DECLARE_GLOBAL_DATA_PTR; + +/* + * utility functions for boards based on the AMD sc520 + * + * void init_sc520(void) + * unsigned long init_sc520_dram(void) + */ + +volatile sc520_mmcr_t *sc520_mmcr = (sc520_mmcr_t *)0xfffef000; + +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; + + /* first set the timer pin mapping */ + sc520_mmcr->clksel = 0x72; /* no clock frequency selected, use 1.1892MHz */ + + /* enable PCI bus arbitrer */ + sc520_mmcr->sysarbctl = 0x02; /* enable concurrent mode */ + + sc520_mmcr->sysarbmenb = 0x1f; /* enable external grants */ + sc520_mmcr->hbctl = 0x04; /* enable posted-writes */ + + if (CONFIG_SYS_SC520_HIGH_SPEED) { + sc520_mmcr->cpuctl = 0x02; /* 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 */ + printf("## CPU Speed set to 100MHz\n"); + 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"); + + /* turn on the SDRAM write buffer */ + sc520_mmcr->dbctl = 0x11; + + /* turn on the cache and disable write through */ + asm("movl %%cr0, %%eax\n" + "andl $0x9fffffff, %%eax\n" + "movl %%eax, %%cr0\n" : : : "eax"); +} + +unsigned long init_sc520_dram(void) +{ + bd_t *bd = gd->bd; + + 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, + * after we are running a stack in RAM, we have troubles. Besides, + * these refresh and delay values are better ? simply specified + * outright in the include/configs/{cfg} file since the HW designer + * simply dictates it. + */ +#else + int val; + + int cas_precharge_delay = CONFIG_SYS_SDRAM_PRECHARGE_DELAY; + int refresh_rate = CONFIG_SYS_SDRAM_REFRESH_RATE; + int ras_cas_delay = CONFIG_SYS_SDRAM_RAS_CAS_DELAY; + + /* set SDRAM speed here */ + + refresh_rate/=78; + if (refresh_rate<=1) { + val = 0; /* 7.8us */ + } else if (refresh_rate==2) { + val = 1; /* 15.6us */ + } else if (refresh_rate==3 || refresh_rate==4) { + val = 2; /* 31.2us */ + } else { + val = 3; /* 62.4us */ + } + + sc520_mmcr->drcctl = (sc520_mmcr->drcctl & 0xcf) | (val<<4); + + val = sc520_mmcr->drctmctl & 0xf0; + + if (cas_precharge_delay==3) { + val |= 0x04; /* 3T */ + } else if (cas_precharge_delay==4) { + val |= 0x08; /* 4T */ + } else if (cas_precharge_delay>4) { + val |= 0x0c; + } + + if (ras_cas_delay > 3) { + val |= 2; + } else { + val |= 1; + } + sc520_mmcr->drctmctl = val; +#endif + + /* We read-back the configuration of the dram + * controller that the assembly code wrote */ + dram_ctrl = sc520_mmcr->drcbendadr; + + bd->bi_dram[0].start = 0; + if (dram_ctrl & 0x80) { + /* bank 0 enabled */ + dram_present = bd->bi_dram[1].start = (dram_ctrl & 0x7f) << 22; + bd->bi_dram[0].size = bd->bi_dram[1].start; + + } else { + bd->bi_dram[0].size = 0; + bd->bi_dram[1].start = bd->bi_dram[0].start; + } + + if (dram_ctrl & 0x8000) { + /* bank 1 enabled */ + dram_present = bd->bi_dram[2].start = (dram_ctrl & 0x7f00) << 14; + bd->bi_dram[1].size = bd->bi_dram[2].start - bd->bi_dram[1].start; + } else { + bd->bi_dram[1].size = 0; + bd->bi_dram[2].start = bd->bi_dram[1].start; + } + + if (dram_ctrl & 0x800000) { + /* bank 2 enabled */ + dram_present = bd->bi_dram[3].start = (dram_ctrl & 0x7f0000) << 6; + bd->bi_dram[2].size = bd->bi_dram[3].start - bd->bi_dram[2].start; + } else { + bd->bi_dram[2].size = 0; + bd->bi_dram[3].start = bd->bi_dram[2].start; + } + + if (dram_ctrl & 0x80000000) { + /* bank 3 enabled */ + dram_present = (dram_ctrl & 0x7f000000) >> 2; + bd->bi_dram[3].size = dram_present - bd->bi_dram[3].start; + } else { + bd->bi_dram[3].size = 0; + } + + +#if 0 + printf("Configured %d bytes of dram\n", dram_present); +#endif + gd->ram_size = dram_present; + + return dram_present; +} + +#ifdef CONFIG_SYS_SC520_RESET +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; + + /* NOTREACHED */ +} +#endif diff --git a/arch/i386/cpu/sc520/sc520_asm.S b/arch/i386/cpu/sc520/sc520_asm.S new file mode 100644 index 00000000000..2042d9bfcf8 --- /dev/null +++ b/arch/i386/cpu/sc520/sc520_asm.S @@ -0,0 +1,581 @@ +/* + * (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 + */ + +/* This file is largely based on code obtned from AMD. AMD's original + * 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 + * ============================================================================ + */ + + +/******************************************************************************* + * AUTHOR : Buddy Fey - Original. + ******************************************************************************* + */ + + +/******************************************************************************* + * FUNCTIONAL DESCRIPTION: + * This routine is called to autodetect the geometry of the DRAM. + * + * This routine is called to determine the number of column bits for the DRAM + * devices in this external bank. This routine assumes that the external bank + * has been configured for an 11-bit column and for 4 internal banks. This gives + * us the maximum address reach in memory. By writing a test value to the max + * address and locating where it aliases to, we can determine the number of valid + * column bits. + * + * This routine is called to determine the number of internal banks each DRAM + * device has. The external bank (under test) is configured for maximum reach + * with 11-bit columns and 4 internal banks. This routine will write to a max + * address (BA1 and BA0 = 1) and then read from an address with BA1=0 to see if + * that column is a "don't care". If BA1 does not affect write/read of data, + * then this device has only 2 internal banks. + * + * This routine is called to determine the ending address for this external + * bank of SDRAM. We write to a max address with a data value and then disable + * row address bits looking for "don't care" locations. Each "don't care" bit + * represents a dividing of the maximum density (128M) by 2. By dividing the + * maximum of 32 4M chunks in an external bank down by all the "don't care" bits + * determined during sizing, we set the proper density. + * + * WARNINGS. + * bp must be preserved because it is used for return linkage. + * + * EXIT + * nothing returned - but the memory subsystem is enabled + ******************************************************************************* + */ + +#include <config.h> + +.section .text +.equ DRCCTL, 0x0fffef010 /* DRAM control register */ +.equ DRCTMCTL, 0x0fffef012 /* DRAM timing control register */ +.equ DRCCFG, 0x0fffef014 /* DRAM bank configuration register */ +.equ DRCBENDADR, 0x0fffef018 /* DRAM bank ending address register */ +.equ ECCCTL, 0x0fffef020 /* DRAM ECC control register */ +.equ ECCINT, 0x0fffefd18 /* DRAM ECC nmi-INT mapping */ +.equ DBCTL, 0x0fffef040 /* DRAM buffer control register */ + +.equ CACHELINESZ, 0x00000010 /* size of our cache line (read buffer) */ +.equ COL11_ADR, 0x0e001e00 /* 11 col addrs */ +.equ COL10_ADR, 0x0e000e00 /* 10 col addrs */ +.equ COL09_ADR, 0x0e000600 /* 9 col addrs */ +.equ COL08_ADR, 0x0e000200 /* 8 col addrs */ +.equ ROW14_ADR, 0x0f000000 /* 14 row addrs */ +.equ ROW13_ADR, 0x07000000 /* 13 row addrs */ +.equ ROW12_ADR, 0x03000000 /* 12 row addrs */ +.equ ROW11_ADR, 0x01000000 /* 11 row addrs/also bank switch */ +.equ ROW10_ADR, 0x00000000 /* 10 row addrs/also bank switch */ +.equ COL11_DATA, 0x0b0b0b0b /* 11 col addrs */ +.equ COL10_DATA, 0x0a0a0a0a /* 10 col data */ +.equ COL09_DATA, 0x09090909 /* 9 col data */ +.equ COL08_DATA, 0x08080808 /* 8 col data */ +.equ ROW14_DATA, 0x3f3f3f3f /* 14 row data (MASK) */ +.equ ROW13_DATA, 0x1f1f1f1f /* 13 row data (MASK) */ +.equ ROW12_DATA, 0x0f0f0f0f /* 12 row data (MASK) */ +.equ ROW11_DATA, 0x07070707 /* 11 row data/also bank switch (MASK) */ +.equ ROW10_DATA, 0xaaaaaaaa /* 10 row data/also bank switch (MASK) */ + + + /* + * initialize dram controller registers + */ +.globl mem_init +mem_init: + xorw %ax,%ax + movl $DBCTL, %edi + movb %al, (%edi) /* disable write buffer */ + + movl $ECCCTL, %edi + movb %al, (%edi) /* disable ECC */ + + movl $DRCTMCTL, %edi + movb $0x1E,%al /* Set SDRAM timing for slowest */ + movb %al, (%edi) + + /* + * setup loop to do 4 external banks starting with bank 3 + */ + movl $0xff000000,%eax /* enable last bank and setup */ + movl $DRCBENDADR, %edi /* ending address register */ + movl %eax, (%edi) + + movl $DRCCFG, %edi /* setup */ + movw $0xbbbb,%ax /* dram config register for */ + movw %ax, (%edi) + + /* + * issue a NOP to all DRAMs + */ + movl $DRCCTL, %edi /* setup DRAM control register with */ + movb $0x1,%al /* Disable refresh,disable write buffer */ + movb %al, (%edi) + movl $CACHELINESZ, %esi /* just a dummy address to write for */ + movw %ax, (%esi) + /* + * delay for 100 usec? 200? + * ******this is a cludge for now ************* + */ + movw $100,%cx +sizdelay: + loop sizdelay /* we need 100 usec here */ + /***********************************************/ + + /* + * issue all banks precharge + */ + movb $0x2,%al /* All banks precharge */ + movb %al, (%edi) + movw %ax, (%esi) + + /* + * issue 2 auto refreshes to all banks + */ + movb $0x4,%al /* Auto refresh cmd */ + movb %al, (%edi) + movw $2,%cx +refresh1: + movw %ax, (%esi) + loop refresh1 + + /* + * issue LOAD MODE REGISTER command + */ + movb $0x3,%al /* Load mode register cmd */ + movb %al, (%edi) + movw %ax, (%esi) + + /* + * issue 8 more auto refreshes to all banks + */ + movb $0x4,%al /* Auto refresh cmd */ + movb %al, (%edi) + movw $8,%cx +refresh2: + movw %ax, (%esi) + loop refresh2 + + /* + * set control register to NORMAL mode + */ + movb $0x0,%al /* Normal mode value */ + movb %al, (%edi) + + /* + * size dram starting with external bank 3 moving to external bank 0 + */ + movl $0x3,%ecx /* start with external bank 3 */ + +nextbank: + + /* + * write col 11 wrap adr + */ + movl $COL11_ADR, %esi /* set address to max col (11) wrap addr */ + movl $COL11_DATA, %eax /* pattern for max supported columns(11) */ + movl %eax, (%esi) /* write max col pattern at max col adr */ + movl (%esi), %ebx /* optional read */ + cmpl %ebx,%eax /* to verify write */ + jnz bad_ram /* this ram is bad */ + /* + * write col 10 wrap adr + */ + + movl $COL10_ADR, %esi /* set address to 10 col wrap address */ + movl $COL10_DATA, %eax /* pattern for 10 col wrap */ + movl %eax, (%esi) /* write 10 col pattern @ 10 col wrap adr */ + movl (%esi), %ebx /* optional read */ + cmpl %ebx,%eax /* to verify write */ + jnz bad_ram /* this ram is bad */ + /* + * write col 9 wrap adr + */ + movl $COL09_ADR, %esi /* set address to 9 col wrap address */ + movl $COL09_DATA, %eax /* pattern for 9 col wrap */ + movl %eax, (%esi) /* write 9 col pattern @ 9 col wrap adr */ + movl (%esi), %ebx /* optional read */ + cmpl %ebx,%eax /* to verify write */ + jnz bad_ram /* this ram is bad */ + /* + * write col 8 wrap adr + */ + movl $COL08_ADR, %esi /* set address to min(8) col wrap address */ + movl $COL08_DATA, %eax /* pattern for min (8) col wrap */ + movl %eax, (%esi) /* write min col pattern @ min col adr */ + movl (%esi), %ebx /* optional read */ + cmpl %ebx,%eax /* to verify write */ + jnz bad_ram /* this ram is bad */ + /* + * write row 14 wrap adr + */ + movl $ROW14_ADR, %esi /* set address to max row (14) wrap addr */ + movl $ROW14_DATA, %eax /* pattern for max supported rows(14) */ + movl %eax, (%esi) /* write max row pattern at max row adr */ + movl (%esi), %ebx /* optional read */ + cmpl %ebx,%eax /* to verify write */ + jnz bad_ram /* this ram is bad */ + /* + * write row 13 wrap adr + */ + movl $ROW13_ADR, %esi /* set address to 13 row wrap address */ + movl $ROW13_DATA, %eax /* pattern for 13 row wrap */ + movl %eax, (%esi) /* write 13 row pattern @ 13 row wrap adr */ + movl (%esi), %ebx /* optional read */ + cmpl %ebx,%eax /* to verify write */ + jnz bad_ram /* this ram is bad */ + /* + * write row 12 wrap adr + */ + movl $ROW12_ADR, %esi /* set address to 12 row wrap address */ + movl $ROW12_DATA, %eax /* pattern for 12 row wrap */ + movl %eax, (%esi) /* write 12 row pattern @ 12 row wrap adr */ + movl (%esi), %ebx /* optional read */ + cmpl %ebx,%eax /* to verify write */ + jnz bad_ram /* this ram is bad */ + /* + * write row 11 wrap adr + */ + movl $ROW11_ADR, %edi /* set address to 11 row wrap address */ + movl $ROW11_DATA, %eax /* pattern for 11 row wrap */ + movl %eax, (%edi) /* write 11 row pattern @ 11 row wrap adr */ + movl (%edi), %ebx /* optional read */ + cmpl %ebx,%eax /* to verify write */ + jnz bad_ram /* this ram is bad */ + /* + * write row 10 wrap adr --- this write is really to determine number of banks + */ + movl $ROW10_ADR, %edi /* set address to 10 row wrap address */ + movl $ROW10_DATA, %eax /* pattern for 10 row wrap (AA) */ + movl %eax, (%edi) /* write 10 row pattern @ 10 row wrap adr */ + movl (%edi), %ebx /* optional read */ + cmpl %ebx,%eax /* to verify write */ + jnz bad_ram /* this ram is bad */ + /* + * read data @ row 12 wrap adr to determine * banks, + * and read data @ row 14 wrap adr to determine * 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, + */ + xorw %di,%di /* value for 2 banks in DI */ + movl (%esi), %ebx /* read from 12 row wrap to check banks + * (esi is setup from the write to row 12 wrap) */ + cmpl %ebx,%eax /* check for AA pattern (eax holds the aa pattern) */ + jz only2 /* if pattern == AA, we only have 2 banks */ + + /* 4 banks */ + + movw $8,%di /* value for 4 banks in DI (BNK_CNT bit) */ + cmpl $ROW11_DATA, %ebx /* only other legitimate values are 11 */ + jz only2 + cmpl $ROW12_DATA, %ebx /* and 12 */ + jnz bad_ram /* its bad if not 11 or 12! */ + + /* fall through */ +only2: + /* + * validate row mask + */ + movl $ROW14_ADR, %esi /* set address back to max row wrap addr */ + movl (%esi), %eax /* read actual number of rows @ row14 adr */ + + cmpl $ROW11_DATA, %eax /* row must be greater than 11 pattern */ + jb bad_ram + + cmpl $ROW14_DATA, %eax /* and row must be less than 14 pattern */ + ja bad_ram + + cmpb %ah,%al /* verify all 4 bytes of dword same */ + jnz bad_ram + movl %eax,%ebx + shrl $16,%ebx + cmpw %bx,%ax + jnz bad_ram + /* + * read col 11 wrap adr for real column data value + */ + movl $COL11_ADR, %esi /* set address to max col (11) wrap addr */ + movl (%esi), %eax /* read real col number at max col adr */ + /* + * validate column data + */ + cmpl $COL08_DATA, %eax /* col must be greater than 8 pattern */ + jb bad_ram + + cmpl $COL11_DATA, %eax /* and row must be less than 11 pattern */ + ja bad_ram + + subl $COL08_DATA, %eax /* normalize column data to zero */ + jc bad_ram + cmpb %ah,%al /* verify all 4 bytes of dword equal */ + jnz bad_ram + movl %eax,%edx + shrl $16,%edx + cmpw %dx,%ax + jnz bad_ram + /* + * merge bank and col data together + */ + addw %di,%dx /* merge of bank and col info in dl */ + /* + * fix ending addr mask based upon col info + */ + movb $3,%al + subb %dh,%al /* dh contains the overflow from the bank/col merge */ + movb %bl,%dh /* bl contains the row mask (aa, 07, 0f, 1f or 3f) */ + xchgw %cx,%ax /* cx = ax = 3 or 2 depending on 2 or 4 bank device */ + shrb %cl,%dh /* */ + incb %dh /* ending addr is 1 greater than real end */ + xchgw %cx,%ax /* cx is bank number again */ + /* + * issue all banks precharge + */ +bad_reint: + movl $DRCCTL, %esi /* setup DRAM control register with */ + movb $0x2,%al /* All banks precharge */ + movb %al, (%esi) + movl $CACHELINESZ, %esi /* address to init read buffer */ + movw %ax, (%esi) + + /* + * update ENDING ADDRESS REGISTER + */ + movl $DRCBENDADR, %edi /* DRAM ending address register */ + movl %ecx,%ebx + addl %ebx, %edi + movb %dh, (%edi) + /* + * update CONFIG REGISTER + */ + xorb %dh,%dh + movw $0x00f,%bx + movw %cx,%ax + shlw $2,%ax + xchgw %cx,%ax + shlw %cl,%dx + shlw %cl,%bx + notw %bx + xchgw %cx,%ax + movl $DRCCFG, %edi + mov (%edi), %ax + andw %bx,%ax + orw %dx,%ax + movw %ax, (%edi) + jcxz cleanup + + decw %cx + movl %ecx,%ebx + movl $DRCBENDADR, %edi /* DRAM ending address register */ + movb $0xff,%al + addl %ebx, %edi + movb %al, (%edi) + /* + * set control register to NORMAL mode + */ + movl $DRCCTL, %esi /* setup DRAM control register with */ + movb $0x0,%al /* Normal mode value */ + movb %al, (%esi) + movl $CACHELINESZ, %esi /* address to init read buffer */ + movw %ax, (%esi) + jmp nextbank + +cleanup: + movl $DRCBENDADR, %edi /* DRAM ending address register */ + movw $4,%cx + xorw %ax,%ax +cleanuplp: + movb (%edi), %al + orb %al,%al + jz emptybank + + addb %ah,%al + jns nottoomuch + + movb $0x7f,%al +nottoomuch: + movb %al,%ah + orb $0x80,%al + movb %al, (%edi) +emptybank: + incl %edi + loop cleanuplp + +#if defined CONFIG_SYS_SDRAM_DRCTMCTL + /* just have your hardware desinger _GIVE_ you what you need here! */ + movl $DRCTMCTL, %edi + movb $CONFIG_SYS_SDRAM_DRCTMCTL,%al + movb (%edi), %al +#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 + * when we run from the RAM */ + movl $DRCTMCTL, %edi /* DRAM timing register */ + movb (%edi), %al +#ifdef CONFIG_SYS_SDRAM_CAS_LATENCY_2T + andb $0xef, %al +#endif +#ifdef CONFIG_SYS_SDRAM_CAS_LATENCY_3T + orb $0x10, %al +#endif + movb %al, (%edi) +#endif +#endif + movl $DRCCTL, %edi /* DRAM Control register */ + movb $0x3,%al /* Load mode register cmd */ + movb %al, (%edi) + movw %ax, (%esi) + + + movl $DRCCTL, %edi /* DRAM Control register */ + movb $0x18,%al /* Enable refresh and NORMAL mode */ + movb %al, (%edi) + + jmp dram_done + +bad_ram: + xorl %edx,%edx + xorl %edi,%edi + jmp bad_reint + +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 + + +done: + movl %ebx, %eax + +#if CONFIG_SYS_SDRAM_ECC_ENABLE + /* 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 $1, %ecx + andl %ecx,%ecx + jz set_ecc + shll $1, %edi + jmp memtest0 + +set_ecc: + /* clear all ram with a memset */ + movl %eax, %ecx + xorl %esi, %esi + xorl %edi, %edi + xorl %eax, %eax + shrl $2, %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 + mov $0x10, %al + movb %al, (%edi) + /* Turn on ECC */ + movl $ECCCTL, %edi + mov $0x05, %al + movb %al, (%edi) +#endif +out: + movl %ebx, %eax + jmp *%ebp diff --git a/arch/i386/cpu/sc520/sc520_pci.c b/arch/i386/cpu/sc520/sc520_pci.c new file mode 100644 index 00000000000..f446c6d5927 --- /dev/null +++ b/arch/i386/cpu/sc520/sc520_pci.c @@ -0,0 +1,171 @@ +/* + * (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 + */ + +/* stuff specific for the sc520, but independent of implementation */ + +#include <common.h> +#include <pci.h> +#include <asm/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; + +# if 1 + printf("set_irq(): map INT%c to IRQ%d\n", pci_pin + 'A', irq); +#endif + 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 (sc520_mmcr->pci_int_map[i] == sc520_irq[irq].priority) + sc520_mmcr->pci_int_map[i] = SC520_IRQ_DISABLED; + } + + /* 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; + } + + /* 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; + + + if (pci_pin < 4) { + /* PCI INTA-INTD */ + /* route the interrupt */ + sc520_mmcr->pci_int_map[pci_pin] = sc520_irq[irq].priority; + } else { + /* GPIRQ0-GPIRQ10 used for additional PCI INTS */ + sc520_mmcr->gp_int_map[pci_pin - 4] = sc520_irq[irq].priority; + + /* also set the polarity in this case */ + sc520_mmcr->intpinpol = sc520_mmcr->intpinpol | (1 << (pci_pin-4)); + } + + /* 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; + + /* 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; + + 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/i386/cpu/sc520/sc520_ssi.c b/arch/i386/cpu/sc520/sc520_ssi.c new file mode 100644 index 00000000000..8dbe17aa60e --- /dev/null +++ b/arch/i386/cpu/sc520/sc520_ssi.c @@ -0,0 +1,94 @@ +/* + * (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 + */ + +/* stuff specific for the sc520, but independent of implementation */ + +#include <common.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; + } + + sc520_mmcr->ssictl = temp; + + 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); + + return 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; +} + +u8 ssi_rx_byte(void) +{ + while (sc520_mmcr->ssista & SSISTA_BSY); + sc520_mmcr->ssicmd = SSICMD_CMD_SEL_RCV; + while (sc520_mmcr->ssista & SSISTA_BSY); + + return sc520_mmcr->ssircv; +} diff --git a/arch/i386/cpu/sc520/sc520_timer.c b/arch/i386/cpu/sc520/sc520_timer.c new file mode 100644 index 00000000000..93b5b555c30 --- /dev/null +++ b/arch/i386/cpu/sc520/sc520_timer.c @@ -0,0 +1,84 @@ +/* + * (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 + */ + +/* stuff specific for the sc520, but independent of implementation */ + +#include <common.h> +#include <asm/interrupt.h> +#include <asm/ic/sc520.h> + +void sc520_timer_isr(void) +{ + /* Ack the GP Timer Interrupt */ + sc520_mmcr->gptmrsta = 0x02; +} + +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 */ + sc520_mmcr->gp_tmr_int_map[1] = 0x01; + + /* Disable GP Timers 1 & 2 - Allow configuration writes */ + sc520_mmcr->gptmr1ctl = 0x4000; + sc520_mmcr->gptmr2ctl = 0x4000; + + /* Reset GP Timers 1 & 2 */ + sc520_mmcr->gptmr1cnt = 0x0000; + sc520_mmcr->gptmr2cnt = 0x0000; + + /* Setup GP Timer 2 as a 100kHz (10us) prescaler */ + sc520_mmcr->gptmr2maxcmpa = 83; + sc520_mmcr->gptmr2ctl = 0xc001; + + /* Setup GP Timer 1 as a 1000 Hz (1ms) interrupt generator */ + sc520_mmcr->gptmr1maxcmpa = 100; + sc520_mmcr->gptmr1ctl = 0xe009; + + unmask_irq (0); + + /* Clear the GP Timer 1 status register to get the show rolling*/ + sc520_mmcr->gptmrsta = 0x02; + + return 0; +} + +void __udelay(unsigned long usec) +{ + int m = 0; + long u; + long temp; + + temp = sc520_mmcr->swtmrmilli; + temp = sc520_mmcr->swtmrmicro; + + do { + m += sc520_mmcr->swtmrmilli; + u = sc520_mmcr->swtmrmicro + (m * 1000); + } while (u < usec); +} diff --git a/arch/i386/cpu/serial.c b/arch/i386/cpu/serial.c new file mode 100644 index 00000000000..e7025a3cdc0 --- /dev/null +++ b/arch/i386/cpu/serial.c @@ -0,0 +1,506 @@ +/* + * (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 new file mode 100644 index 00000000000..25d32e658e6 --- /dev/null +++ b/arch/i386/cpu/start.S @@ -0,0 +1,135 @@ +/* + * U-boot - i386 Startup Code + * + * Copyright (c) 2002 Omicron Ceti AB, Daniel Engström <denaiel@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> + + +.section .text +.code32 +.globl _start +.type _start, @function +.globl _i386boot_start +_i386boot_start: +_start: + movl $0x18,%eax /* Load our segement registes, the + * gdt have already been loaded by start16.S */ + movw %ax,%fs + movw %ax,%ds + movw %ax,%gs + movw %ax,%es + movw %ax,%ss + + /* 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 */ + + /* Early platform init (setup gpio, etc ) */ + mov $early_board_init_ret, %ebp + jmp early_board_init +early_board_init_ret: + + /* The __port80 entry-point should be usabe by now */ + /* so we try to indicate progress */ + movw $0x01, %ax + movl $.progress0, %ebp + jmp show_boot_progress_asm +.progress0: + + /* size memory */ + mov $mem_init_ret, %ebp + jmp mem_init +mem_init_ret: + + /* Check we have enough memory for stack */ + movl $CONFIG_SYS_STACK_SIZE, %ecx + cmpl %ecx, %eax + jae mem_ok + + /* indicate (lack of) progress */ + movw $0x81, %ax + movl $.progress0a, %ebp + jmp show_boot_progress_asm +.progress0a: + jmp die +mem_ok: + /* Set stack pointer to upper memory limit*/ + movl %eax, %esp + + /* indicate progress */ + movw $0x02, %ax + movl $.progress1, %ebp + jmp show_boot_progress_asm +.progress1: + + /* Test the stack */ + pushl $0 + popl %eax + cmpl $0, %eax + jne no_stack + push $0x55aa55aa + popl %ebx + cmpl $0x55aa55aa, %ebx + je stack_ok + +no_stack: + /* indicate (lack of) progress */ + movw $0x82, %ax + movl $.progress1a, %ebp + jmp show_boot_progress_asm +.progress1a: + jmp die + + +stack_ok: + /* indicate progress */ + movw $0x03, %ax + movl $.progress2, %ebp + jmp show_boot_progress_asm +.progress2: + + wbinvd + + /* Get upper memory limit */ + movl %esp, %ecx + subl $CONFIG_SYS_STACK_SIZE, %ecx + + /* Create a Stack Frame */ + pushl %ebp + movl %esp, %ebp + + /* stack_limit parameter */ + pushl %ecx + call board_init_f /* Enter, U-boot! */ + + /* indicate (lack of) progress */ + movw $0x85, %ax + movl $.progress4a, %ebp + jmp show_boot_progress_asm +.progress4a: + +die: hlt + jmp die + hlt diff --git a/arch/i386/cpu/start16.S b/arch/i386/cpu/start16.S new file mode 100644 index 00000000000..1ebb6bc8b63 --- /dev/null +++ b/arch/i386/cpu/start16.S @@ -0,0 +1,112 @@ +/* + * U-boot - i386 Startup Code + * + * Copyright (c) 2002, 2003 Omicron Ceti AB, Daniel Engström <denaiel@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 + */ + + +#define BOOT_SEG 0xffff0000 /* linear segment of boot code */ +#define a32 .byte 0x67; +#define o32 .byte 0x66; + +.section .start16, "ax" +.code16 +.globl start16 +start16: + /* First we let the BSP do some early initialization + * this code have to map the flash to its final position + */ + mov $board_init16_ret, %bp + jmp board_init16 +board_init16_ret: + + /* Turn of cache (this might require a 486-class CPU) */ + movl %cr0, %eax + orl $0x60000000,%eax + movl %eax, %cr0 + wbinvd + + /* load the descriptor tables */ +o32 cs lidt idt_ptr +o32 cs lgdt gdt_ptr + + + /* Now, we enter protected mode */ + movl %cr0, %eax + orl $1,%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 */ + +gdt_ptr: + .word 0x30 /* limit (48 bytes = 6 GDT entries) */ + .long BOOT_SEG + 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 + */ + +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) */ diff --git a/arch/i386/include/asm/interrupt.h b/arch/i386/include/asm/interrupt.h index 8d324d9f37a..07426fe6a7a 100644 --- a/arch/i386/include/asm/interrupt.h +++ b/arch/i386/include/asm/interrupt.h @@ -27,7 +27,7 @@ #ifndef __ASM_INTERRUPT_H_ #define __ASM_INTERRUPT_H_ 1 -/* cpu/i386/interrupts.c */ +/* arch/i386/cpu/interrupts.c */ void set_vector(u8 intnum, void *routine); /* arch/i386/lib/interupts.c */ diff --git a/arch/i386/include/asm/u-boot-i386.h b/arch/i386/include/asm/u-boot-i386.h index a08632d2d31..521fd352bb8 100644 --- a/arch/i386/include/asm/u-boot-i386.h +++ b/arch/i386/include/asm/u-boot-i386.h @@ -33,7 +33,7 @@ void timer_isr(void *); typedef void (timer_fnc_t) (void); int register_timer_isr (timer_fnc_t *isr_func); -/* Architecture specific - can be in cpu/i386/, arch/i386/lib/, or $(BOARD)/ */ +/* Architecture specific - can be in arch/i386/cpu/, arch/i386/lib/, or $(BOARD)/ */ int timer_init(void); /* cpu/.../interrupts.c */ |