You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

771 lines
15 KiB

/************************
function PROBE_DIMM changed by cxk on 09/26/2010
Single CHIP & USE_SB_I2C mode & DDR2 DIMM can work normal
DDR3 SDRAM need to be finished!!
************************/
#define BONITO_HTIO_BASE_VA 0x90000efdfc000000
#define CHIP1_BASE_ADDRESS 0x0000100000000000
#define CHIP2_BASE_ADDRESS 0x0000200000000000
#define CHIP3_BASE_ADDRESS 0x0000300000000000
#ifndef MULTI_CHIP
#ifdef USE_SB_I2C
LEAF(i2cread)
/***************
use register:
v0, v1
a0, a1
***************/
ori a0,a0,1
/* set device address */
//li v0, 0xbfd00000 + SMBUS_HOST_ADDRESS
dli v0, BONITO_HTIO_BASE_VA + SMBUS_HOST_ADDRESS
sb a0, 0(v0);
/* store register offset */
//li v0, 0xbfd00000 + SMBUS_HOST_COMMAND
dli v0, BONITO_HTIO_BASE_VA + SMBUS_HOST_COMMAND
sb a1, 0(v0);
/* read byte data protocol */
li v0, 0x08
//li v1, 0xbfd00000 + SMBUS_HOST_CONTROL
dli v1, BONITO_HTIO_BASE_VA + SMBUS_HOST_CONTROL
sb v0, 0(v1);
/* make sure SMB host ready to start, important!--zfx */
//li v1, 0xbfd00000 + SMBUS_HOST_STATUS
dli v1, BONITO_HTIO_BASE_VA + SMBUS_HOST_STATUS
lbu v0, 0(v1)
andi v0,v0, 0x1f
beqz v0,1f
nop
sb v0, 0(v1)
lbu v0, 0(v1) #flush the write
1:
/* start */
//li v1, 0xbfd00000 + SMBUS_HOST_CONTROL
dli v1, BONITO_HTIO_BASE_VA + SMBUS_HOST_CONTROL
lbu v0, 0(v1)
ori v0, v0, 0x40
sb v0, 0(v1);
/* wait */
//li v1, 0xbfd00000 + SMBUS_HOST_STATUS
dli v1, BONITO_HTIO_BASE_VA + SMBUS_HOST_STATUS
1:
#if 0
/* delay */
li a0, 0x1000
2:
bnez a0,2b
addiu a0, -1
#endif
lbu v0, 0(v1)
andi v0, SMBUS_HOST_STATUS_BUSY
bnez v0, 1b #IDEL ?
nop
//li v1, 0xbfd00000 + SMBUS_HOST_STATUS
dli v1, BONITO_HTIO_BASE_VA + SMBUS_HOST_STATUS
lbu v0, 0(v1)
andi v0,v0, 0x1f
beqz v0,1f
nop
sb v0, 0(v1) #reset
lbu v0, 0(v1) #flush the write
1:
//li v1, 0xbfd00000 + SMBUS_HOST_DATA0
dli v1, BONITO_HTIO_BASE_VA + SMBUS_HOST_DATA0
lbu v0, 0(v1)
jr ra
nop
END(i2cread)
#else
#ifdef USE_GPIO_I2C
#include "i2c_firewall.S"
#endif
#endif
/*************************
PROBE_DIMM:
function: probe the given slot(I2C device id is given in a0),
if there is no DIMM in this slot, clear SDRAM_TYPE to 0,
else read the DIMM infor from the SPD and store the infor in s1(CS_MAP at [17:16],
MEMSIZE at [11:8]).
use register:
a0,a1,a2,a3
v0, v1
t5, t6
t7: store ra
a0: input, i2c device id(don't change it).
a1: register offset of i2c device
*************************/
#if 0 //debug code, used in PROBE_DIMM, after read i2c, print v0
//debug------------
move t5, a0
move t6, v0
TTYDBG("\r\nBanks: ")
move a0, t6
bal hexserial
nop
TTYDBG("\r\n")
move a0, t5
move v0, t6
//------------debug
//Test whether i2cread will dead loop
move t5, a0
TTYDBG("\r\nIn Probe_DIMM, before i2cread!")
move a0, t5
dli a1, 0
bal i2cread
nop
move t5, a0
TTYDBG("\r\nIn Probe_DIMM, after i2cread!")
move a0, t5
#endif
LEAF(PROBE_DIMM)
move t7, ra
//read the i2c spd for learn,read data is abandon
dli a1, 0
bal i2cread
nop
//probe SDRAM type, if SDRAM type error, repeat t6 times.
dli t6, 8 //max probing times(t6)
1:
//delay some time
dli t5, 0xfff
2:
daddiu t5, t5, -1
bnez t5, 2b
nop
daddiu t6, t6, -1
dli a1, 2
bal i2cread
nop
//only bit[7:0] used
andi v0, v0, 0xff
/* v0 should be 0xb or 0x8,else error DIMM type */
dli t5, 0x08
beq v0, t5, DDR2
nop
dli t5, 0x0B
beq v0, t5, DDR3
nop
//this time probe error
bnez t6, 1b
nop
3:
TTYDBG("\r\nNO DIMM in this slot.\r\n")
b ERROR_TYPE
nop
DDR2:
dli t5, 0x2
dsll t5, t5, SDRAM_TYPE_OFFSET
or s1, s1, t5
//probe DIMM_TYPE
dli a1, 20
bal i2cread
nop
//only bit[5:0] used
andi v0, v0, 0x3f
//here just recognize RDIMM and UDIMM
dli t5, 0x01
beq v0, t5, 1f
nop
dli t5, 0x02
beq v0, t5, 2f
nop
TTYDBG("\r\nERROR: DIMM type is not in support range(UDIMM or RDIMM).\r\n")
b ERROR_TYPE
nop
1: //RDIMM
dli t5, 0x1
dsll t5, t5, DIMM_TYPE_OFFSET
or s1, s1, t5
b 3f
nop
2: //UDIMM
3:
//probe DIMM ECC
dli a1, 11
bal i2cread
nop
//only bit[2:0] used
andi v0, v0, 0x07
//here just recognize ECC or not
andi t5, v0, 0x2
dsrl t5, t5, 1
dsll t5, t5, DIMM_ECC_OFFSET
or s1, s1, t5
//probe SDRAM_ROW_SIZE
dli a1, 3
bal i2cread
nop
//only bit[7:0] used
andi v0, v0, 0xff
//v0 should < 15
andi v0, v0, 0x0f
dli t5, 15
subu t5, t5, v0
dsll t5, t5, ROW_SIZE_OFFSET
or s1, s1, t5
//probe SDRAM_COL_SIZE
dli a1, 4
bal i2cread
nop
//only bit[7:0] used
andi v0, v0, 0xff
//v0 should < 14
andi v0, v0, 0x0f
dli t5, 14
subu t5, t5, v0
dsll t5, t5, COL_SIZE_OFFSET
or s1, s1, t5
//probe SDRAM BANK number
dli a1, 17
bal i2cread
nop
//bit[7:0] used
andi v0, v0, 0xff
//here just recognize 4 banks or 8 banks
dli t5, 0x08
beq v0, t5, 1f
nop
dli t5, 0x04
beq v0, t5, 2f
nop
TTYDBG("\r\nERROR: SDRAM Banks number is not in support range(4 or 8).\r\n")
b ERROR_TYPE
nop
1: //8 banks
dli t5, 0x1
dsll t5, t5, EIGHT_BANK_OFFSET
or s1, s1, t5
b 3f
nop
2: //4 banks
3:
//probe DIMM Ranks
dli a1, 5
bal i2cread
nop
//only bit[2:0] used
andi v0, v0, 0x7
//here just recognize 1 ranks or 2 ranks
dli t5, 0x0
beq v0, t5, 1f
nop
dli t5, 0x1
beq v0, t5, 2f
nop
TTYDBG("\r\nERROR: DIMM Ranks number is not in support range(1 or 2).\r\n")
b ERROR_TYPE
nop
1: //1 rank
dli t5, 0x1
b 3f
nop
2: //2 ranks
dli t5, 0x3
3:
dsll t5, t5, MC_CS_MAP_OFFSET
or s1, s1, t5
//probe DIMM Memory SIZE
dli a1, 31
bal i2cread
nop
//only bit[7:0] used
andi v0, v0, 0xff
//currently only support 1 rank >= 512M & 2 ranks <= 4G, else assume there is NO DIMM
move t5, v0
dli t6, 0xe0
and t5, t5, t6
beqz t5, 1f
nop
//1 rank<= 512M
dsrl t5, t5, 7
beqz t5, 2f //1 rank < 512M, error
nop
//1 rank = 512M, double the MEMSIZE if there are 2 ranks
GET_MC_CS_MAP
dsrl a1, a1, 1 //test the cs 1
beqz a1, 5f
nop
//double the size
dsll t5, t5, 1
5:
dsll t5, t5, DIMM_MEMSIZE_OFFSET
or s1, s1, t5
b 3f
nop
1: //1 rank >= 1G
//double the MEMSIZE if there are 2 ranks
GET_MC_CS_MAP
dsrl a1, a1, 1 //test the cs 1
beqz a1, 5f
nop
//double the size
dsll v0, v0, 1
5:
dli t5, 0x7
and t5, t5, v0
beqz t5, 2f //DIMM SIZE > 4G
nop
dsll t5, v0, 1 //MEMSIZE is 512M/unit, v0 is 1G/unit
dsll t5, t5, DIMM_MEMSIZE_OFFSET
or s1, s1, t5
b 3f
nop
2:
//1 rank < 512M or DIMM SIZE > 4G, errors(clear SDRAM_TYPE, assume there is NO DIMM in this slot)
dli t5, 0x3
dsll t5, t5, SDRAM_TYPE_OFFSET
not t5, t5
and s1, s1, t5
TTYDBG("\r\nERROR: DIMM size is not in support range(512M~4G).\r\n")
b ERROR_TYPE
nop
3:
//DDR2 probe finished
b end
nop
DDR3: //DDR3 SDRAM
dli t5, 0x3
dsll t5, t5, SDRAM_TYPE_OFFSET
or s1, s1, t5
//!!!!!!need to be completed
b end
nop
ERROR_TYPE:
//no DIMM or unrecognized DIMM in this slot
dli t5, 0x3
dsll t5, t5, SDRAM_TYPE_OFFSET
not t5, t5
and s1, s1, t5
end:
jr t7
nop
END(PROBE_DIMM)
#else //Multi chips
//not checked now!!!!!!!!!!1
/****************************************************/
/* for multi-chip mode */
/****************************************************/
/* input: a0,a1,a2
a0: device ID
a1: register offset
a2: chip ID (0,1,2,3)
changed registers: v0,v1,t3
*/
LEAF(i2cread)
ori a0,a0,1
/* added address offset according chip ID */
beqz a2,88f
nop
beq a2,0x1, 81f
nop
beq a2,0x2, 82f
nop
dli t3, CHIP3_BASE_ADDRESS
b 88f
81: dli t3, CHIP1_BASE_ADDRESS
b 88f
nop
82: dli t3, CHIP2_BASE_ADDRESS
b 88f
nop
88:
/* set device address */
//li v0, 0xbfd00000 + SMBUS_HOST_ADDRESS
dli v0, BONITO_HTIO_BASE_VA + SMBUS_HOST_ADDRESS
dadd v0,v0,t3
sb a0, 0(v0);
/* store register offset */
//li v0, 0xbfd00000 + SMBUS_HOST_COMMAND
dli v0, BONITO_HTIO_BASE_VA + SMBUS_HOST_COMMAND
dadd v0,v0,t3
sb a1, 0(v0);
/* read byte data protocol */
li v0, 0x08
//li v1, 0xbfd00000 + SMBUS_HOST_CONTROL
dli v1, BONITO_HTIO_BASE_VA + SMBUS_HOST_CONTROL
dadd v1,v1,t3
sb v0, 0(v1);
/* make sure SMB host ready to start, important!--zfx */
//li v1, 0xbfd00000 + SMBUS_HOST_STATUS
dli v1, BONITO_HTIO_BASE_VA + SMBUS_HOST_STATUS
dadd v1,v1,t3
lbu v0, 0(v1)
andi v0,v0, 0x1f
beqz v0,1f
nop
sb v0, 0(v1)
lbu v0, 0(v1) #flush the write
1:
/* start */
//li v1, 0xbfd00000 + SMBUS_HOST_CONTROL
dli v1, BONITO_HTIO_BASE_VA + SMBUS_HOST_CONTROL
dadd v1,v1,t3
lbu v0, 0(v1)
ori v0, v0, 0x40
sb v0, 0(v1);
/* wait */
//li v1, 0xbfd00000 + SMBUS_HOST_STATUS
dli v1, BONITO_HTIO_BASE_VA + SMBUS_HOST_STATUS
dadd v1,v1,t3
1:
#if 0
/* delay */
li a0, 0x1000
2:
bnez a0,2b
addiu a0, -1
#endif
lbu v0, 0(v1)
andi v0, SMBUS_HOST_STATUS_BUSY
bnez v0, 1b #IDEL ?
nop
//li v1, 0xbfd00000 + SMBUS_HOST_STATUS
dli v1, BONITO_HTIO_BASE_VA + SMBUS_HOST_STATUS
dadd v1,v1,t3
lbu v0, 0(v1)
andi v0,v0, 0x1f
beqz v0,1f
nop
sb v0, 0(v1) #reset
lbu v0, 0(v1) #flush the write
1:
//li v1, 0xbfd00000 + SMBUS_HOST_DATA0
dli v1, BONITO_HTIO_BASE_VA + SMBUS_HOST_DATA0
dadd v1,v1,t3
lbu v0, 0(v1)
jr ra
nop
END(i2cread)
/* input: a0,a1,a2
a0: I2C device ID
a1: register offset in the device
a2: CHIP id (0,1,2,3)
output: not set
*/
LEAF(PROBE_DIMM)
move a3,ra;
move s2,a0; //store a0: i2C DEVICE id
move s3,a1; //store a1: REG offset in i2c dev
li a1, 2;
bal i2cread;
nop;
beq v0,SPD_NODEVICE, out;
nop;
/* set DDR type @ s1[7:7] */
/* assumed here v0 should be 0xc or 0x8 */
//bne v0,SPD_TYPEDDR3, ddr2
andi v0,0x4;
srl v0,0x2;
sll v0,DDRTYPE_MASK ;
or s1,v0;
/* set CONTROLLER_SELECT@ s1[3:2] */
/* a1 should set to be MC0_USED or MC1_USD */
/* Firt check whether BOTH MC0 and MC1 used, if
true,set s1[3:2] = 2b'00
*/
or s1,s3;
andi t1,s1,0xc;
bne t1,0xc,10f;
nop
subu s1,0xc
10:
/* set SIZE_PER_CONTROLLE @ s1[6:4] */
/* step 1: read out number of DIMMS Ranks(CS) */
move a0, s2; //store a1: REG offset in i2c dev
li a1, 5;
bal i2cread;
nop;
andi v0,0x3; // MASK for DIMMS Ranks(CS)
move t2,v0;
//bez t2,out
nop
addi t2,0x1
/* step 2: read out DIMMS size */
move a0,s2;
li a1, 31;
bal i2cread;
nop;
bne v0,SPD_DDR2SIZE_512M, 11f;
nop;
//ori s1,DDR2SIZE_512M_MASK;
li v0, 0x20000000
b 1f;
nop;
11:
bne v0,SPD_DDR2SIZE_1G, 12f;
nop;
//ori s1,DDR2SIZE_1G_MASK;
li v0, 0x40000000
b 1f;
nop;
12:
bne v0,SPD_DDR2SIZE_2G, 1f;
nop;
//ori s1,DDR2SIZE_2G_MASK; // v0: 0x80 means 1G
li v0, 0x80000000;
1:
/* step 3: calculate each mem SIZE of one slot*/
beq t2,0x1,21f;
nop
sll v0,0x1
//multu v0,t2;
21:
bne v0,0x20000000, 13f
nop;
/* check whther this channel is smaller than others
if smller: remove other bits,and set DDRPERSZ_512M
else: do nothing, don't set PERSIZE_BIT
// defalut setting 512M leaset MEM size
*/
andi t1,s1,DDR2SIZE_MASK;
beqz t1,211f;
nop
bleu t1,DDR2SIZE_512M_MASK, 15f;
nop
li t1,DDR2SIZE_MASK;
not t2,t1;
and s1,t2;
211:
ori s1,DDRPERSZ_512M ;
b 15f;
nop
13:
bne v0,0x40000000, 14f
nop
/* check whther this channel is smaller than others
if smller: remove other bits,and set DDRPERSZ_1G
else: do nothing, don't set PERSIZE_BIT
*/
andi t1,s1,DDR2SIZE_MASK;
beqz t1,131f;
nop
bleu t1, DDR2SIZE_1G_MASK,15f
nop
li t1,DDR2SIZE_MASK;
not t2,t1;
and s1,t2;
131:
ori s1,DDRPERSZ_1G;
b 15f;
nop
14:/* only support 512M,1G,2G per DIMM now */
bne v0,0x80000000, 15f
nop
/* check whther this channel is smaller than others
if smller: remove other bits,and set DDRPERSZ_2G
else: do nothing, don't set PERSIZE_BIT
*/
andi t1,s1,DDR2SIZE_MASK;
beqz t1,141f;
nop
bleu t1, DDR2SIZE_2G_MASK,15f
nop
li t1,DDR2SIZE_MASK;
not t2,t1;
and s1,t2;
141:
ori s1,DDRPERSZ_2G;
15:
/* check whether MC0 or MC1 used to set CS_MAP */
bne s3, MC0_USED, 2f;
nop;
/* set DDR MC0_CS_MAP @s1[11:8] */
ori s1, 0x400 // at leaset one bit is selected
move a0,s2;
li a1, 5;
bal i2cread;
nop;
andi v0,0x1;
beq v0,0x0,16f;
nop;
ori s1,0x800;
16:
/* set DDR MC0_COL_SIZE @s1[18:16] */
move a0,s2;
li a1, 4;
bal i2cread;
nop;
li t0,14;
sub t0,v0;
sll t0,0x10;
or s1,t0;
/* set MC0_EIGHT_BANK @s1[19] */
move a0,s2;
li a1, 17;
bal i2cread;
nop;
andi v0,0x8;
srl v0,0x3;
sll v0,0x13; //MC0_EIGHT_BANK shift
or s1,v0;
/* set DDR MC0_ROW_SIZE @s1[22:20] */
move a0,s2;
li a1, 3;
bal i2cread;
nop;
li t0,15;
sub t0,v0;
sll t0,0x14;
or s1,t0;
/* set MC0_ECC bit @s1[32] */
move a0,s2;
li a1, 11;
bal i2cread;
li t0,0x2;
andi v0,0x2;
srl v0,0x1;
dsll v0,32;
//dli v0,0x100000000 // for test
or s1,v0;
/* set DIMM Type information @s1[33:33] */
move a0,s2;
li a1, 20;
bal i2cread;
nop;
andi v0,0x1; // only to check whether in Register Dual In_line memory module
dsll v0,33;
or s1,v0;
b out;
nop;
2: /* MC1_USED */
#if 1
/* set DDR MC1_CS_MAP @s1[15:12] ? */
ori s1, 0x4000 // at leaset one bit is selected
move a0,s2;
li a1, 5;
bal i2cread;
nop;
andi v0,0x1;
beq v0,0x0, 26f
nop
ori s1,0x8000
26:
/* set DDR MC1_COL_SIZE @s1[26:24] */
move a0,s2;
li a1, 4;
bal i2cread;
nop;
li t0,14;
sub t0,v0;
sll t0,0x18;
or s1,t0;
/* set MC1_EIGHT_BANK @s1[27] ? */
move a0,s2
li a1, 17;
bal i2cread;
nop;
andi v0,0x8;
srl v0,0x3;
sll v0,27; //MC0_EIGHT_BANK shift
or s1,v0;
/* set DDR MC1_ROW_SIZE @s1[30:28] */
move a0,s2;
li a1, 3;
bal i2cread;
nop;
li t0,15;
sub t0,v0;
sll t0,0x1c;
or s1,t0;
/* set MC1_ECC bit @s1[34] */
move a0,s2;
li a1, 11;
bal i2cread;
li t0,0x2;
andi v0,0x2;
srl v0,0x1;
dsll v0,34;
or s1,v0;
/* set DIMM Type information @s1[35:35] */
move a0,s2;
li a1, 20;
bal i2cread;
nop;
and v0,0x1;// only to check whether in Register Dual In_line memory module
dsll v0,35;
or s1,v0;
#endif
out:/* out of MC0_CS_MAP or MC1_CS_MAP */
//jr ra
jr a3
nop
END(PROBE_DIMM)
#endif