mini2440移植uboot 2014.04(一)
最新版的uboot添加了很多新功能,我决定在最新版代码基础上重新移植一遍加深理解。
我修改的代码已经上传到github上,地址:https://github.com/qiaoyuguo/u-boot-2014.04-mini2440.git
参考文档: s3c2440手册(下载地址) mini2440电路图(下载地址)
参考我的两篇博文:
还有其他几篇文章:
《u-boot2012.04.01移植到mini2440 》
操作系统: debian 7.4
uboot: u-boot-2014.04(下载地址)
交叉编译器:arm-linux-gcc 4.4.3(下载地址)
在移植之前,最好对uboot的代码执行流程有基本的了解,可以参考我的三篇博文:
《uboot 2013.01 代码简析(2)第一阶段初始化》
《uboot 2013.01 代码简析(3)第二阶段初始化》
(一)将smdk2410的文件夹拷贝成mini2440,步骤如下:
host@debian:~/soft/mini2440/u-boot-2014.04$ vim boards.cfg 添加一行: Active arm arm920t s3c24x0 friendlyarm - mini2440 - Qiao<qiaoyuguo2012@gmail.com>
host@debian:~/soft/mini2440/u-boot-2014.04$ mkdir board/friendlyarm
host@debian:~/soft/mini2440/u-boot-2014.04$ cp -r board/samsung/smdk2410/ board/friendlyarm/mini2440
host@debian:~/soft/mini2440/u-boot-2014.04$ mv board/friendlyarm/mini2440/smdk2410.c board/friendlyarm/mini2440/mini2440.c
host@debian:~/soft/mini2440/u-boot-2014.04$ vim board/friendlyarm/mini2440/Makefile
将其中smdk2410.o替换成mini2440.o
host@debian:~/soft/mini2440/u-boot-2014.04$ cp include/configs/smdk2410.h include/configs/mini2440.h
然后进行编译:
host@debian:~/soft/mini2440/u-boot-2014.04$ make mini2440_config host@debian:~/soft/mini2440/u-boot-2014.04$ make CROSS_COMPILE=arm-linux-
编译过程中最后部分的输出信息:
OBJCOPY u-boot.srec
OBJCOPY u-boot.bin
(二)添加SDRAM支持
host@debian:~/soft/mini2440/u-boot-2014.04$ vim include/configs/mini2440.h 删除三行: #define CONFIG_S3C2410 /* specifically a SAMSUNG S3C2410 SoC */ #define CONFIG_SMDK2410 /* on a SAMSUNG SMDK2410 Board */
#define CONFIG_SYS_TEXT_BASE 0x0
添加四行: #define CONFIG_S3C2440 /* specifically a SAMSUNG S3C2440 SoC */ #define CONFIG_MINI2440 /* on a FriendlyArm MINI2440 Board */ #define CONFIG_SKIP_LOWLEVEL_INIT
#define CONFIG_SYS_TEXT_BASE 0x33f80000
arch/arm/cpu/arm920t/start.S中的包含有看门狗、中断以及时钟的配置,而s3c2410和s3c2440的部分配置不一样,所以需要适当的进行修改
首先需要禁止看门狗,根据s3c2440芯片手册(下载地址) ,看门狗寄存器地址如下:
WTCON 0x53000000 Watchdog timer control
WTDAT 0x53000004 Watchdog timer data WTCNT 0x53000008 Watchdog timer count
我们只需要禁止看门狗,这样就只需要考虑WTCON寄存器就可以,从手册的462页中可以看到WTCON详细信息
当前的uboot代码已经满足了禁止看门狗的功能,其代码如下(忽略无关的宏定义,仅列出我们所关心的代码,下同):
define pWTCON 0x53000000 ldr r0, =pWTCON mov r1, #0x0 str r1, [r0]
这段代码将0加载到0x53000000处,从而禁止了看门狗(详细每位数据的含义可以查看手册)。
接着是关于中断的配置,根据s3c2440芯片手册56页,中断相关寄存器地址如下:
SRCPND 0X4A000000 R/W Interrupt request status INTMOD 0X4A000004 W Interrupt mode control INTMSK 0X4A000008 R/W Interrupt mask control PRIORITY 0X4A00000C W IRQ priority control
INTPND 0X4A000010 R/W Interrupt request status
INTOFFSET 0X4A000014 R Interrupt request source offset
SUBSRCPND 0X4A000018 R/W Sub source pending INTSUBMSK 0X4A00001C R/W Interrupt sub mask
我们需要配置中断屏蔽寄存器(INTMSK,见手册388-389页)和子中断屏蔽寄存器(INTSUBMSK,见手册395页),可以看到当前代码如下:
# define INTMSK 0x4A000008 /* Interrupt-Controller base addresses */
# define INTSUBMSK 0x4A00001C
mov r1, #0xffffffff
ldr r0, =INTMSK
str r1, [r0]
# if defined(CONFIG_S3C2410)
ldr r1, =0x3ff ldr r0, =INTSUBMSK str r1, [r0] # endif
该代码中断屏蔽寄存器的代码仍然使用于s3c2440,但是需要添加子中断屏蔽寄存器的代码,可以在s3c2410相关代码中添加elseif语句:
#elseif defined(CONFIG_S3C2440) ldr r1, =0x7fff ldr r0, =INTSUBMSK str r1, [r0]
根据手册,s3c2440中子中断屏蔽寄存器有效位数是低15位,所以我们用0x7fff,使得低15位为1(1表示屏蔽该中断,0表示该中断可用).
接着是时钟分频配置,现有代码如下:
/* FCLK:HCLK:PCLK = 1:2:4 */ /* default FCLK is 120 MHz ! */ ldr r0, =CLKDIVN mov r1, #3 str r1, [r0]
上面代码中提到了FCLK、HCLK、PCLK(参见手册242页),FCLK用于arm920T,HCLK用于AHB,可以用于USB、DMA、LCD、中断和内存控制器等。
PCLK用于APB,可以用于看门狗、IIS、I2C、SPI、ADC、UART、GPIO、RTC等。
当前代码默认采用1:2:4的分频配置,但是mini2440我们要将cpu频率配置成400MHz。
根据手册33页,FCLK最大只能是400MHz,HCLK最大只能是136MHz,PCLK最大只能是68MHz。
要满足时钟频率的限制,可以将分频配置成1:4:8,那么FCLK=400MHz,HCLK等于100MHz,PCLK等于50MHz,都能满足要求。
关于CLKDIVN寄存器的定义,可以查看手册258页,给出了下面的信息:
CLKDIVN 0x4C000014 R/W Clock divider control register
HDIVN [2:1] 10 : HCLK = FCLK/4 when CAMDIVN[9] = 0,HCLK= FCLK/8 when CAMDIVN[9] = 1.
PDIVN [0] 如果为0: PCLK has the clock same as the HCLK/1 如果为1: PCLK has the clock same as the HCLK/2.
而CAMDIVN寄存器定义可以查看手册259页,能看到默认所有位等于0,这样只需要配置HDIVN为10,PDIVN为1既可。CLKDIVN的值应该是0x101=5
手册243页中提到如果HDIVN不是0,那么需要将cpu总线模式从"fast bus mode"改成“asynchronous bus mode"
然后需要对PLL进行配置,才能得到405MHz的输出频率,根据手册255页,可以得到PLL相关寄存器信息:
MPLLCON 0x4C000004 R/W MPLL configuration register 0x00096030 UPLLCON 0x4C000008 R/W UPLL configuration register 0x0004d030 PLLCON Bit Description MDIV [19:12] Main divider control PDIV [9:4] Pre-divider control
SDIV [1:0] Post divider control
input freq output freq MDIV PDIV SDIV
12.0000MHz 48.00 MHz 56(0x38) 2 2
12.0000MHz 405.00 MHz 127(0x7f) 2 1
此处MPLL和UPLL分别用于系统时钟和USB时钟,我们将MPLL输出设定成405MHz, UPLL输出设定成48MHz.
手册255页中还提到,当写入UPLL和MPLL时,需要先写UPLL后写MPLL。
我修改后的代码内容如下:
#if defined(CONFIG_S3C2440) /* FCLK:HCLK:PCLK = 1:4:8 */ ldr r0, =CLKDIVN mov r1, #5 str r1, [r0] /* change bus mode from "fast bus mode" to "asynchronous bus mode" */ mrc p15, 0, r1, c1, c0, 0 /*read ctrl regester*/ orr r1, r1, #0xc0000000 /*asynchronous*/ mcr p15, 0, r1, c1, c0, 0 /*write ctrl register*/ #define S3C2440_MPLL_400MHZ (0x7f<<12 | 0x2<<4 | 0x1) /* refer to s3c2440.pdf page 255 */ #define S3C2440_UPLL_48MHZ (0x38<<12 | 0x2<<4 | 0x2) #define MPLLCON 0x4c000004 #define UPLLCON 0x4c000008 ldr r0, =UPLLCON ldr r1, =S3C2440_UPLL_48MHZ str r1, [r0] ldr r0, =MPLLCON ldr r1, =S3C2440_MPLL_400MHZ str r1, [r0] #else /* FCLK:HCLK:PCLK = 1:2:4 */ /* default FCLK is 120 MHz ! */ ldr r0, =CLKDIVN mov r1, #3 str r1, [r0] #endif
如果没有定义CONFIG_SKIP_LOWLEVEL_INIT, 在执行完这部分代码后会跳转到start.S中的cpu_init_crit,
然后又跳转到board/friendlyarm/mini2440/lowlevel_init.S中的lowlevel_init函数,该函数中包含对sdram连接的BANK0-BANk7
以及SDRAM刷新频率进行配置(可以参考2440手册203-210页)。
但是我们当前代码中定义了CONFIG_SKIP_LOWLEVEL_INIT,所以cpu_init_crit不会执行,暂时也不需要考虑这部分代码。
接着调用_main,_main位于arch/arm/lib/crt0.S文件中,它会依次调用board_init_f和relocate_code.
在relocate_code中执行重定位代码,然后会根据其lr寄存器中的here地址跳转回arch/arm/lib/crt0.S,执行here标签下的内容(主要是board_init_r函数).
修改mini2440.c中的时钟频率,跟上面的汇编代码保持一致:
host@debian:~/soft/mini2440/u-boot-2014.04$ vim board/friendlyarm/mini2440/mini2440.c
host@debian:~/soft/mini2440/u-boot-2011.03$ vim board/friendlyarm/mini2440/mini2440.c
#define FCLK_SPEED 2
#elif FCLK_SPEED==1 /* Fout = 202.8MHz */
#define M_MDIV 0xA1
#define M_PDIV 0x3
#define M_SDIV 0x1
#elif FCLK_SPEED==2 /* Fout = 405MHz */
#define M_MDIV 0x7F
#define M_PDIV 0x2
#define M_SDIV 0x1
#endif
#define USB_CLOCK 2
#elif USB_CLOCK==1
#define U_M_MDIV 0x48
#define U_M_PDIV 0x3
#define U_M_SDIV 0x2
#elif USB_CLOCK==2 /* Fout = 48MHz */
#define U_M_MDIV 0x38
#define U_M_PDIV 0x2
#define U_M_SDIV 0x2
#endif
int board_init (void)
{
......
gd->bd->bi_arch_number = MACH_TYPE_MINI2440;
......
}
此时,执行编译命令:
make CROSS_COMPILE=arm-linux-
会出来很多编译错误:
drivers/mtd/nand/s3c2410_nand.c: In function 's3c2410_hwcontrol': drivers/mtd/nand/s3c2410_nand.c:44: warning: implicit declaration of function 's3c2410_get_base_nand' drivers/mtd/nand/s3c2410_nand.c:44: warning: initialization makes pointer from integer without a cast drivers/mtd/nand/s3c2410_nand.c:59: error: dereferencing pointer to incomplete type drivers/mtd/nand/s3c2410_nand.c:59: error: dereferencing pointer to incomplete type drivers/mtd/nand/s3c2410_nand.c:62: error: dereferencing pointer to incomplete type drivers/mtd/nand/s3c2410_nand.c:62: error: dereferencing pointer to incomplete type drivers/mtd/nand/s3c2410_nand.c: In function 's3c2410_dev_ready': drivers/mtd/nand/s3c2410_nand.c:72: warning: initialization makes pointer from integer without a cast drivers/mtd/nand/s3c2410_nand.c:74: error: dereferencing pointer to incomplete type drivers/mtd/nand/s3c2410_nand.c: In function 'board_nand_init': drivers/mtd/nand/s3c2410_nand.c:116: warning: initialization makes pointer from integer without a cast drivers/mtd/nand/s3c2410_nand.c:137: error: dereferencing pointer to incomplete type drivers/mtd/nand/s3c2410_nand.c:140: error: dereferencing pointer to incomplete type drivers/mtd/nand/s3c2410_nand.c:141: error: dereferencing pointer to incomplete type make[1]: *** [drivers/mtd/nand/s3c2410_nand.o] 错误 1
查看代码可以知道是因为从board_init_r->nand_init经过一长串的调用后调用s3c2410_hwcontrol。
当前代码中在include/configs/mini2440.h中定义了CONFIG_NAND_S3C2410,所以使用了drivers/mtd/nand/s3c2410_nand.c中的代码。
上面的错误是因为未定义s3c2410_get_base_nand引起的,而该函数定义位于arch/arm/include/asm/arch-s3c24x0/s3c2410.h中,
在arch/arm/include/asm/arch-s3c24x0/s3c24x0_cpu.h中有下面内容:
#elif defined CONFIG_S3C2440
#include <asm/arch/s3c2440.h>
实际上当前代码中包含的文件是arch/arm/include/asm/s3c24x0/s3c2440.h,该头文件中没有 s3c2410_get_base_nand函数的定义,由于s3c2410.h和s3c2440.h中代码基本一致,直接包含将代码中 s3c2440.h修改成s3c2410.h即可。
另外几个错误是因为s3c2410_nand未定义引起的,可以在arch/arm/include/asm/arch-s3c24x0/s3c24x0.h中将s3c2440_nand修改成s3c2410_nand即可。
然后重新编译:
make CROSS_COMPILE=arm-linux-
参考《openocd+jlink为mini2440调试u-boot》配置好openocd,然后打开串口:
sudo minicom
在另一个控制台执行下面命令:
sudo openocd -f interface/jlink.cfg -f board/mini2440.cfg
telnet localhost 4444 halt init_2440 load_image /home/host/soft/mini2440/u-boot-2014.04/u-boot.bin 0x33f80000 bin resume 0x33f80000
其中/home/host/soft/mini2440/u-boot-2014.04/u-boot.bin是我的uboot存放路径,根据自己的需要改成自己电脑上的路径即可。
得到下面的输出信息:
U-Boot 2014.04-gf5f2cb1-dirty (Jun 04 2014 - 13:55:36) CPUID: 32440001 FCLK: 405 MHz HCLK: 101.250 MHz PCLK: 50.625 MHz DRAM: 64 MiB
之后没有进入uboot命令行就重启cpu了。
虽然这里能检测到DRAM,这也说明了DRAM的配置是基本上正确的。从s3c2440手册194页和mini2440原理图第5页可以看到DRAM连接nGCS6,
所以其对应基地址是0x30000000,与include/configs/mini2440.h中的PHYS_SDRAM_1的值一模一样。
(三)调试bug(未进入uboot重启cpu)
在include/configs/mini2440.h中添加一行:
#define DEBUG
然后按照上面的步骤将进行编译并将生成u-boot.bin加载到mini2440,从控制台可以得到输出:
U-Boot 2014.04-g0e7a234-dirty (Jun 04 2014 - 14:22:23) U-Boot code: 33F80000 -> 33FF9F84 BSS: -> 340489D0 CPUID: 32440001 FCLK: 405 MHz HCLK: 101.250 MHz PCLK: 50.625 MHz monitor len: 000C89D0 ramsize: 04000000 TLB table from 33ff0000 to 33ff4000 Top of RAM usable for U-Boot at: 33ff0000 Reserving 802k for U-Boot at: 33f27000 Reserving 4160k for malloc() at: 33b17000 Reserving 32 Bytes for Board Info at: 33b16fe0 Reserving 160 Bytes for Global Data at: 33b16f40 New Stack Pointer is: 33b16f30 RAM Configuration: Bank #0: 30000000 64 MiB relocation Offset is: fffa7000
然后就冻结在这个地方,不再有任何输出。
我在board_init_f函数中debug("relocation Offset is: %08lx\n", gd->reloc_off)之前添加了一行代码:
debug("addr=%08lx,_start=%08lx\n", addr,(ulong)&_start);
重新编译加载到mini2440后得到的输出信息如下:
U-Boot 2014.04-g0e7a234-dirty (Jun 04 2014 - 14:35:37) U-Boot code: 33F80000 -> 33FF9FB4 BSS: -> 340489D0 CPUID: 32440001 FCLK: 405 MHz HCLK: 101.250 MHz PCLK: 50.625 MHz monitor len: 000C89D0 ramsize: 04000000 TLB table from 33ff0000 to 33ff4000 Top of RAM usable for U-Boot at: 33ff0000 Reserving 802k for U-Boot at: 33f27000 Reserving 4160k for malloc() at: 33b17000 Reserving 32 Bytes for Board Info at: 33b16fe0 Reserving 160 Bytes for Global Data at: 33b16f40 New Stack Pointer is: 33b16f30 RAM Configuration: Bank #0: 30000000 64 MiB addr=33f27000,_start=33f80000 relocation Offset is: fffa7000
从调试信息可以看出addr < _start,但是gd_reloc_off=addr-(ulong)&_start,明显得到的结果溢出了。
这是因为我们配置的CONFIG_SYS_TEXT_BASE的问题,将其值修改成0x33F00000。
然后重新编译加载到mini2440(但命令中的0x33f80000都要替换成0x33f00000),得到下面的输出:
U-Boot 2014.04-g0e7a234-dirty (Jun 04 2014 - 14:48:22) U-Boot code: 33F00000 -> 33F79FB4 BSS: -> 33FC89D0 CPUID: 32440001 FCLK: 405 MHz HCLK: 101.250 MHz PCLK: 50.625 MHz monitor len: 000C89D0 ramsize: 04000000 TLB table from 33ff0000 to 33ff4000 Top of RAM usable for U-Boot at: 33ff0000 Reserving 802k for U-Boot at: 33f27000 Reserving 4160k for malloc() at: 33b17000 Reserving 32 Bytes for Board Info at: 33b16fe0 Reserving 160 Bytes for Global Data at: 33b16f40 New Stack Pointer is: 33b16f30 RAM Configuration: Bank #0: 30000000 64 MiB addr=33f27000,_start=33f00000 relocation Offset is: 00027000
虽然没有溢出,但是仍然是停留在这个位置不继续执行了。
我将CONFIG_SYS_TEXT_BASE改成了0x33e80000,然后重新编译并加载到mini2440内存中(命令中的地址也相应修改为0x33e80000),得到下面的输出:
U-Boot 2014.04-g0e7a234-dirty (Jun 04 2014 - 15:25:46) U-Boot code: 33E80000 -> 33EF9FA8 BSS: -> 33F489D0 CPUID: 32440001 FCLK: 405 MHz HCLK: 101.250 MHz PCLK: 50.625 MHz monitor len: 000C89D0 ramsize: 04000000 TLB table from 33ff0000 to 33ff4000 Top of RAM usable for U-Boot at: 33ff0000 Reserving 802k for U-Boot at: 33f27000 Reserving 4160k for malloc() at: 33b17000 Reserving 32 Bytes for Board Info at: 33b16fe0 Reserving 160 Bytes for Global Data at: 33b16f40 New Stack Pointer is: 33b16f30 RAM Configuration: Bank #0: 30000000 64 MiB addr=33f27000,_start=33e80000 relocation Offset is: 000a7000 WARNING: Caches not enabled monitor flash len: 000847B0 Now running in RAM - U-Boot at: 33f27000 Flash: fwc addr 00000000 cmd f0 00f0 16bit x 16 bit fwc addr 0000aaaa cmd aa 00aa 16bit x 16 bit fwc addr 00005554 cmd 55 0055 16bit x 16 bit fwc addr 0000aaaa cmd 90 0090 16bit x 16 bit fwc addr 00000000 cmd f0 00f0 16bit x 16 bit JEDEC PROBE: ID f0 ea00 0 fwc addr 00000000 cmd ff 00ff 16bit x 16 bit fwc addr 00000000 cmd 90 0090 16bit x 16 bit fwc addr 00000000 cmd ff 00ff 16bit x 16 bit JEDEC PROBE: ID 90 ea00 0 *** failed *** ### ERROR ### Please RESET the board ###
从输出信息上看sdram已经通过了,但是flash中存在问题,接下来解决这个问题。
posted on 2014-06-04 15:44 qiaoqiao2003 阅读(6049) 评论(4) 编辑 收藏 举报