1、ddr时序的写入

spl阶段将时序写入ddr寄存器。一般来说自己移植ddr的时候就需要干两件事:(1)使用ddr工具获取稳定的ddr时序,(2)修改uboot中定义的ddr各个bank的 大小。

spl_dram_init //board/freescale/imx8mp_evk/spl.c

->ddr_init //drivers/ddr/imx/imx8m/ddr_init.c

2、ddr bank的初始化dram_init_banksize

#yyds干货盘点#Uboot中ddr的初始化_寄存器

从芯片手册可知,i.MX8MP共分为两个ddr区域,3072MB的区域起始地址为0x40000000,第二块5120MB区域的起始地址为0x1000000000。

这里我们以6GB内存的EVK为例,ddr大小的定义:include/configs/imx8mp_evk.h,ddr的比例只能是1:1和3:1,因为Linux的内存管理系统只支持这两种比例。

/* Totally 6GB DDR */
#define CONFIG_SYS_SDRAM_BASE 0x40000000
#define PHYS_SDRAM 0x40000000
#define PHYS_SDRAM_SIZE 0xC0000000 /* 3 GB */
#define PHYS_SDRAM_2 0x100000000
#ifdef CONFIG_TARGET_IMX8MP_DDR4_EVK
#define PHYS_SDRAM_2_SIZE 0x40000000 /* 1 GB */
#else
#define PHYS_SDRAM_2_SIZE 0xC0000000 /* 3 GB */
#endif

board_phys_sdram_size获取ddr 每个bank大小。

__weak int board_phys_sdram_size(phys_size_t *size)
{
if (!size)
return -EINVAL;

*size = PHYS_SDRAM_SIZE;//0xC0000000

#ifdef PHYS_SDRAM_2_SIZE
*size += PHYS_SDRAM_2_SIZE;//0xC0000000
#endif
return 0;
}

arch/arm/mach-imx/imx8m/soc.其中bank1的大小不能超过3072MB,超过3GB的部分会被舍弃。

int dram_init_banksize(void)
{
int bank = 0;
int ret;
phys_size_t sdram_size;
phys_size_t sdram_b1_size, sdram_b2_size;

ret = board_phys_sdram_size(&sdram_size);
if (ret)
return ret;

/* Bank 1 can't cross over 4GB space */
if (sdram_size > 0xc0000000) {
sdram_b1_size = 0xc0000000;
sdram_b2_size = sdram_size - 0xc0000000;
} else {
sdram_b1_size = sdram_size;
sdram_b2_size = 0;
}
//设置ddr第一个bank的起始地址0x40000000
gd->bd->bi_dram[bank].start = PHYS_SDRAM;
if (rom_pointer[1]) {
//带optee的处理
phys_addr_t optee_start = (phys_addr_t)rom_pointer[0];
phys_size_t optee_size = (size_t)rom_pointer[1];

gd->bd->bi_dram[bank].size = optee_start - gd->bd->bi_dram[bank].start;
if ((optee_start + optee_size) < (PHYS_SDRAM + sdram_b1_size)) {
if (++bank >= CONFIG_NR_DRAM_BANKS) {
puts("CONFIG_NR_DRAM_BANKS is not enough\n");
return -1;
}

gd->bd->bi_dram[bank].start = optee_start + optee_size;
gd->bd->bi_dram[bank].size = PHYS_SDRAM +
sdram_b1_size - gd->bd->bi_dram[bank].start;
}
} else {
gd->bd->bi_dram[bank].size = sdram_b1_size;
}

if (sdram_b2_size) {
if (++bank >= CONFIG_NR_DRAM_BANKS) {
puts("CONFIG_NR_DRAM_BANKS is not enough for SDRAM_2\n");
return -1;
}
//第二个bank的起始地址0x100000000
gd->bd->bi_dram[bank].start = 0x100000000UL;
//设置大小
gd->bd->bi_dram[bank].size = sdram_b2_size;
}

return 0;
}

common/board_f.c中的setup_dest_addr会调用我们定义的get_effective_memsize函数来得到ram的最大值。

phys_size_t get_effective_memsize(void)
{
int ret;
phys_size_t sdram_size;
phys_size_t sdram_b1_size;
ret = board_phys_sdram_size(&sdram_size);
if (!ret) {
/* Bank 1 can't cross over 4GB space */
if (sdram_size > 0xc0000000) {
sdram_b1_size = 0xc0000000;
} else {
sdram_b1_size = sdram_size;
}

if (rom_pointer[1]) {
/* We will relocate u-boot to Top of dram1. Tee position has two cases:
* 1. At the top of dram1, Then return the size removed optee size.
* 2. In the middle of dram1, return the size of dram1.
*/
if ((rom_pointer[0] + rom_pointer[1]) == (PHYS_SDRAM + sdram_b1_size))
return ((phys_addr_t)rom_pointer[0] - PHYS_SDRAM);
}

return sdram_b1_size;
} else {
return PHYS_SDRAM_SIZE;
}
}