动机
- 为ss927芯片编译了 adb/adbd 服务,运行后,接着在 win 运行: ./adb devices -l 发现找不到 设备,于是怀疑是 内核需要修改
开始
sdk/SS928V100_SDK_V2.0.2.2/open_source/linux/linux-4.19.90.tar.gz
文件就是内核源文件. 在此同目录下有一个 makefile, 我将其中的变量CHIP
内容改为了 ss927v100, 其它用默认的配置,然后执行 make all, 它会自动解压、打补丁、并使用 ss928v100_defconfig 配置(在 arch/arm64/configs 里) ,然后编译,最终输出内核镜像 uImage 在sdk/SS928V100_SDK_V2.0.2.2/open_source/linux/linux-4.19.y/arch/arm64/boot
目录,至于它会输出在哪,这个可以自己去看编译后的log、文档、makefile。makefile
BUILD_DIR := $(shell pwd) MAKE=make CHIP ?= ss927v100 CPU_TYPE ?= ifeq ($(CHIP), ss927v100) LINUX_SUFFIX := _$(CPU_TYPE) endif KERNEL_ORIGIN_VER:=linux-4.19.90 KERNEL_VER:=linux-4.19.y KERNEL_TAR:=$(KERNEL_VER).tgz LIB_TYPE ?=glibc ARCH_TYPE ?= arm64 KERNEL_CFG ?=$(CHIP)_$(EMMC_FLAG)defconfig BOOT_MEDIA ?= spi ifeq ($(BOOT_MEDIA), spi) MEDIUM_FLAG = _ endif ifeq ($(BOOT_MEDIA), nand) MEDIUM_FLAG = _nand_ endif ifeq ($(BOOT_MEDIA), emmc) MEDIUM_FLAG = _emmc_ endif OSDRV_CROSS ?= aarch64-mix210-linux PUB_IMAGE ?=$(CHIP)_$(EMMC_FLAG)image_$(LIB_TYPE) GREEN = "\e[32;1m" DONE = "\033[0m" ts: echo $(EMMC_FLAG) $(PUB_IMAGE); echo kk all: @echo -e $(GREEN)"-------- kernel : $(KERNEL_ORIGIN_VER) " $(DONE) ifneq ($(BUILD_DIR)/$(KERNEL_VER), $(wildcard $(BUILD_DIR)/$(KERNEL_VER))) pushd $(BUILD_DIR);tar xf $(KERNEL_ORIGIN_VER).tar.gz;popd @echo -e $(GREEN)"patching kernel..." $(DONE) pushd $(BUILD_DIR);mv $(KERNEL_ORIGIN_VER) $(KERNEL_VER);popd pushd $(BUILD_DIR)/$(KERNEL_VER); patch -p1< ../linux-4.19.90.patch;popd pushd $(BUILD_DIR);tar -czf $(KERNEL_TAR) $(KERNEL_VER);popd rm -rf $(BUILD_DIR)/$(KERNEL_VER) @echo -e $(GREEN)"OK:generate patched kernel:$(KERNEL_TAR)!" $(DONE) endif ifneq ($(BUILD_DIR)/$(KERNEL_VER), $(wildcard $(BUILD_DIR)/$(KERNEL_VER))) pushd $(BUILD_DIR);tar xzf $(KERNEL_TAR) -C .;popd endif $(MAKE) -C $(BUILD_DIR)/$(KERNEL_VER) ARCH=$(ARCH_TYPE) CROSS_COMPILE=$(OSDRV_CROSS)- distclean $(MAKE) -C $(BUILD_DIR)/$(KERNEL_VER) ARCH=$(ARCH_TYPE) CROSS_COMPILE=$(OSDRV_CROSS)- $(KERNEL_CFG) $(MAKE) -C $(BUILD_DIR)/$(KERNEL_VER) ARCH=$(ARCH_TYPE) CROSS_COMPILE=$(OSDRV_CROSS)- -j 20 uImage; clean: $(MAKE) -C $(BUILD_DIR)/$(KERNEL_VER) ARCH=$(ARCH_TYPE) CROSS_COMPILE=$(OSDRV_CROSS)- clean distclean: rm $(BUILD_DIR)/$(KERNEL_ORIGIN_VER) -rf rm $(BUILD_DIR)/$(KERNEL_VER) -rf rm $(BUILD_DIR)/$(KERNEL_TAR) -rf
- 接着根据文档的指示,打包 atf 格式的镜像,其后缀是 .bin 文件,罗工说就是给 uImage 添加了一些头部信息。如果不打包为 atf 格式的镜像,那 朴工的uboot 就识别不了 kernel 了。打包为 atf 格式的镜像具体操作如下:
-
进入 open_source/trusted-firmware-a/trusted-firmware-a-2.2 目录 (请确认mk_ss928v100.sh 文件中 linux 内核目录所在的路径): 执行如下命令: chmod +x mk_ss928v100.sh ./mk_ss928v100.sh 在 open_source/trusted-firmware-a/trusted-firmware-a- 2.2/build/ss928v100/release 目录下,生成的 fip.bin 文件就是 ATF+kernle 的镜像
-
- 然后打开 ToolPlatform.exe 工具开始烧录自己编译的 kernel:
- 烧录成功后通过串口查看 log 信息,发现报错了(见 错误log信息),可以发现 UBI 无法附加到 MTD, 导致 根设备挂载失败,没有根设备,最后内核就崩溃了。 所以首先要明白第一个问题,为什么 UBI 无法附加到 MTD,先 看下 MTD和UBI描述,总结就是:UBi是MTD之上的一个管理层,专门为NAND Flash设计,MTD负责底层的硬件访问和抽象,而UBi则负责逻辑卷管理、坏块管理和磨损均衡等高级功能 。 那为什么出现这个错误?
- 先想到是不是 内核不支持 ubi, 然后看 ubi文档,发现为了支持 ubi 磁盘管理系统,内核的一些选项和文档一样都是打开的,也就是内核支持 ubi,所以不是这个原因
错误log信息
ubi0 error: ubi_read_volume_table: the layout volume was not found ubi0 error: ubi_attach_mtd_dev: failed to attach mtd2, error -22 # UBI(Unsorted Block Images)子系统无法附加到 MTD(Memory Technology Device)设备 mtd2 UBI error: cannot attach mtd2 hctosys: unable to open rtc device (rtc0) clk: Not disabling unused clocks ALSA device list: No soundcards found. uart-pl011 11040000.uart: no DMA platform data VFS: Cannot open root device "ubi0:rootfs" or unknown-block(0,0): error -19 # 意思是系统无法挂载根设备 ubi0:rootfs,错误 -19 通常表示“没有这样的设备” Please append a correct "root=" boot option; here are the available partitions: 0100 65536 ram0 (driver?) 0101 65536 ram1 (driver?) 0102 65536 ram2 (driver?) 0103 65536 ram3 (driver?) 0104 65536 ram4 (driver?) 0105 65536 ram5 (driver?) 0106 65536 ram6 (driver?) 0107 65536 ram7 (driver?) 0108 65536 ram8 (driver?) 0109 65536 ram9 (driver?) 010a 65536 ram10 (driver?) 010b 65536 ram11 (driver?) 010c 65536 ram12 (driver?) 010d 65536 ram13 (driver?) 010e 65536 ram14 (driver?) 010f 65536 ram15 (driver?) 1f00 2048 mtdblock0 (driver?) 1f01 12288 mtdblock1 (driver?) 1f02 32768 mtdblock2 (driver?) 1f03 65536 mtdblock3 (driver?) 1f04 8192 mtdblock4 (driver?) 1f05 10240 mtdblock5 (driver?) Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0) # 由于无法挂载根文件系统,系统进入内核崩溃状态 CPU: 0 PID: 1 Comm: swapper/0 Not tainted 4.19.90 #7 Hardware name: Vendor SS928V100 DEMO Board (DT)
MTD和UBI描述
一、MTD的基本概念 MTD(Memory Technology Device)是Linux内核中的一个子系统,它主要用于支持不同类型的闪存设备,如NOR Flash和NAND Flash。MTD提供了一个抽象层,使得文件系统和用户空间程序可以方便地访问底层的闪存硬件。在Linux系统中,MTD设备通常以“/dev/mtdX”和“/dev/mtdblockX”的形式出现,其中X是设备编号。 二、UBi的特性和功能 UBi是一种专为原始闪存设备设计的卷管理系统,它运行在MTD之上,并处理闪存的复杂性,如坏块管理和磨损均衡(wear leveling)。UBi将闪存划分为逻辑擦除块(LEB),并对它们进行管理。其主要功能和特性包括: 坏块管理:UBi能够检测和管理坏块,确保数据写入时不会使用坏块。 磨损均衡:通过均匀分布擦写操作,UBi可以延长闪存的使用寿命。 逻辑卷管理:UBi支持在MTD设备上创建多个逻辑卷,每个卷可以独立使用。 三、UBi和MTD的关系 层级关系:UBi是MTD之上的一个管理层,专门为NAND Flash设计。它处理了NAND Flash固有的一些复杂性,并提供了逻辑卷管理功能。 依赖关系:UBi依赖于MTD来访问底层的闪存硬件。MTD提供了对底层闪存硬件的抽象和基本管理,而UBi则在此基础上增加了更高级的管理功能。 协同工作:在Linux系统中,MTD和UBi通常协同工作,以提供高效、可靠的闪存管理解决方案。MTD负责底层的硬件访问和抽象,而UBi则负责逻辑卷管理、坏块管理和磨损均衡等高级功能。 四、应用场景 UBi和MTD的组合特别适用于嵌入式系统和移动设备,这些设备通常使用NAND Flash作为存储设备。通过提供高效的闪存管理和优化性能,UBi和MTD可以帮助这些设备实现更好的稳定性和可靠性。 综上所述,UBi和MTD之间存在紧密的层级和依赖关系,它们共同为Linux系统中的闪存设备提供了高效、可靠的管理解决方案。
- 那另一个问题:可能是 内核不支持 这个 flase, 于是问了罗工,它说在 sdk/SS928V100_SDK_V2.0.2.2/open_source/linux/linux-4.19.y/drivers/mtd/nand/fmc100/fmc_spi_nand_ids.c 文件的 fmc_spi_nand_flash_table[ ] 数组里有官方默认支持的 flash 的列表,如果你的 flase 不在列表里需要自己添加。那具体要加什么呢?此时去看之前可以运行的内核的启动信息,找到
SPI Nand(cs 0) ID: 0xc9 0x21
关键字,可以看到 flash 的 id 。 这时,罗工给了我一个海康 flash 的新增列表,加进去之后重新编译make ARCH=arm64 CROSS_COMPILE=aarch64-mix210-linux- uImag -j20
然后打包为 atf 格式镜像,发现还是报同样的错,说明这个flase不是海康的,最后问 朴工,添加朴工给的 falsh 列表就可以了,见 添加朴工flash源文件海康flash新增列表
static struct spi_nand_info fmc_spi_nand_flash_table[] = { #if 1 //添加海康SPI NAND FLASH /* HSESFHCSW1G 1.8V 1G-BIT */ //hgpark { .name = "HSESFHCSW1G", .id = {0xc9, 0x21}, .id_len = 2, .chipsize = _128M, .erasesize = _128K, .pagesize = _2K, .oobsize = 64, .badblock_pos = BBP_FIRST_PAGE, .read = { &read_std(1, INFINITE, 24), &read_fast(1, INFINITE, 88), &read_dual(1, INFINITE, 88), &read_dual_addr(1, INFINITE, 88), &read_quad(1, INFINITE, 88), &read_quad_addr(2, INFINITE, 88), 0 }, .write = { &write_std(0, 256, 88), &write_quad(0, 256, 88), 0 }, .erase = { &erase_sector_128k(0, _128K, 88), 0 }, .driver = &spi_driver_general,// &spi_driver_no_qe, }, /* HSESFHCSW1G 1.8V 1G-BIT */ //hgpark { .name = "HSESFHCSW1G", .id = {0x7C, 0xC1}, .id_len = 2, .chipsize = _128M, .erasesize = _128K, .pagesize = _2K, .oobsize = 64, .badblock_pos = BBP_FIRST_PAGE, .read = { &read_std(1, INFINITE, 24), &read_fast(1, INFINITE, 88), &read_dual(1, INFINITE, 88), &read_dual_addr(1, INFINITE, 88), &read_quad(1, INFINITE, 88), &read_quad_addr(2, INFINITE, 88), 0 }, .write = { &write_std(0, 256, 88), &write_quad(0, 256, 88), 0 }, .erase = { &erase_sector_128k(0, _128K, 88), 0 }, .driver = &spi_driver_general,// &spi_driver_no_qe, }, #endif ...
添加朴工flash源文件:fmc_spi_nand_ids.c
/* * The Flash Memory Controller v100 Device Driver for vendor * * Copyright (c) 2016 Shenshu Technologies Co., Ltd. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ #include <asm/setup.h> #include <linux/types.h> #include <linux/io.h> #include <linux/sched.h> #include <linux/printk.h> #include <linux/platform_device.h> #include <linux/mtd/rawnand.h> #include <linux/mtd/partitions.h> #include <linux/mfd/bsp_fmc.h> #include <linux/uaccess.h> #include "../raw/nfc_gen.h" #include "fmc100.h" #include <linux/securec.h> // fx-11-13 set_read_fast(1, INFINITE, 88); set_read_dual(1, INFINITE, 88); set_read_dual_addr(1, INFINITE, 88); set_read_quad(1, INFINITE, 88); set_read_quad_addr(2, INFINITE, 88); set_write_std(0, 256, 88); set_write_quad(0, 256, 88); set_erase_sector_128k(0, _128K, 88); set_read_std(1, INFINITE, 24); set_read_fast(1, INFINITE, 80); set_read_fast(1, INFINITE, 100); set_read_fast(1, INFINITE, 104); set_read_fast(1, INFINITE, 108); set_read_fast(1, INFINITE, 120); set_read_fast(1, INFINITE, 133); set_read_dual(1, INFINITE, 80); set_read_dual(1, INFINITE, 100); set_read_dual(1, INFINITE, 104); set_read_dual(1, INFINITE, 108); set_read_dual(1, INFINITE, 120); set_read_dual(1, INFINITE, 133); set_read_dual_addr(1, INFINITE, 40); set_read_dual_addr(1, INFINITE, 80); set_read_dual_addr(2, INFINITE, 80); set_read_dual_addr(1, INFINITE, 100); set_read_dual_addr(1, INFINITE, 104); set_read_dual_addr(1, INFINITE, 108); set_read_dual_addr(1, INFINITE, 120); set_read_dual_addr(2, INFINITE, 104); set_read_quad(1, INFINITE, 80); set_read_quad(1, INFINITE, 100); set_read_quad(1, INFINITE, 104); set_read_quad(1, INFINITE, 108); set_read_quad(1, INFINITE, 120); set_read_quad(1, INFINITE, 133); set_read_quad_addr(2, INFINITE, 40); set_read_quad_addr(1, INFINITE, 80); set_read_quad_addr(2, INFINITE, 80); set_read_quad_addr(4, INFINITE, 80); set_read_quad_addr(1, INFINITE, 100); set_read_quad_addr(1, INFINITE, 104); set_read_quad_addr(2, INFINITE, 104); set_read_quad_addr(1, INFINITE, 108); set_read_quad_addr(1, INFINITE, 120); set_read_quad_addr(4, INFINITE, 104); set_write_std(0, 256, 24); set_write_std(0, 256, 75); set_write_std(0, 256, 80); set_write_std(0, 256, 100); set_write_std(0, 256, 104); set_write_std(0, 256, 133); set_write_quad(0, 256, 80); set_write_quad(0, 256, 100); set_write_quad(0, 256, 104); set_write_quad(0, 256, 108); set_write_quad(0, 256, 120); set_write_quad(0, 256, 133); set_erase_sector_128k(0, _128K, 24); set_erase_sector_128k(0, _128K, 75); set_erase_sector_128k(0, _128K, 80); set_erase_sector_128k(0, _128K, 104); set_erase_sector_128k(0, _128K, 133); set_erase_sector_256k(0, _256K, 24); set_erase_sector_256k(0, _256K, 75); set_erase_sector_256k(0, _256K, 80); set_erase_sector_256k(0, _256K, 100); set_erase_sector_256k(0, _256K, 104); set_erase_sector_256k(0, _256K, 133); #include "fmc100_spi_general.c" static struct spi_drv spi_driver_general = { .wait_ready = spi_general_wait_ready, .write_enable = spi_general_write_enable, .qe_enable = spi_general_qe_enable, }; /* some spi nand flash default QUAD enable, needn't to set qe enable */ static struct spi_drv spi_driver_no_qe = { .wait_ready = spi_general_wait_ready, .write_enable = spi_general_write_enable, }; #define SPI_NAND_ID_TAB_VER "2.7" /****************************************************************************** * We do not guarantee the compatibility of the following device models in the * table.Device compatibility is based solely on the list of compatible devices * in the release package. ******************************************************************************/ struct spi_nand_info fmc_spi_nand_flash_table[] = { #if 1 //fx-11-13 添加非官方支持的 NAND FLASH /* MXIC MX35UF1G24AD 1Gbit 1.8V */ //hgpark { .name = "MX35UF1G24AD", .id = {0xc2, 0x94, 0x03}, .id_len = 2, .chipsize = _128M, .erasesize = _128K, .pagesize = _2K, .oobsize = 128, .badblock_pos = BBP_FIRST_PAGE, .read = { &read_std(1, INFINITE, 24), /* 20MHz */ &read_fast(1, INFINITE, 104), /* 120MHz */ &read_dual(1, INFINITE, 104), /* 120MHz */ &read_dual_addr(1, INFINITE, 104), /* 108MHz */ &read_quad(1, INFINITE, 104), /* 120MHz */ &read_quad_addr(2, INFINITE, 104), /* 108MHz */ 0 }, .write = { &write_std(0, 256, 24), /* 24MHz */ &write_quad(0, 256, 104), /* 120MHz */ 0 }, .erase = { &erase_sector_128k(0, _128K, 104), /* 120MHz */ 0 }, .driver = &spi_driver_general, //spi_driver_no_qe }, /* HSESFHCSW1G 1.8V 1G-BIT */ //hgpark { .name = "HSESFHCSW1G", .id = {0x7C, 0xC1}, .id_len = 2, .chipsize = _128M, .erasesize = _128K, .pagesize = _2K, .oobsize = 64, .badblock_pos = BBP_FIRST_PAGE, .read = { &read_std(1, INFINITE, 24), &read_fast(1, INFINITE, 80), &read_dual(1, INFINITE, 80), &read_dual_addr(1, INFINITE, 80), &read_quad(1, INFINITE, 80), &read_quad_addr(2, INFINITE, 80), 0 }, .write = { &write_std(0, 256, 80), &write_quad(0, 256, 80), 0 }, .erase = { &erase_sector_128k(0, _128K, 80), 0 }, .driver = &spi_driver_general, //spi_driver_no_qe, }, /* HSESFHCSW1G 1.8V 1G-BIT */ //hgpark { .name = "HSESFHCSW1G", .id = {0xc9, 0x21}, .id_len = 2, .chipsize = _128M, .erasesize = _128K, .pagesize = _2K, .oobsize = 64, .badblock_pos = BBP_FIRST_PAGE, .read = { &read_std(1, INFINITE, 24), &read_fast(1, INFINITE, 80), &read_dual(1, INFINITE, 80), &read_dual_addr(1, INFINITE, 80), &read_quad(1, INFINITE, 80), &read_quad_addr(1, INFINITE, 80), 0 }, .write = { &write_std(0, 256, 80), &write_quad(0, 256, 80), 0 }, .erase = { &erase_sector_128k(0, _128K, 80), 0 }, .driver = &spi_driver_general, //spi_driver_no_qe, }, #endif /* Micron MT29F1G01ABA 1GBit */ /* name id id_len chipsize(Bytes) erasesize pagesize oobsize(Bytes) */ { .name = "MT29F1G01ABA", .id = {0x2C, 0x14}, .id_len = 2, .chipsize = _128M, .erasesize = _128K, .pagesize = _2K, .oobsize = 128, .badblock_pos = BBP_FIRST_PAGE, .read = { /* dummy clock:1 byte, read size:INFINITE bytes, * clock frq:24MHz */ &read_std(1, INFINITE, 24), /* 24MHz */ &read_fast(1, INFINITE, 80), /* 80MHz */ &read_dual(1, INFINITE, 80), /* 80MHz */ &read_dual_addr(1, INFINITE, 80), /* 80MHz */ &read_quad(1, INFINITE, 80), /* 80MHz */ &read_quad_addr(2, INFINITE, 80), /* 80MHz */ 0 }, .write = { /* dummy clock:0 byte, write size:256 bytes, * clock frq:80MHz */ &write_std(0, 256, 80), /* 80MHz 256 bytes*/ &write_quad(0, 256, 80), /* 80MHz 256 bytes*/ 0 }, .erase = { /* dummy clock:0 byte, write size:128KB, * clock frq:80MHz */ &erase_sector_128k(0, _128K, 80), /* 80MHz */ 0 }, .driver = &spi_driver_no_qe, }, /* Micron MT29F1G01ABB 1GBit 1.8V */ { .name = "MT29F1G01ABB", .id = {0x2C, 0x15}, .id_len = 2, .chipsize = _128M, .erasesize = _128K, .pagesize = _2K, .oobsize = 128, .badblock_pos = BBP_FIRST_PAGE, .read = { &read_std(1, INFINITE, 24), &read_fast(1, INFINITE, 80), &read_dual(1, INFINITE, 80), &read_dual_addr(1, INFINITE, 80), &read_quad(1, INFINITE, 80), &read_quad_addr(2, INFINITE, 80), 0 }, .write = { &write_std(0, 256, 80), &write_quad(0, 256, 80), 0 }, .erase = { &erase_sector_128k(0, _128K, 80), 0 }, .driver = &spi_driver_no_qe, }, /* Micron MT29F2G01ABA 2GBit */ { .name = "MT29F2G01ABA", .id = {0x2C, 0x24}, .id_len = 2, .chipsize = _256M, .erasesize = _128K, .pagesize = _2K, .oobsize = 128, .badblock_pos = BBP_FIRST_PAGE, .read = { &read_std(1, INFINITE, 24), &read_fast(1, INFINITE, 108), &read_dual(1, INFINITE, 108), &read_dual_addr(1, INFINITE, 108), &read_quad(1, INFINITE, 108), &read_quad_addr(2, INFINITE, 104), 0 }, .write = { &write_std(0, 256, 80), &write_quad(0, 256, 108), 0 }, .erase = { &erase_sector_128k(0, _128K, 80), 0 }, .driver = &spi_driver_no_qe, }, /* Micron MT29F2G01ABB 2GBit 1.8V */ { .name = "MT29F2G01ABB", .id = {0x2C, 0x25}, .id_len = 2, .chipsize = _256M, .erasesize = _128K, .pagesize = _2K, .oobsize = 128, .badblock_pos = BBP_FIRST_PAGE, .read = { &read_std(1, INFINITE, 24), &read_fast(1, INFINITE, 80), &read_dual(1, INFINITE, 80), &read_dual_addr(1, INFINITE, 80), &read_quad(1, INFINITE, 80), &read_quad_addr(2, INFINITE, 80), 0 }, .write = { &write_std(0, 256, 80), &write_quad(0, 256, 80), 0 }, .erase = { &erase_sector_128k(0, _128K, 80), 0 }, .driver = &spi_driver_no_qe, }, /* Micron MT29F4G01ADAG 4GBit 3.3V */ { .name = "MT29F4G01ADAG", .id = {0x2C, 0x36}, .id_len = 2, .chipsize = _512M, .erasesize = _128K, .pagesize = _2K, .oobsize = 128, .badblock_pos = BBP_FIRST_PAGE, .read = { &read_std(1, INFINITE, 24), &read_fast(1, INFINITE, 108), &read_dual(1, INFINITE, 108), &read_dual_addr(1, INFINITE, 108), &read_quad(1, INFINITE, 108), &read_quad_addr(2, INFINITE, 104), 0 }, .write = { &write_std(0, 256, 80), &write_quad(0, 256, 108), 0 }, .erase = { &erase_sector_128k(0, _128K, 80), 0 }, .driver = &spi_driver_no_qe, }, /* ESMT F50L512M41A 512Mbit */ { .name = "F50L512M41A", .id = {0xC8, 0x20}, .id_len = 2, .chipsize = _64M, .erasesize = _128K, .pagesize = _2K, .oobsize = 64, .badblock_pos = BBP_FIRST_PAGE, .read = { &read_std(1, INFINITE, 24), &read_fast(1, INFINITE, 104), &read_dual(1, INFINITE, 104), &read_quad(1, INFINITE, 104), 0 }, .write = { &write_std(0, 256, 24), &write_quad(0, 256, 104), 0 }, .erase = { &erase_sector_128k(0, _128K, 24), 0 }, .driver = &spi_driver_no_qe, }, /* ESMT F50L1G41A 1Gbit */ { .name = "F50L1G41A", .id = {0xC8, 0x21}, .id_len = 2, .chipsize = _128M, .erasesize = _128K, .pagesize = _2K, .oobsize = 64, .badblock_pos = BBP_FIRST_PAGE, .read = { &read_std(1, INFINITE, 24), &read_fast(1, INFINITE, 104), &read_dual(1, INFINITE, 104), &read_quad(1, INFINITE, 104), 0 }, .write = { &write_std(0, 256, 24), &write_quad(0, 256, 104), 0 }, .erase = { &erase_sector_128k(0, _128K, 24), 0 }, .driver = &spi_driver_no_qe, }, /* GD 3.3v GD5F1GQ5UEYIGY/GD5F1GQ5UEYIGR 1Gbit */ { .name = "GD5F1GQ5UEYIGY", .id = {0xc8, 0x51}, .id_len = 2, .chipsize = _128M, .erasesize = _128K, .pagesize = _2K, .oobsize = 128, .badblock_pos = BBP_FIRST_PAGE, .read = { &read_std(1, INFINITE, 24), &read_fast(1, INFINITE, 133), &read_dual(1, INFINITE, 133), &read_quad(1, INFINITE, 133), 0 }, .write = { &write_std(0, 256, 133), &write_quad(0, 256, 133), 0 }, .erase = { &erase_sector_128k(0, _128K, 133), 0 }, .driver = &spi_driver_general, }, /* ESMT F50L1G41LB-104YG2ME 1Gbit */ { .name = "F50L1G41LB-104YG2ME", .id = {0xC8, 0x01, 0X7F}, .id_len = 3, .chipsize = _128M, .erasesize = _128K, .pagesize = _2K, .oobsize = 64, .badblock_pos = BBP_FIRST_PAGE, .read = { &read_std(1, INFINITE, 24), &read_fast(1, INFINITE, 104), &read_dual(1, INFINITE, 104), &read_quad(1, INFINITE, 104), 0 }, .write = { &write_std(0, 256, 104), &write_quad(0, 256, 104), 0 }, .erase = { &erase_sector_128k(0, _128K, 104), 0 }, .driver = &spi_driver_no_qe, }, /* GD 3.3v GD5F1GQ4UAYIG 1Gbit */ { .name = "GD5F1GQ4UAYIG", .id = {0xc8, 0xf1}, .id_len = 2, .chipsize = _128M, .erasesize = _128K, .pagesize = _2K, .oobsize = 64, .badblock_pos = BBP_FIRST_PAGE, .read = { &read_std(1, INFINITE, 24), &read_fast(1, INFINITE, 120), &read_dual(1, INFINITE, 120), &read_dual_addr(1, INFINITE, 120), &read_quad(1, INFINITE, 120), &read_quad_addr(1, INFINITE, 120), 0 }, .write = { &write_std(0, 256, 24), &write_quad(0, 256, 120), 0 }, .erase = { &erase_sector_128k(0, _128K, 24), 0 }, .driver = &spi_driver_general, }, /* GD 1.8v GD5F1GQ5REYIG 1Gbit */ { .name = "GD5F1GQ5REYIG", .id = {0xc8, 0x41}, .id_len = 2, .chipsize = _128M, .erasesize = _128K, .pagesize = _2K, .oobsize = 128, .badblock_pos = BBP_FIRST_PAGE, .read = { &read_std(1, INFINITE, 24), &read_fast(1, INFINITE, 104), &read_dual(1, INFINITE, 104), &read_quad(1, INFINITE, 104), 0 }, .write = { &write_std(0, 256, 24), &write_quad(0, 256, 104), 0 }, .erase = { &erase_sector_128k(0, _128K, 104), 0 }, .driver = &spi_driver_general, }, /* GD 3.3v GD5F1GQ4UEYIHY 1Gbit */ { .name = "GD5F1GQ4UEYIHY", .id = {0xc8, 0xd9}, .id_len = 2, .chipsize = _128M, .erasesize = _128K, .pagesize = _2K, .oobsize = 64, .badblock_pos = BBP_FIRST_PAGE, .read = { &read_std(1, INFINITE, 24), &read_fast(1, INFINITE, 120), &read_dual(1, INFINITE, 120), &read_dual_addr(1, INFINITE, 120), &read_quad(1, INFINITE, 120), &read_quad_addr(1, INFINITE, 120), 0 }, .write = { &write_std(0, 256, 104), &write_quad(0, 256, 120), 0 }, .erase = { &erase_sector_128k(0, _128K, 104), 0 }, .driver = &spi_driver_general, }, /* GD 1.8v GD5F1GQ4RB9IG 1Gbit */ { .name = "GD5F1GQ4RB9IG", .id = {0xc8, 0xc1}, .id_len = 2, .chipsize = _128M, .erasesize = _128K, .pagesize = _2K, .oobsize = 128, .badblock_pos = BBP_FIRST_PAGE, .read = { &read_std(1, INFINITE, 24), &read_fast(1, INFINITE, 120), &read_dual(1, INFINITE, 120), &read_dual_addr(1, INFINITE, 120), &read_quad(1, INFINITE, 120), &read_quad_addr(1, INFINITE, 120), 0 }, .write = { &write_std(0, 256, 24), &write_quad(0, 256, 120), 0 }, .erase = { &erase_sector_128k(0, _128K, 24), 0 }, .driver = &spi_driver_general, }, /* GD 3.3v GD5F1GQ4UBYIG 1Gbit */ { .name = "GD5F1GQ4UBYIG", .id = {0xc8, 0xd1}, .id_len = 2, .chipsize = _128M, .erasesize = _128K, .pagesize = _2K, .oobsize = 128, .badblock_pos = BBP_FIRST_PAGE, .read = { &read_std(1, INFINITE, 24), &read_fast(1, INFINITE, 120), &read_dual(1, INFINITE, 120), &read_dual_addr(1, INFINITE, 120), &read_quad(1, INFINITE, 120), &read_quad_addr(1, INFINITE, 120), 0 }, .write = { &write_std(0, 256, 24), &write_quad(0, 256, 120), 0 }, .erase = { &erase_sector_128k(0, _128K, 24), 0 }, .driver = &spi_driver_general, }, /* GD 3.3v GD5F2GQ4UAYIG 2Gbit */ { .name = "GD5F2GQ4UAYIG", .id = {0xc8, 0xf2}, .id_len = 2, .chipsize = _256M, .erasesize = _128K, .pagesize = _2K, .oobsize = 64, .badblock_pos = BBP_FIRST_PAGE, .read = { &read_std(1, INFINITE, 24), &read_fast(1, INFINITE, 120), &read_dual(1, INFINITE, 120), &read_dual_addr(1, INFINITE, 120), &read_quad(1, INFINITE, 120), &read_quad_addr(1, INFINITE, 120), 0 }, .write = { &write_std(0, 256, 24), &write_quad(0, 256, 120), 0 }, .erase = { &erase_sector_128k(0, _128K, 24), 0 }, .driver = &spi_driver_general, }, /* GD 3.3v GD5F2GQ4U9IGR/BYIG 2Gbit */ { .name = "GD5F2GQ4U9IGR/BYIG", .id = {0xc8, 0xd2}, .id_len = 2, .chipsize = _256M, .erasesize = _128K, .pagesize = _2K, .oobsize = 128, .badblock_pos = BBP_FIRST_PAGE, .read = { &read_std(1, INFINITE, 24), &read_fast(1, INFINITE, 120), &read_dual(1, INFINITE, 120), &read_dual_addr(1, INFINITE, 120), &read_quad(1, INFINITE, 120), &read_quad_addr(1, INFINITE, 120), 0 }, .write = { &write_std(0, 256, 24), &write_quad(0, 256, 120), 0 }, .erase = { &erase_sector_128k(0, _128K, 24), 0 }, .driver = &spi_driver_general, }, /* GD 3.3v GD5F2GQ5UEYIG 2Gbit */ { .name = "GD5F2GQ5UEYIG", .id = {0xc8, 0x52}, .id_len = 2, .chipsize = _256M, .erasesize = _128K, .pagesize = _2K, .oobsize = 128, .badblock_pos = BBP_FIRST_PAGE, .read = { &read_std(1, INFINITE, 24), &read_fast(1, INFINITE, 104), &read_dual(1, INFINITE, 104), &read_dual_addr(2, INFINITE, 104), &read_quad(1, INFINITE, 104), &read_quad_addr(4, INFINITE, 104), 0 }, .write = { &write_std(0, 256, 104), &write_quad(0, 256, 120), 0 }, .erase = { &erase_sector_128k(0, _128K, 104), 0 }, .driver = &spi_driver_general, }, /* GD 1.8v GD5F2GQ5REYIG 2Gbit */ { .name = "GD5F2GQ5REYIG", .id = {0xc8, 0x42}, .id_len = 2, .chipsize = _256M, .erasesize = _128K, .pagesize = _2K, .oobsize = 128, .badblock_pos = BBP_FIRST_PAGE, .read = { &read_std(1, INFINITE, 24), &read_fast(1, INFINITE, 104), &read_dual(1, INFINITE, 104), &read_dual_addr(2, INFINITE, 104), &read_quad(1, INFINITE, 104), &read_quad_addr(4, INFINITE, 104), 0 }, .write = { &write_std(0, 256, 104), &write_quad(0, 256, 104), 0 }, .erase = { &erase_sector_128k(0, _128K, 104), 0 }, .driver = &spi_driver_general, }, /* GD 3.3v GD5F4GQ4UAYIG 4Gbit */ { .name = "GD5F4GQ4UAYIG", .id = {0xc8, 0xf4}, .id_len = 2, .chipsize = _512M, .erasesize = _128K, .pagesize = _2K, .oobsize = 64, .badblock_pos = BBP_FIRST_PAGE, .read = { &read_std(1, INFINITE, 24), &read_fast(1, INFINITE, 120), &read_dual(1, INFINITE, 120), &read_dual_addr(1, INFINITE, 120), &read_quad(1, INFINITE, 120), &read_quad_addr(1, INFINITE, 120), 0 }, .write = { &write_std(0, 256, 24), &write_quad(0, 256, 120), 0 }, .erase = { &erase_sector_128k(0, _128K, 24), 0 }, .driver = &spi_driver_general, }, /* GD 3.3v GD5F4GQ4UBYIG 4Gbit */ { .name = "GD5F4GQ4UBYIG", .id = {0xc8, 0xd4}, .id_len = 2, .chipsize = _512M, .erasesize = _256K, .pagesize = _4K, .oobsize = 256, .badblock_pos = BBP_FIRST_PAGE, .read = { &read_std(1, INFINITE, 24), &read_fast(1, INFINITE, 120), &read_dual(1, INFINITE, 120), &read_dual_addr(1, INFINITE, 120), &read_quad(1, INFINITE, 120), &read_quad_addr(1, INFINITE, 120), 0 }, .write = { &write_std(0, 256, 24), &write_quad(0, 256, 120), 0 }, .erase = { &erase_sector_256k(0, _256K, 24), 0 }, .driver = &spi_driver_general, }, /* GD 3.3v GD5F4GQ6UEYIG 4Gbit */ { .name = "GD5F4GQ6UEYIG", .id = {0xc8, 0x55}, .id_len = 2, .chipsize = _512M, .erasesize = _128K, .pagesize = _2K, .oobsize = 128, .badblock_pos = BBP_FIRST_PAGE, .read = { &read_std(1, INFINITE, 24), /* 24MHz */ &read_fast(1, INFINITE, 104), /* 104MHz */ &read_dual(1, INFINITE, 104), /* 104MHz */ &read_dual_addr(2, INFINITE, 104), /* 104MHz */ &read_quad(1, INFINITE, 104), /* 104MHz */ &read_quad_addr(4, INFINITE, 104), /* 104MHz */ 0 }, .write = { &write_std(0, 256, 24), /* 24MHz */ &write_quad(0, 256, 104), /* 104MHz */ 0 }, .erase = { &erase_sector_128k(0, _128K, 104), /* 104MHz */ 0 }, .driver = &spi_driver_general, }, /* GD 1.8V GD5F1GQ4RB9IGR 1Gbit */ { .name = "GD5F1GQ4RB9IGR", .id = {0xc8, 0xc1}, .id_len = 2, .chipsize = _128M, .erasesize = _128K, .pagesize = _2K, .oobsize = 128, .badblock_pos = BBP_FIRST_PAGE, .read = { &read_std(1, INFINITE, 24), &read_fast(1, INFINITE, 104), &read_dual(1, INFINITE, 104), &read_dual_addr(1, INFINITE, 104), &read_quad(1, INFINITE, 104), &read_quad_addr(1, INFINITE, 104), 0 }, .write = { &write_std(0, 256, 24), &write_quad(0, 256, 104), 0 }, .erase = { &erase_sector_128k(0, _128K, 24), 0 }, .driver = &spi_driver_general, }, /* GD 1.8V GD5F2GQ4RB9IGR 2Gbit */ { .name = "GD5F2GQ4RB9IGR", .id = {0xc8, 0xc2}, .id_len = 2, .chipsize = _256M, .erasesize = _128K, .pagesize = _2K, .oobsize = 128, .badblock_pos = BBP_FIRST_PAGE, .read = { &read_std(1, INFINITE, 24), &read_fast(1, INFINITE, 104), &read_dual(1, INFINITE, 104), &read_dual_addr(1, INFINITE, 104), &read_quad(1, INFINITE, 104), &read_quad_addr(1, INFINITE, 104), 0 }, .write = { &write_std(0, 256, 24), &write_quad(0, 256, 104), 0 }, .erase = { &erase_sector_128k(0, _128K, 24), 0 }, .driver = &spi_driver_general, }, /* GD 1.8V 5F4GQ6RE9IG 4Gbit */ { .name = "GD5F4GQ6RE9IG", .id = {0xc8, 0x45}, .id_len = 2, .chipsize = _512M, .erasesize = _128K, .pagesize = _2K, .oobsize = 128, .badblock_pos = BBP_FIRST_PAGE, .read = { &read_std(1, INFINITE, 24), &read_fast(1, INFINITE, 80), &read_dual(1, INFINITE, 80), &read_dual_addr(2, INFINITE, 80), &read_quad(1, INFINITE, 80), &read_quad_addr(4, INFINITE, 80), 0 }, .write = { &write_std(0, 256, 80), &write_quad(0, 256, 80), 0 }, .erase = { &erase_sector_128k(0, _128K, 80), 0 }, .driver = &spi_driver_general, }, /* GD 1.8V GD5F4GQ4RAYIG 4Gbit */ { .name = "GD5F4GQ4RAYIG", .id = {0xc8, 0xe4}, .id_len = 2, .chipsize = _512M, .erasesize = _256K, .pagesize = _4K, .oobsize = 256, .badblock_pos = BBP_FIRST_PAGE, .read = { &read_std(1, INFINITE, 24), &read_fast(1, INFINITE, 104), &read_dual(1, INFINITE, 104), &read_dual_addr(1, INFINITE, 104), &read_quad(1, INFINITE, 104), &read_quad_addr(1, INFINITE, 104), 0 }, .write = { &write_std(0, 256, 24), &write_quad(0, 256, 104), 0 }, .erase = { &erase_sector_256k(0, _256K, 24), 0 }, .driver = &spi_driver_general, }, /* Winbond 1.8V W25N02JWZEIF 2Gbit */ { .name = "W25N02JWZEIF", .id = {0xef, 0xbf, 0x22}, .id_len = 3, .chipsize = _256M, .erasesize = _128K, .pagesize = _2K, .oobsize = 64, .badblock_pos = BBP_FIRST_PAGE, .read = { &read_std(1, INFINITE, 24), &read_fast(1, INFINITE, 120), &read_dual(1, INFINITE, 120), &read_dual_addr(1, INFINITE, 120), &read_quad(1, INFINITE, 120), &read_quad_addr(2, INFINITE, 104), 0 }, .write = { &write_std(0, 256, 104), &write_quad(0, 256, 104), 0 }, .erase = { &erase_sector_128k(0, _128K, 104), 0 }, .driver = &spi_driver_general, }, /* GD 1.8V 5F4GQ4RBYIG 4Gbit */ { .name = "5F4GQ4RBYIG", .id = {0xc8, 0xc4}, .id_len = 2, .chipsize = _512M, .erasesize = _256K, .pagesize = _4K, .oobsize = 256, .badblock_pos = BBP_FIRST_PAGE, .read = { &read_std(1, INFINITE, 24), &read_fast(1, INFINITE, 120), &read_dual(1, INFINITE, 120), &read_dual_addr(1, INFINITE, 120), &read_quad(1, INFINITE, 120), &read_quad_addr(1, INFINITE, 120), 0 }, .write = { &write_std(0, 256, 24), &write_quad(0, 256, 120), 0 }, .erase = { &erase_sector_256k(0, _256K, 24), 0 }, .driver = &spi_driver_general, }, /* Winbond W25N01GV 1Gbit 3.3V */ { .name = "W25N01GV", .id = {0xef, 0xaa, 0x21}, .id_len = 3, .chipsize = _128M, .erasesize = _128K, .pagesize = _2K, .oobsize = 64, .badblock_pos = BBP_FIRST_PAGE, .read = { &read_std(1, INFINITE, 24), &read_fast(1, INFINITE, 104), &read_dual(1, INFINITE, 104), &read_dual_addr(1, INFINITE, 104), &read_quad(1, INFINITE, 104), &read_quad_addr(2, INFINITE, 104), 0 }, .write = { &write_std(0, 256, 24), &write_quad(0, 256, 104), 0 }, .erase = { &erase_sector_128k(0, _128K, 24), 0 }, .driver = &spi_driver_no_qe, }, /* Winbond W25N01GWZEIG 1Gbit 1.8V */ { .name = "W25N01GWZEIG", .id = {0xef, 0xba, 0x21}, .id_len = 3, .chipsize = _128M, .erasesize = _128K, .pagesize = _2K, .oobsize = 64, .badblock_pos = BBP_FIRST_PAGE, .read = { &read_std(1, INFINITE, 24), &read_fast(1, INFINITE, 104), &read_dual(1, INFINITE, 104), &read_dual_addr(1, INFINITE, 104), &read_quad(1, INFINITE, 104), &read_quad_addr(2, INFINITE, 104), 0 }, .write = { &write_std(0, 256, 24), &write_quad(0, 256, 80), 0 }, .erase = { &erase_sector_128k(0, _128K, 24), 0 }, .driver = &spi_driver_no_qe, }, /* ATO ATO25D1GA 1Gbit */ { .name = "ATO25D1GA", .id = {0x9b, 0x12}, .id_len = 2, .chipsize = _128M, .erasesize = _128K, .pagesize = _2K, .oobsize = 64, .badblock_pos = BBP_FIRST_PAGE, .read = { &read_std(1, INFINITE, 24), &read_fast(1, INFINITE, 104), &read_quad(1, INFINITE, 104), 0 }, .write = { &write_std(0, 256, 24), &write_quad(0, 256, 104), 0 }, .erase = { &erase_sector_128k(0, _128K, 24), 0 }, .driver = &spi_driver_general, }, /* MXIC MX35LF1GE4AB 1Gbit */ { .name = "MX35LF1GE4AB", .id = {0xc2, 0x12}, .id_len = 2, .chipsize = _128M, .erasesize = _128K, .pagesize = _2K, .oobsize = 64, .badblock_pos = BBP_FIRST_PAGE, .read = { &read_std(1, INFINITE, 24), &read_fast(1, INFINITE, 104), &read_quad(1, INFINITE, 104), 0 }, .write = { &write_std(0, 256, 24), &write_quad(0, 256, 104), 0 }, .erase = { &erase_sector_128k(0, _128K, 24), 0 }, .driver = &spi_driver_general, }, /* MXIC MX35UF1G14AC 1Gbit 1.8V */ { .name = "MX35UF1G14AC", .id = {0xc2, 0x90}, .id_len = 2, .chipsize = _128M, .erasesize = _128K, .pagesize = _2K, .oobsize = 64, .badblock_pos = BBP_FIRST_PAGE, .read = { &read_std(1, INFINITE, 24), &read_fast(1, INFINITE, 104), &read_quad(1, INFINITE, 104), 0 }, .write = { &write_std(0, 256, 24), &write_quad(0, 256, 104), 0 }, .erase = { &erase_sector_128k(0, _128K, 104), 0 }, .driver = &spi_driver_general, }, /* MXIC MX35LF2GE4AB 2Gbit SOP-16Pin */ { .name = "MX35LF2GE4AB", .id = {0xc2, 0x22}, .id_len = 2, .chipsize = _256M, .erasesize = _128K, .pagesize = _2K, .oobsize = 64, .badblock_pos = BBP_FIRST_PAGE, .read = { &read_std(1, INFINITE, 24), &read_fast(1, INFINITE, 104), &read_quad(1, INFINITE, 104), 0 }, .write = { &write_std(0, 256, 24), &write_quad(0, 256, 104), 0 }, .erase = { &erase_sector_128k(0, _128K, 24), 0 }, .driver = &spi_driver_general, }, /* MXIC MX35LF2G14AC 2GBit */ { .name = "MX35LF2G14AC", .id = {0xc2, 0x20}, .id_len = 2, .chipsize = _256M, .erasesize = _128K, .pagesize = _2K, .oobsize = 64, .badblock_pos = BBP_FIRST_PAGE, .read = { &read_std(1, INFINITE, 24), &read_fast(1, INFINITE, 104), &read_quad(1, INFINITE, 104), 0 }, .write = { &write_std(0, 256, 24), &write_quad(0, 256, 104), 0 }, .erase = { &erase_sector_128k(0, _128K, 24), 0 }, .driver = &spi_driver_general, }, /* MXIC MX35UF2G14AC 2Gbit 1.8V */ { .name = "MX35UF2G14AC", .id = {0xc2, 0xa0}, .id_len = 2, .chipsize = _256M, .erasesize = _128K, .pagesize = _2K, .oobsize = 64, .badblock_pos = BBP_FIRST_PAGE, .read = { &read_std(1, INFINITE, 24), &read_fast(1, INFINITE, 104), &read_quad(1, INFINITE, 104), 0 }, .write = { &write_std(0, 256, 24), &write_quad(0, 256, 104), 0 }, .erase = { &erase_sector_128k(0, _128K, 104), 0 }, .driver = &spi_driver_general, }, /* Paragon PN26G01A 1Gbit */ { .name = "PN26G01A", .id = {0xa1, 0xe1}, .id_len = 2, .chipsize = _128M, .erasesize = _128K, .pagesize = _2K, .oobsize = 128, .badblock_pos = BBP_FIRST_PAGE, .read = { &read_std(1, INFINITE, 24), &read_fast(1, INFINITE, 108), &read_dual(1, INFINITE, 108), &read_dual_addr(1, INFINITE, 108), &read_quad(1, INFINITE, 108), &read_quad_addr(1, INFINITE, 108), 0 }, .write = { &write_std(0, 256, 24), &write_quad(0, 256, 108), 0 }, .erase = { &erase_sector_128k(0, _128K, 24), 0 }, .driver = &spi_driver_general, }, /* Paragon PN26G02A 2Gbit */ { .name = "PN26G02A", .id = {0xa1, 0xe2}, .id_len = 2, .chipsize = _256M, .erasesize = _128K, .pagesize = _2K, .oobsize = 128, .badblock_pos = BBP_FIRST_PAGE, .read = { &read_std(1, INFINITE, 24), &read_fast(1, INFINITE, 108), &read_dual(1, INFINITE, 108), &read_dual_addr(1, INFINITE, 108), &read_quad(1, INFINITE, 108), &read_quad_addr(1, INFINITE, 108), 0 }, .write = { &write_std(0, 256, 24), &write_quad(0, 256, 108), 0 }, .erase = { &erase_sector_128k(0, _128K, 24), 0 }, .driver = &spi_driver_general, }, /* All-flash AFS1GQ4UAC 1Gbit */ { .name = "AFS1GQ4UAC", .id = {0xc1, 0x51}, .id_len = 2, .chipsize = _128M, .erasesize = _128K, .pagesize = _2K, .oobsize = 128, .badblock_pos = BBP_FIRST_PAGE, .read = { &read_std(1, INFINITE, 24), &read_fast(1, INFINITE, 80), &read_dual(1, INFINITE, 80), &read_dual_addr(1, INFINITE, 80), &read_quad(1, INFINITE, 80), &read_quad_addr(1, INFINITE, 80), 0 }, .write = { &write_std(0, 256, 24), &write_quad(0, 256, 80), 0 }, .erase = { &erase_sector_128k(0, _128K, 24), 0 }, .driver = &spi_driver_general, }, /* All-flash AFS2GQ4UAD 2Gbit */ { .name = "AFS2GQ4UAD", .id = {0xc1, 0x52}, .id_len = 2, .chipsize = _256M, .erasesize = _128K, .pagesize = _2K, .oobsize = 128, .badblock_pos = BBP_FIRST_PAGE, .read = { &read_std(1, INFINITE, 24), &read_fast(1, INFINITE, 80), &read_dual(1, INFINITE, 80), &read_dual_addr(1, INFINITE, 80), &read_quad(1, INFINITE, 80), &read_quad_addr(1, INFINITE, 80), 0 }, .write = { &write_std(0, 256, 24), &write_quad(0, 256, 80), 0 }, .erase = { &erase_sector_128k(0, _128K, 24), 0 }, .driver = &spi_driver_general, }, /* TOSHIBA TC58CVG0S3H 1Gbit */ { .name = "TC58CVG0S3H", .id = {0x98, 0xc2}, .id_len = 2, .chipsize = _128M, .erasesize = _128K, .pagesize = _2K, .oobsize = 128, .badblock_pos = BBP_FIRST_PAGE, .read = { &read_std(1, INFINITE, 24), &read_fast(1, INFINITE, 104), &read_dual(1, INFINITE, 104), &read_quad(1, INFINITE, 104), 0 }, .write = { &write_std(0, 256, 104), 0 }, .erase = { &erase_sector_128k(0, _128K, 104), 0 }, .driver = &spi_driver_no_qe, }, { .name = "TC58CVG0S3HRAIJ", .id = {0x98, 0xe2, 0x40}, .id_len = 3, .chipsize = _128M, .erasesize = _128K, .pagesize = _2K, .oobsize = 128, .badblock_pos = BBP_FIRST_PAGE, .read = { &read_std(1, INFINITE, 24), &read_fast(1, INFINITE, 133), &read_dual(1, INFINITE, 133), &read_quad(1, INFINITE, 133), 0 }, .write = { &write_std(0, 256, 133), &write_quad(0, 256, 133), 0 }, .erase = { &erase_sector_128k(0, _128K, 133), 0 }, .driver = &spi_driver_no_qe, }, /* TOSHIBA TC58CYG0S3H 1.8V 1Gbit */ { .name = "TC58CYG0S3H", .id = {0x98, 0xb2}, .id_len = 2, .chipsize = _128M, .erasesize = _128K, .pagesize = _2K, .oobsize = 128, .badblock_pos = BBP_FIRST_PAGE, .read = { &read_std(1, INFINITE, 24), &read_fast(1, INFINITE, 104), &read_dual(1, INFINITE, 104), &read_quad(1, INFINITE, 104), 0 }, .write = { &write_std(0, 256, 104), 0 }, .erase = { &erase_sector_128k(0, _128K, 104), 0 }, .driver = &spi_driver_no_qe, }, /* TOSHIBA TC58CYG0S3HRAIJ 1.8V 1Gbit */ { .name = "TC58CYG0S3HRAIJ", .id = {0x98, 0xD2, 0x40}, .id_len = 3, .chipsize = _128M, .erasesize = _128K, .pagesize = _2K, .oobsize = 128, .badblock_pos = BBP_FIRST_PAGE, .read = { &read_std(1, INFINITE, 24), &read_fast(1, INFINITE, 133), &read_dual(1, INFINITE, 133), &read_quad(1, INFINITE, 133), 0 }, .write = { &write_std(0, 256, 133), &write_quad(0, 256, 133), 0 }, .erase = { &erase_sector_128k(0, _128K, 133), 0 }, .driver = &spi_driver_no_qe, }, /* TOSHIBA TC58CVG1S3H 2Gbit */ { .name = "TC58CVG1S3H", .id = {0x98, 0xcb}, .id_len = 2, .chipsize = _256M, .erasesize = _128K, .pagesize = _2K, .oobsize = 128, .badblock_pos = BBP_FIRST_PAGE, .read = { &read_std(1, INFINITE, 24), &read_fast(1, INFINITE, 104), &read_dual(1, INFINITE, 104), &read_quad(1, INFINITE, 104), 0 }, .write = { &write_std(0, 256, 104), 0 }, .erase = { &erase_sector_128k(0, _128K, 104), 0 }, .driver = &spi_driver_no_qe, }, /* TOSHIBA TC58CVG1S3HRAIJ 2Gbit */ { .name = "TC58CVG1S3HRAIJ", .id = {0x98, 0xeb, 0x40}, .id_len = 3, .chipsize = _256M, .erasesize = _128K, .pagesize = _2K, .oobsize = 128, .badblock_pos = BBP_FIRST_PAGE, .read = { &read_std(1, INFINITE, 24), &read_fast(1, INFINITE, 133), &read_dual(1, INFINITE, 133), &read_quad(1, INFINITE, 133), 0 }, .write = { &write_std(0, 256, 133), &write_quad(0, 256, 133), 0 }, .erase = { &erase_sector_128k(0, _128K, 133), 0 }, .driver = &spi_driver_no_qe, }, /* TOSHIBA TC58CYG1S3H 1.8V 2Gbit */ { .name = "TC58CYG1S3H", .id = {0x98, 0xbb}, .id_len = 2, .chipsize = _256M, .erasesize = _128K, .pagesize = _2K, .oobsize = 128, .badblock_pos = BBP_FIRST_PAGE, .read = { &read_std(1, INFINITE, 24), &read_fast(1, INFINITE, 104), &read_dual(1, INFINITE, 104), &read_quad(1, INFINITE, 104), 0 }, .write = { &write_std(0, 256, 75), 0 }, .erase = { &erase_sector_128k(0, _128K, 75), 0 }, .driver = &spi_driver_no_qe, }, /* TOSHIBA TC58CYG1S3HRAIJ 1.8V 2Gbit */ { .name = "TC58CYG1S3HRAIJ", .id = {0x98, 0xdb, 0x40}, .id_len = 3, .chipsize = _256M, .erasesize = _128K, .pagesize = _2K, .oobsize = 128, .badblock_pos = BBP_FIRST_PAGE, .read = { &read_std(1, INFINITE, 24), &read_fast(1, INFINITE, 133), &read_dual(1, INFINITE, 133), &read_quad(1, INFINITE, 133), 0 }, .write = { &write_std(0, 256, 133), &write_quad(0, 256, 133), 0 }, .erase = { &erase_sector_128k(0, _128K, 133), 0 }, .driver = &spi_driver_no_qe, }, /* TOSHIBA TC58CVG2S0H 4Gbit */ { .name = "TC58CVG2S0H", .id = {0x98, 0xcd}, .id_len = 2, .chipsize = _512M, .erasesize = _256K, .pagesize = _4K, .oobsize = 256, .badblock_pos = BBP_FIRST_PAGE, .read = { &read_std(1, INFINITE, 24), &read_fast(1, INFINITE, 104), &read_dual(1, INFINITE, 104), &read_quad(1, INFINITE, 104), 0 }, .write = { &write_std(0, 256, 104), 0 }, .erase = { &erase_sector_256k(0, _256K, 104), 0 }, .driver = &spi_driver_no_qe, }, /* TOSHIBA TC58CVG2S0HRAIJ 4Gbit */ { .name = "TC58CVG2S0HRAIJ", .id = {0x98, 0xed, 0x51}, .id_len = 3, .chipsize = _512M, .erasesize = _256K, .pagesize = _4K, .oobsize = 256, .badblock_pos = BBP_FIRST_PAGE, .read = { &read_std(1, INFINITE, 24), &read_fast(1, INFINITE, 133), &read_dual(1, INFINITE, 133), &read_quad(1, INFINITE, 133), 0 }, .write = { &write_std(0, 256, 133), &write_quad(0, 256, 133), 0 }, .erase = { &erase_sector_256k(0, _256K, 133), 0 }, .driver = &spi_driver_no_qe, }, /* TOSHIBA TC58CYG2S0H 1.8V 4Gbit */ { .name = "TC58CYG2S0H", .id = {0x98, 0xbd}, .id_len = 2, .chipsize = _512M, .erasesize = _256K, .pagesize = _4K, .oobsize = 256, .badblock_pos = BBP_FIRST_PAGE, .read = { &read_std(1, INFINITE, 24), &read_fast(1, INFINITE, 104), &read_dual(1, INFINITE, 104), &read_quad(1, INFINITE, 104), 0 }, .write = { &write_std(0, 256, 75), 0 }, .erase = { &erase_sector_256k(0, _256K, 75), 0 }, .driver = &spi_driver_no_qe, }, /* KIOXIA TH58CYG2S0HRAIJ 1.8V 4Gbit */ { .name = "TH58CYG2S0HRAIJ", .id = {0x98, 0xdd, 0x51}, .id_len = 3, .chipsize = _512M, .erasesize = _256K, .pagesize = _4K, .oobsize = 256, .badblock_pos = BBP_FIRST_PAGE, .read = { &read_std(1, INFINITE, 24), /* 24MHz */ &read_fast(1, INFINITE, 133), /* 133MHz */ &read_dual(1, INFINITE, 133), /* 133MHz */ &read_quad(1, INFINITE, 133), /* 133MHz */ 0 }, .write = { &write_std(0, 256, 133), /* 133MHz */ &write_quad(0, 256, 133), /* 133MHz */ 0 }, .erase = { &erase_sector_256k(0, _256K, 133), /* 133MHz */ 0 }, .driver = &spi_driver_no_qe, }, /* KIOXIA TH58CYG3S0H 1.8V 8Gbit */ { .name = "TH58CYG3S0H", .id = {0x98, 0xd4, 0x51}, .id_len = 3, .chipsize = _1G, .erasesize = _256K, .pagesize = _4K, .oobsize = 256, .badblock_pos = BBP_FIRST_PAGE, .read = { &read_std(1, INFINITE, 24), /* 24MHz */ &read_fast(1, INFINITE, 133), /* 133MHz */ &read_dual(1, INFINITE, 133), /* 133MHz */ &read_quad(1, INFINITE, 133), /* 133MHz */ 0 }, .write = { &write_std(0, 256, 133), /* 133MHz */ &write_quad(0, 256, 133), /* 133MHz */ 0 }, .erase = { &erase_sector_256k(0, _256K, 133), /* 133MHz */ 0 }, .driver = &spi_driver_no_qe, }, /* HeYangTek HYF1GQ4UAACAE 1Gbit */ { .name = "HYF1GQ4UAACAE", .id = {0xc9, 0x51}, .id_len = 2, .chipsize = _128M, .erasesize = _128K, .pagesize = _2K, .oobsize = 128, .badblock_pos = BBP_FIRST_PAGE, .read = { &read_std(1, INFINITE, 24), &read_fast(1, INFINITE, 80), &read_dual(1, INFINITE, 80), &read_dual_addr(1, INFINITE, 80), &read_quad(1, INFINITE, 80), &read_quad_addr(1, INFINITE, 80), 0 }, .write = { &write_std(0, 256, 80), &write_quad(0, 256, 80), 0 }, .erase = { &erase_sector_128k(0, _128K, 80), 0 }, .driver = &spi_driver_general, }, /* HeYangTek HYF2GQ4UAACAE 2Gbit */ { .name = "HYF2GQ4UAACAE", .id = {0xc9, 0x52}, .id_len = 2, .chipsize = _256M, .erasesize = _128K, .pagesize = _2K, .oobsize = 128, .badblock_pos = BBP_FIRST_PAGE, .read = { &read_std(1, INFINITE, 24), &read_fast(1, INFINITE, 80), &read_dual(1, INFINITE, 80), &read_dual_addr(1, INFINITE, 80), &read_quad(1, INFINITE, 80), &read_quad_addr(1, INFINITE, 80), 0 }, .write = { &write_std(0, 256, 80), &write_quad(0, 256, 80), 0 }, .erase = { &erase_sector_128k(0, _128K, 80), 0 }, .driver = &spi_driver_general, }, /* HeYangTek HYF4GQ4UAACBE 4Gbit */ { .name = "HYF4GQ4UAACBE", .id = {0xc9, 0xd4}, .id_len = 2, .chipsize = _512M, .erasesize = _256K, .pagesize = _4K, .oobsize = 256, .badblock_pos = BBP_FIRST_PAGE, .read = { &read_std(1, INFINITE, 24), &read_fast(1, INFINITE, 80), &read_dual(1, INFINITE, 80), &read_dual_addr(1, INFINITE, 80), &read_quad(1, INFINITE, 80), &read_quad_addr(1, INFINITE, 80), 0 }, .write = { &write_std(0, 256, 80), &write_quad(0, 256, 80), 0 }, .erase = { &erase_sector_256k(0, _256K, 80), 0 }, .driver = &spi_driver_general, }, /* Dosilicon 3.3V DS35Q1GA-IB 1Gbit */ { .name = "DS35Q1GA-IB", .id = {0xe5, 0x71}, .id_len = 2, .chipsize = _128M, .erasesize = _128K, .pagesize = _2K, .oobsize = 64, .badblock_pos = BBP_FIRST_PAGE, .read = { &read_std(1, INFINITE, 24), &read_fast(1, INFINITE, 104), &read_dual(1, INFINITE, 104), &read_quad(1, INFINITE, 104), 0 }, .write = { &write_std(0, 256, 80), &write_quad(0, 256, 104), 0 }, .erase = { &erase_sector_128k(0, _128K, 104), 0 }, .driver = &spi_driver_general, }, /* XTX 3.3V XT26G01B 1Gbit */ { .name = "XT26G01B", .id = {0x0B, 0xF1}, .id_len = 2, .chipsize = _128M, .erasesize = _128K, .pagesize = _2K, .oobsize = 64, .badblock_pos = BBP_FIRST_PAGE, .read = { &read_std(1, INFINITE, 24), &read_fast(1, INFINITE, 80), &read_dual(1, INFINITE, 80), &read_dual_addr(1, INFINITE, 80), &read_quad(1, INFINITE, 80), &read_quad_addr(1, INFINITE, 80), 0 }, .write = { &write_std(0, 256, 80), &write_quad(0, 256, 80), 0 }, .erase = { &erase_sector_128k(0, _128K, 80), 0 }, .driver = &spi_driver_general, }, /* Etron 1.8V EM78F044VCA-H 8Gbit */ { .name = "EM78F044VCA-H", .id = {0xD5, 0x8D}, .id_len = 2, .chipsize = _512M * 2, .erasesize = _256K, .pagesize = _4K, .oobsize = 256, .badblock_pos = BBP_FIRST_PAGE, .read = { &read_std(1, INFINITE, 24), &read_fast(1, INFINITE, 100), &read_dual(1, INFINITE, 100), &read_dual_addr(1, INFINITE, 100), &read_quad(1, INFINITE, 100), &read_quad_addr(1, INFINITE, 100), 0 }, .write = { &write_std(0, 256, 100), &write_quad(0, 256, 100), 0 }, .erase = { &erase_sector_256k(0, _256K, 100), 0 }, .driver = &spi_driver_general, }, /* Etron 1.8V EM78E044VCA-H 4Gbit */ { .name = "EM78E044VCA-H", .id = {0xD5, 0x8C}, .id_len = 2, .chipsize = _512M, .erasesize = _256K, .pagesize = _4K, .oobsize = 256, .badblock_pos = BBP_FIRST_PAGE, .read = { &read_std(1, INFINITE, 24), &read_fast(1, INFINITE, 100), &read_dual(1, INFINITE, 100), &read_dual_addr(1, INFINITE, 100), &read_quad(1, INFINITE, 100), &read_quad_addr(1, INFINITE, 100), 0 }, .write = { &write_std(0, 256, 100), &write_quad(0, 256, 100), 0 }, .erase = { &erase_sector_256k(0, _256K, 100), 0 }, .driver = &spi_driver_general, }, /* Etron 1.8V EM78D044VCF-H 2Gbit */ { .name = "EM78D044VCF-H", .id = {0xd5, 0x81}, .id_len = 2, .chipsize = _256M, .erasesize = _128K, .pagesize = _2K, .oobsize = 64, .badblock_pos = BBP_FIRST_PAGE, .read = { &read_std(1, INFINITE, 24), &read_fast(1, INFINITE, 104), &read_dual(1, INFINITE, 104), &read_dual_addr(1, INFINITE, 104), &read_quad(1, INFINITE, 104), &read_quad_addr(1, INFINITE, 104), 0 }, .write = { &write_std(0, 256, 80), &write_quad(0, 256, 104), 0 }, .erase = { &erase_sector_128k(0, _128K, 104), 0 }, .driver = &spi_driver_general, }, /* Etron 3.3V EM73C044VCC-H 1Gbit */ { .name = "EM73C044VCC-H", .id = {0xd5, 0x22}, .id_len = 2, .chipsize = _128M, .erasesize = _128K, .pagesize = _2K, .oobsize = 64, .badblock_pos = BBP_FIRST_PAGE, .read = { &read_std(1, INFINITE, 24), &read_fast(1, INFINITE, 120), &read_dual(1, INFINITE, 120), &read_dual_addr(1, INFINITE, 120), &read_quad(1, INFINITE, 120), &read_quad_addr(1, INFINITE, 120), 0 }, .write = { &write_std(0, 256, 104), &write_quad(0, 256, 120), 0 }, .erase = { &erase_sector_128k(0, _128K, 104), 0 }, .driver = &spi_driver_general, }, /* Micron MT29F4G01ABBFDWB 4GBit 1.8V */ { .name = "MT29F4G01ABBFDWB", .id = {0x2C, 0x35}, .id_len = 2, .chipsize = _512M, .erasesize = _256K, .pagesize = _4K, .oobsize = 256, .badblock_pos = BBP_FIRST_PAGE, .read = { &read_std(1, INFINITE, 24), &read_fast(1, INFINITE, 80), &read_dual(1, INFINITE, 80), &read_quad(1, INFINITE, 80), 0 }, .write = { &write_std(0, 256, 80), &write_quad(0, 256, 80), 0 }, .erase = { &erase_sector_256k(0, _256K, 80), 0 }, .driver = &spi_driver_no_qe, }, /* Dosilicon 3.3V DS35Q2GA-IB 1Gb */ { .name = "DS35Q2GA-IB", .id = {0xe5, 0x72}, .id_len = 2, .chipsize = _256M, .erasesize = _128K, .pagesize = _2K, .oobsize = 64, .badblock_pos = BBP_FIRST_PAGE, .read = { &read_std(1, INFINITE, 24), &read_fast(1, INFINITE, 104), &read_dual(1, INFINITE, 104), &read_quad(1, INFINITE, 104), 0 }, .write = { &write_std(0, 256, 80), &write_quad(0, 256, 104), 0 }, .erase = { &erase_sector_128k(0, _128K, 104), 0 }, .driver = &spi_driver_general, }, /* FM 3.3v FM25S01-DND-A-G 1Gbit */ { .name = "FM25S01-DND-A-G", .id = {0xa1, 0xa1}, .id_len = 2, .chipsize = _128M, .erasesize = _128K, .pagesize = _2K, .oobsize = 128, .badblock_pos = BBP_FIRST_PAGE, .read = { &read_std(1, INFINITE, 24), /* 24MHz */ &read_fast(1, INFINITE, 104), /* 104MHz */ &read_dual(1, INFINITE, 104), /* 104MHz */ &read_dual_addr(1, INFINITE, 40), /* 40MHz */ &read_quad(1, INFINITE, 104), /* 104MHz */ &read_quad_addr(2, INFINITE, 40), /* 40MHz */ 0 }, .write = { &write_std(0, 256, 104), /* 104MHz */ &write_quad(0, 256, 104), /* 104MHz */ 0 }, .erase = { &erase_sector_128k(0, _128K, 104), /* 104MHz */ 0 }, .driver = &spi_driver_no_qe, }, /* FM 3.3v FM25S01A 1Gbit */ { .name = "FM25S01A", .id = {0xa1, 0xe4}, .id_len = 2, .chipsize = _128M, .erasesize = _128K, .pagesize = _2K, .oobsize = 64, .badblock_pos = BBP_FIRST_PAGE, .read = { &read_std(1, INFINITE, 24), /* 104MHz */ &read_fast(1, INFINITE, 104), /* 104MHz */ &read_dual(1, INFINITE, 104), /* 104MHz */ &read_dual_addr(1, INFINITE, 40), /* 40MHz */ &read_quad(1, INFINITE, 104), /* 104MHz */ &read_quad_addr(2, INFINITE, 40), /* 40MHz */ 0 }, .write = { &write_std(0, 256, 104), /* 104MHz */ &write_quad(0, 256, 104), /* 104MHz */ 0 }, .erase = { &erase_sector_128k(0, _128K, 104), /* 104MHz */ 0 }, .driver = &spi_driver_no_qe, }, { .id_len = 0, }, }; static void fmc100_spi_nand_search_rw(struct spi_nand_info *spiinfo, struct spi_op *spiop_rw, u_int iftype, u_int max_dummy, int rw_type) { int ix = 0; struct spi_op **spiop, **fitspiop; int ret; for (fitspiop = spiop = (rw_type ? spiinfo->write : spiinfo->read); (*spiop) && ix < MAX_SPI_OP; spiop++, ix++) { if (((*spiop)->iftype & iftype) && ((*spiop)->dummy <= max_dummy) && (*fitspiop)->iftype < (*spiop)->iftype) fitspiop = spiop; } ret = memcpy_s(spiop_rw, sizeof(struct spi_op), (*fitspiop), sizeof(struct spi_op)); if (ret) printk("%s:memcpy_s failed\n",__func__); } static void fmc100_spi_nand_get_erase(const struct spi_nand_info *spiinfo, struct spi_op *spiop_erase) { int ix; int ret; spiop_erase->size = 0; for (ix = 0; ix < MAX_SPI_OP; ix++) { if (spiinfo->erase[ix] == NULL) break; if (spiinfo->erasesize == spiinfo->erase[ix]->size) { ret = memcpy_s(&spiop_erase[ix], sizeof(struct spi_op), spiinfo->erase[ix], sizeof(struct spi_op)); if (ret) printk("%s:memcpy_s failed\n", __func__); break; } } } static void fmc100_map_spi_op(struct fmc_spi *spi) { unsigned char ix; const int iftype_read[] = { SPI_IF_READ_STD, IF_TYPE_STD, SPI_IF_READ_FAST, IF_TYPE_STD, SPI_IF_READ_DUAL, IF_TYPE_DUAL, SPI_IF_READ_DUAL_ADDR, IF_TYPE_DIO, SPI_IF_READ_QUAD, IF_TYPE_QUAD, SPI_IF_READ_QUAD_ADDR, IF_TYPE_QIO, 0, 0, }; const int iftype_write[] = { SPI_IF_WRITE_STD, IF_TYPE_STD, SPI_IF_WRITE_QUAD, IF_TYPE_QUAD, 0, 0, }; const char *if_str[] = {"STD", "DUAL", "DIO", "QUAD", "QIO"}; fmc_pr(BT_DBG, "\t||*-Start Get SPI operation iftype\n"); for (ix = 0; iftype_write[ix]; ix += 2) { /* 2 is row1 of iftype_write[] */ if (spi->write->iftype == iftype_write[ix]) { spi->write->iftype = iftype_write[ix + 1]; break; } } fmc_pr(BT_DBG, "\t|||-Get best write iftype: %s \n", if_str[spi->write->iftype]); for (ix = 0; iftype_read[ix]; ix += 2) { /* 2 is row1 of iftype_read[] */ if (spi->read->iftype == iftype_read[ix]) { spi->read->iftype = iftype_read[ix + 1]; break; } } fmc_pr(BT_DBG, "\t|||-Get best read iftype: %s \n", if_str[spi->read->iftype]); spi->erase->iftype = IF_TYPE_STD; fmc_pr(BT_DBG, "\t|||-Get best erase iftype: %s \n", if_str[spi->erase->iftype]); fmc_pr(BT_DBG, "\t||*-End Get SPI operation iftype \n"); } static void fmc100_spi_nand_op_cmd_init(struct spi_nand_info *spi_dev, struct fmc_spi *spi) { fmc100_spi_nand_search_rw(spi_dev, spi->read, FMC_SPI_NAND_SUPPORT_READ, FMC_SPI_NAND_SUPPORT_MAX_DUMMY, RW_OP_READ); fmc_pr(BT_DBG, "\t||-Save spi->read op cmd:%#x\n", spi->read->cmd); fmc100_spi_nand_search_rw(spi_dev, spi->write, FMC_SPI_NAND_SUPPORT_WRITE, FMC_SPI_NAND_SUPPORT_MAX_DUMMY, RW_OP_WRITE); fmc_pr(BT_DBG, "\t||-Save spi->write op cmd:%#x\n", spi->write->cmd); fmc100_spi_nand_get_erase(spi_dev, spi->erase); fmc_pr(BT_DBG, "\t||-Save spi->erase op cmd:%#x\n", spi->erase->cmd); fmc100_map_spi_op(spi); } static int fmc100_spi_nand_dis_wr_protect(struct fmc_spi *spi, u_char *reg) { int ret; ret = spi_nand_feature_op(spi, GET_OP, PROTECT_ADDR, reg); if (ret) return ret; fmc_pr(BT_DBG, "\t||-Get protect status[%#x]: %#x\n", PROTECT_ADDR, *reg); if (any_bp_enable(*reg)) { *reg &= ~ALL_BP_MASK; ret = spi_nand_feature_op(spi, SET_OP, PROTECT_ADDR, reg); if (ret) return ret; fmc_pr(BT_DBG, "\t||-Set [%#x]FT %#x\n", PROTECT_ADDR, *reg); spi->driver->wait_ready(spi); ret = spi_nand_feature_op(spi, GET_OP, PROTECT_ADDR, reg); if (ret) return ret; fmc_pr(BT_DBG, "\t||-Check BP disable result: %#x\n", *reg); if (any_bp_enable(*reg)) db_msg("Error: Write protection disable failed!\n"); } return ret; } static int fmc100_spi_nand_dis_chip_inner_ecc(struct fmc_spi *spi, u_char *reg) { int ret; ret = spi_nand_feature_op(spi, GET_OP, FEATURE_ADDR, reg); if (ret) return ret; fmc_pr(BT_DBG, "\t||-Get feature status[%#x]: %#x\n", FEATURE_ADDR, *reg); if (*reg & FEATURE_ECC_ENABLE) { *reg &= ~FEATURE_ECC_ENABLE; ret = spi_nand_feature_op(spi, SET_OP, FEATURE_ADDR, reg); if (ret) return ret; fmc_pr(BT_DBG, "\t||-Set [%#x]FT: %#x\n", FEATURE_ADDR, *reg); spi->driver->wait_ready(spi); ret = spi_nand_feature_op(spi, GET_OP, FEATURE_ADDR, reg); if (ret) return ret; fmc_pr(BT_DBG, "\t||-Check internal ECC disable result: %#x\n", *reg); if (*reg & FEATURE_ECC_ENABLE) db_msg("Error: Chip internal ECC disable failed!\n"); } return ret; } static void fmc100_spi_ids_probe(struct mtd_info *mtd, struct spi_nand_info *spi_dev) { u_char reg; int ret; struct nand_chip *chip = NULL; struct fmc_host *host = NULL; struct fmc_spi *spi = NULL; if (mtd == NULL || spi_dev == NULL) { db_msg("Error: mtd or spi_dev is NULL!\n"); return; } chip = mtd_to_nand(mtd); if (chip == NULL || chip->priv == NULL) { db_msg("Error: chip is NULL!\n"); return; } host = chip->priv; if (host->spi == NULL) { db_msg("Error: host->spi is NULL!\n"); return; } spi = host->spi; fmc_pr(BT_DBG, "\t|*-Start match SPI operation & chip init\n"); spi->host = host; spi->name = spi_dev->name; spi->driver = spi_dev->driver; if (!spi->driver) { db_msg("Error: host->driver is NULL!\n"); return; } fmc100_spi_nand_op_cmd_init(spi_dev, spi); if (spi->driver->qe_enable) spi->driver->qe_enable(spi); /* Disable write protection */ ret = fmc100_spi_nand_dis_wr_protect(spi, ®); if (ret) return; /* Disable chip internal ECC */ ret = fmc100_spi_nand_dis_chip_inner_ecc(spi, ®); if (ret) return; fmc_cs_user[host->cmd_op.cs]++; fmc_pr(BT_DBG, "\t|*-End match SPI operation & chip init\n"); } static struct nand_flash_dev spi_nand_dev; static struct nand_flash_dev *spi_nand_get_flash_info(struct mtd_info *mtd, unsigned char *id) { unsigned char ix; int len; char buffer[BUFF_LEN]; struct nand_chip *chip = mtd_to_nand(mtd); struct fmc_host *host = chip->priv; struct spi_nand_info *spi_dev = fmc_spi_nand_flash_table; struct nand_flash_dev *type = &spi_nand_dev; int ret; fmc_pr(BT_DBG, "\t*-Start find SPI Nand flash\n"); len = sprintf_s(buffer, BUFF_LEN, "SPI Nand(cs %d) ID: %#x %#x", host->cmd_op.cs, id[0], id[1]); if (len < 0) printk("%s,line:%d,sprintf_s failed\n",__func__,__LINE__); for (; spi_dev->id_len; spi_dev++) { if (!access_ok(VERIFY_READ, id, spi_dev->id_len)) { db_msg("err:spi_nand_get_flash_info access_ok fail\n"); return NULL; } if (memcmp(id, spi_dev->id, spi_dev->id_len)) continue; for (ix = 2; ix < spi_dev->id_len; ix++) { /* star from id[2] */ if ((spi_dev->id_len <= MAX_SPI_NAND_ID_LEN)) { len += sprintf_s(buffer + len, BUFF_LEN - len, " %#x", id[ix]); if (len < 0) printk("%s,line:%d,sprintf_s failed\n", __func__,__LINE__); } } pr_info("%s\n", buffer); fmc_pr(BT_DBG, "\t||-CS(%d) found SPI Nand: %s\n", host->cmd_op.cs, spi_dev->name); type->name = spi_dev->name; ret = memcpy_s(type->id, MAX_SPI_NAND_ID_LEN, spi_dev->id, spi_dev->id_len); if (ret) { printk("%s:memcpy_s failed\n",__func__); return NULL; } type->pagesize = spi_dev->pagesize; type->chipsize = (unsigned int)(spi_dev->chipsize >> 20); /* 1M unit shift right 20 bit */ type->erasesize = spi_dev->erasesize; type->id_len = spi_dev->id_len; type->oobsize = spi_dev->oobsize; fmc_pr(BT_DBG, "\t|-Save struct nand_flash_dev info\n"); mtd->oobsize = spi_dev->oobsize; mtd->erasesize = spi_dev->erasesize; mtd->writesize = spi_dev->pagesize; chip->chipsize = spi_dev->chipsize; fmc100_spi_ids_probe(mtd, spi_dev); fmc_pr(BT_DBG, "\t*-Found SPI nand: %s\n", spi_dev->name); return type; } fmc_pr(BT_DBG, "\t*-Not found SPI nand flash, %s\n", buffer); return NULL; } void fmc_spi_nand_ids_register(void) { pr_info("SPI Nand ID Table Version %s\n", SPI_NAND_ID_TAB_VER); get_spi_nand_flash_type_hook = spi_nand_get_flash_info; } #ifdef CONFIG_PM static int fmc100_spi_nand_dis_wp(struct fmc_spi *spi, u_char *reg) { int ret; ret = spi_nand_feature_op(spi, GET_OP, PROTECT_ADDR, reg); if (ret) return ret; fmc_pr(PM_DBG, "\t|-Get protect status[%#x]: %#x\n", PROTECT_ADDR, *reg); if (any_bp_enable(*reg)) { *reg &= ~ALL_BP_MASK; ret = spi_nand_feature_op(spi, SET_OP, PROTECT_ADDR, reg); if (ret) return ret; fmc_pr(PM_DBG, "\t|-Set [%#x]FT %#x\n", PROTECT_ADDR, *reg); spi->driver->wait_ready(spi); ret = spi_nand_feature_op(spi, GET_OP, PROTECT_ADDR, reg); if (ret) return ret; fmc_pr(PM_DBG, "\t|-Check BP disable result: %#x\n", *reg); if (any_bp_enable(*reg)) db_msg("Error: Write protection disable failed!\n"); } return ret; } void fmc100_spi_nand_config(struct fmc_host *host) { u_char reg; int ret; struct fmc_spi *spi = NULL; static const char *str[] = {"STD", "DUAL", "DIO", "QUAD", "QIO"}; if ((host == NULL) || (host->spi == NULL)) { db_msg("Error: host or host->spi is NULL!\n"); return; } spi = host->spi; /* judge whether support QUAD read/write or not, set it if yes */ fmc_pr(PM_DBG, "\t|-SPI read iftype: %s write iftype: %s\n", str[spi->read->iftype], str[spi->write->iftype]); if (spi->driver->qe_enable) spi->driver->qe_enable(spi); /* Disable write protection */ ret = fmc100_spi_nand_dis_wp(spi, ®); if (ret) return; /* Disable chip internal ECC */ ret = spi_nand_feature_op(spi, GET_OP, FEATURE_ADDR, ®); if (ret) return; fmc_pr(PM_DBG, "\t|-Get feature status[%#x]: %#x\n", FEATURE_ADDR, reg); if (reg & FEATURE_ECC_ENABLE) { reg &= ~FEATURE_ECC_ENABLE; ret = spi_nand_feature_op(spi, SET_OP, FEATURE_ADDR, ®); if (ret) return; fmc_pr(PM_DBG, "\t|-Set [%#x]FT: %#x\n", FEATURE_ADDR, reg); spi->driver->wait_ready(spi); ret = spi_nand_feature_op(spi, GET_OP, FEATURE_ADDR, ®); if (ret) return; fmc_pr(PM_DBG, "\t|-Check internal ECC disable result: %#x\n", reg); if (reg & FEATURE_ECC_ENABLE) db_msg("Error: Chip internal ECC disable failed!\n"); } } #endif /* CONFIG_PM */
补充
- 一般 linux 的 kerner、uboot 这些都是标准的,根据版本号来区分
- make menuconfig 根据 .config 打开图形化 ui 配置界面,修改其配置一般不影响 kerner 修改的驱动代码 。 有些配置选项可以是 M , M 的意思是成为单独的 模块 编译出来,如 g_ffs.ko , 这样可以需要的时候再加载,也可以自定义参数如:insmod g_ffs.ko idVendor=0x1D6B iSerialNumber=01234567 functions=adb 。 模块编译之前先整个编译一下比较好: make ARCH=arm64 CROSS_COMPILE=aarch64-mix210-linux- uImage -j20 -> make ARCH=arm64 CROSS_COMPILE=aarch64-mix210-linux- modules. 如果选项是 * 就表示是编译到内核里面去了
- 在启动的时候按任意键进入uboot 模式,输入 printenv 可以查看 uboot 传给 kerner 的一些参数,reset 继续运行