jmp intel_i845gv_out

general_pci_clear_set_byte:
//0003981B: 660FCF                       bswap     edi
	movl	%edi, %ebp
//0003981E: BF2498                       mov       di,09824 ;
//00039821: E951FF                       jmp       000039775   -------- (3)
	CALLDI(general_pci_read_byte)
//00039824: F6D7                         not       bh
	notb	%bh
//00039826: 22C7                         and       al,bh
	andb	%bh, %al
//00039828: F6D7                         not       bh
	notb	%bh
//0003982A: 0AC3                         or        al,bl
	orb	%bl, %al
//0003982C: BF3198                       mov       di,09831 ;
//0003982F: EB96                         jmps      0000397C7   -------- (4)
	CALLDI(general_pci_write_byte)
//00039831: 660FCF                       bswap     edi
	movl	%ebp, %edi
//00039834: FFE7                         jmp       di
	RETDI

gmch_clear_set_byte:
//00039836: BA0000                       mov       dx,00000 ;
	movw	$0x0000, %dx
//00039839: EBE0                         jmps      00003981B   -------- (5)
	jmp	general_pci_clear_set_byte
ich4_clear_set_byte:
//0003983B: BAF800                       mov       dx,000F8 ;
	movw	$0x00F8, %dx
//0003983E: EBDB                         jmps      00003981B   -------- (6)
	jmp	general_pci_clear_set_byte
clear_byte:
//00039840: 8AF8                         mov       bh,al
	movb	%al, %bh
//00039842: B300                         mov       bl,000 ;
	movb	$0x00, %bl
//00039844: EBD5                         jmps      00003981B   -------- (7)
	jmp	general_pci_clear_set_byte
set_byte:
//00039846: 0FB6D8                       movzx     bx,al
	movzx	%al, %bx
//00039849: EBD0                         jmps      00003981B   -------- (8)
	jmp	general_pci_clear_set_byte
gmch_clear_byte:
//0003984B: BA0000                       mov       dx,00000 ;
	movw	$0x0000, %dx
//0003984E: EBF0                         jmps      000039840   -------- (5)
	jmp	clear_byte
ich4_clear_byte:
//00039850: BAF800                       mov       dx,000F8 ;
	movw	$0x00F8, %dx
//00039853: EBEB                         jmps      000039840   -------- (6)
	jmp	clear_byte
gmch_set_byte:
//00039855: BA0000                       mov       dx,00000 ;"  "
	movw	$0x0000, %dx
//00039858: EBEC                         jmps      000039846   -------- (7)
	jmp	set_byte
ich4_pci_set_byte:
//0003985A: BAF800                       mov       dx,000F8 ;
	movw	$0x00F8, %dx
//0003985D: EBE7                         jmps      000039846   -------- (8)
	jmp	set_byte

pci_read_dword:
        movw       $0xCF8,%dx
        andl       $0xfffffffc, %eax
        outl       %eax, %dx
        movw       $0xCFC, %dx
        inl        %dx, %eax
        RETSP

pci_write_dword:
	movw       $0xCF8,%dx
	andl       $0xfffffffc,%eax
	outl       %eax,%dx
	movw       $0xCFC, %dx
	movl       %ebx,%eax
	outl       %eax, %dx
	RETSP

pci_read_word:
	movw	%ax, %dx
	bswapl	%edx
	movw	$0x0CF8, %dx
	andl	$0xfffffffc, %eax
	outl	%eax, %dx	
	bswapl	%edx
	movw	%dx, %ax
	bswapl	%edx
	andw	$0x02, %ax
	addw	%ax, %dx
	addw	$0x04, %dx
	inw	%dx, %ax
	RETSP

pci_write_word:
	movw	%ax, %dx
	bswapl	%edx
	movw	$0x0CF8, %dx
	andl	$0xfffffffc, %eax
	outl	%eax, %dx
	bswapl	%edx
	movw	%dx, %ax
	bswapl 	%edx
	andw	$0x02, %ax
	addw	%ax, %dx
	addw	$0x04, %dx
	movw	%bx, %ax
	outw	%ax, %dx
	RETSP

pci_read_byte:
	movw	%ax, %dx
	bswapl	%edx
	movw	$0x0CF8, %dx
	andl	$0xfffffffc, %eax
	outl	%eax, %dx
	bswapl	%edx
	movw	%dx, %ax
	bswapl	%edx
	andw	$0x03, %ax
	addw	%ax, %dx
	addw	$0x04, %dx
	inb	%dx, %al
	RETSP

pci_write_byte:
	movw	%ax, %dx
	bswapl	%edx
	movw	$0x0CF8, %dx
	andl	$0xfffffffc, %eax
	outl	%eax, %dx
	bswapl	%edx
	movw	%dx, %ax
	bswapl	%edx
	andw	$0x03, %ax
	addw	%ax, %dx
	addw	$0x04, %dx
	mov	%bl, %al
	outb	%al, %dx
	RETSP

ram_3cb60:
	bswap	%edx
	movw	$0x0DFB, %bx
	mulw	%bx
	movw	$0x03E8, %bx
	divw	%bx
	orw	%dx, %dx
	je	no_c
	incw	%ax
no_c:
	movzx	%ax, %ebx
	movw	$0x0800, %dx
	movw	$0x0001, %ax
	outw	%ax, %dx

	addb	$0x08, %dl
	inl	%dx, %eax
	andl	$0x00FFFFFF, %eax
	addl	%eax, %ebx
	subb	$0x08, %dl
1:
	testl	$0xFF000000, %ebx
	je	test_out
in_loop:	
	inw	%dx, %ax
	andw	$0x01, %ax
	je 	in_loop
	outw	%ax, %dx
	subl	$0x01000000, %ebx
	jmp	1b
test_out:
	addb	$0x08, %dl
2:
	inl	%dx, %eax
	andl	$0x00FFFFFF, %eax
	cmpl	%eax, %ebx
	jb	2b
	bswap	%edx
	RETSP	

#define DEBUG_RAM_CONFIG 3


/* DDR DIMM Mode register Definitions */

#define BURST_2           (1<<0)
#define BURST_4           (2<<0)
#define BURST_8           (3<<0)

#define BURST_SEQUENTIAL  (0<<3)
#define BURST_INTERLEAVED (1<<3)

#define CAS_2_0	          (1 << 5)
#define CAS_2_5           00

#define MODE_NORM         (0 << 7)
#define MODE_DLL_RESET    (2 << 7)
#define MODE_TEST         (1 << 7)

#define BURST_LENGTH BURST_4
#define BURST_TYPE   BURST_INTERLEAVED
#define CAS_LATENCY  CAS_2_5

#define MRS_VALUE (MODE_NORM | CAS_LATENCY | BURST_TYPE | BURST_LENGTH)
#define EMRS_VALUE 0x000

#define MD_SHIFT 4

#define RAM_COMMAND_NONE	0x0
#define RAM_COMMAND_NOP		0x1
#define RAM_COMMAND_PRECHARGE	0x2
#define RAM_COMMAND_MRS		0x3
#define RAM_COMMAND_EMRS	0x4
#define RAM_COMMAND_CBR		0x6
#define RAM_COMMAND_NORMAL	0x7

#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
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

#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

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 */

	CONSOLE_DEBUG_TX_CHAR($'Z')
	CONSOLE_DEBUG_TX_CHAR($':')
	
	movl	$0x7c, %eax
	PCI_READ_CONFIG_BYTE
movl	%eax, %esi
	CONSOLE_DEBUG_TX_HEX8(%al)
movl 	%esi, %eax
	andl	$0x8F, %eax
	orb	%bl, %al
	movl	%eax, %esi

	CONSOLE_DEBUG_TX_HEX8(%al)
	CONSOLE_DEBUG_TX_CHAR($'\r')
	CONSOLE_DEBUG_TX_CHAR($'\n')

 	movl	%esi, %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
CONSOLE_DEBUG_TX_CHAR($'S')
CONSOLE_DEBUG_TX_CHAR($':')

movl $0x7c, %eax
PCI_READ_CONFIG_BYTE
movb %al, %bh
	CONSOLE_DEBUG_TX_HEX8(%bh)
	CONSOLE_DEBUG_TX_CHAR($'\r')
	CONSOLE_DEBUG_TX_CHAR($'\n')
	movl	(%ecx), %eax
CONSOLE_DEBUG_TX_CHAR($'T')
CONSOLE_DEBUG_TX_CHAR($':')


	CONSOLE_DEBUG_TX_HEX8(%al)
	CONSOLE_DEBUG_TX_CHAR($'\r')
	CONSOLE_DEBUG_TX_CHAR($'\n')
	

	/* Go to the next base address */
	addl	$0x02000000, %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, (0x1849 << 0) | (0x2560 << 16)
	
	/* 40 - 4F */
	.long 0x40, 0, (05 << 8) | (0xbc << 0 )
	.long 0x44, 0, (0x41 << 0) | (0x20 << 8) | (0x10 << 16)|(0x20<<24)
	.long 0x48, 0, (0x04 << 0) | (0x01 << 8) 
	.long 0x4c, 0, (0x1b << 0) | (0x08 << 8) | (0x10 << 16)


	/* GC - Graphic Control Register */
 	/* 0x52 			*/
	.long 0x52, 0, 0x00000044 


	/* DRB - DRAM Row Boundary Registers
	 * 0x60 - 0x63
	 *     An array of 8 byte registers, which hold the ending
	 *     memory address assigned  to each pair of DIMMS, in 32MB 
	 *     granularity.   
	 */
	/* Conservatively say each row has 32MB of ram, we will fix this up later */
//	.long 0x60, 0x00000000, (0x01 << 0) | (0x02 << 8) | (0x03 << 16) | (0x04 << 24)
/* Aggresively say each row has max ram = 1G, we will fix this up later */
	.long 0x60, 0x00000000, (0x08 << 0) | (0x08 << 8) | (0x08 << 16) | (0x08 << 24)

	/* DRA - DRAM Row Attribute Register 
	 * 0x70 Row 0,1
	 * 0x71 Row 2,3
	 * [7:7] reserved
	 * [6:4] Row Attributes for Odd numbered rows
	 *       000 == 2KB
	 *       001 == 4KB
	 *       010 == 8KB
	 *       011 == 16KB
	 *       Others == Reserved
	 * [3:3] reserved
	 * [2:0] Row Attributes for Even numbered rows
	 *       000 == 2KB
	 *       001 == 4KB
	 *       010 == 8KB
	 *       011 == 16KB (This page size appears broken)
	 *       Others == Reserved
	 */
	.long 0x70, 0x00000000, 0x00000002

	/* DRT - DRAM Time Register
	 * 0x78-0x7B
	 * [31:18] Reserved
	 * [17:15] 
	 *         000: infinite
	 *         001: 0
	 * 	   010: 8 DRAM clocks
 	 * 	   011: 16 DRAM clocks
 	 *	   100: 64 DRAM clocks
    	 * 	   others:
	 * [14:12] Reserved
	 * [11] 
	 *         0 == 120us
	 *         1 == reserved
	 * [10:9]  
	 *         00 == 8 clocks
	 *         01 == 7 clocks
	 *         10 == 6 clocks
	 *         11 == 5 clocks
	 * [8:7]  Reserved
	 * [6:5]  DDR CL
	 *         00 == 2.5
	 *         01 == 2
	 *         10 == Reserved
	 *         11 == Reserved
	 * [4]     Reserved
	 * [3:2] RAS# to CAS# delay
	 *         01 == 3 DRAM clocks
	 *         10 == 2 DRAM Clocks
	 *         11 == Reserved
	 * [1:0] DRAM RAS# precharge
	 *         00 == Reserved
       	 *	   01 == 3 DRAM Clocks
	 * 	   10 == 2 DRAM Clocks
 	 *	   11 == Reserved
	 */
#define DRT_CAS_2_5 (0<<5)
#define DRT_CAS_2_0 (1<<5)
#define DRT_CAS_MASK (3<<5)

#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
#endif

	/* Most aggressive settings possible */
//	.long 0x78, 0x00007190, (0x2b<<24)|(0x41<<16)|(0x82<<8)|0x05
	.long 0x78, 0x00000000, (0x00<<24)|(0x00<<16)|(0x00<<8)|0x00

	/* 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:28] Dynamic Power-Down Mode Enable
	 *	   0 == disable
	 * 	   1 == enable
	 * [27:10] Reserved
	 * [09:07] Refresh mode select
	 *         000 == Reserved
	 *         001 == Refresh interval 15.6 usec
	 *         010 == Refresh interval 7.8 usec
	 *         011 == Refresh interval 64 usec
         *	   111 == Refresh interval 64 clocks
 	 *	   others == 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:01] Reserved
 	 * [00:00] DRAM type(RO)
	 *	   0 == SDR
	 *	   1 == DDR
	 */
//	.long 0x7c, 0x0000007f, (0x20<<24)|(0xc0<<8)|(1 << 8)

	/* 0x80 - 8B */
	.long 0x80, 0, (00<<24)|(0xaf <<16)|(0x01<<8)|(0x29)
	.long 0x84, 0, 0xad
	.long 0x88, 0, 0x01

	/* FDHC - Fixed DRAM Hole Control
	 * 0x97
	 * [7:7] Hole_Enable
	 *       0 == No memory Hole
	 *       1 == Memory Hole from 15MB to 16MB
	 * [6:0] Reserved
	 *
	 * PAM - Programmable Attribute Map
	 * 0x90 [3:0] Reserved
	 * 0x90 [7:4] 0xF0000 - 0xFFFFF
	 * 0x91 [1:0] 0xC0000 - 0xC3FFF
	 * 0x91 [5:4] 0xC4000 - 0xC7FFF
	 * 0x92 [1:0] 0xC8000 - 0xCBFFF
	 * 0x92 [5:4] 0xCC000 - 0xCFFFF
	 * 0x93 [1:0] 0xD0000 - 0xD3FFF
	 * 0x93 [5:4] 0xD4000 - 0xD7FFF
	 * 0x94 [1:0] 0xD8000 - 0xDBFFF
	 * 0x94 [5:4] 0xDC000 - 0xDFFFF
	 * 0x95 [1:0] 0xE0000 - 0xE3FFF
	 * 0x95 [5:4] 0xE4000 - 0xE7FFF
	 * 0x96 [1:0] 0xE8000 - 0xEBFFF
	 * 0x96 [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)
	 */
	.long 0x90, 0x00000000, 0x03311110 
	.long 0x94, 0x00000000, 0x00110000
	.long 0x98, 0x0000ffff, 0x00000445
	.long 0x9c, 0xff0000ff, 0x00380a00


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

	.p2align 3
ram_set_registers:
	movb 	$0xAD, %al
	outb	%al, $0x80
#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)
#if DEBUG_RAM_CONFIG
	CALLSP(dumplpc)
	CALLSP(dumppcibridge)
#endif

#endif
	RET_LABEL(ram_set_registers)

ram_3aada:
	movl	%esp, %ebp

/* RAM NOP */
	movb	$0x7C, %al
	andl	$0x000000ff, %eax
	orl	$0x80000000, %eax
	CALLSP(pci_read_dword)
	andb	$0x8F, %al
	orb	$0x10, %al
	movl	%eax, %ebx
	movb	$0x7C, %al
	andl	$0x000000ff, %eax
	orl	$0x80000000, %eax
	CALLSP(pci_write_dword)
#if 0
	movb	$0x7C, %al
	andl	$0x000000ff, %eax
	orl	$0x80000000, %eax
	CALLSP(pci_read_dword)
	
outb	%al, $0x80
#endif

#if 1
movb	$0xeb, %al
outb	%al,$0x80
#endif

	movl	(%esi), %eax
movb	$0xec, %al
outb	%al, $0x80


	movl	$0x0C8, %eax
	CALLSP(ram_3cb60)

CONSOLE_DEBUG_TX_CHAR($'R')
CONSOLE_DEBUG_TX_CHAR($'1')
CONSOLE_DEBUG_TX_CHAR($'\r')
CONSOLE_DEBUG_TX_CHAR($'\n')


/* All Banks Pre-Charge */
	xorl	%esi, %esi
	movb	$0x7c, %al
	andl	$0x000000ff, %eax
	orl	$0x80000000, %eax
	CALLSP(pci_read_dword)
	andb	$0x8F, %al
	orb 	$0x20, %al
	movl	%eax, %ebx
	movb 	$0x7c, %al
	andl	$0x000000FF, %eax
	orl	$0x80000000, %eax
	CALLSP(pci_write_dword)
	movl	(%esi), %eax
CONSOLE_DEBUG_TX_CHAR($'R')
CONSOLE_DEBUG_TX_CHAR($'2')
CONSOLE_DEBUG_TX_CHAR($'\r')
CONSOLE_DEBUG_TX_CHAR($'\n')

/* EMRS */
	movb	$0x7C, %al
	andl	$0x000000FF, %eax
	orl	$0x80000000, %eax
	CALLSP(pci_read_dword)
	andb	$0x8F, %al
	orb	$0x40, %al
	mov	%eax, %ebx
	movb	$0x7C, %al
	andl	$0x000000FF, %eax
	orl	$0x80000000, %eax
	CALLSP(pci_write_dword)
	movl	(%esi), %eax
CONSOLE_DEBUG_TX_CHAR($'R')
CONSOLE_DEBUG_TX_CHAR($'3')
CONSOLE_DEBUG_TX_CHAR($'\r')
CONSOLE_DEBUG_TX_CHAR($'\n')

/* MRS */
	movb	$0x7C, %al
	andl	$0x000000FF, %eax
	orl	$0x80000000, %eax
	CALLSP(pci_read_dword)
	andb	$0x8F, %al
	orb	$0x30, %al
	movl	%eax, %ebx
	movb 	$0x7C, %al
	andl	$0x000000FF, %eax
	orl	$0x80000000, %eax
	CALLSP(pci_write_dword)
	addl	$0x350, %esi
	orl	$0x800, %esi
	movl	(%esi), %eax
	andl	$0xFE000000, %esi
/* precharge */
	movb	$0x7C, %al
	andl	$0x000000FF, %eax
	orl	$0x80000000, %eax
	CALLSP(pci_read_dword)
	movb	$0x8F, %al
	orb	$0x20, %al
	movl	%eax, %ebx
	movb	$0x7C, %al
	andl	$0x000000FF, %eax
	orl	$0x80000000, %eax
	CALLSP(pci_write_dword)
	movl	(%esi), %eax
/* CBR Refresh Enable */
	movb	$0x7C, %al
	andl	$0x000000FF, %eax
	orl	$0x80000000, %eax
	CALLSP(pci_read_dword)
	andb	$0x8F, %al
	orb	$0x60, %al
	movl	%eax, %ebx
	movb	$0x7C, %al
	andl	$0x000000FF, %eax
	orl	$0x80000000, %eax
	CALLSP(pci_write_dword)
	movl	(%esi), %eax
	movl	(%esi), %eax
	movl	(%esi), %eax
	movl	(%esi), %eax
	movl	(%esi), %eax
	movl	(%esi), %eax
	movl	(%esi), %eax
	movl	(%esi), %eax
	addl	$0x350, %esi
	movb	$0x7C, %al
	andl	$0x000000FF, %eax
	orl	$0x80000000, %eax
	CALLSP(pci_read_dword)
	andb	$0x8F, %al
	orb	$0x30, %al
	movl	%eax, %ebx
	movb	$0x7C, %al
	andl	$0x000000FF, %eax
	orl	$0x80000000, %eax
	CALLSP(pci_write_dword)
	movl	(%esi), %eax
	andl	$0xFE000000, %esi

	movl	%ebp, %esp
	RETSP

	/*
	 * 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
	 *
	 * 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
/* zhu */
	CONSOLE_INFO_TX_CHAR($'Z')
	CONSOLE_INFO_TX_CHAR($':')
	CONSOLE_INFO_TX_HEX8(%ch)
	CONSOLE_INFO_TX_CHAR($'\r')
	CONSOLE_INFO_TX_CHAR($'\n')
	movb	%ch, %al
	/* 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:

	/* Back-to-Back Random Column Accesses */
	movb	$15, %bh
	CALLSP(spd_read_paired_byte)
	jz	spd_missing_data
	testb	%al, %al
	jz	spd_invalid_data
	cmpb	$4, %al
	ja	spd_unsupported_data

	/* Burst Lengths */
	movb	$16, %bh
	CALLSP(spd_read_paired_byte)
	jz	spd_missing_data
	testb	$(1<<2), %al
	jz	spd_unsupported_data

	/* Logical Banks */
	movb	$17, %bh
	CALLSP(spd_read_paired_byte)
	jz	spd_missing_data
	testb	%al, %al
	jz	spd_invalid_data
	
	/* Supported CAS Latencies */
	movb	$18, %bh
	CALLSP(spd_read_paired_byte)
	jz	spd_missing_data
	testb	$(1 << 1), %al /* CL 1.5 */
	jnz	1f
	testb	$(1 << 2), %al /* CL 2.0 */
	jnz	1f
	testb	$(1 << 3), %al /* CL 2.5 */
	jnz	1f
	jmp	spd_unsupported_data
1:
	
	/* Cycle time at Cas Latency (CLX - 0.5) */
	movb	$23, %bh
	CALLSP(spd_read_paired_byte)
	jz	spd_missing_data
        /* DRAM Minimum Clock Cycle when CL is Derated by One Clock*/
	movb	$25, %bh
	CALLSP(spd_read_paired_byte)
	jz 	spd_missing_data

	/* Cycle time at Cas Latency (CLX - 1.0) */
	movb	$26, %bh
	CALLSP(spd_read_paired_byte)
	jz	spd_missing_data
	
	/* tRP Row precharge time */
	movb	$27, %bh
	CALLSP(spd_read_paired_byte)
	jz	spd_missing_data
	testb	$0xfc, %al
	jz	spd_invalid_data
	

	/* 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)





     /* Estimate that SLOW_DOWN_IO takes about 50&76us*/
     /* delay for 200us */

#define DO_DELAY \
        movl $16, %edi          ; \
1:      SLOW_DOWN_IO            ; \
        decl %edi               ; \
        jnz 1b

#define EXTRA_DELAY DO_DELAY

#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 "
crlf:           .string "\r\n" 
.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

mem_stop:
        CONSOLE_ERR_TX_STRING($crlf)
1:
        hlt /* stick here.. */
        jmp 1b

intel_i845gv_out:

	CALL_LABEL(spd_verify_dimms)


	CALL_LABEL(ram_set_registers)
	
	DO_DELAY
	EXTRA_DELAY
//00039EDB: 6633F6                       xor       esi,esi
	xorl	%esi, %esi
//00039EDE: 32C9                         xor       cl,cl
	xorb	%cl, %cl
//00039EE0: B060                         mov       al,060 ;
	movb	$0x60, %al
//00039EE2: 6625FF000000                 and       eax,0000000FF ;
	andl	$0x000000FF, %eax
//00039EE8: 660D00000080                 or        eax,080000000 ;
	orl	$0x80000000, %eax
//00039EEE: 660FCC                       bswap     esp
//00039EF1: BCF79E                       mov       sp,09EF7 ;
//00039EF4: E9DFFA                       jmp       0000399D6   -------- (1)
//00039EF7: 660FCC                       bswap     esp
	CALLSP(pci_read_dword)
2:
//00039EFA: 38C8                         cmp       al,cl
	cmpb	%cl, %al
//00039EFC: 7412                         je        000039F10   -------- (2)
	je 	1f
//00039EFE: 668BF8                       mov       edi,eax
	movl	%eax, %edi
//00039F01: 660FCC                       bswap     esp
//00039F04: BC0A9F                       mov       sp,09F0A ;
//00039F07: E9D00B                       jmp       00003AADA   -------- (3)
//00039F0A: 660FCC                       bswap     esp
	CALLSP(ram_3aada)
//00039F0D: 668BC7                       mov       eax,edi
	movl	%edi, %eax
1:
//00039F10: 8AC8                         mov       cl,al
	movb	%al, %cl
//00039F12: 6633F6                       xor       esi,esi
	xorl	%esi, %esi
//00039F15: 660FB6F1                     movzx     esi,cl
	movzx	%cl, %esi
//00039F19: 66C1E619                     shl       esi,019 ;
	shll	$0x19, %esi
//00039F1D: 66C1E808                     shr       eax,008 ;
	shrl	$0x08, %eax
//00039F21: 6683F800                     cmp       eax,000 ;
	cmpl	$0x00, %eax
//00039F25: 75D3                         jne       000039EFA   -------- (3)
	jne	2b

/* normal mode */
	movb	$0x7C, %al
	andl	$0x000000FF, %eax
	orl	$0x80000000, %eax
	CALLSP(pci_read_dword)
	andb	$0x8F, %al
	orb	$0x70, %al
	movl	%eax, %ebx
	movb	$0x7C, %al
	andl	$0x000000FF, %eax
	orl	$0x80000000, %eax
	CALLSP(pci_write_dword)

CONSOLE_DEBUG_TX_CHAR($'E')
CONSOLE_DEBUG_TX_CHAR($'N')
CONSOLE_DEBUG_TX_CHAR($'\r')
CONSOLE_DEBUG_TX_CHAR($'\n')
hlt
	
