龙芯软件开发(15)-- 搬家前的准备

任何人在搬家前,都需要把新房子修建好,然后再经过装修才能住到新房子里,然而这里的启动程序也不例外,需要把自己的房子先修好,并且通过装修才会住进里面。当然,程序所需要的房子,不是普通的房子,而是内存空间。由于在ROM运行的速度都是比较慢,并且空间有限,不能随时更改ROM里的内容。同时为了下一阶段作好准备,就需要把ROM里的引导程序搬到内存里运行。但是SDRAM在加电后,并不能立即使用,需要进行初始化,设置好参数才能保存数据。比如设置内存的刷新时间,如果设置时间不对,SDRAM就不能保存数据,以前我就有设置不对的参数,导致拷贝到内存的数据很快就丢失了。

在龙芯电脑里,使用的内存是标准的笔记本内存,也就是叫做SO-DIMM内存。这种内存是工业上的标准,出货量都比较大,相对来说是比较便宜的。INTEL 公司为了电脑配件标准化,就定义了一套叫做内存检测标准。在那个标准里,就定义了内存初始化时使用方式,内存类型标识等等。由于内存的参数是不同的厂家不一样,不同的类型也不一样,不同的大小也是不一样,既然是这样的话,就让厂家在出厂前把所有内存的配置信息写到一个EEPROM里,让BIOS启动时再去读取参数,并且进行内存初始化。要读取EEPROM中的信息,就需要使用I2C总线来读取。I2C总线是由PHILIPS公司定义IC之间的相互通讯的协议,它是一种分主从的两线通讯协议,一条线表示时钟信号,一条线表示数据信号,不管数据是读取,还是写入,都是通过数据线来进行的。无论是读取,还是写入数据,都是由主方先发开始信号,然后发送从设备的地址,相应地址的从设备就要响应后面的命令,而不同地址的设备就不会响应后面的命令。为什么读取DIMM 内存上的EEPROM,就需要按I2C的协议进行通讯,才会读取内存的参数,并对内存进行初始化。下面这段程序,就是做这样的事情:

PRINTSTR("DIMM read\r\n")

/* only one memory slot, slave address is 1010000b */

li a1, 0x0
1:
li a0,0xa1
bal i2cread
nop

# save a1
move t1, a1

#print
move a0, v0
bal hexserial
nop

PRINTSTR("\r\n")

# restore a1
move a1,t1
addiu a1,a1,1

li v0, 0x20
bleu a1, v0, 1b
nop

li msize,0
# set some parameters for DDR333
# rank number and DDR type field will be filled later
# to check: fix TCAS?
li sdCfg, 0x341043df

li a0,0xa1

/* read DIMM memory type (must be DDRAM) */
#li a1,2
#bal i2cread
#nop
#bne v0,7,.nodimm
#nop
PRINTSTR("read memory type\r\n")

/* read DIMM number of rows */
li a0,0xa1
li a1,3
bal i2cread
nop
move a0, v0
subu v0, 12
move s1, v0

bgtu v0, 2,.nodimm
nop
PRINTSTR("read number of rows\r\n")

2: /* read DIMM number of cols */
li a0,0xa1
li a1,4
bal i2cread
nop

subu v0, 8
bgtu v0, 4,.nodimm
nop

move t1, s1

bne t1, 0, 10f
nop
bne v0, 2, 20f
nop
li v0, 0
b .ddrtype
nop
20: bne v0, 1, 21f
nop
li v0, 1
b .ddrtype
nop
21: bne v0, 0, 22f
nop
li v0, 2
b .ddrtype
nop
22: bne v0, 3, 33f
nop
li v0, 3
b .ddrtype
nop
10: bne t1, 1, 11f
nop
bne v0, 3, 20f
nop
li v0, 4
b .ddrtype
nop
20: bne v0, 2, 21f
nop
li v0, 5
b .ddrtype
nop
21: bne v0, 1, 22f
nop
li v0, 6
b .ddrtype
nop
22: bne v0, 4, 33f
nop
li v0, 7
b .ddrtype
nop
11: bne t1, 2, 33f
nop
bne v0, 4, 20f
nop
li v0, 8
b .ddrtype
nop
20: bne v0, 3, 21f
nop
li v0, 9
b .ddrtype
nop
21: bne v0, 2, 33f
nop
li v0, 10
b .ddrtype
nop
33: PRINTSTR("DDR type not supported!\r\n");
34: b 34b
nop

.ddrtype:
#bit 25:22 is DDR type field
sll v0, 22
and v0,0x03c00000
or sdCfg,v0

/* read DIMM memory size per side */
li a0,0xa1
li a1,31
bal i2cread
nop
beqz v0,.nodimm
nop
sll tmpsize,v0,22 # multiply by 4M
PRINTSTR("read memory size per side\r\n")

2: /* read DIMM number of blocks-per-ddrram */
li a1,17
bal i2cread
nop
beq v0,2,2f
nop
bne v0,4,.nodimm
nop
PRINTSTR("read blocks per ddrram\r\n")

2: /* read DIMM number of sides (banks) */
li a1,5
bal i2cread
nop
beq v0,1,2f
nop
bne v0,2,.nodimm
nop
sll tmpsize,1 # msize *= 2
or sdCfg, 0x1«27
PRINTSTR("read number of sides\r\n")

2: /* read DIMM width */
li a1,6
bal i2cread
nop
bleu v0,36,2f
nop
bgtu v0,72,.nodimm
nop
PRINTSTR("read width\r\n")

2: addu msize,tmpsize
b 2f
nop

.nodimm:
move dbg,a0
PRINTSTR ("\r\nNo DIMM in slot ")
move a0,dbg
bal hexserial
nop
PRINTSTR("\r\n")
move a0,dbg
#li msize,0x10000000
#li sdCfg,0x3d9043df #~133MHz
li msize,0x20000000
li sdCfg,0x3d5043df #~133MHz

2:
PRINTSTR("DIMM SIZE=")
move a0,msize
bal hexserial
nop
PRINTSTR("\r\n")

li t0, 0xbff00008
sd sdCfg, 0(t0)

#### gx 2006-03-17: mode ####
#li t1,0x20
li t1,0x28
li t0, 0xbff00000
sd t1,0(t0)
nop
li t1,0x0
li t0, 0xbff00000
sd t1,0x30(t0)
nop

#### setup high memory window ####
li t1, 0x10000000
blt msize, t1, 1f
nop

lui t1,0x2000
sd t1,0x20(t0)
nop
lui t1,0x1000
sd t1,0x28(t0)
nop

1:

PRINTSTR("sdcfg=");
move a0,sdCfg
bal hexserial
nop
PRINTSTR("\r\n");
PRINTSTR("msize=");
move a0,msize
bal hexserial
nop
PRINTSTR("\r\n")

skipdimm:

li t1,0 # accumulate pcimembasecfg settings

/* set bar0 mask and translation to point to SDRAM */
sub t0,msize,1
not t0
srl t0,BONITO_PCIMEMBASECFG_ASHIFT-BONITO_PCIMEMBASECFG_MEMBASE0_MASK_SHIFT
and t0,BONITO_PCIMEMBASECFG_MEMBASE0_MASK
or t1,t0

li t0,0x00000000
srl t0,BONITO_PCIMEMBASECFG_ASHIFT-BONITO_PCIMEMBASECFG_MEMBASE0_TRANS_SHIFT
and t0,BONITO_PCIMEMBASECFG_MEMBASE0_TRANS
or t1,t0
or t1,BONITO_PCIMEMBASECFG_MEMBASE0_CACHED

/* set bar1 to minimum size to conserve PCI space */
li t0, ~0
srl t0,BONITO_PCIMEMBASECFG_ASHIFT-BONITO_PCIMEMBASECFG_MEMBASE1_MASK_SHIFT
and t0,BONITO_PCIMEMBASECFG_MEMBASE1_MASK
or t1,t0

li t0,0x00000000
srl t0,BONITO_PCIMEMBASECFG_ASHIFT-BONITO_PCIMEMBASECFG_MEMBASE1_TRANS_SHIFT
and t0,BONITO_PCIMEMBASECFG_MEMBASE1_TRANS
or t1,t0
or t1,BONITO_PCIMEMBASECFG_MEMBASE1_CACHED

sw t1,BONITO_PCIMEMBASECFG(bonito)

/* enable configuration cycles now */
lw t0,BONITO_BONPONCFG(bonito)
and t0,~BONITO_BONPONCFG_CONFIG_DIS
sw t0,BONITO_BONPONCFG(bonito)

/* 蔡军生 2007-1-1 于深圳 */

PRINTSTR("Init SDRAM Done!\r\n");

下一次再来仔细地分析这段程序是怎么样实现的。

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License