最新版的uboot添加了很多新功能,我决定在最新版代码基础上重新移植一遍加深理解。

我修改的代码已经上传到github上,地址:https://github.com/qiaoyuguo/u-boot-2014.04-mini2440.git

参考文档: s3c2440手册(下载地址) mini2440电路图(下载地址

参考我的两篇博文:

mini2440移植uboot 2011.03(上)

mini2440移植uboot 2011.03(下)

还有其他几篇文章:

u-boot2012.04.01移植到mini2440

一步一步将uboot移植到mini2440(-)

DM9000驱动在MINI2440上的移植学习笔记

操作系统: debian 7.4

uboot:   u-boot-2014.04(下载地址

交叉编译器:arm-linux-gcc 4.4.3(下载地址

在移植之前,最好对uboot的代码执行流程有基本的了解,可以参考我的三篇博文:

uboot 2013.01 代码简析(1)开发板配置

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表示该中断可用).

接着是时钟分频配置,现有代码如下:

#  define CLKDIVN   0x4C000014  /* clock divisor register */
    /* FCLK:HCLK:PCLK = 1:2:4 */
/* default FCLK is 120 MHz ! */
ldr r0, =CLKDIVN
mov r1, #
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 [:] Main divider control 
PDIV [:] Pre-divider control
SDIV [:] 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, #
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 #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 #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:: warning: implicit declaration of function 's3c2410_get_base_nand'
drivers/mtd/nand/s3c2410_nand.c:: warning: initialization makes pointer from integer without a cast
drivers/mtd/nand/s3c2410_nand.c:: error: dereferencing pointer to incomplete type
drivers/mtd/nand/s3c2410_nand.c:: error: dereferencing pointer to incomplete type
drivers/mtd/nand/s3c2410_nand.c:: error: dereferencing pointer to incomplete type
drivers/mtd/nand/s3c2410_nand.c:: error: dereferencing pointer to incomplete type
drivers/mtd/nand/s3c2410_nand.c: In function 's3c2410_dev_ready':
drivers/mtd/nand/s3c2410_nand.c:: warning: initialization makes pointer from integer without a cast
drivers/mtd/nand/s3c2410_nand.c:: error: dereferencing pointer to incomplete type
drivers/mtd/nand/s3c2410_nand.c: In function 'board_nand_init':
drivers/mtd/nand/s3c2410_nand.c:: warning: initialization makes pointer from integer without a cast
drivers/mtd/nand/s3c2410_nand.c:: error: dereferencing pointer to incomplete type
drivers/mtd/nand/s3c2410_nand.c:: error: dereferencing pointer to incomplete type
drivers/mtd/nand/s3c2410_nand.c:: error: dereferencing pointer to incomplete type
make[]: *** [drivers/mtd/nand/s3c2410_nand.o] 错误

查看代码可以知道是因为从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
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   - ::)

CPUID:
FCLK: MHz
HCLK: 101.250 MHz
PCLK: 50.625 MHz
DRAM: 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   - ::)

U-Boot code: 33F80000 -> 33FF9F84  BSS: -> 340489D0
CPUID:
FCLK: MHz
HCLK: 101.250 MHz
PCLK: 50.625 MHz
monitor len: 000C89D0
ramsize:
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 Bytes for Board Info at: 33b16fe0
Reserving Bytes for Global Data at: 33b16f40
New Stack Pointer is: 33b16f30
RAM Configuration:
Bank #: 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   - ::)

U-Boot code: 33F80000 -> 33FF9FB4  BSS: -> 340489D0
CPUID:
FCLK: MHz
HCLK: 101.250 MHz
PCLK: 50.625 MHz
monitor len: 000C89D0
ramsize:
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 Bytes for Board Info at: 33b16fe0
Reserving Bytes for Global Data at: 33b16f40
New Stack Pointer is: 33b16f30
RAM Configuration:
Bank #: 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   - ::)

U-Boot code: 33F00000 -> 33F79FB4  BSS: -> 33FC89D0
CPUID:
FCLK: MHz
HCLK: 101.250 MHz
PCLK: 50.625 MHz
monitor len: 000C89D0
ramsize:
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 Bytes for Board Info at: 33b16fe0
Reserving Bytes for Global Data at: 33b16f40
New Stack Pointer is: 33b16f30
RAM Configuration:
Bank #: MiB
addr=33f27000,_start=33f00000
relocation Offset is:

虽然没有溢出,但是仍然是停留在这个位置不继续执行了。

我将CONFIG_SYS_TEXT_BASE改成了0x33e80000,然后重新编译并加载到mini2440内存中(命令中的地址也相应修改为0x33e80000),得到下面的输出:

U-Boot 2014.04-g0e7a234-dirty (Jun   - ::)

U-Boot code: 33E80000 -> 33EF9FA8  BSS: -> 33F489D0
CPUID:
FCLK: MHz
HCLK: 101.250 MHz
PCLK: 50.625 MHz
monitor len: 000C89D0
ramsize:
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 Bytes for Board Info at: 33b16fe0
Reserving Bytes for Global Data at: 33b16f40
New Stack Pointer is: 33b16f30
RAM Configuration:
Bank #: 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 cmd f0 00f0 16bit x bit
fwc addr 0000aaaa cmd aa 00aa 16bit x bit
fwc addr cmd 16bit x bit
fwc addr 0000aaaa cmd 16bit x bit
fwc addr cmd f0 00f0 16bit x bit
JEDEC PROBE: ID f0 ea00
fwc addr cmd ff 00ff 16bit x bit
fwc addr cmd 16bit x bit
fwc addr cmd ff 00ff 16bit x bit
JEDEC PROBE: ID ea00
*** failed ***
### ERROR ### Please RESET the board ###

从输出信息上看sdram已经通过了,但是flash中存在问题,接下来解决这个问题。

最新文章

  1. .NET Core 1.1 发布 文档下载资源汇总
  2. Android项目实战(九):CustomShapeImageView 自定义形状的ImageView
  3. Selenium2Library系列 keywords 之 _SelectElementKeywords 之 select_from_list(self, locator, *items)
  4. Hadoop 的部署适用性(网上资料http://www.linuxidc.com/Linux/2013-10/92141.htm)
  5. 什么是Hadoop,怎样学习Hadoop
  6. mysqldump造成Buffer Pool污染的研究
  7. linux问题: 切换用户之后变成-bash-4.1$
  8. wp8数据存储--独立存储文件 【转】
  9. 手动安装Nginx
  10. Docker入门(三)使用Docker Compose
  11. Kivy折腾笔记
  12. C#对接JAVA系统遇到的AES加密坑
  13. 浅谈MySQL引擎(纯个人理解,如有错误请指正)
  14. Codeforces 786 B. Legacy
  15. 适合新手小白的UI学习路线完整版
  16. Android之Android apk动态加载机制的研究
  17. MFC 常见问题
  18. call()、apply()和bind()的异同
  19. 如何设置datatable的宽度
  20. 批量删除Redis数据库中的Key

热门文章

  1. Docker Push 镜像到公共仓库
  2. 浅谈EntityFramework框架的使用
  3. 从两张Excel表所想到的
  4. 用yum源安装nginx(转)
  5. 使用nginx搭建https服务器(转)
  6. mysql中把字符串转成时间戳进行对比
  7. Android实现夜间模式小结
  8. MySQL四-2:完整性约束
  9. 《TomCat与Java Web开发技术详解》(第二版) 第四章节的学习总结--常用Servlet API
  10. EJB是什么?(节选)