Uboot2016 for tiny4412调试

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

 前面添加点灯代码的时候我们就知道,代码是能够成功运行到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 
    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 
    mov r0, #0
 2024b0c:   e3a00000    mov r0, #0
    bl  board_init_f
 2024b10:   ebffff5e    bl  2024890 

可以看到,在_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.c
index 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.c
index 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.c
index 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.h
index 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)

到这里,我们就可以编译运行了,连接串口可以看到开发板已经运行到新的位置了
Uboot2016 for tiny4412调试_第1张图片
从截图中可以看到,开发板卡在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!

你可能感兴趣的:(u-boot,for,tiny4412)