龙芯软件开发(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");


 


 


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