SPINAND UBI 离线烧录 开发指南

Posted 韦东山

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SPINAND UBI 离线烧录 开发指南相关的知识,希望对你有一定的参考价值。

SPINAND UBI 离线烧录 开发指南

1 概述

编写目的: 介绍Sunxi SPINand 烧写时的数据布局

2 名词解释

UBIunsorted block image
PEBphysical erase block
LEBlogical erase block

PEB 和logical block 关系

1 PEB = 1 logical block
1 logical block = 2 physical blocks

3 总体数据布局

ubi 方案FLASH 上的数据布局

sys_partition.fex 文件中的各个分区大小会按照LEB 大小对齐,sunxi_mbr 分区概念与UBI卷(volume)概念相同
需要修改原镜像文件:物理区TOC0 合逻辑区sunxi_mbr.fex
需要动态生成文件:逻辑区ubi layout volume
注意:

  1. 各分区镜像以实际应用为准
  2. logical page0 = logical block 的两个page0

4 toc0 or boot0

4.1 input file

boot0_nand.fex(非安)or toc0.fex(安全)

4.2 flow

• 验证checksum 是否准确
• 填充storage_data
• 重新生成checksum 并更新boot_file_head_t 中的check_sum

参考文件
include/private_boot0.h
sprite/sprite_download.c
参考函数
download_normal_boot0
download_secure_boot0

4.3 normal boot0

normal boot0 存放于block4-7
参考function: download_normal_boot0

typedef struct _boot0_file_head_t

boot_file_head_t boot_head;
boot0_private_head_t prvt_head;
char hash[64];
__u8 reserved[8];
union 
#ifdef CFG_SUNXI_SELECT_DRAM_PARA
boot_extend_head_t extd_head;
#endif
fes_aide_info_t fes1_res_addr;
 fes_union_addr;
boot0_file_head_t;
/******************************************************************************/
/* file head of Boot0 */
/******************************************************************************/
typedef struct _boot0_private_head_t

>-------__u32 prvt_head_size;
>-------/*debug_mode = 0 : do not print any message,debug_mode = 1 ,print debug message*/
>-------__u8 debug_mode;
>-------/*0:axp, 1: no axp */
>-------__u8 power_mode;
>-------__u8 reserve[2];
>-------/*DRAM patameters for initialising dram. Original values is arbitrary*/
>-------unsigned int dram_para[32];
>-------/*uart: num & uart pin*/
>-------__s32>-->------->------->------->------->-------uart_port;
>-------normal_gpio_cfg uart_ctrl[2];
>-------/* jtag: 1 : enable, 0 : disable */
>-------__s32 enable_jtag;
normal_gpio_cfg>---- jtag_gpio[5];
>-------/* nand/mmc pin*/
normal_gpio_cfg storage_gpio[32];
>-------/*reserve data*/
char storage_data[512 - sizeof(normal_gpio_cfg) * 32];
boot0_private_head_t;

4.4 secure boot0

secure boot0 存放于boot0-block3

typedef struct sbrom_toc0_config

unsigned char config_vsn[4];
unsigned int dram_para[32]; // dram参数
int uart_port; // UART控制器编号
normal_gpio_cfg uart_ctrl[2]; // UART控制器GPIO
int enable_jtag; // JTAG使能
normal_gpio_cfg jtag_gpio[5]; // JTAG控制器GPIO
normal_gpio_cfg storage_gpio[50]; // 存储设备GPIO信息
// 0-23放nand,24-31存放卡0,32-39放卡2
// 40-49存放spi
char storage_data[384]; // 0-159,存储nand信息;160-255,存放卡信息
unsigned int secure_dram_mbytes; //
unsigned int drm_start_mbytes; //
unsigned int drm_size_mbytes; //
unsigned int boot_cpu; //
special_gpio_cfg a15_power_gpio; //the gpio config is to a15 extern power enable
gpio
unsigned int next_exe_pa;
unsigned int secure_without_OS; //secure boot without semelis
unsigned char debug_mode; //1:turn on printf; 0 :turn off printf
unsigned char power_mode; /* 0:axp , 1: dummy pmu */
unsigned char rotpk_flag;
unsigned char reserver[1];
unsigned int card_work_mode;
unsigned int res[2]; // 总共1024字节

sbrom_toc0_config_t;

4.5 filling storage_data

下表中红色字体不能配置错,大部分值直接参考drivers/mtd/awnand/spinand/physic/id.c

attribute nametypevaluecomment
ChipCntunsigned char1
ConnectModeunsigned char1忽略,可以不用理解
BankCntPerChipunsigned char1忽略,可以不用理解
DieCntPerChipunsigned char1
PlaneCntPerDieunsigned char2忽略,可以不用理解
SectorCntPerPageunsigned char4以具体物料为准, 常见为4
ChipConnectInfounsigned short1忽略,可以不用理解
PageCntPerPhyBlkunsigned int64以具体物料为准, 常见为64
BlkCntPerDieunsigned int1024以具体物料为准, 常见为1024,也可能为512 或2048
OperationOptunsigned int0x?参考id.c 各个物料配置
FrequenceParunsigned int100忽略,可以不用理解
SpiModeunsigned int0忽略,可以不用理解
NandChipId[8]unsigned char0x?参考id.c 各个物料配置
pagewithbadflagunsigned int0忽略,可以不用理解
MultiPlaneBlockOffsetunsigned int1忽略,可以不用理解
MaxEraseTimesunsigned int忽略,可以不用理解
EccLimitBitsunsigned int忽略,可以不用理解
uboot_start_blockunsigned int8
uboot_next_blockunsigned int40
logic_start_blockunsigned int40忽略,可以不用理解
nand_specialinfo_pageunsigned int0忽略,可以不用理解
nand_specialinfo_offsetunsigned int0忽略,可以不用理解
physic_block_reservedunsigned int0忽略,可以不用理解
Reserved[4]unsigned int0忽略,可以不用理解

以GigaDevice GD5F1GQ4UBYIG spinand 为例,其大部分信息直接来自id.c


.Model = "GD5F1GQ4UBYIG",
.NandID = 0xc8, 0xd1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
.DieCntPerChip = 1,
.SectCntPerPage = 4,
.PageCntPerBlk = 64,
.BlkCntPerDie = 1024,
.OobSizePerPage = 64,
.OperationOpt = SPINAND_QUAD_READ | SPINAND_QUAD_PROGRAM |
SPINAND_DUAL_READ,
.MaxEraseTimes = 50000,
.EccFlag = HAS_EXT_ECC_SE01,
.EccType = BIT4_LIMIT5_TO_7_ERR8_LIMIT_12,
.EccProtectedType = SIZE16_OFF4_LEN8_OFF4,
.BadBlockFlag = BAD_BLK_FLAG_FRIST_1_PAGE,
,
参考文件:
include/linux/mtd/aw-spinand.h /定义id.c 中id 表的数据结构/
drivers/mtd/awnand/spinand/sunxi-spinand.h /定义boot_spinand_para_t 填充的数据结构/
drivers/mtd/awnand/spinand/sunxi-driver.c /填充函数参考/
drivers/mtd/awnand/spinand/physic/id.c /不同物料的信息配置(id 表配置)/
参考函数:
ubi_nand_get_flash_info–>spinand_mtd_get_flash_info

4.6 update checksum

参考文件:
sprite/sprite_download.c
sprite/sprite_verify.c
board/sunxi/board_common.c
参考函数流程:
download_normal_boot0/download_secure_boot0 -> sunxi_sprite_generate_checksum
-> sunxi_generate_checksum

4.7 burn boot0

• 参考文件:
drivers/mtd/awnand/spinand/sunxi-driver.c
参考函数流程:
spinand_mtd_download_boot0()

注意事项:
如果是安全方案,存放boot0 的blocks 中一半存放secure boot0,一半存放normal
boot0, 参考UBI 方案分区表信息以及第2 章节说明

各个备份按block 对齐(如果boot0 超过1 个block, 单个备份起始block 地址为偶数), 若写单个备份过程中遇到坏块,则中止当前备份写过程,写下一备份即可boot0 的镜像文件已经包含了boot0 header,不需额外分配组织boot0 header 格式,只需更新boot0 header 中的storage_data 部分,其他属性(比如dram_para)不需更新。更新后,需重新生成boot0 header 中的校验和check_sum

5 toc1 or uboot

区域:block8-block31
直接烧写toc1 镜像
参考文件:

sprite/sprite_download.c
drivers/sunxi_flash/nand.c
drivers/sunxi_flash/nand_for_ubi.c
drivers/mtd/awnand/spinand/sunxi-driver.c

参考函数:

sunxi_sprite_download_uboot–>sunxi_sprite_download_toc–sunxi_flash_nand_download_toc–>
ubi_nand_download_uboot–>spinand_mtd_download_uboot

6 secure storage block

区域:block32-block39
烧录器不用处理

7 计算逻辑区域LEB 总数

用户可见LEB 数= 总物理块数- 8 (boot0) - 24 (boot1) - 8 (secure storage) - 20* 总物理块
数/1024 - 4,规则如下:

  1. 减去物理区域块数
  2. 减去坏块处理预留数(每1024 物理块最多20 个物理块,即10 个逻辑块)
  3. 减去4(2 个用于ubi layout volume,1 个用于LEB 原子写,1 个用于磨损均衡处理)推算方式可以参考u-boot-2018/cmd/ubi_simu.c 的ubi_sim_part 和ubi_simu_create_vol函数。
    正常情况下,ubi 方案sys_partition.fex 中各个分区的大小会按照LEB 大小对齐。假如一款flash 有1024 个block, 每个block 有64 个page, 每个page 有2KB,则逻辑块大小为256K(642K2), 那么PEB 大小是256K,LEB 大小为252K, PEB 中的首逻辑页固定用于
    存放ubi_ec_hdr 和ubi_vid_hdr。
    由于预先不知道物料的容量信息及预留块信息,因此sys_partition.fex(sunxi_mbr.fex)中最后一个分区的size 信息默认先填0,待NAND 驱动初始化完成后才知道用户可见LEB 数有多少个,此时需要根据信息改写sunxi_mbr.fex 中最后一个分区的size。

8 动态调整sunxi_mbr 卷

sunxi_mbr.fex 共64k, 共4 个备份,每个备份16K

  1. 计算mbr 卷最后分区size, 单位:扇区(512 字节),计算规则如下:
    根据第5 章节计算出的用户可见leb 数转化出总的扇区数total_sector,依次减去分区表中各个
    分区占用的扇区数
  2. 回填sunxi_mbr.fex 最后一个分区size
  3. 重新计算并回填sunxi_mbr 的crc32
  4. 改写其余3 个备份
sunxi_mbr_t 结构体:u-boot-2018/include/sunxi_mbr.h,结构体各个成员均使用小端存储。
typedef struct sunxi_mbr

unsigned int crc32;
unsigned int version;
unsigned char magic[8];
unsigned int copy;
unsigned int index;
unsigned int PartCount;
unsigned int stamp[1];
sunxi_partition array[SUNXI_MBR_MAX_PART_COUNT];
unsigned int lockflag;
unsigned char res[SUNXI_MBR_RESERVED];
attribute ((packed)) sunxi_mbr_t;

重新计算并回填sunxi_mbr crc32 的代码请参考u-boot-2018/drivers/mtd/aw-spinand/sunxiubi.
c 的adjust_sunxi_mbr 函数。

9 根据sunxi_mbr 动态生成ubi layout volume

ubi layout volume 可以理解为UBI 模块内部用的分区信息文件,sunxi_mbr 分区是用于全志烧写framework 的分区信息文件。二者记录的分区信息本质上是一样的,因此烧写时, 可以由sunxi_mbr 卷转化成ubi layout volume。
ubi layout volume 由128 个struct ubi_vtbl_record(u-boot-2018/drivers/mtd/ubi/ubimedia.h)组成, 结构体各个成员使用大端表示。

struct ubi_vtbl_record 
__be32 reserved_pebs;
__be32 alignment;
__be32 data_pad;
__u8 vol_type;
__u8 upd_marker;
__be16 name_len;
char name[UBI_VOL_NAME_MAX+1];
__u8 flags;
__u8 padding[23];
__be32 crc;
 __packed;
attribute nametypevaluecomment
reserved_pebs__be32卷大小/LEB size, 对于ubi layout volume,固定为2
alignment__be321
data_pad__be320
vol_type__u81动态卷:1,静态卷:2,当前方案均是动态卷
upd_marker__u80
name_len__be16卷名长度
name[128]char
flags__u8分区内最后一个卷udisk,flags UBI_VTBL_AUTORESIZE_FLG
padding[23]__u80
crc__be32crc32_le

ubi layout volume 的内容填充及烧写方法请参考u-boot-2018/cmd/ubi_simu.c 的ubi_simu_create_vol 和wr_vol_table 函数
注意ubi 中crc32_le 算法与sunxi_mbr 的crc32 算法不一样。
ubi 中crc32_le 参考crc32_le.c 用法sunxi_mbr 中crc32 参考crc32.c 用法

10 烧写逻辑卷

PEB = ubi_ec_hdr + ubi_vid_hdr + LEB
其中ubi_ec_hdr 和ubi_vid_hdr 存放于PEB 的首逻辑页(logical page0)。

ubi_ec_hdr 存放于0 字节偏移处,大小与物理页size 对齐
ubi_vid_hdr 存放于1 个物理页size 偏移处,大小也与物理页size 对齐

10.1 ubi_ec_hdr

ubi_ec_hdr:主要用于存储PEB 的擦除次数信息,需动态生成crc32_le 校验值。
struct ubi_ec_hdr 位于u-boot-2018/drivers/mtd/ubi/ubi-media.h,结构体各个成员使用大端表示。

struct ubi_ec_hdr 
__be32 magic;
__u8 version;
__u8 padding1[3];
__be64 ec; /* Warning: the current limit is 31-bit anyway! */
__be32 vid_hdr_offset;
__be32 data_offset;
__be32 image_seq;
__u8 padding2[32];
__be32 hdr_crc;
 __packed;
attribute nametypevaluecomment
magic__be320x55424923UBI#
version__u81
padding1[3]__u80
ec__be641
vid_hdr_offset__be32physical page size2048
data_offset__be32logical page size4096
image_seq__be320
padding2[32]__u80
hdr_crc__be32crc32_le

ubi_ec_hdr 的填充方法请参考u-boot-2018/cmd/ubi_simu.c 的fill_ec_hdr 函数。

10.2 ubi_vid_hdr

ubi_vid_hdr:存放PEB 和LEB&Volume 映射信息,需动态生成crc32_le 校验值
struct ubi_vid_hdr 位于u-boot-2018/drivers/mtd/ubi/ubi-media.h,结构体各个成员使用大端表示。

struct ubi_vid_hdr 
__be32 magic;
__u8 version;
__u8 vol_type;
__u8 copy_flag;
__u8 compat;
__be32 vol_id;
__be32 lnum;
__u8 padding1[4];
__be32 data_size;
__be32 used_ebs;
__be32 data_pad;
__be32 data_crc;
__u8 padding2[4];
__be64 sqnum;
__u8 padding3[12];
__be32 hdr_crc;
 __packed;

ubi_vid_hdr 的填充方法请参考u-boot-2018/cmd/ubi_simu.c 的fill_vid_hdr 函数。

11 数据对齐

有数据对齐需求时,不能填充0xff 数据,可选择填充全0版

以上是关于SPINAND UBI 离线烧录 开发指南的主要内容,如果未能解决你的问题,请参考以下文章

全志Tina Linux SPINAND UBI 离线烧录 开发指南 支持百问网T113 D1-H哪吒 DongshanPI-D1s V853-Pro等开发板

全志Tina Linux SPINAND UBI 离线烧录 开发指南 支持百问网T113 D1-H哪吒 DongshanPI-D1s V853-Pro等开发板

Linux SPI-NAND 驱动开发指南

msp430 工厂生产时 下载程序 有没有像c51编程器那种 直接给芯片烧录程序 然后再焊接芯片到PCB的 烧录器 ?

如何通过串口烧写STM32程序

如何通过串口烧写STM32程序