@ -74,7 +74,8 @@ END(i2cread)
# define SPD_NODEVICE 0xff
# define SPD_TYPEDDR2 0x8
# define SPD_TYPEDDR3 0xc
# define SPD_TYPEDDR3 0xb
# define SPD_NODIMM 0x0
# define DDRTYPE_MASK 0x7
# define DDRPERSZ_512M 0x10
@ -96,40 +97,87 @@ END(i2cread)
# define DDR2SIZE_2G_MASK 0x30
# define DDR2SIZE_MASK 0x70
/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Input: a0 , i2c device ID ; a1 , in MC0 or MC1 flags
* Output: v0 , equals orignal s1 , included all DIMM info
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /
LEAF ( PROBE_DIMM )
move a2 , ra ;
move s2 , a0 ; / / store a0 : i2C DEVICE id
move s3 , a1 ; / / store a1 : REG offset in i2c dev
move s2 , a0 ; / / store a0 : i2C DEVICE id , s2 can be only used before mszie set
move s3 , a1 ; / / store a1 : MC0 or MC1 used flags
li a1 , 2 ;
bal i2cread ;
nop ;
beq v0 , SPD_NODEVICE , out ;
beq v0 , SPD_TYPEDDR3 , 4 f ;
nop ;
beq v0 , SPD_TYPEDDR2 , 4 f ;
nop ;
/ * set DIMM type @ s1 [ 7 : 7 ] * /
/ * assumed here v0 should be 0xc or 0x8 * /
xor v0 , v0
jr a2
nop
4 :
li s1 , 0x0
/ * set DDR type @ s1 [ 7 : 7 ] * /
/ * assumed here v0 should be 0xb or 0x8 * /
/ / bne v0 , SPD_TYPEDDR3 , ddr2
andi v0 , 0x4 ;
srl v0 , 0x2 ;
move t1 , v0
subu t1 , 0x8
beqz t1 , 400 f
nop
li v0 , 0x1
b 500 f
nop
4 0 0 :
li v0 , 0x0
5 0 0 :
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 ] = 2 b ' 00
* /
or s1 , s3 ;
andi t1 , s3 , 0xc
or s1 , t1 ;
# if 0 / * left done in MERGE_CHANNEL * /
andi t1 , s1 , 0xc ;
bne t1 , 0xc , 10 f ;
nop
subu s1 , 0xc
# endif
1 0 :
/ * added for DDR3 check * /
/ / if not ddr3 , jump to 100 f
/ / else , directly set ddr3 size to be 2 G
li a0 , 0x80
and a0 , s1 , a0
beqz a0 , 100 f / / DDR2
nop
# if 1
ori s1 , DDRPERSZ_1G / / DDR3 , default size 2 G
b 15 f
nop
# else
/ / DDR3
move a0 , s2 ; / / store a1 : REG offset in i2c dev
li a1 , 4 ;
bal i2cread ;
nop ;
andi v0 , v0 , 0xf
addi v0 , v0 , 1
sll v0 , v0 , 4
nop
or s1 , s1 , v0
nop
b 15 f
nop
# endif
1 0 0 :
/ * 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
@ -177,6 +225,7 @@ LEAF(PROBE_DIMM)
bne v0 , 0x20000000 , 13 f
nop ;
# if 0
/ * 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
@ -193,6 +242,7 @@ LEAF(PROBE_DIMM)
and s1 , t2 ;
2 1 1 :
# endif / / let compare size outside
ori s1 , DDRPERSZ_512M ;
b 15 f ;
nop
@ -200,6 +250,7 @@ LEAF(PROBE_DIMM)
bne v0 , 0x40000000 , 14 f
nop
# if 0
/ * 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
@ -214,6 +265,7 @@ LEAF(PROBE_DIMM)
and s1 , t2 ;
1 3 1 :
# endif / / let compare size outside
ori s1 , DDRPERSZ_1G ;
b 15 f ;
nop
@ -222,6 +274,7 @@ LEAF(PROBE_DIMM)
bne v0 , 0x80000000 , 15 f
nop
# if 0
/ * 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
@ -236,15 +289,41 @@ LEAF(PROBE_DIMM)
and s1 , t2 ;
1 4 1 :
# endif / / let compare size outside
ori s1 , DDRPERSZ_2G ;
1 5 :
/ * check whether MC0 or MC1 used to set CS_MAP * /
/ / bne s3 , MC0_USED , 2 f ;
bne s3 , 0x4 , 2 f ;
move a0 , s3
andi a0 , 0xc
bne a0 , MC0_USED , 2 f ;
nop ;
/ * set DDR MC0_CS_MAP @ s1 [ 11 : 8 ] * /
ori s1 , 0x400 / / at leaset one bit is selected
/ / First , check whether MC0DIMM0 used
move a0 , s3
andi a0 , 0xf0
bne a0 , 0x30 , 160 f
nop
/ / MC0_DIMM0
ori s1 , 0x100 / / at leaset one bit is selected , CS_MAP [ 0 ]
move a0 , s2 ;
li a1 , 5 ;
bal i2cread ;
nop ;
andi v0 , 0x1 ;
beq v0 , 0x0 , 16 f ;
nop ;
ori s1 , 0x200 ; / / set CS_MAP [ 1 ] = 1 ' b1
b 16 f
nop
1 6 0 :
/ / MC0_DIMM1
ori s1 , 0x400 / / at leaset one bit is selected , CS_MAP [ 2 ]
move a0 , s2 ;
li a1 , 5 ;
bal i2cread ;
@ -255,7 +334,12 @@ LEAF(PROBE_DIMM)
ori s1 , 0x800 ;
1 6 :
/ * set DDR MC0_COL_SIZE @ s1 [ 18 : 16 ] * /
andi a0 , s1 , 0x80
bnez a0 , 1601 f
nop
/ * set DDR2 MC0_COL_SIZE @ s1 [ 18 : 16 ] * /
move a0 , s2 ;
li a1 , 4 ;
bal i2cread ;
@ -285,13 +369,108 @@ LEAF(PROBE_DIMM)
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 1602 f
nop
1 6 0 1 : / / DDR3
/ * set DDR3 MC0_COL_SIZE @ s1 [ 18 : 16 ] * /
move a0 , s2 ;
li a1 , 5 ;
bal i2cread ;
nop ;
andi v0 , 0x7
addi v0 , 0x9
li t0 , 14 ;
sub t0 , v0 ;
sll t0 , 0x10 ;
or s1 , t0 ;
/ * set MC0_EIGHT_BANK @ s1 [ 19 ] * /
li a0 , 0x80000
or s1 , a0 ; / / at leaset 8 banks
/ * set DDR MC0_ROW_SIZE @ s1 [ 22 : 20 ] * /
move a0 , s2 ;
li a1 , 5 ;
bal i2cread ;
nop ;
andi v0 , 0x38
srl v0 , 0x3
li t0 , 3 ;
sub t0 , v0 ;
sll t0 , 0x14 ;
or s1 , t0 ;
# if 0
/ * 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 ;
# endif
1 6 0 2 :
/ / / / / / / / / / / / / / / / / / /
b out ;
nop ;
2 : / * MC1_USED * /
# if 1
/ / First , check whether MC1DIMM0 used
move a0 , s3
andi a0 , 0xf0
bne a0 , 0x30 , 260 f
nop
/ * set DDR MC1_CS_MAP @ s1 [ 15 : 12 ] ? * /
/ / below check for MC1_DIMM0
ori s1 , 0x1000 / / at leaset one bit is selected , CS_MAP [ 0 ]
move a0 , s2 ;
li a1 , 5 ;
bal i2cread ;
nop ;
andi v0 , 0x1 ;
beq v0 , 0x0 , 26 f ;
nop ;
ori s1 , 0x2000 ; / / set CS_MAP [ 1 ] = 1 ' b1
b 26 f
nop
2 6 0 : / / MC1_DIMM1
ori s1 , 0x4000 / / at leaset one bit is selected
move a0 , s2 ;
li a1 , 5 ;
@ -303,6 +482,10 @@ LEAF(PROBE_DIMM)
ori s1 , 0x8000
2 6 :
andi a0 , s1 , 0x80
bnez a0 , 2601 f
nop
/ * set DDR MC1_COL_SIZE @ s1 [ 26 : 24 ] * /
move a0 , s2 ;
li a1 , 4 ;
@ -332,10 +515,352 @@ LEAF(PROBE_DIMM)
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 ;
b 2602 f
nop
2 6 0 1 :
/ * set DDR3 MC1_COL_SIZE @ s1 [ 26 : 24 ] * /
move a0 , s2 ;
li a1 , 5 ;
bal i2cread ;
nop ;
andi v0 , 0x7
addi v0 , 0x9
li t0 , 14 ;
sub t0 , v0 ;
sll t0 , 0x18 ;
or s1 , t0 ;
/ * set MC0_EIGHT_BANK @ s1 [ 19 ] * /
li a0 , 0x8000000
or s1 , a0 / / at leaset 8 banks
/ * set DDR MC0_ROW_SIZE @ s1 [ 30 : 28 ] * /
move a0 , s2 ;
li a1 , 5 ;
bal i2cread ;
nop ;
andi v0 , 0x38
srl v0 , 0x3
li t0 , 3 ;
sub t0 , v0 ;
sll t0 , 0x1c ;
or s1 , t0 ;
# if 0
/ * 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 ;
# endif
out: / * out of MC0_CS_MAP or MC1_CS_MAP * /
2 6 0 2 :
out: / * out of MC0_CS_MAP or MC1_CS_MAP * /
/ / jr ra
move v0 , s1
jr a2
nop
END ( PROBE_DIMM )
/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* input a0 : deteced info on DIMM bonded to CS [ 1 : 0 ], 0 means no dimm
* input a1 : deteced info on DIMM bonded to CS [ 3 : 2 ], 0 means no dimm
* output v0 : merged a0 / a1 together , 0 means no mem
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /
.global MERGE_DIMM
.ent MERGE_DIMM
.set noreorder
.set mips3
MERGE_DIMM:
/ * check whether CS [ 1 : 0 ] and CS [ 3 : 2 ] tied to DIMM * /
bne a0 , 0x0 , 10 f
nop
move v0 , a1 / * no DIMM on CS [ 1 : 0 ], return a1 * /
jr ra
1 0 :
bne a1 , 0x0 , 12 f
nop
move v0 , a0 / * no DIMM on CS [ 3 : 2 ], return a0 * /
jr ra
/ * both CS [ 3 : 2 ] and CS [ 1 : 0 ] conncted to DIMM * /
1 2 :
/ * check whther both DD2 or DD3 * /
andi t0 , a0 , 0x80
andi t1 , a1 , 0x80
bne t0 , t1 , err
nop
beq a2 , MC1_USED , 1 f
nop
# # # # # # # # # # # # # # first check MC0 # # # # # # # # # # #
/ * check whther both Register or Unbuffered * /
dli t2 , 0x200000000
and t0 , a0 , t2
and t1 , a1 , t2
bne t0 , t1 , err
nop
/ * check whther has same row * /
dli t2 , 0x700000
and t0 , a0 , t2
and t1 , a1 , t2
bne t0 , t1 , err
nop
/ * check whther has same bank * /
dli t2 , 0x80000
and t0 , a0 , t2
and t1 , a1 , t2
bne t0 , t1 , err
nop
/ * check whther has same col * /
dli t2 , 0x70000
and t0 , a0 , t2
and t1 , a1 , t2
bne t0 , t1 , err
nop
b 2 f
nop
1 :
# # # # # # # # # # # # # # now check MC1 # # # # # # # # # # #
/ * check whther both Register or Unbuffered * /
dli t2 , 0x800000000
and t0 , a0 , t2
and t1 , a1 , t2
bne t0 , t1 , err
nop
/ * check whther has same row * /
dli t2 , 0x70000000
and t0 , a0 , t2
and t1 , a1 , t2
bne t0 , t1 , err
nop
/ * check whther has same bank * /
dli t2 , 0x8000000
and t0 , a0 , t2
and t1 , a1 , t2
bne t0 , t1 , err
nop
/ * check whther has same col * /
dli t2 , 0x7000000
and t0 , a0 , t2
and t1 , a1 , t2
bne t0 , t1 , err
nop
2 : # # now merge mem size together of DIMM0 and DIMM1 on the same MC # #
/ * set v0 with a0 first * /
move v0 , a0
/ * merge CS_MAP together * /
/ / shift right 2 bits , NOTICE here assume cs [ 3 : 2 ] connected DIMMB
/ / andi t0 , a0 , 0xc00
/ / srl t0 , 0x2
/ / or v0 , t0
andi t0 , a1 , 0xc00
or v0 , t0
/ * merge MIMM mem size together * /
dli t3 , 0x1
andi t0 , a0 , 0x70 ;
srl t0 , 0x4
addi t0 , 0x1c
dsll t4 , t3 , t0 / * t4 : DIMM0 size * /
andi t1 , a1 , 0x70 ;
srl t1 , 0x4
addi t1 , 0x1c
dsll t5 , t3 , t1 / * t5 : DIMM1 size * /
daddu t6 , t4 , t5 / * total mem size of DIMM0 and DMME1 * /
li t7 , 0x1c / * 0x1 < < 0x1c = 256 M * /
dsrl t6 , t6 , t7
/ * now calculate out SIZE_PER_CONTROLER * /
li t4 , 0x0 / * t4 = log2 ( memsize / 256 M ) * /
4 :
dsrl t6 , 0x1
addu t4 , 0x1
bne t6 , 0x1 , 4 b
nop
/ / first clean orignal SIZE_PER_CONTROLLER
dli t5 , 0xffffffff8f
and v0 , t5
sll t4 , 0x4
or v0 , t4
jr ra
nop
err:
li v0 , 0x0 ;
jr ra
nop
.end MERGE_DIMM
/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* input a0 : deteced info on DIMM bonded to MC0 , 0 means no dimm
* input a1 : deteced info on DIMM bonded to MC1 , 0 means no dimm
* output v0 : availabe mem size from compare a0 / a1 , passed to L2XBAR
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /
LEAF ( CALCULATE_MEMSZ )
andi t0 , a0 , 0x70
andi t1 , a1 , 0x70
srl t0 , 0x4
srl t1 , 0x4
beq t0 , $0 , 1 f
nop
beq t1 , $0 , 2 f
nop
# # # # # # # # # # calculate and set memsz # # # # # # # # # # # # # # # # #
ble t0 , t1 , 3 f
nop
move t0 , t1
3 : / * t0 used to record smller size * /
li t1 , 0x1
addu t0 , 28 + 1 ; / * both MC0 and CM1 used * /
dsll t1 , t0
dsubu t1 , 0x1000000 / * remain 16 M according linux kernel * /
move v0 , t1
b 4 f
nop
1 : / / MC0 has no DIMM , only MC1 used
# # # # # # # # # # calculate and set memsz # # # # # # # # # # # # # # # # #
li t0 , 0x1
addu t1 , 28
dsll t0 , t1
dsubu t0 , 0x1000000 / * remain 16 M according linux kernel * /
move v0 , t0
b 4 f
nop
2 : / / MC1 has no DIMM , only MC0 used
# # # # # # # # # # calculate and set memsz # # # # # # # # # # # # # # # # #
li t1 , 0x1
addu t0 , 28
dsll t1 , t0
dsubu t1 , 0x1000000 / * remain 16 M according linux kernel * /
move v0 , t1
b 4 f
nop
4 :
jr ra
END ( CALCULATE_MEMSZ )
/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* input a0 : deteced info on MC0 , 0 means no mem
* input a1 : deteced info on MC1 , 0 means no mem
* output v0 : availabe mem size from compare a0 / a1 , passed to L2XBAR
* The case when MC0 and MC1 not the same DDR2 or DDR3 not concerned
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /
LEAF ( MERGE_CHANNEL )
# move v0 , a0
or v0 , a1 , a0
/ * check whter both MCO and MC1 used , set s1 [ 3 : 2 ] = 2 ' b00 * /
andi t0 , v0 , 0xc
bne t0 , 0xc , 3 f
nop
li t0 , 0xfffffff3 / * set s1 [ 3 : 2 ] = 2 ' b00 * /
and v0 , v0 , t0
3 :
andi t0 , a0 , 0x70
andi t1 , a1 , 0x70
beq t0 , $0 , 1 f
nop
beq t1 , $0 , 2 f
nop
# # # # # # # # # # calculate and merge channel memsz # # # # # # # # # # # # # # # # #
ble t0 , t1 , 5 f
nop
move t0 , t1
5 : / * t0 used to record smller size * /
li t2 , 0xffffff8f
and v0 , t2
or v0 , v0 , t0
b 4 f
nop
1 : / / MC0 has no DIMM , only MC1 used
# # # # # # # # # # calculate and set memsz # # # # # # # # # # # # # # # # #
li t2 , 0xffffff8f
and v0 , t2
or v0 , v0 , t1
b 4 f
nop
2 : / / MC1 has no DIMM , only MC0 used
# # # # # # # # # # calculate and set memsz # # # # # # # # # # # # # # # # #
li t2 , 0xffffff8f
and v0 , t2
or v0 , v0 , t0
b 4 f
nop
4 :
jr ra
nop
END ( MERGE_CHANNEL )