mirror of
https://github.com/fail0verflow/switch-coreboot.git
synced 2025-05-04 01:39:18 -04:00
missing file.
This commit is contained in:
parent
02846565a9
commit
11c8c6f387
1 changed files with 542 additions and 0 deletions
542
src/mainboard/via/epia-m/smbus.inc
Normal file
542
src/mainboard/via/epia-m/smbus.inc
Normal file
|
@ -0,0 +1,542 @@
|
||||||
|
/* Useful macros PCIBUS, and SMBUS functions for getting DRAM going. */
|
||||||
|
/* courtesy Eric Biederman of linuxnetworx.com */
|
||||||
|
|
||||||
|
#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
|
||||||
|
|
||||||
|
#define DEVFN(device, function) (((device) << 3) + (function))
|
||||||
|
#ifndef CONFIG_ADDR
|
||||||
|
#define CONFIG_ADDR(bus,devfn,where) (((bus) << 16) | ((devfn) << 8) | (where))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* jump around these subrs */
|
||||||
|
jmp smbus_pcibus_end
|
||||||
|
|
||||||
|
/* generic SMB routines that work for many systems. The only one that might
|
||||||
|
* not work is the enable_smbus.
|
||||||
|
* you have to define PM_FUNCTION for this to work.
|
||||||
|
*/#define SMBUS_IO_BASE 0xf00
|
||||||
|
#define SMBHSTSTAT 0
|
||||||
|
#define SMBHSTCTL 2
|
||||||
|
#define SMBHSTCMD 3
|
||||||
|
#define SMBHSTADD 4
|
||||||
|
#define SMBHSTDAT0 5
|
||||||
|
#define SMBHSTDAT1 6
|
||||||
|
#define SMBBLKDAT 7
|
||||||
|
|
||||||
|
/* (DA) Lines added to get this to compile */
|
||||||
|
#define PM_DEVFN CONFIG_ADDR(0,0x11*8,0)
|
||||||
|
#define DRAM_CONFIG_PORT 0x5a
|
||||||
|
#define SMBUS_MEM_DEVICE_0 0x50
|
||||||
|
#define LAST_SMBUS_MEM_DEVICE SMBUS_MEM_DEVICE_0
|
||||||
|
#define REGISTERED_DRAM_REGISTER $0x69
|
||||||
|
#define REGISTERED_DRAM $0x2d
|
||||||
|
#define NONREGISTERED_DRAM $0
|
||||||
|
|
||||||
|
|
||||||
|
enable_smbus:
|
||||||
|
/* put the SMBUS at port 0xf00 */
|
||||||
|
CS_WRITE_WORD(PM_DEVFN+ 0xd0, SMBUS_IO_BASE|1) /* iobase addr */
|
||||||
|
CS_WRITE_BYTE(PM_DEVFN + 0xd2, (0x4 << 1) | 1) /* smbus enable */
|
||||||
|
CS_WRITE_WORD(PM_DEVFN + 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
|
||||||
|
movl $(SMBUS_IO_BASE +SMBHSTSTAT), %edx
|
||||||
|
outb %al, %dx
|
||||||
|
RET_LABEL(setup_smbus)
|
||||||
|
|
||||||
|
#ifndef SMBUS_MEM_DEVICE_0
|
||||||
|
#define SMBUS_MEM_DEVICE_0 (0xa << 3)
|
||||||
|
#endif
|
||||||
|
#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 ; \
|
||||||
|
CALLSP(smbus_read_byte)
|
||||||
|
|
||||||
|
smbus_read_byte:
|
||||||
|
/* poll until the smbus is ready for commands */
|
||||||
|
CALL_LABEL(smbus_wait_until_ready)
|
||||||
|
|
||||||
|
/* clear any lingering errors, so that the transaction will run */
|
||||||
|
movl $(SMBUS_IO_BASE + SMBHSTSTAT), %edx
|
||||||
|
inb %dx, %al
|
||||||
|
outb %al, %dx
|
||||||
|
|
||||||
|
/* 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
|
||||||
|
|
||||||
|
/* 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
|
||||||
|
|
||||||
|
#if 1 // TEMPORARY (DA) 20030718
|
||||||
|
|
||||||
|
/* now for code to actually do the deed. Eric did such a good job that
|
||||||
|
* this stuff is basically generic.
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* Routine: spd_set_drb
|
||||||
|
* Arguments: None
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
* %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
|
||||||
|
*/
|
||||||
|
|
||||||
|
spd_set_drb:
|
||||||
|
xorl %ebp, %ebp /* clear the memory address */
|
||||||
|
movl $((DRAM_CONFIG_PORT << 16) |SMBUS_MEM_DEVICE_0), %ebx
|
||||||
|
spd_set_drb_loop_top:
|
||||||
|
// set -1 power-of-two for side 1 (called bank0 in most chipset docs)
|
||||||
|
xorl %edi, %edi
|
||||||
|
subl $1, %edi
|
||||||
|
// set -1 power-of-two for side 2 (called bank1 in most chipset docs)
|
||||||
|
xorl %esi, %esi
|
||||||
|
subl $1, %esi
|
||||||
|
|
||||||
|
movb $3, %bh /* rows */
|
||||||
|
CALLSP(smbus_read_byte)
|
||||||
|
// If it's zero, then we just set current %ebp into the row
|
||||||
|
// end register
|
||||||
|
jz 20f
|
||||||
|
andl $0xf, %eax
|
||||||
|
addl %eax, %edi
|
||||||
|
|
||||||
|
movb $4, %bh /* columns */
|
||||||
|
CALLSP(smbus_read_byte)
|
||||||
|
andl $0xf, %eax
|
||||||
|
addl %eax, %edi
|
||||||
|
|
||||||
|
movb $17, %bh /* banks */
|
||||||
|
CALLSP(smbus_read_byte)
|
||||||
|
andl $0xff, %eax
|
||||||
|
bsrl %eax, %ecx
|
||||||
|
addl %ecx, %edi
|
||||||
|
|
||||||
|
/* Get the module data width and convert it to a power of two */
|
||||||
|
movb $7, %bh /* (high byte) */
|
||||||
|
CALLSP(smbus_read_byte)
|
||||||
|
andl $0xff, %eax
|
||||||
|
movl %eax, %ecx
|
||||||
|
shll $8, %ecx
|
||||||
|
|
||||||
|
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) */
|
||||||
|
// It is less 1 since we started with -1 above.
|
||||||
|
// OK, BITS as power of two (but minus 1)
|
||||||
|
// So, e.g., 8 MB is 64 Mb, 64 Mb is 26 bits. Subtract
|
||||||
|
// (26-1) or 25
|
||||||
|
subl $25, %edi /* Make it multiples of 8MB */
|
||||||
|
|
||||||
|
/* side two */
|
||||||
|
movb $5, %bh /* number of physical banks */
|
||||||
|
CALLSP(smbus_read_byte)
|
||||||
|
cmp $1, %al
|
||||||
|
// it's only one bank
|
||||||
|
jbe 20f
|
||||||
|
// It's two banks. So assign edi to esi
|
||||||
|
/* for now only handle the symmetrical case */
|
||||||
|
// it's two banks, assume however that they're the same size.
|
||||||
|
// it's stupid to have any other kind, right?
|
||||||
|
movl %edi, %esi
|
||||||
|
20:
|
||||||
|
/* Compute the end address for the DRB register */
|
||||||
|
// If it is >= 8, i.e. >= 2^8 or 256, skip it.
|
||||||
|
// >= 8 is a bogus value.
|
||||||
|
cmpl $8, %edi
|
||||||
|
jae 21f
|
||||||
|
movl $1, %eax
|
||||||
|
movl %edi, %ecx
|
||||||
|
shll %cl, %eax
|
||||||
|
// increment row-end by the size of this DIMM half
|
||||||
|
addl %eax, %ebp
|
||||||
|
21:
|
||||||
|
/* Write the comuputed 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
|
||||||
|
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
|
||||||
|
|
||||||
|
addl $0x00020001, %ebx /* increment the smbus device & the config port */
|
||||||
|
cmpb $LAST_SMBUS_MEM_DEVICE, %bl /* see if I have reached the end */
|
||||||
|
jbe spd_set_drb_loop_top
|
||||||
|
|
||||||
|
/* o.k. I'm done return now */
|
||||||
|
RET_LABEL(spd_set_drb)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Routine: spd_set_dramc
|
||||||
|
* Arguments: None
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
* FIXME: won't work with non-contiguous DRAM size regs (like VIA)
|
||||||
|
* need an indirect pointer to an array of reg #s
|
||||||
|
*/
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
2: addl $1, %ebx /* increment the device */
|
||||||
|
cmpb $LAST_SMBUS_MEM_DEVICE, %bl
|
||||||
|
jbe 1b
|
||||||
|
/* We couldn't find anything we must have no memory */
|
||||||
|
jmp no_memory
|
||||||
|
|
||||||
|
spd_set_dramc_out:
|
||||||
|
testb $0x12, %al
|
||||||
|
jz 2f
|
||||||
|
movl REGISTERED_DRAM, %eax
|
||||||
|
jmp 1f
|
||||||
|
2: movl NONREGISTERED_DRAM, %eax
|
||||||
|
1: movl %eax, %edx
|
||||||
|
movl REGISTERED_DRAM_REGISTER, %eax
|
||||||
|
PCI_WRITE_CONFIG_BYTE
|
||||||
|
RET_LABEL(spd_set_dramc)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Routine: spd_read_refresh
|
||||||
|
* Arguments: None
|
||||||
|
*
|
||||||
|
* Trashed: %eax, %ebx, %ecx, %edx, %esp, %eflags
|
||||||
|
* Effects: Uses serial presence detect to find refresh rates.
|
||||||
|
* returns the rate in %eax
|
||||||
|
* It's up to you to set hardware up.
|
||||||
|
* FIXME: Check for illegal/unsupported ram configurations and abort
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
spd_read_refresh:
|
||||||
|
/* Find the first dimm and assume the rest are the same */
|
||||||
|
/* Load the smbus device and port int %ebx */
|
||||||
|
movl $((12 << 8) | SMBUS_MEM_DEVICE_0), %ebx
|
||||||
|
1: CALLSP(smbus_read_byte)
|
||||||
|
jz 2f
|
||||||
|
andl $0x7f, %eax
|
||||||
|
jmp spd_enable_refresh_out
|
||||||
|
|
||||||
|
2: addl $1, %ebx /* increment the device */
|
||||||
|
cmpb $LAST_SMBUS_MEM_DEVICE, %bl
|
||||||
|
jbe 1b
|
||||||
|
/* We couldn't find anything we must have no memory */
|
||||||
|
xorl %eax, %eax
|
||||||
|
spd_enable_refresh_out:
|
||||||
|
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
|
||||||
|
|
||||||
|
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
|
||||||
|
shll %cl, %edi
|
||||||
|
orl %edi, %esi
|
||||||
|
|
||||||
|
2: addl $1, %ebx /* increment the device */
|
||||||
|
addl $4, %ecx /* increment the shift count */
|
||||||
|
cmpb $LAST_SMBUS_MEM_DEVICE, %bl
|
||||||
|
jbe 1b
|
||||||
|
|
||||||
|
movl $0x7f, %eax
|
||||||
|
/* I'm not sure what we should do here. Do nothing. */
|
||||||
|
/* 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 $LAST_SMBUS_MEM_DEVICE, %bl
|
||||||
|
jbe 1b
|
||||||
|
|
||||||
|
shll $8, %esi
|
||||||
|
orl $0x7, %esi /* 32 clocks idle time */
|
||||||
|
movl %esi, %ecx
|
||||||
|
movl $0x78, %eax
|
||||||
|
/* I'm unclear on the concept for non-intel devices */
|
||||||
|
/* 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 $LAST_SMBUS_MEM_DEVICE, %bl
|
||||||
|
jbe 1b
|
||||||
|
|
||||||
|
movl %esi, %edx
|
||||||
|
/* at some point, we need to indicate how to turn ECC on. Not yet.
|
||||||
|
movl $0x53, %eax
|
||||||
|
PCI_WRITE_CONFIG_BYTE
|
||||||
|
*/
|
||||||
|
RET_LABEL(spd_set_nbxcfg)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
smbus_pcibus_end:
|
Loading…
Add table
Reference in a new issue