diff options
82 files changed, 10257 insertions, 84 deletions
@@ -2,6 +2,12 @@ Changes since for U-Boot 0.1.0: ====================================================================== +* 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 + * Patch by Jim Sandoz, 07 Nov 2002: Increase number of network RX buffers (PKTBUFSRX in "include/net.h") for EEPRO100 based boards (especially SP8240) @@ -83,6 +83,10 @@ N: Dave Ellis E: DGE@sixnetio.com D: EEPROM Speedup, SXNI855T port +N: Daniel Engström +E: daniel@omicron.se +D: x86 port, Support for sc520_cdp board + N: Dr. Wolfgang Grandegger E: wg@denx.de D: Support for Interphase 4539 T1/E1/J1 PMC, PN62, CCM, SCM boards diff --git a/MAINTAINERS b/MAINTAINERS index ca5c78eb78..c924c65403 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -250,5 +250,16 @@ Alex Züpke <azu@sysgo.de> dnp1110 SA1110 ######################################################################### +# x86 Systems: # +# # +# Maintainer Name, Email Address # +# Board CPU # +######################################################################### + +Daniel Engström <daniel@omicron.se> + + sc520_cdp x86 + +######################################################################### # End of MAINTAINERS list # ######################################################################### @@ -74,6 +74,9 @@ endif ifeq ($(ARCH),arm) CROSS_COMPILE = arm_920TDI- endif +ifeq ($(ARCH),i386) +#CROSS_COMPILE = i386-elf- +endif endif endif @@ -100,7 +103,10 @@ SUBDIRS = tools \ # U-Boot objects....order is important (i.e. start must be first) OBJS = cpu/$(CPU)/start.o - +ifeq ($(CPU),i386) +OBJS += cpu/$(CPU)/start16.o +OBJS += cpu/$(CPU)/reset.o +endif ifeq ($(CPU),ppc4xx) OBJS += cpu/$(CPU)/resetvec.o endif @@ -108,7 +114,7 @@ endif LIBS = board/$(BOARDDIR)/lib$(BOARD).a LIBS += cpu/$(CPU)/lib$(CPU).a LIBS += lib_$(ARCH)/lib$(ARCH).a -LIBS += fs/jffs2/libjffs2.a +LIBS += fs/jffs2/libjffs2.a fs/fdos/libfdos.a LIBS += net/libnet.a LIBS += disk/libdisk.a LIBS += rtc/librtc.a @@ -627,6 +633,15 @@ cradle_config : unconfig csb226_config : unconfig @./mkconfig $(@:_config=) arm xscale csb226 +#======================================================================== +# i386 +#======================================================================== +######################################################################### +## AMD SC520 CDP +######################################################################### +sc520_cdp_config : unconfig + @./mkconfig $(@:_config=) i386 i386 sc520_cdp + ######################################################################### clean: @@ -536,6 +536,7 @@ The following options need to be configured: CFG_CMD_ELF bootelf, bootvx CFG_CMD_ENV saveenv CFG_CMD_FDC * Floppy Disk Support + CFG_CMD_FDOS * Dos diskette Support CFG_CMD_FLASH flinfo, erase, protect CFG_CMD_FPGA FPGA device initialization support CFG_CMD_I2C * I2C serial bus support @@ -1127,6 +1128,7 @@ The following options need to be configured: Define this to contain any number of null terminated strings (variable = value pairs) that will be part of the default enviroment compiled into the boot image. + For example, place something like this in your board's config file: @@ -1136,9 +1138,9 @@ The following options need to be configured: Warning: This method is based on knowledge about the internal format how the environment is stored by the - U-Boot code. This is NOT an official, expoerted + U-Boot code. This is NOT an official, exported interface! Although it is unlikely that this format - will change soon, there is no guarantee either. + will change soon, but there is no guarantee either. You better know what you are doing here. Note: overly (ab)use of the default environment is diff --git a/board/sc520_cdp/Makefile b/board/sc520_cdp/Makefile new file mode 100644 index 0000000000..0f50393468 --- /dev/null +++ b/board/sc520_cdp/Makefile @@ -0,0 +1,47 @@ +# +# (C) Copyright 2002 +# Daniel Engström, Omicron Ceti AB, daniel@omicron.se. +# +# See file CREDITS for list of people who contributed to this +# project. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# + +include $(TOPDIR)/config.mk + +LIB = lib$(BOARD).a + +OBJS := sc520_cdp.o flash.o +SOBJS := sc520_cdp_asm.o sc520_cdp_asm16.o + +$(LIB): $(OBJS) $(SOBJS) + $(AR) crv $@ $^ + +clean: + rm -f $(SOBJS) $(OBJS) + +distclean: clean + rm -f $(LIB) core *.bak .depend + +######################################################################### + +.depend: Makefile $(SOBJS:.o=.S) $(OBJS:.o=.c) + $(CC) -M $(CPPFLAGS) $(SOBJS:.o=.S) $(OBJS:.o=.c) > $@ + +-include .depend + +######################################################################### diff --git a/board/sc520_cdp/config.mk b/board/sc520_cdp/config.mk new file mode 100644 index 0000000000..d4cd9986d6 --- /dev/null +++ b/board/sc520_cdp/config.mk @@ -0,0 +1,25 @@ +# +# (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 +# + + +TEXT_BASE = 0x387e0000 diff --git a/board/sc520_cdp/flash.c b/board/sc520_cdp/flash.c new file mode 100644 index 0000000000..e43451286f --- /dev/null +++ b/board/sc520_cdp/flash.c @@ -0,0 +1,449 @@ +/* + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Alex Zuepke <azu@sysgo.de> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> + +ulong myflush(void); + + +#define FLASH_BANK_SIZE 0x400000 /* 4 MB */ +#define MAIN_SECT_SIZE 0x20000 /* 128 KB */ + +flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; + + +#define CMD_READ_ARRAY 0x00F000F0 +#define CMD_UNLOCK1 0x00AA00AA +#define CMD_UNLOCK2 0x00550055 +#define CMD_ERASE_SETUP 0x00800080 +#define CMD_ERASE_CONFIRM 0x00300030 +#define CMD_PROGRAM 0x00A000A0 +#define CMD_UNLOCK_BYPASS 0x00200020 + +#define MEM_FLASH_ADDR1 (*(volatile u32 *)(CFG_FLASH_BASE + (0x00000555 << 2))) +#define MEM_FLASH_ADDR2 (*(volatile u32 *)(CFG_FLASH_BASE + (0x000002AA << 2))) + +#define BIT_ERASE_DONE 0x00800080 +#define BIT_RDY_MASK 0x00800080 +#define BIT_PROGRAM_ERROR 0x00200020 +#define BIT_TIMEOUT 0x80000000 /* our flag */ + +#define READY 1 +#define ERR 2 +#define TMO 4 + +/*----------------------------------------------------------------------- + */ + +ulong flash_init(void) +{ + int i, j; + ulong size = 0; + + for (i = 0; i < CFG_MAX_FLASH_BANKS; i++) + { + ulong flashbase = 0; + flash_info[i].flash_id = + (AMD_MANUFACT & FLASH_VENDMASK) | + (AMD_ID_LV160B & FLASH_TYPEMASK); + flash_info[i].size = FLASH_BANK_SIZE; + flash_info[i].sector_count = CFG_MAX_FLASH_SECT; + memset(flash_info[i].protect, 0, CFG_MAX_FLASH_SECT); + if (i == 0) + flashbase = PHYS_FLASH_1; + else + panic("configured to many flash banks!\n"); + for (j = 0; j < flash_info[i].sector_count; j++) + { + + if (j <= 3) + { + /* 1st one is 32 KB */ + if (j == 0) + { + flash_info[i].start[j] = flashbase + 0; + } + + /* 2nd and 3rd are both 16 KB */ + if ((j == 1) || (j == 2)) + { + flash_info[i].start[j] = flashbase + 0x8000 + (j-1)*0x4000; + } + + /* 4th 64 KB */ + if (j == 3) + { + flash_info[i].start[j] = flashbase + 0x10000; + } + } + else + { + flash_info[i].start[j] = flashbase + (j - 3)*MAIN_SECT_SIZE; + } + } + size += flash_info[i].size; + } + + /* + * Protect monitor and environment sectors + */ + flash_protect(FLAG_PROTECT_SET, + i386boot_start-CFG_FLASH_BASE, + i386boot_end-CFG_FLASH_BASE, + &flash_info[0]); + + flash_protect(FLAG_PROTECT_SET, + CFG_ENV_ADDR, + CFG_ENV_ADDR + CFG_ENV_SIZE - 1, + &flash_info[0]); + return size; +} + +/*----------------------------------------------------------------------- + */ +void flash_print_info (flash_info_t *info) +{ + int i; + + switch (info->flash_id & FLASH_VENDMASK) + { + case (AMD_MANUFACT & FLASH_VENDMASK): + printf("AMD: "); + break; + default: + printf("Unknown Vendor "); + break; + } + + switch (info->flash_id & FLASH_TYPEMASK) + { + case (AMD_ID_LV160B & FLASH_TYPEMASK): + printf("2x Amd29F160BB (16Mbit)\n"); + break; + default: + printf("Unknown Chip Type\n"); + goto Done; + break; + } + + printf(" Size: %ld MB in %d Sectors\n", + info->size >> 20, info->sector_count); + + printf(" Sector Start Addresses:"); + for (i = 0; i < info->sector_count; i++) + { + if ((i % 5) == 0) + { + printf ("\n "); + } + printf (" %08lX%s", info->start[i], + info->protect[i] ? " (RO)" : " "); + } + printf ("\n"); + +Done: +} + +/*----------------------------------------------------------------------- + */ + +int flash_erase (flash_info_t *info, int s_first, int s_last) +{ + ulong result; + int iflag, cflag, prot, sect; + int rc = ERR_OK; + int chip1, chip2; + + /* first look for protection bits */ + + if (info->flash_id == FLASH_UNKNOWN) + return ERR_UNKNOWN_FLASH_TYPE; + + if ((s_first < 0) || (s_first > s_last)) { + return ERR_INVAL; + } + + if ((info->flash_id & FLASH_VENDMASK) != + (AMD_MANUFACT & FLASH_VENDMASK)) { + return ERR_UNKNOWN_FLASH_VENDOR; + } + + prot = 0; + for (sect=s_first; sect<=s_last; ++sect) { + if (info->protect[sect]) { + prot++; + } + } + if (prot) + return ERR_PROTECTED; + + /* + * Disable interrupts which might cause a timeout + * here. Remember that our exception vectors are + * at address 0 in the flash, and we don't want a + * (ticker) exception to happen while the flash + * chip is in programming mode. + */ + iflag = disable_interrupts(); + + /* Start erase on unprotected sectors */ + for (sect = s_first; sect<=s_last && !ctrlc(); sect++) + { + printf("Erasing sector %2d ... ", sect); + + /* arm simple, non interrupt dependent timer */ + reset_timer(); + + if (info->protect[sect] == 0) + { /* not protected */ + vu_long *addr = (vu_long *)(info->start[sect]); + + MEM_FLASH_ADDR1 = CMD_UNLOCK1; + MEM_FLASH_ADDR2 = CMD_UNLOCK2; + MEM_FLASH_ADDR1 = CMD_ERASE_SETUP; + + MEM_FLASH_ADDR1 = CMD_UNLOCK1; + MEM_FLASH_ADDR2 = CMD_UNLOCK2; + *addr = CMD_ERASE_CONFIRM; + + /* wait until flash is ready */ + chip1 = chip2 = 0; + + do + { + result = *addr; + + /* check timeout */ + if (get_timer(0) > CFG_FLASH_ERASE_TOUT) + { + MEM_FLASH_ADDR1 = CMD_READ_ARRAY; + chip1 = TMO; + break; + } + + if (!chip1 && (result & 0xFFFF) & BIT_ERASE_DONE) + chip1 = READY; + + if (!chip1 && (result & 0xFFFF) & BIT_PROGRAM_ERROR) + chip1 = ERR; + + if (!chip2 && (result >> 16) & BIT_ERASE_DONE) + chip2 = READY; + + if (!chip2 && (result >> 16) & BIT_PROGRAM_ERROR) + chip2 = ERR; + + } while (!chip1 || !chip2); + + MEM_FLASH_ADDR1 = CMD_READ_ARRAY; + + if (chip1 == ERR || chip2 == ERR) + { + rc = ERR_PROG_ERROR; + goto outahere; + } + if (chip1 == TMO) + { + rc = ERR_TIMOUT; + goto outahere; + } + + printf("ok.\n"); + } + else /* it was protected */ + { + printf("protected!\n"); + } + } + + if (ctrlc()) + printf("User Interrupt!\n"); + +outahere: + /* allow flash to settle - wait 10 ms */ + udelay(10000); + + if (iflag) + enable_interrupts(); + + + return rc; +} + +/*----------------------------------------------------------------------- + * Copy memory to flash + */ + +volatile static int write_word (flash_info_t *info, ulong dest, ulong data) +{ + vu_long *addr = (vu_long *)dest; + ulong result; + int rc = ERR_OK; + int iflag; + int chip1, chip2; + + /* + * Check if Flash is (sufficiently) erased + */ + result = *addr; + if ((result & data) != data) + return ERR_NOT_ERASED; + + + /* + * Disable interrupts which might cause a timeout + * here. Remember that our exception vectors are + * at address 0 in the flash, and we don't want a + * (ticker) exception to happen while the flash + * chip is in programming mode. + */ + iflag = disable_interrupts(); + + MEM_FLASH_ADDR1 = CMD_UNLOCK1; + MEM_FLASH_ADDR2 = CMD_UNLOCK2; + MEM_FLASH_ADDR1 = CMD_UNLOCK_BYPASS; + *addr = CMD_PROGRAM; + *addr = data; + + /* arm simple, non interrupt dependent timer */ + reset_timer(); + + /* wait until flash is ready */ + chip1 = chip2 = 0; + do + { + result = *addr; + + /* check timeout */ + if (get_timer(0) > CFG_FLASH_ERASE_TOUT) + { + chip1 = ERR | TMO; + break; + } + if (!chip1 && ((result & 0x80) == (data & 0x80))) + chip1 = READY; + + if (!chip1 && ((result & 0xFFFF) & BIT_PROGRAM_ERROR)) + { + result = *addr; + + if ((result & 0x80) == (data & 0x80)) + chip1 = READY; + else + chip1 = ERR; + } + + if (!chip2 && ((result & (0x80 << 16)) == (data & (0x80 << 16)))) + chip2 = READY; + + if (!chip2 && ((result >> 16) & BIT_PROGRAM_ERROR)) + { + result = *addr; + + if ((result & (0x80 << 16)) == (data & (0x80 << 16))) + chip2 = READY; + else + chip2 = ERR; + } + + } while (!chip1 || !chip2); + + *addr = CMD_READ_ARRAY; + + if (chip1 == ERR || chip2 == ERR || *addr != data) + rc = ERR_PROG_ERROR; + + if (iflag) + enable_interrupts(); + + + return rc; +} + +/*----------------------------------------------------------------------- + * Copy memory to flash. + */ + +int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt) +{ + ulong cp, wp, data; + int l; + int i, rc; + + wp = (addr & ~3); /* get lower word aligned address */ + + /* + * handle unaligned start bytes + */ + if ((l = addr - wp) != 0) { + data = 0; + for (i=0, cp=wp; i<l; ++i, ++cp) { + data = (data >> 8) | (*(uchar *)cp << 24); + } + for (; i<4 && cnt>0; ++i) { + data = (data >> 8) | (*src++ << 24); + --cnt; + ++cp; + } + for (; cnt==0 && i<4; ++i, ++cp) { + data = (data >> 8) | (*(uchar *)cp << 24); + } + + if ((rc = write_word(info, wp, data)) != 0) { + return (rc); + } + wp += 4; + } + + /* + * handle word aligned part + */ + while (cnt >= 4) { + data = *((vu_long*)src); + if ((rc = write_word(info, wp, data)) != 0) { + return (rc); + } + src += 4; + wp += 4; + cnt -= 4; + } + + if (cnt == 0) { + return ERR_OK; + } + + /* + * handle unaligned tail bytes + */ + data = 0; + for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) { + data = (data >> 8) | (*src++ << 24); + --cnt; + } + for (; i<4; ++i, ++cp) { + data = (data >> 8) | (*(uchar *)cp << 24); + } + + return write_word(info, wp, data); +} diff --git a/board/sc520_cdp/sc520_cdp.c b/board/sc520_cdp/sc520_cdp.c new file mode 100644 index 0000000000..cc818d2660 --- /dev/null +++ b/board/sc520_cdp/sc520_cdp.c @@ -0,0 +1,288 @@ +/* + * (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/ic/sc520.h> +#include <asm/ic/ali512x.h> + +/* ------------------------------------------------------------------------- */ + +static void irq_init(void) +{ + + /* disable global interrupt mode */ + write_mmcr_byte(SC520_PICICR, 0x40); + + /* set irq0-7 to edge */ + write_mmcr_byte(SC520_MPICMODE, 0x00); + + /* set irq9-12 to level, all the other (8, 13-15) are edge */ + write_mmcr_byte(SC520_SL1PICMODE, 0x1e); + + /* set irq16-24 (unused slave pic2) to level */ + write_mmcr_byte(SC520_SL2PICMODE, 0xff); + + /* active low polarity on PIC interrupt pins, + active high polarity on all other irq pins */ + write_mmcr_word(SC520_INTPINPOL, 0); + + /* set irq number mapping */ + write_mmcr_byte(SC520_GPTMR0MAP,0); /* disable GP timer 0 INT */ + write_mmcr_byte(SC520_GPTMR1MAP,0); /* disable GP timer 1 INT */ + write_mmcr_byte(SC520_GPTMR2MAP,0); /* disable GP timer 2 INT */ + write_mmcr_byte(SC520_PIT0MAP,0x1); /* Set PIT timer 0 INT to IRQ0 */ + write_mmcr_byte(SC520_PIT1MAP,0); /* diable PIT timer 1 INT */ + write_mmcr_byte(SC520_PIT2MAP,0); /* diable PIT timer 2 INT */ + write_mmcr_byte(SC520_PCIINTAMAP,0x4); /* Set PCI INT A to IRQ9 */ + write_mmcr_byte(SC520_PCIINTBMAP,0x5); /* Set PCI INT B to IRQ10 */ + write_mmcr_byte(SC520_PCIINTCMAP,0x6); /* Set PCI INT C to IRQ11 */ + write_mmcr_byte(SC520_PCIINTDMAP,0x7); /* Set PCI INT D to IRQ12 */ + write_mmcr_byte(SC520_DMABCINTMAP,0); /* disable DMA INT */ + write_mmcr_byte(SC520_SSIMAP,0); /* disable Synchronius serial INT */ + write_mmcr_byte(SC520_WDTMAP,0); /* disable Watchdor INT */ + write_mmcr_byte(SC520_RTCMAP,0x3); /* Set RTC int to 8 */ + write_mmcr_byte(SC520_WPVMAP,0); /* disable write protect INT */ + write_mmcr_byte(SC520_ICEMAP,0x2); /* Set ICE Debug Serielport INT to IRQ1 */ + write_mmcr_byte(SC520_FERRMAP,0x8); /* Set FP error INT to IRQ13 */ + write_mmcr_byte(SC520_GP0IMAP,6); /* Set GPIRQ0 (ISA IRQ2) to IRQ9 */ + write_mmcr_byte(SC520_GP1IMAP,2); /* Set GPIRQ1 (SIO IRQ1) to IRQ1 */ + write_mmcr_byte(SC520_GP2IMAP,7); /* Set GPIRQ2 (ISA IRQ12) to IRQ12 */ + + if (CFG_USE_SIO_UART) { + write_mmcr_byte(SC520_UART1MAP,0); /* disable internal UART1 INT */ + write_mmcr_byte(SC520_UART2MAP,0); /* disable internal UART2 INT */ + write_mmcr_byte(SC520_GP3IMAP,11); /* Set GPIRQ3 (ISA IRQ3) to IRQ3 */ + write_mmcr_byte(SC520_GP4IMAP,12); /* Set GPIRQ4 (ISA IRQ4) to IRQ4 */ + } else { + write_mmcr_byte(SC520_UART1MAP,12); /* Set internal UART2 INT to IRQ4 */ + write_mmcr_byte(SC520_UART2MAP,11); /* Set internal UART2 INT to IRQ3 */ + write_mmcr_byte(SC520_GP3IMAP,0); /* disable GPIRQ3 (ISA IRQ3) */ + write_mmcr_byte(SC520_GP4IMAP,0); /* disable GPIRQ4 (ISA IRQ4) */ + } + + write_mmcr_byte(SC520_GP5IMAP,13); /* Set GPIRQ5 (ISA IRQ5) to IRQ5 */ + write_mmcr_byte(SC520_GP6IMAP,21); /* Set GPIRQ6 (ISA IRQ6) to IRQ6 */ + write_mmcr_byte(SC520_GP7IMAP,22); /* Set GPIRQ7 (ISA IRQ7) to IRQ7 */ + write_mmcr_byte(SC520_GP8IMAP,3); /* Set GPIRQ8 (SIO IRQ8) to IRQ8 */ + write_mmcr_byte(SC520_GP9IMAP,4); /* Set GPIRQ9 (ISA IRQ9) to IRQ9 */ + write_mmcr_byte(SC520_GP10IMAP,9); /* Set GPIRQ10 (ISA IRQ10) to IRQ10 */ + write_mmcr_word(SC520_PCIHOSTMAP,0x11f); /* Map PCI hostbridge INT to NMI */ + write_mmcr_word(SC520_ECCMAP,0x100); /* Map SDRAM ECC failure INT to NMI */ + +} + +/* PCI stuff */ +static void pci_sc520_cdp_fixup_irq(struct pci_controller *hose, pci_dev_t dev) +{ + char pin; + int irq; + + + pci_hose_read_config_byte(hose, dev, PCI_INTERRUPT_PIN, &pin); + irq = pin-1; + + switch (PCI_DEV(dev)) { + case 20: + break; + case 19: + irq+=1; + break; + case 18: + irq+=2; + break; + case 17: + irq+=3; + break; + default: + return; + } + + irq&=3; /* wrap around */ + irq+=9; /* lowest IRQ is 9 */ + + pci_hose_write_config_byte(hose, dev, PCI_INTERRUPT_LINE, irq); +#if 0 + printf("fixup_irq: device %d pin %c irq %d\n", + PCI_DEV(dev), 'A' + pin -1, irq); +#endif +} + +static struct pci_controller sc520_cdp_hose = { + fixup_irq: pci_sc520_cdp_fixup_irq, +}; + +void pci_init(void) +{ + pci_sc520_init(&sc520_cdp_hose); +} + + +static void silence_uart(int port) +{ + outb(0, port+1); +} + +void setup_ali_sio(int uart_primary) +{ + ali512x_init(); + + ali512x_set_fdc(ALI_ENABLED, 0x3f2, 6, 0); + ali512x_set_pp(ALI_ENABLED, 0x278, 7, 3); + ali512x_set_uart(ALI_ENABLED, ALI_UART1, uart_primary?0x3f8:0x3e8, 4); + ali512x_set_uart(ALI_ENABLED, ALI_UART2, uart_primary?0x2f8:0x2e8, 3); + ali512x_set_rtc(ALI_DISABLED, 0, 0); + ali512x_set_kbc(ALI_ENABLED, 1, 12); + ali512x_set_cio(ALI_ENABLED); + + /* IrDa pins */ + ali512x_cio_function(12, 1, 0, 0); + ali512x_cio_function(13, 1, 0, 0); + + /* SSI chip select pins */ + ali512x_cio_function(14, 0, 0, 0); /* SSI_CS */ + ali512x_cio_function(15, 0, 0, 0); /* SSI_MV */ + ali512x_cio_function(16, 0, 1, 0); /* SSI_SPI# (inverted) */ + + /* Board REV pins */ + ali512x_cio_function(20, 0, 0, 1); + ali512x_cio_function(21, 0, 0, 1); + ali512x_cio_function(22, 0, 0, 1); + ali512x_cio_function(23, 0, 0, 1); +} + + +/* set up the ISA bus timing and system address mappings */ +static void bus_init(void) +{ + + /* set up the GP IO pins */ + write_mmcr_word(SC520_PIOPFS31_16, 0xf7ff); /* set the GPIO pin function 31-16 reg */ + write_mmcr_word(SC520_PIOPFS15_0, 0xffff); /* set the GPIO pin function 15-0 reg */ + write_mmcr_byte(SC520_CSPFS, 0xf8); /* set the CS pin function reg */ + write_mmcr_byte(SC520_CLKSEL, 0x70); + + + write_mmcr_byte(SC520_GPCSRT, 1); /* set the GP CS offset */ + write_mmcr_byte(SC520_GPCSPW, 3); /* set the GP CS pulse width */ + write_mmcr_byte(SC520_GPCSOFF, 1); /* set the GP CS offset */ + write_mmcr_byte(SC520_GPRDW, 3); /* set the RD pulse width */ + write_mmcr_byte(SC520_GPRDOFF, 1); /* set the GP RD offset */ + write_mmcr_byte(SC520_GPWRW, 3); /* set the GP WR pulse width */ + write_mmcr_byte(SC520_GPWROFF, 1); /* set the GP WR offset */ + + write_mmcr_word(SC520_BOOTCSCTL, 0x1823); /* set up timing of BOOTCS */ + write_mmcr_word(SC520_ROMCS1CTL, 0x1823); /* set up timing of ROMCS1 */ + write_mmcr_word(SC520_ROMCS2CTL, 0x1823); /* set up timing of ROMCS2 */ + + /* adjust the memory map: + * by default the first 256MB (0x00000000 - 0x0fffffff) is mapped to SDRAM + * and 256MB to 1G-128k (0x1000000 - 0x37ffffff) is mapped to PCI mmio + * we need to map 1G-128k - 1G (0x38000000 - 0x3fffffff) to CS1 */ + + + /* SRAM = GPCS3 128k @ d0000-effff*/ + write_mmcr_long(SC520_PAR2, 0x4e00400d); + + /* IDE0 = GPCS6 1f0-1f7 */ + write_mmcr_long(SC520_PAR3, 0x380801f0); + + /* IDE1 = GPCS7 3f6 */ + write_mmcr_long(SC520_PAR4, 0x3c0003f6); + /* bootcs */ + write_mmcr_long(SC520_PAR12, 0x8bffe800); + /* romcs2 */ + write_mmcr_long(SC520_PAR13, 0xcbfff000); + /* romcs1 */ + write_mmcr_long(SC520_PAR14, 0xabfff800); + /* 680 LEDS */ + write_mmcr_long(SC520_PAR15, 0x30000640); + + asm ("wbinvd\n"); /* Flush cache, req. after setting the unchached attribute ona PAR */ + + if (CFG_USE_SIO_UART) { + write_mmcr_byte(SC520_ADDDECCTL, read_mmcr_byte(SC520_ADDDECCTL) | UART2_DIS|UART1_DIS); + setup_ali_sio(1); + } else { + write_mmcr_byte(SC520_ADDDECCTL, read_mmcr_byte(SC520_ADDDECCTL) & ~(UART2_DIS|UART1_DIS)); + setup_ali_sio(0); + silence_uart(0x3e8); + silence_uart(0x2e8); + } + +} + + + +/* + * Miscelaneous platform dependent initialisations + */ + +int board_init(void) +{ + DECLARE_GLOBAL_DATA_PTR; + + init_sc520(); + bus_init(); + irq_init(); + + /* max drive current on SDRAM */ + write_mmcr_word(SC520_DSCTL, 0x0100); + + /* enter debug mode after next reset (only if jumper is also set) */ + write_mmcr_byte(SC520_RESCFG, 0x08); + + /* configure the software timer to 33.333MHz */ + write_mmcr_byte(SC520_SWTMRCFG, 0); + gd->bus_clk = 33333000; + + return 0; +} + +int dram_init(void) +{ + init_sc520_dram(); + return 0; +} + +void show_boot_progress(int val) +{ + outb(val&0xff, 0x80); + outb((val&0xff00)>>8, 0x680); +} + + +int last_stage_init(void) +{ + int minor; + int major; + + major = minor = 0; + major |= ali512x_cio_in(23)?2:0; + major |= ali512x_cio_in(22)?1:0; + minor |= ali512x_cio_in(21)?2:0; + minor |= ali512x_cio_in(20)?1:0; + + printf("AMD SC520 CDP revision %d.%d\n", major, minor); +} diff --git a/board/sc520_cdp/sc520_cdp_asm.S b/board/sc520_cdp/sc520_cdp_asm.S new file mode 100644 index 0000000000..1e255fab2e --- /dev/null +++ b/board/sc520_cdp/sc520_cdp_asm.S @@ -0,0 +1,86 @@ +/* + * (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 + */ + +/* now setup the General purpose bus to give us access to the LEDs. + * We can then use the leds to display status information. + */ + +sc520_cdp_registers: +/* size offset value */ +.word 1 ; .word 0x040 ; .long 0x00 /* SDRAM buffer control */ +.word 2 ; .word 0xc08 ; .long 0x0001 /* GP CS offset */ +.word 2 ; .word 0xc09 ; .long 0x0003 /* GP CS width */ +.word 2 ; .word 0xc0a ; .long 0x0001 /* GP CS width */ +.word 2 ; .word 0xc0b ; .long 0x0003 /* GP RD pulse width */ +.word 2 ; .word 0xc0c ; .long 0x0001 /* GP RD offse */ +.word 2 ; .word 0xc0d ; .long 0x0003 /* GP WR pulse width */ +.word 2 ; .word 0xc0e ; .long 0x0001 /* GP WR offset */ +.word 2 ; .word 0xc2c ; .long 0x0000 /* GPIO directionreg */ +.word 2 ; .word 0xc2a ; .long 0x0000 /* GPIO directionreg */ +.word 2 ; .word 0xc22 ; .long 0xffff /* GPIO pin function 31-16 reg */ +.word 2 ; .word 0xc20 ; .long 0xffff /* GPIO pin function 15-0 reg */ +.word 2 ; .word 0x0c4 ; .long 0x28000680 /* PAR 15 for access to led 680 */ +.word 0 ; .word 0x000 ; .long 0x00 + +/* board early intialization */ +.globl early_board_init +early_board_init: + movl $sc520_cdp_registers,%esi +init_loop: + movl $0xfffef000,%edi /* MMCR base to edi */ + movw (%esi), %bx /* load sizer to bx */ + cmpw $0, %bx /* if sie is 0 we're done */ + je done + xorl %edx,%edx + movw 2(%esi), %dx /* load MMCR offset to dx */ + addl %edx, %edi /* add offset to base in edi */ + movl 4(%esi), %eax /* load value in eax */ + cmpw $1, %bx + je byte /* byte op? */ + cmpw $2, %bx + je word /* word op? */ + movl %eax, (%edi) /* must be long, then */ + jmp next +byte: movb %al,(%edi) + jmp next +word: movw %ax,(%edi) +next: addl $8, %esi /* advance esi */ + jmp init_loop + + /* the leds ad 0x80 and 0x680 should now work */ +done: movb $0x88, %al + out %al, $0x80 + movw $0x680, %dx + out %al, %dx + + jmp *%ebp /* return to caller */ + + +.globl __show_boot_progress +__show_boot_progress: + out %al, $0x80 + xchg %al, %ah + movw $0x680, %dx + out %al, %dx + jmp *%ebp + diff --git a/board/sc520_cdp/sc520_cdp_asm16.S b/board/sc520_cdp/sc520_cdp_asm16.S new file mode 100644 index 0000000000..a3cadcfa54 --- /dev/null +++ b/board/sc520_cdp/sc520_cdp_asm16.S @@ -0,0 +1,62 @@ +/* + * (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 + */ + +/* + * 16bit initialization code. + * This code have to map the area of the boot flash + * that is used by U-boot to its final destination. + */ + +.text +.section .start16, "ax" +.code16 +.globl board_init16 +board_init16: + /* Alias MMCR to 0xdf000 */ + movw $0xfffc, %dx + movl $0x800df0cb, %eax + outl %eax, %dx + + /* Set ds to point to MMCR alias */ + movw $0xdf00, %ax + movw %ax, %ds + + /* Map the entire flash at 0x38000000 + * (with BOOTCS and PAR14, use 0xabfff800 for ROMCS1) */ + movl $0xc0, %edi + movl $0x8bfff800, %eax + movl %eax, (%di) + + /* Disable SDRAM write buffer */ + movw $0x40,%di + xorw %ax,%ax + movb %al, (%di) + + /* Disabe MMCR alias */ + movw $0xfffc, %dx + movl $0x000000cb, %eax + outl %eax, %dx + + /* the return address is tored in bp */ + jmp *%bp + diff --git a/board/sc520_cdp/u-boot.lds b/board/sc520_cdp/u-boot.lds new file mode 100644 index 0000000000..ac8d3dbecd --- /dev/null +++ b/board/sc520_cdp/u-boot.lds @@ -0,0 +1,85 @@ +/* + * (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 + */ + +OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") +OUTPUT_ARCH(i386) +ENTRY(_start) + +SECTIONS +{ + . = 0x387e0000; /* Where bootcode in the flash is mapped */ + .text : { *(.text); } + + . = ALIGN(4); + .rodata : { *(.rodata) } + + . = 0x400000; /* Ram data segment to use */ + _i386boot_romdata_dest = ABSOLUTE(.); + .data : AT ( LOADADDR(.rodata) + SIZEOF(.rodata) ) { *(.data) } + _i386boot_romdata_start = LOADADDR(.data); + + . = ALIGN(4); + .got : AT ( LOADADDR(.data) + SIZEOF(.data) ) { *(.got) } + _i386boot_romdata_size = SIZEOF(.data) + SIZEOF(.got); + + + . = ALIGN(4); + _i386boot_bss_start = ABSOLUTE(.); + .bss : { *(.bss) } + _i386boot_bss_size = SIZEOF(.bss); + + + /* 16bit realmode trampoline code */ + .realmode 0x7c0 : AT ( LOADADDR(.got) + SIZEOF(.got) ) { *(.realmode) } + + _i386boot_realmode = LOADADDR(.realmode); + _i386boot_realmode_size = SIZEOF(.realmode); + + /* 16bit BIOS emulation code (just enough to boot Linux) */ + .bios 0 : AT ( LOADADDR(.realmode) + SIZEOF(.realmode) ) { *(.bios) } + + _i386boot_bios = LOADADDR(.bios); + _i386boot_bios_size = SIZEOF(.bios); + + + /* The load addresses below assumes that the flash + * will be mapped so that 0x387f0000 == 0xffff0000 + * at reset time + * + * The fe00 and ff00 offsets of the start32 and start16 + * segments are arbitrary, the just have to be mapped + * at reset and the code have to fit. + * The fff0 offset of reset is important, however. + */ + + + . = 0xfffffe00; + .start32 : AT (0x387ffe00) { *(.start32); } + + . = 0xff00; + .start16 : AT (0x387fff00) { *(.start16); } + + . = 0xfff0; + .reset : AT (0x387ffff0) { *(.reset); } + _i386boot_end = (LOADADDR(.reset) + SIZEOF(.reset) ); +} diff --git a/common/Makefile b/common/Makefile index 3f4ff01909..67387ef64f 100644 --- a/common/Makefile +++ b/common/Makefile @@ -31,7 +31,7 @@ COBJS = main.o altera.o bedbug.o \ cmd_autoscript.o cmd_bedbug.o cmd_boot.o \ cmd_bootm.o cmd_cache.o cmd_console.o cmd_date.o \ cmd_dcr.o cmd_diag.o cmd_doc.o cmd_dtt.o \ - cmd_eeprom.o cmd_elf.o cmd_fdc.o cmd_flash.o \ + cmd_eeprom.o cmd_elf.o cmd_fdc.o cmd_fdos.o cmd_flash.o \ cmd_fpga.o cmd_i2c.o cmd_ide.o cmd_immap.o \ cmd_jffs2.o cmd_log.o cmd_mem.o cmd_mii.o cmd_misc.o \ cmd_net.o cmd_nvedit.o env_common.o \ diff --git a/common/cmd_bootm.c b/common/cmd_bootm.c index 70ca999c06..a0587d019f 100644 --- a/common/cmd_bootm.c +++ b/common/cmd_bootm.c @@ -70,6 +70,10 @@ static int image_info (unsigned long addr); #endif static void print_type (image_header_t *hdr); +#ifdef __I386__ +image_header_t *fake_header(image_header_t *hdr, void *ptr, int size); +#endif + /* * Continue booting an OS image; caller already has: * - copied image header to global variable `header' @@ -84,7 +88,7 @@ typedef void boot_os_Fcn (cmd_tbl_t *cmdtp, int flag, ulong *len_ptr, /* multi-file image length table */ int verify); /* getenv("verify")[0] != 'n' */ -#ifndef CONFIG_ARM +#ifdef CONFIG_PPC static boot_os_Fcn do_bootm_linux; #else extern boot_os_Fcn do_bootm_linux; @@ -128,9 +132,21 @@ int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) memmove (&header, (char *)addr, sizeof(image_header_t)); if (ntohl(hdr->ih_magic) != IH_MAGIC) { +#ifdef __I386__ /* correct image format not implemented yet - fake it */ + if (fake_header(hdr, (void*)addr, -1) != NULL) { + /* to compensate for the addition below */ + addr -= sizeof(image_header_t); + /* turnof verify, + * fake_header() does not fake the data crc + */ + verify = 0; + } else +#endif /* __I386__ */ + { printf ("Bad Magic Number\n"); SHOW_BOOT_PROGRESS (-1); return 1; + } } SHOW_BOOT_PROGRESS (2); @@ -148,7 +164,7 @@ int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) SHOW_BOOT_PROGRESS (3); /* for multi-file images we need the data part, too */ - print_image_hdr ((image_header_t *)addr); + print_image_hdr (hdr); data = addr + sizeof(image_header_t); len = ntohl(hdr->ih_size); @@ -166,8 +182,17 @@ int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) len_ptr = (ulong *)data; - if (hdr->ih_arch != IH_CPU_PPC && hdr->ih_arch != IH_CPU_ARM) { - printf ("Unsupported Architecture\n"); +#if defined(__PPC__) + if (hdr->ih_arch != IH_CPU_PPC) +#elif defined(__ARM__) + if (hdr->ih_arch != IH_CPU_ARM) +#elif defined(__I386__) + if (hdr->ih_arch != IH_CPU_I386) +#else +# error Unknown CPU type +#endif + { + printf ("Unsupported Architecture 0x%x\n", hdr->ih_arch); SHOW_BOOT_PROGRESS (-4); return 1; } @@ -201,7 +226,7 @@ int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) switch (hdr->ih_comp) { case IH_COMP_NONE: - if(hdr->ih_load == addr) { + if(ntohl(hdr->ih_load) == addr) { printf (" XIP %s ... ", name); } else { #if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG) @@ -294,7 +319,7 @@ int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) return 1; } -#ifndef CONFIG_ARM +#ifdef CONFIG_PPC static void do_bootm_linux (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[], diff --git a/common/cmd_fdc.c b/common/cmd_fdc.c index 8e6b7350c2..e45b3361ca 100644 --- a/common/cmd_fdc.c +++ b/common/cmd_fdc.c @@ -51,7 +51,7 @@ #include <rtc.h> #endif -#if (CONFIG_COMMANDS & CFG_CMD_FDC) +#if ((CONFIG_COMMANDS & CFG_CMD_FDC) || (CONFIG_COMMANDS & CFG_CMD_FDOS)) typedef struct { @@ -192,7 +192,10 @@ static FDC_COMMAND_STRUCT cmd; /* global command struct */ /* reads a Register of the FDC */ unsigned char read_fdc_reg(unsigned int addr) { - volatile unsigned char *val = (volatile unsigned char *)(CFG_ISA_IO_BASE_ADDRESS + (addr * CFG_ISA_IO_STRIDE) + CFG_ISA_IO_OFFSET); + volatile unsigned char *val = + (volatile unsigned char *)(CFG_ISA_IO_BASE_ADDRESS + + (addr * CFG_ISA_IO_STRIDE) + + CFG_ISA_IO_OFFSET); return val [0]; } @@ -200,7 +203,10 @@ unsigned char read_fdc_reg(unsigned int addr) /* writes a Register of the FDC */ void write_fdc_reg(unsigned int addr, unsigned char val) { - volatile unsigned char *tmp = (volatile unsigned char *)(CFG_ISA_IO_BASE_ADDRESS + (addr * CFG_ISA_IO_STRIDE) + CFG_ISA_IO_OFFSET); + volatile unsigned char *tmp = + (volatile unsigned char *)(CFG_ISA_IO_BASE_ADDRESS + + (addr * CFG_ISA_IO_STRIDE) + + CFG_ISA_IO_OFFSET); tmp[0]=val; } @@ -279,7 +285,8 @@ int fdc_issue_cmd(FDC_COMMAND_STRUCT *pCMD,FD_GEO_STRUCT *pFG) head = sect / pFG->sect; /* head nr */ sect = sect % pFG->sect; /* remaining blocks */ sect++; /* sectors are 1 based */ - PRINTF("Cmd 0x%02x Track %ld, Head %ld, Sector %ld, Drive %d (blnr %ld)\n",pCMD->cmd[0],track,head,sect,pCMD->drive,pCMD->blnr); + PRINTF("Cmd 0x%02x Track %ld, Head %ld, Sector %ld, Drive %d (blnr %ld)\n", + pCMD->cmd[0],track,head,sect,pCMD->drive,pCMD->blnr); if(head|=0) { /* max heads = 2 */ pCMD->cmd[DRIVE]=pCMD->drive | 0x04; /* head 1 */ @@ -588,7 +595,7 @@ int fdc_check_drive(FDC_COMMAND_STRUCT *pCMD, FD_GEO_STRUCT *pFG) * setup the fdc according the datasheet * assuming in PS2 Mode */ -int fdc_setup(FDC_COMMAND_STRUCT *pCMD, FD_GEO_STRUCT *pFG) +int fdc_setup(int drive, FDC_COMMAND_STRUCT *pCMD, FD_GEO_STRUCT *pFG) { int i; @@ -601,7 +608,7 @@ int fdc_setup(FDC_COMMAND_STRUCT *pCMD, FD_GEO_STRUCT *pFG) for(i=0; i<255; i++) /* then we wait some time */ udelay(500); /* then, we clear the reset in the DOR */ - pCMD->drive=CFG_FDC_DRIVE_NUMBER; + pCMD->drive=drive; select_fdc_drive(pCMD); /* initialize the CCR */ write_fdc_reg(FDC_CCR,pFG->rate); @@ -621,9 +628,8 @@ int fdc_setup(FDC_COMMAND_STRUCT *pCMD, FD_GEO_STRUCT *pFG) PRINTF("Sense Interrupt for drive %d failed\n",i); } } - /* assuming drive 0 for rest of configuration - * issue the configure command */ - pCMD->drive=CFG_FDC_DRIVE_NUMBER; + /* issue the configure command */ + pCMD->drive=drive; select_fdc_drive(pCMD); pCMD->cmd[COMMAND]=FDC_CMD_CONFIGURE; if(fdc_issue_cmd(pCMD,pFG)==FALSE) { @@ -644,7 +650,74 @@ int fdc_setup(FDC_COMMAND_STRUCT *pCMD, FD_GEO_STRUCT *pFG) /* write_fdc_reg(FDC_DOR,0x04); */ return TRUE; } +#endif /* ((CONFIG_COMMANDS & CFG_CMD_FDC)||(CONFIG_COMMANDS & CFG_CMD_FDOS))*/ + +#if (CONFIG_COMMANDS & CFG_CMD_FDOS) + +/* Low level functions for the Floppy-DOS layer */ +/************************************************************************** +* int fdc_fdos_init +* initialize the FDC layer +* +*/ +int fdc_fdos_init (int drive) +{ + FD_GEO_STRUCT *pFG = (FD_GEO_STRUCT *)floppy_type; + FDC_COMMAND_STRUCT *pCMD = &cmd; + + /* setup FDC and scan for drives */ + if(fdc_setup(drive,pCMD,pFG)==FALSE) { + printf("\n** Error in setup FDC **\n"); + return FALSE; + } + if(fdc_check_drive(pCMD,pFG)==FALSE) { + printf("\n** Error in check_drives **\n"); + return FALSE; + } + if((pCMD->flags&(1<<drive))==0) { + /* drive not available */ + printf("\n** Drive %d not available **\n",drive); + return FALSE; + } + if((pCMD->flags&(0x10<<drive))==0) { + /* no disk inserted */ + printf("\n** No disk inserted in drive %d **\n",drive); + return FALSE; + } + /* ok, we have a valid source */ + pCMD->drive=drive; + + /* read first block */ + pCMD->blnr=0; + return TRUE; +} +/************************************************************************** +* int fdc_fdos_seek +* parameter is a block number +*/ +int fdc_fdos_seek (int where) +{ + FD_GEO_STRUCT *pFG = (FD_GEO_STRUCT *)floppy_type; + FDC_COMMAND_STRUCT *pCMD = &cmd; + + pCMD -> blnr = where ; + return (fdc_seek (pCMD, pFG)); +} +/************************************************************************** +* int fdc_fdos_read +* the length is in block number +*/ +int fdc_fdos_read (void *buffer, int len) +{ + FD_GEO_STRUCT *pFG = (FD_GEO_STRUCT *)floppy_type; + FDC_COMMAND_STRUCT *pCMD = &cmd; + + return (fdc_read_data (buffer, len, pCMD, pFG)); +} +#endif /* (CONFIG_COMMANDS & CFG_CMD_FDOS) */ + +#if (CONFIG_COMMANDS & CFG_CMD_FDC) /**************************************************************************** * main routine do_fdcboot */ @@ -677,7 +750,7 @@ int do_fdcboot (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) return 1; } /* setup FDC and scan for drives */ - if(fdc_setup(pCMD,pFG)==FALSE) { + if(fdc_setup(boot_drive,pCMD,pFG)==FALSE) { printf("\n** Error in setup FDC **\n"); return 1; } diff --git a/common/cmd_fdos.c b/common/cmd_fdos.c new file mode 100644 index 0000000000..763f4181ac --- /dev/null +++ b/common/cmd_fdos.c @@ -0,0 +1,145 @@ +/* + * (C) Copyright 2002 + * Stäubli Faverges - <www.staubli.com> + * Pierre AUBERT p.aubert@staubli.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* + * Dos floppy support + */ + +#include <common.h> +#include <config.h> +#include <command.h> +#include <fdc.h> + +#if (CONFIG_COMMANDS & CFG_CMD_FDOS) + +/*----------------------------------------------------------------------------- + * do_fdosboot -- + *----------------------------------------------------------------------------- + */ +int do_fdosboot(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + char *name; + char *ep; + int size; + int rcode = 0; + char buf [10]; + int drive = CFG_FDC_DRIVE_NUMBER; + + /* pre-set load_addr */ + if ((ep = getenv("loadaddr")) != NULL) { + load_addr = simple_strtoul(ep, NULL, 16); + } + + /* pre-set Boot file name */ + if ((name = getenv("bootfile")) == NULL) { + name = "pImage"; + } + + switch (argc) { + case 1: + break; + case 2: + /* only one arg - accept two forms: + * just load address, or just boot file name. + * The latter form must be written "filename" here. + */ + if (argv[1][0] == '"') { /* just boot filename */ + name = argv [1]; + } else { /* load address */ + load_addr = simple_strtoul(argv[1], NULL, 16); + } + break; + case 3: + load_addr = simple_strtoul(argv[1], NULL, 16); + name = argv [2]; + break; + default: + printf ("Usage:\n%s\n", cmdtp->usage); + break; + } + + /* Init physical layer */ + if (!fdc_fdos_init (drive)) { + return (-1); + } + + /* Open file */ + if (dos_open (name) < 0) { + printf ("Unable to open %s\n", name); + return 1; + } + if ((size = dos_read (load_addr)) < 0) { + printf ("boot error\n"); + return 1; + } + flush_cache (load_addr, size); + + sprintf(buf, "%x", size); + setenv("filesize", buf); + + printf("Floppy DOS load complete: %d bytes loaded to 0x%lx\n", + size, load_addr); + + /* Check if we should attempt an auto-start */ + if (((ep = getenv("autostart")) != NULL) && (strcmp(ep,"yes") == 0)) { + char *local_args[2]; + extern int do_bootm (cmd_tbl_t *, int, int, char *[]); + local_args[0] = argv[0]; + local_args[1] = NULL; + printf ("Automatic boot of image at addr 0x%08lX ...\n", load_addr); + rcode = do_bootm (cmdtp, 0, 1, local_args); + } + return rcode; +} + +/*----------------------------------------------------------------------------- + * do_fdosls -- + *----------------------------------------------------------------------------- + */ +int do_fdosls(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + char *path = ""; + int drive = CFG_FDC_DRIVE_NUMBER; + + switch (argc) { + case 1: + break; + case 2: + path = argv [1]; + break; + } + + /* Init physical layer */ + if (!fdc_fdos_init (drive)) { + return (-1); + } + /* Open directory */ + if (dos_open (path) < 0) { + printf ("Unable to open %s\n", path); + return 1; + } + return (dos_dir ()); +} + +#endif diff --git a/common/cmd_ide.c b/common/cmd_ide.c index 9cbfe1bb04..e514cf71e3 100644 --- a/common/cmd_ide.c +++ b/common/cmd_ide.c @@ -44,6 +44,9 @@ #ifdef CONFIG_STATUS_LED # include <status_led.h> #endif +#ifdef __I386__ +#include <asm/io.h> +#endif #ifdef CONFIG_SHOW_BOOT_PROGRESS # include <status_led.h> @@ -114,7 +117,9 @@ ulong ide_bus_offset[CFG_IDE_MAXBUS] = { #endif }; +#ifdef __PPC__ #define ATA_CURR_BASE(dev) (CFG_ATA_BASE_ADDR+ide_bus_offset[IDE_BUS(dev)]) +#endif static int ide_bus_ok[CFG_IDE_MAXBUS]; @@ -142,9 +147,11 @@ static uchar ide_wait (int dev, ulong t); #define IDE_SPIN_UP_TIME_OUT 5000 /* 5 sec spin-up timeout */ -static void __inline__ outb(int dev, int port, unsigned char val); -static unsigned char __inline__ inb(int dev, int port); +static void __inline__ ide_outb(int dev, int port, unsigned char val); +static unsigned char __inline__ ide_inb(int dev, int port); +#ifdef __PPC__ static void input_swap_data(int dev, ulong *sect_buf, int words); +#endif static void input_data(int dev, ulong *sect_buf, int words); static void output_data(int dev, ulong *sect_buf, int words); static void ident_cpy (unsigned char *dest, unsigned char *src, unsigned int len); @@ -517,14 +524,14 @@ void ide_init (void) /* Select device */ udelay (100000); /* 100 ms */ - outb (dev, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(dev)); + ide_outb (dev, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(dev)); udelay (100000); /* 100 ms */ i = 0; do { udelay (10000); /* 10 ms */ - c = inb (dev, ATA_STATUS); + c = ide_inb (dev, ATA_STATUS); i++; if (i > (ATA_RESET_TIME * 100)) { puts ("** Timeout **\n"); @@ -679,30 +686,48 @@ set_pcmcia_timing (int pmode) /* ------------------------------------------------------------------------- */ +#ifdef __PPC__ static void __inline__ -outb(int dev, int port, unsigned char val) +ide_outb(int dev, int port, unsigned char val) { /* Ensure I/O operations complete */ __asm__ volatile("eieio"); *((uchar *)(ATA_CURR_BASE(dev)+port)) = val; #if 0 - printf ("OUTB: 0x%08lx <== 0x%02x\n", ATA_CURR_BASE(dev)+port, val); + printf ("ide_outb: 0x%08lx <== 0x%02x\n", ATA_CURR_BASE(dev)+port, val); #endif } +#else /* ! __PPC__ */ +static void __inline__ +ide_outb(int dev, int port, unsigned char val) +{ + outb(val, port); +} +#endif /* __PPC__ */ + +#ifdef __PPC__ static unsigned char __inline__ -inb(int dev, int port) +ide_inb(int dev, int port) { uchar val; /* Ensure I/O operations complete */ __asm__ volatile("eieio"); val = *((uchar *)(ATA_CURR_BASE(dev)+port)); #if 0 - printf ("INB: 0x%08lx ==> 0x%02x\n", ATA_CURR_BASE(dev)+port, val); + printf ("ide_inb: 0x%08lx ==> 0x%02x\n", ATA_CURR_BASE(dev)+port, val); #endif return (val); } +#else /* ! __PPC__ */ +static unsigned char __inline__ +ide_inb(int dev, int port) +{ + return inb(port); +} +#endif /* __PPC__ */ +#ifdef __PPC__ __inline__ unsigned ld_le16(const volatile unsigned short *addr) { unsigned val; @@ -722,7 +747,14 @@ input_swap_data(int dev, ulong *sect_buf, int words) *dbuf++ = ld_le16(pbuf); } } +#else /* ! __PPC__ */ +#define input_swap_data(x,y,z) input_data(x,y,z) +#endif /* __PPC__ */ + + + +#ifdef __PPC__ static void output_data(int dev, ulong *sect_buf, int words) { @@ -738,7 +770,15 @@ output_data(int dev, ulong *sect_buf, int words) *pbuf = *dbuf++; } } +#else /* ! __PPC__ */ +static void +output_data(int dev, ulong *sect_buf, int words) +{ + outsw(ATA_DATA_REG, sect_buf, words<<1); +} +#endif /* __PPC__ */ +#ifdef __PPC__ static void input_data(int dev, ulong *sect_buf, int words) { @@ -754,6 +794,14 @@ input_data(int dev, ulong *sect_buf, int words) *dbuf++ = *pbuf; } } +#else /* ! __PPC__ */ +static void +input_data(int dev, ulong *sect_buf, int words) +{ + insw(ATA_DATA_REG, sect_buf, words << 1); +} + +#endif /* __PPC__ */ /* ------------------------------------------------------------------------- */ @@ -773,19 +821,19 @@ static void ide_ident (block_dev_desc_t *dev_desc) ide_led (DEVICE_LED(device), 1); /* LED on */ /* Select device */ - outb (device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device)); + ide_outb (device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device)); dev_desc->if_type=IF_TYPE_IDE; #ifdef CONFIG_ATAPI /* check signature */ - if ((inb(device,ATA_SECT_CNT)==0x01) && - (inb(device,ATA_SECT_NUM)==0x01) && - (inb(device,ATA_CYL_LOW)==0x14) && - (inb(device,ATA_CYL_HIGH)==0xEB)) { + if ((ide_inb(device,ATA_SECT_CNT) == 0x01) && + (ide_inb(device,ATA_SECT_NUM) == 0x01) && + (ide_inb(device,ATA_CYL_LOW) == 0x14) && + (ide_inb(device,ATA_CYL_HIGH) == 0xEB)) { /* ATAPI Signature found */ dev_desc->if_type=IF_TYPE_ATAPI; /* Start Ident Command */ - outb (device, ATA_COMMAND, ATAPI_CMD_IDENT); + ide_outb (device, ATA_COMMAND, ATAPI_CMD_IDENT); /* * Wait for completion - ATAPI devices need more time * to become ready @@ -797,7 +845,7 @@ static void ide_ident (block_dev_desc_t *dev_desc) { /* Start Ident Command */ - outb (device, ATA_COMMAND, ATA_CMD_IDENT); + ide_outb (device, ATA_COMMAND, ATA_CMD_IDENT); /* Wait for completion */ @@ -867,15 +915,15 @@ static void ide_ident (block_dev_desc_t *dev_desc) #if 0 /* only used to test the powersaving mode, * if enabled, the drive goes after 5 sec * in standby mode */ - outb (device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device)); + ide_outb (device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device)); c = ide_wait (device, IDE_TIME_OUT); - outb (device, ATA_SECT_CNT, 1); - outb (device, ATA_LBA_LOW, 0); - outb (device, ATA_LBA_MID, 0); - outb (device, ATA_LBA_HIGH, 0); - outb (device, ATA_DEV_HD, ATA_LBA | + ide_outb (device, ATA_SECT_CNT, 1); + ide_outb (device, ATA_LBA_LOW, 0); + ide_outb (device, ATA_LBA_MID, 0); + ide_outb (device, ATA_LBA_HIGH, 0); + ide_outb (device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device)); - outb (device, ATA_COMMAND, 0xe3); + ide_outb (device, ATA_COMMAND, 0xe3); udelay (50); c = ide_wait (device, IDE_TIME_OUT); /* can't take over 500 ms */ #endif @@ -897,7 +945,7 @@ ulong ide_read (int device, ulong blknr, ulong blkcnt, ulong *buffer) /* Select device */ - outb (device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device)); + ide_outb (device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device)); c = ide_wait (device, IDE_TIME_OUT); if (c & ATA_STAT_BUSY) { @@ -907,7 +955,7 @@ ulong ide_read (int device, ulong blknr, ulong blkcnt, ulong *buffer) /* first check if the drive is in Powersaving mode, if yes, * increase the timeout value */ - outb (device, ATA_COMMAND, ATA_CMD_CHK_PWR); + ide_outb (device, ATA_COMMAND, ATA_CMD_CHK_PWR); udelay (50); c = ide_wait (device, IDE_TIME_OUT); /* can't take over 500 ms */ @@ -919,7 +967,7 @@ ulong ide_read (int device, ulong blknr, ulong blkcnt, ulong *buffer) if ((c & ATA_STAT_ERR) == ATA_STAT_ERR) { printf ("No Powersaving mode %X\n", c); } else { - c = inb(device,ATA_SECT_CNT); + c = ide_inb(device,ATA_SECT_CNT); PRINTF("Powersaving %02X\n",c); if(c==0) pwrsave=1; @@ -935,14 +983,14 @@ ulong ide_read (int device, ulong blknr, ulong blkcnt, ulong *buffer) break; } - outb (device, ATA_SECT_CNT, 1); - outb (device, ATA_LBA_LOW, (blknr >> 0) & 0xFF); - outb (device, ATA_LBA_MID, (blknr >> 8) & 0xFF); - outb (device, ATA_LBA_HIGH, (blknr >> 16) & 0xFF); - outb (device, ATA_DEV_HD, ATA_LBA | + ide_outb (device, ATA_SECT_CNT, 1); + ide_outb (device, ATA_LBA_LOW, (blknr >> 0) & 0xFF); + ide_outb (device, ATA_LBA_MID, (blknr >> 8) & 0xFF); + ide_outb (device, ATA_LBA_HIGH, (blknr >> 16) & 0xFF); + ide_outb (device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device) | ((blknr >> 24) & 0xF) ); - outb (device, ATA_COMMAND, ATA_CMD_READ); + ide_outb (device, ATA_COMMAND, ATA_CMD_READ); udelay (50); @@ -960,7 +1008,7 @@ ulong ide_read (int device, ulong blknr, ulong blkcnt, ulong *buffer) } input_data (device, buffer, ATA_SECTORWORDS); - (void) inb (device, ATA_STATUS); /* clear IRQ */ + (void) ide_inb (device, ATA_STATUS); /* clear IRQ */ ++n; ++blknr; @@ -983,7 +1031,7 @@ ulong ide_write (int device, ulong blknr, ulong blkcnt, ulong *buffer) /* Select device */ - outb (device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device)); + ide_outb (device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device)); while (blkcnt-- > 0) { @@ -994,14 +1042,14 @@ ulong ide_write (int device, ulong blknr, ulong blkcnt, ulong *buffer) goto WR_OUT; } - outb (device, ATA_SECT_CNT, 1); - outb (device, ATA_LBA_LOW, (blknr >> 0) & 0xFF); - outb (device, ATA_LBA_MID, (blknr >> 8) & 0xFF); - outb (device, ATA_LBA_HIGH, (blknr >> 16) & 0xFF); - outb (device, ATA_DEV_HD, ATA_LBA | + ide_outb (device, ATA_SECT_CNT, 1); + ide_outb (device, ATA_LBA_LOW, (blknr >> 0) & 0xFF); + ide_outb (device, ATA_LBA_MID, (blknr >> 8) & 0xFF); + ide_outb (device, ATA_LBA_HIGH, (blknr >> 16) & 0xFF); + ide_outb (device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device) | ((blknr >> 24) & 0xF) ); - outb (device, ATA_COMMAND, ATA_CMD_WRITE); + ide_outb (device, ATA_COMMAND, ATA_CMD_WRITE); udelay (50); @@ -1014,7 +1062,7 @@ ulong ide_write (int device, ulong blknr, ulong blkcnt, ulong *buffer) } output_data (device, buffer, ATA_SECTORWORDS); - c = inb (device, ATA_STATUS); /* clear IRQ */ + c = ide_inb (device, ATA_STATUS); /* clear IRQ */ ++n; ++blknr; buffer += ATA_SECTORWORDS; @@ -1063,7 +1111,7 @@ static uchar ide_wait (int dev, ulong t) ulong delay = 10 * t; /* poll every 100 us */ uchar c; - while ((c = inb(dev, ATA_STATUS)) & ATA_STAT_BUSY) { + while ((c = ide_inb(dev, ATA_STATUS)) & ATA_STAT_BUSY) { udelay (100); if (delay-- == 0) { break; @@ -1188,6 +1236,7 @@ static void ide_led (uchar led, uchar status) #define AT_PRINTF(fmt,args...) #endif +#ifdef __PPC__ /* since ATAPI may use commands with not 4 bytes alligned length * we have our own transfer functions, 2 bytes alligned */ static void @@ -1218,6 +1267,22 @@ input_data_shorts(int dev, ushort *sect_buf, int shorts) } } +#else /* ! __PPC__ */ +static void +output_data_shorts(int dev, ushort *sect_buf, int shorts) +{ + outsw(ATA_DATA_REG, sect_buf, shorts); +} + + +static void +input_data_shorts(int dev, ushort *sect_buf, int shorts) +{ + insw(ATA_DATA_REG, sect_buf, shorts); +} + +#endif /* __PPC__ */ + /* * Wait until (Status & mask) == res, or timeout (in ms) * Return last status @@ -1229,9 +1294,8 @@ static uchar atapi_wait_mask (int dev, ulong t,uchar mask, uchar res) ulong delay = 10 * t; /* poll every 100 us */ uchar c; - c = inb(dev,ATA_DEV_CTL); /* prevents to read the status before valid */ - while (((c = inb(dev, ATA_STATUS)) & mask) - != res) { + c = ide_inb(dev,ATA_DEV_CTL); /* prevents to read the status before valid */ + while (((c = ide_inb(dev, ATA_STATUS)) & mask) != res) { /* break if error occurs (doesn't make sense to wait more) */ if((c & ATA_STAT_ERR)==ATA_STAT_ERR) break; @@ -1256,7 +1320,7 @@ unsigned char atapi_issue(int device,unsigned char* ccb,int ccblen, unsigned cha */ mask = ATA_STAT_BUSY|ATA_STAT_DRQ; res = 0; - outb (device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device)); + ide_outb (device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device)); c = atapi_wait_mask(device,ATAPI_TIME_OUT,mask,res); if ((c & mask) != res) { printf ("ATAPI_ISSUE: device %d not ready status %X\n", device,c); @@ -1264,12 +1328,12 @@ unsigned char atapi_issue(int device,unsigned char* ccb,int ccblen, unsigned cha goto AI_OUT; } /* write taskfile */ - outb (device, ATA_ERROR_REG, 0); /* no DMA, no overlaped */ - outb (device, ATA_CYL_LOW, (unsigned char)(buflen & 0xFF)); - outb (device, ATA_CYL_HIGH, (unsigned char)((buflen<<8) & 0xFF)); - outb (device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device)); + ide_outb (device, ATA_ERROR_REG, 0); /* no DMA, no overlaped */ + ide_outb (device, ATA_CYL_LOW, (unsigned char)(buflen & 0xFF)); + ide_outb (device, ATA_CYL_HIGH, (unsigned char)((buflen<<8) & 0xFF)); + ide_outb (device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device)); - outb (device, ATA_COMMAND, ATAPI_CMD_PACKET); + ide_outb (device, ATA_COMMAND, ATAPI_CMD_PACKET); udelay (50); mask = ATA_STAT_DRQ|ATA_STAT_BUSY|ATA_STAT_ERR; @@ -1295,7 +1359,7 @@ unsigned char atapi_issue(int device,unsigned char* ccb,int ccblen, unsigned cha c = atapi_wait_mask(device,ATAPI_TIME_OUT,mask,res); if ((c & mask) != res ) { if (c & ATA_STAT_ERR) { - err=(inb(device,ATA_ERROR_REG))>>4; + err=(ide_inb(device,ATA_ERROR_REG))>>4; AT_PRINTF("atapi_issue 1 returned sense key %X status %02X\n",err,c); } else { printf ("ATTAPI_ISSUE: (no DRQ) after sending ccb (%x) status 0x%02x\n", ccb[0],c); @@ -1303,9 +1367,9 @@ unsigned char atapi_issue(int device,unsigned char* ccb,int ccblen, unsigned cha } goto AI_OUT; } - n=inb(device, ATA_CYL_HIGH); + n=ide_inb(device, ATA_CYL_HIGH); n<<=8; - n+=inb(device, ATA_CYL_LOW); + n+=ide_inb(device, ATA_CYL_LOW); if(n>buflen) { printf("ERROR, transfer bytes %d requested only %d\n",n,buflen); err=0xff; @@ -1324,7 +1388,7 @@ unsigned char atapi_issue(int device,unsigned char* ccb,int ccblen, unsigned cha /* we transfer shorts */ n>>=1; /* ok now decide if it is an in or output */ - if ((inb(device, ATA_SECT_CNT)&0x02)==0) { + if ((ide_inb(device, ATA_SECT_CNT)&0x02)==0) { AT_PRINTF("Write to device\n"); output_data_shorts(device,(unsigned short *)buffer,n); } else { @@ -1337,7 +1401,7 @@ unsigned char atapi_issue(int device,unsigned char* ccb,int ccblen, unsigned cha res=0; c = atapi_wait_mask(device,ATAPI_TIME_OUT,mask,res); if ((c & ATA_STAT_ERR) == ATA_STAT_ERR) { - err=(inb(device,ATA_ERROR_REG) >> 4); + err=(ide_inb(device,ATA_ERROR_REG) >> 4); AT_PRINTF("atapi_issue 2 returned sense key %X status %X\n",err,c); } else { err = 0; diff --git a/common/command.c b/common/command.c index f70cad8cbc..cab68abf8e 100644 --- a/common/command.c +++ b/common/command.c @@ -70,6 +70,7 @@ #include <cmd_vfd.h> /* load a bitmap to the VFDs on TRAB */ #include <cmd_log.h> +#include <cmd_fdos.h> /* * HELP command @@ -253,6 +254,8 @@ cmd_tbl_t cmd_tbl[] = { CMD_TBL_FCCINFO CMD_TBL_FLERASE CMD_TBL_FDC + CMD_TBL_FDOS_BOOT + CMD_TBL_FDOS_LS CMD_TBL_FLINFO CMD_TBL_FPGA CMD_TBL_JFFS2_FSINFO diff --git a/cpu/i386/Makefile b/cpu/i386/Makefile new file mode 100644 index 0000000000..1482398efe --- /dev/null +++ b/cpu/i386/Makefile @@ -0,0 +1,43 @@ +# +# (C) Copyright 2002 +# Daniel Engström, Omicron Ceti AB, daniel@omicron.se. +# +# See file CREDITS for list of people who contributed to this +# project. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# + +include $(TOPDIR)/config.mk + +LIB = 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 + +######################################################################### diff --git a/cpu/i386/config.mk b/cpu/i386/config.mk new file mode 100644 index 0000000000..70caeb270a --- /dev/null +++ b/cpu/i386/config.mk @@ -0,0 +1,26 @@ +# +# (C) Copyright 2002 +# Daniel Engström, Omicron Ceti AB, daniel@omicron.se. +# +# See file CREDITS for list of people who contributed to this +# project. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# + +PLATFORM_RELFLAGS += # -pipe -mpreferred-stack-boundary=2 -fno-builtin -nostdinc -nostdlib + +PLATFORM_CPPFLAGS += -march=i386 diff --git a/cpu/i386/cpu.c b/cpu/i386/cpu.c new file mode 100644 index 0000000000..669823f946 --- /dev/null +++ b/cpu/i386/cpu.c @@ -0,0 +1,62 @@ +/* + * (C) Copyright 2002 + * Daniel Engström, Omicron Ceti AB, daniel@omicron.se. + * + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Marius Groeger <mgroeger@sysgo.de> + * + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Alex Zuepke <azu@sysgo.de> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* + * CPU specific code + */ + +#include <common.h> +#include <command.h> + +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; +} + diff --git a/cpu/i386/interrupts.c b/cpu/i386/interrupts.c new file mode 100644 index 0000000000..81d6881857 --- /dev/null +++ b/cpu/i386/interrupts.c @@ -0,0 +1,583 @@ +/* + * (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 <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 diff --git a/cpu/i386/reset.S b/cpu/i386/reset.S new file mode 100644 index 0000000000..57e32a8b7f --- /dev/null +++ b/cpu/i386/reset.S @@ -0,0 +1,38 @@ +/* + * U-boot - i386 Startup Code + * + * Copyright (c) 2002 Omicron Ceti AB, Daniel Engström <denaiel@omicron.se> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* Reset vector, jumps to start16.S */ + +.extern start16 + +.section .reset, "ax" +.code16 +reset_vector: + cli + cld + jmp start16 + + .org 0xf + nop + diff --git a/cpu/i386/serial.c b/cpu/i386/serial.c new file mode 100644 index 0000000000..c0d2e8aa14 --- /dev/null +++ b/cpu/i386/serial.c @@ -0,0 +1,460 @@ +/* + * (C) Copyright 2002 + * Daniel Engström, Omicron Ceti AB, daniel@omicron.se + * + * (C) Copyright 2000 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ +/*------------------------------------------------------------------------------+ */ +/* + * This source code 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 */ + diff --git a/cpu/i386/start.S b/cpu/i386/start.S new file mode 100644 index 0000000000..025555c0a1 --- /dev/null +++ b/cpu/i386/start.S @@ -0,0 +1,198 @@ +/* + * U-boot - i386 Startup Code + * + * Copyright (c) 2002 Omicron Ceti AB, Daniel Engström <denaiel@omicron.se> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + + +#include <config.h> +#include <version.h> + + +.section .text +.code32 +.globl _start +.type _start, @function +.globl _i386boot_start +_i386boot_start: +_start: + movl $0x18,%eax /* Load our segement registes, the + * gdt have already been loaded by start16.S */ + movw %ax,%fs + movw %ax,%ds + movw %ax,%gs + movw %ax,%es + movw %ax,%ss + + /* We call a few functions in the board support package + * since we have no stack yet we'll have to use %ebp + * to store the return address */ + + /* Early platform init (setup gpio, etc ) */ + mov $early_board_init_ret, %ebp + jmp early_board_init +early_board_init_ret: + + /* The __port80 entry-point should be usabe by now */ + /* so we try to indicate progress */ + movw $0x01, %ax + movl $.progress0, %ebp + jmp __show_boot_progress +.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 + + diff --git a/cpu/i386/start16.S b/cpu/i386/start16.S new file mode 100644 index 0000000000..590a5a6c9d --- /dev/null +++ b/cpu/i386/start16.S @@ -0,0 +1,112 @@ +/* + * U-boot - i386 Startup Code + * + * Copyright (c) 2002 Omicron Ceti AB, Daniel Engström <denaiel@omicron.se> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + + +#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) */ diff --git a/cpu/i386/timer.c b/cpu/i386/timer.c new file mode 100644 index 0000000000..a23cd6e48b --- /dev/null +++ b/cpu/i386/timer.c @@ -0,0 +1,211 @@ +/* + * (C) Copyright 2002 + * Daniel Engström, Omicron Ceti AB, daniel@omicron.se. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/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 diff --git a/doc/README-i386 b/doc/README-i386 new file mode 100644 index 0000000000..99b3e198c4 --- /dev/null +++ b/doc/README-i386 @@ -0,0 +1,74 @@ +This is my attempt to port PPCBoot to the i386 platform. This +work was sponsored by my emplyer, Omicron Ceti AB. http://www.omicron.se + +It is currently capable of booting a linux bzImage from flash on +the AMD SC520 CDP platform. + +It was originally based on PPCBoot taken from the CVS October 28 2002. + +To compile: + +1) Unpack the source tree, either from the complete tarball or + from the virgin snapshot + the patch + +2) Configure the source + $ make sc520_cdp_comfig + $ make + +To use this code on the CDP: +1) Make a suitable kernel, I used 2.4.19 with the mtd-support updated + from the MTD CVS and a patch to allow root=/dev/mtdblock1 which I + included at the end of this file. + The following options in the MTD section might be useful: + + CONFIG_MTD_PHYSMAP=y + CONFIG_MTD_PHYSMAP_START=38100000 + CONFIG_MTD_PHYSMAP_LEN=7a0000 + CONFIG_MTD_PHYSMAP_BUSWIDTH=2 + + +2) Program it in to the CDP flashbank with remon + ppcboot.bin should be programmed att offset 0x7e000 and the kernel at + offset 0. If you want to use a jffs2 root file system (not included here), + it should be programmed to offset 0x100000. + + remon> z + remon> yi + remon> ns ppcboot.bin 7e0000 + remon> ns bzImage 0 + remon> ns image.jffs2 100000 + +3) Connect a terminal to the 25pin serial port at 9600bps, and start the CDP. + + remon> z + remon> g + +4) PPCboot should output some message and a prompt on the terminal, to + start the kernel issue the following command: + + BOOT> bootm + +5) The kernel should boot, and mount the root filesystem if present. + +We hope you find this stuff useful +Daniel Engström, Omicron Ceti AB, daniel@omicron.se + + + +--- linux-2.4.19-orig/init/do_mounts.c Sat Aug 3 02:39:46 2002 ++++ linux-2.4.19/init/do_mounts.c Mon Sep 23 16:21:33 2002 +@@ -224,6 +224,14 @@ + { "ftlc", 0x2c10 }, + { "ftld", 0x2c18 }, + { "mtdblock", 0x1f00 }, ++ { "mtdblock0", 0x1f00 }, ++ { "mtdblock1", 0x1f01 }, ++ { "mtdblock2", 0x1f02 }, ++ { "mtdblock3", 0x1f03 }, ++ { "mtdblock4", 0x1f04 }, ++ { "mtdblock5", 0x1f05 }, ++ { "mtdblock6", 0x1f06 }, ++ { "mtdblock7", 0x1f07 }, + { NULL, 0 } + }; + diff --git a/doc/TODO-i386 b/doc/TODO-i386 new file mode 100644 index 0000000000..0969cbcd58 --- /dev/null +++ b/doc/TODO-i386 @@ -0,0 +1,39 @@ +i386 port missing features: +* i386 cleaness (wbinvld is 486+ ... ) +* Pentium TSC timer/udelay +* setup the BIOS data area and BIOS equipment word to reflect machine config. +* Make reset work (from Linux and from the boot prompt) +* DMA, FDC, RTC, KBC initialization +* video card support (call BIOS to initialize, use helper routrine in BSP to shadow + video rom if on pci) and PC keyboard +* split of part of cpu/i386/interrupt.c to cpu/i385/entry.c? +* re-entry of protected mode from real mode, should be added to realmode_switch.S + (and used by INT 10h and INT 16h handlers for console I/O during early + linux boot...) +* missing functions in lib_i386 and cpu/i386 +* speaker beep interface + +i386 port bugs: +* IDE does not work + +SC520 missing features: +* Watchdog +* SC520 timer/udelay +* SC520 3rd PIC +* SC520 ICE serial +* SC520 MMCR reset + +SC520 CDP board support missing features: +* Synchronius serial port and seriel EEPROM +* environment in SEEP +* environment in flash +* environment in sram +* status LED ? +* flash driver + +SC520 CDP board support bugs: +* 0x680 LEDS dos not work for me +* is it possible to make both the internal serial ports and the + ports on the sio work at the same time? +* ali sio cio lines? +* On-borad ethernet does not work from Linux diff --git a/drivers/pcnet.c b/drivers/pcnet.c index f69cd2ce79..1ba7d817a5 100644 --- a/drivers/pcnet.c +++ b/drivers/pcnet.c @@ -288,8 +288,8 @@ static int pcnet_probe(struct eth_device* dev, bd_t *bis, int dev_nr) unsigned int val; val = pcnet_read_csr(dev, i+12) & 0x0ffff; /* There may be endianness issues here. */ - dev->dev_addr[2*i] = val & 0x0ff; - dev->dev_addr[2*i+1] = (val >> 8) & 0x0ff; + dev->enetaddr[2*i ] = val & 0x0ff; + dev->enetaddr[2*i+1] = (val >> 8) & 0x0ff; } #endif /* PCNET_HAS_PROM */ @@ -349,7 +349,7 @@ static int pcnet_init(struct eth_device* dev, bd_t *bis) lp->rx_ring[i].base = PCI_TO_MEM_LE(dev, lp->rx_buf[i]); lp->rx_ring[i].buf_length = cpu_to_le16(-PKT_BUF_SZ); lp->rx_ring[i].status = cpu_to_le16(0x8000); - DEBUG1("Rx%d: base=0x%x buf_length=0x%x status=0x%x\n", + DEBUG1("Rx%d: base=0x%x buf_length=0x%hx status=0x%hx\n", i, lp->rx_ring[i].base, lp->rx_ring[i].buf_length, lp->rx_ring[i].status); } diff --git a/examples/syscall.S b/examples/syscall.S index 9e8725edcd..9934490433 100644 --- a/examples/syscall.S +++ b/examples/syscall.S @@ -38,12 +38,26 @@ mon_free: sub fp, ip, #4 ldmea fp, {fp, sp, pc} #else /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */ + +#ifdef CONFIG_I386 /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */ +#define SYMBOL_NAME(X) X +#define SYMBOL_NAME_LABEL(X) X##: + +#define SYSCALL(name,n) \ + .globl SYMBOL_NAME(name) ; \ +SYMBOL_NAME_LABEL(name) ; \ + ret + +#endif /* CONFIG_I386 */ + +#ifdef CONFIG_PPC #define SYSCALL(name,n) \ .globl name ; \ name: ; \ li r0,n ; \ sc ; \ blr +#endif /* CONFIG_PPC */ .text diff --git a/fs/Makefile b/fs/Makefile index 9ed0f1e5a9..ad74942d08 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -22,7 +22,7 @@ # # -SUBDIRS := jffs2 +SUBDIRS := jffs2 fdos .depend all: @for dir in $(SUBDIRS) ; do \ diff --git a/fs/fdos/Makefile b/fs/fdos/Makefile new file mode 100644 index 0000000000..af0fff1c84 --- /dev/null +++ b/fs/fdos/Makefile @@ -0,0 +1,49 @@ +# +# (C) Copyright 2002 +# Stäubli Faverges - <www.staubli.com> +# Pierre AUBERT p.aubert@staubli.com +# +# +# See file CREDITS for list of people who contributed to this +# project. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# + +include $(TOPDIR)/config.mk + +LIB = libfdos.a + +AOBJS = +COBJS = fat.o vfat.o dev.o fdos.o fs.o subdir.o +OBJS = $(AOBJS) $(COBJS) + +#CPPFLAGS += + +all: $(LIB) $(AOBJS) + +$(LIB): .depend $(OBJS) + $(AR) crv $@ $(OBJS) + + +######################################################################### + +.depend: Makefile $(AOBJS:.o=.S) $(COBJS:.o=.c) + $(CC) -M $(CFLAGS) $(AOBJS:.o=.S) $(COBJS:.o=.c) > $@ + +sinclude .depend + +######################################################################### diff --git a/fs/fdos/dev.c b/fs/fdos/dev.c new file mode 100644 index 0000000000..f38d07dbd8 --- /dev/null +++ b/fs/fdos/dev.c @@ -0,0 +1,195 @@ +/* + * (C) Copyright 2002 + * Stäubli Faverges - <www.staubli.com> + * Pierre AUBERT p.aubert@staubli.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <config.h> + +#include "dos.h" +#include "fdos.h" + +#if (CONFIG_COMMANDS & CFG_CMD_FDOS) + +#define NB_HEADS 2 +#define NB_TRACKS 80 +#define NB_SECTORS 18 + + +static int lastwhere; + +/*----------------------------------------------------------------------------- + * dev_open -- + *----------------------------------------------------------------------------- + */ +int dev_open (void) +{ + lastwhere = 0; + return (0); +} + +/*----------------------------------------------------------------------------- + * dev_read -- len and where are sectors number + *----------------------------------------------------------------------------- + */ +int dev_read (void *buffer, int where, int len) +{ + PRINTF ("dev_read (len = %d, where = %d)\n", len, where); + + /* Si on ne desire pas lire a la position courante, il faut un seek */ + if (where != lastwhere) { + if (!fdc_fdos_seek (where)) { + PRINTF ("seek error in dev_read"); + lastwhere = -1; + return (-1); + } + } + + if (!fdc_fdos_read (buffer, len)) { + PRINTF ("read error\n"); + lastwhere = -1; + return (-1); + } + lastwhere = where + len; + return (0); +} +/*----------------------------------------------------------------------------- + * check_dev -- verify the diskette format + *----------------------------------------------------------------------------- + */ +int check_dev (BootSector_t *boot, Fs_t *fs) +{ + unsigned int heads, sectors, tracks; + int BootP, Infp0, InfpX, InfTm; + int sect_per_track; + + /* Display Boot header */ + PRINTF ("Jump to boot code 0x%02x 0x%02x 0x%02x\n", + boot -> jump [0], boot -> jump [1], boot -> jump[2]); + PRINTF ("OEM name & version '%*.*s'\n", + BANNER_LG, BANNER_LG, boot -> banner ); + PRINTF ("Bytes per sector hopefully 512 %d\n", + __le16_to_cpu (boot -> secsiz)); + PRINTF ("Cluster size in sectors %d\n", + boot -> clsiz); + PRINTF ("Number of reserved (boot) sectors %d\n", + __le16_to_cpu (boot -> nrsvsect)); + PRINTF ("Number of FAT tables hopefully 2 %d\n", + boot -> nfat); + PRINTF ("Number of directory slots %d\n", + __le16_to_cpu (boot -> dirents)); + PRINTF ("Total sectors on disk %d\n", + __le16_to_cpu (boot -> psect)); + PRINTF ("Media descriptor=first byte of FAT %d\n", + boot -> descr); + PRINTF ("Sectors in FAT %d\n", + __le16_to_cpu (boot -> fatlen)); + PRINTF ("Sectors/track %d\n", + __le16_to_cpu (boot -> nsect)); + PRINTF ("Heads %d\n", + __le16_to_cpu (boot -> nheads)); + PRINTF ("number of hidden sectors %d\n", + __le32_to_cpu (boot -> nhs)); + PRINTF ("big total sectors %d\n", + __le32_to_cpu (boot -> bigsect)); + PRINTF ("physical drive ? %d\n", + boot -> physdrive); + PRINTF ("reserved %d\n", + boot -> reserved); + PRINTF ("dos > 4.0 diskette %d\n", + boot -> dos4); + PRINTF ("serial number %d\n", + __le32_to_cpu (boot -> serial)); + PRINTF ("disk label %*.*s\n", + LABEL_LG, LABEL_LG, boot -> label); + PRINTF ("FAT type %8.8s\n", + boot -> fat_type); + PRINTF ("reserved by 2M %d\n", + boot -> res_2m); + PRINTF ("2M checksum (not used) %d\n", + boot -> CheckSum); + PRINTF ("2MF format version %d\n", + boot -> fmt_2mf); + PRINTF ("1 if write track after format %d\n", + boot -> wt); + PRINTF ("data transfer rate on track 0 %d\n", + boot -> rate_0); + PRINTF ("data transfer rate on track<>0 %d\n", + boot -> rate_any); + PRINTF ("offset to boot program %d\n", + __le16_to_cpu (boot -> BootP)); + PRINTF ("T1: information for track 0 %d\n", + __le16_to_cpu (boot -> Infp0)); + PRINTF ("T2: information for track<>0 %d\n", + __le16_to_cpu (boot -> InfpX)); + PRINTF ("T3: track sectors size table %d\n", + __le16_to_cpu (boot -> InfTm)); + PRINTF ("Format date 0x%04x\n", + __le16_to_cpu (boot -> DateF)); + PRINTF ("Format time 0x%04x\n", + __le16_to_cpu (boot -> TimeF)); + + + /* informations are extracted from boot sector */ + heads = __le16_to_cpu (boot -> nheads); + sectors = __le16_to_cpu (boot -> nsect); + fs -> tot_sectors = __le32_to_cpu (boot -> bigsect); + if (__le16_to_cpu (boot -> psect) != 0) { + fs -> tot_sectors = __le16_to_cpu (boot -> psect); + } + + sect_per_track = heads * sectors; + tracks = (fs -> tot_sectors + sect_per_track - 1) / sect_per_track; + + BootP = __le16_to_cpu (boot -> BootP); + Infp0 = __le16_to_cpu (boot -> Infp0); + InfpX = __le16_to_cpu (boot -> InfpX); + InfTm = __le16_to_cpu (boot -> InfTm); + + if (boot -> dos4 == EXTENDED_BOOT && + strncmp( boot->banner,"2M", 2 ) == 0 && + BootP < SZ_STD_SECTOR && + Infp0 < SZ_STD_SECTOR && + InfpX < SZ_STD_SECTOR && + InfTm < SZ_STD_SECTOR && + BootP >= InfTm + 2 && + InfTm >= InfpX && + InfpX >= Infp0 && + Infp0 >= 76 ) { + + return (-1); + } + + if (heads != NB_HEADS || + tracks != NB_TRACKS || + sectors != NB_SECTORS || + __le16_to_cpu (boot -> secsiz) != SZ_STD_SECTOR || + fs -> tot_sectors == 0 || + (fs -> tot_sectors % sectors) != 0) { + return (-1); + } + + return (0); +} + + +#endif diff --git a/fs/fdos/dos.h b/fs/fdos/dos.h new file mode 100644 index 0000000000..71701c9fb0 --- /dev/null +++ b/fs/fdos/dos.h @@ -0,0 +1,177 @@ +/* + * (C) Copyright 2002 + * Stäubli Faverges - <www.staubli.com> + * Pierre AUBERT p.aubert@staubli.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef _DOS_H_ +#define _DOS_H_ + +/* Definitions for Dos diskettes */ + +/* General definitions */ +#define SZ_STD_SECTOR 512 /* Standard sector size */ +#define MDIR_SIZE 32 /* Direntry size */ +#define FAT_BITS 12 /* Diskette use 12 bits fat */ + +#define MAX_PATH 128 /* Max size of the MSDOS PATH */ +#define MAX_DIR_SECS 64 /* Taille max d'un repertoire (en */ + /* secteurs) */ +/* Misc. definitions */ +#define DELMARK '\xe5' +#define EXTENDED_BOOT (0x29) +#define MEDIA_STD (0xf0) +#define JUMP_0_1 (0xe9) +#define JUMP_0_2 (0xeb) + +/* Boot size is 256 bytes, but we need to read almost a sector, then + assume bootsize is 512 */ +#define BOOTSIZE 512 + +/* Fat definitions for 12 bits fat */ +#define FAT12_MAX_NB 4086 +#define FAT12_LAST 0x0ff6 +#define FAT12_END 0x0fff + +/* file attributes */ +#define ATTR_READONLY 0x01 +#define ATTR_HIDDEN 0x02 +#define ATTR_SYSTEM 0x04 +#define ATTR_VOLUME 0x08 +#define ATTR_DIRECTORY 0x10 +#define ATTR_ARCHIVE 0x20 +#define ATTR_VSE 0x0f + +/* Name format */ +#define EXTCASE 0x10 +#define BASECASE 0x8 + +/* Definition of the boot sector */ +#define BANNER_LG 8 +#define LABEL_LG 11 + +typedef struct bootsector +{ + unsigned char jump [3]; /* 0 Jump to boot code */ + char banner [BANNER_LG]; /* 3 OEM name & version */ + unsigned short secsiz; /* 11 Bytes per sector hopefully 512 */ + unsigned char clsiz; /* 13 Cluster size in sectors */ + unsigned short nrsvsect; /* 14 Number of reserved (boot) sectors */ + unsigned char nfat; /* 16 Number of FAT tables hopefully 2 */ + unsigned short dirents; /* 17 Number of directory slots */ + unsigned short psect; /* 19 Total sectors on disk */ + unsigned char descr; /* 21 Media descriptor=first byte of FAT */ + unsigned short fatlen; /* 22 Sectors in FAT */ + unsigned short nsect; /* 24 Sectors/track */ + unsigned short nheads; /* 26 Heads */ + unsigned int nhs; /* 28 number of hidden sectors */ + unsigned int bigsect; /* 32 big total sectors */ + unsigned char physdrive; /* 36 physical drive ? */ + unsigned char reserved; /* 37 reserved */ + unsigned char dos4; /* 38 dos > 4.0 diskette */ + unsigned int serial; /* 39 serial number */ + char label [LABEL_LG]; /* 43 disk label */ + char fat_type [8]; /* 54 FAT type */ + unsigned char res_2m; /* 62 reserved by 2M */ + unsigned char CheckSum; /* 63 2M checksum (not used) */ + unsigned char fmt_2mf; /* 64 2MF format version */ + unsigned char wt; /* 65 1 if write track after format */ + unsigned char rate_0; /* 66 data transfer rate on track 0 */ + unsigned char rate_any; /* 67 data transfer rate on track<>0 */ + unsigned short BootP; /* 68 offset to boot program */ + unsigned short Infp0; /* 70 T1: information for track 0 */ + unsigned short InfpX; /* 72 T2: information for track<>0 */ + unsigned short InfTm; /* 74 T3: track sectors size table */ + unsigned short DateF; /* 76 Format date */ + unsigned short TimeF; /* 78 Format time */ + unsigned char junk [BOOTSIZE - 80]; /* 80 remaining data */ +} __attribute__ ((packed)) BootSector_t; + +/* Structure d'une entree de repertoire */ +typedef struct directory { + char name [8]; /* file name */ + char ext [3]; /* file extension */ + unsigned char attr; /* attribute byte */ + unsigned char Case; /* case of short filename */ + unsigned char reserved [9]; /* ?? */ + unsigned char time [2]; /* time stamp */ + unsigned char date [2]; /* date stamp */ + unsigned short start; /* starting cluster number */ + unsigned int size; /* size of the file */ +} __attribute__ ((packed)) Directory_t; + + + +#define MAX_VFAT_SUBENTRIES 20 +#define VSE_NAMELEN 13 + +#define VSE1SIZE 5 +#define VSE2SIZE 6 +#define VSE3SIZE 2 + +#define VBUFSIZE ((MAX_VFAT_SUBENTRIES * VSE_NAMELEN) + 1) + +#define MAX_VNAMELEN (255) + +#define VSE_PRESENT 0x01 +#define VSE_LAST 0x40 +#define VSE_MASK 0x1f + +/* Flag used by vfat_lookup */ +#define DO_OPEN 1 +#define ACCEPT_PLAIN 0x20 +#define ACCEPT_DIR 0x10 +#define ACCEPT_LABEL 0x08 +#define SINGLE 2 +#define MATCH_ANY 0x40 + +struct vfat_subentry { + unsigned char id; /* VSE_LAST pour la fin, VSE_MASK */ + /* pour un VSE */ + char text1 [VSE1SIZE * 2]; /* Caracteres encodes sur 16 bits */ + unsigned char attribute; /* 0x0f pour les VFAT */ + unsigned char hash1; /* toujours 0 */ + unsigned char sum; /* Checksum du nom court */ + char text2 [VSE2SIZE * 2]; /* Caracteres encodes sur 16 bits */ + unsigned char sector_l; /* 0 pour les VFAT */ + unsigned char sector_u; /* 0 pour les VFAT */ + char text3 [VSE3SIZE * 2]; /* Caracteres encodes sur 16 bits */ +} __attribute__ ((packed)) ; + +struct vfat_state { + char name [VBUFSIZE]; + int status; /* is now a bit map of 32 bits */ + int subentries; + unsigned char sum; /* no need to remember the sum for each */ + /* entry, it is the same anyways */ +} __attribute__ ((packed)) ; + +/* Conversion macros */ +#define DOS_YEAR(dir) (((dir)->date[1] >> 1) + 1980) +#define DOS_MONTH(dir) (((((dir)->date[1]&0x1) << 3) + ((dir)->date[0] >> 5))) +#define DOS_DAY(dir) ((dir)->date[0] & 0x1f) +#define DOS_HOUR(dir) ((dir)->time[1] >> 3) +#define DOS_MINUTE(dir) (((((dir)->time[1]&0x7) << 3) + ((dir)->time[0] >> 5))) +#define DOS_SEC(dir) (((dir)->time[0] & 0x1f) * 2) + + +#endif + diff --git a/fs/fdos/fat.c b/fs/fdos/fat.c new file mode 100644 index 0000000000..42df755af3 --- /dev/null +++ b/fs/fdos/fat.c @@ -0,0 +1,145 @@ +/* + * (C) Copyright 2002 + * Stäubli Faverges - <www.staubli.com> + * Pierre AUBERT p.aubert@staubli.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <config.h> +#include <malloc.h> + +#if (CONFIG_COMMANDS & CFG_CMD_FDOS) + +#include "dos.h" +#include "fdos.h" + + +/*----------------------------------------------------------------------------- + * fat_decode -- + *----------------------------------------------------------------------------- + */ +unsigned int fat_decode (Fs_t *fs, unsigned int num) +{ + unsigned int start = num * 3 / 2; + unsigned char *address = fs -> fat_buf + start; + + if (num < 2 || start + 1 > (fs -> fat_len * SZ_STD_SECTOR)) + return 1; + + if (num & 1) + return ((address [1] & 0xff) << 4) | ((address [0] & 0xf0 ) >> 4); + else + return ((address [1] & 0xf) << 8) | (address [0] & 0xff ); +} +/*----------------------------------------------------------------------------- + * check_fat -- + *----------------------------------------------------------------------------- + */ +static int check_fat (Fs_t *fs) +{ + int i, f; + + /* Cluster verification */ + for (i = 3 ; i < fs -> num_clus; i++){ + f = fat_decode (fs, i); + if (f < FAT12_LAST && f > fs -> num_clus){ + /* Wrong cluster number detected */ + return (-1); + } + } + return (0); +} +/*----------------------------------------------------------------------------- + * read_one_fat -- + *----------------------------------------------------------------------------- + */ +static int read_one_fat (BootSector_t *boot, Fs_t *fs, int nfat) +{ + if (dev_read (fs -> fat_buf, + (fs -> fat_start + nfat * fs -> fat_len), + fs -> fat_len) < 0) { + return (-1); + } + + if (fs -> fat_buf [0] || fs -> fat_buf [1] || fs -> fat_buf [2]) { + if ((fs -> fat_buf [0] != boot -> descr && + (fs -> fat_buf [0] != 0xf9 || boot -> descr != MEDIA_STD)) || + fs -> fat_buf [0] < MEDIA_STD){ + /* Unknown Media */ + return (-1); + } + if (fs -> fat_buf [1] != 0xff || fs -> fat_buf [2] != 0xff){ + /* FAT doesn't start with good values */ + return (-1); + } + } + + if (fs -> num_clus >= FAT12_MAX_NB) { + /* Too much clusters */ + return (-1); + } + + return check_fat (fs); +} +/*----------------------------------------------------------------------------- + * read_fat -- + *----------------------------------------------------------------------------- + */ +int read_fat (BootSector_t *boot, Fs_t *fs) +{ + unsigned int buflen; + int i; + + /* Allocate Fat Buffer */ + buflen = fs -> fat_len * SZ_STD_SECTOR; + if (fs -> fat_buf) { + free (fs -> fat_buf); + } + + if ((fs -> fat_buf = malloc (buflen)) == NULL) { + return (-1); + } + + /* Try to read each Fat */ + for (i = 0; i< fs -> nb_fat; i++){ + if (read_one_fat (boot, fs, i) == 0) { + /* Fat is OK */ + fs -> num_fat = i; + break; + } + } + + if (i == fs -> nb_fat){ + return (-1); + } + + if (fs -> fat_len > (((fs -> num_clus + 2) * + (FAT_BITS / 4) -1 ) / 2 / + SZ_STD_SECTOR + 1)) { + return (-1); + } + return (0); +} + + + + +#endif diff --git a/fs/fdos/fdos.c b/fs/fdos/fdos.c new file mode 100644 index 0000000000..8963f425f5 --- /dev/null +++ b/fs/fdos/fdos.c @@ -0,0 +1,175 @@ +/* + * (C) Copyright 2002 + * Stäubli Faverges - <www.staubli.com> + * Pierre AUBERT p.aubert@staubli.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <config.h> + +#if (CONFIG_COMMANDS & CFG_CMD_FDOS) +#include <malloc.h> +#include "dos.h" +#include "fdos.h" + + +const char *month [] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; + +Fs_t fs; +File_t file; + +/*----------------------------------------------------------------------------- + * dos_open -- + *----------------------------------------------------------------------------- + */ +int dos_open(char *name) +{ + int lg; + int entry; + char *fname; + + /* We need to suppress the " char around the name */ + if (name [0] == '"') { + name ++; + } + lg = strlen (name); + if (name [lg - 1] == '"') { + name [lg - 1] = '\0'; + } + + /* Open file system */ + if (fs_init (&fs) < 0) { + return -1; + } + + /* Init the file descriptor */ + file.name = name; + file.fs = &fs; + + /* find the subdirectory containing the file */ + if (open_subdir (&file) < 0) { + return (-1); + } + + fname = basename (name); + + /* if we try to open root directory */ + if (*fname == '\0') { + file.file = file.subdir; + return (0); + } + + /* find the file in the subdir */ + entry = 0; + if (vfat_lookup (&file.subdir, + file.fs, + &file.file.dir, + &entry, + 0, + fname, + ACCEPT_DIR | ACCEPT_PLAIN | SINGLE | DO_OPEN, + 0, + &file.file) != 0) { + /* File not found */ + printf ("File not found\n"); + return (-1); + } + + return 0; +} + +/*----------------------------------------------------------------------------- + * dos_read -- + *----------------------------------------------------------------------------- + */ +int dos_read (ulong addr) +{ + int read = 0, nb; + + /* Try to boot a directory ? */ + if (file.file.dir.attr & (ATTR_DIRECTORY | ATTR_VOLUME)) { + printf ("Unable to boot %s !!\n", file.name); + return (-1); + } + while (read < file.file.FileSize) { + PRINTF ("read_file (%ld)\n", (file.file.FileSize - read)); + nb = read_file (&fs, + &file.file, + (char *)addr + read, + read, + (file.file.FileSize - read)); + PRINTF ("read_file -> %d\n", nb); + if (nb < 0) { + printf ("read error\n"); + return (-1); + } + read += nb; + } + return (read); +} +/*----------------------------------------------------------------------------- + * dos_dir -- + *----------------------------------------------------------------------------- + */ +int dos_dir (void) +{ + int entry; + Directory_t dir; + char *name; + + + if ((file.file.dir.attr & ATTR_DIRECTORY) == 0) { + printf ("%s: not a directory !!\n", file.name); + return (1); + } + entry = 0; + if ((name = malloc (MAX_VNAMELEN + 1)) == NULL) { + PRINTF ("Allcation error\n"); + return (1); + } + + while (vfat_lookup (&file.file, + file.fs, + &dir, + &entry, + 0, + NULL, + ACCEPT_DIR | ACCEPT_PLAIN | MATCH_ANY, + name, + NULL) == 0) { + /* Display file info */ + printf ("%3.3s %9d %s %02d %04d %02d:%02d:%02d %s\n", + (dir.attr & ATTR_DIRECTORY) ? "dir" : " ", + __le32_to_cpu (dir.size), + month [DOS_MONTH (&dir) - 1], + DOS_DAY (&dir), + DOS_YEAR (&dir), + DOS_HOUR (&dir), + DOS_MINUTE (&dir), + DOS_SEC (&dir), + name); + + } + free (name); + return (0); +} + +#endif diff --git a/fs/fdos/fdos.h b/fs/fdos/fdos.h new file mode 100644 index 0000000000..18076d8665 --- /dev/null +++ b/fs/fdos/fdos.h @@ -0,0 +1,117 @@ +/* + * (C) Copyright 2002 + * Stäubli Faverges - <www.staubli.com> + * Pierre AUBERT p.aubert@staubli.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef _FDOS_H_ +#define _FDOS_H_ + + +#undef FDOS_DEBUG + +#ifdef FDOS_DEBUG +#define PRINTF(fmt,args...) printf (fmt ,##args) +#else +#define PRINTF(fmt,args...) +#endif + +/* Data structure describing media */ +typedef struct fs +{ + unsigned long tot_sectors; + + int cluster_size; + int num_clus; + + int fat_start; + int fat_len; + int nb_fat; + int num_fat; + + int dir_start; + int dir_len; + + unsigned char *fat_buf; + +} Fs_t; + +/* Data structure describing one file system slot */ +typedef struct slot { + int (*map) (struct fs *fs, + struct slot *file, + int where, + int *len); + unsigned long FileSize; + + unsigned short int FirstAbsCluNr; + unsigned short int PreviousAbsCluNr; + unsigned short int PreviousRelCluNr; + + Directory_t dir; +} Slot_t; + +typedef struct file { + char *name; + int Case; + Fs_t *fs; + Slot_t subdir; + Slot_t file; +} File_t; + + +/* dev.c */ +int dev_read (void *buffer, int where, int len); +int dev_open (void); +int check_dev (BootSector_t *boot, Fs_t *fs); + +/* fat.c */ +unsigned int fat_decode (Fs_t *fs, unsigned int num); +int read_fat (BootSector_t *boot, Fs_t *fs); + +/* vfat.c */ +int vfat_lookup (Slot_t *dir, + Fs_t *fs, + Directory_t *dirent, + int *entry, + int *vfat_start, + char *filename, + int flags, + char *outname, + Slot_t *file); + +/* subdir.c */ +char *basename (char *name); +int open_subdir (File_t *desc); +int open_file (Slot_t *file, Directory_t *dir); +int read_file (Fs_t *fs, + Slot_t *file, + char *buf, + int where, + int len); +void init_subdir (void); + +/* fs.c */ +int fs_init (Fs_t *fs); + + +#endif + diff --git a/fs/fdos/fs.c b/fs/fdos/fs.c new file mode 100644 index 0000000000..68bbde0e27 --- /dev/null +++ b/fs/fdos/fs.c @@ -0,0 +1,120 @@ +/* + * (C) Copyright 2002 + * Stäubli Faverges - <www.staubli.com> + * Pierre AUBERT p.aubert@staubli.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <config.h> +#include <malloc.h> + +#if (CONFIG_COMMANDS & CFG_CMD_FDOS) + +#include "dos.h" +#include "fdos.h" + + +/*----------------------------------------------------------------------------- + * fill_fs -- Read info on file system + *----------------------------------------------------------------------------- + */ +static int fill_fs (BootSector_t *boot, Fs_t *fs) +{ + + fs -> fat_start = __le16_to_cpu (boot -> nrsvsect); + fs -> fat_len = __le16_to_cpu (boot -> fatlen); + fs -> nb_fat = boot -> nfat; + + fs -> dir_start = fs -> fat_start + fs -> nb_fat * fs -> fat_len; + fs -> dir_len = __le16_to_cpu (boot -> dirents) * MDIR_SIZE / SZ_STD_SECTOR; + fs -> cluster_size = boot -> clsiz; + fs -> num_clus = (fs -> tot_sectors - fs -> dir_start - fs -> dir_len) / fs -> cluster_size; + + return (0); +} + +/*----------------------------------------------------------------------------- + * fs_init -- + *----------------------------------------------------------------------------- + */ +int fs_init (Fs_t *fs) +{ + BootSector_t *boot; + + /* Initialize physical device */ + if (dev_open () < 0) { + PRINTF ("Unable to initialize the fdc\n"); + return (-1); + } + init_subdir (); + + /* Allocate space for read the boot sector */ + if ((boot = (BootSector_t *)malloc (sizeof (BootSector_t))) == NULL) { + PRINTF ("Unable to allocate space for boot sector\n"); + return (-1); + } + + /* read boot sector */ + if (dev_read (boot, 0, 1)){ + PRINTF ("Error during boot sector read\n"); + free (boot); + return (-1); + } + + /* we verify it'a a DOS diskette */ + if (boot -> jump [0] != JUMP_0_1 && boot -> jump [0] != JUMP_0_2) { + PRINTF ("Not a DOS diskette\n"); + free (boot); + return (-1); + } + + if (boot -> descr < MEDIA_STD) { + /* We handle only recent medias (type F0) */ + PRINTF ("unrecognized diskette type\n"); + free (boot); + return (-1); + } + + if (check_dev (boot, fs) < 0) { + PRINTF ("Bad diskette\n"); + free (boot); + return (-1); + } + + if (fill_fs (boot, fs) < 0) { + free (boot); + + return (-1); + } + + /* Read FAT */ + if (read_fat (boot, fs) < 0) { + free (boot); + return (-1); + } + + free (boot); + return (0); +} + + + +#endif diff --git a/fs/fdos/subdir.c b/fs/fdos/subdir.c new file mode 100644 index 0000000000..5911f2e88f --- /dev/null +++ b/fs/fdos/subdir.c @@ -0,0 +1,348 @@ +/* + * (C) Copyright 2002 + * Stäubli Faverges - <www.staubli.com> + * Pierre AUBERT p.aubert@staubli.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <config.h> +#include <malloc.h> + +#if (CONFIG_COMMANDS & CFG_CMD_FDOS) + +#include "dos.h" +#include "fdos.h" + +static int cache_sect; +static unsigned char cache [SZ_STD_SECTOR]; + + +#define min(x,y) ((x)<(y)?(x):(y)) + +static int descend (Slot_t *parent, + Fs_t *fs, + char *path); + +/*----------------------------------------------------------------------------- + * init_subdir -- + *----------------------------------------------------------------------------- + */ +void init_subdir (void) +{ + cache_sect = -1; +} +/*----------------------------------------------------------------------------- + * basename -- + *----------------------------------------------------------------------------- + */ +char *basename (char *name) +{ + register char *cptr; + + if (!name || !*name) { + return (""); + } + + for (cptr= name; *cptr++; ); + while (--cptr >= name) { + if (*cptr == '/') { + return (cptr + 1); + } + } + return(name); +} +/*----------------------------------------------------------------------------- + * root_map -- + *----------------------------------------------------------------------------- + */ +static int root_map (Fs_t *fs, Slot_t *file, int where, int *len) +{ + *len = min (*len, fs -> dir_len * SZ_STD_SECTOR - where); + if (*len < 0 ) { + *len = 0; + return (-1); + } + return fs -> dir_start * SZ_STD_SECTOR + where; +} +/*----------------------------------------------------------------------------- + * normal_map -- + *----------------------------------------------------------------------------- + */ +static int normal_map (Fs_t *fs, Slot_t *file, int where, int *len) +{ + int offset; + int NrClu; + unsigned short RelCluNr; + unsigned short CurCluNr; + unsigned short NewCluNr; + unsigned short AbsCluNr; + int clus_size; + + clus_size = fs -> cluster_size * SZ_STD_SECTOR; + offset = where % clus_size; + + *len = min (*len, file -> FileSize - where); + + if (*len < 0 ) { + *len = 0; + return (0); + } + + if (file -> FirstAbsCluNr < 2){ + *len = 0; + return (0); + } + + RelCluNr = where / clus_size; + + if (RelCluNr >= file -> PreviousRelCluNr){ + CurCluNr = file -> PreviousRelCluNr; + AbsCluNr = file -> PreviousAbsCluNr; + } else { + CurCluNr = 0; + AbsCluNr = file -> FirstAbsCluNr; + } + + + NrClu = (offset + *len - 1) / clus_size; + while (CurCluNr <= RelCluNr + NrClu) { + if (CurCluNr == RelCluNr){ + /* we have reached the beginning of our zone. Save + * coordinates */ + file -> PreviousRelCluNr = RelCluNr; + file -> PreviousAbsCluNr = AbsCluNr; + } + NewCluNr = fat_decode (fs, AbsCluNr); + if (NewCluNr == 1 || NewCluNr == 0) { + PRINTF("Fat problem while decoding %d %x\n", + AbsCluNr, NewCluNr); + return (-1); + } + if (CurCluNr == RelCluNr + NrClu) { + break; + } + + if (CurCluNr < RelCluNr && NewCluNr == FAT12_END) { + *len = 0; + return 0; + } + + if (CurCluNr >= RelCluNr && NewCluNr != AbsCluNr + 1) + break; + CurCluNr++; + AbsCluNr = NewCluNr; + } + + *len = min (*len, (1 + CurCluNr - RelCluNr) * clus_size - offset); + + return (((file -> PreviousAbsCluNr - 2) * fs -> cluster_size + + fs -> dir_start + fs -> dir_len) * + SZ_STD_SECTOR + offset); +} +/*----------------------------------------------------------------------------- + * open_subdir -- open the subdir containing the file + *----------------------------------------------------------------------------- + */ +int open_subdir (File_t *desc) +{ + char *pathname; + char *tmp, *s, *path; + char terminator; + + if ((pathname = (char *)malloc (MAX_PATH)) == NULL) { + return (-1); + } + + strcpy (pathname, desc -> name); + + /* Suppress file name */ + tmp = basename (pathname); + *tmp = '\0'; + + /* root directory init */ + desc -> subdir.FirstAbsCluNr = 0; + desc -> subdir.FileSize = -1; + desc -> subdir.map = root_map; + desc -> subdir.dir.attr = ATTR_DIRECTORY; + + tmp = pathname; + for (s = tmp; ; ++s) { + if (*s == '/' || *s == '\0') { + path = tmp; + terminator = *s; + *s = '\0'; + if (s != tmp && strcmp (path,".")) { + if (descend (&desc -> subdir, desc -> fs, path) < 0) { + free (pathname); + return (-1); + } + } + if (terminator == 0) { + break; + } + tmp = s + 1; + } + } + free (pathname); + return (0); +} +/*----------------------------------------------------------------------------- + * descend -- + *----------------------------------------------------------------------------- + */ +static int descend (Slot_t *parent, + Fs_t *fs, + char *path) +{ + int entry; + Slot_t SubDir; + + if(path[0] == '\0' || strcmp (path, ".") == 0) { + return (0); + } + + + entry = 0; + if (vfat_lookup (parent, + fs, + &(SubDir.dir), + &entry, + 0, + path, + ACCEPT_DIR | SINGLE | DO_OPEN, + 0, + &SubDir) == 0) { + *parent = SubDir; + return (0); + } + + if (strcmp(path, "..") == 0) { + parent -> FileSize = -1; + parent -> FirstAbsCluNr = 0; + parent -> map = root_map; + return (0); + } + return (-1); +} +/*----------------------------------------------------------------------------- + * open_file -- + *----------------------------------------------------------------------------- + */ +int open_file (Slot_t *file, Directory_t *dir) +{ + int first; + unsigned long size; + + first = __le16_to_cpu (dir -> start); + + if(first == 0 && + (dir -> attr & ATTR_DIRECTORY) != 0) { + file -> FirstAbsCluNr = 0; + file -> FileSize = -1; + file -> map = root_map; + return (0); + } + + if ((dir -> attr & ATTR_DIRECTORY) != 0) { + size = (1UL << 31) - 1; + } + else { + size = __le32_to_cpu (dir -> size); + } + + file -> map = normal_map; + file -> FirstAbsCluNr = first; + file -> PreviousRelCluNr = 0xffff; + file -> FileSize = size; + return (0); +} +/*----------------------------------------------------------------------------- + * read_file -- + *----------------------------------------------------------------------------- + */ +int read_file (Fs_t *fs, + Slot_t *file, + char *buf, + int where, + int len) +{ + int pos; + int read, nb, sect, offset; + + pos = file -> map (fs, file, where, &len); + if (pos < 0) { + return -1; + } + if (len == 0) { + return (0); + } + + /* Compute sector number */ + sect = pos / SZ_STD_SECTOR; + offset = pos % SZ_STD_SECTOR; + read = 0; + + if (offset) { + /* Read doesn't start at the sector beginning. We need to use our */ + /* cache */ + if (sect != cache_sect) { + if (dev_read (cache, sect, 1) < 0) { + return (-1); + } + cache_sect = sect; + } + nb = min (len, SZ_STD_SECTOR - offset); + + memcpy (buf, cache + offset, nb); + read += nb; + len -= nb; + sect += 1; + } + + if (len > SZ_STD_SECTOR) { + nb = (len - 1) / SZ_STD_SECTOR; + if (dev_read (buf + read, sect, nb) < 0) { + return ((read) ? read : -1); + } + /* update sector position */ + sect += nb; + + /* Update byte position */ + nb *= SZ_STD_SECTOR; + read += nb; + len -= nb; + } + + if (len) { + if (sect != cache_sect) { + if (dev_read (cache, sect, 1) < 0) { + return ((read) ? read : -1); + cache_sect = -1; + } + cache_sect = sect; + } + + memcpy (buf + read, cache, len); + read += len; + } + return (read); +} +#endif diff --git a/fs/fdos/vfat.c b/fs/fdos/vfat.c new file mode 100644 index 0000000000..f8287952e1 --- /dev/null +++ b/fs/fdos/vfat.c @@ -0,0 +1,357 @@ +/* + * (C) Copyright 2002 + * Stäubli Faverges - <www.staubli.com> + * Pierre AUBERT p.aubert@staubli.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <config.h> + +#if (CONFIG_COMMANDS & CFG_CMD_FDOS) +#include <linux/ctype.h> + +#include "dos.h" +#include "fdos.h" + +static int dir_read (Fs_t *fs, + Slot_t *dir, + Directory_t *dirent, + int num, + struct vfat_state *v); + +static int unicode_read (char *in, char *out, int num); +static int match (const char *s, const char *p); +static unsigned char sum_shortname (char *name); +static int check_vfat (struct vfat_state *v, Directory_t *dir); +static char *conv_name (char *name, char *ext, char Case, char *ans); + + +/*----------------------------------------------------------------------------- + * clear_vfat -- + *----------------------------------------------------------------------------- + */ +static void clear_vfat (struct vfat_state *v) +{ + v -> subentries = 0; + v -> status = 0; +} + +/*----------------------------------------------------------------------------- + * vfat_lookup -- + *----------------------------------------------------------------------------- + */ +int vfat_lookup (Slot_t *dir, + Fs_t *fs, + Directory_t *dirent, + int *entry, + int *vfat_start, + char *filename, + int flags, + char *outname, + Slot_t *file) +{ + int found; + struct vfat_state vfat; + char newfile [VSE_NAMELEN]; + int vfat_present = 0; + + if (*entry == -1) { + return -1; + } + + found = 0; + clear_vfat (&vfat); + while (1) { + if (dir_read (fs, dir, dirent, *entry, &vfat) < 0) { + if (vfat_start) { + *vfat_start = *entry; + } + break; + } + (*entry)++; + + /* Empty slot */ + if (dirent -> name[0] == '\0'){ + if (vfat_start == 0) { + break; + } + continue; + } + + if (dirent -> attr == ATTR_VSE) { + /* VSE entry, continue */ + continue; + } + if ( (dirent -> name [0] == DELMARK) || + ((dirent -> attr & ATTR_DIRECTORY) != 0 && + (flags & ACCEPT_DIR) == 0) || + ((dirent -> attr & ATTR_VOLUME) != 0 && + (flags & ACCEPT_LABEL) == 0) || + (((dirent -> attr & (ATTR_DIRECTORY | ATTR_VOLUME)) == 0) && + (flags & ACCEPT_PLAIN) == 0)) { + clear_vfat (&vfat); + continue; + } + + vfat_present = check_vfat (&vfat, dirent); + if (vfat_start) { + *vfat_start = *entry - 1; + if (vfat_present) { + *vfat_start -= vfat.subentries; + } + } + + if (dirent -> attr & ATTR_VOLUME) { + strncpy (newfile, dirent -> name, 8); + newfile [8] = '\0'; + strncat (newfile, dirent -> ext, 3); + newfile [11] = '\0'; + } + else { + conv_name (dirent -> name, dirent -> ext, dirent -> Case, newfile); + } + + if (flags & MATCH_ANY) { + found = 1; + break; + } + + if ((vfat_present && match (vfat.name, filename)) || + (match (newfile, filename))) { + found = 1; + break; + } + clear_vfat (&vfat); + } + + if (found) { + if ((flags & DO_OPEN) && file) { + if (open_file (file, dirent) < 0) { + return (-1); + } + } + if (outname) { + if (vfat_present) { + strcpy (outname, vfat.name); + } + else { + strcpy (outname, newfile); + } + } + return (0); /* File found */ + } else { + *entry = -1; + return -1; /* File not found */ + } +} + +/*----------------------------------------------------------------------------- + * dir_read -- Read one directory entry + *----------------------------------------------------------------------------- + */ +static int dir_read (Fs_t *fs, + Slot_t *dir, + Directory_t *dirent, + int num, + struct vfat_state *v) +{ + + /* read the directory entry */ + if (read_file (fs, + dir, + (char *)dirent, + num * MDIR_SIZE, + MDIR_SIZE) != MDIR_SIZE) { + return (-1); + } + + if (v && (dirent -> attr == ATTR_VSE)) { + struct vfat_subentry *vse; + unsigned char id, last_flag; + char *c; + + vse = (struct vfat_subentry *) dirent; + id = vse -> id & VSE_MASK; + last_flag = (vse -> id & VSE_LAST); + if (id > MAX_VFAT_SUBENTRIES) { + /* Invalid VSE entry */ + return (-1); + } + + + /* Decode VSE */ + if(v -> sum != vse -> sum) { + clear_vfat (v); + v -> sum = vse -> sum; + } + + + v -> status |= 1 << (id - 1); + if (last_flag) { + v -> subentries = id; + } + + c = &(v -> name [VSE_NAMELEN * (id - 1)]); + c += unicode_read (vse->text1, c, VSE1SIZE); + c += unicode_read (vse->text2, c, VSE2SIZE); + c += unicode_read (vse->text3, c, VSE3SIZE); + + if (last_flag) { + *c = '\0'; /* Null terminate long name */ + } + + } + return (0); +} + +/*----------------------------------------------------------------------------- + * unicode_read -- + *----------------------------------------------------------------------------- + */ +static int unicode_read (char *in, char *out, int num) +{ + int j; + + for (j = 0; j < num; ++j) { + if (in [1]) + *out = '_'; + else + *out = in [0]; + out ++; + in += 2; + } + return num; +} + +/*----------------------------------------------------------------------------- + * match -- + *----------------------------------------------------------------------------- + */ +static int match (const char *s, const char *p) +{ + + for (; *p != '\0'; ) { + if (toupper (*s) != toupper (*p)) { + return (0); + } + p++; + s++; + } + + if (*s != '\0') { + return (0); + } + else { + return (1); + } +} +/*----------------------------------------------------------------------------- + * sum_shortname -- + *----------------------------------------------------------------------------- + */ +static unsigned char sum_shortname (char *name) +{ + unsigned char sum; + int j; + + for (j = sum = 0; j < 11; ++j) { + sum = ((sum & 1) ? 0x80 : 0) + (sum >> 1) + + (name [j] ? name [j] : ' '); + } + return (sum); +} +/*----------------------------------------------------------------------------- + * check_vfat -- + * Return 1 if long name is valid, 0 else + *----------------------------------------------------------------------------- + */ +static int check_vfat (struct vfat_state *v, Directory_t *dir) +{ + char name[12]; + + if (v -> subentries == 0) { + return 0; + } + + strncpy (name, dir -> name, 8); + strncpy (name + 8, dir -> ext, 3); + name [11] = '\0'; + + if (v -> sum != sum_shortname (name)) { + return 0; + } + + if( (v -> status & ((1 << v -> subentries) - 1)) != + (1 << v -> subentries) - 1) { + return 0; + } + v->name [VSE_NAMELEN * v -> subentries] = 0; + + return 1; +} +/*----------------------------------------------------------------------------- + * conv_name -- + *----------------------------------------------------------------------------- + */ +static char *conv_name (char *name, char *ext, char Case, char *ans) +{ + char tname [9], text [4]; + int i; + + i = 0; + while (i < 8 && name [i] != ' ' && name [i] != '\0') { + tname [i] = name [i]; + i++; + } + tname [i] = '\0'; + + if (Case & BASECASE) { + for (i = 0; i < 8 && tname [i]; i++) { + tname [i] = tolower (tname [i]); + } + } + + i = 0; + while (i < 3 && ext [i] != ' ' && ext [i] != '\0') { + text [i] = ext [i]; + i++; + } + text [i] = '\0'; + + if (Case & EXTCASE){ + for (i = 0; i < 3 && text [i]; i++) { + text [i] = tolower (text [i]); + } + } + + if (*text) { + strcpy (ans, tname); + strcat (ans, "."); + strcat (ans, text); + } + else { + strcpy(ans, tname); + } + return (ans); +} + + +#endif diff --git a/i386_config.mk b/i386_config.mk new file mode 100644 index 0000000000..9e6d37d0ed --- /dev/null +++ b/i386_config.mk @@ -0,0 +1,24 @@ +# +# (C) Copyright 2000-2002 +# 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 +# + +PLATFORM_CPPFLAGS += -DCONFIG_I386 -D__I386__ diff --git a/include/asm-i386/bitops.h b/include/asm-i386/bitops.h new file mode 100644 index 0000000000..a3063cacc9 --- /dev/null +++ b/include/asm-i386/bitops.h @@ -0,0 +1,384 @@ +#ifndef _I386_BITOPS_H +#define _I386_BITOPS_H + +/* + * Copyright 1992, Linus Torvalds. + */ + +#include <linux/config.h> + +/* + * These have to be done with inline assembly: that way the bit-setting + * is guaranteed to be atomic. All bit operations return 0 if the bit + * was cleared before the operation and != 0 if it was not. + * + * bit 0 is the LSB of addr; bit 32 is the LSB of (addr+1). + */ + +#ifdef CONFIG_SMP +#define LOCK_PREFIX "lock ; " +#else +#define LOCK_PREFIX "" +#endif + +#define ADDR (*(volatile long *) addr) + +/** + * set_bit - Atomically set a bit in memory + * @nr: the bit to set + * @addr: the address to start counting from + * + * This function is atomic and may not be reordered. See __set_bit() + * if you do not require the atomic guarantees. + * Note that @nr may be almost arbitrarily large; this function is not + * restricted to acting on a single-word quantity. + */ +static __inline__ void set_bit(int nr, volatile void * addr) +{ + __asm__ __volatile__( LOCK_PREFIX + "btsl %1,%0" + :"=m" (ADDR) + :"Ir" (nr)); +} + +/** + * __set_bit - Set a bit in memory + * @nr: the bit to set + * @addr: the address to start counting from + * + * Unlike set_bit(), this function is non-atomic and may be reordered. + * If it's called on the same region of memory simultaneously, the effect + * may be that only one operation succeeds. + */ +static __inline__ void __set_bit(int nr, volatile void * addr) +{ + __asm__( + "btsl %1,%0" + :"=m" (ADDR) + :"Ir" (nr)); +} + +/** + * clear_bit - Clears a bit in memory + * @nr: Bit to clear + * @addr: Address to start counting from + * + * clear_bit() is atomic and may not be reordered. However, it does + * not contain a memory barrier, so if it is used for locking purposes, + * you should call smp_mb__before_clear_bit() and/or smp_mb__after_clear_bit() + * in order to ensure changes are visible on other processors. + */ +static __inline__ void clear_bit(int nr, volatile void * addr) +{ + __asm__ __volatile__( LOCK_PREFIX + "btrl %1,%0" + :"=m" (ADDR) + :"Ir" (nr)); +} +#define smp_mb__before_clear_bit() barrier() +#define smp_mb__after_clear_bit() barrier() + +/** + * __change_bit - Toggle a bit in memory + * @nr: the bit to set + * @addr: the address to start counting from + * + * Unlike change_bit(), this function is non-atomic and may be reordered. + * If it's called on the same region of memory simultaneously, the effect + * may be that only one operation succeeds. + */ +static __inline__ void __change_bit(int nr, volatile void * addr) +{ + __asm__ __volatile__( + "btcl %1,%0" + :"=m" (ADDR) + :"Ir" (nr)); +} + +/** + * change_bit - Toggle a bit in memory + * @nr: Bit to clear + * @addr: Address to start counting from + * + * change_bit() is atomic and may not be reordered. + * Note that @nr may be almost arbitrarily large; this function is not + * restricted to acting on a single-word quantity. + */ +static __inline__ void change_bit(int nr, volatile void * addr) +{ + __asm__ __volatile__( LOCK_PREFIX + "btcl %1,%0" + :"=m" (ADDR) + :"Ir" (nr)); +} + +/** + * test_and_set_bit - Set a bit and return its old value + * @nr: Bit to set + * @addr: Address to count from + * + * This operation is atomic and cannot be reordered. + * It also implies a memory barrier. + */ +static __inline__ int test_and_set_bit(int nr, volatile void * addr) +{ + int oldbit; + + __asm__ __volatile__( LOCK_PREFIX + "btsl %2,%1\n\tsbbl %0,%0" + :"=r" (oldbit),"=m" (ADDR) + :"Ir" (nr) : "memory"); + return oldbit; +} + +/** + * __test_and_set_bit - Set a bit and return its old value + * @nr: Bit to set + * @addr: Address to count from + * + * This operation is non-atomic and can be reordered. + * If two examples of this operation race, one can appear to succeed + * but actually fail. You must protect multiple accesses with a lock. + */ +static __inline__ int __test_and_set_bit(int nr, volatile void * addr) +{ + int oldbit; + + __asm__( + "btsl %2,%1\n\tsbbl %0,%0" + :"=r" (oldbit),"=m" (ADDR) + :"Ir" (nr)); + return oldbit; +} + +/** + * test_and_clear_bit - Clear a bit and return its old value + * @nr: Bit to set + * @addr: Address to count from + * + * This operation is atomic and cannot be reordered. + * It also implies a memory barrier. + */ +static __inline__ int test_and_clear_bit(int nr, volatile void * addr) +{ + int oldbit; + + __asm__ __volatile__( LOCK_PREFIX + "btrl %2,%1\n\tsbbl %0,%0" + :"=r" (oldbit),"=m" (ADDR) + :"Ir" (nr) : "memory"); + return oldbit; +} + +/** + * __test_and_clear_bit - Clear a bit and return its old value + * @nr: Bit to set + * @addr: Address to count from + * + * This operation is non-atomic and can be reordered. + * If two examples of this operation race, one can appear to succeed + * but actually fail. You must protect multiple accesses with a lock. + */ +static __inline__ int __test_and_clear_bit(int nr, volatile void * addr) +{ + int oldbit; + + __asm__( + "btrl %2,%1\n\tsbbl %0,%0" + :"=r" (oldbit),"=m" (ADDR) + :"Ir" (nr)); + return oldbit; +} + +/* WARNING: non atomic and it can be reordered! */ +static __inline__ int __test_and_change_bit(int nr, volatile void * addr) +{ + int oldbit; + + __asm__ __volatile__( + "btcl %2,%1\n\tsbbl %0,%0" + :"=r" (oldbit),"=m" (ADDR) + :"Ir" (nr) : "memory"); + return oldbit; +} + +/** + * test_and_change_bit - Change a bit and return its new value + * @nr: Bit to set + * @addr: Address to count from + * + * This operation is atomic and cannot be reordered. + * It also implies a memory barrier. + */ +static __inline__ int test_and_change_bit(int nr, volatile void * addr) +{ + int oldbit; + + __asm__ __volatile__( LOCK_PREFIX + "btcl %2,%1\n\tsbbl %0,%0" + :"=r" (oldbit),"=m" (ADDR) + :"Ir" (nr) : "memory"); + return oldbit; +} + +#if 0 /* Fool kernel-doc since it doesn't do macros yet */ +/** + * test_bit - Determine whether a bit is set + * @nr: bit number to test + * @addr: Address to start counting from + */ +static int test_bit(int nr, const volatile void * addr); +#endif + +static __inline__ int constant_test_bit(int nr, const volatile void * addr) +{ + return ((1UL << (nr & 31)) & (((const volatile unsigned int *) addr)[nr >> 5])) != 0; +} + +static __inline__ int variable_test_bit(int nr, volatile void * addr) +{ + int oldbit; + + __asm__ __volatile__( + "btl %2,%1\n\tsbbl %0,%0" + :"=r" (oldbit) + :"m" (ADDR),"Ir" (nr)); + return oldbit; +} + +#define test_bit(nr,addr) \ +(__builtin_constant_p(nr) ? \ + constant_test_bit((nr),(addr)) : \ + variable_test_bit((nr),(addr))) + +/** + * find_first_zero_bit - find the first zero bit in a memory region + * @addr: The address to start the search at + * @size: The maximum size to search + * + * Returns the bit-number of the first zero bit, not the number of the byte + * containing a bit. + */ +static __inline__ int find_first_zero_bit(void * addr, unsigned size) +{ + int d0, d1, d2; + int res; + + if (!size) + return 0; + /* This looks at memory. Mark it volatile to tell gcc not to move it around */ + __asm__ __volatile__( + "movl $-1,%%eax\n\t" + "xorl %%edx,%%edx\n\t" + "repe; scasl\n\t" + "je 1f\n\t" + "xorl -4(%%edi),%%eax\n\t" + "subl $4,%%edi\n\t" + "bsfl %%eax,%%edx\n" + "1:\tsubl %%ebx,%%edi\n\t" + "shll $3,%%edi\n\t" + "addl %%edi,%%edx" + :"=d" (res), "=&c" (d0), "=&D" (d1), "=&a" (d2) + :"1" ((size + 31) >> 5), "2" (addr), "b" (addr)); + return res; +} + +/** + * find_next_zero_bit - find the first zero bit in a memory region + * @addr: The address to base the search on + * @offset: The bitnumber to start searching at + * @size: The maximum size to search + */ +static __inline__ int find_next_zero_bit (void * addr, int size, int offset) +{ + unsigned long * p = ((unsigned long *) addr) + (offset >> 5); + int set = 0, bit = offset & 31, res; + + if (bit) { + /* + * Look for zero in first byte + */ + __asm__("bsfl %1,%0\n\t" + "jne 1f\n\t" + "movl $32, %0\n" + "1:" + : "=r" (set) + : "r" (~(*p >> bit))); + if (set < (32 - bit)) + return set + offset; + set = 32 - bit; + p++; + } + /* + * No zero yet, search remaining full bytes for a zero + */ + res = find_first_zero_bit (p, size - 32 * (p - (unsigned long *) addr)); + return (offset + set + res); +} + +/** + * ffz - find first zero in word. + * @word: The word to search + * + * Undefined if no zero exists, so code should check against ~0UL first. + */ +static __inline__ unsigned long ffz(unsigned long word) +{ + __asm__("bsfl %1,%0" + :"=r" (word) + :"r" (~word)); + return word; +} + +#ifdef __KERNEL__ + +/** + * ffs - find first bit set + * @x: the word to search + * + * This is defined the same way as + * the libc and compiler builtin ffs routines, therefore + * differs in spirit from the above ffz (man ffs). + */ +static __inline__ int ffs(int x) +{ + int r; + + __asm__("bsfl %1,%0\n\t" + "jnz 1f\n\t" + "movl $-1,%0\n" + "1:" : "=r" (r) : "g" (x)); + return r+1; +} + +/** + * hweightN - returns the hamming weight of a N-bit word + * @x: the word to weigh + * + * The Hamming Weight of a number is the total number of bits set in it. + */ + +#define hweight32(x) generic_hweight32(x) +#define hweight16(x) generic_hweight16(x) +#define hweight8(x) generic_hweight8(x) + +#endif /* __KERNEL__ */ + +#ifdef __KERNEL__ + +#define ext2_set_bit __test_and_set_bit +#define ext2_clear_bit __test_and_clear_bit +#define ext2_test_bit test_bit +#define ext2_find_first_zero_bit find_first_zero_bit +#define ext2_find_next_zero_bit find_next_zero_bit + +/* Bitmap functions for the minix filesystem. */ +#define minix_test_and_set_bit(nr,addr) __test_and_set_bit(nr,addr) +#define minix_set_bit(nr,addr) __set_bit(nr,addr) +#define minix_test_and_clear_bit(nr,addr) __test_and_clear_bit(nr,addr) +#define minix_test_bit(nr,addr) test_bit(nr,addr) +#define minix_find_first_zero_bit(addr,size) find_first_zero_bit(addr,size) + +#endif /* __KERNEL__ */ + +#endif /* _I386_BITOPS_H */ diff --git a/include/asm-i386/byteorder.h b/include/asm-i386/byteorder.h new file mode 100644 index 0000000000..bbfb629fae --- /dev/null +++ b/include/asm-i386/byteorder.h @@ -0,0 +1,47 @@ +#ifndef _I386_BYTEORDER_H +#define _I386_BYTEORDER_H + +#include <asm/types.h> + +#ifdef __GNUC__ + +/* For avoiding bswap on i386 */ +#ifdef __KERNEL__ +#include <linux/config.h> +#endif + +static __inline__ __const__ __u32 ___arch__swab32(__u32 x) +{ +#ifdef CONFIG_X86_BSWAP + __asm__("bswap %0" : "=r" (x) : "0" (x)); +#else + __asm__("xchgb %b0,%h0\n\t" /* swap lower bytes */ + "rorl $16,%0\n\t" /* swap words */ + "xchgb %b0,%h0" /* swap higher bytes */ + :"=q" (x) + : "0" (x)); +#endif + return x; +} + +static __inline__ __const__ __u16 ___arch__swab16(__u16 x) +{ + __asm__("xchgb %b0,%h0" /* swap bytes */ \ + : "=q" (x) \ + : "0" (x)); \ + return x; +} + +#define __arch__swab32(x) ___arch__swab32(x) +#define __arch__swab16(x) ___arch__swab16(x) + +#if !defined(__STRICT_ANSI__) || defined(__KERNEL__) +# define __BYTEORDER_HAS_U64__ +# define __SWAB_64_THRU_32__ +#endif + +#endif /* __GNUC__ */ + +#include <linux/byteorder/little_endian.h> + +#endif /* _I386_BYTEORDER_H */ diff --git a/include/asm-i386/global_data.h b/include/asm-i386/global_data.h new file mode 100644 index 0000000000..324b4357f8 --- /dev/null +++ b/include/asm-i386/global_data.h @@ -0,0 +1,60 @@ +/* + * (C) Copyright 2002 + * 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 + */ + +#ifndef __ASM_GBL_DATA_H +#define __ASM_GBL_DATA_H +/* + * The following data structure is placed in some memory wich is + * available very early after boot (like DPRAM on MPC8xx/MPC82xx, or + * some locked parts of the data cache) to allow for a minimum set of + * global variables during system initialization (until we have set + * up the memory controller so that we can use RAM). + * + * Keep it *SMALL* and remember to set CFG_GBL_DATA_SIZE > sizeof(gd_t) + */ + +typedef struct { + bd_t *bd; + unsigned long flags; + unsigned long baudrate; + unsigned long have_console; /* serial_init() was called */ + unsigned long reloc_off; /* Relocation Offset */ + unsigned long env_addr; /* Address of Environment struct */ + unsigned long env_valid; /* Checksum of Environment valid? */ + unsigned long cpu_clk; /* CPU clock in Hz! */ + unsigned long bus_clk; + unsigned long ram_size; /* RAM size */ + unsigned long reset_status; /* reset status register at boot */ +} gd_t; + +/* + * Global Data Flags + */ +#define GD_FLG_RELOC 0x00001 /* Code was relocated to RAM */ +#define GD_FLG_DEVINIT 0x00002 /* Devices have been initialized */ + +extern gd_t *global_data; + +#define DECLARE_GLOBAL_DATA_PTR gd_t *gd = global_data + +#endif /* __ASM_GBL_DATA_H */ diff --git a/include/asm-i386/i8254.h b/include/asm-i386/i8254.h new file mode 100644 index 0000000000..e13f04e589 --- /dev/null +++ b/include/asm-i386/i8254.h @@ -0,0 +1,56 @@ +/* + * (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 + */ + + +/* i8254.h Intel 8254 PIT registers */ + + +#ifndef _ASMI386_I8254_H_ +#define _ASMI386_I8954_H_ 1 + + + +#define PIT_T0 0x00 /* PIT channel 0 count/status */ +#define PIT_T1 0x01 /* PIT channel 1 count/status */ +#define PIT_T2 0x02 /* PIT channel 2 count/status */ +#define PIT_COMMAND 0x03 /* PIT mode control, latch and read back */ + +/* PIT Command Register Bit Definitions */ + +#define PIT_CMD_CTR0 0x00 /* Select PIT counter 0 */ +#define PIT_CMD_CTR1 0x40 /* Select PIT counter 1 */ +#define PIT_CMD_CTR2 0x80 /* Select PIT counter 2 */ + +#define PIT_CMD_LATCH 0x00 /* Counter Latch Command */ +#define PIT_CMD_LOW 0x10 /* Access counter bits 7-0 */ +#define PIT_CMD_HIGH 0x20 /* Access counter bits 15-8 */ +#define PIT_CMD_BOTH 0x30 /* Access counter bits 15-0 in two accesses */ + +#define PIT_CMD_MODE0 0x00 /* Select mode 0 */ +#define PIT_CMD_MODE1 0x02 /* Select mode 1 */ +#define PIT_CMD_MODE2 0x04 /* Select mode 2 */ +#define PIT_CMD_MODE3 0x06 /* Select mode 3 */ +#define PIT_CMD_MODE4 0x08 /* Select mode 4 */ +#define PIT_CMD_MODE5 0x0A /* Select mode 5 */ + +#endif diff --git a/include/asm-i386/i8259.h b/include/asm-i386/i8259.h new file mode 100644 index 0000000000..0419e0e266 --- /dev/null +++ b/include/asm-i386/i8259.h @@ -0,0 +1,88 @@ +/* + * (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 + */ + +/* i8259.h i8259 PIC Registers */ + +#ifndef _ASMI386_I8259_H_ +#define _ASMI386_I8959_H_ 1 + + +/* PIC I/O mapped registers */ + +#define IRR 0x0 /* Interrupt Request Register */ +#define ISR 0x0 /* In-Service Register */ +#define ICW1 0x0 /* Initialization Control Word 1 */ +#define OCW2 0x0 /* Operation Control Word 2 */ +#define OCW3 0x0 /* Operation Control Word 3 */ +#define ICW2 0x1 /* Initialization Control Word 2 */ +#define ICW3 0x1 /* Initialization Control Word 3 */ +#define ICW4 0x1 /* Initialization Control Word 4 */ +#define IMR 0x1 /* Interrupt Mask Register */ + +/* bits for IRR, IMR, ISR and ICW3 */ +#define IR7 0x80 /* IR7 */ +#define IR6 0x40 /* IR6 */ +#define IR5 0x20 /* IR5 */ +#define IR4 0x10 /* IR4 */ +#define IR3 0x08 /* IR3 */ +#define IR2 0x04 /* IR2 */ +#define IR1 0x02 /* IR1 */ +#define IR0 0x01 /* IR0 */ + +/* bits for SEOI */ +#define SEOI_IR7 0x07 /* IR7 */ +#define SEOI_IR6 0x06 /* IR6 */ +#define SEOI_IR5 0x05 /* IR5 */ +#define SEOI_IR4 0x04 /* IR4 */ +#define SEOI_IR3 0x03 /* IR3 */ +#define SEOI_IR2 0x02 /* IR2 */ +#define SEOI_IR1 0x01 /* IR1 */ +#define SEOI_IR0 0x00 /* IR0 */ + +/* OCW2 bits */ +#define OCW2_RCLR 0x00 /* Rotate/clear */ +#define OCW2_NEOI 0x20 /* Non specific EOI */ +#define OCW2_NOP 0x40 /* NOP */ +#define OCW2_SEOI 0x60 /* Specific EOI */ +#define OCW2_RSET 0x80 /* Rotate/set */ +#define OCW2_REOI 0xA0 /* Rotate on non specific EOI */ +#define OCW2_PSET 0xC0 /* Priority Set Command */ +#define OCW2_RSEOI 0xE0 /* Rotate on specific EOI */ + +/* ICW1 bits */ +#define ICW1_SEL 0x10 /* Select ICW1 */ +#define ICW1_LTIM 0x08 /* Level-Triggered Interrupt Mode */ +#define ICW1_ADI 0x04 /* Address Interval */ +#define ICW1_SNGL 0x02 /* Single PIC */ +#define ICW1_EICW4 0x01 /* Expect initilization ICW4 */ + +/* ICW2 is the starting vector number */ + +/* ICW2 is bit-mask of present slaves for a master device, + * or the slave ID for a slave device */ + +/* ICW4 bits */ +#define ICW4_AEOI 0x02 /* Automatic EOI Mode */ +#define ICW4_PM 0x01 /* Microprocessor Mode */ + +#endif diff --git a/include/asm-i386/ibmpc.h b/include/asm-i386/ibmpc.h new file mode 100644 index 0000000000..abdd1d7629 --- /dev/null +++ b/include/asm-i386/ibmpc.h @@ -0,0 +1,47 @@ +/* + * (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 __ASM_IBMPC_H_ +#define __ASM_IBMPC_H_ 1 + +/* misc ports in an ibm compatible pc */ + +#define MASTER_PIC 0x20 +#define PIT_BASE 0x40 +#define KBDDATA 0x60 +#define SYSCTLB 0x62 +#define KBDCMD 0x64 +#define SYSCTLA 0x92 +#define SLAVE_PIC 0xa0 + +#if 1 +#define UART0_BASE 0x3f8 +#define UART1_BASE 0x2f8 +#else +/* FixMe: uarts swapped */ +#define UART0_BASE 0x2f8 +#define UART1_BASE 0x3f8 +#endif + + +#endif diff --git a/include/asm-i386/ic/ali512x.h b/include/asm-i386/ic/ali512x.h new file mode 100644 index 0000000000..5bc1bd7907 --- /dev/null +++ b/include/asm-i386/ic/ali512x.h @@ -0,0 +1,54 @@ +/* + * (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 __ASM_IC_ALI512X_H_ +#define __ASM_IC_ALI512X_H_ + +# define ALI_INDEX 0x3f0 +# define ALI_DATA 0x3f1 + +# define ALI_ENABLED 1 +# define ALI_DISABLED 0 + +# define ALI_UART1 0 +# define ALI_UART2 1 + +/* setup functions */ +void ali512x_init(void); +void ali512x_set_fdc(int enabled, u16 io, u8 irq, u8 dma_channel); +void ali512x_set_pp(int enabled, u16 io, u8 irq, u8 dma_channel); +void ali512x_set_uart(int enabled, int index, u16 io, u8 irq); +void ali512x_set_rtc(int enabled, u16 io, u8 irq); +void ali512x_set_kbc(int enabled, u8 kbc_irq, u8 mouse_irq); +void ali512x_set_cio(int enabled); + + +/* common I/O functions */ +void ali512x_cio_function(int pin, int special, int inv, int input); +void ali512x_cio_out(int pin, int value); +int ali512x_cio_in(int pin); + +/* misc features */ +void ali512x_set_uart2_irda(int enabled); + +#endif diff --git a/include/asm-i386/ic/sc520.h b/include/asm-i386/ic/sc520.h new file mode 100644 index 0000000000..9708504e31 --- /dev/null +++ b/include/asm-i386/ic/sc520.h @@ -0,0 +1,249 @@ +/* + * (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 _ASM_IC_SC520_H_ +#define _ASM_IC_SC520_H_ 1 + +/* Memory mapped configuration registers, MMCR */ +#define SC520_REVID 0x0000 /* ElanSC520 Microcontroller Revision ID Register */ +#define SC520_CPUCTL 0x0002 /* Am5x86 CPU Control Register */ +#define SC520_DRCCTL 0x0010 /* SDRAM Control Register */ +#define SC520_DRCTMCTL 0x0012 /* SDRAM Timing Control Register */ +#define SC520_DRCCFG 0x0014 /* SDRAM Bank Configuration Register*/ +#define SC520_DRCBENDADR 0x0018 /* SDRAM Bank 0-3 Ending Address Register*/ +#define SC520_ECCCTL 0x0020 /* ECC Control Register */ +#define SC520_ECCSTA 0x0021 /* ECC Status Register */ +#define SC520_ECCCKBPOS 0x0022 /* ECC Check Bit Position Register */ +#define SC520_ECCSBADD 0x0024 /* ECC Single-Bit Error Address Register */ +#define SC520_DBCTL 0x0040 /* SDRAM Buffer Control Register */ +#define SC520_BOOTCSCTL 0x0050 /* /BOOTCS Control Register */ +#define SC520_ROMCS1CTL 0x0054 /* /ROMCS1 Control Register */ +#define SC520_ROMCS2CTL 0x0056 /* /ROMCS2 Control Register */ +#define SC520_HBCTL 0x0060 /* Host Bridge Control Register */ +#define SC520_HBTGTIRQCTL 0x0062 /* Host Bridge Target Interrupt Control Register */ +#define SC520_HBTGTIRQSTA 0x0064 /* Host Bridge Target Interrupt Status Register */ +#define SC520_HBMSTIRQCTL 0x0066 /* Host Bridge Target Interrupt Control Register */ +#define SC520_HBMSTIRQSTA 0x0068 /* Host Bridge Master Interrupt Status Register */ +#define SC520_MSTINTADD 0x006c /* Host Bridge Master Interrupt Address Register */ +#define SC520_SYSARBCTL 0x0070 /* System Arbiter Control Register */ +#define SC520_PCIARBSTA 0x0071 /* PCI Bus Arbiter Status Register */ +#define SC520_SYSARBMENB 0x0072 /* System Arbiter Master Enable Register */ +#define SC520_ARBPRICTL 0x0074 /* Arbiter Priority Control Register */ +#define SC520_ADDDECCTL 0x0080 /* Address Decode Control Register */ +#define SC520_WPVSTA 0x0082 /* Write-Protect Violation Status Register */ +#define SC520_PAR0 0x0088 /* Programmable Address Region 0 Register */ +#define SC520_PAR1 0x008c /* Programmable Address Region 1 Register */ +#define SC520_PAR2 0x0090 /* Programmable Address Region 2 Register */ +#define SC520_PAR3 0x0094 /* Programmable Address Region 3 Register */ +#define SC520_PAR4 0x0098 /* Programmable Address Region 4 Register */ +#define SC520_PAR5 0x009c /* Programmable Address Region 5 Register */ +#define SC520_PAR6 0x00a0 /* Programmable Address Region 6 Register */ +#define SC520_PAR7 0x00a4 /* Programmable Address Region 7 Register */ +#define SC520_PAR8 0x00a8 /* Programmable Address Region 8 Register */ +#define SC520_PAR9 0x00ac /* Programmable Address Region 9 Register */ +#define SC520_PAR10 0x00b0 /* Programmable Address Region 10 Register */ +#define SC520_PAR11 0x00b4 /* Programmable Address Region 11 Register */ +#define SC520_PAR12 0x00b8 /* Programmable Address Region 12 Register */ +#define SC520_PAR13 0x00bc /* Programmable Address Region 13 Register */ +#define SC520_PAR14 0x00c0 /* Programmable Address Region 14 Register */ +#define SC520_PAR15 0x00c4 /* Programmable Address Region 15 Register */ +#define SC520_GPECHO 0x0c00 /* GP Echo Mode Register */ +#define SC520_GPCSDW 0x0c01 /* GP Chip Select Data Width Register */ +#define SC520_GPCSQUAL 0x0c02 /* GP Chip Select Qualification Register */ +#define SC520_GPCSRT 0x0c08 /* GP Chip Select Recovery Time Register */ +#define SC520_GPCSPW 0x0c09 /* GP Chip Select Pulse Width Register */ +#define SC520_GPCSOFF 0x0c0a /* GP Chip Select Offset Register */ +#define SC520_GPRDW 0x0c0b /* GP Read Pulse Width Register */ +#define SC520_GPRDOFF 0x0c0c /* GP Read Offset Register */ +#define SC520_GPWRW 0x0c0d /* GP Write Pulse Width Register */ +#define SC520_GPWROFF 0x0c0e /* GP Write Offset Register */ +#define SC520_GPALEW 0x0c0f /* GP ALE Pulse Width Register */ +#define SC520_GPALEOFF 0x0c10 /* GP ALE Offset Register */ +#define SC520_PIOPFS15_0 0x0c20 /* PIO15-PIO0 Pin Function Select */ +#define SC520_PIOPFS31_16 0x0c22 /* PIO31-PIO16 Pin Function Select */ +#define SC520_CSPFS 0x0c24 /* Chip Select Pin Function Select */ +#define SC520_CLKSEL 0x0c26 /* Clock Select */ +#define SC520_DSCTL 0x0c28 /* Drive Strength Control */ +#define SC520_PIODIR15_0 0x0c2a /* PIO15-PIO0 Direction */ +#define SC520_PIODIR31_16 0x0c2c /* PIO31-PIO16 Direction */ +#define SC520_PIODATA15_0 0x0c30 /* PIO15-PIO0 Data */ +#define SC520_PIODATA31_16 0x0c32 /* PIO31-PIO16 Data */ +#define SC520_PIOSET15_0 0x0c34 /* PIO15-PIO0 Set */ +#define SC520_PIOSET31_16 0x0c36 /* PIO31-PIO16 Set */ +#define SC520_PIOCLR15_0 0x0c38 /* PIO15-PIO0 Clear */ +#define SC520_PIOCLR31_16 0x0c3a /* PIO31-PIO16 Clear */ +#define SC520_SWTMRMILLI 0x0c60 /* Software Timer Millisecond Count */ +#define SC520_SWTMRMICRO 0x0c62 /* Software Timer Microsecond Count */ +#define SC520_SWTMRCFG 0x0c64 /* Software Timer Configuration */ +#define SC520_GPTMRSTA 0x0c70 /* GP Timers Status Register */ +#define SC520_GPTMR0CTL 0x0c72 /* GP Timer 0 Mode/Control Register */ +#define SC520_GPTMR0CNT 0x0c74 /* GP Timer 0 Count Register */ +#define SC520_GPTMR0MAXCMPA 0x0c76 /* GP Timer 0 Maxcount Compare A Register */ +#define SC520_GPTMR0MAXCMPB 0x0c78 /* GP Timer 0 Maxcount Compare B Register */ +#define SC520_GPTMR1CTL 0x0c7a /* GP Timer 1 Mode/Control Register */ +#define SC520_GPTMR1CNT 0x0c7c /* GP Timer 1 Count Register */ +#define SC520_GPTMR1MAXCMPA 0x0c7e /* GP Timer 1 Maxcount Compare Register A */ +#define SC520_GPTMR1MAXCMPB 0x0c80 /* GP Timer 1 Maxcount Compare B Register */ +#define SC520_GPTMR2CTL 0x0c82 /* GP Timer 2 Mode/Control Register */ +#define SC520_GPTMR2CNT 0x0c84 /* GP Timer 2 Count Register */ +#define SC520_GPTMR2MAXCMPA 0x0c8e /* GP Timer 2 Maxcount Compare A Register */ +#define SC520_WDTMRCTL 0x0cb0 /* Watchdog Timer Control Register */ +#define SC520_WDTMRCNTL 0x0cb2 /* Watchdog Timer Count Low Register */ +#define SC520_WDTMRCNTH 0x0cb4 /* Watchdog Timer Count High Register */ +#define SC520_UART1CTL 0x0cc0 /* UART 1 General Control Register */ +#define SC520_UART1STA 0x0cc1 /* UART 1 General Status Register */ +#define SC520_UART1FCRSHAD 0x0cc2 /* UART 1 FIFO Control Shadow Register */ +#define SC520_UART2CTL 0x0cc4 /* UART 2 General Control Register */ +#define SC520_UART2STA 0x0cc5 /* UART 2 General Status Register */ +#define SC520_UART2FCRSHAD 0x0cc6 /* UART 2 FIFO Control Shadow Register */ +#define SC520_PICICR 0x0d00 /* Interrupt Control Register */ +#define SC520_MPICMODE 0x0d02 /* Master PIC Interrupt Mode Register */ +#define SC520_SL1PICMODE 0x0d03 /* Slave 1 PIC Interrupt Mode Register */ +#define SC520_SL2PICMODE 0x0d04 /* Slave 2 PIC Interrupt Mode Register */ +#define SC520_SWINT16_1 0x0d08 /* Software Interrupt 16-1 Control Register */ +#define SC520_SWINT22_17 0x0d0a /* Software Interrupt 22-17/NMI Control Register */ +#define SC520_INTPINPOL 0x0d10 /* Interrupt Pin Polarity Register */ +#define SC520_PCIHOSTMAP 0x0d14 /* PCI Host Bridge Interrupt Mappin Register */ +#define SC520_ECCMAP 0x0d18 /* ECC Interrupt Mapping Register */ +#define SC520_GPTMR0MAP 0x0d1a /* GP Timer 0 Interrupt Mapping Register */ +#define SC520_GPTMR1MAP 0x0d1b /* GP Timer 1 Interrupt Mapping Register */ +#define SC520_GPTMR2MAP 0x0d1c /* GP Timer 2 Interrupt Mapping Register */ +#define SC520_PIT0MAP 0x0d20 /* PIT0 Interrupt Mapping Register */ +#define SC520_PIT1MAP 0x0d21 /* PIT1 Interrupt Mapping Register */ +#define SC520_PIT2MAP 0x0d22 /* PIT2 Interrupt Mapping Register */ +#define SC520_UART1MAP 0x0d28 /* UART 1 Interrupt Mapping Register */ +#define SC520_UART2MAP 0x0d29 /* UART 2 Interrupt Mapping Register */ +#define SC520_PCIINTAMAP 0x0d30 /* PCI Interrupt A Mapping Register */ +#define SC520_PCIINTBMAP 0x0d31 /* PCI Interrupt B Mapping Register */ +#define SC520_PCIINTCMAP 0x0d32 /* PCI Interrupt C Mapping Register */ +#define SC520_PCIINTDMAP 0x0d33 /* PCI Interrupt D Mapping Register */ +#define SC520_DMABCINTMAP 0x0d40 /* DMA Buffer Chaining Interrupt Mapping Register */ +#define SC520_SSIMAP 0x0d41 /* SSI Interrupt Mapping Register */ +#define SC520_WDTMAP 0x0d42 /* Watchdog Timer Interrupt Mapping Register */ +#define SC520_RTCMAP 0x0d43 /* RTC Interrupt Mapping Register */ +#define SC520_WPVMAP 0x0d44 /* Write-Protect Interrupt Mapping Register */ +#define SC520_ICEMAP 0x0d45 /* AMDebug JTAG RX/TX Interrupt Mapping Register */ +#define SC520_FERRMAP 0x0d46 /* Floating Point Error Interrupt Mapping Register */ +#define SC520_GP0IMAP 0x0d50 /* GPIRQ0 Interrupt Mapping Register */ +#define SC520_GP1IMAP 0x0d51 /* GPIRQ1 Interrupt Mapping Register */ +#define SC520_GP2IMAP 0x0d52 /* GPIRQ2 Interrupt Mapping Register */ +#define SC520_GP3IMAP 0x0d53 /* GPIRQ3 Interrupt Mapping Register */ +#define SC520_GP4IMAP 0x0d54 /* GPIRQ4 Interrupt Mapping Register */ +#define SC520_GP5IMAP 0x0d55 /* GPIRQ5 Interrupt Mapping Register */ +#define SC520_GP6IMAP 0x0d56 /* GPIRQ6 Interrupt Mapping Register */ +#define SC520_GP7IMAP 0x0d57 /* GPIRQ7 Interrupt Mapping Register */ +#define SC520_GP8IMAP 0x0d58 /* GPIRQ8 Interrupt Mapping Register */ +#define SC520_GP9IMAP 0x0d59 /* GPIRQ9 Interrupt Mapping Register */ +#define SC520_GP10IMAP 0x0d5a /* GPIRQ10 Interrupt Mapping Register */ +#define SC520_SYSINFO 0x0d70 /* System Board Information Register */ +#define SC520_RESCFG 0x0d72 /* Reset Configuration Register */ +#define SC520_RESSTA 0x0d74 /* Reset Status Register */ +#define SC520_GPDMAMMIO 0x0d81 /* GP-DMA Memory-Mapped I/O Register */ +#define SC520_GPDMAEXTCHMAPA 0x0d82 /* GP-DMA Resource Channel Map A */ +#define SC520_GPDMAEXTCHMAPB 0x0d84 /* GP-DMA Resource Channel Map B */ +#define SC520_GPDMAEXTPG0 0x0d86 /* GP-DMA Channel 0 Extended Page */ +#define SC520_GPDMAEXTPG1 0x0d87 /* GP-DMA Channel 1 Extended Page */ +#define SC520_GPDMAEXTPG2 0x0d88 /* GP-DMA Channel 2 Extended Page */ +#define SC520_GPDMAEXTPG3 0x0d89 /* GP-DMA Channel 3 Extended Page */ +#define SC520_GPDMAEXTPG5 0x0d8a /* GP-DMA Channel 5 Extended Page */ +#define SC520_GPDMAEXTPG6 0x0d8b /* GP-DMA Channel 6 Extended Page */ +#define SC520_GPDMAEXTPG7 0x0d8c /* GP-DMA Channel 7 Extended Page */ +#define SC520_GPDMAEXTTC3 0x0d90 /* GP-DMA Channel 3 Extender Transfer count */ +#define SC520_GPDMAEXTTC5 0x0d91 /* GP-DMA Channel 5 Extender Transfer count */ +#define SC520_GPDMAEXTTC6 0x0d92 /* GP-DMA Channel 6 Extender Transfer count */ +#define SC520_GPDMAEXTTC7 0x0d93 /* GP-DMA Channel 7 Extender Transfer count */ +#define SC520_GPDMABCCTL 0x0d98 /* Buffer Chaining Control */ +#define SC520_GPDMABCSTA 0x0d99 /* Buffer Chaining Status */ +#define SC520_GPDMABSINTENB 0x0d9a /* Buffer Chaining Interrupt Enable */ +#define SC520_GPDMABCVAL 0x0d9b /* Buffer Chaining Valid */ +#define SC520_GPDMANXTADDL3 0x0da0 /* GP-DMA Channel 3 Next Address Low */ +#define SC520_GPDMANXTADDH3 0x0da2 /* GP-DMA Channel 3 Next Address High */ +#define SC520_GPDMANXTADDL5 0x0da4 /* GP-DMA Channel 5 Next Address Low */ +#define SC520_GPDMANXTADDH5 0x0da6 /* GP-DMA Channel 5 Next Address High */ +#define SC520_GPDMANXTADDL6 0x0da8 /* GP-DMA Channel 6 Next Address Low */ +#define SC520_GPDMANXTADDH6 0x0daa /* GP-DMA Channel 6 Next Address High */ +#define SC520_GPDMANXTADDL7 0x0dac /* GP-DMA Channel 7 Next Address Low */ +#define SC520_GPDMANXTADDH7 0x0dae /* GP-DMA Channel 7 Next Address High */ +#define SC520_GPDMANXTTCL3 0x0db0 /* GP-DMA Channel 3 Next Transfer Count Low */ +#define SC520_GPDMANXTTCH3 0x0db2 /* GP-DMA Channel 3 Next Transfer Count High */ +#define SC520_GPDMANXTTCL5 0x0db4 /* GP-DMA Channel 5 Next Transfer Count Low */ +#define SC520_GPDMANXTTCH5 0x0db6 /* GP-DMA Channel 5 Next Transfer Count High */ +#define SC520_GPDMANXTTCL6 0x0db8 /* GP-DMA Channel 6 Next Transfer Count Low */ +#define SC520_GPDMANXTTCH6 0x0dba /* GP-DMA Channel 6 Next Transfer Count High */ +#define SC520_GPDMANXTTCL7 0x0dbc /* GP-DMA Channel 7 Next Transfer Count Low */ +#define SC520_GPDMANXTTCH7 0x0dbe /* GP-DMA Channel 7 Next Transfer Count High */ + +/* MMCR Register bits (not all of them :) ) */ + +/* BITS for SC520_ADDDECCTL: */ +#define WPV_INT_ENB 0x80 /* Write-Protect Violation Interrupt Enable */ +#define IO_HOLE_DEST 0x10 /* I/O Hole Access Destination */ +#define RTC_DIS 0x04 /* RTC Disable */ +#define UART2_DIS 0x02 /* UART2 Disable */ +#define UART1_DIS 0x01 /* UART1 Disable */ + +/* bus mapping constants (used for PCI core initialization) */ /* bus mapping constants */ +#define SC520_REG_ADDR 0x00000cf8 +#define SC520_REG_DATA 0x00000cfc + + +#define SC520_ISA_MEM_PHYS 0x00000000 +#define SC520_ISA_MEM_BUS 0x00000000 +#define SC520_ISA_MEM_SIZE 0x01000000 + +#define SC520_ISA_IO_PHYS 0x00000000 +#define SC520_ISA_IO_BUS 0x00000000 +#define SC520_ISA_IO_SIZE 0x00001000 + +/* PCI I/O space from 0x1000 to 0xfdff */ +#define SC520_PCI_IO_PHYS 0x00001000 +#define SC520_PCI_IO_BUS 0x00001000 +#define SC520_PCI_IO_SIZE 0x0000ee00 + +/* system memory from 0x00000000 to 0x0fffffff */ +#define SC520_PCI_MEMORY_PHYS 0x00000000 +#define SC520_PCI_MEMORY_BUS 0x00000000 +#define SC520_PCI_MEMORY_SIZE 0x10000000 + +/* PCI bus memory from 0x10000000 to 0x27ffffff */ +#define SC520_PCI_MEM_PHYS 0x10000000 +#define SC520_PCI_MEM_BUS 0x10000000 +#define SC520_PCI_MEM_SIZE 0x18000000 + +/* 0x28000000 - 0x3fffffff is used by the flash banks */ + +/* 0x40000000 - 0xffffffff is not adressable by the SC520 */ + +/* utility functions */ +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); + +#endif diff --git a/include/asm-i386/io.h b/include/asm-i386/io.h new file mode 100644 index 0000000000..d8c503ccb3 --- /dev/null +++ b/include/asm-i386/io.h @@ -0,0 +1,207 @@ +#ifndef _ASM_IO_H +#define _ASM_IO_H + +#include <linux/config.h> + +/* + * This file contains the definitions for the x86 IO instructions + * inb/inw/inl/outb/outw/outl and the "string versions" of the same + * (insb/insw/insl/outsb/outsw/outsl). You can also use "pausing" + * versions of the single-IO instructions (inb_p/inw_p/..). + * + * This file is not meant to be obfuscating: it's just complicated + * to (a) handle it all in a way that makes gcc able to optimize it + * as well as possible and (b) trying to avoid writing the same thing + * over and over again with slight variations and possibly making a + * mistake somewhere. + */ + +/* + * Thanks to James van Artsdalen for a better timing-fix than + * the two short jumps: using outb's to a nonexistent port seems + * to guarantee better timings even on fast machines. + * + * On the other hand, I'd like to be sure of a non-existent port: + * I feel a bit unsafe about using 0x80 (should be safe, though) + * + * Linus + */ + + /* + * Bit simplified and optimized by Jan Hubicka + * Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999. + * + * isa_memset_io, isa_memcpy_fromio, isa_memcpy_toio added, + * isa_read[wl] and isa_write[wl] fixed + * - Arnaldo Carvalho de Melo <acme@conectiva.com.br> + */ + +#define IO_SPACE_LIMIT 0xffff + + +#ifdef __KERNEL__ + + +/* + * readX/writeX() are used to access memory mapped devices. On some + * architectures the memory mapped IO stuff needs to be accessed + * differently. On the x86 architecture, we just read/write the + * memory location directly. + */ + +#define readb(addr) (*(volatile unsigned char *) (addr)) +#define readw(addr) (*(volatile unsigned short *) (addr)) +#define readl(addr) (*(volatile unsigned int *) (addr)) +#define __raw_readb readb +#define __raw_readw readw +#define __raw_readl readl + +#define writeb(b,addr) (*(volatile unsigned char *) (addr) = (b)) +#define writew(b,addr) (*(volatile unsigned short *) (addr) = (b)) +#define writel(b,addr) (*(volatile unsigned int *) (addr) = (b)) +#define __raw_writeb writeb +#define __raw_writew writew +#define __raw_writel writel + +#define memset_io(a,b,c) memset((a),(b),(c)) +#define memcpy_fromio(a,b,c) memcpy((a),(b),(c)) +#define memcpy_toio(a,b,c) memcpy((a),(b),(c)) + +/* + * ISA space is 'always mapped' on a typical x86 system, no need to + * explicitly ioremap() it. The fact that the ISA IO space is mapped + * to PAGE_OFFSET is pure coincidence - it does not mean ISA values + * are physical addresses. The following constant pointer can be + * used as the IO-area pointer (it can be iounmapped as well, so the + * analogy with PCI is quite large): + */ +#define isa_readb(a) readb((a)) +#define isa_readw(a) readw((a)) +#define isa_readl(a) readl((a)) +#define isa_writeb(b,a) writeb(b,(a)) +#define isa_writew(w,a) writew(w,(a)) +#define isa_writel(l,a) writel(l,(a)) +#define isa_memset_io(a,b,c) memset_io((a),(b),(c)) +#define isa_memcpy_fromio(a,b,c) memcpy_fromio((a),(b),(c)) +#define isa_memcpy_toio(a,b,c) memcpy_toio((a),(b),(c)) + + + +static inline int check_signature(unsigned long io_addr, + const unsigned char *signature, int length) +{ + int retval = 0; + do { + if (readb(io_addr) != *signature) + goto out; + io_addr++; + signature++; + length--; + } while (length); + retval = 1; +out: + return retval; +} + +/** + * isa_check_signature - find BIOS signatures + * @io_addr: mmio address to check + * @signature: signature block + * @length: length of signature + * + * Perform a signature comparison with the ISA mmio address io_addr. + * Returns 1 on a match. + * + * This function is deprecated. New drivers should use ioremap and + * check_signature. + */ + + +static inline int isa_check_signature(unsigned long io_addr, + const unsigned char *signature, int length) +{ + int retval = 0; + do { + if (isa_readb(io_addr) != *signature) + goto out; + io_addr++; + signature++; + length--; + } while (length); + retval = 1; +out: + return retval; +} + +#endif /* __KERNEL__ */ + +#ifdef SLOW_IO_BY_JUMPING +#define __SLOW_DOWN_IO "\njmp 1f\n1:\tjmp 1f\n1:" +#else +#define __SLOW_DOWN_IO "\noutb %%al,$0x80" +#endif + +#ifdef REALLY_SLOW_IO +#define __FULL_SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO +#else +#define __FULL_SLOW_DOWN_IO __SLOW_DOWN_IO +#endif + + +/* + * Talk about misusing macros.. + */ +#define __OUT1(s,x) \ +static inline void out##s(unsigned x value, unsigned short port) { + +#define __OUT2(s,s1,s2) \ +__asm__ __volatile__ ("out" #s " %" s1 "0,%" s2 "1" + + +#define __OUT(s,s1,x) \ +__OUT1(s,x) __OUT2(s,s1,"w") : : "a" (value), "Nd" (port)); } \ +__OUT1(s##_p,x) __OUT2(s,s1,"w") __FULL_SLOW_DOWN_IO : : "a" (value), "Nd" (port));} + +#define __IN1(s) \ +static inline RETURN_TYPE in##s(unsigned short port) { RETURN_TYPE _v; + +#define __IN2(s,s1,s2) \ +__asm__ __volatile__ ("in" #s " %" s2 "1,%" s1 "0" + +#define __IN(s,s1,i...) \ +__IN1(s) __IN2(s,s1,"w") : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \ +__IN1(s##_p) __IN2(s,s1,"w") __FULL_SLOW_DOWN_IO : "=a" (_v) : "Nd" (port) ,##i ); return _v; } + +#define __INS(s) \ +static inline void ins##s(unsigned short port, void * addr, unsigned long count) \ +{ __asm__ __volatile__ ("rep ; ins" #s \ +: "=D" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); } + +#define __OUTS(s) \ +static inline void outs##s(unsigned short port, const void * addr, unsigned long count) \ +{ __asm__ __volatile__ ("rep ; outs" #s \ +: "=S" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); } + +#define RETURN_TYPE unsigned char +__IN(b,"") +#undef RETURN_TYPE +#define RETURN_TYPE unsigned short +__IN(w,"") +#undef RETURN_TYPE +#define RETURN_TYPE unsigned int +__IN(l,"") +#undef RETURN_TYPE + +__OUT(b,"b",char) +__OUT(w,"w",short) +__OUT(l,,int) + +__INS(b) +__INS(w) +__INS(l) + +__OUTS(b) +__OUTS(w) +__OUTS(l) + +#endif diff --git a/include/asm-i386/pci.h b/include/asm-i386/pci.h new file mode 100644 index 0000000000..15c165b720 --- /dev/null +++ b/include/asm-i386/pci.h @@ -0,0 +1,31 @@ + + +/* + * (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 _PCI_I386_H_ +#define _PCI_I386_H_ 1 + +void pci_setup_type1(struct pci_controller* hose, u32 cfg_addr, u32 cfg_data); + +#endif diff --git a/include/asm-i386/posix_types.h b/include/asm-i386/posix_types.h new file mode 100644 index 0000000000..5529f32702 --- /dev/null +++ b/include/asm-i386/posix_types.h @@ -0,0 +1,80 @@ +#ifndef __ARCH_I386_POSIX_TYPES_H +#define __ARCH_I386_POSIX_TYPES_H + +/* + * This file is generally used by user-level software, so you need to + * be a little careful about namespace pollution etc. Also, we cannot + * assume GCC is being used. + */ + +typedef unsigned short __kernel_dev_t; +typedef unsigned long __kernel_ino_t; +typedef unsigned short __kernel_mode_t; +typedef unsigned short __kernel_nlink_t; +typedef long __kernel_off_t; +typedef int __kernel_pid_t; +typedef unsigned short __kernel_ipc_pid_t; +typedef unsigned short __kernel_uid_t; +typedef unsigned short __kernel_gid_t; +typedef unsigned int __kernel_size_t; +typedef int __kernel_ssize_t; +typedef int __kernel_ptrdiff_t; +typedef long __kernel_time_t; +typedef long __kernel_suseconds_t; +typedef long __kernel_clock_t; +typedef int __kernel_daddr_t; +typedef char * __kernel_caddr_t; +typedef unsigned short __kernel_uid16_t; +typedef unsigned short __kernel_gid16_t; +typedef unsigned int __kernel_uid32_t; +typedef unsigned int __kernel_gid32_t; + +typedef unsigned short __kernel_old_uid_t; +typedef unsigned short __kernel_old_gid_t; + +#ifdef __GNUC__ +typedef long long __kernel_loff_t; +#endif + +typedef struct { +#if defined(__KERNEL__) || defined(__USE_ALL) + int val[2]; +#else /* !defined(__KERNEL__) && !defined(__USE_ALL) */ + int __val[2]; +#endif /* !defined(__KERNEL__) && !defined(__USE_ALL) */ +} __kernel_fsid_t; + +#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) + +#undef __FD_SET +#define __FD_SET(fd,fdsetp) \ + __asm__ __volatile__("btsl %1,%0": \ + "=m" (*(__kernel_fd_set *) (fdsetp)):"r" ((int) (fd))) + +#undef __FD_CLR +#define __FD_CLR(fd,fdsetp) \ + __asm__ __volatile__("btrl %1,%0": \ + "=m" (*(__kernel_fd_set *) (fdsetp)):"r" ((int) (fd))) + +#undef __FD_ISSET +#define __FD_ISSET(fd,fdsetp) (__extension__ ({ \ + unsigned char __result; \ + __asm__ __volatile__("btl %1,%2 ; setb %0" \ + :"=q" (__result) :"r" ((int) (fd)), \ + "m" (*(__kernel_fd_set *) (fdsetp))); \ + __result; })) + +#undef __FD_ZERO +#define __FD_ZERO(fdsetp) \ +do { \ + int __d0, __d1; \ + __asm__ __volatile__("cld ; rep ; stosl" \ + :"=m" (*(__kernel_fd_set *) (fdsetp)), \ + "=&c" (__d0), "=&D" (__d1) \ + :"a" (0), "1" (__FDSET_LONGS), \ + "2" ((__kernel_fd_set *) (fdsetp)) : "memory"); \ +} while (0) + +#endif /* defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) */ + +#endif diff --git a/include/asm-i386/ppcboot-i386.h b/include/asm-i386/ppcboot-i386.h new file mode 100644 index 0000000000..704526e2ff --- /dev/null +++ b/include/asm-i386/ppcboot-i386.h @@ -0,0 +1,53 @@ +/* + * (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 _PPCBOOT_I386_H_ +#define _PPCBOOT_I386_H_ 1 + +/* for the following variables, see start.S */ +extern ulong i386boot_start; /* code start (in flash) */ +extern ulong i386boot_end; /* code end (in flash) */ +extern ulong i386boot_romdata_start;/* datasegment in flash (also code+rodata end) */ +extern ulong i386boot_romdata_dest; /* data location segment in ram */ +extern ulong i386boot_romdata_size; /* size of data segment */ +extern ulong i386boot_bss_start; /* bss start */ +extern ulong i386boot_bss_size; /* bss size */ +extern ulong i386boot_stack_end; /* first usable RAM address after bss and stack */ +extern ulong i386boot_ram_end; /* end of ram */ + +extern ulong i386boot_realmode; /* start of realmode entry code */ +extern ulong i386boot_realmode_size;/* size of realmode entry code */ +extern ulong i386boot_bios; /* start of BIOS emulation code */ +extern ulong i386boot_bios_size; /* size of BIOS emulation code */ + + +/* cpu/.../cpu.c */ +int cpu_init(void); +int timer_init(void); + +/* board/.../... */ +int board_init(void); +int dram_init (void); + + +#endif /* _PPCBOOT_I386_H_ */ diff --git a/include/asm-i386/ptrace.h b/include/asm-i386/ptrace.h new file mode 100644 index 0000000000..d99e464007 --- /dev/null +++ b/include/asm-i386/ptrace.h @@ -0,0 +1,66 @@ +#ifndef _I386_PTRACE_H +#define _I386_PTRACE_H + +#define EBX 0 +#define ECX 1 +#define EDX 2 +#define ESI 3 +#define EDI 4 +#define EBP 5 +#define EAX 6 +#define DS 7 +#define ES 8 +#define FS 9 +#define GS 10 +#define ORIG_EAX 11 +#define EIP 12 +#define CS 13 +#define EFL 14 +#define UESP 15 +#define SS 16 +#define FRAME_SIZE 17 + +/* this struct defines the way the registers are stored on the + stack during a system call. */ + +struct pt_regs { + long ebx; + long ecx; + long edx; + long esi; + long edi; + long ebp; + long eax; + int xds; + int xes; + int xfs; + int xgs; + long orig_eax; + long eip; + int xcs; + long eflags; + long esp; + int xss; +} __attribute__ ((packed)); + + +/* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */ +#define PTRACE_GETREGS 12 +#define PTRACE_SETREGS 13 +#define PTRACE_GETFPREGS 14 +#define PTRACE_SETFPREGS 15 +#define PTRACE_GETFPXREGS 18 +#define PTRACE_SETFPXREGS 19 + +#define PTRACE_SETOPTIONS 21 + +/* options set using PTRACE_SETOPTIONS */ +#define PTRACE_O_TRACESYSGOOD 0x00000001 + +#ifdef __KERNEL__ +#define user_mode(regs) ((VM_MASK & (regs)->eflags) || (3 & (regs)->xcs)) +#define instruction_pointer(regs) ((regs)->eip) +extern void show_regs(struct pt_regs *); +#endif + +#endif diff --git a/include/asm-i386/realmode.h b/include/asm-i386/realmode.h new file mode 100644 index 0000000000..fcb76c336a --- /dev/null +++ b/include/asm-i386/realmode.h @@ -0,0 +1,31 @@ +/* + * (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 __ASM_REALMODE_H_ +#define __ASM_REALMODE_H_ +#include <asm/ptrace.h> + +int bios_setup(void); +int enter_realmode(u16 seg, u16 off, struct pt_regs *in, struct pt_regs *out); + +#endif diff --git a/include/asm-i386/string.h b/include/asm-i386/string.h new file mode 100644 index 0000000000..c378222486 --- /dev/null +++ b/include/asm-i386/string.h @@ -0,0 +1,30 @@ +#ifndef __ASM_I386_STRING_H +#define __ASM_I386_STRING_H + +/* + * We don't do inline string functions, since the + * optimised inline asm versions are not small. + */ + +#define __HAVE_ARCH_STRRCHR +extern char * strrchr(const char * s, int c); + +#define __HAVE_ARCH_STRCHR +extern char * strchr(const char * s, int c); + +#define __HAVE_ARCH_MEMCPY +extern void * memcpy(void *, const void *, __kernel_size_t); + +#define __HAVE_ARCH_MEMMOVE +extern void * memmove(void *, const void *, __kernel_size_t); + +#define __HAVE_ARCH_MEMCHR +extern void * memchr(const void *, int, __kernel_size_t); + +#define __HAVE_ARCH_MEMSET +extern void * memset(void *, int, __kernel_size_t); + +#define __HAVE_ARCH_MEMZERO +extern void memzero(void *ptr, __kernel_size_t n); + +#endif diff --git a/include/asm-i386/types.h b/include/asm-i386/types.h new file mode 100644 index 0000000000..bb100ec4e3 --- /dev/null +++ b/include/asm-i386/types.h @@ -0,0 +1,51 @@ +#ifndef __ASM_I386_TYPES_H +#define __ASM_I386_TYPES_H + +typedef unsigned short umode_t; + +/* + * __xx is ok: it doesn't pollute the POSIX namespace. Use these in the + * header files exported to user space + */ + +typedef __signed__ char __s8; +typedef unsigned char __u8; + +typedef __signed__ short __s16; +typedef unsigned short __u16; + +typedef __signed__ int __s32; +typedef unsigned int __u32; + +#if defined(__GNUC__) && !defined(__STRICT_ANSI__) +typedef __signed__ long long __s64; +typedef unsigned long long __u64; +#endif + +/* + * These aren't exported outside the kernel to avoid name space clashes + */ +#ifdef __KERNEL__ + +typedef signed char s8; +typedef unsigned char u8; + +typedef signed short s16; +typedef unsigned short u16; + +typedef signed int s32; +typedef unsigned int u32; + +typedef signed long long s64; +typedef unsigned long long u64; + +#define BITS_PER_LONG 32 + +/* Dma addresses are 32-bits wide. */ + +typedef u32 dma_addr_t; + +#endif /* __KERNEL__ */ + +#endif + diff --git a/include/asm-i386/u-boot.h b/include/asm-i386/u-boot.h new file mode 100644 index 0000000000..554bc85ea9 --- /dev/null +++ b/include/asm-i386/u-boot.h @@ -0,0 +1,58 @@ +/* + * (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 + */ + +#ifndef _U_BOOT_H_ +#define _U_BOOT_H_ 1 + +typedef struct bd_info { + unsigned long bi_memstart; /* start of DRAM memory */ + unsigned long bi_memsize; /* size of DRAM memory in bytes */ + unsigned long bi_flashstart; /* start of FLASH memory */ + unsigned long bi_flashsize; /* size of FLASH memory */ + unsigned long bi_flashoffset; /* reserved area for startup monitor */ + unsigned long bi_sramstart; /* start of SRAM memory */ + unsigned long bi_sramsize; /* size of SRAM memory */ + unsigned long bi_bootflags; /* boot / reboot flag (for LynxOS) */ + unsigned long bi_ip_addr; /* IP Address */ + unsigned char bi_enetaddr[6]; /* Ethernet adress */ + unsigned short bi_ethspeed; /* Ethernet speed in Mbps */ + unsigned long bi_intfreq; /* Internal Freq, in MHz */ + unsigned long bi_busfreq; /* Bus Freq, in MHz */ + unsigned long bi_baudrate; /* Console Baudrate */ + struct environment_s *bi_env; + struct /* RAM configuration */ + { + ulong start; + ulong size; + }bi_dram[CONFIG_NR_DRAM_BANKS]; +} bd_t; + +#define bi_env_data bi_env->data +#define bi_env_crc bi_env->crc + +#endif /* _U_BOOT_H_ */ diff --git a/include/asm-i386/zimage.h b/include/asm-i386/zimage.h new file mode 100644 index 0000000000..688682611f --- /dev/null +++ b/include/asm-i386/zimage.h @@ -0,0 +1,75 @@ +/* + * (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 _ASM_ZIMAGE_H_ +#define _ASM_ZIMAGE_H_ + +/* linux i386 zImage/bzImage header. Offsets relative to + * the start of the image */ + +#define CMD_LINE_MAGIC_OFF 0x020 /* Magic 0xa33f if the offset below is valid */ +#define CMD_LINE_OFFSET_OFF 0x022 /* Offset to comandline */ +#define SETUP_SECTS_OFF 0x1F1 /* The size of the setup in sectors */ +#define ROOT_FLAGS_OFF 0x1F2 /* If set, the root is mounted readonly */ +#define VID_MODE_OFF 0x1FA /* Video mode control */ +#define ROOT_DEV_OFF 0x1FC /* Default root device number */ +#define BOOT_FLAG_OFF 0x1FE /* 0xAA55 magic number */ +#define HEADER_OFF 0x202 /* Magic signature "HdrS" */ +#define VERSION_OFF 0x206 /* Boot protocol version supported */ +#define REALMODE_SWTCH_OFF 0x208 /* Boot loader hook (see below) */ +#define START_SYS_OFF 0x20C /* Points to kernel version string */ +#define TYPE_OF_LOADER_OFF 0x210 /* Boot loader identifier */ +#define LOADFLAGS_OFF 0x211 /* Boot protocol option flags */ +#define SETUP_MOVE_SIZE_OFF 0x212 /* Move to high memory size (used with hooks) */ +#define CODE32_START_OFF 0x214 /* Boot loader hook (see below) */ +#define RAMDISK_IMAGE_OFF 0x218 /* initrd load address (set by boot loader) */ +#define RAMDISK_SIZE_OFF 0x21C /* initrd size (set by boot loader) */ +#define HEAP_END_PTR_OFF 0x224 /* Free memory after setup end */ +#define CMD_LINE_PTR_OFF 0x228 /* 32-bit pointer to the kernel command line */ + + +#define HEAP_FLAG 0x80 +#define BIG_KERNEL_FLAG 0x01 + +/* magic numbers */ +#define KERNEL_MAGIC 0xaa55 +#define KERNEL_V2_MAGIC 0x53726448 +#define COMMAND_LINE_MAGIC 0xA33F + +/* limits */ +#define BZIMAGE_MAX_SIZE 15*1024*1024 /* 15MB */ +#define ZIMAGE_MAX_SIZE 512*1024 /* 512k */ +#define SETUP_MAX_SIZE 32768 + +#define SETUP_START_OFFSET 0x200 +#define BZIMAGE_LOAD_ADDR 0x100000 +#define ZIMAGE_LOAD_ADDR 0x10000 + +void *load_zimage(char *image, unsigned long kernel_size, + unsigned long initrd_addr, unsigned long initrd_size, + int auto_boot); + +void boot_zimage(void *setup_base); +image_header_t *fake_zimage_header(image_header_t *hdr, void *ptr, int size); + +#endif diff --git a/include/cmd_confdefs.h b/include/cmd_confdefs.h index a5308b6932..25f386b95c 100644 --- a/include/cmd_confdefs.h +++ b/include/cmd_confdefs.h @@ -75,8 +75,8 @@ #define CFG_CMD_FPGA 0x0000010000000000 /* FPGA configuration Support */ #define CFG_CMD_HWFLOW 0x0000020000000000 /* RTS/CTS hw flow control */ #define CFG_CMD_SAVES 0x0000040000000000 /* save S record dump */ -#define CFG_CMD_VFD 0x0000080000000000 /* Display bitmap on VFD display*/ #define CFG_CMD_SPI 0x0000100000000000 /* SPI utility */ +#define CFG_CMD_FDOS 0x0000200000000000 /* Floppy DOS support */ #define CFG_CMD_ALL 0xFFFFFFFFFFFFFFFF /* ALL commands */ @@ -96,6 +96,7 @@ CFG_CMD_EEPROM | \ CFG_CMD_ELF | \ CFG_CMD_FDC | \ + CFG_CMD_FDOS | \ CFG_CMD_HWFLOW | \ CFG_CMD_I2C | \ CFG_CMD_IDE | \ @@ -110,9 +111,9 @@ CFG_CMD_SAVES | \ CFG_CMD_SCSI | \ CFG_CMD_SDRAM | \ + CFG_CMD_SPI | \ CFG_CMD_USB | \ - CFG_CMD_VFD | \ - CFG_CMD_SPI ) + CFG_CMD_VFD ) /* Default configuration */ diff --git a/include/cmd_fdos.h b/include/cmd_fdos.h new file mode 100644 index 0000000000..a444c7abcf --- /dev/null +++ b/include/cmd_fdos.h @@ -0,0 +1,55 @@ +/* + * (C) Copyright 2002 + * Stäubli Faverges - <www.staubli.com> + * Pierre AUBERT p.aubert@staubli.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* + * Dos floppy support + */ +#ifndef _CMD_FDOS_H +#define _CMD_FDOS_H + +#include <common.h> +#include <command.h> + + +#if (CONFIG_COMMANDS & CFG_CMD_FDOS) + +#define CMD_TBL_FDOS_BOOT MK_CMD_TBL_ENTRY( \ + "fdosboot", 5, 3, 0, do_fdosboot, \ + "fdosboot- boot from a dos floppy file\n", \ + "[loadAddr] [filename]\n" \ +), +#define CMD_TBL_FDOS_LS MK_CMD_TBL_ENTRY( \ + "fdosls", 5, 2, 0, do_fdosls, \ + "fdosls - list files in a directory\n", \ + "[directory]\n" \ +), +int do_fdosboot (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]); +int do_fdosls (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]); + +#else +#define CMD_TBL_FDOS_BOOT +#define CMD_TBL_FDOS_LS +#endif + +#endif /* _CMD_FDOS_H */ diff --git a/include/common.h b/include/common.h index 21101f105a..a950cdcc40 100644 --- a/include/common.h +++ b/include/common.h @@ -130,10 +130,15 @@ int getenv_r (uchar *name, uchar *buf, unsigned len); int saveenv (void); #ifdef CONFIG_PPC /* ARM version to be fixed! */ void inline setenv (char *, char *); +#else +void setenv (char *, char *); #endif /* CONFIG_PPC */ #ifdef CONFIG_ARM # include <asm/u-boot-arm.h> /* ARM version to be fixed! */ #endif /* CONFIG_ARM */ +#ifdef CONFIG_I386 /* x86 version to be fixed! */ +# include <asm/ppcboot-i386.h> +#endif /* CONFIG_I386 */ void pci_init (void); void pciinfo (int, int); diff --git a/include/configs/LANTEC.h b/include/configs/LANTEC.h index c7c78ad0c6..fe9ee228ee 100644 --- a/include/configs/LANTEC.h +++ b/include/configs/LANTEC.h @@ -90,6 +90,7 @@ & ~CFG_CMD_EEPROM \ & ~CFG_CMD_ELF \ & ~CFG_CMD_FDC \ + & ~CFG_CMD_FDOS \ & ~CFG_CMD_HWFLOW \ & ~CFG_CMD_I2C \ & ~CFG_CMD_IDE \ diff --git a/include/configs/MPC8260ADS.h b/include/configs/MPC8260ADS.h index 14ad313944..b4d8406aa5 100644 --- a/include/configs/MPC8260ADS.h +++ b/include/configs/MPC8260ADS.h @@ -112,6 +112,7 @@ CFG_CMD_EEPROM | \ CFG_CMD_ELF | \ CFG_CMD_FDC | \ + CFG_CMD_FDOS | \ CFG_CMD_HWFLOW | \ CFG_CMD_IDE | \ CFG_CMD_JFFS2 | \ diff --git a/include/configs/ep8260.h b/include/configs/ep8260.h index 5db1f13a14..1285326f4f 100644 --- a/include/configs/ep8260.h +++ b/include/configs/ep8260.h @@ -276,6 +276,7 @@ ~CFG_CMD_DOC & \ ~CFG_CMD_EEPROM & \ ~CFG_CMD_FDC & \ + ~CFG_CMD_FDOS & \ ~CFG_CMD_HWFLOW & \ ~CFG_CMD_IDE & \ ~CFG_CMD_JFFS2 & \ diff --git a/include/configs/hymod.h b/include/configs/hymod.h index af3ba686df..5d2bed6abc 100644 --- a/include/configs/hymod.h +++ b/include/configs/hymod.h @@ -141,6 +141,7 @@ CFG_CMD_DOC | \ CFG_CMD_ELF | \ CFG_CMD_FDC | \ + CFG_CMD_FDOS | \ CFG_CMD_HWFLOW | \ CFG_CMD_IDE | \ CFG_CMD_JFFS2 | \ diff --git a/include/configs/sc520_cdp.h b/include/configs/sc520_cdp.h new file mode 100644 index 0000000000..e7d6c7942b --- /dev/null +++ b/include/configs/sc520_cdp.h @@ -0,0 +1,210 @@ +/* + * (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 + */ + +/* + * board/config.h - configuration options, board specific + */ + +#ifndef __CONFIG_H +#define __CONFIG_H + +/* + * High Level Configuration Options + * (easy to change) + */ + +#define CONFIG_X86 1 /* This is a X86 CPU */ + +#define CFG_SDRAM_PRECHARGE_DELAY 6 /* 6T */ +#define CFG_SDRAM_REFRESH_RATE 78 /* 7.8uS (choices are 7.8, 15.6, 31.2 or 62.5uS) */ +#define CFG_SDRAM_RAS_CAS_DELAY 3 /* 3T */ + +/* define at most one of these */ +#undef CFG_SDRAM_CAS_LATENCY_2T +#define CFG_SDRAM_CAS_LATENCY_3T + +#define CFG_SC520_HIGH_SPEED 0 /* 100 or 133MHz */ +#define CFG_RESET_GENERIC 1 /* use tripple-fault to reset cpu */ +#undef CFG_RESET_SC520 /* use SC520 MMCR's to reset cpu */ +#undef CFG_TIMER_SC520 /* use SC520 swtimers */ +#define CFG_TIMER_GENERIC 1 /* use the i8254 PIT timers */ +#undef CFG_TIMER_TSC /* use the Pentium TSC timers */ +#define CFG_USE_SIO_UART 0 /* prefer the uarts on the SIO to those + * in the SC520 on the CDP */ + +#define CFG_STACK_SIZE 0x8000 /* Size of bootloader stack */ + +#define CONFIG_SHOW_BOOT_PROGRESS 1 +#define CONFIG_LAST_STAGE_INIT 1 + +/* + * Size of malloc() pool + */ +#define CONFIG_MALLOC_SIZE (CFG_ENV_SIZE + 128*1024) + + +/* allow to overwrite serial and ethaddr */ +#define CONFIG_ENV_OVERWRITE +#define CFG_ENV_IS_NOWHERE 1 +#undef CFG_ENV_IS_IN_FLASH +#undef CFG_ENV_IS_IN_NVRAM +#undef CFG_ENV_IS_INEEPROM + +#define CONFIG_BAUDRATE 9600 + +#define CONFIG_COMMANDS (CONFIG_CMD_DFL | CFG_CMD_PCI | CFG_CMD_JFFS2 | CFG_CMD_IDE | CFG_CMD_NET) + +/* this must be included AFTER the definition of CONFIG_COMMANDS (if any) */ +#include <cmd_confdefs.h> + +#define CONFIG_BOOTDELAY 15 +#define CONFIG_BOOTARGS "root=/dev/mtdblock0 console=ttyS0,9600" +/* #define CONFIG_BOOTCOMMAND "bootm 38000000" */ + +#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +#define CONFIG_KGDB_BAUDRATE 115200 /* speed to run kgdb serial port */ +#define CONFIG_KGDB_SER_INDEX 2 /* which serial port to use */ +#endif + +#define CFG_JFFS2_FIRST_BANK 0 /* use for JFFS2 */ +#define CFG_JFFS2_NUM_BANKS 1 /* */ + +/* + * Miscellaneous configurable options + */ +#define CFG_LONGHELP /* undef to save memory */ +#define CFG_PROMPT "boot > " /* Monitor Command Prompt */ +#define CFG_CBSIZE 256 /* Console I/O Buffer Size */ +#define CFG_PBSIZE (CFG_CBSIZE+sizeof(CFG_PROMPT)+16) /* Print Buffer Size */ +#define CFG_MAXARGS 16 /* max number of command args */ +#define CFG_BARGSIZE CFG_CBSIZE /* Boot Argument Buffer Size */ + +#define CFG_MEMTEST_START 0x00100000 /* memtest works on */ +#define CFG_MEMTEST_END 0x01000000 /* 1 ... 16 MB in DRAM */ + +#undef CFG_CLKS_IN_HZ /* everything, incl board info, in Hz */ + +#define CFG_LOAD_ADDR 0x38000000 /* default load address */ + +#define CFG_HZ 1024 /* incrementer freq: 1kHz */ + + /* valid baudrates */ +#define CFG_BAUDRATE_TABLE { 9600, 19200, 38400, 57600, 115200 } + + +/*----------------------------------------------------------------------- + * Physical Memory Map + */ +#define CONFIG_NR_DRAM_BANKS 4 /* we have 4 banks of DRAM */ + + +#define PHYS_FLASH_1 0x38000000 /* Flash Bank #1 */ +#define PHYS_FLASH_SIZE 0x00800000 /* 8 MB */ + +#define CFG_FLASH_BASE PHYS_FLASH_1 + +/*----------------------------------------------------------------------- + * FLASH and environment organization + */ +#define CFG_MAX_FLASH_BANKS 1 /* max number of memory banks */ +#define CFG_MAX_FLASH_SECT 64 /* max number of sectors on one chip */ + +/* timeout values are in ticks */ +#define CFG_FLASH_ERASE_TOUT (2*CFG_HZ) /* Timeout for Flash Erase */ +#define CFG_FLASH_WRITE_TOUT (2*CFG_HZ) /* Timeout for Flash Write */ + +#define CFG_ENV_IS_IN_FLASH 1 +#define CFG_ENV_ADDR (PHYS_FLASH_1 + 0x7a0000) /* Addr of Environment Sector */ +#define CFG_ENV_SIZE 0x4000 /* Total Size of Environment Sector */ + + +/*----------------------------------------------------------------------- + * Device drivers + */ +#define CONFIG_NET_MULTI /* Multi ethernet cards support */ +#define CONFIG_PCNET +#define CONFIG_PCNET_79C973 +#define CONFIG_PCNET_79C975 +#define PCNET_HAS_PROM 1 +/************************************************************ + * IDE/ATA stuff + ************************************************************/ +#define CFG_IDE_MAXBUS 2 /* max. 2 IDE busses */ +#define CFG_IDE_MAXDEVICE (CFG_IDE_MAXBUS*2) /* max. 2 drives per IDE bus */ + +#define CFG_ATA_IDE0_OFFSET 0x01F0 /* ide0 offste */ +#define CFG_ATA_IDE1_OFFSET 0x0170 /* ide1 offset */ +#define CFG_ATA_DATA_OFFSET 0 /* data reg offset */ +#define CFG_ATA_REG_OFFSET 0 /* reg offset */ +#define CFG_ATA_ALT_OFFSET 0x200 /* alternate register offset */ + +#undef CONFIG_IDE_8xx_DIRECT /* no pcmcia interface required */ +#undef CONFIG_IDE_LED /* no led for ide supported */ +#undef CONFIG_IDE_RESET /* reset for ide unsupported... */ +#undef CONFIG_IDE_RESET_ROUTINE /* no special reset function */ + +/************************************************************ + * ATAPI support (experimental) + ************************************************************/ +#define CONFIG_ATAPI /* enable ATAPI Support */ + +/************************************************************ + * DISK Partition support + ************************************************************/ +#define CONFIG_DOS_PARTITION +#define CONFIG_MAC_PARTITION +#define CONFIG_ISO_PARTITION /* Experimental */ + +/************************************************************ + * Keyboard support + ************************************************************/ +#define CONFIG_ISA_KEYBOARD + +#if 0 +/************************************************************ + * Video support + ************************************************************/ +#define CONFIG_VIDEO /*To enable video controller support */ +#define CONFIG_VIDEO_CT69000 +#define CONFIG_CFB_CONSOLE +#define CONFIG_VIDEO_LOGO +#define CONFIG_CONSOLE_EXTRA_INFO +#define CONFIG_VGA_AS_SINGLE_DEVICE +#define CONFIG_VIDEO_SW_CURSOR +#define CONFIG_VIDEO_ONBOARD /* Video controller is on-board */ +#endif + +/************************************************************ + * RTC + ***********************************************************/ +#define CONFIG_RTC_MC146818 +#undef CONFIG_WATCHDOG /* watchdog disabled */ + +/* + * PCI stuff + */ +#define CONFIG_PCI /* include pci support */ +#define CONFIG_PCI_PNP /* pci plug-and-play */ +#define CONFIG_PCI_SCAN_SHOW + +#endif /* __CONFIG_H */ diff --git a/include/fdc.h b/include/fdc.h new file mode 100644 index 0000000000..7892b0e25e --- /dev/null +++ b/include/fdc.h @@ -0,0 +1,41 @@ +/* + * (C) Copyright 2002 + * Stäubli Faverges - <www.staubli.com> + * Pierre AUBERT p.aubert@staubli.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef _FDC_H_ +#define _FDC_H_ + + + +/* Functions prototype */ +int fdc_fdos_init (int drive); +int fdc_fdos_seek (int where); +int fdc_fdos_read (void *buffer, int len); + +int dos_open(char *name); +int dos_read (ulong addr); +int dos_dir (void); + + + +#endif diff --git a/include/linux/stat.h b/include/linux/stat.h index 9fd32062d6..13899c97c7 100644 --- a/include/linux/stat.h +++ b/include/linux/stat.h @@ -67,7 +67,7 @@ struct stat { #endif /* __PPC__ */ -#ifdef __ARM__ +#if defined (__ARM__) || defined (__I386__) struct stat { unsigned short st_dev; diff --git a/lib_i386/Makefile b/lib_i386/Makefile new file mode 100644 index 0000000000..34994e5446 --- /dev/null +++ b/lib_i386/Makefile @@ -0,0 +1,45 @@ +# +# (C) Copyright 2002 +# 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 +# + +include $(TOPDIR)/config.mk + +LIB = lib$(ARCH).a + +AOBJS = bios.o realmode_switch.o ic/sc520_asm.o + +COBJS = board.o bios_setup.o i386_linux.o zimage.o realmode.o \ + pci_type1.o ic/sc520.o ic/ali512x.o + +OBJS = $(AOBJS) $(COBJS) + +$(LIB): .depend $(OBJS) + $(AR) crv $@ $(OBJS) + +######################################################################### + +.depend: Makefile $(AOBJS:.o=.S) $(COBJS:.o=.c) + $(CC) -M $(CFLAGS) $(AOBJS:.o=.S) $(COBJS:.o=.c) > $@ + +sinclude .depend + +######################################################################### diff --git a/lib_i386/bios.S b/lib_i386/bios.S new file mode 100644 index 0000000000..2f5ea8cda9 --- /dev/null +++ b/lib_i386/bios.S @@ -0,0 +1,443 @@ +/* + * (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 msbios.c from rolo 1.6: + *---------------------------------------------------------------------- + * (C) Copyright 2000 + * Sysgo Real-Time Solutions GmbH + * Klein-Winternheim, Germany + *---------------------------------------------------------------------- + */ + +/* + * During it's initialization phase, before switching to protected + * mode, the Linux Kernel makes a few BIOS calls. This won't work + * if the board does not have a BIOS. + * + * This is a very minimalisic BIOS that supplies just enough + * functionality to keep the Linux Kernel happy. It is NOT + * 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 + +.globl rm_int00 +rm_int00: + pushw $0 + jmp any_interrupt16 +.globl rm_int01 +rm_int01: + pushw $1 + jmp any_interrupt16 +.globl rm_int02 +rm_int02: + pushw $2 + jmp any_interrupt16 +.globl rm_int03 +rm_int03: + pushw $3 + jmp any_interrupt16 +.globl rm_int04 +rm_int04: + pushw $4 + jmp any_interrupt16 +.globl rm_int05 +rm_int05: + pushw $5 + jmp any_interrupt16 +.globl rm_int06 +rm_int06: + pushw $6 + jmp any_interrupt16 +.globl rm_int07 +rm_int07: + pushw $7 + jmp any_interrupt16 +.globl rm_int08 +rm_int08: + pushw $8 + jmp any_interrupt16 +.globl rm_int09 +rm_int09: + pushw $9 + jmp any_interrupt16 +.globl rm_int0a +rm_int0a: + pushw $10 + jmp any_interrupt16 +.globl rm_int0b +rm_int0b: + pushw $11 + jmp any_interrupt16 +.globl rm_int0c +rm_int0c: + pushw $12 + jmp any_interrupt16 +.globl rm_int0d +rm_int0d: + pushw $13 + jmp any_interrupt16 +.globl rm_int0e +rm_int0e: + pushw $14 + jmp any_interrupt16 +.globl rm_int0f +rm_int0f: + pushw $15 + jmp any_interrupt16 +.globl rm_int10 +rm_int10: + pushw $16 + jmp any_interrupt16 +.globl rm_int11 +rm_int11: + pushw $17 + jmp any_interrupt16 +.globl rm_int12 +rm_int12: + pushw $18 + jmp any_interrupt16 +.globl rm_int13 +rm_int13: + pushw $19 + jmp any_interrupt16 +.globl rm_int14 +rm_int14: + pushw $20 + jmp any_interrupt16 +.globl rm_int15 +rm_int15: + pushw $21 + jmp any_interrupt16 +.globl rm_int16 +rm_int16: + pushw $22 + jmp any_interrupt16 +.globl rm_int17 +rm_int17: + pushw $23 + jmp any_interrupt16 +.globl rm_int18 +rm_int18: + pushw $24 + jmp any_interrupt16 +.globl rm_int19 +rm_int19: + pushw $25 + jmp any_interrupt16 +.globl rm_int1a +rm_int1a: + pushw $26 + jmp any_interrupt16 +.globl rm_int1b +rm_int1b: + pushw $27 + jmp any_interrupt16 +.globl rm_int1c +rm_int1c: + pushw $28 + jmp any_interrupt16 +.globl rm_int1d +rm_int1d: + pushw $29 + jmp any_interrupt16 +.globl rm_int1e +rm_int1e: + pushw $30 + jmp any_interrupt16 +.globl rm_int1f +rm_int1f: + pushw $31 + jmp any_interrupt16 +.globl rm_def_int +rm_def_int: + iret + + + /* + * All interrupt jumptable entries jump to here + * after pushing the interrupt vector number onto the + * 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 */ + +gs movw OFFS_VECTOR(%bp), %ax + cmpw $0x10, %ax + je Lint_10h + cmpw $0x11, %ax + je Lint_11h + cmpw $0x13, %ax + je Lint_13h + cmpw $0x15, %ax + je Lint_15h + cmpw $0x16, %ax + je Lint_16h + movw $0xffff, %ax + jmp Lout +Lint_10h: /* VGA BIOS services */ + call bios_10h + jmp Lout +Lint_11h: + call bios_11h + jmp Lout +Lint_13h: /* BIOS disk services */ + call bios_13h + jmp Lout +Lint_15h: /* Misc. BIOS services */ + call bios_15h + jmp Lout +Lint_16h: /* keyboard services */ + call bios_16h + jmp Lout +Lout: + cmpw $0, %ax + je Lhandeled + + /* Insert code for unhandeled INTs here. + * + * ROLO prints a message to the console + * (we could do that but then we're in 16bit mode + * so we'll have to get back into 32bit mode + * to use the console I/O routines (if we do this + * 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 */ + addw $2,%sp /* dump vector number */ + iret /* return from interrupt */ + + +/* + ************************************************************ + * BIOS interrupt 10h -- VGA services + ************************************************************ + */ +bios_10h: +gs movw OFFS_AX(%bp), %ax + shrw $8, %ax + cmpw $0x3, %ax + je Lcur_pos + cmpw $0xf, %ax + je Lvid_state + cmpw $0x12, %ax + je Lvid_cfg + movw $0xffff, %ax + ret +Lcur_pos: /* Read Cursor Position and Size */ +gs movw $0, OFFS_CX(%bp) +gs movw $0, OFFS_DX(%bp) + xorw %ax, %ax + ret +Lvid_state: /* Get Video State */ +gs movw $(80 << 8|0x03), OFFS_AX(%bp) /* 80 columns, 80x25, 16 colors */ +gs movw $0, OFFS_BX(%bp) + xorw %ax, %ax + ret +Lvid_cfg: /* Video Subsystem Configuration (EGA/VGA) */ +gs movw $0x10, OFFS_BX(%bp) /* indicate CGA/MDA/HGA */ + xorw %ax, %ax + ret + + +/* + ************************************************************ + * BIOS interrupt 11h -- Equipment determination + ************************************************************ + */ + +bios_11h: + movw bios_equipment, %ax +gs movw %ax, OFFS_AX(%bp) + xorw %ax, %ax + ret + + +/* + ************************************************************ + * BIOS interrupt 13h -- Disk services + ************************************************************ + */ +bios_13h: +gs movw OFFS_AX(%bp), %ax + shrw $8, %ax + cmpw $0x15, %ax + je Lfunc_15h + movw $0xffff, %ax + ret +Lfunc_15h: +gs movw OFFS_AX(%bp), %ax + andw $0xff, %ax /* return AH=0->drive not present */ +gs movw %ax, OFFS_AX(%bp) + xorw %ax, %ax + ret + + + +/* + *********************************************************** + * BIOS interrupt 15h -- Miscellaneous services + *********************************************************** + */ +bios_15h: +gs movw OFFS_AX(%bp), %ax + shrw $8, %ax + cmpw $0xc0, %ax + je Lfunc_c0h + cmpw $0xe8, %ax + je Lfunc_e8h + cmpw $0x88, %ax + je Lfunc_88h + movw $0xffff, %ax + ret + +Lfunc_c0h: /* Return System Configuration Parameters (PS2 only) */ +gs movw OFFS_FLAGS(%bp), %ax + orw $1, %ax /* return carry -- function not supported */ +gs movw %ax, OFFS_FLAGS(%bp) + xorw %ax, %ax + ret + +Lfunc_e8h: +gs movw OFFS_AX(%bp), %ax + andw $0xff, %ax + cmpw $1, %ax + je Lfunc_e801h +gs movw OFFS_FLAGS(%bp), %ax + orw $1, %ax /* return carry -- function not supported */ +gs movw %ax, OFFS_FLAGS(%bp) + xorw %ax, %ax + 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 */ +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 OFFS_FLAGS(%bp), %ax + andw $0xfffe, %ax /* clear carry -- function succeeded */ +gs movw %ax, OFFS_FLAGS(%bp) + xorw %ax, %ax + ret + +Lmore_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_CX(%bp) +gs movw %ax, OFFS_BX(%bp) /* set BX and DX to number of 64kb chunks - 256 */ +gs movw %ax, 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 + +Lfunc_88h: + movw ram_in_64kb_chunks, %ax + subw $16, %ax + shlw $6, %ax + +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 16h -- keyboard services + ************************************************************ + */ +bios_16h: +gs movw OFFS_AX(%bp), %ax + shrw $8, %ax + cmpw $0x03, %ax + je Lfunc_03h + movw $0xffff, %ax + ret +Lfunc_03h: + xorw %ax, %ax /* do nothing -- function not supported */ + ret + + +.globl ram_in_64kb_chunks +ram_in_64kb_chunks: + .word 0 + +.globl bios_equipment +bios_equipment: + .word 0 + diff --git a/lib_i386/bios_setup.c b/lib_i386/bios_setup.c new file mode 100644 index 0000000000..94319afc58 --- /dev/null +++ b/lib_i386/bios_setup.c @@ -0,0 +1,178 @@ +/* + * (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 + */ + + +/* + * Partly based on msbios.c from rolo 1.6: + *---------------------------------------------------------------------- + * (C) Copyright 2000 + * Sysgo Real-Time Solutions GmbH + * Klein-Winternheim, Germany + *---------------------------------------------------------------------- + */ + +#include <common.h> +#include <asm/realmode.h> +#include <asm/io.h> + +#define NUMVECTS 256 + +#define BIOS_DATA ((char*)0x400) +#define BIOS_DATA_SIZE 256 +#define BIOS_BASE ((char*)0xf0000) +#define BIOS_CS 0xf000 + +extern u16 ram_in_64kb_chunks; +extern u16 bios_equipment; +extern void *rm_int00; +extern void *rm_int01; +extern void *rm_int02; +extern void *rm_int03; +extern void *rm_int04; +extern void *rm_int05; +extern void *rm_int06; +extern void *rm_int07; +extern void *rm_int08; +extern void *rm_int09; +extern void *rm_int0a; +extern void *rm_int0b; +extern void *rm_int0c; +extern void *rm_int0d; +extern void *rm_int0e; +extern void *rm_int0f; +extern void *rm_int10; +extern void *rm_int11; +extern void *rm_int12; +extern void *rm_int13; +extern void *rm_int14; +extern void *rm_int15; +extern void *rm_int16; +extern void *rm_int17; +extern void *rm_int18; +extern void *rm_int19; +extern void *rm_int1a; +extern void *rm_int1b; +extern void *rm_int1c; +extern void *rm_int1d; +extern void *rm_int1e; +extern void *rm_int1f; +extern void *rm_def_int; + +/* + ************************************************************ + * Install an interrupt vector + ************************************************************ + */ + +static void setvector(int vector, u16 segment, void *handler) +{ + u16 *ptr = (u16*)(vector*4); + ptr[0] = ((u32)handler - (segment << 4))&0xffff; + ptr[1] = segment; + +#if 0 + printf("setvector: int%02x -> %04x:%04x\n", + vector, ptr[1], ptr[0]); +#endif +} + +int bios_setup(void) +{ + DECLARE_GLOBAL_DATA_PTR; + static int done=0; + int vector; + + if (done) { + return 0; + } + done = 1; + + if (i386boot_bios_size > 65536) { + printf("BIOS too large (%ld bytes, max is 65536)\n", + i386boot_bios_size); + return -1; + } + + memcpy(BIOS_BASE, (void*)i386boot_bios, i386boot_bios_size); + + /* clear bda */ + memset(BIOS_DATA, 0, BIOS_DATA_SIZE); + + /* enter some values to the bda */ + writew(0x3f8, BIOS_DATA); /* com1 addr */ + writew(0x2f8, BIOS_DATA+2); /* com2 addr */ + writew(0x3e8, BIOS_DATA+4); /* com3 addr */ + writew(0x2e8, BIOS_DATA+6); /* com4 addr */ + writew(0x278, BIOS_DATA+8); /* lpt1 addr */ + /* + * The kernel wants to read the base memory size + * from 40:13. Put a zero there to avoid an error message + */ + writew(0, BIOS_DATA+0x13); /* base memory size */ + + + /* setup realmode interrupt vectors */ + for (vector = 0; vector < NUMVECTS; vector++) { + setvector(vector, BIOS_CS, &rm_def_int); + } + + setvector(0x00, BIOS_CS, &rm_int00); + setvector(0x01, BIOS_CS, &rm_int01); + setvector(0x02, BIOS_CS, &rm_int02); + setvector(0x03, BIOS_CS, &rm_int03); + setvector(0x04, BIOS_CS, &rm_int04); + setvector(0x05, BIOS_CS, &rm_int05); + setvector(0x06, BIOS_CS, &rm_int06); + setvector(0x07, BIOS_CS, &rm_int07); + setvector(0x08, BIOS_CS, &rm_int08); + setvector(0x09, BIOS_CS, &rm_int09); + setvector(0x0a, BIOS_CS, &rm_int0a); + setvector(0x0b, BIOS_CS, &rm_int0b); + setvector(0x0c, BIOS_CS, &rm_int0c); + setvector(0x0d, BIOS_CS, &rm_int0d); + setvector(0x0e, BIOS_CS, &rm_int0e); + setvector(0x0f, BIOS_CS, &rm_int0f); + setvector(0x10, BIOS_CS, &rm_int10); + setvector(0x11, BIOS_CS, &rm_int11); + setvector(0x12, BIOS_CS, &rm_int12); + setvector(0x13, BIOS_CS, &rm_int13); + setvector(0x14, BIOS_CS, &rm_int14); + setvector(0x15, BIOS_CS, &rm_int15); + setvector(0x16, BIOS_CS, &rm_int16); + setvector(0x17, BIOS_CS, &rm_int17); + setvector(0x18, BIOS_CS, &rm_int18); + setvector(0x19, BIOS_CS, &rm_int19); + setvector(0x1a, BIOS_CS, &rm_int1a); + setvector(0x1b, BIOS_CS, &rm_int1b); + setvector(0x1c, BIOS_CS, &rm_int1c); + setvector(0x1d, BIOS_CS, &rm_int1d); + setvector(0x1e, BIOS_CS, &rm_int1e); + setvector(0x1f, BIOS_CS, &rm_int1f); + + /* fill in data area */ + ram_in_64kb_chunks = gd->ram_size >> 16; + bios_equipment = 0; /* FixMe */ + + return 0; +} + diff --git a/lib_i386/board.c b/lib_i386/board.c new file mode 100644 index 0000000000..193860a87a --- /dev/null +++ b/lib_i386/board.c @@ -0,0 +1,448 @@ +/* + * (C) Copyright 2002 + * Daniel Engström, Omicron Ceti AB, daniel@omicron.se + * + * (C) Copyright 2002 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Marius Groeger <mgroeger@sysgo.de> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <watchdog.h> +#include <command.h> +#include <devices.h> +#include <version.h> +#include <malloc.h> +#include <syscall.h> +#include <net.h> +#include <ide.h> + +extern long _i386boot_start; +extern long _i386boot_end; +extern long _i386boot_romdata_start; +extern long _i386boot_romdata_dest; +extern long _i386boot_romdata_size; +extern long _i386boot_bss_start; +extern long _i386boot_bss_size; + +extern long _i386boot_realmode; +extern long _i386boot_realmode_size; +extern long _i386boot_bios; +extern long _i386boot_bios_size; + +/* The symbols defined by the linker script becomes pointers + * which is somewhat inconveient ... */ +ulong i386boot_start = (ulong)&_i386boot_start; /* code start (in flash) defined in start.S */ +ulong i386boot_end = (ulong)&_i386boot_end; /* code end (in flash) */ +ulong i386boot_romdata_start = (ulong)&_i386boot_romdata_start; /* datasegment in flash (also code+rodata end) */ +ulong i386boot_romdata_dest = (ulong)&_i386boot_romdata_dest; /* data location segment in ram */ +ulong i386boot_romdata_size = (ulong)&_i386boot_romdata_size; /* size of data segment */ +ulong i386boot_bss_start = (ulong)&_i386boot_bss_start; /* bss start */ +ulong i386boot_bss_size = (ulong)&_i386boot_bss_size; /* bss size */ + +ulong i386boot_realmode = (ulong)&_i386boot_realmode; /* start of realmode entry code */ +ulong i386boot_realmode_size = (ulong)&_i386boot_realmode_size; /* size of realmode entry code */ +ulong i386boot_bios = (ulong)&_i386boot_bios; /* start of BIOS emulation code */ +ulong i386boot_bios_size = (ulong)&_i386boot_bios_size; /* size of BIOS emulation code */ + + +const char version_string[] = + U_BOOT_VERSION" (" __DATE__ " - " __TIME__ ")"; + + +/* + * Begin and End of memory area for malloc(), and current "brk" + */ +static ulong mem_malloc_start = 0; +static ulong mem_malloc_end = 0; +static ulong mem_malloc_brk = 0; + +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; +} + +void *sbrk (ptrdiff_t increment) +{ + ulong old = mem_malloc_brk; + ulong new = old + increment; + + if ((new < mem_malloc_start) || (new > mem_malloc_end)) { + return (NULL); + } + mem_malloc_brk = new; + + return ((void *) old); +} + +char *strmhz (char *buf, long hz) +{ + long l, n; + long m; + + n = hz / 1000000L; + l = sprintf (buf, "%ld", n); + m = (hz % 1000000L) / 1000L; + if (m != 0) + sprintf (buf + l, ".%03ld", m); + return (buf); +} + +/************************************************************************ + * Init Utilities * + ************************************************************************ + * Some of this code should be moved into the core functions, + * or dropped completely, + * but let's get it working (again) first... + */ +static void syscalls_init (void) +{ + syscall_tbl[SYSCALL_MALLOC] = (void *) malloc; + syscall_tbl[SYSCALL_FREE] = (void *) free; + + syscall_tbl[SYSCALL_INSTALL_HDLR] = (void *) irq_install_handler; + syscall_tbl[SYSCALL_FREE_HDLR] = (void *) irq_free_handler; + +} + +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)); + + gd->baudrate = (i > 0) + ? (int) simple_strtoul (tmp, NULL, 10) + : CONFIG_BAUDRATE; + + return (0); +} + +static int display_banner (void) +{ + + printf ("\n\n%s\n\n", version_string); + printf ("U-Boot code: %08lX -> %08lX data: %08lX -> %08lX\n" + " BSS: %08lX -> %08lX stack: %08lX -> %08lX\n", + i386boot_start, i386boot_romdata_start-1, + i386boot_romdata_dest, i386boot_romdata_dest+i386boot_romdata_size-1, + i386boot_bss_start, i386boot_bss_start+i386boot_bss_size-1, + i386boot_bss_start+i386boot_bss_size, + i386boot_bss_start+i386boot_bss_size+CFG_STACK_SIZE-1); + + + return (0); +} + +/* + * WARNING: this code looks "cleaner" than the PowerPC version, but + * has the disadvantage that you either get nothing, or everything. + * On PowerPC, you might see "DRAM: " before the system hangs - which + * gives a simple yet clear indication which part of the + * initialization if failing. + */ +static int display_dram_config (void) +{ + DECLARE_GLOBAL_DATA_PTR; + int i; + + puts ("DRAM Configuration:\n"); + + for (i=0; i<CONFIG_NR_DRAM_BANKS; i++) { + printf ("Bank #%d: %08lx ", i, gd->bd->bi_dram[i].start); + print_size (gd->bd->bi_dram[i].size, "\n"); + } + + return (0); +} + +static void display_flash_config (ulong size) +{ + puts ("Flash: "); + print_size (size, "\n"); +} + + + +/* + * Breath some life into the board... + * + * Initialize an SMC for serial comms, and carry out some hardware + * tests. + * + * The first part of initialization is running from Flash memory; + * its main purpose is to initialize the RAM so that we + * can relocate the monitor code to RAM. + */ + +/* + * All attempts to come up with a "common" initialization sequence + * that works for all boards and architectures failed: some of the + * requirements are just _too_ different. To get rid of the resulting + * mess of board dependend #ifdef'ed code we now make the whole + * initialization sequence configurable to the user. + * + * The requirements for any new initalization function is simple: it + * receives a pointer to the "global data" structure as it's only + * argument, and returns an integer return code, where 0 means + * "continue" and != 0 means "fatal error, hang the system". + */ +typedef int (init_fnc_t) (void); + +init_fnc_t *init_sequence[] = { + cpu_init, /* basic cpu dependent setup */ + board_init, /* basic board dependent setup */ + dram_init, /* configure available RAM banks */ + mem_malloc_init, /* dependant on dram_init */ + interrupt_init, /* set up exceptions */ + timer_init, + env_init, /* initialize environment */ + init_baudrate, /* initialze baudrate settings */ + serial_init, /* serial communications setup */ + display_banner, + display_dram_config, + + NULL, +}; + +gd_t *global_data; + +void start_i386boot (void) +{ + DECLARE_GLOBAL_DATA_PTR; + char *s; + int i; + ulong size; + static gd_t gd_data; + static bd_t bd_data; + init_fnc_t **init_fnc_ptr; + + show_boot_progress(0x21); + + gd = global_data = &gd_data; + + memset (gd, 0, sizeof (gd_t)); + gd->bd = &bd_data; + memset (gd->bd, 0, sizeof (bd_t)); + show_boot_progress(0x22); + + + for (init_fnc_ptr = init_sequence, i=0; *init_fnc_ptr; ++init_fnc_ptr, i++) { + show_boot_progress(0xa130|i); + + if ((*init_fnc_ptr)() != 0) { + hang (); + } + } + show_boot_progress(0x23); + + /* configure available FLASH banks */ + size = flash_init(); + display_flash_config(size); + show_boot_progress(0x24); + + show_boot_progress(0x25); + + /* initialize environment */ + env_relocate (); + show_boot_progress(0x26); + + + /* IP Address */ + bd_data.bi_ip_addr = getenv_IPaddr ("ipaddr"); + + /* MAC Address */ + { + int i; + ulong reg; + char *s, *e; + uchar tmp[64]; + + i = getenv_r ("ethaddr", tmp, sizeof (tmp)); + s = (i > 0) ? tmp : NULL; + + for (reg = 0; reg < 6; ++reg) { + bd_data.bi_enetaddr[reg] = s ? simple_strtoul (s, &e, 16) : 0; + if (s) + s = (*e) ? e + 1 : e; + } + } + +#if defined(CONFIG_PCI) + /* + * Do pci configuration + */ + pci_init(); +#endif + + show_boot_progress(0x27); + + + devices_init (); + + /* allocate syscalls table (console_init_r will fill it in */ + syscall_tbl = (void **) malloc (NR_SYSCALLS * sizeof (void *)); + + /* Initialize the console (after the relocation and devices init) */ + console_init_r(); + syscalls_init(); + +#ifdef CONFIG_MISC_INIT_R + /* miscellaneous platform dependent initialisations */ + misc_init_r(); +#endif + + +#if (CONFIG_COMMANDS & CFG_CMD_NET) && (0) + WATCHDOG_RESET(); +# ifdef DEBUG + puts ("Reset Ethernet PHY\n"); +# endif + reset_phy(); +#endif + +#if (CONFIG_COMMANDS & CFG_CMD_PCMCIA) && !(CONFIG_COMMANDS & CFG_CMD_IDE) + WATCHDOG_RESET(); + puts ("PCMCIA:"); + pcmcia_init(); +#endif + +#if (CONFIG_COMMANDS & CFG_CMD_KGDB) + WATCHDOG_RESET(); + puts("KGDB: "); + kgdb_init(); +#endif + + /* enable exceptions */ + enable_interrupts (); + show_boot_progress(0x28); + + /* Must happen after interrupts are initialized since + * an irq handler gets installed + */ +#ifdef CONFIG_SERIAL_SOFTWARE_FIFO + serial_buffered_init(); +#endif + +#ifdef CONFIG_STATUS_LED + status_led_set (STATUS_LED_BOOT, STATUS_LED_BLINKING); +#endif + + udelay (20); + + set_timer (0); + + /* Initialize from environment */ + if ((s = getenv ("loadaddr")) != NULL) { + load_addr = simple_strtoul (s, NULL, 16); + } +#if (CONFIG_COMMANDS & CFG_CMD_NET) + if ((s = getenv ("bootfile")) != NULL) { + copy_filename (BootFile, s, sizeof (BootFile)); + } +#endif /* CFG_CMD_NET */ + + WATCHDOG_RESET(); + +#if (CONFIG_COMMANDS & CFG_CMD_IDE) + WATCHDOG_RESET(); + puts("IDE: "); + ide_init(); +#endif /* CFG_CMD_IDE */ + +#if (CONFIG_COMMANDS & CFG_CMD_SCSI) + WATCHDOG_RESET(); + puts("SCSI: "); + scsi_init(); +#endif + +#if (CONFIG_COMMANDS & CFG_CMD_DOC) + WATCHDOG_RESET(); + puts ("DOC: "); + doc_init(); +#endif + +#if (CONFIG_COMMANDS & CFG_CMD_NET) && defined(CONFIG_NET_MULTI) + WATCHDOG_RESET(); + puts("Net: "); + eth_initialize(gd->bd); +#endif + +#ifdef CONFIG_LAST_STAGE_INIT + WATCHDOG_RESET(); + /* + * Some parts can be only initialized if all others (like + * Interrupts) are up and running (i.e. the PC-style ISA + * keyboard). + */ + last_stage_init(); +#endif + + + +#ifdef CONFIG_POST + post_run (NULL, POST_RAM | post_bootmode_get(0)); + if (post_bootmode_get(0) & POST_POWERFAIL) { + post_bootmode_clear(); + board_poweroff(); + } +#endif + + show_boot_progress(0x29); + + /* main_loop() can return to retry autoboot, if so just run it again. */ + for (;;) { + main_loop (); + } + + /* NOTREACHED - no way out of command loop except booting */ +} + +void hang (void) +{ + puts ("### ERROR ### Please RESET the board ###\n"); + for (;;); +} + + diff --git a/lib_i386/i386_linux.c b/lib_i386/i386_linux.c new file mode 100644 index 0000000000..c37a0d8ee6 --- /dev/null +++ b/lib_i386/i386_linux.c @@ -0,0 +1,174 @@ +/* + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Marius Groeger <mgroeger@sysgo.de> + * + * Copyright (C) 2001 Erik Mouw (J.A.K.Mouw@its.tudelft.nl) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include <common.h> +#include <command.h> +#include <cmd_boot.h> +#include <image.h> +#include <zlib.h> +#include <asm/byteorder.h> +#include <asm/zimage.h> + + +extern image_header_t header; /* from cmd_bootm.c */ + + +image_header_t *fake_header(image_header_t *hdr, void *ptr, int size) +{ + /* try each supported image type in order */ + if (NULL != fake_zimage_header(hdr, ptr, size)) { + return hdr; + } + + return NULL; +} + + +void do_bootm_linux(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[], + ulong addr, ulong *len_ptr, int verify) +{ + ulong base_ptr; + + ulong len = 0, checksum; + ulong initrd_start, initrd_end; + ulong data; + image_header_t *hdr = &header; + + /* + * Check if there is an initrd image + */ + if (argc >= 3) { + addr = simple_strtoul(argv[2], NULL, 16); + + printf ("## Loading Ramdisk Image at %08lx ...\n", addr); + + /* Copy header so we can blank CRC field for re-calculation */ + memcpy (&header, (char *)addr, sizeof(image_header_t)); + + if (ntohl(hdr->ih_magic) != IH_MAGIC) { + printf ("Bad Magic Number\n"); + do_reset (cmdtp, flag, argc, argv); + } + + data = (ulong)&header; + len = sizeof(image_header_t); + + checksum = ntohl(hdr->ih_hcrc); + hdr->ih_hcrc = 0; + + if (crc32 (0, (char *)data, len) != checksum) { + printf ("Bad Header Checksum\n"); + do_reset (cmdtp, flag, argc, argv); + } + + print_image_hdr (hdr); + + data = addr + sizeof(image_header_t); + len = ntohl(hdr->ih_size); + + if (verify) { + ulong csum = 0; + + printf (" Verifying Checksum ... "); + csum = crc32 (0, (char *)data, len); + if (csum != ntohl(hdr->ih_dcrc)) { + printf ("Bad Data CRC\n"); + do_reset (cmdtp, flag, argc, argv); + } + printf ("OK\n"); + } + + if ((hdr->ih_os != IH_OS_LINUX) || + (hdr->ih_arch != IH_CPU_I386) || + (hdr->ih_type != IH_TYPE_RAMDISK) ) { + printf ("No Linux i386 Ramdisk Image\n"); + do_reset (cmdtp, flag, argc, argv); + } + + /* + * Now check if we have a multifile image + */ + } else if ((hdr->ih_type==IH_TYPE_MULTI) && (len_ptr[1])) { + ulong tail = ntohl(len_ptr[0]) % 4; + int i; + + /* skip kernel length and terminator */ + data = (ulong)(&len_ptr[2]); + /* skip any additional image length fields */ + for (i=1; len_ptr[i]; ++i) + data += 4; + /* add kernel length, and align */ + data += ntohl(len_ptr[0]); + if (tail) { + data += 4 - tail; + } + + len = ntohl(len_ptr[1]); + + } else { + /* + * no initrd image + */ + data = 0; + } + +#ifdef DEBUG + if (!data) { + printf ("No initrd\n"); + } +#endif + + if (data) { + initrd_start = data; + initrd_end = initrd_start + len; + printf (" Loading Ramdisk to %08lx, end %08lx ... ", + initrd_start, initrd_end); + memmove ((void *)initrd_start, (void *)data, len); + printf ("OK\n"); + } else { + initrd_start = 0; + initrd_end = 0; + } + + base_ptr = load_zimage(addr + sizeof(image_header_t), ntohl(hdr->ih_size), + initrd_start, initrd_end-initrd_start, 0); + + if (NULL == base_ptr) { + printf ("## Kernel loading failed ...\n"); + do_reset(cmdtp, flag, argc, argv); + + } + +#ifdef DEBUG + printf ("## Transferring control to Linux (at address %08x) ...\n", + (u32)base_ptr); +#endif + + /* we assume that the kernel is in place */ + printf("\nStarting kernel ...\n\n"); + + boot_zimage(base_ptr); + +} + + diff --git a/lib_i386/ic/ali512x.c b/lib_i386/ic/ali512x.c new file mode 100644 index 0000000000..4537095dbe --- /dev/null +++ b/lib_i386/ic/ali512x.c @@ -0,0 +1,442 @@ +/* + * (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 new file mode 100644 index 0000000000..d202625bb5 --- /dev/null +++ b/lib_i386/ic/sc520.c @@ -0,0 +1,348 @@ +/* + * (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 new file mode 100644 index 0000000000..72110c4a0a --- /dev/null +++ b/lib_i386/ic/sc520_asm.S @@ -0,0 +1,530 @@ +/* + * (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_type1.c b/lib_i386/pci_type1.c new file mode 100644 index 0000000000..e5577e8206 --- /dev/null +++ b/lib_i386/pci_type1.c @@ -0,0 +1,57 @@ +/* + * Support for type PCI configuration cycles. + * based on pci_indirect.c + * + * Copyright (C) 2002 Daniel Engström, Omicron Ceti AB, daniel@omicron.se. + * + * 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. + */ + +#include <common.h> + +#ifdef CONFIG_PCI + +#include <asm/processor.h> +#include <asm/io.h> +#include <pci.h> + +#define cfg_read(val, addr, type, op) *val = op((type)(addr)) +#define cfg_write(val, addr, type, op) op((val), (type *)(addr)) + +#define TYPE1_PCI_OP(rw, size, type, op, mask) \ +static int \ +type1_##rw##_config_##size(struct pci_controller *hose, \ + pci_dev_t dev, int offset, type val) \ +{ \ + outl(dev | (offset & 0xfc) | 0x80000000, hose->cfg_addr); \ + cfg_##rw(val, hose->cfg_data + (offset & mask), type, op); \ + return 0; \ +} + + +TYPE1_PCI_OP(read, byte, u8 *, inb, 3) +TYPE1_PCI_OP(read, word, u16 *, inw, 2) +TYPE1_PCI_OP(read, dword, u32 *, inl, 0) + +TYPE1_PCI_OP(write, byte, u8, outb, 3) +TYPE1_PCI_OP(write, word, u16, outw, 2) +TYPE1_PCI_OP(write, dword, u32, outl, 0) + +void pci_setup_type1(struct pci_controller* hose, u32 cfg_addr, u32 cfg_data) +{ + pci_set_ops(hose, + type1_read_config_byte, + type1_read_config_word, + type1_read_config_dword, + type1_write_config_byte, + type1_write_config_word, + type1_write_config_dword); + + hose->cfg_addr = (unsigned int *) cfg_addr; + hose->cfg_data = (unsigned char *) cfg_data; +} + +#endif diff --git a/lib_i386/realmode.c b/lib_i386/realmode.c new file mode 100644 index 0000000000..372147cf24 --- /dev/null +++ b/lib_i386/realmode.c @@ -0,0 +1,69 @@ +/* + * (C) Copyright 2002 + * Daniel Engström, Omicron Ceti AB, daniel@omicron.se + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/ptrace.h> + + +#define REALMODE_BASE ((char*)0x7c0) +#define REALMODE_MAILBOX ((char*)0xe00) + + +extern char realmode_enter; + + +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; + } + + /* 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, (REALMODE_MAILBOX-REALMODE_BASE)); + return -1; + } + + memcpy(REALMODE_BASE, i386boot_realmode, i386boot_realmode_size); + + + in->eip = off; + in->xcs = seg; + if (3>in->esp & 0xffff) { + printf("Warning: entering realmode with sp < 4 will fail\n"); + } + + memcpy(REALMODE_MAILBOX, in, sizeof(struct pt_regs)); + + __asm__ volatile ( + "lcall $0x20,%0\n" : : "i" (&realmode_enter) ); + + memcpy(out, REALMODE_MAILBOX, sizeof(struct pt_regs)); + + return out->eax; +} + diff --git a/lib_i386/realmode_switch.S b/lib_i386/realmode_switch.S new file mode 100644 index 0000000000..9f212c2e8e --- /dev/null +++ b/lib_i386/realmode_switch.S @@ -0,0 +1,223 @@ +/* + * (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 + */ + + +/* 32bit -> 16bit -> 32bit mode switch code */ + +/* + * Stack frame at 0xe00 + * e00 ebx; + * e04 ecx; + * e08 edx; + * e0c esi; + * e10 edi; + * e14 ebp; + * e18 eax; + * e1c ds; + * e20 es; + * e24 fs; + * e28 gs; + * e2c orig_eax; + * e30 eip; + * e34 cs; + * e38 eflags; + * e3c esp; + * e40 ss; + */ + +#define a32 .byte 0x67; /* address size prefix 32 */ +#define o32 .byte 0x66; /* operand size prefix 32 */ + +.section .realmode, "ax" +.code16 + + /* 16bit protected mode code here */ +.globl realmode_enter +realmode_enter: +o32 pusha +o32 pushf + cli + sidt saved_idt + sgdt saved_gdt + movl %esp, %eax + movl %eax, saved_protected_mode_esp + + movl $0x10, %eax + movl %eax, %esp + movw $0x28, %ax + movw %ax, %ds + movw %ax, %es + movw %ax, %fs + movw %ax, %gs + + lidt realmode_idt_ptr + movl %cr0, %eax /* Go back into real mode by */ + andl $0x7ffffffe, %eax /* clearing PE to 0 */ + movl %eax, %cr0 + ljmp $0x0,$do_realmode /* switch to real mode */ + +do_realmode: /* realmode code from here */ + movw %cs,%ax + movw %ax,%ds + movw %ax,%es + movw %ax,%fs + movw %ax,%gs + + /* create a temporary stack */ + + movw $0xc0, %ax + movw %ax, %ss + movw $0x200, %ax + movw %ax, %sp + + popl %ebx + popl %ecx + popl %edx + popl %esi + popl %edi + popl %ebp + popl %eax + movl %eax, temp_eax + popl %eax + movw %ax, %ds + popl %eax + movw %ax, %es + popl %eax + movw %ax, %fs + popl %eax + movw %ax, %gs + popl %eax /* orig_eax */ + popl %eax +cs movw %ax, temp_ip + popl %eax +cs movw %ax, temp_cs +o32 popf + popl %eax + popw %ss + movl %eax, %esp +cs movl temp_eax, %eax + wbinvd /* self-modifying code, + * better flush the cache */ + + .byte 0x9a /* lcall */ +temp_ip: + .word 0 /* new ip */ +temp_cs: + .word 0 /* new cs */ +realmode_ret: + /* save eax, esp and ss */ +cs movl %eax, saved_eax + movl %esp, %eax +cs movl %eax, saved_esp + movw %ss, %ax +cs movw %ax, saved_ss + + /* restore the stack, note that we set sp to 0x244; + * pt_regs is 0x44 bytes long and we push the structure + * backwards on to the stack, bottom first */ + + movw $0xc0, %ax + movw %ax, %ss + movw $0x244, %ax + movw %ax, %sp + + xorl %eax,%eax +cs movw saved_ss, %ax + pushl %eax +cs movl saved_esp, %eax + pushl %eax +o32 pushf + xorl %eax,%eax +cs movw temp_cs, %ax + pushl %eax +cs movw temp_ip, %ax + pushl %eax + pushl $0 + movw %gs, %ax + pushl %eax + movw %fs, %ax + pushl %eax + movw %es, %ax + pushl %eax + movw %ds, %ax + pushl %eax + movl saved_eax, %eax + pushl %eax + pushl %ebp + pushl %edi + pushl %esi + pushl %edx + pushl %ecx + pushl %ebx + +o32 cs lidt saved_idt +o32 cs lgdt saved_gdt /* Set GDTR */ + + movl %cr0, %eax /* Go back into protected mode */ + orl $1,%eax /* reset PE to 1 */ + movl %eax, %cr0 + jmp next_line /* flush prefetch queue */ +next_line: + movw $return_ptr, %ax + movw %ax,%bp +o32 cs ljmp *(%bp) + +.code32 +protected_mode: + movl $0x18,%eax /* reload GDT[3] */ + movw %ax,%fs /* reset FS */ + movw %ax,%ds /* reset DS */ + movw %ax,%gs /* reset GS */ + movw %ax,%es /* reset ES */ + movw %ax,%ss /* reset SS */ + movl saved_protected_mode_esp, %eax + movl %eax, %esp + popf + popa + ret + +temp_eax: + .long 0 + +saved_ss: + .word 0 +saved_esp: + .long 0 +saved_eax: + .long 0 + +realmode_idt_ptr: + .word 0x400 + .word 0x0, 0x0 + +saved_gdt: + .word 0, 0, 0, 0 +saved_idt: + .word 0, 0, 0, 0 + +saved_protected_mode_esp: + .long 0 + +return_ptr: + .long protected_mode + .word 0x10 diff --git a/lib_i386/zimage.c b/lib_i386/zimage.c new file mode 100644 index 0000000000..190d46ef74 --- /dev/null +++ b/lib_i386/zimage.c @@ -0,0 +1,276 @@ +/* + * (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 + */ + +/* + * Linux i386 zImage and bzImage loading + * + * based on the procdure described in + * linux/Documentation/i386/boot.txt + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/ptrace.h> +#include <asm/zimage.h> +#include <asm/realmode.h> +#include <asm/byteorder.h> + +/* + * Memory lay-out: + * + * relative to setup_base (which is 0x90000 currently) + * + * 0x0000-0x7FFF Real mode kernel + * 0x8000-0x8FFF Stack and heap + * 0x9000-0x90FF Kernel command line + */ +#define DEFAULT_SETUP_BASE 0x90000 +#define COMMAND_LINE_OFFSET 0x9000 +#define HEAP_END_OFFSET 0x8e00 + +#define COMMAND_LINE_SIZE 2048 + +static void build_command_line(char *command_line, int auto_boot) +{ + char *env_command_line; + + command_line[0] = '\0'; + + env_command_line = getenv("bootargs"); + + /* set console= argument if we use a serial console */ + if (NULL == strstr(env_command_line, "console=")) { + if (0==strcmp(getenv("stdout"), "serial")) { + + /* We seem to use serial console */ + sprintf(command_line, "console=ttyS0,%s ", + getenv("baudrate")); + } + } + + if (auto_boot) { + strcat(command_line, "auto "); + } + + if (NULL != env_command_line) { + strcat(command_line, env_command_line); + } + + + printf("Kernel command line: \"%s\"\n", command_line); +} + +void *load_zimage(char *image, unsigned long kernel_size, + unsigned long initrd_addr, unsigned long initrd_size, + int auto_boot) +{ + void *setup_base; + int setup_size; + int bootproto; + int big_image; + void *load_address; + + + setup_base = (void*)DEFAULT_SETUP_BASE; /* base address for real-mode segment */ + + if (KERNEL_MAGIC != *(u16*)(image + BOOT_FLAG_OFF)) { + printf("Error: Invalid kernel magic (found 0x%04x, expected 0xaa55)\n", + *(u16*)(image + BOOT_FLAG_OFF)); + return 0; + } + + + /* determine boot protocol version */ + if (KERNEL_V2_MAGIC == *(u32*)(image+HEADER_OFF)) { + bootproto = *(u16*)(image+VERSION_OFF); + } else { + /* Very old kernel */ + bootproto = 0x0100; + } + + /* determine size of setup */ + if (0 == *(u8*)(image + SETUP_SECTS_OFF)) { + setup_size = 5 * 512; + } else { + setup_size = (*(u8*)(image + SETUP_SECTS_OFF) + 1) * 512; + } + + if (setup_size > SETUP_MAX_SIZE) { + printf("Error: Setup is too large (%d bytes)\n", setup_size); + } + + /* Determine image type */ + big_image = (bootproto >= 0x0200) && (*(u8*)(image + LOADFLAGS_OFF) & BIG_KERNEL_FLAG); + + /* Derermine load address */ + load_address = (void*)(big_image ? BZIMAGE_LOAD_ADDR:ZIMAGE_LOAD_ADDR); + + /* load setup */ + memmove(setup_base, image, setup_size); + + printf("Using boot protocol version %x.%02x\n", + (bootproto & 0xff00) >> 8, bootproto & 0xff); + + + if (bootproto == 0x0100) { + + *(u16*)(setup_base + CMD_LINE_MAGIC_OFF) = COMMAND_LINE_MAGIC; + *(u16*)(setup_base + CMD_LINE_OFFSET_OFF) = COMMAND_LINE_OFFSET; + + /* A very old kernel MUST have its real-mode code + * loaded at 0x90000 */ + + if ((u32)setup_base != 0x90000) { + /* Copy the real-mode kernel */ + memmove((void*)0x90000, setup_base, setup_size); + /* Copy the command line */ + memmove((void*)0x99000, setup_base+COMMAND_LINE_OFFSET, + COMMAND_LINE_SIZE); + + setup_base = (void*)0x90000; /* Relocated */ + } + + /* It is recommended to clear memory up to the 32K mark */ + memset((void*)0x90000 + setup_size, 0, SETUP_MAX_SIZE-setup_size); + } + + if (bootproto >= 0x0200) { + *(u8*)(setup_base + TYPE_OF_LOADER_OFF) = 0xff; + printf("Linux kernel version %s\n", + (char*)(setup_base + SETUP_START_OFFSET + + *(u16*)(setup_base + START_SYS_OFF + 2))); + + if (initrd_addr) { + printf("Initial RAM disk at linear address 0x%08lx, size %ld bytes\n", + initrd_addr, initrd_size); + + *(u32*)(setup_base + RAMDISK_IMAGE_OFF) = initrd_addr; + *(u32*)(setup_base + RAMDISK_SIZE_OFF)=initrd_size; + } + } + + if (bootproto >= 0x0201) { + *(u16*)(setup_base + HEAP_END_PTR_OFF) = HEAP_END_OFFSET; + + /* CAN_USE_HEAP */ + *(u8*)(setup_base + LOADFLAGS_OFF) = + *(u8*)(setup_base + LOADFLAGS_OFF) | HEAP_FLAG; + } + + if (bootproto >= 0x0202) { + *(u32*)(setup_base + CMD_LINE_PTR_OFF) = (u32)setup_base + COMMAND_LINE_OFFSET; + } else if (bootproto >= 0x0200) { + *(u16*)(setup_base + CMD_LINE_MAGIC_OFF) = COMMAND_LINE_MAGIC; + *(u16*)(setup_base + CMD_LINE_OFFSET_OFF) = COMMAND_LINE_OFFSET; + *(u16*)(setup_base + SETUP_MOVE_SIZE_OFF) = 0x9100; + } + + + + if (big_image) { + if ((kernel_size - setup_size) > BZIMAGE_MAX_SIZE) { + printf("Error: bzImage kernel too big! (size: %ld, max: %d)\n", + kernel_size - setup_size, BZIMAGE_MAX_SIZE); + return 0; + } + + } else if ((kernel_size - setup_size) > ZIMAGE_MAX_SIZE) { + printf("Error: zImage kernel too big! (size: %ld, max: %d)\n", + kernel_size - setup_size, ZIMAGE_MAX_SIZE); + return 0; + } + + /* build command line at COMMAND_LINE_OFFSET */ + build_command_line(setup_base + COMMAND_LINE_OFFSET, auto_boot); + + printf("Loading %czImage at address 0x%08x (%ld bytes)\n", big_image ? 'b' : ' ', + (u32)load_address, kernel_size - setup_size); + + + memmove(load_address, image + setup_size, kernel_size - setup_size); + + /* ready for booting */ + return setup_base; +} + + +void boot_zimage(void *setup_base) +{ + struct pt_regs regs; + + memset(®s, 0, sizeof(struct pt_regs)); + regs.xds = (u32)setup_base >> 4; + regs.xss = 0x8e00; + regs.esp = 0x200; + regs.eflags = 0; + enter_realmode(((u32)setup_base+SETUP_START_OFFSET)>>4, 0, ®s, ®s); +} + + +image_header_t *fake_zimage_header(image_header_t *hdr, void *ptr, int size) +{ + /* There is no way to know the size of a zImage ... * + * so we assume that 2MB will be enough for now */ +#define ZIMAGE_SIZE 0x200000 + + /* load a 1MB, the loaded will have to be moved to its final + * position again later... */ +#define ZIMAGE_LOAD 0x100000 + + ulong checksum; + + if (KERNEL_MAGIC != *(u16*)(ptr + BOOT_FLAG_OFF)) { + /* not a zImage or bzImage */ + return NULL; + } + + if (-1 == size) { + size = ZIMAGE_SIZE; + } +#if 0 + checksum = crc32 (0, ptr, size); +#else + checksum = 0; +#endif + memset(hdr, 0, sizeof(image_header_t)); + + /* Build new header */ + hdr->ih_magic = htonl(IH_MAGIC); + hdr->ih_time = 0; + hdr->ih_size = htonl(size); + hdr->ih_load = htonl(ZIMAGE_LOAD); + hdr->ih_ep = 0; + hdr->ih_dcrc = htonl(checksum); + hdr->ih_os = IH_OS_LINUX; + hdr->ih_arch = IH_CPU_I386; + hdr->ih_type = IH_TYPE_KERNEL; + hdr->ih_comp = IH_COMP_NONE; + + strncpy((char *)hdr->ih_name, "(none)", IH_NMLEN); + + checksum = crc32(0,(const char *)hdr,sizeof(image_header_t)); + + hdr->ih_hcrc = htonl(checksum); + + return hdr; +} |