* Patch by Daniel Engström, 13 Nov 2002:

Add support for i386 architecture and AMD SC520 board

* Patch by Pierre Aubert, 12 Nov 2002:
  Add support for DOS filesystem and booting from DOS floppy disk
This commit is contained in:
wdenk
2002-11-18 00:14:45 +00:00
parent 1d0350ed0b
commit 2262cfeef9
82 changed files with 10257 additions and 84 deletions

43
cpu/i386/Makefile Normal file
View File

@@ -0,0 +1,43 @@
#
# (C) Copyright 2002
# Daniel Engstr<74>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 = lib$(CPU).a
START = start.o start16.o reset.o
OBJS = serial.o interrupts.o cpu.o timer.o
all: .depend $(START) $(LIB)
$(LIB): $(OBJS)
$(AR) crv $@ $(OBJS)
#########################################################################
.depend: Makefile $(START:.o=.S) $(OBJS:.o=.c)
$(CC) -M $(CFLAGS) $(START:.o=.S) $(OBJS:.o=.c) > $@
sinclude .depend
#########################################################################

26
cpu/i386/config.mk Normal file
View File

@@ -0,0 +1,26 @@
#
# (C) Copyright 2002
# Daniel Engstr<74>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 += # -pipe -mpreferred-stack-boundary=2 -fno-builtin -nostdinc -nostdlib
PLATFORM_CPPFLAGS += -march=i386

62
cpu/i386/cpu.c Normal file
View File

@@ -0,0 +1,62 @@
/*
* (C) Copyright 2002
* Daniel Engstr<74>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>
int cpu_init(void)
{
return 0;
}
int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
extern void reset_cpu(ulong addr);
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;
}

583
cpu/i386/interrupts.c Normal file
View File

@@ -0,0 +1,583 @@
/*
* (C) Copyright 2002
* Daniel Engstr<74>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 <syscall.h>
#include <malloc.h>
#include <asm/io.h>
#include <asm/i8259.h>
#include <asm/ibmpc.h>
#if 0
/* done */
int interrupt_init (void);
void irq_install_handler(int, interrupt_handler_t *, void *);
void irq_free_handler (int);
void enable_interrupts (void);
int disable_interrupts (void);
/* todo */
void timer_interrupt (struct pt_regs *);
void external_interrupt (struct pt_regs *);
void reset_timer (void);
ulong get_timer (ulong base);
void set_timer (ulong t);
#endif
struct idt_entry {
u16 base_low;
u16 selector;
u8 res;
u8 access;
u16 base_high;
} __attribute__ ((packed));
struct idt_entry idt[256];
#define MAX_IRQ 16
typedef struct irq_handler {
struct irq_handler *next;
interrupt_handler_t* isr_func;
void *isr_data;
} irq_handler_t;
#define IRQ_DISABLED 1
typedef struct {
irq_handler_t *handler;
unsigned long status;
} irq_desc_t;
static irq_desc_t irq_table[MAX_IRQ];
/* syscall stuff, very untested
* the current approach which includes copying
* part of the stack will work badly for
* varargs functions.
* if we were to store the top three words on the
* stack (eip, ss, eflags) somwhere and add 14 to
* %esp ....
*/
asm(".globl syscall_entry\n" \
"syscall_entry:\n" \
"movl 12(%esp), %eax\n" \
"movl %esp, %ebx\n" \
"addl $16, %ebx\n" \
"pushl %ebx\n" \
"pushl %eax\n" \
"call do_syscall\n" \
"addl $8, %esp\n" \
"iret\n");
void __attribute__ ((regparm(0))) syscall_entry(void);
int __attribute__ ((regparm(0))) do_syscall(u32 nr, u32 *stack)
{
if (nr<NR_SYSCALLS) {
/* We copy 8 args of the syscall,
* this will be a problem with the
* printf syscall .... */
int (*fp)(u32, u32, u32, u32,
u32, u32, u32, u32);
fp = syscall_tbl[nr];
return fp(stack[0], stack[1], stack[2], stack[3],
stack[4], stack[5], stack[6], stack[7]);
}
return -1;
}
asm ("irq_return:\n"
" addl $4, %esp\n"
" popa\n"
" iret\n");
asm ("exp_return:\n"
" addl $12, %esp\n"
" pop %esp\n"
" popa\n"
" iret\n");
char exception_stack[4096];
#define DECLARE_INTERRUPT(x) \
asm(".globl irq_"#x"\n" \
"irq_"#x":\n" \
"pusha \n" \
"pushl $"#x"\n" \
"pushl $irq_return\n" \
"jmp do_irq\n"); \
void __attribute__ ((regparm(0))) irq_##x(void)
#define DECLARE_EXCEPTION(x, f) \
asm(".globl exp_"#x"\n" \
"exp_"#x":\n" \
"pusha \n" \
"movl %esp, %ebx\n" \
"movl $exception_stack, %eax\n" \
"movl %eax, %esp \n" \
"pushl %ebx\n" \
"movl 32(%esp), %ebx\n" \
"xorl %edx, %edx\n" \
"movw 36(%esp), %dx\n" \
"pushl %edx\n" \
"pushl %ebx\n" \
"pushl $"#x"\n" \
"pushl $exp_return\n" \
"jmp "#f"\n"); \
void __attribute__ ((regparm(0))) exp_##x(void)
DECLARE_EXCEPTION(0, divide_exception_entry); /* Divide exception */
DECLARE_EXCEPTION(1, debug_exception_entry); /* Debug exception */
DECLARE_EXCEPTION(2, nmi_entry); /* NMI */
DECLARE_EXCEPTION(3, unknown_exception_entry); /* Breakpoint/Coprocessor Error */
DECLARE_EXCEPTION(4, unknown_exception_entry); /* Overflow */
DECLARE_EXCEPTION(5, unknown_exception_entry); /* Bounds */
DECLARE_EXCEPTION(6, invalid_instruction_entry); /* Invalid instruction */
DECLARE_EXCEPTION(7, unknown_exception_entry); /* Device not present */
DECLARE_EXCEPTION(8, double_fault_entry); /* Double fault */
DECLARE_EXCEPTION(9, unknown_exception_entry); /* Co-processor segment overrun */
DECLARE_EXCEPTION(10, invalid_tss_exception_entry);/* Invalid TSS */
DECLARE_EXCEPTION(11, seg_fault_entry); /* Segment not present */
DECLARE_EXCEPTION(12, stack_fault_entry); /* Stack overflow */
DECLARE_EXCEPTION(13, gpf_entry); /* GPF */
DECLARE_EXCEPTION(14, page_fault_entry); /* PF */
DECLARE_EXCEPTION(15, unknown_exception_entry); /* Reserved */
DECLARE_EXCEPTION(16, fp_exception_entry); /* Floating point */
DECLARE_EXCEPTION(17, alignment_check_entry); /* alignment check */
DECLARE_EXCEPTION(18, machine_check_entry); /* machine check */
DECLARE_EXCEPTION(19, unknown_exception_entry); /* Reserved */
DECLARE_EXCEPTION(20, unknown_exception_entry); /* Reserved */
DECLARE_EXCEPTION(21, unknown_exception_entry); /* Reserved */
DECLARE_EXCEPTION(22, unknown_exception_entry); /* Reserved */
DECLARE_EXCEPTION(23, unknown_exception_entry); /* Reserved */
DECLARE_EXCEPTION(24, unknown_exception_entry); /* Reserved */
DECLARE_EXCEPTION(25, unknown_exception_entry); /* Reserved */
DECLARE_EXCEPTION(26, unknown_exception_entry); /* Reserved */
DECLARE_EXCEPTION(27, unknown_exception_entry); /* Reserved */
DECLARE_EXCEPTION(28, unknown_exception_entry); /* Reserved */
DECLARE_EXCEPTION(29, unknown_exception_entry); /* Reserved */
DECLARE_EXCEPTION(30, unknown_exception_entry); /* Reserved */
DECLARE_EXCEPTION(31, unknown_exception_entry); /* Reserved */
DECLARE_INTERRUPT(0);
DECLARE_INTERRUPT(1);
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);
void __attribute__ ((regparm(0))) default_isr(void);
asm ("default_isr: iret\n");
void disable_irq(int irq)
{
if (irq >= MAX_IRQ) {
return;
}
irq_table[irq].status |= IRQ_DISABLED;
}
void enable_irq(int irq)
{
if (irq >= MAX_IRQ) {
return;
}
irq_table[irq].status &= ~IRQ_DISABLED;
}
/* masks one specific IRQ in the PIC */
static void unmask_irq(int irq)
{
int imr_port;
if (irq >= MAX_IRQ) {
return;
}
if (irq > 7) {
imr_port = SLAVE_PIC + IMR;
} else {
imr_port = MASTER_PIC + IMR;
}
outb(inb(imr_port)&~(1<<(irq&7)), imr_port);
}
/* unmasks one specific IRQ in the PIC */
static void mask_irq(int irq)
{
int imr_port;
if (irq >= MAX_IRQ) {
return;
}
if (irq > 7) {
imr_port = SLAVE_PIC + IMR;
} else {
imr_port = MASTER_PIC + IMR;
}
outb(inb(imr_port)|(1<<(irq&7)), imr_port);
}
/* issue a Specific End Of Interrupt instruciton */
static void specific_eoi(int irq)
{
/* If it is on the slave PIC this have to be performed on
* both the master and the slave PICs */
if (irq > 7) {
outb(OCW2_SEOI|(irq&7), SLAVE_PIC + OCW2);
irq = SEOI_IR2; /* also do IR2 on master */
}
outb(OCW2_SEOI|irq, MASTER_PIC + OCW2);
}
void __attribute__ ((regparm(0))) do_irq(int irq)
{
mask_irq(irq);
if (irq_table[irq].status & IRQ_DISABLED) {
unmask_irq(irq);
specific_eoi(irq);
return;
}
if (NULL != irq_table[irq].handler) {
irq_handler_t *handler;
for (handler = irq_table[irq].handler;
NULL!= handler; handler = handler->next) {
handler->isr_func(handler->isr_data);
}
} else {
if ((irq & 7) != 7) {
printf("Spurious irq %d\n", irq);
}
}
unmask_irq(irq);
specific_eoi(irq);
}
void __attribute__ ((regparm(0))) unknown_exception_entry(int cause, int ip, int seg)
{
printf("Unknown Exception %d at %04x:%08x\n", cause, seg, ip);
}
void __attribute__ ((regparm(0))) divide_exception_entry(int cause, int ip, int seg)
{
printf("Divide Error (Division by zero) at %04x:%08x\n", seg, ip);
while(1);
}
void __attribute__ ((regparm(0))) debug_exception_entry(int cause, int ip, int seg)
{
printf("Debug Interrupt (Single step) at %04x:%08x\n", seg, ip);
}
void __attribute__ ((regparm(0))) nmi_entry(int cause, int ip, int seg)
{
printf("NMI Interrupt at %04x:%08x\n", seg, ip);
}
void __attribute__ ((regparm(0))) invalid_instruction_entry(int cause, int ip, int seg)
{
printf("Invalid Instruction at %04x:%08x\n", seg, ip);
while(1);
}
void __attribute__ ((regparm(0))) double_fault_entry(int cause, int ip, int seg)
{
printf("Double fault at %04x:%08x\n", seg, ip);
while(1);
}
void __attribute__ ((regparm(0))) invalid_tss_exception_entry(int cause, int ip, int seg)
{
printf("Invalid TSS at %04x:%08x\n", seg, ip);
}
void __attribute__ ((regparm(0))) seg_fault_entry(int cause, int ip, int seg)
{
printf("Segmentation fault at %04x:%08x\n", seg, ip);
while(1);
}
void __attribute__ ((regparm(0))) stack_fault_entry(int cause, int ip, int seg)
{
printf("Stack fault at %04x:%08x\n", seg, ip);
while(1);
}
void __attribute__ ((regparm(0))) gpf_entry(int cause, int ip, int seg)
{
printf("General protection fault at %04x:%08x\n", seg, ip);
}
void __attribute__ ((regparm(0))) page_fault_entry(int cause, int ip, int seg)
{
printf("Page fault at %04x:%08x\n", seg, ip);
while(1);
}
void __attribute__ ((regparm(0))) fp_exception_entry(int cause, int ip, int seg)
{
printf("Floating point exception at %04x:%08x\n", seg, ip);
}
void __attribute__ ((regparm(0))) alignment_check_entry(int cause, int ip, int seg)
{
printf("Alignment check at %04x:%08x\n", seg, ip);
}
void __attribute__ ((regparm(0))) machine_check_entry(int cause, int ip, int seg)
{
printf("Machine check exception at %04x:%08x\n", seg, ip);
}
void irq_install_handler(int ino, interrupt_handler_t *func, void *pdata)
{
int status;
if (ino>MAX_IRQ) {
return;
}
if (NULL != irq_table[ino].handler) {
return;
}
status = disable_interrupts();
irq_table[ino].handler = malloc(sizeof(irq_handler_t));
if (NULL == irq_table[ino].handler) {
return;
}
memset(irq_table[ino].handler, 0, sizeof(irq_handler_t));
irq_table[ino].handler->isr_func = func;
irq_table[ino].handler->isr_data = pdata;
if (status) {
enable_interrupts();
}
unmask_irq(ino);
return;
}
void irq_free_handler(int ino)
{
int status;
if (ino>MAX_IRQ) {
return;
}
status = disable_interrupts();
mask_irq(ino);
if (NULL == irq_table[ino].handler) {
return;
}
free(irq_table[ino].handler);
irq_table[ino].handler=NULL;
if (status) {
enable_interrupts();
}
return;
}
asm ("idt_ptr:\n"
".word 0x800\n" /* size of the table 8*256 bytes */
".long idt\n" /* offset */
".word 0x18\n");/* data segment */
static void set_vector(int intnum, void *routine)
{
idt[intnum].base_high = (u16)((u32)(routine)>>16);
idt[intnum].base_low = (u16)((u32)(routine)&0xffff);
}
int interrupt_init(void)
{
int i;
/* Just in case... */
disable_interrupts();
/* Initialize the IDT and stuff */
memset(irq_table, 0, sizeof(irq_table));
/* Setup the IDT */
for (i=0;i<256;i++) {
idt[i].access = 0x8e;
idt[i].res = 0;
idt[i].selector = 0x10;
set_vector(i, default_isr);
}
asm ("cs lidt idt_ptr\n");
/* Setup exceptions */
set_vector(0x00, exp_0);
set_vector(0x01, exp_1);
set_vector(0x02, exp_2);
set_vector(0x03, exp_3);
set_vector(0x04, exp_4);
set_vector(0x05, exp_5);
set_vector(0x06, exp_6);
set_vector(0x07, exp_7);
set_vector(0x08, exp_8);
set_vector(0x09, exp_9);
set_vector(0x0a, exp_10);
set_vector(0x0b, exp_11);
set_vector(0x0c, exp_12);
set_vector(0x0d, exp_13);
set_vector(0x0e, exp_14);
set_vector(0x0f, exp_15);
set_vector(0x10, exp_16);
set_vector(0x11, exp_17);
set_vector(0x12, exp_18);
set_vector(0x13, exp_19);
set_vector(0x14, exp_20);
set_vector(0x15, exp_21);
set_vector(0x16, exp_22);
set_vector(0x17, exp_23);
set_vector(0x18, exp_24);
set_vector(0x19, exp_25);
set_vector(0x1a, exp_26);
set_vector(0x1b, exp_27);
set_vector(0x1c, exp_28);
set_vector(0x1d, exp_29);
set_vector(0x1e, exp_30);
set_vector(0x1f, exp_31);
/* Setup interrupts */
set_vector(0x20, irq_0);
set_vector(0x21, irq_1);
set_vector(0x23, irq_3);
set_vector(0x24, irq_4);
set_vector(0x25, irq_5);
set_vector(0x26, irq_6);
set_vector(0x27, irq_7);
set_vector(0x28, irq_8);
set_vector(0x29, irq_9);
set_vector(0x2a, irq_10);
set_vector(0x2b, irq_11);
set_vector(0x2c, irq_12);
set_vector(0x2d, irq_13);
set_vector(0x2e, irq_14);
set_vector(0x2f, irq_15);
/* vectors 0x30-0x3f are reserved for irq 16-31 */
set_vector(0x40, syscall_entry);
/* Mask all interrupts */
outb(0xff, MASTER_PIC + IMR);
outb(0xff, SLAVE_PIC + IMR);
/* Master PIC */
outb(ICW1_SEL|ICW1_EICW4, MASTER_PIC + ICW1);
outb(0x20, MASTER_PIC + ICW2); /* Place master PIC interrupts at INT20 */
outb(IR2, MASTER_PIC + ICW3); /* ICW3, One slevc PIC is present */
outb(ICW4_PM, MASTER_PIC + ICW4);
for (i=0;i<8;i++) {
outb(OCW2_SEOI|i, MASTER_PIC + OCW2);
}
/* Slave PIC */
outb(ICW1_SEL|ICW1_EICW4, SLAVE_PIC + ICW1);
outb(0x28, SLAVE_PIC + ICW2); /* Place slave PIC interrupts at INT28 */
outb(0x02, SLAVE_PIC + ICW3); /* Slave ID */
outb(ICW4_PM, SLAVE_PIC + ICW4);
for (i=0;i<8;i++) {
outb(OCW2_SEOI|i, SLAVE_PIC + OCW2);
}
/* enable cascade interrerupt */
outb(0xfb, MASTER_PIC + IMR);
outb(0xff, SLAVE_PIC + IMR);
/* It is now safe to enable interrupts */
enable_interrupts();
return 0;
}
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 */
}
#ifdef CFG_RESET_GENERIC
void __attribute__ ((regparm(0))) generate_gpf(void);
asm(".globl generate_gpf\n"
"generate_gpf:\n"
"ljmp $0x70, $0x47114711\n"); /* segment 0x70 is an arbitrary segment which does not
* exist */
void reset_cpu(ulong addr)
{
set_vector(13, generate_gpf); /* general protection fault handler */
set_vector(8, generate_gpf); /* double fault handler */
generate_gpf(); /* start the show */
}
#endif

38
cpu/i386/reset.S Normal file
View File

@@ -0,0 +1,38 @@
/*
* U-boot - i386 Startup Code
*
* Copyright (c) 2002 Omicron Ceti AB, Daniel Engstr<EFBFBD>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 .reset, "ax"
.code16
reset_vector:
cli
cld
jmp start16
.org 0xf
nop

460
cpu/i386/serial.c Normal file
View File

@@ -0,0 +1,460 @@
/*
* (C) Copyright 2002
* Daniel Engstr<74>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 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>
#if CONFIG_SERIAL_SOFTWARE_FIFO
#include <malloc.h>
#endif
#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
#if CONFIG_SERIAL_SOFTWARE_FIFO
/*-----------------------------------------------------------------------------+
| Fifo
+-----------------------------------------------------------------------------*/
typedef struct {
char *rx_buffer;
ulong rx_put;
ulong rx_get;
} serial_buffer_t;
volatile static serial_buffer_t buf_info;
#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;
}
hang ();
}
/*
* Minimal serial functions needed to use one of the SMC ports
* as serial console interface.
*/
int serial_init (void)
{
DECLARE_GLOBAL_DATA_PTR;
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(0x00, UART0_BASE + UART_FCR); /* disable FIFO */
outb(0x00, UART0_BASE + UART_MCR); /* no modem control DTR RTS */
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)
{
DECLARE_GLOBAL_DATA_PTR;
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 ()
{
unsigned char status = 0;
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 ()
{
unsigned char status;
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;
}
#if CONFIG_SERIAL_SOFTWARE_FIFO
void serial_isr (void *arg)
{
int space;
int c;
const int rx_get = buf_info.rx_get;
int 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;
}
while (serial_tstc ()) {
c = serial_getc ();
if (space) {
buf_info.rx_buffer[rx_put++] = c;
space--;
}
if (rx_put == CONFIG_SERIAL_SOFTWARE_FIFO)
rx_put = 0;
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");
} else {
serial_puts ("WARNING: CTS signal not present on serial port.\n");
}
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 active */
outb(inb (UART0_BASE + UART_MCR) | 0x01, UART0_BASE + UART_MCR);
/* Start flow by setting RTS active */
outb(inb (UART0_BASE + UART_MCR) | 0x02, UART0_BASE + UART_MCR);
/* Setup UART FIFO: RX trigger level: 4 byte, Enable FIFO */
outb((1 << 6) | 1, UART0_BASE + UART_FCR);
}
void serial_buffered_putc (const char c)
{
/* Wait for CTS */
#if defined(CONFIG_HW_WATCHDOG)
while (!(inb (UART0_BASE + UART_MSR) & 0x10))
WATCHDOG_RESET ();
#else
while (!(inb (UART0_BASE + UART_MSR) & 0x10));
#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 (CONFIG_COMMANDS & CFG_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)
{
DECLARE_GLOBAL_DATA_PTR;
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 /* CFG_CMD_KGDB */

198
cpu/i386/start.S Normal file
View File

@@ -0,0 +1,198 @@
/*
* U-boot - i386 Startup Code
*
* Copyright (c) 2002 Omicron Ceti AB, Daniel Engstr<EFBFBD>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
.progress0:
/* size memory */
mov $mem_init_ret, %ebp
jmp mem_init
mem_init_ret:
/* check ammount of configured memory
* (we need atleast bss start+bss size+stack size) */
movl $_i386boot_bss_start, %ecx /* BSS start */
addl $_i386boot_bss_size, %ecx /* BSS size */
addl $CFG_STACK_SIZE, %ecx
cmpl %ecx, %eax
jae mem_ok
/* indicate (lack of) progress */
movw $0x81, %ax
movl $.progress0a, %ebp
jmp __show_boot_progress
.progress0a:
jmp die
mem_ok:
/* indicate progress */
movw $0x02, %ax
movl $.progress1, %ebp
jmp __show_boot_progress
.progress1:
/* create a stack after the bss */
movl $_i386boot_bss_start, %eax
addl $_i386boot_bss_size, %eax
addl $CFG_STACK_SIZE, %eax
movl %eax, %esp
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
.progress1a:
jmp die
stack_ok:
/* indicate progress */
movw $0x03, %ax
movl $.progress2, %ebp
jmp __show_boot_progress
.progress2:
/* copy data section to ram, size must be 4-byte aligned */
movl $_i386boot_romdata_dest, %edi /* destination address */
movl $_i386boot_romdata_start, %esi /* source address */
movl $_i386boot_romdata_size, %ecx /* number of bytes to copy */
movl %ecx, %eax
andl $3, %eax
jnz data_fail
shrl $2, %ecx /* copy 4 byte each time */
cld
cmpl $0, %ecx
je data_ok
data_segment:
movsl
loop data_segment
jmp data_ok
data_fail:
/* indicate (lack of) progress */
movw $0x83, %ax
movl $.progress2a, %ebp
jmp __show_boot_progress
.progress2a:
jmp die
data_ok:
/* indicate progress */
movw $0x04, %ax
movl $.progress3, %ebp
jmp __show_boot_progress
.progress3:
/* clear bss section in ram, size must be 4-byte aligned */
movl $_i386boot_bss_start, %eax /* BSS start */
movl $_i386boot_bss_size, %ecx /* BSS size */
movl %ecx, %eax
andl $3, %eax
jnz bss_fail
shrl $2, %ecx /* clear 4 byte each time */
cld
cmpl $0, %ecx
je bss_ok
bss:
movl $0, (%edi)
add $4, %edi
loop bss
jmp bss_ok
bss_fail:
/* indicate (lack of) progress */
movw $0x84, %ax
movl $.progress3a, %ebp
jmp __show_boot_progress
.progress3a:
jmp die
bss_ok:
wbinvd
/* indicate progress */
movw $0x05, %ax
movl $.progress4, %ebp
jmp __show_boot_progress
.progress4:
call start_i386boot /* Enter, U-boot! */
/* indicate (lack of) progress */
movw $0x85, %ax
movl $.progress4a, %ebp
jmp __show_boot_progress
.progress4a:
die: hlt
jmp die
hlt

112
cpu/i386/start16.S Normal file
View File

@@ -0,0 +1,112 @@
/*
* U-boot - i386 Startup Code
*
* Copyright (c) 2002 Omicron Ceti AB, Daniel Engstr<EFBFBD>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 $060000000,%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) */

211
cpu/i386/timer.c Normal file
View File

@@ -0,0 +1,211 @@
/*
* (C) Copyright 2002
* Daniel Engstr<74>m, Omicron Ceti AB, daniel@omicron.se.
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#include <common.h>
#include <asm/io.h>
#include <asm/i8254.h>
#include <asm/ibmpc.h>
static volatile unsigned long system_ticks;
static int timer_init_done =0;
static void timer_isr(void *unused)
{
system_ticks++;
}
unsigned long get_system_ticks(void)
{
return system_ticks;
}
#define TIMER0_VALUE 0x04aa /* 1kHz 1.9318MHz / 1000 */
#define TIMER2_VALUE 0x0a8e /* 440Hz */
int timer_init(void)
{
system_ticks = 0;
irq_install_handler(0, timer_isr, NULL);
/* initialize timer 0 and 2
*
* Timer 0 is used to increment system_tick 1000 times/sec
* Timer 1 was used for DRAM refresh in early PC's
* Timer 2 is used to drive the speaker
* (to stasrt a beep: write 3 to port 0x61,
* to stop it again: write 0)
*/
outb(PIT_CMD_CTR0|PIT_CMD_BOTH|PIT_CMD_MODE2, PIT_BASE + PIT_COMMAND);
outb(TIMER0_VALUE&0xff, PIT_BASE + PIT_T0);
outb(TIMER0_VALUE>>8, PIT_BASE + PIT_T0);
outb(PIT_CMD_CTR2|PIT_CMD_BOTH|PIT_CMD_MODE3, PIT_BASE + PIT_COMMAND);
outb(TIMER2_VALUE&0xff, PIT_BASE + PIT_T2);
outb(TIMER2_VALUE>>8, PIT_BASE + PIT_T2);
timer_init_done = 1;
return 0;
}
#ifdef CFG_TIMER_GENERIC
/* the unit for these is CFG_HZ */
/* FixMe: implement these */
void reset_timer (void)
{
system_ticks = 0;
}
ulong get_timer (ulong base)
{
return (system_ticks - base);
}
void set_timer (ulong t)
{
system_ticks = t;
}
static u16 read_pit(void)
{
u8 low;
outb(PIT_CMD_LATCH, PIT_BASE + PIT_COMMAND);
low = inb(PIT_BASE + PIT_T0);
return ((inb(PIT_BASE + PIT_T0) << 8) | low);
}
/* this is not very exact */
void udelay (unsigned long usec)
{
int counter;
int wraps;
if (!timer_init_done) {
return;
}
counter = read_pit();
wraps = usec/1000;
usec = usec%1000;
usec*=1194;
usec/=1000;
usec+=counter;
if (usec > 1194) {
usec-=1194;
wraps++;
}
while (1) {
int new_count = read_pit();
if (((new_count < usec) && !wraps) || wraps < 0) {
break;
}
if (new_count > counter) {
wraps--;
}
counter = new_count;
}
}
#if 0
/* this is a version with debug output */
void _udelay (unsigned long usec)
{
int counter;
int wraps;
int usec1, usec2, usec3;
int wraps1, wraps2, wraps3, wraps4;
int ctr1, ctr2, ctr3, nct1, nct2;
int i;
usec1=usec;
if (!timer_init_done) {
return;
}
counter = read_pit();
ctr1 = counter;
wraps = usec/1000;
usec = usec%1000;
usec2 = usec;
wraps1 = wraps;
usec*=1194;
usec/=1000;
usec+=counter;
if (usec > 1194) {
usec-=1194;
wraps++;
}
usec3 = usec;
wraps2 = wraps;
ctr2 = wraps3 = nct1 = 4711;
ctr3 = wraps4 = nct2 = 4711;
i=0;
while (1) {
int new_count = read_pit();
i++;
if ((new_count < usec && !wraps) || wraps < 0) {
break;
}
if (new_count > counter) {
wraps--;
}
if (ctr2==4711) {
ctr2 = counter;
wraps3 = wraps;
nct1 = new_count;
} else {
ctr3 = counter;
wraps4 = wraps;
nct2 = new_count;
}
counter = new_count;
}
printf("udelay(%d)\n", usec1);
printf("counter %d\n", ctr1);
printf("1: wraps %d, usec %d\n", wraps1, usec2);
printf("2: wraps %d, usec %d\n", wraps2, usec3);
printf("new_count[0] %d counter %d wraps %d\n", nct1, ctr2, wraps3);
printf("new_count[%d] %d counter %d wraps %d\n", i, nct2, ctr3, wraps4);
printf("%d %d %d %d %d\n",
read_pit(), read_pit(), read_pit(),
read_pit(), read_pit());
}
#endif
#endif