[无中生有]移植u-boot(2020.7)至 JZ2440

目录

  • 2016.11 的移植
    • 1. 准备工作
      • 1.1下载
      • 1.2 尝试编译
      • 1.3 建立工程
    • 2. 分析
      • 2.1 分析start.S 过程
      • 2.2 分析小结
      • 2.2 分析crt0.S
    • 3. 动手
    • patch
  • 2020.4 的移植

本文是基于韦东山视频的学习笔记

汇总点这

前言 本篇是记录移植u-boot (2020.7)的过程和思路,其实有不少好文章已经在描述移植u-boot到JZ2440了,写的又比我好,比如我收藏参考的文章移植u-boot-2019.10到jz2440。

但是本文想尽可能修改更少的代码,保留更多官方的代码,能用既用,至于像更细节的怎样重定位才能更好地支持JZ2440,那应该会留到另一篇进阶的文章。

2016.11 的移植

1. 准备工作

u-boot是什么就不废话了,开干吧。

1.1下载

百度u-boot,去官网,点源码,去FTP服务器直接去下载最新的就好。其实移植的时候最好找个相似的单板进行移植,不然得全部重新写。但是下载后才发现,最新2020.7版本的uboot已经不支持相似单板smdk2410了。

愤怒的我把历史所有版本下载下来,发现最后的支持在2016.11版本,那我们就先移植到这个版本,再移植到2020.7。

新u-boot 配新编译工具,其实直接 apt 下载的arm-linux-gnueabi-gcc 就能完美编译 2016.11 u-boot(ubuntu16)。

使用命令 sudo apt-get install gcc-arm-linux-gnueabi ,成功安装后使用arm-linux-gnueabi-gcc -v 显示

gcc version 5.4.0 20160609 (Ubuntu/Linaro 5.4.0-6ubuntu1~16.04.9)

就对了,工具刚好也是2016年的,这里也是用这个版本。

1.2 尝试编译

使用命令 make smdk2410_config 进行配置,命令成功后会生产 .config 文件,这个文件就是配置文件。

要用自己的交叉编译工具编译,使用命令 make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- 或者直接去Makefile改也行,这里是使用命令 进行编译,命令不能打错,打错命令会使用默认配置gcc

连一个警告都没有,完美编译。

看到编译完成,我啪的一下就烧进去了,很快啊!开发板没有任何反应,我大意了,没有改,板子没有正常启动。什么都没改当然不兼容了,这就烧进去了,这好吗?这不好。

1.3 建立工程

接下来需要建立一个source insight工程,方便我们移植。因为u-boot也兼容其他的板子,为了避免杂乱,我们只加入自己的板子的信息。

  • arch 目录只加 arm -> cpu ->arm920t -> 该目录下的文件 和 s3c24x0
  • arch -> arm -> include 目录只加 asm -> 该目录下的文件 和 arch-s3c24x0目录
  • arch -> arm -> lib 全加
  • board 目录只加 里面的 board -> Samsung -> smdk2410目录
  • include -> configs 里面的 只加 smdk2410.h 文件

其他全加

2. 分析

首先系统烧进去没有任何反应,就是板子没有正常启动,正常启动后应该会有串口输出,串口输出的前提是串口初始化了,板子cpu初始化了(包括时钟),保证代码运行了(重定位、内存初始化)。那么最实在的方法就是从头看看有什么问题。

那么分析源码首先得找到程序入口,就需要从链接文件入手。链接文件是编译过程中产生的,编译后根目录下会出现一个u-boot.lds的文件,这就是链接文件。

OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
 . = 0x00000000;
 . = ALIGN(4);
 .text :
 {
  *(.__image_copy_start)
  *(.vectors)
  arch/arm/cpu/arm920t/start.o (.text*)
  *(.text*)
 }
 . = ALIGN(4);
 .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 . = ALIGN(4);
 .data : {
  *(.data*)
 }
 . = ALIGN(4);
 . = .;
 . = ALIGN(4);
 .u_boot_list : {
  KEEP(*(SORT(.u_boot_list*)));
 }
 . = ALIGN(4);

...此处省略下文

.代表此处,可以看到一开始程序就在 0 地址运行,这么说应该就只能nor flash启动了。然后u-boot分为几个段:text, rodata, data, u_boot_list

text就是程序段,搜索 __image_copy_start 发现,其是这都只是数组,那么真正的代码从 start.S 开始。

这个 start.S...\arch\arm\cpu\arm920t 目录下,事实上u-boot中有很多start.S,第二步建立工程就是分开这些文件,我们用的是arm920t专属的start.S。

2.1 分析start.S 过程

reset开始看

reset:
	/*
	 * set the cpu to SVC32 mode
	 */
	mrs	r0, cpsr
	bic	r0, r0, #0x1f
	orr	r0, r0, #0xd3
	msr	cpsr, r0

第一段是把CPU设置成SVC32模式。

#if	defined(CONFIG_AT91RM9200DK) || defined(CONFIG_AT91RM9200EK)
	/*
	 * relocate exception table
	 */
	ldr	r0, =_start
	ldr	r1, =0x0
	mov	r2, #16
copyex:
	subs	r2, r2, #1
	ldr	r3, [r0], #4
	str	r3, [r1], #4
	bne	copyex
#endif

由于这里没有定义 CONFIG_AT91RM9200DKCONFIG_AT91RM9200EK 。所以这一段是忽略的

#ifdef CONFIG_S3C24X0
	/* turn off the watchdog */

# if defined(CONFIG_S3C2400)
#  define pWTCON	0x15300000
#  define INTMSK	0x14400008	/* Interrupt-Controller base addresses */
#  define CLKDIVN	0x14800014	/* clock divisor register */
#else
#  define pWTCON	0x53000000
#  define INTMSK	0x4A000008	/* Interrupt-Controller base addresses */
#  define INTSUBMSK	0x4A00001C
#  define CLKDIVN	0x4C000014	/* clock divisor register */
# endif

	ldr	r0, =pWTCON
	mov	r1, #0x0
	str	r1, [r0]

	/*
	 * mask all IRQs by setting all bits in the INTMR - default
	 */
	mov	r1, #0xffffffff
	ldr	r0, =INTMSK
	str	r1, [r0]
# if defined(CONFIG_S3C2410)
	ldr	r1, =0x3ff
	ldr	r0, =INTSUBMSK
	str	r1, [r0]
# endif

	/* FCLK:HCLK:PCLK = 1:2:4 */
	/* default FCLK is 120 MHz ! */
	ldr	r0, =CLKDIVN
	mov	r1, #3
	str	r1, [r0]
#endif	/* CONFIG_S3C24X0 */

	/*
	 * we do sys-critical inits only at reboot,
	 * not when booting from ram!
	 */

这一段开始是s3c2410的初始化,包括 关看门狗中断初始化时钟初始化

#ifndef CONFIG_SKIP_LOWLEVEL_INIT
	bl	cpu_init_crit
#endif

这里说,如果没有定义 CONFIG_SKIP_LOWLEVEL_INIT ,便跳到 cpu_init_crit 这个段,我们当然没有定义。这段位于 start.S 后半部分。

#ifndef CONFIG_SKIP_LOWLEVEL_INIT
cpu_init_crit:
	/*
	 * flush v4 I/D caches
	 */
	mov	r0, #0
	mcr	p15, 0, r0, c7, c7, 0	/* flush v3/v4 cache */
	mcr	p15, 0, r0, c8, c7, 0	/* flush v4 TLB */

	/*
	 * disable MMU stuff and caches
	 */
	mrc	p15, 0, r0, c1, c0, 0
	bic	r0, r0, #0x00002300	@ clear bits 13, 9:8 (--V- --RS)
	bic	r0, r0, #0x00000087	@ clear bits 7, 2:0 (B--- -CAM)
	orr	r0, r0, #0x00000002	@ set bit 1 (A) Align
	orr	r0, r0, #0x00001000	@ set bit 12 (I) I-Cache
	mcr	p15, 0, r0, c1, c0, 0

#ifndef CONFIG_SKIP_LOWLEVEL_INIT_ONLY
	/*
	 * before relocating, we have to setup RAM timing
	 * because memory timing is board-dependend, you will
	 * find a lowlevel_init.S in your board directory.
	 */
	mov	ip, lr

	bl	lowlevel_init
	mov	lr, ip
#endif
	mov	pc, lr
#endif /* CONFIG_SKIP_LOWLEVEL_INIT */

如果没有定义 CONFIG_SKIP_LOWLEVEL_INITCONFIG_SKIP_LOWLEVEL_INIT_ONLY 这两个宏,这段代码全生效,这里其实是对cpu的 底层初始化的相关配置,注意在这段代码最后 bl lowlevel_init 才是底层初始化,这个段位于 board\samsung\smdk2410\lowlevelinit.S

.globl lowlevel_init
lowlevel_init:
	/* memory control configuration */
	/* make r0 relative the current location so that it */
	/* reads SMRDATA out of FLASH rather than memory ! */
	ldr     r0, =SMRDATA
	ldr	r1, =CONFIG_SYS_TEXT_BASE
	sub	r0, r0, r1
	ldr	r1, =BWSCON	/* Bus Width Status Controller */
	add     r2, r0, #13*4
0:
	ldr     r3, [r0], #4
	str     r3, [r1], #4
	cmp     r2, r0
	bne     0b

	/* everything is fine now */
	mov	pc, lr

	.ltorg
/* the literal pools origin */

SMRDATA:
    .word (0+(B1_BWSCON<<4)+(B2_BWSCON<<8)+(B3_BWSCON<<12)+(B4_BWSCON<<16)+(B5_BWSCON<<20)+(B6_BWSCON<<24)+(B7_BWSCON<<28))
    .word ((B0_Tacs<<13)+(B0_Tcos<<11)+(B0_Tacc<<8)+(B0_Tcoh<<6)+(B0_Tah<<4)+(B0_Tacp<<2)+(B0_PMC))
    .word ((B1_Tacs<<13)+(B1_Tcos<<11)+(B1_Tacc<<8)+(B1_Tcoh<<6)+(B1_Tah<<4)+(B1_Tacp<<2)+(B1_PMC))
    .word ((B2_Tacs<<13)+(B2_Tcos<<11)+(B2_Tacc<<8)+(B2_Tcoh<<6)+(B2_Tah<<4)+(B2_Tacp<<2)+(B2_PMC))
    .word ((B3_Tacs<<13)+(B3_Tcos<<11)+(B3_Tacc<<8)+(B3_Tcoh<<6)+(B3_Tah<<4)+(B3_Tacp<<2)+(B3_PMC))
    .word ((B4_Tacs<<13)+(B4_Tcos<<11)+(B4_Tacc<<8)+(B4_Tcoh<<6)+(B4_Tah<<4)+(B4_Tacp<<2)+(B4_PMC))
    .word ((B5_Tacs<<13)+(B5_Tcos<<11)+(B5_Tacc<<8)+(B5_Tcoh<<6)+(B5_Tah<<4)+(B5_Tacp<<2)+(B5_PMC))
    .word ((B6_MT<<15)+(B6_Trcd<<2)+(B6_SCAN))
    .word ((B7_MT<<15)+(B7_Trcd<<2)+(B7_SCAN))
    .word ((REFEN<<23)+(TREFMD<<22)+(Trp<<20)+(Trc<<18)+(Tchr<<16)+REFCNT)
    .word 0x32
    .word 0x30
    .word 0x30

根据注释这里是 memory control configuration,内存的初始化。这里有句注释 everything is fine now ,意味着相关配置已经完毕(并不)。执行完这段代码后,跳回 start.S , 之后start.S只剩下一句话 bl _main ,这个段位于 D:\毕业班\u-boot-2016.11_test\arch\arm\lib\crt0.S,至此,start.S完毕。

2.2 分析小结

至今为止,代码依次做了

start.S
-> set the cpu to SVC32 mode 			//设置SVC32 模式
-> turn off the watchdog				//关闭看门狗
-> ask all IRQs by setting all bits in the INTMR - default	//设置中断
-> default FCLK					//设置时钟
-> CONFIG_LOWLEVEL_INIT				//配置底层	
     -> flush v4 I/D caches				
     -> disable MMU stuff and caches
     -> setup RAM timing
	 跳转-> lowlevel.S				//跳到 lowlevel.S 初始化内存
	      -> LOWLEVEL_INIT
                      -> memory control configuration

到目前为止,和之前的 jz2440 u-boot 对比发现,

  1. 这个u-boot 只支持nor启动,因为代码是从 0 地址开始的。
  2. 没有设置异步模式,这可能s3c2440独有需要设置的
  3. 时钟的设置不一样
  4. 还没有设置栈
  5. 还没有代码重定位

2.2 分析crt0.S

/*
 * Set up initial C runtime environment and call board_init_f(0).
 */

#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK)
	ldr	sp, =(CONFIG_SPL_STACK)
#else
	ldr	sp, =(CONFIG_SYS_INIT_SP_ADDR)
#endif

...
//源码没有定义CONFIG_SPL_BUILD 和 CONFIG_SPL_STACK
//便追溯CONFIG_SYS_INIT_SP_ADDR
#define CONFIG_SYS_SDRAM_BASE	PHYS_SDRAM_1
#define CONFIG_SYS_INIT_SP_ADDR	(CONFIG_SYS_SDRAM_BASE + 0x1000 - \
				GENERATED_GBL_DATA_SIZE)
				
...
//追溯 PHYS_SDRAM_1
#define PHYS_SDRAM_1		0x30000000 /* SDRAM Bank #1 */
...
//追溯 GENERATED_GBL_DATA_SIZE
	DEFINE(GENERATED_GBL_DATA_SIZE,
		(sizeof(struct global_data) + 15) & ~15)

文件一开球就设置了栈

	mov	r0, sp
	bl	board_init_f_alloc_reserve
	mov	sp, r0
	/* set up gd here, outside any C code */
	mov	r9, r0
	bl	board_init_f_init_reserve

设置完栈之后就做了两件事:Allocate reserved space 和 Initialize reserved space。

	mov	r0, #0
	bl	board_init_f

跳转到board_init_f,里面有一句

...
	if (initcall_run_list(init_sequence_f))
		hang();
...

而这个 init_sequence_f 实际是个初始化函数的函数队列(好像就是个数组),而其中有一个函数board_early_init_f,是单板早期初始化函数。

...
#if defined(CONFIG_BOARD_EARLY_INIT_F)
	board_early_init_f,
#endif
...

跳到board_early_init_f

#define FCLK_SPEED 1

#if (FCLK_SPEED == 0)		/* Fout = 203MHz, Fin = 12MHz for Audio */
#define M_MDIV	0xC3
#define M_PDIV	0x4
#define M_SDIV	0x1
#elif (FCLK_SPEED == 1)		/* Fout = 400MHz */
#define M_MDIV	0xA1
#define M_PDIV	0x3
#define M_SDIV	0x1
#endif

#define USB_CLOCK 1

#if (USB_CLOCK == 0)
#define U_M_MDIV	0xA1
#define U_M_PDIV	0x3
#define U_M_SDIV	0x1
#elif (USB_CLOCK == 1)
#define U_M_MDIV	0x48
#define U_M_PDIV	0x3
#define U_M_SDIV	0x2
#endif

...

int board_early_init_f(void)
{
	struct s3c24x0_clock_power * const clk_power =
					s3c24x0_get_base_clock_power();
	struct s3c24x0_gpio * const gpio = s3c24x0_get_base_gpio();

	/* to reduce PLL lock time, adjust the LOCKTIME register */
	writel(0xFFFFFF, &clk_power->locktime);

	/* configure MPLL */
	writel((M_MDIV << 12) + (M_PDIV << 4) + M_SDIV,
	       &clk_power->mpllcon);

	/* some delay between MPLL and UPLL */
	pll_delay(4000);

	/* configure UPLL */
	writel((U_M_MDIV << 12) + (U_M_PDIV << 4) + U_M_SDIV,
	       &clk_power->upllcon);

	/* some delay between MPLL and UPLL */
	pll_delay(8000);

	/* set up the I/O ports */
	...
	...
	
	return 0;
}

搜索s3c24x0_get_base_clock_power()时发现,居然有s3c2440.h的头文件,说明还是有对S3C2440的支持的。

至此,和之前对比发现时钟设置确实需要重新设置。

3. 动手

首先是发现了比较重要的,异步模式需要设置和时钟频率要改。这里需要参考S3C2440的芯片手册,下面简称参考手册。

  1. 现在时钟频率比是 FCLK:HCLK:PCLK = 1:2:4,起作用的是这段位于start.S代码,因为在参考手册的特性里介绍了S3C2440的工作频率,Fclk最高400MHz,Hclk最高136MHz,Pclk最高68MHz,而我们又想设置设置Fclk 400MHz,那么最好设置为FCLK:HCLK:PCLK = 1:4:8,修改代码。:
#define CLKDIVN	0x4C000014	/* clock divisor register */
...
	/* FCLK:HCLK:PCLK = 1:2:4 */
	/* default FCLK is 120 MHz ! */
	ldr	r0, =CLKDIVN
	mov	r1, #3 	//这里需要改成-> mov r1, #5
	str	r1, [r0]

由于smdk2410和我们的单板工作频率设置也不一样,这里 board\samsung\smdk2410\smdk2410.c 需要也需要修改代码,不详细写啦。

...

#if (FCLK_SPEED == 0)		/* Fout = 203MHz, Fin = 12MHz for Audio */
#define M_MDIV	0xC3
#define M_PDIV	0x4
#define M_SDIV	0x1
#elif (FCLK_SPEED == 1)		/* Fout = 400MHz */
#define M_MDIV	0xA1	// 需要改成 -> #define M_MDIV	0x5C
#define M_PDIV	0x3		// 需要改成 -> #define M_PDIV	0x1
#define M_SDIV	0x1		// 需要改成 -> #define M_SDIV	0x1	
#endif

...

	/* configure MPLL */
	writel((M_MDIV << 12) + (M_PDIV << 4) + M_SDIV,
	       &clk_power->mpllcon);

...

最后在arch\arm\cpu\arm920t\start.S加上异步模式设置的代码。

...

	/* FCLK:HCLK:PCLK = 1:2:4 */
	/* default FCLK is 120 MHz ! */
	ldr	r0, =CLKDIVN
	mov	r1, #5
	str	r1, [r0]

	// -> 加上这一段代码
	/* 设置CPU工作于异步模式 */
	mrc p15,0,r0,c1,c0,0
	orr r0,r0,#0xc0000000   //R1_nF:OR:R1_iA
	mcr p15,0,r0,c1,c0,0

...

重新执行三步,然后烧写。

make distclean
make smdk2410_config
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- all

烧写重启后屏幕出现以下乱码,其实是好事,说明单板开始工作了,只是工作不正常而已~

怘▒怘▒ff▒▒▒▒▒x▒▒▒▒▒▒▒▒~▒▒xxx▒▒▒▒~▒▒▒▒▒▒▒▒▒▒▒▒怘▒fff▒▒~▒x▒▒▒▒x▒▒▒▒▒x▒▒▒f▒▒▒▒▒▒▒▒▒x▒▒▒f▒▒▒f▒▒▒▒▒▒▒▒▒▒f▒▒▒▒▒ff▒▒▒f▒f▒▒▒f▒▒▒▒▒▒▒▒▒f▒▒▒f▒▒▒▒▒`▒▒▒▒▒▒▒fx怘▒x▒▒▒▒▒▒▒f~f▒▒f▒▒▒▒▒▒`▒▒f▒f▒▒▒▒▒▒▒▒▒▒f▒▒▒▒▒▒fx▒▒▒▒▒▒▒▒▒▒f▒▒xf▒xf▒`▒▒▒▒xf▒▒▒▒f▒▒`f▒▒▒怘▒▒▒▒▒▒fxf▒▒怘▒▒▒f▒▒▒fxf▒▒怘▒f▒▒▒▒▒fxf▒▒怘▒▒f▒▒▒▒▒▒▒▒▒▒▒f▒▒▒▒▒~▒▒▒▒▒▒▒▒▒x▒▒fx▒▒▒▒▒▒▒fx▒▒怘▒怘▒f▒▒▒`
我的乱码是这样子的,不知道大家的会不会和我一样呢

一般出现乱码,其实都只是波特率不正常而已,而波特率又是根据时钟频率设定的。

之前发现了s3c2440.h头文件,最好我们就是编译s3c2440的参数。

但是现在肯定编译的是s3c2410.h的头文件,问题是怎么改成编译s3c2440.h头文件呢。

在linux下u-boot根目录执行查找命令

grep s3c2440 * -nR

//喜大普奔,输出很多相关信息,眼利的发现有一句话

...
arch/arm/include/asm/arch/s3c24x0_cpu.h:13:	#include <asm/arch/s3c2440.h>
...

打开这个文件:

/*
 * (C) Copyright 2009
 * Kevin Morfitt, Fearnside Systems Ltd, 
 *
 * SPDX-License-Identifier:     GPL-2.0+
 */

#ifdef CONFIG_S3C2400
        #include 
#elif defined CONFIG_S3C2410
        #include 
#elif defined CONFIG_S3C2440
        #include 
#else
        #error Please define the s3c24x0 cpu type
#endif

找到了!现在源码肯定是定义了CONFIG_S3C2410,所以我们要继续搜索 CONFIG_S3C2410

grep '#define CONFIG_S3C2410' * -nR

...

输出信息:
include/configs/VCMA9.h:25:#define CONFIG_S3C2410		/* specifically a SAMSUNG S3C2410 SoC */
include/configs/smdk2410.h:21:#define CONFIG_S3C2410		/* specifically a SAMSUNG S3C2410 SoC */
u-boot.cfg:68:#define CONFIG_S3C2410

就在smdk2410.h里面修改!在终端输入作弊代码:vim include/configs/smdk2410.h +21(回车键)2ehs4(Esc):wq(回车键)

然后重新编译烧写,重启开发板,发现输出信息:

U-Boot 2016.11 (Oct 12 2020 - 06:04:57 -0700)

CPUID: 32440001
FCLK:      400 MHz
HCLK:      100 MHz
PCLK:       50 MHz
DRAM:  64 MiB
WARNING: Caches not enabled
Flash: 0 Bytes
NAND:  0 MiB
*** Warning - bad CRC, using default environment

In:    serial
Out:   serial
Err:   serial
Net:   CS8900-0
Error: CS8900-0 address not set.

SMDK2410 #

成功启动!

虽然是成功启动了,我们目前改的不多,实现的功能也不多(Nand启动时没反应的),想要更好适配肯定要有更多的工作。

待续

arm-linux-ld -pie -T u-boot.lds -Bstatic -Ttext 0x0 $UNDEF_SYM arch/arm/cpu/arm920t/start.o

patch

patching file arch/arm/config.mk
patching file arch/arm/cpu/arm920t/start.S
patching file arch/arm/cpu/u-boot.lds
patching file arch/arm/lib/board.c
patching file board/samsung/smdk2440/init.c
patching file board/samsung/smdk2440/lowlevel_init.S
patching file board/samsung/smdk2440/Makefile
patching file board/samsung/smdk2440/smdk2410.c
patching file boards.cfg
patching file drivers/mtd/cfi_flash.c
patching file drivers/mtd/jedec_flash.c
patching file drivers/mtd/nand/Makefile
patching file drivers/mtd/nand/nand_base.c
patching file drivers/mtd/nand/nand_util.c
patching file drivers/mtd/nand/s3c2440_nand.c
patching file include/common.h
patching file include/configs/smdk2440.h

2020.4 的移植

你可能感兴趣的:(Linux嵌入式,笔记,uboot,linux,嵌入式)