Lioker

 

一、u-boot.lds

 1 OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
 2 OUTPUT_ARCH(arm)
 3 ENTRY(_start)
 4 SECTIONS
 5 {
 6  . = 0x00000000;
 7  . = ALIGN(4);
 8  .text :
 9  {
10   *(.__image_copy_start)
11   *(.vectors)
12   arch/arm/cpu/armv7/start.o (.text*)
13   *(.text*)
14  }
15  . = ALIGN(4);
16  .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
17  . = ALIGN(4);
18  .data : {
19   *(.data*)
20  }
21  . = ALIGN(4);
22  . = .;
23  . = ALIGN(4);
24  .u_boot_list : {
25   KEEP(*(SORT(.u_boot_list*)));
26  }
27  . = ALIGN(4);
28  .image_copy_end :
29  {
30   *(.__image_copy_end)
31  }
32  .rel_dyn_start :
33  {
34   *(.__rel_dyn_start)
35  }
36  .rel.dyn : {
37   *(.rel*)
38  }
39  .rel_dyn_end :
40  {
41   *(.__rel_dyn_end)
42  }
43  .end :
44  {
45   *(.__end)
46  }
47  _image_binary_end = .;
48  . = ALIGN(4096);
49  .mmutable : {
50   *(.mmutable)
51  }
52  .bss_start __rel_dyn_start (OVERLAY) : {
53   KEEP(*(.__bss_start));
54   __bss_base = .;
55  }
56  .bss __bss_base (OVERLAY) : {
57   *(.bss*)
58    . = ALIGN(4);
59    __bss_limit = .;
60  }
61  .bss_end __bss_limit (OVERLAY) : {
62   KEEP(*(.__bss_end));
63  }
64  .dynsym _image_binary_end : { *(.dynsym) }
65  .dynbss : { *(.dynbss) }
66  .dynstr : { *(.dynstr*) }
67  .dynamic : { *(.dynamic*) }
68  .plt : { *(.plt*) }
69  .interp : { *(.interp*) }
70  .gnu.hash : { *(.gnu.hash) }
71  .gnu : { *(.gnu*) }
72  .ARM.exidx : { *(.ARM.exidx*) }
73  .gnu.linkonce.armexidx : { *(.gnu.linkonce.armexidx.*) }
74 }
View Code

 

其中,

变量_start定义在文件arch/arm/lib/vectors.S中,为0x87800000,此文件被用来定义中断向量表,其中还包含有变量.vectors和ax

通过链接文件可以确定vectors.S在start.S之前运行

 

变量__image_copy_start在System.map和u-boot.map中均有定义,此处以u-boot.map为例:

其他变量也可以在System.map和u-boot.map中找到定义

而且我们可以通过u-boot.map中函数所属的文件夹确定其粗略位置,如后面章节需要用到的_main()函数就定义在arch/arm/lib/文件夹内

 

 

接下来我将分析start.S,因其内容较多,因此以功能分节

二、进入Supervisor模式,屏蔽IRQ和FIQ

1 b reset                                vectors.S
2   -> b save_boot_params                start.S
3     -> ENTRY(save_boot_params)         start.S
4       -> b save_boot_params_ret        start.S

其中,save_boot_params_ret()函数定义如下:

1 mrs    r0, cpsr               @ 将cpsr寄存器值存储至r0寄存器中
2 and    r1, r0, #0x1f          @ 将r0寄存器值的低5位存储至r1寄存器中
3 teq    r1, #0x1a              @ 判断r1寄存器值是否等于0x1a(0b11010,Hyp模式)
4 bicne  r0, r0, #0x1f          @ 如果不相等,则将r0寄存器值的低5位置0
5 orrne  r0, r0, #0x13          @ 并且与0x13(0b10011,Supervisor模式)进行或运算
6 orr    r0, r0, #0xc0          @ 将r0寄存器值的bit[7:6]置0
7 msr    cpsr,r0

 

cpsr的格式在《ARMv7架构参考手册》中B1.3.3一节

 

其低五位为M[4:0]定义在B1.3.1一节

 

bit[7]为IRQ屏蔽位,bit[6]为FIQ屏蔽位

 

 

三、向量表重定位

/* Set V=0 in CP15 SCTLR register - for VBAR to point to vector */
/* CP15寄存器在《ARMv7架构参考手册》的Table B3-33中有定义,如下图所示 */
/* 参考《ARMv7架构参考手册》的B4.1.130一节 */
mrc    p15, 0, r0, c1, c0, 0    @ 将CP15协处理器c1中SCTLR值存储至r0寄存器中
/* Source Insight提示arch/arm/include/asm/system.h中有其定义:#define CR_V (1 << 13)*/
bic    r0, #CR_V                @ 设置向量表地址为0,让向量表可以重定位
mcr    p15, 0, r0, c1, c0, 0    @ Write CP15 SCTLR Register

/* Set vector address in CP15 VBAR register */
ldr    r0, =_start              @ _start = 0x87800000
/* 参考《ARMv7架构参考手册》的B4.1.156一节 */
mcr    p15, 0, r0, c12, c0, 0   @ Set VBAR,设置向量表基地址

 

在上图中,读者可能会注意到的PL1 or higher

这个是ARM所划分的特权等级,在ARM v7-A架构中有PL0、PL1和PL2三种等级,PL0包含User,PL2包含Hyp,PL1包含其他模式,如下图所示:

 

 

四、设置CP15协处理器

bl cpu_init_cp15
  -> ENTRY(cpu_init_cp15)
 1 /* 参考《ARMv7架构参考手册》的Table B3-38 */
 2 mov    r0, #0                   @ set up for MCR
 3 mcr    p15, 0, r0, c8, c7, 0    @ invalidate TLBs,B4.2.3 PL2或Monitor Mode
 4 mcr    p15, 0, r0, c7, c5, 0    @ invalidate icache,B4.2.1 PL1 or higher
 5 mcr    p15, 0, r0, c7, c5, 6    @ invalidate branch predictors array,Table D14-3
 6 mcr    p15, 0, r0, c7, c10, 4   @ DSB
 7 mcr    p15, 0, r0, c7, c5, 4    @ ISB
 8 
 9 /*
10  * disable MMU stuff and caches
11  */
12 mrc    p15, 0, r0, c1, c0, 0
13 bic    r0, r0, #0x00002000      @ clear bits 13 (--V-)
14 bic    r0, r0, #0x00000007      @ clear bits 2:0 (-CAM)
15 orr    r0, r0, #0x00000002      @ set bit 1 (--A-) Align
16 orr    r0, r0, #0x00000800      @ set bit 11 (Z---) BTB
17 orr    r0, r0, #0x00001000      @ set bit 12 (I) I-cache
18 mcr    p15, 0, r0, c1, c0, 0
19 
20 mov    r5, lr                   @ Store my Caller
21 mrc    p15, 0, r1, c0, c0, 0    @ r1 has Read Main ID Register (MIDR)
22 mov    r3, r1, lsr #20          @ get variant field
23 and    r3, r3, #0xf             @ r3 has CPU variant
24 and    r4, r1, #0xf             @ r4 has CPU revision
25 mov    r2, r3, lsl #4           @ shift variant field for combined value
26 orr    r2, r4, r2               @ r2 has combined CPU variant + revision
27 
28 mov    pc, r5                   @ back to my caller
View Code

 

 

五、设置栈顶指针sp

bl cpu_init_crit                    start.S
  -> ENTRY(cpu_init_crit)
    -> b lowlevel_init
      -> ENTRY(lowlevel_init)       arch/arm/cpu/armv7/lowlevel_init.S
        -> ldr sp, =CONFIG_SYS_INIT_SP_ADDR
        -> bl s_init                /* 空函数 */

 

使用内部RAM设置栈顶

 1 ldr    sp, =CONFIG_SYS_INIT_SP_ADDR
 2 /* 8bit对齐 */
 3 bic    sp, sp, #7

 

CONFIG_SYS_INIT_SP_ADDR值确定过程如下:

ldr sp, =CONFIG_SYS_INIT_SP_ADDR
  -> #define CONFIG_SYS_INIT_SP_ADDR \                        include/configs/mx6ull_lioker.h
  ->   (CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_INIT_SP_OFFSET)
    -> #define CONFIG_SYS_INIT_RAM_ADDR    IRAM_BASE_ADDR
    -> #define CONFIG_SYS_INIT_SP_OFFSET \
    ->   (CONFIG_SYS_INIT_RAM_SIZE - GENERATED_GBL_DATA_SIZE)
    -> #define CONFIG_SYS_INIT_RAM_SIZE    IRAM_SIZE

也就是CONFIG_SYS_INIT_SP_ADDR = IRAM_BASE_ADDR + IRAM_SIZE - GENERATED_GBL_DATA_SIZE

 

IRAM_BASE_ADDR和IRAM_SIZE根据mx6ull_lioker.h头文件和如下的grep命令确定定义在arch/arm/include/asm/arch/imx-regs.h中

$ grep "IRAM_BASE_ADDR" * -nR

arch/arm/include/asm/arch/为arch/arm/include/asm/arch-mx6/的链接文件

 

GENERATED_GBL_DATA_SIZE根据如下的grep命令确定定义在include/generated/generic-asm-offsets.h中,grep命令如下:


 

上述变量定义如下:

 1 #define IRAM_BASE_ADDR              0x00900000
 2 
 3 /* CONFIG_MX6UL在.config中定义,因此IRAM_SIZE = 0x00040000 */
 4 #if !(defined(CONFIG_MX6SX) || defined(CONFIG_MX6UL) || \
 5     defined(CONFIG_MX6SLL) || defined(CONFIG_MX6SL))
 6 #define IRAM_SIZE                   0x00040000
 7 #else
 8 #define IRAM_SIZE                   0x00020000
 9 #endif
10 
11 #define GENERATED_GBL_DATA_SIZE     256

最终,CONFIG_SYS_INIT_SP_ADDR = 0x0091FF00

 

至此,可以确定函数调用流程如下:

save_boot_params_ret     /* 进入SVC模式,关闭IRQ和FIQ,向量表重定位 */
-> cpu_init_cp15 /* 初始化CP15协处理器 */ -> cpu_init_crit
-> lowlevel_init /* 设置栈顶指针CONFIG_SYS_INIT_SP_ADDR = 0x0091FF00 */ -> s_init /* 空函数 */ -> _main

 

 

cpu_init_cp15()和cpu_init_crit()函数执行完后,开始执行指令bl _main

六、struct gd_t gd设置

在第二节中,我们已经确定_main()函数定义在arch/arm/lib/文件夹内

在arch/arm/lib/文件夹内执行grep命令,从而确定_main()函数定义在arch/arm/lib/crt0.S文件中

 

函数定义如下,代码中已删除不执行部分,而且因篇幅问题,本节只介绍gd相关设置

 1 ENTRY(_main)
 2     ldr    sp, =(CONFIG_SYS_INIT_SP_ADDR)   /* sp = 0x0091FF00 */
 3     bic    sp, sp, #7                       /* 8字节对齐 */
 4 
 5     mov    r0, sp                           /* r0 = 0x0091FF00,作为board_init_f_alloc_reserve()函数的输入参数 */
 6     bl    board_init_f_alloc_reserve        /* common/init/board_init.c */
 7     mov    sp, r0                           /* sp = 0x0091FA00 */
 8     /* set up gd here, outside any C code */
 9     mov    r9, r0                           /* r9 = 0x0091FA00,arch/arm/include/asm/global_data.h定义r9存储gd地址 */
10     bl    board_init_f_init_reserve         /* common/init/board_init.c */
11 
12     mov    r0, #0
13     bl    board_init_f                      /* common/board_f.c */
14 
15 #if ! defined(CONFIG_SPL_BUILD)
16     ldr    sp, [r9, #GD_START_ADDR_SP]      /* sp = gd->start_addr_sp = 0x9ef41e90 */
17     bic    sp, sp, #7                       /* 8字节对齐,仍为0x9ef41e90 */
18 
19     ldr    r9, [r9, #GD_BD]                 /* r9 = gd->bd = 0x9ef41fb0 */
20     sub    r9, r9, #GD_SIZE                 /* new GD is below bd,0x9ef41eb8 */
21 
22     adr    lr, here                         /* 相对寻址,lr = here */
23     ldr    r0, [r9, #GD_RELOC_OFF]          /* r0 = gd->reloc_off = 0 */
24     add    lr, lr, r0
25 
26     ldr    r0, [r9, #GD_RELOCADDR]          /* r0 = gd->relocaddr = 0x9ff44000 */
27     b    relocate_code                      /* 代码重定位 */
28 here:
29     bl    relocate_vectors                  /* 向量重定位 */
30 
31     bl    c_runtime_cpu_setup               /* 禁用icache */
32 #endif
33 #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_FRAMEWORK)
34     ldr    r0, =__bss_start                 /* this is auto-relocated! */
35     ldr    r1, =__bss_end                   /* this is auto-relocated! */
36     mov    r2, #0x00000000                  /* prepare zero to clear BSS */
37 
38 clbss_l:
39     cmp    r0, r1                           /* 清除BSS段,while not at end of BSS */
40     strlo    r2, [r0]                       /* clear 32-bit BSS word */
41     addlo    r0, r0, #4                     /* move to next */
42     blo    clbss_l
43 
44 #if ! defined(CONFIG_SPL_BUILD)
45     bl coloured_LED_init                    /* 空函数 */
46     bl red_led_on                           /* 空函数 */
47 #endif
48     /* call board_init_r(gd_t *id, ulong dest_addr) */
49     mov r0, r9                              /* r0用来存储全局变量gd的起始地址 */
50     ldr    r1, [r9, #GD_RELOCADDR]          /* r1用来存储重定位的起始地址 */
51     ldr    pc, =board_init_r                /* this is auto-relocated! */
52     /* we should not return here. */
53 #endif
54 
55 ENDPROC(_main)

 

1. board_init_f_alloc_reserve()和board_init_f_init_reserve()函数调用过程如下:

bl board_init_f_alloc_reserve            /* board_init_f_alloc_reserve(top = 0x91FF00) */
  -> top -= CONFIG_SYS_MALLOC_F_LEN;                      /* 0x91FF00 - 0x400 = 0x91FB00 */
  -> top = rounddown(top-sizeof(struct global_data), 16); /* GD_SIZE = 248 */
    -> top = top-GD_SIZE - ((top-GD_SIZE) % 16);          /* 16字节对齐,top = 0x91FA00 */
  -> return top;                                          /* r0 = 0x91FA00 */
mov sp, r0
bl board_init_f_init_reserve             /* board_init_f_init_reserve(base = 0x91FA00) */
  -> struct global_data *gd_ptr;
  -> gd_ptr = (struct global_data *)base;
  -> base += roundup(sizeof(struct global_data), 16);     /* GD_SIZE = 248 */
    -> base += (GD_SIZE + (16 - 1)) /16) * 16;            /* 0x91FA00 + 256 = 0x91FB00 */
  -> gd->malloc_base = base;                              /* gd->malloc_base = 0x91FB00 */
  -> base += CONFIG_SYS_MALLOC_F_LEN;                     /* 0x91FB00 + 0x400 = 0x91FF00 */

完成后的内存分布如下图所示:

之前所提到的gd是一个全局变量,用于存储CPU主频、环境变量地址、RAM地址和大小等数据

 

2. board_init_f()函数定义如下:

 1 void board_init_f(ulong boot_flags/* = 0 */) {
 2     gd->flags = boot_flags;
 3     gd->have_console = 0;
 4 
 5     /* initcall_run_list()定义在lib/initcall.c中
 6      * init_sequence_f[]定义在common/board_f.c中
 7      */
 8     if (initcall_run_list(init_sequence_f))  /* 初始化序列 */
 9         hang();         /* for ( ; ; ) ; */
10 }

其中,

initcall_run_list()函数定义如下:

 1 int initcall_run_list(const init_fnc_t init_sequence[]) {
 2     const init_fnc_t *init_fnc_ptr;
 3 
 4     for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
 5         int ret = (*init_fnc_ptr)();        /* 依次调用init_sequence[]中的函数 */
 6         if (ret) {
 7             return -1;
 8         }
 9     }
10     return 0;
11 }

init_sequence_f[]定义如下:

 1 /** 
 2  * 函数中包含有gd成员设置的注释与其他注释不会在同一种缩进格式下
 3  * gd成员设置我会在第三点中进行陈述
 4  */
 5 static init_fnc_t init_sequence_f[] = {
 6     setup_mon_len,             /* 获取uboot长度/大小 */
 7     initf_malloc,              /* malloc内存池大小 */
 8     initf_console_record,              /* 空函数 */
 9     arch_cpu_init,                     /* basic arch cpu dependent setup */
10     initf_dm,                          /* 初始化驱动模型 */
11     arch_cpu_init_dm,                  /* 空函数 */
12     mark_bootstage,                    /* need timer, go after init dm */
13     board_early_init_f,                /* 初始化UART_IOMUX */
14     timer_init,                /* 初始化定时器并设置gd成员 */
15     board_postclk_init,                /* Set VDDSOC to 1.175V */
16     get_clocks,                /* 获取sdhc_clk */
17     env_init,                  /* 获取保存环境变量的地址 */
18     init_baud_rate,            /* 根据环境变量获取波特率 */
19     serial_init,               /* 启动UART并设置gd成员 */
20     console_init_f,            /* UART设置完成,将之前暂存的信息打印出来 */
21     display_options,                   /* 打印uboot版本信息 */
22     display_text_info,                 /* 打印uboot主要代码段的起始地址 */
23     print_cpuinfo,                     /* 打印CPU信息 */
24     show_board_info,                   /* 打印单板信息 */
25     INIT_FUNC_WATCHDOG_INIT            /* 初始化看门狗,空函数 */
26     INIT_FUNC_WATCHDOG_RESET           /* 复位看门狗,空函数 */
27     init_func_i2c,                     /* 初始化I2C */
28     announce_dram_init,                /* 打印"DRAM:  " */
29     dram_init,                 /* 获取RAM大小 */
30     INIT_FUNC_WATCHDOG_RESET
31     INIT_FUNC_WATCHDOG_RESET
32     INIT_FUNC_WATCHDOG_RESET
33 
34     setup_dest_addr,                   /* setup_dest_addr()至display_new_sp()均为gd设置 */
35     reserve_round_4k,
36     reserve_mmu,
37     reserve_trace,
38     reserve_uboot,
39     reserve_malloc,
40     reserve_board,
41     setup_machine,
42     reserve_global_data,
43     reserve_fdt,
44     reserve_arch,
45     reserve_stacks,
46     setup_dram_config,
47     show_dram_config,
48     display_new_sp,
49     INIT_FUNC_WATCHDOG_RESET
50     reloc_fdt,                 /* 空函数 */
51     setup_reloc,               /* 代码重定位 */
52     NULL,
53 };

 

3. struct gd_t gd成员设置:

 1 /* 为缩减长度,在此并未提供函数名 */
 2 gd->malloc_base = base;                             /* 0x0091FA00 */
 3 
 4 gd->flags = boot_flags;                             /* 0 */
 5 gd->have_console = 0;
 6 
 7 gd->mon_len = (ulong)&__bss_end - (ulong)_start;    /* 0x878abab8-0x87800000=0xabab8(其值因代码长度而变化) */
 8 
 9 gd->malloc_limit = CONFIG_SYS_MALLOC_F_LEN;         /* 0x400 */
10 gd->malloc_ptr = 0;
11 
12 gd->arch.tbl = 0;
13 gd->arch.tbu = 0;
14 
15 gd->arch.sdhc_clk = mxc_get_clock(MXC_ESDHC2_CLK);  /* SD卡外设时钟:198000000 */
16 
17 gd->env_addr    = (ulong)&default_environment[0];   /* default_environment地址:0x8784454E */
18 gd->env_valid   = 1;
19 /* 在环境变量中查找baudrate,没有则使用CONFIG_BAUDRATE(115200) */
20 gd->baudrate = getenv_ulong("baudrate", 10, CONFIG_BAUDRATE); 
21 
22 gd->flags |= GD_FLG_SERIAL_READY;                   /* 0x00100 */
23 
24 gd->have_console = 1;
25 
26 gd->ram_size = imx_ddr_size();                      /* DRAM大小:0x20000000 = 512M */
27 
28 gd->ram_top = CONFIG_SYS_SDRAM_BASE;                /* DRAM起始地址:0x80000000 */
29 gd->ram_top += get_effective_memsize();             /* 0x80000000 + gd->ram_size = 0xA0000000 */
30 gd->ram_top = board_get_usable_ram_top(gd->mon_len);/* DRAM结束地址:0xA0000000 */
31 gd->relocaddr = gd->ram_top;
32 
33 gd->relocaddr = determine_mp_bootpg(NULL);          /* 0xA0000000 */
34 
35 gd->relocaddr &= ~(4096 - 1);
36 
37 gd->arch.tlb_size = PGTABLE_SIZE;                   /* 4096*4=0x4000 */
38 gd->relocaddr -= gd->arch.tlb_size;                 /* 0x9fffc000 */
39 gd->relocaddr &= ~(0x10000 - 1);                    /* 0x9fff0000 */
40 gd->arch.tlb_addr = gd->relocaddr;
41 
42 gd->relocaddr -= gd->mon_len;                       /* 0x9fff0000 - 0xabab8 = 0x9ff44548 */
43 gd->relocaddr &= ~(4096 - 1);                       /* 0x9ff44000 */
44 gd->start_addr_sp = gd->relocaddr;
45 
46 /* TOTAL_MALLOC_LEN = 16 * 0x100000 */
47 gd->start_addr_sp = gd->start_addr_sp - TOTAL_MALLOC_LEN;  /* 0x9ef42000 */
48 
49 gd->start_addr_sp -= sizeof(bd_t);                  /* 0x9ef41fb0 */
50 gd->bd = (bd_t *)map_sysmem(gd->start_addr_sp, sizeof(bd_t));
51 
52 gd->start_addr_sp -= sizeof(gd_t);                  /* 0x9ef41eb8 */
53 gd->new_gd = (gd_t *)map_sysmem(gd->start_addr_sp, sizeof(gd_t));
54 
55 gd->start_addr_sp -= 16;                            /* 0x9ef41ea8 */
56 gd->start_addr_sp &= ~0xf;                          /* 0x9ef41ea0 */
57 gd->irq_sp = gd->start_addr_sp;
58 gd->start_addr_sp -= 16;                            /* 0x9ef41e90 */
59 
60 gd->bd->bi_dram[0].start = CONFIG_SYS_SDRAM_BASE;   /* 0x80000000 */
61 gd->bd->bi_dram[0].size = get_effective_memsize();  /* gd->bd->bi_dram[0].size = gd->ram_size = 0x20000000 */

在此,我只分析15行和26行代码:

gd->arch.sdhc_clk = mxc_get_clock(MXC_ESDHC2_CLK)调用过程:

mxc_get_clock(MXC_ESDHC2_CLK)
  -> return get_usdhc_clk(1);
    -> u32 cscmr1 = __raw_readl(&imx_ccm->cscmr1);          /* cscmr1 = *0x20c401c = 0x4900100 */
    -> u32 cscdr1 = __raw_readl(&imx_ccm->cscdr1);          /* cscdr1 = *0x20c4024 = 0x6490b00 */
    -> usdhc_podf = (cscdr1 & (0x7 << 16)) >> 16;           /* usdhc_podf = 1 */
    -> clk_sel = cscmr1 & (1 << 17);                        /* clk_sel = 0 */
    -> root_freq = mxc_get_pll_pfd(PLL_BUS, 2);             /* root_freq = 0x179a7b00,为get_usdhc_clk(1)返回值 */
      -> div = __raw_readl(&imx_ccm->analog_pfd_528);       /* div = 0x5058505b */
      -> freq = (u64)decode_pll(PLL_BUS, 24000000);         /* freq = 0x1f78a400 */
        -> u32 div = __raw_readl(&imx_ccm->analog_pll_528);
        -> div &= 0x01;                                     /* 1 */
        -> return 24000000 * (20 + (div << 1));             /* 24000000 * 22 = 528000000 = 0x1f78a400 */
      -> return lldiv(freq * 18, (div & 0x3f)) >> 0);       /* (528000000 * 18, 0x1b) */
        -> do_div(freq * 18, 0x1b);
          -> __div64_32(&n, 0x1b);
View Code

gd->ram_size = imx_ddr_size()调用过程:

dram_init()
  -> gd->ram_size = imx_ddr_size();
    -> struct esd_mmdc_regs *mem = (struct esd_mmdc_regs *)MEMCTL_BASE;    /* 0x21b0000 */
    -> unsigned ctl = readl(&mem->ctl);                     /* ctl  = 0x84180000 */
    -> unsigned misc = readl(&mem->misc);                   /* misc = 0x40201740 */
    -> int bits = 11 + 0 + 0 + 1;                           /* row + col + bank + width */
    -> bits += ESD_MMDC_CTL_GET_ROW(ctl);                   /* ((0x84180000 >> 24) & 7) = 4 */
    -> bits += col_lookup[ESD_MMDC_CTL_GET_COLUMN(ctl)];    /* col_lookup [((0x84180000 >> 20) & 7) = 1] = 10 */
    -> bits += bank_lookup[ESD_MMDC_MISC_GET_BANK(misc)];   /* bank_lookup[((0x40201740 >> 5 ) & 1) = 0] = 3 */
    -> bits += ESD_MMDC_CTL_GET_WIDTH(ctl);                 /* ((0x84180000 >> 16) & 3) = 0 */
    -> bits += ESD_MMDC_CTL_GET_CS1(ctl);                   /* ((0x84180000 >> 30) & 1) = 0 */
    -> return 1 << bits;                                    /* 1 << 29 = 521M,bits = 12 + 4 + 10 + 3 + 0 + 0 = 29 */
View Code

gd所涉及的内存布局如下图所示:

 

_main()函数中调用的和init_sequence_f[]中定义的其他函数我将在接下来几章中进行介绍

 

分类:

技术点:

相关文章: