首页 > 其他分享 >Puas 编译内核 并成功替换

Puas 编译内核 并成功替换

时间:2024-11-14 17:10:35浏览次数:1  
标签:spi read driver write 编译 内核 INFINITE quad Puas

动机

  • 为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, &reg);
      	if (ret)
      		return;
      
      	/* Disable chip internal ECC */
      	ret = fmc100_spi_nand_dis_chip_inner_ecc(spi, &reg);
      	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, &reg);
      	if (ret)
      		return;
      	/* Disable chip internal ECC */
      	ret = spi_nand_feature_op(spi, GET_OP, FEATURE_ADDR, &reg);
      	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, &reg);
      		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, &reg);
      		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 继续运行

标签:spi,read,driver,write,编译,内核,INFINITE,quad,Puas
From: https://www.cnblogs.com/fxw1/p/18546419

相关文章

  • YOLOv3 Darknet安装编译与训练自己的数据集
    文章目录1安装编译darknet与测试darknet1.1安装编译darknet1.1.1下载darknet安装包1.1.2编译darknet1.2测试darknet1.2.1测试单张图片1.2.2连续测试多张图片2.2.3更改检测的阈值(thresh)2.2.4使用TinyYOLOv3预训练模型测试2.2.5使用网络摄像头实时检测2darkn......
  • 从零到一构建并打包 React + TypeScript + Less组件库教程(二、组件库编译多产物及文档
    本系列目录如下:项目初始化搭建+代码规范集成组件库多产物编译及文档编写上篇文章我们将组件库的基本结构和规范进行了整理,本篇的核心基本全在components文件夹下本篇的打包参考了文章https://github.com/worldzhao/blog/issues/5,强烈建议阅读一下此文章,而且讨论区也能......
  • 关于Vulkan应用程序运行时编译GLSL Shader文件的方法
    最近在学习Vulkan,在相关参考书中给出的示例代码因为使用的VulkanSDK较老,出现无法构建成功的问题。而且示例代码给出的Vulkan应用程序运行时编译GLSLShader文件的方法放在现在已经是非常的麻烦。现在新版的VulkanSDK(1.3.X以上)将GLSL编译为SPIR-V非常方便了,可以使用Google提供的S......
  • Windows 下编译 Aseprite
    Aseprite(官网|GitHub)是一款开源的像素画软件,该软件在Steam有售,目前价格为70元。但它是开源软件,作者也允许我们自行编译来免费获得这份软件,通过编译得到的软件可用于创作商用作品(https://www.aseprite.org/faq/#can-i-sell-graphics-created-with-aseprite)。本文介绍在Wind......
  • carla编译安装
    参考链接:Windows构建-CARLA模拟器【Carla】Windows编译版安装-超详细版教程-知乎windows10下源码编译安装CARLA0.9.13_carlawindows源码编译-CSDN博客Carla0.9.14编译安装教程WIN10_windowscarla编译版安装-CSDN博客win10编译安装Carla_0.9.15_win10安装carla-CSDN......
  • 告别头文件,编译效率提升 42%!C++ Modules 实战解析 | 干货推荐
    编者按:AlibabaCloudLinux(简称“Alinux”)是目前阿里云上占比第一的操作系统。2021年,龙蜥以Alinux产品为基础发布了AnolisOS8正式版。本文中,阿里云智能集团开发工程师李泽政以Alinux为操作环境,讲解模块相比传统头文件有哪些优势,并通过若干个例子,学习如何组织一个C++模......
  • pjsip编译、说明及vs2022使用示例
    环境:window10_x64&vs2022pjsip版本:2.14.1 之前整理过pjsip2.10的编译及python使用示例:https://www.cnblogs.com/MikeZhang/p/pjsip20210116.htmlhttps://www.cnblogs.com/MikeZhang/p/win10py3pjsua-20211010.html 今天整理下pjsip2.14.1的编译、接口说明,以及在vs......
  • golang交叉编译
    交叉编译需要linux环境windows安装编译器aptinstallgcc-mingw-w64编译指令windows: CGO_ENABLED=1\ GOOS=windows\ GOARCH=amd64\ CC=x86_64-w64-mingw32-gcc\ gobuild\ -buildmode=c-shared\ -ldflags\ "-s-w\ -X'${ProjectName}/vers......
  • Golang 编译windows应用程序
    因为我们更喜欢在Linux上开发程序,所以生成交叉编译器,以便在Linux上交叉编译出windows程序。安装minGW:在Linux上运行gcc交叉编译生成windows程序我们用到Cgo,因此需要安装C语言交叉编译器sudoapt-getinstallgcc-mingw-w64下载Go语言的源代码gitclonehttps://github.com......
  • BuildRoot 中编译 opencpn 总结
    目录1:升级cmake版本3.24.0-rc52:设置交互编译环境变量3:编译wxWidgets-3.2.64:编译opencpn需要依赖的lib 5:编译opencpn1:升级cmake版本3.24.0-rc5sudobashcmake-3.22.1-linux-x86_64.sh--prefix=/usr--skip-license更改PATH路径corey@fcyswrd-15:~/opencpn/......