RK3228H系统启动流程(一)UBOOT配置启动分析

此生再无相见时 提交于 2020-02-06 19:59:21

一、引言

本文整体介绍RK所提供的SDK中,系统整体的启动流程,包含以下三部分

1、boot启动,即MiniLoaderAll.bin和uboot.img启动
2、linux内核启动,即kernel.img的启动
3、android系统的启动,即ramdisk.img、system.img的启动。
本文先来介绍第一部分

二、U-boot配置(详细过程可看我上一篇文章)

1、工具链配置:

Rockchip U-Boot 默认使用 Google Android 系统提供的 GCC ToolChain,在 “U-BOOT/Makefile” 中指定

2、平台配置

平台配置文件位于"U-Boot/configs"目录下 (为rk322xh_box_defconfig)
其中Rockchip相关的以RK开头,并根据产品形态分为 MID 和 BOX 两种配置,Rockchip 芯片平台的配置
主要是芯片类型,Rockchip 一些 Kconfig 的关键配置,采用savedefconfig 模式保存。该选项内的配置会被优先编译成宏定义并在相关的项前面自动添加 CONFIG_,可以在U-BOOT 自动生成的配置文(include/config.h)中看到生成的宏定义,会优先系统的配置文件,可以支配系统的配置文件。

3、系统配置

位于 U-Boot 根目录下的 include\configs 文件夹下,同样以 RK 开头(为rk33plat.h)
平台的配置,根据不同芯片进行一些细节的配置,如内存地址、简配一些功能模块的配置

整体流程

执行

make rk3368_defconfig
make ARCHV=aarch64

会在rk3368_defconfig配置文件中选择芯片系列,生成include/config.h,如下

* Automatically generated - do not edit */
#define CONFIG_RKCHIP_RK322XH	1
#define CONFIG_PRODUCT_BOX	1
#define CONFIG_NORMAL_WORLD	1
#define CONFIG_SECOND_LEVEL_BOOTLOADER	1
#define CONFIG_BAUDRATE	115200
#define CONFIG_BOARDDIR board/rockchip/rk33xx
#include <config_defaults.h>
#include <configs/rk33plat.h>
#include <asm/config.h>
#include <config_fallbacks.h>
#include <config_uncmd_spl.h>

在该文件中调用rk33plat.h 系统配置文件,设置一系列配置。

三、UBOOT启动分析

程序启动是从u-boot/arch/arm/cpu/armv7目录下的start.S文件开始,里面会调用到该目录下的/rk32xx/lowlevel_init.S文件,start.S函数最后调用_main函数,这个在u-boot/arch/arm/lib/crt0.S文件中,里面再调用board_init_f和board_init_r函数,其定义均在u-boot/arch/arm/lib/board.c文件中。

1、board_init_f函数会调用初始化队列里面的函数,如下定义:

ENTRY(_main)

/*
 * Set up initial C runtime environment and call board_init_f(0).
 */

#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK)
	ldr	sp, =(CONFIG_SPL_STACK)
#else
	ldr	sp, =(CONFIG_SYS_INIT_SP_ADDR)
#endif
	bic	sp, sp, #7	/* 8-byte alignment for ABI compliance */
	mov	r2, sp
	sub	sp, sp, #GD_SIZE	/* allocate one GD above SP */
	bic	sp, sp, #7	/* 8-byte alignment for ABI compliance */
	mov	r9, sp		/* GD is above SP */
	mov	r1, sp
	mov	r0, #0
clr_gd:
	cmp	r1, r2			/* while not at end of GD */
	strlo	r0, [r1]		/* clear 32-bit GD word */
	addlo	r1, r1, #4		/* move to next */
	blo	clr_gd
#if defined(CONFIG_SYS_MALLOC_F_LEN) && !defined(CONFIG_SPL_BUILD)
	sub	sp, sp, #CONFIG_SYS_MALLOC_F_LEN
	str	sp, [r9, #GD_MALLOC_BASE]
#endif
	/* mov r0, #0 not needed due to above code */
	bl	board_init_f
init_fnc_t *init_sequence[] = {
    arch_cpu_init,                   /* basic arch cpu dependent setup */
    mark_bootstage,
#ifdef CONFIG_OF_CONTROL
    fdtdec_check_fdt,
#endif
#if defined(CONFIG_BOARD_EARLY_INIT_F)
    board_early_init_f,
#endif
    timer_init,                /* initialize timer */
#ifdef CONFIG_BOARD_POSTCLK_INIT
    board_postclk_init,
#endif
#ifdef CONFIG_FSL_ESDHC
   get_clocks,
#endif
    env_init,                    /* 设置gd的成员,初始化环境变量 */
    init_baudrate,                /* 设置波特率 */
    serial_init,                    /* 初始化串口 */
    console_init_f,                /* 完成第一阶段的控制台初始化 */
    display_banner,                /* say that we are here */
    print_cpuinfo,                /* 打印uboot时钟频率信息 */
#if defined(CONFIG_DISPLAY_BOARDINFO)
    checkboard,                   /* display board info */
#endif
#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SYS_I2C)
    init_func_i2c,
#endif
    dram_init,                  /* 设置gd->ram_size */
    NULL,
};

board_init_r

最后会执行board_init_r 函数,进入uboot命令行,等待输入命令,若无命令输入,则启动内核
下为crt0.S中(_main)的最后一段

/* Set up final (full) environment */

	bl	c_runtime_cpu_setup	/* we still call old routine here */

	ldr	r0, =__bss_start	/* this is auto-relocated! */
	ldr	r1, =__bss_end		/* this is auto-relocated! */

	mov	r2, #0x00000000		/* prepare zero to clear BSS */

clbss_l:cmp	r0, r1			/* while not at end of BSS */
	strlo	r2, [r0]		/* clear 32-bit BSS word */
	addlo	r0, r0, #4		/* move to next */
	blo	clbss_l

	bl coloured_LED_init
	bl red_led_on

	/* call board_init_r(gd_t *id, ulong dest_addr) */
	mov     r0, r9                  /* gd_t */
	ldr	r1, [r9, #GD_RELOCADDR]	/* dest_addr */
	/* call board_init_r */
	ldr	pc, =board_init_r	/* this is auto-relocated! */

	/* we should not return here. */

board_init_r

void board_init_r(gd_t *id, ulong dest_addr)
{
	ulong malloc_start;
#if !defined(CONFIG_SYS_NO_FLASH)
	ulong flash_size;
#endif

	gd->flags |= GD_FLG_RELOC;	/* tell others: relocation done */
	bootstage_mark_name(BOOTSTAGE_ID_START_UBOOT_R, "board_init_r");

	monitor_flash_len = (ulong)&__rel_dyn_end - (ulong)_start;

	/* Enable caches */
	enable_caches();

	debug("monitor flash len: %08lX\n", monitor_flash_len);
	board_init();	/* Setup chipselects */
	/*
	 * TODO: printing of the clock inforamtion of the board is now
	 * implemented as part of bdinfo command. Currently only support for
	 * davinci SOC's is added. Remove this check once all the board
	 * implement this.
	 */
#ifdef CONFIG_CLOCKS
	set_cpu_clk_info(); /* Setup clock information */
#endif
	serial_initialize();

#ifndef CONFIG_SKIP_RELOCATE_UBOOT
	debug("Now running in RAM - U-Boot at: %08lx\n", dest_addr);
#else
	debug("Now running in RAM - U-Boot at: %08lx\n", CONFIG_SYS_SDRAM_BASE);
#endif

#ifdef CONFIG_LOGBUFFER
	logbuff_init_ptrs();
#endif
#ifdef CONFIG_POST
	post_output_backlog();
#endif

	/* The Malloc area is immediately below the monitor copy in DRAM */
	malloc_start = dest_addr - TOTAL_MALLOC_LEN;
	mem_malloc_init (malloc_start, TOTAL_MALLOC_LEN);

#ifdef CONFIG_ARCH_EARLY_INIT_R
	arch_early_init_r();
#endif
	power_init_board();

#if !defined(CONFIG_SYS_NO_FLASH)
	puts("Flash: ");

	flash_size = flash_init();
	if (flash_size > 0) {
# ifdef CONFIG_SYS_FLASH_CHECKSUM
		print_size(flash_size, "");
		/*
		 * Compute and print flash CRC if flashchecksum is set to 'y'
		 *
		 * NOTE: Maybe we should add some WATCHDOG_RESET()? XXX
		 */
		if (getenv_yesno("flashchecksum") == 1) {
			printf("  CRC: %08X", crc32(0,
				(const unsigned char *) CONFIG_SYS_FLASH_BASE,
				flash_size));
		}
		putc('\n');
# else	/* !CONFIG_SYS_FLASH_CHECKSUM */
		print_size(flash_size, "\n");
# endif /* CONFIG_SYS_FLASH_CHECKSUM */
	} else {
		puts(failed);
		hang();
	}
#endif

#if defined(CONFIG_CMD_NAND)
	puts("NAND:  ");
	nand_init();		/* go init the NAND */
#endif

#if defined(CONFIG_CMD_ONENAND)
	onenand_init();
#endif

#ifdef CONFIG_GENERIC_MMC
	puts("MMC:   ");
	mmc_initialize(gd->bd);
#endif

#ifdef CONFIG_ROCKCHIP
	board_storage_init();
#endif

#ifdef CONFIG_CMD_SCSI
	puts("SCSI:  ");
	scsi_init();
#endif

#ifdef CONFIG_HAS_DATAFLASH
	AT91F_DataflashInit();
	dataflash_print_info();
#endif

	/* initialize environment */
	if (should_load_env())
		env_relocate();
	else
		set_default_env(NULL);

#if defined(CONFIG_CMD_PCI) || defined(CONFIG_PCI)
	arm_pci_init();
#endif

	stdio_init();	/* get the devices list going. */

	jumptable_init();

#if defined(CONFIG_API)
	/* Initialize API */
	api_init();
#endif

	console_init_r();	/* fully init console as a device */

#ifdef CONFIG_DISPLAY_BOARDINFO_LATE
# ifdef CONFIG_OF_CONTROL
	/* Put this here so it appears on the LCD, now it is ready */
	display_fdt_model(gd->fdt_blob);
# else
	checkboard();
# endif
#endif

#if defined(CONFIG_ARCH_MISC_INIT)
	/* miscellaneous arch dependent initialisations */
	arch_misc_init();
#endif
#if defined(CONFIG_MISC_INIT_R)
	/* miscellaneous platform dependent initialisations */
	misc_init_r();
#endif

#ifndef CONFIG_ROCKCHIP
	 /* set up exceptions */
	interrupt_init();
	/* enable exceptions */
	enable_interrupts();
#endif

	/* Initialize from environment */
	load_addr = getenv_ulong("loadaddr", 16, load_addr);

#ifdef CONFIG_BOARD_LATE_INIT
	board_late_init();
#endif

#ifdef CONFIG_BITBANGMII
	bb_miiphy_init();
#endif
#if defined(CONFIG_CMD_NET)
	puts("Net:   ");
	eth_initialize(gd->bd);
#if defined(CONFIG_RESET_PHY_R)
	debug("Reset Ethernet PHY\n");
	reset_phy();
#endif
#endif

#ifdef CONFIG_POST
	post_run(NULL, POST_RAM | post_bootmode_get(0));
#endif

#if defined(CONFIG_PRAM) || defined(CONFIG_LOGBUFFER)
	/*
	 * Export available size of memory for Linux,
	 * taking into account the protected RAM at top of memory
	 */
	{
		ulong pram = 0;
		uchar memsz[32];

#ifdef CONFIG_PRAM
		pram = getenv_ulong("pram", 10, CONFIG_PRAM);
#endif
#ifdef CONFIG_LOGBUFFER
#ifndef CONFIG_ALT_LB_ADDR
		/* Also take the logbuffer into account (pram is in kB) */
		pram += (LOGBUFF_LEN + LOGBUFF_OVERHEAD) / 1024;
#endif
#endif
		sprintf((char *)memsz, "%ldk", (gd->ram_size / 1024) - pram);
		setenv("mem", (char *)memsz);
	}
#endif

	/* main_loop() can return to retry autoboot, if so just run it again. */
	for (;;) {
		main_loop();
	}

	/* NOTREACHED - no way out of command loop except booting */
}

board_init_r函数里调用了board_init和board_late_init函数,其均定义在u-boot/board/rockchip/rk32xx/rk32xx.c文件:

int board_init(void)
{
    /* Set Initial global variables */

    gd->bd->bi_arch_number = MACH_TYPE_RK30XX;
    gd->bd->bi_boot_params = PHYS_SDRAM_1 + 0x88000;

    return 0;
}
int board_late_init(void)
{
    debug("board_late_init\n");
    load_disk_partitions();
    prepare_fdt();
    key_init();
#ifdef CONFIG_POWER_RK
    pmic_init(0);
    fg_init(0); /*fuel gauge init*/
#endif
    SecureBootCheck();

        //TODO:set those buffers in a better way, and use malloc?
    setup_space(gd->arch.rk_extra_buf_addr);

        /* after setup space, get id block data first */
    get_idblk_data();

    if (get_bootloader_ver() == 0) {
        printf("\n#Boot ver: %s\n", bootloader_ver);
    }

    char tmp_buf[30];
    if (getSn(tmp_buf)) {
        tmp_buf[sizeof(tmp_buf)-1] = 0;
        setenv("fbt_sn#", tmp_buf);
    }

#ifdef CONFIG_CMD_FASTBOOT
    fbt_preboot();
#else
    rk_preboot();
#endif
    return 0;
}

可见board_late_init函数里完成开发板按键等功能的初始化,key_init()函数在u-boot/board/rockchip/common/rkloader目录下的key.c文件中实现:

void key_init(void)
{
#if (CONFIG_RKCHIPTYPE == CONFIG_RK3036)
    RockusbKeyInit(&key_rockusb);
    RemotectlInit();
#else
    charge_state_gpio.name = "charge_state";
    charge_state_gpio.flags = 0;
    charge_state_gpio.gpio = ((GPIO_BANK0 << RK_GPIO_BANK_OFFSET) | GPIO_B0);
    gpio_direction_input(charge_state_gpio.gpio);

        //power_hold_gpio.name

    RockusbKeyInit(&key_rockusb);
    FastbootKeyInit(&key_fastboot);
    RecoveryKeyInit(&key_recovery);
    PowerKeyInit();
#endif
}

该文件中还实现按键检测函数checkKey():

int checkKey(uint32* boot_rockusb, uint32* boot_recovery, uint32* boot_fastboot)
{
    *boot_rockusb = 0;
    *boot_recovery = 0;
    *boot_fastboot = 0;

    printf("checkKey\n");

    if(GetPortState(&key_rockusb))
    {
        *boot_rockusb = 1;
        //printf("rockusb key is pressed\n");
    }
    if(GetPortState(&key_recovery))
    {
        *boot_recovery = 1;
        //printf("recovery key is pressed\n");
    }
    if(GetPortState(&key_fastboot))
    {
        *boot_fastboot = 1;
        //printf("fastboot key is pressed\n");
    }

    return 0;
}

系统上电时对于recovery按键的识别就在这个函数中。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!