mini2440移植uboot 2014.04(一)

时间:2023-03-09 09:08:46
mini2440移植uboot 2014.04(一)

最新版的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页,中断相关寄存器地址如下:

mini2440移植uboot 2014.04(一)
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
mini2440移植uboot 2014.04(一)

我们需要配置中断屏蔽寄存器(INTMSK,见手册388-389页)和子中断屏蔽寄存器(INTSUBMSK,见手册395页),可以看到当前代码如下:

mini2440移植uboot 2014.04(一)
#  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
mini2440移植uboot 2014.04(一)

该代码中断屏蔽寄存器的代码仍然使用于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相关寄存器信息:

mini2440移植uboot 2014.04(一)
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
mini2440移植uboot 2014.04(一)

此处MPLL和UPLL分别用于系统时钟和USB时钟,我们将MPLL输出设定成405MHz, UPLL输出设定成48MHz.

手册255页中还提到,当写入UPLL和MPLL时,需要先写UPLL后写MPLL。

我修改后的代码内容如下:

mini2440移植uboot 2014.04(一)
#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-

会出来很多编译错误:

mini2440移植uboot 2014.04(一)
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] 错误
mini2440移植uboot 2014.04(一)

查看代码可以知道是因为从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中存在问题,接下来解决这个问题。