Представляем дизайн драйверов Sunxi SPIN и mtd/ubi для облегчения разработки соответствующих драйверов и приложений.
Этот дизайн подходит для всех платформ Sunxi.
Разработчики модулей Nand, разработчики приложений и т. д.
2 Термины, сокращения и понятия
MTD:(Memory Technology устройство) используется для доступа к устройствам хранения данных linux подсистема. Этот модуль MTD подсистема flash Приводная часть
UBI:UBI Подсистема основана на MTD подсистема,существовать MTD реализовано на nand Логика управления функциями, восходящая защита NAND Характеристики
плохой блок (Bad Block):Производственный процесси nand Физические свойства сами по себе приводят к тому, что существующее покидает завод, и нормальный процесс использования середина приведет к получению некачественного продукта. блок
Драйвер NAND MTD/UBI в основном включает в себя 5 основных компонентов, как показано ниже:
Рисунок 3-1: Архитектура UBI
проиллюстрировать:
Каталог исходного кода ядра: linux-5.4/drivers/mtd/awnand/spinand
.
├── Kconfig
├── Makefile
├── physic
│ ├── bbt.c
│ ├── cache.c
│ ├── core.c
│ ├── ecc.c
│ ├── id.c
│ ├── Makefile
│ ├── ops.c
│ └── physic.h
├── secure-storage.c
├── sunxi-common.c
├── sunxi-core.c
├── sunxi-debug.c
├── sunxi-nftl-core.c
└── sunxi-spinand.h
В каталоге ядра
`-- include
`-- linux
`-- mtd
|-- aw-spinand.h
struct aw_spinand_phy_info {
const char *Model;
unsigned char NandID[MAX_ID_LEN];
unsigned int DieCntPerChip;
unsigned int BlkCntPerDie;
unsigned int PageCntPerBlk;
unsigned int SectCntPerPage;
unsigned int OobSizePerPage;
#define BAD_BLK_FLAG_MARK 0x03
#define BAD_BLK_FLAG_FRIST_1_PAGE 0x00
#define BAD_BLK_FLAG_FIRST_2_PAGE 0x01
#define BAD_BLK_FLAG_LAST_1_PAGE 0x02
#define BAD_BLK_FLAG_LAST_2_PAGE 0x03
int BadBlockFlag;
#define SPINAND_DUAL_READ BIT(0)
#define SPINAND_QUAD_READ BIT(1)
#define SPINAND_QUAD_PROGRAM BIT(2)
#define SPINAND_QUAD_NO_NEED_ENABLE BIT(3)
#define SPINAND_ONEDUMMY_AFTER_RANDOMREAD BIT(8)
int OperationOpt;
int MaxEraseTimes;
#define HAS_EXT_ECC_SE01 BIT(0)
#define HAS_EXT_ECC_STATUS BIT(1)
enum ecc_status_shift ecc_status_shift;
int EccFlag;
enum ecc_limit_err EccType;
enum ecc_oob_protected EccProtectedType;
};
проиллюстрировать:
• Model:flash из model имя
• NandID:flash из id код
• DieCntPerChip: за chip из die число
• BlkCntPerDie: за die Сколько их block
• PageCntPerBlk: за block Сколько их page
• Секткнтперпаже: за page Сколько ихвентиляторокруг
• OobSizePerPage: за page из obb размер
• BadBlockFlag:плохой блок логотипов магазинкаждый существует block из этого page середина
• OperationOpt: поддержка работы
• MaxEraseTimes: Максимальное количество стертых данных.
• EccFlag: Чтение характерного материала ecc status Говорит, что каталог должен быть другим
• GD5F1GQ4UCYIG проходить 0Fh + C0h получать ecc статус, настройка не требуется EccFlag
• MX35LF1GE4AB проходить 7Ch + one dummy byte получать ecc статус, затем настройте EccFlag = HAS_EXT_ECC_STATUS
• Экктип: Настройки ecc Соответствие значений из статусных отношений
• EccProtectedType: в spare Перейти к выбору получения ecc защищать из 16byte как oob округ
Пример (MX35LF2GE4AD):
{
.Model = "MX35LF2GE4AD",
.NandID = {0xc2, 0x26, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff},
.DieCntPerChip = 1,
.SectCntPerPage = 4,
.PageCntPerBlk = 64,
.BlkCntPerDie = 2048,
.OobSizePerPage = 64,
.OperationOpt = SPINAND_QUAD_READ | SPINAND_QUAD_PROGRAM | SPINAND_DUAL_READ,
.MaxEraseTimes = 65000,
.EccFlag = HAS_EXT_ECC_STATUS,
.EccType = BIT4_LIMIT5_TO_8_ERR9_TO_15,
.EccProtectedType = SIZE16_OFF4_LEN4_OFF8,
.BadBlockFlag = BAD_BLK_FLAG_FIRST_2_PAGE,
},
struct aw_spinand_chip {
struct aw_spinand_chip_ops *ops;
struct aw_spinand_ecc *ecc;
struct aw_spinand_cache *cache;
struct aw_spinand_info *info;
struct aw_spinand_bbt *bbt;
struct spi_device *spi;
unsigned int rx_bit;
unsigned int tx_bit;
unsigned int freq;
void *priv;
};
Эта структура определяет flash chip Слой физической моделиструктуры данныха также chip пара слоев flash интерфейс эксплуатации.
• aw_spinand_chip_ops:flash Чтение, запись, стирание и другие рабочие интерфейсы
• aw_spinand_ecc:flash ecc Чтение, запись и проверка рабочего интерфейса
• aw_spinand_cache: для кеша page из управления, улучшить эффективность чтения и письма
• aw_spinand_info:flash ID、page size и другую информацию и получать информацию из рабочего интерфейса
• aw_spinand_bbt:flash плохой блокировать таблицу и интерфейсы операций управления
• spi_device:spi Родительское устройство из операционной структуры
• rx_bit: флаг операции чтения статуса
• tx_bit: флаг операции записи состояния
struct aw_spinand_chip_request {
unsigned int block;
unsigned int page;
unsigned int pageoff;
unsigned int ooblen;
unsigned int datalen;
void *databuf;
void *oobbuf;
unsigned int oobleft;
unsigned int dataleft;
};
Управляйте целевой структурой и изменяйте ее, чтобы заполнить данные, с которыми мы хотим работать. block из этого page изсколько смещенияданные
databuf/oobbuf
• блок: блок, с которым нужно работать
• страница: страница, на которой нужно работать
• pageoff: смещение операции
• ооблен: операция oob длина
• datalen: длина данных операции
• databuf: управлять целевыми данными
• oobbuf: цель операции oob
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;
@magic: erase counter header magic number (%UBI_EC_HDR_MAGIC)
@version: version of UBI implementation which is supposed to accept this UBI image
@padding1: reserved for future, zeroes
@ec: the erase counter
@vid_hdr_offset: where the VID header starts
@data_offset: where the user data start
@image_seq: image sequence number
@padding2: reserved for future, zeroes
@hdr_crc: erase counter header CRC checksum
EC: Erase Подсчитайте, запишите количество стираний блоков, существующих ubiattach Укажите один, когда из если бы PEB Нет
EC, затем используйте среднее значение из EC стоимость, напишите EC Значение увеличивается только при стирании существующих 1
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;
@magic: volume identifier header magic number (%UBI_VID_HDR_MAGIC)
@version: UBI implementation version which is supposed to accept this UBI image(%UBI_VERSION)
@vol_type: volume type (%UBI_VID_DYNAMIC or %UBI_VID_STATIC)
@copy_flag: if this logical eraseblock was copied from another physical eraseblock(for wear-leveling reasons)
@compat: compatibility of this volume(%0, %UBI_COMPAT_DELETE, %UBI_COMPAT_IGNORE,%UBI_COMPAT_PRESERVE, or %UBI_COMPAT_REJECT)
@vol_id: ID of this volume
@lnum: logical eraseblock number
@padding1: reserved for future, zeroes
@data_size: how many bytes of data this logical eraseblock contains
@used_ebs: total number of used logical eraseblocks in this volume
@data_pad: how many bytes at the end of this physical eraseblock are not used
@data_crc: CRC checksum of the data stored in this logical eraseblock
@padding2: reserved for future, zeroes
@sqnum: sequence number
@padding3: reserved for future, zeroes
@hdr_crc: volume identifier header CRC checksum
Описание параметра
@sqnum это создать это VID Время заголовка из глобального счетчика последовательности из значения. каждый раз UBI написать новое из VID Первый раз flash Счетчик глобальной последовательности увеличивается, например, если это логическая eraseblock Карта к новому изфизиз. erase-block час. Глобальный счетчик последовательности является беззнаковым 64 битовое целое число, мы предполагаем, что оно никогда не переполнится. @sqnum(серийный номер) Используется для разделения старых и новых версий блоков логического стирания.
Есть две ситуации, когда может быть несколько физических eraseblock соответствуют той же логике стереть блок, т.е. существующий заголовок идентификации тома середина имеет то же самое из @vol_id и @lnum ценить. Предположим, у нас есть блок логического стирания. L, который отображается в блок физического стирания P。
UBI использовать @copy_flag Поле указывает, что этот блок логического стирания является копией. УБИ Также рассчитать данные из CRC, когда данные перемещаются и сохраняются в копии (P1) из @data_crc поле. Поэтому, когда UBI Надо начинать с двух (P или P1) При выборе физически стертого блока проверяются новые блоки (P1) из @copy_flag。если оно очищено,Ситуация проста,Новый из будет выбран середина. Если это значение установлено,затем проверьте копию (P1) данные КПР. если CRC Проверка верна, потому что этот блок физического стирания выбран середина (П1). В противном случае будет выбран более старый из П. Если дастатический объем,@data_crc Поле содержит содержимое блока логического стирания. CRC Проверьте и. Для динамических томов он не содержит CRC проверятьиправило。толькоиз Исключенияда,Когда блок физически стираетсяданные При перемещении подсистемой выравнивания износа,Данные расчета подсистемы выравнивания износа CRC и сохраните его в @data_crc Полесередина。
@used_ebs Поле仅用于статический объем,это указывает на то, что объемданные Сколько блоков стирания необходимо。Для динамических томов,Это поле не указано и всегда содержит 0.
@data_pad Параметры выравнивания существующего значения рассчитываются при создании тома. Поэтому @data_pad Поле эффективно уменьшает объем блоков логического стирания из-за размера. Когда человек существует UBI Блок программного обеспечения, ориентированный на использование тома (например, крамфс) Это да очень удобно.
LEB и PEB
Рисунок 3-2: PEB-LEB
static int aw_rawnand_mtd_erase(struct mtd_info *mtd, struct erase_info *instr)
description:mtd erase interface
@mtd:MTD device structure
@instr:erase operation descrition structure
return:success return 0,fail return fail code
static int aw_rawnand_mtd_read(struct mtd_info *mtd, loff_t from, size_t len,size_t *retlen, u_char *buf)
description:mtd read interface
@mtd:MTD device structure
@from:offset to read from MTD device
@len: data len
@retlen:had read data len
@buf:data buffer
return:success return max_bitflips,fail return fail code
static int aw_rawnand_mtd_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops)
description:mtd read data with oob
@mtd:MTD device structure
@ops:oob eperation descrition structure
return:success return max_bitflips,fail return fail code
static int aw_rawnand_mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)
description:mtd write data interface
@to:offset to MTD device
@len:want write data len
@retlen:return the writen len
@buf:data buffer
return:success return 0, fail return code fail
static int aw_rawnand_mtd_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *
ops)
description:write data with oob
@mtd:MTD device structure
@to:offset to MTD device
@ops:oob operation descrition structure
return:success return 0, fail return code fail
static int aw_rawnand_mtd_block_isbad(struct mtd_info *mtd, loff_t ofs)
description:check block is badblock or not
@mtd:MTD device structure
@ofs: offset the mtd device start (align to simu block size)
return:true if the block is bad, or false if the block is good
static int aw_rawnand_mtd_block_markbad(struct mtd_info *mtd, loff_t ofs)
description:mark block at the given offset as bad block
@mtd:MTD device structure
@ofs:offset the mtd device start
return:success to mark return 0, or fail return fail code.
static int aw_spinand_chip_read_single_page(struct aw_spinand_chip *chip, struct aw_spinand_chip_request *req)
description:Read physics on a page
@chip:See 3.3.2
@req:See 3.3.3
return:zero on success, else a negative error code.
3.4.2.2 aw_spinand_chip_write_single_page
static int aw_spinand_chip_write_single_page(struct aw_spinand_chip *chip, struct aw_spinand_chip_request *req)
description:Write physics on a page
@chip:See 3.3.2
@req:See 3.3.3
return:zero on success, else a negative error code.
static int aw_spinand_chip_erase_single_block(struct aw_spinand_chip *chip, struct aw_spinand_chip_request *req)
description:Erase physics on a block
@chip:See 3.3.2
@req: See 3.3.3
return:zero on success, else a negative error code.
static int aw_spinand_chip_isbad_single_block(struct aw_spinand_chip *chip, struct aw_spinand_chip_request *req)
description:Set to bad block
@chip:See 3.3.2
@req:See 3.3.3
return:zero on success, else a negative error code.
static int aw_spinand_chip_markbad_single_block(struct aw_spinand_chip *chip, struct aw_spinand_chip_request *req)
description:Set to bad block
@chip:See 3.3.2
@req:See 3.3.3
return:zero on success, else a negative error code.
Device Drivers-->Sunxi flash support-->
[*]Support sunxi nand devices
[*]Support sunxi nand ubifs devices
[*]Support COMM NAND V1 interface
Как показано ниже:
Шаг 4-1: u-boot-spinand-menuconfig
Device Drivers->Memory Technology Device(MTD) support-->sunxi-nand
Рисунок 4-2: UBI
Рисунок 4-3: ker_nand-cfg
Рисунок 4-4: ker_spinand
Device Drivers->SPI support
Рисунок 4-5: spi-1
Рисунок 4-6: spi-2
Device Drivers->DMA Engine support
Рисунок 4-7: DMA-1
Рисунок 4-8: DMA-2
Device Drivers->SOC(System On Chip)
Рисунок 4-9: SID
File systems-->Miscellaneous filesystems-->
картина 4-10: менюconfig_spinand_ubifs
существовать env.cfg середина Добавить и изменить следующее значение, setargs_nand_ubi Первый copy одна порция setargs_nand Затем добавьте соответствующие переменные
Рисунок 4-11: build-mkcmd