u-boot-2009.11移植(适用于TQ2440和MINI2440)第二篇:探索启动代码

时间:2021-06-16 16:36:34

注意:红色标记部分为修改的地方

 

二、第一阶段:探索启动代码

首先进入/cpu/arm920t/start.S

2.1关闭为AT9200写的LED跳转

start_code:

  /*

   * set the cpu to SVC32 mode

   */

  mrs   r0, cpsr

  bic   r0, r0, #0x1f

  orr   r0, r0, #0xd3

  msr   cpsr, r0

 

@ bl coloured_LED_init

@ bl red_LED_on

2.2修改CPU频率初始化设置

2410 2440相比一个不同的地方就是PLL的初始化参数不一样,在数据手册可以查到。这里一开始就将频率升到405MHz。其中还包括了中断掩码的修正。

#if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410)|| defined(CONFIG_S3C2440)

   /* turn off the watchdog */

 

# if defined(CONFIG_S3C2400)

# define pWTCON 0x15300000

# define INTMSK 0x14400008  /* Interupt-Controller base addresses */

# define CLKDIVN   0x14800014  /* clock divisor register */

#else

# define pWTCON 0x53000000

# define INTMSK 0x4A000008  /* Interupt-Controller base addresses */

# define INTSUBMSK 0x4A00001C

# define CLKDIVN   0x4C000014  /* clock divisor register */

# endif

 

#define CLK_CTL_BASE   0x4C000000  /* tekkaman */

#define MDIV_405   0x7f << 12  /* tekkaman */

#define PSDIV_405  0x21        /* tekkaman */

#define MDIV_200   0xa1 << 12  /* tekkaman */

#define PSDIV_200  0x31        /* tekkaman */

 

………

 

# if defined(CONFIG_S3C2410)

   ldr r1, =0x7ff

   ldr r0, =INTSUBMSK

   str r1, [r0]

# endif

 

#if defined(CONFIG_S3C2440)

   ldr r1, =0x7fff

   ldr r0, =INTSUBMSK

   str r1, [r0]

#endif

 

#if defined(CONFIG_S3C2440)

   /* FCLK:HCLK:PCLK = 1:4:8 */

   ldr r0, =CLKDIVN

   mov r1, #5

   str r1, [r0]

   

   mrc p15, 0, r1, c1, c0, 0  

   orr r1, r1, #0xc0000000    

   mcr p15, 0, r1, c1, c0, 0  

   

   

   mov r1, #CLK_CTL_BASE  

   mov r2, #MDIV_405  

   add r2, r2, #PSDIV_405 

   str r2, [r1, #0x04]     /* MPLLCON tekkaman */

 

#else

   /* FCLK:HCLK:PCLK = 1:2:4 */

   /* default FCLK is 120 MHz ! */

   ldr r0, =CLKDIVN

   mov r1, #3

   str r1, [r0]

//#endif   /* CONFIG_S3C2400 || CONFIG_S3C2410 */

   mrc p15, 0, r1, c1, c0, 0  

   orr r1, r1, #0xc0000000

   mcr p15, 0, r1, c1, c0, 0   /*write ctrl register tekkaman*/

   

   

   mov r1, #CLK_CTL_BASE   /* tekkaman*/

   mov r2, #MDIV_200  

   add r2, r2, #PSDIV_200 

   str r2, [r1, #0x04]

#endif

 

#endif /* CONFIG_S3C2400 || CONFIG_S3C2410 || CONFIG_S3C2440 */

 

   /*

    * we do sys-critical inits only at reboot,

 

2.3修改board/sunzl/sunzl2440/lowlevel_init.S文件

依照开发板的内存区的配置情况,修改board/sunzl/sunzl2440/lowlevel_init.S文件,利用友善之臂提供的vivi源码里的信息做了如下更改:

/* 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 */

 

#if defined(CONFIG_S3C2440)

#define Trp        0x2 /* 4clk */

#define REFCNT         1012

#else

#define Trp        0x0 /* 2clk */

#define REFCNT         0x0459

#endif

/**************************************/

 

_TEXT_BASE:

 

2.4修改代码重定向部分

Tekkaman Ninja2009.08开始就在启动时增加了启动时检测自身是否已经在SDRAM中,以及芯片是Norboot还是Nandboot的机制,来决定代码重定向的方式,使得编译出的bin文件可以同时烧入Nand FlashNor flash。至于这部分的原理,在Tekkaman Ninja的博客文章《在U-boot下实现自动识别启动Flash的原理(针对S3C24x0)》中有详细叙述。

再次打开/cpu/arm920t/start.S

#ifndef CONFIG_SKIP_LOWLEVEL_INIT

   bl  cpu_init_crit

#endif

//#ifndef CONFIG_SKIP_RELOCATE_UBOOT

//relocate:            /* relocate U-Boot to RAM       */

/***************** CHECK_CODE_POSITION ******************************************/

   adr r0, _start      /* r0 <- current position of code  */

   ldr r1, _TEXT_BASE      /* test if we run from flash or RAM */

   cmp r0, r1          /* don't reloc during debug        */

   beq stack_setup

/***************** CHECK_CODE_POSITION ******************************************/

 

/***************** CHECK_BOOT_FLASH ******************************************/

   ldr r1, =( (4<<28)|(3<<4)|(3<<2) )     /* address of Internal SRAM  0x4000003C*/

   mov r0, #0      /* r0 = 0 */

   str r0, [r1]

 

 

   mov r1, #0x3c       /* address of men 0x0000003C*/

   ldr r0, [r1]

   cmp r0, #0

   bne relocate

 

   /* recovery  */

   ldr r0, =(0xdeadbeef)

   ldr r1, =( (4<<28)|(3<<4)|(3<<2) )

   str r0, [r1]

/***************** CHECK_BOOT_FLASH ******************************************/

 

/***************** NAND_BOOT *************************************************/

 

#define LENGTH_UBOOT 0x60000

#define NAND_CTL_BASE 0x4E000000

 

#ifdef CONFIG_S3C2440

/* Offset */

#define oNFCONF 0x00

#define oNFCONT 0x04

#define oNFCMD 0x08

#define oNFSTAT 0x20

 

   @ reset NAND

   mov r1, #NAND_CTL_BASE

   ldr r2, =( (7<<12)|(7<<8)|(7<<4)|(0<<0) )

   str r2, [r1, #oNFCONF]

   ldr r2, [r1, #oNFCONF]

   

   ldr r2, =( (1<<4)|(0<<1)|(1<<0) )   @ Active low CE Control

   str r2, [r1, #oNFCONT]

   ldr r2, [r1, #oNFCONT]

   

   ldr r2, =(0x6)  @ RnB Clear

   str r2, [r1, #oNFSTAT]

   ldr r2, [r1, #oNFSTAT]

   

   mov r2, #0xff   @ RESET command

   strb    r2, [r1, #oNFCMD]

   

   mov r3, #0  @ wait

nand1:

   add r3, r3, #0x1

   cmp r3, #0xa

   blt nand1

 

nand2:

   ldr r2, [r1, #oNFSTAT]  @ wait ready

   tst r2, #0x4

   beq nand2

   

   

   ldr r2, [r1, #oNFCONT]

   orr r2, r2, #0x2    @ Flash Memory Chip Disable

   str r2, [r1, #oNFCONT]

   

   @ get read to call C functions (for nand_read())

   ldr sp, DW_STACK_START  @ setup stack pointer

   mov fp, #0  @ no previous frame, so fp=0

 

   @ copy U-Boot to RAM

   ldr r0, =TEXT_BASE

   mov r1, #0x0

   mov r2, #LENGTH_UBOOT

   bl  nand_read_ll

   tst r0, #0x0

   beq ok_nand_read

 

bad_nand_read:

loop2:

   b   loop2   @ infinite loop

ok_nand_read:

   @ verify

   mov r0, #0

   ldr r1, =TEXT_BASE

   mov r2, #0x400  @ 4 bytes * 1024 = 4K-bytes

go_next:

   ldr r3, [r0], #4

   ldr r4, [r1], #4

   teq r3, r4

   bne notmatch

   subs    r2, r2, #4

   beq stack_setup

   bne go_next

 

notmatch:

loop3:

   b   loop3   @ infinite loop

#endif

 

#ifdef CONFIG_S3C2410

 

/* Offset */

#define oNFCONF 0x00

#define oNFCMD 0x04

#define oNFSTAT 0x10

 

   @ reset NAND

   mov r1, #NAND_CTL_BASE

   ldr r2, =0xf830 @ initial value

   str r2, [r1, #oNFCONF]

   ldr r2, [r1, #oNFCONF]

   bic r2, r2, #0x800  @ enable chip

   str r2, [r1, #oNFCONF]

   mov r2, #0xff       @ RESET command

   strb    r2, [r1, #oNFCMD]

   

   

   mov r3, #0  @ wait

nand1:

   add r3, r3, #0x1

   cmp r3, #0xa

   blt nand1

 

nand2:

   ldr r2, [r1, #oNFSTAT]  @ wait ready

   tst r2, #0x1

   beq nand2

   

   ldr r2, [r1, #oNFCONF]

   orr r2, r2, #0x800  @ disable chip

   str r2, [r1, #oNFCONF]

   

   @ get read to call C functions (for nand_read())

   ldr sp, DW_STACK_START  @ setup stack pointer

   mov fp, #0  @ no previous frame, so fp=0

   

   @ copy U-Boot to RAM

   ldr r0, =TEXT_BASE

   mov r1, #0x0

   mov r2, #LENGTH_UBOOT

   bl  nand_read_ll

   tst r0, #0x0

   beq ok_nand_read

 

bad_nand_read:

loop2:

   b   loop2   @ infinite loop

 

 

ok_nand_read:

   @ verify

   mov r0, #0

   ldr r1, =TEXT_BASE

   mov r2, #0x400  @ 4 bytes * 1024 = 4K-bytes

go_next:

   ldr r3, [r0], #4

   ldr r4, [r1], #4

   teq r3, r4

   bne notmatch

   subs    r2, r2, #4

   beq stack_setup

   bne go_next

 

notmatch:

loop3:

   b   loop3   @ infinite loop

 

#endif

/***************** NAND_BOOT *************************************************/

 

/***************** NOR_BOOT *************************************************/

relocate:              /* relocate U-Boot to RAM       */

     /*********** CHECK_FOR_MAGIC_NUMBER***************/

   ldr r1, =(0xdeadbeef)

   cmp r0, r1

   bne loop3

     /*********** CHECK_FOR_MAGIC_NUMBER***************/

   adr r0, _start      /* r0 <- current position of code  */

   ldr r1, _TEXT_BASE      /* test if we run from flash or RAM */

   ldr r2, _armboot_start

   ldr r3, _bss_start

   sub r2, r3, r2      /* r2 <- size of armboot           */

   add r2, r0, r2      /* r2 <- source end address        */

 

copy_loop:

   ldmia   r0!, {r3-r10}       /* copy from source address [r0]   */

   stmia   r1!, {r3-r10}       /* copy to  target address [r1]    */

   cmp r0, r2          /* until source end addreee [r2]   */

   ble copy_loop

//#endif   /* CONFIG_SKIP_RELOCATE_UBOOT */

/***************** NOR_BOOT *************************************************/

   /* Set up the stack                        */

stack_setup:

 

在上面添加的代码中有一个跳转:bl nand_read_ll,它跳入是新增的C语言文件(board/sunzl/sunzl2440/nand_read.c中的函数,这个文件原本是用vivi的代码,好来经过了openmoko的修改,并支持不同的Nand Flash芯片,Tekkaman Ninja又多加了几个个芯片ID以支持所有mini2440TQ2440Nand Flash。代码如下:

/*

 * nand_read.c: Simple NAND read functions for booting from NAND

 *

 * This is used by cpu/arm920/start.S assembler code,

 * and the board-specific linker script must make sure this

 * file is linked within the first 4kB of NAND flash.

 *

 * Taken from GPLv2 licensed vivi bootloader,

 * Copyright (C) 2002 MIZI Research, Inc.

 *

 * Author: Hwang, Chideok <hwang@mizi.com>

 * Date : $Date: 2004/02/04 10:37:37 $

 *

 * u-boot integration and bad-block skipping (C) 2006 by OpenMoko, Inc.

 * Author: Harald Welte <laforge@openmoko.org>

 */

 

#include <common.h>

#include <linux/mtd/nand.h>

 

 

#define __REGb(x)  (*(volatile unsigned char *)(x))

#define __REGw(x)  (*(volatile unsigned short *)(x))

#define __REGi(x)  (*(volatile unsigned int *)(x))

#define NF_BASE    0x4e000000

#if defined(CONFIG_S3C2410)

#define NFCONF     __REGi(NF_BASE + 0x0)

#define NFCMD      __REGb(NF_BASE + 0x4)

#define NFADDR     __REGb(NF_BASE + 0x8)

#define NFDATA     __REGb(NF_BASE + 0xc)

#define NFSTAT     __REGb(NF_BASE + 0x10)

#define NFSTAT_BUSY1

#define nand_select()  (NFCONF &= ~0x800)

#define nand_deselect()(NFCONF |= 0x800)

#define nand_clear_RnB()   do {} while (0)

#elif defined(CONFIG_S3C2440) || defined(CONFIG_S3C2442)

#define NFCONF     __REGi(NF_BASE + 0x0)

#define NFCONT     __REGi(NF_BASE + 0x4)

#define NFCMD      __REGb(NF_BASE + 0x8)

#define NFADDR     __REGb(NF_BASE + 0xc)

#define NFDATA     __REGb(NF_BASE + 0x10)

#define NFDATA16   __REGw(NF_BASE + 0x10)

#define NFSTAT     __REGb(NF_BASE + 0x20)

#define NFSTAT_BUSY1

#define nand_select()  (NFCONT &= ~(1 << 1))

#define nand_deselect()(NFCONT |= (1 << 1))

#define nand_clear_RnB()   (NFSTAT |= (1 << 2))

#endif

 

static inline void nand_wait(void)

{

   int i;

 

   while (!(NFSTAT & NFSTAT_BUSY))

       for (i=0; i<10; i++);

}

 

struct boot_nand_t {

   int page_size;

   int block_size;

   int bad_block_offset;

// unsigned long size;

};

 

#if 0

#if defined(CONFIG_S3C2410)|| defined(CONFIG_sunzl2440)

/* configuration for 2410 with 512byte sized flash */

#define NAND_PAGE_SIZE     512

#define BAD_BLOCK_OFFSET   5

#define NAND_BLOCK_MASK    (NAND_PAGE_SIZE - 1)

#define NAND_BLOCK_SIZE    0x4000

#else

/* configuration for 2440 with 2048byte sized flash */

#define NAND_5_ADDR_CYCLE

#define NAND_PAGE_SIZE     2048

#define BAD_BLOCK_OFFSET   NAND_PAGE_SIZE

#defineNAND_BLOCK_MASK     (NAND_PAGE_SIZE - 1)

#define NAND_BLOCK_SIZE    (NAND_PAGE_SIZE * 64)

#endif

 

/* compile time failure in case of an invalid configuration */

#if defined(CONFIG_S3C2410) && (NAND_PAGE_SIZE != 512)

#error "S3C2410 does not support nand page size != 512"

#endif

#endif

 

static int is_bad_block(struct boot_nand_t * nand, unsigned long i)

{

   unsigned char data;

   unsigned long page_num;

 

   nand_clear_RnB();

   if (nand->page_size == 512) {

       NFCMD = NAND_CMD_READOOB; /* 0x50 */

       NFADDR = nand->bad_block_offset & 0xf;

       NFADDR = (i >> 9) & 0xff;

       NFADDR = (i >> 17) & 0xff;

       NFADDR = (i >> 25) & 0xff;

   } else if (nand->page_size == 2048) {

       page_num = i >> 11; /* addr / 2048 */

       NFCMD = NAND_CMD_READ0;

       NFADDR = nand->bad_block_offset & 0xff;

       NFADDR = (nand->bad_block_offset >> 8) & 0xff;

       NFADDR = page_num & 0xff;

       NFADDR = (page_num >> 8) & 0xff;

       NFADDR = (page_num >> 16) & 0xff;

       NFCMD = NAND_CMD_READSTART;

   } else {

       return -1;

   }

   nand_wait();

   data = (NFDATA & 0xff);

   if (data != 0xff)

       return 1;

 

   return 0;

}

 

static int nand_read_page_ll(struct boot_nand_t * nand, unsigned char *buf, unsigned long addr)

{

   unsigned short *ptr16 = (unsigned short *)buf;

   unsigned int i, page_num;

 

   nand_clear_RnB();

 

   NFCMD = NAND_CMD_READ0;

 

   if (nand->page_size == 512) {

       /* Write Address */

       NFADDR = addr & 0xff;

       NFADDR = (addr >> 9) & 0xff;

       NFADDR = (addr >> 17) & 0xff;

       NFADDR = (addr >> 25) & 0xff;

   } else if (nand->page_size == 2048) {

       page_num = addr >> 11; /* addr / 2048 */

       /* Write Address */

       NFADDR = 0;

       NFADDR = 0;

       NFADDR = page_num & 0xff;

       NFADDR = (page_num >> 8) & 0xff;

       NFADDR = (page_num >> 16) & 0xff;

       NFCMD = NAND_CMD_READSTART;

   } else {

       return -1;

   }

   nand_wait();

 

#if defined(CONFIG_S3C2410)

   for (i = 0; i < nand->page_size; i++) {

       *buf = (NFDATA & 0xff);

       buf++;

   }

#elif defined(CONFIG_S3C2440) || defined(CONFIG_S3C2442)

   for (i = 0; i < (nand->page_size>>1); i++) {

       *ptr16 = NFDATA16;

       ptr16++;

   }

#endif

 

   return nand->page_size;

}

 

static unsigned short nand_read_id()

{

   unsigned short res = 0;

   NFCMD = NAND_CMD_READID;

   NFADDR = 0;

   res = NFDATA;

   res = (res << 8) | NFDATA;

   return res;

}

 

extern unsigned int dynpart_size[];

 

/* low level nand read function */

int nand_read_ll(unsigned char *buf, unsigned long start_addr, int size)

{

   int i, j;

   unsigned short nand_id;

   struct boot_nand_t nand;

 

   /* chip Enable */

   nand_select();

   nand_clear_RnB();

   

   for (i = 0; i < 10; i++)

       ;

   nand_id = nand_read_id();

   if (0) { /* dirty little hack to detect if nand id is misread */

       unsigned short * nid = (unsigned short *)0x31fffff0;

       *nid = nand_id;

   }  

 

      if (nand_id == 0xec76 ||      /* Samsung K91208 */

          nand_id == 0xad76 ) { /*Hynix HY27US08121A*/

       nand.page_size = 512;

       nand.block_size = 16 * 1024;

       nand.bad_block_offset = 5;

   //  nand.size = 0x4000000;

   } else if (nand_id == 0xecf1 || /* Samsung K9F1G08U0B */

          nand_id == 0xecda || /* Samsung K9F2G08U0B */

         nand_id == 0xecd3 )   { /* Samsung K9K8G08 */

       nand.page_size = 2048;

       nand.block_size = 128 * 1024;

       nand.bad_block_offset = nand.page_size;

   //  nand.size = 0x8000000;

   } else {

       return -1; // hang

   }

   if ((start_addr & (nand.block_size-1)) || (size & ((nand.block_size-1))))

       return -1;  /* invalid alignment */

 

   for (i=start_addr; i < (start_addr + size);) {

#ifdef CONFIG_S3C2410_NAND_SKIP_BAD

       if (i & (nand.block_size-1)== 0) {

           if (is_bad_block(&nand, i) ||

               is_bad_block(&nand, i + nand.page_size)) {

               /* Bad block */

               i += nand.block_size;

               size += nand.block_size;

               continue;

           }

       }

#endif

       j = nand_read_page_ll(&nand, buf, i);

       i += j;

       buf += j;

   }

 

   /* chip Disable */

   nand_deselect();

 

   return 0;

}

 

在添加了这个文件之后,记得要在Makefile里加上对这个文件的编译

board/sunzl/sunzl2440/Makefile文件中

include $(TOPDIR)/config.mk

 

LIB= $(obj)lib$(BOARD).a

 

COBJS  := sunzl2440.o nand_read.o flash.o

SOBJS  := lowlevel_init.o

 

2.5初始化堆栈的定义

还记得前面有调用C语言的nand_read_ll函数吧,初始化堆栈的定义就在此

打开/cpu/arm920t/start.S文件

ldrpc, _start_armboot

 

_start_armboot:.word start_armboot

 

#define STACK_BASE 0x33f00000

#define STACK_SIZE 0x10000

   .align  2

DW_STACK_START:.word   STACK_BASE+STACK_SIZE-4

 

到这里,启动的第一阶段就修改完了,但是在 U-boot-1.3.3之后,这些本应放在bin文件前4K的代码会被放到后面,以至启动失败。所以必须手动修改链接时使用的.lds文件,使得这些代码被放在bin文件的最前面:

打开/cpu/arm920t/u-boot.lds文件

SECTIONS

{

   . = 0x00000000;

 

   . = ALIGN(4);

   .text :

   {

       cpu/arm920t/start.o (.text)

       board/sunzl/sunzl2440/lowlevel_init.o  (.text)

       board/sunzl/sunzl2440/nand_read.o   (.text)

       *(.text)

   }