From 65bfc16139b8eb8b39229a0a9d6ef79aedf4d84f Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Thu, 10 Oct 2002 23:55:18 +0000 Subject: [PATCH] src/northbridge/intel/E7500/{sync the directory} src/ram/ramtest.inc{Add movnti ... } src/southbridge/intel/82801ca/{sync the directory} src/southbridge/intel/82870/{sync the directory} src/southbridge/via/vt8231/southgbridge.c - Transform intel_conf_xxx into pcibios_xxxx src/southbridge/via/v82c686/southgbridge.c - Transform intel_conf_xxx into pcibios_xxxx src/winbond/w83627hf/Config - Enable the hardware monitor - Add support for turning on the power_led util/config/NLBConfig.py - Add support for object .c - Add support for object .S - recode how the list of source files is built up. util/lb-dump/dump_lb_table.c - Fix the memory size abreviations --- src/northbridge/intel/E7500/Config | 6 +- src/northbridge/intel/E7500/northbridge.c | 80 +- src/northbridge/intel/E7500/raminit.inc | 2692 ++++++++++------- src/northbridge/intel/E7500/reset_test.inc | 8 +- src/northbridge/intel/E7500/sdram_enable.inc | 168 +- src/ram/ramtest.inc | 13 +- src/ram/spotcheck.inc | 95 + src/sdram/generic_dump_smbus.inc | 37 + src/southbridge/intel/82801ca/82801.h | 5 + src/southbridge/intel/82801ca/ich3_smbus.c | 99 +- src/southbridge/intel/82801ca/nvram.c | 1 - src/southbridge/intel/82801ca/smbus.inc | 168 +- .../intel/82801ca/smbus_noop_read_block.inc | 83 + .../intel/82801ca/smbus_print_block.inc | 86 + .../intel/82801ca/smbus_read_block.inc | 91 + .../intel/82801ca/smbus_write_block.inc | 90 + src/southbridge/intel/82870/82870.h | 5 + src/southbridge/intel/82870/Config | 1 + src/southbridge/intel/82870/p64h2_ioapic.c | 99 +- src/southbridge/intel/82870/p64h2_pcibridge.c | 38 + src/southbridge/via/vt8231/southbridge.c | 22 +- src/southbridge/via/vt82c686/southbridge.c | 2 +- src/superio/winbond/w83627hf/Config | 1 + src/superio/winbond/w83627hf/power_led.c | 22 + src/superio/winbond/w83627hf/superio.c | 16 +- util/config/NLBConfig.py | 42 +- util/lb-dump/dump_lb_table.c | 12 +- 27 files changed, 2657 insertions(+), 1325 deletions(-) create mode 100644 src/ram/spotcheck.inc create mode 100644 src/sdram/generic_dump_smbus.inc create mode 100644 src/southbridge/intel/82801ca/smbus_noop_read_block.inc create mode 100644 src/southbridge/intel/82801ca/smbus_print_block.inc create mode 100644 src/southbridge/intel/82801ca/smbus_read_block.inc create mode 100644 src/southbridge/intel/82801ca/smbus_write_block.inc create mode 100644 src/southbridge/intel/82870/p64h2_pcibridge.c create mode 100644 src/superio/winbond/w83627hf/power_led.c diff --git a/src/northbridge/intel/E7500/Config b/src/northbridge/intel/E7500/Config index 890686c62d..773304b4bf 100644 --- a/src/northbridge/intel/E7500/Config +++ b/src/northbridge/intel/E7500/Config @@ -1,9 +1,9 @@ -mainboardinit arch/i386/lib/set_memory_size_noop.inc +#mainboardinit cpu/i786/enable_sse.inc mainboardinit arch/i386/lib/cpu_reset.inc mainboardinit northbridge/intel/E7500/raminit.inc mainboardinit northbridge/intel/E7500/sdram_enable.inc mainboardinit sdram/generic_sdram.inc +#mainboardinit cpu/i786/disable_sse.inc +mainboardinit sdram/generic_cache_linuxbios.inc object northbridge.o -#object rdram_setup.o -#object rdram_debug.o diff --git a/src/northbridge/intel/E7500/northbridge.c b/src/northbridge/intel/E7500/northbridge.c index b6915aafca..8241eab8b2 100644 --- a/src/northbridge/intel/E7500/northbridge.c +++ b/src/northbridge/intel/E7500/northbridge.c @@ -3,23 +3,71 @@ #include #include #include +#include struct mem_range *sizeram(void) { static struct mem_range mem[4]; - uint16_t tolm, remapbase, remaplimit; + uint16_t tolm, remapbase, remaplimit, drb16; + uint16_t tolm_r, remapbase_r, remaplimit_r; uint8_t drb; + int remap_high; - /* FIXME do some of the configuration here instead of - * just reading it all out, and reporting it. + /* Calculate and report the top of low memory and + * any remapping. */ - /* Read the ram configruation registers */ - pcibios_read_config_word(0, 0, 0xc4, &tolm); - pcibios_read_config_word(0, 0, 0xc6, &remapbase); - remapbase &= 0x1FF; - pcibios_read_config_word(0, 0, 0xc8, &remaplimit); - remaplimit &= 0x1FF; + /* Test if the remap memory high option is set */ + remap_high = 0; + if(get_option(&remap_high, "remap_memory_high")){ + remap_high = 0; + } pcibios_read_config_byte(0, 0, 0x67, &drb); + drb16 = (uint16_t)drb; + if(remap_high && (drb16 > 0x08)) { + /* We only come here if we have at least 512MB of memory, + * so it is safe to hard code tolm. + */ + tolm = 0x2000; + if(drb16 > 0x0040) { + /* There is more than 4GB of memory put + * the remap window at the end of ram. + */ + remapbase = drb16; + remaplimit = remapbase + 0x38; + } + else { + remapbase = 0x0040; + remaplimit = remapbase + (drb16-8); + } + } + else { + tolm = (uint16_t)((pci_memory_base >> 16)&0x0f800); + if((tolm>>8) >= (drb16<<2)) { + tolm = (drb16<<10); + remapbase = 0x3ff; + remaplimit = 0; + } + else { + remapbase = drb16; + remaplimit = remapbase + ((0x0040-(tolm>>10))-1); + } + } + /* Write the ram configruation registers, + * preserving the reserved bits. + */ + pcibios_read_config_word(0, 0, 0xc4, &tolm_r); + tolm |= (tolm_r & 0x7ff); + pcibios_write_config_word(0, 0, 0xc4, tolm); + pcibios_read_config_word(0, 0, 0xc6, &remapbase_r); + remapbase |= (remapbase_r & 0xfc00); + pcibios_write_config_word(0, 0, 0xc6, remapbase); + pcibios_read_config_word(0, 0, 0xc8, &remaplimit_r); + remaplimit |= (remaplimit_r & 0xfc00); + pcibios_write_config_word(0, 0, 0xc8, remaplimit); + +#if 0 + printk_debug("mem info tolm = %x, drb = %x, pci_memory_base = %x, remap = %x-%x\n",tolm,drb,pci_memory_base,remapbase,remaplimit); +#endif mem[0].basek = 0; mem[0].sizek = 640; @@ -29,14 +77,14 @@ struct mem_range *sizeram(void) mem[2].basek = 0; mem[2].sizek = 0; if ((drb << 16) > (tolm << 6)) { - mem[2].basek = 4096*1024; - mem[2].sizek = (drb << 16) - mem[2].basek; - /* I know that the remap window always immediately follows - * the real top of memory. + /* We don't need to consider the remap window + * here because we put it immediately after the + * rest of ram. + * All we must do is calculate the amount + * of unused memory and report it at 4GB. */ - if (remapbase < remaplimit) { - mem[2].sizek = (remaplimit << 16) - mem[2].basek; - } + mem[2].basek = 4096*1024; + mem[2].sizek = (drb << 16) - (tolm << 6); } mem[3].basek = 0; mem[3].sizek = 0; diff --git a/src/northbridge/intel/E7500/raminit.inc b/src/northbridge/intel/E7500/raminit.inc index 5df9ce7b6a..31845180da 100644 --- a/src/northbridge/intel/E7500/raminit.inc +++ b/src/northbridge/intel/E7500/raminit.inc @@ -1,132 +1,32 @@ jmp intel_E7500_out -#define USE_SPD 0 - -#define CS_WRITE_BYTE(addr, byte) \ - movl $addr, %eax ; \ - movl $byte, %edx ; \ - PCI_WRITE_CONFIG_BYTE - -#define CS_WRITE_WORD(addr, word) \ - movl $addr, %eax ; \ - movl $word, %ecx ; \ - PCI_WRITE_CONFIG_WORD - -#define CS_WRITE_LONG(addr, dword) \ - movl $addr, %eax ; \ - movl $dword, %ecx ; \ - PCI_WRITE_CONFIG_DWORD - -#if 1 -#define DRB0 0x10 -#define DRB1 0x10 -#define DRB2 0x10 -#define DRB3 0x10 -#define DRB4 0x10 -#define DRB5 0x10 -#define DRB6 0x10 -#define DRB7 0x10 -#else -/* Conservative setting 8MB of ram on first DIMM... */ -#define DRB0 0x01 -#define DRB1 0x01 -#define DRB2 0x01 -#define DRB3 0x01 -#define DRB4 0x01 -#define DRB5 0x01 -#define DRB6 0x01 -#define DRB7 0x01 -#endif - -#define DRA0 0x0c -#define DRA1 0x0 -#define DRA2 0x0 -#define DRA3 0x0 -#define DRA4 0x0 -#define DRA5 0x0 -#define DRA6 0x0 -#define DRA7 0x0 +#define DEBUG_RAM_CONFIG 0 -#define CAS_LATENCY 3 +/* DDR DIMM Mode register Definitions */ - /* CAS latency 2 */ -#if (CAS_LATENCY == 2) -#define CAS_NB 0x17 - /* - * 7 == 0111 - * 1 == 0001 - */ -#define CAS_MODE 0x2a - /* - * a == 1010 - * 2 == 0010 - */ -#endif +#define BURST_2 (1<<0) +#define BURST_4 (2<<0) +#define BURST_8 (3<<0) - /* CAS latency 3 */ -#if (CAS_LATENCY == 3) -#define CAS_NB 0x13 - /* - * 3 == 0011 - * 1 == 0001 - */ -#define CAS_MODE 0x3a - /* - * a == 1010 - * 3 == 0011 - */ -#endif +#define BURST_SEQUENTIAL (0<<3) +#define BURST_INTERLEAVED (1<<3) -#ifndef CAS_NB -#error "Nothing defined" -#endif +#define CAS_2_0 (0x2<<4) +#define CAS_3_0 (0x3<<4) +#define CAS_1_5 (0x5<<4) +#define CAS_2_5 (0x6<<4) -#if 0 -#define RAM_READ 0x0400 -#else -#define RAM_READ 0x0000 -#endif +#define MODE_NORM (0 << 7) +#define MODE_DLL_RESET (2 << 7) +#define MODE_TEST (1 << 7) -#define DIMM0_BASE \ - xorl %eax, %eax +#define BURST_LENGTH BURST_4 +#define BURST_TYPE BURST_INTERLEAVED +#define CAS_LATENCY CAS_1_5 -#define DIMM_BASE(n) \ - movl $(0x60 + ((n) -1)), %eax ; \ - PCI_READ_CONFIG_BYTE ; \ - andl $0xFF, %eax ; \ - shll $26, %eax ; \ - -#define DIMM_READ \ - addl %ebx, %eax ; \ -#if 0 - movl (%eax), %edx ; \ - xorl $0xdff8, %eax ; \ -#endif - movl (%eax), %edx - -#define DIMM0_READ DIMM0_BASE ; DIMM_READ -#define DIMM1_READ DIMM_BASE(1) ; DIMM_READ -#define DIMM2_READ DIMM_BASE(2) ; DIMM_READ -#define DIMM3_READ DIMM_BASE(3) ; DIMM_READ -#define DIMM4_READ DIMM_BASE(4) ; DIMM_READ -#define DIMM5_READ DIMM_BASE(5) ; DIMM_READ -#define DIMM6_READ DIMM_BASE(6) ; DIMM_READ -#define DIMM7_READ DIMM_BASE(7) ; DIMM_READ - -#define DIMMS_READ_EBX_OFFSET \ - DIMM0_READ ; \ - DIMM1_READ ; \ - DIMM2_READ ; \ - DIMM3_READ ; \ - DIMM4_READ ; \ - DIMM5_READ ; \ - DIMM6_READ ; \ - DIMM7_READ - -#define DIMMS_READ(offset) \ - movl $offset, %ebx ; \ - DIMMS_READ_EBX_OFFSET +#define MRS_VALUE (MODE_NORM | CAS_LATENCY | BURST_TYPE | BURST_LENGTH) +#define EMRS_VALUE 0x000 #define MD_SHIFT 4 @@ -138,1003 +38,1737 @@ jmp intel_E7500_out #define RAM_COMMAND_CBR 0x6 #define RAM_COMMAND_NORMAL 0x7 -#define SET_RAM_COMMAND(command) \ - movl $0x7c, %eax ; \ - PCI_READ_CONFIG_BYTE ; \ - andl $0x8F, %eax ; \ - orl $((command) << 4), %eax ; \ - movl %eax, %edx ; \ - movl $0x7c, %eax ; \ +#define RAM_CMD(command, offset) \ + movl $(((offset) << (MD_SHIFT + 16))|((command << 4) & 0x70)), %ebx ; \ + CALLSP(do_ram_command) + +#define RAM_NOP() RAM_CMD(RAM_COMMAND_NOP, 0) +#define RAM_PRECHARGE() RAM_CMD(RAM_COMMAND_PRECHARGE, 0) +#define RAM_CBR() RAM_CMD(RAM_COMMAND_CBR, 0) +#define RAM_EMRS() RAM_CMD(RAM_COMMAND_EMRS, EMRS_VALUE) + +ram_cas_latency: + .byte CAS_2_5, CAS_2_0, CAS_1_5, CAS_2_5 +ram_mrs: + /* Read the cas latency setting */ + movl $0x78, %eax + PCI_READ_CONFIG_BYTE + /* Transform it into the form expected by SDRAM */ + shrl $4, %eax + andl $3, %eax + movb ram_cas_latency(%eax), %al + shll $(16+MD_SHIFT), %eax + orl %eax, %ebx + orl $((MODE_NORM | BURST_TYPE | BURST_LENGTH) << (16+MD_SHIFT)), %ebx + jmp do_ram_command + +#define RAM_MRS(dll_reset) \ + movl $((dll_reset << (8+MD_SHIFT+ 16))|((RAM_COMMAND_MRS <<4)& 0x70)), %ebx ; \ + CALLSP(ram_mrs) + +#define RAM_NORMAL() \ + movl $0x7c, %eax ;\ + PCI_READ_CONFIG_BYTE ;\ + andl $0x8F, %eax ;\ + orb $(RAM_COMMAND_NORMAL << 4), %al ;\ + movl %eax, %edx ;\ + movl $0x7c, %eax ;\ PCI_WRITE_CONFIG_BYTE -#if 0 -#define COMPUTE_CAS_MODE \ - movl $0x76, %eax ; \ - PCI_READ_CONFIG_BYTE ; \ - andl $0x4, %eax ; \ - xorl $0x4, %eax ; \ - shll $2, %eax ; \ - orl $0x2a, %eax ; \ - -#endif - -#define SET_RAM_MODE_REGISTER \ - SET_RAM_COMMAND(RAM_COMMAND_MRS) ; \ - COMPUTE_CAS_MODE ; \ - shll $3, %eax ; \ - movl %eax, %ebx ; \ - DIMMS_READ_EBX_OFFSET - -#if 0 -#define ASSERT_RAM_COMMAND() DIMMS_READ(RAM_READ) -#define ASSERT_MRS_RAM_COMMAND(mode) DIMMS_READ(mode) -#else -#define ASSERT_RAM_COMMAND() movl (0), %eax -#endif - -#if 0 -#if ! USE_SPD -#define ENABLE_REFRESH() \ - movl $(0x57), %eax ; \ - PCI_READ_CONFIG_BYTE ; \ - orb 0x1, %al ; \ - mov %al, %dl ; \ - movl $(0x57), %eax ; \ +#define RAM_RESET_DDR_PTR() \ + movl $0x88, %eax ;\ + PCI_READ_CONFIG_BYTE ;\ + orb $(1 << 4), %al ;\ + movl %eax, %edx ;\ + movl $0x88, %eax ;\ + PCI_WRITE_CONFIG_BYTE ;\ + movl $0x88, %eax ;\ + PCI_READ_CONFIG_BYTE ;\ + andb $~(1 << 4), %al ;\ + movl %eax, %edx ;\ + movl $0x88, %eax ;\ PCI_WRITE_CONFIG_BYTE - -#else /* USE_SPD */ -#define ENABLE_REFRESH() CALL_LABEL(spd_enable_refresh) -#endif -#else -#define ENABLE_REFRESH() \ - CS_WRITE_BYTE(0x7d, 0x02) ; \ - CS_WRITE_BYTE(0x7e, 0x45) ; \ - CS_WRITE_BYTE(0x7f, 0x20) +do_ram_command: +#if DEBUG_RAM_CONFIG >= 2 + movl %esp, %esi + movl %ebx, %edi + CONSOLE_DEBUG_TX_CHAR($'P') + CONSOLE_DEBUG_TX_CHAR($':') + CONSOLE_DEBUG_TX_HEX8(%bl) + CONSOLE_DEBUG_TX_CHAR($'\r') + CONSOLE_DEBUG_TX_CHAR($'\n') + movl %edi, %ebx + movl %esi, %esp +#endif + /* %ecx - initial address to read from */ + /* Compute the offset */ + movl %ebx, %ecx + shrl $16, %ecx + +1: + /* Set the ram command */ + movl $0x7c, %eax + PCI_READ_CONFIG_BYTE + andl $0x8F, %eax + orb %bl, %al + movl %eax, %edx + movl $0x7c, %eax + PCI_WRITE_CONFIG_BYTE + + /* Assert the command to the memory */ +#if DEBUG_RAM_CONFIG >= 2 + movl %esp, %esi + movl %ebx, %edi + CONSOLE_DEBUG_TX_CHAR($'R') + CONSOLE_DEBUG_TX_CHAR($':') + CONSOLE_DEBUG_TX_HEX32(%ecx) + CONSOLE_DEBUG_TX_CHAR($'\r') + CONSOLE_DEBUG_TX_CHAR($'\n') + movl %edi, %ebx + movl %esi, %esp +#endif + movl (%ecx), %eax + + /* Go to the next base address */ + addl $0x04000000, %ecx + + /* Increment the counter */ + incb %bh + + /* See if we are done */ + cmpb $8, %bh + jb 1b + +3: /* The command has been sent to all dimms so get out */ + RETSP + +#define ENABLE_REFRESH() \ + movl $0x7c, %eax ;\ + PCI_READ_CONFIG_DWORD ;\ + orl $(1 << 29), %eax ;\ + movl %eax, %ecx ;\ + mov $0x7c, %eax ;\ + PCI_WRITE_CONFIG_DWORD + + /* + * Table: constant_register_values + */ + .p2align 3 +constant_register_values: + /* SVID - Subsystem Vendor Identification Register + * 0x2c - 0x2d + * [15:00] Subsytem Vendor ID (Indicates system board vendor) + */ + /* SID - Subsystem Identification Register + * 0x2e - 0x2f + * [15:00] Subsystem ID + */ + .long 0x2c, 0, (0x15d9 << 0) | (0x3480 << 16) + + /* Undocumented + * 0x80 - 0x80 + * This register has something to do with CAS latencies, + * possibily this is the real chipset control. + * At 0x00 CAS latency 1.5 works. + * At 0x06 CAS latency 2.5 works. + * At 0x01 CAS latency 2.0 works. + */ +#if CAS_LATENCY == CAS_2_5 + .long 0x80, 0xfffffe00, 0x6 +#elif CAS_LATENCY == CAS_2_0 + .long 0x80, 0xfffffe00, 0x1 /* Stock BIOS has 0x0d? */ +#elif CAS_LATENCY == CAS_1_5 + .long 0x80, 0xfffffe00, 0x0 #endif -/* Default values for config registers */ - - /* NBXCFG 0x50 - 0x53 */ - /* f == 1111 - * 0 == 0000 - * 0 == 0000 - * 0 == 0000 - * 0 == 0000 - * 1 == 0001 - * 8 == 1000 - * c == 1100 - * SDRAM Row without ECC: - * row 0 == 1 No ECC - * row 1 == 1 No ECC - * row 2 == 1 No ECC - * row 3 == 1 No ECC - * row 4 == 1 No ECC - * row 5 == 1 No ECC - * row 6 == 1 No ECC - * row 7 == 1 No ECC - * Host Bus Fast Data Ready Enable == 0 Disabled - * IDSEL_REDIRECT == 0 (430TX compatibility disable?) - * WSC# Hanshake Disable == 0 enable (Use External IOAPIC) - * Host/DRAM Frequence == 00 100Mhz - * AGP to PCI Access Enable == 0 Disable - * PCI Agent to Aperture Access Disable == 0 Enable (Ignored) - * Aperture Access Global Enable == 0 Disable - * DRAM Data Integrity Mode == 11 (Error Checking/Correction) - * ECC Diagnostic Mode Enable == 0 Not Enabled - * MDA present == 0 Not Present - * USWC Write Post During During I/O Bridge Access Enable == 1 Enabled - * In Order Queue Depth (IQD) (RO) == ?? - */ -#if 0 -#define SET_NBXCFG \ - CS_WRITE_LONG(0x50, 0xff00018c) -#else -#define SET_NBXCFG \ - CS_WRITE_LONG(0x50, 0xff00000c) -#endif + /* Enable periodic memory recalibration */ + .long 0x88, 0xffffff00, 0x80 -#define SET_DRAMC \ - /* DRAMC */ \ - CS_WRITE_BYTE(0x57, 0x8) \ - /* 0 == 0000 \ - * 8 == 1000 \ - * Not registered SDRAM \ - * refresh disabled \ - */ - - /* PAM - Programmable Attribute Map Registers */ - /* Ideally we want to enable all of these as DRAM and teach - * linux it is o.k. to use them... - */ -#define SET_PAM \ - CS_WRITE_BYTE(0x59, 0x30) ; \ - CS_WRITE_BYTE(0x5a, 0x33) ; \ - CS_WRITE_BYTE(0x5b, 0x33) ; \ - CS_WRITE_BYTE(0x5c, 0x33) ; \ - CS_WRITE_BYTE(0x5d, 0x33) ; \ - CS_WRITE_BYTE(0x5e, 0x33) ; \ - CS_WRITE_BYTE(0x5f, 0x33) - -#define SET_DRB \ - /* DRB - DRAM Row Boundary Registers */ \ - CS_WRITE_BYTE(0x60, DRB0) ; \ - CS_WRITE_BYTE(0x61, DRB1) ; \ - CS_WRITE_BYTE(0x62, DRB2) ; \ - CS_WRITE_BYTE(0x63, DRB3) ; \ - CS_WRITE_BYTE(0x64, DRB4) ; \ - CS_WRITE_BYTE(0x65, DRB5) ; \ - CS_WRITE_BYTE(0x66, DRB6) ; \ - CS_WRITE_BYTE(0x67, DRB7) - -#define SET_DRA \ - /* DRA - DRAM Row Attribute Registers */ \ - CS_WRITE_BYTE(0x70, DRA0) ; \ - CS_WRITE_BYTE(0x71, DRA1) ; \ - CS_WRITE_BYTE(0x72, DRA2) ; \ - CS_WRITE_BYTE(0x73, DRA3) ; \ - CS_WRITE_BYTE(0x74, DRA4) ; \ - CS_WRITE_BYTE(0x75, DRA5) ; \ - CS_WRITE_BYTE(0x76, DRA6) ; \ - CS_WRITE_BYTE(0x77, DRA7) - - -#define SET_TOLM \ - /* TOLM - Top Of Low Memory Registers */ \ - CS_WRITE_BYTE(0xc4, 0x00) ; \ - CS_WRITE_BYTE(0xc5, 0x80) - -#define SET_DVNP \ - /* DVNP - Device Not Present Registers */ \ - CS_WRITE_BYTE(0xe0, 0x1e) - - - /* FDHC */ -#define SET_FDHC \ - CS_WRITE_BYTE(0x68, 0x00) - - -#if 0 - /* MBSC - Memory Buffer Strength Control */ - /* 00c00003e820 - * [47:44] 0 == 0000 - * [43:40] 0 == 0000 - * [39:36] c == 1100 - * [35:32] 0 == 0000 - * [31:28] 0 == 0000 - * [27:24] 0 == 0000 - * [23:20] 0 == 0000 - * [19:16] 3 == 0011 - * [15:12] e == 1110 - * [11: 8] 8 == 1000 - * [ 7: 4] 2 == 0010 - * [ 3: 0] 0 == 0000 - * MAA[14:0]#, WEA#, SRASA#, SCASA# Buffer Strengths == 3x - * MAB[14,13,10,12:11,9:0]#, WEB#, SRASB#, SCASB# Buffer Strengths == 1x - * MD[63:0]# Buffer Strength Control 2 == 1x - * MD[63:0]# Buffer Strength Control 1 == 1x - * MECC[7:0] Buffer Strength Control 2 == 1x - * MECC[7:0] Buffer Strength Control 1 == 1x - * CSB7# Buffer Strength == 1x - * CSA7# Buffer Strength == 1x - * CSB6# Buffer Strength == 1x - * CSA6# Buffer Strength == 1x - * CSA5#/CSB5# Buffer Strength == 1x - * CSA4#/CSB4# Buffer Strength == 1x - * CSA3#/CSB3# Buffer Strength == 2x - * CSA2#/CSB2# Buffer Strength == 2x - * CSA1#/CSB1# Buffer Strength == 2x - * CSA0#/CSB0# Buffer Strength == 2x - * DQMA5 Buffer Strength == 2x - * DQMA1 Buffer Strength == 2x - * DQMB5 Buffer Strength == 1x - * DQMB1 Buffer Strength == 1x - * DQMA[7:6,4:2,0] Buffer Strength == 2x - * GCKE Buffer Strength == 1x - * FENA Buffer Strength == 1x - */ - -#define SET_MBSC \ - CS_WRITE_BYTE(0x69, 0x20) ; \ - CS_WRITE_BYTE(0x6a, 0xe8) ; \ - CS_WRITE_BYTE(0x6b, 0x03) ; \ - CS_WRITE_BYTE(0x6c, 0x00) ; \ - CS_WRITE_BYTE(0x6d, 0xc0) ; \ - CS_WRITE_BYTE(0x6e, 0x00) -#else - /* MBSC - Memory Buffer Strength Control */ - /* 00c00003e820 - * [47:44] 0 == 0000 - * [43:40] 0 == 0000 - * [39:36] c == 1100 - * [35:32] 0 == 0000 - * [31:28] 0 == 0000 - * [27:24] 0 == 0000 - * [23:20] 0 == 0000 - * [19:16] 3 == 0011 - * [15:12] e == 1110 - * [11: 8] 8 == 1000 - * [ 7: 4] 2 == 0010 - * [ 3: 0] 0 == 0000 - * MAA[14:0]#, WEA#, SRASA#, SCASA# Buffer Strengths == 3x - * MAB[14,13,10,12:11,9:0]#, WEB#, SRASB#, SCASB# Buffer Strengths == 3x - * MD[63:0]# Buffer Strength Control 2 == 3x - * MD[63:0]# Buffer Strength Control 1 == 3x - * MECC[7:0] Buffer Strength Control 2 == 3x - * MECC[7:0] Buffer Strength Control 1 == 3x - * CSB7# Buffer Strength == 3x - * CSA7# Buffer Strength == 3x - * CSB6# Buffer Strength == 3x - * CSA6# Buffer Strength == 3x - * CSA5#/CSB5# Buffer Strength == 2x - * CSA4#/CSB4# Buffer Strength == 2x - * CSA3#/CSB3# Buffer Strength == 2x - * CSA2#/CSB2# Buffer Strength == 2x - * CSA1#/CSB1# Buffer Strength == 2x - * CSA0#/CSB0# Buffer Strength == 2x - * DQMA5 Buffer Strength == 2x - * DQMA1 Buffer Strength == 3x - * DQMB5 Buffer Strength == 2x - * DQMB1 Buffer Strength == 2x - * DQMA[7:6,4:2,0] Buffer Strength == 3x - * GCKE Buffer Strength == 1x - * FENA Buffer Strength == 3x - */ -#define SET_MBSC \ - CS_WRITE_BYTE(0x69, 0xB3) ; \ - CS_WRITE_BYTE(0x6a, 0xee) ; \ - CS_WRITE_BYTE(0x6b, 0xff) ; \ - CS_WRITE_BYTE(0x6c, 0xff) ; \ - CS_WRITE_BYTE(0x6d, 0xff) ; \ - CS_WRITE_BYTE(0x6e, 0x03) -#endif - - - /* 0x72 SMRAM */ - /* 1 == 0001 - * a == 1010 - * SMM Compatible base segment == 010 (Hardcoded value) - */ -#define SET_SMRAM - /* 0x73 ESMRAMC */ -#define SET_ESRAMC - - /* RPS - Row Page Size Register */ - /* 0x0055 - * [15:12] 0 == 0000 - * [11: 8] 0 == 0000 - * [ 7: 4] 5 == 0101 - * [ 3: 0] 5 == 0101 - * DRB[0] == 4KB - * DRB[1] == 4KB - * DRB[2] == 4KB - * DRB[3] == 4KB - * DRB[4] == 2KB - * DRB[5] == 2KB - * DRB[6] == 2KB - * DRB[7] == 2KB - */ -#define SET_RPS \ - CS_WRITE_WORD(0x74, 0x5555) - - /* SDRAMC */ -#define SET_SDRAMC \ - CS_WRITE_BYTE(0x76, CAS_NB) - - - /* PGPOL - Paging Policy Register */ - /* 0xff07 - * [15:12] f == 1111 - * [11: 8] f == 1111 - * [ 7: 4] 0 == 0000 - * [ 3: 0] 7 == 0111 - * row0 == 4banks - * row1 == 4banks - * row2 == 4banks - * row3 == 4banks - * row4 == 4banks - * row5 == 4banks - * row6 == 4banks - * row7 == 4banks - * Dram Idle Timer (DIT) == 32 clocks - */ -#define SET_PGPOL \ - CS_WRITE_WORD(0x78, 0xff07) - - /* MBFS - Memory Buffer Frequencey Select Register */ - /* 0xffff7f - * [23:20] f == 1111 - * [19:16] f == 1111 - * [15:12] f == 1111 - * [11: 8] f == 1111 - * [ 7: 4] 7 == 0111 - * [ 3: 0] f == 1111 - * MAA[14:0], WEA#, SRASA#, SCASA# == 100Mhz Buffers Enabled - * MAB[14,13,10,12:11,9:0], WEB#, SRASB#, SCASB# == 100Mhz Buffers Enabled - * MD[63:0] Control 2 == 100 Mhz Buffer Enable - * MD[63:0] Control 1 == 100 Mhz B - * MECC[7:0] Control 2 == 100 Mhz B + /* FDHC - Fixed DRAM Hole Control + * 0x58 + * [7:7] Hole_Enable + * 0 == No memory Hole + * 1 == Memory Hole from 15MB to 16MB + * [6:0] Reserved * + * PAM - Programmable Attribute Map + * 0x59 [1:0] Reserved + * 0x59 [5:4] 0xF0000 - 0xFFFFF + * 0x5A [1:0] 0xC0000 - 0xC3FFF + * 0x5A [5:4] 0xC4000 - 0xC7FFF + * 0x5B [1:0] 0xC8000 - 0xCBFFF + * 0x5B [5:4] 0xCC000 - 0xCFFFF + * 0x5C [1:0] 0xD0000 - 0xD3FFF + * 0x5C [5:4] 0xD4000 - 0xD7FFF + * 0x5D [1:0] 0xD8000 - 0xDBFFF + * 0x5D [5:4] 0xDC000 - 0xDFFFF + * 0x5E [1:0] 0xE0000 - 0xE3FFF + * 0x5E [5:4] 0xE4000 - 0xE7FFF + * 0x5F [1:0] 0xE8000 - 0xEBFFF + * 0x5F [5:4] 0xEC000 - 0xEFFFF + * 00 == DRAM Disabled (All Access go to memory mapped I/O space) + * 01 == Read Only (Reads to DRAM, Writes to memory mapped I/O space) + * 10 == Write Only (Writes to DRAM, Reads to memory mapped I/O space) + * 11 == Normal (All Access go to DRAM) */ -#define SET_MBFS \ - CS_WRITE_BYTE(0xca, 0xff) ; \ - CS_WRITE_BYTE(0xcb, 0xff) ; \ - CS_WRITE_BYTE(0xcc, 0x7f) + .long 0x58, 0xcccccf7f, (0x00 << 0) | (0x30 << 8) | (0x33 << 16) | (0x33 << 24) + .long 0x5C, 0xcccccccc, (0x33 << 0) | (0x33 << 8) | (0x33 << 16) | (0x33 << 24) - /* DWTC - DRAM Write Thermal Throttle Control */ -#define SET_DWTC \ - CS_WRITE_BYTE(0xe0, 0xb4) ; \ - CS_WRITE_BYTE(0xe1, 0xbe) ; \ - CS_WRITE_BYTE(0xe2, 0xff) ; \ - CS_WRITE_BYTE(0xe3, 0xd7) ; \ - CS_WRITE_BYTE(0xe4, 0x97) ; \ - CS_WRITE_BYTE(0xe5, 0x3e) ; \ - CS_WRITE_BYTE(0xe6, 0x00) ; \ - CS_WRITE_BYTE(0xe7, 0x80) + /* DRB - DRAM Row Boundary Registers + * 0x60 - 0x6F + * An array of 8 byte registers, which hold the ending + * memory address assigned to each pair of DIMMS, in 64MB + * granularity. + */ + /* Conservatively say each row has 64MB of ram, we will fix this up later */ + .long 0x60, 0x00000000, (0x01 << 0) | (0x02 << 8) | (0x03 << 16) | (0x04 << 24) + .long 0x64, 0x00000000, (0x05 << 0) | (0x06 << 8) | (0x07 << 16) | (0x08 << 24) + .long 0x68, 0xffffffff, 0 + .long 0x6C, 0xffffffff, 0 - /* DRTC - DRAM Read Thermal Throttle Control */ -#define SET_DRTC \ - CS_WRITE_BYTE(0xe8, 0x2c) ; \ - CS_WRITE_BYTE(0xe9, 0xd3) ; \ - CS_WRITE_BYTE(0xea, 0xf7) ; \ - CS_WRITE_BYTE(0xeb, 0xcf) ; \ - CS_WRITE_BYTE(0xec, 0x9d) ; \ - CS_WRITE_BYTE(0xed, 0x3e) ; \ - CS_WRITE_BYTE(0xee, 0x00) ; \ - CS_WRITE_BYTE(0xef, 0x00) + /* DRA - DRAM Row Attribute Register + * 0x70 Row 0,1 + * 0x71 Row 2,3 + * 0x72 Row 4,5 + * 0x73 Row 6,7 + * [7:7] Device width for Odd numbered rows + * 0 == 8 bits wide x8 + * 1 == 4 bits wide x4 + * [6:4] Row Attributes for Odd numbered rows + * 010 == 8KB + * 011 == 16KB + * 100 == 32KB + * 101 == 64KB + * Others == Reserved + * [3:3] Device width for Even numbered rows + * 0 == 8 bits wide x8 + * 1 == 4 bits wide x4 + * [2:0] Row Attributes for Even numbered rows + * 010 == 8KB + * 011 == 16KB + * 100 == 32KB + * 101 == 64KB (This page size appears broken) + * Others == Reserved + */ + .long 0x70, 0x00000000, \ + (((0<<3)|(0<<0))<< 0) | \ + (((0<<3)|(0<<0))<< 4) | \ + (((0<<3)|(0<<0))<< 8) | \ + (((0<<3)|(0<<0))<<12) | \ + (((0<<3)|(0<<0))<<16) | \ + (((0<<3)|(0<<0))<<20) | \ + (((0<<3)|(0<<0))<<24) | \ + (((0<<3)|(0<<0))<<28) + .long 0x74, 0xffffffff, 0 -/* PMCR -- BIOS sets 0x90 into it. - * 0x10 is REQUIRED. - * we have never used it. So why did this ever work? - */ -#define SET_PMCR \ - CS_WRITE_BYTE(0x7a, 0x90); + /* DRT - DRAM Time Register + * 0x78 + * [31:30] Reserved + * [29:29] Back to Back Write-Read Turn Around + * 0 == 3 clocks between WR-RD commands + * 1 == 2 clocks between WR-RD commands + * [28:28] Back to Back Read-Write Turn Around + * 0 == 5 clocks between RD-WR commands + * 1 == 4 clocks between RD-WR commands + * [27:27] Back to Back Read Turn Around + * 0 == 4 clocks between RD commands + * 1 == 3 clocks between RD commands + * [26:24] Read Delay (tRD) + * 000 == 7 clocks + * 001 == 6 clocks + * 010 == 5 clocks + * Others == Reserved + * [23:11] Reserved + * [10:09] Active to Precharge (tRAS) + * 00 == 7 clocks + * 01 == 6 clocks + * 10 == 5 clocks + * 11 == Reserved + * [08:06] Reserved + * [05:04] Cas Latency (tCL) + * 00 == 2.5 Clocks + * 01 == 2.0 Clocks + * 10 == 1.5 Clocks + * 11 == Reserved + * [03:03] Write Ras# to Cas# Delay (tRCD) + * 0 == 3 DRAM Clocks + * 1 == 2 DRAM Clocks + * [02:02] Reserved + * [01:01] Read RAS# to CAS# Delay (tRCD) + * 0 == 3 DRAM Clocks + * 1 == 2 DRAM Clocks + * [00:00] DRAM RAS# to Precharge (tRP) + * 0 == 3 DRAM Clocks + * 1 == 2 DRAM Clocks + */ +#define DRT_CAS_2_5 (0<<4) +#define DRT_CAS_2_0 (1<<4) +#define DRT_CAS_1_5 (2<<4) +#define DRT_CAS_MASK (3<<4) -#define SET_DRT \ - CS_WRITE_BYTE(0x78, 0x0f) ; \ - CS_WRITE_BYTE(0x79, 0x04) ; \ - CS_WRITE_BYTE(0x7a, 0x00) ; \ - CS_WRITE_BYTE(0x7b, 0x01) +#if CAS_LATENCY == CAS_2_5 +#define DRT_CL DRT_CAS_2_5 +#elif CAS_LATENCY == CAS_2_0 +#define DRT_CL DRT_CAS_2_0 +#elif CAS_LATENCY == CAS_1_5 +#define DRT_CL DRT_CAS_1_5 +#endif + /* Most aggressive settings possible */ + .long 0x78, 0xc0fff8c4, (1<<29)|(1<<28)|(1<<27)|(2<<24)|(2<<9)|DRT_CL|(1<<3)|(1<<1)|(1<<0) + + /* FIXME why was I attempting to set a reserved bit? */ + /* 0x0100040f */ + + /* DRC - DRAM Contoller Mode Register + * 0x7c + * [31:30] Reserved + * [29:29] Initialization Complete + * 0 == Not Complete + * 1 == Complete + * [28:22] Reserved + * [21:20] DRAM Data Integrity Mode + * 00 == Disabled, no ECC + * 01 == Reserved + * 10 == Error checking, using chip-kill, with correction + * 11 == Reserved + * [19:18] Reserved + * Must equal 01 + * [17:17] Reserved + * [16:16] Command Per Clock - Address/Control Assertion Rule (CPC) + * 0 == 2n Rule + * 1 == 1n rule + * [15:10] Reserved + * [09:08] Refresh mode select + * 00 == Refresh disabled + * 01 == Refresh interval 15.6 usec + * 10 == Refresh interval 7.8 usec + * 11 == Refresh interval 64 usec + * [07:07] Reserved + * [06:04] Mode Select (SMS) + * 000 == Self Refresh Mode + * 001 == NOP Command + * 010 == All Banks Precharge + * 011 == Mode Register Set + * 100 == Extended Mode Register Set + * 101 == Reserved + * 110 == CBR Refresh + * 111 == Normal Operation + * [03:00] Reserved + */ + .long 0x7c, 0xffcefcff, (2 << 20)|(1 << 16)| (0 << 8) + /* CLOCK_DIS - CK/CK# Disable Register + * 0x8C + * [7:4] Reserved + * [3:3] CK3 + * 0 == Enable + * 1 == Disable + * [2:2] CK2 + * 0 == Enable + * 1 == Disable + * [1:1] CK1 + * 0 == Enable + * 1 == Disable + * [0:0] CK0 + * 0 == Enable + * 1 == Disable + */ + .long 0x8C, 0xfffffff0, 0xf + + /* TOLM - Top of Low Memory Register + * 0xC4 - 0xC5 + * [15:11] Top of low memory (TOLM) + * The address below 4GB that should be treated as RAM, + * on a 128MB granularity. + * [10:00] Reserved + */ + /* REMAPBASE - Remap Base Address Regsiter + * 0xC6 - 0xC7 + * [15:10] Reserved + * [09:00] Remap Base Address [35:26] 64M aligned + * Bits [25:0] are assumed to be 0. + */ + .long 0xc4, 0xfc0007ff, (0x2000 << 0) | (0x3ff << 16) + /* REMAPLIMIT - Remap Limit Address Register + * 0xC8 - 0xC9 + * [15:10] Reserved + * [09:00] Remap Limit Address [35:26] 64M aligned + * When remaplimit < remapbase this register is disabled. + */ + .long 0xc8, 0xfffffc00, 0 + /* DVNP - Device Not Present Register + * 0xE0 - 0xE1 + * [15:05] Reserved + * [04:04] Device 4 Function 1 Present + * 0 == Present + * 1 == Absent + * [03:03] Device 3 Function 1 Present + * 0 == Present + * 1 == Absent + * [02:02] Device 2 Function 1 Present + * 0 == Present + * 1 == Absent + * [01:01] Reserved + * [00:00] Device 0 Function 1 Present + * 0 == Present + * 1 == Absent + */ + .long 0xe0, 0xffffffe2, (1<<4)|(1<<3)|(1<<2)|(0<<0) + +constant_register_values_end: + + /* + * Routine: ram_set_registers + * Arguments: none + * Results: none + * Trashed: %eax, %ebx, %ecx, %edx, %esi, %eflags + * Effects: Do basic ram setup that does not depend on serial + * presence detect information. + * This sets PCI configuration registers to known good + * values based on the table: + * constant_register_values + * Which are a triple of configuration regiser, mask, and value. + * + */ + /* DDR RECOMP/SCOMP table */ + .p2align 3 +ddr_rcomp_scomp_table: + /* register, function 2, function 3 */ + .long 0x054, 0x000000000, 0x000000000 + .long 0x058, 0x076433221, 0x076433221 + .long 0x05c, 0x0fedca988, 0x0fedca988 + .long 0x060, 0x0ffffffff, 0x0ffffffff + .long 0x064, 0x000000000, 0x000000000 + .long 0x068, 0x076433221, 0x076433221 + .long 0x06c, 0x0fedca988, 0x0fedca988 + .long 0x070, 0x0ffffffff, 0x0ffffffff + .long 0x084, 0x000000000, 0x099999999 + .long 0x088, 0x076433221, 0x099999999 + .long 0x08c, 0x0fedca988, 0x099999999 + .long 0x090, 0x0ffffffff, 0x099999999 + .long 0x094, 0x000000000, 0x0aaaaaaaa + .long 0x098, 0x076433221, 0x0aaaaaaaa + .long 0x09c, 0x0fedca988, 0x0aaaaaaaa + .long 0x0a0, 0x0ffffffff, 0x0aaaaaaaa + .long 0x0b4, 0x000000000, 0x000000000 + .long 0x0b8, 0x076433221, 0x076433221 + .long 0x0bc, 0x0fedca988, 0x0fedca988 + .long 0x0c0, 0x0ffffffff, 0x0ffffffff + .long 0x0c4, 0x000000000, 0x000000000 + .long 0x0c8, 0x076433221, 0x076433221 + .long 0x0cc, 0x0fedca988, 0x0fedca988 + .long 0x0d0, 0x0ffffffff, 0x0ffffffff +ddr_rcomp_scomp_table_end: + + .p2align 3 ram_set_registers: - SET_DRB - SET_PAM - SET_DRA - SET_DRT - SET_TOLM - SET_DVNP + CALL_LABEL(ram_set_rcomp_regs) + CALL_LABEL(ram_set_d0f0_regs) + RET_LABEL(ram_set_registers) +ram_set_rcomp_regs: + movl $0x0e0, %eax /*enable device 0 functions 2 & 3 */ + PCI_READ_CONFIG_BYTE + andb $~(1<<1), %al + movb %al, %dl /* Put data in dl */ + movl $0x0e0, %eax /* write to offset e0 */ + PCI_WRITE_CONFIG_BYTE + + /* load the tables in device 0 functions 2 and 3 */ + movl $ddr_rcomp_scomp_table, %ebx +1: movl 0(%ebx), %eax /* get the register address */ + orl $0x200, %eax /* set to function 2 */ + movl 4(%ebx), %ecx /* get the data for function 2 */ + PCI_WRITE_CONFIG_DWORD + movl 0(%ebx), %eax /* get the register address */ + orl $0x300, %eax /* set to function 3 */ + movl 8(%ebx), %ecx /* get the data for function 3 */ + PCI_WRITE_CONFIG_DWORD + addl $12, %ebx + cmpl $ddr_rcomp_scomp_table_end, %ebx + jb 1b + + movl $0x088, %eax /* RCOMP evaluation phase */ + PCI_READ_CONFIG_BYTE + andb $~(1<<5), %al + movb %al, %dl /* Put data in dl */ + movb %al, %cl /* save the byte */ + movl $0x088, %eax /* write to offset 88 */ + PCI_WRITE_CONFIG_BYTE + orb $(1<<5), %cl + movb %cl, %dl /* Put data in dl */ + movl $0x088, %eax /* write to offset 88 */ + PCI_WRITE_CONFIG_BYTE +2: movl $0x088, %eax /* poll for RCOMP evaluation complete */ + PCI_READ_CONFIG_BYTE + andb $(1<<5), %al + jnz 2b + movl $0x088, %eax /* RCOMP/SCOMP register update */ + PCI_READ_CONFIG_BYTE + andb $~(1<<6), %al + movb %al, %dl /* Put data in dl */ + movb %al, %cl /* save the byte */ + movl $0x088, %eax /* write to offset 88 */ + PCI_WRITE_CONFIG_BYTE + orb $(1<<6), %cl + movb %cl, %dl /* Put data in dl */ + movl $0x088, %eax /* write to offset 88 */ + PCI_WRITE_CONFIG_BYTE +3: movl $0x088,%eax /* poll for RCOMP/SCOMP update complete */ + PCI_READ_CONFIG_BYTE + andb $(1<<6), %al + jnz 3b + + /* place the command clock drive strength comp in static override */ + movl $0x0380, %eax /* read function 3 offset 80 */ + PCI_READ_CONFIG_DWORD + /* not sure this next section is correct, documentation on device 0 + function 3, register 80 is lacking. */ + movl %eax, %ecx +#if 0 + CONSOLE_DEBUG_TX_HEX32(%ecx) + movl $0x0380, %eax /* read function 3 offset 80 */ + PCI_READ_CONFIG_DWORD + movl %eax, %ecx +#endif + andl $0xff01ffff, %ecx + shrl $7, %eax + andl $0x00fe0000, %eax + orl %eax, %ecx + movl $0x0380, %eax + PCI_WRITE_CONFIG_DWORD /* Set pull up values */ + movl %ecx, %eax + andl $0xffffff01, %ecx + shrl $7, %eax + andl $0x000000fe, %eax + orl %eax, %ecx + movl $0x0380, %eax + PCI_WRITE_CONFIG_DWORD /* Set pull down values */ + orl $0x80008000, %ecx + movl $0x0380, %eax + PCI_WRITE_CONFIG_DWORD /* enable mode overide */ +#if 0 + movl $0x0380, %eax /* read function 3 offset 80 */ + PCI_READ_CONFIG_DWORD + movl %eax, %ecx + CONSOLE_DEBUG_TX_HEX32(%ecx) +#endif + movl $0x0088, %eax /* enable periodic compensaion */ + PCI_READ_CONFIG_BYTE + orb $(1<<7), %al + mov %al, %dl + movl $0x0088, %eax + PCI_WRITE_CONFIG_BYTE + RET_LABEL(ram_set_rcomp_regs) + +ram_set_d0f0_regs: +#if DEBUG_RAM_CONFIG + CALLSP(dumpnorth) +#endif + movl $constant_register_values, %ebx + jmp ram_set_one_register_start +ram_set_one_register: +#if DEBUG_RAM_CONFIG + movl %ebx, %esi + CONSOLE_DEBUG_TX_CHAR($'C') + CONSOLE_DEBUG_TX_CHAR($':') + movl 0(%esi), %eax + CONSOLE_DEBUG_TX_HEX32(%eax) + CONSOLE_DEBUG_TX_CHAR($':') + movl 4(%esi), %eax + CONSOLE_DEBUG_TX_HEX32(%eax) + CONSOLE_DEBUG_TX_CHAR($':') + movl 8(%esi), %eax + CONSOLE_DEBUG_TX_HEX32(%eax) + CONSOLE_DEBUG_TX_CHAR($'\r') + CONSOLE_DEBUG_TX_CHAR($'\n') + movl %esi, %ebx +#endif /* DEBUG_RAM_CONFIG */ + movl 0(%ebx), %eax /* Read the original value to preserve the reserved bits */ + PCI_READ_CONFIG_DWORD + movl 4(%ebx), %edx /* Reserved bits mask */ + andl %edx, %eax /* Preserve only the reserved bits */ + movl 8(%ebx), %ecx /* Read the new values into %ecx */ + notl %edx + andl %edx, %ecx /* Keep only the unreserved bits */ + orl %eax, %ecx /* Put the two sets of bits together */ + movl 0(%ebx), %eax /* Refetch the address to write */ + PCI_WRITE_CONFIG_DWORD + addl $12, %ebx +ram_set_one_register_start: + cmpl $constant_register_values_end, %ebx + jb ram_set_one_register +#if DEBUG_RAM_CONFIG + CALLSP(dumpnorth) +#endif RET_LABEL(ram_set_registers) -#define DEVFN(device, function) (((device) << 3) + (function)) -#define CONFIG_ADDR(bus,devfn,where) (((bus) << 16) | ((devfn) << 8) | (where)) -#define PM_FUNCTION CONFIG_ADDR(0, PIIX4_DEVFN+3, 0) - -#if USE_SPD + /* + * Routine: sdram_spd_get_page_size + * Arguments: %bl SMBUS_MEM_DEVICE + * Results: + * %edi log base 2 page size of DIMM side 1 in bits + * %esi log base 2 page size of DIMM side 2 in bits + * + * Preserved: %ebx (except %bh), %ebp + * + * Trashed: %eax, %bh, %ecx, %edx, %esp, %eflags + * Used: %eax, %ebx, %ecx, %edx, %esi, %edi, %esp, %eflags + * + * Effects: Uses serial presence detect to set %edi & %esi + * to the page size of a dimm. + * Notes: + * %bl SMBUS_MEM_DEVICE + * %edi holds the page size for the first side of the DIMM. + * %esi holds the page size for the second side of the DIMM. + * memory size is represent as a power of 2. + * + * This routine may be worth moving into generic code somewhere. + */ +sdram_spd_get_page_size: + xorl %edi, %edi + xorl %esi, %esi -#define SMBUS_IO_BASE 0x1000 -#define SMBHSTSTAT 0 -#define SMBHSTCTL 2 -#define SMBHSTCMD 3 -#define SMBHSTADD 4 -#define SMBHSTDAT0 5 -#define SMBHSTDAT1 6 -#define SMBBLKDAT 7 - -enable_smbus: - CS_WRITE_LONG(PM_FUNCTION + 0x90, SMBUS_IO_BASE | 1) /* iobase addr */ - CS_WRITE_BYTE(PM_FUNCTION + 0xd2, (0x4 << 1) | 1) /* smbus enable */ - CS_WRITE_WORD(PM_FUNCTION + 0x4, 1) /* iospace enable */ - RET_LABEL(enable_smbus) - - /* - * Routine: setup_smbus - * Arguments: none - * Results: none - * Trashed: eax, edx - * Effects: The smbus is enabled - */ -setup_smbus: - xor %eax,%eax - movw $(SMBUS_IO_BASE + SMBHSTSTAT), %dx - outb %al, %dx - RET_LABEL(setup_smbus) - -#define SMBUS_MEM_DEVICE_0 (0xa << 3) -#define SMBUS_MEM_DEVICE_1 (SMBUS_MEM_DEVICE_0 +1) -#define SMBUS_MEM_DEVICE_2 (SMBUS_MEM_DEVICE_0 +2) -#define SMBUS_MEM_DEVICE_3 (SMBUS_MEM_DEVICE_0 +3) - - - /* - * Routine: smbus_wait_until_ready - * Arguments: none - * Results: none - * Trashed: eax, edx - * Effects: Upon return the smbus is ready to accept commands - */ -smbus_wait_until_ready: - movl $(SMBUS_IO_BASE + SMBHSTSTAT), %edx -1: inb %dx, %al - testb $1, %al - jnz 1b - RET_LABEL(smbus_wait_until_ready) - - /* - * Routine: smbus_wait_until_done - * Arguments: none - * Results: none - * Trashed: eax, edx - * Effects: Upon return the smbus has completed it's most recent transation - */ -smbus_wait_until_done: - movl $(SMBUS_IO_BASE + SMBHSTSTAT), %edx -1: inb %dx, %al - testb $1, %al - jnz 1b -2: testb $0xFE, %al - jnz 3f - inb %dx, %al - testb $0xFE, %al - jz 2b -3: RET_LABEL(smbus_wait_until_done) - - /* - * Routine: smbus_read_byte - * Arguments: %esp return address - * %bl device on the smbus to read from - * %bh address on the smbus to read - * - * Results: zf clear - * byte read %eax - * On Error: - * zf set - * %eax trashed - * - * Trashed: %edx, %eax - * Effects: reads a byte off of the smbus - */ - -#define SMBUS_READ_BYTE(device, address) \ - movl $( (device) | ((address) << 8)), %ebx ; \ + movb $4, %bh /* columns */ CALLSP(smbus_read_byte) + jz sdram_spd_get_page_size_out + andl $0xf, %eax + addl %eax, %edi + + /* Get the module data width and convert it to a power of two */ + movb $7, %bh /* (high byte) */ + CALLSP(smbus_read_byte) + jz sdram_spd_get_page_size_out + andl $0xff, %eax + movl %eax, %ecx + shll $8, %ecx -smbus_read_byte: - /* poll until the smbus is ready for commands */ - CALL_LABEL(smbus_wait_until_ready) + movb $6, %bh /* (low byte) */ + CALLSP(smbus_read_byte) + jz sdram_spd_get_page_size_out + andl $0xff, %eax + orl %eax, %ecx + bsrl %ecx, %eax /* compute cheap log base 2 */ + addl %eax, %edi - /* clear any lingering errors, so that the transaction will run */ - movl $(SMBUS_IO_BASE + SMBHSTSTAT), %edx - inb %dx, %al - outb %al, %dx + /* side two */ + movb $5, %bh /* number of physical banks */ + CALLSP(smbus_read_byte) + jz sdram_spd_get_page_size_out + cmp $1, %al + jbe sdram_spd_get_page_size_out - /* set the device I'm talking to */ - movl $(SMBUS_IO_BASE + SMBHSTADD), %edx - movb %bl /* device */, %al - shlb $1, %al - orb $1, %al - outb %al, %dx + /* Start with the symmetrical case */ + movl %edi, %esi - /* set the command address... */ - movl $(SMBUS_IO_BASE + SMBHSTCMD), %edx - movb %bh /* address */, %al - outb %al, %dx - - /* clear the data byte */ - movl $(SMBUS_IO_BASE + SMBHSTDAT0), %edx - xorl %eax, %eax - outb %al, %dx - - /* start a byte read, with interrupts disabled */ - movl $(SMBUS_IO_BASE + SMBHSTCTL), %edx - movl $((0x2 << 2) | (1 << 6)), %eax - outb %al, %dx - - /* poll for transaction completion */ - CALL_LABEL(smbus_wait_until_done) - - /* read the results and see if we succeded */ - movl $(SMBUS_IO_BASE + SMBHSTSTAT), %edx - inb %dx, %al - testb $0x02, %al - jz 1f - movl $(SMBUS_IO_BASE + SMBHSTDAT0), %edx - inb %dx, %al -1: - RETSP + movb $4, %bh /* columns */ + CALLSP(smbus_read_byte) + jz sdram_spd_get_page_size_out + testb $0xf0, %al + jz sdram_spd_get_page_size_out + movl %eax, %ecx + andl $0xf, %ecx + subl %ecx, %esi /* Subtract out columns on side 1 */ + shrl $4, %eax + andl $0xf, %eax + addl %eax, %esi /* Add in columns on side 2 */ +sdram_spd_get_page_size_out: + RET_LABEL(sdram_spd_get_page_size) /* - * Routine: spd_set_drb - * Arguments: None + * Routine: sdram_spd_get_width + * Arguments: %bl SMBUS_MEM_DEVICE + * Results: + * %edi width of SDRAM chips on DIMM side 1 in bits + * %esi width of SDRAM chips on DIMM side 2 in bits * - * Trashed: %eax, %ebx, %ecx, %edx, %esi, %edi, %ebp, %esp, %eflags - * Effects: Uses serial presence detect to set the - * DRB registers which holds the ending memory address assigned - * to each DIMM. - * Notes: %ebp holds the currently detected end of memory. - * %ebx holds the configuration port & SMBUS_MEM_DEVICE for - * the current iteration through the loop. + * Preserved: %ebx (except %bh), %ebp + * + * Trashed: %eax, %bh, %ecx, %edx, %esp, %eflags + * Used: %eax, %ebx, %ecx, %edx, %esi, %edi, %esp, %eflags + * + * Effects: Uses serial presence detect to set %edi & %esi + * to the width of a dimm. + * Notes: + * %bl SMBUS_MEM_DEVICE + * %edi holds the width for the first side of the DIMM. + * %esi holds the width for the second side of the DIMM. + * memory size is represent as a power of 2. + * + * This routine may be worth moving into generic code somewhere. + */ +sdram_spd_get_width: + xorl %edi, %edi + xorl %esi, %esi + + movb $13, %bh /* sdram width */ + CALLSP(smbus_read_byte) + jz sdram_spd_get_width_out + movl %eax, %ecx + andl $0x7f, %eax + addl %eax, %edi + + /* side two */ + movb $5, %bh /* number of physical banks */ + CALLSP(smbus_read_byte) + jz sdram_spd_get_width_out + cmp $1, %al + jbe sdram_spd_get_width_out + + /* Start with the symmetrical case */ + movl %edi, %esi + + /* See if I need to double the width */ + testl $0x80, %ecx + jz sdram_spd_get_width_out + + /* Double the width on side 2 */ + addl %esi, %esi +sdram_spd_get_width_out: + RET_LABEL(sdram_spd_get_width) + + + /* + * Routine: sdram_spd_get_dimm_size + * Arguments: %bl SMBUS_MEM_DEVICE + * Results: + * %edi log base 2 size of DIMM side 1 in bits + * %esi log base 2 size of DIMM side 2 in bits + * + * Preserved: %ebx (except %bh), %ebp + * + * Trashed: %eax, %bh, %ecx, %edx, %esp, %eflags + * Used: %eax, %ebx, %ecx, %edx, %esi, %edi, %esp, %eflags + * + * Effects: Uses serial presence detect to set %edi & %esi + * the size of a dimm. + * Notes: + * %bl SMBUS_MEM_DEVICE * %edi holds the memory size for the first side of the DIMM. * %esi holds the memory size for the second side of the DIMM. * memory size is represent as a power of 2. - * An unset memory size is represented as -1 ie. 0xFFFFFFFF + * + * This routine may be worth moving into generic code somewhere. */ -spd_set_drb: - xorl %ebp, %ebp /* clear the memory address */ - movl $((0x60 << 16) |SMBUS_MEM_DEVICE_0), %ebx -spd_set_drb_loop_top: - xorl %edi, %edi - subl $1, %edi - xorl %esi, %esi - subl $1, %esi +sdram_spd_get_dimm_size: + xorl %edi, %edi + xorl %esi, %esi - movb $3, %bh /* rows */ - CALLSP(smbus_read_byte) - jz 20f - andl $0xf, %eax - addl %eax, %edi - - movb $4, %bh /* columns */ + /* Note it might be easier to use byte 31 here, it has the DIMM size as + * a multiple of 4MB. The way we do it now we can size both + * sides of an assymetric dimm. + */ + movb $3, %bh /* rows */ CALLSP(smbus_read_byte) - andl $0xf, %eax - addl %eax, %edi + jz sdram_spd_get_dimm_size_out + andl $0xf, %eax + addl %eax, %edi - movb $17, %bh /* banks */ + movb $4, %bh /* columns */ CALLSP(smbus_read_byte) - andl $0xff, %eax - bsrl %eax, %ecx - addl %ecx, %edi - + jz sdram_spd_get_dimm_size_out + andl $0xf, %eax + addl %eax, %edi + + movb $17, %bh /* banks */ + CALLSP(smbus_read_byte) + jz sdram_spd_get_dimm_size_out + andl $0xff, %eax + bsrl %eax, %ecx /* compute cheap log base 2 */ + addl %ecx, %edi + /* Get the module data width and convert it to a power of two */ - movb $7, %bh /* (high byte) */ + movb $7, %bh /* (high byte) */ CALLSP(smbus_read_byte) - andl $0xff, %eax - movl %eax, %ecx - shll $8, %ecx + jz sdram_spd_get_dimm_size_out + andl $0xff, %eax + movl %eax, %ecx + shll $8, %ecx - movb $6, %bh /* (low byte) */ + movb $6, %bh /* (low byte) */ CALLSP(smbus_read_byte) - andl $0xff, %eax - orl %eax, %ecx - bsrl %ecx, %eax - addl %eax, %edi - - /* now I have the ram size in bits as a power of two (less 1) */ - subl $25, %edi /* Make it multiples of 8MB */ + jz sdram_spd_get_dimm_size_out + andl $0xff, %eax + orl %eax, %ecx + bsrl %ecx, %eax /* compute cheap log base 2 */ + addl %eax, %edi /* side two */ - movb $5, %bh /* number of physical banks */ + movb $5, %bh /* number of physical banks */ CALLSP(smbus_read_byte) - cmp $1, %al - jbe 20f + jz sdram_spd_get_dimm_size_out + cmp $1, %al + jbe sdram_spd_get_dimm_size_out - /* for now only handle the symmetrical case */ - movl %edi, %esi -20: - /* Compute the end address for the DRB register */ - cmpl $8, %edi /* Ignore the dimm if it is over 2GB */ - jae 21f - movl $1, %eax - movl %edi, %ecx - shll %cl, %eax - addl %eax, %ebp -21: - /* Write the computed value for the first half of the DIMM */ - movl %ebp, %edx /* value to write into %edx */ - movl %ebx, %eax - shrl $16, %eax /* port address into %eax */ - PCI_WRITE_CONFIG_BYTE - - /* Compute the end address for the DRB register */ - cmpl $8, %esi /* Ignore the dimm if it is over 2GB */ - jae 30f - mov $1, %eax - movl %esi, %ecx - shll %cl, %eax - addl %eax, %ebp -30: - /* Write the comuputed value for the second half of the DIMM */ - movl %ebp, %edx /* value to write into %edx */ - movl %ebx, %eax - shrl $16, %eax /* port address into %eax */ - addl $1, %eax /* The second half uses one port high */ - PCI_WRITE_CONFIG_BYTE + /* Start with the symmetrical case */ + movl %edi, %esi - addl $0x00020001, %ebx /* increment the smbus device & the config port */ - cmpb $SMBUS_MEM_DEVICE_3, %bl /* see if I have reached the end */ - jbe spd_set_drb_loop_top + movb $3, %bh /* rows */ + CALLSP(smbus_read_byte) + jz sdram_spd_get_dimm_size_out + testb $0xf0, %al + jz sdram_spd_get_dimm_size_out + movl %eax, %ecx + andl $0xf, %ecx + subl %ecx, %esi /* Subtract out rows on side 1 */ + shrl $4, %eax + andl $0xf, %eax + addl %eax, %esi /* Add in rows on side 2 */ + + movb $4, %bh /* columns */ + CALLSP(smbus_read_byte) + jz sdram_spd_get_dimm_size_out + movl %eax, %ecx + andl $0xf, %ecx + subl %ecx, %esi /* Subtract out columns on side 1 */ + shrl $4, %eax + andl $0xf, %eax + addl %eax, %esi /* Add in columns on side 2 */ + +sdram_spd_get_dimm_size_out: + RET_LABEL(sdram_spd_get_dimm_size) - /* o.k. I'm done return now */ - RET_LABEL(spd_set_drb) /* - * Routine: spd_set_dramc - * Arguments: None + * This is a place holder fill this out + * Routine: spd_set_row_attributes + * Arguments: %bl SMBUS_MEM_DEVICE + * Results: + * %edi log base 2 size of DIMM side 1 in bits + * %esi log base 2 size of DIMM side 2 in bits * - * Trashed: %eax, %ebx, %edx, %esp, %eflags - * Effects: Uses serial presence detect to set the - * DRAMC register, which records if ram is registerd or not, - * and controls the refresh rate. - * The refresh rate is not set here, as memory refresh - * cannot be enbaled until after memory is initialized. - * see spd_enable_refresh. - * Notes: - * FIXME: Check for illegal/unsupported ram configurations and abort + * Preserved: %ebx (except %bh), %ebp + * + * Trashed: %eax, %bh, %ecx, %edx, %esp, %eflags + * Used: %eax, %ebx, %ecx, %edx, %esi, %edi, %esp, %eflags + * + * Effects: Uses serial presence detect to set %edi & %esi + * the size of a dimm. + * Notes: + * %bl SMBUS_MEM_DEVICE + * %edi holds the memory size for the first side of the DIMM. + * %esi holds the memory size for the second side of the DIMM. + * memory size is represent as a power of 2. + * + * This routine may be worth moving into generic code somewhere. */ +spd_set_row_attributes: + movl $(SMBUS_MEM_DEVICE_START), %ebx + xorl %ebp, %ebp +spd_get_row_attributes: + CALL_LABEL(sdram_spd_get_page_size) -spd_set_dramc: - /* auto detect if ram is registered or not. */ - /* The DRAMC register also contorls the refresh rate but we can't - * set that here because we must leave refresh disabled. - * see: spd_enable_refresh - */ - /* Find the first dimm and assume the rest are the same */ - /* Load the smbus device and port int %ebx */ - movl $((21 << 8) | SMBUS_MEM_DEVICE_0), %ebx -1: CALLSP(smbus_read_byte) - jz 2f - andl $0x12, %eax - jmp spd_set_dramc_out + /* Test to see if the dimm is present */ + testl %edi, %edi + jz spd_get_row_attributes_dimm_width -2: addl $1, %ebx /* increment the device */ - cmpb $SMBUS_MEM_DEVICE_3, %bl - jbe 1b - /* We couldn't find anything we must have no memory */ - jmp no_memory + /* Test for a valid dimm width */ + cmpl $15, %edi + jb unsupported_page_size + cmpl $18, %edi + ja unsupported_page_size + + /* double because I have 2 channels */ + addl $1, %edi + + /* Convert to the format needed for the DRA register */ + subl $14, %edi + + /* Place in the %ebp the dra place holder */ + movb %bl, %cl + subb $(SMBUS_MEM_DEVICE_START), %cl + shlb $3, %cl + shll %cl, %edi + orl %edi, %ebp + + /* Test to see if the second side is present */ + testl %esi, %esi + jz spd_get_row_attributes_dimm_width + + /* Test for a valid dimm width */ + cmpl $15, %esi + jb unsupported_page_size + cmpl $18, %esi + ja unsupported_page_size + + /* double because I have 2 channels */ + addl $1, %esi + + /* Convert to the format needed for the DRA register */ + subl $14, %esi + + /* Place in the %ebp the dra place holder */ + movb %bl, %cl + subb $(SMBUS_MEM_DEVICE_START), %cl + shlb $3, %cl + addb $4, %cl + shll %cl, %esi + orl %esi, %ebp + +spd_get_row_attributes_dimm_width: + /* Now add the SDRAM chip width to the DRA */ + CALL_LABEL(sdram_spd_get_width) + testl %edi, %edi + jz spd_get_row_attributes_next_dimm + cmpl $4, %edi + jne 1f + + /* Enable an x4 device */ + movl $0x08, %edi + movb %bl, %cl + subb $(SMBUS_MEM_DEVICE_START), %cl + shlb $3, %cl + shll %cl, %edi + orl %edi, %ebp +1: + testl %esi, %esi + jz spd_get_row_attributes_next_dimm + cmpl $4, %esi + jne spd_get_row_attributes_next_dimm + + /* Enable an x4 device */ + movl $0x08, %esi + movb %bl, %cl + subb $(SMBUS_MEM_DEVICE_START), %cl + shlb $3, %cl + addb $4, %cl + shll %cl, %esi + orl %esi, %ebp -spd_set_dramc_out: - testb $0x12, %al - /* $8 is bit value for non-registered DRAM */ - movl $8, %eax - jz 1f - /* this is a registered part. - * observation: for register parts, BIOS zeros (!) - * registers CA-CC. This has an undocumented meaning. - */ - xorl %edx, %edx - movl $0xca, %eax - PCI_WRITE_CONFIG_BYTE - xorl %edx, %edx - movl $0xcb, %eax - PCI_WRITE_CONFIG_BYTE - xorl %edx, %edx - movl $0xcc, %eax - PCI_WRITE_CONFIG_BYTE +spd_get_row_attributes_next_dimm: + /* go to the next DIMM */ + addb $(SMBUS_MEM_DEVICE_INC), %bl /* increment the smbus device */ + cmpb $SMBUS_MEM_DEVICE_END, %bl + jbe spd_get_row_attributes - /* now set the bit value for registered sdram into %eax */ - movl $0x10, %eax -1: movl %eax, %edx - movl $0x57, %eax - PCI_WRITE_CONFIG_BYTE - RET_LABEL(spd_set_dramc) + /* Write the new row attributes register */ + movl $0x70, %eax + movl %ebp, %ecx + PCI_WRITE_CONFIG_DWORD -#endif /* USE_SPD */ + RET_LABEL(spd_set_row_attributes) /* - * Routine: spd_enable_refresh - * Arguments: None + * Routine: sdram_read_paired_byte + * Arguments: %esp return address + * %bl device on the smbus to read from + * %bh address on the smbus to read + * Results: + * zf clear + * byte read in %al + * On Error: + * zf set + * %eax trashed * - * Trashed: %eax, %ebx, %ecx, %edx, %esp, %eflags - * Effects: Uses serial presence detect to set the - * refresh rate in the DRAMC register. - * see spd_set_dramc for the other values. - * FIXME: Check for illegal/unsupported ram configurations and abort + * Preserved: %ebx, %esi, %edi + * + * Trashed: %eax, %ecx, %edx, %ebp, %esp, %eflags + * Used: %eax, %ebx, %ecx, %edx, %esp, %eflags + * + * Effects: Reads two spd bytes from both ram channesl + * and errors if they are not equal. + * It then returns the equal result. */ +spd_read_paired_byte: + movl %esp, %ebp + CALLSP(smbus_read_byte) + setnz %cl + movb %al, %ch + addb $(SMBUS_MEM_CHANNEL_OFF), %bl + CALLSP(smbus_read_byte) + movb %ch, %ah + setnz %ch + subb $(SMBUS_MEM_CHANNEL_OFF), %bl + + /* See if dimms on both sides are equally present */ + cmp %cl, %ch + jne sdram_presence_mismatch + + /* Leave if I have no data */ + testb %cl, %cl + jz spd_verify_byte_out + + /* Verify the data is identical */ + cmp %ah, %al + jne sdram_value_mismatch + + /* Clear the zero flag */ + testb %cl, %cl +spd_verify_byte_out: + movl %ebp, %esp + RETSP + + /* + * Routine: spd_verify_dimms + * Arguments: none + * Results: none + * Preserved: none + * Trashed: %eax, %ebx, %ecx, %edx, %ebp, %esi, %edi, %esp, %eflags + * Used: %eax, %ebx, %ecx, %edx, %ebp, %esi, %edi, %esp, %eflags + * + * Effects: + * - Verify all interesting spd information + * matches for both dimm channels. + * - Additional error checks that can be easily done + * here are computed as well, so I don't need to + * worry about them later. + */ +spd_verify_dimms: + movl $(SMBUS_MEM_DEVICE_START), %ebx +spd_verify_dimm: + /* Verify this is DDR SDRAM */ + movb $2, %bh + CALLSP(spd_read_paired_byte) + jz spd_verify_next_dimm + cmpb $7, %al + jne invalid_dimm_type + + /* Verify the row addresses */ + movb $3, %bh + CALLSP(spd_read_paired_byte) + jz spd_missing_data + testb $0x0f, %al + jz spd_invalid_data + + /* Column addresses */ + movb $4, %bh + CALLSP(spd_read_paired_byte) + jz spd_missing_data + testb $0xf, %al + jz spd_invalid_data + + /* Physical Banks */ + movb $5, %bh + CALLSP(spd_read_paired_byte) + jz spd_missing_data + cmp $1, %al + jb spd_invalid_data + cmp $2, %al + ja spd_invalid_data + + /* Module Data Width */ + movb $7, %bh + CALLSP(spd_read_paired_byte) + jz spd_missing_data + cmpb $0, %al + jne spd_invalid_data + + movb $6, %bh + CALLSP(spd_read_paired_byte) + jz spd_missing_data + cmpb $64, %al + je 1f + cmpb $72, %al + je 1f + jmp spd_unsupported_data +1: + + /* Cycle time at highest CAS latency CL=X */ + movb $9, %bh + CALLSP(spd_read_paired_byte) + jz spd_missing_data + + /* SDRAM type */ + movb $11, %bh + CALLSP(spd_read_paired_byte) + jz spd_missing_data + + /* Refresh Interval */ + movb $12, %bh + CALLSP(spd_read_paired_byte) + jz spd_missing_data + + /* SDRAM Width */ + movb $13, %bh + CALLSP(spd_read_paired_byte) + jz spd_missing_data + andb $0x7f, %al + cmpb $4, %al + je 1f + cmpb $8, %al + je 1f + jmp spd_unsupported_data +1: + +a + /* tRCD RAS to CAS */ + movb $29, %bh + CALLSP(spd_read_paired_byte) + jz spd_missing_data + testb $0xfc, %al + jz spd_invalid_data + + /* tRAS Activate to Precharge */ + movb $30, %bh + CALLSP(spd_read_paired_byte) + jz spd_missing_data + testb %al, %al + jz spd_invalid_data + + /* Module Bank Density */ + movb $31, %bh + CALLSP(spd_read_paired_byte) + jz spd_missing_data + testb $(1<<2), %al /* 16MB */ + jnz spd_unsupported_data + testb $(1<<3), %al + jnz spd_unsupported_data /* 32MB */ + + /* Address and Command Hold Time After Clock */ + movb $33, %bh + CALLSP(spd_read_paired_byte) + jz spd_missing_data + +spd_verify_next_dimm: + /* go to the next DIMM */ + addb $(SMBUS_MEM_DEVICE_INC), %bl /* increment the smbus device */ + cmpb $SMBUS_MEM_DEVICE_END, %bl + jbe spd_verify_dimm +spd_verify_dimms_out: + RET_LABEL(spd_verify_dimms) + + .section ".rom.data" +spd_pre_init: .string "Reading SPD data...\r\n" +spd_post_init: .string "done\r\n" + .previous -refresh_rates: - .byte 0x01 /* Normal 15.625 us -> 15.6 us */ - .byte 0x05 /* Reduced(.25X) 3.9 us -> 7.8 us */ - .byte 0x05 /* Reduced(.5X) 7.8 us -> 7.8 us */ - .byte 0x02 /* Extended(2x) 31.3 us -> 31.2 us */ - .byte 0x03 /* Extended(4x) 62.5 us -> 62.4 us */ - .byte 0x04 /* Extended(8x) 125 us -> 124.8 us */ +refresh_rate_rank: + /* Refresh rates ordered from most conservative (lowest) + * to most agressive (highest) + /* disabled 0 -> rank 3 + * 15.6usec 1 -> rank 1 + * 7.8 usec 2 -> rank 0 + * 64usec 3 -> rank 2 + */ + .byte 3, 1, 0, 2 +refresh_rate_index: + /* Map the spd refresh rates to memory controller settings + * 15.625us -> 15.6us + * 3.9us -> err + * 7.8us -> 7.8us + * 31.3s -> 15.6us + * 62.5us -> 15.6us + * 125us -> 64us + */ + .byte 1, 0xff, 2, 1, 1, 3 +#define MAX_SPD_REFRESH_RATE 5 -#if USE_SPD -spd_enable_refresh: - /* Find the first dimm and assume the rest are the same */ - /* Load the smbus device and port into %ebx */ - movl $((12 << 8) | SMBUS_MEM_DEVICE_0), %ebx -1: CALLSP(smbus_read_byte) - jz 2f - andl $0x7f, %eax - jmp spd_enable_refresh_out +spd_set_dram_controller_mode: + /* Walk through all dimms and find the interesection of the support + * for ecc sdram and refresh rates + */ + movl $(SMBUS_MEM_DEVICE_START), %ebx + /* Read the inititial state */ + movl $0x7c, %eax + PCI_READ_CONFIG_DWORD + movl %eax, %esi -2: addl $1, %ebx /* increment the device */ - cmpb $SMBUS_MEM_DEVICE_3, %bl - jbe 1b - /* We couldn't find anything we must have no memory */ - jmp no_memory +#if USE_OPTION_TABLE == 1 + /* Test if ECC cmos option is enabled */ + movb $RTC_BOOT_BYTE, %al + outb %al, $0x70 + inb $0x71, %al + testb $(1<<2), %al + jnz 1f + /* Clear the ecc enable */ + andl $~(3 << 20), %esi +1: +#endif +spd_get_dram_controller_mode: -spd_enable_refresh_out: - cmpb $0x06, %al /* see if the ram refresh is a supported one */ + /* Test to see if I have ecc sdram */ + movb $11, %bh /* SDRAM type */ + CALLSP(smbus_read_byte) + jz spd_set_dram_controller_mode_next_dimm + cmpb $2, %al + je spd_ecc + /* Clear the ecc enable */ + andl $~(3 << 20), %esi +spd_ecc: + movb $12, %bh /* SDRAM refresh rate */ + CALLSP(smbus_read_byte) + jz spd_set_dram_controller_mode_next_dimm + andl $0x7f, %eax + cmpb $MAX_SPD_REFRESH_RATE, %al + ja unsupported_refresh_rate + cmpb $0xff, %al + je unsupported_refresh_rate + xorl %ecx, %ecx + movb refresh_rate_index(%eax, 1), %cl + + /* Isolate the old refresh rate setting */ + movl %esi, %edx + shrl $8, %edx + andl $3, %edx + + /* Load the refresh rate ranks */ + movb refresh_rate_rank(%edx), %dh + movb refresh_rate_rank(%ecx), %dl + + /* See if the new refresh rate is more conservative than the old + * refresh rate setting. (Lower ranks are more conservative) + */ + cmpb %dh, %dl jae 1f - addl $refresh_rates, %eax /* convert SPD refresh rates to 440GX refresh rates */ - movb (%eax), %cl - jmp 2f -1: movb $0x05, %cl /* unknown ram refresh hard code it to something conservative */ -2: movl $0x57, %eax - PCI_READ_CONFIG_BYTE - andb $0xf8, %al - orb %cl, %al - movb %al, %dl - movl $0x57, %eax - PCI_WRITE_CONFIG_BYTE - RET_LABEL(spd_enable_refresh) - - /* - * Routine: spd_set_rps - * Arguments: None - * - * Trashed: %eax, %ebx, %ecx, %edx, %esi, %edi, %esp, %eflags - * Effects: Uses serial presence detect to set the row size - * on a given DIMM - * Notes: %esi accumulates the row sizes of all of the DIMMs - * %ecx holds the current bit into into %esi - * %bl holds the current SMBUS device - * FIXME: Check for illegal/unsupported ram configurations and abort - */ - -spd_set_rps: - /* The RPS register holds the size of a ``page'' of DRAM on each DIMM */ - /* default all page sizes to 2KB */ - xorl %esi, %esi - /* Index into %esi of bit to set */ - movl $0 , %ecx - /* Load the smbus device into %ebx */ - movl $SMBUS_MEM_DEVICE_0, %ebx + /* Clear the old refresh rate */ + andl $~(3<<8), %esi + /* Move in the new refresh rate */ + shll $8, %ecx + orl %ecx, %esi +1: -1: movb $3, %bh - CALLSP(smbus_read_byte) /* row address bits */ - jz 2f - andl $0xf, %eax - movl %eax, %edi - /* I now have the row page size as a power of 2 */ - subl $11, %edi /* Now make it in multiples of 2Kb */ - jbe 2f - /* FIXME: do something with page sizes greather than 8KB!! */ - shll %cl, %edi - orl %edi, %esi - /* side two */ - movb $5, %bh - CALLSP(smbus_read_byte) /* number of physical banks */ - cmp $1, %al - jbe 2f - /* for now only handle the symmtrical case */ - shll $2, %edi - /* one too many shifts here. */ - /* shll %cl, %edi*/ - orl %edi, %esi + movb $33, %bh /* Address and command hold time after clock */ + CALLSP(smbus_read_byte) + jz spd_set_dram_controller_mode_next_dimm + cmpb $0xa0, %al /* At 133Mhz this constant should be 0x75 */ + jb 1f + andl $~(1<<16), %esi /* Use two clock cyles instead of one */ +1: + +spd_set_dram_controller_mode_next_dimm: + /* go to the next DIMM */ + addb $(SMBUS_MEM_DEVICE_INC), %bl /* increment the smbus device */ + cmpb $SMBUS_MEM_DEVICE_END, %bl + jbe spd_get_dram_controller_mode -2: addl $1, %ebx /* increment the device */ - addl $4, %ecx /* increment the shift count */ - cmpb $SMBUS_MEM_DEVICE_3, %bl - jbe 1b -/* next block is for Ron's attempt to get registered to work. */ -/* we have just verified that we have to have this code. It appears that - * the registered SDRAMs do indeed set the RPS wrong. sheesh. - */ - /* at this point, %esi holds the RPS for all ram. - * we have verified that for registered DRAM the values are - * 1/2 the size they should be. So we test for registered - * and then double the sizes if needed. + /* Now write the controller mode */ + movl $0x7c, %eax + movl %esi, %ecx + PCI_WRITE_CONFIG_DWORD + + RET_LABEL(spd_set_dram_controller_mode) + + +spd_enable_clocks: + /* Walk through all dimms and enable clocks for those that are present. */ - movl $0x57, %eax - PCI_READ_CONFIG_BYTE + movl $(SMBUS_MEM_DEVICE_START), %ebx + /* Read the inititial state */ + movl $0x8c, %eax + PCI_READ_CONFIG_DWORD + movl %eax, %esi +spd_get_clocks: + /* Read any spd byte to see if the dimm is present */ + movb $5, %bh /* Physical Banks */ + CALLSP(smbus_read_byte) + jz spd_enable_clocks_next_dimm - /* is it registered? */ - testb $0x10, %eax + /* Find the index of the dimm */ + movb %bl, %cl + subb $(SMBUS_MEM_DEVICE_START), %cl + /* Now construct the mask to clear the enable bit */ + movl $1, %eax + shll %cl, %eax + notl %eax + andl %eax, %esi + +spd_enable_clocks_next_dimm: + /* go to the next DIMM */ + addb $(SMBUS_MEM_DEVICE_INC), %bl /* increment the smbus device */ + cmpb $SMBUS_MEM_DEVICE_END, %bl + jbe spd_get_clocks + + movl $0x8c, %eax + movl %esi, %ecx + PCI_WRITE_CONFIG_DWORD + + /* If we have no dimm modules bail out */ + andl $0xf, %esi + cmpl $0xf, %esi + je no_memory + RET_LABEL(spd_enable_clocks) + +cas_latency_80: + .byte 0x0, 0x1, 0x6 +cas_latency_78: + .byte DRT_CAS_1_5, DRT_CAS_2_0, DRT_CAS_2_5 + +spd_set_cas_latency: + /* Walk through all dimms and find the interesection of the + * supported cas latencies. + */ + movl $(SMBUS_MEM_DEVICE_START), %ebx + /* Initially allow cas latencies 2.5, 2.0, 1.5 + * which the chipset supports. + */ + movl $((1 << 3)|(1 << 2)|(1 <<1)), %esi +spd_get_cas_latencies: + movb $18, %bh + CALLSP(smbus_read_byte) + jz spd_set_cas_latency_next_dimm + + /* Find the highest supported cas latency */ + bsrl %eax, %ecx + movl $1, %edi + shll %cl, %edi + + /* Remember the supported cas latencies */ + movl %eax, %ecx + + /* Verify each cas latency at 100Mhz */ + /* Verify slowest/highest CAS latency */ + movb $9, %bh + CALLSP(smbus_read_byte) + jz spd_set_cas_latency_next_dimm + + cmpb $0xa0, %al + jbe 1f + /* The bus is too fast so we cannot support this case latency */ + notl %edi + andl %edi, %ecx + notl %edi +1: + + /* Verify the highest CAS latency - 0.5 clocks */ + shrl $1, %edi + testl %edi,%edi + jz 1f + + movb $23, %bh + CALLSP(smbus_read_byte) + jz spd_set_cas_latency_next_dimm + + cmpb $0xa0, %al + jbe 1f + /* The bus is too fast so we cannot support this cas latency */ + notl %edi + andl %edi, %ecx + notl %edi +1: + + /* Verify the highest CAS latency - 1.0 clocks */ + shrl $1, %edi + testl %edi, %edi jz 1f - /* BIOS makes weird page size for registered! */ - /* what we have found is you need to set the EVEN banks to - * twice the size. Fortunately there is a very easy way to - * do this. First, read the WORD value of register 0x74. - */ + movb $25, %bh + CALLSP(smbus_read_byte) + jz spd_set_cas_latency_next_dimm - /* now to double the size of the EVEN banks we only need to add 1 */ - /* because the size is log2 - */ - addl $0x1111, %esi - /* now write that final value of %esi into register 0x74 */ -1: - movl %esi, %ecx - movl $0x74, %eax - PCI_WRITE_CONFIG_WORD - - RET_LABEL(spd_set_rps) - - /* - * Routine: spd_set_pgpol - * Arguments: None - * - * Trashed: %eax, %ebx, %ecx, %edx, %esi, %esp, %eflags - * Effects: Uses serial presence detect to set the number of banks - * on a given DIMM - * Notes: %esi accumulates the banks sizes of all of the DIMMs - * %ecx holds the current bit into into %esi - * %bl holds the current SMBUS device - * FIXME: Check for illegal/unsupported ram configurations and abort - */ - -spd_set_pgpol: - /* The PGPOL register stores the number of logical banks per DIMM, - * and number of clocks the DRAM controller waits in the idle - * state. - */ - /* default all bank counts 2 */ - xorl %esi, %esi - /* Index into %esi of bit to set */ - movl $0 , %ecx - /* Load the smbus device into %ebx */ - movl $SMBUS_MEM_DEVICE_0, %ebx - -1: movb $17, %bh - CALLSP(smbus_read_byte) /* logical banks */ - jz 2f - cmp $0x4, %eax - jl 2f - movl $0x1, %eax - shll %cl, %eax - orl %eax, %esi - /* side two */ - movb $5, %bh - CALLSP(smbus_read_byte) /* number of physical banks */ - cmp $1, %al - jbe 2f - /* for now only handle the symmtrical case */ - movl $0x2, %eax - shll %cl, %eax - orl %eax, %esi - -2: addl $1, %ebx /* increment the device */ - addl $2, %ecx /* increment the shift count */ - cmpb $SMBUS_MEM_DEVICE_3, %bl - jbe 1b - - shll $8, %esi - orl $0x7, %esi /* 32 clocks idle time */ - movl %esi, %ecx - movl $0x78, %eax - PCI_WRITE_CONFIG_WORD - RET_LABEL(spd_set_pgpol) - - /* - * Routine: spd_enable_nbxcfg - * Arguments: None - * - * Trashed: %eax, %ebx, %ecx, %edx, %esi, %esp, %eflags - * Effects: Uses serial presence detect to set the - * ECC support flags in the NBXCFG register - * Notes: %esi accumulates the ECC support of the individual DIMMs. - * %ecx holds the bit that should be flipped for the current DIMM. - * %bl holds the smbus device that corresponds to the current DIMM. - * FIXME: Check for illegal/unsupported ram configurations and abort - */ - -spd_set_nbxcfg: - /* say all dimms have no ECC support */ - movl $0xFF, %esi - /* Index into %esi of bit to set */ - movl $0 , %ecx - /* Load the smbus device into %ebx */ - movl $SMBUS_MEM_DEVICE_0, %ebx - -1: movb $11, %bh - CALLSP(smbus_read_byte) /* module error correction type */ - jz 2f - cmp $0x2, %eax /* 0 == None, 1 == Parity, 2 == ECC */ - jne 2f - movl $0x1, %eax - shll %cl, %eax - xorl %eax, %esi - - /* side two */ - movb $5, %bh - CALLSP(smbus_read_byte) /* number of physical banks */ - cmp $1, %al - jbe 2f - /* The only is the symmtrical case */ - movl $0x2, %eax - shll %cl, %eax - xorl %eax, %esi - -2: addl $1, %ebx /* increment the device */ - addl $2, %ecx /* increment the shift count */ - cmpb $SMBUS_MEM_DEVICE_3, %bl - jbe 1b - - movl %esi, %edx - movl $0x53, %eax - PCI_WRITE_CONFIG_BYTE - /* Now see if esi is 0xff. If it is we are done. If not, - * we need to set 0x18 into register 0x50.l - * we will do this in two steps, first or in 0x80 to 0x50.b, - * then or in 0x1 to 0x51.b - */ - mov %esi, %eax - cmpb $0xff, %al - je 1f - movl $0x50, %eax - PCI_READ_CONFIG_BYTE - orb $0x80, %al - movb %al, %dl - movl $0x50, %eax - PCI_WRITE_CONFIG_BYTE - movl $0x51, %eax - PCI_READ_CONFIG_BYTE - orb $0x1, %al - movb %al, %dl - movl $0x51, %eax - PCI_WRITE_CONFIG_BYTE - // try this. - // we should be setting bit 2 in register 76 and we're not - // technically we should see if CL=2 for the ram, - // but registered is so screwed up that it's kind of a lost - // cause. - movl $0x76, %eax - PCI_READ_CONFIG_BYTE - orb $0x4, %al - movb %al, %dl - movl $0x76, %eax - PCI_WRITE_CONFIG_BYTE + movb $0xa0, %al + jbe 1f + /* The bus is too fast so we cannot support this cas latency */ + notl %edi + andl %edi, %ecx + notl %edi 1: - RET_LABEL(spd_set_nbxcfg) + /* Now find which cas latencies are supported for the bus */ + andl %ecx, %esi +spd_set_cas_latency_next_dimm: + /* go to the next DIMM */ + addb $(SMBUS_MEM_DEVICE_INC), %bl /* increment the smbus device */ + cmpb $SMBUS_MEM_DEVICE_END, %bl + jbe spd_get_cas_latencies -spd_set_sdramc: - RET_LABEL(spd_set_sdramc) + /* After all of the arduous calculation setup with the fastest + * cas latency I can use. + */ + bsfl %esi, %eax + jz inconsistent_cas_latencies + subl $1, %eax + movl %eax, %ecx -#endif /* USE_SPD */ + movl $0x78, %eax + PCI_READ_CONFIG_BYTE + andb $~(DRT_CAS_MASK), %al + orb cas_latency_78(%ecx), %al + movb %al, %dl + movl $0x78, %eax + PCI_WRITE_CONFIG_BYTE + movl $0x80, %eax + movb cas_latency_80(%ecx), %dl + PCI_WRITE_CONFIG_BYTE + RET_LABEL(spd_set_cas_latency) + +spd_set_dram_timing: + /* Walk through all dimms and find the interesection of the + * supported dram timings. + */ + movl $(SMBUS_MEM_DEVICE_START), %ebx + /* Read the inititial state */ + movl $0x78, %eax + PCI_READ_CONFIG_DWORD + movl %eax, %esi +spd_get_dram_timing: + + /* + * tRP + */ + movb $27, %bh + CALLSP(smbus_read_byte) + jz spd_set_dram_timing_next_dimm + cmpb $(20<<2), %al + jbe 1f + /* At 100Mhz if row precharge time is above than 20ns than we + * need 3 clocks not 2 clocks. + */ + andl $~(1<<0), %esi +1: + /* + * tRCD + */ + movb $29, %bh + CALLSP(smbus_read_byte) + jz spd_set_dram_timing_next_dimm + cmpb $(20<<2), %al + jbe 1f + /* At 100Mhz if the Minimum ras to cas delay is about 20ns we + * need 3 clocks not 2 clocks. + */ + andl $~((1<<3)|(1<<1)), %esi +1: + + /* + * tRAS + */ + movb $30, %bh + CALLSP(smbus_read_byte) + jz spd_set_dram_timing_next_dimm + /* Convert tRAS from ns to 100Mhz clock cycles */ + movb $10, %dl + addb %dl, %al /* Make certain we round up */ + subb $1, %al + andl $0xff, %eax /* Clear the upper bits of eax */ + divb %dl, %al + + /* Don't even process small timings */ + cmpb $5, %al + jbe 1f + + /* Die if the value is to large */ + cmpb $7, %al + ja unsupported_rcd + + /* Convert to clocks - 5 */ + subb $5, %al + + /* Convert the existing value into clocks - 5 */ + movl %esi, %ecx + shrl $9, %ecx + andl $3, %ecx + notl %ecx + subl $1, %ecx + + /* See if we need a slower timing */ + cmpb %al, %cl + jbe 1f + + /* O.k. put in our slower timing */ + movb %al, %cl + addb $1, %cl + notl %ecx + shll $9, %ecx + andl $(3<<9), %esi + orl %ecx, %esi + +1: + /* + * tRD + */ + /* Set to a 7 clock read delay */ + andl $~(7<<24), %esi + + /* + * Back to Back Read Turn Around + */ + /* Set to a 4 clock back to back read turn around */ + andl $~(1<<27), %esi + /* + * Back to Back Read-Write Turn Around + */ + /* Set to a 5 clock back to back read to write turn around */ + andl $~(1<<28), %esi + /* + * Back to Back Write-Read Turn Around + */ + /* Set to a 3 clock back to back write to read turn around */ + andl $~(1<<29), %esi + +spd_set_dram_timing_next_dimm: + /* go to the next DIMM */ + addb $(SMBUS_MEM_DEVICE_INC), %bl /* increment the smbus device */ + cmpb $SMBUS_MEM_DEVICE_END, %bl + jbe spd_get_dram_timing + + movl $0x78, %eax + movl %esi, %ecx + PCI_WRITE_CONFIG_DWORD + + RET_LABEL(spd_set_dram_timing) + - /* PAM FDHC MBSC SMRAM ESRAMC MBFS DWTC DRTC */ ram_set_spd_registers: -#if 0 -/* #if USE_SPD */ - CALL_LABEL(enable_smbus) - CALL_LABEL(setup_smbus) - CALL_LABEL(spd_set_drb) - CALL_LABEL(spd_set_dramc) - CALL_LABEL(spd_set_rps) - CALL_LABEL(spd_set_sdramc) - CALL_LABEL(spd_set_pgpol) - CALL_LABEL(spd_set_nbxcfg) -#endif + CONSOLE_INFO_TX_STRING($spd_pre_init) + CALL_LABEL(spd_enable_clocks) + CALL_LABEL(spd_verify_dimms) + CALL_LABEL(spd_set_row_attributes) + CALL_LABEL(spd_set_dram_controller_mode) + CALL_LABEL(spd_set_cas_latency) + CALL_LABEL(spd_set_dram_timing) + CONSOLE_INFO_TX_STRING($spd_post_init) RET_LABEL(ram_set_spd_registers) -#if 0 -get_ecc_ram_size_bytes_ebx: - /* FIXME handle the no ram case. */ - movl $0x67, %eax /* Read the RAM SIZE */ - PCI_READ_CONFIG_BYTE - andl $0x000000ff, %eax /* Convert it to bytes */ - movl %eax, %ebx - shll $23, %ebx - RET_LABEL(get_ecc_ram_size_bytes_ebx) -#endif -/* things that are not used */ -#define FIRST_NORMAL_REFERENCE() -#define SPECIAL_FINISHUP() \ - CS_WRITE_BYTE(0x78, 0x0f) ; \ - CS_WRITE_BYTE(0x79, 0x04) ; \ - CS_WRITE_BYTE(0x7a, 0x00) ; \ - CS_WRITE_BYTE(0x7b, 0x00) ; \ - CS_WRITE_BYTE(0xe0, 0x1e) -#if 0 - CS_WRITE_BYTE(0x52, 0x01) ; \ -1: movl $0x52, %eax ; \ - PCI_READ_CONFIG_BYTE ; \ - andl $0x08, %eax ; \ - jz 1b ; \ - CS_WRITE_BYTE(0x52, 0x0d) ; \ +spd_set_ram_size: + movl $(SMBUS_MEM_DEVICE_START), %ebx + xorl %ebp, %ebp + /* Read the necessary SPD bytes for the first dimm */ +spd_get_dimm_size: + CALL_LABEL(sdram_spd_get_dimm_size) + /* Since I have 2 identical channels double the sizes */ + incl %edi + incl %esi + + /* Convert bits to multiples of 64MB */ + subl $29, %edi + jb 1f + movl %edi, %ecx + movl $1, %eax + shll %cl, %eax + addl %eax, %ebp +1: + /* Write the size of side 1 of the dimm */ + xorl %eax, %eax + movb %bl, %al + subl $(SMBUS_MEM_DEVICE_START), %eax + addl %eax, %eax + addl $0x60, %eax + movl %ebp, %edx + PCI_WRITE_CONFIG_BYTE + + /* Convert bits to multiples of 64MB */ + subl $29, %esi + jb 1f + movl %esi, %ecx + movl $1, %eax + shll %cl, %eax + addl %eax, %ebp +1: + /* Write the size of side 2 of the dimm */ + xorl %eax, %eax + movb %bl, %al + subl $(SMBUS_MEM_DEVICE_START), %eax + addl %eax, %eax + addl $0x61, %eax + movl %ebp, %edx + PCI_WRITE_CONFIG_BYTE + + /* go to the next DIMM */ + addb $(SMBUS_MEM_DEVICE_INC), %bl /* increment the smbus device */ + cmpb $SMBUS_MEM_DEVICE_END, %bl + jbe spd_get_dimm_size +spd_set_ram_size_computed: + /* For now hardset everything at 128MB boundaries */ + /* %ebp has the ram size in multiples of 64MB */ + cmpl $0x30, %ebp + jae spd_set_large_ram_size +spd_set_small_ram_size: + /* I should really adjust all of this in C after I have resources + * to all of the pcie devices. + */ + + /* Round up to 128M granularity */ + addl $1, %ebp + andl $0xfe, %ebp + shll $10, %ebp + movl $0xC4, %eax + movl %ebp, %ecx + PCI_WRITE_CONFIG_WORD + jmp spd_set_ram_size_out +spd_set_large_ram_size: + /* FIXME will this work with 3.5G of ram? */ + /* Put TOLM at 3G */ + movl $0xC4, %eax + movl $0xc000, %ecx + PCI_WRITE_CONFIG_WORD + /* Hard code a 1G remap window, right after the ram */ + cmp $0x40, %ebp + jae 1f + movl $0x40, %ebp /* Ensure we are over 4G */ +1: + movl $0xC6, %eax + movl %ebp, %ecx + PCI_WRITE_CONFIG_WORD + movl $0xC8, %eax + movl %ebp, %edx + addl $0x10, %ecx + PCI_WRITE_CONFIG_WORD + jmp spd_set_ram_size_out + +spd_set_ram_size_out: + RET_LABEL(spd_set_ram_size) + + /* I have finally seen ram bad enough to cause LinuxBIOS + * to die in mysterious ways, before booting up far + * enough to run a memory tester. This code attempts + * to catch this blatantly bad ram, with a spot check. + * For most cases you should boot all of the way up + * and run a memory tester. + */ + /* Ensure I read/write each stick of bank of memory && + * that I do more than 1000 bytes to avoid the northbridge cache. + * Only 64M of each side of each DIMM is currently mapped, + * so we can handle > 4GB of ram here. + */ +bank_msg: .asciz "Bank " +side_msg: .asciz " Side " +verify_ram: + xorl %ecx, %ecx + /* Check to see if the RAM is present, + * in the specified bank and side. + */ +1: movl %ecx, %ebx + shrl $1, %ebx + addl $((5<<8) | SMBUS_MEM_DEVICE_START), %ebx + CALLSP(smbus_read_byte) + jz 5f + testl $1, %ecx + jz 2f + cmpb $2, %al + jne 5f + + /* Display the bank and side we are spot checking. + */ +2: CONSOLE_INFO_TX_STRING($bank_msg) + movl %ecx, %ebx + shrl $1, %ebx + incl %ebx + CONSOLE_INFO_TX_HEX8(%bl) + CONSOLE_INFO_TX_STRING($side_msg) + movl %ecx, %ebx + andl $1, %ebx + CONSOLE_INFO_TX_HEX8(%bl) + + /* Compute the memory address to spot check. */ + movl %ecx, %ebx + xorl %eax, %eax +3: testl %ebx, %ebx + jz 4f + addl $0x04000000, %eax + decl %ebx + jmp 3b +4: + /* Spot check 512K of RAM */ + movl %eax, %ebx + addl $0x0007ffff, %ebx + CALLSP(spot_check) +5: + /* Now find the next bank and side to spot check */ + incl %ecx + cmpl $8, %ecx + jl 1b + RET_LABEL(verify_ram) + + +ram_postinit: +#if DEBUG_RAM_CONFIG + CALLSP(dumpnorth) #endif + /* Include a test to verify that memory is more or less working o.k. + * This test is to catch programming errors and hardware that is out of + * spec, not a test to see if the memory dimms are working 100% + */ + CALL_LABEL(verify_ram) + CALL_LABEL(spd_set_ram_size) + RET_LABEL(ram_postinit) + + +#define FIRST_NORMAL_REFERENCE() CALL_LABEL(ram_postinit) + +#define SPECIAL_FINISHUP() CALL_LABEL(dram_finish) + + .section ".rom.data" +ecc_pre_init: .string "Initializing ECC state...\r\n" +ecc_post_init: .string "ECC state initialized.\r\n" + .previous +dram_finish: + /* Test to see if ECC support is enabled */ + movl $0x7c, %eax + PCI_READ_CONFIG_DWORD + shrl $20, %eax + andl $3, %eax + cmpb $2, %al + jne noecc_init + + CONSOLE_INFO_TX_STRING($ecc_pre_init) + /* Initialize ECC bits */ + movl $0x52, %eax + movl $0x01, %edx + PCI_WRITE_CONFIG_BYTE +1: movl $0x52, %eax + PCI_READ_CONFIG_BYTE + andl $0x08, %eax + jz 1b + movl $0x52, %eax + movl $0x0d, %edx + PCI_WRITE_CONFIG_BYTE + + CONSOLE_INFO_TX_STRING($ecc_post_init) + + /* Clear the ECC error bits */ + movl $0x0180, %eax /* dev 0, function 1, offset 80 */ + movl $0x03, %edx + PCI_WRITE_CONFIG_BYTE + movl $0x0182, %eax /* dev 0, function 1, offset 82 */ + movl $0x03, %edx + PCI_WRITE_CONFIG_BYTE + +noecc_init: + +#if DEBUG_RAM_CONFIG + CALLSP(dumpnorth) +#endif + RET_LABEL(dram_finish) + +#define ERRFUNC(x, str) \ + .section ".rom.data" ;\ +x##_str: ;\ + .string str ;\ + .ascii str ;\ + .previous ;\ +x: ;\ + movl $x##_str, %esi ;\ + jmp mem_err + + +ERRFUNC(invalid_dimm_type, "Invalid dimm type") +ERRFUNC(spd_missing_data, "Missing sdram spd data") +ERRFUNC(spd_invalid_data, "Invalid sdram spd data") +ERRFUNC(spd_unsupported_data, "Unsupported sdram spd value") +ERRFUNC(unsupported_page_size, "Unsupported page size") +ERRFUNC(sdram_presence_mismatch, "DIMM presence mismatch") +ERRFUNC(sdram_value_mismatch, "spd data does not match") +ERRFUNC(unsupported_refresh_rate, "Unsuported spd refresh rate") +ERRFUNC(inconsistent_cas_latencies, "No cas latency supported by all dimms") +ERRFUNC(unsupported_rcd, "Unsupported ras to cas delay") +#undef ERRFUNC + +.section ".rom.data" +mem_err_err: .string "ERROR: " +mem_err_pair: .string " on dimm pair " +mem_err_byte: .string " spd byte " +.previous +mem_err: + movl %ebx, %edi + CONSOLE_ERR_TX_STRING($mem_err_err) + CONSOLE_ERR_TX_STRING(%esi) + CONSOLE_ERR_TX_STRING($mem_err_pair) + movl %edi, %ebx + subb $(SMBUS_MEM_DEVICE_START), %bl + CONSOLE_ERR_TX_HEX8(%bl) + CONSOLE_ERR_TX_STRING($mem_err_byte) + movl %edi, %ebx + CONSOLE_ERR_TX_HEX8(%bh) + jmp mem_stop intel_E7500_out: diff --git a/src/northbridge/intel/E7500/reset_test.inc b/src/northbridge/intel/E7500/reset_test.inc index 957d7d4619..7aad6feb2e 100644 --- a/src/northbridge/intel/E7500/reset_test.inc +++ b/src/northbridge/intel/E7500/reset_test.inc @@ -1,10 +1,10 @@ -#define MCH_RICM 0x94 -#define RICM_DONE (1 << 27) +#define MCH_DRC 0x7C +#define DRC_IC (1 << 29) /* If I have already booted once skip a bunch of initialization */ /* To see if I have already booted I check to see if memory * has been enabled. */ - movl $MCH_RICM, %eax + movl $MCH_DRC, %eax PCI_READ_CONFIG_DWORD - testl $RICM_DONE, %eax + testl $DRC_IC, %eax setnz %al diff --git a/src/northbridge/intel/E7500/sdram_enable.inc b/src/northbridge/intel/E7500/sdram_enable.inc index 15e0a6789b..0141551572 100644 --- a/src/northbridge/intel/E7500/sdram_enable.inc +++ b/src/northbridge/intel/E7500/sdram_enable.inc @@ -1,10 +1,42 @@ jmp sdram_enable_out +#ifndef RAM_NOP +#error RAM_NOP not defined +#endif + +#ifndef RAM_PRECHARGE +#error RAM_PRECHARGE not defined +#endif + +#ifndef RAM_EMRS +#error RAM_EMRS not defined +#endif + +#ifndef RAM_MRS +#error RAM_MRS not defined +#endif + +#ifndef RAM_CBR +#error RAM_CBR not defined +#endif + +#ifndef RAM_NORMAL +#error RAM_NORMAL not defined +#endif + +#if ASM_CONSOLE_LOGLEVEL > BIOS_DEBUG ram_enable_1: .string "Ram Enable 1\r\n" ram_enable_2: .string "Ram Enable 2\r\n" ram_enable_3: .string "Ram Enable 3\r\n" ram_enable_4: .string "Ram Enable 4\r\n" ram_enable_5: .string "Ram Enable 5\r\n" +ram_enable_6: .string "Ram Enable 6\r\n" +ram_enable_7: .string "Ram Enable 7\r\n" +ram_enable_8: .string "Ram Enable 8\r\n" +ram_enable_9: .string "Ram Enable 9\r\n" +ram_enable_10: .string "Ram Enable 10\r\n" +ram_enable_11: .string "Ram Enable 11\r\n" +#endif /* Estimate that SLOW_DOWN_IO takes about 50&76us*/ /* delay for 200us */ @@ -16,103 +48,85 @@ ram_enable_5: .string "Ram Enable 5\r\n" jnz 1b +#define EXTRA_DELAY DO_DELAY + enable_sdram: -/* now the fun begins. - turn on the dram and wait a while (this from the intel book) - turn power on and set the nop bit too - */ - CONSOLE_DEBUG_TX_STRING($ram_enable_1) /* 1 & 2 Power up and start clocks */ + CONSOLE_DEBUG_TX_STRING($ram_enable_1) + CONSOLE_DEBUG_TX_STRING($ram_enable_2) + + /* A 200us delay is needed */ DO_DELAY - DO_DELAY - /* Apply NOP */ + EXTRA_DELAY - SET_RAM_COMMAND(RAM_COMMAND_NOP) - - ASSERT_RAM_COMMAND() /* nop command */ - DO_DELAY + /* 3. Apply NOP */ + CONSOLE_DEBUG_TX_STRING($ram_enable_3) + RAM_NOP() + EXTRA_DELAY /* 4 Precharge all */ - SET_RAM_COMMAND(RAM_COMMAND_PRECHARGE) - ASSERT_RAM_COMMAND() + CONSOLE_DEBUG_TX_STRING($ram_enable_4) + RAM_PRECHARGE() + EXTRA_DELAY /* wait until the all banks idle state... */ - - CONSOLE_DEBUG_TX_STRING($ram_enable_2) - DO_DELAY - /* 5. Issue EMRS to enable DLL */ - SET_RAM_COMMAND(RAM_COMMAND_EMRS) - movl (0x0000<bus->secondary, + PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), + ioapic_a, ioapic_d); word = 0x0146; pci_write_config_word(dev, PCICMD, word); dword = 0x358015d9; pci_write_config_dword(dev, SUBSYS, dword); - if(i==0){ - dword = 0xfc100000; - pci_write_config_dword(dev, MBAR, dword); - word = 0x8804; - pci_write_config_word(dev, ABAR, word); - } - if(i==1){ - dword = 0xfc101000; - pci_write_config_dword(dev, MBAR, dword); - word = 0x8800; - pci_write_config_word(dev, ABAR, word); - } +#if 0 + /* writing to the ABAR is removed here because there is a hardware + error on the super micro boards, and it is not needed. */ + dword = (u32)ioapic_a; + word = 0x8000 + ((dword >>8)&0x0fff); + pci_write_config_word(dev, ABAR, word); +#endif + /* Set up the io apic for the p64h2 - 1461 */ + *ioapic_a=0; + *ioapic_d=(addr<<24); /* Set the address number */ + *ioapic_a=3; + *ioapic_d=1; /* Enable the io apic */ + + /* This code test the setup to see if we really found the io apic */ + *ioapic_a=0; + dword=*ioapic_d; + printk_debug("PCI %d apic id = %x\n",addr,dword); + if(dword!=(addr<<24)) + for(;;); + *ioapic_a=3; + dword=*ioapic_d; + printk_debug("PCI %d apic DT = %x\n",addr,dword); + if(dword!=1) + for(;;); + } - *ioapic_1a=0; - *ioapic_1d=(3<<24); - *ioapic_1a=3; - *ioapic_1d=1; - *ioapic_1a=0; - dword=*ioapic_1d; - printk_debug("PCI 1 apic id = %x\n",dword); - if(dword!=(3<<24)) - for(;;); - *ioapic_1a=3; - dword=*ioapic_1d; - printk_debug("PCI 1 apic DT = %x\n",dword); - if(dword!=1) - for(;;); - - *ioapic_2a=0; - *ioapic_2d=(4<<24); - *ioapic_2a=3; - *ioapic_2d=1; - *ioapic_2a=0; - dword=*ioapic_2d; - printk_debug("PCI 2 apic id = %x\n",dword); - if(dword!=(4<<24)) - for(;;); - *ioapic_2a=3; - dword=*ioapic_2d; - printk_debug("PCI 2 apic DT = %x\n",dword); - if(dword!=1) - for(;;); - - } diff --git a/src/southbridge/intel/82870/p64h2_pcibridge.c b/src/southbridge/intel/82870/p64h2_pcibridge.c new file mode 100644 index 0000000000..2f517b30d6 --- /dev/null +++ b/src/southbridge/intel/82870/p64h2_pcibridge.c @@ -0,0 +1,38 @@ +#include +#include +#include +#include +#include +#include "82870.h" + +void p64h2_setup_pcibridge(void) +{ + struct pci_dev *dev; + u32 dword; + u16 word; + u8 byte; + int i; + + + for(i=0,dev=0;i<4;i++) { + /* find the next pci bridge p64h2 - 1460 */ + dev = pci_find_device(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_82870_1F0, dev); + if (!dev) { + if(i<2) /* there should be at least 2 */ + printk_debug("*** ERROR Southbridge device %x not found\n", + PCI_DEVICE_ID_INTEL_82870_1F0); + break; + } + /* The purpose of changes to HCCR, ACNF, and MTT is to speed up the + PCI bus for cards having high speed transfers. */ + dword = 0xc2040002; + pci_write_config_dword(dev, HCCR, dword); + dword = 0x0000c3bf; + pci_write_config_dword(dev, ACNF, dword); + byte = 0x08; + pci_write_config_byte(dev, MTT, byte); + + } + +} diff --git a/src/southbridge/via/vt8231/southbridge.c b/src/southbridge/via/vt8231/southbridge.c index c715aeeb66..0afc57c676 100644 --- a/src/southbridge/via/vt8231/southbridge.c +++ b/src/southbridge/via/vt8231/southbridge.c @@ -6,24 +6,24 @@ void keyboard_on() { volatile unsigned char regval; - /* regval = intel_conf_readb(0x80008851); */ + /* pcibios_read_config_byte(0, 0x88, 0x51, ®val); */ /*regval |= 0x01; */ regval = 0xcf; - intel_conf_writeb(0x80008851, regval); + pcibios_write_config_byte(0, 0x88, 0x51, regval); /* disable USB1 */ - intel_conf_writeb(0x80008A3C, 0x00); - intel_conf_writeb(0x80008A04, 0x00); - regval = intel_conf_readb(0x80008850); + pcibios_write_config_byte(0, 0x8A, 0x3c, 0x00); + pcibios_write_config_byte(0, 0x8A, 0x04, 0x00); + pcibios_read_config_byte(0, 0x88, 0x50, ®val); regval |= 0x10; - intel_conf_writeb(0x80008850, regval); + pcibios_read_config_byte(0, 0x88, 0x50, regval); /* disable USB2 */ - intel_conf_writeb(0x80008B3C, 0x00); - intel_conf_writeb(0x80008B04, 0x00); - regval = intel_conf_readb(0x80008850); + pcibios_write_config_byte(0, 0x8B, 0x3c, 0x00); + pcibios_write_config_byte(0, 0x8B, 0x04, 0x00); + pcibios_read_config_byte(0, 0x88, 0x50, ®val); regval |= 0x20; - intel_conf_writeb(0x80008850, regval); + pcibios_write_config_byte(0, 0x88, 0x50, regval); pc_keyboard_init(); @@ -34,7 +34,7 @@ void nvram_on() /* the VIA 686A South has a very different nvram setup than the piix4e ... */ /* turn on ProMedia nvram. */ /* TO DO: use the PciWriteByte function here. */ - intel_conf_writeb(0x80008841, 0xFF); + pcibios_write_config_byte(0, 0x88, 0x41, 0xff); } void southbridge_fixup() diff --git a/src/southbridge/via/vt82c686/southbridge.c b/src/southbridge/via/vt82c686/southbridge.c index f8696a109b..69384c460c 100644 --- a/src/southbridge/via/vt82c686/southbridge.c +++ b/src/southbridge/via/vt82c686/southbridge.c @@ -9,7 +9,7 @@ void keyboard_on() struct pci_dev *dev; printk_debug("keyboard_on\n"); - /* regval = intel_conf_readb(0x8000385A); */ + /* pcibios_read_config_byte(0, 0x38, 0x5A, ®val); */ /*regval |= 0x01; */ regval = 0xff; diff --git a/src/superio/winbond/w83627hf/Config b/src/superio/winbond/w83627hf/Config index 4e520054ab..c0174c6a9a 100644 --- a/src/superio/winbond/w83627hf/Config +++ b/src/superio/winbond/w83627hf/Config @@ -1,2 +1,3 @@ dir /src/superio/generic object w83627hf_power.o +object power_led.o diff --git a/src/superio/winbond/w83627hf/power_led.c b/src/superio/winbond/w83627hf/power_led.c new file mode 100644 index 0000000000..31ad2209bb --- /dev/null +++ b/src/superio/winbond/w83627hf/power_led.c @@ -0,0 +1,22 @@ +#include +#include + +void power_led(int state) +{ + unsigned char byte; + + w83627hf_enter_pnp(SIO_BASE); + pnp_set_logical_device(SIO_BASE, GPIO_PORT3_DEVICE); + pnp_set_enable(SIO_BASE, 1); + + /* Enable power LED */ + byte = pnp_read_config(SIO_BASE, 0xf3); + byte &= ~(3 << 6); + byte |= state; + pnp_write_config(SIO_BASE, byte, 0xf3); + + w83627hf_exit_pnp(SIO_BASE); + +} + + diff --git a/src/superio/winbond/w83627hf/superio.c b/src/superio/winbond/w83627hf/superio.c index a9d8d19773..fb742c5af9 100644 --- a/src/superio/winbond/w83627hf/superio.c +++ b/src/superio/winbond/w83627hf/superio.c @@ -111,6 +111,19 @@ static void setup_keyboard(struct superio *sio) } } +static void setup_hw_monitor(struct superio *sio) +{ + unsigned iobase0 = HW_MONITOR_DEFAULT_IOBASE0; + /* Select the device */ + pnp_set_logical_device(sio->port, HW_MONITOR_DEVICE); + /* Disable it while initializing */ + pnp_set_enable(sio->port, 0); + if (sio->hwmonitor) { + pnp_set_iobase0(sio->port, iobase0); + pnp_set_enable(sio->port, 1); + } +} + #if 0 static void setup_acpi_registers(struct superio *sio) @@ -177,8 +190,7 @@ static void enable_devices(struct superio *sio) pnp_set_enable(sio->port, sio->acpi); /* enable/disable hw monitor */ - pnp_set_logical_device(sio->port, HW_MONITOR_DEVICE); - pnp_set_enable(sio->port, sio->hwmonitor); + setup_hw_monitor(sio); #if 0 /* setup acpi registers so I am certain to get diff --git a/util/config/NLBConfig.py b/util/config/NLBConfig.py index 718ef60304..2963d5e207 100644 --- a/util/config/NLBConfig.py +++ b/util/config/NLBConfig.py @@ -40,6 +40,7 @@ makerule_targets = [] treetop = '' target_dir = '' +sources = [] objectrules = [] userdefines = [] @@ -116,8 +117,8 @@ def add_main_rule_dependency(new_dependency): # and an optional rule (can be empty) for actually building # the object def addobject(object, sourcepath, rule, condition, variable): - objectrules.append([object, topify(sourcepath), - rule, condition, variable]) + sourcepath = topify(sourcepath) + objectrules.append([object, sourcepath, rule, condition, variable]) # OK, let's face it, make sucks. # if you have a rule like this: @@ -125,8 +126,26 @@ def addobject(object, sourcepath, rule, condition, variable): # make won't apply the .c.o rule. Toy! def addobject_defaultrule(object, sourcepath, condition, variable): - # defaultrule = "\t $(CC) -c $(CFLAGS) -o $@ $<" - defaultrule = "\t@echo $(CC) ... -o $@ $<\n\t@$(CC) -c $(CFLAGS) -o $@ $<" + # c_defaultrule = "$(CC) -c $(CFLAGS) -o $@ $<" + c_defaultrule = "@echo $(CC) ... -o $@ $<\n\t@$(CC) -c $(CFLAGS) -o $@ $<" + s_defaultrule = "@echo $(CC) ... -o $@ $<\n\t@$(CC) -c $(CPU_OPT) -o $@ $<" + S_defaultrule = "@echo $(CPP) ... $< > $@\n\t@$(CPP) $(CPPFLAGS) $< >$@.new && mv $@.new $@" + # Compute the source file name + if (sourcepath[-2:] != '.c') and (sourcepath[-2:] != '.S'): + base = object[:-2] + sourcepath = os.path.join(sourcepath, base) + '.c' + + sources.append(sourcepath) + if (sourcepath[-2:] == '.c'): + defaultrule = "\t" + c_defaultrule + elif (sourcepath[-2:] == '.S'): + base = os.path.basename(sourcepath) + s_name = base[:-2] + '.s' + mkrule(s_name, sourcepath, [ S_defaultrule ] ) + sourcepath = s_name + defaultrule = "\t" + s_defaultrule + else: + fatal("Invalid object suffix") addobject(object, sourcepath, defaultrule, condition, variable) @@ -426,7 +445,14 @@ def ldscript(dir, command): # def object(dir, command): (obj_name, condition) = match(splitargs_re, command) - addobject_defaultrule(obj_name, dir, condition, 'OBJECTS') + if (obj_name[-2:] == '.c') or (obj_name[-2:] == '.S'): + source_name = os.path.join(dir, obj_name) + obj_name = obj_name[:-2] + '.o' + elif (obj_name[-2:] == '.o'): + source_name = os.path.join(dir, obj_name[:-2] + '.c') + else: + fatal("Invalid object name") + addobject_defaultrule(obj_name, source_name, condition, 'OBJECTS') # COMMAND: driver [] # @@ -1053,6 +1079,8 @@ CPUFLAGS := $(foreach _var_,$(VARIABLES),$(call D_item,$(_var_))) file.write("\nSOURCES=\n") + for source in sources: + file.write("SOURCES += %s\n" % source) # Print out the user defines. file.write("\n# userdefines:\n") @@ -1074,10 +1102,6 @@ CPUFLAGS := $(foreach _var_,$(VARIABLES),$(call D_item,$(_var_))) file.write("\n# objectrules:\n") for objrule in objectrules: source = objrule[1] - if (source[-2:] != '.c'): # no suffix. Build name. - base = objrule[0][:-2] - source = os.path.join(source, base) + ".c" - file.write("\nSOURCES += %s\n" % source) file.write("%s: %s\n" % (objrule[0], source)) file.write("%s\n" % objrule[2]) diff --git a/util/lb-dump/dump_lb_table.c b/util/lb-dump/dump_lb_table.c index 90ed034e2b..da495a6f9b 100644 --- a/util/lb-dump/dump_lb_table.c +++ b/util/lb-dump/dump_lb_table.c @@ -107,16 +107,16 @@ void nop_print(struct lb_record *rec, unsigned long addr) void pretty_print_number(FILE *stream, uint64_t value) { - if (value > 1024ULL*1024*1024*1024*1024) { - value /= 1024ULL*1024*1024*1024*1024; + if (value > 1024ULL*1024*1024*1024*1024*1024) { + value /= 1024ULL*1024*1024*1024*1024*1024; fprintf(stream, "%lldEB", value); } + else if (value > 1024ULL*1024*1024*1024*1024) { + value /= 1024ULL*1024*1024*1024*1024; + fprintf(stream, "%lldPB", value); + } else if (value > 1024ULL*1024*1024*1024) { value /= 1024ULL*1024*1024*1024; - fprintf(stream, "%lldPB", value); - } - else if (value > 1024ULL*1024*1024) { - value /= 1024ULL*1024*1024; fprintf(stream, "%lldTB", value); } else if (value > 1024ULL*1024*1024) {