全志A10/A20 nand flash系统开发

全志A10/A20 nand flash系统开发

本文介绍 全志soc(A10/A20) 从nand flash启动系统,包括下载系统到nand flash的原理及方法,强调是nand flash启动而不是sd卡启动。

解决的问题

全志的资料真的太少了,而且很多不开源,这个坑真的巨大。
文本主要解决了以下几点问题
1.全志soc nand 启动原理;
2. 研究了 全志soc nand 控制器的使用,及驱动;
3. 如何下载bootloader(boot0)到nand flash, 并启动 ;

A10/A20启动原理

A10的启动过程大概可分为5步:
BootRom --> SPL --> Uboot --> Kernel --> RootFileSystem

系统上电后,ARM处理器在复位时从地址0x000000开始执行指令,把板上ROM或Flash映射到这一地址。
A10将启动设备选择程序固化在CPU内部的一个32KB ROM中,

默认的启动时序为SD Card0,NAND FLASH,SD Card2,SPI NOR FLASH。另外通过外部的一个启动选择引脚可以使其跳转到USB启动模式。通常情况下,启动选择引脚状态连接50K内部上拉电阻。在上电后,执行存储在ROM中的启动代码,将自动检测启动选择引脚状态。只有当该引脚状态为低电平时选择USB启动模式。

这可以看作是主程序加载程序。SoC开始从地址0xffff0000获取指令,这是BROM所在的位置。
BROM分为两部分:
第一部分(在0xffff0000处)是FEL模式,
第二部分是eGON模式。BRM(位于0xffff4000)

重置向量位于FEL模式的最开始:地址0xffff0000。
在重置时,它跳到0xffff0028,并将0xffff4000 (eGON.BRM)加载到接下来要执行的程序计数器中。

BROM引导加载程序已经从芯片中提取,可以在 hno’s repository中找到。
The magic signature is “eGON.BRM”.
BROM似乎从0x4000开始。如果BROM在NAND中标识了boot0,则加载并执行它。

A10/A20 芯片上电启动的时候,会自动读取SD卡 8K偏移处24K 内容,从而得到 bootloader,所以我们需要将boot0,烧写到tf卡8K偏移处.
而nand flash启动却不是这样,
BROM将尝试从page 0, 0x40, 0x80, 0xC0开始读取Boot0,…, 0 x1c0。只有这样,它才会放弃并继续使用其他启动选项(或FEL)。所以我们只需要讲boot0 刷到nand flash,0地址就可以了。

参考:https://linux-sunxi.org/BROM

如何制作nand flash 刷机包

制作nand flash 刷机包的工具在 github上可以找到,比如:
https://github.com/z4yx/sunxi-pack
https://github.com/jiangdoudou/linux-sdk-a20
我目前就是使用第一个仓库的工具,自己简单修改后就可以制作刷机包了。
当然工具里面如何制作刷机镜像,及原理 可以自己去研究,有些是开源的,有些是闭源的。

制作好的nand-镜像,如:xxx.img ,可以用 usb刷机工具LiveSuitPack (下载地址:) 刷到nand flash 中。

如果还是不懂,而且需要的人比较多,我可以专门出一篇文章来介绍。

如何下载boot到nand

重点 难点 重点 重点

刚开始想着 只需要把boot0 刷到 nand 的最前面,就能在nand启动了吧。这确实想的有点简单了。
第一步 我先在 uboot中实现对nand flash 的读写,然后使uboot从sd卡启动。
第二部 直接将 boot0,uboot,uboot-spl,刷到 nand 中。

结果很残酷,不管是刷 什么 boot ,都无法启动。

但是上面介绍的使用usb刷boot进 nand 就可以启动,这就很奇怪了
我们可以看看 usb 刷机时的uart log

NB1 : nand phy init ok
boot1 last block 0x0x00000006 .
open nand.
boot1 0x00000002
erasing block 2 succeeded…
Succeed in erasing block 2.
succeed in programming block 2.
boot1 0x00000003
erasing block 3 succeeded…
Succeed in erasing block 3.
succeed in programming block 3.
boot1 0x00000004
erasing block 4 succeeded…
Succeed in erasing block 4.
succeed in programming block 4.
boot1 0x00000005
erasing block 5 succeeded…

NB1 : nand phy init ok
open nand.
read retry mode: 0x0x00010604
lsb enalbe
boot0 0x00000000
boot0 0x00000001
boot0 0x00000000
boot0 0x00000001
lsb disalbe

(完整的log:allwinner-usb-fel.log )
这很明显,这些是对nand 进行操作的。
我对boot0,boot1源码修改过,我就发现 全志 的nand驱动代码其实是同一套。我提供个我修改使用的boot源码allwinner-boot,目前支持对 boot0,boot1的编译使用

static __s32  burn_boot0_lsb_mode( __u32 read_retry_type, __u32 Boot0_buf )
{
    __u32 	            i;
    __u32               length;
	struct boot_flash_info info;
	__u32 nand_version, nand_version0, nand_version1;
    __u8  oob_buf[32];
    __u32 page_size;

     __inf("burn boot0 lsb mode!\n");

    memset(oob_buf, 0xff, 32);
    nand_version = NAND_GetNandVersion();
    nand_version0 = (nand_version>>16)&0xff;
    nand_version1 = (nand_version>>24)&0xff;
    oob_buf[0] = 0xff;
    oob_buf[1] = 0x00;
    oob_buf[2] = nand_version0;
    oob_buf[3] = nand_version1;

	if( NAND_PhyInit( ) == FAIL )
		return -1;
	__inf("open nand.\n");
	__inf("read retry mode: 0x%x\n", read_retry_type);
	if( NAND_LSBInit(read_retry_type) )
	{
	    __inf("lsb init failed.\n");
		goto error;
	}
	NAND_LSBEnable(0, read_retry_type);
	__inf("lsb enalbe \n");
	if( NAND_GetFlashInfo( &info ) == FAIL )
	{
		__inf("get flash info failed.\n");
		goto error;
	}

	/* 检查 page count */
	page_size = info.pagesize*512;

    for( i = BOOT0_START_BLK_NUM;  i <= BOOT0_LAST_BLK_NUM;  i++ )
    {
		struct boot_physical_param  para;
		__u32  k;

        __inf("boot0 %x \n", i);

		/* 擦除块 */
		para.chip  = 0;
		para.block = i;
		if( NAND_PhyErase( &para ) != SUCCESS )
		{
		    __inf("Fail in erasing block %d.\n", i );
    		continue;
    	}

        /* 在块中烧写boot0备份, lsb mode下,每个块只能写前4个page */
		for( k = 0;  k < 4;  k++ )
		{
			para.chip  = 0;
			para.block = i;
			para.page  = k;
			para.mainbuf = (void *) (Boot0_buf + k * page_size);
			para.oobbuf = oob_buf;
			if( NAND_PhyWrite_Seq( &para ) != SUCCESS )
			{
				__inf("Warning. Fail in writing page %d in block %d.\n", k, i );
   			}
   		}

    }

    //check boot0
    for( i = BOOT0_START_BLK_NUM;  i <= BOOT0_LAST_BLK_NUM;  i++ )
    {
		struct boot_physical_param  para;
		__u32  k;

        __inf("boot0 %x \n", i);

        /* 在块中烧写boot0备份, lsb mode下,每个块只能写前4个page */
		for( k = 0;  k < 4;  k++ )
		{
			para.chip  = 0;
			para.block = i;
			para.page  = k;
			para.mainbuf = (void *) (Boot0_buf + k * page_size);
			para.oobbuf = oob_buf;
			if( NAND_PhyRead_Seq( &para ) != SUCCESS )
			{
				__inf("Warning. Fail in reading page %d in block %d.\n",  k, i );
   			}
   		}

    }

    NAND_LSBDisable(0, read_retry_type);
    NAND_LSBExit(read_retry_type);
	__inf("lsb disalbe \n");
    NAND_PhyExit( );
	return 0;

error:
    NAND_PhyExit( );
    return -1;
}

既然nand 驱动也有源码了,那我们看看 usb 是如何把boot刷到nand的,那应该就能解决其中的问题了。

全志soc nand 控制器

既然要对nand进行读写,那对nand 驱动也必然要熟悉了。
先看 A10 / A20 nand 控制器的使用
NFC_Register_Guide.
在这里插入图片描述

这里面坑最大的就是 硬件ECC配置,就是NFC_ECC_CTL寄存器的配置,为什么这么说,我们仔细看看这个寄存器
NFC_REG_ECC_CTL 0x0034 ECC & Random control

NFC_ECC_CTL_ECC_EN (1 << 0)
NFC_ECC_CTL_ECC_PIPELINE (1 << 3)
NFC_ECC_CTL_ECC_EXCEPTION (1 << 4)
NFC_ECC_CTL_ECC_BLOCK_SIZE (1 << 5)
NFC_ECC_CTL_RANDOM_EN (1 << 9)
NFC_ECC_CTL_RANDOM_DIRECTION (1 << 10)
(1 << 11) ??
NFC_ECC_CTL_ECC_MODE (0xf << 12)
NFC_ECC_CTL_RANDOM_SEED (0x7fff << 16))

这里面的NFC_ECC_CTL_ECC_MODE,NFC_ECC_CTL_RANDOM_SEED位如果 写和读的时候 配置不一样,那写完了nand,你想读出来,就会出现 ecc 校验出错的问题,这就是 为什么 之前使用uboot 刷boot到nand 不能启动的原因了,因为 在片上的固件BROM里面对boot0的读取是固定的配置。
如果有人需要对 nand 驱动手动实现,我这里提供一个快速驱动nand的系列命令(boot0.ush-nand flash-registers

启用硬件ECC后,每次写页面数据都会导致一个空闲区域的数据(oob_buf)写入。有时页面大于1K,所以需要多次写入一个页面。备用区域也将按顺序多次写入ECC数据。一次数据写操作会将存储在NFC_USER_DATA(i)上的4byte用户数据写在ECC数据后面,ECC数据的长度取决于ECC的模式。

nand 简单驱动boot0
通过实现nand的读写功能,将uboot-spl.bin 写到nand flash 中,

最后通过nand 启动效果
在这里插入图片描述
后面可能会研究 usb 启动方式。

如果有志同道合的朋友,可以联系我 QQ 839281922

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值