嵌入式学习笔记103-uboot_1.1.6移植(3)

  1. 经过之前对uboot的整体flow分析,现在开始针对2440移植,需要注意的是移植的code可能包含支持部分的2410code 不过并没有在s3c2410板子实测过。
    主要概括:第一阶段的汇编code尽量短小,能用C实现的就用C,由于2440的board和头文件是从2410 copy过来的 里面会有很多信息或者宏关于2410,并且很多.c文件的头文件由于include的是2410,所以新增的一些关于2440的结构体也会一并放在2410.h,移植的思想与前文类似, 根据code的执行流程来移植。
  2. 先移植start.S,还记得《嵌入式学习笔记007-裸奔篇之定时器》么,直接在Reset赋值SP指针后全部调用C函数接口:
Reset:                  
    ldr sp, =4096           @ 设置栈指针,以下都是C函数,调用前需要设好栈
    bl  disable_watch_dog   @ 关闭WATCHDOG,否则CPU会不断重启
    bl  clock_init          @ 设置MPLL,改变FCLK、HCLK、PCLK
    bl  init_led            @ 初始化LED的GPIO管脚
    bl  timer0_init         @ 初始化定时器0 
    bl  init_irq            @ 调用中断初始化函数,在init.c中
    bl  memsetup            @ 设置存储控制器以使用SDRAM
    bl  copy_steppingstone_to_sdram     @ 复制代码到SDRAM中
    ldr sp, =0x34000000     @ 设置系统模式栈指针,
    ldr pc, =on_sdram                   @ 跳到SDRAM中继续执行
on_sdram:
    msr cpsr_c, #0xd2 @ 进入中断模式
    ldr sp, =4096           @ 设置中断模式栈指针
    msr cpsr_c, #0x5f @ 设置I-bit=0,开IRQ中断

    ldr lr, =halt_loop      @ 设置返回地址
    ldr pc, =main           @ 调用main函数
halt_loop:
    b   halt_loop

这里我们也是这样,注释都在code里,主要的就是将SP栈指针放到前面设置好直接调用相应的函数

/* * armboot - Startup Code for ARM920 CPU-core * * Copyright (c) 2001 Marius Gr鰃er <[email protected]> * Copyright (c) 2002 Alex Z黳ke <[email protected]> * Copyright (c) 2002 Gary Jennejohn <[email protected]> * * See file CREDITS for list of people who contributed to this * project. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA */


#include <config.h>
#include <version.h>
/*============ === 代码分析====================== * *还记得P28的config.h怎么来的么,前篇博文有提到 *mkconfig 会在include下生成config.h,最终里面指向 *#include <configs/tq2440.h>,所以接下来的很多宏定义都是 *在include/configs/tq2440.h里定义的 * *=================================================*/


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


.globl _start
_start: b       reset
    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: .word undefined_instruction
_software_interrupt:    .word software_interrupt
_prefetch_abort:    .word prefetch_abort
_data_abort:        .word data_abort
_not_used:      .word not_used
_irq:           .word irq
_fiq:           .word fiq

    .balignl 16,0xdeadbeef

/*============ === 代码分析====================== * *P41-P57 主要设置了中断和异常的向量 *对应的处理函数其实除了IRQ,FIQ其他并没有做啥 * *=================================================*/
/* ************************************************************************* * * Startup Code (reset 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

#ifdef CONFIG_USE_IRQ
/* IRQ stack memory (calculated at run-time) */
.globl IRQ_STACK_START
IRQ_STACK_START:
    .word   0x0badc0de

/* IRQ stack memory (calculated at run-time) */
.globl FIQ_STACK_START
FIQ_STACK_START:
    .word 0x0badc0de
#endif

/*============ === 代码分析====================== * *很明显想要使能IRQ/FIQ的话要在tq2440.h里 *定义这个CONFIG_USE_IRQ,不过stack的值就不是 *这个0x0badc0de,要更改成合适的 * *=================================================*/


/* * the actual reset code */

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

    /* * we do sys-critical inits only at reboot, * not when booting from ram! */
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
    bl  cpu_init_crit
#endif

/*============ === 代码分析====================== * *P140-P146会做一次系统更基本的初始化 *根据上面的注释可知如果是直接从RAM *启动的话不能调用cpu_init_crit 因为他会对RAM做 *清零的动作,code download到RAM结果自己清自己 *明显不行,否则程序跑到cpu_init_crit就挂了 * *=================================================*/

    /* Set up the stack */
stack_setup:
    ldr r0, _TEXT_BASE      /* upper 128 KiB: relocated uboot */
    sub r0, r0, #CFG_MALLOC_LEN /* malloc area */
    sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo */
#ifdef CONFIG_USE_IRQ
    sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
#endif
    sub sp, r0, #12 /* leave 3 words for abort-stack */

/*============ === 代码分析====================== * *P159-P166跟之前的裸奔一样设置好栈,为第二阶段的C准备 *这里需要注意的是,由于栈是对_TEXT_BASE往下偏移的,这就 *要求_TEXT_BASE不能为RAM的基址,如果将_TEXT_BASE设置成 *0x30000000,那再往下就不是RAM了! 这是要注意的,同时_TEXT_BASE *下还作为CFG_MALLOC_LEN的buffer,CFG_GBL_DATA_SIZE等用于 *传给linux的参数 * *=======> 为后面调用C函数要将stack_setup 搬到前面 * *=================================================*/

basic_init:
    bl  disable_watch_dog   @ 关闭WATCHDOG,否则CPU会不断重启
    bl  clock_init                  @ 设置MPLL,改变FCLK、HCLK、PCLK
    bl  init_led                        @ 初始化LED的GPIO管脚
    @bl timer0_init                 @ 初始化定时器0   
    bl  init_irq                        @ 调用中断初始化函数,在init.c中
    @bl uart0_init
    @bl memsetup                        @ 设置存储控制器以使用SDRAM
    @bl copy_steppingstone_to_sdram         @ 复制代码到SDRAM中

#ifndef CONFIG_SKIP_RELOCATE_UBOOT
relocate:               /* relocate U-Boot to RAM */
    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     clear_bss
    ldr r2, _armboot_start
    ldr r3, _bss_start
    sub r2, r3, r2      /* r2 <- size of armboot */
#if 1
    bl  CopyCode2Ram
#else
    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
#endif /* CONFIG_SKIP_RELOCATE_UBOOT */

/*============ === 代码分析====================== * *P191-P211会判断此时正在跑的code是否就是指定的地址 *其中adr r0, _start的用法就是获得真正的运行地址 *比如_start会等于board/tq2440/config.mk * TEXT_BASE = 0x33F80000 *但是程序刚跑是前面的博文讲过PC是从0开始+4的,所以 *地址无关的PC减去_start偏移最后_start=0,而 *_TEXT_BASE = 0x33F80000,所以会执行后面的copy动作, *如果我们直接将code download到RAM的0x33F80000处,这部分的 *code则相当于无效 * *==========> CopyCode2Ram 同时支持nor nand 启动 * *=================================================*/


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

/*============ === 代码分析====================== * *设置好栈后直接调用_start_armboot,由于采用的是 *ldr pc, _start_armboot ldr是赋值绝对地址,最终导致 *跑到运行地址处 * *=================================================*/


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


#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 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
#endif /* CONFIG_SKIP_LOWLEVEL_INIT */

/* ************************************************************************* * * Interrupt handling * ************************************************************************* */

@
@ IRQ stack frame.
@
#define S_FRAME_SIZE 72

#define S_OLD_R0 68
#define S_PSR 64
#define S_PC 60
#define S_LR 56
#define S_SP 52

#define S_IP 48
#define S_FP 44
#define S_R10 40
#define S_R9 36
#define S_R8 32
#define S_R7 28
#define S_R6 24
#define S_R5 20
#define S_R4 16
#define S_R3 12
#define S_R2 8
#define S_R1 4
#define S_R0 0

#define MODE_SVC 0x13
#define I_BIT 0x80

/* * use bad_save_user_regs for abort/prefetch/undef/swi ... * use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling */

    .macro  bad_save_user_regs
    sub sp, sp, #S_FRAME_SIZE
    stmia   sp, {r0 - r12}          @ Calling r0-r12
    ldr r2, _armboot_start
    sub r2, r2, #(CONFIG_STACKSIZE+CFG_MALLOC_LEN)
    sub r2, r2, #(CFG_GBL_DATA_SIZE+8) @ set base 2 words into abort stack
    ldmia   r2, {r2 - r3}           @ get pc, cpsr
    add r0, sp, #S_FRAME_SIZE @ restore sp_SVC

    add r5, sp, #S_SP
    mov r1, lr
    stmia   r5, {r0 - r3}           @ save sp_SVC, lr_SVC, pc, cpsr
    mov r0, sp
    .endm

    .macro  irq_save_user_regs
    sub sp, sp, #S_FRAME_SIZE
    stmia   sp, {r0 - r12}          @ Calling r0-r12
    add     r8, sp, #S_PC
    stmdb   r8, {sp, lr}^                   @ Calling SP, LR
    str     lr, [r8, #0] @ Save calling PC
    mrs     r6, spsr
    str     r6, [r8, #4] @ Save CPSR
    str     r0, [r8, #8] @ Save OLD_R0
    mov r0, sp
    .endm

    .macro  irq_restore_user_regs
    ldmia   sp, {r0 - lr}^          @ Calling r0 - lr
    mov r0, r0
    ldr lr, [sp, #S_PC] @ Get PC
    add sp, sp, #S_FRAME_SIZE
    subs    pc, lr, #4 @ return & move spsr_svc into cpsr
    .endm

    .macro get_bad_stack
    ldr r13, _armboot_start     @ setup our mode stack
    sub r13, r13, #(CONFIG_STACKSIZE+CFG_MALLOC_LEN)
    sub r13, r13, #(CFG_GBL_DATA_SIZE+8) @ reserved a couple spots in abort stack

    str lr, [r13]           @ save caller lr / spsr
    mrs lr, spsr
    str     lr, [r13, #4]

    mov r13, #MODE_SVC @ prepare SVC-Mode
    @ msr   spsr_c, r13
    msr spsr, r13
    mov lr, pc
    movs    pc, lr
    .endm

    .macro get_irq_stack            @ setup IRQ stack
    ldr sp, IRQ_STACK_START
    .endm

    .macro get_fiq_stack            @ setup FIQ stack
    ldr sp, FIQ_STACK_START
    .endm

/* * exception handlers */
    .align  5
undefined_instruction:
    get_bad_stack
    bad_save_user_regs
    bl  do_undefined_instruction

    .align  5
software_interrupt:
    get_bad_stack
    bad_save_user_regs
    bl  do_software_interrupt

    .align  5
prefetch_abort:
    get_bad_stack
    bad_save_user_regs
    bl  do_prefetch_abort

    .align  5
data_abort:
    get_bad_stack
    bad_save_user_regs
    bl  do_data_abort

    .align  5
not_used:
    get_bad_stack
    bad_save_user_regs
    bl  do_not_used

#ifdef CONFIG_USE_IRQ

    .align  5
irq:
    get_irq_stack
    irq_save_user_regs
    bl  do_irq
    irq_restore_user_regs

    .align  5
fiq:
    get_fiq_stack
    /* someone ought to write a more effiction fiq_save_user_regs */
    irq_save_user_regs
    bl  do_fiq
    irq_restore_user_regs

#else

    .align  5
irq:
    get_bad_stack
    bad_save_user_regs
    bl  do_irq

    .align  5
fiq:
    get_bad_stack
    bad_save_user_regs
    bl  do_fiq

#endif

其中移除汇编相关watchdog 时钟即中断,改成C,在board/tq2440新建 basic_init.c,把之前的code扔进去即可,同时修改该目录下的makefile

COBJS   := tq2440.o flash.o basic_init.o 

同时修改该目录下的U-boot.lds使其放置在前面

SECTIONS
{
    . = 0x00000000;

    . = ALIGN(4);
    .text      :
    {
      cpu/arm920t/start.o   (.text)
      board/tq2440/basic_init.o (.text)

而basic_init.c 如下:

/* * init.c: 进行一些初始化 */ 
#define WTCON (*(volatile unsigned long *)0x53000000)
#define CLKDIVN (*(volatile unsigned long *)0x4c000014)
#define GSTATUS1 (*(volatile unsigned long *)0x560000B0)
#define MPLLCON (*(volatile unsigned long *)0x4c000004)
#define MEM_CTL_BASE 0x48000000
#define GPBCON (*(volatile unsigned long *)0x56000010)
#define GPBDAT (*(volatile unsigned long *)0x56000014)
#define INTMSK (*(volatile unsigned long *)0x4A000008)


void disable_watch_dog(void);
void clock_init(void);
void memsetup(void);
void copy_steppingstone_to_sdram(void);
void init_led(void);
void timer0_init(void);
void init_irq(void);

/* * 关闭WATCHDOG,否则CPU会不断重启 */
void disable_watch_dog(void)
{
    WTCON = 0;  // 关闭WATCHDOG很简单,往这个寄存器写0即可
}

#define S3C2410_MPLL_200MHZ ((0x5c<<12)|(0x04<<4)|(0x00))
#define S3C2440_MPLL_200MHZ ((0x5c<<12)|(0x01<<4)|(0x02))
#define S3C2440_MPLL_400MHZ ((0x5c<<12)|(0x01<<4)|(0x01))
/* * 对于MPLLCON寄存器,[19:12]为MDIV,[9:4]为PDIV,[1:0]为SDIV * 有如下计算公式: * S3C2410: MPLL(FCLK) = (m * Fin)/(p * 2^s) * S3C2440: MPLL(FCLK) = (2 * m * Fin)/(p * 2^s) * 其中: m = MDIV + 8, p = PDIV + 2, s = SDIV * 对于本开发板,Fin = 12MHz * 设置CLKDIVN,令分频比为:FCLK:HCLK:PCLK=1:4:8, * FCLK=400MHz,HCLK=100MHz,PCLK=50MHz */
void clock_init(void)
{
    // LOCKTIME = 0x00ffffff; // 使用默认值即可
    CLKDIVN  = 0x05;            // FCLK:HCLK:PCLK=1:4:8, HDIVN=2,PDIVN=1

    /* 如果HDIVN非0,CPU的总线模式应该从“fast bus mode”变为“asynchronous bus mode” */
__asm__(
    "mrc p15, 0, r1, c1, c0, 0\n"        /* 读出控制寄存器 */ 
    "orr r1, r1, #0xc0000000\n"          /* 设置为“asynchronous bus mode” */
    "mcr p15, 0, r1, c1, c0, 0\n"        /* 写入控制寄存器 */
    );

    /* 判断是S3C2410还是S3C2440 */
    if ((GSTATUS1 == 0x32410000) || (GSTATUS1 == 0x32410002))
    {
        MPLLCON = S3C2410_MPLL_200MHZ;  /* 现在,FCLK=200MHz,HCLK=100MHz,PCLK=50MHz */
    }
    else
    {
        MPLLCON = S3C2440_MPLL_400MHZ;  /* 现在,FCLK=400MHz,HCLK=100MHz,PCLK=50MHz */
    }    

    //UPLLCON = ???? ; // have not set yat
}

/* * 设置存储控制器以使用SDRAM */
void memsetup(void)
{
    volatile unsigned long *p = (volatile unsigned long *)MEM_CTL_BASE;

    /* 这个函数之所以这样赋值,而不是像前面的实验(比如mmu实验)那样将配置值 * 写在数组中,是因为要生成”位置无关的代码”,使得这个函数可以在被复制到 * SDRAM之前就可以在steppingstone中运行 */
    /* 存储控制器13个寄存器的值 */
    p[0] = 0x22011110;     //BWSCON
    p[1] = 0x00000700;     //BANKCON0
    p[2] = 0x00000700;     //BANKCON1
    p[3] = 0x00000700;     //BANKCON2
    p[4] = 0x00000700;     //BANKCON3 
    p[5] = 0x00000700;     //BANKCON4
    p[6] = 0x00000700;     //BANKCON5
    p[7] = 0x00018005;     //BANKCON6
    p[8] = 0x00018005;     //BANKCON7

    /* REFRESH = 0x008c0000 + R_CNT * R_CNT = 2^11 +1 - HCLK(MHZ)*SDRAM_REF_TIME(us , 7.8125) * HCLK=12MHz: 0x008C07A3, * HCLK=100MHz: 0x008C04f4 */ 
    p[9]  = 0x008C04f4;
    p[10] = 0x000000B1;     //BANKSIZE
    p[11] = 0x00000030;     //MRSRB6
    p[12] = 0x00000030;     //MRSRB7
}

void copy_steppingstone_to_sdram(void)
{
    unsigned int *pdwSrc  = (unsigned int *)0;
    unsigned int *pdwDest = (unsigned int *)0x30000000;

    while (pdwSrc < (unsigned int *)4096)
    {
        *pdwDest = *pdwSrc;
        pdwDest++;
        pdwSrc++;
    }
}

/* * LED1-4对应GPB5、GPB6、GPB7、GPB8 */
#define GPB5_out (1<<(5*2)) // LED1
#define GPB6_out (1<<(6*2)) // LED2
#define GPB7_out (1<<(7*2)) // LED3
#define GPB8_out (1<<(8*2)) // LED4

/* * K1-K4对应GPG11、GPG3、GPF2、GPF3 */
#define GPG11_eint (2<<(11*2)) // K1,EINT19
#define GPG3_eint (2<<(3*2)) // K2,EINT11
#define GPF3_eint (2<<(3*2)) // K3,EINT3
#define GPF2_eint (2<<(2*2)) // K4,EINT2

void init_led(void)
{
    GPBCON = GPB5_out | GPB6_out | GPB7_out | GPB8_out ;
        GPBDAT = ~0;
        //GPBDAT &= ~(1<<5);
}

/* * Timer input clock Frequency = PCLK / {prescaler value+1} / {divider value} * {prescaler value} = 0~255 * {divider value} = 2, 4, 8, 16 * 本实验的Timer0的时钟频率=100MHz/(99+1)/(16)=62500Hz * 设置Timer0 0.5秒钟触发一次中断: */
/*void timer0_init(void) { TCFG0 = 99; // 预分频器0 = 99 TCFG1 = 0x03; // 选择16分频 TCNTB0 = 31250; // 0.5秒钟触发一次中断 TCON |= (1<<1); // 手动更新 TCON = 0x09; // 自动加载,清“手动更新”位,启动定时器0 }*/

/* * 定时器0中断使能 */ 
void init_irq(void)
{        
    INTMSK   = ~(0);
}

/*#define PCLK 50000000 // init.c中的clock_init函数设置PCLK为50MHz #define UART_CLK PCLK // UART0的时钟源设为PCLK #define UART_BAUD_RATE 115200 // 波特率 #define UART_BRD ((UART_CLK / (UART_BAUD_RATE * 16)) - 1) */
/* * 初始化UART0 * 115200,8N1,无流控 */
/*void uart0_init(void) { GPHCON |= 0xa0; // GPH2,GPH3用作TXD0,RXD0 GPHUP = 0x0c; // GPH2,GPH3内部上拉 ULCON0 = 0x03; // 8N1(8个数据位,无较验,1个停止位) UCON0 = 0x05; // UART时钟源为PCLK UFCON0 = 0x00; // 不使用FIFO UMCON0 = 0x00; // 不使用流控 UBRDIV0 = UART_BRD; // 波特率为115200 } */

 /***************** nand init *************************/

自此,第一阶段的移植就完成了。

3.现在开始移植第二阶段,在start_armboot()先依次初始化:

init_fnc_t *init_sequence[] = {
    cpu_init,       /* basic cpu dependent setup */
    board_init,     /* basic board dependent setup */
    interrupt_init,     /* set up exceptions */
    env_init,       /* initialize environment */
    init_baudrate,      /* initialze baudrate settings */
    serial_init,        /* serial communications setup */
    console_init_f,     /* stage 1 init of console */
    display_banner,     /* say that we are here */
#if defined(CONFIG_DISPLAY_CPUINFO)
    print_cpuinfo,      /* display cpu info (and speed) */
#endif
#if defined(CONFIG_DISPLAY_BOARDINFO)
    checkboard,     /* display board info */
#endif
    dram_init,      /* configure available RAM banks */
    display_dram_config,
    NULL,
};

cpu_init()啥都没做,忽略,board_init()里面删除关于时钟即可,因为我们再前面第一阶段已经完成了。

    /* 判断是S3C2410还是S3C2440 */
    if ((GSTATUS1 == 0x32410000) || (GSTATUS1 == 0x32410002))
    {
        gd->bd->bi_arch_number = MACH_TYPE_SMDK2410;
    }
    else
    {
        gd->bd->bi_arch_number = MACH_TYPE_TQ2440;
    }    

MACH_TYPE_TQ2440自己在相应定义即可。init_baudrate()保持原有,即 115200波特率 8位数据位 无校验 一位停止位。这里最重要的是先调通serial_init(),这样就可以看到打印了,最终call的是serial_setbrg(),里面有个设置波特率的寄存器的公式是reg = get_PCLK() / (16 * gd->baudrate) - 1; 但是2410和2440的get_PCLK(),get_HCLK()是不一样的,要区分对待,在u-boot-1.1.6\cpu\arm920t\s3c24x0\speed.c如下:

static ulong get_PLLCLK(int pllreg)
{
    S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER();
    ulong r, m, p, s;

    if (pllreg == MPLL)
    r = clk_power->MPLLCON;
    else if (pllreg == UPLL)
    r = clk_power->UPLLCON;
    else
    hang();

    m = ((r & 0xFF000) >> 12) + 8;
    p = ((r & 0x003F0) >> 4) + 2;
    s = r & 0x3;

    if(MACH_TYPE_SMDK2410 == gd->bd->bi_arch_number )
        return((CONFIG_SYS_CLK_FREQ * m) / (p << s));
    else if (MACH_TYPE_TQ2440 == gd->bd->bi_arch_number)
        return((CONFIG_SYS_CLK_FREQ * m*2) / (p << s));
    else
        hang ();

}

/* return FCLK frequency */
ulong get_FCLK(void)
{
    return(get_PLLCLK(MPLL));
}

/* return HCLK frequency */
ulong get_HCLK(void)
{
    unsigned long clkdiv;
    unsigned long camdiv;
    int hdiv = 1;
    S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER();

    if(MACH_TYPE_SMDK2410 == gd->bd->bi_arch_number )
        return((clk_power->CLKDIVN & 0x2) ? get_FCLK()/2 : get_FCLK());
    else if (MACH_TYPE_TQ2440 == gd->bd->bi_arch_number)
    {
        clkdiv = clk_power->CLKDIVN;
        camdiv = clk_power->CAMDIVN;
        /* work out clock scalings */
        switch (clkdiv & S3C2440_CLKDIVN_HDIVN_MASK) {
            case S3C2440_CLKDIVN_HDIVN_1:
                hdiv = 1;
                break;
            case S3C2440_CLKDIVN_HDIVN_2:
                hdiv = 2;
                break;
            case S3C2440_CLKDIVN_HDIVN_4_8:
                hdiv = (camdiv & S3C2440_CAMDIVN_HCLK4_HALF) ? 8 : 4;
                break;
            case S3C2440_CLKDIVN_HDIVN_3_6:
                hdiv = (camdiv & S3C2440_CAMDIVN_HCLK3_HALF) ? 6 : 3;
                break;
        }
        return get_FCLK() / hdiv;
    }
    else
        hang ();


}

/* return PCLK frequency */
ulong get_PCLK(void)
{
    unsigned long clkdiv;
    unsigned long camdiv;
    int hdiv = 1;
    S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER();

        if(MACH_TYPE_SMDK2410 == gd->bd->bi_arch_number )
            return((clk_power->CLKDIVN & 0x1) ? get_HCLK()/2 : get_HCLK());
        else if (MACH_TYPE_TQ2440 == gd->bd->bi_arch_number)
        {
            clkdiv = clk_power->CLKDIVN;
            camdiv = clk_power->CAMDIVN;
            /* work out clock scalings */
            switch (clkdiv & S3C2440_CLKDIVN_HDIVN_MASK) {
                case S3C2440_CLKDIVN_HDIVN_1:
                    hdiv = 1;
                    break;
                case S3C2440_CLKDIVN_HDIVN_2:
                    hdiv = 2;
                    break;
                case S3C2440_CLKDIVN_HDIVN_4_8:
                    hdiv = (camdiv & S3C2440_CAMDIVN_HCLK4_HALF) ? 8 : 4;
                    break;
                case S3C2440_CLKDIVN_HDIVN_3_6:
                    hdiv = (camdiv & S3C2440_CAMDIVN_HCLK3_HALF) ? 6 : 3;
                    break;
            }
            return get_FCLK() / hdiv / ((clkdiv & S3C2440_CLKDIVN_PDIVN)? 2:1);
        }
        else
            hang ();


}

现在怎么测试serial呢,直接烧入到nor flash即可,但由于tq2440自带的uboot就在nor,还得靠他到时候把code 烧入到nand flash的,所以只能download到SDRAM………………..,在此之前得稍微修改一下start.S code,禁止bl cpu_init_crit,使能bl memsetup 然后利用DNW download 到SDRAM地址为TEXT_BASE = 0x33F80000处即可,DNW有个选项:

[7] Download Program (uCOS-II or TQ2440_Test) to SDRAM and Run it

接着会有打印出来:

准备下载文件: Z:\u-boot-1.1.6\u-boot.bin

下载属性: 
文件大小        : 94816 (0MB)
起始地址        : 0x33f80000
结束地址        : 0x33f97260

开始下载...

Now, Downloading [ADDRESS:33f80000h,TOTAL:94826]
RECEIVED FILE SIZE:         94826 (92KB/S, 1S)
## Starting application at 0x33F80000 ...


U-Boot 1.1.6 (May 16 2015 - 11:11:55)

DRAM:  64 MB
Flash: 512 kB
*** Warning - bad CRC, using default environment

In:    serial
Out:   serial
Err:   serial
SMDK2410 # 

串口有信息出来就一切都好办了……….. ^_^
4. nor nand flash 移植
nor的很简单 tq2440的板子与tq2440.h里的CONFIG_AMD_LV800匹配,故直接更改这个即可,当然还要更改size,而且还要注意环境变量的存储,/* CFG_ENV_ADDR + CFG_ENV_SIZE <= PHYS_FLASH_SIZE*/

#if 0
#define CONFIG_AMD_LV400 1 /* uncomment this if you have a LV400 flash */
#endif
#define CONFIG_AMD_LV800 1 /* uncomment this if you have a LV800 flash */
#define CFG_MAX_FLASH_BANKS 1 /* max number of memory banks */
#ifdef CONFIG_AMD_LV800
#define PHYS_FLASH_SIZE 0x200000 //0x00100000 /* 1MB */
#define CFG_MAX_FLASH_SECT (19) /* max number of sectors on one chip */
/* CFG_ENV_ADDR + CFG_ENV_SIZE <= PHYS_FLASH_SIZE*/
#define CFG_ENV_ADDR (CFG_FLASH_BASE + 0x01E0000) /* addr of environment */ 
#define CFG_ENV_SIZE 0x10000 /* Total Size of Environment Sector */

继续看start_armboot()下文有:

#if (CONFIG_COMMANDS & CFG_CMD_NAND)
    puts ("NAND: ");
    nand_init();        /* go init the NAND */
#endif

所以启动nand的支持只要在tq2440.h增加nand cmd即可:

#define CONFIG_COMMANDS \
            (CONFIG_CMD_DFL  | \
            CFG_CMD_CACHE    | \
            CFG_CMD_NAND     | \
            /*CFG_CMD_EEPROM |*/ \
            /*CFG_CMD_I2C    |*/ \
            /*CFG_CMD_USB    |*/ \
            CFG_CMD_REGINFO  | \
            CFG_CMD_DATE     | \
            CFG_CMD_ELF)

继续进入nand_init() –> nand_init_chip() –> board_nand_init(nand) ,发现这个board_nand_init(nand)找不到 为extern,没错 这个要我们自己实现! 查看该nand结构体:

struct nand_chip {
    void  __iomem   *IO_ADDR_R;
    void  __iomem   *IO_ADDR_W;

    u_char      (*read_byte)(struct mtd_info *mtd);
    void        (*write_byte)(struct mtd_info *mtd, u_char byte);
    u16     (*read_word)(struct mtd_info *mtd);
    void        (*write_word)(struct mtd_info *mtd, u16 word);

    void        (*write_buf)(struct mtd_info *mtd, const u_char *buf, int len);
    void        (*read_buf)(struct mtd_info *mtd, u_char *buf, int len);
    int     (*verify_buf)(struct mtd_info *mtd, const u_char *buf, int len);
    void        (*select_chip)(struct mtd_info *mtd, int chip);
    int     (*block_bad)(struct mtd_info *mtd, loff_t ofs, int getchip);
    int     (*block_markbad)(struct mtd_info *mtd, loff_t ofs);
    void        (*hwcontrol)(struct mtd_info *mtd, int cmd);
    int     (*dev_ready)(struct mtd_info *mtd);
    void        (*cmdfunc)(struct mtd_info *mtd, unsigned command, int column, int page_addr);
    int     (*waitfunc)(struct mtd_info *mtd, struct nand_chip *this, int state);
    int     (*calculate_ecc)(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code);
    int     (*correct_data)(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc);
    void        (*enable_hwecc)(struct mtd_info *mtd, int mode);
    void        (*erase_cmd)(struct mtd_info *mtd, int page);
    int     (*scan_bbt)(struct mtd_info *mtd);
    int     eccmode;
    int     eccsize;
    int     eccbytes;
    int     eccsteps;
    int     chip_delay;
#if 0
    spinlock_t  chip_lock;
    wait_queue_head_t wq;
    nand_state_t    state;
#endif
    int     page_shift;
    int     phys_erase_shift;
    int     bbt_erase_shift;
    int     chip_shift;
    u_char      *data_buf;
    u_char      *oob_buf;
    int     oobdirty;
    u_char      *data_poi;
    unsigned int    options;
    int     badblockpos;
    int     numchips;
    unsigned long   chipsize;
    int     pagemask;
    int     pagebuf;
    struct nand_oobinfo *autooob;
    uint8_t     *bbt;
    struct nand_bbt_descr   *bbt_td;
    struct nand_bbt_descr   *bbt_md;
    struct nand_bbt_descr   *badblock_pattern;
    struct nand_hw_control  *controller;
    void        *priv;
};

主要的是填充必要的指针或者说指向具体的相关寄存器地址,后面有uboot自带的nand driver完成。由于nand的寄存器是跟IC 有关的,实现的board_nand_init(nand)就在u-boot-1.1.6\cpu\arm920t\s3c24x0下实现,在u-boot-1.1.6\cpu\arm920t\s3c24x0下新建文件nand_flash.c,code如下:

/* * Nand flash interface of s3c2410/s3c2440, by www.arm9.net * Changed from drivers/mtd/nand/s3c2410.c of kernel 2.6.13 */
#include <common.h>
#if (CONFIG_COMMANDS & CFG_CMD_NAND) && !defined(CFG_NAND_LEGACY)
#include <s3c2410.h>
#include <nand.h>
DECLARE_GLOBAL_DATA_PTR;
#define S3C2410_NFSTAT_READY (1<<0)
#define S3C2410_NFCONF_nFCE (1<<11)
#define S3C2440_NFSTAT_READY (1<<0)
#define S3C2440_NFCONT_nFCE (1<<1)
/* select chip, for s3c2410 */
static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip)
{
S3C2410_NAND * const s3c2410nand = S3C2410_GetBase_NAND();
if (chip == -1)
{
s3c2410nand->NFCONF |= S3C2410_NFCONF_nFCE;
}
else
{
s3c2410nand->NFCONF &= ~S3C2410_NFCONF_nFCE;
}
}
/* command and control functions, for s3c2410 * * Note, these all use tglx's method of changing the IO_ADDR_W field * to make the code simpler, and use the nand layer's code to issue the * command and address sequences via the proper IO ports. * */
static void s3c2410_nand_hwcontrol(struct mtd_info *mtd, int cmd)
{
S3C2410_NAND * const s3c2410nand = S3C2410_GetBase_NAND();
struct nand_chip *chip = mtd->priv;
switch (cmd)
{
case NAND_CTL_SETNCE:
case NAND_CTL_CLRNCE:
printf("%s: called for NCE\n", __FUNCTION__);
break;
case NAND_CTL_SETCLE:
chip->IO_ADDR_W = (void *)&s3c2410nand->NFCMD;
break;
case NAND_CTL_SETALE:
chip->IO_ADDR_W = (void *)&s3c2410nand->NFADDR;
break;
default:
chip->IO_ADDR_W = (void *)&s3c2410nand->NFDATA;
break;
}
}
/* s3c2410_nand_devready() * * returns 0 if the nand is busy, 1 if it is ready */
static int s3c2410_nand_devready(struct mtd_info *mtd)
{
S3C2410_NAND * const s3c2410nand = S3C2410_GetBase_NAND();
return (s3c2410nand->NFSTAT & S3C2410_NFSTAT_READY);
}
/* select chip, for s3c2440 */
static void s3c2440_nand_select_chip(struct mtd_info *mtd, int chip)
{
S3C2440_NAND * const s3c2440nand = S3C2440_GetBase_NAND();
if (chip == -1)
{
s3c2440nand->NFCONT |= S3C2440_NFCONT_nFCE;
}
else
{
s3c2440nand->NFCONT &= ~S3C2440_NFCONT_nFCE;
}
}
/* command and control functions */
static void s3c2440_nand_hwcontrol(struct mtd_info *mtd, int cmd)
{
S3C2440_NAND * const s3c2440nand = S3C2440_GetBase_NAND();
struct nand_chip *chip = mtd->priv;
switch (cmd)
{
case NAND_CTL_SETNCE:
case NAND_CTL_CLRNCE:
printf("%s: called for NCE\n", __FUNCTION__);
break;
case NAND_CTL_SETCLE:
chip->IO_ADDR_W = (void *)&s3c2440nand->NFCMD;
break;
case NAND_CTL_SETALE:
chip->IO_ADDR_W = (void *)&s3c2440nand->NFADDR;
break;
default:
chip->IO_ADDR_W = (void *)&s3c2440nand->NFDATA;
break;
}
}
/* s3c2440_nand_devready() * * returns 0 if the nand is busy, 1 if it is ready */
static int s3c2440_nand_devready(struct mtd_info *mtd)
{
S3C2440_NAND * const s3c2440nand = S3C2440_GetBase_NAND();
return (s3c2440nand->NFSTAT & S3C2440_NFSTAT_READY);
}
/* * Nand flash hardware initialization: * Set the timing, enable NAND flash controller */
static void s3c24x0_nand_inithw(void)
{
S3C2410_NAND * const s3c2410nand = S3C2410_GetBase_NAND();
S3C2440_NAND * const s3c2440nand = S3C2440_GetBase_NAND();
#define TACLS 0
#define TWRPH0 4
#define TWRPH1 2
if (gd->bd->bi_arch_number == MACH_TYPE_SMDK2410)
{
/* Enable NAND flash controller, Initialize ECC, enable chip select, Set flash memory timing */
s3c2410nand->NFCONF =
(1<<15)|(1<<12)|(1<<11)|(TACLS<<8)|(TWRPH0<<4)|(TWRPH1<<0);
}
else
{
/* Set flash memory timing */
s3c2440nand->NFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4);
/* Initialize ECC, enable chip select, NAND flash controller enable */
s3c2440nand->NFCONT = (1<<4)|(0<<1)|(1<<0);
}
}
/* * Called by drivers/nand/nand.c, initialize the interface of nand flash */
void board_nand_init(struct nand_chip *chip)
{
S3C2410_NAND * const s3c2410nand = S3C2410_GetBase_NAND();
S3C2440_NAND * const s3c2440nand = S3C2440_GetBase_NAND();
s3c24x0_nand_inithw();
if (gd->bd->bi_arch_number == MACH_TYPE_SMDK2410)
{
chip->IO_ADDR_R = (void *)&s3c2410nand->NFDATA;
chip->IO_ADDR_W = (void *)&s3c2410nand->NFDATA;
chip->hwcontrol = s3c2410_nand_hwcontrol;
chip->dev_ready = s3c2410_nand_devready;
chip->select_chip = s3c2410_nand_select_chip;
chip->options = 0;
}
else
{
chip->IO_ADDR_R = (void *)&s3c2440nand->NFDATA;
chip->IO_ADDR_W = (void *)&s3c2440nand->NFDATA;
chip->hwcontrol = s3c2440_nand_hwcontrol;
chip->dev_ready = s3c2440_nand_devready;
chip->select_chip = s3c2440_nand_select_chip;
chip->options = 0;
}
chip->eccmode = NAND_ECC_SOFT;
}
#endif

修改当前目录makefile加入编译:

COBJS   = i2c.o interrupts.o serial.o speed.o \
      usb_ohci.o nand_flash.o

make进行编译 发现依次有如下等警告:

u-boot-1.1.6/include/linux/mtd/nand.h:412: error: `NAND_MAX_CHIPS' undeclared here (not in a function)
nand.c:38: error: `CFG_NAND_BASE' undeclared here (not in a function)

在tq2440.h增加如下申明:

/* nand configure */
#define CFG_MAX_NAND_DEVICE 1
#define NAND_MAX_CHIPS 1
#define CFG_NAND_BASE 0

5.环境变量设置,由于环境的设置依赖存储介质,所以放在nor 或nand设置后来设置,搜索env_init()发现在env_flash.c env_nand.c 都有实现 怎么区分呢? 可以查看其code前面几行有相应的宏加以判断:

#if defined(CFG_ENV_IS_IN_NAND) /* Environment is in Nand Flash */
#if defined(CFG_ENV_IS_IN_FLASH) /* Environment is in Flash */

所以由于以后要在nand启动,故在tq2440.h设置环境变量放置在nand:

/#define CFG_ENV_IS_IN_FLASH 1
#define CFG_ENV_IS_IN_NAND 1

当然 make编译会出现error:

u-boot-1.1.6/include/environment.h:74:4: 错误: #error "Need to define CFG_ENV_OFFSET when using CFG_ENV_IS_IN_NAND"

//因为nor的偏移地址是直接赋值
#define CFG_ENV_ADDR (CFG_FLASH_BASE + 0x01E0000) /* addr of environment */ 

//nand 用宏标记
#define CFG_ENV_OFFSET 0x40000 //256k,it enouph fo store uboot

再次make编译download到指定SDRAM地址如下打印:

准备下载文件: Z:\u-boot-1.1.6\u-boot.bin

下载属性: 
文件大小        : 131920 (0MB)
起始地址        : 0x33f80000
结束地址        : 0x33fa0350

开始下载...

Now, Downloading [ADDRESS:33f80000h,TOTAL:131930]
RECEIVED FILE SIZE:        131930 (128KB/S, 1S)
## Starting application at 0x33F80000 ...


U-Boot 1.1.6 (May 16 2015 - 12:27:23)

DRAM:  64 MB
Flash:  2 MB
NAND:  256 MiB
*** Warning - bad CRC or NAND, using default environment

In:    serial
Out:   serial
Err:   serial
[TQ2440 ]# 

测试是否支持nand:

[TQ2440 ]# help
nand    - NAND sub-system
nboot   - boot from NAND device
[TQ2440 ]# nand info

Device 0: NAND 256MiB 3,3V 8-bit, sector size 128 KiB


[TQ2440 ]# nand dump 0 10
Page 00000000 dump:
06 00 00 ea fe ff ff ea  fe ff ff ea fe ff ff ea
fe ff ff ea fe ff ff ea  11 00 00 ea fe ff ff ea
01 da a0 e3 18 00 00 eb  1b 00 00 eb 58 00 00 eb
5b 00 00 eb 68 00 00 eb  70 00 00 eb 30 00 00 eb
4a 00 00 eb 0d d3 a0 e3  28 f0 9f e5 d2 f0 21 e3
01 da a0 e3 5f f0 21 e3  1c e0 9f e5 1c f0 9f e5
fe ff ff ea 04 e0 4e e2  ff 5f 2d e9 10 e0 9f e5
10 f0 9f e5 ff 9f fd e8  4c 00 00 30 60 00 00 30
ac 02 00 30 74 00 00 30  4c 02 00 30 00 20 a0 e3
53 34 a0 e3 00 20 83 e5  0e f0 a0 e1 13 c3 a0 e3

========
[TQ2440 ]# nand erase 0 10

NAND erase: device 0 offset 0x0, size 0x10
Erasing at 0x0 -- 819200% complete.
OK
============
[TQ2440 ]# nand dump 0 10
Page 00000000 dump:
ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff

测试 OK

6.网口设置,由于我的是笔记本连WIFI 板子只有网口,所以暂时先不移植网络部分~~

7.同时支持nor nand启动:
现在最后一步就是支持从nand启动了,之前的测试都是直接从SDRAM download的,现在要同时支持从nor和nand启动,先enable cpu_init_crit disable memsetup
先实现nand驱动,在u-boot-1.1.6\board\tq2440新建nand_for_copy.c:

#include <asm-arm/types.h>
#include <s3c2400.h>
#include <s3c24x0.h>

#define GSTATUS1 (*(volatile unsigned int *)0x560000B0)
#define BUSY 1

#define NAND_SECTOR_SIZE 512
#define NAND_BLOCK_MASK (NAND_SECTOR_SIZE - 1)

#define NAND_SECTOR_SIZE_LP 2048
#define NAND_BLOCK_MASK_LP (NAND_SECTOR_SIZE_LP - 1)


char bLARGEBLOCK;           //HJ_add 20090807
char b128MB;                //HJ_add 20090807


/* 渚涘閮ㄨ皟鐢ㄧ殑鍑芥暟 */
void nand_init_ll(void);
int nand_read_ll(unsigned char *buf, unsigned long start_addr, int size);
int nand_read_ll_lp(unsigned char *buf, unsigned long start_addr, int size);

/* NAND Flash鎿嶄綔鐨勬€诲叆鍙? 瀹冧滑灏嗚皟鐢⊿3C2410鎴朣3C2440鐨勭浉搴斿嚱鏁?*/
static void nand_reset(void);
static void wait_idle(void);
static void nand_select_chip(void);
static void nand_deselect_chip(void);
static void write_cmd(int cmd);
static void write_addr(unsigned int addr);
static void write_addr_lp(unsigned int addr);
static unsigned char read_data(void);
int NF_ReadID(void);                //HJ_add 20090807

/* S3C2440鐨凬AND Flash澶勭悊鍑芥暟 */
static void s3c2440_nand_reset(void);
static void s3c2440_wait_idle(void);
static void s3c2440_nand_select_chip(void);
static void s3c2440_nand_deselect_chip(void);
static void s3c2440_write_cmd(int cmd);
static void s3c2440_write_addr(unsigned int addr);
static void s3c2440_write_addr_lp(unsigned int addr);
static unsigned char s3c2440_read_data(void);

/* S3C2440鐨凬AND Flash鎿嶄綔鍑芥暟 */

/* 澶嶄綅 */
static void s3c2440_nand_reset(void)
{
    s3c2440_nand_select_chip();
    s3c2440_write_cmd(0xff);  // 澶嶄綅鍛戒护
    s3c2440_wait_idle();
    s3c2440_nand_deselect_chip();
}

/* 绛夊緟NAND Flash灏辩华 */
static void s3c2440_wait_idle(void)
{
    int i;
    S3C2440_NAND * s3c2440nand = (S3C2440_NAND *)0x4e000000;
    volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFSTAT;

    while(!(*p & BUSY))
        for(i=0; i<10; i++);
}

/* 鍙戝嚭鐗囬€変俊鍙?*/
static void s3c2440_nand_select_chip(void)
{
    int i;
    S3C2440_NAND * s3c2440nand = (S3C2440_NAND *)0x4e000000;

    s3c2440nand->NFCONT &= ~(1<<1);
    for(i=0; i<10; i++);    
}

/* 鍙栨秷鐗囬€変俊鍙?*/
static void s3c2440_nand_deselect_chip(void)
{
    S3C2440_NAND * s3c2440nand = (S3C2440_NAND *)0x4e000000;

    s3c2440nand->NFCONT |= (1<<1);
}

/* 鍙戝嚭鍛戒护 */
static void s3c2440_write_cmd(int cmd)
{
    S3C2440_NAND * s3c2440nand = (S3C2440_NAND *)0x4e000000;

    volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFCMD;
    *p = cmd;
}

/* 鍙戝嚭鍦板潃 */
static void s3c2440_write_addr(unsigned int addr)
{
    int i;
    S3C2440_NAND * s3c2440nand = (S3C2440_NAND *)0x4e000000;
    volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFADDR;

    *p = addr & 0xff;
    for(i=0; i<10; i++);
    *p = (addr >> 9) & 0xff;
    for(i=0; i<10; i++);
    *p = (addr >> 17) & 0xff;
    for(i=0; i<10; i++);
    *p = (addr >> 25) & 0xff;
    for(i=0; i<10; i++);
}


/* 鍙戝嚭鍦板潃 */
static void s3c2440_write_addr_lp(unsigned int addr)
{
    int i;
    S3C2440_NAND * s3c2440nand = (S3C2440_NAND *)0x4e000000;
    volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFADDR;
    int col, page;

    col = addr & NAND_BLOCK_MASK_LP;
    page = addr / NAND_SECTOR_SIZE_LP;

    *p = col & 0xff;            /* Column Address A0~A7 */
    for(i=0; i<10; i++);        
    *p = (col >> 8) & 0x0f;     /* Column Address A8~A11 */
    for(i=0; i<10; i++);
    *p = page & 0xff;           /* Row Address A12~A19 */
    for(i=0; i<10; i++);
    *p = (page >> 8) & 0xff;    /* Row Address A20~A27 */
    for(i=0; i<10; i++);
if (b128MB == 0)
    *p = (page >> 16) & 0x03;   /* Row Address A28~A29 */
    for(i=0; i<10; i++);
}

/* 璇诲彇鏁版嵁 */
static unsigned char s3c2440_read_data(void)
{
    S3C2440_NAND * s3c2440nand = (S3C2440_NAND *)0x4e000000;
    volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFDATA;
    return *p;
}


/* 鍦ㄧ涓€娆′娇鐢∟AND Flash鍓嶏紝澶嶄綅涓€涓婲AND Flash */
static void nand_reset(void)
{
    s3c2440_nand_reset();
}

static void wait_idle(void)
{
    s3c2440_wait_idle();
}

static void nand_select_chip(void)
{
    int i;

    s3c2440_nand_select_chip();

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

static void nand_deselect_chip(void)
{
    s3c2440_nand_deselect_chip();
}

static void write_cmd(int cmd)
{
    s3c2440_write_cmd(cmd);
}
static void write_addr(unsigned int addr)
{
    s3c2440_write_addr(addr);
}

static void write_addr_lp(unsigned int addr)
{
    s3c2440_write_addr_lp(addr);
}

static unsigned char read_data(void)
{
    return s3c2440_read_data();
}

/* 鍒濆鍖朜AND Flash */
void nand_init_ll(void)
{
    S3C2440_NAND * s3c2440nand = (S3C2440_NAND *)0x4e000000;

    #define TACLS 0
    #define TWRPH0 3
    #define TWRPH1 0

    /* 璁剧疆鏃跺簭 */
    s3c2440nand->NFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4);
    /* 浣胯兘NAND Flash鎺у埗鍣? 鍒濆鍖朎CC, 绂佹鐗囬€?*/
    s3c2440nand->NFCONT = (1<<4)|(1<<1)|(1<<0);

    /* 澶嶄綅NAND Flash */
    nand_reset();
}
#if 1
int NF_ReadID(void)
{
    char pMID;
    char pDID;
    int  nBuff;
    char   n4thcycle;
    int i;
    S3C2440_NAND * s3c2440nand = (S3C2440_NAND *)0x4e000000;
    volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFADDR;

    b128MB = 1;
    n4thcycle = nBuff = 0;

    nand_init_ll();
    nand_select_chip();
    write_cmd(0x90);    // read id command
    *p=0x00 & 0xff;
    for ( i = 0; i < 100; i++ );

    pMID = read_data();
    pDID =  read_data();
    nBuff =  read_data();
    n4thcycle = read_data();

    nand_deselect_chip();

    if (pDID >= 0xA0)
    {
        b128MB = 0;
    }

    return (pDID);
}
#endif

/* 璇诲嚱鏁?*/
int nand_read_ll(unsigned char *buf, unsigned long start_addr, int size)
{
    int i, j;
    char dat;
    S3C2440_NAND * s3c2440nand = (S3C2440_NAND *)0x4e000000;
    volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFADDR;


    if ((start_addr & NAND_BLOCK_MASK) || (size & NAND_BLOCK_MASK))
    {
        return -1;    /* 鍦板潃鎴栭暱搴︿笉瀵归綈 */
    }

    /* 閫変腑鑺墖 */
    nand_select_chip();

    for(i=start_addr; i < (start_addr + size);)
    {
/* Check Bad Block */
if(1){
        /* 鍙戝嚭READ0鍛戒护 */
        write_cmd(0x50);

        *p = 5;
        for(j=0; j<10; j++);
        *p = (i >> 9) & 0xff;
        for(j=0; j<10; j++);
        *p = (i >> 17) & 0xff;
        for(j=0; j<10; j++);
        *p = (i >> 25) & 0xff;
        for(j=0; j<10; j++);
        wait_idle();

        dat = read_data();
        write_cmd(0);

        /* 鍙栨秷鐗囬€変俊鍙?*/
        nand_deselect_chip();
        if(dat != 0xff)
            i += 16384;     // 1 Block = 512*32= 16384
/* Read Page */
        /* 閫変腑鑺墖 */
        nand_select_chip();
}
        /* 鍙戝嚭READ0鍛戒护 */
        write_cmd(0);

        /* Write Address */
        write_addr(i);
        wait_idle();

        for(j=0; j < NAND_SECTOR_SIZE; j++, i++)
        {
            *buf = read_data();
            buf++;
        }
    }

    /* 鍙栨秷鐗囬€変俊鍙?*/
    nand_deselect_chip();

    return 0;
}

/* 璇诲嚱鏁? * Large Page */
int nand_read_ll_lp(unsigned char *buf, unsigned long start_addr, int size)
{
    int i, j;
    char dat;
    S3C2440_NAND * s3c2440nand = (S3C2440_NAND *)0x4e000000;
    volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFADDR;

    if ((start_addr & NAND_BLOCK_MASK_LP) || (size & NAND_BLOCK_MASK_LP))
    {
        return -1;    /* 鍦板潃鎴栭暱搴︿笉瀵归綈 */
    }

    /* 閫変腑鑺墖 */
    nand_select_chip();

    for(i=start_addr; i < (start_addr + size);)
    {
/* Check Bad Block */
if(1){
        int col, page;

        col = i & NAND_BLOCK_MASK_LP;
        page = i / NAND_SECTOR_SIZE_LP;
        /* 鍙戝嚭READ0鍛戒护 */
        write_cmd(0x00);

        *p = 5;
        for(j=0; j<10; j++);
        *p = 8;
        for(j=0; j<10; j++);
        *p = page & 0xff;       /* Row Address A12~A19 */
        for(j=0; j<10; j++);
        *p = (page >> 8) & 0xff;        /* Row Address A20~A27 */
        for(j=0; j<10; j++);
if (b128MB == 0)
        *p = (page >> 16) & 0x03;       /* Row Address A28~A29 */
        for(j=0; j<10; j++);

        write_cmd(0x30);
        wait_idle();

        dat = read_data();

        /* 鍙栨秷鐗囬€変俊鍙?*/
        nand_deselect_chip();
        if(dat != 0xff)
            i += 131072;        // 1 Block = 2048*64= 131072
/* Read Page */
        /* 閫変腑鑺墖 */
        nand_select_chip();
}
        /* 鍙戝嚭READ0鍛戒护 */
        write_cmd(0);

        /* Write Address */
        write_addr_lp(i);
        write_cmd(0x30);
        wait_idle();

        for(j=0; j < NAND_SECTOR_SIZE_LP; j++, i++)
        {
            *buf = read_data();
            buf++;
        }
    }

    /* 鍙栨秷鐗囬€変俊鍙?*/
    nand_deselect_chip();

    return 0;
}

int bBootFrmNORFlash(void)
{
    volatile unsigned int *pdw = (volatile unsigned int *)0;
    unsigned int dwVal;

    /* * 鏃犺鏄粠NOR Flash杩樻槸浠嶯AND Flash鍚姩锛? * 鍦板潃0澶勪负鎸囦护"b Reset", 鏈哄櫒鐮佷负0xEA00000B锛? * 瀵逛簬浠嶯AND Flash鍚姩鐨勬儏鍐碉紝鍏跺紑濮?KB鐨勪唬鐮佷細澶嶅埗鍒癈PU鍐呴儴4K鍐呭瓨涓紝 * 瀵逛簬浠嶯OR Flash鍚姩鐨勬儏鍐碉紝NOR Flash鐨勫紑濮嬪湴鍧€鍗充负0銆? * 瀵逛簬NOR Flash锛屽繀椤婚€氳繃涓€瀹氱殑鍛戒护搴忓垪鎵嶈兘鍐欐暟鎹紝 * 鎵€浠ュ彲浠ユ牴鎹繖鐐瑰樊鍒潵鍒嗚鲸鏄粠NAND Flash杩樻槸NOR Flash鍚姩: * 鍚戝湴鍧€0鍐欏叆涓€涓暟鎹紝鐒跺悗璇诲嚭鏉ワ紝濡傛灉娌℃湁鏀瑰彉鐨勮瘽灏辨槸NOR Flash */

    dwVal = *pdw;       
    *pdw = 0x12345678;
    if (*pdw != 0x12345678)
    {
        return 1;
    }
    else
    {
        *pdw = dwVal;
        return 0;
    }
}

int CopyCode2Ram(unsigned long start_addr, unsigned char *buf, int size)
{
    unsigned int *pdwDest;
    unsigned int *pdwSrc;
    int i;

    if (bBootFrmNORFlash())
    {
        pdwDest = (unsigned int *)buf;
        pdwSrc  = (unsigned int *)start_addr;
        /* 浠?NOR Flash鍚姩 */
        for (i = 0; i < size / 4; i++)
        {
            pdwDest[i] = pdwSrc[i];
        }
        return 0;
    }
    else
    {
        /* 鍒濆鍖朜AND Flash */
        nand_init_ll();

        /* 浠?NAND Flash鍚姩 */
        if (NF_ReadID() == 0x76 )
            nand_read_ll(buf, start_addr, (size + NAND_BLOCK_MASK)&~(NAND_BLOCK_MASK));
        else
            nand_read_ll_lp(buf, start_addr, (size + NAND_BLOCK_MASK_LP)&~(NAND_BLOCK_MASK_LP));
        return 0;
    }
}

然后在start.S:

relocate:               /* relocate U-Boot to RAM */
    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     clear_bss
    ldr r2, _armboot_start
    ldr r3, _bss_start
    sub r2, r3, r2      /* r2 <- size of armboot */
#if 1
    bl  CopyCode2Ram
#else
    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
#endif /* CONFIG_SKIP_RELOCATE_UBOOT */

即可,这里令人奇怪的是我将之前《嵌入式学习笔记005-裸奔篇之flash》的nand直接copy到nand_for_copy.c不行~~~~~~~~~~~~ 好无语 -_-
make 编译利用天嵌自带在nor flash的bootloader选择:

[1] Download u-boot or STEPLDR.nb1 or other bootloader to Nand Flash

将code烧入到nand,接着断电将拨码开关拨到nand启动选项后再上电即可:

U-Boot 1.1.6 (May 17 2015 - 10:36:23)

DRAM:  64 MB
Flash:  2 MB
NAND:  256 MiB
*** Warning - bad CRC or NAND, using default environment

In:    serial
Out:   serial
Err:   serial
[TQ2440 ]# 

至此整个uboot的移植就基本完成了,到学习linux kernel时再讲解bootcmd及传参相关的以实现uboot启动kernel~~~~~~

整个工程的源码在我的资源空间:
http://download.csdn.net/detail/fzk374470412/8708973

下载后先解压:
tar jxvf u-boot-1.1.6 -C xxx_your_path
make tq2440_config
make all

你可能感兴趣的:(s3c2440,TQ2440,uboot移植,nand启动)