diff options
Diffstat (limited to 'lib_i386')
-rw-r--r-- | lib_i386/Makefile | 6 | ||||
-rw-r--r-- | lib_i386/bios.S | 135 | ||||
-rw-r--r-- | lib_i386/bios.h | 94 | ||||
-rw-r--r-- | lib_i386/bios_pci.S | 411 | ||||
-rw-r--r-- | lib_i386/bios_setup.c | 60 | ||||
-rw-r--r-- | lib_i386/board.c | 34 | ||||
-rw-r--r-- | lib_i386/ic/ali512x.c | 442 | ||||
-rw-r--r-- | lib_i386/ic/sc520.c | 348 | ||||
-rw-r--r-- | lib_i386/ic/sc520_asm.S | 530 | ||||
-rw-r--r-- | lib_i386/pci.c | 156 | ||||
-rw-r--r-- | lib_i386/realmode.c | 44 | ||||
-rw-r--r-- | lib_i386/realmode_switch.S | 1 | ||||
-rw-r--r-- | lib_i386/video.c | 238 | ||||
-rw-r--r-- | lib_i386/video_bios.c | 221 | ||||
-rw-r--r-- | lib_i386/zimage.c | 4 |
15 files changed, 1312 insertions, 1412 deletions
diff --git a/lib_i386/Makefile b/lib_i386/Makefile index 34994e5..47c5d2c 100644 --- a/lib_i386/Makefile +++ b/lib_i386/Makefile @@ -25,11 +25,11 @@ include $(TOPDIR)/config.mk LIB = lib$(ARCH).a -AOBJS = bios.o realmode_switch.o ic/sc520_asm.o +AOBJS = bios.o bios_pci.o realmode_switch.o COBJS = board.o bios_setup.o i386_linux.o zimage.o realmode.o \ - pci_type1.o ic/sc520.o ic/ali512x.o - + pci_type1.o pci.o video_bios.o video.o + OBJS = $(AOBJS) $(COBJS) $(LIB): .depend $(OBJS) diff --git a/lib_i386/bios.S b/lib_i386/bios.S index 2f5ea8c..ce6e94c 100644 --- a/lib_i386/bios.S +++ b/lib_i386/bios.S @@ -30,6 +30,8 @@ *---------------------------------------------------------------------- */ +#include "bios.h" + /* * During it's initialization phase, before switching to protected * mode, the Linux Kernel makes a few BIOS calls. This won't work @@ -40,29 +42,13 @@ * a general purpose replacement for a real BIOS !! */ -#define OFFS_ES 0 -#define OFFS_GS 2 -#define OFFS_DS 4 -#define OFFS_DI 6 -#define OFFS_SI 8 -#define OFFS_BP 10 -#define OFFS_SP 12 -#define OFFS_BX 14 -#define OFFS_DX 16 -#define OFFS_CX 18 -#define OFFS_AX 20 -#define OFFS_VECTOR 22 -#define OFFS_IP 24 -#define OFFS_CS 26 -#define OFFS_FLAGS 28 - -#define SEGMENT 0x40 -#define STACK 0x800 /* stack at 0x40:0x800 -> 0x800 */ .section .bios, "ax" .code16 .org 0 - + /* a call to f000:0 should warmboot */ + jmp realmode_reset + .globl rm_int00 rm_int00: pushw $0 @@ -202,30 +188,23 @@ rm_def_int: * stack. */ any_interrupt16: - pusha /* save general registers */ - pushw %ds /* save some segments */ - pushw %gs - pushw %es - pushw %ss /* save callers stack segment .. */ - popw %gs /* ... in gs */ - movw $SEGMENT,%ax /* setup my segments */ - movw %ax,%ds - movw %ax,%es - movw %ax,%ss - movw %sp,%bp - movw $STACK,%sp /* setup BIOS stackpointer */ + MAKE_BIOS_STACK gs movw OFFS_VECTOR(%bp), %ax cmpw $0x10, %ax je Lint_10h cmpw $0x11, %ax je Lint_11h + cmpw $0x12, %ax + je Lint_12h cmpw $0x13, %ax je Lint_13h cmpw $0x15, %ax je Lint_15h cmpw $0x16, %ax je Lint_16h + cmpw $0x1a, %ax + je Lint_1ah movw $0xffff, %ax jmp Lout Lint_10h: /* VGA BIOS services */ @@ -234,6 +213,9 @@ Lint_10h: /* VGA BIOS services */ Lint_11h: call bios_11h jmp Lout +Lint_12h: + call bios_12h + jmp Lout Lint_13h: /* BIOS disk services */ call bios_13h jmp Lout @@ -243,6 +225,9 @@ Lint_15h: /* Misc. BIOS services */ Lint_16h: /* keyboard services */ call bios_16h jmp Lout +Lint_1ah: /* PCI bios */ + call bios_1ah + jmp Lout Lout: cmpw $0, %ax je Lhandeled @@ -256,16 +241,7 @@ Lout: * we shuls make int 0x10 and int 0x16 work as well)) */ Lhandeled: - - pushw %gs /* restore callers stack segment */ - popw %ss - movw %bp,%sp /* restore stackpointer */ - - popw %es /* restore segment selectors */ - popw %gs - popw %ds - - popa /* restore GP registers */ + RESTORE_CALLERS_STACK addw $2,%sp /* dump vector number */ iret /* return from interrupt */ @@ -309,7 +285,7 @@ gs movw $0x10, OFFS_BX(%bp) /* indicate CGA/MDA/HGA */ */ bios_11h: - movw bios_equipment, %ax +cs movw bios_equipment, %ax gs movw %ax, OFFS_AX(%bp) xorw %ax, %ax ret @@ -317,6 +293,30 @@ gs movw %ax, OFFS_AX(%bp) /* ************************************************************ + * BIOS interrupt 12h -- Get Memory Size + ************************************************************ + */ +bios_12h: +cs movw ram_in_64kb_chunks, %ax + cmpw $0xa, %ax + ja b12_more_than_640k + shlw $6, %ax + jmp b12_return +b12_more_than_640k: + movw $0x280, %ax +b12_return: +gs movw %ax, OFFS_AX(%bp) /* return number of kilobytes in ax */ + +gs movw OFFS_FLAGS(%bp), %ax + andw $0xfffe, %ax /* clear carry -- function succeeded */ +gs movw %ax, OFFS_FLAGS(%bp) + + xorw %ax, %ax + ret + + +/* + ************************************************************ * BIOS interrupt 13h -- Disk services ************************************************************ */ @@ -372,27 +372,28 @@ gs movw %ax, OFFS_FLAGS(%bp) ret Lfunc_e801h: /* Get memory size for >64M Configurations */ - movw $ram_in_64kb_chunks, %ax - cmpw $256, %ax - ja Lmore_than_16mb - shlw $6, %ax /* multiply by 64 */ -gs movw %ax, OFFS_AX(%bp) /* return memory size in 1kb chunks in AX and CX */ +cs movw ram_in_64kb_chunks, %ax + cmpw $0x100, %ax + ja e801_more_than_16mb + shlw $6, %ax /* multiply by 64 */ + subw $0x400, %ax /* 1st meg does not count */ + +gs movw %ax, OFFS_AX(%bp) /* return memory size between 1M and 16M in 1kb chunks in AX and CX */ gs movw %ax, OFFS_CX(%bp) - xorw %ax, %ax -gs movw %ax, OFFS_BX(%bp) /* set BX and DX to 0*/ -gs movw %ax, OFFS_DX(%bp) +gs movw $0, OFFS_BX(%bp) /* set BX and DX to 0*/ +gs movw $0, OFFS_DX(%bp) gs movw OFFS_FLAGS(%bp), %ax andw $0xfffe, %ax /* clear carry -- function succeeded */ gs movw %ax, OFFS_FLAGS(%bp) xorw %ax, %ax ret -Lmore_than_16mb: +e801_more_than_16mb: subw $0x100, %ax /* subtract 16MB */ -gs movw $0x3c00, OFFS_AX(%bp) /* return 0x3c00 (16MB-384k) in AX and CX */ +gs movw $0x3c00, OFFS_AX(%bp) /* return 0x3c00 (16MB-1MB) in AX and CX */ gs movw $0x3c00, OFFS_CX(%bp) -gs movw %ax, OFFS_BX(%bp) /* set BX and DX to number of 64kb chunks - 256 */ +gs movw %ax, OFFS_BX(%bp) /* set BX and DX to number of 64kb chunks above 16MB */ gs movw %ax, OFFS_DX(%bp) gs movw OFFS_FLAGS(%bp), %ax @@ -402,11 +403,15 @@ gs movw %ax, OFFS_FLAGS(%bp) ret Lfunc_88h: - movw ram_in_64kb_chunks, %ax - subw $16, %ax +cs movw ram_in_64kb_chunks, %ax + cmpw $0x100, %ax + jna b88_not_more_than16 + movw $0x100, %ax +b88_not_more_than16: shlw $6, %ax - -gs movw %ax, OFFS_AX(%bp) /* return number of kilobytes in ax */ + subw $0x400, %ax /* 1st meg does not count */ + +gs movw %ax, OFFS_AX(%bp) /* return number of kilobytes between 16MB and 16MB in ax */ gs movw OFFS_FLAGS(%bp), %ax andw $0xfffe, %ax /* clear carry -- function succeeded */ @@ -432,6 +437,22 @@ Lfunc_03h: xorw %ax, %ax /* do nothing -- function not supported */ ret +/* + ************************************************************ + * BIOS interrupt 1ah -- PCI bios + ************************************************************ + */ +bios_1ah: +gs movw OFFS_AX(%bp), %ax + cmpb $0xb1, %ah + je Lfunc_b1h + movw $0xffff, %ax + ret +Lfunc_b1h: + call realmode_pci_bios + xorw %ax, %ax /* do nothing -- function not supported */ + ret + .globl ram_in_64kb_chunks ram_in_64kb_chunks: diff --git a/lib_i386/bios.h b/lib_i386/bios.h new file mode 100644 index 0000000..876fe31 --- /dev/null +++ b/lib_i386/bios.h @@ -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 + */ + +#ifndef _BIOS_H_ +#define _BIOS_H_ + +#define OFFS_ES 0 /* 16bit */ +#define OFFS_GS 2 /* 16bit */ +#define OFFS_DS 4 /* 16bit */ +#define OFFS_EDI 6 /* 32bit */ +#define OFFS_DI 6 /* low 16 bits of EDI */ +#define OFFS_ESI 10 /* 32bit */ +#define OFFS_SI 10 /* low 16 bits of ESI */ +#define OFFS_EBP 14 /* 32bit */ +#define OFFS_BP 14 /* low 16 bits of EBP */ +#define OFFS_ESP 18 /* 32bit */ +#define OFFS_SP 18 /* low 16 bits of ESP */ +#define OFFS_EBX 22 /* 32bit */ +#define OFFS_BX 22 /* low 16 bits of EBX */ +#define OFFS_BL 22 /* low 8 bits of BX */ +#define OFFS_BH 23 /* high 8 bits of BX */ +#define OFFS_EDX 26 /* 32bit */ +#define OFFS_DX 26 /* low 16 bits of EBX */ +#define OFFS_DL 26 /* low 8 bits of BX */ +#define OFFS_DH 27 /* high 8 bits of BX */ +#define OFFS_ECX 30 /* 32bit */ +#define OFFS_CX 30 /* low 16 bits of EBX */ +#define OFFS_CL 30 /* low 8 bits of BX */ +#define OFFS_CH 31 /* high 8 bits of BX */ +#define OFFS_EAX 34 /* 32bit */ +#define OFFS_AX 34 /* low 16 bits of EBX */ +#define OFFS_AL 34 /* low 8 bits of BX */ +#define OFFS_AH 35 /* high 8 bits of BX */ +#define OFFS_VECTOR 38 /* 16bit */ +#define OFFS_IP 40 /* 16bit */ +#define OFFS_CS 42 /* 16bit */ +#define OFFS_FLAGS 44 /* 16bit */ + +#define SEGMENT 0x40 +#define STACK 0x800 /* stack at 0x40:0x800 -> 0x800 */ + +/* save general registers */ +/* save some segments */ +/* save callers stack segment .. */ +/* ... in gs */ + /* setup my segments */ + /* setup BIOS stackpointer */ + +#define MAKE_BIOS_STACK \ + pushal ; \ + pushw %ds ; \ + pushw %gs ; \ + pushw %es ; \ + pushw %ss ; \ + popw %gs ; \ + movw $SEGMENT,%ax ; \ + movw %ax,%ds ; \ + movw %ax,%es ; \ + movw %ax,%ss ; \ + movw %sp,%bp ; \ + movw $STACK,%sp + +#define RESTORE_CALLERS_STACK \ + pushw %gs ; /* restore callers stack segment */ \ + popw %ss ; \ + movw %bp,%sp ; /* restore stackpointer */ \ + \ + popw %es ; /* restore segment selectors */ \ + popw %gs ; \ + popw %ds ; \ + \ + popal /* restore GP registers */ + +#endif diff --git a/lib_i386/bios_pci.S b/lib_i386/bios_pci.S new file mode 100644 index 0000000..e53791a --- /dev/null +++ b/lib_i386/bios_pci.S @@ -0,0 +1,411 @@ +/* + * (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 + */ + +/* + * x86 realmode assembly implementation of a PCI BIOS + * for platforms that use one PCI hose and configuration + * access type 1. (The common case for low-end PC's) + */ + +#include "bios.h" + +#define PCI_BIOS_DEBUG + +.section .bios, "ax" +.code16 +.globl realmode_pci_bios_call_entry +realmode_pci_bios_call_entry: + MAKE_BIOS_STACK + call realmode_pci_bios + RESTORE_CALLERS_STACK + ret + + +.globl realmode_pci_bios +realmode_pci_bios: +gs movw OFFS_AX(%bp), %ax + cmpb $1, %al + je pci_bios_present + cmpb $2, %al + je pci_bios_find_device + cmpb $3, %al + je pci_bios_find_class + cmpb $6, %al + je pci_bios_generate_special_cycle + cmpb $8, %al + je pci_bios_read_cfg_byte + cmpb $9, %al + je pci_bios_read_cfg_word + cmpb $10, %al + je pci_bios_read_cfg_dword + cmpb $11, %al + je pci_bios_write_cfg_byte + cmpb $12, %al + je pci_bios_write_cfg_word + cmpb $13, %al + je pci_bios_write_cfg_dword + cmpb $14, %al + je pci_bios_get_irq_routing + cmpb $15, %al + je pci_bios_set_irq + jmp unknown_function + +/*****************************************************************************/ + +pci_bios_present: +#ifdef PCI_BIOS_DEBUG +cs incl num_pci_bios_present +#endif + movl $0x20494350, %eax +gs movl %eax, OFFS_EDX(%bp) + movb $0x01, %al +gs movb %al, OFFS_AL(%bp) /* We support cfg type 1 */ + movw $0x0210, %ax /* version 2.10 */ +gs movw %ax, OFFS_BX(%bp) +cs movb pci_last_bus, %al /* last bus number */ +gs movb %al, OFFS_CL(%bp) + jmp clear_carry + +/*****************************************************************************/ + +/* device 0-31, function 0-7 */ +pci_bios_find_device: +#ifdef PCI_BIOS_DEBUG +cs incl num_pci_bios_find_device +#endif +gs movw OFFS_CX(%bp), %di + shll $16, %edi +gs movw OFFS_DX(%bp), %di /* edi now holds device in upper 16 + * bits and vendor in lower 16 bits */ +gs movw OFFS_SI(%bp), %si + xorw %bx, %bx /* start at bus 0 dev 0 function 0 */ +pfd_loop: + xorw %ax, %ax /* dword 0 is vendor/device */ + call __pci_bios_select_register + movw $0xcfc, %dx + inl %dx, %eax + cmpl %edi, %eax /* our device ? */ + je pfd_found_one +pfd_next_dev: + /* check for multi function devices */ + movw %bx, %ax + andw $3, %ax + jnz pfd_function_not_zero + movw $0x000c, %ax + call __pci_bios_select_register + movw $0xcfe, %dx + inb %dx, %al + andb $0x80, %al + jz pfd_not_multi_function +pfd_function_not_zero: + incw %bx /* next function, overflows in to + * device number, then bus number */ + jmp pfd_check_bus + +pfd_not_multi_function: + andw $0xfff8, %bx /* remove function bits */ + addw $0x0008, %bx /* next device, overflows in to bus number */ +pfd_check_bus: +cs movb pci_last_bus, %ah + cmpb %ah, %bh + ja pfd_not_found + jmp pfd_loop +pfd_found_one: + decw %si + js pfd_done + jmp pfd_next_dev + +pfd_done: +gs movw %bx, OFFS_BX(%bp) + jmp clear_carry + +pfd_not_found: + movb $0x86, %ah /* device not found */ + jmp set_carry + +/*****************************************************************************/ + +pci_bios_find_class: +#ifdef PCI_BIOS_DEBUG +cs incl num_pci_bios_find_class +#endif +gs movl OFFS_ECX(%bp), %edi + andl $0x00ffffff, %edi /* edi now holds class-code in lower 24 bits */ +gs movw OFFS_SI(%bp), %si + xorw %bx, %bx /* start at bus 0 dev 0 function 0 */ +pfc_loop: + movw $8, %ax /* dword 8 is class-code high 24bits */ + call __pci_bios_select_register + movw $0xcfc, %dx + inl %dx, %eax + shrl $8, %eax + andl $0x00ffffff, %eax + cmpl %edi, %eax /* our device ? */ + je pfc_found_one +pfc_next_dev: + /* check for multi function devices */ + andw $3, %bx + jnz pfc_function_not_zero + movw $0x000c, %ax + call __pci_bios_select_register + movw $0xcfe, %dx + inb %dx, %al + andb $0x80, %al + jz pfc_not_multi_function +pfc_function_not_zero: + incw %bx /* next function, overflows in to + * device number, then bus number */ + jmp pfc_check_bus + +pfc_not_multi_function: + andw $0xfff8, %bx /* remove function bits */ + addw $0x0008, %bx /* next device, overflows in to bus number */ +pfc_check_bus: +cs movb pci_last_bus, %ah + cmpb %ah, %bh + ja pfc_not_found + jmp pfc_loop +pfc_found_one: + decw %si + js pfc_done + jmp pfc_next_dev + +pfc_done: +gs movw %bx, OFFS_BX(%bp) + jmp clear_carry + +pfc_not_found: + movb $0x86, %ah /* device not found */ + jmp set_carry + +/*****************************************************************************/ + +pci_bios_generate_special_cycle: +#ifdef PCI_BIOS_DEBUG +cs incl num_pci_bios_generate_special_cycle +#endif + movb $0x81, %ah /* function not supported */ + jmp set_carry + +/*****************************************************************************/ + +pci_bios_read_cfg_byte: +#ifdef PCI_BIOS_DEBUG +cs incl num_pci_bios_read_cfg_byte +#endif + call pci_bios_select_register +gs movw OFFS_DI(%bp), %dx + andw $3, %dx + addw $0xcfc, %dx + inb %dx, %al +gs movb %al, OFFS_CL(%bp) + jmp clear_carry + +/*****************************************************************************/ + +pci_bios_read_cfg_word: +#ifdef PCI_BIOS_DEBUG +cs incl num_pci_bios_read_cfg_word +#endif + call pci_bios_select_register +gs movw OFFS_DI(%bp), %dx + andw $2, %dx + addw $0xcfc, %dx + inw %dx, %ax +gs movw %ax, OFFS_CX(%bp) + jmp clear_carry + + +/*****************************************************************************/ + +pci_bios_read_cfg_dword: +#ifdef PCI_BIOS_DEBUG +cs incl num_pci_bios_read_cfg_dword +#endif + call pci_bios_select_register + movw $0xcfc, %dx + inl %dx, %eax +gs movl %eax, OFFS_ECX(%bp) + jmp clear_carry + +/*****************************************************************************/ + +pci_bios_write_cfg_byte: +#ifdef PCI_BIOS_DEBUG +cs incl num_pci_bios_write_cfg_byte +#endif + call pci_bios_select_register +gs movw OFFS_DI(%bp), %dx +gs movb OFFS_CL(%bp), %al + andw $3, %dx + addw $0xcfc, %dx + outb %al, %dx + jmp clear_carry + +/*****************************************************************************/ + +pci_bios_write_cfg_word: +#ifdef PCI_BIOS_DEBUG +cs incl num_pci_bios_write_cfg_word +#endif + call pci_bios_select_register +gs movw OFFS_DI(%bp), %dx +gs movw OFFS_CX(%bp), %ax + andw $2, %dx + addw $0xcfc, %dx + outw %ax, %dx + jmp clear_carry + +/*****************************************************************************/ + +pci_bios_write_cfg_dword: +#ifdef PCI_BIOS_DEBUG +cs incl num_pci_bios_write_cfg_dword +#endif + call pci_bios_select_register +gs movl OFFS_ECX(%bp), %eax + movw $0xcfc, %dx + outl %eax, %dx + jmp clear_carry + +/*****************************************************************************/ + +pci_bios_get_irq_routing: +#ifdef PCI_BIOS_DEBUG +cs incl num_pci_bios_get_irq_routing +#endif + movb $0x81, %ah /* function not supported */ + jmp set_carry + +/*****************************************************************************/ + +pci_bios_set_irq: +#ifdef PCI_BIOS_DEBUG +cs incl num_pci_bios_set_irq +#endif + movb $0x81, %ah /* function not supported */ + jmp set_carry + +/*****************************************************************************/ + +unknown_function: +#ifdef PCI_BIOS_DEBUG +cs incl num_pci_bios_unknown_function +#endif + movb $0x81, %ah /* function not supported */ + jmp set_carry + +/*****************************************************************************/ + +pci_bios_select_register: +gs movw OFFS_BX(%bp), %bx +gs movw OFFS_DI(%bp), %ax +/* destroys eax, dx */ +__pci_bios_select_register: /* BX holds device id, AX holds register index */ + pushl %ebx + andl $0xfc, %eax + andl $0xffff, %ebx + shll $8, %ebx + orl %ebx, %eax + orl $0x80000000, %eax + movw $0xcf8, %dx + outl %eax, %dx + popl %ebx + ret + + +clear_carry: +gs movw OFFS_FLAGS(%bp), %ax + andw $0xfffe, %ax /* clear carry -- function succeeded */ +gs movw %ax, OFFS_FLAGS(%bp) + xorw %ax, %ax +gs movb %ah, OFFS_AH(%bp) + ret + +set_carry: +gs movb %ah, OFFS_AH(%bp) +gs movw OFFS_FLAGS(%bp), %ax + orw $1, %ax /* return carry -- function not supported */ +gs movw %ax, OFFS_FLAGS(%bp) + movw $-1, %ax + ret + +/*****************************************************************************/ + +.globl pci_last_bus +pci_last_bus: + .byte 0 + +#ifdef PCI_BIOS_DEBUG +.globl num_pci_bios_present +num_pci_bios_present: + .long 0 + +.globl num_pci_bios_find_device +num_pci_bios_find_device: + .long 0 + +.globl num_pci_bios_find_class +num_pci_bios_find_class: + .long 0 + +.globl num_pci_bios_generate_special_cycle +num_pci_bios_generate_special_cycle: + .long 0 + +.globl num_pci_bios_read_cfg_byte +num_pci_bios_read_cfg_byte: + .long 0 + +.globl num_pci_bios_read_cfg_word +num_pci_bios_read_cfg_word: + .long 0 + +.globl num_pci_bios_read_cfg_dword +num_pci_bios_read_cfg_dword: + .long 0 + +.globl num_pci_bios_write_cfg_byte +num_pci_bios_write_cfg_byte: + .long 0 + +.globl num_pci_bios_write_cfg_word +num_pci_bios_write_cfg_word: + .long 0 + +.globl num_pci_bios_write_cfg_dword +num_pci_bios_write_cfg_dword: + .long 0 + +.globl num_pci_bios_get_irq_routing +num_pci_bios_get_irq_routing: + .long 0 + +.globl num_pci_bios_set_irq +num_pci_bios_set_irq: + .long 0 + +.globl num_pci_bios_unknown_function +num_pci_bios_unknown_function: + .long 0 +#endif diff --git a/lib_i386/bios_setup.c b/lib_i386/bios_setup.c index 94319af..3da7858 100644 --- a/lib_i386/bios_setup.c +++ b/lib_i386/bios_setup.c @@ -32,6 +32,7 @@ */ #include <common.h> +#include <pci.h> #include <asm/realmode.h> #include <asm/io.h> @@ -42,8 +43,13 @@ #define BIOS_BASE ((char*)0xf0000) #define BIOS_CS 0xf000 +/* these are defined in a 16bit segment and needs + * to be accessed with the RELOC_16_xxxx() macros below + */ extern u16 ram_in_64kb_chunks; extern u16 bios_equipment; +extern u8 pci_last_bus; + extern void *rm_int00; extern void *rm_int01; extern void *rm_int02; @@ -78,6 +84,34 @@ extern void *rm_int1e; extern void *rm_int1f; extern void *rm_def_int; +extern void *realmode_reset; +extern void *realmode_pci_bios_call_entry; + +static int set_jmp_vector(int entry_point, void *target) +{ + if (entry_point & ~0xffff) { + return -1; + } + + if (((u32)target-0xf0000) & ~0xffff) { + return -1; + } + printf("set_jmp_vector: 0xf000:%04x -> %p\n", + entry_point, target); + + /* jmp opcode */ + writeb(0xea, 0xf0000 + entry_point); + + /* offset */ + writew(((u32)target-0xf0000), 0xf0000 + entry_point + 1); + + /* segment */ + writew(0xf000, 0xf0000 + entry_point + 3); + + return 0; +} + + /* ************************************************************ * Install an interrupt vector @@ -96,11 +130,16 @@ static void setvector(int vector, u16 segment, void *handler) #endif } +#define RELOC_16_LONG(seg, off) *(u32*)(seg << 4 | (u32)&off) +#define RELOC_16_WORD(seg, off) *(u16*)(seg << 4 | (u32)&off) +#define RELOC_16_BYTE(seg, off) *(u8*)(seg << 4 | (u32)&off) + int bios_setup(void) { DECLARE_GLOBAL_DATA_PTR; static int done=0; int vector; + struct pci_controller *pri_hose; if (done) { return 0; @@ -169,9 +208,26 @@ int bios_setup(void) setvector(0x1e, BIOS_CS, &rm_int1e); setvector(0x1f, BIOS_CS, &rm_int1f); + set_jmp_vector(0xfff0, &realmode_reset); + set_jmp_vector(0xfe6e, &realmode_pci_bios_call_entry); + /* fill in data area */ - ram_in_64kb_chunks = gd->ram_size >> 16; - bios_equipment = 0; /* FixMe */ + RELOC_16_WORD(0xf000, ram_in_64kb_chunks) = gd->ram_size >> 16; + RELOC_16_WORD(0xf000, bios_equipment) = 0; /* FixMe */ + + /* If we assume only one PCI hose, this PCI hose + * will own PCI bus #0, and the last PCI bus of + * that PCI hose will be the last PCI bus in the + * system. + * (This, ofcause break on multi hose systems, + * but our PCI BIOS only support one hose anyway) + */ + pri_hose = pci_bus_to_hose(0); + if (NULL != pri_hose) { + /* fill in last pci bus number for use by the realmode + * PCI BIOS */ + RELOC_16_BYTE(0xf000, pci_last_bus) = pri_hose->last_busno; + } return 0; } diff --git a/lib_i386/board.c b/lib_i386/board.c index 193860a..85d7d7f 100644 --- a/lib_i386/board.c +++ b/lib_i386/board.c @@ -37,6 +37,7 @@ #include <syscall.h> #include <net.h> #include <ide.h> +#include <asm/u-boot-i386.h> extern long _i386boot_start; extern long _i386boot_end; @@ -82,21 +83,14 @@ static int mem_malloc_init(void) { DECLARE_GLOBAL_DATA_PTR; -#if 1 /* start malloc area right after the stack */ mem_malloc_start = i386boot_bss_start + i386boot_bss_size + CFG_STACK_SIZE; mem_malloc_start = (mem_malloc_start+3)&~3; -#else - mem_malloc_start = 0x400000; -#endif -#if 1 + /* Use all available RAM for malloc() */ mem_malloc_end = gd->ram_size; -#else - /* Use only CONFIG_MALLOC_SIZE bytes of RAM for malloc() */ - mem_malloc_end = mem_malloc_start + CONFIG_MALLOC_SIZE; -#endif + mem_malloc_brk = mem_malloc_start; return 0; @@ -149,10 +143,10 @@ static int init_baudrate (void) { DECLARE_GLOBAL_DATA_PTR; - uchar tmp[64]; /* long enough for environment variables */ - int i = getenv_r ("baudrate", tmp, sizeof (tmp)); + char tmp[64]; /* long enough for environment variables */ + int i = getenv_r("baudrate", tmp, 64); - gd->baudrate = (i > 0) + gd->baudrate = (i != 0) ? (int) simple_strtoul (tmp, NULL, 10) : CONFIG_BAUDRATE; @@ -237,6 +231,7 @@ init_fnc_t *init_sequence[] = { mem_malloc_init, /* dependant on dram_init */ interrupt_init, /* set up exceptions */ timer_init, + serial_init, env_init, /* initialize environment */ init_baudrate, /* initialze baudrate settings */ serial_init, /* serial communications setup */ @@ -267,6 +262,7 @@ void start_i386boot (void) memset (gd->bd, 0, sizeof (bd_t)); show_boot_progress(0x22); + gd->baudrate = CONFIG_BAUDRATE; for (init_fnc_ptr = init_sequence, i=0; *init_fnc_ptr; ++init_fnc_ptr, i++) { show_boot_progress(0xa130|i); @@ -323,7 +319,8 @@ void start_i386boot (void) /* allocate syscalls table (console_init_r will fill it in */ syscall_tbl = (void **) malloc (NR_SYSCALLS * sizeof (void *)); - + memset(syscall_tbl, 0, NR_SYSCALLS * sizeof (void *)); + /* Initialize the console (after the relocation and devices init) */ console_init_r(); syscalls_init(); @@ -355,7 +352,7 @@ void start_i386boot (void) #endif /* enable exceptions */ - enable_interrupts (); + enable_interrupts(); show_boot_progress(0x28); /* Must happen after interrupts are initialized since @@ -369,7 +366,7 @@ void start_i386boot (void) status_led_set (STATUS_LED_BOOT, STATUS_LED_BLINKING); #endif - udelay (20); + udelay(20); set_timer (0); @@ -399,7 +396,7 @@ void start_i386boot (void) #if (CONFIG_COMMANDS & CFG_CMD_DOC) WATCHDOG_RESET(); - puts ("DOC: "); + puts("DOC: "); doc_init(); #endif @@ -428,12 +425,13 @@ void start_i386boot (void) board_poweroff(); } #endif - + + show_boot_progress(0x29); /* main_loop() can return to retry autoboot, if so just run it again. */ for (;;) { - main_loop (); + main_loop(); } /* NOTREACHED - no way out of command loop except booting */ diff --git a/lib_i386/ic/ali512x.c b/lib_i386/ic/ali512x.c deleted file mode 100644 index 4537095..0000000 --- a/lib_i386/ic/ali512x.c +++ /dev/null @@ -1,442 +0,0 @@ -/* - * (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 - */ - -/* - * Based on sc520cdp.c from rolo 1.6: - *---------------------------------------------------------------------- - * (C) Copyright 2000 - * Sysgo Real-Time Solutions GmbH - * Klein-Winternheim, Germany - *---------------------------------------------------------------------- - */ - -#include <common.h> -#include <asm/io.h> -#include <asm/ic/ali512x.h> - - -/* ALI M5123 Logical device numbers: - * 0 FDC - * 1 unused? - * 2 unused? - * 3 lpt - * 4 UART1 - * 5 UART2 - * 6 RTC - * 7 mouse/kbd - * 8 CIO - */ - -/* - ************************************************************ - * Some access primitives for the ALi chip: * - ************************************************************ - */ - -static void ali_write(u8 index, u8 value) -{ - /* write an arbirary register */ - outb(index, ALI_INDEX); - outb(value, ALI_DATA); -} - -static int ali_read(u8 index) -{ - outb(index, ALI_INDEX); - return inb(ALI_DATA); -} - -#define ALI_OPEN() \ - outb(0x51, ALI_DATA); \ - outb(0x23, ALI_DATA) - - -#define ALI_CLOSE() \ - outb(0xbb, ALI_DATA) - -/* Select a logical device */ -#define ALI_SELDEV(dev) \ - ali_write(0x07, dev) - - -void ali512x_init(void) -{ - ALI_OPEN(); - - ali_write(0x02, 0x01); /* soft reset */ - ali_write(0x03, 0x03); /* disable access to CIOs */ - ali_write(0x22, 0x00); /* disable direct powerdown */ - ali_write(0x23, 0x00); /* disable auto powerdown */ - ali_write(0x24, 0x00); /* IR 8 is active hi, pin26 is PDIR */ - - ALI_CLOSE(); -} - -void ali512x_set_fdc(int enabled, u16 io, u8 irq, u8 dma_channel) -{ - ALI_OPEN(); - ALI_SELDEV(0); - - ali_write(0x30, enabled?1:0); - if (enabled) { - ali_write(0x60, io >> 8); - ali_write(0x61, io & 0xff); - ali_write(0x70, irq); - ali_write(0x74, dma_channel); - - /* AT mode, no drive swap */ - ali_write(0xf0, 0x08); - ali_write(0xf1, 0x00); - ali_write(0xf2, 0xff); - ali_write(0xf4, 0x00); - } - ALI_CLOSE(); -} - - -void ali512x_set_pp(int enabled, u16 io, u8 irq, u8 dma_channel) -{ - ALI_OPEN(); - ALI_SELDEV(3); - - ali_write(0x30, enabled?1:0); - if (enabled) { - ali_write(0x60, io >> 8); - ali_write(0x61, io & 0xff); - ali_write(0x70, irq); - ali_write(0x74, dma_channel); - - /* mode: EPP 1.9, ECP FIFO threshold = 7, IRQ active low */ - ali_write(0xf0, 0xbc); - /* 12 MHz, Burst DMA in ECP */ - ali_write(0xf1, 0x05); - } - ALI_CLOSE(); - -} - -void ali512x_set_uart(int enabled, int index, u16 io, u8 irq) -{ - ALI_OPEN(); - ALI_SELDEV(index?5:4); - - ali_write(0x30, enabled?1:0); - if (enabled) { - ali_write(0x60, io >> 8); - ali_write(0x61, io & 0xff); - ali_write(0x70, irq); - - ali_write(0xf0, 0x00); - ali_write(0xf1, 0x00); - - /* huh? write 0xf2 twice - a typo in rolo - * or some secret ali errata? Who knows? - */ - if (index) { - ali_write(0xf2, 0x00); - } - ali_write(0xf2, 0x0c); - } - ALI_CLOSE(); - -} - -void ali512x_set_uart2_irda(int enabled) -{ - ALI_OPEN(); - ALI_SELDEV(5); - - ali_write(0xf1, enabled?0x48:0x00); /* fullduplex IrDa */ - ALI_CLOSE(); - -} - -void ali512x_set_rtc(int enabled, u16 io, u8 irq) -{ - ALI_OPEN(); - ALI_SELDEV(6); - - ali_write(0x30, enabled?1:0); - if (enabled) { - ali_write(0x60, io >> 8); - ali_write(0x61, io & 0xff); - ali_write(0x70, irq); - - ali_write(0xf0, 0x00); - } - ALI_CLOSE(); -} - -void ali512x_set_kbc(int enabled, u8 kbc_irq, u8 mouse_irq) -{ - ALI_OPEN(); - ALI_SELDEV(7); - - ali_write(0x30, enabled?1:0); - if (enabled) { - ali_write(0x70, kbc_irq); - ali_write(0x72, mouse_irq); - - ali_write(0xf0, 0x00); - } - ALI_CLOSE(); -} - - -/* Common I/O - * - * (This descripotsion is base on several incompete sources - * since I have not been able to obtain any datasheet for the device - * there may be some mis-understandings burried in here. - * -- Daniel daniel@omicron.se) - * - * There are 22 CIO pins numbered - * 10-17 - * 20-25 - * 30-37 - * - * 20-24 are dedicated CIO pins, the other 17 are muliplexed with - * other functions. - * - * Secondary - * CIO Pin Function Decription - * ======================================================= - * CIO10 IRQIN1 Interrupt input 1? - * CIO11 IRQIN2 Interrupt input 2? - * CIO12 IRRX IrDa Receive - * CIO13 IRTX IrDa Transmit - * CIO14 P21 KBC P21 fucntion - * CIO15 P20 KBC P21 fucntion - * CIO16 I2C_CLK I2C Clock - * CIO17 I2C_DAT I2C Data - * - * CIO20 - - * CIO21 - - * CIO22 - - * CIO23 - - * CIO24 - - * CIO25 LOCK Keylock - * - * CIO30 KBC_CLK Keybaord Clock - * CIO31 CS0J General Chip Select decoder CS0J - * CIO32 CS1J General Chip Select decoder CS1J - * CIO33 ALT_KCLK Alternative Keyboard Clock - * CIO34 ALT_KDAT Alternative Keyboard Data - * CIO35 ALT_MCLK Alternative Mouse Clock - * CIO36 ALT_MDAT Alternative Mouse Data - * CIO37 ALT_KBC Alternative KBC select - * - * The CIO use a double indirect address scheme. - * - * Reigster 3 in the SIO is used to selectg where the CIO - * I/O registers show up under function 8. Note that these - * registers clash with the CIO function select regsters, - * below. - * - * SIO reigster 3 (CIO Address Selection) bit definitions: - * bit 7 CIO data register enabled - * bit 1-0 CIO indirect registers select - * 0 index = 0xE0 data = 0xE1 - * 1 index = 0xE2 data = 0xE3 - * 2 index = 0xE4 data = 0xE5 - * 3 index = 0xEA data = 0xEB - * - * There are three CIO I/O register accessed via CIO index and CIO data - * 0x01 CIO 10-17 data - * 0x02 CIO 20-25 data (bits 7-6 unused) - * 0x03 CIO 30-37 data - * - * - * The pin function is accessed through normal - * SIO registers, each register have the same format: - * - * Bit Function Value - * 0 Input/output 1=input - * 1 Polarity of signal 1=inverted - * 2 Unused ?? - * 3 Function (normal or special) 1=special - * 7-4 Unused - * - * SIO REG - * 0xe0 CIO 10 Config - * 0xe1 CIO 11 Config - * 0xe2 CIO 12 Config - * 0xe3 CIO 13 Config - * 0xe4 CIO 14 Config - * 0xe5 CIO 15 Config - * 0xe6 CIO 16 Config - * 0xe7 CIO 16 Config - * - * 0xe8 CIO 20 Config - * 0xe9 CIO 21 Config - * 0xea CIO 22 Config - * 0xeb CIO 23 Config - * 0xec CIO 24 Config - * 0xed CIO 25 Config - * - * 0xf5 CIO 30 Config - * 0xf6 CIO 31 Config - * 0xf7 CIO 32 Config - * 0xf8 CIO 33 Config - * 0xf9 CIO 34 Config - * 0xfa CIO 35 Config - * 0xfb CIO 36 Config - * 0xfc CIO 37 Config - * - */ - -void ali512x_set_cio(int enabled) -{ - int i; - - ALI_OPEN(); - ali_write(0x3, 3); /* Disable CIO data register */ - - ALI_SELDEV(8); - ali_write(0x30, enabled?1:0); - - /* set all pins to input to start with */ - for (i=0xe0;i<0xee;i++) { - ali_write(i, 1); - } - for (i=0xf5;i<0xfe;i++) { - ali_write(i, 1); - } - - ALI_CLOSE(); -} - -void ali512x_cio_function(int pin, int special, int inv, int input) -{ - u8 data; - u8 addr; - - - /* valid pins are 10-17, 20-25 and 30-37 */ - if (pin >= 10 && pin <= 17) { - addr = 0xe0+(pin-10); - } else if (pin >= 20 && pin <= 25) { - addr = 0xe8+(pin-20); - } else if (pin >= 30 && pin <= 37) { - addr = 0xf5+(pin-30); - } else { - return; - } - - ALI_OPEN(); - ALI_SELDEV(8); - - ali_write(0x03, 0x03); /* Disable CIO data register */ - - data=0; - if (special) { - data |= 0x08; - } else { - if (inv) { - data |= 0x02; - } - if (input) { - data |= 0x01; - } - } - - ali_write(addr, data); - - ALI_CLOSE(); -} - -void ali512x_cio_out(int pin, int value) -{ - u8 reg; - u8 data; - u8 bit; - - /* valid pins are 10-17, 20-25 and 30-37 */ - if (pin >= 10 && pin <= 17) { - reg = 1; - pin -= 10; - } else if (pin >= 20 && pin <= 25) { - reg = 2; - pin -= 20; - } else if (pin >= 30 && pin <= 37) { - reg = 3; - pin -= 30; - } else { - return; - } - bit = 1 << pin; - - ALI_OPEN(); - ALI_SELDEV(8); - - ali_write(0x03, 0x83); /* Enable CIO data register, use data port at 0xea */ - - ali_write(0xea, reg); /* select I/O register */ - data = ali_read(0xeb); - if (value) { - data |= bit; - } else { - data &= ~bit; - } - ali_write(0xeb, data); - ali_write(0xea, 0); /* select register 0 */ - ali_write(0x03, 0x03); /* Disable CIO data register */ - ALI_CLOSE(); -} - -int ali512x_cio_in(int pin) -{ - u8 reg; - u8 data; - u8 bit; - - /* valid pins are 10-17, 20-25 and 30-37 */ - if (pin >= 10 && pin <= 17) { - reg = 1; - pin -= 10; - } else if (pin >= 20 && pin <= 25) { - reg = 2; - pin -= 20; - } else if (pin >= 30 && pin <= 37) { - reg = 3; - pin -= 30; - } else { - return -1; - } - bit = 1 << pin; - - ALI_OPEN(); - ALI_SELDEV(8); - - ali_write(0x03, 0x83); /* Enable CIO data register, use data port at 0xea */ - - ali_write(0xea, reg); /* select I/O register */ - data = ali_read(0xeb); - ali_write(0xea, 0); /* select register 0 */ - ali_write(0x03, 0x03); /* Disable CIO data register */ - ALI_CLOSE(); - - return data & bit; -} - - diff --git a/lib_i386/ic/sc520.c b/lib_i386/ic/sc520.c deleted file mode 100644 index d202625..0000000 --- a/lib_i386/ic/sc520.c +++ /dev/null @@ -1,348 +0,0 @@ -/* - * (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 <config.h> -#include <pci.h> -#include <asm/io.h> -#include <asm/pci.h> -#include <asm/ic/sc520.h> - -/* - * utility functions for boards based on the AMD sc520 - * - * void write_mmcr_byte(u16 mmcr, u8 data) - * void write_mmcr_word(u16 mmcr, u16 data) - * void write_mmcr_long(u16 mmcr, u32 data) - * - * u8 read_mmcr_byte(u16 mmcr) - * u16 read_mmcr_word(u16 mmcr) - * u32 read_mmcr_long(u16 mmcr) - * - * void init_sc520(void) - * unsigned long init_sc520_dram(void) - * void pci_sc520_init(struct pci_controller *hose) - * - * void reset_timer(void) - * ulong get_timer(ulong base) - * void set_timer(ulong t) - * void udelay(unsigned long usec) - * - */ - -static u32 mmcr_base= 0xfffef000; - -void write_mmcr_byte(u16 mmcr, u8 data) -{ - writeb(data, mmcr+mmcr_base); -} - -void write_mmcr_word(u16 mmcr, u16 data) -{ - writew(data, mmcr+mmcr_base); -} - -void write_mmcr_long(u16 mmcr, u32 data) -{ - writel(data, mmcr+mmcr_base); -} - -u8 read_mmcr_byte(u16 mmcr) -{ - return readb(mmcr+mmcr_base); -} - -u16 read_mmcr_word(u16 mmcr) -{ - return readw(mmcr+mmcr_base); -} - -u32 read_mmcr_long(u16 mmcr) -{ - return readl(mmcr+mmcr_base); -} - - -void init_sc520(void) -{ - DECLARE_GLOBAL_DATA_PTR; - - /* Set the UARTxCTL register at it's slower, - * baud clock giving us a 1.8432 MHz reference - */ - write_mmcr_byte(SC520_UART1CTL, 7); - write_mmcr_byte(SC520_UART2CTL, 7); - - /* first set the timer pin mapping */ - write_mmcr_byte(SC520_CLKSEL, 0x72); /* no clock frequency selected, use 1.1892MHz */ - - /* enable PCI bus arbitrer */ - write_mmcr_byte(SC520_SYSARBCTL,0x02); /* enable concurrent mode */ - - write_mmcr_word(SC520_SYSARBMENB,0x1f); /* enable external grants */ - write_mmcr_word(SC520_HBCTL,0x04); /* enable posted-writes */ - - - if (CFG_SC520_HIGH_SPEED) { - write_mmcr_byte(SC520_CPUCTL, 0x2); /* set it to 133 MHz and write back */ - gd->cpu_clk = 133000000; - printf("## CPU Speed set to 133MHz\n"); - } else { - write_mmcr_byte(SC520_CPUCTL, 1); /* set CPU to 100 MHz and write back cache */ - printf("## CPU Speed set to 100MHz\n"); - gd->cpu_clk = 100000000; - } - - - /* wait at least one millisecond */ - asm("movl $0x2000,%%ecx\n" - "wait_loop: pushl %%ecx\n" - "popl %%ecx\n" - "loop wait_loop\n": : : "ecx"); - - /* turn on the SDRAM write buffer */ - write_mmcr_byte(SC520_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) -{ - DECLARE_GLOBAL_DATA_PTR; - bd_t *bd = gd->bd; - - u32 dram_present=0; - u32 dram_ctrl; - - int val; - - int cas_precharge_delay = CFG_SDRAM_PRECHARGE_DELAY; - int refresh_rate = CFG_SDRAM_REFRESH_RATE; - int ras_cas_delay = CFG_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 */ - } - write_mmcr_byte(SC520_DRCCTL, (read_mmcr_byte(SC520_DRCCTL) & 0xcf) | (val<<4)); - - val = read_mmcr_byte(SC520_DRCTMCTL); - val &= 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; - } - write_mmcr_byte(SC520_DRCTMCTL, val); - - - /* We read-back the configuration of the dram - * controller that the assembly code wrote */ - dram_ctrl = read_mmcr_long(SC520_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_PCI - - - -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_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); - -} - - -#endif - -#ifdef CFG_TIMER_SC520 - - -void reset_timer(void) -{ - write_mmcr_word(SC520_GPTMR0CNT, 0); - write_mmcr_word(SC520_GPTMR0CTL, 0x6001); - -} - -ulong get_timer(ulong base) -{ - /* fixme: 30 or 33 */ - return read_mmcr_word(SC520_GPTMR0CNT) / 33; -} - -void set_timer(ulong t) -{ - /* FixMe: use two cascade coupled timers */ - write_mmcr_word(SC520_GPTMR0CTL, 0x4001); - write_mmcr_word(SC520_GPTMR0CNT, t*33); - write_mmcr_word(SC520_GPTMR0CTL, 0x6001); -} - - -void udelay(unsigned long usec) -{ - int m=0; - long u; - - read_mmcr_word(SC520_SWTMRMILLI); - read_mmcr_word(SC520_SWTMRMICRO); - -#if 0 - /* do not enable this line, udelay is used in the serial driver -> recursion */ - printf("udelay: %ld m.u %d.%d tm.tu %d.%d\n", usec, m, u, tm, tu); -#endif - while (1) { - - m += read_mmcr_word(SC520_SWTMRMILLI); - u = read_mmcr_word(SC520_SWTMRMICRO) + (m * 1000); - - if (usec <= u) { - break; - } - } -} - -#endif - - diff --git a/lib_i386/ic/sc520_asm.S b/lib_i386/ic/sc520_asm.S deleted file mode 100644 index 72110c4..0000000 --- a/lib_i386/ic/sc520_asm.S +++ /dev/null @@ -1,530 +0,0 @@ -/* - * (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 - ******************************************************************************* - */ - -.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 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 -fs movb %al, (%edi) /* disable write buffer */ - - movl $ECCCTL, %edi -fs movb %al, (%edi) /* disable ECC */ - - movl $DRCTMCTL, %edi - movb $0x1E,%al /* Set SDRAM timing for slowest */ -fs 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 */ -fs movl %eax, (%edi) - - movl $DRCCFG, %edi /* setup */ - movw $0xbbbb,%ax /* dram config register for */ -fs 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 */ -fs movb %al, (%edi) - movl $CACHELINESZ, %esi /* just a dummy address to write for */ -fs 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 */ -fs movb %al, (%edi) -fs movw %ax, (%esi) - - /* - * issue 2 auto refreshes to all banks - */ - movb $0x4,%al /* Auto refresh cmd */ -fs movb %al, (%edi) - movw $2,%cx -refresh1: -fs movw %ax, (%esi) - loop refresh1 - - /* - * issue LOAD MODE REGISTER command - */ - movb $0x3,%al /* Load mode register cmd */ -fs movb %al, (%edi) -fs movw %ax, (%esi) - - /* - * issue 8 more auto refreshes to all banks - */ - movb $0x4,%al /* Auto refresh cmd */ -fs movb %al, (%edi) - movw $8,%cx -refresh2: -fs movw %ax, (%esi) - loop refresh2 - - /* - * set control register to NORMAL mode - */ - movb $0x0,%al /* Normal mode value */ -fs 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) */ -fs movl %eax, (%esi) /* write max col pattern at max col adr */ -fs 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 */ -fs movl %eax, (%esi) /* write 10 col pattern @ 10 col wrap adr */ -fs 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 */ -fs movl %eax, (%esi) /* write 9 col pattern @ 9 col wrap adr */ -fs 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 */ -fs movl %eax, (%esi) /* write min col pattern @ min col adr */ -fs 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) */ -fs movl %eax, (%esi) /* write max row pattern at max row adr */ -fs 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 */ -fs movl %eax, (%esi) /* write 13 row pattern @ 13 row wrap adr */ -fs 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 */ -fs movl %eax, (%esi) /* write 12 row pattern @ 12 row wrap adr */ -fs 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 */ -fs movl %eax, (%edi) /* write 11 row pattern @ 11 row wrap adr */ -fs 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) */ -fs movl %eax, (%edi) /* write 10 row pattern @ 10 row wrap adr */ -fs 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 */ -fs 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 */ -fs 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 */ -fs 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 */ -fs movb %al, (%esi) - movl $CACHELINESZ, %esi /* address to init read buffer */ -fs movw %ax, (%esi) - - /* - * update ENDING ADDRESS REGISTER - */ - movl $DRCBENDADR, %edi /* DRAM ending address register */ - movl %ecx,%ebx - addl %ebx, %edi -fs 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 -fs mov (%edi), %ax - andw %bx,%ax - orw %dx,%ax -fs movw %ax, (%edi) - jcxz cleanup - - decw %cx - movl %ecx,%ebx - movl $DRCBENDADR, %edi /* DRAM ending address register */ - movb $0xff,%al - addl %ebx, %edi -fs movb %al, (%edi) - /* - * set control register to NORMAL mode - */ - movl $DRCCTL, %esi /* setup DRAM control register with */ - movb $0x0,%al /* Normal mode value */ -fs movb %al, (%esi) - movl $CACHELINESZ, %esi /* address to init read buffer */ -fs movw %ax, (%esi) - jmp nextbank - -cleanup: - movl $DRCBENDADR, %edi /* DRAM ending address register */ - movw $4,%cx - xorw %ax,%ax -cleanuplp: -fs movb (%edi), %al - orb %al,%al - jz emptybank - - addb %ah,%al - jns nottoomuch - - movb $0x7f,%al -nottoomuch: - movb %al,%ah - orb $0x80,%al -fs movb %al, (%edi) -emptybank: - incl %edi - loop cleanuplp - -#if defined(CFG_SDRAM_CAS_LATENCY_2T) || defined(CFG_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 CFG_SDRAM_CAS_LATENCY_2T - andb $0xef, %al -#endif -#ifdef CFG_SDRAM_CAS_LATENCY_3T - orb $0x10, %al -#endif - movb %al, (%edi) -#endif - movl $DRCCTL, %edi /* DRAM Control register */ - movb $0x3,%al /* Load mode register cmd */ -fs movb %al, (%edi) -fs movw %ax, (%esi) - - - movl $DRCCTL, %edi /* DRAM Control register */ - movb $0x18,%al /* Enable refresh and NORMAL mode */ -fs 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 - - jmp *%ebp diff --git a/lib_i386/pci.c b/lib_i386/pci.c new file mode 100644 index 0000000..acd1d25 --- /dev/null +++ b/lib_i386/pci.c @@ -0,0 +1,156 @@ +/* + * (C) Copyright 2002 + * Daniel Engström, Omicron Ceti AB, daniel@omicron.se + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <pci.h> +#include <asm/io.h> +#include <asm/pci.h> + +#ifdef CONFIG_PCI +#undef PCI_ROM_SCAN_VERBOSE + +int pci_shadow_rom(pci_dev_t dev, unsigned char *dest) +{ + struct pci_controller *hose; + int res = -1; + int i; + + u32 rom_addr; + u32 addr_reg; + u32 size; + + u16 vendor; + u16 device; + u32 class_code; + + hose = pci_bus_to_hose(PCI_BUS(dev)); +#if 0 + printf("pci_shadow_rom() asked to shadow device %x to %x\n", + dev, (u32)dest); +#endif + pci_read_config_word(dev, PCI_VENDOR_ID, &vendor); + pci_read_config_word(dev, PCI_DEVICE_ID, &device); + pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_code); + + class_code &= 0xffffff00; + class_code >>= 8; + +#if 0 + printf("PCI Header Vendor %04x device %04x class %06x\n", + vendor, device, class_code); +#endif + /* Enable the rom addess decoder */ + pci_write_config_dword(dev, PCI_ROM_ADDRESS, PCI_ROM_ADDRESS_MASK); + pci_read_config_dword(dev, PCI_ROM_ADDRESS, &addr_reg); + + if (!addr_reg) { + /* register unimplemented */ + printf("pci_chadow_rom: device do not seem to have a rom\n"); + return -1; + } + + size = (~(addr_reg&PCI_ROM_ADDRESS_MASK))+1; + +#if 0 + printf("ROM is %d bytes\n", size); +#endif + rom_addr = pci_get_rom_window(hose, size); +#if 0 + printf("ROM mapped at %x \n", rom_addr); +#endif + pci_write_config_dword(dev, PCI_ROM_ADDRESS, + pci_phys_to_mem(dev, rom_addr) + |PCI_ROM_ADDRESS_ENABLE); + + + + for (i=rom_addr;i<rom_addr+size; i+=512) { + + + if (readw(i) == 0xaa55) { + u32 pci_data; +#ifdef PCI_ROM_SCAN_VERBOSE + printf("ROM signature found\n"); +#endif + pci_data = readw(0x18+i); + pci_data += i; + + if (0==memcmp((void*)pci_data, "PCIR", 4)) { +#ifdef PCI_ROM_SCAN_VERBOSE + printf("Fount PCI rom image at offset %d\n", i-rom_addr); + printf("Vendor %04x device %04x class %06x\n", + readw(pci_data+4), readw(pci_data+6), + readl(pci_data+0x0d)&0xffffff); + printf("%s\n", + (readw(pci_data+0x15) &0x80)? + "Last image":"More images follow"); + switch (readb(pci_data+0x14)) { + case 0: + printf("X86 code\n"); + break; + case 1: + printf("Openfirmware code\n"); + break; + case 2: + printf("PARISC code\n"); + break; + } + printf("Image size %d\n", readw(pci_data+0x10) * 512); +#endif + /* FixMe: I think we should compare the class code + * bytes as well but I have no reference on the + * exact order of these bytes in the PCI ROM header */ + if (readw(pci_data+4) == vendor && + readw(pci_data+6) == device && + /* (readl(pci_data+0x0d)&0xffffff) == class_code && */ + readb(pci_data+0x14) == 0 /* x86 code image */ ) { +#ifdef PCI_ROM_SCAN_VERBOSE + printf("Suitable ROM image found, copying\n"); +#endif + memmove(dest, (void*)rom_addr, readw(pci_data+0x10) * 512); + res = 0; + break; + + } + if (readw(pci_data+0x15) &0x80) { + break; + } + } + } + + } + +#ifdef PCI_ROM_SCAN_VERBOSE + if (res) { + printf("No suitable image found\n"); + } +#endif + /* disable PAR register and PCI device ROM address devocer */ + pci_remove_rom_window(hose, rom_addr); + + pci_write_config_dword(dev, PCI_ROM_ADDRESS, 0); + + return res; +} + +#endif diff --git a/lib_i386/realmode.c b/lib_i386/realmode.c index 27d4693..d7bb81c 100644 --- a/lib_i386/realmode.c +++ b/lib_i386/realmode.c @@ -33,25 +33,33 @@ extern char realmode_enter; - -int enter_realmode(u16 seg, u16 off, struct pt_regs *in, struct pt_regs *out) +int realmode_setup(void) { - - /* setup out thin bios emulation */ - if (bios_setup()) { - return -1; - } - /* copy the realmode switch code */ if (i386boot_realmode_size > (REALMODE_MAILBOX-REALMODE_BASE)) { printf("realmode switch too large (%ld bytes, max is %d)\n", - i386boot_realmode_size, (int)(REALMODE_MAILBOX-REALMODE_BASE)); + i386boot_realmode_size, (REALMODE_MAILBOX-REALMODE_BASE)); return -1; } memcpy(REALMODE_BASE, (void*)i386boot_realmode, i386boot_realmode_size); + asm("wbinvd\n"); + + return 0; +} +int enter_realmode(u16 seg, u16 off, struct pt_regs *in, struct pt_regs *out) +{ + /* setup out thin bios emulation */ + if (bios_setup()) { + return -1; + } + + if (realmode_setup()) { + return -1; + } + in->eip = off; in->xcs = seg; if (3>(in->esp & 0xffff)) { @@ -59,12 +67,30 @@ int enter_realmode(u16 seg, u16 off, struct pt_regs *in, struct pt_regs *out) } memcpy(REALMODE_MAILBOX, in, sizeof(struct pt_regs)); + asm("wbinvd\n"); __asm__ volatile ( "lcall $0x20,%0\n" : : "i" (&realmode_enter) ); + asm("wbinvd\n"); memcpy(out, REALMODE_MAILBOX, sizeof(struct pt_regs)); return out->eax; } + +/* This code is supposed to access a realmode interrupt + * it does currently not work for me */ +int enter_realmode_int(u8 lvl, struct pt_regs *in, struct pt_regs *out) +{ + /* place two instructions at 0x700 */ + writeb(0xcd, 0x700); /* int $lvl */ + writeb(lvl, 0x701); + writeb(0xcb, 0x702); /* lret */ + asm("wbinvd\n"); + + enter_realmode(0x00, 0x700, in, out); + + return out->eflags&1; +} + diff --git a/lib_i386/realmode_switch.S b/lib_i386/realmode_switch.S index 9f212c2..17adcbd 100644 --- a/lib_i386/realmode_switch.S +++ b/lib_i386/realmode_switch.S @@ -50,7 +50,6 @@ .section .realmode, "ax" .code16 - /* 16bit protected mode code here */ .globl realmode_enter realmode_enter: diff --git a/lib_i386/video.c b/lib_i386/video.c new file mode 100644 index 0000000..776022e --- /dev/null +++ b/lib_i386/video.c @@ -0,0 +1,238 @@ +/* + * (C) Copyright 2002 + * Daniel Engström, Omicron Ceti AB, daniel@omicron.se + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <pci.h> +#include <devices.h> +#include <i8042.h> +#include <asm/ptrace.h> +#include <asm/realmode.h> +#include <asm/io.h> +#include <asm/pci.h> + + +/* basic textmode I/O from linux kernel */ +static char *vidmem = (char *)0xb8000; +static int vidport; +static int lines, cols; +static int orig_x, orig_y; + +static void beep(int dur) +{ + int i; + + outb_p(3, 0x61); + for (i=0;i<10*dur;i++) { + udelay(1000); + } + outb_p(0, 0x61); +} + +static void scroll(void) +{ + int i; + + memcpy ( vidmem, vidmem + cols * 2, ( lines - 1 ) * cols * 2 ); + for ( i = ( lines - 1 ) * cols * 2; i < lines * cols * 2; i += 2 ) + vidmem[i] = ' '; +} + +static void __video_putc(const char c, int *x, int *y) +{ + if (c == '\n') { + (*x) = 0; + if ( ++(*y) >= lines ) { + scroll(); + (*y)--; + } + } else if (c == '\b') { + if ((*x) != 0) { + --(*x); + vidmem [ ( (*x) + cols * (*y) ) * 2 ] = ' '; + } + } else if (c == '\r') { + (*x) = 0; + + } else if (c == '\a') { + beep(3); + + } else if (c == '\t') { + __video_putc(' ', x, y); + __video_putc(' ', x, y); + __video_putc(' ', x, y); + __video_putc(' ', x, y); + __video_putc(' ', x, y); + __video_putc(' ', x, y); + __video_putc(' ', x, y); + __video_putc(' ', x, y); + } else if (c == '\v') { + switch ((*x) % 8) { + case 0: + __video_putc(' ', x, y); + case 7: + __video_putc(' ', x, y); + case 6: + __video_putc(' ', x, y); + case 5: + __video_putc(' ', x, y); + case 4: + __video_putc(' ', x, y); + case 3: + __video_putc(' ', x, y); + case 2: + __video_putc(' ', x, y); + case 1: + __video_putc(' ', x, y); + } + } else if (c == '\f') { + int i; + for (i=0;i<lines*cols*2;i+=2) { + vidmem[i] = 0; + } + (*x) = 0; + (*y) = 0; + } else { + vidmem [ ( (*x) + cols * (*y) ) * 2 ] = c; + if ( ++(*x) >= cols ) { + (*x) = 0; + if ( ++(*y) >= lines ) { + scroll(); + (*y)--; + } + } + } +} + +static void video_putc(const char c) +{ + int x,y,pos; + + x = orig_x; + y = orig_y; + + __video_putc(c, &x, &y); + + orig_x = x; + orig_y = y; + + pos = (x + cols * y) * 2; /* Update cursor position */ + outb_p(14, vidport); + outb_p(0xff & (pos >> 9), vidport+1); + outb_p(15, vidport); + outb_p(0xff & (pos >> 1), vidport+1); +} + +static void video_puts(const char *s) +{ + int x,y,pos; + char c; + + x = orig_x; + y = orig_y; + + while ( ( c = *s++ ) != '\0' ) { + __video_putc(c, &x, &y); + } + + orig_x = x; + orig_y = y; + + pos = (x + cols * y) * 2; /* Update cursor position */ + outb_p(14, vidport); + outb_p(0xff & (pos >> 9), vidport+1); + outb_p(15, vidport); + outb_p(0xff & (pos >> 1), vidport+1); +} + +int video_init(void) +{ + u16 pos; + + static device_t vga_dev; + static device_t kbd_dev; + + vidmem = (char *) 0xb8000; + vidport = 0x3d4; + + lines = 25; + cols = 80; + + outb_p(14, vidport); + pos = inb_p(vidport+1); + pos <<= 8; + outb_p(15, vidport); + pos |= inb_p(vidport+1); + + orig_x = pos%cols; + orig_y = pos/cols; + +#if 0 + printf("pos %x %d %d\n", pos, orig_x, orig_y); +#endif + if (orig_y > lines) { + orig_x = orig_y =0; + } + + + memset(&vga_dev, 0, sizeof(vga_dev)); + strcpy(vga_dev.name, "vga"); + vga_dev.ext = 0; + vga_dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_SYSTEM; + vga_dev.putc = video_putc; /* 'putc' function */ + vga_dev.puts = video_puts; /* 'puts' function */ + vga_dev.tstc = NULL; /* 'tstc' function */ + vga_dev.getc = NULL; /* 'getc' function */ + + if (device_register(&vga_dev) == 0) { + return 1; + } + + if (i8042_kbd_init()) { + return 1; + } + + memset(&kbd_dev, 0, sizeof(kbd_dev)); + strcpy(kbd_dev.name, "kbd"); + kbd_dev.ext = 0; + kbd_dev.flags = DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM; + kbd_dev.putc = NULL; /* 'putc' function */ + kbd_dev.puts = NULL; /* 'puts' function */ + kbd_dev.tstc = i8042_tstc; /* 'tstc' function */ + kbd_dev.getc = i8042_getc; /* 'getc' function */ + + if (device_register(&kbd_dev) == 0) { + return 1; + } + return 0; +} + + +int drv_video_init(void) +{ + if (video_bios_init()) { + return 1; + } + + return video_init(); +} + diff --git a/lib_i386/video_bios.c b/lib_i386/video_bios.c new file mode 100644 index 0000000..d9709b9 --- /dev/null +++ b/lib_i386/video_bios.c @@ -0,0 +1,221 @@ +/* + * (C) Copyright 2002 + * Daniel Engström, Omicron Ceti AB, daniel@omicron.se + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <pci.h> +#include <malloc.h> +#include <asm/ptrace.h> +#include <asm/realmode.h> +#include <asm/io.h> +#include <asm/pci.h> + +#undef PCI_BIOS_DEBUG +#undef VGA_BIOS_DEBUG + +#ifdef VGA_BIOS_DEBUG +#define PRINTF(fmt,args...) printf (fmt ,##args) +#else +#define PRINTF(fmt,args...) +#endif + +#ifdef CONFIG_PCI + +#ifdef PCI_BIOS_DEBUG +#define RELOC_16(seg, off) *(u32*)(seg << 4 | (u32)&off) +extern u32 num_pci_bios_present; +extern u32 num_pci_bios_find_device; +extern u32 num_pci_bios_find_class; +extern u32 num_pci_bios_generate_special_cycle; +extern u32 num_pci_bios_read_cfg_byte; +extern u32 num_pci_bios_read_cfg_word; +extern u32 num_pci_bios_read_cfg_dword; +extern u32 num_pci_bios_write_cfg_byte; +extern u32 num_pci_bios_write_cfg_word; +extern u32 num_pci_bios_write_cfg_dword; +extern u32 num_pci_bios_get_irq_routing; +extern u32 num_pci_bios_set_irq; +extern u32 num_pci_bios_unknown_function; + +void print_bios_bios_stat(void) +{ + printf("16 bit functions:\n"); + printf("pci_bios_present: %d\n", RELOC_16(0xf000, num_pci_bios_present)); + printf("pci_bios_find_device: %d\n", RELOC_16(0xf000, num_pci_bios_find_device)); + printf("pci_bios_find_class: %d\n", RELOC_16(0xf000, num_pci_bios_find_class)); + printf("pci_bios_generate_special_cycle: %d\n", RELOC_16(0xf000, num_pci_bios_generate_special_cycle)); + printf("pci_bios_read_cfg_byte: %d\n", RELOC_16(0xf000, num_pci_bios_read_cfg_byte)); + printf("pci_bios_read_cfg_word: %d\n", RELOC_16(0xf000, num_pci_bios_read_cfg_word)); + printf("pci_bios_read_cfg_dword: %d\n", RELOC_16(0xf000, num_pci_bios_read_cfg_dword)); + printf("pci_bios_write_cfg_byte: %d\n", RELOC_16(0xf000, num_pci_bios_write_cfg_byte)); + printf("pci_bios_write_cfg_word: %d\n", RELOC_16(0xf000, num_pci_bios_write_cfg_word)); + printf("pci_bios_write_cfg_dword: %d\n", RELOC_16(0xf000, num_pci_bios_write_cfg_dword)); + printf("pci_bios_get_irq_routing: %d\n", RELOC_16(0xf000, num_pci_bios_get_irq_routing)); + printf("pci_bios_set_irq: %d\n", RELOC_16(0xf000, num_pci_bios_set_irq)); + printf("pci_bios_unknown_function: %d\n", RELOC_16(0xf000, num_pci_bios_unknown_function)); + +} +#endif + +#define PCI_CLASS_VIDEO 3 +#define PCI_CLASS_VIDEO_STD 0 +#define PCI_CLASS_VIDEO_PROG_IF_VGA 0 + + +static u32 probe_pci_video(void) +{ + pci_dev_t devbusfn; + + if ((devbusfn = pci_find_class(PCI_CLASS_VIDEO, + PCI_CLASS_VIDEO_STD, + PCI_CLASS_VIDEO_PROG_IF_VGA, 0)) != -1) { + u32 old; + u32 addr; + + /* PCI video device detected */ + printf("Found PCI VGA device at %02x.%02x.%x\n", + PCI_BUS(devbusfn), PCI_DEV(devbusfn), PCI_FUNC(devbusfn)); + + /* Enable I/O decoding as well, PCI viudeo boards + * support I/O accesses, but they provide no + * bar register for this since the ports are fixed. + */ + pci_write_config_word(devbusfn, PCI_COMMAND, PCI_COMMAND_MEMORY | PCI_COMMAND_IO | PCI_COMMAND_MASTER); + + /* Test the ROM decoder, do the device support a rom? */ + pci_read_config_dword(devbusfn, PCI_ROM_ADDRESS, &old); + pci_write_config_dword(devbusfn, PCI_ROM_ADDRESS, PCI_ROM_ADDRESS_MASK); + pci_read_config_dword(devbusfn, PCI_ROM_ADDRESS, &addr); + pci_write_config_dword(devbusfn, PCI_ROM_ADDRESS, old); + + if (!addr) { + printf("PCI VGA have no ROM?\n"); + return 0; + } + + /* device have a rom */ + if (pci_shadow_rom(devbusfn, (void*)0xc0000)) { + printf("Shadowing of PCI VGA BIOS failed\n"); + return 0; + } + + /* Now enable lagacy VGA port access */ + if (pci_enable_legacy_video_ports(pci_bus_to_hose(PCI_BUS(devbusfn)))) { + printf("PCI VGA enable failed\n"); + return 0; + } + + + /* return the pci device info, that we'll need later */ + return PCI_BUS(devbusfn) << 8 | + PCI_DEV(devbusfn) << 3 | (PCI_FUNC(devbusfn)&7); + } + + return 0; +} + + +#endif + +static int probe_isa_video(void) +{ + u32 ptr; + char *buf; + + if (0 == (ptr = isa_map_rom(0xc0000, 0x8000))) { + return -1; + } + if (NULL == (buf=malloc(0x8000))) { + isa_unmap_rom(ptr); + return -1; + } + if (readw(ptr) != 0xaa55) { + free(buf); + isa_unmap_rom(ptr); + return -1; + } + + /* shadow the rom */ + memcpy(buf, (void*)ptr, 0x8000); + isa_unmap_rom(ptr); + memcpy((void*)0xc0000, buf, 0x8000); + + free(buf); + + return 0; +} + +int video_bios_init(void) +{ + struct pt_regs regs; + + /* clear the video bios area in case we warmbooted */ + memset((void*)0xc0000, 0, 0x8000); + memset(®s, 0, sizeof(struct pt_regs)); + + if (probe_isa_video()) { + /* No ISA board found, try the PCI bus */ + regs.eax = probe_pci_video(); + } + + /* Did we succeed in mapping any video bios */ + if (readw(0xc0000) == 0xaa55) { + int size; + int i; + u8 sum; + + PRINTF("Found video bios signature\n"); + size = 512*readb(0xc0002); + PRINTF("size %d\n", size); + sum=0; + for (i=0;i<size;i++) { + sum += readb(0xc0000 + i); + } + PRINTF("Checksum is %sOK\n",sum?"NOT ":""); + if (sum) { + return 1; + } + + /* some video bioses (ATI Mach64) seem to think that + * the original int 10 handler is always at + * 0xf000:0xf065 , place an iret instruction there + */ + writeb(0xcf, 0xff065); + + regs.esp = 0x8000; + regs.xss = 0x2000; + enter_realmode(0xc000, 3, ®s, ®s); + PRINTF("INT 0x10 vector after: %04x:%04x\n", + readw(0x42), readw(0x40)); + PRINTF("BIOS returned %scarry\n", regs.eflags & 1?"":"NOT "); +#ifdef PCI_BIOS_DEBUG + print_bios_bios_stat(); +#endif + return (regs.eflags & 1); + + } + + return 1; + +} + + diff --git a/lib_i386/zimage.c b/lib_i386/zimage.c index 190d46e..9d33b2d 100644 --- a/lib_i386/zimage.c +++ b/lib_i386/zimage.c @@ -220,8 +220,8 @@ void boot_zimage(void *setup_base) memset(®s, 0, sizeof(struct pt_regs)); regs.xds = (u32)setup_base >> 4; - regs.xss = 0x8e00; - regs.esp = 0x200; + regs.xss = 0x9000; + regs.esp = 0x9000; regs.eflags = 0; enter_realmode(((u32)setup_base+SETUP_START_OFFSET)>>4, 0, ®s, ®s); } |