U-Boot TPL是一段非常简短的代码,目的是初始化RAM,最近到手了一个自己的PX30板子,没有任何资料,于是就打算上主线代码一步一步来,一启动,喜闻乐见:
U-Boot TPL board init
sdram_init failed
而TPL的C入口如下(至于怎么进入board_init_f没有研究的意义,网上一大堆.):
void board_init_f(ulong dummy)
{
int ret;
#ifdef CONFIG_DEBUG_UART
debug_uart_init();
/*
* Debug UART can be used from here if required:
*
* debug_uart_init();
* printch('a');
* printhex8(0x1234);
* printascii("string");
*/
printascii("U-Boot TPL board init\n");
#endif
secure_timer_init();
ret = sdram_init();
if (ret)
printascii("sdram_init failed\n");
/* return to maskrom */
back_to_bootrom(BROM_BOOT_NEXTSTAGE);
}
由因为Secure Timer是Trusted Zone的内容,所以他肯定也不会出错,除非处理器本身是问题的,也就剩下sdram_init函数了.而PX30的DDR引脚是固定的,也就是没有配置的可能性,所以问题一定在其他地方,根据观察板上焊的是IMG512M32V1D2CEL-107,由于这个板子之前是用在其他产品,说明一定支持这个内存.查得参数是LPDDR3 933MHz @ 16Gbits,因此我也打开了CONFIG_RAM_PX30_LPDDR3这个宏定义.
/* return: 0 = success, other = fail */
int sdram_init(void)
{
struct px30_sdram_params *sdram_params;
int ret = 0;
dram_info.phy = (void *)DDR_PHY_BASE_ADDR;
dram_info.pctl = (void *)DDRC_BASE_ADDR;
dram_info.grf = (void *)GRF_BASE_ADDR;
dram_info.cru = (void *)CRU_BASE_ADDR;
dram_info.msch = (void *)SERVER_MSCH0_BASE_ADDR;
dram_info.ddr_grf = (void *)DDR_GRF_BASE_ADDR;
dram_info.pmugrf = (void *)PMUGRF_BASE_ADDR;
sdram_params = get_default_sdram_config();
ret = sdram_init_detect(&dram_info, sdram_params);
if (ret)
goto error;
sdram_print_ddr_info(&sdram_params->ch.cap_info, &sdram_params->base);
printascii("out\n");
return ret;
error:
return (-1);
}
这是我网上随便很辛苦找的其他PX30的参考原理图.
可见引脚没什么选择的余地,这样更好,说明不会涉及改太多配置.
/* return: 0 = success, other = fail */
int sdram_init(void)
{
struct px30_sdram_params *sdram_params;
int ret = 0;
dram_info.phy = (void *)DDR_PHY_BASE_ADDR;
dram_info.pctl = (void *)DDRC_BASE_ADDR;
dram_info.grf = (void *)GRF_BASE_ADDR;
dram_info.cru = (void *)CRU_BASE_ADDR;
dram_info.msch = (void *)SERVER_MSCH0_BASE_ADDR;
dram_info.ddr_grf = (void *)DDR_GRF_BASE_ADDR;
dram_info.pmugrf = (void *)PMUGRF_BASE_ADDR;
sdram_params = get_default_sdram_config();
ret = sdram_init_detect(&dram_info, sdram_params);
if (ret)
goto error;
sdram_print_ddr_info(&sdram_params->ch.cap_info, &sdram_params->base);
printascii("out\n");
return ret;
error:
return (-1);
}
出问题的是sdram_init_detect,因为没打印out字样,所以跟进分析.
/*
* pre_init: 0: pre init for dram cap detect
* 1: detect correct cap(except cs1 row)info, than reinit
* 2: after reinit, we detect cs1_row, if cs1_row not equal
* to cs0_row and cs is in middle on ddrconf map, we need
* to reinit dram, than set the correct ddrconf.
*/
static int sdram_init_(struct dram_info *dram,
struct px30_sdram_params *sdram_params, u32 pre_init)
{
struct sdram_cap_info *cap_info = &sdram_params->ch.cap_info;
void __iomem *pctl_base = dram->pctl;
rkclk_ddr_reset(dram, 1, 1, 1, 1); //复位DDR控制器之类,这些部分一定不会出问题.
udelay(10);
/*
* dereset ddr phy psrstn to config pll,
* if using phy pll psrstn must be dereset
* before config pll
*/
rkclk_ddr_reset(dram, 1, 1, 1, 0);
rkclk_configure_ddr(dram, sdram_params);
/* release phy srst to provide clk to ctrl */
rkclk_ddr_reset(dram, 1, 1, 0, 0);
udelay(10);
phy_soft_reset(dram->phy);
/* release ctrl presetn, and config ctl registers */
rkclk_ddr_reset(dram, 1, 0, 0, 0);
pctl_cfg(dram->pctl, &sdram_params->pctl_regs, SR_IDLE, PD_IDLE);
cap_info->ddrconfig = calculate_ddrconfig(sdram_params);
set_ctl_address_map(dram, sdram_params);
phy_cfg(dram->phy, &sdram_params->phy_regs, sdram_params->skew,
&sdram_params->base, cap_info->bw);
/* enable dfi_init_start to init phy after ctl srstn deassert */
setbits_le32(pctl_base + DDR_PCTL2_DFIMISC, (1 << 5) | (1 << 4));
rkclk_ddr_reset(dram, 0, 0, 0, 0);
/* wait for dfi_init_done and dram init complete */
while ((readl(pctl_base + DDR_PCTL2_STAT) & 0x7) == 0)
continue;
if (sdram_params->base.dramtype == LPDDR3) //打印一下这个判断.
pctl_write_mr(dram->pctl, 3, 11, 3, LPDDR3);
/* do ddr gate training */
redo_cs0_training:
if (data_training(dram, 0, sdram_params->base.dramtype) != 0) {
if (pre_init != 0)
printascii("DTT cs0 error\n");
return -1;
}
if (check_rd_gate(dram)) {
printascii("re training cs0");
goto redo_cs0_training;
}
if (sdram_params->base.dramtype == LPDDR3) {
if ((read_mr(dram, 1, 8) & 0x3) != 0x3)
return -1;
} else if (sdram_params->base.dramtype == LPDDR2) {
if ((read_mr(dram, 1, 8) & 0x3) != 0x0)
return -1;
}
/* for px30: when 2cs, both 2 cs should be training */
if (pre_init != 0 && cap_info->rank == 2) {
redo_cs1_training:
if (data_training(dram, 1, sdram_params->base.dramtype) != 0) {
printascii("DTT cs1 error\n");
return -1;
}
if (check_rd_gate(dram)) {
printascii("re training cs1");
goto redo_cs1_training;
}
}
if (sdram_params->base.dramtype == DDR4)
pctl_write_vrefdq(dram->pctl, 0x3, 5670,
sdram_params->base.dramtype);
dram_all_config(dram, sdram_params);
enable_low_power(dram, sdram_params);
return 0;
}
/* return: 0 = success, other = fail */
static int sdram_init_detect(struct dram_info *dram,
struct px30_sdram_params *sdram_params)
{
struct sdram_cap_info *cap_info = &sdram_params->ch.cap_info;
u32 ret;
u32 sys_reg = 0;
u32 sys_reg3 = 0;
if (sdram_init_(dram, sdram_params, 0) != 0)
return -1;
if (dram_detect_cap(dram, sdram_params, 0) != 0)
return -1;
/* modify bw, cs related timing */
pctl_remodify_sdram_params(&sdram_params->pctl_regs, cap_info,
sdram_params->base.dramtype);
/* reinit sdram by real dram cap */
ret = sdram_init_(dram, sdram_params, 1);
if (ret != 0)
goto out;
/* redetect cs1 row */
sdram_detect_cs1_row(cap_info, sdram_params->base.dramtype);
if (cap_info->cs1_row) {
sys_reg = readl(&dram->pmugrf->os_reg[2]);
sys_reg3 = readl(&dram->pmugrf->os_reg[3]);
SYS_REG_ENC_CS1_ROW(cap_info->cs1_row,
sys_reg, sys_reg3, 0);
writel(sys_reg, &dram->pmugrf->os_reg[2]);
writel(sys_reg3, &dram->pmugrf->os_reg[3]);
}
ret = sdram_detect_high_row(cap_info);
out:
return ret;
}
最后发现dramtype判断错误,最后发现CONFIG_RAM_PX30_LPDDR3同时开启了好几个,最后关闭其他RAM判断,只留其中一个就好.
if (sdram_params->base.dramtype == LPDDR3)
最后引导就过了这部分.
U-Boot TPL board init
LPDDR3, 333MHz
BW=32 Col=10 Bk=8 CS0 Row=15 CS1 Row=15 CS=2 Die BW=16 Size=2048MB
out
U-Boot SPL 2021.07-rc4-g97c8cb5-dirty (Jun 21 2021 - 21:08:49 +0800)
Trying to boot from MMC1
终于可以进入SPL了,然后卡在这里.
/**
* boot_from_devices() - Try loading a booting U-Boot from a list of devices
*
* @spl_image: Place to put the image details if successful
* @spl_boot_list: List of boot devices to try
* @count: Number of elements in spl_boot_list
* @return 0 if OK, -ve on error
*/
static int boot_from_devices(struct spl_image_info *spl_image,
u32 spl_boot_list[], int count)
{
int i;
for (i = 0; i < count && spl_boot_list[i] != BOOT_DEVICE_NONE; i++) {
struct spl_image_loader *loader;
loader = spl_ll_find_loader(spl_boot_list[i]);
#if defined(CONFIG_SPL_SERIAL_SUPPORT) \
&& defined(CONFIG_SPL_LIBCOMMON_SUPPORT) \
&& !defined(CONFIG_SILENT_CONSOLE)
if (loader)
printf("Trying to boot from %s\n", loader->name); //遇到这里之后就直接GG了.
else
puts(SPL_TPL_PROMPT "Unsupported Boot Device!\n");
#endif
if (loader && !spl_load_image(spl_image, loader)) {
spl_image->boot_device = spl_boot_list[i];
return 0;
}
}
return -ENODEV;
}
因为上面判断到Loader非空,所以一定可以加载spl_load_image,先不论MMC1是不是正确的设备,至少发现了MMC1,然后会调用loader的load_image方法.
static int spl_load_image(struct spl_image_info *spl_image,
struct spl_image_loader *loader)
{
int ret;
struct spl_boot_device bootdev;
bootdev.boot_device = loader->boot_device;
bootdev.boot_device_name = NULL;
ret = loader->load_image(spl_image, &bootdev);
#ifdef CONFIG_SPL_LEGACY_IMAGE_CRC_CHECK
if (!ret && spl_image->dcrc_length) {
/* check data crc */
ulong dcrc = crc32_wd(0, (unsigned char *)spl_image->dcrc_data,
spl_image->dcrc_length, CHUNKSZ_CRC32);
if (dcrc != spl_image->dcrc) {
puts("SPL: Image data CRC check failed!\n");
ret = -EINVAL;
}
}
#endif
return ret;
}
所以这里要往上分析,发现实际从FDT取数据,然后检查FDT正确,检查返回为0,正确,最后进到bl31_entry然后卡死.
static void bl31_entry(uintptr_t bl31_entry, uintptr_t bl32_entry,
uintptr_t bl33_entry, uintptr_t fdt_addr)
{
atf_entry_t atf_entry = (atf_entry_t)bl31_entry;
void *bl31_params;
if (CONFIG_IS_ENABLED(ATF_LOAD_IMAGE_V2))
bl31_params = bl2_plat_get_bl31_params_v2(bl32_entry,
bl33_entry,
fdt_addr);
else
bl31_params = bl2_plat_get_bl31_params(bl32_entry, bl33_entry,
fdt_addr);
raw_write_daif(SPSR_EXCEPTION_MASK);
dcache_disable();
atf_entry(bl31_params, (void *)fdt_addr);
}
后检查ATF_LOAD_IMAGE_V2没打开,由于我下载的是主线ATF,所以这个应该打开.(毕竟不是旧版了)
最后顺利启动了~
U-Boot TPL board init
LPDDR3, 333MHz
BW=32 Col=10 Bk=8 CS0 Row=15 CS1 Row=15 CS=2 Die BW=16 Size=2048MB
out
U-Boot SPL 2021.07-rc4-g386a08b-dirty (Jun 22 2021 - 00:21:54 +0800)
Trying to boot from MMC1
mmc_load_image_raw_sector: mmc block read error
NOTICE: BL31: v2.5(release):2a00877
NOTICE: BL31: Built : 13:26:52, Jun 21 2021
U-Boot 2021.07-rc4-g386a08b-dirty (Jun 22 2021 - 00:22:02 +0800)
Model: Rockchip PX30 EVB
DRAM: 2 GiB
PMIC: RK8090 (on=0x10, off=0x00)
MMC: dwmmc@ff380000: 2, dwmmc@ff390000: 0
Loading Environment from MMC... *** Warning - bad CRC, using default environment
In: serial@ff160000
Out: serial@ff160000
Err: serial@ff160000
Model: Rockchip PX30 EVB
Net: Could not get PHY for ethernet@ff360000: addr -1
No ethernet found.
Hit any key to stop autoboot: 0
switch to partitions #0, OK
mmc0(part 0) is current device
** Unrecognized filesystem type **
MMC Device 1 not found
no mmc device at slot 1
starting USB...
Bus usb@ff340000: USB EHCI 1.00
scanning bus usb@ff340000 for devices... 2 USB Device(s) found
scanning usb for storage devices... 0 Storage Device(s) found
Device 0: unknown device
No ethernet found.
missing environment variable: pxeuuid
missing environment variable: bootfile
Retrieving file: pxelinux.cfg/00000000
No ethernet found.
missing environment variable: bootfile
Retrieving file: pxelinux.cfg/0000000
No ethernet found.
missing environment variable: bootfile
Retrieving file: pxelinux.cfg/000000
No ethernet found.
missing environment variable: bootfile
Retrieving file: pxelinux.cfg/00000
No ethernet found.
missing environment variable: bootfile
Retrieving file: pxelinux.cfg/0000
No ethernet found.
missing environment variable: bootfile
Retrieving file: pxelinux.cfg/000
No ethernet found.
missing environment variable: bootfile
Retrieving file: pxelinux.cfg/00
No ethernet found.
missing environment variable: bootfile
Retrieving file: pxelinux.cfg/0
No ethernet found.
missing environment variable: bootfile
Retrieving file: pxelinux.cfg/default-arm-px30-evb_px30
No ethernet found.
missing environment variable: bootfile
Retrieving file: pxelinux.cfg/default-arm-px30
No ethernet found.
missing environment variable: bootfile
Retrieving file: pxelinux.cfg/default-arm
No ethernet found.
missing environment variable: bootfile
Retrieving file: pxelinux.cfg/default
No ethernet found.
Config file not found
No ethernet found.
=>
后续再看如何移植U-Boot本体.