源码修改之从nand启动,支持nor和nand

    1.将之前写过的bootloader中init.c拷贝到到单板目录smdk2440下          

            修改重名函数,避免相互调用出错    

  

 2.修改start.s 

            将原来的重定位代码重新进行修改         

    bl nand_init                            bl nand_init_ll
                                                      
    mov r0, #0                              mov r0, #0               //原地址      
    ldr r1, =_start                         ldr r1,_TEXT_BASE        //链接地址    不用ldr r1, =_start是因为_start的地址可能在4k之外      
    ldr r2, =__bss_start      ----->        ldr r2, _bss_start_ofs   //需要拷贝代码的长度      
    sub r2, r2, r1                                    
                                            bl copy_code_to_sdram      
    bl copy_code_to_sdram                   bl clear_bss       
    bl clear_bss


    #define CONFIG_SYS_TEXT_BASE    0x33f80000        //预留1M的空间给uboot

 

       删除原来的重定位代码, board_init_f里也屏蔽掉relocate_code(addr_sp, id, addr);      

 ldr pc,=call_board_init_f    //跳到链接地址去运行


/* Set stackpointer in internal RAM to call board_init_f */
call_board_init_f:
    ldr    r0,=0x00000000
    bl    board_init_f    /* arch/arm/lib */

/*
    ...
    ...
*/

/*
* We are done. Do not return, instead branch to second part of board
* initialization, now running from RAM.
*/
#ifdef CONFIG_NAND_SPL
    ldr     r0, _nand_boot_ofs
    mov    pc, r0

 

3.修改启动第二阶段的代码

       原来void board_init_r(gd_t *id, ulong dest_addr)函数的参数一个是gd_t结构体的地址,一个是程序的链接的地址,现在自己传进去,修改代码让board_init_f()函数返回id的地址

   bl    board_init_f    /* arch/arm/lib */

    /*board_init_f返回的是gd_t的地址,存在r0中*/

    ldr r1,_TEXT_BASE
    bl board_init_r        //直接调用第二阶段的函数

  

 4.替换代码,修改makefile 重新编译

      首先修改 smdk2440/Makefile

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


COBJS    := smdk2410.o init.o
SOBJS    := lowlevel_init.o


SRCS    := $(SOBJS:.o=.S) $(COBJS:.o=.c)
OBJS    := $(addprefix $(obj),$(COBJS))
SOBJS    := $(addprefix $(obj),$(SOBJS))

 

去除-pie

    搜索找到定义 -pie的文件   grep  "\-pie" * -nR  

arch/x86/config.mk:43:LDFLAGS_FINAL += --gc-sections -pie
arch/arm/config.mk:75:LDFLAGS_u-boot += -pie
doc/README.arm-relocation:3:At arch level: add linker flag -pie

   修改arm/config.mk文件,注释掉 -pie

   修改链接脚本,把start.S,init.c, lowlevel.S 等文件放在最前面

         修改 arch/arm/cpu/u-boot.lds

    .text :
    {
        __image_copy_start = .;
        CPUDIR/start.o (.text)
        board/samsung/smdk2440/libsmdk2440.o(.text)
        *(.text)
    }

   

    将修改的文件

    arch/arm/lib/board.c

    arm920t/start.s

    smdk2440/int.c

    configs/smdk2440.h 

    include/common.h

    smdk2440/Makefile

    arm/config.mk 

    arch/arm/cpu/u-boot.lds    进行替换

 

    下载到nand上进行测试:

    usb  1  30000000   打开dnw下载自己编译好的uboot.bin

    nand    erase     0  80000

    nand    write    30000000    0    80000

 

    测试完,nand启动的结果:

U-Boot 2012.04.01 (Sep 21 2019 - 09:45:59)

CPUID: 32440001
FCLK:  400 MHz
HCLK:  100 MHz
PCLK:   50 MHz
DRAM:  64 MiB
WARNING: Caches not enabled
Flash: *** failed ***
### ERROR ### Please RESET the board ###

 

    搜索错误代码   “Flash:”,找到启动失败的原因,定位到第二阶段启动函数中

  puts("Flash: ");


    flash_size = flash_init();
    if (flash_size > 0) {
# ifdef CONFIG_SYS_FLASH_CHECKSUM
        char *s = getenv("flashchecksum");


        print_size(flash_size, "");
        /*
         * Compute and print flash CRC if flashchecksum is set to 'y'
         *
         * NOTE: Maybe we should add some WATCHDOG_RESET()? XXX
         */
        if (s && (*s == 'y')) {
            printf("  CRC: %08X", crc32(0,
                (const unsigned char *) CONFIG_SYS_FLASH_BASE,
                flash_size));
        }
        putc('\n');
# else    /* !CONFIG_SYS_FLASH_CHECKSUM */
        print_size(flash_size, "\n");
# endif /* CONFIG_SYS_FLASH_CHECKSUM */
    } else {
        puts(failed);
        hang();        //打印错误信息,卡死代码
    }

 

    报错主要是因为没有识别出norflash,修改flash_init()函数来支持norflash的功能

    首先打开调试命令,以支持debug调试命令,确定是哪个部分的导致flash初始化失败

    #define DEBUG            //    drive/mtd/cfi_flash.c

    #define _DEBUG    1

  

     然后定位到    flash_detect_legacy(phys_addr_t base, int banknum) 函数问题

 flash_read_jedec_ids(info);
 debug("JEDEC PROBE: ID %x %x %x\n",
      info->manufacturer_id,
      info->device_id,
      info->device_id2);
  if (jedec_flash_match(info, info->start[0]))    //匹配flash就是这里失败,然后直接返回           根据打印的    id和芯片手册的id进行比较
      break;

 

最后推导是jedec_table[i] 数组中没有存在的flash类型,这里只有8位的flash,跟打印出来的信息不一致,需要进行修改

   {
        .mfr_id        = (u16)MX_MANUFACT,        //厂家id
        .dev_id        = MX29LV040,                //设备ID
        .name        = "MXIC MX29LV040",
        .uaddr        = {
            [0] = MTD_UADDR_0x0555_0x02AA /* x8 */    //解锁命令
        },
        .DevSize    = SIZE_512KiB,                //内存大小
        .CmdSet        = P_ID_AMD_STD,            //指令集
        .NumEraseRegions= 1,                      //擦除区域
        .regions    = {
            ERASEINFO(0x10000, 8),
        }
    },

       

查看norflash的芯片手册,首先是厂家ID:00C2 和设备ID: 2249

 

   norflash不能直接写,每次发送写命令之前需要先发送解锁命令,写命令

    

 

擦除结构是指flash里面扇区的结构,根据手册可以知道共有四种类型的扇区

 

 

    {
        .mfr_id        = (u16)MX_MANUFACT,        //这款板子上的flash        c2 2249
        .dev_id        = 0x2249,                //设备id
        .name        = "MXIC MX29LV160DB",
        .uaddr        = {
            [1] = MTD_UADDR_0x0555_0x02AA /* 改成x16 的解锁地址(nor发出真正的写命令之前要先发解锁命令)*/
        },
        .DevSize    = SIZE_2MiB,    //总大小
        .CmdSet        = P_ID_AMD_STD,    //命令集
        .NumEraseRegions= 4,        //擦除区域
        .regions    = {
            ERASEINFO(16*1024, 1),    //要擦除区域的大小和块的个数(如果擦除区域=2,这个数组就会有两个擦除元素)
            ERASEINFO(8*1024, 2),
            ERASEINFO(32*1024, 1),
            ERASEINFO(64*1024, 31),
        }
    },

   

改完报错 “too many flash....”

   smdk2440.h     #define CONFIG_SYS_MAX_FLASH_SECT    (128)            //修改扇区数

 

修改完成,再将宏给屏蔽掉,重新下载运行:

U-Boot 2012.04.01 (Sep 23 2019 - 14:20:53)


CPUID: 32440001
FCLK:  400 MHz
HCLK:  100 MHz
PCLK:   50 MHz
DRAM:  64 MiB
WARNING: Caches not enabled
Flash: fwc addr (null) cmd f0 00f0 16bit x 16 bit
fwc addr 0000aaaa cmd aa 00aa 16bit x 16 bit
fwc addr 00005554 cmd 55 0055 16bit x 16 bit
fwc addr 0000aaaa cmd 90 0090 16bit x 16 bit
fwc addr (null) cmd f0 00f0 16bit x 16 bit
JEDEC PROBE: ID c2 2249 0
2 MiB
*** Warning - bad CRC, using default environment


In:    serial
Out:   serial
Err:   serial
Net:   CS8900-0

 

 

修改栈指针,之前没有设置完成    start.s        board.c

        ldr sp,base_sp 

   /*重新设置栈,否则栈指针还是指向0x30000f80,因为重定位函数不再是relocate_code(addr_sp, id, addr),所以board_init_f现在没有重新设置栈*/

    addr_sp &= ~0x07;    //8字节对齐后,sp指针确定
    
#else
    addr_sp += 128;    /* leave 32 words for abort-stack   */
    gd->irq_sp = addr_sp;
#endif


    base_sp = addr_sp;    //传回sp指针
    debug("New Stack Pointer is: %08lx\n", addr_sp);

 

    修改完支持norflash之后,更改代码支持nandflash

        首先打开nandflash的开关

            #define CONFIG_CMD_NAND

      然后编译程序会报错是因为此时只有2410的nand初始化函数,没有2440的nand初始化的函数,根据错误信息来修改对应的代码,首先将原来2410的s3c2410_nand.c复制成时s3c2440_nand.c,在这个基础上修改,修改makefile支持编译s3c2440_nand.c, 首先加入2440的开关,以支持2440对nand的支持

/*
* NAND configuration
*/
#ifdef CONFIG_CMD_NAND


#ifdef CONFIG_S3C2410
#define CONFIG_NAND_S3C2410
#define CONFIG_SYS_S3C2410_NAND_HWECC
#else
#define CONFIG_NAND_S3C2440
#define CONFIG_SYS_S3C2440_NAND_HWECC
#endif


#define CONFIG_SYS_MAX_NAND_DEVICE    1
#define CONFIG_SYS_NAND_BASE        0x4E000000
#endif

            

 然后修改nand的makefile以支持对2440

查看nand的初始化函数,来逐步查看需要重新设置的内容   

void nand_init(void)
{
#ifdef CONFIG_SYS_NAND_SELF_INIT
    board_nand_init();
#else
    int i;


    for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++)
        nand_init_chip(i);
#endif


    printf("%lu MiB\n", total_nand_size / 1024);


#ifdef CONFIG_SYS_NAND_SELECT_DEVICE
    /*
     * Select the chip in the board/cpu specific driver
     */
    board_nand_select_device(nand_info[nand_curr_device].priv, nand_curr_device);
#endif
}

 

CONFIG_SYS_NAND_SELF_INIT宏未定义,所以对nand_init_chip(i)函数进行分析,需要对nand_scan(mtd, maxchips)和board_nand_init(nand)进行分析

#ifndef CONFIG_SYS_NAND_SELF_INIT
static void nand_init_chip(int i)
{
    struct mtd_info *mtd = &nand_info[i];
    struct nand_chip *nand = &nand_chip[i];
    ulong base_addr = base_address[i];
    int maxchips = CONFIG_SYS_NAND_MAX_CHIPS;


    if (maxchips < 1)
        maxchips = 1;


    mtd->priv = nand;
    nand->IO_ADDR_R = nand->IO_ADDR_W = (void  __iomem *)base_addr;


    if (board_nand_init(nand))
        return;


    if (nand_scan(mtd, maxchips))
        return;


    nand_register(i);
}
#endif

 

       首先是 board_nand_init()函数,原来的nand配置寄存器不是当前2440的nand的寄存器,需要修改,而且还需要额外加入控制寄存器的配置

 u_int32_t cfg;
    u_int8_t tacls, twrph0, twrph1;
    struct s3c24x0_clock_power *clk_power = s3c24x0_get_base_clock_power();
    struct s3c2440_nand *nand_reg = s3c2440_get_base_nand();


    debug("board_nand_init()\n");


    writel(readl(&clk_power->clkcon) | (1 << 4), &clk_power->clkcon);


    /* initialize hardware */
#if defined(CONFIG_S3C24XX_CUSTOM_NAND_TIMING)
    tacls  = CONFIG_S3C24XX_TACLS;
    twrph0 = CONFIG_S3C24XX_TWRPH0;
    twrph1 =  CONFIG_S3C24XX_TWRPH1;
#else
    tacls = 4;
    twrph0 = 8;
    twrph1 = 8;
#endif


#ifdef CONFIG_S3C2410
    cfg = S3C2410_NFCONF_EN;
    cfg |= S3C2410_NFCONF_TACLS(tacls - 1);
    cfg |= S3C2410_NFCONF_TWRPH0(twrph0 - 1);
    cfg |= S3C2410_NFCONF_TWRPH1(twrph1 - 1);
#else
    cfg |= ((tacls-1)<<12)|((twrph0-1)<<8)|((twrph1-1)<<4);    //设置配置寄存器 调整时序
#endif
    writel(cfg, &nand_reg->nfconf);    

    cfg = 0;
    cfg |= (1<<4)|(1<<1)|(1<<0);
    writel(cfg, &nand_reg->nfcont);    //设置控制寄存器 调整时序
    
    /* initialize nand_chip data structure */
    nand->IO_ADDR_R = (void *)&nand_reg->nfdata;
    nand->IO_ADDR_W = (void *)&nand_reg->nfdata;


    nand->select_chip = NULL;


    /* read_buf and write_buf are default */
    /* read_byte and write_byte are default */
#ifdef CONFIG_NAND_SPL
    nand->read_buf = nand_read_buf;
#endif


    /* hwcontrol always must be implemented */
    nand->cmd_ctrl = s3c2440_hwcontrol;    //修改对应的函数名


    nand->dev_ready = s3c2440_dev_ready;


#ifdef CONFIG_S3C2410_NAND_HWECC
    nand->ecc.hwctl = s3c2410_nand_enable_hwecc;
    nand->ecc.calculate = s3c2410_nand_calculate_ecc;
    nand->ecc.correct = s3c2410_nand_correct_data;
    nand->ecc.mode = NAND_ECC_HW;
    nand->ecc.size = CONFIG_SYS_NAND_ECCSIZE;
    nand->ecc.bytes = CONFIG_SYS_NAND_ECCBYTES;
#else
    nand->ecc.mode = NAND_ECC_SOFT;
#endif


#ifdef CONFIG_S3C2410_NAND_BBT
    nand->options = NAND_USE_FLASH_BBT;
#else
    nand->options = 0;
#endif


    debug("end of nand_init\n");


    return 0;

 

        然后需要修改s3c2440_hwcontrol和s3c2440_dev_ready

static void s3c2440_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
{
    struct nand_chip *chip = mtd->priv;
    struct s3c2440_nand *nand = s3c2440_get_base_nand();    //4E000000


    debug("hwcontrol(): 0x%02x 0x%02x\n", cmd, ctrl);


    if (ctrl & NAND_CTRL_CHANGE) {
        ulong IO_ADDR_W = (ulong)nand;


        if (!(ctrl & NAND_CLE))
            IO_ADDR_W |= S3C2410_ADDR_NCLE;
        if (!(ctrl & NAND_ALE))
            IO_ADDR_W |= S3C2410_ADDR_NALE;


        chip->IO_ADDR_W = (void *)IO_ADDR_W;


        if (ctrl & NAND_NCE)    //使能片选(与2410区别)
            writel(readl(&nand->nfcont) & ~(1<<1),
                   &nand->nfcont);
        else    //禁止片选
            writel(readl(&nand->nfcont) | (1<<1),
                   &nand->nfcont);
    }


    if (cmd != NAND_CMD_NONE)
        writeb(cmd, chip->IO_ADDR_W);
}



static int s3c2440_dev_ready(struct mtd_info *mtd)
{
    struct s3c2440_nand *nand = s3c2440_get_base_nand();
    debug("dev_ready\n");
    return readl(&nand->nfstat) & 0x01;
}

 

紧接着对nand_scan函数进行修改

     nand_scan
            nand_scan_ident
                nand_set_defaults    //设置读写,选中等命令的指向
                    chip->select_chip = nand_select_chip;
                    chip->cmdfunc = nand_command;
                    chip->read_byte = busw ? nand_read_byte16 : nand_read_byte;
                
          nand_get_flash_type
                chip->select_chip
                chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
                chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
                *maf_id = chip->read_byte(mtd);
                *dev_id = chip->read_byte(mtd);

   

 

  从上面的逻辑顺序可以看出,nand_scan实现的功能就是选择芯片,发送地址数据命令等,最后调用的是nand_select_chip和nand_command等函数,这些函数调用的是chip->cmd_ctrl,然而在board_nand_init时,就已经指定了chip->cmd_ctrl的指向nand->cmd_ctrl = s3c2440_hwcontrol,从程序中可以看出原来的选择芯片和发送地址数据的命令需要修改

/*这个函数最后指向chip->select_chip
    指向多个函数      实现       
    ctrl    选中芯片/取消选中               发命令/发地址
    cmd        命令值                        地址值
*/
static void s3c2440_hwcontrol(struct mtd_info *mtd, int data, unsigned int ctrl)
{
    struct nand_chip *chip = mtd->priv;
    struct s3c2440_nand *nand = s3c2440_get_base_nand();    //4E000000


    if(ctrl & NAND_CLE){
        
        writeb(data, &nand->nfcmd);    //发命令
            
    }else if(ctrl & NAND_ALE){
    
        writeb(data, &nand->nfaddr);    //发地址
    }
}
nand->select_chip = s3c2440_nand_select;    //需要自己添加选中芯片的函数

static void s3c2440_nand_select(struct mtd_info *mtd, int chipnr)
{
    struct s3c2440_nand *nand = s3c2440_get_base_nand();


    switch (chipnr) {
    case -1:    //取消选中
        nand->nfcont |= (1<<1)
        break;
    case 0:        //选中
        nand->nfcont &= ~(1<<1)
        break;


    default:
        BUG();
    }
}

 

修改过的文件:

    smdk2440.h

    drive/mtd/nand/makefile

     s3c2440_nand.c

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值