*同上篇,还是针对遇到的问题简要先记录下,以后有空再补全。

 

一、工程建立

    工程目标板 友善 sbc2410x

    由于工程中已有sbc2410x的内容。所以先要删除一部分。

       删除include/configs/sbc2410x.h

       删除board/sbc2410x整个目录

    修改顶层boards.cfg

       CPU项由arm920t改为s3c2410x。u-boot的初忠是希望尽可能的通用。但带来的坏处是无用代码很多,需要定义很多条件,实际结果是可读性很差,特别是CPU相关的汇编代码部分。所以这里使用arm920t的部分文件+arm920t中s3c24x0的SoC中的文件,在arch/arm/cpu/重新建立一个s3c2410x的CPU,以专一针对s3c2410x组织CPU相关的代码,以方便阅读和分析。

      建立 arch/arm/cpu/s3c2410x

        拷贝 arch/arm/cpu/arm920t/

                        start.S

                        cpu.c

                        config.mk

                        Makefile

                        u-boot.lds

        拷贝 arch/arm/cpu/arm920t/s3c24x0/

                        interrupts.c

                        speed.c

                        timer.c

                        usb.c

                        usb_ohci.c

                        usb_ohci.h

        修改 arch/arm/cpu/s3c2410x/Makefile

           在COBJS-y += cpu.o下面增加

           COBJS-y += cpu.o
           COBJS-y += speed.o
           COBJS-y += timer.o
           COBJS-y += usb.o
           COBJS-y += usb_ohci.o

       在board目录中建立sbc2410x目录

          并将board/samsung/smdk2410/的所有文件拷贝到该目录

          重命名smdk2410.c 为 sbc2410x.c 并修改Makefile中的smdk2410.o 为 sbc2410x.o

          拷贝一份 arch/arm/cpu/arm920t/u-boot.lds到该目录,以修改链接脚本使支持nand启动使用

          修改board/sbc2410x/中的config.mk 在末尾增加一句

                LDSCRIPT=$(SRCTREE)/board/sbc2410x/u-boot.lds
          这样,根目录的链接脚本文件会从board/sbc2410x/u-boot.lds复制。

        在include/configs/将smdk2410.h拷贝一份为sbc2410x.h

 

         至此,在主目录中执行

            make sbc2410x_config     

            make

         应该可以生成一个u-boot.bin

           该u-boot.bin和smdk2410的完全一样。

 

二、基于smdk2410对sbc2410x的汇编级修改

         目标:简化代码,并且从NAND引导,将u-boot复制到RAM中运行。

         原理:当从NAND启动时,S3C2410X会将NAND FLASH中的前4K内容复制到片内的4K SRAM中。该4K SRAM在NAND启动时会被映射到0x0。CPU自动复制后会将PC转至0x0处开始执行。则对于CPU的设置,DRAM的设置,NAND控制器的初始化,代码搬运就必须都在这前4K代码中完成。ARM指令为32位字指令,即,4字节一个指令。编译后必须将arch/arm/cpu/s3c2410x/start.s和board/sbc2410x/lowlevel_init.s的编译后指令控制在1024条以内(4K/4) 。

       首先修改board/sbc2410x/u-boot.lds,以使链接两个汇编文件在前面部分。压缩代码,以使之在4K之内。

       u-boot.lds修改为:

SECTIONS
   {
        . = 0x00000000;        . = ALIGN(4);
        .text :
        {
                arch/arm/cpu/s3c2410x/start.o   (.text)  
                board/sbc2410x/lowlevel_init.o  (.text)        //这行是加入的
                *(.text)
        }        ......


   *这里有一说明,由汇编代码生成的目标文件,不会含有bss rodata等段,完全是text段。

 

   精简和修改arch/arm/cpu/s3c2410x/start.S

/*
 *  armboot - Startup Code for SAMSUNG S3C2410X ARM920T SoC Chipest
 *  2010.11.19 Lianxp Modified from smdk2410's arm920t start.S
 */

#include <common.h>
#include <config.h>

/*
 *************************************************************************
 *
 * Jump vector table as in table 3.1 in [1]
 *
 *************************************************************************
 */


.globl _start
_start:	b	start_code
	ldr	pc, _undefined_instruction
	ldr	pc, _software_interrupt
	ldr	pc, _prefetch_abort
	ldr	pc, _data_abort
	ldr	pc, _not_used
	ldr	pc, _irq
	ldr	pc, _fiq

_undefined_instruction:	b	.
_software_interrupt:	b	.
_prefetch_abort:	b	.
_data_abort:		b	.
_not_used:		b	.
_irq:			b	.
_fiq:			b	.

	.balignl 16,0xdeadbeef


/*
 *************************************************************************
 *
 * Startup Code (called from the ARM reset exception vector)
 *
 * do important init only if we don't start from memory!
 * relocate armboot to ram
 * setup stack
 * jump to second stage
 *
 *************************************************************************
 */

_TEXT_BASE:
	.word	TEXT_BASE

.globl _armboot_start
_armboot_start:
	.word _start

/*
 * These are defined in the board-specific linker script.
 */
.globl _bss_start
_bss_start:
	.word __bss_start

.globl _bss_end
_bss_end:
	.word _end

/*
 * the actual start code
 */

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

/* turn off the watchdog */

#  define pWTCON	0x53000000
#  define INTMSK	0x4A000008	/* Interupt-Controller base addresses */
#  define INTSUBMSK	0x4A00001C
#  define CLKDIVN	0x4C000014	/* clock divisor register */

	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]

	ldr	r1, =0x3ff
	ldr	r0, =INTSUBMSK
	str	r1, [r0]

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

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

	bl	cpu_init_crit
	bl	relocate

	/* Set up the stack						    */
stack_setup:
	ldr	r0, _TEXT_BASE		/* upper 128 KiB: relocated uboot   */
	sub	r0, r0, #CONFIG_SYS_MALLOC_LEN	/* malloc area              */
	sub	r0, r0, #CONFIG_SYS_GBL_DATA_SIZE /* bdinfo                 */
	sub	sp, r0, #12		/* leave 3 words for abort-stack    */
	bic	sp, sp, #7		/* 8-byte alignment for ABI compliance */

clear_bss:
	ldr	r0, _bss_start		/* find start of bss segment        */
	ldr	r1, _bss_end		/* stop here                        */
	mov	r2, #0x00000000		/* clear                            */

clbss_l:str	r2, [r0]		/* clear loop...                    */
	add	r0, r0, #4
	cmp	r0, r1
	ble	clbss_l

	ldr	pc, _start_armboot

_start_armboot:	.word start_armboot


/*
 *************************************************************************
 *
 * CPU_init_critical registers
 *
 * setup important registers
 * setup memory timing
 *
 *************************************************************************
 */


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 2 (A) Align
	orr	r0, r0, #0x00001000	@ set bit 12 (I) I-Cache
	mcr	p15, 0, r0, c1, c0, 0

	/*
	 * 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
	mov	pc, lr

主要是去掉和本处理器无关的代码,去掉中断响应代码(u-boot在s3c2410中不用中断),去掉从nor flash搬运代码的部分。

增加一个子程序调用,从lowlevel_init.s中调用relocate,以使从nand flash中将指令码搬运到内存执行。

 

  修改 board/sbc2410x/lowlevel_init.s

/*
 * Modified from u-boot-2010.09 smdk2410's lowlevel_init.S
 * By Lianxp
 */


#include <config.h>
#include <version.h>

/* CPU Clock Set To 200Mhz*/
_TEXT_BASE:
	.word	TEXT_BASE

.globl lowlevel_init
lowlevel_init:
/* @FCLK:HCLK:PCLK 1:2:4*/

#define MPLLCON	0x4C000004
#define MPLLCON_MDIV	0x5c
#define MPLLCON_PDIV	0x04
#define MPLLCON_SDIV	0x0
CLKSET:	ldr	r0, =MPLLCON
	ldr	r1, =((MPLLCON_MDIV<<12)+(MPLLCON_PDIV<<4)+MPLLCON_SDIV)
	str	r1, [r0]	

/* some parameters for the board */
/* Memory Block Set */

#define BWSCON	0x48000000

/* BWSCON */
#define DW8			(0x0)	/* 00 */
#define DW16			(0x1)	/* 01 */
#define DW32			(0x2)	/* 10 */
#define WAIT			(0x1<<2)
#define UBLB			(0x1<<3)

#define B1_BWSCON		(DW32)
#define B2_BWSCON		(DW16)
#define B3_BWSCON		(DW16 + WAIT + UBLB)
#define B4_BWSCON		(DW16)
#define B5_BWSCON		(DW16)
#define B6_BWSCON		(DW32)
#define B7_BWSCON		(DW32)

/* BANK0CON */
#define B0_Tacs			0x0	/*  0clk */
#define B0_Tcos			0x0	/*  0clk */
#define B0_Tacc			0x7	/* 14clk */
#define B0_Tcoh			0x0	/*  0clk */
#define B0_Tah			0x0	/*  0clk */
#define B0_Tacp			0x0
#define B0_PMC			0x0	/* normal */

/* BANK1CON */
#define B1_Tacs			0x0	/*  0clk */
#define B1_Tcos			0x0	/*  0clk */
#define B1_Tacc			0x7	/* 14clk */
#define B1_Tcoh			0x0	/*  0clk */
#define B1_Tah			0x0	/*  0clk */
#define B1_Tacp			0x0
#define B1_PMC			0x0

#define B2_Tacs			0x0
#define B2_Tcos			0x0
#define B2_Tacc			0x7
#define B2_Tcoh			0x0
#define B2_Tah			0x0
#define B2_Tacp			0x0
#define B2_PMC			0x0

#define B3_Tacs			0x0	/*  0clk */
#define B3_Tcos			0x3	/*  4clk */
#define B3_Tacc			0x7	/* 14clk */
#define B3_Tcoh			0x1	/*  1clk */
#define B3_Tah			0x0	/*  0clk */
#define B3_Tacp			0x3     /*  6clk */
#define B3_PMC			0x0	/* normal */

#define B4_Tacs			0x0	/*  0clk */
#define B4_Tcos			0x0	/*  0clk */
#define B4_Tacc			0x7	/* 14clk */
#define B4_Tcoh			0x0	/*  0clk */
#define B4_Tah			0x0	/*  0clk */
#define B4_Tacp			0x0
#define B4_PMC			0x0	/* normal */

#define B5_Tacs			0x0	/*  0clk */
#define B5_Tcos			0x0	/*  0clk */
#define B5_Tacc			0x7	/* 14clk */
#define B5_Tcoh			0x0	/*  0clk */
#define B5_Tah			0x0	/*  0clk */
#define B5_Tacp			0x0
#define B5_PMC			0x0	/* normal */

#define B6_MT			0x3	/* SDRAM */
#define B6_Trcd			0x1
#define B6_SCAN			0x1	/* 9bit */

#define B7_MT			0x3	/* SDRAM */
#define B7_Trcd			0x1	/* 3clk */
#define B7_SCAN			0x1	/* 9bit */

/* REFRESH parameter */
#define REFEN			0x1	/* Refresh enable */
#define TREFMD			0x0	/* CBR(CAS before RAS)/Auto refresh */
#define Trp			0x0	/* 2clk */
#define Trc			0x3	/* 7clk */
#define Tchr			0x2	/* 3clk */
#define REFCNT			1113	/* period=15.6us, HCLK=60Mhz, (2048+1-15.6*60) */
/**************************************/

	/* memory control configuration */
	/* make r0 relative the current location so that it */
	/* reads SMRDATA out of FLASH rather than memory ! */
MEMSET:	ldr     r0, =SMRDATA
	ldr	r1, _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 ((1<<1)+(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 0xB1
    .word 0x30
    .word 0x30

.globl relocate
relocate:
#define NFCONF		0x4E000000
	mov	ip, lr
	mov	r5, #NFCONF
	ldr	r0, =(1<<15)|(1<<12)|(1<<11)|(7<<8)|(7<<4)|(7)
	str	r0, [r5]
	mov	r8, #0
	ldr	r9, _TEXT_BASE
x3:	mov	r0, r8
	mov	r1, r9
	bl	ReadNandPage
	add	r9, r9, #512             //add a page size to ram addr per time
	add	r8, r8, #1
x4:	cmp	r8, #256
	bcc	x3
	mov	r5, #NFCONF
	ldr	r0, [r5]
	and	r0, r0, #~0x8000
	str	r0, [r5]
	mov	pc, ip
	.ltorg
WaitNandBusy:
	mov	r1,#NFCONF
	ldrb	r0,[r1,#0x10]
	//and	r0,r0,#1
	tst	r0,#0x1
	beq	WaitNandBusy
	mov	pc,lr
	.ltorg
ReadNandPage:
	mov	r7,lr
	mov	r4,r1
	mov	r5,#NFCONF
	ldr	r1,[r5,#0] 		//NFChipEn()
	bic	r1,r1,#0x800
	str	r1,[r5,#0]
	mov	r1,#0xff
	strb	r1,[r5,#4]
	mov	r6,r0
	bl	WaitNandBusy
	mov	r0,r6
	mov	r1,#0 			//WrNFCmd(READCMD0)
	strb	r1,[r5,#4]
	strb	r1,[r5,#8] 		//WrNFAddr(0) a0-a7
	strb	r0,[r5,#8] 		//WrNFAddr(addr) a9-a16
	mov	r1,r0,lsr #8 		//r1 <- (addr>>8)
	strb	r1,[r5,#8]		//WrNFAddr(addr) a17-a24
	mov	r1,r0,lsr #16 		//r1 <- (addr>>16)
	and	r1,r1,#1		//mask a26+
	strb	r1,[r5,#8]		//WrNFAddr(addr) a25
	bl	WaitNandBusy 		//WaitNFBusy()
	mov	r0,#0 			//for(i=0; i<512; i++)
r1:
	ldrb	r1,[r5,#0xc] 		//buf[i] = RdNFDat()
	strb	r1,[r4,r0]              //write buf[i] to ram
	add	r0,r0,#1
	bic	r0,r0,#0x10000
	cmp	r0,#0x200
	bcc	r1
	ldr	r0,[r5,#0] 		//NFChipDs()
	orr	r0,r0,#0x800
	str	r0,[r5,#0]
	mov	pc,r7
	.ltorg
	.balignl 16,0xdeadbeef


   

修改对MPLL的初始化代码,以使主频运行在200M上。修改SDRAM的参数以使可以支持本板的SDRAM运行。这里面有一个设计比较巧妙的地方:该代码的链接地址为0x33f80000,所以SMRDATA的地址在链接后就为0x33f80000+偏移量。而初始化时,代码是在0x0为基地址的4K SRAM中执行的。这样,在代码搬运前SMRDATA实际并不在0x33f80000+偏移量的位置上。所以,这里引入TEXT_BASE,并用编译得到的SMRDATA地址去减基地址TEXT_BASE,得到的恰恰是开始运行的0x33f80000的偏移量,也正是从0x0处计算的实际地址。

 

这段代码搬运的代码写的还比较粗,只适用于K9F1208U0M以及指令兼容的片子。代码中没有进行坏块处理和识别,最大只读取256页,即128K字节的内容。

 

对于其中的一些内容进行一点说明

   1)在进入relocate:之后,执行mov ip,lr是为了保护返回地址。因为在后面还有大量的子程序调用。

   2)在整体搬运过程中,r8属于一个局部的全局变量,用于记录当前在搬运的页地址 0~256

       r9也是一个局部的全局变量,用于记录内存中的偏移位置 0x33f80000~0x33f80000+128K

   3)对于NAND FLASH控制器,每当将需要执行的指令以及地址输入到相应寄存器后,都要轮询NFSTAT寄存器,直到寄存器状态为READY后才能进行数据读取/写入或其他指令操作。一开始,由于没有注意到这一点,从NAND中读出的不是00就是FF,要不就是乱数据。

   4)NAND FLASH在使用00/01指令进行读取数据的时候,其实可以连续的读取后面的数据,后面的数据不光是本页的,还有下一页的数据。包据A段,B段,以及用于校验的C段。由于计算不便,所以本程序每次都重新输入读指令和页地址。

   5)readpage子程序中的 r0->r6 ... r6->r0 属于设计失误,临时保存一下r0的状态。

 

           

至此,编译生成的u-boot.bin可以烧入2410的nand flash,启动u-boot了。

 

 

 

三、u-boot提供了另一种nand启动的方法。

 

        即在nand_spl中的方式。

        大体思路是这样的:写一段较小的可以放入stepping stone中的程序,这段程序用于初始化CPU,初始化RAM,并将NAND FLASH指定位置的指定大小的内容搬到内存中的指定位置,然后跳转到这个内存的指定位置执行后面的代码。

        编译后,指定这个小程序的代码尺寸。编译U-boot,生成u-boot.bin 再通过

                  cat loader.bin u-boot.bin > u-boot-nand.bin     

        将文件合并成一个文件。烧入NAND中。

        这样,当从0x0执行时,首先载入loader那段小程序,将后面的u-boot.bin搬入RAM,然后跳到RAM执行。

        这样做的好处是将u-boot系统又进行了一次拆分,以使可读性和可修改性得到更大的提高。

       

         这种方法实现起来并不复杂,只是看懂了模式,等后面有时间的时候实践一下。