From cb232f1e0439fbe762aac3e30ff5c83ee25ba507 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Thu, 20 Dec 2001 04:04:42 +0000 Subject: [PATCH] Lots and Lots of changes. Mainly bugfixes for the supermicro p4dc6, and a bunch of generic changes. - Started playing with automatic scanning memory for LinuxBIOS tables. - Converted the fill_inbuf drivers to stream drivers. This allows for pure data copying operations to be faster, and it allows skipping of unneeded data on platforms that support it. - Added a section .rodata.streams for the stream driver control structures. This is preparation for building a bootloader that shares source code with LinuxBIOS. - Added a driver command to NLBConfig.py for objects that should always be linked into LinuxBIOS if they are compiled at all. - Moved the boot_successful logic down into the guts of the bootloaders. - Modified the ip style checksum logic so it isn't specific to uniform boot headers... - Added a function ndelay that uses the RTC (this is i786 specific for now). - Added a function to delay in seconds for the braindead harddrive spinup logic. - Added a floppy stream driver. - Added a ide stream driver. - Broke out the ram initialization for the p4dc6 into multiple c files. - Stupidly adapted linuxbiosmain and do_inflate to the new stream interface. get_byte is now a slow function call so it might be able to use some optimization. - Updated the ELF bootloader to the new stream interface and adding a ELF header scanning function so we can boot off of harddrives and not smash their partition tables. - Removed some bogus unlook ahead code from inflate.c - Fixed a problem where we did not enable I/O resources on VGA compatible chips. This caused a trident card to lock up the system when it's memory mapped resources were enabled. - Correctly set up nested pci busses. Before this a pci bus behind a pci bus would not get enabled. - Config changes to the p4dc6 - Added more interrupt sources to the p4dc6 interrupt table - Converted all of the inbuf drivers to stream drivers. All have good conversions except the doc_millenium. --- src/arch/i386/boot/boot.c | 14 + src/arch/i386/config/ldscript.base | 3 + src/arch/i386/lib/hardwaremain.c | 4 - src/config/Config | 2 +- src/cpu/i786/Config | 2 + src/cpu/i786/delay_i786.c | 18 + src/include/delay.h | 1 + src/include/floppy_subr.h | 9 + src/include/northbridge/intel/82860/rdram.h | 15 + src/include/rom/read_bytes.h | 21 + src/lib/Config | 1 + src/lib/delay.c | 7 + src/lib/do_inflate.c | 12 +- src/lib/elfboot.c | 96 +- src/lib/floppy_subr.c | 1038 +++++++++++++++++++ src/lib/inflate.c | 8 - src/lib/linuxbiosmain.c | 7 +- src/lib/newpci.c | 31 +- src/mainboard/supermicro/p4dc6/Config | 5 +- src/mainboard/supermicro/p4dc6/mainboard.c | 99 ++ src/mainboard/supermicro/p4dc6/mptable.c | 30 + src/northbridge/intel/82860/Config | 2 + src/northbridge/intel/82860/rdram_debug.c | 301 ++++++ src/northbridge/intel/82860/rdram_setup.c | 866 ++++++++++++++++ src/pc80/Config | 1 + src/pc80/ide/Config | 1 + src/pc80/ide/ide.c | 447 ++++++++ src/rom/Config | 16 +- src/rom/docmil_fill_inbuf.c | 52 +- src/rom/floppy_fill_inbuf.c | 44 + src/rom/ide_fill_inbuf.c | 84 ++ src/rom/rom_fill_inbuf.c | 157 ++- src/rom/serial_fill_inbuf.c | 42 +- src/rom/tftp_fill_inbuf.c | 109 +- src/rom/tsunami_tigbus_rom_fill_inbuf.c | 111 +- src/southbridge/intel/82801/ich2_power.c | 1 - src/southbridge/intel/82801/ich2_rtc.c | 2 +- util/config/NLBConfig.py | 34 +- 38 files changed, 3398 insertions(+), 295 deletions(-) create mode 100644 src/cpu/i786/delay_i786.c create mode 100644 src/include/floppy_subr.h create mode 100644 src/include/northbridge/intel/82860/rdram.h create mode 100644 src/include/rom/read_bytes.h create mode 100644 src/lib/floppy_subr.c create mode 100644 src/northbridge/intel/82860/rdram_debug.c create mode 100644 src/northbridge/intel/82860/rdram_setup.c create mode 100644 src/pc80/ide/Config create mode 100644 src/pc80/ide/ide.c create mode 100644 src/rom/floppy_fill_inbuf.c create mode 100644 src/rom/ide_fill_inbuf.c diff --git a/src/arch/i386/boot/boot.c b/src/arch/i386/boot/boot.c index 5582cfe85f..58abbeca42 100644 --- a/src/arch/i386/boot/boot.c +++ b/src/arch/i386/boot/boot.c @@ -11,6 +11,7 @@ static struct { struct uniform_boot_header header; + struct linuxbios_header lb_header; struct { struct { struct ube_memory memory; @@ -27,6 +28,14 @@ static struct { .env = (unsigned long)&ube_all.env, .env_bytes = sizeof(ube_all.env), }, + .lb_header = { + .signature = { 'L', 'B', 'I', 'O' }, + .header_bytes = sizeof(ube_all.lb_header), + .header_checksum = 0, + .env_bytes = sizeof(ube_all.env), + .env_checksum = 0, + .env_entries = 0, + }, .env = { .mem = { .memory = { @@ -65,6 +74,11 @@ void *get_ube_pointer(unsigned long totalram) ube_all.header.header_checksum = 0; ube_all.header.header_checksum = uniform_boot_compute_header_checksum(&ube_all.header); + ube_all.lb_header.env_entries = 1; /* FIXME remove this hardcode.. */ + ube_all.lb_header.env_checksum = + compute_checksum(&ube_all.env, sizeof(ube_all.env)); + ube_all.lb_header.header_checksum = + compute_checksum(&ube_all.lb_header, sizeof(ube_all.lb_header)); return &ube_all.header; } diff --git a/src/arch/i386/config/ldscript.base b/src/arch/i386/config/ldscript.base index 08f0d96b22..542df0d41c 100644 --- a/src/arch/i386/config/ldscript.base +++ b/src/arch/i386/config/ldscript.base @@ -46,6 +46,9 @@ SECTIONS } .rodata (.) : { _rodata = .; + streams = . ; + *(.rodata.streams) + estreams = .; *(.rodata) *(.rodata.*) _erodata = .; diff --git a/src/arch/i386/lib/hardwaremain.c b/src/arch/i386/lib/hardwaremain.c index 9197a08616..857713ef09 100644 --- a/src/arch/i386/lib/hardwaremain.c +++ b/src/arch/i386/lib/hardwaremain.c @@ -49,7 +49,6 @@ static char rcsid[] = "$Id$"; #include #include #include -#include #include #include #include @@ -290,9 +289,6 @@ void hardwaremain(int boot_complete) post_code(0x96); write_smp_table((void *)16, processor_map); - /* Reset to booting from this image as late as possible */ - boot_successful(); - #ifdef LINUXBIOS printk_info("Jumping to linuxbiosmain()...\n"); // we could go to argc, argv, for main but it seems like overkill. diff --git a/src/config/Config b/src/config/Config index dac20707cc..e074fdf953 100644 --- a/src/config/Config +++ b/src/config/Config @@ -16,7 +16,7 @@ makerule ldoptions : Makefile.settings ; perl -e 'foreach $$var (split(" ", $$EN makerule linuxbios.strip: linuxbios ; objcopy -O binary linuxbios linuxbios.strip -makerule linuxbios.o : crt0.o linuxbios.a $(LIBGCC_FILE_NAME) ; $(CC) -nostdlib -r -o $@ crt0.o linuxbios.a $(LIBGCC_FILE_NAME) +makerule linuxbios.o : crt0.o $(DRIVERS-1) linuxbios.a $(LIBGCC_FILE_NAME) ; $(CC) -nostdlib -r -o $@ crt0.o $(DRIVERS-1) linuxbios.a $(LIBGCC_FILE_NAME) makerule linuxbios: linuxbios.o ldscript.ld ; $(CC) -nostdlib -nostartfiles -static -o $@ -T ldscript.ld linuxbios.o diff --git a/src/cpu/i786/Config b/src/cpu/i786/Config index 59f9845cfb..8f397addd8 100644 --- a/src/cpu/i786/Config +++ b/src/cpu/i786/Config @@ -1 +1,3 @@ option i786 + +object delay_i786.o diff --git a/src/cpu/i786/delay_i786.c b/src/cpu/i786/delay_i786.c new file mode 100644 index 0000000000..d9d7fb9a77 --- /dev/null +++ b/src/cpu/i786/delay_i786.c @@ -0,0 +1,18 @@ +#include + +void ndelay(unsigned long ns) +{ + unsigned long long count; + unsigned long long stop; + unsigned long long ticks; + + /* FIXME calibrate this... don't just estimage 2Ghz */ + ticks = ns << 1; + rdtscll(count); + stop = ticks + count; + while(stop > count) { + rdtscll(count); + } +} + + diff --git a/src/include/delay.h b/src/include/delay.h index a498ce370d..bffb719a55 100644 --- a/src/include/delay.h +++ b/src/include/delay.h @@ -3,5 +3,6 @@ void udelay(int usecs); void mdelay(int msecs); +void delay(int secs); #endif /* DELAY_H */ diff --git a/src/include/floppy_subr.h b/src/include/floppy_subr.h new file mode 100644 index 0000000000..b0f30d555d --- /dev/null +++ b/src/include/floppy_subr.h @@ -0,0 +1,9 @@ +#ifndef FLOPPY_SUBR_H +#define FLOPPY_SUBR_H + +int floppy_init(void); +int floppy_read(char *dest, unsigned long offset, unsigned long length); +void floppy_fini(void); + + +#endif /* FLOPPY_SUBR_H */ diff --git a/src/include/northbridge/intel/82860/rdram.h b/src/include/northbridge/intel/82860/rdram.h new file mode 100644 index 0000000000..ce4cf9988b --- /dev/null +++ b/src/include/northbridge/intel/82860/rdram.h @@ -0,0 +1,15 @@ +void display_rdram_regs(int); +void display_spd_dev_row_col_bank(u8*, u8*, u8*); +void display_rdram_regs_tparm(int); +void display_smbus_spd(void); +void display_mch_regs(void); +void init_memory(void); + +struct rdram_reg_values { + u16 channel_a; + u16 channel_b; +}; + +void rdram_read_reg(u8, u16, u16, struct rdram_reg_values*); + + diff --git a/src/include/rom/read_bytes.h b/src/include/rom/read_bytes.h new file mode 100644 index 0000000000..e786a31e65 --- /dev/null +++ b/src/include/rom/read_bytes.h @@ -0,0 +1,21 @@ +#ifndef ROM_READ_BYTES_H +#define ROM_READ_BYTES_H + +#include + +typedef long byte_offset_t; + +struct stream { + int (*init)(void); + byte_offset_t (*read)(void *vdest, byte_offset_t count); + byte_offset_t (*skip)(byte_offset_t count); + void (*fini)(void); +}; + +#define __stream __attribute__ ((unused,__section__ (".rodata.streams"))) + +/* Defined by the linker... */ +extern struct stream streams[]; +extern struct stream estreams[]; + +#endif /* ROM_READ_BYTES_H */ diff --git a/src/lib/Config b/src/lib/Config index 78cd0bcc12..cc966cb9ca 100644 --- a/src/lib/Config +++ b/src/lib/Config @@ -13,5 +13,6 @@ object memcmp.o object malloc.o object elfboot.o object do_inflate.o +object floppy_subr.o object delay.o object fallback_boot.o USE_FALLBACK_BOOT diff --git a/src/lib/delay.c b/src/lib/delay.c index 14e00e7633..9b922b550d 100644 --- a/src/lib/delay.c +++ b/src/lib/delay.c @@ -61,3 +61,10 @@ void mdelay(int msecs) udelay(1000); } } +void delay(int secs) +{ + int i; + for(i = 0; i < secs; i++) { + mdelay(1000); + } +} diff --git a/src/lib/do_inflate.c b/src/lib/do_inflate.c index 1cbc810ca2..f98c0e6aa4 100644 --- a/src/lib/do_inflate.c +++ b/src/lib/do_inflate.c @@ -1,7 +1,7 @@ #include #include #include -#include +#include #include #include "definitions.h" #include "do_inflate.h" @@ -24,6 +24,16 @@ static unsigned char window[WSIZE]; /* Sliding window buffer */ static unsigned char *window; /* Sliding window buffer */ #endif +static unsigned char get_byte(void) +{ + unsigned char result; + if (streams->read(&result, 1) != 1) { + printk_err("Unexpected! Out of bytes...\n"); + while(1) ; + } + return result; +} + /* * gzip declarations diff --git a/src/lib/elfboot.c b/src/lib/elfboot.c index 77940cb712..144ae8d2c3 100644 --- a/src/lib/elfboot.c +++ b/src/lib/elfboot.c @@ -1,10 +1,13 @@ #if USE_ELF_BOOT #include +#include #include #include -#include +#include #include #include +#include + extern unsigned char _text; extern unsigned char _etext; @@ -60,37 +63,55 @@ int elfboot(size_t totalram) unsigned long offset; Elf_ehdr *ehdr; Elf_phdr *phdr; + int header_offset; void *ptr, *entry; int i; printk_info("\n"); printk_info("Welcome to elfboot, the open sourced starter.\n"); printk_info("Febuary 2001, Eric Biederman.\n"); - printk_info("Version 0.99\n"); + printk_info("Version 0.9999\n"); printk_info("\n"); + if (streams->init() < 0) { + printk_err("Could not initialize driver...\n"); + goto out; + } ptr = get_ube_pointer(totalram); post_code(0xf8); - /* Read in the initial 512 bytes */ - for(offset = 0; offset < 512; offset++) { - header[offset] = get_byte(); - } - ehdr = (Elf_ehdr *)(&header[0]); - entry = (void *)(ehdr->e_entry); - - /* Sanity check the elf header */ - if ((memcmp(ehdr->e_ident, ELFMAG, 4) != 0) || - (ehdr->e_type != ET_EXEC) || - (!elf_check_arch(ehdr)) || - (ehdr->e_ident[EI_VERSION] != EV_CURRENT) || - (ehdr->e_version != EV_CURRENT) || - (ehdr->e_phoff > ELF_HEAD_SIZE) || - (ehdr->e_phentsize != sizeof(Elf_phdr)) || - ((ehdr->e_phoff + (ehdr->e_phentsize * ehdr->e_phnum)) > - ELF_HEAD_SIZE)) { + /* Read in the initial ELF_HEAD_SIZE bytes */ + if (streams->read(header, ELF_HEAD_SIZE) != ELF_HEAD_SIZE) { + printk_err("Read failed...\n"); goto out; } - phdr = (Elf_phdr *)&header[ehdr->e_phoff]; + /* Scan for an elf header */ + header_offset = -1; + for(i = 0; i < ELF_HEAD_SIZE - (sizeof(Elf_ehdr) + sizeof(Elf_phdr)); i+=16) { + ehdr = (Elf_ehdr *)(&header[i]); + if (memcmp(ehdr->e_ident, ELFMAG, 4) != 0) { + continue; + } + printk_debug("Found ELF candiate at offset %d\n", i); + /* Sanity check the elf header */ + if ((ehdr->e_type == ET_EXEC) && + elf_check_arch(ehdr) && + (ehdr->e_ident[EI_VERSION] == EV_CURRENT) && + (ehdr->e_version == EV_CURRENT) && + (ehdr->e_ehsize == sizeof(Elf_ehdr)) && + (ehdr->e_phentsize = sizeof(Elf_phdr)) && + (ehdr->e_phoff < (ELF_HEAD_SIZE - i)) && + ((ehdr->e_phoff + (ehdr->e_phentsize * ehdr->e_phnum)) <= + (ELF_HEAD_SIZE - i))) { + header_offset = i; + break; + } + ehdr = 0; + } + if (header_offset == -1) { + goto out; + } + entry = (void *)(ehdr->e_entry); + phdr = (Elf_phdr *)&header[ehdr->e_phoff + header_offset]; /* Sanity check the segments and zero the extra bytes */ for(i = 0; i < ehdr->e_phnum; i++) { @@ -115,7 +136,6 @@ int elfboot(size_t totalram) } } } - offset = 0; while(1) { @@ -143,6 +163,7 @@ int elfboot(size_t totalram) } } } + /* If we are out of sections we are done */ if (!cur_phdr) { break; @@ -161,22 +182,23 @@ int elfboot(size_t totalram) start_offset = cur_phdr->p_offset; /* Skip intial buffer unused bytes */ - if (offset < ELF_HEAD_SIZE) { - if (start_offset < ELF_HEAD_SIZE) { + if (offset < (ELF_HEAD_SIZE - header_offset)) { + if (start_offset < (ELF_HEAD_SIZE - header_offset)) { offset = start_offset; } else { - offset = ELF_HEAD_SIZE; + offset = (ELF_HEAD_SIZE - header_offset); } } /* Skip the unused bytes */ - while(offset < start_offset) { - offset++; - get_byte(); + if (streams->skip(start_offset - offset) != (start_offset - offset)) { + printk_err("skip failed\n"); + goto out; } + offset = start_offset; /* Copy data from the initial buffer */ - if (offset < ELF_HEAD_SIZE) { + if (offset < (ELF_HEAD_SIZE - header_offset)) { size_t len; if ((cur_phdr->p_filesz + start_offset) > ELF_HEAD_SIZE) { len = ELF_HEAD_SIZE - start_offset; @@ -184,18 +206,24 @@ int elfboot(size_t totalram) else { len = cur_phdr->p_filesz; } - memcpy(dest, &header[start_offset], len); + memcpy(dest, &header[header_offset + start_offset], len); dest += len; } /* Read the section into memory */ - while(dest < middle) { - *(dest++) = get_byte(); + if (streams->read(dest, middle - dest) != (middle - dest)) { + printk_err("Read failed...\n"); + goto out; } offset += cur_phdr->p_filesz; /* The extra bytes between dest & end have been zeroed */ } + + /* Reset to booting from this image as late as possible */ + streams->fini(); + boot_successful(); + printk_debug("Jumping to boot code\n"); post_code(0xfe); @@ -212,6 +240,12 @@ int elfboot(size_t totalram) } printk_err("\n"); + /* Reset to booting from this image as late as possible */ + streams->fini(); +#if 0 + boot_successful(); +#endif + return 0; } #endif /* USE_ELF_BOOT */ diff --git a/src/lib/floppy_subr.c b/src/lib/floppy_subr.c new file mode 100644 index 0000000000..4877bb37fb --- /dev/null +++ b/src/lib/floppy_subr.c @@ -0,0 +1,1038 @@ +#include +#include +#include +#include +#include + + +#ifndef FD_BASE +#define FD_BASE 0x3f0 +#endif + +#define FD_DRIVE 0 + + +#define FD_STATUS_A (FD_BASE + 0) /* Status register A */ +#define FD_STATUS_B (FD_BASE + 1) /* Status register B */ +#define FD_DOR (FD_BASE + 2) /* Digital Output Register */ +#define FD_TDR (FD_BASE + 3) /* Tape Drive Register */ +#define FD_STATUS (FD_BASE + 4) /* Main Status Register */ +#define FD_DSR (FD_BASE + 4) /* Data Rate Select Register (old) */ +#define FD_DATA (FD_BASE + 5) /* Data Transfer (FIFO) register */ +#define FD_DIR (FD_BASE + 7) /* Digital Input Register (read) */ +#define FD_DCR (FD_BASE + 7) /* Diskette Control Register (write)*/ + +/* Bit of FD_STATUS_A */ +#define STA_INT_PENDING 0x80 /* Interrupt Pending */ + +/* DOR */ +#define DOR_DRIVE0 0x00 +#define DOR_DRIVE1 0x01 +#define DOR_DRIVE2 0x02 +#define DOR_DRIVE3 0x03 +#define DOR_DRIVE_MASK 0x03 +#define DOR_NO_RESET 0x04 +#define DOR_DMA_EN 0x08 +#define DOR_MOT_EN0 0x10 +#define DOR_MOT_EN1 0x20 +#define DOR_MOT_EN2 0x40 +#define DOR_MOT_EN3 0x80 + +/* Bits of main status register */ +#define STATUS_BUSYMASK 0x0F /* drive busy mask */ +#define STATUS_BUSY 0x10 /* FDC busy */ +#define STATUS_NON_DMA 0x20 /* 0- DMA mode */ +#define STATUS_DIR 0x40 /* 0- cpu->fdc */ +#define STATUS_READY 0x80 /* Data reg ready */ + +/* Bits of FD_ST0 */ +#define ST0_DS 0x03 /* drive select mask */ +#define ST0_HA 0x04 /* Head (Address) */ +#define ST0_NR 0x08 /* Not Ready */ +#define ST0_ECE 0x10 /* Equipment check error */ +#define ST0_SE 0x20 /* Seek end */ +#define ST0_INTR 0xC0 /* Interrupt code mask */ +#define ST0_INTR_OK (0 << 6) +#define ST0_INTR_ERROR (1 << 6) +#define ST0_INTR_INVALID (2 << 6) +#define ST0_INTR_POLL_ERROR (3 << 6) + +/* Bits of FD_ST1 */ +#define ST1_MAM 0x01 /* Missing Address Mark */ +#define ST1_WP 0x02 /* Write Protect */ +#define ST1_ND 0x04 /* No Data - unreadable */ +#define ST1_OR 0x10 /* OverRun */ +#define ST1_CRC 0x20 /* CRC error in data or addr */ +#define ST1_EOC 0x80 /* End Of Cylinder */ + +/* Bits of FD_ST2 */ +#define ST2_MAM 0x01 /* Missing Address Mark (again) */ +#define ST2_BC 0x02 /* Bad Cylinder */ +#define ST2_SNS 0x04 /* Scan Not Satisfied */ +#define ST2_SEH 0x08 /* Scan Equal Hit */ +#define ST2_WC 0x10 /* Wrong Cylinder */ +#define ST2_CRC 0x20 /* CRC error in data field */ +#define ST2_CM 0x40 /* Control Mark = deleted */ + +/* Bits of FD_ST3 */ +#define ST3_HA 0x04 /* Head (Address) */ +#define ST3_DS 0x08 /* drive is double-sided */ +#define ST3_TZ 0x10 /* Track Zero signal (1=track 0) */ +#define ST3_RY 0x20 /* drive is ready */ +#define ST3_WP 0x40 /* Write Protect */ +#define ST3_FT 0x80 /* Drive Fault */ + +/* Values for FD_COMMAND */ +#define FD_RECALIBRATE 0x07 /* move to track 0 */ +#define FD_SEEK 0x0F /* seek track */ +#define FD_READ 0xA6 /* read with MT, SKip deleted */ +#define FD_WRITE 0xC5 /* write with MT, MFM */ +#define FD_SENSEI 0x08 /* Sense Interrupt Status */ +#define FD_SPECIFY 0x03 /* specify HUT etc */ +#define FD_FORMAT 0x4D /* format one track */ +#define FD_VERSION 0x10 /* get version code */ +#define FD_CONFIGURE 0x13 /* configure FIFO operation */ +#define FD_PERPENDICULAR 0x12 /* perpendicular r/w mode */ +#define FD_GETSTATUS 0x04 /* read ST3 */ +#define FD_DUMPREGS 0x0E /* dump the contents of the fdc regs */ +#define FD_READID 0xEA /* prints the header of a sector */ +#define FD_UNLOCK 0x14 /* Fifo config unlock */ +#define FD_LOCK 0x94 /* Fifo config lock */ +#define FD_RSEEK_OUT 0x8f /* seek out (i.e. to lower tracks) */ +#define FD_RSEEK_IN 0xcf /* seek in (i.e. to higher tracks) */ + + +/* the following commands are new in the 82078. They are not used in the + * floppy driver, except the first three. These commands may be useful for apps + * which use the FDRAWCMD interface. For doc, get the 82078 spec sheets at + * http://www-techdoc.intel.com/docs/periph/fd_contr/datasheets/ */ + +#define FD_PARTID 0x18 /* part id ("extended" version cmd) */ +#define FD_SAVE 0x2e /* save fdc regs for later restore */ +#define FD_DRIVESPEC 0x8e /* drive specification: Access to the + * 2 Mbps data transfer rate for tape + * drives */ + +#define FD_RESTORE 0x4e /* later restore */ +#define FD_POWERDOWN 0x27 /* configure FDC's powersave features */ +#define FD_FORMAT_N_WRITE 0xef /* format and write in one go. */ +#define FD_OPTION 0x33 /* ISO format (which is a clean way to + * pack more sectors on a track) */ + +/* FDC version return types */ +#define FDC_NONE 0x00 +#define FDC_UNKNOWN 0x10 /* DO NOT USE THIS TYPE EXCEPT IF IDENTIFICATION + FAILS EARLY */ +#define FDC_8272A 0x20 /* Intel 8272a, NEC 765 */ +#define FDC_765ED 0x30 /* Non-Intel 1MB-compatible FDC, can't detect */ +#define FDC_82072 0x40 /* Intel 82072; 8272a + FIFO + DUMPREGS */ +#define FDC_82072A 0x45 /* 82072A (on Sparcs) */ +#define FDC_82077_ORIG 0x51 /* Original version of 82077AA, sans LOCK */ +#define FDC_82077 0x52 /* 82077AA-1 */ +#define FDC_82078_UNKN 0x5f /* Unknown 82078 variant */ +#define FDC_82078 0x60 /* 44pin 82078 or 64pin 82078SL */ +#define FDC_82078_1 0x61 /* 82078-1 (2Mbps fdc) */ +#define FDC_S82078B 0x62 /* S82078B (first seen on Adaptec AVA-2825 VLB + * SCSI/EIDE/Floppy controller) */ +#define FDC_87306 0x63 /* National Semiconductor PC 87306 */ + +/* + * Beware: the fdc type list is roughly sorted by increasing features. + * Presence of features is tested by comparing the FDC version id with the + * "oldest" version that has the needed feature. + * If during FDC detection, an obscure test fails late in the sequence, don't + * assign FDC_UNKNOWN. Else the FDC will be treated as a dumb 8272a, or worse. + * This is especially true if the tests are unneeded. + */ + +/* Parameters for a 1.44 3.5" disk */ +#define DISK_H1440_SIZE 2880 +#define DISK_H1440_SECT 18 +#define DISK_H1440_HEAD 2 +#define DISK_H1440_TRACK 80 +#define DISK_H1440_STRETCH 0 +#define DISK_H1440_GAP 0x1B +#define DISK_H1440_RATE 0x00 +#define DISK_H1440_SPEC1 0xCF +#define DISK_H1440_FMT_GAP 0x6C + +/* Parameters for a 1.44 3.5" drive */ +#define DRIVE_H1440_MAX_DTR 500 +#define DRIVE_H1440_HLT 16 /* ms */ +#define DRIVE_H1440_HUT 16 /* ms */ +#define DRIVE_H1440_SRT 4000 /* us */ +#define DRIVE_H1440_SPINUP 400 /* ms */ +#define DRIVE_H1440_SPINDOWN 3000 /* ms */ +#define DRIVE_H1440_SPINDOWN_OFFSET 10 +#define DRIVE_H1440_SELECT_DELAY 20 /* ms */ +#define DRIVE_H1440_RPS 5 +#define DRIVE_H1440_TRACKS 83 +#define DRIVE_H1440_TIMEOUT 3000 /* ms */ +#define DRIVE_H1440_INTERLEAVE_SECT 20 + +/* Floppy drive configuration */ +#define FIFO_DEPTH 10 +#define USE_IMPLIED_SEEK 0 +#define USE_FIFO 1 +#define FIFO_THRESHOLD 10 +#define TRACK_PRECOMPENSATION 0 + +#define SLOW_FLOPPY 0 + +#define FD_RESET_DELAY 20 /* microseconds */ + +/* + * FDC state + */ +struct drive_state { + unsigned track; +} drive_state[1]; + +struct floppy_fdc_state { + int in_sync; + int spec1; /* spec1 value last used */ + int spec2; /* spec2 value last used */ + int dtr; + unsigned char dor; + unsigned char version; /* FDC version code */ +} fdc_state; + + + +/* Synchronization of FDC access. */ +#define FD_COMMAND_NONE -1 +#define FD_COMMAND_ERROR 2 +#define FD_COMMAND_OKAY 3 + +/* + * globals used by 'result()' + */ +#define MAX_REPLIES 16 + +static void show_floppy(void); +static void floppy_reset(void); + + +static int set_dor(int fdc, char mask, char data) +{ + unsigned char newdor,olddor; + + olddor = fdc_state.dor; + newdor = (olddor & mask) | data; + if (newdor != olddor){ + fdc_state.dor = newdor; + outb(newdor, FD_DOR); + } + return olddor; +} + + +static void bounce_motor(void) +{ + /* Bounce the drive motor... */ + outb(fdc_state.dor & ~(0x10<> 2) & 1; + int status; + unsigned new_dor; + if (drive > 3) { + printk_err("bad drive value\n"); + return; + } + if (fdc != 0) { + printk_err("bad fdc value\n"); + return; + } + drive &= 3; +#if 0 + new_dor = 8; /* Enable the controller */ +#else + new_dor = 0; /* Don't enable DMA on the controller */ +#endif + new_dor |= (1 << (drive + 4)); /* Spinup the selected drive */ + new_dor |= drive; /* Select the drive for commands as well */ + set_dor(fdc, 0xc, new_dor); + + mdelay(DRIVE_H1440_SPINUP); + + status = inb(FD_STATUS); + printk_debug("set_drive status = %02x, new_dor = %02x\n", + status, new_dor); + if (status != STATUS_READY) { + printk_err("set_drive bad status\n"); + } +} + + +/* Disable the motor for a given floppy drive */ +static void floppy_motor_off(int drive) +{ + unsigned mask; + printk_debug("floppy_motor_off\n"); + /* fix the number of drives */ + drive &= 3; + /* Clear the bit for the drive we care about */ + mask = 0xff; + mask &= ~(1 << (drive +4)); + /* Now clear the bit in the Digital Output Register */ + set_dor(0, mask, 0); +} + +/* Set the FDC's data transfer rate on behalf of the specified drive. + * NOTE: with 82072/82077 FDCs, changing the data rate requires a reissue + * of the specify command (i.e. using the fdc_specify function). + */ +static void fdc_dtr(unsigned rate) +{ + rate &= 3; + /* If data rate not already set to desired value, set it. */ + if (fdc_state.in_sync && (rate == fdc_state.dtr)) + return; + + /* Set dtr */ + outb(rate, FD_DCR); + + /* TODO: some FDC/drive combinations (C&T 82C711 with TEAC 1.2MB) + * need a stabilization period of several milliseconds to be + * enforced after data rate changes before R/W operations. + * Pause 5 msec to avoid trouble. (Needs to be 2 jiffies) + */ + fdc_state.dtr = rate & 3; + mdelay(5); +} /* fdc_dtr */ + +static int fdc_configure(int use_implied_seek, int use_fifo, + unsigned fifo_threshold, unsigned precompensation) +{ + unsigned config_bits; + unsigned char cmd[4]; + /* 0 EIS EFIFO POLL FIFOOTHR[4] */ + + /* santize parameters */ + config_bits = fifo_threshold & 0xf; + config_bits |= (1 << 4); /* Always disable background floppy poll */ + config_bits |= (!use_fifo) << 5; + config_bits |= (!!use_implied_seek) << 6; + + precompensation &= 0xff; /* pre-compensation from track 0 upwards */ + + cmd[0] = FD_CONFIGURE; + cmd[1] = 0; + cmd[2] = config_bits; + cmd[3] = precompensation; + + /* Turn on FIFO */ + if (output_new_command(cmd, 4) < 0) + return 0; + return 1; +} + +#define NOMINAL_DTR 500 +/* Issue a "SPECIFY" command to set the step rate time, head unload time, + * head load time, and DMA disable flag to values needed by floppy. + * + * The value "dtr" is the data transfer rate in Kbps. It is needed + * to account for the data rate-based scaling done by the 82072 and 82077 + * FDC types. This parameter is ignored for other types of FDCs (i.e. + * 8272a). + * + * Note that changing the data transfer rate has a (probably deleterious) + * effect on the parameters subject to scaling for 82072/82077 FDCs, so + * fdc_specify is called again after each data transfer rate + * change. + * + * srt: 1000 to 16000 in microseconds + * hut: 16 to 240 milliseconds + * hlt: 2 to 254 milliseconds + * + * These values are rounded up to the next highest available delay time. + */ +static void fdc_specify( + unsigned head_load_time, unsigned head_unload_time, unsigned step_rate) +{ + unsigned char cmd[3]; + unsigned long srt, hlt, hut; + unsigned long dtr = NOMINAL_DTR; + unsigned long scale_dtr = NOMINAL_DTR; + int hlt_max_code = 0x7f; + int hut_max_code = 0xf; + + printk_debug("fdc_specify\n"); + + switch (DISK_H1440_RATE & 0x03) { + case 3: + dtr = 1000; + break; + case 1: + dtr = 300; + if (fdc_state.version >= FDC_82078) { + unsigned char cmd[3]; + /* chose the default rate table, not the one + * where 1 = 2 Mbps */ + cmd[0] = FD_DRIVESPEC; + cmd[1] = FD_DRIVE & 3; + cmd[2] = 0xc0; + output_new_command(cmd,3); + /* FIXME how do I handle errors here? */ + } + break; + case 2: + dtr = 250; + break; + } + + + if (fdc_state.version >= FDC_82072) { + scale_dtr = dtr; + hlt_max_code = 0x00; /* 0==256msec*dtr0/dtr (not linear!) */ + hut_max_code = 0x0; /* 0==256msec*dtr0/dtr (not linear!) */ + } + + /* Convert step rate from microseconds to milliseconds and 4 bits */ + srt = 16 - (step_rate*scale_dtr/1000 + NOMINAL_DTR - 1)/NOMINAL_DTR; + if (SLOW_FLOPPY) { + srt = srt / 4; + } + if (srt > 0xf) { + srt = 0xf; + } + if (srt < 0 ) { + srt = 0; + } + + hlt = (head_load_time*scale_dtr/2 + NOMINAL_DTR - 1)/NOMINAL_DTR; + if (hlt < 0x01) + hlt = 0x01; + else if (hlt > 0x7f) + hlt = hlt_max_code; + + hut = (head_unload_time*scale_dtr/16 + NOMINAL_DTR - 1)/NOMINAL_DTR; + if (hut < 0x1) + hut = 0x1; + else if (hut > 0xf) + hut = hut_max_code; + + cmd[0] = FD_SPECIFY; + cmd[1] = (srt << 4) | hut; + cmd[2] = (hlt << 1) | 1; /* Always disable DMA */ + + /* If these parameters did not change, just return with success */ + if (!fdc_state.in_sync || fdc_state.spec1 != cmd[1] || fdc_state.spec2 != cmd[2]) { + /* Go ahead and set spec1 and spec2 */ + output_command(cmd, 3); + /* FIXME how do I handle errors here... */ + printk_info("FD_SPECIFY(%02x, %02x)\n", cmd[1], cmd[2]); + } +} /* fdc_specify */ + + +/* + * reset is done by pulling bit 2 of DOR low for a while (old FDCs), + * or by setting the self clearing bit 7 of STATUS (newer FDCs) + */ +static void reset_fdc(void) +{ + unsigned char reply[MAX_REPLIES]; + + fdc_state.in_sync = 0; + + /* Pseudo-DMA may intercept 'reset finished' interrupt. */ + /* Irrelevant for systems with true DMA (i386). */ + + if (fdc_state.version >= FDC_82072A) + outb(0x80 | (fdc_state.dtr &3), FD_DSR); + else { + outb(fdc_state.dor & ~DOR_NO_RESET, FD_DOR); + udelay(FD_RESET_DELAY); + outb(fdc_state.dor, FD_DOR); + } + result(reply, MAX_REPLIES); +} + + + +static void show_floppy(void) +{ + + printk_debug("\n"); + printk_debug("floppy driver state\n"); + printk_debug("-------------------\n"); + + printk_debug("fdc_bytes: %02x %02x xx %02x %02x %02x xx %02x\n", + inb(FD_BASE + 0), inb(FD_BASE + 1), + inb(FD_BASE + 3), inb(FD_BASE + 4), inb(FD_BASE + 5), + inb(FD_BASE + 7)); + + printk_debug("status=%x\n", inb(FD_STATUS)); + printk_debug("\n"); +} + +static void floppy_recalibrate(void) +{ + unsigned char cmd[2]; + unsigned char reply[MAX_REPLIES]; + int nr, success; + success = 0; + do { + printk_debug("floppy_recalibrate\n"); + /* Send the recalibrate command to the controller. + * We don't have interrupts or anything we can poll + * so we have to guess when it is done. + */ + cmd[0] = FD_RECALIBRATE; + cmd[1] = 0; + if (output_command(cmd, 2) < 0) + continue; + + /* Sleep for the maximum time the recalibrate command + * can run. + */ + mdelay(80*DRIVE_H1440_SRT/1000); + + /* Now call FD_SENSEI to end the command + * and collect up the reply. + */ + if (output_byte(FD_SENSEI) < 0) + continue; + nr = result(reply, MAX_REPLIES); + + /* Now see if we have succeeded in our seek */ + success = + /* We have the right size result */ + (nr == 2) && + /* The command didn't terminate in error */ + ((reply[0] & ST0_INTR) == ST0_INTR_OK) && + /* We finished a seek */ + (reply[0] & ST0_SE) && + /* We are at cylinder 0 */ + (reply[1] == 0); + } while(!success); + /* Remember we are at track 0 */ + drive_state[FD_DRIVE].track = 0; +} + + +static int floppy_seek(unsigned track) +{ + unsigned char cmd[3]; + unsigned char reply[MAX_REPLIES]; + int nr, success; + unsigned distance, old_track; + + /* Look up the old track and see if we need to + * do anything. + */ + old_track = drive_state[FD_DRIVE].track; + if (old_track == track) { + return 1; + } + + /* Compute the distance we are about to move, + * We need to know this so we know how long to sleep... + */ + distance = (old_track > track)?(old_track - track):(track - old_track); + distance += 1; + + + /* Send the seek command to the controller. + * We don't have interrupts or anything we can poll + * so we have to guess when it is done. + */ + cmd[0] = FD_SEEK; + cmd[1] = FD_DRIVE; + cmd[2] = track; + if (output_command(cmd, 3) < 0) + return 0; + + /* Sleep for the time it takes to step throuhg distance tracks. + */ + mdelay(distance*DRIVE_H1440_SRT/1000); + + /* Now call FD_SENSEI to end the command + * and collect up the reply. + */ + cmd[0] = FD_SENSEI; + if (output_command(cmd, 1) < 0) + return 0; + nr = result(reply, MAX_REPLIES); + + /* Now see if we have succeeded in our seek */ + success = + /* We have the right size result */ + (nr == 2) && + /* The command didn't terminate in error */ + ((reply[0] & ST0_INTR) == ST0_INTR_OK) && + /* We finished a seek */ + (reply[0] & ST0_SE) && + /* We are at cylinder 0 */ + (reply[1] == track); + if (success) + drive_state[FD_DRIVE].track = track; + else { + int i; + printk_debug("seek failed\n"); + printk_debug("nr = %d\n", nr); + printk_debug("ST0 = %02x\n", reply[0]); + printk_debug("PCN = %02x\n", reply[1]); + printk_debug("status = %d\n", inb(FD_STATUS)); + } + return success; +} + +static int read_ok(unsigned head) +{ + unsigned char results[7]; + int result_ok; + int nr; + + /* read back the read results */ + nr = result(results, 7); + + /* Now see if they say we are o.k. */ + result_ok = 0; + /* Are my result bytes o.k.? */ + if (nr == 7) { + /* Are we o.k. */ + if ((results[0] & ST0_INTR) == ST0_INTR_OK) { + result_ok = 1; + } + /* Or did we get just an overflow error */ + else if (((results[0] & ST0_INTR) == ST0_INTR_ERROR) && + (results[1]== ST1_OR) && + (results[2] == 0)) { + result_ok = 1; + } + /* Verify the reply had the correct head */ + if (((results[0] & ST0_HA) >> 2) != head) { + result_ok = 0; + } + /* Verify the reply had the correct drive */ + if (((results[0] & ST0_DS) != FD_DRIVE)) { + result_ok = 0; + } + } + if (!result_ok) { + printk_debug("result_bytes = %d\n", nr); + printk_debug("ST0 = %02x\n", results[0]); + printk_debug("ST1 = %02x\n", results[1]); + printk_debug("ST2 = %02x\n", results[2]); + printk_debug(" C = %02x\n", results[3]); + printk_debug(" H = %02x\n", results[4]); + printk_debug(" R = %02x\n", results[5]); + printk_debug(" N = %02x\n", results[6]); + } + return result_ok; +} + +static int floppy_read_sectors( + char *dest, unsigned byte_offset, unsigned length, + unsigned sector, unsigned head, unsigned track) +{ + /* MT == Multitrack */ + /* MFM == MFM or FM Mode */ + /* SK == Skip deleted data addres Mark */ + /* HDS == Head number select */ + /* DS0 == Disk Drive Select 0 */ + /* DS1 == Disk Drive Select 1 */ + /* C == Cylinder number 0 - 255 */ + /* H == Head number */ + /* R == Record */ + /* N == The number of data bytes written in a sector */ + /* EOT == End of Track */ + /* GPL == Gap Length */ + /* DTL == Data Length */ + /* MT MFM SK 0 1 1 0 0 */ + /* 0 0 0 0 0 HDS DS1 DS0 */ + /* C, H, R, N, EOT, GPL, DTL */ + + int i, status, result_ok; + int max_bytes, bytes_read; + int ret; + unsigned char cmd[9]; + unsigned end_offset; + + end_offset = byte_offset + length; + max_bytes = 512*(DISK_H1440_SECT - sector + 1); + + if (byte_offset >= max_bytes) { + return 0; + } + cmd[0] = FD_READ | (((DISK_H1440_HEAD ==2)?1:0) << 6); + cmd[1] = (head << 2) | FD_DRIVE; + cmd[2] = track; + cmd[3] = head; + cmd[4] = sector; + cmd[5] = 2; /* 2^N *128 == Sector size. Hard coded to 512 bytes */ + cmd[6] = DISK_H1440_SECT; + cmd[7] = DISK_H1440_GAP; + cmd[8] = 0xff; + + /* Output the command bytes */ + if (output_command(cmd, 9) < 0) + return -1; + + /* The execution stage begins when STATUS_READY&STATUS_NON_DMA is set */ + do { + status = inb(FD_STATUS); + status &= STATUS_READY | STATUS_NON_DMA; + } while(status != (STATUS_READY|STATUS_NON_DMA)); + + for(i = 0; i < max_bytes; i++) { + unsigned char byte; + if ((status = wait_til_ready()) < 0) { + break; + } + status &= STATUS_READY|STATUS_DIR|STATUS_NON_DMA; + if (status != (STATUS_READY|STATUS_DIR|STATUS_NON_DMA)) { + break; + } + byte = inb(FD_DATA); + if ((i >= byte_offset) && (i < end_offset)) { + dest[i - byte_offset] = byte; + } + } + bytes_read = i; + + /* The result stage begins when STATUS_NON_DMA is cleared */ + while((status = inb(FD_STATUS)) & STATUS_NON_DMA) { + /* We get extra bytes in the fifo past + * the end of the sector and drop them on the floor. + * Otherwise the fifo is polluted. + */ + inb(FD_DATA); + } + /* Did I get an error? */ + result_ok = read_ok(head); + /* Did I read enough bytes? */ + ret = -1; + if (result_ok && (bytes_read == max_bytes)) { + ret = bytes_read - byte_offset; + if (ret > length) { + ret = length; + } + } + + if (ret < 0) { + printk_debug("ret = %d\n", ret); + printk_debug("bytes_read = %d\n", bytes_read); + printk_debug("status = %x\n", status); + } + return ret; +} + + +static int __floppy_read(char *dest, unsigned long offset, unsigned long length) +{ + unsigned head, track, sector, byte_offset, sector_offset; + int ret; + + /* break the offset up into sectors and bytes */ + byte_offset = offset % 512; + sector_offset = offset / 512; + + /* Find the disk block we are starting with... */ + sector = (sector_offset % DISK_H1440_SECT) + 1; + head = (sector_offset / DISK_H1440_SECT) % DISK_H1440_HEAD; + track = (sector_offset / (DISK_H1440_SECT *DISK_H1440_HEAD))% DISK_H1440_TRACK; + + /* First seek to our start track */ + if (!floppy_seek(track)) { + return -1; + } + /* Then read the data */ + ret = floppy_read_sectors(dest, byte_offset, length, sector, head, track); + if (ret >= 0) { + return ret; + } + /* If we failed reset the fdc... */ + floppy_reset(); + return -1; +} + +int floppy_read(char *dest, unsigned long offset, unsigned long length) +{ + int result, bytes_read;; + printk_debug("floppy_read\n"); + bytes_read = 0; + do { + int max_errors = 3; + do { + result = __floppy_read(dest + bytes_read, offset, length - bytes_read); + if (max_errors-- == 0) { + return (bytes_read)?bytes_read: -1; + } + } while (result <= 0); + offset += result; + bytes_read += result; + } while(bytes_read < length); + return bytes_read; +} + +/* Determine the floppy disk controller type */ +/* This routine was written by David C. Niemi */ +static char get_fdc_version(void) +{ + int bytes, ret; + unsigned char reply_buffer[MAX_REPLIES]; + + ret = output_byte(FD_DUMPREGS); /* 82072 and better know DUMPREGS */ + if (ret < 0) + return FDC_NONE; + if ((bytes = result(reply_buffer, MAX_REPLIES)) <= 0x00) + return FDC_NONE; /* No FDC present ??? */ + if ((bytes==1) && (reply_buffer[0] == 0x80)){ + printk_info("FDC %d is an 8272A\n"); + return FDC_8272A; /* 8272a/765 don't know DUMPREGS */ + } + if (bytes != 10) { + printk_debug("init: DUMPREGS: unexpected return of %d bytes.\n", + bytes); + return FDC_UNKNOWN; + } + if (!fdc_configure(USE_IMPLIED_SEEK, USE_FIFO, FIFO_THRESHOLD, + TRACK_PRECOMPENSATION)) { + printk_info("FDC is an 82072\n"); + return FDC_82072; /* 82072 doesn't know CONFIGURE */ + } + + output_byte(FD_PERPENDICULAR); + if (need_more_output() == MORE_OUTPUT) { + output_byte(0); + } else { + printk_info("FDC is an 82072A\n"); + return FDC_82072A; /* 82072A as found on Sparcs. */ + } + + output_byte(FD_UNLOCK); + bytes = result(reply_buffer, MAX_REPLIES); + if ((bytes == 1) && (reply_buffer[0] == 0x80)){ + printk_info("FDC is a pre-1991 82077\n"); + return FDC_82077_ORIG; /* Pre-1991 82077, doesn't know + * LOCK/UNLOCK */ + } + if ((bytes != 1) || (reply_buffer[0] != 0x00)) { + printk_debug("FDC init: UNLOCK: unexpected return of %d bytes.\n", + bytes); + return FDC_UNKNOWN; + } + output_byte(FD_PARTID); + bytes = result(reply_buffer, MAX_REPLIES); + if (bytes != 1) { + printk_debug("FDC init: PARTID: unexpected return of %d bytes.\n", + bytes); + return FDC_UNKNOWN; + } + if (reply_buffer[0] == 0x80) { + printk_info("FDC is a post-1991 82077\n"); + return FDC_82077; /* Revised 82077AA passes all the tests */ + } + switch (reply_buffer[0] >> 5) { + case 0x0: + /* Either a 82078-1 or a 82078SL running at 5Volt */ + printk_info("FDC is an 82078.\n"); + return FDC_82078; + case 0x1: + printk_info("FDC is a 44pin 82078\n"); + return FDC_82078; + case 0x2: + printk_info("FDC is a S82078B\n"); + return FDC_S82078B; + case 0x3: + printk_info("FDC is a National Semiconductor PC87306\n"); + return FDC_87306; + default: + printk_info("FDC init: 82078 variant with unknown PARTID=%d.\n", + reply_buffer[0] >> 5); + return FDC_82078_UNKN; + } +} /* get_fdc_version */ + + +int floppy_init(void) +{ + printk_debug("floppy_init\n"); + fdc_state.in_sync = 0; + fdc_state.spec1 = -1; + fdc_state.spec2 = -1; + fdc_state.dtr = -1; + fdc_state.dor = DOR_NO_RESET; + fdc_state.version = FDC_UNKNOWN; + reset_fdc(); + /* Try to determine the floppy controller type */ + fdc_state.version = get_fdc_version(); + if (fdc_state.version == FDC_NONE) { + return -1; + } + floppy_reset(); + printk_info("fdc_state.version = %04x\n", fdc_state.version); + return 0; +} + +static void floppy_reset(void) +{ + printk_debug("floppy_reset\n"); + floppy_motor_off(FD_DRIVE); + reset_fdc(); + fdc_dtr(DISK_H1440_RATE); + /* program data rate via ccr */ + collect_interrupt(); + fdc_configure(USE_IMPLIED_SEEK, USE_FIFO, FIFO_THRESHOLD, + TRACK_PRECOMPENSATION); + fdc_specify(DRIVE_H1440_HLT, DRIVE_H1440_HUT, DRIVE_H1440_SRT); + set_drive(FD_DRIVE); + floppy_recalibrate(); + fdc_state.in_sync = 1; +} + +void floppy_fini(void) +{ + /* Disable the floppy and the floppy drive controller */ + set_dor(0, 0, 0); +} diff --git a/src/lib/inflate.c b/src/lib/inflate.c index 8655e307a7..36af6b6e7c 100644 --- a/src/lib/inflate.c +++ b/src/lib/inflate.c @@ -986,14 +986,6 @@ STATIC int inflate() h = hufts; } while (!e); - /* Undo too much lookahead. The next read will be byte aligned so we - * can discard unused bits in the last meaningful byte. - */ - while (bk >= 8) { - bk -= 8; - inptr--; - } - /* flush out slide */ flush_output(wp); diff --git a/src/lib/linuxbiosmain.c b/src/lib/linuxbiosmain.c index 5c8102be6b..04dd286d4e 100644 --- a/src/lib/linuxbiosmain.c +++ b/src/lib/linuxbiosmain.c @@ -18,9 +18,10 @@ */ #include +#include #include #include -#include +#include #include #include @@ -92,6 +93,7 @@ int linuxbiosmain(unsigned long base, unsigned long totalram) printk_notice("\nnetboot_init test complete, all is well (I hope!)\n"); #endif /* USE_TFTP */ + streams->init(); printk_debug("Gunzip setup\n"); gunzip_setup(); printk_debug("Gunzipping boot code\n"); @@ -100,6 +102,7 @@ int linuxbiosmain(unsigned long base, unsigned long totalram) post_code(0xff); return 0; } + streams->fini(); post_code(0xf8); #ifdef TFTP_INITRD @@ -156,6 +159,8 @@ int linuxbiosmain(unsigned long base, unsigned long totalram) set_display(empty_zero_page, 25, 80); set_initrd(empty_zero_page, initrd_start, initrd_size); + /* Reset to booting from this image as late as possible */ + boot_successful(); printk_debug("Jumping to boot code\n"); post_code(0xfe); diff --git a/src/lib/newpci.c b/src/lib/newpci.c index a8131ffa79..c0b6410815 100644 --- a/src/lib/newpci.c +++ b/src/lib/newpci.c @@ -461,8 +461,20 @@ void compute_allocate_io(struct pci_bus *bus) curbus->number, io_base); } - /* Walk through all the devices on current bus and oompute IO address space.*/ + /* Walk through all the devices on current bus and compute IO address space.*/ for (curdev = bus->devices; curdev; curdev = curdev->sibling) { + u32 class_revision; + /* FIXME Special case for VGA for now just note + * we have an I/O resource later make certain + * we don't have a device conflict. + */ + pci_read_config_dword(curdev, PCI_CLASS_REVISION, &class_revision); + if (((class_revision >> 24) == 0x03) && + ((class_revision >> 16) != 0x380)) { + printk_debug("Running VGA fix...\n"); + /* All legacy VGA cards have I/O space registers */ + curdev->command |= PCI_COMMAND_IO; + } for (i = 0; i < 6; i++) { unsigned long size = curdev->size[i]; if (size & PCI_BASE_ADDRESS_SPACE_IO) { @@ -690,8 +702,8 @@ void assign_resources(struct pci_bus *bus) curbus->iobase >> 8); pci_write_config_byte(curbus->self, PCI_IO_LIMIT, curbus->iolimit >> 8); - printk_debug("Bus 0x%x iobase to 0x%x iolimit 0x%x\n", - bus->number, curbus->iobase, curbus->iolimit); + printk_debug("Bus 0x%x Child Bus %x iobase to 0x%x iolimit 0x%x\n", + bus->number,curbus->number, curbus->iobase, curbus->iolimit); } // set the memory range @@ -701,8 +713,8 @@ void assign_resources(struct pci_bus *bus) curbus->membase >> 16); pci_write_config_word(curbus->self, PCI_MEMORY_LIMIT, curbus->memlimit >> 16); - printk_debug("Bus 0x%x membase to 0x%x memlimit 0x%x\n", - bus->number, curbus->membase, curbus->memlimit); + printk_debug("Bus 0x%x Child Bus %x membase to 0x%x memlimit 0x%x\n", + bus->number,curbus->number, curbus->membase, curbus->memlimit); } @@ -713,15 +725,16 @@ void assign_resources(struct pci_bus *bus) curbus->prefmembase >> 16); pci_write_config_word(curbus->self, PCI_PREF_MEMORY_LIMIT, curbus->prefmemlimit >> 16); - printk_debug("Bus 0x%x prefmembase to 0x%x prefmemlimit 0x%x\n", - bus->number, curbus->prefmembase, curbus->prefmemlimit); + printk_debug("Bus 0x%x Child Bus %x prefmembase to 0x%x prefmemlimit 0x%x\n", + bus->number,curbus->number, curbus->prefmembase, + curbus->prefmemlimit); } curbus->self->command |= PCI_COMMAND_MASTER; - + assign_resources(curbus); } - for (curdev = pci_devices; curdev; curdev = curdev->next) { + for (curdev = bus->devices; curdev; curdev = curdev->sibling) { int i; for (i = 0; i < 6; i++) { unsigned long reg; diff --git a/src/mainboard/supermicro/p4dc6/Config b/src/mainboard/supermicro/p4dc6/Config index f463c4600d..7f1e9aa29c 100644 --- a/src/mainboard/supermicro/p4dc6/Config +++ b/src/mainboard/supermicro/p4dc6/Config @@ -16,6 +16,9 @@ nooption USE_DEFAULT_LAYOUT option STACK_SIZE=0x2000 option USE_FALLBACK_BOOT=1 +option USE_RAMTEST=1 +dir /src/ram + #/* falback */ option ZKERNEL_START=0xffff0000 option _ROMBASE= 0xffff8000 @@ -57,7 +60,7 @@ option NO_KEYBOARD option ENABLE_FIXED_AND_VARIABLE_MTRRS #option FINAL_MAINBOARD_FIXUP -object cacheramtest.o +#object cacheramtest.o object mainboard.o object mtrr_values.o object mptable.o HAVE_MP_TABLE diff --git a/src/mainboard/supermicro/p4dc6/mainboard.c b/src/mainboard/supermicro/p4dc6/mainboard.c index 5893b3fc86..87ef9db7bb 100644 --- a/src/mainboard/supermicro/p4dc6/mainboard.c +++ b/src/mainboard/supermicro/p4dc6/mainboard.c @@ -8,6 +8,16 @@ #include #include #include +#include +#include +#include +#include +#include + + +#define SMBUS_MEM_DEVICE_0 (0xa << 3) +extern int rdram_chips; /* number of ram chips on the rimms */ + unsigned long initial_apicid[MAX_CPUS] = { @@ -38,3 +48,92 @@ void hard_reset(void) ich2_hard_reset(); } +static void select_rdram_i2c(void) +{ + unsigned char byte; + w83627hf_enter_pnp(SIO_BASE); + byte = pnp_read_config(SIO_BASE, 0x2b); + byte |= 0x30; + pnp_write_config(SIO_BASE, byte, 0x2b); + pnp_set_logical_device(SIO_BASE, GPIO_PORT2_DEVICE); + pnp_set_enable(SIO_BASE, 1); + byte = pnp_read_config(SIO_BASE, 0xf0); + byte &= ~(1 << 3); + pnp_write_config(SIO_BASE, byte, 0xf0); + w83627hf_exit_pnp(SIO_BASE); +} + +void cache_ram_start(void) +{ + int error; + error = 0; + /* displayinit MUST PRECEDE ALL PRINTK! */ + displayinit(); + printk_info("printk: Testing %d %s\n", 123, "testing!!!"); + printk_info("Finding PCI configuration type.\n"); + pci_set_method(); + printk_info("Setting up smbus controller\n"); + smbus_setup(); + ich2_rtc_init(); + printk_info("Selecting rdram i2c bus\n"); + select_rdram_i2c(); + + display_smbus_spd(); + + init_memory(); + +#if 1 + { + unsigned long addr; + for(addr = 0; addr < 0x20000000; addr += 0x02000000) { + ram_fill(addr, addr + 0x400); + } + /* Do some dummy writes to flush a write cache, in the + * processor. + */ + ram_fill(0xc0000000, 0xc0000400); + for(addr = 0; addr < 0x20000000; addr += 0x02000000) { + ram_verify(addr, addr + 0x400, 1); + } + } +#endif + error |= ramcheck(0x00000000, 0x00080000, 20); + error |= ramcheck(0x02000000, 0x02080000, 20); + error |= ramcheck(0x04000000, 0x04080000, 20); + error |= ramcheck(0x06000000, 0x06080000, 20); + error |= ramcheck(0x08000000, 0x08080000, 20); + error |= ramcheck(0x0a000000, 0x0a080000, 20); + error |= ramcheck(0x0c000000, 0x0c080000, 20); + + error |= ramcheck(0x0e000000, 0x0e080000, 20); + error |= ramcheck(0x10000000, 0x10080000, 20); + error |= ramcheck(0x12000000, 0x12080000, 20); + error |= ramcheck(0x14000000, 0x14080000, 20); + error |= ramcheck(0x16000000, 0x16080000, 20); + error |= ramcheck(0x18000000, 0x18080000, 20); + error |= ramcheck(0x1a000000, 0x1a080000, 20); + error |= ramcheck(0x1c000000, 0x1c080000, 20); + error |= ramcheck(0x1e000000, 0x1e080000, 20); +#if 0 + error |= ramcheck(0x00000000, 0x00080000, 20); +#endif +#if 1 + display_rdram_regs(rdram_chips ); +#endif +#if 1 + display_mch_regs(); +#endif + if (error) { + printk_err("Something isn't working!!!\n"); + while(1); + } else { + printk_info("Leaving cacheram...\n"); + } + +} + + + + + + diff --git a/src/mainboard/supermicro/p4dc6/mptable.c b/src/mainboard/supermicro/p4dc6/mptable.c index 732dda5f8d..3865313be3 100644 --- a/src/mainboard/supermicro/p4dc6/mptable.c +++ b/src/mainboard/supermicro/p4dc6/mptable.c @@ -55,6 +55,34 @@ void smp_write_config_table(void *v, unsigned long * processor_map) smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, 0x04, (4 <<2)|0, 0x02, 0x10); + /* Four standard PCI slots */ + /* Slot 1 */ + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, + 0x04, (7 <<2)|0, 0x02, 0x10); + /* Slot 2 */ + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, + 0x04, (1 <<2)|0, 0x02, 0x11); + /* Slot 3 */ + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, + 0x04, (2 <<2)|0, 0x02, 0x12); + /* Slot 4 */ + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, + 0x04, (3 <<2)|0, 0x02, 0x13); + + /* Two 64 bit PCI slots */ + /* Slot 1 */ + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, + 0x03, (1 <<2)|0, 0x02, 0x12); + /* Slot 2 */ + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, + 0x03, (2 <<2)|0, 0x02, 0x12); + + /* Two SCSI */ + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, + 0x03, (4 <<2)|0, 0x02, 0x12); + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, + 0x03, (4 <<2)|1, 0x02, 0x12); + /* ISA backward compatibility interrupts */ smp_write_intsrc(mc, mp_ExtINT, MP_IRQ_TRIGGER_DEFAULT|MP_IRQ_POLARITY_DEFAULT, 0x05, 0x00, 0x02, 0x00); @@ -66,6 +94,8 @@ void smp_write_config_table(void *v, unsigned long * processor_map) 0x05, 0x03, 0x02, 0x03); smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_DEFAULT|MP_IRQ_POLARITY_DEFAULT, 0x05, 0x04, 0x02, 0x04); + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_DEFAULT|MP_IRQ_POLARITY_DEFAULT, + 0x05, 0x05, 0x02, 0x05); smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_DEFAULT|MP_IRQ_POLARITY_DEFAULT, 0x05, 0x06, 0x02, 0x06); smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_DEFAULT|MP_IRQ_POLARITY_DEFAULT, diff --git a/src/northbridge/intel/82860/Config b/src/northbridge/intel/82860/Config index 990f2efc0c..f64b57e8dc 100644 --- a/src/northbridge/intel/82860/Config +++ b/src/northbridge/intel/82860/Config @@ -2,3 +2,5 @@ mainboardinit arch/i386/lib/set_memory_size_noop.inc mainboardinit arch/i386/lib/cpu_reset.inc object northbridge.o +object rdram_setup.o +object rdram_debug.o diff --git a/src/northbridge/intel/82860/rdram_debug.c b/src/northbridge/intel/82860/rdram_debug.c new file mode 100644 index 0000000000..bea6a33d4b --- /dev/null +++ b/src/northbridge/intel/82860/rdram_debug.c @@ -0,0 +1,301 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LPC_BUS 0 +#define LPC_DEVFN ((0x1f << 3) + 0) + +#define ICH2HUB_BUS 0 +#define ICH2HUB_DEVFN ((0x1e << 3) + 0) + +#define I860MCH_BUS 0 +#define I860MCH_DEVFN ((0x00 << 3) + 0) + +#define I860HUBA_BUS 0 +#define I860HUBA_DEVFN ((0x01 << 3) + 0) + +#define I860HUBB_BUS 0 +#define I860HUBB_DEVFN ((0x02 << 3) + 0) + +#define SMBUS_MEM_DEVICE_0 (0xa << 3) + +#define TSCYCLE_SLOW 1000 /* ns */ +#define TSCYCLE_FAST 10 /* ns */ + +#define I860_MCH_BUS 0 +#define I860_MCH_DEVFN 0 + +#define MCH_GAR0 0x40 +#define MCH_GAR1 0x41 +#define MCH_GAR2 0x42 +#define MCH_GAR3 0x43 +#define MCH_GAR4 0x44 +#define MCH_GAR5 0x45 +#define MCH_GAR6 0x46 +#define MCH_GAR7 0x47 +#define MCH_GAR8 0x48 +#define MCH_GAR9 0x49 +#define MCH_GAR10 0x4a +#define MCH_GAR11 0x4b +#define MCH_GAR12 0x4c +#define MCH_GAR13 0x4d +#define MCH_GAR14 0x4e +#define MCH_GAR15 0x4f +#define MCH_MCHCFG 0x50 +#define MCH_FDHC 0x58 +#define MCH_PAM0 0x59 +#define MCH_PAM1 0x5a +#define MCH_PAM2 0x5b +#define MCH_PAM3 0x5c +#define MCH_PAM4 0x5d +#define MCH_PAM5 0x5e +#define MCH_PAM6 0x5f +#define MCH_GBA0 0x60 +#define MCH_GBA1 0x62 +#define MCH_GBA2 0x64 +#define MCH_GBA3 0x66 +#define MCH_GBA4 0x68 +#define MCH_GBA5 0x6a +#define MCH_GBA6 0x6c +#define MCH_GBA7 0x6e +#define MCH_GBA8 0x70 +#define MCH_GBA9 0x72 +#define MCH_GBA10 0x74 +#define MCH_GBA11 0x76 +#define MCH_GBA12 0x78 +#define MCH_GBA13 0x7a +#define MCH_GBA14 0x7c +#define MCH_GBA15 0x7e +#define MCH_RDPS 0x88 +#define MCH_DRD 0x90 +#define MCH_RICM 0x94 +#define MCH_SMRAM 0x9d +#define MCH_ESMRAM 0x9e +#define MCH_RDT 0xbe +#define MCH_TOM 0xc4 +#define MCH_ERRSTS 0xc8 +#define MCH_ERRCMD 0xca +#define MCH_SMICMD 0xcc +#define MCH_SCICMD 0xce +#define MCH_DRAMRC 0xdc +#define MCH_DERRCTL 0xe2 +#define MCH_EAP 0xe4 + +#define RICM_BUSY (1 << 23) +#define RICM_DONE (1 << 27) + + +#define __S(NAME) NAME##_SHIFT +#define __B(NAME) NAME##_BITS +#define __BIT_MASK(SHIFT, BITS) ((1 << (BITS + SHIFT)) - (1 << (SHIFT))) +#define MASK(NAME) __BIT_MASK(__S(NAME), __B(NAME)) +#define NVAL(NAME, VAL) (MASK(NAME) & ((VAL) << __S(NAME))) +#define VAL(NAME, VALUE) ((MASK(NAME) & VALUE) >> __S(NAME)) + +#define RICM_CMD_SHIFT 0 +#define RICM_CMD_BITS 5 +#define RICM_ADDR_SHIFT 5 +#define RICM_ADDR_BITS 5 +#define RICM_REG_SHIFT 10 +#define RICM_REG_BITS 9 +#define RICM_BROADCAST_SHIFT 19 +#define RICM_BROADCAST_BITS 1 +#define RICM_CHANNEL_SHIFT 20 +#define RICM_CHANNEL_BITS 2 + +#define CMD_RDRAM_READ_REG 0 +#define CMD_RDRAM_WRITE_REG 1 +#define CMD_RDRAM_SET_RESET 2 +#define CMD_SET_FAST_CLK 4 +#define CMD_TEMP_CALIBRATE_ENABLE 5 +#define CMD_TEMP_CALIBRATE 6 +#define CMD_MRH_REDIRECT_NEXT_SIO 8 +#define CMD_MRH_STICK_SIO_RESET 9 +#define CMD_RDRAM_CLEAR_RESET 11 +#define CMD_RDRAM_CURRENT_CALIBRATION 16 +#define CMD_RDRAM_SIO_RESET 17 +#define CMD_RDRAM_POWERDOWN_EXIT 18 +#define CMD_RDRAM_POWERDOWN_ENTRY 19 +#define CMD_RDRAM_NAP_ENTRY 20 +#define CMD_RDRAM_NAP_EXIT 21 +#define CMD_RDRAM_REFRESH 22 +#define CMD_RDRAM_PRECHARGE 23 +#define CMD_MANUAL_CURRENT_CALIBRATION 24 +#define CMD_MCH_RAC_LOAD_RACA_CONFIG 25 +#define CMD_MCH_RAC_LOAD_RACB_CONFIG 26 +#define CMD_MCH_INITIALIZE_RAC 27 +#define CMD_MCH_RAC_CURRENT_CALIBRATION 28 +#define CMD_MCH_RAC_TEMP_CALIBRATE 29 +#define CMD_POWERUP_ALL_SEQUENCE 31 + +#define REG_INIT 0x21 +#define REG_TEST34 0x22 +#define REG_CNFGA 0x23 +#define REG_CNFGB 0x24 +#define REG_DEVID 0x40 +#define REG_REFB 0x41 +#define REG_REFR 0x42 +#define REG_CCA 0x43 +#define REG_CCB 0x44 +#define REG_NAPX 0x45 +#define REG_PDNXA 0x46 +#define REG_PDNX 0x47 +#define REG_TPARM 0x48 +#define REG_TFRM 0x49 +#define REG_TCDLY1 0x4a +#define REG_SKIP 0x4b +#define REG_TCYCLE 0x4c +#define REG_TEST77 0x4d +#define REG_TEST78 0x4e +#define REG_TEST79 0x4f + +#define BCAST 0xffff + +//int rdram_chips=0; /* number of ram chips on the rimms */ +//static u32 total_rdram; /* Total rdram found */ + +u16 rdram_regs[] = { + REG_INIT, + REG_TEST34, + REG_CNFGA, + REG_CNFGB, + REG_DEVID, + REG_REFB, + REG_REFR, + REG_CCA, + REG_CCB, + REG_NAPX, + REG_PDNXA, + REG_PDNX, + REG_TPARM, + REG_TFRM, + REG_TCDLY1, + REG_SKIP, + REG_TCYCLE, + REG_TEST77, + REG_TEST78, + REG_TEST79, +}; +char *rdram_reg_names[] = { + "INIT", + "TEST34", + "CNFGA", + "CNFGB", + "DEVID", + "REFB", + "REFR", + "CCA", + "CCB", + "NAPX", + "PDNXA", + "PDNX", + "TPARM", + "TFRM", + "TCDLY1", + "SKIP", + "TCYCLE", + "TEST77", + "TEST78", + "TEST79", +}; + + +void display_spd_dev_row_col_bank(u8 *spd_devices, u8 *spd_row_col, u8 *spd_banks) +{ + int i; + + for(i=0;i<4;i++) + printk_debug("Devices %d, Row Bits %d, Col Bits %d, Bank Bits %d\n", + spd_devices[i],(spd_row_col[i]>>4),(spd_row_col[i]&0x0f),spd_banks[i]); + +} + +void display_rdram_regs_tparm(int rdram_chips) +{ + int i,j; + + for(i = 0; i < rdram_chips; i++) { + for(j = 12; j < 15; j+=2) { + struct rdram_reg_values values; + u16 reg = rdram_regs[j]; + rdram_read_reg(0, i, reg, &values); + printk_debug("rdram: %2d reg: %02x %10s a: 0x%04x b: 0x%04x\n", + i, reg, rdram_reg_names[j], values.channel_a, values.channel_b); } + } +} + +void display_rdram_regs(int rdram_chips ) +{ + int i,j; + + for(i = 0; i < rdram_chips; i++) { + for(j = 0; j < sizeof(rdram_regs)/sizeof(rdram_regs[0]); j++) { + struct rdram_reg_values values; + u16 reg = rdram_regs[j]; + rdram_read_reg(0, i, reg, &values); + printk_debug("rdram: %2d reg: %02x %10s a: 0x%04x b: 0x%04x\n", + i, reg, rdram_reg_names[j], values.channel_a, values.channel_b); + } + } + +} + +void display_smbus_spd(void) +{ + int i,j; + + for(j = SMBUS_MEM_DEVICE_0; j < SMBUS_MEM_DEVICE_0 + 4; j++) { + int status = 0; + if ((j == 0x1b) || 0) { + printk_debug("skipping device: %02x\n", j); + continue; + } + printk_debug("smbus_device: %02x\n", j); + for(i = 0; (i < 128) && (status == 0); i++) { + unsigned char byte; + status = smbus_read_byte(j, i, &byte); + if (status != 0) { + printk_debug("bad device\n"); + continue; + } + printk_debug("0x%02x ", byte); + if ((i &0x0f) == 0x0f) { + printk_debug("\n"); + } + } + } + printk_debug("\n"); +} + +void display_mch_regs(void) +{ + int i,j; + + printk_debug("MCH Register Dump\n"); + for(i = 0; i < 16; i++) { + printk_debug("%02x: ", i << 4); + for(j = 0; j < 16; j++) { + u8 byte; + u8 addr = (i << 4) | j; + pcibios_read_config_byte(I860_MCH_BUS, I860_MCH_DEVFN, addr, &byte); + printk_debug("%02x ", byte); + } + printk_debug("\n"); + } +} + + diff --git a/src/northbridge/intel/82860/rdram_setup.c b/src/northbridge/intel/82860/rdram_setup.c new file mode 100644 index 0000000000..a9a1fc9086 --- /dev/null +++ b/src/northbridge/intel/82860/rdram_setup.c @@ -0,0 +1,866 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LPC_BUS 0 +#define LPC_DEVFN ((0x1f << 3) + 0) + +#define ICH2HUB_BUS 0 +#define ICH2HUB_DEVFN ((0x1e << 3) + 0) + +#define I860MCH_BUS 0 +#define I860MCH_DEVFN ((0x00 << 3) + 0) + +#define I860HUBA_BUS 0 +#define I860HUBA_DEVFN ((0x01 << 3) + 0) + +#define I860HUBB_BUS 0 +#define I860HUBB_DEVFN ((0x02 << 3) + 0) + +#define SMBUS_MEM_DEVICE_0 (0xa << 3) + +#define TSCYCLE_SLOW 1000 /* ns */ +#define TSCYCLE_FAST 10 /* ns */ +void ndelay(unsigned long); + +#define I860_MCH_BUS 0 +#define I860_MCH_DEVFN 0 + +#define MCH_GAR0 0x40 +#define MCH_GAR1 0x41 +#define MCH_GAR2 0x42 +#define MCH_GAR3 0x43 +#define MCH_GAR4 0x44 +#define MCH_GAR5 0x45 +#define MCH_GAR6 0x46 +#define MCH_GAR7 0x47 +#define MCH_GAR8 0x48 +#define MCH_GAR9 0x49 +#define MCH_GAR10 0x4a +#define MCH_GAR11 0x4b +#define MCH_GAR12 0x4c +#define MCH_GAR13 0x4d +#define MCH_GAR14 0x4e +#define MCH_GAR15 0x4f +#define MCH_MCHCFG 0x50 +#define MCH_FDHC 0x58 +#define MCH_PAM0 0x59 +#define MCH_PAM1 0x5a +#define MCH_PAM2 0x5b +#define MCH_PAM3 0x5c +#define MCH_PAM4 0x5d +#define MCH_PAM5 0x5e +#define MCH_PAM6 0x5f +#define MCH_GBA0 0x60 +#define MCH_GBA1 0x62 +#define MCH_GBA2 0x64 +#define MCH_GBA3 0x66 +#define MCH_GBA4 0x68 +#define MCH_GBA5 0x6a +#define MCH_GBA6 0x6c +#define MCH_GBA7 0x6e +#define MCH_GBA8 0x70 +#define MCH_GBA9 0x72 +#define MCH_GBA10 0x74 +#define MCH_GBA11 0x76 +#define MCH_GBA12 0x78 +#define MCH_GBA13 0x7a +#define MCH_GBA14 0x7c +#define MCH_GBA15 0x7e +#define MCH_RDPS 0x88 +#define MCH_DRD 0x90 +#define MCH_RICM 0x94 +#define MCH_SMRAM 0x9d +#define MCH_ESMRAM 0x9e +#define MCH_RDT 0xbe +#define MCH_TOM 0xc4 +#define MCH_ERRSTS 0xc8 +#define MCH_ERRCMD 0xca +#define MCH_SMICMD 0xcc +#define MCH_SCICMD 0xce +#define MCH_DRAMRC 0xdc +#define MCH_DERRCTL 0xe2 +#define MCH_EAP 0xe4 + +#define RICM_BUSY (1 << 23) +#define RICM_DONE (1 << 27) + + +#define __S(NAME) NAME##_SHIFT +#define __B(NAME) NAME##_BITS +#define __BIT_MASK(SHIFT, BITS) ((1 << (BITS + SHIFT)) - (1 << (SHIFT))) +#define MASK(NAME) __BIT_MASK(__S(NAME), __B(NAME)) +#define NVAL(NAME, VAL) (MASK(NAME) & ((VAL) << __S(NAME))) +#define VAL(NAME, VALUE) ((MASK(NAME) & VALUE) >> __S(NAME)) + +#define RICM_CMD_SHIFT 0 +#define RICM_CMD_BITS 5 +#define RICM_ADDR_SHIFT 5 +#define RICM_ADDR_BITS 5 +#define RICM_REG_SHIFT 10 +#define RICM_REG_BITS 9 +#define RICM_BROADCAST_SHIFT 19 +#define RICM_BROADCAST_BITS 1 +#define RICM_CHANNEL_SHIFT 20 +#define RICM_CHANNEL_BITS 2 + +#define CMD_RDRAM_READ_REG 0 +#define CMD_RDRAM_WRITE_REG 1 +#define CMD_RDRAM_SET_RESET 2 +#define CMD_SET_FAST_CLK 4 +#define CMD_TEMP_CALIBRATE_ENABLE 5 +#define CMD_TEMP_CALIBRATE 6 +#define CMD_MRH_REDIRECT_NEXT_SIO 8 +#define CMD_MRH_STICK_SIO_RESET 9 +#define CMD_RDRAM_CLEAR_RESET 11 +#define CMD_RDRAM_CURRENT_CALIBRATION 16 +#define CMD_RDRAM_SIO_RESET 17 +#define CMD_RDRAM_POWERDOWN_EXIT 18 +#define CMD_RDRAM_POWERDOWN_ENTRY 19 +#define CMD_RDRAM_NAP_ENTRY 20 +#define CMD_RDRAM_NAP_EXIT 21 +#define CMD_RDRAM_REFRESH 22 +#define CMD_RDRAM_PRECHARGE 23 +#define CMD_MANUAL_CURRENT_CALIBRATION 24 +#define CMD_MCH_RAC_LOAD_RACA_CONFIG 25 +#define CMD_MCH_RAC_LOAD_RACB_CONFIG 26 +#define CMD_MCH_INITIALIZE_RAC 27 +#define CMD_MCH_RAC_CURRENT_CALIBRATION 28 +#define CMD_MCH_RAC_TEMP_CALIBRATE 29 +#define CMD_POWERUP_ALL_SEQUENCE 31 + +#define REG_INIT 0x21 +#define REG_TEST34 0x22 +#define REG_CNFGA 0x23 +#define REG_CNFGB 0x24 +#define REG_DEVID 0x40 +#define REG_REFB 0x41 +#define REG_REFR 0x42 +#define REG_CCA 0x43 +#define REG_CCB 0x44 +#define REG_NAPX 0x45 +#define REG_PDNXA 0x46 +#define REG_PDNX 0x47 +#define REG_TPARM 0x48 +#define REG_TFRM 0x49 +#define REG_TCDLY1 0x4a +#define REG_SKIP 0x4b +#define REG_TCYCLE 0x4c +#define REG_TEST77 0x4d +#define REG_TEST78 0x4e +#define REG_TEST79 0x4f + +#define BCAST 0xffff + +static void rdram_wait_until_ready(void) +{ + u32 ricm; + do { + pcibios_read_config_dword(I860_MCH_BUS, I860_MCH_DEVFN, MCH_RICM, &ricm); + } while(ricm & RICM_BUSY); + ndelay(1000); /* delay after ready because the documentation says to */ +} + +/* rdram timing tables */ +static u16 tparm[5]={0x3a,0x3a,0x3a,0x4a,0x5a}; +static u16 tcdly1[5]={0,1,2,2,2}; + +/* serial presence detect needed variables */ +/* Byte 99 number of devices for each stick */ +static u8 spd_devices[4]={0,0,0,0}; +/* Byte 4 # of row address bits, # of column address bits */ +static u8 spd_row_col[4]={0,0,0,0}; +/* Byte 5 # of bank bits lower nibble */ +static u8 spd_banks[4]={0,0,0,0}; +/* Byte 9 Misc. Device configuration S28, and S3 bits are used */ +static u8 spd_misc_conf[4]={0,0,0,0}; +/* Byte 31 power down exit max time phase A (tPDNXA,max) */ +static u8 spd_pdnxa_max[4]={0,0,0,0}; +/* Byte 32 power down exit max time phase B (tPDNXB,max) */ +static u8 spd_pdnxb_max[4]={0,0,0,0}; +/* Byte 33 Map exit max time phase A (tNAPXA,max) */ +static u8 spd_napxa_max[4]={0,0,0,0}; +/* Byte 34 Nap exit max time phase B (tNAPXB,max) */ +static u8 spd_napxb_max[4]={0,0,0,0}; +/* Byte 12 Min ras to cas cycles */ +static u8 spd_rcd_min[4]={0,0,0,0}; +/* Byte 100 Module data width */ +static u8 spd_data_width[4]={0,0,0,0}; +/* Byte 35 bits 0-3<<8 + byte 37 give the rdram max mhz rate */ +static u16 spd_mhz_max[4]={0,0,0,0}; +/* Byte 35 bits 4-7<<4 + byte 36 give the rdram min mhz rate */ +static u16 spd_mhz_min[4]={0,0,0,0}; +/* The size of each device in mega bytes. */ +static u8 spd_size[2]={0,0}; + +int rdram_chips=0; /* number of ram chips on the rimms */ +static u32 total_rdram; /* Total rdram found */ + +/* register index tables */ +static u8 mch_gar[16] ={MCH_GAR0,MCH_GAR1,MCH_GAR2,MCH_GAR3,MCH_GAR4,MCH_GAR5, + MCH_GAR6,MCH_GAR7,MCH_GAR8,MCH_GAR9,MCH_GAR10,MCH_GAR11, + MCH_GAR12,MCH_GAR13,MCH_GAR14,MCH_GAR15}; + +static u8 mch_gba[16] ={MCH_GBA0,MCH_GBA1,MCH_GBA2,MCH_GBA3,MCH_GBA4,MCH_GBA5, + MCH_GBA6,MCH_GBA7,MCH_GBA8,MCH_GBA9,MCH_GBA10,MCH_GBA11, + MCH_GBA12,MCH_GBA13,MCH_GBA14,MCH_GBA15}; + +static void __rdram_run_command(u8 channel, u16 sdevice_id, u16 reg, u16 command) +{ + u32 ricm; + int broadcast; + + broadcast = 0; + if (sdevice_id == BCAST) { + broadcast = 1; + sdevice_id = 0; + } + + /* Read the old register value and modify it */ + pcibios_read_config_dword(I860_MCH_BUS, I860_MCH_DEVFN, MCH_RICM, &ricm); + ricm &= ~(MASK(RICM_CHANNEL) | MASK(RICM_BROADCAST) | MASK(RICM_ADDR) | + MASK(RICM_REG) | MASK(RICM_CMD)); + ricm |= NVAL(RICM_CHANNEL, channel); + ricm |= NVAL(RICM_BROADCAST, broadcast); + ricm |= NVAL(RICM_ADDR, sdevice_id); + ricm |= NVAL(RICM_REG, reg); + ricm |= NVAL(RICM_CMD, command); + + /* Write the command */ + pcibios_write_config_dword(I860_MCH_BUS, I860_MCH_DEVFN, MCH_RICM, ricm); + + /* Start the command running */ + ricm |= RICM_BUSY; + pcibios_write_config_dword(I860_MCH_BUS, I860_MCH_DEVFN, MCH_RICM, ricm); + + /* Wait until the command completes */ + rdram_wait_until_ready(); +} + +static void rdram_run_command(u8 channel, u16 sdevice_id, u16 command) +{ + /* Wait until the previous cmd completes */ + rdram_wait_until_ready(); + + /* Run the command */ + __rdram_run_command(channel, sdevice_id, 0, command); +} + +void rdram_read_reg(u8 channel, u16 sdevice_id, u16 reg, struct rdram_reg_values *res) +{ + u32 drd; + + /* Wait until the previous cmd completes */ + rdram_wait_until_ready(); + + __rdram_run_command(channel, sdevice_id, reg, CMD_RDRAM_READ_REG); + + /* Read back the register value */ + pcibios_read_config_dword(I860_MCH_BUS, I860_MCH_DEVFN, MCH_DRD, &drd); + + res->channel_a = (drd >> 16) &0xffff; + res->channel_b = drd & 0xffff; + return; +} + + +static void rdram_write_reg(u8 channel, u16 sdevice_id, u16 reg, + u16 channel_a, u16 channel_b) +{ + u32 drd; + + /* Wait until the previous cmd completes */ + rdram_wait_until_ready(); + + + /* Write the data values */ + drd = (((u32)channel_a) << 16) | channel_b; + pcibios_write_config_dword(I860_MCH_BUS, I860_MCH_DEVFN, MCH_DRD, drd); + + __rdram_run_command(channel, sdevice_id, reg, CMD_RDRAM_WRITE_REG); + + /* Wait until the command completes */ + rdram_wait_until_ready(); + + return; +} + +static void set_sdevid(int rdram_devices) +{ + int i; + /* First disable the repeater and set every RDRAM to the + * maximum address I can address + */ + rdram_write_reg(0, BCAST, REG_INIT, 0x1f, 0x1f); + for(i = 0; i < rdram_devices; i++) { + /* Set SDEVID and reenable the repeater */ + rdram_write_reg(0, 0x1f, REG_INIT, + (1 << 7) | (i & 0x1f), (1 << 7) | (i & 0x1f)); + + } +} + +static void set_devid(int rdram_devices) +{ + int i; + for(i = 0; i < rdram_devices; i++) { + /* FIXME make this smarter */ + /* Initially set DEVID == SDEVID */ + if ((i % 4) != 5) { + rdram_write_reg(0, i, REG_DEVID, i, i ); + } else { + rdram_write_reg(0, i, REG_DEVID, 0x1f, i); + } + } +} + +static void set_init_bits(int rdram_devices) +{ + int i; + for(i = 0; i < rdram_devices; i++) { + /* Now that the chip is up and running setup the + * power management modes. + */ + rdram_write_reg(0, i, REG_INIT, + (1 << 9) | (1 << 7) | (1 << 6) | (i & 0x1f), + (1 << 9) | (1 << 7) | (1 << 6) | (i & 0x1f) + ); + } +} + +static void rdram_read_domain_initialization(int rdram_devices) +{ + u8 rdt=0x8d; + int i,j,k; + u32 data; + u32 *mem; + u8 adj_a[32],adj_b[32]; + u8 l=20; + + total_rdram=0; + if((spd_rcd_min[0]==8)||(spd_rcd_min[1]==8)) + rdt=0x4d; + /* Set all the rdram devices to the fastest clock cycles */ + rdram_write_reg(0, BCAST, REG_TCDLY1, 0, 0 ); + rdram_write_reg(0, BCAST, REG_TPARM, 0x3a, 0x3a); + + /* find the slowest RDT timming */ + pcibios_write_config_byte(I860_MCH_BUS,I860_MCH_DEVFN,MCH_RDT,rdt); + mem=RAM_ADDR(0x100000); + for(j=0;j7) { + data-=00000004; + i=0; + } + mem[k]=data; + } + printk_debug("Device = %d, %x, %x\n",j,mem[0],mem[4]); + adj_a[j]=(mem[0]&0x0ff)-1; + adj_b[j]=(mem[4]&0x0ff)-1; + if(adj_a[j](16*TSCYCLE_SLOW)) + ndelay(delay); + else + ndelay(16*TSCYCLE_SLOW); + rdram_run_command(0, BCAST, CMD_RDRAM_CLEAR_RESET); + rdram_write_reg(0, BCAST, REG_TEST34, 0, 0); + rdram_write_reg(0, BCAST, REG_TEST78, 0, 0); +} + +/* + - ro CNFGA, CNFGB, + - ok REFB, REFR + - SKIP, TEST79 + TEST34, TEST78, + TEST77, + TCYCLE, + INIT, + DEVID, + PDNXA, PDNX, NAPX, TPARM, TCDLY1, TFRM, REG_CCA, REG, CCB +*/ +static void rdram_init(int rdram_devices) +{ + u16 tcycle; + u16 pdnxa,pdnxb,pdnx,napx,napxa,napxb; + u16 tfrm; + int i; + + /* 3.1/3.2 RDRAM SIO reset */ + rdram_run_command(0, 0, CMD_RDRAM_SIO_RESET); + + /* 3.3 Clear TEST77 */ + rdram_write_reg(0, BCAST, REG_TEST77, 0, 0); + + /* 3.4 Write Tcycle */ + /* Calculate the Tcycle */ + for(tcycle=spd_mhz_max[0],i=1;i<4;i++) + if(spd_mhz_max[i]&&(tcycle>spd_mhz_max[i])) + tcycle=spd_mhz_max[i]; + tcycle = 15625 / tcycle; + rdram_write_reg(0, BCAST, REG_TCYCLE, tcycle, tcycle); + printk_debug("Tcycle = %x\n",tcycle); + + /* 3.5 Set SDEVID */ + set_sdevid(rdram_devices); + + /* 3.6 Set DEVID */ + set_devid(rdram_devices); + + /* 3.7 Write PDNX, PDNXA Registers */ + /* tscycle=10ns or <= 100MHz MCH datasheet pg 156 */ + for(pdnxa=(u16)spd_pdnxa_max[0],i=1;i<4;i++) + if(pdnxa 10) + tfrm-=4; + } + else { + tfrm = 9; + } + rdram_write_reg(0, BCAST, REG_TFRM, tfrm, tfrm); + + /* 3.12 SETR/CLRR */ + rdram_set_clear_reset(); + + /* 3.13 Write CCA and CCB Registers */ + /* Program all Current controll registers with + * an initial approximation. 1/2 their maximum is recommended. + */ + rdram_write_reg(0, BCAST, REG_CCA, 0x40, 0x40); + rdram_write_reg(0, BCAST, REG_CCB, 0x40, 0x40); + + /* 3.14 Powerdown Exit */ + /* test is S28IECO is set, if yes power up ram from PDN state */ + if(spd_misc_conf[0]&4) + rdram_run_command(0, BCAST, CMD_RDRAM_POWERDOWN_EXIT); + + /* 3.15 SETF */ + rdram_run_command(0, BCAST, CMD_SET_FAST_CLK); +} + +void mch_init(void) +{ + u8 byte; + u16 word; + u16 top; + int bits1,bits2; + int reg,reg_last,dev; + + /* Program Group Attribute Registers */ + /* Calculate the GAR value */ + bits1=(spd_row_col[0]>>4)+(spd_row_col[0]&0x0f)+spd_banks[0]; + byte=0x80; + if(bits1==21) { + byte=0x84; + spd_size[0]=32; + } + else if(bits1==20) { + byte=0x82; + spd_size[0]=16; + } + if(byte!=0x80) { + if(spd_banks[0]==5) byte|=0x10; + if((spd_row_col[0]&0x0f)==7) byte|=0x40; + } + for(reg=dev=0;dev>4)+(spd_row_col[1]&0x0f)+spd_banks[1]; + byte=0x80; + if(bits2==21) { + byte=0x84; + spd_size[1]=32; + } + else if(bits2==20) { + byte=0x82; + spd_size[1]=16; + } + if(byte!=0x80) { + if(spd_banks[1]==5) byte|=0x10; + if((spd_row_col[1]&0x0f)==7) byte|=0x40; + } + for(dev=0;dev +#include +#include +#include "ide.h" + +static __inline__ int wait_for_notbusy(unsigned base) { + unsigned i = 0; + do { + if (((inb_p(IDE_REG_ERROR(base)) & 0x80) != 0x80) && + ((inb_p(IDE_REG_STATUS(base)) & 0x80) != 0x80)) + { + return 0; + } + i++; + } while (i != 0); + return 1; +} + +static __inline__ int wait_for_dataready(unsigned base) { + unsigned i = 0; + do { + if (((inb_p(IDE_REG_ERROR(base)) & 0x80) != 0x80) && + ((inb_p(IDE_REG_STATUS(base)) & 0x88) != 0x88)) + { + return 0; + } + i++; + } while (i != 0); + return 1; +} + +static __inline__ int write_command( + unsigned base, + ide_command_t command, + ide_cmd_param_t * params) +{ + if (wait_for_notbusy(base) != 0) return 1; + outb_p(params->precomp, IDE_REG_PRECOMP(base)); + outb_p(params->sector_count, IDE_REG_SECTOR_COUNT(base)); + outb_p(params->sector_number, IDE_REG_SECTOR_NUMBER(base)); + outb_p(params->cylinder & 0xFF, IDE_REG_CYLINDER_LSB(base)); + outb_p((params->cylinder >> 8) & 0x03, IDE_REG_CYLINDER_MSB(base)); + outb_p(params->drivehead, IDE_REG_DRIVEHEAD(base)); + if (wait_for_notbusy(base) != 0) return 1; + outb_p(command, IDE_REG_COMMAND(base)); + return 0; +} + +int ide_shutdown(void) +{ + outb_p(IDE_CMD_STANDBY_IMMEDIATE, IDE_REG_COMMAND(IDE_BASE1)); + outb_p(IDE_CMD_STANDBY_IMMEDIATE2, IDE_REG_COMMAND(IDE_BASE1)); + return 0; +} + +int ide_read_data(unsigned base, void * buf, size_t size) { + register unsigned short * ptr = (unsigned short *) buf; + if (wait_for_dataready(base)) { + printk_debug("data not ready...\n"); + return 1; + } + while (size > 1) { + *ptr++ = inw_p(IDE_REG_DATA(base)); + size -= sizeof(unsigned short); + } + return 0; +} + +int ide_write_data(unsigned base, void * buf, size_t size) { + register unsigned short * ptr = (unsigned short *) buf; + if (wait_for_dataready(base)) return 1; + while (size > 1) { + outw_p(*ptr, IDE_REG_DATA(base)); + ptr++; + size -= sizeof(unsigned short); + } + return 0; +} + +harddisk_info_t harddisk_info[NUM_HD]; + +static char buffer[512]; + +static int init_drive(unsigned base, int driveno) { + volatile int delay; + ide_cmd_param_t cmd = IDE_DEFAULT_COMMAND; + unsigned char command_val; + //unsigned int idx; + //int retval; + unsigned short* drive_info; + + harddisk_info[driveno].controller_port = base; + harddisk_info[driveno].num_heads = 0u; + harddisk_info[driveno].num_cylinders = 0u; + harddisk_info[driveno].num_sectors_per_track = 0u; + harddisk_info[driveno].num_sectors = 0ul; + harddisk_info[driveno].address_mode = IDE_DH_CHS; + harddisk_info[driveno].drive_exists = 0; + + cmd.drivehead = IDE_DH_DEFAULT | IDE_DH_HEAD(0) | IDE_DH_CHS | + IDE_DH_DRIVE(driveno); + write_command(base, IDE_CMD_GET_INFO, &cmd); + if ((inb_p(IDE_REG_STATUS(base)) & 1) != 0) { + /* Well, if that command didn't work, we probably don't have drive. */ + printk_debug("Drive %d: detect FAILED\n", driveno); + return 1; + } + ide_read_data(base, buffer, IDE_SECTOR_SIZE); + + /* Now suck the data out */ +#if 0 + harddisk_info[driveno].num_heads = *((unsigned short *) (buffer + 0x6E)); + harddisk_info[driveno].num_cylinders = *((unsigned short *) (buffer + 0x6C)); + harddisk_info[driveno].num_sectors_per_track = + *((unsigned short *) (buffer + 0x70)); + harddisk_info[driveno].num_sectors = *((unsigned int *) (buffer + 0x72)); +#else + drive_info = (unsigned short*)buffer; + harddisk_info[driveno].num_heads = drive_info[3]; + harddisk_info[driveno].num_cylinders = drive_info[1]; + harddisk_info[driveno].num_sectors_per_track = drive_info[6]; + harddisk_info[driveno].num_sectors = *((unsigned int*)&(drive_info[60])); +#endif + harddisk_info[driveno].drive_exists = 1; + + printk_debug(__FUNCTION__ " sectors_per_track=[%d], num_heads=[%d], num_cylinders=[%d]\n", + harddisk_info[driveno].num_sectors_per_track, + harddisk_info[driveno].num_heads, + harddisk_info[driveno].num_cylinders); + +#define HD harddisk_info[driveno] + if(drive_info[49] != 0) { + printk_debug("IDE%d %d/%d/%d cap: %04x\n", + (int)driveno, (int)HD.num_heads, (int)HD.num_cylinders, (int)HD.num_sectors_per_track, + (int) drive_info[49]); + } + +// printk_debug("drive %d detected heads=0x%X(%u) cyl=0x%X(%u) sec/trk=" +// "0x%X(%u) sects=0x%X(%u)\n", (int)driveno, (int)HD.num_heads, (int)HD.num_heads, +// HD.num_cylinders, (int)HD.num_cylinders, (int)HD.num_sectors_per_track, +// HD.num_sectors_per_track, (int)HD.num_sectors, (int)HD.num_sectors); + +// printk_debug" capability=[%04x]\n", (int)drive_info[49]); + + if (drive_info[49] & 0x200) { /* bit 9 of capability word is lba supported bit */ + harddisk_info[driveno].address_mode = IDE_DH_LBA; + } else { + harddisk_info[driveno].address_mode = IDE_DH_CHS; + } + // harddisk_info[driveno].address_mode = IDE_DH_CHS; + + /* Set up the Extended control register */ + if (harddisk_info[driveno].num_heads > 8) { + command_val = 0x0A; + } else { + command_val = 0x02; + } + + outb_p(command_val, IDE_REG_CONTROL(base)); + + /* Execute the drive diagnostics command */ + write_command(base, IDE_CMD_DRIVE_DIAG, &cmd); + if ((inb_p(IDE_REG_STATUS(base)) & 1) != 0) { + return 1; + } + + /* Reset the bus (again) */ + outb_p(cmd.drivehead, IDE_REG_DRIVEHEAD(base)); + outb_p(0x04, IDE_REG_CONTROL(base)); + for (delay = 0x100; delay > 0; --delay); + outb_p(command_val, IDE_REG_CONTROL(base)); + + /* Now do a drive recalibrate */ + write_command(base, IDE_CMD_RECALIBRATE, &cmd); + if ((inb_p(IDE_REG_STATUS(base)) & 1) != 0) { + return 1; + } + (void)wait_for_notbusy(base); + + /* Set device parameters */ + cmd.sector_count = harddisk_info[driveno].num_sectors_per_track; + cmd.drivehead = IDE_DH_DEFAULT | + IDE_DH_HEAD(harddisk_info[driveno].num_heads) | + IDE_DH_DRIVE(driveno) | + harddisk_info[driveno].address_mode; + write_command(base, IDE_CMD_SET_PARAMS, &cmd); + + /* Set multiple mode */ + cmd.sector_count = 0x10; /* Single-word DMA, mode 0 */ + cmd.drivehead = IDE_DH_DEFAULT | + IDE_DH_HEAD(0) | + IDE_DH_DRIVE(driveno) | + harddisk_info[driveno].address_mode; + write_command(base, IDE_CMD_SET_MULTIMODE, &cmd); + + /* Make sure command is still OK */ + outb_p(command_val, IDE_REG_CONTROL(base)); + + /* Set parameters _again_ */ + cmd.sector_count = harddisk_info[driveno].num_sectors_per_track; + cmd.drivehead = IDE_DH_DEFAULT | + IDE_DH_HEAD(harddisk_info[driveno].num_heads) | + IDE_DH_DRIVE(driveno) | + harddisk_info[driveno].address_mode; + write_command(base, IDE_CMD_SET_PARAMS, &cmd); + + /* Make sure command is still OK */ + outb_p(command_val, IDE_REG_CONTROL(base)); + +#if 0 + /* Exercise the drive to see if it works OK */ + printk_debug("Exercising HardDisk- buffer=0x%08lX\n", (unsigned long) buffer); + outb_p(0x42, 0xeb); + while (1) { + for (idx = 0; idx < harddisk_info[driveno].num_sectors; ++idx) { + outb_p(idx & 0xFF, 0x80); + retval = ide_read_sector(driveno, buffer, idx); + if (retval != 0) { + printk_debug("readsector(driveno=%d, sector=%lu) returned %d!\n", + driveno, (unsigned long) idx, retval); + } + } + printk_debug("Exercise complete!\n"); + outb(0x42, 0xeb); + } +#endif /* 0 */ + + return 0; +} + + +static int init_controller(unsigned base, int basedrive) { + volatile int delay; + + /* First, check to see if the controller even exists */ + outb_p(0x5, IDE_REG_SECTOR_COUNT(base)); + if (inb_p(IDE_REG_SECTOR_COUNT(base)) != 0x5) { + printk_debug("Controller %d: detect FAILED (1)\n", basedrive / 2); + return -1; + } + outb_p(0xA, IDE_REG_SECTOR_COUNT(base)); + if (inb_p(IDE_REG_SECTOR_COUNT(base)) != 0xA) { + printk_debug("Controller %d: detect FAILED (2)\n", basedrive / 2); + return -2; + } + + /* Reset the system */ + outb_p(0x4, IDE_REG_CONTROL(base)); + for (delay = 0x100; delay > 0; --delay); + outb_p(0x0, IDE_REG_CONTROL(base)); + + /* Now initialize the individual drives */ + init_drive(base, basedrive); + init_drive(base, basedrive+1); + + return 0; +} + + +int ide_init(void) { + + outb_p(0x42, 0xEB); +printk_debug ("I am now initializing the ide system\n"); + + if(init_controller(IDE_BASE1, 0) < 0) { + printk_debug ("Initializing the main controller failed!\n"); + /* error return error */ + return -1; + }; + +#if (NUM_HD > 3) + init_controller(IDE_BASE2, 2); +#endif + +#if (NUM_HD > 5) + init_controller(IDE_BASE3, 4); +#endif + +#if (NUM_HD > 7) + init_controller(IDE_BASE4, 6); +#endif + return 0; +} + +/* read a sector or a partial sector */ +int ide_read_sector(int drive, void * buffer, unsigned int block, int byte_offset, + int n_bytes) { + ide_cmd_param_t cmd = IDE_DEFAULT_COMMAND; + unsigned base; + unsigned char sect_buffer[IDE_SECTOR_SIZE]; + unsigned int track; + int status; + int address_mode = harddisk_info[drive].address_mode; + + /* + printk_debug(__FUNCTION__ " drive[%d], buffer[%08x], block[%08x], offset[%d], n_bytes[%d]\n", + drive, buffer, block, byte_offset, n_bytes); + */ +// printk_debug(__FUNCTION__ " block(%08x) to addr(%08x)\r", block, (int)buffer); + if ((drive < 0) || (drive >= NUM_HD) || + (harddisk_info[drive].drive_exists == 0)) + { + printk_debug("unknown drive\n"); + return 1; + } + base = harddisk_info[drive].controller_port; + + if (harddisk_info[drive].num_heads > 8) { + outb_p(0xA, IDE_REG_CONTROL(base)); + } else { + outb_p(0x2, IDE_REG_CONTROL(base)); + } + + cmd.sector_count = 1; + + if (address_mode == IDE_DH_CHS) { + track = block / harddisk_info[drive].num_sectors_per_track; + + cmd.sector_number = 1+(block % harddisk_info[drive].num_sectors_per_track); + cmd.cylinder = track / harddisk_info[drive].num_heads; + cmd.drivehead = IDE_DH_DEFAULT | + IDE_DH_HEAD(track % harddisk_info[drive].num_heads) | + IDE_DH_DRIVE(drive) | + IDE_DH_CHS; + /* + printk_debug(__FUNCTION__ " CHS: track=[%d], sector_number=[%d], cylinder=[%d]\n", + track, cmd.sector_number, cmd.cylinder); + */ + } else { +#if 1 + cmd.sector_number = block & 0xff; /* lower byte of block (lba) */ + cmd.cylinder = (block >> 8) & 0xffff; /* middle 2 bytes of block (lba) */ + cmd.drivehead = IDE_DH_DEFAULT | /* set bits that must be on */ + ((block >> 24) & 0x0f) | /* lower nibble of byte 3 of block */ + IDE_DH_DRIVE(drive) | + IDE_DH_LBA; +#else + cmd.sector_number = (block >> 24) & 0xff; /* byte 0 of block (lba) */ + cmd.cylinder = (block >> 8) & 0xffff; /* bytes 1 & 2 of block (lba) */ + cmd.drivehead = IDE_DH_DEFAULT | /* set bits that must be on */ + ((block >> 4) & 0x0f) | /* upper nibble of byte 3 of block */ + IDE_DH_DRIVE(drive) | + IDE_DH_LBA; +#endif + /* + printk_debug(__FUNCTION__ " LBA: drivehead[%0x], cylinder[%04x], sector[%0x], block[%8x]\n", + cmd.drivehead, cmd.cylinder, cmd.sector_number, block & 0x0fffffff); + */ + } + + write_command(base, IDE_CMD_READ_MULTI_RETRY, &cmd); + if ((inb_p(IDE_REG_STATUS(base)) & 1) != 0) { + printk_debug("ide not ready...\n"); + return 1; + } + if (n_bytes != IDE_SECTOR_SIZE) { + status = ide_read_data(base, sect_buffer, IDE_SECTOR_SIZE); + if (status == 0) { + memcpy(buffer, sect_buffer+byte_offset, n_bytes); + } + } else { + status = ide_read_data(base, buffer, IDE_SECTOR_SIZE); + } + // printk_debug(__FUNCTION__ " status = [%d]\n", status); + return status; +} + +#if 0 +/* read a sector or a partial sector */ +int ide_read_sector(int drive, void * buffer, unsigned int block, int byte_offset, + int n_bytes) { + ide_cmd_param_t cmd = IDE_DEFAULT_COMMAND; + unsigned base; + unsigned char sect_buffer[IDE_SECTOR_SIZE]; + unsigned int track; + int status; + + if ((drive < 0) || (drive >= NUM_HD) || + (harddisk_info[drive].drive_exists == 0)) + { + return 1; + } + base = harddisk_info[drive].controller_port; + + if (harddisk_info[drive].num_heads > 8) { + outb_p(0xA, IDE_REG_CONTROL(base)); + } else { + outb_p(0x2, IDE_REG_CONTROL(base)); + } + + track = block / harddisk_info[drive].num_sectors_per_track; + + cmd.sector_count = 1; + cmd.sector_number = 1+(block % harddisk_info[drive].num_sectors_per_track); + cmd.cylinder = track % harddisk_info[drive].num_heads; + cmd.drivehead = IDE_DH_DEFAULT | + IDE_DH_HEAD(track / harddisk_info[drive].num_heads) | + IDE_DH_DRIVE(drive) | + IDE_DH_CHS; + +// printk_debug(__FUNCTION__ " track=[%d], sector_number=[%d], cylinder=[%d]\n", +// track, cmd.sector_number, cmd.cylinder); + write_command(base, IDE_CMD_READ_MULTI_RETRY, &cmd); + if ((inb_p(IDE_REG_STATUS(base)) & 1) != 0) { + return 1; + } + if (n_bytes != IDE_SECTOR_SIZE) { + status = ide_read_data(base, sect_buffer, IDE_SECTOR_SIZE); + if (status == 0) { + memcpy(buffer, sect_buffer+byte_offset, n_bytes); + } + } else { + status = ide_read_data(base, buffer, IDE_SECTOR_SIZE); + } +// printk_debug(__FUNCTION__ " status = [%d]\n", status); + return status; +} +#endif diff --git a/src/rom/Config b/src/rom/Config index 088be8447f..26940325dd 100644 --- a/src/rom/Config +++ b/src/rom/Config @@ -1,7 +1,9 @@ -object fill_inbuf.o -object rom_fill_inbuf.o -object docmil_fill_inbuf.o -#object docplus_fill_inbuf.o -object tsunami_tigbus_rom_fill_inbuf.o -object serial_fill_inbuf.o -object tftp_fill_inbuf.o +driver rom_fill_inbuf.o USE_GENERIC_ROM +driver docmil_fill_inbuf.o +#driver docplus_fill_inbuf.o +driver tsunami_tigbus_rom_fill_inbuf.o USE_TSUNAMI_TIGBUS_ROM +driver serial_fill_inbuf.o USE_SERIAL_FILL_INBUF +driver tftp_fill_inbuf.o USE_TFTP +driver floppy_fill_inbuf.o BOOT_FLOPPY +driver ide_fill_inbuf.o BOOT_IDE +#object read_bytes.o diff --git a/src/rom/docmil_fill_inbuf.c b/src/rom/docmil_fill_inbuf.c index 229c216f5d..9916da0771 100644 --- a/src/rom/docmil_fill_inbuf.c +++ b/src/rom/docmil_fill_inbuf.c @@ -20,6 +20,10 @@ #define DOC_MIL_BASE 0xffffe000 #endif +static unsigned char *inbuf; /* input buffer */ +static unsigned int insize; /* valid bytes in inbuf */ +static unsigned int inptr; /* index of next byte to be processed in inbuf */ + static unsigned char *nvram; static int block_count; static int firstfill = 1; @@ -53,7 +57,7 @@ reset_doc() } #endif -int +static int fill_inbuf(void) { #ifdef CHECK_DOC_MIL @@ -373,7 +377,7 @@ static int DoCMil_is_alias(volatile char *docptr1, volatile char *docptr2) } #if 0 -int WriteBlockECC(volatile char *docptr, unsigned int block, const char *buf) +static int WriteBlockECC(volatile char *docptr, unsigned int block, const char *buf) { unsigned char eccbuf[6]; volatile char dummy; @@ -458,7 +462,7 @@ int WriteBlockECC(volatile char *docptr, unsigned int block, const char *buf) } #endif -int ReadBlockECC( volatile unsigned char *docptr, unsigned int block, char *buf) +static int ReadBlockECC( volatile unsigned char *docptr, unsigned int block, char *buf) { int i, ret; volatile char dummy; @@ -591,4 +595,46 @@ memcpy_from_doc_mil(void *dest, const void *src, size_t n) } } + +/* FIXME this is a very lazy ugly port of the new interface to the doc millenium + * find a good way to implement this... + */ + +#define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf()) + +static int init_bytes(void) +{ + return; +} +static void fini_bytes(void) +{ + return; +} +static byte_offset_t read_bytes(void *vdest, byte_offset_t count) +{ + byte_offset_t bytes = 0; + unsigned char *dest = vdest; + while(bytes < count) { + *(dest++) = get_byte(); + } + return count; +} + +static byte_offset_t skip_bytes(byte_offset_t count) +{ + byte_offset_t bytes = 0; + while(bytes < count) { + unsigned char byte; + byte = get_byte(); + } + return count; +} + +static struct stream doc_mil_stream __stream = { + .init = init_bytes, + .read = read_bytes, + .skip = skip_bytes, + .fini = fini_bytes, +} + #endif /* USE_DOC_MIL */ diff --git a/src/rom/floppy_fill_inbuf.c b/src/rom/floppy_fill_inbuf.c new file mode 100644 index 0000000000..64c8b5b23e --- /dev/null +++ b/src/rom/floppy_fill_inbuf.c @@ -0,0 +1,44 @@ +#include +#include +#include +#include +#include + +#include +#include + +static unsigned long offset; + +static int init_bytes(void) +{ + offset = 0; + return floppy_init(); +} + +static void fini_bytes(void) +{ + floppy_fini(); +} + +static byte_offset_t read_bytes(void *vdest, byte_offset_t count) +{ + byte_offset_t len; + len = floppy_read(vdest, offset, count); + if (len > 0) { + offset += len; + } + return len; +} + +static byte_offset_t skip_bytes(byte_offset_t count) +{ + offset += count; + return count; +} + +static struct stream floppy_bytes __stream = { + .init = init_bytes, + .read = read_bytes, + .skip = skip_bytes, + .fini = fini_bytes, +}; diff --git a/src/rom/ide_fill_inbuf.c b/src/rom/ide_fill_inbuf.c new file mode 100644 index 0000000000..81ab000070 --- /dev/null +++ b/src/rom/ide_fill_inbuf.c @@ -0,0 +1,84 @@ +#include +#include +#include +#include +#include +#include + +#include +#include + +/* read a sector or a partial sector */ +extern int ide_read_sector(int drive, void * buffer, unsigned int block, int byte_offset, + int n_bytes); +extern int ide_init(void); + + + +static unsigned long offset; +static int init_bytes(void) +{ + int i; + printk_debug ("Trying polled ide\n"); + printk_debug ("Waiting for ide disks to spin up\n"); + printk_debug ("This is a hard coded delay and longer than necessary.\n"); + for(i = 0; i < 25; i++) { + printk_debug("."); + delay(1); + } + printk_debug("\n"); + offset = 0; + return ide_init(); +} + +static void fini_bytes(void) +{ + return; +} + +static byte_offset_t ide_read(void *vdest, byte_offset_t offset, byte_offset_t count) +{ + byte_offset_t bytes = 0; + unsigned char *dest = vdest; + while(bytes < count) { + unsigned int block, byte_offset, len; + int result; + block = offset / 512; + byte_offset = offset %512; + len = 512 - byte_offset; + if (len > (count - bytes)) { + len = (count - bytes); + } + result = ide_read_sector(0, dest, block , byte_offset, len); + if (result != 0) { + return bytes; + } + offset += len; + bytes += len; + dest += len; + } + return bytes; +} + +static byte_offset_t read_bytes(void *vdest, byte_offset_t count) +{ + byte_offset_t len; + len = ide_read(vdest, offset, count); + if (len > 0) { + offset += len; + } + return len; +} + +static byte_offset_t skip_bytes(byte_offset_t count) +{ + offset += count; + return count; +} + +static struct stream ide_stream __stream = { + .init = init_bytes, + .read = read_bytes, + .skip = skip_bytes, + .fini = fini_bytes, +}; diff --git a/src/rom/rom_fill_inbuf.c b/src/rom/rom_fill_inbuf.c index dc61c1ace9..81249a65e2 100644 --- a/src/rom/rom_fill_inbuf.c +++ b/src/rom/rom_fill_inbuf.c @@ -1,10 +1,8 @@ -#ifdef USE_GENERIC_ROM - #include #include #include #include -#include +#include #include @@ -16,102 +14,85 @@ #define ZKERNEL_MASK 0x0000ffff #endif +/* The inbuf copy option has been killed... */ + static unsigned char *zkernel_start = (unsigned char *)ZKERNEL_START; static unsigned long zkernel_mask = ZKERNEL_MASK; static unsigned char *nvram; static int block_count; -static int firstfill = 1; - -#if defined(INBUF_COPY) -static unsigned char *ram; -#endif +static int block_offset; #define K64 (64 * 1024) -int fill_inbuf(void) +static int init_bytes(void) { - extern unsigned char *inbuf; - extern unsigned int insize; - extern unsigned int inptr; + block_count = 0; + block_offset = 0; + nvram = zkernel_start; - if (firstfill) { - block_count = 0; - firstfill = 0; -#ifdef INBUF_COPY - ram = malloc(K64); -#endif - } + printk_debug("%6d:%s() - zkernel_start:0x%08x " + "zkernel_mask:0x%08x\n", + __LINE__, __FUNCTION__, + zkernel_start, zkernel_mask); - if (block_count > 31) { - printk_emerg( "%6d:%s() - overflowed source buffer\n", - __LINE__, __FUNCTION__); - inbuf = zkernel_start; - inptr = 0; - insize = 0; - return (0); - } - - if (!block_count) { - nvram = zkernel_start; - -#ifdef INBUF_COPY - if (!ram) { - printk_emerg("%6d:%s() - " - "ram malloc failed\n", - __LINE__, __FUNCTION__); - inbuf = zkernel_start; - inptr = 0; - insize = 0; - return (0); - } - - printk_debug("%6d:%s() - ram buffer:0x%08x\n", - __LINE__, __FUNCTION__, ram); -#endif - printk_debug("%6d:%s() - zkernel_start:0x%08x " - "zkernel_mask:0x%08x\n", - __LINE__, __FUNCTION__, - zkernel_start, zkernel_mask); - } else { - nvram += K64; - - while (!(zkernel_mask & (1 << block_count))) { - printk_debug("%6d:%s() - skipping block %d\n", - __LINE__, __FUNCTION__, block_count); - - block_count++; - nvram += K64; - - if (block_count > 31) { - printk_emerg("%6d:%s() - " - "overflowed source buffer\n", - __LINE__, __FUNCTION__); - inbuf = zkernel_start; - inptr = 0; - insize = 1; - return (0); - } - } - } - -#ifdef INBUF_COPY - memcpy(ram, nvram, K64); -#endif - printk_debug("%6d:%s() - nvram:0x%p block_count:%d\n", - __LINE__, __FUNCTION__, nvram, block_count); - -#ifdef INBUF_COPY - inbuf = ram; -#else - inbuf = nvram; -#endif - insize = K64; - inptr = 1; - post_code(0xd0 + block_count); - block_count++; - return inbuf[0]; + return 0; } -#endif /* USE_GENERIC_ROM */ +static void fini_bytes(void) +{ + return; +} + +static byte_offset_t rom_read_bytes(int cp, void *vdest, byte_offset_t count) +{ + unsigned char *dest = vdest; + byte_offset_t bytes = 0; + while (bytes < count) { + int length; + if (block_offset == K64) { + block_offset = 0; + block_count++; + nvram+= K64; + } + if (!(zkernel_mask & (1 << block_count))) { + printk_debug("%6d:%s() - skipping block %d\n", + __LINE__, __FUNCTION__, block_count); + continue; + } + if (block_count > 31) { + printk_emerg( "%6d:%s() - overflowed source buffer\n", + __LINE__, __FUNCTION__); + return bytes; + } + length = K64 - block_offset; + if (length > count) { + length = count; + } + if (cp) { + memcpy(dest, nvram + block_offset, length); + } + dest += length; + block_offset += length; + bytes += length; + } + return bytes; +} + +static byte_offset_t skip_bytes(byte_offset_t count) +{ + return rom_read_bytes(0, 0, count); +} + +static byte_offset_t read_bytes(void *vdest, byte_offset_t count) +{ + return rom_read_bytes(1, vdest, count); +} + +static struct stream rom_stream __stream = { + .init = init_bytes, + .read = read_bytes, + .skip = skip_bytes, + .fini = fini_bytes, +}; diff --git a/src/rom/serial_fill_inbuf.c b/src/rom/serial_fill_inbuf.c index 02e2f415e8..654418153d 100644 --- a/src/rom/serial_fill_inbuf.c +++ b/src/rom/serial_fill_inbuf.c @@ -1,32 +1,36 @@ -#ifdef USE_SERIAL_FILL_INBUF - #include #include #include #include -#include +#include #include #include -static int firstfill = 1; -static unsigned char *ram; - -#define K64 (64*1024) - -int fill_inbuf(void) +static int init_bytes(void) { - int rc; - if (firstfill) { - firstfill = 0; - ram = malloc(K64); + return 0; +} +static void fini_bytes(void) +{ +} +static byte_offset_t read_bytes(void *vdest, byte_offset_t count) +{ + return ttys0_rx_bytes(vdest, count); +} +static byte_offset_t skip_bytes(byte_offset_t count) +{ + int64_t i; + for(i = 0; i < count; i++) { + unsigned char byte; + byte = ttys0_rx_byte(); } - inbuf = ram; - insize = ttys0_rx_bytes(inbuf, K64); - inptr = 1; - return inbuf[0]; } - -#endif /* USE_SERIAL_FILL_INBUF */ +static struct stream serial_stream __stream = { + .init = init_bytes, + .read = read_bytes, + .skip = skip_bytes, + .fini = fini_bytes, +}; diff --git a/src/rom/tftp_fill_inbuf.c b/src/rom/tftp_fill_inbuf.c index b6246b57b7..ccea04c126 100644 --- a/src/rom/tftp_fill_inbuf.c +++ b/src/rom/tftp_fill_inbuf.c @@ -1,54 +1,79 @@ -#ifdef USE_TFTP - #include #include #include #include #include -#include +#include -#ifndef DOC_KERNEL_START -#define DOC_KERNEL_START 65536 -#endif +static int block_bytes; +static int block_offset; +static unsigned char *buffer; +static int keof; -static unsigned char *nvram; -static int block_count; -static int firstfill = 1; +extern int tftp_init(const char *name); -static void memcpy_from_doc_mil(void *dest, const void *src, size_t n); -static unsigned char *doc_mil = (unsigned char *) 0xffffe000; -#ifdef CHECK_DOC_MIL -static unsigned char *checkbuf; -#endif /* CHECK_DOC_MIL */ - -static unsigned char *ram; -#define K64 (64 * 1024) - - -int fill_inbuf(void) +static int init_bytes(void) { - extern unsigned char *inbuf; - extern unsigned int insize; - extern unsigned int inptr; - - int rc; - static keof; - - if(keof) - return(-1); - - if(firstfill) { - tftp_init("vmlinux"); - block_count = 0; - firstfill = 0; - inbuf = ram = malloc(512); - keof=0; + tftp_init("vmlinux"); + block_bytes = 0; + block_offset = 0; + firstfill = 0; + buffer = malloc(512); + if (buffer == 0) { + return -1; } - - rc = tftp_fetchone(ram); - insize = rc; - inptr = 1; - return inbuf[0]; + keof=0; } -#endif // USE_TFTP +static void fini_bytes(void) +{ + free(buffer); + buffer = 0; +} + +static byte_offset_t tftp_read_bytes(int cp, void *vdest, byte_offset_t count) +{ + byte_offset_t bytes = 0; + unsigned char *dest = vdest; + if (keof) + return -1; + do { + int length; + if (block_bytes - block_offset == 0) { + block_offset = 0; + block_bytes = tftp_fetchone(buffer); + } + if (block_bytes <= 0) { + keof = 1; + return -1; + } + length = block_bytes - block_offset; + if (length > count) { + length = count; + } + + if (cp) { + memcpy(dest, buffer, + block_offset, length); + } + block_offset += length; + dest += length; + } while (bytes < count); + return bytes; +} + +static byte_offset_t skip_bytes(byte_offset_t count) +{ + return tftp_read_bytes(0, 0, count); +} +static byte_offset_t read_bytes(void *vdest, byte_offset_t count) +{ + return tftp_read_bytes(1, vdest, count); +} + +static struct stream tftp_stream __stream = { + .init = init_bytes, + .read = read_bytes, + .skip = skip_bytes, + .fini = fini_bytes, + +}; diff --git a/src/rom/tsunami_tigbus_rom_fill_inbuf.c b/src/rom/tsunami_tigbus_rom_fill_inbuf.c index 23ca86534c..46fde3d8ed 100644 --- a/src/rom/tsunami_tigbus_rom_fill_inbuf.c +++ b/src/rom/tsunami_tigbus_rom_fill_inbuf.c @@ -1,10 +1,8 @@ -#ifdef USE_TSUNAMI_TIGBUS_ROM - #include #include #include #include -#include +#include #include #include @@ -13,12 +11,7 @@ #define TIG_KERNEL_START 0x20000 #endif -static unsigned long nvram; -static int block_count; -static int firstfill = 1; -static unsigned char *ram; - -#define K64 (64 * 1024) +static unsigned long offset; #define MAX_TIG_FLASH_SIZE (16*1024*1024) static void tsunami_flash_copy_from(void *addr, unsigned long offset, long len) @@ -34,65 +27,49 @@ static void tsunami_flash_copy_from(void *addr, unsigned long offset, long len) } } -int fill_inbuf(void) +static int init_bytes(void) { - extern unsigned char *inbuf; - extern unsigned int insize; - extern unsigned int inptr; - - if (firstfill) { - block_count = 0; - firstfill = 0; - ram = malloc(K64); - if (!ram) { - printk_emerg("%6d:%s() - " - "ram malloc failed\n", - __LINE__, __FUNCTION__); - return 0; - } + offset = 0; + printk_debug("%6d:%s() - TIG_KERNEL_START:0x%08x\n", + __LINE__, __FUNCTION__, + TIG_KERNEL_START); +} +static void fini_bytes(void) +{ + return; +} +static byte_offset_t skip_bytes(byte_offset_t count) +{ + unsigned long new_offset; + byte_offset_t len; + new_offset = offset + count; + if (new_offset > MAX_TIG_FLASH_SIZE) { + new_offset = MAX_TIG_FLASH_SIZE; } - - if (block_count > 31) { - printk_emerg("%6d:%s() - overflowed source buffer\n", - __LINE__, __FUNCTION__); - insize = 0; - return (0); - } - if (!block_count) { - nvram = TIG_KERNEL_START; - printk_debug("%6d:%s() - ram buffer:0x%08x\n", - __LINE__, __FUNCTION__, ram); - printk_debug("%6d:%s() - TIG_KERNEL_START:0x%08x\n", - __LINE__, __FUNCTION__, - TIG_KERNEL_START); - } - - - tsunami_flash_copy_from(ram, nvram, K64); - printk_debug("\n%6d:%s() - nvram:0x%lx block_count:%d\n", - __LINE__, __FUNCTION__, nvram, block_count); - -#if 0 - { - int i; - for(i = 0; i < K64; i+= 16) { - printk_debug("%05x: %02x %02x %02x %02x %02x %02x %02x %02x " - "%02x %02x %02x %02x %02x %02x %02x %02x\n", - (block_count << 16)+i, - ram[i+0], ram[i+1], ram[i+2], ram[i+3], - ram[i+4], ram[i+5], ram[i+6], ram[i+7], - ram[i+8], ram[i+9], ram[i+10], ram[i+11], - ram[i+12], ram[i+13], ram[i+14],ram[i+15]); - } - } -#endif - nvram += K64; - inbuf = ram; - insize = K64; - inptr = 1; - post_code(0xd0 + block_count); - block_count++; - return inbuf[0]; + len = new_offset - offset; + offset = new_offset; + return len; } -#endif /* USE_TSUNAMI_TIGBUS_ROM */ +static byte_offset_t read_bytes(void *vdest, byte_offset_t count) +{ + long length; + length = MAX_TIG_FLASH_SIZE - offset; + if (count < 0) + count = 0; + if (count < length) { + length = count; + } + tsunami_flash_copy_from(vdest, offset, length); + offset += length; + return length; +} + + +static struct stream tsunami_tigbus_rom_stream __stream = { + .init = init_bytes, + .read = read_bytes, + .skip = skip_bytes, + .fini = fini_bytes, + +}; diff --git a/src/southbridge/intel/82801/ich2_power.c b/src/southbridge/intel/82801/ich2_power.c index 60925842f5..bebf55dddf 100644 --- a/src/southbridge/intel/82801/ich2_power.c +++ b/src/southbridge/intel/82801/ich2_power.c @@ -7,7 +7,6 @@ void ich2_power_after_power_fail(int on) { struct pci_dev *dev; - unsigned char byte; dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_1F0, 0); if (!dev) { return; diff --git a/src/southbridge/intel/82801/ich2_rtc.c b/src/southbridge/intel/82801/ich2_rtc.c index d567fb2876..f6b60ee1c4 100644 --- a/src/southbridge/intel/82801/ich2_rtc.c +++ b/src/southbridge/intel/82801/ich2_rtc.c @@ -15,7 +15,7 @@ void ich2_rtc_init(void) rtc_failed = byte & RTC_FAILED; if (rtc_failed) { byte &= ~(1 << 1); /* preserve the power fail state */ - pcibios_write_config_byte(RTC_BUS, RTC_DEVFN, GEN_PMCON_3, &byte); + pcibios_write_config_byte(RTC_BUS, RTC_DEVFN, GEN_PMCON_3, byte); } pcibios_read_config_dword(RTC_BUS, RTC_DEVFN, GEN_STS, &dword); rtc_failed |= dword & (1 << 2); diff --git a/util/config/NLBConfig.py b/util/config/NLBConfig.py index 481b8763f9..a8aaa80172 100644 --- a/util/config/NLBConfig.py +++ b/util/config/NLBConfig.py @@ -41,17 +41,17 @@ def add_main_rule_dependency(new_dependency): # this is a tuple, object name, source it depends on, # and an optional rule (can be empty) for actually building # the object -def addobject(object, sourcepath, rule, condition): - objectrules.append([object, topify(sourcepath), rule, condition]) +def addobject(object, sourcepath, rule, condition, variable): + objectrules.append([object, topify(sourcepath), rule, condition, variable]) # OK, let's face it, make sucks. # if you have a rule like this: # a.o: /some/long/path/a.c # make won't apply the .c.o rule. Toy! -def addobject_defaultrule(object, sourcepath, condition): +def addobject_defaultrule(object, sourcepath, condition, variable): defaultrule = "\t $(CC) -c $(CFLAGS) -o $@ $<" - addobject(object, sourcepath, defaultrule, condition) + addobject(object, sourcepath, defaultrule, condition, variable) # for all these functions, you need: # the dir that the Config file is in @@ -136,7 +136,7 @@ def keyboard(dir, keyboard_name): if (debug): print "KEYBOARD" keyboard_dir = os.path.join(treetop, 'src', keyboard_name) - addobject_defaultrule('keyboard.o', keyboard_dir,'') + addobject_defaultrule('keyboard.o', keyboard_dir,'','OBJECTS') def cpu(dir, cpu_name): common_command_action(dir, 'cpu', cpu_name) @@ -165,7 +165,7 @@ def superio(dir, superio_name): # note that superio is w.r.t. treetop buildfullpath('superio', superio_name) dir = os.path.join(treetop, 'src', 'superio', superio_name) - addobject_defaultrule('superio.o', dir,'') + addobject_defaultrule('superio.o', dir,'','OBJECTS') # commands are of the form: # superio_name [name=val]* @@ -188,8 +188,8 @@ def nsuperio(dir, superio_commands): dir = os.path.join(treetop, 'src', 'superio', superio_name) object="superio_%s.o" % superio_decl_name superio_source = dir + "/superio.c" - addobject_defaultrule(object, superio_source,'') - addobject_defaultrule('nsuperio.o', "", '') + addobject_defaultrule(object, superio_source,'','OBJECTS') + addobject_defaultrule('nsuperio.o', "", '','OBJECTS') rest = m.group(2) superio_cmds = ''; m = command_re.match(rest) @@ -251,7 +251,15 @@ def object(dir, command): m = re.match("([^" + wspc + "]+)([" + wspc + "]([^" + wspc + "]*)|)", command) obj_name = m.group(1) condition = m.group(3) - addobject_defaultrule(obj_name, dir, condition) + addobject_defaultrule(obj_name, dir, condition,'OBJECTS') + +def driver(dir, command): + wspc = string.whitespace + m = re.match("([^" + wspc + "]+)([" + wspc + "]([^" + wspc + "]*)|)", command) + obj_name = m.group(1) + condition = m.group(3) + addobject_defaultrule(obj_name, dir, condition, 'DRIVERS') + # for eventual user-defined rules. # pattern is name : deps ; rule @@ -390,6 +398,7 @@ command_vals = { 'pcibridge' : [], # vendor, bridgename 'superio' : [], # vendor, superio name 'object' : {}, # path/filename.[cS] + 'driver' : {}, # path/filename.[cS] 'mainboardinit' : [], # set of files to include for mainboard init 'config_files' : [], # set of files we built the makefile from 'ldscripts' : [], # set of files we build the linker script from @@ -408,6 +417,7 @@ command_actions = { 'superio' : superio, 'nsuperio' : nsuperio, 'object' : object, + 'driver' : driver, 'linux' : linux, 'payload' : payload, 'raminit' : raminit, @@ -595,13 +605,15 @@ def writemakefile(path): # print out all the object dependencies # There is ALWAYS a crt0.o file.write("OBJECTS-1 := crt0.o\n") + file.write("DRIVERS-1 :=\n") for i in range(len(objectrules)): obj_name = objectrules[i][0] obj_cond = objectrules[i][3] + obj_var = objectrules[i][4] if not obj_cond : - file.write("OBJECTS-1 += %s\n" % (obj_name)) + file.write("%s-1 += %s\n" % (obj_var, obj_name)) else: - file.write("OBJECTS-$(%s) += %s\n" % (obj_cond, obj_name)) + file.write("%s-$(%s) += %s\n" % (obj_var, obj_cond, obj_name)) # print out all ldscript.ld dependencies file.write("LDSUBSCRIPTS-1 := \n" )