单龙芯3A3000-7A1000PMON研究学习-(28)撸起袖子干-再来一杯代码10-内存初始化1

 1.上篇的一个尾巴,不解释了

8:
    TTYDBG("LS3A-7A linkup.")    //HT链接建立
//setup LS3A - 7A HT link done.

    bal  beep_off
    nop

2.正式开始,继续读代码

    TTYDBG("\r\nStart Init Memory, wait a while......\r\n")         //内存控制器初始化
####################################
    move    msize, $0
    move    s3, $0
//!!!!important--s1 must be correctly set

    TTYDBG("NODE 0 MEMORY CONFIG BEGIN\r\n")

重点来了,要开始初始化内存了,难,我估计我看不很懂。

两个寄存器赋初值0.    msize 是s2

2.1 看一眼原理图,内存相关的部分。

 

 原理图太多,MC0和MC1 都连接了这样的内存芯片,每个控制器连接8片,共16片

 

暂时没有找到相关pdf,从百度上看,8Gbits(1GB),16位宽,ddr3类型。

每个通道是8GB ,总共内存大小16GB

3.继续读代码

    //set MC1 dimm infor
    dli     a0, ( MC_SDRAM_TYPE_DDR3    /* sdram type: DDR3/DDR2 */ \
                | MC_DIMM_ECC_NO        /* dimm ECC: YES/NO */ \
                | MC_DIMM_BUF_REG_NO    /* dimm buffer register: YES/NO, for RDIMM use YES, all else use NO*/ \
                | MC_DIMM_WIDTH_64      /* memory data width: 64/32 */ \
                | MC_SDRAM_ROW_16       /* sdram row address number: 15~11 */ \
                | MC_SDRAM_COL_10       /* sdram column address number: 12~9 */ \
                | MC_SDRAM_BANK_8       /* sdram bank number: 8/4 */ \
                | MC_ADDR_MIRROR_NO    /* for standard DDR3 UDIMM, use YES else use NO */ \
                | MC_SDRAM_WIDTH_X16    /* SDRAM device data width: 8/16 */ \
                | MC_USE_CS_0_1         /* the CS pins the sdram connected on(split by '_', from small to big) */ \
                | MC_MEMSIZE_(16)        /* MC memory size, unit: 512MB */ \
                )
    dsll    s1, a0, 32
    //set MC0 dimm infor
    dli     a0, ( MC_SDRAM_TYPE_DDR3    /* sdram type: DDR3/DDR2 */ \
                | MC_DIMM_ECC_NO        /* dimm ECC: YES/NO */ \
                | MC_DIMM_BUF_REG_NO    /* dimm buffer register: YES/NO, for RDIMM use YES, all else use NO*/ \
                | MC_DIMM_WIDTH_64      /* memory data width: 64/32 */ \
                | MC_SDRAM_ROW_16       /* sdram row address number: 15~11 */ \
                | MC_SDRAM_COL_10       /* sdram column address number: 12~9 */ \
                | MC_SDRAM_BANK_8       /* sdram bank number: 8/4 */ \
                | MC_ADDR_MIRROR_NO    /* for standard DDR3 UDIMM, use YES, else use NO */ \
                | MC_SDRAM_WIDTH_X16    /* SDRAM device data width: 8/16 */ \
                | MC_USE_CS_0_1         /* the CS pins the sdram connected on(split by '_', from small to big) */ \
                | MC_MEMSIZE_(16)        /* MC memory size, unit: 512MB 512*16共8G */ \
                )
    or      s1, s1, a0      //内存初始化参数,高32位,低32位一样
    //set used MC and NODE ID
    or      s1, s1, USE_MC_0_1          /* used memory controller: _0/_1/_0_1 */
    or      s1, s1, MC_NODE_ID_0        /* node ID: 0/1/2/3 */

准备参数。MC0和MC1两个控制器都有设置。设置的内容基本相同。

主要保存在s1寄存器中了。

4. 继续,又来了一个包含语句

#include "ddr_dir/loongson3A2000_ddr2_config.S"

4.1 这时候,程序要运行到这个文件的代码了。

/**********************************
    loongson3A2000_ddr2_config.S
        used to set up ddr controllers MC0 and MC1  //用于设置DDR控制器MC0,MC1
        and set up the memory space on L2 Xbar      //设置L2XBAR
    input: s1--MC1 & MC0 DIMM info and Node ID      //输入参数
    note: s1 is damaged by the end of this file     //注意,s1被损坏,在这个文件结束的时候
    original: whd
    rewrite by Chen Xinke on 11/11/2010
    1: reorder the program
    2: DIMM info and memory size is set according to s1[MC1&0_MEMSIZE]
    note: config L2 Xbar still need to be finished,currently only support limited MEMSIZE.
    v1.0    raw
    v1.2    add support for 4G memsize per MC, modify the L2-Xbar config manner of MC1
            to reduce code size.
    v1.4    Modify L2 Xbar config reg code at Interleave mode to reduce code size
            new code:
            1. according to Memsize config open space
            2. config interleave bits
    v1.6    Modify L2 Xbar address window configuration to new pmon-kernel interface.
            (default use NO_INTERLEAVE)
    v1.8    Modify supported Interleave bit. Add Interleave support when each MC uses 1GB or 2GB.
    v2.0    Add support for 8GB per MC.
    v2.1    support for interleave using the X2 interleave function for 3A2000
************************************/
 

来点注释看一下。。。

4.2 检查需要初始化的控制器

//make sure s1[3:2] is correctly set.          //开始执行
    GET_MC_SEL_BITS             //[3:2] 表示MC1,MC0 0表示两个控制器都有效
    dli     a2, 3
    bne     a1, a2, 1f         //不等于3,则跳转
    nop
//s1[3:2]=0b'11, clear to 0b'00
    dli     a2, 0xc
    not     a2, a2
    and     s1, s1, a2         //等于3,则清零[3:2]位
1:

我们的代码实际是0,表示两个控制器都要设置。

4.3 还有一段注释,还是可以留意以下

/**************************
1. 1. check NODE memory size.   //检查内存大小
*  2. set MC0/1_ONLY if the following 2 conditions are satisfied:  //如果以下两个条件满足,设置MC0/1_ONLY
*     (1). s1[3:2]=0b'00
*     (2). MC0 or MC1 MEMSIZE > 0.
* when use AUTO_DDR_CONFIG, one MC may have no DIMM while the other has, in this case,
* the code should set MC0_ONLY or MC1_ONLY in s1 automatically, because the code of 
* configuring L2-Xbar will use this message.
**************************/

4.4 检查内存大小

    GET_MC0_ONLY
    bnez    a1, 1f   //不等于0跳转,实际等于0
    nop
    GET_MC1_ONLY
    bnez    a1, 2f   //不等于0跳转,实际等于0
    nop
//s1[3:2]=0b'00
    //check memory size in this case
    GET_MC0_MEMSIZE   //获得控制器0的内存大小 8G ,得16
    move    t5, a1
    GET_MC1_MEMSIZE   //获得控制器0的内存大小 8G ,得16
    daddu   a1, a1, t5   //a1= 32,共16G
    beqz    a1, 89f    //等于0跳转,实际不跳转
    nop
    dli     t5, 0x20     
    bgt     a1, t5, 89f  //大于32跳转89,实际不大于
    nop
    GET_MC0_MEMSIZE    //得16,a1=16
    bnez    a1, 3f     //不等于0,跳转
    nop
    //MC0_MEMSIZE=0, MC1_MEMSIZE must !=0, set MC1_ONLY ,被跳过
    dli     t5, 0x8
    or      s1, t5     //[3] = 1
    b       4f
    nop
3:  //MC0_MEMSIZE!=0
    GET_MC1_MEMSIZE   //得16,a1=16
    bnez    a1, 4f    //不等于0,跳转
    nop
    //MC1_MEMSIZE=0 set use MC0_ONLY
    dli     t5, 0x4
    or      s1, t5
    b       4f
    nop
1:  //MC0_ONLY
    GET_MC0_MEMSIZE
    b       5f
    nop
2:  //MC1_ONLY
    GET_MC1_MEMSIZE
5:
    beqz    a1, 89f
    nop
    dli     t5, 0x10
    bgt     a1, t5, 89f
    nop
4:                           //继续执行

有几个标号是宏定义,暂不贴出来。正常时跳转到标号4继续执行。

4.5 设置控制器啦

/************************
2. set up Memory Controller.
************************/
/***********************
for single chip or multi-chip:    //用于单芯片或者多芯片
t0: X-bar config base             //xbar配置基地址
t2: chip configuration register location   //芯片的配置寄存器地址
t0,t2 shouldn't be changed to the end of this file.   //这个文件结束时,t0
**********************/

4.6 设置控制器代码部分

    GET_NODE_ID_a0    //ddr_config_define.h 215行,得到node的值,当前为0,存在第44位。
    dli     t2, 0x900000001fe00180
    dli     t0, 0x900000003ff00000
    or      t2, t2, a0
    or      t0, t0, a0      //因为NODE是0,还是和原来的值一样

#if 1 // AdonWang disable cpu buffered read
/* !!!!!!!!!!!!! IMPORTANT !!!!!!!!!!!! */
    PRINTSTR("Disable cpu buffered read\r\n")    //打印
    lw      a1, 0x0(t2)
    li      a0, 0xfffffdff
    and     a1, a1, a0     //清零位[9]    user1.pdf 29/170页,允许MC1 DDR配置空间
    sw      a1, 0x0(t2)    
#endif

看到配置寄存器,是禁止MC1的配置空间被清零,那就是允许配置。 

 4.7 继续

#if 1 // AdonWang disable ddr3 readbuff
/*      May Affect the Performance     */
//This seems better for the spec2000
//if we enable ECC, this bit will be reset
    PRINTSTR("Disable read buffer\r\n")
    lw      a1, 0x4(t2)
    li      a0, 0x18
    or      a1, a1, a0
    sw      a1, 0x4(t2)   //[39:32] 是保留位???
#endif

上图是0x180寄存器,从bit32开始是0x184的寄存器,但是文档中没有相关说明。 

4.8 继续 ,看注释是要配置MC0了

//init MC1 will damage MC0 s1 info   //初始化MC1,将损坏s1寄存器中MC0的部分的信息
//config MC0 if not define MC1_ONLY  //配置MC0,如果没有定义MC1_ONLY
//-------------------------------------

4.9 继续看代码

10:
    GET_MC1_ONLY
    bnez    a1, 11f    //等于0,不跳转
    nop

    dli     t3, 0x0    //t3=0  , mc_init函数中用到。
#ifndef  DISABLE_DIMM_ECC   //宏被定义,代码不执行
    //Enable MC read buffer for ECC Initial
    GET_DIMM_ECC         //dimm ECC: NO  == 0
    beqz    a1, 8f       //等于0,跳转
    nop
    TTYDBG("Enable MC read buffer\r\n")
    lw      a1, 0x4(t2)
    li      a0, 0x8
    sll     a0, a0, t3
    not     a0, a0
    and     a1, a1, a0
    sw      a1, 0x4(t2)
    sync
8:
#endif

通过搜索,start.S中有这个宏定义。 

这段代码中a1不等于0,不跳转,之后 t3 = 0;

 4.10 继续看代码

	//start.S 1779行,包含ddr_dir/ls3A8_ddr_config.S,其中有mc_init
    bal     mc_init    //
    nop

跳转到一个函数执行。这个函数在ls3A8_ddr_config.S中,这个文件没有被显式编译,但是在start.S中被包含进来。(这种方式真的不太好阅读代码)

 这个部分我觉得要先放一下,这里程序比较长,里面还有很多的函数跳转。先认为是一个MC的初始化吧。

这里两个参数,一个t7,为0,表示不自动训练参数,一个是t3 , 0--MC0; 1--MC1,这一次t3=0.

 

4.11 继续,这次初始化MC1

    PRINTSTR("\r\nMC0 Config DONE\r\n")
//-------------------------------------
//config MC1 if not define MC0_ONLY
11:
    GET_MC0_ONLY
    bnez    a1, 12f
    nop

    dli     t3, 0x1

    //shift MC1 DIMM info to low 32bit of s1
    dsrl    t5, s1, 32
    dli     a1, 0xffff8000
    and     t5, t5, a1
    dli     a1, 0xffffffff8000ffff
    and     s1, s1, a1
    or      s1, s1, t5

a1肯定不是0,不跳转,

t3 = 1 ,一会函数调用的参数。

s1右移32位后把值赋给t5

t5的值与操作0xffff,8000,剩下高17位。0-14被清零。

s1与操作0xffff,ffff,8000,ffff 在这MC0的配置信息被破坏了。MC0的信息只剩下高[31]位,和低[15:0]这17位有效了。

t5的值与s1的值或操作。

s1低32位中包含了一些MC1的信息。高32位不变

s1 的值原来是 3<<30|0<<29|0<<28|0<<27|0<<24|2<<20|1<<23|0<<22|1<<25|3<<16|16<<8

高32位与低32位相同。

其中[3:2] = 0,表示使用MC1和MC0

[0] = 0     表示NODE_ID = 0;

经过以上与或操作后。主要考虑的是MC1和MC0两个内存的大小一致。都是8G

S1 =  3<<30|0<<29|0<<28|0<<27|0<<24|2<<20|1<<23|0<<22|1<<25|3<<16|16<<8

4.12 参数准备好之后,就开始初始化这个控制器了。

    bal     mc_init
    nop

后面再分析吧。

4.13 初始化之后,配置xbar

    TTYDBG("\r\nMC1 Config DONE\r\n")
//-------------------------------------
12:
/*******************************
 3. config L2 X-bar
    code procedure: first, MC*_ONLY bits in s1 decides whether this MC is
    used,then according to MC*_MEMSIZE bits in s1 decide memory size and how
    the L2 X-bar windows will be configured.
    note: currently,when use only 1 MC,support memory size: 512M, 1G, 2G, 3G, 4G;
      when use MC0&MC1 both, only support 1G, 2G or 4G Memory size of each Controller.
*******************************/

    sync
    nop
    nop
    nop
    nop

    //disable default pci window
    L2XBAR_DISABLE_WINDOW(0x100);

注意一下注释。

宏定义展开:

#define L2XBAR_DISABLE_WINDOW(OFFSET) \
                        daddiu  v0, t0, OFFSET;       \
                        sd      $0, 0x80(v0);

t0 = 0x3ff0,0000,,访问的地址是0x3ff0,0180,PCI的基址设置为0.

4.14 继续看代码,设置xbar

    GET_MC_SEL_BITS
    beqz    a1, 1f    //a1等于0,跳转
    nop
1:
#ifndef NO_INTERLEAVE   //没定义,要执行
//interleave first, if MC1 memsize != MC0 memsize, do NO_interleave
    GET_MC0_MEMSIZE
    move    t5, a1        //a1= 16  (8G)
    GET_MC1_MEMSIZE
    bne     t5, a1, 1f     // 相等,不跳转
    nop
3:
    GET_NODE_ID_a0;       //a0 = 0 node_id
    XBAR_CONFIG_NODE_a0(0x10, \
                    0x0000000000000000, \
                    0xFFFFFFFFF0000000, \
                    0x00000000000000F0 | (MC_INTERLEAVE_OFFSET << 56))

    PRINTSTR("DDR Interleave space open : 0x00000000 - 0x0FFFFFFF\r\n")    //被打印
    b       2f
    nop
#endif

2:
    //Config PCI windows
    L2XBAR_CONFIG_PCI_AS_CPU(0x10);
    L2XBAR_CONFIG_PCI_BASE_0to8(0x110);
#ifndef NO_INTERLEAVE
    L2XBAR_CONFIG_PCI_AS_CPU(0x18);
    L2XBAR_CONFIG_PCI_BASE_0to8(0x118);
#endif
    PRINTSTR("PCI space open: 0x80000000 - 0x8FFFFFFF\r\n")

4.14.1 展开宏定义XBAR_CONFIG_NODE_a0

#define XBAR_CONFIG_NODE_a0(OFFSET, BASE, MASK, MMAP) \
                        daddiu  v0, t0, OFFSET;       \
                        dli     v1, BASE;             \
                        or      v1, v1, a0;           \
                        sd      v1, 0x00(v0);         \
                        dli     v1, MASK;             \
                        sd      v1, 0x40(v0);         \
                        dli     v1, MMAP;             \
                        sd      v1, 0x80(v0);

v0 = t0 + offset(0x10) = 0x900000003ff00010

v1 = 0,或上a0(0) 还是0

把v1(0) 写入 0x3ff0,0010 

v1 = 0xffff,ffff,f000,000

把v1(0xffff,ffff,f000,000) 写入 0x3ff0,0050 

v1 = 0x14000000000000F0

把v1(0x14000000000000F0) 写入 0x3ff0,0090 

 这里设置的是cpu_win2

 base = 0;

mask= 0xffff,ffff,f000,000

mmap = 0x1400,0000,0000,00F0

mmap的低8位,低4位为0,指向DDR0,高4位为f,表示允许读和取指,并且使能映射。

 高位[63:48]  = 0x1400,转换后的仍然地址是0

 映射的区域0-0xfff,ffff。 映射out_addr 范围: 0x1400,0000,0000,0000~0x1400,0000,0fff,ffff

 

 

4.14.2 展开宏定义L2XBAR_CONFIG_PCI_AS_CPU

#define L2XBAR_CONFIG_PCI_AS_CPU(OFFSET) \
                        daddiu  v0, t0, OFFSET;       \
                        ld      v1, 0x0(v0);          \
                        sd      v1, 0x100(v0);        \
                        ld      v1, 0x40(v0);         \
                        sd      v1, 0x140(v0);        \
                        ld      v1, 0x80(v0);         \
                        sd      v1, 0x180(v0);

v0 = t0 + offset(0x10) = 0x900000003ff00010

v1 = 0x900000003ff00010寄存器的内容,

把v1 写入 0x3ff0,0110 

v1 = 0x900000003ff00050寄存器的内容,

把v1写入 0x3ff0,0150 

v1 = 0x900000003ff00090寄存器的内容

把v1写入 0x3ff0,0190 

 PCI win2的内容与CPUwin2的内容相同。

4.14.3 展开宏定义L2XBAR_CONFIG_PCI_BASE_0to8

#define L2XBAR_CONFIG_PCI_BASE_0to8(OFFSET) \
                        daddiu  v0, t0, OFFSET;       \
                        ld      v1, 0x0(v0);          \
                        dli     a1, 0x80000000;       \
                        or      v1, v1, a1;           \
                        sd      v1, 0x0(v0);

v0 = t0 + offset(0x110) = 0x900000003ff00110

v1 =  0x900000003ff00110寄存器的内容。这个值是0

v1 或a1   = 0x8000,0000

PCI win2 base =  0x8000,0000

4.14.4 展开宏定义L2XBAR_CONFIG_PCI_AS_CPU

#define L2XBAR_CONFIG_PCI_AS_CPU(OFFSET) \
                        daddiu  v0, t0, OFFSET;       \
                        ld      v1, 0x0(v0);          \
                        sd      v1, 0x100(v0);        \
                        ld      v1, 0x40(v0);         \
                        sd      v1, 0x140(v0);        \
                        ld      v1, 0x80(v0);         \
                        sd      v1, 0x180(v0);

v0 = t0 + offset(0x18) = 0x900000003ff00018

读寄存器的内容到v1

 

 这次是把CPUwin3的值,复制一份到PCI_WIN3的寄存器中。

4.14.5 展开宏定义L2XBAR_CONFIG_PCI_BASE_0to8

#define L2XBAR_CONFIG_PCI_BASE_0to8(OFFSET) \
                        daddiu  v0, t0, OFFSET;       \
                        ld      v1, 0x0(v0);          \
                        dli     a1, 0x80000000;       \
                        or      v1, v1, a1;           \
                        sd      v1, 0x0(v0);

v0 = t0 + offset(0x118) = 0x900000003ff00118

v1 =  0x900000003ff00118寄存器的内容。这个值是0

v1 或a1   = 0x8000,0000

PCI win3 base =  0x8000,0000

明天继续吧。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大智兄

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值