Uboot2016 for tiny4412调试

来源:互联网 发布:cda数据分析师认证 编辑:程序博客网 时间:2024/06/05 22:08

 前面已经添加了点灯代码了,那就让我们开始调试吧。

 前面添加点灯代码的时候我们就知道,代码是能够成功运行到crt0.S中的_main的,那我们就可以直接从crt0.S中开始分析了。分析前大家可以花点时间看看crt0.S文件最上面的注释,看完应该就对_main所做的事情有所了解了。另外,我们还可以通过指令arm-none-eabi-objdump -S ./spl/u-boot-spl > u-boot-spl.S 将./spl/u-boot-spl这个可执行文件反汇编,这样就可以通过反汇编代码了解uboot真正的执行流程了。

 先看下面的反汇编代码:

02024af0 <_main>: */#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK)    ldr sp, =(CONFIG_SPL_STACK)#else    ldr sp, =(CONFIG_SYS_INIT_SP_ADDR) 2024af0:   e3a0d781    mov sp, #33816576   ; 0x2040000#if defined(CONFIG_CPU_V7M) /* v7M forbids using SP as BIC destination */    mov r3, sp    bic r3, r3, #7    mov sp, r3#else    bic sp, sp, #7  /* 8-byte alignment for ABI compliance */ 2024af4:   e3cdd007    bic sp, sp, #7#endif    mov r0, sp 2024af8:   e1a0000d    mov r0, sp    bl  board_init_f_alloc_reserve 2024afc:   eb000004    bl  2024b14 <board_init_f_alloc_reserve>    mov sp, r0 2024b00:   e1a0d000    mov sp, r0    /* set up gd here, outside any C code */    mov r9, r0 2024b04:   e1a09000    mov r9, r0    bl  board_init_f_init_reserve 2024b08:   eb000004    bl  2024b20 <board_init_f_init_reserve>    mov r0, #0 2024b0c:   e3a00000    mov r0, #0    bl  board_init_f 2024b10:   ebffff5e    bl  2024890 <board_init_f>

可以看到,在_main中,会对全局变量和栈进行初始化,其中 board_init_f_alloc_reserve 和 board_init_f_init_reserve 这两个函数的代码较少,大家看注释也可了解它们具体做了什么事情。接下来我们重点分析board_init_f这个函数。board_init_f在/arch/arm/mach-exynos/spl_boot.c中实现

void board_init_f(unsigned long bootflag){    __aligned(8) gd_t local_gd;    __attribute__((noreturn)) void (*uboot)(void);    setup_global_data(&local_gd);    if (do_lowlevel_init())        power_exit_wakeup();    copy_uboot_to_ram();    /* Jump to U-Boot image */    uboot = (void *)CONFIG_SYS_TEXT_BASE;    (*uboot)();    /* Never returns Here */}

 接下来先分析do_lowlevel_init()实现了什么功能,代码在/arch/arm/mach-exynos/lowlevel_init.c中,在之前,我曾经在board_init_f函数跳转到u-boot前添加过点灯代码,所以先可以确定do_lowlevel_init()中的代码执行是没有问题的,但是之后再细看的时候,发现uart的初始化也是在do_lowlevel_init()完成的,追踪uart初始化的代码过程是:debug_uart_init()–>_debug_uart_init()–>s5p_serial_init(),首先做如下修改:

diff --git a/arch/arm/mach-exynos/lowlevel_init.c b/arch/arm/mach-exynos/lowlevel_init.cindex 1e090fd..1000785 100644--- a/arch/arm/mach-exynos/lowlevel_init.c+++ b/arch/arm/mach-exynos/lowlevel_init.c@@ -218,8 +218,9 @@ int do_lowlevel_init(void) #ifdef CONFIG_DEBUG_UART #if (defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_SERIAL_SUPPORT)) || \     !defined(CONFIG_SPL_BUILD)-               exynos_pinmux_config(PERIPH_ID_UART3, PINMUX_FLAG_NONE);+               exynos_pinmux_config(PERIPH_ID_UART0, PINMUX_FLAG_NONE);                debug_uart_init();+               printascii("UART Init finish!\n"); #endif #endif

如果UART初始化成功,那么调用printascii函数后,就能将需要输出的内容通过串口输出了。但是做了如上修改后,编译烧写运行发现串口并没有任何的输出,表明UART的初始化还是有问题,接着只能看s5p_serial_init()的代码

static void __maybe_unused s5p_serial_init(struct s5p_uart *uart){    /* enable FIFOs, auto clear Rx FIFO */    writel(0x3, &uart->ufcon);    writel(0, &uart->umcon);    /* 8N1 */    writel(0x3, &uart->ulcon);    /* No interrupts, no DMA, pure polling */    writel(0x245, &uart->ucon);}

对照4412的芯片手册看,上面的初始化过程并没有任何问题,但是为什么串口就是没有输出呢?根据以前的经验,串口的初始化还和时钟频率是有关系的,在之前的所有修改中,我们都没有对时钟频率进行初始化,很有可能之前的时钟频率初始化的代码是无效的,开发板就一直以晶振24MHz运行。其实从arch/arm/mach-exynos/clock_init_exynos4.c的system_clock_init()函数看就知道CMU的寄存器设置是有问题的,大家当然可以照着4412的芯片手册修改这个函数里面的值,但是我找到了一个更适合的函数,位于board/samsung/odroid/odroid.c中的board_clock_init()函数,为什么会找到这个函数呢,我是通过exynos4x12_clock这个结构体找到这个时钟初始化函数的,在原来的system_clock_init()函数中使用的是exynos4_clock,明显不能适配所有情况。不过board_clock_init()只是将APLL时钟设置到1GHZ,4412芯片的APLL时钟是可以到达1.4GHz的。不过只要修改个别数值就可以了。
因为这部分内容修改太多,我将代码上传到github了,想了解具体修改了什么内容的朋友可以上去下载,通过git diff来查看前后的修改。

 通过上面的修改,串口就能够运行起来了,也能将信息打印到串口。接下来分析copy_uboot_to_ram()这个函数,这个函数看函数名就知道作用了,这个函数是将u-boot拷贝到DRAM中继续运行的。最主要的是作如下修改:

diff --git a/arch/arm/mach-exynos/spl_boot.c b/arch/arm/mach-exynos/spl_boot.cindex 7df0102..72aae50 100644--- a/arch/arm/mach-exynos/spl_boot.c+++ b/arch/arm/mach-exynos/spl_boot.c@@ -222,9 +222,14 @@ void copy_uboot_to_ram(void)                break; #endif        case BOOT_MODE_SD:+       /*                offset = BL2_START_OFFSET;                size = BL2_SIZE_BLOC_COUNT;                copy_bl2 = get_irom_func(MMC_INDEX);+       */+               offset = UBOOT_START_OFFSET;+               size = UBOOT_SIZE_BLOC_COUNT;+               copy_bl2 = get_irom_func(MMC_INDEX);                break; #ifdef CONFIG_SUPPORT_EMMC_BOOT        case BOOT_MODE_EMMC:@@ -253,9 +258,32 @@ void copy_uboot_to_ram(void)        default:                break;        }-+#ifdef CONFIG_TINY4412        if (copy_bl2)+       {+               unsigned int i , count = 0;+               unsigned char *buffer = (unsigned char *)0x02050000;+               unsigned char *dst = (unsigned char *)CONFIG_SYS_TEXT_BASE;+               unsigned int step = (0x10000 / 512);++               for (count = 0; count < UBOOT_SIZE_BLOC_COUNT; count += step)+               {+                       copy_bl2((u32)(UBOOT_START_OFFSET+count), (u32)step, (u32)buffer);++                       for (i = 0; i < 0x10000; i++)+                       {+                               *dst++ = buffer[i];+                       }+               }+               printascii("copy_uboot_to_ram done! \n");+       }+#else+       if (copy_bl2) {+               printascii("Go to copy_bl2().\n");                copy_bl2(offset, size, CONFIG_SYS_TEXT_BASE);+               printascii("copy_bl2 finish! \n");+       }+#endif } void memzero(void *s, size_t n)

上面的代码的主要作用是通过一个缓存区域,最后将u-boot拷贝到CONFIG_SYS_TEXT_BASE位置,然后跳转到CONFIG_SYS_TEXT_BASE处运行。当然,代码要能够在DRAM中运行的话,DRAM的初始化过程是必须的,本人对DRAM的初始化过程并不是很熟悉,大家有兴趣的可以上网查资料看看,大概修改如下:

diff --git a/arch/arm/mach-exynos/dmc_init_exynos4.c b/arch/arm/mach-exynos/dmc_init_exynos4.cindex 1d3c388..92867b3 100644--- a/arch/arm/mach-exynos/dmc_init_exynos4.c+++ b/arch/arm/mach-exynos/dmc_init_exynos4.c@@ -124,6 +124,10 @@ static void dmc_init(struct exynos4_dmc *dmc)        writel(mem.memconfig0, &dmc->memconfig0);        writel(mem.memconfig1, &dmc->memconfig1);+#ifdef CONFIG_TINY4412+       writel(0x8000001F, &dmc->ivcontrol);+#endif+        /* Config Precharge Policy */        writel(mem.prechconfig, &dmc->prechconfig);        /*@@ -175,7 +179,8 @@ void mem_ctrl_init(int reset)         * 0: full_sync         */        writel(1, ASYNC_CONFIG);-#if (defined CONFIG_ORIGEN) || (defined CONFIG_TINY4412)+#ifndef CONFIG_TINY4412+#ifdef CONFIG_ORIGEN        /* Interleave: 2Bit, Interleave_bit1: 0x15, Interleave_bit0: 0x7 */        writel(APB_SFR_INTERLEAVE_CONF_VAL, EXYNOS4_MIU_BASE +                APB_SFR_INTERLEAVE_CONF_OFFSET);@@ -204,6 +209,7 @@ void mem_ctrl_init(int reset)                ABP_SFR_SLV_ADDRMAP_CONF_OFFSET); #endif #endif+#endif        /* DREX0 */        dmc = (struct exynos4_dmc *)samsung_get_base_dmc_ctrl();        dmc_init(dmc);

最后还有一点就是,SD卡的布局情况,SD卡的布局情况和之前文章中提到的布局有部分不同,主要是在BL2区域后还有一片区域是用于保存一些环境变量信息的,所以还需要做如下修改:

diff --git a/include/configs/tiny4412.h b/include/configs/tiny4412.hindex 2c2b5b7..3c2bba9 100644--- a/include/configs/tiny4412.h+++ b/include/configs/tiny4412.h@@ -112,8 +112,9 @@ #define CONFIG_SYS_MMC_ENV_DEV         0 #define CONFIG_ENV_SIZE                        (16 << 10)      /* 16 KB */ #define RESERVE_BLOCK_SIZE             (512)-#define BL1_SIZE                       (16 << 10) /*16 K reserved for BL1*/-#define CONFIG_ENV_OFFSET              (RESERVE_BLOCK_SIZE + BL1_SIZE)+#define BL1_SIZE                       (8 << 10) /*8 K reserved for BL1*/+#define BL2_SIZE            (16<< 10) /*16 K reserved for BL2 */+#define CONFIG_ENV_OFFSET              (RESERVE_BLOCK_SIZE + BL1_SIZE + BL2_SIZE) #define CONFIG_SPL_LDSCRIPT    "board/samsung/common/exynos-uboot-spl.lds" #define CONFIG_SPL_MAX_FOOTPRINT       (14 * 1024)

到这里,我们就可以编译运行了,连接串口可以看到开发板已经运行到新的位置了
这里写图片描述
从截图中可以看到,开发板卡在DRAM的大小识别部分了,显然还有部分内容没有修改,导致开发板对DRAM的大小识别有误,不过要想让其运行起来,可以先做如下修改,将tiny4412.h文件中:

#define CONFIG_NR_DRAM_BANKS        4

修改为

#define CONFIG_NR_DRAM_BANKS        2

开发板就可以正常执行了,只是识别的DRAM大小有误,在下一篇文章中会继续修改分析,这篇就先到这里了!
代码可以通过如下指令下载:
git clone https://github.com/xiaojimmychen/u-boot.git

Thanks!

0 0
原创粉丝点击