移植uboot到2440

来源:互联网 发布:ubuntu 电源设置打不开 编辑:程序博客网 时间:2024/06/05 15:00

一、修改顶层Makefile,加入:

shanl2440_config :unconfig@$(MKCONFIG) $(@:_config=) arm arm920t shanl2440 NULL s3c24x0
arm: CPU 的架构(ARCH)
arm920t: CPU 的类型(CPU),其对应于 cpu/arm920t 子目录。
shanl2440: 开发板的型号(BOARD),对应于 board/shanl2440 目录。
NULL: 开发者/或经销商(vender)。(此处没加 vender,为 NULL。) ,如果有vendor,则开发板的目录就在board/vendor/shanl下
s3c24x0: 片上系统(SOC)。


二、建立自己开发板的board信息:

在board下面建立shanl2440目录,并把smdk2410目录中的内容复制过来:

shanl@shanl-Aspire-4740:~/Kernel/u-boot-1.1.6/board$ mkdir shanl2440shanl@shanl-Aspire-4740:~/Kernel/u-boot-1.1.6/board$ cp smdk2410/* shanl2440/

三、编译:

发现出现一下错误:

/home/shanl/Kernel/u-boot-1.1.6/include/config.h:2: fatal error: configs/shanl2440.h: 没有那个文件或目录
解决办法:

进入相应的目录,将2410的配置复制一份shanl2440.h

shanl@shanl-Aspire-4740:~/Kernel/u-boot-1.1.6$ cd include/configs/shanl@shanl-Aspire-4740:~/Kernel/u-boot-1.1.6/include/configs$ cp smdk2410.h shanl2440.h
重新make一下,问题解决,会在根目录下面生成u-boot.bin.

这个u-boot.bin只是披了一层2440外衣的2410可执行程序。下面需要对代码做相关的修改从而支持2440

四、加入板子的配置:

在include\configs\Shanl2440.h中加入:

#defineCONFIG_SHANL24401/* in a SAMSUNG S3C2440 SoC     */
五、关闭看门狗和中断:

将:

/* turn off the watchdog */#if defined(CONFIG_S3C2400)# define pWTCON0x15300000# define INTMSK0x14400008/* Interupt-Controller base addresses */# define CLKDIVN0x14800014/* clock divisor register */#elif defined(CONFIG_S3C2410)# define pWTCON0x53000000# define INTMSK0x4A000008/* Interupt-Controller base addresses */# define INTSUBMSK0x4A00001C# define CLKDIVN0x4C000014/* clock divisor register */#endif#if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410)    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
修改为:

/* turn off the watchdog */#if defined(CONFIG_S3C2400)# define pWTCON0x15300000# define INTMSK0x14400008/* Interupt-Controller base addresses */# define CLKDIVN0x14800014/* clock divisor register */#elif defined(CONFIG_S3C2410) || defined(CONFIG_SHANL2440)# define pWTCON0x53000000# define INTMSK0x4A000008/* Interupt-Controller base addresses */# define INTSUBMSK0x4A00001C# define CLKDIVN0x4C000014/* clock divisor register */#endif#if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410) || defined(CONFIG_SHANL2440)    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) || defined(CONFIG_SHANL2440)    ldr    r1, =0x3ff    ldr    r0, =INTSUBMSK    str    r1, [r0]# endif

六、MMU和SDRAM的设置:

将:

/* * we do sys-critical inits only at reboot, * not when booting from ram! */#ifndef CONFIG_SKIP_LOWLEVEL_INITblcpu_init_crit#endif
改为:

/* * we do sys-critical inits only at reboot, * not when booting from ram! */#ifndef CONFIG_SKIP_LOWLEVEL_INITadr 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 */blnecpu_init_crit#endif
对当前所在地址做一下判断,是运行到sdram上还是nand上,如果已经在sdram上了,就跳过mmu和sdram的设置


七、设置时钟:

首先设置栈,将栈的设置代码放到mmu和sdram设置的后面:

代码如下:

blnecpu_init_crit#endif/* Set up the stack    */stack_setup:ldrr0, _TEXT_BASE/* upper 128 KiB: relocated uboot   */subr0, r0, #CFG_MALLOC_LEN/* malloc area                      */subr0, r0, #CFG_GBL_DATA_SIZE /* bdinfo                        */#ifdef CONFIG_USE_IRQsubr0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)#endifsubsp, r0, #12/* leave 3 words for abort-stack    */
然后跳用c函数对时钟进行设置:

#ifndef CONFIG_SKIP_LOWLEVEL_INIT    bl clock_init#endif    
在 board\shanl2440下面建立文件Boot_init.c

加入时钟的初始化代码:

static inline void delay (unsigned long loops){    __asm__ volatile ("1:\n"      "subs %0, %1, #1\n"      "bne 1b":"=r" (loops):"0" (loops));}/* S3C2440: Mpll = (2*m * Fin) / (p * 2^s), UPLL = (m * Fin) / (p * 2^s) * m = M (the value for divider M)+ 8, p = P (the value for divider P) + 2 */#define S3C2440_MPLL_400MHZ     ((0x5c<<12)|(0x01<<4)|(0x01))#define S3C2440_UPLL_48MHZ      ((0x38<<12)|(0x02<<4)|(0x02))#define S3C2440_CLKDIV          (0x05) // | (1<<3))    /* FCLK:HCLK:PCLK = 1:4:8, UCLK = UPLL/2 */void clock_init(void){S3C24X0_CLOCK_POWER *clk_power = (S3C24X0_CLOCK_POWER *)0x4C000000;        /* FCLK:HCLK:PCLK = 1:4:8 */        clk_power->CLKDIVN = S3C2440_CLKDIV;        /* change to asynchronous bus mod */        __asm__(    "mrc    p15, 0, r1, c1, c0, 0\n"    /* read ctrl register   */                      "orr    r1, r1, #0xc0000000\n"      /* Asynchronous         */                      "mcr    p15, 0, r1, c1, c0, 0\n"    /* write ctrl register  */                      :::"r1"                    );        /* to reduce PLL lock time, adjust the LOCKTIME register */        clk_power->LOCKTIME = 0xFFFFFFFF;        /* configure UPLL */        clk_power->UPLLCON = S3C2440_UPLL_48MHZ;        /* some delay between MPLL and UPLL */        delay (4000);        /* configure MPLL */        clk_power->MPLLCON = S3C2440_MPLL_400MHZ;        /* some delay between MPLL and UPLL */        delay (8000);}
修改board\shanl2440下的Makefile:

COBJS := shanl2440.o flash.o board_init.o SOBJS := lowlevel_init.o 

时钟设置好了,还要修改一个文件speed.c,这个文件供uboot第2阶段使用,修改后的文件如下(以后再分析):

#include <common.h>#if defined(CONFIG_S3C2400) || defined (CONFIG_S3C2410) || defined (CONFIG_TRAB)#if defined(CONFIG_S3C2400)#include <s3c2400.h>#elif defined(CONFIG_S3C2410) || defined (CONFIG_SHANL2440) #include <s3c2410.h>#endifDECLARE_GLOBAL_DATA_PTR;#define MPLL 0#define UPLL 1/* ------------------------------------------------------------------------- *//* NOTE: This describes the proper use of this file. * * CONFIG_SYS_CLK_FREQ should be defined as the input frequency of the PLL. * * get_FCLK(), get_HCLK(), get_PCLK() and get_UCLK() return the clock of * the specified bus in HZ. *//* ------------------------------------------------------------------------- */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;    /* support both of S3C2410 and S3C2440, by www.100ask.net */   return((CONFIG_SYS_CLK_FREQ * m * 2) / (p << s));   /* S3C2440 */}/* return FCLK frequency */ulong get_FCLK(void){    return(get_PLLCLK(MPLL));}/* for s3c2440 */#define S3C2440_CLKDIVN_PDIVN        (1<<0)#define S3C2440_CLKDIVN_HDIVN_MASK   (3<<1)#define S3C2440_CLKDIVN_HDIVN_1      (0<<1)#define S3C2440_CLKDIVN_HDIVN_2      (1<<1)#define S3C2440_CLKDIVN_HDIVN_4_8    (2<<1)#define S3C2440_CLKDIVN_HDIVN_3_6    (3<<1)#define S3C2440_CLKDIVN_UCLK         (1<<3)#define S3C2440_CAMDIVN_CAMCLK_MASK  (0xf<<0)#define S3C2440_CAMDIVN_CAMCLK_SEL   (1<<4)#define S3C2440_CAMDIVN_HCLK3_HALF   (1<<8)#define S3C2440_CAMDIVN_HCLK4_HALF   (1<<9)#define S3C2440_CAMDIVN_DVSEN        (1<<12)/* return HCLK frequency */ulong get_HCLK(void){    S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER();    unsigned long clkdiv;    unsigned long camdiv;    int hdiv = 1;        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;    }}/* return PCLK frequency */ulong get_PCLK(void){    S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER();    unsigned long clkdiv;    unsigned long camdiv;    int hdiv = 1;         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);     }/* return UCLK frequency */ulong get_UCLK(void){    return(get_PLLCLK(UPLL));}#endif /* defined(CONFIG_S3C2400) || defined (CONFIG_S3C2410) || defined (CONFIG_TRAB) */


八、重定位代码:


#ifndef CONFIG_SKIP_RELOCATE_UBOOTrelocate:/* relocate U-Boot to RAM    */adrr0, _start/* r0 <- current position of code   */ldrr1, _TEXT_BASE/* test if we run from flash or RAM */cmp     r0, r1                  /* don't reloc during debug         */beq     stack_setupldrr2, _armboot_startldrr3, _bss_startsubr2, r3, r2/* r2 <- size of armboot            */addr2, r0, r2/* r2 <- source end address         */copy_loop:ldmiar0!, {r3-r10}/* copy from source address [r0]    */stmiar1!, {r3-r10}/* copy to   target address [r1]    */cmpr0, r2/* until source end addreee [r2]    */blecopy_loop#endif/* CONFIG_SKIP_RELOCATE_UBOOT */

修改为:

#ifndef CONFIG_SKIP_RELOCATE_UBOOTrelocate:/* relocate U-Boot to RAM    */adrr0, _start/* r0 <- current position of code   */ldrr1, _TEXT_BASE/* test if we run from flash or RAM */cmp     r0, r1                  /* don't reloc during debug         */beq     clear_bssldrr2, _armboot_startldrr3, _bss_startsubr2, r3, r2/* r2 <- size of armboot            */#if 1bl  CopyCode2Ram/* r0: source, r1: dest, r2: size */#elseaddr2, r0, r2/* r2 <- source end address         */copy_loop:ldmiar0!, {r3-r10}/* copy from source address [r0]    */stmiar1!, {r3-r10}/* copy to   target address [r1]    */cmpr0, r2/* until source end addreee [r2]    */blecopy_loop#endif#endif/* CONFIG_SKIP_RELOCATE_UBOOT */
对于CopyCode2Ram的实现可以在boot_init.c中添加,主要是nandflash的读操作:

#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)/* 供外部调用的函数 */void nand_init_ll(void);void nand_read_ll(unsigned char *buf, unsigned long start_addr, int size);/* NAND Flash操作的总入口, 它们将调用S3C2410或S3C2440的相应函数 */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 unsigned char read_data(void);/* S3C2440的NAND 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 unsigned char s3c2440_read_data(void);/* S3C2440的NAND 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++);    *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;}/* 在第一次使用NAND Flash前,复位一下NAND 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();}/* 初始化NAND Flash */void nand_init_ll(void){S3C2440_NAND * s3c2440nand = (S3C2440_NAND *)0x4e000000;#define TACLS   0#define TWRPH0  2#define TWRPH1  0/* 设置时序 */        s3c2440nand->NFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4);        /* 使能NAND Flash控制器, 初始化ECC, 禁止片选 */        s3c2440nand->NFCONT = (1<<4)|(1<<1)|(1<<0);/* 复位NAND Flash */nand_reset();}/* 读函数 */void nand_read_ll(unsigned char *buf, unsigned long start_addr, int size){    int i, j;        if ((start_addr & NAND_BLOCK_MASK) || (size & NAND_BLOCK_MASK)) {        return ;    /* 地址或长度不对齐 */    }    /* 选中芯片 */    nand_select_chip();    for(i=start_addr; i < (start_addr + size);) {      /* 发出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 ;}/* 读函数   * Large Page  */void nand_read_ll_lp(unsigned char *buf, unsigned long start_addr, int size){    int i, j;        if ((start_addr & NAND_BLOCK_MASK_LP) || (size & NAND_BLOCK_MASK_LP)) {        return ;    /* 地址或长度不对齐 */    }    /* 选中芯片 */    nand_select_chip();    for(i=start_addr; i < (start_addr + size);) {      /* 发出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 ;}int bBootFrmNORFlash(void){    volatile unsigned int *pdw = (volatile unsigned int *)0;    unsigned int dwVal;        /*     * 无论是从NOR Flash还是从NAND Flash启动,     * 地址0处为指令"bReset", 机器码为0xEA00000B,     * 对于从NAND Flash启动的情况,其开始4KB的代码会复制到CPU内部4K内存中,     * 对于从NOR 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    {        /* 初始化NAND Flash */nand_init_ll();        /* 从 NAND Flash启动 */        nand_read_ll_lp(buf, start_addr, (size + NAND_BLOCK_MASK_LP)&~(NAND_BLOCK_MASK_LP));return 0;    }}
然后在 include\S3c24x0.h加入2440nand寄存器的定义:

/* NAND FLASH (see S3C2440 manual chapter 6, www.100ask.net) */typedef struct {    S3C24X0_REG32   NFCONF;    S3C24X0_REG32   NFCONT;    S3C24X0_REG32   NFCMD;    S3C24X0_REG32   NFADDR;    S3C24X0_REG32   NFDATA;    S3C24X0_REG32   NFMECCD0;    S3C24X0_REG32   NFMECCD1;    S3C24X0_REG32   NFSECCD;    S3C24X0_REG32   NFSTAT;    S3C24X0_REG32   NFESTAT0;    S3C24X0_REG32   NFESTAT1;    S3C24X0_REG32   NFMECC0;    S3C24X0_REG32   NFMECC1;    S3C24X0_REG32   NFSECC;    S3C24X0_REG32   NFSBLK;    S3C24X0_REG32   NFEBLK;} /*__attribute__((__packed__))*/ S3C2440_NAND;

到这里,将uboot烧写到nandflash上就可以启动了:

U-Boot 1.1.6 (Mar 22 2013 - 11:33:36)DRAM:  64 MBFlash: 512 kB*** Warning - bad CRC, using default environmentIn:    serialOut:   serialErr:   serialSMDK2410 # SMDK2410 #